a set of small smb3 fixes, some fixing various crediting issues discovered during xfstest runs, five for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAlxLV8IACgkQiiy9cAdy T1HRIgv/fieDI6HBXAoK9mXzVLJXCZ1IxVZTygC3Xn/bCaxHerS+QSe88w0r1QTZ KLCoT7pBBy06uTowX4/cAF0IYTStsYWngBsH3+HL4EEchkZAVe02wAJ8QOCXs9YU UjoMvNLmcyrzwNt8EduNM2jUUpOL8EHiZOQKUvLt1Vdo3xBtyB3Nkttji92YLOQb Cxs0RJdKNaalMphOQwAtbdbZwlL79KGSA0gMm9W2VD744YKMjQ3uGXaTuoe6+w19 voYKVTSelgyZg51yzF20x1Pl3OV/8L6tWgN1BIcKZbfGBshJhhcD93Pef7bmhxNS Y2yF3SPr/zcdgEkwigVlNs1uBCBBeU04/yQr+YvJwNcjsRTcTKOMuquxq4gXM1P8 7f8gA1u0n1H70YKK29sd3sl7Iu8rHVacwlxjfoAcCjMe0VQvOJtR+V/zwP2uWr8T IjX05unBe/B1v+NXqNdkOpE6ZaiJtt2ny5NDZhfeubOouBLsey7/g/gSx48ICrq+ U20kKsb6 =CCH2 -----END PGP SIGNATURE----- Merge tag '5.0-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb3 fixes from Steve French: "A set of small smb3 fixes, some fixing various crediting issues discovered during xfstest runs, five for stable" * tag '5.0-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: print CIFSMaxBufSize as part of /proc/fs/cifs/DebugData smb3: add credits we receive from oplock/break PDUs CIFS: Fix mounts if the client is low on credits CIFS: Do not assume one credit for async responses CIFS: Fix credit calculations in compound mid callback CIFS: Fix credit calculation for encrypted reads with errors CIFS: Fix credits calculations for reads with errors CIFS: Do not reconnect TCP session in add_credits() smb3: Cleanup license mess CIFS: Fix possible hang during async MTU reads and writes cifs: fix memory leak of an allocated cifs_ntsd structure
This commit is contained in:
commit
7c2614bf7a
|
@ -252,6 +252,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
|||
seq_printf(m, ",ACL");
|
||||
#endif
|
||||
seq_putc(m, '\n');
|
||||
seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize);
|
||||
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
||||
seq_printf(m, "Servers:");
|
||||
|
||||
|
|
|
@ -1549,18 +1549,26 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server)
|
|||
}
|
||||
|
||||
static int
|
||||
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
||||
bool malformed)
|
||||
{
|
||||
int length;
|
||||
struct cifs_readdata *rdata = mid->callback_data;
|
||||
|
||||
length = cifs_discard_remaining_data(server);
|
||||
dequeue_mid(mid, rdata->result);
|
||||
dequeue_mid(mid, malformed);
|
||||
mid->resp_buf = server->smallbuf;
|
||||
server->smallbuf = NULL;
|
||||
return length;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
struct cifs_readdata *rdata = mid->callback_data;
|
||||
|
||||
return __cifs_readv_discard(server, mid, rdata->result);
|
||||
}
|
||||
|
||||
int
|
||||
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
||||
{
|
||||
|
@ -1602,12 +1610,23 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* set up first two iov for signature check and to get credits */
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = 4;
|
||||
rdata->iov[1].iov_base = buf + 4;
|
||||
rdata->iov[1].iov_len = server->total_read - 4;
|
||||
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",
|
||||
rdata->iov[1].iov_base, rdata->iov[1].iov_len);
|
||||
|
||||
/* Was the SMB read successful? */
|
||||
rdata->result = server->ops->map_error(buf, false);
|
||||
if (rdata->result != 0) {
|
||||
cifs_dbg(FYI, "%s: server returned error %d\n",
|
||||
__func__, rdata->result);
|
||||
return cifs_readv_discard(server, mid);
|
||||
/* normal error on read response */
|
||||
return __cifs_readv_discard(server, mid, false);
|
||||
}
|
||||
|
||||
/* Is there enough to get to the rest of the READ_RSP header? */
|
||||
|
@ -1651,14 +1670,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
server->total_read += length;
|
||||
}
|
||||
|
||||
/* set up first iov for signature check */
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = 4;
|
||||
rdata->iov[1].iov_base = buf + 4;
|
||||
rdata->iov[1].iov_len = server->total_read - 4;
|
||||
cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
|
||||
rdata->iov[0].iov_base, server->total_read);
|
||||
|
||||
/* how much data is in the response? */
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
use_rdma_mr = rdata->mr;
|
||||
|
|
|
@ -720,6 +720,21 @@ server_unresponsive(struct TCP_Server_Info *server)
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
zero_credits(struct TCP_Server_Info *server)
|
||||
{
|
||||
int val;
|
||||
|
||||
spin_lock(&server->req_lock);
|
||||
val = server->credits + server->echo_credits + server->oplock_credits;
|
||||
if (server->in_flight == 0 && val == 0) {
|
||||
spin_unlock(&server->req_lock);
|
||||
return true;
|
||||
}
|
||||
spin_unlock(&server->req_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
|
||||
{
|
||||
|
@ -732,6 +747,12 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
|
|||
for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
|
||||
try_to_freeze();
|
||||
|
||||
/* reconnect if no credits and no requests in flight */
|
||||
if (zero_credits(server)) {
|
||||
cifs_reconnect(server);
|
||||
return -ECONNABORTED;
|
||||
}
|
||||
|
||||
if (server_unresponsive(server))
|
||||
return -ECONNABORTED;
|
||||
if (cifs_rdma_enabled(server) && server->smbd_conn)
|
||||
|
|
|
@ -293,6 +293,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
int rc;
|
||||
struct smb2_file_all_info *smb2_data;
|
||||
__u32 create_options = 0;
|
||||
struct cifs_fid fid;
|
||||
bool no_cached_open = tcon->nohandlecache;
|
||||
|
||||
*adjust_tz = false;
|
||||
*symlink = false;
|
||||
|
@ -301,6 +303,21 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
GFP_KERNEL);
|
||||
if (smb2_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If it is a root and its handle is cached then use it */
|
||||
if (!strlen(full_path) && !no_cached_open) {
|
||||
rc = open_shroot(xid, tcon, &fid);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = SMB2_query_info(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid, smb2_data);
|
||||
close_shroot(&tcon->crfid);
|
||||
if (rc)
|
||||
goto out;
|
||||
move_smb2_info_to_cifs(data, smb2_data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (backup_cred(cifs_sb))
|
||||
create_options |= CREATE_OPEN_BACKUP_INTENT;
|
||||
|
||||
|
|
|
@ -648,6 +648,13 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
|||
if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK)
|
||||
return false;
|
||||
|
||||
if (rsp->sync_hdr.CreditRequest) {
|
||||
spin_lock(&server->req_lock);
|
||||
server->credits += le16_to_cpu(rsp->sync_hdr.CreditRequest);
|
||||
spin_unlock(&server->req_lock);
|
||||
wake_up(&server->request_q);
|
||||
}
|
||||
|
||||
if (rsp->StructureSize !=
|
||||
smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
|
||||
if (le16_to_cpu(rsp->StructureSize) == 44)
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "cifs_ioctl.h"
|
||||
#include "smbdirect.h"
|
||||
|
||||
/* Change credits for different ops and return the total number of credits */
|
||||
static int
|
||||
change_conf(struct TCP_Server_Info *server)
|
||||
{
|
||||
|
@ -41,17 +42,15 @@ change_conf(struct TCP_Server_Info *server)
|
|||
server->oplock_credits = server->echo_credits = 0;
|
||||
switch (server->credits) {
|
||||
case 0:
|
||||
return -1;
|
||||
return 0;
|
||||
case 1:
|
||||
server->echoes = false;
|
||||
server->oplocks = false;
|
||||
cifs_dbg(VFS, "disabling echoes and oplocks\n");
|
||||
break;
|
||||
case 2:
|
||||
server->echoes = true;
|
||||
server->oplocks = false;
|
||||
server->echo_credits = 1;
|
||||
cifs_dbg(FYI, "disabling oplocks\n");
|
||||
break;
|
||||
default:
|
||||
server->echoes = true;
|
||||
|
@ -64,14 +63,15 @@ change_conf(struct TCP_Server_Info *server)
|
|||
server->echo_credits = 1;
|
||||
}
|
||||
server->credits -= server->echo_credits + server->oplock_credits;
|
||||
return 0;
|
||||
return server->credits + server->echo_credits + server->oplock_credits;
|
||||
}
|
||||
|
||||
static void
|
||||
smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
|
||||
const int optype)
|
||||
{
|
||||
int *val, rc = 0;
|
||||
int *val, rc = -1;
|
||||
|
||||
spin_lock(&server->req_lock);
|
||||
val = server->ops->get_credits_field(server, optype);
|
||||
|
||||
|
@ -101,8 +101,26 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
|
|||
}
|
||||
spin_unlock(&server->req_lock);
|
||||
wake_up(&server->request_q);
|
||||
if (rc)
|
||||
cifs_reconnect(server);
|
||||
|
||||
if (server->tcpStatus == CifsNeedReconnect)
|
||||
return;
|
||||
|
||||
switch (rc) {
|
||||
case -1:
|
||||
/* change_conf hasn't been executed */
|
||||
break;
|
||||
case 0:
|
||||
cifs_dbg(VFS, "Possible client or server bug - zero credits\n");
|
||||
break;
|
||||
case 1:
|
||||
cifs_dbg(VFS, "disabling echoes and oplocks\n");
|
||||
break;
|
||||
case 2:
|
||||
cifs_dbg(FYI, "disabling oplocks\n");
|
||||
break;
|
||||
default:
|
||||
cifs_dbg(FYI, "add %u credits total=%d\n", add, rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -136,7 +154,11 @@ smb2_get_credits(struct mid_q_entry *mid)
|
|||
{
|
||||
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf;
|
||||
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED
|
||||
|| mid->mid_state == MID_RESPONSE_MALFORMED)
|
||||
return le16_to_cpu(shdr->CreditRequest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -165,14 +187,14 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
|
|||
|
||||
scredits = server->credits;
|
||||
/* can deadlock with reopen */
|
||||
if (scredits == 1) {
|
||||
if (scredits <= 8) {
|
||||
*num = SMB2_MAX_BUFFER_SIZE;
|
||||
*credits = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* leave one credit for a possible reopen */
|
||||
scredits--;
|
||||
/* leave some credits for reopen and other ops */
|
||||
scredits -= 8;
|
||||
*num = min_t(unsigned int, size,
|
||||
scredits * SMB2_MAX_BUFFER_SIZE);
|
||||
|
||||
|
@ -3189,11 +3211,23 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
server->ops->is_status_pending(buf, server, 0))
|
||||
return -1;
|
||||
|
||||
rdata->result = server->ops->map_error(buf, false);
|
||||
/* set up first two iov to get credits */
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = 4;
|
||||
rdata->iov[1].iov_base = buf + 4;
|
||||
rdata->iov[1].iov_len =
|
||||
min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4;
|
||||
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",
|
||||
rdata->iov[1].iov_base, rdata->iov[1].iov_len);
|
||||
|
||||
rdata->result = server->ops->map_error(buf, true);
|
||||
if (rdata->result != 0) {
|
||||
cifs_dbg(FYI, "%s: server returned error %d\n",
|
||||
__func__, rdata->result);
|
||||
dequeue_mid(mid, rdata->result);
|
||||
/* normal error on read response */
|
||||
dequeue_mid(mid, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3266,14 +3300,6 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* set up first iov for signature check */
|
||||
rdata->iov[0].iov_base = buf;
|
||||
rdata->iov[0].iov_len = 4;
|
||||
rdata->iov[1].iov_base = buf + 4;
|
||||
rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
|
||||
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
|
||||
rdata->iov[0].iov_base, server->vals->read_rsp_size);
|
||||
|
||||
length = rdata->copy_into_pages(server, rdata, &iter);
|
||||
|
||||
kfree(bvec);
|
||||
|
|
|
@ -2816,6 +2816,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
int resp_buftype = CIFS_NO_BUFFER;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
bool allocated = false;
|
||||
|
||||
cifs_dbg(FYI, "Query Info\n");
|
||||
|
||||
|
@ -2855,14 +2856,21 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
"Error %d allocating memory for acl\n",
|
||||
rc);
|
||||
*dlen = 0;
|
||||
rc = -ENOMEM;
|
||||
goto qinf_exit;
|
||||
}
|
||||
allocated = true;
|
||||
}
|
||||
}
|
||||
|
||||
rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov, min_len, *data);
|
||||
if (rc && allocated) {
|
||||
kfree(*data);
|
||||
*data = NULL;
|
||||
*dlen = 0;
|
||||
}
|
||||
|
||||
qinf_exit:
|
||||
SMB2_query_info_free(&rqst);
|
||||
|
@ -2916,9 +2924,10 @@ smb2_echo_callback(struct mid_q_entry *mid)
|
|||
{
|
||||
struct TCP_Server_Info *server = mid->callback_data;
|
||||
struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
|
||||
unsigned int credits_received = 1;
|
||||
unsigned int credits_received = 0;
|
||||
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED)
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED
|
||||
|| mid->mid_state == MID_RESPONSE_MALFORMED)
|
||||
credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest);
|
||||
|
||||
DeleteMidQEntry(mid);
|
||||
|
@ -3175,7 +3184,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct smb2_sync_hdr *shdr =
|
||||
(struct smb2_sync_hdr *)rdata->iov[0].iov_base;
|
||||
unsigned int credits_received = 1;
|
||||
unsigned int credits_received = 0;
|
||||
struct smb_rqst rqst = { .rq_iov = rdata->iov,
|
||||
.rq_nvec = 2,
|
||||
.rq_pages = rdata->pages,
|
||||
|
@ -3214,6 +3223,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
|
|||
task_io_account_read(rdata->got_bytes);
|
||||
cifs_stats_bytes_read(tcon, rdata->got_bytes);
|
||||
break;
|
||||
case MID_RESPONSE_MALFORMED:
|
||||
credits_received = le16_to_cpu(shdr->CreditRequest);
|
||||
/* fall through */
|
||||
default:
|
||||
if (rdata->result != -ENODATA)
|
||||
rdata->result = -EIO;
|
||||
|
@ -3399,7 +3411,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
|||
struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
|
||||
unsigned int written;
|
||||
struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
|
||||
unsigned int credits_received = 1;
|
||||
unsigned int credits_received = 0;
|
||||
|
||||
switch (mid->mid_state) {
|
||||
case MID_RESPONSE_RECEIVED:
|
||||
|
@ -3427,6 +3439,9 @@ smb2_writev_callback(struct mid_q_entry *mid)
|
|||
case MID_RETRY_NEEDED:
|
||||
wdata->result = -EAGAIN;
|
||||
break;
|
||||
case MID_RESPONSE_MALFORMED:
|
||||
credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest);
|
||||
/* fall through */
|
||||
default:
|
||||
wdata->result = -EIO;
|
||||
break;
|
||||
|
|
|
@ -3,16 +3,6 @@
|
|||
* Copyright (C) 2018, Microsoft Corporation.
|
||||
*
|
||||
* Author(s): Steve French <stfrench@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.
|
||||
*/
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
|
|
@ -3,16 +3,6 @@
|
|||
* Copyright (C) 2018, Microsoft Corporation.
|
||||
*
|
||||
* Author(s): Steve French <stfrench@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.
|
||||
*/
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM cifs
|
||||
|
|
|
@ -786,17 +786,8 @@ static void
|
|||
cifs_compound_callback(struct mid_q_entry *mid)
|
||||
{
|
||||
struct TCP_Server_Info *server = mid->server;
|
||||
unsigned int optype = mid->optype;
|
||||
unsigned int credits_received = 0;
|
||||
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
if (mid->resp_buf)
|
||||
credits_received = server->ops->get_credits(mid);
|
||||
else
|
||||
cifs_dbg(FYI, "Bad state for cancelled MID\n");
|
||||
}
|
||||
|
||||
add_credits(server, credits_received, optype);
|
||||
add_credits(server, server->ops->get_credits(mid), mid->optype);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue