Commit 7a043feb authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents b6dad517 e4645cc2
Loading
Loading
Loading
Loading
+54 −4
Original line number Diff line number Diff line
@@ -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"
@@ -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,
@@ -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);
@@ -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)
+0 −37
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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,
+55 −4
Original line number Diff line number Diff line
@@ -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
@@ -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);

+5 −4
Original line number Diff line number Diff line
@@ -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);

Loading