--- drivers/md/lvm.c.org Mon Nov 19 17:56:04 2001 +++ drivers/md/lvm.c Tue Oct 2 21:14:41 2001 @@ -1,13 +1,13 @@ /* * kernel/lvm.c * - * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software * * February-November 1997 * April-May,July-August,November 1998 * January-March,May,July,September,October 1999 * January,February,July,September-November 2000 - * January 2001 + * January-April 2001 * * * LVM driver is free software; you can redistribute it and/or modify @@ -43,7 +43,8 @@ * support for free (eg. longer) logical volume names * 12/05/1998 - added spin_locks (thanks to Pascal van Dam * ) - * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() + * 25/05/1998 - fixed handling of locked PEs in lvm_map() and + * lvm_chr_ioctl() * 26/05/1998 - reactivated verify_area by access_ok * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go * beyond 128/256 KB max allocation limit per call @@ -125,7 +126,8 @@ * 14/02/2000 - support for 2.3.43 * - integrated Andrea Arcagneli's snapshot code * 25/06/2000 - james (chip) , IKKHAYD! roffl - * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume support + * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume + * support * 06/09/2000 - added devfs support * 07/09/2000 - changed IOP version to 9 * - started to add new char ioctl LV_STATUS_BYDEV_T to support @@ -147,15 +149,24 @@ * 08/01/2001 - Removed conditional compiles related to PROC_FS, * procfs is always supported now. (JT) * 12/01/2001 - avoided flushing logical volume in case of shrinking - * because of unnecessary overhead in case of heavy updates + * because of unecessary overhead in case of heavy updates * 25/01/2001 - Allow RO open of an inactive LV so it can be reactivated. - * 31/01/2001 - If you try and BMAP a snapshot you now get an -EPERM - * 01/02/2001 - factored __remap_snapshot out of lvm_map + * 31/01/2001 - removed blk_init_queue/blk_cleanup_queue queueing will be + * handled by the proper devices. + * - If you try and BMAP a snapshot you now get an -EPERM + * 01/01/2001 - lvm_map() now calls buffer_IO_error on error for 2.4 + * - factored __remap_snapshot out of lvm_map * 12/02/2001 - move devfs code to create VG before LVs - * 14/02/2001 - tidied device defines for blk.h + * 13/02/2001 - allow VG_CREATE on /dev/lvm + * 14/02/2001 - removed modversions.h + * - tidied device defines for blk.h * - tidied debug statements + * - bug: vg[] member not set back to NULL if activation fails * - more lvm_map tidying - * 14/02/2001 - bug: vg[] member not set back to NULL if activation fails + * 15/02/2001 - register /dev/lvm with devfs correctly (major/minor + * were swapped) + * 19/02/2001 - preallocated buffer_heads for rawio when using + * snapshots [JT] * 28/02/2001 - introduced the P_DEV macro and changed some internel * functions to be static [AD] * 28/02/2001 - factored lvm_get_snapshot_use_rate out of blk_ioctl [AD] @@ -163,40 +174,67 @@ * where the check for an existing LV takes place right at * the beginning * 01/03/2001 - Add VG_CREATE_OLD for IOP 10 compatibility - * 02/03/2001 - Don't destroy usermode pointers in lv_t structures duing LV_ - * STATUS_BYxxx and remove redundant lv_t variables from same. + * 02/03/2001 - Don't destroy usermode pointers in lv_t structures duing + * LV_STATUS_BYxxx + * and remove redundant lv_t variables from same. + * - avoid compilation of lvm_dummy_device_request in case of + * Linux >= 2.3.0 to avoid a warning + * - added lvm_name argument to printk in buffer allocation + * in order to avoid a warning + * 04/03/2001 - moved linux/version.h above first use of KERNEL_VERSION + * macros * 05/03/2001 - restore copying pe_t array in lvm_do_lv_status_byname. For * lvdisplay -v (PC) * - restore copying pe_t array in lvm_do_lv_status_byindex (HM) * - added copying pe_t array in lvm_do_lv_status_bydev (HM) * - enhanced lvm_do_lv_status_by{name,index,dev} to be capable * to copy the lv_block_exception_t array to userspace (HM) - * 08/03/2001 - factored lvm_do_pv_flush out of lvm_chr_ioctl [HM] + * 08/03/2001 - initialize new lv_ptr->lv_COW_table_iobuf for snapshots; + * removed obsolete lv_ptr->lv_COW_table_page initialization + * - factored lvm_do_pv_flush out of lvm_chr_ioctl (HM) * 09/03/2001 - Added _lock_open_count to ensure we only drop the lock * when the locking process closes. - * 05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it - * destroys stacking devices. call b_end_io on failed maps. - * (Jens Axboe) - * - Defer writes to an extent that is being moved [JT + AD] - * 28/05/2001 - implemented missing BLKSSZGET ioctl [AD] + * 05/04/2001 - Defer writes to an extent that is being moved [JT] + * 05/04/2001 - use b_rdev and b_rsector rather than b_dev and b_blocknr in + * lvm_map() in order to make stacking devices more happy (HM) + * 11/04/2001 - cleaned up the pvmove queue code. I no longer retain the + * rw flag, instead WRITEA's are just dropped [JT] + * 30/04/2001 - added KERNEL_VERSION > 2.4.3 get_hardsect_size() rather + * than get_hardblocksize() call + * 03/05/2001 - Use copy_to/from_user to preserve pointers in + * lvm_do_status_by* + * 11/05/2001 - avoid accesses to inactive snapshot data in + * __update_hardsectsize() and lvm_do_lv_extend_reduce() (JW) + * 28/05/2001 - implemented missing BLKSSZGET ioctl + * 05/06/2001 - Move _pe_lock out of fast path for lvm_map when no PEs + * locked. Make buffer queue flush not need locking. + * Fix lvm_user_bmap() to set b_rsector for new lvm_map(). [AED] + * 30/06/2001 - Speed up __update_hardsectsize() by checking if PVs have + * the same hardsectsize (very likely) before scanning all LEs + * in the LV each time. [AED] * */ +#include #define MAJOR_NR LVM_BLK_MAJOR #define DEVICE_OFF(device) +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 0) +#define DEVICE_REQUEST lvm_dummy_device_request +#endif #define LOCAL_END_REQUEST /* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */ /* #define LVM_VFS_ENHANCEMENT */ #include - #include - #include #include + +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 39) #include +#endif #include #include @@ -206,6 +244,11 @@ #include #include #include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) +#include +#endif + #include #include #include @@ -217,7 +260,9 @@ #endif #include +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) #include +#endif #include #include @@ -236,7 +281,11 @@ /* * External function prototypes */ +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 42) static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*); +#else +static int lvm_make_request_fn(struct buffer_head *bh, int rw); +#endif static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); @@ -256,7 +305,11 @@ /* * Internal function prototypes */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) +void lvm_cleanup(void); +#else static void lvm_cleanup(void); +#endif static void lvm_init_vars(void); #ifdef LVM_HD_NAME @@ -289,7 +342,16 @@ static int lvm_do_vg_remove(int); static void lvm_geninit(struct gendisk *); static void __update_hardsectsize(lv_t *lv); +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 4, 4) +#define lvm_sectsize(dev) get_hardblocksize(dev) +#else +#define lvm_sectsize(dev) get_hardsect_size(dev) +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) +static struct buffer_head **__allocate_bheads(void); +static void __free_bheads(struct buffer_head **bheads); +#endif static void _queue_io(struct buffer_head *bh, int rw); static struct buffer_head *_dequeue_io(void); @@ -316,6 +378,11 @@ /* volume group descriptor area pointers */ vg_t *vg[ABS_MAX_VG]; +static pv_t *pvp = NULL; +static lv_t *lvp = NULL; +static pe_t *pep = NULL; + + /* map from block minor number to VG and LV numbers */ typedef struct { int vg_number; @@ -341,7 +408,12 @@ static int _lock_open_count = 0; static uint vg_count = 0; static long lvm_chr_open_count = 0; +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); +#else +struct wait_queue *lvm_snapshot_wait = NULL; +struct wait_queue *lvm_wait = NULL; +#endif static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; @@ -356,14 +428,25 @@ ioctl: lvm_chr_ioctl, }; +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 38) +static struct file_operations lvm_blk_fops = +{ + open: lvm_blk_open, + read: block_read, + write: block_write, + release: lvm_blk_close, + ioctl: lvm_blk_ioctl, + fsync: block_fsync, +}; +#else /* block device operations structure needed for 2.3.38? and above */ struct block_device_operations lvm_blk_dops = { - owner: THIS_MODULE, - open: lvm_blk_open, + open: lvm_blk_open, release: lvm_blk_close, ioctl: lvm_blk_ioctl, }; +#endif /* gendisk structures */ @@ -374,13 +457,22 @@ static struct gendisk lvm_gendisk = { - major: MAJOR_NR, - major_name: LVM_NAME, - minor_shift: 0, - max_p: 1, - part: lvm_hd_struct, - sizes: lvm_size, - nr_real: MAX_LV, + MAJOR_NR, /* major # */ + LVM_NAME, /* name of major */ + 0, /* number of times minor is shifted + to get real minor */ + 1, /* maximum partitions per device */ +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 40) + MAX_LV, /* maximum number of real devices */ + lvm_geninit, /* initialization called before we + do other things */ +#endif + lvm_hd_struct, /* partition table */ + lvm_size, /* device size in blocks, copied + to block_size[] */ + MAX_LV, /* number or real devices */ + NULL, /* internal */ + NULL, /* pointer to next gendisk struct (internal) */ }; /* @@ -388,14 +480,19 @@ */ int lvm_init(void) { + struct gendisk *gendisk_ptr = NULL; + if (devfs_register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) { printk(KERN_ERR "%s -- devfs_register_chrdev failed\n", lvm_name); return -EIO; } - +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 37) if (devfs_register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) +#else + if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0) +#endif { printk("%s -- devfs_register_blkdev failed\n", lvm_name); if (devfs_unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) @@ -409,15 +506,35 @@ lvm_init_vars(); lvm_geninit(&lvm_gendisk); - add_gendisk(&lvm_gendisk); + /* insert our gendisk at the corresponding major */ + if (gendisk_head != NULL) { + gendisk_ptr = gendisk_head; + while (gendisk_ptr->next != NULL && + gendisk_ptr->major > lvm_gendisk.major) { + gendisk_ptr = gendisk_ptr->next; + } + lvm_gendisk.next = gendisk_ptr->next; + gendisk_ptr->next = &lvm_gendisk; + } else { + gendisk_head = &lvm_gendisk; + lvm_gendisk.next = NULL; + } #ifdef LVM_HD_NAME /* reference from drivers/block/genhd.c */ lvm_hd_name_ptr = lvm_hd_name; #endif +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 42) blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); +#else + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blk_dev[MAJOR_NR].current_request = NULL; +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 0) + blk_dev[MAJOR_NR].make_req_fn = lvm_make_request_fn; +#endif /* initialise the pe lock */ pe_lock_req.lock = UNLOCK_PE; @@ -436,12 +553,18 @@ return 0; } /* lvm_init() */ - /* * cleanup... */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 30) +void lvm_cleanup(void) +#else static void lvm_cleanup(void) +#endif { + struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; + if (devfs_unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) printk(KERN_ERR "%s -- devfs_unregister_chrdev failed\n", lvm_name); @@ -449,7 +572,25 @@ printk(KERN_ERR "%s -- devfs_unregister_blkdev failed\n", lvm_name); - del_gendisk(&lvm_gendisk); +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 30) + blk_dev[MAJOR_NR].request_fn = NULL; + blk_dev[MAJOR_NR].current_request = NULL; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 0) + blk_dev[MAJOR_NR].make_req_fn = NULL; +#endif + + gendisk_ptr = gendisk_ptr_prev = gendisk_head; + while (gendisk_ptr != NULL) { + if (gendisk_ptr == &lvm_gendisk) + break; + gendisk_ptr_prev = gendisk_ptr; + gendisk_ptr = gendisk_ptr->next; + } + /* delete our gendisk from chain */ + if (gendisk_ptr == &lvm_gendisk) + gendisk_ptr_prev->next = gendisk_ptr->next; blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; @@ -514,7 +655,7 @@ */ static int lvm_chr_open(struct inode *inode, struct file *file) { - unsigned int minor = MINOR(inode->i_rdev); + int minor = MINOR(inode->i_rdev); P_DEV("chr_open MINOR: %d VG#: %d mode: %s%s lock: %d\n", minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock); @@ -525,10 +666,10 @@ /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; - spin_lock(&lvm_lock); - if(lock == current->pid) - _lock_open_count++; - spin_unlock(&lvm_lock); + spin_lock(&lvm_lock); + if(lock == current->pid) + _lock_open_count++; + spin_unlock(&lvm_lock); lvm_chr_open_count++; @@ -610,8 +751,8 @@ /* create a VGDA */ return lvm_do_vg_create(arg, minor); - case VG_CREATE: - /* create a VGDA, assume VG number is filled in */ + case VG_CREATE: + /* create a VGDA, assume VG number is filled in */ return lvm_do_vg_create(arg, -1); case VG_EXTEND: @@ -734,7 +875,7 @@ case PV_FLUSH: /* physical volume buffer flush/invalidate */ - return lvm_do_pv_flush(arg); + return lvm_do_pv_flush(arg); default: @@ -765,16 +906,16 @@ if (lvm_chr_open_count > 0) lvm_chr_open_count--; - spin_lock(&lvm_lock); - if(lock == current->pid) { - if(!_lock_open_count) { + spin_lock(&lvm_lock); + if(lock == current->pid) { + if(!_lock_open_count) { P_DEV("chr_close: unlocking LVM for pid %d\n", lock); - lock = 0; - wake_up_interruptible(&lvm_wait); - } else - _lock_open_count--; + lock = 0; + wake_up_interruptible(&lvm_wait); + } else + _lock_open_count--; } - spin_unlock(&lvm_lock); + spin_unlock(&lvm_lock); MOD_DEC_USE_COUNT; @@ -812,7 +953,7 @@ LV_BLK(minor) >= 0 && LV_BLK(minor) < vg_ptr->lv_max) { - /* Check parallel LV spindown (LV remove) */ + /* Check parallel LV spindown (LV remove) */ if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ @@ -826,6 +967,9 @@ (file->f_mode & FMODE_WRITE)) return -EACCES; +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 38) + file->f_op = &lvm_blk_fops; +#endif /* be sure to increment VG counter */ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; @@ -860,17 +1004,12 @@ switch (command) { case BLKSSZGET: /* get block device sector size as needed e.g. by fdisk */ - return put_user(get_hardsect_size(inode->i_rdev), (int *) arg); + return put_user(lvm_sectsize(inode->i_rdev), (int *) arg); case BLKGETSIZE: /* return device size */ P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size); - if (put_user(lv_ptr->lv_size, (unsigned long *)arg)) - return -EFAULT; - break; - - case BLKGETSIZE64: - if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg)) + if (put_user(lv_ptr->lv_size, (long *)arg)) return -EFAULT; break; @@ -960,7 +1099,9 @@ if(lv_ptr->lv_access & LV_SNAPSHOT) return -EPERM; + /* turn logical block into (dev_t, block). non privileged. */ return lvm_user_bmap(inode, (struct lv_bmap *) arg); + break; case LV_SET_ALLOCATION: /* set allocation flags of a logical volume */ @@ -994,6 +1135,7 @@ P_DEV("blk_close MINOR: %d VG#: %d LV#: %d\n", minor, VG_BLK(minor), LV_BLK(minor)); + sync_dev(inode->i_rdev); if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; lv_ptr->lv_open--; @@ -1048,15 +1190,14 @@ bh.b_blocknr = block; bh.b_dev = bh.b_rdev = inode->i_rdev; bh.b_size = lvm_get_blksize(bh.b_dev); - bh.b_rsector = block * (bh.b_size >> 9); + bh.b_rsector = block * (bh.b_size >> 9); if ((err=lvm_map(&bh, READ)) < 0) { printk("lvm map failed: %d\n", err); return -EINVAL; } - return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || - put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block) ? - -EFAULT : 0; + return (put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || + put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block)); } @@ -1065,7 +1206,7 @@ * (see init_module/lvm_init) */ static void __remap_snapshot(kdev_t rdev, ulong rsector, - ulong pe_start, lv_t *lv, vg_t *vg) { + ulong pe_start, lv_t *lv, vg_t *vg) { /* copy a chunk from the origin to a snapshot device */ down_write(&lv->lv_lock); @@ -1122,6 +1263,7 @@ return 0; } + static int lvm_map(struct buffer_head *bh, int rw) { int minor = MINOR(bh->b_rdev); @@ -1245,7 +1387,7 @@ _remap_snapshot(rdev_map, rsector_map, pe_start, snap, vg_this); } - } + } out: bh->b_rdev = rdev_map; @@ -1254,7 +1396,9 @@ return 1; bad: +#if LINUX_VERSION_CODE >= KERNEL_VERSION ( 2, 4, 0) buffer_IO_error(bh); +#endif up_read(&lv->lv_lock); return -1; } /* lvm_map() */ @@ -1284,14 +1428,34 @@ #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 0) +/* + * this one never should be called... + */ +static void lvm_dummy_device_request(void) +{ + printk(KERN_EMERG "%s -- oops, got lvm request for %s [sector: %lu]\n", + lvm_name, kdevname(CURRENT->rq_dev), CURRENT->sector); + return; +} +#endif + + /* * make request function */ +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 48) static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh) { return (lvm_map(bh, rw) <= 0) ? 0 : 1; } +#else +static int lvm_make_request_fn(struct buffer_head *bh, int rw) { + int r = lvm_map(bh, rw); + return (r <= 0) ? r : 1; +} +#endif /******************************************************************** @@ -1457,14 +1621,14 @@ return -EFAULT; } - /* VG_CREATE now uses minor number in VG structure */ - if (minor == -1) minor = vg_ptr->vg_number; + /* VG_CREATE now uses minor number in VG structure */ + if (minor == -1) minor = vg_ptr->vg_number; /* Validate it */ - if (vg[VG_CHR(minor)] != NULL) { + if (vg[VG_CHR(minor)] != NULL) { P_IOCTL("lvm_do_vg_create ERROR: VG %d in use\n", minor); kfree(vg_ptr); - return -EPERM; + return -EPERM; } /* we are not that active so far... */ @@ -1495,7 +1659,6 @@ /* get the physical volume structures */ vg_ptr->pv_act = vg_ptr->pv_cur = 0; for (p = 0; p < vg_ptr->pv_max; p++) { - pv_t *pvp; /* user space address */ if ((pvp = vg_ptr->pv[p]) != NULL) { ret = lvm_do_pv_create(pvp, vg_ptr, p); @@ -1519,7 +1682,6 @@ /* get the logical volume structures */ vg_ptr->lv_cur = 0; for (l = 0; l < vg_ptr->lv_max; l++) { - lv_t *lvp; /* user space address */ if ((lvp = vg_ptr->lv[l]) != NULL) { if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { @@ -1546,7 +1708,7 @@ /* Second path to correct snapshot logical volumes which are not in place during first path above */ for (l = 0; l < ls; l++) { - lv_t *lvp = snap_lv_ptr[l]; + lvp = snap_lv_ptr[l]; if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { lvm_do_vg_remove(minor); return -EFAULT; @@ -1637,7 +1799,8 @@ lv_t *lv_ptr = NULL; pv_t *pv_ptr = NULL; - if (vg_ptr == NULL) return -ENXIO; + /* If the VG doesn't exist in the kernel then just exit */ + if (!vg_ptr) return 0; if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0) return -EFAULT; @@ -1797,30 +1960,56 @@ } -static void __update_hardsectsize(lv_t *lv) { - int le, e; - int max_hardsectsize = 0, hardsectsize; - - for (le = 0; le < lv->lv_allocated_le; le++) { - hardsectsize = get_hardsect_size(lv->lv_current_pe[le].dev); - if (hardsectsize == 0) - hardsectsize = 512; - if (hardsectsize > max_hardsectsize) - max_hardsectsize = hardsectsize; - } - - /* only perform this operation on active snapshots */ - if ((lv->lv_access & LV_SNAPSHOT) && - (lv->lv_status & LV_ACTIVE)) { - for (e = 0; e < lv->lv_remap_end; e++) { - hardsectsize = get_hardsect_size( lv->lv_block_exception[e].rdev_new); - if (hardsectsize == 0) - hardsectsize = 512; - if (hardsectsize > max_hardsectsize) +static void __update_hardsectsize(lv_t *lv) +{ + int max_hardsectsize = 0, hardsectsize = 0; + int p; + + /* Check PVs first to see if they all have same sector size */ + for (p = 0; p < lv->vg->pv_cur; p++) { + pv_t *pv = lv->vg->pv[p]; + if (pv && (hardsectsize = lvm_sectsize(pv->pv_dev))) { + if (max_hardsectsize == 0) + max_hardsectsize = hardsectsize; + else if (hardsectsize != max_hardsectsize) { + P_DEV("%s PV[%d] (%s) sector size %d, not %d\n", + lv->lv_name, p, kdevname(pv->pv_dev), + hardsectsize, max_hardsectsize); + break; + } + } + } + + /* PVs have different block size, need to check each LE sector size */ + if (hardsectsize != max_hardsectsize) { + int le; + for (le = 0; le < lv->lv_allocated_le; le++) { + hardsectsize = lvm_sectsize(lv->lv_current_pe[le].dev); + if (hardsectsize > max_hardsectsize) { + P_DEV("%s LE[%d] (%s) blocksize %d not %d\n", + lv->lv_name, le, + kdevname(lv->lv_current_pe[le].dev), + hardsectsize, max_hardsectsize); max_hardsectsize = hardsectsize; + } + } + + /* only perform this operation on active snapshots */ + if ((lv->lv_access & LV_SNAPSHOT) && + (lv->lv_status & LV_ACTIVE)) { + int e; + for (e = 0; e < lv->lv_remap_end; e++) { + hardsectsize = lvm_sectsize(lv->lv_block_exception[e].rdev_new); + if (hardsectsize > max_hardsectsize) + max_hardsectsize = hardsectsize; + } } } + if (max_hardsectsize == 0) + max_hardsectsize = SECTOR_SIZE; + P_DEV("hardblocksize for LV %s is %d\n", + kdevname(lv->lv_dev), max_hardsectsize); lvm_hardsectsizes[MINOR(lv->lv_dev)] = max_hardsectsize; } @@ -1834,7 +2023,6 @@ lv_block_exception_t *lvbe = lv->lv_block_exception; vg_t *vg_ptr = vg[VG_CHR(minor)]; lv_t *lv_ptr = NULL; - pe_t *pep; if (!(pep = lv->lv_current_pe)) return -EINVAL; @@ -1876,7 +2064,7 @@ lv_ptr->lv_snapshot_next = NULL; lv_ptr->lv_block_exception = NULL; lv_ptr->lv_iobuf = NULL; - lv_ptr->lv_COW_table_iobuf = NULL; + lv_ptr->lv_COW_table_iobuf = NULL; lv_ptr->lv_snapshot_hash_table = NULL; lv_ptr->lv_snapshot_hash_table_size = 0; lv_ptr->lv_snapshot_hash_mask = 0; @@ -1884,6 +2072,9 @@ lv_ptr->lv_snapshot_use_rate = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) + lv_ptr->bheads = 0; +#endif vg_ptr->lv[l] = lv_ptr; /* get the PE structures from user space if this @@ -1956,12 +2147,11 @@ LVM_SNAPSHOT_DROPPED_SECTOR) { printk(KERN_WARNING - "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n", + "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n", lvm_name); activate = 0; } - /* point to the original logical volume */ lv_ptr = lv_ptr->lv_snapshot_org; @@ -1995,12 +2185,16 @@ lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); /* need to fill the COW exception table data into the page for disk i/o */ - if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) { - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -EINVAL; - } + if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) { + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EINVAL; + } +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) init_waitqueue_head(&lv_ptr->lv_snapshot_wait); +#else + lv_ptr->lv_snapshot_wait = NULL; +#endif } else { kfree(lv_ptr); vg_ptr->lv[l] = NULL; @@ -2022,6 +2216,7 @@ LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; + lv_ptr->vg = vg_ptr; __update_hardsectsize(lv_ptr); @@ -2040,6 +2235,17 @@ org->lv_access |= LV_SNAPSHOT_ORG; lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) + /* allocate a set of buffer_heads for snapshot io */ + if(!org->bheads && !(org->bheads = __allocate_bheads())) { + printk(KERN_CRIT "%s -- LV_CREATE: " + "couldn't allocate buffer heads\n", lvm_name); + /* FIXME: tidy this function and free the lv */ + up_write(&org->lv_lock); + return -ENOMEM; + } +#endif + /* Link in the list of snapshot volumes */ for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next); lv_ptr->lv_snapshot_prev = last; @@ -2064,11 +2270,7 @@ unlockfs(lv_ptr->lv_snapshot_org->lv_dev); #endif - lv_ptr->vg = vg_ptr; - - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de = - lvm_fs_create_lv(vg_ptr, lv_ptr); - + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].de = lvm_fs_create_lv(vg_ptr, lv_ptr); return 0; } /* lvm_do_lv_create() */ @@ -2126,6 +2328,13 @@ /* no more snapshots? */ if (!org->lv_snapshot_next) { org->lv_access &= ~LV_SNAPSHOT_ORG; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) + /* get rid of the buffer heads */ + if(org->bheads) { + __free_bheads(org->bheads); + org->bheads = 0; + } +#endif } up_write(&org->lv_lock); @@ -2184,214 +2393,213 @@ * logical volume extend / reduce */ static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { - ulong size; - lv_block_exception_t *lvbe; + ulong size; + lv_block_exception_t *lvbe; - if (!new_lv->lv_block_exception) - return -ENXIO; + if (!new_lv->lv_block_exception) + return -ENXIO; - size = new_lv->lv_remap_end * sizeof(lv_block_exception_t); - if ((lvbe = vmalloc(size)) == NULL) { - printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: vmalloc " - "error LV_BLOCK_EXCEPTION of %lu Byte at line %d\n", - lvm_name, size, __LINE__); - return -ENOMEM; - } - - if ((new_lv->lv_remap_end > old_lv->lv_remap_end) && - (copy_from_user(lvbe, new_lv->lv_block_exception, size))) { - vfree(lvbe); - return -EFAULT; - } - new_lv->lv_block_exception = lvbe; - - if (lvm_snapshot_alloc_hash_table(new_lv)) { - vfree(new_lv->lv_block_exception); - return -ENOMEM; - } + size = new_lv->lv_remap_end * sizeof(lv_block_exception_t); + if ((lvbe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: vmalloc " + "error LV_BLOCK_EXCEPTION of %lu Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; + } + + if ((new_lv->lv_remap_end > old_lv->lv_remap_end) && + (copy_from_user(lvbe, new_lv->lv_block_exception, size))) { + vfree(lvbe); + return -EFAULT; + } + new_lv->lv_block_exception = lvbe; + + if (lvm_snapshot_alloc_hash_table(new_lv)) { + vfree(new_lv->lv_block_exception); + return -ENOMEM; + } - return 0; + return 0; } static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { - ulong size, l, p, end; - pe_t *pe; + ulong size, l, p, end; + pe_t *pe; + + /* allocate space for new pe structures */ + size = new_lv->lv_current_le * sizeof(pe_t); + if ((pe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: " + "vmalloc error LV_CURRENT_PE of %lu Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; + } + + /* get the PE structures from user space */ + if (copy_from_user(pe, new_lv->lv_current_pe, size)) { + if(old_lv->lv_access & LV_SNAPSHOT) + vfree(new_lv->lv_snapshot_hash_table); + vfree(pe); + return -EFAULT; + } + + new_lv->lv_current_pe = pe; + + /* reduce allocation counters on PV(s) */ + for (l = 0; l < old_lv->lv_allocated_le; l++) { + vg_ptr->pe_allocated--; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + old_lv->lv_current_pe[l].dev) { + vg_ptr->pv[p]->pe_allocated--; + break; + } + } + } - /* allocate space for new pe structures */ - size = new_lv->lv_current_le * sizeof(pe_t); - if ((pe = vmalloc(size)) == NULL) { - printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: " - "vmalloc error LV_CURRENT_PE of %lu Byte at line %d\n", - lvm_name, size, __LINE__); - return -ENOMEM; - } - - /* get the PE structures from user space */ - if (copy_from_user(pe, new_lv->lv_current_pe, size)) { - if(old_lv->lv_access & LV_SNAPSHOT) - vfree(new_lv->lv_snapshot_hash_table); - vfree(pe); - return -EFAULT; - } - - new_lv->lv_current_pe = pe; - - /* reduce allocation counters on PV(s) */ - for (l = 0; l < old_lv->lv_allocated_le; l++) { - vg_ptr->pe_allocated--; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - old_lv->lv_current_pe[l].dev) { - vg_ptr->pv[p]->pe_allocated--; - break; - } - } - } - - /* extend the PE count in PVs */ - for (l = 0; l < new_lv->lv_allocated_le; l++) { - vg_ptr->pe_allocated++; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == + /* extend the PE count in PVs */ + for (l = 0; l < new_lv->lv_allocated_le; l++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == new_lv->lv_current_pe[l].dev) { - vg_ptr->pv[p]->pe_allocated++; - break; - } - } - } - - /* save availiable i/o statistic data */ - if (old_lv->lv_stripes < 2) { /* linear logical volume */ - end = min(old_lv->lv_current_le, new_lv->lv_current_le); - for (l = 0; l < end; l++) { - new_lv->lv_current_pe[l].reads += - old_lv->lv_current_pe[l].reads; - - new_lv->lv_current_pe[l].writes += - old_lv->lv_current_pe[l].writes; - } - - } else { /* striped logical volume */ - uint i, j, source, dest, end, old_stripe_size, new_stripe_size; - - old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes; - new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes; - end = min(old_stripe_size, new_stripe_size); - - for (i = source = dest = 0; - i < new_lv->lv_stripes; i++) { - for (j = 0; j < end; j++) { - new_lv->lv_current_pe[dest + j].reads += - old_lv->lv_current_pe[source + j].reads; - new_lv->lv_current_pe[dest + j].writes += - old_lv->lv_current_pe[source + j].writes; - } - source += old_stripe_size; - dest += new_stripe_size; - } - } + vg_ptr->pv[p]->pe_allocated++; + break; + } + } + } - return 0; + /* save availiable i/o statistic data */ + if (old_lv->lv_stripes < 2) { /* linear logical volume */ + end = min(old_lv->lv_current_le, new_lv->lv_current_le); + for (l = 0; l < end; l++) { + new_lv->lv_current_pe[l].reads += + old_lv->lv_current_pe[l].reads; + + new_lv->lv_current_pe[l].writes += + old_lv->lv_current_pe[l].writes; + } + + } else { /* striped logical volume */ + uint i, j, source, dest, end, old_stripe_size, new_stripe_size; + + old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes; + new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes; + end = min(old_stripe_size, new_stripe_size); + + for (i = source = dest = 0; i < new_lv->lv_stripes; i++) { + for (j = 0; j < end; j++) { + new_lv->lv_current_pe[dest + j].reads += + old_lv->lv_current_pe[source + j].reads; + new_lv->lv_current_pe[dest + j].writes += + old_lv->lv_current_pe[source + j].writes; + } + source += old_stripe_size; + dest += new_stripe_size; + } + } + + return 0; } static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *new_lv) { - int r; - ulong l, e, size; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *old_lv; - pe_t *pe; - - if ((pe = new_lv->lv_current_pe) == NULL) - return -EINVAL; - - for (l = 0; l < vg_ptr->lv_max; l++) - if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) - break; + int r; + ulong l, e, size; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *old_lv; + pe_t *pe; - if (l == vg_ptr->lv_max) - return -ENXIO; + if ((pe = new_lv->lv_current_pe) == NULL) + return -EINVAL; + + for (l = 0; l < vg_ptr->lv_max; l++) + if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) + break; + + if (l == vg_ptr->lv_max) + return -ENXIO; - old_lv = vg_ptr->lv[l]; + old_lv = vg_ptr->lv[l]; if (old_lv->lv_access & LV_SNAPSHOT) { /* only perform this operation on active snapshots */ if (old_lv->lv_status & LV_ACTIVE) - r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); - else + r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); + else r = -EPERM; } else - r = __extend_reduce(vg_ptr, old_lv, new_lv); + r = __extend_reduce(vg_ptr, old_lv, new_lv); - if(r) - return r; + if(r) + return r; - /* copy relevent fields */ + /* copy relevent fields */ down_write(&old_lv->lv_lock); - if(new_lv->lv_access & LV_SNAPSHOT) { - size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ? - old_lv->lv_remap_ptr : new_lv->lv_remap_end; - size *= sizeof(lv_block_exception_t); - memcpy(new_lv->lv_block_exception, - old_lv->lv_block_exception, size); - - old_lv->lv_remap_end = new_lv->lv_remap_end; - old_lv->lv_block_exception = new_lv->lv_block_exception; - old_lv->lv_snapshot_hash_table = - new_lv->lv_snapshot_hash_table; - old_lv->lv_snapshot_hash_table_size = - new_lv->lv_snapshot_hash_table_size; - old_lv->lv_snapshot_hash_mask = - new_lv->lv_snapshot_hash_mask; - - for (e = 0; e < new_lv->lv_remap_ptr; e++) - lvm_hash_link(new_lv->lv_block_exception + e, - new_lv->lv_block_exception[e].rdev_org, - new_lv->lv_block_exception[e].rsector_org, - new_lv); - - } else { - - vfree(old_lv->lv_current_pe); - vfree(old_lv->lv_snapshot_hash_table); - - old_lv->lv_size = new_lv->lv_size; - old_lv->lv_allocated_le = new_lv->lv_allocated_le; - old_lv->lv_current_le = new_lv->lv_current_le; - old_lv->lv_current_pe = new_lv->lv_current_pe; - lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects = - old_lv->lv_size; - lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1; - - if (old_lv->lv_access & LV_SNAPSHOT_ORG) { - lv_t *snap; - for(snap = old_lv->lv_snapshot_next; snap; - snap = snap->lv_snapshot_next) { + if(new_lv->lv_access & LV_SNAPSHOT) { + size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ? + old_lv->lv_remap_ptr : new_lv->lv_remap_end; + size *= sizeof(lv_block_exception_t); + memcpy(new_lv->lv_block_exception, + old_lv->lv_block_exception, size); + + old_lv->lv_remap_end = new_lv->lv_remap_end; + old_lv->lv_block_exception = new_lv->lv_block_exception; + old_lv->lv_snapshot_hash_table = + new_lv->lv_snapshot_hash_table; + old_lv->lv_snapshot_hash_table_size = + new_lv->lv_snapshot_hash_table_size; + old_lv->lv_snapshot_hash_mask = + new_lv->lv_snapshot_hash_mask; + + for (e = 0; e < new_lv->lv_remap_ptr; e++) + lvm_hash_link(new_lv->lv_block_exception + e, + new_lv->lv_block_exception[e].rdev_org, + new_lv->lv_block_exception[e].rsector_org, + new_lv); + + } else { + + vfree(old_lv->lv_current_pe); + vfree(old_lv->lv_snapshot_hash_table); + + old_lv->lv_size = new_lv->lv_size; + old_lv->lv_allocated_le = new_lv->lv_allocated_le; + old_lv->lv_current_le = new_lv->lv_current_le; + old_lv->lv_current_pe = new_lv->lv_current_pe; + lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects = + old_lv->lv_size; + lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1; + + if (old_lv->lv_access & LV_SNAPSHOT_ORG) { + lv_t *snap; + for(snap = old_lv->lv_snapshot_next; snap; + snap = snap->lv_snapshot_next) { down_write(&snap->lv_lock); - snap->lv_current_pe = old_lv->lv_current_pe; - snap->lv_allocated_le = - old_lv->lv_allocated_le; - snap->lv_current_le = old_lv->lv_current_le; - snap->lv_size = old_lv->lv_size; - - lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects - = old_lv->lv_size; - lvm_size[MINOR(snap->lv_dev)] = - old_lv->lv_size >> 1; - __update_hardsectsize(snap); + snap->lv_current_pe = old_lv->lv_current_pe; + snap->lv_allocated_le = + old_lv->lv_allocated_le; + snap->lv_current_le = old_lv->lv_current_le; + snap->lv_size = old_lv->lv_size; + + lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects + = old_lv->lv_size; + lvm_size[MINOR(snap->lv_dev)] = + old_lv->lv_size >> 1; + __update_hardsectsize(snap); up_write(&snap->lv_lock); - } - } - } + } + } + } - __update_hardsectsize(old_lv); + __update_hardsectsize(old_lv); up_write(&old_lv->lv_lock); - return 0; + return 0; } /* lvm_do_lv_extend_reduce() */ @@ -2426,7 +2634,6 @@ lv_ptr, sizeof(lv_t)) != 0) return -EFAULT; - if (saved_ptr1 != NULL) { if (copy_to_user(saved_ptr1, lv_ptr->lv_current_pe, @@ -2434,6 +2641,18 @@ sizeof(pe_t)) != 0) return -EFAULT; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + if (saved_ptr2 != NULL) { + if (copy_to_user(saved_ptr2, + lv_ptr->lv_block_exception, + lv_ptr->lv_remap_ptr * + sizeof(lv_block_exception_t) + ) != 0) + return -EFAULT; + } + if (copy_to_user(&lv_status_byname_req.lv->lv_block_exception, &saved_ptr2, sizeof(void*)) != 0) + return -EFAULT; +#endif /* Restore usermode pointers */ if (copy_to_user(&lv_status_byname_req.lv->lv_current_pe, &saved_ptr1, sizeof(void*)) != 0) return -EFAULT; @@ -2461,9 +2680,6 @@ if (lv_status_byindex_req.lv == NULL) return -EINVAL; - if (lv_status_byindex_req.lv_index <0 || - lv_status_byindex_req.lv_index >= MAX_LV) - return -EINVAL; if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) return -ENXIO; @@ -2482,6 +2698,18 @@ sizeof(pe_t)) != 0) return -EFAULT; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + if (saved_ptr2 != NULL) { + if (copy_to_user(saved_ptr2, + lv_ptr->lv_block_exception, + lv_ptr->lv_remap_ptr * + sizeof(lv_block_exception_t) + ) != 0) + return -EFAULT; + } + if (copy_to_user(&lv_status_byindex_req.lv->lv_block_exception, &saved_ptr2, sizeof(void *)) != 0) + return -EFAULT; +#endif /* Restore usermode pointers */ if (copy_to_user(&lv_status_byindex_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) @@ -2529,6 +2757,18 @@ sizeof(pe_t)) != 0) return -EFAULT; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) + if (saved_ptr2 != NULL) { + if (copy_to_user(saved_ptr2, + lv_ptr->lv_block_exception, + lv_ptr->lv_remap_ptr * + sizeof(lv_block_exception_t) + ) != 0) + return -EFAULT; + } + if (copy_to_user(&lv_status_bydev_req.lv->lv_block_exception, &saved_ptr2, sizeof(void *)) != 0) + return -EFAULT; +#endif /* Restore usermode pointers */ if (copy_to_user(&lv_status_bydev_req.lv->lv_current_pe, &saved_ptr1, sizeof(void *)) != 0) return -EFAULT; @@ -2552,9 +2792,7 @@ if (lv_ptr->lv_dev == lv->lv_dev) { lvm_fs_remove_lv(vg_ptr, lv_ptr); - strncpy(lv_ptr->lv_name, - lv_req->lv_name, - NAME_LEN); + strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN); lvm_fs_create_lv(vg_ptr, lv_ptr); break; } @@ -2629,23 +2867,24 @@ return -ENXIO; } /* lvm_do_pv_status() */ + /* * character device support function flush and invalidate all buffers of a PV */ static int lvm_do_pv_flush(void *arg) { - pv_flush_req_t pv_flush_req; + pv_flush_req_t pv_flush_req; - if (copy_from_user(&pv_flush_req, arg, - sizeof(pv_flush_req)) != 0) - return -EFAULT; + if (copy_from_user(&pv_flush_req, arg, sizeof(pv_flush_req)) != 0) + return -EFAULT; - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); + fsync_dev(pv_flush_req.pv_dev); + invalidate_buffers(pv_flush_req.pv_dev); - return 0; + return 0; } + /* * support function initialize gendisk variables */ @@ -2670,10 +2909,43 @@ return; } /* lvm_gen_init() */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) +static struct buffer_head **__allocate_bheads(void) { + int i; + struct buffer_head *bh = 0, **bheads = 0; + + if(!(bh = vmalloc(sizeof(*bh) * KIO_MAX_SECTORS))) + return 0; + + if(!(bheads = vmalloc(sizeof(*bheads) * KIO_MAX_SECTORS))) { + vfree(bh); + return 0; + } + + for(i = 0; i < KIO_MAX_SECTORS; i++) + bheads[i] = bh + i; + return bheads; +} + +static void __free_bheads(struct buffer_head **bheads) { + vfree(bheads[0]); + vfree(bheads); +} +#endif /* Must have down_write(_pe_lock) when we enqueue buffers */ static void _queue_io(struct buffer_head *bh, int rw) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) + if (rw == WRITEA) { + /* + * Discard write aheads (only 2.2 bdflush uses WRITEA, and + * it will retry any buffers with a WRITE again later). + */ + bh->b_end_io(bh, buffer_uptodate(bh)); + return; + } +#endif if (bh->b_reqnext) BUG(); bh->b_reqnext = _pe_requests; _pe_requests = bh; @@ -2708,10 +2980,12 @@ } } + /* * we must open the pv's before we use them */ static int _open_pv(pv_t *pv) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 0) int err; struct block_device *bd; @@ -2719,22 +2993,28 @@ return -ENOMEM; err = blkdev_get(bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE); - if (err) + if (err) { + bdput(bd); return err; + } pv->bd = bd; +#endif return 0; } static void _close_pv(pv_t *pv) { - if (pv) { - struct block_device *bdev = pv->bd; - pv->bd = NULL; - if (bdev) - blkdev_put(bdev, BDEV_FILE); - } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 0) + if(!pv || !pv->bd) + return; + + blkdev_put(pv->bd, BDEV_FILE); + bdput(pv->bd); + pv->bd = 0; +#endif } + static unsigned long _sectors_to_k(unsigned long sect) { if(SECTOR_SIZE > 1024) { @@ -2744,6 +3024,27 @@ return sect / (1024 / SECTOR_SIZE); } +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) module_init(lvm_init); module_exit(lvm_cleanup); -MODULE_LICENSE("GPL"); +#else +/* + * 2.2.18 has support for module_init so why aren't I using it ? + * 1) I don't want to have to regression test against older kernels. + * 2) It doesn't work; if I use module_init(lvm_init) and build lvm + * into the kernel, lvm_init doesn't get called. If I then leave in + * the lvm_init call in ll_rw_block.c, lvm_init gets called twice ! + * Probably got a link flag wrong somewhere. + */ + +#ifdef MODULE +int __init init_module(void) { + return lvm_init(); +} + +void cleanup_module(void) { + lvm_cleanup(); +} +#endif + +#endif --- drivers/md/lvm-internal.h.org Sun Nov 11 18:09:32 2001 +++ drivers/md/lvm-internal.h Thu Sep 27 08:34:43 2001 @@ -1,5 +1,6 @@ + /* - * kernel/lvm-internal.h + * kernel/lvm_internal.h * * Copyright (C) 2001 Sistina Software * @@ -24,7 +25,9 @@ /* * Changelog * - * 05/01/2001:Joe Thornber - Factored this file out of lvm.c + * 05/01/2001 - Factored this file out of lvm.c (Joe Thornber) + * 11/01/2001 - Renamed lvm_internal and added declarations + * for lvm_fs.c stuff * */ @@ -33,7 +36,7 @@ #include -#define _LVM_INTERNAL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" +#define _LVM_INTERNAL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" /* global variables, defined in lvm.c */ extern char *lvm_version; @@ -45,8 +48,30 @@ extern vg_t *vg[]; extern struct file_operations lvm_chr_fops; +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3, 38) +extern struct file_operations lvm_blk_fops; +#else extern struct block_device_operations lvm_blk_dops; +#endif + +/* 2.4.8 had no global min/max macros, and 2.4.9's were flawed */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) + +#undef min +#define min(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x < _y ? _x : _y; }) + +#undef max +#define max(x,y) ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + (void) (&_x == &_y); \ + _x > _y ? _x : _y; }) +#endif /* debug macros */ #ifdef DEBUG_IOCTL --- drivers/md/lvm-snap.c.org Mon Nov 12 17:34:20 2001 +++ drivers/md/lvm-snap.c Thu Sep 27 08:34:43 2001 @@ -2,22 +2,22 @@ * kernel/lvm-snap.c * * Copyright (C) 2000 Andrea Arcangeli SuSE - * Heinz Mauelshagen, Sistina Software (persistent snapshots) + * 2000 - 2001 Heinz Mauelshagen, Sistina Software * * LVM snapshot driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * LVM snapshot driver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Boston, MA 02111-1307, USA. * */ @@ -28,6 +28,11 @@ * 23/11/2000 - used cpu_to_le64 rather than my own macro * 25/01/2001 - Put LockPage back in * 01/02/2001 - A dropped snapshot is now set as inactive + * 14/02/2001 - tidied debug statements + * 19/02/2001 - changed rawio calls to pass in preallocated buffer_heads + * 26/02/2001 - introduced __brw_kiovec to remove a lot of conditional + * compiles. + * 07/03/2001 - fixed COW exception table not persistent on 2.2 (HM) * 12/03/2001 - lvm_pv_get_number changes: * o made it static * o renamed it to _pv_get_number @@ -38,7 +43,6 @@ */ #include -#include #include #include #include @@ -46,22 +50,42 @@ #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3 ,0) +#include +#endif #include "lvm-internal.h" -static char *lvm_snap_version __attribute__ ((unused)) = - "LVM "LVM_RELEASE_NAME" snapshot code ("LVM_RELEASE_DATE")\n"; +static char *lvm_snap_version __attribute__ ((unused)) = "LVM "LVM_RELEASE_NAME" snapshot code ("LVM_RELEASE_DATE")\n"; +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3 ,0) +#ifndef LockPage +#define LockPage(map) set_bit(PG_locked, &(map)->flags) +#endif +#endif extern const char *const lvm_name; extern int lvm_blocksizes[]; void lvm_snapshot_release(lv_t *); + static int _write_COW_table_block(vg_t *vg, lv_t *lv, int idx, - const char **reason); + const char **reason); static void _disable_snapshot(vg_t *vg, lv_t *lv); +static inline int __brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, + lv_t *lv) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 0) + return brw_kiovec(rw, nr, iovec, dev, b, size); +#else + return brw_kiovec_bh(rw, nr, iovec, dev, b, size, 0, + lv->lv_snapshot_org->bheads, KIO_MAX_SECTORS); +#endif +} + + static int _pv_get_number(vg_t * vg, kdev_t rdev, uint *pvn) { uint p; for(p = 0; p < vg->pv_max; p++) { @@ -70,14 +94,13 @@ if(vg->pv[p]->pv_dev == rdev) break; - } - if(p >= vg->pv_max) { + if(p >= vg->pv_max) { /* bad news, the snapshot COW table is probably corrupt */ printk(KERN_ERR "%s -- _pv_get_number failed for rdev = %u\n", - lvm_name, rdev); + lvm_name, rdev); return -1; } @@ -85,6 +108,7 @@ return 0; } + #define hashfn(dev,block,mask,chunk_size) \ ((HASHDEV(dev)^((block)/(chunk_size))) & (mask)) @@ -166,8 +190,8 @@ or error on this snapshot --> release it */ invalidate_buffers(lv_snap->lv_dev); - /* wipe the snapshot since it's inconsistent now */ - _disable_snapshot(vg, lv_snap); + /* wipe the snapshot since it's inconsistent now */ + _disable_snapshot(vg, lv_snap); for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { @@ -186,9 +210,9 @@ } static inline int lvm_snapshot_prepare_blocks(unsigned long *blocks, - unsigned long start, - int nr_sectors, - int blocksize) + unsigned long start, + int nr_sectors, + int blocksize) { int i, sectors_per_block, nr_blocks; @@ -245,49 +269,48 @@ int lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) { - uint pvn; - int id = 0, is = lv_snap->lv_remap_ptr; - ulong blksize_snap; - lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *) - page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); + uint pvn; + int id = 0, is = lv_snap->lv_remap_ptr; + ulong blksize_snap; + lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *) + page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); - if (is == 0) - return 0; + if (is == 0) + return 0; is--; blksize_snap = - lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); + lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t)); memset(lv_COW_table, 0, blksize_snap); for ( ; is < lv_snap->lv_remap_ptr; is++, id++) { /* store new COW_table entry */ - lv_block_exception_t *be = lv_snap->lv_block_exception + is; - if(_pv_get_number(vg, be->rdev_org, &pvn)) - goto bad; - - lv_COW_table[id].pv_org_number = cpu_to_le64(pvn); - lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org); - if(_pv_get_number(vg, be->rdev_new, &pvn)) - goto bad; - - lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn); - lv_COW_table[id].pv_snap_rsector = - cpu_to_le64(be->rsector_new); + lv_block_exception_t *be = lv_snap->lv_block_exception + is; + if(_pv_get_number(vg, be->rdev_org, &pvn)) + goto bad; + + lv_COW_table[id].pv_org_number = cpu_to_le64(pvn); + lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org); + if(_pv_get_number(vg, be->rdev_new, &pvn)) + goto bad; + + lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn); + lv_COW_table[id].pv_snap_rsector = + cpu_to_le64(be->rsector_new); } - return 0; + return 0; bad: - printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed", lvm_name); - return -1; + printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed", lvm_name); + return -1; } /* * writes a COW exception table sector to disk (HM) */ - int lvm_write_COW_table_block(vg_t * vg, lv_t *lv_snap) { int r; @@ -316,6 +339,7 @@ unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; struct kiobuf * iobuf; + unsigned long blocks[KIO_MAX_SECTORS]; int blksize_snap, blksize_org, min_blksize, max_blksize; int max_sectors, nr_sectors; @@ -363,20 +387,20 @@ iobuf->length = nr_sectors << 9; - if(!lvm_snapshot_prepare_blocks(iobuf->blocks, org_start, + if(!lvm_snapshot_prepare_blocks(blocks, org_start, nr_sectors, blksize_org)) goto fail_prepare; - if (brw_kiovec(READ, 1, &iobuf, org_phys_dev, - iobuf->blocks, blksize_org) != (nr_sectors<<9)) + if (__brw_kiovec(READ, 1, &iobuf, org_phys_dev, blocks, + blksize_org, lv_snap) != (nr_sectors<<9)) goto fail_raw_read; - if(!lvm_snapshot_prepare_blocks(iobuf->blocks, snap_start, + if(!lvm_snapshot_prepare_blocks(blocks, snap_start, nr_sectors, blksize_snap)) goto fail_prepare; - if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, - iobuf->blocks, blksize_snap) != (nr_sectors<<9)) + if (__brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, blocks, + blksize_snap, lv_snap) != (nr_sectors<<9)) goto fail_raw_write; } @@ -401,24 +425,24 @@ return 0; /* slow path */ - out: +out: lvm_drop_snapshot(vg, lv_snap, reason); return 1; - fail_out_of_space: +fail_out_of_space: reason = "out of space"; goto out; - fail_raw_read: +fail_raw_read: reason = "read error"; goto out; - fail_raw_write: +fail_raw_write: reason = "write error"; goto out; - fail_blksize: +fail_blksize: reason = "blocksize error"; goto out; - fail_prepare: +fail_prepare: reason = "couldn't prepare kiovec blocks " "(start probably isn't block aligned)"; goto out; @@ -440,9 +464,17 @@ { struct page * page; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27) page = alloc_page(GFP_KERNEL); - if (!page) - goto out; + if (!page) goto out; +#else + { + unsigned long addr = __get_free_page(GFP_USER); + if (!addr) goto out; + iobuf->pagelist[i] = addr; + page = mem_map + MAP_NR(addr); + } +#endif iobuf->maplist[i] = page; LockPage(page); @@ -451,7 +483,8 @@ iobuf->offset = 0; err = 0; - out: + +out: return err; } @@ -515,7 +548,7 @@ if (ret) goto out_free_kiovec; ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf, - PAGE_SIZE/SECTOR_SIZE); + PAGE_SIZE/SECTOR_SIZE); if (ret) goto out_free_both_kiovecs; ret = lvm_snapshot_alloc_hash_table(lv_snap); @@ -542,8 +575,6 @@ void lvm_snapshot_release(lv_t * lv) { - int nbhs = KIO_MAX_SECTORS; - if (lv->lv_block_exception) { vfree(lv->lv_block_exception); @@ -557,17 +588,21 @@ } if (lv->lv_iobuf) { +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) kiobuf_wait_for_io(lv->lv_iobuf); +#endif unmap_kiobuf(lv->lv_iobuf); free_kiovec(1, &lv->lv_iobuf); lv->lv_iobuf = NULL; } if (lv->lv_COW_table_iobuf) { - kiobuf_wait_for_io(lv->lv_COW_table_iobuf); - unmap_kiobuf(lv->lv_COW_table_iobuf); - free_kiovec(1, &lv->lv_COW_table_iobuf); - lv->lv_COW_table_iobuf = NULL; +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) + kiobuf_wait_for_io(lv->lv_COW_table_iobuf); +#endif + unmap_kiobuf(lv->lv_COW_table_iobuf); + free_kiovec(1, &lv->lv_COW_table_iobuf); + lv->lv_COW_table_iobuf = NULL; } } @@ -579,11 +614,11 @@ int idx_COW_table; uint pvn; ulong snap_pe_start, COW_table_sector_offset, - COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; + COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; ulong blocks[1]; kdev_t snap_phys_dev; lv_block_exception_t *be; - struct kiobuf * COW_table_iobuf = lv_snap->lv_COW_table_iobuf; + struct kiobuf *COW_table_iobuf = lv_snap->lv_COW_table_iobuf; lv_COW_table_disk_t * lv_COW_table = ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); @@ -601,39 +636,40 @@ if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap); - /* sector offset into the on disk COW table */ + /* sector offset into the on disk COW table */ COW_table_sector_offset = (idx % COW_entries_per_pe) / (SECTOR_SIZE / sizeof(lv_COW_table_disk_t)); /* COW table block to write next */ blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); /* store new COW_table entry */ - be = lv_snap->lv_block_exception + idx; - if(_pv_get_number(vg, be->rdev_org, &pvn)) - goto fail_pv_get_number; - - lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(pvn); - lv_COW_table[idx_COW_table].pv_org_rsector = - cpu_to_le64(be->rsector_org); - if(_pv_get_number(vg, snap_phys_dev, &pvn)) - goto fail_pv_get_number; - - lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(pvn); - lv_COW_table[idx_COW_table].pv_snap_rsector = - cpu_to_le64(be->rsector_new); + be = lv_snap->lv_block_exception + idx; + if(_pv_get_number(vg, be->rdev_org, &pvn)) + goto fail_pv_get_number; + + lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(pvn); + lv_COW_table[idx_COW_table].pv_org_rsector = + cpu_to_le64(be->rsector_org); + if(_pv_get_number(vg, snap_phys_dev, &pvn)) + goto fail_pv_get_number; + + lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(pvn); + lv_COW_table[idx_COW_table].pv_snap_rsector = + cpu_to_le64(be->rsector_new); COW_table_iobuf->length = blksize_snap; + /* COW_table_iobuf->nr_pages = 1; */ - if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, - blocks, blksize_snap) != blksize_snap) + if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, + blocks, blksize_snap, lv_snap) != blksize_snap) goto fail_raw_write; - /* initialization of next COW exception table block with zeroes */ + /* initialization of next COW exception table block with zeroes */ end_of_table = idx % COW_entries_per_pe == COW_entries_per_pe - 1; if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table) { /* don't go beyond the end */ - if (idx + 1 >= lv_snap->lv_remap_end) goto out; + if (idx + 1 >= lv_snap->lv_remap_end) goto out; memset(lv_COW_table, 0, blksize_snap); @@ -646,20 +682,20 @@ blocks[0] = snap_pe_start >> (blksize_snap >> 10); } else blocks[0]++; - if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, - blocks, blksize_snap) != + if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, + blocks, blksize_snap, lv_snap) != blksize_snap) goto fail_raw_write; } - out: +out: return 0; - fail_raw_write: +fail_raw_write: *reason = "write error"; return 1; - fail_pv_get_number: +fail_pv_get_number: *reason = "_pv_get_number failed"; return 1; } @@ -683,5 +719,3 @@ lvm_name, err); } } - -MODULE_LICENSE("GPL"); --- drivers/md/lvm-fs.c.org Sun Nov 11 18:09:32 2001 +++ drivers/md/lvm-fs.c Tue Sep 4 10:40:17 2001 @@ -3,7 +3,7 @@ * * Copyright (C) 2001 Sistina Software * - * January,February 2001 + * January-April 2001 * * LVM driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +35,6 @@ #include #include -#include #include #include @@ -64,12 +63,14 @@ static void _show_uuid(const char *src, char *b, char *e); +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) #if 0 static devfs_handle_t lvm_devfs_handle; #endif static devfs_handle_t vg_devfs_handle[MAX_VG]; static devfs_handle_t ch_devfs_handle[MAX_VG]; static devfs_handle_t lv_devfs_handle[MAX_LV]; +#endif static struct proc_dir_entry *lvm_proc_dir = NULL; static struct proc_dir_entry *lvm_proc_vg_subdir = NULL; @@ -82,12 +83,13 @@ /* User-space has already registered this */ #if 0 +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) lvm_devfs_handle = devfs_register( 0 , "lvm", 0, LVM_CHAR_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_chr_fops, NULL); #endif - +#endif lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root); if (lvm_proc_dir) { lvm_proc_vg_subdir = create_proc_entry(LVM_VG_SUBDIR, S_IFDIR, @@ -99,9 +101,10 @@ void lvm_fin_fs() { #if 0 +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) devfs_unregister (lvm_devfs_handle); #endif - +#endif remove_proc_entry(LVM_GLOBAL, lvm_proc_dir); remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir); remove_proc_entry(LVM_DIR, &proc_root); @@ -110,6 +113,7 @@ void lvm_fs_create_vg(vg_t *vg_ptr) { struct proc_dir_entry *pde; +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); @@ -118,6 +122,7 @@ DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_chr_fops, NULL); +#endif vg_ptr->vg_dir_pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR, lvm_proc_vg_subdir); @@ -137,8 +142,10 @@ void lvm_fs_remove_vg(vg_t *vg_ptr) { int i; +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]); devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]); +#endif /* remove lv's */ for(i = 0; i < vg_ptr->lv_max; i++) @@ -173,11 +180,13 @@ struct proc_dir_entry *pde; const char *name = _basename(lv->lv_name); +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) lv_devfs_handle[MINOR(lv->lv_dev)] = devfs_register( vg_devfs_handle[vg_ptr->vg_number], name, DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, MINOR(lv->lv_dev), S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_blk_dops, NULL); +#endif if(vg_ptr->lv_subdir_pde && (pde = create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) { @@ -188,7 +197,9 @@ } void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) { +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 46) devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]); +#endif if(vg_ptr->lv_subdir_pde) { const char *name = _basename(lv->lv_name); @@ -276,12 +287,12 @@ sz += sprintf(page + sz, "number: %u\n", lv->lv_number); sz += sprintf(page + sz, "open: %u\n", lv->lv_open); sz += sprintf(page + sz, "allocation: %u\n", lv->lv_allocation); - if(lv->lv_stripes > 1) { - sz += sprintf(page + sz, "stripes: %u\n", - lv->lv_stripes); - sz += sprintf(page + sz, "stripesize: %u\n", - lv->lv_stripesize); - } + if(lv->lv_stripes > 1) { + sz += sprintf(page + sz, "stripes: %u\n", + lv->lv_stripes); + sz += sprintf(page + sz, "stripesize: %u\n", + lv->lv_stripesize); + } sz += sprintf(page + sz, "device: %02u:%02u\n", MAJOR(lv->lv_dev), MINOR(lv->lv_dev)); @@ -330,8 +341,8 @@ #ifdef DEBUG_LVM_PROC_GET_INFO printk(KERN_DEBUG - "%s - lvm_proc_get_global_info CALLED pos: %lu count: %d\n", - lvm_name, pos, count); + "%s - lvm_proc_get_global_info CALLED pos: %lu count: %d whence: %d\n", + lvm_name, pos, count, whence); #endif if(pos != 0 && buf != NULL) @@ -620,4 +631,3 @@ } *b = '\0'; } -MODULE_LICENSE("GPL"); --- include/linux/lvm.h.org Sun Nov 11 18:09:32 2001 +++ include/linux/lvm.h Wed Oct 3 14:46:47 2001 @@ -3,28 +3,28 @@ * kernel/lvm.h * tools/lib/lvm.h * - * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software * * February-November 1997 * May-July 1998 * January-March,July,September,October,Dezember 1999 * January,February,July,November 2000 - * January 2001 + * January-March,June,July 2001 * * lvm is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * lvm is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Boston, MA 02111-1307, USA. * */ @@ -52,8 +52,7 @@ * 08/12/1999 - changed LVM_LV_SIZE_MAX macro to reflect current 1TB limit * 01/01/2000 - extended lv_v2 core structure by wait_queue member * 12/02/2000 - integrated Andrea Arcagnelli's snapshot work - * 14/02/2001 - changed LVM_SNAPSHOT_MIN_CHUNK to 1 page - * 18/02/2000 - seperated user and kernel space parts by + * 18/02/2000 - seperated user and kernel space parts by * #ifdef them with __KERNEL__ * 08/03/2000 - implemented cluster/shared bits for vg_access * 26/06/2000 - implemented snapshot persistency and resizing support @@ -61,11 +60,17 @@ * 12/11/2000 - removed unneeded timestamp definitions * 24/12/2000 - removed LVM_TO_{CORE,DISK}*, use cpu_{from, to}_le* * instead - Christoph Hellwig - * 01/03/2001 - Rename VG_CREATE to VG_CREATE_OLD and add new VG_CREATE + * 22/01/2001 - Change ulong to uint32_t + * 14/02/2001 - changed LVM_SNAPSHOT_MIN_CHUNK to 1 page + * 20/02/2001 - incremented IOP version to 11 because of incompatible + * change in VG activation (in order to support devfs better) + * 01/03/2001 - Revert to IOP10 and add VG_CREATE_OLD call for compatibility * 08/03/2001 - new lv_t (in core) version number 5: changed page member * to (struct kiobuf *) to use for COW exception table io - * 23/03/2001 - Change a (presumably) mistyped pv_t* to an lv_t* - * 26/03/2001 - changed lv_v4 to lv_v5 in structure definition [HM] + * 26/03/2001 - changed lv_v4 to lv_v5 in structure definition (HM) + * 21/06/2001 - changed BLOCK_SIZE back to 1024 for non S/390 + * 22/06/2001 - added Andreas Dilger's PE on 4k boundary alignment enhancements + * 19/07/2001 - added rwsem compatibility macros for 2.2 kernels * */ @@ -73,10 +78,10 @@ #ifndef _LVM_H_INCLUDE #define _LVM_H_INCLUDE -#define LVM_RELEASE_NAME "1.0.1-rc4(ish)" +#define LVM_RELEASE_NAME "1.0.1-rc4" #define LVM_RELEASE_DATE "03/10/2001" -#define _LVM_KERNEL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" +#define _LVM_KERNEL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" #include @@ -98,23 +103,43 @@ #define DEBUG_READ #define DEBUG_GENDISK #define DEBUG_VG_CREATE - #define DEBUG_LVM_BLK_OPEN + #define DEBUG_DEVICE #define DEBUG_KFREE */ -#endif /* #ifdef __KERNEL__ */ #include #include +#else +#define __KERNEL__ +#include +#include +#undef __KERNEL__ +#endif /* #ifndef __KERNEL__ */ #include #include #ifdef __KERNEL__ +#if LINUX_VERSION_CODE >= KERNEL_VERSION ( 2, 3 ,0) #include +#else +#include +#endif #include #endif /* #ifdef __KERNEL__ */ +#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 3 ,0) +/* Compatibility macros for 2.2 */ +#define rw_semaphore semaphore +#define init_rwsem init_MUTEX +#define down_read down +#define down_write down +#define up_read up +#define up_write up +#define DECLARE_RWSEM DECLARE_MUTEX +#endif + #include #if !defined ( LVM_BLK_MAJOR) || !defined ( LVM_CHAR_MAJOR) @@ -125,7 +150,7 @@ #undef BLOCK_SIZE #endif -#ifdef CONFIG_ARCH_S390 +#ifdef CONFIG_ARCH_S390 #define BLOCK_SIZE 4096 #else #define BLOCK_SIZE 1024 @@ -189,6 +214,38 @@ /* + * VGDA: default disk spaces and offsets + * + * there's space after the structures for later extensions. + * + * offset what size + * --------------- ---------------------------------- ------------ + * 0 physical volume structure ~500 byte + * + * 1K volume group structure ~200 byte + * + * 6K namelist of physical volumes 128 byte each + * + * 6k + n * ~300byte n logical volume structures ~300 byte each + * + * + m * 4byte m physical extent alloc. structs 4 byte each + * + * End of disk - first physical extent typically 4 megabyte + * PE total * + * PE size + * + * + */ + +/* DONT TOUCH THESE !!! */ + + + + + + + +/* * LVM_PE_T_MAX corresponds to: * * 8KB PE size can map a ~512 MB logical volume at the cost of 1MB memory, @@ -298,7 +355,12 @@ #endif /* lock the logical volume manager */ +#if LVM_DRIVER_IOP_VERSION > 11 +#define LVM_LOCK_LVM _IO ( 0xfe, 0x9A) +#else +/* This is actually the same as _IO ( 0xff, 0x00), oops. Remove for IOP 12+ */ #define LVM_LOCK_LVM _IO ( 0xfe, 0x100) +#endif /* END ioctls */ @@ -495,9 +557,9 @@ uint lv_read_ahead; /* delta to version 1 starts here */ - struct lv_v5 *lv_snapshot_org; - struct lv_v5 *lv_snapshot_prev; - struct lv_v5 *lv_snapshot_next; + struct lv_v5 *lv_snapshot_org; + struct lv_v5 *lv_snapshot_prev; + struct lv_v5 *lv_snapshot_next; lv_block_exception_t *lv_block_exception; uint lv_remap_ptr; uint lv_remap_end; @@ -510,11 +572,18 @@ struct list_head *lv_snapshot_hash_table; uint32_t lv_snapshot_hash_table_size; uint32_t lv_snapshot_hash_mask; +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) wait_queue_head_t lv_snapshot_wait; +#else + struct wait_queue *lv_snapshot_wait; +#endif int lv_snapshot_use_rate; struct vg_v3 *vg; uint lv_allocated_snapshot_le; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) + struct buffer_head **bheads; +#endif #else char dummy[200]; #endif @@ -661,6 +730,7 @@ } lv_snapshot_use_rate_req_t; + /* useful inlines */ static inline ulong round_up(ulong n, ulong size) { size--; @@ -671,6 +741,7 @@ return round_up(n, size) / size; } +/* FIXME: nasty capital letters */ static int inline LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg_t *vg, lv_t *lv) { return vg->pe_size / lv->lv_chunk_size; } @@ -693,4 +764,6 @@ return entries; } + #endif /* #ifndef _LVM_H_INCLUDE */ +