Patch "Clarify locking of cifs file and tcon structures and make more granular" has been added to the 4.8-stable tree
This is a note to let you know that I've just added the patch titled
Clarify locking of cifs file and tcon structures and make more granular
to the 4.8-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
clarify-locking-of-cifs-file-and-tcon-structures-and-make-more-granular.patch
and it can be found in the queue-4.8 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
3afca265b5f53a0b15b79531c13858049505582dMon Sep 17 00:00:00 2001
From: Steve French <[email protected]>
Date: Thu, 22 Sep 2016 18:58:16 -0500
Subject: Clarify locking of cifs file and tcon structures and make more granular
From: Steve French <[email protected]>
commit 3afca265b5f53a0b15b79531c13858049505582d upstream.
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).
--- fs/cifs/cifsfs.c | 1 fs/cifs/cifsglob.h | 30 ++++++++++++------------ fs/cifs/cifssmb.c | 4 +-- fs/cifs/file.c | 66 +++++++++++++++++++++++++++++++---------------------- fs/cifs/misc.c | 15 ++++++------ fs/cifs/readdir.c | 6 ++-- fs/cifs/smb2misc.c | 16 ++++++------ 7 files changed, 75 insertions(+), 63 deletions(-)
fs/cifs/cifsfs.c +0 -1
@@ -1271,7 +1271,6 @@ init_cifs(void) GlobalTotalActiveXid =0 ; GlobalMaxActiveXid =0 ;spin_lock_init (&cifs_tcp_ses_lock); -spin_lock_init (&cifs_file_list_lock);spin_lock_init (&GlobalMid_Lock);get_random_bytes (&cifs_lock_secret,sizeof (cifs_lock_secret));
fs/cifs/cifsglob.h +15 -15
@@ -833,6 +833,7 @@ struct cifs_tcon {struct list_head tcon_list;int tc_count;struct list_head openFileList; +spinlock_t open_file_lock;/* protects list above */ struct cifs_ses *ses;/* pointer to session associated with */ char treeName[MAX_TREE_SIZE +1 ];/* UNC name of resource in ASCII */ char *nativeFileSystem;
@@ -889,7 +890,7 @@ struct cifs_tcon {#endif /* CONFIG_CIFS_STATS2 */ __u64 bytes_read;__u64 bytes_written; -spinlock_t stat_lock; +spinlock_t stat_lock;/* protects the two fields above */ #endif /* CONFIG_CIFS_STATS */ FILE_SYSTEM_DEVICE_INFO fsDevInfo;FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;/* ok if fs name truncated */
@@ -1040,8 +1041,10 @@ struct cifs_fid_locks { };struct cifsFileInfo { +/* following two lists are protected by tcon->open_file_lock */ struct list_head tlist;/* pointer to next fid owned by tcon */ struct list_head flist;/* next fid (file instance) for this inode */ +/* lock list below protected by cifsi->lock_sem */ struct cifs_fid_locks *llist;/* brlocks held by this fid */ kuid_t uid;/* allows finding which FileInfo structure */ __u32 pid;/* process id who opened file */
@@ -1049,11 +1052,12 @@ struct cifsFileInfo {/* BB add lock scope info here if needed */ ;/* lock scope id (0 if none) */ struct dentry *dentry; -unsigned int f_flags;struct tcon_link *tlink; +unsigned int f_flags; bool invalidHandle:1; /* file closed via session abend */ bool oplock_break_cancelled:1; -int count;/* refcount protected by cifs_file_list_lock */ +int count; +spinlock_t file_info_lock;/* protects four flag/count fields above */ struct mutex fh_mutex;/* prevents reopen race after dead ses*/ struct cifs_search_info srch_inf;struct work_struct oplock_break;/* work for oplock breaks */
@@ -1120,7 +1124,7 @@ struct cifs_writedata {/* * Take a reference on the file private data. Must be called with -* cifs_file_list_lock held. +* cfile->file_info_lock held. */ static inline void cifsFileInfo_get_locked (struct cifsFileInfo *cifs_file)
@@ -1514,8 +1518,10 @@ require use of the stronger protocol */* GlobalMid_Lock protects: * list operations on pending_mid_q and oplockQ * updates to XID counters, multiplex id and SMB sequence numbers -* cifs_file_list_lock protects: -* list operations on tcp and SMB session lists and tCon lists +* tcp_ses_lock protects: +* list operations on tcp and SMB session lists +* tcon->open_file_lock protects the list of open files hanging off the tcon +* cfile->file_info_lock protects counters and fields in cifs file struct * f_owner.lock protects certain per file struct operations * mapping->page_lock protects certain per page operations *
@@ -1547,18 +1553,12 @@ GLOBAL_EXTERN struct list_head cifs_tcp* tcp session, and the list of tcon's per smb session. It also protects * the reference counters for the server, smb session, and tcon. Finally, * changes to the tcon->tidStatus should be done while holding this lock. +* generally the locks should be taken in order tcp_ses_lock before +* tcon->open_file_lock and that before file->file_info_lock since the +* structure order is cifs_socket-->cifs_ses-->cifs_tcon-->cifs_file */ GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; -/* -* This lock protects the cifs_file->llist and cifs_file->flist -* list operations, and updates to some flags (cifs_file->invalidHandle) -* It will be moved to either use the tcon->stat_lock or equivalent later. -* If cifs_tcp_ses_lock and the lock below are both needed to be held, then -* the cifs_tcp_ses_lock must be grabbed first and released last. -*/ -GLOBAL_EXTERN spinlock_t cifs_file_list_lock; -#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ /* Outstanding dir notify requests */ GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
fs/cifs/cifssmb.c +2 -2
@@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifsstruct list_head *tmp1;/* list all files open on tree connection and mark them invalid */ -spin_lock (&cifs_file_list_lock); +spin_lock (&tcon->open_file_lock);list_for_each_safe (tmp, tmp1, &tcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file->invalidHandle = true; open_file->oplock_break_cancelled = true; } -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tcon->open_file_lock);/* * BB Add call to invalidate_inodes(sb) for all superblocks mounted * to this tcon.
fs/cifs/file.c +39 -27
210 lines not on this page · raw message
fs/cifs/misc.c +8 -7
@@ -120,6 +120,7 @@ tconInfoAlloc(void) ++ret_buf->tc_count;INIT_LIST_HEAD (&ret_buf->openFileList);INIT_LIST_HEAD (&ret_buf->tcon_list); +spin_lock_init (&ret_buf->open_file_lock);#ifdef CONFIG_CIFS_STATS spin_lock_init (&ret_buf->stat_lock);#endif
@@ -465,7 +466,7 @@ is_valid_oplock_break(char *buffer, strucontinue ;cifs_stats_inc (&tcon->stats.cifs_stats.num_oplock_brks); -spin_lock (&cifs_file_list_lock); +spin_lock (&tcon->open_file_lock);list_for_each (tmp2, &tcon->openFileList) { netfile = list_entry(tmp2, struct cifsFileInfo, tlist);
@@ -495,11 +496,11 @@ is_valid_oplock_break(char *buffer, stru &netfile->oplock_break); netfile->oplock_break_cancelled = false; -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tcon->open_file_lock);spin_unlock (&cifs_tcp_ses_lock);return true; } -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tcon->open_file_lock);spin_unlock (&cifs_tcp_ses_lock);cifs_dbg (FYI ,"No matching file for oplock break\n" );return true;
@@ -613,9 +614,9 @@ backup_cred(struct cifs_sb_info *cifs_sbvoid cifs_del_pending_open (struct cifs_pending_open *open) { -spin_lock (&cifs_file_list_lock); +spin_lock (&tlink_tcon (open->tlink)->open_file_lock);list_del (&open->olist); -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tlink_tcon (open->tlink)->open_file_lock); }void
@@ -635,7 +636,7 @@ void cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink, struct cifs_pending_open *open) { - spin_lock(&cifs_file_list_lock); + spin_lock(&tlink_tcon(tlink)->open_file_lock);cifs_add_pending_open_locked (fid, tlink, open); -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tlink_tcon (open->tlink)->open_file_lock); }
fs/cifs/readdir.c +3 -3
@@ -597,14 +597,14 @@ find_cifs_entry(const unsigned int xid, is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {/* close and restart search */ cifs_dbg (FYI ,"search backing up - close and restart search\n" ); -spin_lock (&cifs_file_list_lock); +spin_lock (&cfile->file_info_lock);if (server->ops->dir_needs_close (cfile)) { cfile->invalidHandle = true; -spin_unlock (&cifs_file_list_lock); +spin_unlock (&cfile->file_info_lock);if (server->ops->close_dir) server->ops->close_dir (xid, tcon, &cfile->fid); }else -spin_unlock (&cifs_file_list_lock); +spin_unlock (&cfile->file_info_lock);if (cfile->srch_inf.ntwrk_buf_start) {cifs_dbg (FYI ,"freeing SMB ff cache buf on search rewind\n" );if (cfile->srch_inf.smallBuf)
fs/cifs/smb2misc.c +8 -8
@@ -549,19 +549,19 @@ smb2_is_valid_lease_break(char *buffer)list_for_each (tmp1, &server->smb_ses_list) { ses = list_entry(tmp1, struct cifs_ses, smb_ses_list); -spin_lock (&cifs_file_list_lock);list_for_each (tmp2, &ses->tcon_list) { tcon = list_entry(tmp2, struct cifs_tcon, tcon_list); +spin_lock (&tcon->open_file_lock);cifs_stats_inc ( &tcon->stats.cifs_stats.num_oplock_brks);if (smb2_tcon_has_lease (tcon, rsp, lw)) { -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tcon->open_file_lock);spin_unlock (&cifs_tcp_ses_lock);return true; } +spin_unlock (&tcon->open_file_lock); } -spin_unlock (&cifs_file_list_lock); } }spin_unlock (&cifs_tcp_ses_lock);
@@ -603,7 +603,7 @@ smb2_is_valid_oplock_break(char *buffer, tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);cifs_stats_inc (&tcon->stats.cifs_stats.num_oplock_brks); -spin_lock (&cifs_file_list_lock); +spin_lock (&tcon->open_file_lock);list_for_each (tmp2, &tcon->openFileList) { cfile = list_entry(tmp2, struct cifsFileInfo, tlist);
@@ -615,7 +615,7 @@ smb2_is_valid_oplock_break(char *buffer,cifs_dbg (FYI ,"file id match, oplock break\n" ); cinode =CIFS_I (d_inode (cfile->dentry)); - +spin_lock (&cfile->file_info_lock);if (!CIFS_CACHE_WRITE (cinode) && rsp->OplockLevel ==SMB2_OPLOCK_LEVEL_NONE ) cfile->oplock_break_cancelled = true;
@@ -637,14 +637,14 @@ smb2_is_valid_oplock_break(char *buffer,clear_bit (CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2 , &cinode->flags); - +spin_unlock (&cfile->file_info_lock);queue_work (cifsiod_wq, &cfile->oplock_break); -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tcon->open_file_lock);spin_unlock (&cifs_tcp_ses_lock);return true; } -spin_unlock (&cifs_file_list_lock); +spin_unlock (&tcon->open_file_lock);spin_unlock (&cifs_tcp_ses_lock);cifs_dbg (FYI ,"No matching file for oplock break\n" );return true;
Patches currently in stable-queue which might be from [email protected] are
queue-4.8/fix-regression-which-breaks-dfs-mounting.patch queue-4.8/cleanup-missing-frees-on-some-ioctls.patch queue-4.8/smb3-guids-should-be-constructed-as-random-but-valid-uuids.patch queue-4.8/clarify-locking-of-cifs-file-and-tcon-structures-and-make-more-granular.patch queue-4.8/do-not-send-smb3-set_info-request-if-nothing-is-changing.patch queue-4.8/set-previous-session-id-correctly-on-smb3-reconnect.patch queue-4.8/cifs-limit-the-overall-credit-acquired.patch queue-4.8/fs-cifs-keep-guid-when-assigning-fid-to-fileinfo.patch queue-4.8/display-number-of-credits-available.patch