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 + -
显示快捷键?