* [md PATCH 00/24] Allow bitmaps to be resized.
@ 2012-04-17 8:43 NeilBrown
2012-04-17 8:43 ` [md PATCH 02/24] md/bitmap: add new 'space' attribute for bitmaps NeilBrown
` (24 more replies)
0 siblings, 25 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
The following series has just been added to my for-next queue
and so should be in 3.5.
git://neil.brown.name/md for-next
git://github.com/neilbrown/linux.git md/for-next
It allows md to resize a bitmap on an active array. This
means that arrays can now be reshaped without first removing the
bitmap. The bitmap is resized in-place.
As always: review and testing would be greatly appreciated.
NeilBrown
---
NeilBrown (24):
md/raid5: Allow reshape while a bitmap is present.
md/raid10: resize bitmap when required during reshape.
md: allow array to be resized while bitmap is present.
md/bitmap: make sure reshape request are reflected in superblock.
md/bitmap: add bitmap_resize function to allow bitmap resizing.
md/bitmap: use DIV_ROUND_UP instead of open-code
md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap'
md/bitmap: make bitmap bitops atomic.
md/bitmap: make _page_attr bitops atomic.
md/bitmap: merge bitmap_file_unmap and bitmap_file_put.
md/bitmap: remove async freeing of bitmap file.
md/bitmap: convert some spin_lock_irqsave to spin_lock_irq
md/bitmap: use set_bit, test_bit, etc for operation on bitmap->flags.
md/bitmap: remove single-bit manipulation on sb->state
md/bitmap: remove bitmap_mask_state
md/bitmap: move storage allocation from bitmap_load to bitmap_create.
md/bitmap: separate bitmap file allocation to its own function.
md/bitmap: store bytes in file rather than just in last page.
md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct.
md/bitmap: change *_page_attr() to take a page number, not a page.
md/bitmap: centralise allocation of bitmap file pages.
md/bitmap: allow a bitmap with no backing storage.
md/bitmap: add new 'space' attribute for bitmaps.
md/bitmap: disentangle two different 'pending' flags.
drivers/md/bitmap.c | 1089 +++++++++++++++++++++++++++++----------------------
drivers/md/bitmap.h | 58 ++-
drivers/md/md.c | 53 ++
drivers/md/md.h | 3
drivers/md/raid1.c | 11 -
drivers/md/raid10.c | 47 +-
drivers/md/raid5.c | 20 +
7 files changed, 754 insertions(+), 527 deletions(-)
--
Signature
^ permalink raw reply [flat|nested] 27+ messages in thread
* [md PATCH 01/24] md/bitmap: disentangle two different 'pending' flags.
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 05/24] md/bitmap: change *_page_attr() to take a page number, not a page NeilBrown
` (22 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 213 +++++++++++++++++++++++++++------------------------
drivers/md/bitmap.h | 7 +-
2 files changed, 118 insertions(+), 102 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 97e73e5..a515e5b 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);
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index 55ca5ae..5563043 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -163,9 +163,14 @@ struct bitmap_page {
*/
unsigned int hijacked:1;
/*
+ * If any counter in this page is '1' or '2' - and so could be
+ * cleared then that page is marked as 'pending'
+ */
+ unsigned int pending:1;
+ /*
* count of dirty bits on the page
*/
- unsigned int count:31;
+ unsigned int count:30;
};
/* the main bitmap structure - one per mddev */
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 02/24] md/bitmap: add new 'space' attribute for bitmaps.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 01/24] md/bitmap: disentangle two different 'pending' flags NeilBrown
` (23 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 39 +++++++++++++++++++++++++++++++++++++++
drivers/md/md.c | 33 +++++++++++++++++++++++++++++++--
drivers/md/md.h | 3 +++
3 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index a515e5b..c894aa4 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1935,6 +1935,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)
{
@@ -2110,6 +2148,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 e763fc1..64b86c7 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<<MD_SB_BITMAP_PRESENT) &&
- mddev->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 3609373..7b4a3c3 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? */
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 03/24] md/bitmap: allow a bitmap with no backing storage.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (2 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 06/24] md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct NeilBrown
` (20 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 136 +++++++++++++++++++++++++++++----------------------
drivers/md/md.c | 5 +-
2 files changed, 79 insertions(+), 62 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index c894aa4..9cc42ba 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);
@@ -1802,6 +1814,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 64b86c7..e84e2e6 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
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 04/24] md/bitmap: centralise allocation of bitmap file pages.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (7 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 13/24] md/bitmap: convert some spin_lock_irqsave to spin_lock_irq NeilBrown
` (15 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 149 +++++++++++++++++++++++----------------------------
1 file changed, 68 insertions(+), 81 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 9cc42ba..5629d4a 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<<inode->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: "
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 05/24] md/bitmap: change *_page_attr() to take a page number, not a page.
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 03/24] md/bitmap: allow a bitmap with no backing storage NeilBrown
` (21 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 55 ++++++++++++++++++++++++---------------------------
1 file changed, 26 insertions(+), 29 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 5629d4a..d655399 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;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 06/24] md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (3 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 03/24] md/bitmap: allow a bitmap with no backing storage NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 08/24] md/bitmap: separate bitmap file allocation to its own function NeilBrown
` (19 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 180 +++++++++++++++++++++++++++------------------------
drivers/md/bitmap.h | 17 +++--
drivers/md/md.c | 9 +--
3 files changed, 110 insertions(+), 96 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index d655399..614062a 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,
@@ -1833,9 +1840,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");
@@ -1959,8 +1966,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 5563043..3cdea44 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -191,12 +191,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 e84e2e6..9524192 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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 07/24] md/bitmap: store bytes in file rather than just in last page.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (5 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 09/24] md/bitmap: move storage allocation from bitmap_load to bitmap_create NeilBrown
` (17 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
This number is more generally useful, and bytes-in-last-page is
easily extracted from it.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 14 +++++++-------
drivers/md/bitmap.h | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 614062a..9221f97 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -203,9 +203,11 @@ 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);
+ size = roundup(last_page_size,
bdev_logical_block_size(bdev));
+ }
/* Just make sure we aren't corrupting data or
* metadata
*/
@@ -973,6 +975,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 +1046,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
@@ -1966,9 +1968,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 3cdea44..987ad3c 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -200,7 +200,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;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 08/24] md/bitmap: separate bitmap file allocation to its own function.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (4 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 07/24] md/bitmap: store bytes in file rather than just in last page NeilBrown
` (18 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
This will allow allocation before swapping in a new bitmap.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 113 ++++++++++++++++++++++++++++++---------------------
1 file changed, 67 insertions(+), 46 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 9221f97..0819ec2 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -714,6 +714,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;
@@ -938,11 +990,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;
@@ -971,53 +1022,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;
@@ -1026,8 +1047,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];
@@ -1081,9 +1102,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;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 09/24] md/bitmap: move storage allocation from bitmap_load to bitmap_create.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (6 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 04/24] md/bitmap: centralise allocation of bitmap file pages NeilBrown
` (16 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
We should allocate memory for the storage-bitmap at create-time, not
load time.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 0819ec2..79dafff 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1030,11 +1030,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)
@@ -1781,6 +1776,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));
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 10/24] md/bitmap: remove bitmap_mask_state
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (9 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 11/24] md/bitmap: remove single-bit manipulation on sb->state NeilBrown
` (13 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 37 +++----------------------------------
1 file changed, 3 insertions(+), 34 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 79dafff..f5f0ec5 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -638,38 +638,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
*/
@@ -826,7 +794,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) {
@@ -1829,7 +1798,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);
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 11/24] md/bitmap: remove single-bit manipulation on sb->state
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (10 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 10/24] md/bitmap: remove bitmap_mask_state NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 16/24] md/bitmap: make _page_attr bitops atomic NeilBrown
` (12 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index f5f0ec5..1fd07c5 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -520,7 +520,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);
@@ -615,7 +615,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;
}
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 12/24] md/bitmap: use set_bit, test_bit, etc for operation on bitmap->flags.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (13 preceding siblings ...)
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
2012-04-17 8:43 ` [md PATCH 14/24] md/bitmap: remove async freeing of bitmap file NeilBrown
` (9 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 46 +++++++++++++++++++++-------------------------
drivers/md/bitmap.h | 6 +++---
2 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 1fd07c5..9200ed4 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -269,7 +269,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 {
@@ -287,20 +287,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);
}
@@ -387,7 +383,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)
@@ -519,7 +515,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);
@@ -543,7 +539,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;
}
@@ -615,20 +611,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;
@@ -794,8 +790,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) {
@@ -866,7 +861,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);
@@ -888,7 +883,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);
@@ -939,7 +934,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);
@@ -986,7 +981,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));
@@ -1043,12 +1038,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);
@@ -1757,7 +1753,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);
@@ -1798,7 +1794,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);
@@ -1808,7 +1804,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 987ad3c..ede1084 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -114,9 +114,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 */
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 14/24] md/bitmap: remove async freeing of bitmap file.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (14 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 19/24] md/bitmap: use DIV_ROUND_UP instead of open-code NeilBrown
` (8 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 4322f5b..fb8c978 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -737,7 +737,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;
@@ -746,7 +745,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 */
@@ -762,10 +760,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,
@@ -807,10 +803,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 {
@@ -901,7 +893,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
@@ -1220,7 +1213,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))
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 13/24] md/bitmap: convert some spin_lock_irqsave to spin_lock_irq
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (8 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 04/24] md/bitmap: centralise allocation of bitmap file pages NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 10/24] md/bitmap: remove bitmap_mask_state NeilBrown
` (14 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 32 ++++++++++++++------------------
1 file changed, 14 insertions(+), 18 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 9200ed4..4322f5b 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -735,10 +735,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;
@@ -747,7 +746,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 */
@@ -762,12 +761,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,
@@ -899,7 +897,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;
@@ -909,9 +907,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);
@@ -922,7 +920,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);
@@ -1127,7 +1125,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
@@ -1154,7 +1151,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)) {
@@ -1233,14 +1230,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)
@@ -1814,12 +1811,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",
@@ -1835,7 +1831,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
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 15/24] md/bitmap: merge bitmap_file_unmap and bitmap_file_put.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (12 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 16/24] md/bitmap: make _page_attr bitops atomic NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 12/24] md/bitmap: use set_bit, test_bit, etc for operation on bitmap->flags NeilBrown
` (10 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 34 ++++++++++------------------------
1 file changed, 10 insertions(+), 24 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index fb8c978..d8e2591 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -730,43 +730,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;
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 16/24] md/bitmap: make _page_attr bitops atomic.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (11 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 11/24] md/bitmap: remove single-bit manipulation on sb->state NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 15/24] md/bitmap: merge bitmap_file_unmap and bitmap_file_put NeilBrown
` (11 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 55 +++++++++++++++++++++------------------------------
1 file changed, 23 insertions(+), 32 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index d8e2591..c26100b 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -797,21 +797,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
@@ -882,23 +888,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)
@@ -1060,12 +1060,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)
@@ -1126,15 +1124,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) {
@@ -1154,6 +1148,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;
@@ -1186,6 +1181,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
@@ -1204,18 +1200,13 @@ 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);
if (!bitmap->storage.filemap)
break;
}
}
- spin_unlock_irq(&bitmap->lock);
done:
if (bitmap->allclean == 0)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 19/24] md/bitmap: use DIV_ROUND_UP instead of open-code
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (15 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 14/24] md/bitmap: remove async freeing of bitmap file NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 20/24] md/bitmap: add bitmap_resize function to allow bitmap resizing NeilBrown
` (7 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
Also take the opportunity to simplify CHUNK_BLOCK_RATIO.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 5 ++---
drivers/md/bitmap.h | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index d2750a3..bcd5107 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1695,9 +1695,8 @@ int bitmap_create(struct mddev *mddev)
- BITMAP_BLOCK_SHIFT);
/* now that chunksize and chunkshift are set, we can use these macros */
- chunks = (blocks + bitmap->counts.chunkshift - 1) >>
- bitmap->counts.chunkshift;
- pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
+ chunks = DIV_ROUND_UP(blocks, CHUNK_BLOCK_RATIO(bitmap));
+ pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO);
BUG_ON(!pages);
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index 256a850..530be4d 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -102,7 +102,7 @@ typedef __u16 bitmap_counter_t;
#define BITMAP_BLOCK_SHIFT 9
/* how many blocks per chunk? (this is variable) */
-#define CHUNK_BLOCK_RATIO(bitmap) ((bitmap)->mddev->bitmap_info.chunksize >> BITMAP_BLOCK_SHIFT)
+#define CHUNK_BLOCK_RATIO(bitmap) (1 << (bitmap)->counts.chunkshift)
#endif
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 22/24] md: allow array to be resized while bitmap is present.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (21 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 24/24] md/raid5: Allow reshape while a " NeilBrown
2012-04-18 2:07 ` [md PATCH 00/24] Allow bitmaps to be resized Jack Wang
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
Now that bitmaps can be resized, we can allow an array to be resized
while the bitmap is present.
This only covers resizing that involves changing the effective size
of member devices, not resizing that changes the number of devices.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/md.c | 6 +-----
drivers/md/raid1.c | 11 +++++++++--
drivers/md/raid10.c | 10 ++++++++--
drivers/md/raid5.c | 14 ++++++++++----
4 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9524192..b8f9c8e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6153,11 +6153,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
*/
if (mddev->sync_thread)
return -EBUSY;
- if (mddev->bitmap)
- /* Sorry, cannot grow a bitmap yet, just remove it,
- * grow, and re-add.
- */
- return -EBUSY;
+
rdev_for_each(rdev, mddev) {
sector_t avail = rdev->sectors;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 22cfc66..8e717bd 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2752,9 +2752,16 @@ static int raid1_resize(struct mddev *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
- md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0));
- if (mddev->array_sectors > raid1_size(mddev, sectors, 0))
+ sector_t newsize = raid1_size(mddev, sectors, 0);
+ if (mddev->external_size &&
+ mddev->array_sectors > newsize)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, newsize, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, newsize);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 728fcab..cd64c89 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3666,9 +3666,15 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors)
oldsize = raid10_size(mddev, 0, 0);
size = raid10_size(mddev, sectors, 0);
- md_set_array_sectors(mddev, size);
- if (mddev->array_sectors > size)
+ if (mddev->external_size &&
+ mddev->array_sectors > size)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, size, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, size);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 7bfd59b..eab6168 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5503,12 +5503,18 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
+ sector_t newsize;
sectors &= ~((sector_t)mddev->chunk_sectors - 1);
- md_set_array_sectors(mddev, raid5_size(mddev, sectors,
- mddev->raid_disks));
- if (mddev->array_sectors >
- raid5_size(mddev, sectors, mddev->raid_disks))
+ newsize = raid5_size(mddev, sectors, mddev->raid_disks);
+ if (mddev->external_size &&
+ mddev->array_sectors > newsize)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, sectors, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, newsize);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 21/24] md/bitmap: make sure reshape request are reflected in superblock.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (20 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 17/24] md/bitmap: make bitmap bitops atomic NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 22/24] md: allow array to be resized while bitmap is present NeilBrown
` (2 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index dc5ec72..d1004b6 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -418,6 +418,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);
}
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 20/24] md/bitmap: add bitmap_resize function to allow bitmap resizing.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (16 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 23/24] md/raid10: resize bitmap when required during reshape NeilBrown
` (6 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 23/24] md/raid10: resize bitmap when required during reshape.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (17 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 20/24] md/bitmap: add bitmap_resize function to allow bitmap resizing NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 18/24] md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap' NeilBrown
` (5 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
If a reshape changes the size of the array, then we can now
update the bitmap to suit - so do so.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/raid10.c | 37 ++++++++++++++++++++++++-------------
1 file changed, 24 insertions(+), 13 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index cd64c89..1019f63 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3776,8 +3776,6 @@ static int raid10_check_reshape(struct mddev *mddev)
if (mddev->delta_disks < 0)
return -EINVAL;
- if (mddev->bitmap)
- return -EBUSY;
if (!enough(conf, -1))
return -EINVAL;
@@ -3872,6 +3870,7 @@ static int raid10_start_reshape(struct mddev *mddev)
struct r10conf *conf = mddev->private;
struct md_rdev *rdev;
int spares = 0;
+ int ret;
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
@@ -3928,6 +3927,14 @@ static int raid10_start_reshape(struct mddev *mddev)
spin_unlock_irq(&conf->device_lock);
if (mddev->delta_disks > 0) {
+ if (mddev->bitmap) {
+ ret = bitmap_resize(mddev->bitmap,
+ raid10_size(mddev, 0,
+ conf->geo.raid_disks),
+ 0, 0);
+ if (ret)
+ goto abort;
+ }
rdev_for_each(rdev, mddev)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags)) {
@@ -3967,22 +3974,26 @@ static int raid10_start_reshape(struct mddev *mddev)
mddev->sync_thread = md_register_thread(md_do_sync, mddev,
"reshape");
if (!mddev->sync_thread) {
- mddev->recovery = 0;
- spin_lock_irq(&conf->device_lock);
- conf->geo = conf->prev;
- mddev->raid_disks = conf->geo.raid_disks;
- rdev_for_each(rdev, mddev)
- rdev->new_data_offset = rdev->data_offset;
- smp_wmb();
- conf->reshape_progress = MaxSector;
- mddev->reshape_position = MaxSector;
- spin_unlock_irq(&conf->device_lock);
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto abort;
}
conf->reshape_checkpoint = jiffies;
md_wakeup_thread(mddev->sync_thread);
md_new_event(mddev);
return 0;
+
+abort:
+ mddev->recovery = 0;
+ spin_lock_irq(&conf->device_lock);
+ conf->geo = conf->prev;
+ mddev->raid_disks = conf->geo.raid_disks;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
+ smp_wmb();
+ conf->reshape_progress = MaxSector;
+ mddev->reshape_position = MaxSector;
+ spin_unlock_irq(&conf->device_lock);
+ return ret;
}
/* Calculate the last device-address that could contain
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 18/24] md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap'
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (18 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 23/24] md/raid10: resize bitmap when required during reshape NeilBrown
@ 2012-04-17 8:43 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 17/24] md/bitmap: make bitmap bitops atomic NeilBrown
` (4 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
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 <neilb@suse.de>
---
drivers/md/bitmap.c | 138 ++++++++++++++++++++++++++-------------------------
drivers/md/bitmap.h | 23 +++++----
2 files changed, 84 insertions(+), 77 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index e88e553..d2750a3 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;
@@ -830,7 +829,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)
@@ -854,7 +853,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)
@@ -936,7 +935,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) {
@@ -945,10 +944,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;
@@ -1024,10 +1023,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++;
}
@@ -1066,7 +1065,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;
@@ -1074,7 +1074,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;
@@ -1084,7 +1084,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);
@@ -1099,6 +1099,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.
@@ -1148,21 +1149,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);
@@ -1173,15 +1175,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,28 +1691,29 @@ 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);
/* now that chunksize and chunkshift are set, we can use these macros */
- chunks = (blocks + bitmap->chunkshift - 1) >>
- bitmap->chunkshift;
+ chunks = (blocks + 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;
@@ -1782,17 +1785,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");
@@ -1802,7 +1807,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 ede1084..256a850 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -175,22 +175,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
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 17/24] md/bitmap: make bitmap bitops atomic.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (19 preceding siblings ...)
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 ` NeilBrown
2012-04-17 8:43 ` [md PATCH 21/24] md/bitmap: make sure reshape request are reflected in superblock NeilBrown
` (3 subsequent siblings)
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
This allows us to remove spinlock protection which is
more heavy-weight than simple atomics.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/bitmap.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index c26100b..e88e553 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -842,7 +842,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 */
@@ -864,7 +864,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
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [md PATCH 24/24] md/raid5: Allow reshape while a bitmap is present.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (22 preceding siblings ...)
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 ` NeilBrown
2012-04-18 2:07 ` [md PATCH 00/24] Allow bitmaps to be resized Jack Wang
24 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-17 8:43 UTC (permalink / raw)
To: linux-raid
We always should have allowed this. A raid5 reshape doesn't change
the size of the bitmap, so not need to restrict it.
Also add a test to make sure we don't try to start a reshape on a
failed array.
Signed-off-by: NeilBrown <neilb@suse.de>
---
drivers/md/raid5.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index eab6168..8fba57e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5559,9 +5559,6 @@ static int check_reshape(struct mddev *mddev)
mddev->new_layout == mddev->layout &&
mddev->new_chunk_sectors == mddev->chunk_sectors)
return 0; /* nothing to do */
- if (mddev->bitmap)
- /* Cannot grow a bitmap yet */
- return -EBUSY;
if (has_failed(conf))
return -EINVAL;
if (mddev->delta_disks < 0) {
@@ -5596,6 +5593,9 @@ static int raid5_start_reshape(struct mddev *mddev)
if (!check_stripe_cache(mddev))
return -ENOSPC;
+ if (has_failed(conf))
+ return -EINVAL;
+
rdev_for_each(rdev, mddev) {
if (!test_bit(In_sync, &rdev->flags)
&& !test_bit(Faulty, &rdev->flags))
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [md PATCH 00/24] Allow bitmaps to be resized.
2012-04-17 8:43 [md PATCH 00/24] Allow bitmaps to be resized NeilBrown
` (23 preceding siblings ...)
2012-04-17 8:43 ` [md PATCH 24/24] md/raid5: Allow reshape while a " NeilBrown
@ 2012-04-18 2:07 ` Jack Wang
2012-04-18 3:35 ` NeilBrown
24 siblings, 1 reply; 27+ messages in thread
From: Jack Wang @ 2012-04-18 2:07 UTC (permalink / raw)
To: NeilBrown; +Cc: linux-raid
Dear Neil,
Thanks for your good works.
One query about current grow supporting status:
as the raid wiki show : the RAID level 1/4/5/6 array can be grown . In
my test I can grow raid 1 add disk or remove disk through mdadm grow,
but change level from 1 to 4 or 5 will fail. the simaliar command work
for change level between 4/5/6, change 1 to 10 fail too.
My kernel version is 3.2.15. mdadm version 3.2.3.
Jack
2012/4/17 NeilBrown <neilb@suse.de>:
>
> The following series has just been added to my for-next queue
> and so should be in 3.5.
> git://neil.brown.name/md for-next
> git://github.com/neilbrown/linux.git md/for-next
>
> It allows md to resize a bitmap on an active array. This
> means that arrays can now be reshaped without first removing the
> bitmap. The bitmap is resized in-place.
>
> As always: review and testing would be greatly appreciated.
>
> NeilBrown
>
> ---
>
> NeilBrown (24):
> md/raid5: Allow reshape while a bitmap is present.
> md/raid10: resize bitmap when required during reshape.
> md: allow array to be resized while bitmap is present.
> md/bitmap: make sure reshape request are reflected in superblock.
> md/bitmap: add bitmap_resize function to allow bitmap resizing.
> md/bitmap: use DIV_ROUND_UP instead of open-code
> md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap'
> md/bitmap: make bitmap bitops atomic.
> md/bitmap: make _page_attr bitops atomic.
> md/bitmap: merge bitmap_file_unmap and bitmap_file_put.
> md/bitmap: remove async freeing of bitmap file.
> md/bitmap: convert some spin_lock_irqsave to spin_lock_irq
> md/bitmap: use set_bit, test_bit, etc for operation on bitmap->flags.
> md/bitmap: remove single-bit manipulation on sb->state
> md/bitmap: remove bitmap_mask_state
> md/bitmap: move storage allocation from bitmap_load to bitmap_create.
> md/bitmap: separate bitmap file allocation to its own function.
> md/bitmap: store bytes in file rather than just in last page.
> md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct.
> md/bitmap: change *_page_attr() to take a page number, not a page.
> md/bitmap: centralise allocation of bitmap file pages.
> md/bitmap: allow a bitmap with no backing storage.
> md/bitmap: add new 'space' attribute for bitmaps.
> md/bitmap: disentangle two different 'pending' flags.
>
>
> drivers/md/bitmap.c | 1089 +++++++++++++++++++++++++++++----------------------
> drivers/md/bitmap.h | 58 ++-
> drivers/md/md.c | 53 ++
> drivers/md/md.h | 3
> drivers/md/raid1.c | 11 -
> drivers/md/raid10.c | 47 +-
> drivers/md/raid5.c | 20 +
> 7 files changed, 754 insertions(+), 527 deletions(-)
>
> --
> Signature
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-raid" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [md PATCH 00/24] Allow bitmaps to be resized.
2012-04-18 2:07 ` [md PATCH 00/24] Allow bitmaps to be resized Jack Wang
@ 2012-04-18 3:35 ` NeilBrown
0 siblings, 0 replies; 27+ messages in thread
From: NeilBrown @ 2012-04-18 3:35 UTC (permalink / raw)
To: Jack Wang; +Cc: linux-raid
[-- Attachment #1: Type: text/plain, Size: 771 bytes --]
On Wed, 18 Apr 2012 10:07:37 +0800 Jack Wang <jack.wang.usish@gmail.com>
wrote:
> Dear Neil,
>
> Thanks for your good works.
> One query about current grow supporting status:
>
> as the raid wiki show : the RAID level 1/4/5/6 array can be grown . In
> my test I can grow raid 1 add disk or remove disk through mdadm grow,
> but change level from 1 to 4 or 5 will fail. the simaliar command work
> for change level between 4/5/6, change 1 to 10 fail too.
>
> My kernel version is 3.2.15. mdadm version 3.2.3.
You can definitely change from RAID1 to RAID5 and I think to RAID4.
But you are right that you cannot change RAID1 to RAID10 yet. That should be
easy enough to add, and now that RAID10 can be reshaped, it would make sense.
NeilBrown
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2012-04-18 3:35 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 05/24] md/bitmap: change *_page_attr() to take a page number, not a page 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 06/24] md/bitmap: move some fields of 'struct bitmap' into a 'storage' substruct 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 07/24] md/bitmap: store bytes in file rather than just in last page 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 13/24] md/bitmap: convert some spin_lock_irqsave to spin_lock_irq NeilBrown
2012-04-17 8:43 ` [md PATCH 10/24] md/bitmap: remove bitmap_mask_state 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 16/24] md/bitmap: make _page_attr bitops atomic 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 ` [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 14/24] md/bitmap: remove async freeing of bitmap file NeilBrown
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 20/24] md/bitmap: add bitmap_resize function to allow bitmap resizing 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 18/24] md/bitmap: create a 'struct bitmap_counts' substructure of 'struct bitmap' NeilBrown
2012-04-17 8:43 ` [md PATCH 17/24] md/bitmap: make bitmap bitops atomic 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 22/24] md: allow array to be resized while bitmap is present NeilBrown
2012-04-17 8:43 ` [md PATCH 24/24] md/raid5: Allow reshape while a " NeilBrown
2012-04-18 2:07 ` [md PATCH 00/24] Allow bitmaps to be resized Jack Wang
2012-04-18 3:35 ` NeilBrown
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).