forked from Minki/linux
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] Do not send Query All EAs SMB when mount option nouser_xattr [CIFS] endian errors in lanman protocol support [CIFS] Fix oops in cifs_close due to unitialized lock sem and list in [CIFS] Fix oops when negotiating lanman and no password specified [CIFS] [CIFS] Allow cifsd to suspend if connection is lost [CIFS] Make midState usage more consistent [CIFS] spinlock protect read of last srv response time in timeout path [CIFS] Do not time out posix brl requests when using new posix setfileinfo
This commit is contained in:
commit
dc709bd190
@ -1,3 +1,13 @@
|
|||||||
|
Version 1.45
|
||||||
|
------------
|
||||||
|
Do not time out lockw calls when using posix extensions. Do not
|
||||||
|
time out requests if server still responding reasonably fast
|
||||||
|
on requests on other threads. Improve POSIX locking emulation,
|
||||||
|
(lock cancel now works, and unlock of merged range works even
|
||||||
|
to Windows servers now). Fix oops on mount to lanman servers
|
||||||
|
(win9x, os/2 etc.) when null password. Do not send listxattr
|
||||||
|
(SMB to query all EAs) if nouser_xattr specified.
|
||||||
|
|
||||||
Version 1.44
|
Version 1.44
|
||||||
------------
|
------------
|
||||||
Rewritten sessionsetup support, including support for legacy SMB
|
Rewritten sessionsetup support, including support for legacy SMB
|
||||||
|
@ -408,7 +408,7 @@ A partial list of the supported mount options follows:
|
|||||||
user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended
|
user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended
|
||||||
attributes) to the server (default) e.g. via setfattr
|
attributes) to the server (default) e.g. via setfattr
|
||||||
and getfattr utilities.
|
and getfattr utilities.
|
||||||
nouser_xattr Do not allow getfattr/setfattr to get/set xattrs
|
nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs
|
||||||
mapchars Translate six of the seven reserved characters (not backslash)
|
mapchars Translate six of the seven reserved characters (not backslash)
|
||||||
*?<>|:
|
*?<>|:
|
||||||
to the remap range (above 0xF000), which also
|
to the remap range (above 0xF000), which also
|
||||||
|
@ -277,7 +277,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
if(ses->password)
|
||||||
|
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||||
|
|
||||||
if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||||
if(extended_security & CIFSSEC_MAY_PLNTXT) {
|
if(extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||||
|
@ -402,7 +402,6 @@ static struct quotactl_ops cifs_quotactl_ops = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
|
||||||
static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
||||||
{
|
{
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
@ -422,7 +421,7 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
|||||||
tcon->tidStatus = CifsExiting;
|
tcon->tidStatus = CifsExiting;
|
||||||
up(&tcon->tconSem);
|
up(&tcon->tconSem);
|
||||||
|
|
||||||
/* cancel_brl_requests(tcon); */
|
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
|
||||||
/* cancel_notify_requests(tcon); */
|
/* cancel_notify_requests(tcon); */
|
||||||
if(tcon->ses && tcon->ses->server)
|
if(tcon->ses && tcon->ses->server)
|
||||||
{
|
{
|
||||||
@ -438,7 +437,6 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static int cifs_remount(struct super_block *sb, int *flags, char *data)
|
static int cifs_remount(struct super_block *sb, int *flags, char *data)
|
||||||
{
|
{
|
||||||
@ -457,9 +455,7 @@ struct super_operations cifs_super_ops = {
|
|||||||
unless later we add lazy close of inodes or unless the kernel forgets to call
|
unless later we add lazy close of inodes or unless the kernel forgets to call
|
||||||
us with the same number of releases (closes) as opens */
|
us with the same number of releases (closes) as opens */
|
||||||
.show_options = cifs_show_options,
|
.show_options = cifs_show_options,
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
|
||||||
.umount_begin = cifs_umount_begin,
|
.umount_begin = cifs_umount_begin,
|
||||||
#endif
|
|
||||||
.remount_fs = cifs_remount,
|
.remount_fs = cifs_remount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
|||||||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||||
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
||||||
unsigned int command, unsigned long arg);
|
unsigned int command, unsigned long arg);
|
||||||
#define CIFS_VERSION "1.44"
|
#define CIFS_VERSION "1.45"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) International Business Machines Corp., 2002,2006
|
* Copyright (C) International Business Machines Corp., 2002,2006
|
||||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||||
|
* Jeremy Allison (jra@samba.org)
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License as published
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
@ -159,6 +160,7 @@ struct TCP_Server_Info {
|
|||||||
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||||
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
|
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
|
||||||
|
unsigned long lstrp; /* when we got last response from this server */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -266,14 +268,14 @@ struct cifsTconInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This info hangs off the cifsFileInfo structure. This is used to track
|
* This info hangs off the cifsFileInfo structure, pointed to by llist.
|
||||||
* byte stream locks on the file
|
* This is used to track byte stream locks on the file
|
||||||
*/
|
*/
|
||||||
struct cifsLockInfo {
|
struct cifsLockInfo {
|
||||||
struct cifsLockInfo *next;
|
struct list_head llist; /* pointer to next cifsLockInfo */
|
||||||
int start;
|
__u64 offset;
|
||||||
int length;
|
__u64 length;
|
||||||
int type;
|
__u8 type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -304,6 +306,8 @@ struct cifsFileInfo {
|
|||||||
/* lock scope id (0 if none) */
|
/* lock scope id (0 if none) */
|
||||||
struct file * pfile; /* needed for writepage */
|
struct file * pfile; /* needed for writepage */
|
||||||
struct inode * pInode; /* needed for oplock break */
|
struct inode * pInode; /* needed for oplock break */
|
||||||
|
struct semaphore lock_sem;
|
||||||
|
struct list_head llist; /* list of byte range locks we have. */
|
||||||
unsigned closePend:1; /* file is marked to close */
|
unsigned closePend:1; /* file is marked to close */
|
||||||
unsigned invalidHandle:1; /* file closed via session abend */
|
unsigned invalidHandle:1; /* file closed via session abend */
|
||||||
atomic_t wrtPending; /* handle in use - defer close */
|
atomic_t wrtPending; /* handle in use - defer close */
|
||||||
|
@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
|||||||
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
|
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||||
struct kvec *, int /* nvec to send */,
|
struct kvec *, int /* nvec to send */,
|
||||||
int * /* type of buf returned */ , const int long_op);
|
int * /* type of buf returned */ , const int long_op);
|
||||||
|
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
|
||||||
|
struct smb_hdr * /* input */ ,
|
||||||
|
struct smb_hdr * /* out */ ,
|
||||||
|
int * /* bytes returned */);
|
||||||
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
|
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
|
||||||
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
|
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
|
||||||
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
|
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
|
||||||
|
@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||||||
/* BB get server time for time conversions and add
|
/* BB get server time for time conversions and add
|
||||||
code to use it and timezone since this is not UTC */
|
code to use it and timezone since this is not UTC */
|
||||||
|
|
||||||
if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
|
||||||
memcpy(server->cryptKey, rsp->EncryptionKey,
|
memcpy(server->cryptKey, rsp->EncryptionKey,
|
||||||
CIFS_CRYPTO_KEY_SIZE);
|
CIFS_CRYPTO_KEY_SIZE);
|
||||||
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
|
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
|
||||||
@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
pSMB->hdr.smb_buf_length += count;
|
pSMB->hdr.smb_buf_length += count;
|
||||||
pSMB->ByteCount = cpu_to_le16(count);
|
pSMB->ByteCount = cpu_to_le16(count);
|
||||||
|
|
||||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
if (waitFlag) {
|
||||||
|
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);
|
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
|
||||||
|
}
|
||||||
cifs_stats_inc(&tcon->num_locks);
|
cifs_stats_inc(&tcon->num_locks);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cFYI(1, ("Send error in Lock = %d", rc));
|
cFYI(1, ("Send error in Lock = %d", rc));
|
||||||
@ -1484,6 +1489,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
char *data_offset;
|
char *data_offset;
|
||||||
struct cifs_posix_lock *parm_data;
|
struct cifs_posix_lock *parm_data;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
int timeout = 0;
|
||||||
int bytes_returned = 0;
|
int bytes_returned = 0;
|
||||||
__u16 params, param_offset, offset, byte_count, count;
|
__u16 params, param_offset, offset, byte_count, count;
|
||||||
|
|
||||||
@ -1503,7 +1509,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
pSMB->MaxSetupCount = 0;
|
pSMB->MaxSetupCount = 0;
|
||||||
pSMB->Reserved = 0;
|
pSMB->Reserved = 0;
|
||||||
pSMB->Flags = 0;
|
pSMB->Flags = 0;
|
||||||
pSMB->Timeout = 0;
|
|
||||||
pSMB->Reserved2 = 0;
|
pSMB->Reserved2 = 0;
|
||||||
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
||||||
offset = param_offset + params;
|
offset = param_offset + params;
|
||||||
@ -1529,8 +1534,13 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
(((char *) &pSMB->hdr.Protocol) + offset);
|
(((char *) &pSMB->hdr.Protocol) + offset);
|
||||||
|
|
||||||
parm_data->lock_type = cpu_to_le16(lock_type);
|
parm_data->lock_type = cpu_to_le16(lock_type);
|
||||||
if(waitFlag)
|
if(waitFlag) {
|
||||||
|
timeout = 3; /* blocking operation, no timeout */
|
||||||
parm_data->lock_flags = cpu_to_le16(1);
|
parm_data->lock_flags = cpu_to_le16(1);
|
||||||
|
pSMB->Timeout = cpu_to_le32(-1);
|
||||||
|
} else
|
||||||
|
pSMB->Timeout = 0;
|
||||||
|
|
||||||
parm_data->pid = cpu_to_le32(current->tgid);
|
parm_data->pid = cpu_to_le32(current->tgid);
|
||||||
parm_data->start = cpu_to_le64(pLockData->fl_start);
|
parm_data->start = cpu_to_le64(pLockData->fl_start);
|
||||||
parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
|
parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
|
||||||
@ -1541,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||||||
pSMB->Reserved4 = 0;
|
pSMB->Reserved4 = 0;
|
||||||
pSMB->hdr.smb_buf_length += byte_count;
|
pSMB->hdr.smb_buf_length += byte_count;
|
||||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
if (waitFlag) {
|
||||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cFYI(1, ("Send error in Posix Lock = %d", rc));
|
cFYI(1, ("Send error in Posix Lock = %d", rc));
|
||||||
} else if (get_flag) {
|
} else if (get_flag) {
|
||||||
|
@ -182,6 +182,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||||||
|
|
||||||
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
|
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
|
||||||
{
|
{
|
||||||
|
try_to_freeze();
|
||||||
if(server->protocolType == IPV6) {
|
if(server->protocolType == IPV6) {
|
||||||
rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
|
rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
|
||||||
} else {
|
} else {
|
||||||
@ -612,6 +613,10 @@ multi_t2_fnd:
|
|||||||
#ifdef CONFIG_CIFS_STATS2
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
mid_entry->when_received = jiffies;
|
mid_entry->when_received = jiffies;
|
||||||
#endif
|
#endif
|
||||||
|
/* so we do not time out requests to server
|
||||||
|
which is still responding (since server could
|
||||||
|
be busy but not dead) */
|
||||||
|
server->lstrp = jiffies;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1266,33 +1271,35 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
|
|||||||
|
|
||||||
read_lock(&GlobalSMBSeslock);
|
read_lock(&GlobalSMBSeslock);
|
||||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||||
cFYI(1, ("Next tcon - "));
|
cFYI(1, ("Next tcon"));
|
||||||
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
||||||
if (tcon->ses) {
|
if (tcon->ses) {
|
||||||
if (tcon->ses->server) {
|
if (tcon->ses->server) {
|
||||||
cFYI(1,
|
cFYI(1,
|
||||||
(" old ip addr: %x == new ip %x ?",
|
("old ip addr: %x == new ip %x ?",
|
||||||
tcon->ses->server->addr.sockAddr.sin_addr.
|
tcon->ses->server->addr.sockAddr.sin_addr.
|
||||||
s_addr, new_target_ip_addr));
|
s_addr, new_target_ip_addr));
|
||||||
if (tcon->ses->server->addr.sockAddr.sin_addr.
|
if (tcon->ses->server->addr.sockAddr.sin_addr.
|
||||||
s_addr == new_target_ip_addr) {
|
s_addr == new_target_ip_addr) {
|
||||||
/* BB lock tcon and server and tcp session and increment use count here? */
|
/* BB lock tcon, server and tcp session and increment use count here? */
|
||||||
/* found a match on the TCP session */
|
/* found a match on the TCP session */
|
||||||
/* BB check if reconnection needed */
|
/* BB check if reconnection needed */
|
||||||
cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
|
cFYI(1,("IP match, old UNC: %s new: %s",
|
||||||
tcon->treeName, uncName));
|
tcon->treeName, uncName));
|
||||||
if (strncmp
|
if (strncmp
|
||||||
(tcon->treeName, uncName,
|
(tcon->treeName, uncName,
|
||||||
MAX_TREE_SIZE) == 0) {
|
MAX_TREE_SIZE) == 0) {
|
||||||
cFYI(1,
|
cFYI(1,
|
||||||
("Matched UNC, old user: %s == new: %s ?",
|
("and old usr: %s new: %s",
|
||||||
tcon->treeName, uncName));
|
tcon->treeName, uncName));
|
||||||
if (strncmp
|
if (strncmp
|
||||||
(tcon->ses->userName,
|
(tcon->ses->userName,
|
||||||
userName,
|
userName,
|
||||||
MAX_USERNAME_SIZE) == 0) {
|
MAX_USERNAME_SIZE) == 0) {
|
||||||
read_unlock(&GlobalSMBSeslock);
|
read_unlock(&GlobalSMBSeslock);
|
||||||
return tcon;/* also matched user (smb session)*/
|
/* matched smb session
|
||||||
|
(user name */
|
||||||
|
return tcon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1969,7 +1976,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cFYI(1,("Negotiate caps 0x%x",(int)cap));
|
cFYI(1,("Negotiate caps 0x%x",(int)cap));
|
||||||
|
#ifdef CONFIG_CIFS_DEBUG2
|
||||||
|
if(cap & CIFS_UNIX_FCNTL_CAP)
|
||||||
|
cFYI(1,("FCNTL cap"));
|
||||||
|
if(cap & CIFS_UNIX_EXTATTR_CAP)
|
||||||
|
cFYI(1,("EXTATTR cap"));
|
||||||
|
if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
|
||||||
|
cFYI(1,("POSIX path cap"));
|
||||||
|
if(cap & CIFS_UNIX_XATTR_CAP)
|
||||||
|
cFYI(1,("XATTR cap"));
|
||||||
|
if(cap & CIFS_UNIX_POSIX_ACL_CAP)
|
||||||
|
cFYI(1,("POSIX ACL cap"));
|
||||||
|
#endif /* CIFS_DEBUG2 */
|
||||||
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
|
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
|
||||||
cFYI(1,("setting capabilities failed"));
|
cFYI(1,("setting capabilities failed"));
|
||||||
}
|
}
|
||||||
|
@ -267,6 +267,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||||||
pCifsFile->invalidHandle = FALSE;
|
pCifsFile->invalidHandle = FALSE;
|
||||||
pCifsFile->closePend = FALSE;
|
pCifsFile->closePend = FALSE;
|
||||||
init_MUTEX(&pCifsFile->fh_sem);
|
init_MUTEX(&pCifsFile->fh_sem);
|
||||||
|
init_MUTEX(&pCifsFile->lock_sem);
|
||||||
|
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||||
|
atomic_set(&pCifsFile->wrtPending,0);
|
||||||
|
|
||||||
/* set the following in open now
|
/* set the following in open now
|
||||||
pCifsFile->pfile = file; */
|
pCifsFile->pfile = file; */
|
||||||
write_lock(&GlobalSMBSeslock);
|
write_lock(&GlobalSMBSeslock);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) International Business Machines Corp., 2002,2003
|
* Copyright (C) International Business Machines Corp., 2002,2003
|
||||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||||
|
* Jeremy Allison (jra@samba.org)
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License as published
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private(
|
|||||||
private_data->netfid = netfid;
|
private_data->netfid = netfid;
|
||||||
private_data->pid = current->tgid;
|
private_data->pid = current->tgid;
|
||||||
init_MUTEX(&private_data->fh_sem);
|
init_MUTEX(&private_data->fh_sem);
|
||||||
|
init_MUTEX(&private_data->lock_sem);
|
||||||
|
INIT_LIST_HEAD(&private_data->llist);
|
||||||
private_data->pfile = file; /* needed for writepage */
|
private_data->pfile = file; /* needed for writepage */
|
||||||
private_data->pInode = inode;
|
private_data->pInode = inode;
|
||||||
private_data->invalidHandle = FALSE;
|
private_data->invalidHandle = FALSE;
|
||||||
@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||||||
cifs_sb = CIFS_SB(inode->i_sb);
|
cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
pTcon = cifs_sb->tcon;
|
pTcon = cifs_sb->tcon;
|
||||||
if (pSMBFile) {
|
if (pSMBFile) {
|
||||||
|
struct cifsLockInfo *li, *tmp;
|
||||||
|
|
||||||
pSMBFile->closePend = TRUE;
|
pSMBFile->closePend = TRUE;
|
||||||
if (pTcon) {
|
if (pTcon) {
|
||||||
/* no sense reconnecting to close a file that is
|
/* no sense reconnecting to close a file that is
|
||||||
@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||||||
pSMBFile->netfid);
|
pSMBFile->netfid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete any outstanding lock records.
|
||||||
|
We'll lose them when the file is closed anyway. */
|
||||||
|
down(&pSMBFile->lock_sem);
|
||||||
|
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
|
||||||
|
list_del(&li->llist);
|
||||||
|
kfree(li);
|
||||||
|
}
|
||||||
|
up(&pSMBFile->lock_sem);
|
||||||
|
|
||||||
write_lock(&GlobalSMBSeslock);
|
write_lock(&GlobalSMBSeslock);
|
||||||
list_del(&pSMBFile->flist);
|
list_del(&pSMBFile->flist);
|
||||||
list_del(&pSMBFile->tlist);
|
list_del(&pSMBFile->tlist);
|
||||||
@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
|
||||||
|
__u64 offset, __u8 lockType)
|
||||||
|
{
|
||||||
|
struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
|
||||||
|
if (li == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
li->offset = offset;
|
||||||
|
li->length = len;
|
||||||
|
li->type = lockType;
|
||||||
|
down(&fid->lock_sem);
|
||||||
|
list_add(&li->llist, &fid->llist);
|
||||||
|
up(&fid->lock_sem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||||
{
|
{
|
||||||
int rc, xid;
|
int rc, xid;
|
||||||
@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||||||
struct cifsTconInfo *pTcon;
|
struct cifsTconInfo *pTcon;
|
||||||
__u16 netfid;
|
__u16 netfid;
|
||||||
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
|
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
|
||||||
|
int posix_locking;
|
||||||
|
|
||||||
length = 1 + pfLock->fl_end - pfLock->fl_start;
|
length = 1 + pfLock->fl_end - pfLock->fl_start;
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
@ -639,15 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||||||
}
|
}
|
||||||
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
|
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
|
||||||
|
|
||||||
|
posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
||||||
|
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
|
||||||
|
|
||||||
/* BB add code here to normalize offset and length to
|
/* BB add code here to normalize offset and length to
|
||||||
account for negative length which we can not accept over the
|
account for negative length which we can not accept over the
|
||||||
wire */
|
wire */
|
||||||
if (IS_GETLK(cmd)) {
|
if (IS_GETLK(cmd)) {
|
||||||
if(experimEnabled &&
|
if(posix_locking) {
|
||||||
(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
|
||||||
(CIFS_UNIX_FCNTL_CAP &
|
|
||||||
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
|
|
||||||
int posix_lock_type;
|
int posix_lock_type;
|
||||||
if(lockType & LOCKING_ANDX_SHARED_LOCK)
|
if(lockType & LOCKING_ANDX_SHARED_LOCK)
|
||||||
posix_lock_type = CIFS_RDLCK;
|
posix_lock_type = CIFS_RDLCK;
|
||||||
@ -683,10 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||||||
FreeXid(xid);
|
FreeXid(xid);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if (experimEnabled &&
|
|
||||||
(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
if (!numLock && !numUnlock) {
|
||||||
(CIFS_UNIX_FCNTL_CAP &
|
/* if no lock or unlock then nothing
|
||||||
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
|
to do since we do not know what it is */
|
||||||
|
FreeXid(xid);
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posix_locking) {
|
||||||
int posix_lock_type;
|
int posix_lock_type;
|
||||||
if(lockType & LOCKING_ANDX_SHARED_LOCK)
|
if(lockType & LOCKING_ANDX_SHARED_LOCK)
|
||||||
posix_lock_type = CIFS_RDLCK;
|
posix_lock_type = CIFS_RDLCK;
|
||||||
@ -695,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||||||
|
|
||||||
if(numUnlock == 1)
|
if(numUnlock == 1)
|
||||||
posix_lock_type = CIFS_UNLCK;
|
posix_lock_type = CIFS_UNLCK;
|
||||||
else if(numLock == 0) {
|
|
||||||
/* if no lock or unlock then nothing
|
|
||||||
to do since we do not know what it is */
|
|
||||||
FreeXid(xid);
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
|
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
|
||||||
length, pfLock,
|
length, pfLock,
|
||||||
posix_lock_type, wait_flag);
|
posix_lock_type, wait_flag);
|
||||||
} else
|
} else {
|
||||||
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
|
struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
|
||||||
numUnlock, numLock, lockType, wait_flag);
|
|
||||||
|
if (numLock) {
|
||||||
|
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
|
||||||
|
0, numLock, lockType, wait_flag);
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
/* For Windows locks we must store them. */
|
||||||
|
rc = store_file_lock(fid, length,
|
||||||
|
pfLock->fl_start, lockType);
|
||||||
|
}
|
||||||
|
} else if (numUnlock) {
|
||||||
|
/* For each stored lock that this unlock overlaps
|
||||||
|
completely, unlock it. */
|
||||||
|
int stored_rc = 0;
|
||||||
|
struct cifsLockInfo *li, *tmp;
|
||||||
|
|
||||||
|
down(&fid->lock_sem);
|
||||||
|
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
|
||||||
|
if (pfLock->fl_start <= li->offset &&
|
||||||
|
length >= li->length) {
|
||||||
|
stored_rc = CIFSSMBLock(xid, pTcon, netfid,
|
||||||
|
li->length, li->offset,
|
||||||
|
1, 0, li->type, FALSE);
|
||||||
|
if (stored_rc)
|
||||||
|
rc = stored_rc;
|
||||||
|
|
||||||
|
list_del(&li->llist);
|
||||||
|
kfree(li);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
up(&fid->lock_sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pfLock->fl_flags & FL_POSIX)
|
if (pfLock->fl_flags & FL_POSIX)
|
||||||
posix_lock_file_wait(file, pfLock);
|
posix_lock_file_wait(file, pfLock);
|
||||||
FreeXid(xid);
|
FreeXid(xid);
|
||||||
|
@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
|
|||||||
{ERRinvlevel,-EOPNOTSUPP},
|
{ERRinvlevel,-EOPNOTSUPP},
|
||||||
{ERRdirnotempty, -ENOTEMPTY},
|
{ERRdirnotempty, -ENOTEMPTY},
|
||||||
{ERRnotlocked, -ENOLCK},
|
{ERRnotlocked, -ENOLCK},
|
||||||
|
{ERRcancelviolation, -ENOLCK},
|
||||||
{ERRalreadyexists, -EEXIST},
|
{ERRalreadyexists, -EEXIST},
|
||||||
{ERRmoredata, -EOVERFLOW},
|
{ERRmoredata, -EOVERFLOW},
|
||||||
{ERReasnotsupported,-EOPNOTSUPP},
|
{ERReasnotsupported,-EOPNOTSUPP},
|
||||||
|
@ -556,7 +556,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
|
|||||||
FIND_FILE_STANDARD_INFO * pFindData =
|
FIND_FILE_STANDARD_INFO * pFindData =
|
||||||
(FIND_FILE_STANDARD_INFO *)current_entry;
|
(FIND_FILE_STANDARD_INFO *)current_entry;
|
||||||
filename = &pFindData->FileName[0];
|
filename = &pFindData->FileName[0];
|
||||||
len = le32_to_cpu(pFindData->FileNameLength);
|
len = pFindData->FileNameLength;
|
||||||
} else {
|
} else {
|
||||||
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
|
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||||||
|
|
||||||
/* no capabilities flags in old lanman negotiation */
|
/* no capabilities flags in old lanman negotiation */
|
||||||
|
|
||||||
pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE;
|
pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
|
||||||
/* BB calculate hash with password */
|
/* BB calculate hash with password */
|
||||||
/* and copy into bcc */
|
/* and copy into bcc */
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
#define ERRinvlevel 124
|
#define ERRinvlevel 124
|
||||||
#define ERRdirnotempty 145
|
#define ERRdirnotempty 145
|
||||||
#define ERRnotlocked 158
|
#define ERRnotlocked 158
|
||||||
|
#define ERRcancelviolation 173
|
||||||
#define ERRalreadyexists 183
|
#define ERRalreadyexists 183
|
||||||
#define ERRbadpipe 230
|
#define ERRbadpipe 230
|
||||||
#define ERRpipebusy 231
|
#define ERRpipebusy 231
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) International Business Machines Corp., 2002,2005
|
* Copyright (C) International Business Machines Corp., 2002,2005
|
||||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||||
|
* Jeremy Allison (jra@samba.org) 2006.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or modify
|
* This library is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License as published
|
* it under the terms of the GNU Lesser General Public License as published
|
||||||
@ -36,7 +37,7 @@ extern mempool_t *cifs_mid_poolp;
|
|||||||
extern kmem_cache_t *cifs_oplock_cachep;
|
extern kmem_cache_t *cifs_oplock_cachep;
|
||||||
|
|
||||||
static struct mid_q_entry *
|
static struct mid_q_entry *
|
||||||
AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
||||||
{
|
{
|
||||||
struct mid_q_entry *temp;
|
struct mid_q_entry *temp;
|
||||||
|
|
||||||
@ -203,6 +204,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
|
|||||||
rc = 0;
|
rc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Don't want to modify the buffer as a
|
||||||
|
side effect of this call. */
|
||||||
|
smb_buffer->smb_buf_length = smb_buf_length;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +222,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
|||||||
unsigned int len = iov[0].iov_len;
|
unsigned int len = iov[0].iov_len;
|
||||||
unsigned int total_len;
|
unsigned int total_len;
|
||||||
int first_vec = 0;
|
int first_vec = 0;
|
||||||
|
unsigned int smb_buf_length = smb_buffer->smb_buf_length;
|
||||||
|
|
||||||
if(ssocket == NULL)
|
if(ssocket == NULL)
|
||||||
return -ENOTSOCK; /* BB eventually add reconnect code here */
|
return -ENOTSOCK; /* BB eventually add reconnect code here */
|
||||||
@ -293,9 +299,123 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
|||||||
} else
|
} else
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
|
/* Don't want to modify the buffer as a
|
||||||
|
side effect of this call. */
|
||||||
|
smb_buffer->smb_buf_length = smb_buf_length;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
|
||||||
|
{
|
||||||
|
if(long_op == -1) {
|
||||||
|
/* oplock breaks must not be held up */
|
||||||
|
atomic_inc(&ses->server->inFlight);
|
||||||
|
} else {
|
||||||
|
spin_lock(&GlobalMid_Lock);
|
||||||
|
while(1) {
|
||||||
|
if(atomic_read(&ses->server->inFlight) >=
|
||||||
|
cifs_max_pending){
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
|
atomic_inc(&ses->server->num_waiters);
|
||||||
|
#endif
|
||||||
|
wait_event(ses->server->request_q,
|
||||||
|
atomic_read(&ses->server->inFlight)
|
||||||
|
< cifs_max_pending);
|
||||||
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
|
atomic_dec(&ses->server->num_waiters);
|
||||||
|
#endif
|
||||||
|
spin_lock(&GlobalMid_Lock);
|
||||||
|
} else {
|
||||||
|
if(ses->server->tcpStatus == CifsExiting) {
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* can not count locking commands against total since
|
||||||
|
they are allowed to block on server */
|
||||||
|
|
||||||
|
/* update # of requests on the wire to server */
|
||||||
|
if (long_op < 3)
|
||||||
|
atomic_inc(&ses->server->inFlight);
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
|
||||||
|
struct mid_q_entry **ppmidQ)
|
||||||
|
{
|
||||||
|
if (ses->server->tcpStatus == CifsExiting) {
|
||||||
|
return -ENOENT;
|
||||||
|
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||||
|
cFYI(1,("tcp session dead - return to caller to retry"));
|
||||||
|
return -EAGAIN;
|
||||||
|
} else if (ses->status != CifsGood) {
|
||||||
|
/* check if SMB session is bad because we are setting it up */
|
||||||
|
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
||||||
|
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
||||||
|
return -EAGAIN;
|
||||||
|
} /* else ok - we are setting up session */
|
||||||
|
}
|
||||||
|
*ppmidQ = AllocMidQEntry(in_buf, ses);
|
||||||
|
if (*ppmidQ == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wait_for_response(struct cifsSesInfo *ses,
|
||||||
|
struct mid_q_entry *midQ,
|
||||||
|
unsigned long timeout,
|
||||||
|
unsigned long time_to_wait)
|
||||||
|
{
|
||||||
|
unsigned long curr_timeout;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
curr_timeout = timeout + jiffies;
|
||||||
|
wait_event(ses->server->response_q,
|
||||||
|
(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
|
||||||
|
time_after(jiffies, curr_timeout) ||
|
||||||
|
((ses->server->tcpStatus != CifsGood) &&
|
||||||
|
(ses->server->tcpStatus != CifsNew)));
|
||||||
|
|
||||||
|
if (time_after(jiffies, curr_timeout) &&
|
||||||
|
(midQ->midState == MID_REQUEST_SUBMITTED) &&
|
||||||
|
((ses->server->tcpStatus == CifsGood) ||
|
||||||
|
(ses->server->tcpStatus == CifsNew))) {
|
||||||
|
|
||||||
|
unsigned long lrt;
|
||||||
|
|
||||||
|
/* We timed out. Is the server still
|
||||||
|
sending replies ? */
|
||||||
|
spin_lock(&GlobalMid_Lock);
|
||||||
|
lrt = ses->server->lstrp;
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
|
||||||
|
/* Calculate time_to_wait past last receive time.
|
||||||
|
Although we prefer not to time out if the
|
||||||
|
server is still responding - we will time
|
||||||
|
out if the server takes more than 15 (or 45
|
||||||
|
or 180) seconds to respond to this request
|
||||||
|
and has not responded to any request from
|
||||||
|
other threads on the client within 10 seconds */
|
||||||
|
lrt += time_to_wait;
|
||||||
|
if (time_after(jiffies, lrt)) {
|
||||||
|
/* No replies for time_to_wait. */
|
||||||
|
cERROR(1,("server not responding"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
|
struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
|
||||||
@ -323,75 +443,27 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
/* Ensure that we do not send more than 50 overlapping requests
|
/* Ensure that we do not send more than 50 overlapping requests
|
||||||
to the same server. We may make this configurable later or
|
to the same server. We may make this configurable later or
|
||||||
use ses->maxReq */
|
use ses->maxReq */
|
||||||
if(long_op == -1) {
|
|
||||||
/* oplock breaks must not be held up */
|
|
||||||
atomic_inc(&ses->server->inFlight);
|
|
||||||
} else {
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
|
||||||
while(1) {
|
|
||||||
if(atomic_read(&ses->server->inFlight) >=
|
|
||||||
cifs_max_pending){
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
|
||||||
atomic_inc(&ses->server->num_waiters);
|
|
||||||
#endif
|
|
||||||
wait_event(ses->server->request_q,
|
|
||||||
atomic_read(&ses->server->inFlight)
|
|
||||||
< cifs_max_pending);
|
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
|
||||||
atomic_dec(&ses->server->num_waiters);
|
|
||||||
#endif
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
|
||||||
} else {
|
|
||||||
if(ses->server->tcpStatus == CifsExiting) {
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
cifs_small_buf_release(in_buf);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* can not count locking commands against total since
|
rc = wait_for_free_request(ses, long_op);
|
||||||
they are allowed to block on server */
|
if (rc) {
|
||||||
|
cifs_small_buf_release(in_buf);
|
||||||
if(long_op < 3) {
|
return rc;
|
||||||
/* update # of requests on the wire to server */
|
|
||||||
atomic_inc(&ses->server->inFlight);
|
|
||||||
}
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure that we sign in the same order that we send on this socket
|
/* make sure that we sign in the same order that we send on this socket
|
||||||
and avoid races inside tcp sendmsg code that could cause corruption
|
and avoid races inside tcp sendmsg code that could cause corruption
|
||||||
of smb data */
|
of smb data */
|
||||||
|
|
||||||
down(&ses->server->tcpSem);
|
down(&ses->server->tcpSem);
|
||||||
|
|
||||||
if (ses->server->tcpStatus == CifsExiting) {
|
rc = allocate_mid(ses, in_buf, &midQ);
|
||||||
rc = -ENOENT;
|
if (rc) {
|
||||||
goto out_unlock2;
|
|
||||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
|
||||||
cFYI(1,("tcp session dead - return to caller to retry"));
|
|
||||||
rc = -EAGAIN;
|
|
||||||
goto out_unlock2;
|
|
||||||
} else if (ses->status != CifsGood) {
|
|
||||||
/* check if SMB session is bad because we are setting it up */
|
|
||||||
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
|
||||||
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
|
||||||
rc = -EAGAIN;
|
|
||||||
goto out_unlock2;
|
|
||||||
} /* else ok - we are setting up session */
|
|
||||||
}
|
|
||||||
midQ = AllocMidQEntry(in_buf, ses);
|
|
||||||
if (midQ == NULL) {
|
|
||||||
up(&ses->server->tcpSem);
|
up(&ses->server->tcpSem);
|
||||||
cifs_small_buf_release(in_buf);
|
cifs_small_buf_release(in_buf);
|
||||||
/* If not lock req, update # of requests on wire to server */
|
/* Update # of requests on wire to server */
|
||||||
if(long_op < 3) {
|
atomic_dec(&ses->server->inFlight);
|
||||||
atomic_dec(&ses->server->inFlight);
|
wake_up(&ses->server->request_q);
|
||||||
wake_up(&ses->server->request_q);
|
return rc;
|
||||||
}
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
|
rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
|
||||||
@ -406,32 +478,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
atomic_dec(&ses->server->inSend);
|
atomic_dec(&ses->server->inSend);
|
||||||
midQ->when_sent = jiffies;
|
midQ->when_sent = jiffies;
|
||||||
#endif
|
#endif
|
||||||
if(rc < 0) {
|
|
||||||
DeleteMidQEntry(midQ);
|
up(&ses->server->tcpSem);
|
||||||
up(&ses->server->tcpSem);
|
cifs_small_buf_release(in_buf);
|
||||||
cifs_small_buf_release(in_buf);
|
|
||||||
/* If not lock req, update # of requests on wire to server */
|
if(rc < 0)
|
||||||
if(long_op < 3) {
|
goto out;
|
||||||
atomic_dec(&ses->server->inFlight);
|
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
} else {
|
|
||||||
up(&ses->server->tcpSem);
|
|
||||||
cifs_small_buf_release(in_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (long_op == -1)
|
if (long_op == -1)
|
||||||
goto cifs_no_response_exit2;
|
goto out;
|
||||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||||
timeout = 180 * HZ;
|
timeout = 180 * HZ;
|
||||||
else if (long_op == 1)
|
else if (long_op == 1)
|
||||||
timeout = 45 * HZ; /* should be greater than
|
timeout = 45 * HZ; /* should be greater than
|
||||||
servers oplock break timeout (about 43 seconds) */
|
servers oplock break timeout (about 43 seconds) */
|
||||||
else if (long_op > 2) {
|
else
|
||||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
|
||||||
} else
|
|
||||||
timeout = 15 * HZ;
|
timeout = 15 * HZ;
|
||||||
|
|
||||||
/* wait for 15 seconds or until woken up due to response arriving or
|
/* wait for 15 seconds or until woken up due to response arriving or
|
||||||
due to last connection to this server being unmounted */
|
due to last connection to this server being unmounted */
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
@ -441,19 +504,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* No user interrupts in wait - wreaks havoc with performance */
|
/* No user interrupts in wait - wreaks havoc with performance */
|
||||||
if(timeout != MAX_SCHEDULE_TIMEOUT) {
|
wait_for_response(ses, midQ, timeout, 10 * HZ);
|
||||||
timeout += jiffies;
|
|
||||||
wait_event(ses->server->response_q,
|
|
||||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
|
||||||
time_after(jiffies, timeout) ||
|
|
||||||
((ses->server->tcpStatus != CifsGood) &&
|
|
||||||
(ses->server->tcpStatus != CifsNew)));
|
|
||||||
} else {
|
|
||||||
wait_event(ses->server->response_q,
|
|
||||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
|
||||||
((ses->server->tcpStatus != CifsGood) &&
|
|
||||||
(ses->server->tcpStatus != CifsNew)));
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (midQ->resp_buf) {
|
if (midQ->resp_buf) {
|
||||||
@ -481,11 +532,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
}
|
}
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
DeleteMidQEntry(midQ);
|
DeleteMidQEntry(midQ);
|
||||||
/* If not lock req, update # of requests on wire to server */
|
/* Update # of requests on wire to server */
|
||||||
if(long_op < 3) {
|
atomic_dec(&ses->server->inFlight);
|
||||||
atomic_dec(&ses->server->inFlight);
|
wake_up(&ses->server->request_q);
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,24 +585,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
cFYI(1,("Bad MID state?"));
|
cFYI(1,("Bad MID state?"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cifs_no_response_exit2:
|
|
||||||
|
out:
|
||||||
|
|
||||||
DeleteMidQEntry(midQ);
|
DeleteMidQEntry(midQ);
|
||||||
|
atomic_dec(&ses->server->inFlight);
|
||||||
if(long_op < 3) {
|
wake_up(&ses->server->request_q);
|
||||||
atomic_dec(&ses->server->inFlight);
|
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
out_unlock2:
|
|
||||||
up(&ses->server->tcpSem);
|
|
||||||
cifs_small_buf_release(in_buf);
|
|
||||||
/* If not lock req, update # of requests on wire to server */
|
|
||||||
if(long_op < 3) {
|
|
||||||
atomic_dec(&ses->server->inFlight);
|
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -583,85 +620,34 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
/* Ensure that we do not send more than 50 overlapping requests
|
/* Ensure that we do not send more than 50 overlapping requests
|
||||||
to the same server. We may make this configurable later or
|
to the same server. We may make this configurable later or
|
||||||
use ses->maxReq */
|
use ses->maxReq */
|
||||||
if(long_op == -1) {
|
|
||||||
/* oplock breaks must not be held up */
|
|
||||||
atomic_inc(&ses->server->inFlight);
|
|
||||||
} else {
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
|
||||||
while(1) {
|
|
||||||
if(atomic_read(&ses->server->inFlight) >=
|
|
||||||
cifs_max_pending){
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
|
||||||
atomic_inc(&ses->server->num_waiters);
|
|
||||||
#endif
|
|
||||||
wait_event(ses->server->request_q,
|
|
||||||
atomic_read(&ses->server->inFlight)
|
|
||||||
< cifs_max_pending);
|
|
||||||
#ifdef CONFIG_CIFS_STATS2
|
|
||||||
atomic_dec(&ses->server->num_waiters);
|
|
||||||
#endif
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
|
||||||
} else {
|
|
||||||
if(ses->server->tcpStatus == CifsExiting) {
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* can not count locking commands against total since
|
rc = wait_for_free_request(ses, long_op);
|
||||||
they are allowed to block on server */
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
if(long_op < 3) {
|
|
||||||
/* update # of requests on the wire to server */
|
|
||||||
atomic_inc(&ses->server->inFlight);
|
|
||||||
}
|
|
||||||
spin_unlock(&GlobalMid_Lock);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* make sure that we sign in the same order that we send on this socket
|
/* make sure that we sign in the same order that we send on this socket
|
||||||
and avoid races inside tcp sendmsg code that could cause corruption
|
and avoid races inside tcp sendmsg code that could cause corruption
|
||||||
of smb data */
|
of smb data */
|
||||||
|
|
||||||
down(&ses->server->tcpSem);
|
down(&ses->server->tcpSem);
|
||||||
|
|
||||||
if (ses->server->tcpStatus == CifsExiting) {
|
rc = allocate_mid(ses, in_buf, &midQ);
|
||||||
rc = -ENOENT;
|
if (rc) {
|
||||||
goto out_unlock;
|
|
||||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
|
||||||
cFYI(1,("tcp session dead - return to caller to retry"));
|
|
||||||
rc = -EAGAIN;
|
|
||||||
goto out_unlock;
|
|
||||||
} else if (ses->status != CifsGood) {
|
|
||||||
/* check if SMB session is bad because we are setting it up */
|
|
||||||
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
|
||||||
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
|
||||||
rc = -EAGAIN;
|
|
||||||
goto out_unlock;
|
|
||||||
} /* else ok - we are setting up session */
|
|
||||||
}
|
|
||||||
midQ = AllocMidQEntry(in_buf, ses);
|
|
||||||
if (midQ == NULL) {
|
|
||||||
up(&ses->server->tcpSem);
|
up(&ses->server->tcpSem);
|
||||||
/* If not lock req, update # of requests on wire to server */
|
/* Update # of requests on wire to server */
|
||||||
if(long_op < 3) {
|
atomic_dec(&ses->server->inFlight);
|
||||||
atomic_dec(&ses->server->inFlight);
|
wake_up(&ses->server->request_q);
|
||||||
wake_up(&ses->server->request_q);
|
return rc;
|
||||||
}
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||||
up(&ses->server->tcpSem);
|
|
||||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||||
in_buf->smb_buf_length));
|
in_buf->smb_buf_length));
|
||||||
DeleteMidQEntry(midQ);
|
DeleteMidQEntry(midQ);
|
||||||
/* If not lock req, update # of requests on wire to server */
|
up(&ses->server->tcpSem);
|
||||||
if(long_op < 3) {
|
/* Update # of requests on wire to server */
|
||||||
atomic_dec(&ses->server->inFlight);
|
atomic_dec(&ses->server->inFlight);
|
||||||
wake_up(&ses->server->request_q);
|
wake_up(&ses->server->request_q);
|
||||||
}
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,27 +663,19 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
atomic_dec(&ses->server->inSend);
|
atomic_dec(&ses->server->inSend);
|
||||||
midQ->when_sent = jiffies;
|
midQ->when_sent = jiffies;
|
||||||
#endif
|
#endif
|
||||||
if(rc < 0) {
|
up(&ses->server->tcpSem);
|
||||||
DeleteMidQEntry(midQ);
|
|
||||||
up(&ses->server->tcpSem);
|
if(rc < 0)
|
||||||
/* If not lock req, update # of requests on wire to server */
|
goto out;
|
||||||
if(long_op < 3) {
|
|
||||||
atomic_dec(&ses->server->inFlight);
|
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
} else
|
|
||||||
up(&ses->server->tcpSem);
|
|
||||||
if (long_op == -1)
|
if (long_op == -1)
|
||||||
goto cifs_no_response_exit;
|
goto out;
|
||||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||||
timeout = 180 * HZ;
|
timeout = 180 * HZ;
|
||||||
else if (long_op == 1)
|
else if (long_op == 1)
|
||||||
timeout = 45 * HZ; /* should be greater than
|
timeout = 45 * HZ; /* should be greater than
|
||||||
servers oplock break timeout (about 43 seconds) */
|
servers oplock break timeout (about 43 seconds) */
|
||||||
else if (long_op > 2) {
|
else
|
||||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
|
||||||
} else
|
|
||||||
timeout = 15 * HZ;
|
timeout = 15 * HZ;
|
||||||
/* wait for 15 seconds or until woken up due to response arriving or
|
/* wait for 15 seconds or until woken up due to response arriving or
|
||||||
due to last connection to this server being unmounted */
|
due to last connection to this server being unmounted */
|
||||||
@ -708,19 +686,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* No user interrupts in wait - wreaks havoc with performance */
|
/* No user interrupts in wait - wreaks havoc with performance */
|
||||||
if(timeout != MAX_SCHEDULE_TIMEOUT) {
|
wait_for_response(ses, midQ, timeout, 10 * HZ);
|
||||||
timeout += jiffies;
|
|
||||||
wait_event(ses->server->response_q,
|
|
||||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
|
||||||
time_after(jiffies, timeout) ||
|
|
||||||
((ses->server->tcpStatus != CifsGood) &&
|
|
||||||
(ses->server->tcpStatus != CifsNew)));
|
|
||||||
} else {
|
|
||||||
wait_event(ses->server->response_q,
|
|
||||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
|
||||||
((ses->server->tcpStatus != CifsGood) &&
|
|
||||||
(ses->server->tcpStatus != CifsNew)));
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (midQ->resp_buf) {
|
if (midQ->resp_buf) {
|
||||||
@ -748,11 +714,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
}
|
}
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
DeleteMidQEntry(midQ);
|
DeleteMidQEntry(midQ);
|
||||||
/* If not lock req, update # of requests on wire to server */
|
/* Update # of requests on wire to server */
|
||||||
if(long_op < 3) {
|
atomic_dec(&ses->server->inFlight);
|
||||||
atomic_dec(&ses->server->inFlight);
|
wake_up(&ses->server->request_q);
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -799,23 +763,253 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||||||
cERROR(1,("Bad MID state?"));
|
cERROR(1,("Bad MID state?"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cifs_no_response_exit:
|
|
||||||
|
out:
|
||||||
|
|
||||||
DeleteMidQEntry(midQ);
|
DeleteMidQEntry(midQ);
|
||||||
|
atomic_dec(&ses->server->inFlight);
|
||||||
if(long_op < 3) {
|
wake_up(&ses->server->request_q);
|
||||||
atomic_dec(&ses->server->inFlight);
|
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
out_unlock:
|
|
||||||
up(&ses->server->tcpSem);
|
|
||||||
/* If not lock req, update # of requests on wire to server */
|
|
||||||
if(long_op < 3) {
|
|
||||||
atomic_dec(&ses->server->inFlight);
|
|
||||||
wake_up(&ses->server->request_q);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
|
||||||
|
struct mid_q_entry *midQ)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
struct cifsSesInfo *ses = tcon->ses;
|
||||||
|
__u16 mid = in_buf->Mid;
|
||||||
|
|
||||||
|
header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
|
||||||
|
in_buf->Mid = mid;
|
||||||
|
down(&ses->server->tcpSem);
|
||||||
|
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||||
|
if (rc) {
|
||||||
|
up(&ses->server->tcpSem);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||||
|
(struct sockaddr *) &(ses->server->addr.sockAddr));
|
||||||
|
up(&ses->server->tcpSem);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
|
||||||
|
blocking lock to return. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||||
|
struct smb_hdr *in_buf,
|
||||||
|
struct smb_hdr *out_buf)
|
||||||
|
{
|
||||||
|
int bytes_returned;
|
||||||
|
struct cifsSesInfo *ses = tcon->ses;
|
||||||
|
LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
|
||||||
|
|
||||||
|
/* We just modify the current in_buf to change
|
||||||
|
the type of lock from LOCKING_ANDX_SHARED_LOCK
|
||||||
|
or LOCKING_ANDX_EXCLUSIVE_LOCK to
|
||||||
|
LOCKING_ANDX_CANCEL_LOCK. */
|
||||||
|
|
||||||
|
pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
|
||||||
|
pSMB->Timeout = 0;
|
||||||
|
pSMB->hdr.Mid = GetNextMid(ses->server);
|
||||||
|
|
||||||
|
return SendReceive(xid, ses, in_buf, out_buf,
|
||||||
|
&bytes_returned, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||||
|
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
|
||||||
|
int *pbytes_returned)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
int rstart = 0;
|
||||||
|
unsigned int receive_len;
|
||||||
|
struct mid_q_entry *midQ;
|
||||||
|
struct cifsSesInfo *ses;
|
||||||
|
|
||||||
|
if (tcon == NULL || tcon->ses == NULL) {
|
||||||
|
cERROR(1,("Null smb session"));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
ses = tcon->ses;
|
||||||
|
|
||||||
|
if(ses->server == NULL) {
|
||||||
|
cERROR(1,("Null tcp session"));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ses->server->tcpStatus == CifsExiting)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
/* Ensure that we do not send more than 50 overlapping requests
|
||||||
|
to the same server. We may make this configurable later or
|
||||||
|
use ses->maxReq */
|
||||||
|
|
||||||
|
rc = wait_for_free_request(ses, 3);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* make sure that we sign in the same order that we send on this socket
|
||||||
|
and avoid races inside tcp sendmsg code that could cause corruption
|
||||||
|
of smb data */
|
||||||
|
|
||||||
|
down(&ses->server->tcpSem);
|
||||||
|
|
||||||
|
rc = allocate_mid(ses, in_buf, &midQ);
|
||||||
|
if (rc) {
|
||||||
|
up(&ses->server->tcpSem);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||||
|
up(&ses->server->tcpSem);
|
||||||
|
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||||
|
in_buf->smb_buf_length));
|
||||||
|
DeleteMidQEntry(midQ);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||||
|
|
||||||
|
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||||
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
|
atomic_inc(&ses->server->inSend);
|
||||||
|
#endif
|
||||||
|
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||||
|
(struct sockaddr *) &(ses->server->addr.sockAddr));
|
||||||
|
#ifdef CONFIG_CIFS_STATS2
|
||||||
|
atomic_dec(&ses->server->inSend);
|
||||||
|
midQ->when_sent = jiffies;
|
||||||
|
#endif
|
||||||
|
up(&ses->server->tcpSem);
|
||||||
|
|
||||||
|
if(rc < 0) {
|
||||||
|
DeleteMidQEntry(midQ);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for a reply - allow signals to interrupt. */
|
||||||
|
rc = wait_event_interruptible(ses->server->response_q,
|
||||||
|
(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
|
||||||
|
((ses->server->tcpStatus != CifsGood) &&
|
||||||
|
(ses->server->tcpStatus != CifsNew)));
|
||||||
|
|
||||||
|
/* Were we interrupted by a signal ? */
|
||||||
|
if ((rc == -ERESTARTSYS) &&
|
||||||
|
(midQ->midState == MID_REQUEST_SUBMITTED) &&
|
||||||
|
((ses->server->tcpStatus == CifsGood) ||
|
||||||
|
(ses->server->tcpStatus == CifsNew))) {
|
||||||
|
|
||||||
|
if (in_buf->Command == SMB_COM_TRANSACTION2) {
|
||||||
|
/* POSIX lock. We send a NT_CANCEL SMB to cause the
|
||||||
|
blocking lock to return. */
|
||||||
|
|
||||||
|
rc = send_nt_cancel(tcon, in_buf, midQ);
|
||||||
|
if (rc) {
|
||||||
|
DeleteMidQEntry(midQ);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
|
||||||
|
to cause the blocking lock to return. */
|
||||||
|
|
||||||
|
rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
|
||||||
|
|
||||||
|
/* If we get -ENOLCK back the lock may have
|
||||||
|
already been removed. Don't exit in this case. */
|
||||||
|
if (rc && rc != -ENOLCK) {
|
||||||
|
DeleteMidQEntry(midQ);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait 5 seconds for the response. */
|
||||||
|
if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) {
|
||||||
|
/* We got the response - restart system call. */
|
||||||
|
rstart = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock(&GlobalMid_Lock);
|
||||||
|
if (midQ->resp_buf) {
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
receive_len = midQ->resp_buf->smb_buf_length;
|
||||||
|
} else {
|
||||||
|
cERROR(1,("No response for cmd %d mid %d",
|
||||||
|
midQ->command, midQ->mid));
|
||||||
|
if(midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||||
|
if(ses->server->tcpStatus == CifsExiting)
|
||||||
|
rc = -EHOSTDOWN;
|
||||||
|
else {
|
||||||
|
ses->server->tcpStatus = CifsNeedReconnect;
|
||||||
|
midQ->midState = MID_RETRY_NEEDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != -EHOSTDOWN) {
|
||||||
|
if(midQ->midState == MID_RETRY_NEEDED) {
|
||||||
|
rc = -EAGAIN;
|
||||||
|
cFYI(1,("marking request for retry"));
|
||||||
|
} else {
|
||||||
|
rc = -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
DeleteMidQEntry(midQ);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||||
|
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||||
|
receive_len, xid));
|
||||||
|
rc = -EIO;
|
||||||
|
} else { /* rcvd frame is ok */
|
||||||
|
|
||||||
|
if (midQ->resp_buf && out_buf
|
||||||
|
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||||
|
out_buf->smb_buf_length = receive_len;
|
||||||
|
memcpy((char *)out_buf + 4,
|
||||||
|
(char *)midQ->resp_buf + 4,
|
||||||
|
receive_len);
|
||||||
|
|
||||||
|
dump_smb(out_buf, 92);
|
||||||
|
/* convert the length into a more usable form */
|
||||||
|
if((receive_len > 24) &&
|
||||||
|
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||||
|
SECMODE_SIGN_ENABLED))) {
|
||||||
|
rc = cifs_verify_signature(out_buf,
|
||||||
|
ses->server->mac_signing_key,
|
||||||
|
midQ->sequence_number+1);
|
||||||
|
if(rc) {
|
||||||
|
cERROR(1,("Unexpected SMB signature"));
|
||||||
|
/* BB FIXME add code to kill session */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pbytes_returned = out_buf->smb_buf_length;
|
||||||
|
|
||||||
|
/* BB special case reconnect tid and uid here? */
|
||||||
|
rc = map_smb_to_linux_error(out_buf);
|
||||||
|
|
||||||
|
/* convert ByteCount if necessary */
|
||||||
|
if (receive_len >=
|
||||||
|
sizeof (struct smb_hdr) -
|
||||||
|
4 /* do not count RFC1001 header */ +
|
||||||
|
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||||
|
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
|
||||||
|
} else {
|
||||||
|
rc = -EIO;
|
||||||
|
cERROR(1,("Bad MID state?"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeleteMidQEntry(midQ);
|
||||||
|
if (rstart && rc == -EACCES)
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
@ -330,11 +330,15 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
|
|||||||
sb = direntry->d_inode->i_sb;
|
sb = direntry->d_inode->i_sb;
|
||||||
if(sb == NULL)
|
if(sb == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
xid = GetXid();
|
|
||||||
|
|
||||||
cifs_sb = CIFS_SB(sb);
|
cifs_sb = CIFS_SB(sb);
|
||||||
pTcon = cifs_sb->tcon;
|
pTcon = cifs_sb->tcon;
|
||||||
|
|
||||||
|
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
xid = GetXid();
|
||||||
|
|
||||||
full_path = build_path_from_dentry(direntry);
|
full_path = build_path_from_dentry(direntry);
|
||||||
if(full_path == NULL) {
|
if(full_path == NULL) {
|
||||||
FreeXid(xid);
|
FreeXid(xid);
|
||||||
|
Loading…
Reference in New Issue
Block a user