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

Merge branch 'aufs5.x-rcN/00base' into aufs5.x-rcN/01modular

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