diff options
author | NeilBrown <neilb@suse.de> | 2010-06-01 05:37:34 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2010-07-25 23:21:34 -0400 |
commit | e384e58549a2e9a83071ad80280c1a9053cfd84c (patch) | |
tree | 805619143612ddc8cc71a45dd4522393c23a576f /drivers | |
parent | ef4256733506f2459a0c436b62267d22a3f0cec6 (diff) |
md/bitmap: prepare for storing write-intent-bitmap via dm-dirty-log.
This allows md/raid5 to fully work as a dm target.
Normally md uses a 'filemap' which contains a list of pages of bits
each of which may be written separately.
dm-log uses and all-or-nothing approach to writing the log, so
when using a dm-log, ->filemap is NULL and the flags normally stored
in filemap_attr are stored in ->logattrs instead.
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/bitmap.c | 128 | ||||
-rw-r--r-- | drivers/md/bitmap.h | 5 | ||||
-rw-r--r-- | drivers/md/md.h | 5 |
3 files changed, 99 insertions, 39 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 29a3c864e6b0..93765261c363 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "md.h" | 29 | #include "md.h" |
30 | #include "bitmap.h" | 30 | #include "bitmap.h" |
31 | 31 | ||
32 | #include <linux/dm-dirty-log.h> | ||
32 | /* debug macros */ | 33 | /* debug macros */ |
33 | 34 | ||
34 | #define DEBUG 0 | 35 | #define DEBUG 0 |
@@ -694,6 +695,8 @@ static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned lon | |||
694 | static inline struct page *filemap_get_page(struct bitmap *bitmap, | 695 | static inline struct page *filemap_get_page(struct bitmap *bitmap, |
695 | unsigned long chunk) | 696 | unsigned long chunk) |
696 | { | 697 | { |
698 | if (bitmap->filemap == NULL) | ||
699 | return NULL; | ||
697 | if (file_page_index(bitmap, chunk) >= bitmap->file_pages) | 700 | if (file_page_index(bitmap, chunk) >= bitmap->file_pages) |
698 | return NULL; | 701 | return NULL; |
699 | return bitmap->filemap[file_page_index(bitmap, chunk) | 702 | return bitmap->filemap[file_page_index(bitmap, chunk) |
@@ -793,19 +796,28 @@ enum bitmap_page_attr { | |||
793 | static inline void set_page_attr(struct bitmap *bitmap, struct page *page, | 796 | static inline void set_page_attr(struct bitmap *bitmap, struct page *page, |
794 | enum bitmap_page_attr attr) | 797 | enum bitmap_page_attr attr) |
795 | { | 798 | { |
796 | __set_bit((page->index<<2) + attr, bitmap->filemap_attr); | 799 | if (page) |
800 | __set_bit((page->index<<2) + attr, bitmap->filemap_attr); | ||
801 | else | ||
802 | __set_bit(attr, &bitmap->logattrs); | ||
797 | } | 803 | } |
798 | 804 | ||
799 | static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, | 805 | static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, |
800 | enum bitmap_page_attr attr) | 806 | enum bitmap_page_attr attr) |
801 | { | 807 | { |
802 | __clear_bit((page->index<<2) + attr, bitmap->filemap_attr); | 808 | if (page) |
809 | __clear_bit((page->index<<2) + attr, bitmap->filemap_attr); | ||
810 | else | ||
811 | __clear_bit(attr, &bitmap->logattrs); | ||
803 | } | 812 | } |
804 | 813 | ||
805 | static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page, | 814 | static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page, |
806 | enum bitmap_page_attr attr) | 815 | enum bitmap_page_attr attr) |
807 | { | 816 | { |
808 | return test_bit((page->index<<2) + attr, bitmap->filemap_attr); | 817 | if (page) |
818 | return test_bit((page->index<<2) + attr, bitmap->filemap_attr); | ||
819 | else | ||
820 | return test_bit(attr, &bitmap->logattrs); | ||
809 | } | 821 | } |
810 | 822 | ||
811 | /* | 823 | /* |
@@ -818,27 +830,30 @@ static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *p | |||
818 | static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) | 830 | static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) |
819 | { | 831 | { |
820 | unsigned long bit; | 832 | unsigned long bit; |
821 | struct page *page; | 833 | struct page *page = NULL; |
822 | void *kaddr; | 834 | void *kaddr; |
823 | unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap); | 835 | unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap); |
824 | 836 | ||
825 | if (!bitmap->filemap) | 837 | if (!bitmap->filemap) { |
826 | return; | 838 | struct dm_dirty_log *log = bitmap->mddev->bitmap_info.log; |
827 | 839 | if (log) | |
828 | page = filemap_get_page(bitmap, chunk); | 840 | log->type->mark_region(log, chunk); |
829 | if (!page) | 841 | } else { |
830 | return; | ||
831 | bit = file_page_offset(bitmap, chunk); | ||
832 | 842 | ||
833 | /* set the bit */ | 843 | page = filemap_get_page(bitmap, chunk); |
834 | kaddr = kmap_atomic(page, KM_USER0); | 844 | if (!page) |
835 | if (bitmap->flags & BITMAP_HOSTENDIAN) | 845 | return; |
836 | set_bit(bit, kaddr); | 846 | bit = file_page_offset(bitmap, chunk); |
837 | else | ||
838 | ext2_set_bit(bit, kaddr); | ||
839 | kunmap_atomic(kaddr, KM_USER0); | ||
840 | PRINTK("set file bit %lu page %lu\n", bit, page->index); | ||
841 | 847 | ||
848 | /* set the bit */ | ||
849 | kaddr = kmap_atomic(page, KM_USER0); | ||
850 | if (bitmap->flags & BITMAP_HOSTENDIAN) | ||
851 | set_bit(bit, kaddr); | ||
852 | else | ||
853 | ext2_set_bit(bit, kaddr); | ||
854 | kunmap_atomic(kaddr, KM_USER0); | ||
855 | PRINTK("set file bit %lu page %lu\n", bit, page->index); | ||
856 | } | ||
842 | /* record page number so it gets flushed to disk when unplug occurs */ | 857 | /* record page number so it gets flushed to disk when unplug occurs */ |
843 | set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); | 858 | set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); |
844 | } | 859 | } |
@@ -855,6 +870,16 @@ void bitmap_unplug(struct bitmap *bitmap) | |||
855 | 870 | ||
856 | if (!bitmap) | 871 | if (!bitmap) |
857 | return; | 872 | return; |
873 | if (!bitmap->filemap) { | ||
874 | /* Must be using a dirty_log */ | ||
875 | struct dm_dirty_log *log = bitmap->mddev->bitmap_info.log; | ||
876 | dirty = test_and_clear_bit(BITMAP_PAGE_DIRTY, &bitmap->logattrs); | ||
877 | need_write = test_and_clear_bit(BITMAP_PAGE_NEEDWRITE, &bitmap->logattrs); | ||
878 | if (dirty || need_write) | ||
879 | if (log->type->flush(log)) | ||
880 | bitmap->flags |= BITMAP_WRITE_ERROR; | ||
881 | goto out; | ||
882 | } | ||
858 | 883 | ||
859 | /* look at each page to see if there are any set bits that need to be | 884 | /* look at each page to see if there are any set bits that need to be |
860 | * flushed out to disk */ | 885 | * flushed out to disk */ |
@@ -883,6 +908,7 @@ void bitmap_unplug(struct bitmap *bitmap) | |||
883 | else | 908 | else |
884 | md_super_wait(bitmap->mddev); | 909 | md_super_wait(bitmap->mddev); |
885 | } | 910 | } |
911 | out: | ||
886 | if (bitmap->flags & BITMAP_WRITE_ERROR) | 912 | if (bitmap->flags & BITMAP_WRITE_ERROR) |
887 | bitmap_file_kick(bitmap); | 913 | bitmap_file_kick(bitmap); |
888 | } | 914 | } |
@@ -925,11 +951,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) | |||
925 | printk(KERN_INFO "%s: bitmap file is out of date, doing full " | 951 | printk(KERN_INFO "%s: bitmap file is out of date, doing full " |
926 | "recovery\n", bmname(bitmap)); | 952 | "recovery\n", bmname(bitmap)); |
927 | 953 | ||
928 | bytes = (chunks + 7) / 8; | 954 | bytes = DIV_ROUND_UP(bitmap->chunks, 8); |
929 | if (!bitmap->mddev->bitmap_info.external) | 955 | if (!bitmap->mddev->bitmap_info.external) |
930 | bytes += sizeof(bitmap_super_t); | 956 | bytes += sizeof(bitmap_super_t); |
931 | 957 | ||
932 | num_pages = (bytes + PAGE_SIZE - 1) / PAGE_SIZE; | 958 | num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); |
933 | 959 | ||
934 | if (file && i_size_read(file->f_mapping->host) < bytes) { | 960 | if (file && i_size_read(file->f_mapping->host) < bytes) { |
935 | printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", | 961 | printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", |
@@ -1090,6 +1116,7 @@ void bitmap_daemon_work(mddev_t *mddev) | |||
1090 | struct page *page = NULL, *lastpage = NULL; | 1116 | struct page *page = NULL, *lastpage = NULL; |
1091 | int blocks; | 1117 | int blocks; |
1092 | void *paddr; | 1118 | void *paddr; |
1119 | struct dm_dirty_log *log = mddev->bitmap_info.log; | ||
1093 | 1120 | ||
1094 | /* Use a mutex to guard daemon_work against | 1121 | /* Use a mutex to guard daemon_work against |
1095 | * bitmap_destroy. | 1122 | * bitmap_destroy. |
@@ -1114,11 +1141,12 @@ void bitmap_daemon_work(mddev_t *mddev) | |||
1114 | spin_lock_irqsave(&bitmap->lock, flags); | 1141 | spin_lock_irqsave(&bitmap->lock, flags); |
1115 | for (j = 0; j < bitmap->chunks; j++) { | 1142 | for (j = 0; j < bitmap->chunks; j++) { |
1116 | bitmap_counter_t *bmc; | 1143 | bitmap_counter_t *bmc; |
1117 | if (!bitmap->filemap) | 1144 | if (!bitmap->filemap) { |
1118 | /* error or shutdown */ | 1145 | if (!log) |
1119 | break; | 1146 | /* error or shutdown */ |
1120 | 1147 | break; | |
1121 | page = filemap_get_page(bitmap, j); | 1148 | } else |
1149 | page = filemap_get_page(bitmap, j); | ||
1122 | 1150 | ||
1123 | if (page != lastpage) { | 1151 | if (page != lastpage) { |
1124 | /* skip this page unless it's marked as needing cleaning */ | 1152 | /* skip this page unless it's marked as needing cleaning */ |
@@ -1187,14 +1215,17 @@ void bitmap_daemon_work(mddev_t *mddev) | |||
1187 | -1); | 1215 | -1); |
1188 | 1216 | ||
1189 | /* clear the bit */ | 1217 | /* clear the bit */ |
1190 | paddr = kmap_atomic(page, KM_USER0); | 1218 | if (page) { |
1191 | if (bitmap->flags & BITMAP_HOSTENDIAN) | 1219 | paddr = kmap_atomic(page, KM_USER0); |
1192 | clear_bit(file_page_offset(bitmap, j), | 1220 | if (bitmap->flags & BITMAP_HOSTENDIAN) |
1193 | paddr); | 1221 | clear_bit(file_page_offset(bitmap, j), |
1194 | else | 1222 | paddr); |
1195 | ext2_clear_bit(file_page_offset(bitmap, j), | 1223 | else |
1196 | paddr); | 1224 | ext2_clear_bit(file_page_offset(bitmap, j), |
1197 | kunmap_atomic(paddr, KM_USER0); | 1225 | paddr); |
1226 | kunmap_atomic(paddr, KM_USER0); | ||
1227 | } else | ||
1228 | log->type->clear_region(log, j); | ||
1198 | } | 1229 | } |
1199 | } else | 1230 | } else |
1200 | j |= PAGE_COUNTER_MASK; | 1231 | j |= PAGE_COUNTER_MASK; |
@@ -1202,12 +1233,16 @@ void bitmap_daemon_work(mddev_t *mddev) | |||
1202 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1233 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1203 | 1234 | ||
1204 | /* now sync the final page */ | 1235 | /* now sync the final page */ |
1205 | if (lastpage != NULL) { | 1236 | if (lastpage != NULL || log != NULL) { |
1206 | spin_lock_irqsave(&bitmap->lock, flags); | 1237 | spin_lock_irqsave(&bitmap->lock, flags); |
1207 | if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { | 1238 | if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { |
1208 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1239 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1209 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1240 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1210 | write_page(bitmap, lastpage, 0); | 1241 | if (lastpage) |
1242 | write_page(bitmap, lastpage, 0); | ||
1243 | else | ||
1244 | if (log->type->flush(log)) | ||
1245 | bitmap->flags |= BITMAP_WRITE_ERROR; | ||
1211 | } else { | 1246 | } else { |
1212 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1247 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1213 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1248 | spin_unlock_irqrestore(&bitmap->lock, flags); |
@@ -1372,7 +1407,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto | |||
1372 | (*bmc)--; | 1407 | (*bmc)--; |
1373 | if (*bmc <= 2) | 1408 | if (*bmc <= 2) |
1374 | set_page_attr(bitmap, | 1409 | set_page_attr(bitmap, |
1375 | filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)), | 1410 | filemap_get_page( |
1411 | bitmap, | ||
1412 | offset >> CHUNK_BLOCK_SHIFT(bitmap)), | ||
1376 | BITMAP_PAGE_CLEAN); | 1413 | BITMAP_PAGE_CLEAN); |
1377 | 1414 | ||
1378 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1415 | spin_unlock_irqrestore(&bitmap->lock, flags); |
@@ -1649,10 +1686,13 @@ int bitmap_create(mddev_t *mddev) | |||
1649 | 1686 | ||
1650 | BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); | 1687 | BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); |
1651 | 1688 | ||
1652 | if (!file && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */ | 1689 | if (!file |
1690 | && !mddev->bitmap_info.offset | ||
1691 | && !mddev->bitmap_info.log) /* bitmap disabled, nothing to do */ | ||
1653 | return 0; | 1692 | return 0; |
1654 | 1693 | ||
1655 | BUG_ON(file && mddev->bitmap_info.offset); | 1694 | BUG_ON(file && mddev->bitmap_info.offset); |
1695 | BUG_ON(mddev->bitmap_info.offset && mddev->bitmap_info.log); | ||
1656 | 1696 | ||
1657 | bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL); | 1697 | bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL); |
1658 | if (!bitmap) | 1698 | if (!bitmap) |
@@ -1730,7 +1770,17 @@ int bitmap_create(mddev_t *mddev) | |||
1730 | || bitmap->events_cleared == mddev->events) | 1770 | || bitmap->events_cleared == mddev->events) |
1731 | /* no need to keep dirty bits to optimise a re-add of a missing device */ | 1771 | /* no need to keep dirty bits to optimise a re-add of a missing device */ |
1732 | start = mddev->recovery_cp; | 1772 | start = mddev->recovery_cp; |
1733 | err = bitmap_init_from_disk(bitmap, start); | 1773 | if (mddev->bitmap_info.log) { |
1774 | unsigned long i; | ||
1775 | struct dm_dirty_log *log = mddev->bitmap_info.log; | ||
1776 | for (i = 0; i < bitmap->chunks; i++) | ||
1777 | if (!log->type->in_sync(log, i, 1)) | ||
1778 | bitmap_set_memory_bits(bitmap, | ||
1779 | (sector_t)i << CHUNK_BLOCK_SHIFT(bitmap), | ||
1780 | 1); | ||
1781 | err = 0; | ||
1782 | } else | ||
1783 | err = bitmap_init_from_disk(bitmap, start); | ||
1734 | 1784 | ||
1735 | if (err) | 1785 | if (err) |
1736 | goto error; | 1786 | goto error; |
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 3797dea4723a..a7a11134268d 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h | |||
@@ -222,6 +222,10 @@ struct bitmap { | |||
222 | unsigned long file_pages; /* number of pages in the file */ | 222 | unsigned long file_pages; /* number of pages in the file */ |
223 | int last_page_size; /* bytes in the last page */ | 223 | int last_page_size; /* bytes in the last page */ |
224 | 224 | ||
225 | unsigned long logattrs; /* used when filemap_attr doesn't exist | ||
226 | * because we are working with a dirty_log | ||
227 | */ | ||
228 | |||
225 | unsigned long flags; | 229 | unsigned long flags; |
226 | 230 | ||
227 | int allclean; | 231 | int allclean; |
@@ -243,6 +247,7 @@ struct bitmap { | |||
243 | wait_queue_head_t behind_wait; | 247 | wait_queue_head_t behind_wait; |
244 | 248 | ||
245 | struct sysfs_dirent *sysfs_can_clear; | 249 | struct sysfs_dirent *sysfs_can_clear; |
250 | |||
246 | }; | 251 | }; |
247 | 252 | ||
248 | /* the bitmap API */ | 253 | /* the bitmap API */ |
diff --git a/drivers/md/md.h b/drivers/md/md.h index 0a850780b5d1..cccbadb31bae 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
@@ -317,6 +317,11 @@ struct mddev_s | |||
317 | * hot-adding a bitmap. It should | 317 | * hot-adding a bitmap. It should |
318 | * eventually be settable by sysfs. | 318 | * eventually be settable by sysfs. |
319 | */ | 319 | */ |
320 | /* When md is serving under dm, it might use a | ||
321 | * dirty_log to store the bits. | ||
322 | */ | ||
323 | struct dm_dirty_log *log; | ||
324 | |||
320 | struct mutex mutex; | 325 | struct mutex mutex; |
321 | unsigned long chunksize; | 326 | unsigned long chunksize; |
322 | unsigned long daemon_sleep; /* how many jiffies between updates? */ | 327 | unsigned long daemon_sleep; /* how many jiffies between updates? */ |