Skip to content

Commit 2f4d450

Browse files
Miklos Szeredibrauner
authored andcommitted
statmount: add flag to retrieve unescaped options
Filesystem options can be retrieved with STATMOUNT_MNT_OPTS, which returns a string of comma separated options, where some characters are escaped using the \OOO notation. Add a new flag, STATMOUNT_OPT_ARRAY, which instead returns the raw option values separated with '\0' charaters. Since escaped charaters are rare, this inteface is preferable for non-libmount users which likley don't want to deal with option de-escaping. Example code: if (st->mask & STATMOUNT_OPT_ARRAY) { const char *opt = st->str + st->opt_array; for (unsigned int i = 0; i < st->opt_num; i++) { printf("opt_array[%i]: <%s>\n", i, opt); opt += strlen(opt) + 1; } } Example ouput: (1) mnt_opts: <lowerdir+=/l\054w\054r,lowerdir+=/l\054w\054r1,upperdir=/upp\054r,workdir=/w\054rk,redirect_dir=nofollow,uuid=null> (2) opt_array[0]: <lowerdir+=/l,w,r> opt_array[1]: <lowerdir+=/l,w,r1> opt_array[2]: <upperdir=/upp,r> opt_array[3]: <workdir=/w,rk> opt_array[4]: <redirect_dir=nofollow> opt_array[5]: <uuid=null> Signed-off-by: Miklos Szeredi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Acked-by: Jeff Layton <[email protected]> [brauner: tweak variable naming and parsing add example output] Signed-off-by: Christian Brauner <[email protected]>
1 parent 39bb1bf commit 2f4d450

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

fs/namespace.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5072,6 +5072,43 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
50725072
return 0;
50735073
}
50745074

5075+
static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
5076+
{
5077+
struct vfsmount *mnt = s->mnt;
5078+
struct super_block *sb = mnt->mnt_sb;
5079+
size_t start = seq->count;
5080+
char *buf_start, *buf_end, *opt_start, *opt_end;
5081+
u32 count = 0;
5082+
int err;
5083+
5084+
if (!sb->s_op->show_options)
5085+
return 0;
5086+
5087+
buf_start = seq->buf + start;
5088+
err = sb->s_op->show_options(seq, mnt->mnt_root);
5089+
if (err)
5090+
return err;
5091+
5092+
if (unlikely(seq_has_overflowed(seq)))
5093+
return -EAGAIN;
5094+
5095+
if (seq->count == start)
5096+
return 0;
5097+
5098+
buf_end = seq->buf + seq->count;
5099+
*buf_end = '\0';
5100+
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
5101+
opt_end = strchrnul(opt_start, ',');
5102+
*opt_end = '\0';
5103+
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
5104+
if (WARN_ON_ONCE(++count == 0))
5105+
return -EOVERFLOW;
5106+
}
5107+
seq->count = buf_start - 1 - seq->buf;
5108+
s->sm.opt_num = count;
5109+
return 0;
5110+
}
5111+
50755112
static int statmount_string(struct kstatmount *s, u64 flag)
50765113
{
50775114
int ret = 0;
@@ -5097,6 +5134,10 @@ static int statmount_string(struct kstatmount *s, u64 flag)
50975134
sm->mnt_opts = start;
50985135
ret = statmount_mnt_opts(s, seq);
50995136
break;
5137+
case STATMOUNT_OPT_ARRAY:
5138+
sm->opt_array = start;
5139+
ret = statmount_opt_array(s, seq);
5140+
break;
51005141
case STATMOUNT_FS_SUBTYPE:
51015142
sm->fs_subtype = start;
51025143
statmount_fs_subtype(s, seq);
@@ -5250,6 +5291,9 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
52505291
if (!err && s->mask & STATMOUNT_MNT_OPTS)
52515292
err = statmount_string(s, STATMOUNT_MNT_OPTS);
52525293

5294+
if (!err && s->mask & STATMOUNT_OPT_ARRAY)
5295+
err = statmount_string(s, STATMOUNT_OPT_ARRAY);
5296+
52535297
if (!err && s->mask & STATMOUNT_FS_SUBTYPE)
52545298
err = statmount_string(s, STATMOUNT_FS_SUBTYPE);
52555299

@@ -5278,7 +5322,8 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
52785322

52795323
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
52805324
STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
5281-
STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE)
5325+
STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \
5326+
STATMOUNT_OPT_ARRAY)
52825327

52835328
static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
52845329
struct statmount __user *buf, size_t bufsize,

include/uapi/linux/mount.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ struct mount_attr {
154154
*/
155155
struct statmount {
156156
__u32 size; /* Total size, including strings */
157-
__u32 mnt_opts; /* [str] Mount options of the mount */
157+
__u32 mnt_opts; /* [str] Options (comma separated, escaped) */
158158
__u64 mask; /* What results were written */
159159
__u32 sb_dev_major; /* Device ID */
160160
__u32 sb_dev_minor;
@@ -175,7 +175,9 @@ struct statmount {
175175
__u64 mnt_ns_id; /* ID of the mount namespace */
176176
__u32 fs_subtype; /* [str] Subtype of fs_type (if any) */
177177
__u32 sb_source; /* [str] Source string of the mount */
178-
__u64 __spare2[48];
178+
__u32 opt_num; /* Number of fs options */
179+
__u32 opt_array; /* [str] Array of nul terminated fs options */
180+
__u64 __spare2[47];
179181
char str[]; /* Variable size part containing strings */
180182
};
181183

@@ -211,6 +213,7 @@ struct mnt_id_req {
211213
#define STATMOUNT_MNT_OPTS 0x00000080U /* Want/got mnt_opts */
212214
#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
213215
#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
216+
#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
214217

215218
/*
216219
* Special @mnt_id values that can be passed to listmount

0 commit comments

Comments
 (0)