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 | ||
