Unlike common disk filesystems, overlay filesystem enable features through mount options(e.g. -o index=on will enable index feature), so it's a good time to save enabled features on the upper root dir according to mount options. The given feature will be enabled when user give option "-o xxx=on" during mount time. This patch add three already support features: redirect_dir, index and nfs_export, the first one belongs to the incompatable feature set, and the other two belong to the ro_compatable feature set. eg: mount -t overlay -olowerdir=lower,upperdir=upper,workdir=work \ -oredirect_dir=on,index=on,nfs_export=on overlay merge trusted.overlay.feature_ro_compat="index,nfs_export" trusted.overlay.feature_incompat="redirect_dir" This patch also introduce three sets of feature check/set helper functions ovl_has_xxx_feature() and ovl_set_xxx_feature() which learn from ext4 filesystem driver. Suggested-by: Amir Goldstein <amir73il@xxxxxxxxx> Signed-off-by: zhangyi (F) <yi.zhang@xxxxxxxxxx> --- fs/overlayfs/overlayfs.h | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/overlayfs/ovl_entry.h | 2 ++ fs/overlayfs/super.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 121e81cc1550..53ed4e73f889 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -47,6 +47,79 @@ enum ovl_entry_flag { }; /* Features */ +enum ovl_feature_flag { + OVL_FEATURE_COMPAT, + OVL_FEATURE_RO_COMPAT, + OVL_FEATURE_INCOMPAT, + OVL_FEATURE_MAX, +}; + +#define OVL_FEATURE_RO_COMPAT_INDEX "index" +#define OVL_FEATURE_RO_COMPAT_NFS_EXPORT "nfs_export" + +#define OVL_FEATURE_INCOMPAT_REDIRECT_DIR "redirect_dir" + +int ovl_set_feature_set(struct super_block *sb, + enum ovl_feature_flag flag, const char *new); + +#define OVL_FEATURE_COMPAT_FUNCS(name, flagname) \ +static inline bool ovl_has_feature_##name(struct super_block *sb) \ +{ \ + bool exist;\ + down_read(&OVL_FS(sb)->feature.lock); \ + exist = ((OVL_FS(sb)->feature.compat) && \ + (strstr(OVL_FS(sb)->feature.compat, \ + OVL_FEATURE_COMPAT_##flagname))); \ + up_read(&OVL_FS(sb)->feature.lock); \ + return exist; \ +} \ +static inline int ovl_set_feature_##name(struct super_block *sb) \ +{ \ + return ovl_set_feature_set(sb, OVL_FEATURE_COMPAT, \ + OVL_FEATURE_COMPAT_##flagname); \ +} \ + +#define OVL_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ +static inline bool ovl_has_feature_##name(struct super_block *sb) \ +{ \ + bool exist;\ + down_read(&OVL_FS(sb)->feature.lock); \ + exist = ((OVL_FS(sb)->feature.ro_compat) && \ + (strstr(OVL_FS(sb)->feature.ro_compat, \ + OVL_FEATURE_RO_COMPAT_##flagname))); \ + up_read(&OVL_FS(sb)->feature.lock); \ + return exist; \ +} \ +static inline int ovl_set_feature_##name(struct super_block *sb) \ +{ \ + return ovl_set_feature_set(sb, OVL_FEATURE_RO_COMPAT, \ + OVL_FEATURE_RO_COMPAT_##flagname); \ +} \ + +#define OVL_FEATURE_INCOMPAT_FUNCS(name, flagname) \ +static inline bool ovl_has_feature_##name(struct super_block *sb) \ +{ \ + bool exist;\ + down_read(&OVL_FS(sb)->feature.lock); \ + exist = ((OVL_FS(sb)->feature.incompat) && \ + (strstr(OVL_FS(sb)->feature.incompat, \ + OVL_FEATURE_INCOMPAT_##flagname))); \ + up_read(&OVL_FS(sb)->feature.lock); \ + return exist; \ +} \ +static inline int ovl_set_feature_##name(struct super_block *sb) \ +{ \ + return ovl_set_feature_set(sb, OVL_FEATURE_INCOMPAT, \ + OVL_FEATURE_INCOMPAT_##flagname); \ +} \ + + +OVL_FEATURE_RO_COMPAT_FUNCS(index, INDEX) +OVL_FEATURE_RO_COMPAT_FUNCS(nfs_export, NFS_EXPORT) + +OVL_FEATURE_INCOMPAT_FUNCS(redirect_dir, REDIRECT_DIR) + + static inline bool ovl_has_unknown_compat_features(struct super_block *sb) { return (OVL_FS(sb)->feature.compat_unknown != NULL); diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index f8c5e0191a12..ff8bf783a097 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -36,6 +36,8 @@ struct ovl_feature { char *compat; char *ro_compat; char *incompat; + struct rw_semaphore lock; /* protect feature string */ + const char *compat_unknown; const char *ro_compat_unknown; const char *incompat_unknown; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 19b7d0869fbd..4787f9356dfd 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -189,13 +189,22 @@ static const char *ovl_feature_compat_supp[] = { }; static const char *ovl_feature_ro_compat_supp[] = { + OVL_FEATURE_RO_COMPAT_INDEX, + OVL_FEATURE_RO_COMPAT_NFS_EXPORT, NULL }; static const char *ovl_feature_incompat_supp[] = { + OVL_FEATURE_INCOMPAT_REDIRECT_DIR, NULL }; +static const char *ovl_feature_set[] = { + OVL_XATTR_FEATURE_COMPAT, + OVL_XATTR_FEATURE_RO_COMPAT, + OVL_XATTR_FEATURE_INCOMPAT +}; + /* * Get overlay feature from the real root dentry. * @@ -431,6 +440,8 @@ static int ovl_init_features(struct dentry *root, struct ovl_feature *of) { int err; + init_rwsem(&of->lock); + err = ovl_get_feature_set(root, OVL_XATTR_FEATURE_COMPAT, ovl_feature_compat_supp, &of->compat, &of->compat_unknown); @@ -487,6 +498,49 @@ static bool ovl_check_feature_ok(struct super_block *sb, bool readonly) return true; } +/* + * Set one specified feature to the upper root dir + * + * @sb: overlay super block + * @flag: feature set flag, compat/ro compat/incompat + * @new: new feature want to set + * Return 0 if success, errno otherwise. + */ +int ovl_set_feature_set(struct super_block *sb, + enum ovl_feature_flag flag, const char *new) +{ + struct ovl_feature *of = &OVL_FS(sb)->feature; + bool update = false; + char **feature; + int err; + + /* Don't set feature if no upper layer */ + if (!OVL_FS(sb)->upper_mnt) + return 0; + + down_write(&of->lock); + if (flag == OVL_FEATURE_COMPAT) + feature = &of->compat; + else if (flag == OVL_FEATURE_RO_COMPAT) + feature = &of->ro_compat; + else + feature = &of->incompat; + + err = ovl_update_feature(feature, new, &update); + if (err) + goto out; + if (!update) + goto out; + + /* Set updated compat features to upper root dir */ + err = ovl_set_feature(sb->s_root, ovl_dentry_upper(sb->s_root), + ovl_feature_set[flag], *feature); +out: + up_write(&of->lock); + return err; +} + + static struct kmem_cache *ovl_inode_cachep; static struct inode *ovl_alloc_inode(struct super_block *sb) @@ -1689,6 +1743,23 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) if (!ovl_check_feature_ok(sb, (sb_rdonly(sb)))) goto out_free_root; + /* Turn on features according to mount options */ + if (ofs->config.index && !ovl_has_feature_index(sb)) { + err = ovl_set_feature_index(sb); + if (err) + goto out_free_root; + } + if (ofs->config.nfs_export && !ovl_has_feature_nfs_export(sb)) { + err = ovl_set_feature_nfs_export(sb); + if (err) + goto out_free_root; + } + if (ofs->config.redirect_dir && !ovl_has_feature_redirect_dir(sb)) { + err = ovl_set_feature_redirect_dir(sb); + if (err) + goto out_free_root; + } + return 0; out_free_root: -- 2.13.6 -- To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html