|
@@ -883,6 +883,8 @@ void bitmap_unplug(struct bitmap *bitmap)
|
|
need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
|
|
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_DIRTY);
|
|
clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
|
|
clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
|
|
|
|
+ if (dirty || need_write)
|
|
|
|
+ clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
|
|
if (dirty)
|
|
if (dirty)
|
|
wait = 1;
|
|
wait = 1;
|
|
spin_unlock_irqrestore(&bitmap->lock, flags);
|
|
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->bp[page].count += inc;
|
|
bitmap_checkfree(bitmap, page);
|
|
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,
|
|
static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
|
|
sector_t offset, sector_t *blocks,
|
|
sector_t offset, sector_t *blocks,
|
|
int create);
|
|
int create);
|
|
@@ -1099,8 +1112,8 @@ void bitmap_daemon_work(struct mddev *mddev)
|
|
{
|
|
{
|
|
struct bitmap *bitmap;
|
|
struct bitmap *bitmap;
|
|
unsigned long j;
|
|
unsigned long j;
|
|
|
|
+ unsigned long nextpage;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
- struct page *page = NULL, *lastpage = NULL;
|
|
|
|
sector_t blocks;
|
|
sector_t blocks;
|
|
void *paddr;
|
|
void *paddr;
|
|
|
|
|
|
@@ -1124,114 +1137,120 @@ void bitmap_daemon_work(struct mddev *mddev)
|
|
}
|
|
}
|
|
bitmap->allclean = 1;
|
|
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);
|
|
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++) {
|
|
for (j = 0; j < bitmap->chunks; j++) {
|
|
bitmap_counter_t *bmc;
|
|
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;
|
|
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,
|
|
bmc = bitmap_get_counter(bitmap,
|
|
(sector_t)j << bitmap->chunkshift,
|
|
(sector_t)j << bitmap->chunkshift,
|
|
&blocks, 0);
|
|
&blocks, 0);
|
|
- if (!bmc)
|
|
|
|
|
|
+
|
|
|
|
+ if (!bmc) {
|
|
j |= PAGE_COUNTER_MASK;
|
|
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;
|
|
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);
|
|
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:
|
|
done:
|
|
if (bitmap->allclean == 0)
|
|
if (bitmap->allclean == 0)
|
|
@@ -1386,11 +1405,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
|
|
|
|
|
|
(*bmc)--;
|
|
(*bmc)--;
|
|
if (*bmc <= 2) {
|
|
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;
|
|
bitmap->allclean = 0;
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&bitmap->lock, flags);
|
|
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;
|
|
*bmc |= NEEDED_MASK;
|
|
else {
|
|
else {
|
|
if (*bmc <= 2) {
|
|
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;
|
|
bitmap->allclean = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1551,11 +1564,9 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
if (!*bmc) {
|
|
if (!*bmc) {
|
|
- struct page *page;
|
|
|
|
*bmc = 2 | (needed ? NEEDED_MASK : 0);
|
|
*bmc = 2 | (needed ? NEEDED_MASK : 0);
|
|
bitmap_count_page(bitmap, offset, 1);
|
|
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;
|
|
bitmap->allclean = 0;
|
|
}
|
|
}
|
|
spin_unlock_irq(&bitmap->lock);
|
|
spin_unlock_irq(&bitmap->lock);
|