1

vfs-6.11.mount.api

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZpEGjAAKCRCRxhvAZXjc
 okXfAP4tFUYszUsSqYdsgy9UvXw3Dr5zOIzQmN++NdjGkbU5fgEAs2ystqEfJgr3
 v7XvGbu65CvL4/slNhBZOU4yekGx5Qc=
 =C4QD
 -----END PGP SIGNATURE-----

Merge tag 'vfs-6.11.mount.api' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs mount API updates from Christian Brauner:

 - Add a generic helper to parse uid and gid mount options.

   Currently we open-code the same logic in various filesystems which is
   error prone, especially since the verification of uid and gid mount
   options is a sensitive operation in the face of idmappings.

   Add a generic helper and convert all filesystems over to it. Make
   sure that filesystems that are mountable in unprivileged containers
   verify that the specified uid and gid can be represented in the
   owning namespace of the filesystem.

 - Convert hostfs to the new mount api.

* tag 'vfs-6.11.mount.api' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  fuse: Convert to new uid/gid option parsing helpers
  fuse: verify {g,u}id mount options correctly
  fat: Convert to new uid/gid option parsing helpers
  fat: Convert to new mount api
  fat: move debug into fat_mount_options
  vboxsf: Convert to new uid/gid option parsing helpers
  tracefs: Convert to new uid/gid option parsing helpers
  smb: client: Convert to new uid/gid option parsing helpers
  tmpfs: Convert to new uid/gid option parsing helpers
  ntfs3: Convert to new uid/gid option parsing helpers
  isofs: Convert to new uid/gid option parsing helpers
  hugetlbfs: Convert to new uid/gid option parsing helpers
  ext4: Convert to new uid/gid option parsing helpers
  exfat: Convert to new uid/gid option parsing helpers
  efivarfs: Convert to new uid/gid option parsing helpers
  debugfs: Convert to new uid/gid option parsing helpers
  autofs: Convert to new uid/gid option parsing helpers
  fs_parse: add uid & gid option option parsing helpers
  hostfs: Add const qualifier to host_root in hostfs_fill_super()
  hostfs: convert hostfs to use the new mount API
This commit is contained in:
Linus Torvalds 2024-07-15 11:31:32 -07:00
commit b8fc1bd73a
21 changed files with 597 additions and 530 deletions

View File

@ -645,6 +645,8 @@ The members are as follows:
fs_param_is_blockdev Blockdev path * Needs lookup
fs_param_is_path Path * Needs lookup
fs_param_is_fd File descriptor result->int_32
fs_param_is_uid User ID (u32) result->uid
fs_param_is_gid Group ID (u32) result->gid
======================= ======================= =====================
Note that if the value is of fs_param_is_bool type, fs_parse() will try
@ -678,6 +680,8 @@ The members are as follows:
fsparam_bdev() fs_param_is_blockdev
fsparam_path() fs_param_is_path
fsparam_fd() fs_param_is_fd
fsparam_uid() fs_param_is_uid
fsparam_gid() fs_param_is_gid
======================= ===============================================
all of which take two arguments, name string and option number - for
@ -784,8 +788,9 @@ process the parameters it is given.
option number (which it returns).
If successful, and if the parameter type indicates the result is a
boolean, integer or enum type, the value is converted by this function and
the result stored in result->{boolean,int_32,uint_32,uint_64}.
boolean, integer, enum, uid, or gid type, the value is converted by this
function and the result stored in
result->{boolean,int_32,uint_32,uint_64,uid,gid}.
If a match isn't initially made, the key is prefixed with "no" and no
value is present then an attempt will be made to look up the key with the

View File

