aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/sysfs/file.c39
-rw-r--r--include/linux/kernfs.h9
2 files changed, 35 insertions, 13 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 9852450867cf..74e3478d9cb4 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -146,6 +146,7 @@ static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf,
146static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) 146static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos)
147{ 147{
148 struct sysfs_open_file *of = sf->private; 148 struct sysfs_open_file *of = sf->private;
149 const struct kernfs_ops *ops;
149 150
150 /* 151 /*
151 * @of->mutex nests outside active ref and is just to ensure that 152 * @of->mutex nests outside active ref and is just to ensure that
@@ -155,26 +156,42 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos)
155 if (!sysfs_get_active(of->sd)) 156 if (!sysfs_get_active(of->sd))
156 return ERR_PTR(-ENODEV); 157 return ERR_PTR(-ENODEV);
157 158
158 /* 159 ops = kernfs_ops(of->sd);
159 * The same behavior and code as single_open(). Returns !NULL if 160 if (ops->seq_start) {
160 * pos is at the beginning; otherwise, NULL. 161 return ops->seq_start(sf, ppos);
161 */ 162 } else {
162 return NULL + !*ppos; 163 /*
164 * The same behavior and code as single_open(). Returns
165 * !NULL if pos is at the beginning; otherwise, NULL.
166 */
167 return NULL + !*ppos;
168 }
163} 169}
164 170
165static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) 171static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos)
166{ 172{
167 /* 173 struct sysfs_open_file *of = sf->private;
168 * The same behavior and code as single_open(), always terminate 174 const struct kernfs_ops *ops = kernfs_ops(of->sd);
169 * after the initial read. 175
170 */ 176 if (ops->seq_next) {
171 ++*ppos; 177 return ops->seq_next(sf, v, ppos);
172 return NULL; 178 } else {
179 /*
180 * The same behavior and code as single_open(), always
181 * terminate after the initial read.
182 */
183 ++*ppos;
184 return NULL;
185 }
173} 186}
174 187
175static void kernfs_seq_stop(struct seq_file *sf, void *v) 188static void kernfs_seq_stop(struct seq_file *sf, void *v)
176{ 189{
177 struct sysfs_open_file *of = sf->private; 190 struct sysfs_open_file *of = sf->private;
191 const struct kernfs_ops *ops = kernfs_ops(of->sd);
192
193 if (ops->seq_stop)
194 ops->seq_stop(sf, v);
178 195
179 sysfs_put_active(of->sd); 196 sysfs_put_active(of->sd);
180 mutex_unlock(&of->mutex); 197 mutex_unlock(&of->mutex);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index d0912cf02087..ba993ebcd81e 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -37,8 +37,9 @@ struct kernfs_ops {
37 /* 37 /*
38 * Read is handled by either seq_file or raw_read(). 38 * Read is handled by either seq_file or raw_read().
39 * 39 *
40 * If seq_show() is present, seq_file path is active. The behavior 40 * If seq_show() is present, seq_file path is active. Other seq
41 * is equivalent to single_open(). @sf->private points to the 41 * operations are optional and if not implemented, the behavior is
42 * equivalent to single_open(). @sf->private points to the
42 * associated sysfs_open_file. 43 * associated sysfs_open_file.
43 * 44 *
44 * read() is bounced through kernel buffer and a read larger than 45 * read() is bounced through kernel buffer and a read larger than
@@ -46,6 +47,10 @@ struct kernfs_ops {
46 */ 47 */
47 int (*seq_show)(struct seq_file *sf, void *v); 48 int (*seq_show)(struct seq_file *sf, void *v);
48 49
50 void *(*seq_start)(struct seq_file *sf, loff_t *ppos);
51 void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos);
52 void (*seq_stop)(struct seq_file *sf, void *v);
53
49 ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, 54 ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes,
50 loff_t off); 55 loff_t off);
51 56