Commit acc07941 authored by Ronnie Sahlberg's avatar Ronnie Sahlberg Committed by Greg Kroah-Hartman

cifs: add spinlock for the openFileList to cifsInodeInfo

[ Upstream commit 487317c9 ]

We can not depend on the tcon->open_file_lock here since in multiuser mode
we may have the same file/inode open via multiple different tcons.

The current code is race prone and will crash if one user deletes a file
at the same time a different user opens/create the file.

To avoid this we need to have a spinlock attached to the inode and not the tcon.

RHBZ:  1580165

CC: Stable <stable@vger.kernel.org>
Signed-off-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 1d064876
...@@ -292,6 +292,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -292,6 +292,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->uniqueid = 0; cifs_inode->uniqueid = 0;
cifs_inode->createtime = 0; cifs_inode->createtime = 0;
cifs_inode->epoch = 0; cifs_inode->epoch = 0;
spin_lock_init(&cifs_inode->open_file_lock);
generate_random_uuid(cifs_inode->lease_key); generate_random_uuid(cifs_inode->lease_key);
/* /*
......
...@@ -1287,6 +1287,7 @@ struct cifsInodeInfo { ...@@ -1287,6 +1287,7 @@ struct cifsInodeInfo {
struct rw_semaphore lock_sem; /* protect the fields above */ struct rw_semaphore lock_sem; /* protect the fields above */
/* BB add in lists for dirty pages i.e. write caching info for oplock */ /* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList; struct list_head openFileList;
spinlock_t open_file_lock; /* protects openFileList */
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
unsigned int oplock; /* oplock/lease level we have */ unsigned int oplock; /* oplock/lease level we have */
unsigned int epoch; /* used to track lease state changes */ unsigned int epoch; /* used to track lease state changes */
...@@ -1687,10 +1688,14 @@ require use of the stronger protocol */ ...@@ -1687,10 +1688,14 @@ require use of the stronger protocol */
* tcp_ses_lock protects: * tcp_ses_lock protects:
* list operations on tcp and SMB session lists * list operations on tcp and SMB session lists
* tcon->open_file_lock protects the list of open files hanging off the tcon * tcon->open_file_lock protects the list of open files hanging off the tcon
* inode->open_file_lock protects the openFileList hanging off the inode
* cfile->file_info_lock protects counters and fields in cifs file struct * 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
* *
* Note that the cifs_tcon.open_file_lock should be taken before
* not after the cifsInodeInfo.open_file_lock
*
* Semaphores * Semaphores
* ---------- * ----------
* sesSem operations on smb session * sesSem operations on smb session
......
...@@ -336,10 +336,12 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, ...@@ -336,10 +336,12 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
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*/
spin_lock(&cinode->open_file_lock);
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(&cinode->open_file_lock);
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
if (fid->purge_cache) if (fid->purge_cache)
...@@ -411,7 +413,9 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler) ...@@ -411,7 +413,9 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
/* remove it from the lists */ /* remove it from the lists */
spin_lock(&cifsi->open_file_lock);
list_del(&cifs_file->flist); list_del(&cifs_file->flist);
spin_unlock(&cifsi->open_file_lock);
list_del(&cifs_file->tlist); list_del(&cifs_file->tlist);
if (list_empty(&cifsi->openFileList)) { if (list_empty(&cifsi->openFileList)) {
...@@ -1929,10 +1933,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1929,10 +1933,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
if (!rc) if (!rc)
return inv_file; return inv_file;
else { else {
spin_lock(&tcon->open_file_lock); spin_lock(&cifs_inode->open_file_lock);
list_move_tail(&inv_file->flist, list_move_tail(&inv_file->flist,
&cifs_inode->openFileList); &cifs_inode->openFileList);
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
cifsFileInfo_put(inv_file); cifsFileInfo_put(inv_file);
++refind; ++refind;
inv_file = NULL; inv_file = NULL;
......
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