CIFS: fix deadlock in cached root handling
commit 7e5a70ad88b1e6f6d9b934b2efb41afff496820f upstream. 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: 3d4ef9a15343 ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
f3160a1d71
commit
e867ef1130
@ -553,7 +553,50 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||
oparams.fid = pfid;
|
||||
oparams.reconnect = false;
|
||||
|
||||
/*
|
||||
* 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 = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL);
|
||||
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 critical section */
|
||||
SMB2_close(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cached root is still invalid, continue normaly */
|
||||
|
||||
if (rc == 0) {
|
||||
memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
|
||||
tcon->crfid.tcon = tcon;
|
||||
@ -561,6 +604,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||
kref_init(&tcon->crfid.refcount);
|
||||
kref_get(&tcon->crfid.refcount);
|
||||
}
|
||||
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user