Skip to content

Commit

Permalink
Merge tag '6.4-rc6-smb3-client-fixes' of git://git.samba.org/sfrench/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
torvalds committed Jun 15, 2023
2 parents b6dad51 + e4645cc commit 7a043fe
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 56 deletions.
58 changes: 54 additions & 4 deletions fs/smb/client/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <uapi/linux/ethtool.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
Expand Down Expand Up @@ -130,12 +131,14 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
struct TCP_Server_Info *server = chan->server;

seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
"\n\t\tNumber of credits: %d Dialect 0x%x"
"\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
"\n\t\tTCP status: %d Instance: %d"
"\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d"
"\n\t\tIn Send: %d In MaxReq Wait: %d",
i+1, server->conn_id,
server->credits,
server->echo_credits,
server->oplock_credits,
server->dialect,
server->tcpStatus,
server->reconnect_instance,
Expand All @@ -146,18 +149,62 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
atomic_read(&server->num_waiters));
}

static inline const char *smb_speed_to_str(size_t bps)
{
size_t mbps = bps / 1000 / 1000;

switch (mbps) {
case SPEED_10:
return "10Mbps";
case SPEED_100:
return "100Mbps";
case SPEED_1000:
return "1Gbps";
case SPEED_2500:
return "2.5Gbps";
case SPEED_5000:
return "5Gbps";
case SPEED_10000:
return "10Gbps";
case SPEED_14000:
return "14Gbps";
case SPEED_20000:
return "20Gbps";
case SPEED_25000:
return "25Gbps";
case SPEED_40000:
return "40Gbps";
case SPEED_50000:
return "50Gbps";
case SPEED_56000:
return "56Gbps";
case SPEED_100000:
return "100Gbps";
case SPEED_200000:
return "200Gbps";
case SPEED_400000:
return "400Gbps";
case SPEED_800000:
return "800Gbps";
default:
return "Unknown";
}
}

static void
cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
{
struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;

seq_printf(m, "\tSpeed: %zu bps\n", iface->speed);
seq_printf(m, "\tSpeed: %s\n", smb_speed_to_str(iface->speed));
seq_puts(m, "\t\tCapabilities: ");
if (iface->rdma_capable)
seq_puts(m, "rdma ");
if (iface->rss_capable)
seq_puts(m, "rss ");
if (!iface->rdma_capable && !iface->rss_capable)
seq_puts(m, "None");
seq_putc(m, '\n');
if (iface->sockaddr.ss_family == AF_INET)
seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
Expand Down Expand Up @@ -350,8 +397,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
atomic_read(&server->smbd_conn->mr_used_count));
skip_rdma:
#endif
seq_printf(m, "\nNumber of credits: %d Dialect 0x%x",
server->credits, server->dialect);
seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x",
server->credits,
server->echo_credits,
server->oplock_credits,
server->dialect);
if (server->compress_algorithm == SMB3_COMPRESS_LZNT1)
seq_printf(m, " COMPRESS_LZNT1");
else if (server->compress_algorithm == SMB3_COMPRESS_LZ77)
Expand Down
37 changes: 0 additions & 37 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,43 +970,6 @@ release_iface(struct kref *ref)
kfree(iface);
}

/*
* compare two interfaces a and b
* return 0 if everything matches.
* return 1 if a has higher link speed, or rdma capable, or rss capable
* return -1 otherwise.
*/
static inline int
iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
{
int cmp_ret = 0;

WARN_ON(!a || !b);
if (a->speed == b->speed) {
if (a->rdma_capable == b->rdma_capable) {
if (a->rss_capable == b->rss_capable) {
cmp_ret = memcmp(&a->sockaddr, &b->sockaddr,
sizeof(a->sockaddr));
if (!cmp_ret)
return 0;
else if (cmp_ret > 0)
return 1;
else
return -1;
} else if (a->rss_capable > b->rss_capable)
return 1;
else
return -1;
} else if (a->rdma_capable > b->rdma_capable)
return 1;
else
return -1;
} else if (a->speed > b->speed)
return 1;
else
return -1;
}

