five smb3 client fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmbbVKkACgkQiiy9cAdy
 T1FTUgv8C/Qek0abESCC9AEvKUiAGwabOcdvKQnpCjI3eLQVmwGIHXXPdnkgxJmL
 gUQm4CBj6jWw5OfhBw2BTvnVz9YahQC8Xbg0XfLomaggD8NxVFnQyiWyyjPJtIiQ
 JRhOqV82Ko2NFMpouwfNTLPLMBpjNp6IrvkAY2bH5vUzPmoC/aU+eQMVXMqTFalD
 Q+vV2cFBcMsTTsRFCMG0er8114A1XvyG4IKr/95bTDjn/wnOVX9sUGrMbNXuoCsj
 yzMAkBoc60k2PjGoYMIQJsVDFryz7TpF7wyS2Oo5EkqzR/GKcIYGxTn0AznVhs83
 5mAPXgyqpxg3wAsIVAs+vj0Jo2/cfpWuLb9pR5kt3lNA5EH7D1DNzXcHSe8GPvC6
 iwrFI0RnR59HbDh1UGOSoVZv/W9cwmam6WG5HpS7YcRYocZqZyv+XjxUTlj2r+nV
 12v9nnAWkH2Ub6kf3WHPzeXS3L6mvucody8b01UUL+j8hqWKN67sbXzH0Y2Nv0tv
 KFgbJCSk
 =CntT
 -----END PGP SIGNATURE-----

Merge tag 'v6.11-rc6-cifs-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

 - fix potential mount hang

 - fix retry problem in two types of compound operations

 - important netfs integration fix in SMB1 read paths

 - fix potential uninitialized zero point of inode

 - minor patch to improve debugging for potential crediting problems

* tag 'v6.11-rc6-cifs-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  netfs, cifs: Improve some debugging bits
  cifs: Fix SMB1 readv/writev callback in the same way as SMB2/3
  cifs: Fix zero_point init on inode initialisation
  smb: client: fix double put of @cfile in smb2_set_path_size()
  smb: client: fix double put of @cfile in smb2_rename_path()
  smb: client: fix hang in wait_for_response() for negproto
This commit is contained in:
Linus Torvalds 2024-09-06 17:30:33 -07:00
commit a86b83f777
6 changed files with 70 additions and 13 deletions

View file

@ -270,7 +270,7 @@ static void netfs_reset_subreq_iter(struct netfs_io_request *rreq,
if (count == remaining) if (count == remaining)
return; return;
_debug("R=%08x[%u] ITER RESUB-MISMATCH %zx != %zx-%zx-%llx %x\n", _debug("R=%08x[%u] ITER RESUB-MISMATCH %zx != %zx-%zx-%llx %x",
rreq->debug_id, subreq->debug_index, rreq->debug_id, subreq->debug_index,
iov_iter_count(&subreq->io_iter), subreq->transferred, iov_iter_count(&subreq->io_iter), subreq->transferred,
subreq->len, rreq->i_size, subreq->len, rreq->i_size,

View file

@ -1261,16 +1261,32 @@ openRetry:
return rc; return rc;
} }
static void cifs_readv_worker(struct work_struct *work)
{
struct cifs_io_subrequest *rdata =
container_of(work, struct cifs_io_subrequest, subreq.work);
netfs_subreq_terminated(&rdata->subreq,
(rdata->result == 0 || rdata->result == -EAGAIN) ?
rdata->got_bytes : rdata->result, true);
}
static void static void
cifs_readv_callback(struct mid_q_entry *mid) cifs_readv_callback(struct mid_q_entry *mid)
{ {
struct cifs_io_subrequest *rdata = mid->callback_data; struct cifs_io_subrequest *rdata = mid->callback_data;
struct netfs_inode *ictx = netfs_inode(rdata->rreq->inode);
struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(rdata->req->cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
struct smb_rqst rqst = { .rq_iov = rdata->iov, struct smb_rqst rqst = { .rq_iov = rdata->iov,
.rq_nvec = 2, .rq_nvec = 2,
.rq_iter = rdata->subreq.io_iter }; .rq_iter = rdata->subreq.io_iter };
struct cifs_credits credits = { .value = 1, .instance = 0 }; struct cifs_credits credits = {
.value = 1,
.instance = 0,
.rreq_debug_id = rdata->rreq->debug_id,
.rreq_debug_index = rdata->subreq.debug_index,
};
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n", cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%zu\n",
__func__, mid->mid, mid->mid_state, rdata->result, __func__, mid->mid, mid->mid_state, rdata->result,
@ -1282,6 +1298,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
if (server->sign) { if (server->sign) {
int rc = 0; int rc = 0;
iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
rc = cifs_verify_signature(&rqst, server, rc = cifs_verify_signature(&rqst, server,
mid->sequence_number); mid->sequence_number);
if (rc) if (rc)
@ -1306,13 +1323,21 @@ cifs_readv_callback(struct mid_q_entry *mid)
rdata->result = -EIO; rdata->result = -EIO;
} }
if (rdata->result == 0 || rdata->result == -EAGAIN) if (rdata->result == -ENODATA) {
iov_iter_advance(&rdata->subreq.io_iter, rdata->got_bytes); __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
rdata->result = 0;
} else {
if (rdata->got_bytes < rdata->actual_len &&
rdata->subreq.start + rdata->subreq.transferred + rdata->got_bytes ==
ictx->remote_i_size) {
__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);
rdata->result = 0;
}
}
rdata->credits.value = 0; rdata->credits.value = 0;
netfs_subreq_terminated(&rdata->subreq, INIT_WORK(&rdata->subreq.work, cifs_readv_worker);
(rdata->result == 0 || rdata->result == -EAGAIN) ? queue_work(cifsiod_wq, &rdata->subreq.work);
rdata->got_bytes : rdata->result,
false);
release_mid(mid); release_mid(mid);
add_credits(server, &credits, 0); add_credits(server, &credits, 0);
} }
@ -1619,9 +1644,15 @@ static void
cifs_writev_callback(struct mid_q_entry *mid) cifs_writev_callback(struct mid_q_entry *mid)
{ {
struct cifs_io_subrequest *wdata = mid->callback_data; struct cifs_io_subrequest *wdata = mid->callback_data;
struct TCP_Server_Info *server = wdata->server;
struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink); struct cifs_tcon *tcon = tlink_tcon(wdata->req->cfile->tlink);
WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
struct cifs_credits credits = { .value = 1, .instance = 0 }; struct cifs_credits credits = {
.value = 1,
.instance = 0,
.rreq_debug_id = wdata->rreq->debug_id,
.rreq_debug_index = wdata->subreq.debug_index,
};
ssize_t result; ssize_t result;
size_t written; size_t written;
@ -1657,9 +1688,16 @@ cifs_writev_callback(struct mid_q_entry *mid)
break; break;
} }
trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index,
wdata->credits.value,
server->credits, server->in_flight,
0, cifs_trace_rw_credits_write_response_clear);
wdata->credits.value = 0; wdata->credits.value = 0;
cifs_write_subrequest_terminated(wdata, result, true); cifs_write_subrequest_terminated(wdata, result, true);
release_mid(mid); release_mid(mid);
trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0,
server->credits, server->in_flight,
credits.value, cifs_trace_rw_credits_write_response_add);
add_credits(tcon->ses->server, &credits, 0); add_credits(tcon->ses->server, &credits, 0);
} }

View file

