@@ -148,57 +148,6 @@ static void cifs_resolve_server(struct work_struct *work)
148
148
mutex_unlock (& server -> srv_mutex );
149
149
}
150
150
151
- #ifdef CONFIG_CIFS_DFS_UPCALL
152
- /* These functions must be called with server->srv_mutex held */
153
- static void reconn_set_next_dfs_target (struct TCP_Server_Info * server ,
154
- struct cifs_sb_info * cifs_sb ,
155
- struct dfs_cache_tgt_list * tgt_list ,
156
- struct dfs_cache_tgt_iterator * * tgt_it )
157
- {
158
- const char * name ;
159
- int rc ;
160
-
161
- if (!cifs_sb || !cifs_sb -> origin_fullpath )
162
- return ;
163
-
164
- if (!* tgt_it ) {
165
- * tgt_it = dfs_cache_get_tgt_iterator (tgt_list );
166
- } else {
167
- * tgt_it = dfs_cache_get_next_tgt (tgt_list , * tgt_it );
168
- if (!* tgt_it )
169
- * tgt_it = dfs_cache_get_tgt_iterator (tgt_list );
170
- }
171
-
172
- cifs_dbg (FYI , "%s: UNC: %s\n" , __func__ , cifs_sb -> origin_fullpath );
173
-
174
- name = dfs_cache_get_tgt_name (* tgt_it );
175
-
176
- kfree (server -> hostname );
177
-
178
- server -> hostname = extract_hostname (name );
179
- if (IS_ERR (server -> hostname )) {
180
- cifs_dbg (FYI ,
181
- "%s: failed to extract hostname from target: %ld\n" ,
182
- __func__ , PTR_ERR (server -> hostname ));
183
- return ;
184
- }
185
-
186
- rc = reconn_set_ipaddr_from_hostname (server );
187
- if (rc ) {
188
- cifs_dbg (FYI , "%s: failed to resolve hostname: %d\n" ,
189
- __func__ , rc );
190
- }
191
- }
192
-
193
- static inline int reconn_setup_dfs_targets (struct cifs_sb_info * cifs_sb ,
194
- struct dfs_cache_tgt_list * tl )
195
- {
196
- if (!cifs_sb -> origin_fullpath )
197
- return - EOPNOTSUPP ;
198
- return dfs_cache_noreq_find (cifs_sb -> origin_fullpath + 1 , NULL , tl );
199
- }
200
- #endif
201
-
202
151
/**
203
152
* Mark all sessions and tcons for reconnect.
204
153
*
@@ -278,6 +227,21 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
278
227
}
279
228
}
280
229
230
+ static bool cifs_tcp_ses_needs_reconnect (struct TCP_Server_Info * server , int num_targets )
231
+ {
232
+ spin_lock (& GlobalMid_Lock );
233
+ server -> nr_targets = num_targets ;
234
+ if (server -> tcpStatus == CifsExiting ) {
235
+ /* the demux thread will exit normally next time through the loop */
236
+ spin_unlock (& GlobalMid_Lock );
237
+ wake_up (& server -> response_q );
238
+ return false;
239
+ }
240
+ server -> tcpStatus = CifsNeedReconnect ;
241
+ spin_unlock (& GlobalMid_Lock );
242
+ return true;
243
+ }
244
+
281
245
/*
282
246
* cifs tcp session reconnection
283
247
*
@@ -286,99 +250,32 @@ static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server
286
250
* reconnect tcp session
287
251
* wake up waiters on reconnection? - (not needed currently)
288
252
*/
289
- int
290
- cifs_reconnect (struct TCP_Server_Info * server )
253
+ static int __cifs_reconnect (struct TCP_Server_Info * server )
291
254
{
292
255
int rc = 0 ;
293
- #ifdef CONFIG_CIFS_DFS_UPCALL
294
- struct super_block * sb = NULL ;
295
- struct cifs_sb_info * cifs_sb = NULL ;
296
- struct dfs_cache_tgt_list tgt_list = DFS_CACHE_TGT_LIST_INIT (tgt_list );
297
- struct dfs_cache_tgt_iterator * tgt_it = NULL ;
298
- #endif
299
256
300
- spin_lock (& GlobalMid_Lock );
301
- server -> nr_targets = 1 ;
302
- #ifdef CONFIG_CIFS_DFS_UPCALL
303
- spin_unlock (& GlobalMid_Lock );
304
- sb = cifs_get_tcp_super (server );
305
- if (IS_ERR (sb )) {
306
- rc = PTR_ERR (sb );
307
- cifs_dbg (FYI , "%s: will not do DFS failover: rc = %d\n" ,
308
- __func__ , rc );
309
- sb = NULL ;
310
- } else {
311
- cifs_sb = CIFS_SB (sb );
312
- rc = reconn_setup_dfs_targets (cifs_sb , & tgt_list );
313
- if (rc ) {
314
- cifs_sb = NULL ;
315
- if (rc != - EOPNOTSUPP ) {
316
- cifs_server_dbg (VFS , "%s: no target servers for DFS failover\n" ,
317
- __func__ );
318
- }
319
- } else {
320
- server -> nr_targets = dfs_cache_get_nr_tgts (& tgt_list );
321
- }
322
- }
323
- cifs_dbg (FYI , "%s: will retry %d target(s)\n" , __func__ ,
324
- server -> nr_targets );
325
- spin_lock (& GlobalMid_Lock );
326
- #endif
327
- if (server -> tcpStatus == CifsExiting ) {
328
- /* the demux thread will exit normally next time through the loop */
329
- spin_unlock (& GlobalMid_Lock );
330
- #ifdef CONFIG_CIFS_DFS_UPCALL
331
- dfs_cache_free_tgts (& tgt_list );
332
- cifs_put_tcp_super (sb );
333
- #endif
334
- wake_up (& server -> response_q );
335
- return rc ;
336
- } else
337
- server -> tcpStatus = CifsNeedReconnect ;
338
- spin_unlock (& GlobalMid_Lock );
257
+ if (!cifs_tcp_ses_needs_reconnect (server , 1 ))
258
+ return 0 ;
339
259
340
260
cifs_mark_tcp_ses_conns_for_reconnect (server );
341
261
342
262
do {
343
263
try_to_freeze ();
344
-
345
264
mutex_lock (& server -> srv_mutex );
346
265
347
-
348
266
if (!cifs_swn_set_server_dstaddr (server )) {
349
- #ifdef CONFIG_CIFS_DFS_UPCALL
350
- if (cifs_sb && cifs_sb -> origin_fullpath )
351
- /*
352
- * Set up next DFS target server (if any) for reconnect. If DFS
353
- * feature is disabled, then we will retry last server we
354
- * connected to before.
355
- */
356
- reconn_set_next_dfs_target (server , cifs_sb , & tgt_list , & tgt_it );
357
- else {
358
- #endif
359
- /*
360
- * Resolve the hostname again to make sure that IP address is up-to-date.
361
- */
267
+ /* resolve the hostname again to make sure that IP address is up-to-date */
362
268
rc = reconn_set_ipaddr_from_hostname (server );
363
- if (rc ) {
364
- cifs_dbg (FYI , "%s: failed to resolve hostname: %d\n" ,
365
- __func__ , rc );
366
- }
367
-
368
- #ifdef CONFIG_CIFS_DFS_UPCALL
369
- }
370
- #endif
371
-
372
-
269
+ cifs_dbg (FYI , "%s: reconn_set_ipaddr_from_hostname: rc=%d\n" , __func__ , rc );
373
270
}
374
271
375
272
if (cifs_rdma_enabled (server ))
376
273
rc = smbd_reconnect (server );
377
274
else
378
275
rc = generic_ip_connect (server );
379
276
if (rc ) {
380
- cifs_dbg (FYI , "reconnect error %d\n" , rc );
381
277
mutex_unlock (& server -> srv_mutex );
278
+ cifs_dbg (FYI , "%s: reconnect error %d\n" , __func__ , rc );
382
279
msleep (3000 );
383
280
} else {
384
281
atomic_inc (& tcpSesReconnectCount );
@@ -392,26 +289,158 @@ cifs_reconnect(struct TCP_Server_Info *server)
392
289
}
393
290
} while (server -> tcpStatus == CifsNeedReconnect );
394
291
292
+ if (server -> tcpStatus == CifsNeedNegotiate )
293
+ mod_delayed_work (cifsiod_wq , & server -> echo , 0 );
294
+
295
+ wake_up (& server -> response_q );
296
+ return rc ;
297
+ }
298
+
395
299
#ifdef CONFIG_CIFS_DFS_UPCALL
396
- if (tgt_it ) {
397
- rc = dfs_cache_noreq_update_tgthint (cifs_sb -> origin_fullpath + 1 ,
398
- tgt_it );
300
+ static int reconnect_dfs_server (struct TCP_Server_Info * server , struct cifs_sb_info * cifs_sb )
301
+ {
302
+ int rc = 0 ;
303
+ const char * refpath = cifs_sb -> origin_fullpath + 1 ;
304
+ struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT (tl );
305
+ struct dfs_cache_tgt_iterator * tit = NULL ;
306
+ int num_targets = 1 ;
307
+ char * hostname ;
308
+
309
+ /*
310
+ * Determine the number of dfs targets the referral path in @cifs_sb resolves to.
311
+ *
312
+ * smb2_reconnect() needs to know how long it should wait based upon the number of dfs
313
+ * targets (server->nr_targets). It's also possible that the cached referral was cleared
314
+ * through /proc/fs/cifs/dfscache or the target list is empty due to server settings after
315
+ * refreshing the referral, so, in this case, default it to 1.
316
+ */
317
+ if (!dfs_cache_noreq_find (refpath , NULL , & tl )) {
318
+ num_targets = dfs_cache_get_nr_tgts (& tl );
319
+ if (!num_targets )
320
+ num_targets = 1 ;
321
+ }
322
+
323
+ if (!cifs_tcp_ses_needs_reconnect (server , num_targets ))
324
+ return 0 ;
325
+
326
+ cifs_mark_tcp_ses_conns_for_reconnect (server );
327
+
328
+ do {
329
+ /* Get next dfs target from target list (if any) */
330
+ if (!tit )
331
+ tit = dfs_cache_get_tgt_iterator (& tl );
332
+ else
333
+ tit = dfs_cache_get_next_tgt (& tl , tit );
334
+
335
+ try_to_freeze ();
336
+ mutex_lock (& server -> srv_mutex );
337
+
338
+ if (!cifs_swn_set_server_dstaddr (server )) {
339
+ /*
340
+ * If any dfs target was selected, then update @server with either a
341
+ * hostname or an address.
342
+ */
343
+ if (tit ) {
344
+ hostname = extract_hostname (dfs_cache_get_tgt_name (tit ));
345
+ if (!IS_ERR (hostname )) {
346
+ kfree (server -> hostname );
347
+ server -> hostname = hostname ;
348
+ } else {
349
+ cifs_dbg (FYI , "%s: couldn't extract hostname or address from dfs target: %ld\n" ,
350
+ __func__ , PTR_ERR (hostname ));
351
+ cifs_dbg (FYI , "%s: default to last target server: %s\n" ,
352
+ __func__ , server -> hostname );
353
+ }
354
+ }
355
+ /* resolve the hostname again to make sure that IP address is up-to-date. */
356
+ rc = reconn_set_ipaddr_from_hostname (server );
357
+ cifs_dbg (FYI , "%s: reconn_set_ipaddr_from_hostname: rc=%d\n" , __func__ , rc );
358
+ }
359
+
360
+ /* Reconnect the socket */
361
+ if (cifs_rdma_enabled (server ))
362
+ rc = smbd_reconnect (server );
363
+ else
364
+ rc = generic_ip_connect (server );
365
+
399
366
if (rc ) {
400
- cifs_server_dbg (VFS , "%s: failed to update DFS target hint: rc = %d\n" ,
401
- __func__ , rc );
367
+ /* Failed to reconnect socket. Retry next dfs target. */
368
+ mutex_unlock (& server -> srv_mutex );
369
+ cifs_dbg (FYI , "%s: reconnect error %d\n" , __func__ , rc );
370
+ msleep (3000 );
371
+ continue ;
402
372
}
403
- dfs_cache_free_tgts (& tgt_list );
404
- }
405
373
406
- cifs_put_tcp_super (sb );
407
- #endif
374
+ /*
375
+ * Socket was created. Update tcp session status to CifsNeedNegotiate so that a
376
+ * process waiting for reconnect will know it needs to re-establish session and tcon
377
+ * through the reconnected target server.
378
+ */
379
+ atomic_inc (& tcpSesReconnectCount );
380
+ set_credits (server , 1 );
381
+ spin_lock (& GlobalMid_Lock );
382
+ if (server -> tcpStatus != CifsExiting )
383
+ server -> tcpStatus = CifsNeedNegotiate ;
384
+ spin_unlock (& GlobalMid_Lock );
385
+ cifs_swn_reset_server_dstaddr (server );
386
+ mutex_unlock (& server -> srv_mutex );
387
+ } while (server -> tcpStatus == CifsNeedReconnect );
388
+
389
+ if (tit )
390
+ dfs_cache_noreq_update_tgthint (refpath , tit );
391
+
392
+ dfs_cache_free_tgts (& tl );
393
+
394
+ /* Need to set up echo worker again once connection has been established */
408
395
if (server -> tcpStatus == CifsNeedNegotiate )
409
396
mod_delayed_work (cifsiod_wq , & server -> echo , 0 );
410
397
411
398
wake_up (& server -> response_q );
412
399
return rc ;
413
400
}
414
401
402
+ int cifs_reconnect (struct TCP_Server_Info * server )
403
+ {
404
+ int rc ;
405
+ struct super_block * sb ;
406
+ struct cifs_sb_info * cifs_sb ;
407
+
408
+ /*
409
+ * If tcp session is not an dfs connection or it is a channel, then reconnect to last target
410
+ * server.
411
+ */
412
+ spin_lock (& cifs_tcp_ses_lock );
413
+ if (!server -> is_dfs_conn || server -> is_channel ) {
414
+ spin_unlock (& cifs_tcp_ses_lock );
415
+ return __cifs_reconnect (server );
416
+ }
417
+ spin_unlock (& cifs_tcp_ses_lock );
418
+
419
+ /* If no superblock, then it might be an ipc connection */
420
+ sb = cifs_get_tcp_super (server );
421
+ if (IS_ERR (sb ))
422
+ return __cifs_reconnect (server );
423
+
424
+ /*
425
+ * Check for a referral path to look up in superblock. If unset, then simply reconnect to
426
+ * last target server.
427
+ */
428
+ cifs_sb = CIFS_SB (sb );
429
+ if (!cifs_sb -> origin_fullpath || !cifs_sb -> origin_fullpath [0 ])
430
+ rc = __cifs_reconnect (server );
431
+ else
432
+ rc = reconnect_dfs_server (server , cifs_sb );
433
+
434
+ cifs_put_tcp_super (sb );
435
+ return rc ;
436
+ }
437
+ #else
438
+ int cifs_reconnect (struct TCP_Server_Info * server )
439
+ {
440
+ return __cifs_reconnect (server );
441
+ }
442
+ #endif
443
+
415
444
static void
416
445
cifs_echo_request (struct work_struct * work )
417
446
{
0 commit comments