]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
ovl: add support for "xino" mount and config options
authorAmir Goldstein <amir73il@gmail.com>
Thu, 29 Mar 2018 06:08:18 +0000 (09:08 +0300)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 12 Apr 2018 10:04:50 +0000 (12:04 +0200)
With mount option "xino=on", mounter declares that there are enough
free high bits in underlying fs to hold the layer fsid.
If overlayfs does encounter underlying inodes using the high xino
bits reserved for layer fsid, a warning will be emitted and the original
inode number will be used.

The mount option name "xino" goes after a similar meaning mount option
of aufs, but in overlayfs case, the mapping is stateless.

An example for a use case of "xino=on" is when upper/lower is on an xfs
filesystem. xfs uses 64bit inode numbers, but it currently never uses the
upper 8bit for inode numbers exposed via stat(2) and that is not likely to
change in the future without user opting-in for a new xfs feature. The
actual number of unused upper bit is much larger and determined by the xfs
filesystem geometry (64 - agno_log - agblklog - inopblog). That means
that for all practical purpose, there are enough unused bits in xfs
inode numbers for more than OVL_MAX_STACK unique fsid's.

Another use case of "xino=on" is when upper/lower is on tmpfs. tmpfs inode
numbers are allocated sequentially since boot, so they will practially
never use the high inode number bits.

For compatibility with applications that expect 32bit inodes, the feature
can be disabled with "xino=off". The option "xino=auto" automatically
detects underlying filesystem that use 32bit inodes and enables the
feature. The Kconfig option OVERLAY_FS_XINO_AUTO and module parameter of
the same name, determine if the default mode for overlayfs mount is
"xino=auto" or "xino=off".

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/Kconfig
fs/overlayfs/ovl_entry.h
fs/overlayfs/super.c

index ce6ff5a0a6e4e8b75d4f588981d9c710432bb52b..17032631c5cf62cc200c8bf2f897bb3e4c0c96cb 100644 (file)
@@ -86,3 +86,20 @@ config OVERLAY_FS_NFS_EXPORT
          case basis with the "nfs_export=on" mount option.
 
          Say N unless you fully understand the consequences.
