[PATCH] ubifs: allow userspace to map mounts to volumes
From: Rabin Vincent
Date: Wed May 24 2017 - 05:22:01 EST
From: Rabin Vincent <rabinv@xxxxxxxx>
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 <rabinv@xxxxxxxx>
---
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