diff options
author | Dave Chinner <dchinner@redhat.com> | 2010-03-22 20:43:17 -0400 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-05-19 10:58:10 -0400 |
commit | 55b66332d0921146a914d5d75a7b870a65dc4938 (patch) | |
tree | 254f130969b118cc777371691e892db20e96b5a6 | |
parent | 99428ad0f665a5d5b245ab36cefb6b231d977e73 (diff) |
xfs: introduce new internal log vector structure
The current log IO vector structure is a flat array and not
extensible. To make it possible to keep separate log IO vectors for
individual log items, we need a method of chaining log IO vectors
together.
Introduce a new log vector type that can be used to wrap the
existing log IO vectors on use that internally to the log. This
means that the existing external interface (xfs_log_write) does not
change and hence no changes to the transaction commit code are
required.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
-rw-r--r-- | fs/xfs/xfs_log.c | 143 | ||||
-rw-r--r-- | fs/xfs/xfs_log.h | 6 |
2 files changed, 90 insertions, 59 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 8c856d24538c..2e6f3b82e4b7 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
@@ -50,7 +50,7 @@ kmem_zone_t *xfs_log_ticket_zone; | |||
50 | (off) += (bytes);} | 50 | (off) += (bytes);} |
51 | 51 | ||
52 | /* Local miscellaneous function prototypes */ | 52 | /* Local miscellaneous function prototypes */ |
53 | STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket, | 53 | STATIC int xlog_commit_record(struct log *log, struct xlog_ticket *ticket, |
54 | xlog_in_core_t **, xfs_lsn_t *); | 54 | xlog_in_core_t **, xfs_lsn_t *); |
55 | STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, | 55 | STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, |
56 | xfs_buftarg_t *log_target, | 56 | xfs_buftarg_t *log_target, |
@@ -59,11 +59,9 @@ STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, | |||
59 | STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes); | 59 | STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes); |
60 | STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog); | 60 | STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog); |
61 | STATIC void xlog_dealloc_log(xlog_t *log); | 61 | STATIC void xlog_dealloc_log(xlog_t *log); |
62 | STATIC int xlog_write(xfs_mount_t *mp, xfs_log_iovec_t region[], | 62 | STATIC int xlog_write(struct log *log, struct xfs_log_vec *log_vector, |
63 | int nentries, struct xlog_ticket *tic, | 63 | struct xlog_ticket *tic, xfs_lsn_t *start_lsn, |
64 | xfs_lsn_t *start_lsn, | 64 | xlog_in_core_t **commit_iclog, uint flags); |
65 | xlog_in_core_t **commit_iclog, | ||
66 | uint flags); | ||
67 | 65 | ||
68 | /* local state machine functions */ | 66 | /* local state machine functions */ |
69 | STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int); | 67 | STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int); |
@@ -258,7 +256,7 @@ xfs_log_done( | |||
258 | * If we get an error, just continue and give back the log ticket. | 256 | * If we get an error, just continue and give back the log ticket. |
259 | */ | 257 | */ |
260 | (((ticket->t_flags & XLOG_TIC_INITED) == 0) && | 258 | (((ticket->t_flags & XLOG_TIC_INITED) == 0) && |
261 | (xlog_commit_record(mp, ticket, iclog, &lsn)))) { | 259 | (xlog_commit_record(log, ticket, iclog, &lsn)))) { |
262 | lsn = (xfs_lsn_t) -1; | 260 | lsn = (xfs_lsn_t) -1; |
263 | if (ticket->t_flags & XLOG_TIC_PERM_RESERV) { | 261 | if (ticket->t_flags & XLOG_TIC_PERM_RESERV) { |
264 | flags |= XFS_LOG_REL_PERM_RESERV; | 262 | flags |= XFS_LOG_REL_PERM_RESERV; |
@@ -516,18 +514,10 @@ xfs_log_unmount_write(xfs_mount_t *mp) | |||
516 | #ifdef DEBUG | 514 | #ifdef DEBUG |
517 | xlog_in_core_t *first_iclog; | 515 | xlog_in_core_t *first_iclog; |
518 | #endif | 516 | #endif |
519 | xfs_log_iovec_t reg[1]; | ||
520 | xlog_ticket_t *tic = NULL; | 517 | xlog_ticket_t *tic = NULL; |
521 | xfs_lsn_t lsn; | 518 | xfs_lsn_t lsn; |
522 | int error; | 519 | int error; |
523 | 520 | ||
524 | /* the data section must be 32 bit size aligned */ | ||
525 | struct { | ||
526 | __uint16_t magic; | ||
527 | __uint16_t pad1; | ||
528 | __uint32_t pad2; /* may as well make it 64 bits */ | ||
529 | } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; | ||
530 | |||
531 | /* | 521 | /* |
532 | * Don't write out unmount record on read-only mounts. | 522 | * Don't write out unmount record on read-only mounts. |
533 | * Or, if we are doing a forced umount (typically because of IO errors). | 523 | * Or, if we are doing a forced umount (typically because of IO errors). |
@@ -549,16 +539,30 @@ xfs_log_unmount_write(xfs_mount_t *mp) | |||
549 | } while (iclog != first_iclog); | 539 | } while (iclog != first_iclog); |
550 | #endif | 540 | #endif |
551 | if (! (XLOG_FORCED_SHUTDOWN(log))) { | 541 | if (! (XLOG_FORCED_SHUTDOWN(log))) { |
552 | reg[0].i_addr = (void*)&magic; | ||
553 | reg[0].i_len = sizeof(magic); | ||
554 | reg[0].i_type = XLOG_REG_TYPE_UNMOUNT; | ||
555 | |||
556 | error = xfs_log_reserve(mp, 600, 1, &tic, | 542 | error = xfs_log_reserve(mp, 600, 1, &tic, |
557 | XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE); | 543 | XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE); |
558 | if (!error) { | 544 | if (!error) { |
545 | /* the data section must be 32 bit size aligned */ | ||
546 | struct { | ||
547 | __uint16_t magic; | ||
548 | __uint16_t pad1; | ||
549 | __uint32_t pad2; /* may as well make it 64 bits */ | ||
550 | } magic = { | ||
551 | .magic = XLOG_UNMOUNT_TYPE, | ||
552 | }; | ||
553 | struct xfs_log_iovec reg = { | ||
554 | .i_addr = (void *)&magic, | ||
555 | .i_len = sizeof(magic), | ||
556 | .i_type = XLOG_REG_TYPE_UNMOUNT, | ||
557 | }; | ||
558 | struct xfs_log_vec vec = { | ||
559 | .lv_niovecs = 1, | ||
560 | .lv_iovecp = ®, | ||
561 | }; | ||
562 | |||
559 | /* remove inited flag */ | 563 | /* remove inited flag */ |
560 | ((xlog_ticket_t *)tic)->t_flags = 0; | 564 | tic->t_flags = 0; |
561 | error = xlog_write(mp, reg, 1, tic, &lsn, | 565 | error = xlog_write(log, &vec, tic, &lsn, |
562 | NULL, XLOG_UNMOUNT_TRANS); | 566 | NULL, XLOG_UNMOUNT_TRANS); |
563 | /* | 567 | /* |
564 | * At this point, we're umounting anyway, | 568 | * At this point, we're umounting anyway, |
@@ -679,11 +683,15 @@ xfs_log_write( | |||
679 | { | 683 | { |
680 | struct log *log = mp->m_log; | 684 | struct log *log = mp->m_log; |
681 | int error; | 685 | int error; |
686 | struct xfs_log_vec vec = { | ||
687 | .lv_niovecs = nentries, | ||
688 | .lv_iovecp = reg, | ||
689 | }; | ||
682 | 690 | ||
683 | if (XLOG_FORCED_SHUTDOWN(log)) | 691 | if (XLOG_FORCED_SHUTDOWN(log)) |
684 | return XFS_ERROR(EIO); | 692 | return XFS_ERROR(EIO); |
685 | 693 | ||
686 | error = xlog_write(mp, reg, nentries, tic, start_lsn, NULL, 0); | 694 | error = xlog_write(log, &vec, tic, start_lsn, NULL, 0); |
687 | if (error) | 695 | if (error) |
688 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); | 696 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); |
689 | return error; | 697 | return error; |
@@ -1190,26 +1198,31 @@ out: | |||
1190 | * ticket. Return the lsn of the commit record. | 1198 | * ticket. Return the lsn of the commit record. |
1191 | */ | 1199 | */ |
1192 | STATIC int | 1200 | STATIC int |
1193 | xlog_commit_record(xfs_mount_t *mp, | 1201 | xlog_commit_record( |
1194 | xlog_ticket_t *ticket, | 1202 | struct log *log, |
1195 | xlog_in_core_t **iclog, | 1203 | struct xlog_ticket *ticket, |
1196 | xfs_lsn_t *commitlsnp) | 1204 | struct xlog_in_core **iclog, |
1205 | xfs_lsn_t *commitlsnp) | ||
1197 | { | 1206 | { |
1198 | int error; | 1207 | struct xfs_mount *mp = log->l_mp; |
1199 | xfs_log_iovec_t reg[1]; | 1208 | int error; |
1200 | 1209 | struct xfs_log_iovec reg = { | |
1201 | reg[0].i_addr = NULL; | 1210 | .i_addr = NULL, |
1202 | reg[0].i_len = 0; | 1211 | .i_len = 0, |
1203 | reg[0].i_type = XLOG_REG_TYPE_COMMIT; | 1212 | .i_type = XLOG_REG_TYPE_COMMIT, |
1213 | }; | ||
1214 | struct xfs_log_vec vec = { | ||
1215 | .lv_niovecs = 1, | ||
1216 | .lv_iovecp = ®, | ||
1217 | }; | ||
1204 | 1218 | ||
1205 | ASSERT_ALWAYS(iclog); | 1219 | ASSERT_ALWAYS(iclog); |
1206 | if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, | 1220 | error = xlog_write(log, &vec, ticket, commitlsnp, iclog, |
1207 | iclog, XLOG_COMMIT_TRANS))) { | 1221 | XLOG_COMMIT_TRANS); |
1222 | if (error) | ||
1208 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); | 1223 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); |
1209 | } | ||
1210 | return error; | 1224 | return error; |
1211 | } /* xlog_commit_record */ | 1225 | } |
1212 | |||
1213 | 1226 | ||
1214 | /* | 1227 | /* |
1215 | * Push on the buffer cache code if we ever use more than 75% of the on-disk | 1228 | * Push on the buffer cache code if we ever use more than 75% of the on-disk |
@@ -1636,9 +1649,9 @@ xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket) | |||
1636 | static int | 1649 | static int |
1637 | xlog_write_calc_vec_length( | 1650 | xlog_write_calc_vec_length( |
1638 | struct xlog_ticket *ticket, | 1651 | struct xlog_ticket *ticket, |
1639 | struct xfs_log_iovec reg[], | 1652 | struct xfs_log_vec *log_vector) |
1640 | int nentries) | ||
1641 | { | 1653 | { |
1654 | struct xfs_log_vec *lv; | ||
1642 | int headers = 0; | 1655 | int headers = 0; |
1643 | int len = 0; | 1656 | int len = 0; |
1644 | int i; | 1657 | int i; |
@@ -1647,12 +1660,15 @@ xlog_write_calc_vec_length( | |||
1647 | if (ticket->t_flags & XLOG_TIC_INITED) | 1660 | if (ticket->t_flags & XLOG_TIC_INITED) |
1648 | headers++; | 1661 | headers++; |
1649 | 1662 | ||
1650 | for (i = 0; i < nentries; i++) { | 1663 | for (lv = log_vector; lv; lv = lv->lv_next) { |
1651 | /* each region gets >= 1 */ | 1664 | headers += lv->lv_niovecs; |
1652 | headers++; | 1665 | |
1666 | for (i = 0; i < lv->lv_niovecs; i++) { | ||
1667 | struct xfs_log_iovec *vecp = &lv->lv_iovecp[i]; | ||
1653 | 1668 | ||
1654 | len += reg[i].i_len; | 1669 | len += vecp->i_len; |
1655 | xlog_tic_add_region(ticket, reg[i].i_len, reg[i].i_type); | 1670 | xlog_tic_add_region(ticket, vecp->i_len, vecp->i_type); |
1671 | } | ||
1656 | } | 1672 | } |
1657 | 1673 | ||
1658 | ticket->t_res_num_ophdrs += headers; | 1674 | ticket->t_res_num_ophdrs += headers; |
@@ -1858,16 +1874,16 @@ xlog_write_copy_finish( | |||
1858 | */ | 1874 | */ |
1859 | STATIC int | 1875 | STATIC int |
1860 | xlog_write( | 1876 | xlog_write( |
1861 | struct xfs_mount *mp, | 1877 | struct log *log, |
1862 | struct xfs_log_iovec reg[], | 1878 | struct xfs_log_vec *log_vector, |
1863 | int nentries, | ||
1864 | struct xlog_ticket *ticket, | 1879 | struct xlog_ticket *ticket, |
1865 | xfs_lsn_t *start_lsn, | 1880 | xfs_lsn_t *start_lsn, |
1866 | struct xlog_in_core **commit_iclog, | 1881 | struct xlog_in_core **commit_iclog, |
1867 | uint flags) | 1882 | uint flags) |
1868 | { | 1883 | { |
1869 | struct log *log = mp->m_log; | ||
1870 | struct xlog_in_core *iclog = NULL; | 1884 | struct xlog_in_core *iclog = NULL; |
1885 | struct xfs_log_iovec *vecp; | ||
1886 | struct xfs_log_vec *lv; | ||
1871 | int len; | 1887 | int len; |
1872 | int index; | 1888 | int index; |
1873 | int partial_copy = 0; | 1889 | int partial_copy = 0; |
@@ -1879,25 +1895,28 @@ xlog_write( | |||
1879 | 1895 | ||
1880 | *start_lsn = 0; | 1896 | *start_lsn = 0; |
1881 | 1897 | ||
1882 | len = xlog_write_calc_vec_length(ticket, reg, nentries); | 1898 | len = xlog_write_calc_vec_length(ticket, log_vector); |
1883 | if (ticket->t_curr_res < len) { | 1899 | if (ticket->t_curr_res < len) { |
1884 | xlog_print_tic_res(mp, ticket); | 1900 | xlog_print_tic_res(log->l_mp, ticket); |
1885 | #ifdef DEBUG | 1901 | #ifdef DEBUG |
1886 | xlog_panic( | 1902 | xlog_panic( |
1887 | "xfs_log_write: reservation ran out. Need to up reservation"); | 1903 | "xfs_log_write: reservation ran out. Need to up reservation"); |
1888 | #else | 1904 | #else |
1889 | /* Customer configurable panic */ | 1905 | /* Customer configurable panic */ |
1890 | xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp, | 1906 | xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, log->l_mp, |
1891 | "xfs_log_write: reservation ran out. Need to up reservation"); | 1907 | "xfs_log_write: reservation ran out. Need to up reservation"); |
1892 | 1908 | ||
1893 | /* If we did not panic, shutdown the filesystem */ | 1909 | /* If we did not panic, shutdown the filesystem */ |
1894 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | 1910 | xfs_force_shutdown(log->l_mp, SHUTDOWN_CORRUPT_INCORE); |
1895 | #endif | 1911 | #endif |
1896 | } | 1912 | } |
1897 | 1913 | ||
1898 | ticket->t_curr_res -= len; | 1914 | ticket->t_curr_res -= len; |
1899 | 1915 | ||
1900 | for (index = 0; index < nentries; ) { | 1916 | index = 0; |
1917 | lv = log_vector; | ||
1918 | vecp = lv->lv_iovecp; | ||
1919 | while (lv && index < lv->lv_niovecs) { | ||
1901 | __psint_t ptr; | 1920 | __psint_t ptr; |
1902 | int log_offset; | 1921 | int log_offset; |
1903 | 1922 | ||
@@ -1917,13 +1936,14 @@ xlog_write( | |||
1917 | * This loop writes out as many regions as can fit in the amount | 1936 | * This loop writes out as many regions as can fit in the amount |
1918 | * of space which was allocated by xlog_state_get_iclog_space(). | 1937 | * of space which was allocated by xlog_state_get_iclog_space(). |
1919 | */ | 1938 | */ |
1920 | while (index < nentries) { | 1939 | while (lv && index < lv->lv_niovecs) { |
1940 | struct xfs_log_iovec *reg = &vecp[index]; | ||
1921 | struct xlog_op_header *ophdr; | 1941 | struct xlog_op_header *ophdr; |
1922 | int start_rec_copy; | 1942 | int start_rec_copy; |
1923 | int copy_len; | 1943 | int copy_len; |
1924 | int copy_off; | 1944 | int copy_off; |
1925 | 1945 | ||
1926 | ASSERT(reg[index].i_len % sizeof(__int32_t) == 0); | 1946 | ASSERT(reg->i_len % sizeof(__int32_t) == 0); |
1927 | ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0); | 1947 | ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0); |
1928 | 1948 | ||
1929 | start_rec_copy = xlog_write_start_rec(ptr, ticket); | 1949 | start_rec_copy = xlog_write_start_rec(ptr, ticket); |
@@ -1942,7 +1962,7 @@ xlog_write( | |||
1942 | 1962 | ||
1943 | len += xlog_write_setup_copy(ticket, ophdr, | 1963 | len += xlog_write_setup_copy(ticket, ophdr, |
1944 | iclog->ic_size-log_offset, | 1964 | iclog->ic_size-log_offset, |
1945 | reg[index].i_len, | 1965 | reg->i_len, |
1946 | ©_off, ©_len, | 1966 | ©_off, ©_len, |
1947 | &partial_copy, | 1967 | &partial_copy, |
1948 | &partial_copy_len); | 1968 | &partial_copy_len); |
@@ -1950,7 +1970,7 @@ xlog_write( | |||
1950 | 1970 | ||
1951 | /* copy region */ | 1971 | /* copy region */ |
1952 | ASSERT(copy_len >= 0); | 1972 | ASSERT(copy_len >= 0); |
1953 | memcpy((xfs_caddr_t)ptr, reg[index].i_addr + copy_off, | 1973 | memcpy((xfs_caddr_t)ptr, reg->i_addr + copy_off, |
1954 | copy_len); | 1974 | copy_len); |
1955 | xlog_write_adv_cnt(ptr, len, log_offset, copy_len); | 1975 | xlog_write_adv_cnt(ptr, len, log_offset, copy_len); |
1956 | 1976 | ||
@@ -1982,9 +2002,14 @@ xlog_write( | |||
1982 | if (partial_copy) | 2002 | if (partial_copy) |
1983 | break; | 2003 | break; |
1984 | 2004 | ||
1985 | index++; | 2005 | if (++index == lv->lv_niovecs) { |
2006 | lv = lv->lv_next; | ||
2007 | index = 0; | ||
2008 | if (lv) | ||
2009 | vecp = lv->lv_iovecp; | ||
2010 | } | ||
1986 | if (record_cnt == 0) { | 2011 | if (record_cnt == 0) { |
1987 | if (index == nentries) | 2012 | if (!lv) |
1988 | return 0; | 2013 | return 0; |
1989 | break; | 2014 | break; |
1990 | } | 2015 | } |
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index f3a564d298d0..229d1f36ba9a 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h | |||
@@ -110,6 +110,12 @@ typedef struct xfs_log_iovec { | |||
110 | uint i_type; /* type of region */ | 110 | uint i_type; /* type of region */ |
111 | } xfs_log_iovec_t; | 111 | } xfs_log_iovec_t; |
112 | 112 | ||
113 | struct xfs_log_vec { | ||
114 | struct xfs_log_vec *lv_next; /* next lv in build list */ | ||
115 | int lv_niovecs; /* number of iovecs in lv */ | ||
116 | struct xfs_log_iovec *lv_iovecp; /* iovec array */ | ||
117 | }; | ||
118 | |||
113 | /* | 119 | /* |
114 | * Structure used to pass callback function and the function's argument | 120 | * Structure used to pass callback function and the function's argument |
115 | * to the log manager. | 121 | * to the log manager. |