Skip to content
This repository has been archived by the owner on Aug 14, 2023. It is now read-only.

Commit

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

Pull overlayfs update from Amir Goldstein:

 - fix two NULL pointer deref bugs (Zhihao Cheng)

 - add support for "data-only" lower layers destined to be used by
   composefs

 - port overlayfs to the new mount api (Christian Brauner)

* tag 'ovl-update-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs: (26 commits)
  ovl: add Amir as co-maintainer
  ovl: reserve ability to reconfigure mount options with new mount api
  ovl: modify layer parameter parsing
  ovl: port to new mount api
  ovl: factor out ovl_parse_options() helper
  ovl: store enum redirect_mode in config instead of a string
  ovl: pass ovl_fs to xino helpers
  ovl: clarify ovl_get_root() semantics
  ovl: negate the ofs->share_whiteout boolean
  ovl: check type and offset of struct vfsmount in ovl_entry
  ovl: implement lazy lookup of lowerdata in data-only layers
  ovl: prepare for lazy lookup of lowerdata inode
  ovl: prepare to store lowerdata redirect for lazy lowerdata lookup
  ovl: implement lookup in data-only layers
  ovl: introduce data-only lower layers
  ovl: remove unneeded goto instructions
  ovl: deduplicate lowerdata and lowerstack[]
  ovl: deduplicate lowerpath and lowerstack[]
  ovl: move ovl_entry into ovl_inode
  ovl: factor out ovl_free_entry() and ovl_stack_*() helpers
  ...
  • Loading branch information
torvalds committed Jun 29, 2023
2 parents eee9c70 + 62149a7 commit be3c213
Show file tree
Hide file tree
Showing 15 changed files with 1,390 additions and 704 deletions.
44 changes: 39 additions & 5 deletions Documentation/filesystems/overlayfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,11 @@ Mount options:
Redirects are enabled.
- "redirect_dir=follow":
Redirects are not created, but followed.
- "redirect_dir=off":
Redirects are not created and only followed if "redirect_always_follow"
feature is enabled in the kernel/module config.
- "redirect_dir=nofollow":
Redirects are not created and not followed (equivalent to "redirect_dir=off"
if "redirect_always_follow" feature is not enabled).
Redirects are not created and not followed.
- "redirect_dir=off":
If "redirect_always_follow" is enabled in the kernel/module config,
this "off" traslates to "follow", otherwise it translates to "nofollow".

When the NFS export feature is enabled, every copied up directory is
indexed by the file handle of the lower inode and a file handle of the
Expand Down Expand Up @@ -371,6 +370,41 @@ conflict with metacopy=on, and will result in an error.
[*] redirect_dir=follow only conflicts with metacopy=on if upperdir=... is
given.


Data-only lower layers
----------------------

With "metacopy" feature enabled, an overlayfs regular file may be a composition
of information from up to three different layers:

1) metadata from a file in the upper layer

2) st_ino and st_dev object identifier from a file in a lower layer

3) data from a file in another lower layer (further below)

The "lower data" file can be on any lower layer, except from the top most
lower layer.

Below the top most lower layer, any number of lower most layers may be defined
as "data-only" lower layers, using double colon ("::") separators.
A normal lower layer is not allowed to be below a data-only layer, so single
colon separators are not allowed to the right of double colon ("::") separators.


For example:

mount -t overlay overlay -olowerdir=/l1:/l2:/l3::/do1::/do2 /merged

The paths of files in the "data-only" lower layers are not visible in the
merged overlayfs directories and the metadata and st_ino/st_dev of files
in the "data-only" lower layers are not visible in overlayfs inodes.

Only the data of the files in the "data-only" lower layers may be visible
when a "metacopy" file in one of the lower layers above it, has a "redirect"
to the absolute path of the "lower data" file in the "data-only" lower layer.


Sharing and copying layers
--------------------------

Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -15937,6 +15937,7 @@ F: include/media/i2c/ov2659.h

OVERLAY FILESYSTEM
M: Miklos Szeredi <[email protected]>
M: Amir Goldstein <[email protected]>
L: [email protected]
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
Expand Down
2 changes: 1 addition & 1 deletion fs/overlayfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
obj-$(CONFIG_OVERLAY_FS) += overlay.o

