[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <lsq.1570043211.844466427@decadent.org.uk>
Date: Wed, 02 Oct 2019 20:06:51 +0100
From: Ben Hutchings <ben@...adent.org.uk>
To: linux-kernel@...r.kernel.org, stable@...r.kernel.org
CC: akpm@...ux-foundation.org, Denis Kirjanov <kda@...ux-powerpc.org>,
"Ronnie Sahlberg" <lsahlber@...hat.com>,
"Steve French" <stfrench@...rosoft.com>,
"Pavel Shilovsky" <pshilov@...rosoft.com>
Subject: [PATCH 3.16 58/87] cifs: add spinlock for the openFileList to
cifsInodeInfo
3.16.75-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ronnie Sahlberg <lsahlber@...hat.com>
commit 487317c99477d00f22370625d53be3239febabbe upstream.
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
Signed-off-by: Ronnie Sahlberg <lsahlber@...hat.com>
Signed-off-by: Steve French <stfrench@...rosoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@...rosoft.com>
[bwh: Backported to 3.16: adjust context, indentation]
Signed-off-by: Ben Hutchings <ben@...adent.org.uk>
---
fs/cifs/cifsfs.c | 1 +
fs/cifs/cifsglob.h | 5 +++++
fs/cifs/file.c | 8 ++++++--
3 files changed, 12 insertions(+), 2 deletions(-)
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -260,6 +260,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->uniqueid = 0;
cifs_inode->createtime = 0;
cifs_inode->epoch = 0;
+ spin_lock_init(&cifs_inode->open_file_lock);
#ifdef CONFIG_CIFS_SMB2
generate_random_uuid(cifs_inode->lease_key);
#endif
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1116,6 +1116,7 @@ struct cifsInodeInfo {
struct rw_semaphore lock_sem; /* protect the fields above */
/* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList;
+ spinlock_t open_file_lock; /* protects openFileList */
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
unsigned int oplock; /* oplock/lease level we have */
unsigned int epoch; /* used to track lease state changes */
@@ -1485,10 +1486,14 @@ require use of the stronger protocol */
* 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
+ * inode->open_file_lock protects the openFileList hanging off the inode
* 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
*
+ * Note that the cifs_tcon.open_file_lock should be taken before
+ * not after the cifsInodeInfo.open_file_lock
+ *
* Semaphores
* ----------
* sesSem operations on smb session
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -337,10 +337,12 @@ cifs_new_fileinfo(struct cifs_fid *fid,
list_add(&cfile->tlist, &tcon->openFileList);
/* if readable file instance put first in list*/
+ spin_lock(&cinode->open_file_lock);
if (file->f_mode & FMODE_READ)
list_add(&cfile->flist, &cinode->openFileList);
else
list_add_tail(&cfile->flist, &cinode->openFileList);
+ spin_unlock(&cinode->open_file_lock);
spin_unlock(&tcon->open_file_lock);
if (fid->purge_cache)
@@ -412,7 +414,9 @@ void _cifsFileInfo_put(struct cifsFileIn
cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
/* remove it from the lists */
+ spin_lock(&cifsi->open_file_lock);
list_del(&cifs_file->flist);
+ spin_unlock(&cifsi->open_file_lock);
list_del(&cifs_file->tlist);
if (list_empty(&cifsi->openFileList)) {
@@ -1850,10 +1854,10 @@ refind_writable:
if (!rc)
return inv_file;
else {
- spin_lock(&tcon->open_file_lock);
+ spin_lock(&cifs_inode->open_file_lock);
list_move_tail(&inv_file->flist,
&cifs_inode->openFileList);
- spin_unlock(&tcon->open_file_lock);
+ spin_unlock(&cifs_inode->open_file_lock);
cifsFileInfo_put(inv_file);
++refind;
inv_file = NULL;
Powered by blists - more mailing lists