Commit 6787dc24 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '4.16-rc-SMB3' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs updates from Steve French:
 "Some fixes for stable, fixed SMB3 DFS support, SMB3 Direct (RDMA) and
  various bug fixes and cleanup"

* tag '4.16-rc-SMB3' of git://git.samba.org/sfrench/cifs-2.6: (60 commits)
  fs/cifs/cifsacl.c Fixes typo in a comment
  update internal version number for cifs.ko
  cifs: add .splice_write
  CIFS: document tcon/ses/server refcount dance
  move a few externs to smbdirect.h to eliminate warning
  CIFS: zero sensitive data when freeing
  Cleanup some minor endian issues in smb3 rdma
  CIFS: dump IPC tcon in debug proc file
  CIFS: use tcon_ipc instead of use_ipc parameter of SMB2_ioctl
  CIFS: make IPC a regular tcon
  cifs: remove redundant duplicated assignment of pointer 'node'
  CIFS: SMBD: work around gcc -Wmaybe-uninitialized warning
  cifs: Fix autonegotiate security settings mismatch
  CIFS: SMBD: _smbd_get_connection() can be static
  CIFS: SMBD: Disable signing on SMB direct transport
  CIFS: SMBD: Add SMB Direct debug counters
  CIFS: SMBD: Upper layer performs SMB read via RDMA write through memory registration
  CIFS: SMBD: Read correct returned data length for RDMA write (SMB read) I/O
  CIFS: SMBD: Upper layer performs SMB write via RDMA read through memory registration
  CIFS: SMBD: Implement RDMA memory registration
  ...
