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
This commit is contained in:
commit
bb40784f4a
15 changed files with 368 additions and 229 deletions
|
@ -1,6 +1,9 @@
|
|||
Version 1.52
|
||||
------------
|
||||
Fix oops on second mount to server when null auth is used.
|
||||
Enable experimental Kerberos support. Return writebehind errors on flush
|
||||
and sync so that events like out of disk space get reported properly on
|
||||
cached files.
|
||||
|
||||
Version 1.51
|
||||
------------
|
||||
|
|
|
@ -225,12 +225,9 @@ If no password is provided, mount.cifs will prompt for password entry
|
|||
|
||||
Restrictions
|
||||
============
|
||||
Servers must support the NTLM SMB dialect (which is the most recent, supported
|
||||
by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers)
|
||||
Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC
|
||||
1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a
|
||||
problem as most servers support this. IPv6 support is planned for the future,
|
||||
and is almost complete.
|
||||
1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a
|
||||
problem as most servers support this.
|
||||
|
||||
Valid filenames differ between Windows and Linux. Windows typically restricts
|
||||
filenames which contain certain reserved characters (e.g.the character :
|
||||
|
@ -458,6 +455,8 @@ A partial list of the supported mount options follows:
|
|||
byte range locks).
|
||||
remount remount the share (often used to change from ro to rw mounts
|
||||
or vice versa)
|
||||
cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for
|
||||
the file. (EXPERIMENTAL)
|
||||
servern Specify the server 's netbios name (RFC1001 name) to use
|
||||
when attempting to setup a session to the server. This is
|
||||
This is needed for mounting to some older servers (such
|
||||
|
@ -584,8 +583,8 @@ Experimental When set to 1 used to enable certain experimental
|
|||
performance enhancement was disabled when
|
||||
signing turned on in case buffer was modified
|
||||
just before it was sent, also this flag will
|
||||
be used to use the new experimental sessionsetup
|
||||
code).
|
||||
be used to use the new experimental directory change
|
||||
notification code).
|
||||
|
||||
These experimental features and tracing can be enabled by changing flags in
|
||||
/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:
|
|||
Two other experimental features are under development. To test these
|
||||
requires enabling CONFIG_CIFS_EXPERIMENTAL
|
||||
|
||||
ipv6 enablement
|
||||
cifsacl support needed to retrieve approximated mode bits based on
|
||||
the contents on the CIFS ACL.
|
||||
|
||||
DNOTIFY fcntl: needed for support of directory change
|
||||
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
|
|||
returned success.
|
||||
|
||||
Also note that "cat /proc/fs/cifs/DebugData" will display information about
|
||||
the active sessions and the shares that are mounted. Note: NTLMv2 enablement
|
||||
will not work since its implementation is not quite complete yet. Do not alter
|
||||
the ExtendedSecurity configuration value unless you are doing specific testing.
|
||||
Enabling extended security works to Windows 2000 Workstations and XP but not to
|
||||
Windows 2000 server or Samba since it does not usually send "raw NTLMSSP"
|
||||
(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not
|
||||
complete in the CIFS VFS yet).
|
||||
the active sessions and the shares that are mounted.
|
||||
Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is enabled
|
||||
but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
|
||||
LANMAN support do not require this helpr.
|
||||
|
|
|
@ -16,7 +16,7 @@ SecurityDescriptors
|
|||
c) Better pam/winbind integration (e.g. to handle uid mapping
|
||||
better)
|
||||
|
||||
d) Kerberos/SPNEGO session setup support - (started)
|
||||
d) Verify that Kerberos signing works
|
||||
|
||||
e) Cleanup now unneeded SessSetup code in
|
||||
fs/cifs/connect.c and add back in NTLMSSP code if any servers
|
||||
|
|
|
@ -66,20 +66,26 @@ struct key_type cifs_spnego_key_type = {
|
|||
.describe = user_describe,
|
||||
};
|
||||
|
||||
#define MAX_VER_STR_LEN 9 /* length of longest version string e.g.
|
||||
strlen(";ver=0xFF") */
|
||||
#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
|
||||
in future could have strlen(";sec=ntlmsspi") */
|
||||
#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
|
||||
/* get a key struct with a SPNEGO security blob, suitable for session setup */
|
||||
struct key *
|
||||
cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname)
|
||||
cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
||||
{
|
||||
struct TCP_Server_Info *server = sesInfo->server;
|
||||
char *description, *dp;
|
||||
size_t desc_len;
|
||||
struct key *spnego_key;
|
||||
const char *hostname = server->hostname;
|
||||
|
||||
|
||||
/* version + ;ip{4|6}= + address + ;host=hostname +
|
||||
;sec= + ;uid= + NULL */
|
||||
desc_len = 4 + 5 + 32 + 1 + 5 + strlen(hostname) +
|
||||
strlen(";sec=krb5") + 7 + sizeof(uid_t)*2 + 1;
|
||||
/* BB: come up with better scheme for determining length */
|
||||
/* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host=
|
||||
hostname sec=mechanism uid=0x uid */
|
||||
desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 +
|
||||
strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2);
|
||||
spnego_key = ERR_PTR(-ENOMEM);
|
||||
description = kzalloc(desc_len, GFP_KERNEL);
|
||||
if (description == NULL)
|
||||
|
@ -88,7 +94,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo, const char *hostname)
|
|||
dp = description;
|
||||
/* start with version and hostname portion of UNC string */
|
||||
spnego_key = ERR_PTR(-EINVAL);
|
||||
sprintf(dp, "0x%2.2x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
|
||||
sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
|
||||
hostname);
|
||||
dp = description + strlen(description);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ struct cifs_spnego_msg {
|
|||
|
||||
#ifdef __KERNEL__
|
||||
extern struct key_type cifs_spnego_key_type;
|
||||
extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo);
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _CIFS_SPNEGO_H */
|
||||
|
|
|
@ -269,6 +269,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||
|
||||
/* BB need to add parm so we can store the SID BB */
|
||||
|
||||
if (!pdacl) {
|
||||
/* no DACL in the security descriptor, set
|
||||
all the permissions for user/group/other */
|
||||
inode->i_mode |= S_IRWXUGO;
|
||||
return;
|
||||
}
|
||||
|
||||
/* validate that we do not go past end of acl */
|
||||
if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
|
||||
cERROR(1, ("ACL too small to parse DACL"));
|
||||
|
@ -286,12 +293,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
|
|||
user/group/other have no permissions */
|
||||
inode->i_mode &= ~(S_IRWXUGO);
|
||||
|
||||
if (!pdacl) {
|
||||
/* no DACL in the security descriptor, set
|
||||
all the permissions for user/group/other */
|
||||
inode->i_mode |= S_IRWXUGO;
|
||||
return;
|
||||
}
|
||||
acl_base = (char *)pdacl;
|
||||
acl_size = sizeof(struct cifs_acl);
|
||||
|
||||
|
|
|
@ -266,6 +266,7 @@ cifs_alloc_inode(struct super_block *sb)
|
|||
cifs_inode->cifsAttrs = 0x20; /* default */
|
||||
atomic_set(&cifs_inode->inUse, 0);
|
||||
cifs_inode->time = 0;
|
||||
cifs_inode->write_behind_rc = 0;
|
||||
/* Until the file is open and we have gotten oplock
|
||||
info back from the server, can not assume caching of
|
||||
file data or metadata */
|
||||
|
@ -852,7 +853,7 @@ static int cifs_oplock_thread(void *dummyarg)
|
|||
struct cifsTconInfo *pTcon;
|
||||
struct inode *inode;
|
||||
__u16 netfid;
|
||||
int rc;
|
||||
int rc, waitrc = 0;
|
||||
|
||||
set_freezable();
|
||||
do {
|
||||
|
@ -884,9 +885,11 @@ static int cifs_oplock_thread(void *dummyarg)
|
|||
filemap_fdatawrite(inode->i_mapping);
|
||||
if (CIFS_I(inode)->clientCanCacheRead
|
||||
== 0) {
|
||||
filemap_fdatawait(inode->i_mapping);
|
||||
waitrc = filemap_fdatawait(inode->i_mapping);
|
||||
invalidate_remote_inode(inode);
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = waitrc;
|
||||
} else
|
||||
rc = 0;
|
||||
/* mutex_unlock(&inode->i_mutex);*/
|
||||
|
|
|
@ -110,6 +110,7 @@ struct mac_key {
|
|||
unsigned int len;
|
||||
union {
|
||||
char ntlm[CIFS_SESS_KEY_SIZE + 16];
|
||||
char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */
|
||||
struct {
|
||||
char key[16];
|
||||
struct ntlmv2_resp resp;
|
||||
|
@ -139,6 +140,7 @@ struct TCP_Server_Info {
|
|||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
|
||||
char *hostname; /* hostname portion of UNC string */
|
||||
struct socket *ssocket;
|
||||
union {
|
||||
struct sockaddr_in sockAddr;
|
||||
|
@ -471,6 +473,17 @@ struct dir_notify_req {
|
|||
#define CIFS_LARGE_BUFFER 2
|
||||
#define CIFS_IOVEC 4 /* array of response buffers */
|
||||
|
||||
/* Type of Request to SendReceive2 */
|
||||
#define CIFS_STD_OP 0 /* normal request timeout */
|
||||
#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */
|
||||
#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */
|
||||
#define CIFS_BLOCKING_OP 4 /* operation can block */
|
||||
#define CIFS_ASYNC_OP 8 /* do not wait for response */
|
||||
#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */
|
||||
#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */
|
||||
#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */
|
||||
#define CIFS_NO_RESP 0x040 /* no response buffer required */
|
||||
|
||||
/* Security Flags: indicate type of session setup needed */
|
||||
#define CIFSSEC_MAY_SIGN 0x00001
|
||||
#define CIFSSEC_MAY_NTLM 0x00002
|
||||
|
|
|
@ -48,10 +48,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
|||
struct smb_hdr * /* input */ ,
|
||||
struct smb_hdr * /* out */ ,
|
||||
int * /* bytes returned */ , const int long_op);
|
||||
extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
struct smb_hdr *in_buf, int flags);
|
||||
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||
struct kvec *, int /* nvec to send */,
|
||||
int * /* type of buf returned */ , const int long_op,
|
||||
const int logError /* whether to log status code*/ );
|
||||
int * /* type of buf returned */ , const int flags);
|
||||
extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
|
||||
struct cifsTconInfo *,
|
||||
struct smb_hdr * /* input */ ,
|
||||
|
@ -76,8 +77,6 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
|||
extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
|
||||
struct cifsSesInfo *ses,
|
||||
void **request_buf);
|
||||
extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo,
|
||||
const char *hostname);
|
||||
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
const int stage,
|
||||
const struct nls_table *nls_cp);
|
||||
|
@ -248,15 +247,15 @@ extern int CIFSSMBQueryReparseLinkInfo(const int xid,
|
|||
extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
|
||||
const char *fileName, const int disposition,
|
||||
const int access_flags, const int omode,
|
||||
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
|
||||
const char *fileName, const int disposition,
|
||||
const int access_flags, const int omode,
|
||||
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
__u16 *netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
|
||||
u32 posix_flags, __u64 mode, __u16 * netfid,
|
||||
u32 posix_flags, __u64 mode, __u16 *netfid,
|
||||
FILE_UNIX_BASIC_INFO *pRetData,
|
||||
__u32 *pOplock, const char *name,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
|
@ -277,7 +276,7 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
|||
const __u64 offset, unsigned int *nbytes,
|
||||
struct kvec *iov, const int nvec, const int long_op);
|
||||
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
|
||||
const unsigned char *searchName, __u64 * inode_number,
|
||||
const unsigned char *searchName, __u64 *inode_number,
|
||||
const struct nls_table *nls_codepage,
|
||||
int remap_special_chars);
|
||||
extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
|
||||
|
@ -352,5 +351,5 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
|
|||
const char *local_acl, const int buflen, const int acl_type,
|
||||
const struct nls_table *nls_codepage, int remap_special_chars);
|
||||
extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
|
||||
const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
|
||||
const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
|
||||
#endif /* _CIFSPROTO_H */
|
||||
|
|
|
@ -698,9 +698,7 @@ int
|
|||
CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
|
||||
{
|
||||
struct smb_hdr *smb_buffer;
|
||||
struct smb_hdr *smb_buffer_response; /* BB removeme BB */
|
||||
int rc = 0;
|
||||
int length;
|
||||
|
||||
cFYI(1, ("In tree disconnect"));
|
||||
/*
|
||||
|
@ -737,16 +735,12 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
|
|||
if (rc) {
|
||||
up(&tcon->tconSem);
|
||||
return rc;
|
||||
} else {
|
||||
smb_buffer_response = smb_buffer; /* BB removeme BB */
|
||||
}
|
||||
rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
|
||||
&length, 0);
|
||||
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
|
||||
if (rc)
|
||||
cFYI(1, ("Tree disconnect failed %d", rc));
|
||||
|
||||
if (smb_buffer)
|
||||
cifs_small_buf_release(smb_buffer);
|
||||
up(&tcon->tconSem);
|
||||
|
||||
/* No need to return error on this operation if tid invalidated and
|
||||
|
@ -760,10 +754,8 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
|
|||
int
|
||||
CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
||||
{
|
||||
struct smb_hdr *smb_buffer_response;
|
||||
LOGOFF_ANDX_REQ *pSMB;
|
||||
int rc = 0;
|
||||
int length;
|
||||
|
||||
cFYI(1, ("In SMBLogoff for session disconnect"));
|
||||
if (ses)
|
||||
|
@ -782,8 +774,6 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
|||
return rc;
|
||||
}
|
||||
|
||||
smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
|
||||
|
||||
if (ses->server) {
|
||||
pSMB->hdr.Mid = GetNextMid(ses->server);
|
||||
|
||||
|
@ -795,8 +785,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
|||
pSMB->hdr.Uid = ses->Suid;
|
||||
|
||||
pSMB->AndXCommand = 0xFF;
|
||||
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
|
||||
smb_buffer_response, &length, 0);
|
||||
rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (ses->server) {
|
||||
atomic_dec(&ses->server->socketUseCount);
|
||||
if (atomic_read(&ses->server->socketUseCount) == 0) {
|
||||
|
@ -807,7 +796,6 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
|
|||
}
|
||||
}
|
||||
up(&ses->sesSem);
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
/* if session dead then we do not need to do ulogoff,
|
||||
since server closed smb session, no sense reporting
|
||||
|
@ -1255,7 +1243,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
/* long_op set to 1 to allow for oplock break timeouts */
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 1);
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
|
||||
cifs_stats_inc(&tcon->num_opens);
|
||||
if (rc) {
|
||||
cFYI(1, ("Error in Open = %d", rc));
|
||||
|
@ -1368,7 +1356,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
/* long_op set to 1 to allow for oplock break timeouts */
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 1);
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
|
||||
cifs_stats_inc(&tcon->num_opens);
|
||||
if (rc) {
|
||||
cFYI(1, ("Error in Open = %d", rc));
|
||||
|
@ -1446,7 +1434,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
|
|||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
|
||||
&resp_buf_type, 0 /* not long op */, 1 /* log err */ );
|
||||
&resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
|
||||
cifs_stats_inc(&tcon->num_reads);
|
||||
pSMBr = (READ_RSP *)iov[0].iov_base;
|
||||
if (rc) {
|
||||
|
@ -1665,7 +1653,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
|||
|
||||
|
||||
rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
|
||||
long_op, 0 /* do not log STATUS code */ );
|
||||
long_op);
|
||||
cifs_stats_inc(&tcon->num_writes);
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error Write2 = %d", rc));
|
||||
|
@ -1707,7 +1695,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||
int timeout = 0;
|
||||
__u16 count;
|
||||
|
||||
cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
|
||||
cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock));
|
||||
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
|
||||
|
||||
if (rc)
|
||||
|
@ -1716,10 +1704,10 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
|
||||
|
||||
if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
|
||||
timeout = -1; /* no response expected */
|
||||
timeout = CIFS_ASYNC_OP; /* no response expected */
|
||||
pSMB->Timeout = 0;
|
||||
} else if (waitFlag == TRUE) {
|
||||
timeout = 3; /* blocking operation, no timeout */
|
||||
timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
|
||||
pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
|
||||
} else {
|
||||
pSMB->Timeout = 0;
|
||||
|
@ -1749,15 +1737,16 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||
if (waitFlag) {
|
||||
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned);
|
||||
cifs_small_buf_release(pSMB);
|
||||
} else {
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
|
||||
timeout);
|
||||
/* SMB buffer freed by function above */
|
||||
}
|
||||
cifs_stats_inc(&tcon->num_locks);
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error in Lock = %d", rc));
|
||||
}
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
@ -1776,7 +1765,9 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
int rc = 0;
|
||||
int timeout = 0;
|
||||
int bytes_returned = 0;
|
||||
int resp_buf_type = 0;
|
||||
__u16 params, param_offset, offset, byte_count, count;
|
||||
struct kvec iov[1];
|
||||
|
||||
cFYI(1, ("Posix Lock"));
|
||||
|
||||
|
@ -1818,7 +1809,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
|
||||
parm_data->lock_type = cpu_to_le16(lock_type);
|
||||
if (waitFlag) {
|
||||
timeout = 3; /* blocking operation, no timeout */
|
||||
timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
|
||||
parm_data->lock_flags = cpu_to_le16(1);
|
||||
pSMB->Timeout = cpu_to_le32(-1);
|
||||
} else
|
||||
|
@ -1838,8 +1829,13 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned);
|
||||
} else {
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
|
||||
&resp_buf_type, timeout);
|
||||
pSMB = NULL; /* request buf already freed by SendReceive2. Do
|
||||
not try to free it twice below on exit */
|
||||
pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
|
@ -1874,6 +1870,11 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
if (pSMB)
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
if (resp_buf_type == CIFS_SMALL_BUFFER)
|
||||
cifs_small_buf_release(iov[0].iov_base);
|
||||
else if (resp_buf_type == CIFS_LARGE_BUFFER)
|
||||
cifs_buf_release(iov[0].iov_base);
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
||||
|
@ -1886,8 +1887,6 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
|
|||
{
|
||||
int rc = 0;
|
||||
CLOSE_REQ *pSMB = NULL;
|
||||
CLOSE_RSP *pSMBr = NULL;
|
||||
int bytes_returned;
|
||||
cFYI(1, ("In CIFSSMBClose"));
|
||||
|
||||
/* do not retry on dead session on close */
|
||||
|
@ -1897,13 +1896,10 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
|
||||
|
||||
pSMB->FileID = (__u16) smb_file_id;
|
||||
pSMB->LastWriteTime = 0xFFFFFFFF;
|
||||
pSMB->ByteCount = 0;
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
cifs_stats_inc(&tcon->num_closes);
|
||||
if (rc) {
|
||||
if (rc != -EINTR) {
|
||||
|
@ -1912,8 +1908,6 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
|
|||
}
|
||||
}
|
||||
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
/* Since session is dead, file will be closed on server already */
|
||||
if (rc == -EAGAIN)
|
||||
rc = 0;
|
||||
|
@ -3102,7 +3096,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
|
|||
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
|
||||
|
||||
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
|
||||
0 /* not long op */, 0 /* do not log STATUS codes */ );
|
||||
CIFS_STD_OP);
|
||||
cifs_stats_inc(&tcon->num_acl_get);
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error in QuerySecDesc = %d", rc));
|
||||
|
@ -3763,8 +3757,6 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
|
|||
{
|
||||
int rc = 0;
|
||||
FINDCLOSE_REQ *pSMB = NULL;
|
||||
CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
|
||||
int bytes_returned;
|
||||
|
||||
cFYI(1, ("In CIFSSMBFindClose"));
|
||||
rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
|
||||
|
@ -3776,16 +3768,13 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
|
||||
pSMB->FileID = searchHandle;
|
||||
pSMB->ByteCount = 0;
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (rc) {
|
||||
cERROR(1, ("Send error in FindClose = %d", rc));
|
||||
}
|
||||
cifs_stats_inc(&tcon->num_fclose);
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
/* Since session is dead, search handle closed on server already */
|
||||
if (rc == -EAGAIN)
|
||||
|
@ -4707,11 +4696,9 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
|
|||
__u16 fid, __u32 pid_of_opener, int SetAllocation)
|
||||
{
|
||||
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
||||
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
|
||||
char *data_offset;
|
||||
struct file_end_of_file_info *parm_data;
|
||||
int rc = 0;
|
||||
int bytes_returned = 0;
|
||||
__u16 params, param_offset, offset, byte_count, count;
|
||||
|
||||
cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
|
||||
|
@ -4721,8 +4708,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
|
||||
|
||||
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
|
||||
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
|
||||
|
||||
|
@ -4773,17 +4758,13 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
|
|||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (rc) {
|
||||
cFYI(1,
|
||||
("Send error in SetFileInfo (SetFileSize) = %d",
|
||||
rc));
|
||||
}
|
||||
|
||||
if (pSMB)
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
||||
|
@ -4801,10 +4782,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
|||
const FILE_BASIC_INFO *data, __u16 fid)
|
||||
{
|
||||
struct smb_com_transaction2_sfi_req *pSMB = NULL;
|
||||
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
|
||||
char *data_offset;
|
||||
int rc = 0;
|
||||
int bytes_returned = 0;
|
||||
__u16 params, param_offset, offset, byte_count, count;
|
||||
|
||||
cFYI(1, ("Set Times (via SetFileInfo)"));
|
||||
|
@ -4813,8 +4792,6 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
|
||||
|
||||
/* At this point there is no need to override the current pid
|
||||
with the pid of the opener, but that could change if we someday
|
||||
use an existing handle (rather than opening one on the fly) */
|
||||
|
@ -4854,14 +4831,11 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
|
||||
}
|
||||
|
||||
cifs_small_buf_release(pSMB);
|
||||
|
||||
/* Note: On -EAGAIN error only caller can retry on handle based calls
|
||||
since file handle passed in no longer valid */
|
||||
|
||||
|
@ -5152,7 +5126,8 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->ByteCount = 0;
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, -1);
|
||||
(struct smb_hdr *)pSMBr, &bytes_returned,
|
||||
CIFS_ASYNC_OP);
|
||||
if (rc) {
|
||||
cFYI(1, ("Error in Notify = %d", rc));
|
||||
} else {
|
||||
|
|
|
@ -438,9 +438,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
csocket = server->ssocket;
|
||||
wake_up(&server->response_q);
|
||||
continue;
|
||||
} else if (length < 4) {
|
||||
cFYI(1, ("less than four bytes received (%d bytes)",
|
||||
length));
|
||||
} else if (length < pdu_length) {
|
||||
cFYI(1, ("requested %d bytes but only got %d bytes",
|
||||
pdu_length, length));
|
||||
pdu_length -= length;
|
||||
msleep(1);
|
||||
goto incomplete_rcv;
|
||||
|
@ -752,6 +752,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
|
||||
kfree(server->hostname);
|
||||
kfree(server);
|
||||
if (length > 0)
|
||||
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
||||
|
@ -760,6 +761,34 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* extract the host portion of the UNC string */
|
||||
static char *
|
||||
extract_hostname(const char *unc)
|
||||
{
|
||||
const char *src;
|
||||
char *dst, *delim;
|
||||
unsigned int len;
|
||||
|
||||
/* skip double chars at beginning of string */
|
||||
/* BB: check validity of these bytes? */
|
||||
src = unc + 2;
|
||||
|
||||
/* delimiter between hostname and sharename is always '\\' now */
|
||||
delim = strchr(src, '\\');
|
||||
if (!delim)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
len = delim - src;
|
||||
dst = kmalloc((len + 1), GFP_KERNEL);
|
||||
if (dst == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_parse_mount_options(char *options, const char *devname,
|
||||
struct smb_vol *vol)
|
||||
|
@ -1781,11 +1810,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
|
||||
memset(&volume_info, 0, sizeof(struct smb_vol));
|
||||
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (volume_info.nullauth) {
|
||||
|
@ -1798,11 +1824,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
cifserror("No username specified");
|
||||
/* In userspace mount helper we can get user name from alternate
|
||||
locations such as env variables and files on disk */
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (volume_info.UNCip && volume_info.UNC) {
|
||||
|
@ -1821,11 +1844,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
|
||||
if (rc <= 0) {
|
||||
/* we failed translating address */
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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,
|
|||
/* BB using ip addr as server name to connect to the
|
||||
DFS root below */
|
||||
cERROR(1, ("Connecting to DFS root not implemented yet"));
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
} else /* which servers DFS root would we conect to */ {
|
||||
cERROR(1,
|
||||
("CIFS mount error: No UNC path (e.g. -o "
|
||||
"unc=//192.168.1.100/public) specified"));
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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,
|
|||
if (cifs_sb->local_nls == NULL) {
|
||||
cERROR(1, ("CIFS mount error: iocharset %s not found",
|
||||
volume_info.iocharset));
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -ELIBACC;
|
||||
rc = -ELIBACC;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1878,11 +1889,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
&sin_server6.sin6_addr,
|
||||
volume_info.username, &srvTcp);
|
||||
} else {
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (srvTcp) {
|
||||
|
@ -1906,22 +1914,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
"Aborting operation"));
|
||||
if (csocket != NULL)
|
||||
sock_release(csocket);
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
|
||||
if (!srvTcp) {
|
||||
rc = -ENOMEM;
|
||||
sock_release(csocket);
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
goto out;
|
||||
} else {
|
||||
memcpy(&srvTcp->addr.sockAddr, &sin_server,
|
||||
sizeof(struct sockaddr_in));
|
||||
|
@ -1929,6 +1929,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
/* BB Add code for ipv6 case too */
|
||||
srvTcp->ssocket = csocket;
|
||||
srvTcp->protocolType = IPV4;
|
||||
srvTcp->hostname = extract_hostname(volume_info.UNC);
|
||||
if (IS_ERR(srvTcp->hostname)) {
|
||||
rc = PTR_ERR(srvTcp->hostname);
|
||||
sock_release(csocket);
|
||||
goto out;
|
||||
}
|
||||
init_waitqueue_head(&srvTcp->response_q);
|
||||
init_waitqueue_head(&srvTcp->request_q);
|
||||
INIT_LIST_HEAD(&srvTcp->pending_mid_q);
|
||||
|
@ -1938,16 +1944,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
srvTcp->tcpStatus = CifsNew;
|
||||
init_MUTEX(&srvTcp->tcpSem);
|
||||
srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
|
||||
if ( IS_ERR(srvTcp->tsk) ) {
|
||||
if (IS_ERR(srvTcp->tsk)) {
|
||||
rc = PTR_ERR(srvTcp->tsk);
|
||||
cERROR(1, ("error %d create cifsd thread", rc));
|
||||
srvTcp->tsk = NULL;
|
||||
sock_release(csocket);
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.password);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
kfree(srvTcp->hostname);
|
||||
goto out;
|
||||
}
|
||||
wait_for_completion(&cifsd_complete);
|
||||
rc = 0;
|
||||
|
@ -1962,8 +1965,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
if (existingCifsSes) {
|
||||
pSesInfo = existingCifsSes;
|
||||
cFYI(1, ("Existing smb sess found"));
|
||||
kfree(volume_info.password);
|
||||
/* volume_info.UNC freed at end of function */
|
||||
} else if (!rc) {
|
||||
cFYI(1, ("Existing smb sess not found"));
|
||||
pSesInfo = sesInfoAlloc();
|
||||
|
@ -1977,8 +1978,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
|
||||
if (!rc) {
|
||||
/* volume_info.password freed at unmount */
|
||||
if (volume_info.password)
|
||||
if (volume_info.password) {
|
||||
pSesInfo->password = volume_info.password;
|
||||
/* set to NULL to prevent freeing on exit */
|
||||
volume_info.password = NULL;
|
||||
}
|
||||
if (volume_info.username)
|
||||
strncpy(pSesInfo->userName,
|
||||
volume_info.username,
|
||||
|
@ -2000,8 +2004,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
up(&pSesInfo->sesSem);
|
||||
if (!rc)
|
||||
atomic_inc(&srvTcp->socketUseCount);
|
||||
} else
|
||||
kfree(volume_info.password);
|
||||
}
|
||||
}
|
||||
|
||||
/* search for existing tcon to this server share */
|
||||
|
@ -2106,9 +2109,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
"", cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
kfree(volume_info.UNC);
|
||||
FreeXid(xid);
|
||||
return -ENODEV;
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
} else {
|
||||
/* BB Do we need to wrap sesSem around
|
||||
* this TCon call and Unix SetFS as
|
||||
|
@ -2231,6 +2233,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
(in which case it is not needed anymore) but when new sesion is created
|
||||
the password ptr is put in the new session structure (in which case the
|
||||
password will be freed at unmount time) */
|
||||
out:
|
||||
/* zero out password before freeing */
|
||||
if (volume_info.password != NULL) {
|
||||
memset(volume_info.password, 0, strlen(volume_info.password));
|
||||
kfree(volume_info.password);
|
||||
}
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
|
@ -2374,7 +2382,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
|
||||
&bytes_returned, 1);
|
||||
&bytes_returned, CIFS_LONG_OP);
|
||||
if (rc) {
|
||||
/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
|
||||
} else if ((smb_buffer_response->WordCount == 3)
|
||||
|
@ -2678,7 +2686,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
pSMB->req.ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
|
||||
&bytes_returned, 1);
|
||||
&bytes_returned, CIFS_LONG_OP);
|
||||
|
||||
if (smb_buffer_response->Status.CifsError ==
|
||||
cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
|
||||
|
@ -3105,7 +3113,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
pSMB->req.ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
|
||||
&bytes_returned, 1);
|
||||
&bytes_returned, CIFS_LONG_OP);
|
||||
if (rc) {
|
||||
/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
|
||||
} else if ((smb_buffer_response->WordCount == 3) ||
|
||||
|
@ -3381,7 +3389,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
pSMB->hdr.smb_buf_length += count;
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
|
||||
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
|
||||
CIFS_STD_OP);
|
||||
|
||||
/* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
|
||||
/* above now done in SendReceive */
|
||||
|
|
|
@ -130,7 +130,9 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
|
|||
if (file->f_path.dentry->d_inode->i_mapping) {
|
||||
/* BB no need to lock inode until after invalidate
|
||||
since namei code should already have it locked? */
|
||||
filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
|
||||
rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
|
||||
if (rc != 0)
|
||||
CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc;
|
||||
}
|
||||
cFYI(1, ("invalidating remote inode since open detected it "
|
||||
"changed"));
|
||||
|
@ -425,7 +427,9 @@ static int cifs_reopen_file(struct file *file, int can_flush)
|
|||
pCifsInode = CIFS_I(inode);
|
||||
if (pCifsInode) {
|
||||
if (can_flush) {
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc != 0)
|
||||
CIFS_I(inode)->write_behind_rc = rc;
|
||||
/* temporarily disable caching while we
|
||||
go to server to get inode info */
|
||||
pCifsInode->clientCanCacheAll = FALSE;
|
||||
|
@ -835,9 +839,9 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
|||
xid = GetXid();
|
||||
|
||||
if (*poffset > file->f_path.dentry->d_inode->i_size)
|
||||
long_op = 2; /* writes past end of file can take a long time */
|
||||
long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
|
||||
else
|
||||
long_op = 1;
|
||||
long_op = CIFS_LONG_OP;
|
||||
|
||||
for (total_written = 0; write_size > total_written;
|
||||
total_written += bytes_written) {
|
||||
|
@ -884,7 +888,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
|||
}
|
||||
} else
|
||||
*poffset += bytes_written;
|
||||
long_op = FALSE; /* subsequent writes fast -
|
||||
long_op = CIFS_STD_OP; /* subsequent writes fast -
|
||||
15 seconds is plenty */
|
||||
}
|
||||
|
||||
|
@ -934,9 +938,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
xid = GetXid();
|
||||
|
||||
if (*poffset > file->f_path.dentry->d_inode->i_size)
|
||||
long_op = 2; /* writes past end of file can take a long time */
|
||||
long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
|
||||
else
|
||||
long_op = 1;
|
||||
long_op = CIFS_LONG_OP;
|
||||
|
||||
for (total_written = 0; write_size > total_written;
|
||||
total_written += bytes_written) {
|
||||
|
@ -1002,7 +1006,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
}
|
||||
} else
|
||||
*poffset += bytes_written;
|
||||
long_op = FALSE; /* subsequent writes fast -
|
||||
long_op = CIFS_STD_OP; /* subsequent writes fast -
|
||||
15 seconds is plenty */
|
||||
}
|
||||
|
||||
|
@ -1087,11 +1091,11 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
|
|||
read_unlock(&GlobalSMBSeslock);
|
||||
return open_file;
|
||||
}
|
||||
|
||||
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
/* Had to unlock since following call can block */
|
||||
rc = cifs_reopen_file(open_file->pfile, FALSE);
|
||||
if (!rc) {
|
||||
if (!rc) {
|
||||
if (!open_file->closePend)
|
||||
return open_file;
|
||||
else { /* start over in case this was deleted */
|
||||
|
@ -1114,7 +1118,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
|
|||
/* can not use this handle, no write
|
||||
pending on this one after all */
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
|
||||
|
||||
if (open_file->closePend) /* list could have changed */
|
||||
goto refind_writable;
|
||||
/* else we simply continue to the next entry. Thus
|
||||
|
@ -1360,14 +1364,17 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
open_file->netfid,
|
||||
bytes_to_write, offset,
|
||||
&bytes_written, iov, n_iov,
|
||||
1);
|
||||
CIFS_LONG_OP);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
if (rc || bytes_written < bytes_to_write) {
|
||||
cERROR(1, ("Write2 ret %d, wrote %d",
|
||||
rc, bytes_written));
|
||||
/* BB what if continued retry is
|
||||
requested via mount flags? */
|
||||
set_bit(AS_EIO, &mapping->flags);
|
||||
if (rc == -ENOSPC)
|
||||
set_bit(AS_ENOSPC, &mapping->flags);
|
||||
else
|
||||
set_bit(AS_EIO, &mapping->flags);
|
||||
} else {
|
||||
cifs_stats_bytes_written(cifs_sb->tcon,
|
||||
bytes_written);
|
||||
|
@ -1499,9 +1506,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
|
|||
cFYI(1, ("Sync file - name: %s datasync: 0x%x",
|
||||
dentry->d_name.name, datasync));
|
||||
|
||||
rc = filemap_fdatawrite(inode->i_mapping);
|
||||
if (rc == 0)
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc == 0) {
|
||||
rc = CIFS_I(inode)->write_behind_rc;
|
||||
CIFS_I(inode)->write_behind_rc = 0;
|
||||
}
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1553,8 +1562,11 @@ int cifs_flush(struct file *file, fl_owner_t id)
|
|||
filemapfdatawrite appears easier for the time being */
|
||||
|
||||
rc = filemap_fdatawrite(inode->i_mapping);
|
||||
if (!rc) /* reset wb rc if we were able to write out dirty pages */
|
||||
/* reset wb rc if we were able to write out dirty pages */
|
||||
if (!rc) {
|
||||
rc = CIFS_I(inode)->write_behind_rc;
|
||||
CIFS_I(inode)->write_behind_rc = 0;
|
||||
}
|
||||
|
||||
cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
|
||||
|
||||
|
|
|
@ -1233,7 +1233,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
|
|||
int cifs_revalidate(struct dentry *direntry)
|
||||
{
|
||||
int xid;
|
||||
int rc = 0;
|
||||
int rc = 0, wbrc = 0;
|
||||
char *full_path;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsInodeInfo *cifsInode;
|
||||
|
@ -1333,7 +1333,9 @@ int cifs_revalidate(struct dentry *direntry)
|
|||
if (direntry->d_inode->i_mapping) {
|
||||
/* do we need to lock inode until after invalidate completes
|
||||
below? */
|
||||
filemap_fdatawrite(direntry->d_inode->i_mapping);
|
||||
wbrc = filemap_fdatawrite(direntry->d_inode->i_mapping);
|
||||
if (wbrc)
|
||||
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
|
||||
}
|
||||
if (invalidate_inode) {
|
||||
/* shrink_dcache not necessary now that cifs dentry ops
|
||||
|
@ -1342,7 +1344,9 @@ int cifs_revalidate(struct dentry *direntry)
|
|||
shrink_dcache_parent(direntry); */
|
||||
if (S_ISREG(direntry->d_inode->i_mode)) {
|
||||
if (direntry->d_inode->i_mapping)
|
||||
filemap_fdatawait(direntry->d_inode->i_mapping);
|
||||
wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
|
||||
if (wbrc)
|
||||
CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
|
||||
/* may eventually have to do this for open files too */
|
||||
if (list_empty(&(cifsInode->openFileList))) {
|
||||
/* changed on server - flush read ahead pages */
|
||||
|
@ -1485,10 +1489,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
|
||||
/* BB check if we need to refresh inode from server now ? BB */
|
||||
|
||||
/* need to flush data before changing file size on server */
|
||||
filemap_write_and_wait(direntry->d_inode->i_mapping);
|
||||
|
||||
if (attrs->ia_valid & ATTR_SIZE) {
|
||||
/*
|
||||
Flush data before changing file size on server. If the
|
||||
flush returns error, store it to report later and continue.
|
||||
BB: This should be smarter. Why bother flushing pages that
|
||||
will be truncated anyway? Also, should we error out here if
|
||||
the flush returns error?
|
||||
*/
|
||||
rc = filemap_write_and_wait(direntry->d_inode->i_mapping);
|
||||
if (rc != 0) {
|
||||
CIFS_I(direntry->d_inode)->write_behind_rc = rc;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
/* To avoid spurious oplock breaks from server, in the case of
|
||||
inodes that we already have open, avoid doing path based
|
||||
setting of file size if we can do it by handle.
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "ntlmssp.h"
|
||||
#include "nterr.h"
|
||||
#include <linux/utsname.h>
|
||||
#include "cifs_spnego.h"
|
||||
|
||||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
SESSION_SETUP_ANDX *pSMB;
|
||||
__u32 capabilities;
|
||||
int count;
|
||||
int resp_buf_type = 0;
|
||||
struct kvec iov[2];
|
||||
int resp_buf_type;
|
||||
struct kvec iov[3];
|
||||
enum securityEnum type;
|
||||
__u16 action;
|
||||
int bytes_remaining;
|
||||
struct key *spnego_key = NULL;
|
||||
|
||||
if (ses == NULL)
|
||||
return -EINVAL;
|
||||
|
@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
|
||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||
|
||||
/* we will send the SMB in two pieces,
|
||||
a fixed length beginning part, and a
|
||||
second part which will include the strings
|
||||
and rest of bcc area, in order to avoid having
|
||||
to do a large buffer 17K allocation */
|
||||
/* we will send the SMB in three pieces:
|
||||
a fixed length beginning part, an optional
|
||||
SPNEGO blob (which can be zero length), and a
|
||||
last part which will include the strings
|
||||
and rest of bcc area. This allows us to avoid
|
||||
a large buffer 17K allocation */
|
||||
iov[0].iov_base = (char *)pSMB;
|
||||
iov[0].iov_len = smb_buf->smb_buf_length + 4;
|
||||
|
||||
/* setting this here allows the code at the end of the function
|
||||
to free the request buffer if there's an error */
|
||||
resp_buf_type = CIFS_SMALL_BUFFER;
|
||||
|
||||
/* 2000 big enough to fit max user, domain, NOS name etc. */
|
||||
str_area = kmalloc(2000, GFP_KERNEL);
|
||||
if (str_area == NULL) {
|
||||
cifs_small_buf_release(smb_buf);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
bcc_ptr = str_area;
|
||||
|
||||
ses->flags &= ~CIFS_SES_LANMAN;
|
||||
|
||||
iov[1].iov_base = NULL;
|
||||
iov[1].iov_len = 0;
|
||||
|
||||
if (type == LANMAN) {
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
char lnm_session_key[CIFS_SESS_KEY_SIZE];
|
||||
|
@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
struct ntlmv2_resp */
|
||||
|
||||
if (v2_sess_key == NULL) {
|
||||
cifs_small_buf_release(smb_buf);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
|
||||
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
|
||||
|
@ -499,22 +509,67 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
} else
|
||||
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
} else /* NTLMSSP or SPNEGO */ {
|
||||
} else if (type == Kerberos) {
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
struct cifs_spnego_msg *msg;
|
||||
spnego_key = cifs_get_spnego_key(ses);
|
||||
if (IS_ERR(spnego_key)) {
|
||||
rc = PTR_ERR(spnego_key);
|
||||
spnego_key = NULL;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
|
||||
msg = spnego_key->payload.data;
|
||||
/* bail out if key is too long */
|
||||
if (msg->sesskey_len >
|
||||
sizeof(ses->server->mac_signing_key.data.krb5)) {
|
||||
cERROR(1, ("Kerberos signing key too long (%u bytes)",
|
||||
msg->sesskey_len));
|
||||
rc = -EOVERFLOW;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
ses->server->mac_signing_key.len = msg->sesskey_len;
|
||||
memcpy(ses->server->mac_signing_key.data.krb5, msg->data,
|
||||
msg->sesskey_len);
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
capabilities |= CAP_EXTENDED_SECURITY;
|
||||
pSMB->req.Capabilities = cpu_to_le32(capabilities);
|
||||
/* BB set password lengths */
|
||||
iov[1].iov_base = msg->data + msg->sesskey_len;
|
||||
iov[1].iov_len = msg->secblob_len;
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len);
|
||||
|
||||
if (ses->capabilities & CAP_UNICODE) {
|
||||
/* unicode strings must be word aligned */
|
||||
if (iov[0].iov_len % 2) {
|
||||
*bcc_ptr = 0;
|
||||
bcc_ptr++;
|
||||
}
|
||||
unicode_oslm_strings(&bcc_ptr, nls_cp);
|
||||
unicode_domain_string(&bcc_ptr, ses, nls_cp);
|
||||
} else
|
||||
/* BB: is this right? */
|
||||
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||
#else /* ! CONFIG_CIFS_UPCALL */
|
||||
cERROR(1, ("Kerberos negotiated but upcall support disabled!"));
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
#endif /* CONFIG_CIFS_UPCALL */
|
||||
} else {
|
||||
cERROR(1, ("secType %d not supported!", type));
|
||||
rc = -ENOSYS;
|
||||
goto ssetup_exit;
|
||||
}
|
||||
|
||||
count = (long) bcc_ptr - (long) str_area;
|
||||
iov[2].iov_base = str_area;
|
||||
iov[2].iov_len = (long) bcc_ptr - (long) str_area;
|
||||
|
||||
count = iov[1].iov_len + iov[2].iov_len;
|
||||
smb_buf->smb_buf_length += count;
|
||||
|
||||
BCC_LE(smb_buf) = cpu_to_le16(count);
|
||||
|
||||
iov[1].iov_base = str_area;
|
||||
iov[1].iov_len = count;
|
||||
rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type,
|
||||
0 /* not long op */, 1 /* log NT STATUS if any */ );
|
||||
rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
|
||||
CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
|
||||
/* SMB request buf freed in SendReceive2 */
|
||||
|
||||
cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
|
||||
|
@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
ses, nls_cp);
|
||||
|
||||
ssetup_exit:
|
||||
if (spnego_key)
|
||||
key_put(spnego_key);
|
||||
kfree(str_area);
|
||||
if (resp_buf_type == CIFS_SMALL_BUFFER) {
|
||||
cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
|
||||
|
|
|
@ -308,7 +308,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
|||
|
||||
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
|
||||
{
|
||||
if (long_op == -1) {
|
||||
if (long_op == CIFS_ASYNC_OP) {
|
||||
/* oplock breaks must not be held up */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
} else {
|
||||
|
@ -337,7 +337,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
|
|||
as they are allowed to block on server */
|
||||
|
||||
/* update # of requests on the wire to server */
|
||||
if (long_op < 3)
|
||||
if (long_op != CIFS_BLOCKING_OP)
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
break;
|
||||
|
@ -415,17 +415,48 @@ static int wait_for_response(struct cifsSesInfo *ses,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Send an SMB Request. No response info (other than return code)
|
||||
* needs to be parsed.
|
||||
*
|
||||
* flags indicate the type of request buffer and how long to wait
|
||||
* and whether to log NT STATUS code (error) before mapping it to POSIX error
|
||||
*
|
||||
*/
|
||||
int
|
||||
SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
struct smb_hdr *in_buf, int flags)
|
||||
{
|
||||
int rc;
|
||||
struct kvec iov[1];
|
||||
int resp_buf_type;
|
||||
|
||||
iov[0].iov_base = (char *)in_buf;
|
||||
iov[0].iov_len = in_buf->smb_buf_length + 4;
|
||||
flags |= CIFS_NO_RESP;
|
||||
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc));
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
|
||||
const int long_op, const int logError)
|
||||
const int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
int long_op;
|
||||
unsigned int receive_len;
|
||||
unsigned long timeout;
|
||||
struct mid_q_entry *midQ;
|
||||
struct smb_hdr *in_buf = iov[0].iov_base;
|
||||
|
||||
long_op = flags & CIFS_TIMEOUT_MASK;
|
||||
|
||||
*pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
|
||||
|
||||
if ((ses == NULL) || (ses->server == NULL)) {
|
||||
|
@ -483,15 +514,22 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (long_op == -1)
|
||||
goto out;
|
||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||
if (long_op == CIFS_STD_OP)
|
||||
timeout = 15 * HZ;
|
||||
else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == 1)
|
||||
else if (long_op == CIFS_LONG_OP)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
else
|
||||
timeout = 15 * HZ;
|
||||
else if (long_op == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
else if (long_op == CIFS_BLOCKING_OP)
|
||||
timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
|
||||
else {
|
||||
cERROR(1, ("unknown timeout flag %d", long_op));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* wait for 15 seconds or until woken up due to response arriving or
|
||||
due to last connection to this server being unmounted */
|
||||
|
@ -566,7 +604,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(midQ->resp_buf, logError);
|
||||
rc = map_smb_to_linux_error(midQ->resp_buf,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
|
@ -574,8 +613,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(midQ->resp_buf) =
|
||||
le16_to_cpu(BCC_LE(midQ->resp_buf));
|
||||
midQ->resp_buf = NULL; /* mark it so will not be freed
|
||||
by DeleteMidQEntry */
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL; /* mark it so buf will
|
||||
not be freed by
|
||||
DeleteMidQEntry */
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1, ("Bad MID state?"));
|
||||
|
@ -663,17 +704,25 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (long_op == -1)
|
||||
goto out;
|
||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == 1)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
else
|
||||
if (long_op == CIFS_STD_OP)
|
||||
timeout = 15 * HZ;
|
||||
/* wait for 15 seconds or until woken up due to response arriving or
|
||||
due to last connection to this server being unmounted */
|
||||
else if (long_op == CIFS_ASYNC_OP)
|
||||
goto out;
|
||||
else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == CIFS_LONG_OP)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
else if (long_op == CIFS_BLOCKING_OP)
|
||||
timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
|
||||
else {
|
||||
cERROR(1, ("unknown timeout flag %d", long_op));
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
/* if signal pending do not hold up user for full smb timeout
|
||||
but we still give response a chance to complete */
|
||||
|
@ -812,7 +861,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->hdr.Mid = GetNextMid(ses->server);
|
||||
|
||||
return SendReceive(xid, ses, in_buf, out_buf,
|
||||
&bytes_returned, 0);
|
||||
&bytes_returned, CIFS_STD_OP);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -844,7 +893,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
rc = wait_for_free_request(ses, 3);
|
||||
rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
Loading…
Reference in a new issue