Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9162ab20 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French
Browse files

cifs: consolidate reconnect logic in smb_init routines



There's a large cut and paste chunk of code in smb_init and
small_smb_init to handle reconnects. Break it out into a separate
function, clean it up and have both routines call it.

Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 6ab409b5
Loading
Loading
Loading
Loading
+123 −189
Original line number Diff line number Diff line
@@ -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) {
	/*
	 * 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) {
			/* 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)) {
		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 */

	if (ses->status == CifsExiting)
		return -EIO;

	/*
	 * 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);

		/* 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(&tcon->ses->sesSem);
			if (tcon->ses->need_reconnect)
				rc = cifs_setup_session(0, tcon->ses,
							nls_codepage);
			if (!rc && (tcon->need_reconnect)) {

	/*
	 * 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, 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) {
	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 (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->capabilities & CAP_UNIX)
		reset_cifs_unix_caps(0, tcon, NULL, NULL);

				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 */
	/*
	 * 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?
	 */

				/* Check if handle based operation so we
				   know whether we can continue or not without
				   returning to caller to reset file handle */
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: {
						unload_nls(nls_codepage);
						return -EAGAIN;
	case SMB_COM_LOCKING_ANDX:
		rc = -EAGAIN;
	}
				}
			} else {
				up(&tcon->ses->sesSem);
			}
			unload_nls(nls_codepage);

		} else {
			return -EIO;
		}
	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;