From: NeilBrown <neilb@suse.de>
To: linux-raid@vger.kernel.org
Subject: [md PATCH 20/24] md/bitmap: add bitmap_resize function to allow bitmap resizing.
Date: Tue, 17 Apr 2012 18:43:42 +1000 [thread overview]
Message-ID: <20120417084342.6433.10586.stgit@notabene.brown> (raw)
In-Reply-To: <20120417084324.6433.68345.stgit@notabene.brown>
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.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 191 +++++++++++++++++++++++++++++++++++++++++++--------
drivers/md/bitmap.h | 3 +
2 files changed, 165 insertions(+), 29 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index bcd5107..dc5ec72 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -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,38 +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);
-
- /* now that chunksize and chunkshift are set, we can use these macros */
- chunks = DIV_ROUND_UP(blocks, CHUNK_BLOCK_RATIO(bitmap));
- 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:
@@ -1808,6 +1782,165 @@ 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;
+ sector_t chunks;
+ sector_t block;
+ long 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.
+ */
+ space = DIV_ROUND_UP(bitmap->counts.chunks, 8 * 512);
+ }
+ chunkshift = bitmap->counts.chunkshift;
+ chunkshift--;
+ do {
+ /* 'chunkshift' is shift from block size to chunk size */
+ chunkshift++;
+ chunks = DIV_ROUND_UP(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(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;
+}
+
static ssize_t
location_show(struct mddev *mddev, char *page)
{
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index 530be4d..fd723d7 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -258,6 +258,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
next prev parent reply other threads:[~2012-04-17 8:43 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
2012-04-17 8:43 ` [md PATCH 02/24] md/bitmap: add new 'space' attribute for bitmaps NeilBrown
2012-04-17 8:43 ` [md PATCH 01/24] md/bitmap: disentangle two different 'pending' flags NeilBrown
2012-04-17 8:43 ` [md PATCH 06/24] md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct NeilBrown
2012-04-17 8:43 ` [md PATCH 03/24] md/bitmap: allow a bitmap with no backing storage NeilBrown
2012-04-17 8:43 ` [md PATCH 05/24] md/bitmap: change *_page_attr() to take a page number, not a page NeilBrown
2012-04-17 8:43 ` [md PATCH 07/24] md/bitmap: store bytes in file rather than just in last page NeilBrown
2012-04-17 8:43 ` [md PATCH 08/24] md/bitmap: separate bitmap file allocation to its own function NeilBrown
2012-04-17 8:43 ` [md PATCH 09/24] md/bitmap: move storage allocation from bitmap_load to bitmap_create NeilBrown
2012-04-17 8:43 ` [md PATCH 04/24] md/bitmap: centralise allocation of bitmap file pages NeilBrown
2012-04-17 8:43 ` [md PATCH 10/24] md/bitmap: remove bitmap_mask_state NeilBrown
2012-04-17 8:43 ` [md PATCH 13/24] md/bitmap: convert some spin_lock_irqsave to spin_lock_irq NeilBrown
2012-04-17 8:43 ` [md PATCH 16/24] md/bitmap: make _page_attr bitops atomic NeilBrown
2012-04-17 8:43 ` [md PATCH 11/24] md/bitmap: remove single-bit manipulation on sb->state NeilBrown
2012-04-17 8:43 ` [md PATCH 14/24] md/bitmap: remove async freeing of bitmap file NeilBrown
2012-04-17 8:43 ` [md PATCH 12/24] md/bitmap: use set_bit, test_bit, etc for operation on bitmap->flags NeilBrown
2012-04-17 8:43 ` [md PATCH 15/24] md/bitmap: merge bitmap_file_unmap and bitmap_file_put NeilBrown
2012-04-17 8:43 ` NeilBrown [this message]
2012-04-17 8:43 ` [md PATCH 19/24] md/bitmap: use DIV_ROUND_UP instead of open-code NeilBrown
2012-04-17 8:43 ` [md PATCH 23/24] md/raid10: resize bitmap when required during reshape NeilBrown
2012-04-17 8:43 ` [md PATCH 17/24] md/bitmap: make bitmap bitops atomic NeilBrown
2012-04-17 8:43 ` [md PATCH 18/24] md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap' NeilBrown
2012-04-17 8:43 ` [md PATCH 22/24] md: allow array to be resized while bitmap is present NeilBrown
2012-04-17 8:43 ` [md PATCH 21/24] md/bitmap: make sure reshape request are reflected in superblock NeilBrown
2012-04-17 8:43 ` [md PATCH 24/24] md/raid5: Allow reshape while a bitmap is present NeilBrown
2012-04-18 2:07 ` [md PATCH 00/24] Allow bitmaps to be resized Jack Wang
2012-04-18 3:35 ` NeilBrown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120417084342.6433.10586.stgit@notabene.brown \
--to=neilb@suse.de \
--cc=linux-raid@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).