parents a4b7fd7d 36c7ce4a
......@@ -196,6 +196,14 @@ config CIFS_SMB311
This dialect includes improved security negotiation features.
If unsure, say N
config CIFS_SMB_DIRECT
bool "SMB Direct support (Experimental)"
depends on CIFS=m && INFINIBAND || CIFS=y && INFINIBAND=y
help
Enables SMB Direct experimental support for SMB 3.0, 3.02 and 3.1.1.
SMB Direct allows transferring SMB packets over RDMA. If unsure,
say N.
config CIFS_FSCACHE
bool "Provide CIFS client caching support"
depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y
......
......@@ -19,3 +19,5 @@ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
cifs-$(CONFIG_CIFS_SMB_DIRECT) += smbdirect.o
......@@ -30,6 +30,9 @@
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifsfs.h"
#ifdef CONFIG_CIFS_SMB_DIRECT
#include "smbdirect.h"
#endif
void
cifs_dump_mem(char *label, void *data, int length)
......@@ -107,6 +110,32 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
}
#ifdef CONFIG_PROC_FS
static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
{
__u32 dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
seq_printf(m, "%s Mounts: %d ", tcon->treeName, tcon->tc_count);
if (tcon->nativeFileSystem)
seq_printf(m, "Type: %s ", tcon->nativeFileSystem);
seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x\n\tPathComponentMax: %d Status: %d",
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
le32_to_cpu(tcon->fsAttrInfo.Attributes),
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
tcon->tidStatus);
if (dev_type == FILE_DEVICE_DISK)
seq_puts(m, " type: DISK ");
else if (dev_type == FILE_DEVICE_CD_ROM)
seq_puts(m, " type: CDROM ");
else
seq_printf(m, " type: %d ", dev_type);
if (tcon->ses->server->ops->dump_share_caps)
tcon->ses->server->ops->dump_share_caps(m, tcon);
if (tcon->need_reconnect)
seq_puts(m, "\tDISCONNECTED ");
seq_putc(m, '\n');
}
static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{
struct list_head *tmp1, *tmp2, *tmp3;
......@@ -115,7 +144,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
struct cifs_ses *ses;
struct cifs_tcon *tcon;
int i, j;
__u32 dev_type;
seq_puts(m,
"Display Internal CIFS Data Structures for Debugging\n"
......@@ -152,6 +180,72 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
list_for_each(tmp1, &cifs_tcp_ses_list) {
server = list_entry(tmp1, struct TCP_Server_Info,
tcp_ses_list);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (!server->rdma)
goto skip_rdma;
seq_printf(m, "\nSMBDirect (in hex) protocol version: %x "
"transport status: %x",
server->smbd_conn->protocol,
server->smbd_conn->transport_status);
seq_printf(m, "\nConn receive_credit_max: %x "
"send_credit_target: %x max_send_size: %x",
server->smbd_conn->receive_credit_max,
server->smbd_conn->send_credit_target,
server->smbd_conn->max_send_size);
seq_printf(m, "\nConn max_fragmented_recv_size: %x "
"max_fragmented_send_size: %x max_receive_size:%x",
server->smbd_conn->max_fragmented_recv_size,
server->smbd_conn->max_fragmented_send_size,
server->smbd_conn->max_receive_size);
seq_printf(m, "\nConn keep_alive_interval: %x "
"max_readwrite_size: %x rdma_readwrite_threshold: %x",
server->smbd_conn->keep_alive_interval,
server->smbd_conn->max_readwrite_size,
server->smbd_conn->rdma_readwrite_threshold);
seq_printf(m, "\nDebug count_get_receive_buffer: %x "
"count_put_receive_buffer: %x count_send_empty: %x",
server->smbd_conn->count_get_receive_buffer,
server->smbd_conn->count_put_receive_buffer,
server->smbd_conn->count_send_empty);
seq_printf(m, "\nRead Queue count_reassembly_queue: %x "
"count_enqueue_reassembly_queue: %x "
"count_dequeue_reassembly_queue: %x "
"fragment_reassembly_remaining: %x "
"reassembly_data_length: %x "
"reassembly_queue_length: %x",
server->smbd_conn->count_reassembly_queue,
server->smbd_conn->count_enqueue_reassembly_queue,
server->smbd_conn->count_dequeue_reassembly_queue,
server->smbd_conn->fragment_reassembly_remaining,
server->smbd_conn->reassembly_data_length,
server->smbd_conn->reassembly_queue_length);
seq_printf(m, "\nCurrent Credits send_credits: %x "
"receive_credits: %x receive_credit_target: %x",
atomic_read(&server->smbd_conn->send_credits),
atomic_read(&server->smbd_conn->receive_credits),
server->smbd_conn->receive_credit_target);
seq_printf(m, "\nPending send_pending: %x send_payload_pending:"
" %x smbd_send_pending: %x smbd_recv_pending: %x",
atomic_read(&server->smbd_conn->send_pending),
atomic_read(&server->smbd_conn->send_payload_pending),
server->smbd_conn->smbd_send_pending,
server->smbd_conn->smbd_recv_pending);
seq_printf(m, "\nReceive buffers count_receive_queue: %x "
"count_empty_packet_queue: %x",
server->smbd_conn->count_receive_queue,
server->smbd_conn->count_empty_packet_queue);
seq_printf(m, "\nMR responder_resources: %x "
"max_frmr_depth: %x mr_type: %x",
server->smbd_conn->responder_resources,
server->smbd_conn->max_frmr_depth,
server->smbd_conn->mr_type);
seq_printf(m, "\nMR mr_ready_count: %x mr_used_count: %x",
atomic_read(&server->smbd_conn->mr_ready_count),
atomic_read(&server->smbd_conn->mr_used_count));
skip_rdma:
#endif
seq_printf(m, "\nNumber of credits: %d", server->credits);
i++;
list_for_each(tmp2, &server->smb_ses_list) {
......@@ -176,6 +270,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
ses->ses_count, ses->serverOS, ses->serverNOS,
ses->capabilities, ses->status);
}
if (server->rdma)
seq_printf(m, "RDMA\n\t");
seq_printf(m, "TCP status: %d\n\tLocal Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d",
server->tcpStatus, server->srv_count,
......@@ -189,35 +285,19 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_puts(m, "\n\tShares:");
j = 0;
seq_printf(m, "\n\t%d) IPC: ", j);
if (ses->tcon_ipc)
cifs_debug_tcon(m, ses->tcon_ipc);
else
seq_puts(m, "none\n");
list_for_each(tmp3, &ses->tcon_list) {
tcon = list_entry(tmp3, struct cifs_tcon,
tcon_list);
++j;
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
seq_printf(m, "\n\t%d) %s Mounts: %d ", j,
tcon->treeName, tcon->tc_count);
if (tcon->nativeFileSystem) {
seq_printf(m, "Type: %s ",
tcon->nativeFileSystem);
}
seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
"\n\tPathComponentMax: %d Status: %d",
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
le32_to_cpu(tcon->fsAttrInfo.Attributes),
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
tcon->tidStatus);
if (dev_type == FILE_DEVICE_DISK)
seq_puts(m, " type: DISK ");
else if (dev_type == FILE_DEVICE_CD_ROM)
seq_puts(m, " type: CDROM ");
else
seq_printf(m, " type: %d ", dev_type);
if (server->ops->dump_share_caps)
server->ops->dump_share_caps(m, tcon);
if (tcon->need_reconnect)
seq_puts(m, "\tDISCONNECTED ");
seq_putc(m, '\n');
seq_printf(m, "\n\t%d) ", j);
cifs_debug_tcon(m, tcon);
}
seq_puts(m, "\n\tMIDs:\n");
......@@ -374,6 +454,45 @@ static const struct file_operations cifs_stats_proc_fops = {
};
#endif /* STATS */
#ifdef CONFIG_CIFS_SMB_DIRECT
#define PROC_FILE_DEFINE(name) \
static ssize_t name##_write(struct file *file, const char __user *buffer, \
size_t count, loff_t *ppos) \
{ \
int rc; \
rc = kstrtoint_from_user(buffer, count, 10, & name); \
if (rc) \
return rc; \
return count; \
} \
static int name##_proc_show(struct seq_file *m, void *v) \
{ \
seq_printf(m, "%d\n", name ); \
return 0; \
} \
static int name##_open(struct inode *inode, struct file *file) \
{ \
return single_open(file, name##_proc_show, NULL); \
} \
\
static const struct file_operations cifs_##name##_proc_fops = { \
.open = name##_open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
.write = name##_write, \
}
PROC_FILE_DEFINE(rdma_readwrite_threshold);
PROC_FILE_DEFINE(smbd_max_frmr_depth);
PROC_FILE_DEFINE(smbd_keep_alive_interval);
PROC_FILE_DEFINE(smbd_max_receive_size);
PROC_FILE_DEFINE(smbd_max_fragmented_recv_size);
PROC_FILE_DEFINE(smbd_max_send_size);
PROC_FILE_DEFINE(smbd_send_credit_target);
PROC_FILE_DEFINE(smbd_receive_credit_max);
#endif
static struct proc_dir_entry *proc_fs_cifs;
static const struct file_operations cifsFYI_proc_fops;
static const struct file_operations cifs_lookup_cache_proc_fops;
......@@ -401,6 +520,24 @@ cifs_proc_init(void)
&cifs_security_flags_proc_fops);
proc_create("LookupCacheEnabled", 0, proc_fs_cifs,
&cifs_lookup_cache_proc_fops);
#ifdef CONFIG_CIFS_SMB_DIRECT
proc_create("rdma_readwrite_threshold", 0, proc_fs_cifs,
&cifs_rdma_readwrite_threshold_proc_fops);
proc_create("smbd_max_frmr_depth", 0, proc_fs_cifs,
&cifs_smbd_max_frmr_depth_proc_fops);
proc_create("smbd_keep_alive_interval", 0, proc_fs_cifs,
&cifs_smbd_keep_alive_interval_proc_fops);
proc_create("smbd_max_receive_size", 0, proc_fs_cifs,
&cifs_smbd_max_receive_size_proc_fops);
proc_create("smbd_max_fragmented_recv_size", 0, proc_fs_cifs,
&cifs_smbd_max_fragmented_recv_size_proc_fops);
proc_create("smbd_max_send_size", 0, proc_fs_cifs,
&cifs_smbd_max_send_size_proc_fops);
proc_create("smbd_send_credit_target", 0, proc_fs_cifs,
&cifs_smbd_send_credit_target_proc_fops);
proc_create("smbd_receive_credit_max", 0, proc_fs_cifs,
&cifs_smbd_receive_credit_max_proc_fops);
#endif
}
void
......@@ -418,6 +555,16 @@ cifs_proc_clean(void)
remove_proc_entry("SecurityFlags", proc_fs_cifs);
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
#ifdef CONFIG_CIFS_SMB_DIRECT
remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
remove_proc_entry("smbd_keep_alive_interval", proc_fs_cifs);
remove_proc_entry("smbd_max_receive_size", proc_fs_cifs);
remove_proc_entry("smbd_max_fragmented_recv_size", proc_fs_cifs);
remove_proc_entry("smbd_max_send_size", proc_fs_cifs);
remove_proc_entry("smbd_send_credit_target", proc_fs_cifs);
remove_proc_entry("smbd_receive_credit_max", proc_fs_cifs);
#endif
remove_proc_entry("fs/cifs", NULL);
}
......
......@@ -1125,7 +1125,7 @@ int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
return rc;
}
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
struct inode *inode, const char *path,
......
......@@ -325,9 +325,8 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
{
int i;
int rc;
char password_with_pad[CIFS_ENCPWD_SIZE];
char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
if (password)
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
......
......@@ -327,6 +327,8 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
default:
seq_puts(s, "(unknown)");
}
if (server->rdma)
seq_puts(s, ",rdma");
}
static void
......@@ -1068,6 +1070,7 @@ const struct file_operations cifs_file_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
.unlocked_ioctl = cifs_ioctl,
.copy_file_range = cifs_copy_file_range,
......@@ -1086,6 +1089,7 @@ const struct file_operations cifs_file_strict_ops = {
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
.unlocked_ioctl = cifs_ioctl,
.copy_file_range = cifs_copy_file_range,
......@@ -1105,6 +1109,7 @@ const struct file_operations cifs_file_direct_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = cifs_ioctl,
.copy_file_range = cifs_copy_file_range,
.clone_file_range = cifs_clone_file_range,
......@@ -1122,6 +1127,7 @@ const struct file_operations cifs_file_nobrl_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
.unlocked_ioctl = cifs_ioctl,
.copy_file_range = cifs_copy_file_range,
......@@ -1139,6 +1145,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
.flush = cifs_flush,
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.llseek = cifs_llseek,
.unlocked_ioctl = cifs_ioctl,
.copy_file_range = cifs_copy_file_range,
......@@ -1157,6 +1164,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = cifs_ioctl,
.copy_file_range = cifs_copy_file_range,
.clone_file_range = cifs_clone_file_range,
......
......@@ -149,5 +149,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "2.10"
#define CIFS_VERSION "2.11"
#endif /* _CIFSFS_H */
......@@ -64,8 +64,8 @@
#define RFC1001_NAME_LEN 15
#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
/* currently length of NIP6_FMT */
#define SERVER_NAME_LENGTH 40
/* maximum length of ip addr as a string (including ipv6 and sctp) */
#define SERVER_NAME_LENGTH 80
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
/* echo interval in seconds */
......@@ -230,8 +230,14 @@ struct smb_version_operations {
__u64 (*get_next_mid)(struct TCP_Server_Info *);
/* data offset from read response message */
unsigned int (*read_data_offset)(char *);
/* data length from read response message */
unsigned int (*read_data_length)(char *);
/*
* Data length from read response message
* When in_remaining is true, the returned data length is in
* message field DataRemaining for out-of-band data read (e.g through
* Memory Registration RDMA write in SMBD).
* Otherwise, the returned data length is in message field DataLength.
*/
unsigned int (*read_data_length)(char *, bool in_remaining);
/* map smb to linux error */
int (*map_error)(char *, bool);
/* find mid corresponding to the response message */
......@@ -532,6 +538,7 @@ struct smb_vol {
bool nopersistent:1;
bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
bool rdma:1;
unsigned int rsize;
unsigned int wsize;
bool sockopt_tcp_nodelay:1;
......@@ -648,6 +655,10 @@ struct TCP_Server_Info {
bool sec_kerberos; /* supports plain Kerberos */
bool sec_mskerberos; /* supports legacy MS Kerberos */
bool large_buf; /* is current buffer large? */
/* use SMBD connection instead of socket */
bool rdma;
/* point to the SMBD connection if RDMA is used instead of socket */
struct smbd_connection *smbd_conn;
struct delayed_work echo; /* echo ping workqueue job */
char *smallbuf; /* pointer to current "small" buffer */
char *bigbuf; /* pointer to current "big" buffer */
......@@ -822,12 +833,12 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
struct cifs_ses {
struct list_head smb_ses_list;
struct list_head tcon_list;
struct cifs_tcon *tcon_ipc;
struct mutex session_mutex;
struct TCP_Server_Info *server; /* pointer to server info */
int ses_count; /* reference counter */
enum statusEnum status;
unsigned overrideSecFlg; /* if non-zero override global sec flags */
__u32 ipc_tid; /* special tid for connection to IPC share */
char *serverOS; /* name of operating system underlying server */
char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */
......@@ -835,8 +846,7 @@ struct cifs_ses {
kuid_t linux_uid; /* overriding owner of files on the mount */
kuid_t cred_uid; /* owner of credentials */
unsigned int capabilities;
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */
char serverName[SERVER_NAME_LEN_WITH_NULL];
char *user_name; /* must not be null except during init of sess
and after mount option parsing we fill it */
char *domainName;
......@@ -931,7 +941,9 @@ struct cifs_tcon {
FILE_SYSTEM_DEVICE_INFO fsDevInfo;
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
bool ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */
bool ipc:1; /* set if connection to IPC$ share (always also pipe) */
bool pipe:1; /* set if connection to pipe share */
bool print:1; /* set if connection to printer share */
bool retry:1;
bool nocase:1;
bool seal:1; /* transport encryption for this mounted share */
......@@ -944,7 +956,6 @@ struct cifs_tcon {
bool need_reopen_files:1; /* need to reopen tcon file handles */
bool use_resilient:1; /* use resilient instead of durable handles */
bool use_persistent:1; /* use persistent instead of durable handles */
bool print:1; /* set if connection to printer share */
__le32 capabilities;
__u32 share_flags;
__u32 maximal_access;
......@@ -1147,6 +1158,9 @@ struct cifs_readdata {
struct cifs_readdata *rdata,
struct iov_iter *iter);
struct kvec iov[2];
#ifdef CONFIG_CIFS_SMB_DIRECT
struct smbd_mr *mr;
#endif
unsigned int pagesz;
unsigned int tailsz;
unsigned int credits;
......@@ -1169,6 +1183,9 @@ struct cifs_writedata {
pid_t pid;
unsigned int bytes;
int result;
#ifdef CONFIG_CIFS_SMB_DIRECT
struct smbd_mr *mr;
#endif
unsigned int pagesz;
unsigned int tailsz;
unsigned int credits;
......
......@@ -106,6 +106,10 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
struct kvec *, int /* nvec to send */,
int * /* type of buf returned */, const int flags,
struct kvec * /* resp vec */);
extern int smb2_send_recv(const unsigned int xid, struct cifs_ses *pses,
struct kvec *pkvec, int nvec_to_send,
int *pbuftype, const int flags,
struct kvec *presp);
extern int SendReceiveBlockingLock(const unsigned int xid,
struct cifs_tcon *ptcon,
struct smb_hdr *in_buf ,
......
......@@ -43,6 +43,7 @@
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "fscache.h"
#include "smbdirect.h"
#ifdef CONFIG_CIFS_POSIX
static struct {
......@@ -1454,6 +1455,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
struct cifs_readdata *rdata = mid->callback_data;
char *buf = server->smallbuf;
unsigned int buflen = get_rfc1002_length(buf) + 4;
bool use_rdma_mr = false;
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
__func__, mid->mid, rdata->offset, rdata->bytes);
......@@ -1542,8 +1544,11 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
rdata->iov[0].iov_base, server->total_read);
/* how much data is in the response? */
data_len = server->ops->read_data_length(buf);
if (data_offset + data_len > buflen) {
#ifdef CONFIG_CIFS_SMB_DIRECT
use_rdma_mr = rdata->mr;
#endif
data_len = server->ops->read_data_length(buf, use_rdma_mr);
if (!use_rdma_mr && (data_offset + data_len > buflen)) {
/* data_len is corrupt -- discard frame */
rdata->result = -EIO;
return cifs_readv_discard(server, mid);
......@@ -1923,6 +1928,12 @@ cifs_writedata_release(struct kref *refcount)
{
struct cifs_writedata *wdata = container_of(refcount,
struct cifs_writedata, refcount);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (wdata->mr) {
smbd_deregister_mr(wdata->mr);
wdata->mr = NULL;
}
#endif
if (wdata->cfile)
cifsFileInfo_put(wdata->cfile);
......@@ -4822,10 +4833,11 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
*target_nodes = NULL;
cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
if (ses == NULL)
if (ses == NULL || ses->tcon_ipc == NULL)
return -ENODEV;
getDFSRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
......@@ -4833,7 +4845,7 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
/* server pointer checked in called function,
but should never be null here anyway */
pSMB->hdr.Mid = get_next_mid(ses->server);
pSMB->hdr.Tid = ses->ipc_tid;
pSMB->hdr.Tid = ses->tcon_ipc->tid;
pSMB->hdr.Uid = ses->Suid;
if (ses->capabilities & CAP_STATUS32)
pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
......
This diff is collapsed.
......@@ -42,7 +42,7 @@
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include "fscache.h"
#include "smbdirect.h"
static inline int cifs_convert_flags(unsigned int flags)
{
......@@ -2902,7 +2902,12 @@ cifs_readdata_release(struct kref *refcount)
{
struct cifs_readdata *rdata = container_of(refcount,
struct cifs_readdata, refcount);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (rdata->mr) {
smbd_deregister_mr(rdata->mr);
rdata->mr = NULL;
}
#endif
if (rdata->cfile)
cifsFileInfo_put(rdata->cfile);
......@@ -3031,6 +3036,10 @@ uncached_fill_pages(struct TCP_Server_Info *server,
}
if (iter)
result = copy_page_from_iter(page, 0, n, iter);
#ifdef CONFIG_CIFS_SMB_DIRECT
else if (rdata->mr)
result = n;
#endif
else
result = cifs_read_page_from_socket(server, page, n);
if (result < 0)
......@@ -3471,20 +3480,18 @@ static const struct vm_operations_struct cifs_file_vm_ops = {
int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
{
int rc, xid;
int xid, rc = 0;
struct inode *inode = file_inode(file);
xid = get_xid();
if (!CIFS_CACHE_READ(CIFS_I(inode))) {
if (!CIFS_CACHE_READ(CIFS_I(inode)))
rc = cifs_zap_mapping(inode);
if (rc)
return rc;
}
rc = generic_file_mmap(file, vma);
if (rc == 0)
if (!rc)
rc = generic_file_mmap(file, vma);
if (!rc)
vma->vm_ops = &cifs_file_vm_ops;
free_xid(xid);
return rc;
}
......@@ -3494,16 +3501,16 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
int rc, xid;
xid = get_xid();
rc = cifs_revalidate_file(file);
if (rc) {
if (rc)
cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n",
rc);
free_xid(xid);
return rc;
}
rc = generic_file_mmap(file, vma);
if (rc == 0)
if (!rc)
rc = generic_file_mmap(file, vma);
if (!rc)
vma->vm_ops = &cifs_file_vm_ops;
free_xid(xid);
return rc;
}
......@@ -3600,6 +3607,10 @@ readpages_fill_pages(struct TCP_Server_Info *server,
if (iter)
result = copy_page_from_iter(page, 0, n, iter);
#ifdef CONFIG_CIFS_SMB_DIRECT
else if (rdata->mr)
result = n;
#endif
else
result = cifs_read_page_from_socket(server, page, n);
if (result < 0)
......
......@@ -1049,7 +1049,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
tcon->resource_id = CIFS_I(inode)->uniqueid;
#endif
if (rc && tcon->ipc) {
if (rc && tcon->pipe) {
cifs_dbg(FYI, "ipc connection - fake read inode\n");
spin_lock(&inode->i_lock);
inode->i_mode |= S_IFDIR;
......
......@@ -98,14 +98,11 @@ sesInfoFree(struct cifs_ses *buf_to_free)
kfree(buf_to_free->serverOS);
kfree(buf_to_free->serverDomain);
kfree(buf_to_free->serverNOS);
if (buf_to_free->password) {
memset(buf_to_free->password, 0, strlen(buf_to_free->password));
kfree(buf_to_free->password);
}
kzfree(buf_to_free->password);
kfree(buf_to_free->user_name);
kfree(buf_to_free->domainName);
kfree(buf_to_free->auth_key.response);
kfree(buf_to_free);
kzfree(buf_to_free->auth_key.response);
kzfree(buf_to_free);
}
struct cifs_tcon *
......@@ -136,10 +133,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
}
atomic_dec(&tconInfoAllocCount);
kfree(buf_to_free->nativeFileSystem);
if (buf_to_free->password) {
memset(buf_to_free->password, 0, strlen(buf_to_free->password));
kfree(buf_to_free->password);
}
kzfree(buf_to_free->password);
kfree(buf_to_free);
}
......
......@@ -87,9 +87,11 @@ cifs_read_data_offset(char *buf)
}
static unsigned int
cifs_read_data_length(char *buf)
cifs_read_data_length(char *buf, bool in_remaining)
{
READ_RSP *rsp = (READ_RSP *)buf;
/* It's a bug reading remaining data for SMB1 packets */
WARN_ON(in_remaining);
return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
le16_to_cpu(rsp->DataLength);
}
......
......@@ -74,7 +74,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
nr_ioctl_req.Reserved = 0;
rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
true /* is_fsctl */, false /* use_ipc */,
true /* is_fsctl */,
(char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
NULL, NULL /* no return info */);
if (rc == -EOPNOTSUPP) {
......
......@@ -578,7 +578,7 @@ smb2_is_valid_lease_break(char *buffer)
bool
smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
{
struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
struct smb2_oplock_break_rsp *rsp = (struct smb2_oplock_break_rsp *)buffer;
struct list_head *tmp, *tmp1, *tmp2;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
......
......@@ -32,6 +32,7 @@
#include "smb2status.h"
#include "smb2glob.h"
#include "cifs_ioctl.h"
#include "smbdirect.h"
static int
change_conf(struct TCP_Server_Info *server)
......@@ -250,7 +251,11 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
/* start with specified wsize, or default */
wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
wsize = min_t(unsigned int, wsize, server->max_write);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma)
wsize = min_t(unsigned int,
wsize, server->smbd_conn->max_readwrite_size);
#endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
......@@ -266,6 +271,11 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
/* start with specified rsize, or default */
rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
rsize = min_t(unsigned int, rsize, server->max_read);
#ifdef CONFIG_CIFS_SMB_DIRECT
if (server->rdma)
rsize = min_t(unsigned int,
rsize, server->smbd_conn->max_readwrite_size);
#endif
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
......@@ -283,7 +293,6 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
false /* use_ipc */,
NULL /* no data input */, 0 /* no data input */,
(char **)&out_buf, &ret_data_len);
if (rc != 0)
......@@ -782,7 +791,6 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
false /* use_ipc */,
NULL, 0 /* no input */,
(char **)&res_key, &ret_data_len);
......@@ -848,8 +856,7 @@ smb2_copychunk_range(const unsigned int xid,
/* Request server copy to target from src identified by key */
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
true /* is_fsctl */, false /* use_ipc */,
(char *)pcchunk,
true /* is_fsctl */, (char *)pcchunk,
sizeof(struct copychunk_ioctl), (char **)&retbuf,
&ret_data_len);
if (rc == 0) {
......@@ -947,9 +954,13 @@ smb2_read_data_offset(char *buf)
}
static unsigned int
smb2_read_data_length(char *buf)
smb2_read_data_length(char *buf, bool in_remaining)
{
struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
if (in_remaining)
return le32_to_cpu(rsp->DataRemaining);
return le32_to_cpu(rsp->DataLength);
}
......@@ -1006,7 +1017,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
true /* is_fctl */, false /* use_ipc */,
true /* is_fctl */,
&setsparse, 1, NULL, NULL);
if (rc) {
tcon->broken_sparse_sup = true;
......@@ -1077,7 +1088,7 @@ smb2_duplicate_extents(const unsigned int xid,
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
trgtfile->fid.volatile_fid,
FSCTL_DUPLICATE_EXTENTS_TO_FILE,
true /* is_fsctl */, false /* use_ipc */,
true /* is_fsctl */,
(char *)&dup_ext_buf,
sizeof(struct duplicate_extents_to_file),
NULL,
......@@ -1112,7 +1123,7 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
FSCTL_SET_INTEGRITY_INFORMATION,
true /* is_fsctl */, false /* use_ipc */,
true /* is_fsctl */,
(char *)&integr_info,
sizeof(struct fsctl_set_integrity_information_req),
NULL,
......@@ -1132,7 +1143,7 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
FSCTL_SRV_ENUMERATE_SNAPSHOTS,
true /* is_fsctl */, false /* use_ipc */,
true /* is_fsctl */,
NULL, 0 /* no input data */,
(char **)&retbuf,
&ret_data_len);
......@@ -1351,16 +1362,20 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name);
/*
* Use any tcon from the current session. Here, the first one.
* Try to use the IPC tcon, otherwise just use any
*/
spin_lock(&cifs_tcp_ses_lock);
tcon = list_first_entry_or_null(&ses->tcon_list, struct cifs_tcon,
tcon_list);
if (tcon)
tcon->tc_count++;
spin_unlock(&cifs_tcp_ses_lock);
tcon = ses->tcon_ipc;
if (tcon == NULL) {
spin_lock(&cifs_tcp_ses_lock);
tcon = list_first_entry_or_null(&ses->tcon_list,
struct cifs_tcon,
tcon_list);
if (tcon)
tcon->tc_count++;
spin_unlock(&cifs_tcp_ses_lock);
}
if (!tcon) {
if (tcon == NULL) {
cifs_dbg(VFS, "session %p has no tcon available for a dfs referral request\n",
ses);
rc = -ENOTCONN;
......@@ -1389,20 +1404,11 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len);
do {
/* try first with IPC */
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_DFS_GET_REFERRALS,
true /* is_fsctl */, true /* use_ipc */,
true /* is_fsctl */,
(char *)dfs_req, dfs_req_size,
(char **)&dfs_rsp, &dfs_rsp_size);
if (rc == -ENOTCONN) {
/* try with normal tcon */
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_DFS_GET_REFERRALS,
true /* is_fsctl */, false /*use_ipc*/,
(char *)dfs_req, dfs_req_size,
(char **)&dfs_rsp, &dfs_rsp_size);
}
} while (rc == -EAGAIN);
if (rc) {
......@@ -1421,7 +1427,8 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
}
out:
if (tcon) {
if (tcon && !tcon->ipc) {
/* ipc tcons are not refcounted */
spin_lock(&cifs_tcp_ses_lock);
tcon->tc_count--;
spin_unlock(&cifs_tcp_ses_lock);
......@@ -1713,8 +1720,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
true /* is_fctl */, false /* use_ipc */,
(char *)&fsctl_buf,
true /* is_fctl */, (char *)&fsctl_buf,
sizeof(struct file_zero_data_information), NULL, NULL);
free_xid(xid);
return rc;
......@@ -1748,8 +1754,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
true /* is_fctl */, false /* use_ipc */,
(char *)&fsctl_buf,
true /* is_fctl */, (char *)&fsctl_buf,
sizeof(struct file_zero_data_information), NULL, NULL);
free_xid(xid);
return rc;
......@@ -2411,6 +2416,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
struct iov_iter iter;
struct kvec iov;
int length;
bool use_rdma_mr = false;
if (shdr->Command != SMB2_READ) {
cifs_dbg(VFS, "only big read responses are supported\n");
......@@ -2437,7 +2443,10 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
}
data_offset = server->ops->read_data_offset(buf) + 4;
data_len = server->ops->read_data_length(buf);
#ifdef CONFIG_CIFS_SMB_DIRECT
use_rdma_mr = rdata->mr;
#endif
data_len = server->ops->read_data_length(buf, use_rdma_mr);
if (data_offset < server->vals->read_rsp_size) {
/*
......
This diff is collapsed.
......@@ -195,7 +195,7 @@ struct smb2_symlink_err_rsp {
#define SMB2_CLIENT_GUID_SIZE 16
struct smb2_negotiate_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 36 */
__le16 DialectCount;
__le16 SecurityMode;
......@@ -282,7 +282,7 @@ struct smb2_negotiate_rsp {
#define SMB2_SESSION_REQ_FLAG_ENCRYPT_DATA 0x04
struct smb2_sess_setup_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 25 */
__u8 Flags;
__u8 SecurityMode;
......@@ -308,7 +308,7 @@ struct smb2_sess_setup_rsp {
} __packed;
struct smb2_logoff_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 4 */
__le16 Reserved;
} __packed;
......@@ -323,7 +323,7 @@ struct smb2_logoff_rsp {
#define SMB2_SHAREFLAG_CLUSTER_RECONNECT 0x0001
struct smb2_tree_connect_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 9 */
__le16 Reserved; /* Flags in SMB3.1.1 */
__le16 PathOffset;
......@@ -375,7 +375,7 @@ struct smb2_tree_connect_rsp {
#define SMB2_SHARE_CAP_ASYMMETRIC cpu_to_le32(0x00000080) /* 3.02 */
struct smb2_tree_disconnect_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 4 */
__le16 Reserved;
} __packed;
......@@ -496,7 +496,7 @@ struct smb2_tree_disconnect_rsp {
#define SVHDX_OPEN_DEVICE_CONTEXT 0x83CE6F1AD851E0986E34401CC9BCFCE9
struct smb2_create_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 57 */
__u8 SecurityFlags;
__u8 RequestedOplockLevel;
......@@ -753,7 +753,7 @@ struct duplicate_extents_to_file {
} __packed;
struct smb2_ioctl_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 57 */
__u16 Reserved;
__le32 CtlCode;
......@@ -789,7 +789,7 @@ struct smb2_ioctl_rsp {
/* Currently defined values for close flags */
#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001)
struct smb2_close_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 24 */
__le16 Flags;
__le32 Reserved;
......@@ -812,7 +812,7 @@ struct smb2_close_rsp {
} __packed;
struct smb2_flush_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 24 */
__le16 Reserved1;
__le32 Reserved2;
......@@ -830,9 +830,9 @@ struct smb2_flush_rsp {
#define SMB2_READFLAG_READ_UNBUFFERED 0x01
/* Channel field for read and write: exactly one of following flags can be set*/
#define SMB2_CHANNEL_NONE 0x00000000
#define SMB2_CHANNEL_RDMA_V1 0x00000001 /* SMB3 or later */
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000002 /* SMB3.02 or later */
#define SMB2_CHANNEL_NONE cpu_to_le32(0x00000000)
#define SMB2_CHANNEL_RDMA_V1 cpu_to_le32(0x00000001) /* SMB3 or later */
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE cpu_to_le32(0x00000002) /* >= SMB3.02 */
/* SMB2 read request without RFC1001 length at the beginning */
struct smb2_read_plain_req {
......@@ -847,8 +847,8 @@ struct smb2_read_plain_req {
__le32 MinimumCount;
__le32 Channel; /* MBZ except for SMB3 or later */
__le32 RemainingBytes;
__le16 ReadChannelInfoOffset; /* Reserved MBZ */
__le16 ReadChannelInfoLength; /* Reserved MBZ */
__le16 ReadChannelInfoOffset;
__le16 ReadChannelInfoLength;
__u8 Buffer[1];
} __packed;
......@@ -868,7 +868,7 @@ struct smb2_read_rsp {
#define SMB2_WRITEFLAG_WRITE_UNBUFFERED 0x00000002 /* SMB3.02 or later */
struct smb2_write_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 49 */
__le16 DataOffset; /* offset from start of SMB2 header to write data */
__le32 Length;
......@@ -877,8 +877,8 @@ struct smb2_write_req {
__u64 VolatileFileId; /* opaque endianness */
__le32 Channel; /* Reserved MBZ */
__le32 RemainingBytes;
__le16 WriteChannelInfoOffset; /* Reserved MBZ */
__le16 WriteChannelInfoLength; /* Reserved MBZ */
__le16 WriteChannelInfoOffset;
__le16 WriteChannelInfoLength;
__le32 Flags;
__u8 Buffer[1];
} __packed;
......@@ -907,7 +907,7 @@ struct smb2_lock_element {
} __packed;
struct smb2_lock_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 48 */
__le16 LockCount;
__le32 Reserved;
......@@ -924,7 +924,7 @@ struct smb2_lock_rsp {
} __packed;
struct smb2_echo_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 4 */
__u16 Reserved;
} __packed;
......@@ -942,7 +942,7 @@ struct smb2_echo_rsp {
#define SMB2_REOPEN 0x10
struct smb2_query_directory_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 33 */
__u8 FileInformationClass;
__u8 Flags;
......@@ -989,7 +989,7 @@ struct smb2_query_directory_rsp {
#define SL_INDEX_SPECIFIED 0x00000004
struct smb2_query_info_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 41 */
__u8 InfoType;
__u8 FileInfoClass;
......@@ -1013,7 +1013,7 @@ struct smb2_query_info_rsp {
} __packed;
struct smb2_set_info_req {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 33 */
__u8 InfoType;
__u8 FileInfoClass;
......@@ -1031,7 +1031,19 @@ struct smb2_set_info_rsp {
__le16 StructureSize; /* Must be 2 */
} __packed;
struct smb2_oplock_break {
/* oplock break without an rfc1002 header */
struct smb2_oplock_break_req {
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 24 */
__u8 OplockLevel;
__u8 Reserved;
__le32 Reserved2;
__u64 PersistentFid;
__u64 VolatileFid;
} __packed;
/* oplock break with an rfc1002 header */
struct smb2_oplock_break_rsp {
struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 24 */
__u8 OplockLevel;
......@@ -1057,7 +1069,7 @@ struct smb2_lease_break {
} __packed;
struct smb2_lease_ack {
struct smb2_hdr hdr;
struct smb2_sync_hdr sync_hdr;
__le16 StructureSize; /* Must be 36 */
__le16 Reserved;
__le32 Flags;
......
......@@ -125,8 +125,7 @@ extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
struct smb2_err_rsp **err_buf);
extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u32 opcode,
bool is_fsctl, bool use_ipc,
char *in_data, u32 indatalen,
bool is_fsctl, char *in_data, u32 indatalen,
char **out_data, u32 *plen /* returned data len */);
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id);
......
This diff is collapsed.
/*
* Copyright (C) 2017, Microsoft Corporation.
*
* Author(s): Long Li <longli@microsoft.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*/
#ifndef _SMBDIRECT_H
#define _SMBDIRECT_H
#ifdef CONFIG_CIFS_SMB_DIRECT
#define cifs_rdma_enabled(server) ((server)->rdma)
#include "cifsglob.h"
#include <rdma/ib_verbs.h>
#include <rdma/rdma_cm.h>
#include <linux/mempool.h>
extern int rdma_readwrite_threshold;
extern int smbd_max_frmr_depth;
extern int smbd_keep_alive_interval;
extern int smbd_max_receive_size;
extern int smbd_max_fragmented_recv_size;
extern int smbd_max_send_size;
extern int smbd_send_credit_target;
extern int smbd_receive_credit_max;
enum keep_alive_status {
KEEP_ALIVE_NONE,
KEEP_ALIVE_PENDING,
KEEP_ALIVE_SENT,
};
enum smbd_connection_status {
SMBD_CREATED,
SMBD_CONNECTING,
SMBD_CONNECTED,
SMBD_NEGOTIATE_FAILED,
SMBD_DISCONNECTING,
SMBD_DISCONNECTED,
SMBD_DESTROYED
};
/*
* The context for the SMBDirect transport
* Everything related to the transport is here. It has several logical parts
* 1. RDMA related structures
* 2. SMBDirect connection parameters
* 3. Memory registrations
* 4. Receive and reassembly queues for data receive path
* 5. mempools for allocating packets
*/
struct smbd_connection {
enum smbd_connection_status transport_status;
/* RDMA related */
struct rdma_cm_id *id;
struct ib_qp_init_attr qp_attr;
struct ib_pd *pd;
struct ib_cq *send_cq, *recv_cq;
struct ib_device_attr dev_attr;
int ri_rc;
struct completion ri_done;
wait_queue_head_t conn_wait;
wait_queue_head_t wait_destroy;
struct completion negotiate_completion;
bool negotiate_done;
struct work_struct destroy_work;
struct work_struct disconnect_work;
struct work_struct recv_done_work;
struct work_struct post_send_credits_work;
spinlock_t lock_new_credits_offered;
int new_credits_offered;
/* Connection parameters defined in [MS-SMBD] 3.1.1.1 */
int receive_credit_max;
int send_credit_target;
int max_send_size;
int max_fragmented_recv_size;
int max_fragmented_send_size;
int max_receive_size;
int keep_alive_interval;
int max_readwrite_size;
enum keep_alive_status keep_alive_requested;
int protocol;
atomic_t send_credits;
atomic_t receive_credits;
int receive_credit_target;
int fragment_reassembly_remaining;
/* Memory registrations */
/* Maximum number of RDMA read/write outstanding on this connection */
int responder_resources;
/* Maximum number of SGEs in a RDMA write/read */
int max_frmr_depth;
/*
* If payload is less than or equal to the threshold,
* use RDMA send/recv to send upper layer I/O.
* If payload is more than the threshold,
* use RDMA read/write through memory registration for I/O.
*/
int rdma_readwrite_threshold;
enum ib_mr_type mr_type;
struct list_head mr_list;
spinlock_t mr_list_lock;
/* The number of available MRs ready for memory registration */
atomic_t mr_ready_count;
atomic_t mr_used_count;
wait_queue_head_t wait_mr;
struct work_struct mr_recovery_work;
/* Used by transport to wait until all MRs are returned */
wait_queue_head_t wait_for_mr_cleanup;
/* Activity accoutning */
/* Pending reqeusts issued from upper layer */
int smbd_send_pending;
wait_queue_head_t wait_smbd_send_pending;
int smbd_recv_pending;
wait_queue_head_t wait_smbd_recv_pending;
atomic_t send_pending;
wait_queue_head_t wait_send_pending;
atomic_t send_payload_pending;
wait_queue_head_t wait_send_payload_pending;
/* Receive queue */
struct list_head receive_queue;
int count_receive_queue;
spinlock_t receive_queue_lock;
struct list_head empty_packet_queue;
int count_empty_packet_queue;
spinlock_t empty_packet_queue_lock;
wait_queue_head_t wait_receive_queues;
/* Reassembly queue */
struct list_head reassembly_queue;
spinlock_t reassembly_queue_lock;
wait_queue_head_t wait_reassembly_queue;
/* total data length of reassembly queue */
int reassembly_data_length;
int reassembly_queue_length;
/* the offset to first buffer in reassembly queue */
int first_entry_offset;
bool send_immediate;
wait_queue_head_t wait_send_queue;
/*
* Indicate if we have received a full packet on the connection
* This is used to identify the first SMBD packet of a assembled
* payload (SMB packet) in reassembly queue so we can return a
* RFC1002 length to upper layer to indicate the length of the SMB
* packet received
*/
bool full_packet_received;
struct workqueue_struct *workqueue;
struct delayed_work idle_timer_work;
struct delayed_work send_immediate_work;
/* Memory pool for preallocating buffers */
/* request pool for RDMA send */
struct kmem_cache *request_cache;
mempool_t *request_mempool;
/* response pool for RDMA receive */
struct kmem_cache *response_cache;
mempool_t *response_mempool;
/* for debug purposes */
unsigned int count_get_receive_buffer;
unsigned int count_put_receive_buffer;
unsigned int count_reassembly_queue;
unsigned int count_enqueue_reassembly_queue;
unsigned int count_dequeue_reassembly_queue;
unsigned int count_send_empty;
};
enum smbd_message_type {
SMBD_NEGOTIATE_RESP,
SMBD_TRANSFER_DATA,
};
#define SMB_DIRECT_RESPONSE_REQUESTED 0x0001
/* SMBD negotiation request packet [MS-SMBD] 2.2.1 */
struct smbd_negotiate_req {
__le16 min_version;
__le16 max_version;
__le16 reserved;
__le16 credits_requested;
__le32 preferred_send_size;
__le32 max_receive_size;
__le32 max_fragmented_size;
} __packed;
/* SMBD negotiation response packet [MS-SMBD] 2.2.2 */
struct smbd_negotiate_resp {
__le16 min_version;
__le16 max_version;
__le16 negotiated_version;
__le16 reserved;
__le16 credits_requested;
__le16 credits_granted;
__le32 status;
__le32 max_readwrite_size;
__le32 preferred_send_size;
__le32 max_receive_size;
__le32 max_fragmented_size;
} __packed;
/* SMBD data transfer packet with payload [MS-SMBD] 2.2.3 */
struct smbd_data_transfer {
__le16 credits_requested;
__le16 credits_granted;
__le16 flags;
__le16 reserved;
__le32 remaining_data_length;
__le32 data_offset;
__le32 data_length;
__le32 padding;
__u8 buffer[];
} __packed;
/* The packet fields for a registered RDMA buffer */
struct smbd_buffer_descriptor_v1 {
__le64 offset;
__le32 token;
__le32 length;
} __packed;
/* Default maximum number of SGEs in a RDMA send/recv */
#define SMBDIRECT_MAX_SGE 16
/* The context for a SMBD request */
struct smbd_request {
struct smbd_connection *info;
struct ib_cqe cqe;
/* true if this request carries upper layer payload */
bool has_payload;
/* the SGE entries for this packet */
struct ib_sge sge[SMBDIRECT_MAX_SGE];
int num_sge;
/* SMBD packet header follows this structure */
u8 packet[];
};
/* The context for a SMBD response */
struct smbd_response {
struct smbd_connection *info;
struct ib_cqe cqe;
struct ib_sge sge;
enum smbd_message_type type;
/* Link to receive queue or reassembly queue */
struct list_head list;
/* Indicate if this is the 1st packet of a payload */
bool first_segment;
/* SMBD packet header and payload follows this structure */
u8 packet[];
};
/* Create a SMBDirect session */
struct smbd_connection *smbd_get_connection(
struct TCP_Server_Info *server, struct sockaddr *dstaddr);
/* Reconnect SMBDirect session */
int smbd_reconnect(struct TCP_Server_Info *server);
/* Destroy SMBDirect session */
void smbd_destroy(struct smbd_connection *info);
/* Interface for carrying upper layer I/O through send/recv */
int smbd_recv(struct smbd_connection *info, struct msghdr *msg);
int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst);
enum mr_state {
MR_READY,
MR_REGISTERED,
MR_INVALIDATED,
MR_ERROR
};
struct smbd_mr {
struct smbd_connection *conn;
struct list_head list;
enum mr_state state;
struct ib_mr *mr;
struct scatterlist *sgl;
int sgl_count;
enum dma_data_direction dir;
union {
struct ib_reg_wr wr;
struct ib_send_wr inv_wr;
};
struct ib_cqe cqe;
bool need_invalidate;
struct completion invalidate_done;
};
/* Interfaces to register and deregister MR for RDMA read/write */
struct smbd_mr *smbd_register_mr(
struct smbd_connection *info, struct page *pages[], int num_pages,
int tailsz, bool writing, bool need_invalidate);
int smbd_deregister_mr(struct smbd_mr *mr);
#else
#define cifs_rdma_enabled(server) 0
struct smbd_connection {};
static inline void *smbd_get_connection(
struct TCP_Server_Info *server, struct sockaddr *dstaddr) {return NULL;}
static inline int smbd_reconnect(struct TCP_Server_Info *server) {return -1; }
static inline void smbd_destroy(struct smbd_connection *info) {}
static inline int smbd_recv(struct smbd_connection *info, struct msghdr *msg) {return -1; }
static inline int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst) {return -1; }
#endif
#endif
......@@ -37,6 +37,10 @@
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smbdirect.h"
/* Max number of iovectors we can use off the stack when sending requests. */
#define CIFS_MAX_IOV_SIZE 8
void
cifs_wake_up_task(struct mid_q_entry *mid)
......@@ -229,7 +233,10 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
struct socket *ssocket = server->ssocket;
struct msghdr smb_msg;
int val = 1;
if (cifs_rdma_enabled(server) && server->smbd_conn) {
rc = smbd_send(server->smbd_conn, rqst);
goto smbd_done;
}
if (ssocket == NULL)
return -ENOTSOCK;
......@@ -298,7 +305,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
*/
server->tcpStatus = CifsNeedReconnect;
}
smbd_done:
if (rc < 0 && rc != -EINTR)
cifs_dbg(VFS, "Error %d sending data on socket to server\n",
rc);
......@@ -803,12 +810,16 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
const int flags, struct kvec *resp_iov)
{
struct smb_rqst rqst;
struct kvec *new_iov;
struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
int rc;
new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), GFP_KERNEL);
if (!new_iov)
return -ENOMEM;
if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1),
GFP_KERNEL);
if (!new_iov)
return -ENOMEM;
} else
new_iov = s_iov;
/* 1st iov is a RFC1001 length followed by the rest of the packet */
memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
......@@ -823,7 +834,51 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rqst.rq_nvec = n_vec + 1;
rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
kfree(new_iov);
if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
kfree(new_iov);
return rc;
}
/* Like SendReceive2 but iov[0] does not contain an rfc1002 header */
int
smb2_send_recv(const unsigned int xid, struct cifs_ses *ses,
struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
const int flags, struct kvec *resp_iov)
{
struct smb_rqst rqst;
struct kvec s_iov[CIFS_MAX_IOV_SIZE], *new_iov;
int rc;
int i;
__u32 count;
__be32 rfc1002_marker;
if (n_vec + 1 > CIFS_MAX_IOV_SIZE) {
new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1),
GFP_KERNEL);
if (!new_iov)
return -ENOMEM;
} else
new_iov = s_iov;
/* 1st iov is an RFC1002 Session Message length */
memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
count = 0;
for (i = 1; i < n_vec + 1; i++)
count += new_iov[i].iov_len;
rfc1002_marker = cpu_to_be32(count);
new_iov[0].iov_base = &rfc1002_marker;
new_iov[0].iov_len = 4;
memset(&rqst, 0, sizeof(struct smb_rqst));
rqst.rq_iov = new_iov;
rqst.rq_nvec = n_vec + 1;
rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
if (n_vec + 1 > CIFS_MAX_IOV_SIZE)
kfree(new_iov);
return rc;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment