summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-18 16:39:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-18 16:39:19 -0400
commit9272f2dc3956c6b6c4335de51bc897fa3b981584 (patch)
tree0fed79884531f07bbc3abeca876d3a8b60f653b3 /fs
parente83e43237236ba89316e97a3743b5bd585726e47 (diff)
parentff273cb879fbc6cd3c5d03a56cfc33f5830e2837 (diff)
Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs/smb3 updates from Steve French: "Improved SMB3 support (symlink and device emulation, and remapping by default the 7 reserved posix characters) and a workaround for cifs mounts to Mac (working around a commonly encountered Mac server bug)" * 'for-linus' of git://git.samba.org/sfrench/cifs-2.6: [CIFS] Remove obsolete comment Check minimum response length on query_network_interface Workaround Mac server problem Remap reserved posix characters by default (part 3/3) Allow conversion of characters in Mac remap range (part 2) Allow conversion of characters in Mac remap range. Part 1 mfsymlinks support for SMB2.1/SMB3. Part 2 query symlink Add mfsymlinks support for SMB2.1/SMB3. Part 1 create symlink Allow mknod and mkfifo on SMB2/SMB3 mounts add defines for two new file attributes
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/cifs_unicode.c203
-rw-r--r--fs/cifs/cifs_unicode.h31
-rw-r--r--fs/cifs/cifsencrypt.c2
-rw-r--r--fs/cifs/cifsglob.h6
-rw-r--r--fs/cifs/cifssmb.c16
-rw-r--r--fs/cifs/connect.c46
-rw-r--r--fs/cifs/dir.c22
-rw-r--r--fs/cifs/file.c6
-rw-r--r--fs/cifs/inode.c57
-rw-r--r--fs/cifs/link.c145
-rw-r--r--fs/cifs/readdir.c8
-rw-r--r--fs/cifs/smb1ops.c33
-rw-r--r--fs/cifs/smb2misc.c12
-rw-r--r--fs/cifs/smb2ops.c27
-rw-r--r--fs/cifs/smb2pdu.c2
-rw-r--r--fs/cifs/smb2pdu.h2
-rw-r--r--fs/cifs/smb2proto.h8
-rw-r--r--fs/cifs/smbencrypt.c1
-rw-r--r--fs/cifs/xattr.c32
20 files changed, 489 insertions, 171 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 9409fa10bd5c..3182273a3407 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -45,6 +45,7 @@
45#define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */ 45#define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */
46#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */ 46#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
47#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */ 47#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
48#define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */
48 49
49struct cifs_sb_info { 50struct cifs_sb_info {
50 struct rb_root tlink_tree; 51 struct rb_root tlink_tree;
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 15e9505aa35f..0303c6793d90 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#include <linux/fs.h> 21#include <linux/fs.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include "cifs_fs_sb.h"
23#include "cifs_unicode.h" 24#include "cifs_unicode.h"
24#include "cifs_uniupr.h" 25#include "cifs_uniupr.h"
25#include "cifspdu.h" 26#include "cifspdu.h"
@@ -61,26 +62,24 @@ cifs_utf16_bytes(const __le16 *from, int maxbytes,
61 return outlen; 62 return outlen;
62} 63}
63 64
64/* 65int cifs_remap(struct cifs_sb_info *cifs_sb)
65 * cifs_mapchar - convert a host-endian char to proper char in codepage
66 * @target - where converted character should be copied
67 * @src_char - 2 byte host-endian source character
68 * @cp - codepage to which character should be converted
69 * @mapchar - should character be mapped according to mapchars mount option?
70 *
71 * This function handles the conversion of a single character. It is the
72 * responsibility of the caller to ensure that the target buffer is large
73 * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
74 */
75static int
76cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
77 bool mapchar)
78{ 66{
79 int len = 1; 67 int map_type;
68
69 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
70 map_type = SFM_MAP_UNI_RSVD;
71 else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
72 map_type = SFU_MAP_UNI_RSVD;
73 else
74 map_type = NO_MAP_UNI_RSVD;
80 75
81 if (!mapchar) 76 return map_type;
82 goto cp_convert; 77}
83 78
79/* Convert character using the SFU - "Services for Unix" remapping range */
80static bool
81convert_sfu_char(const __u16 src_char, char *target)
82{
84 /* 83 /*
85 * BB: Cannot handle remapping UNI_SLASH until all the calls to 84 * BB: Cannot handle remapping UNI_SLASH until all the calls to
86 * build_path_from_dentry are modified, as they use slash as 85 * build_path_from_dentry are modified, as they use slash as
@@ -106,19 +105,74 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
106 *target = '<'; 105 *target = '<';
107 break; 106 break;
108 default: 107 default:
109 goto cp_convert; 108 return false;
110 } 109 }
110 return true;
111}
112
113/* Convert character using the SFM - "Services for Mac" remapping range */
114static bool
115convert_sfm_char(const __u16 src_char, char *target)
116{
117 switch (src_char) {
118 case SFM_COLON:
119 *target = ':';
120 break;
121 case SFM_ASTERISK:
122 *target = '*';
123 break;
124 case SFM_QUESTION:
125 *target = '?';
126 break;
127 case SFM_PIPE:
128 *target = '|';
129 break;
130 case SFM_GRTRTHAN:
131 *target = '>';
132 break;
133 case SFM_LESSTHAN:
134 *target = '<';
135 break;
136 case SFM_SLASH:
137 *target = '\\';
138 break;
139 default:
140 return false;
141 }
142 return true;
143}
111 144
112out:
113 return len;
114 145
115cp_convert: 146/*
147 * cifs_mapchar - convert a host-endian char to proper char in codepage
148 * @target - where converted character should be copied
149 * @src_char - 2 byte host-endian source character
150 * @cp - codepage to which character should be converted
151 * @map_type - How should the 7 NTFS/SMB reserved characters be mapped to UCS2?
152 *
153 * This function handles the conversion of a single character. It is the
154 * responsibility of the caller to ensure that the target buffer is large
155 * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
156 */
157static int
158cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
159 int maptype)
160{
161 int len = 1;
162
163 if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target))
164 return len;
165 else if ((maptype == SFU_MAP_UNI_RSVD) &&
166 convert_sfu_char(src_char, target))
167 return len;
168
169 /* if character not one of seven in special remap set */
116 len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); 170 len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
117 if (len <= 0) { 171 if (len <= 0) {
118 *target = '?'; 172 *target = '?';
119 len = 1; 173 len = 1;
120 } 174 }
121 goto out; 175 return len;
122} 176}
123 177
124/* 178/*
@@ -145,7 +199,7 @@ cp_convert:
145 */ 199 */
146int 200int
147cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, 201cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
148 const struct nls_table *codepage, bool mapchar) 202 const struct nls_table *codepage, int map_type)
149{ 203{
150 int i, charlen, safelen; 204 int i, charlen, safelen;
151 int outlen = 0; 205 int outlen = 0;
@@ -172,13 +226,13 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
172 * conversion bleed into the null terminator 226 * conversion bleed into the null terminator
173 */ 227 */
174 if (outlen >= safelen) { 228 if (outlen >= safelen) {
175 charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar); 229 charlen = cifs_mapchar(tmp, ftmp, codepage, map_type);
176 if ((outlen + charlen) > (tolen - nullsize)) 230 if ((outlen + charlen) > (tolen - nullsize))
177 break; 231 break;
178 } 232 }
179 233
180 /* put converted char into 'to' buffer */ 234 /* put converted char into 'to' buffer */
181 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); 235 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type);
182 outlen += charlen; 236 outlen += charlen;
183 } 237 }
184 238
@@ -267,7 +321,7 @@ cifs_strndup_from_utf16(const char *src, const int maxlen,
267 if (!dst) 321 if (!dst)
268 return NULL; 322 return NULL;
269 cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage, 323 cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage,
270 false); 324 NO_MAP_UNI_RSVD);
271 } else { 325 } else {
272 len = strnlen(src, maxlen); 326 len = strnlen(src, maxlen);
273 len++; 327 len++;
@@ -280,6 +334,66 @@ cifs_strndup_from_utf16(const char *src, const int maxlen,
280 return dst; 334 return dst;
281} 335}
282 336
337static __le16 convert_to_sfu_char(char src_char)
338{
339 __le16 dest_char;
340
341 switch (src_char) {
342 case ':':
343 dest_char = cpu_to_le16(UNI_COLON);
344 break;
345 case '*':
346 dest_char = cpu_to_le16(UNI_ASTERISK);
347 break;
348 case '?':
349 dest_char = cpu_to_le16(UNI_QUESTION);
350 break;
351 case '<':
352 dest_char = cpu_to_le16(UNI_LESSTHAN);
353 break;
354 case '>':
355 dest_char = cpu_to_le16(UNI_GRTRTHAN);
356 break;
357 case '|':
358 dest_char = cpu_to_le16(UNI_PIPE);
359 break;
360 default:
361 dest_char = 0;
362 }
363
364 return dest_char;
365}
366
367static __le16 convert_to_sfm_char(char src_char)
368{
369 __le16 dest_char;
370
371 switch (src_char) {
372 case ':':
373 dest_char = cpu_to_le16(SFM_COLON);
374 break;
375 case '*':
376 dest_char = cpu_to_le16(SFM_ASTERISK);
377 break;
378 case '?':
379 dest_char = cpu_to_le16(SFM_QUESTION);
380 break;
381 case '<':
382 dest_char = cpu_to_le16(SFM_LESSTHAN);
383 break;
384 case '>':
385 dest_char = cpu_to_le16(SFM_GRTRTHAN);
386 break;
387 case '|':
388 dest_char = cpu_to_le16(SFM_PIPE);
389 break;
390 default:
391 dest_char = 0;
392 }
393
394 return dest_char;
395}
396
283/* 397/*
284 * Convert 16 bit Unicode pathname to wire format from string in current code 398 * Convert 16 bit Unicode pathname to wire format from string in current code
285 * page. Conversion may involve remapping up the six characters that are 399 * page. Conversion may involve remapping up the six characters that are
@@ -288,7 +402,7 @@ cifs_strndup_from_utf16(const char *src, const int maxlen,
288 */ 402 */
289int 403int
290cifsConvertToUTF16(__le16 *target, const char *source, int srclen, 404cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
291 const struct nls_table *cp, int mapChars) 405 const struct nls_table *cp, int map_chars)
292{ 406{
293 int i, charlen; 407 int i, charlen;
294 int j = 0; 408 int j = 0;
@@ -296,39 +410,30 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
296 __le16 dst_char; 410 __le16 dst_char;
297 wchar_t tmp; 411 wchar_t tmp;
298 412
299 if (!mapChars) 413 if (map_chars == NO_MAP_UNI_RSVD)
300 return cifs_strtoUTF16(target, source, PATH_MAX, cp); 414 return cifs_strtoUTF16(target, source, PATH_MAX, cp);
301 415
302 for (i = 0; i < srclen; j++) { 416 for (i = 0; i < srclen; j++) {
303 src_char = source[i]; 417 src_char = source[i];
304 charlen = 1; 418 charlen = 1;
305 switch (src_char) { 419
306 case 0: 420 /* check if end of string */
421 if (src_char == 0)
307 goto ctoUTF16_out; 422 goto ctoUTF16_out;
308 case ':': 423
309 dst_char = cpu_to_le16(UNI_COLON); 424 /* see if we must remap this char */
310 break; 425 if (map_chars == SFU_MAP_UNI_RSVD)
311 case '*': 426 dst_char = convert_to_sfu_char(src_char);
312 dst_char = cpu_to_le16(UNI_ASTERISK); 427 else if (map_chars == SFM_MAP_UNI_RSVD)
313 break; 428 dst_char = convert_to_sfm_char(src_char);
314 case '?': 429 else
315 dst_char = cpu_to_le16(UNI_QUESTION); 430 dst_char = 0;
316 break;
317 case '<':
318 dst_char = cpu_to_le16(UNI_LESSTHAN);
319 break;
320 case '>':
321 dst_char = cpu_to_le16(UNI_GRTRTHAN);
322 break;
323 case '|':
324 dst_char = cpu_to_le16(UNI_PIPE);
325 break;
326 /* 431 /*
327 * FIXME: We can not handle remapping backslash (UNI_SLASH) 432 * FIXME: We can not handle remapping backslash (UNI_SLASH)
328 * until all the calls to build_path_from_dentry are modified, 433 * until all the calls to build_path_from_dentry are modified,
329 * as they use backslash as separator. 434 * as they use backslash as separator.
330 */ 435 */
331 default: 436 if (dst_char == 0) {
332 charlen = cp->char2uni(source + i, srclen - i, &tmp); 437 charlen = cp->char2uni(source + i, srclen - i, &tmp);
333 dst_char = cpu_to_le16(tmp); 438 dst_char = cpu_to_le16(tmp);
334 439
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
index d8eac3b6cefb..bdc52cb9a676 100644
--- a/fs/cifs/cifs_unicode.h
+++ b/fs/cifs/cifs_unicode.h
@@ -52,6 +52,34 @@
52#define UNI_PIPE (__u16) ('|' + 0xF000) 52#define UNI_PIPE (__u16) ('|' + 0xF000)
53#define UNI_SLASH (__u16) ('\\' + 0xF000) 53#define UNI_SLASH (__u16) ('\\' + 0xF000)
54 54
55/*
56 * Macs use an older "SFM" mapping of the symbols above. Fortunately it does
57 * not conflict (although almost does) with the mapping above.
58 */
59
60#define SFM_ASTERISK ((__u16) 0xF021)
61#define SFM_QUESTION ((__u16) 0xF025)
62#define SFM_COLON ((__u16) 0xF022)
63#define SFM_GRTRTHAN ((__u16) 0xF024)
64#define SFM_LESSTHAN ((__u16) 0xF023)
65#define SFM_PIPE ((__u16) 0xF027)
66#define SFM_SLASH ((__u16) 0xF026)
67
68/*
69 * Mapping mechanism to use when one of the seven reserved characters is
70 * encountered. We can only map using one of the mechanisms at a time
71 * since otherwise readdir could return directory entries which we would
72 * not be able to open
73 *
74 * NO_MAP_UNI_RSVD = do not perform any remapping of the character
75 * SFM_MAP_UNI_RSVD = map reserved characters using SFM scheme (MAC compatible)
76 * SFU_MAP_UNI_RSVD = map reserved characters ala SFU ("mapchars" option)
77 *
78 */
79#define NO_MAP_UNI_RSVD 0
80#define SFM_MAP_UNI_RSVD 1
81#define SFU_MAP_UNI_RSVD 2
82
55/* Just define what we want from uniupr.h. We don't want to define the tables 83/* Just define what we want from uniupr.h. We don't want to define the tables
56 * in each source file. 84 * in each source file.
57 */ 85 */
@@ -75,7 +103,7 @@ extern const struct UniCaseRange CifsUniLowerRange[];
75 103
76#ifdef __KERNEL__ 104#ifdef __KERNEL__
77int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, 105int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
78 const struct nls_table *codepage, bool mapchar); 106 const struct nls_table *cp, int map_type);
79int cifs_utf16_bytes(const __le16 *from, int maxbytes, 107int cifs_utf16_bytes(const __le16 *from, int maxbytes,
80 const struct nls_table *codepage); 108 const struct nls_table *codepage);
81int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *); 109int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *);
@@ -84,6 +112,7 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen,
84 const struct nls_table *codepage); 112 const struct nls_table *codepage);
85extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen, 113extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen,
86 const struct nls_table *cp, int mapChars); 114 const struct nls_table *cp, int mapChars);
115extern int cifs_remap(struct cifs_sb_info *cifs_sb);
87#ifdef CONFIG_CIFS_SMB2 116#ifdef CONFIG_CIFS_SMB2
88extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen, 117extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
89 int *utf16_len, const struct nls_table *cp, 118 int *utf16_len, const struct nls_table *cp,
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 4934347321d3..4ac7445e6ec7 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -431,7 +431,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
431 return -ENOMEM; 431 return -ENOMEM;
432 cifs_from_utf16(ses->domainName, 432 cifs_from_utf16(ses->domainName,
433 (__le16 *)blobptr, attrsize, attrsize, 433 (__le16 *)blobptr, attrsize, attrsize,
434 nls_cp, false); 434 nls_cp, NO_MAP_UNI_RSVD);
435 break; 435 break;
436 } 436 }
437 } 437 }
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 25b8392bfdd2..02a33e529904 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -323,11 +323,11 @@ struct smb_version_operations {
323 int (*async_writev)(struct cifs_writedata *, 323 int (*async_writev)(struct cifs_writedata *,
324 void (*release)(struct kref *)); 324 void (*release)(struct kref *));
325 /* sync read from the server */ 325 /* sync read from the server */
326 int (*sync_read)(const unsigned int, struct cifsFileInfo *, 326 int (*sync_read)(const unsigned int, struct cifs_fid *,
327 struct cifs_io_parms *, unsigned int *, char **, 327 struct cifs_io_parms *, unsigned int *, char **,
328 int *); 328 int *);
329 /* sync write to the server */ 329 /* sync write to the server */
330 int (*sync_write)(const unsigned int, struct cifsFileInfo *, 330 int (*sync_write)(const unsigned int, struct cifs_fid *,
331 struct cifs_io_parms *, unsigned int *, struct kvec *, 331 struct cifs_io_parms *, unsigned int *, struct kvec *,
332 unsigned long); 332 unsigned long);
333 /* open dir, start readdir */ 333 /* open dir, start readdir */
@@ -466,6 +466,7 @@ struct smb_vol {
466 bool direct_io:1; 466 bool direct_io:1;
467 bool strict_io:1; /* strict cache behavior */ 467 bool strict_io:1; /* strict cache behavior */
468 bool remap:1; /* set to remap seven reserved chars in filenames */ 468 bool remap:1; /* set to remap seven reserved chars in filenames */
469 bool sfu_remap:1; /* remap seven reserved chars ala SFU */
469 bool posix_paths:1; /* unset to not ask for posix pathnames. */ 470 bool posix_paths:1; /* unset to not ask for posix pathnames. */
470 bool no_linux_ext:1; 471 bool no_linux_ext:1;
471 bool sfu_emul:1; 472 bool sfu_emul:1;
@@ -499,6 +500,7 @@ struct smb_vol {
499#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \ 500#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
500 CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \ 501 CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \
501 CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \ 502 CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \
503 CIFS_MOUNT_MAP_SFM_CHR | \
502 CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \ 504 CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \
503 CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \ 505 CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \
504 CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \ 506 CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 66f65001a6d8..61d00a6e398f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -867,7 +867,7 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
867 int rc = 0; 867 int rc = 0;
868 int bytes_returned; 868 int bytes_returned;
869 int name_len; 869 int name_len;
870 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 870 int remap = cifs_remap(cifs_sb);
871 871
872DelFileRetry: 872DelFileRetry:
873 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, 873 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -913,7 +913,7 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
913 int rc = 0; 913 int rc = 0;
914 int bytes_returned; 914 int bytes_returned;
915 int name_len; 915 int name_len;
916 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 916 int remap = cifs_remap(cifs_sb);
917 917
918 cifs_dbg(FYI, "In CIFSSMBRmDir\n"); 918 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
919RmDirRetry: 919RmDirRetry:
@@ -958,7 +958,7 @@ CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
958 CREATE_DIRECTORY_RSP *pSMBr = NULL; 958 CREATE_DIRECTORY_RSP *pSMBr = NULL;
959 int bytes_returned; 959 int bytes_returned;
960 int name_len; 960 int name_len;
961 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 961 int remap = cifs_remap(cifs_sb);
962 962
963 cifs_dbg(FYI, "In CIFSSMBMkDir\n"); 963 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
964MkDirRetry: 964MkDirRetry:
@@ -1280,7 +1280,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1280 __u16 count; 1280 __u16 count;
1281 struct cifs_sb_info *cifs_sb = oparms->cifs_sb; 1281 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1282 struct cifs_tcon *tcon = oparms->tcon; 1282 struct cifs_tcon *tcon = oparms->tcon;
1283 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 1283 int remap = cifs_remap(cifs_sb);
1284 const struct nls_table *nls = cifs_sb->local_nls; 1284 const struct nls_table *nls = cifs_sb->local_nls;
1285 int create_options = oparms->create_options; 1285 int create_options = oparms->create_options;
1286 int desired_access = oparms->desired_access; 1286 int desired_access = oparms->desired_access;
@@ -2572,7 +2572,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
2572 int bytes_returned; 2572 int bytes_returned;
2573 int name_len, name_len2; 2573 int name_len, name_len2;
2574 __u16 count; 2574 __u16 count;
2575 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 2575 int remap = cifs_remap(cifs_sb);
2576 2576
2577 cifs_dbg(FYI, "In CIFSSMBRename\n"); 2577 cifs_dbg(FYI, "In CIFSSMBRename\n");
2578renameRetry: 2578renameRetry:
@@ -2968,7 +2968,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
2968 int bytes_returned; 2968 int bytes_returned;
2969 int name_len, name_len2; 2969 int name_len, name_len2;
2970 __u16 count; 2970 __u16 count;
2971 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 2971 int remap = cifs_remap(cifs_sb);
2972 2972
2973 cifs_dbg(FYI, "In CIFSCreateHardLink\n"); 2973 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
2974winCreateHardLinkRetry: 2974winCreateHardLinkRetry:
@@ -4367,7 +4367,7 @@ findFirstRetry:
4367 return rc; 4367 return rc;
4368 4368
4369 nls_codepage = cifs_sb->local_nls; 4369 nls_codepage = cifs_sb->local_nls;
4370 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 4370 remap = cifs_remap(cifs_sb);
4371 4371
4372 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 4372 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4373 name_len = 4373 name_len =
@@ -5527,7 +5527,7 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5527 int name_len; 5527 int name_len;
5528 int rc = 0; 5528 int rc = 0;
5529 int bytes_returned = 0; 5529 int bytes_returned = 0;
5530 int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR; 5530 int remap = cifs_remap(cifs_sb);
5531 5531
5532 __u16 params, byte_count, data_count, param_offset, offset; 5532 __u16 params, byte_count, data_count, param_offset, offset;
5533 5533
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 239e1fb33000..24fa08d261fb 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -70,6 +70,7 @@ enum {
70 Opt_forcegid, Opt_noforcegid, 70 Opt_forcegid, Opt_noforcegid,
71 Opt_noblocksend, Opt_noautotune, 71 Opt_noblocksend, Opt_noautotune,
72 Opt_hard, Opt_soft, Opt_perm, Opt_noperm, 72 Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
73 Opt_mapposix, Opt_nomapposix,
73 Opt_mapchars, Opt_nomapchars, Opt_sfu, 74 Opt_mapchars, Opt_nomapchars, Opt_sfu,
74 Opt_nosfu, Opt_nodfs, Opt_posixpaths, 75 Opt_nosfu, Opt_nodfs, Opt_posixpaths,
75 Opt_noposixpaths, Opt_nounix, 76 Opt_noposixpaths, Opt_nounix,
@@ -124,8 +125,10 @@ static const match_table_t cifs_mount_option_tokens = {
124 { Opt_soft, "soft" }, 125 { Opt_soft, "soft" },
125 { Opt_perm, "perm" }, 126 { Opt_perm, "perm" },
126 { Opt_noperm, "noperm" }, 127 { Opt_noperm, "noperm" },
127 { Opt_mapchars, "mapchars" }, 128 { Opt_mapchars, "mapchars" }, /* SFU style */
128 { Opt_nomapchars, "nomapchars" }, 129 { Opt_nomapchars, "nomapchars" },
130 { Opt_mapposix, "mapposix" }, /* SFM style */
131 { Opt_nomapposix, "nomapposix" },
129 { Opt_sfu, "sfu" }, 132 { Opt_sfu, "sfu" },
130 { Opt_nosfu, "nosfu" }, 133 { Opt_nosfu, "nosfu" },
131 { Opt_nodfs, "nodfs" }, 134 { Opt_nodfs, "nodfs" },
@@ -1231,6 +1234,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1231 vol->linux_uid = current_uid(); 1234 vol->linux_uid = current_uid();
1232 vol->linux_gid = current_gid(); 1235 vol->linux_gid = current_gid();
1233 1236
1237 /*
1238 * default to SFM style remapping of seven reserved characters
1239 * unless user overrides it or we negotiate CIFS POSIX where
1240 * it is unnecessary. Can not simultaneously use more than one mapping
1241 * since then readdir could list files that open could not open
1242 */
1243 vol->remap = true;
1244
1234 /* default to only allowing write access to owner of the mount */ 1245 /* default to only allowing write access to owner of the mount */
1235 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; 1246 vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
1236 1247
@@ -1338,10 +1349,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1338 vol->noperm = 1; 1349 vol->noperm = 1;
1339 break; 1350 break;
1340 case Opt_mapchars: 1351 case Opt_mapchars:
1341 vol->remap = 1; 1352 vol->sfu_remap = true;
1353 vol->remap = false; /* disable SFM mapping */
1342 break; 1354 break;
1343 case Opt_nomapchars: 1355 case Opt_nomapchars:
1344 vol->remap = 0; 1356 vol->sfu_remap = false;
1357 break;
1358 case Opt_mapposix:
1359 vol->remap = true;
1360 vol->sfu_remap = false; /* disable SFU mapping */
1361 break;
1362 case Opt_nomapposix:
1363 vol->remap = false;
1345 break; 1364 break;
1346 case Opt_sfu: 1365 case Opt_sfu:
1347 vol->sfu_emul = 1; 1366 vol->sfu_emul = 1;
@@ -3197,6 +3216,8 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3197 if (pvolume_info->server_ino) 3216 if (pvolume_info->server_ino)
3198 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; 3217 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
3199 if (pvolume_info->remap) 3218 if (pvolume_info->remap)
3219 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
3220 if (pvolume_info->sfu_remap)
3200 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; 3221 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
3201 if (pvolume_info->no_xattr) 3222 if (pvolume_info->no_xattr)
3202 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; 3223 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
@@ -3239,10 +3260,20 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3239 } 3260 }
3240 if (pvolume_info->mfsymlinks) { 3261 if (pvolume_info->mfsymlinks) {
3241 if (pvolume_info->sfu_emul) { 3262 if (pvolume_info->sfu_emul) {
3242 cifs_dbg(VFS, "mount option mfsymlinks ignored if sfu mount option is used\n"); 3263 /*
3243 } else { 3264 * Our SFU ("Services for Unix" emulation does not allow
3244 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; 3265 * creating symlinks but does allow reading existing SFU
3266 * symlinks (it does allow both creating and reading SFU
3267 * style mknod and FIFOs though). When "mfsymlinks" and
3268 * "sfu" are both enabled at the same time, it allows
3269 * reading both types of symlinks, but will only create
3270 * them with mfsymlinks format. This allows better
3271 * Apple compatibility (probably better for Samba too)
3272 * while still recognizing old Windows style symlinks.
3273 */
3274 cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
3245 } 3275 }
3276 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
3246 } 3277 }
3247 3278
3248 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) 3279 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
@@ -3330,8 +3361,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
3330 ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; 3361 ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
3331 3362
3332 rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls, 3363 rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls,
3333 &num_referrals, &referrals, 3364 &num_referrals, &referrals, cifs_remap(cifs_sb));
3334 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
3335 3365
3336 if (!rc && num_referrals > 0) { 3366 if (!rc && num_referrals > 0) {
3337 char *fake_devname = NULL; 3367 char *fake_devname = NULL;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 073640675a39..b72bc29cba23 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -577,12 +577,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
577 struct cifs_io_parms io_parms; 577 struct cifs_io_parms io_parms;
578 char *full_path = NULL; 578 char *full_path = NULL;
579 struct inode *newinode = NULL; 579 struct inode *newinode = NULL;
580 int oplock = 0; 580 __u32 oplock = 0;
581 struct cifs_fid fid; 581 struct cifs_fid fid;
582 struct cifs_open_parms oparms; 582 struct cifs_open_parms oparms;
583 FILE_ALL_INFO *buf = NULL; 583 FILE_ALL_INFO *buf = NULL;
584 unsigned int bytes_written; 584 unsigned int bytes_written;
585 struct win_dev *pdev; 585 struct win_dev *pdev;
586 struct kvec iov[2];
586 587
587 if (!old_valid_dev(device_number)) 588 if (!old_valid_dev(device_number))
588 return -EINVAL; 589 return -EINVAL;
@@ -658,7 +659,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
658 oparms.fid = &fid; 659 oparms.fid = &fid;
659 oparms.reconnect = false; 660 oparms.reconnect = false;
660 661
661 rc = CIFS_open(xid, &oparms, &oplock, buf); 662 if (tcon->ses->server->oplocks)
663 oplock = REQ_OPLOCK;
664 else
665 oplock = 0;
666 rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
662 if (rc) 667 if (rc)
663 goto mknod_out; 668 goto mknod_out;
664 669
@@ -668,25 +673,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
668 */ 673 */
669 674
670 pdev = (struct win_dev *)buf; 675 pdev = (struct win_dev *)buf;
671 io_parms.netfid = fid.netfid;
672 io_parms.pid = current->tgid; 676 io_parms.pid = current->tgid;
673 io_parms.tcon = tcon; 677 io_parms.tcon = tcon;
674 io_parms.offset = 0; 678 io_parms.offset = 0;
675 io_parms.length = sizeof(struct win_dev); 679 io_parms.length = sizeof(struct win_dev);
680 iov[1].iov_base = buf;
681 iov[1].iov_len = sizeof(struct win_dev);
676 if (S_ISCHR(mode)) { 682 if (S_ISCHR(mode)) {
677 memcpy(pdev->type, "IntxCHR", 8); 683 memcpy(pdev->type, "IntxCHR", 8);
678 pdev->major = cpu_to_le64(MAJOR(device_number)); 684 pdev->major = cpu_to_le64(MAJOR(device_number));
679 pdev->minor = cpu_to_le64(MINOR(device_number)); 685 pdev->minor = cpu_to_le64(MINOR(device_number));
680 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, 686 rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
681 NULL, 0); 687 &bytes_written, iov, 1);
682 } else if (S_ISBLK(mode)) { 688 } else if (S_ISBLK(mode)) {
683 memcpy(pdev->type, "IntxBLK", 8); 689 memcpy(pdev->type, "IntxBLK", 8);
684 pdev->major = cpu_to_le64(MAJOR(device_number)); 690 pdev->major = cpu_to_le64(MAJOR(device_number));
685 pdev->minor = cpu_to_le64(MINOR(device_number)); 691 pdev->minor = cpu_to_le64(MINOR(device_number));
686 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, (char *)pdev, 692 rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
687 NULL, 0); 693 &bytes_written, iov, 1);
688 } /* else if (S_ISFIFO) */ 694 } /* else if (S_ISFIFO) */
689 CIFSSMBClose(xid, tcon, fid.netfid); 695 tcon->ses->server->ops->close(xid, tcon, &fid);
690 d_drop(direntry); 696 d_drop(direntry);
691 697
692 /* FIXME: add code here to set EAs */ 698 /* FIXME: add code here to set EAs */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 8f7b40fd8f3b..3e4d00a06c44 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1687,8 +1687,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
1687 io_parms.tcon = tcon; 1687 io_parms.tcon = tcon;
1688 io_parms.offset = *offset; 1688 io_parms.offset = *offset;
1689 io_parms.length = len; 1689 io_parms.length = len;
1690 rc = server->ops->sync_write(xid, open_file, &io_parms, 1690 rc = server->ops->sync_write(xid, &open_file->fid,
1691 &bytes_written, iov, 1); 1691 &io_parms, &bytes_written, iov, 1);
1692 } 1692 }
1693 if (rc || (bytes_written == 0)) { 1693 if (rc || (bytes_written == 0)) {
1694 if (total_written) 1694 if (total_written)
@@ -3206,7 +3206,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
3206 io_parms.tcon = tcon; 3206 io_parms.tcon = tcon;
3207 io_parms.offset = *offset; 3207 io_parms.offset = *offset;
3208 io_parms.length = current_read_size; 3208 io_parms.length = current_read_size;
3209 rc = server->ops->sync_read(xid, open_file, &io_parms, 3209 rc = server->ops->sync_read(xid, &open_file->fid, &io_parms,
3210 &bytes_read, &cur_offset, 3210 &bytes_read, &cur_offset,
3211 &buf_type); 3211 &buf_type);
3212 } while (rc == -EAGAIN); 3212 } while (rc == -EAGAIN);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8fd4ee8e07ff..197cb503d528 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -30,6 +30,7 @@
30#include "cifsproto.h" 30#include "cifsproto.h"
31#include "cifs_debug.h" 31#include "cifs_debug.h"
32#include "cifs_fs_sb.h" 32#include "cifs_fs_sb.h"
33#include "cifs_unicode.h"
33#include "fscache.h" 34#include "fscache.h"
34 35
35 36
@@ -412,7 +413,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
412 struct cifs_sb_info *cifs_sb, unsigned int xid) 413 struct cifs_sb_info *cifs_sb, unsigned int xid)
413{ 414{
414 int rc; 415 int rc;
415 int oplock = 0; 416 __u32 oplock;
416 struct tcon_link *tlink; 417 struct tcon_link *tlink;
417 struct cifs_tcon *tcon; 418 struct cifs_tcon *tcon;
418 struct cifs_fid fid; 419 struct cifs_fid fid;
@@ -451,8 +452,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
451 oparms.fid = &fid; 452 oparms.fid = &fid;
452 oparms.reconnect = false; 453 oparms.reconnect = false;
453 454
454 rc = CIFS_open(xid, &oparms, &oplock, NULL); 455 if (tcon->ses->server->oplocks)
456 oplock = REQ_OPLOCK;
457 else
458 oplock = 0;
459 rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
455 if (rc) { 460 if (rc) {
461 cifs_dbg(FYI, "check sfu type of %s, open rc = %d\n", path, rc);
456 cifs_put_tlink(tlink); 462 cifs_put_tlink(tlink);
457 return rc; 463 return rc;
458 } 464 }
@@ -464,7 +470,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
464 io_parms.offset = 0; 470 io_parms.offset = 0;
465 io_parms.length = 24; 471 io_parms.length = 24;
466 472
467 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); 473 rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
474 &bytes_read, &pbuf, &buf_type);
468 if ((rc == 0) && (bytes_read >= 8)) { 475 if ((rc == 0) && (bytes_read >= 8)) {
469 if (memcmp("IntxBLK", pbuf, 8) == 0) { 476 if (memcmp("IntxBLK", pbuf, 8) == 0) {
470 cifs_dbg(FYI, "Block device\n"); 477 cifs_dbg(FYI, "Block device\n");
@@ -504,7 +511,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
504 fattr->cf_dtype = DT_REG; 511 fattr->cf_dtype = DT_REG;
505 rc = -EOPNOTSUPP; /* or some unknown SFU type */ 512 rc = -EOPNOTSUPP; /* or some unknown SFU type */
506 } 513 }
507 CIFSSMBClose(xid, tcon, fid.netfid); 514
515 tcon->ses->server->ops->close(xid, tcon, &fid);
508 cifs_put_tlink(tlink); 516 cifs_put_tlink(tlink);
509 return rc; 517 return rc;
510} 518}
@@ -539,7 +547,7 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
539 rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path, 547 rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path,
540 "SETFILEBITS", ea_value, 4 /* size of buf */, 548 "SETFILEBITS", ea_value, 4 /* size of buf */,
541 cifs_sb->local_nls, 549 cifs_sb->local_nls,
542 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 550 cifs_remap(cifs_sb));
543 cifs_put_tlink(tlink); 551 cifs_put_tlink(tlink);
544 if (rc < 0) 552 if (rc < 0)
545 return (int)rc; 553 return (int)rc;
@@ -952,11 +960,18 @@ struct inode *cifs_root_iget(struct super_block *sb)
952 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 960 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
953 961
954 xid = get_xid(); 962 xid = get_xid();
955 if (tcon->unix_ext) 963 if (tcon->unix_ext) {
956 rc = cifs_get_inode_info_unix(&inode, "", sb, xid); 964 rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
957 else 965 /* some servers mistakenly claim POSIX support */
958 rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL); 966 if (rc != -EOPNOTSUPP)
967 goto iget_no_retry;
968 cifs_dbg(VFS, "server does not support POSIX extensions");
969 tcon->unix_ext = false;
970 }
971
972 rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
959 973
974iget_no_retry:
960 if (!inode) { 975 if (!inode) {
961 inode = ERR_PTR(rc); 976 inode = ERR_PTR(rc);
962 goto out; 977 goto out;
@@ -1117,8 +1132,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
1117 /* rename the file */ 1132 /* rename the file */
1118 rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL, 1133 rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, NULL,
1119 cifs_sb->local_nls, 1134 cifs_sb->local_nls,
1120 cifs_sb->mnt_cifs_flags & 1135 cifs_remap(cifs_sb));
1121 CIFS_MOUNT_MAP_SPECIAL_CHR);
1122 if (rc != 0) { 1136 if (rc != 0) {
1123 rc = -EBUSY; 1137 rc = -EBUSY;
1124 goto undo_setattr; 1138 goto undo_setattr;
@@ -1159,8 +1173,7 @@ out:
1159 */ 1173 */
1160undo_rename: 1174undo_rename:
1161 CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name, 1175 CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, dentry->d_name.name,
1162 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 1176 cifs_sb->local_nls, cifs_remap(cifs_sb));
1163 CIFS_MOUNT_MAP_SPECIAL_CHR);
1164undo_setattr: 1177undo_setattr:
1165 if (dosattr != origattr) { 1178 if (dosattr != origattr) {
1166 info_buf->Attributes = cpu_to_le32(origattr); 1179 info_buf->Attributes = cpu_to_le32(origattr);
@@ -1226,7 +1239,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
1226 le64_to_cpu(tcon->fsUnixInfo.Capability))) { 1239 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1227 rc = CIFSPOSIXDelFile(xid, tcon, full_path, 1240 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
1228 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls, 1241 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1229 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 1242 cifs_remap(cifs_sb));
1230 cifs_dbg(FYI, "posix del rc %d\n", rc); 1243 cifs_dbg(FYI, "posix del rc %d\n", rc);
1231 if ((rc == 0) || (rc == -ENOENT)) 1244 if ((rc == 0) || (rc == -ENOENT))
1232 goto psx_del_no_retry; 1245 goto psx_del_no_retry;
@@ -1349,8 +1362,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
1349 } 1362 }
1350 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, 1363 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
1351 cifs_sb->local_nls, 1364 cifs_sb->local_nls,
1352 cifs_sb->mnt_cifs_flags & 1365 cifs_remap(cifs_sb));
1353 CIFS_MOUNT_MAP_SPECIAL_CHR);
1354 } else { 1366 } else {
1355 struct TCP_Server_Info *server = tcon->ses->server; 1367 struct TCP_Server_Info *server = tcon->ses->server;
1356 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 1368 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
@@ -1392,8 +1404,7 @@ cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
1392 mode &= ~current_umask(); 1404 mode &= ~current_umask();
1393 rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, 1405 rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
1394 NULL /* netfid */, info, &oplock, full_path, 1406 NULL /* netfid */, info, &oplock, full_path,
1395 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 1407 cifs_sb->local_nls, cifs_remap(cifs_sb));
1396 CIFS_MOUNT_MAP_SPECIAL_CHR);
1397 if (rc == -EOPNOTSUPP) 1408 if (rc == -EOPNOTSUPP)
1398 goto posix_mkdir_out; 1409 goto posix_mkdir_out;
1399 else if (rc) { 1410 else if (rc) {
@@ -1617,8 +1628,7 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
1617 if (rc == 0) { 1628 if (rc == 0) {
1618 rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid, 1629 rc = CIFSSMBRenameOpenFile(xid, tcon, fid.netfid,
1619 (const char *) to_dentry->d_name.name, 1630 (const char *) to_dentry->d_name.name,
1620 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 1631 cifs_sb->local_nls, cifs_remap(cifs_sb));
1621 CIFS_MOUNT_MAP_SPECIAL_CHR);
1622 CIFSSMBClose(xid, tcon, fid.netfid); 1632 CIFSSMBClose(xid, tcon, fid.netfid);
1623 } 1633 }
1624do_rename_exit: 1634do_rename_exit:
@@ -1694,16 +1704,14 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry,
1694 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name, 1704 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
1695 info_buf_source, 1705 info_buf_source,
1696 cifs_sb->local_nls, 1706 cifs_sb->local_nls,
1697 cifs_sb->mnt_cifs_flags & 1707 cifs_remap(cifs_sb));
1698 CIFS_MOUNT_MAP_SPECIAL_CHR);
1699 if (tmprc != 0) 1708 if (tmprc != 0)
1700 goto unlink_target; 1709 goto unlink_target;
1701 1710
1702 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name, 1711 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
1703 info_buf_target, 1712 info_buf_target,
1704 cifs_sb->local_nls, 1713 cifs_sb->local_nls,
1705 cifs_sb->mnt_cifs_flags & 1714 cifs_remap(cifs_sb));
1706 CIFS_MOUNT_MAP_SPECIAL_CHR);
1707 1715
1708 if (tmprc == 0 && (info_buf_source->UniqueId == 1716 if (tmprc == 0 && (info_buf_source->UniqueId ==
1709 info_buf_target->UniqueId)) { 1717 info_buf_target->UniqueId)) {
@@ -2068,8 +2076,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
2068 rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN, 2076 rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
2069 GENERIC_WRITE, CREATE_NOT_DIR, &netfid, 2077 GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
2070 &oplock, NULL, cifs_sb->local_nls, 2078 &oplock, NULL, cifs_sb->local_nls,
2071 cifs_sb->mnt_cifs_flags & 2079 cifs_remap(cifs_sb));
2072 CIFS_MOUNT_MAP_SPECIAL_CHR);
2073 if (rc == 0) { 2080 if (rc == 0) {
2074 unsigned int bytes_written; 2081 unsigned int bytes_written;
2075 2082
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 5657416d3483..2ec6037f61c7 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -28,6 +28,10 @@
28#include "cifsproto.h" 28#include "cifsproto.h"
29#include "cifs_debug.h" 29#include "cifs_debug.h"
30#include "cifs_fs_sb.h" 30#include "cifs_fs_sb.h"
31#include "cifs_unicode.h"
32#ifdef CONFIG_CIFS_SMB2
33#include "smb2proto.h"
34#endif
31 35
32/* 36/*
33 * M-F Symlink Functions - Begin 37 * M-F Symlink Functions - Begin
@@ -401,6 +405,134 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
401} 405}
402 406
403/* 407/*
408 * SMB 2.1/SMB3 Protocol specific functions
409 */
410#ifdef CONFIG_CIFS_SMB2
411int
412smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
413 struct cifs_sb_info *cifs_sb, const unsigned char *path,
414 char *pbuf, unsigned int *pbytes_read)
415{
416 int rc;
417 struct cifs_fid fid;
418 struct cifs_open_parms oparms;
419 struct cifs_io_parms io_parms;
420 int buf_type = CIFS_NO_BUFFER;
421 __le16 *utf16_path;
422 __u8 oplock = SMB2_OPLOCK_LEVEL_II;
423 struct smb2_file_all_info *pfile_info = NULL;
424
425 oparms.tcon = tcon;
426 oparms.cifs_sb = cifs_sb;
427 oparms.desired_access = GENERIC_READ;
428 oparms.create_options = CREATE_NOT_DIR;
429 if (backup_cred(cifs_sb))
430 oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
431 oparms.disposition = FILE_OPEN;
432 oparms.fid = &fid;
433 oparms.reconnect = false;
434
435 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
436 if (utf16_path == NULL)
437 return -ENOMEM;
438
439 pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
440 GFP_KERNEL);
441
442 if (pfile_info == NULL) {
443 kfree(utf16_path);
444 return -ENOMEM;
445 }
446
447 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
448 if (rc)
449 goto qmf_out_open_fail;
450
451 if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
452 /* it's not a symlink */
453 rc = -ENOENT; /* Is there a better rc to return? */
454 goto qmf_out;
455 }
456
457 io_parms.netfid = fid.netfid;
458 io_parms.pid = current->tgid;
459 io_parms.tcon = tcon;
460 io_parms.offset = 0;
461 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
462 io_parms.persistent_fid = fid.persistent_fid;
463 io_parms.volatile_fid = fid.volatile_fid;
464 rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
465qmf_out:
466 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
467qmf_out_open_fail:
468 kfree(utf16_path);
469 kfree(pfile_info);
470 return rc;
471}
472
473int
474smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
475 struct cifs_sb_info *cifs_sb, const unsigned char *path,
476 char *pbuf, unsigned int *pbytes_written)
477{
478 int rc;
479 struct cifs_fid fid;
480 struct cifs_open_parms oparms;
481 struct cifs_io_parms io_parms;
482 int create_options = CREATE_NOT_DIR;
483 __le16 *utf16_path;
484 __u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
485 struct kvec iov[2];
486
487 if (backup_cred(cifs_sb))
488 create_options |= CREATE_OPEN_BACKUP_INTENT;
489
490 cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
491
492 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
493 if (!utf16_path)
494 return -ENOMEM;
495
496 oparms.tcon = tcon;
497 oparms.cifs_sb = cifs_sb;
498 oparms.desired_access = GENERIC_WRITE;
499 oparms.create_options = create_options;
500 oparms.disposition = FILE_CREATE;
501 oparms.fid = &fid;
502 oparms.reconnect = false;
503
504 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
505 if (rc) {
506 kfree(utf16_path);
507 return rc;
508 }
509
510 io_parms.netfid = fid.netfid;
511 io_parms.pid = current->tgid;
512 io_parms.tcon = tcon;
513 io_parms.offset = 0;
514 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
515 io_parms.persistent_fid = fid.persistent_fid;
516 io_parms.volatile_fid = fid.volatile_fid;
517
518 /* iov[0] is reserved for smb header */
519 iov[1].iov_base = pbuf;
520 iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
521
522 rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
523
524 /* Make sure we wrote all of the symlink data */
525 if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
526 rc = -EIO;
527
528 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
529
530 kfree(utf16_path);
531 return rc;
532}
533#endif /* CONFIG_CIFS_SMB2 */
534
535/*
404 * M-F Symlink Functions - End 536 * M-F Symlink Functions - End
405 */ 537 */
406 538
@@ -435,8 +567,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
435 if (tcon->unix_ext) 567 if (tcon->unix_ext)
436 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name, 568 rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
437 cifs_sb->local_nls, 569 cifs_sb->local_nls,
438 cifs_sb->mnt_cifs_flags & 570 cifs_remap(cifs_sb));
439 CIFS_MOUNT_MAP_SPECIAL_CHR);
440 else { 571 else {
441 server = tcon->ses->server; 572 server = tcon->ses->server;
442 if (!server->ops->create_hardlink) { 573 if (!server->ops->create_hardlink) {
@@ -461,11 +592,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
461 spin_lock(&old_file->d_inode->i_lock); 592 spin_lock(&old_file->d_inode->i_lock);
462 inc_nlink(old_file->d_inode); 593 inc_nlink(old_file->d_inode);
463 spin_unlock(&old_file->d_inode->i_lock); 594 spin_unlock(&old_file->d_inode->i_lock);
464 /* 595
465 * BB should we make this contingent on superblock flag
466 * NOATIME?
467 */
468 /* old_file->d_inode->i_ctime = CURRENT_TIME; */
469 /* 596 /*
470 * parent dir timestamps will update from srv within a 597 * parent dir timestamps will update from srv within a
471 * second, would it really be worth it to set the parent 598 * second, would it really be worth it to set the parent
@@ -475,7 +602,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
475 } 602 }
476 /* 603 /*
477 * if not oplocked will force revalidate to get info on source 604 * if not oplocked will force revalidate to get info on source
478 * file from srv 605 * file from srv. Note Samba server prior to 4.2 has bug -
606 * not updating src file ctime on hardlinks but Windows servers
607 * handle it properly
479 */ 608 */
480 cifsInode->time = 0; 609 cifsInode->time = 0;
481 610
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index d2141f101382..8fd2a95860ba 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -239,7 +239,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
239 rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, 239 rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
240 OPEN_REPARSE_POINT, &fid, &oplock, NULL, 240 OPEN_REPARSE_POINT, &fid, &oplock, NULL,
241 cifs_sb->local_nls, 241 cifs_sb->local_nls,
242 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 242 cifs_remap(cifs_sb);
243 if (!rc) { 243 if (!rc) {
244 tmpbuffer = kmalloc(maxpath); 244 tmpbuffer = kmalloc(maxpath);
245 rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path, 245 rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
@@ -704,15 +704,15 @@ static int cifs_filldir(char *find_entry, struct file *file,
704 704
705 if (file_info->srch_inf.unicode) { 705 if (file_info->srch_inf.unicode) {
706 struct nls_table *nlt = cifs_sb->local_nls; 706 struct nls_table *nlt = cifs_sb->local_nls;
707 int map_type;
707 708
709 map_type = cifs_remap(cifs_sb);
708 name.name = scratch_buf; 710 name.name = scratch_buf;
709 name.len = 711 name.len =
710 cifs_from_utf16((char *)name.name, (__le16 *)de.name, 712 cifs_from_utf16((char *)name.name, (__le16 *)de.name,
711 UNICODE_NAME_MAX, 713 UNICODE_NAME_MAX,
712 min_t(size_t, de.namelen, 714 min_t(size_t, de.namelen,
713 (size_t)max_len), nlt, 715 (size_t)max_len), nlt, map_type);
714 cifs_sb->mnt_cifs_flags &
715 CIFS_MOUNT_MAP_SPECIAL_CHR);
716 name.len -= nls_nullsize(nlt); 716 name.len -= nls_nullsize(nlt);
717 } else { 717 } else {
718 name.name = de.name; 718 name.name = de.name;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 52131d8cb4d5..d2979036a4c7 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -23,6 +23,7 @@
23#include "cifsproto.h" 23#include "cifsproto.h"
24#include "cifs_debug.h" 24#include "cifs_debug.h"
25#include "cifspdu.h" 25#include "cifspdu.h"
26#include "cifs_unicode.h"
26 27
27/* 28/*
28 * An NT cancel request header looks just like the original request except: 29 * An NT cancel request header looks just like the original request except:
@@ -530,13 +531,11 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
530 531
531 rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info, 532 rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info,
532 0 /* not legacy */, cifs_sb->local_nls, 533 0 /* not legacy */, cifs_sb->local_nls,
533 cifs_sb->mnt_cifs_flags & 534 cifs_remap(cifs_sb));
534 CIFS_MOUNT_MAP_SPECIAL_CHR);
535 535
536 if (rc == -EOPNOTSUPP || rc == -EINVAL) 536 if (rc == -EOPNOTSUPP || rc == -EINVAL)
537 rc = SMBQueryInformation(xid, tcon, full_path, file_info, 537 rc = SMBQueryInformation(xid, tcon, full_path, file_info,
538 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 538 cifs_sb->local_nls, cifs_remap(cifs_sb));
539 CIFS_MOUNT_MAP_SPECIAL_CHR);
540 kfree(file_info); 539 kfree(file_info);
541 return rc; 540 return rc;
542} 541}
@@ -552,8 +551,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
552 551
553 /* could do find first instead but this returns more info */ 552 /* could do find first instead but this returns more info */
554 rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */, 553 rc = CIFSSMBQPathInfo(xid, tcon, full_path, data, 0 /* not legacy */,
555 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 554 cifs_sb->local_nls, cifs_remap(cifs_sb));
556 CIFS_MOUNT_MAP_SPECIAL_CHR);
557 /* 555 /*
558 * BB optimize code so we do not make the above call when server claims 556 * BB optimize code so we do not make the above call when server claims
559 * no NT SMB support and the above call failed at least once - set flag 557 * no NT SMB support and the above call failed at least once - set flag
@@ -562,8 +560,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
562 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { 560 if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
563 rc = SMBQueryInformation(xid, tcon, full_path, data, 561 rc = SMBQueryInformation(xid, tcon, full_path, data,
564 cifs_sb->local_nls, 562 cifs_sb->local_nls,
565 cifs_sb->mnt_cifs_flags & 563 cifs_remap(cifs_sb));
566 CIFS_MOUNT_MAP_SPECIAL_CHR);
567 *adjustTZ = true; 564 *adjustTZ = true;
568 } 565 }
569 566
@@ -611,8 +608,7 @@ cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
611 */ 608 */
612 return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid, 609 return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid,
613 cifs_sb->local_nls, 610 cifs_sb->local_nls,
614 cifs_sb->mnt_cifs_flags & 611 cifs_remap(cifs_sb));
615 CIFS_MOUNT_MAP_SPECIAL_CHR);
616} 612}
617 613
618static int 614static int
@@ -703,8 +699,7 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
703 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY; 699 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
704 info.Attributes = cpu_to_le32(dosattrs); 700 info.Attributes = cpu_to_le32(dosattrs);
705 rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls, 701 rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
706 cifs_sb->mnt_cifs_flags & 702 cifs_remap(cifs_sb));
707 CIFS_MOUNT_MAP_SPECIAL_CHR);
708 if (rc == 0) 703 if (rc == 0)
709 cifsInode->cifsAttrs = dosattrs; 704 cifsInode->cifsAttrs = dosattrs;
710} 705}
@@ -720,8 +715,7 @@ cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
720 oparms->create_options, 715 oparms->create_options,
721 &oparms->fid->netfid, oplock, buf, 716 &oparms->fid->netfid, oplock, buf,
722 oparms->cifs_sb->local_nls, 717 oparms->cifs_sb->local_nls,
723 oparms->cifs_sb->mnt_cifs_flags 718 cifs_remap(oparms->cifs_sb));
724 & CIFS_MOUNT_MAP_SPECIAL_CHR);
725 return CIFS_open(xid, oparms, oplock, buf); 719 return CIFS_open(xid, oparms, oplock, buf);
726} 720}
727 721
@@ -749,21 +743,21 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
749} 743}
750 744
751static int 745static int
752cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, 746cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid,
753 struct cifs_io_parms *parms, unsigned int *bytes_read, 747 struct cifs_io_parms *parms, unsigned int *bytes_read,
754 char **buf, int *buf_type) 748 char **buf, int *buf_type)
755{ 749{
756 parms->netfid = cfile->fid.netfid; 750 parms->netfid = pfid->netfid;
757 return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type); 751 return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
758} 752}
759 753
760static int 754static int
761cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, 755cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid,
762 struct cifs_io_parms *parms, unsigned int *written, 756 struct cifs_io_parms *parms, unsigned int *written,
763 struct kvec *iov, unsigned long nr_segs) 757 struct kvec *iov, unsigned long nr_segs)
764{ 758{
765 759
766 parms->netfid = cfile->fid.netfid; 760 parms->netfid = pfid->netfid;
767 return CIFSSMBWrite2(xid, parms, written, iov, nr_segs); 761 return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
768} 762}
769 763
@@ -800,8 +794,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
800 tcon = tlink_tcon(tlink); 794 tcon = tlink_tcon(tlink);
801 795
802 rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls, 796 rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
803 cifs_sb->mnt_cifs_flags & 797 cifs_remap(cifs_sb));
804 CIFS_MOUNT_MAP_SPECIAL_CHR);
805 if (rc == 0) { 798 if (rc == 0) {
806 cinode->cifsAttrs = le32_to_cpu(buf->Attributes); 799 cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
807 goto out; 800 goto out;
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 4aa7a0f07d6e..1a08a34838fc 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -379,6 +379,14 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
379 int len; 379 int len;
380 const char *start_of_path; 380 const char *start_of_path;
381 __le16 *to; 381 __le16 *to;
382 int map_type;
383
384 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
385 map_type = SFM_MAP_UNI_RSVD;
386 else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
387 map_type = SFU_MAP_UNI_RSVD;
388 else
389 map_type = NO_MAP_UNI_RSVD;
382 390
383 /* Windows doesn't allow paths beginning with \ */ 391 /* Windows doesn't allow paths beginning with \ */
384 if (from[0] == '\\') 392 if (from[0] == '\\')
@@ -386,9 +394,7 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
386 else 394 else
387 start_of_path = from; 395 start_of_path = from;
388 to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len, 396 to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
389 cifs_sb->local_nls, 397 cifs_sb->local_nls, map_type);
390 cifs_sb->mnt_cifs_flags &
391 CIFS_MOUNT_MAP_SPECIAL_CHR);
392 return to; 398 return to;
393} 399}
394 400
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f522193b7184..c5f521bcdee2 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -265,15 +265,18 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
265 FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */, 265 FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
266 NULL /* no data input */, 0 /* no data input */, 266 NULL /* no data input */, 0 /* no data input */,
267 (char **)&out_buf, &ret_data_len); 267 (char **)&out_buf, &ret_data_len);
268 268 if (rc != 0)
269 if ((rc == 0) && (ret_data_len > 0)) { 269 cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
270 else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) {
271 cifs_dbg(VFS, "server returned bad net interface info buf\n");
272 rc = -EINVAL;
273 } else {
270 /* Dump info on first interface */ 274 /* Dump info on first interface */
271 cifs_dbg(FYI, "Adapter Capability 0x%x\t", 275 cifs_dbg(FYI, "Adapter Capability 0x%x\t",
272 le32_to_cpu(out_buf->Capability)); 276 le32_to_cpu(out_buf->Capability));
273 cifs_dbg(FYI, "Link Speed %lld\n", 277 cifs_dbg(FYI, "Link Speed %lld\n",
274 le64_to_cpu(out_buf->LinkSpeed)); 278 le64_to_cpu(out_buf->LinkSpeed));
275 } else 279 }
276 cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
277 280
278 return rc; 281 return rc;
279} 282}
@@ -711,23 +714,23 @@ smb2_read_data_length(char *buf)
711 714
712 715
713static int 716static int
714smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile, 717smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid,
715 struct cifs_io_parms *parms, unsigned int *bytes_read, 718 struct cifs_io_parms *parms, unsigned int *bytes_read,
716 char **buf, int *buf_type) 719 char **buf, int *buf_type)
717{ 720{
718 parms->persistent_fid = cfile->fid.persistent_fid; 721 parms->persistent_fid = pfid->persistent_fid;
719 parms->volatile_fid = cfile->fid.volatile_fid; 722 parms->volatile_fid = pfid->volatile_fid;
720 return SMB2_read(xid, parms, bytes_read, buf, buf_type); 723 return SMB2_read(xid, parms, bytes_read, buf, buf_type);
721} 724}
722 725
723static int 726static int
724smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, 727smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid,
725 struct cifs_io_parms *parms, unsigned int *written, 728 struct cifs_io_parms *parms, unsigned int *written,
726 struct kvec *iov, unsigned long nr_segs) 729 struct kvec *iov, unsigned long nr_segs)
727{ 730{
728 731
729 parms->persistent_fid = cfile->fid.persistent_fid; 732 parms->persistent_fid = pfid->persistent_fid;
730 parms->volatile_fid = cfile->fid.volatile_fid; 733 parms->volatile_fid = pfid->volatile_fid;
731 return SMB2_write(xid, parms, written, iov, nr_segs); 734 return SMB2_write(xid, parms, written, iov, nr_segs);
732} 735}
733 736
@@ -1452,6 +1455,8 @@ struct smb_version_operations smb21_operations = {
1452 .rename = smb2_rename_path, 1455 .rename = smb2_rename_path,
1453 .create_hardlink = smb2_create_hardlink, 1456 .create_hardlink = smb2_create_hardlink,
1454 .query_symlink = smb2_query_symlink, 1457 .query_symlink = smb2_query_symlink,
1458 .query_mf_symlink = smb3_query_mf_symlink,
1459 .create_mf_symlink = smb3_create_mf_symlink,
1455 .open = smb2_open_file, 1460 .open = smb2_open_file,
1456 .set_fid = smb2_set_fid, 1461 .set_fid = smb2_set_fid,
1457 .close = smb2_close_file, 1462 .close = smb2_close_file,
@@ -1531,6 +1536,8 @@ struct smb_version_operations smb30_operations = {
1531 .rename = smb2_rename_path, 1536 .rename = smb2_rename_path,
1532 .create_hardlink = smb2_create_hardlink, 1537 .create_hardlink = smb2_create_hardlink,
1533 .query_symlink = smb2_query_symlink, 1538 .query_symlink = smb2_query_symlink,
1539 .query_mf_symlink = smb3_query_mf_symlink,
1540 .create_mf_symlink = smb3_create_mf_symlink,
1534 .open = smb2_open_file, 1541 .open = smb2_open_file,
1535 .set_fid = smb2_set_fid, 1542 .set_fid = smb2_set_fid,
1536 .close = smb2_close_file, 1543 .close = smb2_close_file,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 74b3a6684383..8f1672bb82d5 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1098,6 +1098,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1098 1098
1099 if (oparms->create_options & CREATE_OPTION_READONLY) 1099 if (oparms->create_options & CREATE_OPTION_READONLY)
1100 file_attributes |= ATTR_READONLY; 1100 file_attributes |= ATTR_READONLY;
1101 if (oparms->create_options & CREATE_OPTION_SPECIAL)
1102 file_attributes |= ATTR_SYSTEM;
1101 1103
1102 req->ImpersonationLevel = IL_IMPERSONATION; 1104 req->ImpersonationLevel = IL_IMPERSONATION;
1103 req->DesiredAccess = cpu_to_le32(oparms->desired_access); 1105 req->DesiredAccess = cpu_to_le32(oparms->desired_access);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index fbe486c285a9..e3188abdafd0 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -352,6 +352,8 @@ struct smb2_tree_disconnect_rsp {
352#define FILE_ATTRIBUTE_OFFLINE 0x00001000 352#define FILE_ATTRIBUTE_OFFLINE 0x00001000
353#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 353#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000
354#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 354#define FILE_ATTRIBUTE_ENCRYPTED 0x00004000
355#define FILE_ATTRIBUTE_INTEGRITY_STREAM 0x00008000
356#define FILE_ATTRIBUTE_NO_SCRUB_DATA 0x00020000
355 357
356/* Oplock levels */ 358/* Oplock levels */
357#define SMB2_OPLOCK_LEVEL_NONE 0x00 359#define SMB2_OPLOCK_LEVEL_NONE 0x00
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 67e8ce8055de..79dc650c18b2 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -82,7 +82,13 @@ extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
82extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon, 82extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
83 const char *from_name, const char *to_name, 83 const char *from_name, const char *to_name,
84 struct cifs_sb_info *cifs_sb); 84 struct cifs_sb_info *cifs_sb);
85 85extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
86 struct cifs_sb_info *cifs_sb, const unsigned char *path,
87 char *pbuf, unsigned int *pbytes_written);
88extern int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
89 struct cifs_sb_info *cifs_sb,
90 const unsigned char *path, char *pbuf,
91 unsigned int *pbytes_read);
86extern int smb2_open_file(const unsigned int xid, 92extern int smb2_open_file(const unsigned int xid,
87 struct cifs_open_parms *oparms, 93 struct cifs_open_parms *oparms,
88 __u32 *oplock, FILE_ALL_INFO *buf); 94 __u32 *oplock, FILE_ALL_INFO *buf);
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index 43eb1367b103..6c1566366a66 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -29,6 +29,7 @@
29#include <linux/string.h> 29#include <linux/string.h>
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31#include <linux/random.h> 31#include <linux/random.h>
32#include "cifs_fs_sb.h"
32#include "cifs_unicode.h" 33#include "cifs_unicode.h"
33#include "cifspdu.h" 34#include "cifspdu.h"
34#include "cifsglob.h" 35#include "cifsglob.h"
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 5ac836a86b18..72a4d10653d6 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -28,6 +28,8 @@
28#include "cifsglob.h" 28#include "cifsglob.h"
29#include "cifsproto.h" 29#include "cifsproto.h"
30#include "cifs_debug.h" 30#include "cifs_debug.h"
31#include "cifs_fs_sb.h"
32#include "cifs_unicode.h"
31 33
32#define MAX_EA_VALUE_SIZE 65535 34#define MAX_EA_VALUE_SIZE 65535
33#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" 35#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
@@ -85,8 +87,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name)
85 if (pTcon->ses->server->ops->set_EA) 87 if (pTcon->ses->server->ops->set_EA)
86 rc = pTcon->ses->server->ops->set_EA(xid, pTcon, 88 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
87 full_path, ea_name, NULL, (__u16)0, 89 full_path, ea_name, NULL, (__u16)0,
88 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 90 cifs_sb->local_nls, cifs_remap(cifs_sb));
89 CIFS_MOUNT_MAP_SPECIAL_CHR);
90 } 91 }
91remove_ea_exit: 92remove_ea_exit:
92 kfree(full_path); 93 kfree(full_path);
@@ -154,8 +155,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
154 if (pTcon->ses->server->ops->set_EA) 155 if (pTcon->ses->server->ops->set_EA)
155 rc = pTcon->ses->server->ops->set_EA(xid, pTcon, 156 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
156 full_path, ea_name, ea_value, (__u16)value_size, 157 full_path, ea_name, ea_value, (__u16)value_size,
157 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 158 cifs_sb->local_nls, cifs_remap(cifs_sb));
158 CIFS_MOUNT_MAP_SPECIAL_CHR);
159 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) 159 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
160 == 0) { 160 == 0) {
161 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 161 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
@@ -165,8 +165,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
165 if (pTcon->ses->server->ops->set_EA) 165 if (pTcon->ses->server->ops->set_EA)
166 rc = pTcon->ses->server->ops->set_EA(xid, pTcon, 166 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
167 full_path, ea_name, ea_value, (__u16)value_size, 167 full_path, ea_name, ea_value, (__u16)value_size,
168 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 168 cifs_sb->local_nls, cifs_remap(cifs_sb));
169 CIFS_MOUNT_MAP_SPECIAL_CHR);
170 } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, 169 } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
171 strlen(CIFS_XATTR_CIFS_ACL)) == 0) { 170 strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
172#ifdef CONFIG_CIFS_ACL 171#ifdef CONFIG_CIFS_ACL
@@ -199,8 +198,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
199 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, 198 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
200 ea_value, (const int)value_size, 199 ea_value, (const int)value_size,
201 ACL_TYPE_ACCESS, cifs_sb->local_nls, 200 ACL_TYPE_ACCESS, cifs_sb->local_nls,
202 cifs_sb->mnt_cifs_flags & 201 cifs_remap(cifs_sb));
203 CIFS_MOUNT_MAP_SPECIAL_CHR);
204 cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc); 202 cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
205#else 203#else
206 cifs_dbg(FYI, "set POSIX ACL not supported\n"); 204 cifs_dbg(FYI, "set POSIX ACL not supported\n");
@@ -212,8 +210,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
212 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, 210 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
213 ea_value, (const int)value_size, 211 ea_value, (const int)value_size,
214 ACL_TYPE_DEFAULT, cifs_sb->local_nls, 212 ACL_TYPE_DEFAULT, cifs_sb->local_nls,
215 cifs_sb->mnt_cifs_flags & 213 cifs_remap(cifs_sb));
216 CIFS_MOUNT_MAP_SPECIAL_CHR);
217 cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc); 214 cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
218#else 215#else
219 cifs_dbg(FYI, "set default POSIX ACL not supported\n"); 216 cifs_dbg(FYI, "set default POSIX ACL not supported\n");
@@ -285,8 +282,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
285 if (pTcon->ses->server->ops->query_all_EAs) 282 if (pTcon->ses->server->ops->query_all_EAs)
286 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 283 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
287 full_path, ea_name, ea_value, buf_size, 284 full_path, ea_name, ea_value, buf_size,
288 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 285 cifs_sb->local_nls, cifs_remap(cifs_sb));
289 CIFS_MOUNT_MAP_SPECIAL_CHR);
290 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { 286 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
291 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 287 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
292 goto get_ea_exit; 288 goto get_ea_exit;
@@ -295,8 +291,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
295 if (pTcon->ses->server->ops->query_all_EAs) 291 if (pTcon->ses->server->ops->query_all_EAs)
296 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 292 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
297 full_path, ea_name, ea_value, buf_size, 293 full_path, ea_name, ea_value, buf_size,
298 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 294 cifs_sb->local_nls, cifs_remap(cifs_sb));
299 CIFS_MOUNT_MAP_SPECIAL_CHR);
300 } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, 295 } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
301 strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { 296 strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
302#ifdef CONFIG_CIFS_POSIX 297#ifdef CONFIG_CIFS_POSIX
@@ -304,8 +299,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
304 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, 299 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
305 ea_value, buf_size, ACL_TYPE_ACCESS, 300 ea_value, buf_size, ACL_TYPE_ACCESS,
306 cifs_sb->local_nls, 301 cifs_sb->local_nls,
307 cifs_sb->mnt_cifs_flags & 302 cifs_remap(cifs_sb));
308 CIFS_MOUNT_MAP_SPECIAL_CHR);
309#else 303#else
310 cifs_dbg(FYI, "Query POSIX ACL not supported yet\n"); 304 cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
311#endif /* CONFIG_CIFS_POSIX */ 305#endif /* CONFIG_CIFS_POSIX */
@@ -316,8 +310,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
316 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, 310 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
317 ea_value, buf_size, ACL_TYPE_DEFAULT, 311 ea_value, buf_size, ACL_TYPE_DEFAULT,
318 cifs_sb->local_nls, 312 cifs_sb->local_nls,
319 cifs_sb->mnt_cifs_flags & 313 cifs_remap(cifs_sb));
320 CIFS_MOUNT_MAP_SPECIAL_CHR);
321#else 314#else
322 cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n"); 315 cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
323#endif /* CONFIG_CIFS_POSIX */ 316#endif /* CONFIG_CIFS_POSIX */
@@ -421,8 +414,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
421 if (pTcon->ses->server->ops->query_all_EAs) 414 if (pTcon->ses->server->ops->query_all_EAs)
422 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 415 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
423 full_path, NULL, data, buf_size, 416 full_path, NULL, data, buf_size,
424 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 417 cifs_sb->local_nls, cifs_remap(cifs_sb));
425 CIFS_MOUNT_MAP_SPECIAL_CHR);
426list_ea_exit: 418list_ea_exit:
427 kfree(full_path); 419 kfree(full_path);
428 free_xid(xid); 420 free_xid(xid);