lkml.org 
[lkml]   [2022]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 2/5] smb3: missing inode locks in zero range
    From
    Date
    smb3 fallocate zero range was not grabbing the inode or filemap_invalidate
    locks so could have race with pagemap reinstantiating the page.

    Cc: stable@vger.kernel.org
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: Steve French <stfrench@microsoft.com>
    ---

    fs/cifs/smb2ops.c | 55 +++++++++++++++++++++++++++++------------------------
    1 file changed, 30 insertions(+), 25 deletions(-)

    diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
    index 7e3de6a0e1dc..1c5a93ced946 100644
    --- a/fs/cifs/smb2ops.c
    +++ b/fs/cifs/smb2ops.c
    @@ -3298,26 +3298,43 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
    return pntsd;
    }

    +static long smb3_zero_data(struct file *file, struct cifs_tcon *tcon,
    + loff_t offset, loff_t len, unsigned int xid)
    +{
    + struct cifsFileInfo *cfile = file->private_data;
    + struct file_zero_data_information fsctl_buf;
    +
    + cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
    +
    + fsctl_buf.FileOffset = cpu_to_le64(offset);
    + fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
    +
    + return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
    + cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
    + (char *)&fsctl_buf,
    + sizeof(struct file_zero_data_information),
    + 0, NULL, NULL);
    +}
    +
    static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
    loff_t offset, loff_t len, bool keep_size)
    {
    struct cifs_ses *ses = tcon->ses;
    - struct inode *inode;
    - struct cifsInodeInfo *cifsi;
    + struct inode *inode = file_inode(file);
    + struct cifsInodeInfo *cifsi = CIFS_I(inode);
    struct cifsFileInfo *cfile = file->private_data;
    - struct file_zero_data_information fsctl_buf;
    long rc;
    unsigned int xid;
    __le64 eof;

    xid = get_xid();

    - inode = d_inode(cfile->dentry);
    - cifsi = CIFS_I(inode);
    -
    trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
    ses->Suid, offset, len);

    + inode_lock(inode);
    + filemap_invalidate_lock(inode->i_mapping);
    +
    /*
    * We zero the range through ioctl, so we need remove the page caches
    * first, otherwise the data may be inconsistent with the server.
    @@ -3325,26 +3342,12 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
    truncate_pagecache_range(inode, offset, offset + len - 1);

    /* if file not oplocked can't be sure whether asking to extend size */
    - if (!CIFS_CACHE_READ(cifsi))
    - if (keep_size == false) {
    - rc = -EOPNOTSUPP;
    - trace_smb3_zero_err(xid, cfile->fid.persistent_fid,
    - tcon->tid, ses->Suid, offset, len, rc);
    - free_xid(xid);
    - return rc;
    - }
    -
    - cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
    -
    - fsctl_buf.FileOffset = cpu_to_le64(offset);
    - fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
    + rc = -EOPNOTSUPP;
    + if (keep_size == false && !CIFS_CACHE_READ(cifsi))
    + goto zero_range_exit;

    - rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
    - cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
    - (char *)&fsctl_buf,
    - sizeof(struct file_zero_data_information),
    - 0, NULL, NULL);
    - if (rc)
    + rc = smb3_zero_data(file, tcon, offset, len, xid);
    + if (rc < 0)
    goto zero_range_exit;

    /*
    @@ -3357,6 +3360,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
    }

    zero_range_exit:
    + filemap_invalidate_unlock(inode->i_mapping);
    + inode_unlock(inode);
    free_xid(xid);
    if (rc)
    trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,

    \
     
     \ /
      Last update: 2022-08-23 18:40    [W:3.331 / U:1.188 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site