Skip to content

Commit 6485ac6

Browse files
committed
Merge tag 'smb3-client-fixes-6.3-rc3' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs client fixes from Steve French: "Twelve cifs/smb3 client fixes (most also for stable) - forced umount fix - fix for two perf regressions - reconnect fixes - small debugging improvements - multichannel fixes" * tag 'smb3-client-fixes-6.3-rc3' of git://git.samba.org/sfrench/cifs-2.6: smb3: fix unusable share after force unmount failure cifs: fix dentry lookups in directory handle cache smb3: lower default deferred close timeout to address perf regression cifs: fix missing unload_nls() in smb2_reconnect() cifs: avoid race conditions with parallel reconnects cifs: append path to open_enter trace event cifs: print session id while listing open files cifs: dump pending mids for all channels in DebugData cifs: empty interface list when server doesn't support query interfaces cifs: do not poll server interfaces too regularly cifs: lock chan_lock outside match_session cifs: check only tcon status on tcon related functions
2 parents da8e7da + 491eafc commit 6485ac6

File tree

15 files changed

+221
-92
lines changed

15 files changed

+221
-92
lines changed

fs/cifs/cached_dir.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
9999
return dentry;
100100
}
101101

102+
static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,
103+
const char *path)
104+
{
105+
size_t len = 0;
106+
107+
if (!*path)
108+
return path;
109+
110+
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
111+
cifs_sb->prepath) {
112+
len = strlen(cifs_sb->prepath) + 1;
113+
if (unlikely(len > strlen(path)))
114+
return ERR_PTR(-EINVAL);
115+
}
116+
return path + len;
117+
}
118+
102119
/*
103120
* Open the and cache a directory handle.
104121
* If error then *cfid is not initialized.
@@ -125,6 +142,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
125142
struct dentry *dentry = NULL;
126143
struct cached_fid *cfid;
127144
struct cached_fids *cfids;
145+
const char *npath;
128146

129147
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
130148
is_smb1_server(tcon->ses->server))
@@ -160,6 +178,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
160178
return 0;
161179
}
162180

181+
/*
182+
* Skip any prefix paths in @path as lookup_positive_unlocked() ends up
183+
* calling ->lookup() which already adds those through
184+
* build_path_from_dentry(). Also, do it earlier as we might reconnect
185+
* below when trying to send compounded request and then potentially
186+
* having a different prefix path (e.g. after DFS failover).
187+
*/
188+
npath = path_no_prefix(cifs_sb, path);
189+
if (IS_ERR(npath)) {
190+
rc = PTR_ERR(npath);
191+
kfree(utf16_path);
192+
return rc;
193+
}
194+
163195
/*
164196
* We do not hold the lock for the open because in case
165197
* SMB2_open needs to reconnect.
@@ -184,6 +216,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
184216

185217
oparms = (struct cifs_open_parms) {
186218
.tcon = tcon,
219+
.path = path,
187220
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
188221
.desired_access = FILE_READ_ATTRIBUTES,
189222
.disposition = FILE_OPEN,
@@ -251,10 +284,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
251284
(char *)&cfid->file_all_info))
252285
cfid->file_all_info_is_valid = true;
253286

254-
if (!path[0])
287+
if (!npath[0])
255288
dentry = dget(cifs_sb->root);
256289
else {
257-
dentry = path_to_dentry(cifs_sb, path);
290+
dentry = path_to_dentry(cifs_sb, npath);
258291
if (IS_ERR(dentry)) {
259292
rc = -ENOENT;
260293
goto oshr_free;

fs/cifs/cifs_debug.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
176176

177177
seq_puts(m, "# Version:1\n");
178178
seq_puts(m, "# Format:\n");
179-
seq_puts(m, "# <tree id> <persistent fid> <flags> <count> <pid> <uid>");
179+
seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
180180
#ifdef CONFIG_CIFS_DEBUG2
181181
seq_printf(m, " <filename> <mid>\n");
182182
#else
@@ -189,8 +189,9 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
189189
spin_lock(&tcon->open_file_lock);
190190
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
191191
seq_printf(m,
192-
"0x%x 0x%llx 0x%x %d %d %d %pd",
192+
"0x%x 0x%llx 0x%llx 0x%x %d %d %d %pd",
193193
tcon->tid,
194+
ses->Suid,
194195
cfile->fid.persistent_fid,
195196
cfile->f_flags,
196197
cfile->count,
@@ -216,6 +217,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
216217
{
217218
struct mid_q_entry *mid_entry;
218219
struct TCP_Server_Info *server;
220+
struct TCP_Server_Info *chan_server;
219221
struct cifs_ses *ses;
220222
struct cifs_tcon *tcon;
221223
struct cifs_server_iface *iface;
@@ -474,23 +476,35 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
474476
seq_puts(m, "\t\t[CONNECTED]\n");
475477
}
476478
spin_unlock(&ses->iface_lock);
479+
480+
seq_puts(m, "\n\n\tMIDs: ");
481+
spin_lock(&ses->chan_lock);
482+
for (j = 0; j < ses->chan_count; j++) {
483+
chan_server = ses->chans[j].server;
484+
if (!chan_server)
485+
continue;
486+
487+
if (list_empty(&chan_server->pending_mid_q))
488+
continue;
489+
490+
seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
491+
chan_server->conn_id);
492+
spin_lock(&chan_server->mid_lock);
493+
list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
494+
seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
495+
mid_entry->mid_state,
496+
le16_to_cpu(mid_entry->command),
497+
mid_entry->pid,
498+
mid_entry->callback_data,
499+
mid_entry->mid);
500+
}
501+
spin_unlock(&chan_server->mid_lock);
502+
}
503+
spin_unlock(&ses->chan_lock);
504+
seq_puts(m, "\n--\n");
477505
}
478506
if (i == 0)
479507
seq_printf(m, "\n\t\t[NONE]");
480-
481-
seq_puts(m, "\n\n\tMIDs: ");
482-
spin_lock(&server->mid_lock);
483-
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
484-
seq_printf(m, "\n\tState: %d com: %d pid:"
485-
" %d cbdata: %p mid %llu\n",
486-
mid_entry->mid_state,
487-
le16_to_cpu(mid_entry->command),
488-
mid_entry->pid,
489-
mid_entry->callback_data,
490-
mid_entry->mid);
491-
}
492-
spin_unlock(&server->mid_lock);
493-
seq_printf(m, "\n--\n");
494508
}
495509
if (c == 0)
496510
seq_printf(m, "\n\t[NONE]");

fs/cifs/cifsfs.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -731,13 +731,16 @@ static void cifs_umount_begin(struct super_block *sb)
731731
spin_lock(&tcon->tc_lock);
732732
if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) {
733733
/* we have other mounts to same share or we have
734-
already tried to force umount this and woken up
734+
already tried to umount this and woken up
735735
all waiting network requests, nothing to do */
736736
spin_unlock(&tcon->tc_lock);
737737
spin_unlock(&cifs_tcp_ses_lock);
738738
return;
739-
} else if (tcon->tc_count == 1)
740-
tcon->status = TID_EXITING;
739+
}
740+
/*
741+
* can not set tcon->status to TID_EXITING yet since we don't know if umount -f will
742+
* fail later (e.g. due to open files). TID_EXITING will be set just before tdis req sent
743+
*/
741744
spin_unlock(&tcon->tc_lock);
742745
spin_unlock(&cifs_tcp_ses_lock);
743746

