xfs: reset inode per-lifetime state when recycling it
authorDave Chinner <dchinner@redhat.com>
Thu, 23 Jun 2011 01:34:59 +0000 (01:34 +0000)
committerAlex Elder <aelder@sgi.com>
Fri, 24 Jun 2011 03:13:31 +0000 (22:13 -0500)
XFS inodes has several per-lifetime state fields that determine the
behaviour of the inode. These state fields are not all reset when an
inode is reused from the reclaimable state.

This can lead to unexpected behaviour of the new inode such as
speculative preallocation not being truncated away in the expected
manner for local files until the inode is subsequently truncated,
freed or cycles out of the cache. It can also lead to an inode being
considered to be a filestream inode or having been truncated when
that is not the case.

Rework the reinitialisation of the inode when it is recycled to
ensure that it is pristine before it is reused. While there, also
fix the resetting of state flags in the recycling error paths so the
inode does not become unreclaimable.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Alex Elder <aelder@sgi.com>
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.h

index cb9b6d1469f7579256061f6de61755c0d6b63df6..3631783b2b5385ee939a61e5cafd5b06ef6b0a45 100644 (file)
@@ -253,16 +253,21 @@ xfs_iget_cache_hit(
                        rcu_read_lock();
                        spin_lock(&ip->i_flags_lock);
 
-                       ip->i_flags &= ~XFS_INEW;
-                       ip->i_flags |= XFS_IRECLAIMABLE;
-                       __xfs_inode_set_reclaim_tag(pag, ip);
+                       ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM);
+                       ASSERT(ip->i_flags & XFS_IRECLAIMABLE);
                        trace_xfs_iget_reclaim_fail(ip);
                        goto out_error;
                }
 
                spin_lock(&pag->pag_ici_lock);
                spin_lock(&ip->i_flags_lock);
-               ip->i_flags &= ~(XFS_IRECLAIMABLE | XFS_IRECLAIM);
+
+               /*
+                * Clear the per-lifetime state in the inode as we are now
+                * effectively a new inode and need to return to the initial
+                * state before reuse occurs.
+                */
+               ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS;
                ip->i_flags |= XFS_INEW;
                __xfs_inode_clear_reclaim_tag(mp, pag, ip);
                inode->i_state = I_NEW;
index 3ae6d58e54739b42b8ff5ff49dfaad7648201add..964cfea776868684afb26f818b8a761ce652b1b5 100644 (file)
@@ -383,6 +383,16 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
 #define XFS_ITRUNCATED         0x0020  /* truncated down so flush-on-close */
 #define XFS_IDIRTY_RELEASE     0x0040  /* dirty release already seen */
 
+/*
+ * Per-lifetime flags need to be reset when re-using a reclaimable inode during
+ * inode lookup. Thi prevents unintended behaviour on the new inode from
+ * ocurring.
+ */
+#define XFS_IRECLAIM_RESET_FLAGS       \
+       (XFS_IRECLAIMABLE | XFS_IRECLAIM | \
+        XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | \
+        XFS_IFILESTREAM);
+
 /*
  * Flags for inode locking.
  * Bit ranges: 1<<1  - 1<<16-1 -- iolock/ilock modes (bitfield)