Commit 4a267003 authored by Konstantin Baev's avatar Konstantin Baev

update sources/2.6.27

- source: cifs-2.6.git - refspec: v2.6.27-etercifs - commit: 1827b7d4082cc5aef979a6d86c7cb96f9dee2c09 merge with new kernel minor version (v2.6.27.8)
parent d99211de
...@@ -70,7 +70,8 @@ struct key_type cifs_spnego_key_type = { ...@@ -70,7 +70,8 @@ struct key_type cifs_spnego_key_type = {
strlen("ver=0xFF") */ strlen("ver=0xFF") */
#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
in future could have strlen(";sec=ntlmsspi") */ in future could have strlen(";sec=ntlmsspi") */
#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ /* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */
#define MAX_IPV6_ADDR_LEN 43
/* get a key struct with a SPNEGO security blob, suitable for session setup */ /* get a key struct with a SPNEGO security blob, suitable for session setup */
struct key * struct key *
cifs_get_spnego_key(struct cifsSesInfo *sesInfo) cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
......
...@@ -510,10 +510,11 @@ static void cifs_umount_begin(struct super_block *sb) ...@@ -510,10 +510,11 @@ static void cifs_umount_begin(struct super_block *sb)
tcon = cifs_sb->tcon; tcon = cifs_sb->tcon;
if (tcon == NULL) if (tcon == NULL)
return; return;
down(&tcon->tconSem);
if (atomic_read(&tcon->useCount) == 1) read_lock(&cifs_tcp_ses_lock);
if (tcon->tc_count == 1)
tcon->tidStatus = CifsExiting; tcon->tidStatus = CifsExiting;
up(&tcon->tconSem); read_unlock(&cifs_tcp_ses_lock);
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */ /* cancel_notify_requests(tcon); */
...@@ -980,11 +981,10 @@ static int cifs_oplock_thread(void *dummyarg) ...@@ -980,11 +981,10 @@ static int cifs_oplock_thread(void *dummyarg)
not bother sending an oplock release if session not bother sending an oplock release if session
to server still is disconnected since oplock to server still is disconnected since oplock
already released by the server in that case */ already released by the server in that case */
if (pTcon->tidStatus != CifsNeedReconnect) { if (!pTcon->need_reconnect) {
/* PV: disable caching if oplock missed */ /* PV: disable caching if oplock missed */
CIFS_I(inode)->clientCanCacheRead = false; CIFS_I(inode)->clientCanCacheRead = false;
CIFS_I(inode)->clientCanCacheAll = false; CIFS_I(inode)->clientCanCacheAll = false;
rc = CIFSSMBLock(0, pTcon, netfid, rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0, 0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE, 0, LOCKING_ANDX_OPLOCK_RELEASE,
...@@ -1002,24 +1002,24 @@ static int cifs_oplock_thread(void *dummyarg) ...@@ -1002,24 +1002,24 @@ static int cifs_oplock_thread(void *dummyarg)
static int cifs_dnotify_thread(void *dummyarg) static int cifs_dnotify_thread(void *dummyarg)
{ {
struct list_head *tmp; struct list_head *tmp;
struct cifsSesInfo *ses; struct TCP_Server_Info *server;
do { do {
if (try_to_freeze()) if (try_to_freeze())
continue; continue;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(15*HZ); schedule_timeout(15*HZ);
read_lock(&GlobalSMBSeslock);
/* check if any stuck requests that need /* check if any stuck requests that need
to be woken up and wakeq so the to be woken up and wakeq so the
thread can wake up and error out */ thread can wake up and error out */
list_for_each(tmp, &GlobalSMBSessionList) { read_lock(&cifs_tcp_ses_lock);
ses = list_entry(tmp, struct cifsSesInfo, list_for_each(tmp, &cifs_tcp_ses_list) {
cifsSessionList); server = list_entry(tmp, struct TCP_Server_Info,
if (ses->server && atomic_read(&ses->server->inFlight)) tcp_ses_list);
wake_up_all(&ses->server->response_q); if (atomic_read(&server->inFlight))
wake_up_all(&server->response_q);
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&cifs_tcp_ses_lock);
} while (!kthread_should_stop()); } while (!kthread_should_stop());
return 0; return 0;
...@@ -1030,9 +1030,7 @@ init_cifs(void) ...@@ -1030,9 +1030,7 @@ init_cifs(void)
{ {
int rc = 0; int rc = 0;
cifs_proc_init(); cifs_proc_init();
/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ INIT_LIST_HEAD(&cifs_tcp_ses_list);
INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q); INIT_LIST_HEAD(&GlobalOplock_Q);
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
INIT_LIST_HEAD(&GlobalDnotifyReqList); INIT_LIST_HEAD(&GlobalDnotifyReqList);
...@@ -1060,6 +1058,7 @@ init_cifs(void) ...@@ -1060,6 +1058,7 @@ init_cifs(void)
GlobalMaxActiveXid = 0; GlobalMaxActiveXid = 0;
memset(Local_System_Name, 0, 15); memset(Local_System_Name, 0, 15);
rwlock_init(&GlobalSMBSeslock); rwlock_init(&GlobalSMBSeslock);
rwlock_init(&cifs_tcp_ses_lock);
spin_lock_init(&GlobalMid_Lock); spin_lock_init(&GlobalMid_Lock);
if (cifs_max_pending < 2) { if (cifs_max_pending < 2) {
......
...@@ -85,8 +85,7 @@ enum securityEnum { ...@@ -85,8 +85,7 @@ enum securityEnum {
}; };
enum protocolEnum { enum protocolEnum {
IPV4 = 0, TCP = 0,
IPV6,
SCTP SCTP
/* Netbios frames protocol not supported at this time */ /* Netbios frames protocol not supported at this time */
}; };
...@@ -122,6 +121,9 @@ struct cifs_cred { ...@@ -122,6 +121,9 @@ struct cifs_cred {
*/ */
struct TCP_Server_Info { struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */ /* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
...@@ -141,7 +143,8 @@ struct TCP_Server_Info { ...@@ -141,7 +143,8 @@ struct TCP_Server_Info {
char versionMajor; char versionMajor;
char versionMinor; char versionMinor;
bool svlocal:1; /* local server or remote */ bool svlocal:1; /* local server or remote */
atomic_t socketUseCount; /* number of open cifs sessions on socket */ bool noblocksnd; /* use blocking sendmsg */
bool noautotune; /* do not autotune send buf sizes */
atomic_t inFlight; /* number of requests on the wire to server */ atomic_t inFlight; /* number of requests on the wire to server */
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_t inSend; /* requests trying to send */ atomic_t inSend; /* requests trying to send */
...@@ -192,13 +195,14 @@ struct cifsUidInfo { ...@@ -192,13 +195,14 @@ struct cifsUidInfo {
* Session structure. One of these for each uid session with a particular host * Session structure. One of these for each uid session with a particular host
*/ */
struct cifsSesInfo { struct cifsSesInfo {
struct list_head cifsSessionList; struct list_head smb_ses_list;
struct list_head tcon_list;
struct semaphore sesSem; struct semaphore sesSem;
#if 0 #if 0
struct cifsUidInfo *uidInfo; /* pointer to user info */ struct cifsUidInfo *uidInfo; /* pointer to user info */
#endif #endif
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of mounts (tree connections) on this ses */ int ses_count; /* reference counter */
enum statusEnum status; enum statusEnum status;
unsigned overrideSecFlg; /* if non-zero override global sec flags */ unsigned overrideSecFlg; /* if non-zero override global sec flags */
__u16 ipc_tid; /* special tid for connection to IPC share */ __u16 ipc_tid; /* special tid for connection to IPC share */
...@@ -214,6 +218,7 @@ struct cifsSesInfo { ...@@ -214,6 +218,7 @@ struct cifsSesInfo {
char userName[MAX_USERNAME_SIZE + 1]; char userName[MAX_USERNAME_SIZE + 1];
char *domainName; char *domainName;
char *password; char *password;
bool need_reconnect:1; /* connection reset, uid now invalid */
}; };
/* no more than one of the following three session flags may be set */ /* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1 #define CIFS_SES_NT4 1
...@@ -228,16 +233,15 @@ struct cifsSesInfo { ...@@ -228,16 +233,15 @@ struct cifsSesInfo {
* session * session
*/ */
struct cifsTconInfo { struct cifsTconInfo {
struct list_head cifsConnectionList; struct list_head tcon_list;
int tc_count;
struct list_head openFileList; struct list_head openFileList;
struct semaphore tconSem;
struct cifsSesInfo *ses; /* pointer to session associated with */ struct cifsSesInfo *ses; /* pointer to session associated with */
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
char *nativeFileSystem; char *nativeFileSystem;
__u16 tid; /* The 2 byte tree id */ __u16 tid; /* The 2 byte tree id */
__u16 Flags; /* optional support bits */ __u16 Flags; /* optional support bits */
enum statusEnum tidStatus; enum statusEnum tidStatus;
atomic_t useCount; /* how many explicit/implicit mounts to share */
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
atomic_t num_smbs_sent; atomic_t num_smbs_sent;
atomic_t num_writes; atomic_t num_writes;
...@@ -285,6 +289,7 @@ struct cifsTconInfo { ...@@ -285,6 +289,7 @@ struct cifsTconInfo {
bool seal:1; /* transport encryption for this mounted share */ bool seal:1; /* transport encryption for this mounted share */
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
for this mount even if server would support */ for this mount even if server would support */
bool need_reconnect:1; /* connection reset, tid now invalid */
/* BB add field for back pointer to sb struct(s)? */ /* BB add field for back pointer to sb struct(s)? */
}; };
...@@ -585,21 +590,21 @@ require use of the stronger protocol */ ...@@ -585,21 +590,21 @@ require use of the stronger protocol */
#endif #endif
/* /*
* The list of servers that did not respond with NT LM 0.12. * the list of TCP_Server_Info structures, ie each of the sockets
* This list helps improve performance and eliminate the messages indicating * connecting our client to a distinct server (ip address), is
* that we had a communications error talking to the server in this list. * chained together by cifs_tcp_ses_list. The list of all our SMB
* sessions (and from that the tree connections) can be found
* by iterating over cifs_tcp_ses_list
*/ */
/* Feature not supported */ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
/* /*
* The following is a hash table of all the users we know about. * This lock protects the cifs_tcp_ses_list, the list of smb sessions per
* tcp session, and the list of tcon's per smb session. It also protects
* the reference counters for the server, smb session, and tcon. Finally,
* changes to the tcon->tidStatus should be done while holding this lock.
*/ */
GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
/* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */
GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
GLOBAL_EXTERN struct list_head GlobalOplock_Q; GLOBAL_EXTERN struct list_head GlobalOplock_Q;
......
...@@ -36,7 +36,7 @@ extern void cifs_buf_release(void *); ...@@ -36,7 +36,7 @@ extern void cifs_buf_release(void *);
extern struct smb_hdr *cifs_small_buf_get(void); extern struct smb_hdr *cifs_small_buf_get(void);
extern void cifs_small_buf_release(void *); extern void cifs_small_buf_release(void *);
extern int smb_send(struct socket *, struct smb_hdr *, extern int smb_send(struct socket *, struct smb_hdr *,
unsigned int /* length */ , struct sockaddr *); unsigned int /* length */ , struct sockaddr *, bool);
extern unsigned int _GetXid(void); extern unsigned int _GetXid(void);
extern void _FreeXid(unsigned int); extern void _FreeXid(unsigned int);
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid)); #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
......
...@@ -190,10 +190,10 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, ...@@ -190,10 +190,10 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* need to prevent multiple threads trying to /* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */ simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem); down(&tcon->ses->sesSem);
if (tcon->ses->status == CifsNeedReconnect) if (tcon->ses->need_reconnect)
rc = cifs_setup_session(0, tcon->ses, rc = cifs_setup_session(0, tcon->ses,
nls_codepage); nls_codepage);
if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { if (!rc && (tcon->need_reconnect)) {
mark_open_files_invalid(tcon); mark_open_files_invalid(tcon);
rc = CIFSTCon(0, tcon->ses, tcon->treeName, rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage); tcon, nls_codepage);
...@@ -337,10 +337,10 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, ...@@ -337,10 +337,10 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* need to prevent multiple threads trying to /* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */ simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem); down(&tcon->ses->sesSem);
if (tcon->ses->status == CifsNeedReconnect) if (tcon->ses->need_reconnect)
rc = cifs_setup_session(0, tcon->ses, rc = cifs_setup_session(0, tcon->ses,
nls_codepage); nls_codepage);
if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { if (!rc && (tcon->need_reconnect)) {
mark_open_files_invalid(tcon); mark_open_files_invalid(tcon);
rc = CIFSTCon(0, tcon->ses, tcon->treeName, rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage); tcon, nls_codepage);
...@@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) ...@@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc = -EIO; rc = -EIO;
goto neg_err_exit; goto neg_err_exit;
} }
read_lock(&cifs_tcp_ses_lock);
if (server->socketUseCount.counter > 1) { if (server->srv_count > 1) {
read_unlock(&cifs_tcp_ses_lock);
if (memcmp(server->server_GUID, if (memcmp(server->server_GUID,
pSMBr->u.extended_response. pSMBr->u.extended_response.
GUID, 16) != 0) { GUID, 16) != 0) {
...@@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) ...@@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
pSMBr->u.extended_response.GUID, pSMBr->u.extended_response.GUID,
16); 16);
} }
} else } else {
read_unlock(&cifs_tcp_ses_lock);
memcpy(server->server_GUID, memcpy(server->server_GUID,
pSMBr->u.extended_response.GUID, 16); pSMBr->u.extended_response.GUID, 16);
}
if (count == 16) { if (count == 16) {
server->secType = RawNTLMSSP; server->secType = RawNTLMSSP;
...@@ -739,50 +742,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) ...@@ -739,50 +742,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
int rc = 0; int rc = 0;
cFYI(1, ("In tree disconnect")); cFYI(1, ("In tree disconnect"));
/*
* If last user of the connection and
* connection alive - disconnect it
* If this is the last connection on the server session disconnect it
* (and inside session disconnect we should check if tcp socket needs
* to be freed and kernel thread woken up).
*/
if (tcon)
down(&tcon->tconSem);
else
return -EIO;
atomic_dec(&tcon->useCount); /* BB: do we need to check this? These should never be NULL. */
if (atomic_read(&tcon->useCount) > 0) { if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
up(&tcon->tconSem); return -EIO;
return -EBUSY;
}
/* No need to return error on this operation if tid invalidated and /*
closed on server already e.g. due to tcp session crashing */ * No need to return error on this operation if tid invalidated and
if (tcon->tidStatus == CifsNeedReconnect) { * closed on server already e.g. due to tcp session crashing. Also,
up(&tcon->tconSem); * the tcon is no longer on the list, so no need to take lock before
* checking this.
*/
if (tcon->need_reconnect)
return 0; return 0;
}
if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
up(&tcon->tconSem);
return -EIO;
}
rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
(void **)&smb_buffer); (void **)&smb_buffer);
if (rc) { if (rc)
up(&tcon->tconSem);
return rc; return rc;
}
rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
if (rc) if (rc)
cFYI(1, ("Tree disconnect failed %d", rc)); cFYI(1, ("Tree disconnect failed %d", rc));
up(&tcon->tconSem);
/* No need to return error on this operation if tid invalidated and /* No need to return error on this operation if tid invalidated and
closed on server already e.g. due to tcp session crashing */ closed on server already e.g. due to tcp session crashing */
if (rc == -EAGAIN) if (rc == -EAGAIN)
rc = 0; rc = 0;
...@@ -796,43 +780,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) ...@@ -796,43 +780,36 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
int rc = 0; int rc = 0;
cFYI(1, ("In SMBLogoff for session disconnect")); cFYI(1, ("In SMBLogoff for session disconnect"));
if (ses)
down(&ses->sesSem); /*
else * BB: do we need to check validity of ses and server? They should
* always be valid since we have an active reference. If not, that
* should probably be a BUG()
*/
if (!ses || !ses->server)
return -EIO; return -EIO;
atomic_dec(&ses->inUse); down(&ses->sesSem);
if (atomic_read(&ses->inUse) > 0) { if (ses->need_reconnect)
up(&ses->sesSem); goto session_already_dead; /* no need to send SMBlogoff if uid
return -EBUSY; already closed due to reconnect */
}
rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
if (rc) { if (rc) {
up(&ses->sesSem); up(&ses->sesSem);
return rc; return rc;
} }
if (ses->server) { pSMB->hdr.Mid = GetNextMid(ses->server);
pSMB->hdr.Mid = GetNextMid(ses->server);
if (ses->server->secMode & if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
}
pSMB->hdr.Uid = ses->Suid; pSMB->hdr.Uid = ses->Suid;
pSMB->AndXCommand = 0xFF; pSMB->AndXCommand = 0xFF;
rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
if (ses->server) { session_already_dead:
atomic_dec(&ses->server->socketUseCount);
if (atomic_read(&ses->server->socketUseCount) == 0) {
spin_lock(&GlobalMid_Lock);
ses->server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
rc = -ESHUTDOWN;
}
}
up(&ses->sesSem); up(&ses->sesSem);
/* if session dead then we do not need to do ulogoff, /* if session dead then we do not need to do ulogoff,
...@@ -1539,7 +1516,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, ...@@ -1539,7 +1516,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
__u32 bytes_sent; __u32 bytes_sent;
__u16 byte_count; __u16 byte_count;
/* cFYI(1,("write at %lld %d bytes",offset,count));*/ /* cFYI(1, ("write at %lld %d bytes",offset,count));*/
if (tcon->ses == NULL) if (tcon->ses == NULL)
return -ECONNABORTED; return -ECONNABORTED;
......
...@@ -502,7 +502,7 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -502,7 +502,7 @@ int cifs_close(struct inode *inode, struct file *file)
if (pTcon) { if (pTcon) {
/* no sense reconnecting to close a file that is /* no sense reconnecting to close a file that is
already closed */ already closed */
if (pTcon->tidStatus != CifsNeedReconnect) { if (!pTcon->need_reconnect) {
timeout = 2; timeout = 2;
while ((atomic_read(&pSMBFile->wrtPending) != 0) while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout <= 2048)) { && (timeout <= 2048)) {
...@@ -1405,7 +1405,10 @@ retry: ...@@ -1405,7 +1405,10 @@ retry:
if ((wbc->nr_to_write -= n_iov) <= 0) if ((wbc->nr_to_write -= n_iov) <= 0)
done = 1; done = 1;
index = next; index = next;
} } else
/* Need to re-find the pages we skipped */
index = pvec.pages[0]->index + 1;
pagevec_release(&pvec); pagevec_release(&pvec);
} }
if (!scanned && !done) { if (!scanned && !done) {
...@@ -1822,7 +1825,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1822,7 +1825,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
pagevec_init(&lru_pvec, 0); pagevec_init(&lru_pvec, 0);
cFYI(DBG2, ("rpages: num pages %d", num_pages)); cFYI(DBG2, ("rpages: num pages %d", num_pages));
for (i = 0; i < num_pages; ) { for (i = 0; i < num_pages; ) {
unsigned contig_pages; unsigned contig_pages;
struct page *tmp_page; struct page *tmp_page;
......
...@@ -75,12 +75,12 @@ sesInfoAlloc(void) ...@@ -75,12 +75,12 @@ sesInfoAlloc(void)
ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL);
if (ret_buf) { if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&sesInfoAllocCount); atomic_inc(&sesInfoAllocCount);
ret_buf->status = CifsNew; ret_buf->status = CifsNew;
list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); ++ret_buf->ses_count;
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
INIT_LIST_HEAD(&ret_buf->tcon_list);
init_MUTEX(&ret_buf->sesSem); init_MUTEX(&ret_buf->sesSem);
write_unlock(&GlobalSMBSeslock);
} }
return ret_buf; return ret_buf;
} }
...@@ -93,10 +93,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) ...@@ -93,10 +93,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
return; return;
} }
write_lock(&GlobalSMBSeslock);
atomic_dec(&sesInfoAllocCount); atomic_dec(&sesInfoAllocCount);
list_del(&buf_to_free->cifsSessionList);
write_unlock(&GlobalSMBSeslock);
kfree(buf_to_free->serverOS); kfree(buf_to_free->serverOS);
kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverDomain);
kfree(buf_to_free->serverNOS); kfree(buf_to_free->serverNOS);
...@@ -111,17 +108,14 @@ tconInfoAlloc(void) ...@@ -111,17 +108,14 @@ tconInfoAlloc(void)
struct cifsTconInfo *ret_buf; struct cifsTconInfo *ret_buf;
ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL);
if (ret_buf) { if (ret_buf) {
write_lock(&GlobalSMBSeslock);
atomic_inc(&tconInfoAllocCount); atomic_inc(&tconInfoAllocCount);
list_add(&ret_buf->cifsConnectionList,
&GlobalTreeConnectionList);
ret_buf->tidStatus = CifsNew; ret_buf->tidStatus = CifsNew;
++ret_buf->tc_count;
INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->openFileList);
init_MUTEX(&ret_buf->tconSem); INIT_LIST_HEAD(&ret_buf->tcon_list);
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
spin_lock_init(&ret_buf->stat_lock); spin_lock_init(&ret_buf->stat_lock);
#endif #endif
write_unlock(&GlobalSMBSeslock);
} }
return ret_buf; return ret_buf;
} }
...@@ -133,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free) ...@@ -133,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
cFYI(1, ("Null buffer passed to tconInfoFree")); cFYI(1, ("Null buffer passed to tconInfoFree"));
return; return;
} }
write_lock(&GlobalSMBSeslock);
atomic_dec(&tconInfoAllocCount); atomic_dec(&tconInfoAllocCount);
list_del(&buf_to_free->cifsConnectionList);
write_unlock(&GlobalSMBSeslock);
kfree(buf_to_free->nativeFileSystem); kfree(buf_to_free->nativeFileSystem);
kfree(buf_to_free); kfree(buf_to_free);
} }
...@@ -354,9 +345,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -354,9 +345,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
if (current->fsuid != treeCon->ses->linux_uid) { if (current->fsuid != treeCon->ses->linux_uid) {
cFYI(1, ("Multiuser mode and UID " cFYI(1, ("Multiuser mode and UID "
"did not match tcon uid")); "did not match tcon uid"));
read_lock(&GlobalSMBSeslock); read_lock(&cifs_tcp_ses_lock);
list_for_each(temp_item, &GlobalSMBSessionList) { list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
if (ses->linux_uid == current->fsuid) { if (ses->linux_uid == current->fsuid) {
if (ses->server == treeCon->ses->server) { if (ses->server == treeCon->ses->server) {
cFYI(1, ("found matching uid substitute right smb_uid")); cFYI(1, ("found matching uid substitute right smb_uid"));
...@@ -368,7 +359,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -368,7 +359,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
} }
} }
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&cifs_tcp_ses_lock);
} }
} }
} }
...@@ -501,9 +492,10 @@ bool ...@@ -501,9 +492,10 @@ bool
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
{ {
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp; struct list_head *tmp, *tmp1, *tmp2;
struct list_head *tmp1; struct cifsSesInfo *ses;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
struct cifsInodeInfo *pCifsInode;
struct cifsFileInfo *netfile; struct cifsFileInfo *netfile;
cFYI(1, ("Checking for oplock break or dnotify response")); cFYI(1, ("Checking for oplock break or dnotify response"));
...@@ -558,42 +550,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -558,42 +550,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return false; return false;
/* look up tcon based on tid & uid */ /* look up tcon based on tid & uid */
read_lock(&GlobalSMBSeslock); read_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &srv->smb_ses_list) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) { list_for_each(tmp1, &ses->tcon_list) {
tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list);
if (tcon->tid != buf->Tid)
continue;
cifs_stats_inc(&tcon->num_oplock_brks); cifs_stats_inc(&tcon->num_oplock_brks);
list_for_each(tmp1, &tcon->openFileList) { list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp1, struct cifsFileInfo, netfile = list_entry(tmp2, struct cifsFileInfo,
tlist); tlist);
if (pSMB->Fid == netfile->netfid) { if (pSMB->Fid != netfile->netfid)
struct cifsInodeInfo *pCifsInode; continue;
read_unlock(&GlobalSMBSeslock);
cFYI(1, read_unlock(&cifs_tcp_ses_lock);
("file id match, oplock break")); cFYI(1, ("file id match, oplock break"));
pCifsInode = pCifsInode = CIFS_I(netfile->pInode);
CIFS_I(netfile->pInode); pCifsInode->clientCanCacheAll = false;
pCifsInode->clientCanCacheAll = false; if (pSMB->OplockLevel == 0)
if (pSMB->OplockLevel == 0) pCifsInode->clientCanCacheRead = false;
pCifsInode->clientCanCacheRead pCifsInode->oplockPending = true;
= false; AllocOplockQEntry(netfile->pInode,
pCifsInode->oplockPending = true; netfile->netfid, tcon);
AllocOplockQEntry(netfile->pInode, cFYI(1, ("about to wake up oplock thread"));
netfile->netfid, if (oplockThread)
tcon); wake_up_process(oplockThread);
cFYI(1,
("about to wake up oplock thread")); return true;
if (oplockThread)
wake_up_process(oplockThread);
return true;
}
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("No matching file for oplock break")); cFYI(1, ("No matching file for oplock break"));
return true; return true;
} }
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&cifs_tcp_ses_lock);
cFYI(1, ("Can not process oplock break for non-existent connection")); cFYI(1, ("Can not process oplock break for non-existent connection"));
return true; return true;
} }
......
...@@ -162,7 +162,7 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon) ...@@ -162,7 +162,7 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
int int
smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length, struct sockaddr *sin) unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd)
{ {
int rc = 0; int rc = 0;
int i = 0; int i = 0;
...@@ -179,7 +179,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -179,7 +179,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_namelen = sizeof(struct sockaddr);
smb_msg.msg_control = NULL; smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0; smb_msg.msg_controllen = 0;
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ if (noblocksnd)
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
else
smb_msg.msg_flags = MSG_NOSIGNAL;
/* smb header is converted in header_assemble. bcc and rest of SMB word /* smb header is converted in header_assemble. bcc and rest of SMB word
area, and byte area if necessary, is converted to littleendian in area, and byte area if necessary, is converted to littleendian in
...@@ -230,8 +233,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -230,8 +233,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
} }
static int static int
smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec,
struct sockaddr *sin) struct sockaddr *sin, bool noblocksnd)
{ {
int rc = 0; int rc = 0;
int i = 0; int i = 0;
...@@ -241,6 +244,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -241,6 +244,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
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; unsigned int smb_buf_length = smb_buffer->smb_buf_length;
struct socket *ssocket = server->ssocket;
if (ssocket == NULL) if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */ return -ENOTSOCK; /* BB eventually add reconnect code here */
...@@ -249,7 +253,10 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -249,7 +253,10 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_namelen = sizeof(struct sockaddr);
smb_msg.msg_control = NULL; smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0; smb_msg.msg_controllen = 0;
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ if (noblocksnd)
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;
else
smb_msg.msg_flags = MSG_NOSIGNAL;
/* smb header is converted in header_assemble. bcc and rest of SMB word /* smb header is converted in header_assemble. bcc and rest of SMB word
area, and byte area if necessary, is converted to littleendian in area, and byte area if necessary, is converted to littleendian in
...@@ -284,8 +291,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -284,8 +291,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
if (rc < 0) if (rc < 0)
break; break;
if (rc >= total_len) { if (rc == total_len) {
WARN_ON(rc > total_len); total_len = 0;
break;
} else if (rc > total_len) {
cERROR(1, ("sent %d requested %d", rc, total_len));
break; break;
} }
if (rc == 0) { if (rc == 0) {
...@@ -313,6 +323,16 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -313,6 +323,16 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
i = 0; /* in case we get ENOSPC on the next send */ i = 0; /* in case we get ENOSPC on the next send */
} }
if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
cFYI(1, ("partial send (%d remaining), terminating session",
total_len));
/* If we have only sent part of an SMB then the next SMB
could be taken as the remainder of this one. We need
to kill the socket so the server throws away the partial
SMB */
server->tcpStatus = CifsNeedReconnect;
}
if (rc < 0) { if (rc < 0) {
cERROR(1, ("Error %d sending data on socket to server", rc)); cERROR(1, ("Error %d sending data on socket to server", rc));
} else } else
...@@ -519,8 +539,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -519,8 +539,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_inc(&ses->server->inSend); atomic_inc(&ses->server->inSend);
#endif #endif
rc = smb_send2(ses->server->ssocket, iov, n_vec, rc = smb_send2(ses->server, iov, n_vec,
(struct sockaddr *) &(ses->server->addr.sockAddr)); (struct sockaddr *) &(ses->server->addr.sockAddr),
ses->server->noblocksnd);
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_dec(&ses->server->inSend); atomic_dec(&ses->server->inSend);
midQ->when_sent = jiffies; midQ->when_sent = jiffies;
...@@ -712,7 +733,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -712,7 +733,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
atomic_inc(&ses->server->inSend); atomic_inc(&ses->server->inSend);
#endif #endif
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr)); (struct sockaddr *) &(ses->server->addr.sockAddr),
ses->server->noblocksnd);
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_dec(&ses->server->inSend); atomic_dec(&ses->server->inSend);
midQ->when_sent = jiffies; midQ->when_sent = jiffies;
...@@ -852,7 +874,8 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, ...@@ -852,7 +874,8 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
return rc; return rc;
} }
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr)); (struct sockaddr *) &(ses->server->addr.sockAddr),
ses->server->noblocksnd);
up(&ses->server->tcpSem); up(&ses->server->tcpSem);
return rc; return rc;
} }
...@@ -942,7 +965,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -942,7 +965,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
atomic_inc(&ses->server->inSend); atomic_inc(&ses->server->inSend);
#endif #endif
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->addr.sockAddr)); (struct sockaddr *) &(ses->server->addr.sockAddr),
ses->server->noblocksnd);
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
atomic_dec(&ses->server->inSend); atomic_dec(&ses->server->inSend);
midQ->when_sent = jiffies; midQ->when_sent = jiffies;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment