U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Marek Vasut <marex@denx.de>
To: u-boot@lists.denx.de
Cc: Marek Vasut <marex@denx.de>,
	Heinrich Schuchardt <xypron.glpk@gmx.de>,
	Ilias Apalodimas <ilias.apalodimas@linaro.org>,
	Mattijs Korpershoek <mkorpershoek@baylibre.com>,
	Simon Glass <sjg@chromium.org>, Tom Rini <trini@konsulko.com>
Subject: [PATCH 3/7] fs: exfat: Rework exfat_fs_readdir() to behave like exfat_fs_ls()
Date: Sun, 13 Apr 2025 10:55:01 +0200	[thread overview]
Message-ID: <20250413085740.5953-3-marex@denx.de> (raw)
In-Reply-To: <20250413085740.5953-1-marex@denx.de>

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@denx.de>
---
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
Cc: u-boot@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


  parent reply	other threads:[~2025-04-13  8:58 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-13  8:54 [PATCH 1/7] fs: exfat: Flush node before put in read() callback Marek Vasut
2025-04-13  8:55 ` [PATCH 2/7] fs: exfat: Inhibit "impossible" print on write to bogus file Marek Vasut
2025-04-13  8:55 ` Marek Vasut [this message]
2025-04-13  8:55 ` [PATCH 4/7] fs: exfat: Fix exfat_fs_exists() return value Marek Vasut
2025-04-13  8:55 ` [PATCH 5/7] test_fs: Add test -e test Marek Vasut
2025-04-13  8:55 ` [PATCH 6/7] fs: exfat: Implement trivial 'rename' support Marek Vasut
2025-04-13  8:55 ` [PATCH 7/7] test_fs: Test 'mv' command on exfat and fs_generic Marek Vasut
2025-04-22 13:58 ` [PATCH 1/7] fs: exfat: Flush node before put in read() callback Tom Rini

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=20250413085740.5953-3-marex@denx.de \
    --to=marex@denx.de \
    --cc=ilias.apalodimas@linaro.org \
    --cc=mkorpershoek@baylibre.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=xypron.glpk@gmx.de \
    /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