[*] 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
--------------------------
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 */
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;
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)
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++;
/*
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;
int err;
struct path *stack = NULL;
struct ovl_path *lowerstack;
+ unsigned int numlowerdata = 0;
unsigned int i;
struct ovl_entry *oe;
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;
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];
}