Commit 85fab2b2 authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: v5.12-rc1 idmapper userns 1/2, new parameter



In mainline, by the commit
	549c7297717c3 2021-01-24 fs: make helpers idmap mount aware
and its series, a new parameter 'user_ns' was added to some inode
operations.  Aufs simply follows it, but it is still testing.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent ccc9496d
......@@ -133,6 +133,11 @@ static inline struct dentry *au_br_dentry(struct au_branch *br)
return br->br_path.dentry;
}
static inline struct user_namespace *au_br_userns(struct au_branch *br)
{
return mnt_user_ns(br->br_path.mnt);
}
static inline struct super_block *au_br_sb(struct au_branch *br)
{
return au_br_mnt(br)->mnt_sb;
......@@ -291,6 +296,12 @@ struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex)
return au_br_mnt(au_sbr(sb, bindex));
}
static inline
struct user_namespace *au_sbr_userns(struct super_block *sb, aufs_bindex_t bindex)
{
return au_br_userns(au_sbr(sb, bindex));
}
static inline
struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex)
{
......
......@@ -151,7 +151,7 @@ struct au_cpup_reg_attr {
};
static noinline_for_stack
int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct path *h_src,
struct au_cpup_reg_attr *h_src_attr)
{
int err, sbits, icex;
......@@ -163,11 +163,11 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
struct kstat *h_st;
struct au_branch *br;
h_path.dentry = au_h_dptr(dst, bindex);
h_idst = d_inode(h_path.dentry);
br = au_sbr(dst->d_sb, bindex);
h_path.mnt = au_br_mnt(br);
h_isrc = d_inode(h_src);
h_path.dentry = au_h_dptr(dst, bindex);
h_idst = d_inode(h_path.dentry);
h_isrc = d_inode(h_src->dentry);
ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
| ATTR_ATIME | ATTR_MTIME
| ATTR_ATIME_SET | ATTR_MTIME_SET;
......@@ -211,7 +211,7 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
if (!err) {
mnt_flags = au_mntflags(dst->d_sb);
verbose = !!au_opt_test(mnt_flags, VERBOSE);
err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose);
err = au_cpup_xattr(&h_path, h_src, icex, verbose);
}
return err;
......@@ -581,16 +581,18 @@ static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode)
int err;
struct dentry *h_dentry;
struct inode *h_inode;
struct user_namespace *h_userns;
h_userns = mnt_user_ns(h_path->mnt);
h_dentry = h_path->dentry;
h_inode = d_inode(h_dentry);
/* forget_all_cached_acls(h_inode)); */
err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS);
err = vfsub_removexattr(h_userns, h_dentry, XATTR_NAME_POSIX_ACL_ACCESS);
AuTraceErr(err);
if (err == -EOPNOTSUPP)
err = 0;
if (!err)
err = vfsub_acl_chmod(h_inode, mode);
err = vfsub_acl_chmod(h_userns, h_inode, mode);
AuTraceErr(err);
return err;
......@@ -601,8 +603,11 @@ static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent,
{
int err;
struct inode *dir, *inode;
struct user_namespace *h_userns;
err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT);
h_userns = mnt_user_ns(h_path->mnt);
err = vfsub_removexattr(h_userns, h_path->dentry,
XATTR_NAME_POSIX_ACL_DEFAULT);
AuTraceErr(err);
if (err == -EOPNOTSUPP)
err = 0;
......@@ -783,6 +788,7 @@ static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode;
struct super_block *sb;
struct au_branch *br;
struct path h_src_path;
/* to reduce stack size */
struct {
struct au_dtime dt;
......@@ -874,7 +880,9 @@ static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
/* todo: necessary? */
/* au_pin_hdir_unlock(cpg->pin); */
err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr);
h_src_path.dentry = h_src;
h_src_path.mnt = au_sbr_mnt(sb, cpg->bsrc);
err = cpup_iattr(cpg->dentry, cpg->bdst, &h_src_path, &a->h_src_attr);
if (unlikely(err)) {
/* todo: necessary? */
/* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */
......@@ -1076,6 +1084,7 @@ static int au_do_sio_cpup_simple(struct au_cp_generic *cpg)
struct dentry *dentry, *parent;
struct file *h_file;
struct inode *h_dir;
struct user_namespace *h_userns;
dentry = cpg->dentry;
h_file = NULL;
......@@ -1089,7 +1098,8 @@ static int au_do_sio_cpup_simple(struct au_cp_generic *cpg)
parent = dget_parent(dentry);
h_dir = au_h_iptr(d_inode(parent), cpg->bdst);
if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE)
h_userns = au_sbr_userns(dentry->d_sb, cpg->bdst);
if (!au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC | MAY_WRITE)
&& !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode))
err = au_cpup_simple(cpg);
else {
......@@ -1259,6 +1269,7 @@ int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file)
struct inode *dir, *h_dir, *h_tmpdir;
struct au_wbr *wbr;
struct au_pin wh_pin, *pin_orig;
struct user_namespace *h_userns;
dentry = cpg->dentry;
bdst = cpg->bdst;
......@@ -1287,7 +1298,8 @@ int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file)
cpg->pin = &wh_pin;
}
if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE)
h_userns = au_sbr_userns(dentry->d_sb, bdst);
if (!au_test_h_perm_sio(h_userns, h_tmpdir, MAY_EXEC | MAY_WRITE)
&& !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode))
err = au_cpup_wh(cpg, file);
else {
......
......@@ -22,6 +22,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
struct dentry *h_dentry;
struct inode *h_inode;
struct au_branch *br;
struct user_namespace *h_userns;
int wh_found, opq;
unsigned char wh_able;
const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
......@@ -30,9 +31,11 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
wh_found = 0;
br = au_sbr(dentry->d_sb, bindex);
h_userns = au_br_userns(br);
wh_able = !!au_br_whable(br->br_perm);
if (wh_able)
wh_found = au_wh_test(h_parent, &args->whname, ignore_perm);
wh_found = au_wh_test(h_userns, h_parent, &args->whname,
ignore_perm);
h_dentry = ERR_PTR(wh_found);
if (!wh_found)
goto real_lookup;
......@@ -49,7 +52,7 @@ real_lookup:
if (!ignore_perm)
h_dentry = vfsub_lkup_one(args->name, h_parent);
else
h_dentry = au_sio_lkup_one(args->name, h_parent);
h_dentry = au_sio_lkup_one(h_userns, args->name, h_parent);
if (IS_ERR(h_dentry)) {
if (PTR_ERR(h_dentry) == -ENAMETOOLONG
&& !allow_neg)
......@@ -84,7 +87,7 @@ real_lookup:
goto out; /* success */
inode_lock_shared_nested(h_inode, AuLsc_I_CHILD);
opq = au_diropq_test(h_dentry);
opq = au_diropq_test(h_userns, h_dentry);
inode_unlock_shared(h_inode);
if (opq > 0)
au_set_dbdiropq(dentry, bindex);
......@@ -229,12 +232,13 @@ out:
return err;
}
struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent)
struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name,
struct dentry *parent)
{
struct dentry *dentry;
int wkq_err;
if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC))
if (!au_test_h_perm_sio(userns, d_inode(parent), MAY_EXEC))
dentry = vfsub_lkup_one(name, parent);
else {
struct vfsub_lkup_one_args args = {
......@@ -259,14 +263,16 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh)
int err;
struct dentry *parent, *h_parent, *h_dentry;
struct au_branch *br;
struct user_namespace *h_userns;
parent = dget_parent(dentry);
h_parent = au_h_dptr(parent, bindex);
br = au_sbr(dentry->d_sb, bindex);
h_userns = au_br_userns(br);
if (wh)
h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
else
h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent);
h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
err = PTR_ERR(h_dentry);
if (IS_ERR(h_dentry))
goto out;
......
......@@ -60,7 +60,8 @@ struct au_do_lookup_args {
/* dentry.c */
extern const struct dentry_operations aufs_dop, aufs_dop_noreval;
struct au_branch;
struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent);
struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name,
struct dentry *parent);
int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
struct dentry *h_parent, struct au_branch *br);
......
......@@ -624,12 +624,14 @@ static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
int err, wkq_err;
struct dentry *h_dentry;
struct inode *h_inode;
struct user_namespace *h_userns;
h_userns = au_sbr_userns(dentry->d_sb, arg->bindex);
h_dentry = au_h_dptr(dentry, arg->bindex);
h_inode = d_inode(h_dentry);
/* todo: i_mode changes anytime? */
inode_lock_shared_nested(h_inode, AuLsc_I_CHILD);
err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ);
err = au_test_h_perm_sio(h_userns, h_inode, MAY_EXEC | MAY_READ);
inode_unlock_shared(h_inode);
if (!err)
err = do_test_empty(dentry, arg);
......
......@@ -19,6 +19,7 @@ static int h_permission(struct inode *h_inode, int mask,
{
int err;
const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
struct user_namespace *h_userns;
err = -EPERM;
if (write_mask && IS_IMMUTABLE(h_inode))
......@@ -38,19 +39,21 @@ static int h_permission(struct inode *h_inode, int mask,
* - nfs always sets SB_POSIXACL regardless its mount option 'noacl.'
* in this case, generic_permission() returns -EOPNOTSUPP.
*/
h_userns = mnt_user_ns(h_path->mnt);
if ((write_mask && !au_br_writable(brperm))
|| (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode)
&& write_mask && !(mask & MAY_READ))
|| !h_inode->i_op->permission) {
/* AuLabel(generic_permission); */
/* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */
err = generic_permission(h_inode, mask);
err = generic_permission(h_userns, h_inode, mask);
if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode))
err = h_inode->i_op->permission(h_inode, mask);
err = h_inode->i_op->permission(h_userns, h_inode,
mask);
AuTraceErr(err);
} else {
/* AuLabel(h_inode->permission); */
err = h_inode->i_op->permission(h_inode, mask);
err = h_inode->i_op->permission(h_userns, h_inode, mask);
AuTraceErr(err);
}
......@@ -63,7 +66,8 @@ out:
return err;
}
static int aufs_permission(struct inode *inode, int mask)
static int aufs_permission(struct user_namespace *userns, struct inode *inode,
int mask)
{
int err;
aufs_bindex_t bindex, bbot;
......@@ -911,18 +915,20 @@ out:
return err;
}
static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
static int aufs_setattr(struct user_namespace *userns, struct dentry *dentry,
struct iattr *ia)
{
int err;
struct inode *inode, *delegated;
struct super_block *sb;
struct file *file;
struct au_icpup_args *a;
struct user_namespace *h_userns;
inode = d_inode(dentry);
IMustLock(inode);
err = setattr_prepare(dentry, ia);
err = setattr_prepare(userns, dentry, ia);
if (unlikely(err))
goto out;
......@@ -1015,8 +1021,10 @@ static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
* regardless aufs 'acl' option setting.
* why don't all acl-aware fs call this func from their ->setattr()?
*/
if (!err && (ia->ia_valid & ATTR_MODE))
err = vfsub_acl_chmod(a->h_inode, ia->ia_mode);
if (!err && (ia->ia_valid & ATTR_MODE)) {
h_userns = mnt_user_ns(a->h_path.mnt);
err = vfsub_acl_chmod(h_userns, a->h_inode, ia->ia_mode);
}
if (!err)
au_cpup_attr_changeable(inode);
......@@ -1078,6 +1086,7 @@ ssize_t au_sxattr(struct dentry *dentry, struct inode *inode,
struct super_block *sb;
struct au_icpup_args *a;
struct inode *h_inode;
struct user_namespace *h_userns;
IMustLock(inode);
......@@ -1096,23 +1105,25 @@ ssize_t au_sxattr(struct dentry *dentry, struct inode *inode,
err = au_h_path_to_set_attr(dentry, a, &h_path);
if (unlikely(err))
goto out_di;
h_userns = mnt_user_ns(h_path.mnt);
inode_unlock(a->h_inode);
switch (arg->type) {
case AU_XATTR_SET:
AuDebugOn(d_is_negative(h_path.dentry));
err = vfsub_setxattr(h_path.dentry,
err = vfsub_setxattr(h_userns, h_path.dentry,
arg->u.set.name, arg->u.set.value,
arg->u.set.size, arg->u.set.flags);
break;
case AU_ACL_SET:
err = -EOPNOTSUPP;
h_inode = d_inode(h_path.dentry);
if (h_inode->i_op->set_acl)
if (h_inode->i_op->set_acl) {
/* this will call posix_acl_update_mode */
err = h_inode->i_op->set_acl(h_inode,
err = h_inode->i_op->set_acl(h_userns, h_inode,
arg->u.acl_set.acl,
arg->u.acl_set.type);
}
break;
}
if (!err)
......@@ -1243,8 +1254,8 @@ out:
return err;
}
static int aufs_getattr(const struct path *path, struct kstat *st,
u32 request, unsigned int query)
static int aufs_getattr(struct user_namespace *userns, const struct path *path,
struct kstat *st, u32 request, unsigned int query)
{
int err;
unsigned char positive;
......@@ -1281,7 +1292,7 @@ static int aufs_getattr(const struct path *path, struct kstat *st,
goto out_di;
out_fill:
generic_fillattr(inode, st);
generic_fillattr(userns, inode, st);
out_di:
di_read_unlock(dentry, AuLock_IR);
out_si:
......
......@@ -353,8 +353,8 @@ out:
return err;
}
int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
dev_t dev)
int aufs_mknod(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t dev)
{
struct simple_arg arg = {
.type = Mknod,
......@@ -366,7 +366,8 @@ int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
return add_simple(dir, dentry, &arg);
}
int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
int aufs_symlink(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, const char *symname)
{
struct simple_arg arg = {
.type = Symlink,
......@@ -375,8 +376,8 @@ int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
return add_simple(dir, dentry, &arg);
}
int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
bool want_excl)
int aufs_create(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode, bool want_excl)
{
struct simple_arg arg = {
.type = Creat,
......@@ -403,7 +404,8 @@ int au_aopen_or_create(struct inode *dir, struct dentry *dentry,
return add_simple(dir, dentry, &arg);
}
int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
int aufs_tmpfile(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode)
{
int err;
aufs_bindex_t bindex;
......@@ -411,6 +413,7 @@ int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
struct dentry *parent, *h_parent, *h_dentry;
struct inode *h_dir, *inode;
struct vfsmount *h_mnt;
struct user_namespace *h_userns;
struct au_wr_dir_args wr_dir_args = {
.force_btgt = -1,
.flags = AuWrDir_TMPFILE
......@@ -457,8 +460,9 @@ int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
if (unlikely(err))
goto out_parent;
h_userns = mnt_user_ns(h_mnt);
h_parent = au_h_dptr(parent, bindex);
h_dentry = vfs_tmpfile(h_parent, mode, /*open_flag*/0);
h_dentry = vfs_tmpfile(h_userns, h_parent, mode, /*open_flag*/0);
if (IS_ERR(h_dentry)) {
err = PTR_ERR(h_dentry);
goto out_mnt;
......@@ -814,7 +818,8 @@ out:
return err;
}
int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
int aufs_mkdir(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode)
{
int err, rerr;
aufs_bindex_t bindex;
......
......@@ -81,6 +81,7 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
umode_t h_mode;
struct dentry *h_dentry, *h_latest;
struct inode *h_inode;
struct user_namespace *h_userns;
h_dentry = au_h_dptr(dentry, bindex);
if (d_really_is_positive(dentry)) {
......@@ -118,12 +119,13 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
* let's try heavy test.
*/
err = -EACCES;
h_userns = au_sbr_userns(dentry->d_sb, bindex);
if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)
&& au_test_h_perm(d_inode(h_parent),
&& au_test_h_perm(h_userns, d_inode(h_parent),
MAY_EXEC | MAY_WRITE)))
goto out;
h_latest = au_sio_lkup_one(&dentry->d_name, h_parent);
h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
err = -EIO;
if (IS_ERR(h_latest))
goto out;
......
......@@ -940,7 +940,8 @@ static void au_ren_rev_dt(int err, struct au_ren_args *a)
/* ---------------------------------------------------------------------- */
int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
int aufs_rename(struct user_namespace *userns,
struct inode *_src_dir, struct dentry *_src_dentry,
struct inode *_dst_dir, struct dentry *_dst_dentry,
unsigned int _flags)
{
......
......@@ -499,18 +499,20 @@ int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
return err;
}
int au_test_h_perm(struct inode *h_inode, int mask)
int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode,
int mask)
{
if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID))
return 0;
return inode_permission(h_inode, mask);
return inode_permission(h_userns, h_inode, mask);
}
int au_test_h_perm_sio(struct inode *h_inode, int mask)
int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode,
int mask)
{
if (au_test_nfs(h_inode->i_sb)
&& (mask & MAY_WRITE)
&& S_ISDIR(h_inode->i_mode))
mask |= MAY_READ; /* force permission check */
return au_test_h_perm(h_inode, mask);
return au_test_h_perm(h_userns, h_inode, mask);
}
......@@ -124,8 +124,10 @@ int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
struct inode *au_new_inode(struct dentry *dentry, int must_new);
int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
struct inode *inode);
int au_test_h_perm(struct inode *h_inode, int mask);
int au_test_h_perm_sio(struct inode *h_inode, int mask);
int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode,
int mask);
int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode,
int mask);
static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex,
ino_t h_ino, unsigned int d_type, ino_t *ino)
......@@ -200,18 +202,21 @@ int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force,
/* i_op_add.c */
int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_parent, int isdir);
int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
dev_t dev);
int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
bool want_excl);
int aufs_mknod(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t dev);
int aufs_symlink(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, const char *symname);
int aufs_create(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode, bool want_excl);
struct vfsub_aopen_args;
int au_aopen_or_create(struct inode *dir, struct dentry *dentry,
struct vfsub_aopen_args *args);
int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode);
int aufs_tmpfile(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode);
int aufs_link(struct dentry *src_dentry, struct inode *dir,
struct dentry *dentry);
int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
int aufs_mkdir(struct user_namespace *userns, struct inode *dir,
struct dentry *dentry, umode_t mode);
/* i_op_del.c */
int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
......@@ -222,9 +227,10 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry);
/* i_op_ren.c */
int au_wbr(struct dentry *dentry, aufs_bindex_t btgt);
int aufs_rename(struct inode *src_dir, struct dentry *src_dentry,
struct inode *dir, struct dentry *dentry,
unsigned int flags);
int aufs_rename(struct user_namespace *userns,
struct inode *_src_dir, struct dentry *_src_dentry,
struct inode *_dst_dir, struct dentry *_dst_dentry,
unsigned int _flags);
/* iinfo.c */
struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
......@@ -294,19 +300,20 @@ AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
#ifdef CONFIG_AUFS_XATTR
/* xattr.c */
int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags,
unsigned int verbose);
ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size);
void au_xattr_init(struct super_block *sb);
#else
AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src,
AuStubInt0(au_cpup_xattr, struct path *h_dst, struct path *h_src,
int ignore_flags, unsigned int verbose);
AuStubVoid(au_xattr_init, struct super_block *sb);
#endif
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *aufs_get_acl(struct inode *inode, int type);
int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
int aufs_set_acl(struct user_namespace *userns, struct inode *inode,
struct posix_acl *acl, int type);
#endif
#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL)
......
......@@ -50,7 +50,8 @@ out:
return acl;
}
int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
int aufs_set_acl(struct user_namespace *userns, struct inode *inode,
struct posix_acl *acl, int type)
{
int err;
ssize_t ssz;
......
......@@ -1026,7 +1026,10 @@ static void aufs_kill_sb(struct super_block *sb)
struct file_system_type aufs_fs_type = {
.name = AUFS_FSTYPE,
/* a race between rename and others */
.fs_flags = FS_RENAME_DOES_D_MOVE,
.fs_flags = FS_RENAME_DOES_D_MOVE
/* untested */
/*| FS_ALLOW_IDMAP*/
,
.mount = aufs_mount,
.kill_sb = aufs_kill_sb,
/* no need to __module_get() and module_put(). */
......
......@@ -231,6 +231,7 @@ int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl)
{
int err;
struct dentry *d;
struct user_namespace *userns;
IMustLock(dir);
......@@ -240,9 +241,10 @@ int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl)
path->dentry = d;
if (unlikely(err))
goto out;
userns = mnt_user_ns(path->mnt);
lockdep_off();
err = vfs_create(dir, path->dentry, mode, want_excl);
err = vfs_create(userns, dir, path->dentry, mode, want_excl);
lockdep_on();
if (!err) {
struct path tmp = *path;
......@@ -264,6 +266,7 @@ int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
{
int err;
struct dentry *d;
struct user_namespace *userns;
IMustLock(dir);
......@@ -273,9 +276,10 @@ int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
path->dentry = d;
if (unlikely(err))
goto out;
userns = mnt_user_ns(path->mnt);
lockdep_off();
err = vfs_symlink(dir, path->dentry, symname);
err = vfs_symlink(userns, dir, path->dentry, symname);
lockdep_on();
if (!err) {
struct path tmp = *path;
......@@ -297,6 +301,7 @@ int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
{
int err;
struct dentry *d;
struct user_namespace *userns;
IMustLock(dir);
......@@ -306,9 +311,10 @@ int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
path->dentry = d;
if (unlikely(err))
goto out;
userns = mnt_user_ns(path->mnt);
lockdep_off();
err = vfs_mknod(dir, path->dentry, mode, dev);
err = vfs_mknod(userns, dir, path->dentry, mode, dev);
lockdep_on();
if (!err) {
struct path tmp = *path;
......@@ -341,6 +347,7 @@ int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path,
{
int err;
struct dentry *d;
struct user_namespace *userns;
IMustLock(dir);
......@@ -355,9 +362,10 @@ int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path,
path->dentry = d;
if (unlikely(err))
goto out;
userns = mnt_user_ns(path->mnt);
lockdep_off();
err = vfs_link(src_dentry, dir, path->dentry, delegated_inode);
err = vfs_link(src_dentry, userns, dir, path->dentry, delegated_inode);
lockdep_on();
if (!err) {
struct path tmp = *path;
......@@ -383,6 +391,7 @@ int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
struct inode **delegated_inode, unsigned int flags)
{
int err;
struct renamedata rd;
struct path tmp = {
.mnt = path->mnt
};
......@@ -399,9 +408,16 @@ int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
if (unlikely(err))
goto out;
rd.old_mnt_userns = mnt_user_ns(path->mnt);
rd.old_dir = src_dir;
rd.old_dentry = src_dentry;
rd.new_mnt_userns = rd.old_mnt_userns;
rd.new_dir = dir;
rd.new_dentry = path->dentry;
rd.delegated_inode = delegated_inode;
rd.flags = flags;
lockdep_off();
err = vfs_rename(src_dir, src_dentry, dir, path->dentry,
delegated_inode, flags);
err = vfs_rename(&rd);
lockdep_on();
if (!err) {
int did;
......@@ -425,6 +441,7 @@ int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
{
int err;
struct dentry *d;
struct user_namespace *userns;
IMustLock(dir);
......@@ -434,9 +451,10 @@ int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
path->dentry = d;
if (unlikely(err))
goto out;
userns = mnt_user_ns(path->mnt);
lockdep_off();
err = vfs_mkdir(dir, path->dentry, mode);
err = vfs_mkdir(userns, dir, path->dentry, mode);
lockdep_on();
if (!err) {
struct path tmp = *path;
......@@ -458,6 +476,7 @@ int vfsub_rmdir(struct inode *dir, struct path *path)
{
int err;
struct dentry *d;
struct user_namespace *userns;
IMustLock(dir);
......@@ -467,9 +486,10 @@ int vfsub_rmdir(struct inode *dir, struct path *path)
path->dentry = d;
if (unlikely(err))
goto out;
userns = mnt_user_ns(path->mnt);
lockdep_off();
err = vfs_rmdir(dir, path->dentry);
err = vfs_rmdir(userns, dir, path->dentry);
lockdep_on();
if (!err) {
struct path tmp = {
......@@ -627,6 +647,7 @@ int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
int err;
struct inode *h_inode;
struct super_block *h_sb;
struct user_namespace *h_userns;
if (!h_file) {
err = vfsub_truncate(h_path, length);
......@@ -642,8 +663,10 @@ int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
if (!err)
err = security_path_truncate(h_path);
if (!err) {
h_userns = mnt_user_ns(h_path->mnt);
lockdep_off();
err = do_truncate(h_path->dentry, length, attr, h_file);
err = do_truncate(h_userns, h_path->dentry, length, attr,
h_file);
lockdep_on();
}
lockdep_off();
......@@ -672,8 +695,10 @@ static void au_call_vfsub_mkdir(void *args)
int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode)
{
int err, do_sio, wkq_err;
struct user_namespace *userns;
do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
userns = mnt_user_ns(path->mnt);
do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE);
if (!do_sio) {
lockdep_off();
err = vfsub_mkdir(dir, path, mode);
......@@ -708,8 +733,10 @@ static void au_call_vfsub_rmdir(void *args)
int vfsub_sio_rmdir(struct inode *dir, struct path *path)
{
int err, do_sio, wkq_err;
struct user_namespace *userns;
do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
userns = mnt_user_ns(path->mnt);
do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE);
if (!do_sio) {
lockdep_off();
err = vfsub_rmdir(dir, path);
......@@ -741,14 +768,16 @@ static void call_notify_change(void *args)
{
struct notify_change_args *a = args;
struct inode *h_inode;
struct user_namespace *userns;
h_inode = d_inode(a->path->dentry);
IMustLock(h_inode);
*a->errp = -EPERM;
if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
userns = mnt_user_ns(a->path->mnt);
lockdep_off();
*a->errp = notify_change(a->path->dentry, a->ia,
*a->errp = notify_change(userns, a->path->dentry, a->ia,
a->delegated_inode);
lockdep_on();
if (!*a->errp)
......@@ -805,6 +834,7 @@ static void call_unlink(void *args)
struct unlink_args *a = args;
struct dentry *d = a->path->dentry;
struct inode *h_inode;
struct user_namespace *userns;
const int stop_sillyrename = (au_test_nfs(d->d_sb)
&& au_dcount(d) == 1);
......@@ -824,8 +854,9 @@ static void call_unlink(void *args)
ihold(h_inode);
}
userns = mnt_user_ns(a->path->mnt);
lockdep_off();
*a->errp = vfs_unlink(a->dir, d, a->delegated_inode);
*a->errp = vfs_unlink(userns, a->dir, d, a->delegated_inode);
lockdep_on();
if (!*a->errp) {
struct path tmp = {
......
......@@ -221,17 +221,19 @@ static inline int vfsub_update_time(struct inode *h_inode,
}
#ifdef CONFIG_FS_POSIX_ACL
static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode)
static inline int vfsub_acl_chmod(struct user_namespace *h_userns,
struct inode *h_inode, umode_t h_mode)
{
int err;
err = posix_acl_chmod(h_inode, h_mode);
err = posix_acl_chmod(h_userns, h_inode, h_mode);
if (err == -EOPNOTSUPP)
err = 0;
return err;
}
#else
AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode);
AuStubInt0(vfsub_acl_chmod, struct user_namespace *h_userns,
struct inode *h_inode, umode_t h_mode);
#endif
long vfsub_splice_to(struct file *in, loff_t *ppos,
......@@ -314,24 +316,26 @@ static inline int vfsub_getattr(const struct path *path, struct kstat *st)
/* ---------------------------------------------------------------------- */
static inline int vfsub_setxattr(struct dentry *dentry, const char *name,
static inline int vfsub_setxattr(struct user_namespace *userns,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
int err;
lockdep_off();
err = vfs_setxattr(dentry, name, value, size, flags);
err = vfs_setxattr(userns, dentry, name, value, size, flags);
lockdep_on();
return err;
}
static inline int vfsub_removexattr(struct dentry *dentry, const char *name)
static inline int vfsub_removexattr(struct user_namespace *userns,
struct dentry *dentry, const char *name)
{
int err;
lockdep_off();
err = vfs_removexattr(dentry, name);
err = vfs_removexattr(userns, dentry, name);
lockdep_on();
return err;
......
......@@ -51,7 +51,8 @@ int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
* test if the @wh_name exists under @h_parent.
* @try_sio specifies the necessary of super-io.
*/
int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
struct qstr *wh_name, int try_sio)
{
int err;
struct dentry *wh_dentry;
......@@ -59,7 +60,7 @@ int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
if (!try_sio)
wh_dentry = vfsub_lkup_one(wh_name, h_parent);
else
wh_dentry = au_sio_lkup_one(wh_name, h_parent);
wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_parent);
err = PTR_ERR(wh_dentry);
if (IS_ERR(wh_dentry)) {
if (err == -ENAMETOOLONG)
......@@ -88,14 +89,14 @@ out:
/*
* test if the @h_dentry sets opaque or not.
*/
int au_diropq_test(struct dentry *h_dentry)
int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry)
{
int err;
struct inode *h_dir;
h_dir = d_inode(h_dentry);
err = au_wh_test(h_dentry, &diropq_name,
au_test_h_perm_sio(h_dir, MAY_EXEC));
err = au_wh_test(h_userns, h_dentry, &diropq_name,
au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC));
return err;
}
......@@ -112,6 +113,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
/* strict atomic_t is unnecessary here */
static unsigned short cnt;
struct qstr qs;
struct user_namespace *h_userns;
BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
......@@ -135,10 +137,11 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
*p++ = '.';
AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN);
h_userns = au_br_userns(br);
qs.name = name;
for (i = 0; i < 3; i++) {
sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
dentry = au_sio_lkup_one(&qs, h_parent);
dentry = au_sio_lkup_one(h_userns, &qs, h_parent);
if (IS_ERR(dentry) || d_is_negative(dentry))
goto out_name;
dput(dentry);
......@@ -737,9 +740,12 @@ struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
unsigned int flags)
{
struct dentry *diropq, *h_dentry;
struct user_namespace *h_userns;
h_userns = au_sbr_userns(dentry->d_sb, bindex);
h_dentry = au_h_dptr(dentry, bindex);
if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE))
if (!au_test_h_perm_sio(h_userns, d_inode(h_dentry),
MAY_EXEC | MAY_WRITE))
diropq = do_diropq(dentry, bindex, flags);
else {
int wkq_err;
......@@ -925,11 +931,13 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
struct path h_tmp;
struct inode *wh_inode, *h_dir;
struct au_branch *br;
struct user_namespace *h_userns;
h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */
IMustLock(h_dir);
br = au_sbr(dir->i_sb, bindex);
h_userns = au_br_userns(br);
wh_inode = d_inode(wh_dentry);
inode_lock_nested(wh_inode, AuLsc_I_CHILD);
......@@ -937,7 +945,7 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
* someone else might change some whiteouts while we were sleeping.
* it means this whlist may have an obsoleted entry.
*/
if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE))
if (!au_test_h_perm_sio(h_userns, wh_inode, MAY_EXEC | MAY_WRITE))
err = del_wh_children(wh_dentry, whlist, bindex, br);
else {
int wkq_err;
......
......@@ -16,8 +16,9 @@
/* whout.c */
int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio);
int au_diropq_test(struct dentry *h_dentry);
int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
struct qstr *wh_name, int try_sio);
int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry);
struct au_branch;
struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
struct qstr *prefix);
......
......@@ -51,21 +51,26 @@ out:
static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1;
static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
static int au_do_cpup_xattr(struct path *h_dst, struct path *h_src,
char *name, char **buf, unsigned int ignore_flags,
unsigned int verbose)
{
int err;
ssize_t ssz;
struct inode *h_idst;
struct dentry *h_dst_dentry, *h_src_dentry;
struct user_namespace *h_dst_userns, *h_src_userns;
ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS);
h_src_userns = mnt_user_ns(h_src->mnt);
h_src_dentry = h_src->dentry;
ssz = vfs_getxattr_alloc(h_src_userns, h_src_dentry, name, buf, 0,
GFP_NOFS);
err = ssz;
if (unlikely(err <= 0)) {
if (err == -ENODATA
|| (err == -EOPNOTSUPP
&& ((ignore_flags & au_xattr_out_of_list)
|| (au_test_nfs_noacl(d_inode(h_src))
|| (au_test_nfs_noacl(d_inode(h_src_dentry))
&& (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS)
|| !strcmp(name,
XATTR_NAME_POSIX_ACL_DEFAULT))))
......@@ -77,9 +82,12 @@ static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
}
/* unlock it temporary */
h_idst = d_inode(h_dst);
h_dst_userns = mnt_user_ns(h_dst->mnt);
h_dst_dentry = h_dst->dentry;
h_idst = d_inode(h_dst_dentry);
inode_unlock(h_idst);
err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0);
err = vfsub_setxattr(h_dst_userns, h_dst_dentry, name, *buf, ssz,
/*flags*/0);
inode_lock_nested(h_idst, AuLsc_I_CHILD2);
if (unlikely(err)) {
if (verbose || au_debug_test())
......@@ -91,25 +99,28 @@ out:
return err;
}
int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags,
unsigned int verbose)
{
int err, unlocked, acl_access, acl_default;
ssize_t ssz;
struct dentry *h_dst_dentry, *h_src_dentry;
struct inode *h_isrc, *h_idst;
char *value, *p, *o, *e;
/* try stopping to update the source inode while we are referencing */
/* there should not be the parent-child relationship between them */
h_isrc = d_inode(h_src);
h_idst = d_inode(h_dst);
h_dst_dentry = h_dst->dentry;
h_idst = d_inode(h_dst_dentry);
h_src_dentry = h_src->dentry;
h_isrc = d_inode(h_src_dentry);
inode_unlock(h_idst);
inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD);
inode_lock_nested(h_idst, AuLsc_I_CHILD2);
unlocked = 0;
/* some filesystems don't list POSIX ACL, for example tmpfs */
ssz = vfs_listxattr(h_src, NULL, 0);
ssz = vfs_listxattr(h_src_dentry, NULL, 0);
err = ssz;
if (unlikely(err < 0)) {
AuTraceErr(err);
......@@ -128,7 +139,7 @@ int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
o = p;
if (unlikely(!p))
goto out;
err = vfs_listxattr(h_src, p, ssz);
err = vfs_listxattr(h_src_dentry, p, ssz);
}
inode_unlock_shared(h_isrc);
unlocked = 1;
......@@ -242,7 +253,7 @@ static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode,
break;
case AU_XATTR_GET:
AuDebugOn(d_is_negative(h_path.dentry));
err = vfs_getxattr(h_path.dentry,
err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry,
arg->u.get.name, arg->u.get.value,
arg->u.get.size);
break;
......@@ -314,6 +325,7 @@ static int au_xattr_get(const struct xattr_handler *handler,
}
static int au_xattr_set(const struct xattr_handler *handler,
struct user_namespace *userns,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value, size_t size,
int flags)
......
......@@ -245,7 +245,7 @@ struct file *au_xino_create2(struct super_block *sb, struct path *base,
}
/* no need to mnt_want_write() since we call dentry_open() later */
err = vfs_create(dir, path.dentry, 0666, NULL);
err = vfs_create(mnt_user_ns(base->mnt), dir, path.dentry, 0666, NULL);
if (unlikely(err)) {
file = ERR_PTR(err);
pr_err("%pd create err %d\n", dentry, err);
......
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