[PATCH] lvm merge

Andreas Dilger (adilger@turbolabs.com)
Sat, 27 Oct 2001 19:08:54 -0600


Linus,
the attached patch merges a whole bunch of trivial LVM changes from CVS into
the main kernel source. They are pretty much all changes in formatting or
code reordering with no functional changes, adding comments, and similar.
I haven't checked specifically, but most (or all) of these changes should
also be in Alan's LVM sources already.

There are some one-liner fixes included such as checking for NULL values
and similar stand-alone fixes.

Cheers, Andreas
=============================================================================
--- linux.orig/drivers/md/lvm.c Thu Oct 25 03:04:38 2001
+++ linux/drivers/md/lvm.c Sat Oct 27 14:26:43 2001
@@ -1,7 +1,7 @@
/*
* 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
@@ -43,7 +43,8 @@
* support for free (eg. longer) logical volume names
* 12/05/1998 - added spin_locks (thanks to Pascal van Dam
* <pascal@ramoth.xs4all.nl>)
- * 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
@@ -148,6 +150,9 @@
* procfs is always supported now. (JT)
* 12/01/2001 - avoided flushing logical volume in case of shrinking
* because of unecessary overhead in case of heavy updates
+ * 25/01/2001 - Allow RO open of an inactive LV so it can be reactivated.
+ * - If you try and BMAP a snapshot you now get an -EPERM
+ * 28/02/2001 - factored lvm_get_snapshot_use_rate out of blk_ioctl [AD]
* 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)
@@ -188,6 +193,9 @@
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/locks.h>
+
+
+#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#include <asm/ioctl.h>
#include <asm/segment.h>
@@ -244,12 +252,12 @@
static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
static int lvm_blk_open(struct inode *, struct file *);

-static int lvm_chr_open(struct inode *, struct file *);
-
-static int lvm_chr_close(struct inode *, struct file *);
static int lvm_blk_close(struct inode *, struct file *);
+static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg);
static int lvm_user_bmap(struct inode *, struct lv_bmap *);

+static int lvm_chr_open(struct inode *, struct file *);
+static int lvm_chr_close(struct inode *, struct file *);
static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong);

int lvm_proc_read_vg_info(char *, char **, off_t, int, int *, void *);
@@ -321,7 +329,6 @@
static devfs_handle_t ch_devfs_handle[MAX_VG];
static devfs_handle_t lv_devfs_handle[MAX_LV];

-static pv_t *pvp = NULL;
static lv_t *lvp = NULL;
static pe_t *pep = NULL;
static pe_t *pep1 = NULL;
@@ -400,20 +406,25 @@
nr_real: MAX_LV,
};

+
/*
* Driver initialization...
*/
int lvm_init(void)
{
- if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) {
- printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name);
+ 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 (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)
+ if (devfs_register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)
{
- printk("%s -- register_blkdev failed\n", lvm_name);
- if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
- printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
+ printk("%s -- devfs_register_blkdev failed\n", lvm_name);
+ if (devfs_unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
+ printk(KERN_ERR
+ "%s -- devfs_unregister_chrdev failed\n",
+ lvm_name);
return -EIO;
}

@@ -432,6 +445,7 @@
lvm_init_vars();
lvm_geninit(&lvm_gendisk);

+ /* insert our gendisk at the corresponding major */
add_gendisk(&lvm_gendisk);

#ifdef LVM_HD_NAME
@@ -447,35 +461,32 @@
if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);
*/

- printk(KERN_INFO
- "%s%s -- "
#ifdef MODULE
- "Module"
+ printk(KERN_INFO "%s module loaded\n", lvm_version);
#else
- "Driver"
+ printk(KERN_INFO "%s\n", lvm_version);
#endif
- " successfully initialized\n",
- lvm_version, lvm_name);

return 0;
} /* lvm_init() */

