* [PATCH 00/10] fs: Use device special nodes for devfs
@ 2025-11-27 9:19 Sascha Hauer
2025-11-27 9:19 ` [PATCH 01/10] fs: implement mknod Sascha Hauer
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
Until now we have a devfs which is a filesystem of its own. This
comes with a few limitations:
- we cannot create directories under /dev/
- Links are implemented in the devfs filesystem. They do not show
up as regular links
This series overcomes these limitations by implementing device special
nodes. These nodes are limited to ramfs, so we cannot mount arbitrary
filesystems and use the device special files found on them. Nevertheless
we can create and use device special files on ramfs which is enough
to drop the devfs filesystem implementation and just use ramfs on /dev/.
This will in future allow us to create /dev/disk/by-* structures under
/dev/.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sascha Hauer (10):
fs: implement mknod
commands: add mknod command
fs: ramfs: add device file support
cdev: add cdev_size() helper
fs: fix st_size for device files
fs: retire devfs as filesystem
fs: include cdevname in struct stat
fs: stat_print: get cdevname from stat
fs: replace cdev links with aliases
ls: use ~0 for FILE_SIZE_STREAM
commands/Kconfig | 4 +
commands/Makefile | 1 +
commands/devinfo.c | 7 +-
commands/ls.c | 8 +-
commands/mknod.c | 43 +++++++++++
common/partitions.c | 2 +-
common/startup.c | 2 +-
drivers/block/dm/dm-core.c | 1 -
fs/devfs-core.c | 179 ++++++++++++++++++++++++--------------------
fs/devfs.c | 180 +++------------------------------------------
fs/fs.c | 75 +++++++++++++------
fs/ramfs.c | 18 +++++
include/block.h | 2 -
include/driver.h | 10 +--
include/fcntl.h | 6 ++
include/linux/fs.h | 13 ++++
include/linux/stat.h | 1 +
17 files changed, 266 insertions(+), 286 deletions(-)
---
base-commit: f018a6e4606ef31c6975af6b960aa7824f79df73
change-id: 20251127-devfs-c138cff5482a
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 01/10] fs: implement mknod
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 02/10] commands: add mknod command Sascha Hauer
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
This implements mknod for the barebox VFS. Use the cdevname for
connecting a device special node with a cdev. In Linux this is done with
major/minor numbers which shouldn't be necessary for barebox as we do
not intend to mount filesystems which contain device special nodes, but
instead create them in ramfs. If a mounted filesystem contains special
nodes then these won't work with barebox.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/devfs.c | 13 +++++++++++++
fs/fs.c | 35 +++++++++++++++++++++++++++++++++++
include/fcntl.h | 6 ++++++
include/linux/fs.h | 13 +++++++++++++
4 files changed, 67 insertions(+)
diff --git a/fs/devfs.c b/fs/devfs.c
index 15c7a63d3949a5fa7c5ec15f58bc9f4c53b7852b..be3272be49e66eb843823b3ff664a1565f326790 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -103,6 +103,12 @@ static int devfs_open(struct inode *inode, struct file *f)
struct devfs_inode *node = container_of(inode, struct devfs_inode, inode);
struct cdev *cdev = node->cdev;
+ if (inode->cdevname) {
+ cdev = cdev_by_name(inode->cdevname);
+ if (!cdev)
+ return -ENOENT;
+ }
+
f->f_size = cdev->flags & DEVFS_IS_CHARACTER_DEV ?
FILE_SIZE_STREAM : cdev->size;
f->private_data = cdev;
@@ -188,6 +194,13 @@ static const struct file_operations devfs_file_operations = {
.memmap = devfs_memmap,
};
+void init_special_inode(struct inode *inode, umode_t mode, const char *cdevname)
+{
+ inode->i_mode = mode;
+ inode->i_fop = &devfs_file_operations;
+ inode->cdevname = strdup(cdevname);
+}
+
static int devfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
{
struct devfs_inode *dinode;
diff --git a/fs/fs.c b/fs/fs.c
index 528299e039d2d73b76c363b7ece32b6255d925f1..bfcfadff7fa76de17c68a0dca4843aa02cb62b6d 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -826,6 +826,8 @@ static int dentry_delete_subtree(struct super_block *sb, struct dentry *parent)
static void destroy_inode(struct inode *inode)
{
+ free(inode->cdevname);
+
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
@@ -2745,6 +2747,39 @@ int openat(int dirfd, const char *pathname, int flags)
}
EXPORT_SYMBOL(openat);
+static int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+ const char *cdevname)
+{
+ int error;
+
+ if (!dir->i_op->mknod)
+ return -EPERM;
+
+ error = dir->i_op->mknod(dir, dentry, mode, cdevname);
+
+ return error;
+}
+
+int mknodat(int dirfd, const char *pathname, mode_t mode, const char *devname)
+{
+ struct dentry *dentry;
+ struct path path;
+ int error;
+
+ dentry = filename_create(dirfd, getname(pathname), &path, 0);
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
+ goto out;
+ }
+
+ error = vfs_mknod(path.dentry->d_inode, dentry, mode, devname);
+
+ dput(dentry);
+ path_put(&path);
+out:
+ return errno_set(error);
+}
+
int unlinkat(int dirfd, const char *pathname, int flags)
{
int ret;
diff --git a/include/fcntl.h b/include/fcntl.h
index db7926ee25fbe14607063d420697964801cd8321..57c01002cc9290bfae53f3b5be5615eda874c720 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -46,6 +46,8 @@ static inline int openat(int dirfd, const char *pathname, int flags, ...)
}
#endif
+int mknodat(int dirfd, const char *pathname, mode_t mode, const char *devname);
+
static inline int open(const char *pathname, int flags, ...)
{
return openat(AT_FDCWD, pathname, flags);
@@ -56,4 +58,8 @@ static inline int creat(const char *pathname, mode_t mode)
return open(pathname, O_CREAT | O_WRONLY | O_TRUNC);
}
+static inline int mknod(const char *pathname, mode_t mode, const char *devname)
+{
+ return mknodat(AT_FDCWD, pathname, mode, devname);
+}
#endif /* __FCNTL_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ed4332c79d496b18b37b120b6008e1e474316e76..f6b8f6a8e08b7e56716005453d6f9c4488ba853f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -149,6 +149,8 @@ struct inode {
char *i_link;
+ char *cdevname;
+
void *i_private; /* fs or device private pointer */
};
@@ -429,6 +431,16 @@ void ihold(struct inode *inode);
void inc_nlink(struct inode *inode);
void clear_nlink(struct inode *inode);
void set_nlink(struct inode *inode, unsigned int nlink);
+#ifdef CONFIG_FS_DEVFS
+void init_special_inode(struct inode *inode, umode_t mode, const char *cdevname);
+#else
+static inline void init_special_inode(struct inode *inode, umode_t mode,
+ const char *cdevname)
+{
+}
+#endif
+
+struct cdev;
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
@@ -436,6 +448,7 @@ struct inode_operations {
const char *(*get_link) (struct dentry *dentry, struct inode *inode);
int (*create) (struct inode *,struct dentry *, umode_t);
+ int (*mknod) (struct inode *,struct dentry *, umode_t, const char *name);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct inode *,struct dentry *,const char *);
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 02/10] commands: add mknod command
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
2025-11-27 9:19 ` [PATCH 01/10] fs: implement mknod Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 03/10] fs: ramfs: add device file support Sascha Hauer
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
Add a mknod command. This is intended for testing/debugging purposes as
normally device special nodes are created automatically in devfs.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/Kconfig | 4 ++++
commands/Makefile | 1 +
commands/mknod.c | 43 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 48 insertions(+)
diff --git a/commands/Kconfig b/commands/Kconfig
index c7c03a65477b4f083c256dc55053aab8c8ad2741..6b8e19533dc07b54c41326b84adabb1553bc415d 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1144,6 +1144,10 @@ config CMD_MKDIR
Options:
-p make parent directories as needed
+config CMD_MKNOD
+ tristate
+ prompt "mknod"
+
config CMD_PWD
tristate
default y
diff --git a/commands/Makefile b/commands/Makefile
index 8fffac8fd4428d275f86c5ad9898fed96c5b18ac..356957cab56bd97f80dbac67a3e17c333d4be45c 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_CMD_CD) += cd.o
obj-$(CONFIG_CMD_PWD) += pwd.o
obj-$(CONFIG_CMD_MKDIR) += mkdir.o
obj-$(CONFIG_CMD_RMDIR) += rmdir.o
+obj-$(CONFIG_CMD_MKNOD) += mknod.o
obj-$(CONFIG_CMD_CP) += cp.o
obj-$(CONFIG_CMD_RM) += rm.o
obj-$(CONFIG_CMD_CAT) += cat.o
diff --git a/commands/mknod.c b/commands/mknod.c
new file mode 100644
index 0000000000000000000000000000000000000000..e99078995f995f54ba1d06587fc3d27e09f79e3b
--- /dev/null
+++ b/commands/mknod.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <command.h>
+#include <fs.h>
+
+static int do_mknod(int argc, char *argv[])
+{
+ const char *filename, *cdevname;
+ umode_t mode;
+
+ if (argc < 4)
+ return COMMAND_ERROR_USAGE;
+
+ filename = argv[1];
+ if (!strcmp(argv[2], "b"))
+ mode = S_IFBLK;
+ else if (!strcmp(argv[2], "c"))
+ mode = S_IFCHR;
+ else
+ return COMMAND_ERROR_USAGE;
+
+ cdevname = argv[3];
+
+ return mknod(filename, mode, cdevname);
+}
+
+BAREBOX_CMD_HELP_START(mknod)
+BAREBOX_CMD_HELP_TEXT("make a device special node.")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("usage: mknod <name> c|b <cdevname>")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Create a device special node named <name> directing")
+BAREBOX_CMD_HELP_TEXT("to cdev <cdevname>. This can either be a block (b) or")
+BAREBOX_CMD_HELP_TEXT("character (c) device.")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(mknod)
+ .cmd = do_mknod,
+ BAREBOX_CMD_DESC("make device nodes")
+ BAREBOX_CMD_OPTS("NAME TYPE CDEVNAME")
+ BAREBOX_CMD_GROUP(CMD_GRP_FILE)
+ BAREBOX_CMD_HELP(cmd_mknod_help)
+BAREBOX_CMD_END
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 03/10] fs: ramfs: add device file support
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
2025-11-27 9:19 ` [PATCH 01/10] fs: implement mknod Sascha Hauer
2025-11-27 9:19 ` [PATCH 02/10] commands: add mknod command Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 04/10] cdev: add cdev_size() helper Sascha Hauer
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
Implement the mknod hook in ramfs for creating device special files.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/ramfs.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/fs/ramfs.c b/fs/ramfs.c
index 1caace0183a58e8a07001eb6ce9df8ea1895ac0b..d86bf6144e8485269c589ba0024377f9852a8eaa 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -89,6 +89,9 @@ static struct inode *ramfs_get_inode(struct super_block *sb, const struct inode
case S_IFLNK:
inode->i_op = &ramfs_symlink_inode_operations;
break;
+ case S_IFBLK:
+ case S_IFCHR:
+ break;
}
return inode;
@@ -149,6 +152,20 @@ static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode)
return ramfs_mknod(dir, dentry, mode | S_IFREG);
}
+static int __ramfs_mknod(struct inode *dir,struct dentry *dentry, umode_t mode,
+ const char *cdevname)
+{
+ int ret;
+
+ ret = ramfs_mknod(dir, dentry, mode);
+ if (ret)
+ return ret;
+
+ init_special_inode(dentry->d_inode, mode, cdevname);
+
+ return 0;
+}
+
static int ramfs_symlink(struct inode *dir, struct dentry *dentry,
const char *symname)
{
@@ -196,6 +213,7 @@ static const struct inode_operations ramfs_dir_inode_operations =
.unlink = simple_unlink,
.create = ramfs_create,
.tmpfile = ramfs_tmpfile,
+ .mknod = __ramfs_mknod,
};
static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node,
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 04/10] cdev: add cdev_size() helper
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (2 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 03/10] fs: ramfs: add device file support Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 05/10] fs: fix st_size for device files Sascha Hauer
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
We'll need the size of a cdev later, add a helper for retrieving the
size.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/devfs-core.c | 6 ++++++
fs/devfs.c | 3 +--
include/driver.h | 1 +
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 92e7c5823ed0d3a4c54cc7b2b1c9bf32ac535907..7841ac71540675c27ec3a695f0b7333cd3b02e0c 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -435,6 +435,12 @@ int cdev_truncate(struct cdev *cdev, size_t size)
return -EPERM;
}
+loff_t cdev_size(struct cdev *cdev)
+{
+ return cdev->flags & DEVFS_IS_CHARACTER_DEV ?
+ FILE_SIZE_STREAM : cdev->size;
+}
+
static struct cdev *cdev_alloc(const char *name)
{
struct cdev *new;
diff --git a/fs/devfs.c b/fs/devfs.c
index be3272be49e66eb843823b3ff664a1565f326790..a48c6452697b47cbd3ffc6f993230e7993e565fe 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -109,8 +109,7 @@ static int devfs_open(struct inode *inode, struct file *f)
return -ENOENT;
}
- f->f_size = cdev->flags & DEVFS_IS_CHARACTER_DEV ?
- FILE_SIZE_STREAM : cdev->size;
+ f->f_size = cdev_size(cdev);
f->private_data = cdev;
return cdev_open(cdev, f->f_flags);
diff --git a/include/driver.h b/include/driver.h
index c130a3cd63fd5e6dc365a33c765a22dc4e2ca90a..7d93c07c402421bd449adfda3aebaddddf5d3266 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -524,6 +524,7 @@ int cdev_protect(struct cdev*, size_t count, loff_t offset, int prot);
int cdev_discard_range(struct cdev*, loff_t count, loff_t offset);
int cdev_memmap(struct cdev*, void **map, int flags);
int cdev_truncate(struct cdev*, size_t size);
+loff_t cdev_size(struct cdev *cdev);
loff_t cdev_unallocated_space(struct cdev *cdev);
static inline bool cdev_is_partition(const struct cdev *cdev)
{
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 05/10] fs: fix st_size for device files
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (3 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 04/10] cdev: add cdev_size() helper Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 06/10] fs: retire devfs as filesystem Sascha Hauer
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
In Linux device special files have zero size, but in barebox the
device files traditionally have the size of the underlying device.
Initialize struct stat::s_size with the cdev size.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/fs.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/fs.c b/fs/fs.c
index bfcfadff7fa76de17c68a0dca4843aa02cb62b6d..b96393e2301e2d8a622e319e0033953399b4e989 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1100,11 +1100,23 @@ EXPORT_SYMBOL(readdir);
static void stat_inode(struct inode *inode, struct stat *s)
{
+ if (inode->cdevname) {
+ struct cdev *cdev;
+
+ cdev = cdev_by_name(inode->cdevname);
+ if (cdev) {
+ s->st_size = cdev_size(cdev);
+ } else {
+ s->st_size = 0;
+ }
+ } else {
+ s->st_size = inode->i_size;
+ }
+
s->st_ino = inode->i_ino;
s->st_mode = inode->i_mode;
s->st_uid = inode->i_uid;
s->st_gid = inode->i_gid;
- s->st_size = inode->i_size;
}
int fstat(int fd, struct stat *s)
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 06/10] fs: retire devfs as filesystem
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (4 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 05/10] fs: fix st_size for device files Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 07/10] fs: include cdevname in struct stat Sascha Hauer
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
Switch over to device special files for implementing devfs. With this we
can drop the current devfs implementation as a filesystem driver.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/startup.c | 2 +-
fs/devfs-core.c | 35 +++++++++++
fs/devfs.c | 174 +------------------------------------------------------
include/driver.h | 1 +
4 files changed, 39 insertions(+), 173 deletions(-)
diff --git a/common/startup.c b/common/startup.c
index dfea8394fdee67f53cb608aea882d20151cc9c61..ba3bb79c861aaa9268121ee6868399fcce8ec36c 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -60,7 +60,7 @@ static int mount_root(void)
mkdir("/dev", 0);
mkdir("/tmp", 0);
mkdir("/mnt", 0);
- mount("none", "devfs", "/dev", NULL);
+ devfs_init();
if (IS_ENABLED(CONFIG_FS_EFIVARFS) && efi_is_payload()) {
mkdir("/efivars", 0);
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 7841ac71540675c27ec3a695f0b7333cd3b02e0c..c4ff5fe5718ea2c0236fdbf124e56a13e17702d1 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -458,6 +458,39 @@ static void cdev_free(struct cdev *cdev)
free(cdev);
}
+static bool devfs_initialized;
+
+static void devfs_mknod(struct cdev *cdev)
+{
+ char *path;
+ int ret;
+
+ if (!devfs_initialized)
+ return;
+
+ path = xasprintf("/dev/%s", cdev->name);
+
+ if (cdev->link)
+ ret = symlink(cdev->link->name, path);
+ else
+ ret = mknod(path, S_IFCHR | 0600, cdev->name);
+
+ free(path);
+
+ if (ret)
+ pr_err("Failed to create /dev/%s: %pe\n", cdev->name, ERR_PTR(ret));
+}
+
+void devfs_init(void)
+{
+ struct cdev *cdev;
+
+ devfs_initialized = true;
+
+ for_each_cdev(cdev)
+ devfs_mknod(cdev);
+}
+
int devfs_create(struct cdev *new)
{
struct cdev *cdev;
@@ -479,6 +512,8 @@ int devfs_create(struct cdev *new)
if (new->link)
list_add_tail(&new->link_entry, &new->link->links);
+ devfs_mknod(new);
+
return 0;
}
diff --git a/fs/devfs.c b/fs/devfs.c
index a48c6452697b47cbd3ffc6f993230e7993e565fe..061fbf5d2ffe11671c13ee5bd2cc315c378bb86f 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -29,6 +29,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/mtd-abi.h>
#include <block.h>
+#include <stringlist.h>
struct devfs_inode {
struct inode inode;
@@ -143,41 +144,6 @@ static int devfs_truncate(struct file *f, loff_t size)
return cdev_truncate(cdev, size);
}
-static struct inode *devfs_alloc_inode(struct super_block *sb)
-{
- struct devfs_inode *node;
-
- node = xzalloc(sizeof(*node));
- if (!node)
- return NULL;
-
- return &node->inode;
-}
-
-static void devfs_destroy_inode(struct inode *inode)
-{
- struct devfs_inode *node = container_of(inode, struct devfs_inode, inode);
-
- free(node);
-}
-
-static int devfs_iterate(struct file *file, struct dir_context *ctx)
-{
- struct cdev *cdev;
-
- dir_emit_dots(file, ctx);
-
- for_each_cdev(cdev) {
- dir_emit(ctx, cdev->name, strlen(cdev->name),
- 1 /* FIXME */, DT_REG);
- }
-
- return 0;
-}
-
-static const struct inode_operations devfs_file_inode_operations;
-static const struct file_operations devfs_dir_operations;
-static const struct inode_operations devfs_dir_inode_operations;
static const struct file_operations devfs_file_operations = {
.open = devfs_open,
.release = devfs_close,
@@ -197,141 +163,5 @@ void init_special_inode(struct inode *inode, umode_t mode, const char *cdevname)
{
inode->i_mode = mode;
inode->i_fop = &devfs_file_operations;
- inode->cdevname = strdup(cdevname);
-}
-
-static int devfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
-{
- struct devfs_inode *dinode;
- struct inode *inode;
- struct cdev *cdev;
-
- cdev = cdev_by_name(dentry->name);
- if (!cdev)
- return -ENOENT;
-
- inode = d_inode(dentry);
- if (!inode)
- return 0;
-
- dinode = container_of(inode, struct devfs_inode, inode);
-
- if (dinode->cdev != cdev)
- return 0;
-
- return 1;
+ inode->cdevname = xstrdup(cdevname);
}
-
-static const struct dentry_operations devfs_dentry_operations = {
- .d_revalidate = devfs_lookup_revalidate,
-};
-
-static struct inode *devfs_get_inode(struct super_block *sb, const struct inode *dir,
- umode_t mode)
-{
- struct inode *inode = new_inode(sb);
-
- if (!inode)
- return NULL;
-
- inode->i_ino = get_next_ino();
- inode->i_mode = mode;
-
- switch (mode & S_IFMT) {
- default:
- return NULL;
- case S_IFCHR:
- case S_IFBLK:
- inode->i_op = &devfs_file_inode_operations;
- inode->i_fop = &devfs_file_operations;
- break;
- case S_IFDIR:
- inode->i_op = &devfs_dir_inode_operations;
- inode->i_fop = &devfs_dir_operations;
- inc_nlink(inode);
- break;
- }
-
- return inode;
-}
-
-static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry,
- unsigned int flags)
-{
- struct devfs_inode *dinode;
- struct inode *inode;
- struct cdev *cdev;
- umode_t mode;
-
- cdev = cdev_by_name(dentry->name);
- if (!cdev)
- return ERR_PTR(-ENOENT);
-
- mode = cdev_get_block_device(cdev) ? S_IFBLK : S_IFCHR;
-
- inode = devfs_get_inode(dir->i_sb, dir, mode);
- if (!inode)
- return ERR_PTR(-ENOMEM);
-
- if (cdev->ops->write)
- inode->i_mode |= S_IWUSR;
- if (cdev->ops->read)
- inode->i_mode |= S_IRUSR;
-
- dinode = container_of(inode, struct devfs_inode, inode);
-
- inode->i_size = cdev->size;
- dinode->cdev = cdev;
-
- d_add(dentry, inode);
-
- return NULL;
-}
-
-static const struct file_operations devfs_dir_operations = {
- .iterate = devfs_iterate,
-};
-
-static const struct inode_operations devfs_dir_inode_operations =
-{
- .lookup = devfs_lookup,
-};
-
-static const struct super_operations devfs_ops = {
- .alloc_inode = devfs_alloc_inode,
- .destroy_inode = devfs_destroy_inode,
-};
-
-static int devfs_probe(struct device *dev)
-{
- struct inode *inode;
- struct fs_device *fsdev = dev_to_fs_device(dev);
- struct super_block *sb = &fsdev->sb;
-
- sb->s_op = &devfs_ops;
- sb->s_d_op = &devfs_dentry_operations;
-
- inode = devfs_get_inode(sb, NULL, S_IFDIR);
- sb->s_root = d_make_root(inode);
-
- return 0;
-}
-
-static void devfs_delete(struct device *dev)
-{
-}
-
-static struct fs_driver devfs_driver = {
- .drv = {
- .probe = devfs_probe,
- .remove = devfs_delete,
- .name = "devfs",
- }
-};
-
-static int devfs_init(void)
-{
- return register_fs_driver(&devfs_driver);
-}
-
-coredevice_initcall(devfs_init);
diff --git a/include/driver.h b/include/driver.h
index 7d93c07c402421bd449adfda3aebaddddf5d3266..5a67d20ccff3fca339e7b40c32ecfbc244f358f5 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -459,6 +459,7 @@ static inline const char *cdev_name(struct cdev *cdev)
return cdev ? cdev->name : NULL;
}
+void devfs_init(void);
int devfs_create(struct cdev *);
int devfs_create_link(struct cdev *, const char *name);
int devfs_remove(struct cdev *);
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 07/10] fs: include cdevname in struct stat
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (5 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 06/10] fs: retire devfs as filesystem Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 08/10] fs: stat_print: get cdevname from stat Sascha Hauer
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
In Linux struct stat contains the major/minor numbers of the underlying
device, consequently we put the cdev name into struct stat.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/fs.c | 1 +
include/linux/stat.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/fs/fs.c b/fs/fs.c
index b96393e2301e2d8a622e319e0033953399b4e989..41cdaf5070798388aa989d16e7bf2ace081b4a2b 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1117,6 +1117,7 @@ static void stat_inode(struct inode *inode, struct stat *s)
s->st_mode = inode->i_mode;
s->st_uid = inode->i_uid;
s->st_gid = inode->i_gid;
+ s->st_cdevname = inode->cdevname;
}
int fstat(int fd, struct stat *s)
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 6ee05b52873f47e5d17a4387829187512be29ea8..84b6484a1f2149d1f2d770f0f11bf0ae0ef63744 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -55,6 +55,7 @@ struct stat {
unsigned short st_mode;
unsigned short st_uid;
unsigned short st_gid;
+ const char *st_cdevname; /* barebox specific */
loff_t st_size;
};
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 08/10] fs: stat_print: get cdevname from stat
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (6 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 07/10] fs: include cdevname in struct stat Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 09/10] fs: replace cdev links with aliases Sascha Hauer
2025-11-27 9:19 ` [PATCH 10/10] ls: use ~0 for FILE_SIZE_STREAM Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
In stat_print() we have to take the filename component of the input path
and retrieve the cdev from that name. Now that we have the cdevname in
struct stat we can simplify this.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/fs.c | 25 ++++---------------------
1 file changed, 4 insertions(+), 21 deletions(-)
diff --git a/fs/fs.c b/fs/fs.c
index 41cdaf5070798388aa989d16e7bf2ace081b4a2b..4146ecbf3c01229cac89e5acdbc42d66ffc97dfc 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -137,7 +137,6 @@ void stat_print(int dirfd, const char *filename, const struct stat *st)
struct fs_device *fdev;
struct cdev *cdev = NULL;
const char *type = NULL, *typeprefix = "";
- bool is_cdev_link = false;
char modestr[11];
mkmodestr(st->st_mode, modestr);
@@ -152,23 +151,10 @@ void stat_print(int dirfd, const char *filename, const struct stat *st)
case S_IFREG: type = "regular file"; break;
}
- if (st->st_mode & S_IFCHR) {
- char *path;
-
- path = canonicalize_path(dirfd, filename);
- if (path) {
- const char *devicefile = devpath_to_name(path);
- struct cdev *lcdev;
-
- lcdev = lcdev_by_name(devicefile);
- cdev = cdev_readlink(lcdev);
- if (cdev != lcdev)
- is_cdev_link = true;
- if (cdev)
- bdev = cdev_get_block_device(cdev);
-
- free(path);
- }
+ if ((st->st_mode & S_IFCHR) && st->st_cdevname) {
+ cdev = cdev_by_name(st->st_cdevname);
+ if (cdev)
+ bdev = cdev_get_block_device(cdev);
}
printf(" File: %s", filename);
@@ -182,9 +168,6 @@ void stat_print(int dirfd, const char *filename, const struct stat *st)
printf(" -> <readlink error %pe>", ERR_PTR(ret));
else
printf(" -> %s", realname);
- } else if (is_cdev_link) {
- printf(" ~> %s", cdev->name);
- typeprefix = "cdev link to ";
}
printf("\nSize: ");
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 09/10] fs: replace cdev links with aliases
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (7 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 08/10] fs: stat_print: get cdevname from stat Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
2025-11-27 9:19 ` [PATCH 10/10] ls: use ~0 for FILE_SIZE_STREAM Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/devinfo.c | 7 ++-
common/partitions.c | 2 +-
drivers/block/dm/dm-core.c | 1 -
fs/devfs-core.c | 148 +++++++++++++++++++--------------------------
include/block.h | 2 -
include/driver.h | 8 +--
6 files changed, 71 insertions(+), 97 deletions(-)
diff --git a/commands/devinfo.c b/commands/devinfo.c
index c87b30e84307e5053bc35e8bd70ac7af63f688b8..d898e81b3278808a7eed5116d210020d8715a09f 100644
--- a/commands/devinfo.c
+++ b/commands/devinfo.c
@@ -9,7 +9,8 @@
static int do_devinfo_subtree(struct device *dev, int depth)
{
struct device *child;
- struct cdev *cdev, *cdevl;
+ struct cdev *cdev;
+ struct string_list *sl;
int i;
for (i = 0; i < depth; i++)
@@ -26,8 +27,8 @@ static int do_devinfo_subtree(struct device *dev, int depth)
cdev->offset + cdev->size - 1,
size_human_readable(cdev->size),
cdev->name);
- list_for_each_entry(cdevl, &cdev->links, link_entry)
- printf(", %s", cdevl->name);
+ string_list_for_each_entry(sl, &cdev->aliases)
+ printf(", %s", sl->str);
printf("\n");
}
} else {
diff --git a/common/partitions.c b/common/partitions.c
index 7563cb0e6767891ee7f1fe264ce86703408f790a..1a4e046c5f55314ccb2abf5094b0966def8c5b55 100644
--- a/common/partitions.c
+++ b/common/partitions.c
@@ -63,7 +63,7 @@ static int register_one_partition(struct block_device *blk, struct partition *pa
return 0;
partition_name = xasprintf("%s.%s", blk->cdev.name, part->name);
- ret = devfs_create_link(cdev, partition_name);
+ ret = devfs_add_alias(cdev, partition_name);
if (ret)
dev_warn(blk->dev, "Failed to create link from %s to %s\n",
partition_name, cdev->name);
diff --git a/drivers/block/dm/dm-core.c b/drivers/block/dm/dm-core.c
index fd7ed0d84ed7388f8c1cd4aa19e0466191459fd6..2f48cfeb06f7b2da6d26850820f228a6f522fc2f 100644
--- a/drivers/block/dm/dm-core.c
+++ b/drivers/block/dm/dm-core.c
@@ -77,7 +77,6 @@ int dm_cdev_open(struct dm_cdev *dmcdev, const char *path, ulong flags,
return -ENODEV;
}
- dmcdev->cdev = cdev_readlink(dmcdev->cdev);
break;
default:
*errmsg = xstrdup("Only regular files and device specials are supported");
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index c4ff5fe5718ea2c0236fdbf124e56a13e17702d1..32e9b5f867ed1d1696a4c16fb154474f933de342 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -50,42 +50,21 @@ int devfs_partition_complete(struct string_list *sl, char *instr)
}
#endif
-struct cdev *cdev_readlink(const struct cdev *cdev)
-{
- if (!cdev)
- return NULL;
-
- if (cdev->link)
- cdev = cdev->link;
-
- /* links to links are not allowed */
- BUG_ON(cdev->link);
-
- return (void *)cdev;
-}
-
-struct cdev *lcdev_by_name(const char *filename)
+struct cdev *cdev_by_name(const char *filename)
{
struct cdev *cdev;
+ struct string_list *entry;
for_each_cdev(cdev) {
if (!strcmp(cdev->name, filename))
return cdev;
+ string_list_for_each_entry(entry, &cdev->aliases)
+ if (!strcmp(entry->str, filename))
+ return cdev;
}
return NULL;
}
-struct cdev *cdev_by_name(const char *filename)
-{
- struct cdev *cdev;
-
- cdev = lcdev_by_name(filename);
- if (!cdev)
- return NULL;
-
- return cdev_readlink(cdev);
-}
-
struct cdev *cdev_by_device_node(struct device_node *node)
{
struct cdev *cdev;
@@ -95,7 +74,7 @@ struct cdev *cdev_by_device_node(struct device_node *node)
for_each_cdev(cdev) {
if (cdev_of_node(cdev) == node)
- return cdev_readlink(cdev);
+ return cdev;
}
return NULL;
}
@@ -133,9 +112,6 @@ cdev_find_child_by_gpt_typeuuid(struct cdev *cdev, const guid_t *typeuuid)
{
struct cdev *partcdev;
- /* Follow links to support storage-by-alias */
- cdev = cdev_readlink(cdev);
-
if (!cdev_is_gpt_partitioned(cdev))
return ERR_PTR(-EINVAL);
@@ -153,6 +129,29 @@ cdev_find_child_by_gpt_typeuuid(struct cdev *cdev, const guid_t *typeuuid)
return ERR_PTR(-ENOENT);
}
+static bool cdev_has_partname_alias(struct cdev *cdev, const char *partname)
+{
+ char *fullname;
+ struct string_list *sl;
+ bool ret = false;
+
+ if (!cdev->master)
+ return false;
+
+ fullname = xasprintf("%s.%s", cdev->master->name, partname);
+
+ string_list_for_each_entry(sl, &cdev->aliases) {
+ if (streq_ptr(sl->str, fullname)) {
+ ret = true;
+ break;
+ }
+ }
+
+ free(fullname);
+
+ return ret;
+}
+
/**
* cdev_find_partition - find a partition belonging to a physical device
*
@@ -164,15 +163,10 @@ struct cdev *cdev_find_partition(struct cdev *cdevm, const char *name)
struct cdev *partcdev;
for_each_cdev_partition(partcdev, cdevm) {
- struct cdev *cdevl;
-
if (streq_ptr(partcdev->partname, name))
return partcdev;
-
- list_for_each_entry(cdevl, &partcdev->links, link_entry) {
- if (streq_ptr(cdevl->partname, name))
- return cdevl;
- }
+ if (cdev_has_partname_alias(partcdev, name))
+ return partcdev;
}
return NULL;
@@ -190,15 +184,11 @@ struct cdev *device_find_partition(struct device *dev, const char *name)
struct device *child;
list_for_each_entry(cdev, &dev->cdevs, devices_list) {
- struct cdev *cdevl;
-
if (streq_ptr(cdev->partname, name))
return cdev;
- list_for_each_entry(cdevl, &cdev->links, link_entry) {
- if (streq_ptr(cdevl->partname, name))
- return cdev_readlink(cdevl);
- }
+ if (cdev_has_partname_alias(cdev, name))
+ return cdev;
}
device_for_each_child(dev, child) {
@@ -460,20 +450,36 @@ static void cdev_free(struct cdev *cdev)
static bool devfs_initialized;
+static int cdev_symlink(struct cdev *cdev, const char *linkname)
+{
+ char *path;
+ int ret;
+
+ if (!devfs_initialized)
+ return 0;
+
+ path = xasprintf("/dev/%s", linkname);
+ ret = symlink(cdev->name, path);
+ free(path);
+
+ return ret;
+}
+
static void devfs_mknod(struct cdev *cdev)
{
char *path;
int ret;
+ struct string_list *sl;
if (!devfs_initialized)
return;
path = xasprintf("/dev/%s", cdev->name);
- if (cdev->link)
- ret = symlink(cdev->link->name, path);
- else
- ret = mknod(path, S_IFCHR | 0600, cdev->name);
+ string_list_for_each_entry(sl, &cdev->aliases)
+ cdev_symlink(cdev, sl->str);
+
+ ret = mknod(path, S_IFCHR | 0600, cdev->name);
free(path);
@@ -499,8 +505,8 @@ int devfs_create(struct cdev *new)
if (cdev)
return -EEXIST;
- INIT_LIST_HEAD(&new->links);
INIT_LIST_HEAD(&new->partitions);
+ string_list_init(&new->aliases);
list_add_tail(&new->list, &cdev_list);
if (new->dev) {
@@ -509,46 +515,22 @@ int devfs_create(struct cdev *new)
new->device_node = new->dev->of_node;
}
- if (new->link)
- list_add_tail(&new->link_entry, &new->link->links);
-
devfs_mknod(new);
return 0;
}
-int devfs_create_link(struct cdev *cdev, const char *name)
+int devfs_add_alias(struct cdev *cdev, const char *name)
{
- struct cdev *new;
- int ret;
-
- /*
- * Create a link to the real cdev instead of creating
- * a link to a link.
- */
- cdev = cdev_readlink(cdev);
-
- new = cdev_alloc(name);
- new->link = cdev;
+ struct cdev *conflict;
- ret = devfs_create(new);
- if (ret) {
- cdev_free(new);
- return ret;
- }
-
- if (cdev->partname) {
- size_t partnameoff = 0;
-
- if (cdev->master) {
- size_t masterlen = strlen(cdev->master->name);
+ conflict = cdev_by_name(name);
+ if (conflict)
+ return -EEXIST;
- if (!strncmp(name, cdev->master->name, masterlen))
- partnameoff += masterlen + 1;
- }
+ string_list_add(&cdev->aliases, name);
- new->partname = xstrdup(name + partnameoff);
- }
+ cdev_symlink(cdev, name);
return 0;
}
@@ -565,8 +547,7 @@ int devfs_remove(struct cdev *cdev)
if (cdev->dev)
list_del(&cdev->devices_list);
- list_for_each_entry_safe(c, tmp, &cdev->links, link_entry)
- devfs_remove(c);
+ string_list_free(&cdev->aliases);
list_for_each_entry_safe(c, tmp, &cdev->partitions, partition_entry)
cdevfs_del_partition(c);
@@ -574,9 +555,6 @@ int devfs_remove(struct cdev *cdev)
if (cdev_is_partition(cdev))
list_del(&cdev->partition_entry);
- if (cdev->link)
- cdev_free(cdev);
-
return 0;
}
@@ -681,7 +659,7 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev,
if (overlap) {
if (!IS_ERR(overlap)) {
/* only fails with -EEXIST, which is fine */
- (void)devfs_create_link(overlap, partinfo->name);
+ (void)devfs_add_alias(overlap, partinfo->name);
}
return overlap;
diff --git a/include/block.h b/include/block.h
index fc7a0a32fb2d6bc579aa6305433fb2a9e39f336a..a8ebe202288fff83677948f3d67bc12cae5dc107 100644
--- a/include/block.h
+++ b/include/block.h
@@ -104,13 +104,11 @@ static inline bool cdev_is_block_device(const struct cdev *cdev)
static inline bool cdev_is_block_partition(const struct cdev *cdev)
{
- cdev = cdev_readlink(cdev);
return cdev_is_block_device(cdev) && cdev_is_partition(cdev);
}
static inline bool cdev_is_block_disk(const struct cdev *cdev)
{
- cdev = cdev_readlink(cdev);
return cdev_is_block_device(cdev) && !cdev_is_partition(cdev);
}
diff --git a/include/driver.h b/include/driver.h
index 5a67d20ccff3fca339e7b40c32ecfbc244f358f5..afd22b88e5116c73bd79fc650fee9cbf6acfe247 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -17,6 +17,7 @@
#include <init.h>
#include <errno.h>
#include <filetype.h>
+#include <stringlist.h>
#define FORMAT_DRIVER_NAME_ID "%s%d"
@@ -432,8 +433,7 @@ struct cdev {
u16 typeflags; /* GPT type-specific attributes */
int open;
struct mtd_info *mtd;
- struct cdev *link;
- struct list_head link_entry, links;
+ struct string_list aliases;
struct list_head partition_entry, partitions;
struct cdev *master;
enum filetype filetype;
@@ -461,13 +461,11 @@ static inline const char *cdev_name(struct cdev *cdev)
void devfs_init(void);
int devfs_create(struct cdev *);
-int devfs_create_link(struct cdev *, const char *name);
+int devfs_add_alias(struct cdev *, const char *name);
int devfs_remove(struct cdev *);
int cdev_find_free_index(const char *);
struct cdev *cdev_find_partition(struct cdev *cdevm, const char *name);
struct cdev *device_find_partition(struct device *dev, const char *name);
-struct cdev *lcdev_by_name(const char *filename);
-struct cdev *cdev_readlink(const struct cdev *cdev);
struct cdev *cdev_by_device_node(struct device_node *node);
struct cdev *cdev_by_partuuid(const char *partuuid);
struct cdev *cdev_by_diskuuid(const char *partuuid);
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 10/10] ls: use ~0 for FILE_SIZE_STREAM
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
` (8 preceding siblings ...)
2025-11-27 9:19 ` [PATCH 09/10] fs: replace cdev links with aliases Sascha Hauer
@ 2025-11-27 9:19 ` Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2025-11-27 9:19 UTC (permalink / raw)
To: BAREBOX
For stream size files we used to show ((loff_t) -1) as file size which
is quite unreadable. Use ~0 in this case.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/ls.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/commands/ls.c b/commands/ls.c
index 1ccd44f7bbc00a03b773b56020a7117ce94b24cd..5c9e0f738b03ae36655b04ec1037811a4abc0423 100644
--- a/commands/ls.c
+++ b/commands/ls.c
@@ -33,8 +33,12 @@ static void ls_one(const char *path, const char* fullname)
return;
mkmodestr(s.st_mode, modestr);
- printf("%s %*llu %*.*s", modestr, SIZELEN, s.st_size, namelen,
- namelen, path);
+ if (s.st_size == FILE_SIZE_STREAM)
+ printf("%s %*s %*.*s", modestr, SIZELEN, "~0", namelen,
+ namelen, path);
+ else
+ printf("%s %*llu %*.*s", modestr, SIZELEN, s.st_size, namelen,
+ namelen, path);
if (S_ISLNK(s.st_mode)) {
char realname[PATH_MAX];
--
2.47.3
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-11-27 9:32 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-11-27 9:19 [PATCH 00/10] fs: Use device special nodes for devfs Sascha Hauer
2025-11-27 9:19 ` [PATCH 01/10] fs: implement mknod Sascha Hauer
2025-11-27 9:19 ` [PATCH 02/10] commands: add mknod command Sascha Hauer
2025-11-27 9:19 ` [PATCH 03/10] fs: ramfs: add device file support Sascha Hauer
2025-11-27 9:19 ` [PATCH 04/10] cdev: add cdev_size() helper Sascha Hauer
2025-11-27 9:19 ` [PATCH 05/10] fs: fix st_size for device files Sascha Hauer
2025-11-27 9:19 ` [PATCH 06/10] fs: retire devfs as filesystem Sascha Hauer
2025-11-27 9:19 ` [PATCH 07/10] fs: include cdevname in struct stat Sascha Hauer
2025-11-27 9:19 ` [PATCH 08/10] fs: stat_print: get cdevname from stat Sascha Hauer
2025-11-27 9:19 ` [PATCH 09/10] fs: replace cdev links with aliases Sascha Hauer
2025-11-27 9:19 ` [PATCH 10/10] ls: use ~0 for FILE_SIZE_STREAM Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox