Skip to content

Commit 7a043fe

Browse files
committed
Merge tag '6.4-rc6-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: "Eight, mostly small, smb3 client fixes: - important fix for deferred close oops (race with unmount) found with xfstest generic/098 to some servers - important reconnect fix - fix problem with max_credits mount option - two multichannel (interface related) fixes - one trivial removal of confusing comment - two small debugging improvements (to better spot crediting problems)" * tag '6.4-rc6-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: add a warning when the in-flight count goes negative cifs: fix lease break oops in xfstest generic/098 cifs: fix max_credits implementation cifs: fix sockaddr comparison in iface_cmp smb/client: print "Unknown" instead of bogus link speed value cifs: print all credit counters in DebugData cifs: fix status checks in cifs_tree_connect smb: remove obsolete comment
2 parents b6dad51 + e4645cc commit 7a043fe

9 files changed

Lines changed: 190 additions & 56 deletions

File tree

fs/smb/client/cifs_debug.c

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/module.h>
1313
#include <linux/proc_fs.h>
1414
#include <linux/uaccess.h>
15+
#include <uapi/linux/ethtool.h>
1516
#include "cifspdu.h"
1617
#include "cifsglob.h"
1718
#include "cifsproto.h"
@@ -130,12 +131,14 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
130131
struct TCP_Server_Info *server = chan->server;
131132

132133
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
133-
"\n\t\tNumber of credits: %d Dialect 0x%x"
134+
"\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
134135
"\n\t\tTCP status: %d Instance: %d"
135136
"\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d"
136137
"\n\t\tIn Send: %d In MaxReq Wait: %d",
137138
i+1, server->conn_id,
138139
server->credits,
140+
server->echo_credits,
141+
server->oplock_credits,
139142
server->dialect,
140143
server->tcpStatus,
141144
server->reconnect_instance,
@@ -146,18 +149,62 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
146149
atomic_read(&server->num_waiters));
147150
}
148151

152+
static inline const char *smb_speed_to_str(size_t bps)
153+
{
154+
size_t mbps = bps / 1000 / 1000;
155+
156+
switch (mbps) {
157+
case SPEED_10:
158+
return "10Mbps";
159+
case SPEED_100:
160+
return "100Mbps";
161+
case SPEED_1000:
162+
return "1Gbps";
163+
case SPEED_2500:
164+
return "2.5Gbps";
165+
case SPEED_5000:
166+
return "5Gbps";
167+
case SPEED_10000:
168+
return "10Gbps";
169+
case SPEED_14000:
170+
return "14Gbps";
171+
case SPEED_20000:
172+
return "20Gbps";
173+
case SPEED_25000:
174+
return "25Gbps";
175+
case SPEED_40000:
176+
return "40Gbps";
177+
case SPEED_50000:
178+
return "50Gbps";
179+
case SPEED_56000:
180+
return "56Gbps";
181+
case SPEED_100000:
182+
return "100Gbps";
183+
case SPEED_200000:
184+
return "200Gbps";
185+
case SPEED_400000:
186+
return "400Gbps";
187+
case SPEED_800000:
188+
return "800Gbps";
189+
default:
190+
return "Unknown";
191+
}
192+
}
193+
149194
static void
150195
cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
151196
{
152197
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
153198
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
154199

155-
seq_printf(m, "\tSpeed: %zu bps\n", iface->speed);
200+
seq_printf(m, "\tSpeed: %s\n", smb_speed_to_str(iface->speed));
156201
seq_puts(m, "\t\tCapabilities: ");
157202
if (iface->rdma_capable)
158203
seq_puts(m, "rdma ");
159204
if (iface->rss_capable)
160205
seq_puts(m, "rss ");
206+
if (!iface->rdma_capable && !iface->rss_capable)
207+
seq_puts(m, "None");
161208
seq_putc(m, '\n');
162209
if (iface->sockaddr.ss_family == AF_INET)
163210
seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
@@ -350,8 +397,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
350397
atomic_read(&server->smbd_conn->mr_used_count));
351398
skip_rdma:
352399
#endif
353-
seq_printf(m, "\nNumber of credits: %d Dialect 0x%x",
354-
server->credits, server->dialect);
400+
seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x",
401+
server->credits,
402+
server->echo_credits,
403+
server->oplock_credits,
404+
server->dialect);
355405
if (server->compress_algorithm == SMB3_COMPRESS_LZNT1)
356406
seq_printf(m, " COMPRESS_LZNT1");
357407
else if (server->compress_algorithm == SMB3_COMPRESS_LZ77)

