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]);
|
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,
|
rc = compound_send_recv(xid, ses, flags, 2, rqst,
|
||||||
resp_buftype, rsp_iov);
|
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)
|
if (rc)
|
||||||
goto oshr_exit;
|
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))
|
(char *)&tcon->crfid.file_all_info))
|
||||||
tcon->crfid.file_all_info_is_valid = 1;
|
tcon->crfid.file_all_info_is_valid = 1;
|
||||||
|
|
||||||
oshr_exit:
|
oshr_exit:
|
||||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
|
oshr_free:
|
||||||
SMB2_open_free(&rqst[0]);
|
SMB2_open_free(&rqst[0]);
|
||||||
SMB2_query_info_free(&rqst[1]);
|
SMB2_query_info_free(&rqst[1]);
|
||||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||||
|
Loading…
Reference in New Issue
Block a user