diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 16:01:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 16:01:47 -0500 |
commit | 8efdf2b759409f85953b84d52a14ea4d39c80474 (patch) | |
tree | 237cfcc537fe7840a3c81660740f6073fae63c75 /fs/cifs | |
parent | c224b76b560f3c65f0d10fbb59d3f00379eb0aaf (diff) | |
parent | c481e9feee78c6ce1ba0a1c8c892049f6514f6cf (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.h | 29 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 34 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 54 | ||||
-rw-r--r-- | fs/cifs/connect.c | 25 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 57 | ||||
-rw-r--r-- | fs/cifs/misc.c | 22 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 12 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 114 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 115 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 28 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 4 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 12 | ||||
-rw-r--r-- | fs/cifs/transport.c | 13 |
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 | ||
622 | static inline __u64 | 624 | static inline __u64 |
623 | get_next_mid(struct TCP_Server_Info *server) | 625 | get_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 | ||
630 | static inline __le16 | ||
631 | get_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 | |||
641 | static inline __u16 | ||
642 | get_mid(const struct smb_hdr *smb) | ||
643 | { | ||
644 | return le16_to_cpu(smb->Mid); | ||
645 | } | ||
646 | |||
647 | static inline bool | ||
648 | compare_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 | ||
1355 | typedef 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 | |||
1355 | typedef struct smb_com_transaction_ioctl_rsp { | 1384 | typedef 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 | |||
2218 | typedef struct { | 2250 | typedef 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, | |||
360 | extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 360 | extern 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); |
363 | extern int CIFSSMB_set_compression(const unsigned int xid, | ||
364 | struct cifs_tcon *tcon, __u16 fid); | ||
363 | extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, | 365 | extern 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 | ||
3202 | int | ||
3203 | CIFSSMB_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) | |||
2255 | static void | 2257 | static void |
2256 | cifs_put_smb_ses(struct cifs_ses *ses) | 2258 | cifs_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 | ||
280 | static int | 280 | static int |
281 | check_smb_hdr(struct smb_hdr *smb, __u16 mid) | 281 | check_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 | |||
310 | checkSMB(char *buf, unsigned int total_read) | 304 | checkSMB(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 | ||
809 | static int | 809 | static int |
810 | cifs_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 | |||
816 | static int | ||
810 | cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, | 817 | cifs_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 | ||
213 | static int | ||
214 | SMB3_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 | |||
238 | static void | ||
239 | smb3_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 | |||
272 | static void | ||
273 | smb2_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 | |||
212 | static int | 300 | static int |
213 | smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, | 301 | smb2_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 | ||
310 | static void | 410 | static void |
@@ -446,6 +546,14 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, | |||
446 | } | 546 | } |
447 | 547 | ||
448 | static int | 548 | static int |
549 | smb2_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 | |||
556 | static int | ||
449 | smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, | 557 | smb2_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 | |||
1254 | int | ||
1255 | SMB2_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 | |||
1237 | int | 1277 | int |
1238 | SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, | 1278 | SMB2_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 | ||
2314 | qinf_exit: | 2354 | qfsinf_exit: |
2355 | free_rsp_buf(resp_buftype, iov.iov_base); | ||
2356 | return rc; | ||
2357 | } | ||
2358 | |||
2359 | int | ||
2360 | SMB2_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 | |||
2417 | qfsattr_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 | ||
572 | struct compress_ioctl { | ||
573 | __le16 CompressionState; /* See cifspdu.h for possible flag values */ | ||
574 | } __packed; | ||
575 | |||
572 | struct smb2_ioctl_req { | 576 | struct 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 | ||
590 | struct smb2_ioctl_rsp { | 594 | struct 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 | ||
882 | struct smb2_fs_full_size_info { | 888 | struct 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 */ | ||
902 | struct 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, | |||
142 | extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, | 142 | extern 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); |
145 | extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, | ||
146 | u64 persistent_fid, u64 volatile_fid); | ||
145 | extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, | 147 | extern 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); |
148 | extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, | 150 | extern 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); |
153 | extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, | ||
154 | u64 persistent_file_id, u64 volatile_file_id, int lvl); | ||
151 | extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, | 155 | extern 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) | |||
466 | static inline void | 466 | static inline void |
467 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) | 467 | smb2_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 | ||
472 | static struct mid_q_entry * | 472 | static 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; |