summaryrefslogtreecommitdiff
path: root/fs/overlayfs/super.c
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2023-04-27 12:48:46 +0300
committerAmir Goldstein <amir73il@gmail.com>2023-06-19 14:01:13 +0300
commit37ebf056d6cfc6638c821386bc33a9602bbc0d28 (patch)
tree6afbbc69d724e289a11e7985c3d991986810ccb5 /fs/overlayfs/super.c
parent9e88f9052415289f2789abb6ae68a40a4701b8e1 (diff)
ovl: introduce data-only lower layers
Introduce the format lowerdir=lower1:lower2::lowerdata1::lowerdata2 where the lower layers on the right of the :: separators are not merged into the overlayfs merge dirs. Data-only lower layers are only allowed at the bottom of the stack. The files in those layers are only meant to be accessible via absolute redirect from metacopy files in lower layers. Following changes will implement lookup in the data layers. This feature was requested for composefs ostree use case, where the lower data layer should only be accessiable via absolute redirects from metacopy inodes. The lower data layers are not required to a have a unique uuid or any uuid at all, because they are never used to compose the overlayfs inode st_ino/st_dev. Reviewed-by: Alexander Larsson <alexl@redhat.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/super.c')
-rw-r--r--fs/overlayfs/super.c69
1 files changed, 62 insertions, 7 deletions
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];
}