From bf07bb7d5be813630d3530be274b3324f85e310c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:06 +1000 Subject: md/bitmap: disentangle two different 'pending' flags. There are two different 'pending' concepts in the handling of the write intent bitmap. Firstly, a 'page' from the bitmap (which container PAGE_SIZE*8 bits) may have changes (bits cleared) that should be written in due course. There is no hurry for these and the page will transition from PENDING to NEEDWRITE and will then be written, though if it ever becomes DIRTY it will be written much sooner and PENDING will be cleared. Secondly, a page of counters - which contains PAGE_SIZE/2 counters, one for each bit, can usefully have a 'pending' flag which indicates if any of the counters are low (2 or 1) and ready to be processed by bitmap_daemon_work(). If this flag is clear we can skip the whole page. These two concepts are currently combined in the bitmap-file flag. This causes a tighter connection between the counters and the bitmap file than I would like - as I want to add some flexibility to the bitmap file. So introduce a new flag with the page-of-counters, and rewrite bitmap_daemon_work() so that it handles the two different 'pending' concepts separately. This also allows us to clear BITMAP_PAGE_PENDING when we write out a dirty page, which may occasionally reduce the number of times we write a page. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 213 +++++++++++++++++++++++++++------------------------- 1 file changed, 112 insertions(+), 101 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 17e2b472e16..c7784a98567 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -883,6 +883,8 @@ void bitmap_unplug(struct bitmap *bitmap) need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); + if (dirty || need_write) + clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING); if (dirty) wait = 1; spin_unlock_irqrestore(&bitmap->lock, flags); @@ -1086,6 +1088,17 @@ static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) bitmap->bp[page].count += inc; bitmap_checkfree(bitmap, page); } + +static void bitmap_set_pending(struct bitmap *bitmap, sector_t offset) +{ + sector_t chunk = offset >> bitmap->chunkshift; + unsigned long page = chunk >> PAGE_COUNTER_SHIFT; + struct bitmap_page *bp = &bitmap->bp[page]; + + if (!bp->pending) + bp->pending = 1; +} + static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, sector_t offset, sector_t *blocks, int create); @@ -1099,8 +1112,8 @@ void bitmap_daemon_work(struct mddev *mddev) { struct bitmap *bitmap; unsigned long j; + unsigned long nextpage; unsigned long flags; - struct page *page = NULL, *lastpage = NULL; sector_t blocks; void *paddr; @@ -1124,114 +1137,120 @@ void bitmap_daemon_work(struct mddev *mddev) } bitmap->allclean = 1; + /* Any file-page which is PENDING now needs to be written. + * So set NEEDWRITE now, then after we make any last-minute changes + * we will write it. + */ spin_lock_irqsave(&bitmap->lock, flags); + if (!bitmap->filemap) + /* error or shutdown */ + goto out; + + for (j = 0; j < bitmap->file_pages; j++) + if (test_page_attr(bitmap, bitmap->filemap[j], + BITMAP_PAGE_PENDING)) { + set_page_attr(bitmap, bitmap->filemap[j], + BITMAP_PAGE_NEEDWRITE); + clear_page_attr(bitmap, bitmap->filemap[j], + BITMAP_PAGE_PENDING); + } + + if (bitmap->need_sync && + mddev->bitmap_info.external == 0) { + /* Arrange for superblock update as well as + * other changes */ + bitmap_super_t *sb; + bitmap->need_sync = 0; + sb = kmap_atomic(bitmap->sb_page); + sb->events_cleared = + cpu_to_le64(bitmap->events_cleared); + kunmap_atomic(sb); + set_page_attr(bitmap, bitmap->sb_page, BITMAP_PAGE_NEEDWRITE); + } + /* Now look at the bitmap counters and if any are '2' or '1', + * decrement and handle accordingly. + */ + nextpage = 0; for (j = 0; j < bitmap->chunks; j++) { bitmap_counter_t *bmc; - if (!bitmap->filemap) - /* error or shutdown */ - break; - page = filemap_get_page(bitmap, j); - - if (page != lastpage) { - /* skip this page unless it's marked as needing cleaning */ - if (!test_page_attr(bitmap, page, BITMAP_PAGE_PENDING)) { - int need_write = test_page_attr(bitmap, page, - BITMAP_PAGE_NEEDWRITE); - if (need_write) - clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); - - spin_unlock_irqrestore(&bitmap->lock, flags); - if (need_write) - write_page(bitmap, page, 0); - spin_lock_irqsave(&bitmap->lock, flags); - j |= (PAGE_BITS - 1); + if (j == nextpage) { + nextpage += PAGE_COUNTER_RATIO; + if (!bitmap->bp[j >> PAGE_COUNTER_SHIFT].pending) { + j |= PAGE_COUNTER_MASK; continue; } - - /* grab the new page, sync and release the old */ - if (lastpage != NULL) { - if (test_page_attr(bitmap, lastpage, - BITMAP_PAGE_NEEDWRITE)) { - clear_page_attr(bitmap, lastpage, - BITMAP_PAGE_NEEDWRITE); - spin_unlock_irqrestore(&bitmap->lock, flags); - write_page(bitmap, lastpage, 0); - } else { - set_page_attr(bitmap, lastpage, - BITMAP_PAGE_NEEDWRITE); - bitmap->allclean = 0; - spin_unlock_irqrestore(&bitmap->lock, flags); - } - } else - spin_unlock_irqrestore(&bitmap->lock, flags); - lastpage = page; - - /* We are possibly going to clear some bits, so make - * sure that events_cleared is up-to-date. - */ - if (bitmap->need_sync && - mddev->bitmap_info.external == 0) { - bitmap_super_t *sb; - bitmap->need_sync = 0; - sb = kmap_atomic(bitmap->sb_page); - sb->events_cleared = - cpu_to_le64(bitmap->events_cleared); - kunmap_atomic(sb); - write_page(bitmap, bitmap->sb_page, 1); - } - spin_lock_irqsave(&bitmap->lock, flags); - if (!bitmap->need_sync) - clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING); - else - bitmap->allclean = 0; + bitmap->bp[j >> PAGE_COUNTER_SHIFT].pending = 0; } bmc = bitmap_get_counter(bitmap, (sector_t)j << bitmap->chunkshift, &blocks, 0); - if (!bmc) + + if (!bmc) { j |= PAGE_COUNTER_MASK; - else if (*bmc) { - if (*bmc == 1 && !bitmap->need_sync) { - /* we can clear the bit */ - *bmc = 0; - bitmap_count_page(bitmap, - (sector_t)j << bitmap->chunkshift, - -1); - - /* clear the bit */ - paddr = kmap_atomic(page); - if (bitmap->flags & BITMAP_HOSTENDIAN) - clear_bit(file_page_offset(bitmap, j), - paddr); - else - __clear_bit_le( - file_page_offset(bitmap, - j), - paddr); - kunmap_atomic(paddr); - } else if (*bmc <= 2) { - *bmc = 1; /* maybe clear the bit next time */ - set_page_attr(bitmap, page, BITMAP_PAGE_PENDING); + continue; + } + if (*bmc == 1 && !bitmap->need_sync) { + /* We can clear the bit */ + struct page *page; + *bmc = 0; + bitmap_count_page( + bitmap, + (sector_t)j << bitmap->chunkshift, + -1); + + page = filemap_get_page(bitmap, j); + paddr = kmap_atomic(page); + if (bitmap->flags & BITMAP_HOSTENDIAN) + clear_bit(file_page_offset(bitmap, j), + paddr); + else + __clear_bit_le(file_page_offset(bitmap, j), + paddr); + kunmap_atomic(paddr); + if (!test_page_attr(bitmap, page, + BITMAP_PAGE_NEEDWRITE)) { + set_page_attr(bitmap, page, + BITMAP_PAGE_PENDING); bitmap->allclean = 0; } + } else if (*bmc && *bmc <= 2) { + *bmc = 1; + bitmap_set_pending( + bitmap, + (sector_t)j << bitmap->chunkshift); + bitmap->allclean = 0; } } - spin_unlock_irqrestore(&bitmap->lock, flags); - /* now sync the final page */ - if (lastpage != NULL) { - spin_lock_irqsave(&bitmap->lock, flags); - if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) { - clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); - spin_unlock_irqrestore(&bitmap->lock, flags); - write_page(bitmap, lastpage, 0); - } else { - set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); - bitmap->allclean = 0; + /* Now start writeout on any page in NEEDWRITE that isn't DIRTY. + * DIRTY pages need to be written by bitmap_unplug so it can wait + * for them. + * If we find any DIRTY page we stop there and let bitmap_unplug + * handle all the rest. This is important in the case where + * the first blocking holds the superblock and it has been updated. + * We mustn't write any other blocks before the superblock. + */ + for (j = 0; j < bitmap->file_pages; j++) { + struct page *page = bitmap->filemap[j]; + + if (test_page_attr(bitmap, page, + BITMAP_PAGE_DIRTY)) + /* bitmap_unplug will handle the rest */ + break; + if (test_page_attr(bitmap, page, + BITMAP_PAGE_NEEDWRITE)) { + clear_page_attr(bitmap, page, + BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); + write_page(bitmap, page, 0); + spin_lock_irqsave(&bitmap->lock, flags); + if (!bitmap->filemap) + break; } } +out: + spin_unlock_irqrestore(&bitmap->lock, flags); done: if (bitmap->allclean == 0) @@ -1386,11 +1405,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto (*bmc)--; if (*bmc <= 2) { - set_page_attr(bitmap, - filemap_get_page( - bitmap, - offset >> bitmap->chunkshift), - BITMAP_PAGE_PENDING); + bitmap_set_pending(bitmap, offset); bitmap->allclean = 0; } spin_unlock_irqrestore(&bitmap->lock, flags); @@ -1476,9 +1491,7 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i *bmc |= NEEDED_MASK; else { if (*bmc <= 2) { - set_page_attr(bitmap, - filemap_get_page(bitmap, offset >> bitmap->chunkshift), - BITMAP_PAGE_PENDING); + bitmap_set_pending(bitmap, offset); bitmap->allclean = 0; } } @@ -1551,11 +1564,9 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n return; } if (!*bmc) { - struct page *page; *bmc = 2 | (needed ? NEEDED_MASK : 0); bitmap_count_page(bitmap, offset, 1); - page = filemap_get_page(bitmap, offset >> bitmap->chunkshift); - set_page_attr(bitmap, page, BITMAP_PAGE_PENDING); + bitmap_set_pending(bitmap, offset); bitmap->allclean = 0; } spin_unlock_irq(&bitmap->lock); -- cgit v1.2.3-70-g09d2 From 6409bb05a9831f6af36a20b97cda13059c2ef1b6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:07 +1000 Subject: md/bitmap: add new 'space' attribute for bitmaps. If we are to allow bitmaps to be resized when the array is resized, we need to know how much space there is. So create an attribute to store this information and set appropriate defaults. It can be set more precisely via sysfs, or future metadata extensions may allow it to be recorded. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/md/md.c | 33 +++++++++++++++++++++++++++++++-- drivers/md/md.h | 3 +++ 3 files changed, 73 insertions(+), 2 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c7784a98567..ac688fb54e1 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1934,6 +1934,44 @@ location_store(struct mddev *mddev, const char *buf, size_t len) static struct md_sysfs_entry bitmap_location = __ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store); +/* 'bitmap/space' is the space available at 'location' for the + * bitmap. This allows the kernel to know when it is safe to + * resize the bitmap to match a resized array. + */ +static ssize_t +space_show(struct mddev *mddev, char *page) +{ + return sprintf(page, "%lu\n", mddev->bitmap_info.space); +} + +static ssize_t +space_store(struct mddev *mddev, const char *buf, size_t len) +{ + unsigned long sectors; + int rv; + + rv = kstrtoul(buf, 10, §ors); + if (rv) + return rv; + + if (sectors == 0) + return -EINVAL; + + if (mddev->bitmap && + sectors < ((mddev->bitmap->file_pages - 1) * PAGE_SIZE + + mddev->bitmap->last_page_size + 511) >> 9) + return -EFBIG; /* Bitmap is too big for this small space */ + + /* could make sure it isn't too big, but that isn't really + * needed - user-space should be careful. + */ + mddev->bitmap_info.space = sectors; + return len; +} + +static struct md_sysfs_entry bitmap_space = +__ATTR(space, S_IRUGO|S_IWUSR, space_show, space_store); + static ssize_t timeout_show(struct mddev *mddev, char *page) { @@ -2109,6 +2147,7 @@ __ATTR(max_backlog_used, S_IRUGO | S_IWUSR, static struct attribute *md_bitmap_attrs[] = { &bitmap_location.attr, + &bitmap_space.attr, &bitmap_timeout.attr, &bitmap_backlog.attr, &bitmap_chunksize.attr, diff --git a/drivers/md/md.c b/drivers/md/md.c index ac99616f48d..9a677f2078a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1197,7 +1197,10 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->dev_sectors = ((sector_t)sb->size) * 2; mddev->events = ev1; mddev->bitmap_info.offset = 0; + mddev->bitmap_info.space = 0; + /* bitmap can use 60 K after the 4K superblocks */ mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9; + mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9); mddev->reshape_backwards = 0; if (mddev->minor_version >= 91) { @@ -1234,9 +1237,12 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->max_disks = MD_SB_DISKS; if (sb->state & (1<bitmap_info.file == NULL) + mddev->bitmap_info.file == NULL) { mddev->bitmap_info.offset = mddev->bitmap_info.default_offset; + mddev->bitmap_info.space = + mddev->bitmap_info.space; + } } else if (mddev->pers == NULL) { /* Insist on good event counter while assembling, except @@ -1677,7 +1683,12 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->dev_sectors = le64_to_cpu(sb->size); mddev->events = ev1; mddev->bitmap_info.offset = 0; + mddev->bitmap_info.space = 0; + /* Default location for bitmap is 1K after superblock + * using 3K - total of 4K + */ mddev->bitmap_info.default_offset = 1024 >> 9; + mddev->bitmap_info.default_space = (4096-1024) >> 9; mddev->reshape_backwards = 0; mddev->recovery_cp = le64_to_cpu(sb->resync_offset); @@ -1686,9 +1697,23 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) mddev->max_disks = (4096-256)/2; if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) && - mddev->bitmap_info.file == NULL ) + mddev->bitmap_info.file == NULL) { mddev->bitmap_info.offset = (__s32)le32_to_cpu(sb->bitmap_offset); + /* Metadata doesn't record how much space is available. + * For 1.0, we assume we can use up to the superblock + * if before, else to 4K beyond superblock. + * For others, assume no change is possible. + */ + if (mddev->minor_version > 0) + mddev->bitmap_info.space = 0; + else if (mddev->bitmap_info.offset > 0) + mddev->bitmap_info.space = + 8 - mddev->bitmap_info.offset; + else + mddev->bitmap_info.space = + -mddev->bitmap_info.offset; + } if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) { mddev->reshape_position = le64_to_cpu(sb->reshape_position); @@ -5280,6 +5305,7 @@ static void md_clean(struct mddev *mddev) mddev->merge_check_needed = 0; mddev->bitmap_info.offset = 0; mddev->bitmap_info.default_offset = 0; + mddev->bitmap_info.default_space = 0; mddev->bitmap_info.chunksize = 0; mddev->bitmap_info.daemon_sleep = 0; mddev->bitmap_info.max_write_behind = 0; @@ -6076,6 +6102,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info) set_bit(MD_CHANGE_DEVS, &mddev->flags); mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9; + mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9); mddev->bitmap_info.offset = 0; mddev->reshape_position = MaxSector; @@ -6258,6 +6285,8 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) return -EINVAL; mddev->bitmap_info.offset = mddev->bitmap_info.default_offset; + mddev->bitmap_info.space = + mddev->bitmap_info.default_space; mddev->pers->quiesce(mddev, 1); rv = bitmap_create(mddev); if (!rv) diff --git a/drivers/md/md.h b/drivers/md/md.h index 360937389e6..7b4a3c318ca 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -393,10 +393,13 @@ struct mddev { * For external metadata, offset * from start of device. */ + unsigned long space; /* space available at this offset */ loff_t default_offset; /* this is the offset to use when * hot-adding a bitmap. It should * eventually be settable by sysfs. */ + unsigned long default_space; /* space available at + * default offset */ struct mutex mutex; unsigned long chunksize; unsigned long daemon_sleep; /* how many jiffies between updates? */ -- cgit v1.2.3-70-g09d2 From ef99bf480de9bde9d3b2afdf05324670fab4e571 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:08 +1000 Subject: md/bitmap: allow a bitmap with no backing storage. An md bitmap comprises two parts - internal counting of active writes per 'chunk'. - external storage of whether there are any active writes on each chunk The second requires the first, but the first doesn't require the second. Not having backing storage means that the bitmap cannot expedite resync after a crash, but it still allows us to expedite the recovery of a recently-removed device. So: allow a bitmap to exist even if there is no backing device. In that case we default to 128M chunks. A particular value of this is that we can remove and re-add a bitmap (possibly of a different granularity) on a degraded array, and not lose the information needed to fast-recover the missing device. We don't actually activate these bitmaps yet - that will come in a later patch. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 136 +++++++++++++++++++++++++++++----------------------- drivers/md/md.c | 5 +- 2 files changed, 79 insertions(+), 62 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index ac688fb54e1..c042efd019c 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -553,6 +553,14 @@ static int bitmap_read_sb(struct bitmap *bitmap) unsigned long long events; int err = -EINVAL; + if (!bitmap->file && !bitmap->mddev->bitmap_info.offset) { + chunksize = 128 * 1024 * 1024; + daemon_sleep = 5 * HZ; + write_behind = 0; + bitmap->flags = BITMAP_STALE; + err = 0; + goto out_no_sb; + } /* page 0 is the superblock, read it... */ if (bitmap->file) { loff_t isize = i_size_read(bitmap->file->f_mapping->host); @@ -623,18 +631,19 @@ static int bitmap_read_sb(struct bitmap *bitmap) } /* assign fields using values from superblock */ - bitmap->mddev->bitmap_info.chunksize = chunksize; - bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep; - bitmap->mddev->bitmap_info.max_write_behind = write_behind; bitmap->flags |= le32_to_cpu(sb->state); if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN) bitmap->flags |= BITMAP_HOSTENDIAN; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); - if (bitmap->flags & BITMAP_STALE) - bitmap->events_cleared = bitmap->mddev->events; err = 0; out: kunmap_atomic(sb); +out_no_sb: + if (bitmap->flags & BITMAP_STALE) + bitmap->events_cleared = bitmap->mddev->events; + bitmap->mddev->bitmap_info.chunksize = chunksize; + bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep; + bitmap->mddev->bitmap_info.max_write_behind = write_behind; if (err) bitmap_print_sb(bitmap); return err; @@ -837,9 +846,6 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) void *kaddr; unsigned long chunk = block >> bitmap->chunkshift; - if (!bitmap->filemap) - return; - page = filemap_get_page(bitmap, chunk); if (!page) return; @@ -857,6 +863,29 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); } +static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) +{ + unsigned long bit; + struct page *page; + void *paddr; + unsigned long chunk = block >> bitmap->chunkshift; + + page = filemap_get_page(bitmap, chunk); + if (!page) + return; + bit = file_page_offset(bitmap, chunk); + paddr = kmap_atomic(page); + if (bitmap->flags & BITMAP_HOSTENDIAN) + clear_bit(bit, paddr); + else + __clear_bit_le(bit, paddr); + kunmap_atomic(paddr); + if (!test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE)) { + set_page_attr(bitmap, page, BITMAP_PAGE_PENDING); + bitmap->allclean = 0; + } +} + /* this gets called when the md device is ready to unplug its underlying * (slave) device queues -- before we let any writes go down, we need to * sync the dirty pages of the bitmap file to disk */ @@ -867,7 +896,7 @@ void bitmap_unplug(struct bitmap *bitmap) struct page *page; int wait = 0; - if (!bitmap) + if (!bitmap || !bitmap->filemap) return; /* look at each page to see if there are any set bits that need to be @@ -930,7 +959,20 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) chunks = bitmap->chunks; file = bitmap->file; - BUG_ON(!file && !bitmap->mddev->bitmap_info.offset); + if (!file && !bitmap->mddev->bitmap_info.offset) { + /* No permanent bitmap - fill with '1s'. */ + bitmap->filemap = NULL; + bitmap->file_pages = 0; + for (i = 0; i < chunks ; i++) { + /* if the disk bit is set, set the memory bit */ + int needed = ((sector_t)(i+1) << (bitmap->chunkshift) + >= start); + bitmap_set_memory_bits(bitmap, + (sector_t)i << bitmap->chunkshift, + needed); + } + return 0; + } outofdate = bitmap->flags & BITMAP_STALE; if (outofdate) @@ -1045,15 +1087,6 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) } } - /* everything went OK */ - ret = 0; - bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET); - - if (bit_cnt) { /* Kick recovery if any bits were set */ - set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery); - md_wakeup_thread(bitmap->mddev->thread); - } - printk(KERN_INFO "%s: bitmap initialized from disk: " "read %lu/%lu pages, set %lu of %lu bits\n", bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks); @@ -1073,6 +1106,12 @@ void bitmap_write_all(struct bitmap *bitmap) */ int i; + if (!bitmap || !bitmap->filemap) + return; + if (bitmap->file) + /* Only one copy, so nothing needed */ + return; + spin_lock_irq(&bitmap->lock); for (i = 0; i < bitmap->file_pages; i++) set_page_attr(bitmap, bitmap->filemap[i], @@ -1115,7 +1154,6 @@ void bitmap_daemon_work(struct mddev *mddev) unsigned long nextpage; unsigned long flags; sector_t blocks; - void *paddr; /* Use a mutex to guard daemon_work against * bitmap_destroy. @@ -1142,10 +1180,6 @@ void bitmap_daemon_work(struct mddev *mddev) * we will write it. */ spin_lock_irqsave(&bitmap->lock, flags); - if (!bitmap->filemap) - /* error or shutdown */ - goto out; - for (j = 0; j < bitmap->file_pages; j++) if (test_page_attr(bitmap, bitmap->filemap[j], BITMAP_PAGE_PENDING)) { @@ -1161,11 +1195,14 @@ void bitmap_daemon_work(struct mddev *mddev) * other changes */ bitmap_super_t *sb; bitmap->need_sync = 0; - sb = kmap_atomic(bitmap->sb_page); - sb->events_cleared = - cpu_to_le64(bitmap->events_cleared); - kunmap_atomic(sb); - set_page_attr(bitmap, bitmap->sb_page, BITMAP_PAGE_NEEDWRITE); + if (bitmap->filemap) { + sb = kmap_atomic(bitmap->sb_page); + sb->events_cleared = + cpu_to_le64(bitmap->events_cleared); + kunmap_atomic(sb); + set_page_attr(bitmap, bitmap->sb_page, + BITMAP_PAGE_NEEDWRITE); + } } /* Now look at the bitmap counters and if any are '2' or '1', * decrement and handle accordingly. @@ -1173,6 +1210,7 @@ void bitmap_daemon_work(struct mddev *mddev) nextpage = 0; for (j = 0; j < bitmap->chunks; j++) { bitmap_counter_t *bmc; + sector_t block = (sector_t)j << bitmap->chunkshift; if (j == nextpage) { nextpage += PAGE_COUNTER_RATIO; @@ -1183,7 +1221,7 @@ void bitmap_daemon_work(struct mddev *mddev) bitmap->bp[j >> PAGE_COUNTER_SHIFT].pending = 0; } bmc = bitmap_get_counter(bitmap, - (sector_t)j << bitmap->chunkshift, + block, &blocks, 0); if (!bmc) { @@ -1192,33 +1230,12 @@ void bitmap_daemon_work(struct mddev *mddev) } if (*bmc == 1 && !bitmap->need_sync) { /* We can clear the bit */ - struct page *page; *bmc = 0; - bitmap_count_page( - bitmap, - (sector_t)j << bitmap->chunkshift, - -1); - - page = filemap_get_page(bitmap, j); - paddr = kmap_atomic(page); - if (bitmap->flags & BITMAP_HOSTENDIAN) - clear_bit(file_page_offset(bitmap, j), - paddr); - else - __clear_bit_le(file_page_offset(bitmap, j), - paddr); - kunmap_atomic(paddr); - if (!test_page_attr(bitmap, page, - BITMAP_PAGE_NEEDWRITE)) { - set_page_attr(bitmap, page, - BITMAP_PAGE_PENDING); - bitmap->allclean = 0; - } + bitmap_count_page(bitmap, block, -1); + bitmap_file_clear_bit(bitmap, block); } else if (*bmc && *bmc <= 2) { *bmc = 1; - bitmap_set_pending( - bitmap, - (sector_t)j << bitmap->chunkshift); + bitmap_set_pending(bitmap, block); bitmap->allclean = 0; } } @@ -1249,7 +1266,6 @@ void bitmap_daemon_work(struct mddev *mddev) break; } } -out: spin_unlock_irqrestore(&bitmap->lock, flags); done: @@ -1551,7 +1567,7 @@ EXPORT_SYMBOL(bitmap_cond_end_sync); static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed) { /* For each chunk covered by any of these sectors, set the - * counter to 1 and set resync_needed. They should all + * counter to 2 and possibly set resync_needed. They should all * be 0 at this point */ @@ -1678,10 +1694,6 @@ int bitmap_create(struct mddev *mddev) BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); - if (!file - && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */ - return 0; - BUG_ON(file && mddev->bitmap_info.offset); bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL); @@ -1801,6 +1813,10 @@ int bitmap_load(struct mddev *mddev) if (err) goto out; + bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET); + + /* Kick recovery in case any bits were set */ + set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery); mddev->thread->timeout = mddev->bitmap_info.daemon_sleep; md_wakeup_thread(mddev->thread); diff --git a/drivers/md/md.c b/drivers/md/md.c index 9a677f2078a..607771bb7e9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5139,7 +5139,8 @@ int md_run(struct mddev *mddev) err = -EINVAL; mddev->pers->stop(mddev); } - if (err == 0 && mddev->pers->sync_request) { + if (err == 0 && mddev->pers->sync_request && + (mddev->bitmap_info.file || mddev->bitmap_info.offset)) { err = bitmap_create(mddev); if (err) { printk(KERN_ERR "%s: failed to create bitmap (%d)\n", @@ -7847,7 +7848,7 @@ void md_check_recovery(struct mddev *mddev) goto unlock; if (mddev->pers->sync_request) { - if (spares && mddev->bitmap && ! mddev->bitmap->file) { + if (spares) { /* We are adding a device or devices to an array * which has the bitmap stored on all devices. * So make sure all bitmap pages get written -- cgit v1.2.3-70-g09d2 From 27581e5ae01f77b5472dc5c2368b41063fed7f37 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:08 +1000 Subject: md/bitmap: centralise allocation of bitmap file pages. Instead of allocating pages in read_sb_page, read_page and bitmap_read_sb, allocate them all in bitmap_init_from disk. Also replace the hack of calling "attach_page_buffers(page, NULL)" to ensure that free_buffer() won't complain, by putting a test for PagePrivate in free_buffer(). Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 149 ++++++++++++++++++++++++---------------------------- 1 file changed, 68 insertions(+), 81 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c042efd019c..324a198e8be 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -130,22 +130,14 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page) */ /* IO operations when bitmap is stored near all superblocks */ -static struct page *read_sb_page(struct mddev *mddev, loff_t offset, - struct page *page, - unsigned long index, int size) +static int read_sb_page(struct mddev *mddev, loff_t offset, + struct page *page, + unsigned long index, int size) { /* choose a good rdev and read the page from there */ struct md_rdev *rdev; sector_t target; - int did_alloc = 0; - - if (!page) { - page = alloc_page(GFP_KERNEL); - if (!page) - return ERR_PTR(-ENOMEM); - did_alloc = 1; - } rdev_for_each(rdev, mddev) { if (! test_bit(In_sync, &rdev->flags) @@ -158,15 +150,10 @@ static struct page *read_sb_page(struct mddev *mddev, loff_t offset, roundup(size, bdev_logical_block_size(rdev->bdev)), page, READ, true)) { page->index = index; - attach_page_buffers(page, NULL); /* so that free_buffer will - * quietly no-op */ - return page; + return 0; } } - if (did_alloc) - put_page(page); - return ERR_PTR(-EIO); - + return -EIO; } static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mddev) @@ -325,8 +312,12 @@ __clear_page_buffers(struct page *page) } static void free_buffers(struct page *page) { - struct buffer_head *bh = page_buffers(page); + struct buffer_head *bh; + if (!PagePrivate(page)) + return; + + bh = page_buffers(page); while (bh) { struct buffer_head *next = bh->b_this_page; free_buffer_head(bh); @@ -343,11 +334,12 @@ static void free_buffers(struct page *page) * This usage is similar to how swap files are handled, and allows us * to write to a file with no concerns of memory allocation failing. */ -static struct page *read_page(struct file *file, unsigned long index, - struct bitmap *bitmap, - unsigned long count) +static int read_page(struct file *file, unsigned long index, + struct bitmap *bitmap, + unsigned long count, + struct page *page) { - struct page *page = NULL; + int ret = 0; struct inode *inode = file->f_path.dentry->d_inode; struct buffer_head *bh; sector_t block; @@ -355,16 +347,9 @@ static struct page *read_page(struct file *file, unsigned long index, pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE, (unsigned long long)index << PAGE_SHIFT); - page = alloc_page(GFP_KERNEL); - if (!page) - page = ERR_PTR(-ENOMEM); - if (IS_ERR(page)) - goto out; - bh = alloc_page_buffers(page, 1<i_blkbits, 0); if (!bh) { - put_page(page); - page = ERR_PTR(-ENOMEM); + ret = -ENOMEM; goto out; } attach_page_buffers(page, bh); @@ -376,8 +361,7 @@ static struct page *read_page(struct file *file, unsigned long index, bh->b_blocknr = bmap(inode, block); if (bh->b_blocknr == 0) { /* Cannot use this file! */ - free_buffers(page); - page = ERR_PTR(-EINVAL); + ret = -EINVAL; goto out; } bh->b_bdev = inode->i_sb->s_bdev; @@ -400,17 +384,15 @@ static struct page *read_page(struct file *file, unsigned long index, wait_event(bitmap->write_wait, atomic_read(&bitmap->pending_writes)==0); - if (bitmap->flags & BITMAP_WRITE_ERROR) { - free_buffers(page); - page = ERR_PTR(-EIO); - } + if (bitmap->flags & BITMAP_WRITE_ERROR) + ret = -EIO; out: - if (IS_ERR(page)) - printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %ld\n", + if (ret) + printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %d\n", (int)PAGE_SIZE, (unsigned long long)index << PAGE_SHIFT, - PTR_ERR(page)); - return page; + ret); + return ret; } /* @@ -552,6 +534,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) unsigned long chunksize, daemon_sleep, write_behind; unsigned long long events; int err = -EINVAL; + struct page *sb_page; if (!bitmap->file && !bitmap->mddev->bitmap_info.offset) { chunksize = 128 * 1024 * 1024; @@ -562,24 +545,27 @@ static int bitmap_read_sb(struct bitmap *bitmap) goto out_no_sb; } /* page 0 is the superblock, read it... */ + sb_page = alloc_page(GFP_KERNEL); + if (!sb_page) + return -ENOMEM; + bitmap->sb_page = sb_page; + if (bitmap->file) { loff_t isize = i_size_read(bitmap->file->f_mapping->host); int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize; - bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes); + err = read_page(bitmap->file, 0, + bitmap, bytes, sb_page); } else { - bitmap->sb_page = read_sb_page(bitmap->mddev, - bitmap->mddev->bitmap_info.offset, - NULL, - 0, sizeof(bitmap_super_t)); + err = read_sb_page(bitmap->mddev, + bitmap->mddev->bitmap_info.offset, + sb_page, + 0, sizeof(bitmap_super_t)); } - if (IS_ERR(bitmap->sb_page)) { - err = PTR_ERR(bitmap->sb_page); - bitmap->sb_page = NULL; + if (err) return err; - } - sb = kmap_atomic(bitmap->sb_page); + sb = kmap_atomic(sb_page); chunksize = le32_to_cpu(sb->chunksize); daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ; @@ -948,7 +934,8 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) { unsigned long i, chunks, index, oldindex, bit; - struct page *page = NULL, *oldpage = NULL; + int pnum; + struct page *page = NULL; unsigned long num_pages, bit_cnt = 0; struct file *file; unsigned long bytes, offset; @@ -999,6 +986,22 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) if (!bitmap->filemap) goto err; + pnum = 0; + offset = 0; + if (bitmap->sb_page) { + bitmap->filemap[0] = bitmap->sb_page; + pnum = 1; + offset = sizeof(bitmap_super_t); + } + for ( ; pnum < num_pages; pnum++) { + bitmap->filemap[pnum] = alloc_page(GFP_KERNEL); + if (!bitmap->filemap[pnum]) { + bitmap->file_pages = pnum; + goto err; + } + } + bitmap->file_pages = pnum; + /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */ bitmap->filemap_attr = kzalloc( roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)), @@ -1019,39 +1022,22 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) count = bytes - index * PAGE_SIZE; else count = PAGE_SIZE; - if (index == 0 && bitmap->sb_page) { - /* - * if we're here then the superblock page - * contains some bits (PAGE_SIZE != sizeof sb) - * we've already read it in, so just use it - */ - page = bitmap->sb_page; - offset = sizeof(bitmap_super_t); - if (!file) - page = read_sb_page( - bitmap->mddev, - bitmap->mddev->bitmap_info.offset, - page, - index, count); - } else if (file) { - page = read_page(file, index, bitmap, count); - offset = 0; - } else { - page = read_sb_page(bitmap->mddev, - bitmap->mddev->bitmap_info.offset, - NULL, - index, count); - offset = 0; - } - if (IS_ERR(page)) { /* read error */ - ret = PTR_ERR(page); + page = bitmap->filemap[index]; + if (file) + ret = read_page(file, index, bitmap, + count, page); + else + ret = read_sb_page( + bitmap->mddev, + bitmap->mddev->bitmap_info.offset, + page, + index, count); + + if (ret) goto err; - } oldindex = index; - oldpage = page; - bitmap->filemap[bitmap->file_pages++] = page; bitmap->last_page_size = count; if (outofdate) { @@ -1085,6 +1071,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) needed); bit_cnt++; } + offset = 0; } printk(KERN_INFO "%s: bitmap initialized from disk: " -- cgit v1.2.3-70-g09d2 From d189122d4bca2647441fdc170dc6d4cc5c8bb2fa Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:09 +1000 Subject: md/bitmap: change *_page_attr() to take a page number, not a page. Most often we have the page number, not the page. And that is what the *_page_attr() functions really want. So change the arguments to take that number. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 55 +++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 324a198e8be..511f0ed5a5d 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -800,22 +800,22 @@ enum bitmap_page_attr { BITMAP_PAGE_NEEDWRITE = 2, /* there are cleared bits that need to be synced */ }; -static inline void set_page_attr(struct bitmap *bitmap, struct page *page, - enum bitmap_page_attr attr) +static inline void set_page_attr(struct bitmap *bitmap, int pnum, + enum bitmap_page_attr attr) { - __set_bit((page->index<<2) + attr, bitmap->filemap_attr); + __set_bit((pnum<<2) + attr, bitmap->filemap_attr); } -static inline void clear_page_attr(struct bitmap *bitmap, struct page *page, - enum bitmap_page_attr attr) +static inline void clear_page_attr(struct bitmap *bitmap, int pnum, + enum bitmap_page_attr attr) { - __clear_bit((page->index<<2) + attr, bitmap->filemap_attr); + __clear_bit((pnum<<2) + attr, bitmap->filemap_attr); } -static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page, +static inline unsigned long test_page_attr(struct bitmap *bitmap, int pnum, enum bitmap_page_attr attr) { - return test_bit((page->index<<2) + attr, bitmap->filemap_attr); + return test_bit((pnum<<2) + attr, bitmap->filemap_attr); } /* @@ -846,7 +846,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) kunmap_atomic(kaddr); pr_debug("set file bit %lu page %lu\n", bit, page->index); /* record page number so it gets flushed to disk when unplug occurs */ - set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); + set_page_attr(bitmap, page->index, BITMAP_PAGE_DIRTY); } static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) @@ -866,8 +866,8 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) else __clear_bit_le(bit, paddr); kunmap_atomic(paddr); - if (!test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE)) { - set_page_attr(bitmap, page, BITMAP_PAGE_PENDING); + if (!test_page_attr(bitmap, page->index, BITMAP_PAGE_NEEDWRITE)) { + set_page_attr(bitmap, page->index, BITMAP_PAGE_PENDING); bitmap->allclean = 0; } } @@ -879,7 +879,6 @@ void bitmap_unplug(struct bitmap *bitmap) { unsigned long i, flags; int dirty, need_write; - struct page *page; int wait = 0; if (!bitmap || !bitmap->filemap) @@ -893,19 +892,18 @@ void bitmap_unplug(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); return; } - page = bitmap->filemap[i]; - dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); - need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); - clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY); - clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); + dirty = test_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); + need_write = test_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); + clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); + clear_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); if (dirty || need_write) - clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING); + clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING); if (dirty) wait = 1; spin_unlock_irqrestore(&bitmap->lock, flags); if (dirty || need_write) - write_page(bitmap, page, 0); + write_page(bitmap, bitmap->filemap[i], 0); } if (wait) { /* if any writes were performed, we need to wait on them */ if (bitmap->file) @@ -1101,7 +1099,7 @@ void bitmap_write_all(struct bitmap *bitmap) spin_lock_irq(&bitmap->lock); for (i = 0; i < bitmap->file_pages; i++) - set_page_attr(bitmap, bitmap->filemap[i], + set_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); bitmap->allclean = 0; spin_unlock_irq(&bitmap->lock); @@ -1168,11 +1166,11 @@ void bitmap_daemon_work(struct mddev *mddev) */ spin_lock_irqsave(&bitmap->lock, flags); for (j = 0; j < bitmap->file_pages; j++) - if (test_page_attr(bitmap, bitmap->filemap[j], + if (test_page_attr(bitmap, j, BITMAP_PAGE_PENDING)) { - set_page_attr(bitmap, bitmap->filemap[j], + set_page_attr(bitmap, j, BITMAP_PAGE_NEEDWRITE); - clear_page_attr(bitmap, bitmap->filemap[j], + clear_page_attr(bitmap, j, BITMAP_PAGE_PENDING); } @@ -1187,7 +1185,7 @@ void bitmap_daemon_work(struct mddev *mddev) sb->events_cleared = cpu_to_le64(bitmap->events_cleared); kunmap_atomic(sb); - set_page_attr(bitmap, bitmap->sb_page, + set_page_attr(bitmap, 0, BITMAP_PAGE_NEEDWRITE); } } @@ -1236,18 +1234,17 @@ void bitmap_daemon_work(struct mddev *mddev) * We mustn't write any other blocks before the superblock. */ for (j = 0; j < bitmap->file_pages; j++) { - struct page *page = bitmap->filemap[j]; - if (test_page_attr(bitmap, page, + if (test_page_attr(bitmap, j, BITMAP_PAGE_DIRTY)) /* bitmap_unplug will handle the rest */ break; - if (test_page_attr(bitmap, page, + if (test_page_attr(bitmap, j, BITMAP_PAGE_NEEDWRITE)) { - clear_page_attr(bitmap, page, + clear_page_attr(bitmap, j, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - write_page(bitmap, page, 0); + write_page(bitmap, bitmap->filemap[j], 0); spin_lock_irqsave(&bitmap->lock, flags); if (!bitmap->filemap) break; -- cgit v1.2.3-70-g09d2 From 1ec885cdd01a9ad867dbb9fd32a1bfcc0875c486 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:10 +1000 Subject: md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct. This new 'struct bitmap_storage' reflects the external storage of the bitmap. Having this clearly defined will make it easier to change the storage used while the array is active. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 180 +++++++++++++++++++++++++++------------------------- drivers/md/bitmap.h | 17 +++-- drivers/md/md.c | 9 +-- 3 files changed, 110 insertions(+), 96 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 511f0ed5a5d..c98f2fee1bd 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -195,6 +195,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) struct md_rdev *rdev = NULL; struct block_device *bdev; struct mddev *mddev = bitmap->mddev; + struct bitmap_storage *store = &bitmap->storage; while ((rdev = next_active_rdev(rdev, mddev)) != NULL) { int size = PAGE_SIZE; @@ -202,8 +203,8 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; - if (page->index == bitmap->file_pages-1) - size = roundup(bitmap->last_page_size, + if (page->index == store->file_pages-1) + size = roundup(store->last_page_size, bdev_logical_block_size(bdev)); /* Just make sure we aren't corrupting data or * metadata @@ -263,7 +264,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) { struct buffer_head *bh; - if (bitmap->file == NULL) { + if (bitmap->storage.file == NULL) { switch (write_sb_page(bitmap, page, wait)) { case -EINVAL: bitmap->flags |= BITMAP_WRITE_ERROR; @@ -408,9 +409,9 @@ void bitmap_update_sb(struct bitmap *bitmap) return; if (bitmap->mddev->bitmap_info.external) return; - if (!bitmap->sb_page) /* no superblock */ + if (!bitmap->storage.sb_page) /* no superblock */ return; - sb = kmap_atomic(bitmap->sb_page); + sb = kmap_atomic(bitmap->storage.sb_page); sb->events = cpu_to_le64(bitmap->mddev->events); if (bitmap->mddev->events < bitmap->events_cleared) /* rocking back to read-only */ @@ -421,7 +422,7 @@ void bitmap_update_sb(struct bitmap *bitmap) sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ); sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind); kunmap_atomic(sb); - write_page(bitmap, bitmap->sb_page, 1); + write_page(bitmap, bitmap->storage.sb_page, 1); } /* print out the bitmap file superblock */ @@ -429,9 +430,9 @@ void bitmap_print_sb(struct bitmap *bitmap) { bitmap_super_t *sb; - if (!bitmap || !bitmap->sb_page) + if (!bitmap || !bitmap->storage.sb_page) return; - sb = kmap_atomic(bitmap->sb_page); + sb = kmap_atomic(bitmap->storage.sb_page); printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap)); printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic)); printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version)); @@ -470,15 +471,15 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) unsigned long chunksize, daemon_sleep, write_behind; int err = -EINVAL; - bitmap->sb_page = alloc_page(GFP_KERNEL); - if (IS_ERR(bitmap->sb_page)) { - err = PTR_ERR(bitmap->sb_page); - bitmap->sb_page = NULL; + bitmap->storage.sb_page = alloc_page(GFP_KERNEL); + if (IS_ERR(bitmap->storage.sb_page)) { + err = PTR_ERR(bitmap->storage.sb_page); + bitmap->storage.sb_page = NULL; return err; } - bitmap->sb_page->index = 0; + bitmap->storage.sb_page->index = 0; - sb = kmap_atomic(bitmap->sb_page); + sb = kmap_atomic(bitmap->storage.sb_page); sb->magic = cpu_to_le32(BITMAP_MAGIC); sb->version = cpu_to_le32(BITMAP_MAJOR_HI); @@ -536,7 +537,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) int err = -EINVAL; struct page *sb_page; - if (!bitmap->file && !bitmap->mddev->bitmap_info.offset) { + if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) { chunksize = 128 * 1024 * 1024; daemon_sleep = 5 * HZ; write_behind = 0; @@ -548,13 +549,13 @@ static int bitmap_read_sb(struct bitmap *bitmap) sb_page = alloc_page(GFP_KERNEL); if (!sb_page) return -ENOMEM; - bitmap->sb_page = sb_page; + bitmap->storage.sb_page = sb_page; - if (bitmap->file) { - loff_t isize = i_size_read(bitmap->file->f_mapping->host); + if (bitmap->storage.file) { + loff_t isize = i_size_read(bitmap->storage.file->f_mapping->host); int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize; - err = read_page(bitmap->file, 0, + err = read_page(bitmap->storage.file, 0, bitmap, bytes, sb_page); } else { err = read_sb_page(bitmap->mddev, @@ -647,9 +648,9 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, bitmap_super_t *sb; int old; - if (!bitmap->sb_page) /* can't set the state */ + if (!bitmap->storage.sb_page) /* can't set the state */ return 0; - sb = kmap_atomic(bitmap->sb_page); + sb = kmap_atomic(bitmap->storage.sb_page); old = le32_to_cpu(sb->state) & bits; switch (op) { case MASK_SET: @@ -678,17 +679,19 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, * file a page at a time. There's a superblock at the start of the file. */ /* calculate the index of the page that contains this bit */ -static inline unsigned long file_page_index(struct bitmap *bitmap, unsigned long chunk) +static inline unsigned long file_page_index(struct bitmap_storage *store, + unsigned long chunk) { - if (!bitmap->mddev->bitmap_info.external) + if (store->sb_page) chunk += sizeof(bitmap_super_t) << 3; return chunk >> PAGE_BIT_SHIFT; } /* calculate the (bit) offset of this bit within a page */ -static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned long chunk) +static inline unsigned long file_page_offset(struct bitmap_storage *store, + unsigned long chunk) { - if (!bitmap->mddev->bitmap_info.external) + if (store->sb_page) chunk += sizeof(bitmap_super_t) << 3; return chunk & (PAGE_BITS - 1); } @@ -700,13 +703,13 @@ static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned lon * 1 page (e.g., x86) or less than 1 page -- so the bitmap might start on page * 0 or page 1 */ -static inline struct page *filemap_get_page(struct bitmap *bitmap, +static inline struct page *filemap_get_page(struct bitmap_storage *store, unsigned long chunk) { - if (file_page_index(bitmap, chunk) >= bitmap->file_pages) + if (file_page_index(store, chunk) >= store->file_pages) return NULL; - return bitmap->filemap[file_page_index(bitmap, chunk) - - file_page_index(bitmap, 0)]; + return store->filemap[file_page_index(store, chunk) + - file_page_index(store, 0)]; } static void bitmap_file_unmap(struct bitmap *bitmap) @@ -715,16 +718,17 @@ static void bitmap_file_unmap(struct bitmap *bitmap) unsigned long *attr; int pages; unsigned long flags; + struct bitmap_storage *store = &bitmap->storage; spin_lock_irqsave(&bitmap->lock, flags); - map = bitmap->filemap; - bitmap->filemap = NULL; - attr = bitmap->filemap_attr; - bitmap->filemap_attr = NULL; - pages = bitmap->file_pages; - bitmap->file_pages = 0; - sb_page = bitmap->sb_page; - bitmap->sb_page = NULL; + map = store->filemap; + store->filemap = NULL; + attr = store->filemap_attr; + store->filemap_attr = NULL; + pages = store->file_pages; + store->file_pages = 0; + sb_page = store->sb_page; + store->sb_page = NULL; spin_unlock_irqrestore(&bitmap->lock, flags); while (pages--) @@ -743,8 +747,8 @@ static void bitmap_file_put(struct bitmap *bitmap) unsigned long flags; spin_lock_irqsave(&bitmap->lock, flags); - file = bitmap->file; - bitmap->file = NULL; + file = bitmap->storage.file; + bitmap->storage.file = NULL; spin_unlock_irqrestore(&bitmap->lock, flags); if (file) @@ -771,11 +775,11 @@ static void bitmap_file_kick(struct bitmap *bitmap) if (bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET) == 0) { bitmap_update_sb(bitmap); - if (bitmap->file) { + if (bitmap->storage.file) { path = kmalloc(PAGE_SIZE, GFP_KERNEL); if (path) - ptr = d_path(&bitmap->file->f_path, path, - PAGE_SIZE); + ptr = d_path(&bitmap->storage.file->f_path, + path, PAGE_SIZE); printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n", @@ -803,19 +807,19 @@ enum bitmap_page_attr { static inline void set_page_attr(struct bitmap *bitmap, int pnum, enum bitmap_page_attr attr) { - __set_bit((pnum<<2) + attr, bitmap->filemap_attr); + __set_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); } static inline void clear_page_attr(struct bitmap *bitmap, int pnum, enum bitmap_page_attr attr) { - __clear_bit((pnum<<2) + attr, bitmap->filemap_attr); + __clear_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); } static inline unsigned long test_page_attr(struct bitmap *bitmap, int pnum, enum bitmap_page_attr attr) { - return test_bit((pnum<<2) + attr, bitmap->filemap_attr); + return test_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); } /* @@ -832,10 +836,10 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) void *kaddr; unsigned long chunk = block >> bitmap->chunkshift; - page = filemap_get_page(bitmap, chunk); + page = filemap_get_page(&bitmap->storage, chunk); if (!page) return; - bit = file_page_offset(bitmap, chunk); + bit = file_page_offset(&bitmap->storage, chunk); /* set the bit */ kaddr = kmap_atomic(page); @@ -856,10 +860,10 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) void *paddr; unsigned long chunk = block >> bitmap->chunkshift; - page = filemap_get_page(bitmap, chunk); + page = filemap_get_page(&bitmap->storage, chunk); if (!page) return; - bit = file_page_offset(bitmap, chunk); + bit = file_page_offset(&bitmap->storage, chunk); paddr = kmap_atomic(page); if (bitmap->flags & BITMAP_HOSTENDIAN) clear_bit(bit, paddr); @@ -881,14 +885,14 @@ void bitmap_unplug(struct bitmap *bitmap) int dirty, need_write; int wait = 0; - if (!bitmap || !bitmap->filemap) + if (!bitmap || !bitmap->storage.filemap) return; /* look at each page to see if there are any set bits that need to be * flushed out to disk */ - for (i = 0; i < bitmap->file_pages; i++) { + for (i = 0; i < bitmap->storage.file_pages; i++) { spin_lock_irqsave(&bitmap->lock, flags); - if (!bitmap->filemap) { + if (!bitmap->storage.filemap) { spin_unlock_irqrestore(&bitmap->lock, flags); return; } @@ -903,10 +907,10 @@ void bitmap_unplug(struct bitmap *bitmap) spin_unlock_irqrestore(&bitmap->lock, flags); if (dirty || need_write) - write_page(bitmap, bitmap->filemap[i], 0); + write_page(bitmap, bitmap->storage.filemap[i], 0); } if (wait) { /* if any writes were performed, we need to wait on them */ - if (bitmap->file) + if (bitmap->storage.file) wait_event(bitmap->write_wait, atomic_read(&bitmap->pending_writes)==0); else @@ -940,14 +944,15 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) int outofdate; int ret = -ENOSPC; void *paddr; + struct bitmap_storage *store = &bitmap->storage; chunks = bitmap->chunks; - file = bitmap->file; + file = store->file; if (!file && !bitmap->mddev->bitmap_info.offset) { /* No permanent bitmap - fill with '1s'. */ - bitmap->filemap = NULL; - bitmap->file_pages = 0; + store->filemap = NULL; + store->file_pages = 0; for (i = 0; i < chunks ; i++) { /* if the disk bit is set, set the memory bit */ int needed = ((sector_t)(i+1) << (bitmap->chunkshift) @@ -980,39 +985,40 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) ret = -ENOMEM; - bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL); - if (!bitmap->filemap) + store->filemap = kmalloc(sizeof(struct page *) + * num_pages, GFP_KERNEL); + if (!store->filemap) goto err; pnum = 0; offset = 0; - if (bitmap->sb_page) { - bitmap->filemap[0] = bitmap->sb_page; + if (store->sb_page) { + store->filemap[0] = store->sb_page; pnum = 1; offset = sizeof(bitmap_super_t); } for ( ; pnum < num_pages; pnum++) { - bitmap->filemap[pnum] = alloc_page(GFP_KERNEL); - if (!bitmap->filemap[pnum]) { - bitmap->file_pages = pnum; + store->filemap[pnum] = alloc_page(GFP_KERNEL); + if (!store->filemap[pnum]) { + store->file_pages = pnum; goto err; } } - bitmap->file_pages = pnum; + store->file_pages = pnum; /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */ - bitmap->filemap_attr = kzalloc( + store->filemap_attr = kzalloc( roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)), GFP_KERNEL); - if (!bitmap->filemap_attr) + if (!store->filemap_attr) goto err; oldindex = ~0L; for (i = 0; i < chunks; i++) { int b; - index = file_page_index(bitmap, i); - bit = file_page_offset(bitmap, i); + index = file_page_index(&bitmap->storage, i); + bit = file_page_offset(&bitmap->storage, i); if (index != oldindex) { /* this is a new page, read it in */ int count; /* unmap the old page, we're done with it */ @@ -1020,7 +1026,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) count = bytes - index * PAGE_SIZE; else count = PAGE_SIZE; - page = bitmap->filemap[index]; + page = store->filemap[index]; if (file) ret = read_page(file, index, bitmap, count, page); @@ -1036,7 +1042,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) oldindex = index; - bitmap->last_page_size = count; + store->last_page_size = count; if (outofdate) { /* @@ -1074,7 +1080,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) printk(KERN_INFO "%s: bitmap initialized from disk: " "read %lu/%lu pages, set %lu of %lu bits\n", - bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks); + bmname(bitmap), store->file_pages, + num_pages, bit_cnt, chunks); return 0; @@ -1091,14 +1098,14 @@ void bitmap_write_all(struct bitmap *bitmap) */ int i; - if (!bitmap || !bitmap->filemap) + if (!bitmap || !bitmap->storage.filemap) return; - if (bitmap->file) + if (bitmap->storage.file) /* Only one copy, so nothing needed */ return; spin_lock_irq(&bitmap->lock); - for (i = 0; i < bitmap->file_pages; i++) + for (i = 0; i < bitmap->storage.file_pages; i++) set_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); bitmap->allclean = 0; @@ -1165,7 +1172,7 @@ void bitmap_daemon_work(struct mddev *mddev) * we will write it. */ spin_lock_irqsave(&bitmap->lock, flags); - for (j = 0; j < bitmap->file_pages; j++) + for (j = 0; j < bitmap->storage.file_pages; j++) if (test_page_attr(bitmap, j, BITMAP_PAGE_PENDING)) { set_page_attr(bitmap, j, @@ -1180,8 +1187,8 @@ void bitmap_daemon_work(struct mddev *mddev) * other changes */ bitmap_super_t *sb; bitmap->need_sync = 0; - if (bitmap->filemap) { - sb = kmap_atomic(bitmap->sb_page); + if (bitmap->storage.filemap) { + sb = kmap_atomic(bitmap->storage.sb_page); sb->events_cleared = cpu_to_le64(bitmap->events_cleared); kunmap_atomic(sb); @@ -1233,7 +1240,7 @@ void bitmap_daemon_work(struct mddev *mddev) * the first blocking holds the superblock and it has been updated. * We mustn't write any other blocks before the superblock. */ - for (j = 0; j < bitmap->file_pages; j++) { + for (j = 0; j < bitmap->storage.file_pages; j++) { if (test_page_attr(bitmap, j, BITMAP_PAGE_DIRTY)) @@ -1244,9 +1251,9 @@ void bitmap_daemon_work(struct mddev *mddev) clear_page_attr(bitmap, j, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); - write_page(bitmap, bitmap->filemap[j], 0); + write_page(bitmap, bitmap->storage.filemap[j], 0); spin_lock_irqsave(&bitmap->lock, flags); - if (!bitmap->filemap) + if (!bitmap->storage.filemap) break; } } @@ -1700,7 +1707,7 @@ int bitmap_create(struct mddev *mddev) } else bitmap->sysfs_can_clear = NULL; - bitmap->file = file; + bitmap->storage.file = file; if (file) { get_file(file); /* As future accesses to this file will use bmap, @@ -1832,9 +1839,9 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) << (PAGE_SHIFT - 10), chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize, chunk_kb ? "KB" : "B"); - if (bitmap->file) { + if (bitmap->storage.file) { seq_printf(seq, ", file: "); - seq_path(seq, &bitmap->file->f_path, " \t\n"); + seq_path(seq, &bitmap->storage.file->f_path, " \t\n"); } seq_printf(seq, "\n"); @@ -1958,8 +1965,9 @@ space_store(struct mddev *mddev, const char *buf, size_t len) return -EINVAL; if (mddev->bitmap && - sectors < ((mddev->bitmap->file_pages - 1) * PAGE_SIZE - + mddev->bitmap->last_page_size + 511) >> 9) + sectors < ((mddev->bitmap->storage.file_pages - 1) + * PAGE_SIZE + + mddev->bitmap->storage.last_page_size + 511) >> 9) return -EFBIG; /* Bitmap is too big for this small space */ /* could make sure it isn't too big, but that isn't really diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 79e17983473..162ab095b86 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -188,12 +188,17 @@ struct bitmap { /* bitmap spinlock */ spinlock_t lock; - struct file *file; /* backing disk file */ - struct page *sb_page; /* cached copy of the bitmap file superblock */ - struct page **filemap; /* list of cache pages for the file */ - unsigned long *filemap_attr; /* attributes associated w/ filemap pages */ - unsigned long file_pages; /* number of pages in the file */ - int last_page_size; /* bytes in the last page */ + struct bitmap_storage { + struct file *file; /* backing disk file */ + struct page *sb_page; /* cached copy of the bitmap + * file superblock */ + struct page **filemap; /* list of cache pages for + * the file */ + unsigned long *filemap_attr; /* attributes associated + * w/ filemap pages */ + unsigned long file_pages; /* number of pages in the file*/ + int last_page_size; /* bytes in the last page */ + } storage; unsigned long flags; diff --git a/drivers/md/md.c b/drivers/md/md.c index 607771bb7e9..9e2336fbbd3 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1989,7 +1989,7 @@ super_1_allow_new_offset(struct md_rdev *rdev, bitmap = rdev->mddev->bitmap; if (bitmap && !rdev->mddev->bitmap_info.file && rdev->sb_start + rdev->mddev->bitmap_info.offset + - bitmap->file_pages * (PAGE_SIZE>>9) > new_offset) + bitmap->storage.file_pages * (PAGE_SIZE>>9) > new_offset) return 0; if (rdev->badblocks.sector + rdev->badblocks.size > new_offset) return 0; @@ -5649,7 +5649,7 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg) goto out; /* bitmap disabled, zero the first byte and copy out */ - if (!mddev->bitmap || !mddev->bitmap->file) { + if (!mddev->bitmap || !mddev->bitmap->storage.file) { file->pathname[0] = '\0'; goto copy_out; } @@ -5658,7 +5658,8 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg) if (!buf) goto out; - ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname)); + ptr = d_path(&mddev->bitmap->storage.file->f_path, + buf, sizeof(file->pathname)); if (IS_ERR(ptr)) goto out; @@ -6299,7 +6300,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info) /* remove the bitmap */ if (!mddev->bitmap) return -ENOENT; - if (mddev->bitmap->file) + if (mddev->bitmap->storage.file) return -EINVAL; mddev->pers->quiesce(mddev, 1); bitmap_destroy(mddev); -- cgit v1.2.3-70-g09d2 From 9b1215c102d4b12f6c815d7fdd35d0628db35b28 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:11 +1000 Subject: md/bitmap: store bytes in file rather than just in last page. This number is more generally useful, and bytes-in-last-page is easily extracted from it. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 16 +++++++++------- drivers/md/bitmap.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c98f2fee1bd..7a3be0d4103 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -203,9 +203,13 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; - if (page->index == store->file_pages-1) - size = roundup(store->last_page_size, + if (page->index == store->file_pages-1) { + int last_page_size = store->bytes & (PAGE_SIZE-1); + if (last_page_size == 0) + last_page_size = PAGE_SIZE; + size = roundup(last_page_size, bdev_logical_block_size(bdev)); + } /* Just make sure we aren't corrupting data or * metadata */ @@ -973,6 +977,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) if (!bitmap->mddev->bitmap_info.external) bytes += sizeof(bitmap_super_t); + store->bytes = bytes; + num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); if (file && i_size_read(file->f_mapping->host) < bytes) { @@ -1042,8 +1048,6 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) oldindex = index; - store->last_page_size = count; - if (outofdate) { /* * if bitmap is out of date, dirty the @@ -1965,9 +1969,7 @@ space_store(struct mddev *mddev, const char *buf, size_t len) return -EINVAL; if (mddev->bitmap && - sectors < ((mddev->bitmap->storage.file_pages - 1) - * PAGE_SIZE - + mddev->bitmap->storage.last_page_size + 511) >> 9) + sectors < (mddev->bitmap->storage.bytes + 511) >> 9) return -EFBIG; /* Bitmap is too big for this small space */ /* could make sure it isn't too big, but that isn't really diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 162ab095b86..26689260e17 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -197,7 +197,7 @@ struct bitmap { unsigned long *filemap_attr; /* attributes associated * w/ filemap pages */ unsigned long file_pages; /* number of pages in the file*/ - int last_page_size; /* bytes in the last page */ + unsigned long bytes; /* total bytes in the bitmap */ } storage; unsigned long flags; -- cgit v1.2.3-70-g09d2 From d1244cb062750bdb2298ca2565239d3d8cbd91a8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:12 +1000 Subject: md/bitmap: separate bitmap file allocation to its own function. This will allow allocation before swapping in a new bitmap. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 113 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 46 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 7a3be0d4103..4ac60ed66c4 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -716,6 +716,58 @@ static inline struct page *filemap_get_page(struct bitmap_storage *store, - file_page_index(store, 0)]; } +static int bitmap_storage_alloc(struct bitmap_storage *store, + unsigned long chunks, int with_super) +{ + int pnum; + unsigned long num_pages; + unsigned long bytes; + + bytes = DIV_ROUND_UP(chunks, 8); + if (with_super) + bytes += sizeof(bitmap_super_t); + + num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); + + store->filemap = kmalloc(sizeof(struct page *) + * num_pages, GFP_KERNEL); + if (!store->filemap) + return -ENOMEM; + + if (with_super && !store->sb_page) { + store->sb_page = alloc_page(GFP_KERNEL); + if (store->sb_page == NULL) + return -ENOMEM; + store->sb_page->index = 0; + } + pnum = 0; + if (store->sb_page) { + store->filemap[0] = store->sb_page; + pnum = 1; + } + for ( ; pnum < num_pages; pnum++) { + store->filemap[pnum] = alloc_page(GFP_KERNEL); + if (!store->filemap[pnum]) { + store->file_pages = pnum; + return -ENOMEM; + } + store->filemap[pnum]->index = pnum; + } + store->file_pages = pnum; + + /* We need 4 bits per page, rounded up to a multiple + * of sizeof(unsigned long) */ + store->filemap_attr = kzalloc( + roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)), + GFP_KERNEL); + if (!store->filemap_attr) + return -ENOMEM; + + store->bytes = bytes; + + return 0; +} + static void bitmap_file_unmap(struct bitmap *bitmap) { struct page **map, *sb_page; @@ -940,11 +992,10 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) { unsigned long i, chunks, index, oldindex, bit; - int pnum; struct page *page = NULL; - unsigned long num_pages, bit_cnt = 0; + unsigned long bit_cnt = 0; struct file *file; - unsigned long bytes, offset; + unsigned long offset; int outofdate; int ret = -ENOSPC; void *paddr; @@ -973,53 +1024,23 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) printk(KERN_INFO "%s: bitmap file is out of date, doing full " "recovery\n", bmname(bitmap)); - bytes = DIV_ROUND_UP(bitmap->chunks, 8); - if (!bitmap->mddev->bitmap_info.external) - bytes += sizeof(bitmap_super_t); - - store->bytes = bytes; - - num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); - - if (file && i_size_read(file->f_mapping->host) < bytes) { + if (file && i_size_read(file->f_mapping->host) < store->bytes) { printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n", - bmname(bitmap), - (unsigned long) i_size_read(file->f_mapping->host), - bytes); + bmname(bitmap), + (unsigned long) i_size_read(file->f_mapping->host), + store->bytes); goto err; } - ret = -ENOMEM; - - store->filemap = kmalloc(sizeof(struct page *) - * num_pages, GFP_KERNEL); - if (!store->filemap) + ret = bitmap_storage_alloc(&bitmap->storage, bitmap->chunks, + !bitmap->mddev->bitmap_info.external); + if (ret) goto err; - pnum = 0; + oldindex = ~0L; offset = 0; - if (store->sb_page) { - store->filemap[0] = store->sb_page; - pnum = 1; + if (!bitmap->mddev->bitmap_info.external) offset = sizeof(bitmap_super_t); - } - for ( ; pnum < num_pages; pnum++) { - store->filemap[pnum] = alloc_page(GFP_KERNEL); - if (!store->filemap[pnum]) { - store->file_pages = pnum; - goto err; - } - } - store->file_pages = pnum; - - /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */ - store->filemap_attr = kzalloc( - roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)), - GFP_KERNEL); - if (!store->filemap_attr) - goto err; - - oldindex = ~0L; for (i = 0; i < chunks; i++) { int b; @@ -1028,8 +1049,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) if (index != oldindex) { /* this is a new page, read it in */ int count; /* unmap the old page, we're done with it */ - if (index == num_pages-1) - count = bytes - index * PAGE_SIZE; + if (index == store->file_pages-1) + count = store->bytes - index * PAGE_SIZE; else count = PAGE_SIZE; page = store->filemap[index]; @@ -1083,9 +1104,9 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) } printk(KERN_INFO "%s: bitmap initialized from disk: " - "read %lu/%lu pages, set %lu of %lu bits\n", + "read %lu pages, set %lu of %lu bits\n", bmname(bitmap), store->file_pages, - num_pages, bit_cnt, chunks); + bit_cnt, chunks); return 0; -- cgit v1.2.3-70-g09d2 From bc9891a8853842a19c33dda0ba02fbacf7da067f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:12 +1000 Subject: md/bitmap: move storage allocation from bitmap_load to bitmap_create. We should allocate memory for the storage-bitmap at create-time, not load time. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 4ac60ed66c4..1a93ed1fb8d 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1032,11 +1032,6 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) goto err; } - ret = bitmap_storage_alloc(&bitmap->storage, bitmap->chunks, - !bitmap->mddev->bitmap_info.external); - if (ret) - goto err; - oldindex = ~0L; offset = 0; if (!bitmap->mddev->bitmap_info.external) @@ -1782,6 +1777,12 @@ int bitmap_create(struct mddev *mddev) if (!bitmap->bp) goto error; + if (file || mddev->bitmap_info.offset) { + err = bitmap_storage_alloc(&bitmap->storage, bitmap->chunks, + !mddev->bitmap_info.external); + if (err) + goto error; + } printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", pages, bmname(bitmap)); -- cgit v1.2.3-70-g09d2 From edbb79df6731bb1e99c15f5a519a864d488f4808 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:13 +1000 Subject: md/bitmap: remove bitmap_mask_state This function isn't really needed. It sets or clears a flag in both bitmap->flags and sb->state. However both times it is called, bitmap_update_sb is called soon afterwards which copies bitmap->flags to sb->state. So just make changes to bitmap->flags, and open-code those rather than hiding in a function. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 37 +++---------------------------------- 1 file changed, 3 insertions(+), 34 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 1a93ed1fb8d..2d25f3aebd4 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -640,38 +640,6 @@ out_no_sb: return err; } -enum bitmap_mask_op { - MASK_SET, - MASK_UNSET -}; - -/* record the state of the bitmap in the superblock. Return the old value */ -static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits, - enum bitmap_mask_op op) -{ - bitmap_super_t *sb; - int old; - - if (!bitmap->storage.sb_page) /* can't set the state */ - return 0; - sb = kmap_atomic(bitmap->storage.sb_page); - old = le32_to_cpu(sb->state) & bits; - switch (op) { - case MASK_SET: - sb->state |= cpu_to_le32(bits); - bitmap->flags |= bits; - break; - case MASK_UNSET: - sb->state &= cpu_to_le32(~bits); - bitmap->flags &= ~bits; - break; - default: - BUG(); - } - kunmap_atomic(sb); - return old; -} - /* * general bitmap file operations */ @@ -828,7 +796,8 @@ static void bitmap_file_kick(struct bitmap *bitmap) { char *path, *ptr = NULL; - if (bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET) == 0) { + if (!(bitmap->flags & BITMAP_STALE)) { + bitmap->flags |= BITMAP_STALE; bitmap_update_sb(bitmap); if (bitmap->storage.file) { @@ -1830,7 +1799,7 @@ int bitmap_load(struct mddev *mddev) if (err) goto out; - bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET); + bitmap->flags &= ~BITMAP_STALE; /* Kick recovery in case any bits were set */ set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery); -- cgit v1.2.3-70-g09d2 From 84e923453e19d6427c6aa884d9561f01e1425d09 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:14 +1000 Subject: md/bitmap: remove single-bit manipulation on sb->state Just do single-bit manipulations on bitmap->flags and copy whole value between that and sb->state. This will allow next patch which changes how bit manipulations are performed on bitmap->flags. This does result in BITMAP_STALE not being set in sb by bitmap_read_sb, however as the setting is determined by other information in the 'sb' we do not lose information this way. Normally, bitmap_load will be called shortly which will clear BITMAP_STALE anyway. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2d25f3aebd4..09d360ff77d 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -522,7 +522,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) memcpy(sb->uuid, bitmap->mddev->uuid, 16); bitmap->flags |= BITMAP_STALE; - sb->state |= cpu_to_le32(BITMAP_STALE); + sb->state = cpu_to_le32(bitmap->flags); bitmap->events_cleared = bitmap->mddev->events; sb->events_cleared = cpu_to_le64(bitmap->mddev->events); @@ -617,7 +617,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) "-- forcing full recovery\n", bmname(bitmap), events, (unsigned long long) bitmap->mddev->events); - sb->state |= cpu_to_le32(BITMAP_STALE); + bitmap->flags |= BITMAP_STALE; } } -- cgit v1.2.3-70-g09d2 From b405fe91e50c60c80e72d798025aea4917096421 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:15 +1000 Subject: md/bitmap: use set_bit, test_bit, etc for operation on bitmap->flags. We currently use '&' and '|' which isn't the norm in the kernel and doesn't allow easy atomicity. So change to bit numbers and {set,clear,test}_bit. This allows us to remove a spinlock/unlock (which was dubious anyway) and some other simplifications. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 46 +++++++++++++++++++++------------------------- drivers/md/bitmap.h | 6 +++--- 2 files changed, 24 insertions(+), 28 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 09d360ff77d..f3a9dffc3fc 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -271,7 +271,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) if (bitmap->storage.file == NULL) { switch (write_sb_page(bitmap, page, wait)) { case -EINVAL: - bitmap->flags |= BITMAP_WRITE_ERROR; + set_bit(BITMAP_WRITE_ERROR, &bitmap->flags); } } else { @@ -289,20 +289,16 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) wait_event(bitmap->write_wait, atomic_read(&bitmap->pending_writes)==0); } - if (bitmap->flags & BITMAP_WRITE_ERROR) + if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) bitmap_file_kick(bitmap); } static void end_bitmap_write(struct buffer_head *bh, int uptodate) { struct bitmap *bitmap = bh->b_private; - unsigned long flags; - if (!uptodate) { - spin_lock_irqsave(&bitmap->lock, flags); - bitmap->flags |= BITMAP_WRITE_ERROR; - spin_unlock_irqrestore(&bitmap->lock, flags); - } + if (!uptodate) + set_bit(BITMAP_WRITE_ERROR, &bitmap->flags); if (atomic_dec_and_test(&bitmap->pending_writes)) wake_up(&bitmap->write_wait); } @@ -389,7 +385,7 @@ static int read_page(struct file *file, unsigned long index, wait_event(bitmap->write_wait, atomic_read(&bitmap->pending_writes)==0); - if (bitmap->flags & BITMAP_WRITE_ERROR) + if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) ret = -EIO; out: if (ret) @@ -521,7 +517,7 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) memcpy(sb->uuid, bitmap->mddev->uuid, 16); - bitmap->flags |= BITMAP_STALE; + set_bit(BITMAP_STALE, &bitmap->flags); sb->state = cpu_to_le32(bitmap->flags); bitmap->events_cleared = bitmap->mddev->events; sb->events_cleared = cpu_to_le64(bitmap->mddev->events); @@ -545,7 +541,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) chunksize = 128 * 1024 * 1024; daemon_sleep = 5 * HZ; write_behind = 0; - bitmap->flags = BITMAP_STALE; + set_bit(BITMAP_STALE, &bitmap->flags); err = 0; goto out_no_sb; } @@ -617,20 +613,20 @@ static int bitmap_read_sb(struct bitmap *bitmap) "-- forcing full recovery\n", bmname(bitmap), events, (unsigned long long) bitmap->mddev->events); - bitmap->flags |= BITMAP_STALE; + set_bit(BITMAP_STALE, &bitmap->flags); } } /* assign fields using values from superblock */ bitmap->flags |= le32_to_cpu(sb->state); if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN) - bitmap->flags |= BITMAP_HOSTENDIAN; + set_bit(BITMAP_HOSTENDIAN, &bitmap->flags); bitmap->events_cleared = le64_to_cpu(sb->events_cleared); err = 0; out: kunmap_atomic(sb); out_no_sb: - if (bitmap->flags & BITMAP_STALE) + if (test_bit(BITMAP_STALE, &bitmap->flags)) bitmap->events_cleared = bitmap->mddev->events; bitmap->mddev->bitmap_info.chunksize = chunksize; bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep; @@ -796,8 +792,7 @@ static void bitmap_file_kick(struct bitmap *bitmap) { char *path, *ptr = NULL; - if (!(bitmap->flags & BITMAP_STALE)) { - bitmap->flags |= BITMAP_STALE; + if (!test_and_set_bit(BITMAP_STALE, &bitmap->flags)) { bitmap_update_sb(bitmap); if (bitmap->storage.file) { @@ -868,7 +863,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) /* set the bit */ kaddr = kmap_atomic(page); - if (bitmap->flags & BITMAP_HOSTENDIAN) + if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags)) set_bit(bit, kaddr); else __set_bit_le(bit, kaddr); @@ -890,7 +885,7 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) return; bit = file_page_offset(&bitmap->storage, chunk); paddr = kmap_atomic(page); - if (bitmap->flags & BITMAP_HOSTENDIAN) + if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags)) clear_bit(bit, paddr); else __clear_bit_le(bit, paddr); @@ -941,7 +936,7 @@ void bitmap_unplug(struct bitmap *bitmap) else md_super_wait(bitmap->mddev); } - if (bitmap->flags & BITMAP_WRITE_ERROR) + if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) bitmap_file_kick(bitmap); } EXPORT_SYMBOL(bitmap_unplug); @@ -988,7 +983,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) return 0; } - outofdate = bitmap->flags & BITMAP_STALE; + outofdate = test_bit(BITMAP_STALE, &bitmap->flags); if (outofdate) printk(KERN_INFO "%s: bitmap file is out of date, doing full " "recovery\n", bmname(bitmap)); @@ -1045,12 +1040,13 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) write_page(bitmap, page, 1); ret = -EIO; - if (bitmap->flags & BITMAP_WRITE_ERROR) + if (test_bit(BITMAP_WRITE_ERROR, + &bitmap->flags)) goto err; } } paddr = kmap_atomic(page); - if (bitmap->flags & BITMAP_HOSTENDIAN) + if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags)) b = test_bit(bit, paddr); else b = test_bit_le(bit, paddr); @@ -1758,7 +1754,7 @@ int bitmap_create(struct mddev *mddev) mddev->bitmap = bitmap; - return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0; + return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0; error: bitmap_free(bitmap); @@ -1799,7 +1795,7 @@ int bitmap_load(struct mddev *mddev) if (err) goto out; - bitmap->flags &= ~BITMAP_STALE; + clear_bit(BITMAP_STALE, &bitmap->flags); /* Kick recovery in case any bits were set */ set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery); @@ -1809,7 +1805,7 @@ int bitmap_load(struct mddev *mddev) bitmap_update_sb(bitmap); - if (bitmap->flags & BITMAP_WRITE_ERROR) + if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) err = -EIO; out: return err; diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 26689260e17..e2d999a62ba 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -111,9 +111,9 @@ typedef __u16 bitmap_counter_t; /* use these for bitmap->flags and bitmap->sb->state bit-fields */ enum bitmap_state { - BITMAP_STALE = 0x002, /* the bitmap file is out of date or had -EIO */ - BITMAP_WRITE_ERROR = 0x004, /* A write error has occurred */ - BITMAP_HOSTENDIAN = 0x8000, + BITMAP_STALE = 1, /* the bitmap file is out of date or had -EIO */ + BITMAP_WRITE_ERROR = 2, /* A write error has occurred */ + BITMAP_HOSTENDIAN =15, }; /* the superblock at the front of the bitmap file -- little endian */ -- cgit v1.2.3-70-g09d2 From 7466712347c58c367636cc875801c8703bc729e7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:19 +1000 Subject: md/bitmap: convert some spin_lock_irqsave to spin_lock_irq All of these sites can only be called from process context with irqs enabled, so using irqsave/irqrestore just adds noise. Remove it. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index f3a9dffc3fc..a1862d9e6d8 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -737,10 +737,9 @@ static void bitmap_file_unmap(struct bitmap *bitmap) struct page **map, *sb_page; unsigned long *attr; int pages; - unsigned long flags; struct bitmap_storage *store = &bitmap->storage; - spin_lock_irqsave(&bitmap->lock, flags); + spin_lock_irq(&bitmap->lock); map = store->filemap; store->filemap = NULL; attr = store->filemap_attr; @@ -749,7 +748,7 @@ static void bitmap_file_unmap(struct bitmap *bitmap) store->file_pages = 0; sb_page = store->sb_page; store->sb_page = NULL; - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); while (pages--) if (map[pages] != sb_page) /* 0 is sb_page, release it below */ @@ -764,12 +763,11 @@ static void bitmap_file_unmap(struct bitmap *bitmap) static void bitmap_file_put(struct bitmap *bitmap) { struct file *file; - unsigned long flags; - spin_lock_irqsave(&bitmap->lock, flags); + spin_lock_irq(&bitmap->lock); file = bitmap->storage.file; bitmap->storage.file = NULL; - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); if (file) wait_event(bitmap->write_wait, @@ -901,7 +899,7 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) * sync the dirty pages of the bitmap file to disk */ void bitmap_unplug(struct bitmap *bitmap) { - unsigned long i, flags; + unsigned long i; int dirty, need_write; int wait = 0; @@ -911,9 +909,9 @@ void bitmap_unplug(struct bitmap *bitmap) /* look at each page to see if there are any set bits that need to be * flushed out to disk */ for (i = 0; i < bitmap->storage.file_pages; i++) { - spin_lock_irqsave(&bitmap->lock, flags); + spin_lock_irq(&bitmap->lock); if (!bitmap->storage.filemap) { - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); return; } dirty = test_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); @@ -924,7 +922,7 @@ void bitmap_unplug(struct bitmap *bitmap) clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING); if (dirty) wait = 1; - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); if (dirty || need_write) write_page(bitmap, bitmap->storage.filemap[i], 0); @@ -1129,7 +1127,6 @@ void bitmap_daemon_work(struct mddev *mddev) struct bitmap *bitmap; unsigned long j; unsigned long nextpage; - unsigned long flags; sector_t blocks; /* Use a mutex to guard daemon_work against @@ -1156,7 +1153,7 @@ void bitmap_daemon_work(struct mddev *mddev) * So set NEEDWRITE now, then after we make any last-minute changes * we will write it. */ - spin_lock_irqsave(&bitmap->lock, flags); + spin_lock_irq(&bitmap->lock); for (j = 0; j < bitmap->storage.file_pages; j++) if (test_page_attr(bitmap, j, BITMAP_PAGE_PENDING)) { @@ -1235,14 +1232,14 @@ void bitmap_daemon_work(struct mddev *mddev) BITMAP_PAGE_NEEDWRITE)) { clear_page_attr(bitmap, j, BITMAP_PAGE_NEEDWRITE); - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); write_page(bitmap, bitmap->storage.filemap[j], 0); - spin_lock_irqsave(&bitmap->lock, flags); + spin_lock_irq(&bitmap->lock); if (!bitmap->storage.filemap) break; } } - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); done: if (bitmap->allclean == 0) @@ -1815,12 +1812,11 @@ EXPORT_SYMBOL_GPL(bitmap_load); void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) { unsigned long chunk_kb; - unsigned long flags; if (!bitmap) return; - spin_lock_irqsave(&bitmap->lock, flags); + spin_lock_irq(&bitmap->lock); chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10; seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], " "%lu%s chunk", @@ -1836,7 +1832,7 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) } seq_printf(seq, "\n"); - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irq(&bitmap->lock); } static ssize_t -- cgit v1.2.3-70-g09d2 From 62f82faaceb483284ea938b3a092b9f0a4d2d029 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:21 +1000 Subject: md/bitmap: remove async freeing of bitmap file. There is no real value in freeing things the moment there is an error. It is just as good to free the bitmap file and pages when the bitmap is explicitly removed (and replaced?) or at shutdown. With this gone, the bitmap will only disappear when the array is quiescent, so we can remove some locking. As the 'filemap' doesn't disappear now, include extra checks before trying to write any of it out. Also remove the check for "has it disappeared" in bitmap_daemon_write(). Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index a1862d9e6d8..7e015c9ea73 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -739,7 +739,6 @@ static void bitmap_file_unmap(struct bitmap *bitmap) int pages; struct bitmap_storage *store = &bitmap->storage; - spin_lock_irq(&bitmap->lock); map = store->filemap; store->filemap = NULL; attr = store->filemap_attr; @@ -748,7 +747,6 @@ static void bitmap_file_unmap(struct bitmap *bitmap) store->file_pages = 0; sb_page = store->sb_page; store->sb_page = NULL; - spin_unlock_irq(&bitmap->lock); while (pages--) if (map[pages] != sb_page) /* 0 is sb_page, release it below */ @@ -764,10 +762,8 @@ static void bitmap_file_put(struct bitmap *bitmap) { struct file *file; - spin_lock_irq(&bitmap->lock); file = bitmap->storage.file; bitmap->storage.file = NULL; - spin_unlock_irq(&bitmap->lock); if (file) wait_event(bitmap->write_wait, @@ -809,10 +805,6 @@ static void bitmap_file_kick(struct bitmap *bitmap) "%s: disabling internal bitmap due to errors\n", bmname(bitmap)); } - - bitmap_file_put(bitmap); - - return; } enum bitmap_page_attr { @@ -903,7 +895,8 @@ void bitmap_unplug(struct bitmap *bitmap) int dirty, need_write; int wait = 0; - if (!bitmap || !bitmap->storage.filemap) + if (!bitmap || !bitmap->storage.filemap || + test_bit(BITMAP_STALE, &bitmap->flags)) return; /* look at each page to see if there are any set bits that need to be @@ -1222,7 +1215,10 @@ void bitmap_daemon_work(struct mddev *mddev) * the first blocking holds the superblock and it has been updated. * We mustn't write any other blocks before the superblock. */ - for (j = 0; j < bitmap->storage.file_pages; j++) { + for (j = 0; + j < bitmap->storage.file_pages + && !test_bit(BITMAP_STALE, &bitmap->flags); + j++) { if (test_page_attr(bitmap, j, BITMAP_PAGE_DIRTY)) @@ -1235,8 +1231,6 @@ void bitmap_daemon_work(struct mddev *mddev) spin_unlock_irq(&bitmap->lock); write_page(bitmap, bitmap->storage.filemap[j], 0); spin_lock_irq(&bitmap->lock); - if (!bitmap->storage.filemap) - break; } } spin_unlock_irq(&bitmap->lock); -- cgit v1.2.3-70-g09d2 From fae7d326cd0905624c173337fdfcfe9b86b9e6e2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:21 +1000 Subject: md/bitmap: merge bitmap_file_unmap and bitmap_file_put. There functions really do one thing together: release the 'bitmap_storage'. So make them just one function. Since we removed the locking (previous patch), we don't need to zero any fields before freeing them, so it all becomes a bit simpler. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 7e015c9ea73..d2ab7d3df3e 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -732,43 +732,25 @@ static int bitmap_storage_alloc(struct bitmap_storage *store, return 0; } -static void bitmap_file_unmap(struct bitmap *bitmap) +static void bitmap_file_unmap(struct bitmap_storage *store) { struct page **map, *sb_page; - unsigned long *attr; int pages; - struct bitmap_storage *store = &bitmap->storage; + struct file *file; + file = store->file; map = store->filemap; - store->filemap = NULL; - attr = store->filemap_attr; - store->filemap_attr = NULL; pages = store->file_pages; - store->file_pages = 0; sb_page = store->sb_page; - store->sb_page = NULL; while (pages--) if (map[pages] != sb_page) /* 0 is sb_page, release it below */ free_buffers(map[pages]); kfree(map); - kfree(attr); + kfree(store->filemap_attr); if (sb_page) free_buffers(sb_page); -} - -static void bitmap_file_put(struct bitmap *bitmap) -{ - struct file *file; - - file = bitmap->storage.file; - bitmap->storage.file = NULL; - - if (file) - wait_event(bitmap->write_wait, - atomic_read(&bitmap->pending_writes)==0); - bitmap_file_unmap(bitmap); if (file) { struct inode *inode = file->f_path.dentry->d_inode; @@ -1610,8 +1592,12 @@ static void bitmap_free(struct bitmap *bitmap) if (!bitmap) /* there was no bitmap */ return; - /* release the bitmap file and kill the daemon */ - bitmap_file_put(bitmap); + /* Shouldn't be needed - but just in case.... */ + wait_event(bitmap->write_wait, + atomic_read(&bitmap->pending_writes) == 0); + + /* release the bitmap file */ + bitmap_file_unmap(&bitmap->storage); bp = bitmap->bp; pages = bitmap->pages; -- cgit v1.2.3-70-g09d2 From bdfd1140731a67c74fd74814f222c8078171adcd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:22 +1000 Subject: md/bitmap: make _page_attr bitops atomic. Using e.g. set_bit instead of __set_bit and using test_and_clear_bit allow us to remove some locking and contract other locked ranges. It is rare that we set or clear a lot of these bits, so gain should outweigh any cost. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 55 ++++++++++++++++++++++------------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index d2ab7d3df3e..2e2f53cd5b2 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -799,21 +799,27 @@ enum bitmap_page_attr { static inline void set_page_attr(struct bitmap *bitmap, int pnum, enum bitmap_page_attr attr) { - __set_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); + set_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); } static inline void clear_page_attr(struct bitmap *bitmap, int pnum, enum bitmap_page_attr attr) { - __clear_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); + clear_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); } -static inline unsigned long test_page_attr(struct bitmap *bitmap, int pnum, - enum bitmap_page_attr attr) +static inline int test_page_attr(struct bitmap *bitmap, int pnum, + enum bitmap_page_attr attr) { return test_bit((pnum<<2) + attr, bitmap->storage.filemap_attr); } +static inline int test_and_clear_page_attr(struct bitmap *bitmap, int pnum, + enum bitmap_page_attr attr) +{ + return test_and_clear_bit((pnum<<2) + attr, + bitmap->storage.filemap_attr); +} /* * bitmap_file_set_bit -- called before performing a write to the md device * to set (and eventually sync) a particular bit in the bitmap file @@ -884,23 +890,17 @@ void bitmap_unplug(struct bitmap *bitmap) /* look at each page to see if there are any set bits that need to be * flushed out to disk */ for (i = 0; i < bitmap->storage.file_pages; i++) { - spin_lock_irq(&bitmap->lock); - if (!bitmap->storage.filemap) { - spin_unlock_irq(&bitmap->lock); + if (!bitmap->storage.filemap) return; - } - dirty = test_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); - need_write = test_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); - clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); - clear_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); - if (dirty || need_write) + dirty = test_and_clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); + need_write = test_and_clear_page_attr(bitmap, i, + BITMAP_PAGE_NEEDWRITE); + if (dirty || need_write) { clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING); + write_page(bitmap, bitmap->storage.filemap[i], 0); + } if (dirty) wait = 1; - spin_unlock_irq(&bitmap->lock); - - if (dirty || need_write) - write_page(bitmap, bitmap->storage.filemap[i], 0); } if (wait) { /* if any writes were performed, we need to wait on them */ if (bitmap->storage.file) @@ -1062,12 +1062,10 @@ void bitmap_write_all(struct bitmap *bitmap) /* Only one copy, so nothing needed */ return; - spin_lock_irq(&bitmap->lock); for (i = 0; i < bitmap->storage.file_pages; i++) set_page_attr(bitmap, i, BITMAP_PAGE_NEEDWRITE); bitmap->allclean = 0; - spin_unlock_irq(&bitmap->lock); } static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) @@ -1128,15 +1126,11 @@ void bitmap_daemon_work(struct mddev *mddev) * So set NEEDWRITE now, then after we make any last-minute changes * we will write it. */ - spin_lock_irq(&bitmap->lock); for (j = 0; j < bitmap->storage.file_pages; j++) - if (test_page_attr(bitmap, j, - BITMAP_PAGE_PENDING)) { + if (test_and_clear_page_attr(bitmap, j, + BITMAP_PAGE_PENDING)) set_page_attr(bitmap, j, BITMAP_PAGE_NEEDWRITE); - clear_page_attr(bitmap, j, - BITMAP_PAGE_PENDING); - } if (bitmap->need_sync && mddev->bitmap_info.external == 0) { @@ -1156,6 +1150,7 @@ void bitmap_daemon_work(struct mddev *mddev) /* Now look at the bitmap counters and if any are '2' or '1', * decrement and handle accordingly. */ + spin_lock_irq(&bitmap->lock); nextpage = 0; for (j = 0; j < bitmap->chunks; j++) { bitmap_counter_t *bmc; @@ -1188,6 +1183,7 @@ void bitmap_daemon_work(struct mddev *mddev) bitmap->allclean = 0; } } + spin_unlock_irq(&bitmap->lock); /* Now start writeout on any page in NEEDWRITE that isn't DIRTY. * DIRTY pages need to be written by bitmap_unplug so it can wait @@ -1206,16 +1202,11 @@ void bitmap_daemon_work(struct mddev *mddev) BITMAP_PAGE_DIRTY)) /* bitmap_unplug will handle the rest */ break; - if (test_page_attr(bitmap, j, - BITMAP_PAGE_NEEDWRITE)) { - clear_page_attr(bitmap, j, - BITMAP_PAGE_NEEDWRITE); - spin_unlock_irq(&bitmap->lock); + if (test_and_clear_page_attr(bitmap, j, + BITMAP_PAGE_NEEDWRITE)) { write_page(bitmap, bitmap->storage.filemap[j], 0); - spin_lock_irq(&bitmap->lock); } } - spin_unlock_irq(&bitmap->lock); done: if (bitmap->allclean == 0) -- cgit v1.2.3-70-g09d2 From 63c68268b2fc63f7f612dfebecb5c9cbbd3ebeaf Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:23 +1000 Subject: md/bitmap: make bitmap bitops atomic. This allows us to remove spinlock protection which is more heavy-weight than simple atomics. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2e2f53cd5b2..7c3c1c58ff1 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -844,7 +844,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags)) set_bit(bit, kaddr); else - __set_bit_le(bit, kaddr); + test_and_set_bit_le(bit, kaddr); kunmap_atomic(kaddr); pr_debug("set file bit %lu page %lu\n", bit, page->index); /* record page number so it gets flushed to disk when unplug occurs */ @@ -866,7 +866,7 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags)) clear_bit(bit, paddr); else - __clear_bit_le(bit, paddr); + test_and_clear_bit_le(bit, paddr); kunmap_atomic(paddr); if (!test_page_attr(bitmap, page->index, BITMAP_PAGE_NEEDWRITE)) { set_page_attr(bitmap, page->index, BITMAP_PAGE_PENDING); @@ -1536,9 +1536,7 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e) for (chunk = s; chunk <= e; chunk++) { sector_t sec = (sector_t)chunk << bitmap->chunkshift; bitmap_set_memory_bits(bitmap, sec, 1); - spin_lock_irq(&bitmap->lock); bitmap_file_set_bit(bitmap, sec); - spin_unlock_irq(&bitmap->lock); if (sec < bitmap->mddev->recovery_cp) /* We are asserting that the array is dirty, * so move the recovery_cp address back so -- cgit v1.2.3-70-g09d2 From 40cffcc0e8f9f6e295630cb8b8d58a13baa6c7f9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:24 +1000 Subject: md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap' The new "struct bitmap_counts" contains all the fields that are related to counting the number of active writes in each bitmap chunk. Having this separate will make it easier to change the chunksize or overall size of a bitmap atomically. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 138 +++++++++++++++++++++++++++------------------------- drivers/md/bitmap.h | 23 +++++---- 2 files changed, 84 insertions(+), 77 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 7c3c1c58ff1..c100a47bc15 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -45,7 +45,7 @@ static inline char *bmname(struct bitmap *bitmap) * if we find our page, we increment the page's refcount so that it stays * allocated while we're using it */ -static int bitmap_checkpage(struct bitmap *bitmap, +static int bitmap_checkpage(struct bitmap_counts *bitmap, unsigned long page, int create) __releases(bitmap->lock) __acquires(bitmap->lock) @@ -76,8 +76,7 @@ __acquires(bitmap->lock) spin_lock_irq(&bitmap->lock); if (mappage == NULL) { - pr_debug("%s: bitmap map page allocation failed, hijacking\n", - bmname(bitmap)); + pr_debug("md/bitmap: map page allocation failed, hijacking\n"); /* failed - set the hijacked flag so that we can use the * pointer as a counter */ if (!bitmap->bp[page].map) @@ -100,7 +99,7 @@ __acquires(bitmap->lock) /* if page is completely empty, put it back on the free list, or dealloc it */ /* if page was hijacked, unmark the flag so it might get alloced next time */ /* Note: lock should be held when calling this */ -static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page) +static void bitmap_checkfree(struct bitmap_counts *bitmap, unsigned long page) { char *ptr; @@ -832,7 +831,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) unsigned long bit; struct page *page; void *kaddr; - unsigned long chunk = block >> bitmap->chunkshift; + unsigned long chunk = block >> bitmap->counts.chunkshift; page = filemap_get_page(&bitmap->storage, chunk); if (!page) @@ -856,7 +855,7 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block) unsigned long bit; struct page *page; void *paddr; - unsigned long chunk = block >> bitmap->chunkshift; + unsigned long chunk = block >> bitmap->counts.chunkshift; page = filemap_get_page(&bitmap->storage, chunk); if (!page) @@ -938,7 +937,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) void *paddr; struct bitmap_storage *store = &bitmap->storage; - chunks = bitmap->chunks; + chunks = bitmap->counts.chunks; file = store->file; if (!file && !bitmap->mddev->bitmap_info.offset) { @@ -947,10 +946,10 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) store->file_pages = 0; for (i = 0; i < chunks ; i++) { /* if the disk bit is set, set the memory bit */ - int needed = ((sector_t)(i+1) << (bitmap->chunkshift) + int needed = ((sector_t)(i+1) << (bitmap->counts.chunkshift) >= start); bitmap_set_memory_bits(bitmap, - (sector_t)i << bitmap->chunkshift, + (sector_t)i << bitmap->counts.chunkshift, needed); } return 0; @@ -1026,10 +1025,10 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) kunmap_atomic(paddr); if (b) { /* if the disk bit is set, set the memory bit */ - int needed = ((sector_t)(i+1) << bitmap->chunkshift + int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift >= start); bitmap_set_memory_bits(bitmap, - (sector_t)i << bitmap->chunkshift, + (sector_t)i << bitmap->counts.chunkshift, needed); bit_cnt++; } @@ -1068,7 +1067,8 @@ void bitmap_write_all(struct bitmap *bitmap) bitmap->allclean = 0; } -static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) +static void bitmap_count_page(struct bitmap_counts *bitmap, + sector_t offset, int inc) { sector_t chunk = offset >> bitmap->chunkshift; unsigned long page = chunk >> PAGE_COUNTER_SHIFT; @@ -1076,7 +1076,7 @@ static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) bitmap_checkfree(bitmap, page); } -static void bitmap_set_pending(struct bitmap *bitmap, sector_t offset) +static void bitmap_set_pending(struct bitmap_counts *bitmap, sector_t offset) { sector_t chunk = offset >> bitmap->chunkshift; unsigned long page = chunk >> PAGE_COUNTER_SHIFT; @@ -1086,7 +1086,7 @@ static void bitmap_set_pending(struct bitmap *bitmap, sector_t offset) bp->pending = 1; } -static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, +static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap, sector_t offset, sector_t *blocks, int create); @@ -1101,6 +1101,7 @@ void bitmap_daemon_work(struct mddev *mddev) unsigned long j; unsigned long nextpage; sector_t blocks; + struct bitmap_counts *counts; /* Use a mutex to guard daemon_work against * bitmap_destroy. @@ -1150,21 +1151,22 @@ void bitmap_daemon_work(struct mddev *mddev) /* Now look at the bitmap counters and if any are '2' or '1', * decrement and handle accordingly. */ - spin_lock_irq(&bitmap->lock); + counts = &bitmap->counts; + spin_lock_irq(&counts->lock); nextpage = 0; - for (j = 0; j < bitmap->chunks; j++) { + for (j = 0; j < counts->chunks; j++) { bitmap_counter_t *bmc; - sector_t block = (sector_t)j << bitmap->chunkshift; + sector_t block = (sector_t)j << counts->chunkshift; if (j == nextpage) { nextpage += PAGE_COUNTER_RATIO; - if (!bitmap->bp[j >> PAGE_COUNTER_SHIFT].pending) { + if (!counts->bp[j >> PAGE_COUNTER_SHIFT].pending) { j |= PAGE_COUNTER_MASK; continue; } - bitmap->bp[j >> PAGE_COUNTER_SHIFT].pending = 0; + counts->bp[j >> PAGE_COUNTER_SHIFT].pending = 0; } - bmc = bitmap_get_counter(bitmap, + bmc = bitmap_get_counter(counts, block, &blocks, 0); @@ -1175,15 +1177,15 @@ void bitmap_daemon_work(struct mddev *mddev) if (*bmc == 1 && !bitmap->need_sync) { /* We can clear the bit */ *bmc = 0; - bitmap_count_page(bitmap, block, -1); + bitmap_count_page(counts, block, -1); bitmap_file_clear_bit(bitmap, block); } else if (*bmc && *bmc <= 2) { *bmc = 1; - bitmap_set_pending(bitmap, block); + bitmap_set_pending(counts, block); bitmap->allclean = 0; } } - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&counts->lock); /* Now start writeout on any page in NEEDWRITE that isn't DIRTY. * DIRTY pages need to be written by bitmap_unplug so it can wait @@ -1215,7 +1217,7 @@ void bitmap_daemon_work(struct mddev *mddev) mutex_unlock(&mddev->bitmap_info.mutex); } -static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, +static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap, sector_t offset, sector_t *blocks, int create) __releases(bitmap->lock) @@ -1277,10 +1279,10 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect sector_t blocks; bitmap_counter_t *bmc; - spin_lock_irq(&bitmap->lock); - bmc = bitmap_get_counter(bitmap, offset, &blocks, 1); + spin_lock_irq(&bitmap->counts.lock); + bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 1); if (!bmc) { - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&bitmap->counts.lock); return 0; } @@ -1292,7 +1294,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect */ prepare_to_wait(&bitmap->overflow_wait, &__wait, TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&bitmap->counts.lock); io_schedule(); finish_wait(&bitmap->overflow_wait, &__wait); continue; @@ -1301,7 +1303,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect switch (*bmc) { case 0: bitmap_file_set_bit(bitmap, offset); - bitmap_count_page(bitmap, offset, 1); + bitmap_count_page(&bitmap->counts, offset, 1); /* fall through */ case 1: *bmc = 2; @@ -1309,7 +1311,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect (*bmc)++; - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&bitmap->counts.lock); offset += blocks; if (sectors > blocks) @@ -1339,10 +1341,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto unsigned long flags; bitmap_counter_t *bmc; - spin_lock_irqsave(&bitmap->lock, flags); - bmc = bitmap_get_counter(bitmap, offset, &blocks, 0); + spin_lock_irqsave(&bitmap->counts.lock, flags); + bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 0); if (!bmc) { - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irqrestore(&bitmap->counts.lock, flags); return; } @@ -1361,10 +1363,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto (*bmc)--; if (*bmc <= 2) { - bitmap_set_pending(bitmap, offset); + bitmap_set_pending(&bitmap->counts, offset); bitmap->allclean = 0; } - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irqrestore(&bitmap->counts.lock, flags); offset += blocks; if (sectors > blocks) sectors -= blocks; @@ -1383,8 +1385,8 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks = 1024; return 1; /* always resync if no bitmap */ } - spin_lock_irq(&bitmap->lock); - bmc = bitmap_get_counter(bitmap, offset, blocks, 0); + spin_lock_irq(&bitmap->counts.lock); + bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0); rv = 0; if (bmc) { /* locked */ @@ -1398,7 +1400,7 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t } } } - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&bitmap->counts.lock); return rv; } @@ -1435,8 +1437,8 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i *blocks = 1024; return; } - spin_lock_irqsave(&bitmap->lock, flags); - bmc = bitmap_get_counter(bitmap, offset, blocks, 0); + spin_lock_irqsave(&bitmap->counts.lock, flags); + bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0); if (bmc == NULL) goto unlock; /* locked */ @@ -1447,13 +1449,13 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i *bmc |= NEEDED_MASK; else { if (*bmc <= 2) { - bitmap_set_pending(bitmap, offset); + bitmap_set_pending(&bitmap->counts, offset); bitmap->allclean = 0; } } } unlock: - spin_unlock_irqrestore(&bitmap->lock, flags); + spin_unlock_irqrestore(&bitmap->counts.lock, flags); } EXPORT_SYMBOL(bitmap_end_sync); @@ -1493,7 +1495,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) bitmap->mddev->curr_resync_completed = sector; set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags); - sector &= ~((1ULL << bitmap->chunkshift) - 1); + sector &= ~((1ULL << bitmap->counts.chunkshift) - 1); s = 0; while (s < sector && s < bitmap->mddev->resync_max_sectors) { bitmap_end_sync(bitmap, s, &blocks, 0); @@ -1513,19 +1515,19 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n sector_t secs; bitmap_counter_t *bmc; - spin_lock_irq(&bitmap->lock); - bmc = bitmap_get_counter(bitmap, offset, &secs, 1); + spin_lock_irq(&bitmap->counts.lock); + bmc = bitmap_get_counter(&bitmap->counts, offset, &secs, 1); if (!bmc) { - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&bitmap->counts.lock); return; } if (!*bmc) { *bmc = 2 | (needed ? NEEDED_MASK : 0); - bitmap_count_page(bitmap, offset, 1); - bitmap_set_pending(bitmap, offset); + bitmap_count_page(&bitmap->counts, offset, 1); + bitmap_set_pending(&bitmap->counts, offset); bitmap->allclean = 0; } - spin_unlock_irq(&bitmap->lock); + spin_unlock_irq(&bitmap->counts.lock); } /* dirty the memory and file bits for bitmap chunks "s" to "e" */ @@ -1534,7 +1536,7 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e) unsigned long chunk; for (chunk = s; chunk <= e; chunk++) { - sector_t sec = (sector_t)chunk << bitmap->chunkshift; + sector_t sec = (sector_t)chunk << bitmap->counts.chunkshift; bitmap_set_memory_bits(bitmap, sec, 1); bitmap_file_set_bit(bitmap, sec); if (sec < bitmap->mddev->recovery_cp) @@ -1588,8 +1590,8 @@ static void bitmap_free(struct bitmap *bitmap) /* release the bitmap file */ bitmap_file_unmap(&bitmap->storage); - bp = bitmap->bp; - pages = bitmap->pages; + bp = bitmap->counts.bp; + pages = bitmap->counts.pages; /* free all allocated memory */ @@ -1642,7 +1644,7 @@ int bitmap_create(struct mddev *mddev) if (!bitmap) return -ENOMEM; - spin_lock_init(&bitmap->lock); + spin_lock_init(&bitmap->counts.lock); atomic_set(&bitmap->pending_writes, 0); init_waitqueue_head(&bitmap->write_wait); init_waitqueue_head(&bitmap->overflow_wait); @@ -1689,27 +1691,28 @@ int bitmap_create(struct mddev *mddev) goto error; bitmap->daemon_lastrun = jiffies; - bitmap->chunkshift = (ffz(~mddev->bitmap_info.chunksize) + bitmap->counts.chunkshift = (ffz(~mddev->bitmap_info.chunksize) - BITMAP_BLOCK_SHIFT); - chunks = (blocks + (1 << bitmap->chunkshift) - 1) >> - bitmap->chunkshift; + chunks = (blocks + (1 << bitmap->counts.chunkshift) - 1) >> + bitmap->counts.chunkshift; pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO; BUG_ON(!pages); - bitmap->chunks = chunks; - bitmap->pages = pages; - bitmap->missing_pages = pages; + bitmap->counts.chunks = chunks; + bitmap->counts.pages = pages; + bitmap->counts.missing_pages = pages; - bitmap->bp = kzalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL); + bitmap->counts.bp = kzalloc(pages * sizeof(*bitmap->counts.bp), + GFP_KERNEL); err = -ENOMEM; - if (!bitmap->bp) + if (!bitmap->counts.bp) goto error; if (file || mddev->bitmap_info.offset) { - err = bitmap_storage_alloc(&bitmap->storage, bitmap->chunks, + err = bitmap_storage_alloc(&bitmap->storage, bitmap->counts.chunks, !mddev->bitmap_info.external); if (err) goto error; @@ -1781,17 +1784,19 @@ EXPORT_SYMBOL_GPL(bitmap_load); void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) { unsigned long chunk_kb; + struct bitmap_counts *counts; if (!bitmap) return; - spin_lock_irq(&bitmap->lock); + counts = &bitmap->counts; + chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10; seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], " "%lu%s chunk", - bitmap->pages - bitmap->missing_pages, - bitmap->pages, - (bitmap->pages - bitmap->missing_pages) + counts->pages - counts->missing_pages, + counts->pages, + (counts->pages - counts->missing_pages) << (PAGE_SHIFT - 10), chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize, chunk_kb ? "KB" : "B"); @@ -1801,7 +1806,6 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) } seq_printf(seq, "\n"); - spin_unlock_irq(&bitmap->lock); } static ssize_t diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index e2d999a62ba..6bde180e987 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -172,22 +172,25 @@ struct bitmap_page { /* the main bitmap structure - one per mddev */ struct bitmap { - struct bitmap_page *bp; - unsigned long pages; /* total number of pages in the bitmap */ - unsigned long missing_pages; /* number of pages not yet allocated */ - struct mddev *mddev; /* the md device that the bitmap is for */ + struct bitmap_counts { + spinlock_t lock; + struct bitmap_page *bp; + unsigned long pages; /* total number of pages + * in the bitmap */ + unsigned long missing_pages; /* number of pages + * not yet allocated */ + unsigned long chunkshift; /* chunksize = 2^chunkshift + * (for bitops) */ + unsigned long chunks; /* Total number of data + * chunks for the array */ + } counts; - /* bitmap chunksize -- how much data does each bit represent? */ - unsigned long chunkshift; /* chunksize = 2^(chunkshift+9) (for bitops) */ - unsigned long chunks; /* total number of data chunks for the array */ + struct mddev *mddev; /* the md device that the bitmap is for */ __u64 events_cleared; int need_sync; - /* bitmap spinlock */ - spinlock_t lock; - struct bitmap_storage { struct file *file; /* backing disk file */ struct page *sb_page; /* cached copy of the bitmap -- cgit v1.2.3-70-g09d2 From 15702d7fb6e7a6baf5a04286a227b0ad2fe4a03f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:25 +1000 Subject: md/bitmap: use DIV_ROUND_UP instead of open-code Also take the opportunity to simplify CHUNK_BLOCK_RATIO. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index c100a47bc15..bc552bbad83 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1694,9 +1694,8 @@ int bitmap_create(struct mddev *mddev) bitmap->counts.chunkshift = (ffz(~mddev->bitmap_info.chunksize) - BITMAP_BLOCK_SHIFT); - chunks = (blocks + (1 << bitmap->counts.chunkshift) - 1) >> - bitmap->counts.chunkshift; - pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO; + chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << bitmap->counts.chunkshift); + pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO); BUG_ON(!pages); -- cgit v1.2.3-70-g09d2 From d60b479d177a5735b6b4db6ee5280ef6653f50e7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:25 +1000 Subject: 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 --- drivers/md/bitmap.c | 199 ++++++++++++++++++++++++++++++++++++++++++++-------- drivers/md/bitmap.h | 3 + 2 files changed, 172 insertions(+), 30 deletions(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index bc552bbad83..a35561f8f57 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -698,7 +698,7 @@ static int bitmap_storage_alloc(struct bitmap_storage *store, return -ENOMEM; if (with_super && !store->sb_page) { - store->sb_page = alloc_page(GFP_KERNEL); + store->sb_page = alloc_page(GFP_KERNEL|__GFP_ZERO); if (store->sb_page == NULL) return -ENOMEM; store->sb_page->index = 0; @@ -709,7 +709,7 @@ static int bitmap_storage_alloc(struct bitmap_storage *store, pnum = 1; } for ( ; pnum < num_pages; pnum++) { - store->filemap[pnum] = alloc_page(GFP_KERNEL); + store->filemap[pnum] = alloc_page(GFP_KERNEL|__GFP_ZERO); if (!store->filemap[pnum]) { store->file_pages = pnum; return -ENOMEM; @@ -1630,8 +1630,6 @@ int bitmap_create(struct mddev *mddev) { struct bitmap *bitmap; sector_t blocks = mddev->resync_max_sectors; - unsigned long chunks; - unsigned long pages; struct file *file = mddev->bitmap_info.file; int err; struct sysfs_dirent *bm = NULL; @@ -1691,37 +1689,14 @@ int bitmap_create(struct mddev *mddev) goto error; bitmap->daemon_lastrun = jiffies; - bitmap->counts.chunkshift = (ffz(~mddev->bitmap_info.chunksize) - - BITMAP_BLOCK_SHIFT); - - chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << bitmap->counts.chunkshift); - pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO); - - BUG_ON(!pages); - - bitmap->counts.chunks = chunks; - bitmap->counts.pages = pages; - bitmap->counts.missing_pages = pages; - - bitmap->counts.bp = kzalloc(pages * sizeof(*bitmap->counts.bp), - GFP_KERNEL); - - err = -ENOMEM; - if (!bitmap->counts.bp) + err = bitmap_resize(bitmap, blocks, mddev->bitmap_info.chunksize, 1); + if (err) goto error; - if (file || mddev->bitmap_info.offset) { - err = bitmap_storage_alloc(&bitmap->storage, bitmap->counts.chunks, - !mddev->bitmap_info.external); - if (err) - goto error; - } printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", - pages, bmname(bitmap)); + bitmap->counts.pages, bmname(bitmap)); mddev->bitmap = bitmap; - - return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0; error: @@ -1807,6 +1782,170 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) seq_printf(seq, "\n"); } +int bitmap_resize(struct bitmap *bitmap, sector_t blocks, + int chunksize, int init) +{ + /* If chunk_size is 0, choose an appropriate chunk size. + * Then possibly allocate new storage space. + * Then quiesce, copy bits, replace bitmap, and re-start + * + * This function is called both to set up the initial bitmap + * and to resize the bitmap while the array is active. + * If this happens as a result of the array being resized, + * chunksize will be zero, and we need to choose a suitable + * chunksize, otherwise we use what we are given. + */ + struct bitmap_storage store; + struct bitmap_counts old_counts; + unsigned long chunks; + sector_t block; + sector_t old_blocks, new_blocks; + int chunkshift; + int ret = 0; + long pages; + struct bitmap_page *new_bp; + + if (chunksize == 0) { + /* If there is enough space, leave the chunk size unchanged, + * else increase by factor of two until there is enough space. + */ + long bytes; + long space = bitmap->mddev->bitmap_info.space; + + if (space == 0) { + /* We don't know how much space there is, so limit + * to current size - in sectors. + */ + bytes = DIV_ROUND_UP(bitmap->counts.chunks, 8); + if (!bitmap->mddev->bitmap_info.external) + bytes += sizeof(bitmap_super_t); + space = DIV_ROUND_UP(bytes, 512); + bitmap->mddev->bitmap_info.space = space; + } + chunkshift = bitmap->counts.chunkshift; + chunkshift--; + do { + /* 'chunkshift' is shift from block size to chunk size */ + chunkshift++; + chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift); + bytes = DIV_ROUND_UP(chunks, 8); + if (!bitmap->mddev->bitmap_info.external) + bytes += sizeof(bitmap_super_t); + } while (bytes > (space << 9)); + } else + chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT; + + chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift); + memset(&store, 0, sizeof(store)); + if (bitmap->mddev->bitmap_info.offset || bitmap->mddev->bitmap_info.file) + ret = bitmap_storage_alloc(&store, chunks, + !bitmap->mddev->bitmap_info.external); + if (ret) + goto err; + + pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO); + + new_bp = kzalloc(pages * sizeof(*new_bp), GFP_KERNEL); + ret = -ENOMEM; + if (!new_bp) { + bitmap_file_unmap(&store); + goto err; + } + + if (!init) + bitmap->mddev->pers->quiesce(bitmap->mddev, 1); + + store.file = bitmap->storage.file; + bitmap->storage.file = NULL; + + if (store.sb_page && bitmap->storage.sb_page) + memcpy(page_address(store.sb_page), + page_address(bitmap->storage.sb_page), + sizeof(bitmap_super_t)); + bitmap_file_unmap(&bitmap->storage); + bitmap->storage = store; + + old_counts = bitmap->counts; + bitmap->counts.bp = new_bp; + bitmap->counts.pages = pages; + bitmap->counts.missing_pages = pages; + bitmap->counts.chunkshift = chunkshift; + bitmap->counts.chunks = chunks; + bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift + + BITMAP_BLOCK_SHIFT); + + blocks = min(old_counts.chunks << old_counts.chunkshift, + chunks << chunkshift); + + spin_lock_irq(&bitmap->counts.lock); + for (block = 0; block < blocks; ) { + bitmap_counter_t *bmc_old, *bmc_new; + int set; + + bmc_old = bitmap_get_counter(&old_counts, block, + &old_blocks, 0); + set = bmc_old && NEEDED(*bmc_old); + + if (set) { + bmc_new = bitmap_get_counter(&bitmap->counts, block, + &new_blocks, 1); + if (*bmc_new == 0) { + /* need to set on-disk bits too. */ + sector_t end = block + new_blocks; + sector_t start = block >> chunkshift; + start <<= chunkshift; + while (start < end) { + bitmap_file_set_bit(bitmap, block); + start += 1 << chunkshift; + } + *bmc_new = 2; + bitmap_count_page(&bitmap->counts, + block, 1); + bitmap_set_pending(&bitmap->counts, + block); + } + *bmc_new |= NEEDED_MASK; + if (new_blocks < old_blocks) + old_blocks = new_blocks; + } + block += old_blocks; + } + + if (!init) { + int i; + while (block < (chunks << chunkshift)) { + bitmap_counter_t *bmc; + bmc = bitmap_get_counter(&bitmap->counts, block, + &new_blocks, 1); + if (bmc) { + /* new space. It needs to be resynced, so + * we set NEEDED_MASK. + */ + if (*bmc == 0) { + *bmc = NEEDED_MASK | 2; + bitmap_count_page(&bitmap->counts, + block, 1); + bitmap_set_pending(&bitmap->counts, + block); + } + } + block += new_blocks; + } + for (i = 0; i < bitmap->storage.file_pages; i++) + set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); + } + spin_unlock_irq(&bitmap->counts.lock); + + if (!init) { + bitmap_unplug(bitmap); + bitmap->mddev->pers->quiesce(bitmap->mddev, 0); + } + ret = 0; +err: + return ret; +} +EXPORT_SYMBOL_GPL(bitmap_resize); + static ssize_t location_show(struct mddev *mddev, char *page) { diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 6bde180e987..04dcde3871b 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -255,6 +255,9 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); void bitmap_unplug(struct bitmap *bitmap); void bitmap_daemon_work(struct mddev *mddev); + +int bitmap_resize(struct bitmap *bitmap, sector_t blocks, + int chunksize, int init); #endif #endif -- cgit v1.2.3-70-g09d2 From b81a040481233e5171cb3fbc62f44636d5ea18b2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:26 +1000 Subject: md/bitmap: make sure reshape request are reflected in superblock. As a reshape may change the sync_size and/or chunk_size, we need to update these whenever we write out the bitmap superblock. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index a35561f8f57..8f681da0027 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -420,6 +420,9 @@ void bitmap_update_sb(struct bitmap *bitmap) /* Just in case these have been changed via sysfs: */ sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ); sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind); + /* This might have been changed by a reshape */ + sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors); + sb->chunksize = cpu_to_le32(bitmap->mddev->bitmap_info.chunksize); kunmap_atomic(sb); write_page(bitmap, bitmap->storage.sb_page, 1); } -- cgit v1.2.3-70-g09d2 From 1dff2b87a34a1ac1d1898ea109bf97ed396aca53 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 22 May 2012 13:55:34 +1000 Subject: md/bitmap: record the space available for the bitmap in the superblock. Now that bitmaps can grow and shrink it is best if we record how much space is available. This means that when we reduce the size of the bitmap we won't "lose" the space for late when we might want to increase the size of the bitmap again. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 7 +++++++ drivers/md/bitmap.h | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/md/bitmap.c') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 8f681da0027..15dbe03117e 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -423,6 +423,8 @@ void bitmap_update_sb(struct bitmap *bitmap) /* This might have been changed by a reshape */ sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors); sb->chunksize = cpu_to_le32(bitmap->mddev->bitmap_info.chunksize); + sb->sectors_reserved = cpu_to_le32(bitmap->mddev-> + bitmap_info.space); kunmap_atomic(sb); write_page(bitmap, bitmap->storage.sb_page, 1); } @@ -536,6 +538,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) bitmap_super_t *sb; unsigned long chunksize, daemon_sleep, write_behind; unsigned long long events; + unsigned long sectors_reserved = 0; int err = -EINVAL; struct page *sb_page; @@ -573,6 +576,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) chunksize = le32_to_cpu(sb->chunksize); daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ; write_behind = le32_to_cpu(sb->write_behind); + sectors_reserved = le32_to_cpu(sb->sectors_reserved); /* verify that the bitmap-specific fields are valid */ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) @@ -633,6 +637,9 @@ out_no_sb: bitmap->mddev->bitmap_info.chunksize = chunksize; bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep; bitmap->mddev->bitmap_info.max_write_behind = write_behind; + if (bitmap->mddev->bitmap_info.space == 0 || + bitmap->mddev->bitmap_info.space > sectors_reserved) + bitmap->mddev->bitmap_info.space = sectors_reserved; if (err) bitmap_print_sb(bitmap); return err; diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 04dcde3871b..df4aeb6ac6f 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -128,8 +128,10 @@ typedef struct bitmap_super_s { __le32 chunksize; /* 52 the bitmap chunk size in bytes */ __le32 daemon_sleep; /* 56 seconds between disk flushes */ __le32 write_behind; /* 60 number of outstanding write-behind writes */ + __le32 sectors_reserved; /* 64 number of 512-byte sectors that are + * reserved for the bitmap. */ - __u8 pad[256 - 64]; /* set to zero */ + __u8 pad[256 - 68]; /* set to zero */ } bitmap_super_t; /* notes: -- cgit v1.2.3-70-g09d2