fs/smb/client/cifsglob.h

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -970,43 +970,6 @@ release_iface(struct kref *ref)
970970
kfree(iface);
971971
}
972972

973-
/*
974-
* compare two interfaces a and b
975-
* return 0 if everything matches.
976-
* return 1 if a has higher link speed, or rdma capable, or rss capable
977-
* return -1 otherwise.
978-
*/
979-
static inline int
980-
iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
981-
{
982-
int cmp_ret = 0;
983-
984-
WARN_ON(!a || !b);
985-
if (a->speed == b->speed) {
986-
if (a->rdma_capable == b->rdma_capable) {
987-
if (a->rss_capable == b->rss_capable) {
988-
cmp_ret = memcmp(&a->sockaddr, &b->sockaddr,
989-
sizeof(a->sockaddr));
990-
if (!cmp_ret)
991-
return 0;
992-
else if (cmp_ret > 0)
993-
return 1;
994-
else
995-
return -1;
996-
} else if (a->rss_capable > b->rss_capable)
997-
return 1;
998-
else
999-
return -1;
1000-
} else if (a->rdma_capable > b->rdma_capable)
1001-
return 1;
1002-
else
1003-
return -1;
1004-
} else if (a->speed > b->speed)
1005-
return 1;
1006-
else
1007-
return -1;
1008-
}
1009-
1010973
struct cifs_chan {
1011974
unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
1012975
struct TCP_Server_Info *server;

fs/smb/client/cifsproto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ extern int cifs_handle_standard(struct TCP_Server_Info *server,
8787
struct mid_q_entry *mid);
8888
extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
8989
extern int smb3_parse_opt(const char *options, const char *key, char **val);
90+
extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
9091
extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
9192
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
9293
extern int cifs_call_async(struct TCP_Server_Info *server,

fs/smb/client/connect.c

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,6 +1288,56 @@ cifs_demultiplex_thread(void *p)
12881288
module_put_and_kthread_exit(0);
12891289
}
12901290

1291+
int
1292+
cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs)
1293+
{
1294+
struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1295+
struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1296+
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
1297+
struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
1298+
1299+
switch (srcaddr->sa_family) {
1300+
case AF_UNSPEC:
1301+
switch (rhs->sa_family) {
1302+
case AF_UNSPEC:
1303+
return 0;
1304+
case AF_INET:
1305+
case AF_INET6:
1306+
return 1;
1307+
default:
1308+
return -1;
1309+
}
1310+
case AF_INET: {
1311+
switch (rhs->sa_family) {
1312+
case AF_UNSPEC:
1313+
return -1;
1314+
case AF_INET:
1315+
return memcmp(saddr4, vaddr4,
1316+
sizeof(struct sockaddr_in));
1317+
case AF_INET6:
1318+
return 1;
1319+
default:
1320+
return -1;
1321+
}
1322+
}
1323+
case AF_INET6: {
1324+
switch (rhs->sa_family) {
1325+
case AF_UNSPEC:
1326+
case AF_INET:
1327+
return -1;
1328+
case AF_INET6:
1329+
return memcmp(saddr6,
1330+
vaddr6,
1331+
sizeof(struct sockaddr_in6));
1332+
default:
1333+
return -1;
1334+
}
1335+
}
1336+
default:
1337+
return -1; /* don't expect to be here */
1338+
}
1339+
}
1340+
12911341
/*
12921342
* Returns true if srcaddr isn't specified and rhs isn't specified, or
12931343
* if srcaddr is specified and matches the IP address of the rhs argument
@@ -4086,16 +4136,17 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
40864136

40874137
/* only send once per connect */
40884138
spin_lock(&tcon->tc_lock);
4139+
if (tcon->status == TID_GOOD) {
4140+
spin_unlock(&tcon->tc_lock);
4141+
return 0;
4142+
}
4143+
40894144
if (tcon->status != TID_NEW &&
40904145
tcon->status != TID_NEED_TCON) {
40914146
spin_unlock(&tcon->tc_lock);
40924147
return -EHOSTDOWN;
40934148
}
40944149

