1. 08 Aug, 2022 1 commit
    • NeilBrown's avatar
      NFS: don't unhash dentry during unlink/rename · 3c59366c
      NeilBrown authored
      NFS unlink() (and rename over existing target) must determine if the
      file is open, and must perform a "silly rename" instead of an unlink (or
      before rename) if it is.  Otherwise the client might hold a file open
      which has been removed on the server.
      
      Consequently if it determines that the file isn't open, it must block
      any subsequent opens until the unlink/rename has been completed on the
      server.
      
      This is currently achieved by unhashing the dentry.  This forces any
      open attempt to the slow-path for lookup which will block on i_rwsem on
      the directory until the unlink/rename completes.  A future patch will
      change the VFS to only get a shared lock on i_rwsem for unlink, so this
      will no longer work.
      
      Instead we introduce an explicit interlock.  A special value is stored
      in dentry->d_fsdata while the unlink/rename is running and
      ->d_revalidate blocks while that value is present.  When ->d_revalidate
      unblocks, the dentry will be invalid.  This closes the race
      without requiring exclusion on i_rwsem.
      
      d_fsdata is already used in two different ways.
      1/ an IS_ROOT directory dentry might have a "devname" stored in
         d_fsdata.  Such a dentry doesn't have a name and so cannot be the
         target of unlink or rename.  For safety we check if an old devname
         is still stored, and remove it if it is.
      2/ a dentry with DCACHE_NFSFS_RENAMED set will have a 'struct
         nfs_unlinkdata' stored in d_fsdata.  While this is set maydelete()
         will fail, so an unlink or rename will never proceed on such
         a dentry.
      
      Neither of these can be in effect when a dentry is the target of unlink
      or rename.  So we can expect d_fsdata to be NULL, and store a special
      value ((void*)1) which is given the name NFS_FSDATA_BLOCKED to indicate
      that any lookup will be blocked.
      
      The d_count() is incremented under d_lock() when a lookup finds the
      dentry, so we check d_count() is low, and set NFS_FSDATA_BLOCKED under
      the same lock to avoid any races.
      Signed-off-by: default avatarNeilBrown <neilb@suse.de>
      Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
      3c59366c
  2. 02 Aug, 2022 2 commits
  3. 27 Jul, 2022 3 commits
  4. 25 Jul, 2022 11 commits
  5. 23 Jul, 2022 12 commits
  6. 13 Jul, 2022 1 commit
    • Trond Myklebust's avatar
      NFSv4: Fix races in the legacy idmapper upcall · 51fd2eb5
      Trond Myklebust authored
      nfs_idmap_instantiate() will cause the process that is waiting in
      request_key_with_auxdata() to wake up and exit. If there is a second
      process waiting for the idmap->idmap_mutex, then it may wake up and
      start a new call to request_key_with_auxdata(). If the call to
      idmap_pipe_downcall() from the first process has not yet finished
      calling nfs_idmap_complete_pipe_upcall_locked(), then we may end up
      triggering the WARN_ON_ONCE() in nfs_idmap_prepare_pipe_upcall().
      
      The fix is to ensure that we clear idmap->idmap_upcall_data before
      calling nfs_idmap_instantiate().
      
      Fixes: e9ab41b6 ("NFSv4: Clean up the legacy idmapper upcall")
      Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
      51fd2eb5
  7. 12 Jul, 2022 8 commits
  8. 10 Jul, 2022 2 commits