diff options
-rw-r--r-- | Documentation/filesystems/cifs/AUTHORS | 1 | ||||
-rw-r--r-- | Documentation/filesystems/cifs/TODO | 97 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 19 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 119 | ||||
-rw-r--r-- | fs/cifs/connect.c | 8 | ||||
-rw-r--r-- | fs/cifs/file.c | 872 | ||||
-rw-r--r-- | fs/cifs/misc.c | 13 | ||||
-rw-r--r-- | fs/cifs/sess.c | 1192 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 8 | ||||
-rw-r--r-- | fs/cifs/smb2inode.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb2maperror.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 6 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 73 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 94 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 2 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 5 | ||||
-rw-r--r-- | fs/cifs/transport.c | 25 |
20 files changed, 1702 insertions, 844 deletions
diff --git a/Documentation/filesystems/cifs/AUTHORS b/Documentation/filesystems/cifs/AUTHORS index ca4a67a0bb1e..c98800df677f 100644 --- a/Documentation/filesystems/cifs/AUTHORS +++ b/Documentation/filesystems/cifs/AUTHORS | |||
@@ -40,6 +40,7 @@ Gunter Kukkukk (testing and suggestions for support of old servers) | |||
40 | Igor Mammedov (DFS support) | 40 | Igor Mammedov (DFS support) |
41 | Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) | 41 | Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) |
42 | Scott Lovenberg | 42 | Scott Lovenberg |
43 | Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features) | ||
43 | 44 | ||
44 | Test case and Bug Report contributors | 45 | Test case and Bug Report contributors |
45 | ------------------------------------- | 46 | ------------------------------------- |
diff --git a/Documentation/filesystems/cifs/TODO b/Documentation/filesystems/cifs/TODO index 355abcdcda98..066ffddc3964 100644 --- a/Documentation/filesystems/cifs/TODO +++ b/Documentation/filesystems/cifs/TODO | |||
@@ -1,4 +1,4 @@ | |||
1 | Version 1.53 May 20, 2008 | 1 | Version 2.03 August 1, 2014 |
2 | 2 | ||
3 | A Partial List of Missing Features | 3 | A Partial List of Missing Features |
4 | ================================== | 4 | ================================== |
@@ -7,63 +7,49 @@ Contributions are welcome. There are plenty of opportunities | |||
7 | for visible, important contributions to this module. Here | 7 | for visible, important contributions to this module. Here |
8 | is a partial list of the known problems and missing features: | 8 | is a partial list of the known problems and missing features: |
9 | 9 | ||
10 | a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown | 10 | a) SMB3 (and SMB3.02) missing optional features: |
11 | so that these operations can be supported to Windows servers | 11 | - RDMA |
12 | - multichannel (started) | ||
13 | - directory leases (improved metadata caching) | ||
14 | - T10 copy offload (copy chunk is only mechanism supported) | ||
15 | - encrypted shares | ||
12 | 16 | ||
13 | b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS | 17 | b) improved sparse file support |
14 | SecurityDescriptors | ||
15 | 18 | ||
16 | c) Better pam/winbind integration (e.g. to handle uid mapping | 19 | c) Directory entry caching relies on a 1 second timer, rather than |
17 | better) | ||
18 | |||
19 | d) Cleanup now unneeded SessSetup code in | ||
20 | fs/cifs/connect.c and add back in NTLMSSP code if any servers | ||
21 | need it | ||
22 | |||
23 | e) fix NTLMv2 signing when two mounts with different users to same | ||
24 | server. | ||
25 | |||
26 | f) Directory entry caching relies on a 1 second timer, rather than | ||
27 | using FindNotify or equivalent. - (started) | 20 | using FindNotify or equivalent. - (started) |
28 | 21 | ||
29 | g) quota support (needs minor kernel change since quota calls | 22 | d) quota support (needs minor kernel change since quota calls |
30 | to make it to network filesystems or deviceless filesystems) | 23 | to make it to network filesystems or deviceless filesystems) |
31 | 24 | ||
32 | h) investigate sync behavior (including syncpage) and check | 25 | e) improve support for very old servers (OS/2 and Win9x for example) |
33 | for proper behavior of intr/nointr | ||
34 | |||
35 | i) improve support for very old servers (OS/2 and Win9x for example) | ||
36 | Including support for changing the time remotely (utimes command). | 26 | Including support for changing the time remotely (utimes command). |
37 | 27 | ||
38 | j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the | 28 | f) hook lower into the sockets api (as NFS/SunRPC does) to avoid the |
39 | extra copy in/out of the socket buffers in some cases. | 29 | extra copy in/out of the socket buffers in some cases. |
40 | 30 | ||
41 | k) Better optimize open (and pathbased setfilesize) to reduce the | 31 | g) Better optimize open (and pathbased setfilesize) to reduce the |
42 | oplock breaks coming from windows srv. Piggyback identical file | 32 | oplock breaks coming from windows srv. Piggyback identical file |
43 | opens on top of each other by incrementing reference count rather | 33 | opens on top of each other by incrementing reference count rather |
44 | than resending (helps reduce server resource utilization and avoid | 34 | than resending (helps reduce server resource utilization and avoid |
45 | spurious oplock breaks). | 35 | spurious oplock breaks). |
46 | 36 | ||
47 | l) Improve performance of readpages by sending more than one read | 37 | h) Add support for storing symlink info to Windows servers |
48 | at a time when 8 pages or more are requested. In conjuntion | ||
49 | add support for async_cifs_readpages. | ||
50 | |||
51 | m) Add support for storing symlink info to Windows servers | ||
52 | in the Extended Attribute format their SFU clients would recognize. | 38 | in the Extended Attribute format their SFU clients would recognize. |
53 | 39 | ||
54 | n) Finish fcntl D_NOTIFY support so kde and gnome file list windows | 40 | i) Finish inotify support so kde and gnome file list windows |
55 | will autorefresh (partially complete by Asser). Needs minor kernel | 41 | will autorefresh (partially complete by Asser). Needs minor kernel |
56 | vfs change to support removing D_NOTIFY on a file. | 42 | vfs change to support removing D_NOTIFY on a file. |
57 | 43 | ||
58 | o) Add GUI tool to configure /proc/fs/cifs settings and for display of | 44 | j) Add GUI tool to configure /proc/fs/cifs settings and for display of |
59 | the CIFS statistics (started) | 45 | the CIFS statistics (started) |
60 | 46 | ||
61 | p) implement support for security and trusted categories of xattrs | 47 | k) implement support for security and trusted categories of xattrs |
62 | (requires minor protocol extension) to enable better support for SELINUX | 48 | (requires minor protocol extension) to enable better support for SELINUX |
63 | 49 | ||
64 | q) Implement O_DIRECT flag on open (already supported on mount) | 50 | l) Implement O_DIRECT flag on open (already supported on mount) |
65 | 51 | ||
66 | r) Create UID mapping facility so server UIDs can be mapped on a per | 52 | m) Create UID mapping facility so server UIDs can be mapped on a per |
67 | mount or a per server basis to client UIDs or nobody if no mapping | 53 | mount or a per server basis to client UIDs or nobody if no mapping |
68 | exists. This is helpful when Unix extensions are negotiated to | 54 | exists. This is helpful when Unix extensions are negotiated to |
69 | allow better permission checking when UIDs differ on the server | 55 | allow better permission checking when UIDs differ on the server |
@@ -71,28 +57,29 @@ and client. Add new protocol request to the CIFS protocol | |||
71 | standard for asking the server for the corresponding name of a | 57 | standard for asking the server for the corresponding name of a |
72 | particular uid. | 58 | particular uid. |
73 | 59 | ||
74 | s) Add support for CIFS Unix and also the newer POSIX extensions to the | 60 | n) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too) |
75 | server side for Samba 4. | 61 | |
62 | o) mount check for unmatched uids | ||
76 | 63 | ||
77 | t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) | 64 | p) Add support for new vfs entry point for fallocate |
78 | need to add ability to set time to server (utimes command) | ||
79 | 65 | ||
80 | u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too) | 66 | q) Add tools to take advantage of cifs/smb3 specific ioctls and features |
67 | such as "CopyChunk" (fast server side file copy) | ||
81 | 68 | ||
82 | v) mount check for unmatched uids | 69 | r) encrypted file support |
83 | 70 | ||
84 | w) Add support for new vfs entry point for fallocate | 71 | s) improved stats gathering, tools (perhaps integration with nfsometer?) |
85 | 72 | ||
86 | x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of | 73 | t) allow setting more NTFS/SMB3 file attributes remotely (currently limited to compressed |
87 | processes can proceed better in parallel (on the server) | 74 | file attribute via chflags) |
88 | 75 | ||
89 | y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount | 76 | u) mount helper GUI (to simplify the various configuration options on mount) |
90 | restriction of wsize max being 127K) | ||
91 | 77 | ||
92 | KNOWN BUGS (updated April 24, 2007) | 78 | |
79 | KNOWN BUGS | ||
93 | ==================================== | 80 | ==================================== |
94 | See http://bugzilla.samba.org - search on product "CifsVFS" for | 81 | See http://bugzilla.samba.org - search on product "CifsVFS" for |
95 | current bug list. | 82 | current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS) |
96 | 83 | ||
97 | 1) existing symbolic links (Windows reparse points) are recognized but | 84 | 1) existing symbolic links (Windows reparse points) are recognized but |
98 | can not be created remotely. They are implemented for Samba and those that | 85 | can not be created remotely. They are implemented for Samba and those that |
@@ -100,30 +87,18 @@ support the CIFS Unix extensions, although earlier versions of Samba | |||
100 | overly restrict the pathnames. | 87 | overly restrict the pathnames. |
101 | 2) follow_link and readdir code does not follow dfs junctions | 88 | 2) follow_link and readdir code does not follow dfs junctions |
102 | but recognizes them | 89 | but recognizes them |
103 | 3) create of new files to FAT partitions on Windows servers can | ||
104 | succeed but still return access denied (appears to be Windows | ||
105 | server not cifs client problem) and has not been reproduced recently. | ||
106 | NTFS partitions do not have this problem. | ||
107 | 4) Unix/POSIX capabilities are reset after reconnection, and affect | ||
108 | a few fields in the tree connection but we do do not know which | ||
109 | superblocks to apply these changes to. We should probably walk | ||
110 | the list of superblocks to set these. Also need to check the | ||
111 | flags on the second mount to the same share, and see if we | ||
112 | can do the same trick that NFS does to remount duplicate shares. | ||
113 | 90 | ||
114 | Misc testing to do | 91 | Misc testing to do |
115 | ================== | 92 | ================== |
116 | 1) check out max path names and max path name components against various server | 93 | 1) check out max path names and max path name components against various server |
117 | types. Try nested symlinks (8 deep). Return max path name in stat -f information | 94 | types. Try nested symlinks (8 deep). Return max path name in stat -f information |
118 | 95 | ||
119 | 2) Modify file portion of ltp so it can run against a mounted network | 96 | 2) Improve xfstest's cifs enablement and adapt xfstests where needed to test |
120 | share and run it against cifs vfs in automated fashion. | 97 | cifs better |
121 | 98 | ||
122 | 3) Additional performance testing and optimization using iozone and similar - | 99 | 3) Additional performance testing and optimization using iozone and similar - |
123 | there are some easy changes that can be done to parallelize sequential writes, | 100 | there are some easy changes that can be done to parallelize sequential writes, |
124 | and when signing is disabled to request larger read sizes (larger than | 101 | and when signing is disabled to request larger read sizes (larger than |
125 | negotiated size) and send larger write sizes to modern servers. | 102 | negotiated size) and send larger write sizes to modern servers. |
126 | 103 | ||
127 | 4) More exhaustively test against less common servers. More testing | 104 | 4) More exhaustively test against less common servers |
128 | against Windows 9x, Windows ME servers. | ||
129 | |||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index f3ac4154cbb6..44ec72684df5 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -213,7 +213,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
213 | tcon->nativeFileSystem); | 213 | tcon->nativeFileSystem); |
214 | } | 214 | } |
215 | seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" | 215 | seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" |
216 | "\n\tPathComponentMax: %d Status: 0x%d", | 216 | "\n\tPathComponentMax: %d Status: %d", |
217 | le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), | 217 | le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), |
218 | le32_to_cpu(tcon->fsAttrInfo.Attributes), | 218 | le32_to_cpu(tcon->fsAttrInfo.Attributes), |
219 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), | 219 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 70f178a7c759..560480263336 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -136,5 +136,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
136 | extern const struct export_operations cifs_export_ops; | 136 | extern const struct export_operations cifs_export_ops; |
137 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ | 137 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ |
138 | 138 | ||
139 | #define CIFS_VERSION "2.03" | 139 | #define CIFS_VERSION "2.04" |
140 | #endif /* _CIFSFS_H */ | 140 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index de6aed8c78e5..0012e1e291d4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -404,6 +404,11 @@ struct smb_version_operations { | |||
404 | const struct cifs_fid *, u32 *); | 404 | const struct cifs_fid *, u32 *); |
405 | int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, | 405 | int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, |
406 | int); | 406 | int); |
407 | /* writepages retry size */ | ||
408 | unsigned int (*wp_retry_size)(struct inode *); | ||
409 | /* get mtu credits */ | ||
410 | int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, | ||
411 | unsigned int *, unsigned int *); | ||
407 | }; | 412 | }; |
408 | 413 | ||
409 | struct smb_version_values { | 414 | struct smb_version_values { |
@@ -640,6 +645,16 @@ add_credits(struct TCP_Server_Info *server, const unsigned int add, | |||
640 | } | 645 | } |
641 | 646 | ||
642 | static inline void | 647 | static inline void |
648 | add_credits_and_wake_if(struct TCP_Server_Info *server, const unsigned int add, | ||
649 | const int optype) | ||
650 | { | ||
651 | if (add) { | ||
652 | server->ops->add_credits(server, add, optype); | ||
653 | wake_up(&server->request_q); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | static inline void | ||
643 | set_credits(struct TCP_Server_Info *server, const int val) | 658 | set_credits(struct TCP_Server_Info *server, const int val) |
644 | { | 659 | { |
645 | server->ops->set_credits(server, val); | 660 | server->ops->set_credits(server, val); |
@@ -1044,6 +1059,7 @@ struct cifs_readdata { | |||
1044 | struct address_space *mapping; | 1059 | struct address_space *mapping; |
1045 | __u64 offset; | 1060 | __u64 offset; |
1046 | unsigned int bytes; | 1061 | unsigned int bytes; |
1062 | unsigned int got_bytes; | ||
1047 | pid_t pid; | 1063 | pid_t pid; |
1048 | int result; | 1064 | int result; |
1049 | struct work_struct work; | 1065 | struct work_struct work; |
@@ -1053,6 +1069,7 @@ struct cifs_readdata { | |||
1053 | struct kvec iov; | 1069 | struct kvec iov; |
1054 | unsigned int pagesz; | 1070 | unsigned int pagesz; |
1055 | unsigned int tailsz; | 1071 | unsigned int tailsz; |
1072 | unsigned int credits; | ||
1056 | unsigned int nr_pages; | 1073 | unsigned int nr_pages; |
1057 | struct page *pages[]; | 1074 | struct page *pages[]; |
1058 | }; | 1075 | }; |
@@ -1073,6 +1090,7 @@ struct cifs_writedata { | |||
1073 | int result; | 1090 | int result; |
1074 | unsigned int pagesz; | 1091 | unsigned int pagesz; |
1075 | unsigned int tailsz; | 1092 | unsigned int tailsz; |
1093 | unsigned int credits; | ||
1076 | unsigned int nr_pages; | 1094 | unsigned int nr_pages; |
1077 | struct page *pages[]; | 1095 | struct page *pages[]; |
1078 | }; | 1096 | }; |
@@ -1398,6 +1416,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
1398 | #define CIFS_OBREAK_OP 0x0100 /* oplock break request */ | 1416 | #define CIFS_OBREAK_OP 0x0100 /* oplock break request */ |
1399 | #define CIFS_NEG_OP 0x0200 /* negotiate request */ | 1417 | #define CIFS_NEG_OP 0x0200 /* negotiate request */ |
1400 | #define CIFS_OP_MASK 0x0380 /* mask request type */ | 1418 | #define CIFS_OP_MASK 0x0380 /* mask request type */ |
1419 | #define CIFS_HAS_CREDITS 0x0400 /* already has credits */ | ||
1401 | 1420 | ||
1402 | /* Security Flags: indicate type of session setup needed */ | 1421 | /* Security Flags: indicate type of session setup needed */ |
1403 | #define CIFSSEC_MAY_SIGN 0x00001 | 1422 | #define CIFSSEC_MAY_SIGN 0x00001 |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ca7980a1e303..c31ce98c1704 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -36,6 +36,7 @@ extern struct smb_hdr *cifs_buf_get(void); | |||
36 | extern void cifs_buf_release(void *); | 36 | extern void cifs_buf_release(void *); |
37 | extern struct smb_hdr *cifs_small_buf_get(void); | 37 | extern struct smb_hdr *cifs_small_buf_get(void); |
38 | extern void cifs_small_buf_release(void *); | 38 | extern void cifs_small_buf_release(void *); |
39 | extern void free_rsp_buf(int, void *); | ||
39 | extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | 40 | extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, |
40 | struct kvec *iov); | 41 | struct kvec *iov); |
41 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, | 42 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, |
@@ -89,6 +90,9 @@ extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *, | |||
89 | struct smb_rqst *); | 90 | struct smb_rqst *); |
90 | extern int cifs_check_receive(struct mid_q_entry *mid, | 91 | extern int cifs_check_receive(struct mid_q_entry *mid, |
91 | struct TCP_Server_Info *server, bool log_error); | 92 | struct TCP_Server_Info *server, bool log_error); |
93 | extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, | ||
94 | unsigned int size, unsigned int *num, | ||
95 | unsigned int *credits); | ||
92 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, | 96 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, |
93 | struct kvec *, int /* nvec to send */, | 97 | struct kvec *, int /* nvec to send */, |
94 | int * /* type of buf returned */ , const int flags); | 98 | int * /* type of buf returned */ , const int flags); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6ce4e0954b98..66f65001a6d8 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -196,10 +196,6 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) | |||
196 | if (rc) | 196 | if (rc) |
197 | goto out; | 197 | goto out; |
198 | 198 | ||
199 | /* | ||
200 | * FIXME: check if wsize needs updated due to negotiated smb buffer | ||
201 | * size shrinking | ||
202 | */ | ||
203 | atomic_inc(&tconInfoReconnectCount); | 199 | atomic_inc(&tconInfoReconnectCount); |
204 | 200 | ||
205 | /* tell server Unix caps we support */ | 201 | /* tell server Unix caps we support */ |
@@ -1517,7 +1513,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1517 | return length; | 1513 | return length; |
1518 | 1514 | ||
1519 | server->total_read += length; | 1515 | server->total_read += length; |
1520 | rdata->bytes = length; | ||
1521 | 1516 | ||
1522 | cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n", | 1517 | cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n", |
1523 | server->total_read, buflen, data_len); | 1518 | server->total_read, buflen, data_len); |
@@ -1560,12 +1555,18 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
1560 | rc); | 1555 | rc); |
1561 | } | 1556 | } |
1562 | /* FIXME: should this be counted toward the initiating task? */ | 1557 | /* FIXME: should this be counted toward the initiating task? */ |
1563 | task_io_account_read(rdata->bytes); | 1558 | task_io_account_read(rdata->got_bytes); |
1564 | cifs_stats_bytes_read(tcon, rdata->bytes); | 1559 | cifs_stats_bytes_read(tcon, rdata->got_bytes); |
1565 | break; | 1560 | break; |
1566 | case MID_REQUEST_SUBMITTED: | 1561 | case MID_REQUEST_SUBMITTED: |
1567 | case MID_RETRY_NEEDED: | 1562 | case MID_RETRY_NEEDED: |
1568 | rdata->result = -EAGAIN; | 1563 | rdata->result = -EAGAIN; |
1564 | if (server->sign && rdata->got_bytes) | ||
1565 | /* reset bytes number since we can not check a sign */ | ||
1566 | rdata->got_bytes = 0; | ||
1567 | /* FIXME: should this be counted toward the initiating task? */ | ||
1568 | task_io_account_read(rdata->got_bytes); | ||
1569 | cifs_stats_bytes_read(tcon, rdata->got_bytes); | ||
1569 | break; | 1570 | break; |
1570 | default: | 1571 | default: |
1571 | rdata->result = -EIO; | 1572 | rdata->result = -EIO; |
@@ -1734,10 +1735,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
1734 | 1735 | ||
1735 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ | 1736 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ |
1736 | if (*buf) { | 1737 | if (*buf) { |
1737 | if (resp_buf_type == CIFS_SMALL_BUFFER) | 1738 | free_rsp_buf(resp_buf_type, iov[0].iov_base); |
1738 | cifs_small_buf_release(iov[0].iov_base); | ||
1739 | else if (resp_buf_type == CIFS_LARGE_BUFFER) | ||
1740 | cifs_buf_release(iov[0].iov_base); | ||
1741 | } else if (resp_buf_type != CIFS_NO_BUFFER) { | 1739 | } else if (resp_buf_type != CIFS_NO_BUFFER) { |
1742 | /* return buffer to caller to free */ | 1740 | /* return buffer to caller to free */ |
1743 | *buf = iov[0].iov_base; | 1741 | *buf = iov[0].iov_base; |
@@ -1899,28 +1897,80 @@ cifs_writedata_release(struct kref *refcount) | |||
1899 | static void | 1897 | static void |
1900 | cifs_writev_requeue(struct cifs_writedata *wdata) | 1898 | cifs_writev_requeue(struct cifs_writedata *wdata) |
1901 | { | 1899 | { |
1902 | int i, rc; | 1900 | int i, rc = 0; |
1903 | struct inode *inode = wdata->cfile->dentry->d_inode; | 1901 | struct inode *inode = wdata->cfile->dentry->d_inode; |
1904 | struct TCP_Server_Info *server; | 1902 | struct TCP_Server_Info *server; |
1903 | unsigned int rest_len; | ||
1905 | 1904 | ||
1906 | for (i = 0; i < wdata->nr_pages; i++) { | 1905 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; |
1907 | lock_page(wdata->pages[i]); | 1906 | i = 0; |
1908 | clear_page_dirty_for_io(wdata->pages[i]); | 1907 | rest_len = wdata->bytes; |
1909 | } | ||
1910 | |||
1911 | do { | 1908 | do { |
1912 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | 1909 | struct cifs_writedata *wdata2; |
1913 | rc = server->ops->async_writev(wdata, cifs_writedata_release); | 1910 | unsigned int j, nr_pages, wsize, tailsz, cur_len; |
1914 | } while (rc == -EAGAIN); | 1911 | |
1912 | wsize = server->ops->wp_retry_size(inode); | ||
1913 | if (wsize < rest_len) { | ||
1914 | nr_pages = wsize / PAGE_CACHE_SIZE; | ||
1915 | if (!nr_pages) { | ||
1916 | rc = -ENOTSUPP; | ||
1917 | break; | ||
1918 | } | ||
1919 | cur_len = nr_pages * PAGE_CACHE_SIZE; | ||
1920 | tailsz = PAGE_CACHE_SIZE; | ||
1921 | } else { | ||
1922 | nr_pages = DIV_ROUND_UP(rest_len, PAGE_CACHE_SIZE); | ||
1923 | cur_len = rest_len; | ||
1924 | tailsz = rest_len - (nr_pages - 1) * PAGE_CACHE_SIZE; | ||
1925 | } | ||
1915 | 1926 | ||
1916 | for (i = 0; i < wdata->nr_pages; i++) { | 1927 | wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete); |
1917 | unlock_page(wdata->pages[i]); | 1928 | if (!wdata2) { |
1918 | if (rc != 0) { | 1929 | rc = -ENOMEM; |
1919 | SetPageError(wdata->pages[i]); | 1930 | break; |
1920 | end_page_writeback(wdata->pages[i]); | ||
1921 | page_cache_release(wdata->pages[i]); | ||
1922 | } | 1931 | } |
1923 | } | 1932 | |
1933 | for (j = 0; j < nr_pages; j++) { | ||
1934 | wdata2->pages[j] = wdata->pages[i + j]; | ||
1935 | lock_page(wdata2->pages[j]); | ||
1936 | clear_page_dirty_for_io(wdata2->pages[j]); | ||
1937 | } | ||
1938 | |||
1939 | wdata2->sync_mode = wdata->sync_mode; | ||
1940 | wdata2->nr_pages = nr_pages; | ||
1941 | wdata2->offset = page_offset(wdata2->pages[0]); | ||
1942 | wdata2->pagesz = PAGE_CACHE_SIZE; | ||
1943 | wdata2->tailsz = tailsz; | ||
1944 | wdata2->bytes = cur_len; | ||
1945 | |||
1946 | wdata2->cfile = find_writable_file(CIFS_I(inode), false); | ||
1947 | if (!wdata2->cfile) { | ||
1948 | cifs_dbg(VFS, "No writable handles for inode\n"); | ||
1949 | rc = -EBADF; | ||
1950 | break; | ||
1951 | } | ||
1952 | wdata2->pid = wdata2->cfile->pid; | ||
1953 | rc = server->ops->async_writev(wdata2, cifs_writedata_release); | ||
1954 | |||
1955 | for (j = 0; j < nr_pages; j++) { | ||
1956 | unlock_page(wdata2->pages[j]); | ||
1957 | if (rc != 0 && rc != -EAGAIN) { | ||
1958 | SetPageError(wdata2->pages[j]); | ||
1959 | end_page_writeback(wdata2->pages[j]); | ||
1960 | page_cache_release(wdata2->pages[j]); | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | if (rc) { | ||
1965 | kref_put(&wdata2->refcount, cifs_writedata_release); | ||
1966 | if (rc == -EAGAIN) | ||
1967 | continue; | ||
1968 | break; | ||
1969 | } | ||
1970 | |||
1971 | rest_len -= cur_len; | ||
1972 | i += nr_pages; | ||
1973 | } while (i < wdata->nr_pages); | ||
1924 | 1974 | ||
1925 | mapping_set_error(inode->i_mapping, rc); | 1975 | mapping_set_error(inode->i_mapping, rc); |
1926 | kref_put(&wdata->refcount, cifs_writedata_release); | 1976 | kref_put(&wdata->refcount, cifs_writedata_release); |
@@ -2203,10 +2253,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
2203 | } | 2253 | } |
2204 | 2254 | ||
2205 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ | 2255 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ |
2206 | if (resp_buf_type == CIFS_SMALL_BUFFER) | 2256 | free_rsp_buf(resp_buf_type, iov[0].iov_base); |
2207 | cifs_small_buf_release(iov[0].iov_base); | ||
2208 | else if (resp_buf_type == CIFS_LARGE_BUFFER) | ||
2209 | cifs_buf_release(iov[0].iov_base); | ||
2210 | 2257 | ||
2211 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 2258 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
2212 | since file handle passed in no longer valid */ | 2259 | since file handle passed in no longer valid */ |
@@ -2451,10 +2498,7 @@ plk_err_exit: | |||
2451 | if (pSMB) | 2498 | if (pSMB) |
2452 | cifs_small_buf_release(pSMB); | 2499 | cifs_small_buf_release(pSMB); |
2453 | 2500 | ||
2454 | if (resp_buf_type == CIFS_SMALL_BUFFER) | 2501 | free_rsp_buf(resp_buf_type, iov[0].iov_base); |
2455 | cifs_small_buf_release(iov[0].iov_base); | ||
2456 | else if (resp_buf_type == CIFS_LARGE_BUFFER) | ||
2457 | cifs_buf_release(iov[0].iov_base); | ||
2458 | 2502 | ||
2459 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 2503 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
2460 | since file handle passed in no longer valid */ | 2504 | since file handle passed in no longer valid */ |
@@ -3838,10 +3882,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, | |||
3838 | } | 3882 | } |
3839 | } | 3883 | } |
3840 | qsec_out: | 3884 | qsec_out: |
3841 | if (buf_type == CIFS_SMALL_BUFFER) | 3885 | free_rsp_buf(buf_type, iov[0].iov_base); |
3842 | cifs_small_buf_release(iov[0].iov_base); | ||
3843 | else if (buf_type == CIFS_LARGE_BUFFER) | ||
3844 | cifs_buf_release(iov[0].iov_base); | ||
3845 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ | 3886 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ |
3846 | return rc; | 3887 | return rc; |
3847 | } | 3888 | } |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b98366f21f9e..03ed8a09581c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -557,7 +557,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | |||
557 | try_to_freeze(); | 557 | try_to_freeze(); |
558 | 558 | ||
559 | if (server_unresponsive(server)) { | 559 | if (server_unresponsive(server)) { |
560 | total_read = -EAGAIN; | 560 | total_read = -ECONNABORTED; |
561 | break; | 561 | break; |
562 | } | 562 | } |
563 | 563 | ||
@@ -571,7 +571,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | |||
571 | break; | 571 | break; |
572 | } else if (server->tcpStatus == CifsNeedReconnect) { | 572 | } else if (server->tcpStatus == CifsNeedReconnect) { |
573 | cifs_reconnect(server); | 573 | cifs_reconnect(server); |
574 | total_read = -EAGAIN; | 574 | total_read = -ECONNABORTED; |
575 | break; | 575 | break; |
576 | } else if (length == -ERESTARTSYS || | 576 | } else if (length == -ERESTARTSYS || |
577 | length == -EAGAIN || | 577 | length == -EAGAIN || |
@@ -588,7 +588,7 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | |||
588 | cifs_dbg(FYI, "Received no data or error: expecting %d\n" | 588 | cifs_dbg(FYI, "Received no data or error: expecting %d\n" |
589 | "got %d", to_read, length); | 589 | "got %d", to_read, length); |
590 | cifs_reconnect(server); | 590 | cifs_reconnect(server); |
591 | total_read = -EAGAIN; | 591 | total_read = -ECONNABORTED; |
592 | break; | 592 | break; |
593 | } | 593 | } |
594 | } | 594 | } |
@@ -786,7 +786,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
786 | cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); | 786 | cifs_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); |
787 | cifs_reconnect(server); | 787 | cifs_reconnect(server); |
788 | wake_up(&server->response_q); | 788 | wake_up(&server->response_q); |
789 | return -EAGAIN; | 789 | return -ECONNABORTED; |
790 | } | 790 | } |
791 | 791 | ||
792 | /* switch to large buffer if too big for a small one */ | 792 | /* switch to large buffer if too big for a small one */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b88b1ade4d3d..4ab2f79ffa7a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1670,8 +1670,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, | |||
1670 | break; | 1670 | break; |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | len = min((size_t)cifs_sb->wsize, | 1673 | len = min(server->ops->wp_retry_size(dentry->d_inode), |
1674 | write_size - total_written); | 1674 | (unsigned int)write_size - total_written); |
1675 | /* iov[0] is reserved for smb header */ | 1675 | /* iov[0] is reserved for smb header */ |
1676 | iov[1].iov_base = (char *)write_data + total_written; | 1676 | iov[1].iov_base = (char *)write_data + total_written; |
1677 | iov[1].iov_len = len; | 1677 | iov[1].iov_len = len; |
@@ -1878,15 +1878,163 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1878 | return rc; | 1878 | return rc; |
1879 | } | 1879 | } |
1880 | 1880 | ||
1881 | static struct cifs_writedata * | ||
1882 | wdata_alloc_and_fillpages(pgoff_t tofind, struct address_space *mapping, | ||
1883 | pgoff_t end, pgoff_t *index, | ||
1884 | unsigned int *found_pages) | ||
1885 | { | ||
1886 | unsigned int nr_pages; | ||
1887 | struct page **pages; | ||
1888 | struct cifs_writedata *wdata; | ||
1889 | |||
1890 | wdata = cifs_writedata_alloc((unsigned int)tofind, | ||
1891 | cifs_writev_complete); | ||
1892 | if (!wdata) | ||
1893 | return NULL; | ||
1894 | |||
1895 | /* | ||
1896 | * find_get_pages_tag seems to return a max of 256 on each | ||
1897 | * iteration, so we must call it several times in order to | ||
1898 | * fill the array or the wsize is effectively limited to | ||
1899 | * 256 * PAGE_CACHE_SIZE. | ||
1900 | */ | ||
1901 | *found_pages = 0; | ||
1902 | pages = wdata->pages; | ||
1903 | do { | ||
1904 | nr_pages = find_get_pages_tag(mapping, index, | ||
1905 | PAGECACHE_TAG_DIRTY, tofind, | ||
1906 | pages); | ||
1907 | *found_pages += nr_pages; | ||
1908 | tofind -= nr_pages; | ||
1909 | pages += nr_pages; | ||
1910 | } while (nr_pages && tofind && *index <= end); | ||
1911 | |||
1912 | return wdata; | ||
1913 | } | ||
1914 | |||
1915 | static unsigned int | ||
1916 | wdata_prepare_pages(struct cifs_writedata *wdata, unsigned int found_pages, | ||
1917 | struct address_space *mapping, | ||
1918 | struct writeback_control *wbc, | ||
1919 | pgoff_t end, pgoff_t *index, pgoff_t *next, bool *done) | ||
1920 | { | ||
1921 | unsigned int nr_pages = 0, i; | ||
1922 | struct page *page; | ||
1923 | |||
1924 | for (i = 0; i < found_pages; i++) { | ||
1925 | page = wdata->pages[i]; | ||
1926 | /* | ||
1927 | * At this point we hold neither mapping->tree_lock nor | ||
1928 | * lock on the page itself: the page may be truncated or | ||
1929 | * invalidated (changing page->mapping to NULL), or even | ||
1930 | * swizzled back from swapper_space to tmpfs file | ||
1931 | * mapping | ||
1932 | */ | ||
1933 | |||
1934 | if (nr_pages == 0) | ||
1935 | lock_page(page); | ||
1936 | else if (!trylock_page(page)) | ||
1937 | break; | ||
1938 | |||
1939 | if (unlikely(page->mapping != mapping)) { | ||
1940 | unlock_page(page); | ||
1941 | break; | ||
1942 | } | ||
1943 | |||
1944 | if (!wbc->range_cyclic && page->index > end) { | ||
1945 | *done = true; | ||
1946 | unlock_page(page); | ||
1947 | break; | ||
1948 | } | ||
1949 | |||
1950 | if (*next && (page->index != *next)) { | ||
1951 | /* Not next consecutive page */ | ||
1952 | unlock_page(page); | ||
1953 | break; | ||
1954 | } | ||
1955 | |||
1956 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1957 | wait_on_page_writeback(page); | ||
1958 | |||
1959 | if (PageWriteback(page) || | ||
1960 | !clear_page_dirty_for_io(page)) { | ||
1961 | unlock_page(page); | ||
1962 | break; | ||
1963 | } | ||
1964 | |||
1965 | /* | ||
1966 | * This actually clears the dirty bit in the radix tree. | ||
1967 | * See cifs_writepage() for more commentary. | ||
1968 | */ | ||
1969 | set_page_writeback(page); | ||
1970 | if (page_offset(page) >= i_size_read(mapping->host)) { | ||
1971 | *done = true; | ||
1972 | unlock_page(page); | ||
1973 | end_page_writeback(page); | ||
1974 | break; | ||
1975 | } | ||
1976 | |||
1977 | wdata->pages[i] = page; | ||
1978 | *next = page->index + 1; | ||
1979 | ++nr_pages; | ||
1980 | } | ||
1981 | |||
1982 | /* reset index to refind any pages skipped */ | ||
1983 | if (nr_pages == 0) | ||
1984 | *index = wdata->pages[0]->index + 1; | ||
1985 | |||
1986 | /* put any pages we aren't going to use */ | ||
1987 | for (i = nr_pages; i < found_pages; i++) { | ||
1988 | page_cache_release(wdata->pages[i]); | ||
1989 | wdata->pages[i] = NULL; | ||
1990 | } | ||
1991 | |||
1992 | return nr_pages; | ||
1993 | } | ||
1994 | |||
1995 | static int | ||
1996 | wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, | ||
1997 | struct address_space *mapping, struct writeback_control *wbc) | ||
1998 | { | ||
1999 | int rc = 0; | ||
2000 | struct TCP_Server_Info *server; | ||
2001 | unsigned int i; | ||
2002 | |||
2003 | wdata->sync_mode = wbc->sync_mode; | ||
2004 | wdata->nr_pages = nr_pages; | ||
2005 | wdata->offset = page_offset(wdata->pages[0]); | ||
2006 | wdata->pagesz = PAGE_CACHE_SIZE; | ||
2007 | wdata->tailsz = min(i_size_read(mapping->host) - | ||
2008 | page_offset(wdata->pages[nr_pages - 1]), | ||
2009 | (loff_t)PAGE_CACHE_SIZE); | ||
2010 | wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) + wdata->tailsz; | ||
2011 | |||
2012 | if (wdata->cfile != NULL) | ||
2013 | cifsFileInfo_put(wdata->cfile); | ||
2014 | wdata->cfile = find_writable_file(CIFS_I(mapping->host), false); | ||
2015 | if (!wdata->cfile) { | ||
2016 | cifs_dbg(VFS, "No writable handles for inode\n"); | ||
2017 | rc = -EBADF; | ||
2018 | } else { | ||
2019 | wdata->pid = wdata->cfile->pid; | ||
2020 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | ||
2021 | rc = server->ops->async_writev(wdata, cifs_writedata_release); | ||
2022 | } | ||
2023 | |||
2024 | for (i = 0; i < nr_pages; ++i) | ||
2025 | unlock_page(wdata->pages[i]); | ||
2026 | |||
2027 | return rc; | ||
2028 | } | ||
2029 | |||
1881 | static int cifs_writepages(struct address_space *mapping, | 2030 | static int cifs_writepages(struct address_space *mapping, |
1882 | struct writeback_control *wbc) | 2031 | struct writeback_control *wbc) |
1883 | { | 2032 | { |
1884 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); | 2033 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); |
2034 | struct TCP_Server_Info *server; | ||
1885 | bool done = false, scanned = false, range_whole = false; | 2035 | bool done = false, scanned = false, range_whole = false; |
1886 | pgoff_t end, index; | 2036 | pgoff_t end, index; |
1887 | struct cifs_writedata *wdata; | 2037 | struct cifs_writedata *wdata; |
1888 | struct TCP_Server_Info *server; | ||
1889 | struct page *page; | ||
1890 | int rc = 0; | 2038 | int rc = 0; |
1891 | 2039 | ||
1892 | /* | 2040 | /* |
@@ -1906,152 +2054,50 @@ static int cifs_writepages(struct address_space *mapping, | |||
1906 | range_whole = true; | 2054 | range_whole = true; |
1907 | scanned = true; | 2055 | scanned = true; |
1908 | } | 2056 | } |
2057 | server = cifs_sb_master_tcon(cifs_sb)->ses->server; | ||
1909 | retry: | 2058 | retry: |
1910 | while (!done && index <= end) { | 2059 | while (!done && index <= end) { |
1911 | unsigned int i, nr_pages, found_pages; | 2060 | unsigned int i, nr_pages, found_pages, wsize, credits; |
1912 | pgoff_t next = 0, tofind; | 2061 | pgoff_t next = 0, tofind, saved_index = index; |
1913 | struct page **pages; | 2062 | |
2063 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, | ||
2064 | &wsize, &credits); | ||
2065 | if (rc) | ||
2066 | break; | ||
1914 | 2067 | ||
1915 | tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1, | 2068 | tofind = min((wsize / PAGE_CACHE_SIZE) - 1, end - index) + 1; |
1916 | end - index) + 1; | ||
1917 | 2069 | ||
1918 | wdata = cifs_writedata_alloc((unsigned int)tofind, | 2070 | wdata = wdata_alloc_and_fillpages(tofind, mapping, end, &index, |
1919 | cifs_writev_complete); | 2071 | &found_pages); |
1920 | if (!wdata) { | 2072 | if (!wdata) { |
1921 | rc = -ENOMEM; | 2073 | rc = -ENOMEM; |
2074 | add_credits_and_wake_if(server, credits, 0); | ||
1922 | break; | 2075 | break; |
1923 | } | 2076 | } |
1924 | 2077 | ||
1925 | /* | ||
1926 | * find_get_pages_tag seems to return a max of 256 on each | ||
1927 | * iteration, so we must call it several times in order to | ||
1928 | * fill the array or the wsize is effectively limited to | ||
1929 | * 256 * PAGE_CACHE_SIZE. | ||
1930 | */ | ||
1931 | found_pages = 0; | ||
1932 | pages = wdata->pages; | ||
1933 | do { | ||
1934 | nr_pages = find_get_pages_tag(mapping, &index, | ||
1935 | PAGECACHE_TAG_DIRTY, | ||
1936 | tofind, pages); | ||
1937 | found_pages += nr_pages; | ||
1938 | tofind -= nr_pages; | ||
1939 | pages += nr_pages; | ||
1940 | } while (nr_pages && tofind && index <= end); | ||
1941 | |||
1942 | if (found_pages == 0) { | 2078 | if (found_pages == 0) { |
1943 | kref_put(&wdata->refcount, cifs_writedata_release); | 2079 | kref_put(&wdata->refcount, cifs_writedata_release); |
2080 | add_credits_and_wake_if(server, credits, 0); | ||
1944 | break; | 2081 | break; |
1945 | } | 2082 | } |
1946 | 2083 | ||
1947 | nr_pages = 0; | 2084 | nr_pages = wdata_prepare_pages(wdata, found_pages, mapping, wbc, |
1948 | for (i = 0; i < found_pages; i++) { | 2085 | end, &index, &next, &done); |
1949 | page = wdata->pages[i]; | ||
1950 | /* | ||
1951 | * At this point we hold neither mapping->tree_lock nor | ||
1952 | * lock on the page itself: the page may be truncated or | ||
1953 | * invalidated (changing page->mapping to NULL), or even | ||
1954 | * swizzled back from swapper_space to tmpfs file | ||
1955 | * mapping | ||
1956 | */ | ||
1957 | |||
1958 | if (nr_pages == 0) | ||
1959 | lock_page(page); | ||
1960 | else if (!trylock_page(page)) | ||
1961 | break; | ||
1962 | |||
1963 | if (unlikely(page->mapping != mapping)) { | ||
1964 | unlock_page(page); | ||
1965 | break; | ||
1966 | } | ||
1967 | |||
1968 | if (!wbc->range_cyclic && page->index > end) { | ||
1969 | done = true; | ||
1970 | unlock_page(page); | ||
1971 | break; | ||
1972 | } | ||
1973 | |||
1974 | if (next && (page->index != next)) { | ||
1975 | /* Not next consecutive page */ | ||
1976 | unlock_page(page); | ||
1977 | break; | ||
1978 | } | ||
1979 | |||
1980 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1981 | wait_on_page_writeback(page); | ||
1982 | |||
1983 | if (PageWriteback(page) || | ||
1984 | !clear_page_dirty_for_io(page)) { | ||
1985 | unlock_page(page); | ||
1986 | break; | ||
1987 | } | ||
1988 | |||
1989 | /* | ||
1990 | * This actually clears the dirty bit in the radix tree. | ||
1991 | * See cifs_writepage() for more commentary. | ||
1992 | */ | ||
1993 | set_page_writeback(page); | ||
1994 | |||
1995 | if (page_offset(page) >= i_size_read(mapping->host)) { | ||
1996 | done = true; | ||
1997 | unlock_page(page); | ||
1998 | end_page_writeback(page); | ||
1999 | break; | ||
2000 | } | ||
2001 | |||
2002 | wdata->pages[i] = page; | ||
2003 | next = page->index + 1; | ||
2004 | ++nr_pages; | ||
2005 | } | ||
2006 | |||
2007 | /* reset index to refind any pages skipped */ | ||
2008 | if (nr_pages == 0) | ||
2009 | index = wdata->pages[0]->index + 1; | ||
2010 | |||
2011 | /* put any pages we aren't going to use */ | ||
2012 | for (i = nr_pages; i < found_pages; i++) { | ||
2013 | page_cache_release(wdata->pages[i]); | ||
2014 | wdata->pages[i] = NULL; | ||
2015 | } | ||
2016 | 2086 | ||
2017 | /* nothing to write? */ | 2087 | /* nothing to write? */ |
2018 | if (nr_pages == 0) { | 2088 | if (nr_pages == 0) { |
2019 | kref_put(&wdata->refcount, cifs_writedata_release); | 2089 | kref_put(&wdata->refcount, cifs_writedata_release); |
2090 | add_credits_and_wake_if(server, credits, 0); | ||
2020 | continue; | 2091 | continue; |
2021 | } | 2092 | } |
2022 | 2093 | ||
2023 | wdata->sync_mode = wbc->sync_mode; | 2094 | wdata->credits = credits; |
2024 | wdata->nr_pages = nr_pages; | ||
2025 | wdata->offset = page_offset(wdata->pages[0]); | ||
2026 | wdata->pagesz = PAGE_CACHE_SIZE; | ||
2027 | wdata->tailsz = | ||
2028 | min(i_size_read(mapping->host) - | ||
2029 | page_offset(wdata->pages[nr_pages - 1]), | ||
2030 | (loff_t)PAGE_CACHE_SIZE); | ||
2031 | wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) + | ||
2032 | wdata->tailsz; | ||
2033 | |||
2034 | do { | ||
2035 | if (wdata->cfile != NULL) | ||
2036 | cifsFileInfo_put(wdata->cfile); | ||
2037 | wdata->cfile = find_writable_file(CIFS_I(mapping->host), | ||
2038 | false); | ||
2039 | if (!wdata->cfile) { | ||
2040 | cifs_dbg(VFS, "No writable handles for inode\n"); | ||
2041 | rc = -EBADF; | ||
2042 | break; | ||
2043 | } | ||
2044 | wdata->pid = wdata->cfile->pid; | ||
2045 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | ||
2046 | rc = server->ops->async_writev(wdata, | ||
2047 | cifs_writedata_release); | ||
2048 | } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); | ||
2049 | 2095 | ||
2050 | for (i = 0; i < nr_pages; ++i) | 2096 | rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); |
2051 | unlock_page(wdata->pages[i]); | ||
2052 | 2097 | ||
2053 | /* send failure -- clean up the mess */ | 2098 | /* send failure -- clean up the mess */ |
2054 | if (rc != 0) { | 2099 | if (rc != 0) { |
2100 | add_credits_and_wake_if(server, wdata->credits, 0); | ||
2055 | for (i = 0; i < nr_pages; ++i) { | 2101 | for (i = 0; i < nr_pages; ++i) { |
2056 | if (rc == -EAGAIN) | 2102 | if (rc == -EAGAIN) |
2057 | redirty_page_for_writepage(wbc, | 2103 | redirty_page_for_writepage(wbc, |
@@ -2066,6 +2112,11 @@ retry: | |||
2066 | } | 2112 | } |
2067 | kref_put(&wdata->refcount, cifs_writedata_release); | 2113 | kref_put(&wdata->refcount, cifs_writedata_release); |
2068 | 2114 | ||
2115 | if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) { | ||
2116 | index = saved_index; | ||
2117 | continue; | ||
2118 | } | ||
2119 | |||
2069 | wbc->nr_to_write -= nr_pages; | 2120 | wbc->nr_to_write -= nr_pages; |
2070 | if (wbc->nr_to_write <= 0) | 2121 | if (wbc->nr_to_write <= 0) |
2071 | done = true; | 2122 | done = true; |
@@ -2362,123 +2413,109 @@ cifs_uncached_writev_complete(struct work_struct *work) | |||
2362 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); | 2413 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); |
2363 | } | 2414 | } |
2364 | 2415 | ||
2365 | /* attempt to send write to server, retry on any -EAGAIN errors */ | ||
2366 | static int | 2416 | static int |
2367 | cifs_uncached_retry_writev(struct cifs_writedata *wdata) | 2417 | wdata_fill_from_iovec(struct cifs_writedata *wdata, struct iov_iter *from, |
2418 | size_t *len, unsigned long *num_pages) | ||
2368 | { | 2419 | { |
2369 | int rc; | 2420 | size_t save_len, copied, bytes, cur_len = *len; |
2370 | struct TCP_Server_Info *server; | 2421 | unsigned long i, nr_pages = *num_pages; |
2371 | 2422 | ||
2372 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | 2423 | save_len = cur_len; |
2424 | for (i = 0; i < nr_pages; i++) { | ||
2425 | bytes = min_t(const size_t, cur_len, PAGE_SIZE); | ||
2426 | copied = copy_page_from_iter(wdata->pages[i], 0, bytes, from); | ||
2427 | cur_len -= copied; | ||
2428 | /* | ||
2429 | * If we didn't copy as much as we expected, then that | ||
2430 | * may mean we trod into an unmapped area. Stop copying | ||
2431 | * at that point. On the next pass through the big | ||
2432 | * loop, we'll likely end up getting a zero-length | ||
2433 | * write and bailing out of it. | ||
2434 | */ | ||
2435 | if (copied < bytes) | ||
2436 | break; | ||
2437 | } | ||
2438 | cur_len = save_len - cur_len; | ||
2439 | *len = cur_len; | ||
2373 | 2440 | ||
2374 | do { | 2441 | /* |
2375 | if (wdata->cfile->invalidHandle) { | 2442 | * If we have no data to send, then that probably means that |
2376 | rc = cifs_reopen_file(wdata->cfile, false); | 2443 | * the copy above failed altogether. That's most likely because |
2377 | if (rc != 0) | 2444 | * the address in the iovec was bogus. Return -EFAULT and let |
2378 | continue; | 2445 | * the caller free anything we allocated and bail out. |
2379 | } | 2446 | */ |
2380 | rc = server->ops->async_writev(wdata, | 2447 | if (!cur_len) |
2381 | cifs_uncached_writedata_release); | 2448 | return -EFAULT; |
2382 | } while (rc == -EAGAIN); | ||
2383 | 2449 | ||
2384 | return rc; | 2450 | /* |
2451 | * i + 1 now represents the number of pages we actually used in | ||
2452 | * the copy phase above. | ||
2453 | */ | ||
2454 | *num_pages = i + 1; | ||
2455 | return 0; | ||
2385 | } | 2456 | } |
2386 | 2457 | ||
2387 | static ssize_t | 2458 | static int |
2388 | cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) | 2459 | cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, |
2460 | struct cifsFileInfo *open_file, | ||
2461 | struct cifs_sb_info *cifs_sb, struct list_head *wdata_list) | ||
2389 | { | 2462 | { |
2390 | unsigned long nr_pages, i; | 2463 | int rc = 0; |
2391 | size_t bytes, copied, len, cur_len; | 2464 | size_t cur_len; |
2392 | ssize_t total_written = 0; | 2465 | unsigned long nr_pages, num_pages, i; |
2393 | loff_t offset; | 2466 | struct cifs_writedata *wdata; |
2394 | struct cifsFileInfo *open_file; | 2467 | struct iov_iter saved_from; |
2395 | struct cifs_tcon *tcon; | 2468 | loff_t saved_offset = offset; |
2396 | struct cifs_sb_info *cifs_sb; | ||
2397 | struct cifs_writedata *wdata, *tmp; | ||
2398 | struct list_head wdata_list; | ||
2399 | int rc; | ||
2400 | pid_t pid; | 2469 | pid_t pid; |
2401 | 2470 | struct TCP_Server_Info *server; | |
2402 | len = iov_iter_count(from); | ||
2403 | rc = generic_write_checks(file, poffset, &len, 0); | ||
2404 | if (rc) | ||
2405 | return rc; | ||
2406 | |||
2407 | if (!len) | ||
2408 | return 0; | ||
2409 | |||
2410 | iov_iter_truncate(from, len); | ||
2411 | |||
2412 | INIT_LIST_HEAD(&wdata_list); | ||
2413 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
2414 | open_file = file->private_data; | ||
2415 | tcon = tlink_tcon(open_file->tlink); | ||
2416 | |||
2417 | if (!tcon->ses->server->ops->async_writev) | ||
2418 | return -ENOSYS; | ||
2419 | |||
2420 | offset = *poffset; | ||
2421 | 2471 | ||
2422 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | 2472 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
2423 | pid = open_file->pid; | 2473 | pid = open_file->pid; |
2424 | else | 2474 | else |
2425 | pid = current->tgid; | 2475 | pid = current->tgid; |
2426 | 2476 | ||
2477 | server = tlink_tcon(open_file->tlink)->ses->server; | ||
2478 | memcpy(&saved_from, from, sizeof(struct iov_iter)); | ||
2479 | |||
2427 | do { | 2480 | do { |
2428 | size_t save_len; | 2481 | unsigned int wsize, credits; |
2482 | |||
2483 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, | ||
2484 | &wsize, &credits); | ||
2485 | if (rc) | ||
2486 | break; | ||
2429 | 2487 | ||
2430 | nr_pages = get_numpages(cifs_sb->wsize, len, &cur_len); | 2488 | nr_pages = get_numpages(wsize, len, &cur_len); |
2431 | wdata = cifs_writedata_alloc(nr_pages, | 2489 | wdata = cifs_writedata_alloc(nr_pages, |
2432 | cifs_uncached_writev_complete); | 2490 | cifs_uncached_writev_complete); |
2433 | if (!wdata) { | 2491 | if (!wdata) { |
2434 | rc = -ENOMEM; | 2492 | rc = -ENOMEM; |
2493 | add_credits_and_wake_if(server, credits, 0); | ||
2435 | break; | 2494 | break; |
2436 | } | 2495 | } |
2437 | 2496 | ||
2438 | rc = cifs_write_allocate_pages(wdata->pages, nr_pages); | 2497 | rc = cifs_write_allocate_pages(wdata->pages, nr_pages); |
2439 | if (rc) { | 2498 | if (rc) { |
2440 | kfree(wdata); | 2499 | kfree(wdata); |
2500 | add_credits_and_wake_if(server, credits, 0); | ||
2441 | break; | 2501 | break; |
2442 | } | 2502 | } |
2443 | 2503 | ||
2444 | save_len = cur_len; | 2504 | num_pages = nr_pages; |
2445 | for (i = 0; i < nr_pages; i++) { | 2505 | rc = wdata_fill_from_iovec(wdata, from, &cur_len, &num_pages); |
2446 | bytes = min_t(size_t, cur_len, PAGE_SIZE); | 2506 | if (rc) { |
2447 | copied = copy_page_from_iter(wdata->pages[i], 0, bytes, | ||
2448 | from); | ||
2449 | cur_len -= copied; | ||
2450 | /* | ||
2451 | * If we didn't copy as much as we expected, then that | ||
2452 | * may mean we trod into an unmapped area. Stop copying | ||
2453 | * at that point. On the next pass through the big | ||
2454 | * loop, we'll likely end up getting a zero-length | ||
2455 | * write and bailing out of it. | ||
2456 | */ | ||
2457 | if (copied < bytes) | ||
2458 | break; | ||
2459 | } | ||
2460 | cur_len = save_len - cur_len; | ||
2461 | |||
2462 | /* | ||
2463 | * If we have no data to send, then that probably means that | ||
2464 | * the copy above failed altogether. That's most likely because | ||
2465 | * the address in the iovec was bogus. Set the rc to -EFAULT, | ||
2466 | * free anything we allocated and bail out. | ||
2467 | */ | ||
2468 | if (!cur_len) { | ||
2469 | for (i = 0; i < nr_pages; i++) | 2507 | for (i = 0; i < nr_pages; i++) |
2470 | put_page(wdata->pages[i]); | 2508 | put_page(wdata->pages[i]); |
2471 | kfree(wdata); | 2509 | kfree(wdata); |
2472 | rc = -EFAULT; | 2510 | add_credits_and_wake_if(server, credits, 0); |
2473 | break; | 2511 | break; |
2474 | } | 2512 | } |
2475 | 2513 | ||
2476 | /* | 2514 | /* |
2477 | * i + 1 now represents the number of pages we actually used in | 2515 | * Bring nr_pages down to the number of pages we actually used, |
2478 | * the copy phase above. Bring nr_pages down to that, and free | 2516 | * and free any pages that we didn't use. |
2479 | * any pages that we didn't use. | ||
2480 | */ | 2517 | */ |
2481 | for ( ; nr_pages > i + 1; nr_pages--) | 2518 | for ( ; nr_pages > num_pages; nr_pages--) |
2482 | put_page(wdata->pages[nr_pages - 1]); | 2519 | put_page(wdata->pages[nr_pages - 1]); |
2483 | 2520 | ||
2484 | wdata->sync_mode = WB_SYNC_ALL; | 2521 | wdata->sync_mode = WB_SYNC_ALL; |
@@ -2489,18 +2526,69 @@ cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) | |||
2489 | wdata->bytes = cur_len; | 2526 | wdata->bytes = cur_len; |
2490 | wdata->pagesz = PAGE_SIZE; | 2527 | wdata->pagesz = PAGE_SIZE; |
2491 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); | 2528 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); |
2492 | rc = cifs_uncached_retry_writev(wdata); | 2529 | wdata->credits = credits; |
2530 | |||
2531 | if (!wdata->cfile->invalidHandle || | ||
2532 | !cifs_reopen_file(wdata->cfile, false)) | ||
2533 | rc = server->ops->async_writev(wdata, | ||
2534 | cifs_uncached_writedata_release); | ||
2493 | if (rc) { | 2535 | if (rc) { |
2536 | add_credits_and_wake_if(server, wdata->credits, 0); | ||
2494 | kref_put(&wdata->refcount, | 2537 | kref_put(&wdata->refcount, |
2495 | cifs_uncached_writedata_release); | 2538 | cifs_uncached_writedata_release); |
2539 | if (rc == -EAGAIN) { | ||
2540 | memcpy(from, &saved_from, | ||
2541 | sizeof(struct iov_iter)); | ||
2542 | iov_iter_advance(from, offset - saved_offset); | ||
2543 | continue; | ||
2544 | } | ||
2496 | break; | 2545 | break; |
2497 | } | 2546 | } |
2498 | 2547 | ||
2499 | list_add_tail(&wdata->list, &wdata_list); | 2548 | list_add_tail(&wdata->list, wdata_list); |
2500 | offset += cur_len; | 2549 | offset += cur_len; |
2501 | len -= cur_len; | 2550 | len -= cur_len; |
2502 | } while (len > 0); | 2551 | } while (len > 0); |
2503 | 2552 | ||
2553 | return rc; | ||
2554 | } | ||
2555 | |||
2556 | static ssize_t | ||
2557 | cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset) | ||
2558 | { | ||
2559 | size_t len; | ||
2560 | ssize_t total_written = 0; | ||
2561 | struct cifsFileInfo *open_file; | ||
2562 | struct cifs_tcon *tcon; | ||
2563 | struct cifs_sb_info *cifs_sb; | ||
2564 | struct cifs_writedata *wdata, *tmp; | ||
2565 | struct list_head wdata_list; | ||
2566 | struct iov_iter saved_from; | ||
2567 | int rc; | ||
2568 | |||
2569 | len = iov_iter_count(from); | ||
2570 | rc = generic_write_checks(file, poffset, &len, 0); | ||
2571 | if (rc) | ||
2572 | return rc; | ||
2573 | |||
2574 | if (!len) | ||
2575 | return 0; | ||
2576 | |||
2577 | iov_iter_truncate(from, len); | ||
2578 | |||
2579 | INIT_LIST_HEAD(&wdata_list); | ||
2580 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
2581 | open_file = file->private_data; | ||
2582 | tcon = tlink_tcon(open_file->tlink); | ||
2583 | |||
2584 | if (!tcon->ses->server->ops->async_writev) | ||
2585 | return -ENOSYS; | ||
2586 | |||
2587 | memcpy(&saved_from, from, sizeof(struct iov_iter)); | ||
2588 | |||
2589 | rc = cifs_write_from_iter(*poffset, len, from, open_file, cifs_sb, | ||
2590 | &wdata_list); | ||
2591 | |||
2504 | /* | 2592 | /* |
2505 | * If at least one write was successfully sent, then discard any rc | 2593 | * If at least one write was successfully sent, then discard any rc |
2506 | * value from the later writes. If the other write succeeds, then | 2594 | * value from the later writes. If the other write succeeds, then |
@@ -2529,7 +2617,25 @@ restart_loop: | |||
2529 | 2617 | ||
2530 | /* resend call if it's a retryable error */ | 2618 | /* resend call if it's a retryable error */ |
2531 | if (rc == -EAGAIN) { | 2619 | if (rc == -EAGAIN) { |
2532 | rc = cifs_uncached_retry_writev(wdata); | 2620 | struct list_head tmp_list; |
2621 | struct iov_iter tmp_from; | ||
2622 | |||
2623 | INIT_LIST_HEAD(&tmp_list); | ||
2624 | list_del_init(&wdata->list); | ||
2625 | |||
2626 | memcpy(&tmp_from, &saved_from, | ||
2627 | sizeof(struct iov_iter)); | ||
2628 | iov_iter_advance(&tmp_from, | ||
2629 | wdata->offset - *poffset); | ||
2630 | |||
2631 | rc = cifs_write_from_iter(wdata->offset, | ||
2632 | wdata->bytes, &tmp_from, | ||
2633 | open_file, cifs_sb, &tmp_list); | ||
2634 | |||
2635 | list_splice(&tmp_list, &wdata_list); | ||
2636 | |||
2637 | kref_put(&wdata->refcount, | ||
2638 | cifs_uncached_writedata_release); | ||
2533 | goto restart_loop; | 2639 | goto restart_loop; |
2534 | } | 2640 | } |
2535 | } | 2641 | } |
@@ -2722,26 +2828,6 @@ cifs_uncached_readdata_release(struct kref *refcount) | |||
2722 | cifs_readdata_release(refcount); | 2828 | cifs_readdata_release(refcount); |
2723 | } | 2829 | } |
2724 | 2830 | ||
2725 | static int | ||
2726 | cifs_retry_async_readv(struct cifs_readdata *rdata) | ||
2727 | { | ||
2728 | int rc; | ||
2729 | struct TCP_Server_Info *server; | ||
2730 | |||
2731 | server = tlink_tcon(rdata->cfile->tlink)->ses->server; | ||
2732 | |||
2733 | do { | ||
2734 | if (rdata->cfile->invalidHandle) { | ||
2735 | rc = cifs_reopen_file(rdata->cfile, true); | ||
2736 | if (rc != 0) | ||
2737 | continue; | ||
2738 | } | ||
2739 | rc = server->ops->async_readv(rdata); | ||
2740 | } while (rc == -EAGAIN); | ||
2741 | |||
2742 | return rc; | ||
2743 | } | ||
2744 | |||
2745 | /** | 2831 | /** |
2746 | * cifs_readdata_to_iov - copy data from pages in response to an iovec | 2832 | * cifs_readdata_to_iov - copy data from pages in response to an iovec |
2747 | * @rdata: the readdata response with list of pages holding data | 2833 | * @rdata: the readdata response with list of pages holding data |
@@ -2754,7 +2840,7 @@ cifs_retry_async_readv(struct cifs_readdata *rdata) | |||
2754 | static int | 2840 | static int |
2755 | cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) | 2841 | cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) |
2756 | { | 2842 | { |
2757 | size_t remaining = rdata->bytes; | 2843 | size_t remaining = rdata->got_bytes; |
2758 | unsigned int i; | 2844 | unsigned int i; |
2759 | 2845 | ||
2760 | for (i = 0; i < rdata->nr_pages; i++) { | 2846 | for (i = 0; i < rdata->nr_pages; i++) { |
@@ -2782,11 +2868,12 @@ static int | |||
2782 | cifs_uncached_read_into_pages(struct TCP_Server_Info *server, | 2868 | cifs_uncached_read_into_pages(struct TCP_Server_Info *server, |
2783 | struct cifs_readdata *rdata, unsigned int len) | 2869 | struct cifs_readdata *rdata, unsigned int len) |
2784 | { | 2870 | { |
2785 | int total_read = 0, result = 0; | 2871 | int result = 0; |
2786 | unsigned int i; | 2872 | unsigned int i; |
2787 | unsigned int nr_pages = rdata->nr_pages; | 2873 | unsigned int nr_pages = rdata->nr_pages; |
2788 | struct kvec iov; | 2874 | struct kvec iov; |
2789 | 2875 | ||
2876 | rdata->got_bytes = 0; | ||
2790 | rdata->tailsz = PAGE_SIZE; | 2877 | rdata->tailsz = PAGE_SIZE; |
2791 | for (i = 0; i < nr_pages; i++) { | 2878 | for (i = 0; i < nr_pages; i++) { |
2792 | struct page *page = rdata->pages[i]; | 2879 | struct page *page = rdata->pages[i]; |
@@ -2820,55 +2907,45 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, | |||
2820 | if (result < 0) | 2907 | if (result < 0) |
2821 | break; | 2908 | break; |
2822 | 2909 | ||
2823 | total_read += result; | 2910 | rdata->got_bytes += result; |
2824 | } | 2911 | } |
2825 | 2912 | ||
2826 | return total_read > 0 ? total_read : result; | 2913 | return rdata->got_bytes > 0 && result != -ECONNABORTED ? |
2914 | rdata->got_bytes : result; | ||
2827 | } | 2915 | } |
2828 | 2916 | ||
2829 | ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) | 2917 | static int |
2918 | cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | ||
2919 | struct cifs_sb_info *cifs_sb, struct list_head *rdata_list) | ||
2830 | { | 2920 | { |
2831 | struct file *file = iocb->ki_filp; | 2921 | struct cifs_readdata *rdata; |
2832 | ssize_t rc; | 2922 | unsigned int npages, rsize, credits; |
2833 | size_t len, cur_len; | 2923 | size_t cur_len; |
2834 | ssize_t total_read = 0; | 2924 | int rc; |
2835 | loff_t offset = iocb->ki_pos; | ||
2836 | unsigned int npages; | ||
2837 | struct cifs_sb_info *cifs_sb; | ||
2838 | struct cifs_tcon *tcon; | ||
2839 | struct cifsFileInfo *open_file; | ||
2840 | struct cifs_readdata *rdata, *tmp; | ||
2841 | struct list_head rdata_list; | ||
2842 | pid_t pid; | 2925 | pid_t pid; |
2926 | struct TCP_Server_Info *server; | ||
2843 | 2927 | ||
2844 | len = iov_iter_count(to); | 2928 | server = tlink_tcon(open_file->tlink)->ses->server; |
2845 | if (!len) | ||
2846 | return 0; | ||
2847 | |||
2848 | INIT_LIST_HEAD(&rdata_list); | ||
2849 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
2850 | open_file = file->private_data; | ||
2851 | tcon = tlink_tcon(open_file->tlink); | ||
2852 | |||
2853 | if (!tcon->ses->server->ops->async_readv) | ||
2854 | return -ENOSYS; | ||
2855 | 2929 | ||
2856 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | 2930 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
2857 | pid = open_file->pid; | 2931 | pid = open_file->pid; |
2858 | else | 2932 | else |
2859 | pid = current->tgid; | 2933 | pid = current->tgid; |
2860 | 2934 | ||
2861 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | ||
2862 | cifs_dbg(FYI, "attempting read on write only file instance\n"); | ||
2863 | |||
2864 | do { | 2935 | do { |
2865 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); | 2936 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, |
2937 | &rsize, &credits); | ||
2938 | if (rc) | ||
2939 | break; | ||
2940 | |||
2941 | cur_len = min_t(const size_t, len, rsize); | ||
2866 | npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); | 2942 | npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); |
2867 | 2943 | ||
2868 | /* allocate a readdata struct */ | 2944 | /* allocate a readdata struct */ |
2869 | rdata = cifs_readdata_alloc(npages, | 2945 | rdata = cifs_readdata_alloc(npages, |
2870 | cifs_uncached_readv_complete); | 2946 | cifs_uncached_readv_complete); |
2871 | if (!rdata) { | 2947 | if (!rdata) { |
2948 | add_credits_and_wake_if(server, credits, 0); | ||
2872 | rc = -ENOMEM; | 2949 | rc = -ENOMEM; |
2873 | break; | 2950 | break; |
2874 | } | 2951 | } |
@@ -2884,44 +2961,113 @@ ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) | |||
2884 | rdata->pid = pid; | 2961 | rdata->pid = pid; |
2885 | rdata->pagesz = PAGE_SIZE; | 2962 | rdata->pagesz = PAGE_SIZE; |
2886 | rdata->read_into_pages = cifs_uncached_read_into_pages; | 2963 | rdata->read_into_pages = cifs_uncached_read_into_pages; |
2964 | rdata->credits = credits; | ||
2887 | 2965 | ||
2888 | rc = cifs_retry_async_readv(rdata); | 2966 | if (!rdata->cfile->invalidHandle || |
2967 | !cifs_reopen_file(rdata->cfile, true)) | ||
2968 | rc = server->ops->async_readv(rdata); | ||
2889 | error: | 2969 | error: |
2890 | if (rc) { | 2970 | if (rc) { |
2971 | add_credits_and_wake_if(server, rdata->credits, 0); | ||
2891 | kref_put(&rdata->refcount, | 2972 | kref_put(&rdata->refcount, |
2892 | cifs_uncached_readdata_release); | 2973 | cifs_uncached_readdata_release); |
2974 | if (rc == -EAGAIN) | ||
2975 | continue; | ||
2893 | break; | 2976 | break; |
2894 | } | 2977 | } |
2895 | 2978 | ||
2896 | list_add_tail(&rdata->list, &rdata_list); | 2979 | list_add_tail(&rdata->list, rdata_list); |
2897 | offset += cur_len; | 2980 | offset += cur_len; |
2898 | len -= cur_len; | 2981 | len -= cur_len; |
2899 | } while (len > 0); | 2982 | } while (len > 0); |
2900 | 2983 | ||
2984 | return rc; | ||
2985 | } | ||
2986 | |||
2987 | ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) | ||
2988 | { | ||
2989 | struct file *file = iocb->ki_filp; | ||
2990 | ssize_t rc; | ||
2991 | size_t len; | ||
2992 | ssize_t total_read = 0; | ||
2993 | loff_t offset = iocb->ki_pos; | ||
2994 | struct cifs_sb_info *cifs_sb; | ||
2995 | struct cifs_tcon *tcon; | ||
2996 | struct cifsFileInfo *open_file; | ||
2997 | struct cifs_readdata *rdata, *tmp; | ||
2998 | struct list_head rdata_list; | ||
2999 | |||
3000 | len = iov_iter_count(to); | ||
3001 | if (!len) | ||
3002 | return 0; | ||
3003 | |||
3004 | INIT_LIST_HEAD(&rdata_list); | ||
3005 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
3006 | open_file = file->private_data; | ||
3007 | tcon = tlink_tcon(open_file->tlink); | ||
3008 | |||
3009 | if (!tcon->ses->server->ops->async_readv) | ||
3010 | return -ENOSYS; | ||
3011 | |||
3012 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | ||
3013 | cifs_dbg(FYI, "attempting read on write only file instance\n"); | ||
3014 | |||
3015 | rc = cifs_send_async_read(offset, len, open_file, cifs_sb, &rdata_list); | ||
3016 | |||
2901 | /* if at least one read request send succeeded, then reset rc */ | 3017 | /* if at least one read request send succeeded, then reset rc */ |
2902 | if (!list_empty(&rdata_list)) | 3018 | if (!list_empty(&rdata_list)) |
2903 | rc = 0; | 3019 | rc = 0; |
2904 | 3020 | ||
2905 | len = iov_iter_count(to); | 3021 | len = iov_iter_count(to); |
2906 | /* the loop below should proceed in the order of increasing offsets */ | 3022 | /* the loop below should proceed in the order of increasing offsets */ |
3023 | again: | ||
2907 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { | 3024 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { |
2908 | again: | ||
2909 | if (!rc) { | 3025 | if (!rc) { |
2910 | /* FIXME: freezable sleep too? */ | 3026 | /* FIXME: freezable sleep too? */ |
2911 | rc = wait_for_completion_killable(&rdata->done); | 3027 | rc = wait_for_completion_killable(&rdata->done); |
2912 | if (rc) | 3028 | if (rc) |
2913 | rc = -EINTR; | 3029 | rc = -EINTR; |
2914 | else if (rdata->result) { | 3030 | else if (rdata->result == -EAGAIN) { |
2915 | rc = rdata->result; | ||
2916 | /* resend call if it's a retryable error */ | 3031 | /* resend call if it's a retryable error */ |
2917 | if (rc == -EAGAIN) { | 3032 | struct list_head tmp_list; |
2918 | rc = cifs_retry_async_readv(rdata); | 3033 | unsigned int got_bytes = rdata->got_bytes; |
2919 | goto again; | 3034 | |
3035 | list_del_init(&rdata->list); | ||
3036 | INIT_LIST_HEAD(&tmp_list); | ||
3037 | |||
3038 | /* | ||
3039 | * Got a part of data and then reconnect has | ||
3040 | * happened -- fill the buffer and continue | ||
3041 | * reading. | ||
3042 | */ | ||
3043 | if (got_bytes && got_bytes < rdata->bytes) { | ||
3044 | rc = cifs_readdata_to_iov(rdata, to); | ||
3045 | if (rc) { | ||
3046 | kref_put(&rdata->refcount, | ||
3047 | cifs_uncached_readdata_release); | ||
3048 | continue; | ||
3049 | } | ||
2920 | } | 3050 | } |
2921 | } else { | 3051 | |
3052 | rc = cifs_send_async_read( | ||
3053 | rdata->offset + got_bytes, | ||
3054 | rdata->bytes - got_bytes, | ||
3055 | rdata->cfile, cifs_sb, | ||
3056 | &tmp_list); | ||
3057 | |||
3058 | list_splice(&tmp_list, &rdata_list); | ||
3059 | |||
3060 | kref_put(&rdata->refcount, | ||
3061 | cifs_uncached_readdata_release); | ||
3062 | goto again; | ||
3063 | } else if (rdata->result) | ||
3064 | rc = rdata->result; | ||
3065 | else | ||
2922 | rc = cifs_readdata_to_iov(rdata, to); | 3066 | rc = cifs_readdata_to_iov(rdata, to); |
2923 | } | ||
2924 | 3067 | ||
3068 | /* if there was a short read -- discard anything left */ | ||
3069 | if (rdata->got_bytes && rdata->got_bytes < rdata->bytes) | ||
3070 | rc = -ENODATA; | ||
2925 | } | 3071 | } |
2926 | list_del_init(&rdata->list); | 3072 | list_del_init(&rdata->list); |
2927 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | 3073 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); |
@@ -3030,18 +3176,19 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) | |||
3030 | 3176 | ||
3031 | for (total_read = 0, cur_offset = read_data; read_size > total_read; | 3177 | for (total_read = 0, cur_offset = read_data; read_size > total_read; |
3032 | total_read += bytes_read, cur_offset += bytes_read) { | 3178 | total_read += bytes_read, cur_offset += bytes_read) { |
3033 | current_read_size = min_t(uint, read_size - total_read, rsize); | 3179 | do { |
3034 | /* | 3180 | current_read_size = min_t(uint, read_size - total_read, |
3035 | * For windows me and 9x we do not want to request more than it | 3181 | rsize); |
3036 | * negotiated since it will refuse the read then. | 3182 | /* |
3037 | */ | 3183 | * For windows me and 9x we do not want to request more |
3038 | if ((tcon->ses) && !(tcon->ses->capabilities & | 3184 | * than it negotiated since it will refuse the read |
3185 | * then. | ||
3186 | */ | ||
3187 | if ((tcon->ses) && !(tcon->ses->capabilities & | ||
3039 | tcon->ses->server->vals->cap_large_files)) { | 3188 | tcon->ses->server->vals->cap_large_files)) { |
3040 | current_read_size = min_t(uint, current_read_size, | 3189 | current_read_size = min_t(uint, |
3041 | CIFSMaxBufSize); | 3190 | current_read_size, CIFSMaxBufSize); |
3042 | } | 3191 | } |
3043 | rc = -EAGAIN; | ||
3044 | while (rc == -EAGAIN) { | ||
3045 | if (open_file->invalidHandle) { | 3192 | if (open_file->invalidHandle) { |
3046 | rc = cifs_reopen_file(open_file, true); | 3193 | rc = cifs_reopen_file(open_file, true); |
3047 | if (rc != 0) | 3194 | if (rc != 0) |
@@ -3054,7 +3201,8 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) | |||
3054 | rc = server->ops->sync_read(xid, open_file, &io_parms, | 3201 | rc = server->ops->sync_read(xid, open_file, &io_parms, |
3055 | &bytes_read, &cur_offset, | 3202 | &bytes_read, &cur_offset, |
3056 | &buf_type); | 3203 | &buf_type); |
3057 | } | 3204 | } while (rc == -EAGAIN); |
3205 | |||
3058 | if (rc || (bytes_read == 0)) { | 3206 | if (rc || (bytes_read == 0)) { |
3059 | if (total_read) { | 3207 | if (total_read) { |
3060 | break; | 3208 | break; |
@@ -3133,25 +3281,30 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
3133 | static void | 3281 | static void |
3134 | cifs_readv_complete(struct work_struct *work) | 3282 | cifs_readv_complete(struct work_struct *work) |
3135 | { | 3283 | { |
3136 | unsigned int i; | 3284 | unsigned int i, got_bytes; |
3137 | struct cifs_readdata *rdata = container_of(work, | 3285 | struct cifs_readdata *rdata = container_of(work, |
3138 | struct cifs_readdata, work); | 3286 | struct cifs_readdata, work); |
3139 | 3287 | ||
3288 | got_bytes = rdata->got_bytes; | ||
3140 | for (i = 0; i < rdata->nr_pages; i++) { | 3289 | for (i = 0; i < rdata->nr_pages; i++) { |
3141 | struct page *page = rdata->pages[i]; | 3290 | struct page *page = rdata->pages[i]; |
3142 | 3291 | ||
3143 | lru_cache_add_file(page); | 3292 | lru_cache_add_file(page); |
3144 | 3293 | ||
3145 | if (rdata->result == 0) { | 3294 | if (rdata->result == 0 || |
3295 | (rdata->result == -EAGAIN && got_bytes)) { | ||
3146 | flush_dcache_page(page); | 3296 | flush_dcache_page(page); |
3147 | SetPageUptodate(page); | 3297 | SetPageUptodate(page); |
3148 | } | 3298 | } |
3149 | 3299 | ||
3150 | unlock_page(page); | 3300 | unlock_page(page); |
3151 | 3301 | ||
3152 | if (rdata->result == 0) | 3302 | if (rdata->result == 0 || |
3303 | (rdata->result == -EAGAIN && got_bytes)) | ||
3153 | cifs_readpage_to_fscache(rdata->mapping->host, page); | 3304 | cifs_readpage_to_fscache(rdata->mapping->host, page); |
3154 | 3305 | ||
3306 | got_bytes -= min_t(unsigned int, PAGE_CACHE_SIZE, got_bytes); | ||
3307 | |||
3155 | page_cache_release(page); | 3308 | page_cache_release(page); |
3156 | rdata->pages[i] = NULL; | 3309 | rdata->pages[i] = NULL; |
3157 | } | 3310 | } |
@@ -3162,7 +3315,7 @@ static int | |||
3162 | cifs_readpages_read_into_pages(struct TCP_Server_Info *server, | 3315 | cifs_readpages_read_into_pages(struct TCP_Server_Info *server, |
3163 | struct cifs_readdata *rdata, unsigned int len) | 3316 | struct cifs_readdata *rdata, unsigned int len) |
3164 | { | 3317 | { |
3165 | int total_read = 0, result = 0; | 3318 | int result = 0; |
3166 | unsigned int i; | 3319 | unsigned int i; |
3167 | u64 eof; | 3320 | u64 eof; |
3168 | pgoff_t eof_index; | 3321 | pgoff_t eof_index; |
@@ -3174,6 +3327,7 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, | |||
3174 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; | 3327 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; |
3175 | cifs_dbg(FYI, "eof=%llu eof_index=%lu\n", eof, eof_index); | 3328 | cifs_dbg(FYI, "eof=%llu eof_index=%lu\n", eof, eof_index); |
3176 | 3329 | ||
3330 | rdata->got_bytes = 0; | ||
3177 | rdata->tailsz = PAGE_CACHE_SIZE; | 3331 | rdata->tailsz = PAGE_CACHE_SIZE; |
3178 | for (i = 0; i < nr_pages; i++) { | 3332 | for (i = 0; i < nr_pages; i++) { |
3179 | struct page *page = rdata->pages[i]; | 3333 | struct page *page = rdata->pages[i]; |
@@ -3228,10 +3382,70 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, | |||
3228 | if (result < 0) | 3382 | if (result < 0) |
3229 | break; | 3383 | break; |
3230 | 3384 | ||
3231 | total_read += result; | 3385 | rdata->got_bytes += result; |
3232 | } | 3386 | } |
3233 | 3387 | ||
3234 | return total_read > 0 ? total_read : result; | 3388 | return rdata->got_bytes > 0 && result != -ECONNABORTED ? |
3389 | rdata->got_bytes : result; | ||
3390 | } | ||
3391 | |||
3392 | static int | ||
3393 | readpages_get_pages(struct address_space *mapping, struct list_head *page_list, | ||
3394 | unsigned int rsize, struct list_head *tmplist, | ||
3395 | unsigned int *nr_pages, loff_t *offset, unsigned int *bytes) | ||
3396 | { | ||
3397 | struct page *page, *tpage; | ||
3398 | unsigned int expected_index; | ||
3399 | int rc; | ||
3400 | |||
3401 | INIT_LIST_HEAD(tmplist); | ||
3402 | |||
3403 | page = list_entry(page_list->prev, struct page, lru); | ||
3404 | |||
3405 | /* | ||
3406 | * Lock the page and put it in the cache. Since no one else | ||
3407 | * should have access to this page, we're safe to simply set | ||
3408 | * PG_locked without checking it first. | ||
3409 | */ | ||
3410 | __set_page_locked(page); | ||
3411 | rc = add_to_page_cache_locked(page, mapping, | ||
3412 | page->index, GFP_KERNEL); | ||
3413 | |||
3414 | /* give up if we can't stick it in the cache */ | ||
3415 | if (rc) { | ||
3416 | __clear_page_locked(page); | ||
3417 | return rc; | ||
3418 | } | ||
3419 | |||
3420 | /* move first page to the tmplist */ | ||
3421 | *offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
3422 | *bytes = PAGE_CACHE_SIZE; | ||
3423 | *nr_pages = 1; | ||
3424 | list_move_tail(&page->lru, tmplist); | ||
3425 | |||
3426 | /* now try and add more pages onto the request */ | ||
3427 | expected_index = page->index + 1; | ||
3428 | list_for_each_entry_safe_reverse(page, tpage, page_list, lru) { | ||
3429 | /* discontinuity ? */ | ||
3430 | if (page->index != expected_index) | ||
3431 | break; | ||
3432 | |||
3433 | /* would this page push the read over the rsize? */ | ||
3434 | if (*bytes + PAGE_CACHE_SIZE > rsize) | ||
3435 | break; | ||
3436 | |||
3437 | __set_page_locked(page); | ||
3438 | if (add_to_page_cache_locked(page, mapping, page->index, | ||
3439 | GFP_KERNEL)) { | ||
3440 | __clear_page_locked(page); | ||
3441 | break; | ||
3442 | } | ||
3443 | list_move_tail(&page->lru, tmplist); | ||
3444 | (*bytes) += PAGE_CACHE_SIZE; | ||
3445 | expected_index++; | ||
3446 | (*nr_pages)++; | ||
3447 | } | ||
3448 | return rc; | ||
3235 | } | 3449 | } |
3236 | 3450 | ||
3237 | static int cifs_readpages(struct file *file, struct address_space *mapping, | 3451 | static int cifs_readpages(struct file *file, struct address_space *mapping, |
@@ -3241,19 +3455,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3241 | struct list_head tmplist; | 3455 | struct list_head tmplist; |
3242 | struct cifsFileInfo *open_file = file->private_data; | 3456 | struct cifsFileInfo *open_file = file->private_data; |
3243 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 3457 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
3244 | unsigned int rsize = cifs_sb->rsize; | 3458 | struct TCP_Server_Info *server; |
3245 | pid_t pid; | 3459 | pid_t pid; |
3246 | 3460 | ||
3247 | /* | 3461 | /* |
3248 | * Give up immediately if rsize is too small to read an entire page. | ||
3249 | * The VFS will fall back to readpage. We should never reach this | ||
3250 | * point however since we set ra_pages to 0 when the rsize is smaller | ||
3251 | * than a cache page. | ||
3252 | */ | ||
3253 | if (unlikely(rsize < PAGE_CACHE_SIZE)) | ||
3254 | return 0; | ||
3255 | |||
3256 | /* | ||
3257 | * Reads as many pages as possible from fscache. Returns -ENOBUFS | 3462 | * Reads as many pages as possible from fscache. Returns -ENOBUFS |
3258 | * immediately if the cookie is negative | 3463 | * immediately if the cookie is negative |
3259 | * | 3464 | * |
@@ -3271,7 +3476,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3271 | pid = current->tgid; | 3476 | pid = current->tgid; |
3272 | 3477 | ||
3273 | rc = 0; | 3478 | rc = 0; |
3274 | INIT_LIST_HEAD(&tmplist); | 3479 | server = tlink_tcon(open_file->tlink)->ses->server; |
3275 | 3480 | ||
3276 | cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n", | 3481 | cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n", |
3277 | __func__, file, mapping, num_pages); | 3482 | __func__, file, mapping, num_pages); |
@@ -3288,58 +3493,35 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3288 | * the rdata->pages, then we want them in increasing order. | 3493 | * the rdata->pages, then we want them in increasing order. |
3289 | */ | 3494 | */ |
3290 | while (!list_empty(page_list)) { | 3495 | while (!list_empty(page_list)) { |
3291 | unsigned int i; | 3496 | unsigned int i, nr_pages, bytes, rsize; |
3292 | unsigned int bytes = PAGE_CACHE_SIZE; | ||
3293 | unsigned int expected_index; | ||
3294 | unsigned int nr_pages = 1; | ||
3295 | loff_t offset; | 3497 | loff_t offset; |
3296 | struct page *page, *tpage; | 3498 | struct page *page, *tpage; |
3297 | struct cifs_readdata *rdata; | 3499 | struct cifs_readdata *rdata; |
3500 | unsigned credits; | ||
3298 | 3501 | ||
3299 | page = list_entry(page_list->prev, struct page, lru); | 3502 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, |
3503 | &rsize, &credits); | ||
3504 | if (rc) | ||
3505 | break; | ||
3300 | 3506 | ||
3301 | /* | 3507 | /* |
3302 | * Lock the page and put it in the cache. Since no one else | 3508 | * Give up immediately if rsize is too small to read an entire |
3303 | * should have access to this page, we're safe to simply set | 3509 | * page. The VFS will fall back to readpage. We should never |
3304 | * PG_locked without checking it first. | 3510 | * reach this point however since we set ra_pages to 0 when the |
3511 | * rsize is smaller than a cache page. | ||
3305 | */ | 3512 | */ |
3306 | __set_page_locked(page); | 3513 | if (unlikely(rsize < PAGE_CACHE_SIZE)) { |
3307 | rc = add_to_page_cache_locked(page, mapping, | 3514 | add_credits_and_wake_if(server, credits, 0); |
3308 | page->index, GFP_KERNEL); | 3515 | return 0; |
3516 | } | ||
3309 | 3517 | ||
3310 | /* give up if we can't stick it in the cache */ | 3518 | rc = readpages_get_pages(mapping, page_list, rsize, &tmplist, |
3519 | &nr_pages, &offset, &bytes); | ||
3311 | if (rc) { | 3520 | if (rc) { |
3312 | __clear_page_locked(page); | 3521 | add_credits_and_wake_if(server, credits, 0); |
3313 | break; | 3522 | break; |
3314 | } | 3523 | } |
3315 | 3524 | ||
3316 | /* move first page to the tmplist */ | ||
3317 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
3318 | list_move_tail(&page->lru, &tmplist); | ||
3319 | |||
3320 | /* now try and add more pages onto the request */ | ||
3321 | expected_index = page->index + 1; | ||
3322 | list_for_each_entry_safe_reverse(page, tpage, page_list, lru) { | ||
3323 | /* discontinuity ? */ | ||
3324 | if (page->index != expected_index) | ||
3325 | break; | ||
3326 | |||
3327 | /* would this page push the read over the rsize? */ | ||
3328 | if (bytes + PAGE_CACHE_SIZE > rsize) | ||
3329 | break; | ||
3330 | |||
3331 | __set_page_locked(page); | ||
3332 | if (add_to_page_cache_locked(page, mapping, | ||
3333 | page->index, GFP_KERNEL)) { | ||
3334 | __clear_page_locked(page); | ||
3335 | break; | ||
3336 | } | ||
3337 | list_move_tail(&page->lru, &tmplist); | ||
3338 | bytes += PAGE_CACHE_SIZE; | ||
3339 | expected_index++; | ||
3340 | nr_pages++; | ||
3341 | } | ||
3342 | |||
3343 | rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); | 3525 | rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); |
3344 | if (!rdata) { | 3526 | if (!rdata) { |
3345 | /* best to give up if we're out of mem */ | 3527 | /* best to give up if we're out of mem */ |
@@ -3350,6 +3532,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3350 | page_cache_release(page); | 3532 | page_cache_release(page); |
3351 | } | 3533 | } |
3352 | rc = -ENOMEM; | 3534 | rc = -ENOMEM; |
3535 | add_credits_and_wake_if(server, credits, 0); | ||
3353 | break; | 3536 | break; |
3354 | } | 3537 | } |
3355 | 3538 | ||
@@ -3360,21 +3543,32 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
3360 | rdata->pid = pid; | 3543 | rdata->pid = pid; |
3361 | rdata->pagesz = PAGE_CACHE_SIZE; | 3544 | rdata->pagesz = PAGE_CACHE_SIZE; |
3362 | rdata->read_into_pages = cifs_readpages_read_into_pages; | 3545 | rdata->read_into_pages = cifs_readpages_read_into_pages; |
3546 | rdata->credits = credits; | ||
3363 | 3547 | ||
3364 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { | 3548 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { |
3365 | list_del(&page->lru); | 3549 | list_del(&page->lru); |
3366 | rdata->pages[rdata->nr_pages++] = page; | 3550 | rdata->pages[rdata->nr_pages++] = page; |
3367 | } | 3551 | } |
3368 | 3552 | ||
3369 | rc = cifs_retry_async_readv(rdata); | 3553 | if (!rdata->cfile->invalidHandle || |
3370 | if (rc != 0) { | 3554 | !cifs_reopen_file(rdata->cfile, true)) |
3555 | rc = server->ops->async_readv(rdata); | ||
3556 | if (rc) { | ||
3557 | add_credits_and_wake_if(server, rdata->credits, 0); | ||
3371 | for (i = 0; i < rdata->nr_pages; i++) { | 3558 | for (i = 0; i < rdata->nr_pages; i++) { |
3372 | page = rdata->pages[i]; | 3559 | page = rdata->pages[i]; |
3373 | lru_cache_add_file(page); | 3560 | lru_cache_add_file(page); |
3374 | unlock_page(page); | 3561 | unlock_page(page); |
3375 | page_cache_release(page); | 3562 | page_cache_release(page); |
3563 | if (rc == -EAGAIN) | ||
3564 | list_add_tail(&page->lru, &tmplist); | ||
3376 | } | 3565 | } |
3377 | kref_put(&rdata->refcount, cifs_readdata_release); | 3566 | kref_put(&rdata->refcount, cifs_readdata_release); |
3567 | if (rc == -EAGAIN) { | ||
3568 | /* Re-add pages to the page_list and retry */ | ||
3569 | list_splice(&tmplist, page_list); | ||
3570 | continue; | ||
3571 | } | ||
3378 | break; | 3572 | break; |
3379 | } | 3573 | } |
3380 | 3574 | ||
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 6bf55d0ed494..81340c6253eb 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -226,6 +226,15 @@ cifs_small_buf_release(void *buf_to_free) | |||
226 | return; | 226 | return; |
227 | } | 227 | } |
228 | 228 | ||
229 | void | ||
230 | free_rsp_buf(int resp_buftype, void *rsp) | ||
231 | { | ||
232 | if (resp_buftype == CIFS_SMALL_BUFFER) | ||
233 | cifs_small_buf_release(rsp); | ||
234 | else if (resp_buftype == CIFS_LARGE_BUFFER) | ||
235 | cifs_buf_release(rsp); | ||
236 | } | ||
237 | |||
229 | /* NB: MID can not be set if treeCon not passed in, in that | 238 | /* NB: MID can not be set if treeCon not passed in, in that |
230 | case it is responsbility of caller to set the mid */ | 239 | case it is responsbility of caller to set the mid */ |
231 | void | 240 | void |
@@ -414,7 +423,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) | |||
414 | return true; | 423 | return true; |
415 | } | 424 | } |
416 | if (pSMBr->hdr.Status.CifsError) { | 425 | if (pSMBr->hdr.Status.CifsError) { |
417 | cifs_dbg(FYI, "notify err 0x%d\n", | 426 | cifs_dbg(FYI, "notify err 0x%x\n", |
418 | pSMBr->hdr.Status.CifsError); | 427 | pSMBr->hdr.Status.CifsError); |
419 | return true; | 428 | return true; |
420 | } | 429 | } |
@@ -441,7 +450,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) | |||
441 | if (pSMB->hdr.WordCount != 8) | 450 | if (pSMB->hdr.WordCount != 8) |
442 | return false; | 451 | return false; |
443 | 452 | ||
444 | cifs_dbg(FYI, "oplock type 0x%d level 0x%d\n", | 453 | cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n", |
445 | pSMB->LockType, pSMB->OplockLevel); | 454 | pSMB->LockType, pSMB->OplockLevel); |
446 | if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) | 455 | if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) |
447 | return false; | 456 | return false; |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index e87387dbf39f..39ee32688eac 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -520,382 +520,559 @@ select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) | |||
520 | } | 520 | } |
521 | } | 521 | } |
522 | 522 | ||
523 | int | 523 | struct sess_data { |
524 | CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, | 524 | unsigned int xid; |
525 | const struct nls_table *nls_cp) | 525 | struct cifs_ses *ses; |
526 | struct nls_table *nls_cp; | ||
527 | void (*func)(struct sess_data *); | ||
528 | int result; | ||
529 | |||
530 | /* we will send the SMB in three pieces: | ||
531 | * a fixed length beginning part, an optional | ||
532 | * SPNEGO blob (which can be zero length), and a | ||
533 | * last part which will include the strings | ||
534 | * and rest of bcc area. This allows us to avoid | ||
535 | * a large buffer 17K allocation | ||
536 | */ | ||
537 | int buf0_type; | ||
538 | struct kvec iov[3]; | ||
539 | }; | ||
540 | |||
541 | static int | ||
542 | sess_alloc_buffer(struct sess_data *sess_data, int wct) | ||
526 | { | 543 | { |
527 | int rc = 0; | 544 | int rc; |
528 | int wct; | 545 | struct cifs_ses *ses = sess_data->ses; |
529 | struct smb_hdr *smb_buf; | 546 | struct smb_hdr *smb_buf; |
530 | char *bcc_ptr; | ||
531 | char *str_area; | ||
532 | SESSION_SETUP_ANDX *pSMB; | ||
533 | __u32 capabilities; | ||
534 | __u16 count; | ||
535 | int resp_buf_type; | ||
536 | struct kvec iov[3]; | ||
537 | enum securityEnum type; | ||
538 | __u16 action, bytes_remaining; | ||
539 | struct key *spnego_key = NULL; | ||
540 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | ||
541 | u16 blob_len; | ||
542 | char *ntlmsspblob = NULL; | ||
543 | 547 | ||
544 | if (ses == NULL) { | 548 | rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, |
545 | WARN(1, "%s: ses == NULL!", __func__); | 549 | (void **)&smb_buf); |
546 | return -EINVAL; | ||
547 | } | ||
548 | 550 | ||
549 | type = select_sectype(ses->server, ses->sectype); | 551 | if (rc) |
550 | cifs_dbg(FYI, "sess setup type %d\n", type); | 552 | return rc; |
551 | if (type == Unspecified) { | 553 | |
552 | cifs_dbg(VFS, | 554 | sess_data->iov[0].iov_base = (char *)smb_buf; |
553 | "Unable to select appropriate authentication method!"); | 555 | sess_data->iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4; |
554 | return -EINVAL; | 556 | /* |
557 | * This variable will be used to clear the buffer | ||
558 | * allocated above in case of any error in the calling function. | ||
559 | */ | ||
560 | sess_data->buf0_type = CIFS_SMALL_BUFFER; | ||
561 | |||
562 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | ||
563 | sess_data->iov[2].iov_base = kmalloc(2000, GFP_KERNEL); | ||
564 | if (!sess_data->iov[2].iov_base) { | ||
565 | rc = -ENOMEM; | ||
566 | goto out_free_smb_buf; | ||
555 | } | 567 | } |
556 | 568 | ||
557 | if (type == RawNTLMSSP) { | 569 | return 0; |
558 | /* if memory allocation is successful, caller of this function | 570 | |
559 | * frees it. | 571 | out_free_smb_buf: |
560 | */ | 572 | kfree(smb_buf); |
561 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | 573 | sess_data->iov[0].iov_base = NULL; |
562 | if (!ses->ntlmssp) | 574 | sess_data->iov[0].iov_len = 0; |
563 | return -ENOMEM; | 575 | sess_data->buf0_type = CIFS_NO_BUFFER; |
564 | ses->ntlmssp->sesskey_per_smbsess = false; | 576 | return rc; |
577 | } | ||
578 | |||
579 | static void | ||
580 | sess_free_buffer(struct sess_data *sess_data) | ||
581 | { | ||
565 | 582 | ||
583 | free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base); | ||
584 | sess_data->buf0_type = CIFS_NO_BUFFER; | ||
585 | kfree(sess_data->iov[2].iov_base); | ||
586 | } | ||
587 | |||
588 | static int | ||
589 | sess_establish_session(struct sess_data *sess_data) | ||
590 | { | ||
591 | struct cifs_ses *ses = sess_data->ses; | ||
592 | |||
593 | mutex_lock(&ses->server->srv_mutex); | ||
594 | if (!ses->server->session_estab) { | ||
595 | if (ses->server->sign) { | ||
596 | ses->server->session_key.response = | ||
597 | kmemdup(ses->auth_key.response, | ||
598 | ses->auth_key.len, GFP_KERNEL); | ||
599 | if (!ses->server->session_key.response) { | ||
600 | mutex_unlock(&ses->server->srv_mutex); | ||
601 | return -ENOMEM; | ||
602 | } | ||
603 | ses->server->session_key.len = | ||
604 | ses->auth_key.len; | ||
605 | } | ||
606 | ses->server->sequence_number = 0x2; | ||
607 | ses->server->session_estab = true; | ||
566 | } | 608 | } |
609 | mutex_unlock(&ses->server->srv_mutex); | ||
567 | 610 | ||
568 | ssetup_ntlmssp_authenticate: | 611 | cifs_dbg(FYI, "CIFS session established successfully\n"); |
569 | if (phase == NtLmChallenge) | 612 | spin_lock(&GlobalMid_Lock); |
570 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | 613 | ses->status = CifsGood; |
614 | ses->need_reconnect = false; | ||
615 | spin_unlock(&GlobalMid_Lock); | ||
571 | 616 | ||
572 | if (type == LANMAN) { | 617 | return 0; |
573 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | 618 | } |
574 | /* LANMAN and plaintext are less secure and off by default. | ||
575 | So we make this explicitly be turned on in kconfig (in the | ||
576 | build) and turned on at runtime (changed from the default) | ||
577 | in proc/fs/cifs or via mount parm. Unfortunately this is | ||
578 | needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ | ||
579 | return -EOPNOTSUPP; | ||
580 | #endif | ||
581 | wct = 10; /* lanman 2 style sessionsetup */ | ||
582 | } else if ((type == NTLM) || (type == NTLMv2)) { | ||
583 | /* For NTLMv2 failures eventually may need to retry NTLM */ | ||
584 | wct = 13; /* old style NTLM sessionsetup */ | ||
585 | } else /* same size: negotiate or auth, NTLMSSP or extended security */ | ||
586 | wct = 12; | ||
587 | 619 | ||
588 | rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, | 620 | static int |
589 | (void **)&smb_buf); | 621 | sess_sendreceive(struct sess_data *sess_data) |
590 | if (rc) | 622 | { |
591 | return rc; | 623 | int rc; |
624 | struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base; | ||
625 | __u16 count; | ||
592 | 626 | ||
593 | pSMB = (SESSION_SETUP_ANDX *)smb_buf; | 627 | count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len; |
628 | smb_buf->smb_buf_length = | ||
629 | cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); | ||
630 | put_bcc(count, smb_buf); | ||
631 | |||
632 | rc = SendReceive2(sess_data->xid, sess_data->ses, | ||
633 | sess_data->iov, 3 /* num_iovecs */, | ||
634 | &sess_data->buf0_type, | ||
635 | CIFS_LOG_ERROR); | ||
636 | |||
637 | return rc; | ||
638 | } | ||
594 | 639 | ||
640 | /* | ||
641 | * LANMAN and plaintext are less secure and off by default. | ||
642 | * So we make this explicitly be turned on in kconfig (in the | ||
643 | * build) and turned on at runtime (changed from the default) | ||
644 | * in proc/fs/cifs or via mount parm. Unfortunately this is | ||
645 | * needed for old Win (e.g. Win95), some obscure NAS and OS/2 | ||
646 | */ | ||
647 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
648 | static void | ||
649 | sess_auth_lanman(struct sess_data *sess_data) | ||
650 | { | ||
651 | int rc = 0; | ||
652 | struct smb_hdr *smb_buf; | ||
653 | SESSION_SETUP_ANDX *pSMB; | ||
654 | char *bcc_ptr; | ||
655 | struct cifs_ses *ses = sess_data->ses; | ||
656 | char lnm_session_key[CIFS_AUTH_RESP_SIZE]; | ||
657 | __u32 capabilities; | ||
658 | __u16 bytes_remaining; | ||
659 | |||
660 | /* lanman 2 style sessionsetup */ | ||
661 | /* wct = 10 */ | ||
662 | rc = sess_alloc_buffer(sess_data, 10); | ||
663 | if (rc) | ||
664 | goto out; | ||
665 | |||
666 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
667 | bcc_ptr = sess_data->iov[2].iov_base; | ||
595 | capabilities = cifs_ssetup_hdr(ses, pSMB); | 668 | capabilities = cifs_ssetup_hdr(ses, pSMB); |
596 | 669 | ||
597 | /* we will send the SMB in three pieces: | 670 | pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; |
598 | a fixed length beginning part, an optional | ||
599 | SPNEGO blob (which can be zero length), and a | ||
600 | last part which will include the strings | ||
601 | and rest of bcc area. This allows us to avoid | ||
602 | a large buffer 17K allocation */ | ||
603 | iov[0].iov_base = (char *)pSMB; | ||
604 | iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4; | ||
605 | |||
606 | /* setting this here allows the code at the end of the function | ||
607 | to free the request buffer if there's an error */ | ||
608 | resp_buf_type = CIFS_SMALL_BUFFER; | ||
609 | 671 | ||
610 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | 672 | /* no capabilities flags in old lanman negotiation */ |
611 | str_area = kmalloc(2000, GFP_KERNEL); | 673 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
612 | if (str_area == NULL) { | ||
613 | rc = -ENOMEM; | ||
614 | goto ssetup_exit; | ||
615 | } | ||
616 | bcc_ptr = str_area; | ||
617 | 674 | ||
618 | iov[1].iov_base = NULL; | 675 | /* Calculate hash with password and copy into bcc_ptr. |
619 | iov[1].iov_len = 0; | 676 | * Encryption Key (stored as in cryptkey) gets used if the |
677 | * security mode bit in Negottiate Protocol response states | ||
678 | * to use challenge/response method (i.e. Password bit is 1). | ||
679 | */ | ||
680 | rc = calc_lanman_hash(ses->password, ses->server->cryptkey, | ||
681 | ses->server->sec_mode & SECMODE_PW_ENCRYPT ? | ||
682 | true : false, lnm_session_key); | ||
620 | 683 | ||
621 | if (type == LANMAN) { | 684 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE); |
622 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 685 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
623 | char lnm_session_key[CIFS_AUTH_RESP_SIZE]; | 686 | |
687 | /* | ||
688 | * can not sign if LANMAN negotiated so no need | ||
689 | * to calculate signing key? but what if server | ||
690 | * changed to do higher than lanman dialect and | ||
691 | * we reconnected would we ever calc signing_key? | ||
692 | */ | ||
624 | 693 | ||
625 | pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; | 694 | cifs_dbg(FYI, "Negotiating LANMAN setting up strings\n"); |
695 | /* Unicode not allowed for LANMAN dialects */ | ||
696 | ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); | ||
626 | 697 | ||
627 | /* no capabilities flags in old lanman negotiation */ | 698 | sess_data->iov[2].iov_len = (long) bcc_ptr - |
699 | (long) sess_data->iov[2].iov_base; | ||
628 | 700 | ||
629 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); | 701 | rc = sess_sendreceive(sess_data); |
702 | if (rc) | ||
703 | goto out; | ||
630 | 704 | ||
631 | /* Calculate hash with password and copy into bcc_ptr. | 705 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
632 | * Encryption Key (stored as in cryptkey) gets used if the | 706 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; |
633 | * security mode bit in Negottiate Protocol response states | ||
634 | * to use challenge/response method (i.e. Password bit is 1). | ||
635 | */ | ||
636 | 707 | ||
637 | rc = calc_lanman_hash(ses->password, ses->server->cryptkey, | 708 | /* lanman response has a word count of 3 */ |
638 | ses->server->sec_mode & SECMODE_PW_ENCRYPT ? | 709 | if (smb_buf->WordCount != 3) { |
639 | true : false, lnm_session_key); | 710 | rc = -EIO; |
711 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | ||
712 | goto out; | ||
713 | } | ||
640 | 714 | ||
641 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE); | 715 | if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) |
642 | bcc_ptr += CIFS_AUTH_RESP_SIZE; | 716 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ |
717 | |||
718 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | ||
719 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); | ||
643 | 720 | ||
644 | /* can not sign if LANMAN negotiated so no need | 721 | bytes_remaining = get_bcc(smb_buf); |
645 | to calculate signing key? but what if server | 722 | bcc_ptr = pByteArea(smb_buf); |
646 | changed to do higher than lanman dialect and | ||
647 | we reconnected would we ever calc signing_key? */ | ||
648 | 723 | ||
649 | cifs_dbg(FYI, "Negotiating LANMAN setting up strings\n"); | 724 | /* BB check if Unicode and decode strings */ |
650 | /* Unicode not allowed for LANMAN dialects */ | 725 | if (bytes_remaining == 0) { |
651 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 726 | /* no string area to decode, do nothing */ |
727 | } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { | ||
728 | /* unicode string area must be word-aligned */ | ||
729 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { | ||
730 | ++bcc_ptr; | ||
731 | --bytes_remaining; | ||
732 | } | ||
733 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, | ||
734 | sess_data->nls_cp); | ||
735 | } else { | ||
736 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, | ||
737 | sess_data->nls_cp); | ||
738 | } | ||
739 | |||
740 | rc = sess_establish_session(sess_data); | ||
741 | out: | ||
742 | sess_data->result = rc; | ||
743 | sess_data->func = NULL; | ||
744 | sess_free_buffer(sess_data); | ||
745 | } | ||
746 | |||
747 | #else | ||
748 | |||
749 | static void | ||
750 | sess_auth_lanman(struct sess_data *sess_data) | ||
751 | { | ||
752 | sess_data->result = -EOPNOTSUPP; | ||
753 | sess_data->func = NULL; | ||
754 | } | ||
652 | #endif | 755 | #endif |
653 | } else if (type == NTLM) { | 756 | |
654 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 757 | static void |
655 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | 758 | sess_auth_ntlm(struct sess_data *sess_data) |
759 | { | ||
760 | int rc = 0; | ||
761 | struct smb_hdr *smb_buf; | ||
762 | SESSION_SETUP_ANDX *pSMB; | ||
763 | char *bcc_ptr; | ||
764 | struct cifs_ses *ses = sess_data->ses; | ||
765 | __u32 capabilities; | ||
766 | __u16 bytes_remaining; | ||
767 | |||
768 | /* old style NTLM sessionsetup */ | ||
769 | /* wct = 13 */ | ||
770 | rc = sess_alloc_buffer(sess_data, 13); | ||
771 | if (rc) | ||
772 | goto out; | ||
773 | |||
774 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
775 | bcc_ptr = sess_data->iov[2].iov_base; | ||
776 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
777 | |||
778 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
779 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
656 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); | 780 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
657 | pSMB->req_no_secext.CaseSensitivePasswordLength = | 781 | pSMB->req_no_secext.CaseSensitivePasswordLength = |
658 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); | 782 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
659 | 783 | ||
660 | /* calculate ntlm response and session key */ | 784 | /* calculate ntlm response and session key */ |
661 | rc = setup_ntlm_response(ses, nls_cp); | 785 | rc = setup_ntlm_response(ses, sess_data->nls_cp); |
662 | if (rc) { | 786 | if (rc) { |
663 | cifs_dbg(VFS, "Error %d during NTLM authentication\n", | 787 | cifs_dbg(VFS, "Error %d during NTLM authentication\n", |
664 | rc); | 788 | rc); |
665 | goto ssetup_exit; | 789 | goto out; |
666 | } | 790 | } |
667 | 791 | ||
668 | /* copy ntlm response */ | 792 | /* copy ntlm response */ |
669 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | 793 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
670 | CIFS_AUTH_RESP_SIZE); | 794 | CIFS_AUTH_RESP_SIZE); |
671 | bcc_ptr += CIFS_AUTH_RESP_SIZE; | 795 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
672 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | 796 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
673 | CIFS_AUTH_RESP_SIZE); | 797 | CIFS_AUTH_RESP_SIZE); |
674 | bcc_ptr += CIFS_AUTH_RESP_SIZE; | 798 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
675 | 799 | ||
676 | if (ses->capabilities & CAP_UNICODE) { | 800 | if (ses->capabilities & CAP_UNICODE) { |
677 | /* unicode strings must be word aligned */ | 801 | /* unicode strings must be word aligned */ |
678 | if (iov[0].iov_len % 2) { | 802 | if (sess_data->iov[0].iov_len % 2) { |
679 | *bcc_ptr = 0; | 803 | *bcc_ptr = 0; |
680 | bcc_ptr++; | 804 | bcc_ptr++; |
681 | } | ||
682 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
683 | } else | ||
684 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
685 | } else if (type == NTLMv2) { | ||
686 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
687 | |||
688 | /* LM2 password would be here if we supported it */ | ||
689 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; | ||
690 | |||
691 | /* calculate nlmv2 response and session key */ | ||
692 | rc = setup_ntlmv2_rsp(ses, nls_cp); | ||
693 | if (rc) { | ||
694 | cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", | ||
695 | rc); | ||
696 | goto ssetup_exit; | ||
697 | } | 805 | } |
698 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | 806 | unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); |
699 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); | 807 | } else { |
700 | bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE; | 808 | ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); |
701 | 809 | } | |
702 | /* set case sensitive password length after tilen may get | ||
703 | * assigned, tilen is 0 otherwise. | ||
704 | */ | ||
705 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
706 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
707 | 810 | ||
708 | if (ses->capabilities & CAP_UNICODE) { | ||
709 | if (iov[0].iov_len % 2) { | ||
710 | *bcc_ptr = 0; | ||
711 | bcc_ptr++; | ||
712 | } | ||
713 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
714 | } else | ||
715 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
716 | } else if (type == Kerberos) { | ||
717 | #ifdef CONFIG_CIFS_UPCALL | ||
718 | struct cifs_spnego_msg *msg; | ||
719 | 811 | ||
720 | spnego_key = cifs_get_spnego_key(ses); | 812 | sess_data->iov[2].iov_len = (long) bcc_ptr - |
721 | if (IS_ERR(spnego_key)) { | 813 | (long) sess_data->iov[2].iov_base; |
722 | rc = PTR_ERR(spnego_key); | ||
723 | spnego_key = NULL; | ||
724 | goto ssetup_exit; | ||
725 | } | ||
726 | 814 | ||
727 | msg = spnego_key->payload.data; | 815 | rc = sess_sendreceive(sess_data); |
728 | /* check version field to make sure that cifs.upcall is | 816 | if (rc) |
729 | sending us a response in an expected form */ | 817 | goto out; |
730 | if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { | ||
731 | cifs_dbg(VFS, "incorrect version of cifs.upcall " | ||
732 | "expected %d but got %d)", | ||
733 | CIFS_SPNEGO_UPCALL_VERSION, msg->version); | ||
734 | rc = -EKEYREJECTED; | ||
735 | goto ssetup_exit; | ||
736 | } | ||
737 | 818 | ||
738 | ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, | 819 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
739 | GFP_KERNEL); | 820 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; |
740 | if (!ses->auth_key.response) { | ||
741 | cifs_dbg(VFS, | ||
742 | "Kerberos can't allocate (%u bytes) memory", | ||
743 | msg->sesskey_len); | ||
744 | rc = -ENOMEM; | ||
745 | goto ssetup_exit; | ||
746 | } | ||
747 | ses->auth_key.len = msg->sesskey_len; | ||
748 | |||
749 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
750 | capabilities |= CAP_EXTENDED_SECURITY; | ||
751 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
752 | iov[1].iov_base = msg->data + msg->sesskey_len; | ||
753 | iov[1].iov_len = msg->secblob_len; | ||
754 | pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len); | ||
755 | |||
756 | if (ses->capabilities & CAP_UNICODE) { | ||
757 | /* unicode strings must be word aligned */ | ||
758 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
759 | *bcc_ptr = 0; | ||
760 | bcc_ptr++; | ||
761 | } | ||
762 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
763 | unicode_domain_string(&bcc_ptr, ses, nls_cp); | ||
764 | } else | ||
765 | /* BB: is this right? */ | ||
766 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
767 | #else /* ! CONFIG_CIFS_UPCALL */ | ||
768 | cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n"); | ||
769 | rc = -ENOSYS; | ||
770 | goto ssetup_exit; | ||
771 | #endif /* CONFIG_CIFS_UPCALL */ | ||
772 | } else if (type == RawNTLMSSP) { | ||
773 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | ||
774 | cifs_dbg(VFS, "NTLMSSP requires Unicode support\n"); | ||
775 | rc = -ENOSYS; | ||
776 | goto ssetup_exit; | ||
777 | } | ||
778 | 821 | ||
779 | cifs_dbg(FYI, "ntlmssp session setup phase %d\n", phase); | 822 | if (smb_buf->WordCount != 3) { |
780 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 823 | rc = -EIO; |
781 | capabilities |= CAP_EXTENDED_SECURITY; | 824 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); |
782 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | 825 | goto out; |
783 | switch(phase) { | 826 | } |
784 | case NtLmNegotiate: | ||
785 | build_ntlmssp_negotiate_blob( | ||
786 | pSMB->req.SecurityBlob, ses); | ||
787 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
788 | iov[1].iov_base = pSMB->req.SecurityBlob; | ||
789 | pSMB->req.SecurityBlobLength = | ||
790 | cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
791 | break; | ||
792 | case NtLmAuthenticate: | ||
793 | /* | ||
794 | * 5 is an empirical value, large enough to hold | ||
795 | * authenticate message plus max 10 of av paris, | ||
796 | * domain, user, workstation names, flags, etc. | ||
797 | */ | ||
798 | ntlmsspblob = kzalloc( | ||
799 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
800 | GFP_KERNEL); | ||
801 | if (!ntlmsspblob) { | ||
802 | rc = -ENOMEM; | ||
803 | goto ssetup_exit; | ||
804 | } | ||
805 | 827 | ||
806 | rc = build_ntlmssp_auth_blob(ntlmsspblob, | 828 | if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) |
807 | &blob_len, ses, nls_cp); | 829 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ |
808 | if (rc) | 830 | |
809 | goto ssetup_exit; | 831 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ |
810 | iov[1].iov_len = blob_len; | 832 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); |
811 | iov[1].iov_base = ntlmsspblob; | 833 | |
812 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); | 834 | bytes_remaining = get_bcc(smb_buf); |
813 | /* | 835 | bcc_ptr = pByteArea(smb_buf); |
814 | * Make sure that we tell the server that we are using | 836 | |
815 | * the uid that it just gave us back on the response | 837 | /* BB check if Unicode and decode strings */ |
816 | * (challenge) | 838 | if (bytes_remaining == 0) { |
817 | */ | 839 | /* no string area to decode, do nothing */ |
818 | smb_buf->Uid = ses->Suid; | 840 | } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { |
819 | break; | 841 | /* unicode string area must be word-aligned */ |
820 | default: | 842 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { |
821 | cifs_dbg(VFS, "invalid phase %d\n", phase); | 843 | ++bcc_ptr; |
822 | rc = -ENOSYS; | 844 | --bytes_remaining; |
823 | goto ssetup_exit; | ||
824 | } | 845 | } |
825 | /* unicode strings must be word aligned */ | 846 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, |
826 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 847 | sess_data->nls_cp); |
848 | } else { | ||
849 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, | ||
850 | sess_data->nls_cp); | ||
851 | } | ||
852 | |||
853 | rc = sess_establish_session(sess_data); | ||
854 | out: | ||
855 | sess_data->result = rc; | ||
856 | sess_data->func = NULL; | ||
857 | sess_free_buffer(sess_data); | ||
858 | kfree(ses->auth_key.response); | ||
859 | ses->auth_key.response = NULL; | ||
860 | } | ||
861 | |||
862 | static void | ||
863 | sess_auth_ntlmv2(struct sess_data *sess_data) | ||
864 | { | ||
865 | int rc = 0; | ||
866 | struct smb_hdr *smb_buf; | ||
867 | SESSION_SETUP_ANDX *pSMB; | ||
868 | char *bcc_ptr; | ||
869 | struct cifs_ses *ses = sess_data->ses; | ||
870 | __u32 capabilities; | ||
871 | __u16 bytes_remaining; | ||
872 | |||
873 | /* old style NTLM sessionsetup */ | ||
874 | /* wct = 13 */ | ||
875 | rc = sess_alloc_buffer(sess_data, 13); | ||
876 | if (rc) | ||
877 | goto out; | ||
878 | |||
879 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
880 | bcc_ptr = sess_data->iov[2].iov_base; | ||
881 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
882 | |||
883 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
884 | |||
885 | /* LM2 password would be here if we supported it */ | ||
886 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; | ||
887 | |||
888 | /* calculate nlmv2 response and session key */ | ||
889 | rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp); | ||
890 | if (rc) { | ||
891 | cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc); | ||
892 | goto out; | ||
893 | } | ||
894 | |||
895 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
896 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
897 | bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE; | ||
898 | |||
899 | /* set case sensitive password length after tilen may get | ||
900 | * assigned, tilen is 0 otherwise. | ||
901 | */ | ||
902 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
903 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
904 | |||
905 | if (ses->capabilities & CAP_UNICODE) { | ||
906 | if (sess_data->iov[0].iov_len % 2) { | ||
827 | *bcc_ptr = 0; | 907 | *bcc_ptr = 0; |
828 | bcc_ptr++; | 908 | bcc_ptr++; |
829 | } | 909 | } |
830 | unicode_oslm_strings(&bcc_ptr, nls_cp); | 910 | unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); |
831 | } else { | 911 | } else { |
832 | cifs_dbg(VFS, "secType %d not supported!\n", type); | 912 | ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); |
833 | rc = -ENOSYS; | ||
834 | goto ssetup_exit; | ||
835 | } | 913 | } |
836 | 914 | ||
837 | iov[2].iov_base = str_area; | ||
838 | iov[2].iov_len = (long) bcc_ptr - (long) str_area; | ||
839 | 915 | ||
840 | count = iov[1].iov_len + iov[2].iov_len; | 916 | sess_data->iov[2].iov_len = (long) bcc_ptr - |
841 | smb_buf->smb_buf_length = | 917 | (long) sess_data->iov[2].iov_base; |
842 | cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); | ||
843 | 918 | ||
844 | put_bcc(count, smb_buf); | 919 | rc = sess_sendreceive(sess_data); |
920 | if (rc) | ||
921 | goto out; | ||
845 | 922 | ||
846 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, | 923 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
847 | CIFS_LOG_ERROR); | 924 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; |
848 | /* SMB request buf freed in SendReceive2 */ | 925 | |
926 | if (smb_buf->WordCount != 3) { | ||
927 | rc = -EIO; | ||
928 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | ||
929 | goto out; | ||
930 | } | ||
931 | |||
932 | if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) | ||
933 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ | ||
934 | |||
935 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | ||
936 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); | ||
849 | 937 | ||
850 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 938 | bytes_remaining = get_bcc(smb_buf); |
851 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 939 | bcc_ptr = pByteArea(smb_buf); |
852 | 940 | ||
853 | if ((type == RawNTLMSSP) && (resp_buf_type != CIFS_NO_BUFFER) && | 941 | /* BB check if Unicode and decode strings */ |
854 | (smb_buf->Status.CifsError == | 942 | if (bytes_remaining == 0) { |
855 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) { | 943 | /* no string area to decode, do nothing */ |
856 | if (phase != NtLmNegotiate) { | 944 | } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { |
857 | cifs_dbg(VFS, "Unexpected more processing error\n"); | 945 | /* unicode string area must be word-aligned */ |
858 | goto ssetup_exit; | 946 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { |
947 | ++bcc_ptr; | ||
948 | --bytes_remaining; | ||
859 | } | 949 | } |
860 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | 950 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, |
861 | phase = NtLmChallenge; /* process ntlmssp challenge */ | 951 | sess_data->nls_cp); |
862 | rc = 0; /* MORE_PROC rc is not an error here, but expected */ | 952 | } else { |
953 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, | ||
954 | sess_data->nls_cp); | ||
863 | } | 955 | } |
956 | |||
957 | rc = sess_establish_session(sess_data); | ||
958 | out: | ||
959 | sess_data->result = rc; | ||
960 | sess_data->func = NULL; | ||
961 | sess_free_buffer(sess_data); | ||
962 | kfree(ses->auth_key.response); | ||
963 | ses->auth_key.response = NULL; | ||
964 | } | ||
965 | |||
966 | #ifdef CONFIG_CIFS_UPCALL | ||
967 | static void | ||
968 | sess_auth_kerberos(struct sess_data *sess_data) | ||
969 | { | ||
970 | int rc = 0; | ||
971 | struct smb_hdr *smb_buf; | ||
972 | SESSION_SETUP_ANDX *pSMB; | ||
973 | char *bcc_ptr; | ||
974 | struct cifs_ses *ses = sess_data->ses; | ||
975 | __u32 capabilities; | ||
976 | __u16 bytes_remaining; | ||
977 | struct key *spnego_key = NULL; | ||
978 | struct cifs_spnego_msg *msg; | ||
979 | u16 blob_len; | ||
980 | |||
981 | /* extended security */ | ||
982 | /* wct = 12 */ | ||
983 | rc = sess_alloc_buffer(sess_data, 12); | ||
864 | if (rc) | 984 | if (rc) |
865 | goto ssetup_exit; | 985 | goto out; |
866 | 986 | ||
867 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | 987 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; |
988 | bcc_ptr = sess_data->iov[2].iov_base; | ||
989 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
990 | |||
991 | spnego_key = cifs_get_spnego_key(ses); | ||
992 | if (IS_ERR(spnego_key)) { | ||
993 | rc = PTR_ERR(spnego_key); | ||
994 | spnego_key = NULL; | ||
995 | goto out; | ||
996 | } | ||
997 | |||
998 | msg = spnego_key->payload.data; | ||
999 | /* | ||
1000 | * check version field to make sure that cifs.upcall is | ||
1001 | * sending us a response in an expected form | ||
1002 | */ | ||
1003 | if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { | ||
1004 | cifs_dbg(VFS, | ||
1005 | "incorrect version of cifs.upcall (expected %d but got %d)", | ||
1006 | CIFS_SPNEGO_UPCALL_VERSION, msg->version); | ||
1007 | rc = -EKEYREJECTED; | ||
1008 | goto out_put_spnego_key; | ||
1009 | } | ||
1010 | |||
1011 | ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, | ||
1012 | GFP_KERNEL); | ||
1013 | if (!ses->auth_key.response) { | ||
1014 | cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory", | ||
1015 | msg->sesskey_len); | ||
1016 | rc = -ENOMEM; | ||
1017 | goto out_put_spnego_key; | ||
1018 | } | ||
1019 | ses->auth_key.len = msg->sesskey_len; | ||
1020 | |||
1021 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
1022 | capabilities |= CAP_EXTENDED_SECURITY; | ||
1023 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
1024 | sess_data->iov[1].iov_base = msg->data + msg->sesskey_len; | ||
1025 | sess_data->iov[1].iov_len = msg->secblob_len; | ||
1026 | pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len); | ||
1027 | |||
1028 | if (ses->capabilities & CAP_UNICODE) { | ||
1029 | /* unicode strings must be word aligned */ | ||
1030 | if ((sess_data->iov[0].iov_len | ||
1031 | + sess_data->iov[1].iov_len) % 2) { | ||
1032 | *bcc_ptr = 0; | ||
1033 | bcc_ptr++; | ||
1034 | } | ||
1035 | unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); | ||
1036 | unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp); | ||
1037 | } else { | ||
1038 | /* BB: is this right? */ | ||
1039 | ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); | ||
1040 | } | ||
1041 | |||
1042 | sess_data->iov[2].iov_len = (long) bcc_ptr - | ||
1043 | (long) sess_data->iov[2].iov_base; | ||
1044 | |||
1045 | rc = sess_sendreceive(sess_data); | ||
1046 | if (rc) | ||
1047 | goto out_put_spnego_key; | ||
1048 | |||
1049 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1050 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; | ||
1051 | |||
1052 | if (smb_buf->WordCount != 4) { | ||
868 | rc = -EIO; | 1053 | rc = -EIO; |
869 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | 1054 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); |
870 | goto ssetup_exit; | 1055 | goto out_put_spnego_key; |
871 | } | 1056 | } |
872 | action = le16_to_cpu(pSMB->resp.Action); | 1057 | |
873 | if (action & GUEST_LOGIN) | 1058 | if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) |
874 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ | 1059 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ |
1060 | |||
875 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | 1061 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ |
876 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); | 1062 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); |
877 | /* response can have either 3 or 4 word count - Samba sends 3 */ | 1063 | |
878 | /* and lanman response is 3 */ | ||
879 | bytes_remaining = get_bcc(smb_buf); | 1064 | bytes_remaining = get_bcc(smb_buf); |
880 | bcc_ptr = pByteArea(smb_buf); | 1065 | bcc_ptr = pByteArea(smb_buf); |
881 | 1066 | ||
882 | if (smb_buf->WordCount == 4) { | 1067 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
883 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 1068 | if (blob_len > bytes_remaining) { |
884 | if (blob_len > bytes_remaining) { | 1069 | cifs_dbg(VFS, "bad security blob length %d\n", |
885 | cifs_dbg(VFS, "bad security blob length %d\n", | 1070 | blob_len); |
886 | blob_len); | 1071 | rc = -EINVAL; |
887 | rc = -EINVAL; | 1072 | goto out_put_spnego_key; |
888 | goto ssetup_exit; | ||
889 | } | ||
890 | if (phase == NtLmChallenge) { | ||
891 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); | ||
892 | /* now goto beginning for ntlmssp authenticate phase */ | ||
893 | if (rc) | ||
894 | goto ssetup_exit; | ||
895 | } | ||
896 | bcc_ptr += blob_len; | ||
897 | bytes_remaining -= blob_len; | ||
898 | } | 1073 | } |
1074 | bcc_ptr += blob_len; | ||
1075 | bytes_remaining -= blob_len; | ||
899 | 1076 | ||
900 | /* BB check if Unicode and decode strings */ | 1077 | /* BB check if Unicode and decode strings */ |
901 | if (bytes_remaining == 0) { | 1078 | if (bytes_remaining == 0) { |
@@ -906,60 +1083,371 @@ ssetup_ntlmssp_authenticate: | |||
906 | ++bcc_ptr; | 1083 | ++bcc_ptr; |
907 | --bytes_remaining; | 1084 | --bytes_remaining; |
908 | } | 1085 | } |
909 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); | 1086 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, |
1087 | sess_data->nls_cp); | ||
910 | } else { | 1088 | } else { |
911 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); | 1089 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, |
1090 | sess_data->nls_cp); | ||
912 | } | 1091 | } |
913 | 1092 | ||
914 | ssetup_exit: | 1093 | rc = sess_establish_session(sess_data); |
915 | if (spnego_key) { | 1094 | out_put_spnego_key: |
916 | key_invalidate(spnego_key); | 1095 | key_invalidate(spnego_key); |
917 | key_put(spnego_key); | 1096 | key_put(spnego_key); |
1097 | out: | ||
1098 | sess_data->result = rc; | ||
1099 | sess_data->func = NULL; | ||
1100 | sess_free_buffer(sess_data); | ||
1101 | kfree(ses->auth_key.response); | ||
1102 | ses->auth_key.response = NULL; | ||
1103 | } | ||
1104 | |||
1105 | #else | ||
1106 | |||
1107 | static void | ||
1108 | sess_auth_kerberos(struct sess_data *sess_data) | ||
1109 | { | ||
1110 | cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n"); | ||
1111 | sess_data->result = -ENOSYS; | ||
1112 | sess_data->func = NULL; | ||
1113 | } | ||
1114 | #endif /* ! CONFIG_CIFS_UPCALL */ | ||
1115 | |||
1116 | /* | ||
1117 | * The required kvec buffers have to be allocated before calling this | ||
1118 | * function. | ||
1119 | */ | ||
1120 | static int | ||
1121 | _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) | ||
1122 | { | ||
1123 | struct smb_hdr *smb_buf; | ||
1124 | SESSION_SETUP_ANDX *pSMB; | ||
1125 | struct cifs_ses *ses = sess_data->ses; | ||
1126 | __u32 capabilities; | ||
1127 | char *bcc_ptr; | ||
1128 | |||
1129 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1130 | smb_buf = (struct smb_hdr *)pSMB; | ||
1131 | |||
1132 | capabilities = cifs_ssetup_hdr(ses, pSMB); | ||
1133 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | ||
1134 | cifs_dbg(VFS, "NTLMSSP requires Unicode support\n"); | ||
1135 | return -ENOSYS; | ||
918 | } | 1136 | } |
919 | kfree(str_area); | ||
920 | kfree(ntlmsspblob); | ||
921 | ntlmsspblob = NULL; | ||
922 | if (resp_buf_type == CIFS_SMALL_BUFFER) { | ||
923 | cifs_dbg(FYI, "ssetup freeing small buf %p\n", iov[0].iov_base); | ||
924 | cifs_small_buf_release(iov[0].iov_base); | ||
925 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) | ||
926 | cifs_buf_release(iov[0].iov_base); | ||
927 | 1137 | ||
928 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | 1138 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
929 | if ((phase == NtLmChallenge) && (rc == 0)) | 1139 | capabilities |= CAP_EXTENDED_SECURITY; |
930 | goto ssetup_ntlmssp_authenticate; | 1140 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); |
1141 | |||
1142 | bcc_ptr = sess_data->iov[2].iov_base; | ||
1143 | /* unicode strings must be word aligned */ | ||
1144 | if ((sess_data->iov[0].iov_len + sess_data->iov[1].iov_len) % 2) { | ||
1145 | *bcc_ptr = 0; | ||
1146 | bcc_ptr++; | ||
1147 | } | ||
1148 | unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp); | ||
1149 | |||
1150 | sess_data->iov[2].iov_len = (long) bcc_ptr - | ||
1151 | (long) sess_data->iov[2].iov_base; | ||
1152 | |||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | static void | ||
1157 | sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data); | ||
1158 | |||
1159 | static void | ||
1160 | sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data) | ||
1161 | { | ||
1162 | int rc; | ||
1163 | struct smb_hdr *smb_buf; | ||
1164 | SESSION_SETUP_ANDX *pSMB; | ||
1165 | struct cifs_ses *ses = sess_data->ses; | ||
1166 | __u16 bytes_remaining; | ||
1167 | char *bcc_ptr; | ||
1168 | u16 blob_len; | ||
1169 | |||
1170 | cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n"); | ||
1171 | |||
1172 | /* | ||
1173 | * if memory allocation is successful, caller of this function | ||
1174 | * frees it. | ||
1175 | */ | ||
1176 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | ||
1177 | if (!ses->ntlmssp) { | ||
1178 | rc = -ENOMEM; | ||
1179 | goto out; | ||
1180 | } | ||
1181 | ses->ntlmssp->sesskey_per_smbsess = false; | ||
1182 | |||
1183 | /* wct = 12 */ | ||
1184 | rc = sess_alloc_buffer(sess_data, 12); | ||
1185 | if (rc) | ||
1186 | goto out; | ||
1187 | |||
1188 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1189 | |||
1190 | /* Build security blob before we assemble the request */ | ||
1191 | build_ntlmssp_negotiate_blob(pSMB->req.SecurityBlob, ses); | ||
1192 | sess_data->iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
1193 | sess_data->iov[1].iov_base = pSMB->req.SecurityBlob; | ||
1194 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
1195 | |||
1196 | rc = _sess_auth_rawntlmssp_assemble_req(sess_data); | ||
1197 | if (rc) | ||
1198 | goto out; | ||
1199 | |||
1200 | rc = sess_sendreceive(sess_data); | ||
1201 | |||
1202 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1203 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; | ||
1204 | |||
1205 | /* If true, rc here is expected and not an error */ | ||
1206 | if (sess_data->buf0_type != CIFS_NO_BUFFER && | ||
1207 | smb_buf->Status.CifsError == | ||
1208 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | ||
1209 | rc = 0; | ||
1210 | |||
1211 | if (rc) | ||
1212 | goto out; | ||
1213 | |||
1214 | cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); | ||
1215 | |||
1216 | if (smb_buf->WordCount != 4) { | ||
1217 | rc = -EIO; | ||
1218 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | ||
1219 | goto out; | ||
1220 | } | ||
1221 | |||
1222 | ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ | ||
1223 | cifs_dbg(FYI, "UID = %llu\n", ses->Suid); | ||
1224 | |||
1225 | bytes_remaining = get_bcc(smb_buf); | ||
1226 | bcc_ptr = pByteArea(smb_buf); | ||
1227 | |||
1228 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | ||
1229 | if (blob_len > bytes_remaining) { | ||
1230 | cifs_dbg(VFS, "bad security blob length %d\n", | ||
1231 | blob_len); | ||
1232 | rc = -EINVAL; | ||
1233 | goto out; | ||
1234 | } | ||
1235 | |||
1236 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); | ||
1237 | out: | ||
1238 | sess_free_buffer(sess_data); | ||
931 | 1239 | ||
932 | if (!rc) { | 1240 | if (!rc) { |
933 | mutex_lock(&ses->server->srv_mutex); | 1241 | sess_data->func = sess_auth_rawntlmssp_authenticate; |
934 | if (!ses->server->session_estab) { | 1242 | return; |
935 | if (ses->server->sign) { | 1243 | } |
936 | ses->server->session_key.response = | 1244 | |
937 | kmemdup(ses->auth_key.response, | 1245 | /* Else error. Cleanup */ |
938 | ses->auth_key.len, GFP_KERNEL); | 1246 | kfree(ses->auth_key.response); |
939 | if (!ses->server->session_key.response) { | 1247 | ses->auth_key.response = NULL; |
940 | rc = -ENOMEM; | 1248 | kfree(ses->ntlmssp); |
941 | mutex_unlock(&ses->server->srv_mutex); | 1249 | ses->ntlmssp = NULL; |
942 | goto keycp_exit; | 1250 | |
943 | } | 1251 | sess_data->func = NULL; |
944 | ses->server->session_key.len = | 1252 | sess_data->result = rc; |
945 | ses->auth_key.len; | 1253 | } |
946 | } | ||
947 | ses->server->sequence_number = 0x2; | ||
948 | ses->server->session_estab = true; | ||
949 | } | ||
950 | mutex_unlock(&ses->server->srv_mutex); | ||
951 | 1254 | ||
952 | cifs_dbg(FYI, "CIFS session established successfully\n"); | 1255 | static void |
953 | spin_lock(&GlobalMid_Lock); | 1256 | sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) |
954 | ses->status = CifsGood; | 1257 | { |
955 | ses->need_reconnect = false; | 1258 | int rc; |
956 | spin_unlock(&GlobalMid_Lock); | 1259 | struct smb_hdr *smb_buf; |
1260 | SESSION_SETUP_ANDX *pSMB; | ||
1261 | struct cifs_ses *ses = sess_data->ses; | ||
1262 | __u16 bytes_remaining; | ||
1263 | char *bcc_ptr; | ||
1264 | char *ntlmsspblob = NULL; | ||
1265 | u16 blob_len; | ||
1266 | |||
1267 | cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n"); | ||
1268 | |||
1269 | /* wct = 12 */ | ||
1270 | rc = sess_alloc_buffer(sess_data, 12); | ||
1271 | if (rc) | ||
1272 | goto out; | ||
1273 | |||
1274 | /* Build security blob before we assemble the request */ | ||
1275 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1276 | smb_buf = (struct smb_hdr *)pSMB; | ||
1277 | /* | ||
1278 | * 5 is an empirical value, large enough to hold | ||
1279 | * authenticate message plus max 10 of av paris, | ||
1280 | * domain, user, workstation names, flags, etc. | ||
1281 | */ | ||
1282 | ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
1283 | GFP_KERNEL); | ||
1284 | if (!ntlmsspblob) { | ||
1285 | rc = -ENOMEM; | ||
1286 | goto out; | ||
957 | } | 1287 | } |
958 | 1288 | ||
959 | keycp_exit: | 1289 | rc = build_ntlmssp_auth_blob(ntlmsspblob, |
1290 | &blob_len, ses, sess_data->nls_cp); | ||
1291 | if (rc) | ||
1292 | goto out_free_ntlmsspblob; | ||
1293 | sess_data->iov[1].iov_len = blob_len; | ||
1294 | sess_data->iov[1].iov_base = ntlmsspblob; | ||
1295 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); | ||
1296 | /* | ||
1297 | * Make sure that we tell the server that we are using | ||
1298 | * the uid that it just gave us back on the response | ||
1299 | * (challenge) | ||
1300 | */ | ||
1301 | smb_buf->Uid = ses->Suid; | ||
1302 | |||
1303 | rc = _sess_auth_rawntlmssp_assemble_req(sess_data); | ||
1304 | if (rc) | ||
1305 | goto out_free_ntlmsspblob; | ||
1306 | |||
1307 | rc = sess_sendreceive(sess_data); | ||
1308 | if (rc) | ||
1309 | goto out_free_ntlmsspblob; | ||
1310 | |||
1311 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | ||
1312 | smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; | ||
1313 | if (smb_buf->WordCount != 4) { | ||
1314 | rc = -EIO; | ||
1315 | cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); | ||
1316 | goto out_free_ntlmsspblob; | ||
1317 | } | ||
1318 | |||
1319 | if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) | ||
1320 | cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ | ||
1321 | |||
1322 | bytes_remaining = get_bcc(smb_buf); | ||
1323 | bcc_ptr = pByteArea(smb_buf); | ||
1324 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | ||
1325 | if (blob_len > bytes_remaining) { | ||
1326 | cifs_dbg(VFS, "bad security blob length %d\n", | ||
1327 | blob_len); | ||
1328 | rc = -EINVAL; | ||
1329 | goto out_free_ntlmsspblob; | ||
1330 | } | ||
1331 | bcc_ptr += blob_len; | ||
1332 | bytes_remaining -= blob_len; | ||
1333 | |||
1334 | |||
1335 | /* BB check if Unicode and decode strings */ | ||
1336 | if (bytes_remaining == 0) { | ||
1337 | /* no string area to decode, do nothing */ | ||
1338 | } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { | ||
1339 | /* unicode string area must be word-aligned */ | ||
1340 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { | ||
1341 | ++bcc_ptr; | ||
1342 | --bytes_remaining; | ||
1343 | } | ||
1344 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, | ||
1345 | sess_data->nls_cp); | ||
1346 | } else { | ||
1347 | decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, | ||
1348 | sess_data->nls_cp); | ||
1349 | } | ||
1350 | |||
1351 | out_free_ntlmsspblob: | ||
1352 | kfree(ntlmsspblob); | ||
1353 | out: | ||
1354 | sess_free_buffer(sess_data); | ||
1355 | |||
1356 | if (!rc) | ||
1357 | rc = sess_establish_session(sess_data); | ||
1358 | |||
1359 | /* Cleanup */ | ||
960 | kfree(ses->auth_key.response); | 1360 | kfree(ses->auth_key.response); |
961 | ses->auth_key.response = NULL; | 1361 | ses->auth_key.response = NULL; |
962 | kfree(ses->ntlmssp); | 1362 | kfree(ses->ntlmssp); |
1363 | ses->ntlmssp = NULL; | ||
1364 | |||
1365 | sess_data->func = NULL; | ||
1366 | sess_data->result = rc; | ||
1367 | } | ||
1368 | |||
1369 | static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) | ||
1370 | { | ||
1371 | int type; | ||
1372 | |||
1373 | type = select_sectype(ses->server, ses->sectype); | ||
1374 | cifs_dbg(FYI, "sess setup type %d\n", type); | ||
1375 | if (type == Unspecified) { | ||
1376 | cifs_dbg(VFS, | ||
1377 | "Unable to select appropriate authentication method!"); | ||
1378 | return -EINVAL; | ||
1379 | } | ||
1380 | |||
1381 | switch (type) { | ||
1382 | case LANMAN: | ||
1383 | /* LANMAN and plaintext are less secure and off by default. | ||
1384 | * So we make this explicitly be turned on in kconfig (in the | ||
1385 | * build) and turned on at runtime (changed from the default) | ||
1386 | * in proc/fs/cifs or via mount parm. Unfortunately this is | ||
1387 | * needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ | ||
1388 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
1389 | sess_data->func = sess_auth_lanman; | ||
1390 | break; | ||
1391 | #else | ||
1392 | return -EOPNOTSUPP; | ||
1393 | #endif | ||
1394 | case NTLM: | ||
1395 | sess_data->func = sess_auth_ntlm; | ||
1396 | break; | ||
1397 | case NTLMv2: | ||
1398 | sess_data->func = sess_auth_ntlmv2; | ||
1399 | break; | ||
1400 | case Kerberos: | ||
1401 | #ifdef CONFIG_CIFS_UPCALL | ||
1402 | sess_data->func = sess_auth_kerberos; | ||
1403 | break; | ||
1404 | #else | ||
1405 | cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n"); | ||
1406 | return -ENOSYS; | ||
1407 | break; | ||
1408 | #endif /* CONFIG_CIFS_UPCALL */ | ||
1409 | case RawNTLMSSP: | ||
1410 | sess_data->func = sess_auth_rawntlmssp_negotiate; | ||
1411 | break; | ||
1412 | default: | ||
1413 | cifs_dbg(VFS, "secType %d not supported!\n", type); | ||
1414 | return -ENOSYS; | ||
1415 | } | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, | ||
1421 | const struct nls_table *nls_cp) | ||
1422 | { | ||
1423 | int rc = 0; | ||
1424 | struct sess_data *sess_data; | ||
1425 | |||
1426 | if (ses == NULL) { | ||
1427 | WARN(1, "%s: ses == NULL!", __func__); | ||
1428 | return -EINVAL; | ||
1429 | } | ||
1430 | |||
1431 | sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL); | ||
1432 | if (!sess_data) | ||
1433 | return -ENOMEM; | ||
1434 | |||
1435 | rc = select_sec(ses, sess_data); | ||
1436 | if (rc) | ||
1437 | goto out; | ||
1438 | |||
1439 | sess_data->xid = xid; | ||
1440 | sess_data->ses = ses; | ||
1441 | sess_data->buf0_type = CIFS_NO_BUFFER; | ||
1442 | sess_data->nls_cp = (struct nls_table *) nls_cp; | ||
1443 | |||
1444 | while (sess_data->func) | ||
1445 | sess_data->func(sess_data); | ||
1446 | |||
1447 | /* Store result before we free sess_data */ | ||
1448 | rc = sess_data->result; | ||
963 | 1449 | ||
1450 | out: | ||
1451 | kfree(sess_data); | ||
964 | return rc; | 1452 | return rc; |
965 | } | 1453 | } |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index d1fdfa848703..5e8c22d6c7b9 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -1009,6 +1009,12 @@ cifs_is_read_op(__u32 oplock) | |||
1009 | return oplock == OPLOCK_READ; | 1009 | return oplock == OPLOCK_READ; |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | static unsigned int | ||
1013 | cifs_wp_retry_size(struct inode *inode) | ||
1014 | { | ||
1015 | return CIFS_SB(inode->i_sb)->wsize; | ||
1016 | } | ||
1017 | |||
1012 | struct smb_version_operations smb1_operations = { | 1018 | struct smb_version_operations smb1_operations = { |
1013 | .send_cancel = send_nt_cancel, | 1019 | .send_cancel = send_nt_cancel, |
1014 | .compare_fids = cifs_compare_fids, | 1020 | .compare_fids = cifs_compare_fids, |
@@ -1019,6 +1025,7 @@ struct smb_version_operations smb1_operations = { | |||
1019 | .set_credits = cifs_set_credits, | 1025 | .set_credits = cifs_set_credits, |
1020 | .get_credits_field = cifs_get_credits_field, | 1026 | .get_credits_field = cifs_get_credits_field, |
1021 | .get_credits = cifs_get_credits, | 1027 | .get_credits = cifs_get_credits, |
1028 | .wait_mtu_credits = cifs_wait_mtu_credits, | ||
1022 | .get_next_mid = cifs_get_next_mid, | 1029 | .get_next_mid = cifs_get_next_mid, |
1023 | .read_data_offset = cifs_read_data_offset, | 1030 | .read_data_offset = cifs_read_data_offset, |
1024 | .read_data_length = cifs_read_data_length, | 1031 | .read_data_length = cifs_read_data_length, |
@@ -1078,6 +1085,7 @@ struct smb_version_operations smb1_operations = { | |||
1078 | .query_mf_symlink = cifs_query_mf_symlink, | 1085 | .query_mf_symlink = cifs_query_mf_symlink, |
1079 | .create_mf_symlink = cifs_create_mf_symlink, | 1086 | .create_mf_symlink = cifs_create_mf_symlink, |
1080 | .is_read_op = cifs_is_read_op, | 1087 | .is_read_op = cifs_is_read_op, |
1088 | .wp_retry_size = cifs_wp_retry_size, | ||
1081 | #ifdef CONFIG_CIFS_XATTR | 1089 | #ifdef CONFIG_CIFS_XATTR |
1082 | .query_all_EAs = CIFSSMBQAllEAs, | 1090 | .query_all_EAs = CIFSSMBQAllEAs, |
1083 | .set_EA = CIFSSMBSetEA, | 1091 | .set_EA = CIFSSMBSetEA, |
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 84c012a6aba0..0150182a4494 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c | |||
@@ -91,7 +91,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon, | |||
91 | case SMB2_OP_SET_EOF: | 91 | case SMB2_OP_SET_EOF: |
92 | tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid, | 92 | tmprc = SMB2_set_eof(xid, tcon, fid.persistent_fid, |
93 | fid.volatile_fid, current->tgid, | 93 | fid.volatile_fid, current->tgid, |
94 | (__le64 *)data); | 94 | (__le64 *)data, false); |
95 | break; | 95 | break; |
96 | case SMB2_OP_SET_INFO: | 96 | case SMB2_OP_SET_INFO: |
97 | tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid, | 97 | tmprc = SMB2_set_info(xid, tcon, fid.persistent_fid, |
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index 94bd4fbb13d3..e31a9dfdcd39 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c | |||
@@ -605,7 +605,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { | |||
605 | {STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"}, | 605 | {STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"}, |
606 | {STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"}, | 606 | {STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"}, |
607 | {STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"}, | 607 | {STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"}, |
608 | {STATUS_CANNOT_DELETE, -EIO, "STATUS_CANNOT_DELETE"}, | 608 | {STATUS_CANNOT_DELETE, -EACCES, "STATUS_CANNOT_DELETE"}, |
609 | {STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"}, | 609 | {STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"}, |
610 | {STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"}, | 610 | {STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"}, |
611 | {STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"}, | 611 | {STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"}, |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index b8021fde987d..f2e6ac29a8d6 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
@@ -437,7 +437,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, | |||
437 | continue; | 437 | continue; |
438 | 438 | ||
439 | cifs_dbg(FYI, "found in the open list\n"); | 439 | cifs_dbg(FYI, "found in the open list\n"); |
440 | cifs_dbg(FYI, "lease key match, lease break 0x%d\n", | 440 | cifs_dbg(FYI, "lease key match, lease break 0x%x\n", |
441 | le32_to_cpu(rsp->NewLeaseState)); | 441 | le32_to_cpu(rsp->NewLeaseState)); |
442 | 442 | ||
443 | server->ops->set_oplock_level(cinode, lease_state, 0, NULL); | 443 | server->ops->set_oplock_level(cinode, lease_state, 0, NULL); |
@@ -467,7 +467,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, | |||
467 | } | 467 | } |
468 | 468 | ||
469 | cifs_dbg(FYI, "found in the pending open list\n"); | 469 | cifs_dbg(FYI, "found in the pending open list\n"); |
470 | cifs_dbg(FYI, "lease key match, lease break 0x%d\n", | 470 | cifs_dbg(FYI, "lease key match, lease break 0x%x\n", |
471 | le32_to_cpu(rsp->NewLeaseState)); | 471 | le32_to_cpu(rsp->NewLeaseState)); |
472 | 472 | ||
473 | open->oplock = lease_state; | 473 | open->oplock = lease_state; |
@@ -546,7 +546,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) | |||
546 | return false; | 546 | return false; |
547 | } | 547 | } |
548 | 548 | ||
549 | cifs_dbg(FYI, "oplock level 0x%d\n", rsp->OplockLevel); | 549 | cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel); |
550 | 550 | ||
551 | /* look up tcon based on tid & uid */ | 551 | /* look up tcon based on tid & uid */ |
552 | spin_lock(&cifs_tcp_ses_lock); | 552 | spin_lock(&cifs_tcp_ses_lock); |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 787844bde384..77f8aeb9c2fc 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
21 | #include <linux/vfs.h> | 21 | #include <linux/vfs.h> |
22 | #include <linux/falloc.h> | ||
22 | #include "cifsglob.h" | 23 | #include "cifsglob.h" |
23 | #include "smb2pdu.h" | 24 | #include "smb2pdu.h" |
24 | #include "smb2proto.h" | 25 | #include "smb2proto.h" |
@@ -112,6 +113,53 @@ smb2_get_credits(struct mid_q_entry *mid) | |||
112 | return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest); | 113 | return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest); |
113 | } | 114 | } |
114 | 115 | ||
116 | static int | ||
117 | smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | ||
118 | unsigned int *num, unsigned int *credits) | ||
119 | { | ||
120 | int rc = 0; | ||
121 | unsigned int scredits; | ||
122 | |||
123 | spin_lock(&server->req_lock); | ||
124 | while (1) { | ||
125 | if (server->credits <= 0) { | ||
126 | spin_unlock(&server->req_lock); | ||
127 | cifs_num_waiters_inc(server); | ||
128 | rc = wait_event_killable(server->request_q, | ||
129 | has_credits(server, &server->credits)); | ||
130 | cifs_num_waiters_dec(server); | ||
131 | if (rc) | ||
132 | return rc; | ||
133 | spin_lock(&server->req_lock); | ||
134 | } else { | ||
135 | if (server->tcpStatus == CifsExiting) { | ||
136 | spin_unlock(&server->req_lock); | ||
137 | return -ENOENT; | ||
138 | } | ||
139 | |||
140 | scredits = server->credits; | ||
141 | /* can deadlock with reopen */ | ||
142 | if (scredits == 1) { | ||
143 | *num = SMB2_MAX_BUFFER_SIZE; | ||
144 | *credits = 0; | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | /* leave one credit for a possible reopen */ | ||
149 | scredits--; | ||
150 | *num = min_t(unsigned int, size, | ||
151 | scredits * SMB2_MAX_BUFFER_SIZE); | ||
152 | |||
153 | *credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); | ||
154 | server->credits -= *credits; | ||
155 | server->in_flight++; | ||
156 | break; | ||
157 | } | ||
158 | } | ||
159 | spin_unlock(&server->req_lock); | ||
160 | return rc; | ||
161 | } | ||
162 | |||
115 | static __u64 | 163 | static __u64 |
116 | smb2_get_next_mid(struct TCP_Server_Info *server) | 164 | smb2_get_next_mid(struct TCP_Server_Info *server) |
117 | { | 165 | { |
@@ -182,8 +230,9 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | |||
182 | /* start with specified wsize, or default */ | 230 | /* start with specified wsize, or default */ |
183 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; | 231 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; |
184 | wsize = min_t(unsigned int, wsize, server->max_write); | 232 | wsize = min_t(unsigned int, wsize, server->max_write); |
185 | /* set it to the maximum buffer size value we can send with 1 credit */ | 233 | |
186 | wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); | 234 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
235 | wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); | ||
187 | 236 | ||
188 | return wsize; | 237 | return wsize; |
189 | } | 238 | } |
@@ -197,8 +246,9 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | |||
197 | /* start with specified rsize, or default */ | 246 | /* start with specified rsize, or default */ |
198 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; | 247 | rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; |
199 | rsize = min_t(unsigned int, rsize, server->max_read); | 248 | rsize = min_t(unsigned int, rsize, server->max_read); |
200 | /* set it to the maximum buffer size value we can send with 1 credit */ | 249 | |
201 | rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); | 250 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
251 | rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); | ||
202 | 252 | ||
203 | return rsize; | 253 | return rsize; |
204 | } | 254 | } |
@@ -687,7 +737,7 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, | |||
687 | { | 737 | { |
688 | __le64 eof = cpu_to_le64(size); | 738 | __le64 eof = cpu_to_le64(size); |
689 | return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, | 739 | return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, |
690 | cfile->fid.volatile_fid, cfile->pid, &eof); | 740 | cfile->fid.volatile_fid, cfile->pid, &eof, false); |
691 | } | 741 | } |
692 | 742 | ||
693 | static int | 743 | static int |
@@ -1104,6 +1154,13 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch) | |||
1104 | return le32_to_cpu(lc->lcontext.LeaseState); | 1154 | return le32_to_cpu(lc->lcontext.LeaseState); |
1105 | } | 1155 | } |
1106 | 1156 | ||
1157 | static unsigned int | ||
1158 | smb2_wp_retry_size(struct inode *inode) | ||
1159 | { | ||
1160 | return min_t(unsigned int, CIFS_SB(inode->i_sb)->wsize, | ||
1161 | SMB2_MAX_BUFFER_SIZE); | ||
1162 | } | ||
1163 | |||
1107 | struct smb_version_operations smb20_operations = { | 1164 | struct smb_version_operations smb20_operations = { |
1108 | .compare_fids = smb2_compare_fids, | 1165 | .compare_fids = smb2_compare_fids, |
1109 | .setup_request = smb2_setup_request, | 1166 | .setup_request = smb2_setup_request, |
@@ -1113,6 +1170,7 @@ struct smb_version_operations smb20_operations = { | |||
1113 | .set_credits = smb2_set_credits, | 1170 | .set_credits = smb2_set_credits, |
1114 | .get_credits_field = smb2_get_credits_field, | 1171 | .get_credits_field = smb2_get_credits_field, |
1115 | .get_credits = smb2_get_credits, | 1172 | .get_credits = smb2_get_credits, |
1173 | .wait_mtu_credits = cifs_wait_mtu_credits, | ||
1116 | .get_next_mid = smb2_get_next_mid, | 1174 | .get_next_mid = smb2_get_next_mid, |
1117 | .read_data_offset = smb2_read_data_offset, | 1175 | .read_data_offset = smb2_read_data_offset, |
1118 | .read_data_length = smb2_read_data_length, | 1176 | .read_data_length = smb2_read_data_length, |
@@ -1177,6 +1235,7 @@ struct smb_version_operations smb20_operations = { | |||
1177 | .create_lease_buf = smb2_create_lease_buf, | 1235 | .create_lease_buf = smb2_create_lease_buf, |
1178 | .parse_lease_buf = smb2_parse_lease_buf, | 1236 | .parse_lease_buf = smb2_parse_lease_buf, |
1179 | .clone_range = smb2_clone_range, | 1237 | .clone_range = smb2_clone_range, |
1238 | .wp_retry_size = smb2_wp_retry_size, | ||
1180 | }; | 1239 | }; |
1181 | 1240 | ||
1182 | struct smb_version_operations smb21_operations = { | 1241 | struct smb_version_operations smb21_operations = { |
@@ -1188,6 +1247,7 @@ struct smb_version_operations smb21_operations = { | |||
1188 | .set_credits = smb2_set_credits, | 1247 | .set_credits = smb2_set_credits, |
1189 | .get_credits_field = smb2_get_credits_field, | 1248 | .get_credits_field = smb2_get_credits_field, |
1190 | .get_credits = smb2_get_credits, | 1249 | .get_credits = smb2_get_credits, |
1250 | .wait_mtu_credits = smb2_wait_mtu_credits, | ||
1191 | .get_next_mid = smb2_get_next_mid, | 1251 | .get_next_mid = smb2_get_next_mid, |
1192 | .read_data_offset = smb2_read_data_offset, | 1252 | .read_data_offset = smb2_read_data_offset, |
1193 | .read_data_length = smb2_read_data_length, | 1253 | .read_data_length = smb2_read_data_length, |
@@ -1252,6 +1312,7 @@ struct smb_version_operations smb21_operations = { | |||
1252 | .create_lease_buf = smb2_create_lease_buf, | 1312 | .create_lease_buf = smb2_create_lease_buf, |
1253 | .parse_lease_buf = smb2_parse_lease_buf, | 1313 | .parse_lease_buf = smb2_parse_lease_buf, |
1254 | .clone_range = smb2_clone_range, | 1314 | .clone_range = smb2_clone_range, |
1315 | .wp_retry_size = smb2_wp_retry_size, | ||
1255 | }; | 1316 | }; |
1256 | 1317 | ||
1257 | struct smb_version_operations smb30_operations = { | 1318 | struct smb_version_operations smb30_operations = { |
@@ -1263,6 +1324,7 @@ struct smb_version_operations smb30_operations = { | |||
1263 | .set_credits = smb2_set_credits, | 1324 | .set_credits = smb2_set_credits, |
1264 | .get_credits_field = smb2_get_credits_field, | 1325 | .get_credits_field = smb2_get_credits_field, |
1265 | .get_credits = smb2_get_credits, | 1326 | .get_credits = smb2_get_credits, |
1327 | .wait_mtu_credits = smb2_wait_mtu_credits, | ||
1266 | .get_next_mid = smb2_get_next_mid, | 1328 | .get_next_mid = smb2_get_next_mid, |
1267 | .read_data_offset = smb2_read_data_offset, | 1329 | .read_data_offset = smb2_read_data_offset, |
1268 | .read_data_length = smb2_read_data_length, | 1330 | .read_data_length = smb2_read_data_length, |
@@ -1330,6 +1392,7 @@ struct smb_version_operations smb30_operations = { | |||
1330 | .parse_lease_buf = smb3_parse_lease_buf, | 1392 | .parse_lease_buf = smb3_parse_lease_buf, |
1331 | .clone_range = smb2_clone_range, | 1393 | .clone_range = smb2_clone_range, |
1332 | .validate_negotiate = smb3_validate_negotiate, | 1394 | .validate_negotiate = smb3_validate_negotiate, |
1395 | .wp_retry_size = smb2_wp_retry_size, | ||
1333 | }; | 1396 | }; |
1334 | 1397 | ||
1335 | struct smb_version_values smb20_values = { | 1398 | struct smb_version_values smb20_values = { |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index b0b260dbb19d..42ebc1a8be6c 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -108,7 +108,6 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
108 | if (!tcon) | 108 | if (!tcon) |
109 | goto out; | 109 | goto out; |
110 | 110 | ||
111 | /* BB FIXME when we do write > 64K add +1 for every 64K in req or rsp */ | ||
112 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ | 111 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ |
113 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ | 112 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ |
114 | if ((tcon->ses) && | 113 | if ((tcon->ses) && |
@@ -245,10 +244,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) | |||
245 | if (rc) | 244 | if (rc) |
246 | goto out; | 245 | goto out; |
247 | atomic_inc(&tconInfoReconnectCount); | 246 | atomic_inc(&tconInfoReconnectCount); |
248 | /* | ||
249 | * BB FIXME add code to check if wsize needs update due to negotiated | ||
250 | * smb buffer size shrinking. | ||
251 | */ | ||
252 | out: | 247 | out: |
253 | /* | 248 | /* |
254 | * Check if handle based operation so we know whether we can continue | 249 | * Check if handle based operation so we know whether we can continue |
@@ -309,16 +304,6 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon, | |||
309 | return rc; | 304 | return rc; |
310 | } | 305 | } |
311 | 306 | ||
312 | static void | ||
313 | free_rsp_buf(int resp_buftype, void *rsp) | ||
314 | { | ||
315 | if (resp_buftype == CIFS_SMALL_BUFFER) | ||
316 | cifs_small_buf_release(rsp); | ||
317 | else if (resp_buftype == CIFS_LARGE_BUFFER) | ||
318 | cifs_buf_release(rsp); | ||
319 | } | ||
320 | |||
321 | |||
322 | /* | 307 | /* |
323 | * | 308 | * |
324 | * SMB2 Worker functions follow: | 309 | * SMB2 Worker functions follow: |
@@ -1738,12 +1723,18 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
1738 | rc); | 1723 | rc); |
1739 | } | 1724 | } |
1740 | /* FIXME: should this be counted toward the initiating task? */ | 1725 | /* FIXME: should this be counted toward the initiating task? */ |
1741 | task_io_account_read(rdata->bytes); | 1726 | task_io_account_read(rdata->got_bytes); |
1742 | cifs_stats_bytes_read(tcon, rdata->bytes); | 1727 | cifs_stats_bytes_read(tcon, rdata->got_bytes); |
1743 | break; | 1728 | break; |
1744 | case MID_REQUEST_SUBMITTED: | 1729 | case MID_REQUEST_SUBMITTED: |
1745 | case MID_RETRY_NEEDED: | 1730 | case MID_RETRY_NEEDED: |
1746 | rdata->result = -EAGAIN; | 1731 | rdata->result = -EAGAIN; |
1732 | if (server->sign && rdata->got_bytes) | ||
1733 | /* reset bytes number since we can not check a sign */ | ||
1734 | rdata->got_bytes = 0; | ||
1735 | /* FIXME: should this be counted toward the initiating task? */ | ||
1736 | task_io_account_read(rdata->got_bytes); | ||
1737 | cifs_stats_bytes_read(tcon, rdata->got_bytes); | ||
1747 | break; | 1738 | break; |
1748 | default: | 1739 | default: |
1749 | if (rdata->result != -ENODATA) | 1740 | if (rdata->result != -ENODATA) |
@@ -1762,11 +1753,12 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
1762 | int | 1753 | int |
1763 | smb2_async_readv(struct cifs_readdata *rdata) | 1754 | smb2_async_readv(struct cifs_readdata *rdata) |
1764 | { | 1755 | { |
1765 | int rc; | 1756 | int rc, flags = 0; |
1766 | struct smb2_hdr *buf; | 1757 | struct smb2_hdr *buf; |
1767 | struct cifs_io_parms io_parms; | 1758 | struct cifs_io_parms io_parms; |
1768 | struct smb_rqst rqst = { .rq_iov = &rdata->iov, | 1759 | struct smb_rqst rqst = { .rq_iov = &rdata->iov, |
1769 | .rq_nvec = 1 }; | 1760 | .rq_nvec = 1 }; |
1761 | struct TCP_Server_Info *server; | ||
1770 | 1762 | ||
1771 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", | 1763 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", |
1772 | __func__, rdata->offset, rdata->bytes); | 1764 | __func__, rdata->offset, rdata->bytes); |
@@ -1777,18 +1769,41 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
1777 | io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; | 1769 | io_parms.persistent_fid = rdata->cfile->fid.persistent_fid; |
1778 | io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; | 1770 | io_parms.volatile_fid = rdata->cfile->fid.volatile_fid; |
1779 | io_parms.pid = rdata->pid; | 1771 | io_parms.pid = rdata->pid; |
1772 | |||
1773 | server = io_parms.tcon->ses->server; | ||
1774 | |||
1780 | rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0); | 1775 | rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0); |
1781 | if (rc) | 1776 | if (rc) { |
1777 | if (rc == -EAGAIN && rdata->credits) { | ||
1778 | /* credits was reset by reconnect */ | ||
1779 | rdata->credits = 0; | ||
1780 | /* reduce in_flight value since we won't send the req */ | ||
1781 | spin_lock(&server->req_lock); | ||
1782 | server->in_flight--; | ||
1783 | spin_unlock(&server->req_lock); | ||
1784 | } | ||
1782 | return rc; | 1785 | return rc; |
1786 | } | ||
1783 | 1787 | ||
1784 | buf = (struct smb2_hdr *)rdata->iov.iov_base; | 1788 | buf = (struct smb2_hdr *)rdata->iov.iov_base; |
1785 | /* 4 for rfc1002 length field */ | 1789 | /* 4 for rfc1002 length field */ |
1786 | rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4; | 1790 | rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4; |
1787 | 1791 | ||
1792 | if (rdata->credits) { | ||
1793 | buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, | ||
1794 | SMB2_MAX_BUFFER_SIZE)); | ||
1795 | spin_lock(&server->req_lock); | ||
1796 | server->credits += rdata->credits - | ||
1797 | le16_to_cpu(buf->CreditCharge); | ||
1798 | spin_unlock(&server->req_lock); | ||
1799 | wake_up(&server->request_q); | ||
1800 | flags = CIFS_HAS_CREDITS; | ||
1801 | } | ||
1802 | |||
1788 | kref_get(&rdata->refcount); | 1803 | kref_get(&rdata->refcount); |
1789 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, | 1804 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, |
1790 | cifs_readv_receive, smb2_readv_callback, | 1805 | cifs_readv_receive, smb2_readv_callback, |
1791 | rdata, 0); | 1806 | rdata, flags); |
1792 | if (rc) { | 1807 | if (rc) { |
1793 | kref_put(&rdata->refcount, cifs_readdata_release); | 1808 | kref_put(&rdata->refcount, cifs_readdata_release); |
1794 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); | 1809 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); |
@@ -1906,15 +1921,25 @@ int | |||
1906 | smb2_async_writev(struct cifs_writedata *wdata, | 1921 | smb2_async_writev(struct cifs_writedata *wdata, |
1907 | void (*release)(struct kref *kref)) | 1922 | void (*release)(struct kref *kref)) |
1908 | { | 1923 | { |
1909 | int rc = -EACCES; | 1924 | int rc = -EACCES, flags = 0; |
1910 | struct smb2_write_req *req = NULL; | 1925 | struct smb2_write_req *req = NULL; |
1911 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 1926 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
1927 | struct TCP_Server_Info *server = tcon->ses->server; | ||
1912 | struct kvec iov; | 1928 | struct kvec iov; |
1913 | struct smb_rqst rqst; | 1929 | struct smb_rqst rqst; |
1914 | 1930 | ||
1915 | rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req); | 1931 | rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req); |
1916 | if (rc) | 1932 | if (rc) { |
1933 | if (rc == -EAGAIN && wdata->credits) { | ||
1934 | /* credits was reset by reconnect */ | ||
1935 | wdata->credits = 0; | ||
1936 | /* reduce in_flight value since we won't send the req */ | ||
1937 | spin_lock(&server->req_lock); | ||
1938 | server->in_flight--; | ||
1939 | spin_unlock(&server->req_lock); | ||
1940 | } | ||
1917 | goto async_writev_out; | 1941 | goto async_writev_out; |
1942 | } | ||
1918 | 1943 | ||
1919 | req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid); | 1944 | req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid); |
1920 | 1945 | ||
@@ -1947,9 +1972,20 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
1947 | 1972 | ||
1948 | inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */); | 1973 | inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */); |
1949 | 1974 | ||
1975 | if (wdata->credits) { | ||
1976 | req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, | ||
1977 | SMB2_MAX_BUFFER_SIZE)); | ||
1978 | spin_lock(&server->req_lock); | ||
1979 | server->credits += wdata->credits - | ||
1980 | le16_to_cpu(req->hdr.CreditCharge); | ||
1981 | spin_unlock(&server->req_lock); | ||
1982 | wake_up(&server->request_q); | ||
1983 | flags = CIFS_HAS_CREDITS; | ||
1984 | } | ||
1985 | |||
1950 | kref_get(&wdata->refcount); | 1986 | kref_get(&wdata->refcount); |
1951 | rc = cifs_call_async(tcon->ses->server, &rqst, NULL, | 1987 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, wdata, |
1952 | smb2_writev_callback, wdata, 0); | 1988 | flags); |
1953 | 1989 | ||
1954 | if (rc) { | 1990 | if (rc) { |
1955 | kref_put(&wdata->refcount, release); | 1991 | kref_put(&wdata->refcount, release); |
@@ -2325,7 +2361,7 @@ SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
2325 | 2361 | ||
2326 | int | 2362 | int |
2327 | SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | 2363 | SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, |
2328 | u64 volatile_fid, u32 pid, __le64 *eof) | 2364 | u64 volatile_fid, u32 pid, __le64 *eof, bool is_falloc) |
2329 | { | 2365 | { |
2330 | struct smb2_file_eof_info info; | 2366 | struct smb2_file_eof_info info; |
2331 | void *data; | 2367 | void *data; |
@@ -2336,8 +2372,12 @@ SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, | |||
2336 | data = &info; | 2372 | data = &info; |
2337 | size = sizeof(struct smb2_file_eof_info); | 2373 | size = sizeof(struct smb2_file_eof_info); |
2338 | 2374 | ||
2339 | return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid, | 2375 | if (is_falloc) |
2340 | FILE_END_OF_FILE_INFORMATION, 1, &data, &size); | 2376 | return send_set_info(xid, tcon, persistent_fid, volatile_fid, |
2377 | pid, FILE_ALLOCATION_INFORMATION, 1, &data, &size); | ||
2378 | else | ||
2379 | return send_set_info(xid, tcon, persistent_fid, volatile_fid, | ||
2380 | pid, FILE_END_OF_FILE_INFORMATION, 1, &data, &size); | ||
2341 | } | 2381 | } |
2342 | 2382 | ||
2343 | int | 2383 | int |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 0ce48db20a65..67e8ce8055de 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -139,7 +139,7 @@ extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
139 | __le16 *target_file); | 139 | __le16 *target_file); |
140 | extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, | 140 | extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, |
141 | u64 persistent_fid, u64 volatile_fid, u32 pid, | 141 | u64 persistent_fid, u64 volatile_fid, u32 pid, |
142 | __le64 *eof); | 142 | __le64 *eof, bool is_fallocate); |
143 | extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, | 143 | extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, |
144 | u64 persistent_fid, u64 volatile_fid, | 144 | u64 persistent_fid, u64 volatile_fid, |
145 | FILE_BASIC_INFO *buf); | 145 | FILE_BASIC_INFO *buf); |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 59c748ce872f..5111e7272db6 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -466,7 +466,12 @@ 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 | unsigned int i, num = le16_to_cpu(hdr->CreditCharge); | ||
470 | |||
469 | hdr->MessageId = get_next_mid64(server); | 471 | hdr->MessageId = get_next_mid64(server); |
472 | /* skip message numbers according to CreditCharge field */ | ||
473 | for (i = 1; i < num; i++) | ||
474 | get_next_mid(server); | ||
470 | } | 475 | } |
471 | 476 | ||
472 | static struct mid_q_entry * | 477 | static struct mid_q_entry * |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 18cd5650a5fc..9d087f4e7d4e 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -448,6 +448,15 @@ wait_for_free_request(struct TCP_Server_Info *server, const int timeout, | |||
448 | return wait_for_free_credits(server, timeout, val); | 448 | return wait_for_free_credits(server, timeout, val); |
449 | } | 449 | } |
450 | 450 | ||
451 | int | ||
452 | cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | ||
453 | unsigned int *num, unsigned int *credits) | ||
454 | { | ||
455 | *num = size; | ||
456 | *credits = 0; | ||
457 | return 0; | ||
458 | } | ||
459 | |||
451 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, | 460 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, |
452 | struct mid_q_entry **ppmidQ) | 461 | struct mid_q_entry **ppmidQ) |
453 | { | 462 | { |
@@ -531,20 +540,23 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | |||
531 | { | 540 | { |
532 | int rc, timeout, optype; | 541 | int rc, timeout, optype; |
533 | struct mid_q_entry *mid; | 542 | struct mid_q_entry *mid; |
543 | unsigned int credits = 0; | ||
534 | 544 | ||
535 | timeout = flags & CIFS_TIMEOUT_MASK; | 545 | timeout = flags & CIFS_TIMEOUT_MASK; |
536 | optype = flags & CIFS_OP_MASK; | 546 | optype = flags & CIFS_OP_MASK; |
537 | 547 | ||
538 | rc = wait_for_free_request(server, timeout, optype); | 548 | if ((flags & CIFS_HAS_CREDITS) == 0) { |
539 | if (rc) | 549 | rc = wait_for_free_request(server, timeout, optype); |
540 | return rc; | 550 | if (rc) |
551 | return rc; | ||
552 | credits = 1; | ||
553 | } | ||
541 | 554 | ||
542 | mutex_lock(&server->srv_mutex); | 555 | mutex_lock(&server->srv_mutex); |
543 | mid = server->ops->setup_async_request(server, rqst); | 556 | mid = server->ops->setup_async_request(server, rqst); |
544 | if (IS_ERR(mid)) { | 557 | if (IS_ERR(mid)) { |
545 | mutex_unlock(&server->srv_mutex); | 558 | mutex_unlock(&server->srv_mutex); |
546 | add_credits(server, 1, optype); | 559 | add_credits_and_wake_if(server, credits, optype); |
547 | wake_up(&server->request_q); | ||
548 | return PTR_ERR(mid); | 560 | return PTR_ERR(mid); |
549 | } | 561 | } |
550 | 562 | ||
@@ -572,8 +584,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | |||
572 | return 0; | 584 | return 0; |
573 | 585 | ||
574 | cifs_delete_mid(mid); | 586 | cifs_delete_mid(mid); |
575 | add_credits(server, 1, optype); | 587 | add_credits_and_wake_if(server, credits, optype); |
576 | wake_up(&server->request_q); | ||
577 | return rc; | 588 | return rc; |
578 | } | 589 | } |
579 | 590 | ||