Commit 1bf70c7c authored by Steve French's avatar Steve French Committed by Luis Henriques

Clarify locking of cifs file and tcon structures and make more granular

BugLink: http://bugs.launchpad.net/bugs/1637510

commit 3afca265 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).
Signed-off-by: default avatarSteve French <steve.french@primarydata.com>
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: default avatarAurelien Aptel <aaptel@suse.com>
Reviewed-by: default avatarGermano Percossi <germano.percossi@citrix.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
parent 16745282
...@@ -1206,7 +1206,6 @@ init_cifs(void) ...@@ -1206,7 +1206,6 @@ init_cifs(void)
GlobalTotalActiveXid = 0; GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0; GlobalMaxActiveXid = 0;
spin_lock_init(&cifs_tcp_ses_lock); spin_lock_init(&cifs_tcp_ses_lock);
spin_lock_init(&cifs_file_list_lock);
spin_lock_init(&GlobalMid_Lock); spin_lock_init(&GlobalMid_Lock);
if (cifs_max_pending < 2) { if (cifs_max_pending < 2) {
......
...@@ -827,6 +827,7 @@ struct cifs_tcon { ...@@ -827,6 +827,7 @@ struct cifs_tcon {
struct list_head tcon_list; struct list_head tcon_list;
int tc_count; int tc_count;
struct list_head openFileList; struct list_head openFileList;
spinlock_t open_file_lock; /* protects list above */
struct cifs_ses *ses; /* pointer to session associated with */ struct cifs_ses *ses; /* pointer to session associated with */
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
char *nativeFileSystem; char *nativeFileSystem;
...@@ -883,7 +884,7 @@ struct cifs_tcon { ...@@ -883,7 +884,7 @@ struct cifs_tcon {
#endif /* CONFIG_CIFS_STATS2 */ #endif /* CONFIG_CIFS_STATS2 */
__u64 bytes_read; __u64 bytes_read;
__u64 bytes_written; __u64 bytes_written;
spinlock_t stat_lock; spinlock_t stat_lock; /* protects the two fields above */
#endif /* CONFIG_CIFS_STATS */ #endif /* CONFIG_CIFS_STATS */
FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_DEVICE_INFO fsDevInfo;
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */
...@@ -1034,8 +1035,10 @@ struct cifs_fid_locks { ...@@ -1034,8 +1035,10 @@ struct cifs_fid_locks {
}; };
struct cifsFileInfo { 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 tlist; /* pointer to next fid owned by tcon */
struct list_head flist; /* next fid (file instance) for this inode */ 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 */ struct cifs_fid_locks *llist; /* brlocks held by this fid */
kuid_t uid; /* allows finding which FileInfo structure */ kuid_t uid; /* allows finding which FileInfo structure */
__u32 pid; /* process id who opened file */ __u32 pid; /* process id who opened file */
...@@ -1043,11 +1046,12 @@ struct cifsFileInfo { ...@@ -1043,11 +1046,12 @@ struct cifsFileInfo {
/* BB add lock scope info here if needed */ ; /* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */ /* lock scope id (0 if none) */
struct dentry *dentry; struct dentry *dentry;
unsigned int f_flags;
struct tcon_link *tlink; struct tcon_link *tlink;
unsigned int f_flags;
bool invalidHandle:1; /* file closed via session abend */ bool invalidHandle:1; /* file closed via session abend */
bool oplock_break_cancelled:1; 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 mutex fh_mutex; /* prevents reopen race after dead ses*/
struct cifs_search_info srch_inf; struct cifs_search_info srch_inf;
struct work_struct oplock_break; /* work for oplock breaks */ struct work_struct oplock_break; /* work for oplock breaks */
...@@ -1114,7 +1118,7 @@ struct cifs_writedata { ...@@ -1114,7 +1118,7 @@ struct cifs_writedata {
/* /*
* Take a reference on the file private data. Must be called with * 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 static inline void
cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file) cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
...@@ -1508,8 +1512,10 @@ require use of the stronger protocol */ ...@@ -1508,8 +1512,10 @@ require use of the stronger protocol */
* GlobalMid_Lock protects: * GlobalMid_Lock protects:
* list operations on pending_mid_q and oplockQ * list operations on pending_mid_q and oplockQ
* updates to XID counters, multiplex id and SMB sequence numbers * updates to XID counters, multiplex id and SMB sequence numbers
* cifs_file_list_lock protects: * tcp_ses_lock protects:
* list operations on tcp and SMB session lists and tCon lists * 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 * f_owner.lock protects certain per file struct operations
* mapping->page_lock protects certain per page operations * mapping->page_lock protects certain per page operations
* *
...@@ -1541,18 +1547,12 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; ...@@ -1541,18 +1547,12 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
* tcp session, and the list of tcon's per smb session. It also protects * 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, * the reference counters for the server, smb session, and tcon. Finally,
* changes to the tcon->tidStatus should be done while holding this lock. * 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; 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 */ #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */
/* Outstanding dir notify requests */ /* Outstanding dir notify requests */
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
......
...@@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) ...@@ -98,13 +98,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
struct list_head *tmp1; struct list_head *tmp1;
/* list all files open on tree connection and mark them invalid */ /* 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) { list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
open_file = list_entry(tmp, struct cifsFileInfo, tlist); open_file = list_entry(tmp, struct cifsFileInfo, tlist);
open_file->invalidHandle = true; open_file->invalidHandle = true;
open_file->oplock_break_cancelled = 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 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
* to this tcon. * to this tcon.
......
...@@ -305,6 +305,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -305,6 +305,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
cfile->tlink = cifs_get_tlink(tlink); cfile->tlink = cifs_get_tlink(tlink);
INIT_WORK(&cfile->oplock_break, cifs_oplock_break); INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
mutex_init(&cfile->fh_mutex); mutex_init(&cfile->fh_mutex);
spin_lock_init(&cfile->file_info_lock);
cifs_sb_active(inode->i_sb); cifs_sb_active(inode->i_sb);
...@@ -317,7 +318,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -317,7 +318,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
oplock = 0; oplock = 0;
} }
spin_lock(&cifs_file_list_lock); spin_lock(&tcon->open_file_lock);
if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
oplock = fid->pending_open->oplock; oplock = fid->pending_open->oplock;
list_del(&fid->pending_open->olist); list_del(&fid->pending_open->olist);
...@@ -326,12 +327,13 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -326,12 +327,13 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
server->ops->set_fid(cfile, fid, oplock); server->ops->set_fid(cfile, fid, oplock);
list_add(&cfile->tlist, &tcon->openFileList); list_add(&cfile->tlist, &tcon->openFileList);
/* if readable file instance put first in list*/ /* if readable file instance put first in list*/
if (file->f_mode & FMODE_READ) if (file->f_mode & FMODE_READ)
list_add(&cfile->flist, &cinode->openFileList); list_add(&cfile->flist, &cinode->openFileList);
else else
list_add_tail(&cfile->flist, &cinode->openFileList); list_add_tail(&cfile->flist, &cinode->openFileList);
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
if (fid->purge_cache) if (fid->purge_cache)
cifs_zap_mapping(inode); cifs_zap_mapping(inode);
...@@ -343,16 +345,16 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -343,16 +345,16 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
struct cifsFileInfo * struct cifsFileInfo *
cifsFileInfo_get(struct cifsFileInfo *cifs_file) cifsFileInfo_get(struct cifsFileInfo *cifs_file)
{ {
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file->file_info_lock);
cifsFileInfo_get_locked(cifs_file); cifsFileInfo_get_locked(cifs_file);
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file->file_info_lock);
return cifs_file; return cifs_file;
} }
/* /*
* Release a reference on the file private data. This may involve closing * Release a reference on the file private data. This may involve closing
* the filehandle out on the server. Must be called without holding * the filehandle out on the server. Must be called without holding
* cifs_file_list_lock. * tcon->open_file_lock and cifs_file->file_info_lock.
*/ */
void cifsFileInfo_put(struct cifsFileInfo *cifs_file) void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{ {
...@@ -367,11 +369,15 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -367,11 +369,15 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
struct cifs_pending_open open; struct cifs_pending_open open;
bool oplock_break_cancelled; bool oplock_break_cancelled;
spin_lock(&cifs_file_list_lock); spin_lock(&tcon->open_file_lock);
spin_lock(&cifs_file->file_info_lock);
if (--cifs_file->count > 0) { if (--cifs_file->count > 0) {
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file->file_info_lock);
spin_unlock(&tcon->open_file_lock);
return; return;
} }
spin_unlock(&cifs_file->file_info_lock);
if (server->ops->get_lease_key) if (server->ops->get_lease_key)
server->ops->get_lease_key(inode, &fid); server->ops->get_lease_key(inode, &fid);
...@@ -395,7 +401,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) ...@@ -395,7 +401,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags); set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags);
cifs_set_oplock_level(cifsi, 0); cifs_set_oplock_level(cifsi, 0);
} }
spin_unlock(&cifs_file_list_lock);
spin_unlock(&tcon->open_file_lock);
oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break); oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
...@@ -772,10 +779,10 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -772,10 +779,10 @@ int cifs_closedir(struct inode *inode, struct file *file)
server = tcon->ses->server; server = tcon->ses->server;
cifs_dbg(FYI, "Freeing private data in close dir\n"); cifs_dbg(FYI, "Freeing private data in close dir\n");
spin_lock(&cifs_file_list_lock); spin_lock(&cfile->file_info_lock);
if (server->ops->dir_needs_close(cfile)) { if (server->ops->dir_needs_close(cfile)) {
cfile->invalidHandle = true; cfile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock); spin_unlock(&cfile->file_info_lock);
if (server->ops->close_dir) if (server->ops->close_dir)
rc = server->ops->close_dir(xid, tcon, &cfile->fid); rc = server->ops->close_dir(xid, tcon, &cfile->fid);
else else
...@@ -784,7 +791,7 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -784,7 +791,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
/* not much we can do if it fails anyway, ignore rc */ /* not much we can do if it fails anyway, ignore rc */
rc = 0; rc = 0;
} else } else
spin_unlock(&cifs_file_list_lock); spin_unlock(&cfile->file_info_lock);
buf = cfile->srch_inf.ntwrk_buf_start; buf = cfile->srch_inf.ntwrk_buf_start;
if (buf) { if (buf) {
...@@ -1720,12 +1727,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1720,12 +1727,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
{ {
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
/* only filter by fsuid on multiuser mounts */ /* only filter by fsuid on multiuser mounts */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
fsuid_only = false; fsuid_only = false;
spin_lock(&cifs_file_list_lock); spin_lock(&tcon->open_file_lock);
/* we could simply get the first_list_entry since write-only entries /* we could simply get the first_list_entry since write-only entries
are always at the end of the list but since the first entry might are always at the end of the list but since the first entry might
have a close pending, we go through the whole list */ have a close pending, we go through the whole list */
...@@ -1736,8 +1744,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1736,8 +1744,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
if (!open_file->invalidHandle) { if (!open_file->invalidHandle) {
/* found a good file */ /* found a good file */
/* lock it so it will not be closed on us */ /* lock it so it will not be closed on us */
cifsFileInfo_get_locked(open_file); cifsFileInfo_get(open_file);
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
return open_file; return open_file;
} /* else might as well continue, and look for } /* else might as well continue, and look for
another, or simply have the caller reopen it another, or simply have the caller reopen it
...@@ -1745,7 +1753,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1745,7 +1753,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
} else /* write only file */ } else /* write only file */
break; /* write only files are last so must be done */ break; /* write only files are last so must be done */
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
return NULL; return NULL;
} }
...@@ -1754,6 +1762,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1754,6 +1762,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
{ {
struct cifsFileInfo *open_file, *inv_file = NULL; struct cifsFileInfo *open_file, *inv_file = NULL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
bool any_available = false; bool any_available = false;
int rc; int rc;
unsigned int refind = 0; unsigned int refind = 0;
...@@ -1769,15 +1778,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1769,15 +1778,16 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
} }
cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
tcon = cifs_sb_master_tcon(cifs_sb);
/* only filter by fsuid on multiuser mounts */ /* only filter by fsuid on multiuser mounts */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
fsuid_only = false; fsuid_only = false;
spin_lock(&cifs_file_list_lock); spin_lock(&tcon->open_file_lock);
refind_writable: refind_writable:
if (refind > MAX_REOPEN_ATT) { if (refind > MAX_REOPEN_ATT) {
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
return NULL; return NULL;
} }
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
...@@ -1788,8 +1798,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1788,8 +1798,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
if (!open_file->invalidHandle) { if (!open_file->invalidHandle) {
/* found a good writable file */ /* found a good writable file */
cifsFileInfo_get_locked(open_file); cifsFileInfo_get(open_file);
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
return open_file; return open_file;
} else { } else {
if (!inv_file) if (!inv_file)
...@@ -1805,24 +1815,24 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1805,24 +1815,24 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
if (inv_file) { if (inv_file) {
any_available = false; any_available = false;
cifsFileInfo_get_locked(inv_file); cifsFileInfo_get(inv_file);
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
if (inv_file) { if (inv_file) {
rc = cifs_reopen_file(inv_file, false); rc = cifs_reopen_file(inv_file, false);
if (!rc) if (!rc)
return inv_file; return inv_file;
else { else {
spin_lock(&cifs_file_list_lock); spin_lock(&tcon->open_file_lock);
list_move_tail(&inv_file->flist, list_move_tail(&inv_file->flist,
&cifs_inode->openFileList); &cifs_inode->openFileList);
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
cifsFileInfo_put(inv_file); cifsFileInfo_put(inv_file);
spin_lock(&cifs_file_list_lock);
++refind; ++refind;
inv_file = NULL; inv_file = NULL;
spin_lock(&tcon->open_file_lock);
goto refind_writable; goto refind_writable;
} }
} }
...@@ -3632,15 +3642,17 @@ static int cifs_readpage(struct file *file, struct page *page) ...@@ -3632,15 +3642,17 @@ static int cifs_readpage(struct file *file, struct page *page)
static int is_inode_writable(struct cifsInodeInfo *cifs_inode) static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
{ {
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifs_tcon *tcon =
cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
spin_lock(&cifs_file_list_lock); spin_lock(&tcon->open_file_lock);
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
return 1; return 1;
} }
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
return 0; return 0;
} }
......
...@@ -120,6 +120,7 @@ tconInfoAlloc(void) ...@@ -120,6 +120,7 @@ tconInfoAlloc(void)
++ret_buf->tc_count; ++ret_buf->tc_count;
INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->openFileList);
INIT_LIST_HEAD(&ret_buf->tcon_list); INIT_LIST_HEAD(&ret_buf->tcon_list);
spin_lock_init(&ret_buf->open_file_lock);
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
spin_lock_init(&ret_buf->stat_lock); spin_lock_init(&ret_buf->stat_lock);
#endif #endif
...@@ -465,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) ...@@ -465,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
continue; continue;
cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); 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) { list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp2, struct cifsFileInfo, netfile = list_entry(tmp2, struct cifsFileInfo,
tlist); tlist);
...@@ -495,11 +496,11 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) ...@@ -495,11 +496,11 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
&netfile->oplock_break); &netfile->oplock_break);
netfile->oplock_break_cancelled = false; netfile->oplock_break_cancelled = false;
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return true; return true;
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "No matching file for oplock break\n"); cifs_dbg(FYI, "No matching file for oplock break\n");
return true; return true;
...@@ -613,9 +614,9 @@ backup_cred(struct cifs_sb_info *cifs_sb) ...@@ -613,9 +614,9 @@ backup_cred(struct cifs_sb_info *cifs_sb)
void void
cifs_del_pending_open(struct cifs_pending_open *open) 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); list_del(&open->olist);
spin_unlock(&cifs_file_list_lock); spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
} }
void void
...@@ -635,7 +636,7 @@ void ...@@ -635,7 +636,7 @@ void
cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink, cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
struct cifs_pending_open *open) 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); cifs_add_pending_open_locked(fid, tlink, open);
spin_unlock(&cifs_file_list_lock); spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
} }
...@@ -594,14 +594,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, ...@@ -594,14 +594,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
/* close and restart search */ /* close and restart search */
cifs_dbg(FYI, "search backing up - close and restart search\n"); 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)) { if (server->ops->dir_needs_close(cfile)) {
cfile->invalidHandle = true; cfile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock); spin_unlock(&cfile->file_info_lock);
if (server->ops->close_dir) if (server->ops->close_dir)
server->ops->close_dir(xid, tcon, &cfile->fid); server->ops->close_dir(xid, tcon, &cfile->fid);
} else } else
spin_unlock(&cifs_file_list_lock); spin_unlock(&cfile->file_info_lock);
if (cfile->srch_inf.ntwrk_buf_start) { if (cfile->srch_inf.ntwrk_buf_start) {
cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n"); cifs_dbg(FYI, "freeing SMB ff cache buf on search rewind\n");
if (cfile->srch_inf.smallBuf) if (cfile->srch_inf.smallBuf)
......
...@@ -525,19 +525,19 @@ smb2_is_valid_lease_break(char *buffer) ...@@ -525,19 +525,19 @@ smb2_is_valid_lease_break(char *buffer)
list_for_each(tmp1, &server->smb_ses_list) { list_for_each(tmp1, &server->smb_ses_list) {
ses = list_entry(tmp1, struct cifs_ses, 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) { list_for_each(tmp2, &ses->tcon_list) {
tcon = list_entry(tmp2, struct cifs_tcon, tcon = list_entry(tmp2, struct cifs_tcon,
tcon_list); tcon_list);
spin_lock(&tcon->open_file_lock);
cifs_stats_inc( cifs_stats_inc(
&tcon->stats.cifs_stats.num_oplock_brks); &tcon->stats.cifs_stats.num_oplock_brks);
if (smb2_tcon_has_lease(tcon, rsp, lw)) { 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); spin_unlock(&cifs_tcp_ses_lock);
return true; return true;
} }
spin_unlock(&tcon->open_file_lock);
} }
spin_unlock(&cifs_file_list_lock);
} }
} }
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
...@@ -579,7 +579,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -579,7 +579,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); 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) { list_for_each(tmp2, &tcon->openFileList) {
cfile = list_entry(tmp2, struct cifsFileInfo, cfile = list_entry(tmp2, struct cifsFileInfo,
tlist); tlist);
...@@ -591,7 +591,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -591,7 +591,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
cifs_dbg(FYI, "file id match, oplock break\n"); cifs_dbg(FYI, "file id match, oplock break\n");
cinode = CIFS_I(d_inode(cfile->dentry)); cinode = CIFS_I(d_inode(cfile->dentry));
spin_lock(&cfile->file_info_lock);
if (!CIFS_CACHE_WRITE(cinode) && if (!CIFS_CACHE_WRITE(cinode) &&
rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE) rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
cfile->oplock_break_cancelled = true; cfile->oplock_break_cancelled = true;
...@@ -613,14 +613,14 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) ...@@ -613,14 +613,14 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
clear_bit( clear_bit(
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
&cinode->flags); &cinode->flags);
spin_unlock(&cfile->file_info_lock);
queue_work(cifsiod_wq, &cfile->oplock_break); 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); spin_unlock(&cifs_tcp_ses_lock);
return true; return true;
} }
spin_unlock(&cifs_file_list_lock); spin_unlock(&tcon->open_file_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
cifs_dbg(FYI, "No matching file for oplock break\n"); cifs_dbg(FYI, "No matching file for oplock break\n");
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment