diff options
author | Dave Chinner <dchinner@redhat.com> | 2011-04-07 22:45:07 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2011-04-07 22:45:07 -0400 |
commit | fd074841cfe01b006465fb9388091012585e8dfb (patch) | |
tree | 7ec409fade00b6c18987e1cb2a62443c074ce274 /fs | |
parent | cd4a3c503c185f5f0a20f04f90da0a6966dd03bd (diff) |
xfs: push the AIL from memory reclaim and periodic sync
When we are short on memory, we want to expedite the cleaning of
dirty objects. Hence when we run short on memory, we need to kick
the AIL flushing into action to clean as many dirty objects as
quickly as possible. To implement this, sample the lsn of the log
item at the head of the AIL and use that as the push target for the
AIL flush.
Further, we keep items in the AIL that are dirty that are not
tracked any other way, so we can get objects sitting in the AIL that
don't get written back until the AIL is pushed. Hence to get the
filesystem to the idle state, we might need to push the AIL to flush
out any remaining dirty objects sitting in the AIL. This requires
the same push mechanism as the reclaim push.
This patch also renames xfs_trans_ail_tail() to xfs_ail_min_lsn() to
match the new xfs_ail_max_lsn() function introduced in this patch.
Similarly for xfs_trans_ail_push -> xfs_ail_push.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_log.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 50 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_priv.h | 7 |
4 files changed, 61 insertions, 9 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index debe2822c930..9ad956052b69 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "xfs_log.h" | 22 | #include "xfs_log.h" |
23 | #include "xfs_inum.h" | 23 | #include "xfs_inum.h" |
24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
25 | #include "xfs_trans_priv.h" | ||
25 | #include "xfs_sb.h" | 26 | #include "xfs_sb.h" |
26 | #include "xfs_ag.h" | 27 | #include "xfs_ag.h" |
27 | #include "xfs_mount.h" | 28 | #include "xfs_mount.h" |
@@ -462,6 +463,9 @@ xfs_sync_worker( | |||
462 | else | 463 | else |
463 | xfs_log_force(mp, 0); | 464 | xfs_log_force(mp, 0); |
464 | error = xfs_qm_sync(mp, SYNC_TRYLOCK); | 465 | error = xfs_qm_sync(mp, SYNC_TRYLOCK); |
466 | |||
467 | /* start pushing all the metadata that is currently dirty */ | ||
468 | xfs_ail_push_all(mp->m_ail); | ||
465 | } | 469 | } |
466 | 470 | ||
467 | /* queue us up again */ | 471 | /* queue us up again */ |
@@ -1027,8 +1031,9 @@ xfs_reclaim_inode_shrink( | |||
1027 | 1031 | ||
1028 | mp = container_of(shrink, struct xfs_mount, m_inode_shrink); | 1032 | mp = container_of(shrink, struct xfs_mount, m_inode_shrink); |
1029 | if (nr_to_scan) { | 1033 | if (nr_to_scan) { |
1030 | /* kick background reclaimer */ | 1034 | /* kick background reclaimer and push the AIL */ |
1031 | xfs_syncd_queue_reclaim(mp); | 1035 | xfs_syncd_queue_reclaim(mp); |
1036 | xfs_ail_push_all(mp->m_ail); | ||
1032 | 1037 | ||
1033 | if (!(gfp_mask & __GFP_FS)) | 1038 | if (!(gfp_mask & __GFP_FS)) |
1034 | return -1; | 1039 | return -1; |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 25efa9b8a602..24643169e632 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
@@ -761,7 +761,7 @@ xfs_log_need_covered(xfs_mount_t *mp) | |||
761 | break; | 761 | break; |
762 | case XLOG_STATE_COVER_NEED: | 762 | case XLOG_STATE_COVER_NEED: |
763 | case XLOG_STATE_COVER_NEED2: | 763 | case XLOG_STATE_COVER_NEED2: |
764 | if (!xfs_trans_ail_tail(log->l_ailp) && | 764 | if (!xfs_ail_min_lsn(log->l_ailp) && |
765 | xlog_iclogs_empty(log)) { | 765 | xlog_iclogs_empty(log)) { |
766 | if (log->l_covered_state == XLOG_STATE_COVER_NEED) | 766 | if (log->l_covered_state == XLOG_STATE_COVER_NEED) |
767 | log->l_covered_state = XLOG_STATE_COVER_DONE; | 767 | log->l_covered_state = XLOG_STATE_COVER_DONE; |
@@ -801,7 +801,7 @@ xlog_assign_tail_lsn( | |||
801 | xfs_lsn_t tail_lsn; | 801 | xfs_lsn_t tail_lsn; |
802 | struct log *log = mp->m_log; | 802 | struct log *log = mp->m_log; |
803 | 803 | ||
804 | tail_lsn = xfs_trans_ail_tail(mp->m_ail); | 804 | tail_lsn = xfs_ail_min_lsn(mp->m_ail); |
805 | if (!tail_lsn) | 805 | if (!tail_lsn) |
806 | tail_lsn = atomic64_read(&log->l_last_sync_lsn); | 806 | tail_lsn = atomic64_read(&log->l_last_sync_lsn); |
807 | 807 | ||
@@ -1239,7 +1239,7 @@ xlog_grant_push_ail( | |||
1239 | * the filesystem is shutting down. | 1239 | * the filesystem is shutting down. |
1240 | */ | 1240 | */ |
1241 | if (!XLOG_FORCED_SHUTDOWN(log)) | 1241 | if (!XLOG_FORCED_SHUTDOWN(log)) |
1242 | xfs_trans_ail_push(log->l_ailp, threshold_lsn); | 1242 | xfs_ail_push(log->l_ailp, threshold_lsn); |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | /* | 1245 | /* |
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 8012bfbc6dc0..acdb92f14d51 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -90,6 +90,20 @@ xfs_ail_min( | |||
90 | return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); | 90 | return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); |
91 | } | 91 | } |
92 | 92 | ||
93 | /* | ||
94 | * Return a pointer to the last item in the AIL. If the AIL is empty, then | ||
95 | * return NULL. | ||
96 | */ | ||
97 | static xfs_log_item_t * | ||
98 | xfs_ail_max( | ||
99 | struct xfs_ail *ailp) | ||
100 | { | ||
101 | if (list_empty(&ailp->xa_ail)) | ||
102 | return NULL; | ||
103 | |||
104 | return list_entry(ailp->xa_ail.prev, xfs_log_item_t, li_ail); | ||
105 | } | ||
106 | |||
93 | /* | 107 | /* |
94 | * Return a pointer to the item which follows the given item in the AIL. If | 108 | * Return a pointer to the item which follows the given item in the AIL. If |
95 | * the given item is the last item in the list, then return NULL. | 109 | * the given item is the last item in the list, then return NULL. |
@@ -114,7 +128,7 @@ xfs_ail_next( | |||
114 | * item in the AIL. | 128 | * item in the AIL. |
115 | */ | 129 | */ |
116 | xfs_lsn_t | 130 | xfs_lsn_t |
117 | xfs_trans_ail_tail( | 131 | xfs_ail_min_lsn( |
118 | struct xfs_ail *ailp) | 132 | struct xfs_ail *ailp) |
119 | { | 133 | { |
120 | xfs_lsn_t lsn = 0; | 134 | xfs_lsn_t lsn = 0; |
@@ -130,6 +144,25 @@ xfs_trans_ail_tail( | |||
130 | } | 144 | } |
131 | 145 | ||
132 | /* | 146 | /* |
147 | * Return the maximum lsn held in the AIL, or zero if the AIL is empty. | ||
148 | */ | ||
149 | static xfs_lsn_t | ||
150 | xfs_ail_max_lsn( | ||
151 | struct xfs_ail *ailp) | ||
152 | { | ||
153 | xfs_lsn_t lsn = 0; | ||
154 | xfs_log_item_t *lip; | ||
155 | |||
156 | spin_lock(&ailp->xa_lock); | ||
157 | lip = xfs_ail_max(ailp); | ||
158 | if (lip) | ||
159 | lsn = lip->li_lsn; | ||
160 | spin_unlock(&ailp->xa_lock); | ||
161 | |||
162 | return lsn; | ||
163 | } | ||
164 | |||
165 | /* | ||
133 | * AIL traversal cursor initialisation. | 166 | * AIL traversal cursor initialisation. |
134 | * | 167 | * |
135 | * The cursor keeps track of where our current traversal is up | 168 | * The cursor keeps track of where our current traversal is up |
@@ -504,7 +537,7 @@ xfs_ail_worker( | |||
504 | * any of the objects, so the lock is not needed. | 537 | * any of the objects, so the lock is not needed. |
505 | */ | 538 | */ |
506 | void | 539 | void |
507 | xfs_trans_ail_push( | 540 | xfs_ail_push( |
508 | struct xfs_ail *ailp, | 541 | struct xfs_ail *ailp, |
509 | xfs_lsn_t threshold_lsn) | 542 | xfs_lsn_t threshold_lsn) |
510 | { | 543 | { |
@@ -526,6 +559,19 @@ xfs_trans_ail_push( | |||
526 | } | 559 | } |
527 | 560 | ||
528 | /* | 561 | /* |
562 | * Push out all items in the AIL immediately | ||
563 | */ | ||
564 | void | ||
565 | xfs_ail_push_all( | ||
566 | struct xfs_ail *ailp) | ||
567 | { | ||
568 | xfs_lsn_t threshold_lsn = xfs_ail_max_lsn(ailp); | ||
569 | |||
570 | if (threshold_lsn) | ||
571 | xfs_ail_push(ailp, threshold_lsn); | ||
572 | } | ||
573 | |||
574 | /* | ||
529 | * This is to be called when an item is unlocked that may have | 575 | * This is to be called when an item is unlocked that may have |
530 | * been in the AIL. It will wake up the first member of the AIL | 576 | * been in the AIL. It will wake up the first member of the AIL |
531 | * wait list if this item's unlocking might allow it to progress. | 577 | * wait list if this item's unlocking might allow it to progress. |
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 6ebd322bd37c..6b164e9e9a1f 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h | |||
@@ -104,12 +104,13 @@ xfs_trans_ail_delete( | |||
104 | xfs_trans_ail_delete_bulk(ailp, &lip, 1); | 104 | xfs_trans_ail_delete_bulk(ailp, &lip, 1); |
105 | } | 105 | } |
106 | 106 | ||
107 | void xfs_trans_ail_push(struct xfs_ail *, xfs_lsn_t); | 107 | void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); |
108 | void xfs_ail_push_all(struct xfs_ail *); | ||
109 | xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp); | ||
110 | |||
108 | void xfs_trans_unlocked_item(struct xfs_ail *, | 111 | void xfs_trans_unlocked_item(struct xfs_ail *, |
109 | xfs_log_item_t *); | 112 | xfs_log_item_t *); |
110 | 113 | ||
111 | xfs_lsn_t xfs_trans_ail_tail(struct xfs_ail *ailp); | ||
112 | |||
113 | struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp, | 114 | struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp, |
114 | struct xfs_ail_cursor *cur, | 115 | struct xfs_ail_cursor *cur, |
115 | xfs_lsn_t lsn); | 116 | xfs_lsn_t lsn); |