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>
* if we find our page, we increment the page's refcount so that it stays
* allocated while we're using it
*/
* 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)
unsigned long page, int create)
__releases(bitmap->lock)
__acquires(bitmap->lock)
spin_lock_irq(&bitmap->lock);
if (mappage == NULL) {
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)
/* failed - set the hijacked flag so that we can use the
* pointer as a counter */
if (!bitmap->bp[page].map)
/* 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 */
/* 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)
unsigned long bit;
struct page *page;
void *kaddr;
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)
page = filemap_get_page(&bitmap->storage, chunk);
if (!page)
unsigned long bit;
struct page *page;
void *paddr;
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)
page = filemap_get_page(&bitmap->storage, chunk);
if (!page)
void *paddr;
struct bitmap_storage *store = &bitmap->storage;
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) {
file = store->file;
if (!file && !bitmap->mddev->bitmap_info.offset) {
store->file_pages = 0;
for (i = 0; i < chunks ; i++) {
/* if the disk bit is set, set the memory bit */
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,
>= start);
bitmap_set_memory_bits(bitmap,
- (sector_t)i << bitmap->chunkshift,
+ (sector_t)i << bitmap->counts.chunkshift,
kunmap_atomic(paddr);
if (b) {
/* if the disk bit is set, set the memory bit */
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,
>= start);
bitmap_set_memory_bits(bitmap,
- (sector_t)i << bitmap->chunkshift,
+ (sector_t)i << bitmap->counts.chunkshift,
-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;
{
sector_t chunk = offset >> bitmap->chunkshift;
unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
bitmap_checkfree(bitmap, page);
}
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;
{
sector_t chunk = offset >> bitmap->chunkshift;
unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
-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);
sector_t offset, sector_t *blocks,
int create);
unsigned long j;
unsigned long nextpage;
sector_t blocks;
unsigned long j;
unsigned long nextpage;
sector_t blocks;
+ struct bitmap_counts *counts;
/* Use a mutex to guard daemon_work against
* bitmap_destroy.
/* Use a mutex to guard daemon_work against
* bitmap_destroy.
/* Now look at the bitmap counters and if any are '2' or '1',
* decrement and handle accordingly.
*/
/* 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);
- for (j = 0; j < bitmap->chunks; j++) {
+ for (j = 0; j < counts->chunks; j++) {
- sector_t block = (sector_t)j << bitmap->chunkshift;
+ sector_t block = (sector_t)j << counts->chunkshift;
if (j == nextpage) {
nextpage += PAGE_COUNTER_RATIO;
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;
}
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,
if (*bmc == 1 && !bitmap->need_sync) {
/* We can clear the bit */
*bmc = 0;
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_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;
}
}
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
/* 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
mutex_unlock(&mddev->bitmap_info.mutex);
}
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)
sector_t offset, sector_t *blocks,
int create)
__releases(bitmap->lock)
sector_t blocks;
bitmap_counter_t *bmc;
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);
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
*/
prepare_to_wait(&bitmap->overflow_wait, &__wait,
TASK_UNINTERRUPTIBLE);
*/
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;
io_schedule();
finish_wait(&bitmap->overflow_wait, &__wait);
continue;
switch (*bmc) {
case 0:
bitmap_file_set_bit(bitmap, offset);
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;
/* fall through */
case 1:
*bmc = 2;
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
offset += blocks;
if (sectors > blocks)
offset += blocks;
if (sectors > blocks)
unsigned long flags;
bitmap_counter_t *bmc;
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);
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
(*bmc)--;
if (*bmc <= 2) {
(*bmc)--;
if (*bmc <= 2) {
- bitmap_set_pending(bitmap, offset);
+ bitmap_set_pending(&bitmap->counts, offset);
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
offset += blocks;
if (sectors > blocks)
sectors -= blocks;
offset += blocks;
if (sectors > blocks)
sectors -= blocks;
*blocks = 1024;
return 1; /* always resync if no bitmap */
}
*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 */
rv = 0;
if (bmc) {
/* locked */
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
*blocks = 1024;
return;
}
*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 */
if (bmc == NULL)
goto unlock;
/* locked */
*bmc |= NEEDED_MASK;
else {
if (*bmc <= 2) {
*bmc |= NEEDED_MASK;
else {
if (*bmc <= 2) {
- bitmap_set_pending(bitmap, offset);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
}
}
unlock:
bitmap->allclean = 0;
}
}
}
unlock:
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
}
EXPORT_SYMBOL(bitmap_end_sync);
}
EXPORT_SYMBOL(bitmap_end_sync);
bitmap->mddev->curr_resync_completed = sector;
set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
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);
s = 0;
while (s < sector && s < bitmap->mddev->resync_max_sectors) {
bitmap_end_sync(bitmap, s, &blocks, 0);
sector_t secs;
bitmap_counter_t *bmc;
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);
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return;
}
if (!*bmc) {
*bmc = 2 | (needed ? NEEDED_MASK : 0);
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);
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
}
/* dirty the memory and file bits for bitmap chunks "s" to "e" */
}
/* dirty the memory and file bits for bitmap chunks "s" to "e" */
unsigned long chunk;
for (chunk = s; chunk <= e; chunk++) {
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)
bitmap_set_memory_bits(bitmap, sec, 1);
bitmap_file_set_bit(bitmap, sec);
if (sec < bitmap->mddev->recovery_cp)
/* release the bitmap file */
bitmap_file_unmap(&bitmap->storage);
/* 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 */
/* free all allocated memory */
if (!bitmap)
return -ENOMEM;
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);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
init_waitqueue_head(&bitmap->overflow_wait);
goto error;
bitmap->daemon_lastrun = jiffies;
goto error;
bitmap->daemon_lastrun = jiffies;
- bitmap->chunkshift = (ffz(~mddev->bitmap_info.chunksize)
+ bitmap->counts.chunkshift = (ffz(~mddev->bitmap_info.chunksize)
- chunks = (blocks + (1 << bitmap->chunkshift) - 1) >>
- bitmap->chunkshift;
+ chunks = (blocks + (1 << bitmap->counts.chunkshift) - 1) >>
+ bitmap->counts.chunkshift;
pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
BUG_ON(!pages);
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);
+ if (!bitmap->counts.bp)
goto error;
if (file || mddev->bitmap_info.offset) {
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;
!mddev->bitmap_info.external);
if (err)
goto error;
void bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
{
unsigned long chunk_kb;
void bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
{
unsigned long chunk_kb;
+ struct bitmap_counts *counts;
- 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",
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");
<< (PAGE_SHIFT - 10),
chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize,
chunk_kb ? "KB" : "B");
- spin_unlock_irq(&bitmap->lock);
/* the main bitmap structure - one per mddev */
struct bitmap {
/* 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;
__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
struct bitmap_storage {
struct file *file; /* backing disk file */
struct page *sb_page; /* cached copy of the bitmap