Skip to content

Commit

Permalink
Merge tag 'ovl-fixes-5.5-rc2' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/mszeredi/vfs

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
  • Loading branch information
torvalds committed Dec 14, 2019
2 parents e31736d + 35c6cb4 commit 81c64b0
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. SPDX-License-Identifier: GPL-2.0
Written by: Neil Brown
Please see MAINTAINERS file for where to send questions.

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -12394,7 +12394,7 @@ L: [email protected]
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 <[email protected]>
Expand Down
53 changes: 25 additions & 28 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/*
Expand All @@ -242,42 +246,35 @@ 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
* dentry when we decode fid, the only way to tell if we should assign
* 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,
Expand All @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
80 changes: 49 additions & 31 deletions fs/overlayfs/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -231,43 +232,29 @@ 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);
return err;

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)
Expand All @@ -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;
}

/*
Expand Down Expand Up @@ -777,37 +768,64 @@ static struct dentry *ovl_lower_fh_to_d(struct super_block *sb,
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);
err = PTR_ERR(dentry);
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,
Expand Down
8 changes: 7 additions & 1 deletion fs/overlayfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,14 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
if (ovl_test_flag(OVL_INDEX, d_inode(dentry)) ||
(!ovl_verify_lower(dentry->d_sb) &&
(is_dir || lowerstat.nlink == 1))) {
stat->ino = lowerstat.ino;
lower_layer = ovl_layer_lower(dentry);
/*
* Cannot use origin st_dev;st_ino because
* origin inode content may differ from overlay
* inode content.
*/
if (samefs || lower_layer->fsid)
stat->ino = lowerstat.ino;
}

/*
Expand Down
Loading

0 comments on commit 81c64b0

Please sign in to comment.