1526 lines · 39.4 KB · C
RawDownload
/* * bitmap.c two-level bitmap (C) Peter T. Breuer (ptb@ot.uc3m.es) 2003 * * bitmap_create  - sets up the bitmap structure * bitmap_destroy - destroys the bitmap structure * * additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.: * - added disk storage for bitmap * - changes to allow various bitmap chunk sizes */ /* * Still to do: * * flush after percent set rather than just time based. (maybe both). * wait if count gets too high, wake when it drops to half. */ #include <linux/module.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/file.h>#include <linux/mount.h>#include <linux/buffer_head.h>#include <linux/raid/md.h>#include <linux/raid/bitmap.h> /* debug macros */ #define DEBUG 0 #if DEBUG/* these are for debugging purposes only! */ /* define one and only one of these */#define INJECT_FAULTS_1 0 /* cause bitmap_alloc_page to fail always */#define INJECT_FAULTS_2 0 /* cause bitmap file to be kicked when first bit set*/#define INJECT_FAULTS_3 0 /* treat bitmap file as kicked at init time */#define INJECT_FAULTS_4 0 /* undef */#define INJECT_FAULTS_5 0 /* undef */#define INJECT_FAULTS_6 0 /* if these are defined, the driver will fail! debug only */#define INJECT_FATAL_FAULT_1 0 /* fail kmalloc, causing bitmap_create to fail */#define INJECT_FATAL_FAULT_2 0 /* undef */#define INJECT_FATAL_FAULT_3 0 /* undef */#endif //#define DPRINTK PRINTK /* set this NULL to avoid verbose debug output */#define DPRINTK(x...) do { } while(0) #ifndef PRINTK#  if DEBUG > 0#    define PRINTK(x...) printk(KERN_DEBUG x)#  else#    define PRINTK(x...)#  endif#endif static inline char * bmname(struct bitmap *bitmap){	return bitmap->mddev ? mdname(bitmap->mddev) : "mdX";}  /* * just a placeholder - calls kmalloc for bitmap pages */static unsigned char *bitmap_alloc_page(struct bitmap *bitmap){	unsigned char *page; #ifdef INJECT_FAULTS_1	page = NULL;#else	page = kmalloc(PAGE_SIZE, GFP_NOIO);#endif	if (!page)		printk("%s: bitmap_alloc_page FAILED\n", bmname(bitmap));	else		PRINTK("%s: bitmap_alloc_page: allocated page at %p\n",			bmname(bitmap), page);	return page;} /* * for now just a placeholder -- just calls kfree for bitmap pages */static void bitmap_free_page(struct bitmap *bitmap, unsigned char *page){	PRINTK("%s: bitmap_free_page: free page %p\n", bmname(bitmap), page);	kfree(page);} /* * check a page and, if necessary, allocate it (or hijack it if the alloc fails) * * 1) check to see if this page is allocated, if it's not then try to alloc * 2) if the alloc fails, set the page's hijacked flag so we'll use the *    page pointer directly as a counter * * 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, unsigned long page, int create){	unsigned char *mappage; 	if (page >= bitmap->pages) {		printk(KERN_ALERT			"%s: invalid bitmap page request: %lu (> %lu)\n",			bmname(bitmap), page, bitmap->pages-1);		return -EINVAL;	}  	if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */		return 0; 	if (bitmap->bp[page].map) /* page is already allocated, just return */		return 0; 	if (!create)		return -ENOENT; 	spin_unlock_irq(&bitmap->lock); 	/* this page has not been allocated yet */ 	if ((mappage = bitmap_alloc_page(bitmap)) == NULL) {		PRINTK("%s: bitmap map page allocation failed, hijacking\n",			bmname(bitmap));		/* failed - set the hijacked flag so that we can use the		 * pointer as a counter */		spin_lock_irq(&bitmap->lock);		if (!bitmap->bp[page].map)			bitmap->bp[page].hijacked = 1;		goto out;	} 	/* got a page */ 	spin_lock_irq(&bitmap->lock); 	/* recheck the page */ 	if (bitmap->bp[page].map || bitmap->bp[page].hijacked) {		/* somebody beat us to getting the page */		bitmap_free_page(bitmap, mappage);		return 0;	} 	/* no page was in place and we have one, so install it */ 	memset(mappage, 0, PAGE_SIZE);	bitmap->bp[page].map = mappage;	bitmap->missing_pages--;out:	return 0;}  /* 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){	char *ptr; 	if (bitmap->bp[page].count) /* page is still busy */		return; 	/* page is no longer in use, it can be released */ 	if (bitmap->bp[page].hijacked) { /* page was hijacked, undo this now */		bitmap->bp[page].hijacked = 0;		bitmap->bp[page].map = NULL;		return;	} 	/* normal case, free the page */ #if 0/* actually ... let's not.  We will probably need the page again exactly when * memory is tight and we are flusing to disk */	return;#else	ptr = bitmap->bp[page].map;	bitmap->bp[page].map = NULL;	bitmap->missing_pages++;	bitmap_free_page(bitmap, ptr);	return;#endif}  /* * bitmap file handling - read and write the bitmap file and its superblock */ /* copy the pathname of a file to a buffer */char *file_path(struct file *file, char *buf, int count){	struct dentry *d;	struct vfsmount *v; 	if (!buf)		return NULL; 	d = file->f_path.dentry;	v = file->f_path.mnt; 	buf = d_path(d, v, buf, count); 	return IS_ERR(buf) ? NULL : buf;} /* * 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); 	ITERATE_RDEV(mddev, rdev, tmp) {		if (! test_bit(In_sync, &rdev->flags)		    || test_bit(Faulty, &rdev->flags))			continue; 		target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512); 		if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) {			page->index = index;			attach_page_buffers(page, NULL); /* so that free_buffer will							  * quietly no-op */			return page;		}	}	return ERR_PTR(-EIO); } 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 (test_bit(In_sync, &rdev->flags)		    && !test_bit(Faulty, &rdev->flags))			md_super_write(mddev, rdev,				       (rdev->sb_offset<<1) + offset				       + page->index * (PAGE_SIZE/512),				       PAGE_SIZE,				       page); 	if (wait)		md_super_wait(mddev);	return 0;} /* * write out a page to a file */static int write_page(struct bitmap *bitmap, struct page *page, int wait){	struct buffer_head *bh; 	if (bitmap->file == NULL)		return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); 	bh = page_buffers(page); 	while (bh && bh->b_blocknr) {		atomic_inc(&bitmap->pending_writes);		set_buffer_locked(bh);		set_buffer_mapped(bh);		submit_bh(WRITE, bh);		bh = bh->b_this_page;	} 	if (wait) {		wait_event(bitmap->write_wait,			   atomic_read(&bitmap->pending_writes)==0);		return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;	}	return 0;} static void end_bitmap_write(struct buffer_head *bh, int uptodate){	struct bitmap *bitmap = bh->b_private;	unsigned long flags; 	if (!uptodate) {		spin_lock_irqsave(&bitmap->lock, flags);		bitmap->flags |= BITMAP_WRITE_ERROR;		spin_unlock_irqrestore(&bitmap->lock, flags);	}	if (atomic_dec_and_test(&bitmap->pending_writes))		wake_up(&bitmap->write_wait);} /* copied from buffer.c */static void__clear_page_buffers(struct page *page){	ClearPagePrivate(page);	set_page_private(page, 0);	page_cache_release(page);}static void free_buffers(struct page *page){	struct buffer_head *bh = page_buffers(page); 	while (bh) {		struct buffer_head *next = bh->b_this_page;		free_buffer_head(bh);		bh = next;	}	__clear_page_buffers(page);	put_page(page);} /* read a page from a file. * We both read the page, and attach buffers to the page to record the * address of each block (using bmap).  These addresses will be used * to write the block later, completely bypassing the filesystem. * This usage is similar to how swap files are handled, and allows us * to write to a file with no concerns of memory allocation failing. */static struct page *read_page(struct file *file, unsigned long index,			      struct bitmap *bitmap,			      unsigned long count){	struct page *page = NULL;	struct inode *inode = file->f_path.dentry->d_inode;	struct buffer_head *bh;	sector_t block; 	PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE,			(unsigned long long)index << PAGE_SHIFT); 	page = alloc_page(GFP_KERNEL);	if (!page)		page = ERR_PTR(-ENOMEM);	if (IS_ERR(page))		goto out; 	bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);	if (!bh) {		put_page(page);		page = ERR_PTR(-ENOMEM);		goto out;	}	attach_page_buffers(page, bh);	block = index << (PAGE_SHIFT - inode->i_blkbits);	while (bh) {		if (count == 0)			bh->b_blocknr = 0;		else {			bh->b_blocknr = bmap(inode, block);			if (bh->b_blocknr == 0) {				/* Cannot use this file! */				free_buffers(page);				page = ERR_PTR(-EINVAL);				goto out;			}			bh->b_bdev = inode->i_sb->s_bdev;			if (count < (1<<inode->i_blkbits))				count = 0;			else				count -= (1<<inode->i_blkbits); 			bh->b_end_io = end_bitmap_write;			bh->b_private = bitmap;			atomic_inc(&bitmap->pending_writes);			set_buffer_locked(bh);			set_buffer_mapped(bh);			submit_bh(READ, bh);		}		block++;		bh = bh->b_this_page;	}	page->index = index; 	wait_event(bitmap->write_wait,		   atomic_read(&bitmap->pending_writes)==0);	if (bitmap->flags & BITMAP_WRITE_ERROR) {		free_buffers(page);		page = ERR_PTR(-EIO);	}out:	if (IS_ERR(page))		printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n",			(int)PAGE_SIZE,			(unsigned long long)index << PAGE_SHIFT,			PTR_ERR(page));	return page;} /* * bitmap file superblock operations */ /* update the event counter and sync the superblock to disk */int bitmap_update_sb(struct bitmap *bitmap){	bitmap_super_t *sb;	unsigned long flags; 	if (!bitmap || !bitmap->mddev) /* no bitmap for this array */		return 0;	spin_lock_irqsave(&bitmap->lock, flags);	if (!bitmap->sb_page) { /* no superblock */		spin_unlock_irqrestore(&bitmap->lock, flags);		return 0;	}	spin_unlock_irqrestore(&bitmap->lock, flags);	sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);	sb->events = cpu_to_le64(bitmap->mddev->events);	if (!bitmap->mddev->degraded)		sb->events_cleared = cpu_to_le64(bitmap->mddev->events);	kunmap_atomic(sb, KM_USER0);	return write_page(bitmap, bitmap->sb_page, 1);} /* print out the bitmap file superblock */void bitmap_print_sb(struct bitmap *bitmap){	bitmap_super_t *sb; 	if (!bitmap || !bitmap->sb_page)		return;	sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);	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",					*(__u32 *)(sb->uuid+0),					*(__u32 *)(sb->uuid+4),					*(__u32 *)(sb->uuid+8),					*(__u32 *)(sb->uuid+12));	printk(KERN_DEBUG "        events: %llu\n",			(unsigned long long) le64_to_cpu(sb->events));	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",			(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_atomic(sb, KM_USER0);} /* read the superblock from the bitmap file and initialize some bitmap fields */static int bitmap_read_sb(struct bitmap *bitmap){	char *reason = NULL;	bitmap_super_t *sb;	unsigned long chunksize, daemon_sleep, write_behind;	unsigned long long events;	int err = -EINVAL; 	/* page 0 is the superblock, read it... */	if (bitmap->file) {		loff_t isize = i_size_read(bitmap->file->f_mapping->host);		int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize; 		bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);	} else {		bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0);	}	if (IS_ERR(bitmap->sb_page)) {		err = PTR_ERR(bitmap->sb_page);		bitmap->sb_page = NULL;		return err;	} 	sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0); 	chunksize = le32_to_cpu(sb->chunksize);	daemon_sleep = le32_to_cpu(sb->daemon_sleep);	write_behind = le32_to_cpu(sb->write_behind);

Lines 1–500 of 1526.