ovl: make path-type a bitmap

OVL_PATH_PURE_UPPER -> __OVL_PATH_UPPER | __OVL_PATH_PURE
OVL_PATH_UPPER      -> __OVL_PATH_UPPER
OVL_PATH_MERGE      -> __OVL_PATH_UPPER | __OVL_PATH_MERGE
OVL_PATH_LOWER      -> 0

Multiple R/O layers will allow __OVL_PATH_MERGE without __OVL_PATH_UPPER.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
This commit is contained in:
Miklos Szeredi 2014-12-13 00:59:42 +01:00
parent 49c21e1cac
commit 1afaba1ecb
6 changed files with 41 additions and 36 deletions

View File

@ -385,7 +385,7 @@ int ovl_copy_up(struct dentry *dentry)
struct kstat stat;
enum ovl_path_type type = ovl_path_type(dentry);
if (type != OVL_PATH_LOWER)
if (OVL_TYPE_UPPER(type))
break;
next = dget(dentry);
@ -394,7 +394,7 @@ int ovl_copy_up(struct dentry *dentry)
parent = dget_parent(next);
type = ovl_path_type(parent);
if (type != OVL_PATH_LOWER)
if (OVL_TYPE_UPPER(type))
break;
dput(next);

View File

@ -152,7 +152,7 @@ static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
* correct link count. nlink=1 seems to pacify 'find' and
* other utilities.
*/
if (type == OVL_PATH_MERGE)
if (OVL_TYPE_MERGE(type))
stat->nlink = 1;
return 0;
@ -630,7 +630,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
goto out_drop_write;
type = ovl_path_type(dentry);
if (type == OVL_PATH_PURE_UPPER) {
if (OVL_TYPE_PURE_UPPER(type)) {
err = ovl_remove_upper(dentry, is_dir);
} else {
const struct cred *old_cred;
@ -712,7 +712,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
/* Don't copy up directory trees */
old_type = ovl_path_type(old);
err = -EXDEV;
if ((old_type == OVL_PATH_LOWER || old_type == OVL_PATH_MERGE) && is_dir)
if (OVL_TYPE_MERGE_OR_LOWER(old_type) && is_dir)
goto out;
if (new->d_inode) {
@ -725,25 +725,25 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
new_type = ovl_path_type(new);
err = -EXDEV;
if (!overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir)
if (!overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir)
goto out;
err = 0;
if (new_type == OVL_PATH_LOWER && old_type == OVL_PATH_LOWER) {
if (!OVL_TYPE_UPPER(new_type) && !OVL_TYPE_UPPER(old_type)) {
if (ovl_dentry_lower(old)->d_inode ==
ovl_dentry_lower(new)->d_inode)
goto out;
}
if (new_type != OVL_PATH_LOWER && old_type != OVL_PATH_LOWER) {
if (OVL_TYPE_UPPER(new_type) && OVL_TYPE_UPPER(old_type)) {
if (ovl_dentry_upper(old)->d_inode ==
ovl_dentry_upper(new)->d_inode)
goto out;
}
} else {
if (ovl_dentry_is_opaque(new))
new_type = OVL_PATH_UPPER;
new_type = __OVL_PATH_UPPER;
else
new_type = OVL_PATH_PURE_UPPER;
new_type = __OVL_PATH_UPPER | __OVL_PATH_PURE;
}
err = ovl_want_write(old);
@ -763,8 +763,8 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
goto out_drop_write;
}
old_opaque = old_type != OVL_PATH_PURE_UPPER;
new_opaque = new_type != OVL_PATH_PURE_UPPER;
old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
if (old_opaque || new_opaque) {
err = -ENOMEM;
@ -787,7 +787,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
old_cred = override_creds(override_cred);
}
if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) {
if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
opaquedir = ovl_check_empty_and_clear(new);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir)) {

View File

@ -238,7 +238,10 @@ out:
static bool ovl_need_xattr_filter(struct dentry *dentry,
enum ovl_path_type type)
{
return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode);
if ((type & (__OVL_PATH_PURE | __OVL_PATH_UPPER)) == __OVL_PATH_UPPER)
return S_ISDIR(dentry->d_inode->i_mode);
else
return false;
}
ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
@ -299,7 +302,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
goto out_drop_write;
if (type == OVL_PATH_LOWER) {
if (!OVL_TYPE_UPPER(type)) {
err = vfs_getxattr(realpath.dentry, name, NULL, 0);
if (err < 0)
goto out_drop_write;
@ -321,7 +324,7 @@ out:
static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
struct dentry *realdentry)
{
if (type != OVL_PATH_LOWER)
if (OVL_TYPE_UPPER(type))
return false;
if (special_file(realdentry->d_inode->i_mode))

View File

@ -12,12 +12,17 @@
struct ovl_entry;
enum ovl_path_type {
OVL_PATH_PURE_UPPER,
OVL_PATH_UPPER,
OVL_PATH_MERGE,
OVL_PATH_LOWER,
__OVL_PATH_PURE = (1 << 0),
__OVL_PATH_UPPER = (1 << 1),
__OVL_PATH_MERGE = (1 << 2),
};
#define OVL_TYPE_UPPER(type) ((type) & __OVL_PATH_UPPER)
#define OVL_TYPE_MERGE(type) ((type) & __OVL_PATH_MERGE)
#define OVL_TYPE_PURE_UPPER(type) ((type) & __OVL_PATH_PURE)
#define OVL_TYPE_MERGE_OR_LOWER(type) \
(OVL_TYPE_MERGE(type) || !OVL_TYPE_UPPER(type))
extern const char *ovl_opaque_xattr;
static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)

View File

@ -253,8 +253,8 @@ static void ovl_dir_reset(struct file *file)
ovl_cache_put(od, dentry);
od->cache = NULL;
}
WARN_ON(!od->is_real && type != OVL_PATH_MERGE);
if (od->is_real && type == OVL_PATH_MERGE)
WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type));
if (od->is_real && OVL_TYPE_MERGE(type))
od->is_real = false;
}
@ -429,7 +429,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
/*
* Need to check if we started out being a lower dir, but got copied up
*/
if (!od->is_upper && ovl_path_type(dentry) != OVL_PATH_LOWER) {
if (!od->is_upper && OVL_TYPE_UPPER(ovl_path_type(dentry))) {
struct inode *inode = file_inode(file);
realfile = lockless_dereference(od->upperfile);
@ -495,8 +495,8 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
}
INIT_LIST_HEAD(&od->cursor.l_node);
od->realfile = realfile;
od->is_real = (type != OVL_PATH_MERGE);
od->is_upper = (type != OVL_PATH_LOWER);
od->is_real = !OVL_TYPE_MERGE(type);
od->is_upper = OVL_TYPE_UPPER(type);
od->cursor.is_cursor = true;
file->private_data = od;

View File

@ -64,22 +64,19 @@ const char *ovl_opaque_xattr = "trusted.overlay.opaque";
enum ovl_path_type ovl_path_type(struct dentry *dentry)
{
struct ovl_entry *oe = dentry->d_fsdata;
enum ovl_path_type type = 0;
if (oe->__upperdentry) {
type = __OVL_PATH_UPPER;
if (oe->lowerdentry) {
if (S_ISDIR(dentry->d_inode->i_mode))
return OVL_PATH_MERGE;
else
return OVL_PATH_UPPER;
} else {
if (oe->opaque)
return OVL_PATH_UPPER;
else
return OVL_PATH_PURE_UPPER;
type |= __OVL_PATH_MERGE;
} else if (!oe->opaque) {
type |= __OVL_PATH_PURE;
}
} else {
return OVL_PATH_LOWER;
}
return type;
}
static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe)
@ -101,7 +98,7 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
enum ovl_path_type type = ovl_path_type(dentry);
if (type == OVL_PATH_LOWER)
if (!OVL_TYPE_UPPER(type))
ovl_path_lower(dentry, path);
else
ovl_path_upper(dentry, path);