Skip to content

Commit

Permalink
Merge branch 'overlayfs-next' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/mszeredi/vfs into for-next
  • Loading branch information
Al Viro committed Feb 20, 2015
2 parents a95104f + 4330397 commit ce7b9fa
Show file tree
Hide file tree
Showing 7 changed files with 517 additions and 319 deletions.
28 changes: 28 additions & 0 deletions Documentation/filesystems/overlayfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ overlay filesystem (though an operation on the name of the file such as
rename or unlink will of course be noticed and handled).


Multiple lower layers
---------------------

Multiple lower layers can now be given using the the colon (":") as a
separator character between the directory names. For example:

mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 /merged

As the example shows, "upperdir=" and "workdir=" may be omitted. In
that case the overlay will be read-only.

The specified lower directories will be stacked beginning from the
rightmost one and going left. In the above example lower1 will be the
top, lower2 the middle and lower3 the bottom layer.


Non-standard behavior
---------------------

Expand Down Expand Up @@ -196,3 +212,15 @@ Changes to the underlying filesystems while part of a mounted overlay
filesystem are not allowed. If the underlying filesystem is changed,
the behavior of the overlay is undefined, though it will not result in
a crash or deadlock.

Testsuite
---------

There's testsuite developed by David Howells at:

git://git.infradead.org/users/dhowells/unionmount-testsuite.git

Run as root:

# cd unionmount-testsuite
# ./run --ov
5 changes: 2 additions & 3 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
ovl_set_timestamps(upperdentry, stat);

return err;

}

static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
Expand Down Expand Up @@ -385,7 +384,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);
Expand All @@ -394,7 +393,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);
Expand Down
28 changes: 14 additions & 14 deletions fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,14 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry,

static int ovl_set_opaque(struct dentry *upperdentry)
{
return ovl_do_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0);
return ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0);
}

static void ovl_remove_opaque(struct dentry *upperdentry)
{
int err;

err = ovl_do_removexattr(upperdentry, ovl_opaque_xattr);
err = ovl_do_removexattr(upperdentry, OVL_XATTR_OPAQUE);
if (err) {
pr_warn("overlayfs: failed to remove opaque from '%s' (%i)\n",
upperdentry->d_name.name, err);
Expand All @@ -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;
Expand Down Expand Up @@ -506,7 +506,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
struct dentry *opaquedir = NULL;
int err;

if (is_dir) {
if (is_dir && OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) {
opaquedir = ovl_check_empty_and_clear(dentry);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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)) {
Expand Down
12 changes: 7 additions & 5 deletions fs/overlayfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)

static bool ovl_is_private_xattr(const char *name)
{
return strncmp(name, "trusted.overlay.", 14) == 0;
return strncmp(name, OVL_XATTR_PRE_NAME, OVL_XATTR_PRE_LEN) == 0;
}

int ovl_setxattr(struct dentry *dentry, const char *name,
Expand Down Expand Up @@ -238,7 +238,10 @@ int ovl_setxattr(struct dentry *dentry, const char *name,
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,
Expand Down Expand Up @@ -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;
Expand All @@ -321,7 +324,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
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))
Expand Down Expand Up @@ -430,5 +433,4 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
}

return inode;

}
18 changes: 13 additions & 5 deletions fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,20 @@
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),
};

extern const char *ovl_opaque_xattr;
#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))

#define OVL_XATTR_PRE_NAME "trusted.overlay."
#define OVL_XATTR_PRE_LEN 16
#define OVL_XATTR_OPAQUE OVL_XATTR_PRE_NAME"opaque"

static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
{
Expand Down Expand Up @@ -130,6 +137,7 @@ void ovl_dentry_version_inc(struct dentry *dentry);
void ovl_path_upper(struct dentry *dentry, struct path *path);
void ovl_path_lower(struct dentry *dentry, struct path *path);
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
struct dentry *ovl_dentry_upper(struct dentry *dentry);
struct dentry *ovl_dentry_lower(struct dentry *dentry);
struct dentry *ovl_dentry_real(struct dentry *dentry);
Expand Down
Loading

0 comments on commit ce7b9fa

Please sign in to comment.