]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb/client: use bsearch() to find target in smb2_error_map_table
authorChenXiaoSong <chenxiaosong@kylinos.cn>
Tue, 23 Dec 2025 09:24:40 +0000 (17:24 +0800)
committerSteve French <stfrench@microsoft.com>
Mon, 9 Feb 2026 03:24:41 +0000 (21:24 -0600)
The smb2_error_map_table array currently has 1740 elements. When searching
for the last element, the original loop-based search method requires 1740
comparisons, while binary search algorithm requires only 10 comparisons.

Suggested-by: David Howells <dhowells@redhat.com>
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Reviewed-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/linux-cifs/20260106071507.1420900-5-chenxiaosong.chenxiaosong@linux.dev/
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb2maperror.c

index c36cfe707bf112892e5b8021a930fd959dd7f836..090bbd10623d3e6a10c7f4edb52a0115876a3d50 100644 (file)
@@ -30,13 +30,36 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
 #include "smb2_mapping_table.c"
 };
 
+static __always_inline int cmp_smb2_status(const void *_key, const void *_pivot)
+{
+       __u32 key = *(__u32 *)_key;
+       const struct status_to_posix_error *pivot = _pivot;
+
+       if (key < pivot->smb2_status)
+               return -1;
+       if (key > pivot->smb2_status)
+               return 1;
+       return 0;
+}
+
+static const struct status_to_posix_error *smb2_get_err_map(__u32 smb2_status)
+{
+       const struct status_to_posix_error *err_map;
+
+       err_map = __inline_bsearch(&smb2_status, smb2_error_map_table,
+                                  ARRAY_SIZE(smb2_error_map_table),
+                                  sizeof(struct status_to_posix_error),
+                                  cmp_smb2_status);
+       return err_map;
+}
+
 int
 map_smb2_to_linux_error(char *buf, bool log_err)
 {
        struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
-       unsigned int i;
        int rc = -EIO;
        __le32 smb2err = shdr->Status;
+       const struct status_to_posix_error *err_map;
 
        if (smb2err == 0) {
                trace_smb3_cmd_done(le32_to_cpu(shdr->Id.SyncId.TreeId),
@@ -50,21 +73,20 @@ map_smb2_to_linux_error(char *buf, bool log_err)
                   (smb2err != STATUS_END_OF_FILE)) ||
                  (cifsFYI & CIFS_RC);
 
-       for (i = 0; i < sizeof(smb2_error_map_table) /
-                       sizeof(struct status_to_posix_error); i++) {
-               if (smb2_error_map_table[i].smb2_status == smb2err) {
-                       if (log_err)
-                               pr_notice("Status code returned 0x%08x %s\n", smb2err,
-                                         smb2_error_map_table[i].status_string);
-                       rc = smb2_error_map_table[i].posix_error;
-                       break;
-               }
-       }
+       err_map = smb2_get_err_map(le32_to_cpu(smb2err));
+       if (!err_map)
+               goto out;
+
+       rc = err_map->posix_error;
+       if (log_err)
+               pr_notice("Status code returned 0x%08x %s\n",
+                         err_map->smb2_status, err_map->status_string);
 
+out:
        /* on error mapping not found  - return EIO */
 
        cifs_dbg(FYI, "Mapping SMB2 status code 0x%08x to POSIX err %d\n",
-                __le32_to_cpu(smb2err), rc);
+                le32_to_cpu(smb2err), rc);
 
        trace_smb3_cmd_err(le32_to_cpu(shdr->Id.SyncId.TreeId),
                           le64_to_cpu(shdr->SessionId),