/* * 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 * - added bitmap daemon (to asynchronously clear bitmap bits from disk) */ /* * 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. * allow bitmap to be mirrored with superblock (before or after...) * allow hot-add to re-instate a current device. * allow hot-add of bitmap after quiessing device */ #include <linux/module.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/config.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";} /* * test if the bitmap is active */int bitmap_active(struct bitmap *bitmap){ unsigned long flags; int res = 0; if (!bitmap) return res; spin_lock_irqsave(&bitmap->lock, flags); res = bitmap->flags & BITMAP_ACTIVE; spin_unlock_irqrestore(&bitmap->lock, flags); return res;} #define WRITE_POOL_SIZE 256/* mempool for queueing pending writes on the bitmap file */static void *write_pool_alloc(unsigned int gfp_flags, void *data){ return kmalloc(sizeof(struct page_list), gfp_flags);} static void write_pool_free(void *ptr, void *data){ kfree(ptr);} /* * 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 inline 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_dentry; v = file->f_vfsmnt; 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); 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 to a file */static int write_page(struct bitmap *bitmap, struct page *page, int wait){ int ret = -ENOMEM; if (bitmap->file == NULL) return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); if (wait) lock_page(page); else { if (TestSetPageLocked(page)) return -EAGAIN; /* already locked */ if (PageWriteback(page)) { unlock_page(page); return -EAGAIN; } } 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_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);} /* read a page from a file, pinning it into cache, and return bytes_read */static struct page *read_page(struct file *file, unsigned long index, unsigned long *bytes_read){ struct inode *inode = file->f_mapping->host; struct page *page = NULL; loff_t isize = i_size_read(inode); unsigned long end_index = isize >> PAGE_CACHE_SHIFT; PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_CACHE_SIZE, (unsigned long long)index << PAGE_CACHE_SHIFT); page = read_cache_page(inode->i_mapping, index, (filler_t *)inode->i_mapping->a_ops->readpage, file); if (IS_ERR(page)) goto out; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) { page_cache_release(page); page = ERR_PTR(-EIO); goto out; } if (index > end_index) /* we have read beyond EOF */ *bytes_read = 0; else if (index == end_index) /* possible short read */ *bytes_read = isize & ~PAGE_CACHE_MASK; else *bytes_read = PAGE_CACHE_SIZE; /* got a full page */out: if (IS_ERR(page)) printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", (int)PAGE_CACHE_SIZE, (unsigned long long)index << PAGE_CACHE_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(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); 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(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", *(__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); kunmap(bitmap->sb_page);} /* 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; unsigned long bytes_read; unsigned long long events; int err = -EINVAL; /* page 0 is the superblock, read it... */ 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; return err; } sb = (bitmap_super_t *)kmap(bitmap->sb_page); if (bytes_read < sizeof(*sb)) { /* short read */ printk(KERN_INFO "%s: bitmap file superblock truncated\n", bmname(bitmap)); err = -ENOSPC; goto out; } chunksize = le32_to_cpu(sb->chunksize); daemon_sleep = le32_to_cpu(sb->daemon_sleep); /* verify that the bitmap-specific fields are valid */ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) reason = "bad magic"; else if (sb->version != cpu_to_le32(BITMAP_MAJOR)) reason = "unrecognized superblock version"; else if (chunksize < 512 || chunksize > (1024 * 1024 * 4)) reason = "bitmap chunksize out of range (512B - 4MB)"; else if ((1 << ffz(~chunksize)) != chunksize) reason = "bitmap chunksize not a power of 2"; else if (daemon_sleep < 1 || daemon_sleep > 15) reason = "daemon sleep period out of range"; if (reason) { printk(KERN_INFO "%s: invalid bitmap file superblock: %s\n", bmname(bitmap), reason); goto out; } /* keep the array size field of the bitmap superblock up to date */ sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors); if (!bitmap->mddev->persistent) goto success; Lines 1–500 of 1606. Load more
/* * 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 * - added bitmap daemon (to asynchronously clear bitmap bits from disk) */ /* * 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. * allow bitmap to be mirrored with superblock (before or after...) * allow hot-add to re-instate a current device. * allow hot-add of bitmap after quiessing device */ #include <linux/module.h> #include <linux/version.h> #include <linux/errno.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/config.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"; } /* * test if the bitmap is active */ int bitmap_active(struct bitmap *bitmap) { unsigned long flags; int res = 0; if (!bitmap) return res; spin_lock_irqsave(&bitmap->lock, flags); res = bitmap->flags & BITMAP_ACTIVE; spin_unlock_irqrestore(&bitmap->lock, flags); return res; } #define WRITE_POOL_SIZE 256 /* mempool for queueing pending writes on the bitmap file */ static void *write_pool_alloc(unsigned int gfp_flags, void *data) { return kmalloc(sizeof(struct page_list), gfp_flags); } static void write_pool_free(void *ptr, void *data) { kfree(ptr); } /* * 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 inline 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_dentry; v = file->f_vfsmnt; 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); 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 to a file */ static int write_page(struct bitmap *bitmap, struct page *page, int wait) { int ret = -ENOMEM; if (bitmap->file == NULL) return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); if (wait) lock_page(page); else { if (TestSetPageLocked(page)) return -EAGAIN; /* already locked */ if (PageWriteback(page)) { unlock_page(page); return -EAGAIN; } } 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_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); } /* read a page from a file, pinning it into cache, and return bytes_read */ static struct page *read_page(struct file *file, unsigned long index, unsigned long *bytes_read) { struct inode *inode = file->f_mapping->host; struct page *page = NULL; loff_t isize = i_size_read(inode); unsigned long end_index = isize >> PAGE_CACHE_SHIFT; PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_CACHE_SIZE, (unsigned long long)index << PAGE_CACHE_SHIFT); page = read_cache_page(inode->i_mapping, index, (filler_t *)inode->i_mapping->a_ops->readpage, file); if (IS_ERR(page)) goto out; wait_on_page_locked(page); if (!PageUptodate(page) || PageError(page)) { page_cache_release(page); page = ERR_PTR(-EIO); goto out; } if (index > end_index) /* we have read beyond EOF */ *bytes_read = 0; else if (index == end_index) /* possible short read */ *bytes_read = isize & ~PAGE_CACHE_MASK; else *bytes_read = PAGE_CACHE_SIZE; /* got a full page */ out: if (IS_ERR(page)) printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n", (int)PAGE_CACHE_SIZE, (unsigned long long)index << PAGE_CACHE_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(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); 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(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", *(__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); kunmap(bitmap->sb_page); } /* 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; unsigned long bytes_read; unsigned long long events; int err = -EINVAL; /* page 0 is the superblock, read it... */ 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; return err; } sb = (bitmap_super_t *)kmap(bitmap->sb_page); if (bytes_read < sizeof(*sb)) { /* short read */ printk(KERN_INFO "%s: bitmap file superblock truncated\n", bmname(bitmap)); err = -ENOSPC; goto out; } chunksize = le32_to_cpu(sb->chunksize); daemon_sleep = le32_to_cpu(sb->daemon_sleep); /* verify that the bitmap-specific fields are valid */ if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) reason = "bad magic"; else if (sb->version != cpu_to_le32(BITMAP_MAJOR)) reason = "unrecognized superblock version"; else if (chunksize < 512 || chunksize > (1024 * 1024 * 4)) reason = "bitmap chunksize out of range (512B - 4MB)"; else if ((1 << ffz(~chunksize)) != chunksize) reason = "bitmap chunksize not a power of 2"; else if (daemon_sleep < 1 || daemon_sleep > 15) reason = "daemon sleep period out of range"; if (reason) { printk(KERN_INFO "%s: invalid bitmap file superblock: %s\n", bmname(bitmap), reason); goto out; } /* keep the array size field of the bitmap superblock up to date */ sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors); if (!bitmap->mddev->persistent) goto success;