@ -656,6 +656,19 @@ allocate_buffers(struct TCP_Server_Info *server)
static bool static bool
server_unresponsive(struct TCP_Server_Info *server) server_unresponsive(struct TCP_Server_Info *server)
{ {
/*
* If we're in the process of mounting a share or reconnecting a session
* and the server abruptly shut down (e.g. socket wasn't closed, packet
* had been ACK'ed but no SMB response), don't wait longer than 20s to
* negotiate protocol.
*/
spin_lock(&server->srv_lock);
if (server->tcpStatus == CifsInNegotiate &&
time_after(jiffies, server->lstrp + 20 * HZ)) {
spin_unlock(&server->srv_lock);
cifs_reconnect(server, false);
return true;
}
/* /*
* We need to wait 3 echo intervals to make sure we handle such * We need to wait 3 echo intervals to make sure we handle such
* situations right: * situations right:
@ -667,7 +680,6 @@ server_unresponsive(struct TCP_Server_Info *server)
* 65s kernel_recvmsg times out, and we see that we haven't gotten * 65s kernel_recvmsg times out, and we see that we haven't gotten
* a response in >60s. * a response in >60s.
*/ */
spin_lock(&server->srv_lock);
if ((server->tcpStatus == CifsGood || if ((server->tcpStatus == CifsGood ||
server->tcpStatus == CifsNeedNegotiate) && server->tcpStatus == CifsNeedNegotiate) &&
(!server->ops->can_echo || server->ops->can_echo(server)) && (!server->ops->can_echo || server->ops->can_echo(server)) &&

View file

@ -172,6 +172,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
CIFS_I(inode)->time = 0; /* force reval */ CIFS_I(inode)->time = 0; /* force reval */
return -ESTALE; return -ESTALE;
} }
if (inode->i_state & I_NEW)
CIFS_I(inode)->netfs.zero_point = fattr->cf_eof;
cifs_revalidate_cache(inode, fattr); cifs_revalidate_cache(inode, fattr);

View file

@ -1106,6 +1106,8 @@ int smb2_rename_path(const unsigned int xid,
co, DELETE, SMB2_OP_RENAME, cfile, source_dentry); co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
if (rc == -EINVAL) { if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease"); cifs_dbg(FYI, "invalid lease key, resending request without lease");
cifs_get_writable_path(tcon, from_name,
FIND_WR_WITH_DELETE, &cfile);
rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb, rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
co, DELETE, SMB2_OP_RENAME, cfile, NULL); co, DELETE, SMB2_OP_RENAME, cfile, NULL);
} }
@ -1149,6 +1151,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
cfile, NULL, NULL, dentry); cfile, NULL, NULL, dentry);
if (rc == -EINVAL) { if (rc == -EINVAL) {
cifs_dbg(FYI, "invalid lease key, resending request without lease"); cifs_dbg(FYI, "invalid lease key, resending request without lease");
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, rc = smb2_compound_op(xid, tcon, cifs_sb,
full_path, &oparms, &in_iov, full_path, &oparms, &in_iov,
&(int){SMB2_OP_SET_EOF}, 1, &(int){SMB2_OP_SET_EOF}, 1,

View file

@ -316,7 +316,8 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
cifs_trace_rw_credits_no_adjust_up); cifs_trace_rw_credits_no_adjust_up);
trace_smb3_too_many_credits(server->CurrentMid, trace_smb3_too_many_credits(server->CurrentMid,
server->conn_id, server->hostname, 0, credits->value - new_val, 0); server->conn_id, server->hostname, 0, credits->value - new_val, 0);
cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)", cifs_server_dbg(VFS, "R=%x[%x] request has less credits (%d) than required (%d)",
subreq->rreq->debug_id, subreq->subreq.debug_index,
credits->value, new_val); credits->value, new_val);
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -338,8 +339,9 @@ smb2_adjust_credits(struct TCP_Server_Info *server,
trace_smb3_reconnect_detected(server->CurrentMid, trace_smb3_reconnect_detected(server->CurrentMid,
server->conn_id, server->hostname, scredits, server->conn_id, server->hostname, scredits,
credits->value - new_val, in_flight); credits->value - new_val, in_flight);
cifs_server_dbg(VFS, "trying to return %d credits to old session\n", cifs_server_dbg(VFS, "R=%x[%x] trying to return %d credits to old session\n",
credits->value - new_val); subreq->rreq->debug_id, subreq->subreq.debug_index,
credits->value - new_val);
return -EAGAIN; return -EAGAIN;
} }