]> Git Repo - J-linux.git/commitdiff
Merge tag 'vfs-6.11.inode' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
authorLinus Torvalds <[email protected]>
Mon, 15 Jul 2024 18:39:44 +0000 (11:39 -0700)
committerLinus Torvalds <[email protected]>
Mon, 15 Jul 2024 18:39:44 +0000 (11:39 -0700)
Pull vfs inode / dentry updates from Christian Brauner:
 "This contains smaller performance improvements to inodes and dentries:

  inode:

   - Add rcu based inode lookup variants.

     They avoid one inode hash lock acquire in the common case thereby
     significantly reducing contention. We already support RCU-based
     operations but didn't take advantage of them during inode
     insertion.

     Callers of iget_locked() get the improvement without any code
     changes. Callers that need a custom callback can switch to
     iget5_locked_rcu() as e.g., did btrfs.

     With 20 threads each walking a dedicated 1000 dirs * 1000 files
     directory tree to stat(2) on a 32 core + 24GB ram vm:

        before: 3.54s user 892.30s system 1966% cpu 45.549 total
        after:  3.28s user 738.66s system 1955% cpu 37.932 total (-16.7%)

     Long-term we should pick up the effort to introduce more
     fine-grained locking and possibly improve on the currently used
     hash implementation.

   - Start zeroing i_state in inode_init_always() instead of doing it in
     individual filesystems.

     This allows us to remove an unneeded lock acquire in new_inode()
     and not burden individual filesystems with this.

  dcache:

   - Move d_lockref out of the area used by RCU lookup to avoid
     cacheline ping poing because the embedded name is sharing a
     cacheline with d_lockref.

   - Fix dentry size on 32bit with CONFIG_SMP=y so it does actually end
     up with 128 bytes in total"

* tag 'vfs-6.11.inode' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
  fs: fix dentry size
  vfs: move d_lockref out of the area used by RCU lookup
  bcachefs: remove now spurious i_state initialization
  xfs: remove now spurious i_state initialization in xfs_inode_alloc
  vfs: partially sanitize i_state zeroing on inode creation
  xfs: preserve i_state around inode_init_always in xfs_reinit_inode
  btrfs: use iget5_locked_rcu
  vfs: add rcu-based find_inode variants for iget ops

1  2 
fs/bcachefs/fs.c
fs/btrfs/inode.c
fs/inode.c
fs/xfs/xfs_icache.c
include/linux/dcache.h
include/linux/fs.h

diff --combined fs/bcachefs/fs.c
index fa1fee05cf8f571bff276a8bc1ad22f88c14da62,8122214e00a3888457499d6bc4340aec4662575d..0c7d1bc0548a4589ea1f503ee8e4d8298db79a3f
@@@ -188,18 -188,6 +188,18 @@@ static struct bch_inode_info *bch2_inod
        BUG_ON(!old);
  
        if (unlikely(old != inode)) {
 +              /*
 +               * bcachefs doesn't use I_NEW; we have no use for it since we
 +               * only insert fully created inodes in the inode hash table. But
 +               * discard_new_inode() expects it to be set...
 +               */
 +              inode->v.i_flags |= I_NEW;
 +              /*
 +               * We don't want bch2_evict_inode() to delete the inode on disk,
 +               * we just raced and had another inode in cache. Normally new
 +               * inodes don't have nlink == 0 - except tmpfiles do...
 +               */
 +              set_nlink(&inode->v, 1);
                discard_new_inode(&inode->v);
                inode = old;
        } else {
                list_add(&inode->ei_vfs_inode_list, &c->vfs_inodes_list);
                mutex_unlock(&c->vfs_inodes_lock);
                /*
 -               * we really don't want insert_inode_locked2() to be setting
 -               * I_NEW...
 +               * Again, I_NEW makes no sense for bcachefs. This is only needed
 +               * for clearing I_NEW, but since the inode was already fully
 +               * created and initialized we didn't actually want
 +               * inode_insert5() to set it for us.
                 */
                unlock_new_inode(&inode->v);
        }
@@@ -241,10 -227,7 +241,9 @@@ static struct bch_inode_info *__bch2_ne
        mutex_init(&inode->ei_update_lock);
        two_state_lock_init(&inode->ei_pagecache_lock);
        INIT_LIST_HEAD(&inode->ei_vfs_inode_list);
 +      inode->ei_flags = 0;
        mutex_init(&inode->ei_quota_lock);
