summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/jfs/Kconfig1
-rw-r--r--fs/jfs/Makefile2
-rw-r--r--fs/jfs/jfs_unicode.h17
-rw-r--r--fs/jfs/jfs_uniupr.c121
-rw-r--r--fs/nls/Kconfig8
-rw-r--r--fs/nls/Makefile1
-rw-r--r--fs/nls/nls_ucs2_data.h15
-rw-r--r--fs/nls/nls_ucs2_utils.c (renamed from fs/smb/server/uniupr.h)156
-rw-r--r--fs/nls/nls_ucs2_utils.h285
-rw-r--r--fs/smb/client/Kconfig1
-rw-r--r--fs/smb/client/Makefile5
-rw-r--r--fs/smb/client/cached_dir.c2
-rw-r--r--fs/smb/client/cifs_debug.c2
-rw-r--r--fs/smb/client/cifs_unicode.c1
-rw-r--r--fs/smb/client/cifs_unicode.h330
-rw-r--r--fs/smb/client/cifs_uniupr.h239
-rw-r--r--fs/smb/client/cifsfs.c2
-rw-r--r--fs/smb/client/cifsfs.h11
-rw-r--r--fs/smb/client/cifsglob.h72
-rw-r--r--fs/smb/client/cifsproto.h9
-rw-r--r--fs/smb/client/connect.c21
-rw-r--r--fs/smb/client/dfs.c271
-rw-r--r--fs/smb/client/dfs.h141
-rw-r--r--fs/smb/client/dfs_cache.c10
-rw-r--r--fs/smb/client/dfs_cache.h12
-rw-r--r--fs/smb/client/dir.c4
-rw-r--r--fs/smb/client/inode.c498
-rw-r--r--fs/smb/client/misc.c2
-rw-r--r--fs/smb/client/namespace.c (renamed from fs/smb/client/cifs_dfs_ref.c)113
-rw-r--r--fs/smb/client/readdir.c23
-rw-r--r--fs/smb/client/sess.c72
-rw-r--r--fs/smb/client/smb1ops.c26
-rw-r--r--fs/smb/client/smb2inode.c203
-rw-r--r--fs/smb/client/smb2misc.c6
-rw-r--r--fs/smb/client/smb2ops.c298
-rw-r--r--fs/smb/client/smb2pdu.c19
-rw-r--r--fs/smb/client/smb2proto.h17
-rw-r--r--fs/smb/client/smb2transport.c4
-rw-r--r--fs/smb/client/transport.c29
-rw-r--r--fs/smb/common/smb2pdu.h22
-rw-r--r--fs/smb/server/Kconfig1
-rw-r--r--fs/smb/server/unicode.c1
-rw-r--r--fs/smb/server/unicode.h325
43 files changed, 1377 insertions, 2021 deletions
diff --git a/fs/jfs/Kconfig b/fs/jfs/Kconfig
index 17488440eef1..3728cf4d944d 100644
--- a/fs/jfs/Kconfig
+++ b/fs/jfs/Kconfig
@@ -3,6 +3,7 @@ config JFS_FS
tristate "JFS filesystem support"
select BUFFER_HEAD
select NLS
+ select NLS_UCS2_UTILS
select CRC32
select LEGACY_DIRECT_IO
help
diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile
index 7156d2c218c7..b769bbf8bdc2 100644
--- a/fs/jfs/Makefile
+++ b/fs/jfs/Makefile
@@ -9,7 +9,7 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
jfs_unicode.o jfs_dtree.o jfs_inode.o jfs_discard.o \
jfs_extent.o symlink.o jfs_metapage.o \
- jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \
+ jfs_logmgr.o jfs_txnmgr.o \
resize.o xattr.o ioctl.o
jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o
diff --git a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h
index 9db62d047daa..b6a78d4aef1b 100644
--- a/fs/jfs/jfs_unicode.h
+++ b/fs/jfs/jfs_unicode.h
@@ -8,16 +8,9 @@
#include <linux/slab.h>
#include <asm/byteorder.h>
+#include "../nls/nls_ucs2_data.h"
#include "jfs_types.h"
-typedef struct {
- wchar_t start;
- wchar_t end;
- signed char *table;
-} UNICASERANGE;
-
-extern signed char UniUpperTable[512];
-extern UNICASERANGE UniUpperRange[];
extern int get_UCSname(struct component_name *, struct dentry *);
extern int jfs_strfromUCS_le(char *, const __le16 *, int, struct nls_table *);
@@ -107,12 +100,12 @@ static inline wchar_t *UniStrncpy_from_le(wchar_t * ucs1, const __le16 * ucs2,
*/
static inline wchar_t UniToupper(wchar_t uc)
{
- UNICASERANGE *rp;
+ const struct UniCaseRange *rp;
- if (uc < sizeof(UniUpperTable)) { /* Latin characters */
- return uc + UniUpperTable[uc]; /* Use base tables */
+ if (uc < sizeof(NlsUniUpperTable)) { /* Latin characters */
+ return uc + NlsUniUpperTable[uc]; /* Use base tables */
} else {
- rp = UniUpperRange; /* Use range tables */
+ rp = NlsUniUpperRange; /* Use range tables */
while (rp->start) {
if (uc < rp->start) /* Before start of range */
return uc; /* Uppercase = input */
diff --git a/fs/jfs/jfs_uniupr.c b/fs/jfs/jfs_uniupr.c
deleted file mode 100644
index d0b18c7befb8..000000000000
--- a/fs/jfs/jfs_uniupr.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (C) International Business Machines Corp., 2000-2002
- */
-
-#include <linux/fs.h>
-#include "jfs_unicode.h"
-
-/*
- * Latin upper case
- */
-signed char UniUpperTable[512] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
- 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */
- -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, 0, 0, 0, 0, 0, /* 070-07f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
- -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */
- -32,-32,-32,-32,-32,-32,-32, 0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
- 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
- -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
- 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
- 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
- 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
- -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
- 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
- -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,-79, 0, -1, /* 1d0-1df */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
- 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
-};
-
-/* Upper case range - Greek */
-static signed char UniCaseRangeU03a0[47] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-38,-37,-37,-37, /* 3a0-3af */
- 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */
- -32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63,
-};
-
-/* Upper case range - Cyrillic */
-static signed char UniCaseRangeU0430[48] = {
- -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */
- -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */
- 0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80, 0,-80,-80, /* 450-45f */
-};
-
-/* Upper case range - Extended cyrillic */
-static signed char UniCaseRangeU0490[61] = {
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
- 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
-};
-
-/* Upper case range - Extended latin and greek */
-static signed char UniCaseRangeU1e00[509] = {
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
- 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0,-59, 0, -1, 0, -1, /* 1e90-1e9f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
- 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
- 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
- 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
- 74, 74, 86, 86, 86, 86,100,100, 0, 0,112,112,126,126, 0, 0, /* 1f70-1f7f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
- 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
- 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
- 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
- 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
- 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-/* Upper case range - Wide latin */
-static signed char UniCaseRangeUff40[27] = {
- 0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */
- -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,
-};
-
-/*
- * Upper Case Range
- */
-UNICASERANGE UniUpperRange[] = {
- { 0x03a0, 0x03ce, UniCaseRangeU03a0 },
- { 0x0430, 0x045f, UniCaseRangeU0430 },
- { 0x0490, 0x04cc, UniCaseRangeU0490 },
- { 0x1e00, 0x1ffc, UniCaseRangeU1e00 },
- { 0xff40, 0xff5a, UniCaseRangeUff40 },
- { 0 }
-};
diff --git a/fs/nls/Kconfig b/fs/nls/Kconfig
index c7857e36adbb..a0d0e2f7ec83 100644
--- a/fs/nls/Kconfig
+++ b/fs/nls/Kconfig
@@ -617,4 +617,12 @@ config NLS_UTF8
input/output character sets. Say Y here for the UTF-8 encoding of
the Unicode/ISO9646 universal character set.
+config NLS_UCS2_UTILS
+ tristate "NLS UCS-2 UTILS"
+ help
+ Set of older UCS-2 conversion utilities and tables used by some
+ filesystems including SMB/CIFS. This includes upper case conversion
+ tables. This will automatically be selected when the filesystem
+ that uses it is selected.
+
endif # NLS
diff --git a/fs/nls/Makefile b/fs/nls/Makefile
index ac54db297128..5062c699d041 100644
--- a/fs/nls/Makefile
+++ b/fs/nls/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_NLS_MAC_INUIT) += mac-inuit.o
obj-$(CONFIG_NLS_MAC_ROMANIAN) += mac-romanian.o
obj-$(CONFIG_NLS_MAC_ROMAN) += mac-roman.o
obj-$(CONFIG_NLS_MAC_TURKISH) += mac-turkish.o
+obj-$(CONFIG_NLS_UCS2_UTILS) += nls_ucs2_utils.o
diff --git a/fs/nls/nls_ucs2_data.h b/fs/nls/nls_ucs2_data.h
new file mode 100644
index 000000000000..1f454dc0f4e0
--- /dev/null
+++ b/fs/nls/nls_ucs2_data.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _NLS_UCS2_DATA_H
+#define _NLS_UCS2_DATA_H
+
+struct UniCaseRange {
+ wchar_t start;
+ wchar_t end;
+ signed char *table;
+};
+
+extern signed char NlsUniUpperTable[512];
+extern const struct UniCaseRange NlsUniUpperRange[];
+
+#endif /* _NLS_UCS2_DATA_H */
diff --git a/fs/smb/server/uniupr.h b/fs/nls/nls_ucs2_utils.c
index 26583b776897..a69781c54dd8 100644
--- a/fs/smb/server/uniupr.h
+++ b/fs/nls/nls_ucs2_utils.c
@@ -1,19 +1,27 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Some of the source code in this file came from fs/cifs/uniupr.h
* Copyright (c) International Business Machines Corp., 2000,2002
*
- * uniupr.h - Unicode compressed case ranges
+ * Some of the source code in this file came from fs/cifs/cifs_unicode.c
+ *
+ * Copyright (c) International Business Machines Corp., 2000,2009
+ * Modified by Steve French (sfrench@us.ibm.com)
+ * Modified by Namjae Jeon (linkinjeon@kernel.org)
*
*/
-#ifndef __KSMBD_UNIUPR_H
-#define __KSMBD_UNIUPR_H
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include "nls_ucs2_utils.h"
+
+MODULE_LICENSE("GPL");
-#ifndef UNIUPR_NOUPPER
/*
* Latin upper case
*/
-signed char SmbUniUpperTable[512] = {
+signed char NlsUniUpperTable[512] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
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] = {
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
};
+EXPORT_SYMBOL_GPL(NlsUniUpperTable);
/* Upper case range - Greek */
static signed char UniCaseRangeU03a0[47] = {
@@ -126,7 +135,7 @@ static signed char UniCaseRangeUff40[27] = {
/*
* Upper Case Range
*/
-const struct UniCaseRange SmbUniUpperRange[] = {
+const struct UniCaseRange NlsUniUpperRange[] = {
{0x03a0, 0x03ce, UniCaseRangeU03a0},
{0x0430, 0x045f, UniCaseRangeU0430},
{0x0490, 0x04cc, UniCaseRangeU0490},
@@ -134,135 +143,4 @@ const struct UniCaseRange SmbUniUpperRange[] = {
{0xff40, 0xff5a, UniCaseRangeUff40},
{0}
};
-#endif
-
-#ifndef UNIUPR_NOLOWER
-/*
- * Latin lower case
- */
-signed char CifsUniLowerTable[512] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
- 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, /* 040-04f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0,
- 0, 0, 0, /* 050-05f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, /* 0c0-0cf */
- 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32,
- 32, 32, 32, 0, /* 0d0-0df */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
- 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
- 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
- 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0,
- 0, /* 170-17f */
- 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79,
- 0, /* 180-18f */
- 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
- 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
- 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
- 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
- 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
- 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
-};
-
-/* Lower case range - Greek */
-static signed char UniCaseRangeL0380[44] = {
- 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
- 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, /* 390-39f */
- 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-};
-
-/* Lower case range - Cyrillic */
-static signed char UniCaseRangeL0400[48] = {
- 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 0, 80, 80, /* 400-40f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, /* 410-41f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, /* 420-42f */
-};
-
-/* Lower case range - Extended cyrillic */
-static signed char UniCaseRangeL0490[60] = {
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
- 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
-};
-
-/* Lower case range - Extended latin and greek */
-static signed char UniCaseRangeL1e00[504] = {
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
- 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
- 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0,
- 0, 0, /* 1fc0-1fcf */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0,
- 0, 0, /* 1fe0-1fef */
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-/* Lower case range - Wide latin */
-static signed char UniCaseRangeLff20[27] = {
- 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, /* ff20-ff2f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-};
-
-/*
- * Lower Case Range
- */
-const struct UniCaseRange CifsUniLowerRange[] = {
- {0x0380, 0x03ab, UniCaseRangeL0380},
- {0x0400, 0x042f, UniCaseRangeL0400},
- {0x0490, 0x04cb, UniCaseRangeL0490},
- {0x1e00, 0x1ff7, UniCaseRangeL1e00},
- {0xff20, 0xff3a, UniCaseRangeLff20},
- {0}
-};
-#endif
-
-#endif /* __KSMBD_UNIUPR_H */
+EXPORT_SYMBOL_GPL(NlsUniUpperRange);
diff --git a/fs/nls/nls_ucs2_utils.h b/fs/nls/nls_ucs2_utils.h
new file mode 100644
index 000000000000..ef18d30db1d0
--- /dev/null
+++ b/fs/nls/nls_ucs2_utils.h
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Some of the source code in this file came from fs/cifs/cifs_unicode.c
+ * and then via server/unicode.c
+ * cifs_unicode: Unicode kernel case support
+ *
+ * Function:
+ * Convert a unicode character to upper or lower case using
+ * compressed tables.
+ *
+ * Copyright (c) International Business Machines Corp., 2000,2009
+ *
+ *
+ * Notes:
+ * These APIs are based on the C library functions. The semantics
+ * should match the C functions but with expanded size operands.
+ *
+ * The upper/lower functions are based on a table created by mkupr.
+ * This is a compressed table of upper and lower case conversion.
+ *
+ */
+#ifndef _NLS_UCS2_UTILS_H
+#define _NLS_UCS2_UTILS_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+#include <linux/nls.h>
+#include <linux/unicode.h>
+#include "nls_ucs2_data.h"
+
+/*
+ * Windows maps these to the user defined 16 bit Unicode range since they are
+ * reserved symbols (along with \ and /), otherwise illegal to store
+ * in filenames in NTFS
+ */
+#define UNI_ASTERISK ((__u16)('*' + 0xF000))
+#define UNI_QUESTION ((__u16)('?' + 0xF000))
+#define UNI_COLON ((__u16)(':' + 0xF000))
+#define UNI_GRTRTHAN ((__u16)('>' + 0xF000))
+#define UNI_LESSTHAN ((__u16)('<' + 0xF000))
+#define UNI_PIPE ((__u16)('|' + 0xF000))
+#define UNI_SLASH ((__u16)('\\' + 0xF000))
+
+/*
+ * UniStrcat: Concatenate the second string to the first
+ *
+ * Returns:
+ * Address of the first string
+ */
+static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
+{
+ wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
+
+ while (*ucs1++)
+ /*NULL*/; /* To end of first string */
+ ucs1--; /* Return to the null */
+ while ((*ucs1++ = *ucs2++))
+ /*NULL*/; /* copy string 2 over */
+ return anchor;
+}
+
+/*
+ * UniStrchr: Find a character in a string
+ *
+ * Returns:
+ * Address of first occurrence of character in string
+ * or NULL if the character is not in the string
+ */
+static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
+{
+ while ((*ucs != uc) && *ucs)
+ ucs++;
+
+ if (*ucs == uc)
+ return (wchar_t *)ucs;
+ return NULL;
+}
+
+/*
+ * UniStrcmp: Compare two strings
+ *
+ * Returns:
+ * < 0: First string is less than second
+ * = 0: Strings are equal
+ * > 0: First string is greater than second
+ */
+static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
+{
+ while ((*ucs1 == *ucs2) && *ucs1) {
+ ucs1++;
+ ucs2++;
+ }
+ return (int)*ucs1 - (int)*ucs2;
+}
+
+/*
+ * UniStrcpy: Copy a string
+ */
+static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
+{
+ wchar_t *anchor = ucs1; /* save the start of result string */
+
+ while ((*ucs1++ = *ucs2++))
+ /*NULL*/;
+ return anchor;
+}
+
+/*
+ * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
+ */
+static inline size_t UniStrlen(const wchar_t *ucs1)
+{
+ int i = 0;
+
+ while (*ucs1++)
+ i++;
+ return i;
+}
+
+/*
+ * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
+ * string (length limited)
+ */
+static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
+{
+ int i = 0;
+
+ while (*ucs1++) {
+ i++;
+ if (i >= maxlen)
+ break;
+ }
+ return i;
+}
+
+/*
+ * UniStrncat: Concatenate length limited string
+ */
+static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+ wchar_t *anchor = ucs1; /* save pointer to string 1 */
+
+ while (*ucs1++)
+ /*NULL*/;
+ ucs1--; /* point to null terminator of s1 */
+ while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
+ ucs1++;
+ ucs2++;
+ }
+ *ucs1 = 0; /* Null terminate the result */
+ return anchor;
+}
+
+/*
+ * UniStrncmp: Compare length limited string
+ */
+static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+ if (!n)
+ return 0; /* Null strings are equal */
+ while ((*ucs1 == *ucs2) && *ucs1 && --n) {
+ ucs1++;
+ ucs2++;
+ }
+ return (int)*ucs1 - (int)*ucs2;
+}
+
+/*
+ * UniStrncmp_le: Compare length limited string - native to little-endian
+ */
+static inline int
+UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+ if (!n)
+ return 0; /* Null strings are equal */
+ while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
+ ucs1++;
+ ucs2++;
+ }
+ return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
+}
+
+/*
+ * UniStrncpy: Copy length limited string with pad
+ */
+static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+ wchar_t *anchor = ucs1;
+
+ while (n-- && *ucs2) /* Copy the strings */
+ *ucs1++ = *ucs2++;
+
+ n++;
+ while (n--) /* Pad with nulls */
+ *ucs1++ = 0;
+ return anchor;
+}
+
+/*
+ * UniStrncpy_le: Copy length limited string with pad to little-endian
+ */
+static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+ wchar_t *anchor = ucs1;
+
+ while (n-- && *ucs2) /* Copy the strings */
+ *ucs1++ = __le16_to_cpu(*ucs2++);
+
+ n++;
+ while (n--) /* Pad with nulls */
+ *ucs1++ = 0;
+ return anchor;
+}
+
+/*
+ * UniStrstr: Find a string in a string
+ *
+ * Returns:
+ * Address of first match found
+ * NULL if no matching string is found
+ */
+static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
+{
+ const wchar_t *anchor1 = ucs1;
+ const wchar_t *anchor2 = ucs2;
+
+ while (*ucs1) {
+ if (*ucs1 == *ucs2) {
+ /* Partial match found */
+ ucs1++;
+ ucs2++;
+ } else {
+ if (!*ucs2) /* Match found */
+ return (wchar_t *)anchor1;
+ ucs1 = ++anchor1; /* No match */
+ ucs2 = anchor2;
+ }
+ }
+
+ if (!*ucs2) /* Both end together */
+ return (wchar_t *)anchor1; /* Match found */
+ return NULL; /* No match */
+}
+
+#ifndef UNIUPR_NOUPPER
+/*
+ * UniToupper: Convert a unicode character to upper case
+ */
+static inline wchar_t UniToupper(register wchar_t uc)
+{
+ register const struct UniCaseRange *rp;
+
+ if (uc < sizeof(NlsUniUpperTable)) {
+ /* Latin characters */
+ return uc + NlsUniUpperTable[uc]; /* Use base tables */
+ }
+
+ rp = NlsUniUpperRange; /* Use range tables */
+ while (rp->start) {
+ if (uc < rp->start) /* Before start of range */
+ return uc; /* Uppercase = input */
+ if (uc <= rp->end) /* In range */
+ return uc + rp->table[uc - rp->start];
+ rp++; /* Try next range */
+ }
+ return uc; /* Past last range */
+}
+
+/*
+ * UniStrupr: Upper case a unicode string
+ */
+static inline __le16 *UniStrupr(register __le16 *upin)
+{
+ register __le16 *up;
+
+ up = upin;
+ while (*up) { /* For all characters */
+ *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
+ up++;
+ }
+ return upin; /* Return input pointer */
+}
+#endif /* UNIUPR_NOUPPER */
+
+#endif /* _NLS_UCS2_UTILS_H */
diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig
index 4c0d53bf931a..2927bd174a88 100644
--- a/fs/smb/client/Kconfig
+++ b/fs/smb/client/Kconfig
@@ -3,6 +3,7 @@ config CIFS
tristate "SMB3 and CIFS support (advanced network filesystem)"
depends on INET
select NLS
+ select NLS_UCS2_UTILS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_SHA256
diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile
index 304a7f6cc13a..0b07eb94c93b 100644
--- a/fs/smb/client/Makefile
+++ b/fs/smb/client/Makefile
@@ -11,7 +11,8 @@ cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \
readdir.o ioctl.o sess.o export.o unc.o winucase.o \
smb2ops.o smb2maperror.o smb2transport.o \
smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
- dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
+ dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o \
+ namespace.o
$(obj)/asn1.o: $(obj)/cifs_spnego_negtokeninit.asn1.h
@@ -21,7 +22,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
-cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o
+cifs-$(CONFIG_CIFS_DFS_UPCALL) += dfs_cache.o dfs.o
cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index fe483f163dbc..2d5e9a9d5b8b 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -218,7 +218,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
.tcon = tcon,
.path = path,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
- .desired_access = FILE_READ_ATTRIBUTES,
+ .desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.fid = pfid,
};
diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index aec6e9137474..76922fcc4bc6 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -331,7 +331,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
/* channel info will be printed as a part of sessions below */
- if (CIFS_SERVER_IS_CHAN(server))
+ if (SERVER_IS_CHAN(server))
continue;
c++;
diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c
index e7582dd79179..79d99a913944 100644
--- a/fs/smb/client/cifs_unicode.c
+++ b/fs/smb/client/cifs_unicode.c
@@ -8,7 +8,6 @@
#include <linux/slab.h>
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
-#include "cifs_uniupr.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifs_debug.h"
diff --git a/fs/smb/client/cifs_unicode.h b/fs/smb/client/cifs_unicode.h
index 80b3d845419f..e137a0dfbbe9 100644
--- a/fs/smb/client/cifs_unicode.h
+++ b/fs/smb/client/cifs_unicode.h
@@ -21,21 +21,7 @@
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/nls.h>
-
-#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
-
-/*
- * Windows maps these to the user defined 16 bit Unicode range since they are
- * reserved symbols (along with \ and /), otherwise illegal to store
- * in filenames in NTFS
- */
-#define UNI_ASTERISK (__u16) ('*' + 0xF000)
-#define UNI_QUESTION (__u16) ('?' + 0xF000)
-#define UNI_COLON (__u16) (':' + 0xF000)
-#define UNI_GRTRTHAN (__u16) ('>' + 0xF000)
-#define UNI_LESSTHAN (__u16) ('<' + 0xF000)
-#define UNI_PIPE (__u16) ('|' + 0xF000)
-#define UNI_SLASH (__u16) ('\\' + 0xF000)
+#include "../../nls/nls_ucs2_utils.h"
/*
* Macs use an older "SFM" mapping of the symbols above. Fortunately it does
@@ -68,27 +54,6 @@
#define SFM_MAP_UNI_RSVD 1
#define SFU_MAP_UNI_RSVD 2
-/* Just define what we want from uniupr.h. We don't want to define the tables
- * in each source file.
- */
-#ifndef UNICASERANGE_DEFINED
-struct UniCaseRange {
- wchar_t start;
- wchar_t end;
- signed char *table;
-};
-#endif /* UNICASERANGE_DEFINED */
-
-#ifndef UNIUPR_NOUPPER
-extern signed char CifsUniUpperTable[512];
-extern const struct UniCaseRange CifsUniUpperRange[];
-#endif /* UNIUPR_NOUPPER */
-
-#ifndef UNIUPR_NOLOWER
-extern signed char CifsUniLowerTable[512];
-extern const struct UniCaseRange CifsUniLowerRange[];
-#endif /* UNIUPR_NOLOWER */
-
#ifdef __KERNEL__
int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
const struct nls_table *cp, int map_type);
@@ -108,297 +73,4 @@ extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
wchar_t cifs_toupper(wchar_t in);
-/*
- * UniStrcat: Concatenate the second string to the first
- *
- * Returns:
- * Address of the first string
- */
-static inline __le16 *
-UniStrcat(__le16 *ucs1, const __le16 *ucs2)
-{
- __le16 *anchor = ucs1; /* save a pointer to start of ucs1 */
-
- while (*ucs1++) ; /* To end of first string */
- ucs1--; /* Return to the null */
- while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */
- return anchor;
-}
-
-/*
- * UniStrchr: Find a character in a string
- *
- * Returns:
- * Address of first occurrence of character in string
- * or NULL if the character is not in the string
- */
-static inline wchar_t *
-UniStrchr(const wchar_t *ucs, wchar_t uc)
-{
- while ((*ucs != uc) && *ucs)
- ucs++;
-
- if (*ucs == uc)
- return (wchar_t *) ucs;
- return NULL;
-}
-
-/*
- * UniStrcmp: Compare two strings
- *
- * Returns:
- * < 0: First string is less than second
- * = 0: Strings are equal
- * > 0: First string is greater than second
- */
-static inline int
-UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
-{
- while ((*ucs1 == *ucs2) && *ucs1) {
- ucs1++;
- ucs2++;
- }
- return (int) *ucs1 - (int) *ucs2;
-}
-
-/*
- * UniStrcpy: Copy a string
- */
-static inline wchar_t *
-UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
-{
- wchar_t *anchor = ucs1; /* save the start of result string */
-
- while ((*ucs1++ = *ucs2++)) ;
- return anchor;
-}
-
-/*
- * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
- */
-static inline size_t
-UniStrlen(const wchar_t *ucs1)
-{
- int i = 0;
-
- while (*ucs1++)
- i++;
- return i;
-}
-
-/*
- * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
- * string (length limited)
- */
-static inline size_t
-UniStrnlen(const wchar_t *ucs1, int maxlen)
-{
- int i = 0;
-
- while (*ucs1++) {
- i++;
- if (i >= maxlen)
- break;
- }
- return i;
-}
-
-/*
- * UniStrncat: Concatenate length limited string
- */
-static inline wchar_t *
-UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- wchar_t *anchor = ucs1; /* save pointer to string 1 */
-
- while (*ucs1++) ;
- ucs1--; /* point to null terminator of s1 */
- while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
- ucs1++;
- ucs2++;
- }
- *ucs1 = 0; /* Null terminate the result */
- return (anchor);
-}
-
-/*
- * UniStrncmp: Compare length limited string
- */
-static inline int
-UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- if (!n)
- return 0; /* Null strings are equal */
- while ((*ucs1 == *ucs2) && *ucs1 && --n) {
- ucs1++;
- ucs2++;
- }
- return (int) *ucs1 - (int) *ucs2;
-}
-
-/*
- * UniStrncmp_le: Compare length limited string - native to little-endian
- */
-static inline int
-UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- if (!n)
- return 0; /* Null strings are equal */
- while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
- ucs1++;
- ucs2++;
- }
- return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
-}
-
-/*
- * UniStrncpy: Copy length limited string with pad
- */
-static inline wchar_t *
-UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- wchar_t *anchor = ucs1;
-
- while (n-- && *ucs2) /* Copy the strings */
- *ucs1++ = *ucs2++;
-
- n++;
- while (n--) /* Pad with nulls */
- *ucs1++ = 0;
- return anchor;
-}
-
-/*
- * UniStrncpy_le: Copy length limited string with pad to little-endian
- */
-static inline wchar_t *
-UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- wchar_t *anchor = ucs1;
-
- while (n-- && *ucs2) /* Copy the strings */
- *ucs1++ = __le16_to_cpu(*ucs2++);
-
- n++;
- while (n--) /* Pad with nulls */
- *ucs1++ = 0;
- return anchor;
-}
-
-/*
- * UniStrstr: Find a string in a string
- *
- * Returns:
- * Address of first match found
- * NULL if no matching string is found
- */
-static inline wchar_t *
-UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
-{
- const wchar_t *anchor1 = ucs1;
- const wchar_t *anchor2 = ucs2;
-
- while (*ucs1) {
- if (*ucs1 == *ucs2) {
- /* Partial match found */
- ucs1++;
- ucs2++;
- } else {
- if (!*ucs2) /* Match found */
- return (wchar_t *) anchor1;
- ucs1 = ++anchor1; /* No match */
- ucs2 = anchor2;
- }
- }
-
- if (!*ucs2) /* Both end together */
- return (wchar_t *) anchor1; /* Match found */
- return NULL; /* No match */
-}
-
-#ifndef UNIUPR_NOUPPER
-/*
- * UniToupper: Convert a unicode character to upper case
- */
-static inline wchar_t
-UniToupper(register wchar_t uc)
-{
- register const struct UniCaseRange *rp;
-
- if (uc < sizeof(CifsUniUpperTable)) {
- /* Latin characters */
- return uc + CifsUniUpperTable[uc]; /* Use base tables */
- } else {
- rp = CifsUniUpperRange; /* Use range tables */
- while (rp->start) {
- if (uc < rp->start) /* Before start of range */
- return uc; /* Uppercase = input */
- if (uc <= rp->end) /* In range */
- return uc + rp->table[uc - rp->start];
- rp++; /* Try next range */
- }
- }
- return uc; /* Past last range */
-}
-
-/*
- * UniStrupr: Upper case a unicode string
- */
-static inline __le16 *
-UniStrupr(register __le16 *upin)
-{
- register __le16 *up;
-
- up = upin;
- while (*up) { /* For all characters */
- *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
- up++;
- }
- return upin; /* Return input pointer */
-}
-#endif /* UNIUPR_NOUPPER */
-
-#ifndef UNIUPR_NOLOWER
-/*
- * UniTolower: Convert a unicode character to lower case
- */
-static inline wchar_t
-UniTolower(register wchar_t uc)
-{
- register const struct UniCaseRange *rp;
-
- if (uc < sizeof(CifsUniLowerTable)) {
- /* Latin characters */
- return uc + CifsUniLowerTable[uc]; /* Use base tables */
- } else {
- rp = CifsUniLowerRange; /* Use range tables */
- while (rp->start) {
- if (uc < rp->start) /* Before start of range */
- return uc; /* Uppercase = input */
- if (uc <= rp->end) /* In range */
- return uc + rp->table[uc - rp->start];
- rp++; /* Try next range */
- }
- }
- return uc; /* Past last range */
-}
-
-/*
- * UniStrlwr: Lower case a unicode string
- */
-static inline wchar_t *
-UniStrlwr(register wchar_t *upin)
-{
- register wchar_t *up;
-
- up = upin;
- while (*up) { /* For all characters */
- *up = UniTolower(*up);
- up++;
- }
- return upin; /* Return input pointer */
-}
-
-#endif
-
#endif /* _CIFS_UNICODE_H */
diff --git a/fs/smb/client/cifs_uniupr.h b/fs/smb/client/cifs_uniupr.h
deleted file mode 100644
index 7b272fcdf0d3..000000000000
--- a/fs/smb/client/cifs_uniupr.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (c) International Business Machines Corp., 2000,2002
- *
- * uniupr.h - Unicode compressed case ranges
-*/
-
-#ifndef UNIUPR_NOUPPER
-/*
- * Latin upper case
- */
-signed char CifsUniUpperTable[512] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
- 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */
- -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
- -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */
- -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
- 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
- -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
- 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
- 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
- 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
- -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
- 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
- -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
- 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
-};
-
-/* Upper case range - Greek */
-static signed char UniCaseRangeU03a0[47] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */
- 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */
- -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64,
- -63, -63,
-};
-
-/* Upper case range - Cyrillic */
-static signed char UniCaseRangeU0430[48] = {
- -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */
- -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */
- 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */
-};
-
-/* Upper case range - Extended cyrillic */
-static signed char UniCaseRangeU0490[61] = {
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
- 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
-};
-
-/* Upper case range - Extended latin and greek */
-static signed char UniCaseRangeU1e00[509] = {
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
- 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
- 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
- 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
- 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
- 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
- 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
- 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
- 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
- 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
- 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
- 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
- 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-/* Upper case range - Wide latin */
-static signed char UniCaseRangeUff40[27] = {
- 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */
- -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
-};
-
-/*
- * Upper Case Range
- */
-const struct UniCaseRange CifsUniUpperRange[] = {
- {0x03a0, 0x03ce, UniCaseRangeU03a0},
- {0x0430, 0x045f, UniCaseRangeU0430},
- {0x0490, 0x04cc, UniCaseRangeU0490},
- {0x1e00, 0x1ffc, UniCaseRangeU1e00},
- {0xff40, 0xff5a, UniCaseRangeUff40},
- {0}
-};
-#endif
-
-#ifndef UNIUPR_NOLOWER
-/*
- * Latin lower case
- */
-signed char CifsUniLowerTable[512] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
- 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */
- 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
- 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
- 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
- 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */
- 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */
- 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
- 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
- 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
- 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
- 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
- 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
-};
-
-/* Lower case range - Greek */
-static signed char UniCaseRangeL0380[44] = {
- 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
- 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */
- 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-};
-
-/* Lower case range - Cyrillic */
-static signed char UniCaseRangeL0400[48] = {
- 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */
-};
-
-/* Lower case range - Extended cyrillic */
-static signed char UniCaseRangeL0490[60] = {
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
- 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
-};
-
-/* Lower case range - Extended latin and greek */
-static signed char UniCaseRangeL1e00[504] = {
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
- 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
- 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
- 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
- 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-/* Lower case range - Wide latin */
-static signed char UniCaseRangeLff20[27] = {
- 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
-};
-
-/*
- * Lower Case Range
- */
-const struct UniCaseRange CifsUniLowerRange[] = {
- {0x0380, 0x03ab, UniCaseRangeL0380},
- {0x0400, 0x042f, UniCaseRangeL0400},
- {0x0490, 0x04cb, UniCaseRangeL0490},
- {0x1e00, 0x1ff7, UniCaseRangeL1e00},
- {0xff20, 0xff3a, UniCaseRangeLff20},
- {0}
-};
-#endif
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 6fc8f43b1c9d..73c44e097a69 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1805,7 +1805,7 @@ exit_cifs(void)
cifs_dbg(NOISY, "exit_smb3\n");
unregister_filesystem(&cifs_fs_type);
unregister_filesystem(&smb3_fs_type);
- cifs_dfs_release_automount_timer();
+ cifs_release_automount_timer();
exit_cifs_idmap();
#ifdef CONFIG_CIFS_SWN_UPCALL
cifs_genl_exit();
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index 15c8cc4b6680..532c38fe07cd 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -81,7 +81,7 @@ extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
extern const struct inode_operations cifs_file_inode_ops;
extern const struct inode_operations cifs_symlink_inode_ops;
-extern const struct inode_operations cifs_dfs_referral_inode_operations;
+extern const struct inode_operations cifs_namespace_inode_operations;
/* Functions related to files and directories */
@@ -118,14 +118,7 @@ extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned
extern const struct dentry_operations cifs_dentry_ops;
extern const struct dentry_operations cifs_ci_dentry_ops;
-#ifdef CONFIG_CIFS_DFS_UPCALL
-extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
-#else
-static inline struct vfsmount *cifs_dfs_d_automount(struct path *path)
-{
- return ERR_PTR(-EREMOTE);
-}
-#endif
+extern struct vfsmount *cifs_d_automount(struct path *path);
/* Functions related to symlinks */
extern const char *cifs_get_link(struct dentry *, struct inode *,
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 657dee4b2c8c..259e231f8b4f 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -186,6 +186,12 @@ struct cifs_cred {
};
struct cifs_open_info_data {
+ bool adjust_tz;
+ union {
+ bool reparse_point;
+ bool symlink;
+ };
+ __u32 reparse_tag;
char *symlink_target;
union {
struct smb2_file_all_info fi;
@@ -193,6 +199,10 @@ struct cifs_open_info_data {
};
};
+#define cifs_open_data_reparse(d) \
+ ((d)->reparse_point || \
+ (le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
+
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
{
kfree(data->symlink_target);
@@ -318,16 +328,21 @@ struct smb_version_operations {
int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *);
/* query path data from the server */
- int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
+ int (*query_path_info)(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ struct cifs_open_info_data *data);
/* query file data from the server */
int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
- /* query reparse tag from srv to determine which type of special file */
- int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *path,
- __u32 *reparse_tag);
+ /* query reparse point to determine which type of special file */
+ int (*query_reparse_point)(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ u32 *tag, struct kvec *rsp,
+ int *rsp_buftype);
/* get server index number */
int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid,
@@ -376,9 +391,12 @@ struct smb_version_operations {
const char *, const char *,
struct cifs_sb_info *);
/* query symlink target */
- int (*query_symlink)(const unsigned int, struct cifs_tcon *,
- struct cifs_sb_info *, const char *,
- char **, bool);
+ int (*query_symlink)(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ char **target_path,
+ struct kvec *rsp_iov);
/* open a file for non-posix mounts */
int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
void *buf);
@@ -727,8 +745,9 @@ struct TCP_Server_Info {
* primary_server holds the ref-counted
* pointer to primary channel connection for the session.
*/
-#define CIFS_SERVER_IS_CHAN(server) (!!(server)->primary_server)
+#define SERVER_IS_CHAN(server) (!!(server)->primary_server)
struct TCP_Server_Info *primary_server;
+ __u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */
#ifdef CONFIG_CIFS_SWN_UPCALL
bool use_swn_dstaddr;
@@ -1076,7 +1095,7 @@ cap_unix(struct cifs_ses *ses)
* inode with new info
*/
-#define CIFS_FATTR_DFS_REFERRAL 0x1
+#define CIFS_FATTR_JUNCTION 0x1
#define CIFS_FATTR_DELETE_PENDING 0x2
#define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8
@@ -1721,11 +1740,23 @@ struct cifs_mount_ctx {
struct list_head dfs_ses_list;
};
+static inline void __free_dfs_info_param(struct dfs_info3_param *param)
+{
+ kfree(param->path_name);
+ kfree(param->node_name);
+}
+
static inline void free_dfs_info_param(struct dfs_info3_param *param)
{
+ if (param)
+ __free_dfs_info_param(param);
+}
+
+static inline void zfree_dfs_info_param(struct dfs_info3_param *param)
+{
if (param) {
- kfree(param->path_name);
- kfree(param->node_name);
+ __free_dfs_info_param(param);
+ memset(param, 0, sizeof(*param));
}
}
@@ -2184,4 +2215,17 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,
}
}
+struct smb2_compound_vars {
+ struct cifs_open_parms oparms;
+ struct kvec rsp_iov[3];
+ struct smb_rqst rqst[3];
+ struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
+ struct kvec qi_iov;
+ struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
+ struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
+ struct kvec close_iov;
+ struct smb2_file_rename_info rename_info;
+ struct smb2_file_link_info link_info;
+};
+
#endif /* _CIFS_GLOB_H */
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 1d71d658e167..7d8035846680 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -207,6 +207,9 @@ extern struct inode *cifs_iget(struct super_block *sb,
int cifs_get_inode_info(struct inode **inode, const char *full_path,
struct cifs_open_info_data *data, struct super_block *sb, int xid,
const struct cifs_fid *fid);
+bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
+ struct cifs_fattr *fattr,
+ u32 tag);
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
struct super_block *sb, unsigned int xid);
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,
int from_reconnect);
extern void cifs_put_tcon(struct cifs_tcon *tcon);
-#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
-extern void cifs_dfs_release_automount_timer(void);
-#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
-#define cifs_dfs_release_automount_timer() do { } while (0)
-#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
+extern void cifs_release_automount_timer(void);
void cifs_proc_init(void);
void cifs_proc_clean(void);
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 238538dde4e3..3bd71f982170 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -154,7 +154,7 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
int i;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
spin_lock(&pserver->srv_lock);
if (!all_channels) {
@@ -202,7 +202,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
cifs_dbg(FYI, "%s: marking necessary sessions and tcons for reconnect\n", __func__);
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
spin_lock(&cifs_tcp_ses_lock);
@@ -453,10 +453,10 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_
static int reconnect_dfs_server(struct TCP_Server_Info *server)
{
- int rc = 0;
- struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
struct dfs_cache_tgt_iterator *target_hint = NULL;
+ DFS_CACHE_TGT_LIST(tl);
int num_targets = 0;
+ int rc = 0;
/*
* 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)
return 0;
}
-
-static void clean_demultiplex_info(struct TCP_Server_Info *server)
+static noinline_for_stack void
+clean_demultiplex_info(struct TCP_Server_Info *server)
{
int length;
@@ -1551,7 +1551,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
* Skip ses channels since they're only handled in lower layers
* (e.g. cifs_send_recv).
*/
- if (CIFS_SERVER_IS_CHAN(server) ||
+ if (SERVER_IS_CHAN(server) ||
!match_server(server, ctx, false)) {
spin_unlock(&server->srv_lock);
continue;
@@ -1587,7 +1587,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
spin_unlock(&cifs_tcp_ses_lock);
/* For secondary channels, we pick up ref-count on the primary server */
- if (CIFS_SERVER_IS_CHAN(server))
+ if (SERVER_IS_CHAN(server))
cifs_put_tcp_session(server->primary_server, from_reconnect);
cancel_delayed_work_sync(&server->echo);
@@ -1686,6 +1686,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
tcp_ses->session_estab = false;
tcp_ses->sequence_number = 0;
+ tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */
tcp_ses->reconnect_instance = 1;
tcp_ses->lstrp = jiffies;
tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
@@ -1792,7 +1793,7 @@ out_err_crypto_release:
out_err:
if (tcp_ses) {
- if (CIFS_SERVER_IS_CHAN(tcp_ses))
+ if (SERVER_IS_CHAN(tcp_ses))
cifs_put_tcp_session(tcp_ses->primary_server, false);
kfree(tcp_ses->hostname);
kfree(tcp_ses->leaf_fullpath);
@@ -3813,7 +3814,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
struct nls_table *nls_info)
{
int rc = -ENOSYS;
- struct TCP_Server_Info *pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ struct TCP_Server_Info *pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr;
struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr;
bool is_binding = false;
diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c
index ee772c3d9f00..81b84151450d 100644
--- a/fs/smb/client/dfs.c
+++ b/fs/smb/client/dfs.c
@@ -3,7 +3,6 @@
* Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de>
*/
-#include <linux/namei.h>
#include "cifsproto.h"
#include "cifs_debug.h"
#include "dns_resolve.h"
@@ -96,51 +95,134 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
return 0;
}
-static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
- const struct dfs_cache_tgt_iterator *tit)
+static inline int parse_dfs_target(struct smb3_fs_context *ctx,
+ struct dfs_ref_walk *rw,
+ struct dfs_info3_param *tgt)
+{
+ int rc;
+ const char *fpath = ref_walk_fpath(rw) + 1;
+
+ rc = ref_walk_get_tgt(rw, tgt);
+ if (!rc)
+ rc = dfs_parse_target_referral(fpath, tgt, ctx);
+ return rc;
+}
+
+static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx,
+ struct dfs_info3_param *tgt,
+ struct dfs_ref_walk *rw)
{
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
- struct dfs_info3_param ref = {};
- bool is_refsrv;
- int rc, rc2;
+ struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
+ char *ref_path, *full_path;
+ int rc;
- rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
- if (rc)
+ full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb));
+ if (IS_ERR(full_path))
+ return PTR_ERR(full_path);
+
+ if (!tgt || (tgt->server_type == DFS_TYPE_LINK &&
+ DFS_INTERLINK(tgt->flags)))
+ ref_path = dfs_get_path(cifs_sb, ctx->UNC);
+ else
+ ref_path = dfs_get_path(cifs_sb, full_path);
+ if (IS_ERR(ref_path)) {
+ rc = PTR_ERR(ref_path);
+ kfree(full_path);
return rc;
+ }
+ ref_walk_path(rw) = ref_path;
+ ref_walk_fpath(rw) = full_path;
+ return 0;
+}
- rc = dfs_parse_target_referral(full_path + 1, &ref, ctx);
- if (rc)
- goto out;
+static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
+ struct dfs_ref_walk *rw)
+{
+ struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
+ struct dfs_info3_param tgt = {};
+ bool is_refsrv;
+ int rc = -ENOENT;
- cifs_mount_put_conns(mnt_ctx);
- rc = get_session(mnt_ctx, ref_path);
- if (rc)
- goto out;
+again:
+ do {
+ if (ref_walk_empty(rw)) {
+ rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1,
+ NULL, ref_walk_tl(rw));
+ if (rc) {
+ rc = cifs_mount_get_tcon(mnt_ctx);
+ if (!rc)
+ rc = cifs_is_path_remote(mnt_ctx);
+ continue;
+ }
+ if (!ref_walk_num_tgts(rw)) {
+ rc = -ENOENT;
+ continue;
+ }
+ }
- is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
+ while (ref_walk_next_tgt(rw)) {
+ rc = parse_dfs_target(ctx, rw, &tgt);
+ if (rc)
+ continue;
- rc = -EREMOTE;
- if (ref.flags & DFSREF_STORAGE_SERVER) {
- rc = cifs_mount_get_tcon(mnt_ctx);
- if (rc)
- goto out;
+ cifs_mount_put_conns(mnt_ctx);
+ rc = get_session(mnt_ctx, ref_walk_path(rw));
+ if (rc)
+ continue;
- /* some servers may not advertise referral capability under ref.flags */
- is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
+ is_refsrv = tgt.server_type == DFS_TYPE_ROOT ||
+ DFS_INTERLINK(tgt.flags);
+ ref_walk_set_tgt_hint(rw);
- rc = cifs_is_path_remote(mnt_ctx);
- }
+ if (tgt.flags & DFSREF_STORAGE_SERVER) {
+ rc = cifs_mount_get_tcon(mnt_ctx);
+ if (!rc)
+ rc = cifs_is_path_remote(mnt_ctx);
+ if (!rc)
+ break;
+ if (rc != -EREMOTE)
+ continue;
+ }
- dfs_cache_noreq_update_tgthint(ref_path + 1, tit);
+ if (is_refsrv) {
+ rc = add_root_smb_session(mnt_ctx);
+ if (rc)
+ goto out;
+ }
- if (rc == -EREMOTE && is_refsrv) {
- rc2 = add_root_smb_session(mnt_ctx);
- if (rc2)
- rc = rc2;
- }
+ rc = ref_walk_advance(rw);
+ if (!rc) {
+ rc = set_ref_paths(mnt_ctx, &tgt, rw);
+ if (!rc) {
+ rc = -EREMOTE;
+ goto again;
+ }
+ }
+ if (rc != -ELOOP)
+ goto out;
+ }
+ } while (rc && ref_walk_descend(rw));
out:
- free_dfs_info_param(&ref);
+ free_dfs_info_param(&tgt);
+ return rc;
+}
+
+static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx)
+{
+ struct dfs_ref_walk *rw;
+ int rc;
+
+ rw = ref_walk_alloc();
+ if (IS_ERR(rw))
+ return PTR_ERR(rw);
+
+ ref_walk_init(rw);
+ rc = set_ref_paths(mnt_ctx, NULL, rw);
+ if (!rc)
+ rc = __dfs_referral_walk(mnt_ctx, rw);
+ ref_walk_free(rw);
return rc;
}
@@ -148,105 +230,48 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
{
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
- char *ref_path = NULL, *full_path = NULL;
- struct dfs_cache_tgt_iterator *tit;
struct cifs_tcon *tcon;
- char *origin_fullpath = NULL;
- char sep = CIFS_DIR_SEP(cifs_sb);
- int num_links = 0;
+ char *origin_fullpath;
int rc;
- ref_path = dfs_get_path(cifs_sb, ctx->UNC);
- if (IS_ERR(ref_path))
- return PTR_ERR(ref_path);
+ origin_fullpath = dfs_get_path(cifs_sb, ctx->source);
+ if (IS_ERR(origin_fullpath))
+ return PTR_ERR(origin_fullpath);
- full_path = smb3_fs_context_fullpath(ctx, sep);
- if (IS_ERR(full_path)) {
- rc = PTR_ERR(full_path);
- full_path = NULL;
+ rc = dfs_referral_walk(mnt_ctx);
+ if (rc)
goto out;
- }
- origin_fullpath = kstrdup(full_path, GFP_KERNEL);
- if (!origin_fullpath) {
- rc = -ENOMEM;
- goto out;
+ tcon = mnt_ctx->tcon;
+ spin_lock(&tcon->tc_lock);
+ if (!tcon->origin_fullpath) {
+ tcon->origin_fullpath = origin_fullpath;
+ origin_fullpath = NULL;
}
+ spin_unlock(&tcon->tc_lock);
- do {
- struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
-
- rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl);
- if (rc) {
- rc = cifs_mount_get_tcon(mnt_ctx);
- if (!rc)
- rc = cifs_is_path_remote(mnt_ctx);
- break;
- }
-
- tit = dfs_cache_get_tgt_iterator(&tl);
- if (!tit) {
- cifs_dbg(VFS, "%s: dfs referral (%s) with no targets\n", __func__,
- ref_path + 1);
- rc = -ENOENT;
- dfs_cache_free_tgts(&tl);
- break;
- }
-
- do {
- rc = get_dfs_conn(mnt_ctx, ref_path, full_path, tit);
- if (!rc)
- break;
- if (rc == -EREMOTE) {
- if (++num_links > MAX_NESTED_LINKS) {
- rc = -ELOOP;
- break;
- }
- kfree(ref_path);
- kfree(full_path);
- ref_path = full_path = NULL;
-
- full_path = smb3_fs_context_fullpath(ctx, sep);
- if (IS_ERR(full_path)) {
- rc = PTR_ERR(full_path);
- full_path = NULL;
- } else {
- ref_path = dfs_get_path(cifs_sb, full_path);
- if (IS_ERR(ref_path)) {
- rc = PTR_ERR(ref_path);
- ref_path = NULL;
- }
- }
- break;
- }
- } while ((tit = dfs_cache_get_next_tgt(&tl, tit)));
- dfs_cache_free_tgts(&tl);
- } while (rc == -EREMOTE);
-
- if (!rc) {
- tcon = mnt_ctx->tcon;
-
- spin_lock(&tcon->tc_lock);
- if (!tcon->origin_fullpath) {
- tcon->origin_fullpath = origin_fullpath;
- origin_fullpath = NULL;
- }
- spin_unlock(&tcon->tc_lock);
-
- if (list_empty(&tcon->dfs_ses_list)) {
- list_replace_init(&mnt_ctx->dfs_ses_list,
- &tcon->dfs_ses_list);
- queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
- dfs_cache_get_ttl() * HZ);
- } else {
- dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
- }
+ if (list_empty(&tcon->dfs_ses_list)) {
+ list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list);
+ queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
+ dfs_cache_get_ttl() * HZ);
+ } else {
+ dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
}
out:
kfree(origin_fullpath);
- kfree(ref_path);
- kfree(full_path);
+ return rc;
+}
+
+/* Resolve UNC hostname in @ctx->source and set ip addr in @ctx->dstaddr */
+static int update_fs_context_dstaddr(struct smb3_fs_context *ctx)
+{
+ struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
+ int rc;
+
+ rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
+ if (!rc)
+ cifs_set_port(addr, ctx->port);
return rc;
}
@@ -256,6 +281,10 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
bool nodfs = ctx->nodfs;
int rc;
+ rc = update_fs_context_dstaddr(ctx);
+ if (rc)
+ return rc;
+
*isdfs = false;
rc = get_session(mnt_ctx, NULL);
if (rc)
@@ -426,7 +455,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
/* Try to tree connect to all dfs targets */
for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
const char *target = dfs_cache_get_tgt_name(tit);
- struct dfs_cache_tgt_list ntl = DFS_CACHE_TGT_LIST_INIT(ntl);
+ DFS_CACHE_TGT_LIST(ntl);
kfree(share);
kfree(prefix);
@@ -520,7 +549,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
int rc;
struct TCP_Server_Info *server = tcon->ses->server;
const struct smb_version_operations *ops = server->ops;
- struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
+ DFS_CACHE_TGT_LIST(tl);
struct cifs_sb_info *cifs_sb = NULL;
struct super_block *sb = NULL;
struct dfs_info3_param ref = {0};
diff --git a/fs/smb/client/dfs.h b/fs/smb/client/dfs.h
index 98e9d2aca6a7..875ab7ae57fc 100644
--- a/fs/smb/client/dfs.h
+++ b/fs/smb/client/dfs.h
@@ -9,6 +9,110 @@
#include "cifsglob.h"
#include "fs_context.h"
#include "cifs_unicode.h"
+#include <linux/namei.h>
+
+#define DFS_INTERLINK(v) \
+ (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
+
+struct dfs_ref {
+ char *path;
+ char *full_path;
+ struct dfs_cache_tgt_list tl;
+ struct dfs_cache_tgt_iterator *tit;
+};
+
+struct dfs_ref_walk {
+ struct dfs_ref *ref;
+ struct dfs_ref refs[MAX_NESTED_LINKS];
+};
+
+#define ref_walk_start(w) ((w)->refs)
+#define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1])
+#define ref_walk_cur(w) ((w)->ref)
+#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w))
+
+#define ref_walk_tit(w) (ref_walk_cur(w)->tit)
+#define ref_walk_empty(w) (!ref_walk_tit(w))
+#define ref_walk_path(w) (ref_walk_cur(w)->path)
+#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path)
+#define ref_walk_tl(w) (&ref_walk_cur(w)->tl)
+
+static inline struct dfs_ref_walk *ref_walk_alloc(void)
+{
+ struct dfs_ref_walk *rw;
+
+ rw = kmalloc(sizeof(*rw), GFP_KERNEL);
+ if (!rw)
+ return ERR_PTR(-ENOMEM);
+ return rw;
+}
+
+static inline void ref_walk_init(struct dfs_ref_walk *rw)
+{
+ memset(rw, 0, sizeof(*rw));
+ ref_walk_cur(rw) = ref_walk_start(rw);
+}
+
+static inline void __ref_walk_free(struct dfs_ref *ref)
+{
+ kfree(ref->path);
+ kfree(ref->full_path);
+ dfs_cache_free_tgts(&ref->tl);
+ memset(ref, 0, sizeof(*ref));
+}
+
+static inline void ref_walk_free(struct dfs_ref_walk *rw)
+{
+ struct dfs_ref *ref = ref_walk_start(rw);
+
+ for (; ref <= ref_walk_end(rw); ref++)
+ __ref_walk_free(ref);
+ kfree(rw);
+}
+
+static inline int ref_walk_advance(struct dfs_ref_walk *rw)
+{
+ struct dfs_ref *ref = ref_walk_cur(rw) + 1;
+
+ if (ref > ref_walk_end(rw))
+ return -ELOOP;
+ __ref_walk_free(ref);
+ ref_walk_cur(rw) = ref;
+ return 0;
+}
+
+static inline struct dfs_cache_tgt_iterator *
+ref_walk_next_tgt(struct dfs_ref_walk *rw)
+{
+ struct dfs_cache_tgt_iterator *tit;
+ struct dfs_ref *ref = ref_walk_cur(rw);
+
+ if (!ref->tit)
+ tit = dfs_cache_get_tgt_iterator(&ref->tl);
+ else
+ tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit);
+ ref->tit = tit;
+ return tit;
+}
+
+static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw,
+ struct dfs_info3_param *tgt)
+{
+ zfree_dfs_info_param(tgt);
+ return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1,
+ ref_walk_tit(rw), tgt);
+}
+
+static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw)
+{
+ return dfs_cache_get_nr_tgts(ref_walk_tl(rw));
+}
+
+static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw)
+{
+ dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1,
+ ref_walk_tit(rw));
+}
struct dfs_root_ses {
struct list_head list;
@@ -34,43 +138,6 @@ static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *p
cifs_remap(cifs_sb), path, ref, tl);
}
-/* Return DFS full path out of a dentry set for automount */
-static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
-{
- struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
- struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
- size_t len;
- char *s;
-
- spin_lock(&tcon->tc_lock);
- if (unlikely(!tcon->origin_fullpath)) {
- spin_unlock(&tcon->tc_lock);
- return ERR_PTR(-EREMOTE);
- }
- spin_unlock(&tcon->tc_lock);
-
- s = dentry_path_raw(dentry, page, PATH_MAX);
- if (IS_ERR(s))
- return s;
- /* for root, we want "" */
- if (!s[1])
- s++;
-
- spin_lock(&tcon->tc_lock);
- len = strlen(tcon->origin_fullpath);
- if (s < (char *)page + len) {
- spin_unlock(&tcon->tc_lock);
- return ERR_PTR(-ENAMETOOLONG);
- }
-
- s -= len;
- memcpy(s, tcon->origin_fullpath, len);
- spin_unlock(&tcon->tc_lock);
- convert_delimiter(s, '/');
-
- return s;
-}
-
static inline void dfs_put_root_smb_sessions(struct list_head *head)
{
struct dfs_root_ses *root, *tmp;
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 33adf43a01f1..508d831fabe3 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -29,8 +29,6 @@
#define CACHE_MIN_TTL 120 /* 2 minutes */
#define CACHE_DEFAULT_TTL 300 /* 5 minutes */
-#define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
-
struct cache_dfs_tgt {
char *name;
int path_consumed;
@@ -174,7 +172,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
"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",
ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags,
- IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
+ DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
list_for_each_entry(t, &ce->tlist, list) {
@@ -243,7 +241,7 @@ static inline void dump_ce(const struct cache_entry *ce)
ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
ce->etime.tv_nsec,
ce->hdr_flags, ce->ref_flags,
- IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
+ DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
ce->path_consumed,
cache_entry_expired(ce) ? "yes" : "no");
dump_tgts(ce);
@@ -1177,9 +1175,9 @@ static bool is_ses_good(struct cifs_ses *ses)
/* Refresh dfs referral of tcon and mark it for reconnect if needed */
static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh)
{
- struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl);
- struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl);
struct TCP_Server_Info *server = ses->server;
+ DFS_CACHE_TGT_LIST(old_tl);
+ DFS_CACHE_TGT_LIST(new_tl);
bool needs_refresh = false;
struct cache_entry *ce;
unsigned int xid;
diff --git a/fs/smb/client/dfs_cache.h b/fs/smb/client/dfs_cache.h
index c6d89cd6d4fd..18a08a2ca93b 100644
--- a/fs/smb/client/dfs_cache.h
+++ b/fs/smb/client/dfs_cache.h
@@ -16,7 +16,11 @@
extern struct workqueue_struct *dfscache_wq;
extern atomic_t dfs_cache_ttl;
-#define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
+#define DFS_CACHE_TGT_LIST_INIT(var) \
+ { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
+
+#define DFS_CACHE_TGT_LIST(var) \
+ struct dfs_cache_tgt_list var = DFS_CACHE_TGT_LIST_INIT(var)
struct dfs_cache_tgt_list {
int tl_numtgts;
@@ -51,8 +55,8 @@ static inline struct dfs_cache_tgt_iterator *
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
struct dfs_cache_tgt_iterator *it)
{
- if (!tl || list_empty(&tl->tl_list) || !it ||
- list_is_last(&it->it_list, &tl->tl_list))
+ if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list) ||
+ !it || list_is_last(&it->it_list, &tl->tl_list))
return NULL;
return list_next_entry(it, it_list);
}
@@ -71,7 +75,7 @@ static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl)
{
struct dfs_cache_tgt_iterator *it, *nit;
- if (!tl || list_empty(&tl->tl_list))
+ if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list))
return;
list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
list_del(&it->it_list);
diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c
index 30b1e1bfd204..580a27a3a7e6 100644
--- a/fs/smb/client/dir.c
+++ b/fs/smb/client/dir.c
@@ -797,7 +797,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
const struct dentry_operations cifs_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
- .d_automount = cifs_dfs_d_automount,
+ .d_automount = cifs_d_automount,
/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
};
@@ -872,5 +872,5 @@ const struct dentry_operations cifs_ci_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
.d_hash = cifs_ci_hash,
.d_compare = cifs_ci_compare,
- .d_automount = cifs_dfs_d_automount,
+ .d_automount = cifs_d_automount,
};
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 93fe43789d7a..de2dfbaae821 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -58,13 +58,9 @@ static void cifs_set_ops(struct inode *inode)
inode->i_data.a_ops = &cifs_addr_ops;
break;
case S_IFDIR:
-#ifdef CONFIG_CIFS_DFS_UPCALL
if (IS_AUTOMOUNT(inode)) {
- inode->i_op = &cifs_dfs_referral_inode_operations;
+ inode->i_op = &cifs_namespace_inode_operations;
} else {
-#else /* NO DFS support, treat as a directory */
- {
-#endif
inode->i_op = &cifs_dir_inode_ops;
inode->i_fop = &cifs_dir_ops;
}
@@ -218,7 +214,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
}
spin_unlock(&inode->i_lock);
- if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
+ if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
inode->i_flags |= S_AUTOMOUNT;
if (inode->i_state & I_NEW)
cifs_set_ops(inode);
@@ -327,14 +323,14 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
*
* Needed to setup cifs_fattr data for the directory which is the
* junction to the new submount (ie to setup the fake directory
- * which represents a DFS referral).
+ * which represents a DFS referral or reparse mount point).
*/
-static void
-cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
+static void cifs_create_junction_fattr(struct cifs_fattr *fattr,
+ struct super_block *sb)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- cifs_dbg(FYI, "creating fake fattr for DFS referral\n");
+ cifs_dbg(FYI, "%s: creating fake fattr\n", __func__);
memset(fattr, 0, sizeof(*fattr));
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)
ktime_get_coarse_real_ts64(&fattr->cf_mtime);
fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
fattr->cf_nlink = 2;
- fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
+ fattr->cf_flags = CIFS_FATTR_JUNCTION;
+}
+
+/* Update inode with final fattr data */
+static int update_inode_info(struct super_block *sb,
+ struct cifs_fattr *fattr,
+ struct inode **inode)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ int rc = 0;
+
+ if (!*inode) {
+ *inode = cifs_iget(sb, fattr);
+ if (!*inode)
+ rc = -ENOMEM;
+ return rc;
+ }
+ /* We already have inode, update it.
+ *
+ * If file type or uniqueid is different, return error.
+ */
+ if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+ CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
+ CIFS_I(*inode)->time = 0; /* force reval */
+ return -ESTALE;
+ }
+ return cifs_fattr_to_inode(*inode, fattr);
}
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -373,7 +395,7 @@ cifs_get_file_info_unix(struct file *filp)
if (!rc) {
cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
} else if (rc == -EREMOTE) {
- cifs_create_dfs_fattr(&fattr, inode->i_sb);
+ cifs_create_junction_fattr(&fattr, inode->i_sb);
rc = 0;
} else
goto cifs_gfiunix_out;
@@ -385,17 +407,18 @@ cifs_gfiunix_out:
return rc;
}
-int cifs_get_inode_info_unix(struct inode **pinode,
- const unsigned char *full_path,
- struct super_block *sb, unsigned int xid)
+static int cifs_get_unix_fattr(const unsigned char *full_path,
+ struct super_block *sb,
+ struct cifs_fattr *fattr,
+ struct inode **pinode,
+ const unsigned int xid)
{
- int rc;
+ struct TCP_Server_Info *server;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
FILE_UNIX_BASIC_INFO find_data;
- struct cifs_fattr fattr;
struct cifs_tcon *tcon;
- struct TCP_Server_Info *server;
struct tcon_link *tlink;
- struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ int rc, tmprc;
cifs_dbg(FYI, "Getting info on %s\n", full_path);
@@ -412,59 +435,61 @@ int cifs_get_inode_info_unix(struct inode **pinode,
cifs_put_tlink(tlink);
if (!rc) {
- cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
+ cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb);
} else if (rc == -EREMOTE) {
- cifs_create_dfs_fattr(&fattr, sb);
+ cifs_create_junction_fattr(fattr, sb);
rc = 0;
} else {
return rc;
}
+ if (!*pinode)
+ cifs_fill_uniqueid(sb, fattr);
+
/* check for Minshall+French symlinks */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
- int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
- full_path);
- if (tmprc)
- cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
- if (S_ISLNK(fattr.cf_mode) && !fattr.cf_symlink_target) {
+ if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) {
if (!server->ops->query_symlink)
return -EOPNOTSUPP;
- rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
- &fattr.cf_symlink_target, false);
- if (rc) {
- cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
- goto cgiiu_exit;
- }
+ rc = server->ops->query_symlink(xid, tcon,
+ cifs_sb, full_path,
+ &fattr->cf_symlink_target,
+ NULL);
+ cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
}
+ return rc;
+}
- if (*pinode == NULL) {
- /* get new inode */
- cifs_fill_uniqueid(sb, &fattr);
- *pinode = cifs_iget(sb, &fattr);
- if (!*pinode)
- rc = -ENOMEM;
- } else {
- /* we already have inode, update it */
-
- /* if uniqueid is different, return error */
- if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
- CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
- CIFS_I(*pinode)->time = 0; /* force reval */
- rc = -ESTALE;
- goto cgiiu_exit;
- }
+int cifs_get_inode_info_unix(struct inode **pinode,
+ const unsigned char *full_path,
+ struct super_block *sb, unsigned int xid)
+{
+ struct cifs_fattr fattr = {};
+ int rc;
- /* if filetype is different, return error */
- rc = cifs_fattr_to_inode(*pinode, &fattr);
- }
+ rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid);
+ if (rc)
+ goto out;
-cgiiu_exit:
+ rc = update_inode_info(sb, &fattr, pinode);
+out:
kfree(fattr.cf_symlink_target);
return rc;
}
#else
+static inline int cifs_get_unix_fattr(const unsigned char *full_path,
+ struct super_block *sb,
+ struct cifs_fattr *fattr,
+ struct inode **pinode,
+ const unsigned int xid)
+{
+ return -EOPNOTSUPP;
+}
+
int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *full_path,
struct super_block *sb, unsigned int xid)
@@ -632,10 +657,11 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
}
/* Fill a cifs_fattr struct with info from POSIX info struct */
-static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
+static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
+ struct cifs_open_info_data *data,
struct cifs_sid *owner,
struct cifs_sid *group,
- struct super_block *sb, bool adjust_tz, bool symlink)
+ struct super_block *sb)
{
struct smb311_posix_qinfo *info = &data->posix_fi;
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
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
- if (adjust_tz) {
+ if (data->adjust_tz) {
fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
}
@@ -669,7 +695,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
/* The srv fs device id is overridden on network mount so setting rdev isn't needed here */
/* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */
- if (symlink) {
+ if (data->symlink) {
fattr->cf_mode |= S_IFLNK;
fattr->cf_dtype = DT_LNK;
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
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
}
-static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
- struct super_block *sb, bool adjust_tz, bool symlink,
- u32 reparse_tag)
+bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
+ struct cifs_fattr *fattr,
+ u32 tag)
+{
+ switch (tag) {
+ case IO_REPARSE_TAG_LX_SYMLINK:
+ fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
+ fattr->cf_dtype = DT_LNK;
+ break;
+ case IO_REPARSE_TAG_LX_FIFO:
+ fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
+ fattr->cf_dtype = DT_FIFO;
+ break;
+ case IO_REPARSE_TAG_AF_UNIX:
+ fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
+ fattr->cf_dtype = DT_SOCK;
+ break;
+ case IO_REPARSE_TAG_LX_CHR:
+ fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
+ fattr->cf_dtype = DT_CHR;
+ break;
+ case IO_REPARSE_TAG_LX_BLK:
+ fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
+ fattr->cf_dtype = DT_BLK;
+ break;
+ case 0: /* SMB1 symlink */
+ case IO_REPARSE_TAG_SYMLINK:
+ case IO_REPARSE_TAG_NFS:
+ fattr->cf_mode = S_IFLNK;
+ fattr->cf_dtype = DT_LNK;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
+ struct cifs_open_info_data *data,
+ struct super_block *sb)
{
struct smb2_file_all_info *info = &data->fi;
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
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
- if (adjust_tz) {
+ if (data->adjust_tz) {
fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
}
@@ -719,28 +782,13 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
-
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
- if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
- fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_LNK;
- } else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
- fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_FIFO;
- } else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
- fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_SOCK;
- } else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
- fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_CHR;
- } else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
- fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_BLK;
- } else if (symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
- reparse_tag == IO_REPARSE_TAG_NFS) {
- fattr->cf_mode = S_IFLNK;
- fattr->cf_dtype = DT_LNK;
- } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+
+ if (cifs_open_data_reparse(data) &&
+ cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag))
+ goto out_reparse;
+
+ if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
fattr->cf_dtype = DT_DIR;
/*
@@ -769,6 +817,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i
}
}
+out_reparse:
if (S_ISLNK(fattr->cf_mode)) {
fattr->cf_symlink_target = data->symlink_target;
data->symlink_target = NULL;
@@ -789,8 +838,6 @@ cifs_get_file_info(struct file *filp)
struct cifsFileInfo *cfile = filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
- bool symlink = false;
- u32 tag = 0;
if (!server->ops->query_file_info)
return -ENOSYS;
@@ -800,14 +847,15 @@ cifs_get_file_info(struct file *filp)
switch (rc) {
case 0:
/* TODO: add support to query reparse tag */
+ data.adjust_tz = false;
if (data.symlink_target) {
- symlink = true;
- tag = IO_REPARSE_TAG_SYMLINK;
+ data.symlink = true;
+ data.reparse_tag = IO_REPARSE_TAG_SYMLINK;
}
- cifs_open_info_to_fattr(&fattr, &data, inode->i_sb, false, symlink, tag);
+ cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
break;
case -EREMOTE:
- cifs_create_dfs_fattr(&fattr, inode->i_sb);
+ cifs_create_junction_fattr(&fattr, inode->i_sb);
rc = 0;
break;
case -EOPNOTSUPP:
@@ -960,22 +1008,66 @@ static inline bool is_inode_cache_good(struct inode *ino)
return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
}
-int cifs_get_inode_info(struct inode **inode, const char *full_path,
- struct cifs_open_info_data *data, struct super_block *sb, int xid,
- const struct cifs_fid *fid)
+static int reparse_info_to_fattr(struct cifs_open_info_data *data,
+ struct super_block *sb,
+ const unsigned int xid,
+ struct cifs_tcon *tcon,
+ const char *full_path,
+ struct cifs_fattr *fattr)
{
+ struct TCP_Server_Info *server = tcon->ses->server;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct kvec rsp_iov, *iov = NULL;
+ int rsp_buftype = CIFS_NO_BUFFER;
+ u32 tag = data->reparse_tag;
+ int rc = 0;
+
+ if (!tag && server->ops->query_reparse_point) {
+ rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
+ full_path, &tag,
+ &rsp_iov, &rsp_buftype);
+ if (!rc)
+ iov = &rsp_iov;
+ }
+ switch ((data->reparse_tag = tag)) {
+ case 0: /* SMB1 symlink */
+ iov = NULL;
+ fallthrough;
+ case IO_REPARSE_TAG_NFS:
+ case IO_REPARSE_TAG_SYMLINK:
+ if (!data->symlink_target && server->ops->query_symlink) {
+ rc = server->ops->query_symlink(xid, tcon,
+ cifs_sb, full_path,
+ &data->symlink_target,
+ iov);
+ }
+ break;
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ cifs_create_junction_fattr(fattr, sb);
+ goto out;
+ }
+
+ cifs_open_info_to_fattr(fattr, data, sb);
+out:
+ free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
+ return rc;
+}
+
+static int cifs_get_fattr(struct cifs_open_info_data *data,
+ struct super_block *sb, int xid,
+ const struct cifs_fid *fid,
+ struct cifs_fattr *fattr,
+ struct inode **inode,
+ const char *full_path)
+{
+ struct cifs_open_info_data tmp_data = {};
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
struct tcon_link *tlink;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- bool adjust_tz = false;
- struct cifs_fattr fattr = {0};
- bool is_reparse_point = false;
- struct cifs_open_info_data tmp_data = {};
void *smb1_backup_rsp_buf = NULL;
int rc = 0;
int tmprc = 0;
- __u32 reparse_tag = 0;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -988,12 +1080,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
*/
if (!data) {
- if (is_inode_cache_good(*inode)) {
- cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
- goto out;
- }
- rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, &tmp_data,
- &adjust_tz, &is_reparse_point);
+ rc = server->ops->query_path_info(xid, tcon, cifs_sb,
+ full_path, &tmp_data);
data = &tmp_data;
}
@@ -1008,28 +1096,16 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
* since we have to check if its reparse tag matches a known
* special file type e.g. symlink or fifo or char etc.
*/
- if (is_reparse_point && data->symlink_target) {
- reparse_tag = IO_REPARSE_TAG_SYMLINK;
- } else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) &&
- server->ops->query_reparse_tag) {
- tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path,
- &reparse_tag);
- if (tmprc)
- cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
- if (server->ops->query_symlink) {
- tmprc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
- &data->symlink_target,
- is_reparse_point);
- if (tmprc)
- cifs_dbg(FYI, "%s: query_symlink: rc = %d\n", __func__,
- tmprc);
- }
+ if (cifs_open_data_reparse(data)) {
+ rc = reparse_info_to_fattr(data, sb, xid, tcon,
+ full_path, fattr);
+ } else {
+ cifs_open_info_to_fattr(fattr, data, sb);
}
- cifs_open_info_to_fattr(&fattr, data, sb, adjust_tz, is_reparse_point, reparse_tag);
break;
case -EREMOTE:
/* DFS link, no metadata available on this server */
- cifs_create_dfs_fattr(&fattr, sb);
+ cifs_create_junction_fattr(fattr, sb);
rc = 0;
break;
case -EACCES:
@@ -1059,8 +1135,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
fdi = (FILE_DIRECTORY_INFO *)fi;
si = (SEARCH_ID_FULL_DIR_INFO *)fi;
- cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb);
- fattr.cf_uniqueid = le64_to_cpu(si->UniqueId);
+ cifs_dir_info_to_fattr(fattr, fdi, cifs_sb);
+ fattr->cf_uniqueid = le64_to_cpu(si->UniqueId);
/* uniqueid set, skip get inum step */
goto handle_mnt_opt;
} else {
@@ -1077,10 +1153,10 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
}
/*
- * 3. Get or update inode number (fattr.cf_uniqueid)
+ * 3. Get or update inode number (fattr->cf_uniqueid)
*/
- cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr);
+ cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr);
/*
* 4. Tweak fattr based on mount options
@@ -1089,17 +1165,17 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
handle_mnt_opt:
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
/* query for SFU type info if supported and needed */
- if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
- tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
+ if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
+ tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
if (tmprc)
cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
}
/* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
- rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
- full_path, fid);
+ rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
+ true, full_path, fid);
if (rc == -EREMOTE)
rc = 0;
if (rc) {
@@ -1108,8 +1184,8 @@ handle_mnt_opt:
goto out;
}
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
- rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
- full_path, fid);
+ rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
+ false, full_path, fid);
if (rc == -EREMOTE)
rc = 0;
if (rc) {
@@ -1121,60 +1197,57 @@ handle_mnt_opt:
/* fill in remaining high mode bits e.g. SUID, VTX */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
- cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
+ cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
/* check for Minshall+French symlinks */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
- tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
- full_path);
- if (tmprc)
- cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
- /*
- * 5. Update inode with final fattr data
- */
-
- if (!*inode) {
- *inode = cifs_iget(sb, &fattr);
- if (!*inode)
- rc = -ENOMEM;
- } else {
- /* we already have inode, update it */
-
- /* if uniqueid is different, return error */
- if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
- CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
- CIFS_I(*inode)->time = 0; /* force reval */
- rc = -ESTALE;
- goto out;
- }
- /* if filetype is different, return error */
- rc = cifs_fattr_to_inode(*inode, &fattr);
- }
out:
cifs_buf_release(smb1_backup_rsp_buf);
cifs_put_tlink(tlink);
cifs_free_open_info(&tmp_data);
+ return rc;
+}
+
+int cifs_get_inode_info(struct inode **inode,
+ const char *full_path,
+ struct cifs_open_info_data *data,
+ struct super_block *sb, int xid,
+ const struct cifs_fid *fid)
+{
+ struct cifs_fattr fattr = {};
+ int rc;
+
+ if (is_inode_cache_good(*inode)) {
+ cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
+ return 0;
+ }
+
+ rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path);
+ if (rc)
+ goto out;
+
+ rc = update_inode_info(sb, &fattr, inode);
+out:
kfree(fattr.cf_symlink_target);
return rc;
}
-int
-smb311_posix_get_inode_info(struct inode **inode,
- const char *full_path,
- struct super_block *sb, unsigned int xid)
+static int smb311_posix_get_fattr(struct cifs_fattr *fattr,
+ const char *full_path,
+ struct super_block *sb,
+ const unsigned int xid)
{
+ struct cifs_open_info_data data = {};
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_tcon *tcon;
struct tcon_link *tlink;
- struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- bool adjust_tz = false;
- struct cifs_fattr fattr = {0};
- bool symlink = false;
- struct cifs_open_info_data data = {};
struct cifs_sid owner, group;
- int rc = 0;
- int tmprc = 0;
+ int tmprc;
+ int rc;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
@@ -1185,14 +1258,9 @@ smb311_posix_get_inode_info(struct inode **inode,
* 1. Fetch file metadata
*/
- if (is_inode_cache_good(*inode)) {
- cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
- goto out;
- }
-
- rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data,
- &owner, &group, &adjust_tz,
- &symlink);
+ rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
+ full_path, &data,
+ &owner, &group);
/*
* 2. Convert it to internal cifs metadata (fattr)
@@ -1200,12 +1268,11 @@ smb311_posix_get_inode_info(struct inode **inode,
switch (rc) {
case 0:
- smb311_posix_info_to_fattr(&fattr, &data, &owner, &group,
- sb, adjust_tz, symlink);
+ smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb);
break;
case -EREMOTE:
/* DFS link, no metadata available on this server */
- cifs_create_dfs_fattr(&fattr, sb);
+ cifs_create_junction_fattr(fattr, sb);
rc = 0;
break;
case -EACCES:
@@ -1221,49 +1288,42 @@ smb311_posix_get_inode_info(struct inode **inode,
goto out;
}
-
/*
* 3. Tweak fattr based on mount options
*/
-
/* check for Minshall+French symlinks */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
- tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
- full_path);
- if (tmprc)
- cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+ tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
+ cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
}
- /*
- * 4. Update inode with final fattr data
- */
-
- if (!*inode) {
- *inode = cifs_iget(sb, &fattr);
- if (!*inode)
- rc = -ENOMEM;
- } else {
- /* we already have inode, update it */
+out:
+ cifs_put_tlink(tlink);
+ cifs_free_open_info(&data);
+ return rc;
+}
- /* if uniqueid is different, return error */
- if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
- CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
- CIFS_I(*inode)->time = 0; /* force reval */
- rc = -ESTALE;
- goto out;
- }
+int smb311_posix_get_inode_info(struct inode **inode, const char *full_path,
+ struct super_block *sb, const unsigned int xid)
+{
+ struct cifs_fattr fattr = {};
+ int rc;
- /* if filetype is different, return error */
- rc = cifs_fattr_to_inode(*inode, &fattr);
+ if (is_inode_cache_good(*inode)) {
+ cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
+ return 0;
}
+
+ rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid);
+ if (rc)
+ goto out;
+
+ rc = update_inode_info(sb, &fattr, inode);
out:
- cifs_put_tlink(tlink);
- cifs_free_open_info(&data);
kfree(fattr.cf_symlink_target);
return rc;
}
-
static const struct inode_operations cifs_ipc_inode_ops = {
.lookup = cifs_lookup,
};
@@ -1367,13 +1427,14 @@ retry_iget5_locked:
/* gets root inode */
struct inode *cifs_root_iget(struct super_block *sb)
{
- unsigned int xid;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- struct inode *inode = NULL;
- long rc;
+ struct cifs_fattr fattr = {};
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ struct inode *inode = NULL;
+ unsigned int xid;
char *path = NULL;
int len;
+ int rc;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
&& cifs_sb->prepath) {
@@ -1391,21 +1452,29 @@ struct inode *cifs_root_iget(struct super_block *sb)
xid = get_xid();
if (tcon->unix_ext) {
- rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
+ rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid);
/* some servers mistakenly claim POSIX support */
if (rc != -EOPNOTSUPP)
- goto iget_no_retry;
+ goto iget_root;
cifs_dbg(VFS, "server does not support POSIX extensions\n");
tcon->unix_ext = false;
}
convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
if (tcon->posix_extensions)
- rc = smb311_posix_get_inode_info(&inode, path, sb, xid);
+ rc = smb311_posix_get_fattr(&fattr, path, sb, xid);
else
- rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
+ rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path);
+
+iget_root:
+ if (!rc) {
+ if (fattr.cf_flags & CIFS_FATTR_JUNCTION) {
+ fattr.cf_flags &= ~CIFS_FATTR_JUNCTION;
+ cifs_autodisable_serverino(cifs_sb);
+ }
+ inode = cifs_iget(sb, &fattr);
+ }
-iget_no_retry:
if (!inode) {
inode = ERR_PTR(rc);
goto out;
@@ -1429,6 +1498,7 @@ iget_no_retry:
out:
kfree(path);
free_xid(xid);
+ kfree(fattr.cf_symlink_target);
return inode;
}
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index d7e85d9a2655..366b755ca913 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -476,7 +476,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
return false;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
+ pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
/* look up tcon based on tid & uid */
spin_lock(&cifs_tcp_ses_lock);
diff --git a/fs/smb/client/cifs_dfs_ref.c b/fs/smb/client/namespace.c
index b1c2499b1c3b..c8f5ed8a69f1 100644
--- a/fs/smb/client/cifs_dfs_ref.c
+++ b/fs/smb/client/namespace.c
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Contains the CIFS DFS referral mounting routines used for handling
- * traversal via DFS junction point
+ * Contains mounting routines used for handling traversal via SMB junctions.
*
* Copyright (c) 2007 Igor Mammedov
* Copyright (C) International Business Machines Corp., 2008
* Author(s): Igor Mammedov (niallain@gmail.com)
* Steve French (sfrench@us.ibm.com)
+ * Copyright (c) 2023 Paulo Alcantara <palcantara@suse.de>
*/
#include <linux/dcache.h>
@@ -19,32 +19,31 @@
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifsfs.h"
-#include "dns_resolve.h"
#include "cifs_debug.h"
-#include "dfs.h"
#include "fs_context.h"
-static LIST_HEAD(cifs_dfs_automount_list);
+static LIST_HEAD(cifs_automount_list);
-static void cifs_dfs_expire_automounts(struct work_struct *work);
-static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
- cifs_dfs_expire_automounts);
-static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
+static void cifs_expire_automounts(struct work_struct *work);
+static DECLARE_DELAYED_WORK(cifs_automount_task,
+ cifs_expire_automounts);
+static int cifs_mountpoint_expiry_timeout = 500 * HZ;
-static void cifs_dfs_expire_automounts(struct work_struct *work)
+static void cifs_expire_automounts(struct work_struct *work)
{
- struct list_head *list = &cifs_dfs_automount_list;
+ struct list_head *list = &cifs_automount_list;
mark_mounts_for_expiry(list);
if (!list_empty(list))
- schedule_delayed_work(&cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
+ schedule_delayed_work(&cifs_automount_task,
+ cifs_mountpoint_expiry_timeout);
}
-void cifs_dfs_release_automount_timer(void)
+void cifs_release_automount_timer(void)
{
- BUG_ON(!list_empty(&cifs_dfs_automount_list));
- cancel_delayed_work_sync(&cifs_dfs_automount_task);
+ if (WARN_ON(!list_empty(&cifs_automount_list)))
+ return;
+ cancel_delayed_work_sync(&cifs_automount_task);
}
/**
@@ -118,26 +117,53 @@ cifs_build_devname(char *nodename, const char *prepath)
return dev;
}
-static int set_dest_addr(struct smb3_fs_context *ctx)
+/* Return full path out of a dentry set for automount */
+static char *automount_fullpath(struct dentry *dentry, void *page)
{
- struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
- int rc;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ size_t len;
+ char *s;
+
+ spin_lock(&tcon->tc_lock);
+ if (!tcon->origin_fullpath) {
+ spin_unlock(&tcon->tc_lock);
+ return build_path_from_dentry_optional_prefix(dentry,
+ page,
+ true);
+ }
+ spin_unlock(&tcon->tc_lock);
+
+ s = dentry_path_raw(dentry, page, PATH_MAX);
+ if (IS_ERR(s))
+ return s;
+ /* for root, we want "" */
+ if (!s[1])
+ s++;
+
+ spin_lock(&tcon->tc_lock);
+ len = strlen(tcon->origin_fullpath);
+ if (s < (char *)page + len) {
+ spin_unlock(&tcon->tc_lock);
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+
+ s -= len;
+ memcpy(s, tcon->origin_fullpath, len);
+ spin_unlock(&tcon->tc_lock);
+ convert_delimiter(s, '/');
- rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
- if (!rc)
- cifs_set_port(addr, ctx->port);
- return rc;
+ return s;
}
/*
* Create a vfsmount that we can automount
*/
-static struct vfsmount *cifs_dfs_do_automount(struct path *path)
+static struct vfsmount *cifs_do_automount(struct path *path)
{
int rc;
struct dentry *mntpt = path->dentry;
struct fs_context *fc;
- struct cifs_sb_info *cifs_sb;
void *page = NULL;
struct smb3_fs_context *ctx, *cur_ctx;
struct smb3_fs_context tmp;
@@ -147,17 +173,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
if (IS_ROOT(mntpt))
return ERR_PTR(-ESTALE);
- /*
- * The MSDFS spec states that paths in DFS referral requests and
- * responses must be prefixed by a single '\' character instead of
- * the double backslashes usually used in the UNC. This function
- * gives us the latter, so we must adjust the result.
- */
- cifs_sb = CIFS_SB(mntpt->d_sb);
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
- return ERR_PTR(-EREMOTE);
-
- cur_ctx = cifs_sb->ctx;
+ cur_ctx = CIFS_SB(mntpt->d_sb)->ctx;
fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
if (IS_ERR(fc))
@@ -166,7 +182,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
ctx = smb3_fc2context(fc);
page = alloc_dentry_path();
- full_path = dfs_get_automount_devname(mntpt, page);
+ full_path = automount_fullpath(mntpt, page);
if (IS_ERR(full_path)) {
mnt = ERR_CAST(full_path);
goto out;
@@ -196,15 +212,10 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
ctx->source = NULL;
goto out;
}
- cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n",
- __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr);
-
- rc = set_dest_addr(ctx);
- if (!rc)
- mnt = fc_mount(fc);
- else
- mnt = ERR_PTR(rc);
+ cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s\n",
+ __func__, ctx->source, ctx->UNC, ctx->prepath);
+ mnt = fc_mount(fc);
out:
put_fs_context(fc);
free_dentry_path(page);
@@ -214,25 +225,25 @@ out:
/*
* Attempt to automount the referral
*/
-struct vfsmount *cifs_dfs_d_automount(struct path *path)
+struct vfsmount *cifs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
- newmnt = cifs_dfs_do_automount(path);
+ newmnt = cifs_do_automount(path);
if (IS_ERR(newmnt)) {
cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
return newmnt;
}
mntget(newmnt); /* prevent immediate expiration */
- mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
- schedule_delayed_work(&cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
+ mnt_set_expiry(newmnt, &cifs_automount_list);
+ schedule_delayed_work(&cifs_automount_task,
+ cifs_mountpoint_expiry_timeout);
cifs_dbg(FYI, "leaving %s [ok]\n" , __func__);
return newmnt;
}
-const struct inode_operations cifs_dfs_referral_inode_operations = {
+const struct inode_operations cifs_namespace_inode_operations = {
};
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index ef638086d734..47fc22de8d20 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -143,6 +143,7 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
case IO_REPARSE_TAG_DFSR:
case IO_REPARSE_TAG_SYMLINK:
case IO_REPARSE_TAG_NFS:
+ case IO_REPARSE_TAG_MOUNT_POINT:
case 0:
return true;
}
@@ -163,29 +164,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
* TODO: go through all documented reparse tags to see if we can
* reasonably map some of them to directories vs. files vs. symlinks
*/
+ if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
+ cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag))
+ goto out_reparse;
+
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
fattr->cf_dtype = DT_DIR;
- } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
- fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_LNK;
- } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
- fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_FIFO;
- } else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
- fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_SOCK;
- } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
- fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_CHR;
- } else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
- fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
- fattr->cf_dtype = DT_BLK;
- } else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
+ } else {
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_REG;
}
+out_reparse:
/*
* We need to revalidate it further to make a decision about whether it
* is a symbolic link, DFS referral or a reparse point with a direct
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index c57ca2050b73..79f26c560edf 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -323,12 +323,12 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
ses->chans[chan_index].iface = iface;
/* No iface is found. if secondary chan, drop connection */
- if (!iface && CIFS_SERVER_IS_CHAN(server))
+ if (!iface && SERVER_IS_CHAN(server))
ses->chans[chan_index].server = NULL;
spin_unlock(&ses->chan_lock);
- if (!iface && CIFS_SERVER_IS_CHAN(server))
+ if (!iface && SERVER_IS_CHAN(server))
cifs_put_tcp_session(server, false);
return rc;
@@ -360,11 +360,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
{
struct TCP_Server_Info *chan_server;
struct cifs_chan *chan;
- struct smb3_fs_context ctx = {NULL};
+ struct smb3_fs_context *ctx;
static const char unc_fmt[] = "\\%s\\foo";
- char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
+ size_t len;
int rc;
unsigned int xid = get_xid();
@@ -388,54 +388,64 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
* the session and server without caring about memory
* management.
*/
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto out_free_xid;
+ }
/* Always make new connection for now (TODO?) */
- ctx.nosharesock = true;
+ ctx->nosharesock = true;
/* Auth */
- ctx.domainauto = ses->domainAuto;
- ctx.domainname = ses->domainName;
+ ctx->domainauto = ses->domainAuto;
+ ctx->domainname = ses->domainName;
/* no hostname for extra channels */
- ctx.server_hostname = "";
+ ctx->server_hostname = "";
- ctx.username = ses->user_name;
- ctx.password = ses->password;
- ctx.sectype = ses->sectype;
- ctx.sign = ses->sign;
+ ctx->username = ses->user_name;
+ ctx->password = ses->password;
+ ctx->sectype = ses->sectype;
+ ctx->sign = ses->sign;
/* UNC and paths */
/* XXX: Use ses->server->hostname? */
- sprintf(unc, unc_fmt, ses->ip_addr);
- ctx.UNC = unc;
- ctx.prepath = "";
+ len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL;
+ ctx->UNC = kzalloc(len, GFP_KERNEL);
+ if (!ctx->UNC) {
+ rc = -ENOMEM;
+ goto out_free_ctx;
+ }
+ scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr);
+ ctx->prepath = "";
/* Reuse same version as master connection */
- ctx.vals = ses->server->vals;
- ctx.ops = ses->server->ops;
+ ctx->vals = ses->server->vals;
+ ctx->ops = ses->server->ops;
- ctx.noblocksnd = ses->server->noblocksnd;
- ctx.noautotune = ses->server->noautotune;
- ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
- ctx.echo_interval = ses->server->echo_interval / HZ;
- ctx.max_credits = ses->server->max_credits;
+ ctx->noblocksnd = ses->server->noblocksnd;
+ ctx->noautotune = ses->server->noautotune;
+ ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay;
+ ctx->echo_interval = ses->server->echo_interval / HZ;
+ ctx->max_credits = ses->server->max_credits;
/*
* This will be used for encoding/decoding user/domain/pw
* during sess setup auth.
*/
- ctx.local_nls = cifs_sb->local_nls;
+ ctx->local_nls = cifs_sb->local_nls;
/* Use RDMA if possible */
- ctx.rdma = iface->rdma_capable;
- memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
+ ctx->rdma = iface->rdma_capable;
+ memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr));
/* reuse master con client guid */
- memcpy(&ctx.client_guid, ses->server->client_guid,
- SMB2_CLIENT_GUID_SIZE);
- ctx.use_client_guid = true;
+ memcpy(&ctx->client_guid, ses->server->client_guid,
+ sizeof(ctx->client_guid));
+ ctx->use_client_guid = true;
- chan_server = cifs_get_tcp_session(&ctx, ses->server);
+ chan_server = cifs_get_tcp_session(ctx, ses->server);
spin_lock(&ses->chan_lock);
chan = &ses->chans[ses->chan_count];
@@ -497,6 +507,10 @@ out:
cifs_put_tcp_session(chan->server, 0);
}
+ kfree(ctx->UNC);
+out_free_ctx:
+ kfree(ctx);
+out_free_xid:
free_xid(xid);
return rc;
}
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 7d1b3fc014d9..9bf8735cdd1e 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -542,14 +542,17 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
-static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- struct cifs_open_info_data *data, bool *adjustTZ, bool *symlink)
+static int cifs_query_path_info(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ struct cifs_open_info_data *data)
{
int rc;
FILE_ALL_INFO fi = {};
- *symlink = false;
+ data->symlink = false;
+ data->adjust_tz = false;
/* could do find first instead but this returns more info */
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,
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
cifs_remap(cifs_sb));
- *adjustTZ = true;
+ data->adjust_tz = true;
}
if (!rc) {
@@ -589,7 +592,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
/* Need to check if this is a symbolic link or not */
tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
if (tmprc == -EOPNOTSUPP)
- *symlink = true;
+ data->symlink = true;
else if (tmprc == 0)
CIFSSMBClose(xid, tcon, fid.netfid);
}
@@ -969,13 +972,16 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
#endif
}
-static int
-cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- char **target_path, bool is_reparse_point)
+static int cifs_query_symlink(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ char **target_path,
+ struct kvec *rsp_iov)
{
int rc;
int oplock = 0;
+ bool is_reparse_point = !!rsp_iov;
struct cifs_fid fid;
struct cifs_open_parms oparms;
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 8e696fbd72fa..b41e2e872b22 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -35,34 +35,22 @@ free_set_inf_compound(struct smb_rqst *rqst)
SMB2_close_free(&rqst[2]);
}
-
-struct cop_vars {
- struct cifs_open_parms oparms;
- struct kvec rsp_iov[3];
- struct smb_rqst rqst[3];
- struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
- struct kvec qi_iov[1];
- struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
- struct kvec close_iov[1];
- struct smb2_file_rename_info rename_info;
- struct smb2_file_link_info link_info;
-};
-
/*
* note: If cfile is passed, the reference to it is dropped here.
* So make sure that you do not reuse cfile after return from this func.
*
- * If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all
- * error responses. Caller is also responsible for freeing them up.
+ * If passing @out_iov and @out_buftype, ensure to make them both large enough
+ * (>= 3) to hold all compounded responses. Caller is also responsible for
+ * freeing them up with free_rsp_buf().
*/
static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path,
__u32 desired_access, __u32 create_disposition, __u32 create_options,
umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
__u8 **extbuf, size_t *extbuflen,
- struct kvec *err_iov, int *err_buftype)
+ struct kvec *out_iov, int *out_buftype)
{
- struct cop_vars *vars = NULL;
+ struct smb2_compound_vars *vars = NULL;
struct kvec *rsp_iov;
struct smb_rqst *rqst;
int rc;
@@ -133,7 +121,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
/* Operation */
switch (command) {
case SMB2_OP_QUERY_INFO:
- rqst[num_rqst].rq_iov = &vars->qi_iov[0];
+ rqst[num_rqst].rq_iov = &vars->qi_iov;
rqst[num_rqst].rq_nvec = 1;
if (cfile)
@@ -167,7 +155,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
full_path);
break;
case SMB2_OP_POSIX_QUERY_INFO:
- rqst[num_rqst].rq_iov = &vars->qi_iov[0];
+ rqst[num_rqst].rq_iov = &vars->qi_iov;
rqst[num_rqst].rq_nvec = 1;
if (cfile)
@@ -375,7 +363,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
goto after_close;
/* Close */
flags |= CIFS_CP_CREATE_CLOSE_OP;
- rqst[num_rqst].rq_iov = &vars->close_iov[0];
+ rqst[num_rqst].rq_iov = &vars->close_iov;
rqst[num_rqst].rq_nvec = 1;
rc = SMB2_close_init(tcon, server,
&rqst[num_rqst], COMPOUND_FID,
@@ -529,9 +517,9 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
if (cfile)
cifsFileInfo_put(cfile);
- if (rc && err_iov && err_buftype) {
- memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov));
- memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype));
+ if (out_iov && out_buftype) {
+ memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov));
+ memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype));
} else {
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
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,
return rc;
}
-int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse)
+static int parse_create_response(struct cifs_open_info_data *data,
+ struct cifs_sb_info *cifs_sb,
+ const struct kvec *iov)
+{
+ struct smb2_create_rsp *rsp = iov->iov_base;
+ bool reparse_point = false;
+ u32 tag = 0;
+ int rc = 0;
+
+ switch (rsp->hdr.Status) {
+ case STATUS_STOPPED_ON_SYMLINK:
+ rc = smb2_parse_symlink_response(cifs_sb, iov,
+ &data->symlink_target);
+ if (rc)
+ return rc;
+ tag = IO_REPARSE_TAG_SYMLINK;
+ reparse_point = true;
+ break;
+ case STATUS_SUCCESS:
+ reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
+ break;
+ }
+ data->reparse_point = reparse_point;
+ data->reparse_tag = tag;
+ return rc;
+}
+
+int smb2_query_path_info(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ struct cifs_open_info_data *data)
{
__u32 create_options = 0;
struct cifsFileInfo *cfile;
struct cached_fid *cfid = NULL;
- struct kvec err_iov[3] = {};
- int err_buftype[3] = {};
+ struct smb2_hdr *hdr;
+ struct kvec out_iov[3] = {};
+ int out_buftype[3] = {};
bool islink;
int rc, rc2;
- *adjust_tz = false;
- *reparse = false;
+ data->adjust_tz = false;
+ data->reparse_point = false;
if (strcmp(full_path, ""))
rc = -ENOENT;
@@ -575,69 +593,73 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
- NULL, NULL, err_iov, err_buftype);
- if (rc) {
- struct smb2_hdr *hdr = err_iov[0].iov_base;
-
- if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER))
+ NULL, NULL, out_iov, out_buftype);
+ hdr = out_iov[0].iov_base;
+ /*
+ * If first iov is unset, then SMB session was dropped or we've got a
+ * cached open file (@cfile).
+ */
+ if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
+ goto out;
+
+ switch (rc) {
+ case 0:
+ case -EOPNOTSUPP:
+ rc = parse_create_response(data, cifs_sb, &out_iov[0]);
+ if (rc || !data->reparse_point)
goto out;
- if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
- hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
- rc = smb2_parse_symlink_response(cifs_sb, err_iov,
- &data->symlink_target);
- if (rc)
- goto out;
-
- *reparse = true;
- create_options |= OPEN_REPARSE_POINT;
-
- /* Failed on a symbolic link - query a reparse point info */
- cifs_get_readable_path(tcon, full_path, &cfile);
- rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
- FILE_READ_ATTRIBUTES, FILE_OPEN,
- create_options, ACL_NO_MODE, data,
- SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
- NULL, NULL);
+
+ create_options |= OPEN_REPARSE_POINT;
+ /* Failed on a symbolic link - query a reparse point info */
+ cifs_get_readable_path(tcon, full_path, &cfile);
+ rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
+ FILE_READ_ATTRIBUTES, FILE_OPEN,
+ create_options, ACL_NO_MODE, data,
+ SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
+ NULL, NULL);
+ break;
+ case -EREMOTE:
+ break;
+ default:
+ if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
+ break;
+ rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
+ full_path, &islink);
+ if (rc2) {
+ rc = rc2;
goto out;
- } else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) {
- rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
- full_path, &islink);
- if (rc2) {
- rc = rc2;
- goto out;
- }
- if (islink)
- rc = -EREMOTE;
}
+ if (islink)
+ rc = -EREMOTE;
}
out:
- free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
- free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
- free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
+ free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
+ free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
+ free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
return rc;
}
-
-int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
+int smb311_posix_query_path_info(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
struct cifs_open_info_data *data,
struct cifs_sid *owner,
- struct cifs_sid *group,
- bool *adjust_tz, bool *reparse)
+ struct cifs_sid *group)
{
int rc;
__u32 create_options = 0;
struct cifsFileInfo *cfile;
- struct kvec err_iov[3] = {};
- int err_buftype[3] = {};
+ struct kvec out_iov[3] = {};
+ int out_buftype[3] = {};
__u8 *sidsbuf = NULL;
__u8 *sidsbuf_end = NULL;
size_t sidsbuflen = 0;
size_t owner_len, group_len;
- *adjust_tz = false;
- *reparse = false;
+ data->adjust_tz = false;
+ data->reparse_point = false;
/*
* 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,
cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
- &sidsbuf, &sidsbuflen, err_iov, err_buftype);
- if (rc == -EOPNOTSUPP) {
+ &sidsbuf, &sidsbuflen, out_iov, out_buftype);
+ /*
+ * If first iov is unset, then SMB session was dropped or we've got a
+ * cached open file (@cfile).
+ */
+ if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
+ goto out;
+
+ switch (rc) {
+ case 0:
+ case -EOPNOTSUPP:
/* BB TODO: When support for special files added to Samba re-verify this path */
- if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
- ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
- ((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
- rc = smb2_parse_symlink_response(cifs_sb, err_iov, &data->symlink_target);
- if (rc)
- goto out;
- }
- *reparse = true;
- create_options |= OPEN_REPARSE_POINT;
+ rc = parse_create_response(data, cifs_sb, &out_iov[0]);
+ if (rc || !data->reparse_point)
+ goto out;
+ create_options |= OPEN_REPARSE_POINT;
/* Failed on a symbolic link - query a reparse point info */
cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
FILE_OPEN, create_options, ACL_NO_MODE, data,
SMB2_OP_POSIX_QUERY_INFO, cfile,
&sidsbuf, &sidsbuflen, NULL, NULL);
+ break;
}
+out:
if (rc == 0) {
sidsbuf_end = sidsbuf + sidsbuflen;
@@ -689,11 +717,10 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
memcpy(group, sidsbuf + owner_len, group_len);
}
-out:
kfree(sidsbuf);
- free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
- free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
- free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
+ free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
+ free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
+ free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
return rc;
}
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index 3935a60db5c3..25f7cd6f23d6 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -145,7 +145,7 @@ smb2_check_message(char *buf, unsigned int len, struct TCP_Server_Info *server)
__u64 mid;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
/*
* 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)
cifs_dbg(FYI, "Checking for lease break\n");
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
/* look up tcon based on tid & uid */
spin_lock(&cifs_tcp_ses_lock);
@@ -698,7 +698,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel);
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
/* look up tcon based on tid & uid */
spin_lock(&cifs_tcp_ses_lock);
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 182e2e879ecf..e3dd698854d6 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -172,8 +172,17 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val)
spin_lock(&server->req_lock);
server->credits = val;
- if (val == 1)
+ if (val == 1) {
server->reconnect_instance++;
+ /*
+ * ChannelSequence updated for all channels in primary channel so that consistent
+ * across SMB3 requests sent on any channel. See MS-SMB2 3.2.4.1 and 3.2.7.1
+ */
+ if (SERVER_IS_CHAN(server))
+ server->primary_server->channel_sequence_num++;
+ else
+ server->channel_sequence_num++;
+ }
scredits = server->credits;
in_flight = server->in_flight;
spin_unlock(&server->req_lock);
@@ -1075,31 +1084,28 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
-
static int
smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
const char *path, const char *ea_name, const void *ea_value,
const __u16 ea_value_len, const struct nls_table *nls_codepage,
struct cifs_sb_info *cifs_sb)
{
+ struct smb2_compound_vars *vars;
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses);
+ struct smb_rqst *rqst;
+ struct kvec *rsp_iov;
__le16 *utf16_path = NULL;
int ea_name_len = strlen(ea_name);
int flags = CIFS_CP_CREATE_CLOSE_OP;
int len;
- struct smb_rqst rqst[3];
int resp_buftype[3];
- struct kvec rsp_iov[3];
- struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
struct cifs_open_parms oparms;
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
struct cifs_fid fid;
- struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
unsigned int size[1];
void *data[1];
struct smb2_file_full_ea_info *ea = NULL;
- struct kvec close_iov[1];
struct smb2_query_info_rsp *rsp;
int rc, used_len = 0;
@@ -1113,9 +1119,14 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
if (!utf16_path)
return -ENOMEM;
- memset(rqst, 0, sizeof(rqst));
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- memset(rsp_iov, 0, sizeof(rsp_iov));
+ vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+ if (!vars) {
+ rc = -ENOMEM;
+ goto out_free_path;
+ }
+ rqst = vars->rqst;
+ rsp_iov = vars->rsp_iov;
if (ses->server->ops->query_all_EAs) {
if (!ea_value) {
@@ -1160,8 +1171,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
}
/* Open */
- memset(&open_iov, 0, sizeof(open_iov));
- rqst[0].rq_iov = open_iov;
+ rqst[0].rq_iov = vars->open_iov;
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
oparms = (struct cifs_open_parms) {
@@ -1181,8 +1191,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
/* Set Info */
- memset(&si_iov, 0, sizeof(si_iov));
- rqst[1].rq_iov = si_iov;
+ rqst[1].rq_iov = vars->si_iov;
rqst[1].rq_nvec = 1;
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,
smb2_set_next_command(tcon, &rqst[1]);
smb2_set_related(&rqst[1]);
-
/* Close */
- memset(&close_iov, 0, sizeof(close_iov));
- rqst[2].rq_iov = close_iov;
+ rqst[2].rq_iov = &vars->close_iov;
rqst[2].rq_nvec = 1;
rc = SMB2_close_init(tcon, server,
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
@@ -1228,13 +1235,15 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
sea_exit:
kfree(ea);
- kfree(utf16_path);
SMB2_open_free(&rqst[0]);
SMB2_set_info_free(&rqst[1]);
SMB2_close_free(&rqst[2]);
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
+ kfree(vars);
+out_free_path:
+ kfree(utf16_path);
return rc;
}
#endif
@@ -1446,16 +1455,6 @@ req_res_key_exit:
return rc;
}
-struct iqi_vars {
- struct smb_rqst rqst[3];
- struct kvec rsp_iov[3];
- struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
- struct kvec qi_iov[1];
- struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
- struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
- struct kvec close_iov[1];
-};
-
static int
smb2_ioctl_query_info(const unsigned int xid,
struct cifs_tcon *tcon,
@@ -1463,7 +1462,7 @@ smb2_ioctl_query_info(const unsigned int xid,
__le16 *path, int is_dir,
unsigned long p)
{
- struct iqi_vars *vars;
+ struct smb2_compound_vars *vars;
struct smb_rqst *rqst;
struct kvec *rsp_iov;
struct cifs_ses *ses = tcon->ses;
@@ -1581,7 +1580,7 @@ smb2_ioctl_query_info(const unsigned int xid,
rc = -EINVAL;
goto free_open_req;
}
- rqst[1].rq_iov = &vars->si_iov[0];
+ rqst[1].rq_iov = vars->si_iov;
rqst[1].rq_nvec = 1;
/* MS-FSCC 2.4.13 FileEndOfFileInformation */
@@ -1593,7 +1592,7 @@ smb2_ioctl_query_info(const unsigned int xid,
SMB2_O_INFO_FILE, 0, data, size);
free_req1_func = SMB2_set_info_free;
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
- rqst[1].rq_iov = &vars->qi_iov[0];
+ rqst[1].rq_iov = &vars->qi_iov;
rqst[1].rq_nvec = 1;
rc = SMB2_query_info_init(tcon, server,
@@ -1615,7 +1614,7 @@ smb2_ioctl_query_info(const unsigned int xid,
smb2_set_related(&rqst[1]);
/* Close */
- rqst[2].rq_iov = &vars->close_iov[0];
+ rqst[2].rq_iov = &vars->close_iov;
rqst[2].rq_nvec = 1;
rc = SMB2_close_init(tcon, server,
@@ -2408,7 +2407,7 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
return false;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
spin_lock(&cifs_tcp_ses_lock);
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,
struct kvec *rsp, int *buftype,
struct cifs_sb_info *cifs_sb)
{
+ struct smb2_compound_vars *vars;
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server = cifs_pick_channel(ses);
int flags = CIFS_CP_CREATE_CLOSE_OP;
- struct smb_rqst rqst[3];
+ struct smb_rqst *rqst;
int resp_buftype[3];
- struct kvec rsp_iov[3];
- struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
- struct kvec qi_iov[1];
- struct kvec close_iov[1];
+ struct kvec *rsp_iov;
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
struct cifs_open_parms oparms;
struct cifs_fid fid;
@@ -2549,9 +2546,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
- memset(rqst, 0, sizeof(rqst));
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- memset(rsp_iov, 0, sizeof(rsp_iov));
+ vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+ if (!vars) {
+ rc = -ENOMEM;
+ goto out_free_path;
+ }
+ rqst = vars->rqst;
+ rsp_iov = vars->rsp_iov;
/*
* 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,
open_cached_dir(xid, tcon, path, cifs_sb, false,
&cfid); /* cfid null if open dir failed */
- memset(&open_iov, 0, sizeof(open_iov));
- rqst[0].rq_iov = open_iov;
+ rqst[0].rq_iov = vars->open_iov;
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
oparms = (struct cifs_open_parms) {
@@ -2579,8 +2580,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
goto qic_exit;
smb2_set_next_command(tcon, &rqst[0]);
- memset(&qi_iov, 0, sizeof(qi_iov));
- rqst[1].rq_iov = qi_iov;
+ rqst[1].rq_iov = &vars->qi_iov;
rqst[1].rq_nvec = 1;
if (cfid) {
@@ -2607,8 +2607,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_related(&rqst[1]);
}
- memset(&close_iov, 0, sizeof(close_iov));
- rqst[2].rq_iov = close_iov;
+ rqst[2].rq_iov = &vars->close_iov;
rqst[2].rq_nvec = 1;
rc = SMB2_close_init(tcon, server,
@@ -2639,7 +2638,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
*buftype = resp_buftype[1];
qic_exit:
- kfree(utf16_path);
SMB2_open_free(&rqst[0]);
SMB2_query_info_free(&rqst[1]);
SMB2_close_free(&rqst[2]);
@@ -2647,6 +2645,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
if (cfid)
close_cached_dir(cfid);
+ kfree(vars);
+out_free_path:
+ kfree(utf16_path);
return rc;
}
@@ -2949,154 +2950,32 @@ parse_reparse_point(struct reparse_data_buffer *buf,
}
}
-static int
-smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- char **target_path, bool is_reparse_point)
+static int smb2_query_symlink(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ char **target_path,
+ struct kvec *rsp_iov)
{
- int rc;
- __le16 *utf16_path = NULL;
- __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
- struct cifs_open_parms oparms;
- struct cifs_fid fid;
- struct kvec err_iov = {NULL, 0};
- struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
- int flags = CIFS_CP_CREATE_CLOSE_OP;
- struct smb_rqst rqst[3];
- int resp_buftype[3];
- struct kvec rsp_iov[3];
- struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
- struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
- struct kvec close_iov[1];
- struct smb2_create_rsp *create_rsp;
- struct smb2_ioctl_rsp *ioctl_rsp;
- struct reparse_data_buffer *reparse_buf;
- int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
- u32 plen;
+ struct reparse_data_buffer *buf;
+ struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
+ u32 plen = le32_to_cpu(io->OutputCount);
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
- *target_path = NULL;
-
- if (smb3_encryption_required(tcon))
- flags |= CIFS_TRANSFORM_REQ;
-
- memset(rqst, 0, sizeof(rqst));
- resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- memset(rsp_iov, 0, sizeof(rsp_iov));
-
- utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
- if (!utf16_path)
- return -ENOMEM;
-
- /* Open */
- memset(&open_iov, 0, sizeof(open_iov));
- rqst[0].rq_iov = open_iov;
- rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
-
- oparms = (struct cifs_open_parms) {
- .tcon = tcon,
- .path = full_path,
- .desired_access = FILE_READ_ATTRIBUTES,
- .disposition = FILE_OPEN,
- .create_options = cifs_create_options(cifs_sb, create_options),
- .fid = &fid,
- };
-
- rc = SMB2_open_init(tcon, server,
- &rqst[0], &oplock, &oparms, utf16_path);
- if (rc)
- goto querty_exit;
- smb2_set_next_command(tcon, &rqst[0]);
-
-
- /* IOCTL */
- memset(&io_iov, 0, sizeof(io_iov));
- rqst[1].rq_iov = io_iov;
- rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
-
- rc = SMB2_ioctl_init(tcon, server,
- &rqst[1], fid.persistent_fid,
- fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
- CIFSMaxBufSize -
- MAX_SMB2_CREATE_RESPONSE_SIZE -
- MAX_SMB2_CLOSE_RESPONSE_SIZE);
- if (rc)
- goto querty_exit;
-
- smb2_set_next_command(tcon, &rqst[1]);
- smb2_set_related(&rqst[1]);
-
-
- /* Close */
- memset(&close_iov, 0, sizeof(close_iov));
- rqst[2].rq_iov = close_iov;
- rqst[2].rq_nvec = 1;
-
- rc = SMB2_close_init(tcon, server,
- &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
- if (rc)
- goto querty_exit;
-
- smb2_set_related(&rqst[2]);
-
- rc = compound_send_recv(xid, tcon->ses, server,
- flags, 3, rqst,
- resp_buftype, rsp_iov);
-
- create_rsp = rsp_iov[0].iov_base;
- if (create_rsp && create_rsp->hdr.Status)
- err_iov = rsp_iov[0];
- ioctl_rsp = rsp_iov[1].iov_base;
-
- /*
- * Open was successful and we got an ioctl response.
- */
- if ((rc == 0) && (is_reparse_point)) {
- /* See MS-FSCC 2.3.23 */
-
- reparse_buf = (struct reparse_data_buffer *)
- ((char *)ioctl_rsp +
- le32_to_cpu(ioctl_rsp->OutputOffset));
- plen = le32_to_cpu(ioctl_rsp->OutputCount);
-
- if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
- rsp_iov[1].iov_len) {
- cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
- plen);
- rc = -EIO;
- goto querty_exit;
- }
-
- rc = parse_reparse_point(reparse_buf, plen, target_path,
- cifs_sb);
- goto querty_exit;
- }
-
- if (!rc || !err_iov.iov_base) {
- rc = -ENOENT;
- goto querty_exit;
- }
-
- rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path);
-
- querty_exit:
- cifs_dbg(FYI, "query symlink rc %d\n", rc);
- kfree(utf16_path);
- SMB2_open_free(&rqst[0]);
- SMB2_ioctl_free(&rqst[1]);
- SMB2_close_free(&rqst[2]);
- free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
- free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
- free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
- return rc;
+ buf = (struct reparse_data_buffer *)((u8 *)io +
+ le32_to_cpu(io->OutputOffset));
+ return parse_reparse_point(buf, plen, target_path, cifs_sb);
}
-int
-smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- __u32 *tag)
+static int smb2_query_reparse_point(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ u32 *tag, struct kvec *rsp,
+ int *rsp_buftype)
{
+ struct smb2_compound_vars *vars;
int rc;
__le16 *utf16_path = NULL;
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
@@ -3104,12 +2983,9 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_fid fid;
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
int flags = CIFS_CP_CREATE_CLOSE_OP;
- struct smb_rqst rqst[3];
+ struct smb_rqst *rqst;
int resp_buftype[3];
- struct kvec rsp_iov[3];
- struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
- struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
- struct kvec close_iov[1];
+ struct kvec *rsp_iov;
struct smb2_ioctl_rsp *ioctl_rsp;
struct reparse_data_buffer *reparse_buf;
u32 plen;
@@ -3119,20 +2995,24 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
- memset(rqst, 0, sizeof(rqst));
- resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- memset(rsp_iov, 0, sizeof(rsp_iov));
-
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
if (!utf16_path)
return -ENOMEM;
+ resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
+ vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+ if (!vars) {
+ rc = -ENOMEM;
+ goto out_free_path;
+ }
+ rqst = vars->rqst;
+ rsp_iov = vars->rsp_iov;
+
/*
* setup smb2open - TODO add optimization to call cifs_get_readable_path
* to see if there is a handle already open that we can use
*/
- memset(&open_iov, 0, sizeof(open_iov));
- rqst[0].rq_iov = open_iov;
+ rqst[0].rq_iov = vars->open_iov;
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
oparms = (struct cifs_open_parms) {
@@ -3152,8 +3032,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
/* IOCTL */
- memset(&io_iov, 0, sizeof(io_iov));
- rqst[1].rq_iov = io_iov;
+ rqst[1].rq_iov = vars->io_iov;
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
rc = SMB2_ioctl_init(tcon, server,
@@ -3168,10 +3047,8 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_next_command(tcon, &rqst[1]);
smb2_set_related(&rqst[1]);
-
/* Close */
- memset(&close_iov, 0, sizeof(close_iov));
- rqst[2].rq_iov = close_iov;
+ rqst[2].rq_iov = &vars->close_iov;
rqst[2].rq_nvec = 1;
rc = SMB2_close_init(tcon, server,
@@ -3206,16 +3083,21 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
goto query_rp_exit;
}
*tag = le32_to_cpu(reparse_buf->ReparseTag);
+ *rsp = rsp_iov[1];
+ *rsp_buftype = resp_buftype[1];
+ resp_buftype[1] = CIFS_NO_BUFFER;
}
query_rp_exit:
- kfree(utf16_path);
SMB2_open_free(&rqst[0]);
SMB2_ioctl_free(&rqst[1]);
SMB2_close_free(&rqst[2]);
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
+ kfree(vars);
+out_free_path:
+ kfree(utf16_path);
return rc;
}
@@ -4401,7 +4283,7 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
u8 *ses_enc_key;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
@@ -5299,6 +5181,7 @@ struct smb_version_operations smb20_operations = {
.can_echo = smb2_can_echo,
.echo = SMB2_echo,
.query_path_info = smb2_query_path_info,
+ .query_reparse_point = smb2_query_reparse_point,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,
@@ -5400,6 +5283,7 @@ struct smb_version_operations smb21_operations = {
.can_echo = smb2_can_echo,
.echo = SMB2_echo,
.query_path_info = smb2_query_path_info,
+ .query_reparse_point = smb2_query_reparse_point,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,
@@ -5504,7 +5388,7 @@ struct smb_version_operations smb30_operations = {
.echo = SMB2_echo,
.query_path_info = smb2_query_path_info,
/* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
- .query_reparse_tag = smb2_query_reparse_tag,
+ .query_reparse_point = smb2_query_reparse_point,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,
@@ -5617,7 +5501,7 @@ struct smb_version_operations smb311_operations = {
.can_echo = smb2_can_echo,
.echo = SMB2_echo,
.query_path_info = smb2_query_path_info,
- .query_reparse_tag = smb2_query_reparse_tag,
+ .query_reparse_point = smb2_query_reparse_point,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index a457f07f820d..092b0087c9dc 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -88,9 +88,20 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
const struct cifs_tcon *tcon,
struct TCP_Server_Info *server)
{
+ struct smb3_hdr_req *smb3_hdr;
shdr->ProtocolId = SMB2_PROTO_NUMBER;
shdr->StructureSize = cpu_to_le16(64);
shdr->Command = smb2_cmd;
+ if (server->dialect >= SMB30_PROT_ID) {
+ /* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
+ smb3_hdr = (struct smb3_hdr_req *)shdr;
+ /* if primary channel is not set yet, use default channel for chan sequence num */
+ if (SERVER_IS_CHAN(server))
+ smb3_hdr->ChannelSequence =
+ cpu_to_le16(server->primary_server->channel_sequence_num);
+ else
+ smb3_hdr->ChannelSequence = cpu_to_le16(server->channel_sequence_num);
+ }
if (server) {
spin_lock(&server->req_lock);
/* Request up to 10 credits but don't go over the limit. */
@@ -553,7 +564,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
* secondary channels don't have the hostname field populated
* use the hostname field in the primary channel instead
*/
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
cifs_server_lock(pserver);
hostname = pserver->hostname;
if (hostname && (hostname[0] != 0)) {
@@ -2570,8 +2581,8 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
/* Do not append the separator if the path is empty */
if (path[0] != cpu_to_le16(0x0000)) {
- UniStrcat(*out_path, sep);
- UniStrcat(*out_path, path);
+ UniStrcat((wchar_t *)*out_path, (wchar_t *)sep);
+ UniStrcat((wchar_t *)*out_path, (wchar_t *)path);
}
unload_nls(cp);
@@ -3785,7 +3796,7 @@ void smb2_reconnect_server(struct work_struct *work)
bool resched = false;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
mutex_lock(&pserver->reconnect_mutex);
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index d5d7ffb7711c..46eff9ec302a 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -56,9 +56,11 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *path,
__u32 *reparse_tag);
-int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
- struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
+int smb2_query_path_info(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
+ struct cifs_open_info_data *data);
extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, __u64 size,
struct cifs_sb_info *cifs_sb, bool set_alloc);
@@ -275,12 +277,13 @@ extern int smb2_query_info_compound(const unsigned int xid,
struct kvec *rsp, int *buftype,
struct cifs_sb_info *cifs_sb);
/* query path info from the server using SMB311 POSIX extensions*/
-int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifs_sb_info *cifs_sb, const char *full_path,
+int smb311_posix_query_path_info(const unsigned int xid,
+ struct cifs_tcon *tcon,
+ struct cifs_sb_info *cifs_sb,
+ const char *full_path,
struct cifs_open_info_data *data,
struct cifs_sid *owner,
- struct cifs_sid *group,
- bool *adjust_tz, bool *reparse);
+ struct cifs_sid *group);
int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out);
int posix_info_sid_size(const void *beg, const void *end);
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 7676091b3e77..23c50ed7d4b5 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -86,7 +86,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
spin_lock(&cifs_tcp_ses_lock);
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
if (ses->Suid == ses_id)
@@ -149,7 +149,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
struct cifs_ses *ses;
/* If server is a channel, select the primary channel */
- pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
+ pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
if (ses->Suid != ses_id)
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index f280502a2aee..1b5d9794ed5b 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -416,13 +416,19 @@ out:
return rc;
}
+struct send_req_vars {
+ struct smb2_transform_hdr tr_hdr;
+ struct smb_rqst rqst[MAX_COMPOUND];
+ struct kvec iov;
+};
+
static int
smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst, int flags)
{
- struct kvec iov;
- struct smb2_transform_hdr *tr_hdr;
- struct smb_rqst cur_rqst[MAX_COMPOUND];
+ struct send_req_vars *vars;
+ struct smb_rqst *cur_rqst;
+ struct kvec *iov;
int rc;
if (!(flags & CIFS_TRANSFORM_REQ))
@@ -436,16 +442,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
return -EIO;
}
- tr_hdr = kzalloc(sizeof(*tr_hdr), GFP_NOFS);
- if (!tr_hdr)
+ vars = kzalloc(sizeof(*vars), GFP_NOFS);
+ if (!vars)
return -ENOMEM;
+ cur_rqst = vars->rqst;
+ iov = &vars->iov;
- memset(&cur_rqst[0], 0, sizeof(cur_rqst));
- memset(&iov, 0, sizeof(iov));
-
- iov.iov_base = tr_hdr;
- iov.iov_len = sizeof(*tr_hdr);
- cur_rqst[0].rq_iov = &iov;
+ iov->iov_base = &vars->tr_hdr;
+ iov->iov_len = sizeof(vars->tr_hdr);
+ cur_rqst[0].rq_iov = iov;
cur_rqst[0].rq_nvec = 1;
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,
rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
out:
- kfree(tr_hdr);
+ kfree(vars);
return rc;
}
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index bae590eec871..2680251b9aac 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -153,6 +153,28 @@ struct smb2_hdr {
__u8 Signature[16];
} __packed;
+struct smb3_hdr_req {
+ __le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
+ __le16 StructureSize; /* 64 */
+ __le16 CreditCharge; /* MBZ */
+ __le16 ChannelSequence; /* See MS-SMB2 3.2.4.1 and 3.2.7.1 */
+ __le16 Reserved;
+ __le16 Command;
+ __le16 CreditRequest; /* CreditResponse */
+ __le32 Flags;
+ __le32 NextCommand;
+ __le64 MessageId;
+ union {
+ struct {
+ __le32 ProcessId;
+ __le32 TreeId;
+ } __packed SyncId;
+ __le64 AsyncId;
+ } __packed Id;
+ __le64 SessionId;
+ __u8 Signature[16];
+} __packed;
+
struct smb2_pdu {
struct smb2_hdr hdr;
__le16 StructureSize2; /* size of wct area (varies, request specific) */
diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig
index 7055cb5d2880..793151ddd60e 100644
--- a/fs/smb/server/Kconfig
+++ b/fs/smb/server/Kconfig
@@ -5,6 +5,7 @@ config SMB_SERVER
depends on FILE_LOCKING
select NLS
select NLS_UTF8
+ select NLS_UCS2_UTILS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_HMAC
diff --git a/fs/smb/server/unicode.c b/fs/smb/server/unicode.c
index 9ae676906ed3..393dd4a7432b 100644
--- a/fs/smb/server/unicode.c
+++ b/fs/smb/server/unicode.c
@@ -11,7 +11,6 @@
#include <asm/unaligned.h>
#include "glob.h"
#include "unicode.h"
-#include "uniupr.h"
#include "smb_common.h"
/*
diff --git a/fs/smb/server/unicode.h b/fs/smb/server/unicode.h
index 076f6034a789..28c7c736f7bb 100644
--- a/fs/smb/server/unicode.h
+++ b/fs/smb/server/unicode.h
@@ -18,49 +18,14 @@
* This is a compressed table of upper and lower case conversion.
*
*/
-#ifndef _CIFS_UNICODE_H
-#define _CIFS_UNICODE_H
+#ifndef _SMB_UNICODE_H
+#define _SMB_UNICODE_H
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/nls.h>
#include <linux/unicode.h>
-
-#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
-
-/*
- * Windows maps these to the user defined 16 bit Unicode range since they are
- * reserved symbols (along with \ and /), otherwise illegal to store
- * in filenames in NTFS
- */
-#define UNI_ASTERISK ((__u16)('*' + 0xF000))
-#define UNI_QUESTION ((__u16)('?' + 0xF000))
-#define UNI_COLON ((__u16)(':' + 0xF000))
-#define UNI_GRTRTHAN ((__u16)('>' + 0xF000))
-#define UNI_LESSTHAN ((__u16)('<' + 0xF000))
-#define UNI_PIPE ((__u16)('|' + 0xF000))
-#define UNI_SLASH ((__u16)('\\' + 0xF000))
-
-/* Just define what we want from uniupr.h. We don't want to define the tables
- * in each source file.
- */
-#ifndef UNICASERANGE_DEFINED
-struct UniCaseRange {
- wchar_t start;
- wchar_t end;
- signed char *table;
-};
-#endif /* UNICASERANGE_DEFINED */
-
-#ifndef UNIUPR_NOUPPER
-extern signed char SmbUniUpperTable[512];
-extern const struct UniCaseRange SmbUniUpperRange[];
-#endif /* UNIUPR_NOUPPER */
-
-#ifndef UNIUPR_NOLOWER
-extern signed char CifsUniLowerTable[512];
-extern const struct UniCaseRange CifsUniLowerRange[];
-#endif /* UNIUPR_NOLOWER */
+#include "../../nls/nls_ucs2_utils.h"
#ifdef __KERNEL__
int smb_strtoUTF16(__le16 *to, const char *from, int len,
@@ -73,286 +38,4 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
#endif
-/*
- * UniStrcat: Concatenate the second string to the first
- *
- * Returns:
- * Address of the first string
- */
-static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
-{
- wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
-
- while (*ucs1++)
- /*NULL*/; /* To end of first string */
- ucs1--; /* Return to the null */
- while ((*ucs1++ = *ucs2++))
- /*NULL*/; /* copy string 2 over */
- return anchor;
-}
-
-/*
- * UniStrchr: Find a character in a string
- *
- * Returns:
- * Address of first occurrence of character in string
- * or NULL if the character is not in the string
- */
-static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
-{
- while ((*ucs != uc) && *ucs)
- ucs++;
-
- if (*ucs == uc)
- return (wchar_t *)ucs;
- return NULL;
-}
-
-/*
- * UniStrcmp: Compare two strings
- *
- * Returns:
- * < 0: First string is less than second
- * = 0: Strings are equal
- * > 0: First string is greater than second
- */
-static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
-{
- while ((*ucs1 == *ucs2) && *ucs1) {
- ucs1++;
- ucs2++;
- }
- return (int)*ucs1 - (int)*ucs2;
-}
-
-/*
- * UniStrcpy: Copy a string
- */
-static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
-{
- wchar_t *anchor = ucs1; /* save the start of result string */
-
- while ((*ucs1++ = *ucs2++))
- /*NULL*/;
- return anchor;
-}
-
-/*
- * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
- */
-static inline size_t UniStrlen(const wchar_t *ucs1)
-{
- int i = 0;
-
- while (*ucs1++)
- i++;
- return i;
-}
-
-/*
- * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
- * string (length limited)
- */
-static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
-{
- int i = 0;
-
- while (*ucs1++) {
- i++;
- if (i >= maxlen)
- break;
- }
- return i;
-}
-
-/*
- * UniStrncat: Concatenate length limited string
- */
-static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- wchar_t *anchor = ucs1; /* save pointer to string 1 */
-
- while (*ucs1++)
- /*NULL*/;
- ucs1--; /* point to null terminator of s1 */
- while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
- ucs1++;
- ucs2++;
- }
- *ucs1 = 0; /* Null terminate the result */
- return anchor;
-}
-
-/*
- * UniStrncmp: Compare length limited string
- */
-static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- if (!n)
- return 0; /* Null strings are equal */
- while ((*ucs1 == *ucs2) && *ucs1 && --n) {
- ucs1++;
- ucs2++;
- }
- return (int)*ucs1 - (int)*ucs2;
-}
-
-/*
- * UniStrncmp_le: Compare length limited string - native to little-endian
- */
-static inline int
-UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- if (!n)
- return 0; /* Null strings are equal */
- while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
- ucs1++;
- ucs2++;
- }
- return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
-}
-
-/*
- * UniStrncpy: Copy length limited string with pad
- */
-static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- wchar_t *anchor = ucs1;
-
- while (n-- && *ucs2) /* Copy the strings */
- *ucs1++ = *ucs2++;
-
- n++;
- while (n--) /* Pad with nulls */
- *ucs1++ = 0;
- return anchor;
-}
-
-/*
- * UniStrncpy_le: Copy length limited string with pad to little-endian
- */
-static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
- wchar_t *anchor = ucs1;
-
- while (n-- && *ucs2) /* Copy the strings */
- *ucs1++ = __le16_to_cpu(*ucs2++);
-
- n++;
- while (n--) /* Pad with nulls */
- *ucs1++ = 0;
- return anchor;
-}
-
-/*
- * UniStrstr: Find a string in a string
- *
- * Returns:
- * Address of first match found
- * NULL if no matching string is found
- */
-static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
-{
- const wchar_t *anchor1 = ucs1;
- const wchar_t *anchor2 = ucs2;
-
- while (*ucs1) {
- if (*ucs1 == *ucs2) {
- /* Partial match found */
- ucs1++;
- ucs2++;
- } else {
- if (!*ucs2) /* Match found */
- return (wchar_t *)anchor1;
- ucs1 = ++anchor1; /* No match */
- ucs2 = anchor2;
- }
- }
-
- if (!*ucs2) /* Both end together */
- return (wchar_t *)anchor1; /* Match found */
- return NULL; /* No match */
-}
-
-#ifndef UNIUPR_NOUPPER
-/*
- * UniToupper: Convert a unicode character to upper case
- */
-static inline wchar_t UniToupper(register wchar_t uc)
-{
- register const struct UniCaseRange *rp;
-
- if (uc < sizeof(SmbUniUpperTable)) {
- /* Latin characters */
- return uc + SmbUniUpperTable[uc]; /* Use base tables */
- }
-
- rp = SmbUniUpperRange; /* Use range tables */
- while (rp->start) {
- if (uc < rp->start) /* Before start of range */
- return uc; /* Uppercase = input */
- if (uc <= rp->end) /* In range */
- return uc + rp->table[uc - rp->start];
- rp++; /* Try next range */
- }
- return uc; /* Past last range */
-}
-
-/*
- * UniStrupr: Upper case a unicode string
- */
-static inline __le16 *UniStrupr(register __le16 *upin)
-{
- register __le16 *up;
-
- up = upin;
- while (*up) { /* For all characters */
- *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
- up++;
- }
- return upin; /* Return input pointer */
-}
-#endif /* UNIUPR_NOUPPER */
-
-#ifndef UNIUPR_NOLOWER
-/*
- * UniTolower: Convert a unicode character to lower case
- */
-static inline wchar_t UniTolower(register wchar_t uc)
-{
- register const struct UniCaseRange *rp;
-
- if (uc < sizeof(CifsUniLowerTable)) {
- /* Latin characters */
- return uc + CifsUniLowerTable[uc]; /* Use base tables */
- }
-
- rp = CifsUniLowerRange; /* Use range tables */
- while (rp->start) {
- if (uc < rp->start) /* Before start of range */
- return uc; /* Uppercase = input */
- if (uc <= rp->end) /* In range */
- return uc + rp->table[uc - rp->start];
- rp++; /* Try next range */
- }
- return uc; /* Past last range */
-}
-
-/*
- * UniStrlwr: Lower case a unicode string
- */
-static inline wchar_t *UniStrlwr(register wchar_t *upin)
-{
- register wchar_t *up;
-
- up = upin;
- while (*up) { /* For all characters */
- *up = UniTolower(*up);
- up++;
- }
- return upin; /* Return input pointer */
-}
-
-#endif
-
-#endif /* _CIFS_UNICODE_H */
+#endif /* _SMB_UNICODE_H */