@@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
694
694
695
695
smb2_set_related (& rqst [1 ]);
696
696
697
+ /*
698
+ * We do not hold the lock for the open because in case
699
+ * SMB2_open needs to reconnect, it will end up calling
700
+ * cifs_mark_open_files_invalid() which takes the lock again
701
+ * thus causing a deadlock
702
+ */
703
+
704
+ mutex_unlock (& tcon -> crfid .fid_mutex );
697
705
rc = compound_send_recv (xid , ses , flags , 2 , rqst ,
698
706
resp_buftype , rsp_iov );
707
+ mutex_lock (& tcon -> crfid .fid_mutex );
708
+
709
+ /*
710
+ * Now we need to check again as the cached root might have
711
+ * been successfully re-opened from a concurrent process
712
+ */
713
+
714
+ if (tcon -> crfid .is_valid ) {
715
+ /* work was already done */
716
+
717
+ /* stash fids for close() later */
718
+ struct cifs_fid fid = {
719
+ .persistent_fid = pfid -> persistent_fid ,
720
+ .volatile_fid = pfid -> volatile_fid ,
721
+ };
722
+
723
+ /*
724
+ * caller expects this func to set pfid to a valid
725
+ * cached root, so we copy the existing one and get a
726
+ * reference.
727
+ */
728
+ memcpy (pfid , tcon -> crfid .fid , sizeof (* pfid ));
729
+ kref_get (& tcon -> crfid .refcount );
730
+
731
+ mutex_unlock (& tcon -> crfid .fid_mutex );
732
+
733
+ if (rc == 0 ) {
734
+ /* close extra handle outside of crit sec */
735
+ SMB2_close (xid , tcon , fid .persistent_fid , fid .volatile_fid );
736
+ }
737
+ goto oshr_free ;
738
+ }
739
+
740
+ /* Cached root is still invalid, continue normaly */
741
+
699
742
if (rc )
700
743
goto oshr_exit ;
701
744
@@ -729,8 +772,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
729
772
(char * )& tcon -> crfid .file_all_info ))
730
773
tcon -> crfid .file_all_info_is_valid = 1 ;
731
774
732
- oshr_exit :
775
+ oshr_exit :
733
776
mutex_unlock (& tcon -> crfid .fid_mutex );
777
+ oshr_free :
734
778
SMB2_open_free (& rqst [0 ]);
735
779
SMB2_query_info_free (& rqst [1 ]);
736
780
free_rsp_buf (resp_buftype [0 ], rsp_iov [0 ].iov_base );
0 commit comments