fs/cifs/cifssmb.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,11 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
8686

8787
/*
8888
* only tree disconnect, open, and write, (and ulogoff which does not
89-
* have tcon) are allowed as we start force umount
89+
* have tcon) are allowed as we start umount
9090
*/
9191
spin_lock(&tcon->tc_lock);
9292
if (tcon->status == TID_EXITING) {
93-
if (smb_command != SMB_COM_WRITE_ANDX &&
94-
smb_command != SMB_COM_OPEN_ANDX &&
95-
smb_command != SMB_COM_TREE_DISCONNECT) {
93+
if (smb_command != SMB_COM_TREE_DISCONNECT) {
9694
spin_unlock(&tcon->tc_lock);
9795
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
9896
smb_command);

fs/cifs/connect.c

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -212,31 +212,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
212212
cifs_chan_update_iface(ses, server);
213213

214214
spin_lock(&ses->chan_lock);
215-
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
216-
goto next_session;
215+
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) {
216+
spin_unlock(&ses->chan_lock);
217+
continue;
218+
}
217219

218220
if (mark_smb_session)
219221
CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
220222
else
221223
cifs_chan_set_need_reconnect(ses, server);
222224

225+
cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
226+
__func__, ses->chans_need_reconnect);
227+
223228
/* If all channels need reconnect, then tcon needs reconnect */
224-
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
225-
goto next_session;
229+
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
230+
spin_unlock(&ses->chan_lock);
231+
continue;
232+
}
233+
spin_unlock(&ses->chan_lock);
226234

