if (!page)
printk("%s: bitmap_alloc_page FAILED\n", bmname(bitmap));
else
- printk("%s: bitmap_alloc_page: allocated page at %p\n",
+ PRINTK("%s: bitmap_alloc_page: allocated page at %p\n",
bmname(bitmap), page);
return page;
}
* basic page I/O operations
*/
+/* IO operations when bitmap is stored near all superblocks */
+static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long index)
+{
+ /* choose a good rdev and read the page from there */
+
+ mdk_rdev_t *rdev;
+ struct list_head *tmp;
+ struct page *page = alloc_page(GFP_KERNEL);
+ sector_t target;
+
+ 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:
+ target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512);
+
+ } while (!sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ));
+
+ page->index = index;
+ return page;
+}
+
+static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wait)
+{
+ mdk_rdev_t *rdev;
+ struct list_head *tmp;
+
+ ITERATE_RDEV(mddev, rdev, tmp)
+ if (rdev->in_sync && !rdev->faulty)
+ md_super_write(mddev, rdev,
+ (rdev->sb_offset<<1) + offset
+ + page->index * (PAGE_SIZE/512),
+ PAGE_SIZE,
+ page);
+
+ if (wait)
+ wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+ return 0;
+}
+
/*
- * write out a page
+ * write out a page to a file
*/
-static int write_page(struct page *page, int wait)
+static int write_page(struct bitmap *bitmap, struct page *page, int wait)
{
int ret = -ENOMEM;
- lock_page(page);
+ if (bitmap->file == NULL)
+ return write_sb_page(bitmap->mddev, bitmap->offset, page, wait);
- if (page->mapping == NULL)
- goto unlock_out;
- else if (i_size_read(page->mapping->host) < page->index << PAGE_SHIFT) {
- ret = -ENOENT;
- goto unlock_out;
- }
+ lock_page(page);
ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE);
if (!ret)
ret = page->mapping->a_ops->commit_write(NULL, page, 0,
PAGE_SIZE);
if (ret) {
-unlock_out:
unlock_page(page);
return ret;
}
set_page_dirty(page); /* force it to be written out */
+
+ if (!wait) {
+ /* add to list to be waited for by daemon */
+ struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO);
+ item->page = page;
+ page_cache_get(page);
+ spin_lock(&bitmap->write_lock);
+ list_add(&item->list, &bitmap->complete_pages);
+ spin_unlock(&bitmap->write_lock);
+ md_wakeup_thread(bitmap->writeback_daemon);
+ }
return write_one_page(page, wait);
}
spin_unlock_irqrestore(&bitmap->lock, flags);
return 0;
}
- page_cache_get(bitmap->sb_page);
spin_unlock_irqrestore(&bitmap->lock, flags);
sb = (bitmap_super_t *)kmap(bitmap->sb_page);
sb->events = cpu_to_le64(bitmap->mddev->events);
if (!bitmap->mddev->degraded)
sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
kunmap(bitmap->sb_page);
- write_page(bitmap->sb_page, 0);
- return 0;
+ return write_page(bitmap, bitmap->sb_page, 0);
}
/* print out the bitmap file superblock */
return;
sb = (bitmap_super_t *)kmap(bitmap->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));
- printk(KERN_DEBUG " uuid: %08x.%08x.%08x.%08x\n",
+ printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic));
+ printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version));
+ printk(KERN_DEBUG " uuid: %08x.%08x.%08x.%08x\n",
*(__u32 *)(sb->uuid+0),
*(__u32 *)(sb->uuid+4),
*(__u32 *)(sb->uuid+8),
*(__u32 *)(sb->uuid+12));
- printk(KERN_DEBUG " events: %llu\n",
+ printk(KERN_DEBUG " events: %llu\n",
(unsigned long long) le64_to_cpu(sb->events));
- printk(KERN_DEBUG "events_clred: %llu\n",
+ printk(KERN_DEBUG "events cleared: %llu\n",
(unsigned long long) le64_to_cpu(sb->events_cleared));
- printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state));
- printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize));
- printk(KERN_DEBUG "daemon sleep: %ds\n", le32_to_cpu(sb->daemon_sleep));
- printk(KERN_DEBUG " sync size: %llu KB\n", le64_to_cpu(sb->sync_size));
+ printk(KERN_DEBUG " state: %08x\n", le32_to_cpu(sb->state));
+ printk(KERN_DEBUG " chunksize: %d B\n", le32_to_cpu(sb->chunksize));
+ 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);
kunmap(bitmap->sb_page);
}
int err = -EINVAL;
/* page 0 is the superblock, read it... */
- bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read);
+ if (bitmap->file)
+ bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read);
+ else {
+ bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0);
+ bytes_read = PAGE_SIZE;
+ }
if (IS_ERR(bitmap->sb_page)) {
err = PTR_ERR(bitmap->sb_page);
bitmap->sb_page = NULL;
static void bitmap_stop_daemons(struct bitmap *bitmap);
/* dequeue the next item in a page list -- don't call from irq context */
-static struct page_list *dequeue_page(struct bitmap *bitmap,
- struct list_head *head)
+static struct page_list *dequeue_page(struct bitmap *bitmap)
{
struct page_list *item = NULL;
+ struct list_head *head = &bitmap->complete_pages;
spin_lock(&bitmap->write_lock);
if (list_empty(head))
static void drain_write_queues(struct bitmap *bitmap)
{
- struct list_head *queues[] = { &bitmap->complete_pages, NULL };
- struct list_head *head;
struct page_list *item;
- int i;
- for (i = 0; queues[i]; i++) {
- head = queues[i];
- while ((item = dequeue_page(bitmap, head))) {
- page_cache_release(item->page);
- mempool_free(item, bitmap->write_pool);
- }
+ while ((item = dequeue_page(bitmap))) {
+ /* don't bother to wait */
+ page_cache_release(item->page);
+ mempool_free(item, bitmap->write_pool);
}
- spin_lock(&bitmap->write_lock);
- bitmap->writes_pending = 0; /* make sure waiters continue */
wake_up(&bitmap->write_wait);
- spin_unlock(&bitmap->write_lock);
}
static void bitmap_file_put(struct bitmap *bitmap)
bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET);
bitmap_update_sb(bitmap);
- path = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (path)
- ptr = file_path(bitmap->file, path, PAGE_SIZE);
+ if (bitmap->file) {
+ path = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (path)
+ ptr = file_path(bitmap->file, path, PAGE_SIZE);
- printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n",
- bmname(bitmap), ptr ? ptr : "");
+ printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n",
+ bmname(bitmap), ptr ? ptr : "");
- kfree(path);
+ kfree(path);
+ }
bitmap_file_put(bitmap);
void *kaddr;
unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap);
- if (!bitmap->file || !bitmap->filemap) {
+ if (!bitmap->filemap) {
return;
}
* flushed out to disk */
for (i = 0; i < bitmap->file_pages; i++) {
spin_lock_irqsave(&bitmap->lock, flags);
- if (!bitmap->file || !bitmap->filemap) {
+ if (!bitmap->filemap) {
spin_unlock_irqrestore(&bitmap->lock, flags);
return 0;
}
spin_unlock_irqrestore(&bitmap->lock, flags);
if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE))
- write_page(page, 0);
+ if (write_page(bitmap, page, 0))
+ return 1;
}
if (wait) { /* if any writes were performed, we need to wait on them */
- spin_lock_irq(&bitmap->write_lock);
- wait_event_lock_irq(bitmap->write_wait,
- bitmap->writes_pending == 0, bitmap->write_lock,
- wake_up_process(bitmap->writeback_daemon->tsk));
- spin_unlock_irq(&bitmap->write_lock);
+ if (bitmap->file) {
+ spin_lock_irq(&bitmap->write_lock);
+ wait_event_lock_irq(bitmap->write_wait,
+ list_empty(&bitmap->complete_pages), bitmap->write_lock,
+ wake_up_process(bitmap->writeback_daemon->tsk));
+ spin_unlock_irq(&bitmap->write_lock);
+ } else
+ wait_event(bitmap->mddev->sb_wait,
+ atomic_read(&bitmap->mddev->pending_writes)==0);
}
return 0;
}
chunks = bitmap->chunks;
file = bitmap->file;
- BUG_ON(!file);
+ BUG_ON(!file && !bitmap->offset);
#if INJECT_FAULTS_3
outofdate = 1;
num_pages = (bytes + sizeof(bitmap_super_t) + PAGE_SIZE - 1) / PAGE_SIZE;
- if (i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) {
+ if (file && i_size_read(file->f_mapping->host) < bytes + sizeof(bitmap_super_t)) {
printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
bmname(bitmap),
(unsigned long) i_size_read(file->f_mapping->host),
*/
page = bitmap->sb_page;
offset = sizeof(bitmap_super_t);
- } else {
+ } else if (file) {
page = read_page(file, index, &dummy);
- if (IS_ERR(page)) { /* read error */
- ret = PTR_ERR(page);
- goto out;
- }
offset = 0;
+ } else {
+ page = read_sb_page(bitmap->mddev, bitmap->offset, index);
+ offset = 0;
+ }
+ if (IS_ERR(page)) { /* read error */
+ ret = PTR_ERR(page);
+ goto out;
}
+
oldindex = index;
oldpage = page;
kmap(page);
*/
memset(page_address(page) + offset, 0xff,
PAGE_SIZE - offset);
- ret = write_page(page, 1);
+ ret = write_page(bitmap, page, 1);
if (ret) {
kunmap(page);
/* release, page not in filemap yet */
return ret;
}
+void bitmap_write_all(struct bitmap *bitmap)
+{
+ /* We don't actually write all bitmap blocks here,
+ * just flag them as needing to be written
+ */
+
+ unsigned long chunks = bitmap->chunks;
+ unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t);
+ unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE;
+ while (num_pages--)
+ bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE;
+}
+
static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
{
int bitmap_daemon_work(struct bitmap *bitmap)
{
- unsigned long bit, j;
+ unsigned long j;
unsigned long flags;
struct page *page = NULL, *lastpage = NULL;
int err = 0;
for (j = 0; j < bitmap->chunks; j++) {
bitmap_counter_t *bmc;
spin_lock_irqsave(&bitmap->lock, flags);
- if (!bitmap->file || !bitmap->filemap) {
+ if (!bitmap->filemap) {
/* error or shutdown */
spin_unlock_irqrestore(&bitmap->lock, flags);
break;
}
page = filemap_get_page(bitmap, j);
- /* skip this page unless it's marked as needing cleaning */
- if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) {
- if (attr & BITMAP_PAGE_NEEDWRITE) {
- page_cache_get(page);
- clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
- }
- spin_unlock_irqrestore(&bitmap->lock, flags);
- if (attr & BITMAP_PAGE_NEEDWRITE) {
- if (write_page(page, 0))
- bitmap_file_kick(bitmap);
- page_cache_release(page);
- }
- continue;
- }
-
- bit = file_page_offset(j);
if (page != lastpage) {
+ /* skip this page unless it's marked as needing cleaning */
+ if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) {
+ if (attr & BITMAP_PAGE_NEEDWRITE) {
+ page_cache_get(page);
+ clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
+ }
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ if (attr & BITMAP_PAGE_NEEDWRITE) {
+ if (write_page(bitmap, page, 0))
+ bitmap_file_kick(bitmap);
+ page_cache_release(page);
+ }
+ continue;
+ }
+
/* grab the new page, sync and release the old */
page_cache_get(page);
if (lastpage != NULL) {
if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
- write_page(lastpage, 0);
+ err = write_page(bitmap, lastpage, 0);
} else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
-1);
/* clear the bit */
- clear_bit(bit, page_address(page));
+ clear_bit(file_page_offset(j), page_address(page));
}
}
spin_unlock_irqrestore(&bitmap->lock, flags);
if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
- write_page(lastpage, 0);
+ err = write_page(bitmap, lastpage, 0);
} else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
struct page_list *item;
int err = 0;
- while (1) {
- PRINTK("%s: bitmap writeback daemon waiting...\n", bmname(bitmap));
- down_interruptible(&bitmap->write_done);
- if (signal_pending(current)) {
- printk(KERN_INFO
- "%s: bitmap writeback daemon got signal, exiting...\n",
- bmname(bitmap));
- break;
- }
+ if (signal_pending(current)) {
+ printk(KERN_INFO
+ "%s: bitmap writeback daemon got signal, exiting...\n",
+ bmname(bitmap));
+ err = -EINTR;
+ goto out;
+ }
- PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap));
- /* wait on bitmap page writebacks */
- while ((item = dequeue_page(bitmap, &bitmap->complete_pages))) {
- page = item->page;
- mempool_free(item, bitmap->write_pool);
- PRINTK("wait on page writeback: %p %lu\n", page, bitmap->writes_pending);
- wait_on_page_writeback(page);
- PRINTK("finished page writeback: %p %lu\n", page, bitmap->writes_pending);
- spin_lock(&bitmap->write_lock);
- if (!--bitmap->writes_pending)
- wake_up(&bitmap->write_wait);
- spin_unlock(&bitmap->write_lock);
- err = PageError(page);
- page_cache_release(page);
- if (err) {
- printk(KERN_WARNING "%s: bitmap file writeback "
- "failed (page %lu): %d\n",
- bmname(bitmap), page->index, err);
- bitmap_file_kick(bitmap);
- goto out;
- }
+ PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap));
+ /* wait on bitmap page writebacks */
+ while ((item = dequeue_page(bitmap))) {
+ page = item->page;
+ mempool_free(item, bitmap->write_pool);
+ PRINTK("wait on page writeback: %p\n", page);
+ wait_on_page_writeback(page);
+ PRINTK("finished page writeback: %p\n", page);
+
+ err = PageError(page);
+ page_cache_release(page);
+ if (err) {
+ printk(KERN_WARNING "%s: bitmap file writeback "
+ "failed (page %lu): %d\n",
+ bmname(bitmap), page->index, err);
+ bitmap_file_kick(bitmap);
+ goto out;
}
}
-out:
+ out:
+ wake_up(&bitmap->write_wait);
if (err) {
printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n",
- bmname(bitmap), err);
+ bmname(bitmap), err);
daemon_exit(bitmap, &bitmap->writeback_daemon);
}
- return;
}
static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr,
spin_lock_irqsave(&bitmap->lock, flags);
*ptr = NULL;
+
if (!bitmap->file) /* no need for daemon if there's no backing file */
goto out_unlock;
spin_unlock_irqrestore(&bitmap->lock, flags);
memset(kmap(page), 0xff, PAGE_SIZE);
kunmap(page);
- write_page(page, 0);
+ if (write_page(bitmap, page, 0))
+ return 1;
}
return 0;
BUG_ON(sizeof(bitmap_super_t) != 256);
- if (!file) /* bitmap disabled, nothing to do */
+ if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */
return 0;
+ BUG_ON(file && mddev->bitmap_offset);
+
bitmap = kmalloc(sizeof(*bitmap), GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
mddev->bitmap = bitmap;
spin_lock_init(&bitmap->write_lock);
- init_MUTEX_LOCKED(&bitmap->write_done);
INIT_LIST_HEAD(&bitmap->complete_pages);
init_waitqueue_head(&bitmap->write_wait);
bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc,
return -ENOMEM;
bitmap->file = file;
- get_file(file);
+ bitmap->offset = mddev->bitmap_offset;
+ if (file) get_file(file);
/* read superblock from bitmap file (this sets bitmap->chunksize) */
err = bitmap_read_sb(bitmap);
if (err)