aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_log.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2010-03-22 20:29:44 -0400
committerAlex Elder <aelder@sgi.com>2010-05-19 10:58:09 -0400
commitb5203cd0a43c17dfb9d498bc9e3146624e8c9622 (patch)
treece779712f4419aa238e0bf3a919ecc4010953fea /fs/xfs/xfs_log.c
parent9b9fc2b7602ed671d1a8524d4c31302b89554947 (diff)
xfs: factor xlog_write
xlog_write is a mess that takes a lot of effort to understand. It is a mass of nested loops with 4 space indents to get it to fit in 80 columns and lots of funky variables that aren't obvious what they mean or do. Break it down into understandable chunks. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
Diffstat (limited to 'fs/xfs/xfs_log.c')
-rw-r--r--fs/xfs/xfs_log.c339
1 files changed, 226 insertions, 113 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 81323d73a4ee..4a0ec592564c 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -1630,6 +1630,193 @@ xlog_print_tic_res(xfs_mount_t *mp, xlog_ticket_t *ticket)
1630} 1630}
1631 1631
1632/* 1632/*
1633 * Calculate the potential space needed by the log vector. Each region gets
1634 * its own xlog_op_header_t and may need to be double word aligned.
1635 */
1636static int
1637xlog_write_calc_vec_length(
1638 struct xlog_ticket *ticket,
1639 struct xfs_log_iovec reg[],
1640 int nentries)
1641{
1642 int headers = 0;
1643 int len = 0;
1644 int i;
1645
1646 /* acct for start rec of xact */
1647 if (ticket->t_flags & XLOG_TIC_INITED)
1648 headers++;
1649
1650 for (i = 0; i < nentries; i++) {
1651 /* each region gets >= 1 */
1652 headers++;
1653
1654 len += reg[i].i_len;
1655 xlog_tic_add_region(ticket, reg[i].i_len, reg[i].i_type);
1656 }
1657
1658 ticket->t_res_num_ophdrs += headers;
1659 len += headers * sizeof(struct xlog_op_header);
1660
1661 return len;
1662}
1663
1664/*
1665 * If first write for transaction, insert start record We can't be trying to
1666 * commit if we are inited. We can't have any "partial_copy" if we are inited.
1667 */
1668static int
1669xlog_write_start_rec(
1670 __psint_t ptr,
1671 struct xlog_ticket *ticket)
1672{
1673 struct xlog_op_header *ophdr = (struct xlog_op_header *)ptr;
1674
1675 if (!(ticket->t_flags & XLOG_TIC_INITED))
1676 return 0;
1677
1678 ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
1679 ophdr->oh_clientid = ticket->t_clientid;
1680 ophdr->oh_len = 0;
1681 ophdr->oh_flags = XLOG_START_TRANS;
1682 ophdr->oh_res2 = 0;
1683
1684 ticket->t_flags &= ~XLOG_TIC_INITED;
1685
1686 return sizeof(struct xlog_op_header);
1687}
1688
1689static xlog_op_header_t *
1690xlog_write_setup_ophdr(
1691 struct log *log,
1692 __psint_t ptr,
1693 struct xlog_ticket *ticket,
1694 uint flags)
1695{
1696 struct xlog_op_header *ophdr = (struct xlog_op_header *)ptr;
1697
1698 ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
1699 ophdr->oh_clientid = ticket->t_clientid;
1700 ophdr->oh_res2 = 0;
1701
1702 /* are we copying a commit or unmount record? */
1703 ophdr->oh_flags = flags;
1704
1705 /*
1706 * We've seen logs corrupted with bad transaction client ids. This
1707 * makes sure that XFS doesn't generate them on. Turn this into an EIO
1708 * and shut down the filesystem.
1709 */
1710 switch (ophdr->oh_clientid) {
1711 case XFS_TRANSACTION:
1712 case XFS_VOLUME:
1713 case XFS_LOG:
1714 break;
1715 default:
1716 xfs_fs_cmn_err(CE_WARN, log->l_mp,
1717 "Bad XFS transaction clientid 0x%x in ticket 0x%p",
1718 ophdr->oh_clientid, ticket);
1719 return NULL;
1720 }
1721
1722 return ophdr;
1723}
1724
1725/*
1726 * Set up the parameters of the region copy into the log. This has
1727 * to handle region write split across multiple log buffers - this
1728 * state is kept external to this function so that this code can
1729 * can be written in an obvious, self documenting manner.
1730 */
1731static int
1732xlog_write_setup_copy(
1733 struct xlog_ticket *ticket,
1734 struct xlog_op_header *ophdr,
1735 int space_available,
1736 int space_required,
1737 int *copy_off,
1738 int *copy_len,
1739 int *last_was_partial_copy,
1740 int *bytes_consumed)
1741{
1742 int still_to_copy;
1743
1744 still_to_copy = space_required - *bytes_consumed;
1745 *copy_off = *bytes_consumed;
1746
1747 if (still_to_copy <= space_available) {
1748 /* write of region completes here */
1749 *copy_len = still_to_copy;
1750 ophdr->oh_len = cpu_to_be32(*copy_len);
1751 if (*last_was_partial_copy)
1752 ophdr->oh_flags |= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS);
1753 *last_was_partial_copy = 0;
1754 *bytes_consumed = 0;
1755 return 0;
1756 }
1757
1758 /* partial write of region, needs extra log op header reservation */
1759 *copy_len = space_available;
1760 ophdr->oh_len = cpu_to_be32(*copy_len);
1761 ophdr->oh_flags |= XLOG_CONTINUE_TRANS;
1762 if (*last_was_partial_copy)
1763 ophdr->oh_flags |= XLOG_WAS_CONT_TRANS;
1764 *bytes_consumed += *copy_len;
1765 (*last_was_partial_copy)++;
1766
1767 /* account for new log op header */
1768 ticket->t_curr_res -= sizeof(struct xlog_op_header);
1769 ticket->t_res_num_ophdrs++;
1770
1771 return sizeof(struct xlog_op_header);
1772}
1773
1774static int
1775xlog_write_copy_finish(
1776 struct log *log,
1777 struct xlog_in_core *iclog,
1778 uint flags,
1779 int *record_cnt,
1780 int *data_cnt,
1781 int *partial_copy,
1782 int *partial_copy_len,
1783 int log_offset,
1784 struct xlog_in_core **commit_iclog)
1785{
1786 if (*partial_copy) {
1787 /*
1788 * This iclog has already been marked WANT_SYNC by
1789 * xlog_state_get_iclog_space.
1790 */
1791 xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt);
1792 *record_cnt = 0;
1793 *data_cnt = 0;
1794 return xlog_state_release_iclog(log, iclog);
1795 }
1796
1797 *partial_copy = 0;
1798 *partial_copy_len = 0;
1799
1800 if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) {
1801 /* no more space in this iclog - push it. */
1802 xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt);
1803 *record_cnt = 0;
1804 *data_cnt = 0;
1805
1806 spin_lock(&log->l_icloglock);
1807 xlog_state_want_sync(log, iclog);
1808 spin_unlock(&log->l_icloglock);
1809
1810 if (!commit_iclog)
1811 return xlog_state_release_iclog(log, iclog);
1812 ASSERT(flags & XLOG_COMMIT_TRANS);
1813 *commit_iclog = iclog;
1814 }
1815
1816 return 0;
1817}
1818
1819/*
1633 * Write some region out to in-core log 1820 * Write some region out to in-core log
1634 * 1821 *
1635 * This will be called when writing externally provided regions or when 1822 * This will be called when writing externally provided regions or when
@@ -1689,7 +1876,6 @@ xlog_write(
1689 int start_rec_copy; /* # bytes to copy for start record */ 1876 int start_rec_copy; /* # bytes to copy for start record */
1690 int partial_copy; /* did we split a region? */ 1877 int partial_copy; /* did we split a region? */
1691 int partial_copy_len;/* # bytes copied if split region */ 1878 int partial_copy_len;/* # bytes copied if split region */
1692 int need_copy; /* # bytes need to memcpy this region */
1693 int copy_len; /* # bytes actually memcpy'ing */ 1879 int copy_len; /* # bytes actually memcpy'ing */
1694 int copy_off; /* # bytes from entry start */ 1880 int copy_off; /* # bytes from entry start */
1695 int contwr; /* continued write of in-core log? */ 1881 int contwr; /* continued write of in-core log? */
@@ -1697,24 +1883,9 @@ xlog_write(
1697 int record_cnt = 0, data_cnt = 0; 1883 int record_cnt = 0, data_cnt = 0;
1698 1884
1699 partial_copy_len = partial_copy = 0; 1885 partial_copy_len = partial_copy = 0;
1700
1701 /* Calculate potential maximum space. Each region gets its own
1702 * xlog_op_header_t and may need to be double word aligned.
1703 */
1704 len = 0;
1705 if (ticket->t_flags & XLOG_TIC_INITED) { /* acct for start rec of xact */
1706 len += sizeof(xlog_op_header_t);
1707 ticket->t_res_num_ophdrs++;
1708 }
1709
1710 for (index = 0; index < nentries; index++) {
1711 len += sizeof(xlog_op_header_t); /* each region gets >= 1 */
1712 ticket->t_res_num_ophdrs++;
1713 len += reg[index].i_len;
1714 xlog_tic_add_region(ticket, reg[index].i_len, reg[index].i_type);
1715 }
1716 contwr = *start_lsn = 0; 1886 contwr = *start_lsn = 0;
1717 1887
1888 len = xlog_write_calc_vec_length(ticket, reg, nentries);
1718 if (ticket->t_curr_res < len) { 1889 if (ticket->t_curr_res < len) {
1719 xlog_print_tic_res(mp, ticket); 1890 xlog_print_tic_res(mp, ticket);
1720#ifdef DEBUG 1891#ifdef DEBUG
@@ -1748,81 +1919,23 @@ xlog_write(
1748 while (index < nentries) { 1919 while (index < nentries) {
1749 ASSERT(reg[index].i_len % sizeof(__int32_t) == 0); 1920 ASSERT(reg[index].i_len % sizeof(__int32_t) == 0);
1750 ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0); 1921 ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0);
1751 start_rec_copy = 0;
1752 1922
1753 /* If first write for transaction, insert start record. 1923 start_rec_copy = xlog_write_start_rec(ptr, ticket);
1754 * We can't be trying to commit if we are inited. We can't 1924 if (start_rec_copy) {
1755 * have any "partial_copy" if we are inited.
1756 */
1757 if (ticket->t_flags & XLOG_TIC_INITED) {
1758 logop_head = (xlog_op_header_t *)ptr;
1759 logop_head->oh_tid = cpu_to_be32(ticket->t_tid);
1760 logop_head->oh_clientid = ticket->t_clientid;
1761 logop_head->oh_len = 0;
1762 logop_head->oh_flags = XLOG_START_TRANS;
1763 logop_head->oh_res2 = 0;
1764 ticket->t_flags &= ~XLOG_TIC_INITED; /* clear bit */
1765 record_cnt++; 1925 record_cnt++;
1766
1767 start_rec_copy = sizeof(xlog_op_header_t);
1768 xlog_write_adv_cnt(ptr, len, log_offset, start_rec_copy); 1926 xlog_write_adv_cnt(ptr, len, log_offset, start_rec_copy);
1769 } 1927 }
1770 1928
1771 /* Copy log operation header directly into data section */ 1929 logop_head = xlog_write_setup_ophdr(log, ptr, ticket, flags);
1772 logop_head = (xlog_op_header_t *)ptr; 1930 if (!logop_head)
1773 logop_head->oh_tid = cpu_to_be32(ticket->t_tid); 1931 return XFS_ERROR(EIO);
1774 logop_head->oh_clientid = ticket->t_clientid;
1775 logop_head->oh_res2 = 0;
1776
1777 /* header copied directly */
1778 xlog_write_adv_cnt(ptr, len, log_offset, sizeof(xlog_op_header_t)); 1932 xlog_write_adv_cnt(ptr, len, log_offset, sizeof(xlog_op_header_t));
1779 1933
1780 /* are we copying a commit or unmount record? */ 1934 len += xlog_write_setup_copy(ticket, logop_head,
1781 logop_head->oh_flags = flags; 1935 iclog->ic_size - log_offset,
1782 1936 reg[index].i_len, &copy_off,
1783 /* 1937 &copy_len, &partial_copy,
1784 * We've seen logs corrupted with bad transaction client 1938 &partial_copy_len);
1785 * ids. This makes sure that XFS doesn't generate them on.
1786 * Turn this into an EIO and shut down the filesystem.
1787 */
1788 switch (logop_head->oh_clientid) {
1789 case XFS_TRANSACTION:
1790 case XFS_VOLUME:
1791 case XFS_LOG:
1792 break;
1793 default:
1794 xfs_fs_cmn_err(CE_WARN, mp,
1795 "Bad XFS transaction clientid 0x%x in ticket 0x%p",
1796 logop_head->oh_clientid, ticket);
1797 return XFS_ERROR(EIO);
1798 }
1799
1800 /* Partial write last time? => (partial_copy != 0)
1801 * need_copy is the amount we'd like to copy if everything could
1802 * fit in the current memcpy.
1803 */
1804 need_copy = reg[index].i_len - partial_copy_len;
1805
1806 copy_off = partial_copy_len;
1807 if (need_copy <= iclog->ic_size - log_offset) { /*complete write */
1808 copy_len = need_copy;
1809 logop_head->oh_len = cpu_to_be32(copy_len);
1810 if (partial_copy)
1811 logop_head->oh_flags|= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS);
1812 partial_copy_len = partial_copy = 0;
1813 } else { /* partial write */
1814 copy_len = iclog->ic_size - log_offset;
1815 logop_head->oh_len = cpu_to_be32(copy_len);
1816 logop_head->oh_flags |= XLOG_CONTINUE_TRANS;
1817 if (partial_copy)
1818 logop_head->oh_flags |= XLOG_WAS_CONT_TRANS;
1819 partial_copy_len += copy_len;
1820 partial_copy++;
1821 len += sizeof(xlog_op_header_t); /* from splitting of region */
1822 /* account for new log op header */
1823 ticket->t_curr_res -= sizeof(xlog_op_header_t);
1824 ticket->t_res_num_ophdrs++;
1825 }
1826 xlog_verify_dest_ptr(log, ptr); 1939 xlog_verify_dest_ptr(log, ptr);
1827 1940
1828 /* copy region */ 1941 /* copy region */
@@ -1834,34 +1947,34 @@ xlog_write(
1834 copy_len += start_rec_copy + sizeof(xlog_op_header_t); 1947 copy_len += start_rec_copy + sizeof(xlog_op_header_t);
1835 record_cnt++; 1948 record_cnt++;
1836 data_cnt += contwr ? copy_len : 0; 1949 data_cnt += contwr ? copy_len : 0;
1837 if (partial_copy) { /* copied partial region */ 1950
1838 /* already marked WANT_SYNC by xlog_state_get_iclog_space */ 1951 error = xlog_write_copy_finish(log, iclog, flags,
1839 xlog_state_finish_copy(log, iclog, record_cnt, data_cnt); 1952 &record_cnt, &data_cnt,
1840 record_cnt = data_cnt = 0; 1953 &partial_copy, &partial_copy_len,
1841 if ((error = xlog_state_release_iclog(log, iclog))) 1954 log_offset, commit_iclog);
1842 return error; 1955 if (error)
1843 break; /* don't increment index */ 1956 return error;
1844 } else { /* copied entire region */ 1957
1845 index++; 1958 /*
1846 partial_copy_len = partial_copy = 0; 1959 * if we had a partial copy, we need to get more iclog
1847 1960 * space but we don't want to increment the region
1848 if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) { 1961 * index because there is still more is this region to write.
1849 xlog_state_finish_copy(log, iclog, record_cnt, data_cnt); 1962 *
1850 record_cnt = data_cnt = 0; 1963 * If we completed writing this region, and we flushed
1851 spin_lock(&log->l_icloglock); 1964 * the iclog (indicated by resetting of the record
1852 xlog_state_want_sync(log, iclog); 1965 * count), then we also need to get more log space. If
1853 spin_unlock(&log->l_icloglock); 1966 * this was the last record, though, we are done and
1854 if (commit_iclog) { 1967 * can just return.
1855 ASSERT(flags & XLOG_COMMIT_TRANS); 1968 */
1856 *commit_iclog = iclog; 1969 if (partial_copy)
1857 } else if ((error = xlog_state_release_iclog(log, iclog))) 1970 break;
1858 return error; 1971
1859 if (index == nentries) 1972 index++;
1860 return 0; /* we are done */ 1973 if (record_cnt == 0) {
1861 else 1974 if (index == nentries)
1862 break; 1975 return 0;
1863 } 1976 break;
1864 } /* if (partial_copy) */ 1977 }
1865 } /* while (index < nentries) */ 1978 } /* while (index < nentries) */
1866 } /* for (index = 0; index < nentries; ) */ 1979 } /* for (index = 0; index < nentries; ) */
1867 ASSERT(len == 0); 1980 ASSERT(len == 0);