Commit bdc01020 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ovl-fixes-6.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs

Pull overlayfs fix from Amir Goldstein:
 "Change the on-disk format for the new "xwhiteouts" feature introduced
  in v6.7

  The change reduces unneeded overhead of an extra getxattr per readdir.
  The only user of the "xwhiteout" feature is the external composefs
  tool, which has been updated to support the new on-disk format.

  This change is also designated for 6.7.y"

* tag 'ovl-fixes-6.8-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs:
  ovl: mark xwhiteouts directory with overlay.opaque='x'
parents a658e0e9 420332b9
...@@ -145,7 +145,9 @@ filesystem, an overlay filesystem needs to record in the upper filesystem ...@@ -145,7 +145,9 @@ filesystem, an overlay filesystem needs to record in the upper filesystem
that files have been removed. This is done using whiteouts and opaque that files have been removed. This is done using whiteouts and opaque
directories (non-directories are always opaque). directories (non-directories are always opaque).
A whiteout is created as a character device with 0/0 device number. A whiteout is created as a character device with 0/0 device number or
as a zero-size regular file with the xattr "trusted.overlay.whiteout".
When a whiteout is found in the upper level of a merged directory, any When a whiteout is found in the upper level of a merged directory, any
matching name in the lower level is ignored, and the whiteout itself matching name in the lower level is ignored, and the whiteout itself
is also hidden. is also hidden.
...@@ -154,6 +156,13 @@ A directory is made opaque by setting the xattr "trusted.overlay.opaque" ...@@ -154,6 +156,13 @@ A directory is made opaque by setting the xattr "trusted.overlay.opaque"
to "y". Where the upper filesystem contains an opaque directory, any to "y". Where the upper filesystem contains an opaque directory, any
directory in the lower filesystem with the same name is ignored. directory in the lower filesystem with the same name is ignored.
An opaque directory should not conntain any whiteouts, because they do not
serve any purpose. A merge directory containing regular files with the xattr
"trusted.overlay.whiteout", should be additionally marked by setting the xattr
"trusted.overlay.opaque" to "x" on the merge directory itself.
This is needed to avoid the overhead of checking the "trusted.overlay.whiteout"
on all entries during readdir in the common case.
readdir readdir
------- -------
...@@ -534,8 +543,9 @@ A lower dir with a regular whiteout will always be handled by the overlayfs ...@@ -534,8 +543,9 @@ A lower dir with a regular whiteout will always be handled by the overlayfs
mount, so to support storing an effective whiteout file in an overlayfs mount an mount, so to support storing an effective whiteout file in an overlayfs mount an
alternative form of whiteout is supported. This form is a regular, zero-size alternative form of whiteout is supported. This form is a regular, zero-size
file with the "overlay.whiteout" xattr set, inside a directory with the file with the "overlay.whiteout" xattr set, inside a directory with the
"overlay.whiteouts" xattr set. Such whiteouts are never created by overlayfs, "overlay.opaque" xattr set to "x" (see `whiteouts and opaque directories`_).
but can be used by userspace tools (like containers) that generate lower layers. These alternative whiteouts are never created by overlayfs, but can be used by
userspace tools (like containers) that generate lower layers.
These alternative whiteouts can be escaped using the standard xattr escape These alternative whiteouts can be escaped using the standard xattr escape
mechanism in order to properly nest to any depth. mechanism in order to properly nest to any depth.
......
...@@ -18,10 +18,11 @@ ...@@ -18,10 +18,11 @@
struct ovl_lookup_data { struct ovl_lookup_data {
struct super_block *sb; struct super_block *sb;
struct vfsmount *mnt; const struct ovl_layer *layer;
struct qstr name; struct qstr name;
bool is_dir; bool is_dir;
bool opaque; bool opaque;
bool xwhiteouts;
bool stop; bool stop;
bool last; bool last;
char *redirect; char *redirect;
...@@ -201,17 +202,13 @@ struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh, ...@@ -201,17 +202,13 @@ struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh,
return real; return real;
} }
static bool ovl_is_opaquedir(struct ovl_fs *ofs, const struct path *path)
{
return ovl_path_check_dir_xattr(ofs, path, OVL_XATTR_OPAQUE);
}
static struct dentry *ovl_lookup_positive_unlocked(struct ovl_lookup_data *d, static struct dentry *ovl_lookup_positive_unlocked(struct ovl_lookup_data *d,
const char *name, const char *name,
struct dentry *base, int len, struct dentry *base, int len,
bool drop_negative) bool drop_negative)
{ {
struct dentry *ret = lookup_one_unlocked(mnt_idmap(d->mnt), name, base, len); struct dentry *ret = lookup_one_unlocked(mnt_idmap(d->layer->mnt), name,
base, len);
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) { if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
if (drop_negative && ret->d_lockref.count == 1) { if (drop_negative && ret->d_lockref.count == 1) {
...@@ -232,10 +229,13 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, ...@@ -232,10 +229,13 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
size_t prelen, const char *post, size_t prelen, const char *post,
struct dentry **ret, bool drop_negative) struct dentry **ret, bool drop_negative)
{ {
struct ovl_fs *ofs = OVL_FS(d->sb);
struct dentry *this; struct dentry *this;
struct path path; struct path path;
int err; int err;
bool last_element = !post[0]; bool last_element = !post[0];
bool is_upper = d->layer->idx == 0;
char val;
this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative); this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative);
if (IS_ERR(this)) { if (IS_ERR(this)) {
...@@ -253,8 +253,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, ...@@ -253,8 +253,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
} }
path.dentry = this; path.dentry = this;
path.mnt = d->mnt; path.mnt = d->layer->mnt;
if (ovl_path_is_whiteout(OVL_FS(d->sb), &path)) { if (ovl_path_is_whiteout(ofs, &path)) {
d->stop = d->opaque = true; d->stop = d->opaque = true;
goto put_and_out; goto put_and_out;
} }
...@@ -272,7 +272,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, ...@@ -272,7 +272,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
d->stop = true; d->stop = true;
goto put_and_out; goto put_and_out;
} }
err = ovl_check_metacopy_xattr(OVL_FS(d->sb), &path, NULL); err = ovl_check_metacopy_xattr(ofs, &path, NULL);
if (err < 0) if (err < 0)
goto out_err; goto out_err;
...@@ -292,7 +292,12 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d, ...@@ -292,7 +292,12 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
if (d->last) if (d->last)
goto out; goto out;
if (ovl_is_opaquedir(OVL_FS(d->sb), &path)) { /* overlay.opaque=x means xwhiteouts directory */
val = ovl_get_opaquedir_val(ofs, &path);
if (last_element && !is_upper && val == 'x') {
d->xwhiteouts = true;
ovl_layer_set_xwhiteouts(ofs, d->layer);
} else if (val == 'y') {
d->stop = true; d->stop = true;
if (last_element) if (last_element)
d->opaque = true; d->opaque = true;
...@@ -863,7 +868,8 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper, ...@@ -863,7 +868,8 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
* Returns next layer in stack starting from top. * Returns next layer in stack starting from top.
* Returns -1 if this is the last layer. * Returns -1 if this is the last layer.
*/ */
int ovl_path_next(int idx, struct dentry *dentry, struct path *path) int ovl_path_next(int idx, struct dentry *dentry, struct path *path,
const struct ovl_layer **layer)
{ {
struct ovl_entry *oe = OVL_E(dentry); struct ovl_entry *oe = OVL_E(dentry);
struct ovl_path *lowerstack = ovl_lowerstack(oe); struct ovl_path *lowerstack = ovl_lowerstack(oe);
...@@ -871,13 +877,16 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path) ...@@ -871,13 +877,16 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
BUG_ON(idx < 0); BUG_ON(idx < 0);
if (idx == 0) { if (idx == 0) {
ovl_path_upper(dentry, path); ovl_path_upper(dentry, path);
if (path->dentry) if (path->dentry) {
*layer = &OVL_FS(dentry->d_sb)->layers[0];
return ovl_numlower(oe) ? 1 : -1; return ovl_numlower(oe) ? 1 : -1;
}
idx++; idx++;
} }
BUG_ON(idx > ovl_numlower(oe)); BUG_ON(idx > ovl_numlower(oe));
path->dentry = lowerstack[idx - 1].dentry; path->dentry = lowerstack[idx - 1].dentry;
path->mnt = lowerstack[idx - 1].layer->mnt; *layer = lowerstack[idx - 1].layer;
path->mnt = (*layer)->mnt;
return (idx < ovl_numlower(oe)) ? idx + 1 : -1; return (idx < ovl_numlower(oe)) ? idx + 1 : -1;
} }
...@@ -1055,7 +1064,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -1055,7 +1064,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
old_cred = ovl_override_creds(dentry->d_sb); old_cred = ovl_override_creds(dentry->d_sb);
upperdir = ovl_dentry_upper(dentry->d_parent); upperdir = ovl_dentry_upper(dentry->d_parent);
if (upperdir) { if (upperdir) {
d.mnt = ovl_upper_mnt(ofs); d.layer = &ofs->layers[0];
err = ovl_lookup_layer(upperdir, &d, &upperdentry, true); err = ovl_lookup_layer(upperdir, &d, &upperdentry, true);
if (err) if (err)
goto out; goto out;
...@@ -1111,7 +1120,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -1111,7 +1120,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
else if (d.is_dir || !ofs->numdatalayer) else if (d.is_dir || !ofs->numdatalayer)
d.last = lower.layer->idx == ovl_numlower(roe); d.last = lower.layer->idx == ovl_numlower(roe);
d.mnt = lower.layer->mnt; d.layer = lower.layer;
err = ovl_lookup_layer(lower.dentry, &d, &this, false); err = ovl_lookup_layer(lower.dentry, &d, &this, false);
if (err) if (err)
goto out_put; goto out_put;
...@@ -1278,6 +1287,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -1278,6 +1287,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (upperopaque) if (upperopaque)
ovl_dentry_set_opaque(dentry); ovl_dentry_set_opaque(dentry);
if (d.xwhiteouts)
ovl_dentry_set_xwhiteouts(dentry);
if (upperdentry) if (upperdentry)
ovl_dentry_set_upper_alias(dentry); ovl_dentry_set_upper_alias(dentry);
......
...@@ -50,7 +50,6 @@ enum ovl_xattr { ...@@ -50,7 +50,6 @@ enum ovl_xattr {
OVL_XATTR_METACOPY, OVL_XATTR_METACOPY,
OVL_XATTR_PROTATTR, OVL_XATTR_PROTATTR,
OVL_XATTR_XWHITEOUT, OVL_XATTR_XWHITEOUT,
OVL_XATTR_XWHITEOUTS,
}; };
enum ovl_inode_flag { enum ovl_inode_flag {
...@@ -70,6 +69,8 @@ enum ovl_entry_flag { ...@@ -70,6 +69,8 @@ enum ovl_entry_flag {
OVL_E_UPPER_ALIAS, OVL_E_UPPER_ALIAS,
OVL_E_OPAQUE, OVL_E_OPAQUE,
OVL_E_CONNECTED, OVL_E_CONNECTED,
/* Lower stack may contain xwhiteout entries */
OVL_E_XWHITEOUTS,
}; };
enum { enum {
...@@ -477,6 +478,10 @@ bool ovl_dentry_test_flag(unsigned long flag, struct dentry *dentry); ...@@ -477,6 +478,10 @@ bool ovl_dentry_test_flag(unsigned long flag, struct dentry *dentry);
bool ovl_dentry_is_opaque(struct dentry *dentry); bool ovl_dentry_is_opaque(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_dentry_has_xwhiteouts(struct dentry *dentry);
void ovl_dentry_set_xwhiteouts(struct dentry *dentry);
void ovl_layer_set_xwhiteouts(struct ovl_fs *ofs,
const struct ovl_layer *layer);
bool ovl_dentry_has_upper_alias(struct dentry *dentry); bool ovl_dentry_has_upper_alias(struct dentry *dentry);
void ovl_dentry_set_upper_alias(struct dentry *dentry); void ovl_dentry_set_upper_alias(struct dentry *dentry);
bool ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags); bool ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags);
...@@ -494,11 +499,10 @@ struct file *ovl_path_open(const struct path *path, int flags); ...@@ -494,11 +499,10 @@ struct file *ovl_path_open(const struct path *path, int flags);
int ovl_copy_up_start(struct dentry *dentry, int flags); int ovl_copy_up_start(struct dentry *dentry, int flags);
void ovl_copy_up_end(struct dentry *dentry); void ovl_copy_up_end(struct dentry *dentry);
bool ovl_already_copied_up(struct dentry *dentry, int flags); bool ovl_already_copied_up(struct dentry *dentry, int flags);
bool ovl_path_check_dir_xattr(struct ovl_fs *ofs, const struct path *path, char ovl_get_dir_xattr_val(struct ovl_fs *ofs, const struct path *path,
enum ovl_xattr ox); enum ovl_xattr ox);
bool ovl_path_check_origin_xattr(struct ovl_fs *ofs, const struct path *path); bool ovl_path_check_origin_xattr(struct ovl_fs *ofs, const struct path *path);
bool ovl_path_check_xwhiteout_xattr(struct ovl_fs *ofs, const struct path *path); bool ovl_path_check_xwhiteout_xattr(struct ovl_fs *ofs, const struct path *path);
bool ovl_path_check_xwhiteouts_xattr(struct ovl_fs *ofs, const struct path *path);
bool ovl_init_uuid_xattr(struct super_block *sb, struct ovl_fs *ofs, bool ovl_init_uuid_xattr(struct super_block *sb, struct ovl_fs *ofs,
const struct path *upperpath); const struct path *upperpath);
...@@ -573,7 +577,13 @@ static inline bool ovl_is_impuredir(struct super_block *sb, ...@@ -573,7 +577,13 @@ static inline bool ovl_is_impuredir(struct super_block *sb,
.mnt = ovl_upper_mnt(ofs), .mnt = ovl_upper_mnt(ofs),
}; };
return ovl_path_check_dir_xattr(ofs, &upperpath, OVL_XATTR_IMPURE); return ovl_get_dir_xattr_val(ofs, &upperpath, OVL_XATTR_IMPURE) == 'y';
}
static inline char ovl_get_opaquedir_val(struct ovl_fs *ofs,
const struct path *path)
{
return ovl_get_dir_xattr_val(ofs, path, OVL_XATTR_OPAQUE);
} }
static inline bool ovl_redirect_follow(struct ovl_fs *ofs) static inline bool ovl_redirect_follow(struct ovl_fs *ofs)
...@@ -680,7 +690,8 @@ int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin, ...@@ -680,7 +690,8 @@ int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin,
struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh); struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh);
struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper, struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
struct dentry *origin, bool verify); struct dentry *origin, bool verify);
int ovl_path_next(int idx, struct dentry *dentry, struct path *path); int ovl_path_next(int idx, struct dentry *dentry, struct path *path,
const struct ovl_layer **layer);
int ovl_verify_lowerdata(struct dentry *dentry); int ovl_verify_lowerdata(struct dentry *dentry);
struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags); unsigned int flags);
......
...@@ -40,6 +40,8 @@ struct ovl_layer { ...@@ -40,6 +40,8 @@ struct ovl_layer {
int idx; int idx;
/* One fsid per unique underlying sb (upper fsid == 0) */ /* One fsid per unique underlying sb (upper fsid == 0) */
int fsid; int fsid;
/* xwhiteouts were found on this layer */
bool has_xwhiteouts;
}; };
struct ovl_path { struct ovl_path {
...@@ -59,7 +61,7 @@ struct ovl_fs { ...@@ -59,7 +61,7 @@ struct ovl_fs {
unsigned int numfs; unsigned int numfs;
/* Number of data-only lower layers */ /* Number of data-only lower layers */
unsigned int numdatalayer; unsigned int numdatalayer;
const struct ovl_layer *layers; struct ovl_layer *layers;
struct ovl_sb *fs; struct ovl_sb *fs;
/* workbasedir is the path at workdir= mount option */ /* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir; struct dentry *workbasedir;
......
...@@ -305,8 +305,6 @@ static inline int ovl_dir_read(const struct path *realpath, ...@@ -305,8 +305,6 @@ static inline int ovl_dir_read(const struct path *realpath,
if (IS_ERR(realfile)) if (IS_ERR(realfile))
return PTR_ERR(realfile); return PTR_ERR(realfile);
rdd->in_xwhiteouts_dir = rdd->dentry &&
ovl_path_check_xwhiteouts_xattr(OVL_FS(rdd->dentry->d_sb), realpath);
rdd->first_maybe_whiteout = NULL; rdd->first_maybe_whiteout = NULL;
rdd->ctx.pos = 0; rdd->ctx.pos = 0;
do { do {
...@@ -359,10 +357,13 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list, ...@@ -359,10 +357,13 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
.is_lowest = false, .is_lowest = false,
}; };
int idx, next; int idx, next;
const struct ovl_layer *layer;
for (idx = 0; idx != -1; idx = next) { for (idx = 0; idx != -1; idx = next) {
next = ovl_path_next(idx, dentry, &realpath); next = ovl_path_next(idx, dentry, &realpath, &layer);
rdd.is_upper = ovl_dentry_upper(dentry) == realpath.dentry; rdd.is_upper = ovl_dentry_upper(dentry) == realpath.dentry;
rdd.in_xwhiteouts_dir = layer->has_xwhiteouts &&
ovl_dentry_has_xwhiteouts(dentry);
if (next != -1) { if (next != -1) {
err = ovl_dir_read(&realpath, &rdd); err = ovl_dir_read(&realpath, &rdd);
......
...@@ -1249,6 +1249,7 @@ static struct dentry *ovl_get_root(struct super_block *sb, ...@@ -1249,6 +1249,7 @@ static struct dentry *ovl_get_root(struct super_block *sb,
struct ovl_entry *oe) struct ovl_entry *oe)
{ {
struct dentry *root; struct dentry *root;
struct ovl_fs *ofs = OVL_FS(sb);
struct ovl_path *lowerpath = ovl_lowerstack(oe); struct ovl_path *lowerpath = ovl_lowerstack(oe);
unsigned long ino = d_inode(lowerpath->dentry)->i_ino; unsigned long ino = d_inode(lowerpath->dentry)->i_ino;
int fsid = lowerpath->layer->fsid; int fsid = lowerpath->layer->fsid;
...@@ -1270,6 +1271,20 @@ static struct dentry *ovl_get_root(struct super_block *sb, ...@@ -1270,6 +1271,20 @@ static struct dentry *ovl_get_root(struct super_block *sb,
ovl_set_flag(OVL_IMPURE, d_inode(root)); ovl_set_flag(OVL_IMPURE, d_inode(root));
} }
/* Look for xwhiteouts marker except in the lowermost layer */
for (int i = 0; i < ovl_numlower(oe) - 1; i++, lowerpath++) {
struct path path = {
.mnt = lowerpath->layer->mnt,
.dentry = lowerpath->dentry,
};
/* overlay.opaque=x means xwhiteouts directory */
if (ovl_get_opaquedir_val(ofs, &path) == 'x') {
ovl_layer_set_xwhiteouts(ofs, lowerpath->layer);
ovl_dentry_set_xwhiteouts(root);
}
}
/* Root is always merge -> can have whiteouts */ /* Root is always merge -> can have whiteouts */
ovl_set_flag(OVL_WHITEOUTS, d_inode(root)); ovl_set_flag(OVL_WHITEOUTS, d_inode(root));
ovl_dentry_set_flag(OVL_E_CONNECTED, root); ovl_dentry_set_flag(OVL_E_CONNECTED, root);
......
...@@ -461,6 +461,33 @@ void ovl_dentry_set_opaque(struct dentry *dentry) ...@@ -461,6 +461,33 @@ void ovl_dentry_set_opaque(struct dentry *dentry)
ovl_dentry_set_flag(OVL_E_OPAQUE, dentry); ovl_dentry_set_flag(OVL_E_OPAQUE, dentry);
} }
bool ovl_dentry_has_xwhiteouts(struct dentry *dentry)
{
return ovl_dentry_test_flag(OVL_E_XWHITEOUTS, dentry);
}
void ovl_dentry_set_xwhiteouts(struct dentry *dentry)
{
ovl_dentry_set_flag(OVL_E_XWHITEOUTS, dentry);
}
/*
* ovl_layer_set_xwhiteouts() is called before adding the overlay dir
* dentry to dcache, while readdir of that same directory happens after
* the overlay dir dentry is in dcache, so if some cpu observes that
* ovl_dentry_is_xwhiteouts(), it will also observe layer->has_xwhiteouts
* for the layers where xwhiteouts marker was found in that merge dir.
*/
void ovl_layer_set_xwhiteouts(struct ovl_fs *ofs,
const struct ovl_layer *layer)
{
if (layer->has_xwhiteouts)
return;
/* Write once to read-mostly layer properties */
ofs->layers[layer->idx].has_xwhiteouts = true;
}
/* /*
* For hard links and decoded file handles, it's possible for ovl_dentry_upper() * For hard links and decoded file handles, it's possible for ovl_dentry_upper()
* to return positive, while there's no actual upper alias for the inode. * to return positive, while there's no actual upper alias for the inode.
...@@ -739,19 +766,6 @@ bool ovl_path_check_xwhiteout_xattr(struct ovl_fs *ofs, const struct path *path) ...@@ -739,19 +766,6 @@ bool ovl_path_check_xwhiteout_xattr(struct ovl_fs *ofs, const struct path *path)
return res >= 0; return res >= 0;
} }
bool ovl_path_check_xwhiteouts_xattr(struct ovl_fs *ofs, const struct path *path)
{
struct dentry *dentry = path->dentry;
int res;
/* xattr.whiteouts must be a directory */
if (!d_is_dir(dentry))
return false;
res = ovl_path_getxattr(ofs, path, OVL_XATTR_XWHITEOUTS, NULL, 0);
return res >= 0;
}
/* /*
* Load persistent uuid from xattr into s_uuid if found, or store a new * Load persistent uuid from xattr into s_uuid if found, or store a new
* random generated value in s_uuid and in xattr. * random generated value in s_uuid and in xattr.
...@@ -811,20 +825,17 @@ bool ovl_init_uuid_xattr(struct super_block *sb, struct ovl_fs *ofs, ...@@ -811,20 +825,17 @@ bool ovl_init_uuid_xattr(struct super_block *sb, struct ovl_fs *ofs,
return false; return false;
} }
bool ovl_path_check_dir_xattr(struct ovl_fs *ofs, const struct path *path, char ovl_get_dir_xattr_val(struct ovl_fs *ofs, const struct path *path,
enum ovl_xattr ox) enum ovl_xattr ox)
{ {
int res; int res;
char val; char val;
if (!d_is_dir(path->dentry)) if (!d_is_dir(path->dentry))
return false; return 0;
res = ovl_path_getxattr(ofs, path, ox, &val, 1); res = ovl_path_getxattr(ofs, path, ox, &val, 1);
if (res == 1 && val == 'y') return res == 1 ? val : 0;
return true;
return false;
} }
#define OVL_XATTR_OPAQUE_POSTFIX "opaque" #define OVL_XATTR_OPAQUE_POSTFIX "opaque"
...@@ -837,7 +848,6 @@ bool ovl_path_check_dir_xattr(struct ovl_fs *ofs, const struct path *path, ...@@ -837,7 +848,6 @@ bool ovl_path_check_dir_xattr(struct ovl_fs *ofs, const struct path *path,
#define OVL_XATTR_METACOPY_POSTFIX "metacopy" #define OVL_XATTR_METACOPY_POSTFIX "metacopy"
#define OVL_XATTR_PROTATTR_POSTFIX "protattr" #define OVL_XATTR_PROTATTR_POSTFIX "protattr"
#define OVL_XATTR_XWHITEOUT_POSTFIX "whiteout" #define OVL_XATTR_XWHITEOUT_POSTFIX "whiteout"
#define OVL_XATTR_XWHITEOUTS_POSTFIX "whiteouts"
#define OVL_XATTR_TAB_ENTRY(x) \ #define OVL_XATTR_TAB_ENTRY(x) \
[x] = { [false] = OVL_XATTR_TRUSTED_PREFIX x ## _POSTFIX, \ [x] = { [false] = OVL_XATTR_TRUSTED_PREFIX x ## _POSTFIX, \
...@@ -854,7 +864,6 @@ const char *const ovl_xattr_table[][2] = { ...@@ -854,7 +864,6 @@ const char *const ovl_xattr_table[][2] = {
OVL_XATTR_TAB_ENTRY(OVL_XATTR_METACOPY), OVL_XATTR_TAB_ENTRY(OVL_XATTR_METACOPY),
OVL_XATTR_TAB_ENTRY(OVL_XATTR_PROTATTR), OVL_XATTR_TAB_ENTRY(OVL_XATTR_PROTATTR),
OVL_XATTR_TAB_ENTRY(OVL_XATTR_XWHITEOUT), OVL_XATTR_TAB_ENTRY(OVL_XATTR_XWHITEOUT),
OVL_XATTR_TAB_ENTRY(OVL_XATTR_XWHITEOUTS),
}; };
int ovl_check_setxattr(struct ovl_fs *ofs, struct dentry *upperdentry, int ovl_check_setxattr(struct ovl_fs *ofs, struct dentry *upperdentry,
......
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