Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d19b9846 authored by Tejun Heo's avatar Tejun Heo Committed by Greg Kroah-Hartman
Browse files

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: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2d0cfbec
Loading
Loading
Loading
Loading
+28 −11
Original line number Diff line number Diff line
@@ -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);

	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.
		 * 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)
{
	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.
		 * 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);
+7 −2
Original line number Diff line number Diff line
@@ -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);