]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
smb/client: use binary search for SMB1 DOS/SRV error mapping
authorHuiwen He <hehuiwen@kylinos.cn>
Thu, 2 Apr 2026 14:18:37 +0000 (14:18 +0000)
committerSteve French <stfrench@microsoft.com>
Mon, 6 Apr 2026 00:58:40 +0000 (19:58 -0500)
Currently, map_smb_to_linux_error() uses linear searches for both
mapping_table_ERRDOS[] and mapping_table_ERRSRV[].

Refactor this by introducing search_mapping_table_ERRDOS() and
search_mapping_table_ERRSRV() that implements binary search(as the tables
are sorted).This improves lookup performance and reduces code duplication.

Also remove the sentinel entries from the mapping tables as they are no
longer needed with ARRAY_SIZE().

Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/smb1maperror.c

index 294ac9646bff810ad236d4c142f2b0f7e698a320..28e1c84fa83b7933da1287406cfd2899c38fa02c 100644 (file)
@@ -9,6 +9,7 @@
  *   Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
  */
 
+#include <linux/bsearch.h>
 #include "cifsproto.h"
 #include "smb1proto.h"
 #include "smberr.h"
@@ -20,13 +21,24 @@ struct smb_to_posix_error {
        int posix_code;
 };
 
+static __always_inline int smb1_posix_error_cmp(const void *_key, const void *_pivot)
+{
+       __u16 key = *(__u16 *)_key;
+       const struct smb_to_posix_error *pivot = _pivot;
+
+       if (key < pivot->smb_err)
+               return -1;
+       if (key > pivot->smb_err)
+               return 1;
+       return 0;
+}
+
 static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 /*
  * Automatically generated by the `gen_smb1_mapping` script,
  * sorted by DOS error code (ascending).
  */
 #include "smb1_err_dos_map.c"
-       {0, 0}
 };
 
 static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
@@ -35,7 +47,6 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
  * sorted by SRV error code (ascending).
  */
 #include "smb1_err_srv_map.c"
-       {0, 0}
 };
 
 /*****************************************************************************
@@ -72,14 +83,32 @@ search_ntstatus_to_dos_map(__u32 ntstatus)
                                ntstatus_to_dos_cmp);
 }
 
+static const struct smb_to_posix_error *
+search_mapping_table_ERRDOS(__u16 smb_err)
+{
+       return __inline_bsearch(&smb_err, mapping_table_ERRDOS,
+                               ARRAY_SIZE(mapping_table_ERRDOS),
+                               sizeof(struct smb_to_posix_error),
+                               smb1_posix_error_cmp);
+}
+
+static const struct smb_to_posix_error *
+search_mapping_table_ERRSRV(__u16 smb_err)
+{
+       return __inline_bsearch(&smb_err, mapping_table_ERRSRV,
+                               ARRAY_SIZE(mapping_table_ERRSRV),
+                               sizeof(struct smb_to_posix_error),
+                               smb1_posix_error_cmp);
+}
+
 int
 map_smb_to_linux_error(char *buf, bool logErr)
 {
        struct smb_hdr *smb = (struct smb_hdr *)buf;
-       unsigned int i;
        int rc = -EIO;  /* if transport error smb error may not be set */
        __u8 smberrclass;
        __u16 smberrcode;
+       const struct smb_to_posix_error *err_map = NULL;
 
        /* BB if NT Status codes - map NT BB */
 
@@ -112,38 +141,16 @@ map_smb_to_linux_error(char *buf, bool logErr)
 
        /* old style errors */
 
-       /* DOS class smb error codes - map DOS */
        if (smberrclass == ERRDOS) {
+               /* DOS class smb error codes - map DOS */
                /* 1 byte field no need to byte reverse */
-               for (i = 0;
-                    i <
-                    sizeof(mapping_table_ERRDOS) /
-                    sizeof(struct smb_to_posix_error); i++) {
-                       if (mapping_table_ERRDOS[i].smb_err == 0)
-                               break;
-                       else if (mapping_table_ERRDOS[i].smb_err ==
-                                                               smberrcode) {
-                               rc = mapping_table_ERRDOS[i].posix_code;
-                               break;
-                       }
-                       /* else try next error mapping one to see if match */
-               }
+               err_map = search_mapping_table_ERRDOS(smberrcode);
        } else if (smberrclass == ERRSRV) {
                /* server class of error codes */
-               for (i = 0;
-                    i <
-                    sizeof(mapping_table_ERRSRV) /
-                    sizeof(struct smb_to_posix_error); i++) {
-                       if (mapping_table_ERRSRV[i].smb_err == 0)
-                               break;
-                       else if (mapping_table_ERRSRV[i].smb_err ==
-                                                               smberrcode) {
-                               rc = mapping_table_ERRSRV[i].posix_code;
-                               break;
-                       }
-                       /* else try next error mapping to see if match */
-               }
+               err_map = search_mapping_table_ERRSRV(smberrcode);
        }
+       if (err_map)
+               rc = err_map->posix_code;
        /* else ERRHRD class errors or junk  - return EIO */
 
        /* special cases for NT status codes which cannot be translated to DOS codes */