aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/bitmap.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-12-13 20:49:55 -0500
committerNeilBrown <neilb@suse.de>2009-12-13 20:51:41 -0500
commit43a705076e51c5af21ec4260a35699775ea298f5 (patch)
treeff8e161d841c41992dbbcca2a844816411941c3c /drivers/md/bitmap.c
parent72e02075a33f739e21430262f71da8e82db9dbb3 (diff)
md: support updating bitmap parameters via sysfs.
A new attribute directory 'bitmap' in 'md' is created which contains files for configuring the bitmap. 'location' identifies where the bitmap is, either 'none', or 'file' or 'sector offset from metadata'. Writing 'location' can create or remove a bitmap. Adding a 'file' bitmap this way is not yet supported. 'chunksize' and 'time_base' must be set before 'location' can be set. 'chunksize' can be set before creating a bitmap, but is currently always over-ridden by the bitmap superblock. 'time_base' and 'backlog' can be updated at any time. Signed-off-by: NeilBrown <neilb@suse.de> Reviewed-by: Andre Noll <maan@systemlinux.org>
Diffstat (limited to 'drivers/md/bitmap.c')
-rw-r--r--drivers/md/bitmap.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 958865445f06..24fff75b2191 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -510,6 +510,9 @@ void bitmap_update_sb(struct bitmap *bitmap)
510 bitmap->events_cleared = bitmap->mddev->events; 510 bitmap->events_cleared = bitmap->mddev->events;
511 sb->events_cleared = cpu_to_le64(bitmap->events_cleared); 511 sb->events_cleared = cpu_to_le64(bitmap->events_cleared);
512 } 512 }
513 /* Just in case these have been changed via sysfs: */
514 sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
515 sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind);
513 kunmap_atomic(sb, KM_USER0); 516 kunmap_atomic(sb, KM_USER0);
514 write_page(bitmap, bitmap->sb_page, 1); 517 write_page(bitmap, bitmap->sb_page, 1);
515} 518}
@@ -1714,6 +1717,208 @@ int bitmap_create(mddev_t *mddev)
1714 return err; 1717 return err;
1715} 1718}
1716 1719
1720static ssize_t
1721location_show(mddev_t *mddev, char *page)
1722{
1723 ssize_t len;
1724 if (mddev->bitmap_info.file) {
1725 len = sprintf(page, "file");
1726 } else if (mddev->bitmap_info.offset) {
1727 len = sprintf(page, "%+lld", (long long)mddev->bitmap_info.offset);
1728 } else
1729 len = sprintf(page, "none");
1730 len += sprintf(page+len, "\n");
1731 return len;
1732}
1733
1734static ssize_t
1735location_store(mddev_t *mddev, const char *buf, size_t len)
1736{
1737
1738 if (mddev->pers) {
1739 if (!mddev->pers->quiesce)
1740 return -EBUSY;
1741 if (mddev->recovery || mddev->sync_thread)
1742 return -EBUSY;
1743 }
1744
1745 if (mddev->bitmap || mddev->bitmap_info.file ||
1746 mddev->bitmap_info.offset) {
1747 /* bitmap already configured. Only option is to clear it */
1748 if (strncmp(buf, "none", 4) != 0)
1749 return -EBUSY;
1750 if (mddev->pers) {
1751 mddev->pers->quiesce(mddev, 1);
1752 bitmap_destroy(mddev);
1753 mddev->pers->quiesce(mddev, 0);
1754 }
1755 mddev->bitmap_info.offset = 0;
1756 if (mddev->bitmap_info.file) {
1757 struct file *f = mddev->bitmap_info.file;
1758 mddev->bitmap_info.file = NULL;
1759 restore_bitmap_write_access(f);
1760 fput(f);
1761 }
1762 } else {
1763 /* No bitmap, OK to set a location */
1764 long long offset;
1765 if (strncmp(buf, "none", 4) == 0)
1766 /* nothing to be done */;
1767 else if (strncmp(buf, "file:", 5) == 0) {
1768 /* Not supported yet */
1769 return -EINVAL;
1770 } else {
1771 int rv;
1772 if (buf[0] == '+')
1773 rv = strict_strtoll(buf+1, 10, &offset);
1774 else
1775 rv = strict_strtoll(buf, 10, &offset);
1776 if (rv)
1777 return rv;
1778 if (offset == 0)
1779 return -EINVAL;
1780 if (mddev->major_version == 0 &&
1781 offset != mddev->bitmap_info.default_offset)
1782 return -EINVAL;
1783 mddev->bitmap_info.offset = offset;
1784 if (mddev->pers) {
1785 mddev->pers->quiesce(mddev, 1);
1786 rv = bitmap_create(mddev);
1787 if (rv) {
1788 bitmap_destroy(mddev);
1789 mddev->bitmap_info.offset = 0;
1790 }
1791 mddev->pers->quiesce(mddev, 0);
1792 if (rv)
1793 return rv;
1794 }
1795 }
1796 }
1797 if (!mddev->external) {
1798 /* Ensure new bitmap info is stored in
1799 * metadata promptly.
1800 */
1801 set_bit(MD_CHANGE_DEVS, &mddev->flags);
1802 md_wakeup_thread(mddev->thread);
1803 }
1804 return len;
1805}
1806
1807static struct md_sysfs_entry bitmap_location =
1808__ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store);
1809
1810static ssize_t
1811timeout_show(mddev_t *mddev, char *page)
1812{
1813 ssize_t len;
1814 unsigned long secs = mddev->bitmap_info.daemon_sleep / HZ;
1815 unsigned long jifs = mddev->bitmap_info.daemon_sleep % HZ;
1816
1817 len = sprintf(page, "%lu", secs);
1818 if (jifs)
1819 len += sprintf(page+len, ".%03u", jiffies_to_msecs(jifs));
1820 len += sprintf(page+len, "\n");
1821 return len;
1822}
1823
1824static ssize_t
1825timeout_store(mddev_t *mddev, const char *buf, size_t len)
1826{
1827 /* timeout can be set at any time */
1828 unsigned long timeout;
1829 int rv = strict_strtoul_scaled(buf, &timeout, 4);
1830 if (rv)
1831 return rv;
1832
1833 /* just to make sure we don't overflow... */
1834 if (timeout >= LONG_MAX / HZ)
1835 return -EINVAL;
1836
1837 timeout = timeout * HZ / 10000;
1838
1839 if (timeout >= MAX_SCHEDULE_TIMEOUT)
1840 timeout = MAX_SCHEDULE_TIMEOUT-1;
1841 if (timeout < 1)
1842 timeout = 1;
1843 mddev->bitmap_info.daemon_sleep = timeout;
1844 if (mddev->thread) {
1845 /* if thread->timeout is MAX_SCHEDULE_TIMEOUT, then
1846 * the bitmap is all clean and we don't need to
1847 * adjust the timeout right now
1848 */
1849 if (mddev->thread->timeout < MAX_SCHEDULE_TIMEOUT) {
1850 mddev->thread->timeout = timeout;
1851 md_wakeup_thread(mddev->thread);
1852 }
1853 }
1854 return len;
1855}
1856
1857static struct md_sysfs_entry bitmap_timeout =
1858__ATTR(time_base, S_IRUGO|S_IWUSR, timeout_show, timeout_store);
1859
1860static ssize_t
1861backlog_show(mddev_t *mddev, char *page)
1862{
1863 return sprintf(page, "%lu\n", mddev->bitmap_info.max_write_behind);
1864}
1865
1866static ssize_t
1867backlog_store(mddev_t *mddev, const char *buf, size_t len)
1868{
1869 unsigned long backlog;
1870 int rv = strict_strtoul(buf, 10, &backlog);
1871 if (rv)
1872 return rv;
1873 if (backlog > COUNTER_MAX)
1874 return -EINVAL;
1875 mddev->bitmap_info.max_write_behind = backlog;
1876 return len;
1877}
1878
1879static struct md_sysfs_entry bitmap_backlog =
1880__ATTR(backlog, S_IRUGO|S_IWUSR, backlog_show, backlog_store);
1881
1882static ssize_t
1883chunksize_show(mddev_t *mddev, char *page)
1884{
1885 return sprintf(page, "%lu\n", mddev->bitmap_info.chunksize);
1886}
1887
1888static ssize_t
1889chunksize_store(mddev_t *mddev, const char *buf, size_t len)
1890{
1891 /* Can only be changed when no bitmap is active */
1892 int rv;
1893 unsigned long csize;
1894 if (mddev->bitmap)
1895 return -EBUSY;
1896 rv = strict_strtoul(buf, 10, &csize);
1897 if (rv)
1898 return rv;
1899 if (csize < 512 ||
1900 !is_power_of_2(csize))
1901 return -EINVAL;
1902 mddev->bitmap_info.chunksize = csize;
1903 return len;
1904}
1905
1906static struct md_sysfs_entry bitmap_chunksize =
1907__ATTR(chunksize, S_IRUGO|S_IWUSR, chunksize_show, chunksize_store);
1908
1909static struct attribute *md_bitmap_attrs[] = {
1910 &bitmap_location.attr,
1911 &bitmap_timeout.attr,
1912 &bitmap_backlog.attr,
1913 &bitmap_chunksize.attr,
1914 NULL
1915};
1916struct attribute_group md_bitmap_group = {
1917 .name = "bitmap",
1918 .attrs = md_bitmap_attrs,
1919};
1920
1921
1717/* the bitmap API -- for raid personalities */ 1922/* the bitmap API -- for raid personalities */
1718EXPORT_SYMBOL(bitmap_startwrite); 1923EXPORT_SYMBOL(bitmap_startwrite);
1719EXPORT_SYMBOL(bitmap_endwrite); 1924EXPORT_SYMBOL(bitmap_endwrite);