diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-07-06 16:34:10 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2020-05-06 17:14:14 -0400 |
commit | b6e70e2d20460c9ddc2241111f8f0aa8d2e2bc12 (patch) | |
tree | 43b80e904aa71adacb7716393bb61319b05dfee5 | |
parent | 2a1703857c5a347fe50ea1d984882b0ceb765031 (diff) |
fs: insert_inode_locked2()
New helper for bcachefs, so that when we race inserting an inode we can
atomically grab a ref to the inode already in the inode cache.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | fs/inode.c | 40 | ||||
-rw-r--r-- | include/linux/fs.h | 1 |
2 files changed, 41 insertions, 0 deletions
diff --git a/fs/inode.c b/fs/inode.c index 2c7d26015b3b..6dec6f6336ce 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1487,6 +1487,46 @@ int insert_inode_locked(struct inode *inode) } EXPORT_SYMBOL(insert_inode_locked); +struct inode *insert_inode_locked2(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + ino_t ino = inode->i_ino; + struct hlist_head *head = inode_hashtable + hash(sb, ino); + + while (1) { + struct inode *old = NULL; + spin_lock(&inode_hash_lock); + hlist_for_each_entry(old, head, i_hash) { + if (old->i_ino != ino) + continue; + if (old->i_sb != sb) + 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 | I_CREATING; + hlist_add_head(&inode->i_hash, head); + spin_unlock(&inode->i_lock); + spin_unlock(&inode_hash_lock); + return NULL; + } + __iget(old); + spin_unlock(&old->i_lock); + spin_unlock(&inode_hash_lock); + wait_on_inode(old); + if (unlikely(!inode_unhashed(old))) + return old; + iput(old); + } +} +EXPORT_SYMBOL(insert_inode_locked2); + int insert_inode_locked4(struct inode *inode, unsigned long hashval, int (*test)(struct inode *, void *), void *data) { diff --git a/include/linux/fs.h b/include/linux/fs.h index da0ca2d972d9..207ccf1b9bfe 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2961,6 +2961,7 @@ extern struct inode *find_inode_nowait(struct super_block *, void *data); extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *); extern int insert_inode_locked(struct inode *); +extern struct inode *insert_inode_locked2(struct inode *); #ifdef CONFIG_DEBUG_LOCK_ALLOC extern void lockdep_annotate_inode_mutex_key(struct inode *inode); #else |