Merge tag 'nfsd-5.3' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2019 04:22:43 +0000 (21:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Jul 2019 04:22:43 +0000 (21:22 -0700)
Pull nfsd updates from Bruce Fields:
 "Highlights:

   - Add a new /proc/fs/nfsd/clients/ directory which exposes some
     long-requested information about NFSv4 clients (like open files)
     and allows forced revocation of client state.

   - Replace the global duplicate reply cache by a cache per network
     namespace; previously, a request in one network namespace could
     incorrectly match an entry from another, though we haven't seen
     this in production. This is the last remaining container bug that
     I'm aware of; at this point you should be able to run separate
     nfsd's in each network namespace, each with their own set of
     exports, and everything should work.

   - Cleanup and modify lock code to show the pid of lockd as the owner
     of NLM locks. This is the correct version of the bugfix originally
     attempted in b8eee0e90f97 ("lockd: Show pid of lockd for remote
     locks")"

* tag 'nfsd-5.3' of git://linux-nfs.org/~bfields/linux: (34 commits)
  nfsd: Make __get_nfsdfs_client() static
  nfsd: Make two functions static
  nfsd: Fix misuse of strlcpy
  sunrpc/cache: remove the exporting of cache_seq_next
  nfsd: decode implementation id
  nfsd: create xdr_netobj_dup helper
  nfsd: allow forced expiration of NFSv4 clients
  nfsd: create get_nfsdfs_clp helper
  nfsd4: show layout stateids
  nfsd: show lock and deleg stateids
  nfsd4: add file to display list of client's opens
  nfsd: add more information to client info file
  nfsd: escape high characters in binary data
  nfsd: copy client's address including port number to cl_addr
  nfsd4: add a client info file
  nfsd: make client/ directory names small ints
  nfsd: add nfsd/clients directory
  nfsd4: use reference count to free client
  nfsd: rename cl_refcount
  nfsd: persist nfsd filesystem across mounts
  ...

1  2 
fs/locks.c
include/linux/fs.h
net/sunrpc/cache.c

diff --combined fs/locks.c
@@@ -658,9 -658,6 +658,6 @@@ static inline int locks_overlap(struct 
   */
  static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
  {
-       if (fl1->fl_lmops && fl1->fl_lmops->lm_compare_owner)
-               return fl2->fl_lmops == fl1->fl_lmops &&
-                       fl1->fl_lmops->lm_compare_owner(fl1, fl2);
        return fl1->fl_owner == fl2->fl_owner;
  }
  
@@@ -701,8 -698,6 +698,6 @@@ static void locks_delete_global_locks(s
  static unsigned long
  posix_owner_key(struct file_lock *fl)
  {
-       if (fl->fl_lmops && fl->fl_lmops->lm_owner_key)
-               return fl->fl_lmops->lm_owner_key(fl);
        return (unsigned long)fl->fl_owner;
  }
  
@@@ -1534,21 -1529,11 +1529,21 @@@ static void time_out_leases(struct inod
  
  static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
  {
 -      if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT))
 -              return false;
 -      if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE))
 -              return false;
 -      return locks_conflict(breaker, lease);
 +      bool rc;
 +
 +      if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT)) {
 +              rc = false;
 +              goto trace;
 +      }
 +      if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) {
 +              rc = false;
 +              goto trace;
 +      }
 +
 +      rc = locks_conflict(breaker, lease);
 +trace:
 +      trace_leases_conflict(rc, lease, breaker);
 +      return rc;
  }
  
  static bool
