[PATCH 3/7] fs: exfat: Rework exfat_fs_readdir() to behave like exfat_fs_ls()
Marek Vasut
marex at denx.de
Sun Apr 13 10:55:01 CEST 2025
The exfat_fs_readdir() depends on state created in exfat_fs_opendir(),
but that state may be disrupted by fs_close() called by the FS layer
in fs_opendir(), because exfat porting layer unmounts the filesystem
in ->close() callback.
To avoid this disruption, avoid creating state in exfat_fs_opendir(),
cache only the directory name to list there, and rework exfat_fs_readdir()
to work in a similar way to exfat_fs_ls(). That is, make exfat_fs_readdir()
open the directory, look up specific entry, extract its properties to be
reported to FS layer, and close the directory. This is slow, but avoids
the disruption. The slowness does not affect regular 'ls' command, which
uses exfat_fs_ls() fast path.
Fixes: b86a651b646c ("fs: exfat: Add U-Boot porting layer")
Signed-off-by: Marek Vasut <marex at denx.de>
---
Cc: Heinrich Schuchardt <xypron.glpk at gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas at linaro.org>
Cc: Mattijs Korpershoek <mkorpershoek at baylibre.com>
Cc: Simon Glass <sjg at chromium.org>
Cc: Tom Rini <trini at konsulko.com>
Cc: u-boot at lists.denx.de
---
fs/exfat/io.c | 111 ++++++++++++++++++++++++++++++--------------------
1 file changed, 67 insertions(+), 44 deletions(-)
diff --git a/fs/exfat/io.c b/fs/exfat/io.c
index 12498a4a6ec..004ba5d3e45 100644
--- a/fs/exfat/io.c
+++ b/fs/exfat/io.c
@@ -597,15 +597,13 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
}
#ifdef __UBOOT__
+#define PATH_MAX FS_DIRENT_NAME_LEN
+
struct exfat_dir_stream {
+ char dirname[PATH_MAX];
struct fs_dir_stream fs_dirs;
struct fs_dirent dirent;
-
- struct exfat_node* node;
- struct exfat_iterator it;
- /* State tracker flags for emulated . and .. dirents */
- bool dot;
- bool dotdot;
+ int offset;
};
int exfat_fs_probe(struct blk_desc *fs_dev_desc,
@@ -626,8 +624,6 @@ error:
return ret;
}
-#define PATH_MAX FS_DIRENT_NAME_LEN
-
/* Adapted from uclibc 1.0.35 */
static char *exfat_realpath(const char *path, char got_path[])
{
@@ -721,31 +717,31 @@ int exfat_lookup_realpath(struct exfat* ef, struct exfat_node** node,
int exfat_fs_opendir(const char *filename, struct fs_dir_stream **dirsp)
{
struct exfat_dir_stream *dirs;
+ struct exfat_node *dnode;
int err;
- dirs = calloc(1, sizeof(*dirs));
- if (!dirs)
- return -ENOMEM;
-
- err = exfat_lookup_realpath(&ctxt.ef, &dirs->node, filename);
+ err = exfat_lookup_realpath(&ctxt.ef, &dnode, filename);
if (err)
- goto err_out;
+ return err;
- if (!(dirs->node->attrib & EXFAT_ATTRIB_DIR)) {
+ if (!(dnode->attrib & EXFAT_ATTRIB_DIR))
err = -ENOTDIR;
- goto err_out;
- }
- err = exfat_opendir(&ctxt.ef, dirs->node, &dirs->it);
+ exfat_put_node(&ctxt.ef, dnode);
+
if (err)
- goto err_out;
+ return err;
+
+ dirs = calloc(1, sizeof(*dirs));
+ if (!dirs)
+ return -ENOMEM;
+
+ strcpy(dirs->dirname, filename);
+ dirs->offset = -1;
*dirsp = &dirs->fs_dirs;
return 0;
-err_out:
- free(dirs);
- return err;
}
int exfat_fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
@@ -753,50 +749,77 @@ int exfat_fs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
struct exfat_dir_stream *dirs =
container_of(fs_dirs, struct exfat_dir_stream, fs_dirs);
struct fs_dirent *dent = &dirs->dirent;
- struct exfat_node* node;
+ struct exfat_node *dnode, *node;
+ struct exfat_iterator it;
+ int offset = 0;
+ int err;
+
+ err = exfat_lookup_realpath(&ctxt.ef, &dnode, dirs->dirname);
+ if (err)
+ return err;
+
+ if (!(dnode->attrib & EXFAT_ATTRIB_DIR)) {
+ err = -ENOTDIR;
+ goto err_out;
+ }
/* Emulate current directory ./ */
- if (!dirs->dot) {
- dirs->dot = true;
+ if (dirs->offset == -1) {
+ dirs->offset++;
snprintf(dent->name, FS_DIRENT_NAME_LEN, ".");
dent->type = FS_DT_DIR;
*dentp = dent;
- return 0;
+ goto err_out;
}
/* Emulate parent directory ../ */
- if (!dirs->dotdot) {
- dirs->dotdot = true;
+ if (dirs->offset == 0) {
+ dirs->offset++;
snprintf(dent->name, FS_DIRENT_NAME_LEN, "..");
dent->type = FS_DT_DIR;
*dentp = dent;
- return 0;
+ goto err_out;
}
+ err = exfat_opendir(&ctxt.ef, dnode, &it);
+ if (err)
+ goto err_out;
+
+ *dentp = NULL;
+
/* Read actual directory content */
- node = exfat_readdir(&dirs->it);
- if (!node) { /* No more content, reset . and .. emulation */
- dirs->dot = false;
- dirs->dotdot = false;
- return 1;
- }
+ while ((node = exfat_readdir(&it))) {
+ if (dirs->offset != ++offset) {
+ exfat_put_node(&ctxt.ef, node);
+ continue;
+ }
- exfat_get_name(node, dent->name);
- if (node->attrib & EXFAT_ATTRIB_DIR) {
- dent->type = FS_DT_DIR;
- } else {
- dent->type = FS_DT_REG;
- dent->size = node->size;
+ exfat_get_name(node, dent->name);
+ if (node->attrib & EXFAT_ATTRIB_DIR) {
+ dent->type = FS_DT_DIR;
+ } else {
+ dent->type = FS_DT_REG;
+ dent->size = node->size;
+ }
+ exfat_put_node(&ctxt.ef, node);
+ *dentp = dent;
+ dirs->offset++;
+ break;
}
- *dentp = dent;
+ exfat_closedir(&ctxt.ef, &it);
- return 0;
+err_out:
+ exfat_put_node(&ctxt.ef, dnode);
+ return err;
}
void exfat_fs_closedir(struct fs_dir_stream *fs_dirs)
{
- free(fs_dirs);
+ struct exfat_dir_stream *dirs =
+ container_of(fs_dirs, struct exfat_dir_stream, fs_dirs);
+
+ free(dirs);
}
int exfat_fs_ls(const char *dirname)
--
2.47.2
More information about the U-Boot
mailing list