Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 May 2019 03:50:27 +0000 (20:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 May 2019 03:50:27 +0000 (20:50 -0700)
Pull misc vfs updates from Al Viro:
 "Assorted stuff, with no common topic whatsoever..."

* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  libfs: document simple_get_link()
  Documentation/filesystems/Locking: fix ->get_link() prototype
  Documentation/filesystems/vfs.txt: document how ->i_link works
  Documentation/filesystems/vfs.txt: remove bogus "Last updated" date
  fs: use timespec64 in relatime_need_update
  fs/block_dev.c: remove unused include

1  2 
Documentation/filesystems/Locking
fs/block_dev.c
fs/inode.c
fs/libfs.c

index 7b20c385cc022ec86ca0d8cba8c5c239aff5e405,428455bf9c97a13f69c801c16434078f7cfce0a0..dac43557538413651c069a893d374cfd7b8dc7ab
@@@ -52,7 -52,7 +52,7 @@@ prototypes
        int (*rename) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *, unsigned int);
        int (*readlink) (struct dentry *, char __user *,int);
-       const char *(*get_link) (struct dentry *, struct inode *, void **);
+       const char *(*get_link) (struct dentry *, struct inode *, struct delayed_call *);
        void (*truncate) (struct inode *);
        int (*permission) (struct inode *, int, unsigned int);
        int (*get_acl)(struct inode *, int);
@@@ -118,7 -118,6 +118,7 @@@ set:               exclusiv
  --------------------------- super_operations ---------------------------
  prototypes:
        struct inode *(*alloc_inode)(struct super_block *sb);
 +      void (*free_inode)(struct inode *);
        void (*destroy_inode)(struct inode *);
        void (*dirty_inode) (struct inode *, int flags);
        int (*write_inode) (struct inode *, struct writeback_control *wbc);
@@@ -140,7 -139,6 +140,7 @@@ locking rules
        All may block [not true, see below]
                        s_umount
  alloc_inode:
 +free_inode:                           called from RCU callback
  destroy_inode:
  dirty_inode:
  write_inode:
diff --combined fs/block_dev.c
index 500aaa3e59900cdabb27e370f1b38f30d0b2919b,6b584817d461c1cb39108d1c280a786a55391a58..f80045048bb7c00686a4fc34bf8632735c672baf
@@@ -30,7 -30,6 +30,6 @@@
  #include <linux/log2.h>
  #include <linux/cleancache.h>
  #include <linux/dax.h>
- #include <linux/badblocks.h>
  #include <linux/task_io_accounting_ops.h>
  #include <linux/falloc.h>
  #include <linux/uaccess.h>
