Skip to content

Commit 1b907d0

Browse files
committed
Merge tag '6.7-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - ctime caching fix (for setxattr) - encryption fix - DNS resolver mount fix - debugging improvements - multichannel fixes including cases where server stops or starts supporting multichannel after mount - reconnect fix - minor cleanups * tag '6.7-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal module version number for cifs.ko cifs: handle when server stops supporting multichannel cifs: handle when server starts supporting multichannel Missing field not being returned in ioctl CIFS_IOC_GET_MNT_INFO smb3: allow dumping session and tcon id to improve stats analysis and debugging smb: client: fix mount when dns_resolver key is not available smb3: fix caching of ctime on setxattr smb3: minor cleanup of session handling code cifs: reconnect work should have reference on server struct cifs: do not pass cifs_sb when trying to add channels cifs: account for primary channel in the interface list cifs: distribute channels across interfaces based on speed cifs: handle cases where a channel is closed smb3: more minor cleanups for session handling routines smb3: minor RDMA cleanup cifs: Fix encryption of cleared, but unset rq_iter data buffers
2 parents 3ca112b + fd2bd7c commit 1b907d0

File tree

16 files changed

+491
-88
lines changed

16 files changed

+491
-88
lines changed

fs/smb/client/cifs_debug.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
136136
{
137137
struct TCP_Server_Info *server = chan->server;
138138

139+
if (!server) {
140+
seq_printf(m, "\n\n\t\tChannel: %d DISABLED", i+1);
141+
return;
142+
}
143+
139144
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
140145
"\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
141146
"\n\t\tTCP status: %d Instance: %d"
@@ -279,6 +284,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
279284
struct cifs_ses *ses;
280285
struct cifs_tcon *tcon;
281286
struct cifs_server_iface *iface;
287+
size_t iface_weight = 0, iface_min_speed = 0;
288+
struct cifs_server_iface *last_iface = NULL;
282289
int c, i, j;
283290

284291
seq_puts(m,
@@ -544,11 +551,25 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
544551
"\tLast updated: %lu seconds ago",
545552
ses->iface_count,
546553
(jiffies - ses->iface_last_update) / HZ);
554+
555+
last_iface = list_last_entry(&ses->iface_list,
556+
struct cifs_server_iface,
557+
iface_head);
558+
iface_min_speed = last_iface->speed;
559+
547560
j = 0;
548561
list_for_each_entry(iface, &ses->iface_list,
549562
iface_head) {
550563
seq_printf(m, "\n\t%d)", ++j);
551564
cifs_dump_iface(m, iface);
565+
566+
iface_weight = iface->speed / iface_min_speed;
567+
seq_printf(m, "\t\tWeight (cur,total): (%zu,%zu)"
568+
"\n\t\tAllocated channels: %u\n",
569+
iface->weight_fulfilled,
570+
iface_weight,
571+
iface->num_channels);
572+
552573
if (is_ses_using_iface(ses, iface))
553574
seq_puts(m, "\t\t[CONNECTED]\n");
554575
}
@@ -746,14 +767,14 @@ static ssize_t name##_write(struct file *file, const char __user *buffer, \
746767
size_t count, loff_t *ppos) \
747768
{ \
748769
int rc; \
749-
rc = kstrtoint_from_user(buffer, count, 10, & name); \
770+
rc = kstrtoint_from_user(buffer, count, 10, &name); \
750771
if (rc) \
751772
return rc; \
752773
return count; \
753774
} \
754775
static int name##_proc_show(struct seq_file *m, void *v) \
755776
{ \
756-
seq_printf(m, "%d\n", name ); \
777+
seq_printf(m, "%d\n", name); \
757778
return 0; \
758779
} \
759780
static int name##_open(struct inode *inode, struct file *file) \

fs/smb/client/cifs_ioctl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ struct smb_mnt_fs_info {
2626
__u64 cifs_posix_caps;
2727
} __packed;
2828

29+
struct smb_mnt_tcon_info {
30+
__u32 tid;
31+
__u64 session_id;
32+
} __packed;
33+
2934
struct smb_snapshot_array {
3035
__u32 number_of_snapshots;
3136
__u32 number_of_snapshots_returned;
@@ -108,6 +113,7 @@ struct smb3_notify_info {
108113
#define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify)
109114
#define CIFS_DUMP_FULL_KEY _IOWR(CIFS_IOCTL_MAGIC, 10, struct smb3_full_key_debug_info)
110115
#define CIFS_IOC_NOTIFY_INFO _IOWR(CIFS_IOCTL_MAGIC, 11, struct smb3_notify_info)
116+
#define CIFS_IOC_GET_TCON_INFO _IOR(CIFS_IOCTL_MAGIC, 12, struct smb_mnt_tcon_info)
111117
#define CIFS_IOC_SHUTDOWN _IOR('X', 125, __u32)
112118

113119
/*

fs/smb/client/cifsfs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,6 @@ extern const struct export_operations cifs_export_ops;
152152
#endif /* CONFIG_CIFS_NFSD_EXPORT */
153153

154154
/* when changing internal version - update following two lines at same time */
155-
#define SMB3_PRODUCT_BUILD 45
156-
#define CIFS_VERSION "2.45"
155+
#define SMB3_PRODUCT_BUILD 46
156+
#define CIFS_VERSION "2.46"
157157
#endif /* _CIFSFS_H */

fs/smb/client/cifsglob.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ struct TCP_Server_Info {
650650
bool noautotune; /* do not autotune send buf sizes */
651651
bool nosharesock;
652652
bool tcp_nodelay;
653+
bool terminate;
653654
unsigned int credits; /* send no more requests at once */
654655
unsigned int max_credits; /* can override large 32000 default at mnt */
655656
unsigned int in_flight; /* number of requests on the wire to server */
@@ -969,6 +970,8 @@ struct cifs_server_iface {
969970
struct list_head iface_head;
970971
struct kref refcount;
971972
size_t speed;
973+
size_t weight_fulfilled;
974+
unsigned int num_channels;
972975
unsigned int rdma_capable : 1;
973976
unsigned int rss_capable : 1;
974977
unsigned int is_active : 1; /* unset if non existent */
@@ -1050,6 +1053,7 @@ struct cifs_ses {
10501053
spinlock_t chan_lock;
10511054
/* ========= begin: protected by chan_lock ======== */
10521055
#define CIFS_MAX_CHANNELS 16
1056+
#define CIFS_INVAL_CHAN_INDEX (-1)
10531057
#define CIFS_ALL_CHANNELS_SET(ses) \
10541058
((1UL << (ses)->chan_count) - 1)
10551059
#define CIFS_ALL_CHANS_GOOD(ses) \
@@ -2143,6 +2147,7 @@ static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
21432147
unsigned int len, skip;
21442148
unsigned int nents = 0;
21452149
unsigned long addr;
2150+
size_t data_size;
21462151
int i, j;
21472152

21482153
/*
@@ -2158,17 +2163,21 @@ static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
21582163
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
21592164
*/
21602165
for (i = 0; i < num_rqst; i++) {
2166+
data_size = iov_iter_count(&rqst[i].rq_iter);
2167+
21612168
/* We really don't want a mixture of pinned and unpinned pages
21622169
* in the sglist. It's hard to keep track of which is what.
21632170
* Instead, we convert to a BVEC-type iterator higher up.
21642171
*/
2165-
if (WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
2172+
if (data_size &&
2173+
WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
21662174
return -EIO;
21672175

21682176
/* We also don't want to have any extra refs or pins to clean
21692177
* up in the sglist.
21702178
*/
2171-
if (WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
2179+
if (data_size &&
2180+
WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
21722181
return -EIO;
21732182

21742183
for (j = 0; j < rqst[i].rq_nvec; j++) {
@@ -2184,7 +2193,8 @@ static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
21842193
}
21852194
skip = 0;
21862195
}
2187-
nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
2196+
if (data_size)
2197+
nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
21882198
}
21892199
nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
21902200
return nents;

fs/smb/client/cifsproto.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
132132
struct smb_hdr *in_buf,
133133
struct smb_hdr *out_buf,
134134
int *bytes_returned);
135+
135136
void
136137
cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
137138
bool all_channels);
@@ -610,13 +611,13 @@ void cifs_free_hash(struct shash_desc **sdesc);
610611

611612
struct cifs_chan *
612613
cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server);
613-
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);
614+
int cifs_try_adding_channels(struct cifs_ses *ses);
614615
bool is_server_using_iface(struct TCP_Server_Info *server,
615616
struct cifs_server_iface *iface);
616617
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
617618
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
618619

619-
unsigned int
620+
int
620621
cifs_ses_get_chan_index(struct cifs_ses *ses,
621622
struct TCP_Server_Info *server);
622623
void
@@ -640,6 +641,8 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
640641
bool
641642
cifs_chan_is_iface_active(struct cifs_ses *ses,
642643
struct TCP_Server_Info *server);
644+
void
645+
cifs_disable_secondary_channels(struct cifs_ses *ses);
643646
int
644647
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
645648
int

fs/smb/client/connect.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ static void smb2_query_server_interfaces(struct work_struct *work)
132132
free_xid(xid);
133133

134134
if (rc) {
135+
if (rc == -EOPNOTSUPP)
136+
return;
137+
135138
cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
136139
__func__, rc);
137140
}
@@ -173,8 +176,12 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
173176
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
174177
spin_lock(&ses->chan_lock);
175178
for (i = 0; i < ses->chan_count; i++) {
179+
if (!ses->chans[i].server)
180+
continue;
181+
176182
spin_lock(&ses->chans[i].server->srv_lock);
177-
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
183+
if (ses->chans[i].server->tcpStatus != CifsExiting)
184+
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
178185
spin_unlock(&ses->chans[i].server->srv_lock);
179186
}
180187
spin_unlock(&ses->chan_lock);
@@ -212,6 +219,14 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
212219

213220
spin_lock(&cifs_tcp_ses_lock);
214221
list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) {
222+
/*
223+
* if channel has been marked for termination, nothing to do
224+
* for the channel. in fact, we cannot find the channel for the
225+
* server. So safe to exit here
226+
*/
227+
if (server->terminate)
228+
break;
229+
215230
/* check if iface is still active */
216231
if (!cifs_chan_is_iface_active(ses, server))
217232
cifs_chan_update_iface(ses, server);
@@ -246,6 +261,8 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
246261
spin_lock(&tcon->tc_lock);
247262
tcon->status = TID_NEED_RECON;
248263
spin_unlock(&tcon->tc_lock);
264+
265+
cancel_delayed_work(&tcon->query_interfaces);
249266
}
250267
if (ses->tcon_ipc) {
251268
ses->tcon_ipc->need_reconnect = true;
@@ -385,7 +402,13 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
385402
spin_unlock(&server->srv_lock);
386403
cifs_swn_reset_server_dstaddr(server);
387404
cifs_server_unlock(server);
388-
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
405+
406+
/* increase ref count which reconnect work will drop */
407+
spin_lock(&cifs_tcp_ses_lock);
408+
server->srv_count++;
409+
spin_unlock(&cifs_tcp_ses_lock);
410+
if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
411+
cifs_put_tcp_session(server, false);
389412
}
390413
} while (server->tcpStatus == CifsNeedReconnect);
391414

@@ -515,7 +538,13 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
515538
spin_unlock(&server->srv_lock);
516539
cifs_swn_reset_server_dstaddr(server);
517540
cifs_server_unlock(server);
518-
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
541+
542+
/* increase ref count which reconnect work will drop */
543+
spin_lock(&cifs_tcp_ses_lock);
544+
server->srv_count++;
545+
spin_unlock(&cifs_tcp_ses_lock);
546+
if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
547+
cifs_put_tcp_session(server, false);
519548
} while (server->tcpStatus == CifsNeedReconnect);
520549

521550
mutex_lock(&server->refpath_lock);
@@ -1597,16 +1626,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
15971626

15981627
cancel_delayed_work_sync(&server->echo);
15991628

1600-
if (from_reconnect)
1629+
if (from_reconnect) {
16011630
/*
16021631
* Avoid deadlock here: reconnect work calls
16031632
* cifs_put_tcp_session() at its end. Need to be sure
16041633
* that reconnect work does nothing with server pointer after
16051634
* that step.
16061635
*/
1607-
cancel_delayed_work(&server->reconnect);
1608-
else
1609-
cancel_delayed_work_sync(&server->reconnect);
1636+
if (cancel_delayed_work(&server->reconnect))
1637+
cifs_put_tcp_session(server, from_reconnect);
1638+
} else {
1639+
if (cancel_delayed_work_sync(&server->reconnect))
1640+
cifs_put_tcp_session(server, from_reconnect);
1641+
}
16101642

16111643
spin_lock(&server->srv_lock);
16121644
server->tcpStatus = CifsExiting;
@@ -3560,7 +3592,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
35603592
ctx->prepath = NULL;
35613593

35623594
out:
3563-
cifs_try_adding_channels(cifs_sb, mnt_ctx.ses);
3595+
cifs_try_adding_channels(mnt_ctx.ses);
35643596
rc = mount_setup_tlink(cifs_sb, mnt_ctx.ses, mnt_ctx.tcon);
35653597
if (rc)
35663598
goto error;

fs/smb/client/dfs.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,15 +263,23 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
263263
return rc;
264264
}
265265

266-
/* Resolve UNC hostname in @ctx->source and set ip addr in @ctx->dstaddr */
266+
/*
267+
* If @ctx->dfs_automount, then update @ctx->dstaddr earlier with the DFS root
268+
* server from where we'll start following any referrals. Otherwise rely on the
269+
* value provided by mount(2) as the user might not have dns_resolver key set up
270+
* and therefore failing to upcall to resolve UNC hostname under @ctx->source.
271+
*/
267272
static int update_fs_context_dstaddr(struct smb3_fs_context *ctx)
268273
{
269274
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
270-
int rc;
275+
int rc = 0;
271276

272-
rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
273-
if (!rc)
274-
cifs_set_port(addr, ctx->port);
277+
if (!ctx->nodfs && ctx->dfs_automount) {
278+
rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
279+
if (!rc)
280+
cifs_set_port(addr, ctx->port);
281+
ctx->dfs_automount = false;
282+
}
275283
return rc;
276284
}
277285

fs/smb/client/fs_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ struct smb3_fs_context {
268268
bool witness:1; /* use witness protocol */
269269
char *leaf_fullpath;
270270
struct cifs_ses *dfs_root_ses;
271+
bool dfs_automount:1; /* set for dfs automount only */
271272
};
272273

273274
extern const struct fs_parameter_spec smb3_fs_parameters[];

fs/smb/client/ioctl.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,20 @@ static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
117117
return rc;
118118
}
119119

120+
static long smb_mnt_get_tcon_info(struct cifs_tcon *tcon, void __user *arg)
121+
{
122+
int rc = 0;
123+
struct smb_mnt_tcon_info tcon_inf;
124+
125+
tcon_inf.tid = tcon->tid;
126+
tcon_inf.session_id = tcon->ses->Suid;
127+
128+
if (copy_to_user(arg, &tcon_inf, sizeof(struct smb_mnt_tcon_info)))
129+
rc = -EFAULT;
130+
131+
return rc;
132+
}
133+
120134
static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
121135
void __user *arg)
122136
{
@@ -129,6 +143,7 @@ static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
129143

130144
fsinf->version = 1;
131145
fsinf->protocol_id = tcon->ses->server->vals->protocol_id;
146+
fsinf->tcon_flags = tcon->Flags;
132147
fsinf->device_characteristics =
133148
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics);
134149
fsinf->device_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
@@ -414,6 +429,17 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
414429
tcon = tlink_tcon(pSMBFile->tlink);
415430
rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
416431
break;
432+
case CIFS_IOC_GET_TCON_INFO:
433+
cifs_sb = CIFS_SB(inode->i_sb);
434+
tlink = cifs_sb_tlink(cifs_sb);
435+
if (IS_ERR(tlink)) {
436+
rc = PTR_ERR(tlink);
437+
break;
438+
}
439+
tcon = tlink_tcon(tlink);
440+
rc = smb_mnt_get_tcon_info(tcon, (void __user *)arg);
441+
cifs_put_tlink(tlink);
442+
break;
417443
case CIFS_ENUMERATE_SNAPSHOTS:
418444
if (pSMBFile == NULL)
419445
break;

0 commit comments

Comments
 (0)