aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-07 16:01:47 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-07 16:01:47 -0500
commit8efdf2b759409f85953b84d52a14ea4d39c80474 (patch)
tree237cfcc537fe7840a3c81660740f6073fae63c75 /fs/cifs
parentc224b76b560f3c65f0d10fbb59d3f00379eb0aaf (diff)
parentc481e9feee78c6ce1ba0a1c8c892049f6514f6cf (diff)
Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS updates from Steve French: "Includes a couple of fixes, plus changes to make multiplex identifiers easier to read and correlate with network traces, and a set of enhancements for SMB3 dialect. Also adds support for per-file compression for both cifs and smb2/smb3 ("chattr +c filename). Should have at least one other merge request ready by next week with some new SMB3 security features and copy offload support" * 'for-linus' of git://git.samba.org/sfrench/cifs-2.6: Query network adapter info at mount time for debugging Fix unused variable warning when CIFS POSIX disabled Allow setting per-file compression via CIFS protocol Query File System Alignment Query device characteristics at mount time from server on SMB2/3 not just on cifs mounts cifs: Send a logoff request before removing a smb session cifs: Make big endian multiplex ID sequences monotonic on the wire cifs: Remove redundant multiplex identifier check from check_smb_hdr() Query file system attributes from server on SMB2, not just cifs, mounts Allow setting per-file compression via SMB2/3 Fix corrupt SMB2 ioctl requests
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsglob.h29
-rw-r--r--fs/cifs/cifspdu.h34
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/cifssmb.c54
-rw-r--r--fs/cifs/connect.c25
-rw-r--r--fs/cifs/ioctl.c57
-rw-r--r--fs/cifs/misc.c22
-rw-r--r--fs/cifs/smb1ops.c12
-rw-r--r--fs/cifs/smb2ops.c114
-rw-r--r--fs/cifs/smb2pdu.c115
-rw-r--r--fs/cifs/smb2pdu.h28
-rw-r--r--fs/cifs/smb2proto.h4
-rw-r--r--fs/cifs/smb2transport.c12
-rw-r--r--fs/cifs/transport.c13
14 files changed, 464 insertions, 57 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 52b6f6c26bfc..26b1c1dc93f6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -278,6 +278,8 @@ struct smb_version_operations {
278 /* set attributes */ 278 /* set attributes */
279 int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *, 279 int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
280 const unsigned int); 280 const unsigned int);
281 int (*set_compression)(const unsigned int, struct cifs_tcon *,
282 struct cifsFileInfo *);
281 /* check if we can send an echo or nor */ 283 /* check if we can send an echo or nor */
282 bool (*can_echo)(struct TCP_Server_Info *); 284 bool (*can_echo)(struct TCP_Server_Info *);
283 /* send echo request */ 285 /* send echo request */
@@ -620,11 +622,34 @@ set_credits(struct TCP_Server_Info *server, const int val)
620} 622}
621 623
622static inline __u64 624static inline __u64
623get_next_mid(struct TCP_Server_Info *server) 625get_next_mid64(struct TCP_Server_Info *server)
624{ 626{
625 return server->ops->get_next_mid(server); 627 return server->ops->get_next_mid(server);
626} 628}
627 629
630static inline __le16
631get_next_mid(struct TCP_Server_Info *server)
632{
633 __u16 mid = get_next_mid64(server);
634 /*
635 * The value in the SMB header should be little endian for easy
636 * on-the-wire decoding.
637 */
638 return cpu_to_le16(mid);
639}
640
641static inline __u16
642get_mid(const struct smb_hdr *smb)
643{
644 return le16_to_cpu(smb->Mid);
645}
646
647static inline bool
648compare_mid(__u16 mid, const struct smb_hdr *smb)
649{
650 return mid == le16_to_cpu(smb->Mid);
651}
652
628/* 653/*
629 * When the server supports very large reads and writes via POSIX extensions, 654 * When the server supports very large reads and writes via POSIX extensions,
630 * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not 655 * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
@@ -828,6 +853,8 @@ struct cifs_tcon {
828 __u32 maximal_access; 853 __u32 maximal_access;
829 __u32 vol_serial_number; 854 __u32 vol_serial_number;
830 __le64 vol_create_time; 855 __le64 vol_create_time;
856 __u32 ss_flags; /* sector size flags */
857 __u32 perf_sector_size; /* best sector size for perf */
831#endif /* CONFIG_CIFS_SMB2 */ 858#endif /* CONFIG_CIFS_SMB2 */
832#ifdef CONFIG_CIFS_FSCACHE 859#ifdef CONFIG_CIFS_FSCACHE
833 u64 resource_id; /* server resource id */ 860 u64 resource_id; /* server resource id */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 08f9dfb1a894..9e5ee34de986 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -428,7 +428,7 @@ struct smb_hdr {
428 __u16 Tid; 428 __u16 Tid;
429 __le16 Pid; 429 __le16 Pid;
430 __u16 Uid; 430 __u16 Uid;
431 __u16 Mid; 431 __le16 Mid;
432 __u8 WordCount; 432 __u8 WordCount;
433} __attribute__((packed)); 433} __attribute__((packed));
434 434
@@ -1352,6 +1352,35 @@ typedef struct smb_com_transaction_ioctl_req {
1352 __u8 Data[1]; 1352 __u8 Data[1];
1353} __attribute__((packed)) TRANSACT_IOCTL_REQ; 1353} __attribute__((packed)) TRANSACT_IOCTL_REQ;
1354 1354
1355typedef struct smb_com_transaction_compr_ioctl_req {
1356 struct smb_hdr hdr; /* wct = 23 */
1357 __u8 MaxSetupCount;
1358 __u16 Reserved;
1359 __le32 TotalParameterCount;
1360 __le32 TotalDataCount;
1361 __le32 MaxParameterCount;
1362 __le32 MaxDataCount;
1363 __le32 ParameterCount;
1364 __le32 ParameterOffset;
1365 __le32 DataCount;
1366 __le32 DataOffset;
1367 __u8 SetupCount; /* four setup words follow subcommand */
1368 /* SNIA spec incorrectly included spurious pad here */
1369 __le16 SubCommand; /* 2 = IOCTL/FSCTL */
1370 __le32 FunctionCode;
1371 __u16 Fid;
1372 __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */
1373 __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */
1374 __le16 ByteCount;
1375 __u8 Pad[3];
1376 __le16 compression_state; /* See below for valid flags */
1377} __attribute__((packed)) TRANSACT_COMPR_IOCTL_REQ;
1378
1379/* compression state flags */
1380#define COMPRESSION_FORMAT_NONE 0x0000
1381#define COMPRESSION_FORMAT_DEFAULT 0x0001
1382#define COMPRESSION_FORMAT_LZNT1 0x0002
1383
1355typedef struct smb_com_transaction_ioctl_rsp { 1384typedef struct smb_com_transaction_ioctl_rsp {
1356 struct smb_hdr hdr; /* wct = 19 */ 1385 struct smb_hdr hdr; /* wct = 19 */
1357 __u8 Reserved[3]; 1386 __u8 Reserved[3];
@@ -2215,6 +2244,9 @@ typedef struct {
2215 __le32 DeviceCharacteristics; 2244 __le32 DeviceCharacteristics;
2216} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ 2245} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
2217 2246
2247/* minimum includes first three fields, and empty FS Name */
2248#define MIN_FS_ATTR_INFO_SIZE 12
2249
2218typedef struct { 2250typedef struct {
2219 __le32 Attributes; 2251 __le32 Attributes;
2220 __le32 MaxPathNameComponentLength; 2252 __le32 MaxPathNameComponentLength;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b5ec2a268f56..aa3397620342 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -360,6 +360,8 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
360extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 360extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
361 __u16 fid, char **symlinkinfo, 361 __u16 fid, char **symlinkinfo,
362 const struct nls_table *nls_codepage); 362 const struct nls_table *nls_codepage);
363extern int CIFSSMB_set_compression(const unsigned int xid,
364 struct cifs_tcon *tcon, __u16 fid);
363extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, 365extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
364 const char *fileName, const int disposition, 366 const char *fileName, const int disposition,
365 const int access_flags, const int omode, 367 const int access_flags, const int omode,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index ccd31ab815d4..93b29474714a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3199,6 +3199,60 @@ qreparse_out:
3199 return rc; 3199 return rc;
3200} 3200}
3201 3201
3202int
3203CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3204 __u16 fid)
3205{
3206 int rc = 0;
3207 int bytes_returned;
3208 struct smb_com_transaction_compr_ioctl_req *pSMB;
3209 struct smb_com_transaction_ioctl_rsp *pSMBr;
3210
3211 cifs_dbg(FYI, "Set compression for %u\n", fid);
3212 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3213 (void **) &pSMBr);
3214 if (rc)
3215 return rc;
3216
3217 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3218
3219 pSMB->TotalParameterCount = 0;
3220 pSMB->TotalDataCount = __constant_cpu_to_le32(2);
3221 pSMB->MaxParameterCount = 0;
3222 pSMB->MaxDataCount = 0;
3223 pSMB->MaxSetupCount = 4;
3224 pSMB->Reserved = 0;
3225 pSMB->ParameterOffset = 0;
3226 pSMB->DataCount = __constant_cpu_to_le32(2);
3227 pSMB->DataOffset =
3228 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3229 compression_state) - 4); /* 84 */
3230 pSMB->SetupCount = 4;
3231 pSMB->SubCommand = __constant_cpu_to_le16(NT_TRANSACT_IOCTL);
3232 pSMB->ParameterCount = 0;
3233 pSMB->FunctionCode = __constant_cpu_to_le32(FSCTL_SET_COMPRESSION);
3234 pSMB->IsFsctl = 1; /* FSCTL */
3235 pSMB->IsRootFlag = 0;
3236 pSMB->Fid = fid; /* file handle always le */
3237 /* 3 byte pad, followed by 2 byte compress state */
3238 pSMB->ByteCount = __constant_cpu_to_le16(5);
3239 inc_rfc1001_len(pSMB, 5);
3240
3241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3242 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3243 if (rc)
3244 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3245
3246 cifs_buf_release(pSMB);
3247
3248 /*
3249 * Note: On -EAGAIN error only caller can retry on handle based calls
3250 * since file handle passed in no longer valid.
3251 */
3252 return rc;
3253}
3254
3255
3202#ifdef CONFIG_CIFS_POSIX 3256#ifdef CONFIG_CIFS_POSIX
3203 3257
3204/*Convert an Access Control Entry from wire format to local POSIX xattr format*/ 3258/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a279ffc0bc29..62a55147400a 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2242,6 +2242,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
2242 2242
2243 spin_lock(&cifs_tcp_ses_lock); 2243 spin_lock(&cifs_tcp_ses_lock);
2244 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 2244 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
2245 if (ses->status == CifsExiting)
2246 continue;
2245 if (!match_session(ses, vol)) 2247 if (!match_session(ses, vol))
2246 continue; 2248 continue;
2247 ++ses->ses_count; 2249 ++ses->ses_count;
@@ -2255,24 +2257,37 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
2255static void 2257static void
2256cifs_put_smb_ses(struct cifs_ses *ses) 2258cifs_put_smb_ses(struct cifs_ses *ses)
2257{ 2259{
2258 unsigned int xid; 2260 unsigned int rc, xid;
2259 struct TCP_Server_Info *server = ses->server; 2261 struct TCP_Server_Info *server = ses->server;
2260 2262
2261 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count); 2263 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
2264
2262 spin_lock(&cifs_tcp_ses_lock); 2265 spin_lock(&cifs_tcp_ses_lock);
2266 if (ses->status == CifsExiting) {
2267 spin_unlock(&cifs_tcp_ses_lock);
2268 return;
2269 }
2263 if (--ses->ses_count > 0) { 2270 if (--ses->ses_count > 0) {
2264 spin_unlock(&cifs_tcp_ses_lock); 2271 spin_unlock(&cifs_tcp_ses_lock);
2265 return; 2272 return;
2266 } 2273 }
2267 2274 if (ses->status == CifsGood)
2268 list_del_init(&ses->smb_ses_list); 2275 ses->status = CifsExiting;
2269 spin_unlock(&cifs_tcp_ses_lock); 2276 spin_unlock(&cifs_tcp_ses_lock);
2270 2277
2271 if (ses->status == CifsGood && server->ops->logoff) { 2278 if (ses->status == CifsExiting && server->ops->logoff) {
2272 xid = get_xid(); 2279 xid = get_xid();
2273 server->ops->logoff(xid, ses); 2280 rc = server->ops->logoff(xid, ses);
2281 if (rc)
2282 cifs_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
2283 __func__, rc);
2274 _free_xid(xid); 2284 _free_xid(xid);
2275 } 2285 }
2286
2287 spin_lock(&cifs_tcp_ses_lock);
2288 list_del_init(&ses->smb_ses_list);
2289 spin_unlock(&cifs_tcp_ses_lock);
2290
2276 sesInfoFree(ses); 2291 sesInfoFree(ses);
2277 cifs_put_tcp_session(server); 2292 cifs_put_tcp_session(server);
2278} 2293}
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 3e0845585853..ba54bf6ab116 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * vfs operations that deal with io control 4 * vfs operations that deal with io control
5 * 5 *
6 * Copyright (C) International Business Machines Corp., 2005,2007 6 * Copyright (C) International Business Machines Corp., 2005,2013
7 * Author(s): Steve French (sfrench@us.ibm.com) 7 * Author(s): Steve French (sfrench@us.ibm.com)
8 * 8 *
9 * This library is free software; you can redistribute it and/or modify 9 * This library is free software; you can redistribute it and/or modify
@@ -34,13 +34,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
34 int rc = -ENOTTY; /* strange error - but the precedent */ 34 int rc = -ENOTTY; /* strange error - but the precedent */
35 unsigned int xid; 35 unsigned int xid;
36 struct cifs_sb_info *cifs_sb; 36 struct cifs_sb_info *cifs_sb;
37#ifdef CONFIG_CIFS_POSIX
38 struct cifsFileInfo *pSMBFile = filep->private_data; 37 struct cifsFileInfo *pSMBFile = filep->private_data;
39 struct cifs_tcon *tcon; 38 struct cifs_tcon *tcon;
40 __u64 ExtAttrBits = 0; 39 __u64 ExtAttrBits = 0;
41 __u64 ExtAttrMask = 0;
42 __u64 caps; 40 __u64 caps;
43#endif /* CONFIG_CIFS_POSIX */
44 41
45 xid = get_xid(); 42 xid = get_xid();
46 43
@@ -49,13 +46,14 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
49 cifs_sb = CIFS_SB(inode->i_sb); 46 cifs_sb = CIFS_SB(inode->i_sb);
50 47
51 switch (command) { 48 switch (command) {
52#ifdef CONFIG_CIFS_POSIX
53 case FS_IOC_GETFLAGS: 49 case FS_IOC_GETFLAGS:
54 if (pSMBFile == NULL) 50 if (pSMBFile == NULL)
55 break; 51 break;
56 tcon = tlink_tcon(pSMBFile->tlink); 52 tcon = tlink_tcon(pSMBFile->tlink);
57 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 53 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
54#ifdef CONFIG_CIFS_POSIX
58 if (CIFS_UNIX_EXTATTR_CAP & caps) { 55 if (CIFS_UNIX_EXTATTR_CAP & caps) {
56 __u64 ExtAttrMask = 0;
59 rc = CIFSGetExtAttr(xid, tcon, 57 rc = CIFSGetExtAttr(xid, tcon,
60 pSMBFile->fid.netfid, 58 pSMBFile->fid.netfid,
61 &ExtAttrBits, &ExtAttrMask); 59 &ExtAttrBits, &ExtAttrMask);
@@ -63,29 +61,50 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
63 rc = put_user(ExtAttrBits & 61 rc = put_user(ExtAttrBits &
64 FS_FL_USER_VISIBLE, 62 FS_FL_USER_VISIBLE,
65 (int __user *)arg); 63 (int __user *)arg);
64 if (rc != EOPNOTSUPP)
65 break;
66 }
67#endif /* CONFIG_CIFS_POSIX */
68 rc = 0;
69 if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
70 /* add in the compressed bit */
71 ExtAttrBits = FS_COMPR_FL;
72 rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
73 (int __user *)arg);
66 } 74 }
67 break; 75 break;
68
69 case FS_IOC_SETFLAGS: 76 case FS_IOC_SETFLAGS:
70 if (pSMBFile == NULL) 77 if (pSMBFile == NULL)
71 break; 78 break;
72 tcon = tlink_tcon(pSMBFile->tlink); 79 tcon = tlink_tcon(pSMBFile->tlink);
73 caps = le64_to_cpu(tcon->fsUnixInfo.Capability); 80 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
74 if (CIFS_UNIX_EXTATTR_CAP & caps) { 81
75 if (get_user(ExtAttrBits, (int __user *)arg)) { 82 if (get_user(ExtAttrBits, (int __user *)arg)) {
76 rc = -EFAULT; 83 rc = -EFAULT;
77 break; 84 break;
78 } 85 }
79 /* 86
80 * rc = CIFSGetExtAttr(xid, tcon, 87 /*
81 * pSMBFile->fid.netfid, 88 * if (CIFS_UNIX_EXTATTR_CAP & caps)
82 * extAttrBits, 89 * rc = CIFSSetExtAttr(xid, tcon,
83 * &ExtAttrMask); 90 * pSMBFile->fid.netfid,
84 */ 91 * extAttrBits,
92 * &ExtAttrMask);
93 * if (rc != EOPNOTSUPP)
94 * break;
95 */
96
97 /* Currently only flag we can set is compressed flag */
98 if ((ExtAttrBits & FS_COMPR_FL) == 0)
99 break;
100
101 /* Try to set compress flag */
102 if (tcon->ses->server->ops->set_compression) {
103 rc = tcon->ses->server->ops->set_compression(
104 xid, tcon, pSMBFile);
105 cifs_dbg(FYI, "set compress flag rc %d\n", rc);
85 } 106 }
86 cifs_dbg(FYI, "set flags not implemented yet\n");
87 break; 107 break;
88#endif /* CONFIG_CIFS_POSIX */
89 default: 108 default:
90 cifs_dbg(FYI, "unsupported ioctl\n"); 109 cifs_dbg(FYI, "unsupported ioctl\n");
91 break; 110 break;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 138a011633fe..2f9f3790679d 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -278,7 +278,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
278} 278}
279 279
280static int 280static int
281check_smb_hdr(struct smb_hdr *smb, __u16 mid) 281check_smb_hdr(struct smb_hdr *smb)
282{ 282{
283 /* does it have the right SMB "signature" ? */ 283 /* does it have the right SMB "signature" ? */
284 if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) { 284 if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
@@ -287,13 +287,6 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
287 return 1; 287 return 1;
288 } 288 }
289 289
290 /* Make sure that message ids match */
291 if (mid != smb->Mid) {
292 cifs_dbg(VFS, "Mids do not match. received=%u expected=%u\n",
293 smb->Mid, mid);
294 return 1;
295 }
296
297 /* if it's a response then accept */ 290 /* if it's a response then accept */
298 if (smb->Flags & SMBFLG_RESPONSE) 291 if (smb->Flags & SMBFLG_RESPONSE)
299 return 0; 292 return 0;
@@ -302,7 +295,8 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
302 if (smb->Command == SMB_COM_LOCKING_ANDX) 295 if (smb->Command == SMB_COM_LOCKING_ANDX)
303 return 0; 296 return 0;
304 297
305 cifs_dbg(VFS, "Server sent request, not response. mid=%u\n", smb->Mid); 298 cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
299 get_mid(smb));
306 return 1; 300 return 1;
307} 301}
308 302
@@ -310,7 +304,6 @@ int
310checkSMB(char *buf, unsigned int total_read) 304checkSMB(char *buf, unsigned int total_read)
311{ 305{
312 struct smb_hdr *smb = (struct smb_hdr *)buf; 306 struct smb_hdr *smb = (struct smb_hdr *)buf;
313 __u16 mid = smb->Mid;
314 __u32 rfclen = be32_to_cpu(smb->smb_buf_length); 307 __u32 rfclen = be32_to_cpu(smb->smb_buf_length);
315 __u32 clc_len; /* calculated length */ 308 __u32 clc_len; /* calculated length */
316 cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n", 309 cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
@@ -348,7 +341,7 @@ checkSMB(char *buf, unsigned int total_read)
348 } 341 }
349 342
350 /* otherwise, there is enough to get to the BCC */ 343 /* otherwise, there is enough to get to the BCC */
351 if (check_smb_hdr(smb, mid)) 344 if (check_smb_hdr(smb))
352 return -EIO; 345 return -EIO;
353 clc_len = smbCalcSize(smb); 346 clc_len = smbCalcSize(smb);
354 347
@@ -359,6 +352,7 @@ checkSMB(char *buf, unsigned int total_read)
359 } 352 }
360 353
361 if (4 + rfclen != clc_len) { 354 if (4 + rfclen != clc_len) {
355 __u16 mid = get_mid(smb);
362 /* check if bcc wrapped around for large read responses */ 356 /* check if bcc wrapped around for large read responses */
363 if ((rfclen > 64 * 1024) && (rfclen > clc_len)) { 357 if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
364 /* check if lengths match mod 64K */ 358 /* check if lengths match mod 64K */
@@ -366,11 +360,11 @@ checkSMB(char *buf, unsigned int total_read)
366 return 0; /* bcc wrapped */ 360 return 0; /* bcc wrapped */
367 } 361 }
368 cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n", 362 cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
369 clc_len, 4 + rfclen, smb->Mid); 363 clc_len, 4 + rfclen, mid);
370 364
371 if (4 + rfclen < clc_len) { 365 if (4 + rfclen < clc_len) {
372 cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n", 366 cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
373 rfclen, smb->Mid); 367 rfclen, mid);
374 return -EIO; 368 return -EIO;
375 } else if (rfclen > clc_len + 512) { 369 } else if (rfclen > clc_len + 512) {
376 /* 370 /*
@@ -383,7 +377,7 @@ checkSMB(char *buf, unsigned int total_read)
383 * data to 512 bytes. 377 * data to 512 bytes.
384 */ 378 */
385 cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n", 379 cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
386 rfclen, smb->Mid); 380 rfclen, mid);
387 return -EIO; 381 return -EIO;
388 } 382 }
389 } 383 }
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 8233b174de3d..384cffe42850 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -67,7 +67,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
67 mutex_unlock(&server->srv_mutex); 67 mutex_unlock(&server->srv_mutex);
68 68
69 cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n", 69 cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n",
70 in_buf->Mid, rc); 70 get_mid(in_buf), rc);
71 71
72 return rc; 72 return rc;
73} 73}
@@ -101,7 +101,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
101 101
102 spin_lock(&GlobalMid_Lock); 102 spin_lock(&GlobalMid_Lock);
103 list_for_each_entry(mid, &server->pending_mid_q, qhead) { 103 list_for_each_entry(mid, &server->pending_mid_q, qhead) {
104 if (mid->mid == buf->Mid && 104 if (compare_mid(mid->mid, buf) &&
105 mid->mid_state == MID_REQUEST_SUBMITTED && 105 mid->mid_state == MID_REQUEST_SUBMITTED &&
106 le16_to_cpu(mid->command) == buf->Command) { 106 le16_to_cpu(mid->command) == buf->Command) {
107 spin_unlock(&GlobalMid_Lock); 107 spin_unlock(&GlobalMid_Lock);
@@ -807,6 +807,13 @@ out:
807} 807}
808 808
809static int 809static int
810cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
811 struct cifsFileInfo *cfile)
812{
813 return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid);
814}
815
816static int
810cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, 817cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
811 const char *path, struct cifs_sb_info *cifs_sb, 818 const char *path, struct cifs_sb_info *cifs_sb,
812 struct cifs_fid *fid, __u16 search_flags, 819 struct cifs_fid *fid, __u16 search_flags,
@@ -956,6 +963,7 @@ struct smb_version_operations smb1_operations = {
956 .set_path_size = CIFSSMBSetEOF, 963 .set_path_size = CIFSSMBSetEOF,
957 .set_file_size = CIFSSMBSetFileSize, 964 .set_file_size = CIFSSMBSetFileSize,
958 .set_file_info = smb_set_file_info, 965 .set_file_info = smb_set_file_info,
966 .set_compression = cifs_set_compression,
959 .echo = CIFSSMBEcho, 967 .echo = CIFSSMBEcho,
960 .mkdir = CIFSSMBMkDir, 968 .mkdir = CIFSSMBMkDir,
961 .mkdir_setinfo = cifs_mkdir_setinfo, 969 .mkdir_setinfo = cifs_mkdir_setinfo,
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 861b33214144..c571be8cb76e 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -209,6 +209,94 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
209 return rsize; 209 return rsize;
210} 210}
211 211
212#ifdef CONFIG_CIFS_STATS2
213static int
214SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
215{
216 int rc;
217 unsigned int ret_data_len = 0;
218 struct network_interface_info_ioctl_rsp *out_buf;
219
220 rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
221 FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
222 NULL /* no data input */, 0 /* no data input */,
223 (char **)&out_buf, &ret_data_len);
224
225 if ((rc == 0) && (ret_data_len > 0)) {
226 /* Dump info on first interface */
227 cifs_dbg(FYI, "Adapter Capability 0x%x\t",
228 le32_to_cpu(out_buf->Capability));
229 cifs_dbg(FYI, "Link Speed %lld\n",
230 le64_to_cpu(out_buf->LinkSpeed));
231 } else
232 cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
233
234 return rc;
235}
236#endif /* STATS2 */
237
238static void
239smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
240{
241 int rc;
242 __le16 srch_path = 0; /* Null - open root of share */
243 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
244 struct cifs_open_parms oparms;
245 struct cifs_fid fid;
246
247 oparms.tcon = tcon;
248 oparms.desired_access = FILE_READ_ATTRIBUTES;
249 oparms.disposition = FILE_OPEN;
250 oparms.create_options = 0;
251 oparms.fid = &fid;
252 oparms.reconnect = false;
253
254 rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
255 if (rc)
256 return;
257
258#ifdef CONFIG_CIFS_STATS2
259 SMB3_request_interfaces(xid, tcon);
260#endif /* STATS2 */
261
262 SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
263 FS_ATTRIBUTE_INFORMATION);
264 SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
265 FS_DEVICE_INFORMATION);
266 SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
267 FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */
268 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
269 return;
270}
271
272static void
273smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
274{
275 int rc;
276 __le16 srch_path = 0; /* Null - open root of share */
277 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
278 struct cifs_open_parms oparms;
279 struct cifs_fid fid;
280
281 oparms.tcon = tcon;
282 oparms.desired_access = FILE_READ_ATTRIBUTES;
283 oparms.disposition = FILE_OPEN;
284 oparms.create_options = 0;
285 oparms.fid = &fid;
286 oparms.reconnect = false;
287
288 rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
289 if (rc)
290 return;
291
292 SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
293 FS_ATTRIBUTE_INFORMATION);
294 SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
295 FS_DEVICE_INFORMATION);
296 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
297 return;
298}
299
212static int 300static int
213smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, 301smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
214 struct cifs_sb_info *cifs_sb, const char *full_path) 302 struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -304,7 +392,19 @@ smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon)
304 seq_puts(m, " ASYMMETRIC,"); 392 seq_puts(m, " ASYMMETRIC,");
305 if (tcon->capabilities == 0) 393 if (tcon->capabilities == 0)
306 seq_puts(m, " None"); 394 seq_puts(m, " None");
395 if (tcon->ss_flags & SSINFO_FLAGS_ALIGNED_DEVICE)
396 seq_puts(m, " Aligned,");
397 if (tcon->ss_flags & SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE)
398 seq_puts(m, " Partition Aligned,");
399 if (tcon->ss_flags & SSINFO_FLAGS_NO_SEEK_PENALTY)
400 seq_puts(m, " SSD,");
401 if (tcon->ss_flags & SSINFO_FLAGS_TRIM_ENABLED)
402 seq_puts(m, " TRIM-support,");
403
307 seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags); 404 seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags);
405 if (tcon->perf_sector_size)
406 seq_printf(m, "\tOptimal sector size: 0x%x",
407 tcon->perf_sector_size);
308} 408}
309 409
310static void 410static void
@@ -446,6 +546,14 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
446} 546}
447 547
448static int 548static int
549smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
550 struct cifsFileInfo *cfile)
551{
552 return SMB2_set_compression(xid, tcon, cfile->fid.persistent_fid,
553 cfile->fid.volatile_fid);
554}
555
556static int
449smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, 557smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
450 const char *path, struct cifs_sb_info *cifs_sb, 558 const char *path, struct cifs_sb_info *cifs_sb,
451 struct cifs_fid *fid, __u16 search_flags, 559 struct cifs_fid *fid, __u16 search_flags,
@@ -865,6 +973,7 @@ struct smb_version_operations smb20_operations = {
865 .logoff = SMB2_logoff, 973 .logoff = SMB2_logoff,
866 .tree_connect = SMB2_tcon, 974 .tree_connect = SMB2_tcon,
867 .tree_disconnect = SMB2_tdis, 975 .tree_disconnect = SMB2_tdis,
976 .qfs_tcon = smb2_qfs_tcon,
868 .is_path_accessible = smb2_is_path_accessible, 977 .is_path_accessible = smb2_is_path_accessible,
869 .can_echo = smb2_can_echo, 978 .can_echo = smb2_can_echo,
870 .echo = SMB2_echo, 979 .echo = SMB2_echo,
@@ -874,6 +983,7 @@ struct smb_version_operations smb20_operations = {
874 .set_path_size = smb2_set_path_size, 983 .set_path_size = smb2_set_path_size,
875 .set_file_size = smb2_set_file_size, 984 .set_file_size = smb2_set_file_size,
876 .set_file_info = smb2_set_file_info, 985 .set_file_info = smb2_set_file_info,
986 .set_compression = smb2_set_compression,
877 .mkdir = smb2_mkdir, 987 .mkdir = smb2_mkdir,
878 .mkdir_setinfo = smb2_mkdir_setinfo, 988 .mkdir_setinfo = smb2_mkdir_setinfo,
879 .rmdir = smb2_rmdir, 989 .rmdir = smb2_rmdir,
@@ -936,6 +1046,7 @@ struct smb_version_operations smb21_operations = {
936 .logoff = SMB2_logoff, 1046 .logoff = SMB2_logoff,
937 .tree_connect = SMB2_tcon, 1047 .tree_connect = SMB2_tcon,
938 .tree_disconnect = SMB2_tdis, 1048 .tree_disconnect = SMB2_tdis,
1049 .qfs_tcon = smb2_qfs_tcon,
939 .is_path_accessible = smb2_is_path_accessible, 1050 .is_path_accessible = smb2_is_path_accessible,
940 .can_echo = smb2_can_echo, 1051 .can_echo = smb2_can_echo,
941 .echo = SMB2_echo, 1052 .echo = SMB2_echo,
@@ -945,6 +1056,7 @@ struct smb_version_operations smb21_operations = {
945 .set_path_size = smb2_set_path_size, 1056 .set_path_size = smb2_set_path_size,
946 .set_file_size = smb2_set_file_size, 1057 .set_file_size = smb2_set_file_size,
947 .set_file_info = smb2_set_file_info, 1058 .set_file_info = smb2_set_file_info,
1059 .set_compression = smb2_set_compression,
948 .mkdir = smb2_mkdir, 1060 .mkdir = smb2_mkdir,
949 .mkdir_setinfo = smb2_mkdir_setinfo, 1061 .mkdir_setinfo = smb2_mkdir_setinfo,
950 .rmdir = smb2_rmdir, 1062 .rmdir = smb2_rmdir,
@@ -1008,6 +1120,7 @@ struct smb_version_operations smb30_operations = {
1008 .logoff = SMB2_logoff, 1120 .logoff = SMB2_logoff,
1009 .tree_connect = SMB2_tcon, 1121 .tree_connect = SMB2_tcon,
1010 .tree_disconnect = SMB2_tdis, 1122 .tree_disconnect = SMB2_tdis,
1123 .qfs_tcon = smb3_qfs_tcon,
1011 .is_path_accessible = smb2_is_path_accessible, 1124 .is_path_accessible = smb2_is_path_accessible,
1012 .can_echo = smb2_can_echo, 1125 .can_echo = smb2_can_echo,
1013 .echo = SMB2_echo, 1126 .echo = SMB2_echo,
@@ -1017,6 +1130,7 @@ struct smb_version_operations smb30_operations = {
1017 .set_path_size = smb2_set_path_size, 1130 .set_path_size = smb2_set_path_size,
1018 .set_file_size = smb2_set_file_size, 1131 .set_file_size = smb2_set_file_size,
1019 .set_file_info = smb2_set_file_info, 1132 .set_file_info = smb2_set_file_info,
1133 .set_compression = smb2_set_compression,
1020 .mkdir = smb2_mkdir, 1134 .mkdir = smb2_mkdir,
1021 .mkdir_setinfo = smb2_mkdir_setinfo, 1135 .mkdir_setinfo = smb2_mkdir_setinfo,
1022 .rmdir = smb2_rmdir, 1136 .rmdir = smb2_rmdir,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index edccb5252462..8ab05b0d6778 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1137,6 +1137,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
1137 1137
1138 cifs_dbg(FYI, "SMB2 IOCTL\n"); 1138 cifs_dbg(FYI, "SMB2 IOCTL\n");
1139 1139
1140 *out_data = NULL;
1140 /* zero out returned data len, in case of error */ 1141 /* zero out returned data len, in case of error */
1141 if (plen) 1142 if (plen)
1142 *plen = 0; 1143 *plen = 0;
@@ -1182,11 +1183,23 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
1182 req->Flags = 0; 1183 req->Flags = 0;
1183 1184
1184 iov[0].iov_base = (char *)req; 1185 iov[0].iov_base = (char *)req;
1185 /* 4 for rfc1002 length field */
1186 iov[0].iov_len = get_rfc1002_length(req) + 4;
1187 1186
1188 if (indatalen) 1187 /*
1189 inc_rfc1001_len(req, indatalen); 1188 * If no input data, the size of ioctl struct in
1189 * protocol spec still includes a 1 byte data buffer,
1190 * but if input data passed to ioctl, we do not
1191 * want to double count this, so we do not send
1192 * the dummy one byte of data in iovec[0] if sending
1193 * input data (in iovec[1]). We also must add 4 bytes
1194 * in first iovec to allow for rfc1002 length field.
1195 */
1196
1197 if (indatalen) {
1198 iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
1199 inc_rfc1001_len(req, indatalen - 1);
1200 } else
1201 iov[0].iov_len = get_rfc1002_length(req) + 4;
1202
1190 1203
1191 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); 1204 rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
1192 rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; 1205 rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
@@ -1234,6 +1247,33 @@ ioctl_exit:
1234 return rc; 1247 return rc;
1235} 1248}
1236 1249
1250/*
1251 * Individual callers to ioctl worker function follow
1252 */
1253
1254int
1255SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
1256 u64 persistent_fid, u64 volatile_fid)
1257{
1258 int rc;
1259 char *res_key = NULL;
1260 struct compress_ioctl fsctl_input;
1261 char *ret_data = NULL;
1262
1263 fsctl_input.CompressionState =
1264 __constant_cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
1265
1266 rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
1267 FSCTL_SET_COMPRESSION, true /* is_fsctl */,
1268 (char *)&fsctl_input /* data input */,
1269 2 /* in data len */, &ret_data /* out data */, NULL);
1270
1271 cifs_dbg(FYI, "set compression rc %d\n", rc);
1272 kfree(res_key);
1273
1274 return rc;
1275}
1276
1237int 1277int
1238SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 1278SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
1239 u64 persistent_fid, u64 volatile_fid) 1279 u64 persistent_fid, u64 volatile_fid)
@@ -2299,7 +2339,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
2299 rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0); 2339 rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
2300 if (rc) { 2340 if (rc) {
2301 cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); 2341 cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
2302 goto qinf_exit; 2342 goto qfsinf_exit;
2303 } 2343 }
2304 rsp = (struct smb2_query_info_rsp *)iov.iov_base; 2344 rsp = (struct smb2_query_info_rsp *)iov.iov_base;
2305 2345
@@ -2311,7 +2351,70 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
2311 if (!rc) 2351 if (!rc)
2312 copy_fs_info_to_kstatfs(info, fsdata); 2352 copy_fs_info_to_kstatfs(info, fsdata);
2313 2353
2314qinf_exit: 2354qfsinf_exit:
2355 free_rsp_buf(resp_buftype, iov.iov_base);
2356 return rc;
2357}
2358
2359int
2360SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
2361 u64 persistent_fid, u64 volatile_fid, int level)
2362{
2363 struct smb2_query_info_rsp *rsp = NULL;
2364 struct kvec iov;
2365 int rc = 0;
2366 int resp_buftype, max_len, min_len;
2367 struct cifs_ses *ses = tcon->ses;
2368 unsigned int rsp_len, offset;
2369
2370 if (level == FS_DEVICE_INFORMATION) {
2371 max_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
2372 min_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
2373 } else if (level == FS_ATTRIBUTE_INFORMATION) {
2374 max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO);
2375 min_len = MIN_FS_ATTR_INFO_SIZE;
2376 } else if (level == FS_SECTOR_SIZE_INFORMATION) {
2377 max_len = sizeof(struct smb3_fs_ss_info);
2378 min_len = sizeof(struct smb3_fs_ss_info);
2379 } else {
2380 cifs_dbg(FYI, "Invalid qfsinfo level %d\n", level);
2381 return -EINVAL;
2382 }
2383
2384 rc = build_qfs_info_req(&iov, tcon, level, max_len,
2385 persistent_fid, volatile_fid);
2386 if (rc)
2387 return rc;
2388
2389 rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
2390 if (rc) {
2391 cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
2392 goto qfsattr_exit;
2393 }
2394 rsp = (struct smb2_query_info_rsp *)iov.iov_base;
2395
2396 rsp_len = le32_to_cpu(rsp->OutputBufferLength);
2397 offset = le16_to_cpu(rsp->OutputBufferOffset);
2398 rc = validate_buf(offset, rsp_len, &rsp->hdr, min_len);
2399 if (rc)
2400 goto qfsattr_exit;
2401
2402 if (level == FS_ATTRIBUTE_INFORMATION)
2403 memcpy(&tcon->fsAttrInfo, 4 /* RFC1001 len */ + offset
2404 + (char *)&rsp->hdr, min_t(unsigned int,
2405 rsp_len, max_len));
2406 else if (level == FS_DEVICE_INFORMATION)
2407 memcpy(&tcon->fsDevInfo, 4 /* RFC1001 len */ + offset
2408 + (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO));
2409 else if (level == FS_SECTOR_SIZE_INFORMATION) {
2410 struct smb3_fs_ss_info *ss_info = (struct smb3_fs_ss_info *)
2411 (4 /* RFC1001 len */ + offset + (char *)&rsp->hdr);
2412 tcon->ss_flags = le32_to_cpu(ss_info->Flags);
2413 tcon->perf_sector_size =
2414 le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf);
2415 }
2416
2417qfsattr_exit:
2315 free_rsp_buf(resp_buftype, iov.iov_base); 2418 free_rsp_buf(resp_buftype, iov.iov_base);
2316 return rc; 2419 return rc;
2317} 2420}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index b83d0118a757..6183b1b7550f 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -569,6 +569,10 @@ struct network_interface_info_ioctl_rsp {
569 569
570#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ 570#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
571 571
572struct compress_ioctl {
573 __le16 CompressionState; /* See cifspdu.h for possible flag values */
574} __packed;
575
572struct smb2_ioctl_req { 576struct smb2_ioctl_req {
573 struct smb2_hdr hdr; 577 struct smb2_hdr hdr;
574 __le16 StructureSize; /* Must be 57 */ 578 __le16 StructureSize; /* Must be 57 */
@@ -584,7 +588,7 @@ struct smb2_ioctl_req {
584 __le32 MaxOutputResponse; 588 __le32 MaxOutputResponse;
585 __le32 Flags; 589 __le32 Flags;
586 __u32 Reserved2; 590 __u32 Reserved2;
587 char Buffer[0]; 591 __u8 Buffer[0];
588} __packed; 592} __packed;
589 593
590struct smb2_ioctl_rsp { 594struct smb2_ioctl_rsp {
@@ -870,14 +874,16 @@ struct smb2_lease_ack {
870 874
871/* File System Information Classes */ 875/* File System Information Classes */
872#define FS_VOLUME_INFORMATION 1 /* Query */ 876#define FS_VOLUME_INFORMATION 1 /* Query */
873#define FS_LABEL_INFORMATION 2 /* Set */ 877#define FS_LABEL_INFORMATION 2 /* Local only */
874#define FS_SIZE_INFORMATION 3 /* Query */ 878#define FS_SIZE_INFORMATION 3 /* Query */
875#define FS_DEVICE_INFORMATION 4 /* Query */ 879#define FS_DEVICE_INFORMATION 4 /* Query */
876#define FS_ATTRIBUTE_INFORMATION 5 /* Query */ 880#define FS_ATTRIBUTE_INFORMATION 5 /* Query */
877#define FS_CONTROL_INFORMATION 6 /* Query, Set */ 881#define FS_CONTROL_INFORMATION 6 /* Query, Set */
878#define FS_FULL_SIZE_INFORMATION 7 /* Query */ 882#define FS_FULL_SIZE_INFORMATION 7 /* Query */
879#define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ 883#define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */
880#define FS_DRIVER_PATH_INFORMATION 9 /* Query */ 884#define FS_DRIVER_PATH_INFORMATION 9 /* Local only */
885#define FS_VOLUME_FLAGS_INFORMATION 10 /* Local only */
886#define FS_SECTOR_SIZE_INFORMATION 11 /* SMB3 or later. Query */
881 887
882struct smb2_fs_full_size_info { 888struct smb2_fs_full_size_info {
883 __le64 TotalAllocationUnits; 889 __le64 TotalAllocationUnits;
@@ -887,6 +893,22 @@ struct smb2_fs_full_size_info {
887 __le32 BytesPerSector; 893 __le32 BytesPerSector;
888} __packed; 894} __packed;
889 895
896#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001
897#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002
898#define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004
899#define SSINFO_FLAGS_TRIM_ENABLED 0x00000008
900
901/* sector size info struct */
902struct smb3_fs_ss_info {
903 __le32 LogicalBytesPerSector;
904 __le32 PhysicalBytesPerSectorForAtomicity;
905 __le32 PhysicalBytesPerSectorForPerf;
906 __le32 FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
907 __le32 Flags;
908 __le32 ByteOffsetForSectorAlignment;
909 __le32 ByteOffsetForPartitionAlignment;
910} __packed;
911
890/* partial list of QUERY INFO levels */ 912/* partial list of QUERY INFO levels */
891#define FILE_DIRECTORY_INFORMATION 1 913#define FILE_DIRECTORY_INFORMATION 1
892#define FILE_FULL_DIRECTORY_INFORMATION 2 914#define FILE_FULL_DIRECTORY_INFORMATION 2
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index e3fb4801ee96..313813e4c19b 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -142,12 +142,16 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
142extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, 142extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
143 u64 persistent_fid, u64 volatile_fid, 143 u64 persistent_fid, u64 volatile_fid,
144 FILE_BASIC_INFO *buf); 144 FILE_BASIC_INFO *buf);
145extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
146 u64 persistent_fid, u64 volatile_fid);
145extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, 147extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
146 const u64 persistent_fid, const u64 volatile_fid, 148 const u64 persistent_fid, const u64 volatile_fid,
147 const __u8 oplock_level); 149 const __u8 oplock_level);
148extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, 150extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
149 u64 persistent_file_id, u64 volatile_file_id, 151 u64 persistent_file_id, u64 volatile_file_id,
150 struct kstatfs *FSData); 152 struct kstatfs *FSData);
153extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
154 u64 persistent_file_id, u64 volatile_file_id, int lvl);
151extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, 155extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
152 const __u64 persist_fid, const __u64 volatile_fid, 156 const __u64 persist_fid, const __u64 volatile_fid,
153 const __u32 pid, const __u64 length, const __u64 offset, 157 const __u32 pid, const __u64 length, const __u64 offset,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 340abca3aa52..59c748ce872f 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -466,7 +466,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
466static inline void 466static inline void
467smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) 467smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
468{ 468{
469 hdr->MessageId = get_next_mid(server); 469 hdr->MessageId = get_next_mid64(server);
470} 470}
471 471
472static struct mid_q_entry * 472static struct mid_q_entry *
@@ -516,13 +516,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
516 return -EAGAIN; 516 return -EAGAIN;
517 } 517 }
518 518
519 if (ses->status != CifsGood) { 519 if (ses->status == CifsNew) {
520 /* check if SMB2 session is bad because we are setting it up */
521 if ((buf->Command != SMB2_SESSION_SETUP) && 520 if ((buf->Command != SMB2_SESSION_SETUP) &&
522 (buf->Command != SMB2_NEGOTIATE)) 521 (buf->Command != SMB2_NEGOTIATE))
523 return -EAGAIN; 522 return -EAGAIN;
524 /* else ok - we are setting up session */ 523 /* else ok - we are setting up session */
525 } 524 }
525
526 if (ses->status == CifsExiting) {
527 if (buf->Command != SMB2_LOGOFF)
528 return -EAGAIN;
529 /* else ok - we are shutting down the session */
530 }
531
526 *mid = smb2_mid_entry_alloc(buf, ses->server); 532 *mid = smb2_mid_entry_alloc(buf, ses->server);
527 if (*mid == NULL) 533 if (*mid == NULL)
528 return -ENOMEM; 534 return -ENOMEM;
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 800b938e4061..b37570952846 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -58,7 +58,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
58 return temp; 58 return temp;
59 else { 59 else {
60 memset(temp, 0, sizeof(struct mid_q_entry)); 60 memset(temp, 0, sizeof(struct mid_q_entry));
61 temp->mid = smb_buffer->Mid; /* always LE */ 61 temp->mid = get_mid(smb_buffer);
62 temp->pid = current->pid; 62 temp->pid = current->pid;
63 temp->command = cpu_to_le16(smb_buffer->Command); 63 temp->command = cpu_to_le16(smb_buffer->Command);
64 cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command); 64 cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
@@ -431,13 +431,20 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf,
431 return -EAGAIN; 431 return -EAGAIN;
432 } 432 }
433 433
434 if (ses->status != CifsGood) { 434 if (ses->status == CifsNew) {
435 /* check if SMB session is bad because we are setting it up */
436 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && 435 if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
437 (in_buf->Command != SMB_COM_NEGOTIATE)) 436 (in_buf->Command != SMB_COM_NEGOTIATE))
438 return -EAGAIN; 437 return -EAGAIN;
439 /* else ok - we are setting up session */ 438 /* else ok - we are setting up session */
440 } 439 }
440
441 if (ses->status == CifsExiting) {
442 /* check if SMB session is bad because we are setting it up */
443 if (in_buf->Command != SMB_COM_LOGOFF_ANDX)
444 return -EAGAIN;
445 /* else ok - we are shutting down session */
446 }
447
441 *ppmidQ = AllocMidQEntry(in_buf, ses->server); 448 *ppmidQ = AllocMidQEntry(in_buf, ses->server);
442 if (*ppmidQ == NULL) 449 if (*ppmidQ == NULL)
443 return -ENOMEM; 450 return -ENOMEM;