diff --git a/drivers/virtio/fs.c b/drivers/virtio/fs.c index 9437f31bdba..f1065fe96d7 100644 --- a/drivers/virtio/fs.c +++ b/drivers/virtio/fs.c @@ -224,6 +224,7 @@ int virtio_fs_readdir(struct udevice *dev, u64 nodeid, u64 fh, u64 offset, in.size = size; in.offset = offset; ret = virtio_fs_xfer(dev, &inhdr, &in, sizeof(in), &outhdr, buf, size); + log_debug("fh %llx offset %llx\n", in.fh, in.offset); log_debug("len %x error %x unique %llx\n", outhdr.len, outhdr.error, outhdr.unique); if (ret) diff --git a/drivers/virtio/fs_dir.c b/drivers/virtio/fs_dir.c index b346ded8a09..cfd9573250a 100644 --- a/drivers/virtio/fs_dir.c +++ b/drivers/virtio/fs_dir.c @@ -25,18 +25,14 @@ static int virtio_fs_dir_open(struct udevice *dev, struct fs_dir_stream *strm) struct udevice *fs = dev_get_parent(dev); int ret; - strm = malloc(sizeof(struct fs_dir_stream)); - if (!strm) - return log_msg_ret("vso", -ENOMEM); - log_debug("opening inode %lld\n", dir_priv->inode); ret = virtio_fs_opendir(fs, dir_priv->inode, &strm->fh); + log_debug("2 open ret %d strm %p fh %llx\n", ret, strm, strm->fh); if (ret) { log_err("Failed to open directory: %d\n", ret); return ret; } strm->dev = dev; - strm->offset = 0; return 0; @@ -53,7 +49,8 @@ int virtio_fs_dir_read(struct udevice *dev, struct fs_dir_stream *strm, char buf[0x200]; int ret, size; - log_debug("start %lld strm %p\n", dir_priv->inode, strm); + log_debug("start %lld strm %p fh %llx\n", dir_priv->inode, strm, + strm->fh); log_debug("offset %lld\n", strm->offset); ret = virtio_fs_readdir(fs, dir_priv->inode, strm->fh, strm->offset, buf, sizeof(buf), &size); @@ -163,14 +160,12 @@ int virtio_fs_setup_dir(struct udevice *fsdev, const char *path, { struct virtio_fs_dir_priv *dir_priv; struct udevice *dir; - bool has_path; u64 inode; int ret; log_debug("looking up path '%s'\n", path); inode = FUSE_ROOT_ID; - has_path = path && strcmp("/", path); - if (has_path) { + if (*path) { ret = virtio_fs_lookup(fsdev, path, &inode); if (ret) { log_err("Failed to lookup directory '%s': %d\n", path, @@ -193,7 +188,7 @@ int virtio_fs_setup_dir(struct udevice *fsdev, const char *path, return 0; no_add: - if (has_path) + if (*path) ret = virtio_fs_forget(fsdev, inode); return ret; diff --git a/drivers/virtio/fs_internal.h b/drivers/virtio/fs_internal.h index 460a79d9854..c620e0f40e4 100644 --- a/drivers/virtio/fs_internal.h +++ b/drivers/virtio/fs_internal.h @@ -152,10 +152,10 @@ long virtio_fs_read(struct udevice *dev, u64 nodeid, u64 fh, u64 offset, * Looks up a path to find the corresponding inode in the virtio-fs filesystem, * then creates and probes a new 'directory' device to represent it. * - * If the path is the root (NULL or "/"), it uses the root inode directly. + * If the path is the root (@path is ""), it uses the root inode directly. * * @fsdev: The virtio-fs filesystem device - * @path: The path of the directory to set up (e.g., "/boot" or "/") + * @path: The path of the directory to set up (e.g., "/boot", or "" for root) * @devp: On success, returns a pointer to the newly created directory device * Return: 0 on success, -ve on error */ diff --git a/fs/dir-uclass.c b/fs/dir-uclass.c index f2c3a7c3806..c5d7ef45d3b 100644 --- a/fs/dir-uclass.c +++ b/fs/dir-uclass.c @@ -26,7 +26,7 @@ int dir_add_probe(struct udevice *fsdev, struct driver *drv, const char *path, str = strdup(dev_name); if (!str) goto no_dev_name; - dup_path = strdup(path && strcmp("/", path) ? path : ""); + dup_path = strdup(path); if (!str) goto no_dev_path; diff --git a/fs/fs-uclass.c b/fs/fs-uclass.c index 96fb04a106c..a335391bd74 100644 --- a/fs/fs-uclass.c +++ b/fs/fs-uclass.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -41,8 +42,35 @@ int fs_split_path(const char *fname, char **subdirp, const char **leafp) int fs_lookup_dir(struct udevice *dev, const char *path, struct udevice **dirp) { struct fs_ops *ops = fs_get_ops(dev); + struct udevice *dir; + int ret; - return ops->lookup_dir(dev, path, dirp); + if (!path || !strcmp("/", path)) + path = ""; + + /* see if we already have this directory */ + device_foreach_child(dir, dev) { + struct dir_uc_priv *priv; + + if (!device_active(dir)) + continue; + + priv = dev_get_uclass_priv(dir); + log_debug("dir %s '%s' '%s'\n", dir->name, path, priv->path); + if (!strcmp(path, priv->path)) { + *dirp = dir; + log_debug("found: dev '%s'\n", dir->name); + return 0; + } + } + + ret = ops->lookup_dir(dev, path, &dir); + if (ret) + return log_msg_ret("fld", ret); + + *dirp = dir; + + return 0; } int fs_mount(struct udevice *dev) diff --git a/fs/sandbox/sandboxfs.c b/fs/sandbox/sandboxfs.c index adf852ee53d..5b8f4f50a8e 100644 --- a/fs/sandbox/sandboxfs.c +++ b/fs/sandbox/sandboxfs.c @@ -206,7 +206,8 @@ static int sandbox_dir_open(struct udevice *dev, struct fs_dir_stream *strm) struct dir_uc_priv *dir_uc_priv = dev_get_uclass_priv(dev); int ret; - ret = os_dirent_ls(dir_uc_priv->path, &priv->head); + ret = os_dirent_ls(*dir_uc_priv->path ? dir_uc_priv->path : ".", + &priv->head); if (ret) { log_err("Failed to open directory: %d\n", ret); return ret; @@ -300,7 +301,8 @@ static int sandbox_dir_open_file(struct udevice *dir, const char *leaf, struct udevice *dev; off_t size; - snprintf(pathname, sizeof(pathname), "%s/%s", uc_priv->path, leaf); + snprintf(pathname, sizeof(pathname), "%s/%s", + *uc_priv->path ? uc_priv->path: ".", leaf); ftype = os_get_filetype(pathname); if (ftype < 0) return log_msg_ret("soF", ftype); @@ -367,7 +369,7 @@ static int sandbox_fs_lookup_dir(struct udevice *dev, const char *path, int ftype; int ret; - ftype = os_get_filetype(path ?: "/"); + ftype = os_get_filetype(*path ? path : "/"); if (ftype < 0) return ftype; if (ftype != OS_FILET_DIR) diff --git a/include/dir.h b/include/dir.h index f948843c6b3..c25fac4fcd3 100644 --- a/include/dir.h +++ b/include/dir.h @@ -117,10 +117,11 @@ int dir_close(struct udevice *dev, struct fs_dir_stream *strm); /** * dir_add_probe() - Add a new directory and probe it * + * This sets up the uclass-private data for the new directory + * * @fsdev: Filesystem containing the directory * @drv: Driver to use - * @path Absolute path to directory (within the filesystem), or NULL/"/" for - * root + * @path Absolute path to directory (within the filesystem), or "" for root * @devp: Returns the new device, probed ready for use * */ int dir_add_probe(struct udevice *fsdev, struct driver *drv, const char *path, diff --git a/include/fs.h b/include/fs.h index 5321d339b07..6696b9e26c7 100644 --- a/include/fs.h +++ b/include/fs.h @@ -58,8 +58,11 @@ struct fs_ops { /** * lookup_dir() - Look up a directory on a filesystem * + * This should not set up the uclass-private data; this is done by + * fs_lookup_dir() + * * @dev: Filesystem device - * @path: Path to look up, empty or "/" for the root + * @path: Path to look up, "" for the root * @dirp: Returns associated directory device, creating if necessary * Return 0 if OK, -ENOENT, other -ve on error */ @@ -89,8 +92,10 @@ int fs_unmount(struct udevice *dev); /** * fs_lookup_dir() - Look up a directory on a filesystem * + * If a new directory-device is created, its uclass data is set up also + * * @dev: Filesystem device - * @path: Path to look up, empty or "/" for the root + * @path: Path to look up, "" or "/" for the root * @dirp: Returns associated directory device, creating if necessary * Return 0 if OK, -ENOENT, other -ve on error */ diff --git a/test/dm/fs.c b/test/dm/fs.c index e94b7854184..31712617d09 100644 --- a/test/dm/fs.c +++ b/test/dm/fs.c @@ -44,7 +44,7 @@ static int dm_test_fs_dir(struct unit_test_state *uts) ut_assertok(fs_mount(fsdev)); ut_asserteq(-ENOENT, fs_lookup_dir(fsdev, "does-not-exit", &dir)); - ut_assertok(fs_lookup_dir(fsdev, ".", &dir)); + ut_assertok(fs_lookup_dir(fsdev, "", &dir)); ut_assertnonnull(dir); ut_asserteq_str("fs.dir", dir->name); @@ -79,7 +79,7 @@ static int dm_test_fs_file(struct unit_test_state *uts) ut_assertok(fs_mount(fsdev)); - ut_assertok(fs_lookup_dir(fsdev, ".", &dir)); + ut_assertok(fs_lookup_dir(fsdev, "", &dir)); ut_assertnonnull(dir); ut_asserteq_str("fs.dir", dir->name);