diff mbox

[PATCH-v9,2/3] vfs: add find_inode_nowait() function

Message ID 1422855422-7444-3-git-send-email-tytso@mit.edu (mailing list archive)
State New, archived
Headers show

Commit Message

Theodore Ts'o Feb. 2, 2015, 5:37 a.m. UTC
Add a new function find_inode_nowait() which is an even more general
version of ilookup5_nowait().  It is designed for callers which need
very fine grained control over when the function is allowed to block
or increment the inode's reference count.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 fs/inode.c         | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  5 +++++
 2 files changed, 55 insertions(+)

Comments

Michael Kerrisk (man-pages) Feb. 2, 2015, 6:04 a.m. UTC | #1
[CC += linux-api@]

On Mon, Feb 2, 2015 at 6:37 AM, Theodore Ts'o <tytso@mit.edu> wrote:
> Add a new function find_inode_nowait() which is an even more general
> version of ilookup5_nowait().  It is designed for callers which need
> very fine grained control over when the function is allowed to block
> or increment the inode's reference count.
>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
>  fs/inode.c         | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/fs.h |  5 +++++
>  2 files changed, 55 insertions(+)
>
> diff --git a/fs/inode.c b/fs/inode.c
> index 4feb85c..740cba7 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -1284,6 +1284,56 @@ struct inode *ilookup(struct super_block *sb, unsigned long ino)
>  }
>  EXPORT_SYMBOL(ilookup);
>
> +/**
> + * find_inode_nowait - find an inode in the inode cache
> + * @sb:                super block of file system to search
> + * @hashval:   hash value (usually inode number) to search for
> + * @match:     callback used for comparisons between inodes
> + * @data:      opaque data pointer to pass to @match
> + *
> + * Search for the inode specified by @hashval and @data in the inode
> + * cache, where the helper function @match will return 0 if the inode
> + * does not match, 1 if the inode does match, and -1 if the search
> + * should be stopped.  The @match function must be responsible for
> + * taking the i_lock spin_lock and checking i_state for an inode being
> + * freed or being initialized, and incrementing the reference count
> + * before returning 1.  It also must not sleep, since it is called with
> + * the inode_hash_lock spinlock held.
> + *
> + * This is a even more generalized version of ilookup5() when the
> + * function must never block --- find_inode() can block in
> + * __wait_on_freeing_inode() --- or when the caller can not increment
> + * the reference count because the resulting iput() might cause an
> + * inode eviction.  The tradeoff is that the @match funtion must be
> + * very carefully implemented.
> + */
> +struct inode *find_inode_nowait(struct super_block *sb,
> +                               unsigned long hashval,
> +                               int (*match)(struct inode *, unsigned long,
> +                                            void *),
> +                               void *data)
> +{
> +       struct hlist_head *head = inode_hashtable + hash(sb, hashval);
> +       struct inode *inode, *ret_inode = NULL;
> +       int mval;
> +
> +       spin_lock(&inode_hash_lock);
> +       hlist_for_each_entry(inode, head, i_hash) {
> +               if (inode->i_sb != sb)
> +                       continue;
> +               mval = match(inode, hashval, data);
> +               if (mval == 0)
> +                       continue;
> +               if (mval == 1)
> +                       ret_inode = inode;
> +               goto out;
> +       }
> +out:
> +       spin_unlock(&inode_hash_lock);
> +       return ret_inode;
> +}
> +EXPORT_SYMBOL(find_inode_nowait);
> +
>  int insert_inode_locked(struct inode *inode)
>  {
>         struct super_block *sb = inode->i_sb;
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 5ca285f..af810cc 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2441,6 +2441,11 @@ extern struct inode *ilookup(struct super_block *sb, unsigned long ino);
>
>  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 *,
> +                                      unsigned long,
> +                                      int (*match)(struct inode *,
> +                                                   unsigned long, void *),
> +                                      void *data);
>  extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
>  extern int insert_inode_locked(struct inode *);
>  #ifdef CONFIG_DEBUG_LOCK_ALLOC
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/inode.c b/fs/inode.c
index 4feb85c..740cba7 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1284,6 +1284,56 @@  struct inode *ilookup(struct super_block *sb, unsigned long ino)
 }
 EXPORT_SYMBOL(ilookup);
 
+/**
+ * find_inode_nowait - find an inode in the inode cache
+ * @sb:		super block of file system to search
+ * @hashval:	hash value (usually inode number) to search for
+ * @match:	callback used for comparisons between inodes
+ * @data:	opaque data pointer to pass to @match
+ *
+ * Search for the inode specified by @hashval and @data in the inode
+ * cache, where the helper function @match will return 0 if the inode
+ * does not match, 1 if the inode does match, and -1 if the search
+ * should be stopped.  The @match function must be responsible for
+ * taking the i_lock spin_lock and checking i_state for an inode being
+ * freed or being initialized, and incrementing the reference count
+ * before returning 1.  It also must not sleep, since it is called with
+ * the inode_hash_lock spinlock held.
+ *
+ * This is a even more generalized version of ilookup5() when the
+ * function must never block --- find_inode() can block in
+ * __wait_on_freeing_inode() --- or when the caller can not increment
+ * the reference count because the resulting iput() might cause an
+ * inode eviction.  The tradeoff is that the @match funtion must be
+ * very carefully implemented.
+ */
+struct inode *find_inode_nowait(struct super_block *sb,
+				unsigned long hashval,
+				int (*match)(struct inode *, unsigned long,
+					     void *),
+				void *data)
+{
+	struct hlist_head *head = inode_hashtable + hash(sb, hashval);
+	struct inode *inode, *ret_inode = NULL;
+	int mval;
+
+	spin_lock(&inode_hash_lock);
+	hlist_for_each_entry(inode, head, i_hash) {
+		if (inode->i_sb != sb)
+			continue;
+		mval = match(inode, hashval, data);
+		if (mval == 0)
+			continue;
+		if (mval == 1)
+			ret_inode = inode;
+		goto out;
+	}
+out:
+	spin_unlock(&inode_hash_lock);
+	return ret_inode;
+}
+EXPORT_SYMBOL(find_inode_nowait);
+
 int insert_inode_locked(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 5ca285f..af810cc 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2441,6 +2441,11 @@  extern struct inode *ilookup(struct super_block *sb, unsigned long ino);
 
 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 *,
+				       unsigned long,
+				       int (*match)(struct inode *,
+						    unsigned long, void *),
+				       void *data);
 extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
 extern int insert_inode_locked(struct inode *);
 #ifdef CONFIG_DEBUG_LOCK_ALLOC