1. 25 2月, 2020 1 次提交
    • A
      cifs: fix rename() by ensuring source handle opened with DELETE bit · 86f740f2
      Aurelien Aptel 提交于
      To rename a file in SMB2 we open it with the DELETE access and do a
      special SetInfo on it. If the handle is missing the DELETE bit the
      server will fail the SetInfo with STATUS_ACCESS_DENIED.
      
      We currently try to reuse any existing opened handle we have with
      cifs_get_writable_path(). That function looks for handles with WRITE
      access but doesn't check for DELETE, making rename() fail if it finds
      a handle to reuse. Simple reproducer below.
      
      To select handles with the DELETE bit, this patch adds a flag argument
      to cifs_get_writable_path() and find_writable_file() and the existing
      'bool fsuid_only' argument is converted to a flag.
      
      The cifsFileInfo struct only stores the UNIX open mode but not the
      original SMB access flags. Since the DELETE bit is not mapped in that
      mode, this patch stores the access mask in cifs_fid on file open,
      which is accessible from cifsFileInfo.
      
      Simple reproducer:
      
      	#include <stdio.h>
      	#include <stdlib.h>
      	#include <sys/types.h>
      	#include <sys/stat.h>
      	#include <fcntl.h>
      	#include <unistd.h>
      	#define E(s) perror(s), exit(1)
      
      	int main(int argc, char *argv[])
      	{
      		int fd, ret;
      		if (argc != 3) {
      			fprintf(stderr, "Usage: %s A B\n"
      			"create&open A in write mode, "
      			"rename A to B, close A\n", argv[0]);
      			return 0;
      		}
      
      		fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
      		if (fd == -1) E("openat()");
      
      		ret = rename(argv[1], argv[2]);
      		if (ret) E("rename()");
      
      		ret = close(fd);
      		if (ret) E("close()");
      
      		return ret;
      	}
      
      $ gcc -o bugrename bugrename.c
      $ ./bugrename /mnt/a /mnt/b
      rename(): Permission denied
      
      Fixes: 8de9e86c ("cifs: create a helper to find a writeable handle by path name")
      CC: Stable <stable@vger.kernel.org>
      Signed-off-by: NAurelien Aptel <aaptel@suse.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      Reviewed-by: NPavel Shilovsky <pshilov@microsoft.com>
      Reviewed-by: NPaulo Alcantara (SUSE) <pc@cjr.nz>
      86f740f2
  2. 06 2月, 2020 1 次提交
    • S
      cifs: add SMB3 change notification support · d26c2ddd
      Steve French 提交于
      A commonly used SMB3 feature is change notification, allowing an
      app to be notified about changes to a directory. The SMB3
      Notify request blocks until the server detects a change to that
      directory or its contents that matches the completion flags
      that were passed in and the "watch_tree" flag (which indicates
      whether subdirectories under this directory should be also
      included).  See MS-SMB2 2.2.35 for additional detail.
      
      To use this simply pass in the following structure to ioctl:
      
       struct __attribute__((__packed__)) smb3_notify {
              uint32_t completion_filter;
              bool    watch_tree;
       } __packed;
      
       using CIFS_IOC_NOTIFY  0x4005cf09
       or equivalently _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify)
      
      SMB3 change notification is supported by all major servers.
      The ioctl will block until the server detects a change to that
      directory or its subdirectories (if watch_tree is set).
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      Reviewed-by: NAurelien Aptel <aaptel@suse.com>
      Acked-by: NPaulo Alcantara (SUSE) <pc@cjr.nz>
      d26c2ddd
  3. 04 2月, 2020 1 次提交
  4. 27 1月, 2020 1 次提交
    • V
      CIFS: Fix task struct use-after-free on reconnect · f1f27ad7
      Vincent Whitchurch 提交于
      The task which created the MID may be gone by the time cifsd attempts to
      call the callbacks on MIDs from cifs_reconnect().
      
      This leads to a use-after-free of the task struct in cifs_wake_up_task:
      
       ==================================================================
       BUG: KASAN: use-after-free in __lock_acquire+0x31a0/0x3270
       Read of size 8 at addr ffff8880103e3a68 by task cifsd/630
      
       CPU: 0 PID: 630 Comm: cifsd Not tainted 5.5.0-rc6+ #119
       Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
       Call Trace:
        dump_stack+0x8e/0xcb
        print_address_description.constprop.5+0x1d3/0x3c0
        ? __lock_acquire+0x31a0/0x3270
        __kasan_report+0x152/0x1aa
        ? __lock_acquire+0x31a0/0x3270
        ? __lock_acquire+0x31a0/0x3270
        kasan_report+0xe/0x20
        __lock_acquire+0x31a0/0x3270
        ? __wake_up_common+0x1dc/0x630
        ? _raw_spin_unlock_irqrestore+0x4c/0x60
        ? mark_held_locks+0xf0/0xf0
        ? _raw_spin_unlock_irqrestore+0x39/0x60
        ? __wake_up_common_lock+0xd5/0x130
        ? __wake_up_common+0x630/0x630
        lock_acquire+0x13f/0x330
        ? try_to_wake_up+0xa3/0x19e0
        _raw_spin_lock_irqsave+0x38/0x50
        ? try_to_wake_up+0xa3/0x19e0
        try_to_wake_up+0xa3/0x19e0
        ? cifs_compound_callback+0x178/0x210
        ? set_cpus_allowed_ptr+0x10/0x10
        cifs_reconnect+0xa1c/0x15d0
        ? generic_ip_connect+0x1860/0x1860
        ? rwlock_bug.part.0+0x90/0x90
        cifs_readv_from_socket+0x479/0x690
        cifs_read_from_socket+0x9d/0xe0
        ? cifs_readv_from_socket+0x690/0x690
        ? mempool_resize+0x690/0x690
        ? rwlock_bug.part.0+0x90/0x90
        ? memset+0x1f/0x40
        ? allocate_buffers+0xff/0x340
        cifs_demultiplex_thread+0x388/0x2a50
        ? cifs_handle_standard+0x610/0x610
        ? rcu_read_lock_held_common+0x120/0x120
        ? mark_lock+0x11b/0xc00
        ? __lock_acquire+0x14ed/0x3270
        ? __kthread_parkme+0x78/0x100
        ? lockdep_hardirqs_on+0x3e8/0x560
        ? lock_downgrade+0x6a0/0x6a0
        ? lockdep_hardirqs_on+0x3e8/0x560
        ? _raw_spin_unlock_irqrestore+0x39/0x60
        ? cifs_handle_standard+0x610/0x610
        kthread+0x2bb/0x3a0
        ? kthread_create_worker_on_cpu+0xc0/0xc0
        ret_from_fork+0x3a/0x50
      
       Allocated by task 649:
        save_stack+0x19/0x70
        __kasan_kmalloc.constprop.5+0xa6/0xf0
        kmem_cache_alloc+0x107/0x320
        copy_process+0x17bc/0x5370
        _do_fork+0x103/0xbf0
        __x64_sys_clone+0x168/0x1e0
        do_syscall_64+0x9b/0xec0
        entry_SYSCALL_64_after_hwframe+0x49/0xbe
      
       Freed by task 0:
        save_stack+0x19/0x70
        __kasan_slab_free+0x11d/0x160
        kmem_cache_free+0xb5/0x3d0
        rcu_core+0x52f/0x1230
        __do_softirq+0x24d/0x962
      
       The buggy address belongs to the object at ffff8880103e32c0
        which belongs to the cache task_struct of size 6016
       The buggy address is located 1960 bytes inside of
        6016-byte region [ffff8880103e32c0, ffff8880103e4a40)
       The buggy address belongs to the page:
       page:ffffea000040f800 refcount:1 mapcount:0 mapping:ffff8880108da5c0
       index:0xffff8880103e4c00 compound_mapcount: 0
       raw: 4000000000010200 ffffea00001f2208 ffffea00001e3408 ffff8880108da5c0
       raw: ffff8880103e4c00 0000000000050003 00000001ffffffff 0000000000000000
       page dumped because: kasan: bad access detected
      
       Memory state around the buggy address:
        ffff8880103e3900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
        ffff8880103e3980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
       >ffff8880103e3a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                                                 ^
        ffff8880103e3a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
        ffff8880103e3b00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
       ==================================================================
      
      This can be reliably reproduced by adding the below delay to
      cifs_reconnect(), running find(1) on the mount, restarting the samba
      server while find is running, and killing find during the delay:
      
        	spin_unlock(&GlobalMid_Lock);
        	mutex_unlock(&server->srv_mutex);
      
       +	msleep(10000);
       +
        	cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
        	list_for_each_safe(tmp, tmp2, &retry_list) {
        		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
      
      Fix this by holding a reference to the task struct until the MID is
      freed.
      Signed-off-by: NVincent Whitchurch <vincent.whitchurch@axis.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      CC: Stable <stable@vger.kernel.org>
      Reviewed-by: NPaulo Alcantara (SUSE) <pc@cjr.nz>
      Reviewed-by: NPavel Shilovsky <pshilov@microsoft.com>
      f1f27ad7
  5. 23 12月, 2019 1 次提交
  6. 13 12月, 2019 1 次提交
  7. 05 12月, 2019 1 次提交
  8. 04 12月, 2019 1 次提交
    • S
      smb3: query attributes on file close · 43f8a6a7
      Steve French 提交于
      Since timestamps on files on most servers can be updated at
      close, and since timestamps on our dentries default to one
      second we can have stale timestamps in some common cases
      (e.g. open, write, close, stat, wait one second, stat - will
      show different mtime for the first and second stat).
      
      The SMB2/SMB3 protocol allows querying timestamps at close
      so add the code to request timestamp and attr information
      (which is cheap for the server to provide) to be returned
      when a file is closed (it is not needed for the many
      paths that call SMB2_close that are from compounded
      query infos and close nor is it needed for some of
      the cases where a directory close immediately follows a
      directory open.
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      Acked-by: NRonnie Sahlberg <lsahlber@redhat.com>
      Reviewed-by: NAurelien Aptel <aaptel@suse.com>
      Reviewed-by: NPavel Shilovsky <pshilov@microsoft.com>
      43f8a6a7
  9. 25 11月, 2019 10 次提交
    • S
      smb3: dump in_send and num_waiters stats counters by default · 1ae9a5a5
      Steve French 提交于
      Number of requests in_send and the number of waiters on sendRecv
      are useful counters in various cases, move them from
      CONFIG_CIFS_STATS2 to be on by default especially with multichannel
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      Acked-by: NRonnie Sahlberg <lsahlber@redhat.com>
      1ae9a5a5
    • P
      CIFS: Properly process SMB3 lease breaks · 9bd45408
      Pavel Shilovsky 提交于
      Currenly we doesn't assume that a server may break a lease
      from RWH to RW which causes us setting a wrong lease state
      on a file and thus mistakenly flushing data and byte-range
      locks and purging cached data on the client. This leads to
      performance degradation because subsequent IOs go directly
      to the server.
      
      Fix this by propagating new lease state and epoch values
      to the oplock break handler through cifsFileInfo structure
      and removing the use of cifsInodeInfo flags for that. It
      allows to avoid some races of several lease/oplock breaks
      using those flags in parallel.
      Signed-off-by: NPavel Shilovsky <pshilov@microsoft.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      9bd45408
    • R
      cifs: move cifsFileInfo_put logic into a work-queue · 32546a95
      Ronnie Sahlberg 提交于
      This patch moves the final part of the cifsFileInfo_put() logic where we
      need a write lock on lock_sem to be processed in a separate thread that
      holds no other locks.
      This is to prevent deadlocks like the one below:
      
      > there are 6 processes looping to while trying to down_write
      > cinode->lock_sem, 5 of them from _cifsFileInfo_put, and one from
      > cifs_new_fileinfo
      >
      > and there are 5 other processes which are blocked, several of them
      > waiting on either PG_writeback or PG_locked (which are both set), all
      > for the same page of the file
      >
      > 2 inode_lock() (inode->i_rwsem) for the file
      > 1 wait_on_page_writeback() for the page
      > 1 down_read(inode->i_rwsem) for the inode of the directory
      > 1 inode_lock()(inode->i_rwsem) for the inode of the directory
      > 1 __lock_page
      >
      >
      > so processes are blocked waiting on:
      >   page flags PG_locked and PG_writeback for one specific page
      >   inode->i_rwsem for the directory
      >   inode->i_rwsem for the file
      >   cifsInodeInflock_sem
      >
      >
      >
      > here are the more gory details (let me know if I need to provide
      > anything more/better):
      >
      > [0 00:48:22.765] [UN]  PID: 8863   TASK: ffff8c691547c5c0  CPU: 3
      > COMMAND: "reopen_file"
      >  #0 [ffff9965007e3ba8] __schedule at ffffffff9b6e6095
      >  #1 [ffff9965007e3c38] schedule at ffffffff9b6e64df
      >  #2 [ffff9965007e3c48] rwsem_down_write_slowpath at ffffffff9af283d7
      >  #3 [ffff9965007e3cb8] legitimize_path at ffffffff9b0f975d
      >  #4 [ffff9965007e3d08] path_openat at ffffffff9b0fe55d
      >  #5 [ffff9965007e3dd8] do_filp_open at ffffffff9b100a33
      >  #6 [ffff9965007e3ee0] do_sys_open at ffffffff9b0eb2d6
      >  #7 [ffff9965007e3f38] do_syscall_64 at ffffffff9ae04315
      > * (I think legitimize_path is bogus)
      >
      > in path_openat
      >         } else {
      >                 const char *s = path_init(nd, flags);
      >                 while (!(error = link_path_walk(s, nd)) &&
      >                         (error = do_last(nd, file, op)) > 0) {  <<<<
      >
      > do_last:
      >         if (open_flag & O_CREAT)
      >                 inode_lock(dir->d_inode);  <<<<
      >         else
      > so it's trying to take inode->i_rwsem for the directory
      >
      >      DENTRY           INODE           SUPERBLK     TYPE PATH
      > ffff8c68bb8e79c0 ffff8c691158ef20 ffff8c6915bf9000 DIR  /mnt/vm1_smb/
      > inode.i_rwsem is ffff8c691158efc0
      >
      > <struct rw_semaphore 0xffff8c691158efc0>:
      >         owner: <struct task_struct 0xffff8c6914275d00> (UN -   8856 -
      > reopen_file), counter: 0x0000000000000003
      >         waitlist: 2
      >         0xffff9965007e3c90     8863   reopen_file      UN 0  1:29:22.926
      >   RWSEM_WAITING_FOR_WRITE
      >         0xffff996500393e00     9802   ls               UN 0  1:17:26.700
      >   RWSEM_WAITING_FOR_READ
      >
      >
      > the owner of the inode.i_rwsem of the directory is:
      >
      > [0 00:00:00.109] [UN]  PID: 8856   TASK: ffff8c6914275d00  CPU: 3
      > COMMAND: "reopen_file"
      >  #0 [ffff99650065b828] __schedule at ffffffff9b6e6095
      >  #1 [ffff99650065b8b8] schedule at ffffffff9b6e64df
      >  #2 [ffff99650065b8c8] schedule_timeout at ffffffff9b6e9f89
      >  #3 [ffff99650065b940] msleep at ffffffff9af573a9
      >  #4 [ffff99650065b948] _cifsFileInfo_put.cold.63 at ffffffffc0a42dd6 [cifs]
      >  #5 [ffff99650065ba38] cifs_writepage_locked at ffffffffc0a0b8f3 [cifs]
      >  #6 [ffff99650065bab0] cifs_launder_page at ffffffffc0a0bb72 [cifs]
      >  #7 [ffff99650065bb30] invalidate_inode_pages2_range at ffffffff9b04d4bd
      >  #8 [ffff99650065bcb8] cifs_invalidate_mapping at ffffffffc0a11339 [cifs]
      >  #9 [ffff99650065bcd0] cifs_revalidate_mapping at ffffffffc0a1139a [cifs]
      > #10 [ffff99650065bcf0] cifs_d_revalidate at ffffffffc0a014f6 [cifs]
      > #11 [ffff99650065bd08] path_openat at ffffffff9b0fe7f7
      > #12 [ffff99650065bdd8] do_filp_open at ffffffff9b100a33
      > #13 [ffff99650065bee0] do_sys_open at ffffffff9b0eb2d6
      > #14 [ffff99650065bf38] do_syscall_64 at ffffffff9ae04315
      >
      > cifs_launder_page is for page 0xffffd1e2c07d2480
      >
      > crash> page.index,mapping,flags 0xffffd1e2c07d2480
      >       index = 0x8
      >       mapping = 0xffff8c68f3cd0db0
      >   flags = 0xfffffc0008095
      >
      >   PAGE-FLAG       BIT  VALUE
      >   PG_locked         0  0000001
      >   PG_uptodate       2  0000004
      >   PG_lru            4  0000010
      >   PG_waiters        7  0000080
      >   PG_writeback     15  0008000
      >
      >
      > inode is ffff8c68f3cd0c40
      > inode.i_rwsem is ffff8c68f3cd0ce0
      >      DENTRY           INODE           SUPERBLK     TYPE PATH
      > ffff8c68a1f1b480 ffff8c68f3cd0c40 ffff8c6915bf9000 REG
      > /mnt/vm1_smb/testfile.8853
      >
      >
      > this process holds the inode->i_rwsem for the parent directory, is
      > laundering a page attached to the inode of the file it's opening, and in
      > _cifsFileInfo_put is trying to down_write the cifsInodeInflock_sem
      > for the file itself.
      >
      >
      > <struct rw_semaphore 0xffff8c68f3cd0ce0>:
      >         owner: <struct task_struct 0xffff8c6914272e80> (UN -   8854 -
      > reopen_file), counter: 0x0000000000000003
      >         waitlist: 1
      >         0xffff9965005dfd80     8855   reopen_file      UN 0  1:29:22.912
      >   RWSEM_WAITING_FOR_WRITE
      >
      > this is the inode.i_rwsem for the file
      >
      > the owner:
      >
      > [0 00:48:22.739] [UN]  PID: 8854   TASK: ffff8c6914272e80  CPU: 2
      > COMMAND: "reopen_file"
      >  #0 [ffff99650054fb38] __schedule at ffffffff9b6e6095
      >  #1 [ffff99650054fbc8] schedule at ffffffff9b6e64df
      >  #2 [ffff99650054fbd8] io_schedule at ffffffff9b6e68e2
      >  #3 [ffff99650054fbe8] __lock_page at ffffffff9b03c56f
      >  #4 [ffff99650054fc80] pagecache_get_page at ffffffff9b03dcdf
      >  #5 [ffff99650054fcc0] grab_cache_page_write_begin at ffffffff9b03ef4c
      >  #6 [ffff99650054fcd0] cifs_write_begin at ffffffffc0a064ec [cifs]
      >  #7 [ffff99650054fd30] generic_perform_write at ffffffff9b03bba4
      >  #8 [ffff99650054fda8] __generic_file_write_iter at ffffffff9b04060a
      >  #9 [ffff99650054fdf0] cifs_strict_writev.cold.70 at ffffffffc0a4469b [cifs]
      > #10 [ffff99650054fe48] new_sync_write at ffffffff9b0ec1dd
      > #11 [ffff99650054fed0] vfs_write at ffffffff9b0eed35
      > #12 [ffff99650054ff00] ksys_write at ffffffff9b0eefd9
      > #13 [ffff99650054ff38] do_syscall_64 at ffffffff9ae04315
      >
      > the process holds the inode->i_rwsem for the file to which it's writing,
      > and is trying to __lock_page for the same page as in the other processes
      >
      >
      > the other tasks:
      > [0 00:00:00.028] [UN]  PID: 8859   TASK: ffff8c6915479740  CPU: 2
      > COMMAND: "reopen_file"
      >  #0 [ffff9965007b39d8] __schedule at ffffffff9b6e6095
      >  #1 [ffff9965007b3a68] schedule at ffffffff9b6e64df
      >  #2 [ffff9965007b3a78] schedule_timeout at ffffffff9b6e9f89
      >  #3 [ffff9965007b3af0] msleep at ffffffff9af573a9
      >  #4 [ffff9965007b3af8] cifs_new_fileinfo.cold.61 at ffffffffc0a42a07 [cifs]
      >  #5 [ffff9965007b3b78] cifs_open at ffffffffc0a0709d [cifs]
      >  #6 [ffff9965007b3cd8] do_dentry_open at ffffffff9b0e9b7a
      >  #7 [ffff9965007b3d08] path_openat at ffffffff9b0fe34f
      >  #8 [ffff9965007b3dd8] do_filp_open at ffffffff9b100a33
      >  #9 [ffff9965007b3ee0] do_sys_open at ffffffff9b0eb2d6
      > #10 [ffff9965007b3f38] do_syscall_64 at ffffffff9ae04315
      >
      > this is opening the file, and is trying to down_write cinode->lock_sem
      >
      >
      > [0 00:00:00.041] [UN]  PID: 8860   TASK: ffff8c691547ae80  CPU: 2
      > COMMAND: "reopen_file"
      > [0 00:00:00.057] [UN]  PID: 8861   TASK: ffff8c6915478000  CPU: 3
      > COMMAND: "reopen_file"
      > [0 00:00:00.059] [UN]  PID: 8858   TASK: ffff8c6914271740  CPU: 2
      > COMMAND: "reopen_file"
      > [0 00:00:00.109] [UN]  PID: 8862   TASK: ffff8c691547dd00  CPU: 6
      > COMMAND: "reopen_file"
      >  #0 [ffff9965007c3c78] __schedule at ffffffff9b6e6095
      >  #1 [ffff9965007c3d08] schedule at ffffffff9b6e64df
      >  #2 [ffff9965007c3d18] schedule_timeout at ffffffff9b6e9f89
      >  #3 [ffff9965007c3d90] msleep at ffffffff9af573a9
      >  #4 [ffff9965007c3d98] _cifsFileInfo_put.cold.63 at ffffffffc0a42dd6 [cifs]
      >  #5 [ffff9965007c3e88] cifs_close at ffffffffc0a07aaf [cifs]
      >  #6 [ffff9965007c3ea0] __fput at ffffffff9b0efa6e
      >  #7 [ffff9965007c3ee8] task_work_run at ffffffff9aef1614
      >  #8 [ffff9965007c3f20] exit_to_usermode_loop at ffffffff9ae03d6f
      >  #9 [ffff9965007c3f38] do_syscall_64 at ffffffff9ae0444c
      >
      > closing the file, and trying to down_write cifsi->lock_sem
      >
      >
      > [0 00:48:22.839] [UN]  PID: 8857   TASK: ffff8c6914270000  CPU: 7
      > COMMAND: "reopen_file"
      >  #0 [ffff9965006a7cc8] __schedule at ffffffff9b6e6095
      >  #1 [ffff9965006a7d58] schedule at ffffffff9b6e64df
      >  #2 [ffff9965006a7d68] io_schedule at ffffffff9b6e68e2
      >  #3 [ffff9965006a7d78] wait_on_page_bit at ffffffff9b03cac6
      >  #4 [ffff9965006a7e10] __filemap_fdatawait_range at ffffffff9b03b028
      >  #5 [ffff9965006a7ed8] filemap_write_and_wait at ffffffff9b040165
      >  #6 [ffff9965006a7ef0] cifs_flush at ffffffffc0a0c2fa [cifs]
      >  #7 [ffff9965006a7f10] filp_close at ffffffff9b0e93f1
      >  #8 [ffff9965006a7f30] __x64_sys_close at ffffffff9b0e9a0e
      >  #9 [ffff9965006a7f38] do_syscall_64 at ffffffff9ae04315
      >
      > in __filemap_fdatawait_range
      >                         wait_on_page_writeback(page);
      > for the same page of the file
      >
      >
      >
      > [0 00:48:22.718] [UN]  PID: 8855   TASK: ffff8c69142745c0  CPU: 7
      > COMMAND: "reopen_file"
      >  #0 [ffff9965005dfc98] __schedule at ffffffff9b6e6095
      >  #1 [ffff9965005dfd28] schedule at ffffffff9b6e64df
      >  #2 [ffff9965005dfd38] rwsem_down_write_slowpath at ffffffff9af283d7
      >  #3 [ffff9965005dfdf0] cifs_strict_writev at ffffffffc0a0c40a [cifs]
      >  #4 [ffff9965005dfe48] new_sync_write at ffffffff9b0ec1dd
      >  #5 [ffff9965005dfed0] vfs_write at ffffffff9b0eed35
      >  #6 [ffff9965005dff00] ksys_write at ffffffff9b0eefd9
      >  #7 [ffff9965005dff38] do_syscall_64 at ffffffff9ae04315
      >
      >         inode_lock(inode);
      >
      >
      > and one 'ls' later on, to see whether the rest of the mount is available
      > (the test file is in the root, so we get blocked up on the directory
      > ->i_rwsem), so the entire mount is unavailable
      >
      > [0 00:36:26.473] [UN]  PID: 9802   TASK: ffff8c691436ae80  CPU: 4
      > COMMAND: "ls"
      >  #0 [ffff996500393d28] __schedule at ffffffff9b6e6095
      >  #1 [ffff996500393db8] schedule at ffffffff9b6e64df
      >  #2 [ffff996500393dc8] rwsem_down_read_slowpath at ffffffff9b6e9421
      >  #3 [ffff996500393e78] down_read_killable at ffffffff9b6e95e2
      >  #4 [ffff996500393e88] iterate_dir at ffffffff9b103c56
      >  #5 [ffff996500393ec8] ksys_getdents64 at ffffffff9b104b0c
      >  #6 [ffff996500393f30] __x64_sys_getdents64 at ffffffff9b104bb6
      >  #7 [ffff996500393f38] do_syscall_64 at ffffffff9ae04315
      >
      > in iterate_dir:
      >         if (shared)
      >                 res = down_read_killable(&inode->i_rwsem);  <<<<
      >         else
      >                 res = down_write_killable(&inode->i_rwsem);
      >
      Reported-by: NFrank Sorenson <sorenson@redhat.com>
      Reviewed-by: NPavel Shilovsky <pshilov@microsoft.com>
      Signed-off-by: NRonnie Sahlberg <lsahlber@redhat.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      32546a95
    • A
      cifs: try opening channels after mounting · d70e9fa5
      Aurelien Aptel 提交于
      After doing mount() successfully we call cifs_try_adding_channels()
      which will open as many channels as it can.
      
      Channels are closed when the master session is closed.
      
      The master connection becomes the first channel.
      
      ,-------------> global cifs_tcp_ses_list <-------------------------.
      |                                                                  |
      '- TCP_Server_Info  <-->  TCP_Server_Info  <-->  TCP_Server_Info <-'
            (master con)           (chan#1 con)         (chan#2 con)
            |      ^                    ^                    ^
            v      '--------------------|--------------------'
         cifs_ses                       |
         - chan_count = 3               |
         - chans[] ---------------------'
         - smb3signingkey[]
            (master signing key)
      
      Note how channel connections don't have sessions. That's because
      cifs_ses can only be part of one linked list (list_head are internal
      to the elements).
      
      For signing keys, each channel has its own signing key which must be
      used only after the channel has been bound. While it's binding it must
      use the master session signing key.
      
      For encryption keys, since channel connections do not have sessions
      attached we must now find matching session by looping over all sessions
      in smb2_get_enc_key().
      
      Each channel is opened like a regular server connection but at the
      session setup request step it must set the
      SMB2_SESSION_REQ_FLAG_BINDING flag and use the session id to bind to.
      
      Finally, while sending in compound_send_recv() for requests that
      aren't negprot, ses-setup or binding related, use a channel by cycling
      through the available ones (round-robin).
      Signed-off-by: NAurelien Aptel <aaptel@suse.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      d70e9fa5
    • A
      CIFS: refactor cifs_get_inode_info() · b8f7442b
      Aurelien Aptel 提交于
      Make logic of cifs_get_inode() much clearer by moving code to sub
      functions and adding comments.
      
      Document the steps this function does.
      
      cifs_get_inode_info() gets and updates a file inode metadata from its
      file path.
      
      * If caller already has raw info data from server they can pass it.
      * If inode already exists (just need to update) caller can pass it.
      
      Step 1: get raw data from server if none was passed
      Step 2: parse raw data into intermediate internal cifs_fattr struct
      Step 3: set fattr uniqueid which is later used for inode number. This
              can sometime be done from raw data
      Step 4: tweak fattr according to mount options (file_mode, acl to mode
              bits, uid, gid, etc)
      Step 5: update or create inode from final fattr struct
      
      * add is_smb1_server() helper
      * add is_inode_cache_good() helper
      * move SMB1-backupcreds-getinfo-retry to separate func
        cifs_backup_query_path_info().
      * move set-uniqueid code to separate func cifs_set_fattr_ino()
      * don't clobber uniqueid from backup cred retry
      * fix some probable corner cases memleaks
      Signed-off-by: NAurelien Aptel <aaptel@suse.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      b8f7442b
    • A
      cifs: switch servers depending on binding state · f6a6bf7c
      Aurelien Aptel 提交于
      Currently a lot of the code to initialize a connection & session uses
      the cifs_ses as input. But depending on if we are opening a new session
      or a new channel we need to use different server pointers.
      
      Add a "binding" flag in cifs_ses and a helper function that returns
      the server ptr a session should use (only in the sess establishment
      code path).
      Signed-off-by: NAurelien Aptel <aaptel@suse.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      f6a6bf7c
    • A
      cifs: add server param · f780bd3f
      Aurelien Aptel 提交于
      As we get down to the transport layer, plenty of functions are passed
      the session pointer and assume the transport to use is ses->server.
      
      Instead we modify those functions to pass (ses, server) so that we
      can decouple the session from the server.
      Signed-off-by: NAurelien Aptel <aaptel@suse.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      f780bd3f
    • A
      cifs: add multichannel mount options and data structs · bcc88801
      Aurelien Aptel 提交于
      adds:
      - [no]multichannel to enable/disable multichannel
      - max_channels=N to control how many channels to create
      
      these options are then stored in the volume struct.
      
      - store channels and max_channels in cifs_ses
      Signed-off-by: NAurelien Aptel <aaptel@suse.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      bcc88801
    • R
      smb3: add debug messages for closing unmatched open · 87bc2376
      Ronnie Sahlberg 提交于
      Helps distinguish between an interrupted close and a truly
      unmatched open.
      Signed-off-by: NRonnie Sahlberg <lsahlber@redhat.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      87bc2376
    • P
      CIFS: Fix NULL pointer dereference in mid callback · 86a7964b
      Pavel Shilovsky 提交于
      There is a race between a system call processing thread
      and the demultiplex thread when mid->resp_buf becomes NULL
      and later is being accessed to get credits. It happens when
      the 1st thread wakes up before a mid callback is called in
      the 2nd one but the mid state has already been set to
      MID_RESPONSE_RECEIVED. This causes NULL pointer dereference
      in mid callback.
      
      Fix this by saving credits from the response before we
      update the mid state and then use this value in the mid
      callback rather then accessing a response buffer.
      
      Cc: Stable <stable@vger.kernel.org>
      Fixes: ee258d79 ("CIFS: Move credit processing to mid callbacks for SMB3")
      Tested-by: NFrank Sorenson <sorenson@redhat.com>
      Reviewed-by: NRonnie Sahlberg <lsahlber@redhat.com>
      Signed-off-by: NPavel Shilovsky <pshilov@microsoft.com>
      Signed-off-by: NSteve French <stfrench@microsoft.com>
      86a7964b
  10. 25 10月, 2019 1 次提交
    • D
      cifs: Fix cifsInodeInfo lock_sem deadlock when reconnect occurs · d46b0da7
      Dave Wysochanski 提交于
      There's a deadlock that is possible and can easily be seen with
      a test where multiple readers open/read/close of the same file
      and a disruption occurs causing reconnect.  The deadlock is due
      a reader thread inside cifs_strict_readv calling down_read and
      obtaining lock_sem, and then after reconnect inside
      cifs_reopen_file calling down_read a second time.  If in
      between the two down_read calls, a down_write comes from
      another process, deadlock occurs.
      
              CPU0                    CPU1
              ----                    ----
      cifs_strict_readv()
       down_read(&cifsi->lock_sem);
                                     _cifsFileInfo_put
                                        OR
                                     cifs_new_fileinfo
                                      down_write(&cifsi->lock_sem);
      cifs_reopen_file()
       down_read(&cifsi->lock_sem);
      
      Fix the above by changing all down_write(lock_sem) calls to
      down_write_trylock(lock_sem)/msleep() loop, which in turn
      makes the second down_read call benign since it will never
      block behind the writer while holding lock_sem.
      Signed-off-by: NDave Wysochanski <dwysocha@redhat.com>
      Suggested-by: NRonnie Sahlberg <lsahlber@redhat.com>
      Reviewed--by: NRonnie Sahlberg <lsahlber@redhat.com>
      Reviewed-by: NPavel Shilovsky <pshilov@microsoft.com>
      d46b0da7
  11. 09 10月, 2019 1 次提交
  12. 26 9月, 2019 1 次提交
  13. 17 9月, 2019 8 次提交
  14. 08 7月, 2019 4 次提交
  15. 14 6月, 2019 1 次提交
  16. 16 5月, 2019 1 次提交
  17. 08 5月, 2019 5 次提交