+
+config OVERLAY_FS_XINO_AUTO
+       bool "Overlayfs: auto enable inode number mapping"
+       default n
+       depends on OVERLAY_FS
+       help
+         If this config option is enabled then overlay filesystems will use
+         unused high bits in undelying filesystem inode numbers to map all
+         inodes to a unified address space.  The mapped 64bit inode numbers
+         might not be compatible with applications that expect 32bit inodes.
+
+         If compatibility with applications that expect 32bit inodes is not an
+         issue, then it is safe and recommended to say Y here.
+
+         For more information, see Documentation/filesystems/overlayfs.txt
+
+         If unsure, say N.
index 620bd20f9a221d9c19662b4ece94d9fae08dcfb3..41655a7d68947068e2e13b57739aa1bd7a1279eb 100644 (file)
@@ -18,6 +18,7 @@ struct ovl_config {
        const char *redirect_mode;
        bool index;
        bool nfs_export;
+       int xino;
 };
 
 struct ovl_sb {
index d7284444f4041a8e29179219622e270940d99055..e8551c97de51c0676416d982aad60b9ca72c0373 100644 (file)
@@ -51,6 +51,11 @@ module_param_named(nfs_export, ovl_nfs_export_def, bool, 0644);
 MODULE_PARM_DESC(ovl_nfs_export_def,
                 "Default to on or off for the NFS export feature");
 
+static bool ovl_xino_auto_def = IS_ENABLED(CONFIG_OVERLAY_FS_XINO_AUTO);
+module_param_named(xino_auto, ovl_xino_auto_def, bool, 0644);
+MODULE_PARM_DESC(ovl_xino_auto_def,
+                "Auto enable xino feature");
+
 static void ovl_entry_stack_free(struct ovl_entry *oe)
 {
        unsigned int i;
@@ -327,6 +332,23 @@ static const char *ovl_redirect_mode_def(void)
        return ovl_redirect_dir_def ? "on" : "off";
 }
 
+enum {
+       OVL_XINO_OFF,
+       OVL_XINO_AUTO,
+       OVL_XINO_ON,
+};
+
+static const char * const ovl_xino_str[] = {
+       "off",
+       "auto",
+       "on",
+};
+
+static inline int ovl_xino_def(void)
+{
+       return ovl_xino_auto_def ? OVL_XINO_AUTO : OVL_XINO_OFF;
+}
+
 /**
  * ovl_show_options
  *
@@ -352,6 +374,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
        if (ofs->config.nfs_export != ovl_nfs_export_def)
                seq_printf(m, ",nfs_export=%s", ofs->config.nfs_export ?
                                                "on" : "off");
+       if (ofs->config.xino != ovl_xino_def())
+               seq_printf(m, ",xino=%s", ovl_xino_str[ofs->config.xino]);
        return 0;
 }
 
@@ -386,6 +410,9 @@ enum {
        OPT_INDEX_OFF,
        OPT_NFS_EXPORT_ON,
        OPT_NFS_EXPORT_OFF,
+       OPT_XINO_ON,
+       OPT_XINO_OFF,
+       OPT_XINO_AUTO,
        OPT_ERR,
 };
 
@@ -399,6 +426,9 @@ static const match_table_t ovl_tokens = {
        {OPT_INDEX_OFF,                 "index=off"},
        {OPT_NFS_EXPORT_ON,             "nfs_export=on"},
        {OPT_NFS_EXPORT_OFF,            "nfs_export=off"},
+       {OPT_XINO_ON,                   "xino=on"},
+       {OPT_XINO_OFF,                  "xino=off"},
+       {OPT_XINO_AUTO,                 "xino=auto"},
        {OPT_ERR,                       NULL}
 };
 
@@ -513,6 +543,18 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
                        config->nfs_export = false;
                        break;
 
+               case OPT_XINO_ON:
+                       config->xino = OVL_XINO_ON;
+                       break;
+
+               case OPT_XINO_OFF:
+                       config->xino = OVL_XINO_OFF;
+                       break;
+
+               case OPT_XINO_AUTO:
+                       config->xino = OVL_XINO_AUTO;
+                       break;
+
                default:
                        pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
                        return -EINVAL;
@@ -1197,9 +1239,31 @@ static int ovl_get_lower_layers(struct ovl_fs *ofs, struct path *stack,
                ofs->numlower++;
        }
 
-       /* When all layers on same fs, overlay can use real inode numbers */
-       if (!ofs->numlowerfs || (ofs->numlowerfs == 1 && !ofs->upper_mnt))
+       /*
+        * When all layers on same fs, overlay can use real inode numbers.
+        * With mount option "xino=on", mounter declares that there are enough
+        * free high bits in underlying fs to hold the unique fsid.
+        * If overlayfs does encounter underlying inodes using the high xino
+        * bits reserved for fsid, it emits a warning and uses the original
+        * inode number.
+        */
+       if (!ofs->numlowerfs || (ofs->numlowerfs == 1 && !ofs->upper_mnt)) {
                ofs->xino_bits = 0;
+               ofs->config.xino = OVL_XINO_OFF;
+       } else if (ofs->config.xino == OVL_XINO_ON && !ofs->xino_bits) {
+               /*
+                * This is a roundup of number of bits needed for numlowerfs+1
+                * (i.e. ilog2(numlowerfs+1 - 1) + 1). fsid 0 is reserved for
+                * upper fs even with non upper overlay.
+                */
+               BUILD_BUG_ON(ilog2(OVL_MAX_STACK) > 31);
+               ofs->xino_bits = ilog2(ofs->numlowerfs) + 1;
+       }
+
+       if (ofs->xino_bits) {
+               pr_info("overlayfs: \"xino\" feature enabled using %d upper inode bits.\n",
+                       ofs->xino_bits);
+       }
 
        err = 0;
 out:
@@ -1311,6 +1375,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        ofs->config.index = ovl_index_def;
        ofs->config.nfs_export = ovl_nfs_export_def;
+       ofs->config.xino = ovl_xino_def();
        err = ovl_parse_opt((char *) data, &ofs->config);
        if (err)
                goto out_err;
@@ -1325,7 +1390,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_stack_depth = 0;
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        /* Assume underlaying fs uses 32bit inodes unless proven otherwise */
-       ofs->xino_bits = BITS_PER_LONG - 32;
+       if (ofs->config.xino != OVL_XINO_OFF)
+               ofs->xino_bits = BITS_PER_LONG - 32;
+
        if (ofs->config.upperdir) {
                if (!ofs->config.workdir) {
                        pr_err("overlayfs: missing 'workdir'\n");