aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_log.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2010-05-21 00:37:18 -0400
committerAlex Elder <aelder@sgi.com>2010-05-24 11:38:03 -0400
commit71e330b593905e40d6c5afa824d38ee02d70ce5f (patch)
tree4c9fa6c4766280752fc40f3057fd6cf64396c16c /fs/xfs/xfs_log.c
parenta9a745daadab26f13884ff26a50fa38247c11ce9 (diff)
xfs: Introduce delayed logging core code
The delayed logging code only changes in-memory structures and as such can be enabled and disabled with a mount option. Add the mount option and emit a warning that this is an experimental feature that should not be used in production yet. We also need infrastructure to track committed items that have not yet been written to the log. This is what the Committed Item List (CIL) is for. The log item also needs to be extended to track the current log vector, the associated memory buffer and it's location in the Commit Item List. Extend the log item and log vector structures to enable this tracking. To maintain the current log format for transactions with delayed logging, we need to introduce a checkpoint transaction and a context for tracking each checkpoint from initiation to transaction completion. This includes adding a log ticket for tracking space log required/used by the context checkpoint. To track all the changes we need an io vector array per log item, rather than a single array for the entire transaction. Using the new log vector structure for this requires two passes - the first to allocate the log vector structures and chain them together, and the second to fill them out. This log vector chain can then be passed to the CIL for formatting, pinning and insertion into the CIL. Formatting of the log vector chain is relatively simple - it's just a loop over the iovecs on each log vector, but it is made slightly more complex because we re-write the iovec after the copy to point back at the memory buffer we just copied into. This code also needs to pin log items. If the log item is not already tracked in this checkpoint context, then it needs to be pinned. Otherwise it is already pinned and we don't need to pin it again. The only other complexity is calculating the amount of new log space the formatting has consumed. This needs to be accounted to the transaction in progress, and the accounting is made more complex becase we need also to steal space from it for log metadata in the checkpoint transaction. Calculate all this at insert time and update all the tickets, counters, etc correctly. Once we've formatted all the log items in the transaction, attach the busy extents to the checkpoint context so the busy extents live until checkpoint completion and can be processed at that point in time. Transactions can then be freed at this point in time. Now we need to issue checkpoints - we are tracking the amount of log space used by the items in the CIL, so we can trigger background checkpoints when the space usage gets to a certain threshold. Otherwise, checkpoints need ot be triggered when a log synchronisation point is reached - a log force event. Because the log write code already handles chained log vectors, writing the transaction is trivial, too. Construct a transaction header, add it to the head of the chain and write it into the log, then issue a commit record write. Then we can release the checkpoint log ticket and attach the context to the log buffer so it can be called during Io completion to complete the checkpoint. We also need to allow for synchronising multiple in-flight checkpoints. This is needed for two things - the first is to ensure that checkpoint commit records appear in the log in the correct sequence order (so they are replayed in the correct order). The second is so that xfs_log_force_lsn() operates correctly and only flushes and/or waits for the specific sequence it was provided with. To do this we need a wait variable and a list tracking the checkpoint commits in progress. We can walk this list and wait for the checkpoints to change state or complete easily, an this provides the necessary synchronisation for correct operation in both cases. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_log.c')
-rw-r--r--fs/xfs/xfs_log.c64
1 files changed, 49 insertions, 15 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 19d0c5f73e24..027ebfe20677 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -54,9 +54,6 @@ STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp,
54STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes); 54STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes);
55STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog); 55STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog);
56STATIC void xlog_dealloc_log(xlog_t *log); 56STATIC void xlog_dealloc_log(xlog_t *log);
57STATIC int xlog_write(struct log *log, struct xfs_log_vec *log_vector,
58 struct xlog_ticket *tic, xfs_lsn_t *start_lsn,
59 xlog_in_core_t **commit_iclog, uint flags);
60 57
61/* local state machine functions */ 58/* local state machine functions */
62STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int); 59STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int);
@@ -86,12 +83,6 @@ STATIC int xlog_regrant_write_log_space(xlog_t *log,
86STATIC void xlog_ungrant_log_space(xlog_t *log, 83STATIC void xlog_ungrant_log_space(xlog_t *log,
87 xlog_ticket_t *ticket); 84 xlog_ticket_t *ticket);
88 85
89
90/* local ticket functions */
91STATIC xlog_ticket_t *xlog_ticket_alloc(xlog_t *log, int unit_bytes, int count,
92 char clientid, uint flags,
93 int alloc_flags);
94
95#if defined(DEBUG) 86#if defined(DEBUG)
96STATIC void xlog_verify_dest_ptr(xlog_t *log, char *ptr); 87STATIC void xlog_verify_dest_ptr(xlog_t *log, char *ptr);
97STATIC void xlog_verify_grant_head(xlog_t *log, int equals); 88STATIC void xlog_verify_grant_head(xlog_t *log, int equals);
@@ -460,6 +451,13 @@ xfs_log_mount(
460 /* Normal transactions can now occur */ 451 /* Normal transactions can now occur */
461 mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY; 452 mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY;
462 453
454 /*
455 * Now the log has been fully initialised and we know were our
456 * space grant counters are, we can initialise the permanent ticket
457 * needed for delayed logging to work.
458 */
459 xlog_cil_init_post_recovery(mp->m_log);
460
463 return 0; 461 return 0;
464 462
465out_destroy_ail: 463out_destroy_ail:
@@ -666,6 +664,10 @@ xfs_log_item_init(
666 item->li_ailp = mp->m_ail; 664 item->li_ailp = mp->m_ail;
667 item->li_type = type; 665 item->li_type = type;
668 item->li_ops = ops; 666 item->li_ops = ops;
667 item->li_lv = NULL;
668
669 INIT_LIST_HEAD(&item->li_ail);
670 INIT_LIST_HEAD(&item->li_cil);
669} 671}
670 672
671/* 673/*
@@ -1176,6 +1178,9 @@ xlog_alloc_log(xfs_mount_t *mp,
1176 *iclogp = log->l_iclog; /* complete ring */ 1178 *iclogp = log->l_iclog; /* complete ring */
1177 log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ 1179 log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */
1178 1180
1181 error = xlog_cil_init(log);
1182 if (error)
1183 goto out_free_iclog;
1179 return log; 1184 return log;
1180 1185
1181out_free_iclog: 1186out_free_iclog:
@@ -1502,6 +1507,8 @@ xlog_dealloc_log(xlog_t *log)
1502 xlog_in_core_t *iclog, *next_iclog; 1507 xlog_in_core_t *iclog, *next_iclog;
1503 int i; 1508 int i;
1504 1509
1510 xlog_cil_destroy(log);
1511
1505 iclog = log->l_iclog; 1512 iclog = log->l_iclog;
1506 for (i=0; i<log->l_iclog_bufs; i++) { 1513 for (i=0; i<log->l_iclog_bufs; i++) {
1507 sv_destroy(&iclog->ic_force_wait); 1514 sv_destroy(&iclog->ic_force_wait);
@@ -1544,8 +1551,10 @@ xlog_state_finish_copy(xlog_t *log,
1544 * print out info relating to regions written which consume 1551 * print out info relating to regions written which consume
1545 * the reservation 1552 * the reservation
1546 */ 1553 */
1547STATIC void 1554void
1548xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket) 1555xlog_print_tic_res(
1556 struct xfs_mount *mp,
1557 struct xlog_ticket *ticket)
1549{ 1558{
1550 uint i; 1559 uint i;
1551 uint ophdr_spc = ticket->t_res_num_ophdrs * (uint)sizeof(xlog_op_header_t); 1560 uint ophdr_spc = ticket->t_res_num_ophdrs * (uint)sizeof(xlog_op_header_t);
@@ -1877,7 +1886,7 @@ xlog_write_copy_finish(
1877 * we don't update ic_offset until the end when we know exactly how many 1886 * we don't update ic_offset until the end when we know exactly how many
1878 * bytes have been written out. 1887 * bytes have been written out.
1879 */ 1888 */
1880STATIC int 1889int
1881xlog_write( 1890xlog_write(
1882 struct log *log, 1891 struct log *log,
1883 struct xfs_log_vec *log_vector, 1892 struct xfs_log_vec *log_vector,
@@ -1901,9 +1910,26 @@ xlog_write(
1901 *start_lsn = 0; 1910 *start_lsn = 0;
1902 1911
1903 len = xlog_write_calc_vec_length(ticket, log_vector); 1912 len = xlog_write_calc_vec_length(ticket, log_vector);
1904 if (ticket->t_curr_res < len) 1913 if (log->l_cilp) {
1914 /*
1915 * Region headers and bytes are already accounted for.
1916 * We only need to take into account start records and
1917 * split regions in this function.
1918 */
1919 if (ticket->t_flags & XLOG_TIC_INITED)
1920 ticket->t_curr_res -= sizeof(xlog_op_header_t);
1921
1922 /*
1923 * Commit record headers need to be accounted for. These
1924 * come in as separate writes so are easy to detect.
1925 */
1926 if (flags & (XLOG_COMMIT_TRANS | XLOG_UNMOUNT_TRANS))
1927 ticket->t_curr_res -= sizeof(xlog_op_header_t);
1928 } else
1929 ticket->t_curr_res -= len;
1930
1931 if (ticket->t_curr_res < 0)
1905 xlog_print_tic_res(log->l_mp, ticket); 1932 xlog_print_tic_res(log->l_mp, ticket);
1906 ticket->t_curr_res -= len;
1907 1933
1908 index = 0; 1934 index = 0;
1909 lv = log_vector; 1935 lv = log_vector;
@@ -2999,6 +3025,8 @@ _xfs_log_force(
2999 3025
3000 XFS_STATS_INC(xs_log_force); 3026 XFS_STATS_INC(xs_log_force);
3001 3027
3028 xlog_cil_push(log, 1);
3029
3002 spin_lock(&log->l_icloglock); 3030 spin_lock(&log->l_icloglock);
3003 3031
3004 iclog = log->l_iclog; 3032 iclog = log->l_iclog;
@@ -3148,6 +3176,12 @@ _xfs_log_force_lsn(
3148 3176
3149 XFS_STATS_INC(xs_log_force); 3177 XFS_STATS_INC(xs_log_force);
3150 3178
3179 if (log->l_cilp) {
3180 lsn = xlog_cil_push_lsn(log, lsn);
3181 if (lsn == NULLCOMMITLSN)
3182 return 0;
3183 }
3184
3151try_again: 3185try_again:
3152 spin_lock(&log->l_icloglock); 3186 spin_lock(&log->l_icloglock);
3153 iclog = log->l_iclog; 3187 iclog = log->l_iclog;
@@ -3322,7 +3356,7 @@ xfs_log_get_trans_ident(
3322/* 3356/*
3323 * Allocate and initialise a new log ticket. 3357 * Allocate and initialise a new log ticket.
3324 */ 3358 */
3325STATIC xlog_ticket_t * 3359xlog_ticket_t *
3326xlog_ticket_alloc( 3360xlog_ticket_alloc(
3327 struct log *log, 3361 struct log *log,
3328 int unit_bytes, 3362 int unit_bytes,