xfs
[Top] [All Lists]

[PATCH v3 3/8] xfs: create helper to check whether to free eofblocks on

To: xfs@xxxxxxxxxxx
Subject: [PATCH v3 3/8] xfs: create helper to check whether to free eofblocks on inode
From: Brian Foster <bfoster@xxxxxxxxxx>
Date: Fri, 14 Sep 2012 08:19:50 -0400
In-reply-to: <1347625195-6369-1-git-send-email-bfoster@xxxxxxxxxx>
References: <1347625195-6369-1-git-send-email-bfoster@xxxxxxxxxx>
This check is used in multiple places to determine whether we
should check for (and potentially free) post EOF blocks on an
inode. Add a helper to consolidate the check.

Note that when we remove an inode from the cache (xfs_inactive()),
we are required to trim post-EOF blocks even if the inode is marked
preallocated or append-only to maintain correct space accounting.
The 'force' parameter to xfs_can_free_eofblocks() specifies whether
we should ignore the prealloc/append-only status of the inode.

Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx>
---
 fs/xfs/xfs_vnodeops.c |   19 +++++++------------
 fs/xfs/xfs_vnodeops.h |   40 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index d883881..12f5087 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -435,11 +435,7 @@ xfs_release(
        if (ip->i_d.di_nlink == 0)
                return 0;
 
-       if ((S_ISREG(ip->i_d.di_mode) &&
-            (VFS_I(ip)->i_size > 0 ||
-             (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
-            (ip->i_df.if_flags & XFS_IFEXTENTS))  &&
-           (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
+       if (xfs_can_free_eofblocks(ip, false)) {
 
                /*
                 * If we can't get the iolock just skip truncating the blocks
@@ -515,13 +511,12 @@ xfs_inactive(
                goto out;
 
        if (ip->i_d.di_nlink != 0) {
-               if ((S_ISREG(ip->i_d.di_mode) &&
-                   (VFS_I(ip)->i_size > 0 ||
-                    (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) &&
-                   (ip->i_df.if_flags & XFS_IFEXTENTS) &&
-                   (!(ip->i_d.di_flags &
-                               (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
-                    ip->i_delayed_blks != 0))) {
+               /*
+                * force is true because we are evicting an inode from the
+                * cache. Post-eof blocks must be freed, lest we end up with
+                * broken free space accounting.
+                */
+               if (xfs_can_free_eofblocks(ip, true)) {
                        error = xfs_free_eofblocks(mp, ip, false);
                        if (error)
                                return VN_INACTIVE_CACHE;
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index 447e146..d5701e3 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -1,6 +1,10 @@
 #ifndef _XFS_VNODEOPS_H
 #define _XFS_VNODEOPS_H 1
 
+#include "xfs_bmap_btree.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+
 struct attrlist_cursor_kern;
 struct file;
 struct iattr;
@@ -9,8 +13,42 @@ struct iovec;
 struct kiocb;
 struct pipe_inode_info;
 struct uio;
-struct xfs_inode;
 
+/*
+ * Test whether it is appropriate to check an inode for and free post EOF
+ * blocks. The 'force' parameter determines whether we should also consider
+ * regular files that are marked preallocated or append-only.
+ */
+static inline bool
+xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
+{
+       /* prealloc/delalloc exists only on regular files */
+       if (!S_ISREG(ip->i_d.di_mode))
+               return false;
+
+       /*
+        * Zero sized files with no cached pages and delalloc blocks will not
+        * have speculative prealloc/delalloc blocks to remove.
+        */
+       if (VFS_I(ip)->i_size == 0 &&
+           VN_CACHED(VFS_I(ip)) == 0 &&
+           ip->i_delayed_blks == 0)
+               return false;
+
+       /* If we haven't read in the extent list, then don't do it now. */
+       if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
+               return false;
+
+       /*
+        * Do not free real preallocated or append-only files unless the file
+        * has delalloc blocks and we are forced to remove them.
+        */
+       if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
+               if (!force || ip->i_delayed_blks == 0)
+                       return false;
+
+       return true;
+}
 
 int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags);
 int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap, int flags);
-- 
1.7.7.6

<Prev in Thread] Current Thread [Next in Thread>