summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-11-28 14:54:26 -0500
committerPawel Osmialowski <p.osmialowsk@mcdsrvbld02.digital.local>2015-03-27 18:13:16 +0100
commit291b9c03dfe7830a829c99779090903c8e76351c (patch)
treeaefac32bff8da0c56f114e1fde9eef225a78a7a2
parent8f0331d7f6d54be4cf51efcd14df9787293dda35 (diff)
downloadlinux-3.10-291b9c03dfe7830a829c99779090903c8e76351c.tar.gz
linux-3.10-291b9c03dfe7830a829c99779090903c8e76351c.tar.bz2
linux-3.10-291b9c03dfe7830a829c99779090903c8e76351c.zip
sysfs, kernfs: add kernfs_ops->seq_{start|next|stop}()
kernfs_ops currently only supports single_open() behavior which is pretty restrictive. Add optional callbacks ->seq_{start|next|stop}() which, when implemented, are invoked for seq_file traversal. This allows full seq_file functionality for kernfs users. This currently doesn't have any user and doesn't change any behavior. v2: Refreshed on top of the updated "sysfs, kernfs: prepare read path for kernfs". Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 9852450867c..74e3478d9cb 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,
static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos)
{
struct sysfs_open_file *of = sf->private;
+ const struct kernfs_ops *ops;
/*
* @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)
if (!sysfs_get_active(of->sd))
return ERR_PTR(-ENODEV);
- /*
- * The same behavior and code as single_open(). Returns !NULL if
- * pos is at the beginning; otherwise, NULL.
- */
- return NULL + !*ppos;
+ ops = kernfs_ops(of->sd);
+ if (ops->seq_start) {
+ return ops->seq_start(sf, ppos);
+ } else {
+ /*
+ * The same behavior and code as single_open(). Returns
+ * !NULL if pos is at the beginning; otherwise, NULL.
+ */
+ return NULL + !*ppos;
+ }
}
static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos)
{
- /*
- * The same behavior and code as single_open(), always terminate
- * after the initial read.
- */
- ++*ppos;
- return NULL;
+ struct sysfs_open_file *of = sf->private;
+ const struct kernfs_ops *ops = kernfs_ops(of->sd);
+
+ if (ops->seq_next) {
+ return ops->seq_next(sf, v, ppos);
+ } else {
+ /*
+ * The same behavior and code as single_open(), always
+ * terminate after the initial read.
+ */
+ ++*ppos;
+ return NULL;
+ }
}
static void kernfs_seq_stop(struct seq_file *sf, void *v)
{
struct sysfs_open_file *of = sf->private;
+ const struct kernfs_ops *ops = kernfs_ops(of->sd);
+
+ if (ops->seq_stop)
+ ops->seq_stop(sf, v);
sysfs_put_active(of->sd);
mutex_unlock(&of->mutex);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index d0912cf0208..ba993ebcd81 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -37,8 +37,9 @@ struct kernfs_ops {
/*
* Read is handled by either seq_file or raw_read().
*
- * If seq_show() is present, seq_file path is active. The behavior
- * is equivalent to single_open(). @sf->private points to the
+ * If seq_show() is present, seq_file path is active. Other seq
+ * operations are optional and if not implemented, the behavior is
+ * equivalent to single_open(). @sf->private points to the
* associated sysfs_open_file.
*
* read() is bounced through kernel buffer and a read larger than
@@ -46,6 +47,10 @@ struct kernfs_ops {
*/
int (*seq_show)(struct seq_file *sf, void *v);
+ void *(*seq_start)(struct seq_file *sf, loff_t *ppos);
+ void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos);
+ void (*seq_stop)(struct seq_file *sf, void *v);
+
ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes,
loff_t off);