Skip to content

Commit

Permalink
Merge tag 'ovl-update-5.6' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/mszeredi/vfs

Pull overlayfs update from Miklos Szeredi:

 - Try to preserve holes in sparse files when copying up, thus saving
   disk space and improving performance.

 - Fix a performance regression introduced in v4.19 by preserving
   asynchronicity of IO when fowarding to underlying layers. Add VFS
   helpers to submit async iocbs.

 - Fix a regression in lseek(2) introduced in v4.19 that breaks >2G
   seeks on 32bit kernels.

 - Fix a corner case where st_ino/st_dev was not preserved across copy
   up.

 - Miscellaneous fixes and cleanups.

* tag 'ovl-update-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: fix lseek overflow on 32bit
  ovl: add splice file read write helper
  ovl: implement async IO routines
  vfs: add vfs_iocb_iter_[read|write] helper functions
  ovl: layer is const
  ovl: fix corner case of non-constant st_dev;st_ino
  ovl: fix corner case of conflicting lower layer uuid
  ovl: generalize the lower_fs[] array
  ovl: simplify ovl_same_sb() helper
  ovl: generalize the lower_layers[] array
  ovl: improving copy-up efficiency for big sparse file
  ovl: use ovl_inode_lock in ovl_llseek()
  ovl: use pr_fmt auto generate prefix
  ovl: fix wrong WARN_ON() in ovl_cache_update_ino()
  • Loading branch information
Linus Torvalds committed Feb 4, 2020
2 parents a45ad71 + a4ac9d4 commit 7f879e1
Show file tree
Hide file tree
Showing 13 changed files with 521 additions and 228 deletions.
43 changes: 40 additions & 3 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

static int ovl_ccup_set(const char *buf, const struct kernel_param *param)
{
pr_warn("overlayfs: \"check_copy_up\" module option is obsolete\n");
pr_warn("\"check_copy_up\" module option is obsolete\n");
return 0;
}

Expand Down Expand Up @@ -123,6 +123,9 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
loff_t old_pos = 0;
loff_t new_pos = 0;
loff_t cloned;
loff_t data_pos = -1;
loff_t hole_len;
bool skip_hole = false;
int error = 0;

if (len == 0)
Expand All @@ -144,7 +147,11 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
goto out;
/* Couldn't clone, so now we try to copy the data */

/* FIXME: copy up sparse files efficiently */
/* Check if lower fs supports seek operation */
if (old_file->f_mode & FMODE_LSEEK &&
old_file->f_op->llseek)
skip_hole = true;

while (len) {
size_t this_len = OVL_COPY_UP_CHUNK_SIZE;
long bytes;
Expand All @@ -157,6 +164,36 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
break;
}

/*
* Fill zero for hole will cost unnecessary disk space
* and meanwhile slow down the copy-up speed, so we do
* an optimization for hole during copy-up, it relies
* on SEEK_DATA implementation in lower fs so if lower
* fs does not support it, copy-up will behave as before.
*
* Detail logic of hole detection as below:
* When we detect next data position is larger than current
* position we will skip that hole, otherwise we copy
* data in the size of OVL_COPY_UP_CHUNK_SIZE. Actually,
* it may not recognize all kind of holes and sometimes
* only skips partial of hole area. However, it will be
* enough for most of the use cases.
*/

if (skip_hole && data_pos < old_pos) {
data_pos = vfs_llseek(old_file, old_pos, SEEK_DATA);
if (data_pos > old_pos) {
hole_len = data_pos - old_pos;
len -= hole_len;
old_pos = new_pos = data_pos;
continue;
} else if (data_pos == -ENXIO) {
break;
} else if (data_pos < 0) {
skip_hole = false;
}
}

bytes = do_splice_direct(old_file, &old_pos,
new_file, &new_pos,
this_len, SPLICE_F_MOVE);
Expand Down Expand Up @@ -480,7 +517,7 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
}

inode_lock(temp->d_inode);
if (c->metacopy)
if (S_ISREG(c->stat.mode))
err = ovl_set_size(temp, &c->stat);
if (!err)
err = ovl_set_attr(temp, &c->stat);
Expand Down
10 changes: 5 additions & 5 deletions fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
dput(wdentry);

