|
@@ -100,110 +100,138 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
|
|
|
to this tcon */
|
|
|
}
|
|
|
|
|
|
-/* Allocate and return pointer to an SMB request buffer, and set basic
|
|
|
- SMB information in the SMB header. If the return code is zero, this
|
|
|
- function must have filled in request_buf pointer */
|
|
|
+/* reconnect the socket, tcon, and smb session if needed */
|
|
|
static int
|
|
|
-small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|
|
- void **request_buf)
|
|
|
+cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
+ struct cifsSesInfo *ses;
|
|
|
+ struct TCP_Server_Info *server;
|
|
|
+ struct nls_table *nls_codepage;
|
|
|
|
|
|
- /* 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->tidStatus == CifsExiting) {
|
|
|
- /* only tree disconnect, open, and write,
|
|
|
- (and ulogoff which does not have tcon)
|
|
|
- are allowed as we start force umount */
|
|
|
- if ((smb_command != SMB_COM_WRITE_ANDX) &&
|
|
|
- (smb_command != SMB_COM_OPEN_ANDX) &&
|
|
|
- (smb_command != SMB_COM_TREE_DISCONNECT)) {
|
|
|
- cFYI(1, ("can not send cmd %d while umounting",
|
|
|
- smb_command));
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * 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)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ses = tcon->ses;
|
|
|
+ server = ses->server;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * only tree disconnect, open, and write, (and ulogoff which does not
|
|
|
+ * have tcon) are allowed as we start force umount
|
|
|
+ */
|
|
|
+ if (tcon->tidStatus == CifsExiting) {
|
|
|
+ if (smb_command != SMB_COM_WRITE_ANDX &&
|
|
|
+ smb_command != SMB_COM_OPEN_ANDX &&
|
|
|
+ smb_command != SMB_COM_TREE_DISCONNECT) {
|
|
|
+ cFYI(1, ("can not send cmd %d while umounting",
|
|
|
+ smb_command));
|
|
|
+ return -ENODEV;
|
|
|
}
|
|
|
- if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
|
|
|
- (tcon->ses->server)) {
|
|
|
- struct nls_table *nls_codepage;
|
|
|
- /* Give Demultiplex thread up to 10 seconds to
|
|
|
- reconnect, should be greater than cifs socket
|
|
|
- timeout which is 7 seconds */
|
|
|
- while (tcon->ses->server->tcpStatus ==
|
|
|
- CifsNeedReconnect) {
|
|
|
- wait_event_interruptible_timeout(tcon->ses->server->response_q,
|
|
|
- (tcon->ses->server->tcpStatus ==
|
|
|
- CifsGood), 10 * HZ);
|
|
|
- if (tcon->ses->server->tcpStatus ==
|
|
|
- CifsNeedReconnect) {
|
|
|
- /* on "soft" mounts we wait once */
|
|
|
- if (!tcon->retry ||
|
|
|
- (tcon->ses->status == CifsExiting)) {
|
|
|
- cFYI(1, ("gave up waiting on "
|
|
|
- "reconnect in smb_init"));
|
|
|
- return -EHOSTDOWN;
|
|
|
- } /* else "hard" mount - keep retrying
|
|
|
- until process is killed or server
|
|
|
- comes back on-line */
|
|
|
- } else /* TCP session is reestablished now */
|
|
|
- break;
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- nls_codepage = load_nls_default();
|
|
|
- /* need to prevent multiple threads trying to
|
|
|
- simultaneously reconnect the same SMB session */
|
|
|
- down(&tcon->ses->sesSem);
|
|
|
- if (tcon->ses->need_reconnect)
|
|
|
- rc = cifs_setup_session(0, tcon->ses,
|
|
|
- nls_codepage);
|
|
|
- if (!rc && (tcon->need_reconnect)) {
|
|
|
- mark_open_files_invalid(tcon);
|
|
|
- rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
|
|
- tcon, nls_codepage);
|
|
|
- up(&tcon->ses->sesSem);
|
|
|
- /* BB FIXME add code to check if wsize needs
|
|
|
- update due to negotiated smb buffer size
|
|
|
- shrinking */
|
|
|
- if (rc == 0) {
|
|
|
- atomic_inc(&tconInfoReconnectCount);
|
|
|
- /* tell server Unix caps we support */
|
|
|
- if (tcon->ses->capabilities & CAP_UNIX)
|
|
|
- reset_cifs_unix_caps(
|
|
|
- 0 /* no xid */,
|
|
|
- tcon,
|
|
|
- NULL /* we do not know sb */,
|
|
|
- NULL /* no vol info */);
|
|
|
- }
|
|
|
+ if (ses->status == CifsExiting)
|
|
|
+ return -EIO;
|
|
|
|
|
|
- cFYI(1, ("reconnect tcon rc = %d", rc));
|
|
|
- /* Removed call to reopen open files here.
|
|
|
- It is safer (and faster) to reopen files
|
|
|
- one at a time as needed in read and write */
|
|
|
-
|
|
|
- /* Check if handle based operation so we
|
|
|
- know whether we can continue or not without
|
|
|
- returning to caller to reset file handle */
|
|
|
- switch (smb_command) {
|
|
|
- case SMB_COM_READ_ANDX:
|
|
|
- case SMB_COM_WRITE_ANDX:
|
|
|
- case SMB_COM_CLOSE:
|
|
|
- case SMB_COM_FIND_CLOSE2:
|
|
|
- case SMB_COM_LOCKING_ANDX: {
|
|
|
- unload_nls(nls_codepage);
|
|
|
- return -EAGAIN;
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- up(&tcon->ses->sesSem);
|
|
|
- }
|
|
|
- unload_nls(nls_codepage);
|
|
|
+ /*
|
|
|
+ * Give demultiplex thread up to 10 seconds to reconnect, should be
|
|
|
+ * greater than cifs socket timeout which is 7 seconds
|
|
|
+ */
|
|
|
+ while (server->tcpStatus == CifsNeedReconnect) {
|
|
|
+ wait_event_interruptible_timeout(server->response_q,
|
|
|
+ (server->tcpStatus == CifsGood), 10 * HZ);
|
|
|
|
|
|
- } else {
|
|
|
- return -EIO;
|
|
|
+ /* is TCP session is reestablished now ?*/
|
|
|
+ if (server->tcpStatus != CifsNeedReconnect)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * on "soft" mounts we wait once. Hard mounts keep
|
|
|
+ * retrying until process is killed or server comes
|
|
|
+ * back on-line
|
|
|
+ */
|
|
|
+ if (!tcon->retry || ses->status == CifsExiting) {
|
|
|
+ cFYI(1, ("gave up waiting on reconnect in smb_init"));
|
|
|
+ return -EHOSTDOWN;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (!ses->need_reconnect && !tcon->need_reconnect)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ nls_codepage = load_nls_default();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * need to prevent multiple threads trying to simultaneously
|
|
|
+ * reconnect the same SMB session
|
|
|
+ */
|
|
|
+ down(&ses->sesSem);
|
|
|
+ if (ses->need_reconnect)
|
|
|
+ rc = cifs_setup_session(0, ses, nls_codepage);
|
|
|
+
|
|
|
+ /* do we need to reconnect tcon? */
|
|
|
+ if (rc || !tcon->need_reconnect) {
|
|
|
+ up(&ses->sesSem);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ mark_open_files_invalid(tcon);
|
|
|
+ rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
|
|
|
+ up(&ses->sesSem);
|
|
|
+ cFYI(1, ("reconnect tcon rc = %d", rc));
|
|
|
+
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * FIXME: check if wsize needs updated due to negotiated smb buffer
|
|
|
+ * size shrinking
|
|
|
+ */
|
|
|
+ atomic_inc(&tconInfoReconnectCount);
|
|
|
+
|
|
|
+ /* tell server Unix caps we support */
|
|
|
+ if (ses->capabilities & CAP_UNIX)
|
|
|
+ reset_cifs_unix_caps(0, tcon, NULL, NULL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Removed call to reopen open files here. It is safer (and faster) to
|
|
|
+ * reopen files one at a time as needed in read and write.
|
|
|
+ *
|
|
|
+ * FIXME: what about file locks? don't we need to reclaim them ASAP?
|
|
|
+ */
|
|
|
+
|
|
|
+out:
|
|
|
+ /*
|
|
|
+ * Check if handle based operation so we know whether we can continue
|
|
|
+ * or not without returning to caller to reset file handle
|
|
|
+ */
|
|
|
+ switch (smb_command) {
|
|
|
+ case SMB_COM_READ_ANDX:
|
|
|
+ case SMB_COM_WRITE_ANDX:
|
|
|
+ case SMB_COM_CLOSE:
|
|
|
+ case SMB_COM_FIND_CLOSE2:
|
|
|
+ case SMB_COM_LOCKING_ANDX:
|
|
|
+ rc = -EAGAIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ unload_nls(nls_codepage);
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
+/* Allocate and return pointer to an SMB request buffer, and set basic
|
|
|
+ SMB information in the SMB header. If the return code is zero, this
|
|
|
+ function must have filled in request_buf pointer */
|
|
|
+static int
|
|
|
+small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|
|
+ void **request_buf)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ rc = cifs_reconnect_tcon(tcon, smb_command);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
@@ -256,101 +284,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
|
|
|
{
|
|
|
int rc = 0;
|
|
|
|
|
|
- /* 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->tidStatus == CifsExiting) {
|
|
|
- /* only tree disconnect, open, and write,
|
|
|
- (and ulogoff which does not have tcon)
|
|
|
- are allowed as we start force umount */
|
|
|
- if ((smb_command != SMB_COM_WRITE_ANDX) &&
|
|
|
- (smb_command != SMB_COM_OPEN_ANDX) &&
|
|
|
- (smb_command != SMB_COM_TREE_DISCONNECT)) {
|
|
|
- cFYI(1, ("can not send cmd %d while umounting",
|
|
|
- smb_command));
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
|
|
|
- (tcon->ses->server)) {
|
|
|
- struct nls_table *nls_codepage;
|
|
|
- /* Give Demultiplex thread up to 10 seconds to
|
|
|
- reconnect, should be greater than cifs socket
|
|
|
- timeout which is 7 seconds */
|
|
|
- while (tcon->ses->server->tcpStatus ==
|
|
|
- CifsNeedReconnect) {
|
|
|
- wait_event_interruptible_timeout(tcon->ses->server->response_q,
|
|
|
- (tcon->ses->server->tcpStatus ==
|
|
|
- CifsGood), 10 * HZ);
|
|
|
- if (tcon->ses->server->tcpStatus ==
|
|
|
- CifsNeedReconnect) {
|
|
|
- /* on "soft" mounts we wait once */
|
|
|
- if (!tcon->retry ||
|
|
|
- (tcon->ses->status == CifsExiting)) {
|
|
|
- cFYI(1, ("gave up waiting on "
|
|
|
- "reconnect in smb_init"));
|
|
|
- return -EHOSTDOWN;
|
|
|
- } /* else "hard" mount - keep retrying
|
|
|
- until process is killed or server
|
|
|
- comes on-line */
|
|
|
- } else /* TCP session is reestablished now */
|
|
|
- break;
|
|
|
- }
|
|
|
- nls_codepage = load_nls_default();
|
|
|
- /* need to prevent multiple threads trying to
|
|
|
- simultaneously reconnect the same SMB session */
|
|
|
- down(&tcon->ses->sesSem);
|
|
|
- if (tcon->ses->need_reconnect)
|
|
|
- rc = cifs_setup_session(0, tcon->ses,
|
|
|
- nls_codepage);
|
|
|
- if (!rc && (tcon->need_reconnect)) {
|
|
|
- mark_open_files_invalid(tcon);
|
|
|
- rc = CIFSTCon(0, tcon->ses, tcon->treeName,
|
|
|
- tcon, nls_codepage);
|
|
|
- up(&tcon->ses->sesSem);
|
|
|
- /* BB FIXME add code to check if wsize needs
|
|
|
- update due to negotiated smb buffer size
|
|
|
- shrinking */
|
|
|
- if (rc == 0) {
|
|
|
- atomic_inc(&tconInfoReconnectCount);
|
|
|
- /* tell server Unix caps we support */
|
|
|
- if (tcon->ses->capabilities & CAP_UNIX)
|
|
|
- reset_cifs_unix_caps(
|
|
|
- 0 /* no xid */,
|
|
|
- tcon,
|
|
|
- NULL /* do not know sb */,
|
|
|
- NULL /* no vol info */);
|
|
|
- }
|
|
|
-
|
|
|
- cFYI(1, ("reconnect tcon rc = %d", rc));
|
|
|
- /* Removed call to reopen open files here.
|
|
|
- It is safer (and faster) to reopen files
|
|
|
- one at a time as needed in read and write */
|
|
|
-
|
|
|
- /* Check if handle based operation so we
|
|
|
- know whether we can continue or not without
|
|
|
- returning to caller to reset file handle */
|
|
|
- switch (smb_command) {
|
|
|
- case SMB_COM_READ_ANDX:
|
|
|
- case SMB_COM_WRITE_ANDX:
|
|
|
- case SMB_COM_CLOSE:
|
|
|
- case SMB_COM_FIND_CLOSE2:
|
|
|
- case SMB_COM_LOCKING_ANDX: {
|
|
|
- unload_nls(nls_codepage);
|
|
|
- return -EAGAIN;
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- up(&tcon->ses->sesSem);
|
|
|
- }
|
|
|
- unload_nls(nls_codepage);
|
|
|
-
|
|
|
- } else {
|
|
|
- return -EIO;
|
|
|
- }
|
|
|
- }
|
|
|
+ rc = cifs_reconnect_tcon(tcon, smb_command);
|
|
|
if (rc)
|
|
|
return rc;
|
|
|
|
|
@@ -3961,6 +3895,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
|
|
|
if (is_unicode) {
|
|
|
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
|
|
|
GFP_KERNEL);
|
|
|
+ if (tmp == NULL) {
|
|
|
+ rc = -ENOMEM;
|
|
|
+ goto parse_DFS_referrals_exit;
|
|
|
+ }
|
|
|
cifsConvertToUCS((__le16 *) tmp, searchName,
|
|
|
PATH_MAX, nls_codepage, remap);
|
|
|
node->path_consumed = cifs_ucs2_bytes(tmp,
|