4095-
if (tcon->status == TID_GOOD) {
4096-
spin_unlock(&tcon->tc_lock);
4097-
return 0;
4098-
}
40994150
tcon->status = TID_IN_TCON;
41004151
spin_unlock(&tcon->tc_lock);
41014152

fs/smb/client/dfs.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -575,16 +575,17 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
575575

576576
/* only send once per connect */
577577
spin_lock(&tcon->tc_lock);
578+
if (tcon->status == TID_GOOD) {
579+
spin_unlock(&tcon->tc_lock);
580+
return 0;
581+
}
582+
578583
if (tcon->status != TID_NEW &&
579584
tcon->status != TID_NEED_TCON) {
580585
spin_unlock(&tcon->tc_lock);
581586
return -EHOSTDOWN;
582587
}
583588

584-
if (tcon->status == TID_GOOD) {
585-
spin_unlock(&tcon->tc_lock);
586-
return 0;
587-
}
588589
tcon->status = TID_IN_TCON;
589590
spin_unlock(&tcon->tc_lock);
590591

fs/smb/client/file.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4942,9 +4942,13 @@ void cifs_oplock_break(struct work_struct *work)
49424942
* disconnected since oplock already released by the server
49434943
*/
49444944
if (!oplock_break_cancelled) {
4945-
rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
4945+
/* check for server null since can race with kill_sb calling tree disconnect */
4946+
if (tcon->ses && tcon->ses->server) {
4947+
rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
49464948
volatile_fid, net_fid, cinode);
4947-
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
4949+
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
4950+
} else
4951+
pr_warn_once("lease break not sent for unmounted share\n");
49484952
}
49494953

49504954
cifs_done_oplock_break(cinode);

fs/smb/client/smb2ops.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ static int
3434
change_conf(struct TCP_Server_Info *server)
3535
{
3636
server->credits += server->echo_credits + server->oplock_credits;
37+
if (server->credits > server->max_credits)
38+
server->credits = server->max_credits;
3739
server->oplock_credits = server->echo_credits = 0;
3840
switch (server->credits) {
3941
case 0:
@@ -91,6 +93,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
9193
server->conn_id, server->hostname, *val,
9294
add, server->in_flight);
9395
}
96+
WARN_ON_ONCE(server->in_flight == 0);
9497
server->in_flight--;
9598
if (server->in_flight == 0 &&
9699
((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
@@ -510,6 +513,43 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
510513
return rsize;
511514
}
512515

516+
/*
517+
* compare two interfaces a and b
518+
* return 0 if everything matches.
519+
* return 1 if a is rdma capable, or rss capable, or has higher link speed
520+
* return -1 otherwise.
521+
*/
522+
static int
523+
iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
524+
{
525+
int cmp_ret = 0;
526+
527+
WARN_ON(!a || !b);
528+
if (a->rdma_capable == b->rdma_capable) {
529+
if (a->rss_capable == b->rss_capable) {
530+
if (a->speed == b->speed) {
531+
cmp_ret = cifs_ipaddr_cmp((struct sockaddr *) &a->sockaddr,
532+
(struct sockaddr *) &b->sockaddr);
533+
if (!cmp_ret)
534+
return 0;
535+
else if (cmp_ret > 0)
536+
return 1;
537+
else
538+
return -1;
539+
} else if (a->speed > b->speed)
540+
return 1;
541+
else
542+
return -1;
543+
} else if (a->rss_capable > b->rss_capable)
544+
return 1;
545+
else
546+
return -1;
547+
} else if (a->rdma_capable > b->rdma_capable)
548+
return 1;
549+
else
550+
return -1;
551+
}
552+
513553
static int
514554
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
515555
size_t buf_len, struct cifs_ses *ses, bool in_mount)

0 commit comments

Comments
 (0)