diff mbox series

ksmbd: retry iterate_dir in smb2_query_dir

Message ID 20241205023120.792280-1-hobin.woo@samsung.com (mailing list archive)
State New, archived
Headers show
Series ksmbd: retry iterate_dir in smb2_query_dir | expand

Commit Message

Hobin Woo Dec. 5, 2024, 2:31 a.m. UTC
Some file systems do not ensure that the single call of iterate_dir
reaches the end of the directory. For example, FUSE fetches entries from
a daemon using 4KB buffer and stops fetching if entries exceed the
buffer. And then an actor of caller, KSMBD, is used to fill the entries
from the buffer.
Thus, pattern searching on FUSE, files located after the 4KB could not
be found and STATUS_NO_SUCH_FILE was returned.

Signed-off-by: Hobin Woo <hobin.woo@samsung.com>
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
Tested-by: Yoonho Shin <yoonho.shin@samsung.com>
---
 fs/smb/server/smb2pdu.c | 12 +++++++++++-
 fs/smb/server/vfs.h     |  1 +
 2 files changed, 12 insertions(+), 1 deletion(-)

Comments

Namjae Jeon Dec. 5, 2024, 12:44 p.m. UTC | #1
On Thu, Dec 5, 2024 at 11:31 AM Hobin Woo <hobin.woo@samsung.com> wrote:
>
> Some file systems do not ensure that the single call of iterate_dir
> reaches the end of the directory. For example, FUSE fetches entries from
> a daemon using 4KB buffer and stops fetching if entries exceed the
> buffer. And then an actor of caller, KSMBD, is used to fill the entries
> from the buffer.
> Thus, pattern searching on FUSE, files located after the 4KB could not
> be found and STATUS_NO_SUCH_FILE was returned.
>
> Signed-off-by: Hobin Woo <hobin.woo@samsung.com>
> Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
> Reviewed-by: Namjae Jeon <linkinjeon@kernel.org>
> Tested-by: Yoonho Shin <yoonho.shin@samsung.com>
Applied it to #ksmbd-for-next-next.
Thanks for your patch!
diff mbox series

Patch

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 4f539eeadbb0..1923f91d40b6 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -4228,6 +4228,7 @@  static bool __query_dir(struct dir_context *ctx, const char *name, int namlen,
 	/* dot and dotdot entries are already reserved */
 	if (!strcmp(".", name) || !strcmp("..", name))
 		return true;
+	d_info->num_scan++;
 	if (ksmbd_share_veto_filename(priv->work->tcon->share_conf, name))
 		return true;
 	if (!match_pattern(name, namlen, priv->search_pattern))
@@ -4390,8 +4391,17 @@  int smb2_query_dir(struct ksmbd_work *work)
 	query_dir_private.info_level		= req->FileInformationClass;
 	dir_fp->readdir_data.private		= &query_dir_private;
 	set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir);
-
+again:
+	d_info.num_scan = 0;
 	rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx);
+	/*
+	 * num_entry can be 0 if the directory iteration stops before reaching
+	 * the end of the directory and no file is matched with the search
+	 * pattern.
+	 */
+	if (rc >= 0 && !d_info.num_entry && d_info.num_scan &&
+			d_info.out_buf_len > 0)
+		goto again;
 	/*
 	 * req->OutputBufferLength is too small to contain even one entry.
 	 * In this case, it immediately returns OutputBufferLength 0 to client.
diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h
index cb76f4b5bafe..06903024a2d8 100644
--- a/fs/smb/server/vfs.h
+++ b/fs/smb/server/vfs.h
@@ -43,6 +43,7 @@  struct ksmbd_dir_info {
 	char		*rptr;
 	int		name_len;
 	int		out_buf_len;
+	int		num_scan;
 	int		num_entry;
 	int		data_count;
 	int		last_entry_offset;