From: Sascha Hauer <s.hauer@pengutronix.de>
To: BAREBOX <barebox@lists.infradead.org>
Subject: [PATCH 3/4] fs: devfs: propagate cdev aliases to the partitions
Date: Mon, 31 Aug 2026 11:48:27 +0200 [thread overview]
Message-ID: <20260831-usbdisk-aliases-v1-3-0a2e40a35f3d@pengutronix.de> (raw)
In-Reply-To: <20260831-usbdisk-aliases-v1-0-0a2e40a35f3d@pengutronix.de>
USB mass storage registers a disk as "disk0" and additionally aliases it
to "usbdisk0" so it can be told apart from other block devices at a
glance. That is only half of the work though: the partitions are named
after their master cdev, so /dev/disk0.0 and /dev/disk0.data have no
counterpart under the alias and the whole point of having one is lost as
soon as you want to address a partition.
Derive the missing aliases in devfs_add_alias_node() by replacing the
master's name at the start of a partition name with the alias, so that
"disk0" -> "usbdisk0" also gives:
/dev/usbdisk0.0 -> disk0.0
/dev/usbdisk0.data -> disk0.0
The master alias and the partitions can appear in either order, so both
directions have to be covered. USB storage adds the alias only after the
partition table has been parsed, hence a new master alias propagates
down to the partitions that are already there. A repartitioning at
runtime on the other hand removes the partitions - which takes the
derived aliases with them - and creates new ones on a master that
already has aliases, hence a new partition inherits from its master.
The same applies to the "disk0.<label>" alias a partition receives from
register_one_partition() after it has been created.
Aliases created this way are marked as derived and are never used as a
source for further derivation. Without that an alias that contains a dot
itself - "diskuuid.<uuid>" from storage-by-alias does - would keep
deriving new aliases from the ones it just created and never terminate.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Assisted-by: Claude:claude-opus-5
---
fs/devfs-core.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
include/driver.h | 1 +
2 files changed, 110 insertions(+), 1 deletion(-)
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 8b023009a0..d647be9b9d 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -553,7 +553,26 @@ int devfs_create(struct cdev *new)
return 0;
}
-int devfs_add_alias_node(struct cdev *cdev, const char *name, struct device_node *np)
+/*
+ * An alias for a cdev is only half of the work when the cdev is partitioned:
+ * The partitions are named after their master cdev, so they have to become
+ * reachable under the alias as well. Registering "disk0" as "usbdisk0" thus
+ * results in:
+ *
+ * /dev/disk0
+ * /dev/disk0.0
+ * /dev/disk0.data -> disk0.0
+ * /dev/usbdisk0 -> disk0
+ * /dev/usbdisk0.0 -> disk0.0
+ * /dev/usbdisk0.data -> disk0.0
+ *
+ * The alias of the master and the partitions can show up in any order: USB
+ * mass storage registers the alias only once the whole device including its
+ * partitions is there, while repartitioning at runtime adds partitions to a
+ * master that already has aliases. Both directions are handled below.
+ */
+static int __devfs_add_alias(struct cdev *cdev, const char *name,
+ struct device_node *np, bool derived)
{
struct cdev *conflict;
struct cdev_alias *alias;
@@ -565,6 +584,7 @@ int devfs_add_alias_node(struct cdev *cdev, const char *name, struct device_node
alias = xzalloc(sizeof(*alias));
alias->name = xstrdup(name);
alias->device_node = np;
+ alias->derived = derived;
list_add_tail(&alias->list, &cdev->aliases);
cdev_symlink(cdev, name);
@@ -572,6 +592,89 @@ int devfs_add_alias_node(struct cdev *cdev, const char *name, struct device_node
return 0;
}
+/*
+ * Add an alias for @cdev derived from @name by replacing the leading @stem
+ * with @alias, i.e. stem "disk0", alias "usbdisk0" and name "disk0.data"
+ * yields the alias "usbdisk0.data".
+ */
+static void devfs_add_derived_alias(struct cdev *cdev, const char *stem,
+ const char *alias, const char *name)
+{
+ size_t stemlen = strlen(stem);
+ char *derived;
+
+ /* Only names of the form "<stem>.<partition>" can be translated */
+ if (strncmp(name, stem, stemlen) || name[stemlen] != '.')
+ return;
+
+ derived = xasprintf("%s%s", alias, name + stemlen);
+
+ /* A name clash only means we can't offer this alias, that's ok */
+ __devfs_add_alias(cdev, derived, NULL, true);
+
+ free(derived);
+}
+
+/*
+ * The partition @cdev has become known as @name. Make it known under the
+ * aliases of its master as well.
+ */
+static void devfs_inherit_master_aliases(struct cdev *cdev, const char *name)
+{
+ struct cdev *master = cdev->master;
+ struct cdev_alias *alias;
+
+ if (!master)
+ return;
+
+ cdev_for_each_alias(alias, master)
+ devfs_add_derived_alias(cdev, master->name, alias->name, name);
+}
+
+/*
+ * The master @cdev has become known as @alias. Make its partitions known
+ * under that alias as well, both by their name and by their own aliases.
+ */
+static void devfs_propagate_alias(struct cdev *cdev, const char *alias)
+{
+ struct cdev_alias *partalias;
+ struct cdev *partcdev;
+
+ for_each_cdev_partition(partcdev, cdev) {
+ devfs_add_derived_alias(partcdev, cdev->name, alias,
+ partcdev->name);
+
+ /*
+ * Appending to the list we are walking is fine here: the
+ * aliases added above and below are derived ones and those
+ * are skipped. Without that, an alias containing a dot
+ * itself (like "diskuuid.<uuid>") would endlessly derive
+ * new aliases from the ones it just created.
+ */
+ cdev_for_each_alias(partalias, partcdev) {
+ if (partalias->derived)
+ continue;
+
+ devfs_add_derived_alias(partcdev, cdev->name, alias,
+ partalias->name);
+ }
+ }
+}
+
+int devfs_add_alias_node(struct cdev *cdev, const char *name, struct device_node *np)
+{
+ int ret;
+
+ ret = __devfs_add_alias(cdev, name, np, false);
+ if (ret)
+ return ret;
+
+ devfs_inherit_master_aliases(cdev, name);
+ devfs_propagate_alias(cdev, name);
+
+ return 0;
+}
+
int devfs_add_alias(struct cdev *cdev, const char *name)
{
return devfs_add_alias_node(cdev, name, NULL);
@@ -735,6 +838,9 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev,
return (void *)mtd;
list_add_tail(&mtd->cdev.partition_entry, &cdev->partitions);
+
+ devfs_inherit_master_aliases(&mtd->cdev, mtd->cdev.name);
+
return &mtd->cdev;
}
@@ -757,6 +863,8 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev,
cdev_create_default_automount(new);
+ devfs_inherit_master_aliases(new, new->name);
+
return new;
}
diff --git a/include/driver.h b/include/driver.h
index b0602e6f16..c26a89c5ce 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -458,6 +458,7 @@ struct cdev_alias {
char *name;
struct device_node *device_node;
struct list_head list;
+ bool derived; /* automatically derived from an alias of the master cdev */
};
static inline struct device_node *cdev_of_node(const struct cdev *cdev)
--
2.47.3
next prev parent reply other threads:[~2026-08-31 9:49 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 9:48 [PATCH 0/4] extend cdev alias support Sascha Hauer
2026-08-31 9:48 ` [PATCH 1/4] fs: devfs: remove aliases from the list when freeing them Sascha Hauer
2026-08-31 9:48 ` [PATCH 2/4] fs: remove the default automount when a cdev is removed Sascha Hauer
2026-08-31 9:48 ` Sascha Hauer [this message]
2026-08-31 9:48 ` [PATCH 4/4] fs: devfs: make the default automount reachable under cdev aliases Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260831-usbdisk-aliases-v1-3-0a2e40a35f3d@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox