Skip to content

Commit c9f7110

Browse files
Paulo AlcantaraSteve French
authored andcommitted
cifs: keep referral server sessions alive
At every mount, keep all sessions alive that were used for chasing the DFS referrals as long as the dfs mounts are active. Use those sessions in DFS cache to refresh all active tcons as well as cached entries. They will be managed by a list of mount_group structures that will be indexed by a randomly generated uuid at mount time, so we can put all the sessions related to specific dfs mounts and avoid leaking them. Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Reviewed-by: Aurelien Aptel <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 2b133b7 commit c9f7110

File tree

4 files changed

+275
-468
lines changed

4 files changed

+275
-468
lines changed

fs/cifs/cifs_fs_sb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ struct cifs_sb_info {
7777
* failover properly.
7878
*/
7979
char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
80+
/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
81+
uuid_t dfs_mount_id;
8082
/*
8183
* Indicate whether serverino option was turned off later
8284
* (cifs_autodisable_serverino) in order to match new mounts.

fs/cifs/connect.c

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
368368
cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
369369
__func__, rc);
370370
}
371-
rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
372-
if (rc) {
373-
cifs_server_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
374-
__func__, rc);
375-
}
376371
dfs_cache_free_tgts(&tgt_list);
377-
378372
}
379373

380374
cifs_put_tcp_super(sb);
@@ -1601,14 +1595,17 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
16011595
{
16021596
unsigned int rc, xid;
16031597
struct TCP_Server_Info *server = ses->server;
1604-
16051598
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
16061599

16071600
spin_lock(&cifs_tcp_ses_lock);
16081601
if (ses->status == CifsExiting) {
16091602
spin_unlock(&cifs_tcp_ses_lock);
16101603
return;
16111604
}
1605+
1606+
cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
1607+
cifs_dbg(FYI, "%s: ses ipc: %s\n", __func__, ses->tcon_ipc ? ses->tcon_ipc->treeName : "NONE");
1608+
16121609
if (--ses->ses_count > 0) {
16131610
spin_unlock(&cifs_tcp_ses_lock);
16141611
return;
@@ -3284,25 +3281,23 @@ static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *
32843281
}
32853282

32863283
#ifdef CONFIG_CIFS_DFS_UPCALL
3287-
static void set_root_ses(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
3284+
static void set_root_ses(struct cifs_sb_info *cifs_sb, const uuid_t *mount_id, struct cifs_ses *ses,
32883285
struct cifs_ses **root_ses)
32893286
{
32903287
if (ses) {
32913288
spin_lock(&cifs_tcp_ses_lock);
32923289
ses->ses_count++;
3293-
if (ses->tcon_ipc)
3290+
cifs_dbg(FYI, "%s: new ses_count=%d\n", __func__, ses->ses_count);
3291+
if (ses->tcon_ipc) {
3292+
cifs_dbg(FYI, "%s: ipc tcon: %s\n", __func__, ses->tcon_ipc->treeName);
32943293
ses->tcon_ipc->remap = cifs_remap(cifs_sb);
3294+
}
32953295
spin_unlock(&cifs_tcp_ses_lock);
3296+
dfs_cache_add_refsrv_session(mount_id, ses);
32963297
}
32973298
*root_ses = ses;
32983299
}
32993300

3300-
static void put_root_ses(struct cifs_ses *ses)
3301-
{
3302-
if (ses)
3303-
cifs_put_smb_ses(ses);
3304-
}
3305-
33063301
/* Set up next dfs prefix path in @dfs_path */
33073302
static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
33083303
const unsigned int xid, struct TCP_Server_Info *server,
@@ -3382,9 +3377,9 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
33823377
struct cifs_ses *ses = NULL, *root_ses = NULL;
33833378
struct cifs_tcon *tcon = NULL;
33843379
int count = 0;
3380+
uuid_t mount_id = {0};
33853381
char *ref_path = NULL, *full_path = NULL;
33863382
char *oldmnt = NULL;
3387-
char *mntdata = NULL;
33883383
bool ref_server = false;
33893384

33903385
rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
@@ -3407,12 +3402,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34073402
if (rc != -EREMOTE)
34083403
goto error;
34093404
}
3410-
/* Save mount options */
3411-
mntdata = kstrdup(cifs_sb->ctx->mount_options, GFP_KERNEL);
3412-
if (!mntdata) {
3413-
rc = -ENOMEM;
3414-
goto error;
3415-
}
3405+
34163406
/* Get path of DFS root */
34173407
ref_path = build_unc_path_to_root(ctx, cifs_sb, false);
34183408
if (IS_ERR(ref_path)) {
@@ -3421,7 +3411,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34213411
goto error;
34223412
}
34233413

3424-
set_root_ses(cifs_sb, ses, &root_ses);
3414+
uuid_gen(&mount_id);
3415+
set_root_ses(cifs_sb, &mount_id, ses, &root_ses);
34253416
do {
34263417
/* Save full path of last DFS path we used to resolve final target server */
34273418
kfree(full_path);
@@ -3455,10 +3446,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34553446
rc = is_referral_server(ref_path + 1, tcon, &ref_server);
34563447
if (rc)
34573448
break;
3458-
if (ref_server) {
3459-
put_root_ses(root_ses);
3460-
set_root_ses(cifs_sb, ses, &root_ses);
3461-
}
3449+
if (ref_server)
3450+
set_root_ses(cifs_sb, &mount_id, ses, &root_ses);
34623451

34633452
/* Get next dfs path and then continue chasing them if -EREMOTE */
34643453
rc = next_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path);
@@ -3469,8 +3458,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34693458

34703459
if (rc)
34713460
goto error;
3472-
put_root_ses(root_ses);
3473-
root_ses = NULL;
3461+
34743462
kfree(ref_path);
34753463
ref_path = NULL;
34763464
/*
@@ -3492,10 +3480,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34923480
tcon->remap = cifs_remap(cifs_sb);
34933481
spin_unlock(&cifs_tcp_ses_lock);
34943482

3495-
/* Add original context for DFS cache to be used when refreshing referrals */
3496-
rc = dfs_cache_add_vol(mntdata, ctx, cifs_sb->origin_fullpath);
3497-
if (rc)
3498-
goto error;
34993483
/*
35003484
* After reconnecting to a different server, unique ids won't
35013485
* match anymore, so we disable serverino. This prevents
@@ -3510,6 +3494,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
35103494
kfree(cifs_sb->prepath);
35113495
cifs_sb->prepath = ctx->prepath;
35123496
ctx->prepath = NULL;
3497+
uuid_copy(&cifs_sb->dfs_mount_id, &mount_id);
35133498

35143499
out:
35153500
free_xid(xid);
@@ -3519,9 +3504,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
35193504
error:
35203505
kfree(ref_path);
35213506
kfree(full_path);
3522-
kfree(mntdata);
35233507
kfree(cifs_sb->origin_fullpath);
3524-
put_root_ses(root_ses);
3508+
dfs_cache_put_refsrv_sessions(&mount_id);
35253509
mount_put_conns(cifs_sb, xid, server, ses, tcon);
35263510
return rc;
35273511
}
@@ -3751,7 +3735,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
37513735

37523736
kfree(cifs_sb->prepath);
37533737
#ifdef CONFIG_CIFS_DFS_UPCALL
3754-
dfs_cache_del_vol(cifs_sb->origin_fullpath);
3738+
dfs_cache_put_refsrv_sessions(&cifs_sb->dfs_mount_id);
37553739
kfree(cifs_sb->origin_fullpath);
37563740
#endif
37573741
call_rcu(&cifs_sb->rcu, delayed_free);

0 commit comments

Comments
 (0)