forked from mirrors/linux
		
	fs: export mount options via statmount()
statmount() can export arbitrary strings, so utilize the __spare1 slot for a mnt_opts string pointer, and then support asking for and setting the mount options during statmount(). This calls into the helper for showing mount options, which already uses a seq_file, so fits in nicely with our existing mechanism for exporting strings via statmount(). Signed-off-by: Josef Bacik <josef@toxicpanda.com> Link: https://lore.kernel.org/r/3aa6bf8bd5d0a21df9ebd63813af8ab532c18276.1719257716.git.josef@toxicpanda.com Reviewed-by: Jeff Layton <jlayton@kernel.org> [brauner: only call sb->s_op->show_options()] Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
		
							parent
							
								
									c72b6b7224
								
							
						
					
					
						commit
						f9af549d1f
					
				
					 2 changed files with 38 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -4980,6 +4980,34 @@ static void statmount_mnt_ns_id(struct kstatmount *s, struct mnt_namespace *ns)
 | 
			
		|||
	s->sm.mnt_ns_id = ns->seq;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
 | 
			
		||||
{
 | 
			
		||||
	struct vfsmount *mnt = s->mnt;
 | 
			
		||||
	struct super_block *sb = mnt->mnt_sb;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (sb->s_op->show_options) {
 | 
			
		||||
		size_t start = seq->count;
 | 
			
		||||
 | 
			
		||||
		err = sb->s_op->show_options(seq, mnt->mnt_root);
 | 
			
		||||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
 | 
			
		||||
		if (unlikely(seq_has_overflowed(seq)))
 | 
			
		||||
			return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
		if (seq->count == start)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		/* skip leading comma */
 | 
			
		||||
		memmove(seq->buf + start, seq->buf + start + 1,
 | 
			
		||||
			seq->count - start - 1);
 | 
			
		||||
		seq->count--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int statmount_string(struct kstatmount *s, u64 flag)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -5000,6 +5028,10 @@ static int statmount_string(struct kstatmount *s, u64 flag)
 | 
			
		|||
		sm->mnt_point = seq->count;
 | 
			
		||||
		ret = statmount_mnt_point(s, seq);
 | 
			
		||||
		break;
 | 
			
		||||
	case STATMOUNT_MNT_OPTS:
 | 
			
		||||
		sm->mnt_opts = seq->count;
 | 
			
		||||
		ret = statmount_mnt_opts(s, seq);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		WARN_ON_ONCE(true);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -5130,6 +5162,9 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
 | 
			
		|||
	if (!err && s->mask & STATMOUNT_MNT_POINT)
 | 
			
		||||
		err = statmount_string(s, STATMOUNT_MNT_POINT);
 | 
			
		||||
 | 
			
		||||
	if (!err && s->mask & STATMOUNT_MNT_OPTS)
 | 
			
		||||
		err = statmount_string(s, STATMOUNT_MNT_OPTS);
 | 
			
		||||
 | 
			
		||||
	if (!err && s->mask & STATMOUNT_MNT_NS_ID)
 | 
			
		||||
		statmount_mnt_ns_id(s, ns);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5151,7 +5186,7 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
 | 
			
		||||
			      STATMOUNT_FS_TYPE)
 | 
			
		||||
			      STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS)
 | 
			
		||||
 | 
			
		||||
static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
 | 
			
		||||
			      struct statmount __user *buf, size_t bufsize,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -154,7 +154,7 @@ struct mount_attr {
 | 
			
		|||
 */
 | 
			
		||||
struct statmount {
 | 
			
		||||
	__u32 size;		/* Total size, including strings */
 | 
			
		||||
	__u32 __spare1;
 | 
			
		||||
	__u32 mnt_opts;		/* [str] Mount options of the mount */
 | 
			
		||||
	__u64 mask;		/* What results were written */
 | 
			
		||||
	__u32 sb_dev_major;	/* Device ID */
 | 
			
		||||
	__u32 sb_dev_minor;
 | 
			
		||||
| 
						 | 
				
			
			@ -206,6 +206,7 @@ struct mnt_id_req {
 | 
			
		|||
#define STATMOUNT_MNT_POINT		0x00000010U	/* Want/got mnt_point */
 | 
			
		||||
#define STATMOUNT_FS_TYPE		0x00000020U	/* Want/got fs_type */
 | 
			
		||||
#define STATMOUNT_MNT_NS_ID		0x00000040U	/* Want/got mnt_ns_id */
 | 
			
		||||
#define STATMOUNT_MNT_OPTS		0x00000080U	/* Want/got mnt_opts */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Special @mnt_id values that can be passed to listmount
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue