Commit d602fb68 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

Pull overlayfs fixes from Miklos Szeredi:
 "Fix regressions:

   - missing CONFIG_EXPORTFS dependency

   - failure if upper fs doesn't support xattr

   - bad error cleanup

  This also adds the concept of "impure" directories complementing the
  "origin" marking introduced in -rc1. Together they enable getting
  consistent st_ino and d_ino for directory listings.

  And there's a bug fix and a cleanup as well"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: filter trusted xattr for non-admin
  ovl: mark upper merge dir with type origin entries "impure"
  ovl: mark upper dir with type origin entries "impure"
  ovl: remove unused arg from ovl_lookup_temp()
  ovl: handle rename when upper doesn't support xattr
  ovl: don't fail copy-up if upper doesn't support xattr
  ovl: check on mount time if upper fs supports setting xattr
  ovl: fix creds leak in copy up error path
  ovl: select EXPORTFS
parents f511c0b1 a082c6f6
config OVERLAY_FS config OVERLAY_FS
tristate "Overlay filesystem support" tristate "Overlay filesystem support"
select EXPORTFS
help help
An overlay filesystem combines two filesystems - an 'upper' filesystem An overlay filesystem combines two filesystems - an 'upper' filesystem
and a 'lower' filesystem. When a name exists in both filesystems, the and a 'lower' filesystem. When a name exists in both filesystems, the
......
...@@ -300,7 +300,11 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower, ...@@ -300,7 +300,11 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
return PTR_ERR(fh); return PTR_ERR(fh);
} }
err = ovl_do_setxattr(upper, OVL_XATTR_ORIGIN, fh, fh ? fh->len : 0, 0); /*
* Do not fail when upper doesn't support xattrs.
*/
err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh,
fh ? fh->len : 0, 0);
kfree(fh); kfree(fh);
return err; return err;
...@@ -342,13 +346,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, ...@@ -342,13 +346,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
if (tmpfile) if (tmpfile)
temp = ovl_do_tmpfile(upperdir, stat->mode); temp = ovl_do_tmpfile(upperdir, stat->mode);
else else
temp = ovl_lookup_temp(workdir, dentry); temp = ovl_lookup_temp(workdir);
err = PTR_ERR(temp);
if (IS_ERR(temp))
goto out1;
err = 0; err = 0;
if (!tmpfile) if (IS_ERR(temp)) {
err = PTR_ERR(temp);
temp = NULL;
}
if (!err && !tmpfile)
err = ovl_create_real(wdir, temp, &cattr, NULL, true); err = ovl_create_real(wdir, temp, &cattr, NULL, true);
if (new_creds) { if (new_creds) {
...@@ -454,6 +459,11 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, ...@@ -454,6 +459,11 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
ovl_path_upper(parent, &parentpath); ovl_path_upper(parent, &parentpath);
upperdir = parentpath.dentry; upperdir = parentpath.dentry;
/* Mark parent "impure" because it may now contain non-pure upper */
err = ovl_set_impure(parent, upperdir);
if (err)
return err;
err = vfs_getattr(&parentpath, &pstat, err = vfs_getattr(&parentpath, &pstat,
STATX_ATIME | STATX_MTIME, AT_STATX_SYNC_AS_STAT); STATX_ATIME | STATX_MTIME, AT_STATX_SYNC_AS_STAT);
if (err) if (err)
......
...@@ -41,7 +41,7 @@ void ovl_cleanup(struct inode *wdir, struct dentry *wdentry) ...@@ -41,7 +41,7 @@ void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
} }
} }
struct dentry *ovl_lookup_temp(struct dentry *workdir, struct dentry *dentry) struct dentry *ovl_lookup_temp(struct dentry *workdir)
{ {
struct dentry *temp; struct dentry *temp;
char name[20]; char name[20];
...@@ -68,7 +68,7 @@ static struct dentry *ovl_whiteout(struct dentry *workdir, ...@@ -68,7 +68,7 @@ static struct dentry *ovl_whiteout(struct dentry *workdir,
struct dentry *whiteout; struct dentry *whiteout;
struct inode *wdir = workdir->d_inode; struct inode *wdir = workdir->d_inode;
whiteout = ovl_lookup_temp(workdir, dentry); whiteout = ovl_lookup_temp(workdir);
if (IS_ERR(whiteout)) if (IS_ERR(whiteout))
return whiteout; return whiteout;
...@@ -127,17 +127,28 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry, ...@@ -127,17 +127,28 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry,
return err; return err;
} }
static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper,
int xerr)
{ {
int err; int err;
err = ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0); err = ovl_check_setxattr(dentry, upper, OVL_XATTR_OPAQUE, "y", 1, xerr);
if (!err) if (!err)
ovl_dentry_set_opaque(dentry); ovl_dentry_set_opaque(dentry);
return err; return err;
} }
static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
{
/*
* Fail with -EIO when trying to create opaque dir and upper doesn't
* support xattrs. ovl_rename() calls ovl_set_opaque_xerr(-EXDEV) to
* return a specific error for noxattr case.
*/
return ovl_set_opaque_xerr(dentry, upperdentry, -EIO);
}
/* Common operations required to be done after creation of file on upper */ /* Common operations required to be done after creation of file on upper */
static void ovl_instantiate(struct dentry *dentry, struct inode *inode, static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
struct dentry *newdentry, bool hardlink) struct dentry *newdentry, bool hardlink)
...@@ -162,6 +173,11 @@ static bool ovl_type_merge(struct dentry *dentry) ...@@ -162,6 +173,11 @@ static bool ovl_type_merge(struct dentry *dentry)
return OVL_TYPE_MERGE(ovl_path_type(dentry)); return OVL_TYPE_MERGE(ovl_path_type(dentry));
} }
static bool ovl_type_origin(struct dentry *dentry)
{
return OVL_TYPE_ORIGIN(ovl_path_type(dentry));
}
static int ovl_create_upper(struct dentry *dentry, struct inode *inode, static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
struct cattr *attr, struct dentry *hardlink) struct cattr *attr, struct dentry *hardlink)
{ {
...@@ -250,7 +266,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, ...@@ -250,7 +266,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (upper->d_parent->d_inode != udir) if (upper->d_parent->d_inode != udir)
goto out_unlock; goto out_unlock;
opaquedir = ovl_lookup_temp(workdir, dentry); opaquedir = ovl_lookup_temp(workdir);
err = PTR_ERR(opaquedir); err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir)) if (IS_ERR(opaquedir))
goto out_unlock; goto out_unlock;
...@@ -382,7 +398,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, ...@@ -382,7 +398,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (err) if (err)
goto out; goto out;
newdentry = ovl_lookup_temp(workdir, dentry); newdentry = ovl_lookup_temp(workdir);
err = PTR_ERR(newdentry); err = PTR_ERR(newdentry);
if (IS_ERR(newdentry)) if (IS_ERR(newdentry))
goto out_unlock; goto out_unlock;
...@@ -846,18 +862,16 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir) ...@@ -846,18 +862,16 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir)
if (IS_ERR(redirect)) if (IS_ERR(redirect))
return PTR_ERR(redirect); return PTR_ERR(redirect);
err = ovl_do_setxattr(ovl_dentry_upper(dentry), OVL_XATTR_REDIRECT, err = ovl_check_setxattr(dentry, ovl_dentry_upper(dentry),
redirect, strlen(redirect), 0); OVL_XATTR_REDIRECT,
redirect, strlen(redirect), -EXDEV);
if (!err) { if (!err) {
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
ovl_dentry_set_redirect(dentry, redirect); ovl_dentry_set_redirect(dentry, redirect);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
} else { } else {
kfree(redirect); kfree(redirect);
if (err == -EOPNOTSUPP) pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err);
ovl_clear_redirect_dir(dentry->d_sb);
else
pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err);
/* Fall back to userspace copy-up */ /* Fall back to userspace copy-up */
err = -EXDEV; err = -EXDEV;
} }
...@@ -943,6 +957,25 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, ...@@ -943,6 +957,25 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
old_upperdir = ovl_dentry_upper(old->d_parent); old_upperdir = ovl_dentry_upper(old->d_parent);
new_upperdir = ovl_dentry_upper(new->d_parent); new_upperdir = ovl_dentry_upper(new->d_parent);
if (!samedir) {
/*
* When moving a merge dir or non-dir with copy up origin into
* a new parent, we are marking the new parent dir "impure".
* When ovl_iterate() iterates an "impure" upper dir, it will
* lookup the origin inodes of the entries to fill d_ino.
*/
if (ovl_type_origin(old)) {
err = ovl_set_impure(new->d_parent, new_upperdir);
if (err)
goto out_revert_creds;
}
if (!overwrite && ovl_type_origin(new)) {
err = ovl_set_impure(old->d_parent, old_upperdir);
if (err)
goto out_revert_creds;
}
}
trap = lock_rename(new_upperdir, old_upperdir); trap = lock_rename(new_upperdir, old_upperdir);
olddentry = lookup_one_len(old->d_name.name, old_upperdir, olddentry = lookup_one_len(old->d_name.name, old_upperdir,
...@@ -992,7 +1025,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, ...@@ -992,7 +1025,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
if (ovl_type_merge_or_lower(old)) if (ovl_type_merge_or_lower(old))
err = ovl_set_redirect(old, samedir); err = ovl_set_redirect(old, samedir);
else if (!old_opaque && ovl_type_merge(new->d_parent)) else if (!old_opaque && ovl_type_merge(new->d_parent))
err = ovl_set_opaque(old, olddentry); err = ovl_set_opaque_xerr(old, olddentry, -EXDEV);
if (err) if (err)
goto out_dput; goto out_dput;
} }
...@@ -1000,7 +1033,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, ...@@ -1000,7 +1033,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
if (ovl_type_merge_or_lower(new)) if (ovl_type_merge_or_lower(new))
err = ovl_set_redirect(new, samedir); err = ovl_set_redirect(new, samedir);
else if (!new_opaque && ovl_type_merge(old->d_parent)) else if (!new_opaque && ovl_type_merge(old->d_parent))
err = ovl_set_opaque(new, newdentry); err = ovl_set_opaque_xerr(new, newdentry, -EXDEV);
if (err) if (err)
goto out_dput; goto out_dput;
} }
......
...@@ -240,6 +240,16 @@ int ovl_xattr_get(struct dentry *dentry, const char *name, ...@@ -240,6 +240,16 @@ int ovl_xattr_get(struct dentry *dentry, const char *name,
return res; return res;
} }
static bool ovl_can_list(const char *s)
{
/* List all non-trusted xatts */
if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
return true;
/* Never list trusted.overlay, list other trusted for superuser only */
return !ovl_is_private_xattr(s) && capable(CAP_SYS_ADMIN);
}
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
{ {
struct dentry *realdentry = ovl_dentry_real(dentry); struct dentry *realdentry = ovl_dentry_real(dentry);
...@@ -263,7 +273,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) ...@@ -263,7 +273,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
return -EIO; return -EIO;
len -= slen; len -= slen;
if (ovl_is_private_xattr(s)) { if (!ovl_can_list(s)) {
res -= slen; res -= slen;
memmove(s, s + slen, len); memmove(s, s + slen, len);
} else { } else {
......
...@@ -169,17 +169,7 @@ static struct dentry *ovl_get_origin(struct dentry *dentry, ...@@ -169,17 +169,7 @@ static struct dentry *ovl_get_origin(struct dentry *dentry,
static bool ovl_is_opaquedir(struct dentry *dentry) static bool ovl_is_opaquedir(struct dentry *dentry)
{ {
int res; return ovl_check_dir_xattr(dentry, OVL_XATTR_OPAQUE);
char val;
if (!d_is_dir(dentry))
return false;
res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
if (res == 1 && val == 'y')
return true;
return false;
} }
static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
...@@ -351,6 +341,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -351,6 +341,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int ctr = 0; unsigned int ctr = 0;
struct inode *inode = NULL; struct inode *inode = NULL;
bool upperopaque = false; bool upperopaque = false;
bool upperimpure = false;
char *upperredirect = NULL; char *upperredirect = NULL;
struct dentry *this; struct dentry *this;
unsigned int i; unsigned int i;
...@@ -395,6 +386,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -395,6 +386,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
poe = roe; poe = roe;
} }
upperopaque = d.opaque; upperopaque = d.opaque;
if (upperdentry && d.is_dir)
upperimpure = ovl_is_impuredir(upperdentry);
} }
if (!d.stop && poe->numlower) { if (!d.stop && poe->numlower) {
...@@ -463,6 +456,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -463,6 +456,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
revert_creds(old_cred); revert_creds(old_cred);
oe->opaque = upperopaque; oe->opaque = upperopaque;
oe->impure = upperimpure;
oe->redirect = upperredirect; oe->redirect = upperredirect;
oe->__upperdentry = upperdentry; oe->__upperdentry = upperdentry;
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
......
...@@ -24,6 +24,7 @@ enum ovl_path_type { ...@@ -24,6 +24,7 @@ enum ovl_path_type {
#define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX "opaque" #define OVL_XATTR_OPAQUE OVL_XATTR_PREFIX "opaque"
#define OVL_XATTR_REDIRECT OVL_XATTR_PREFIX "redirect" #define OVL_XATTR_REDIRECT OVL_XATTR_PREFIX "redirect"
#define OVL_XATTR_ORIGIN OVL_XATTR_PREFIX "origin" #define OVL_XATTR_ORIGIN OVL_XATTR_PREFIX "origin"
#define OVL_XATTR_IMPURE OVL_XATTR_PREFIX "impure"
/* /*
* The tuple (fh,uuid) is a universal unique identifier for a copy up origin, * The tuple (fh,uuid) is a universal unique identifier for a copy up origin,
...@@ -203,10 +204,10 @@ struct dentry *ovl_dentry_real(struct dentry *dentry); ...@@ -203,10 +204,10 @@ struct dentry *ovl_dentry_real(struct dentry *dentry);
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache); void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
bool ovl_dentry_is_opaque(struct dentry *dentry); bool ovl_dentry_is_opaque(struct dentry *dentry);
bool ovl_dentry_is_impure(struct dentry *dentry);
bool ovl_dentry_is_whiteout(struct dentry *dentry); bool ovl_dentry_is_whiteout(struct dentry *dentry);
void ovl_dentry_set_opaque(struct dentry *dentry); void ovl_dentry_set_opaque(struct dentry *dentry);
bool ovl_redirect_dir(struct super_block *sb); bool ovl_redirect_dir(struct super_block *sb);
void ovl_clear_redirect_dir(struct super_block *sb);
const char *ovl_dentry_get_redirect(struct dentry *dentry); const char *ovl_dentry_get_redirect(struct dentry *dentry);
void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect); void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
...@@ -219,6 +220,17 @@ bool ovl_is_whiteout(struct dentry *dentry); ...@@ -219,6 +220,17 @@ bool ovl_is_whiteout(struct dentry *dentry);
struct file *ovl_path_open(struct path *path, int flags); struct file *ovl_path_open(struct path *path, int flags);
int ovl_copy_up_start(struct dentry *dentry); int ovl_copy_up_start(struct dentry *dentry);
void ovl_copy_up_end(struct dentry *dentry); void ovl_copy_up_end(struct dentry *dentry);
bool ovl_check_dir_xattr(struct dentry *dentry, const char *name);
int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
const char *name, const void *value, size_t size,
int xerr);
int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry);
static inline bool ovl_is_impuredir(struct dentry *dentry)
{
return ovl_check_dir_xattr(dentry, OVL_XATTR_IMPURE);
}
/* namei.c */ /* namei.c */
int ovl_path_next(int idx, struct dentry *dentry, struct path *path); int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
...@@ -263,7 +275,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to) ...@@ -263,7 +275,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
/* dir.c */ /* dir.c */
extern const struct inode_operations ovl_dir_inode_operations; extern const struct inode_operations ovl_dir_inode_operations;
struct dentry *ovl_lookup_temp(struct dentry *workdir, struct dentry *dentry); struct dentry *ovl_lookup_temp(struct dentry *workdir);
struct cattr { struct cattr {
dev_t rdev; dev_t rdev;
umode_t mode; umode_t mode;
......
...@@ -28,6 +28,7 @@ struct ovl_fs { ...@@ -28,6 +28,7 @@ struct ovl_fs {
/* creds of process who forced instantiation of super block */ /* creds of process who forced instantiation of super block */
const struct cred *creator_cred; const struct cred *creator_cred;
bool tmpfile; bool tmpfile;
bool noxattr;
wait_queue_head_t copyup_wq; wait_queue_head_t copyup_wq;
/* sb common to all layers */ /* sb common to all layers */
struct super_block *same_sb; struct super_block *same_sb;
...@@ -42,6 +43,7 @@ struct ovl_entry { ...@@ -42,6 +43,7 @@ struct ovl_entry {
u64 version; u64 version;
const char *redirect; const char *redirect;
bool opaque; bool opaque;
bool impure;
bool copying; bool copying;
}; };
struct rcu_head rcu; struct rcu_head rcu;
......
...@@ -891,6 +891,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -891,6 +891,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
dput(temp); dput(temp);
else else
pr_warn("overlayfs: upper fs does not support tmpfile.\n"); pr_warn("overlayfs: upper fs does not support tmpfile.\n");
/*
* Check if upper/work fs supports trusted.overlay.*
* xattr
*/
err = ovl_do_setxattr(ufs->workdir, OVL_XATTR_OPAQUE,
"0", 1, 0);
if (err) {
ufs->noxattr = true;
pr_warn("overlayfs: upper fs does not support xattr.\n");
} else {
vfs_removexattr(ufs->workdir, OVL_XATTR_OPAQUE);
}
} }
} }
...@@ -961,7 +974,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -961,7 +974,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
path_put(&workpath); path_put(&workpath);
kfree(lowertmp); kfree(lowertmp);
oe->__upperdentry = upperpath.dentry; if (upperpath.dentry) {
oe->__upperdentry = upperpath.dentry;
oe->impure = ovl_is_impuredir(upperpath.dentry);
}
for (i = 0; i < numlower; i++) { for (i = 0; i < numlower; i++) {
oe->lowerstack[i].dentry = stack[i].dentry; oe->lowerstack[i].dentry = stack[i].dentry;
oe->lowerstack[i].mnt = ufs->lower_mnt[i]; oe->lowerstack[i].mnt = ufs->lower_mnt[i];
......
...@@ -175,6 +175,13 @@ bool ovl_dentry_is_opaque(struct dentry *dentry) ...@@ -175,6 +175,13 @@ bool ovl_dentry_is_opaque(struct dentry *dentry)
return oe->opaque; return oe->opaque;
} }
bool ovl_dentry_is_impure(struct dentry *dentry)
{
struct ovl_entry *oe = dentry->d_fsdata;
return oe->impure;
}
bool ovl_dentry_is_whiteout(struct dentry *dentry) bool ovl_dentry_is_whiteout(struct dentry *dentry)
{ {
return !dentry->d_inode && ovl_dentry_is_opaque(dentry); return !dentry->d_inode && ovl_dentry_is_opaque(dentry);
...@@ -191,14 +198,7 @@ bool ovl_redirect_dir(struct super_block *sb) ...@@ -191,14 +198,7 @@ bool ovl_redirect_dir(struct super_block *sb)
{ {
struct ovl_fs *ofs = sb->s_fs_info; struct ovl_fs *ofs = sb->s_fs_info;
return ofs->config.redirect_dir; return ofs->config.redirect_dir && !ofs->noxattr;
}
void ovl_clear_redirect_dir(struct super_block *sb)
{
struct ovl_fs *ofs = sb->s_fs_info;
ofs->config.redirect_dir = false;
} }
const char *ovl_dentry_get_redirect(struct dentry *dentry) const char *ovl_dentry_get_redirect(struct dentry *dentry)
...@@ -303,3 +303,59 @@ void ovl_copy_up_end(struct dentry *dentry) ...@@ -303,3 +303,59 @@ void ovl_copy_up_end(struct dentry *dentry)
wake_up_locked(&ofs->copyup_wq); wake_up_locked(&ofs->copyup_wq);
spin_unlock(&ofs->copyup_wq.lock); spin_unlock(&ofs->copyup_wq.lock);
} }
bool ovl_check_dir_xattr(struct dentry *dentry, const char *name)
{
int res;
char val;
if (!d_is_dir(dentry))
return false;
res = vfs_getxattr(dentry, name, &val, 1);
if (res == 1 && val == 'y')
return true;
return false;
}
int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
const char *name, const void *value, size_t size,
int xerr)
{
int err;
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
if (ofs->noxattr)
return xerr;
err = ovl_do_setxattr(upperdentry, name, value, size, 0);
if (err == -EOPNOTSUPP) {
pr_warn("overlayfs: cannot set %s xattr on upper\n", name);
ofs->noxattr = true;
return xerr;
}
return err;
}
int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry)
{
int err;
struct ovl_entry *oe = dentry->d_fsdata;
if (oe->impure)
return 0;
/*
* Do not fail when upper doesn't support xattrs.
* Upper inodes won't have origin nor redirect xattr anyway.
*/
err = ovl_check_setxattr(dentry, upperdentry, OVL_XATTR_IMPURE,
"y", 1, 0);
if (!err)
oe->impure = true;
return 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