diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index b63e0db03631..d55381d3fa0f 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -657,6 +657,22 @@ can be useful in case the underlying disk is copied and the UUID of this copy is changed. This is only applicable if all lower/upper/work directories are on the same filesystem, otherwise it will fallback to normal behaviour. + +UUID and fsid +------------- + +The UUID of overlayfs instance itself and the fsid reported by statfs(2) are +controlled by the "uuid" mount option, which supports these values: + +- "null": (default) + UUID of overlayfs is null. fsid is taken from upper most filesystem. +- "off": + UUID of overlayfs is null. fsid is taken from upper most filesystem. + UUID of underlying layers is ignored. +- "on": + UUID of overlayfs is generated and used to report a unique fsid. + + Volatile mount -------------- diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 2ead7c9a7748..618651b54818 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -416,7 +416,7 @@ struct ovl_fh *ovl_encode_real_fh(struct ovl_fs *ofs, struct dentry *real, if (is_upper) fh->fb.flags |= OVL_FH_FLAG_PATH_UPPER; fh->fb.len = sizeof(fh->fb) + buflen; - if (ofs->config.uuid) + if (ovl_origin_uuid(ofs)) fh->fb.uuid = *uuid; return fh; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index d00ec43f2376..84c06512fb71 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -171,8 +171,9 @@ struct dentry *ovl_decode_real_fh(struct ovl_fs *ofs, struct ovl_fh *fh, * layer where file handle will be decoded. * In case of uuid=off option just make sure that stored uuid is null. */ - if (ofs->config.uuid ? !uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid) : - !uuid_is_null(&fh->fb.uuid)) + if (ovl_origin_uuid(ofs) ? + !uuid_equal(&fh->fb.uuid, &mnt->mnt_sb->s_uuid) : + !uuid_is_null(&fh->fb.uuid)) return NULL; bytes = (fh->fb.len - offsetof(struct ovl_fb, fid)); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 453610fb9bf9..000dd89fe319 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -67,6 +67,12 @@ enum { OVL_REDIRECT_ON, }; +enum { + OVL_UUID_OFF, + OVL_UUID_NULL, + OVL_UUID_ON, +}; + enum { OVL_XINO_OFF, OVL_XINO_AUTO, @@ -534,6 +540,16 @@ static inline bool ovl_redirect_dir(struct ovl_fs *ofs) return ofs->config.redirect_mode == OVL_REDIRECT_ON; } +static inline bool ovl_origin_uuid(struct ovl_fs *ofs) +{ + return ofs->config.uuid != OVL_UUID_OFF; +} + +static inline bool ovl_has_fsid(struct ovl_fs *ofs) +{ + return ofs->config.uuid == OVL_UUID_ON; +} + /* * With xino=auto, we do best effort to keep all inodes on same st_dev and * d_ino consistent with st_ino. diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index 7a5196c94d75..5d03f449adb1 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -12,7 +12,7 @@ struct ovl_config { int redirect_mode; int verity_mode; bool index; - bool uuid; + int uuid; bool nfs_export; int xino; bool metacopy; diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c index 575a60b76a6c..1ff93467e793 100644 --- a/fs/overlayfs/params.c +++ b/fs/overlayfs/params.c @@ -65,6 +65,23 @@ static const struct constant_table ovl_parameter_bool[] = { {} }; +static const struct constant_table ovl_parameter_uuid[] = { + { "off", OVL_UUID_OFF }, + { "null", OVL_UUID_NULL }, + { "on", OVL_UUID_ON }, + {} +}; + +static const char *ovl_uuid_mode(struct ovl_config *config) +{ + return ovl_parameter_uuid[config->uuid].name; +} + +static int ovl_uuid_def(void) +{ + return OVL_UUID_NULL; +} + static const struct constant_table ovl_parameter_xino[] = { { "off", OVL_XINO_OFF }, { "auto", OVL_XINO_AUTO }, @@ -129,7 +146,7 @@ const struct fs_parameter_spec ovl_parameter_spec[] = { fsparam_flag("default_permissions", Opt_default_permissions), fsparam_enum("redirect_dir", Opt_redirect_dir, ovl_parameter_redirect_dir), fsparam_enum("index", Opt_index, ovl_parameter_bool), - fsparam_enum("uuid", Opt_uuid, ovl_parameter_bool), + fsparam_enum("uuid", Opt_uuid, ovl_parameter_uuid), fsparam_enum("nfs_export", Opt_nfs_export, ovl_parameter_bool), fsparam_flag("userxattr", Opt_userxattr), fsparam_enum("xino", Opt_xino, ovl_parameter_xino), @@ -701,7 +718,7 @@ int ovl_init_fs_context(struct fs_context *fc) ofs->config.redirect_mode = ovl_redirect_mode_def(); ofs->config.index = ovl_index_def; - ofs->config.uuid = true; + ofs->config.uuid = ovl_uuid_def(); ofs->config.nfs_export = ovl_nfs_export_def; ofs->config.xino = ovl_xino_def(); ofs->config.metacopy = ovl_metacopy_def; @@ -947,8 +964,8 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry) ovl_redirect_mode(&ofs->config)); if (ofs->config.index != ovl_index_def) seq_printf(m, ",index=%s", ofs->config.index ? "on" : "off"); - if (!ofs->config.uuid) - seq_puts(m, ",uuid=off"); + if (ofs->config.uuid != ovl_uuid_def()) + seq_printf(m, ",uuid=%s", ovl_uuid_mode(&ofs->config)); if (ofs->config.nfs_export != ovl_nfs_export_def) seq_printf(m, ",nfs_export=%s", ofs->config.nfs_export ? "on" : "off"); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index e56108ffe8aa..c2bab6106e98 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -242,8 +242,9 @@ static int ovl_sync_fs(struct super_block *sb, int wait) */ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) { - struct ovl_fs *ofs = dentry->d_sb->s_fs_info; - struct dentry *root_dentry = dentry->d_sb->s_root; + struct super_block *sb = dentry->d_sb; + struct ovl_fs *ofs = OVL_FS(sb); + struct dentry *root_dentry = sb->s_root; struct path path; int err; @@ -253,6 +254,8 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) if (!err) { buf->f_namelen = ofs->namelen; buf->f_type = OVERLAYFS_SUPER_MAGIC; + if (ovl_has_fsid(ofs)) + buf->f_fsid = uuid_to_fsid(sb->s_uuid.b); } return err; @@ -1421,9 +1424,12 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) if (!ovl_upper_mnt(ofs)) sb->s_flags |= SB_RDONLY; - if (!ofs->config.uuid && ofs->numfs > 1) { - pr_warn("The uuid=off requires a single fs for lower and upper, falling back to uuid=on.\n"); - ofs->config.uuid = true; + if (!ovl_origin_uuid(ofs) && ofs->numfs > 1) { + pr_warn("The uuid=off requires a single fs for lower and upper, falling back to uuid=null.\n"); + ofs->config.uuid = OVL_UUID_NULL; + } else if (ovl_has_fsid(ofs)) { + /* Use per instance uuid/fsid */ + uuid_gen(&sb->s_uuid); } if (!ovl_force_readonly(ofs) && ofs->config.index) {