-
/*
* cleanup...
*/
+
static void lvm_cleanup(void)
{
devfs_unregister (lvm_devfs_handle);
+ if (devfs_unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
+ printk(KERN_ERR "%s -- devfs_unregister_chrdev failed\n",
+ lvm_name);
+ if (devfs_unregister_blkdev(MAJOR_NR, lvm_name) < 0)
+ printk(KERN_ERR "%s -- devfs_unregister_blkdev failed\n",
+ lvm_name);

- if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) {
- printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
- }
- if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) {
- printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name);
- }


+ /* delete our gendisk from chain */
del_gendisk(&lvm_gendisk);

blk_size[MAJOR_NR] = NULL;
@@ -491,16 +502,17 @@
lvm_hd_name_ptr = NULL;
#endif

+#ifdef MODULE
printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
+#endif

return;
} /* lvm_cleanup() */

-
/*
* support function to initialize lvm variables
*/
-void __init lvm_init_vars(void)
+static void __init lvm_init_vars(void)
{
int v;

@@ -509,8 +521,8 @@
lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;

pe_lock_req.lock = UNLOCK_PE;
- pe_lock_req.data.lv_dev = \
- pe_lock_req.data.pv_dev = \
+ pe_lock_req.data.lv_dev = 0;
+ pe_lock_req.data.pv_dev = 0;
pe_lock_req.data.pv_offset = 0;

/* Initialize VG pointers */
@@ -533,11 +545,13 @@
*
********************************************************************/

+#define MODE_TO_STR(mode) (mode) & FMODE_READ ? "READ" : "", \
+ (mode) & FMODE_WRITE ? "WRITE" : ""
+
/*
* character device open routine
*/
-static int lvm_chr_open(struct inode *inode,
- struct file *file)
+static int lvm_chr_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);

@@ -580,9 +600,8 @@
/* otherwise cc will complain about unused variables */
(void) lvm_lock;

- P_IOCTL("%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d "
- "VG#: %d mode: 0x%X\n",
- lvm_name, command, minor, VG_CHR(minor), file->f_mode);
+ P_IOCTL("chr MINOR: %d command: 0x%X arg: %p VG#: %d mode: %s%s\n",
+ minor, command, arg, VG_CHR(minor), MODE_TO_STR(file->f_mode));

#ifdef LVM_TOTAL_RESET
if (lvm_reset_spindown > 0) return -EACCES;
@@ -683,7 +706,7 @@


case VG_STATUS_GET_NAMELIST:
- /* get volume group count */
+ /* get volume group names */
for (l = v = 0; v < ABS_MAX_VG; v++) {
if (vg[v] != NULL) {
if (copy_to_user(arg + l * NAME_LEN,
@@ -738,6 +761,7 @@


case LV_STATUS_BYDEV:
+ /* get status of a logical volume by device */
return lvm_do_lv_status_bydev(vg_ptr, arg);


@@ -764,7 +777,7 @@

default:
printk(KERN_WARNING
- "%s -- lvm_chr_ioctl: unknown command %x\n",
+ "%s -- lvm_chr_ioctl: unknown command 0x%x\n",
lvm_name, command);
return -EINVAL;
}
@@ -779,9 +797,8 @@
static int lvm_chr_close(struct inode *inode, struct file *file)
{
#ifdef DEBUG
- int minor = MINOR(inode->i_rdev);
- printk(KERN_DEBUG
- "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor));
+ printk(KERN_DEBUG "%s - lvm_chr_close VG#:\n",
+ MINOR(inode->i_rdev), VG_CHR(MINOR(inode->i_rdev)));
#endif

#ifdef LVM_TOTAL_RESET
@@ -840,8 +859,12 @@
if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;

/* Check inactive LV and open for read/write */
- if (!(lv_ptr->lv_status & LV_ACTIVE))
- return -EPERM;
+ /* We need to be able to "read" an inactive LV
+ to re-activate it again */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (!(lv_ptr->lv_status & LV_ACTIVE)))
+ return -EPERM;
+
if (!(lv_ptr->lv_access & LV_WRITE) &&
(file->f_mode & FMODE_WRITE))
return -EACCES;
@@ -878,10 +896,9 @@
void *arg = (void *) a;
struct hd_geometry *hd = (struct hd_geometry *) a;

- P_IOCTL("%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X "
- "VG#: %dl LV#: %d\n",
- lvm_name, minor, command, (ulong) arg,
- VG_BLK(minor), LV_BLK(minor));
+ P_IOCTL("blk MINOR: %d command: 0x%X arg: %p VG#: %d LV#: %d "
+ "mode: %s%s\n", minor, command, arg, VG_BLK(minor),
+ LV_BLK(minor), MODE_TO_STR(file->f_mode));

switch (command) {
case BLKSSZGET:
@@ -890,23 +907,23 @@

case BLKGETSIZE:
/* return device size */
- P_IOCTL("%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n",
- lvm_name, lv_ptr->lv_size);
+ P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size);
if (put_user(lv_ptr->lv_size, (unsigned long *)arg))
return -EFAULT;
break;

+#ifdef BLKGETSIZE64
case BLKGETSIZE64:
if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg))
return -EFAULT;
break;
-
+#endif

case BLKFLSBUF:
/* flush buffer cache */
if (!capable(CAP_SYS_ADMIN)) return -EACCES;

- P_IOCTL("%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name);
+ P_IOCTL("BLKFLSBUF\n");

fsync_dev(inode->i_rdev);
invalidate_buffers(inode->i_rdev);
@@ -917,8 +934,8 @@
/* set read ahead for block device */
if (!capable(CAP_SYS_ADMIN)) return -EACCES;

- P_IOCTL("%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n",
- lvm_name, (long) arg, MAJOR(inode->i_rdev), minor);
+ P_IOCTL("BLKRASET: %ld sectors for %s\n",
+ (long) arg, kdevname(inode->i_rdev));

if ((long) arg < LVM_MIN_READ_AHEAD ||
(long) arg > LVM_MAX_READ_AHEAD)
@@ -930,7 +947,7 @@

case BLKRAGET:
/* get current read ahead setting */
- P_IOCTL("%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
+ P_IOCTL("BLKRAGET %d\n", lv_ptr->lv_read_ahead);
if (put_user(lv_ptr->lv_read_ahead, (long *)arg))
return -EFAULT;
break;
@@ -956,10 +973,10 @@
copy_to_user((long *) &hd->start, &start,
sizeof(start)) != 0)
return -EFAULT;
- }

- P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n",
- lvm_name, lv_ptr->lv_size / heads / sectors);
+ P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n",
+ lvm_name, cylinders);
+ }
break;


@@ -1077,6 +1093,7 @@
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);
if ((err=lvm_map(&bh, READ)) < 0) {
printk("lvm map failed: %d\n", err);
return -EINVAL;
@@ -1796,7 +1481,7 @@
/*
* character device support function VGDA create
*/
-int lvm_do_vg_create(int minor, void *arg)
+static int lvm_do_vg_create(int minor, void *arg)
{
int ret = 0;
ulong l, ls = 0, p, size;
@@ -1804,8 +1489,6 @@
vg_t *vg_ptr;
lv_t **snap_lv_ptr;

- if (vg[VG_CHR(minor)] != NULL) return -EPERM;
-
if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
printk(KERN_CRIT
"%s -- VG_CREATE: kmalloc error VG at line %d\n",
@@ -1814,35 +1497,45 @@
}
/* get the volume group structure */
if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
+ P_IOCTL("lvm_do_vg_create ERROR: copy VG ptr %p (%d bytes)\n",
+ arg, sizeof(vg_t));
kfree(vg_ptr);
return -EFAULT;
}

+ /* Validate it */
+ if (vg[VG_CHR(minor)] != NULL) {
+ P_IOCTL("lvm_do_vg_create ERROR: VG %d in use\n", minor);
+ kfree(vg_ptr);
+ return -EPERM;
+ }
+
/* we are not that active so far... */
vg_ptr->vg_status &= ~VG_ACTIVE;
- vg[VG_CHR(minor)] = vg_ptr;
- vg[VG_CHR(minor)]->pe_allocated = 0;
+ vg_ptr->pe_allocated = 0;

if (vg_ptr->pv_max > ABS_MAX_PV) {
printk(KERN_WARNING
"%s -- Can't activate VG: ABS_MAX_PV too small\n",
lvm_name);
kfree(vg_ptr);
- vg[VG_CHR(minor)] = NULL;
return -EPERM;
}
+
if (vg_ptr->lv_max > ABS_MAX_LV) {
printk(KERN_WARNING
"%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
lvm_name, vg_ptr->lv_max);
kfree(vg_ptr);
- vg_ptr = NULL;
return -EPERM;
}

+ vg[VG_CHR(minor)] = vg_ptr;
+
/* 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);
@@ -1866,9 +1565,12 @@
/* 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) {
+ P_IOCTL("ERROR: copying LV ptr %p (%d bytes)\n",
+ lvp, sizeof(lv_t));
lvm_do_vg_remove(minor);
return -EFAULT;
}
@@ -1892,7 +1592,7 @@
/* Second path to correct snapshot logical volumes which are not
in place during first path above */
for (l = 0; l < ls; l++) {
- lvp = snap_lv_ptr[l];
+ lv_t *lvp = snap_lv_ptr[l];
if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
lvm_do_vg_remove(minor);
return -EFAULT;
@@ -1986,6 +1683,9 @@
lv_t *lv_ptr = NULL;
pv_t *pv_ptr = NULL;

+ /* 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;

@@ -2086,44 +1784,49 @@
* character device support function physical volume create
*/
static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) {
- pv_t *pv_ptr = NULL;
+ pv_t *pv;

- pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL);
- if (pv_ptr == NULL) {
+ pv = kmalloc(sizeof(pv_t),GFP_KERNEL);
+ if (pv == NULL) {
printk(KERN_CRIT
- "%s -- VG_CREATE: kmalloc error PV at line %d\n",
+ "%s -- PV_CREATE: kmalloc error PV at line %d\n",
lvm_name, __LINE__);
return -ENOMEM;
}
- if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) {
+
+ memset(pv, 0, sizeof(*pv));
+
+ if (copy_from_user(pv, pvp, sizeof(pv_t)) != 0) {
+ P_IOCTL("lvm_do_pv_create ERROR: copy PV ptr %p (%d bytes)\n",
+ pvp, sizeof(pv_t));
+ kfree(pv);
return -EFAULT;
}
/* We don't need the PE list
in kernel space as with LVs pe_t list (see below) */
- pv_ptr->pe = NULL;
- pv_ptr->pe_allocated = 0;
- pv_ptr->pv_status = PV_ACTIVE;
+ pv->pe = NULL;
+ pv->pe_allocated = 0;
+ pv->pv_status = PV_ACTIVE;
vg_ptr->pv_act++;
vg_ptr->pv_cur++;

+ vg_ptr->pv[p] = pv;
return 0;
} /* lvm_do_pv_create() */


/*
- * character device support function physical volume create
+ * character device support function physical volume remove
*/
static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) {
- pv_t *pv_ptr = vg_ptr->pv[p];
+ pv_t *pv = vg_ptr->pv[p];

- lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv_ptr);
- vg_ptr->pe_total -= pv_ptr->pe_total;
+ lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv);
+ vg_ptr->pe_total -= pv->pe_total;
vg_ptr->pv_cur--;
vg_ptr->pv_act--;
-#ifdef LVM_GET_INODE
- lvm_clear_inode(pv_ptr->inode);
-#endif
- kfree(pv_ptr);
+ kfree(pv);
+
vg_ptr->pv[p] = NULL;

return 0;
@@ -2218,8 +1936,8 @@

lv_status_save = lv_ptr->lv_status;
lv_ptr->lv_status &= ~LV_ACTIVE;
- lv_ptr->lv_snapshot_org = \
- lv_ptr->lv_snapshot_prev = \
+ lv_ptr->lv_snapshot_org = NULL;
+ lv_ptr->lv_snapshot_prev = NULL;
lv_ptr->lv_snapshot_next = NULL;
lv_ptr->lv_block_exception = NULL;
lv_ptr->lv_iobuf = NULL;
@@ -2232,9 +1950,10 @@
vg_ptr->lv[l] = lv_ptr;

/* get the PE structures from user space if this
- is no snapshot logical volume */
+ is not a snapshot logical volume */
if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
size = lv_ptr->lv_allocated_le * sizeof(pe_t);
+
if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
printk(KERN_CRIT
"%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
@@ -2254,6 +1975,8 @@
return -ENOMEM;
}
if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) {
+ P_IOCTL("ERROR: copying PE ptr %p (%d bytes)\n",
+ pep, sizeof(size));
vfree(lv_ptr->lv_current_pe);
kfree(lv_ptr);
vg_ptr->lv[l] = NULL;
@@ -2275,6 +1998,15 @@
vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
if (lv_ptr->lv_snapshot_org != NULL) {
size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
+
+ if (!size) {
+ printk(KERN_WARNING
+ "%s -- zero length exception table requested\n",
+ lvm_name);
+ kfree(lv_ptr);
+ return -EINVAL;
+ }
+
if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
printk(KERN_CRIT
"%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
@@ -2400,9 +2134,8 @@

#ifdef LVM_VFS_ENHANCEMENT
/* VFS function call to unlock the filesystem */
- if (lv_ptr->lv_access & LV_SNAPSHOT) {
+ if (lv_ptr->lv_access & LV_SNAPSHOT)
unlockfs(lv_ptr->lv_snapshot_org->lv_dev);
- }
#endif

return 0;
@@ -2848,9 +2617,7 @@
if (lv_ptr->lv_dev == lv->lv_dev)
{
lvm_do_remove_proc_entry_of_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_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
break;
}
@@ -2869,9 +2636,6 @@
{
uint p;
pv_t *pv_ptr;
-#ifdef LVM_GET_INODE
- struct inode *inode_sav;
-#endif

if (vg_ptr == NULL) return -ENXIO;
if (copy_from_user(&pv_change_req, arg,
@@ -2883,20 +2648,14 @@
if (pv_ptr != NULL &&
strcmp(pv_ptr->pv_name,
pv_change_req.pv_name) == 0) {
-#ifdef LVM_GET_INODE
- inode_sav = pv_ptr->inode;
-#endif
if (copy_from_user(pv_ptr,
pv_change_req.pv,
sizeof(pv_t)) != 0)
return -EFAULT;

/* We don't need the PE list
in kernel space as with LVs pe_t list */
pv_ptr->pe = NULL;
-#ifdef LVM_GET_INODE
- pv_ptr->inode = inode_sav;
-#endif
return 0;
}
}
--- linux.orig/drivers/md/lvm-snap.c Thu Oct 25 01:49:46 2001
+++ linux/drivers/md/lvm-snap.c Thu Oct 25 15:00:38 2001
@@ -2,22 +2,22 @@
* kernel/lvm-snap.c
*
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> 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.
*
*/

@@ -105,10 +143,18 @@
unsigned long mask = lv->lv_snapshot_hash_mask;
int chunk_size = lv->lv_chunk_size;

+ if (!hash_table)
+ BUG();
hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
list_add(&exception->hash, hash_table);
}

+/*
+ * Determine if we already have a snapshot chunk for this block.
+ * Return: 1 if it the chunk already exists
+ * 0 if we need to COW this block and allocate a new chunk
+ * -1 if the snapshot was disabled because it ran out of space
+ */
int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector,
unsigned long pe_start, lv_t * lv)
{
@@ -118,6 +166,9 @@
int chunk_size = lv->lv_chunk_size;
lv_block_exception_t * exception;

+ if (!lv->lv_block_exception)
+ return -1;
+
pe_off = pe_start % chunk_size;
pe_adjustment = (*org_sector-pe_off) % chunk_size;
__org_start = *org_sector - pe_adjustment;
@@ -150,26 +204,33 @@
}

lvm_snapshot_release(lv_snap);
+ lv_snap->lv_status &= ~LV_ACTIVE;

printk(KERN_INFO
- "%s -- giving up to snapshot %s on %s due %s\n",
+ "%s -- giving up to snapshot %s on %s: %s\n",
lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name,
reason);
}

-static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks,
+static inline int lvm_snapshot_prepare_blocks(unsigned long *blocks,
unsigned long start,
int nr_sectors,
int blocksize)
{
int i, sectors_per_block, nr_blocks;

- sectors_per_block = blocksize >> 9;
+ sectors_per_block = blocksize / SECTOR_SIZE;
+
+ if (start & (sectors_per_block - 1))
+ return 0;
+
nr_blocks = nr_sectors / sectors_per_block;
start /= sectors_per_block;

for (i = 0; i < nr_blocks; i++)
blocks[i] = start++;
+
+ return 1;
}

inline int lvm_get_blksize(kdev_t dev)
@@ -211,23 +272,34 @@

void lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap)
{
- int id = 0, is = lv_snap->lv_remap_ptr;
- ulong blksize_snap;
+ 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_page);
+
+ if (is == 0)
+ return;

- if (is == 0) return;
is--;
- blksize_snap = lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new);
- is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t));
+ blksize_snap =
+ 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_COW_table[id].pv_org_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_org));
- lv_COW_table[id].pv_org_rsector = cpu_to_le64(lv_snap->lv_block_exception[is].rsector_org);
- lv_COW_table[id].pv_snap_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_new));
- lv_COW_table[id].pv_snap_rsector = cpu_to_le64(lv_snap->lv_block_exception[is].rsector_new);
+ lv_block_exception_t *be = lv_snap->lv_block_exception + is;
+ uint pvn;
+
+ pvn = lvm_pv_get_number(vg, be->rdev_org);
+
+ lv_COW_table[id].pv_org_number = cpu_to_le64(pvn);
+ lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org);
+
+ pvn = lvm_pv_get_number(vg, be->rdev_new);
+
+ lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn);
+ lv_COW_table[id].pv_snap_rsector = cpu_to_le64(be->rsector_new);
}
}