if (err) {
pr_err("overlayfs: cleanup of '%pd2' failed (%i)\n",
pr_err("cleanup of '%pd2' failed (%i)\n",
wdentry, err);
}

Expand All @@ -53,7 +53,7 @@ static struct dentry *ovl_lookup_temp(struct dentry *workdir)

temp = lookup_one_len(name, workdir, strlen(name));
if (!IS_ERR(temp) && temp->d_inode) {
pr_err("overlayfs: workdir/%s already exists\n", name);
pr_err("workdir/%s already exists\n", name);
dput(temp);
temp = ERR_PTR(-EIO);
}
Expand Down Expand Up @@ -134,7 +134,7 @@ static int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry,
d = lookup_one_len(dentry->d_name.name, dentry->d_parent,
dentry->d_name.len);
if (IS_ERR(d)) {
pr_warn("overlayfs: failed lookup after mkdir (%pd2, err=%i).\n",
pr_warn("failed lookup after mkdir (%pd2, err=%i).\n",
dentry, err);
return PTR_ERR(d);
}
Expand Down Expand Up @@ -267,7 +267,7 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,

d_instantiate(dentry, inode);
if (inode != oip.newinode) {
pr_warn_ratelimited("overlayfs: newly created inode found in cache (%pd2)\n",
pr_warn_ratelimited("newly created inode found in cache (%pd2)\n",
dentry);
}

Expand Down Expand Up @@ -1009,7 +1009,7 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir)
spin_unlock(&dentry->d_lock);
} else {
kfree(redirect);
pr_warn_ratelimited("overlayfs: failed to set redirect (%i)\n",
pr_warn_ratelimited("failed to set redirect (%i)\n",
err);
/* Fall back to userspace copy-up */
err = -EXDEV;
Expand Down
28 changes: 13 additions & 15 deletions fs/overlayfs/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ static int ovl_encode_maybe_copy_up(struct dentry *dentry)
}

if (err) {
pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n",
pr_warn_ratelimited("failed to copy up on encode (%pd2, err=%i)\n",
dentry, err);
}

Expand Down Expand Up @@ -244,7 +244,7 @@ static int ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen)
return err;

fail:
pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
pr_warn_ratelimited("failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
dentry, err, buflen, fh ? (int)fh->fb.len : 0,
fh ? fh->fb.type : 0);
goto out;
Expand Down Expand Up @@ -358,7 +358,7 @@ static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
*/
static struct dentry *ovl_lookup_real_one(struct dentry *connected,
struct dentry *real,
struct ovl_layer *layer)
const struct ovl_layer *layer)
{
struct inode *dir = d_inode(connected);
struct dentry *this, *parent = NULL;
Expand Down Expand Up @@ -406,25 +406,24 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
return this;

fail:
pr_warn_ratelimited("overlayfs: failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n",
pr_warn_ratelimited("failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n",
real, layer->idx, connected, err);
this = ERR_PTR(err);
goto out;
}

static struct dentry *ovl_lookup_real(struct super_block *sb,
struct dentry *real,
struct ovl_layer *layer);
const struct ovl_layer *layer);

/*
* Lookup an indexed or hashed overlay dentry by real inode.
*/
static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
struct dentry *real,
struct ovl_layer *layer)
const struct ovl_layer *layer)
{
struct ovl_fs *ofs = sb->s_fs_info;
struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt };
struct dentry *index = NULL;
struct dentry *this = NULL;
struct inode *inode;
Expand Down Expand Up @@ -466,7 +465,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
* recursive call walks back from indexed upper to the topmost
* connected/hashed upper parent (or up to root).
*/
this = ovl_lookup_real(sb, upper, &upper_layer);
this = ovl_lookup_real(sb, upper, &ofs->layers[0]);
dput(upper);
}

Expand All @@ -487,7 +486,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
*/
static struct dentry *ovl_lookup_real_ancestor(struct super_block *sb,
struct dentry *real,
struct ovl_layer *layer)
const struct ovl_layer *layer)
{
struct dentry *next, *parent = NULL;
struct dentry *ancestor = ERR_PTR(-EIO);
Expand Down Expand Up @@ -540,7 +539,7 @@ static struct dentry *ovl_lookup_real_ancestor(struct super_block *sb,
*/
static struct dentry *ovl_lookup_real(struct super_block *sb,
struct dentry *real,
struct ovl_layer *layer)
const struct ovl_layer *layer)
{
struct dentry *connected;
int err = 0;
Expand Down Expand Up @@ -631,7 +630,7 @@ static struct dentry *ovl_lookup_real(struct super_block *sb,
return connected;

fail:
pr_warn_ratelimited("overlayfs: failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n",
pr_warn_ratelimited("failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n",
real, layer->idx, connected, err);
dput(connected);
return ERR_PTR(err);
Expand All @@ -646,8 +645,7 @@ static struct dentry *ovl_get_dentry(struct super_block *sb,
struct dentry *index)
{
struct ovl_fs *ofs = sb->s_fs_info;
struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt };
struct ovl_layer *layer = upper ? &upper_layer : lowerpath->layer;
const struct ovl_layer *layer = upper ? &ofs->layers[0] : lowerpath->layer;
struct dentry *real = upper ?: (index ?: lowerpath->dentry);

/*
Expand Down Expand Up @@ -822,7 +820,7 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
return dentry;

out_err:
pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
pr_warn_ratelimited("failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n",
fh_len, fh_type, flags, err);
dentry = ERR_PTR(err);
goto out;
Expand All @@ -831,7 +829,7 @@ static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid,
static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
{
pr_warn_ratelimited("overlayfs: connectable file handles not supported; use 'no_subtree_check' exportfs option.\n");
pr_warn_ratelimited("connectable file handles not supported; use 'no_subtree_check' exportfs option.\n");
return ERR_PTR(-EACCES);
}

Expand Down
Loading

0 comments on commit 7f879e1

Please sign in to comment.