Erofs over fscache need CONFIG_CACHEFILES_ONDEMAND in cachefiles module. We cannot know whether it is supported from userspace, so we export this feature to user by sysfs interface.
[Before] $ cat /sys/fs/cachefiles/features/cachefiles_ondemand cat: /sys/fs/cachefiles/features/cachefiles_ondemand: No such file or directory [After] $ cat /sys/fs/cachefiles/features/cachefiles_ondemand supported Signed-off-by: Hongbo Li <lihongb...@huawei.com> --- fs/cachefiles/Makefile | 3 +- fs/cachefiles/internal.h | 7 +++ fs/cachefiles/main.c | 7 +++ fs/cachefiles/sysfs.c | 101 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 fs/cachefiles/sysfs.c diff --git a/fs/cachefiles/Makefile b/fs/cachefiles/Makefile index c37a7a9af10b..e5d9dd27f94f 100644 --- a/fs/cachefiles/Makefile +++ b/fs/cachefiles/Makefile @@ -13,7 +13,8 @@ cachefiles-y := \ namei.o \ security.o \ volume.o \ - xattr.o + xattr.o \ + sysfs.o cachefiles-$(CONFIG_CACHEFILES_ERROR_INJECTION) += error_inject.o cachefiles-$(CONFIG_CACHEFILES_ONDEMAND) += ondemand.o diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index 6845a90cdfcc..4926684b3044 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h @@ -419,6 +419,13 @@ extern void cachefiles_prepare_to_write(struct fscache_cookie *cookie); extern bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume); extern int cachefiles_check_volume_xattr(struct cachefiles_volume *volume); +/* + * sysfs.c + */ + +int __init cachefiles_init_sysfs(void); +void cachefiles_exit_sysfs(void); + /* * Error handling */ diff --git a/fs/cachefiles/main.c b/fs/cachefiles/main.c index 3f369c6f816d..0dcad6bb4b1f 100644 --- a/fs/cachefiles/main.c +++ b/fs/cachefiles/main.c @@ -64,9 +64,15 @@ static int __init cachefiles_init(void) goto error_object_jar; } + ret = cachefiles_init_sysfs(); + if (ret) + goto sysfs_err; + pr_info("Loaded\n"); return 0; +sysfs_err: + kmem_cache_destroy(cachefiles_object_jar); error_object_jar: misc_deregister(&cachefiles_dev); error_dev: @@ -85,6 +91,7 @@ static void __exit cachefiles_exit(void) { pr_info("Unloading\n"); + cachefiles_exit_sysfs(); kmem_cache_destroy(cachefiles_object_jar); misc_deregister(&cachefiles_dev); cachefiles_unregister_error_injection(); diff --git a/fs/cachefiles/sysfs.c b/fs/cachefiles/sysfs.c new file mode 100644 index 000000000000..adfb260df59c --- /dev/null +++ b/fs/cachefiles/sysfs.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <linux/sysfs.h> +#include <linux/kobject.h> + +#include "internal.h" + +enum { + attr_feature, +}; + +struct cachefiles_attr { + struct attribute attr; + short attr_id; +}; + +#define CACHEFILES_ATTR(_name, _mode, _id) \ +static struct cachefiles_attr cachefiles_attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .attr_id = attr_##_id, \ +} + +#define CACHEFILES_ATTR_FEATURE(_name) CACHEFILES_ATTR(_name, 0444, feature) + +#define ATTR_LIST(name) (&cachefiles_attr_##name.attr) + +/* supported features of cachefiles */ +#if IS_ENABLED(CONFIG_CACHEFILES_ONDEMAND) +CACHEFILES_ATTR_FEATURE(cachefiles_ondemand); +#endif + +static struct attribute *cachefiles_feat_attrs[] = { +#if IS_ENABLED(CONFIG_CACHEFILES_ONDEMAND) + ATTR_LIST(cachefiles_ondemand), + NULL, +#endif +}; + +ATTRIBUTE_GROUPS(cachefiles_feat); + +static ssize_t cachefiles_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct cachefiles_attr *a = container_of(attr, struct cachefiles_attr, attr); + + switch (a->attr_id) { + case attr_feature: + return sysfs_emit(buf, "supported\n"); + } + + return 0; +}; + +static const struct sysfs_ops cachefiles_attr_ops = { + .show = cachefiles_attr_show, +}; + +static const struct kobj_type cachefiles_ktype = { + .sysfs_ops = &cachefiles_attr_ops, +}; + +static struct kset cachefiles_root = { + .kobj = {.ktype = &cachefiles_ktype}, +}; + +static const struct kobj_type cachefiles_feat_ktype = { + .default_groups = cachefiles_feat_groups, + .sysfs_ops = &cachefiles_attr_ops, +}; + +static struct kobject cachefiles_feat = { + .kset = &cachefiles_root, +}; + +int __init cachefiles_init_sysfs(void) +{ + int ret; + + kobject_set_name(&cachefiles_root.kobj, "cachefiles"); + cachefiles_root.kobj.parent = fs_kobj; + ret = kset_register(&cachefiles_root); + if (ret) + goto root_err; + + ret = kobject_init_and_add(&cachefiles_feat, &cachefiles_feat_ktype, + NULL, "features"); + if (ret) + goto feat_err; + return ret; + +feat_err: + kobject_put(&cachefiles_feat); + kset_unregister(&cachefiles_root); +root_err: + return ret; +} + +void cachefiles_exit_sysfs(void) +{ + kobject_put(&cachefiles_feat); + kset_unregister(&cachefiles_root); +} -- 2.34.1