@@ -370,13 +369,11 @@
#ifdef DEBUG_SNAPSHOT
printk(KERN_INFO
"%s -- COW: "
- "org %02d:%02d faulting %lu start %lu, "
- "snap %02d:%02d start %lu, "
+ "org %s faulting %lu start %lu, snap %s start %lu, "
"size %d, pe_start %lu pe_off %lu, virt_sec %lu\n",
lvm_name,
- MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector,
- org_start,
- MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start,
+ kdevname(org_phys_dev), org_phys_sector, org_start,
+ kdevname(snap_phys_dev), snap_start,
chunk_size,
org_pe_start, pe_off,
org_virt_sector);
@@ -434,52 +441,51 @@
return 0;

/* slow path */
- out:
+out:
lvm_drop_snapshot(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;
}

int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors)
{
int bytes, nr_pages, err, i;

- bytes = sectors << 9;
+ bytes = sectors * SECTOR_SIZE;
nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT;
err = expand_kiobuf(iobuf, nr_pages);
- if (err)
- goto out;
+ if (err) goto out;

err = -ENOMEM;
iobuf->locked = 0;
iobuf->nr_pages = 0;
for (i = 0; i < nr_pages; i++)
{
struct page * page;

page = alloc_page(GFP_KERNEL);
- if (!page)
- goto out;
+ if (!page) goto out;

iobuf->maplist[i] = page;
iobuf->nr_pages++;
}
iobuf->offset = 0;

err = 0;
- out:
+
+out:
return err;
}

