aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_extfree_item.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-04-23 01:58:39 -0400
committerBen Myers <bpm@sgi.com>2012-05-14 17:20:31 -0400
commit43ff2122e6492bcc88b065c433453dce88223b30 (patch)
tree0f762cfb753edd73402b8830e0927d9efba30c61 /fs/xfs/xfs_extfree_item.c
parent960c60af8b9481595e68875e79b2602e73169c29 (diff)
xfs: on-stack delayed write buffer lists
Queue delwri buffers on a local on-stack list instead of a per-buftarg one, and write back the buffers per-process instead of by waking up xfsbufd. This is now easily doable given that we have very few places left that write delwri buffers: - log recovery: Only done at mount time, and already forcing out the buffers synchronously using xfs_flush_buftarg - quotacheck: Same story. - dquot reclaim: Writes out dirty dquots on the LRU under memory pressure. We might want to look into doing more of this via xfsaild, but it's already more optimal than the synchronous inode reclaim that writes each buffer synchronously. - xfsaild: This is the main beneficiary of the change. By keeping a local list of buffers to write we reduce latency of writing out buffers, and more importably we can remove all the delwri list promotions which were hitting the buffer cache hard under sustained metadata loads. The implementation is very straight forward - xfs_buf_delwri_queue now gets a new list_head pointer that it adds the delwri buffers to, and all callers need to eventually submit the list using xfs_buf_delwi_submit or xfs_buf_delwi_submit_nowait. Buffers that already are on a delwri list are skipped in xfs_buf_delwri_queue, assuming they already are on another delwri list. The biggest change to pass down the buffer list was done to the AIL pushing. Now that we operate on buffers the trylock, push and pushbuf log item methods are merged into a single push routine, which tries to lock the item, and if possible add the buffer that needs writeback to the buffer list. This leads to much simpler code than the previous split but requires the individual IOP_PUSH instances to unlock and reacquire the AIL around calls to blocking routines. Given that xfsailds now also handle writing out buffers, the conditions for log forcing and the sleep times needed some small changes. The most important one is that we consider an AIL busy as long we still have buffers to push, and the other one is that we do increment the pushed LSN for buffers that are under flushing at this moment, but still count them towards the stuck items for restart purposes. Without this we could hammer on stuck items without ever forcing the log and not make progress under heavy random delete workloads on fast flash storage devices. [ Dave Chinner: - rebase on previous patches. - improved comments for XBF_DELWRI_Q handling - fix XBF_ASYNC handling in queue submission (test 106 failure) - rename delwri submit function buffer list parameters for clarity - xfs_efd_item_push() should return XFS_ITEM_PINNED ] Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_extfree_item.c')
-rw-r--r--fs/xfs/xfs_extfree_item.c55
1 files changed, 14 insertions, 41 deletions
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index 35c2aff38b2..9549ef179e0 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -147,22 +147,20 @@ xfs_efi_item_unpin(
147} 147}
148 148
149/* 149/*
150 * Efi items have no locking or pushing. However, since EFIs are 150 * Efi items have no locking or pushing. However, since EFIs are pulled from
151 * pulled from the AIL when their corresponding EFDs are committed 151 * the AIL when their corresponding EFDs are committed to disk, their situation
152 * to disk, their situation is very similar to being pinned. Return 152 * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller
153 * XFS_ITEM_PINNED so that the caller will eventually flush the log. 153 * will eventually flush the log. This should help in getting the EFI out of
154 * This should help in getting the EFI out of the AIL. 154 * the AIL.
155 */ 155 */
156STATIC uint 156STATIC uint
157xfs_efi_item_trylock( 157xfs_efi_item_push(
158 struct xfs_log_item *lip) 158 struct xfs_log_item *lip,
159 struct list_head *buffer_list)
159{ 160{
160 return XFS_ITEM_PINNED; 161 return XFS_ITEM_PINNED;
161} 162}
162 163
163/*
164 * Efi items have no locking, so just return.
165 */
166STATIC void 164STATIC void
167xfs_efi_item_unlock( 165xfs_efi_item_unlock(
168 struct xfs_log_item *lip) 166 struct xfs_log_item *lip)
@@ -190,17 +188,6 @@ xfs_efi_item_committed(
190} 188}
191 189
192/* 190/*
193 * There isn't much you can do to push on an efi item. It is simply
194 * stuck waiting for all of its corresponding efd items to be
195 * committed to disk.
196 */
197STATIC void
198xfs_efi_item_push(
199 struct xfs_log_item *lip)
200{
201}
202
203/*
204 * The EFI dependency tracking op doesn't do squat. It can't because 191 * The EFI dependency tracking op doesn't do squat. It can't because
205 * it doesn't know where the free extent is coming from. The dependency 192 * it doesn't know where the free extent is coming from. The dependency
206 * tracking has to be handled by the "enclosing" metadata object. For 193 * tracking has to be handled by the "enclosing" metadata object. For
@@ -222,7 +209,6 @@ static const struct xfs_item_ops xfs_efi_item_ops = {
222 .iop_format = xfs_efi_item_format, 209 .iop_format = xfs_efi_item_format,
223 .iop_pin = xfs_efi_item_pin, 210 .iop_pin = xfs_efi_item_pin,
224 .iop_unpin = xfs_efi_item_unpin, 211 .iop_unpin = xfs_efi_item_unpin,
225 .iop_trylock = xfs_efi_item_trylock,
226 .iop_unlock = xfs_efi_item_unlock, 212 .iop_unlock = xfs_efi_item_unlock,
227 .iop_committed = xfs_efi_item_committed, 213 .iop_committed = xfs_efi_item_committed,
228 .iop_push = xfs_efi_item_push, 214 .iop_push = xfs_efi_item_push,
@@ -404,19 +390,17 @@ xfs_efd_item_unpin(
404} 390}
405 391
406/* 392/*
407 * Efd items have no locking, so just return success. 393 * There isn't much you can do to push on an efd item. It is simply stuck
394 * waiting for the log to be flushed to disk.
408 */ 395 */
409STATIC uint 396STATIC uint
410xfs_efd_item_trylock( 397xfs_efd_item_push(
411 struct xfs_log_item *lip) 398 struct xfs_log_item *lip,
399 struct list_head *buffer_list)
412{ 400{
413 return XFS_ITEM_LOCKED; 401 return XFS_ITEM_PINNED;
414} 402}
415 403
416/*
417 * Efd items have no locking or pushing, so return failure
418 * so that the caller doesn't bother with us.
419 */
420STATIC void 404STATIC void
421xfs_efd_item_unlock( 405xfs_efd_item_unlock(
422 struct xfs_log_item *lip) 406 struct xfs_log_item *lip)
@@ -451,16 +435,6 @@ xfs_efd_item_committed(
451} 435}
452 436
453/* 437/*
454 * There isn't much you can do to push on an efd item. It is simply
455 * stuck waiting for the log to be flushed to disk.
456 */
457STATIC void
458xfs_efd_item_push(
459 struct xfs_log_item *lip)
460{
461}
462
463/*
464 * The EFD dependency tracking op doesn't do squat. It can't because 438 * The EFD dependency tracking op doesn't do squat. It can't because
465 * it doesn't know where the free extent is coming from. The dependency 439 * it doesn't know where the free extent is coming from. The dependency
466 * tracking has to be handled by the "enclosing" metadata object. For 440 * tracking has to be handled by the "enclosing" metadata object. For
@@ -482,7 +456,6 @@ static const struct xfs_item_ops xfs_efd_item_ops = {
482 .iop_format = xfs_efd_item_format, 456 .iop_format = xfs_efd_item_format,
483 .iop_pin = xfs_efd_item_pin, 457 .iop_pin = xfs_efd_item_pin,
484 .iop_unpin = xfs_efd_item_unpin, 458 .iop_unpin = xfs_efd_item_unpin,
485 .iop_trylock = xfs_efd_item_trylock,
486 .iop_unlock = xfs_efd_item_unlock, 459 .iop_unlock = xfs_efd_item_unlock,
487 .iop_committed = xfs_efd_item_committed, 460 .iop_committed = xfs_efd_item_committed,
488 .iop_push = xfs_efd_item_push, 461 .iop_push = xfs_efd_item_push,