mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-15 12:04:14 -05:00
Merge tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - Fix unlink race and rename races - SMB3.1.1 compression fix - Avoid unneeded strlen calls in cifs_get_spnego_key - Fix slab out of bounds in parse_server_interfaces() - Fix mid leak and server buffer leak - smbdirect send error path fix - update internal version # - Fix unneeded response time update in negotiate protocol * tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: remove redundant lstrp update in negotiate protocol cifs: update internal version number smb: client: don't wait for info->send_pending == 0 on error smb: client: fix mid_q_entry memleak leak with per-mid locking smb3: fix for slab out of bounds on mount to ksmbd cifs: avoid extra calls to strlen() in cifs_get_spnego_key() cifs: Fix collect_sample() to handle any iterator type smb: client: fix race with concurrent opens in rename(2) smb: client: fix race with concurrent opens in unlink(2)
This commit is contained in:
@@ -124,55 +124,44 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
|
||||
dp = description;
|
||||
/* start with version and hostname portion of UNC string */
|
||||
spnego_key = ERR_PTR(-EINVAL);
|
||||
sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
|
||||
hostname);
|
||||
dp = description + strlen(description);
|
||||
dp += sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
|
||||
hostname);
|
||||
|
||||
/* add the server address */
|
||||
if (server->dstaddr.ss_family == AF_INET)
|
||||
sprintf(dp, "ip4=%pI4", &sa->sin_addr);
|
||||
dp += sprintf(dp, "ip4=%pI4", &sa->sin_addr);
|
||||
else if (server->dstaddr.ss_family == AF_INET6)
|
||||
sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
|
||||
dp += sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
|
||||
else
|
||||
goto out;
|
||||
|
||||
dp = description + strlen(description);
|
||||
|
||||
/* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */
|
||||
if (server->sec_kerberos)
|
||||
sprintf(dp, ";sec=krb5");
|
||||
dp += sprintf(dp, ";sec=krb5");
|
||||
else if (server->sec_mskerberos)
|
||||
sprintf(dp, ";sec=mskrb5");
|
||||
dp += sprintf(dp, ";sec=mskrb5");
|
||||
else if (server->sec_iakerb)
|
||||
sprintf(dp, ";sec=iakerb");
|
||||
dp += sprintf(dp, ";sec=iakerb");
|
||||
else {
|
||||
cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n");
|
||||
sprintf(dp, ";sec=krb5");
|
||||
dp += sprintf(dp, ";sec=krb5");
|
||||
}
|
||||
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";uid=0x%x",
|
||||
from_kuid_munged(&init_user_ns, sesInfo->linux_uid));
|
||||
dp += sprintf(dp, ";uid=0x%x",
|
||||
from_kuid_munged(&init_user_ns, sesInfo->linux_uid));
|
||||
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";creduid=0x%x",
|
||||
dp += sprintf(dp, ";creduid=0x%x",
|
||||
from_kuid_munged(&init_user_ns, sesInfo->cred_uid));
|
||||
|
||||
if (sesInfo->user_name) {
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";user=%s", sesInfo->user_name);
|
||||
}
|
||||
if (sesInfo->user_name)
|
||||
dp += sprintf(dp, ";user=%s", sesInfo->user_name);
|
||||
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";pid=0x%x", current->pid);
|
||||
dp += sprintf(dp, ";pid=0x%x", current->pid);
|
||||
|
||||
if (sesInfo->upcall_target == UPTARGET_MOUNT) {
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";upcall_target=mount");
|
||||
} else {
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";upcall_target=app");
|
||||
}
|
||||
if (sesInfo->upcall_target == UPTARGET_MOUNT)
|
||||
dp += sprintf(dp, ";upcall_target=mount");
|
||||
else
|
||||
dp += sprintf(dp, ";upcall_target=app");
|
||||
|
||||
cifs_dbg(FYI, "key description = %s\n", description);
|
||||
saved_cred = override_creds(spnego_cred);
|
||||
|
||||
@@ -145,6 +145,6 @@ extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
/* when changing internal version - update following two lines at same time */
|
||||
#define SMB3_PRODUCT_BUILD 55
|
||||
#define CIFS_VERSION "2.55"
|
||||
#define SMB3_PRODUCT_BUILD 56
|
||||
#define CIFS_VERSION "2.56"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
||||
@@ -1732,6 +1732,7 @@ struct mid_q_entry {
|
||||
int mid_rc; /* rc for MID_RC */
|
||||
__le16 command; /* smb command code */
|
||||
unsigned int optype; /* operation type */
|
||||
spinlock_t mid_lock;
|
||||
bool wait_cancelled:1; /* Cancelled while waiting for response */
|
||||
bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid_q */
|
||||
bool large_buf:1; /* if valid response, is pointer to large buf */
|
||||
@@ -2036,6 +2037,9 @@ require use of the stronger protocol */
|
||||
* cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo
|
||||
* ->invalidHandle initiate_cifs_search
|
||||
* ->oplock_break_cancelled
|
||||
* mid_q_entry->mid_lock mid_q_entry->callback alloc_mid
|
||||
* smb2_mid_entry_alloc
|
||||
* (Any fields of mid_q_entry that will need protection)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef DECLARE_GLOBALS_HERE
|
||||
@@ -2375,6 +2379,23 @@ static inline bool cifs_netbios_name(const char *name, size_t namelen)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute mid callback atomically - ensures callback runs exactly once
|
||||
* and prevents sleeping in atomic context.
|
||||
*/
|
||||
static inline void mid_execute_callback(struct mid_q_entry *mid)
|
||||
{
|
||||
void (*callback)(struct mid_q_entry *mid);
|
||||
|
||||
spin_lock(&mid->mid_lock);
|
||||
callback = mid->callback;
|
||||
mid->callback = NULL; /* Mark as executed, */
|
||||
spin_unlock(&mid->mid_lock);
|
||||
|
||||
if (callback)
|
||||
callback(mid);
|
||||
}
|
||||
|
||||
#define CIFS_REPARSE_SUPPORT(tcon) \
|
||||
((tcon)->posix_extensions || \
|
||||
(le32_to_cpu((tcon)->fsAttrInfo.Attributes) & \
|
||||
|
||||
@@ -46,6 +46,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
|
||||
temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
|
||||
memset(temp, 0, sizeof(struct mid_q_entry));
|
||||
kref_init(&temp->refcount);
|
||||
spin_lock_init(&temp->mid_lock);
|
||||
temp->mid = get_mid(smb_buffer);
|
||||
temp->pid = current->pid;
|
||||
temp->command = cpu_to_le16(smb_buffer->Command);
|
||||
@@ -345,16 +346,15 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
rc = wait_for_response(server, midQ);
|
||||
if (rc != 0) {
|
||||
send_cancel(server, &rqst, midQ);
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
spin_lock(&midQ->mid_lock);
|
||||
if (midQ->callback) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = release_mid;
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
add_credits(server, &credits, 0);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
}
|
||||
|
||||
rc = cifs_sync_mid_result(midQ, server);
|
||||
@@ -527,15 +527,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
rc = wait_for_response(server, midQ);
|
||||
if (rc) {
|
||||
send_cancel(server, &rqst, midQ);
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
if (midQ->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
spin_lock(&midQ->mid_lock);
|
||||
if (midQ->callback) {
|
||||
/* no longer considered to be "in-flight" */
|
||||
midQ->callback = release_mid;
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
spin_unlock(&midQ->mid_lock);
|
||||
}
|
||||
|
||||
/* We got the response - restart system call. */
|
||||
|
||||
@@ -155,58 +155,29 @@ static int cmp_bkt(const void *_a, const void *_b)
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* Support other iter types, if required.
|
||||
* Only ITER_XARRAY is supported for now.
|
||||
* Collect some 2K samples with 2K gaps between.
|
||||
*/
|
||||
static int collect_sample(const struct iov_iter *iter, ssize_t max, u8 *sample)
|
||||
static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample)
|
||||
{
|
||||
struct folio *folios[16], *folio;
|
||||
unsigned int nr, i, j, npages;
|
||||
loff_t start = iter->xarray_start + iter->iov_offset;
|
||||
pgoff_t last, index = start / PAGE_SIZE;
|
||||
size_t len, off, foff;
|
||||
void *p;
|
||||
int s = 0;
|
||||
struct iov_iter iter = *source;
|
||||
size_t s = 0;
|
||||
|
||||
last = (start + max - 1) / PAGE_SIZE;
|
||||
do {
|
||||
nr = xa_extract(iter->xarray, (void **)folios, index, last, ARRAY_SIZE(folios),
|
||||
XA_PRESENT);
|
||||
if (nr == 0)
|
||||
return -EIO;
|
||||
while (iov_iter_count(&iter) >= SZ_2K) {
|
||||
size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max);
|
||||
size_t n;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
folio = folios[i];
|
||||
npages = folio_nr_pages(folio);
|
||||
foff = start - folio_pos(folio);
|
||||
off = foff % PAGE_SIZE;
|
||||
n = copy_from_iter(sample + s, part, &iter);
|
||||
if (n != part)
|
||||
return -EFAULT;
|
||||
|
||||
for (j = foff / PAGE_SIZE; j < npages; j++) {
|
||||
size_t len2;
|
||||
s += n;
|
||||
max -= n;
|
||||
|
||||
len = min_t(size_t, max, PAGE_SIZE - off);
|
||||
len2 = min_t(size_t, len, SZ_2K);
|
||||
if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K)
|
||||
break;
|
||||
|
||||
p = kmap_local_page(folio_page(folio, j));
|
||||
memcpy(&sample[s], p, len2);
|
||||
kunmap_local(p);
|
||||
|
||||
s += len2;
|
||||
|
||||
if (len2 < SZ_2K || s >= max - SZ_2K)
|
||||
return s;
|
||||
|
||||
max -= len;
|
||||
if (max <= 0)
|
||||
return s;
|
||||
|
||||
start += len;
|
||||
off = 0;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
} while (nr == ARRAY_SIZE(folios));
|
||||
iov_iter_advance(&iter, SZ_2K);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
|
||||
cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
|
||||
list_for_each_entry_safe(mid, nmid, &retry_list, qhead) {
|
||||
list_del_init(&mid->qhead);
|
||||
mid->callback(mid);
|
||||
mid_execute_callback(mid);
|
||||
release_mid(mid);
|
||||
}
|
||||
|
||||
@@ -919,7 +919,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type)
|
||||
list_del_init(&mid->qhead);
|
||||
mid->mid_rc = mid_rc;
|
||||
mid->mid_state = MID_RC;
|
||||
mid->callback(mid);
|
||||
mid_execute_callback(mid);
|
||||
release_mid(mid);
|
||||
}
|
||||
|
||||
@@ -1117,7 +1117,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server)
|
||||
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
||||
cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid);
|
||||
list_del_init(&mid_entry->qhead);
|
||||
mid_entry->callback(mid_entry);
|
||||
mid_execute_callback(mid_entry);
|
||||
release_mid(mid_entry);
|
||||
}
|
||||
/* 1/8th of sec is more than enough time for them to exit */
|
||||
@@ -1394,7 +1394,7 @@ cifs_demultiplex_thread(void *p)
|
||||
}
|
||||
|
||||
if (!mids[i]->multiRsp || mids[i]->multiEnd)
|
||||
mids[i]->callback(mids[i]);
|
||||
mid_execute_callback(mids[i]);
|
||||
|
||||
release_mid(mids[i]);
|
||||
} else if (server->ops->is_oplock_break &&
|
||||
@@ -4205,7 +4205,6 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
|
||||
return 0;
|
||||
}
|
||||
|
||||
server->lstrp = jiffies;
|
||||
server->tcpStatus = CifsInNegotiate;
|
||||
server->neg_start = jiffies;
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
@@ -1943,15 +1943,24 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
__u32 dosattr = 0, origattr = 0;
|
||||
struct TCP_Server_Info *server;
|
||||
struct iattr *attrs = NULL;
|
||||
__u32 dosattr = 0, origattr = 0;
|
||||
bool rehash = false;
|
||||
|
||||
cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
|
||||
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
|
||||
/* Unhash dentry in advance to prevent any concurrent opens */
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (!d_unhashed(dentry)) {
|
||||
__d_drop(dentry);
|
||||
rehash = true;
|
||||
}
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@@ -2003,7 +2012,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
cifs_drop_nlink(inode);
|
||||
}
|
||||
} else if (rc == -ENOENT) {
|
||||
d_drop(dentry);
|
||||
if (simple_positive(dentry))
|
||||
d_delete(dentry);
|
||||
} else if (rc == -EBUSY) {
|
||||
if (server->ops->rename_pending_delete) {
|
||||
rc = server->ops->rename_pending_delete(full_path,
|
||||
@@ -2056,6 +2066,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
kfree(attrs);
|
||||
free_xid(xid);
|
||||
cifs_put_tlink(tlink);
|
||||
if (rehash)
|
||||
d_rehash(dentry);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2462,6 +2474,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
bool rehash = false;
|
||||
unsigned int xid;
|
||||
int rc, tmprc;
|
||||
int retry_count = 0;
|
||||
@@ -2477,6 +2490,17 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
||||
if (unlikely(cifs_forced_shutdown(cifs_sb)))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* Prevent any concurrent opens on the target by unhashing the dentry.
|
||||
* VFS already unhashes the target when renaming directories.
|
||||
*/
|
||||
if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) {
|
||||
if (!d_unhashed(target_dentry)) {
|
||||
d_drop(target_dentry);
|
||||
rehash = true;
|
||||
}
|
||||
}
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@@ -2518,6 +2542,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rehash = false;
|
||||
/*
|
||||
* No-replace is the natural behavior for CIFS, so skip unlink hacks.
|
||||
*/
|
||||
@@ -2576,12 +2602,16 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
|
||||
goto cifs_rename_exit;
|
||||
rc = cifs_do_rename(xid, source_dentry, from_name,
|
||||
target_dentry, to_name);
|
||||
if (!rc)
|
||||
rehash = false;
|
||||
}
|
||||
|
||||
/* force revalidate to go get info when needed */
|
||||
CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
|
||||
|
||||
cifs_rename_exit:
|
||||
if (rehash)
|
||||
d_rehash(target_dentry);
|
||||
kfree(info_buf_source);
|
||||
free_dentry_path(page2);
|
||||
free_dentry_path(page1);
|
||||
|
||||
@@ -772,6 +772,13 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
bytes_left -= sizeof(*p);
|
||||
break;
|
||||
}
|
||||
/* Validate that Next doesn't point beyond the buffer */
|
||||
if (next > bytes_left) {
|
||||
cifs_dbg(VFS, "%s: invalid Next pointer %zu > %zd\n",
|
||||
__func__, next, bytes_left);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
|
||||
bytes_left -= next;
|
||||
}
|
||||
@@ -783,7 +790,9 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
}
|
||||
|
||||
/* Azure rounds the buffer size up 8, to a 16 byte boundary */
|
||||
if ((bytes_left > 8) || p->Next)
|
||||
if ((bytes_left > 8) ||
|
||||
(bytes_left >= offsetof(struct network_interface_info_ioctl_rsp, Next)
|
||||
+ sizeof(p->Next) && p->Next))
|
||||
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
|
||||
|
||||
ses->iface_last_update = jiffies;
|
||||
@@ -4805,7 +4814,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
|
||||
dw->server->ops->is_network_name_deleted(dw->buf,
|
||||
dw->server);
|
||||
|
||||
mid->callback(mid);
|
||||
mid_execute_callback(mid);
|
||||
} else {
|
||||
spin_lock(&dw->server->srv_lock);
|
||||
if (dw->server->tcpStatus == CifsNeedReconnect) {
|
||||
@@ -4813,7 +4822,7 @@ static void smb2_decrypt_offload(struct work_struct *work)
|
||||
mid->mid_state = MID_RETRY_NEEDED;
|
||||
spin_unlock(&dw->server->mid_queue_lock);
|
||||
spin_unlock(&dw->server->srv_lock);
|
||||
mid->callback(mid);
|
||||
mid_execute_callback(mid);
|
||||
} else {
|
||||
spin_lock(&dw->server->mid_queue_lock);
|
||||
mid->mid_state = MID_REQUEST_SUBMITTED;
|
||||
|
||||
@@ -771,6 +771,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr,
|
||||
temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
|
||||
memset(temp, 0, sizeof(struct mid_q_entry));
|
||||
kref_init(&temp->refcount);
|
||||
spin_lock_init(&temp->mid_lock);
|
||||
temp->mid = le64_to_cpu(shdr->MessageId);
|
||||
temp->credits = credits > 0 ? credits : 1;
|
||||
temp->pid = current->pid;
|
||||
|
||||
@@ -1337,10 +1337,6 @@ void smbd_destroy(struct TCP_Server_Info *server)
|
||||
log_rdma_event(INFO, "cancelling idle timer\n");
|
||||
cancel_delayed_work_sync(&info->idle_timer_work);
|
||||
|
||||
log_rdma_event(INFO, "wait for all send posted to IB to finish\n");
|
||||
wait_event(info->wait_send_pending,
|
||||
atomic_read(&info->send_pending) == 0);
|
||||
|
||||
/* It's not possible for upper layer to get to reassembly */
|
||||
log_rdma_event(INFO, "drain the reassembly queue\n");
|
||||
do {
|
||||
@@ -1986,7 +1982,11 @@ int smbd_send(struct TCP_Server_Info *server,
|
||||
*/
|
||||
|
||||
wait_event(info->wait_send_pending,
|
||||
atomic_read(&info->send_pending) == 0);
|
||||
atomic_read(&info->send_pending) == 0 ||
|
||||
sc->status != SMBDIRECT_SOCKET_CONNECTED);
|
||||
|
||||
if (sc->status != SMBDIRECT_SOCKET_CONNECTED && rc == 0)
|
||||
rc = -EAGAIN;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1005,15 +1005,14 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n",
|
||||
midQ[i]->mid, le16_to_cpu(midQ[i]->command));
|
||||
send_cancel(server, &rqst[i], midQ[i]);
|
||||
spin_lock(&server->mid_queue_lock);
|
||||
spin_lock(&midQ[i]->mid_lock);
|
||||
midQ[i]->wait_cancelled = true;
|
||||
if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED ||
|
||||
midQ[i]->mid_state == MID_RESPONSE_RECEIVED) {
|
||||
if (midQ[i]->callback) {
|
||||
midQ[i]->callback = cifs_cancelled_callback;
|
||||
cancelled_mid[i] = true;
|
||||
credits[i].value = 0;
|
||||
}
|
||||
spin_unlock(&server->mid_queue_lock);
|
||||
spin_unlock(&midQ[i]->mid_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user