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 */ |
