bitmap.c
来自「linux 内核源代码」· C语言 代码 · 共 1,568 行 · 第 1/3 页
C
1,568 行
struct page *page = NULL, *lastpage = NULL; int blocks; void *paddr; if (bitmap == NULL) return; if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ)) return; bitmap->daemon_lastrun = jiffies; for (j = 0; j < bitmap->chunks; j++) { bitmap_counter_t *bmc; spin_lock_irqsave(&bitmap->lock, flags); if (!bitmap->filemap) { /* error or shutdown */ spin_unlock_irqrestore(&bitmap->lock, flags); 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_CLEAN)) { 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); 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); spin_unlock_irqrestore(&bitmap->lock, flags); } } else spin_unlock_irqrestore(&bitmap->lock, flags); lastpage = page;/* printk("bitmap clean at page %lu\n", j);*/ spin_lock_irqsave(&bitmap->lock, flags); clear_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } bmc = bitmap_get_counter(bitmap, j << CHUNK_BLOCK_SHIFT(bitmap), &blocks, 0); if (bmc) {/* if (j < 100) printk("bitmap: j=%lu, *bmc = 0x%x\n", j, *bmc);*/ if (*bmc == 2) { *bmc=1; /* maybe clear the bit next time */ set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } else if (*bmc == 1) { /* we can clear the bit */ *bmc = 0; bitmap_count_page(bitmap, j << CHUNK_BLOCK_SHIFT(bitmap), -1); /* clear the bit */ paddr = kmap_atomic(page, KM_USER0); if (bitmap->flags & BITMAP_HOSTENDIAN) clear_bit(file_page_offset(j), paddr); else ext2_clear_bit(file_page_offset(j), paddr); kunmap_atomic(paddr, KM_USER0); } } 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); spin_unlock_irqrestore(&bitmap->lock, flags); } }}static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap, sector_t offset, int *blocks, int create){ /* If 'create', we might release the lock and reclaim it. * The lock must have been taken with interrupts enabled. * If !create, we don't release the lock. */ sector_t chunk = offset >> CHUNK_BLOCK_SHIFT(bitmap); unsigned long page = chunk >> PAGE_COUNTER_SHIFT; unsigned long pageoff = (chunk & PAGE_COUNTER_MASK) << COUNTER_BYTE_SHIFT; sector_t csize; if (bitmap_checkpage(bitmap, page, create) < 0) { csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap)); *blocks = csize - (offset & (csize- 1)); return NULL; } /* now locked ... */ if (bitmap->bp[page].hijacked) { /* hijacked pointer */ /* should we use the first or second counter field * of the hijacked pointer? */ int hi = (pageoff > PAGE_COUNTER_MASK); csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap) + PAGE_COUNTER_SHIFT - 1); *blocks = csize - (offset & (csize- 1)); return &((bitmap_counter_t *) &bitmap->bp[page].map)[hi]; } else { /* page is allocated */ csize = ((sector_t)1) << (CHUNK_BLOCK_SHIFT(bitmap)); *blocks = csize - (offset & (csize- 1)); return (bitmap_counter_t *) &(bitmap->bp[page].map[pageoff]); }}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; spin_lock_irq(&bitmap->lock); bmc = bitmap_get_counter(bitmap, offset, &blocks, 1); if (!bmc) { spin_unlock_irq(&bitmap->lock); return 0; } if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) { DEFINE_WAIT(__wait); /* note that it is safe to do the prepare_to_wait * after the test as long as we do it before dropping * the spinlock. */ prepare_to_wait(&bitmap->overflow_wait, &__wait, TASK_UNINTERRUPTIBLE); spin_unlock_irq(&bitmap->lock); blk_unplug(bitmap->mddev->queue); schedule(); finish_wait(&bitmap->overflow_wait, &__wait); continue; } switch(*bmc) { case 0: bitmap_file_set_bit(bitmap, offset); bitmap_count_page(bitmap,offset, 1); blk_plug_device(bitmap->mddev->queue); /* fall through */ case 1: *bmc = 2; } (*bmc)++; spin_unlock_irq(&bitmap->lock); offset += blocks; if (sectors > blocks) sectors -= blocks; else sectors = 0; } return 0;}void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, 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; bitmap_counter_t *bmc; spin_lock_irqsave(&bitmap->lock, flags); bmc = bitmap_get_counter(bitmap, offset, &blocks, 0); if (!bmc) { spin_unlock_irqrestore(&bitmap->lock, flags); return; } if (!success && ! (*bmc & NEEDED_MASK)) *bmc |= NEEDED_MASK; if ((*bmc & COUNTER_MAX) == COUNTER_MAX) wake_up(&bitmap->overflow_wait); (*bmc)--; if (*bmc <= 2) { set_page_attr(bitmap, filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)), BITMAP_PAGE_CLEAN); } spin_unlock_irqrestore(&bitmap->lock, flags); offset += blocks; if (sectors > blocks) sectors -= blocks; else sectors = 0; }}int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded){ bitmap_counter_t *bmc; int rv; if (bitmap == NULL) {/* FIXME or bitmap set as 'failed' */ *blocks = 1024; return 1; /* always resync if no bitmap */ } spin_lock_irq(&bitmap->lock); bmc = bitmap_get_counter(bitmap, offset, blocks, 0); rv = 0; if (bmc) { /* locked */ if (RESYNC(*bmc)) rv = 1; else if (NEEDED(*bmc)) { rv = 1; if (!degraded) { /* don't set/clear bits if degraded */ *bmc |= RESYNC_MASK; *bmc &= ~NEEDED_MASK; } } } spin_unlock_irq(&bitmap->lock); return rv;}void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted){ bitmap_counter_t *bmc; unsigned long flags;/* if (offset == 0) printk("bitmap_end_sync 0 (%d)\n", aborted);*/ if (bitmap == NULL) { *blocks = 1024; return; } spin_lock_irqsave(&bitmap->lock, flags); bmc = bitmap_get_counter(bitmap, offset, blocks, 0); if (bmc == NULL) goto unlock; /* locked *//* if (offset == 0) printk("bitmap_end sync found 0x%x, blocks %d\n", *bmc, *blocks);*/ if (RESYNC(*bmc)) { *bmc &= ~RESYNC_MASK; if (!NEEDED(*bmc) && aborted) *bmc |= NEEDED_MASK; else { if (*bmc <= 2) { set_page_attr(bitmap, filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)), BITMAP_PAGE_CLEAN); } } } unlock: spin_unlock_irqrestore(&bitmap->lock, flags);}void bitmap_close_sync(struct bitmap *bitmap){ /* Sync has finished, and any bitmap chunks that weren't synced * properly have been aborted. It remains to us to clear the * RESYNC bit wherever it is still on */ sector_t sector = 0; int blocks; if (!bitmap) return; while (sector < bitmap->mddev->resync_max_sectors) { bitmap_end_sync(bitmap, sector, &blocks, 0);/* if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n", (unsigned long long)sector, blocks);*/ sector += blocks; }}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. They should all * be 0 at this point */ 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 | (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);}/* dirty the memory and file bits for bitmap chunks "s" to "e" */void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e){ unsigned long chunk; for (chunk = s; chunk <= e; chunk++) { sector_t sec = chunk << CHUNK_BLOCK_SHIFT(bitmap); bitmap_set_memory_bits(bitmap, sec, 1); bitmap_file_set_bit(bitmap, sec); }}/* * 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 */static void bitmap_free(struct bitmap *bitmap){ unsigned long k, pages; struct bitmap_page *bp; if (!bitmap) /* there was no bitmap */ return; /* release the bitmap file and kill the daemon */ bitmap_file_put(bitmap); bp = bitmap->bp; pages = bitmap->pages; /* free all allocated memory */ if (bp) /* deallocate the page memory */ for (k = 0; k < pages; k++) if (bp[k].map && !bp[k].hijacked) kfree(bp[k].map); 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 */ if (mddev->thread) mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; bitmap_free(bitmap);}/* * initialize the bitmap structure * if this returns an error, bitmap_destroy must be called to do clean up */int bitmap_create(mddev_t *mddev){ struct bitmap *bitmap; unsigned long blocks = mddev->resync_max_sectors; unsigned long chunks; unsigned long pages; struct file *file = mddev->bitmap_file; int err; sector_t start; BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */ return 0; BUG_ON(file && mddev->bitmap_offset); bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL); if (!bitmap) return -ENOMEM; spin_lock_init(&bitmap->lock); atomic_set(&bitmap->pending_writes, 0); init_waitqueue_head(&bitmap->write_wait); init_waitqueue_head(&bitmap->overflow_wait); bitmap->mddev = mddev; bitmap->file = file; bitmap->offset = mddev->bitmap_offset; if (file) { get_file(file); do_sync_mapping_range(file->f_mapping, 0, LLONG_MAX, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER); } /* read superblock from bitmap file (this sets bitmap->chunksize) */ err = bitmap_read_sb(bitmap); if (err) goto error; bitmap->chunkshift = ffz(~bitmap->chunksize); /* now that chunksize and chunkshift are set, we can use these macros */ chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) / CHUNK_BLOCK_RATIO(bitmap); pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO; BUG_ON(!pages); bitmap->chunks = chunks; bitmap->pages = pages; bitmap->missing_pages = pages; bitmap->counter_bits = COUNTER_BITS; bitmap->syncchunk = ~0UL;#ifdef INJECT_FATAL_FAULT_1 bitmap->bp = NULL;#else bitmap->bp = kzalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL);#endif err = -ENOMEM; if (!bitmap->bp) goto error; /* now that we have some pages available, initialize the in-memory * bitmap from the on-disk bitmap */ 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) goto error; printk(KERN_INFO "created bitmap (%lu pages) for device %s\n", pages, bmname(bitmap)); mddev->bitmap = bitmap; mddev->thread->timeout = bitmap->daemon_sleep * HZ; bitmap_update_sb(bitmap); return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0; error: bitmap_free(bitmap); return err;}/* the bitmap API -- for raid personalities */EXPORT_SYMBOL(bitmap_startwrite);EXPORT_SYMBOL(bitmap_endwrite);EXPORT_SYMBOL(bitmap_start_sync);EXPORT_SYMBOL(bitmap_end_sync);EXPORT_SYMBOL(bitmap_unplug);EXPORT_SYMBOL(bitmap_close_sync);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?