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>
This commit is contained in:
Tejun Heo 2013-11-28 14:54:26 -05:00 committed by Greg Kroah-Hartman
parent 2d0cfbec2a
commit d19b9846df
2 changed files with 35 additions and 13 deletions

View File

@ -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);

View File

@ -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);