diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-26 22:20:37 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-26 22:20:37 -0500 |
| commit | bb40784f4aeae7b9d70c49b422f78ffdfc539739 (patch) | |
| tree | 496e32e4976d59d3ddd06852af5fbc5b2831ea68 | |
| parent | 3050d45caded2d9fb8170547d08c389122c6c5d5 (diff) | |
| parent | 2b83457bded19cb57c5bdd59ebe16fe1a919c088 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
[CIFS] Fix check after use error in ACL code
[CIFS] Fix potential data corruption when writing out cached dirty pages
[CIFS] Fix spurious reconnect on 2nd peek from read of SMB length
[CIFS] remove build warning
[CIFS] Have CIFS_SessSetup build correct SPNEGO SessionSetup request
[CIFS] minor checkpatch cleanup
[CIFS] have cifs_get_spnego_key get the hostname from TCP_Server_Info
[CIFS] add hostname field to TCP_Server_Info struct
[CIFS] clean up error handling in cifs_mount
[CIFS] add ver= prefix to upcall format version
[CIFS] Fix buffer overflow if server sends corrupt response to small
| -rw-r--r-- | fs/cifs/CHANGES | 3 | ||||
| -rw-r--r-- | fs/cifs/README | 27 | ||||
| -rw-r--r-- | fs/cifs/TODO | 2 | ||||
| -rw-r--r-- | fs/cifs/cifs_spnego.c | 20 | ||||
| -rw-r--r-- | fs/cifs/cifs_spnego.h | 1 | ||||
| -rw-r--r-- | fs/cifs/cifsacl.c | 13 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 7 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 13 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 17 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 97 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 141 | ||||
| -rw-r--r-- | fs/cifs/file.c | 44 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 26 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 93 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 91 |
15 files changed, 367 insertions, 228 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 64dd22239b21..a609599287aa 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | Version 1.52 | 1 | Version 1.52 |
| 2 | ------------ | 2 | ------------ |
| 3 | Fix oops on second mount to server when null auth is used. | 3 | Fix oops on second mount to server when null auth is used. |
| 4 | Enable experimental Kerberos support. Return writebehind errors on flush | ||
| 5 | and sync so that events like out of disk space get reported properly on | ||
| 6 | cached files. | ||
| 4 | 7 | ||
| 5 | Version 1.51 | 8 | Version 1.51 |
| 6 | ------------ | 9 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index b806b11b5560..bf11329ac784 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -225,12 +225,9 @@ If no password is provided, mount.cifs will prompt for password entry | |||
| 225 | 225 | ||
| 226 | Restrictions | 226 | Restrictions |
| 227 | ============ | 227 | ============ |
| 228 | Servers must support the NTLM SMB dialect (which is the most recent, supported | ||
| 229 | by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers) | ||
| 230 | Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC | 228 | Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC |
| 231 | 1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a | 229 | 1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a |
| 232 | problem as most servers support this. IPv6 support is planned for the future, | 230 | problem as most servers support this. |
| 233 | and is almost complete. | ||
| 234 | 231 | ||
| 235 | Valid filenames differ between Windows and Linux. Windows typically restricts | 232 | Valid filenames differ between Windows and Linux. Windows typically restricts |
| 236 | filenames which contain certain reserved characters (e.g.the character : | 233 | filenames which contain certain reserved characters (e.g.the character : |
| @@ -458,6 +455,8 @@ A partial list of the supported mount options follows: | |||
| 458 | byte range locks). | 455 | byte range locks). |
| 459 | remount remount the share (often used to change from ro to rw mounts | 456 | remount remount the share (often used to change from ro to rw mounts |
| 460 | or vice versa) | 457 | or vice versa) |
| 458 | cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for | ||
| 459 | the file. (EXPERIMENTAL) | ||
| 461 | servern Specify the server 's netbios name (RFC1001 name) to use | 460 | servern Specify the server 's netbios name (RFC1001 name) to use |
| 462 | when attempting to setup a session to the server. This is | 461 | when attempting to setup a session to the server. This is |
| 463 | This is needed for mounting to some older servers (such | 462 | This is needed for mounting to some older servers (such |
| @@ -584,8 +583,8 @@ Experimental When set to 1 used to enable certain experimental | |||
| 584 | performance enhancement was disabled when | 583 | performance enhancement was disabled when |
| 585 | signing turned on in case buffer was modified | 584 | signing turned on in case buffer was modified |
| 586 | just before it was sent, also this flag will | 585 | just before it was sent, also this flag will |
| 587 | be used to use the new experimental sessionsetup | 586 | be used to use the new experimental directory change |
| 588 | code). | 587 | notification code). |
| 589 | 588 | ||
| 590 | These experimental features and tracing can be enabled by changing flags in | 589 | These experimental features and tracing can be enabled by changing flags in |
| 591 | /proc/fs/cifs (after the cifs module has been installed or built into the | 590 | /proc/fs/cifs (after the cifs module has been installed or built into the |
| @@ -608,7 +607,8 @@ the start of smb requests and responses can be enabled via: | |||
| 608 | Two other experimental features are under development. To test these | 607 | Two other experimental features are under development. To test these |
| 609 | requires enabling CONFIG_CIFS_EXPERIMENTAL | 608 | requires enabling CONFIG_CIFS_EXPERIMENTAL |
| 610 | 609 | ||
| 611 | ipv6 enablement | 610 | cifsacl support needed to retrieve approximated mode bits based on |
| 611 | the contents on the CIFS ACL. | ||
| 612 | 612 | ||
| 613 | DNOTIFY fcntl: needed for support of directory change | 613 | DNOTIFY fcntl: needed for support of directory change |
| 614 | notification and perhaps later for file leases) | 614 | notification and perhaps later for file leases) |
| @@ -625,10 +625,7 @@ that they represent all for that share, not just those for which the server | |||
| 625 | returned success. | 625 | returned success. |
| 626 | 626 | ||
| 627 | Also note that "cat /proc/fs/cifs/DebugData" will display information about | 627 | Also note that "cat /proc/fs/cifs/DebugData" will display information about |
| 628 | the active sessions and the shares that are mounted. Note: NTLMv2 enablement | 628 | the active sessions and the shares that are mounted. |
| 629 | will not work since its implementation is not quite complete yet. Do not alter | 629 | Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled |
| 630 | the ExtendedSecurity configuration value unless you are doing specific testing. | 630 | but requires a user space helper (from the Samba project). NTLM and NTLMv2 and |
| 631 | Enabling extended security works to Windows 2000 Workstations and XP but not to | 631 | LANMAN support do not require this helpr. |
| 632 | Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" | ||
| 633 | (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not | ||
| 634 | complete in the CIFS VFS yet). | ||
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 29d4b2715254..a8852c200728 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
| @@ -16,7 +16,7 @@ SecurityDescriptors | |||
| 16 | c) Better pam/winbind integration (e.g. to handle uid mapping | 16 | c) Better pam/winbind integration (e.g. to handle uid mapping |
| 17 | better) | 17 | better) |
| 18 | 18 | ||
| 19 | d) Kerberos/SPNEGO session setup support - (started) | 19 | d) Verify that Kerberos signing works |
| 20 | 20 | ||
| 21 | e) Cleanup now unneeded SessSetup code in | 21 | e) Cleanup now unneeded SessSetup code in |
| 22 | fs/cifs/connect.c and add back in NTLMSSP code if any servers | 22 | fs/cifs/connect.c and add back in NTLMSSP code if any servers |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index ad54a3a6e434..1529d2b12e9c 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
| @@ -66,20 +66,26 @@ struct key_type cifs_spnego_key_type = { | |||
| 66 | .describe = user_describe, | 66 | .describe = user_describe, |
| 67 | }; | 67 | }; |
| 68 | 68 | ||
| 69 | #define MAX_VER_STR_LEN 9 /* length of longest version string e.g. | ||
| 70 | strlen(";ver=0xFF") */ | ||
| 71 | #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg | ||
| 72 | in future could have strlen(";sec=ntlmsspi") */ | ||
| 73 | #define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ | ||
| 69 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ | 74 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ |
| 70 | struct key * | 75 | struct key * |
| 71 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname) | 76 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) |
| 72 | { | 77 | { |
| 73 | struct TCP_Server_Info *server = sesInfo->server; | 78 | struct TCP_Server_Info *server = sesInfo->server; |
| 74 | char *description, *dp; | 79 | char *description, *dp; |
| 75 | size_t desc_len; | 80 | size_t desc_len; |
| 76 | struct key *spnego_key; | 81 | struct key *spnego_key; |
| 82 | const char *hostname = server->hostname; | ||
| 77 | 83 | ||
| 78 | 84 | /* BB: come up with better scheme for determining length */ | |
| 79 | /* version + ;ip{4|6}= + address + ;host=hostname + | 85 | /* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host= |
| 80 | ;sec= + ;uid= + NULL */ | 86 | hostname sec=mechanism uid=0x uid */ |
| 81 | desc_len = 4 + 5 + 32 + 1 + 5 + strlen(hostname) + | 87 | desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 + |
| 82 | strlen(";sec=krb5") + 7 + sizeof(uid_t)*2 + 1; | 88 | strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2); |
| 83 | spnego_key = ERR_PTR(-ENOMEM); | 89 | spnego_key = ERR_PTR(-ENOMEM); |
| 84 | description = kzalloc(desc_len, GFP_KERNEL); | 90 | description = kzalloc(desc_len, GFP_KERNEL); |
| 85 | if (description == NULL) | 91 | if (description == NULL) |
| @@ -88,7 +94,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname) | |||
| 88 | dp = description; | 94 | dp = description; |
| 89 | /* start with version and hostname portion of UNC string */ | 95 | /* start with version and hostname portion of UNC string */ |
| 90 | spnego_key = ERR_PTR(-EINVAL); | 96 | spnego_key = ERR_PTR(-EINVAL); |
| 91 | sprintf(dp, "0x%2.2x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, | 97 | sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, |
| 92 | hostname); | 98 | hostname); |
| 93 | dp = description + strlen(description); | 99 | dp = description + strlen(description); |
| 94 | 100 | ||
diff --git a/fs/cifs/cifs_spnego.h b/fs/cifs/cifs_spnego.h index f443f3b35134..05a34b17a1ab 100644 --- a/fs/cifs/cifs_spnego.h +++ b/fs/cifs/cifs_spnego.h | |||
| @@ -41,6 +41,7 @@ struct cifs_spnego_msg { | |||
| 41 | 41 | ||
| 42 | #ifdef __KERNEL__ | 42 | #ifdef __KERNEL__ |
| 43 | extern struct key_type cifs_spnego_key_type; | 43 | extern struct key_type cifs_spnego_key_type; |
| 44 | extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo); | ||
| 44 | #endif /* KERNEL */ | 45 | #endif /* KERNEL */ |
| 45 | 46 | ||
| 46 | #endif /* _CIFS_SPNEGO_H */ | 47 | #endif /* _CIFS_SPNEGO_H */ |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index dabbce00712b..f02fdef463a7 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -269,6 +269,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 269 | 269 | ||
| 270 | /* BB need to add parm so we can store the SID BB */ | 270 | /* BB need to add parm so we can store the SID BB */ |
| 271 | 271 | ||
| 272 | if (!pdacl) { | ||
| 273 | /* no DACL in the security descriptor, set | ||
| 274 | all the permissions for user/group/other */ | ||
| 275 | inode->i_mode |= S_IRWXUGO; | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | |||
| 272 | /* validate that we do not go past end of acl */ | 279 | /* validate that we do not go past end of acl */ |
| 273 | if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { | 280 | if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { |
| 274 | cERROR(1, ("ACL too small to parse DACL")); | 281 | cERROR(1, ("ACL too small to parse DACL")); |
| @@ -286,12 +293,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 286 | user/group/other have no permissions */ | 293 | user/group/other have no permissions */ |
| 287 | inode->i_mode &= ~(S_IRWXUGO); | 294 | inode->i_mode &= ~(S_IRWXUGO); |
| 288 | 295 | ||
| 289 | if (!pdacl) { | ||
| 290 | /* no DACL in the security descriptor, set | ||
| 291 | all the permissions for user/group/other */ | ||
| 292 | inode->i_mode |= S_IRWXUGO; | ||
| 293 | return; | ||
| 294 | } | ||
| 295 | acl_base = (char *)pdacl; | 296 | acl_base = (char *)pdacl; |
| 296 | acl_size = sizeof(struct cifs_acl); | 297 | acl_size = sizeof(struct cifs_acl); |
| 297 | 298 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 416dc9fe8961..093beaa3900d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -266,6 +266,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
| 266 | cifs_inode->cifsAttrs = 0x20; /* default */ | 266 | cifs_inode->cifsAttrs = 0x20; /* default */ |
| 267 | atomic_set(&cifs_inode->inUse, 0); | 267 | atomic_set(&cifs_inode->inUse, 0); |
| 268 | cifs_inode->time = 0; | 268 | cifs_inode->time = 0; |
| 269 | cifs_inode->write_behind_rc = 0; | ||
| 269 | /* Until the file is open and we have gotten oplock | 270 | /* Until the file is open and we have gotten oplock |
| 270 | info back from the server, can not assume caching of | 271 | info back from the server, can not assume caching of |
| 271 | file data or metadata */ | 272 | file data or metadata */ |
| @@ -852,7 +853,7 @@ static int cifs_oplock_thread(void *dummyarg) | |||
| 852 | struct cifsTconInfo *pTcon; | 853 | struct cifsTconInfo *pTcon; |
| 853 | struct inode *inode; | 854 | struct inode *inode; |
| 854 | __u16 netfid; | 855 | __u16 netfid; |
| 855 | int rc; | 856 | int rc, waitrc = 0; |
| 856 | 857 | ||
| 857 | set_freezable(); | 858 | set_freezable(); |
| 858 | do { | 859 | do { |
| @@ -884,9 +885,11 @@ static int cifs_oplock_thread(void *dummyarg) | |||
| 884 | filemap_fdatawrite(inode->i_mapping); | 885 | filemap_fdatawrite(inode->i_mapping); |
| 885 | if (CIFS_I(inode)->clientCanCacheRead | 886 | if (CIFS_I(inode)->clientCanCacheRead |
| 886 | == 0) { | 887 | == 0) { |
| 887 | filemap_fdatawait(inode->i_mapping); | 888 | waitrc = filemap_fdatawait(inode->i_mapping); |
| 888 | invalidate_remote_inode(inode); | 889 | invalidate_remote_inode(inode); |
| 889 | } | 890 | } |
| 891 | if (rc == 0) | ||
| 892 | rc = waitrc; | ||
| 890 | } else | 893 | } else |
| 891 | rc = 0; | 894 | rc = 0; |
| 892 | /* mutex_unlock(&inode->i_mutex);*/ | 895 | /* mutex_unlock(&inode->i_mutex);*/ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 87f51f23276f..1fde2197ad76 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -110,6 +110,7 @@ struct mac_key { | |||
| 110 | unsigned int len; | 110 | unsigned int len; |
| 111 | union { | 111 | union { |
| 112 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; | 112 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; |
| 113 | char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */ | ||
| 113 | struct { | 114 | struct { |
| 114 | char key[16]; | 115 | char key[16]; |
| 115 | struct ntlmv2_resp resp; | 116 | struct ntlmv2_resp resp; |
| @@ -139,6 +140,7 @@ struct TCP_Server_Info { | |||
| 139 | /* 15 character server name + 0x20 16th byte indicating type = srv */ | 140 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
| 140 | char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; | 141 | char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; |
| 141 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; | 142 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; |
| 143 | char *hostname; /* hostname portion of UNC string */ | ||
| 142 | struct socket *ssocket; | 144 | struct socket *ssocket; |
| 143 | union { | 145 | union { |
| 144 | struct sockaddr_in sockAddr; | 146 | struct sockaddr_in sockAddr; |
| @@ -471,6 +473,17 @@ struct dir_notify_req { | |||
| 471 | #define CIFS_LARGE_BUFFER 2 | 473 | #define CIFS_LARGE_BUFFER 2 |
| 472 | #define CIFS_IOVEC 4 /* array of response buffers */ | 474 | #define CIFS_IOVEC 4 /* array of response buffers */ |
| 473 | 475 | ||
| 476 | /* Type of Request to SendReceive2 */ | ||
| 477 | #define CIFS_STD_OP 0 /* normal request timeout */ | ||
| 478 | #define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ | ||
| 479 | #define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ | ||
| 480 | #define CIFS_BLOCKING_OP 4 /* operation can block */ | ||
| 481 | #define CIFS_ASYNC_OP 8 /* do not wait for response */ | ||
| 482 | #define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */ | ||
| 483 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ | ||
| 484 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ | ||
| 485 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ | ||
| 486 | |||
| 474 | /* Security Flags: indicate type of session setup needed */ | 487 | /* Security Flags: indicate type of session setup needed */ |
| 475 | #define CIFSSEC_MAY_SIGN 0x00001 | 488 | #define CIFSSEC_MAY_SIGN 0x00001 |
| 476 | #define CIFSSEC_MAY_NTLM 0x00002 | 489 | #define CIFSSEC_MAY_NTLM 0x00002 |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index dd1d7c200ee6..8350eec49663 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -48,10 +48,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
| 48 | struct smb_hdr * /* input */ , | 48 | struct smb_hdr * /* input */ , |
| 49 | struct smb_hdr * /* out */ , | 49 | struct smb_hdr * /* out */ , |
| 50 | int * /* bytes returned */ , const int long_op); | 50 | int * /* bytes returned */ , const int long_op); |
| 51 | extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | ||
| 52 | struct smb_hdr *in_buf, int flags); | ||
| 51 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 53 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, |
| 52 | struct kvec *, int /* nvec to send */, | 54 | struct kvec *, int /* nvec to send */, |
| 53 | int * /* type of buf returned */ , const int long_op, | 55 | int * /* type of buf returned */ , const int flags); |
| 54 | const int logError /* whether to log status code*/ ); | ||
| 55 | extern int SendReceiveBlockingLock(const unsigned int /* xid */ , | 56 | extern int SendReceiveBlockingLock(const unsigned int /* xid */ , |
| 56 | struct cifsTconInfo *, | 57 | struct cifsTconInfo *, |
| 57 | struct smb_hdr * /* input */ , | 58 | struct smb_hdr * /* input */ , |
| @@ -76,8 +77,6 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , | |||
| 76 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, | 77 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, |
| 77 | struct cifsSesInfo *ses, | 78 | struct cifsSesInfo *ses, |
| 78 | void **request_buf); | 79 | void **request_buf); |
| 79 | extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo, | ||
| 80 | const char *hostname); | ||
| 81 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 80 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, |
| 82 | const int stage, | 81 | const int stage, |
| 83 | const struct nls_table *nls_cp); | 82 | const struct nls_table *nls_cp); |
| @@ -248,15 +247,15 @@ extern int CIFSSMBQueryReparseLinkInfo(const int xid, | |||
| 248 | extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 247 | extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, |
| 249 | const char *fileName, const int disposition, | 248 | const char *fileName, const int disposition, |
| 250 | const int access_flags, const int omode, | 249 | const int access_flags, const int omode, |
| 251 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | 250 | __u16 *netfid, int *pOplock, FILE_ALL_INFO *, |
| 252 | const struct nls_table *nls_codepage, int remap); | 251 | const struct nls_table *nls_codepage, int remap); |
| 253 | extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | 252 | extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, |
| 254 | const char *fileName, const int disposition, | 253 | const char *fileName, const int disposition, |
| 255 | const int access_flags, const int omode, | 254 | const int access_flags, const int omode, |
| 256 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | 255 | __u16 *netfid, int *pOplock, FILE_ALL_INFO *, |
| 257 | const struct nls_table *nls_codepage, int remap); | 256 | const struct nls_table *nls_codepage, int remap); |
| 258 | extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, | 257 | extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, |
| 259 | u32 posix_flags, __u64 mode, __u16 * netfid, | 258 | u32 posix_flags, __u64 mode, __u16 *netfid, |
| 260 | FILE_UNIX_BASIC_INFO *pRetData, | 259 | FILE_UNIX_BASIC_INFO *pRetData, |
| 261 | __u32 *pOplock, const char *name, | 260 | __u32 *pOplock, const char *name, |
| 262 | const struct nls_table *nls_codepage, int remap); | 261 | const struct nls_table *nls_codepage, int remap); |
| @@ -277,7 +276,7 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
| 277 | const __u64 offset, unsigned int *nbytes, | 276 | const __u64 offset, unsigned int *nbytes, |
| 278 | struct kvec *iov, const int nvec, const int long_op); | 277 | struct kvec *iov, const int nvec, const int long_op); |
| 279 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 278 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
| 280 | const unsigned char *searchName, __u64 * inode_number, | 279 | const unsigned char *searchName, __u64 *inode_number, |
| 281 | const struct nls_table *nls_codepage, | 280 | const struct nls_table *nls_codepage, |
| 282 | int remap_special_chars); | 281 | int remap_special_chars); |
| 283 | extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, | 282 | extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, |
| @@ -352,5 +351,5 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, | |||
| 352 | const char *local_acl, const int buflen, const int acl_type, | 351 | const char *local_acl, const int buflen, const int acl_type, |
| 353 | const struct nls_table *nls_codepage, int remap_special_chars); | 352 | const struct nls_table *nls_codepage, int remap_special_chars); |
| 354 | extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, | 353 | extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, |
| 355 | const int netfid, __u64 * pExtAttrBits, __u64 *pMask); | 354 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask); |
| 356 | #endif /* _CIFSPROTO_H */ | 355 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 59d7b7c037ad..9e8a6bef029a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -698,9 +698,7 @@ int | |||
| 698 | CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | 698 | CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) |
| 699 | { | 699 | { |
| 700 | struct smb_hdr *smb_buffer; | 700 | struct smb_hdr *smb_buffer; |
| 701 | struct smb_hdr *smb_buffer_response; /* BB removeme BB */ | ||
| 702 | int rc = 0; | 701 | int rc = 0; |
| 703 | int length; | ||
| 704 | 702 | ||
| 705 | cFYI(1, ("In tree disconnect")); | 703 | cFYI(1, ("In tree disconnect")); |
| 706 | /* | 704 | /* |
| @@ -737,16 +735,12 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
| 737 | if (rc) { | 735 | if (rc) { |
| 738 | up(&tcon->tconSem); | 736 | up(&tcon->tconSem); |
| 739 | return rc; | 737 | return rc; |
| 740 | } else { | ||
| 741 | smb_buffer_response = smb_buffer; /* BB removeme BB */ | ||
| 742 | } | 738 | } |
| 743 | rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, | 739 | |
| 744 | &length, 0); | 740 | rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); |
| 745 | if (rc) | 741 | if (rc) |
| 746 | cFYI(1, ("Tree disconnect failed %d", rc)); | 742 | cFYI(1, ("Tree disconnect failed %d", rc)); |
| 747 | 743 | ||
| 748 | if (smb_buffer) | ||
| 749 | cifs_small_buf_release(smb_buffer); | ||
| 750 | up(&tcon->tconSem); | 744 | up(&tcon->tconSem); |
| 751 | 745 | ||
| 752 | /* No need to return error on this operation if tid invalidated and | 746 | /* No need to return error on this operation if tid invalidated and |
| @@ -760,10 +754,8 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
| 760 | int | 754 | int |
| 761 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | 755 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) |
| 762 | { | 756 | { |
| 763 | struct smb_hdr *smb_buffer_response; | ||
| 764 | LOGOFF_ANDX_REQ *pSMB; | 757 | LOGOFF_ANDX_REQ *pSMB; |
| 765 | int rc = 0; | 758 | int rc = 0; |
| 766 | int length; | ||
| 767 | 759 | ||
| 768 | cFYI(1, ("In SMBLogoff for session disconnect")); | 760 | cFYI(1, ("In SMBLogoff for session disconnect")); |
| 769 | if (ses) | 761 | if (ses) |
| @@ -782,8 +774,6 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
| 782 | return rc; | 774 | return rc; |
| 783 | } | 775 | } |
| 784 | 776 | ||
| 785 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | ||
| 786 | |||
| 787 | if (ses->server) { | 777 | if (ses->server) { |
| 788 | pSMB->hdr.Mid = GetNextMid(ses->server); | 778 | pSMB->hdr.Mid = GetNextMid(ses->server); |
| 789 | 779 | ||
| @@ -795,8 +785,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
| 795 | pSMB->hdr.Uid = ses->Suid; | 785 | pSMB->hdr.Uid = ses->Suid; |
| 796 | 786 | ||
| 797 | pSMB->AndXCommand = 0xFF; | 787 | pSMB->AndXCommand = 0xFF; |
| 798 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 788 | rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); |
| 799 | smb_buffer_response, &length, 0); | ||
| 800 | if (ses->server) { | 789 | if (ses->server) { |
| 801 | atomic_dec(&ses->server->socketUseCount); | 790 | atomic_dec(&ses->server->socketUseCount); |
| 802 | if (atomic_read(&ses->server->socketUseCount) == 0) { | 791 | if (atomic_read(&ses->server->socketUseCount) == 0) { |
| @@ -807,7 +796,6 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
| 807 | } | 796 | } |
| 808 | } | 797 | } |
| 809 | up(&ses->sesSem); | 798 | up(&ses->sesSem); |
| 810 | cifs_small_buf_release(pSMB); | ||
| 811 | 799 | ||
| 812 | /* if session dead then we do not need to do ulogoff, | 800 | /* if session dead then we do not need to do ulogoff, |
| 813 | since server closed smb session, no sense reporting | 801 | since server closed smb session, no sense reporting |
| @@ -1255,7 +1243,7 @@ OldOpenRetry: | |||
| 1255 | pSMB->ByteCount = cpu_to_le16(count); | 1243 | pSMB->ByteCount = cpu_to_le16(count); |
| 1256 | /* long_op set to 1 to allow for oplock break timeouts */ | 1244 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 1257 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1245 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1258 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | 1246 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); |
| 1259 | cifs_stats_inc(&tcon->num_opens); | 1247 | cifs_stats_inc(&tcon->num_opens); |
| 1260 | if (rc) { | 1248 | if (rc) { |
| 1261 | cFYI(1, ("Error in Open = %d", rc)); | 1249 | cFYI(1, ("Error in Open = %d", rc)); |
| @@ -1368,7 +1356,7 @@ openRetry: | |||
| 1368 | pSMB->ByteCount = cpu_to_le16(count); | 1356 | pSMB->ByteCount = cpu_to_le16(count); |
| 1369 | /* long_op set to 1 to allow for oplock break timeouts */ | 1357 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 1370 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1358 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1371 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | 1359 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); |
| 1372 | cifs_stats_inc(&tcon->num_opens); | 1360 | cifs_stats_inc(&tcon->num_opens); |
| 1373 | if (rc) { | 1361 | if (rc) { |
| 1374 | cFYI(1, ("Error in Open = %d", rc)); | 1362 | cFYI(1, ("Error in Open = %d", rc)); |
| @@ -1446,7 +1434,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
| 1446 | iov[0].iov_base = (char *)pSMB; | 1434 | iov[0].iov_base = (char *)pSMB; |
| 1447 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 1435 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 1448 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 1436 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
| 1449 | &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); | 1437 | &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); |
| 1450 | cifs_stats_inc(&tcon->num_reads); | 1438 | cifs_stats_inc(&tcon->num_reads); |
| 1451 | pSMBr = (READ_RSP *)iov[0].iov_base; | 1439 | pSMBr = (READ_RSP *)iov[0].iov_base; |
| 1452 | if (rc) { | 1440 | if (rc) { |
| @@ -1665,7 +1653,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
| 1665 | 1653 | ||
| 1666 | 1654 | ||
| 1667 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, | 1655 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, |
| 1668 | long_op, 0 /* do not log STATUS code */ ); | 1656 | long_op); |
| 1669 | cifs_stats_inc(&tcon->num_writes); | 1657 | cifs_stats_inc(&tcon->num_writes); |
| 1670 | if (rc) { | 1658 | if (rc) { |
| 1671 | cFYI(1, ("Send error Write2 = %d", rc)); | 1659 | cFYI(1, ("Send error Write2 = %d", rc)); |
| @@ -1707,7 +1695,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1707 | int timeout = 0; | 1695 | int timeout = 0; |
| 1708 | __u16 count; | 1696 | __u16 count; |
| 1709 | 1697 | ||
| 1710 | cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock)); | 1698 | cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock)); |
| 1711 | rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); | 1699 | rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); |
| 1712 | 1700 | ||
| 1713 | if (rc) | 1701 | if (rc) |
| @@ -1716,10 +1704,10 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1716 | pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ | 1704 | pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ |
| 1717 | 1705 | ||
| 1718 | if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { | 1706 | if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { |
| 1719 | timeout = -1; /* no response expected */ | 1707 | timeout = CIFS_ASYNC_OP; /* no response expected */ |
| 1720 | pSMB->Timeout = 0; | 1708 | pSMB->Timeout = 0; |
| 1721 | } else if (waitFlag == TRUE) { | 1709 | } else if (waitFlag == TRUE) { |
| 1722 | timeout = 3; /* blocking operation, no timeout */ | 1710 | timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ |
| 1723 | pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ | 1711 | pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */ |
| 1724 | } else { | 1712 | } else { |
| 1725 | pSMB->Timeout = 0; | 1713 | pSMB->Timeout = 0; |
| @@ -1749,15 +1737,16 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1749 | if (waitFlag) { | 1737 | if (waitFlag) { |
| 1750 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, | 1738 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, |
| 1751 | (struct smb_hdr *) pSMBr, &bytes_returned); | 1739 | (struct smb_hdr *) pSMBr, &bytes_returned); |
| 1740 | cifs_small_buf_release(pSMB); | ||
| 1752 | } else { | 1741 | } else { |
| 1753 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1742 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, |
| 1754 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1743 | timeout); |
| 1744 | /* SMB buffer freed by function above */ | ||
| 1755 | } | 1745 | } |
| 1756 | cifs_stats_inc(&tcon->num_locks); | 1746 | cifs_stats_inc(&tcon->num_locks); |
| 1757 | if (rc) { | 1747 | if (rc) { |
| 1758 | cFYI(1, ("Send error in Lock = %d", rc)); | 1748 | cFYI(1, ("Send error in Lock = %d", rc)); |
| 1759 | } | 1749 | } |
| 1760 | cifs_small_buf_release(pSMB); | ||
| 1761 | 1750 | ||
| 1762 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1751 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
| 1763 | since file handle passed in no longer valid */ | 1752 | since file handle passed in no longer valid */ |
| @@ -1776,7 +1765,9 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1776 | int rc = 0; | 1765 | int rc = 0; |
| 1777 | int timeout = 0; | 1766 | int timeout = 0; |
| 1778 | int bytes_returned = 0; | 1767 | int bytes_returned = 0; |
| 1768 | int resp_buf_type = 0; | ||
| 1779 | __u16 params, param_offset, offset, byte_count, count; | 1769 | __u16 params, param_offset, offset, byte_count, count; |
| 1770 | struct kvec iov[1]; | ||
| 1780 | 1771 | ||
| 1781 | cFYI(1, ("Posix Lock")); | 1772 | cFYI(1, ("Posix Lock")); |
| 1782 | 1773 | ||
| @@ -1818,7 +1809,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1818 | 1809 | ||
| 1819 | parm_data->lock_type = cpu_to_le16(lock_type); | 1810 | parm_data->lock_type = cpu_to_le16(lock_type); |
| 1820 | if (waitFlag) { | 1811 | if (waitFlag) { |
| 1821 | timeout = 3; /* blocking operation, no timeout */ | 1812 | timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */ |
| 1822 | parm_data->lock_flags = cpu_to_le16(1); | 1813 | parm_data->lock_flags = cpu_to_le16(1); |
| 1823 | pSMB->Timeout = cpu_to_le32(-1); | 1814 | pSMB->Timeout = cpu_to_le32(-1); |
| 1824 | } else | 1815 | } else |
| @@ -1838,8 +1829,13 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1838 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, | 1829 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, |
| 1839 | (struct smb_hdr *) pSMBr, &bytes_returned); | 1830 | (struct smb_hdr *) pSMBr, &bytes_returned); |
| 1840 | } else { | 1831 | } else { |
| 1841 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1832 | iov[0].iov_base = (char *)pSMB; |
| 1842 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1833 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 1834 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | ||
| 1835 | &resp_buf_type, timeout); | ||
| 1836 | pSMB = NULL; /* request buf already freed by SendReceive2. Do | ||
| 1837 | not try to free it twice below on exit */ | ||
| 1838 | pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base; | ||
| 1843 | } | 1839 | } |
| 1844 | 1840 | ||
| 1845 | if (rc) { | 1841 | if (rc) { |
| @@ -1874,6 +1870,11 @@ plk_err_exit: | |||
| 1874 | if (pSMB) | 1870 | if (pSMB) |
| 1875 | cifs_small_buf_release(pSMB); | 1871 | cifs_small_buf_release(pSMB); |
| 1876 | 1872 | ||
| 1873 | if (resp_buf_type == CIFS_SMALL_BUFFER) | ||
| 1874 | cifs_small_buf_release(iov[0].iov_base); | ||
| 1875 | else if (resp_buf_type == CIFS_LARGE_BUFFER) | ||
| 1876 | cifs_buf_release(iov[0].iov_base); | ||
| 1877 | |||
| 1877 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1878 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
| 1878 | since file handle passed in no longer valid */ | 1879 | since file handle passed in no longer valid */ |
| 1879 | 1880 | ||
| @@ -1886,8 +1887,6 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
| 1886 | { | 1887 | { |
| 1887 | int rc = 0; | 1888 | int rc = 0; |
| 1888 | CLOSE_REQ *pSMB = NULL; | 1889 | CLOSE_REQ *pSMB = NULL; |
| 1889 | CLOSE_RSP *pSMBr = NULL; | ||
| 1890 | int bytes_returned; | ||
| 1891 | cFYI(1, ("In CIFSSMBClose")); | 1890 | cFYI(1, ("In CIFSSMBClose")); |
| 1892 | 1891 | ||
| 1893 | /* do not retry on dead session on close */ | 1892 | /* do not retry on dead session on close */ |
| @@ -1897,13 +1896,10 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
| 1897 | if (rc) | 1896 | if (rc) |
| 1898 | return rc; | 1897 | return rc; |
| 1899 | 1898 | ||
| 1900 | pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ | ||
| 1901 | |||
| 1902 | pSMB->FileID = (__u16) smb_file_id; | 1899 | pSMB->FileID = (__u16) smb_file_id; |
| 1903 | pSMB->LastWriteTime = 0xFFFFFFFF; | 1900 | pSMB->LastWriteTime = 0xFFFFFFFF; |
| 1904 | pSMB->ByteCount = 0; | 1901 | pSMB->ByteCount = 0; |
| 1905 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1902 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
| 1906 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 1907 | cifs_stats_inc(&tcon->num_closes); | 1903 | cifs_stats_inc(&tcon->num_closes); |
| 1908 | if (rc) { | 1904 | if (rc) { |
| 1909 | if (rc != -EINTR) { | 1905 | if (rc != -EINTR) { |
| @@ -1912,8 +1908,6 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
| 1912 | } | 1908 | } |
| 1913 | } | 1909 | } |
| 1914 | 1910 | ||
| 1915 | cifs_small_buf_release(pSMB); | ||
| 1916 | |||
| 1917 | /* Since session is dead, file will be closed on server already */ | 1911 | /* Since session is dead, file will be closed on server already */ |
| 1918 | if (rc == -EAGAIN) | 1912 | if (rc == -EAGAIN) |
| 1919 | rc = 0; | 1913 | rc = 0; |
| @@ -3102,7 +3096,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | |||
| 3102 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 3096 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 3103 | 3097 | ||
| 3104 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 3098 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
| 3105 | 0 /* not long op */, 0 /* do not log STATUS codes */ ); | 3099 | CIFS_STD_OP); |
| 3106 | cifs_stats_inc(&tcon->num_acl_get); | 3100 | cifs_stats_inc(&tcon->num_acl_get); |
| 3107 | if (rc) { | 3101 | if (rc) { |
| 3108 | cFYI(1, ("Send error in QuerySecDesc = %d", rc)); | 3102 | cFYI(1, ("Send error in QuerySecDesc = %d", rc)); |
| @@ -3763,8 +3757,6 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, | |||
| 3763 | { | 3757 | { |
| 3764 | int rc = 0; | 3758 | int rc = 0; |
| 3765 | FINDCLOSE_REQ *pSMB = NULL; | 3759 | FINDCLOSE_REQ *pSMB = NULL; |
| 3766 | CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */ | ||
| 3767 | int bytes_returned; | ||
| 3768 | 3760 | ||
| 3769 | cFYI(1, ("In CIFSSMBFindClose")); | 3761 | cFYI(1, ("In CIFSSMBFindClose")); |
| 3770 | rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); | 3762 | rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB); |
| @@ -3776,16 +3768,13 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, | |||
| 3776 | if (rc) | 3768 | if (rc) |
| 3777 | return rc; | 3769 | return rc; |
| 3778 | 3770 | ||
| 3779 | pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ | ||
| 3780 | pSMB->FileID = searchHandle; | 3771 | pSMB->FileID = searchHandle; |
| 3781 | pSMB->ByteCount = 0; | 3772 | pSMB->ByteCount = 0; |
| 3782 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3773 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
| 3783 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 3784 | if (rc) { | 3774 | if (rc) { |
| 3785 | cERROR(1, ("Send error in FindClose = %d", rc)); | 3775 | cERROR(1, ("Send error in FindClose = %d", rc)); |
| 3786 | } | 3776 | } |
| 3787 | cifs_stats_inc(&tcon->num_fclose); | 3777 | cifs_stats_inc(&tcon->num_fclose); |
| 3788 | cifs_small_buf_release(pSMB); | ||
| 3789 | 3778 | ||
| 3790 | /* Since session is dead, search handle closed on server already */ | 3779 | /* Since session is dead, search handle closed on server already */ |
| 3791 | if (rc == -EAGAIN) | 3780 | if (rc == -EAGAIN) |
| @@ -4707,11 +4696,9 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
| 4707 | __u16 fid, __u32 pid_of_opener, int SetAllocation) | 4696 | __u16 fid, __u32 pid_of_opener, int SetAllocation) |
| 4708 | { | 4697 | { |
| 4709 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 4698 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
| 4710 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | ||
| 4711 | char *data_offset; | 4699 | char *data_offset; |
| 4712 | struct file_end_of_file_info *parm_data; | 4700 | struct file_end_of_file_info *parm_data; |
| 4713 | int rc = 0; | 4701 | int rc = 0; |
| 4714 | int bytes_returned = 0; | ||
| 4715 | __u16 params, param_offset, offset, byte_count, count; | 4702 | __u16 params, param_offset, offset, byte_count, count; |
| 4716 | 4703 | ||
| 4717 | cFYI(1, ("SetFileSize (via SetFileInfo) %lld", | 4704 | cFYI(1, ("SetFileSize (via SetFileInfo) %lld", |
| @@ -4721,8 +4708,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
| 4721 | if (rc) | 4708 | if (rc) |
| 4722 | return rc; | 4709 | return rc; |
| 4723 | 4710 | ||
| 4724 | pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; | ||
| 4725 | |||
| 4726 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | 4711 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); |
| 4727 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | 4712 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); |
| 4728 | 4713 | ||
| @@ -4773,17 +4758,13 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
| 4773 | pSMB->Reserved4 = 0; | 4758 | pSMB->Reserved4 = 0; |
| 4774 | pSMB->hdr.smb_buf_length += byte_count; | 4759 | pSMB->hdr.smb_buf_length += byte_count; |
| 4775 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4760 | pSMB->ByteCount = cpu_to_le16(byte_count); |
| 4776 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4761 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
| 4777 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 4778 | if (rc) { | 4762 | if (rc) { |
| 4779 | cFYI(1, | 4763 | cFYI(1, |
| 4780 | ("Send error in SetFileInfo (SetFileSize) = %d", | 4764 | ("Send error in SetFileInfo (SetFileSize) = %d", |
| 4781 | rc)); | 4765 | rc)); |
| 4782 | } | 4766 | } |
| 4783 | 4767 | ||
| 4784 | if (pSMB) | ||
| 4785 | cifs_small_buf_release(pSMB); | ||
| 4786 | |||
| 4787 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 4768 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
| 4788 | since file handle passed in no longer valid */ | 4769 | since file handle passed in no longer valid */ |
| 4789 | 4770 | ||
| @@ -4801,10 +4782,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | |||
| 4801 | const FILE_BASIC_INFO *data, __u16 fid) | 4782 | const FILE_BASIC_INFO *data, __u16 fid) |
| 4802 | { | 4783 | { |
| 4803 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 4784 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
| 4804 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | ||
| 4805 | char *data_offset; | 4785 | char *data_offset; |
| 4806 | int rc = 0; | 4786 | int rc = 0; |
| 4807 | int bytes_returned = 0; | ||
| 4808 | __u16 params, param_offset, offset, byte_count, count; | 4787 | __u16 params, param_offset, offset, byte_count, count; |
| 4809 | 4788 | ||
| 4810 | cFYI(1, ("Set Times (via SetFileInfo)")); | 4789 | cFYI(1, ("Set Times (via SetFileInfo)")); |
| @@ -4813,8 +4792,6 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | |||
| 4813 | if (rc) | 4792 | if (rc) |
| 4814 | return rc; | 4793 | return rc; |
| 4815 | 4794 | ||
| 4816 | pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB; | ||
| 4817 | |||
| 4818 | /* At this point there is no need to override the current pid | 4795 | /* At this point there is no need to override the current pid |
| 4819 | with the pid of the opener, but that could change if we someday | 4796 | with the pid of the opener, but that could change if we someday |
| 4820 | use an existing handle (rather than opening one on the fly) */ | 4797 | use an existing handle (rather than opening one on the fly) */ |
| @@ -4854,14 +4831,11 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | |||
| 4854 | pSMB->hdr.smb_buf_length += byte_count; | 4831 | pSMB->hdr.smb_buf_length += byte_count; |
| 4855 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4832 | pSMB->ByteCount = cpu_to_le16(byte_count); |
| 4856 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); | 4833 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); |
| 4857 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4834 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
| 4858 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 4859 | if (rc) { | 4835 | if (rc) { |
| 4860 | cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc)); | 4836 | cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc)); |
| 4861 | } | 4837 | } |
| 4862 | 4838 | ||
| 4863 | cifs_small_buf_release(pSMB); | ||
| 4864 | |||
| 4865 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 4839 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
| 4866 | since file handle passed in no longer valid */ | 4840 | since file handle passed in no longer valid */ |
| 4867 | 4841 | ||
| @@ -5152,7 +5126,8 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
| 5152 | pSMB->ByteCount = 0; | 5126 | pSMB->ByteCount = 0; |
| 5153 | 5127 | ||
| 5154 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5128 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 5155 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); | 5129 | (struct smb_hdr *)pSMBr, &bytes_returned, |
| 5130 | CIFS_ASYNC_OP); | ||
| 5156 | if (rc) { | 5131 | if (rc) { |
| 5157 | cFYI(1, ("Error in Notify = %d", rc)); | 5132 | cFYI(1, ("Error in Notify = %d", rc)); |
| 5158 | } else { | 5133 | } else { |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c52a76ff4bb9..fd9147cdb5a9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -438,9 +438,9 @@ incomplete_rcv: | |||
| 438 | csocket = server->ssocket; | 438 | csocket = server->ssocket; |
| 439 | wake_up(&server->response_q); | 439 | wake_up(&server->response_q); |
| 440 | continue; | 440 | continue; |
| 441 | } else if (length < 4) { | 441 | } else if (length < pdu_length) { |
| 442 | cFYI(1, ("less than four bytes received (%d bytes)", | 442 | cFYI(1, ("requested %d bytes but only got %d bytes", |
| 443 | length)); | 443 | pdu_length, length)); |
| 444 | pdu_length -= length; | 444 | pdu_length -= length; |
| 445 | msleep(1); | 445 | msleep(1); |
| 446 | goto incomplete_rcv; | 446 | goto incomplete_rcv; |
| @@ -752,6 +752,7 @@ multi_t2_fnd: | |||
| 752 | } | 752 | } |
| 753 | write_unlock(&GlobalSMBSeslock); | 753 | write_unlock(&GlobalSMBSeslock); |
| 754 | 754 | ||
| 755 | kfree(server->hostname); | ||
| 755 | kfree(server); | 756 | kfree(server); |
| 756 | if (length > 0) | 757 | if (length > 0) |
| 757 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, | 758 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, |
| @@ -760,6 +761,34 @@ multi_t2_fnd: | |||
| 760 | return 0; | 761 | return 0; |
| 761 | } | 762 | } |
| 762 | 763 | ||
| 764 | /* extract the host portion of the UNC string */ | ||
| 765 | static char * | ||
| 766 | extract_hostname(const char *unc) | ||
| 767 | { | ||
| 768 | const char *src; | ||
| 769 | char *dst, *delim; | ||
| 770 | unsigned int len; | ||
| 771 | |||
| 772 | /* skip double chars at beginning of string */ | ||
| 773 | /* BB: check validity of these bytes? */ | ||
| 774 | src = unc + 2; | ||
| 775 | |||
| 776 | /* delimiter between hostname and sharename is always '\\' now */ | ||
| 777 | delim = strchr(src, '\\'); | ||
| 778 | if (!delim) | ||
| 779 | return ERR_PTR(-EINVAL); | ||
| 780 | |||
| 781 | len = delim - src; | ||
| 782 | dst = kmalloc((len + 1), GFP_KERNEL); | ||
| 783 | if (dst == NULL) | ||
| 784 | return ERR_PTR(-ENOMEM); | ||
| 785 | |||
| 786 | memcpy(dst, src, len); | ||
| 787 | dst[len] = '\0'; | ||
| 788 | |||
| 789 | return dst; | ||
| 790 | } | ||
| 791 | |||
| 763 | static int | 792 | static int |
| 764 | cifs_parse_mount_options(char *options, const char *devname, | 793 | cifs_parse_mount_options(char *options, const char *devname, |
| 765 | struct smb_vol *vol) | 794 | struct smb_vol *vol) |
| @@ -1781,11 +1810,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1781 | 1810 | ||
| 1782 | memset(&volume_info, 0, sizeof(struct smb_vol)); | 1811 | memset(&volume_info, 0, sizeof(struct smb_vol)); |
| 1783 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { | 1812 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { |
| 1784 | kfree(volume_info.UNC); | 1813 | rc = -EINVAL; |
| 1785 | kfree(volume_info.password); | 1814 | goto out; |
| 1786 | kfree(volume_info.prepath); | ||
| 1787 | FreeXid(xid); | ||
| 1788 | return -EINVAL; | ||
| 1789 | } | 1815 | } |
| 1790 | 1816 | ||
| 1791 | if (volume_info.nullauth) { | 1817 | if (volume_info.nullauth) { |
| @@ -1798,11 +1824,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1798 | cifserror("No username specified"); | 1824 | cifserror("No username specified"); |
| 1799 | /* In userspace mount helper we can get user name from alternate | 1825 | /* In userspace mount helper we can get user name from alternate |
| 1800 | locations such as env variables and files on disk */ | 1826 | locations such as env variables and files on disk */ |
| 1801 | kfree(volume_info.UNC); | 1827 | rc = -EINVAL; |
| 1802 | kfree(volume_info.password); | 1828 | goto out; |
| 1803 | kfree(volume_info.prepath); | ||
| 1804 | FreeXid(xid); | ||
| 1805 | return -EINVAL; | ||
| 1806 | } | 1829 | } |
| 1807 | 1830 | ||
| 1808 | if (volume_info.UNCip && volume_info.UNC) { | 1831 | if (volume_info.UNCip && volume_info.UNC) { |
| @@ -1821,11 +1844,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1821 | 1844 | ||
| 1822 | if (rc <= 0) { | 1845 | if (rc <= 0) { |
| 1823 | /* we failed translating address */ | 1846 | /* we failed translating address */ |
| 1824 | kfree(volume_info.UNC); | 1847 | rc = -EINVAL; |
| 1825 | kfree(volume_info.password); | 1848 | goto out; |
| 1826 | kfree(volume_info.prepath); | ||
| 1827 | FreeXid(xid); | ||
| 1828 | return -EINVAL; | ||
| 1829 | } | 1849 | } |
| 1830 | 1850 | ||
| 1831 | cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); | 1851 | cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); |
| @@ -1835,20 +1855,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1835 | /* BB using ip addr as server name to connect to the | 1855 | /* BB using ip addr as server name to connect to the |
| 1836 | DFS root below */ | 1856 | DFS root below */ |
| 1837 | cERROR(1, ("Connecting to DFS root not implemented yet")); | 1857 | cERROR(1, ("Connecting to DFS root not implemented yet")); |
| 1838 | kfree(volume_info.UNC); | 1858 | rc = -EINVAL; |
| 1839 | kfree(volume_info.password); | 1859 | goto out; |
| 1840 | kfree(volume_info.prepath); | ||
| 1841 | FreeXid(xid); | ||
| 1842 | return -EINVAL; | ||
| 1843 | } else /* which servers DFS root would we conect to */ { | 1860 | } else /* which servers DFS root would we conect to */ { |
| 1844 | cERROR(1, | 1861 | cERROR(1, |
| 1845 | ("CIFS mount error: No UNC path (e.g. -o " | 1862 | ("CIFS mount error: No UNC path (e.g. -o " |
| 1846 | "unc=//192.168.1.100/public) specified")); | 1863 | "unc=//192.168.1.100/public) specified")); |
| 1847 | kfree(volume_info.UNC); | 1864 | rc = -EINVAL; |
| 1848 | kfree(volume_info.password); | 1865 | goto out; |
| 1849 | kfree(volume_info.prepath); | ||
| 1850 | FreeXid(xid); | ||
| 1851 | return -EINVAL; | ||
| 1852 | } | 1866 | } |
| 1853 | 1867 | ||
| 1854 | /* this is needed for ASCII cp to Unicode converts */ | 1868 | /* this is needed for ASCII cp to Unicode converts */ |
| @@ -1860,11 +1874,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1860 | if (cifs_sb->local_nls == NULL) { | 1874 | if (cifs_sb->local_nls == NULL) { |
| 1861 | cERROR(1, ("CIFS mount error: iocharset %s not found", | 1875 | cERROR(1, ("CIFS mount error: iocharset %s not found", |
| 1862 | volume_info.iocharset)); | 1876 | volume_info.iocharset)); |
| 1863 | kfree(volume_info.UNC); | 1877 | rc = -ELIBACC; |
| 1864 | kfree(volume_info.password); | 1878 | goto out; |
| 1865 | kfree(volume_info.prepath); | ||
| 1866 | FreeXid(xid); | ||
| 1867 | return -ELIBACC; | ||
| 1868 | } | 1879 | } |
| 1869 | } | 1880 | } |
| 1870 | 1881 | ||
| @@ -1878,11 +1889,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1878 | &sin_server6.sin6_addr, | 1889 | &sin_server6.sin6_addr, |
| 1879 | volume_info.username, &srvTcp); | 1890 | volume_info.username, &srvTcp); |
| 1880 | } else { | 1891 | } else { |
| 1881 | kfree(volume_info.UNC); | 1892 | rc = -EINVAL; |
| 1882 | kfree(volume_info.password); | 1893 | goto out; |
| 1883 | kfree(volume_info.prepath); | ||
| 1884 | FreeXid(xid); | ||
| 1885 | return -EINVAL; | ||
| 1886 | } | 1894 | } |
| 1887 | 1895 | ||
| 1888 | if (srvTcp) { | 1896 | if (srvTcp) { |
| @@ -1906,22 +1914,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1906 | "Aborting operation")); | 1914 | "Aborting operation")); |
| 1907 | if (csocket != NULL) | 1915 | if (csocket != NULL) |
| 1908 | sock_release(csocket); | 1916 | sock_release(csocket); |
| 1909 | kfree(volume_info.UNC); | 1917 | goto out; |
| 1910 | kfree(volume_info.password); | ||
| 1911 | kfree(volume_info.prepath); | ||
| 1912 | FreeXid(xid); | ||
| 1913 | return rc; | ||
| 1914 | } | 1918 | } |
| 1915 | 1919 | ||
| 1916 | srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); | 1920 | srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); |
| 1917 | if (!srvTcp) { | 1921 | if (!srvTcp) { |
| 1918 | rc = -ENOMEM; | 1922 | rc = -ENOMEM; |
| 1919 | sock_release(csocket); | 1923 | sock_release(csocket); |
| 1920 | kfree(volume_info.UNC); | 1924 | goto out; |
| 1921 | kfree(volume_info.password); | ||
| 1922 | kfree(volume_info.prepath); | ||
| 1923 | FreeXid(xid); | ||
| 1924 | return rc; | ||
| 1925 | } else { | 1925 | } else { |
| 1926 | memcpy(&srvTcp->addr.sockAddr, &sin_server, | 1926 | memcpy(&srvTcp->addr.sockAddr, &sin_server, |
| 1927 | sizeof(struct sockaddr_in)); | 1927 | sizeof(struct sockaddr_in)); |
| @@ -1929,6 +1929,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1929 | /* BB Add code for ipv6 case too */ | 1929 | /* BB Add code for ipv6 case too */ |
| 1930 | srvTcp->ssocket = csocket; | 1930 | srvTcp->ssocket = csocket; |
| 1931 | srvTcp->protocolType = IPV4; | 1931 | srvTcp->protocolType = IPV4; |
| 1932 | srvTcp->hostname = extract_hostname(volume_info.UNC); | ||
| 1933 | if (IS_ERR(srvTcp->hostname)) { | ||
| 1934 | rc = PTR_ERR(srvTcp->hostname); | ||
| 1935 | sock_release(csocket); | ||
| 1936 | goto out; | ||
| 1937 | } | ||
| 1932 | init_waitqueue_head(&srvTcp->response_q); | 1938 | init_waitqueue_head(&srvTcp->response_q); |
| 1933 | init_waitqueue_head(&srvTcp->request_q); | 1939 | init_waitqueue_head(&srvTcp->request_q); |
| 1934 | INIT_LIST_HEAD(&srvTcp->pending_mid_q); | 1940 | INIT_LIST_HEAD(&srvTcp->pending_mid_q); |
| @@ -1938,16 +1944,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1938 | srvTcp->tcpStatus = CifsNew; | 1944 | srvTcp->tcpStatus = CifsNew; |
| 1939 | init_MUTEX(&srvTcp->tcpSem); | 1945 | init_MUTEX(&srvTcp->tcpSem); |
| 1940 | srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); | 1946 | srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); |
| 1941 | if ( IS_ERR(srvTcp->tsk) ) { | 1947 | if (IS_ERR(srvTcp->tsk)) { |
| 1942 | rc = PTR_ERR(srvTcp->tsk); | 1948 | rc = PTR_ERR(srvTcp->tsk); |
| 1943 | cERROR(1, ("error %d create cifsd thread", rc)); | 1949 | cERROR(1, ("error %d create cifsd thread", rc)); |
| 1944 | srvTcp->tsk = NULL; | 1950 | srvTcp->tsk = NULL; |
| 1945 | sock_release(csocket); | 1951 | sock_release(csocket); |
| 1946 | kfree(volume_info.UNC); | 1952 | kfree(srvTcp->hostname); |
| 1947 | kfree(volume_info.password); | 1953 | goto out; |
| 1948 | kfree(volume_info.prepath); | ||
| 1949 | FreeXid(xid); | ||
| 1950 | return rc; | ||
| 1951 | } | 1954 | } |
| 1952 | wait_for_completion(&cifsd_complete); | 1955 | wait_for_completion(&cifsd_complete); |
| 1953 | rc = 0; | 1956 | rc = 0; |
| @@ -1962,8 +1965,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1962 | if (existingCifsSes) { | 1965 | if (existingCifsSes) { |
| 1963 | pSesInfo = existingCifsSes; | 1966 | pSesInfo = existingCifsSes; |
| 1964 | cFYI(1, ("Existing smb sess found")); | 1967 | cFYI(1, ("Existing smb sess found")); |
| 1965 | kfree(volume_info.password); | ||
| 1966 | /* volume_info.UNC freed at end of function */ | ||
| 1967 | } else if (!rc) { | 1968 | } else if (!rc) { |
| 1968 | cFYI(1, ("Existing smb sess not found")); | 1969 | cFYI(1, ("Existing smb sess not found")); |
| 1969 | pSesInfo = sesInfoAlloc(); | 1970 | pSesInfo = sesInfoAlloc(); |
| @@ -1977,8 +1978,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1977 | 1978 | ||
| 1978 | if (!rc) { | 1979 | if (!rc) { |
| 1979 | /* volume_info.password freed at unmount */ | 1980 | /* volume_info.password freed at unmount */ |
| 1980 | if (volume_info.password) | 1981 | if (volume_info.password) { |
| 1981 | pSesInfo->password = volume_info.password; | 1982 | pSesInfo->password = volume_info.password; |
| 1983 | /* set to NULL to prevent freeing on exit */ | ||
| 1984 | volume_info.password = NULL; | ||
| 1985 | } | ||
| 1982 | if (volume_info.username) | 1986 | if (volume_info.username) |
| 1983 | strncpy(pSesInfo->userName, | 1987 | strncpy(pSesInfo->userName, |
| 1984 | volume_info.username, | 1988 | volume_info.username, |
| @@ -2000,8 +2004,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2000 | up(&pSesInfo->sesSem); | 2004 | up(&pSesInfo->sesSem); |
| 2001 | if (!rc) | 2005 | if (!rc) |
| 2002 | atomic_inc(&srvTcp->socketUseCount); | 2006 | atomic_inc(&srvTcp->socketUseCount); |
| 2003 | } else | 2007 | } |
| 2004 | kfree(volume_info.password); | ||
| 2005 | } | 2008 | } |
| 2006 | 2009 | ||
| 2007 | /* search for existing tcon to this server share */ | 2010 | /* search for existing tcon to this server share */ |
| @@ -2106,9 +2109,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2106 | "", cifs_sb->local_nls, | 2109 | "", cifs_sb->local_nls, |
| 2107 | cifs_sb->mnt_cifs_flags & | 2110 | cifs_sb->mnt_cifs_flags & |
| 2108 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 2111 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 2109 | kfree(volume_info.UNC); | 2112 | rc = -ENODEV; |
| 2110 | FreeXid(xid); | 2113 | goto out; |
| 2111 | return -ENODEV; | ||
| 2112 | } else { | 2114 | } else { |
| 2113 | /* BB Do we need to wrap sesSem around | 2115 | /* BB Do we need to wrap sesSem around |
| 2114 | * this TCon call and Unix SetFS as | 2116 | * this TCon call and Unix SetFS as |
| @@ -2231,6 +2233,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2231 | (in which case it is not needed anymore) but when new sesion is created | 2233 | (in which case it is not needed anymore) but when new sesion is created |
| 2232 | the password ptr is put in the new session structure (in which case the | 2234 | the password ptr is put in the new session structure (in which case the |
| 2233 | password will be freed at unmount time) */ | 2235 | password will be freed at unmount time) */ |
| 2236 | out: | ||
| 2237 | /* zero out password before freeing */ | ||
| 2238 | if (volume_info.password != NULL) { | ||
| 2239 | memset(volume_info.password, 0, strlen(volume_info.password)); | ||
| 2240 | kfree(volume_info.password); | ||
| 2241 | } | ||
| 2234 | kfree(volume_info.UNC); | 2242 | kfree(volume_info.UNC); |
| 2235 | kfree(volume_info.prepath); | 2243 | kfree(volume_info.prepath); |
| 2236 | FreeXid(xid); | 2244 | FreeXid(xid); |
| @@ -2374,7 +2382,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2374 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | 2382 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); |
| 2375 | 2383 | ||
| 2376 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | 2384 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, |
| 2377 | &bytes_returned, 1); | 2385 | &bytes_returned, CIFS_LONG_OP); |
| 2378 | if (rc) { | 2386 | if (rc) { |
| 2379 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | 2387 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ |
| 2380 | } else if ((smb_buffer_response->WordCount == 3) | 2388 | } else if ((smb_buffer_response->WordCount == 3) |
| @@ -2678,7 +2686,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2678 | pSMB->req.ByteCount = cpu_to_le16(count); | 2686 | pSMB->req.ByteCount = cpu_to_le16(count); |
| 2679 | 2687 | ||
| 2680 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | 2688 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, |
| 2681 | &bytes_returned, 1); | 2689 | &bytes_returned, CIFS_LONG_OP); |
| 2682 | 2690 | ||
| 2683 | if (smb_buffer_response->Status.CifsError == | 2691 | if (smb_buffer_response->Status.CifsError == |
| 2684 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | 2692 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) |
| @@ -3105,7 +3113,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3105 | pSMB->req.ByteCount = cpu_to_le16(count); | 3113 | pSMB->req.ByteCount = cpu_to_le16(count); |
| 3106 | 3114 | ||
| 3107 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | 3115 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, |
| 3108 | &bytes_returned, 1); | 3116 | &bytes_returned, CIFS_LONG_OP); |
| 3109 | if (rc) { | 3117 | if (rc) { |
| 3110 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ | 3118 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ |
| 3111 | } else if ((smb_buffer_response->WordCount == 3) || | 3119 | } else if ((smb_buffer_response->WordCount == 3) || |
| @@ -3381,7 +3389,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3381 | pSMB->hdr.smb_buf_length += count; | 3389 | pSMB->hdr.smb_buf_length += count; |
| 3382 | pSMB->ByteCount = cpu_to_le16(count); | 3390 | pSMB->ByteCount = cpu_to_le16(count); |
| 3383 | 3391 | ||
| 3384 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); | 3392 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
| 3393 | CIFS_STD_OP); | ||
| 3385 | 3394 | ||
| 3386 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ | 3395 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ |
| 3387 | /* above now done in SendReceive */ | 3396 | /* above now done in SendReceive */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 68ad4ca0cfa3..dd26e2759b17 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -130,7 +130,9 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | |||
| 130 | if (file->f_path.dentry->d_inode->i_mapping) { | 130 | if (file->f_path.dentry->d_inode->i_mapping) { |
| 131 | /* BB no need to lock inode until after invalidate | 131 | /* BB no need to lock inode until after invalidate |
| 132 | since namei code should already have it locked? */ | 132 | since namei code should already have it locked? */ |
| 133 | filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); | 133 | rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); |
| 134 | if (rc != 0) | ||
| 135 | CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; | ||
| 134 | } | 136 | } |
| 135 | cFYI(1, ("invalidating remote inode since open detected it " | 137 | cFYI(1, ("invalidating remote inode since open detected it " |
| 136 | "changed")); | 138 | "changed")); |
| @@ -425,7 +427,9 @@ reopen_error_exit: | |||
| 425 | pCifsInode = CIFS_I(inode); | 427 | pCifsInode = CIFS_I(inode); |
| 426 | if (pCifsInode) { | 428 | if (pCifsInode) { |
| 427 | if (can_flush) { | 429 | if (can_flush) { |
| 428 | filemap_write_and_wait(inode->i_mapping); | 430 | rc = filemap_write_and_wait(inode->i_mapping); |
| 431 | if (rc != 0) | ||
| 432 | CIFS_I(inode)->write_behind_rc = rc; | ||
| 429 | /* temporarily disable caching while we | 433 | /* temporarily disable caching while we |
| 430 | go to server to get inode info */ | 434 | go to server to get inode info */ |
| 431 | pCifsInode->clientCanCacheAll = FALSE; | 435 | pCifsInode->clientCanCacheAll = FALSE; |
| @@ -835,9 +839,9 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 835 | xid = GetXid(); | 839 | xid = GetXid(); |
| 836 | 840 | ||
| 837 | if (*poffset > file->f_path.dentry->d_inode->i_size) | 841 | if (*poffset > file->f_path.dentry->d_inode->i_size) |
| 838 | long_op = 2; /* writes past end of file can take a long time */ | 842 | long_op = CIFS_VLONG_OP; /* writes past EOF take long time */ |
| 839 | else | 843 | else |
| 840 | long_op = 1; | 844 | long_op = CIFS_LONG_OP; |
| 841 | 845 | ||
| 842 | for (total_written = 0; write_size > total_written; | 846 | for (total_written = 0; write_size > total_written; |
| 843 | total_written += bytes_written) { | 847 | total_written += bytes_written) { |
| @@ -884,7 +888,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 884 | } | 888 | } |
| 885 | } else | 889 | } else |
| 886 | *poffset += bytes_written; | 890 | *poffset += bytes_written; |
| 887 | long_op = FALSE; /* subsequent writes fast - | 891 | long_op = CIFS_STD_OP; /* subsequent writes fast - |
| 888 | 15 seconds is plenty */ | 892 | 15 seconds is plenty */ |
| 889 | } | 893 | } |
| 890 | 894 | ||
| @@ -934,9 +938,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 934 | xid = GetXid(); | 938 | xid = GetXid(); |
| 935 | 939 | ||
| 936 | if (*poffset > file->f_path.dentry->d_inode->i_size) | 940 | if (*poffset > file->f_path.dentry->d_inode->i_size) |
| 937 | long_op = 2; /* writes past end of file can take a long time */ | 941 | long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */ |
| 938 | else | 942 | else |
| 939 | long_op = 1; | 943 | long_op = CIFS_LONG_OP; |
| 940 | 944 | ||
| 941 | for (total_written = 0; write_size > total_written; | 945 | for (total_written = 0; write_size > total_written; |
| 942 | total_written += bytes_written) { | 946 | total_written += bytes_written) { |
| @@ -1002,7 +1006,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 1002 | } | 1006 | } |
| 1003 | } else | 1007 | } else |
| 1004 | *poffset += bytes_written; | 1008 | *poffset += bytes_written; |
| 1005 | long_op = FALSE; /* subsequent writes fast - | 1009 | long_op = CIFS_STD_OP; /* subsequent writes fast - |
| 1006 | 15 seconds is plenty */ | 1010 | 15 seconds is plenty */ |
| 1007 | } | 1011 | } |
| 1008 | 1012 | ||
| @@ -1087,11 +1091,11 @@ refind_writable: | |||
| 1087 | read_unlock(&GlobalSMBSeslock); | 1091 | read_unlock(&GlobalSMBSeslock); |
| 1088 | return open_file; | 1092 | return open_file; |
| 1089 | } | 1093 | } |
| 1090 | 1094 | ||
| 1091 | read_unlock(&GlobalSMBSeslock); | 1095 | read_unlock(&GlobalSMBSeslock); |
| 1092 | /* Had to unlock since following call can block */ | 1096 | /* Had to unlock since following call can block */ |
| 1093 | rc = cifs_reopen_file(open_file->pfile, FALSE); | 1097 | rc = cifs_reopen_file(open_file->pfile, FALSE); |
| 1094 | if (!rc) { | 1098 | if (!rc) { |
| 1095 | if (!open_file->closePend) | 1099 | if (!open_file->closePend) |
| 1096 | return open_file; | 1100 | return open_file; |
| 1097 | else { /* start over in case this was deleted */ | 1101 | else { /* start over in case this was deleted */ |
| @@ -1114,7 +1118,7 @@ refind_writable: | |||
| 1114 | /* can not use this handle, no write | 1118 | /* can not use this handle, no write |
| 1115 | pending on this one after all */ | 1119 | pending on this one after all */ |
| 1116 | atomic_dec(&open_file->wrtPending); | 1120 | atomic_dec(&open_file->wrtPending); |
| 1117 | 1121 | ||
| 1118 | if (open_file->closePend) /* list could have changed */ | 1122 | if (open_file->closePend) /* list could have changed */ |
| 1119 | goto refind_writable; | 1123 | goto refind_writable; |
| 1120 | /* else we simply continue to the next entry. Thus | 1124 | /* else we simply continue to the next entry. Thus |
| @@ -1360,14 +1364,17 @@ retry: | |||
| 1360 | open_file->netfid, | 1364 | open_file->netfid, |
| 1361 | bytes_to_write, offset, | 1365 | bytes_to_write, offset, |
| 1362 | &bytes_written, iov, n_iov, | 1366 | &bytes_written, iov, n_iov, |
| 1363 | 1); | 1367 | CIFS_LONG_OP); |
| 1364 | atomic_dec(&open_file->wrtPending); | 1368 | atomic_dec(&open_file->wrtPending); |
| 1365 | if (rc || bytes_written < bytes_to_write) { | 1369 | if (rc || bytes_written < bytes_to_write) { |
| 1366 | cERROR(1, ("Write2 ret %d, wrote %d", | 1370 | cERROR(1, ("Write2 ret %d, wrote %d", |
| 1367 | rc, bytes_written)); | 1371 | rc, bytes_written)); |
| 1368 | /* BB what if continued retry is | 1372 | /* BB what if continued retry is |
| 1369 | requested via mount flags? */ | 1373 | requested via mount flags? */ |
| 1370 | set_bit(AS_EIO, &mapping->flags); | 1374 | if (rc == -ENOSPC) |
| 1375 | set_bit(AS_ENOSPC, &mapping->flags); | ||
| 1376 | else | ||
| 1377 | set_bit(AS_EIO, &mapping->flags); | ||
| 1371 | } else { | 1378 | } else { |
| 1372 | cifs_stats_bytes_written(cifs_sb->tcon, | 1379 | cifs_stats_bytes_written(cifs_sb->tcon, |
| 1373 | bytes_written); | 1380 | bytes_written); |
| @@ -1499,9 +1506,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
| 1499 | cFYI(1, ("Sync file - name: %s datasync: 0x%x", | 1506 | cFYI(1, ("Sync file - name: %s datasync: 0x%x", |
| 1500 | dentry->d_name.name, datasync)); | 1507 | dentry->d_name.name, datasync)); |
| 1501 | 1508 | ||
| 1502 | rc = filemap_fdatawrite(inode->i_mapping); | 1509 | rc = filemap_write_and_wait(inode->i_mapping); |
| 1503 | if (rc == 0) | 1510 | if (rc == 0) { |
| 1511 | rc = CIFS_I(inode)->write_behind_rc; | ||
| 1504 | CIFS_I(inode)->write_behind_rc = 0; | 1512 | CIFS_I(inode)->write_behind_rc = 0; |
| 1513 | } | ||
| 1505 | FreeXid(xid); | 1514 | FreeXid(xid); |
| 1506 | return rc; | 1515 | return rc; |
| 1507 | } | 1516 | } |
| @@ -1553,8 +1562,11 @@ int cifs_flush(struct file *file, fl_owner_t id) | |||
| 1553 | filemapfdatawrite appears easier for the time being */ | 1562 | filemapfdatawrite appears easier for the time being */ |
| 1554 | 1563 | ||
| 1555 | rc = filemap_fdatawrite(inode->i_mapping); | 1564 | rc = filemap_fdatawrite(inode->i_mapping); |
| 1556 | if (!rc) /* reset wb rc if we were able to write out dirty pages */ | 1565 | /* reset wb rc if we were able to write out dirty pages */ |
| 1566 | if (!rc) { | ||
| 1567 | rc = CIFS_I(inode)->write_behind_rc; | ||
| 1557 | CIFS_I(inode)->write_behind_rc = 0; | 1568 | CIFS_I(inode)->write_behind_rc = 0; |
| 1569 | } | ||
| 1558 | 1570 | ||
| 1559 | cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc)); | 1571 | cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc)); |
| 1560 | 1572 | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7d907e84e032..e915eb1d2e66 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1233,7 +1233,7 @@ cifs_rename_exit: | |||
| 1233 | int cifs_revalidate(struct dentry *direntry) | 1233 | int cifs_revalidate(struct dentry *direntry) |
| 1234 | { | 1234 | { |
| 1235 | int xid; | 1235 | int xid; |
| 1236 | int rc = 0; | 1236 | int rc = 0, wbrc = 0; |
| 1237 | char *full_path; | 1237 | char *full_path; |
| 1238 | struct cifs_sb_info *cifs_sb; | 1238 | struct cifs_sb_info *cifs_sb; |
| 1239 | struct cifsInodeInfo *cifsInode; | 1239 | struct cifsInodeInfo *cifsInode; |
| @@ -1333,7 +1333,9 @@ int cifs_revalidate(struct dentry *direntry) | |||
| 1333 | if (direntry->d_inode->i_mapping) { | 1333 | if (direntry->d_inode->i_mapping) { |
| 1334 | /* do we need to lock inode until after invalidate completes | 1334 | /* do we need to lock inode until after invalidate completes |
| 1335 | below? */ | 1335 | below? */ |
| 1336 | filemap_fdatawrite(direntry->d_inode->i_mapping); | 1336 | wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping); |
| 1337 | if (wbrc) | ||
| 1338 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | ||
| 1337 | } | 1339 | } |
| 1338 | if (invalidate_inode) { | 1340 | if (invalidate_inode) { |
| 1339 | /* shrink_dcache not necessary now that cifs dentry ops | 1341 | /* shrink_dcache not necessary now that cifs dentry ops |
| @@ -1342,7 +1344,9 @@ int cifs_revalidate(struct dentry *direntry) | |||
| 1342 | shrink_dcache_parent(direntry); */ | 1344 | shrink_dcache_parent(direntry); */ |
| 1343 | if (S_ISREG(direntry->d_inode->i_mode)) { | 1345 | if (S_ISREG(direntry->d_inode->i_mode)) { |
| 1344 | if (direntry->d_inode->i_mapping) | 1346 | if (direntry->d_inode->i_mapping) |
| 1345 | filemap_fdatawait(direntry->d_inode->i_mapping); | 1347 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); |
| 1348 | if (wbrc) | ||
| 1349 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | ||
| 1346 | /* may eventually have to do this for open files too */ | 1350 | /* may eventually have to do this for open files too */ |
| 1347 | if (list_empty(&(cifsInode->openFileList))) { | 1351 | if (list_empty(&(cifsInode->openFileList))) { |
| 1348 | /* changed on server - flush read ahead pages */ | 1352 | /* changed on server - flush read ahead pages */ |
| @@ -1485,10 +1489,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1485 | 1489 | ||
| 1486 | /* BB check if we need to refresh inode from server now ? BB */ | 1490 | /* BB check if we need to refresh inode from server now ? BB */ |
| 1487 | 1491 | ||
| 1488 | /* need to flush data before changing file size on server */ | ||
| 1489 | filemap_write_and_wait(direntry->d_inode->i_mapping); | ||
| 1490 | |||
| 1491 | if (attrs->ia_valid & ATTR_SIZE) { | 1492 | if (attrs->ia_valid & ATTR_SIZE) { |
| 1493 | /* | ||
| 1494 | Flush data before changing file size on server. If the | ||
| 1495 | flush returns error, store it to report later and continue. | ||
| 1496 | BB: This should be smarter. Why bother flushing pages that | ||
| 1497 | will be truncated anyway? Also, should we error out here if | ||
| 1498 | the flush returns error? | ||
| 1499 | */ | ||
| 1500 | rc = filemap_write_and_wait(direntry->d_inode->i_mapping); | ||
| 1501 | if (rc != 0) { | ||
| 1502 | CIFS_I(direntry->d_inode)->write_behind_rc = rc; | ||
| 1503 | rc = 0; | ||
| 1504 | } | ||
| 1505 | |||
| 1492 | /* To avoid spurious oplock breaks from server, in the case of | 1506 | /* To avoid spurious oplock breaks from server, in the case of |
| 1493 | inodes that we already have open, avoid doing path based | 1507 | inodes that we already have open, avoid doing path based |
| 1494 | setting of file size if we can do it by handle. | 1508 | setting of file size if we can do it by handle. |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 899dc6078d9a..d0cb469daab7 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "ntlmssp.h" | 29 | #include "ntlmssp.h" |
| 30 | #include "nterr.h" | 30 | #include "nterr.h" |
| 31 | #include <linux/utsname.h> | 31 | #include <linux/utsname.h> |
| 32 | #include "cifs_spnego.h" | ||
| 32 | 33 | ||
| 33 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 34 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| 34 | unsigned char *p24); | 35 | unsigned char *p24); |
| @@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 340 | SESSION_SETUP_ANDX *pSMB; | 341 | SESSION_SETUP_ANDX *pSMB; |
| 341 | __u32 capabilities; | 342 | __u32 capabilities; |
| 342 | int count; | 343 | int count; |
| 343 | int resp_buf_type = 0; | 344 | int resp_buf_type; |
| 344 | struct kvec iov[2]; | 345 | struct kvec iov[3]; |
| 345 | enum securityEnum type; | 346 | enum securityEnum type; |
| 346 | __u16 action; | 347 | __u16 action; |
| 347 | int bytes_remaining; | 348 | int bytes_remaining; |
| 349 | struct key *spnego_key = NULL; | ||
| 348 | 350 | ||
| 349 | if (ses == NULL) | 351 | if (ses == NULL) |
| 350 | return -EINVAL; | 352 | return -EINVAL; |
| @@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 377 | 379 | ||
| 378 | capabilities = cifs_ssetup_hdr(ses, pSMB); | 380 | capabilities = cifs_ssetup_hdr(ses, pSMB); |
| 379 | 381 | ||
| 380 | /* we will send the SMB in two pieces, | 382 | /* we will send the SMB in three pieces: |
| 381 | a fixed length beginning part, and a | 383 | a fixed length beginning part, an optional |
| 382 | second part which will include the strings | 384 | SPNEGO blob (which can be zero length), and a |
| 383 | and rest of bcc area, in order to avoid having | 385 | last part which will include the strings |
| 384 | to do a large buffer 17K allocation */ | 386 | and rest of bcc area. This allows us to avoid |
| 387 | a large buffer 17K allocation */ | ||
| 385 | iov[0].iov_base = (char *)pSMB; | 388 | iov[0].iov_base = (char *)pSMB; |
| 386 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | 389 | iov[0].iov_len = smb_buf->smb_buf_length + 4; |
| 387 | 390 | ||
| 391 | /* setting this here allows the code at the end of the function | ||
| 392 | to free the request buffer if there's an error */ | ||
| 393 | resp_buf_type = CIFS_SMALL_BUFFER; | ||
| 394 | |||
| 388 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | 395 | /* 2000 big enough to fit max user, domain, NOS name etc. */ |
| 389 | str_area = kmalloc(2000, GFP_KERNEL); | 396 | str_area = kmalloc(2000, GFP_KERNEL); |
| 390 | if (str_area == NULL) { | 397 | if (str_area == NULL) { |
| 391 | cifs_small_buf_release(smb_buf); | 398 | rc = -ENOMEM; |
| 392 | return -ENOMEM; | 399 | goto ssetup_exit; |
| 393 | } | 400 | } |
| 394 | bcc_ptr = str_area; | 401 | bcc_ptr = str_area; |
| 395 | 402 | ||
| 396 | ses->flags &= ~CIFS_SES_LANMAN; | 403 | ses->flags &= ~CIFS_SES_LANMAN; |
| 397 | 404 | ||
| 405 | iov[1].iov_base = NULL; | ||
| 406 | iov[1].iov_len = 0; | ||
| 407 | |||
| 398 | if (type == LANMAN) { | 408 | if (type == LANMAN) { |
| 399 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 409 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 400 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; | 410 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; |
| @@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 463 | struct ntlmv2_resp */ | 473 | struct ntlmv2_resp */ |
| 464 | 474 | ||
| 465 | if (v2_sess_key == NULL) { | 475 | if (v2_sess_key == NULL) { |
| 466 | cifs_small_buf_release(smb_buf); | 476 | rc = -ENOMEM; |
| 467 | return -ENOMEM; | 477 | goto ssetup_exit; |
| 468 | } | 478 | } |
| 469 | 479 | ||
| 470 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 480 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
| @@ -499,22 +509,67 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 499 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | 509 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); |
| 500 | } else | 510 | } else |
| 501 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 511 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
| 502 | } else /* NTLMSSP or SPNEGO */ { | 512 | } else if (type == Kerberos) { |
| 513 | #ifdef CONFIG_CIFS_UPCALL | ||
| 514 | struct cifs_spnego_msg *msg; | ||
| 515 | spnego_key = cifs_get_spnego_key(ses); | ||
| 516 | if (IS_ERR(spnego_key)) { | ||
| 517 | rc = PTR_ERR(spnego_key); | ||
| 518 | spnego_key = NULL; | ||
| 519 | goto ssetup_exit; | ||
| 520 | } | ||
| 521 | |||
| 522 | msg = spnego_key->payload.data; | ||
| 523 | /* bail out if key is too long */ | ||
| 524 | if (msg->sesskey_len > | ||
| 525 | sizeof(ses->server->mac_signing_key.data.krb5)) { | ||
| 526 | cERROR(1, ("Kerberos signing key too long (%u bytes)", | ||
| 527 | msg->sesskey_len)); | ||
| 528 | rc = -EOVERFLOW; | ||
| 529 | goto ssetup_exit; | ||
| 530 | } | ||
| 531 | ses->server->mac_signing_key.len = msg->sesskey_len; | ||
| 532 | memcpy(ses->server->mac_signing_key.data.krb5, msg->data, | ||
| 533 | msg->sesskey_len); | ||
| 503 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 534 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 504 | capabilities |= CAP_EXTENDED_SECURITY; | 535 | capabilities |= CAP_EXTENDED_SECURITY; |
| 505 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | 536 | pSMB->req.Capabilities = cpu_to_le32(capabilities); |
| 506 | /* BB set password lengths */ | 537 | iov[1].iov_base = msg->data + msg->sesskey_len; |
| 538 | iov[1].iov_len = msg->secblob_len; | ||
| 539 | pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len); | ||
| 540 | |||
| 541 | if (ses->capabilities & CAP_UNICODE) { | ||
| 542 | /* unicode strings must be word aligned */ | ||
| 543 | if (iov[0].iov_len % 2) { | ||
| 544 | *bcc_ptr = 0; | ||
| 545 | bcc_ptr++; | ||
| 546 | } | ||
| 547 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
| 548 | unicode_domain_string(&bcc_ptr, ses, nls_cp); | ||
| 549 | } else | ||
| 550 | /* BB: is this right? */ | ||
| 551 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 552 | #else /* ! CONFIG_CIFS_UPCALL */ | ||
| 553 | cERROR(1, ("Kerberos negotiated but upcall support disabled!")); | ||
| 554 | rc = -ENOSYS; | ||
| 555 | goto ssetup_exit; | ||
| 556 | #endif /* CONFIG_CIFS_UPCALL */ | ||
| 557 | } else { | ||
| 558 | cERROR(1, ("secType %d not supported!", type)); | ||
| 559 | rc = -ENOSYS; | ||
| 560 | goto ssetup_exit; | ||
| 507 | } | 561 | } |
| 508 | 562 | ||
| 509 | count = (long) bcc_ptr - (long) str_area; | 563 | iov[2].iov_base = str_area; |
| 564 | iov[2].iov_len = (long) bcc_ptr - (long) str_area; | ||
| 565 | |||
| 566 | count = iov[1].iov_len + iov[2].iov_len; | ||
| 510 | smb_buf->smb_buf_length += count; | 567 | smb_buf->smb_buf_length += count; |
| 511 | 568 | ||
| 512 | BCC_LE(smb_buf) = cpu_to_le16(count); | 569 | BCC_LE(smb_buf) = cpu_to_le16(count); |
| 513 | 570 | ||
| 514 | iov[1].iov_base = str_area; | 571 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, |
| 515 | iov[1].iov_len = count; | 572 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); |
| 516 | rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, | ||
| 517 | 0 /* not long op */, 1 /* log NT STATUS if any */ ); | ||
| 518 | /* SMB request buf freed in SendReceive2 */ | 573 | /* SMB request buf freed in SendReceive2 */ |
| 519 | 574 | ||
| 520 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); | 575 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); |
| @@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 560 | ses, nls_cp); | 615 | ses, nls_cp); |
| 561 | 616 | ||
| 562 | ssetup_exit: | 617 | ssetup_exit: |
| 618 | if (spnego_key) | ||
| 619 | key_put(spnego_key); | ||
| 563 | kfree(str_area); | 620 | kfree(str_area); |
| 564 | if (resp_buf_type == CIFS_SMALL_BUFFER) { | 621 | if (resp_buf_type == CIFS_SMALL_BUFFER) { |
| 565 | cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); | 622 | cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 7ed32b3cb781..50b623ad9320 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -308,7 +308,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
| 308 | 308 | ||
| 309 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | 309 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) |
| 310 | { | 310 | { |
| 311 | if (long_op == -1) { | 311 | if (long_op == CIFS_ASYNC_OP) { |
| 312 | /* oplock breaks must not be held up */ | 312 | /* oplock breaks must not be held up */ |
| 313 | atomic_inc(&ses->server->inFlight); | 313 | atomic_inc(&ses->server->inFlight); |
| 314 | } else { | 314 | } else { |
| @@ -337,7 +337,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
| 337 | as they are allowed to block on server */ | 337 | as they are allowed to block on server */ |
| 338 | 338 | ||
| 339 | /* update # of requests on the wire to server */ | 339 | /* update # of requests on the wire to server */ |
| 340 | if (long_op < 3) | 340 | if (long_op != CIFS_BLOCKING_OP) |
| 341 | atomic_inc(&ses->server->inFlight); | 341 | atomic_inc(&ses->server->inFlight); |
| 342 | spin_unlock(&GlobalMid_Lock); | 342 | spin_unlock(&GlobalMid_Lock); |
| 343 | break; | 343 | break; |
| @@ -415,17 +415,48 @@ static int wait_for_response(struct cifsSesInfo *ses, | |||
| 415 | } | 415 | } |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | |||
| 419 | /* | ||
| 420 | * | ||
| 421 | * Send an SMB Request. No response info (other than return code) | ||
| 422 | * needs to be parsed. | ||
| 423 | * | ||
| 424 | * flags indicate the type of request buffer and how long to wait | ||
| 425 | * and whether to log NT STATUS code (error) before mapping it to POSIX error | ||
| 426 | * | ||
| 427 | */ | ||
| 428 | int | ||
| 429 | SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | ||
| 430 | struct smb_hdr *in_buf, int flags) | ||
| 431 | { | ||
| 432 | int rc; | ||
| 433 | struct kvec iov[1]; | ||
| 434 | int resp_buf_type; | ||
| 435 | |||
| 436 | iov[0].iov_base = (char *)in_buf; | ||
| 437 | iov[0].iov_len = in_buf->smb_buf_length + 4; | ||
| 438 | flags |= CIFS_NO_RESP; | ||
| 439 | rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); | ||
| 440 | #ifdef CONFIG_CIFS_DEBUG2 | ||
| 441 | cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc)); | ||
| 442 | #endif | ||
| 443 | return rc; | ||
| 444 | } | ||
| 445 | |||
| 418 | int | 446 | int |
| 419 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 447 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
| 420 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, | 448 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
| 421 | const int long_op, const int logError) | 449 | const int flags) |
| 422 | { | 450 | { |
| 423 | int rc = 0; | 451 | int rc = 0; |
| 452 | int long_op; | ||
| 424 | unsigned int receive_len; | 453 | unsigned int receive_len; |
| 425 | unsigned long timeout; | 454 | unsigned long timeout; |
| 426 | struct mid_q_entry *midQ; | 455 | struct mid_q_entry *midQ; |
| 427 | struct smb_hdr *in_buf = iov[0].iov_base; | 456 | struct smb_hdr *in_buf = iov[0].iov_base; |
| 428 | 457 | ||
| 458 | long_op = flags & CIFS_TIMEOUT_MASK; | ||
| 459 | |||
| 429 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ | 460 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ |
| 430 | 461 | ||
| 431 | if ((ses == NULL) || (ses->server == NULL)) { | 462 | if ((ses == NULL) || (ses->server == NULL)) { |
| @@ -483,15 +514,22 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 483 | if (rc < 0) | 514 | if (rc < 0) |
| 484 | goto out; | 515 | goto out; |
| 485 | 516 | ||
| 486 | if (long_op == -1) | 517 | if (long_op == CIFS_STD_OP) |
| 487 | goto out; | 518 | timeout = 15 * HZ; |
| 488 | else if (long_op == 2) /* writes past end of file can take loong time */ | 519 | else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ |
| 489 | timeout = 180 * HZ; | 520 | timeout = 180 * HZ; |
| 490 | else if (long_op == 1) | 521 | else if (long_op == CIFS_LONG_OP) |
| 491 | timeout = 45 * HZ; /* should be greater than | 522 | timeout = 45 * HZ; /* should be greater than |
| 492 | servers oplock break timeout (about 43 seconds) */ | 523 | servers oplock break timeout (about 43 seconds) */ |
| 493 | else | 524 | else if (long_op == CIFS_ASYNC_OP) |
| 494 | timeout = 15 * HZ; | 525 | goto out; |
| 526 | else if (long_op == CIFS_BLOCKING_OP) | ||
| 527 | timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ | ||
| 528 | else { | ||
| 529 | cERROR(1, ("unknown timeout flag %d", long_op)); | ||
| 530 | rc = -EIO; | ||
| 531 | goto out; | ||
| 532 | } | ||
| 495 | 533 | ||
| 496 | /* wait for 15 seconds or until woken up due to response arriving or | 534 | /* wait for 15 seconds or until woken up due to response arriving or |
| 497 | due to last connection to this server being unmounted */ | 535 | due to last connection to this server being unmounted */ |
| @@ -566,7 +604,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 566 | } | 604 | } |
| 567 | 605 | ||
| 568 | /* BB special case reconnect tid and uid here? */ | 606 | /* BB special case reconnect tid and uid here? */ |
| 569 | rc = map_smb_to_linux_error(midQ->resp_buf, logError); | 607 | rc = map_smb_to_linux_error(midQ->resp_buf, |
| 608 | flags & CIFS_LOG_ERROR); | ||
| 570 | 609 | ||
| 571 | /* convert ByteCount if necessary */ | 610 | /* convert ByteCount if necessary */ |
| 572 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 611 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
| @@ -574,8 +613,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 574 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) | 613 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) |
| 575 | BCC(midQ->resp_buf) = | 614 | BCC(midQ->resp_buf) = |
| 576 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | 615 | le16_to_cpu(BCC_LE(midQ->resp_buf)); |
| 577 | midQ->resp_buf = NULL; /* mark it so will not be freed | 616 | if ((flags & CIFS_NO_RESP) == 0) |
| 578 | by DeleteMidQEntry */ | 617 | midQ->resp_buf = NULL; /* mark it so buf will |
| 618 | not be freed by | ||
| 619 | DeleteMidQEntry */ | ||
| 579 | } else { | 620 | } else { |
| 580 | rc = -EIO; | 621 | rc = -EIO; |
| 581 | cFYI(1, ("Bad MID state?")); | 622 | cFYI(1, ("Bad MID state?")); |
| @@ -663,17 +704,25 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 663 | if (rc < 0) | 704 | if (rc < 0) |
| 664 | goto out; | 705 | goto out; |
| 665 | 706 | ||
| 666 | if (long_op == -1) | 707 | if (long_op == CIFS_STD_OP) |
| 708 | timeout = 15 * HZ; | ||
| 709 | /* wait for 15 seconds or until woken up due to response arriving or | ||
| 710 | due to last connection to this server being unmounted */ | ||
| 711 | else if (long_op == CIFS_ASYNC_OP) | ||
| 667 | goto out; | 712 | goto out; |
| 668 | else if (long_op == 2) /* writes past end of file can take loong time */ | 713 | else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ |
| 669 | timeout = 180 * HZ; | 714 | timeout = 180 * HZ; |
| 670 | else if (long_op == 1) | 715 | else if (long_op == CIFS_LONG_OP) |
| 671 | timeout = 45 * HZ; /* should be greater than | 716 | timeout = 45 * HZ; /* should be greater than |
| 672 | servers oplock break timeout (about 43 seconds) */ | 717 | servers oplock break timeout (about 43 seconds) */ |
| 673 | else | 718 | else if (long_op == CIFS_BLOCKING_OP) |
| 674 | timeout = 15 * HZ; | 719 | timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ |
| 675 | /* wait for 15 seconds or until woken up due to response arriving or | 720 | else { |
| 676 | due to last connection to this server being unmounted */ | 721 | cERROR(1, ("unknown timeout flag %d", long_op)); |
| 722 | rc = -EIO; | ||
| 723 | goto out; | ||
| 724 | } | ||
| 725 | |||
| 677 | if (signal_pending(current)) { | 726 | if (signal_pending(current)) { |
| 678 | /* if signal pending do not hold up user for full smb timeout | 727 | /* if signal pending do not hold up user for full smb timeout |
| 679 | but we still give response a chance to complete */ | 728 | but we still give response a chance to complete */ |
| @@ -812,7 +861,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 812 | pSMB->hdr.Mid = GetNextMid(ses->server); | 861 | pSMB->hdr.Mid = GetNextMid(ses->server); |
| 813 | 862 | ||
| 814 | return SendReceive(xid, ses, in_buf, out_buf, | 863 | return SendReceive(xid, ses, in_buf, out_buf, |
| 815 | &bytes_returned, 0); | 864 | &bytes_returned, CIFS_STD_OP); |
| 816 | } | 865 | } |
| 817 | 866 | ||
| 818 | int | 867 | int |
| @@ -844,7 +893,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 844 | to the same server. We may make this configurable later or | 893 | to the same server. We may make this configurable later or |
| 845 | use ses->maxReq */ | 894 | use ses->maxReq */ |
| 846 | 895 | ||
| 847 | rc = wait_for_free_request(ses, 3); | 896 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); |
| 848 | if (rc) | 897 | if (rc) |
| 849 | return rc; | 898 | return rc; |
| 850 | 899 | ||
