From: Rabin Vincent <rab...@axis.com> There currently appears to be no way for userspace to find out the underlying volume number for a mounted ubifs file system, since ubifs uses anonymous block devices. The volume name is present in /proc/mounts but UBI volumes can be renamed after the volume has been mounted.
To remedy this, provide a directory in /sys/fs/ubifs named after the underlying anonymous block device's number (obtainable by userspace via stat(2)) and provide a link named "ubi" to the underlying UBI volume. # mount | head -1 ubi0:rootfs on / type ubifs (rw,relatime) # ubirename /dev/ubi0 rootfs foo # mount | head -1 ubi0:rootfs on / type ubifs (rw,relatime) # stat / File: / Size: 1520 Blocks: 0 IO Block: 4096 directory Device: dh/13d Inode: 1 Links: 18 ... # ls -l /sys/fs/ubifs/ drwxr-xr-x 2 root root 0 May 23 09:57 0:13 drwxr-xr-x 2 root root 0 May 23 09:57 0:17 # ls -l /sys/fs/ubifs/0\:13/ lrwxrwxrwx 1 root root 0 May 23 11:45 ubi -> ../../../devices/virtual/ubi/ubi0/ubi0_10 Signed-off-by: Rabin Vincent <rab...@axis.com> --- Documentation/ABI/testing/sysfs-fs-ubifs | 6 +++ drivers/mtd/ubi/kapi.c | 12 ++++++ fs/ubifs/Makefile | 2 +- fs/ubifs/super.c | 16 +++++++- fs/ubifs/sysfs.c | 66 ++++++++++++++++++++++++++++++++ fs/ubifs/sysfs.h | 11 ++++++ fs/ubifs/ubifs.h | 7 ++++ include/linux/mtd/ubi.h | 3 ++ 8 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-fs-ubifs create mode 100644 fs/ubifs/sysfs.c create mode 100644 fs/ubifs/sysfs.h diff --git a/Documentation/ABI/testing/sysfs-fs-ubifs b/Documentation/ABI/testing/sysfs-fs-ubifs new file mode 100644 index 0000000..1735859 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-fs-ubifs @@ -0,0 +1,6 @@ +What: /sys/fs/ubifs/<disk>/ubi +Date: May 2017 +Description: + This symbolic link points to the file system's underlying UBI + volume. The <disk> is the major:minor numbers of the anonymous + block device backing the file system. diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d4b2e87..aa766d9 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -107,6 +107,18 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc, EXPORT_SYMBOL_GPL(ubi_get_volume_info); /** + * ubi_volume_kobject - get kobject for a UBI volume. + * @desc: volume descriptor + * + * Retrieves a pointer to the struct kobject underlying the UBI volume. + * The caller must hold a reference to the UBI volume. + */ +struct kobject *ubi_volume_kobj(struct ubi_volume_desc *desc) +{ + return &desc->vol->dev.kobj; +} + +/** * ubi_open_volume - open UBI volume. * @ubi_num: UBI device number * @vol_id: volume ID diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile index 6f3251c..7bf4689 100644 --- a/fs/ubifs/Makefile +++ b/fs/ubifs/Makefile @@ -4,5 +4,5 @@ ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o -ubifs-y += misc.o +ubifs-y += sysfs.o misc.o ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index cf4cc99..fdcfefe 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1164,6 +1164,10 @@ static int mount_ubifs(struct ubifs_info *c) if (err) return err; + err = ubifs_sysfs_register(c); + if (err) + goto out_debugging; + err = check_volume_empty(c); if (err) goto out_free; @@ -1496,6 +1500,8 @@ static int mount_ubifs(struct ubifs_info *c) vfree(c->ileb_buf); vfree(c->sbuf); kfree(c->bottom_up_buf); + ubifs_sysfs_unregister(c); +out_debugging: ubifs_debugging_exit(c); return err; } @@ -1536,6 +1542,7 @@ static void ubifs_umount(struct ubifs_info *c) vfree(c->sbuf); kfree(c->bottom_up_buf); ubifs_debugging_exit(c); + ubifs_sysfs_unregister(c); } /** @@ -2271,14 +2278,20 @@ static int __init ubifs_init(void) if (err) goto out_compr; + err = ubifs_sysfs_init(); + if (err) + goto out_dbg; + err = register_filesystem(&ubifs_fs_type); if (err) { pr_err("UBIFS error (pid %d): cannot register file system, error %d", current->pid, err); - goto out_dbg; + goto out_sysfs; } return 0; +out_sysfs: + ubifs_sysfs_exit(); out_dbg: dbg_debugfs_exit(); out_compr: @@ -2308,6 +2321,7 @@ static void __exit ubifs_exit(void) rcu_barrier(); kmem_cache_destroy(ubifs_inode_slab); unregister_filesystem(&ubifs_fs_type); + ubifs_sysfs_exit(); } module_exit(ubifs_exit); diff --git a/fs/ubifs/sysfs.c b/fs/ubifs/sysfs.c new file mode 100644 index 0000000..8f2cba1 --- /dev/null +++ b/fs/ubifs/sysfs.c @@ -0,0 +1,66 @@ +#include <linux/fs.h> + +#include "ubifs.h" + +static struct kset *ubifs_kset; + +static void ubifs_sb_release(struct kobject *kobj) +{ + struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj); + + complete(&c->kobj_unregister); +} + +static struct kobj_type ubifs_sb_ktype = { + .sysfs_ops = &kobj_sysfs_ops, + .release = ubifs_sb_release, +}; + +int ubifs_sysfs_register(struct ubifs_info *c) +{ + dev_t devt = c->vfs_sb->s_dev; + int ret; + + c->kobj.kset = ubifs_kset; + init_completion(&c->kobj_unregister); + + ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL, + "%u:%u", MAJOR(devt), MINOR(devt)); + if (ret) + goto out_put; + + ret = sysfs_create_link(&c->kobj, ubi_volume_kobj(c->ubi), "ubi"); + if (ret) + goto out_del; + + return 0; + +out_del: + kobject_del(&c->kobj); +out_put: + kobject_put(&c->kobj); + wait_for_completion(&c->kobj_unregister); + return ret; +} + +void ubifs_sysfs_unregister(struct ubifs_info *c) +{ + sysfs_remove_link(&c->kobj, "ubi"); + kobject_del(&c->kobj); + kobject_put(&c->kobj); + wait_for_completion(&c->kobj_unregister); +} + +int __init ubifs_sysfs_init(void) +{ + ubifs_kset = kset_create_and_add("ubifs", NULL, fs_kobj); + if (!ubifs_kset) + return -ENOMEM; + + return 0; +} + +void ubifs_sysfs_exit(void) +{ + kset_unregister(ubifs_kset); +} diff --git a/fs/ubifs/sysfs.h b/fs/ubifs/sysfs.h new file mode 100644 index 0000000..4b7e70b --- /dev/null +++ b/fs/ubifs/sysfs.h @@ -0,0 +1,11 @@ +#ifndef __UBIFS_SYSFS_H__ +#define __UBIFS_SYSFS_H__ + +struct ubifs_info; + +int ubifs_sysfs_init(void); +void ubifs_sysfs_exit(void); +int ubifs_sysfs_register(struct ubifs_info *c); +void ubifs_sysfs_unregister(struct ubifs_info *c); + +#endif diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 298b4d8..3a3154f 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -43,7 +43,10 @@ #else #include <linux/fscrypt_notsupp.h> #endif +#include <linux/sysfs.h> +#include <linux/completion.h> #include <linux/random.h> +#include "sysfs.h" #include "ubifs-media.h" /* Version of this UBIFS implementation */ @@ -1216,6 +1219,8 @@ struct ubifs_debug_info; * @mount_opts: UBIFS-specific mount options * * @dbg: debugging-related information + * @kobj: kobject for /sys/fs/ubifs/ + * @kobj_unregister: completion to unregister sysfs kobject */ struct ubifs_info { struct super_block *vfs_sb; @@ -1446,6 +1451,8 @@ struct ubifs_info { struct ubifs_mount_opts mount_opts; struct ubifs_debug_info *dbg; + struct kobject kobj; + struct completion kobj_unregister; }; extern struct list_head ubifs_infos; diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h index 1e271cb..d35e84f 100644 --- a/include/linux/mtd/ubi.h +++ b/include/linux/mtd/ubi.h @@ -26,6 +26,8 @@ #include <linux/scatterlist.h> #include <mtd/ubi-user.h> +struct kobject; + /* All voumes/LEBs */ #define UBI_ALL -1 @@ -241,6 +243,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode); struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, int mode); struct ubi_volume_desc *ubi_open_volume_path(const char *pathname, int mode); +struct kobject *ubi_volume_kobj(struct ubi_volume_desc *desc); int ubi_register_volume_notifier(struct notifier_block *nb, int ignore_existing); -- 2.1.4