Commit | Line | Data |
---|---|---|
9277a6d4 DLM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Simple file system for zoned block devices exposing zones as files. | |
4 | * | |
5 | * Copyright (C) 2022 Western Digital Corporation or its affiliates. | |
6 | */ | |
7 | #include <linux/fs.h> | |
8 | #include <linux/seq_file.h> | |
9 | #include <linux/blkdev.h> | |
10 | ||
11 | #include "zonefs.h" | |
12 | ||
13 | struct zonefs_sysfs_attr { | |
14 | struct attribute attr; | |
15 | ssize_t (*show)(struct zonefs_sb_info *sbi, char *buf); | |
16 | }; | |
17 | ||
18 | static inline struct zonefs_sysfs_attr *to_attr(struct attribute *attr) | |
19 | { | |
20 | return container_of(attr, struct zonefs_sysfs_attr, attr); | |
21 | } | |
22 | ||
23 | #define ZONEFS_SYSFS_ATTR_RO(name) \ | |
24 | static struct zonefs_sysfs_attr zonefs_sysfs_attr_##name = __ATTR_RO(name) | |
25 | ||
26 | #define ATTR_LIST(name) &zonefs_sysfs_attr_##name.attr | |
27 | ||
28 | static ssize_t zonefs_sysfs_attr_show(struct kobject *kobj, | |
29 | struct attribute *attr, char *buf) | |
30 | { | |
31 | struct zonefs_sb_info *sbi = | |
32 | container_of(kobj, struct zonefs_sb_info, s_kobj); | |
33 | struct zonefs_sysfs_attr *zonefs_attr = | |
34 | container_of(attr, struct zonefs_sysfs_attr, attr); | |
35 | ||
36 | if (!zonefs_attr->show) | |
37 | return 0; | |
38 | ||
39 | return zonefs_attr->show(sbi, buf); | |
40 | } | |
41 | ||
42 | static ssize_t max_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf) | |
43 | { | |
44 | return sysfs_emit(buf, "%u\n", sbi->s_max_wro_seq_files); | |
45 | } | |
46 | ZONEFS_SYSFS_ATTR_RO(max_wro_seq_files); | |
47 | ||
48 | static ssize_t nr_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf) | |
49 | { | |
50 | return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_wro_seq_files)); | |
51 | } | |
52 | ZONEFS_SYSFS_ATTR_RO(nr_wro_seq_files); | |
53 | ||
87c9ce3f DLM |
54 | static ssize_t max_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf) |
55 | { | |
56 | return sysfs_emit(buf, "%u\n", sbi->s_max_active_seq_files); | |
57 | } | |
58 | ZONEFS_SYSFS_ATTR_RO(max_active_seq_files); | |
59 | ||
60 | static ssize_t nr_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf) | |
61 | { | |
62 | return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_active_seq_files)); | |
63 | } | |
64 | ZONEFS_SYSFS_ATTR_RO(nr_active_seq_files); | |
65 | ||
9277a6d4 DLM |
66 | static struct attribute *zonefs_sysfs_attrs[] = { |
67 | ATTR_LIST(max_wro_seq_files), | |
68 | ATTR_LIST(nr_wro_seq_files), | |
87c9ce3f DLM |
69 | ATTR_LIST(max_active_seq_files), |
70 | ATTR_LIST(nr_active_seq_files), | |
9277a6d4 DLM |
71 | NULL, |
72 | }; | |
73 | ATTRIBUTE_GROUPS(zonefs_sysfs); | |
74 | ||
75 | static void zonefs_sysfs_sb_release(struct kobject *kobj) | |
76 | { | |
77 | struct zonefs_sb_info *sbi = | |
78 | container_of(kobj, struct zonefs_sb_info, s_kobj); | |
79 | ||
80 | complete(&sbi->s_kobj_unregister); | |
81 | } | |
82 | ||
83 | static const struct sysfs_ops zonefs_sysfs_attr_ops = { | |
84 | .show = zonefs_sysfs_attr_show, | |
85 | }; | |
86 | ||
87 | static struct kobj_type zonefs_sb_ktype = { | |
88 | .default_groups = zonefs_sysfs_groups, | |
89 | .sysfs_ops = &zonefs_sysfs_attr_ops, | |
90 | .release = zonefs_sysfs_sb_release, | |
91 | }; | |
92 | ||
93 | static struct kobject *zonefs_sysfs_root; | |
94 | ||
95 | int zonefs_sysfs_register(struct super_block *sb) | |
96 | { | |
97 | struct zonefs_sb_info *sbi = ZONEFS_SB(sb); | |
98 | int ret; | |
99 | ||
100 | init_completion(&sbi->s_kobj_unregister); | |
101 | ret = kobject_init_and_add(&sbi->s_kobj, &zonefs_sb_ktype, | |
102 | zonefs_sysfs_root, "%s", sb->s_id); | |
103 | if (ret) { | |
104 | kobject_put(&sbi->s_kobj); | |
105 | wait_for_completion(&sbi->s_kobj_unregister); | |
106 | return ret; | |
107 | } | |
108 | ||
109 | sbi->s_sysfs_registered = true; | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | void zonefs_sysfs_unregister(struct super_block *sb) | |
115 | { | |
116 | struct zonefs_sb_info *sbi = ZONEFS_SB(sb); | |
117 | ||
118 | if (!sbi || !sbi->s_sysfs_registered) | |
119 | return; | |
120 | ||
121 | kobject_del(&sbi->s_kobj); | |
122 | kobject_put(&sbi->s_kobj); | |
123 | wait_for_completion(&sbi->s_kobj_unregister); | |
124 | } | |
125 | ||
126 | int __init zonefs_sysfs_init(void) | |
127 | { | |
128 | zonefs_sysfs_root = kobject_create_and_add("zonefs", fs_kobj); | |
129 | if (!zonefs_sysfs_root) | |
130 | return -ENOMEM; | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | void zonefs_sysfs_exit(void) | |
136 | { | |
137 | kobject_put(zonefs_sysfs_root); | |
138 | zonefs_sysfs_root = NULL; | |
139 | } |