lkml.org 
[lkml]   [2019]   [Sep]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.19 119/167] cifs: add spinlock for the openFileList to cifsInodeInfo
    Date
    From: Ronnie Sahlberg <lsahlber@redhat.com>

    [ Upstream commit 487317c99477d00f22370625d53be3239febabbe ]

    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: Ronnie Sahlberg <lsahlber@redhat.com>
    Signed-off-by: Steve French <stfrench@microsoft.com>
    Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/cifs/cifsfs.c | 1 +
    fs/cifs/cifsglob.h | 5 +++++
    fs/cifs/file.c | 8 ++++++--
    3 files changed, 12 insertions(+), 2 deletions(-)

    diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
    index fb32f3d6925e8..64e3888f30e6d 100644
    --- a/fs/cifs/cifsfs.c
    +++ b/fs/cifs/cifsfs.c
    @@ -292,6 +292,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);
    generate_random_uuid(cifs_inode->lease_key);

    /*
    diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
    index 0ee0072c1f362..57af9bac0045a 100644
    --- a/fs/cifs/cifsglob.h
    +++ b/fs/cifs/cifsglob.h
    @@ -1287,6 +1287,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 */
    @@ -1687,10 +1688,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
    diff --git a/fs/cifs/file.c b/fs/cifs/file.c
    index 933013543edab..8703b5f26f452 100644
    --- a/fs/cifs/file.c
    +++ b/fs/cifs/file.c
    @@ -336,10 +336,12 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
    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)
    @@ -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);

    /* 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)) {
    @@ -1929,10 +1933,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
    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;
    --
    2.20.1
    \
     
     \ /
      Last update: 2019-09-03 18:31    [W:4.244 / U:1.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site