-       inode->v.i_state = 0;
 +      memset(&inode->ei_devs_need_flush, 0, sizeof(inode->ei_devs_need_flush));
  
        if (unlikely(inode_init_always(c->vfs_sb, &inode->v))) {
                kmem_cache_free(bch2_inode_cache, inode);
@@@ -1171,7 -1154,6 +1170,7 @@@ static const struct file_operations bch
        .read_iter      = bch2_read_iter,
        .write_iter     = bch2_write_iter,
        .mmap           = bch2_mmap,
 +      .get_unmapped_area = thp_get_unmapped_area,
        .fsync          = bch2_fsync,
        .splice_read    = filemap_splice_read,
        .splice_write   = iter_file_splice_write,
@@@ -1503,6 -1485,11 +1502,6 @@@ static void bch2_vfs_inode_init(struct 
        bch2_iget5_set(&inode->v, &inum);
        bch2_inode_update_after_write(trans, inode, bi, ~0);
  
 -      if (BCH_SUBVOLUME_SNAP(subvol))
 -              set_bit(EI_INODE_SNAPSHOT, &inode->ei_flags);
 -      else
 -              clear_bit(EI_INODE_SNAPSHOT, &inode->ei_flags);
 -
        inode->v.i_blocks       = bi->bi_sectors;
        inode->v.i_ino          = bi->bi_inum;
        inode->v.i_rdev         = bi->bi_dev;
        inode->ei_qid           = bch_qid(bi);
        inode->ei_subvol        = inum.subvol;
  
 +      if (BCH_SUBVOLUME_SNAP(subvol))
 +              set_bit(EI_INODE_SNAPSHOT, &inode->ei_flags);
 +
        inode->v.i_mapping->a_ops = &bch_address_space_operations;
  
        switch (inode->v.i_mode & S_IFMT) {
@@@ -1954,7 -1938,8 +1953,7 @@@ got_sb
  
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
 -              ret = bch2_err_class(ret);
 -              return ERR_PTR(ret);
 +              goto err;
        }
  
        c = sb->s_fs_info;
        sb->s_time_min          = div_s64(S64_MIN, c->sb.time_units_per_sec) + 1;
        sb->s_time_max          = div_s64(S64_MAX, c->sb.time_units_per_sec);
        sb->s_uuid              = c->sb.user_uuid;
 +      sb->s_shrink->seeks     = 0;
        c->vfs_sb               = sb;
        strscpy(sb->s_id, c->name, sizeof(sb->s_id));
  
  err_put_super:
        __bch2_fs_stop(c);
        deactivate_locked_super(sb);
 +err:
 +      if (ret)
 +              pr_err("error: %s", bch2_err_str(ret));
 +      /*
 +       * On an inconsistency error in recovery we might see an -EROFS derived
 +       * errorcode (from the journal), but we don't want to return that to
 +       * userspace as that causes util-linux to retry the mount RO - which is
 +       * confusing:
 +       */
 +      if (bch2_err_matches(ret, EROFS) && ret != -EROFS)
 +              ret = -EIO;
        return ERR_PTR(bch2_err_class(ret));
  }
  
diff --combined fs/btrfs/inode.c
index 3a2b902b2d1f9e5ef238a6001efd361ed057afed,cbb2c92b6c084df01d058dcdd8971b23494b68a3..d62c96f00ff8157c27a9590ed71949cf56b53e25
@@@ -5587,7 -5587,7 +5587,7 @@@ static struct inode *btrfs_iget_locked(
        args.ino = ino;
        args.root = root;
  
-       inode = iget5_locked(s, hashval, btrfs_find_actor,
+       inode = iget5_locked_rcu(s, hashval, btrfs_find_actor,
                             btrfs_init_locked_inode,
                             (void *)&args);
        return inode;
@@@ -10385,7 -10385,7 +10385,7 @@@ out_unlock
  out_folios:
        for (i = 0; i < nr_folios; i++) {
                if (folios[i])
 -                      __folio_put(folios[i]);
 +                      folio_put(folios[i]);
        }
        kvfree(folios);
  out:
diff --combined fs/inode.c
index e0815acc5abba9fa2be2425d775c62c30f07a528,ad7844ca92f9bc0b2d20e64ce5ae2780ea3fd85c..f356fe2ec2b609144be8b030447fdec6b3056f1f
@@@ -162,6 -162,7 +162,7 @@@ int inode_init_always(struct super_bloc
        inode->i_sb = sb;
        inode->i_blkbits = sb->s_blocksize_bits;
        inode->i_flags = 0;
+       inode->i_state = 0;
        atomic64_set(&inode->i_sequence, 0);
        atomic_set(&inode->i_count, 1);
        inode->i_op = &empty_iops;
  
        if (unlikely(security_inode_alloc(inode)))
                return -ENOMEM;
        this_cpu_inc(nr_inodes);
  
        return 0;
@@@ -886,36 -888,45 +888,45 @@@ long prune_icache_sb(struct super_bloc
        return freed;
  }
  
- static void __wait_on_freeing_inode(struct inode *inode);
+ static void __wait_on_freeing_inode(struct inode *inode, bool locked);
  /*
   * Called with the inode lock held.
   */
  static struct inode *find_inode(struct super_block *sb,
                                struct hlist_head *head,
                                int (*test)(struct inode *, void *),
-                               void *data)
+                               void *data, bool locked)
  {
        struct inode *inode = NULL;
  
+       if (locked)
+               lockdep_assert_held(&inode_hash_lock);
+       else
+               lockdep_assert_not_held(&inode_hash_lock);
+       rcu_read_lock();
  repeat:
-       hlist_for_each_entry(inode, head, i_hash) {
+       hlist_for_each_entry_rcu(inode, head, i_hash) {
                if (inode->i_sb != sb)
                        continue;
                if (!test(inode, data))
                        continue;
                spin_lock(&inode->i_lock);
                if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
-                       __wait_on_freeing_inode(inode);
+                       __wait_on_freeing_inode(inode, locked);
                        goto repeat;
                }
                if (unlikely(inode->i_state & I_CREATING)) {
                        spin_unlock(&inode->i_lock);
+                       rcu_read_unlock();
                        return ERR_PTR(-ESTALE);
                }
                __iget(inode);
                spin_unlock(&inode->i_lock);
+               rcu_read_unlock();
                return inode;
        }
+       rcu_read_unlock();
        return NULL;
  }
  
   * iget_locked for details.
   */
  static struct inode *find_inode_fast(struct super_block *sb,
-                               struct hlist_head *head, unsigned long ino)
+                               struct hlist_head *head, unsigned long ino,
+                               bool locked)
  {
        struct inode *inode = NULL;
  
+       if (locked)
+               lockdep_assert_held(&inode_hash_lock);
+       else
+               lockdep_assert_not_held(&inode_hash_lock);
+       rcu_read_lock();
  repeat:
-       hlist_for_each_entry(inode, head, i_hash) {
+       hlist_for_each_entry_rcu(inode, head, i_hash) {
                if (inode->i_ino != ino)
                        continue;
                if (inode->i_sb != sb)
                        continue;
                spin_lock(&inode->i_lock);
                if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
-                       __wait_on_freeing_inode(inode);
+                       __wait_on_freeing_inode(inode, locked);
                        goto repeat;
                }
                if (unlikely(inode->i_state & I_CREATING)) {
                        spin_unlock(&inode->i_lock);
+                       rcu_read_unlock();
                        return ERR_PTR(-ESTALE);
                }
                __iget(inode);
                spin_unlock(&inode->i_lock);
+               rcu_read_unlock();
                return inode;
        }
+       rcu_read_unlock();
        return NULL;
  }
  
@@@ -1004,14 -1025,7 +1025,7 @@@ EXPORT_SYMBOL(get_next_ino)
   */
  struct inode *new_inode_pseudo(struct super_block *sb)
  {
-       struct inode *inode = alloc_inode(sb);
-       if (inode) {
-               spin_lock(&inode->i_lock);
-               inode->i_state = 0;
-               spin_unlock(&inode->i_lock);
-       }
-       return inode;
+       return alloc_inode(sb);
  }
  
  /**
@@@ -1161,7 -1175,7 +1175,7 @@@ struct inode *inode_insert5(struct inod
  
  again:
        spin_lock(&inode_hash_lock);
-       old = find_inode(inode->i_sb, head, test, data);
+       old = find_inode(inode->i_sb, head, test, data, true);
        if (unlikely(old)) {
                /*
                 * Uhhuh, somebody else created the same inode under us.
@@@ -1235,7 -1249,6 +1249,6 @@@ struct inode *iget5_locked(struct super
                struct inode *new = alloc_inode(sb);
  
                if (new) {
-                       new->i_state = 0;
                        inode = inode_insert5(new, hashval, test, set, data);
                        if (unlikely(inode != new))
                                destroy_inode(new);
  }
  EXPORT_SYMBOL(iget5_locked);
  
+ /**
+  * iget5_locked_rcu - obtain an inode from a mounted file system
+  * @sb:               super block of file system
+  * @hashval:  hash value (usually inode number) to get
+  * @test:     callback used for comparisons between inodes
+  * @set:      callback used to initialize a new struct inode
+  * @data:     opaque data pointer to pass to @test and @set
+  *
+  * This is equivalent to iget5_locked, except the @test callback must
+  * tolerate the inode not being stable, including being mid-teardown.
+  */
+ struct inode *iget5_locked_rcu(struct super_block *sb, unsigned long hashval,
+               int (*test)(struct inode *, void *),
+               int (*set)(struct inode *, void *), void *data)
+ {
+       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+       struct inode *inode, *new;
+ again:
+       inode = find_inode(sb, head, test, data, false);
+       if (inode) {
+               if (IS_ERR(inode))
+                       return NULL;
+               wait_on_inode(inode);
+               if (unlikely(inode_unhashed(inode))) {
+                       iput(inode);
+                       goto again;
+               }
+               return inode;
+       }
+       new = alloc_inode(sb);
+       if (new) {
+               inode = inode_insert5(new, hashval, test, set, data);
+               if (unlikely(inode != new))
+                       destroy_inode(new);
+       }
+       return inode;
+ }
+ EXPORT_SYMBOL_GPL(iget5_locked_rcu);
  /**
   * iget_locked - obtain an inode from a mounted file system
   * @sb:               super block of file system
@@@ -1263,9 -1317,7 +1317,7 @@@ struct inode *iget_locked(struct super_
        struct hlist_head *head = inode_hashtable + hash(sb, ino);
        struct inode *inode;
  again:
-       spin_lock(&inode_hash_lock);
-       inode = find_inode_fast(sb, head, ino);
-       spin_unlock(&inode_hash_lock);
+       inode = find_inode_fast(sb, head, ino, false);
        if (inode) {
                if (IS_ERR(inode))
                        return NULL;
  
                spin_lock(&inode_hash_lock);
                /* We released the lock, so.. */
-               old = find_inode_fast(sb, head, ino);
+               old = find_inode_fast(sb, head, ino, true);
                if (!old) {
                        inode->i_ino = ino;
                        spin_lock(&inode->i_lock);
@@@ -1419,7 -1471,7 +1471,7 @@@ struct inode *ilookup5_nowait(struct su
        struct inode *inode;
  
        spin_lock(&inode_hash_lock);
-       inode = find_inode(sb, head, test, data);
+       inode = find_inode(sb, head, test, data, true);
        spin_unlock(&inode_hash_lock);
  
        return IS_ERR(inode) ? NULL : inode;
@@@ -1474,7 -1526,7 +1526,7 @@@ struct inode *ilookup(struct super_bloc
        struct inode *inode;
  again:
        spin_lock(&inode_hash_lock);
-       inode = find_inode_fast(sb, head, ino);
+       inode = find_inode_fast(sb, head, ino, true);
        spin_unlock(&inode_hash_lock);
  
        if (inode) {
@@@ -2235,17 -2287,21 +2287,21 @@@ EXPORT_SYMBOL(inode_needs_sync)
   * wake_up_bit(&inode->i_state, __I_NEW) after removing from the hash list
   * will DTRT.
   */
- static void __wait_on_freeing_inode(struct inode *inode)
+ static void __wait_on_freeing_inode(struct inode *inode, bool locked)
  {
        wait_queue_head_t *wq;
        DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW);
        wq = bit_waitqueue(&inode->i_state, __I_NEW);
        prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE);
        spin_unlock(&inode->i_lock);
-       spin_unlock(&inode_hash_lock);
+       rcu_read_unlock();
+       if (locked)
+               spin_unlock(&inode_hash_lock);
        schedule();
        finish_wait(wq, &wait.wq_entry);
-       spin_lock(&inode_hash_lock);
+       if (locked)
+               spin_lock(&inode_hash_lock);
+       rcu_read_lock();
  }
  
  static __initdata unsigned long ihash_entries;
@@@ -2538,7 -2594,6 +2594,7 @@@ bool in_group_or_capable(struct mnt_idm
                return true;
        return false;
  }
 +EXPORT_SYMBOL(in_group_or_capable);
  
  /**
   * mode_strip_sgid - handle the sgid bit for non-directories
diff --combined fs/xfs/xfs_icache.c
index 9967334ea99f1a77b3d58b5d061c1b8b539f163d,088ac200b026e2e12fff5de72abfcb54d1a83a24..cf629302d48e7444cc34ff64d67a9a11ee51dd87
@@@ -86,9 -86,8 +86,8 @@@ xfs_inode_alloc
                return NULL;
        }
  
-       /* VFS doesn't initialise i_mode or i_state! */
+       /* VFS doesn't initialise i_mode! */
        VFS_I(ip)->i_mode = 0;
-       VFS_I(ip)->i_state = 0;
        mapping_set_large_folios(VFS_I(ip)->i_mapping);
  
        XFS_STATS_INC(mp, vn_active);
@@@ -314,6 -313,7 +313,7 @@@ xfs_reinit_inode
        dev_t                   dev = inode->i_rdev;
        kuid_t                  uid = inode->i_uid;
        kgid_t                  gid = inode->i_gid;
+       unsigned long           state = inode->i_state;
  
        error = inode_init_always(mp->m_super, inode);
  
        inode->i_rdev = dev;
        inode->i_uid = uid;
        inode->i_gid = gid;
+       inode->i_state = state;
        mapping_set_large_folios(inode->i_mapping);
        return error;
  }
@@@ -1155,7 -1156,7 +1156,7 @@@ xfs_inode_free_eofblocks
        }
        *lockflags |= XFS_IOLOCK_EXCL;
  
 -      if (xfs_can_free_eofblocks(ip, false))
 +      if (xfs_can_free_eofblocks(ip))
                return xfs_free_eofblocks(ip);
  
        /* inode could be preallocated or append-only */
diff --combined include/linux/dcache.h
index ea58843942b968dd8be4c430e9d018fdd10068d1,58916b3f53ad115d133b10193d84c87d70cbf695..bff956f7b2b984b2c7ca17728ea2cbeb6347e7d5
@@@ -71,7 -71,7 +71,7 @@@ extern const struct qstr dotdot_name
  # define DNAME_INLINE_LEN 40 /* 192 bytes */
  #else
  # ifdef CONFIG_SMP
- #  define DNAME_INLINE_LEN 40 /* 128 bytes */
+ #  define DNAME_INLINE_LEN 36 /* 128 bytes */
  # else
  #  define DNAME_INLINE_LEN 44 /* 128 bytes */
  # endif
@@@ -89,13 -89,18 +89,18 @@@ struct dentry 
        struct inode *d_inode;          /* Where the name belongs to - NULL is
                                         * negative */
        unsigned char d_iname[DNAME_INLINE_LEN];        /* small names */
+       /* --- cacheline 1 boundary (64 bytes) was 32 bytes ago --- */
  
        /* Ref lookup also touches following */
-       struct lockref d_lockref;       /* per-dentry lock and refcount */
        const struct dentry_operations *d_op;
        struct super_block *d_sb;       /* The root of the dentry tree */
        unsigned long d_time;           /* used by d_revalidate */
        void *d_fsdata;                 /* fs-specific data */
+       /* --- cacheline 2 boundary (128 bytes) --- */
+       struct lockref d_lockref;       /* per-dentry lock and refcount
+                                        * keep separate from RCU lookup area if
+                                        * possible!
+                                        */
  
        union {
                struct list_head d_lru;         /* LRU list */
@@@ -278,8 -283,6 +283,8 @@@ static inline unsigned d_count(const st
        return dentry->d_lockref.count;
  }
  
 +ino_t d_parent_ino(struct dentry *dentry);
 +
  /*
   * helper function for dentry_operations.d_dname() members
   */
diff --combined include/linux/fs.h
index 0e76af38a6ad3c801733dd6e1ed5501cc95081cf,aac51da4f90cc5918b950b76a9a1c68d566fb0d6..dc9f9c4b2572dcf6946a4dd382e58d1b37732620
@@@ -660,13 -660,9 +660,13 @@@ struct inode 
        };
        dev_t                   i_rdev;
        loff_t                  i_size;
 -      struct timespec64       __i_atime;
 -      struct timespec64       __i_mtime;
 -      struct timespec64       __i_ctime; /* use inode_*_ctime accessors! */
 +      time64_t                i_atime_sec;
 +      time64_t                i_mtime_sec;
 +      time64_t                i_ctime_sec;
 +      u32                     i_atime_nsec;
 +      u32                     i_mtime_nsec;
 +      u32                     i_ctime_nsec;
 +      u32                     i_generation;
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
        unsigned short          i_bytes;
        u8                      i_blkbits;
                unsigned                i_dir_seq;
        };
  
 -      __u32                   i_generation;
  
  #ifdef CONFIG_FSNOTIFY
        __u32                   i_fsnotify_mask; /* all events this inode cares about */
 +      /* 32-bit hole reserved for expanding i_fsnotify_mask */
        struct fsnotify_mark_connector __rcu    *i_fsnotify_marks;
  #endif
  
@@@ -1542,27 -1538,23 +1542,27 @@@ struct timespec64 inode_set_ctime_curre
  
  static inline time64_t inode_get_atime_sec(const struct inode *inode)
  {
 -      return inode->__i_atime.tv_sec;
 +      return inode->i_atime_sec;
  }
  
  static inline long inode_get_atime_nsec(const struct inode *inode)
  {
 -      return inode->__i_atime.tv_nsec;
 +      return inode->i_atime_nsec;
  }
  
  static inline struct timespec64 inode_get_atime(const struct inode *inode)
  {
 -      return inode->__i_atime;
 +      struct timespec64 ts = { .tv_sec  = inode_get_atime_sec(inode),
 +                               .tv_nsec = inode_get_atime_nsec(inode) };
 +
 +      return ts;
  }
  
  static inline struct timespec64 inode_set_atime_to_ts(struct inode *inode,
                                                      struct timespec64 ts)
  {
 -      inode->__i_atime = ts;
 +      inode->i_atime_sec = ts.tv_sec;
 +      inode->i_atime_nsec = ts.tv_nsec;
        return ts;
  }
  
@@@ -1571,32 -1563,28 +1571,32 @@@ static inline struct timespec64 inode_s
  {
        struct timespec64 ts = { .tv_sec  = sec,
                                 .tv_nsec = nsec };
 +
        return inode_set_atime_to_ts(inode, ts);
  }
  
  static inline time64_t inode_get_mtime_sec(const struct inode *inode)
  {
 -      return inode->__i_mtime.tv_sec;
 +      return inode->i_mtime_sec;
  }
  
  static inline long inode_get_mtime_nsec(const struct inode *inode)
  {
 -      return inode->__i_mtime.tv_nsec;
 +      return inode->i_mtime_nsec;
  }
  
  static inline struct timespec64 inode_get_mtime(const struct inode *inode)
  {
 -      return inode->__i_mtime;
 +      struct timespec64 ts = { .tv_sec  = inode_get_mtime_sec(inode),
 +                               .tv_nsec = inode_get_mtime_nsec(inode) };
 +      return ts;
  }
  
  static inline struct timespec64 inode_set_mtime_to_ts(struct inode *inode,
                                                      struct timespec64 ts)
  {
 -      inode->__i_mtime = ts;
 +      inode->i_mtime_sec = ts.tv_sec;
 +      inode->i_mtime_nsec = ts.tv_nsec;
        return ts;
  }
  
@@@ -1610,27 -1598,23 +1610,27 @@@ static inline struct timespec64 inode_s
  
  static inline time64_t inode_get_ctime_sec(const struct inode *inode)
  {
 -      return inode->__i_ctime.tv_sec;
 +      return inode->i_ctime_sec;
  }
  
  static inline long inode_get_ctime_nsec(const struct inode *inode)
  {
 -      return inode->__i_ctime.tv_nsec;
 +      return inode->i_ctime_nsec;
  }
  
  static inline struct timespec64 inode_get_ctime(const struct inode *inode)
  {
 -      return inode->__i_ctime;
 +      struct timespec64 ts = { .tv_sec  = inode_get_ctime_sec(inode),
 +                               .tv_nsec = inode_get_ctime_nsec(inode) };
 +
 +      return ts;
  }
  
  static inline struct timespec64 inode_set_ctime_to_ts(struct inode *inode,
                                                      struct timespec64 ts)
  {
 -      inode->__i_ctime = ts;
 +      inode->i_ctime_sec = ts.tv_sec;
 +      inode->i_ctime_nsec = ts.tv_nsec;
        return ts;
  }
  
@@@ -1942,8 -1926,6 +1942,8 @@@ void inode_init_owner(struct mnt_idmap 
  extern bool may_open_dev(const struct path *path);
  umode_t mode_strip_sgid(struct mnt_idmap *idmap,
                        const struct inode *dir, umode_t mode);
 +bool in_group_or_capable(struct mnt_idmap *idmap,
 +                       const struct inode *inode, vfsgid_t vfsgid);
  
  /*
   * This is the "filldir" function type, used by readdir() to let
@@@ -2703,7 -2685,7 +2703,7 @@@ static inline struct file *file_clone_o
  }
  extern int filp_close(struct file *, fl_owner_t id);
  
 -extern struct filename *getname_flags(const char __user *, int, int *);
 +extern struct filename *getname_flags(const char __user *, int);
  extern struct filename *getname_uflags(const char __user *, int);
  extern struct filename *getname(const char __user *);
  extern struct filename *getname_kernel(const char *);
@@@ -3047,7 -3029,12 +3047,12 @@@ extern struct inode *inode_insert5(stru
                int (*test)(struct inode *, void *),
                int (*set)(struct inode *, void *),
                void *data);
- extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
+ struct inode *iget5_locked(struct super_block *, unsigned long,
+                          int (*test)(struct inode *, void *),
+                          int (*set)(struct inode *, void *), void *);
+ struct inode *iget5_locked_rcu(struct super_block *, unsigned long,
+                              int (*test)(struct inode *, void *),
+                              int (*set)(struct inode *, void *), void *);
  extern struct inode * iget_locked(struct super_block *, unsigned long);
  extern struct inode *find_inode_nowait(struct super_block *,
                                       unsigned long,
@@@ -3369,10 -3356,6 +3374,10 @@@ extern int generic_file_fsync(struct fi
  extern int generic_check_addressable(unsigned, u64);
  
  extern void generic_set_sb_d_ops(struct super_block *sb);
 +extern int generic_ci_match(const struct inode *parent,
 +                          const struct qstr *name,
 +                          const struct qstr *folded_name,
 +                          const u8 *de_name, u32 de_name_len);
  
  static inline bool sb_has_encoding(const struct super_block *sb)
  {
@@@ -3458,6 -3441,20 +3463,6 @@@ static inline int kiocb_set_rw_flags(st
        return 0;
  }
  
 -static inline ino_t parent_ino(struct dentry *dentry)
 -{
 -      ino_t res;
 -
 -      /*
 -       * Don't strictly need d_lock here? If the parent ino could change
 -       * then surely we'd have a deeper race in the caller?
 -       */
 -      spin_lock(&dentry->d_lock);
 -      res = dentry->d_parent->d_inode->i_ino;
 -      spin_unlock(&dentry->d_lock);
 -      return res;
 -}
 -
  /* Transaction based IO helpers */
  
  /*
@@@ -3582,7 -3579,7 +3587,7 @@@ static inline bool dir_emit_dot(struct 
  static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx)
  {
        return ctx->actor(ctx, "..", 2, ctx->pos,
 -                        parent_ino(file->f_path.dentry), DT_DIR);
 +                        d_parent_ino(file->f_path.dentry), DT_DIR);
  }
  static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx)
  {
@@@ -3621,21 -3618,4 +3626,21 @@@ extern int vfs_fadvise(struct file *fil
  extern int generic_fadvise(struct file *file, loff_t offset, loff_t len,
                           int advice);
  
 +static inline bool vfs_empty_path(int dfd, const char __user *path)
 +{
 +      char c;
 +
 +      if (dfd < 0)
 +              return false;
 +
 +      /* We now allow NULL to be used for empty path. */
 +      if (!path)
 +              return true;
 +
 +      if (unlikely(get_user(c, path)))
 +              return false;
 +
 +      return !c;
 +}
 +
  #endif /* _LINUX_FS_H */
This page took 0.094188 seconds and 4 git commands to generate.