@@ -547,41 +547,39 @@
while (buckets--)
INIT_LIST_HEAD(hash+buckets);
err = 0;
- out:
+out:
return err;
}

int lvm_snapshot_alloc(lv_t * lv_snap)
{
- int err, blocksize, max_sectors;
+ int ret, max_sectors;

- err = alloc_kiovec(1, &lv_snap->lv_iobuf);
- if (err)
- goto out;
+ /* allocate kiovec to do chunk io */
+ ret = alloc_kiovec(1, &lv_snap->lv_iobuf);
+ if (ret) goto out;

- blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)];
max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9);

- err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
- if (err)
- goto out_free_kiovec;
-
- err = lvm_snapshot_alloc_hash_table(lv_snap);
- if (err)
+ ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
+ if (ret)
goto out_free_kiovec;

+ ret = lvm_snapshot_alloc_hash_table(lv_snap);
+ if (ret) goto out_free_kiovec;

- lv_snap->lv_COW_table_page = alloc_page(GFP_KERNEL);
- if (!lv_snap->lv_COW_table_page)
- goto out_free_kiovec;
+ lv_snap->lv_COW_table_page = alloc_page(GFP_KERNEL);
+ if (!lv_snap->lv_COW_table_page)
+ goto out_free_kiovec;

- out:
- return err;
+out:
+ return ret;

- out_free_kiovec:
+out_free_kiovec:
unmap_kiobuf(lv_snap->lv_iobuf);
free_kiovec(1, &lv_snap->lv_iobuf);
vfree(lv_snap->lv_snapshot_hash_table);
+ lv_snap->lv_iobuf = NULL;
lv_snap->lv_snapshot_hash_table = NULL;
goto out;
}
--- linux.orig/include/linux/lvm.h Thu Oct 25 01:50:48 2001
+++ linux/include/linux/lvm.h Thu Oct 25 15:00:37 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,7 +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
- * 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
@@ -107,6 +125,7 @@
#include <asm/semaphore.h>
#endif /* #ifdef __KERNEL__ */

+
#include <asm/page.h>

#if !defined ( LVM_BLK_MAJOR) || !defined ( LVM_CHAR_MAJOR)
@@ -117,7 +136,7 @@
#undef BLOCK_SIZE
#endif

-#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_ARCH_S390
#define BLOCK_SIZE 4096
#else
#define BLOCK_SIZE 1024
@@ -127,7 +146,8 @@
#define SECTOR_SIZE 512
#endif

-#define LVM_STRUCT_VERSION 1 /* structure version */
+/* structure version */
+#define LVM_STRUCT_VERSION 1

#define LVM_DIR_PREFIX "/dev/"

@@ -293,6 +315,9 @@

/*
* ioctls
+ * FIXME: the last parameter to _IO{W,R,WR} is a data type. The macro will
+ * expand this using sizeof(), so putting "1" there is misleading
+ * because sizeof(1) = sizeof(int) = sizeof(2) = 4 on a 32-bit machine!
*/
/* volume group */
#define VG_CREATE _IOW ( 0xfe, 0x00, 1)
@@ -376,7 +342,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 */


@@ -383,6 +412,9 @@
#define PV_ALLOCATABLE 0x02 /* pv_allocatable */


+/* misc */
+#define LVM_SNAPSHOT_DROPPED_SECTOR 1
+
/*
* Structure definitions core/disk follow
*

--
Andreas Dilger
http://sourceforge.net/projects/ext2resize/
http://www-mddsp.enel.ucalgary.ca/People/adilger/

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/