Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce7b9fac authored by Al Viro's avatar Al Viro
Browse files

Merge branch 'overlayfs-next' of...

Merge branch 'overlayfs-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs into for-next
parents a95104fd 4330397e
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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
---------------------

@@ -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
+2 −3
Original line number Diff line number Diff line
@@ -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,
@@ -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);
@@ -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);
+14 −14
Original line number Diff line number Diff line
@@ -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);
@@ -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;
@@ -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))
@@ -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)) {
+7 −5
Original line number Diff line number Diff line
@@ -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,
@@ -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,
@@ -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 @@ 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))
@@ -430,5 +433,4 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
	}

	return inode;

}
+13 −5
Original line number Diff line number Diff line
@@ -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)
{
@@ -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);
Loading