Commit 8565bdf8 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 5a4de7dc c8ebf077
...@@ -452,6 +452,9 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon) ...@@ -452,6 +452,9 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
struct cached_fid *cfid, *q; struct cached_fid *cfid, *q;
LIST_HEAD(entry); LIST_HEAD(entry);
if (cfids == NULL)
return;
spin_lock(&cfids->cfid_list_lock); spin_lock(&cfids->cfid_list_lock);
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) { list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
list_move(&cfid->entry, &entry); list_move(&cfid->entry, &entry);
...@@ -651,6 +654,9 @@ void free_cached_dirs(struct cached_fids *cfids) ...@@ -651,6 +654,9 @@ void free_cached_dirs(struct cached_fids *cfids)
struct cached_fid *cfid, *q; struct cached_fid *cfid, *q;
LIST_HEAD(entry); LIST_HEAD(entry);
if (cfids == NULL)
return;
if (cfids->laundromat) { if (cfids->laundromat) {
kthread_stop(cfids->laundromat); kthread_stop(cfids->laundromat);
cfids->laundromat = NULL; cfids->laundromat = NULL;
......
...@@ -1807,6 +1807,7 @@ static inline bool is_retryable_error(int error) ...@@ -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_RETRY_NEEDED 8 /* session closed while this request out */
#define MID_RESPONSE_MALFORMED 0x10 #define MID_RESPONSE_MALFORMED 0x10
#define MID_SHUTDOWN 0x20 #define MID_SHUTDOWN 0x20
#define MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */
/* Flags */ /* Flags */
#define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ #define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */
...@@ -1943,7 +1944,7 @@ require use of the stronger protocol */ ...@@ -1943,7 +1944,7 @@ require use of the stronger protocol */
* cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once * cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once
* ->can_cache_brlcks * ->can_cache_brlcks
* cifsInodeInfo->deferred_lock cifsInodeInfo->deferred_closes cifsInodeInfo_alloc * 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->fh_mutex cifsFileInfo cifs_new_fileinfo
* cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo * cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo
* ->invalidHandle initiate_cifs_search * ->invalidHandle initiate_cifs_search
......
...@@ -512,7 +512,7 @@ extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses); ...@@ -512,7 +512,7 @@ extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);
extern struct cifs_ses *sesInfoAlloc(void); extern struct cifs_ses *sesInfoAlloc(void);
extern void sesInfoFree(struct cifs_ses *); 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 void tconInfoFree(struct cifs_tcon *);
extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, 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) ...@@ -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) if (tcon == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -2492,7 +2493,10 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) ...@@ -2492,7 +2493,10 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
goto out_fail; 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) { if (tcon == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_fail; goto out_fail;
......
...@@ -113,18 +113,22 @@ sesInfoFree(struct cifs_ses *buf_to_free) ...@@ -113,18 +113,22 @@ sesInfoFree(struct cifs_ses *buf_to_free)
} }
struct cifs_tcon * struct cifs_tcon *
tconInfoAlloc(void) tcon_info_alloc(bool dir_leases_enabled)
{ {
struct cifs_tcon *ret_buf; struct cifs_tcon *ret_buf;
ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
if (!ret_buf) if (!ret_buf)
return NULL; return NULL;
ret_buf->cfids = init_cached_dirs();
if (!ret_buf->cfids) { if (dir_leases_enabled == true) {
kfree(ret_buf); ret_buf->cfids = init_cached_dirs();
return NULL; if (!ret_buf->cfids) {
kfree(ret_buf);
return NULL;
}
} }
/* else ret_buf->cfids is already set to NULL above */
atomic_inc(&tconInfoAllocCount); atomic_inc(&tconInfoAllocCount);
ret_buf->status = TID_NEW; ret_buf->status = TID_NEW;
......
...@@ -539,6 +539,9 @@ static int parse_create_response(struct cifs_open_info_data *data, ...@@ -539,6 +539,9 @@ static int parse_create_response(struct cifs_open_info_data *data,
int rc = 0; int rc = 0;
switch (rsp->hdr.Status) { switch (rsp->hdr.Status) {
case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
reparse_point = true;
break;
case STATUS_STOPPED_ON_SYMLINK: case STATUS_STOPPED_ON_SYMLINK:
rc = smb2_parse_symlink_response(cifs_sb, iov, rc = smb2_parse_symlink_response(cifs_sb, iov,
&data->symlink_target); &data->symlink_target);
......
...@@ -877,8 +877,6 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -877,8 +877,6 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
"STATUS_IO_REPARSE_TAG_MISMATCH"}, "STATUS_IO_REPARSE_TAG_MISMATCH"},
{STATUS_IO_REPARSE_DATA_INVALID, -EIO, {STATUS_IO_REPARSE_DATA_INVALID, -EIO,
"STATUS_IO_REPARSE_DATA_INVALID"}, "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, -EIO,
"STATUS_REPARSE_POINT_NOT_RESOLVED"}, "STATUS_REPARSE_POINT_NOT_RESOLVED"},
{STATUS_DIRECTORY_IS_A_REPARSE_POINT, -EIO, {STATUS_DIRECTORY_IS_A_REPARSE_POINT, -EIO,
......
...@@ -848,7 +848,7 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) ...@@ -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); iov[num].iov_base = create_posix_buf(mode);
if (mode == ACL_NO_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) if (iov[num].iov_base == NULL)
return -ENOMEM; return -ENOMEM;
iov[num].iov_len = sizeof(struct create_posix); iov[num].iov_len = sizeof(struct create_posix);
...@@ -3878,7 +3878,7 @@ void smb2_reconnect_server(struct work_struct *work) ...@@ -3878,7 +3878,7 @@ void smb2_reconnect_server(struct work_struct *work)
goto done; goto done;
/* allocate a dummy tcon struct used for reconnect */ /* allocate a dummy tcon struct used for reconnect */
tcon = tconInfoAlloc(); tcon = tcon_info_alloc(false);
if (!tcon) { if (!tcon) {
resched = true; resched = true;
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) { list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
......
...@@ -1401,10 +1401,13 @@ int smbd_reconnect(struct TCP_Server_Info *server) ...@@ -1401,10 +1401,13 @@ int smbd_reconnect(struct TCP_Server_Info *server)
server->smbd_conn = smbd_get_connection( server->smbd_conn = smbd_get_connection(
server, (struct sockaddr *) &server->dstaddr); server, (struct sockaddr *) &server->dstaddr);
if (server->smbd_conn) if (server->smbd_conn) {
cifs_dbg(VFS, "RDMA transport re-established\n"); cifs_dbg(VFS, "RDMA transport re-established\n");
trace_smb3_smbd_connect_done(server->hostname, server->conn_id, &server->dstaddr);
return server->smbd_conn ? 0 : -ENOENT; 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) static void destroy_caches_and_workqueue(struct smbd_connection *info)
......
...@@ -935,6 +935,8 @@ DEFINE_EVENT(smb3_connect_class, smb3_##name, \ ...@@ -935,6 +935,8 @@ DEFINE_EVENT(smb3_connect_class, smb3_##name, \
TP_ARGS(hostname, conn_id, addr)) TP_ARGS(hostname, conn_id, addr))
DEFINE_SMB3_CONNECT_EVENT(connect_done); 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, DECLARE_EVENT_CLASS(smb3_connect_err_class,
TP_PROTO(char *hostname, __u64 conn_id, TP_PROTO(char *hostname, __u64 conn_id,
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
void void
cifs_wake_up_task(struct mid_q_entry *mid) 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); wake_up_process(mid->callback_data);
} }
...@@ -87,7 +89,8 @@ static void __release_mid(struct kref *refcount) ...@@ -87,7 +89,8 @@ static void __release_mid(struct kref *refcount)
struct TCP_Server_Info *server = midEntry->server; struct TCP_Server_Info *server = midEntry->server;
if (midEntry->resp_buf && (midEntry->mid_flags & MID_WAIT_CANCELLED) && 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)
server->ops->handle_cancelled_mid(midEntry, server); server->ops->handle_cancelled_mid(midEntry, server);
...@@ -737,7 +740,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) ...@@ -737,7 +740,8 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
int error; int error;
error = wait_event_state(server->response_q, 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)); (TASK_KILLABLE|TASK_FREEZABLE_UNSAFE));
if (error < 0) if (error < 0)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -890,7 +894,7 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) ...@@ -890,7 +894,7 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
spin_lock(&server->mid_lock); spin_lock(&server->mid_lock);
switch (mid->mid_state) { switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED: case MID_RESPONSE_READY:
spin_unlock(&server->mid_lock); spin_unlock(&server->mid_lock);
return rc; return rc;
case MID_RETRY_NEEDED: case MID_RETRY_NEEDED:
...@@ -989,6 +993,9 @@ cifs_compound_callback(struct mid_q_entry *mid) ...@@ -989,6 +993,9 @@ cifs_compound_callback(struct mid_q_entry *mid)
credits.instance = server->reconnect_instance; credits.instance = server->reconnect_instance;
add_credits(server, &credits, mid->optype); add_credits(server, &credits, mid->optype);
if (mid->mid_state == MID_RESPONSE_RECEIVED)
mid->mid_state = MID_RESPONSE_READY;
} }
static void static void
...@@ -1209,7 +1216,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1209,7 +1216,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
send_cancel(server, &rqst[i], midQ[i]); send_cancel(server, &rqst[i], midQ[i]);
spin_lock(&server->mid_lock); spin_lock(&server->mid_lock);
midQ[i]->mid_flags |= MID_WAIT_CANCELLED; 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; midQ[i]->callback = cifs_cancelled_callback;
cancelled_mid[i] = true; cancelled_mid[i] = true;
credits[i].value = 0; credits[i].value = 0;
...@@ -1230,7 +1238,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1230,7 +1238,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
} }
if (!midQ[i]->resp_buf || if (!midQ[i]->resp_buf ||
midQ[i]->mid_state != MID_RESPONSE_RECEIVED) { midQ[i]->mid_state != MID_RESPONSE_READY) {
rc = -EIO; rc = -EIO;
cifs_dbg(FYI, "Bad MID state?\n"); cifs_dbg(FYI, "Bad MID state?\n");
goto out; goto out;
...@@ -1417,7 +1425,8 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, ...@@ -1417,7 +1425,8 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
if (rc != 0) { if (rc != 0) {
send_cancel(server, &rqst, midQ); send_cancel(server, &rqst, midQ);
spin_lock(&server->mid_lock); 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" */ /* no longer considered to be "in-flight" */
midQ->callback = release_mid; midQ->callback = release_mid;
spin_unlock(&server->mid_lock); spin_unlock(&server->mid_lock);
...@@ -1434,7 +1443,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, ...@@ -1434,7 +1443,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
} }
if (!midQ->resp_buf || !out_buf || if (!midQ->resp_buf || !out_buf ||
midQ->mid_state != MID_RESPONSE_RECEIVED) { midQ->mid_state != MID_RESPONSE_READY) {
rc = -EIO; rc = -EIO;
cifs_server_dbg(VFS, "Bad MID state?\n"); cifs_server_dbg(VFS, "Bad MID state?\n");
goto out; goto out;
...@@ -1558,14 +1567,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1558,14 +1567,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
/* Wait for a reply - allow signals to interrupt. */ /* Wait for a reply - allow signals to interrupt. */
rc = wait_event_interruptible(server->response_q, 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 != CifsGood) &&
(server->tcpStatus != CifsNew))); (server->tcpStatus != CifsNew)));
/* Were we interrupted by a signal ? */ /* Were we interrupted by a signal ? */
spin_lock(&server->srv_lock); spin_lock(&server->srv_lock);
if ((rc == -ERESTARTSYS) && 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 == CifsGood) ||
(server->tcpStatus == CifsNew))) { (server->tcpStatus == CifsNew))) {
spin_unlock(&server->srv_lock); spin_unlock(&server->srv_lock);
...@@ -1596,7 +1607,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1596,7 +1607,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
if (rc) { if (rc) {
send_cancel(server, &rqst, midQ); send_cancel(server, &rqst, midQ);
spin_lock(&server->mid_lock); 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" */ /* no longer considered to be "in-flight" */
midQ->callback = release_mid; midQ->callback = release_mid;
spin_unlock(&server->mid_lock); spin_unlock(&server->mid_lock);
...@@ -1616,7 +1628,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1616,7 +1628,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
return rc; return rc;
/* rcvd frame is ok */ /* 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; rc = -EIO;
cifs_tcon_dbg(VFS, "Bad MID state?\n"); cifs_tcon_dbg(VFS, "Bad MID state?\n");
goto out; goto out;
......
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