forked from Minki/linux
CIFS: fix deadlock in cached root handling
Prevent deadlock between open_shroot() and
cifs_mark_open_files_invalid() by releasing the lock before entering
SMB2_open, taking it again after and checking if we still need to use
the result.
Link: https://lore.kernel.org/linux-cifs/684ed01c-cbca-2716-bc28-b0a59a0f8521@prodrive-technologies.com/T/#u
Fixes: 3d4ef9a153
("smb3: fix redundant opens on root")
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
CC: Stable <stable@vger.kernel.org>
This commit is contained in:
parent
ae9b728c8d
commit
7e5a70ad88
@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
/*
|
||||
* We do not hold the lock for the open because in case
|
||||
* SMB2_open needs to reconnect, it will end up calling
|
||||
* cifs_mark_open_files_invalid() which takes the lock again
|
||||
* thus causing a deadlock
|
||||
*/
|
||||
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
rc = compound_send_recv(xid, ses, flags, 2, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
mutex_lock(&tcon->crfid.fid_mutex);
|
||||
|
||||
/*
|
||||
* Now we need to check again as the cached root might have
|
||||
* been successfully re-opened from a concurrent process
|
||||
*/
|
||||
|
||||
if (tcon->crfid.is_valid) {
|
||||
/* work was already done */
|
||||
|
||||
/* stash fids for close() later */
|
||||
struct cifs_fid fid = {
|
||||
.persistent_fid = pfid->persistent_fid,
|
||||
.volatile_fid = pfid->volatile_fid,
|
||||
};
|
||||
|
||||
/*
|
||||
* caller expects this func to set pfid to a valid
|
||||
* cached root, so we copy the existing one and get a
|
||||
* reference.
|
||||
*/
|
||||
memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
|
||||
kref_get(&tcon->crfid.refcount);
|
||||
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
|
||||
if (rc == 0) {
|
||||
/* close extra handle outside of crit sec */
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
}
|
||||
goto oshr_free;
|
||||
}
|
||||
|
||||
/* Cached root is still invalid, continue normaly */
|
||||
|
||||
if (rc)
|
||||
goto oshr_exit;
|
||||
|
||||
@ -729,8 +772,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||
(char *)&tcon->crfid.file_all_info))
|
||||
tcon->crfid.file_all_info_is_valid = 1;
|
||||
|
||||
oshr_exit:
|
||||
oshr_exit:
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
oshr_free:
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
|
Loading…
Reference in New Issue
Block a user