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 | ||
9277a6d4 DLM |
18 | #define ZONEFS_SYSFS_ATTR_RO(name) \ |
19 | static struct zonefs_sysfs_attr zonefs_sysfs_attr_##name = __ATTR_RO(name) | |
20 | ||
21 | #define ATTR_LIST(name) &zonefs_sysfs_attr_##name.attr | |
22 | ||
23 | static ssize_t zonefs_sysfs_attr_show(struct kobject *kobj, | |
24 | struct attribute *attr, char *buf) | |
25 | { | |
26 | struct zonefs_sb_info *sbi = | |
27 | container_of(kobj, struct zonefs_sb_info, s_kobj); | |
28 | struct zonefs_sysfs_attr *zonefs_attr = | |
29 | container_of(attr, struct zonefs_sysfs_attr, attr); | |
30 | ||
31 | if (!zonefs_attr->show) | |
32 | return 0; | |
33 | ||
34 | return zonefs_attr->show(sbi, buf); | |
35 | } | |
36 | ||
37 | static ssize_t max_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf) | |
38 | { | |
39 | return sysfs_emit(buf, "%u\n", sbi->s_max_wro_seq_files); | |
40 | } | |
41 | ZONEFS_SYSFS_ATTR_RO(max_wro_seq_files); | |
42 | ||
43 | static ssize_t nr_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf) | |
44 | { | |
45 | return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_wro_seq_files)); | |
46 | } | |
47 | ZONEFS_SYSFS_ATTR_RO(nr_wro_seq_files); | |
48 | ||
87c9ce3f DLM |
49 | static ssize_t max_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf) |
50 | { | |
51 | return sysfs_emit(buf, "%u\n", sbi->s_max_active_seq_files); | |
52 | } | |
53 | ZONEFS_SYSFS_ATTR_RO(max_active_seq_files); | |
54 | ||
55 | static ssize_t nr_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf) | |
56 | { | |
57 | return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_active_seq_files)); | |
58 | } | |
59 | ZONEFS_SYSFS_ATTR_RO(nr_active_seq_files); | |
60 | ||
9277a6d4 DLM |
61 | static struct attribute *zonefs_sysfs_attrs[] = { |
62 | ATTR_LIST(max_wro_seq_files), | |
63 | ATTR_LIST(nr_wro_seq_files), | |
87c9ce3f DLM |
64 | ATTR_LIST(max_active_seq_files), |
65 | ATTR_LIST(nr_active_seq_files), | |
9277a6d4 DLM |
66 | NULL, |
67 | }; | |
68 | ATTRIBUTE_GROUPS(zonefs_sysfs); | |
69 | ||
70 | static void zonefs_sysfs_sb_release(struct kobject *kobj) | |
71 | { | |
72 | struct zonefs_sb_info *sbi = | |
73 | container_of(kobj, struct zonefs_sb_info, s_kobj); | |
74 | ||
75 | complete(&sbi->s_kobj_unregister); | |
76 | } | |
77 | ||
78 | static const struct sysfs_ops zonefs_sysfs_attr_ops = { | |
79 | .show = zonefs_sysfs_attr_show, | |
80 | }; | |
81 | ||
2b188a2c | 82 | static const struct kobj_type zonefs_sb_ktype = { |
9277a6d4 DLM |
83 | .default_groups = zonefs_sysfs_groups, |
84 | .sysfs_ops = &zonefs_sysfs_attr_ops, | |
85 | .release = zonefs_sysfs_sb_release, | |
86 | }; | |
87 | ||
88 | static struct kobject *zonefs_sysfs_root; | |
89 | ||
90 | int zonefs_sysfs_register(struct super_block *sb) | |
91 | { | |
92 | struct zonefs_sb_info *sbi = ZONEFS_SB(sb); | |
93 | int ret; | |
94 | ||
95 | init_completion(&sbi->s_kobj_unregister); | |
96 | ret = kobject_init_and_add(&sbi->s_kobj, &zonefs_sb_ktype, | |
97 | zonefs_sysfs_root, "%s", sb->s_id); | |
98 | if (ret) { | |
99 | kobject_put(&sbi->s_kobj); | |
100 | wait_for_completion(&sbi->s_kobj_unregister); | |
101 | return ret; | |
102 | } | |
103 | ||
104 | sbi->s_sysfs_registered = true; | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | void zonefs_sysfs_unregister(struct super_block *sb) | |
110 | { | |
111 | struct zonefs_sb_info *sbi = ZONEFS_SB(sb); | |
112 | ||
113 | if (!sbi || !sbi->s_sysfs_registered) | |
114 | return; | |
115 | ||
116 | kobject_del(&sbi->s_kobj); | |
117 | kobject_put(&sbi->s_kobj); | |
118 | wait_for_completion(&sbi->s_kobj_unregister); | |
119 | } | |
120 | ||
121 | int __init zonefs_sysfs_init(void) | |
122 | { | |
123 | zonefs_sysfs_root = kobject_create_and_add("zonefs", fs_kobj); | |
124 | if (!zonefs_sysfs_root) | |
125 | return -ENOMEM; | |
126 | ||
127 | return 0; | |
128 | } | |
129 | ||
130 | void zonefs_sysfs_exit(void) | |
131 | { | |
132 | kobject_put(zonefs_sysfs_root); | |
133 | zonefs_sysfs_root = NULL; | |
134 | } |