@@@ -210,6 -209,7 +209,6 @@@ __blkdev_direct_IO_simple(struct kiocb 
        struct bio bio;
        ssize_t ret;
        blk_qc_t qc;
 -      int i;
        struct bvec_iter_all iter_all;
  
        if ((pos | iov_iter_alignment(iter)) &
        }
        __set_current_state(TASK_RUNNING);
  
 -      bio_for_each_segment_all(bvec, &bio, i, iter_all) {
 +      bio_for_each_segment_all(bvec, &bio, iter_all) {
                if (should_dirty && !PageCompound(bvec->bv_page))
                        set_page_dirty_lock(bvec->bv_page);
 -              put_page(bvec->bv_page);
 +              if (!bio_flagged(&bio, BIO_NO_PAGE_REF))
 +                      put_page(bvec->bv_page);
        }
  
        if (unlikely(bio.bi_status))
@@@ -307,10 -306,10 +306,10 @@@ static void blkdev_bio_end_io(struct bi
        struct blkdev_dio *dio = bio->bi_private;
        bool should_dirty = dio->should_dirty;
  
 -      if (dio->multi_bio && !atomic_dec_and_test(&dio->ref)) {
 -              if (bio->bi_status && !dio->bio.bi_status)
 -                      dio->bio.bi_status = bio->bi_status;
 -      } else {
 +      if (bio->bi_status && !dio->bio.bi_status)
 +              dio->bio.bi_status = bio->bi_status;
 +
 +      if (!dio->multi_bio || atomic_dec_and_test(&dio->ref)) {
                if (!dio->is_sync) {
                        struct kiocb *iocb = dio->iocb;
                        ssize_t ret;
                if (!bio_flagged(bio, BIO_NO_PAGE_REF)) {
                        struct bvec_iter_all iter_all;
                        struct bio_vec *bvec;
 -                      int i;
  
 -                      bio_for_each_segment_all(bvec, bio, i, iter_all)
 +                      bio_for_each_segment_all(bvec, bio, iter_all)
                                put_page(bvec->bv_page);
                }
                bio_put(bio);
@@@ -788,9 -788,17 +787,9 @@@ static struct inode *bdev_alloc_inode(s
        return &ei->vfs_inode;
  }
  
 -static void bdev_i_callback(struct rcu_head *head)
 -{
 -      struct inode *inode = container_of(head, struct inode, i_rcu);
 -      struct bdev_inode *bdi = BDEV_I(inode);
 -
 -      kmem_cache_free(bdev_cachep, bdi);
 -}
 -
 -static void bdev_destroy_inode(struct inode *inode)
 +static void bdev_free_inode(struct inode *inode)
  {
 -      call_rcu(&inode->i_rcu, bdev_i_callback);
 +      kmem_cache_free(bdev_cachep, BDEV_I(inode));
  }
  
  static void init_once(void *foo)
@@@ -830,7 -838,7 +829,7 @@@ static void bdev_evict_inode(struct ino
  static const struct super_operations bdev_sops = {
        .statfs = simple_statfs,
        .alloc_inode = bdev_alloc_inode,
 -      .destroy_inode = bdev_destroy_inode,
 +      .free_inode = bdev_free_inode,
        .drop_inode = generic_delete_inode,
        .evict_inode = bdev_evict_inode,
  };
diff --combined fs/inode.c
index 16b10e53292e38ff268f4563a857ebddd9e46550,f8ed7144c3dde00cf6bbe4e2939fda09eea74237..e9d18b2c3f91f8de9ec1f17618360ad13efbba07
@@@ -202,28 -202,12 +202,28 @@@ out
  }
  EXPORT_SYMBOL(inode_init_always);
  
 +void free_inode_nonrcu(struct inode *inode)
 +{
 +      kmem_cache_free(inode_cachep, inode);
 +}
 +EXPORT_SYMBOL(free_inode_nonrcu);
 +
 +static void i_callback(struct rcu_head *head)
 +{
 +      struct inode *inode = container_of(head, struct inode, i_rcu);
 +      if (inode->free_inode)
 +              inode->free_inode(inode);
 +      else
 +              free_inode_nonrcu(inode);
 +}
 +
  static struct inode *alloc_inode(struct super_block *sb)
  {
 +      const struct super_operations *ops = sb->s_op;
        struct inode *inode;
  
 -      if (sb->s_op->alloc_inode)
 -              inode = sb->s_op->alloc_inode(sb);
 +      if (ops->alloc_inode)
 +              inode = ops->alloc_inode(sb);
        else
                inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
  
                return NULL;
  
        if (unlikely(inode_init_always(sb, inode))) {
 -              if (inode->i_sb->s_op->destroy_inode)
 -                      inode->i_sb->s_op->destroy_inode(inode);
 -              else
 -                      kmem_cache_free(inode_cachep, inode);
 +              if (ops->destroy_inode) {
 +                      ops->destroy_inode(inode);
 +                      if (!ops->free_inode)
 +                              return NULL;
 +              }
 +              inode->free_inode = ops->free_inode;
 +              i_callback(&inode->i_rcu);
                return NULL;
        }
  
        return inode;
  }
  
 -void free_inode_nonrcu(struct inode *inode)
 -{
 -      kmem_cache_free(inode_cachep, inode);
 -}
 -EXPORT_SYMBOL(free_inode_nonrcu);
 -
  void __destroy_inode(struct inode *inode)
  {
        BUG_ON(inode_has_buffers(inode));
  }
  EXPORT_SYMBOL(__destroy_inode);
  
 -static void i_callback(struct rcu_head *head)
 -{
 -      struct inode *inode = container_of(head, struct inode, i_rcu);
 -      kmem_cache_free(inode_cachep, inode);
 -}
 -
  static void destroy_inode(struct inode *inode)
  {
 +      const struct super_operations *ops = inode->i_sb->s_op;
 +
        BUG_ON(!list_empty(&inode->i_lru));
        __destroy_inode(inode);
 -      if (inode->i_sb->s_op->destroy_inode)
 -              inode->i_sb->s_op->destroy_inode(inode);
 -      else
 -              call_rcu(&inode->i_rcu, i_callback);
 +      if (ops->destroy_inode) {
 +              ops->destroy_inode(inode);
 +              if (!ops->free_inode)
 +                      return;
 +      }
 +      inode->free_inode = ops->free_inode;
 +      call_rcu(&inode->i_rcu, i_callback);
  }
  
  /**
@@@ -1613,7 -1601,7 +1613,7 @@@ EXPORT_SYMBOL(bmap)
   * passed since the last atime update.
   */
  static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
-                            struct timespec now)
+                            struct timespec64 now)
  {
  
        if (!(mnt->mnt_flags & MNT_RELATIME))
@@@ -1714,7 -1702,7 +1714,7 @@@ bool atime_needs_update(const struct pa
  
        now = current_time(inode);
  
-       if (!relatime_need_update(mnt, inode, timespec64_to_timespec(now)))
+       if (!relatime_need_update(mnt, inode, now))
                return false;
  
        if (timespec64_equal(&inode->i_atime, &now))
@@@ -1829,13 -1817,8 +1829,13 @@@ int file_remove_privs(struct file *file
        int kill;
        int error = 0;
  
 -      /* Fast path for nothing security related */
 -      if (IS_NOSEC(inode))
 +      /*
 +       * Fast path for nothing security related.
 +       * As well for non-regular files, e.g. blkdev inodes.
 +       * For example, blkdev_write_iter() might get here
 +       * trying to remove privs which it is not allowed to.
 +       */
 +      if (IS_NOSEC(inode) || !S_ISREG(inode->i_mode))
                return 0;
  
        kill = dentry_needs_remove_privs(dentry);
diff --combined fs/libfs.c
index 9efb647917e0222db97c710fdc50f873ef5e4150,5f74a98729742f6045c380aa42f6d12ed9ce9a18..4b59b1816efbaf31fb6e4cd831363e06c7b6bb3b
@@@ -146,11 -146,9 +146,11 @@@ loff_t dcache_dir_lseek(struct file *fi
        switch (whence) {
                case 1:
                        offset += file->f_pos;
 +                      /* fall through */
                case 0:
                        if (offset >= 0)
                                break;
 +                      /* fall through */
                default:
                        return -EINVAL;
        }
@@@ -1169,6 -1167,20 +1169,20 @@@ simple_nosetlease(struct file *filp, lo
  }
  EXPORT_SYMBOL(simple_nosetlease);
  
+ /**
+  * simple_get_link - generic helper to get the target of "fast" symlinks
+  * @dentry: not used here
+  * @inode: the symlink inode
+  * @done: not used here
+  *
+  * Generic helper for filesystems to use for symlink inodes where a pointer to
+  * the symlink target is stored in ->i_link.  NOTE: this isn't normally called,
+  * since as an optimization the path lookup code uses any non-NULL ->i_link
+  * directly, without calling ->get_link().  But ->get_link() still must be set,
+  * to mark the inode_operations as being for a symlink.
+  *
+  * Return: the symlink target
+  */
  const char *simple_get_link(struct dentry *dentry, struct inode *inode,
                            struct delayed_call *done)
  {