forked from Minki/linux
5 cifs/smb3 fixes, three for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmMKi7cACgkQiiy9cAdy T1GV7gv/aQR1eQpk1wOnctwFWWaoRLKiiAtq18fg78JfGqjTyJaclxB+c1TV6PKY WPbQq0TqLgAi46QKTtgDNnxexXzIz7pSBZGsM02PVb4hGfeO7GRcG7PVuPSrRCvE nq/p2BT9FyxqyL0pXox6GLSZ86IYYnjmI1HPseE9WqD33hsNIgdwpLNlh1fWzv04 kFU/TZ1hboOky/plnhjkvyR4QyK9oUX44qj8kuwWN838gSruKI/+wVprIIKMuiFg 2bNwFdwQeM/7mWnCEHOdyhO9Upy0WCVQHjqq3+LkE52xgdUxd0my5wQKdO5LiTv3 AZGJ4XGsTc3aaWPZ/zVMMmt9JDFRe84JmQOdk0Ff2MxKTWmQYo+ZznArRUuYf8cc 6jPK1SefQEqqrtA4h/c+osNfAJJmpL3KxbQ4Hpj55cQZzY32iPuLsW2JyQKY+cUG 7j+8Av5wmM8iwJzH/B2DL3TIhY1xhPAsAsd6BXhF+iDzcCG7XgDx8VUTFPhp8QsD W8re2OMz =tss7 -----END PGP SIGNATURE----- Merge tag '6.0-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cfis fixes from Steve French: - two locking fixes (zero range, punch hole) - DFS 9 fix (padding), affecting some servers - three minor cleanup changes * tag '6.0-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: Add helper function to check smb1+ server cifs: Use help macro to get the mid header size cifs: Use help macro to get the header preamble size cifs: skip extra NULL byte in filenames smb3: missing inode locks in punch hole smb3: missing inode locks in zero range
This commit is contained in:
commit
c7bb3fbc1b
@ -32,10 +32,9 @@ 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;
|
||||
|
||||
/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
|
||||
if (is_smb2) {
|
||||
if (!is_smb1(server)) {
|
||||
if (iov[0].iov_len <= 4)
|
||||
return -EIO;
|
||||
i = 0;
|
||||
|
@ -557,6 +557,8 @@ struct smb_version_values {
|
||||
|
||||
#define HEADER_SIZE(server) (server->vals->header_size)
|
||||
#define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
|
||||
#define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size)
|
||||
#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1 - HEADER_PREAMBLE_SIZE(server))
|
||||
|
||||
/**
|
||||
* CIFS superblock mount flags (mnt_cifs_flags) to consider when
|
||||
@ -750,6 +752,11 @@ struct TCP_Server_Info {
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline bool is_smb1(struct TCP_Server_Info *server)
|
||||
{
|
||||
return HEADER_PREAMBLE_SIZE(server) != 0;
|
||||
}
|
||||
|
||||
static inline void cifs_server_lock(struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned int nofs_flag = memalloc_nofs_save();
|
||||
|
@ -871,7 +871,7 @@ smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
|
||||
/*
|
||||
* SMB1 does not use credits.
|
||||
*/
|
||||
if (server->vals->header_preamble_size)
|
||||
if (is_smb1(server))
|
||||
return 0;
|
||||
|
||||
return le16_to_cpu(shdr->CreditRequest);
|
||||
@ -1050,7 +1050,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
|
||||
/* make sure this will fit in a large buffer */
|
||||
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
|
||||
server->vals->header_preamble_size) {
|
||||
HEADER_PREAMBLE_SIZE(server)) {
|
||||
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
|
||||
cifs_reconnect(server, true);
|
||||
return -ECONNABORTED;
|
||||
@ -1065,8 +1065,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
|
||||
/* now read the rest */
|
||||
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
|
||||
pdu_length - HEADER_SIZE(server) + 1
|
||||
+ server->vals->header_preamble_size);
|
||||
pdu_length - MID_HEADER_SIZE(server));
|
||||
|
||||
if (length < 0)
|
||||
return length;
|
||||
@ -1122,7 +1121,7 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
|
||||
/*
|
||||
* SMB1 does not use credits.
|
||||
*/
|
||||
if (server->vals->header_preamble_size)
|
||||
if (is_smb1(server))
|
||||
return;
|
||||
|
||||
if (shdr->CreditRequest) {
|
||||
@ -1180,10 +1179,10 @@ cifs_demultiplex_thread(void *p)
|
||||
if (length < 0)
|
||||
continue;
|
||||
|
||||
if (server->vals->header_preamble_size == 0)
|
||||
server->total_read = 0;
|
||||
else
|
||||
if (is_smb1(server))
|
||||
server->total_read = length;
|
||||
else
|
||||
server->total_read = 0;
|
||||
|
||||
/*
|
||||
* The right amount was read from socket - 4 bytes,
|
||||
@ -1198,8 +1197,7 @@ next_pdu:
|
||||
server->pdu_size = pdu_length;
|
||||
|
||||
/* make sure we have enough to get to the MID */
|
||||
if (server->pdu_size < HEADER_SIZE(server) - 1 -
|
||||
server->vals->header_preamble_size) {
|
||||
if (server->pdu_size < MID_HEADER_SIZE(server)) {
|
||||
cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
|
||||
server->pdu_size);
|
||||
cifs_reconnect(server, true);
|
||||
@ -1208,9 +1206,8 @@ next_pdu:
|
||||
|
||||
/* read down to the MID */
|
||||
length = cifs_read_from_socket(server,
|
||||
buf + server->vals->header_preamble_size,
|
||||
HEADER_SIZE(server) - 1
|
||||
- server->vals->header_preamble_size);
|
||||
buf + HEADER_PREAMBLE_SIZE(server),
|
||||
MID_HEADER_SIZE(server));
|
||||
if (length < 0)
|
||||
continue;
|
||||
server->total_read += length;
|
||||
|
@ -3307,26 +3307,43 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
|
||||
return pntsd;
|
||||
}
|
||||
|
||||
static long smb3_zero_data(struct file *file, struct cifs_tcon *tcon,
|
||||
loff_t offset, loff_t len, unsigned int xid)
|
||||
{
|
||||
struct cifsFileInfo *cfile = file->private_data;
|
||||
struct file_zero_data_information fsctl_buf;
|
||||
|
||||
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
|
||||
|
||||
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
||||
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
||||
|
||||
return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
|
||||
(char *)&fsctl_buf,
|
||||
sizeof(struct file_zero_data_information),
|
||||
0, NULL, NULL);
|
||||
}
|
||||
|
||||
static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
loff_t offset, loff_t len, bool keep_size)
|
||||
{
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct inode *inode;
|
||||
struct cifsInodeInfo *cifsi;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(inode);
|
||||
struct cifsFileInfo *cfile = file->private_data;
|
||||
struct file_zero_data_information fsctl_buf;
|
||||
long rc;
|
||||
unsigned int xid;
|
||||
__le64 eof;
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
inode = d_inode(cfile->dentry);
|
||||
cifsi = CIFS_I(inode);
|
||||
|
||||
trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
|
||||
ses->Suid, offset, len);
|
||||
|
||||
inode_lock(inode);
|
||||
filemap_invalidate_lock(inode->i_mapping);
|
||||
|
||||
/*
|
||||
* We zero the range through ioctl, so we need remove the page caches
|
||||
* first, otherwise the data may be inconsistent with the server.
|
||||
@ -3334,26 +3351,12 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
truncate_pagecache_range(inode, offset, offset + len - 1);
|
||||
|
||||
/* if file not oplocked can't be sure whether asking to extend size */
|
||||
if (!CIFS_CACHE_READ(cifsi))
|
||||
if (keep_size == false) {
|
||||
rc = -EOPNOTSUPP;
|
||||
trace_smb3_zero_err(xid, cfile->fid.persistent_fid,
|
||||
tcon->tid, ses->Suid, offset, len, rc);
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
rc = -EOPNOTSUPP;
|
||||
if (keep_size == false && !CIFS_CACHE_READ(cifsi))
|
||||
goto zero_range_exit;
|
||||
|
||||
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
|
||||
|
||||
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
||||
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
||||
|
||||
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
|
||||
(char *)&fsctl_buf,
|
||||
sizeof(struct file_zero_data_information),
|
||||
0, NULL, NULL);
|
||||
if (rc)
|
||||
rc = smb3_zero_data(file, tcon, offset, len, xid);
|
||||
if (rc < 0)
|
||||
goto zero_range_exit;
|
||||
|
||||
/*
|
||||
@ -3366,6 +3369,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
}
|
||||
|
||||
zero_range_exit:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
inode_unlock(inode);
|
||||
free_xid(xid);
|
||||
if (rc)
|
||||
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
|
||||
@ -3379,7 +3384,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||
loff_t offset, loff_t len)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct cifsFileInfo *cfile = file->private_data;
|
||||
struct file_zero_data_information fsctl_buf;
|
||||
long rc;
|
||||
@ -3388,14 +3393,12 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
inode = d_inode(cfile->dentry);
|
||||
|
||||
inode_lock(inode);
|
||||
/* Need to make file sparse, if not already, before freeing range. */
|
||||
/* Consider adding equivalent for compressed since it could also work */
|
||||
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
filemap_invalidate_lock(inode->i_mapping);
|
||||
@ -3415,8 +3418,10 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||
(char *)&fsctl_buf,
|
||||
sizeof(struct file_zero_data_information),
|
||||
CIFSMaxBufSize, NULL, NULL);
|
||||
free_xid(xid);
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2572,19 +2572,15 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
|
||||
|
||||
path_len = UniStrnlen((wchar_t *)path, PATH_MAX);
|
||||
|
||||
/*
|
||||
* make room for one path separator between the treename and
|
||||
* path
|
||||
*/
|
||||
*out_len = treename_len + 1 + path_len;
|
||||
/* make room for one path separator only if @path isn't empty */
|
||||
*out_len = treename_len + (path[0] ? 1 : 0) + path_len;
|
||||
|
||||
/*
|
||||
* final path needs to be null-terminated UTF16 with a
|
||||
* size aligned to 8
|
||||
* final path needs to be 8-byte aligned as specified in
|
||||
* MS-SMB2 2.2.13 SMB2 CREATE Request.
|
||||
*/
|
||||
|
||||
*out_size = roundup((*out_len+1)*2, 8);
|
||||
*out_path = kzalloc(*out_size, GFP_KERNEL);
|
||||
*out_size = roundup(*out_len * sizeof(__le16), 8);
|
||||
*out_path = kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL);
|
||||
if (!*out_path)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -261,8 +261,8 @@ smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
|
||||
int nvec;
|
||||
unsigned long buflen = 0;
|
||||
|
||||
if (server->vals->header_preamble_size == 0 &&
|
||||
rqst->rq_nvec >= 2 && rqst->rq_iov[0].iov_len == 4) {
|
||||
if (!is_smb1(server) && rqst->rq_nvec >= 2 &&
|
||||
rqst->rq_iov[0].iov_len == 4) {
|
||||
iov = &rqst->rq_iov[1];
|
||||
nvec = rqst->rq_nvec - 1;
|
||||
} else {
|
||||
@ -346,7 +346,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
||||
|
||||
/* Generate a rfc1002 marker for SMB2+ */
|
||||
if (server->vals->header_preamble_size == 0) {
|
||||
if (!is_smb1(server)) {
|
||||
struct kvec hiov = {
|
||||
.iov_base = &rfc1002_marker,
|
||||
.iov_len = 4
|
||||
@ -1238,7 +1238,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
buf = (char *)midQ[i]->resp_buf;
|
||||
resp_iov[i].iov_base = buf;
|
||||
resp_iov[i].iov_len = midQ[i]->resp_buf_size +
|
||||
server->vals->header_preamble_size;
|
||||
HEADER_PREAMBLE_SIZE(server);
|
||||
|
||||
if (midQ[i]->large_buf)
|
||||
resp_buf_type[i] = CIFS_LARGE_BUFFER;
|
||||
@ -1643,7 +1643,7 @@ int
|
||||
cifs_discard_remaining_data(struct TCP_Server_Info *server)
|
||||
{
|
||||
unsigned int rfclen = server->pdu_size;
|
||||
int remaining = rfclen + server->vals->header_preamble_size -
|
||||
int remaining = rfclen + HEADER_PREAMBLE_SIZE(server) -
|
||||
server->total_read;
|
||||
|
||||
while (remaining > 0) {
|
||||
@ -1689,8 +1689,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
unsigned int data_offset, data_len;
|
||||
struct cifs_readdata *rdata = mid->callback_data;
|
||||
char *buf = server->smallbuf;
|
||||
unsigned int buflen = server->pdu_size +
|
||||
server->vals->header_preamble_size;
|
||||
unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
|
||||
bool use_rdma_mr = false;
|
||||
|
||||
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
|
||||
@ -1724,10 +1723,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
|
||||
/* set up first two iov for signature check and to get credits */
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = server->vals->header_preamble_size;
|
||||
rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
|
||||
rdata->iov[0].iov_len = HEADER_PREAMBLE_SIZE(server);
|
||||
rdata->iov[1].iov_base = buf + HEADER_PREAMBLE_SIZE(server);
|
||||
rdata->iov[1].iov_len =
|
||||
server->total_read - server->vals->header_preamble_size;
|
||||
server->total_read - HEADER_PREAMBLE_SIZE(server);
|
||||
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
|
||||
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
|
||||
cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
|
||||
@ -1752,7 +1751,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
}
|
||||
|
||||
data_offset = server->ops->read_data_offset(buf) +
|
||||
server->vals->header_preamble_size;
|
||||
HEADER_PREAMBLE_SIZE(server);
|
||||
if (data_offset < server->total_read) {
|
||||
/*
|
||||
* win2k8 sometimes sends an offset of 0 when the read
|
||||
|
Loading…
Reference in New Issue
Block a user