Commit 81c64b0b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull overlayfs fixes from Miklos Szeredi:
 "Fix some bugs and documentation"

* tag 'ovl-fixes-5.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  docs: filesystems: overlayfs: Fix restview warnings
  docs: filesystems: overlayfs: Rename overlayfs.txt to .rst
  ovl: relax WARN_ON() on rename to self
  ovl: fix corner case of non-unique st_dev;st_ino
  ovl: don't use a temp buf for encoding real fh
  ovl: make sure that real fid is 32bit aligned in memory
  ovl: fix lookup failure on multi lower squashfs
parents e31736d9 35c6cb41
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
.. SPDX-License-Identifier: GPL-2.0

Written by: Neil Brown
Please see MAINTAINERS file for where to send questions.

@@ -181,7 +183,7 @@ Kernel config options:
    worried about backward compatibility with kernels that have the redirect_dir
    feature and follow redirects even if turned off.

Module options (can also be changed through /sys/module/overlay/parameters/*):
Module options (can also be changed through /sys/module/overlay/parameters/):

- "redirect_dir=BOOL":
    See OVERLAY_FS_REDIRECT_DIR kernel config option above.
@@ -263,7 +265,7 @@ top, lower2 the middle and lower3 the bottom layer.


Metadata only copy up
--------------------
---------------------

When metadata only copy up feature is enabled, overlayfs will only copy
up metadata (as opposed to whole file), when a metadata specific operation
@@ -286,10 +288,10 @@ pointed by REDIRECT. This should not be possible on local system as setting
"trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible
for untrusted layers like from a pen drive.

Note: redirect_dir={off|nofollow|follow(*)} conflicts with metacopy=on, and
Note: redirect_dir={off|nofollow|follow[*]} conflicts with metacopy=on, and
results in an error.

(*) redirect_dir=follow only conflicts with metacopy=on if upperdir=... is
[*] redirect_dir=follow only conflicts with metacopy=on if upperdir=... is
given.

Sharing and copying layers
+1 −1
Original line number Diff line number Diff line
@@ -12394,7 +12394,7 @@ L: linux-unionfs@vger.kernel.org
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
S:	Supported
F:	fs/overlayfs/
F:	Documentation/filesystems/overlayfs.txt
F:	Documentation/filesystems/overlayfs.rst
P54 WIRELESS DRIVER
M:	Christian Lamparter <chunkeey@googlemail.com>
+25 −28
Original line number Diff line number Diff line
@@ -227,13 +227,17 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper)
{
	struct ovl_fh *fh;
	int fh_type, fh_len, dwords;
	void *buf;
	int fh_type, dwords;
	int buflen = MAX_HANDLE_SZ;
	uuid_t *uuid = &real->d_sb->s_uuid;
	int err;

	buf = kmalloc(buflen, GFP_KERNEL);
	if (!buf)
	/* Make sure the real fid stays 32bit aligned */
	BUILD_BUG_ON(OVL_FH_FID_OFFSET % 4);
	BUILD_BUG_ON(MAX_HANDLE_SZ + OVL_FH_FID_OFFSET > 255);

	fh = kzalloc(buflen + OVL_FH_FID_OFFSET, GFP_KERNEL);
	if (!fh)
		return ERR_PTR(-ENOMEM);

	/*
@@ -242,27 +246,19 @@ struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper)
	 * the price or reconnecting the dentry.
	 */
	dwords = buflen >> 2;
	fh_type = exportfs_encode_fh(real, buf, &dwords, 0);
	fh_type = exportfs_encode_fh(real, (void *)fh->fb.fid, &dwords, 0);
	buflen = (dwords << 2);

	fh = ERR_PTR(-EIO);
	err = -EIO;
	if (WARN_ON(fh_type < 0) ||
	    WARN_ON(buflen > MAX_HANDLE_SZ) ||
	    WARN_ON(fh_type == FILEID_INVALID))
		goto out;
		goto out_err;

	BUILD_BUG_ON(MAX_HANDLE_SZ + offsetof(struct ovl_fh, fid) > 255);
	fh_len = offsetof(struct ovl_fh, fid) + buflen;
	fh = kmalloc(fh_len, GFP_KERNEL);
	if (!fh) {
		fh = ERR_PTR(-ENOMEM);
		goto out;
	}

	fh->version = OVL_FH_VERSION;
	fh->magic = OVL_FH_MAGIC;
	fh->type = fh_type;
	fh->flags = OVL_FH_FLAG_CPU_ENDIAN;
	fh->fb.version = OVL_FH_VERSION;
	fh->fb.magic = OVL_FH_MAGIC;
	fh->fb.type = fh_type;
	fh->fb.flags = OVL_FH_FLAG_CPU_ENDIAN;
	/*
	 * When we will want to decode an overlay dentry from this handle
	 * and all layers are on the same fs, if we get a disconncted real
@@ -270,14 +266,15 @@ struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper)
	 * it to upperdentry or to lowerstack is by checking this flag.
	 */
	if (is_upper)
		fh->flags |= OVL_FH_FLAG_PATH_UPPER;
	fh->len = fh_len;
	fh->uuid = *uuid;
	memcpy(fh->fid, buf, buflen);
		fh->fb.flags |= OVL_FH_FLAG_PATH_UPPER;
	fh->fb.len = sizeof(fh->fb) + buflen;
	fh->fb.uuid = *uuid;

out:
	kfree(buf);
	return fh;

out_err:
	kfree(fh);
	return ERR_PTR(err);
}

int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
@@ -300,8 +297,8 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
	/*
	 * Do not fail when upper doesn't support xattrs.
	 */
	err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh,
				 fh ? fh->len : 0, 0);
	err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh->buf,
				 fh ? fh->fb.len : 0, 0);
	kfree(fh);

	return err;
@@ -317,7 +314,7 @@ static int ovl_set_upper_fh(struct dentry *upper, struct dentry *index)
	if (IS_ERR(fh))
		return PTR_ERR(fh);

	err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh, fh->len, 0);
	err = ovl_do_setxattr(index, OVL_XATTR_UPPER, fh->buf, fh->fb.len, 0);

	kfree(fh);
	return err;
+1 −1
Original line number Diff line number Diff line
@@ -1170,7 +1170,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
	if (newdentry == trap)
		goto out_dput;

	if (WARN_ON(olddentry->d_inode == newdentry->d_inode))
	if (olddentry->d_inode == newdentry->d_inode)
		goto out_dput;

	err = 0;
+49 −31
Original line number Diff line number Diff line
@@ -211,10 +211,11 @@ static int ovl_check_encode_origin(struct dentry *dentry)
	return 1;
}

static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
static int ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen)
{
	struct ovl_fh *fh = NULL;
	int err, enc_lower;
	int len;

	/*
	 * Check if we should encode a lower or upper file handle and maybe
@@ -231,11 +232,12 @@ static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
		return PTR_ERR(fh);

	err = -EOVERFLOW;
	if (fh->len > buflen)
	len = OVL_FH_LEN(fh);
	if (len > buflen)
		goto fail;

	memcpy(buf, (char *)fh, fh->len);
	err = fh->len;
	memcpy(fid, fh, len);
	err = len;

out:
	kfree(fh);
@@ -243,31 +245,16 @@ out:

fail:
	pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
			    dentry, err, buflen, fh ? (int)fh->len : 0,
			    fh ? fh->type : 0);
			    dentry, err, buflen, fh ? (int)fh->fb.len : 0,
			    fh ? fh->fb.type : 0);
	goto out;
}

static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len)
{
	int res, len = *max_len << 2;

	res = ovl_d_to_fh(dentry, (char *)fid, len);
	if (res <= 0)
		return FILEID_INVALID;

	len = res;

	/* Round up to dwords */
	*max_len = (len + 3) >> 2;
	return OVL_FILEID;
}

static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
			 struct inode *parent)
{
	struct dentry *dentry;
	int type;
	int bytes = *max_len << 2;

	/* TODO: encode connectable file handles */
	if (parent)
@@ -277,10 +264,14 @@ static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
	if (WARN_ON(!dentry))
		return FILEID_INVALID;

	type = ovl_dentry_to_fh(dentry, fid, max_len);

	bytes = ovl_dentry_to_fid(dentry, fid, bytes);
	dput(dentry);
	return type;
	if (bytes <= 0)
		return FILEID_INVALID;

	*max_len = bytes >> 2;

	return OVL_FILEID_V1;
}

/*
@@ -777,24 +768,45 @@ out_err:
	goto out;
}

static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type)
{
	struct ovl_fh *fh;

	/* If on-wire inner fid is aligned - nothing to do */
	if (fh_type == OVL_FILEID_V1)
		return (struct ovl_fh *)fid;

	if (fh_type != OVL_FILEID_V0)
		return ERR_PTR(-EINVAL);

	fh = kzalloc(buflen, GFP_KERNEL);
	if (!fh)
		return ERR_PTR(-ENOMEM);

	/* Copy unaligned inner fh into aligned buffer */
	memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET);
	return fh;
}

static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
				       int fh_len, int fh_type)
{
	struct dentry *dentry = NULL;
	struct ovl_fh *fh = (struct ovl_fh *) fid;
	struct ovl_fh *fh = NULL;
	int len = fh_len << 2;
	unsigned int flags = 0;
	int err;

	err = -EINVAL;
	if (fh_type != OVL_FILEID)
	fh = ovl_fid_to_fh(fid, len, fh_type);
	err = PTR_ERR(fh);
	if (IS_ERR(fh))
		goto out_err;

	err = ovl_check_fh_len(fh, len);
	if (err)
		goto out_err;

	flags = fh->flags;
	flags = fh->fb.flags;
	dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ?
		 ovl_upper_fh_to_d(sb, fh) :
		 ovl_lower_fh_to_d(sb, fh);
@@ -802,12 +814,18 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
	if (IS_ERR(dentry) && err != -ESTALE)
		goto out_err;

out:
	/* We may have needed to re-align OVL_FILEID_V0 */
	if (!IS_ERR_OR_NULL(fh) && fh != (void *)fid)
		kfree(fh);

	return dentry;

out_err:
	pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
			    len, fh_type, flags, err);
	return ERR_PTR(err);
			    fh_len, fh_type, flags, err);
	dentry = ERR_PTR(err);
	goto out;
}

static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid,
Loading