Commit 2a8c810d authored by Alexander Mikhalitsyn's avatar Alexander Mikhalitsyn Committed by Miklos Szeredi

fuse: support idmapped getattr inode op

We have to:
- pass an idmapping to the generic_fillattr()
to properly handle UIG/GID mapping for the userspace.
- pass -/- to fuse_fillattr() (analog of generic_fillattr() in fuse).

Difference between these two is that generic_fillattr() takes all the
stat() data from the inode directly, while fuse_fillattr() codepath takes a
fresh data just from the userspace reply on the FUSE_GETATTR request.

In some cases we can just pass &nop_mnt_idmap, because idmapping won't be
used in these codepaths. For example, when 3rd argument of
fuse_do_getattr() is NULL then idmap argument is not used.
Signed-off-by: default avatarAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Reviewed-by: default avatarChristian Brauner <brauner@kernel.org>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 556208e1
...@@ -1135,18 +1135,22 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, ...@@ -1135,18 +1135,22 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
return err; return err;
} }
static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode,
struct kstat *stat) struct fuse_attr *attr, struct kstat *stat)
{ {
unsigned int blkbits; unsigned int blkbits;
struct fuse_conn *fc = get_fuse_conn(inode); 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->dev = inode->i_sb->s_dev;
stat->ino = attr->ino; stat->ino = attr->ino;
stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
stat->nlink = attr->nlink; stat->nlink = attr->nlink;
stat->uid = make_kuid(fc->user_ns, attr->uid); stat->uid = vfsuid_into_kuid(vfsuid);
stat->gid = make_kgid(fc->user_ns, attr->gid); stat->gid = vfsgid_into_kgid(vfsgid);
stat->rdev = inode->i_rdev; stat->rdev = inode->i_rdev;
stat->atime.tv_sec = attr->atime; stat->atime.tv_sec = attr->atime;
stat->atime.tv_nsec = attr->atimensec; stat->atime.tv_nsec = attr->atimensec;
...@@ -1185,8 +1189,8 @@ static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr) ...@@ -1185,8 +1189,8 @@ static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr)
attr->blksize = sx->blksize; attr->blksize = sx->blksize;
} }
static int fuse_do_statx(struct inode *inode, struct file *file, static int fuse_do_statx(struct mnt_idmap *idmap, struct inode *inode,
struct kstat *stat) struct file *file, struct kstat *stat)
{ {
int err; int err;
struct fuse_attr attr; struct fuse_attr attr;
...@@ -1239,15 +1243,15 @@ static int fuse_do_statx(struct inode *inode, struct file *file, ...@@ -1239,15 +1243,15 @@ static int fuse_do_statx(struct inode *inode, struct file *file,
stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME); stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME);
stat->btime.tv_sec = sx->btime.tv_sec; stat->btime.tv_sec = sx->btime.tv_sec;
stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1); 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; stat->result_mask |= STATX_TYPE;
} }
return 0; return 0;
} }
static int fuse_do_getattr(struct inode *inode, struct kstat *stat, static int fuse_do_getattr(struct mnt_idmap *idmap, struct inode *inode,
struct file *file) struct kstat *stat, struct file *file)
{ {
int err; int err;
struct fuse_getattr_in inarg; struct fuse_getattr_in inarg;
...@@ -1286,15 +1290,15 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, ...@@ -1286,15 +1290,15 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
ATTR_TIMEOUT(&outarg), ATTR_TIMEOUT(&outarg),
attr_version); attr_version);
if (stat) if (stat)
fuse_fillattr(inode, &outarg.attr, stat); fuse_fillattr(idmap, inode, &outarg.attr, stat);
} }
} }
return err; return err;
} }
static int fuse_update_get_attr(struct inode *inode, struct file *file, static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
struct kstat *stat, u32 request_mask, struct file *file, struct kstat *stat,
unsigned int flags) u32 request_mask, unsigned int flags)
{ {
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
...@@ -1325,17 +1329,17 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, ...@@ -1325,17 +1329,17 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
forget_all_cached_acls(inode); forget_all_cached_acls(inode);
/* Try statx if BTIME is requested */ /* Try statx if BTIME is requested */
if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) { 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) { if (err == -ENOSYS) {
fc->no_statx = 1; fc->no_statx = 1;
err = 0; err = 0;
goto retry; goto retry;
} }
} else { } else {
err = fuse_do_getattr(inode, stat, file); err = fuse_do_getattr(idmap, inode, stat, file);
} }
} else if (stat) { } 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->mode = fi->orig_i_mode;
stat->ino = fi->orig_ino; stat->ino = fi->orig_ino;
if (test_bit(FUSE_I_BTIME, &fi->state)) { if (test_bit(FUSE_I_BTIME, &fi->state)) {
...@@ -1349,7 +1353,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, ...@@ -1349,7 +1353,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask) 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, int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
...@@ -1493,7 +1497,7 @@ static int fuse_perm_getattr(struct inode *inode, int mask) ...@@ -1493,7 +1497,7 @@ static int fuse_perm_getattr(struct inode *inode, int mask)
return -ECHILD; return -ECHILD;
forget_all_cached_acls(inode); forget_all_cached_acls(inode);
return fuse_do_getattr(inode, NULL, NULL); return fuse_do_getattr(&nop_mnt_idmap, inode, NULL, NULL);
} }
/* /*
...@@ -2072,7 +2076,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry, ...@@ -2072,7 +2076,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
* ia_mode calculation may have used stale i_mode. * ia_mode calculation may have used stale i_mode.
* Refresh and recalculate. * Refresh and recalculate.
*/ */
ret = fuse_do_getattr(inode, NULL, file); ret = fuse_do_getattr(idmap, inode, NULL, file);
if (ret) if (ret)
return ret; return ret;
...@@ -2129,7 +2133,7 @@ static int fuse_getattr(struct mnt_idmap *idmap, ...@@ -2129,7 +2133,7 @@ static int fuse_getattr(struct mnt_idmap *idmap,
return -EACCES; 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 = { static const struct inode_operations fuse_dir_inode_operations = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment