Loading fs/cifs/cifsproto.h +1 −0 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data, const char *devname); extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) extern void cifs_dfs_release_automount_timer(void); Loading fs/cifs/cifssmb.c +13 −8 Original line number Diff line number Diff line Loading @@ -112,9 +112,12 @@ cifs_kmap_unlock(void) #define cifs_kmap_unlock() do { ; } while(0) #endif /* CONFIG_HIGHMEM */ /* Mark as invalid, all open files on tree connections since they were closed when session to server was lost */ static void mark_open_files_invalid(struct cifs_tcon *pTcon) /* * Mark as invalid, all open files on tree connections since they * were closed when session to server was lost. */ void cifs_mark_open_files_invalid(struct cifs_tcon *tcon) { struct cifsFileInfo *open_file = NULL; struct list_head *tmp; Loading @@ -122,14 +125,16 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon) /* list all files open on tree connection and mark them invalid */ spin_lock(&cifs_file_list_lock); list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { list_for_each_safe(tmp, tmp1, &tcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file->invalidHandle = true; open_file->oplock_break_cancelled = true; } spin_unlock(&cifs_file_list_lock); /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ /* * BB Add call to invalidate_inodes(sb) for all superblocks mounted * to this tcon. */ } /* reconnect the socket, tcon, and smb session if needed */ Loading Loading @@ -209,7 +214,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) goto out; } mark_open_files_invalid(tcon); cifs_mark_open_files_invalid(tcon); rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); mutex_unlock(&ses->session_mutex); cFYI(1, "reconnect tcon rc = %d", rc); Loading fs/cifs/connect.c +3 −0 Original line number Diff line number Diff line Loading @@ -317,6 +317,9 @@ cifs_reconnect(struct TCP_Server_Info *server) server->tcpStatus = CifsNeedReconnect; spin_unlock(&GlobalMid_Lock); server->maxBuf = 0; #ifdef CONFIG_CIFS_SMB2 server->max_read = 0; #endif cFYI(1, "Reconnecting tcp session"); Loading fs/cifs/smb2pdu.c +126 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,132 @@ static int smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) { int rc = 0; /* BB add missing code here */ struct nls_table *nls_codepage; struct cifs_ses *ses; struct TCP_Server_Info *server; /* * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so * check for tcp and smb session status done differently * for those three - in the calling routine. */ if (tcon == NULL) return rc; if (smb2_command == SMB2_TREE_CONNECT) return rc; 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 ((smb2_command != SMB2_WRITE) && (smb2_command != SMB2_CREATE) && (smb2_command != SMB2_TREE_DISCONNECT)) { cFYI(1, "can not send cmd %d while umounting", smb2_command); return -ENODEV; } } if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || (!tcon->ses->server)) return -EIO; ses = tcon->ses; server = ses->server; /* * Give demultiplex thread up to 10 seconds to reconnect, should be * greater than cifs socket timeout which is 7 seconds */ while (server->tcpStatus == CifsNeedReconnect) { /* * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE * here since they are implicitly done when session drops. */ switch (smb2_command) { /* * BB Should we keep oplock break and add flush to exceptions? */ case SMB2_TREE_DISCONNECT: case SMB2_CANCEL: case SMB2_CLOSE: case SMB2_OPLOCK_BREAK: return -EAGAIN; } wait_event_interruptible_timeout(server->response_q, (server->tcpStatus != CifsNeedReconnect), 10 * HZ); /* are we still trying to reconnect? */ 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) { cFYI(1, "gave up waiting on reconnect in smb_init"); return -EHOSTDOWN; } } if (!tcon->ses->need_reconnect && !tcon->need_reconnect) return rc; nls_codepage = load_nls_default(); /* * need to prevent multiple threads trying to simultaneously reconnect * the same SMB session */ mutex_lock(&tcon->ses->session_mutex); rc = cifs_negotiate_protocol(0, tcon->ses); if (!rc && tcon->ses->need_reconnect) rc = cifs_setup_session(0, tcon->ses, nls_codepage); if (rc || !tcon->need_reconnect) { mutex_unlock(&tcon->ses->session_mutex); goto out; } cifs_mark_open_files_invalid(tcon); rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); mutex_unlock(&tcon->ses->session_mutex); cFYI(1, "reconnect tcon rc = %d", rc); if (rc) goto out; atomic_inc(&tconInfoReconnectCount); /* * BB FIXME add code to check if wsize needs update due to negotiated * smb buffer size shrinking. */ out: /* * Check if handle based operation so we know whether we can continue * or not without returning to caller to reset file handle. */ /* * BB Is flush done by server on drop of tcp session? Should we special * case it and skip above? */ switch (smb2_command) { case SMB2_FLUSH: case SMB2_READ: case SMB2_WRITE: case SMB2_LOCK: case SMB2_IOCTL: case SMB2_QUERY_DIRECTORY: case SMB2_CHANGE_NOTIFY: case SMB2_QUERY_INFO: case SMB2_SET_INFO: return -EAGAIN; } unload_nls(nls_codepage); return rc; } Loading Loading
fs/cifs/cifsproto.h +1 −0 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data, const char *devname); extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); extern void cifs_umount(struct cifs_sb_info *); extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) extern void cifs_dfs_release_automount_timer(void); Loading
fs/cifs/cifssmb.c +13 −8 Original line number Diff line number Diff line Loading @@ -112,9 +112,12 @@ cifs_kmap_unlock(void) #define cifs_kmap_unlock() do { ; } while(0) #endif /* CONFIG_HIGHMEM */ /* Mark as invalid, all open files on tree connections since they were closed when session to server was lost */ static void mark_open_files_invalid(struct cifs_tcon *pTcon) /* * Mark as invalid, all open files on tree connections since they * were closed when session to server was lost. */ void cifs_mark_open_files_invalid(struct cifs_tcon *tcon) { struct cifsFileInfo *open_file = NULL; struct list_head *tmp; Loading @@ -122,14 +125,16 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon) /* list all files open on tree connection and mark them invalid */ spin_lock(&cifs_file_list_lock); list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { list_for_each_safe(tmp, tmp1, &tcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file->invalidHandle = true; open_file->oplock_break_cancelled = true; } spin_unlock(&cifs_file_list_lock); /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ /* * BB Add call to invalidate_inodes(sb) for all superblocks mounted * to this tcon. */ } /* reconnect the socket, tcon, and smb session if needed */ Loading Loading @@ -209,7 +214,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) goto out; } mark_open_files_invalid(tcon); cifs_mark_open_files_invalid(tcon); rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); mutex_unlock(&ses->session_mutex); cFYI(1, "reconnect tcon rc = %d", rc); Loading
fs/cifs/connect.c +3 −0 Original line number Diff line number Diff line Loading @@ -317,6 +317,9 @@ cifs_reconnect(struct TCP_Server_Info *server) server->tcpStatus = CifsNeedReconnect; spin_unlock(&GlobalMid_Lock); server->maxBuf = 0; #ifdef CONFIG_CIFS_SMB2 server->max_read = 0; #endif cFYI(1, "Reconnecting tcp session"); Loading
fs/cifs/smb2pdu.c +126 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,132 @@ static int smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) { int rc = 0; /* BB add missing code here */ struct nls_table *nls_codepage; struct cifs_ses *ses; struct TCP_Server_Info *server; /* * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so * check for tcp and smb session status done differently * for those three - in the calling routine. */ if (tcon == NULL) return rc; if (smb2_command == SMB2_TREE_CONNECT) return rc; 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 ((smb2_command != SMB2_WRITE) && (smb2_command != SMB2_CREATE) && (smb2_command != SMB2_TREE_DISCONNECT)) { cFYI(1, "can not send cmd %d while umounting", smb2_command); return -ENODEV; } } if ((!tcon->ses) || (tcon->ses->status == CifsExiting) || (!tcon->ses->server)) return -EIO; ses = tcon->ses; server = ses->server; /* * Give demultiplex thread up to 10 seconds to reconnect, should be * greater than cifs socket timeout which is 7 seconds */ while (server->tcpStatus == CifsNeedReconnect) { /* * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE * here since they are implicitly done when session drops. */ switch (smb2_command) { /* * BB Should we keep oplock break and add flush to exceptions? */ case SMB2_TREE_DISCONNECT: case SMB2_CANCEL: case SMB2_CLOSE: case SMB2_OPLOCK_BREAK: return -EAGAIN; } wait_event_interruptible_timeout(server->response_q, (server->tcpStatus != CifsNeedReconnect), 10 * HZ); /* are we still trying to reconnect? */ 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) { cFYI(1, "gave up waiting on reconnect in smb_init"); return -EHOSTDOWN; } } if (!tcon->ses->need_reconnect && !tcon->need_reconnect) return rc; nls_codepage = load_nls_default(); /* * need to prevent multiple threads trying to simultaneously reconnect * the same SMB session */ mutex_lock(&tcon->ses->session_mutex); rc = cifs_negotiate_protocol(0, tcon->ses); if (!rc && tcon->ses->need_reconnect) rc = cifs_setup_session(0, tcon->ses, nls_codepage); if (rc || !tcon->need_reconnect) { mutex_unlock(&tcon->ses->session_mutex); goto out; } cifs_mark_open_files_invalid(tcon); rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); mutex_unlock(&tcon->ses->session_mutex); cFYI(1, "reconnect tcon rc = %d", rc); if (rc) goto out; atomic_inc(&tconInfoReconnectCount); /* * BB FIXME add code to check if wsize needs update due to negotiated * smb buffer size shrinking. */ out: /* * Check if handle based operation so we know whether we can continue * or not without returning to caller to reset file handle. */ /* * BB Is flush done by server on drop of tcp session? Should we special * case it and skip above? */ switch (smb2_command) { case SMB2_FLUSH: case SMB2_READ: case SMB2_WRITE: case SMB2_LOCK: case SMB2_IOCTL: case SMB2_QUERY_DIRECTORY: case SMB2_CHANGE_NOTIFY: case SMB2_QUERY_INFO: case SMB2_SET_INFO: return -EAGAIN; } unload_nls(nls_codepage); return rc; } Loading