mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-04 04:02:26 +00:00
Six smb3 client fixes, including three for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmUOSHkACgkQiiy9cAdy T1HAswwAmCPPUWgIiR4XqWiXOmWh60+4Q7xsmSVvRAixvTf79Tkif/1AmVYhnYls QvnbT5TIFPtFbnWHOIYSPxkjBlVRNTgSviSdOebZAv4aP3DJ+HhWqnv39ti7DFMt qbNn9j53czq5eLChkIiCfqbeg4I8ra+vqZeeDs5TaRFqMLZ5KlJGlVJjnf88/o8m cCjifqq53Bq1pZeaR1Q9aiwuzsSKazs4odEeFvwFSw0tsdjEj4Rk5vJqDcMnt460 yIXzoUv3iGJ2oz7qi5uysGPOpLAbDqwbJ5+127qja3cbgHg3MJqwotheRuULYX8G Dz9hhgu5oGlvSO+fZXnsT2bQL+oqYUyql9EU5NBTF2gPf5M3E1vQaMNPj1cueNAg dfa3x3Ez/M1XuH2aptK3ePuPIQIZgMjpMC7BPBKaIvxtGcNxEIuL0s+TEQbjJ8R1 /ybJv2i+LYfCrnjTDvH0Y4lTS40AHIcOwywQd6rbMuStK71+B7/bNYJkdKKK9PEF L39ZwXDj =Q4Rt -----END PGP SIGNATURE----- Merge tag '6.6-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client fixes from Steve French: "Six smb3 client fixes, including three for stable, from the SMB plugfest (testing event) this week: - Reparse point handling fix (found when investigating dir enumeration when fifo in dir) - Fix excessive thread creation for dir lease cleanup - UAF fix in negotiate path - remove duplicate error message mapping and fix confusing warning message - add dynamic trace point to improve debugging RDMA connection attempts" * tag '6.6-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb3: fix confusing debug message smb: client: handle STATUS_IO_REPARSE_TAG_NOT_HANDLED smb3: remove duplicate error mapping cifs: Fix UAF in cifs_demultiplex_thread() smb3: do not start laundromat thread when dir leases disabled smb3: Add dynamic trace points for RDMA (smbdirect) reconnect
This commit is contained in:
commit
8565bdf8cd
@ -452,6 +452,9 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
||||
struct cached_fid *cfid, *q;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
if (cfids == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
list_move(&cfid->entry, &entry);
|
||||
@ -651,6 +654,9 @@ void free_cached_dirs(struct cached_fids *cfids)
|
||||
struct cached_fid *cfid, *q;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
if (cfids == NULL)
|
||||
return;
|
||||
|
||||
if (cfids->laundromat) {
|
||||
kthread_stop(cfids->laundromat);
|
||||
cfids->laundromat = NULL;
|
||||
|
@ -1807,6 +1807,7 @@ static inline bool is_retryable_error(int error)
|
||||
#define MID_RETRY_NEEDED 8 /* session closed while this request out */
|
||||
#define MID_RESPONSE_MALFORMED 0x10
|
||||
#define MID_SHUTDOWN 0x20
|
||||
#define MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */
|
||||
|
||||
/* Flags */
|
||||
#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */
|
||||
@ -1943,7 +1944,7 @@ require use of the stronger protocol */
|
||||
* cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once
|
||||
* ->can_cache_brlcks
|
||||
* cifsInodeInfo->deferred_lock cifsInodeInfo->deferred_closes cifsInodeInfo_alloc
|
||||
* cached_fid->fid_mutex cifs_tcon->crfid tconInfoAlloc
|
||||
* cached_fid->fid_mutex cifs_tcon->crfid tcon_info_alloc
|
||||
* cifsFileInfo->fh_mutex cifsFileInfo cifs_new_fileinfo
|
||||
* cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo
|
||||
* ->invalidHandle initiate_cifs_search
|
||||
|
@ -512,7 +512,7 @@ extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);
|
||||
|
||||
extern struct cifs_ses *sesInfoAlloc(void);
|
||||
extern void sesInfoFree(struct cifs_ses *);
|
||||
extern struct cifs_tcon *tconInfoAlloc(void);
|
||||
extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled);
|
||||
extern void tconInfoFree(struct cifs_tcon *);
|
||||
|
||||
extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
|
@ -1882,7 +1882,8 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
tcon = tconInfoAlloc();
|
||||
/* no need to setup directory caching on IPC share, so pass in false */
|
||||
tcon = tcon_info_alloc(false);
|
||||
if (tcon == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -2492,7 +2493,10 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
tcon = tconInfoAlloc();
|
||||
if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
|
||||
tcon = tcon_info_alloc(true);
|
||||
else
|
||||
tcon = tcon_info_alloc(false);
|
||||
if (tcon == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out_fail;
|
||||
|
@ -113,18 +113,22 @@ sesInfoFree(struct cifs_ses *buf_to_free)
|
||||
}
|
||||
|
||||
struct cifs_tcon *
|
||||
tconInfoAlloc(void)
|
||||
tcon_info_alloc(bool dir_leases_enabled)
|
||||
{
|
||||
struct cifs_tcon *ret_buf;
|
||||
|
||||
ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
|
||||
if (!ret_buf)
|
||||
return NULL;
|
||||
ret_buf->cfids = init_cached_dirs();
|
||||
if (!ret_buf->cfids) {
|
||||
kfree(ret_buf);
|
||||
return NULL;
|
||||
|
||||
if (dir_leases_enabled == true) {
|
||||
ret_buf->cfids = init_cached_dirs();
|
||||
if (!ret_buf->cfids) {
|
||||
kfree(ret_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* else ret_buf->cfids is already set to NULL above */
|
||||
|
||||
atomic_inc(&tconInfoAllocCount);
|
||||
ret_buf->status = TID_NEW;
|
||||
|
@ -539,6 +539,9 @@ static int parse_create_response(struct cifs_open_info_data *data,
|
||||
int rc = 0;
|
||||
|
||||
switch (rsp->hdr.Status) {
|
||||
case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
|
||||
reparse_point = true;
|
||||
break;
|
||||
case STATUS_STOPPED_ON_SYMLINK:
|
||||
rc = smb2_parse_symlink_response(cifs_sb, iov,
|
||||
&data->symlink_target);
|
||||
|
@ -877,8 +877,6 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
||||
"STATUS_IO_REPARSE_TAG_MISMATCH"},
|
||||
{STATUS_IO_REPARSE_DATA_INVALID, -EIO,
|
||||
"STATUS_IO_REPARSE_DATA_INVALID"},
|
||||
{STATUS_IO_REPARSE_TAG_NOT_HANDLED, -EIO,
|
||||
"STATUS_IO_REPARSE_TAG_NOT_HANDLED"},
|
||||
{STATUS_REPARSE_POINT_NOT_RESOLVED, -EIO,
|
||||
"STATUS_REPARSE_POINT_NOT_RESOLVED"},
|
||||
{STATUS_DIRECTORY_IS_A_REPARSE_POINT, -EIO,
|
||||
|
@ -848,7 +848,7 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
|
||||
|
||||
iov[num].iov_base = create_posix_buf(mode);
|
||||
if (mode == ACL_NO_MODE)
|
||||
cifs_dbg(FYI, "Invalid mode\n");
|
||||
cifs_dbg(FYI, "%s: no mode\n", __func__);
|
||||
if (iov[num].iov_base == NULL)
|
||||
return -ENOMEM;
|
||||
iov[num].iov_len = sizeof(struct create_posix);
|
||||
@ -3878,7 +3878,7 @@ void smb2_reconnect_server(struct work_struct *work)
|
||||
goto done;
|
||||
|
||||
/* allocate a dummy tcon struct used for reconnect */
|
||||
tcon = tconInfoAlloc();
|
||||
tcon = tcon_info_alloc(false);
|
||||
if (!tcon) {
|
||||
resched = true;
|
||||
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
|
||||
|
@ -1401,10 +1401,13 @@ int smbd_reconnect(struct TCP_Server_Info *server)
|
||||
server->smbd_conn = smbd_get_connection(
|
||||
server, (struct sockaddr *) &server->dstaddr);
|
||||
|
||||
if (server->smbd_conn)
|
||||
if (server->smbd_conn) {
|
||||
cifs_dbg(VFS, "RDMA transport re-established\n");
|
||||
|
||||
return server->smbd_conn ? 0 : -ENOENT;
|
||||
trace_smb3_smbd_connect_done(server->hostname, server->conn_id, &server->dstaddr);
|
||||
return 0;
|
||||
}
|
||||
trace_smb3_smbd_connect_err(server->hostname, server->conn_id, &server->dstaddr);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void destroy_caches_and_workqueue(struct smbd_connection *info)
|
||||
|
@ -935,6 +935,8 @@ DEFINE_EVENT(smb3_connect_class, smb3_##name, \
|
||||
TP_ARGS(hostname, conn_id, addr))
|
||||
|
||||
DEFINE_SMB3_CONNECT_EVENT(connect_done);
|
||||
DEFINE_SMB3_CONNECT_EVENT(smbd_connect_done);
|
||||
DEFINE_SMB3_CONNECT_EVENT(smbd_connect_err);
|
||||
|
||||
DECLARE_EVENT_CLASS(smb3_connect_err_class,
|
||||
TP_PROTO(char *hostname, __u64 conn_id,
|
||||
|
@ -35,6 +35,8 @@
|
||||
void
|
||||
cifs_wake_up_task(struct mid_q_entry *mid)
|
||||
{
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED)
|
||||
mid->mid_state = MID_RESPONSE_READY;
|
||||
wake_up_process(mid->callback_data);
|
||||
}
|
||||
|
||||
@ -87,7 +89,8 @@ static void __release_mid(struct kref *refcount)
|
||||
struct TCP_Server_Info *server = midEntry->server;
|
||||
|
||||
if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) &&
|
||||
midEntry->mid_state == MID_RESPONSE_RECEIVED &&
|
||||
(midEntry->mid_state == MID_RESPONSE_RECEIVED ||
|
||||
midEntry->mid_state == MID_RESPONSE_READY) &&
|
||||
server->ops->handle_cancelled_mid)
|
||||
server->ops->handle_cancelled_mid(midEntry, server);
|
||||
|
||||
@ -737,7 +740,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
|
||||
int error;
|
||||
|
||||
error = wait_event_state(server->response_q,
|
||||
midQ->mid_state != MID_REQUEST_SUBMITTED,
|
||||
midQ->mid_state != MID_REQUEST_SUBMITTED &&
|
||||
midQ->mid_state != MID_RESPONSE_RECEIVED,
|
||||
(TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
|
||||
if (error < 0)
|
||||
return -ERESTARTSYS;
|
||||
@ -890,7 +894,7 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
|
||||
|
||||
spin_lock(&server->mid_lock);
|
||||
switch (mid->mid_state) {
|
||||
case MID_RESPONSE_RECEIVED:
|
||||
case MID_RESPONSE_READY:
|
||||
spin_unlock(&server->mid_lock);
|
||||
return rc;
|
||||
case MID_RETRY_NEEDED:
|
||||
@ -989,6 +993,9 @@ cifs_compound_callback(struct mid_q_entry *mid)
|
||||
credits.instance = server->reconnect_instance;
|
||||
|
||||
add_credits(server, &credits, mid->optype);
|
||||
|
||||
if (mid->mid_state == MID_RESPONSE_RECEIVED)
|
||||
mid->mid_state = MID_RESPONSE_READY;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1209,7 +1216,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
send_cancel(server, &rqst[i], midQ[i]);
|
||||
spin_lock(&server->mid_lock);
|
||||
midQ[i]->mid_flags |= MID_WAIT_CANCELLED;
|
||||
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
midQ[i]->callback = cifs_cancelled_callback;
|
||||
cancelled_mid[i] = true;
|
||||
credits[i].value = 0;
|
||||
@ -1230,7 +1238,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
}
|
||||
|
||||
if (!midQ[i]->resp_buf ||
|
||||
midQ[i]->mid_state != MID_RESPONSE_RECEIVED) {
|
||||
midQ[i]->mid_state != MID_RESPONSE_READY) {
|
||||
rc = -EIO;
|
||||
cifs_dbg(FYI, "Bad MID state?\n");
|
||||
goto out;
|
||||
@ -1417,7 +1425,8 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
if (rc != 0) {
|
||||
send_cancel(server, &rqst, midQ);
|
||||
spin_lock(&server->mid_lock);
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = release_mid;
|
||||
spin_unlock(&server->mid_lock);
|
||||
@ -1434,7 +1443,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
}
|
||||
|
||||
if (!midQ->resp_buf || !out_buf ||
|
||||
midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
||||
midQ->mid_state != MID_RESPONSE_READY) {
|
||||
rc = -EIO;
|
||||
cifs_server_dbg(VFS, "Bad MID state?\n");
|
||||
goto out;
|
||||
@ -1558,14 +1567,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
/* Wait for a reply - allow signals to interrupt. */
|
||||
rc = wait_event_interruptible(server->response_q,
|
||||
(!(midQ->mid_state == MID_REQUEST_SUBMITTED)) ||
|
||||
(!(midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED)) ||
|
||||
((server->tcpStatus != CifsGood) &&
|
||||
(server->tcpStatus != CifsNew)));
|
||||
|
||||
/* Were we interrupted by a signal ? */
|
||||
spin_lock(&server->srv_lock);
|
||||
if ((rc == -ERESTARTSYS) &&
|
||||
(midQ->mid_state == MID_REQUEST_SUBMITTED) &&
|
||||
(midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED) &&
|
||||
((server->tcpStatus == CifsGood) ||
|
||||
(server->tcpStatus == CifsNew))) {
|
||||
spin_unlock(&server->srv_lock);
|
||||
@ -1596,7 +1607,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (rc) {
|
||||
send_cancel(server, &rqst, midQ);
|
||||
spin_lock(&server->mid_lock);
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = release_mid;
|
||||
spin_unlock(&server->mid_lock);
|
||||
@ -1616,7 +1628,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
return rc;
|
||||
|
||||
/* rcvd frame is ok */
|
||||
if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_RECEIVED) {
|
||||
if (out_buf == NULL || midQ->mid_state != MID_RESPONSE_READY) {
|
||||
rc = -EIO;
|
||||
cifs_tcon_dbg(VFS, "Bad MID state?\n");
|
||||
goto out;
|
||||
|
Loading…
Reference in New Issue
Block a user