Commit 1915ad84 authored by Steve French's avatar Steve French Committed by Steve French

have to reconnect open files safely, one at a time, as needed

parent c0426ae3
......@@ -211,6 +211,7 @@ struct cifsFileInfo {
struct inode * pInode; /* needed for oplock break */
int endOfSearch:1; /* we have reached end of search */
int closePend:1; /* file is marked to close */
int reopenPend:1; /* reopen of file in progress */
int emptyDir:1;
int invalidHandle:1; /* file closed via session abend */
char * search_resume_name;
......
......@@ -21,7 +21,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
/* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
/* These are mostly routines that operate on a pathname, or on a tree id */
/* (mounted volume), but there are eight handle based routines which must be */
/* treated slightly different for reconnection purposes since we never want */
/* to reuse a stale file handle and the caller knows the file handle */
#include <linux/fs.h>
#include <linux/kernel.h>
......@@ -49,21 +53,45 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
{
int rc = 0;
if(tcon && (tcon->tidStatus == CifsNeedReconnect)) {
if(tcon->ses) {
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
check for tcp and smb session status done differently
for those three - in the calling routine */
if(tcon) {
if((tcon->ses) && (tcon->ses->server)){
if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
/* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket
timeout which is 7 seconds */
wait_event_interruptible_timeout(tcon->ses->server->response_q,
(tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
if(tcon->ses->server->tcpStatus == CifsNeedReconnect)
return -EHOSTDOWN;
}
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
struct nls_table *nls_codepage = load_nls_default();
if(tcon->ses->status == CifsNeedReconnect)
rc = setup_session(0, tcon->ses, nls_codepage);
if(!rc) {
if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
nls_codepage);
up(&tcon->ses->sesSem);
cFYI(1, ("reconnect tcon rc = %d", rc));
if(!rc)
reopen_files(tcon,nls_codepage);
/* Remove call to reopen files here -
it is safer (and faster) to reopen
files as needed in read and write */
/* if(!rc)
reopen_files(tcon,nls_codepage);*/
} else {
up(&tcon->ses->sesSem);
}
unload_nls(nls_codepage);
} else
rc = -EIO;
} else {
return -EIO;
}
}
if(rc)
return rc;
......@@ -209,7 +237,6 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
* (and inside session disconnect we should check if tcp socket needs
* to be freed and kernel thread woken up).
*/
tdisRetry:
if (tcon)
down(&tcon->tconSem);
else
......@@ -221,12 +248,19 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
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 */
if(tcon->tidStatus == CifsNeedReconnect) {
up(&tcon->tconSem);
return 0;
}
/* BB remove (from server) list of shares - but with smp safety BB */
/* BB is ses active - do we need to check here - but how? BB */
if((tcon->ses == 0) || (tcon->ses->server == 0)) {
up(&tcon->tconSem);
return -EIO;
}
if((tcon->ses == 0) || (tcon->ses->server == 0)) {
up(&tcon->tconSem);
return -EIO;
}
rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
(void **) &smb_buffer, (void **) &smb_buffer_response);
......@@ -242,8 +276,12 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
if (smb_buffer)
buf_release(smb_buffer);
up(&tcon->tconSem);
/* No need to return error on this operation if tid invalidated and
closed on server already e.g. due to tcp session crashing */
if (rc == -EAGAIN)
goto tdisRetry;
rc = 0;
return rc;
}
......@@ -256,9 +294,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
int length;
cFYI(1, ("In SMBLogoff for session disconnect"));
LogoffRetry:
if (ses)
down(&ses->sesSem); /* check this sem more places */
down(&ses->sesSem);
else
return -EIO;
......@@ -292,8 +329,12 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
if (pSMB)
buf_release(pSMB);
up(&ses->sesSem);
/* if session dead then we do not need to do ulogoff,
since server closed smb session, no sense reporting
error */
if (rc == -EAGAIN)
goto LogoffRetry;
rc = 0;
return rc;
}
......@@ -537,7 +578,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
char *pReadData = NULL;
int bytes_returned;
readRetry:
*nbytes = 0;
rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
(void **) &pSMBr);
......@@ -588,9 +628,9 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
else
*buf = (char *)pSMB;
}
if (rc == -EAGAIN)
goto readRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......@@ -605,7 +645,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
WRITE_RSP *pSMBr = NULL;
int bytes_returned;
writeRetry:
rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -646,8 +685,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
if (pSMB)
buf_release(pSMB);
if (rc == -EAGAIN)
goto writeRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......@@ -666,7 +705,6 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
__u64 temp;
cFYI(1, ("In CIFSSMBLock"));
lockRetry:
rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -701,8 +739,9 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
}
if (pSMB)
buf_release(pSMB);
if (rc == -EAGAIN)
goto lockRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......@@ -732,9 +771,9 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
if (pSMB)
buf_release(pSMB);
/* file will be closed on server if session is dead */
/* Since session is dead, file will be closed on server already */
if(rc == -EAGAIN)
rc = -EHOSTDOWN; /* should we fake success? */
rc = 0;
return rc;
}
......@@ -822,7 +861,6 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
int len_of_str;
cFYI(1, ("Rename to File by handle"));
renameOpenFileRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -880,8 +918,8 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
if (pSMB)
buf_release(pSMB);
if (rc == -EAGAIN)
goto renameOpenFileRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......@@ -1249,7 +1287,6 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
struct smb_com_transaction_ioctl_rsp * pSMBr;
cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
queryReparseLinkInfoRetry:
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -1314,8 +1351,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
}
if (pSMB)
buf_release(pSMB);
if (rc == -EAGAIN)
goto queryReparseLinkInfoRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......@@ -1686,7 +1724,6 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("In FindNext"));
findNextRetry:
if(resume_file_name == NULL) {
return -EIO;
}
......@@ -1771,8 +1808,8 @@ CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
if (pSMB)
buf_release(pSMB);
if (rc == -EAGAIN)
goto findNextRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......@@ -1784,8 +1821,8 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
FINDCLOSE_REQ *pSMB = NULL;
CLOSE_RSP *pSMBr = NULL;
int bytes_returned;
cFYI(1, ("In CIFSSMBFindClose"));
findCloseRetry:
rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -1801,8 +1838,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
if (pSMB)
buf_release(pSMB);
/* Since session is dead, search handle closed on server already */
if (rc == -EAGAIN)
goto findCloseRetry;
rc = 0;
return rc;
}
......@@ -2363,7 +2401,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
__u32 tmp;
cFYI(1, ("SetFileSize (via SetFileInfo)"));
SetFileSizeRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
......@@ -2434,8 +2471,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
if (pSMB)
buf_release(pSMB);
if (rc == -EAGAIN)
goto SetFileSizeRetry;
/* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
......
......@@ -821,7 +821,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket)
/* Eventually check for other socket options to change from
the default. sock_setsockopt not used because it expects
user space buffer */
(*csocket)->sk->sk_rcvtimeo = 8 * HZ;
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
return rc;
}
......@@ -1002,8 +1002,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
strncpy(pSesInfo->domainName,
volume_info.domainname,MAX_USERNAME_SIZE);
pSesInfo->linux_uid = volume_info.linux_uid;
down(&pSesInfo->sesSem);
rc = setup_session(xid,pSesInfo, cifs_sb->local_nls);
up(&pSesInfo->sesSem);
if(!rc)
atomic_inc(&srvTcp->socketUseCount);
}
......
......@@ -740,10 +740,22 @@ cifs_commit_write(struct file *file, struct page *page, unsigned offset,
if (file->private_data == NULL) {
rc = -EBADF;
} else {
cifs_sb = CIFS_SB(inode->i_sb);
open_file = (struct cifsFileInfo *)file->private_data;
rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, position,
open_file->netfid,open_file->pid,FALSE);
cifs_sb = CIFS_SB(inode->i_sb);
rc = -EAGAIN;
while(rc == -EAGAIN) {
if((open_file->invalidHandle == TRUE) &&
(open_file->closePend == FALSE)) {
open_file->reopenPend = TRUE;
rc = cifs_reopen_file(file->f_dentry->d_inode,file);
open_file->reopenPend = FALSE;
}
if(rc != 0)
break;
rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon,
position, open_file->netfid,
open_file->pid,FALSE);
}
cFYI(1,(" SetEOF (commit write) rc = %d",rc));
}
}
......
......@@ -665,7 +665,12 @@ cifs_truncate_file(struct inode *inode)
if(rc == 0) {
FreeXid(xid);
return;
}
}
/* Do not need reopen and retry on EAGAIN since we will
retry by pathname below */
if(rc == -EAGAIN)
rc = -EHOSTDOWN;
break; /* now that we found one valid file handle no
sense continuing to loop trying others */
}
......@@ -767,19 +772,31 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
if((open_file->pfile) &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
read_unlock(&GlobalSMBSeslock);
found = TRUE;
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
open_file->netfid,open_file->pid,FALSE);
cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
break; /* now that we found one valid file handle no
if(open_file->invalidHandle == FALSE) {
/* we found a valid, writeable network file
handle to use to try to set the file size */
__u16 nfid = open_file->netfid;
__u32 npid = open_file->pid;
read_unlock(&GlobalSMBSeslock);
found = TRUE;
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
nfid,npid,FALSE);
cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
/* Do not need reopen and retry on EAGAIN since we will
retry by pathname below */
break; /* now that we found one valid file handle no
sense continuing to loop trying others */
}
}
}
if(found == FALSE)
read_unlock(&GlobalSMBSeslock);
if(rc != 0) {
/* Set file size by pathname rather than by handle either
because no valid, writeable file handle for it was found or
because there was an error setting it by handle */
rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
cifs_sb->local_nls);
cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
......
......@@ -184,9 +184,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return -ENOENT;
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
cFYI(1,("tcp session dead - return to caller to retry"));
/* Give Demultiplex thread up to 10 seconds to reconnect */
wait_event_interruptible_timeout(ses->server->response_q,
(ses->server->tcpStatus == CifsGood), 10 * HZ);
return -EAGAIN;
} else if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */
......
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