diff options
| -rw-r--r-- | Documentation/filesystems/overlayfs.rst | 35 | ||||
| -rw-r--r-- | fs/overlayfs/namei.c | 2 | ||||
| -rw-r--r-- | fs/overlayfs/ovl_entry.h | 9 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 69 |
4 files changed, 107 insertions, 8 deletions
diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 4c76fda07645..4f36b8919f7c 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -371,6 +371,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 -------------------------- diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 8ea2a8358a92..5c1b0397c8ce 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -356,7 +356,7 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected, struct dentry *origin = NULL; int i; - for (i = 1; i < ofs->numlayer; i++) { + for (i = 1; i <= ovl_numlowerlayer(ofs); i++) { /* * If lower fs uuid is not unique among lower fs we cannot match * fh->uuid to layer. diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 548c93e030fc..93ff299da0dd 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -57,6 +57,8 @@ struct ovl_fs { unsigned int numlayer; /* Number of unique fs among layers including upper fs */ unsigned int numfs; + /* Number of data-only lower layers */ + unsigned int numdatalayer; const struct ovl_layer *layers; struct ovl_sb *fs; /* workbasedir is the path at workdir= mount option */ @@ -90,6 +92,13 @@ struct ovl_fs { errseq_t errseq; }; + +/* Number of lower layers, not including data-only layers */ +static inline unsigned int ovl_numlowerlayer(struct ovl_fs *ofs) +{ + return ofs->numlayer - ofs->numdatalayer - 1; +} + static inline struct vfsmount *ovl_upper_mnt(struct ovl_fs *ofs) { return ofs->layers[0].mnt; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index b1124cf85206..be2bdf37b0d5 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -1568,6 +1568,16 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path) return ofs->numfs++; } +/* + * The fsid after the last lower fsid is used for the data layers. + * It is a "null fs" with a null sb, null uuid, and no pseudo dev. + */ +static int ovl_get_data_fsid(struct ovl_fs *ofs) +{ + return ofs->numfs; +} + + static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, struct path *stack, unsigned int numlower, struct ovl_layer *layers) @@ -1575,11 +1585,14 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, int err; unsigned int i; - ofs->fs = kcalloc(numlower + 1, sizeof(struct ovl_sb), GFP_KERNEL); + ofs->fs = kcalloc(numlower + 2, sizeof(struct ovl_sb), GFP_KERNEL); if (ofs->fs == NULL) return -ENOMEM; - /* idx/fsid 0 are reserved for upper fs even with lower only overlay */ + /* + * idx/fsid 0 are reserved for upper fs even with lower only overlay + * and the last fsid is reserved for "null fs" of the data layers. + */ ofs->numfs++; /* @@ -1604,7 +1617,10 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, struct inode *trap; int fsid; - fsid = ovl_get_fsid(ofs, &stack[i]); + if (i < numlower - ofs->numdatalayer) + fsid = ovl_get_fsid(ofs, &stack[i]); + else + fsid = ovl_get_data_fsid(ofs); if (fsid < 0) return fsid; @@ -1692,6 +1708,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, int err; struct path *stack = NULL; struct ovl_path *lowerstack; + unsigned int numlowerdata = 0; unsigned int i; struct ovl_entry *oe; @@ -1704,13 +1721,50 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, if (!stack) return ERR_PTR(-ENOMEM); - err = -EINVAL; - for (i = 0; i < numlower; i++) { + for (i = 0; i < numlower;) { err = ovl_lower_dir(lower, &stack[i], ofs, &sb->s_stack_depth); if (err) goto out_err; lower = strchr(lower, '\0') + 1; + + i++; + if (i == numlower) + break; + + err = -EINVAL; + /* + * Empty lower layer path could mean :: separator that indicates + * a data-only lower data. + * Several data-only layers are allowed, but they all need to be + * at the bottom of the stack. + */ + if (*lower) { + /* normal lower dir */ + if (numlowerdata) { + pr_err("lower data-only dirs must be at the bottom of the stack.\n"); + goto out_err; + } + } else { + /* data-only lower dir */ + if (!ofs->config.metacopy) { + pr_err("lower data-only dirs require metacopy support.\n"); + goto out_err; + } + if (i == numlower - 1) { + pr_err("lowerdir argument must not end with double colon.\n"); + goto out_err; + } + lower++; + numlower--; + numlowerdata++; + } + } + + if (numlowerdata) { + ofs->numdatalayer = numlowerdata; + pr_info("using the lowest %d of %d lowerdirs as data layers\n", + numlowerdata, numlower); } err = -EINVAL; @@ -1725,12 +1779,13 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, goto out_err; err = -ENOMEM; - oe = ovl_alloc_entry(numlower); + /* Data-only layers are not merged in root directory */ + oe = ovl_alloc_entry(numlower - numlowerdata); if (!oe) goto out_err; lowerstack = ovl_lowerstack(oe); - for (i = 0; i < numlower; i++) { + for (i = 0; i < numlower - numlowerdata; i++) { lowerstack[i].dentry = dget(stack[i].dentry); lowerstack[i].layer = &ofs->layers[i+1]; } |