235+
spin_lock(&ses->ses_lock);
227236
ses->ses_status = SES_NEED_RECON;
237+
spin_unlock(&ses->ses_lock);
228238

229239
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
230240
tcon->need_reconnect = true;
241+
spin_lock(&tcon->tc_lock);
231242
tcon->status = TID_NEED_RECON;
243+
spin_unlock(&tcon->tc_lock);
232244
}
233245
if (ses->tcon_ipc) {
234246
ses->tcon_ipc->need_reconnect = true;
247+
spin_lock(&ses->tcon_ipc->tc_lock);
235248
ses->tcon_ipc->status = TID_NEED_RECON;
249+
spin_unlock(&ses->tcon_ipc->tc_lock);
236250
}
237-
238-
next_session:
239-
spin_unlock(&ses->chan_lock);
240251
}
241252
spin_unlock(&cifs_tcp_ses_lock);
242253
}
@@ -1721,7 +1732,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
17211732
return ERR_PTR(rc);
17221733
}
17231734

1724-
/* this function must be called with ses_lock held */
1735+
/* this function must be called with ses_lock and chan_lock held */
17251736
static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
17261737
{
17271738
if (ctx->sectype != Unspecified &&
@@ -1732,12 +1743,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
17321743
* If an existing session is limited to less channels than
17331744
* requested, it should not be reused
17341745
*/
1735-
spin_lock(&ses->chan_lock);
1736-
if (ses->chan_max < ctx->max_channels) {
1737-
spin_unlock(&ses->chan_lock);
1746+
if (ses->chan_max < ctx->max_channels)
17381747
return 0;
1739-
}
1740-
spin_unlock(&ses->chan_lock);
17411748

17421749
switch (ses->sectype) {
17431750
case Kerberos:
@@ -1865,10 +1872,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
18651872
spin_unlock(&ses->ses_lock);
18661873
continue;
18671874
}
1875+
spin_lock(&ses->chan_lock);
18681876
if (!match_session(ses, ctx)) {
1877+
spin_unlock(&ses->chan_lock);
18691878
spin_unlock(&ses->ses_lock);
18701879
continue;
18711880
}
1881+
spin_unlock(&ses->chan_lock);
18721882
spin_unlock(&ses->ses_lock);
18731883

18741884
++ses->ses_count;
@@ -2314,6 +2324,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
23142324
WARN_ON(tcon->tc_count < 0);
23152325

23162326
list_del_init(&tcon->tcon_list);
2327+
tcon->status = TID_EXITING;
23172328
spin_unlock(&tcon->tc_lock);
23182329
spin_unlock(&cifs_tcp_ses_lock);
23192330

@@ -2693,6 +2704,7 @@ cifs_match_super(struct super_block *sb, void *data)
26932704

26942705
spin_lock(&tcp_srv->srv_lock);
26952706
spin_lock(&ses->ses_lock);
2707+
spin_lock(&ses->chan_lock);
26962708
spin_lock(&tcon->tc_lock);
26972709
if (!match_server(tcp_srv, ctx, dfs_super_cmp) ||
26982710
!match_session(ses, ctx) ||
@@ -2705,6 +2717,7 @@ cifs_match_super(struct super_block *sb, void *data)
27052717
rc = compare_mount_options(sb, mnt_data);
27062718
out:
27072719
spin_unlock(&tcon->tc_lock);
2720+
spin_unlock(&ses->chan_lock);
27082721
spin_unlock(&ses->ses_lock);
27092722
spin_unlock(&tcp_srv->srv_lock);
27102723

@@ -3652,11 +3665,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
36523665

36533666
/* only send once per connect */
36543667
spin_lock(&server->srv_lock);
3655-
if (!server->ops->need_neg(server) ||
3668+
if (server->tcpStatus != CifsGood &&
3669+
server->tcpStatus != CifsNew &&
36563670
server->tcpStatus != CifsNeedNegotiate) {
3671+
spin_unlock(&server->srv_lock);
3672+
return -EHOSTDOWN;
3673+
}
3674+
3675+
if (!server->ops->need_neg(server) &&
3676+
server->tcpStatus == CifsGood) {
36573677
spin_unlock(&server->srv_lock);
36583678
return 0;
36593679
}
3680+
36603681
server->tcpStatus = CifsInNegotiate;
36613682
spin_unlock(&server->srv_lock);
36623683

@@ -3690,23 +3711,28 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
36903711
bool is_binding = false;
36913712

36923713
spin_lock(&ses->ses_lock);
3714+
cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
3715+
__func__, ses->chans_need_reconnect);
3716+
36933717
if (ses->ses_status != SES_GOOD &&
36943718
ses->ses_status != SES_NEW &&
36953719
ses->ses_status != SES_NEED_RECON) {
36963720
spin_unlock(&ses->ses_lock);
3697-
return 0;
3721+
return -EHOSTDOWN;
36983722
}
36993723

37003724
/* only send once per connect */
37013725
spin_lock(&ses->chan_lock);
3702-
if (CIFS_ALL_CHANS_GOOD(ses) ||
3703-
cifs_chan_in_reconnect(ses, server)) {
3726+
if (CIFS_ALL_CHANS_GOOD(ses)) {
3727+
if (ses->ses_status == SES_NEED_RECON)
3728+
ses->ses_status = SES_GOOD;
37043729
spin_unlock(&ses->chan_lock);
37053730
spin_unlock(&ses->ses_lock);
37063731
return 0;
37073732
}
3708-
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
3733+
37093734
cifs_chan_set_in_reconnect(ses, server);
3735+
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
37103736
spin_unlock(&ses->chan_lock);
37113737

37123738
if (!is_binding)
@@ -4036,9 +4062,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
40364062

40374063
/* only send once per connect */
40384064
spin_lock(&tcon->tc_lock);
4039-
if (tcon->ses->ses_status != SES_GOOD ||
4040-
(tcon->status != TID_NEW &&
4041-
tcon->status != TID_NEED_TCON)) {
4065+
if (tcon->status != TID_NEW &&
4066+
tcon->status != TID_NEED_TCON) {
4067+
spin_unlock(&tcon->tc_lock);
4068+
return -EHOSTDOWN;
4069+
}
4070+
4071+
if (tcon->status == TID_GOOD) {
40424072
spin_unlock(&tcon->tc_lock);
40434073
return 0;
40444074
}

fs/cifs/dfs.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -502,9 +502,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
502502

503503
/* only send once per connect */
504504
spin_lock(&tcon->tc_lock);
505-
if (tcon->ses->ses_status != SES_GOOD ||
506-
(tcon->status != TID_NEW &&
507-
tcon->status != TID_NEED_TCON)) {
505+
if (tcon->status != TID_NEW &&
506+
tcon->status != TID_NEED_TCON) {
507+
spin_unlock(&tcon->tc_lock);
508+
return -EHOSTDOWN;
509+
}
510+
511+
if (tcon->status == TID_GOOD) {
508512
spin_unlock(&tcon->tc_lock);
509513
return 0;
510514
}

fs/cifs/dfs_cache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1191,7 +1191,7 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r
11911191
}
11921192

11931193
spin_lock(&ipc->tc_lock);
1194-
if (ses->ses_status != SES_GOOD || ipc->status != TID_GOOD) {
1194+
if (ipc->status != TID_GOOD) {
11951195
spin_unlock(&ipc->tc_lock);
11961196
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__);
11971197
goto out;

0 commit comments

Comments
 (0)