overlay-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \
copy_up.o export.o
copy_up.o export.o params.o
11 changes: 11 additions & 0 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
/* Restore timestamps on parent (best effort) */
ovl_set_timestamps(ofs, upperdir, &c->pstat);
ovl_dentry_set_upper_alias(c->dentry);
ovl_dentry_update_reval(c->dentry, upper);
}
}
inode_unlock(udir);
Expand Down Expand Up @@ -894,6 +895,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
inode_unlock(udir);

ovl_dentry_set_upper_alias(c->dentry);
ovl_dentry_update_reval(c->dentry, ovl_dentry_upper(c->dentry));
}

out:
Expand Down Expand Up @@ -1071,6 +1073,15 @@ static int ovl_copy_up_flags(struct dentry *dentry, int flags)
if (WARN_ON(disconnected && d_is_dir(dentry)))
return -EIO;

/*
* We may not need lowerdata if we are only doing metacopy up, but it is
* not very important to optimize this case, so do lazy lowerdata lookup
* before any copy up, so we can do it before taking ovl_inode_lock().
*/
err = ovl_maybe_lookup_lowerdata(dentry);
if (err)
return err;

old_cred = ovl_override_creds(dentry->d_sb);
while (!err) {
struct dentry *next;
Expand Down
9 changes: 4 additions & 5 deletions fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
ofs->whiteout = whiteout;
}

if (ofs->share_whiteout) {
if (!ofs->no_shared_whiteout) {
whiteout = ovl_lookup_temp(ofs, workdir);
if (IS_ERR(whiteout))
goto out;
Expand All @@ -95,7 +95,7 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
if (err != -EMLINK) {
pr_warn("Failed to link whiteout - disabling whiteout inode sharing(nlink=%u, err=%i)\n",
ofs->whiteout->d_inode->i_nlink, err);
ofs->share_whiteout = false;
ofs->no_shared_whiteout = true;
}
dput(whiteout);
}
Expand Down Expand Up @@ -269,8 +269,7 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,

ovl_dir_modified(dentry->d_parent, false);
ovl_dentry_set_upper_alias(dentry);
ovl_dentry_update_reval(dentry, newdentry,
DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
ovl_dentry_init_reval(dentry, newdentry, NULL);

if (!hardlink) {
/*
Expand Down Expand Up @@ -953,7 +952,7 @@ static bool ovl_type_merge_or_lower(struct dentry *dentry)

static bool ovl_can_move(struct dentry *dentry)
{
return ovl_redirect_dir(dentry->d_sb) ||
return ovl_redirect_dir(OVL_FS(dentry->d_sb)) ||
!d_is_dir(dentry) || !ovl_type_merge_or_lower(dentry);
}

Expand Down
41 changes: 21 additions & 20 deletions fs/overlayfs/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static int ovl_connectable_layer(struct dentry *dentry)

/* We can get overlay root from root of any layer */
if (dentry == dentry->d_sb->s_root)
return oe->numlower;
return ovl_numlower(oe);

/*
* If it's an unindexed merge dir, then it's not connectable with any
Expand All @@ -91,7 +91,7 @@ static int ovl_connectable_layer(struct dentry *dentry)
return 0;

/* We can get upper/overlay path from indexed/lower dentry */
return oe->lowerstack[0].layer->idx;
return ovl_lowerstack(oe)->layer->idx;
}

/*
Expand All @@ -105,14 +105,15 @@ static int ovl_connectable_layer(struct dentry *dentry)
static int ovl_connect_layer(struct dentry *dentry)
{
struct dentry *next, *parent = NULL;
struct ovl_entry *oe = OVL_E(dentry);
int origin_layer;
int err = 0;

if (WARN_ON(dentry == dentry->d_sb->s_root) ||
WARN_ON(!ovl_dentry_lower(dentry)))
return -EIO;

origin_layer = OVL_E(dentry)->lowerstack[0].layer->idx;
origin_layer = ovl_lowerstack(oe)->layer->idx;
if (ovl_dentry_test_flag(OVL_E_CONNECTED, dentry))
return origin_layer;

Expand Down Expand Up @@ -285,21 +286,29 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
struct dentry *lower = lowerpath ? lowerpath->dentry : NULL;
struct dentry *upper = upper_alias ?: index;
struct dentry *dentry;
struct inode *inode;
struct inode *inode = NULL;
struct ovl_entry *oe;
struct ovl_inode_params oip = {
.lowerpath = lowerpath,
.index = index,
.numlower = !!lower
};

/* We get overlay directory dentries with ovl_lookup_real() */
if (d_is_dir(upper ?: lower))
return ERR_PTR(-EIO);

oe = ovl_alloc_entry(!!lower);
if (!oe)
return ERR_PTR(-ENOMEM);

oip.upperdentry = dget(upper);
if (lower) {
ovl_lowerstack(oe)->dentry = dget(lower);
ovl_lowerstack(oe)->layer = lowerpath->layer;
}
oip.oe = oe;
inode = ovl_get_inode(sb, &oip);
if (IS_ERR(inode)) {
ovl_free_entry(oe);
dput(upper);
return ERR_CAST(inode);
}
Expand All @@ -314,20 +323,11 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
dentry = d_alloc_anon(inode->i_sb);
if (unlikely(!dentry))
goto nomem;
oe = ovl_alloc_entry(lower ? 1 : 0);
if (!oe)
goto nomem;

if (lower) {
oe->lowerstack->dentry = dget(lower);
oe->lowerstack->layer = lowerpath->layer;
}
dentry->d_fsdata = oe;
if (upper_alias)
ovl_dentry_set_upper_alias(dentry);

ovl_dentry_update_reval(dentry, upper,
DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE);
ovl_dentry_init_reval(dentry, upper, OVL_I_E(inode));

return d_instantiate_anon(dentry, inode);

Expand All @@ -342,15 +342,16 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
/* Get the upper or lower dentry in stack whose on layer @idx */
static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
{
struct ovl_entry *oe = dentry->d_fsdata;
struct ovl_entry *oe = OVL_E(dentry);
struct ovl_path *lowerstack = ovl_lowerstack(oe);
int i;

if (!idx)
return ovl_dentry_upper(dentry);

for (i = 0; i < oe->numlower; i++) {
if (oe->lowerstack[i].layer->idx == idx)
return oe->lowerstack[i].dentry;
for (i = 0; i < ovl_numlower(oe); i++) {
if (lowerstack[i].layer->idx == idx)
return lowerstack[i].dentry;
}

return NULL;
Expand Down
21 changes: 19 additions & 2 deletions fs/overlayfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,23 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
{
struct dentry *dentry = file_dentry(file);
struct path realpath;
int err;

real->flags = 0;
real->file = file->private_data;

if (allow_meta)
if (allow_meta) {
ovl_path_real(dentry, &realpath);
else
} else {
/* lazy lookup of lowerdata */
err = ovl_maybe_lookup_lowerdata(dentry);
if (err)
return err;

ovl_path_realdata(dentry, &realpath);
}
if (!realpath.dentry)
return -EIO;

/* Has it been copied up since we'd opened it? */
if (unlikely(file_inode(real->file) != d_inode(realpath.dentry))) {
Expand Down Expand Up @@ -150,6 +159,11 @@ static int ovl_open(struct inode *inode, struct file *file)
struct path realpath;
int err;

/* lazy lookup of lowerdata */
err = ovl_maybe_lookup_lowerdata(dentry);
if (err)
return err;

err = ovl_maybe_copy_up(dentry, file->f_flags);
if (err)
return err;
Expand All @@ -158,6 +172,9 @@ static int ovl_open(struct inode *inode, struct file *file)
file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

ovl_path_realdata(dentry, &realpath);
if (!realpath.dentry)
return -EIO;

realfile = ovl_open_realfile(file, &realpath);
if (IS_ERR(realfile))
return PTR_ERR(realfile);
Expand Down
Loading

0 comments on commit be3c213

Please sign in to comment.