Commit 9ffc59d5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '4.18-rc1-more-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Misc SMB3 fixes, including particularly important ones for signing,
  some minor documentation and debug improvements and another posix
  smb3.11 fix"

* tag '4.18-rc1-more-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Fix invalid check in __cifs_calc_signature()
  cifs: Use correct packet length in SMB2_TRANSFORM header
  smb3: fix corrupt path in subdirs on smb311 with posix
  smb3: do not display empty interface list
  smb3: Fix mode on mkdir on smb311 mounts
  cifs: Fix kernel oops when traceSMB is enabled
  CIFS: dump every session iface info
  CIFS: parse and store info on iface queries
  CIFS: add iface info to struct cifs_ses
  CIFS: complete PDU definitions for interface queries
  CIFS: move default port definitions to cifsglob.h
  cifs: Fix encryption/signing
  cifs: update __smb_send_rqst() to take an array of requests
  cifs: remove smb2_send_recv()
  cifs: push rfc1002 generation down the stack
  smb3: increase initial number of credits requested to allow write
  cifs: minor documentation updates
  cifs: add lease tracking to the cached root fid
  smb3: note that smb3.11 posix extensions mount option is experimental
parents a5696313 83ffdead
......@@ -42,9 +42,11 @@ Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
Scott Lovenberg
Pavel Shilovsky (for great work adding SMB2 support, and various SMB3 features)
Aurelien Aptel (for DFS SMB3 work and some key bug fixes)
Ronnie Sahlberg (for SMB3 xattr work and bug fixes)
Ronnie Sahlberg (for SMB3 xattr work, bug fixes, and lots of great work on compounding)
Shirish Pargaonkar (for many ACL patches over the years)
Sachin Prabhu (many bug fixes, including for reconnect, copy offload and security)
Paulo Alcantara
Long Li (some great work on RDMA, SMB Direct)
Test case and Bug Report contributors
......@@ -58,5 +60,4 @@ mention to the Stanford Checker (SWAT) which pointed out many minor
bugs in error paths. Valuable suggestions also have come from Al Viro
and Dave Miller.
And thanks to the IBM LTC and Power test teams and SuSE testers for
finding multiple bugs during excellent stress test runs.
And thanks to the IBM LTC and Power test teams and SuSE and Citrix and RedHat testers for finding multiple bugs during excellent stress test runs.
See https://wiki.samba.org/index.php/LinuxCIFSKernel for
more current information.
Version 1.62
------------
Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened
......
......@@ -9,14 +9,14 @@ is a partial list of the known problems and missing features:
a) SMB3 (and SMB3.02) missing optional features:
- multichannel (started), integration with RDMA
- directory leases (improved metadata caching)
- T10 copy offload (copy chunk, and "Duplicate Extents" ioctl
- directory leases (improved metadata caching), started (root dir only)
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
currently the only two server side copy mechanisms supported)
b) improved sparse file support
c) Directory entry caching relies on a 1 second timer, rather than
using Directory Leases
using Directory Leases, currently only the root file handle is cached longer
d) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems)
......@@ -42,6 +42,8 @@ mount or a per server basis to client UIDs or nobody if no mapping
exists. Also better integration with winbind for resolving SID owners
k) Add tools to take advantage of more smb3 specific ioctls and features
(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server
is in progress)
l) encrypted file support
......@@ -71,9 +73,8 @@ t) split cifs and smb3 support into separate modules so legacy (and less
secure) CIFS dialect can be disabled in environments that don't need it
and simplify the code.
u) Finish up SMB3.1.1 dialect support
v) POSIX Extensions for SMB3.1.1
v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
so far).
KNOWN BUGS
====================================
......@@ -92,8 +93,8 @@ Misc testing to do
1) check out max path names and max path name components against various server
types. Try nested symlinks (8 deep). Return max path name in stat -f information
2) Improve xfstest's cifs enablement and adapt xfstests where needed to test
cifs better
2) Improve xfstest's cifs/smb3 enablement and adapt xfstests where needed to test
cifs/smb3 better
3) Additional performance testing and optimization using iozone and similar -
there are some easy changes that can be done to parallelize sequential writes,
......
......@@ -126,6 +126,25 @@ static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon)
seq_putc(m, '\n');
}
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, "\t\tSpeed: %zu bps\n", iface->speed);
seq_puts(m, "\t\tCapabilities: ");
if (iface->rdma_capable)
seq_puts(m, "rdma ");
if (iface->rss_capable)
seq_puts(m, "rss ");
seq_putc(m, '\n');
if (iface->sockaddr.ss_family == AF_INET)
seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
else if (iface->sockaddr.ss_family == AF_INET6)
seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
}
static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{
struct list_head *tmp1, *tmp2, *tmp3;
......@@ -312,6 +331,16 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
mid_entry->mid);
}
spin_unlock(&GlobalMid_Lock);
spin_lock(&ses->iface_lock);
if (ses->iface_count)
seq_printf(m, "\n\tServer interfaces: %zu\n",
ses->iface_count);
for (j = 0; j < ses->iface_count; j++) {
seq_printf(m, "\t%d)\n", j);
cifs_dump_iface(m, &ses->iface_list[j]);
}
spin_unlock(&ses->iface_lock);
}
}
spin_unlock(&cifs_tcp_ses_lock);
......
......@@ -37,7 +37,6 @@
#include <crypto/aead.h>
int __cifs_calc_signature(struct smb_rqst *rqst,
int start,
struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash)
{
......@@ -45,16 +44,27 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
int rc;
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;
int is_smb2 = server->vals->header_preamble_size == 0;
for (i = start; i < n_vec; i++) {
/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
if (is_smb2) {
if (iov[0].iov_len <= 4)
return -EIO;
i = 0;
} else {
if (n_vec < 2 || iov[0].iov_len != 4)
return -EIO;
i = 1; /* skip rfc1002 length */
}
for (; i < n_vec; i++) {
if (iov[i].iov_len == 0)
continue;
if (iov[i].iov_base == NULL) {
cifs_dbg(VFS, "null iovec entry\n");
return -EIO;
}
if (i == 1 && iov[1].iov_len <= 4)
break; /* nothing to sign or corrupt header */
rc = crypto_shash_update(shash,
iov[i].iov_base, iov[i].iov_len);
if (rc) {
......@@ -118,7 +128,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
return rc;
}
return __cifs_calc_signature(rqst, 1, server, signature,
return __cifs_calc_signature(rqst, server, signature,
&server->secmech.sdescmd5->shash);
}
......
......@@ -33,6 +33,9 @@
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
#define CIFS_PORT 445
#define RFC1001_PORT 139
/*
* The sizes of various internal tables and strings
*/
......@@ -312,6 +315,10 @@ struct smb_version_operations {
/* send echo request */
int (*echo)(struct TCP_Server_Info *);
/* create directory */
int (*posix_mkdir)(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb);
int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
struct cifs_sb_info *);
/* set info on created directory */
......@@ -838,6 +845,13 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
#endif
struct cifs_server_iface {
size_t speed;
unsigned int rdma_capable : 1;
unsigned int rss_capable : 1;
struct sockaddr_storage sockaddr;
};
/*
* Session structure. One of these for each uid session with a particular host
*/
......@@ -875,6 +889,20 @@ struct cifs_ses {
#ifdef CONFIG_CIFS_SMB311
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
#endif /* 3.1.1 */
/*
* Network interfaces available on the server this session is
* connected to.
*
* Other channels can be opened by connecting and binding this
* session to interfaces from this list.
*
* iface_lock should be taken when accessing any of these fields
*/
spinlock_t iface_lock;
struct cifs_server_iface *iface_list;
size_t iface_count;
unsigned long iface_last_update; /* jiffies */
};
static inline bool
......@@ -883,6 +911,14 @@ cap_unix(struct cifs_ses *ses)
return ses->server->vals->cap_unix & ses->capabilities;
}
struct cached_fid {
bool is_valid:1; /* Do we have a useable root fid */
struct cifs_fid *fid;
struct mutex fid_mutex;
struct cifs_tcon *tcon;
struct work_struct lease_break;
};
/*
* there is one of these for each connection to a resource on a particular
* session
......@@ -987,9 +1023,7 @@ struct cifs_tcon {
struct fscache_cookie *fscache; /* cookie for share */
#endif
struct list_head pending_opens; /* list of incomplete opens */
bool valid_root_fid:1; /* Do we have a useable root fid */
struct mutex prfid_mutex; /* prevents reopen race after dead ses*/
struct cifs_fid *prfid; /* handle to the directory at top of share */
struct cached_fid crfid; /* Cached root fid */
/* BB add field for back pointer to sb struct(s)? */
};
......
......@@ -112,10 +112,6 @@ 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 ,
......@@ -544,7 +540,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
unsigned int *pbytes_written);
int __cifs_calc_signature(struct smb_rqst *rqst, int start,
int __cifs_calc_signature(struct smb_rqst *rqst,
struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash);
enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
......@@ -552,6 +548,7 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
void cifs_aio_ctx_release(struct kref *refcount);
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
void smb2_cached_lease_break(struct work_struct *work);
int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
struct sdesc **sdesc);
......
......@@ -107,10 +107,10 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
}
spin_unlock(&tcon->open_file_lock);
mutex_lock(&tcon->prfid_mutex);
tcon->valid_root_fid = false;
memset(tcon->prfid, 0, sizeof(struct cifs_fid));
mutex_unlock(&tcon->prfid_mutex);
mutex_lock(&tcon->crfid.fid_mutex);
tcon->crfid.is_valid = false;
memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
mutex_unlock(&tcon->crfid.fid_mutex);
/*
* BB Add call to invalidate_inodes(sb) for all superblocks mounted
......
......@@ -57,9 +57,6 @@
#include "smb2proto.h"
#include "smbdirect.h"
#define CIFS_PORT 445
#define RFC1001_PORT 139
extern mempool_t *cifs_req_poolp;
extern bool disable_legacy_dialects;
......@@ -3029,8 +3026,11 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
#ifdef CONFIG_CIFS_SMB311
if ((volume_info->linux_ext) && (ses->server->posix_ext_supported)) {
if (ses->server->vals->protocol_id == SMB311_PROT_ID)
if (ses->server->vals->protocol_id == SMB311_PROT_ID) {
tcon->posix_extensions = true;
printk_once(KERN_WARNING
"SMB3.11 POSIX Extensions are experimental\n");
}
}
#endif /* 311 */
......
......@@ -1575,6 +1575,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}
server = tcon->ses->server;
#ifdef CONFIG_CIFS_SMB311
if ((server->ops->posix_mkdir) && (tcon->posix_extensions)) {
rc = server->ops->posix_mkdir(xid, inode, mode, tcon, full_path,
cifs_sb);
d_drop(direntry); /* for time being always refresh inode info */
goto mkdir_out;
}
#endif /* SMB311 */
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
......@@ -1583,8 +1594,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}
server = tcon->ses->server;
if (!server->ops->mkdir) {
rc = -ENOSYS;
goto mkdir_out;
......
......@@ -82,6 +82,7 @@ sesInfoAlloc(void)
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
INIT_LIST_HEAD(&ret_buf->tcon_list);
mutex_init(&ret_buf->session_mutex);
spin_lock_init(&ret_buf->iface_lock);
}
return ret_buf;
}
......@@ -102,6 +103,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
kfree(buf_to_free->user_name);
kfree(buf_to_free->domainName);
kzfree(buf_to_free->auth_key.response);
kfree(buf_to_free->iface_list);
kzfree(buf_to_free);
}
......@@ -117,8 +119,9 @@ tconInfoAlloc(void)
INIT_LIST_HEAD(&ret_buf->openFileList);
INIT_LIST_HEAD(&ret_buf->tcon_list);
spin_lock_init(&ret_buf->open_file_lock);
mutex_init(&ret_buf->prfid_mutex);
ret_buf->prfid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL);
mutex_init(&ret_buf->crfid.fid_mutex);
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
GFP_KERNEL);
#ifdef CONFIG_CIFS_STATS
spin_lock_init(&ret_buf->stat_lock);
#endif
......@@ -136,7 +139,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
atomic_dec(&tconInfoAllocCount);
kfree(buf_to_free->nativeFileSystem);
kzfree(buf_to_free->password);
kfree(buf_to_free->prfid);
kfree(buf_to_free->crfid.fid);
kfree(buf_to_free);
}
......
......@@ -454,7 +454,8 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
#ifdef CONFIG_CIFS_SMB311
/* SMB311 POSIX extensions paths do not include leading slash */
else if (cifs_sb_master_tlink(cifs_sb) &&
cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
cifs_sb_master_tcon(cifs_sb)->posix_extensions &&
(from[0] == '/')) {
start_of_path = from + 1;
}
#endif /* 311 */
......@@ -492,10 +493,11 @@ cifs_ses_oplock_break(struct work_struct *work)
{
struct smb2_lease_break_work *lw = container_of(work,
struct smb2_lease_break_work, lease_break);
int rc;
int rc = 0;
rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
lw->lease_state);
cifs_dbg(FYI, "Lease release rc %d\n", rc);
cifs_put_tlink(lw->tlink);
kfree(lw);
......@@ -561,6 +563,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
open->oplock = lease_state;
}
return found;
}
......@@ -603,6 +606,18 @@ smb2_is_valid_lease_break(char *buffer)
return true;
}
spin_unlock(&tcon->open_file_lock);
if (tcon->crfid.is_valid &&
!memcmp(rsp->LeaseKey,
tcon->crfid.fid->lease_key,
SMB2_LEASE_KEY_SIZE)) {
INIT_WORK(&tcon->crfid.lease_break,
smb2_cached_lease_break);
queue_work(cifsiod_wq,
&tcon->crfid.lease_break);
spin_unlock(&cifs_tcp_ses_lock);
return true;
}
}
}
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -851,8 +851,11 @@ struct validate_negotiate_info_rsp {
__le16 Dialect; /* Dialect in use for the connection */
} __packed;
#define RSS_CAPABLE 0x00000001
#define RDMA_CAPABLE 0x00000002
#define RSS_CAPABLE cpu_to_le32(0x00000001)
#define RDMA_CAPABLE cpu_to_le32(0x00000002)
#define INTERNETWORK cpu_to_le16(0x0002)
#define INTERNETWORKV6 cpu_to_le16(0x0017)
struct network_interface_info_ioctl_rsp {
__le32 Next; /* next interface. zero if this is last one */
......@@ -860,7 +863,21 @@ struct network_interface_info_ioctl_rsp {
__le32 Capability; /* RSS or RDMA Capable */
__le32 Reserved;
__le64 LinkSpeed;
char SockAddr_Storage[128];
__le16 Family;
__u8 Buffer[126];
} __packed;
struct iface_info_ipv4 {
__be16 Port;
__be32 IPv4Address;
__be64 Reserved;
} __packed;
struct iface_info_ipv6 {
__be16 Port;
__be32 FlowInfo;
__u8 IPv6Address[16];
__be32 ScopeId;
} __packed;
#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
......
......@@ -79,6 +79,10 @@ extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, bool set_alloc);
extern int smb2_set_file_info(struct inode *inode, const char *full_path,
FILE_BASIC_INFO *buf, const unsigned int xid);
extern int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
umode_t mode, struct cifs_tcon *tcon,
const char *full_path,
struct cifs_sb_info *cifs_sb);
extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
......@@ -109,6 +113,8 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work);
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
extern unsigned long
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker);
/*
* SMB2 Worker functions - most of protocol specific implementation details
......
......@@ -171,9 +171,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
unsigned char *sigptr = smb2_signature;
struct kvec *iov = rqst->rq_iov;
int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base;
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct cifs_ses *ses;
ses = smb2_find_smb_ses(server, shdr->SessionId);
......@@ -204,7 +202,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
return rc;
}
rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr,
rc = __cifs_calc_signature(rqst, server, sigptr,
&server->secmech.sdeschmacsha256->shash);
if (!rc)
......@@ -414,9 +412,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
unsigned char smb3_signature[SMB2_CMACAES_SIZE];
unsigned char *sigptr = smb3_signature;
struct kvec *iov = rqst->rq_iov;
int iov_hdr_index = rqst->rq_nvec > 1 ? 1 : 0;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)iov[iov_hdr_index].iov_base;
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base;
struct cifs_ses *ses;
ses = smb2_find_smb_ses(server, shdr->SessionId);
......@@ -447,7 +443,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
return rc;
}
rc = __cifs_calc_signature(rqst, iov_hdr_index, server, sigptr,
rc = __cifs_calc_signature(rqst, server, sigptr,
&server->secmech.sdesccmacaes->shash);
if (!rc)
......@@ -462,7 +458,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
{
int rc = 0;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
server->tcpStatus == CifsNeedNegotiate)
......@@ -635,7 +631,7 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
{
int rc;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
struct mid_q_entry *mid;
smb2_seq_num_into_buf(ses->server, shdr);
......@@ -656,7 +652,7 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
{
int rc;
struct smb2_sync_hdr *shdr =
(struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
(struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
struct mid_q_entry *mid;
smb2_seq_num_into_buf(server, shdr);
......
......@@ -18,6 +18,7 @@
#include "smbdirect.h"
#include "cifs_debug.h"
#include "cifsproto.h"
#include "smb2proto.h"
static struct smbd_response *get_empty_queue_buffer(
struct smbd_connection *info);
......@@ -2087,7 +2088,7 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
struct kvec vec;
int nvecs;
int size;
unsigned int buflen = 0, remaining_data_length;
unsigned int buflen, remaining_data_length;
int start, i, j;
int max_iov_size =
info->max_send_size - sizeof(struct smbd_data_transfer);
......@@ -2111,25 +2112,13 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
log_write(ERR, "expected the pdu length in 1st iov, but got %zu\n", rqst->rq_iov[0].iov_len);
return -EINVAL;
}
iov = &rqst->rq_iov[1];
/* total up iov array first */
for (i = 0; i < rqst->rq_nvec-1; i++) {
buflen += iov[i].iov_len;
}
/*
* Add in the page array if there is one. The caller needs to set
* rq_tailsz to PAGE_SIZE when the buffer has multiple pages and
* ends at page boundary
*/
if (rqst->rq_npages) {
if (rqst->rq_npages == 1)
buflen += rqst->rq_tailsz;
else
buflen += rqst->rq_pagesz * (rqst->rq_npages - 1) -
rqst->rq_offset + rqst->rq_tailsz;
}
buflen = smb2_rqst_len(rqst, true);
if (buflen + sizeof(struct smbd_data_transfer) >
info->max_fragmented_send_size) {
......@@ -2139,6 +2128,8 @@ int smbd_send(struct smbd_connection *info, struct smb_rqst *rqst)
goto done;
}
iov = &rqst->rq_iov[1];
cifs_dbg(FYI, "Sending smb (RDMA): smb_len=%u\n", buflen);
for (i = 0; i < rqst->rq_nvec-1; i++)
dump_smb(iov[i].iov_base, iov[i].iov_len);
......
......@@ -378,7 +378,7 @@ DEFINE_EVENT(smb3_open_err_class, smb3_##name, \
TP_ARGS(xid, tid, sesid, create_options, desired_access, rc))
DEFINE_SMB3_OPEN_ERR_EVENT(open_err);
DEFINE_SMB3_OPEN_ERR_EVENT(posix_mkdir_err);
DECLARE_EVENT_CLASS(smb3_open_done_class,
TP_PROTO(unsigned int xid,
......@@ -420,6 +420,7 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \
TP_ARGS(xid, fid, tid, sesid, create_options, desired_access))
DEFINE_SMB3_OPEN_DONE_EVENT(open_done);
DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done);
#endif /* _CIFS_TRACE_H */
......
......@@ -201,15 +201,24 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
return 0;
}
static unsigned long
rqst_len(struct smb_rqst *rqst)
unsigned long
smb2_rqst_len(struct smb_rqst *rqst, bool skip_rfc1002_marker)
{
unsigned int i;
struct kvec *iov = rqst->rq_iov;
struct kvec *iov;
int nvec;
unsigned long buflen = 0;
if (skip_rfc1002_marker && rqst->rq_iov[0].iov_len == 4) {
iov = &rqst->rq_iov[1];
nvec = rqst->rq_nvec - 1;
} else {
iov = rqst->rq_iov;
nvec = rqst->rq_nvec;
}
/* total up iov array first */
for (i = 0; i < rqst->rq_nvec; i++)
for (i = 0; i < nvec; i++)
buflen += iov[i].iov_len;
/*
......@@ -236,18 +245,20 @@ rqst_len(struct smb_rqst *rqst)
}
static int
__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst)
{
int rc;
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;
unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
unsigned long send_length;
unsigned int i;
int rc = 0;
struct kvec *iov;
int n_vec;
unsigned int send_length = 0;
unsigned int i, j;
size_t total_len = 0, sent, size;
struct socket *ssocket = server->ssocket;
struct msghdr smb_msg;
int val = 1;
__be32 rfc1002_marker;
if (cifs_rdma_enabled(server) && server->smbd_conn) {
rc = smbd_send(server->smbd_conn, rqst);
goto smbd_done;
......@@ -255,51 +266,67 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
if (ssocket == NULL)
return -ENOTSOCK;
/* sanity check send length */
send_length = rqst_len(rqst);
if (send_length != smb_buf_length + 4) {
WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
send_length, smb_buf_length);
return -EIO;
}
if (n_vec < 2)
return -EIO;
cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
dump_smb(iov[0].iov_base, iov[0].iov_len);
dump_smb(iov[1].iov_base, iov[1].iov_len);
/* cork the socket */
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
(char *)&val, sizeof(val));
size = 0;
for (i = 0; i < n_vec; i++)
size += iov[i].iov_len;
for (j = 0; j < num_rqst; j++)
send_length += smb2_rqst_len(&rqst[j], true);
rfc1002_marker = cpu_to_be32(send_length);
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size);
/* Generate a rfc1002 marker for SMB2+ */
if (server->vals->header_preamble_size == 0) {
struct kvec hiov = {
.iov_base = &rfc1002_marker,
.iov_len = 4
};
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, &hiov,
1, 4);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
goto uncork;
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
goto uncork;
total_len += sent;
send_length += 4;
}
total_len += sent;
cifs_dbg(FYI, "Sending smb: smb_len=%u\n", send_length);
/* now walk the page array and send each page in it */
for (i = 0; i < rqst->rq_npages; i++) {
struct bio_vec bvec;
for (j = 0; j < num_rqst; j++) {
iov = rqst[j].rq_iov;
n_vec = rqst[j].rq_nvec;
bvec.bv_page = rqst->rq_pages[i];
rqst_page_get_length(rqst, i, &bvec.bv_len, &bvec.bv_offset);
size = 0;
for (i = 0; i < n_vec; i++) {
dump_smb(iov[i].iov_base, iov[i].iov_len);
size += iov[i].iov_len;
}
iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC,
iov, n_vec, size);
iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
&bvec, 1, bvec.bv_len);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
break;
goto uncork;
total_len += sent;
/* now walk the page array and send each page in it */
for (i = 0; i < rqst[j].rq_npages; i++) {
struct bio_vec bvec;
bvec.bv_page = rqst[j].rq_pages[i];
rqst_page_get_length(&rqst[j], i, &bvec.bv_len,
&bvec.bv_offset);
iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC,
&bvec, 1, bvec.bv_len);
rc = smb_send_kvec(server, &smb_msg, &sent);
if (rc < 0)
break;
total_len += sent;
}
}
uncork:
......@@ -308,9 +335,9 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
(char *)&val, sizeof(val));
if ((total_len > 0) && (total_len != smb_buf_length + 4)) {
if ((total_len > 0) && (total_len != send_length)) {
cifs_dbg(FYI, "partial send (wanted=%u sent=%zu): terminating session\n",
smb_buf_length + 4, total_len);
send_length, total_len);
/*
* If we have only sent part of an SMB then the next SMB could
* be taken as the remainder of this one. We need to kill the
......@@ -335,7 +362,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
int rc;
if (!(flags & CIFS_TRANSFORM_REQ))
return __smb_send_rqst(server, rqst);
return __smb_send_rqst(server, 1, rqst);
if (!server->ops->init_transform_rq ||
!server->ops->free_transform_rq) {
......@@ -347,7 +374,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
if (rc)
return rc;
rc = __smb_send_rqst(server, &cur_rqst);
rc = __smb_send_rqst(server, 1, &cur_rqst);
server->ops->free_transform_rq(&cur_rqst);
return rc;
}
......@@ -365,7 +392,7 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
iov[1].iov_base = (char *)smb_buffer + 4;
iov[1].iov_len = smb_buf_length;
return __smb_send_rqst(server, &rqst);
return __smb_send_rqst(server, 1, &rqst);
}
static int
......@@ -730,7 +757,6 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
* to the same server. We may make this configurable later or
* use ses->maxReq.
*/
rc = wait_for_free_request(ses->server, timeout, optype);
if (rc)
return rc;
......@@ -766,8 +792,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
#ifdef CONFIG_CIFS_SMB311
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP))
smb311_update_preauth_hash(ses, rqst->rq_iov+1,
rqst->rq_nvec-1);
smb311_update_preauth_hash(ses, rqst->rq_iov,
rqst->rq_nvec);
#endif
if (timeout == CIFS_ASYNC_OP)
......@@ -812,8 +838,8 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
#ifdef CONFIG_CIFS_SMB311
if ((ses->status == CifsNew) || (optype & CIFS_NEG_OP)) {
struct kvec iov = {
.iov_base = buf,
.iov_len = midQ->resp_buf_size
.iov_base = resp_iov->iov_base,
.iov_len = resp_iov->iov_len
};
smb311_update_preauth_hash(ses, &iov, 1);
}
......@@ -872,49 +898,6 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
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_array(n_vec + 1, sizeof(struct kvec),
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;
}
int
SendReceive(const unsigned int xid, struct cifs_ses *ses,
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
......
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