aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2016-09-22 19:58:16 -0400
committerSteve French <smfrench@gmail.com>2016-10-12 13:08:32 -0400
commit3afca265b5f53a0b15b79531c13858049505582d (patch)
treeac9c7c97ee38fb4c156731643120833c5e53f63c
parentd171356ff11ab1825e456dfb979755e01b3c54a1 (diff)
Clarify locking of cifs file and tcon structures and make more granular
Remove the global file_list_lock to simplify cifs/smb3 locking and have spinlocks that more closely match the information they are protecting. Add new tcon->open_file_lock and file->file_info_lock spinlocks. Locks continue to follow a heirachy, cifs_socket --> cifs_ses --> cifs_tcon --> cifs_file where global tcp_ses_lock still protects socket and cifs_ses, while the the newer locks protect the lower level structure's information (tcon and cifs_file respectively). CC: Stable <stable@vger.kernel.org> Signed-off-by: Steve French <steve.french@primarydata.com> Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Reviewed-by: Germano Percossi <germano.percossi@citrix.com>
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsglob.h30
-rw-r--r--fs/cifs/cifssmb.c4
-rw-r--r--fs/cifs/file.c66
-rw-r--r--fs/cifs/misc.c15
-rw-r--r--fs/cifs/readdir.c6
-rw-r--r--fs/cifs/smb2misc.c16
7 files changed, 75 insertions, 63 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 978dbf049a77..d2b2703fed7d 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1262,7 +1262,6 @@ init_cifs(void)
1262 GlobalTotalActiveXid = 0; 1262 GlobalTotalActiveXid = 0;
1263 GlobalMaxActiveXid = 0; 1263 GlobalMaxActiveXid = 0;
1264 spin_lock_init(&cifs_tcp_ses_lock); 1264 spin_lock_init(&cifs_tcp_ses_lock);
1265 spin_lock_init(&cifs_file_list_lock);
1266 spin_lock_init(&GlobalMid_Lock); 1265 spin_lock_init(&GlobalMid_Lock);
1267 1266
1268 get_random_bytes(&cifs_lock_secret, sizeof(cifs_lock_secret)); 1267 get_random_bytes(&cifs_lock_secret, sizeof(cifs_lock_secret));
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 8f1d8c1e72be..65f78b7a9062 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -833,6 +833,7 @@ struct cifs_tcon {
833 struct list_head tcon_list; 833 struct list_head tcon_list;
834 int tc_count; 834 int tc_count;
835 struct list_head openFileList; 835 struct list_head openFileList;
836 spinlock_t open_file_lock; /* protects list above */
836 struct cifs_ses *ses; /* pointer to session associated with */ 837 struct cifs_ses *ses; /* pointer to session associated with */
837 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ 838 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
838 char *nativeFileSystem; 839 char *nativeFileSystem;
@@ -889,7 +890,7 @@ struct cifs_tcon {
889#endif /* CONFIG_CIFS_STATS2 */ 890#endif /* CONFIG_CIFS_STATS2 */
890 __u64 bytes_read; 891 __u64 bytes_read;
891 __u64 bytes_written; 892 __u64 bytes_written;
892 spinlock_t stat_lock; 893 spinlock_t stat_lock; /* protects the two fields above */
893#endif /* CONFIG_CIFS_STATS */ 894#endif /* CONFIG_CIFS_STATS */
894 FILE_SYSTEM_DEVICE_INFO fsDevInfo; 895 FILE_SYSTEM_DEVICE_INFO fsDevInfo;
895 FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ 896 FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
@@ -1040,8 +1041,10 @@ struct cifs_fid_locks {
1040}; 1041};
1041 1042
1042struct cifsFileInfo { 1043struct cifsFileInfo {
1044 /* following two lists are protected by tcon->open_file_lock */
1043 struct list_head tlist; /* pointer to next fid owned by tcon */ 1045 struct list_head tlist; /* pointer to next fid owned by tcon */
1044 struct list_head flist; /* next fid (file instance) for this inode */ 1046 struct list_head flist; /* next fid (file instance) for this inode */
1047 /* lock list below protected by cifsi->lock_sem */
1045 struct cifs_fid_locks *llist; /* brlocks held by this fid */ 1048 struct cifs_fid_locks *llist; /* brlocks held by this fid */
1046 kuid_t uid; /* allows finding which FileInfo structure */ 1049 kuid_t uid; /* allows finding which FileInfo structure */
1047 __u32 pid; /* process id who opened file */ 1050 __u32 pid; /* process id who opened file */
@@ -1049,11 +1052,12 @@ struct cifsFileInfo {
1049 /* BB add lock scope info here if needed */ ; 1052 /* BB add lock scope info here if needed */ ;
1050 /* lock scope id (0 if none) */ 1053 /* lock scope id (0 if none) */
1051 struct dentry *dentry; 1054 struct dentry *dentry;
1052 unsigned int f_flags;
1053 struct tcon_link *tlink; 1055 struct tcon_link *tlink;
1056 unsigned int f_flags;
1054 bool invalidHandle:1; /* file closed via session abend */ 1057 bool invalidHandle:1; /* file closed via session abend */
1055 bool oplock_break_cancelled:1; 1058 bool oplock_break_cancelled:1;
1056 int count; /* refcount protected by cifs_file_list_lock */ 1059 int count;
1060 spinlock_t file_info_lock; /* protects four flag/count fields above */
1057 struct mutex fh_mutex; /* prevents reopen race after dead ses*/ 1061 struct mutex fh_mutex; /* prevents reopen race after dead ses*/
1058 struct cifs_search_info srch_inf; 1062 struct cifs_search_info srch_inf;
1059 struct work_struct oplock_break; /* work for oplock breaks */ 1063 struct work_struct oplock_break; /* work for oplock breaks */
@@ -1120,7 +1124,7 @@ struct cifs_writedata {
1120 1124
1121/* 1125/*
1122 * Take a reference on the file private data. Must be called with 1126 * Take a reference on the file private data. Must be called with
1123 * cifs_file_list_lock held. 1127 * cfile->file_info_lock held.
1124 */ 1128 */
1125static inline void 1129static inline void
1126cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file) 1130cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
@@ -1514,8 +1518,10 @@ require use of the stronger protocol */
1514 * GlobalMid_Lock protects: 1518 * GlobalMid_Lock protects:
1515 * list operations on pending_mid_q and oplockQ 1519 * list operations on pending_mid_q and oplockQ
1516 * updates to XID counters, multiplex id and SMB sequence numbers 1520 * updates to XID counters, multiplex id and SMB sequence numbers
1517 * cifs_file_list_lock protects: 1521 * tcp_ses_lock protects:
1518 * list operations on tcp and SMB session lists and tCon lists 1522 * list operations on tcp and SMB session lists
1523 * tcon->open_file_lock protects the list of open files hanging off the tcon
1524 * cfile->file_info_lock protects counters and fields in cifs file struct
1519 * f_owner.lock protects certain per file struct operations 1525 * f_owner.lock protects certain per file struct operations
1520 * mapping->page_lock protects certain per page operations 1526 * mapping->page_lock protects certain per page operations
1521 * 1527 *
@@ -1547,18 +1553,12 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
1547 * tcp session, and the list of tcon's per smb session. It also protects 1553 * tcp session, and the list of tcon's per smb session. It also protects
1548 * the reference counters for the server, smb session, and tcon. Finally, 1554 * the reference counters for the server, smb session, and tcon. Finally,
1549 * changes to the tcon->tidStatus should be done while holding this lock. 1555 * changes to the tcon->tidStatus should be done while holding this lock.
1556 * generally the locks should be taken in order tcp_ses_lock before
1557 * tcon->open_file_lock and that before file->file_info_lock since the
1558 * structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file
1550 */ 1559 */
1551GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; 1560GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock;
1552 1561
1553/*
1554 * This lock protects the cifs_file->llist and cifs_file->flist
1555 * list operations, and updates to some flags (cifs_file->invalidHandle)
1556 * It will be moved to either use the tcon->stat_lock or equivalent later.
1557 * If cifs_tcp_ses_lock and the lock below are both needed to be held, then
1558 * the cifs_tcp_ses_lock must be grabbed first and released last.
1559 */
1560GLOBAL_EXTERN spinlock_t cifs_file_list_lock;
1561
1562#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ 1562#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
1563/* Outstanding dir notify requests */ 1563/* Outstanding dir notify requests */
1564GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; 1564GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f82d2823622f..3f3185febc58 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
98 struct list_head *tmp1; 98 struct list_head *tmp1;
99 99
100 /* list all files open on tree connection and mark them invalid */ 100 /* list all files open on tree connection and mark them invalid */
101 spin_lock(&cifs_file_list_lock); 101 spin_lock(&tcon->open_file_lock);
102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) { 102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
103 open_file = list_entry(tmp, struct cifsFileInfo, tlist); 103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
104 open_file->invalidHandle = true; 104 open_file->invalidHandle = true;
105 open_file->oplock_break_cancelled = true; 105 open_file->oplock_break_cancelled = true;
106 } 106 }
107 spin_unlock(&cifs_file_list_lock); 107 spin_unlock(&tcon->open_file_lock);
108 /* 108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted 109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon. 110 * to this tcon.
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index a95fe8b1afe9..ee5ceae22411 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -305,6 +305,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
305 cfile->tlink = cifs_get_tlink(tlink); 305 cfile->tlink = cifs_get_tlink(tlink);
306 INIT_WORK(&cfile->oplock_break, cifs_oplock_break); 306 INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
307 mutex_init(&cfile->fh_mutex); 307 mutex_init(&cfile->fh_mutex);
308 spin_lock_init(&cfile->file_info_lock);
308 309
309 cifs_sb_active(inode->i_sb); 310 cifs_sb_active(inode->i_sb);
310 311
@@ -317,7 +318,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
317 oplock = 0; 318 oplock = 0;
318 } 319 }
319 320
320 spin_lock(&cifs_file_list_lock); 321 spin_lock(&tcon->open_file_lock);
321 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) 322 if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
322 oplock = fid->pending_open->oplock; 323 oplock = fid->pending_open->oplock;
323 list_del(&fid->pending_open->olist); 324 list_del(&fid->pending_open->olist);
@@ -326,12 +327,13 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
326 server->ops->set_fid(cfile, fid, oplock); 327 server->ops->set_fid(cfile, fid, oplock);
327 328
328 list_add(&cfile->tlist, &tcon->openFileList); 329 list_add(&cfile->tlist, &tcon->openFileList);
330
329 /* if readable file instance put first in list*/ 331 /* if readable file instance put first in list*/
330 if (file->f_mode & FMODE_READ) 332 if (file->f_mode & FMODE_READ)
331 list_add(&cfile->flist, &cinode->openFileList); 333 list_add(&cfile->flist, &cinode->openFileList);
332 else 334 else
333 list_add_tail(&cfile->flist, &cinode->openFileList); 335 list_add_tail(&cfile->flist, &cinode->openFileList);
334 spin_unlock(&cifs_file_list_lock); 336 spin_unlock(&tcon->open_file_lock);
335 337
336 if (fid->purge_cache) 338 if (fid->purge_cache)
337 cifs_zap_mapping(inode); 339 cifs_zap_mapping(inode);
@@ -343,16 +345,16 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
343struct cifsFileInfo * 345struct cifsFileInfo *
344cifsFileInfo_get(struct cifsFileInfo *cifs_file) 346cifsFileInfo_get(struct cifsFileInfo *cifs_file)
345{ 347{
346 spin_lock(&cifs_file_list_lock); 348 spin_lock(&cifs_file->file_info_lock);
347 cifsFileInfo_get_locked(cifs_file); 349 cifsFileInfo_get_locked(cifs_file);
348 spin_unlock(&cifs_file_list_lock); 350 spin_unlock(&cifs_file->file_info_lock);
349 return cifs_file; 351 return cifs_file;
350} 352}
351 353
352/* 354/*
353 * Release a reference on the file private data. This may involve closing 355 * Release a reference on the file private data. This may involve closing
354 * the filehandle out on the server. Must be called without holding 356 * the filehandle out on the server. Must be called without holding
355 * cifs_file_list_lock. 357 * tcon->open_file_lock and cifs_file->file_info_lock.
356 */ 358 */
357void cifsFileInfo_put(struct cifsFileInfo *cifs_file) 359void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
358{ 360{
@@ -367,11 +369,15 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
367 struct cifs_pending_open open; 369 struct cifs_pending_open open;
368 bool oplock_break_cancelled; 370 bool oplock_break_cancelled;
369 371
370 spin_lock(&cifs_file_list_lock); 372 spin_lock(&tcon->open_file_lock);
373
374 spin_lock(&cifs_file->file_info_lock);
371 if (--cifs_file->count > 0) { 375 if (--cifs_file->count > 0) {
372 spin_unlock(&cifs_file_list_lock); 376 spin_unlock(&cifs_file->file_info_lock);
377 spin_unlock(&tcon->open_file_lock);
373 return; 378 return;
374 } 379 }
380 spin_unlock(&cifs_file->file_info_lock);
375 381
376 if (server->ops->get_lease_key) 382 if (server->ops->get_lease_key)
377 server->ops->get_lease_key(inode, &fid); 383 server->ops->get_lease_key(inode, &fid);
@@ -395,7 +401,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
395 set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags); 401 set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
396 cifs_set_oplock_level(cifsi, 0); 402 cifs_set_oplock_level(cifsi, 0);
397 } 403 }
398 spin_unlock(&cifs_file_list_lock); 404
405 spin_unlock(&tcon->open_file_lock);
399 406
400 oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break); 407 oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
401 408
@@ -772,10 +779,10 @@ int cifs_closedir(struct inode *inode, struct file *file)
772 server = tcon->ses->server; 779 server = tcon->ses->server;
773 780
774 cifs_dbg(FYI, "Freeing private data in close dir\n"); 781 cifs_dbg(FYI, "Freeing private data in close dir\n");
775 spin_lock(&cifs_file_list_lock); 782 spin_lock(&cfile->file_info_lock);
776 if (server->ops->dir_needs_close(cfile)) { 783 if (server->ops->dir_needs_close(cfile)) {
777 cfile->invalidHandle = true; 784 cfile->invalidHandle = true;
778 spin_unlock(&cifs_file_list_lock); 785 spin_unlock(&cfile->file_info_lock);
779 if (server->ops->close_dir) 786 if (server->ops->close_dir)
780 rc = server->ops->close_dir(xid, tcon, &cfile->fid); 787 rc = server->ops->close_dir(xid, tcon, &cfile->fid);
781 else 788 else
@@ -784,7 +791,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
784 /* not much we can do if it fails anyway, ignore rc */ 791 /* not much we can do if it fails anyway, ignore rc */
785 rc = 0; 792 rc = 0;
786 } else 793 } else
787 spin_unlock(&cifs_file_list_lock); 794 spin_unlock(&cfile->file_info_lock);
788 795
789 buf = cfile->srch_inf.ntwrk_buf_start; 796 buf = cfile->srch_inf.ntwrk_buf_start;
790 if (buf) { 797 if (buf) {
@@ -1728,12 +1735,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1728{ 1735{
1729 struct cifsFileInfo *open_file = NULL; 1736 struct cifsFileInfo *open_file = NULL;
1730 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 1737 struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1738 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1731 1739
1732 /* only filter by fsuid on multiuser mounts */ 1740 /* only filter by fsuid on multiuser mounts */
1733 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 1741 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1734 fsuid_only = false; 1742 fsuid_only = false;
1735 1743
1736 spin_lock(&cifs_file_list_lock); 1744 spin_lock(&tcon->open_file_lock);
1737 /* we could simply get the first_list_entry since write-only entries 1745 /* we could simply get the first_list_entry since write-only entries
1738 are always at the end of the list but since the first entry might 1746 are always at the end of the list but since the first entry might
1739 have a close pending, we go through the whole list */ 1747 have a close pending, we go through the whole list */
@@ -1744,8 +1752,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1744 if (!open_file->invalidHandle) { 1752 if (!open_file->invalidHandle) {
1745 /* found a good file */ 1753 /* found a good file */
1746 /* lock it so it will not be closed on us */ 1754 /* lock it so it will not be closed on us */
1747 cifsFileInfo_get_locked(open_file); 1755 cifsFileInfo_get(open_file);
1748 spin_unlock(&cifs_file_list_lock); 1756 spin_unlock(&tcon->open_file_lock);
1749 return open_file; 1757 return open_file;
1750 } /* else might as well continue, and look for 1758 } /* else might as well continue, and look for
1751 another, or simply have the caller reopen it 1759 another, or simply have the caller reopen it
@@ -1753,7 +1761,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
1753 } else /* write only file */ 1761 } else /* write only file */
1754 break; /* write only files are last so must be done */ 1762 break; /* write only files are last so must be done */
1755 } 1763 }
1756 spin_unlock(&cifs_file_list_lock); 1764 spin_unlock(&tcon->open_file_lock);
1757 return NULL; 1765 return NULL;
1758} 1766}
1759 1767
@@ -1762,6 +1770,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1762{ 1770{
1763 struct cifsFileInfo *open_file, *inv_file = NULL; 1771 struct cifsFileInfo *open_file, *inv_file = NULL;
1764 struct cifs_sb_info *cifs_sb; 1772 struct cifs_sb_info *cifs_sb;
1773 struct cifs_tcon *tcon;
1765 bool any_available = false; 1774 bool any_available = false;
1766 int rc; 1775 int rc;
1767 unsigned int refind = 0; 1776 unsigned int refind = 0;
@@ -1777,15 +1786,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
1777 } 1786 }
1778 1787
1779 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 1788 cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
1789 tcon = cifs_sb_master_tcon(cifs_sb);
1780 1790
1781 /* only filter by fsuid on multiuser mounts */ 1791 /* only filter by fsuid on multiuser mounts */
1782 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 1792 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
1783 fsuid_only = false; 1793 fsuid_only = false;
1784 1794
1785 spin_lock(&cifs_file_list_lock); 1795 spin_lock(&tcon->open_file_lock);
1786refind_writable: 1796refind_writable:
1787 if (refind > MAX_REOPEN_ATT) { 1797 if (refind > MAX_REOPEN_ATT) {
1788 spin_unlock(&cifs_file_list_lock); 1798 spin_unlock(&tcon->open_file_lock);
1789 return NULL; 1799 return NULL;
1790 } 1800 }
1791 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 1801 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
@@ -1796,8 +1806,8 @@ refind_writable:
1796 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 1806 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
1797 if (!open_file->invalidHandle) { 1807 if (!open_file->invalidHandle) {
1798 /* found a good writable file */ 1808 /* found a good writable file */
1799 cifsFileInfo_get_locked(open_file); 1809 cifsFileInfo_get(open_file);
1800 spin_unlock(&cifs_file_list_lock); 1810 spin_unlock(&tcon->open_file_lock);
1801 return open_file; 1811 return open_file;
1802 } else { 1812 } else {
1803 if (!inv_file) 1813 if (!inv_file)
@@ -1813,24 +1823,24 @@ refind_writable:
1813 1823
1814 if (inv_file) { 1824 if (inv_file) {
1815 any_available = false; 1825 any_available = false;
1816 cifsFileInfo_get_locked(inv_file); 1826 cifsFileInfo_get(inv_file);
1817 } 1827 }
1818 1828
1819 spin_unlock(&cifs_file_list_lock); 1829 spin_unlock(&tcon->open_file_lock);
1820 1830
1821 if (inv_file) { 1831 if (inv_file) {
1822 rc = cifs_reopen_file(inv_file, false); 1832 rc = cifs_reopen_file(inv_file, false);
1823 if (!rc) 1833 if (!rc)
1824 return inv_file; 1834 return inv_file;
1825 else { 1835 else {
1826 spin_lock(&cifs_file_list_lock); 1836 spin_lock(&tcon->open_file_lock);
1827 list_move_tail(&inv_file->flist, 1837 list_move_tail(&inv_file->flist,
1828 &cifs_inode->openFileList); 1838 &cifs_inode->openFileList);
1829 spin_unlock(&cifs_file_list_lock); 1839 spin_unlock(&tcon->open_file_lock);
1830 cifsFileInfo_put(inv_file); 1840 cifsFileInfo_put(inv_file);
1831 spin_lock(&cifs_file_list_lock);
1832 ++refind; 1841 ++refind;
1833 inv_file = NULL; 1842 inv_file = NULL;
1843 spin_lock(&tcon->open_file_lock);
1834 goto refind_writable; 1844 goto refind_writable;
1835 } 1845 }
1836 } 1846 }
@@ -3612,15 +3622,17 @@ static int cifs_readpage(struct file *file, struct page *page)
3612static int is_inode_writable(struct cifsInodeInfo *cifs_inode) 3622static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
3613{ 3623{
3614 struct cifsFileInfo *open_file; 3624 struct cifsFileInfo *open_file;
3625 struct cifs_tcon *tcon =
3626 cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
3615 3627
3616 spin_lock(&cifs_file_list_lock); 3628 spin_lock(&tcon->open_file_lock);
3617 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 3629 list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
3618 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 3630 if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
3619 spin_unlock(&cifs_file_list_lock); 3631 spin_unlock(&tcon->open_file_lock);
3620 return 1; 3632 return 1;
3621 } 3633 }
3622 } 3634 }
3623 spin_unlock(&cifs_file_list_lock); 3635 spin_unlock(&tcon->open_file_lock);
3624 return 0; 3636 return 0;
3625} 3637}
3626 3638
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 813fe13c2ae1..c6729156f9a0 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -120,6 +120,7 @@ tconInfoAlloc(void)
120 ++ret_buf->tc_count; 120 ++ret_buf->tc_count;
121 INIT_LIST_HEAD(&ret_buf->openFileList); 121 INIT_LIST_HEAD(&ret_buf->openFileList);
122 INIT_LIST_HEAD(&ret_buf->tcon_list); 122 INIT_LIST_HEAD(&ret_buf->tcon_list);
123 spin_lock_init(&ret_buf->open_file_lock);
123#ifdef CONFIG_CIFS_STATS 124#ifdef CONFIG_CIFS_STATS
124 spin_lock_init(&ret_buf->stat_lock); 125 spin_lock_init(&ret_buf->stat_lock);
125#endif 126#endif
@@ -465,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
465 continue; 466 continue;
466 467
467 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); 468 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
468 spin_lock(&cifs_file_list_lock); 469 spin_lock(&tcon->open_file_lock);
469 list_for_each(tmp2, &tcon->openFileList) { 470 list_for_each(tmp2, &tcon->openFileList) {
470 netfile = list_entry(tmp2, struct cifsFileInfo, 471 netfile = list_entry(tmp2, struct cifsFileInfo,
471 tlist); 472 tlist);
@@ -495,11 +496,11 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
495 &netfile->oplock_break); 496 &netfile->oplock_break);
496 netfile->oplock_break_cancelled = false; 497 netfile->oplock_break_cancelled = false;
497 498
498 spin_unlock(&cifs_file_list_lock); 499 spin_unlock(&tcon->open_file_lock);
499 spin_unlock(&cifs_tcp_ses_lock); 500 spin_unlock(&cifs_tcp_ses_lock);
500 return true; 501 return true;
501 } 502 }
502 spin_unlock(&cifs_file_list_lock); 503 spin_unlock(&tcon->open_file_lock);
503 spin_unlock(&cifs_tcp_ses_lock); 504 spin_unlock(&cifs_tcp_ses_lock);
504 cifs_dbg(FYI, "No matching file for oplock break\n"); 505 cifs_dbg(FYI, "No matching file for oplock break\n");
505 return true; 506 return true;
@@ -613,9 +614,9 @@ backup_cred(struct cifs_sb_info *cifs_sb)
613void 614void
614cifs_del_pending_open(struct cifs_pending_open *open) 615cifs_del_pending_open(struct cifs_pending_open *open)
615{ 616{
616 spin_lock(&cifs_file_list_lock); 617 spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
617 list_del(&open->olist); 618 list_del(&open->olist);
618 spin_unlock(&cifs_file_list_lock); 619 spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
619} 620}
620 621
621void 622void
@@ -635,7 +636,7 @@ void
635cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink, 636cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
636 struct cifs_pending_open *open) 637 struct cifs_pending_open *open)
637{ 638{
638 spin_lock(&cifs_file_list_lock); 639 spin_lock(&tlink_tcon(tlink)->open_file_lock);
639 cifs_add_pending_open_locked(fid, tlink, open); 640 cifs_add_pending_open_locked(fid, tlink, open);
640 spin_unlock(&cifs_file_list_lock); 641 spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
641} 642}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 65cf85dcda09..8f6a2a5863b9 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -597,14 +597,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
597 is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { 597 is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
598 /* close and restart search */ 598 /* close and restart search */
599 cifs_dbg(FYI, "search backing up - close and restart search\n"); 599 cifs_dbg(FYI, "search backing up - close and restart search\n");
600 spin_lock(&cifs_file_list_lock); 600 spin_lock(&cfile->file_info_lock);
601 if (server->ops->dir_needs_close(cfile)) { 601 if (server->ops->dir_needs_close(cfile)) {
602 cfile->invalidHandle = true; 602 cfile->invalidHandle = true;
603 spin_unlock(&cifs_file_list_lock); 603 spin_unlock(&cfile->file_info_lock);
604 if (server->ops->close_dir) 604 if (server->ops->close_dir)
605 server->ops->close_dir(xid, tcon, &cfile->fid); 605 server->ops->close_dir(xid, tcon, &cfile->fid);
606 } else 606 } else
607 spin_unlock(&cifs_file_list_lock); 607 spin_unlock(&cfile->file_info_lock);
608 if (cfile->srch_inf.ntwrk_buf_start) { 608 if (cfile->srch_inf.ntwrk_buf_start) {
609 cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n"); 609 cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n");
610 if (cfile->srch_inf.smallBuf) 610 if (cfile->srch_inf.smallBuf)
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 389fb9f8c84e..3d383489b9cf 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -549,19 +549,19 @@ smb2_is_valid_lease_break(char *buffer)
549 list_for_each(tmp1, &server->smb_ses_list) { 549 list_for_each(tmp1, &server->smb_ses_list) {
550 ses = list_entry(tmp1, struct cifs_ses, smb_ses_list); 550 ses = list_entry(tmp1, struct cifs_ses, smb_ses_list);
551 551
552 spin_lock(&cifs_file_list_lock);
553 list_for_each(tmp2, &ses->tcon_list) { 552 list_for_each(tmp2, &ses->tcon_list) {
554 tcon = list_entry(tmp2, struct cifs_tcon, 553 tcon = list_entry(tmp2, struct cifs_tcon,
555 tcon_list); 554 tcon_list);
555 spin_lock(&tcon->open_file_lock);
556 cifs_stats_inc( 556 cifs_stats_inc(
557 &tcon->stats.cifs_stats.num_oplock_brks); 557 &tcon->stats.cifs_stats.num_oplock_brks);
558 if (smb2_tcon_has_lease(tcon, rsp, lw)) { 558 if (smb2_tcon_has_lease(tcon, rsp, lw)) {
559 spin_unlock(&cifs_file_list_lock); 559 spin_unlock(&tcon->open_file_lock);
560 spin_unlock(&cifs_tcp_ses_lock); 560 spin_unlock(&cifs_tcp_ses_lock);
561 return true; 561 return true;
562 } 562 }
563 spin_unlock(&tcon->open_file_lock);
563 } 564 }
564 spin_unlock(&cifs_file_list_lock);
565 } 565 }
566 } 566 }
567 spin_unlock(&cifs_tcp_ses_lock); 567 spin_unlock(&cifs_tcp_ses_lock);
@@ -603,7 +603,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
603 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); 603 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
604 604
605 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); 605 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
606 spin_lock(&cifs_file_list_lock); 606 spin_lock(&tcon->open_file_lock);
607 list_for_each(tmp2, &tcon->openFileList) { 607 list_for_each(tmp2, &tcon->openFileList) {
608 cfile = list_entry(tmp2, struct cifsFileInfo, 608 cfile = list_entry(tmp2, struct cifsFileInfo,
609 tlist); 609 tlist);
@@ -615,7 +615,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
615 615
616 cifs_dbg(FYI, "file id match, oplock break\n"); 616 cifs_dbg(FYI, "file id match, oplock break\n");
617 cinode = CIFS_I(d_inode(cfile->dentry)); 617 cinode = CIFS_I(d_inode(cfile->dentry));
618 618 spin_lock(&cfile->file_info_lock);
619 if (!CIFS_CACHE_WRITE(cinode) && 619 if (!CIFS_CACHE_WRITE(cinode) &&
620 rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE) 620 rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
621 cfile->oplock_break_cancelled = true; 621 cfile->oplock_break_cancelled = true;
@@ -637,14 +637,14 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
637 clear_bit( 637 clear_bit(
638 CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, 638 CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
639 &cinode->flags); 639 &cinode->flags);
640 640 spin_unlock(&cfile->file_info_lock);
641 queue_work(cifsiod_wq, &cfile->oplock_break); 641 queue_work(cifsiod_wq, &cfile->oplock_break);
642 642
643 spin_unlock(&cifs_file_list_lock); 643 spin_unlock(&tcon->open_file_lock);
644 spin_unlock(&cifs_tcp_ses_lock); 644 spin_unlock(&cifs_tcp_ses_lock);
645 return true; 645 return true;
646 } 646 }
647 spin_unlock(&cifs_file_list_lock); 647 spin_unlock(&tcon->open_file_lock);
648 spin_unlock(&cifs_tcp_ses_lock); 648 spin_unlock(&cifs_tcp_ses_lock);
649 cifs_dbg(FYI, "No matching file for oplock break\n"); 649 cifs_dbg(FYI, "No matching file for oplock break\n");
650 return true; 650 return true;