xfs: add background scanning to clear eofblocks inodes
authorBrian Foster <bfoster@redhat.com>
Tue, 6 Nov 2012 14:50:47 +0000 (09:50 -0500)
committerBen Myers <bpm@sgi.com>
Thu, 8 Nov 2012 21:34:59 +0000 (15:34 -0600)
Create a new mount workqueue and delayed_work to enable background
scanning and freeing of eofblocks inodes. The scanner kicks in once
speculative preallocation occurs and stops requeueing itself when
no eofblocks inodes exist.

The scan interval is based on the new
'speculative_prealloc_lifetime' tunable (default to 5m). The
background scanner performs unfiltered, best effort scans (which
skips inodes under lock contention or with a dirty cache mapping).

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
fs/xfs/xfs_globals.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_linux.h
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_super.c
fs/xfs/xfs_sysctl.c
fs/xfs/xfs_sysctl.h

index 76e81cff70b9a71b2f3a9a5c3d2487a437992fa1..5399ef222dd738b85d39096ac7db5a39ebb8c359 100644 (file)
@@ -21,7 +21,8 @@
 /*
  * Tunable XFS parameters.  xfs_params is required even when CONFIG_SYSCTL=n,
  * other XFS code uses these values.  Times are measured in centisecs (i.e.
- * 100ths of a second).
+ * 100ths of a second) with the exception of eofb_timer, which is measured in
+ * seconds.
  */
 xfs_param_t xfs_params = {
                          /*    MIN             DFLT            MAX     */
@@ -40,4 +41,5 @@ xfs_param_t xfs_params = {
        .rotorstep      = {     1,              1,              255     },
        .inherit_nodfrg = {     0,              1,              1       },
        .fstrm_timer    = {     1,              30*100,         3600*100},
+       .eofb_timer     = {     1,              300,            3600*24},
 };
index 906e6dcd2c55fa51ee929cf30cb2e5cf140a0c0c..96e344e3e9277fdc0bb307d04d8945d81602c70a 100644 (file)
@@ -615,6 +615,32 @@ restart:
        return last_error;
 }
 
+/*
+ * Background scanning to trim post-EOF preallocated space. This is queued
+ * based on the 'background_prealloc_discard_period' tunable (5m by default).
+ */
+STATIC void
+xfs_queue_eofblocks(
+       struct xfs_mount *mp)
+{
+       rcu_read_lock();
+       if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_EOFBLOCKS_TAG))
+               queue_delayed_work(mp->m_eofblocks_workqueue,
+                                  &mp->m_eofblocks_work,
+                                  msecs_to_jiffies(xfs_eofb_secs * 1000));
+       rcu_read_unlock();
+}
+
+void
+xfs_eofblocks_worker(
+       struct work_struct *work)
+{
+       struct xfs_mount *mp = container_of(to_delayed_work(work),
+                               struct xfs_mount, m_eofblocks_work);
+       xfs_icache_free_eofblocks(mp, NULL);
+       xfs_queue_eofblocks(mp);
+}
+
 int
 xfs_inode_ag_iterator(
        struct xfs_mount        *mp,
@@ -1273,6 +1299,9 @@ xfs_inode_set_eofblocks_tag(
                                   XFS_ICI_EOFBLOCKS_TAG);
                spin_unlock(&ip->i_mount->m_perag_lock);
 
+               /* kick off background trimming */
+               xfs_queue_eofblocks(ip->i_mount);
+
                trace_xfs_perag_set_eofblocks(ip->i_mount, pag->pag_agno,
                                              -1, _RET_IP_);
        }
index 4934a77024cfbfee16607ebf307eb6167e4c3314..e0f138c70a2ff666e5b831651c875e2545e66a2c 100644 (file)
@@ -38,6 +38,7 @@ void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
 void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
 void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
 int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
+void xfs_eofblocks_worker(struct work_struct *);
 
 int xfs_sync_inode_grab(struct xfs_inode *ip);
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
index 828662f70d64ec2f0bf43a66a6832c77debbdf18..0a134ca5211cf65e835aecfb07790fe717b083c9 100644 (file)
 #define xfs_rotorstep          xfs_params.rotorstep.val
 #define xfs_inherit_nodefrag   xfs_params.inherit_nodfrg.val
 #define xfs_fstrm_centisecs    xfs_params.fstrm_timer.val
