mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-21 12:11:49 +08:00
Merge branch 'vfs.idmap' into vfs.all
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
commit
4d07d6a6f1
@ -12,7 +12,6 @@
|
||||
#include <linux/posix_acl_xattr.h>
|
||||
|
||||
static struct posix_acl *__fuse_get_acl(struct fuse_conn *fc,
|
||||
struct mnt_idmap *idmap,
|
||||
struct inode *inode, int type, bool rcu)
|
||||
{
|
||||
int size;
|
||||
@ -74,7 +73,7 @@ struct posix_acl *fuse_get_acl(struct mnt_idmap *idmap,
|
||||
if (fuse_no_acl(fc, inode))
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
return __fuse_get_acl(fc, idmap, inode, type, false);
|
||||
return __fuse_get_acl(fc, inode, type, false);
|
||||
}
|
||||
|
||||
struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu)
|
||||
@ -90,8 +89,7 @@ struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu)
|
||||
*/
|
||||
if (!fc->posix_acl)
|
||||
return NULL;
|
||||
|
||||
return __fuse_get_acl(fc, &nop_mnt_idmap, inode, type, rcu);
|
||||
return __fuse_get_acl(fc, inode, type, rcu);
|
||||
}
|
||||
|
||||
int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
@ -146,8 +144,8 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
* be stripped.
|
||||
*/
|
||||
if (fc->posix_acl &&
|
||||
!in_group_or_capable(&nop_mnt_idmap, inode,
|
||||
i_gid_into_vfsgid(&nop_mnt_idmap, inode)))
|
||||
!in_group_or_capable(idmap, inode,
|
||||
i_gid_into_vfsgid(idmap, inode)))
|
||||
extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
|
||||
|
||||
ret = fuse_setxattr(inode, name, value, size, 0, extra_flags);
|
||||
|
146
fs/fuse/dir.c
146
fs/fuse/dir.c
@ -572,7 +572,33 @@ static int get_create_supp_group(struct inode *dir, struct fuse_in_arg *ext)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_create_ext(struct fuse_args *args,
|
||||
static int get_owner_uid_gid(struct mnt_idmap *idmap, struct fuse_conn *fc, struct fuse_in_arg *ext)
|
||||
{
|
||||
struct fuse_ext_header *xh;
|
||||
struct fuse_owner_uid_gid *owner_creds;
|
||||
u32 owner_creds_len = fuse_ext_size(sizeof(*owner_creds));
|
||||
kuid_t owner_fsuid;
|
||||
kgid_t owner_fsgid;
|
||||
|
||||
xh = extend_arg(ext, owner_creds_len);
|
||||
if (!xh)
|
||||
return -ENOMEM;
|
||||
|
||||
xh->size = owner_creds_len;
|
||||
xh->type = FUSE_EXT_OWNER_UID_GID;
|
||||
|
||||
owner_creds = (struct fuse_owner_uid_gid *) &xh[1];
|
||||
|
||||
owner_fsuid = mapped_fsuid(idmap, fc->user_ns);
|
||||
owner_fsgid = mapped_fsgid(idmap, fc->user_ns);
|
||||
owner_creds->uid = from_kuid(fc->user_ns, owner_fsuid);
|
||||
owner_creds->gid = from_kgid(fc->user_ns, owner_fsgid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_create_ext(struct mnt_idmap *idmap,
|
||||
struct fuse_args *args,
|
||||
struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode)
|
||||
{
|
||||
@ -584,6 +610,8 @@ static int get_create_ext(struct fuse_args *args,
|
||||
err = get_security_context(dentry, mode, &ext);
|
||||
if (!err && fc->create_supp_group)
|
||||
err = get_create_supp_group(dir, &ext);
|
||||
if (!err && fc->owner_uid_gid_ext)
|
||||
err = get_owner_uid_gid(idmap, fc, &ext);
|
||||
|
||||
if (!err && ext.size) {
|
||||
WARN_ON(args->in_numargs >= ARRAY_SIZE(args->in_args));
|
||||
@ -609,9 +637,9 @@ static void free_ext_value(struct fuse_args *args)
|
||||
* If the filesystem doesn't support this, then fall back to separate
|
||||
* 'mknod' + 'open' requests.
|
||||
*/
|
||||
static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
||||
struct file *file, unsigned int flags,
|
||||
umode_t mode, u32 opcode)
|
||||
static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *entry, struct file *file,
|
||||
unsigned int flags, umode_t mode, u32 opcode)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
@ -668,7 +696,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
||||
args.out_args[1].size = sizeof(*outopenp);
|
||||
args.out_args[1].value = outopenp;
|
||||
|
||||
err = get_create_ext(&args, dir, entry, mode);
|
||||
err = get_create_ext(idmap, &args, dir, entry, mode);
|
||||
if (err)
|
||||
goto out_put_forget_req;
|
||||
|
||||
@ -729,6 +757,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
|
||||
umode_t mode)
|
||||
{
|
||||
int err;
|
||||
struct mnt_idmap *idmap = file_mnt_idmap(file);
|
||||
struct fuse_conn *fc = get_fuse_conn(dir);
|
||||
struct dentry *res = NULL;
|
||||
|
||||
@ -753,7 +782,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
|
||||
if (fc->no_create)
|
||||
goto mknod;
|
||||
|
||||
err = fuse_create_open(dir, entry, file, flags, mode, FUSE_CREATE);
|
||||
err = fuse_create_open(idmap, dir, entry, file, flags, mode, FUSE_CREATE);
|
||||
if (err == -ENOSYS) {
|
||||
fc->no_create = 1;
|
||||
goto mknod;
|
||||
@ -764,7 +793,7 @@ out_dput:
|
||||
return err;
|
||||
|
||||
mknod:
|
||||
err = fuse_mknod(&nop_mnt_idmap, dir, entry, mode, 0);
|
||||
err = fuse_mknod(idmap, dir, entry, mode, 0);
|
||||
if (err)
|
||||
goto out_dput;
|
||||
no_open:
|
||||
@ -774,9 +803,9 @@ no_open:
|
||||
/*
|
||||
* Code shared between mknod, mkdir, symlink and link
|
||||
*/
|
||||
static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
|
||||
struct inode *dir, struct dentry *entry,
|
||||
umode_t mode)
|
||||
static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm,
|
||||
struct fuse_args *args, struct inode *dir,
|
||||
struct dentry *entry, umode_t mode)
|
||||
{
|
||||
struct fuse_entry_out outarg;
|
||||
struct inode *inode;
|
||||
@ -798,7 +827,7 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
|
||||
args->out_args[0].value = &outarg;
|
||||
|
||||
if (args->opcode != FUSE_LINK) {
|
||||
err = get_create_ext(args, dir, entry, mode);
|
||||
err = get_create_ext(idmap, args, dir, entry, mode);
|
||||
if (err)
|
||||
goto out_put_forget_req;
|
||||
}
|
||||
@ -864,13 +893,13 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
||||
args.in_args[0].value = &inarg;
|
||||
args.in_args[1].size = entry->d_name.len + 1;
|
||||
args.in_args[1].value = entry->d_name.name;
|
||||
return create_new_entry(fm, &args, dir, entry, mode);
|
||||
return create_new_entry(idmap, fm, &args, dir, entry, mode);
|
||||
}
|
||||
|
||||
static int fuse_create(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *entry, umode_t mode, bool excl)
|
||||
{
|
||||
return fuse_mknod(&nop_mnt_idmap, dir, entry, mode, 0);
|
||||
return fuse_mknod(idmap, dir, entry, mode, 0);
|
||||
}
|
||||
|
||||
static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
|
||||
@ -882,7 +911,7 @@ static int fuse_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
|
||||
if (fc->no_tmpfile)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = fuse_create_open(dir, file->f_path.dentry, file, file->f_flags, mode, FUSE_TMPFILE);
|
||||
err = fuse_create_open(idmap, dir, file->f_path.dentry, file, file->f_flags, mode, FUSE_TMPFILE);
|
||||
if (err == -ENOSYS) {
|
||||
fc->no_tmpfile = 1;
|
||||
err = -EOPNOTSUPP;
|
||||
@ -909,7 +938,7 @@ static int fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
args.in_args[0].value = &inarg;
|
||||
args.in_args[1].size = entry->d_name.len + 1;
|
||||
args.in_args[1].value = entry->d_name.name;
|
||||
return create_new_entry(fm, &args, dir, entry, S_IFDIR);
|
||||
return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR);
|
||||
}
|
||||
|
||||
static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
@ -925,7 +954,7 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
args.in_args[0].value = entry->d_name.name;
|
||||
args.in_args[1].size = len;
|
||||
args.in_args[1].value = link;
|
||||
return create_new_entry(fm, &args, dir, entry, S_IFLNK);
|
||||
return create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK);
|
||||
}
|
||||
|
||||
void fuse_flush_time_update(struct inode *inode)
|
||||
@ -1082,6 +1111,9 @@ static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir,
|
||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
|
||||
return -EINVAL;
|
||||
|
||||
if ((flags & RENAME_WHITEOUT) && (idmap != &nop_mnt_idmap))
|
||||
return -EINVAL;
|
||||
|
||||
if (flags) {
|
||||
if (fc->no_rename2 || fc->minor < 23)
|
||||
return -EINVAL;
|
||||
@ -1119,7 +1151,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
|
||||
args.in_args[0].value = &inarg;
|
||||
args.in_args[1].size = newent->d_name.len + 1;
|
||||
args.in_args[1].value = newent->d_name.name;
|
||||
err = create_new_entry(fm, &args, newdir, newent, inode->i_mode);
|
||||
err = create_new_entry(&nop_mnt_idmap, fm, &args, newdir, newent, inode->i_mode);
|
||||
if (!err)
|
||||
fuse_update_ctime_in_cache(inode);
|
||||
else if (err == -EINTR)
|
||||
@ -1128,18 +1160,22 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
|
||||
return err;
|
||||
}
|
||||
|
||||
static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
|
||||
struct kstat *stat)
|
||||
static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct fuse_attr *attr, struct kstat *stat)
|
||||
{
|
||||
unsigned int blkbits;
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
vfsuid_t vfsuid = make_vfsuid(idmap, fc->user_ns,
|
||||
make_kuid(fc->user_ns, attr->uid));
|
||||
vfsgid_t vfsgid = make_vfsgid(idmap, fc->user_ns,
|
||||
make_kgid(fc->user_ns, attr->gid));
|
||||
|
||||
stat->dev = inode->i_sb->s_dev;
|
||||
stat->ino = attr->ino;
|
||||
stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
|
||||
stat->nlink = attr->nlink;
|
||||
stat->uid = make_kuid(fc->user_ns, attr->uid);
|
||||
stat->gid = make_kgid(fc->user_ns, attr->gid);
|
||||
stat->uid = vfsuid_into_kuid(vfsuid);
|
||||
stat->gid = vfsgid_into_kgid(vfsgid);
|
||||
stat->rdev = inode->i_rdev;
|
||||
stat->atime.tv_sec = attr->atime;
|
||||
stat->atime.tv_nsec = attr->atimensec;
|
||||
@ -1178,8 +1214,8 @@ static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr)
|
||||
attr->blksize = sx->blksize;
|
||||
}
|
||||
|
||||
static int fuse_do_statx(struct inode *inode, struct file *file,
|
||||
struct kstat *stat)
|
||||
static int fuse_do_statx(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct file *file, struct kstat *stat)
|
||||
{
|
||||
int err;
|
||||
struct fuse_attr attr;
|
||||
@ -1232,15 +1268,15 @@ static int fuse_do_statx(struct inode *inode, struct file *file,
|
||||
stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
|
||||
stat->btime.tv_sec = sx->btime.tv_sec;
|
||||
stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1);
|
||||
fuse_fillattr(inode, &attr, stat);
|
||||
fuse_fillattr(idmap, inode, &attr, stat);
|
||||
stat->result_mask |= STATX_TYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
|
||||
struct file *file)
|
||||
static int fuse_do_getattr(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct kstat *stat, struct file *file)
|
||||
{
|
||||
int err;
|
||||
struct fuse_getattr_in inarg;
|
||||
@ -1279,15 +1315,15 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
|
||||
ATTR_TIMEOUT(&outarg),
|
||||
attr_version);
|
||||
if (stat)
|
||||
fuse_fillattr(inode, &outarg.attr, stat);
|
||||
fuse_fillattr(idmap, inode, &outarg.attr, stat);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fuse_update_get_attr(struct inode *inode, struct file *file,
|
||||
struct kstat *stat, u32 request_mask,
|
||||
unsigned int flags)
|
||||
static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
|
||||
struct file *file, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags)
|
||||
{
|
||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
@ -1318,17 +1354,17 @@ retry:
|
||||
forget_all_cached_acls(inode);
|
||||
/* Try statx if BTIME is requested */
|
||||
if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) {
|
||||
err = fuse_do_statx(inode, file, stat);
|
||||
err = fuse_do_statx(idmap, inode, file, stat);
|
||||
if (err == -ENOSYS) {
|
||||
fc->no_statx = 1;
|
||||
err = 0;
|
||||
goto retry;
|
||||
}
|
||||
} else {
|
||||
err = fuse_do_getattr(inode, stat, file);
|
||||
err = fuse_do_getattr(idmap, inode, stat, file);
|
||||
}
|
||||
} else if (stat) {
|
||||
generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
|
||||
generic_fillattr(idmap, request_mask, inode, stat);
|
||||
stat->mode = fi->orig_i_mode;
|
||||
stat->ino = fi->orig_ino;
|
||||
if (test_bit(FUSE_I_BTIME, &fi->state)) {
|
||||
@ -1342,7 +1378,7 @@ retry:
|
||||
|
||||
int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask)
|
||||
{
|
||||
return fuse_update_get_attr(inode, file, NULL, mask, 0);
|
||||
return fuse_update_get_attr(&nop_mnt_idmap, inode, file, NULL, mask, 0);
|
||||
}
|
||||
|
||||
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
|
||||
@ -1486,7 +1522,7 @@ static int fuse_perm_getattr(struct inode *inode, int mask)
|
||||
return -ECHILD;
|
||||
|
||||
forget_all_cached_acls(inode);
|
||||
return fuse_do_getattr(inode, NULL, NULL);
|
||||
return fuse_do_getattr(&nop_mnt_idmap, inode, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1534,7 +1570,7 @@ static int fuse_permission(struct mnt_idmap *idmap,
|
||||
}
|
||||
|
||||
if (fc->default_permissions) {
|
||||
err = generic_permission(&nop_mnt_idmap, inode, mask);
|
||||
err = generic_permission(idmap, inode, mask);
|
||||
|
||||
/* If permission is denied, try to refresh file
|
||||
attributes. This is also needed, because the root
|
||||
@ -1542,7 +1578,7 @@ static int fuse_permission(struct mnt_idmap *idmap,
|
||||
if (err == -EACCES && !refreshed) {
|
||||
err = fuse_perm_getattr(inode, mask);
|
||||
if (!err)
|
||||
err = generic_permission(&nop_mnt_idmap,
|
||||
err = generic_permission(idmap,
|
||||
inode, mask);
|
||||
}
|
||||
|
||||
@ -1738,17 +1774,27 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
|
||||
struct fuse_setattr_in *arg, bool trust_local_cmtime)
|
||||
static void iattr_to_fattr(struct mnt_idmap *idmap, struct fuse_conn *fc,
|
||||
struct iattr *iattr, struct fuse_setattr_in *arg,
|
||||
bool trust_local_cmtime)
|
||||
{
|
||||
unsigned ivalid = iattr->ia_valid;
|
||||
|
||||
if (ivalid & ATTR_MODE)
|
||||
arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
|
||||
if (ivalid & ATTR_UID)
|
||||
arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
|
||||
if (ivalid & ATTR_GID)
|
||||
arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
|
||||
|
||||
if (ivalid & ATTR_UID) {
|
||||
kuid_t fsuid = from_vfsuid(idmap, fc->user_ns, iattr->ia_vfsuid);
|
||||
arg->valid |= FATTR_UID;
|
||||
arg->uid = from_kuid(fc->user_ns, fsuid);
|
||||
}
|
||||
|
||||
if (ivalid & ATTR_GID) {
|
||||
kgid_t fsgid = from_vfsgid(idmap, fc->user_ns, iattr->ia_vfsgid);
|
||||
arg->valid |= FATTR_GID;
|
||||
arg->gid = from_kgid(fc->user_ns, fsgid);
|
||||
}
|
||||
|
||||
if (ivalid & ATTR_SIZE)
|
||||
arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
|
||||
if (ivalid & ATTR_ATIME) {
|
||||
@ -1868,8 +1914,8 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff)
|
||||
* vmtruncate() doesn't allow for this case, so do the rlimit checking
|
||||
* and the actual truncation by hand.
|
||||
*/
|
||||
int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
||||
struct file *file)
|
||||
int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr, struct file *file)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct fuse_mount *fm = get_fuse_mount(inode);
|
||||
@ -1889,7 +1935,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
||||
if (!fc->default_permissions)
|
||||
attr->ia_valid |= ATTR_FORCE;
|
||||
|
||||
err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
|
||||
err = setattr_prepare(idmap, dentry, attr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1948,7 +1994,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
||||
|
||||
memset(&inarg, 0, sizeof(inarg));
|
||||
memset(&outarg, 0, sizeof(outarg));
|
||||
iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
|
||||
iattr_to_fattr(idmap, fc, attr, &inarg, trust_local_cmtime);
|
||||
if (file) {
|
||||
struct fuse_file *ff = file->private_data;
|
||||
inarg.valid |= FATTR_FH;
|
||||
@ -2065,7 +2111,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
|
||||
* ia_mode calculation may have used stale i_mode.
|
||||
* Refresh and recalculate.
|
||||
*/
|
||||
ret = fuse_do_getattr(inode, NULL, file);
|
||||
ret = fuse_do_getattr(idmap, inode, NULL, file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2083,7 +2129,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
|
||||
if (!attr->ia_valid)
|
||||
return 0;
|
||||
|
||||
ret = fuse_do_setattr(entry, attr, file);
|
||||
ret = fuse_do_setattr(idmap, entry, attr, file);
|
||||
if (!ret) {
|
||||
/*
|
||||
* If filesystem supports acls it may have updated acl xattrs in
|
||||
@ -2122,7 +2168,7 @@ static int fuse_getattr(struct mnt_idmap *idmap,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return fuse_update_get_attr(inode, NULL, stat, request_mask, flags);
|
||||
return fuse_update_get_attr(idmap, inode, NULL, stat, request_mask, flags);
|
||||
}
|
||||
|
||||
static const struct inode_operations fuse_dir_inode_operations = {
|
||||
|
@ -2967,7 +2967,7 @@ static void fuse_do_truncate(struct file *file)
|
||||
attr.ia_file = file;
|
||||
attr.ia_valid |= ATTR_FILE;
|
||||
|
||||
fuse_do_setattr(file_dentry(file), &attr, file);
|
||||
fuse_do_setattr(file_mnt_idmap(file), file_dentry(file), &attr, file);
|
||||
}
|
||||
|
||||
static inline loff_t fuse_round_up(struct fuse_conn *fc, loff_t off)
|
||||
|
@ -845,6 +845,9 @@ struct fuse_conn {
|
||||
/* Add supplementary group info when creating a new inode */
|
||||
unsigned int create_supp_group:1;
|
||||
|
||||
/* Add owner_{u,g}id info when creating a new inode */
|
||||
unsigned int owner_uid_gid_ext:1;
|
||||
|
||||
/* Does the filesystem support per inode DAX? */
|
||||
unsigned int inode_dax:1;
|
||||
|
||||
@ -1330,8 +1333,8 @@ bool fuse_write_update_attr(struct inode *inode, loff_t pos, ssize_t written);
|
||||
int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
|
||||
int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
|
||||
int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
||||
struct file *file);
|
||||
int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr, struct file *file);
|
||||
|
||||
void fuse_set_initialized(struct fuse_conn *fc);
|
||||
|
||||
|
@ -1343,6 +1343,14 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
|
||||
}
|
||||
if (flags & FUSE_NO_EXPORT_SUPPORT)
|
||||
fm->sb->s_export_op = &fuse_export_fid_operations;
|
||||
if (flags & FUSE_OWNER_UID_GID_EXT)
|
||||
fc->owner_uid_gid_ext = 1;
|
||||
if (flags & FUSE_ALLOW_IDMAP) {
|
||||
if (fc->owner_uid_gid_ext && fc->default_permissions)
|
||||
fm->sb->s_iflags &= ~SB_I_NOIDMAP;
|
||||
else
|
||||
ok = false;
|
||||
}
|
||||
} else {
|
||||
ra_pages = fc->max_read / PAGE_SIZE;
|
||||
fc->no_lock = 1;
|
||||
@ -1390,7 +1398,8 @@ void fuse_send_init(struct fuse_mount *fm)
|
||||
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
|
||||
FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
|
||||
FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
|
||||
FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND;
|
||||
FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_OWNER_UID_GID_EXT |
|
||||
FUSE_ALLOW_IDMAP;
|
||||
#ifdef CONFIG_FUSE_DAX
|
||||
if (fm->fc->dax)
|
||||
flags |= FUSE_MAP_ALIGNMENT;
|
||||
@ -1567,6 +1576,7 @@ static void fuse_sb_defaults(struct super_block *sb)
|
||||
sb->s_time_gran = 1;
|
||||
sb->s_export_op = &fuse_export_operations;
|
||||
sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE;
|
||||
sb->s_iflags |= SB_I_NOIDMAP;
|
||||
if (sb->s_user_ns != &init_user_ns)
|
||||
sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
|
||||
sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);
|
||||
@ -1979,7 +1989,7 @@ static void fuse_kill_sb_anon(struct super_block *sb)
|
||||
static struct file_system_type fuse_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "fuse",
|
||||
.fs_flags = FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
|
||||
.fs_flags = FS_HAS_SUBTYPE | FS_USERNS_MOUNT | FS_ALLOW_IDMAP,
|
||||
.init_fs_context = fuse_init_fs_context,
|
||||
.parameters = fuse_fs_parameters,
|
||||
.kill_sb = fuse_kill_sb_anon,
|
||||
@ -2000,7 +2010,7 @@ static struct file_system_type fuseblk_fs_type = {
|
||||
.init_fs_context = fuse_init_fs_context,
|
||||
.parameters = fuse_fs_parameters,
|
||||
.kill_sb = fuse_kill_sb_blk,
|
||||
.fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
|
||||
.fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE | FS_ALLOW_IDMAP,
|
||||
};
|
||||
MODULE_ALIAS_FS("fuseblk");
|
||||
|
||||
|
@ -1628,6 +1628,7 @@ static struct file_system_type virtio_fs_type = {
|
||||
.name = "virtiofs",
|
||||
.init_fs_context = virtio_fs_init_fs_context,
|
||||
.kill_sb = virtio_kill_sb,
|
||||
.fs_flags = FS_ALLOW_IDMAP,
|
||||
};
|
||||
|
||||
static int virtio_fs_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
|
||||
|
@ -4471,6 +4471,10 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
|
||||
if (!(m->mnt_sb->s_type->fs_flags & FS_ALLOW_IDMAP))
|
||||
return -EINVAL;
|
||||
|
||||
/* The filesystem has turned off idmapped mounts. */
|
||||
if (m->mnt_sb->s_iflags & SB_I_NOIDMAP)
|
||||
return -EINVAL;
|
||||
|
||||
/* We're not controlling the superblock. */
|
||||
if (!ns_capable(fs_userns, CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
@ -1204,6 +1204,7 @@ extern int send_sigurg(struct fown_struct *fown);
|
||||
#define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */
|
||||
#define SB_I_RETIRED 0x00000800 /* superblock shouldn't be reused */
|
||||
#define SB_I_NOUMASK 0x00001000 /* VFS does not apply umask */
|
||||
#define SB_I_NOIDMAP 0x00002000 /* No idmapped mounts on this superblock */
|
||||
|
||||
/* Possible states of 'frozen' field */
|
||||
enum {
|
||||
|
@ -217,6 +217,11 @@
|
||||
* - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag
|
||||
* - add FUSE_NO_EXPORT_SUPPORT init flag
|
||||
* - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag
|
||||
*
|
||||
* 7.41
|
||||
* - add FUSE_EXT_OWNER_UID_GID
|
||||
* - add FUSE_OWNER_UID_GID_EXT
|
||||
* - add FUSE_ALLOW_IDMAP
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
@ -252,7 +257,7 @@
|
||||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 40
|
||||
#define FUSE_KERNEL_MINOR_VERSION 41
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
@ -421,6 +426,9 @@ struct fuse_file_lock {
|
||||
* FUSE_NO_EXPORT_SUPPORT: explicitly disable export support
|
||||
* FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit
|
||||
* of the request ID indicates resend requests
|
||||
* FUSE_OWNER_UID_GID_EXT: add inode owner UID/GID info to create, mkdir,
|
||||
* symlink and mknod
|
||||
* FUSE_ALLOW_IDMAP: allow creation of idmapped mounts
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
@ -466,6 +474,8 @@ struct fuse_file_lock {
|
||||
|
||||
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
|
||||
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
|
||||
#define FUSE_OWNER_UID_GID_EXT (1ULL << 40)
|
||||
#define FUSE_ALLOW_IDMAP (1ULL << 41)
|
||||
|
||||
/**
|
||||
* CUSE INIT request/reply flags
|
||||
@ -575,11 +585,13 @@ struct fuse_file_lock {
|
||||
* extension type
|
||||
* FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx
|
||||
* FUSE_EXT_GROUPS: &fuse_supp_groups extension
|
||||
* FUSE_EXT_OWNER_UID_GID: &fuse_owner_uid_gid extension
|
||||
*/
|
||||
enum fuse_ext_type {
|
||||
/* Types 0..31 are reserved for fuse_secctx_header */
|
||||
FUSE_MAX_NR_SECCTX = 31,
|
||||
FUSE_EXT_GROUPS = 32,
|
||||
FUSE_EXT_OWNER_UID_GID = 33,
|
||||
};
|
||||
|
||||
enum fuse_opcode {
|
||||
@ -1186,4 +1198,14 @@ struct fuse_supp_groups {
|
||||
uint32_t groups[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fuse_owner_uid_gid - Inode owner UID/GID extension
|
||||
* @uid: inode owner UID
|
||||
* @gid: inode owner GID
|
||||
*/
|
||||
struct fuse_owner_uid_gid {
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_FUSE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user