Merge tag 'xfs-4.13-merge-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[muen/linux.git] / fs / xfs / xfs_icache.c
index b9c12e1cc23a5d39e64362203b6b1852d7659b35..0a9e6985a0d092ff8493347c597b1b509c9048ef 100644 (file)
@@ -368,6 +368,11 @@ xfs_iget_cache_hit(
        if (ip->i_flags & XFS_IRECLAIMABLE) {
                trace_xfs_iget_reclaim(ip);
 
+               if (flags & XFS_IGET_INCORE) {
+                       error = -EAGAIN;
+                       goto out_error;
+               }
+
                /*
                 * We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode
                 * from stomping over us while we recycle the inode.  We can't
@@ -432,7 +437,8 @@ xfs_iget_cache_hit(
        if (lock_flags != 0)
                xfs_ilock(ip, lock_flags);
 
-       xfs_iflags_clear(ip, XFS_ISTALE | XFS_IDONTCACHE);
+       if (!(flags & XFS_IGET_INCORE))
+               xfs_iflags_clear(ip, XFS_ISTALE | XFS_IDONTCACHE);
        XFS_STATS_INC(mp, xs_ig_found);
 
        return 0;
@@ -603,6 +609,10 @@ again:
                        goto out_error_or_again;
        } else {
                rcu_read_unlock();
+               if (flags & XFS_IGET_INCORE) {
+                       error = -ENOENT;
+                       goto out_error_or_again;
+               }
                XFS_STATS_INC(mp, xs_ig_missed);
 
                error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip,
@@ -623,7 +633,7 @@ again:
        return 0;
 
 out_error_or_again:
-       if (error == -EAGAIN) {
+       if (!(flags & XFS_IGET_INCORE) && error == -EAGAIN) {
                delay(1);
                goto again;
        }
@@ -631,6 +641,44 @@ out_error_or_again:
        return error;
 }
 
+/*
+ * "Is this a cached inode that's also allocated?"
+ *
+ * Look up an inode by number in the given file system.  If the inode is
+ * in cache and isn't in purgatory, return 1 if the inode is allocated
+ * and 0 if it is not.  For all other cases (not in cache, being torn
+ * down, etc.), return a negative error code.
+ *
+ * The caller has to prevent inode allocation and freeing activity,
+ * presumably by locking the AGI buffer.   This is to ensure that an
+ * inode cannot transition from allocated to freed until the caller is
+ * ready to allow that.  If the inode is in an intermediate state (new,
+ * reclaimable, or being reclaimed), -EAGAIN will be returned; if the
+ * inode is not in the cache, -ENOENT will be returned.  The caller must
+ * deal with these scenarios appropriately.
+ *
+ * This is a specialized use case for the online scrubber; if you're
+ * reading this, you probably want xfs_iget.
+ */
+int
+xfs_icache_inode_is_allocated(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       xfs_ino_t               ino,
+       bool                    *inuse)
+{
+       struct xfs_inode        *ip;
+       int                     error;
+
+       error = xfs_iget(mp, tp, ino, XFS_IGET_INCORE, 0, &ip);
+       if (error)
+               return error;
+
+       *inuse = !!(VFS_I(ip)->i_mode);
+       IRELE(ip);
+       return 0;
+}
+
 /*
  * The inode lookup is done in batches to keep the amount of lock traffic and
  * radix tree lookups to a minimum. The batch size is a trade off between