diff options
-rw-r--r-- | Documentation/md.txt | 29 | ||||
-rw-r--r-- | drivers/md/bitmap.c | 205 | ||||
-rw-r--r-- | drivers/md/md.c | 5 | ||||
-rw-r--r-- | drivers/md/md.h | 3 |
4 files changed, 240 insertions, 2 deletions
diff --git a/Documentation/md.txt b/Documentation/md.txt index 4edd39ec7db9..18fad6876228 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt | |||
@@ -296,6 +296,35 @@ All md devices contain: | |||
296 | active-idle | 296 | active-idle |
297 | like active, but no writes have been seen for a while (safe_mode_delay). | 297 | like active, but no writes have been seen for a while (safe_mode_delay). |
298 | 298 | ||
299 | bitmap/location | ||
300 | This indicates where the write-intent bitmap for the array is | ||
301 | stored. | ||
302 | It can be one of "none", "file" or "[+-]N". | ||
303 | "file" may later be extended to "file:/file/name" | ||
304 | "[+-]N" means that many sectors from the start of the metadata. | ||
305 | This is replicated on all devices. For arrays with externally | ||
306 | managed metadata, the offset is from the beginning of the | ||
307 | device. | ||
308 | bitmap/chunksize | ||
309 | The size, in bytes, of the chunk which will be represented by a | ||
310 | single bit. For RAID456, it is a portion of an individual | ||
311 | device. For RAID10, it is a portion of the array. For RAID1, it | ||
312 | is both (they come to the same thing). | ||
313 | bitmap/time_base | ||
314 | The time, in seconds, between looking for bits in the bitmap to | ||
315 | be cleared. In the current implementation, a bit will be cleared | ||
316 | between 2 and 3 times "time_base" after all the covered blocks | ||
317 | are known to be in-sync. | ||
318 | bitmap/backlog | ||
319 | When write-mostly devices are active in a RAID1, write requests | ||
320 | to those devices proceed in the background - the filesystem (or | ||
321 | other user of the device) does not have to wait for them. | ||
322 | 'backlog' sets a limit on the number of concurrent background | ||
323 | writes. If there are more than this, new writes will by | ||
324 | synchronous. | ||
325 | |||
326 | |||
327 | |||
299 | 328 | ||
300 | As component devices are added to an md array, they appear in the 'md' | 329 | As component devices are added to an md array, they appear in the 'md' |
301 | directory as new directories named | 330 | directory as new directories named |
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 | ||
1720 | static ssize_t | ||
1721 | location_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 | |||
1734 | static ssize_t | ||
1735 | location_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 | |||
1807 | static struct md_sysfs_entry bitmap_location = | ||
1808 | __ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store); | ||
1809 | |||
1810 | static ssize_t | ||
1811 | timeout_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 | |||
1824 | static ssize_t | ||
1825 | timeout_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 | |||
1857 | static struct md_sysfs_entry bitmap_timeout = | ||
1858 | __ATTR(time_base, S_IRUGO|S_IWUSR, timeout_show, timeout_store); | ||
1859 | |||
1860 | static ssize_t | ||
1861 | backlog_show(mddev_t *mddev, char *page) | ||
1862 | { | ||
1863 | return sprintf(page, "%lu\n", mddev->bitmap_info.max_write_behind); | ||
1864 | } | ||
1865 | |||
1866 | static ssize_t | ||
1867 | backlog_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 | |||
1879 | static struct md_sysfs_entry bitmap_backlog = | ||
1880 | __ATTR(backlog, S_IRUGO|S_IWUSR, backlog_show, backlog_store); | ||
1881 | |||
1882 | static ssize_t | ||
1883 | chunksize_show(mddev_t *mddev, char *page) | ||
1884 | { | ||
1885 | return sprintf(page, "%lu\n", mddev->bitmap_info.chunksize); | ||
1886 | } | ||
1887 | |||
1888 | static ssize_t | ||
1889 | chunksize_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 | |||
1906 | static struct md_sysfs_entry bitmap_chunksize = | ||
1907 | __ATTR(chunksize, S_IRUGO|S_IWUSR, chunksize_show, chunksize_store); | ||
1908 | |||
1909 | static struct attribute *md_bitmap_attrs[] = { | ||
1910 | &bitmap_location.attr, | ||
1911 | &bitmap_timeout.attr, | ||
1912 | &bitmap_backlog.attr, | ||
1913 | &bitmap_chunksize.attr, | ||
1914 | NULL | ||
1915 | }; | ||
1916 | struct 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 */ |
1718 | EXPORT_SYMBOL(bitmap_startwrite); | 1923 | EXPORT_SYMBOL(bitmap_startwrite); |
1719 | EXPORT_SYMBOL(bitmap_endwrite); | 1924 | EXPORT_SYMBOL(bitmap_endwrite); |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 93287f88f1f4..859edbf8c9b0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -4018,6 +4018,7 @@ static void mddev_delayed_delete(struct work_struct *ws) | |||
4018 | mddev->sysfs_action = NULL; | 4018 | mddev->sysfs_action = NULL; |
4019 | mddev->private = NULL; | 4019 | mddev->private = NULL; |
4020 | } | 4020 | } |
4021 | sysfs_remove_group(&mddev->kobj, &md_bitmap_group); | ||
4021 | kobject_del(&mddev->kobj); | 4022 | kobject_del(&mddev->kobj); |
4022 | kobject_put(&mddev->kobj); | 4023 | kobject_put(&mddev->kobj); |
4023 | } | 4024 | } |
@@ -4109,6 +4110,8 @@ static int md_alloc(dev_t dev, char *name) | |||
4109 | disk->disk_name); | 4110 | disk->disk_name); |
4110 | error = 0; | 4111 | error = 0; |
4111 | } | 4112 | } |
4113 | if (sysfs_create_group(&mddev->kobj, &md_bitmap_group)) | ||
4114 | printk(KERN_DEBUG "pointless warning\n"); | ||
4112 | abort: | 4115 | abort: |
4113 | mutex_unlock(&disks_mutex); | 4116 | mutex_unlock(&disks_mutex); |
4114 | if (!error) { | 4117 | if (!error) { |
@@ -4434,7 +4437,7 @@ static int deny_bitmap_write_access(struct file * file) | |||
4434 | return 0; | 4437 | return 0; |
4435 | } | 4438 | } |
4436 | 4439 | ||
4437 | static void restore_bitmap_write_access(struct file *file) | 4440 | void restore_bitmap_write_access(struct file *file) |
4438 | { | 4441 | { |
4439 | struct inode *inode = file->f_mapping->host; | 4442 | struct inode *inode = file->f_mapping->host; |
4440 | 4443 | ||
diff --git a/drivers/md/md.h b/drivers/md/md.h index b5c306925d94..fce02073f1a4 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
@@ -372,7 +372,7 @@ struct md_sysfs_entry { | |||
372 | ssize_t (*show)(mddev_t *, char *); | 372 | ssize_t (*show)(mddev_t *, char *); |
373 | ssize_t (*store)(mddev_t *, const char *, size_t); | 373 | ssize_t (*store)(mddev_t *, const char *, size_t); |
374 | }; | 374 | }; |
375 | 375 | extern struct attribute_group md_bitmap_group; | |
376 | 376 | ||
377 | static inline char * mdname (mddev_t * mddev) | 377 | static inline char * mdname (mddev_t * mddev) |
378 | { | 378 | { |
@@ -465,5 +465,6 @@ extern int md_check_no_bitmap(mddev_t *mddev); | |||
465 | extern int md_integrity_register(mddev_t *mddev); | 465 | extern int md_integrity_register(mddev_t *mddev); |
466 | extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); | 466 | extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); |
467 | extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); | 467 | extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); |
468 | extern void restore_bitmap_write_access(struct file *file); | ||
468 | 469 | ||
469 | #endif /* _MD_MD_H */ | 470 | #endif /* _MD_MD_H */ |