diff options
Diffstat (limited to 'fs/ubifs/lpt_commit.c')
-rw-r--r-- | fs/ubifs/lpt_commit.c | 210 |
1 files changed, 173 insertions, 37 deletions
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index a41434b42785..96ca95707175 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c | |||
@@ -320,6 +320,8 @@ no_space: | |||
320 | dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, " | 320 | dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, " |
321 | "done_lsave %d", lnum, offs, len, done_ltab, done_lsave); | 321 | "done_lsave %d", lnum, offs, len, done_ltab, done_lsave); |
322 | dbg_dump_lpt_info(c); | 322 | dbg_dump_lpt_info(c); |
323 | dbg_dump_lpt_lebs(c); | ||
324 | dump_stack(); | ||
323 | return err; | 325 | return err; |
324 | } | 326 | } |
325 | 327 | ||
@@ -546,8 +548,10 @@ static int write_cnodes(struct ubifs_info *c) | |||
546 | no_space: | 548 | no_space: |
547 | ubifs_err("LPT out of space mismatch"); | 549 | ubifs_err("LPT out of space mismatch"); |
548 | dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab " | 550 | dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab " |
549 | "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave); | 551 | "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave); |
550 | dbg_dump_lpt_info(c); | 552 | dbg_dump_lpt_info(c); |
553 | dbg_dump_lpt_lebs(c); | ||
554 | dump_stack(); | ||
551 | return err; | 555 | return err; |
552 | } | 556 | } |
553 | 557 | ||
@@ -749,7 +753,7 @@ static void lpt_tgc_start(struct ubifs_info *c) | |||
749 | * LPT trivial garbage collection is where a LPT LEB contains only dirty and | 753 | * LPT trivial garbage collection is where a LPT LEB contains only dirty and |
750 | * free space and so may be reused as soon as the next commit is completed. | 754 | * free space and so may be reused as soon as the next commit is completed. |
751 | * This function is called after the commit is completed (master node has been | 755 | * This function is called after the commit is completed (master node has been |
752 | * written) and unmaps LPT LEBs that were marked for trivial GC. | 756 | * written) and un-maps LPT LEBs that were marked for trivial GC. |
753 | */ | 757 | */ |
754 | static int lpt_tgc_end(struct ubifs_info *c) | 758 | static int lpt_tgc_end(struct ubifs_info *c) |
755 | { | 759 | { |
@@ -1025,7 +1029,7 @@ static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num, | |||
1025 | * @c: UBIFS file-system description object | 1029 | * @c: UBIFS file-system description object |
1026 | * @node_type: LPT node type | 1030 | * @node_type: LPT node type |
1027 | */ | 1031 | */ |
1028 | static int get_lpt_node_len(struct ubifs_info *c, int node_type) | 1032 | static int get_lpt_node_len(const struct ubifs_info *c, int node_type) |
1029 | { | 1033 | { |
1030 | switch (node_type) { | 1034 | switch (node_type) { |
1031 | case UBIFS_LPT_NNODE: | 1035 | case UBIFS_LPT_NNODE: |
@@ -1046,7 +1050,7 @@ static int get_lpt_node_len(struct ubifs_info *c, int node_type) | |||
1046 | * @buf: buffer | 1050 | * @buf: buffer |
1047 | * @len: length of buffer | 1051 | * @len: length of buffer |
1048 | */ | 1052 | */ |
1049 | static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len) | 1053 | static int get_pad_len(const struct ubifs_info *c, uint8_t *buf, int len) |
1050 | { | 1054 | { |
1051 | int offs, pad_len; | 1055 | int offs, pad_len; |
1052 | 1056 | ||
@@ -1063,7 +1067,8 @@ static int get_pad_len(struct ubifs_info *c, uint8_t *buf, int len) | |||
1063 | * @buf: buffer | 1067 | * @buf: buffer |
1064 | * @node_num: node number is returned here | 1068 | * @node_num: node number is returned here |
1065 | */ | 1069 | */ |
1066 | static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num) | 1070 | static int get_lpt_node_type(const struct ubifs_info *c, uint8_t *buf, |
1071 | int *node_num) | ||
1067 | { | 1072 | { |
1068 | uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; | 1073 | uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; |
1069 | int pos = 0, node_type; | 1074 | int pos = 0, node_type; |
@@ -1081,7 +1086,7 @@ static int get_lpt_node_type(struct ubifs_info *c, uint8_t *buf, int *node_num) | |||
1081 | * | 1086 | * |
1082 | * This function returns %1 if the buffer contains a node or %0 if it does not. | 1087 | * This function returns %1 if the buffer contains a node or %0 if it does not. |
1083 | */ | 1088 | */ |
1084 | static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len) | 1089 | static int is_a_node(const struct ubifs_info *c, uint8_t *buf, int len) |
1085 | { | 1090 | { |
1086 | uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; | 1091 | uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES; |
1087 | int pos = 0, node_type, node_len; | 1092 | int pos = 0, node_type, node_len; |
@@ -1105,7 +1110,6 @@ static int is_a_node(struct ubifs_info *c, uint8_t *buf, int len) | |||
1105 | return 1; | 1110 | return 1; |
1106 | } | 1111 | } |
1107 | 1112 | ||
1108 | |||
1109 | /** | 1113 | /** |
1110 | * lpt_gc_lnum - garbage collect a LPT LEB. | 1114 | * lpt_gc_lnum - garbage collect a LPT LEB. |
1111 | * @c: UBIFS file-system description object | 1115 | * @c: UBIFS file-system description object |
@@ -1463,7 +1467,7 @@ void ubifs_lpt_free(struct ubifs_info *c, int wr_only) | |||
1463 | #ifdef CONFIG_UBIFS_FS_DEBUG | 1467 | #ifdef CONFIG_UBIFS_FS_DEBUG |
1464 | 1468 | ||
1465 | /** | 1469 | /** |
1466 | * dbg_is_all_ff - determine if a buffer contains only 0xff bytes. | 1470 | * dbg_is_all_ff - determine if a buffer contains only 0xFF bytes. |
1467 | * @buf: buffer | 1471 | * @buf: buffer |
1468 | * @len: buffer length | 1472 | * @len: buffer length |
1469 | */ | 1473 | */ |
@@ -1488,7 +1492,7 @@ static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs) | |||
1488 | struct ubifs_nnode *nnode; | 1492 | struct ubifs_nnode *nnode; |
1489 | int hght; | 1493 | int hght; |
1490 | 1494 | ||
1491 | /* Entire tree is in memory so first_nnode / next_nnode are ok */ | 1495 | /* Entire tree is in memory so first_nnode / next_nnode are OK */ |
1492 | nnode = first_nnode(c, &hght); | 1496 | nnode = first_nnode(c, &hght); |
1493 | for (; nnode; nnode = next_nnode(c, nnode, &hght)) { | 1497 | for (; nnode; nnode = next_nnode(c, nnode, &hght)) { |
1494 | struct ubifs_nbranch *branch; | 1498 | struct ubifs_nbranch *branch; |
@@ -1602,7 +1606,10 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) | |||
1602 | { | 1606 | { |
1603 | int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len; | 1607 | int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len; |
1604 | int ret; | 1608 | int ret; |
1605 | void *buf = c->dbg_buf; | 1609 | void *buf = c->dbg->buf; |
1610 | |||
1611 | if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) | ||
1612 | return 0; | ||
1606 | 1613 | ||
1607 | dbg_lp("LEB %d", lnum); | 1614 | dbg_lp("LEB %d", lnum); |
1608 | err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); | 1615 | err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); |
@@ -1704,6 +1711,9 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c) | |||
1704 | long long free = 0; | 1711 | long long free = 0; |
1705 | int i; | 1712 | int i; |
1706 | 1713 | ||
1714 | if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) | ||
1715 | return 0; | ||
1716 | |||
1707 | for (i = 0; i < c->lpt_lebs; i++) { | 1717 | for (i = 0; i < c->lpt_lebs; i++) { |
1708 | if (c->ltab[i].tgc || c->ltab[i].cmt) | 1718 | if (c->ltab[i].tgc || c->ltab[i].cmt) |
1709 | continue; | 1719 | continue; |
@@ -1716,6 +1726,8 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c) | |||
1716 | dbg_err("LPT space error: free %lld lpt_sz %lld", | 1726 | dbg_err("LPT space error: free %lld lpt_sz %lld", |
1717 | free, c->lpt_sz); | 1727 | free, c->lpt_sz); |
1718 | dbg_dump_lpt_info(c); | 1728 | dbg_dump_lpt_info(c); |
1729 | dbg_dump_lpt_lebs(c); | ||
1730 | dump_stack(); | ||
1719 | return -EINVAL; | 1731 | return -EINVAL; |
1720 | } | 1732 | } |
1721 | return 0; | 1733 | return 0; |
@@ -1731,15 +1743,19 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c) | |||
1731 | */ | 1743 | */ |
1732 | int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) | 1744 | int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) |
1733 | { | 1745 | { |
1746 | struct ubifs_debug_info *d = c->dbg; | ||
1734 | long long chk_lpt_sz, lpt_sz; | 1747 | long long chk_lpt_sz, lpt_sz; |
1735 | int err = 0; | 1748 | int err = 0; |
1736 | 1749 | ||
1750 | if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) | ||
1751 | return 0; | ||
1752 | |||
1737 | switch (action) { | 1753 | switch (action) { |
1738 | case 0: | 1754 | case 0: |
1739 | c->chk_lpt_sz = 0; | 1755 | d->chk_lpt_sz = 0; |
1740 | c->chk_lpt_sz2 = 0; | 1756 | d->chk_lpt_sz2 = 0; |
1741 | c->chk_lpt_lebs = 0; | 1757 | d->chk_lpt_lebs = 0; |
1742 | c->chk_lpt_wastage = 0; | 1758 | d->chk_lpt_wastage = 0; |
1743 | if (c->dirty_pn_cnt > c->pnode_cnt) { | 1759 | if (c->dirty_pn_cnt > c->pnode_cnt) { |
1744 | dbg_err("dirty pnodes %d exceed max %d", | 1760 | dbg_err("dirty pnodes %d exceed max %d", |
1745 | c->dirty_pn_cnt, c->pnode_cnt); | 1761 | c->dirty_pn_cnt, c->pnode_cnt); |
@@ -1752,35 +1768,35 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) | |||
1752 | } | 1768 | } |
1753 | return err; | 1769 | return err; |
1754 | case 1: | 1770 | case 1: |
1755 | c->chk_lpt_sz += len; | 1771 | d->chk_lpt_sz += len; |
1756 | return 0; | 1772 | return 0; |
1757 | case 2: | 1773 | case 2: |
1758 | c->chk_lpt_sz += len; | 1774 | d->chk_lpt_sz += len; |
1759 | c->chk_lpt_wastage += len; | 1775 | d->chk_lpt_wastage += len; |
1760 | c->chk_lpt_lebs += 1; | 1776 | d->chk_lpt_lebs += 1; |
1761 | return 0; | 1777 | return 0; |
1762 | case 3: | 1778 | case 3: |
1763 | chk_lpt_sz = c->leb_size; | 1779 | chk_lpt_sz = c->leb_size; |
1764 | chk_lpt_sz *= c->chk_lpt_lebs; | 1780 | chk_lpt_sz *= d->chk_lpt_lebs; |
1765 | chk_lpt_sz += len - c->nhead_offs; | 1781 | chk_lpt_sz += len - c->nhead_offs; |
1766 | if (c->chk_lpt_sz != chk_lpt_sz) { | 1782 | if (d->chk_lpt_sz != chk_lpt_sz) { |
1767 | dbg_err("LPT wrote %lld but space used was %lld", | 1783 | dbg_err("LPT wrote %lld but space used was %lld", |
1768 | c->chk_lpt_sz, chk_lpt_sz); | 1784 | d->chk_lpt_sz, chk_lpt_sz); |
1769 | err = -EINVAL; | 1785 | err = -EINVAL; |
1770 | } | 1786 | } |
1771 | if (c->chk_lpt_sz > c->lpt_sz) { | 1787 | if (d->chk_lpt_sz > c->lpt_sz) { |
1772 | dbg_err("LPT wrote %lld but lpt_sz is %lld", | 1788 | dbg_err("LPT wrote %lld but lpt_sz is %lld", |
1773 | c->chk_lpt_sz, c->lpt_sz); | 1789 | d->chk_lpt_sz, c->lpt_sz); |
1774 | err = -EINVAL; | 1790 | err = -EINVAL; |
1775 | } | 1791 | } |
1776 | if (c->chk_lpt_sz2 && c->chk_lpt_sz != c->chk_lpt_sz2) { | 1792 | if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) { |
1777 | dbg_err("LPT layout size %lld but wrote %lld", | 1793 | dbg_err("LPT layout size %lld but wrote %lld", |
1778 | c->chk_lpt_sz, c->chk_lpt_sz2); | 1794 | d->chk_lpt_sz, d->chk_lpt_sz2); |
1779 | err = -EINVAL; | 1795 | err = -EINVAL; |
1780 | } | 1796 | } |
1781 | if (c->chk_lpt_sz2 && c->new_nhead_offs != len) { | 1797 | if (d->chk_lpt_sz2 && d->new_nhead_offs != len) { |
1782 | dbg_err("LPT new nhead offs: expected %d was %d", | 1798 | dbg_err("LPT new nhead offs: expected %d was %d", |
1783 | c->new_nhead_offs, len); | 1799 | d->new_nhead_offs, len); |
1784 | err = -EINVAL; | 1800 | err = -EINVAL; |
1785 | } | 1801 | } |
1786 | lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; | 1802 | lpt_sz = (long long)c->pnode_cnt * c->pnode_sz; |
@@ -1788,26 +1804,146 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) | |||
1788 | lpt_sz += c->ltab_sz; | 1804 | lpt_sz += c->ltab_sz; |
1789 | if (c->big_lpt) | 1805 | if (c->big_lpt) |
1790 | lpt_sz += c->lsave_sz; | 1806 | lpt_sz += c->lsave_sz; |
1791 | if (c->chk_lpt_sz - c->chk_lpt_wastage > lpt_sz) { | 1807 | if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) { |
1792 | dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", | 1808 | dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld", |
1793 | c->chk_lpt_sz, c->chk_lpt_wastage, lpt_sz); | 1809 | d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz); |
1794 | err = -EINVAL; | 1810 | err = -EINVAL; |
1795 | } | 1811 | } |
1796 | if (err) | 1812 | if (err) { |
1797 | dbg_dump_lpt_info(c); | 1813 | dbg_dump_lpt_info(c); |
1798 | c->chk_lpt_sz2 = c->chk_lpt_sz; | 1814 | dbg_dump_lpt_lebs(c); |
1799 | c->chk_lpt_sz = 0; | 1815 | dump_stack(); |
1800 | c->chk_lpt_wastage = 0; | 1816 | } |
1801 | c->chk_lpt_lebs = 0; | 1817 | d->chk_lpt_sz2 = d->chk_lpt_sz; |
1802 | c->new_nhead_offs = len; | 1818 | d->chk_lpt_sz = 0; |
1819 | d->chk_lpt_wastage = 0; | ||
1820 | d->chk_lpt_lebs = 0; | ||
1821 | d->new_nhead_offs = len; | ||
1803 | return err; | 1822 | return err; |
1804 | case 4: | 1823 | case 4: |
1805 | c->chk_lpt_sz += len; | 1824 | d->chk_lpt_sz += len; |
1806 | c->chk_lpt_wastage += len; | 1825 | d->chk_lpt_wastage += len; |
1807 | return 0; | 1826 | return 0; |
1808 | default: | 1827 | default: |
1809 | return -EINVAL; | 1828 | return -EINVAL; |
1810 | } | 1829 | } |
1811 | } | 1830 | } |
1812 | 1831 | ||
1832 | /** | ||
1833 | * dbg_dump_lpt_leb - dump an LPT LEB. | ||
1834 | * @c: UBIFS file-system description object | ||
1835 | * @lnum: LEB number to dump | ||
1836 | * | ||
1837 | * This function dumps an LEB from LPT area. Nodes in this area are very | ||
1838 | * different to nodes in the main area (e.g., they do not have common headers, | ||
1839 | * they do not have 8-byte alignments, etc), so we have a separate function to | ||
1840 | * dump LPT area LEBs. Note, LPT has to be locked by the caller. | ||
1841 | */ | ||
1842 | static void dump_lpt_leb(const struct ubifs_info *c, int lnum) | ||
1843 | { | ||
1844 | int err, len = c->leb_size, node_type, node_num, node_len, offs; | ||
1845 | void *buf = c->dbg->buf; | ||
1846 | |||
1847 | printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n", | ||
1848 | current->pid, lnum); | ||
1849 | err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); | ||
1850 | if (err) { | ||
1851 | ubifs_err("cannot read LEB %d, error %d", lnum, err); | ||
1852 | return; | ||
1853 | } | ||
1854 | while (1) { | ||
1855 | offs = c->leb_size - len; | ||
1856 | if (!is_a_node(c, buf, len)) { | ||
1857 | int pad_len; | ||
1858 | |||
1859 | pad_len = get_pad_len(c, buf, len); | ||
1860 | if (pad_len) { | ||
1861 | printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n", | ||
1862 | lnum, offs, pad_len); | ||
1863 | buf += pad_len; | ||
1864 | len -= pad_len; | ||
1865 | continue; | ||
1866 | } | ||
1867 | if (len) | ||
1868 | printk(KERN_DEBUG "LEB %d:%d, free %d bytes\n", | ||
1869 | lnum, offs, len); | ||
1870 | break; | ||
1871 | } | ||
1872 | |||
1873 | node_type = get_lpt_node_type(c, buf, &node_num); | ||
1874 | switch (node_type) { | ||
1875 | case UBIFS_LPT_PNODE: | ||
1876 | { | ||
1877 | node_len = c->pnode_sz; | ||
1878 | if (c->big_lpt) | ||
1879 | printk(KERN_DEBUG "LEB %d:%d, pnode num %d\n", | ||
1880 | lnum, offs, node_num); | ||
1881 | else | ||
1882 | printk(KERN_DEBUG "LEB %d:%d, pnode\n", | ||
1883 | lnum, offs); | ||
1884 | break; | ||
1885 | } | ||
1886 | case UBIFS_LPT_NNODE: | ||
1887 | { | ||
1888 | int i; | ||
1889 | struct ubifs_nnode nnode; | ||
1890 | |||
1891 | node_len = c->nnode_sz; | ||
1892 | if (c->big_lpt) | ||
1893 | printk(KERN_DEBUG "LEB %d:%d, nnode num %d, ", | ||
1894 | lnum, offs, node_num); | ||
1895 | else | ||
1896 | printk(KERN_DEBUG "LEB %d:%d, nnode, ", | ||
1897 | lnum, offs); | ||
1898 | err = ubifs_unpack_nnode(c, buf, &nnode); | ||
1899 | for (i = 0; i < UBIFS_LPT_FANOUT; i++) { | ||
1900 | printk("%d:%d", nnode.nbranch[i].lnum, | ||
1901 | nnode.nbranch[i].offs); | ||
1902 | if (i != UBIFS_LPT_FANOUT - 1) | ||
1903 | printk(", "); | ||
1904 | } | ||
1905 | printk("\n"); | ||
1906 | break; | ||
1907 | } | ||
1908 | case UBIFS_LPT_LTAB: | ||
1909 | node_len = c->ltab_sz; | ||
1910 | printk(KERN_DEBUG "LEB %d:%d, ltab\n", | ||
1911 | lnum, offs); | ||
1912 | break; | ||
1913 | case UBIFS_LPT_LSAVE: | ||
1914 | node_len = c->lsave_sz; | ||
1915 | printk(KERN_DEBUG "LEB %d:%d, lsave len\n", lnum, offs); | ||
1916 | break; | ||
1917 | default: | ||
1918 | ubifs_err("LPT node type %d not recognized", node_type); | ||
1919 | return; | ||
1920 | } | ||
1921 | |||
1922 | buf += node_len; | ||
1923 | len -= node_len; | ||
1924 | } | ||
1925 | |||
1926 | printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n", | ||
1927 | current->pid, lnum); | ||
1928 | } | ||
1929 | |||
1930 | /** | ||
1931 | * dbg_dump_lpt_lebs - dump LPT lebs. | ||
1932 | * @c: UBIFS file-system description object | ||
1933 | * | ||
1934 | * This function dumps all LPT LEBs. The caller has to make sure the LPT is | ||
1935 | * locked. | ||
1936 | */ | ||
1937 | void dbg_dump_lpt_lebs(const struct ubifs_info *c) | ||
1938 | { | ||
1939 | int i; | ||
1940 | |||
1941 | printk(KERN_DEBUG "(pid %d) start dumping all LPT LEBs\n", | ||
1942 | current->pid); | ||
1943 | for (i = 0; i < c->lpt_lebs; i++) | ||
1944 | dump_lpt_leb(c, i + c->lpt_first); | ||
1945 | printk(KERN_DEBUG "(pid %d) finish dumping all LPT LEBs\n", | ||
1946 | current->pid); | ||
1947 | } | ||
1948 | |||
1813 | #endif /* CONFIG_UBIFS_FS_DEBUG */ | 1949 | #endif /* CONFIG_UBIFS_FS_DEBUG */ |