]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
cifs: define variable sized buffer for querydir responses
authorShyam Prasad N <sprasad@microsoft.com>
Tue, 10 Mar 2026 10:30:17 +0000 (16:00 +0530)
committerSteve French <stfrench@microsoft.com>
Wed, 24 Jun 2026 21:49:02 +0000 (16:49 -0500)
QueryDirectory responses today are stored in one of two fixed
sized buffers: smallbuf (448 bytes) or bigbuf (16KB). These are
borrowed from server struct and are not sufficient for large-sized
query dir operations.

With this change we will now define a new buffer type specifically
for cifs_search_info to hold variable sized responses. These will
be allocated by kmalloc and freed by kfree.

Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/cifsglob.h
fs/smb/client/file.c
fs/smb/client/readdir.c
fs/smb/client/smb2pdu.c

index befc5eecb55ca82d69138636595dc797da8b106c..99f9e6dca62b60b056a31b67c6874ffaae35f076 100644 (file)
@@ -1393,6 +1393,7 @@ struct cifs_search_info {
        bool emptyDir:1;
        bool unicode:1;
        bool smallBuf:1; /* so we know which buf_release function to call */
+       bool is_dynamic_buf:1; /* dynamically allocated buffer - can be variable size */
 };
 
 #define ACL_NO_MODE    ((umode_t)(-1))
@@ -1906,6 +1907,7 @@ enum cifs_find_flags {
 #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
 #define   CIFS_SMALL_BUFFER     1
 #define   CIFS_LARGE_BUFFER     2
+#define   CIFS_DYNAMIC_BUFFER   3    /* Dynamically allocated buffer */
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
 /* Type of Request to SendReceive2 */
index 58430ba51b1025447be8afa0454cfb4313009ab6..8b25d6c9ec5e9eb2cfda42552b81328c3911b118 100644 (file)
@@ -1563,6 +1563,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
                cfile->srch_inf.ntwrk_buf_start = NULL;
                if (cfile->srch_inf.smallBuf)
                        cifs_small_buf_release(buf);
+               else if (cfile->srch_inf.is_dynamic_buf)
+                       kfree(buf);
                else
                        cifs_buf_release(buf);
        }
index 1ff77f3d1de09506ef3fd4d8a683dbd06a9bf0f6..a50c86bbe60f3fc4d25e4cfaadefd428f137f69d 100644 (file)
@@ -732,6 +732,8 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
                        if (cfile->srch_inf.smallBuf)
                                cifs_small_buf_release(cfile->srch_inf.
                                                ntwrk_buf_start);
+                       else if (cfile->srch_inf.is_dynamic_buf)
+                               kfree(cfile->srch_inf.ntwrk_buf_start);
                        else
                                cifs_buf_release(cfile->srch_inf.
                                                ntwrk_buf_start);
index 85642ea992d5782eca3041825ad7ba19e6e7fcc6..d058584b8f05fabf372a786a5860be8d7cfe280e 100644 (file)
@@ -5673,6 +5673,8 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
        if (srch_inf->ntwrk_buf_start) {
                if (srch_inf->smallBuf)
                        cifs_small_buf_release(srch_inf->ntwrk_buf_start);
+               else if (srch_inf->is_dynamic_buf)
+                       kfree(srch_inf->ntwrk_buf_start);
                else
                        cifs_buf_release(srch_inf->ntwrk_buf_start);
        }
@@ -5692,12 +5694,18 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
        cifs_dbg(FYI, "num entries %d last_index %lld srch start %p srch end %p\n",
                 srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
                 srch_inf->srch_entries_start, srch_inf->last_entry);
-       if (resp_buftype == CIFS_LARGE_BUFFER)
+       if (resp_buftype == CIFS_LARGE_BUFFER) {
                srch_inf->smallBuf = false;
-       else if (resp_buftype == CIFS_SMALL_BUFFER)
+               srch_inf->is_dynamic_buf = false;
+       } else if (resp_buftype == CIFS_SMALL_BUFFER) {
                srch_inf->smallBuf = true;
-       else
+               srch_inf->is_dynamic_buf = false;
+       } else if (resp_buftype == CIFS_DYNAMIC_BUFFER) {
+               srch_inf->smallBuf = false;
+               srch_inf->is_dynamic_buf = true;
+       } else {
                cifs_tcon_dbg(VFS, "Invalid search buffer type\n");
+       }
 
        return 0;
 }