@ -126,7 +126,7 @@ enum {
const struct fs_parameter_spec autofs_param_specs[] = {
fsparam_flag ("direct", Opt_direct),
fsparam_fd ("fd", Opt_fd),
fsparam_u32 ("gid", Opt_gid),
fsparam_gid ("gid", Opt_gid),
fsparam_flag ("ignore", Opt_ignore),
fsparam_flag ("indirect", Opt_indirect),
fsparam_u32 ("maxproto", Opt_maxproto),
@ -134,7 +134,7 @@ const struct fs_parameter_spec autofs_param_specs[] = {
fsparam_flag ("offset", Opt_offset),
fsparam_u32 ("pgrp", Opt_pgrp),
fsparam_flag ("strictexpire", Opt_strictexpire),
fsparam_u32 ("uid", Opt_uid),
fsparam_uid ("uid", Opt_uid),
{}
};
@ -193,8 +193,6 @@ static int autofs_parse_param(struct fs_context *fc, struct fs_parameter *param)
struct autofs_fs_context *ctx = fc->fs_private;
struct autofs_sb_info *sbi = fc->s_fs_info;
struct fs_parse_result result;
kuid_t uid;
kgid_t gid;
int opt;
opt = fs_parse(fc, autofs_param_specs, param, &result);
@ -205,16 +203,10 @@ static int autofs_parse_param(struct fs_context *fc, struct fs_parameter *param)
case Opt_fd:
return autofs_parse_fd(fc, sbi, param, &result);
case Opt_uid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
return invalfc(fc, "Invalid uid");
ctx->uid = uid;
ctx->uid = result.uid;
break;
case Opt_gid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
return invalfc(fc, "Invalid gid");
ctx->gid = gid;
ctx->gid = result.gid;
break;
case Opt_pgrp:
ctx->pgrp = result.uint_32;

View File

@ -92,9 +92,9 @@ enum {
};
static const struct fs_parameter_spec debugfs_param_specs[] = {
fsparam_u32 ("gid", Opt_gid),
fsparam_gid ("gid", Opt_gid),
fsparam_u32oct ("mode", Opt_mode),
fsparam_u32 ("uid", Opt_uid),
fsparam_uid ("uid", Opt_uid),
{}
};
@ -102,8 +102,6 @@ static int debugfs_parse_param(struct fs_context *fc, struct fs_parameter *param
{
struct debugfs_fs_info *opts = fc->s_fs_info;
struct fs_parse_result result;
kuid_t uid;
kgid_t gid;
int opt;
opt = fs_parse(fc, debugfs_param_specs, param, &result);
@ -120,16 +118,10 @@ static int debugfs_parse_param(struct fs_context *fc, struct fs_parameter *param
switch (opt) {
case Opt_uid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
return invalf(fc, "Unknown uid");
opts->uid = uid;
opts->uid = result.uid;
break;
case Opt_gid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
return invalf(fc, "Unknown gid");
opts->gid = gid;
opts->gid = result.gid;
break;
case Opt_mode:
opts->mode = result.uint_32 & S_IALLUGO;

View File

@ -275,8 +275,8 @@ enum {
};
static const struct fs_parameter_spec efivarfs_parameters[] = {
fsparam_u32("uid", Opt_uid),
fsparam_u32("gid", Opt_gid),
fsparam_uid("uid", Opt_uid),
fsparam_gid("gid", Opt_gid),
{},
};
@ -293,14 +293,10 @@ static int efivarfs_parse_param(struct fs_context *fc, struct fs_parameter *para
switch (opt) {
case Opt_uid:
opts->uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(opts->uid))
return -EINVAL;
opts->uid = result.uid;
break;
case Opt_gid:
opts->gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(opts->gid))
return -EINVAL;
opts->gid = result.gid;
break;
default:
return -EINVAL;

View File

@ -225,8 +225,8 @@ static const struct constant_table exfat_param_enums[] = {
};
static const struct fs_parameter_spec exfat_parameters[] = {
fsparam_u32("uid", Opt_uid),
fsparam_u32("gid", Opt_gid),
fsparam_uid("uid", Opt_uid),
fsparam_gid("gid", Opt_gid),
fsparam_u32oct("umask", Opt_umask),
fsparam_u32oct("dmask", Opt_dmask),
fsparam_u32oct("fmask", Opt_fmask),
@ -262,10 +262,10 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
switch (opt) {
case Opt_uid:
opts->fs_uid = make_kuid(current_user_ns(), result.uint_32);
opts->fs_uid = result.uid;
break;
case Opt_gid:
opts->fs_gid = make_kgid(current_user_ns(), result.uint_32);
opts->fs_gid = result.gid;
break;
case Opt_umask:
opts->fs_fmask = result.uint_32;

View File

@ -1721,8 +1721,8 @@ static const struct fs_parameter_spec ext4_param_specs[] = {
fsparam_flag ("bsdgroups", Opt_grpid),
fsparam_flag ("nogrpid", Opt_nogrpid),
fsparam_flag ("sysvgroups", Opt_nogrpid),
fsparam_u32 ("resgid", Opt_resgid),
fsparam_u32 ("resuid", Opt_resuid),
fsparam_gid ("resgid", Opt_resgid),
fsparam_uid ("resuid", Opt_resuid),
fsparam_u32 ("sb", Opt_sb),
fsparam_enum ("errors", Opt_errors, ext4_param_errors),
fsparam_flag ("nouid32", Opt_nouid32),
@ -2127,8 +2127,6 @@ static int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param)
struct fs_parse_result result;
const struct mount_opts *m;
int is_remount;
kuid_t uid;
kgid_t gid;
int token;
token = fs_parse(fc, ext4_param_specs, param, &result);
@ -2270,23 +2268,11 @@ static int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param)
ctx->spec |= EXT4_SPEC_s_stripe;
return 0;
case Opt_resuid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid)) {
ext4_msg(NULL, KERN_ERR, "Invalid uid value %d",
result.uint_32);
return -EINVAL;
}
ctx->s_resuid = uid;
ctx->s_resuid = result.uid;
ctx->spec |= EXT4_SPEC_s_resuid;
return 0;
case Opt_resgid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid)) {
ext4_msg(NULL, KERN_ERR, "Invalid gid value %d",
result.uint_32);
return -EINVAL;
}
ctx->s_resgid = gid;
ctx->s_resgid = result.gid;
ctx->spec |= EXT4_SPEC_s_resgid;
return 0;
case Opt_journal_dev:

View File

@ -7,6 +7,8 @@
#include <linux/hash.h>
#include <linux/ratelimit.h>
#include <linux/msdos_fs.h>
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
/*
* vfat shortname flags
@ -51,7 +53,8 @@ struct fat_mount_options {
tz_set:1, /* Filesystem timestamps' offset set */
rodir:1, /* allow ATTR_RO for directory */
discard:1, /* Issue discard requests on deletions */
dos1xfloppy:1; /* Assume default BPB for DOS 1.x floppies */
dos1xfloppy:1, /* Assume default BPB for DOS 1.x floppies */
debug:1; /* Not currently used */
};
#define FAT_HASH_BITS 8
@ -415,12 +418,21 @@ extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
extern struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, loff_t i_pos);
extern int fat_sync_inode(struct inode *inode);
extern int fat_fill_super(struct super_block *sb, void *data, int silent,
int isvfat, void (*setup)(struct super_block *));
extern int fat_fill_super(struct super_block *sb, struct fs_context *fc,
void (*setup)(struct super_block *));
extern int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
struct inode *i2);
extern const struct fs_parameter_spec fat_param_spec[];
int fat_init_fs_context(struct fs_context *fc, bool is_vfat);
void fat_free_fc(struct fs_context *fc);
int fat_parse_param(struct fs_context *fc, struct fs_parameter *param,
bool is_vfat);
int fat_reconfigure(struct fs_context *fc);
static inline unsigned long fat_dir_hash(int logstart)
{
return hash_32(logstart, FAT_HASH_BITS);

View File

@ -16,7 +16,6 @@
#include <linux/mpage.h>
#include <linux/vfs.h>
#include <linux/seq_file.h>
#include <linux/parser.h>
#include <linux/uio.h>
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
@ -804,16 +803,17 @@ static void __exit fat_destroy_inodecache(void)
kmem_cache_destroy(fat_inode_cachep);
}
static int fat_remount(struct super_block *sb, int *flags, char *data)
int fat_reconfigure(struct fs_context *fc)
{
bool new_rdonly;
struct super_block *sb = fc->root->d_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
*flags |= SB_NODIRATIME | (sbi->options.isvfat ? 0 : SB_NOATIME);
fc->sb_flags |= SB_NODIRATIME | (sbi->options.isvfat ? 0 : SB_NOATIME);
sync_filesystem(sb);
/* make sure we update state on remount. */
new_rdonly = *flags & SB_RDONLY;
new_rdonly = fc->sb_flags & SB_RDONLY;
if (new_rdonly != sb_rdonly(sb)) {
if (new_rdonly)
fat_set_state(sb, 0, 0);
@ -822,6 +822,7 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
}
return 0;
}
EXPORT_SYMBOL_GPL(fat_reconfigure);
static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
{
@ -939,8 +940,6 @@ static const struct super_operations fat_sops = {
.evict_inode = fat_evict_inode,
.put_super = fat_put_super,
.statfs = fat_statfs,
.remount_fs = fat_remount,
.show_options = fat_show_options,
};
@ -1037,355 +1036,282 @@ static int fat_show_options(struct seq_file *m, struct dentry *root)
}
enum {
Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage,
Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug,
Opt_immutable, Opt_dots, Opt_nodots,
Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy,
Opt_check, Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask,
Opt_allow_utime, Opt_codepage, Opt_usefree, Opt_nocase, Opt_quiet,
Opt_showexec, Opt_debug, Opt_immutable, Opt_dots, Opt_dotsOK,
Opt_charset, Opt_shortname, Opt_utf8, Opt_utf8_bool,
Opt_uni_xl, Opt_uni_xl_bool, Opt_nonumtail, Opt_nonumtail_bool,
Opt_obsolete, Opt_flush, Opt_tz, Opt_rodir, Opt_errors, Opt_discard,
Opt_nfs, Opt_nfs_enum, Opt_time_offset, Opt_dos1xfloppy,
};
static const match_table_t fat_tokens = {
{Opt_check_r, "check=relaxed"},
{Opt_check_s, "check=strict"},
{Opt_check_n, "check=normal"},
{Opt_check_r, "check=r"},
{Opt_check_s, "check=s"},
{Opt_check_n, "check=n"},
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{Opt_umask, "umask=%o"},
{Opt_dmask, "dmask=%o"},
{Opt_fmask, "fmask=%o"},
{Opt_allow_utime, "allow_utime=%o"},
{Opt_codepage, "codepage=%u"},
{Opt_usefree, "usefree"},
{Opt_nocase, "nocase"},
{Opt_quiet, "quiet"},
{Opt_showexec, "showexec"},
{Opt_debug, "debug"},
{Opt_immutable, "sys_immutable"},
{Opt_flush, "flush"},
{Opt_tz_utc, "tz=UTC"},
{Opt_time_offset, "time_offset=%d"},
{Opt_err_cont, "errors=continue"},
{Opt_err_panic, "errors=panic"},
{Opt_err_ro, "errors=remount-ro"},
{Opt_discard, "discard"},
{Opt_nfs_stale_rw, "nfs"},
{Opt_nfs_stale_rw, "nfs=stale_rw"},
{Opt_nfs_nostale_ro, "nfs=nostale_ro"},
{Opt_dos1xfloppy, "dos1xfloppy"},
{Opt_obsolete, "conv=binary"},
{Opt_obsolete, "conv=text"},
{Opt_obsolete, "conv=auto"},
{Opt_obsolete, "conv=b"},
{Opt_obsolete, "conv=t"},
{Opt_obsolete, "conv=a"},
{Opt_obsolete, "fat=%u"},
{Opt_obsolete, "blocksize=%u"},
{Opt_obsolete, "cvf_format=%20s"},
{Opt_obsolete, "cvf_options=%100s"},
{Opt_obsolete, "posix"},
{Opt_err, NULL},
};
static const match_table_t msdos_tokens = {
{Opt_nodots, "nodots"},
{Opt_nodots, "dotsOK=no"},
{Opt_dots, "dots"},
{Opt_dots, "dotsOK=yes"},
{Opt_err, NULL}
};
static const match_table_t vfat_tokens = {
{Opt_charset, "iocharset=%s"},
{Opt_shortname_lower, "shortname=lower"},
{Opt_shortname_win95, "shortname=win95"},
{Opt_shortname_winnt, "shortname=winnt"},
{Opt_shortname_mixed, "shortname=mixed"},
{Opt_utf8_no, "utf8=0"}, /* 0 or no or false */
{Opt_utf8_no, "utf8=no"},
{Opt_utf8_no, "utf8=false"},
{Opt_utf8_yes, "utf8=1"}, /* empty or 1 or yes or true */
{Opt_utf8_yes, "utf8=yes"},
{Opt_utf8_yes, "utf8=true"},
{Opt_utf8_yes, "utf8"},
{Opt_uni_xl_no, "uni_xlate=0"}, /* 0 or no or false */
{Opt_uni_xl_no, "uni_xlate=no"},
{Opt_uni_xl_no, "uni_xlate=false"},
{Opt_uni_xl_yes, "uni_xlate=1"}, /* empty or 1 or yes or true */
{Opt_uni_xl_yes, "uni_xlate=yes"},
{Opt_uni_xl_yes, "uni_xlate=true"},
{Opt_uni_xl_yes, "uni_xlate"},
{Opt_nonumtail_no, "nonumtail=0"}, /* 0 or no or false */
{Opt_nonumtail_no, "nonumtail=no"},
{Opt_nonumtail_no, "nonumtail=false"},
{Opt_nonumtail_yes, "nonumtail=1"}, /* empty or 1 or yes or true */
{Opt_nonumtail_yes, "nonumtail=yes"},
{Opt_nonumtail_yes, "nonumtail=true"},
{Opt_nonumtail_yes, "nonumtail"},
{Opt_rodir, "rodir"},
{Opt_err, NULL}
static const struct constant_table fat_param_check[] = {
{"relaxed", 'r'},
{"r", 'r'},
{"strict", 's'},
{"s", 's'},
{"normal", 'n'},
{"n", 'n'},
{}
};
static int parse_options(struct super_block *sb, char *options, int is_vfat,
int silent, int *debug, struct fat_mount_options *opts)
static const struct constant_table fat_param_tz[] = {
{"UTC", 0},
{}
};
static const struct constant_table fat_param_errors[] = {
{"continue", FAT_ERRORS_CONT},
{"panic", FAT_ERRORS_PANIC},
{"remount-ro", FAT_ERRORS_RO},
{}
};
static const struct constant_table fat_param_nfs[] = {
{"stale_rw", FAT_NFS_STALE_RW},
{"nostale_ro", FAT_NFS_NOSTALE_RO},
{}
};
/*
* These are all obsolete but we still reject invalid options.
* The corresponding values are therefore meaningless.
*/
static const struct constant_table fat_param_conv[] = {
{"binary", 0},
{"text", 0},
{"auto", 0},
{"b", 0},
{"t", 0},
{"a", 0},
{}
};
/* Core options. See below for vfat and msdos extras */
const struct fs_parameter_spec fat_param_spec[] = {
fsparam_enum ("check", Opt_check, fat_param_check),
fsparam_uid ("uid", Opt_uid),
fsparam_gid ("gid", Opt_gid),
fsparam_u32oct ("umask", Opt_umask),
fsparam_u32oct ("dmask", Opt_dmask),
fsparam_u32oct ("fmask", Opt_fmask),
fsparam_u32oct ("allow_utime", Opt_allow_utime),
fsparam_u32 ("codepage", Opt_codepage),
fsparam_flag ("usefree", Opt_usefree),
fsparam_flag ("nocase", Opt_nocase),
fsparam_flag ("quiet", Opt_quiet),
fsparam_flag ("showexec", Opt_showexec),
fsparam_flag ("debug", Opt_debug),
fsparam_flag ("sys_immutable", Opt_immutable),
fsparam_flag ("flush", Opt_flush),
fsparam_enum ("tz", Opt_tz, fat_param_tz),
fsparam_s32 ("time_offset", Opt_time_offset),
fsparam_enum ("errors", Opt_errors, fat_param_errors),
fsparam_flag ("discard", Opt_discard),
fsparam_flag ("nfs", Opt_nfs),
fsparam_enum ("nfs", Opt_nfs_enum, fat_param_nfs),
fsparam_flag ("dos1xfloppy", Opt_dos1xfloppy),
__fsparam(fs_param_is_enum, "conv",
Opt_obsolete, fs_param_deprecated, fat_param_conv),
__fsparam(fs_param_is_u32, "fat",
Opt_obsolete, fs_param_deprecated, NULL),
__fsparam(fs_param_is_u32, "blocksize",
Opt_obsolete, fs_param_deprecated, NULL),
__fsparam(fs_param_is_string, "cvf_format",
Opt_obsolete, fs_param_deprecated, NULL),
__fsparam(fs_param_is_string, "cvf_options",
Opt_obsolete, fs_param_deprecated, NULL),
__fsparam(NULL, "posix",
Opt_obsolete, fs_param_deprecated, NULL),
{}
};
EXPORT_SYMBOL_GPL(fat_param_spec);
static const struct fs_parameter_spec msdos_param_spec[] = {
fsparam_flag_no ("dots", Opt_dots),
fsparam_bool ("dotsOK", Opt_dotsOK),
{}
};
static const struct constant_table fat_param_shortname[] = {
{"lower", VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95},
{"win95", VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95},
{"winnt", VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT},
{"mixed", VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95},
{}
};
static const struct fs_parameter_spec vfat_param_spec[] = {
fsparam_string ("iocharset", Opt_charset),
fsparam_enum ("shortname", Opt_shortname, fat_param_shortname),
fsparam_flag ("utf8", Opt_utf8),
fsparam_bool ("utf8", Opt_utf8_bool),
fsparam_flag ("uni_xlate", Opt_uni_xl),
fsparam_bool ("uni_xlate", Opt_uni_xl_bool),
fsparam_flag ("nonumtail", Opt_nonumtail),
fsparam_bool ("nonumtail", Opt_nonumtail_bool),
fsparam_flag ("rodir", Opt_rodir),
{}
};
int fat_parse_param(struct fs_context *fc, struct fs_parameter *param,
bool is_vfat)
{
char *p;
substring_t args[MAX_OPT_ARGS];
int option;
char *iocharset;
struct fat_mount_options *opts = fc->fs_private;
struct fs_parse_result result;
int opt;
opts->isvfat = is_vfat;
/* remount options have traditionally been ignored */
if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE)
return 0;
opts->fs_uid = current_uid();
opts->fs_gid = current_gid();
opts->fs_fmask = opts->fs_dmask = current_umask();
opts->allow_utime = -1;
opts->codepage = fat_default_codepage;
fat_reset_iocharset(opts);
if (is_vfat) {
opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
opts->rodir = 0;
} else {
opts->shortname = 0;
opts->rodir = 1;
opt = fs_parse(fc, fat_param_spec, param, &result);
/* If option not found in fat_param_spec, try vfat/msdos options */
if (opt == -ENOPARAM) {
if (is_vfat)
opt = fs_parse(fc, vfat_param_spec, param, &result);
else
opt = fs_parse(fc, msdos_param_spec, param, &result);
}
opts->name_check = 'n';
opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0;
opts->unicode_xlate = 0;
opts->numtail = 1;
opts->usefree = opts->nocase = 0;
opts->tz_set = 0;
opts->nfs = 0;
opts->errors = FAT_ERRORS_RO;
*debug = 0;
opts->utf8 = IS_ENABLED(CONFIG_FAT_DEFAULT_UTF8) && is_vfat;
if (opt < 0)
return opt;
if (!options)
goto out;
while ((p = strsep(&options, ",")) != NULL) {
int token;
if (!*p)
continue;
token = match_token(p, fat_tokens, args);
if (token == Opt_err) {
if (is_vfat)
token = match_token(p, vfat_tokens, args);
else
token = match_token(p, msdos_tokens, args);
}
switch (token) {
case Opt_check_s:
opts->name_check = 's';
break;
case Opt_check_r:
opts->name_check = 'r';
break;
case Opt_check_n:
opts->name_check = 'n';
break;
case Opt_usefree:
opts->usefree = 1;
break;
case Opt_nocase:
if (!is_vfat)
opts->nocase = 1;
else {
/* for backward compatibility */
opts->shortname = VFAT_SFN_DISPLAY_WIN95
| VFAT_SFN_CREATE_WIN95;
}
break;
case Opt_quiet:
opts->quiet = 1;
break;
case Opt_showexec:
opts->showexec = 1;
break;
case Opt_debug:
*debug = 1;
break;
case Opt_immutable:
opts->sys_immutable = 1;
break;
case Opt_uid:
if (match_int(&args[0], &option))
return -EINVAL;
opts->fs_uid = make_kuid(current_user_ns(), option);
if (!uid_valid(opts->fs_uid))
return -EINVAL;
break;
case Opt_gid:
if (match_int(&args[0], &option))
return -EINVAL;
opts->fs_gid = make_kgid(current_user_ns(), option);
if (!gid_valid(opts->fs_gid))
return -EINVAL;
break;
case Opt_umask:
if (match_octal(&args[0], &option))
return -EINVAL;
opts->fs_fmask = opts->fs_dmask = option;
break;
case Opt_dmask:
if (match_octal(&args[0], &option))
return -EINVAL;
opts->fs_dmask = option;
break;
case Opt_fmask:
if (match_octal(&args[0], &option))
return -EINVAL;
opts->fs_fmask = option;
break;
case Opt_allow_utime:
if (match_octal(&args[0], &option))
return -EINVAL;
opts->allow_utime = option & (S_IWGRP | S_IWOTH);
break;
case Opt_codepage:
if (match_int(&args[0], &option))
return -EINVAL;
opts->codepage = option;
break;
case Opt_flush:
opts->flush = 1;
break;
case Opt_time_offset:
if (match_int(&args[0], &option))
return -EINVAL;
/*
* GMT+-12 zones may have DST corrections so at least
* 13 hours difference is needed. Make the limit 24
* just in case someone invents something unusual.
*/
if (option < -24 * 60 || option > 24 * 60)
return -EINVAL;
opts->tz_set = 1;
opts->time_offset = option;
break;
case Opt_tz_utc:
opts->tz_set = 1;
opts->time_offset = 0;
break;
case Opt_err_cont:
opts->errors = FAT_ERRORS_CONT;
break;
case Opt_err_panic:
opts->errors = FAT_ERRORS_PANIC;
break;
case Opt_err_ro:
opts->errors = FAT_ERRORS_RO;
break;
case Opt_nfs_stale_rw:
opts->nfs = FAT_NFS_STALE_RW;
break;
case Opt_nfs_nostale_ro:
opts->nfs = FAT_NFS_NOSTALE_RO;
break;
case Opt_dos1xfloppy:
opts->dos1xfloppy = 1;
break;
/* msdos specific */
case Opt_dots:
opts->dotsOK = 1;
break;
case Opt_nodots:
opts->dotsOK = 0;
break;
/* vfat specific */
case Opt_charset:
fat_reset_iocharset(opts);
iocharset = match_strdup(&args[0]);
if (!iocharset)
return -ENOMEM;
opts->iocharset = iocharset;
break;
case Opt_shortname_lower:
opts->shortname = VFAT_SFN_DISPLAY_LOWER
| VFAT_SFN_CREATE_WIN95;
break;
case Opt_shortname_win95:
switch (opt) {
case Opt_check:
opts->name_check = result.uint_32;
break;
case Opt_usefree:
opts->usefree = 1;
break;
case Opt_nocase:
if (!is_vfat)
opts->nocase = 1;
else {
/* for backward compatibility */
opts->shortname = VFAT_SFN_DISPLAY_WIN95
| VFAT_SFN_CREATE_WIN95;
break;
case Opt_shortname_winnt:
opts->shortname = VFAT_SFN_DISPLAY_WINNT
| VFAT_SFN_CREATE_WINNT;
break;
case Opt_shortname_mixed:
opts->shortname = VFAT_SFN_DISPLAY_WINNT
| VFAT_SFN_CREATE_WIN95;
break;
case Opt_utf8_no: /* 0 or no or false */
opts->utf8 = 0;
break;
case Opt_utf8_yes: /* empty or 1 or yes or true */
opts->utf8 = 1;
break;
case Opt_uni_xl_no: /* 0 or no or false */
opts->unicode_xlate = 0;
break;
case Opt_uni_xl_yes: /* empty or 1 or yes or true */
opts->unicode_xlate = 1;
break;
case Opt_nonumtail_no: /* 0 or no or false */
opts->numtail = 1; /* negated option */
break;
case Opt_nonumtail_yes: /* empty or 1 or yes or true */
opts->numtail = 0; /* negated option */
break;
case Opt_rodir:
opts->rodir = 1;
break;
case Opt_discard:
opts->discard = 1;
break;
/* obsolete mount options */
case Opt_obsolete:
fat_msg(sb, KERN_INFO, "\"%s\" option is obsolete, "
"not supported now", p);
break;
/* unknown option */
default:
if (!silent) {
fat_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" "
"or missing value", p);
}
return -EINVAL;
| VFAT_SFN_CREATE_WIN95;
}
}
break;
case Opt_quiet:
opts->quiet = 1;
break;
case Opt_showexec:
opts->showexec = 1;
break;
case Opt_debug:
opts->debug = 1;
break;
case Opt_immutable:
opts->sys_immutable = 1;
break;
case Opt_uid:
opts->fs_uid = result.uid;
break;
case Opt_gid:
opts->fs_gid = result.gid;
break;
case Opt_umask:
opts->fs_fmask = opts->fs_dmask = result.uint_32;
break;
case Opt_dmask:
opts->fs_dmask = result.uint_32;
break;
case Opt_fmask:
opts->fs_fmask = result.uint_32;
break;
case Opt_allow_utime:
opts->allow_utime = result.uint_32 & (S_IWGRP | S_IWOTH);
break;
case Opt_codepage:
opts->codepage = result.uint_32;
break;
case Opt_flush:
opts->flush = 1;
break;
case Opt_time_offset:
/*
* GMT+-12 zones may have DST corrections so at least
* 13 hours difference is needed. Make the limit 24
* just in case someone invents something unusual.
*/
if (result.int_32 < -24 * 60 || result.int_32 > 24 * 60)
return -EINVAL;
opts->tz_set = 1;
opts->time_offset = result.int_32;
break;
case Opt_tz:
opts->tz_set = 1;
opts->time_offset = result.uint_32;
break;
case Opt_errors:
opts->errors = result.uint_32;
break;
case Opt_nfs:
opts->nfs = FAT_NFS_STALE_RW;
break;
case Opt_nfs_enum:
opts->nfs = result.uint_32;
break;
case Opt_dos1xfloppy:
opts->dos1xfloppy = 1;
break;
out:
/* UTF-8 doesn't provide FAT semantics */
if (!strcmp(opts->iocharset, "utf8")) {
fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset"
" for FAT filesystems, filesystem will be "
"case sensitive!");
}
/* msdos specific */
case Opt_dots: /* dots / nodots */
opts->dotsOK = !result.negated;
break;
case Opt_dotsOK: /* dotsOK = yes/no */
opts->dotsOK = result.boolean;
break;
/* If user doesn't specify allow_utime, it's initialized from dmask. */
if (opts->allow_utime == (unsigned short)-1)
opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
if (opts->unicode_xlate)
opts->utf8 = 0;
if (opts->nfs == FAT_NFS_NOSTALE_RO) {
sb->s_flags |= SB_RDONLY;
sb->s_export_op = &fat_export_ops_nostale;
/* vfat specific */
case Opt_charset:
fat_reset_iocharset(opts);
opts->iocharset = param->string;
param->string = NULL; /* Steal string */
break;
case Opt_shortname:
opts->shortname = result.uint_32;
break;
case Opt_utf8:
opts->utf8 = 1;
break;
case Opt_utf8_bool:
opts->utf8 = result.boolean;
break;
case Opt_uni_xl:
opts->unicode_xlate = 1;
break;
case Opt_uni_xl_bool:
opts->unicode_xlate = result.boolean;
break;
case Opt_nonumtail:
opts->numtail = 0; /* negated option */
break;
case Opt_nonumtail_bool:
opts->numtail = !result.boolean; /* negated option */
break;
case Opt_rodir:
opts->rodir = 1;
break;
case Opt_discard:
opts->discard = 1;
break;
/* obsolete mount options */
case Opt_obsolete:
printk(KERN_INFO "FAT-fs: \"%s\" option is obsolete, "
"not supported now", param->key);
break;
default:
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(fat_parse_param);
static int fat_read_root(struct inode *inode)
{
@ -1604,9 +1530,11 @@ out:
/*
* Read the super block of an MS-DOS FS.
*/
int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
int fat_fill_super(struct super_block *sb, struct fs_context *fc,
void (*setup)(struct super_block *))
{
struct fat_mount_options *opts = fc->fs_private;
int silent = fc->sb_flags & SB_SILENT;
struct inode *root_inode = NULL, *fat_inode = NULL;
struct inode *fsinfo_inode = NULL;
struct buffer_head *bh;
@ -1614,7 +1542,6 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
struct msdos_sb_info *sbi;
u16 logical_sector_size;
u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
int debug;
long error;
char buf[50];
struct timespec64 ts;
@ -1643,9 +1570,27 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
error = parse_options(sb, data, isvfat, silent, &debug, &sbi->options);
if (error)
goto out_fail;
/* UTF-8 doesn't provide FAT semantics */
if (!strcmp(opts->iocharset, "utf8")) {
fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset"
" for FAT filesystems, filesystem will be"
" case sensitive!");
}
/* If user doesn't specify allow_utime, it's initialized from dmask. */
if (opts->allow_utime == (unsigned short)-1)
opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
if (opts->unicode_xlate)
opts->utf8 = 0;
if (opts->nfs == FAT_NFS_NOSTALE_RO) {
sb->s_flags |= SB_RDONLY;
sb->s_export_op = &fat_export_ops_nostale;
}
/* Apply parsed options to sbi (structure copy) */
sbi->options = *opts;
/* Transfer ownership of iocharset to sbi->options */
opts->iocharset = NULL;
setup(sb); /* flavour-specific stuff that needs options */
@ -1950,6 +1895,57 @@ int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
}
EXPORT_SYMBOL_GPL(fat_flush_inodes);
int fat_init_fs_context(struct fs_context *fc, bool is_vfat)
{
struct fat_mount_options *opts;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return -ENOMEM;
opts->isvfat = is_vfat;
opts->fs_uid = current_uid();
opts->fs_gid = current_gid();
opts->fs_fmask = opts->fs_dmask = current_umask();
opts->allow_utime = -1;
opts->codepage = fat_default_codepage;
fat_reset_iocharset(opts);
if (is_vfat) {
opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
opts->rodir = 0;
} else {
opts->shortname = 0;
opts->rodir = 1;
}
opts->name_check = 'n';
opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0;
opts->unicode_xlate = 0;
opts->numtail = 1;
opts->usefree = opts->nocase = 0;
opts->tz_set = 0;
opts->nfs = 0;
opts->errors = FAT_ERRORS_RO;
opts->debug = 0;
opts->utf8 = IS_ENABLED(CONFIG_FAT_DEFAULT_UTF8) && is_vfat;
fc->fs_private = opts;
/* fc->ops assigned by caller */
return 0;
}
EXPORT_SYMBOL_GPL(fat_init_fs_context);
void fat_free_fc(struct fs_context *fc)
{
struct fat_mount_options *opts = fc->fs_private;
if (opts->iocharset != fat_default_iocharset)
kfree(opts->iocharset);
kfree(fc->fs_private);
}
EXPORT_SYMBOL_GPL(fat_free_fc);
static int __init init_fat_fs(void)
{
int err;

View File

@ -650,24 +650,48 @@ static void setup(struct super_block *sb)
sb->s_flags |= SB_NOATIME;
}
static int msdos_fill_super(struct super_block *sb, void *data, int silent)
static int msdos_fill_super(struct super_block *sb, struct fs_context *fc)
{
return fat_fill_super(sb, data, silent, 0, setup);
return fat_fill_super(sb, fc, setup);
}
static struct dentry *msdos_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
static int msdos_get_tree(struct fs_context *fc)
{
return mount_bdev(fs_type, flags, dev_name, data, msdos_fill_super);
return get_tree_bdev(fc, msdos_fill_super);
}
static int msdos_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
return fat_parse_param(fc, param, false);
}
static const struct fs_context_operations msdos_context_ops = {
.parse_param = msdos_parse_param,
.get_tree = msdos_get_tree,
.reconfigure = fat_reconfigure,
.free = fat_free_fc,
};
static int msdos_init_fs_context(struct fs_context *fc)
{
int err;
/* Initialize with is_vfat == false */
err = fat_init_fs_context(fc, false);
if (err)
return err;
fc->ops = &msdos_context_ops;
return 0;
}
static struct file_system_type msdos_fs_type = {
.owner = THIS_MODULE,
.name = "msdos",
.mount = msdos_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
.init_fs_context = msdos_init_fs_context,
.parameters = fat_param_spec,
};
MODULE_ALIAS_FS("msdos");

View File

@ -1195,24 +1195,48 @@ static void setup(struct super_block *sb)
sb->s_d_op = &vfat_dentry_ops;
}
static int vfat_fill_super(struct super_block *sb, void *data, int silent)
static int vfat_fill_super(struct super_block *sb, struct fs_context *fc)
{
return fat_fill_super(sb, data, silent, 1, setup);
return fat_fill_super(sb, fc, setup);
}
static struct dentry *vfat_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
static int vfat_get_tree(struct fs_context *fc)
{
return mount_bdev(fs_type, flags, dev_name, data, vfat_fill_super);
return get_tree_bdev(fc, vfat_fill_super);
}
static int vfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
return fat_parse_param(fc, param, true);
}
static const struct fs_context_operations vfat_context_ops = {
.parse_param = vfat_parse_param,
.get_tree = vfat_get_tree,
.reconfigure = fat_reconfigure,
.free = fat_free_fc,
};
static int vfat_init_fs_context(struct fs_context *fc)
{
int err;
/* Initialize with is_vfat == true */
err = fat_init_fs_context(fc, true);
if (err)
return err;
fc->ops = &vfat_context_ops;
return 0;
}
static struct file_system_type vfat_fs_type = {
.owner = THIS_MODULE,
.name = "vfat",
.mount = vfat_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
.init_fs_context = vfat_init_fs_context,
.parameters = fat_param_spec,
};
MODULE_ALIAS_FS("vfat");

View File

@ -308,6 +308,40 @@ int fs_param_is_fd(struct p_log *log, const struct fs_parameter_spec *p,
}
EXPORT_SYMBOL(fs_param_is_fd);
int fs_param_is_uid(struct p_log *log, const struct fs_parameter_spec *p,
struct fs_parameter *param, struct fs_parse_result *result)
{
kuid_t uid;
if (fs_param_is_u32(log, p, param, result) != 0)
return fs_param_bad_value(log, param);
uid = make_kuid(current_user_ns(), result->uint_32);
if (!uid_valid(uid))
return inval_plog(log, "Invalid uid '%s'", param->string);
result->uid = uid;
return 0;
}
EXPORT_SYMBOL(fs_param_is_uid);
int fs_param_is_gid(struct p_log *log, const struct fs_parameter_spec *p,
struct fs_parameter *param, struct fs_parse_result *result)
{
kgid_t gid;
if (fs_param_is_u32(log, p, param, result) != 0)
return fs_param_bad_value(log, param);
gid = make_kgid(current_user_ns(), result->uint_32);
if (!gid_valid(gid))
return inval_plog(log, "Invalid gid '%s'", param->string);
result->gid = gid;
return 0;
}
EXPORT_SYMBOL(fs_param_is_gid);
int fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p,
struct fs_parameter *param, struct fs_parse_result *result)
{

View File

@ -740,8 +740,8 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = {
fsparam_string ("source", OPT_SOURCE),
fsparam_u32 ("fd", OPT_FD),
fsparam_u32oct ("rootmode", OPT_ROOTMODE),
fsparam_u32 ("user_id", OPT_USER_ID),
fsparam_u32 ("group_id", OPT_GROUP_ID),
fsparam_uid ("user_id", OPT_USER_ID),
fsparam_gid ("group_id", OPT_GROUP_ID),
fsparam_flag ("default_permissions", OPT_DEFAULT_PERMISSIONS),
fsparam_flag ("allow_other", OPT_ALLOW_OTHER),
fsparam_u32 ("max_read", OPT_MAX_READ),
@ -755,6 +755,8 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
struct fs_parse_result result;
struct fuse_fs_context *ctx = fsc->fs_private;
int opt;
kuid_t kuid;
kgid_t kgid;
if (fsc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
/*
@ -799,16 +801,26 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
break;
case OPT_USER_ID:
ctx->user_id = make_kuid(fsc->user_ns, result.uint_32);
if (!uid_valid(ctx->user_id))
kuid = result.uid;
/*
* The requested uid must be representable in the
* filesystem's idmapping.
*/
if (!kuid_has_mapping(fsc->user_ns, kuid))
return invalfc(fsc, "Invalid user_id");
ctx->user_id = kuid;
ctx->user_id_present = true;
break;
case OPT_GROUP_ID:
ctx->group_id = make_kgid(fsc->user_ns, result.uint_32);
if (!gid_valid(ctx->group_id))
kgid = result.gid;
/*
* The requested gid must be representable in the
* filesystem's idmapping.
*/
if (!kgid_has_mapping(fsc->user_ns, kgid))
return invalfc(fsc, "Invalid group_id");
ctx->group_id = kgid;
ctx->group_id_present = true;
break;

View File

@ -16,11 +16,16 @@
#include <linux/seq_file.h>
#include <linux/writeback.h>
#include <linux/mount.h>
#include <linux/fs_context.h>
#include <linux/namei.h>
#include "hostfs.h"
#include <init.h>
#include <kern.h>
struct hostfs_fs_info {
char *host_root_path;
};
struct hostfs_inode_info {
int fd;
fmode_t mode;
@ -90,8 +95,10 @@ static char *__dentry_name(struct dentry *dentry, char *name)
char *p = dentry_path_raw(dentry, name, PATH_MAX);
char *root;
size_t len;
struct hostfs_fs_info *fsi;
root = dentry->d_sb->s_fs_info;
fsi = dentry->d_sb->s_fs_info;
root = fsi->host_root_path;
len = strlen(root);
if (IS_ERR(p)) {
__putname(name);
@ -196,8 +203,10 @@ static int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
long long f_bavail;
long long f_files;
long long f_ffree;
struct hostfs_fs_info *fsi;
err = do_statfs(dentry->d_sb->s_fs_info,
fsi = dentry->d_sb->s_fs_info;
err = do_statfs(fsi->host_root_path,
&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
&sf->f_namelen);
@ -245,7 +254,11 @@ static void hostfs_free_inode(struct inode *inode)
static int hostfs_show_options(struct seq_file *seq, struct dentry *root)
{
const char *root_path = root->d_sb->s_fs_info;
struct hostfs_fs_info *fsi;
const char *root_path;
fsi = root->d_sb->s_fs_info;
root_path = fsi->host_root_path;
size_t offset = strlen(root_ino) + 1;
if (strlen(root_path) > offset)
@ -911,10 +924,11 @@ static const struct inode_operations hostfs_link_iops = {
.get_link = hostfs_get_link,
};
static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
static int hostfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct hostfs_fs_info *fsi = sb->s_fs_info;
const char *host_root = fc->source;
struct inode *root_inode;
char *host_root_path, *req_root = d;
int err;
sb->s_blocksize = 1024;
@ -928,15 +942,15 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
return err;
/* NULL is printed as '(null)' by printf(): avoid that. */
if (req_root == NULL)
req_root = "";
if (fc->source == NULL)
host_root = "";
sb->s_fs_info = host_root_path =
kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
if (host_root_path == NULL)
fsi->host_root_path =
kasprintf(GFP_KERNEL, "%s/%s", root_ino, host_root);
if (fsi->host_root_path == NULL)
return -ENOMEM;
root_inode = hostfs_iget(sb, host_root_path);
root_inode = hostfs_iget(sb, fsi->host_root_path);
if (IS_ERR(root_inode))
return PTR_ERR(root_inode);
@ -944,7 +958,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
char *name;
iput(root_inode);
name = follow_link(host_root_path);
name = follow_link(fsi->host_root_path);
if (IS_ERR(name))
return PTR_ERR(name);
@ -961,11 +975,38 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
return 0;
}
static struct dentry *hostfs_read_sb(struct file_system_type *type,
int flags, const char *dev_name,
void *data)
static int hostfs_fc_get_tree(struct fs_context *fc)
{
return mount_nodev(type, flags, data, hostfs_fill_sb_common);
return get_tree_nodev(fc, hostfs_fill_super);
}
static void hostfs_fc_free(struct fs_context *fc)
{
struct hostfs_fs_info *fsi = fc->s_fs_info;
if (!fsi)
return;
kfree(fsi->host_root_path);
kfree(fsi);
}
static const struct fs_context_operations hostfs_context_ops = {
.get_tree = hostfs_fc_get_tree,
.free = hostfs_fc_free,
};
static int hostfs_init_fs_context(struct fs_context *fc)
{
struct hostfs_fs_info *fsi;
fsi = kzalloc(sizeof(*fsi), GFP_KERNEL);
if (!fsi)
return -ENOMEM;
fc->s_fs_info = fsi;
fc->ops = &hostfs_context_ops;
return 0;
}
static void hostfs_kill_sb(struct super_block *s)
@ -975,11 +1016,11 @@ static void hostfs_kill_sb(struct super_block *s)
}
static struct file_system_type hostfs_type = {
.owner = THIS_MODULE,
.name = "hostfs",
.mount = hostfs_read_sb,
.kill_sb = hostfs_kill_sb,
.fs_flags = 0,
.owner = THIS_MODULE,
.name = "hostfs",
.init_fs_context = hostfs_init_fs_context,
.kill_sb = hostfs_kill_sb,
.fs_flags = 0,
};
MODULE_ALIAS_FS("hostfs");

View File

@ -73,13 +73,13 @@ enum hugetlb_param {
};
static const struct fs_parameter_spec hugetlb_fs_parameters[] = {
fsparam_u32 ("gid", Opt_gid),
fsparam_gid ("gid", Opt_gid),
fsparam_string("min_size", Opt_min_size),
fsparam_u32oct("mode", Opt_mode),
fsparam_string("nr_inodes", Opt_nr_inodes),
fsparam_string("pagesize", Opt_pagesize),
fsparam_string("size", Opt_size),
fsparam_u32 ("uid", Opt_uid),
fsparam_uid ("uid", Opt_uid),
{}
};
@ -1376,15 +1376,11 @@ static int hugetlbfs_parse_param(struct fs_context *fc, struct fs_parameter *par
switch (opt) {
case Opt_uid:
ctx->uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(ctx->uid))
goto bad_val;
ctx->uid = result.uid;
return 0;
case Opt_gid:
ctx->gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(ctx->gid))
goto bad_val;
ctx->gid = result.gid;
return 0;
case Opt_mode:

View File

@ -326,8 +326,8 @@ static const struct fs_parameter_spec isofs_param_spec[] = {
fsparam_u32 ("session", Opt_session),
fsparam_u32 ("sbsector", Opt_sb),
fsparam_enum ("check", Opt_check, isofs_param_check),
fsparam_u32 ("uid", Opt_uid),
fsparam_u32 ("gid", Opt_gid),
fsparam_uid ("uid", Opt_uid),
fsparam_gid ("gid", Opt_gid),
/* Note: mode/dmode historically accepted %u not strictly %o */
fsparam_u32 ("mode", Opt_mode),
fsparam_u32 ("dmode", Opt_dmode),
@ -344,8 +344,6 @@ static int isofs_parse_param(struct fs_context *fc,
struct isofs_options *popt = fc->fs_private;
struct fs_parse_result result;
int opt;
kuid_t uid;
kgid_t gid;
unsigned int n;
/* There are no remountable options */
@ -409,17 +407,11 @@ static int isofs_parse_param(struct fs_context *fc,
case Opt_ignore:
break;
case Opt_uid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
return -EINVAL;
popt->uid = uid;
popt->uid = result.uid;
popt->uid_set = 1;
break;
case Opt_gid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
return -EINVAL;
popt->gid = gid;
popt->gid = result.gid;
popt->gid_set = 1;
break;
case Opt_mode:

View File

@ -259,8 +259,8 @@ enum Opt {
// clang-format off
static const struct fs_parameter_spec ntfs_fs_parameters[] = {
fsparam_u32("uid", Opt_uid),
fsparam_u32("gid", Opt_gid),
fsparam_uid("uid", Opt_uid),
fsparam_gid("gid", Opt_gid),
fsparam_u32oct("umask", Opt_umask),
fsparam_u32oct("dmask", Opt_dmask),
fsparam_u32oct("fmask", Opt_fmask),
@ -319,14 +319,10 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
switch (opt) {
case Opt_uid:
opts->fs_uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(opts->fs_uid))
return invalf(fc, "ntfs3: Invalid value for uid.");
opts->fs_uid = result.uid;
break;
case Opt_gid:
opts->fs_gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(opts->fs_gid))
return invalf(fc, "ntfs3: Invalid value for gid.");
opts->fs_gid = result.gid;
break;
case Opt_umask:
if (result.uint_32 & ~07777)

View File

@ -128,12 +128,14 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_flag("compress", Opt_compress),
fsparam_flag("witness", Opt_witness),
/* Mount options which take uid or gid */
fsparam_uid("backupuid", Opt_backupuid),
fsparam_gid("backupgid", Opt_backupgid),
fsparam_uid("uid", Opt_uid),
fsparam_uid("cruid", Opt_cruid),
fsparam_gid("gid", Opt_gid),
/* Mount options which take numeric value */
fsparam_u32("backupuid", Opt_backupuid),
fsparam_u32("backupgid", Opt_backupgid),
fsparam_u32("uid", Opt_uid),
fsparam_u32("cruid", Opt_cruid),
fsparam_u32("gid", Opt_gid),
fsparam_u32("file_mode", Opt_file_mode),
fsparam_u32("dirmode", Opt_dirmode),
fsparam_u32("dir_mode", Opt_dirmode),
@ -951,8 +953,6 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
int i, opt;
bool is_smb3 = !strcmp(fc->fs_type->name, "smb3");
bool skip_parsing = false;
kuid_t uid;
kgid_t gid;
cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key);
@ -1083,38 +1083,23 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
}
break;
case Opt_uid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
goto cifs_parse_mount_err;
ctx->linux_uid = uid;
ctx->linux_uid = result.uid;
ctx->uid_specified = true;
break;
case Opt_cruid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
goto cifs_parse_mount_err;
ctx->cred_uid = uid;
ctx->cred_uid = result.uid;
ctx->cruid_specified = true;
break;
case Opt_backupuid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
goto cifs_parse_mount_err;
ctx->backupuid = uid;
ctx->backupuid = result.uid;
ctx->backupuid_specified = true;
break;
case Opt_backupgid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
goto cifs_parse_mount_err;
ctx->backupgid = gid;
ctx->backupgid = result.gid;
ctx->backupgid_specified = true;
break;
case Opt_gid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
goto cifs_parse_mount_err;
ctx->linux_gid = gid;
ctx->linux_gid = result.gid;
ctx->gid_specified = true;
break;
case Opt_port:

View File

@ -296,9 +296,9 @@ enum {
};
static const struct fs_parameter_spec tracefs_param_specs[] = {
fsparam_u32 ("gid", Opt_gid),
fsparam_gid ("gid", Opt_gid),
fsparam_u32oct ("mode", Opt_mode),
fsparam_u32 ("uid", Opt_uid),
fsparam_uid ("uid", Opt_uid),
{}
};
@ -306,8 +306,6 @@ static int tracefs_parse_param(struct fs_context *fc, struct fs_parameter *param
{
struct tracefs_fs_info *opts = fc->s_fs_info;
struct fs_parse_result result;
kuid_t uid;
kgid_t gid;
int opt;
opt = fs_parse(fc, tracefs_param_specs, param, &result);
@ -316,16 +314,10 @@ static int tracefs_parse_param(struct fs_context *fc, struct fs_parameter *param
switch (opt) {
case Opt_uid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
return invalf(fc, "Unknown uid");
opts->uid = uid;
opts->uid = result.uid;
break;
case Opt_gid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
return invalf(fc, "Unknown gid");
opts->gid = gid;
opts->gid = result.gid;
break;
case Opt_mode:
opts->mode = result.uint_32 & S_IALLUGO;

View File

@ -41,8 +41,8 @@ enum { opt_nls, opt_uid, opt_gid, opt_ttl, opt_dmode, opt_fmode,
static const struct fs_parameter_spec vboxsf_fs_parameters[] = {
fsparam_string ("nls", opt_nls),
fsparam_u32 ("uid", opt_uid),
fsparam_u32 ("gid", opt_gid),
fsparam_uid ("uid", opt_uid),
fsparam_gid ("gid", opt_gid),
fsparam_u32 ("ttl", opt_ttl),
fsparam_u32oct ("dmode", opt_dmode),
fsparam_u32oct ("fmode", opt_fmode),
@ -55,8 +55,6 @@ static int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct vboxsf_fs_context *ctx = fc->fs_private;
struct fs_parse_result result;
kuid_t uid;
kgid_t gid;
int opt;
opt = fs_parse(fc, vboxsf_fs_parameters, param, &result);
@ -73,16 +71,10 @@ static int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param)
param->string = NULL;
break;
case opt_uid:
uid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(uid))
return -EINVAL;
ctx->o.uid = uid;
ctx->o.uid = result.uid;
break;
case opt_gid:
gid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(gid))
return -EINVAL;
ctx->o.gid = gid;
ctx->o.gid = result.gid;
break;
case opt_ttl:
ctx->o.ttl = msecs_to_jiffies(result.uint_32);

View File

@ -28,7 +28,7 @@ typedef int fs_param_type(struct p_log *,
*/
fs_param_type fs_param_is_bool, fs_param_is_u32, fs_param_is_s32, fs_param_is_u64,
fs_param_is_enum, fs_param_is_string, fs_param_is_blob, fs_param_is_blockdev,
fs_param_is_path, fs_param_is_fd;
fs_param_is_path, fs_param_is_fd, fs_param_is_uid, fs_param_is_gid;
/*
* Specification of the type of value a parameter wants.
@ -57,6 +57,8 @@ struct fs_parse_result {
int int_32; /* For spec_s32/spec_enum */
unsigned int uint_32; /* For spec_u32{,_octal,_hex}/spec_enum */
u64 uint_64; /* For spec_u64 */
kuid_t uid;
kgid_t gid;
};
};
@ -131,6 +133,8 @@ static inline bool fs_validate_description(const char *name,
#define fsparam_bdev(NAME, OPT) __fsparam(fs_param_is_blockdev, NAME, OPT, 0, NULL)
#define fsparam_path(NAME, OPT) __fsparam(fs_param_is_path, NAME, OPT, 0, NULL)
#define fsparam_fd(NAME, OPT) __fsparam(fs_param_is_fd, NAME, OPT, 0, NULL)
#define fsparam_uid(NAME, OPT) __fsparam(fs_param_is_uid, NAME, OPT, 0, NULL)
#define fsparam_gid(NAME, OPT) __fsparam(fs_param_is_gid, NAME, OPT, 0, NULL)
/* String parameter that allows empty argument */
#define fsparam_string_empty(NAME, OPT) \

View File

@ -3917,14 +3917,14 @@ static const struct constant_table shmem_param_enums_huge[] = {
};
const struct fs_parameter_spec shmem_fs_parameters[] = {
fsparam_u32 ("gid", Opt_gid),
fsparam_gid ("gid", Opt_gid),
fsparam_enum ("huge", Opt_huge, shmem_param_enums_huge),
fsparam_u32oct("mode", Opt_mode),
fsparam_string("mpol", Opt_mpol),
fsparam_string("nr_blocks", Opt_nr_blocks),
fsparam_string("nr_inodes", Opt_nr_inodes),
fsparam_string("size", Opt_size),
fsparam_u32 ("uid", Opt_uid),
fsparam_uid ("uid", Opt_uid),
fsparam_flag ("inode32", Opt_inode32),
fsparam_flag ("inode64", Opt_inode64),
fsparam_flag ("noswap", Opt_noswap),
@ -3984,9 +3984,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
ctx->mode = result.uint_32 & 07777;
break;
case Opt_uid:
kuid = make_kuid(current_user_ns(), result.uint_32);
if (!uid_valid(kuid))
goto bad_value;
kuid = result.uid;
/*
* The requested uid must be representable in the
@ -3998,9 +3996,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
ctx->uid = kuid;
break;
case Opt_gid:
kgid = make_kgid(current_user_ns(), result.uint_32);
if (!gid_valid(kgid))
goto bad_value;
kgid = result.gid;
/*
* The requested gid must be representable in the