@@@ -1763,10 -1748,10 +1758,10 @@@ int fcntl_getlease(struct file *filp
  }
  
  /**
 - * check_conflicting_open - see if the given dentry points to a file that has
 + * check_conflicting_open - see if the given file points to an inode that has
   *                        an existing open that would conflict with the
   *                        desired lease.
 - * @dentry:   dentry to check
 + * @filp:     file to check
   * @arg:      type of lease that we're trying to acquire
   * @flags:    current lock flags
   *
   * conflict with the lease we're trying to set.
   */
  static int
 -check_conflicting_open(const struct dentry *dentry, const long arg, int flags)
 +check_conflicting_open(struct file *filp, const long arg, int flags)
  {
 -      int ret = 0;
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = locks_inode(filp);
 +      int self_wcount = 0, self_rcount = 0;
  
        if (flags & FL_LAYOUT)
                return 0;
  
 -      if ((arg == F_RDLCK) && inode_is_open_for_write(inode))
 -              return -EAGAIN;
 +      if (arg == F_RDLCK)
 +              return inode_is_open_for_write(inode) ? -EAGAIN : 0;
 +      else if (arg != F_WRLCK)
 +              return 0;
  
 -      if ((arg == F_WRLCK) && ((d_count(dentry) > 1) ||
 -          (atomic_read(&inode->i_count) > 1)))
 -              ret = -EAGAIN;
 +      /*
 +       * Make sure that only read/write count is from lease requestor.
 +       * Note that this will result in denying write leases when i_writecount
 +       * is negative, which is what we want.  (We shouldn't grant write leases
 +       * on files open for execution.)
 +       */
 +      if (filp->f_mode & FMODE_WRITE)
 +              self_wcount = 1;
 +      else if (filp->f_mode & FMODE_READ)
 +              self_rcount = 1;
  
 -      return ret;
 +      if (atomic_read(&inode->i_writecount) != self_wcount ||
 +          atomic_read(&inode->i_readcount) != self_rcount)
 +              return -EAGAIN;
 +
 +      return 0;
  }
  
  static int
  generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv)
  {
        struct file_lock *fl, *my_fl = NULL, *lease;
 -      struct dentry *dentry = filp->f_path.dentry;
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = locks_inode(filp);
        struct file_lock_context *ctx;
        bool is_deleg = (*flp)->fl_flags & FL_DELEG;
        int error;
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
        time_out_leases(inode, &dispose);
 -      error = check_conflicting_open(dentry, arg, lease->fl_flags);
 +      error = check_conflicting_open(filp, arg, lease->fl_flags);
        if (error)
                goto out;
  
         * precedes these checks.
         */
        smp_mb();
 -      error = check_conflicting_open(dentry, arg, lease->fl_flags);
 +      error = check_conflicting_open(filp, arg, lease->fl_flags);
        if (error) {
                locks_unlink_lock_ctx(lease);
                goto out;
diff --combined include/linux/fs.h
@@@ -694,7 -694,7 +694,7 @@@ struct inode 
        atomic_t                i_count;
        atomic_t                i_dio_count;
        atomic_t                i_writecount;
 -#ifdef CONFIG_IMA
 +#if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
        atomic_t                i_readcount; /* struct files open RO */
  #endif
        union {
@@@ -1019,8 -1019,6 +1019,6 @@@ struct file_lock_operations 
  };
  
  struct lock_manager_operations {
-       int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
-       unsigned long (*lm_owner_key)(struct file_lock *);
        fl_owner_t (*lm_get_owner)(fl_owner_t);
        void (*lm_put_owner)(fl_owner_t);
        void (*lm_notify)(struct file_lock *);  /* unblock callback */
@@@ -1769,7 -1767,7 +1767,7 @@@ struct block_device_operations
  /*
   * These flags control the behavior of the remap_file_range function pointer.
   * If it is called with len == 0 that means "remap to end of source file".
 - * See Documentation/filesystems/vfs.txt for more details about this call.
 + * See Documentation/filesystems/vfs.rst for more details about this call.
   *
   * REMAP_FILE_DEDUP: only remap if contents identical (i.e. deduplicate)
   * REMAP_FILE_CAN_SHORTEN: caller can handle a shortened request
@@@ -1889,9 -1887,6 +1887,9 @@@ extern ssize_t vfs_readv(struct file *
                unsigned long, loff_t *, rwf_t);
  extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
                                   loff_t, size_t, unsigned int);
 +extern ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
 +                                     struct file *file_out, loff_t pos_out,
 +                                     size_t len, unsigned int flags);
  extern int generic_remap_file_range_prep(struct file *file_in, loff_t pos_in,
                                         struct file *file_out, loff_t pos_out,
                                         loff_t *count,
@@@ -2177,8 -2172,6 +2175,8 @@@ static inline void file_accessed(struc
                touch_atime(&file->f_path);
  }
  
 +extern int file_modified(struct file *file);
 +
  int sync_inode(struct inode *inode, struct writeback_control *wbc);
  int sync_inode_metadata(struct inode *inode, int wait);
  
@@@ -2189,7 -2182,6 +2187,7 @@@ struct file_system_type 
  #define FS_BINARY_MOUNTDATA   2
  #define FS_HAS_SUBTYPE                4
  #define FS_USERNS_MOUNT               8       /* Can be mounted by userns root */
 +#define FS_DISALLOW_NOTIFY_PERM       16      /* Disable fanotify permission events */
  #define FS_RENAME_DOES_D_MOVE 32768   /* FS will handle d_move() during rename() internally. */
        int (*init_fs_context)(struct fs_context *);
        const struct fs_parameter_description *parameters;
@@@ -2718,8 -2710,6 +2716,8 @@@ extern int filemap_flush(struct address
  extern int filemap_fdatawait_keep_errors(struct address_space *mapping);
  extern int filemap_fdatawait_range(struct address_space *, loff_t lstart,
                                   loff_t lend);
 +extern int filemap_fdatawait_range_keep_errors(struct address_space *mapping,
 +              loff_t start_byte, loff_t end_byte);
  
  static inline int filemap_fdatawait(struct address_space *mapping)
  {
@@@ -2898,7 -2888,7 +2896,7 @@@ static inline bool inode_is_open_for_wr
        return atomic_read(&inode->i_writecount) > 0;
  }
  
 -#ifdef CONFIG_IMA
 +#if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
  static inline void i_readcount_dec(struct inode *inode)
  {
        BUG_ON(!atomic_read(&inode->i_readcount));
@@@ -3054,10 -3044,6 +3052,10 @@@ extern ssize_t generic_write_checks(str
  extern int generic_remap_checks(struct file *file_in, loff_t pos_in,
                                struct file *file_out, loff_t pos_out,
                                loff_t *count, unsigned int remap_flags);
 +extern int generic_file_rw_checks(struct file *file_in, struct file *file_out);
 +extern int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
 +                                  struct file *file_out, loff_t pos_out,
 +                                  size_t *count, unsigned int flags);
  extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);
  extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *);
  extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *);
diff --combined net/sunrpc/cache.c
@@@ -1,4 -1,3 +1,4 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * net/sunrpc/cache.c
   *
@@@ -6,6 -5,9 +6,6 @@@
   * used by sunrpc clients and servers.
   *
   * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
 - *
 - * Released under terms in GPL version 2.  See COPYING.
 - *
   */
  
  #include <linux/types.h>
@@@ -1375,7 -1377,6 +1375,6 @@@ static void *cache_seq_next(struct seq_
                                hlist_first_rcu(&cd->hash_table[hash])),
                                struct cache_head, cache_list);
  }
- EXPORT_SYMBOL_GPL(cache_seq_next);
  
  void *cache_seq_start_rcu(struct seq_file *m, loff_t *pos)
        __acquires(RCU)