Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 305936
b: refs/heads/master
c: bf07bb7
h: refs/heads/master
v: v3
  • Loading branch information
NeilBrown committed May 22, 2012
1 parent 260efb1 commit 9881c42
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 103 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: bc0934f0477d0a2350a478004799d9c064923b7b
refs/heads/master: bf07bb7d5be813630d3530be274b3324f85e310c
213 changes: 112 additions & 101 deletions trunk/drivers/md/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion trunk/drivers/md/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,15 @@ struct bitmap_page {
* pointer and use it as two counters itself
*/
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 */
Expand Down

0 comments on commit 9881c42

Please sign in to comment.