bitmap.c
来自「linux 内核源代码」· C语言 代码 · 共 1,568 行 · 第 1/3 页
C
1,568 行
/* * 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#endifstatic 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(struct bitmap *bitmap, struct page *page, int wait){ mdk_rdev_t *rdev; struct list_head *tmp; mddev_t *mddev = bitmap->mddev; ITERATE_RDEV(mddev, rdev, tmp) if (test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) { int size = PAGE_SIZE; if (page->index == bitmap->file_pages-1) size = roundup(bitmap->last_page_size, bdev_hardsect_size(rdev->bdev)); /* Just make sure we aren't corrupting data or * metadata */ if (bitmap->offset < 0) { /* DATA BITMAP METADATA */ if (bitmap->offset + (long)(page->index * (PAGE_SIZE/512)) + size/512 > 0) /* bitmap runs in to metadata */ return -EINVAL; if (rdev->data_offset + mddev->size*2 > rdev->sb_offset*2 + bitmap->offset) /* data runs in to bitmap */ return -EINVAL; } else if (rdev->sb_offset*2 < rdev->data_offset) { /* METADATA BITMAP DATA */ if (rdev->sb_offset*2 + bitmap->offset + page->index*(PAGE_SIZE/512) + size/512 > rdev->data_offset) /* bitmap runs in to data */ return -EINVAL; } else { /* DATA METADATA BITMAP - no problems */ } md_super_write(mddev, rdev, (rdev->sb_offset<<1) + bitmap->offset + page->index * (PAGE_SIZE/512), size, page); } if (wait) md_super_wait(mddev); return 0;}static void bitmap_file_kick(struct bitmap *bitmap);/* * write out a page to a file */static void write_page(struct bitmap *bitmap, struct page *page, int wait){ struct buffer_head *bh; if (bitmap->file == NULL) { switch (write_sb_page(bitmap, page, wait)) { case -EINVAL: bitmap->flags |= BITMAP_WRITE_ERROR; } } else { 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); } } if (bitmap->flags & BITMAP_WRITE_ERROR) bitmap_file_kick(bitmap);}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 */void bitmap_update_sb(struct bitmap *bitmap){ bitmap_super_t *sb; unsigned long flags; if (!bitmap || !bitmap->mddev) /* no bitmap for this array */ return; spin_lock_irqsave(&bitmap->lock, flags); if (!bitmap->sb_page) { /* no superblock */ spin_unlock_irqrestore(&bitmap->lock, flags); return; } 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); 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?