aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2009-04-06 12:42:59 -0400
committerChristoph Hellwig <hch@brick.lst.de>2009-04-06 12:42:59 -0400
commit9d7fef74b23fe57803c5f71fab11630d9ec2cb4b (patch)
treee196c150f77c9c45d9dc0b5e2c06ae867c9bc2a4 /fs/xfs
parentc626d174cfe38e7f0545d074c299527892cd8c45 (diff)
xfs: inform the xfsaild of the push target before sleeping
When trying to reserve log space, we find the amount of space we need, then go to sleep waiting for space. When we are woken, we try to push the tail of the log forward to make sure we have space available. Unfortunately, this means that if there is not space available, and everyone who needs space goes to sleep there is no-one left to push the tail of the log to make space available. Once we have a thread waiting for space to become available, the others queue up behind it in a FIFO, and none of them push the tail of the log. This can result in everyone going to sleep in xlog_grant_log_space() if the first sleeper races with the last I/O that moves the tail of the log forward. With no further I/O tomove the tail of the log, there is nothing to wake the sleepers and hence all transactions just stop. Fix this by making sure the xfsaild will create enough space for the transaction that is about to sleep by moving the push target far enough forwards to ensure that that the curent proceeees will have enough space available when it is woken. That is, we push the AIL before we go to sleep. Because we've inserted the log ticket into the queue before we've pushed and gone to sleep, subsequent transactions will wait behind this one. Hence we are guaranteed to have space available when we are woken. Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_log.c37
1 files changed, 19 insertions, 18 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 8016d3040748..3750f04ede0b 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -2560,18 +2560,19 @@ redo:
2560 xlog_ins_ticketq(&log->l_reserve_headq, tic); 2560 xlog_ins_ticketq(&log->l_reserve_headq, tic);
2561 xlog_trace_loggrant(log, tic, 2561 xlog_trace_loggrant(log, tic,
2562 "xlog_grant_log_space: sleep 2"); 2562 "xlog_grant_log_space: sleep 2");
2563 spin_unlock(&log->l_grant_lock);
2564 xlog_grant_push_ail(log->l_mp, need_bytes);
2565 spin_lock(&log->l_grant_lock);
2566
2563 XFS_STATS_INC(xs_sleep_logspace); 2567 XFS_STATS_INC(xs_sleep_logspace);
2564 sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s); 2568 sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s);
2565 2569
2566 if (XLOG_FORCED_SHUTDOWN(log)) { 2570 spin_lock(&log->l_grant_lock);
2567 spin_lock(&log->l_grant_lock); 2571 if (XLOG_FORCED_SHUTDOWN(log))
2568 goto error_return; 2572 goto error_return;
2569 }
2570 2573
2571 xlog_trace_loggrant(log, tic, 2574 xlog_trace_loggrant(log, tic,
2572 "xlog_grant_log_space: wake 2"); 2575 "xlog_grant_log_space: wake 2");
2573 xlog_grant_push_ail(log->l_mp, need_bytes);
2574 spin_lock(&log->l_grant_lock);
2575 goto redo; 2576 goto redo;
2576 } else if (tic->t_flags & XLOG_TIC_IN_Q) 2577 } else if (tic->t_flags & XLOG_TIC_IN_Q)
2577 xlog_del_ticketq(&log->l_reserve_headq, tic); 2578 xlog_del_ticketq(&log->l_reserve_headq, tic);
@@ -2650,7 +2651,7 @@ xlog_regrant_write_log_space(xlog_t *log,
2650 * for more free space, otherwise try to get some space for 2651 * for more free space, otherwise try to get some space for
2651 * this transaction. 2652 * this transaction.
2652 */ 2653 */
2653 2654 need_bytes = tic->t_unit_res;
2654 if ((ntic = log->l_write_headq)) { 2655 if ((ntic = log->l_write_headq)) {
2655 free_bytes = xlog_space_left(log, log->l_grant_write_cycle, 2656 free_bytes = xlog_space_left(log, log->l_grant_write_cycle,
2656 log->l_grant_write_bytes); 2657 log->l_grant_write_bytes);
@@ -2670,26 +2671,25 @@ xlog_regrant_write_log_space(xlog_t *log,
2670 2671
2671 xlog_trace_loggrant(log, tic, 2672 xlog_trace_loggrant(log, tic,
2672 "xlog_regrant_write_log_space: sleep 1"); 2673 "xlog_regrant_write_log_space: sleep 1");
2674 spin_unlock(&log->l_grant_lock);
2675 xlog_grant_push_ail(log->l_mp, need_bytes);
2676 spin_lock(&log->l_grant_lock);
2677
2673 XFS_STATS_INC(xs_sleep_logspace); 2678 XFS_STATS_INC(xs_sleep_logspace);
2674 sv_wait(&tic->t_wait, PINOD|PLTWAIT, 2679 sv_wait(&tic->t_wait, PINOD|PLTWAIT,
2675 &log->l_grant_lock, s); 2680 &log->l_grant_lock, s);
2676 2681
2677 /* If we're shutting down, this tic is already 2682 /* If we're shutting down, this tic is already
2678 * off the queue */ 2683 * off the queue */
2679 if (XLOG_FORCED_SHUTDOWN(log)) { 2684 spin_lock(&log->l_grant_lock);
2680 spin_lock(&log->l_grant_lock); 2685 if (XLOG_FORCED_SHUTDOWN(log))
2681 goto error_return; 2686 goto error_return;
2682 }
2683 2687
2684 xlog_trace_loggrant(log, tic, 2688 xlog_trace_loggrant(log, tic,
2685 "xlog_regrant_write_log_space: wake 1"); 2689 "xlog_regrant_write_log_space: wake 1");
2686 xlog_grant_push_ail(log->l_mp, tic->t_unit_res);
2687 spin_lock(&log->l_grant_lock);
2688 } 2690 }
2689 } 2691 }
2690 2692
2691 need_bytes = tic->t_unit_res;
2692
2693redo: 2693redo:
2694 if (XLOG_FORCED_SHUTDOWN(log)) 2694 if (XLOG_FORCED_SHUTDOWN(log))
2695 goto error_return; 2695 goto error_return;
@@ -2699,19 +2699,20 @@ redo:
2699 if (free_bytes < need_bytes) { 2699 if (free_bytes < need_bytes) {
2700 if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) 2700 if ((tic->t_flags & XLOG_TIC_IN_Q) == 0)
2701 xlog_ins_ticketq(&log->l_write_headq, tic); 2701 xlog_ins_ticketq(&log->l_write_headq, tic);
2702 spin_unlock(&log->l_grant_lock);
2703 xlog_grant_push_ail(log->l_mp, need_bytes);
2704 spin_lock(&log->l_grant_lock);
2705
2702 XFS_STATS_INC(xs_sleep_logspace); 2706 XFS_STATS_INC(xs_sleep_logspace);
2703 sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s); 2707 sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s);
2704 2708
2705 /* If we're shutting down, this tic is already off the queue */ 2709 /* If we're shutting down, this tic is already off the queue */
2706 if (XLOG_FORCED_SHUTDOWN(log)) { 2710 spin_lock(&log->l_grant_lock);
2707 spin_lock(&log->l_grant_lock); 2711 if (XLOG_FORCED_SHUTDOWN(log))
2708 goto error_return; 2712 goto error_return;
2709 }
2710 2713
2711 xlog_trace_loggrant(log, tic, 2714 xlog_trace_loggrant(log, tic,
2712 "xlog_regrant_write_log_space: wake 2"); 2715 "xlog_regrant_write_log_space: wake 2");
2713 xlog_grant_push_ail(log->l_mp, need_bytes);
2714 spin_lock(&log->l_grant_lock);
2715 goto redo; 2716 goto redo;
2716 } else if (tic->t_flags & XLOG_TIC_IN_Q) 2717 } else if (tic->t_flags & XLOG_TIC_IN_Q)
2717 xlog_del_ticketq(&log->l_write_headq, tic); 2718 xlog_del_ticketq(&log->l_write_headq, tic);