diff options
-rw-r--r-- | drivers/md/bitmap.c | 199 | ||||
-rw-r--r-- | drivers/md/bitmap.h | 3 |
2 files changed, 172 insertions, 30 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index bc552bbad83e..a35561f8f57d 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
@@ -698,7 +698,7 @@ static int bitmap_storage_alloc(struct bitmap_storage *store, | |||
698 | return -ENOMEM; | 698 | return -ENOMEM; |
699 | 699 | ||
700 | if (with_super && !store->sb_page) { | 700 | if (with_super && !store->sb_page) { |
701 | store->sb_page = alloc_page(GFP_KERNEL); | 701 | store->sb_page = alloc_page(GFP_KERNEL|__GFP_ZERO); |
702 | if (store->sb_page == NULL) | 702 | if (store->sb_page == NULL) |
703 | return -ENOMEM; | 703 | return -ENOMEM; |
704 | store->sb_page->index = 0; | 704 | store->sb_page->index = 0; |
@@ -709,7 +709,7 @@ static int bitmap_storage_alloc(struct bitmap_storage *store, | |||
709 | pnum = 1; | 709 | pnum = 1; |
710 | } | 710 | } |
711 | for ( ; pnum < num_pages; pnum++) { | 711 | for ( ; pnum < num_pages; pnum++) { |
712 | store->filemap[pnum] = alloc_page(GFP_KERNEL); | 712 | store->filemap[pnum] = alloc_page(GFP_KERNEL|__GFP_ZERO); |
713 | if (!store->filemap[pnum]) { | 713 | if (!store->filemap[pnum]) { |
714 | store->file_pages = pnum; | 714 | store->file_pages = pnum; |
715 | return -ENOMEM; | 715 | return -ENOMEM; |
@@ -1630,8 +1630,6 @@ int bitmap_create(struct mddev *mddev) | |||
1630 | { | 1630 | { |
1631 | struct bitmap *bitmap; | 1631 | struct bitmap *bitmap; |
1632 | sector_t blocks = mddev->resync_max_sectors; | 1632 | sector_t blocks = mddev->resync_max_sectors; |
1633 | unsigned long chunks; | ||
1634 | unsigned long pages; | ||
1635 | struct file *file = mddev->bitmap_info.file; | 1633 | struct file *file = mddev->bitmap_info.file; |
1636 | int err; | 1634 | int err; |
1637 | struct sysfs_dirent *bm = NULL; | 1635 | struct sysfs_dirent *bm = NULL; |
@@ -1691,37 +1689,14 @@ int bitmap_create(struct mddev *mddev) | |||
1691 | goto error; | 1689 | goto error; |
1692 | 1690 | ||
1693 | bitmap->daemon_lastrun = jiffies; | 1691 | bitmap->daemon_lastrun = jiffies; |
1694 | bitmap->counts.chunkshift = (ffz(~mddev->bitmap_info.chunksize) | 1692 | err = bitmap_resize(bitmap, blocks, mddev->bitmap_info.chunksize, 1); |
1695 | - BITMAP_BLOCK_SHIFT); | 1693 | if (err) |
1696 | |||
1697 | chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << bitmap->counts.chunkshift); | ||
1698 | pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO); | ||
1699 | |||
1700 | BUG_ON(!pages); | ||
1701 | |||
1702 | bitmap->counts.chunks = chunks; | ||
1703 | bitmap->counts.pages = pages; | ||
1704 | bitmap->counts.missing_pages = pages; | ||
1705 | |||
1706 | bitmap->counts.bp = kzalloc(pages * sizeof(*bitmap->counts.bp), | ||
1707 | GFP_KERNEL); | ||
1708 | |||
1709 | err = -ENOMEM; | ||
1710 | if (!bitmap->counts.bp) | ||
1711 | goto error; | 1694 | goto error; |
1712 | 1695 | ||
1713 | if (file || mddev->bitmap_info.offset) { | ||
1714 | err = bitmap_storage_alloc(&bitmap->storage, bitmap->counts.chunks, | ||
1715 | !mddev->bitmap_info.external); | ||
1716 | if (err) | ||
1717 | goto error; | ||
1718 | } | ||
1719 | printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", | 1696 | printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", |
1720 | pages, bmname(bitmap)); | 1697 | bitmap->counts.pages, bmname(bitmap)); |
1721 | 1698 | ||
1722 | mddev->bitmap = bitmap; | 1699 | mddev->bitmap = bitmap; |
1723 | |||
1724 | |||
1725 | return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0; | 1700 | return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0; |
1726 | 1701 | ||
1727 | error: | 1702 | error: |
@@ -1807,6 +1782,170 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) | |||
1807 | seq_printf(seq, "\n"); | 1782 | seq_printf(seq, "\n"); |
1808 | } | 1783 | } |
1809 | 1784 | ||
1785 | int bitmap_resize(struct bitmap *bitmap, sector_t blocks, | ||
1786 | int chunksize, int init) | ||
1787 | { | ||
1788 | /* If chunk_size is 0, choose an appropriate chunk size. | ||
1789 | * Then possibly allocate new storage space. | ||
1790 | * Then quiesce, copy bits, replace bitmap, and re-start | ||
1791 | * | ||
1792 | * This function is called both to set up the initial bitmap | ||
1793 | * and to resize the bitmap while the array is active. | ||
1794 | * If this happens as a result of the array being resized, | ||
1795 | * chunksize will be zero, and we need to choose a suitable | ||
1796 | * chunksize, otherwise we use what we are given. | ||
1797 | */ | ||
1798 | struct bitmap_storage store; | ||
1799 | struct bitmap_counts old_counts; | ||
1800 | unsigned long chunks; | ||
1801 | sector_t block; | ||
1802 | sector_t old_blocks, new_blocks; | ||
1803 | int chunkshift; | ||
1804 | int ret = 0; | ||
1805 | long pages; | ||
1806 | struct bitmap_page *new_bp; | ||
1807 | |||
1808 | if (chunksize == 0) { | ||
1809 | /* If there is enough space, leave the chunk size unchanged, | ||
1810 | * else increase by factor of two until there is enough space. | ||
1811 | */ | ||
1812 | long bytes; | ||
1813 | long space = bitmap->mddev->bitmap_info.space; | ||
1814 | |||
1815 | if (space == 0) { | ||
1816 | /* We don't know how much space there is, so limit | ||
1817 | * to current size - in sectors. | ||
1818 | */ | ||
1819 | bytes = DIV_ROUND_UP(bitmap->counts.chunks, 8); | ||
1820 | if (!bitmap->mddev->bitmap_info.external) | ||
1821 | bytes += sizeof(bitmap_super_t); | ||
1822 | space = DIV_ROUND_UP(bytes, 512); | ||
1823 | bitmap->mddev->bitmap_info.space = space; | ||
1824 | } | ||
1825 | chunkshift = bitmap->counts.chunkshift; | ||
1826 | chunkshift--; | ||
1827 | do { | ||
1828 | /* 'chunkshift' is shift from block size to chunk size */ | ||
1829 | chunkshift++; | ||
1830 | chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift); | ||
1831 | bytes = DIV_ROUND_UP(chunks, 8); | ||
1832 | if (!bitmap->mddev->bitmap_info.external) | ||
1833 | bytes += sizeof(bitmap_super_t); | ||
1834 | } while (bytes > (space << 9)); | ||
1835 | } else | ||
1836 | chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT; | ||
1837 | |||
1838 | chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift); | ||
1839 | memset(&store, 0, sizeof(store)); | ||
1840 | if (bitmap->mddev->bitmap_info.offset || bitmap->mddev->bitmap_info.file) | ||
1841 | ret = bitmap_storage_alloc(&store, chunks, | ||
1842 | !bitmap->mddev->bitmap_info.external); | ||
1843 | if (ret) | ||
1844 | goto err; | ||
1845 | |||
1846 | pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO); | ||
1847 | |||
1848 | new_bp = kzalloc(pages * sizeof(*new_bp), GFP_KERNEL); | ||
1849 | ret = -ENOMEM; | ||
1850 | if (!new_bp) { | ||
1851 | bitmap_file_unmap(&store); | ||
1852 | goto err; | ||
1853 | } | ||
1854 | |||
1855 | if (!init) | ||
1856 | bitmap->mddev->pers->quiesce(bitmap->mddev, 1); | ||
1857 | |||
1858 | store.file = bitmap->storage.file; | ||
1859 | bitmap->storage.file = NULL; | ||
1860 | |||
1861 | if (store.sb_page && bitmap->storage.sb_page) | ||
1862 | memcpy(page_address(store.sb_page), | ||
1863 | page_address(bitmap->storage.sb_page), | ||
1864 | sizeof(bitmap_super_t)); | ||
1865 | bitmap_file_unmap(&bitmap->storage); | ||
1866 | bitmap->storage = store; | ||
1867 | |||
1868 | old_counts = bitmap->counts; | ||
1869 | bitmap->counts.bp = new_bp; | ||
1870 | bitmap->counts.pages = pages; | ||
1871 | bitmap->counts.missing_pages = pages; | ||
1872 | bitmap->counts.chunkshift = chunkshift; | ||
1873 | bitmap->counts.chunks = chunks; | ||
1874 | bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift + | ||
1875 | BITMAP_BLOCK_SHIFT); | ||
1876 | |||
1877 | blocks = min(old_counts.chunks << old_counts.chunkshift, | ||
1878 | chunks << chunkshift); | ||
1879 | |||
1880 | spin_lock_irq(&bitmap->counts.lock); | ||
1881 | for (block = 0; block < blocks; ) { | ||
1882 | bitmap_counter_t *bmc_old, *bmc_new; | ||
1883 | int set; | ||
1884 | |||
1885 | bmc_old = bitmap_get_counter(&old_counts, block, | ||
1886 | &old_blocks, 0); | ||
1887 | set = bmc_old && NEEDED(*bmc_old); | ||
1888 | |||
1889 | if (set) { | ||
1890 | bmc_new = bitmap_get_counter(&bitmap->counts, block, | ||
1891 | &new_blocks, 1); | ||
1892 | if (*bmc_new == 0) { | ||
1893 | /* need to set on-disk bits too. */ | ||
1894 | sector_t end = block + new_blocks; | ||
1895 | sector_t start = block >> chunkshift; | ||
1896 | start <<= chunkshift; | ||
1897 | while (start < end) { | ||
1898 | bitmap_file_set_bit(bitmap, block); | ||
1899 | start += 1 << chunkshift; | ||
1900 | } | ||
1901 | *bmc_new = 2; | ||
1902 | bitmap_count_page(&bitmap->counts, | ||
1903 | block, 1); | ||
1904 | bitmap_set_pending(&bitmap->counts, | ||
1905 | block); | ||
1906 | } | ||
1907 | *bmc_new |= NEEDED_MASK; | ||
1908 | if (new_blocks < old_blocks) | ||
1909 | old_blocks = new_blocks; | ||
1910 | } | ||
1911 | block += old_blocks; | ||
1912 | } | ||
1913 | |||
1914 | if (!init) { | ||
1915 | int i; | ||
1916 | while (block < (chunks << chunkshift)) { | ||
1917 | bitmap_counter_t *bmc; | ||
1918 | bmc = bitmap_get_counter(&bitmap->counts, block, | ||
1919 | &new_blocks, 1); | ||
1920 | if (bmc) { | ||
1921 | /* new space. It needs to be resynced, so | ||
1922 | * we set NEEDED_MASK. | ||
1923 | */ | ||
1924 | if (*bmc == 0) { | ||
1925 | *bmc = NEEDED_MASK | 2; | ||
1926 | bitmap_count_page(&bitmap->counts, | ||
1927 | block, 1); | ||
1928 | bitmap_set_pending(&bitmap->counts, | ||
1929 | block); | ||
1930 | } | ||
1931 | } | ||
1932 | block += new_blocks; | ||
1933 | } | ||
1934 | for (i = 0; i < bitmap->storage.file_pages; i++) | ||
1935 | set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); | ||
1936 | } | ||
1937 | spin_unlock_irq(&bitmap->counts.lock); | ||
1938 | |||
1939 | if (!init) { | ||
1940 | bitmap_unplug(bitmap); | ||
1941 | bitmap->mddev->pers->quiesce(bitmap->mddev, 0); | ||
1942 | } | ||
1943 | ret = 0; | ||
1944 | err: | ||
1945 | return ret; | ||
1946 | } | ||
1947 | EXPORT_SYMBOL_GPL(bitmap_resize); | ||
1948 | |||
1810 | static ssize_t | 1949 | static ssize_t |
1811 | location_show(struct mddev *mddev, char *page) | 1950 | location_show(struct mddev *mddev, char *page) |
1812 | { | 1951 | { |
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 6bde180e987b..04dcde3871be 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h | |||
@@ -255,6 +255,9 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); | |||
255 | 255 | ||
256 | void bitmap_unplug(struct bitmap *bitmap); | 256 | void bitmap_unplug(struct bitmap *bitmap); |
257 | void bitmap_daemon_work(struct mddev *mddev); | 257 | void bitmap_daemon_work(struct mddev *mddev); |
258 | |||
259 | int bitmap_resize(struct bitmap *bitmap, sector_t blocks, | ||
260 | int chunksize, int init); | ||
258 | #endif | 261 | #endif |
259 | 262 | ||
260 | #endif | 263 | #endif |