aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2011-12-27 07:23:34 -0500
committerPavel Shilovsky <pshilovsky@samba.org>2012-07-24 13:54:59 -0400
commitaa24d1e9692411e605084938ced6b160f92df454 (patch)
tree399446513c2437af67ca8ed065ba16f272715bb4 /fs
parentfaaf946a7d5b79194358437150f34ab4c66bfe21 (diff)
CIFS: Process reconnects for SMB2 shares
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/cifssmb.c21
-rw-r--r--fs/cifs/connect.c3
-rw-r--r--fs/cifs/smb2pdu.c127
4 files changed, 143 insertions, 9 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 3b4d41f9ceeb..61baaa3330fb 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -171,6 +171,7 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data,
171 const char *devname); 171 const char *devname);
172extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); 172extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
173extern void cifs_umount(struct cifs_sb_info *); 173extern void cifs_umount(struct cifs_sb_info *);
174extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
174 175
175#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) 176#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
176extern void cifs_dfs_release_automount_timer(void); 177extern void cifs_dfs_release_automount_timer(void);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index dcb0ad87e173..f1dfc7844f1b 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -112,24 +112,29 @@ cifs_kmap_unlock(void)
112#define cifs_kmap_unlock() do { ; } while(0) 112#define cifs_kmap_unlock() do { ; } while(0)
113#endif /* CONFIG_HIGHMEM */ 113#endif /* CONFIG_HIGHMEM */
114 114
115/* Mark as invalid, all open files on tree connections since they 115/*
116 were closed when session to server was lost */ 116 * Mark as invalid, all open files on tree connections since they
117static void mark_open_files_invalid(struct cifs_tcon *pTcon) 117 * were closed when session to server was lost.
118 */
119void
120cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
118{ 121{
119 struct cifsFileInfo *open_file = NULL; 122 struct cifsFileInfo *open_file = NULL;
120 struct list_head *tmp; 123 struct list_head *tmp;
121 struct list_head *tmp1; 124 struct list_head *tmp1;
122 125
123/* list all files open on tree connection and mark them invalid */ 126 /* list all files open on tree connection and mark them invalid */
124 spin_lock(&cifs_file_list_lock); 127 spin_lock(&cifs_file_list_lock);
125 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { 128 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
126 open_file = list_entry(tmp, struct cifsFileInfo, tlist); 129 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
127 open_file->invalidHandle = true; 130 open_file->invalidHandle = true;
128 open_file->oplock_break_cancelled = true; 131 open_file->oplock_break_cancelled = true;
129 } 132 }
130 spin_unlock(&cifs_file_list_lock); 133 spin_unlock(&cifs_file_list_lock);
131 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted 134 /*
132 to this tcon */ 135 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
136 * to this tcon.
137 */
133} 138}
134 139
135/* reconnect the socket, tcon, and smb session if needed */ 140/* reconnect the socket, tcon, and smb session if needed */
@@ -209,7 +214,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
209 goto out; 214 goto out;
210 } 215 }
211 216
212 mark_open_files_invalid(tcon); 217 cifs_mark_open_files_invalid(tcon);
213 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); 218 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
214 mutex_unlock(&ses->session_mutex); 219 mutex_unlock(&ses->session_mutex);
215 cFYI(1, "reconnect tcon rc = %d", rc); 220 cFYI(1, "reconnect tcon rc = %d", rc);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a6197224b102..7cf8b1632242 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -317,6 +317,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
317 server->tcpStatus = CifsNeedReconnect; 317 server->tcpStatus = CifsNeedReconnect;
318 spin_unlock(&GlobalMid_Lock); 318 spin_unlock(&GlobalMid_Lock);
319 server->maxBuf = 0; 319 server->maxBuf = 0;
320#ifdef CONFIG_CIFS_SMB2
321 server->max_read = 0;
322#endif
320 323
321 cFYI(1, "Reconnecting tcp session"); 324 cFYI(1, "Reconnecting tcp session");
322 325
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 1bf037ec5a9d..48c04b2832e2 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -127,7 +127,132 @@ static int
127smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) 127smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
128{ 128{
129 int rc = 0; 129 int rc = 0;
130 /* BB add missing code here */ 130 struct nls_table *nls_codepage;
131 struct cifs_ses *ses;
132 struct TCP_Server_Info *server;
133
134 /*
135 * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
136 * check for tcp and smb session status done differently
137 * for those three - in the calling routine.
138 */
139 if (tcon == NULL)
140 return rc;
141
142 if (smb2_command == SMB2_TREE_CONNECT)
143 return rc;
144
145 if (tcon->tidStatus == CifsExiting) {
146 /*
147 * only tree disconnect, open, and write,
148 * (and ulogoff which does not have tcon)
149 * are allowed as we start force umount.
150 */
151 if ((smb2_command != SMB2_WRITE) &&
152 (smb2_command != SMB2_CREATE) &&
153 (smb2_command != SMB2_TREE_DISCONNECT)) {
154 cFYI(1, "can not send cmd %d while umounting",
155 smb2_command);
156 return -ENODEV;
157 }
158 }
159 if ((!tcon->ses) || (tcon->ses->status == CifsExiting) ||
160 (!tcon->ses->server))
161 return -EIO;
162
163 ses = tcon->ses;
164 server = ses->server;
165
166 /*
167 * Give demultiplex thread up to 10 seconds to reconnect, should be
168 * greater than cifs socket timeout which is 7 seconds
169 */
170 while (server->tcpStatus == CifsNeedReconnect) {
171 /*
172 * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
173 * here since they are implicitly done when session drops.
174 */
175 switch (smb2_command) {
176 /*
177 * BB Should we keep oplock break and add flush to exceptions?
178 */
179 case SMB2_TREE_DISCONNECT:
180 case SMB2_CANCEL:
181 case SMB2_CLOSE:
182 case SMB2_OPLOCK_BREAK:
183 return -EAGAIN;
184 }
185
186 wait_event_interruptible_timeout(server->response_q,
187 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
188
189 /* are we still trying to reconnect? */
190 if (server->tcpStatus != CifsNeedReconnect)
191 break;
192
193 /*
194 * on "soft" mounts we wait once. Hard mounts keep
195 * retrying until process is killed or server comes
196 * back on-line
197 */
198 if (!tcon->retry) {
199 cFYI(1, "gave up waiting on reconnect in smb_init");
200 return -EHOSTDOWN;
201 }
202 }
203
204 if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
205 return rc;
206
207 nls_codepage = load_nls_default();
208
209 /*
210 * need to prevent multiple threads trying to simultaneously reconnect
211 * the same SMB session
212 */
213 mutex_lock(&tcon->ses->session_mutex);
214 rc = cifs_negotiate_protocol(0, tcon->ses);
215 if (!rc && tcon->ses->need_reconnect)
216 rc = cifs_setup_session(0, tcon->ses, nls_codepage);
217
218 if (rc || !tcon->need_reconnect) {
219 mutex_unlock(&tcon->ses->session_mutex);
220 goto out;
221 }
222
223 cifs_mark_open_files_invalid(tcon);
224 rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
225 mutex_unlock(&tcon->ses->session_mutex);
226 cFYI(1, "reconnect tcon rc = %d", rc);
227 if (rc)
228 goto out;
229 atomic_inc(&tconInfoReconnectCount);
230 /*
231 * BB FIXME add code to check if wsize needs update due to negotiated
232 * smb buffer size shrinking.
233 */
234out:
235 /*
236 * Check if handle based operation so we know whether we can continue
237 * or not without returning to caller to reset file handle.
238 */
239 /*
240 * BB Is flush done by server on drop of tcp session? Should we special
241 * case it and skip above?
242 */
243 switch (smb2_command) {
244 case SMB2_FLUSH:
245 case SMB2_READ:
246 case SMB2_WRITE:
247 case SMB2_LOCK:
248 case SMB2_IOCTL:
249 case SMB2_QUERY_DIRECTORY:
250 case SMB2_CHANGE_NOTIFY:
251 case SMB2_QUERY_INFO:
252 case SMB2_SET_INFO:
253 return -EAGAIN;
254 }
255 unload_nls(nls_codepage);
131 return rc; 256 return rc;
132} 257}
133 258