History

Merge tag '6.6-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French: - fixes for excessive stack usage - multichannel reconnect improvements - DFS fix and cleanup patches - move UCS-2 conversion code to fs/nls and update cifs and jfs to use them - cleanup patch for compounding, one to fix confusing function name - inode number collision fix - reparse point fixes (including avoiding an extra unneeded query on symlinks) and a minor cleanup - directory lease (caching) improvement * tag '6.6-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6: (24 commits) fs/jfs: Use common ucs2 upper case table fs/smb/client: Use common code in client fs/smb: Swing unicode common code from smb->NLS fs/smb: Remove unicode 'lower' tables SMB3: rename macro CIFS_SERVER_IS_CHAN to avoid confusion [SMB3] send channel sequence number in SMB3 requests after reconnects cifs: update desired access while requesting for directory lease smb: client: reduce stack usage in smb2_query_reparse_point() smb: client: reduce stack usage in smb2_query_info_compound() smb: client: reduce stack usage in smb2_set_ea() smb: client: reduce stack usage in smb_send_rqst() smb: client: reduce stack usage in cifs_demultiplex_thread() smb: client: reduce stack usage in cifs_try_adding_channels() smb: cilent: set reparse mount points as automounts smb: client: query reparse points in older dialects smb: client: do not query reparse points twice on symlinks smb: client: parse reparse point flag in create response smb: client: get rid of dfs code dep in namespace.c smb: client: get rid of dfs naming in automount code smb: client: rename cifs_dfs_ref.c to namespace.c ...

Linus Torvalds committed 3 years ago

Commit b97d64c2 parents 47d154e f3a9b3743 files · +1377 −2021Browse files

Unified · Split

43 files
  1. fs/jfs/Kconfig +1 −0
  2. fs/jfs/Makefile +1 −1
  3. fs/jfs/jfs_unicode.h +5 −12
  4. fs/jfs/jfs_uniupr.c +0 −121
  5. fs/nls/Kconfig +8 −0
  6. fs/nls/Makefile +1 −0
  7. fs/nls/nls_ucs2_data.h +15 −0
  8. fs/nls/nls_ucs2_utils.c +17 −139
  9. fs/nls/nls_ucs2_utils.h +285 −0
  10. fs/smb/client/Kconfig +1 −0
  11. fs/smb/client/Makefile +3 −2
  12. fs/smb/client/cached_dir.c +1 −1
  13. fs/smb/client/cifs_debug.c +1 −1
  14. fs/smb/client/cifs_unicode.c +0 −1
  15. fs/smb/client/cifs_unicode.h +1 −329
  16. fs/smb/client/cifs_uniupr.h +0 −239
  17. fs/smb/client/cifsfs.c +1 −1
  18. fs/smb/client/cifsfs.h +2 −9
  19. fs/smb/client/cifsglob.h +58 −14
  20. fs/smb/client/cifsproto.h +4 −5
  21. fs/smb/client/connect.c +11 −10
  22. fs/smb/client/dfs.c +150 −121
  23. fs/smb/client/dfs.h +104 −37
  24. fs/smb/client/dfs_cache.c +4 −6
  25. fs/smb/client/dfs_cache.h +8 −4
  26. fs/smb/client/dir.c +2 −2
  27. fs/smb/client/inode.c +284 −214
  28. fs/smb/client/misc.c +1 −1
  29. fs/smb/client/namespace.c +62 −51
  30. fs/smb/client/readdir.c +7 −16
  31. fs/smb/client/sess.c +43 −29
  32. fs/smb/client/smb1ops.c +16 −10
  33. fs/smb/client/smb2inode.c +115 −88
  34. fs/smb/client/smb2misc.c +3 −3
  35. fs/smb/client/smb2ops.c +91 −207
  36. fs/smb/client/smb2pdu.c +15 −4
  37. fs/smb/client/smb2proto.h +10 −7
  38. fs/smb/client/smb2transport.c +2 −2
  39. fs/smb/client/transport.c +17 −12
  40. fs/smb/common/smb2pdu.h +22 −0
  41. fs/smb/server/Kconfig +1 −0
  42. fs/smb/server/unicode.c +0 −1
  43. fs/smb/server/unicode.h +4 −321
