if (!page)
return ERR_PTR(-ENOMEM);
- do {
- ITERATE_RDEV(mddev, rdev, tmp)
- if (rdev->in_sync && !rdev->faulty)
- goto found;
- return ERR_PTR(-EIO);
- found:
+ ITERATE_RDEV(mddev, rdev, tmp) {
+ if (! rdev->in_sync || rdev->faulty)
+ continue;
+
target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512);
- } while (!sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ));
+ if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) {
+ page->index = index;
+ return page;
+ }
+ }
+ return ERR_PTR(-EIO);
- page->index = index;
- return page;
}
static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wait)
printk(KERN_DEBUG " daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep));
printk(KERN_DEBUG " sync size: %llu KB\n",
(unsigned long long)le64_to_cpu(sb->sync_size)/2);
+ printk(KERN_DEBUG "max write behind: %d\n", le32_to_cpu(sb->write_behind));
kunmap(bitmap->sb_page);
}
{
char *reason = NULL;
bitmap_super_t *sb;
- unsigned long chunksize, daemon_sleep;
+ unsigned long chunksize, daemon_sleep, write_behind;
unsigned long bytes_read;
unsigned long long events;
int err = -EINVAL;
chunksize = le32_to_cpu(sb->chunksize);
daemon_sleep = le32_to_cpu(sb->daemon_sleep);
+ write_behind = le32_to_cpu(sb->write_behind);
/* verify that the bitmap-specific fields are valid */
if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
else if ((1 << ffz(~chunksize)) != chunksize)
reason = "bitmap chunksize not a power of 2";
else if (daemon_sleep < 1 || daemon_sleep > 15)
- reason = "daemon sleep period out of range";
+ reason = "daemon sleep period out of range (1-15s)";
+ else if (write_behind > COUNTER_MAX)
+ reason = "write-behind limit out of range (0 - 16383)";
if (reason) {
printk(KERN_INFO "%s: invalid bitmap file superblock: %s\n",
bmname(bitmap), reason);
/* assign fields using values from superblock */
bitmap->chunksize = chunksize;
bitmap->daemon_sleep = daemon_sleep;
+ bitmap->daemon_lastrun = jiffies;
+ bitmap->max_write_behind = write_behind;
bitmap->flags |= sb->state;
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
+ if (sb->state & BITMAP_STALE)
+ bitmap->events_cleared = bitmap->mddev->events;
err = 0;
out:
kunmap(bitmap->sb_page);
return 0;
}
-static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset,
- unsigned long sectors, int in_sync);
+static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed);
/* * bitmap_init_from_disk -- called at bitmap_create time to initialize
* the in-memory bitmap from the on-disk bitmap -- also, sets up the
* memory mapping of the bitmap file
* if there's no bitmap file, or if the bitmap file had been
* previously kicked from the array, we mark all the bits as
* 1's in order to cause a full resync.
+ *
+ * We ignore all bits for sectors that end earlier than 'start'.
+ * This is used when reading an out-of-date bitmap...
*/
-static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync)
+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;
* whole page and write it out
*/
memset(page_address(page) + offset, 0xff,
- PAGE_SIZE - offset);
+ PAGE_SIZE - offset);
ret = write_page(bitmap, page, 1);
if (ret) {
kunmap(page);
}
if (test_bit(bit, page_address(page))) {
/* if the disk bit is set, set the memory bit */
- bitmap_set_memory_bits(bitmap,
- i << CHUNK_BLOCK_SHIFT(bitmap), 1, in_sync);
+ bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap),
+ ((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start)
+ );
bit_cnt++;
+ set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
}
}
}
}
-int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors)
+int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int behind)
{
if (!bitmap) return 0;
+
+ if (behind) {
+ atomic_inc(&bitmap->behind_writes);
+ PRINTK(KERN_DEBUG "inc write-behind count %d/%d\n",
+ atomic_read(&bitmap->behind_writes), bitmap->max_write_behind);
+ }
+
while (sectors) {
int blocks;
bitmap_counter_t *bmc;
}
void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors,
- int success)
+ int success, int behind)
{
if (!bitmap) return;
+ if (behind) {
+ atomic_dec(&bitmap->behind_writes);
+ PRINTK(KERN_DEBUG "dec write-behind count %d/%d\n",
+ atomic_read(&bitmap->behind_writes), bitmap->max_write_behind);
+ }
+
while (sectors) {
int blocks;
unsigned long flags;
}
}
-static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset,
- unsigned long sectors, int in_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 unless in_sync. They should all
+ * counter to 1 and set resync_needed. They should all
* be 0 at this point
*/
- while (sectors) {
- int secs;
- bitmap_counter_t *bmc;
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, &secs, 1);
- if (!bmc) {
- spin_unlock_irq(&bitmap->lock);
- return;
- }
- if (! *bmc) {
- struct page *page;
- *bmc = 1 | (in_sync? 0 : NEEDED_MASK);
- bitmap_count_page(bitmap, offset, 1);
- page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap));
- set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
- }
+
+ int secs;
+ bitmap_counter_t *bmc;
+ spin_lock_irq(&bitmap->lock);
+ bmc = bitmap_get_counter(bitmap, offset, &secs, 1);
+ if (!bmc) {
spin_unlock_irq(&bitmap->lock);
- if (sectors > secs)
- sectors -= secs;
- else
- sectors = 0;
+ return;
+ }
+ if (! *bmc) {
+ struct page *page;
+ *bmc = 1 | (needed?NEEDED_MASK:0);
+ bitmap_count_page(bitmap, offset, 1);
+ page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap));
+ set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
}
+ spin_unlock_irq(&bitmap->lock);
+
+}
+
+/*
+ * flush out any pending updates
+ */
+void bitmap_flush(mddev_t *mddev)
+{
+ struct bitmap *bitmap = mddev->bitmap;
+ int sleep;
+
+ if (!bitmap) /* there was no bitmap */
+ return;
+
+ /* run the daemon_work three time to ensure everything is flushed
+ * that can be
+ */
+ sleep = bitmap->daemon_sleep;
+ bitmap->daemon_sleep = 0;
+ bitmap_daemon_work(bitmap);
+ bitmap_daemon_work(bitmap);
+ bitmap_daemon_work(bitmap);
+ bitmap->daemon_sleep = sleep;
+ bitmap_update_sb(bitmap);
}
/*
* free memory that was allocated
*/
-void bitmap_destroy(mddev_t *mddev)
+static void bitmap_free(struct bitmap *bitmap)
{
unsigned long k, pages;
struct bitmap_page *bp;
- struct bitmap *bitmap = mddev->bitmap;
if (!bitmap) /* there was no bitmap */
return;
- mddev->bitmap = NULL; /* disconnect from the md device */
-
/* release the bitmap file and kill the daemon */
bitmap_file_put(bitmap);
kfree(bp);
kfree(bitmap);
}
+void bitmap_destroy(mddev_t *mddev)
+{
+ struct bitmap *bitmap = mddev->bitmap;
+
+ if (!bitmap) /* there was no bitmap */
+ return;
+
+ mddev->bitmap = NULL; /* disconnect from the md device */
+
+ bitmap_free(bitmap);
+}
/*
* initialize the bitmap structure
unsigned long pages;
struct file *file = mddev->bitmap_file;
int err;
+ sector_t start;
BUG_ON(sizeof(bitmap_super_t) != 256);
spin_lock_init(&bitmap->lock);
bitmap->mddev = mddev;
- mddev->bitmap = bitmap;
spin_lock_init(&bitmap->write_lock);
INIT_LIST_HEAD(&bitmap->complete_pages);
init_waitqueue_head(&bitmap->write_wait);
bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc,
write_pool_free, NULL);
+ err = -ENOMEM;
if (!bitmap->write_pool)
- return -ENOMEM;
+ goto error;
bitmap->file = file;
bitmap->offset = mddev->bitmap_offset;
/* read superblock from bitmap file (this sets bitmap->chunksize) */
err = bitmap_read_sb(bitmap);
if (err)
- return err;
+ goto error;
bitmap->chunkshift = find_first_bit(&bitmap->chunksize,
sizeof(bitmap->chunksize));
#else
bitmap->bp = kmalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL);
#endif
+ err = -ENOMEM;
if (!bitmap->bp)
- return -ENOMEM;
+ goto error;
memset(bitmap->bp, 0, pages * sizeof(*bitmap->bp));
bitmap->flags |= BITMAP_ACTIVE;
/* now that we have some pages available, initialize the in-memory
* bitmap from the on-disk bitmap */
- err = bitmap_init_from_disk(bitmap, mddev->recovery_cp == MaxSector);
+ start = 0;
+ if (mddev->degraded == 0
+ || bitmap->events_cleared == mddev->events)
+ /* no need to keep dirty bits to optimise a re-add of a missing device */
+ start = mddev->recovery_cp;
+ err = bitmap_init_from_disk(bitmap, start);
+
if (err)
- return err;
+ goto error;
printk(KERN_INFO "created bitmap (%lu pages) for device %s\n",
pages, bmname(bitmap));
+ mddev->bitmap = bitmap;
+
/* kick off the bitmap daemons */
err = bitmap_start_daemons(bitmap);
if (err)
return err;
return bitmap_update_sb(bitmap);
+
+ error:
+ bitmap_free(bitmap);
+ return err;
}
/* the bitmap API -- for raid personalities */