+#define xfs_eofb_secs          xfs_params.eofb_timer.val
 
 #define current_cpu()          (raw_smp_processor_id())
 #define current_pid()          (current->pid)
index 6f1c997704cdc8c8065a907dc4e7096d256fe3b4..41ae7e1590f5d82dda98e4b0fe29b89c3abfbf10 100644 (file)
@@ -1428,6 +1428,8 @@ xfs_unmountfs(
        __uint64_t              resblks;
        int                     error;
 
+       cancel_delayed_work_sync(&mp->m_eofblocks_work);
+
        xfs_qm_unmount_quotas(mp);
        xfs_rtunmount_inodes(mp);
        IRELE(mp->m_rootip);
index a631ca3b9065469d39a688da1f906bc6a6063bf2..dc306a09f56fa8338d055b2fa5f843975c4ab520 100644 (file)
@@ -196,6 +196,8 @@ typedef struct xfs_mount {
 #endif
        struct xfs_mru_cache    *m_filestream;  /* per-mount filestream data */
        struct delayed_work     m_reclaim_work; /* background inode reclaim */
+       struct delayed_work     m_eofblocks_work; /* background eof blocks
+                                                    trimming */
        __int64_t               m_update_flags; /* sb flags we need to update
                                                   on the next remount,rw */
        struct shrinker         m_inode_shrink; /* inode reclaim shrinker */
@@ -207,6 +209,7 @@ typedef struct xfs_mount {
        struct workqueue_struct *m_cil_workqueue;
        struct workqueue_struct *m_reclaim_workqueue;
        struct workqueue_struct *m_log_workqueue;
+       struct workqueue_struct *m_eofblocks_workqueue;
 } xfs_mount_t;
 
 /*
index 3d9ea947e9f80d347518c98081be7c645799a8fa..ab8839b262725dd8a36482aee672288f9f052655 100644 (file)
@@ -874,8 +874,15 @@ xfs_init_mount_workqueues(
        if (!mp->m_log_workqueue)
                goto out_destroy_reclaim;
 
+       mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
+                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+       if (!mp->m_eofblocks_workqueue)
+               goto out_destroy_log;
+
        return 0;
 
+out_destroy_log:
+       destroy_workqueue(mp->m_log_workqueue);
 out_destroy_reclaim:
        destroy_workqueue(mp->m_reclaim_workqueue);
 out_destroy_cil:
@@ -892,6 +899,7 @@ STATIC void
 xfs_destroy_mount_workqueues(
        struct xfs_mount        *mp)
 {
+       destroy_workqueue(mp->m_eofblocks_workqueue);
        destroy_workqueue(mp->m_log_workqueue);
        destroy_workqueue(mp->m_reclaim_workqueue);
        destroy_workqueue(mp->m_cil_workqueue);
@@ -1393,6 +1401,7 @@ xfs_fs_fill_super(
        mutex_init(&mp->m_growlock);
        atomic_set(&mp->m_active_trans, 0);
        INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
+       INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
 
        mp->m_super = sb;
        sb->s_fs_info = mp;
index ee2d2adaa438121a1c875a5a7dda6b96f16c20c0..2801b5ce6cdb61d9ba03a1b518561a64924a7068 100644 (file)
@@ -202,6 +202,15 @@ static ctl_table xfs_table[] = {
                .extra1         = &xfs_params.fstrm_timer.min,
                .extra2         = &xfs_params.fstrm_timer.max,
        },
+       {
+               .procname       = "speculative_prealloc_lifetime",
+               .data           = &xfs_params.eofb_timer.val,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &xfs_params.eofb_timer.min,
+               .extra2         = &xfs_params.eofb_timer.max,
+       },
        /* please keep this the last entry */
 #ifdef CONFIG_PROC_FS
        {
index b9937d450f8e6d72e01e186c09f446c791028ef2..bd8e157c20efa254c736952967e6c894dbd706a0 100644 (file)
@@ -47,6 +47,7 @@ typedef struct xfs_param {
        xfs_sysctl_val_t rotorstep;     /* inode32 AG rotoring control knob */
        xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */
        xfs_sysctl_val_t fstrm_timer;   /* Filestream dir-AG assoc'n timeout. */
+       xfs_sysctl_val_t eofb_timer;    /* Interval between eofb scan wakeups */
 } xfs_param_t;
 
 /*