fs/jfs/Kconfig+1−0
@@ -3,6 +3,7 @@ config JFS_FS · 2 unmodified lines
33 tristate "JFS filesystem support"
44 select BUFFER_HEAD
55 select NLS
6+ select NLS_UCS2_UTILS
67 select CRC32
78 select LEGACY_DIRECT_IO
89 help
fs/jfs/Makefile+1−1
@@ -9,7 +9,7 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ · 8 unmodified lines
99 jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
1010 jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \
1111 jfs_extent.o symlink.o jfs_metapage.o \
12− jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
12+ jfs_logmgr.o jfs_txnmgr.o \
1313 resize.o xattr.o ioctl.o
1414
1515 jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
fs/jfs/jfs_unicode.h+5−12
@@ -8,16 +8,9 @@ · 7 unmodified lines
88
99 #include <linux/slab.h>
1010 #include <asm/byteorder.h>
11+#include "../nls/nls_ucs2_data.h"
1112 #include "jfs_types.h"
1213
13−typedef struct {
14− wchar_t start;
15− wchar_t end;
16− signed char *table;
17−} UNICASERANGE;
18−
19−extern signed char UniUpperTable[512];
20−extern UNICASERANGE UniUpperRange[];
2114 extern int get_UCSname(struct component_name *, struct dentry *);
2215 extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table *);
2316
@@ -107,12 +100,12 @@ static inline wchar_t *UniStrncpy_from_le(wchar_t * ucs1, const __le16 * ucs2, · 83 unmodified lines
107100 */
108101 static inline wchar_t UniToupper(wchar_t uc)
109102 {
110− UNICASERANGE *rp;
103+ const struct UniCaseRange *rp;
111104
112− if (uc < sizeof(UniUpperTable)) { /* Latin characters */
113− return uc + UniUpperTable[uc]; /* Use base tables */
105+ if (uc < sizeof(NlsUniUpperTable)) { /* Latin characters */
106+ return uc + NlsUniUpperTable[uc]; /* Use base tables */
114107 } else {
115− rp = UniUpperRange; /* Use range tables */
108+ rp = NlsUniUpperRange; /* Use range tables */
116109 while (rp->start) {
117110 if (uc < rp->start) /* Before start of range */
118111 return uc; /* Uppercase = input */
fs/jfs/jfs_uniupr.c+0−121
@@ -1,121 +0,0 @@
1−// SPDX-License-Identifier: GPL-2.0-or-later
2−/*
3− * Copyright (C) International Business Machines Corp., 2000-2002
4− */
5−
6−#include <linux/fs.h>
7−#include "jfs_unicode.h"
8−
9−/*
10− * Latin upper case
11− */
12−signed char UniUpperTable[512] = {
13− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
14− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
15− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
16− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
17− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
18− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
19− 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */
20− -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, 0, 0, 0, 0, 0, /* 070-07f */
21− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
22− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
23− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
24− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
25− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
26− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
27− -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */
28− -32,-32,-32,-32,-32,-32,-32, 0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */
29− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
30− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
31− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
32− 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
33− -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
34− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
35− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
36− 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
37− 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
38− 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
39− 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
40− -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
41− 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
42− -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,-79, 0, -1, /* 1d0-1df */
43− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
44− 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
45−};
46−
47−/* Upper case range - Greek */
48−static signed char UniCaseRangeU03a0[47] = {
49− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-38,-37,-37,-37, /* 3a0-3af */
50− 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */
51− -32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63,
52−};
53−
54−/* Upper case range - Cyrillic */
55−static signed char UniCaseRangeU0430[48] = {
56− -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */
57− -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */
58− 0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80, 0,-80,-80, /* 450-45f */
59−};
60−
61−/* Upper case range - Extended cyrillic */
62−static signed char UniCaseRangeU0490[61] = {
63− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
64− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
65− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
66− 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
67−};
68−
69−/* Upper case range - Extended latin and greek */
70−static signed char UniCaseRangeU1e00[509] = {
71− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
72− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
73− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
74− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
75− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
76− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
77− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
78− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
79− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
80− 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0,-59, 0, -1, 0, -1, /* 1e90-1e9f */
81− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
82− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
83− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
84− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
85− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
86− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
87− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
88− 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
89− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
90− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
91− 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
92− 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
93− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
94− 74, 74, 86, 86, 86, 86,100,100, 0, 0,112,112,126,126, 0, 0, /* 1f70-1f7f */
95− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
96− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
97− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
98− 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
99− 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
100− 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
101− 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
102− 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103−};
104−
105−/* Upper case range - Wide latin */
106−static signed char UniCaseRangeUff40[27] = {
107− 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */
108− -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,
109−};
110−
111−/*
112− * Upper Case Range
113− */
114−UNICASERANGE UniUpperRange[] = {
115− { 0x03a0, 0x03ce, UniCaseRangeU03a0 },
116− { 0x0430, 0x045f, UniCaseRangeU0430 },
117− { 0x0490, 0x04cc, UniCaseRangeU0490 },
118− { 0x1e00, 0x1ffc, UniCaseRangeU1e00 },
119− { 0xff40, 0xff5a, UniCaseRangeUff40 },
120− { 0 }
121−};
fs/nls/Kconfig+8−0
@@ -617,4 +617,12 @@ config NLS_UTF8 · 616 unmodified lines
617617 input/output character sets. Say Y here for the UTF-8 encoding of
618618 the Unicode/ISO9646 universal character set.
619619
620+config NLS_UCS2_UTILS
621+ tristate "NLS UCS-2 UTILS"
622+ help
623+ Set of older UCS-2 conversion utilities and tables used by some
624+ filesystems including SMB/CIFS. This includes upper case conversion
625+ tables. This will automatically be selected when the filesystem
626+ that uses it is selected.
627+
620628 endif # NLS
fs/nls/Makefile+1−0
@@ -54,3 +54,4 @@ obj-$(CONFIG_NLS_MAC_INUIT) += mac-inuit.o · 53 unmodified lines
5454 obj-$(CONFIG_NLS_MAC_ROMANIAN) += mac-romanian.o
5555 obj-$(CONFIG_NLS_MAC_ROMAN) += mac-roman.o
5656 obj-$(CONFIG_NLS_MAC_TURKISH) += mac-turkish.o
57+obj-$(CONFIG_NLS_UCS2_UTILS) += nls_ucs2_utils.o
fs/nls/nls_ucs2_data.h+15−0
@@ -0,0 +1,15 @@
1+/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
3+#ifndef _NLS_UCS2_DATA_H
4+#define _NLS_UCS2_DATA_H
5+
6+struct UniCaseRange {
7+ wchar_t start;
8+ wchar_t end;
9+ signed char *table;
10+};
11+
12+extern signed char NlsUniUpperTable[512];
13+extern const struct UniCaseRange NlsUniUpperRange[];
14+
15+#endif /* _NLS_UCS2_DATA_H */
fs/nls/nls_ucs2_utils.crenamed from fs/smb/server/uniupr.h+17−139
@@ -1,19 +1,27 @@
1−/* SPDX-License-Identifier: GPL-2.0-or-later */
1+// SPDX-License-Identifier: GPL-2.0-or-later
22 /*
33 * Some of the source code in this file came from fs/cifs/uniupr.h
44 * Copyright (c) International Business Machines Corp., 2000,2002
55 *
6− * uniupr.h - Unicode compressed case ranges
6+ * Some of the source code in this file came from fs/cifs/cifs_unicode.c
7+ *
8+ * Copyright (c) International Business Machines Corp., 2000,2009
9+ * Modified by Steve French (sfrench@us.ibm.com)
10+ * Modified by Namjae Jeon (linkinjeon@kernel.org)
711 *
812 */
9−#ifndef __KSMBD_UNIUPR_H
10−#define __KSMBD_UNIUPR_H
13+#include <linux/fs.h>
14+#include <linux/module.h>
15+#include <linux/slab.h>
16+#include <asm/unaligned.h>
17+#include "nls_ucs2_utils.h"
18+
19+MODULE_LICENSE("GPL");
1120
12−#ifndef UNIUPR_NOUPPER
1321 /*
1422 * Latin upper case
1523 */
16−signed char SmbUniUpperTable[512] = {
24+signed char NlsUniUpperTable[512] = {
1725 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
1826 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
1927 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
@@ -51,6 +59,7 @@ signed char SmbUniUpperTable[512] = { · 31 unmodified lines
5159 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
5260 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
5361 };
62+EXPORT_SYMBOL_GPL(NlsUniUpperTable);
5463
5564 /* Upper case range - Greek */
5665 static signed char UniCaseRangeU03a0[47] = {
@@ -126,7 +135,7 @@ static signed char UniCaseRangeUff40[27] = { · 69 unmodified lines
126135 /*
127136 * Upper Case Range
128137 */
129−const struct UniCaseRange SmbUniUpperRange[] = {
138+const struct UniCaseRange NlsUniUpperRange[] = {
130139 {0x03a0, 0x03ce, UniCaseRangeU03a0},
131140 {0x0430, 0x045f, UniCaseRangeU0430},
132141 {0x0490, 0x04cc, UniCaseRangeU0490},
@@ -134,135 +143,4 @@ const struct UniCaseRange SmbUniUpperRange[] = { · 1 unmodified line
134143 {0xff40, 0xff5a, UniCaseRangeUff40},
135144 {0}
136145 };
137−#endif
138−
139−#ifndef UNIUPR_NOLOWER
140−/*
141− * Latin lower case
142− */
143−signed char CifsUniLowerTable[512] = {
144− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
145− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
146− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
147− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
148− 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
149− 32, 32, 32, /* 040-04f */
150− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0,
151− 0, 0, 0, /* 050-05f */
152− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
153− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
154− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
155− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
156− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
157− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
158− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
159− 32, 32, 32, 32, /* 0c0-0cf */
160− 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32,
161− 32, 32, 32, 0, /* 0d0-0df */
162− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
163− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
164− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
165− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
166− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
167− 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
168− 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
169− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
170− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
171− 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0,
172− 0, /* 170-17f */
173− 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79,
174− 0, /* 180-18f */
175− 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
176− 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
177− 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
178− 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
179− 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
180− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
181− 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
182−};
183−
184−/* Lower case range - Greek */
185−static signed char UniCaseRangeL0380[44] = {
186− 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
187− 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
188− 32, 32, 32, /* 390-39f */
189− 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
190−};
191−
192−/* Lower case range - Cyrillic */
193−static signed char UniCaseRangeL0400[48] = {
194− 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
195− 0, 80, 80, /* 400-40f */
196− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
197− 32, 32, 32, /* 410-41f */
198− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
199− 32, 32, 32, /* 420-42f */
200−};
201−
202−/* Lower case range - Extended cyrillic */
203−static signed char UniCaseRangeL0490[60] = {
204− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
205− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
206− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
207− 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
208−};
209−
210−/* Lower case range - Extended latin and greek */
211−static signed char UniCaseRangeL1e00[504] = {
212− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
213− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
214− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
215− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
216− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
217− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
218− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
219− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
220− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
221− 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
222− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
223− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
224− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
225− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
226− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
227− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
228− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
229− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
230− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
231− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
232− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
233− 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
234− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
235− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
236− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
237− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
238− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
239− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
240− 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0,
241− 0, 0, /* 1fc0-1fcf */
242− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
243− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0,
244− 0, 0, /* 1fe0-1fef */
245− 0, 0, 0, 0, 0, 0, 0, 0,
246−};
247−
248−/* Lower case range - Wide latin */
249−static signed char UniCaseRangeLff20[27] = {
250− 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
251− 32, /* ff20-ff2f */
252− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
253−};
254−
255−/*
256− * Lower Case Range
257− */
258−const struct UniCaseRange CifsUniLowerRange[] = {
259− {0x0380, 0x03ab, UniCaseRangeL0380},
260− {0x0400, 0x042f, UniCaseRangeL0400},
261− {0x0490, 0x04cb, UniCaseRangeL0490},
262− {0x1e00, 0x1ff7, UniCaseRangeL1e00},
263− {0xff20, 0xff3a, UniCaseRangeLff20},
264− {0}
265−};
266−#endif
267−
268−#endif /* __KSMBD_UNIUPR_H */
146+EXPORT_SYMBOL_GPL(NlsUniUpperRange);
fs/nls/nls_ucs2_utils.h+285−0
@@ -0,0 +1,285 @@
1+/* SPDX-License-Identifier: GPL-2.0-or-later */
2+/*
3+ * Some of the source code in this file came from fs/cifs/cifs_unicode.c
4+ * and then via server/unicode.c
5+ * cifs_unicode: Unicode kernel case support
6+ *
7+ * Function:
8+ * Convert a unicode character to upper or lower case using
9+ * compressed tables.
10+ *
11+ * Copyright (c) International Business Machines Corp., 2000,2009
12+ *
13+ *
14+ * Notes:
15+ * These APIs are based on the C library functions. The semantics
16+ * should match the C functions but with expanded size operands.
17+ *
18+ * The upper/lower functions are based on a table created by mkupr.
19+ * This is a compressed table of upper and lower case conversion.
20+ *
21+ */
22+#ifndef _NLS_UCS2_UTILS_H
23+#define _NLS_UCS2_UTILS_H
24+
25+#include <asm/byteorder.h>
26+#include <linux/types.h>
27+#include <linux/nls.h>
28+#include <linux/unicode.h>
29+#include "nls_ucs2_data.h"
30+
31+/*
32+ * Windows maps these to the user defined 16 bit Unicode range since they are
33+ * reserved symbols (along with \ and /), otherwise illegal to store
34+ * in filenames in NTFS
35+ */
36+#define UNI_ASTERISK ((__u16)('*' + 0xF000))
37+#define UNI_QUESTION ((__u16)('?' + 0xF000))
38+#define UNI_COLON ((__u16)(':' + 0xF000))
39+#define UNI_GRTRTHAN ((__u16)('>' + 0xF000))
40+#define UNI_LESSTHAN ((__u16)('<' + 0xF000))
41+#define UNI_PIPE ((__u16)('|' + 0xF000))
42+#define UNI_SLASH ((__u16)('\\' + 0xF000))
43+
44+/*
45+ * UniStrcat: Concatenate the second string to the first
46+ *
47+ * Returns:
48+ * Address of the first string
49+ */
50+static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
51+{
52+ wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
53+
54+ while (*ucs1++)
55+ /*NULL*/; /* To end of first string */
56+ ucs1--; /* Return to the null */
57+ while ((*ucs1++ = *ucs2++))
58+ /*NULL*/; /* copy string 2 over */
59+ return anchor;
60+}
61+
62+/*
63+ * UniStrchr: Find a character in a string
64+ *
65+ * Returns:
66+ * Address of first occurrence of character in string
67+ * or NULL if the character is not in the string
68+ */
69+static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
70+{
71+ while ((*ucs != uc) && *ucs)
72+ ucs++;
73+
74+ if (*ucs == uc)
75+ return (wchar_t *)ucs;
76+ return NULL;
77+}
78+
79+/*
80+ * UniStrcmp: Compare two strings
81+ *
82+ * Returns:
83+ * < 0: First string is less than second
84+ * = 0: Strings are equal
85+ * > 0: First string is greater than second
86+ */
87+static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
88+{
89+ while ((*ucs1 == *ucs2) && *ucs1) {
90+ ucs1++;
91+ ucs2++;
92+ }
93+ return (int)*ucs1 - (int)*ucs2;
94+}
95+
96+/*
97+ * UniStrcpy: Copy a string
98+ */
99+static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
100+{
101+ wchar_t *anchor = ucs1; /* save the start of result string */
102+
103+ while ((*ucs1++ = *ucs2++))
104+ /*NULL*/;
105+ return anchor;
106+}
107+
108+/*
109+ * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
110+ */
111+static inline size_t UniStrlen(const wchar_t *ucs1)
112+{
113+ int i = 0;
114+
115+ while (*ucs1++)
116+ i++;
117+ return i;
118+}
119+
120+/*
121+ * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
122+ * string (length limited)
123+ */
124+static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
125+{
126+ int i = 0;
127+
128+ while (*ucs1++) {
129+ i++;
130+ if (i >= maxlen)
131+ break;
132+ }
133+ return i;
134+}
135+
136+/*
137+ * UniStrncat: Concatenate length limited string
138+ */
139+static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
140+{
141+ wchar_t *anchor = ucs1; /* save pointer to string 1 */
142+
143+ while (*ucs1++)
144+ /*NULL*/;
145+ ucs1--; /* point to null terminator of s1 */
146+ while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
147+ ucs1++;
148+ ucs2++;
149+ }
150+ *ucs1 = 0; /* Null terminate the result */
151+ return anchor;
152+}
153+
154+/*
155+ * UniStrncmp: Compare length limited string
156+ */
157+static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
158+{
159+ if (!n)
160+ return 0; /* Null strings are equal */
161+ while ((*ucs1 == *ucs2) && *ucs1 && --n) {
162+ ucs1++;
163+ ucs2++;
164+ }
165+ return (int)*ucs1 - (int)*ucs2;
166+}
167+
168+/*
169+ * UniStrncmp_le: Compare length limited string - native to little-endian
170+ */
171+static inline int
172+UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
173+{
174+ if (!n)
175+ return 0; /* Null strings are equal */
176+ while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
177+ ucs1++;
178+ ucs2++;
179+ }
180+ return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
181+}
182+
183+/*
184+ * UniStrncpy: Copy length limited string with pad
185+ */
186+static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
187+{
188+ wchar_t *anchor = ucs1;
189+
190+ while (n-- && *ucs2) /* Copy the strings */
191+ *ucs1++ = *ucs2++;
192+
193+ n++;
194+ while (n--) /* Pad with nulls */
195+ *ucs1++ = 0;
196+ return anchor;
197+}
198+
199+/*
200+ * UniStrncpy_le: Copy length limited string with pad to little-endian
201+ */
202+static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
203+{
204+ wchar_t *anchor = ucs1;
205+
206+ while (n-- && *ucs2) /* Copy the strings */
207+ *ucs1++ = __le16_to_cpu(*ucs2++);
208+
209+ n++;
210+ while (n--) /* Pad with nulls */
211+ *ucs1++ = 0;
212+ return anchor;
213+}
214+
215+/*
216+ * UniStrstr: Find a string in a string
217+ *
218+ * Returns:
219+ * Address of first match found
220+ * NULL if no matching string is found
221+ */
222+static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
223+{
224+ const wchar_t *anchor1 = ucs1;
225+ const wchar_t *anchor2 = ucs2;
226+
227+ while (*ucs1) {
228+ if (*ucs1 == *ucs2) {
229+ /* Partial match found */
230+ ucs1++;
231+ ucs2++;
232+ } else {
233+ if (!*ucs2) /* Match found */
234+ return (wchar_t *)anchor1;
235+ ucs1 = ++anchor1; /* No match */
236+ ucs2 = anchor2;
237+ }
238+ }
239+
240+ if (!*ucs2) /* Both end together */
241+ return (wchar_t *)anchor1; /* Match found */
242+ return NULL; /* No match */
243+}
244+
245+#ifndef UNIUPR_NOUPPER
246+/*
247+ * UniToupper: Convert a unicode character to upper case
248+ */
249+static inline wchar_t UniToupper(register wchar_t uc)
250+{
251+ register const struct UniCaseRange *rp;
252+
253+ if (uc < sizeof(NlsUniUpperTable)) {
254+ /* Latin characters */
255+ return uc + NlsUniUpperTable[uc]; /* Use base tables */
256+ }
257+
258+ rp = NlsUniUpperRange; /* Use range tables */
259+ while (rp->start) {
260+ if (uc < rp->start) /* Before start of range */
261+ return uc; /* Uppercase = input */
262+ if (uc <= rp->end) /* In range */
263+ return uc + rp->table[uc - rp->start];
264+ rp++; /* Try next range */
265+ }
266+ return uc; /* Past last range */
267+}
268+
269+/*
270+ * UniStrupr: Upper case a unicode string
271+ */
272+static inline __le16 *UniStrupr(register __le16 *upin)
273+{
274+ register __le16 *up;
275+
276+ up = upin;
277+ while (*up) { /* For all characters */
278+ *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
279+ up++;
280+ }
281+ return upin; /* Return input pointer */
282+}
283+#endif /* UNIUPR_NOUPPER */
284+
285+#endif /* _NLS_UCS2_UTILS_H */
fs/smb/client/Kconfig+1−0
@@ -3,6 +3,7 @@ config CIFS · 2 unmodified lines
33 tristate "SMB3 and CIFS support (advanced network filesystem)"
44 depends on INET
55 select NLS
6+ select NLS_UCS2_UTILS
67 select CRYPTO
78 select CRYPTO_MD5
89 select CRYPTO_SHA256
fs/smb/client/Makefile+3−2
@@ -11,7 +11,8 @@ cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \ · 10 unmodified lines
1111 readdir.o ioctl.o sess.o export.o unc.o winucase.o \
1212 smb2ops.o smb2maperror.o smb2transport.o \
1313 smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
14− dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
14+ dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o \
15+ namespace.o
1516
1617 $(obj)/asn1.o: $(obj)/cifs_spnego_negtokeninit.asn1.h
1718
@@ -21,7 +22,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o · 3 unmodified lines
2122
2223 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
2324
24−cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o
25+cifs-$(CONFIG_CIFS_DFS_UPCALL) += dfs_cache.o dfs.o
2526
2627 cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
2728
fs/smb/client/cached_dir.c+1−1
@@ -218,7 +218,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, · 217 unmodified lines
218218 .tcon = tcon,
219219 .path = path,
220220 .create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
221− .desired_access = FILE_READ_ATTRIBUTES,
221+ .desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES,
222222 .disposition = FILE_OPEN,
223223 .fid = pfid,
224224 };
fs/smb/client/cifs_debug.c+1−1
@@ -331,7 +331,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) · 330 unmodified lines
331331 spin_lock(&cifs_tcp_ses_lock);
332332 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
333333 /* channel info will be printed as a part of sessions below */
334− if (CIFS_SERVER_IS_CHAN(server))
334+ if (SERVER_IS_CHAN(server))
335335 continue;
336336
337337 c++;
fs/smb/client/cifs_unicode.c+0−1
@@ -8,7 +8,6 @@ · 7 unmodified lines
88 #include <linux/slab.h>
99 #include "cifs_fs_sb.h"
1010 #include "cifs_unicode.h"
11−#include "cifs_uniupr.h"
1211 #include "cifspdu.h"
1312 #include "cifsglob.h"
1413 #include "cifs_debug.h"
fs/smb/client/cifs_unicode.h+1−329
@@ -21,21 +21,7 @@ · 20 unmodified lines
2121 #include <asm/byteorder.h>
2222 #include <linux/types.h>
2323 #include <linux/nls.h>
24−
25−#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
26−
27−/*
28− * Windows maps these to the user defined 16 bit Unicode range since they are
29− * reserved symbols (along with \ and /), otherwise illegal to store
30− * in filenames in NTFS
31− */
32−#define UNI_ASTERISK (__u16) ('*' + 0xF000)
33−#define UNI_QUESTION (__u16) ('?' + 0xF000)
34−#define UNI_COLON (__u16) (':' + 0xF000)
35−#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
36−#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
37−#define UNI_PIPE (__u16) ('|' + 0xF000)
38−#define UNI_SLASH (__u16) ('\\' + 0xF000)
24+#include "../../nls/nls_ucs2_utils.h"
3925
4026 /*
4127 * Macs use an older "SFM" mapping of the symbols above. Fortunately it does
@@ -68,27 +54,6 @@ · 26 unmodified lines
6854 #define SFM_MAP_UNI_RSVD 1
6955 #define SFU_MAP_UNI_RSVD 2
7056
71−/* Just define what we want from uniupr.h. We don't want to define the tables
72− * in each source file.
73− */
74−#ifndef UNICASERANGE_DEFINED
75−struct UniCaseRange {
76− wchar_t start;
77− wchar_t end;
78− signed char *table;
79−};
80−#endif /* UNICASERANGE_DEFINED */
81−
82−#ifndef UNIUPR_NOUPPER
83−extern signed char CifsUniUpperTable[512];
84−extern const struct UniCaseRange CifsUniUpperRange[];
85−#endif /* UNIUPR_NOUPPER */
86−
87−#ifndef UNIUPR_NOLOWER
88−extern signed char CifsUniLowerTable[512];
89−extern const struct UniCaseRange CifsUniLowerRange[];
90−#endif /* UNIUPR_NOLOWER */
91−
9257 #ifdef __KERNEL__
9358 int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
9459 const struct nls_table *cp, int map_type);
@@ -108,297 +73,4 @@ extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen, · 13 unmodified lines
10873
10974 wchar_t cifs_toupper(wchar_t in);
11075
111−/*
112− * UniStrcat: Concatenate the second string to the first
113− *
114− * Returns:
115− * Address of the first string
116− */
117−static inline __le16 *
118−UniStrcat(__le16 *ucs1, const __le16 *ucs2)
119−{
120− __le16 *anchor = ucs1; /* save a pointer to start of ucs1 */
121−
122− while (*ucs1++) ; /* To end of first string */
123− ucs1--; /* Return to the null */
124− while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */
125− return anchor;
126−}
127−
128−/*
129− * UniStrchr: Find a character in a string
130− *
131− * Returns:
132− * Address of first occurrence of character in string
133− * or NULL if the character is not in the string
134− */
135−static inline wchar_t *
136−UniStrchr(const wchar_t *ucs, wchar_t uc)
137−{
138− while ((*ucs != uc) && *ucs)
139− ucs++;
140−
141− if (*ucs == uc)
142− return (wchar_t *) ucs;
143− return NULL;
144−}
145−
146−/*
147− * UniStrcmp: Compare two strings
148− *
149− * Returns:
150− * < 0: First string is less than second
151− * = 0: Strings are equal
152− * > 0: First string is greater than second
153− */
154−static inline int
155−UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
156−{
157− while ((*ucs1 == *ucs2) && *ucs1) {
158− ucs1++;
159− ucs2++;
160− }
161− return (int) *ucs1 - (int) *ucs2;
162−}
163−
164−/*
165− * UniStrcpy: Copy a string
166− */
167−static inline wchar_t *
168−UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
169−{
170− wchar_t *anchor = ucs1; /* save the start of result string */
171−
172− while ((*ucs1++ = *ucs2++)) ;
173− return anchor;
174−}
175−
176−/*
177− * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
178− */
179−static inline size_t
180−UniStrlen(const wchar_t *ucs1)
181−{
182− int i = 0;
183−
184− while (*ucs1++)
185− i++;
186− return i;
187−}
188−
189−/*
190− * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
191− * string (length limited)
192− */
193−static inline size_t
194−UniStrnlen(const wchar_t *ucs1, int maxlen)
195−{
196− int i = 0;
197−
198− while (*ucs1++) {
199− i++;
200− if (i >= maxlen)
201− break;
202− }
203− return i;
204−}
205−
206−/*
207− * UniStrncat: Concatenate length limited string
208− */
209−static inline wchar_t *
210−UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
211−{
212− wchar_t *anchor = ucs1; /* save pointer to string 1 */
213−
214− while (*ucs1++) ;
215− ucs1--; /* point to null terminator of s1 */
216− while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
217− ucs1++;
218− ucs2++;
219− }
220− *ucs1 = 0; /* Null terminate the result */
221− return (anchor);
222−}
223−
224−/*
225− * UniStrncmp: Compare length limited string
226− */
227−static inline int
228−UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
229−{
230− if (!n)
231− return 0; /* Null strings are equal */
232− while ((*ucs1 == *ucs2) && *ucs1 && --n) {
233− ucs1++;
234− ucs2++;
235− }
236− return (int) *ucs1 - (int) *ucs2;
237−}
238−
239−/*
240− * UniStrncmp_le: Compare length limited string - native to little-endian
241− */
242−static inline int
243−UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
244−{
245− if (!n)
246− return 0; /* Null strings are equal */
247− while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
248− ucs1++;
249− ucs2++;
250− }
251− return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
252−}
253−
254−/*
255− * UniStrncpy: Copy length limited string with pad
256− */
257−static inline wchar_t *
258−UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
259−{
260− wchar_t *anchor = ucs1;
261−
262− while (n-- && *ucs2) /* Copy the strings */
263− *ucs1++ = *ucs2++;
264−
265− n++;
266− while (n--) /* Pad with nulls */
267− *ucs1++ = 0;
268− return anchor;
269−}
270−
271−/*
272− * UniStrncpy_le: Copy length limited string with pad to little-endian
273− */
274−static inline wchar_t *
275−UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
276−{
277− wchar_t *anchor = ucs1;
278−
279− while (n-- && *ucs2) /* Copy the strings */
280− *ucs1++ = __le16_to_cpu(*ucs2++);
281−
282− n++;
283− while (n--) /* Pad with nulls */
284− *ucs1++ = 0;
285− return anchor;
286−}
287−
288−/*
289− * UniStrstr: Find a string in a string
290− *
291− * Returns:
292− * Address of first match found
293− * NULL if no matching string is found
294− */
295−static inline wchar_t *
296−UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
297−{
298− const wchar_t *anchor1 = ucs1;
299− const wchar_t *anchor2 = ucs2;
300−
301− while (*ucs1) {
302− if (*ucs1 == *ucs2) {
303− /* Partial match found */
304− ucs1++;
305− ucs2++;
306− } else {
307− if (!*ucs2) /* Match found */
308− return (wchar_t *) anchor1;
309− ucs1 = ++anchor1; /* No match */
310− ucs2 = anchor2;
311− }
312− }
313−
314− if (!*ucs2) /* Both end together */
315− return (wchar_t *) anchor1; /* Match found */
316− return NULL; /* No match */
317−}
318−
319−#ifndef UNIUPR_NOUPPER
320−/*
321− * UniToupper: Convert a unicode character to upper case
322− */
323−static inline wchar_t
324−UniToupper(register wchar_t uc)
325−{
326− register const struct UniCaseRange *rp;
327−
328− if (uc < sizeof(CifsUniUpperTable)) {
329− /* Latin characters */
330− return uc + CifsUniUpperTable[uc]; /* Use base tables */
331− } else {
332− rp = CifsUniUpperRange; /* Use range tables */
333− while (rp->start) {
334− if (uc < rp->start) /* Before start of range */
335− return uc; /* Uppercase = input */
336− if (uc <= rp->end) /* In range */
337− return uc + rp->table[uc - rp->start];
338− rp++; /* Try next range */
339− }
340− }
341− return uc; /* Past last range */
342−}
343−
344−/*
345− * UniStrupr: Upper case a unicode string
346− */
347−static inline __le16 *
348−UniStrupr(register __le16 *upin)
349−{
350− register __le16 *up;
351−
352− up = upin;
353− while (*up) { /* For all characters */
354− *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
355− up++;
356− }
357− return upin; /* Return input pointer */
358−}
359−#endif /* UNIUPR_NOUPPER */
360−
361−#ifndef UNIUPR_NOLOWER
362−/*
363− * UniTolower: Convert a unicode character to lower case
364− */
365−static inline wchar_t
366−UniTolower(register wchar_t uc)
367−{
368− register const struct UniCaseRange *rp;
369−
370− if (uc < sizeof(CifsUniLowerTable)) {
371− /* Latin characters */
372− return uc + CifsUniLowerTable[uc]; /* Use base tables */
373− } else {
374− rp = CifsUniLowerRange; /* Use range tables */
375− while (rp->start) {
376− if (uc < rp->start) /* Before start of range */
377− return uc; /* Uppercase = input */
378− if (uc <= rp->end) /* In range */
379− return uc + rp->table[uc - rp->start];
380− rp++; /* Try next range */
381− }
382− }
383− return uc; /* Past last range */
384−}
385−
386−/*
387− * UniStrlwr: Lower case a unicode string
388− */
389−static inline wchar_t *
390−UniStrlwr(register wchar_t *upin)
391−{
392− register wchar_t *up;
393−
394− up = upin;
395− while (*up) { /* For all characters */
396− *up = UniTolower(*up);
397− up++;
398− }
399− return upin; /* Return input pointer */
400−}
401−
402−#endif
403−
40476 #endif /* _CIFS_UNICODE_H */
fs/smb/client/cifs_uniupr.h+0−239
@@ -1,239 +0,0 @@
1−/* SPDX-License-Identifier: GPL-2.0-or-later */
2−/*
3− * Copyright (c) International Business Machines Corp., 2000,2002
4− *
5− * uniupr.h - Unicode compressed case ranges
6−*/
7−
8−#ifndef UNIUPR_NOUPPER
9−/*
10− * Latin upper case
11− */
12−signed char CifsUniUpperTable[512] = {
13− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
14− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
15− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
16− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
17− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
18− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
19− 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */
20− -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */
21− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
22− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
23− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
24− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
25− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
26− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
27− -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */
28− -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */
29− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
30− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
31− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
32− 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
33− -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
34− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
35− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
36− 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
37− 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
38− 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
39− 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
40− -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
41− 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
42− -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
43− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
44− 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
45−};
46−
47−/* Upper case range - Greek */
48−static signed char UniCaseRangeU03a0[47] = {
49− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */
50− 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */
51− -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64,
52− -63, -63,
53−};
54−
55−/* Upper case range - Cyrillic */
56−static signed char UniCaseRangeU0430[48] = {
57− -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */
58− -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */
59− 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */
60−};
61−
62−/* Upper case range - Extended cyrillic */
63−static signed char UniCaseRangeU0490[61] = {
64− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
65− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
66− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
67− 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
68−};
69−
70−/* Upper case range - Extended latin and greek */
71−static signed char UniCaseRangeU1e00[509] = {
72− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
73− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
74− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
75− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
76− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
77− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
78− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
79− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
80− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
81− 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */
82− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
83− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
84− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
85− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
86− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
87− 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
88− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
89− 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
90− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
91− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
92− 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
93− 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
94− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
95− 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */
96− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
97− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
98− 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
99− 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
100− 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
101− 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
102− 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
103− 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104−};
105−
106−/* Upper case range - Wide latin */
107−static signed char UniCaseRangeUff40[27] = {
108− 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */
109− -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
110−};
111−
112−/*
113− * Upper Case Range
114− */
115−const struct UniCaseRange CifsUniUpperRange[] = {
116− {0x03a0, 0x03ce, UniCaseRangeU03a0},
117− {0x0430, 0x045f, UniCaseRangeU0430},
118− {0x0490, 0x04cc, UniCaseRangeU0490},
119− {0x1e00, 0x1ffc, UniCaseRangeU1e00},
120− {0xff40, 0xff5a, UniCaseRangeUff40},
121− {0}
122−};
123−#endif
124−
125−#ifndef UNIUPR_NOLOWER
126−/*
127− * Latin lower case
128− */
129−signed char CifsUniLowerTable[512] = {
130− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
131− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
132− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
133− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
134− 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */
135− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */
136− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
137− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
138− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
139− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
140− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
141− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
142− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */
143− 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */
144− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
145− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
146− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
147− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
148− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
149− 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
150− 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
151− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
152− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
153− 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */
154− 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */
155− 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
156− 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
157− 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
158− 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
159− 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
160− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
161− 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
162−};
163−
164−/* Lower case range - Greek */
165−static signed char UniCaseRangeL0380[44] = {
166− 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
167− 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */
168− 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
169−};
170−
171−/* Lower case range - Cyrillic */
172−static signed char UniCaseRangeL0400[48] = {
173− 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */
174− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */
175− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */
176−};
177−
178−/* Lower case range - Extended cyrillic */
179−static signed char UniCaseRangeL0490[60] = {
180− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
181− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
182− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
183− 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
184−};
185−
186−/* Lower case range - Extended latin and greek */
187−static signed char UniCaseRangeL1e00[504] = {
188− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
189− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
190− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
191− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
192− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
193− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
194− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
195− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
196− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
197− 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
198− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
199− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
200− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
201− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
202− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
203− 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
204− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
205− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
206− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
207− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
208− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
209− 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
210− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
211− 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
212− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
213− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
214− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
215− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
216− 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */
217− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
218− 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */
219− 0, 0, 0, 0, 0, 0, 0, 0,
220−};
221−
222−/* Lower case range - Wide latin */
223−static signed char UniCaseRangeLff20[27] = {
224− 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */
225− 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
226−};
227−
228−/*
229− * Lower Case Range
230− */
231−const struct UniCaseRange CifsUniLowerRange[] = {
232− {0x0380, 0x03ab, UniCaseRangeL0380},
233− {0x0400, 0x042f, UniCaseRangeL0400},
234− {0x0490, 0x04cb, UniCaseRangeL0490},
235− {0x1e00, 0x1ff7, UniCaseRangeL1e00},
236− {0xff20, 0xff3a, UniCaseRangeLff20},
237− {0}
238−};
239−#endif
fs/smb/client/cifsfs.c+1−1
@@ -1805,7 +1805,7 @@ exit_cifs(void) · 1804 unmodified lines
18051805 cifs_dbg(NOISY, "exit_smb3\n");
18061806 unregister_filesystem(&cifs_fs_type);
18071807 unregister_filesystem(&smb3_fs_type);
1808− cifs_dfs_release_automount_timer();
1808+ cifs_release_automount_timer();
18091809 exit_cifs_idmap();
18101810 #ifdef CONFIG_CIFS_SWN_UPCALL
18111811 cifs_genl_exit();
fs/smb/client/cifsfs.h+2−9
@@ -81,7 +81,7 @@ extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start, · 80 unmodified lines
8181
8282 extern const struct inode_operations cifs_file_inode_ops;
8383 extern const struct inode_operations cifs_symlink_inode_ops;
84−extern const struct inode_operations cifs_dfs_referral_inode_operations;
84+extern const struct inode_operations cifs_namespace_inode_operations;
8585
8686
8787 /* Functions related to files and directories */
@@ -118,14 +118,7 @@ extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned · 30 unmodified lines
118118 extern const struct dentry_operations cifs_dentry_ops;
119119 extern const struct dentry_operations cifs_ci_dentry_ops;
120120
121−#ifdef CONFIG_CIFS_DFS_UPCALL
122−extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
123−#else
124−static inline struct vfsmount *cifs_dfs_d_automount(struct path *path)
125−{
126− return ERR_PTR(-EREMOTE);
127−}
128−#endif
121+extern struct vfsmount *cifs_d_automount(struct path *path);
129122
130123 /* Functions related to symlinks */
131124 extern const char *cifs_get_link(struct dentry *, struct inode *,
fs/smb/client/cifsglob.h+58−14
@@ -186,6 +186,12 @@ struct cifs_cred { · 185 unmodified lines
186186 };
187187
188188 struct cifs_open_info_data {
189+ bool adjust_tz;
190+ union {
191+ bool reparse_point;
192+ bool symlink;
193+ };
194+ __u32 reparse_tag;
189195 char *symlink_target;
190196 union {
191197 struct smb2_file_all_info fi;
@@ -193,6 +199,10 @@ struct cifs_open_info_data { · 1 unmodified line
193199 };
194200 };
195201
202+#define cifs_open_data_reparse(d) \
203+ ((d)->reparse_point || \
204+ (le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
205+
196206 static inline void cifs_free_open_info(struct cifs_open_info_data *data)
197207 {
198208 kfree(data->symlink_target);
@@ -318,16 +328,21 @@ struct smb_version_operations { · 119 unmodified lines
318328 int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
319329 struct cifs_sb_info *, const char *);
320330 /* query path data from the server */
321− int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon,
322− struct cifs_sb_info *cifs_sb, const char *full_path,
323− struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
331+ int (*query_path_info)(const unsigned int xid,
332+ struct cifs_tcon *tcon,
333+ struct cifs_sb_info *cifs_sb,
334+ const char *full_path,
335+ struct cifs_open_info_data *data);
324336 /* query file data from the server */
325337 int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
326338 struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
327− /* query reparse tag from srv to determine which type of special file */
328− int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
329− struct cifs_sb_info *cifs_sb, const char *path,
330− __u32 *reparse_tag);
339+ /* query reparse point to determine which type of special file */
340+ int (*query_reparse_point)(const unsigned int xid,
341+ struct cifs_tcon *tcon,
342+ struct cifs_sb_info *cifs_sb,
343+ const char *full_path,
344+ u32 *tag, struct kvec *rsp,
345+ int *rsp_buftype);
331346 /* get server index number */
332347 int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
333348 struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid,
@@ -376,9 +391,12 @@ struct smb_version_operations { · 42 unmodified lines
376391 const char *, const char *,
377392 struct cifs_sb_info *);
378393 /* query symlink target */
379− int (*query_symlink)(const unsigned int, struct cifs_tcon *,
380− struct cifs_sb_info *, const char *,
381− char **, bool);
394+ int (*query_symlink)(const unsigned int xid,
395+ struct cifs_tcon *tcon,
396+ struct cifs_sb_info *cifs_sb,
397+ const char *full_path,
398+ char **target_path,
399+ struct kvec *rsp_iov);
382400 /* open a file for non-posix mounts */
383401 int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
384402 void *buf);
@@ -727,8 +745,9 @@ struct TCP_Server_Info { · 342 unmodified lines
727745 * primary_server holds the ref-counted
728746 * pointer to primary channel connection for the session.
729747 */
730−#define CIFS_SERVER_IS_CHAN(server) (!!(server)->primary_server)
748+#define SERVER_IS_CHAN(server) (!!(server)->primary_server)
731749 struct TCP_Server_Info *primary_server;
750+ __u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */
732751
733752 #ifdef CONFIG_CIFS_SWN_UPCALL
734753 bool use_swn_dstaddr;
@@ -1076,7 +1095,7 @@ cap_unix(struct cifs_ses *ses) · 341 unmodified lines
10761095 * inode with new info
10771096 */
10781097
1079−#define CIFS_FATTR_DFS_REFERRAL 0x1
1098+#define CIFS_FATTR_JUNCTION 0x1
10801099 #define CIFS_FATTR_DELETE_PENDING 0x2
10811100 #define CIFS_FATTR_NEED_REVAL 0x4
10821101 #define CIFS_FATTR_INO_COLLISION 0x8
@@ -1721,11 +1740,23 @@ struct cifs_mount_ctx { · 638 unmodified lines
17211740 struct list_head dfs_ses_list;
17221741 };
17231742
1743+static inline void __free_dfs_info_param(struct dfs_info3_param *param)
1744+{
1745+ kfree(param->path_name);
1746+ kfree(param->node_name);
1747+}
1748+
17241749 static inline void free_dfs_info_param(struct dfs_info3_param *param)
1750+{
1751+ if (param)
1752+ __free_dfs_info_param(param);
1753+}
1754+
1755+static inline void zfree_dfs_info_param(struct dfs_info3_param *param)
17251756 {
17261757 if (param) {
1727− kfree(param->path_name);
1728− kfree(param->node_name);
1758+ __free_dfs_info_param(param);
1759+ memset(param, 0, sizeof(*param));
17291760 }
17301761 }
17311762
@@ -2184,4 +2215,17 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable, · 452 unmodified lines
21842215 }
21852216 }
21862217
2218+struct smb2_compound_vars {
2219+ struct cifs_open_parms oparms;
2220+ struct kvec rsp_iov[3];
2221+ struct smb_rqst rqst[3];
2222+ struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
2223+ struct kvec qi_iov;
2224+ struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
2225+ struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
2226+ struct kvec close_iov;
2227+ struct smb2_file_rename_info rename_info;
2228+ struct smb2_file_link_info link_info;
2229+};
2230+
21872231 #endif /* _CIFS_GLOB_H */
fs/smb/client/cifsproto.h+4−5
@@ -207,6 +207,9 @@ extern struct inode *cifs_iget(struct super_block *sb, · 206 unmodified lines
207207 int cifs_get_inode_info(struct inode **inode, const char *full_path,
208208 struct cifs_open_info_data *data, struct super_block *sb, int xid,
209209 const struct cifs_fid *fid);
210+bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
211+ struct cifs_fattr *fattr,
212+ u32 tag);
210213 extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
211214 struct super_block *sb, unsigned int xid);
212215 extern int cifs_get_inode_info_unix(struct inode **pinode,
@@ -295,11 +298,7 @@ extern void cifs_put_tcp_session(struct TCP_Server_Info *server, · 82 unmodified lines
295298 int from_reconnect);
296299 extern void cifs_put_tcon(struct cifs_tcon *tcon);
297300
298−#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
299−extern void cifs_dfs_release_automount_timer(void);
300−#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
301−#define cifs_dfs_release_automount_timer() do { } while (0)
302−#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
301+extern void cifs_release_automount_timer(void);
303302
304303 void cifs_proc_init(void);
305304 void cifs_proc_clean(void);
fs/smb/client/connect.c+11−10
@@ -154,7 +154,7 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, · 153 unmodified lines
154154 int i;
155155
156156 /* If server is a channel, select the primary channel */
157− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
157+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
158158
159159 spin_lock(&pserver->srv_lock);
160160 if (!all_channels) {
@@ -202,7 +202,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, · 41 unmodified lines
202202 cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__);
203203
204204 /* If server is a channel, select the primary channel */
205− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
205+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
206206
207207
208208 spin_lock(&cifs_tcp_ses_lock);
@@ -453,10 +453,10 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_ · 244 unmodified lines
453453
454454 static int reconnect_dfs_server(struct TCP_Server_Info *server)
455455 {
456− int rc = 0;
457− struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
458456 struct dfs_cache_tgt_iterator *target_hint = NULL;
457+ DFS_CACHE_TGT_LIST(tl);
459458 int num_targets = 0;
459+ int rc = 0;
460460
461461 /*
462462 * Determine the number of dfs targets the referral path in @cifs_sb resolves to.
@@ -911,8 +911,8 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) · 448 unmodified lines
911911 return 0;
912912 }
913913
914−
915−static void clean_demultiplex_info(struct TCP_Server_Info *server)
914+static noinline_for_stack void
915+clean_demultiplex_info(struct TCP_Server_Info *server)
916916 {
917917 int length;
918918
@@ -1551,7 +1551,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx) · 632 unmodified lines
15511551 * Skip ses channels since they're only handled in lower layers
15521552 * (e.g. cifs_send_recv).
15531553 */
1554− if (CIFS_SERVER_IS_CHAN(server) ||
1554+ if (SERVER_IS_CHAN(server) ||
15551555 !match_server(server, ctx, false)) {
15561556 spin_unlock(&server->srv_lock);
15571557 continue;
@@ -1587,7 +1587,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) · 29 unmodified lines
15871587 spin_unlock(&cifs_tcp_ses_lock);
15881588
15891589 /* For secondary channels, we pick up ref-count on the primary server */
1590− if (CIFS_SERVER_IS_CHAN(server))
1590+ if (SERVER_IS_CHAN(server))
15911591 cifs_put_tcp_session(server->primary_server, from_reconnect);
15921592
15931593 cancel_delayed_work_sync(&server->echo);
@@ -1686,6 +1686,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, · 92 unmodified lines
16861686 ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
16871687 tcp_ses->session_estab = false;
16881688 tcp_ses->sequence_number = 0;
1689+ tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */
16891690 tcp_ses->reconnect_instance = 1;
16901691 tcp_ses->lstrp = jiffies;
16911692 tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
@@ -1792,7 +1793,7 @@ out_err_crypto_release: · 100 unmodified lines
17921793
17931794 out_err:
17941795 if (tcp_ses) {
1795− if (CIFS_SERVER_IS_CHAN(tcp_ses))
1796+ if (SERVER_IS_CHAN(tcp_ses))
17961797 cifs_put_tcp_session(tcp_ses->primary_server, false);
17971798 kfree(tcp_ses->hostname);
17981799 kfree(tcp_ses->leaf_fullpath);
@@ -3813,7 +3814,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, · 2014 unmodified lines
38133814 struct nls_table *nls_info)
38143815 {
38153816 int rc = -ENOSYS;
3816− struct TCP_Server_Info *pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
3817+ struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
38173818 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr;
38183819 struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr;
38193820 bool is_binding = false;
fs/smb/client/dfs.c+150−121
@@ -3,7 +3,6 @@ · 2 unmodified lines
33 * Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de>
44 */
55
6−#include <linux/namei.h>
76 #include "cifsproto.h"
87 #include "cifs_debug.h"
98 #include "dns_resolve.h"
@@ -96,51 +95,134 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) · 86 unmodified lines
9695 return 0;
9796 }
9897
99−static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
100− const struct dfs_cache_tgt_iterator *tit)
98+static inline int parse_dfs_target(struct smb3_fs_context *ctx,
99+ struct dfs_ref_walk *rw,
100+ struct dfs_info3_param *tgt)
101+{
102+ int rc;
103+ const char *fpath = ref_walk_fpath(rw) + 1;
104+
105+ rc = ref_walk_get_tgt(rw, tgt);
106+ if (!rc)
107+ rc = dfs_parse_target_referral(fpath, tgt, ctx);
108+ return rc;
109+}
110+
111+static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx,
112+ struct dfs_info3_param *tgt,
113+ struct dfs_ref_walk *rw)
101114 {
102115 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
103− struct dfs_info3_param ref = {};
104− bool is_refsrv;
105− int rc, rc2;
116+ struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
117+ char *ref_path, *full_path;
118+ int rc;
106119
107− rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
108− if (rc)
120+ full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb));
121+ if (IS_ERR(full_path))
122+ return PTR_ERR(full_path);
123+
124+ if (!tgt || (tgt->server_type == DFS_TYPE_LINK &&
125+ DFS_INTERLINK(tgt->flags)))
126+ ref_path = dfs_get_path(cifs_sb, ctx->UNC);
127+ else
128+ ref_path = dfs_get_path(cifs_sb, full_path);
129+ if (IS_ERR(ref_path)) {
130+ rc = PTR_ERR(ref_path);
131+ kfree(full_path);
109132 return rc;
133+ }
134+ ref_walk_path(rw) = ref_path;
135+ ref_walk_fpath(rw) = full_path;
136+ return 0;
137+}
110138
111− rc = dfs_parse_target_referral(full_path + 1, &ref, ctx);
112− if (rc)
113− goto out;
139+static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
140+ struct dfs_ref_walk *rw)
141+{
142+ struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
143+ struct dfs_info3_param tgt = {};
144+ bool is_refsrv;
145+ int rc = -ENOENT;
114146
115− cifs_mount_put_conns(mnt_ctx);
116− rc = get_session(mnt_ctx, ref_path);
117− if (rc)
118− goto out;
147+again:
148+ do {
149+ if (ref_walk_empty(rw)) {
150+ rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1,
151+ NULL, ref_walk_tl(rw));
152+ if (rc) {
153+ rc = cifs_mount_get_tcon(mnt_ctx);
154+ if (!rc)
155+ rc = cifs_is_path_remote(mnt_ctx);
156+ continue;
157+ }
158+ if (!ref_walk_num_tgts(rw)) {
159+ rc = -ENOENT;
160+ continue;
161+ }
162+ }
119163
120− is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
164+ while (ref_walk_next_tgt(rw)) {
165+ rc = parse_dfs_target(ctx, rw, &tgt);
166+ if (rc)
167+ continue;
121168
122− rc = -EREMOTE;
123− if (ref.flags & DFSREF_STORAGE_SERVER) {
124− rc = cifs_mount_get_tcon(mnt_ctx);
125− if (rc)
126− goto out;
169+ cifs_mount_put_conns(mnt_ctx);
170+ rc = get_session(mnt_ctx, ref_walk_path(rw));
171+ if (rc)
172+ continue;
127173
128− /* some servers may not advertise referral capability under ref.flags */
129− is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
174+ is_refsrv = tgt.server_type == DFS_TYPE_ROOT ||
175+ DFS_INTERLINK(tgt.flags);
176+ ref_walk_set_tgt_hint(rw);
130177
131− rc = cifs_is_path_remote(mnt_ctx);
132− }
178+ if (tgt.flags & DFSREF_STORAGE_SERVER) {
179+ rc = cifs_mount_get_tcon(mnt_ctx);
180+ if (!rc)
181+ rc = cifs_is_path_remote(mnt_ctx);
182+ if (!rc)
183+ break;
184+ if (rc != -EREMOTE)
185+ continue;
186+ }
133187
134− dfs_cache_noreq_update_tgthint(ref_path + 1, tit);
188+ if (is_refsrv) {
189+ rc = add_root_smb_session(mnt_ctx);
190+ if (rc)
191+ goto out;
192+ }
135193
136− if (rc == -EREMOTE && is_refsrv) {
137− rc2 = add_root_smb_session(mnt_ctx);
138− if (rc2)
139− rc = rc2;
140− }
194+ rc = ref_walk_advance(rw);
195+ if (!rc) {
196+ rc = set_ref_paths(mnt_ctx, &tgt, rw);
197+ if (!rc) {
198+ rc = -EREMOTE;
199+ goto again;
200+ }
201+ }
202+ if (rc != -ELOOP)
203+ goto out;
204+ }
205+ } while (rc && ref_walk_descend(rw));
141206
142207 out:
143− free_dfs_info_param(&ref);
208+ free_dfs_info_param(&tgt);
209+ return rc;
210+}
211+
212+static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx)
213+{
214+ struct dfs_ref_walk *rw;
215+ int rc;
216+
217+ rw = ref_walk_alloc();
218+ if (IS_ERR(rw))
219+ return PTR_ERR(rw);
220+
221+ ref_walk_init(rw);
222+ rc = set_ref_paths(mnt_ctx, NULL, rw);
223+ if (!rc)
224+ rc = __dfs_referral_walk(mnt_ctx, rw);
225+ ref_walk_free(rw);
144226 return rc;
145227 }
146228
@@ -148,105 +230,48 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) · 1 unmodified line
148230 {
149231 struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
150232 struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
151− char *ref_path = NULL, *full_path = NULL;
152− struct dfs_cache_tgt_iterator *tit;
153233 struct cifs_tcon *tcon;
154− char *origin_fullpath = NULL;
155− char sep = CIFS_DIR_SEP(cifs_sb);
156− int num_links = 0;
234+ char *origin_fullpath;
157235 int rc;
158236
159− ref_path = dfs_get_path(cifs_sb, ctx->UNC);
160− if (IS_ERR(ref_path))
161− return PTR_ERR(ref_path);
237+ origin_fullpath = dfs_get_path(cifs_sb, ctx->source);
238+ if (IS_ERR(origin_fullpath))
239+ return PTR_ERR(origin_fullpath);
162240
163− full_path = smb3_fs_context_fullpath(ctx, sep);
164− if (IS_ERR(full_path)) {
165− rc = PTR_ERR(full_path);
166− full_path = NULL;
241+ rc = dfs_referral_walk(mnt_ctx);
242+ if (rc)
167243 goto out;
168− }
169244
170− origin_fullpath = kstrdup(full_path, GFP_KERNEL);
171− if (!origin_fullpath) {
172− rc = -ENOMEM;
173− goto out;
245+ tcon = mnt_ctx->tcon;
246+ spin_lock(&tcon->tc_lock);
247+ if (!tcon->origin_fullpath) {
248+ tcon->origin_fullpath = origin_fullpath;
249+ origin_fullpath = NULL;
174250 }
251+ spin_unlock(&tcon->tc_lock);
175252
176− do {
177− struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
178−
179− rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl);
180− if (rc) {
181− rc = cifs_mount_get_tcon(mnt_ctx);
182− if (!rc)
183− rc = cifs_is_path_remote(mnt_ctx);
184− break;
185− }
186−
187− tit = dfs_cache_get_tgt_iterator(&tl);
188− if (!tit) {
189− cifs_dbg(VFS, "%s: dfs referral (%s) with no targets\n", __func__,
190− ref_path + 1);
191− rc = -ENOENT;
192− dfs_cache_free_tgts(&tl);
193− break;
194− }
195−
196− do {
197− rc = get_dfs_conn(mnt_ctx, ref_path, full_path, tit);
198− if (!rc)
199− break;
200− if (rc == -EREMOTE) {
201− if (++num_links > MAX_NESTED_LINKS) {
202− rc = -ELOOP;
203− break;
204− }
205− kfree(ref_path);
206− kfree(full_path);
207− ref_path = full_path = NULL;
208−
209− full_path = smb3_fs_context_fullpath(ctx, sep);
210− if (IS_ERR(full_path)) {
211− rc = PTR_ERR(full_path);
212− full_path = NULL;
213− } else {
214− ref_path = dfs_get_path(cifs_sb, full_path);
215− if (IS_ERR(ref_path)) {
216− rc = PTR_ERR(ref_path);
217− ref_path = NULL;
218− }
219− }
220− break;
221− }
222− } while ((tit = dfs_cache_get_next_tgt(&tl, tit)));
223− dfs_cache_free_tgts(&tl);
224− } while (rc == -EREMOTE);
225−
226− if (!rc) {
227− tcon = mnt_ctx->tcon;
228−
229− spin_lock(&tcon->tc_lock);
230− if (!tcon->origin_fullpath) {
231− tcon->origin_fullpath = origin_fullpath;
232− origin_fullpath = NULL;
233− }
234− spin_unlock(&tcon->tc_lock);
235−
236− if (list_empty(&tcon->dfs_ses_list)) {
237− list_replace_init(&mnt_ctx->dfs_ses_list,
238− &tcon->dfs_ses_list);
239− queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
240− dfs_cache_get_ttl() * HZ);
241− } else {
242− dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
243− }
253+ if (list_empty(&tcon->dfs_ses_list)) {
254+ list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list);
255+ queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
256+ dfs_cache_get_ttl() * HZ);
257+ } else {
258+ dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
244259 }
245260
246261 out:
247262 kfree(origin_fullpath);
248− kfree(ref_path);
249− kfree(full_path);
263+ return rc;
264+}
265+
266+/* Resolve UNC hostname in @ctx->source and set ip addr in @ctx->dstaddr */
267+static int update_fs_context_dstaddr(struct smb3_fs_context *ctx)
268+{
269+ struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
270+ int rc;
271+
272+ rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
273+ if (!rc)
274+ cifs_set_port(addr, ctx->port);
250275 return rc;
251276 }
252277
@@ -256,6 +281,10 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) · 3 unmodified lines
256281 bool nodfs = ctx->nodfs;
257282 int rc;
258283
284+ rc = update_fs_context_dstaddr(ctx);
285+ if (rc)
286+ return rc;
287+
259288 *isdfs = false;
260289 rc = get_session(mnt_ctx, NULL);
261290 if (rc)
@@ -426,7 +455,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t · 164 unmodified lines
426455 /* Try to tree connect to all dfs targets */
427456 for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
428457 const char *target = dfs_cache_get_tgt_name(tit);
429− struct dfs_cache_tgt_list ntl = DFS_CACHE_TGT_LIST_INIT(ntl);
458+ DFS_CACHE_TGT_LIST(ntl);
430459
431460 kfree(share);
432461 kfree(prefix);
@@ -520,7 +549,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru · 87 unmodified lines
520549 int rc;
521550 struct TCP_Server_Info *server = tcon->ses->server;
522551 const struct smb_version_operations *ops = server->ops;
523− struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
552+ DFS_CACHE_TGT_LIST(tl);
524553 struct cifs_sb_info *cifs_sb = NULL;
525554 struct super_block *sb = NULL;
526555 struct dfs_info3_param ref = {0};
fs/smb/client/dfs.h+104−37
@@ -9,6 +9,110 @@ · 8 unmodified lines
99 #include "cifsglob.h"
1010 #include "fs_context.h"
1111 #include "cifs_unicode.h"
12+#include <linux/namei.h>
13+
14+#define DFS_INTERLINK(v) \
15+ (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
16+
17+struct dfs_ref {
18+ char *path;
19+ char *full_path;
20+ struct dfs_cache_tgt_list tl;
21+ struct dfs_cache_tgt_iterator *tit;
22+};
23+
24+struct dfs_ref_walk {
25+ struct dfs_ref *ref;
26+ struct dfs_ref refs[MAX_NESTED_LINKS];
27+};
28+
29+#define ref_walk_start(w) ((w)->refs)
30+#define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1])
31+#define ref_walk_cur(w) ((w)->ref)
32+#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w))
33+
34+#define ref_walk_tit(w) (ref_walk_cur(w)->tit)
35+#define ref_walk_empty(w) (!ref_walk_tit(w))
36+#define ref_walk_path(w) (ref_walk_cur(w)->path)
37+#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path)
38+#define ref_walk_tl(w) (&ref_walk_cur(w)->tl)
39+
40+static inline struct dfs_ref_walk *ref_walk_alloc(void)
41+{
42+ struct dfs_ref_walk *rw;
43+
44+ rw = kmalloc(sizeof(*rw), GFP_KERNEL);
45+ if (!rw)
46+ return ERR_PTR(-ENOMEM);
47+ return rw;
48+}
49+
50+static inline void ref_walk_init(struct dfs_ref_walk *rw)
51+{
52+ memset(rw, 0, sizeof(*rw));
53+ ref_walk_cur(rw) = ref_walk_start(rw);
54+}
55+
56+static inline void __ref_walk_free(struct dfs_ref *ref)
57+{
58+ kfree(ref->path);
59+ kfree(ref->full_path);
60+ dfs_cache_free_tgts(&ref->tl);
61+ memset(ref, 0, sizeof(*ref));
62+}
63+
64+static inline void ref_walk_free(struct dfs_ref_walk *rw)
65+{
66+ struct dfs_ref *ref = ref_walk_start(rw);
67+
68+ for (; ref <= ref_walk_end(rw); ref++)
69+ __ref_walk_free(ref);
70+ kfree(rw);
71+}
72+
73+static inline int ref_walk_advance(struct dfs_ref_walk *rw)
74+{
75+ struct dfs_ref *ref = ref_walk_cur(rw) + 1;
76+
77+ if (ref > ref_walk_end(rw))
78+ return -ELOOP;
79+ __ref_walk_free(ref);
80+ ref_walk_cur(rw) = ref;
81+ return 0;
82+}
83+
84+static inline struct dfs_cache_tgt_iterator *
85+ref_walk_next_tgt(struct dfs_ref_walk *rw)
86+{
87+ struct dfs_cache_tgt_iterator *tit;
88+ struct dfs_ref *ref = ref_walk_cur(rw);
89+
90+ if (!ref->tit)
91+ tit = dfs_cache_get_tgt_iterator(&ref->tl);
92+ else
93+ tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit);
94+ ref->tit = tit;
95+ return tit;
96+}
97+
98+static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw,
99+ struct dfs_info3_param *tgt)
100+{
101+ zfree_dfs_info_param(tgt);
102+ return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1,
103+ ref_walk_tit(rw), tgt);
104+}
105+
106+static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw)
107+{
108+ return dfs_cache_get_nr_tgts(ref_walk_tl(rw));
109+}
110+
111+static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw)
112+{
113+ dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1,
114+ ref_walk_tit(rw));
115+}
12116
13117 struct dfs_root_ses {
14118 struct list_head list;
@@ -34,43 +138,6 @@ static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *p · 19 unmodified lines
34138 cifs_remap(cifs_sb), path, ref, tl);
35139 }
36140
37−/* Return DFS full path out of a dentry set for automount */
38−static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
39−{
40− struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
41− struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
42− size_t len;
43− char *s;
44−
45− spin_lock(&tcon->tc_lock);
46− if (unlikely(!tcon->origin_fullpath)) {
47− spin_unlock(&tcon->tc_lock);
48− return ERR_PTR(-EREMOTE);
49− }
50− spin_unlock(&tcon->tc_lock);
51−
52− s = dentry_path_raw(dentry, page, PATH_MAX);
53− if (IS_ERR(s))
54− return s;
55− /* for root, we want "" */
56− if (!s[1])
57− s++;
58−
59− spin_lock(&tcon->tc_lock);
60− len = strlen(tcon->origin_fullpath);
61− if (s < (char *)page + len) {
62− spin_unlock(&tcon->tc_lock);
63− return ERR_PTR(-ENAMETOOLONG);
64− }
65−
66− s -= len;
67− memcpy(s, tcon->origin_fullpath, len);
68− spin_unlock(&tcon->tc_lock);
69− convert_delimiter(s, '/');
70−
71− return s;
72−}
73−
74141 static inline void dfs_put_root_smb_sessions(struct list_head *head)
75142 {
76143 struct dfs_root_ses *root, *tmp;
fs/smb/client/dfs_cache.c+4−6
@@ -29,8 +29,6 @@ · 28 unmodified lines
2929 #define CACHE_MIN_TTL 120 /* 2 minutes */
3030 #define CACHE_DEFAULT_TTL 300 /* 5 minutes */
3131
32−#define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
33−
3432 struct cache_dfs_tgt {
3533 char *name;
3634 int path_consumed;
@@ -174,7 +172,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v) · 137 unmodified lines
174172 "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n",
175173 ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
176174 ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags,
177− IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
175+ DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
178176 ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
179177
180178 list_for_each_entry(t, &ce->tlist, list) {
@@ -243,7 +241,7 @@ static inline void dump_ce(const struct cache_entry *ce) · 62 unmodified lines
243241 ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
244242 ce->etime.tv_nsec,
245243 ce->hdr_flags, ce->ref_flags,
246− IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
244+ DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
247245 ce->path_consumed,
248246 cache_entry_expired(ce) ? "yes" : "no");
249247 dump_tgts(ce);
@@ -1177,9 +1175,9 @@ static bool is_ses_good(struct cifs_ses *ses) · 927 unmodified lines
11771175 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
11781176 static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh)
11791177 {
1180− struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl);
1181− struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl);
11821178 struct TCP_Server_Info *server = ses->server;
1179+ DFS_CACHE_TGT_LIST(old_tl);
1180+ DFS_CACHE_TGT_LIST(new_tl);
11831181 bool needs_refresh = false;
11841182 struct cache_entry *ce;
11851183 unsigned int xid;
fs/smb/client/dfs_cache.h+8−4
@@ -16,7 +16,11 @@ · 15 unmodified lines
1616 extern struct workqueue_struct *dfscache_wq;
1717 extern atomic_t dfs_cache_ttl;
1818
19−#define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
19+#define DFS_CACHE_TGT_LIST_INIT(var) \
20+ { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
21+
22+#define DFS_CACHE_TGT_LIST(var) \
23+ struct dfs_cache_tgt_list var = DFS_CACHE_TGT_LIST_INIT(var)
2024
2125 struct dfs_cache_tgt_list {
2226 int tl_numtgts;
@@ -51,8 +55,8 @@ static inline struct dfs_cache_tgt_iterator * · 28 unmodified lines
5155 dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
5256 struct dfs_cache_tgt_iterator *it)
5357 {
54− if (!tl || list_empty(&tl->tl_list) || !it ||
55− list_is_last(&it->it_list, &tl->tl_list))
58+ if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list) ||
59+ !it || list_is_last(&it->it_list, &tl->tl_list))
5660 return NULL;
5761 return list_next_entry(it, it_list);
5862 }
@@ -71,7 +75,7 @@ static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl) · 12 unmodified lines
7175 {
7276 struct dfs_cache_tgt_iterator *it, *nit;
7377
74− if (!tl || list_empty(&tl->tl_list))
78+ if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list))
7579 return;
7680 list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
7781 list_del(&it->it_list);
fs/smb/client/dir.c+2−2
@@ -797,7 +797,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags) · 796 unmodified lines
797797
798798 const struct dentry_operations cifs_dentry_ops = {
799799 .d_revalidate = cifs_d_revalidate,
800− .d_automount = cifs_dfs_d_automount,
800+ .d_automount = cifs_d_automount,
801801 /* d_delete: cifs_d_delete, */ /* not needed except for debugging */
802802 };
803803
@@ -872,5 +872,5 @@ const struct dentry_operations cifs_ci_dentry_ops = { · 68 unmodified lines
872872 .d_revalidate = cifs_d_revalidate,
873873 .d_hash = cifs_ci_hash,
874874 .d_compare = cifs_ci_compare,
875− .d_automount = cifs_dfs_d_automount,
875+ .d_automount = cifs_d_automount,
876876 };
fs/smb/client/inode.c+284−214
@@ -58,13 +58,9 @@ static void cifs_set_ops(struct inode *inode) · 57 unmodified lines
5858 inode->i_data.a_ops = &cifs_addr_ops;
5959 break;
6060 case S_IFDIR:
61−#ifdef CONFIG_CIFS_DFS_UPCALL
6261 if (IS_AUTOMOUNT(inode)) {
63− inode->i_op = &cifs_dfs_referral_inode_operations;
62+ inode->i_op = &cifs_namespace_inode_operations;
6463 } else {
65−#else /* NO DFS support, treat as a directory */
66− {
67−#endif
6864 inode->i_op = &cifs_dir_inode_ops;
6965 inode->i_fop = &cifs_dir_ops;
7066 }
@@ -218,7 +214,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) · 147 unmodified lines
218214 }
219215 spin_unlock(&inode->i_lock);
220216
221− if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
217+ if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
222218 inode->i_flags |= S_AUTOMOUNT;
223219 if (inode->i_state & I_NEW)
224220 cifs_set_ops(inode);
@@ -327,14 +323,14 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, · 102 unmodified lines
327323 *
328324 * Needed to setup cifs_fattr data for the directory which is the
329325 * junction to the new submount (ie to setup the fake directory
330− * which represents a DFS referral).
326+ * which represents a DFS referral or reparse mount point).
331327 */
332−static void
333−cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
328+static void cifs_create_junction_fattr(struct cifs_fattr *fattr,
329+ struct super_block *sb)
334330 {
335331 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
336332
337− cifs_dbg(FYI, "creating fake fattr for DFS referral\n");
333+ cifs_dbg(FYI, "%s: creating fake fattr\n", __func__);
338334
339335 memset(fattr, 0, sizeof(*fattr));
340336 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
@@ -343,7 +339,33 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) · 2 unmodified lines
343339 ktime_get_coarse_real_ts64(&fattr->cf_mtime);
344340 fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
345341 fattr->cf_nlink = 2;
346− fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
342+ fattr->cf_flags = CIFS_FATTR_JUNCTION;
343+}
344+
345+/* Update inode with final fattr data */
346+static int update_inode_info(struct super_block *sb,
347+ struct cifs_fattr *fattr,
348+ struct inode **inode)
349+{
350+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
351+ int rc = 0;
352+
353+ if (!*inode) {
354+ *inode = cifs_iget(sb, fattr);
355+ if (!*inode)
356+ rc = -ENOMEM;
357+ return rc;
358+ }
359+ /* We already have inode, update it.
360+ *
361+ * If file type or uniqueid is different, return error.
362+ */
363+ if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
364+ CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
365+ CIFS_I(*inode)->time = 0; /* force reval */
366+ return -ESTALE;
367+ }
368+ return cifs_fattr_to_inode(*inode, fattr);
347369 }
348370
349371 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -373,7 +395,7 @@ cifs_get_file_info_unix(struct file *filp) · 23 unmodified lines
373395 if (!rc) {
374396 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
375397 } else if (rc == -EREMOTE) {
376− cifs_create_dfs_fattr(&fattr, inode->i_sb);
398+ cifs_create_junction_fattr(&fattr, inode->i_sb);
377399 rc = 0;
378400 } else
379401 goto cifs_gfiunix_out;
@@ -385,17 +407,18 @@ cifs_gfiunix_out: · 5 unmodified lines
385407 return rc;
386408 }
387409
388−int cifs_get_inode_info_unix(struct inode **pinode,
389− const unsigned char *full_path,
390− struct super_block *sb, unsigned int xid)
410+static int cifs_get_unix_fattr(const unsigned char *full_path,
411+ struct super_block *sb,
412+ struct cifs_fattr *fattr,
413+ struct inode **pinode,
414+ const unsigned int xid)
391415 {
392− int rc;
416+ struct TCP_Server_Info *server;
417+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
393418 FILE_UNIX_BASIC_INFO find_data;
394− struct cifs_fattr fattr;
395419 struct cifs_tcon *tcon;
396− struct TCP_Server_Info *server;
397420 struct tcon_link *tlink;
398− struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
421+ int rc, tmprc;
399422
400423 cifs_dbg(FYI, "Getting info on %s\n", full_path);
401424
@@ -412,59 +435,61 @@ int cifs_get_inode_info_unix(struct inode **pinode, · 10 unmodified lines
412435 cifs_put_tlink(tlink);
413436
414437 if (!rc) {
415− cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
438+ cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb);
416439 } else if (rc == -EREMOTE) {
417− cifs_create_dfs_fattr(&fattr, sb);
440+ cifs_create_junction_fattr(fattr, sb);
418441 rc = 0;
419442 } else {
420443 return rc;
421444 }
422445
446+ if (!*pinode)
447+ cifs_fill_uniqueid(sb, fattr);
448+
423449 /* check for Minshall+French symlinks */
424450 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
425− int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
426− full_path);
427− if (tmprc)
428− cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
451+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
452+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
429453 }
430454
431− if (S_ISLNK(fattr.cf_mode) && !fattr.cf_symlink_target) {
455+ if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) {
432456 if (!server->ops->query_symlink)
433457 return -EOPNOTSUPP;
434− rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
435− &fattr.cf_symlink_target, false);
436− if (rc) {
437− cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
438− goto cgiiu_exit;
439− }
458+ rc = server->ops->query_symlink(xid, tcon,
459+ cifs_sb, full_path,
460+ &fattr->cf_symlink_target,
461+ NULL);
462+ cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
440463 }
464+ return rc;
465+}
441466
442− if (*pinode == NULL) {
443− /* get new inode */
444− cifs_fill_uniqueid(sb, &fattr);
445− *pinode = cifs_iget(sb, &fattr);
446− if (!*pinode)
447− rc = -ENOMEM;
448− } else {
449− /* we already have inode, update it */
450−
451− /* if uniqueid is different, return error */
452− if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
453− CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
454− CIFS_I(*pinode)->time = 0; /* force reval */
455− rc = -ESTALE;
456− goto cgiiu_exit;
457− }
467+int cifs_get_inode_info_unix(struct inode **pinode,
468+ const unsigned char *full_path,
469+ struct super_block *sb, unsigned int xid)
470+{
471+ struct cifs_fattr fattr = {};
472+ int rc;
458473
459− /* if filetype is different, return error */
460− rc = cifs_fattr_to_inode(*pinode, &fattr);
461− }
474+ rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid);
475+ if (rc)
476+ goto out;
462477
463−cgiiu_exit:
478+ rc = update_inode_info(sb, &fattr, pinode);
479+out:
464480 kfree(fattr.cf_symlink_target);
465481 return rc;
466482 }
467483 #else
484+static inline int cifs_get_unix_fattr(const unsigned char *full_path,
485+ struct super_block *sb,
486+ struct cifs_fattr *fattr,
487+ struct inode **pinode,
488+ const unsigned int xid)
489+{
490+ return -EOPNOTSUPP;
491+}
492+
468493 int cifs_get_inode_info_unix(struct inode **pinode,
469494 const unsigned char *full_path,
470495 struct super_block *sb, unsigned int xid)
@@ -632,10 +657,11 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, · 161 unmodified lines
632657 }
633658
634659 /* Fill a cifs_fattr struct with info from POSIX info struct */
635−static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
660+static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
661+ struct cifs_open_info_data *data,
636662 struct cifs_sid *owner,
637663 struct cifs_sid *group,
638− struct super_block *sb, bool adjust_tz, bool symlink)
664+ struct super_block *sb)
639665 {
640666 struct smb311_posix_qinfo *info = &data->posix_fi;
641667 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -655,7 +681,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope · 13 unmodified lines
655681 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
656682 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
657683
658− if (adjust_tz) {
684+ if (data->adjust_tz) {
659685 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
660686 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
661687 }
@@ -669,7 +695,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope · 7 unmodified lines
669695 /* The srv fs device id is overridden on network mount so setting rdev isn't needed here */
670696 /* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */
671697
672− if (symlink) {
698+ if (data->symlink) {
673699 fattr->cf_mode |= S_IFLNK;
674700 fattr->cf_dtype = DT_LNK;
675701 fattr->cf_symlink_target = data->symlink_target;
@@ -690,9 +716,46 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope · 14 unmodified lines
690716 fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
691717 }
692718
693−static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
694− struct super_block *sb, bool adjust_tz, bool symlink,
695− u32 reparse_tag)
719+bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
720+ struct cifs_fattr *fattr,
721+ u32 tag)
722+{
723+ switch (tag) {
724+ case IO_REPARSE_TAG_LX_SYMLINK:
725+ fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
726+ fattr->cf_dtype = DT_LNK;
727+ break;
728+ case IO_REPARSE_TAG_LX_FIFO:
729+ fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
730+ fattr->cf_dtype = DT_FIFO;
731+ break;
732+ case IO_REPARSE_TAG_AF_UNIX:
733+ fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
734+ fattr->cf_dtype = DT_SOCK;
735+ break;
736+ case IO_REPARSE_TAG_LX_CHR:
737+ fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
738+ fattr->cf_dtype = DT_CHR;
739+ break;
740+ case IO_REPARSE_TAG_LX_BLK:
741+ fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
742+ fattr->cf_dtype = DT_BLK;
743+ break;
744+ case 0: /* SMB1 symlink */
745+ case IO_REPARSE_TAG_SYMLINK:
746+ case IO_REPARSE_TAG_NFS:
747+ fattr->cf_mode = S_IFLNK;
748+ fattr->cf_dtype = DT_LNK;
749+ break;
750+ default:
751+ return false;
752+ }
753+ return true;
754+}
755+
756+static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
757+ struct cifs_open_info_data *data,
758+ struct super_block *sb)
696759 {
697760 struct smb2_file_all_info *info = &data->fi;
698761 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -711,7 +774,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i · 12 unmodified lines
711774 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
712775 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
713776
714− if (adjust_tz) {
777+ if (data->adjust_tz) {
715778 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
716779 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
717780 }
@@ -719,28 +782,13 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i · 1 unmodified line
719782 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
720783 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
721784 fattr->cf_createtime = le64_to_cpu(info->CreationTime);
722−
723785 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
724− if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
725− fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
726− fattr->cf_dtype = DT_LNK;
727− } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
728− fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
729− fattr->cf_dtype = DT_FIFO;
730− } else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
731− fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
732− fattr->cf_dtype = DT_SOCK;
733− } else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
734− fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
735− fattr->cf_dtype = DT_CHR;
736− } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
737− fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
738− fattr->cf_dtype = DT_BLK;
739− } else if (symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
740− reparse_tag == IO_REPARSE_TAG_NFS) {
741− fattr->cf_mode = S_IFLNK;
742− fattr->cf_dtype = DT_LNK;
743− } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
786+
787+ if (cifs_open_data_reparse(data) &&
788+ cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag))
789+ goto out_reparse;
790+
791+ if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
744792 fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
745793 fattr->cf_dtype = DT_DIR;
746794 /*
@@ -769,6 +817,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i · 22 unmodified lines
769817 }
770818 }
771819
820+out_reparse:
772821 if (S_ISLNK(fattr->cf_mode)) {
773822 fattr->cf_symlink_target = data->symlink_target;
774823 data->symlink_target = NULL;
@@ -789,8 +838,6 @@ cifs_get_file_info(struct file *filp) · 14 unmodified lines
789838 struct cifsFileInfo *cfile = filp->private_data;
790839 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
791840 struct TCP_Server_Info *server = tcon->ses->server;
792− bool symlink = false;
793− u32 tag = 0;
794841
795842 if (!server->ops->query_file_info)
796843 return -ENOSYS;
@@ -800,14 +847,15 @@ cifs_get_file_info(struct file *filp) · 3 unmodified lines
800847 switch (rc) {
801848 case 0:
802849 /* TODO: add support to query reparse tag */
850+ data.adjust_tz = false;
803851 if (data.symlink_target) {
804− symlink = true;
805− tag = IO_REPARSE_TAG_SYMLINK;
852+ data.symlink = true;
853+ data.reparse_tag = IO_REPARSE_TAG_SYMLINK;
806854 }
807− cifs_open_info_to_fattr(&fattr, &data, inode->i_sb, false, symlink, tag);
855+ cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
808856 break;
809857 case -EREMOTE:
810− cifs_create_dfs_fattr(&fattr, inode->i_sb);
858+ cifs_create_junction_fattr(&fattr, inode->i_sb);
811859 rc = 0;
812860 break;
813861 case -EOPNOTSUPP:
@@ -960,22 +1008,66 @@ static inline bool is_inode_cache_good(struct inode *ino) · 146 unmodified lines
9601008 return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
9611009 }
9621010
963−int cifs_get_inode_info(struct inode **inode, const char *full_path,
964− struct cifs_open_info_data *data, struct super_block *sb, int xid,
965− const struct cifs_fid *fid)
1011+static int reparse_info_to_fattr(struct cifs_open_info_data *data,
1012+ struct super_block *sb,
1013+ const unsigned int xid,
1014+ struct cifs_tcon *tcon,
1015+ const char *full_path,
1016+ struct cifs_fattr *fattr)
9661017 {
1018+ struct TCP_Server_Info *server = tcon->ses->server;
1019+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1020+ struct kvec rsp_iov, *iov = NULL;
1021+ int rsp_buftype = CIFS_NO_BUFFER;
1022+ u32 tag = data->reparse_tag;
1023+ int rc = 0;
1024+
1025+ if (!tag && server->ops->query_reparse_point) {
1026+ rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
1027+ full_path, &tag,
1028+ &rsp_iov, &rsp_buftype);
1029+ if (!rc)
1030+ iov = &rsp_iov;
1031+ }
1032+ switch ((data->reparse_tag = tag)) {
1033+ case 0: /* SMB1 symlink */
1034+ iov = NULL;
1035+ fallthrough;
1036+ case IO_REPARSE_TAG_NFS:
1037+ case IO_REPARSE_TAG_SYMLINK:
1038+ if (!data->symlink_target && server->ops->query_symlink) {
1039+ rc = server->ops->query_symlink(xid, tcon,
1040+ cifs_sb, full_path,
1041+ &data->symlink_target,
1042+ iov);
1043+ }
1044+ break;
1045+ case IO_REPARSE_TAG_MOUNT_POINT:
1046+ cifs_create_junction_fattr(fattr, sb);
1047+ goto out;
1048+ }
1049+
1050+ cifs_open_info_to_fattr(fattr, data, sb);
1051+out:
1052+ free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
1053+ return rc;
1054+}
1055+
1056+static int cifs_get_fattr(struct cifs_open_info_data *data,
1057+ struct super_block *sb, int xid,
1058+ const struct cifs_fid *fid,
1059+ struct cifs_fattr *fattr,
1060+ struct inode **inode,
1061+ const char *full_path)
1062+{
1063+ struct cifs_open_info_data tmp_data = {};
9671064 struct cifs_tcon *tcon;
9681065 struct TCP_Server_Info *server;
9691066 struct tcon_link *tlink;
9701067 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
971− bool adjust_tz = false;
972− struct cifs_fattr fattr = {0};
973− bool is_reparse_point = false;
974− struct cifs_open_info_data tmp_data = {};
9751068 void *smb1_backup_rsp_buf = NULL;
9761069 int rc = 0;
9771070 int tmprc = 0;
978− __u32 reparse_tag = 0;
9791071
9801072 tlink = cifs_sb_tlink(cifs_sb);
9811073 if (IS_ERR(tlink))
@@ -988,12 +1080,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, · 6 unmodified lines
9881080 */
9891081
9901082 if (!data) {
991− if (is_inode_cache_good(*inode)) {
992− cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
993− goto out;
994− }
995− rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, &tmp_data,
996− &adjust_tz, &is_reparse_point);
1083+ rc = server->ops->query_path_info(xid, tcon, cifs_sb,
1084+ full_path, &tmp_data);
9971085 data = &tmp_data;
9981086 }
9991087
@@ -1008,28 +1096,16 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, · 8 unmodified lines
10081096 * since we have to check if its reparse tag matches a known
10091097 * special file type e.g. symlink or fifo or char etc.
10101098 */
1011− if (is_reparse_point && data->symlink_target) {
1012− reparse_tag = IO_REPARSE_TAG_SYMLINK;
1013− } else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) &&
1014− server->ops->query_reparse_tag) {
1015− tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path,
1016− &reparse_tag);
1017− if (tmprc)
1018− cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
1019− if (server->ops->query_symlink) {
1020− tmprc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
1021− &data->symlink_target,
1022− is_reparse_point);
1023− if (tmprc)
1024− cifs_dbg(FYI, "%s: query_symlink: rc = %d\n", __func__,
1025− tmprc);
1026− }
1099+ if (cifs_open_data_reparse(data)) {
1100+ rc = reparse_info_to_fattr(data, sb, xid, tcon,
1101+ full_path, fattr);
1102+ } else {
1103+ cifs_open_info_to_fattr(fattr, data, sb);
10271104 }
1028− cifs_open_info_to_fattr(&fattr, data, sb, adjust_tz, is_reparse_point, reparse_tag);
10291105 break;
10301106 case -EREMOTE:
10311107 /* DFS link, no metadata available on this server */
1032− cifs_create_dfs_fattr(&fattr, sb);
1108+ cifs_create_junction_fattr(fattr, sb);
10331109 rc = 0;
10341110 break;
10351111 case -EACCES:
@@ -1059,8 +1135,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, · 23 unmodified lines
10591135 fdi = (FILE_DIRECTORY_INFO *)fi;
10601136 si = (SEARCH_ID_FULL_DIR_INFO *)fi;
10611137
1062− cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb);
1063− fattr.cf_uniqueid = le64_to_cpu(si->UniqueId);
1138+ cifs_dir_info_to_fattr(fattr, fdi, cifs_sb);
1139+ fattr->cf_uniqueid = le64_to_cpu(si->UniqueId);
10641140 /* uniqueid set, skip get inum step */
10651141 goto handle_mnt_opt;
10661142 } else {
@@ -1077,10 +1153,10 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, · 10 unmodified lines
10771153 }
10781154
10791155 /*
1080− * 3. Get or update inode number (fattr.cf_uniqueid)
1156+ * 3. Get or update inode number (fattr->cf_uniqueid)
10811157 */
10821158
1083− cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr);
1159+ cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr);
10841160
10851161 /*
10861162 * 4. Tweak fattr based on mount options
@@ -1089,17 +1165,17 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path, · 2 unmodified lines
10891165 handle_mnt_opt:
10901166 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
10911167 /* query for SFU type info if supported and needed */
1092− if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
1093− cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
1094− tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
1168+ if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
1169+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
1170+ tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
10951171 if (tmprc)
10961172 cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
10971173 }
10981174
10991175 /* fill in 0777 bits from ACL */
11001176 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
1101− rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
1102− full_path, fid);
1177+ rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
1178+ true, full_path, fid);
11031179 if (rc == -EREMOTE)
11041180 rc = 0;
11051181 if (rc) {
@@ -1108,8 +1184,8 @@ handle_mnt_opt: · 2 unmodified lines
11081184 goto out;
11091185 }
11101186 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
1111− rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
1112− full_path, fid);
1187+ rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
1188+ false, full_path, fid);
11131189 if (rc == -EREMOTE)
11141190 rc = 0;
11151191 if (rc) {
@@ -1121,60 +1197,57 @@ handle_mnt_opt: · 5 unmodified lines
11211197
11221198 /* fill in remaining high mode bits e.g. SUID, VTX */
11231199 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
1124− cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
1200+ cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
11251201
11261202 /* check for Minshall+French symlinks */
11271203 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
1128− tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
1129− full_path);
1130− if (tmprc)
1131− cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
1204+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
1205+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
11321206 }
11331207
1134− /*
1135− * 5. Update inode with final fattr data
1136− */
1137−
1138− if (!*inode) {
1139− *inode = cifs_iget(sb, &fattr);
1140− if (!*inode)
1141− rc = -ENOMEM;
1142− } else {
1143− /* we already have inode, update it */
1144−
1145− /* if uniqueid is different, return error */
1146− if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
1147− CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
1148− CIFS_I(*inode)->time = 0; /* force reval */
1149− rc = -ESTALE;
1150− goto out;
1151− }
1152− /* if filetype is different, return error */
1153− rc = cifs_fattr_to_inode(*inode, &fattr);
1154− }
11551208 out:
11561209 cifs_buf_release(smb1_backup_rsp_buf);
11571210 cifs_put_tlink(tlink);
11581211 cifs_free_open_info(&tmp_data);
1212+ return rc;
1213+}
1214+
1215+int cifs_get_inode_info(struct inode **inode,
1216+ const char *full_path,
1217+ struct cifs_open_info_data *data,
1218+ struct super_block *sb, int xid,
1219+ const struct cifs_fid *fid)
1220+{
1221+ struct cifs_fattr fattr = {};
1222+ int rc;
1223+
1224+ if (is_inode_cache_good(*inode)) {
1225+ cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
1226+ return 0;
1227+ }
1228+
1229+ rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path);
1230+ if (rc)
1231+ goto out;
1232+
1233+ rc = update_inode_info(sb, &fattr, inode);
1234+out:
11591235 kfree(fattr.cf_symlink_target);
11601236 return rc;
11611237 }
11621238
1163−int
1164−smb311_posix_get_inode_info(struct inode **inode,
1165− const char *full_path,
1166− struct super_block *sb, unsigned int xid)
1239+static int smb311_posix_get_fattr(struct cifs_fattr *fattr,
1240+ const char *full_path,
1241+ struct super_block *sb,
1242+ const unsigned int xid)
11671243 {
1244+ struct cifs_open_info_data data = {};
1245+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
11681246 struct cifs_tcon *tcon;
11691247 struct tcon_link *tlink;
1170− struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1171− bool adjust_tz = false;
1172− struct cifs_fattr fattr = {0};
1173− bool symlink = false;
1174− struct cifs_open_info_data data = {};
11751248 struct cifs_sid owner, group;
1176− int rc = 0;
1177− int tmprc = 0;
1249+ int tmprc;
1250+ int rc;
11781251
11791252 tlink = cifs_sb_tlink(cifs_sb);
11801253 if (IS_ERR(tlink))
@@ -1185,14 +1258,9 @@ smb311_posix_get_inode_info(struct inode **inode, · 4 unmodified lines
11851258 * 1. Fetch file metadata
11861259 */
11871260
1188− if (is_inode_cache_good(*inode)) {
1189− cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
1190− goto out;
1191− }
1192−
1193− rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data,
1194− &owner, &group, &adjust_tz,
1195− &symlink);
1261+ rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
1262+ full_path, &data,
1263+ &owner, &group);
11961264
11971265 /*
11981266 * 2. Convert it to internal cifs metadata (fattr)
@@ -1200,12 +1268,11 @@ smb311_posix_get_inode_info(struct inode **inode, · 1 unmodified line
12001268
12011269 switch (rc) {
12021270 case 0:
1203− smb311_posix_info_to_fattr(&fattr, &data, &owner, &group,
1204− sb, adjust_tz, symlink);
1271+ smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb);
12051272 break;
12061273 case -EREMOTE:
12071274 /* DFS link, no metadata available on this server */
1208− cifs_create_dfs_fattr(&fattr, sb);
1275+ cifs_create_junction_fattr(fattr, sb);
12091276 rc = 0;
12101277 break;
12111278 case -EACCES:
@@ -1221,49 +1288,42 @@ smb311_posix_get_inode_info(struct inode **inode, · 9 unmodified lines
12211288 goto out;
12221289 }
12231290
1224−
12251291 /*
12261292 * 3. Tweak fattr based on mount options
12271293 */
1228−
12291294 /* check for Minshall+French symlinks */
12301295 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
1231− tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
1232− full_path);
1233− if (tmprc)
1234− cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
1296+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
1297+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
12351298 }
12361299
1237− /*
1238− * 4. Update inode with final fattr data
1239− */
1240−
1241− if (!*inode) {
1242− *inode = cifs_iget(sb, &fattr);
1243− if (!*inode)
1244− rc = -ENOMEM;
1245− } else {
1246− /* we already have inode, update it */
1300+out:
1301+ cifs_put_tlink(tlink);
1302+ cifs_free_open_info(&data);
1303+ return rc;
1304+}
12471305
1248− /* if uniqueid is different, return error */
1249− if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
1250− CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
1251− CIFS_I(*inode)->time = 0; /* force reval */
1252− rc = -ESTALE;
1253− goto out;
1254− }
1306+int smb311_posix_get_inode_info(struct inode **inode, const char *full_path,
1307+ struct super_block *sb, const unsigned int xid)
1308+{
1309+ struct cifs_fattr fattr = {};
1310+ int rc;
12551311
1256− /* if filetype is different, return error */
1257− rc = cifs_fattr_to_inode(*inode, &fattr);
1312+ if (is_inode_cache_good(*inode)) {
1313+ cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
1314+ return 0;
12581315 }
1316+
1317+ rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid);
1318+ if (rc)
1319+ goto out;
1320+
1321+ rc = update_inode_info(sb, &fattr, inode);
12591322 out:
1260− cifs_put_tlink(tlink);
1261− cifs_free_open_info(&data);
12621323 kfree(fattr.cf_symlink_target);
12631324 return rc;
12641325 }
12651326
1266−
12671327 static const struct inode_operations cifs_ipc_inode_ops = {
12681328 .lookup = cifs_lookup,
12691329 };
@@ -1367,13 +1427,14 @@ retry_iget5_locked: · 97 unmodified lines
13671427 /* gets root inode */
13681428 struct inode *cifs_root_iget(struct super_block *sb)
13691429 {
1370− unsigned int xid;
13711430 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1372− struct inode *inode = NULL;
1373− long rc;
1431+ struct cifs_fattr fattr = {};
13741432 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1433+ struct inode *inode = NULL;
1434+ unsigned int xid;
13751435 char *path = NULL;
13761436 int len;
1437+ int rc;
13771438
13781439 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
13791440 && cifs_sb->prepath) {
@@ -1391,21 +1452,29 @@ struct inode *cifs_root_iget(struct super_block *sb) · 11 unmodified lines
13911452
13921453 xid = get_xid();
13931454 if (tcon->unix_ext) {
1394− rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
1455+ rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid);
13951456 /* some servers mistakenly claim POSIX support */
13961457 if (rc != -EOPNOTSUPP)
1397− goto iget_no_retry;
1458+ goto iget_root;
13981459 cifs_dbg(VFS, "server does not support POSIX extensions\n");
13991460 tcon->unix_ext = false;
14001461 }
14011462
14021463 convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
14031464 if (tcon->posix_extensions)
1404− rc = smb311_posix_get_inode_info(&inode, path, sb, xid);
1465+ rc = smb311_posix_get_fattr(&fattr, path, sb, xid);
14051466 else
1406− rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
1467+ rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path);
1468+
1469+iget_root:
1470+ if (!rc) {
1471+ if (fattr.cf_flags & CIFS_FATTR_JUNCTION) {
1472+ fattr.cf_flags &= ~CIFS_FATTR_JUNCTION;
1473+ cifs_autodisable_serverino(cifs_sb);
1474+ }
1475+ inode = cifs_iget(sb, &fattr);
1476+ }
14071477
1408−iget_no_retry:
14091478 if (!inode) {
14101479 inode = ERR_PTR(rc);
14111480 goto out;
@@ -1429,6 +1498,7 @@ iget_no_retry: · 17 unmodified lines
14291498 out:
14301499 kfree(path);
14311500 free_xid(xid);
1501+ kfree(fattr.cf_symlink_target);
14321502 return inode;
14331503 }
14341504
fs/smb/client/misc.c+1−1
@@ -476,7 +476,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) · 475 unmodified lines
476476 return false;
477477
478478 /* If server is a channel, select the primary channel */
479− pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
479+ pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
480480
481481 /* look up tcon based on tid & uid */
482482 spin_lock(&cifs_tcp_ses_lock);
fs/smb/client/namespace.crenamed from fs/smb/client/cifs_dfs_ref.c+62−51
@@ -1,12 +1,12 @@
11 // SPDX-License-Identifier: GPL-2.0-or-later
22 /*
3− * Contains the CIFS DFS referral mounting routines used for handling
4− * traversal via DFS junction point
3+ * Contains mounting routines used for handling traversal via SMB junctions.
54 *
65 * Copyright (c) 2007 Igor Mammedov
76 * Copyright (C) International Business Machines Corp., 2008
87 * Author(s): Igor Mammedov (niallain@gmail.com)
98 * Steve French (sfrench@us.ibm.com)
9+ * Copyright (c) 2023 Paulo Alcantara <palcantara@suse.de>
1010 */
1111
1212 #include <linux/dcache.h>
@@ -19,32 +19,31 @@ · 6 unmodified lines
1919 #include "cifsglob.h"
2020 #include "cifsproto.h"
2121 #include "cifsfs.h"
22−#include "dns_resolve.h"
2322 #include "cifs_debug.h"
24−#include "dfs.h"
2523 #include "fs_context.h"
2624
27−static LIST_HEAD(cifs_dfs_automount_list);
25+static LIST_HEAD(cifs_automount_list);
2826
29−static void cifs_dfs_expire_automounts(struct work_struct *work);
30−static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
31− cifs_dfs_expire_automounts);
32−static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
27+static void cifs_expire_automounts(struct work_struct *work);
28+static DECLARE_DELAYED_WORK(cifs_automount_task,
29+ cifs_expire_automounts);
30+static int cifs_mountpoint_expiry_timeout = 500 * HZ;
3331
34−static void cifs_dfs_expire_automounts(struct work_struct *work)
32+static void cifs_expire_automounts(struct work_struct *work)
3533 {
36− struct list_head *list = &cifs_dfs_automount_list;
34+ struct list_head *list = &cifs_automount_list;
3735
3836 mark_mounts_for_expiry(list);
3937 if (!list_empty(list))
40− schedule_delayed_work(&cifs_dfs_automount_task,
41− cifs_dfs_mountpoint_expiry_timeout);
38+ schedule_delayed_work(&cifs_automount_task,
39+ cifs_mountpoint_expiry_timeout);
4240 }
4341
44−void cifs_dfs_release_automount_timer(void)
42+void cifs_release_automount_timer(void)
4543 {
46− BUG_ON(!list_empty(&cifs_dfs_automount_list));
47− cancel_delayed_work_sync(&cifs_dfs_automount_task);
44+ if (WARN_ON(!list_empty(&cifs_automount_list)))
45+ return;
46+ cancel_delayed_work_sync(&cifs_automount_task);
4847 }
4948
5049 /**
@@ -118,26 +117,53 @@ cifs_build_devname(char *nodename, const char *prepath) · 67 unmodified lines
118117 return dev;
119118 }
120119
121−static int set_dest_addr(struct smb3_fs_context *ctx)
120+/* Return full path out of a dentry set for automount */
121+static char *automount_fullpath(struct dentry *dentry, void *page)
122122 {
123− struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
124− int rc;
123+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
124+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
125+ size_t len;
126+ char *s;
127+
128+ spin_lock(&tcon->tc_lock);
129+ if (!tcon->origin_fullpath) {
130+ spin_unlock(&tcon->tc_lock);
131+ return build_path_from_dentry_optional_prefix(dentry,
132+ page,
133+ true);
134+ }
135+ spin_unlock(&tcon->tc_lock);
136+
137+ s = dentry_path_raw(dentry, page, PATH_MAX);
138+ if (IS_ERR(s))
139+ return s;
140+ /* for root, we want "" */
141+ if (!s[1])
142+ s++;
143+
144+ spin_lock(&tcon->tc_lock);
145+ len = strlen(tcon->origin_fullpath);
146+ if (s < (char *)page + len) {
147+ spin_unlock(&tcon->tc_lock);
148+ return ERR_PTR(-ENAMETOOLONG);
149+ }
150+
151+ s -= len;
152+ memcpy(s, tcon->origin_fullpath, len);
153+ spin_unlock(&tcon->tc_lock);
154+ convert_delimiter(s, '/');
125155
126− rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
127− if (!rc)
128− cifs_set_port(addr, ctx->port);
129− return rc;
156+ return s;
130157 }
131158
132159 /*
133160 * Create a vfsmount that we can automount
134161 */
135−static struct vfsmount *cifs_dfs_do_automount(struct path *path)
162+static struct vfsmount *cifs_do_automount(struct path *path)
136163 {
137164 int rc;
138165 struct dentry *mntpt = path->dentry;
139166 struct fs_context *fc;
140− struct cifs_sb_info *cifs_sb;
141167 void *page = NULL;
142168 struct smb3_fs_context *ctx, *cur_ctx;
143169 struct smb3_fs_context tmp;
@@ -147,17 +173,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) · 3 unmodified lines
147173 if (IS_ROOT(mntpt))
148174 return ERR_PTR(-ESTALE);
149175
150− /*
151− * The MSDFS spec states that paths in DFS referral requests and
152− * responses must be prefixed by a single '\' character instead of
153− * the double backslashes usually used in the UNC. This function
154− * gives us the latter, so we must adjust the result.
155− */
156− cifs_sb = CIFS_SB(mntpt->d_sb);
157− if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
158− return ERR_PTR(-EREMOTE);
159−
160− cur_ctx = cifs_sb->ctx;
176+ cur_ctx = CIFS_SB(mntpt->d_sb)->ctx;
161177
162178 fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
163179 if (IS_ERR(fc))
@@ -166,7 +182,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) · 2 unmodified lines
166182 ctx = smb3_fc2context(fc);
167183
168184 page = alloc_dentry_path();
169− full_path = dfs_get_automount_devname(mntpt, page);
185+ full_path = automount_fullpath(mntpt, page);
170186 if (IS_ERR(full_path)) {
171187 mnt = ERR_CAST(full_path);
172188 goto out;
@@ -196,15 +212,10 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) · 23 unmodified lines
196212 ctx->source = NULL;
197213 goto out;
198214 }
199− cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n",
200− __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr);
201−
202− rc = set_dest_addr(ctx);
203− if (!rc)
204− mnt = fc_mount(fc);
205− else
206− mnt = ERR_PTR(rc);
215+ cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s\n",
216+ __func__, ctx->source, ctx->UNC, ctx->prepath);
207217
218+ mnt = fc_mount(fc);
208219 out:
209220 put_fs_context(fc);
210221 free_dentry_path(page);
@@ -214,25 +225,25 @@ out: · 3 unmodified lines
214225 /*
215226 * Attempt to automount the referral
216227 */
217−struct vfsmount *cifs_dfs_d_automount(struct path *path)
228+struct vfsmount *cifs_d_automount(struct path *path)
218229 {
219230 struct vfsmount *newmnt;
220231
221232 cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
222233
223− newmnt = cifs_dfs_do_automount(path);
234+ newmnt = cifs_do_automount(path);
224235 if (IS_ERR(newmnt)) {
225236 cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
226237 return newmnt;
227238 }
228239
229240 mntget(newmnt); /* prevent immediate expiration */
230− mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
231− schedule_delayed_work(&cifs_dfs_automount_task,
232− cifs_dfs_mountpoint_expiry_timeout);
241+ mnt_set_expiry(newmnt, &cifs_automount_list);
242+ schedule_delayed_work(&cifs_automount_task,
243+ cifs_mountpoint_expiry_timeout);
233244 cifs_dbg(FYI, "leaving %s [ok]\n" , __func__);
234245 return newmnt;
235246 }
236247
237−const struct inode_operations cifs_dfs_referral_inode_operations = {
248+const struct inode_operations cifs_namespace_inode_operations = {
238249 };
fs/smb/client/readdir.c+7−16
@@ -143,6 +143,7 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr) · 142 unmodified lines
143143 case IO_REPARSE_TAG_DFSR:
144144 case IO_REPARSE_TAG_SYMLINK:
145145 case IO_REPARSE_TAG_NFS:
146+ case IO_REPARSE_TAG_MOUNT_POINT:
146147 case 0:
147148 return true;
148149 }
@@ -163,29 +164,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) · 14 unmodified lines
163164 * TODO: go through all documented reparse tags to see if we can
164165 * reasonably map some of them to directories vs. files vs. symlinks
165166 */
167+ if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
168+ cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag))
169+ goto out_reparse;
170+
166171 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
167172 fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
168173 fattr->cf_dtype = DT_DIR;
169− } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
170− fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
171− fattr->cf_dtype = DT_LNK;
172− } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
173− fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
174− fattr->cf_dtype = DT_FIFO;
175− } else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
176− fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
177− fattr->cf_dtype = DT_SOCK;
178− } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
179− fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
180− fattr->cf_dtype = DT_CHR;
181− } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
182− fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
183− fattr->cf_dtype = DT_BLK;
184− } else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
174+ } else {
185175 fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
186176 fattr->cf_dtype = DT_REG;
187177 }
188178
179+out_reparse:
189180 /*
190181 * We need to revalidate it further to make a decision about whether it
191182 * is a symbolic link, DFS referral or a reparse point with a direct
fs/smb/client/sess.c+43−29
@@ -323,12 +323,12 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) · 322 unmodified lines
323323 ses->chans[chan_index].iface = iface;
324324
325325 /* No iface is found. if secondary chan, drop connection */
326− if (!iface && CIFS_SERVER_IS_CHAN(server))
326+ if (!iface && SERVER_IS_CHAN(server))
327327 ses->chans[chan_index].server = NULL;
328328
329329 spin_unlock(&ses->chan_lock);
330330
331− if (!iface && CIFS_SERVER_IS_CHAN(server))
331+ if (!iface && SERVER_IS_CHAN(server))
332332 cifs_put_tcp_session(server, false);
333333
334334 return rc;
@@ -360,11 +360,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, · 25 unmodified lines
360360 {
361361 struct TCP_Server_Info *chan_server;
362362 struct cifs_chan *chan;
363− struct smb3_fs_context ctx = {NULL};
363+ struct smb3_fs_context *ctx;
364364 static const char unc_fmt[] = "\\%s\\foo";
365− char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
366365 struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
367366 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
367+ size_t len;
368368 int rc;
369369 unsigned int xid = get_xid();
370370
@@ -388,54 +388,64 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, · 17 unmodified lines
388388 * the session and server without caring about memory
389389 * management.
390390 */
391+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
392+ if (!ctx) {
393+ rc = -ENOMEM;
394+ goto out_free_xid;
395+ }
391396
392397 /* Always make new connection for now (TODO?) */
393− ctx.nosharesock = true;
398+ ctx->nosharesock = true;
394399
395400 /* Auth */
396− ctx.domainauto = ses->domainAuto;
397− ctx.domainname = ses->domainName;
401+ ctx->domainauto = ses->domainAuto;
402+ ctx->domainname = ses->domainName;
398403
399404 /* no hostname for extra channels */
400− ctx.server_hostname = "";
405+ ctx->server_hostname = "";
401406
402− ctx.username = ses->user_name;
403− ctx.password = ses->password;
404− ctx.sectype = ses->sectype;
405− ctx.sign = ses->sign;
407+ ctx->username = ses->user_name;
408+ ctx->password = ses->password;
409+ ctx->sectype = ses->sectype;
410+ ctx->sign = ses->sign;
406411
407412 /* UNC and paths */
408413 /* XXX: Use ses->server->hostname? */
409− sprintf(unc, unc_fmt, ses->ip_addr);
410− ctx.UNC = unc;
411− ctx.prepath = "";
414+ len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL;
415+ ctx->UNC = kzalloc(len, GFP_KERNEL);
416+ if (!ctx->UNC) {
417+ rc = -ENOMEM;
418+ goto out_free_ctx;
419+ }
420+ scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr);
421+ ctx->prepath = "";
412422
413423 /* Reuse same version as master connection */
414− ctx.vals = ses->server->vals;
415− ctx.ops = ses->server->ops;
424+ ctx->vals = ses->server->vals;
425+ ctx->ops = ses->server->ops;
416426
417− ctx.noblocksnd = ses->server->noblocksnd;
418− ctx.noautotune = ses->server->noautotune;
419− ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
420− ctx.echo_interval = ses->server->echo_interval / HZ;
421− ctx.max_credits = ses->server->max_credits;
427+ ctx->noblocksnd = ses->server->noblocksnd;
428+ ctx->noautotune = ses->server->noautotune;
429+ ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay;
430+ ctx->echo_interval = ses->server->echo_interval / HZ;
431+ ctx->max_credits = ses->server->max_credits;
422432
423433 /*
424434 * This will be used for encoding/decoding user/domain/pw
425435 * during sess setup auth.
426436 */
427− ctx.local_nls = cifs_sb->local_nls;
437+ ctx->local_nls = cifs_sb->local_nls;
428438
429439 /* Use RDMA if possible */
430− ctx.rdma = iface->rdma_capable;
431− memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
440+ ctx->rdma = iface->rdma_capable;
441+ memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr));
432442
433443 /* reuse master con client guid */
434− memcpy(&ctx.client_guid, ses->server->client_guid,
435− SMB2_CLIENT_GUID_SIZE);
436− ctx.use_client_guid = true;
444+ memcpy(&ctx->client_guid, ses->server->client_guid,
445+ sizeof(ctx->client_guid));
446+ ctx->use_client_guid = true;
437447
438− chan_server = cifs_get_tcp_session(&ctx, ses->server);
448+ chan_server = cifs_get_tcp_session(ctx, ses->server);
439449
440450 spin_lock(&ses->chan_lock);
441451 chan = &ses->chans[ses->chan_count];
@@ -497,6 +507,10 @@ out: · 55 unmodified lines
497507 cifs_put_tcp_session(chan->server, 0);
498508 }
499509
510+ kfree(ctx->UNC);
511+out_free_ctx:
512+ kfree(ctx);
513+out_free_xid:
500514 free_xid(xid);
501515 return rc;
502516 }
fs/smb/client/smb1ops.c+16−10
@@ -542,14 +542,17 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, · 541 unmodified lines
542542 return rc;
543543 }
544544
545−static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
546− struct cifs_sb_info *cifs_sb, const char *full_path,
547− struct cifs_open_info_data *data, bool *adjustTZ, bool *symlink)
545+static int cifs_query_path_info(const unsigned int xid,
546+ struct cifs_tcon *tcon,
547+ struct cifs_sb_info *cifs_sb,
548+ const char *full_path,
549+ struct cifs_open_info_data *data)
548550 {
549551 int rc;
550552 FILE_ALL_INFO fi = {};
551553
552− *symlink = false;
554+ data->symlink = false;
555+ data->adjust_tz = false;
553556
554557 /* could do find first instead but this returns more info */
555558 rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls,
@@ -562,7 +565,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 6 unmodified lines
562565 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
563566 rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
564567 cifs_remap(cifs_sb));
565− *adjustTZ = true;
568+ data->adjust_tz = true;
566569 }
567570
568571 if (!rc) {
@@ -589,7 +592,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 20 unmodified lines
589592 /* Need to check if this is a symbolic link or not */
590593 tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
591594 if (tmprc == -EOPNOTSUPP)
592− *symlink = true;
595+ data->symlink = true;
593596 else if (tmprc == 0)
594597 CIFSSMBClose(xid, tcon, fid.netfid);
595598 }
@@ -969,13 +972,16 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon, · 373 unmodified lines
969972 #endif
970973 }
971974
972−static int
973−cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
974− struct cifs_sb_info *cifs_sb, const char *full_path,
975− char **target_path, bool is_reparse_point)
975+static int cifs_query_symlink(const unsigned int xid,
976+ struct cifs_tcon *tcon,
977+ struct cifs_sb_info *cifs_sb,
978+ const char *full_path,
979+ char **target_path,
980+ struct kvec *rsp_iov)
976981 {
977982 int rc;
978983 int oplock = 0;
984+ bool is_reparse_point = !!rsp_iov;
979985 struct cifs_fid fid;
980986 struct cifs_open_parms oparms;
981987
fs/smb/client/smb2inode.c+115−88
@@ -35,34 +35,22 @@ free_set_inf_compound(struct smb_rqst *rqst) · 34 unmodified lines
3535 SMB2_close_free(&rqst[2]);
3636 }
3737
38−
39−struct cop_vars {
40− struct cifs_open_parms oparms;
41− struct kvec rsp_iov[3];
42− struct smb_rqst rqst[3];
43− struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
44− struct kvec qi_iov[1];
45− struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
46− struct kvec close_iov[1];
47− struct smb2_file_rename_info rename_info;
48− struct smb2_file_link_info link_info;
49−};
50−
5138 /*
5239 * note: If cfile is passed, the reference to it is dropped here.
5340 * So make sure that you do not reuse cfile after return from this func.
5441 *
55− * If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all
56− * error responses. Caller is also responsible for freeing them up.
42+ * If passing @out_iov and @out_buftype, ensure to make them both large enough
43+ * (>= 3) to hold all compounded responses. Caller is also responsible for
44+ * freeing them up with free_rsp_buf().
5745 */
5846 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
5947 struct cifs_sb_info *cifs_sb, const char *full_path,
6048 __u32 desired_access, __u32 create_disposition, __u32 create_options,
6149 umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
6250 __u8 **extbuf, size_t *extbuflen,
63− struct kvec *err_iov, int *err_buftype)
51+ struct kvec *out_iov, int *out_buftype)
6452 {
65− struct cop_vars *vars = NULL;
53+ struct smb2_compound_vars *vars = NULL;
6654 struct kvec *rsp_iov;
6755 struct smb_rqst *rqst;
6856 int rc;
@@ -133,7 +121,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 64 unmodified lines
133121 /* Operation */
134122 switch (command) {
135123 case SMB2_OP_QUERY_INFO:
136− rqst[num_rqst].rq_iov = &vars->qi_iov[0];
124+ rqst[num_rqst].rq_iov = &vars->qi_iov;
137125 rqst[num_rqst].rq_nvec = 1;
138126
139127 if (cfile)
@@ -167,7 +155,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 27 unmodified lines
167155 full_path);
168156 break;
169157 case SMB2_OP_POSIX_QUERY_INFO:
170− rqst[num_rqst].rq_iov = &vars->qi_iov[0];
158+ rqst[num_rqst].rq_iov = &vars->qi_iov;
171159 rqst[num_rqst].rq_nvec = 1;
172160
173161 if (cfile)
@@ -375,7 +363,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 201 unmodified lines
375363 goto after_close;
376364 /* Close */
377365 flags |= CIFS_CP_CREATE_CLOSE_OP;
378− rqst[num_rqst].rq_iov = &vars->close_iov[0];
366+ rqst[num_rqst].rq_iov = &vars->close_iov;
379367 rqst[num_rqst].rq_nvec = 1;
380368 rc = SMB2_close_init(tcon, server,
381369 &rqst[num_rqst], COMPOUND_FID,
@@ -529,9 +517,9 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 147 unmodified lines
529517 if (cfile)
530518 cifsFileInfo_put(cfile);
531519
532− if (rc && err_iov && err_buftype) {
533− memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov));
534− memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype));
520+ if (out_iov && out_buftype) {
521+ memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov));
522+ memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype));
535523 } else {
536524 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
537525 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
@@ -541,20 +529,50 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, · 3 unmodified lines
541529 return rc;
542530 }
543531
544−int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
545− struct cifs_sb_info *cifs_sb, const char *full_path,
546− struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse)
532+static int parse_create_response(struct cifs_open_info_data *data,
533+ struct cifs_sb_info *cifs_sb,
534+ const struct kvec *iov)
535+{
536+ struct smb2_create_rsp *rsp = iov->iov_base;
537+ bool reparse_point = false;
538+ u32 tag = 0;
539+ int rc = 0;
540+
541+ switch (rsp->hdr.Status) {
542+ case STATUS_STOPPED_ON_SYMLINK:
543+ rc = smb2_parse_symlink_response(cifs_sb, iov,
544+ &data->symlink_target);
545+ if (rc)
546+ return rc;
547+ tag = IO_REPARSE_TAG_SYMLINK;
548+ reparse_point = true;
549+ break;
550+ case STATUS_SUCCESS:
551+ reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
552+ break;
553+ }
554+ data->reparse_point = reparse_point;
555+ data->reparse_tag = tag;
556+ return rc;
557+}
558+
559+int smb2_query_path_info(const unsigned int xid,
560+ struct cifs_tcon *tcon,
561+ struct cifs_sb_info *cifs_sb,
562+ const char *full_path,
563+ struct cifs_open_info_data *data)
547564 {
548565 __u32 create_options = 0;
549566 struct cifsFileInfo *cfile;
550567 struct cached_fid *cfid = NULL;
551− struct kvec err_iov[3] = {};
552− int err_buftype[3] = {};
568+ struct smb2_hdr *hdr;
569+ struct kvec out_iov[3] = {};
570+ int out_buftype[3] = {};
553571 bool islink;
554572 int rc, rc2;
555573
556− *adjust_tz = false;
557− *reparse = false;
574+ data->adjust_tz = false;
575+ data->reparse_point = false;
558576
559577 if (strcmp(full_path, ""))
560578 rc = -ENOENT;
@@ -575,69 +593,73 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 14 unmodified lines
575593 cifs_get_readable_path(tcon, full_path, &cfile);
576594 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
577595 create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
578− NULL, NULL, err_iov, err_buftype);
579− if (rc) {
580− struct smb2_hdr *hdr = err_iov[0].iov_base;
581−
582− if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER))
596+ NULL, NULL, out_iov, out_buftype);
597+ hdr = out_iov[0].iov_base;
598+ /*
599+ * If first iov is unset, then SMB session was dropped or we've got a
600+ * cached open file (@cfile).
601+ */
602+ if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
603+ goto out;
604+
605+ switch (rc) {
606+ case 0:
607+ case -EOPNOTSUPP:
608+ rc = parse_create_response(data, cifs_sb, &out_iov[0]);
609+ if (rc || !data->reparse_point)
583610 goto out;
584− if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
585− hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
586− rc = smb2_parse_symlink_response(cifs_sb, err_iov,
587− &data->symlink_target);
588− if (rc)
589− goto out;
590−
591− *reparse = true;
592− create_options |= OPEN_REPARSE_POINT;
593−
594− /* Failed on a symbolic link - query a reparse point info */
595− cifs_get_readable_path(tcon, full_path, &cfile);
596− rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
597− FILE_READ_ATTRIBUTES, FILE_OPEN,
598− create_options, ACL_NO_MODE, data,
599− SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
600− NULL, NULL);
611+
612+ create_options |= OPEN_REPARSE_POINT;
613+ /* Failed on a symbolic link - query a reparse point info */
614+ cifs_get_readable_path(tcon, full_path, &cfile);
615+ rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
616+ FILE_READ_ATTRIBUTES, FILE_OPEN,
617+ create_options, ACL_NO_MODE, data,
618+ SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
619+ NULL, NULL);
620+ break;
621+ case -EREMOTE:
622+ break;
623+ default:
624+ if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
625+ break;
626+ rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
627+ full_path, &islink);
628+ if (rc2) {
629+ rc = rc2;
601630 goto out;
602− } else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) {
603− rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
604− full_path, &islink);
605− if (rc2) {
606− rc = rc2;
607− goto out;
608− }
609− if (islink)
610− rc = -EREMOTE;
611631 }
632+ if (islink)
633+ rc = -EREMOTE;
612634 }
613635
614636 out:
615− free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
616− free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
617− free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
637+ free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
638+ free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
639+ free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
618640 return rc;
619641 }
620642
621−
622−int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
623− struct cifs_sb_info *cifs_sb, const char *full_path,
643+int smb311_posix_query_path_info(const unsigned int xid,
644+ struct cifs_tcon *tcon,
645+ struct cifs_sb_info *cifs_sb,
646+ const char *full_path,
624647 struct cifs_open_info_data *data,
625648 struct cifs_sid *owner,
626− struct cifs_sid *group,
627− bool *adjust_tz, bool *reparse)
649+ struct cifs_sid *group)
628650 {
629651 int rc;
630652 __u32 create_options = 0;
631653 struct cifsFileInfo *cfile;
632− struct kvec err_iov[3] = {};
633− int err_buftype[3] = {};
654+ struct kvec out_iov[3] = {};
655+ int out_buftype[3] = {};
634656 __u8 *sidsbuf = NULL;
635657 __u8 *sidsbuf_end = NULL;
636658 size_t sidsbuflen = 0;
637659 size_t owner_len, group_len;
638660
639− *adjust_tz = false;
640− *reparse = false;
661+ data->adjust_tz = false;
662+ data->reparse_point = false;
641663
642664 /*
643665 * BB TODO: Add support for using the cached root handle.
@@ -649,27 +671,33 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 5 unmodified lines
649671 cifs_get_readable_path(tcon, full_path, &cfile);
650672 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
651673 create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
652− &sidsbuf, &sidsbuflen, err_iov, err_buftype);
653− if (rc == -EOPNOTSUPP) {
674+ &sidsbuf, &sidsbuflen, out_iov, out_buftype);
675+ /*
676+ * If first iov is unset, then SMB session was dropped or we've got a
677+ * cached open file (@cfile).
678+ */
679+ if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
680+ goto out;
681+
682+ switch (rc) {
683+ case 0:
684+ case -EOPNOTSUPP:
654685 /* BB TODO: When support for special files added to Samba re-verify this path */
655− if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
656− ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
657− ((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
658− rc = smb2_parse_symlink_response(cifs_sb, err_iov, &data->symlink_target);
659− if (rc)
660− goto out;
661− }
662− *reparse = true;
663− create_options |= OPEN_REPARSE_POINT;
686+ rc = parse_create_response(data, cifs_sb, &out_iov[0]);
687+ if (rc || !data->reparse_point)
688+ goto out;
664689
690+ create_options |= OPEN_REPARSE_POINT;
665691 /* Failed on a symbolic link - query a reparse point info */
666692 cifs_get_readable_path(tcon, full_path, &cfile);
667693 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
668694 FILE_OPEN, create_options, ACL_NO_MODE, data,
669695 SMB2_OP_POSIX_QUERY_INFO, cfile,
670696 &sidsbuf, &sidsbuflen, NULL, NULL);
697+ break;
671698 }
672699
700+out:
673701 if (rc == 0) {
674702 sidsbuf_end = sidsbuf + sidsbuflen;
675703
@@ -689,11 +717,10 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines
689717 memcpy(group, sidsbuf + owner_len, group_len);
690718 }
691719
692−out:
693720 kfree(sidsbuf);
694− free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
695− free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
696− free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
721+ free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
722+ free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
723+ free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
697724 return rc;
698725 }
699726
fs/smb/client/smb2misc.c+3−3
@@ -145,7 +145,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server) · 144 unmodified lines
145145 __u64 mid;
146146
147147 /* If server is a channel, select the primary channel */
148− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
148+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
149149
150150 /*
151151 * Add function to do table lookup of StructureSize by command
@@ -623,7 +623,7 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) · 471 unmodified lines
623623 cifs_dbg(FYI, "Checking for lease break\n");
624624
625625 /* If server is a channel, select the primary channel */
626− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
626+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
627627
628628 /* look up tcon based on tid & uid */
629629 spin_lock(&cifs_tcp_ses_lock);
@@ -698,7 +698,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) · 68 unmodified lines
698698 cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel);
699699
700700 /* If server is a channel, select the primary channel */
701− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
701+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
702702
703703 /* look up tcon based on tid & uid */
704704 spin_lock(&cifs_tcp_ses_lock);
fs/smb/client/smb2ops.c+91−207
@@ -172,8 +172,17 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val) · 171 unmodified lines
172172
173173 spin_lock(&server->req_lock);
174174 server->credits = val;
175− if (val == 1)
175+ if (val == 1) {
176176 server->reconnect_instance++;
177+ /*
178+ * ChannelSequence updated for all channels in primary channel so that consistent
179+ * across SMB3 requests sent on any channel. See MS-SMB2 3.2.4.1 and 3.2.7.1
180+ */
181+ if (SERVER_IS_CHAN(server))
182+ server->primary_server->channel_sequence_num++;
183+ else
184+ server->channel_sequence_num++;
185+ }
177186 scredits = server->credits;
178187 in_flight = server->in_flight;
179188 spin_unlock(&server->req_lock);
@@ -1075,31 +1084,28 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, · 895 unmodified lines
10751084 return rc;
10761085 }
10771086
1078−
10791087 static int
10801088 smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
10811089 const char *path, const char *ea_name, const void *ea_value,
10821090 const __u16 ea_value_len, const struct nls_table *nls_codepage,
10831091 struct cifs_sb_info *cifs_sb)
10841092 {
1093+ struct smb2_compound_vars *vars;
10851094 struct cifs_ses *ses = tcon->ses;
10861095 struct TCP_Server_Info *server = cifs_pick_channel(ses);
1096+ struct smb_rqst *rqst;
1097+ struct kvec *rsp_iov;
10871098 __le16 *utf16_path = NULL;
10881099 int ea_name_len = strlen(ea_name);
10891100 int flags = CIFS_CP_CREATE_CLOSE_OP;
10901101 int len;
1091− struct smb_rqst rqst[3];
10921102 int resp_buftype[3];
1093− struct kvec rsp_iov[3];
1094− struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
10951103 struct cifs_open_parms oparms;
10961104 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
10971105 struct cifs_fid fid;
1098− struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
10991106 unsigned int size[1];
11001107 void *data[1];
11011108 struct smb2_file_full_ea_info *ea = NULL;
1102− struct kvec close_iov[1];
11031109 struct smb2_query_info_rsp *rsp;
11041110 int rc, used_len = 0;
11051111
@@ -1113,9 +1119,14 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 7 unmodified lines
11131119 if (!utf16_path)
11141120 return -ENOMEM;
11151121
1116− memset(rqst, 0, sizeof(rqst));
11171122 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
1118− memset(rsp_iov, 0, sizeof(rsp_iov));
1123+ vars = kzalloc(sizeof(*vars), GFP_KERNEL);
1124+ if (!vars) {
1125+ rc = -ENOMEM;
1126+ goto out_free_path;
1127+ }
1128+ rqst = vars->rqst;
1129+ rsp_iov = vars->rsp_iov;
11191130
11201131 if (ses->server->ops->query_all_EAs) {
11211132 if (!ea_value) {
@@ -1160,8 +1171,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 38 unmodified lines
11601171 }
11611172
11621173 /* Open */
1163− memset(&open_iov, 0, sizeof(open_iov));
1164− rqst[0].rq_iov = open_iov;
1174+ rqst[0].rq_iov = vars->open_iov;
11651175 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
11661176
11671177 oparms = (struct cifs_open_parms) {
@@ -1181,8 +1191,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines
11811191
11821192
11831193 /* Set Info */
1184− memset(&si_iov, 0, sizeof(si_iov));
1185− rqst[1].rq_iov = si_iov;
1194+ rqst[1].rq_iov = vars->si_iov;
11861195 rqst[1].rq_nvec = 1;
11871196
11881197 len = sizeof(*ea) + ea_name_len + ea_value_len + 1;
@@ -1210,10 +1219,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 21 unmodified lines
12101219 smb2_set_next_command(tcon, &rqst[1]);
12111220 smb2_set_related(&rqst[1]);
12121221
1213−
12141222 /* Close */
1215− memset(&close_iov, 0, sizeof(close_iov));
1216− rqst[2].rq_iov = close_iov;
1223+ rqst[2].rq_iov = &vars->close_iov;
12171224 rqst[2].rq_nvec = 1;
12181225 rc = SMB2_close_init(tcon, server,
12191226 &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
@@ -1228,13 +1235,15 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, · 8 unmodified lines
12281235
12291236 sea_exit:
12301237 kfree(ea);
1231− kfree(utf16_path);
12321238 SMB2_open_free(&rqst[0]);
12331239 SMB2_set_info_free(&rqst[1]);
12341240 SMB2_close_free(&rqst[2]);
12351241 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
12361242 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
12371243 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
1244+ kfree(vars);
1245+out_free_path:
1246+ kfree(utf16_path);
12381247 return rc;
12391248 }
12401249 #endif
@@ -1446,16 +1455,6 @@ req_res_key_exit: · 205 unmodified lines
14461455 return rc;
14471456 }
14481457
1449−struct iqi_vars {
1450− struct smb_rqst rqst[3];
1451− struct kvec rsp_iov[3];
1452− struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
1453− struct kvec qi_iov[1];
1454− struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
1455− struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
1456− struct kvec close_iov[1];
1457−};
1458−
14591458 static int
14601459 smb2_ioctl_query_info(const unsigned int xid,
14611460 struct cifs_tcon *tcon,
@@ -1463,7 +1462,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 1 unmodified line
14631462 __le16 *path, int is_dir,
14641463 unsigned long p)
14651464 {
1466− struct iqi_vars *vars;
1465+ struct smb2_compound_vars *vars;
14671466 struct smb_rqst *rqst;
14681467 struct kvec *rsp_iov;
14691468 struct cifs_ses *ses = tcon->ses;
@@ -1581,7 +1580,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 111 unmodified lines
15811580 rc = -EINVAL;
15821581 goto free_open_req;
15831582 }
1584− rqst[1].rq_iov = &vars->si_iov[0];
1583+ rqst[1].rq_iov = vars->si_iov;
15851584 rqst[1].rq_nvec = 1;
15861585
15871586 /* MS-FSCC 2.4.13 FileEndOfFileInformation */
@@ -1593,7 +1592,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 5 unmodified lines
15931592 SMB2_O_INFO_FILE, 0, data, size);
15941593 free_req1_func = SMB2_set_info_free;
15951594 } else if (qi.flags == PASSTHRU_QUERY_INFO) {
1596− rqst[1].rq_iov = &vars->qi_iov[0];
1595+ rqst[1].rq_iov = &vars->qi_iov;
15971596 rqst[1].rq_nvec = 1;
15981597
15991598 rc = SMB2_query_info_init(tcon, server,
@@ -1615,7 +1614,7 @@ smb2_ioctl_query_info(const unsigned int xid, · 15 unmodified lines
16151614 smb2_set_related(&rqst[1]);
16161615
16171616 /* Close */
1618− rqst[2].rq_iov = &vars->close_iov[0];
1617+ rqst[2].rq_iov = &vars->close_iov;
16191618 rqst[2].rq_nvec = 1;
16201619
16211620 rc = SMB2_close_init(tcon, server,
@@ -2408,7 +2407,7 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server) · 786 unmodified lines
24082407 return false;
24092408
24102409 /* If server is a channel, select the primary channel */
2411− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
2410+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
24122411
24132412 spin_lock(&cifs_tcp_ses_lock);
24142413 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
@@ -2524,15 +2523,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 109 unmodified lines
25242523 struct kvec *rsp, int *buftype,
25252524 struct cifs_sb_info *cifs_sb)
25262525 {
2526+ struct smb2_compound_vars *vars;
25272527 struct cifs_ses *ses = tcon->ses;
25282528 struct TCP_Server_Info *server = cifs_pick_channel(ses);
25292529 int flags = CIFS_CP_CREATE_CLOSE_OP;
2530− struct smb_rqst rqst[3];
2530+ struct smb_rqst *rqst;
25312531 int resp_buftype[3];
2532− struct kvec rsp_iov[3];
2533− struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
2534− struct kvec qi_iov[1];
2535− struct kvec close_iov[1];
2532+ struct kvec *rsp_iov;
25362533 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
25372534 struct cifs_open_parms oparms;
25382535 struct cifs_fid fid;
@@ -2549,9 +2546,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 10 unmodified lines
25492546 if (smb3_encryption_required(tcon))
25502547 flags |= CIFS_TRANSFORM_REQ;
25512548
2552− memset(rqst, 0, sizeof(rqst));
25532549 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
2554− memset(rsp_iov, 0, sizeof(rsp_iov));
2550+ vars = kzalloc(sizeof(*vars), GFP_KERNEL);
2551+ if (!vars) {
2552+ rc = -ENOMEM;
2553+ goto out_free_path;
2554+ }
2555+ rqst = vars->rqst;
2556+ rsp_iov = vars->rsp_iov;
25552557
25562558 /*
25572559 * We can only call this for things we know are directories.
@@ -2560,8 +2562,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 2 unmodified lines
25602562 open_cached_dir(xid, tcon, path, cifs_sb, false,
25612563 &cfid); /* cfid null if open dir failed */
25622564
2563− memset(&open_iov, 0, sizeof(open_iov));
2564− rqst[0].rq_iov = open_iov;
2565+ rqst[0].rq_iov = vars->open_iov;
25652566 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
25662567
25672568 oparms = (struct cifs_open_parms) {
@@ -2579,8 +2580,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 11 unmodified lines
25792580 goto qic_exit;
25802581 smb2_set_next_command(tcon, &rqst[0]);
25812582
2582− memset(&qi_iov, 0, sizeof(qi_iov));
2583− rqst[1].rq_iov = qi_iov;
2583+ rqst[1].rq_iov = &vars->qi_iov;
25842584 rqst[1].rq_nvec = 1;
25852585
25862586 if (cfid) {
@@ -2607,8 +2607,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 20 unmodified lines
26072607 smb2_set_related(&rqst[1]);
26082608 }
26092609
2610− memset(&close_iov, 0, sizeof(close_iov));
2611− rqst[2].rq_iov = close_iov;
2610+ rqst[2].rq_iov = &vars->close_iov;
26122611 rqst[2].rq_nvec = 1;
26132612
26142613 rc = SMB2_close_init(tcon, server,
@@ -2639,7 +2638,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 24 unmodified lines
26392638 *buftype = resp_buftype[1];
26402639
26412640 qic_exit:
2642− kfree(utf16_path);
26432641 SMB2_open_free(&rqst[0]);
26442642 SMB2_query_info_free(&rqst[1]);
26452643 SMB2_close_free(&rqst[2]);
@@ -2647,6 +2645,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, · 1 unmodified line
26472645 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
26482646 if (cfid)
26492647 close_cached_dir(cfid);
2648+ kfree(vars);
2649+out_free_path:
2650+ kfree(utf16_path);
26502651 return rc;
26512652 }
26522653
@@ -2949,154 +2950,32 @@ parse_reparse_point(struct reparse_data_buffer *buf, · 296 unmodified lines
29492950 }
29502951 }
29512952
2952−static int
2953−smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
2954− struct cifs_sb_info *cifs_sb, const char *full_path,
2955− char **target_path, bool is_reparse_point)
2953+static int smb2_query_symlink(const unsigned int xid,
2954+ struct cifs_tcon *tcon,
2955+ struct cifs_sb_info *cifs_sb,
2956+ const char *full_path,
2957+ char **target_path,
2958+ struct kvec *rsp_iov)
29562959 {
2957− int rc;
2958− __le16 *utf16_path = NULL;
2959− __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
2960− struct cifs_open_parms oparms;
2961− struct cifs_fid fid;
2962− struct kvec err_iov = {NULL, 0};
2963− struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
2964− int flags = CIFS_CP_CREATE_CLOSE_OP;
2965− struct smb_rqst rqst[3];
2966− int resp_buftype[3];
2967− struct kvec rsp_iov[3];
2968− struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
2969− struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
2970− struct kvec close_iov[1];
2971− struct smb2_create_rsp *create_rsp;
2972− struct smb2_ioctl_rsp *ioctl_rsp;
2973− struct reparse_data_buffer *reparse_buf;
2974− int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
2975− u32 plen;
2960+ struct reparse_data_buffer *buf;
2961+ struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
2962+ u32 plen = le32_to_cpu(io->OutputCount);
29762963
29772964 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
29782965
2979− *target_path = NULL;
2980−
2981− if (smb3_encryption_required(tcon))
2982− flags |= CIFS_TRANSFORM_REQ;
2983−
2984− memset(rqst, 0, sizeof(rqst));
2985− resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
2986− memset(rsp_iov, 0, sizeof(rsp_iov));
2987−
2988− utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
2989− if (!utf16_path)
2990− return -ENOMEM;
2991−
2992− /* Open */
2993− memset(&open_iov, 0, sizeof(open_iov));
2994− rqst[0].rq_iov = open_iov;
2995− rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
2996−
2997− oparms = (struct cifs_open_parms) {
2998− .tcon = tcon,
2999− .path = full_path,
3000− .desired_access = FILE_READ_ATTRIBUTES,
3001− .disposition = FILE_OPEN,
3002− .create_options = cifs_create_options(cifs_sb, create_options),
3003− .fid = &fid,
3004− };
3005−
3006− rc = SMB2_open_init(tcon, server,
3007− &rqst[0], &oplock, &oparms, utf16_path);
3008− if (rc)
3009− goto querty_exit;
3010− smb2_set_next_command(tcon, &rqst[0]);
3011−
3012−
3013− /* IOCTL */
3014− memset(&io_iov, 0, sizeof(io_iov));
3015− rqst[1].rq_iov = io_iov;
3016− rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
3017−
3018− rc = SMB2_ioctl_init(tcon, server,
3019− &rqst[1], fid.persistent_fid,
3020− fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
3021− CIFSMaxBufSize -
3022− MAX_SMB2_CREATE_RESPONSE_SIZE -
3023− MAX_SMB2_CLOSE_RESPONSE_SIZE);
3024− if (rc)
3025− goto querty_exit;
3026−
3027− smb2_set_next_command(tcon, &rqst[1]);
3028− smb2_set_related(&rqst[1]);
3029−
3030−
3031− /* Close */
3032− memset(&close_iov, 0, sizeof(close_iov));
3033− rqst[2].rq_iov = close_iov;
3034− rqst[2].rq_nvec = 1;
3035−
3036− rc = SMB2_close_init(tcon, server,
3037− &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
3038− if (rc)
3039− goto querty_exit;
3040−
3041− smb2_set_related(&rqst[2]);
3042−
3043− rc = compound_send_recv(xid, tcon->ses, server,
3044− flags, 3, rqst,
3045− resp_buftype, rsp_iov);
3046−
3047− create_rsp = rsp_iov[0].iov_base;
3048− if (create_rsp && create_rsp->hdr.Status)
3049− err_iov = rsp_iov[0];
3050− ioctl_rsp = rsp_iov[1].iov_base;
3051−
3052− /*
3053− * Open was successful and we got an ioctl response.
3054− */
3055− if ((rc == 0) && (is_reparse_point)) {
3056− /* See MS-FSCC 2.3.23 */
3057−
3058− reparse_buf = (struct reparse_data_buffer *)
3059− ((char *)ioctl_rsp +
3060− le32_to_cpu(ioctl_rsp->OutputOffset));
3061− plen = le32_to_cpu(ioctl_rsp->OutputCount);
3062−
3063− if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
3064− rsp_iov[1].iov_len) {
3065− cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
3066− plen);
3067− rc = -EIO;
3068− goto querty_exit;
3069− }
3070−
3071− rc = parse_reparse_point(reparse_buf, plen, target_path,
3072− cifs_sb);
3073− goto querty_exit;
3074− }
3075−
3076− if (!rc || !err_iov.iov_base) {
3077− rc = -ENOENT;
3078− goto querty_exit;
3079− }
3080−
3081− rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path);
3082−
3083− querty_exit:
3084− cifs_dbg(FYI, "query symlink rc %d\n", rc);
3085− kfree(utf16_path);
3086− SMB2_open_free(&rqst[0]);
3087− SMB2_ioctl_free(&rqst[1]);
3088− SMB2_close_free(&rqst[2]);
3089− free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
3090− free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
3091− free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
3092− return rc;
2966+ buf = (struct reparse_data_buffer *)((u8 *)io +
2967+ le32_to_cpu(io->OutputOffset));
2968+ return parse_reparse_point(buf, plen, target_path, cifs_sb);
30932969 }
30942970
3095−int
3096−smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
3097− struct cifs_sb_info *cifs_sb, const char *full_path,
3098− __u32 *tag)
2971+static int smb2_query_reparse_point(const unsigned int xid,
2972+ struct cifs_tcon *tcon,
2973+ struct cifs_sb_info *cifs_sb,
2974+ const char *full_path,
2975+ u32 *tag, struct kvec *rsp,
2976+ int *rsp_buftype)
30992977 {
2978+ struct smb2_compound_vars *vars;
31002979 int rc;
31012980 __le16 *utf16_path = NULL;
31022981 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
@@ -3104,12 +2983,9 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, · 1 unmodified line
31042983 struct cifs_fid fid;
31052984 struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
31062985 int flags = CIFS_CP_CREATE_CLOSE_OP;
3107− struct smb_rqst rqst[3];
2986+ struct smb_rqst *rqst;
31082987 int resp_buftype[3];
3109− struct kvec rsp_iov[3];
3110− struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
3111− struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
3112− struct kvec close_iov[1];
2988+ struct kvec *rsp_iov;
31132989 struct smb2_ioctl_rsp *ioctl_rsp;
31142990 struct reparse_data_buffer *reparse_buf;
31152991 u32 plen;
@@ -3119,20 +2995,24 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, · 3 unmodified lines
31192995 if (smb3_encryption_required(tcon))
31202996 flags |= CIFS_TRANSFORM_REQ;
31212997
3122− memset(rqst, 0, sizeof(rqst));
3123− resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
3124− memset(rsp_iov, 0, sizeof(rsp_iov));
3125−
31262998 utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
31272999 if (!utf16_path)
31283000 return -ENOMEM;
31293001
3002+ resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
3003+ vars = kzalloc(sizeof(*vars), GFP_KERNEL);
3004+ if (!vars) {
3005+ rc = -ENOMEM;
3006+ goto out_free_path;
3007+ }
3008+ rqst = vars->rqst;
3009+ rsp_iov = vars->rsp_iov;
3010+
31303011 /*
31313012 * setup smb2open - TODO add optimization to call cifs_get_readable_path
31323013 * to see if there is a handle already open that we can use
31333014 */
3134− memset(&open_iov, 0, sizeof(open_iov));
3135− rqst[0].rq_iov = open_iov;
3015+ rqst[0].rq_iov = vars->open_iov;
31363016 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
31373017
31383018 oparms = (struct cifs_open_parms) {
@@ -3152,8 +3032,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, · 13 unmodified lines
31523032
31533033
31543034 /* IOCTL */
3155− memset(&io_iov, 0, sizeof(io_iov));
3156− rqst[1].rq_iov = io_iov;
3035+ rqst[1].rq_iov = vars->io_iov;
31573036 rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
31583037
31593038 rc = SMB2_ioctl_init(tcon, server,
@@ -3168,10 +3047,8 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, · 8 unmodified lines
31683047 smb2_set_next_command(tcon, &rqst[1]);
31693048 smb2_set_related(&rqst[1]);
31703049
3171−
31723050 /* Close */
3173− memset(&close_iov, 0, sizeof(close_iov));
3174− rqst[2].rq_iov = close_iov;
3051+ rqst[2].rq_iov = &vars->close_iov;
31753052 rqst[2].rq_nvec = 1;
31763053
31773054 rc = SMB2_close_init(tcon, server,
@@ -3206,16 +3083,21 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, · 28 unmodified lines
32063083 goto query_rp_exit;
32073084 }
32083085 *tag = le32_to_cpu(reparse_buf->ReparseTag);
3086+ *rsp = rsp_iov[1];
3087+ *rsp_buftype = resp_buftype[1];
3088+ resp_buftype[1] = CIFS_NO_BUFFER;
32093089 }
32103090
32113091 query_rp_exit:
3212− kfree(utf16_path);
32133092 SMB2_open_free(&rqst[0]);
32143093 SMB2_ioctl_free(&rqst[1]);
32153094 SMB2_close_free(&rqst[2]);
32163095 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
32173096 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
32183097 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
3098+ kfree(vars);
3099+out_free_path:
3100+ kfree(utf16_path);
32193101 return rc;
32203102 }
32213103
@@ -4401,7 +4283,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key) · 1179 unmodified lines
44014283 u8 *ses_enc_key;
44024284
44034285 /* If server is a channel, select the primary channel */
4404− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
4286+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
44054287
44064288 spin_lock(&cifs_tcp_ses_lock);
44074289 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
@@ -5299,6 +5181,7 @@ struct smb_version_operations smb20_operations = { · 891 unmodified lines
52995181 .can_echo = smb2_can_echo,
53005182 .echo = SMB2_echo,
53015183 .query_path_info = smb2_query_path_info,
5184+ .query_reparse_point = smb2_query_reparse_point,
53025185 .get_srv_inum = smb2_get_srv_inum,
53035186 .query_file_info = smb2_query_file_info,
53045187 .set_path_size = smb2_set_path_size,
@@ -5400,6 +5283,7 @@ struct smb_version_operations smb21_operations = { · 95 unmodified lines
54005283 .can_echo = smb2_can_echo,
54015284 .echo = SMB2_echo,
54025285 .query_path_info = smb2_query_path_info,
5286+ .query_reparse_point = smb2_query_reparse_point,
54035287 .get_srv_inum = smb2_get_srv_inum,
54045288 .query_file_info = smb2_query_file_info,
54055289 .set_path_size = smb2_set_path_size,
@@ -5504,7 +5388,7 @@ struct smb_version_operations smb30_operations = { · 98 unmodified lines
55045388 .echo = SMB2_echo,
55055389 .query_path_info = smb2_query_path_info,
55065390 /* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
5507− .query_reparse_tag = smb2_query_reparse_tag,
5391+ .query_reparse_point = smb2_query_reparse_point,
55085392 .get_srv_inum = smb2_get_srv_inum,
55095393 .query_file_info = smb2_query_file_info,
55105394 .set_path_size = smb2_set_path_size,
@@ -5617,7 +5501,7 @@ struct smb_version_operations smb311_operations = { · 106 unmodified lines
56175501 .can_echo = smb2_can_echo,
56185502 .echo = SMB2_echo,
56195503 .query_path_info = smb2_query_path_info,
5620− .query_reparse_tag = smb2_query_reparse_tag,
5504+ .query_reparse_point = smb2_query_reparse_point,
56215505 .get_srv_inum = smb2_get_srv_inum,
56225506 .query_file_info = smb2_query_file_info,
56235507 .set_path_size = smb2_set_path_size,
fs/smb/client/smb2pdu.c+15−4
@@ -88,9 +88,20 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd, · 87 unmodified lines
8888 const struct cifs_tcon *tcon,
8989 struct TCP_Server_Info *server)
9090 {
91+ struct smb3_hdr_req *smb3_hdr;
9192 shdr->ProtocolId = SMB2_PROTO_NUMBER;
9293 shdr->StructureSize = cpu_to_le16(64);
9394 shdr->Command = smb2_cmd;
95+ if (server->dialect >= SMB30_PROT_ID) {
96+ /* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
97+ smb3_hdr = (struct smb3_hdr_req *)shdr;
98+ /* if primary channel is not set yet, use default channel for chan sequence num */
99+ if (SERVER_IS_CHAN(server))
100+ smb3_hdr->ChannelSequence =
101+ cpu_to_le16(server->primary_server->channel_sequence_num);
102+ else
103+ smb3_hdr->ChannelSequence = cpu_to_le16(server->channel_sequence_num);
104+ }
94105 if (server) {
95106 spin_lock(&server->req_lock);
96107 /* Request up to 10 credits but don't go over the limit. */
@@ -553,7 +564,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 456 unmodified lines
553564 * secondary channels don't have the hostname field populated
554565 * use the hostname field in the primary channel instead
555566 */
556− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
567+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
557568 cifs_server_lock(pserver);
558569 hostname = pserver->hostname;
559570 if (hostname && (hostname[0] != 0)) {
@@ -2570,8 +2581,8 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, · 2010 unmodified lines
25702581
25712582 /* Do not append the separator if the path is empty */
25722583 if (path[0] != cpu_to_le16(0x0000)) {
2573− UniStrcat(*out_path, sep);
2574− UniStrcat(*out_path, path);
2584+ UniStrcat((wchar_t *)*out_path, (wchar_t *)sep);
2585+ UniStrcat((wchar_t *)*out_path, (wchar_t *)path);
25752586 }
25762587
25772588 unload_nls(cp);
@@ -3785,7 +3796,7 @@ void smb2_reconnect_server(struct work_struct *work) · 1207 unmodified lines
37853796 bool resched = false;
37863797
37873798 /* If server is a channel, select the primary channel */
3788− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
3799+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
37893800
37903801 /* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
37913802 mutex_lock(&pserver->reconnect_mutex);
fs/smb/client/smb2proto.h+10−7
@@ -56,9 +56,11 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server, · 55 unmodified lines
5656 extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
5757 struct cifs_sb_info *cifs_sb, const char *path,
5858 __u32 *reparse_tag);
59−int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
60− struct cifs_sb_info *cifs_sb, const char *full_path,
61− struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
59+int smb2_query_path_info(const unsigned int xid,
60+ struct cifs_tcon *tcon,
61+ struct cifs_sb_info *cifs_sb,
62+ const char *full_path,
63+ struct cifs_open_info_data *data);
6264 extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
6365 const char *full_path, __u64 size,
6466 struct cifs_sb_info *cifs_sb, bool set_alloc);
@@ -275,12 +277,13 @@ extern int smb2_query_info_compound(const unsigned int xid, · 210 unmodified lines
275277 struct kvec *rsp, int *buftype,
276278 struct cifs_sb_info *cifs_sb);
277279 /* query path info from the server using SMB311 POSIX extensions*/
278−int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
279− struct cifs_sb_info *cifs_sb, const char *full_path,
280+int smb311_posix_query_path_info(const unsigned int xid,
281+ struct cifs_tcon *tcon,
282+ struct cifs_sb_info *cifs_sb,
283+ const char *full_path,
280284 struct cifs_open_info_data *data,
281285 struct cifs_sid *owner,
282− struct cifs_sid *group,
283− bool *adjust_tz, bool *reparse);
286+ struct cifs_sid *group);
284287 int posix_info_parse(const void *beg, const void *end,
285288 struct smb2_posix_info_parsed *out);
286289 int posix_info_sid_size(const void *beg, const void *end);
fs/smb/client/smb2transport.c+2−2
@@ -86,7 +86,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) · 85 unmodified lines
8686 spin_lock(&cifs_tcp_ses_lock);
8787
8888 /* If server is a channel, select the primary channel */
89− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
89+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
9090
9191 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
9292 if (ses->Suid == ses_id)
@@ -149,7 +149,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) · 56 unmodified lines
149149 struct cifs_ses *ses;
150150
151151 /* If server is a channel, select the primary channel */
152− pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
152+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
153153
154154 list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
155155 if (ses->Suid != ses_id)
fs/smb/client/transport.c+17−12
@@ -416,13 +416,19 @@ out: · 415 unmodified lines
416416 return rc;
417417 }
418418
419+struct send_req_vars {
420+ struct smb2_transform_hdr tr_hdr;
421+ struct smb_rqst rqst[MAX_COMPOUND];
422+ struct kvec iov;
423+};
424+
419425 static int
420426 smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
421427 struct smb_rqst *rqst, int flags)
422428 {
423− struct kvec iov;
424− struct smb2_transform_hdr *tr_hdr;
425− struct smb_rqst cur_rqst[MAX_COMPOUND];
429+ struct send_req_vars *vars;
430+ struct smb_rqst *cur_rqst;
431+ struct kvec *iov;
426432 int rc;
427433
428434 if (!(flags & CIFS_TRANSFORM_REQ))
@@ -436,16 +442,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, · 7 unmodified lines
436442 return -EIO;
437443 }
438444
439− tr_hdr = kzalloc(sizeof(*tr_hdr), GFP_NOFS);
440− if (!tr_hdr)
445+ vars = kzalloc(sizeof(*vars), GFP_NOFS);
446+ if (!vars)
441447 return -ENOMEM;
448+ cur_rqst = vars->rqst;
449+ iov = &vars->iov;
442450
443− memset(&cur_rqst[0], 0, sizeof(cur_rqst));
444− memset(&iov, 0, sizeof(iov));
445−
446− iov.iov_base = tr_hdr;
447− iov.iov_len = sizeof(*tr_hdr);
448− cur_rqst[0].rq_iov = &iov;
451+ iov->iov_base = &vars->tr_hdr;
452+ iov->iov_len = sizeof(vars->tr_hdr);
453+ cur_rqst[0].rq_iov = iov;
449454 cur_rqst[0].rq_nvec = 1;
450455
451456 rc = server->ops->init_transform_rq(server, num_rqst + 1,
@@ -456,7 +461,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, · 4 unmodified lines
456461 rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
457462 smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
458463 out:
459− kfree(tr_hdr);
464+ kfree(vars);
460465 return rc;
461466 }
462467
fs/smb/common/smb2pdu.h+22−0
@@ -153,6 +153,28 @@ struct smb2_hdr { · 152 unmodified lines
153153 __u8 Signature[16];
154154 } __packed;
155155
156+struct smb3_hdr_req {
157+ __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
158+ __le16 StructureSize; /* 64 */
159+ __le16 CreditCharge; /* MBZ */
160+ __le16 ChannelSequence; /* See MS-SMB2 3.2.4.1 and 3.2.7.1 */
161+ __le16 Reserved;
162+ __le16 Command;
163+ __le16 CreditRequest; /* CreditResponse */
164+ __le32 Flags;
165+ __le32 NextCommand;
166+ __le64 MessageId;
167+ union {
168+ struct {
169+ __le32 ProcessId;
170+ __le32 TreeId;
171+ } __packed SyncId;
172+ __le64 AsyncId;
173+ } __packed Id;
174+ __le64 SessionId;
175+ __u8 Signature[16];
176+} __packed;
177+
156178 struct smb2_pdu {
157179 struct smb2_hdr hdr;
158180 __le16 StructureSize2; /* size of wct area (varies, request specific) */
fs/smb/server/Kconfig+1−0
@@ -5,6 +5,7 @@ config SMB_SERVER · 4 unmodified lines
55 depends on FILE_LOCKING
66 select NLS
77 select NLS_UTF8
8+ select NLS_UCS2_UTILS
89 select CRYPTO
910 select CRYPTO_MD5
1011 select CRYPTO_HMAC
fs/smb/server/unicode.c+0−1
@@ -11,7 +11,6 @@ · 10 unmodified lines
1111 #include <asm/unaligned.h>
1212 #include "glob.h"
1313 #include "unicode.h"
14−#include "uniupr.h"
1514 #include "smb_common.h"
1615
1716 /*
fs/smb/server/unicode.h+4−321
@@ -18,49 +18,14 @@ · 17 unmodified lines
1818 * This is a compressed table of upper and lower case conversion.
1919 *
2020 */
21−#ifndef _CIFS_UNICODE_H
22−#define _CIFS_UNICODE_H
21+#ifndef _SMB_UNICODE_H
22+#define _SMB_UNICODE_H
2323
2424 #include <asm/byteorder.h>
2525 #include <linux/types.h>
2626 #include <linux/nls.h>
2727 #include <linux/unicode.h>
28−
29−#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
30−
31−/*
32− * Windows maps these to the user defined 16 bit Unicode range since they are
33− * reserved symbols (along with \ and /), otherwise illegal to store
34− * in filenames in NTFS
35− */
36−#define UNI_ASTERISK ((__u16)('*' + 0xF000))
37−#define UNI_QUESTION ((__u16)('?' + 0xF000))
38−#define UNI_COLON ((__u16)(':' + 0xF000))
39−#define UNI_GRTRTHAN ((__u16)('>' + 0xF000))
40−#define UNI_LESSTHAN ((__u16)('<' + 0xF000))
41−#define UNI_PIPE ((__u16)('|' + 0xF000))
42−#define UNI_SLASH ((__u16)('\\' + 0xF000))
43−
44−/* Just define what we want from uniupr.h. We don't want to define the tables
45− * in each source file.
46− */
47−#ifndef UNICASERANGE_DEFINED
48−struct UniCaseRange {
49− wchar_t start;
50− wchar_t end;
51− signed char *table;
52−};
53−#endif /* UNICASERANGE_DEFINED */
54−
55−#ifndef UNIUPR_NOUPPER
56−extern signed char SmbUniUpperTable[512];
57−extern const struct UniCaseRange SmbUniUpperRange[];
58−#endif /* UNIUPR_NOUPPER */
59−
60−#ifndef UNIUPR_NOLOWER
61−extern signed char CifsUniLowerTable[512];
62−extern const struct UniCaseRange CifsUniLowerRange[];
63−#endif /* UNIUPR_NOLOWER */
28+#include "../../nls/nls_ucs2_utils.h"
6429
6530 #ifdef __KERNEL__
6631 int smb_strtoUTF16(__le16 *to, const char *from, int len,
@@ -73,286 +38,4 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen, · 6 unmodified lines
7338 char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
7439 #endif
7540
76−/*
77− * UniStrcat: Concatenate the second string to the first
78− *
79− * Returns:
80− * Address of the first string
81− */
82−static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
83−{
84− wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
85−
86− while (*ucs1++)
87− /*NULL*/; /* To end of first string */
88− ucs1--; /* Return to the null */
89− while ((*ucs1++ = *ucs2++))
90− /*NULL*/; /* copy string 2 over */
91− return anchor;
92−}
93−
94−/*
95− * UniStrchr: Find a character in a string
96− *
97− * Returns:
98− * Address of first occurrence of character in string
99− * or NULL if the character is not in the string
100− */
101−static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
102−{
103− while ((*ucs != uc) && *ucs)
104− ucs++;
105−
106− if (*ucs == uc)
107− return (wchar_t *)ucs;
108− return NULL;
109−}
110−
111−/*
112− * UniStrcmp: Compare two strings
113− *
114− * Returns:
115− * < 0: First string is less than second
116− * = 0: Strings are equal
117− * > 0: First string is greater than second
118− */
119−static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
120−{
121− while ((*ucs1 == *ucs2) && *ucs1) {
122− ucs1++;
123− ucs2++;
124− }
125− return (int)*ucs1 - (int)*ucs2;
126−}
127−
128−/*
129− * UniStrcpy: Copy a string
130− */
131−static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
132−{
133− wchar_t *anchor = ucs1; /* save the start of result string */
134−
135− while ((*ucs1++ = *ucs2++))
136− /*NULL*/;
137− return anchor;
138−}
139−
140−/*
141− * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
142− */
143−static inline size_t UniStrlen(const wchar_t *ucs1)
144−{
145− int i = 0;
146−
147− while (*ucs1++)
148− i++;
149− return i;
150−}
151−
152−/*
153− * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
154− * string (length limited)
155− */
156−static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
157−{
158− int i = 0;
159−
160− while (*ucs1++) {
161− i++;
162− if (i >= maxlen)
163− break;
164− }
165− return i;
166−}
167−
168−/*
169− * UniStrncat: Concatenate length limited string
170− */
171−static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
172−{
173− wchar_t *anchor = ucs1; /* save pointer to string 1 */
174−
175− while (*ucs1++)
176− /*NULL*/;
177− ucs1--; /* point to null terminator of s1 */
178− while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
179− ucs1++;
180− ucs2++;
181− }
182− *ucs1 = 0; /* Null terminate the result */
183− return anchor;
184−}
185−
186−/*
187− * UniStrncmp: Compare length limited string
188− */
189−static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
190−{
191− if (!n)
192− return 0; /* Null strings are equal */
193− while ((*ucs1 == *ucs2) && *ucs1 && --n) {
194− ucs1++;
195− ucs2++;
196− }
197− return (int)*ucs1 - (int)*ucs2;
198−}
199−
200−/*
201− * UniStrncmp_le: Compare length limited string - native to little-endian
202− */
203−static inline int
204−UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
205−{
206− if (!n)
207− return 0; /* Null strings are equal */
208− while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
209− ucs1++;
210− ucs2++;
211− }
212− return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
213−}
214−
215−/*
216− * UniStrncpy: Copy length limited string with pad
217− */
218−static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
219−{
220− wchar_t *anchor = ucs1;
221−
222− while (n-- && *ucs2) /* Copy the strings */
223− *ucs1++ = *ucs2++;
224−
225− n++;
226− while (n--) /* Pad with nulls */
227− *ucs1++ = 0;
228− return anchor;
229−}
230−
231−/*
232− * UniStrncpy_le: Copy length limited string with pad to little-endian
233− */
234−static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
235−{
236− wchar_t *anchor = ucs1;
237−
238− while (n-- && *ucs2) /* Copy the strings */
239− *ucs1++ = __le16_to_cpu(*ucs2++);
240−
241− n++;
242− while (n--) /* Pad with nulls */
243− *ucs1++ = 0;
244− return anchor;
245−}
246−
247−/*
248− * UniStrstr: Find a string in a string
249− *
250− * Returns:
251− * Address of first match found
252− * NULL if no matching string is found
253− */
254−static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
255−{
256− const wchar_t *anchor1 = ucs1;
257− const wchar_t *anchor2 = ucs2;
258−
259− while (*ucs1) {
260− if (*ucs1 == *ucs2) {
261− /* Partial match found */
262− ucs1++;
263− ucs2++;
264− } else {
265− if (!*ucs2) /* Match found */
266− return (wchar_t *)anchor1;
267− ucs1 = ++anchor1; /* No match */
268− ucs2 = anchor2;
269− }
270− }
271−
272− if (!*ucs2) /* Both end together */
273− return (wchar_t *)anchor1; /* Match found */
274− return NULL; /* No match */
275−}
276−
277−#ifndef UNIUPR_NOUPPER
278−/*
279− * UniToupper: Convert a unicode character to upper case
280− */
281−static inline wchar_t UniToupper(register wchar_t uc)
282−{
283− register const struct UniCaseRange *rp;
284−
285− if (uc < sizeof(SmbUniUpperTable)) {
286− /* Latin characters */
287− return uc + SmbUniUpperTable[uc]; /* Use base tables */
288− }
289−
290− rp = SmbUniUpperRange; /* Use range tables */
291− while (rp->start) {
292− if (uc < rp->start) /* Before start of range */
293− return uc; /* Uppercase = input */
294− if (uc <= rp->end) /* In range */
295− return uc + rp->table[uc - rp->start];
296− rp++; /* Try next range */
297− }
298− return uc; /* Past last range */
299−}
300−
301−/*
302− * UniStrupr: Upper case a unicode string
303− */
304−static inline __le16 *UniStrupr(register __le16 *upin)
305−{
306− register __le16 *up;
307−
308− up = upin;
309− while (*up) { /* For all characters */
310− *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
311− up++;
312− }
313− return upin; /* Return input pointer */
314−}
315−#endif /* UNIUPR_NOUPPER */
316−
317−#ifndef UNIUPR_NOLOWER
318−/*
319− * UniTolower: Convert a unicode character to lower case
320− */
321−static inline wchar_t UniTolower(register wchar_t uc)
322−{
323− register const struct UniCaseRange *rp;
324−
325− if (uc < sizeof(CifsUniLowerTable)) {
326− /* Latin characters */
327− return uc + CifsUniLowerTable[uc]; /* Use base tables */
328− }
329−
330− rp = CifsUniLowerRange; /* Use range tables */
331− while (rp->start) {
332− if (uc < rp->start) /* Before start of range */
333− return uc; /* Uppercase = input */
334− if (uc <= rp->end) /* In range */
335− return uc + rp->table[uc - rp->start];
336− rp++; /* Try next range */
337− }
338− return uc; /* Past last range */
339−}
340−
341−/*
342− * UniStrlwr: Lower case a unicode string
343− */
344−static inline wchar_t *UniStrlwr(register wchar_t *upin)
345−{
346− register wchar_t *up;
347−
348− up = upin;
349− while (*up) { /* For all characters */
350− *up = UniTolower(*up);
351− up++;
352− }
353− return upin; /* Return input pointer */
354−}
355−
356−#endif
357−
358−#endif /* _CIFS_UNICODE_H */
41+#endif /* _SMB_UNICODE_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t