struct cifs_chan {
unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
struct TCP_Server_Info *server;
Expand Down
1 change: 1 addition & 0 deletions fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ extern int cifs_handle_standard(struct TCP_Server_Info *server,
struct mid_q_entry *mid);
extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
extern int smb3_parse_opt(const char *options, const char *key, char **val);
extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
extern int cifs_call_async(struct TCP_Server_Info *server,
Expand Down
59 changes: 55 additions & 4 deletions fs/smb/client/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,56 @@ cifs_demultiplex_thread(void *p)
module_put_and_kthread_exit(0);
}

int
cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs)
{
struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;

switch (srcaddr->sa_family) {
case AF_UNSPEC:
switch (rhs->sa_family) {
case AF_UNSPEC:
return 0;
case AF_INET:
case AF_INET6:
return 1;
default:
return -1;
}
case AF_INET: {
switch (rhs->sa_family) {
case AF_UNSPEC:
return -1;
case AF_INET:
return memcmp(saddr4, vaddr4,
sizeof(struct sockaddr_in));
case AF_INET6:
return 1;
default:
return -1;
}
}
case AF_INET6: {
switch (rhs->sa_family) {
case AF_UNSPEC:
case AF_INET:
return -1;
case AF_INET6:
return memcmp(saddr6,
vaddr6,
sizeof(struct sockaddr_in6));
default:
return -1;
}
}
default:
return -1; /* don't expect to be here */
}
}

/*
* Returns true if srcaddr isn't specified and rhs isn't specified, or
* if srcaddr is specified and matches the IP address of the rhs argument
Expand Down Expand Up @@ -4086,16 +4136,17 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru

/* only send once per connect */
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock);
return 0;
}

if (tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON) {
spin_unlock(&tcon->tc_lock);
return -EHOSTDOWN;
}

if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock);
return 0;
}
tcon->status = TID_IN_TCON;
spin_unlock(&tcon->tc_lock);

Expand Down
9 changes: 5 additions & 4 deletions fs/smb/client/dfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,16 +575,17 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru

/* only send once per connect */
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock);
return 0;
}

if (tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON) {
spin_unlock(&tcon->tc_lock);
return -EHOSTDOWN;
}

if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock);
return 0;
}
tcon->status = TID_IN_TCON;
spin_unlock(&tcon->tc_lock);

Expand Down
8 changes: 6 additions & 2 deletions fs/smb/client/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -4942,9 +4942,13 @@ void cifs_oplock_break(struct work_struct *work)
* disconnected since oplock already released by the server
*/
if (!oplock_break_cancelled) {
rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
/* check for server null since can race with kill_sb calling tree disconnect */
if (tcon->ses && tcon->ses->server) {
rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
volatile_fid, net_fid, cinode);
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
} else
pr_warn_once("lease break not sent for unmounted share\n");
}

cifs_done_oplock_break(cinode);
Expand Down
40 changes: 40 additions & 0 deletions fs/smb/client/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ static int
change_conf(struct TCP_Server_Info *server)
{
server->credits += server->echo_credits + server->oplock_credits;
if (server->credits > server->max_credits)
server->credits = server->max_credits;
server->oplock_credits = server->echo_credits = 0;
switch (server->credits) {
case 0:
Expand Down Expand Up @@ -91,6 +93,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
server->conn_id, server->hostname, *val,
add, server->in_flight);
}
WARN_ON_ONCE(server->in_flight == 0);
server->in_flight--;
if (server->in_flight == 0 &&
((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
Expand Down Expand Up @@ -510,6 +513,43 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
return rsize;
}

/*
* compare two interfaces a and b
* return 0 if everything matches.
* return 1 if a is rdma capable, or rss capable, or has higher link speed
* return -1 otherwise.
*/
static int
iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
{
int cmp_ret = 0;

WARN_ON(!a || !b);
if (a->rdma_capable == b->rdma_capable) {
if (a->rss_capable == b->rss_capable) {
if (a->speed == b->speed) {
cmp_ret = cifs_ipaddr_cmp((struct sockaddr *) &a->sockaddr,
(struct sockaddr *) &b->sockaddr);
if (!cmp_ret)
return 0;
else if (cmp_ret > 0)
return 1;
else
return -1;
} else if (a->speed > b->speed)
return 1;
else
return -1;
} else if (a->rss_capable > b->rss_capable)
return 1;
else
return -1;
} else if (a->rdma_capable > b->rdma_capable)
return 1;
else
return -1;
}

static int
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
size_t buf_len, struct cifs_ses *ses, bool in_mount)
Expand Down
Loading

0 comments on commit 7a043fe

Please sign in to comment.