18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/proc_namespace.c - handling of /proc/<pid>/{mounts,mountinfo,mountstats}
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * In fact, that's a piece of procfs; it's *almost* isolated from
68c2ecf20Sopenharmony_ci * the rest of fs/proc, but has rather close relationships with
78c2ecf20Sopenharmony_ci * fs/namespace.c, thus here instead of fs/proc
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <linux/mnt_namespace.h>
118c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
128c2ecf20Sopenharmony_ci#include <linux/security.h>
138c2ecf20Sopenharmony_ci#include <linux/fs_struct.h>
148c2ecf20Sopenharmony_ci#include <linux/sched/task.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "proc/internal.h" /* only for get_proc_task() in ->open() */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "pnode.h"
198c2ecf20Sopenharmony_ci#include "internal.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic __poll_t mounts_poll(struct file *file, poll_table *wait)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	struct seq_file *m = file->private_data;
248c2ecf20Sopenharmony_ci	struct proc_mounts *p = m->private;
258c2ecf20Sopenharmony_ci	struct mnt_namespace *ns = p->ns;
268c2ecf20Sopenharmony_ci	__poll_t res = EPOLLIN | EPOLLRDNORM;
278c2ecf20Sopenharmony_ci	int event;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	poll_wait(file, &p->ns->poll, wait);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	event = READ_ONCE(ns->event);
328c2ecf20Sopenharmony_ci	if (m->poll_event != event) {
338c2ecf20Sopenharmony_ci		m->poll_event = event;
348c2ecf20Sopenharmony_ci		res |= EPOLLERR | EPOLLPRI;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return res;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct proc_fs_opts {
418c2ecf20Sopenharmony_ci	int flag;
428c2ecf20Sopenharmony_ci	const char *str;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic int show_sb_opts(struct seq_file *m, struct super_block *sb)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	static const struct proc_fs_opts fs_opts[] = {
488c2ecf20Sopenharmony_ci		{ SB_SYNCHRONOUS, ",sync" },
498c2ecf20Sopenharmony_ci		{ SB_DIRSYNC, ",dirsync" },
508c2ecf20Sopenharmony_ci		{ SB_MANDLOCK, ",mand" },
518c2ecf20Sopenharmony_ci		{ SB_LAZYTIME, ",lazytime" },
528c2ecf20Sopenharmony_ci		{ 0, NULL }
538c2ecf20Sopenharmony_ci	};
548c2ecf20Sopenharmony_ci	const struct proc_fs_opts *fs_infop;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) {
578c2ecf20Sopenharmony_ci		if (sb->s_flags & fs_infop->flag)
588c2ecf20Sopenharmony_ci			seq_puts(m, fs_infop->str);
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	return security_sb_show_options(m, sb);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	static const struct proc_fs_opts mnt_opts[] = {
678c2ecf20Sopenharmony_ci		{ MNT_NOSUID, ",nosuid" },
688c2ecf20Sopenharmony_ci		{ MNT_NODEV, ",nodev" },
698c2ecf20Sopenharmony_ci		{ MNT_NOEXEC, ",noexec" },
708c2ecf20Sopenharmony_ci		{ MNT_NOATIME, ",noatime" },
718c2ecf20Sopenharmony_ci		{ MNT_NODIRATIME, ",nodiratime" },
728c2ecf20Sopenharmony_ci		{ MNT_RELATIME, ",relatime" },
738c2ecf20Sopenharmony_ci		{ MNT_NOSYMFOLLOW, ",nosymfollow" },
748c2ecf20Sopenharmony_ci		{ 0, NULL }
758c2ecf20Sopenharmony_ci	};
768c2ecf20Sopenharmony_ci	const struct proc_fs_opts *fs_infop;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) {
798c2ecf20Sopenharmony_ci		if (mnt->mnt_flags & fs_infop->flag)
808c2ecf20Sopenharmony_ci			seq_puts(m, fs_infop->str);
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic inline void mangle(struct seq_file *m, const char *s)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	seq_escape(m, s, " \t\n\\");
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic void show_type(struct seq_file *m, struct super_block *sb)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	mangle(m, sb->s_type->name);
928c2ecf20Sopenharmony_ci	if (sb->s_subtype) {
938c2ecf20Sopenharmony_ci		seq_putc(m, '.');
948c2ecf20Sopenharmony_ci		mangle(m, sb->s_subtype);
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct proc_mounts *p = m->private;
1018c2ecf20Sopenharmony_ci	struct mount *r = real_mount(mnt);
1028c2ecf20Sopenharmony_ci	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
1038c2ecf20Sopenharmony_ci	struct super_block *sb = mnt_path.dentry->d_sb;
1048c2ecf20Sopenharmony_ci	int err;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (sb->s_op->show_devname) {
1078c2ecf20Sopenharmony_ci		err = sb->s_op->show_devname(m, mnt_path.dentry);
1088c2ecf20Sopenharmony_ci		if (err)
1098c2ecf20Sopenharmony_ci			goto out;
1108c2ecf20Sopenharmony_ci	} else {
1118c2ecf20Sopenharmony_ci		mangle(m, r->mnt_devname ? r->mnt_devname : "none");
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci	seq_putc(m, ' ');
1148c2ecf20Sopenharmony_ci	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
1158c2ecf20Sopenharmony_ci	err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
1168c2ecf20Sopenharmony_ci	if (err)
1178c2ecf20Sopenharmony_ci		goto out;
1188c2ecf20Sopenharmony_ci	seq_putc(m, ' ');
1198c2ecf20Sopenharmony_ci	show_type(m, sb);
1208c2ecf20Sopenharmony_ci	seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
1218c2ecf20Sopenharmony_ci	err = show_sb_opts(m, sb);
1228c2ecf20Sopenharmony_ci	if (err)
1238c2ecf20Sopenharmony_ci		goto out;
1248c2ecf20Sopenharmony_ci	show_mnt_opts(m, mnt);
1258c2ecf20Sopenharmony_ci	if (sb->s_op->show_options)
1268c2ecf20Sopenharmony_ci		err = sb->s_op->show_options(m, mnt_path.dentry);
1278c2ecf20Sopenharmony_ci	seq_puts(m, " 0 0\n");
1288c2ecf20Sopenharmony_ciout:
1298c2ecf20Sopenharmony_ci	return err;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct proc_mounts *p = m->private;
1358c2ecf20Sopenharmony_ci	struct mount *r = real_mount(mnt);
1368c2ecf20Sopenharmony_ci	struct super_block *sb = mnt->mnt_sb;
1378c2ecf20Sopenharmony_ci	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
1388c2ecf20Sopenharmony_ci	int err;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
1418c2ecf20Sopenharmony_ci		   MAJOR(sb->s_dev), MINOR(sb->s_dev));
1428c2ecf20Sopenharmony_ci	if (sb->s_op->show_path) {
1438c2ecf20Sopenharmony_ci		err = sb->s_op->show_path(m, mnt->mnt_root);
1448c2ecf20Sopenharmony_ci		if (err)
1458c2ecf20Sopenharmony_ci			goto out;
1468c2ecf20Sopenharmony_ci	} else {
1478c2ecf20Sopenharmony_ci		seq_dentry(m, mnt->mnt_root, " \t\n\\");
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci	seq_putc(m, ' ');
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
1528c2ecf20Sopenharmony_ci	err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
1538c2ecf20Sopenharmony_ci	if (err)
1548c2ecf20Sopenharmony_ci		goto out;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
1578c2ecf20Sopenharmony_ci	show_mnt_opts(m, mnt);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* Tagged fields ("foo:X" or "bar") */
1608c2ecf20Sopenharmony_ci	if (IS_MNT_SHARED(r))
1618c2ecf20Sopenharmony_ci		seq_printf(m, " shared:%i", r->mnt_group_id);
1628c2ecf20Sopenharmony_ci	if (IS_MNT_SLAVE(r)) {
1638c2ecf20Sopenharmony_ci		int master = r->mnt_master->mnt_group_id;
1648c2ecf20Sopenharmony_ci		int dom = get_dominating_id(r, &p->root);
1658c2ecf20Sopenharmony_ci		seq_printf(m, " master:%i", master);
1668c2ecf20Sopenharmony_ci		if (dom && dom != master)
1678c2ecf20Sopenharmony_ci			seq_printf(m, " propagate_from:%i", dom);
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci	if (IS_MNT_UNBINDABLE(r))
1708c2ecf20Sopenharmony_ci		seq_puts(m, " unbindable");
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* Filesystem specific data */
1738c2ecf20Sopenharmony_ci	seq_puts(m, " - ");
1748c2ecf20Sopenharmony_ci	show_type(m, sb);
1758c2ecf20Sopenharmony_ci	seq_putc(m, ' ');
1768c2ecf20Sopenharmony_ci	if (sb->s_op->show_devname) {
1778c2ecf20Sopenharmony_ci		err = sb->s_op->show_devname(m, mnt->mnt_root);
1788c2ecf20Sopenharmony_ci		if (err)
1798c2ecf20Sopenharmony_ci			goto out;
1808c2ecf20Sopenharmony_ci	} else {
1818c2ecf20Sopenharmony_ci		mangle(m, r->mnt_devname ? r->mnt_devname : "none");
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci	seq_puts(m, sb_rdonly(sb) ? " ro" : " rw");
1848c2ecf20Sopenharmony_ci	err = show_sb_opts(m, sb);
1858c2ecf20Sopenharmony_ci	if (err)
1868c2ecf20Sopenharmony_ci		goto out;
1878c2ecf20Sopenharmony_ci	if (sb->s_op->show_options)
1888c2ecf20Sopenharmony_ci		err = sb->s_op->show_options(m, mnt->mnt_root);
1898c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
1908c2ecf20Sopenharmony_ciout:
1918c2ecf20Sopenharmony_ci	return err;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct proc_mounts *p = m->private;
1978c2ecf20Sopenharmony_ci	struct mount *r = real_mount(mnt);
1988c2ecf20Sopenharmony_ci	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
1998c2ecf20Sopenharmony_ci	struct super_block *sb = mnt_path.dentry->d_sb;
2008c2ecf20Sopenharmony_ci	int err;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* device */
2038c2ecf20Sopenharmony_ci	if (sb->s_op->show_devname) {
2048c2ecf20Sopenharmony_ci		seq_puts(m, "device ");
2058c2ecf20Sopenharmony_ci		err = sb->s_op->show_devname(m, mnt_path.dentry);
2068c2ecf20Sopenharmony_ci		if (err)
2078c2ecf20Sopenharmony_ci			goto out;
2088c2ecf20Sopenharmony_ci	} else {
2098c2ecf20Sopenharmony_ci		if (r->mnt_devname) {
2108c2ecf20Sopenharmony_ci			seq_puts(m, "device ");
2118c2ecf20Sopenharmony_ci			mangle(m, r->mnt_devname);
2128c2ecf20Sopenharmony_ci		} else
2138c2ecf20Sopenharmony_ci			seq_puts(m, "no device");
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/* mount point */
2178c2ecf20Sopenharmony_ci	seq_puts(m, " mounted on ");
2188c2ecf20Sopenharmony_ci	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
2198c2ecf20Sopenharmony_ci	err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
2208c2ecf20Sopenharmony_ci	if (err)
2218c2ecf20Sopenharmony_ci		goto out;
2228c2ecf20Sopenharmony_ci	seq_putc(m, ' ');
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* file system type */
2258c2ecf20Sopenharmony_ci	seq_puts(m, "with fstype ");
2268c2ecf20Sopenharmony_ci	show_type(m, sb);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/* optional statistics */
2298c2ecf20Sopenharmony_ci	if (sb->s_op->show_stats) {
2308c2ecf20Sopenharmony_ci		seq_putc(m, ' ');
2318c2ecf20Sopenharmony_ci		err = sb->s_op->show_stats(m, mnt_path.dentry);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	seq_putc(m, '\n');
2358c2ecf20Sopenharmony_ciout:
2368c2ecf20Sopenharmony_ci	return err;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic int mounts_open_common(struct inode *inode, struct file *file,
2408c2ecf20Sopenharmony_ci			      int (*show)(struct seq_file *, struct vfsmount *))
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct task_struct *task = get_proc_task(inode);
2438c2ecf20Sopenharmony_ci	struct nsproxy *nsp;
2448c2ecf20Sopenharmony_ci	struct mnt_namespace *ns = NULL;
2458c2ecf20Sopenharmony_ci	struct path root;
2468c2ecf20Sopenharmony_ci	struct proc_mounts *p;
2478c2ecf20Sopenharmony_ci	struct seq_file *m;
2488c2ecf20Sopenharmony_ci	int ret = -EINVAL;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!task)
2518c2ecf20Sopenharmony_ci		goto err;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	task_lock(task);
2548c2ecf20Sopenharmony_ci	nsp = task->nsproxy;
2558c2ecf20Sopenharmony_ci	if (!nsp || !nsp->mnt_ns) {
2568c2ecf20Sopenharmony_ci		task_unlock(task);
2578c2ecf20Sopenharmony_ci		put_task_struct(task);
2588c2ecf20Sopenharmony_ci		goto err;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci	ns = nsp->mnt_ns;
2618c2ecf20Sopenharmony_ci	get_mnt_ns(ns);
2628c2ecf20Sopenharmony_ci	if (!task->fs) {
2638c2ecf20Sopenharmony_ci		task_unlock(task);
2648c2ecf20Sopenharmony_ci		put_task_struct(task);
2658c2ecf20Sopenharmony_ci		ret = -ENOENT;
2668c2ecf20Sopenharmony_ci		goto err_put_ns;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	get_fs_root(task->fs, &root);
2698c2ecf20Sopenharmony_ci	task_unlock(task);
2708c2ecf20Sopenharmony_ci	put_task_struct(task);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts));
2738c2ecf20Sopenharmony_ci	if (ret)
2748c2ecf20Sopenharmony_ci		goto err_put_path;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	m = file->private_data;
2778c2ecf20Sopenharmony_ci	m->poll_event = ns->event;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	p = m->private;
2808c2ecf20Sopenharmony_ci	p->ns = ns;
2818c2ecf20Sopenharmony_ci	p->root = root;
2828c2ecf20Sopenharmony_ci	p->show = show;
2838c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&p->cursor.mnt_list);
2848c2ecf20Sopenharmony_ci	p->cursor.mnt.mnt_flags = MNT_CURSOR;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return 0;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci err_put_path:
2898c2ecf20Sopenharmony_ci	path_put(&root);
2908c2ecf20Sopenharmony_ci err_put_ns:
2918c2ecf20Sopenharmony_ci	put_mnt_ns(ns);
2928c2ecf20Sopenharmony_ci err:
2938c2ecf20Sopenharmony_ci	return ret;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic int mounts_release(struct inode *inode, struct file *file)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct seq_file *m = file->private_data;
2998c2ecf20Sopenharmony_ci	struct proc_mounts *p = m->private;
3008c2ecf20Sopenharmony_ci	path_put(&p->root);
3018c2ecf20Sopenharmony_ci	mnt_cursor_del(p->ns, &p->cursor);
3028c2ecf20Sopenharmony_ci	put_mnt_ns(p->ns);
3038c2ecf20Sopenharmony_ci	return seq_release_private(inode, file);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int mounts_open(struct inode *inode, struct file *file)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	return mounts_open_common(inode, file, show_vfsmnt);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int mountinfo_open(struct inode *inode, struct file *file)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	return mounts_open_common(inode, file, show_mountinfo);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int mountstats_open(struct inode *inode, struct file *file)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	return mounts_open_common(inode, file, show_vfsstat);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciconst struct file_operations proc_mounts_operations = {
3228c2ecf20Sopenharmony_ci	.open		= mounts_open,
3238c2ecf20Sopenharmony_ci	.read_iter	= seq_read_iter,
3248c2ecf20Sopenharmony_ci	.splice_read	= generic_file_splice_read,
3258c2ecf20Sopenharmony_ci	.llseek		= seq_lseek,
3268c2ecf20Sopenharmony_ci	.release	= mounts_release,
3278c2ecf20Sopenharmony_ci	.poll		= mounts_poll,
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ciconst struct file_operations proc_mountinfo_operations = {
3318c2ecf20Sopenharmony_ci	.open		= mountinfo_open,
3328c2ecf20Sopenharmony_ci	.read_iter	= seq_read_iter,
3338c2ecf20Sopenharmony_ci	.splice_read	= generic_file_splice_read,
3348c2ecf20Sopenharmony_ci	.llseek		= seq_lseek,
3358c2ecf20Sopenharmony_ci	.release	= mounts_release,
3368c2ecf20Sopenharmony_ci	.poll		= mounts_poll,
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ciconst struct file_operations proc_mountstats_operations = {
3408c2ecf20Sopenharmony_ci	.open		= mountstats_open,
3418c2ecf20Sopenharmony_ci	.read_iter	= seq_read_iter,
3428c2ecf20Sopenharmony_ci	.splice_read	= generic_file_splice_read,
3438c2ecf20Sopenharmony_ci	.llseek		= seq_lseek,
3448c2ecf20Sopenharmony_ci	.release	= mounts_release,
3458c2ecf20Sopenharmony_ci};
346