aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/bitmap.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-05-21 23:55:25 -0400
committerNeilBrown <neilb@suse.de>2012-05-21 23:55:25 -0400
commitd60b479d177a5735b6b4db6ee5280ef6653f50e7 (patch)
tree8fc110bc113817f237559da6da68ca2a75e3614c /drivers/md/bitmap.c
parent15702d7fb6e7a6baf5a04286a227b0ad2fe4a03f (diff)
md/bitmap: add bitmap_resize function to allow bitmap resizing.
This function will allocate the new data structures and copy bits across from old to new, allowing for the possibility that the chunksize has changed. Use the same function for performing the initial allocation of the structures. This improves test coverage. When bitmap_resize is used to resize an existing bitmap, it only copies '1' bits in, not '0' bits. So when allocating the bitmap, ensure everything is initialised to ZERO. Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/bitmap.c')
-rw-r--r--drivers/md/bitmap.c199
1 files changed, 169 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
1785int 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;
1944err:
1945 return ret;
1946}
1947EXPORT_SYMBOL_GPL(bitmap_resize);
1948
1810static ssize_t 1949static ssize_t
1811location_show(struct mddev *mddev, char *page) 1950location_show(struct mddev *mddev, char *page)
1812{ 1951{