Re: [PATCH v4 9/9] ovl: use iget5_prealloc() to hash a newly created inode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, May 22, 2018 at 6:21 PM, Miklos Szeredi <miklos@xxxxxxxxxx> wrote:
> On Fri, May 18, 2018 at 06:01:22PM +0200, Miklos Szeredi wrote:
>> On Fri, May 18, 2018 at 5:40 PM, Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote:
>> > On Fri, May 18, 2018 at 05:11:20PM +0200, Miklos Szeredi wrote:
>> >> On Fri, May 18, 2018 at 5:03 PM, Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote:
>
>> >> > Mind explaining what the hell is wrong with insert_inode_locked4()?
>> >>
>> >> That it doesn't return the old inode if found.
>> >>
>> >> Btw, these functions are eerily similar, and it'd be nice to reduce
>> >> the number of them.
>
> How about this one?
>

Pushed tested branch ovl-fixed.
For sanity check of iget5_locked() also ran xfstests -g quick on btrfs.

Thanks,
Amir.


> ---
>
> From: Miklos Szeredi <miklos@xxxxxxxxxx>
> Date: Thu, 17 May 2018 10:53:05 +0200
> Subject: vfs: factor out inode_insert5()
>
> Split out common helper for race free insertion of an already allocated
> inode into the cache.  Use this from iget5_locked() and
> insert_inode_locked4().  Make iget5_locked() use new_inode()/iput() instead
> of alloc_inode()/destroy_inode() directly.
>
> Also export to modules for use by filesystems which want to preallocate an
> inode before file/directory creation.
>
> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx>
> ---
>  fs/inode.c         |  164 ++++++++++++++++++++++++-----------------------------
>  include/linux/fs.h |    4 +
>  2 files changed, 79 insertions(+), 89 deletions(-)
>
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -1003,6 +1003,70 @@ void unlock_two_nondirectories(struct in
>  EXPORT_SYMBOL(unlock_two_nondirectories);
>
>  /**
> + * inode_insert5 - obtain an inode from a mounted file system
> + * @inode:     pre-allocated inode to use for insert to cache
> + * @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
> + *
> + * Search for the inode specified by @hashval and @data in the inode cache,
> + * and if present it is return it with an increased reference count. This is
> + * a variant of iget5_locked() for callers that don't want to fail on memory
> + * allocation of inode.
> + *
> + * If the inode is not in cache, insert the pre-allocated inode to cache and
> + * return it locked, hashed, and with the I_NEW flag set. The file system gets
> + * to fill it in before unlocking it via unlock_new_inode().
> + *
> + * Note both @test and @set are called with the inode_hash_lock held, so can't
> + * sleep.
> + */
> +struct inode *inode_insert5(struct inode *inode, unsigned long hashval,
> +                           int (*test)(struct inode *, void *),
> +                           int (*set)(struct inode *, void *), void *data)
> +{
> +       struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval);
> +       struct inode *old;
> +
> +again:
> +       spin_lock(&inode_hash_lock);
> +       old = find_inode(inode->i_sb, head, test, data);
> +       if (unlikely(old)) {
> +               /*
> +                * Uhhuh, somebody else created the same inode under us.
> +                * Use the old inode instead of the preallocated one.
> +                */
> +               spin_unlock(&inode_hash_lock);
> +               wait_on_inode(old);
> +               if (unlikely(inode_unhashed(old))) {
> +                       iput(old);
> +                       goto again;
> +               }
> +               return old;
> +       }
> +
> +       if (set && unlikely(set(inode, data))) {
> +               inode = NULL;
> +               goto unlock;
> +       }
> +
> +       /*
> +        * Return the locked inode with I_NEW set, the
> +        * caller is responsible for filling in the contents
> +        */
> +       spin_lock(&inode->i_lock);
> +       inode->i_state |= I_NEW;
> +       hlist_add_head(&inode->i_hash, head);
> +       spin_unlock(&inode->i_lock);
> +unlock:
> +       spin_unlock(&inode_hash_lock);
> +
> +       return inode;
> +}
> +EXPORT_SYMBOL(inode_insert5);
> +
> +/**
>   * iget5_locked - obtain an inode from a mounted file system
>   * @sb:                super block of file system
>   * @hashval:   hash value (usually inode number) to get
> @@ -1026,66 +1090,18 @@ struct inode *iget5_locked(struct super_
>                 int (*test)(struct inode *, void *),
>                 int (*set)(struct inode *, void *), void *data)
>  {
> -       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
> -       struct inode *inode;
> -again:
> -       spin_lock(&inode_hash_lock);
> -       inode = find_inode(sb, head, test, data);
> -       spin_unlock(&inode_hash_lock);
> -
> -       if (inode) {
> -               wait_on_inode(inode);
> -               if (unlikely(inode_unhashed(inode))) {
> -                       iput(inode);
> -                       goto again;
> -               }
> -               return inode;
> -       }
> +       struct inode *inode = ilookup5(sb, hashval, test, data);
>
> -       inode = alloc_inode(sb);
> -       if (inode) {
> -               struct inode *old;
> +       if (!inode) {
> +               struct inode *new = new_inode(sb);
>
> -               spin_lock(&inode_hash_lock);
> -               /* We released the lock, so.. */
> -               old = find_inode(sb, head, test, data);
> -               if (!old) {
> -                       if (set(inode, data))
> -                               goto set_failed;
> -
> -                       spin_lock(&inode->i_lock);
> -                       inode->i_state = I_NEW;
> -                       hlist_add_head(&inode->i_hash, head);
> -                       spin_unlock(&inode->i_lock);
> -                       inode_sb_list_add(inode);
> -                       spin_unlock(&inode_hash_lock);
> -
> -                       /* Return the locked inode with I_NEW set, the
> -                        * caller is responsible for filling in the contents
> -                        */
> -                       return inode;
> -               }
> -
> -               /*
> -                * Uhhuh, somebody else created the same inode under
> -                * us. Use the old inode instead of the one we just
> -                * allocated.
> -                */
> -               spin_unlock(&inode_hash_lock);
> -               destroy_inode(inode);
> -               inode = old;
> -               wait_on_inode(inode);
> -               if (unlikely(inode_unhashed(inode))) {
> -                       iput(inode);
> -                       goto again;
> +               if (new) {
> +                       inode = inode_insert5(new, hashval, test, set, data);
> +                       if (unlikely(inode != new))
> +                               iput(new);
>                 }
>         }
>         return inode;
> -
> -set_failed:
> -       spin_unlock(&inode_hash_lock);
> -       destroy_inode(inode);
> -       return NULL;
>  }
>  EXPORT_SYMBOL(iget5_locked);
>
> @@ -1426,43 +1442,13 @@ EXPORT_SYMBOL(insert_inode_locked);
>  int insert_inode_locked4(struct inode *inode, unsigned long hashval,
>                 int (*test)(struct inode *, void *), void *data)
>  {
> -       struct super_block *sb = inode->i_sb;
> -       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
> +       struct inode *old = inode_insert5(inode, hashval, test, NULL, data);
>
> -       while (1) {
> -               struct inode *old = NULL;
> -
> -               spin_lock(&inode_hash_lock);
> -               hlist_for_each_entry(old, head, i_hash) {
> -                       if (old->i_sb != sb)
> -                               continue;
> -                       if (!test(old, data))
> -                               continue;
> -                       spin_lock(&old->i_lock);
> -                       if (old->i_state & (I_FREEING|I_WILL_FREE)) {
> -                               spin_unlock(&old->i_lock);
> -                               continue;
> -                       }
> -                       break;
> -               }
> -               if (likely(!old)) {
> -                       spin_lock(&inode->i_lock);
> -                       inode->i_state |= I_NEW;
> -                       hlist_add_head(&inode->i_hash, head);
> -                       spin_unlock(&inode->i_lock);
> -                       spin_unlock(&inode_hash_lock);
> -                       return 0;
> -               }
> -               __iget(old);
> -               spin_unlock(&old->i_lock);
> -               spin_unlock(&inode_hash_lock);
> -               wait_on_inode(old);
> -               if (unlikely(!inode_unhashed(old))) {
> -                       iput(old);
> -                       return -EBUSY;
> -               }
> +       if (old != inode) {
>                 iput(old);
> +               return -EBUSY;
>         }
> +       return 0;
>  }
>  EXPORT_SYMBOL(insert_inode_locked4);
>
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2879,6 +2879,10 @@ extern struct inode *ilookup5(struct sup
>                 int (*test)(struct inode *, void *), void *data);
>  extern struct inode *ilookup(struct super_block *sb, unsigned long ino);
>
> +extern struct inode *inode_insert5(struct inode *inode, unsigned long hashval,
> +               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 *);
>  extern struct inode * iget_locked(struct super_block *, unsigned long);
>  extern struct inode *find_inode_nowait(struct super_block *,
--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux