All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steven Lembark <lembark@wrkhors.com>
To: linux-lvm@sistina.com
Subject: [linux-lvm] Unable to compile 2.4.6
Date: Wed, 04 Jul 2001 19:20:07 -0500	[thread overview]
Message-ID: <9880000.994292407@dizzy> (raw)

[-- Attachment #1: Type: text/plain, Size: 90 bytes --]


Run configure, apply patch.  2.4.6 links before patch, doesn't link after applying patch.

[-- Attachment #2: errmsg --]
[-- Type: application/octet-stream, Size: 127039 bytes --]

make -w bzImage;

make[1]: Leaving directory `/usr/src/linux/arch/i386/lib'
ld -m elf_i386 -T /usr/src/linux/arch/i386/vmlinux.lds -e stext arch/i386/kernel/head.o arch/i386/kernel/init_task.o init/main.o init/version.o \
--start-group \
arch/i386/kernel/kernel.o arch/i386/mm/mm.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o \
drivers/parport/driver.o drivers/char/char.o drivers/block/block.o drivers/misc/misc.o drivers/net/net.o drivers/media/media.o drivers/char/agp/agp.o drivers/char/drm/drm.o drivers/scsi/scsidrv.o drivers/cdrom/driver.o drivers/pci/driver.o drivers/video/video.o drivers/md/mddev.o \
net/network.o \
/usr/src/linux/arch/i386/lib/lib.a /usr/src/linux/lib/lib.a /usr/src/linux/arch/i386/lib/lib.a \
--end-group \
-o vmlinux
drivers/md/mddev.o: In function `__update_hardblocksize':
drivers/md/mddev.o(.text+0x2411): undefined reference to `get_hardblocksize'
drivers/md/mddev.o(.text+0x244d): undefined reference to `get_hardblocksize'
make: *** [vmlinux] Error 1

lvm-0.9.1_beta7-2.4.6.patch

--- linux/include/linux/lvm.h.orig	Wed Jul  4 13:56:52 2001
+++ linux/include/linux/lvm.h	Sun May  6 20:04:40 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 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
@@ -60,6 +60,14 @@
  *    12/11/2000 - removed unneeded timestamp definitions
  *    24/12/2000 - removed LVM_TO_{CORE,DISK}*, use cpu_{from, to}_le*
  *                 instead - Christoph Hellwig
+ *    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
+ *    26/03/2001 - changed lv_v4 to lv_v5 in structure definition (HM)
  *
  */
 
@@ -67,9 +75,11 @@
 #ifndef _LVM_H_INCLUDE
 #define _LVM_H_INCLUDE
 
-#define	_LVM_KERNEL_H_VERSION	"LVM 0.9.1_beta2 (18/01/2001)"
+#define LVM_RELEASE_NAME "0.9.1_beta7"
+#define LVM_RELEASE_DATE "10/04/2001"
+
+#define	_LVM_KERNEL_H_VERSION	"LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")"
 
-#include <linux/config.h>
 #include <linux/version.h>
 
 /*
@@ -90,13 +100,20 @@
    #define DEBUG_READ
    #define DEBUG_GENDISK
    #define DEBUG_VG_CREATE
-   #define DEBUG_LVM_BLK_OPEN
+   #define DEBUG_DEVICE
    #define DEBUG_KFREE
  */
 #endif				/* #ifdef __KERNEL__ */
 
+#ifndef __KERNEL__
+#define __KERNEL__
+#include <linux/kdev_t.h>
+#include <linux/list.h>
+#undef __KERNEL__
+#else
 #include <linux/kdev_t.h>
 #include <linux/list.h>
+#endif				/* #ifndef __KERNEL__ */
 
 #include <asm/types.h>
 #include <linux/major.h>
@@ -117,10 +134,10 @@
 #undef	BLOCK_SIZE
 #endif
 
-#ifdef CONFIG_ARCH_S390 
+#ifdef CONFIG_ARCH_S390
 #define BLOCK_SIZE	4096
 #else
-#define BLOCK_SIZE	1024
+#define BLOCK_SIZE	512
 #endif
 
 #ifndef	SECTOR_SIZE
@@ -141,7 +158,7 @@
 /* set the default structure version */
 #if ( LVM_STRUCT_VERSION == 1)
 #define pv_t pv_v2_t
-#define lv_t lv_v4_t
+#define lv_t lv_v5_t
 #define vg_t vg_v3_t
 #define pv_disk_t pv_disk_v2_t
 #define lv_disk_t lv_disk_v3_t
@@ -299,7 +316,7 @@
 
 #define	LVM_SNAPSHOT_MAX_CHUNK	1024	/* 1024 KB */
 #define	LVM_SNAPSHOT_DEF_CHUNK	64	/* 64  KB */
-#define	LVM_SNAPSHOT_MIN_CHUNK	1	/* 1   KB */
+#define	LVM_SNAPSHOT_MIN_CHUNK	(PAGE_SIZE/1024)	/* 4 or 8 KB */
 
 #define	UNDEF	-1
 #define FALSE	0
@@ -323,7 +340,7 @@
  * ioctls
  */
 /* volume group */
-#define	VG_CREATE               _IOW ( 0xfe, 0x00, 1)
+#define	VG_CREATE_OLD           _IOW ( 0xfe, 0x00, 1)
 #define	VG_REMOVE               _IOW ( 0xfe, 0x01, 1)
 
 #define	VG_EXTEND               _IOW ( 0xfe, 0x03, 1)
@@ -336,6 +353,8 @@
 #define	VG_SET_EXTENDABLE       _IOW ( 0xfe, 0x08, 1)
 #define	VG_RENAME		_IOW ( 0xfe, 0x09, 1)
 
+/* Since 0.9beta6 */
+#define	VG_CREATE               _IOW ( 0xfe, 0x0a, 1)
 
 /* logical volume */
 #define	LV_CREATE               _IOW ( 0xfe, 0x20, 1)
@@ -418,6 +437,9 @@
 #define	PV_ALLOCATABLE       0x02	/* pv_allocatable */
 
 
+/* misc */
+#define LVM_SNAPSHOT_DROPPED_SECTOR 1
+
 /*
  * Structure definitions core/disk follow
  *
@@ -440,10 +462,10 @@
 /* remap physical sector/rdev pairs including hash */
 typedef struct {
 	struct list_head hash;
-	ulong rsector_org;
-	kdev_t rdev_org;
-	ulong rsector_new;
-	kdev_t rdev_new;
+	uint32_t rsector_org;
+	kdev_t   rdev_org;
+	uint32_t rsector_new;
+	kdev_t   rdev_new;
 } lv_block_exception_v1_t;
 
 /* disk stored pe information */
@@ -571,21 +593,21 @@
 /* core PE information */
 typedef struct {
 	kdev_t dev;
-	ulong pe;		/* to be changed if > 2TB */
-	ulong reads;
-	ulong writes;
+	uint32_t pe;		/* to be changed if > 2TB */
+	uint32_t reads;
+	uint32_t writes;
 } pe_t;
 
 typedef struct {
 	char lv_name[NAME_LEN];
 	kdev_t old_dev;
 	kdev_t new_dev;
-	ulong old_pe;
-	ulong new_pe;
+	uint32_t old_pe;
+	uint32_t new_pe;
 } le_remap_req_t;
 
 typedef struct lv_bmap {
-	ulong lv_block;
+	uint32_t lv_block;
 	dev_t lv_dev;
 } lv_bmap_t;
 
@@ -594,7 +616,7 @@
  */
 
 /* core */
-typedef struct lv_v4 {
+typedef struct lv_v5 {
 	char lv_name[NAME_LEN];
 	char vg_name[NAME_LEN];
 	uint lv_access;
@@ -617,9 +639,9 @@
 	uint lv_read_ahead;
 
 	/* delta to version 1 starts here */
-	struct lv_v4 *lv_snapshot_org;
-	struct lv_v4 *lv_snapshot_prev;
-	struct lv_v4 *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;
@@ -627,11 +649,11 @@
 	uint lv_snapshot_minor;
 #ifdef __KERNEL__
 	struct kiobuf *lv_iobuf;
+	struct kiobuf *lv_COW_table_iobuf;
 	struct semaphore lv_snapshot_sem;
 	struct list_head *lv_snapshot_hash_table;
-	ulong lv_snapshot_hash_table_size;
-	ulong lv_snapshot_hash_mask;
-	struct page *lv_COW_table_page;
+	uint32_t lv_snapshot_hash_table_size;
+	uint32_t lv_snapshot_hash_mask;
 	wait_queue_head_t lv_snapshot_wait;
 	int	lv_snapshot_use_rate;
 	void	*vg;
@@ -640,7 +662,7 @@
 #else
 	char dummy[200];
 #endif
-} lv_v4_t;
+} lv_v5_t;
 
 /* disk */
 typedef struct {
@@ -791,7 +813,7 @@
 	struct {
 		kdev_t lv_dev;
 		kdev_t pv_dev;
-		ulong pv_offset;
+		uint32_t pv_offset;
 	} data;
 } pe_lock_req_t;
 
@@ -804,7 +826,7 @@
 
 /* Request structure LV_STATUS_BYINDEX */
 typedef struct {
-	ulong lv_index;
+	uint32_t lv_index;
 	lv_t *lv;
 	/* Transfer size because user space and kernel space differ */
 	ushort size;
@@ -813,7 +835,7 @@
 /* Request structure LV_STATUS_BYDEV... */
 typedef struct {
 	dev_t dev;
-	pv_t *lv;
+	lv_t *lv;
 } lv_status_bydev_req_t;
 
 
--- linux/drivers/md/lvm.c.orig	Wed Jul  4 13:48:04 2001
+++ linux/drivers/md/lvm.c	Sun May  6 20:04:40 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,February,March 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
  *                 <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
@@ -72,7 +73,7 @@
  *                 only other update ioctls are blocked now
  *               - fixed pv->pe to NULL for pv_status
  *               - using lv_req structure in lvm_chr_ioctl() now
- *               - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce()
+ *               - fixed NULL ptr reference bug in lvm_do_lv_extendreduce()
  *                 caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE)
  *    09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to
  *                 handle lgoical volume private read ahead sector
@@ -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,28 +150,70 @@
  *                 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
- *    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)
+ *    25/01/2001 - Allow RO open of an inactive LV so it can be reactivated.
+ *    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
+ *    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
+ *    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]
+ *               - fixed user address accessing bug in lvm_do_lv_create()
+ *                 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.
+ *               - 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 - 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 - 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)
  *
  */
 
+#include <linux/version.h>
 
-static char *lvm_version = "LVM version 0.9.1_beta2  by Heinz Mauelshagen  (18/01/2001)\n";
-static char *lvm_short_version = "version 0.9.1_beta2 (18/01/2001)";
-
-#define MAJOR_NR	LVM_BLK_MAJOR
-#define	DEVICE_OFF(device)
+#define MAJOR_NR LVM_BLK_MAJOR
+#define DEVICE_OFF(device)
+#define LOCAL_END_REQUEST
 
 /* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
 /* #define	LVM_VFS_ENHANCEMENT */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
-
 #include <linux/kernel.h>
 #include <linux/vmalloc.h>
+
 #include <linux/slab.h>
 #include <linux/init.h>
 
@@ -180,6 +224,8 @@
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
 #include <linux/locks.h>
+
+
 #include <linux/smp_lock.h>
 #include <asm/ioctl.h>
 #include <asm/segment.h>
@@ -195,7 +241,7 @@
 #include <linux/errno.h>
 #include <linux/lvm.h>
 
-#include "lvm-snap.h"
+#include "lvm-internal.h"
 
 #define	LVM_CORRECT_READ_AHEAD( a) \
    if      ( a < LVM_MIN_READ_AHEAD || \
@@ -205,24 +251,6 @@
 #  define WRITEA WRITE
 #endif
 
-/* debug macros */
-#ifdef DEBUG_IOCTL
-#define P_IOCTL(fmt, args...) printk(KERN_DEBUG "lvm ioctl: " fmt, ## args)
-#else
-#define P_IOCTL(fmt, args...)
-#endif
-
-#ifdef DEBUG_MAP
-#define P_MAP(fmt, args...) printk(KERN_DEBUG "lvm map: " fmt, ## args)
-#else
-#define P_MAP(fmt, args...)
-#endif
-
-#ifdef DEBUG_KFREE
-#define P_KFREE(fmt, args...) printk(KERN_DEBUG "lvm kfree: " fmt, ## args)
-#else
-#define P_KFREE(fmt, args...)
-#endif
 
 /*
  * External function prototypes
@@ -232,27 +260,14 @@
 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 *);
-int lvm_proc_read_lv_info(char *, char **, off_t, int, int *, void *);
-int lvm_proc_read_pv_info(char *, char **, off_t, int, int *, void *);
-static int lvm_proc_get_global_info(char *, char **, off_t, int, int *, void *);
-
-void lvm_do_create_devfs_entry_of_vg ( vg_t *);
-
-void lvm_do_create_proc_entry_of_vg ( vg_t *);
-void lvm_do_remove_proc_entry_of_vg ( vg_t *);
-void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *);
-void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *);
-void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *);
-void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *);
 
 /* End external function prototypes */
 
@@ -284,33 +299,38 @@
 
 static int lvm_do_pv_change(vg_t*, void*);
 static int lvm_do_pv_status(vg_t *, void *);
+static int lvm_do_pv_flush(void *);
 
-static int lvm_do_vg_create(int, void *);
+static int lvm_do_vg_create(void *, int minor);
 static int lvm_do_vg_extend(vg_t *, void *);
 static int lvm_do_vg_reduce(vg_t *, void *);
 static int lvm_do_vg_rename(vg_t *, void *);
 static int lvm_do_vg_remove(int);
 static void lvm_geninit(struct gendisk *);
-static char *lvm_show_uuid ( char *);
+static void __update_hardblocksize(lv_t *lv);
+
+
 #ifdef LVM_HD_NAME
 void lvm_hd_name(char *, int);
 #endif
 /* END Internal function prototypes */
 
 
-/* volume group descriptor area pointers */
-static vg_t *vg[ABS_MAX_VG];
+/* variables */
+char *lvm_version = "LVM version "LVM_RELEASE_NAME"  by Heinz Mauelshagen  "
+                    "("LVM_RELEASE_DATE")\n";
+char *lvm_short_version = "version "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")";
+ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
+int loadtime = 0;
+const char *const lvm_name = LVM_NAME;
 
-static devfs_handle_t lvm_devfs_handle;
-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];
+
+/* 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;
-static pe_t *pep1 = NULL;
-static char *basename = NULL;
 
 
 /* map from block minor number to VG and LV numbers */
@@ -323,7 +343,6 @@
 
 /* Request structures (lvm_chr_ioctl()) */
 static pv_change_req_t pv_change_req;
-static pv_flush_req_t pv_flush_req;
 static pv_status_req_t pv_status_req;
 static pe_lock_req_t pe_lock_req;
 static le_remap_req_t le_remap_req;
@@ -335,32 +354,27 @@
 
 static char pv_name[NAME_LEN];
 /* static char rootvg[NAME_LEN] = { 0, }; */
-const char *const lvm_name = LVM_NAME;
 static int lock = 0;
-static int loadtime = 0;
+static int _lock_open_count = 0;
 static uint vg_count = 0;
 static long lvm_chr_open_count = 0;
-static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
 static DECLARE_WAIT_QUEUE_HEAD(lvm_wait);
-static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait);
 
 static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
 
-static struct proc_dir_entry *lvm_proc_dir = NULL;
-static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;
-struct proc_dir_entry *pde = NULL;
+static struct buffer_head *_pe_requests;
+static struct semaphore _pe_lock;
 
-static struct file_operations lvm_chr_fops =
-{
+
+struct file_operations lvm_chr_fops = {
 	open:		lvm_chr_open,
 	release:	lvm_chr_close,
 	ioctl:		lvm_chr_ioctl,
 };
 
-
 /* block device operations structure needed for 2.3.38? and above */
-static struct block_device_operations lvm_blk_dops =
+struct block_device_operations lvm_blk_dops =
 {
 	open: 		lvm_blk_open,
 	release:	lvm_blk_close,
@@ -370,10 +384,10 @@
 
 /* gendisk structures */
 static struct hd_struct lvm_hd_struct[MAX_LV];
-static int lvm_blocksizes[MAX_LV] =
-{0,};
-static int lvm_size[MAX_LV] =
-{0,};
+static int lvm_blocksizes[MAX_LV];
+static int lvm_hardsectsizes[MAX_LV];
+static int lvm_size[MAX_LV];
+
 static struct gendisk lvm_gendisk =
 {
 	MAJOR_NR,		/* major # */
@@ -408,18 +422,7 @@
 		return -EIO;
 	}
 
-	lvm_devfs_handle = devfs_register(
-		0 , "lvm", 0, 0, LVM_CHAR_MAJOR,
-		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-		&lvm_chr_fops, NULL);
-
-	lvm_proc_dir = create_proc_entry (LVM_DIR, S_IFDIR, &proc_root);
-	if (lvm_proc_dir != NULL) {
-		lvm_proc_vg_subdir = create_proc_entry (LVM_VG_SUBDIR, S_IFDIR, lvm_proc_dir);
-		pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir);
-		if ( pde != NULL) pde->read_proc = &lvm_proc_get_global_info;
-	}
-
+	lvm_init_fs();
 	lvm_init_vars();
 	lvm_geninit(&lvm_gendisk);
 
@@ -445,6 +448,10 @@
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
 
 
+	/* initialise the pe lock */
+	pe_lock_req.lock = UNLOCK_PE;
+	init_MUTEX(&_pe_lock);
+
 	/* optional read root VGDA */
 /*
    if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);
@@ -463,16 +470,14 @@
 	return 0;
 } /* lvm_init() */
 
-
 /*
  * cleanup...
  */
+
 static void lvm_cleanup(void)
 {
 	struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL;
 
-	devfs_unregister (lvm_devfs_handle);
-
 	if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) {
 		printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
 	}
@@ -481,6 +486,7 @@
 	}
 
 
+
 	gendisk_ptr = gendisk_ptr_prev = gendisk_head;
 	while (gendisk_ptr != NULL) {
 		if (gendisk_ptr == &lvm_gendisk)
@@ -496,25 +502,23 @@
 	blksize_size[MAJOR_NR] = NULL;
 	hardsect_size[MAJOR_NR] = NULL;
 
-	remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
-	remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
-	remove_proc_entry(LVM_DIR, &proc_root);
-
 #ifdef LVM_HD_NAME
 	/* reference from linux/drivers/block/genhd.c */
 	lvm_hd_name_ptr = NULL;
 #endif
 
+	/* unregister with procfs and devfs */
+	lvm_fin_fs();
+
 	printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
 
 	return;
 }	/* lvm_cleanup() */
 
-
 /*
  * support function to initialize lvm variables
  */
-void __init lvm_init_vars(void)
+static void __init lvm_init_vars(void)
 {
 	int v;
 
@@ -550,16 +554,12 @@
 /*
  * 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);
 
-#ifdef DEBUG
-	printk(KERN_DEBUG
-	 "%s -- lvm_chr_open MINOR: %d  VG#: %d  mode: 0x%X  lock: %d\n",
-	       lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
-#endif
+	P_DEV("%s -- lvm_chr_open MINOR: %d  VG#: %d  mode: 0x%X  lock: %d\n",
+	      lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
 
 	/* super user validation */
 	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
@@ -567,6 +567,11 @@
 	/* 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);
+
 	lvm_chr_open_count++;
 
 	MOD_INC_USE_COUNT;
@@ -583,7 +588,7 @@
  *
  */
 static int lvm_chr_ioctl(struct inode *inode, struct file *file,
-			 uint command, ulong a)
+		  uint command, ulong a)
 {
 	int minor = MINOR(inode->i_rdev);
 	uint extendable, l, v;
@@ -644,9 +649,13 @@
 		   physical volume (move's done in user space's pvmove) */
 		return lvm_do_pe_lock_unlock(vg_ptr,arg);
 
-	case VG_CREATE:
+	case VG_CREATE_OLD:
 		/* create a VGDA */
-		return lvm_do_vg_create(minor, arg);
+		return lvm_do_vg_create(arg, minor);
+
+	case VG_CREATE:
+	        /* create a VGDA, assume VG number is filled in */
+		return lvm_do_vg_create(arg, -1);
 
 	case VG_EXTEND:
 		/* extend a volume group */
@@ -697,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,
@@ -752,6 +761,7 @@
 
 
 	case LV_STATUS_BYDEV:
+		/* get status of a logical volume by device */
 		return lvm_do_lv_status_bydev(vg_ptr, arg);
 
 
@@ -767,18 +777,12 @@
 
 	case PV_FLUSH:
 		/* physical volume buffer flush/invalidate */
-		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);
-		return 0;
+		return lvm_do_pv_flush(arg);
 
 
 	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;
 	}
@@ -790,7 +794,7 @@
 /*
  * character device close routine
  */
-static int lvm_chr_close(struct inode *inode, struct file *file)
+int lvm_chr_close(struct inode *inode, struct file *file)
 {
 #ifdef DEBUG
 	int minor = MINOR(inode->i_rdev);
@@ -806,10 +810,16 @@
 #endif
 
 	if (lvm_chr_open_count > 0) lvm_chr_open_count--;
-	if (lock == current->pid) {
-		lock = 0;	/* release lock */
-		wake_up_interruptible(&lvm_wait);
+
+	spin_lock(&lvm_lock);
+	if(lock == current->pid) {
+		if(!_lock_open_count) {
+			lock = 0;
+			wake_up_interruptible(&lvm_wait);
+		} else
+			_lock_open_count--;
 	}
+	spin_unlock(&lvm_lock);
 
 	MOD_DEC_USE_COUNT;
 
@@ -833,11 +843,8 @@
 	lv_t *lv_ptr;
 	vg_t *vg_ptr = vg[VG_BLK(minor)];
 
-#ifdef DEBUG_LVM_BLK_OPEN
-	printk(KERN_DEBUG
-	  "%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  mode: 0x%X\n",
-	    lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);
-#endif
+	P_DEV("%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  mode: 0x%X\n",
+	      lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);
 
 #ifdef LVM_TOTAL_RESET
 	if (lvm_reset_spindown > 0)
@@ -850,12 +857,16 @@
 	    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 */
-		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;
@@ -867,12 +878,7 @@
 
 		MOD_INC_USE_COUNT;
 
-#ifdef DEBUG_LVM_BLK_OPEN
-		printk(KERN_DEBUG
-		       "%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  size: %d\n",
-		       lvm_name, minor, VG_BLK(minor), LV_BLK(minor),
-		       lv_ptr->lv_size);
-#endif
+		P_DEV("%s -- OPEN OK, LV size %d\n", lvm_name, lv_ptr->lv_size);
 
 		return 0;
 	}
@@ -892,7 +898,7 @@
 	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  "
+	P_IOCTL("%s -- lvm_blk_ioctl MINOR: %d  command: 0x%X  arg: %lX  "
 		"VG#: %dl  LV#: %d\n",
 		lvm_name, minor, command, (ulong) arg,
 		VG_BLK(minor), LV_BLK(minor));
@@ -922,8 +928,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("%s -- lvm_blk_ioctl -- BLKRASET: %ld sectors for %s\n",
+			lvm_name, (long) arg, kdevname(inode->i_rdev));
 
 		if ((long) arg < LVM_MIN_READ_AHEAD ||
 		    (long) arg > LVM_MAX_READ_AHEAD)
@@ -960,10 +966,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;
 
 
@@ -987,6 +993,11 @@
 		break;
 
 	case LV_BMAP:
+                /* turn logical block into (dev_t, block).  non privileged. */
+                /* don't bmap a snapshot, since the mapping can change */
+		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;
@@ -998,40 +1009,11 @@
 		break;
 
 	case LV_SNAPSHOT_USE_RATE:
-		if (!(lv_ptr->lv_access & LV_SNAPSHOT)) return -EPERM;
-		{
-			lv_snapshot_use_rate_req_t	lv_snapshot_use_rate_req;
-
-			if (copy_from_user(&lv_snapshot_use_rate_req, arg,
-					   sizeof(lv_snapshot_use_rate_req_t)))
-				return -EFAULT;
-			if (lv_snapshot_use_rate_req.rate < 0 ||
-			    lv_snapshot_use_rate_req.rate  > 100) return -EFAULT;
-
-			switch (lv_snapshot_use_rate_req.block)
-			{
-			case 0:
-				lv_ptr->lv_snapshot_use_rate = lv_snapshot_use_rate_req.rate;
-				if (lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end < lv_ptr->lv_snapshot_use_rate)
-					interruptible_sleep_on (&lv_ptr->lv_snapshot_wait);
-				break;
-
-			case O_NONBLOCK:
-				break;
-
-			default:
-				return -EFAULT;
-			}
-			lv_snapshot_use_rate_req.rate = lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end;
-			if (copy_to_user(arg, &lv_snapshot_use_rate_req,
-					 sizeof(lv_snapshot_use_rate_req_t)))
-				return -EFAULT;
-		}
-		break;
+		return lvm_get_snapshot_use_rate(lv_ptr, arg);
 
 	default:
 		printk(KERN_WARNING
-		       "%s -- lvm_blk_ioctl: unknown command %d\n",
+		       "%s -- lvm_blk_ioctl: unknown command 0x%x\n",
 		       lvm_name, command);
 		return -EINVAL;
 	}
@@ -1064,6 +1046,38 @@
 	return 0;
 } /* lvm_blk_close() */
 
+static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg)
+{
+	lv_snapshot_use_rate_req_t lv_rate_req;
+
+	if (!(lv->lv_access & LV_SNAPSHOT))
+		return -EPERM;
+
+	if (copy_from_user(&lv_rate_req, arg, sizeof(lv_rate_req)))
+		return -EFAULT;
+
+	if (lv_rate_req.rate < 0 || lv_rate_req.rate > 100)
+		return -EINVAL;
+
+	switch (lv_rate_req.block) {
+	case 0:
+		lv->lv_snapshot_use_rate = lv_rate_req.rate;
+		if (lv->lv_remap_ptr * 100 / lv->lv_remap_end <
+		    lv->lv_snapshot_use_rate)
+			interruptible_sleep_on(&lv->lv_snapshot_wait);
+		break;
+
+	case O_NONBLOCK:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	lv_rate_req.rate = lv->lv_remap_ptr * 100 / lv->lv_remap_end;
+
+	return copy_to_user(arg, &lv_rate_req,
+			    sizeof(lv_rate_req)) ? -EFAULT : 0;
+}
 
 static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result)
 {
@@ -1075,398 +1089,16 @@
 		return -EFAULT;
 
 	memset(&bh,0,sizeof bh);
-	bh.b_rsector = block;
-	bh.b_dev = bh.b_rdev = inode->i_dev;
+	bh.b_blocknr = block;
+	bh.b_dev = bh.b_rdev = inode->i_rdev;
 	bh.b_size = lvm_get_blksize(bh.b_dev);
 	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, &user_result->lv_block) ? -EFAULT : 0;
-}
-
-
-/*
- * provide VG info for proc filesystem use (global)
- */
-int lvm_vg_info(vg_t *vg_ptr, char *buf) {
-	int sz = 0;
-	char inactive_flag = ' ';
-
-	if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
-	sz = sprintf(buf,
-		     "\nVG: %c%s  [%d PV, %d LV/%d open] "
-		     " PE Size: %d KB\n"
-		     "  Usage [KB/PE]: %d /%d total  "
-		     "%d /%d used  %d /%d free",
-		     inactive_flag,
-		     vg_ptr->vg_name,
-		     vg_ptr->pv_cur,
-		     vg_ptr->lv_cur,
-		     vg_ptr->lv_open,
-	     	     vg_ptr->pe_size >> 1,
-		     vg_ptr->pe_size * vg_ptr->pe_total >> 1,
-		     vg_ptr->pe_total,
-		     vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
-	     	     vg_ptr->pe_allocated,
-		     (vg_ptr->pe_total - vg_ptr->pe_allocated) *
-	     	     vg_ptr->pe_size >> 1,
-		     vg_ptr->pe_total - vg_ptr->pe_allocated);
-	return sz;
-}
-
-
-/*
- * provide LV info for proc filesystem use (global)
- */
-int lvm_lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) {
-	int sz = 0;
-	char inactive_flag = 'A', allocation_flag = ' ',
-	     stripes_flag = ' ', rw_flag = ' ';
-
-	if (!(lv_ptr->lv_status & LV_ACTIVE))
-		inactive_flag = 'I';
-	rw_flag = 'R';
-	if (lv_ptr->lv_access & LV_WRITE)
-		rw_flag = 'W';
-	allocation_flag = 'D';
-	if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
-		allocation_flag = 'C';
-	stripes_flag = 'L';
-	if (lv_ptr->lv_stripes > 1)
-		stripes_flag = 'S';
-	sz += sprintf(buf+sz,
-		      "[%c%c%c%c",
-		      inactive_flag,
-	 rw_flag,
-		      allocation_flag,
-		      stripes_flag);
-	if (lv_ptr->lv_stripes > 1)
-		sz += sprintf(buf+sz, "%-2d",
-			      lv_ptr->lv_stripes);
-	else
-		sz += sprintf(buf+sz, "  ");
-	basename = strrchr(lv_ptr->lv_name, '/');
-	if ( basename == 0) basename = lv_ptr->lv_name;
-	else                basename++;
-	sz += sprintf(buf+sz, "] %-25s", basename);
-	if (strlen(basename) > 25)
-		sz += sprintf(buf+sz,
-			      "\n                              ");
-	sz += sprintf(buf+sz, "%9d /%-6d   ",
-		      lv_ptr->lv_size >> 1,
-		      lv_ptr->lv_size / vg_ptr->pe_size);
-
-	if (lv_ptr->lv_open == 0)
-		sz += sprintf(buf+sz, "close");
-	else
-		sz += sprintf(buf+sz, "%dx open",
-			      lv_ptr->lv_open);
-
-	return sz;
-}
-
-
-/*
- * provide PV info for proc filesystem use (global)
- */
-int lvm_pv_info(pv_t *pv_ptr, char *buf) {
-	int sz = 0;
-	char inactive_flag = 'A', allocation_flag = ' ';
-	char *pv_name = NULL;
-
-	if (!(pv_ptr->pv_status & PV_ACTIVE))
-		inactive_flag = 'I';
-	allocation_flag = 'A';
-	if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE))
-		allocation_flag = 'N';
-	pv_name = strrchr(pv_ptr->pv_name+1,'/');
-	if ( pv_name == 0) pv_name = pv_ptr->pv_name;
-	else               pv_name++;
-	sz = sprintf(buf,
-		     "[%c%c] %-21s %8d /%-6d  "
-		     "%8d /%-6d  %8d /%-6d",
-		     inactive_flag,
-		     allocation_flag,
-		     pv_name,
-		     pv_ptr->pe_total *
-		     pv_ptr->pe_size >> 1,
-		     pv_ptr->pe_total,
-		     pv_ptr->pe_allocated *
-		     pv_ptr->pe_size >> 1,
-		     pv_ptr->pe_allocated,
-		     (pv_ptr->pe_total -
-		      pv_ptr->pe_allocated) *
-		     pv_ptr->pe_size >> 1,
-		     pv_ptr->pe_total -
-		     pv_ptr->pe_allocated);
-	return sz;
-}
-
-
-/*
- * Support functions /proc-Filesystem
- */
-
-#define  LVM_PROC_BUF   ( i == 0 ? dummy_buf : &buf[sz])
-
-/*
- * provide global LVM information
- */
-static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int count, int *eof, void *data)
-{
-	int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
-	 lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds;
-	static off_t sz;
-	off_t sz_last;
-	static char *buf = NULL;
-	static char dummy_buf[160];	/* sized for 2 lines */
-	vg_t *vg_ptr;
-	lv_t *lv_ptr;
-	pv_t *pv_ptr;
-
-
-#ifdef DEBUG_LVM_PROC_GET_INFO
-	printk(KERN_DEBUG
-	       "%s - lvm_proc_get_global_info CALLED  pos: %lu  count: %d  whence: %d\n",
-	       lvm_name, pos, count, whence);
-#endif
-
-	MOD_INC_USE_COUNT;
-
-	if (pos == 0 || buf == NULL) {
-		sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \
-		lv_open_total = pe_t_bytes = hash_table_bytes = \
-		lv_block_exception_t_bytes = 0;
-
-		/* search for activity */
-		for (v = 0; v < ABS_MAX_VG; v++) {
-			if ((vg_ptr = vg[v]) != NULL) {
-				vg_counter++;
-				pv_counter += vg_ptr->pv_cur;
-				lv_counter += vg_ptr->lv_cur;
-				if (vg_ptr->lv_cur > 0) {
-					for (l = 0; l < vg[v]->lv_max; l++) {
-						if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
-							pe_t_bytes += lv_ptr->lv_allocated_le;
-							hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size;
-							if (lv_ptr->lv_block_exception != NULL)
-								lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
-							if (lv_ptr->lv_open > 0) {
-								lv_open_counter++;
-								lv_open_total += lv_ptr->lv_open;
-							}
-						}
-					}
-				}
-			}
-		}
-		pe_t_bytes *= sizeof(pe_t);
-		lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
-
-		if (buf != NULL) {
-			P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__);
-			lock_kernel();
-			vfree(buf);
-			unlock_kernel();
-			buf = NULL;
-		}
-		/* 2 times: first to get size to allocate buffer,
-		   2nd to fill the malloced buffer */
-		for (i = 0; i < 2; i++) {
-			sz = 0;
-			sz += sprintf(LVM_PROC_BUF,
-				      "LVM "
-#ifdef MODULE
-				      "module"
-#else
-				      "driver"
-#endif
-				      " %s\n\n"
-				    "Total:  %d VG%s  %d PV%s  %d LV%s ",
-				      lvm_short_version,
-				  vg_counter, vg_counter == 1 ? "" : "s",
-				  pv_counter, pv_counter == 1 ? "" : "s",
-				 lv_counter, lv_counter == 1 ? "" : "s");
-			sz += sprintf(LVM_PROC_BUF,
-				      "(%d LV%s open",
-				      lv_open_counter,
-				      lv_open_counter == 1 ? "" : "s");
-			if (lv_open_total > 0)
-				sz += sprintf(LVM_PROC_BUF,
-					      " %d times)\n",
-					      lv_open_total);
-			else
-				sz += sprintf(LVM_PROC_BUF, ")");
-			sz += sprintf(LVM_PROC_BUF,
-				      "\nGlobal: %lu bytes malloced   IOP version: %d   ",
-				      vg_counter * sizeof(vg_t) +
-				      pv_counter * sizeof(pv_t) +
-				      lv_counter * sizeof(lv_t) +
-				      pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last,
-				      lvm_iop_version);
-
-			seconds = CURRENT_TIME - loadtime;
-			if (seconds < 0)
-				loadtime = CURRENT_TIME + seconds;
-			if (seconds / 86400 > 0) {
-				sz += sprintf(LVM_PROC_BUF, "%d day%s ",
-					      seconds / 86400,
-					      seconds / 86400 == 0 ||
-					 seconds / 86400 > 1 ? "s" : "");
-			}
-			sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
-				      (seconds % 86400) / 3600,
-				      (seconds % 3600) / 60,
-				      seconds % 60);
-
-			if (vg_counter > 0) {
-				for (v = 0; v < ABS_MAX_VG; v++) {
-					/* volume group */
-					if ((vg_ptr = vg[v]) != NULL) {
-						sz += lvm_vg_info(vg_ptr, LVM_PROC_BUF);
-
-						/* physical volumes */
-						sz += sprintf(LVM_PROC_BUF,
-							      "\n  PV%s ",
-							      vg_ptr->pv_cur == 1 ? ": " : "s:");
-						c = 0;
-						for (p = 0; p < vg_ptr->pv_max; p++) {
-							if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
-								sz += lvm_pv_info(pv_ptr, LVM_PROC_BUF);
-
-								c++;
-								if (c < vg_ptr->pv_cur)
-									sz += sprintf(LVM_PROC_BUF,
-										      "\n       ");
-							}
-						}
-
-						/* logical volumes */
-						sz += sprintf(LVM_PROC_BUF,
-							   "\n    LV%s ",
-							      vg_ptr->lv_cur == 1 ? ": " : "s:");
-						c = 0;
-						for (l = 0; l < vg_ptr->lv_max; l++) {
-							if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
-								sz += lvm_lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF);
-								c++;
-								if (c < vg_ptr->lv_cur)
-									sz += sprintf(LVM_PROC_BUF,
-										      "\n         ");
-							}
-						}
-						if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
-						sz += sprintf(LVM_PROC_BUF, "\n");
-					}
-				}
-			}
-			if (buf == NULL) {
-				lock_kernel();
-				buf = vmalloc(sz);
-				unlock_kernel();
-				if (buf == NULL) {
-					sz = 0;
-					MOD_DEC_USE_COUNT;
-					return sprintf(page, "%s - vmalloc error at line %d\n",
-						     lvm_name, __LINE__);
-				}
-			}
-			sz_last = sz;
-		}
-	}
-	MOD_DEC_USE_COUNT;
-	if (pos > sz - 1) {
-		lock_kernel();
-		vfree(buf);
-		unlock_kernel();
-		buf = NULL;
-		return 0;
-	}
-	*start = &buf[pos];
-	if (sz - pos < count)
-		return sz - pos;
-	else
-		return count;
-} /* lvm_proc_get_global_info() */
-
-
-/*
- * provide VG information
- */
-int lvm_proc_read_vg_info(char *page, char **start, off_t off,
-			  int count, int *eof, void *data) {
-	int sz = 0;
-	vg_t *vg = data;
-
-	sz += sprintf ( page+sz, "name:         %s\n", vg->vg_name);
-	sz += sprintf ( page+sz, "size:         %u\n",
-		        vg->pe_total * vg->pe_size / 2);
-	sz += sprintf ( page+sz, "access:       %u\n", vg->vg_access);
-	sz += sprintf ( page+sz, "status:       %u\n", vg->vg_status);
-	sz += sprintf ( page+sz, "number:       %u\n", vg->vg_number);
-	sz += sprintf ( page+sz, "LV max:       %u\n", vg->lv_max);
-	sz += sprintf ( page+sz, "LV current:   %u\n", vg->lv_cur);
-	sz += sprintf ( page+sz, "LV open:      %u\n", vg->lv_open);
-	sz += sprintf ( page+sz, "PV max:       %u\n", vg->pv_max);
-	sz += sprintf ( page+sz, "PV current:   %u\n", vg->pv_cur);
-	sz += sprintf ( page+sz, "PV active:    %u\n", vg->pv_act);
-	sz += sprintf ( page+sz, "PE size:      %u\n", vg->pe_size / 2);
-	sz += sprintf ( page+sz, "PE total:     %u\n", vg->pe_total);
-	sz += sprintf ( page+sz, "PE allocated: %u\n", vg->pe_allocated);
-	sz += sprintf ( page+sz, "uuid:         %s\n", lvm_show_uuid(vg->vg_uuid));
-
-	return sz;
-}
-
-
-/*
- * provide LV information
- */
-int lvm_proc_read_lv_info(char *page, char **start, off_t off,
-			  int count, int *eof, void *data) {
-	int sz = 0;
-	lv_t *lv = data;
-
-	sz += sprintf ( page+sz, "name:         %s\n", lv->lv_name);
-	sz += sprintf ( page+sz, "size:         %u\n", lv->lv_size);
-	sz += sprintf ( page+sz, "access:       %u\n", lv->lv_access);
-	sz += sprintf ( page+sz, "status:       %u\n", lv->lv_status);
-	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);
-	sz += sprintf ( page+sz, "device:       %02u:%02u\n",
-                        MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
-
-	return sz;
-}
-
-
-/*
- * provide PV information
- */
-int lvm_proc_read_pv_info(char *page, char **start, off_t off,
-			  int count, int *eof, void *data) {
-	int sz = 0;
-	pv_t *pv = data;
-
-	sz += sprintf ( page+sz, "name:         %s\n", pv->pv_name);
-	sz += sprintf ( page+sz, "size:         %u\n", pv->pv_size);
-	sz += sprintf ( page+sz, "status:       %u\n", pv->pv_status);
-	sz += sprintf ( page+sz, "number:       %u\n", pv->pv_number);
-	sz += sprintf ( page+sz, "allocatable:  %u\n", pv->pv_allocatable);
-	sz += sprintf ( page+sz, "LV current:   %u\n", pv->lv_cur);
-	sz += sprintf ( page+sz, "PE size:      %u\n", pv->pe_size / 2);
-	sz += sprintf ( page+sz, "PE total:     %u\n", pv->pe_total);
-	sz += sprintf ( page+sz, "PE allocated: %u\n", pv->pe_allocated);
-	sz += sprintf ( page+sz, "device:       %02u:%02u\n",
-                        MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
-	sz += sprintf ( page+sz, "uuid:         %s\n", lvm_show_uuid(pv->pv_uuid));
-
-
-	return sz;
+	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));
 }
 
 
@@ -1474,172 +1106,164 @@
  * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c
  * (see init_module/lvm_init)
  */
+static inline void __remap_snapshot(kdev_t rdev, ulong rsector,
+				    ulong pe_start, lv_t *lv, vg_t *vg) {
+	if (!lvm_snapshot_remap_block(&rdev, &rsector, pe_start, lv) &&
+	    !lvm_snapshot_COW(rdev, rsector, pe_start, rsector, vg, lv))
+		lvm_write_COW_table_block(vg, lv);
+}
+
 static int lvm_map(struct buffer_head *bh, int rw)
 {
 	int minor = MINOR(bh->b_rdev);
-	int ret = 0;
 	ulong index;
 	ulong pe_start;
 	ulong size = bh->b_size >> 9;
-	ulong rsector_tmp = bh->b_rsector;
-	ulong rsector_sav;
-	kdev_t rdev_tmp = bh->b_rdev;
-	kdev_t rdev_sav;
+	ulong rsector_org = bh->b_rsector;
+	ulong rsector_map;
+	kdev_t rdev_map;
 	vg_t *vg_this = vg[VG_BLK(minor)];
 	lv_t *lv = vg_this->lv[LV_BLK(minor)];
 
 
+	down(&lv->lv_snapshot_sem);
 	if (!(lv->lv_status & LV_ACTIVE)) {
 		printk(KERN_ALERT
 		       "%s - lvm_map: ll_rw_blk for inactive LV %s\n",
 		       lvm_name, lv->lv_name);
-		return -1;
+		goto bad;
 	}
 
 	if ((rw == WRITE || rw == WRITEA) &&
 	    !(lv->lv_access & LV_WRITE)) {
 		printk(KERN_CRIT
-		    "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
+		       "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
 		       lvm_name, lv->lv_name);
-		return -1;
+		goto bad;
 	}
 
-	P_MAP("%s - lvm_map minor:%d  *rdev: %02d:%02d  *rsector: %lu  "
-	      "size:%lu\n",
+	P_MAP("%s - lvm_map minor: %d  *rdev: %s  *rsector: %lu  size:%lu\n",
 	      lvm_name, minor,
-	      MAJOR(rdev_tmp),
-	      MINOR(rdev_tmp),
-	      rsector_tmp, size);
+	      kdevname(bh->b_dev),
+	      rsector_org, size);
 
-	if (rsector_tmp + size > lv->lv_size) {
+	if (rsector_org + size > lv->lv_size) {
 		printk(KERN_ALERT
 		       "%s - lvm_map access beyond end of device; *rsector: "
                        "%lu or size: %lu wrong for minor: %2d\n",
-                       lvm_name, rsector_tmp, size, minor);
-		return -1;
+                       lvm_name, rsector_org, size, minor);
+		goto bad;
 	}
-	rsector_sav = rsector_tmp;
-	rdev_sav = rdev_tmp;
 
-lvm_second_remap:
-	/* linear mapping */
-	if (lv->lv_stripes < 2) {
+
+	if (lv->lv_stripes < 2) { /* linear mapping */
 		/* get the index */
-		index = rsector_tmp / vg_this->pe_size;
+		index = rsector_org / vg_this->pe_size;
 		pe_start = lv->lv_current_pe[index].pe;
-		rsector_tmp = lv->lv_current_pe[index].pe +
-		    (rsector_tmp % vg_this->pe_size);
-		rdev_tmp = lv->lv_current_pe[index].dev;
-
-		P_MAP("lv_current_pe[%ld].pe: %ld  rdev: %02d:%02d  "
-		      "rsector:%ld\n",
-		       index,
-		       lv->lv_current_pe[index].pe,
-		       MAJOR(rdev_tmp),
-		       MINOR(rdev_tmp),
-		       rsector_tmp);
+		rsector_map = lv->lv_current_pe[index].pe +
+			(rsector_org % vg_this->pe_size);
+		rdev_map = lv->lv_current_pe[index].dev;
+
+		P_MAP("lv_current_pe[%ld].pe: %d  rdev: %s  rsector:%ld\n",
+		      index, lv->lv_current_pe[index].pe,
+		      kdevname(rdev_map), rsector_map);
 
-		/* striped mapping */
-	} else {
+	} else {		/* striped mapping */
 		ulong stripe_index;
 		ulong stripe_length;
 
 		stripe_length = vg_this->pe_size * lv->lv_stripes;
-		stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize;
-		index = rsector_tmp / stripe_length +
-		    (stripe_index % lv->lv_stripes) *
-		    (lv->lv_allocated_le / lv->lv_stripes);
+		stripe_index = (rsector_org % stripe_length) /
+			lv->lv_stripesize;
+		index = rsector_org / stripe_length +
+			(stripe_index % lv->lv_stripes) *
+			(lv->lv_allocated_le / lv->lv_stripes);
 		pe_start = lv->lv_current_pe[index].pe;
-		rsector_tmp = lv->lv_current_pe[index].pe +
-		    (rsector_tmp % stripe_length) -
-		    (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
-		    stripe_index / lv->lv_stripes *
-		    (lv->lv_stripes - 1) * lv->lv_stripesize;
-		rdev_tmp = lv->lv_current_pe[index].dev;
-	}
-
-	P_MAP("lv_current_pe[%ld].pe: %ld  rdev: %02d:%02d  rsector:%ld\n"
-	       "stripe_length: %ld  stripe_index: %ld\n",
-	       index,
-	       lv->lv_current_pe[index].pe,
-	       MAJOR(rdev_tmp),
-	       MINOR(rdev_tmp),
-	       rsector_tmp,
-	       stripe_length,
-	       stripe_index);
+		rsector_map = lv->lv_current_pe[index].pe +
+			(rsector_org % stripe_length) -
+			(stripe_index % lv->lv_stripes) * lv->lv_stripesize -
+			stripe_index / lv->lv_stripes *
+			(lv->lv_stripes - 1) * lv->lv_stripesize;
+		rdev_map = lv->lv_current_pe[index].dev;
+
+		P_MAP("lv_current_pe[%ld].pe: %d  rdev: %s  rsector:%ld\n"
+		      "stripe_length: %ld  stripe_index: %ld\n",
+		      index, lv->lv_current_pe[index].pe, kdevname(rdev_map),
+		      rsector_map, stripe_length, stripe_index);
+	}
 
 	/* handle physical extents on the move */
-	if (pe_lock_req.lock == LOCK_PE) {
-		if (rdev_tmp == pe_lock_req.data.pv_dev &&
-		    rsector_tmp >= pe_lock_req.data.pv_offset &&
-		    rsector_tmp < (pe_lock_req.data.pv_offset +
-				   vg_this->pe_size)) {
-			sleep_on(&lvm_map_wait);
-			rsector_tmp = rsector_sav;
-			rdev_tmp = rdev_sav;
-			goto lvm_second_remap;
-		}
+	down(&_pe_lock);
+	if((pe_lock_req.lock == LOCK_PE) &&
+	   (rdev_map == pe_lock_req.data.pv_dev) &&
+	   (rsector_map >= pe_lock_req.data.pv_offset) &&
+	   (rsector_map < (pe_lock_req.data.pv_offset + vg_this->pe_size)) &&
+	   ((rw == WRITE) || (rw == WRITEA))) {
+		/* defer this bh until the PE has moved */
+		if(((int) bh) & 0x3) {
+			printk(KERN_ERR 
+			       "%s -- bh uses low 2 bits of pointer\n",
+			       lvm_name);
+			up(&_pe_lock);
+			goto bad;
+		}
+
+		bh->b_reqnext = _pe_requests;
+		_pe_requests = (struct buffer_head *) ((int) bh | rw);
+		up(&_pe_lock);
+		up(&lv->lv_snapshot_sem);
+		return 0;
 	}
+	up(&_pe_lock);
+
 	/* statistic */
 	if (rw == WRITE || rw == WRITEA)
 		lv->lv_current_pe[index].writes++;
 	else
 		lv->lv_current_pe[index].reads++;
 
-	/* snapshot volume exception handling on physical device address base */
-	if (lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)) {
-		/* original logical volume */
-		if (lv->lv_access & LV_SNAPSHOT_ORG) {
-			/* Serializes the access to the lv_snapshot_next list */
-			down(&lv->lv_snapshot_sem);
-			if (rw == WRITE || rw == WRITEA)
-			{
-				lv_t *lv_ptr;
-
-				/* start with first snapshot and loop thrugh all of them */
-				for (lv_ptr = lv->lv_snapshot_next;
-				     lv_ptr != NULL;
-				     lv_ptr = lv_ptr->lv_snapshot_next) {
-					/* Check for inactive snapshot */
-					if (!(lv_ptr->lv_status & LV_ACTIVE)) continue;
-					/* Serializes the COW with the accesses to the snapshot device */
-					down(&lv_ptr->lv_snapshot_sem);
-					/* do we still have exception storage for this snapshot free? */
-					if (lv_ptr->lv_block_exception != NULL) {
-						rdev_sav = rdev_tmp;
-						rsector_sav = rsector_tmp;
-						if (!lvm_snapshot_remap_block(&rdev_tmp,
-									      &rsector_tmp,
-									      pe_start,
-									      lv_ptr)) {
-							/* create a new mapping */
-							if (!(ret = lvm_snapshot_COW(rdev_tmp,
-									       	     rsector_tmp,
-									             pe_start,
-									             rsector_sav,
-									             lv_ptr)))
-								ret = lvm_write_COW_table_block(vg_this,
-												lv_ptr);
-						}
-						rdev_tmp = rdev_sav;
-						rsector_tmp = rsector_sav;
-					}
-					up(&lv_ptr->lv_snapshot_sem);
-				}
-			}
-			up(&lv->lv_snapshot_sem);
-		} else {
-			/* remap snapshot logical volume */
-			down(&lv->lv_snapshot_sem);
-			if (lv->lv_block_exception != NULL)
-				lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv);
-			up(&lv->lv_snapshot_sem);
+	/* snapshot volume exception handling on physical device
+           address base */
+	if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)))
+		goto out;
+
+	if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */
+		if (lv->lv_block_exception)
+			lvm_snapshot_remap_block(&rdev_map, &rsector_map,
+						 pe_start, lv);
+		else
+			goto bad;
+
+	} else if(rw == WRITE || rw == WRITEA) { /* snapshot origin */
+		lv_t *snap;
+
+		/* start with first snapshot and loop through all of
+		   them */
+		for (snap = lv->lv_snapshot_next; snap;
+		     snap = snap->lv_snapshot_next) {
+			/* Check for inactive snapshot */
+			if (!(snap->lv_status & LV_ACTIVE))
+				continue;
+
+			/* Serializes the COW with the accesses to the
+			   snapshot device */
+			down(&snap->lv_snapshot_sem);
+			__remap_snapshot(rdev_map, rsector_map,
+					 pe_start, snap, vg_this);
+			up(&snap->lv_snapshot_sem);
 		}
 	}
-	bh->b_rdev = rdev_tmp;
-	bh->b_rsector = rsector_tmp;
 
-	return ret;
+ out:
+	bh->b_rdev = rdev_map;
+	bh->b_rsector = rsector_map;
+	up(&lv->lv_snapshot_sem);
+	return 1;
+
+ bad:
+	buffer_IO_error(bh);
+	up(&lv->lv_snapshot_sem);
+	return -1;
 } /* lvm_map() */
 
 
@@ -1667,18 +1291,15 @@
 #endif
 
 
+
+
 /*
  * make request function
  */
 static int lvm_make_request_fn(request_queue_t *q,
 			       int rw,
-			       struct buffer_head *bh)
-{
-	if (lvm_map(bh, rw) >= 0)
-		return 1;
-
-	buffer_IO_error(bh);
-	return 0;
+			       struct buffer_head *bh) {
+	return (lvm_map(bh, rw) <= 0) ? 0 : 1;
 }
 
 
@@ -1718,33 +1339,60 @@
  */
 static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
 {
+	pe_lock_req_t new_lock;
+	uint q;
 	uint p;
 
 	if (vg_ptr == NULL) return -ENXIO;
-	if (copy_from_user(&pe_lock_req, arg,
-			   sizeof(pe_lock_req_t)) != 0) return -EFAULT;
+	if (copy_from_user(&new_lock, arg, sizeof(new_lock)) != 0) 
+		return -EFAULT;
 
-	switch (pe_lock_req.lock) {
+	switch (new_lock.lock) {
 	case LOCK_PE:
+		if(pe_lock_req.lock == LOCK_PE)
+			return -EBUSY;
+
 		for (p = 0; p < vg_ptr->pv_max; p++) {
 			if (vg_ptr->pv[p] != NULL &&
-			    pe_lock_req.data.pv_dev ==
-			    vg_ptr->pv[p]->pv_dev)
+			    new_lock.data.pv_dev == vg_ptr->pv[p]->pv_dev)
 				break;
 		}
 		if (p == vg_ptr->pv_max) return -ENXIO;
 
+		pe_lock_req = new_lock;
+
+		down(&_pe_lock);
 		pe_lock_req.lock = UNLOCK_PE;
+		up(&_pe_lock);
+
 		fsync_dev(pe_lock_req.data.lv_dev);
+
+		down(&_pe_lock);
 		pe_lock_req.lock = LOCK_PE;
+		up(&_pe_lock);
 		break;
 
 	case UNLOCK_PE:
+		down(&_pe_lock);
 		pe_lock_req.lock = UNLOCK_PE;
 		pe_lock_req.data.lv_dev = \
 		pe_lock_req.data.pv_dev = \
 		pe_lock_req.data.pv_offset = 0;
-		wake_up(&lvm_map_wait);
+		q = (uint) _pe_requests;
+		_pe_requests = 0;
+		up(&_pe_lock);
+
+		/* handle all deferred io for this PE */
+		while(q) {
+			struct buffer_head *d_bh = 
+				(struct buffer_head *) (q & ~0x3);
+			int rw = q & 0x3;
+			q = (uint) d_bh->b_reqnext;
+
+			/* resubmit this buffer head */
+			d_bh->b_reqnext = 0;
+			generic_make_request(rw, d_bh);
+		}
 		break;
 
 	default:
@@ -1781,6 +1429,8 @@
 					    le_remap_req.new_dev;
 					lv_ptr->lv_current_pe[le].pe =
 					    le_remap_req.new_pe;
+
+					__update_hardblocksize(lv_ptr);
 					return 0;
 				}
 			}
@@ -1794,7 +1444,7 @@
 /*
  * character device support function VGDA create
  */
-int lvm_do_vg_create(int minor, void *arg)
+static int lvm_do_vg_create(void *arg, int minor)
 {
 	int ret = 0;
 	ulong l, ls = 0, p, size;
@@ -1802,8 +1452,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",
@@ -1816,28 +1464,40 @@
 		return -EFAULT;
 	}
 
+	/* 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) {
+	    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;
 	}
 
+	/* create devfs and procfs entries */
+	lvm_fs_create_vg(vg_ptr);
+
+	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++) {
@@ -1885,8 +1545,6 @@
 		}
 	}
 
-	lvm_do_create_devfs_entry_of_vg ( vg_ptr);
-
 	/* Second path to correct snapshot logical volumes which are not
 	   in place during first path above */
 	for (l = 0; l < ls; l++) {
@@ -1901,8 +1559,6 @@
 		}
 	}
 
-	lvm_do_create_proc_entry_of_vg ( vg_ptr);
-
 	vfree(snap_lv_ptr);
 
 	vg_count++;
@@ -1934,7 +1590,6 @@
 				if ( ret != 0) return ret;
 				pv_ptr = vg_ptr->pv[p];
 				vg_ptr->pe_total += pv_ptr->pe_total;
-				lvm_do_create_proc_entry_of_pv(vg_ptr, pv_ptr);
 				return 0;
 			}
 		}
@@ -1984,10 +1639,13 @@
 	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;
 
-	lvm_do_remove_proc_entry_of_vg ( vg_ptr);
+	lvm_fs_remove_vg(vg_ptr);
 
 	strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1);
 	for ( l = 0; l < vg_ptr->lv_max; l++)
@@ -2009,7 +1667,7 @@
 		strncpy(pv_ptr->vg_name, vg_name, NAME_LEN);
 	}
 
-	lvm_do_create_proc_entry_of_vg ( vg_ptr);
+	lvm_fs_create_vg(vg_ptr);
 
 	return 0;
 } /* lvm_do_vg_rename */
@@ -2036,6 +1694,9 @@
 	/* let's go inactive */
 	vg_ptr->vg_status &= ~VG_ACTIVE;
 
+	/* remove from procfs and devfs */
+	lvm_fs_remove_vg(vg_ptr);
+
 	/* free LVs */
 	/* first free snapshot logical volumes */
 	for (i = 0; i < vg_ptr->lv_max; i++) {
@@ -2063,11 +1724,6 @@
 		}
 	}
 
-	devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]);
-	devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]);
-
-	lvm_do_remove_proc_entry_of_vg ( vg_ptr);
-
 	P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
 	kfree(vg_ptr);
 	vg[VG_CHR(minor)] = NULL;
@@ -2089,7 +1745,7 @@
 	pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL);
 	if (pv_ptr == 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;
 	}
@@ -2103,18 +1759,20 @@
 	pv_ptr->pv_status = PV_ACTIVE;
 	vg_ptr->pv_act++;
 	vg_ptr->pv_cur++;
+	lvm_fs_create_pv(vg_ptr, pv_ptr);
 
 	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];
 
-	lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv_ptr);
+	lvm_fs_remove_pv(vg_ptr, pv_ptr);
+
 	vg_ptr->pe_total -= pv_ptr->pe_total;
 	vg_ptr->pv_cur--;
 	vg_ptr->pv_act--;
@@ -2128,12 +1786,39 @@
 }
 
 
+static void __update_hardblocksize(lv_t *lv) {
+	int le, e;
+	int max_hardblocksize = 0, hardblocksize;
+
+	for (le = 0; le < lv->lv_allocated_le; le++) {
+		hardblocksize = get_hardblocksize(lv->lv_current_pe[le].dev);
+		if (hardblocksize == 0)
+			hardblocksize = 512;
+		if (hardblocksize > max_hardblocksize)
+			max_hardblocksize = hardblocksize;
+	}
+
+	if (lv->lv_access & LV_SNAPSHOT) {
+		for (e = 0; e < lv->lv_remap_end; e++) {
+			hardblocksize =
+				get_hardblocksize(
+					lv->lv_block_exception[e].rdev_new);
+			if (hardblocksize == 0)
+				hardblocksize = 512;
+			if (hardblocksize > max_hardblocksize)
+				max_hardblocksize = hardblocksize;
+		}
+	}
+
+	lvm_hardsectsizes[MINOR(lv->lv_dev)] = max_hardblocksize;
+}
+
 /*
  * character device support function logical volume create
  */
 static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
 {
-	int e, ret, l, le, l_new, p, size;
+	int e, ret, l, le, l_new, p, size, activate = 1;
 	ulong lv_status_save;
 	lv_block_exception_t *lvbe = lv->lv_block_exception;
 	vg_t *vg_ptr = vg[VG_CHR(minor)];
@@ -2143,7 +1828,7 @@
 	if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK)
 		return -EINVAL;
 
-	for (l = 0; l < vg_ptr->lv_max; l++) {
+	for (l = 0; l < vg_ptr->lv_cur; l++) {
 		if (vg_ptr->lv[l] != NULL &&
 		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
 			return -EEXIST;
@@ -2177,16 +1862,17 @@
 	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_snapshot_hash_table = NULL;
 	lv_ptr->lv_snapshot_hash_table_size = 0;
 	lv_ptr->lv_snapshot_hash_mask = 0;
-	lv_ptr->lv_COW_table_page = NULL;
 	init_MUTEX(&lv_ptr->lv_snapshot_sem);
 	lv_ptr->lv_snapshot_use_rate = 0;
+
 	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) {
@@ -2238,6 +1924,16 @@
 					vg_ptr->lv[l] = NULL;
 					return -EFAULT;
 				}
+
+				if(lv_ptr->lv_block_exception[0].rsector_org ==
+				   LVM_SNAPSHOT_DROPPED_SECTOR)
+				{
+					printk(KERN_WARNING
+   "%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;
 
@@ -2271,10 +1967,13 @@
 						       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 */
-				lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr);
+				if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) {
+					kfree(lv_ptr);
+					vg_ptr->lv[l] = NULL;
+					return -EINVAL;
+				}
 				init_waitqueue_head(&lv_ptr->lv_snapshot_wait);
 			} else {
-				vfree(lv_ptr->lv_block_exception);
 				kfree(lv_ptr);
 				vg_ptr->lv[l] = NULL;
 				return -EFAULT;
@@ -2296,21 +1995,7 @@
 	vg_ptr->lv_cur++;
 	lv_ptr->lv_status = lv_status_save;
 
-	{
-	char *lv_tmp, *lv_buf = lv->lv_name;
-
-	strtok(lv->lv_name, "/");       /* /dev */
-	while((lv_tmp = strtok(NULL, "/")) != NULL)
-		lv_buf = lv_tmp;
-
-	lv_devfs_handle[lv->lv_number] = devfs_register(
-		vg_devfs_handle[vg_ptr->vg_number], lv_buf,
-		DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number,
-		S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-		&lvm_blk_dops, NULL);
-	}
-
-	lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
+	__update_hardblocksize(lv_ptr);
 
 	/* optionally add our new snapshot LV */
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
@@ -2327,6 +2012,7 @@
 		org->lv_access |= LV_SNAPSHOT_ORG;
 		lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */
 
+
 		/* 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;
@@ -2335,7 +2021,11 @@
 	}
 
 	/* activate the logical volume */
-	lv_ptr->lv_status |= LV_ACTIVE;
+	if(activate)
+		lv_ptr->lv_status |= LV_ACTIVE;
+	else
+		lv_ptr->lv_status &= ~LV_ACTIVE;
+
 	if ( lv_ptr->lv_access & LV_WRITE)
 		set_device_ro(lv_ptr->lv_dev, 0);
 	else
@@ -2350,6 +2040,7 @@
 
 	lv_ptr->vg = vg_ptr;
 
+	lvm_fs_create_lv(vg_ptr, lv_ptr);
 	return 0;
 } /* lvm_do_lv_create() */
 
@@ -2387,6 +2078,8 @@
 	    lv_ptr->lv_snapshot_next != NULL)
 		return -EPERM;
 
+	lvm_fs_remove_lv(vg_ptr, lv_ptr);
+
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		/*
 		 * Atomically make the the snapshot invisible
@@ -2401,11 +2094,13 @@
 			lv_ptr->lv_snapshot_next->lv_snapshot_prev =
 			    lv_ptr->lv_snapshot_prev;
 		}
-		up(&org->lv_snapshot_sem);
 
 		/* no more snapshots? */
-		if (!org->lv_snapshot_next)
+		if (!org->lv_snapshot_next) {
 			org->lv_access &= ~LV_SNAPSHOT_ORG;
+		}
+		up(&org->lv_snapshot_sem);
+
 		lvm_snapshot_release(lv_ptr);
 
 		/* Update the VG PE(s) used by snapshot reserve space. */
@@ -2448,10 +2143,6 @@
 		vfree(lv_ptr->lv_current_pe);
 	}
 
-	devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]);
-
-	lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr);
-
 	P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
 	kfree(lv_ptr);
 	vg_ptr->lv[l] = NULL;
@@ -2461,204 +2152,212 @@
 
 
 /*
- * character device support function logical volume extend / reduce
+ * logical volume extend / reduce
  */
-static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv)
-{
-	ulong end, l, le, p, size, old_allocated_le;
-	vg_t *vg_ptr = vg[VG_CHR(minor)];
-	lv_t *lv_ptr;
-	pe_t *pe;
+static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) {
+	ulong size;
+	lv_block_exception_t *lvbe;
 
-	if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
+	if (!new_lv->lv_block_exception)
+		return -ENXIO;
 
-	for (l = 0; l < vg_ptr->lv_max; l++) {
-		if (vg_ptr->lv[l] != NULL &&
-		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
-			break;
+	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 (l == vg_ptr->lv_max) return -ENXIO;
-	lv_ptr = vg_ptr->lv[l];
 
-	/* check for active snapshot */
-	if (lv->lv_access & LV_SNAPSHOT)
-	{
-		ulong e;
-		lv_block_exception_t *lvbe, *lvbe_old;
-		struct list_head * lvs_hash_table_old;
-
-		if (lv->lv_block_exception == NULL) return -ENXIO;
-		size = 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 (lv->lv_remap_end > lv_ptr->lv_remap_end)
-		{
-			if (copy_from_user(lvbe, lv->lv_block_exception, size))
-			{
-				vfree(lvbe);
-				return -EFAULT;
-			}
-		}
-
-		lvbe_old = lv_ptr->lv_block_exception;
-		lvs_hash_table_old = lv_ptr->lv_snapshot_hash_table;
-
-		/* we need to play on the safe side here... */
-		down(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
-		if (lv_ptr->lv_block_exception == NULL ||
-		    lv_ptr->lv_remap_ptr > lv_ptr->lv_remap_end)
-		{
-			up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
-			vfree(lvbe);
-			return -EPERM;
-		}
-		memcpy(lvbe,
-		       lv_ptr->lv_block_exception,
-		       (lv->lv_remap_end > lv_ptr->lv_remap_end ?
-			lv_ptr->lv_remap_ptr : lv->lv_remap_end) * sizeof(lv_block_exception_t));
-
-		lv_ptr->lv_block_exception = lvbe;
-		lv_ptr->lv_remap_end = lv->lv_remap_end;
-		if (lvm_snapshot_alloc_hash_table(lv_ptr) != 0)
-		{
-			lvm_drop_snapshot(lv_ptr, "no memory for hash table");
-			up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
-			vfree(lvbe_old);
-			vfree(lvs_hash_table_old);
-			return -ENOMEM;
-		}
-
-		for (e = 0; e < lv_ptr->lv_remap_ptr; e++)
-			lvm_hash_link (lv_ptr->lv_block_exception + e,
-				       lv_ptr->lv_block_exception[e].rdev_org,
-				       lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
-
-		up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
-
-		vfree(lvbe_old);
-		vfree(lvs_hash_table_old);
+	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;
 
-		return 0;
+	if (lvm_snapshot_alloc_hash_table(new_lv)) {
+		vfree(new_lv->lv_block_exception);
+		return -ENOMEM;
 	}
 
+	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;
 
-	/* we drop in here in case it is an original logical volume */
-	if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) {
+	/* 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",
+		       "%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, pep, size)) {
+	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 (le = 0; le < lv_ptr->lv_allocated_le; le++) {
+	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 ==
-			lv_ptr->lv_current_pe[le].dev) {
+			    old_lv->lv_current_pe[l].dev) {
 				vg_ptr->pv[p]->pe_allocated--;
 				break;
 			}
 		}
 	}
 
-
-	/* save pointer to "old" lv/pe pointer array */
-	pep1 = lv_ptr->lv_current_pe;
-	end = lv_ptr->lv_current_le;
-
-	/* save open counter... */
-	lv->lv_open = lv_ptr->lv_open;
-	lv->lv_snapshot_prev = lv_ptr->lv_snapshot_prev;
-	lv->lv_snapshot_next = lv_ptr->lv_snapshot_next;
-	lv->lv_snapshot_org  = lv_ptr->lv_snapshot_org;
-
-	lv->lv_current_pe = pe;
-
-	/* save # of old allocated logical extents */
-	old_allocated_le = lv_ptr->lv_allocated_le;
-
-	/* copy preloaded LV */
-	memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
-
-	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
-	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
-	lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
-	/* vg_lv_map array doesn't have to be changed here */
-
-	LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
+	/* 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 */
-	/* linear logical volume */
-	if (lv_ptr->lv_stripes < 2) {
-		/* Check what last LE shall be used */
-		if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le;
-		for (le = 0; le < end; le++) {
-			lv_ptr->lv_current_pe[le].reads  += pep1[le].reads;
-			lv_ptr->lv_current_pe[le].writes += pep1[le].writes;
+	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;
 		}
-		/* striped logical volume */
-	} else {
+
+	} else {		/* striped logical volume */
 		uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
 
-		old_stripe_size = old_allocated_le / lv_ptr->lv_stripes;
-		new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes;
-		end = old_stripe_size;
-		if (end > new_stripe_size) end = 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 < lv_ptr->lv_stripes; i++) {
+		     i < new_lv->lv_stripes; i++) {
 			for (j = 0; j < end; j++) {
-				lv_ptr->lv_current_pe[dest + j].reads +=
-				    pep1[source + j].reads;
-				lv_ptr->lv_current_pe[dest + j].writes +=
-				    pep1[source + j].writes;
+				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;
 		}
 	}
 
-	/* extend the PE count in PVs */
-	for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
-		vg_ptr->pe_allocated++;
-		for (p = 0; p < vg_ptr->pv_cur; p++) {
-			if (vg_ptr->pv[p]->pv_dev ==
-                            lv_ptr->lv_current_pe[le].dev) {
-				vg_ptr->pv[p]->pe_allocated++;
-				break;
-			}
-		}
-	}
+	return 0;
+}
 
-	vfree ( pep1);
-	pep1 = NULL;
+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 (lv->lv_access & LV_SNAPSHOT_ORG)
-	{
-		/* Correct the snapshot size information */
-		while ((lv_ptr = lv_ptr->lv_snapshot_next) != NULL)
-		{
-			lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
-			lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
-			lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
-			lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
-			lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
-			lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
+	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];
+
+	if (old_lv->lv_access & LV_SNAPSHOT)
+		r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv);
+	else
+		r = __extend_reduce(vg_ptr, old_lv, new_lv);
+
+	if(r)
+		return r;
+
+	/* copy relevent fields */
+	down(&old_lv->lv_snapshot_sem);
+
+	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(&snap->lv_snapshot_sem);
+				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_hardblocksize(snap);
+				up(&snap->lv_snapshot_sem);
+			}
 		}
 	}
 
+	__update_hardblocksize(old_lv);
+	up(&old_lv->lv_snapshot_sem);
+
 	return 0;
 } /* lvm_do_lv_extend_reduce() */
 
@@ -2669,10 +2368,10 @@
 static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
 {
 	uint l;
-	ulong size;
-	lv_t lv;
-	lv_t *lv_ptr;
 	lv_status_byname_req_t lv_status_byname_req;
+	void *saved_ptr1;
+	void *saved_ptr2;
+	lv_t *lv_ptr;
 
 	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&lv_status_byname_req, arg,
@@ -2680,28 +2379,27 @@
 		return -EFAULT;
 
 	if (lv_status_byname_req.lv == NULL) return -EINVAL;
-	if (copy_from_user(&lv, lv_status_byname_req.lv,
-			   sizeof(lv_t)) != 0)
-		return -EFAULT;
 
 	for (l = 0; l < vg_ptr->lv_max; l++) {
-		lv_ptr = vg_ptr->lv[l];
-		if (lv_ptr != NULL &&
+		if ((lv_ptr = vg_ptr->lv[l]) != NULL &&
 		    strcmp(lv_ptr->lv_name,
-			    lv_status_byname_req.lv_name) == 0) {
-			if (copy_to_user(lv_status_byname_req.lv,
+			   lv_status_byname_req.lv_name) == 0) {
+		        /* Save usermode pointers */
+		        saved_ptr1 = lv_status_byname_req.lv->lv_current_pe;
+			saved_ptr2 = lv_status_byname_req.lv->lv_block_exception;
+		        if (copy_to_user(lv_status_byname_req.lv,
 					 lv_ptr,
 					 sizeof(lv_t)) != 0)
 				return -EFAULT;
-
-			if (lv.lv_current_pe != NULL) {
-				size = lv_ptr->lv_allocated_le *
-				       sizeof(pe_t);
-				if (copy_to_user(lv.lv_current_pe,
+			if (saved_ptr1 != NULL) {
+				if (copy_to_user(saved_ptr1,
 						 lv_ptr->lv_current_pe,
-						 size) != 0)
+						 lv_ptr->lv_allocated_le *
+				       		 sizeof(pe_t)) != 0)
 					return -EFAULT;
 			}
+			/* Restore usermode pointers */
+			lv_status_byname_req.lv->lv_current_pe = saved_ptr1;
 			return 0;
 		}
 	}
@@ -2714,34 +2412,37 @@
  */
 static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
 {
-	ulong size;
-	lv_t lv;
-	lv_t *lv_ptr;
 	lv_status_byindex_req_t lv_status_byindex_req;
+	void *saved_ptr1;
+	void *saved_ptr2;
+	lv_t *lv_ptr;
 
 	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&lv_status_byindex_req, arg,
 			   sizeof(lv_status_byindex_req)) != 0)
 		return -EFAULT;
 
-	if ((lvp = lv_status_byindex_req.lv) == NULL)
+	if (lv_status_byindex_req.lv == NULL)
 		return -EINVAL;
 	if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
 		return -ENXIO;
 
-	if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0)
+	/* Save usermode pointers */
+	saved_ptr1 = lv_status_byindex_req.lv->lv_current_pe;
+	saved_ptr2 = lv_status_byindex_req.lv->lv_block_exception;
+	if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != 0)
 		return -EFAULT;
-
-	if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0)
-		return -EFAULT;
-
-	if (lv.lv_current_pe != NULL) {
-		size = lv_ptr->lv_allocated_le * sizeof(pe_t);
-		if (copy_to_user(lv.lv_current_pe,
-			 	 lv_ptr->lv_current_pe,
-				 size) != 0)
+	if (saved_ptr1 != NULL) {
+		if (copy_to_user(saved_ptr1,
+				 lv_ptr->lv_current_pe,
+				 lv_ptr->lv_allocated_le *
+		       		 sizeof(pe_t)) != 0)
 			return -EFAULT;
 	}
+
+	/* Restore usermode pointers */
+	lv_status_byindex_req.lv->lv_current_pe = saved_ptr1;
+
 	return 0;
 } /* lvm_do_lv_status_byindex() */
 
@@ -2752,6 +2453,9 @@
 static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) {
 	int l;
 	lv_status_bydev_req_t lv_status_bydev_req;
+	void *saved_ptr1;
+	void *saved_ptr2;
+	lv_t *lv_ptr;
 
 	if (vg_ptr == NULL) return -ENXIO;
 	if (copy_from_user(&lv_status_bydev_req, arg,
@@ -2764,10 +2468,23 @@
 	}
 
 	if ( l == vg_ptr->lv_max) return -ENXIO;
+	lv_ptr = vg_ptr->lv[l];
+
+	/* Save usermode pointers */
+	saved_ptr1 = lv_status_bydev_req.lv->lv_current_pe;
+	saved_ptr2 = lv_status_bydev_req.lv->lv_block_exception;
 
-	if (copy_to_user(lv_status_bydev_req.lv,
-			 vg_ptr->lv[l], sizeof(lv_t)) != 0)
+	if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0)
 		return -EFAULT;
+	if (saved_ptr1 != NULL) {
+		if (copy_to_user(saved_ptr1,
+				 lv_ptr->lv_current_pe,
+				 lv_ptr->lv_allocated_le *
+		       		 sizeof(pe_t)) != 0)
+			return -EFAULT;
+	}
+	/* Restore usermode pointers */
+	lv_status_bydev_req.lv->lv_current_pe = saved_ptr1;
 
 	return 0;
 } /* lvm_do_lv_status_bydev() */
@@ -2787,11 +2504,11 @@
 		if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue;
 		if (lv_ptr->lv_dev == lv->lv_dev)
 		{
-			lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr);
+			lvm_fs_remove_lv(vg_ptr, lv_ptr);
 			strncpy(lv_ptr->lv_name,
 				lv_req->lv_name,
 				NAME_LEN);
-			lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
+			lvm_fs_create_lv(vg_ptr, lv_ptr);
 			break;
 		}
 	}
@@ -2871,160 +2588,28 @@
 } /* lvm_do_pv_status() */
 
 
-
-/*
- * create a devfs entry for a volume group
- */
-void lvm_do_create_devfs_entry_of_vg ( vg_t *vg_ptr) {
-	vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL);
-	ch_devfs_handle[vg_ptr->vg_number] = devfs_register(
-		vg_devfs_handle[vg_ptr->vg_number] , "group",
-		DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number,
-		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-		&lvm_chr_fops, NULL);
-}
-
-
-/*
- * create a /proc entry for a logical volume
- */
-void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) {
-	char *basename;
-
-	if ( vg_ptr->lv_subdir_pde != NULL) {
-		basename = strrchr(lv_ptr->lv_name, '/');
-		if (basename == NULL) basename = lv_ptr->lv_name;
-		else		      basename++;
-		pde = create_proc_entry(basename, S_IFREG,
-					vg_ptr->lv_subdir_pde);
-		if ( pde != NULL) {
-			pde->read_proc = lvm_proc_read_lv_info;
-			pde->data = lv_ptr;
-		}
-	}
-}
-
-
-/*
- * remove a /proc entry for a logical volume
- */
-void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) {
-	char *basename;
-
-	if ( vg_ptr->lv_subdir_pde != NULL) {
-		basename = strrchr(lv_ptr->lv_name, '/');
-		if (basename == NULL) basename = lv_ptr->lv_name;
-		else		      basename++;
-		remove_proc_entry(basename, vg_ptr->lv_subdir_pde);
-	}
-}
-
-
-/*
- * create a /proc entry for a physical volume
- */
-void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) {
-	int offset = 0;
-	char *basename;
-	char buffer[NAME_LEN];
-
-	basename = pv_ptr->pv_name;
-	if (strncmp(basename, "/dev/", 5) == 0) offset = 5;
-	strncpy(buffer, basename + offset, sizeof(buffer));
-	basename = buffer;
-	while ( ( basename = strchr ( basename, '/')) != NULL) *basename = '_';
-	pde = create_proc_entry(buffer, S_IFREG, vg_ptr->pv_subdir_pde);
-	if ( pde != NULL) {
-		pde->read_proc = lvm_proc_read_pv_info;
-		pde->data = pv_ptr;
-	}
-}
-
-
 /*
- * remove a /proc entry for a physical volume
+ * character device support function flush and invalidate all buffers of a PV
  */
-void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) {
-	char *basename;
-
-	basename = strrchr(pv_ptr->pv_name, '/');
-	if ( vg_ptr->pv_subdir_pde != NULL) {
-		basename = strrchr(pv_ptr->pv_name, '/');
-		if (basename == NULL) basename = pv_ptr->pv_name;
-		else		      basename++;
-		remove_proc_entry(basename, vg_ptr->pv_subdir_pde);
-	}
-}
-
-
-/*
- * create a /proc entry for a volume group
- */
-void lvm_do_create_proc_entry_of_vg ( vg_t *vg_ptr) {
-	int l, p;
-	pv_t *pv_ptr;
-	lv_t *lv_ptr;
+static int lvm_do_pv_flush(void *arg)
+{
+	pv_flush_req_t pv_flush_req;
 
-	pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
-				lvm_proc_vg_subdir);
-	if ( pde != NULL) {
-		vg_ptr->vg_dir_pde = pde;
-		pde = create_proc_entry("group", S_IFREG,
-					vg_ptr->vg_dir_pde);
-		if ( pde != NULL) {
-			pde->read_proc = lvm_proc_read_vg_info;
-			pde->data = vg_ptr;
-		}
-                pde = create_proc_entry(LVM_LV_SUBDIR, S_IFDIR,
-                                        vg_ptr->vg_dir_pde);
-                if ( pde != NULL) {
-                        vg_ptr->lv_subdir_pde = pde;
-                        for ( l = 0; l < vg_ptr->lv_max; l++) {
-				if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue;
-				lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
-                        }
-                }
-                pde = create_proc_entry(LVM_PV_SUBDIR, S_IFDIR,
-                                        vg_ptr->vg_dir_pde);
-                if ( pde != NULL) {
-                        vg_ptr->pv_subdir_pde = pde;
-			for ( p = 0; p < vg_ptr->pv_max; p++) {
-				if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue;
-				lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr);
-                        }
-                }
-        }
-}
+	if (copy_from_user(&pv_flush_req, arg,
+			   sizeof(pv_flush_req)) != 0)
+		return -EFAULT;
 
-/*
- * remove a /proc entry for a volume group
- */
-void lvm_do_remove_proc_entry_of_vg ( vg_t *vg_ptr) {
-	int l, p;
-	lv_t *lv_ptr;
-	pv_t *pv_ptr;
+	fsync_dev(pv_flush_req.pv_dev);
+	invalidate_buffers(pv_flush_req.pv_dev);
 
-	for ( l = 0; l < vg_ptr->lv_max; l++) {
-		if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue;
-		lvm_do_remove_proc_entry_of_lv ( vg_ptr, vg_ptr->lv[l]);
-	}
-	for ( p = 0; p < vg_ptr->pv_max; p++) {
-		if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue;
-		lvm_do_remove_proc_entry_of_pv ( vg_ptr, vg_ptr->pv[p]);
-	}
-	if ( vg_ptr->vg_dir_pde != NULL) {
-		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
-		remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde);
-		remove_proc_entry("group", vg_ptr->vg_dir_pde);
-		remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir);
-	}
+	return 0;
 }
 
 
 /*
  * support function initialize gendisk variables
  */
-void __init lvm_geninit(struct gendisk *lvm_gdisk)
+static void __init lvm_geninit(struct gendisk *lvm_gdisk)
 {
 	int i = 0;
 
@@ -3040,36 +2625,11 @@
 
 	blk_size[MAJOR_NR] = lvm_size;
 	blksize_size[MAJOR_NR] = lvm_blocksizes;
-	hardsect_size[MAJOR_NR] = lvm_blocksizes;
+	hardsect_size[MAJOR_NR] = lvm_hardsectsizes;
 
 	return;
 } /* lvm_gen_init() */
 
-
-/*
- * return a pointer to a '-' padded uuid
- */
-static char *lvm_show_uuid ( char *uuidstr) {
-	int i, j;
-	static char uuid[NAME_LEN] = { 0, };
-
-	memset ( uuid, 0, NAME_LEN);
-
-	i = 6;
-	memcpy ( uuid, uuidstr, i);
-	uuidstr += i;
-
-	for ( j = 0; j < 6; j++) {
-		uuid[i++] = '-';
-		memcpy ( &uuid[i], uuidstr, 4);
-		uuidstr += 4;
-		i += 4;
-	}
-
-	memcpy ( &uuid[i], uuidstr, 2 );
-
-	return uuid;
-}
 
 module_init(lvm_init);
 module_exit(lvm_cleanup);
--- linux/drivers/md/lvm-internal.h.orig Mon May  7 01:04:40 2001
+++ linux/drivers/md/lvm-internal.h Mon May  7 01:04:40 2001
@@ -0,0 +1,104 @@
+/*
+ * kernel/lvm_internal.h
+ *
+ * Copyright (C) 2001 Sistina Software
+ *
+ *
+ * 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * LVM 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.
+ *
+ */
+
+/*
+ * Changelog
+ *
+ *    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
+ *
+ */
+
+#ifndef LVM_INTERNAL_H
+#define LVM_INTERNAL_H
+
+#include <linux/lvm.h>
+
+#define	_LVM_INTERNAL_H_VERSION	"LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")"
+
+/* global variables, defined in lvm.c */
+extern char *lvm_version;
+extern char *lvm_short_version;
+extern ushort lvm_iop_version;
+extern int loadtime;
+extern const char *const lvm_name;
+
+
+extern vg_t *vg[];
+extern struct file_operations lvm_chr_fops;
+
+extern struct block_device_operations lvm_blk_dops;
+
+
+/* debug macros */
+#ifdef DEBUG_IOCTL
+#define P_IOCTL(fmt, args...) printk(KERN_DEBUG "lvm ioctl: " fmt, ## args)
+#else
+#define P_IOCTL(fmt, args...)
+#endif
+
+#ifdef DEBUG_MAP
+#define P_MAP(fmt, args...) printk(KERN_DEBUG "lvm map: " fmt, ## args)
+#else
+#define P_MAP(fmt, args...)
+#endif
+
+#ifdef DEBUG_KFREE
+#define P_KFREE(fmt, args...) printk(KERN_DEBUG "lvm kfree: " fmt, ## args)
+#else
+#define P_KFREE(fmt, args...)
+#endif
+
+#ifdef DEBUG_DEVICE
+#define P_DEV(fmt, args...) printk(KERN_DEBUG "lvm device: " fmt, ## args)
+#else
+#define P_DEV(fmt, args...)
+#endif
+
+
+/* lvm-snap.c */
+int lvm_get_blksize(kdev_t);
+int lvm_snapshot_alloc(lv_t *);
+int lvm_snapshot_fill_COW_page(vg_t *, lv_t *);
+int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, vg_t *vg, lv_t *);
+int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);
+void lvm_snapshot_release(lv_t *);
+int lvm_write_COW_table_block(vg_t *, lv_t *);
+void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *);
+int lvm_snapshot_alloc_hash_table(lv_t *);
+void lvm_drop_snapshot(vg_t *vg, lv_t *, const char *);
+
+
+/* lvm_fs.c */
+void lvm_init_fs(void);
+void lvm_fin_fs(void);
+
+void lvm_fs_create_vg(vg_t *vg_ptr);
+void lvm_fs_remove_vg(vg_t *vg_ptr);
+void lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv);
+void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv);
+void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv);
+void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv);
+
+#endif
--- linux/drivers/md/lvm-snap.c.orig	Wed Jul  4 13:48:04 2001
+++ linux/drivers/md/lvm-snap.c	Sun May  6 20:04:40 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.
  *
  */
 
@@ -26,6 +26,19 @@
  *
  *    05/07/2000 - implemented persistent snapshot support
  *    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
+ *                 o pv number is returned in new uint * arg
+ *                 o -1 returned on error
+ *                 lvm_snapshot_fill_COW_table has a return value too.
  *
  */
 
@@ -38,26 +51,48 @@
 #include <linux/lvm.h>
 
 
-#include "lvm-snap.h"
+#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 0.9.1_beta2 snapshot code (18/01/2001)\n";
 
 extern const char *const lvm_name;
 extern int lvm_blocksizes[];
 
 void lvm_snapshot_release(lv_t *);
 
-uint lvm_pv_get_number(vg_t * vg, kdev_t rdev)
-{
+static int _write_COW_table_block(vg_t *vg, lv_t *lv, int idx,
+				  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) {
+	return brw_kiovec(rw, nr, iovec, dev, b, size);
+}
+
+
+static int _pv_get_number(vg_t * vg, kdev_t rdev, uint *pvn) {
 	uint p;
+	for(p = 0; p < vg->pv_max; p++) {
+		if(vg->pv[p] == NULL)
+			continue;
 
-	for ( p = 0; p < vg->pv_max; p++)
-	{
-		if ( vg->pv[p] == NULL) continue;
-		if ( vg->pv[p]->pv_dev == rdev) break;
+		if(vg->pv[p]->pv_dev == rdev)
+			break;
+	}
+
+	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);
+		return -1;
 	}
 
-	return vg->pv[p]->pv_number;
+	*pvn = vg->pv[p]->pv_number;
+	return 0;
 }
 
 
@@ -133,7 +168,7 @@
 	return ret;
 }
 
-void lvm_drop_snapshot(lv_t * lv_snap, const char * reason)
+void lvm_drop_snapshot(vg_t *vg, lv_t *lv_snap, const char *reason)
 {
 	kdev_t last_dev;
 	int i;
@@ -142,6 +177,9 @@
 	   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);
+
 	for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) {
 		if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) {
 			last_dev = lv_snap->lv_block_exception[i].rdev_new;
@@ -150,9 +188,10 @@
 	}
 
 	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);
 }
@@ -209,128 +248,58 @@
 #endif
 
 
-void lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap)
+int lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_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);
+	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;
 	is--;
-        blksize_snap = lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new);
+        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;
+		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;
+
+ bad:
+	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 lvm_write_COW_table_block(vg_t * vg, lv_t *lv_snap)
 {
-	int blksize_snap;
-	int end_of_table;
-	int idx = lv_snap->lv_remap_ptr, idx_COW_table;
-	int nr_pages_tmp;
-	int length_tmp;
-	ulong snap_pe_start, COW_table_sector_offset,
-	      COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block;
-	const char * reason;
-	kdev_t snap_phys_dev;
-	struct kiobuf * iobuf = lv_snap->lv_iobuf;
-	struct page * page_tmp;
-	lv_COW_table_disk_t * lv_COW_table =
-	   ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_page);
-
-	idx--;
-
-	COW_chunks_per_pe = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv_snap);
-	COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap);
-
-	/* get physical addresse of destination chunk */
-	snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
-	snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
-
-	blksize_snap = lvm_get_blksize(snap_phys_dev);
-
-        COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
-        idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block;
-
-	if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap);
-
-	/* 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 */
-	iobuf->blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10);
-
-	/* store new COW_table entry */
-	lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[idx].rdev_org));
-	lv_COW_table[idx_COW_table].pv_org_rsector = cpu_to_le64(lv_snap->lv_block_exception[idx].rsector_org);
-	lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(lvm_pv_get_number(vg, snap_phys_dev));
-	lv_COW_table[idx_COW_table].pv_snap_rsector = cpu_to_le64(lv_snap->lv_block_exception[idx].rsector_new);
-
-	length_tmp = iobuf->length;
-	iobuf->length = blksize_snap;
-	page_tmp = iobuf->maplist[0];
-        iobuf->maplist[0] = lv_snap->lv_COW_table_page;
-	nr_pages_tmp = iobuf->nr_pages;
-	iobuf->nr_pages = 1;
-
-	if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
-		       iobuf->blocks, blksize_snap) != blksize_snap)
-		goto fail_raw_write;
-
-
-	/* 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 good_out;
-
-		memset(lv_COW_table, 0, blksize_snap);
-
-		if (end_of_table)
-		{
-			idx++;
-			snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
-			snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
-			blksize_snap = lvm_get_blksize(snap_phys_dev);
-			iobuf->blocks[0] = snap_pe_start >> (blksize_snap >> 10);
-		} else iobuf->blocks[0]++;
-
-		if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
-			       iobuf->blocks, blksize_snap) != blksize_snap)
-			goto fail_raw_write;
-	}
-
-
- good_out:
-	iobuf->length = length_tmp;
-        iobuf->maplist[0] = page_tmp;
-	iobuf->nr_pages = nr_pages_tmp;
-	return 0;
-
-	/* slow path */
- out:
-	lvm_drop_snapshot(lv_snap, reason);
-	return 1;
-
- fail_raw_write:
-	reason = "write error";
-	goto out;
+	int r;
+	const char *err;
+	if((r = _write_COW_table_block(vg, lv_snap,
+				       lv_snap->lv_remap_ptr - 1, &err)))
+		lvm_drop_snapshot(vg, lv_snap, err);
+	return r;
 }
 
 /*
@@ -345,12 +314,13 @@
 		     unsigned long org_phys_sector,
 		     unsigned long org_pe_start,
 		     unsigned long org_virt_sector,
-		     lv_t * lv_snap)
+		     vg_t *vg, lv_t* lv_snap)
 {
 	const char * reason;
 	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;
 
@@ -370,13 +340,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);
@@ -400,16 +368,16 @@
 
 		iobuf->length = nr_sectors << 9;
 
-		lvm_snapshot_prepare_blocks(iobuf->blocks, org_start,
+		lvm_snapshot_prepare_blocks(blocks, org_start,
 					    nr_sectors, blksize_org);
-		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;
 
-		lvm_snapshot_prepare_blocks(iobuf->blocks, snap_start,
+		lvm_snapshot_prepare_blocks(blocks, snap_start,
 					    nr_sectors, blksize_snap);
-		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;
 	}
 
@@ -434,20 +402,20 @@
 	return 0;
 
 	/* slow path */
- out:
-	lvm_drop_snapshot(lv_snap, reason);
+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;
 }
@@ -456,30 +424,30 @@
 {
 	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->locked = 1;
 	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;
+		LockPage(page);
 		iobuf->nr_pages++;
 	}
 	iobuf->offset = 0;
 
 	err = 0;
- out:
+
+out:
 	return err;
 }
 
@@ -521,41 +489,49 @@
 	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;
+	ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors);
+	if (ret) goto out_free_kiovec;
 
-	err = lvm_snapshot_alloc_hash_table(lv_snap);
-	if (err)
-		goto out_free_kiovec;
+	/* allocate kiovec to do exception table io */
+	ret = alloc_kiovec(1, &lv_snap->lv_COW_table_iobuf);
+	if (ret) goto out_free_kiovec;
 
+	ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf,
+					     PAGE_SIZE/SECTOR_SIZE);
+	if (ret) goto out_free_both_kiovecs;
 
-		lv_snap->lv_COW_table_page = alloc_page(GFP_KERNEL);
-		if (!lv_snap->lv_COW_table_page)
-			goto out_free_kiovec;
+	ret = lvm_snapshot_alloc_hash_table(lv_snap);
+	if (ret) goto out_free_both_kiovecs;
 
- out:
-	return err;
 
- out_free_kiovec:
+out:
+	return ret;
+
+out_free_both_kiovecs:
+	unmap_kiobuf(lv_snap->lv_COW_table_iobuf);
+	free_kiovec(1, &lv_snap->lv_COW_table_iobuf);
+	lv_snap->lv_COW_table_iobuf = NULL;
+
+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;
+	if (lv_snap->lv_snapshot_hash_table != NULL)
+		vfree(lv_snap->lv_snapshot_hash_table);
 	lv_snap->lv_snapshot_hash_table = NULL;
 	goto out;
 }
@@ -580,9 +556,125 @@
 		free_kiovec(1, &lv->lv_iobuf);
 		lv->lv_iobuf = NULL;
 	}
-	if (lv->lv_COW_table_page)
+	if (lv->lv_COW_table_iobuf)
 	{
-		free_page((ulong)lv->lv_COW_table_page);
-		lv->lv_COW_table_page = NULL;
+	        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;
+	}
+}
+
+
+static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap,
+				  int idx, const char **reason) {
+	int blksize_snap;
+	int end_of_table;
+	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;
+	ulong blocks[1];
+	kdev_t snap_phys_dev;
+	lv_block_exception_t *be;
+	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]);
+
+	COW_chunks_per_pe = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv_snap);
+	COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap);
+
+	/* get physical addresse of destination chunk */
+	snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
+	snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
+
+	blksize_snap = lvm_get_blksize(snap_phys_dev);
+
+        COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
+        idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block;
+
+	if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap);
+
+	/* 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);
+
+	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, lv_snap) != blksize_snap)
+		goto fail_raw_write;
+
+	/* 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;
+
+		memset(lv_COW_table, 0, blksize_snap);
+
+		if (end_of_table)
+		{
+			idx++;
+			snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new;
+			snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size;
+			blksize_snap = lvm_get_blksize(snap_phys_dev);
+			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, lv_snap) !=
+                    blksize_snap)
+			goto fail_raw_write;
+	}
+
+out:
+	return 0;
+
+fail_raw_write:
+	*reason = "write error";
+	return 1;
+
+fail_pv_get_number:
+	*reason = "_pv_get_number failed";
+	return 1;
+}
+
+/*
+ * FIXME_1.2
+ * This function is a bit of a hack; we need to ensure that the
+ * snapshot is never made active again, because it will surely be
+ * corrupt.  At the moment we do not have access to the LVM metadata
+ * from within the kernel.  So we set the first exception to point to
+ * sector 1 (which will always be within the metadata, and as such
+ * invalid).  User land tools will check for this when they are asked
+ * to activate the snapshot and prevent this from happening.
+ */
+
+static void _disable_snapshot(vg_t *vg, lv_t *lv) {
+	const char *err;
+	lv->lv_block_exception[0].rsector_org = LVM_SNAPSHOT_DROPPED_SECTOR;
+	if(_write_COW_table_block(vg, lv, 0, &err) < 0) {
+		printk(KERN_ERR "%s -- couldn't disable snapshot: %s\n",
+		       lvm_name, err);
 	}
 }
--- linux/drivers/md/lvm-fs.c.orig Mon May  7 01:04:40 2001
+++ linux/drivers/md/lvm-fs.c Mon May  7 01:04:40 2001
@@ -0,0 +1,604 @@
+/*
+ * kernel/lvm-fs.c
+ *
+ * Copyright (C) 2001 Sistina Software
+ *
+ * January-March 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * LVM 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.
+ *
+ */
+
+/*
+ * Changelog
+ *
+ *    11/01/2001 - First version (Joe Thornber)
+ *    21/03/2001 - added display of stripes and stripe size (HM)
+ *    04/10/2001 - corrected devfs_register() call in lvm_init_fs()
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+
+#include <linux/devfs_fs_kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/lvm.h>
+
+#include "lvm-internal.h"
+
+
+static int _proc_read_vg(char *page, char **start, off_t off,
+			 int count, int *eof, void *data);
+static int _proc_read_lv(char *page, char **start, off_t off,
+			 int count, int *eof, void *data);
+static int _proc_read_pv(char *page, char **start, off_t off,
+			 int count, int *eof, void *data);
+static int _proc_read_global(char *page, char **start, off_t off,
+			     int count, int *eof, void *data);
+
+static int _vg_info(vg_t *vg_ptr, char *buf);
+static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf);
+static int _pv_info(pv_t *pv_ptr, char *buf);
+
+static void _show_uuid(const char *src, char *b, char *e);
+
+static devfs_handle_t lvm_devfs_handle;
+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];
+
+static struct proc_dir_entry *lvm_proc_dir = NULL;
+static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;
+
+/* inline functions */
+
+/* public interface */
+void lvm_init_fs() {
+	struct proc_dir_entry *pde;
+
+	lvm_devfs_handle = devfs_register(
+		0 , "lvm", 0, LVM_CHAR_MAJOR, 0,
+		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+		&lvm_chr_fops, NULL);
+
+	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,
+						       lvm_proc_dir);
+		pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir);
+		if ( pde != NULL) pde->read_proc = _proc_read_global;
+	}
+}
+
+void lvm_fin_fs() {
+	devfs_unregister (lvm_devfs_handle);
+
+	remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
+	remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
+	remove_proc_entry(LVM_DIR, &proc_root);
+}
+
+void lvm_fs_create_vg(vg_t *vg_ptr) {
+	struct proc_dir_entry *pde;
+
+	vg_devfs_handle[vg_ptr->vg_number] =
+		devfs_mk_dir(0, vg_ptr->vg_name, NULL);
+
+	ch_devfs_handle[vg_ptr->vg_number] = devfs_register(
+		vg_devfs_handle[vg_ptr->vg_number] , "group",
+		DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number,
+		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+		&lvm_chr_fops, NULL);
+
+	vg_ptr->vg_dir_pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
+					       lvm_proc_vg_subdir);
+
+	if((pde = create_proc_entry("group", S_IFREG, vg_ptr->vg_dir_pde))) {
+		pde->read_proc = _proc_read_vg;
+		pde->data = vg_ptr;
+	}
+
+	vg_ptr->lv_subdir_pde =
+		create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
+
+	vg_ptr->pv_subdir_pde =
+		create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
+}
+
+void lvm_fs_remove_vg(vg_t *vg_ptr) {
+	int i;
+
+	devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]);
+	devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
+
+	/* remove lv's */
+	for(i = 0; i < vg_ptr->lv_max; i++)
+		if(vg_ptr->lv[i]) lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]);
+
+	/* remove pv's */
+	for(i = 0; i < vg_ptr->pv_max; i++)
+		if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
+
+	if(vg_ptr->vg_dir_pde) {
+		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
+		remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde);
+		remove_proc_entry("group", vg_ptr->vg_dir_pde);
+		remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir);
+	}
+}
+
+
+static inline const char *_basename(const char *str) {
+	const char *name = strrchr(str, '/');
+	name = name ? name + 1 : str;
+	return name;
+}
+
+void lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) {
+	struct proc_dir_entry *pde;
+	const char *name = _basename(lv->lv_name);
+
+	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);
+
+	if(vg_ptr->lv_subdir_pde &&
+	   (pde = create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) {
+		pde->read_proc = _proc_read_lv;
+		pde->data = lv;
+	}
+}
+
+void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) {
+	devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]);
+
+	if(vg_ptr->lv_subdir_pde) {
+		const char *name = _basename(lv->lv_name);
+		remove_proc_entry(name, vg_ptr->lv_subdir_pde);
+	}
+}
+
+
+static inline void _make_pv_name(const char *src, char *b, char *e) {
+	int offset = strlen(LVM_DIR_PREFIX);
+	if(strncmp(src, LVM_DIR_PREFIX, offset))
+		offset = 0;
+
+	e--;
+	src += offset;
+	while(*src && (b != e)) {
+		*b++ = (*src == '/') ? '_' : *src;
+		src++;
+	}
+	*b = '\0';
+}
+
+void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv) {
+	struct proc_dir_entry *pde;
+	char name[NAME_LEN];
+
+	if(!vg_ptr->pv_subdir_pde)
+		return;
+
+	_make_pv_name(pv->pv_name, name, name + sizeof(name));
+	if((pde = create_proc_entry(name, S_IFREG, vg_ptr->pv_subdir_pde))) {
+		pde->read_proc = _proc_read_pv;
+		pde->data = pv;
+	}
+}
+
+void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) {
+	char name[NAME_LEN];
+
+	if(!vg_ptr->pv_subdir_pde)
+		return;
+
+	_make_pv_name(pv->pv_name, name, name + sizeof(name));
+	remove_proc_entry(name, vg_ptr->pv_subdir_pde);
+}
+
+
+static int _proc_read_vg(char *page, char **start, off_t off,
+			  int count, int *eof, void *data) {
+	int sz = 0;
+	vg_t *vg_ptr = data;
+	char uuid[NAME_LEN];
+
+	sz += sprintf(page + sz, "name:         %s\n", vg_ptr->vg_name);
+	sz += sprintf(page + sz, "size:         %u\n",
+		      vg_ptr->pe_total * vg_ptr->pe_size / 2);
+	sz += sprintf(page + sz, "access:       %u\n", vg_ptr->vg_access);
+	sz += sprintf(page + sz, "status:       %u\n", vg_ptr->vg_status);
+	sz += sprintf(page + sz, "number:       %u\n", vg_ptr->vg_number);
+	sz += sprintf(page + sz, "LV max:       %u\n", vg_ptr->lv_max);
+	sz += sprintf(page + sz, "LV current:   %u\n", vg_ptr->lv_cur);
+	sz += sprintf(page + sz, "LV open:      %u\n", vg_ptr->lv_open);
+	sz += sprintf(page + sz, "PV max:       %u\n", vg_ptr->pv_max);
+	sz += sprintf(page + sz, "PV current:   %u\n", vg_ptr->pv_cur);
+	sz += sprintf(page + sz, "PV active:    %u\n", vg_ptr->pv_act);
+	sz += sprintf(page + sz, "PE size:      %u\n", vg_ptr->pe_size / 2);
+	sz += sprintf(page + sz, "PE total:     %u\n", vg_ptr->pe_total);
+	sz += sprintf(page + sz, "PE allocated: %u\n", vg_ptr->pe_allocated);
+
+	_show_uuid(vg_ptr->vg_uuid, uuid, uuid + sizeof(uuid));
+	sz += sprintf(page + sz, "uuid:         %s\n", uuid);
+
+	return sz;
+}
+
+static int _proc_read_lv(char *page, char **start, off_t off,
+			  int count, int *eof, void *data) {
+	int sz = 0;
+	lv_t *lv = data;
+
+	sz += sprintf(page + sz, "name:         %s\n", lv->lv_name);
+	sz += sprintf(page + sz, "size:         %u\n", lv->lv_size);
+	sz += sprintf(page + sz, "access:       %u\n", lv->lv_access);
+	sz += sprintf(page + sz, "status:       %u\n", lv->lv_status);
+	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);
+	}
+	sz += sprintf(page + sz, "device:       %02u:%02u\n",
+		      MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
+
+	return sz;
+}
+
+static int _proc_read_pv(char *page, char **start, off_t off,
+			 int count, int *eof, void *data) {
+	int sz = 0;
+	pv_t *pv = data;
+	char uuid[NAME_LEN];
+
+	sz += sprintf(page + sz, "name:         %s\n", pv->pv_name);
+	sz += sprintf(page + sz, "size:         %u\n", pv->pv_size);
+	sz += sprintf(page + sz, "status:       %u\n", pv->pv_status);
+	sz += sprintf(page + sz, "number:       %u\n", pv->pv_number);
+	sz += sprintf(page + sz, "allocatable:  %u\n", pv->pv_allocatable);
+	sz += sprintf(page + sz, "LV current:   %u\n", pv->lv_cur);
+	sz += sprintf(page + sz, "PE size:      %u\n", pv->pe_size / 2);
+	sz += sprintf(page + sz, "PE total:     %u\n", pv->pe_total);
+	sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated);
+	sz += sprintf(page + sz, "device:       %02u:%02u\n",
+                      MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
+
+	_show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid));
+	sz += sprintf(page + sz, "uuid:         %s\n", uuid);
+
+	return sz;
+}
+
+static int _proc_read_global(char *page, char **start, off_t pos, int count,
+			     int *eof, void *data) {
+
+#define  LVM_PROC_BUF   ( i == 0 ? dummy_buf : &buf[sz])
+
+	int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
+		lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds;
+	static off_t sz;
+	off_t sz_last;
+	static char *buf = NULL;
+	static char dummy_buf[160];	/* sized for 2 lines */
+	vg_t *vg_ptr;
+	lv_t *lv_ptr;
+	pv_t *pv_ptr;
+
+
+#ifdef DEBUG_LVM_PROC_GET_INFO
+	printk(KERN_DEBUG
+	       "%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)
+		goto out;
+
+	sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \
+		lv_open_total = pe_t_bytes = hash_table_bytes = \
+		lv_block_exception_t_bytes = 0;
+
+	/* get some statistics */
+	for (v = 0; v < ABS_MAX_VG; v++) {
+		if ((vg_ptr = vg[v]) != NULL) {
+			vg_counter++;
+			pv_counter += vg_ptr->pv_cur;
+			lv_counter += vg_ptr->lv_cur;
+			if (vg_ptr->lv_cur > 0) {
+				for (l = 0; l < vg[v]->lv_max; l++) {
+					if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
+						pe_t_bytes += lv_ptr->lv_allocated_le;
+						hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size;
+						if (lv_ptr->lv_block_exception != NULL)
+							lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
+						if (lv_ptr->lv_open > 0) {
+							lv_open_counter++;
+							lv_open_total += lv_ptr->lv_open;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	pe_t_bytes *= sizeof(pe_t);
+	lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
+
+	if (buf != NULL) {
+		P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__);
+		lock_kernel();
+		vfree(buf);
+		unlock_kernel();
+		buf = NULL;
+	}
+	/* 2 times: first to get size to allocate buffer,
+	   2nd to fill the malloced buffer */
+	for (i = 0; i < 2; i++) {
+		sz = 0;
+		sz += sprintf(LVM_PROC_BUF,
+			      "LVM "
+#ifdef MODULE
+			      "module"
+#else
+			      "driver"
+#endif
+			      " %s\n\n"
+			      "Total:  %d VG%s  %d PV%s  %d LV%s ",
+			      lvm_short_version,
+			      vg_counter, vg_counter == 1 ? "" : "s",
+			      pv_counter, pv_counter == 1 ? "" : "s",
+			      lv_counter, lv_counter == 1 ? "" : "s");
+		sz += sprintf(LVM_PROC_BUF,
+			      "(%d LV%s open",
+			      lv_open_counter,
+			      lv_open_counter == 1 ? "" : "s");
+		if (lv_open_total > 0)
+			sz += sprintf(LVM_PROC_BUF,
+				      " %d times)\n",
+				      lv_open_total);
+		else
+			sz += sprintf(LVM_PROC_BUF, ")");
+		sz += sprintf(LVM_PROC_BUF,
+			      "\nGlobal: %lu bytes malloced   IOP version: %d   ",
+			      vg_counter * sizeof(vg_t) +
+			      pv_counter * sizeof(pv_t) +
+			      lv_counter * sizeof(lv_t) +
+			      pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last,
+			      lvm_iop_version);
+
+		seconds = CURRENT_TIME - loadtime;
+		if (seconds < 0)
+			loadtime = CURRENT_TIME + seconds;
+		if (seconds / 86400 > 0) {
+			sz += sprintf(LVM_PROC_BUF, "%d day%s ",
+				      seconds / 86400,
+				      seconds / 86400 == 0 ||
+				      seconds / 86400 > 1 ? "s" : "");
+		}
+		sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
+			      (seconds % 86400) / 3600,
+			      (seconds % 3600) / 60,
+			      seconds % 60);
+
+		if (vg_counter > 0) {
+			for (v = 0; v < ABS_MAX_VG; v++) {
+				/* volume group */
+				if ((vg_ptr = vg[v]) != NULL) {
+					sz += _vg_info(vg_ptr, LVM_PROC_BUF);
+
+					/* physical volumes */
+					sz += sprintf(LVM_PROC_BUF,
+						      "\n  PV%s ",
+						      vg_ptr->pv_cur == 1 ? ": " : "s:");
+					c = 0;
+					for (p = 0; p < vg_ptr->pv_max; p++) {
+						if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
+							sz += _pv_info(pv_ptr, LVM_PROC_BUF);
+
+							c++;
+							if (c < vg_ptr->pv_cur)
+								sz += sprintf(LVM_PROC_BUF,
+									      "\n       ");
+						}
+					}
+
+					/* logical volumes */
+					sz += sprintf(LVM_PROC_BUF,
+						      "\n    LV%s ",
+						      vg_ptr->lv_cur == 1 ? ": " : "s:");
+					c = 0;
+					for (l = 0; l < vg_ptr->lv_max; l++) {
+						if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
+							sz += _lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF);
+							c++;
+							if (c < vg_ptr->lv_cur)
+								sz += sprintf(LVM_PROC_BUF,
+									      "\n         ");
+						}
+					}
+					if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
+					sz += sprintf(LVM_PROC_BUF, "\n");
+				}
+			}
+		}
+		if (buf == NULL) {
+			lock_kernel();
+			buf = vmalloc(sz);
+			unlock_kernel();
+			if (buf == NULL) {
+				sz = 0;
+				return sprintf(page, "%s - vmalloc error at line %d\n",
+					       lvm_name, __LINE__);
+			}
+		}
+		sz_last = sz;
+	}
+
+ out:
+	if (pos > sz - 1) {
+		lock_kernel();
+		vfree(buf);
+		unlock_kernel();
+		buf = NULL;
+		return 0;
+	}
+	*start = &buf[pos];
+	if (sz - pos < count)
+		return sz - pos;
+	else
+		return count;
+
+#undef LVM_PROC_BUF
+}
+
+/*
+ * provide VG info for proc filesystem use (global)
+ */
+static int _vg_info(vg_t *vg_ptr, char *buf) {
+	int sz = 0;
+	char inactive_flag = ' ';
+
+	if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
+	sz = sprintf(buf,
+		     "\nVG: %c%s  [%d PV, %d LV/%d open] "
+		     " PE Size: %d KB\n"
+		     "  Usage [KB/PE]: %d /%d total  "
+		     "%d /%d used  %d /%d free",
+		     inactive_flag,
+		     vg_ptr->vg_name,
+		     vg_ptr->pv_cur,
+		     vg_ptr->lv_cur,
+		     vg_ptr->lv_open,
+	     	     vg_ptr->pe_size >> 1,
+		     vg_ptr->pe_size * vg_ptr->pe_total >> 1,
+		     vg_ptr->pe_total,
+		     vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
+	     	     vg_ptr->pe_allocated,
+		     (vg_ptr->pe_total - vg_ptr->pe_allocated) *
+	     	     vg_ptr->pe_size >> 1,
+		     vg_ptr->pe_total - vg_ptr->pe_allocated);
+	return sz;
+}
+
+
+/*
+ * provide LV info for proc filesystem use (global)
+ */
+static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) {
+	int sz = 0;
+	char inactive_flag = 'A', allocation_flag = ' ',
+		stripes_flag = ' ', rw_flag = ' ', *basename;
+
+	if (!(lv_ptr->lv_status & LV_ACTIVE))
+		inactive_flag = 'I';
+	rw_flag = 'R';
+	if (lv_ptr->lv_access & LV_WRITE)
+		rw_flag = 'W';
+	allocation_flag = 'D';
+	if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
+		allocation_flag = 'C';
+	stripes_flag = 'L';
+	if (lv_ptr->lv_stripes > 1)
+		stripes_flag = 'S';
+	sz += sprintf(buf+sz,
+		      "[%c%c%c%c",
+		      inactive_flag,
+	 rw_flag,
+		      allocation_flag,
+		      stripes_flag);
+	if (lv_ptr->lv_stripes > 1)
+		sz += sprintf(buf+sz, "%-2d",
+			      lv_ptr->lv_stripes);
+	else
+		sz += sprintf(buf+sz, "  ");
+
+	/* FIXME: use _basename */
+	basename = strrchr(lv_ptr->lv_name, '/');
+	if ( basename == 0) basename = lv_ptr->lv_name;
+	else                basename++;
+	sz += sprintf(buf+sz, "] %-25s", basename);
+	if (strlen(basename) > 25)
+		sz += sprintf(buf+sz,
+			      "\n                              ");
+	sz += sprintf(buf+sz, "%9d /%-6d   ",
+		      lv_ptr->lv_size >> 1,
+		      lv_ptr->lv_size / vg_ptr->pe_size);
+
+	if (lv_ptr->lv_open == 0)
+		sz += sprintf(buf+sz, "close");
+	else
+		sz += sprintf(buf+sz, "%dx open",
+			      lv_ptr->lv_open);
+
+	return sz;
+}
+
+
+/*
+ * provide PV info for proc filesystem use (global)
+ */
+static int _pv_info(pv_t *pv, char *buf) {
+	int sz = 0;
+	char inactive_flag = 'A', allocation_flag = ' ';
+	char *pv_name = NULL;
+
+	if (!(pv->pv_status & PV_ACTIVE))
+		inactive_flag = 'I';
+	allocation_flag = 'A';
+	if (!(pv->pv_allocatable & PV_ALLOCATABLE))
+		allocation_flag = 'N';
+	pv_name = strrchr(pv->pv_name+1,'/');
+	if ( pv_name == 0) pv_name = pv->pv_name;
+	else               pv_name++;
+	sz = sprintf(buf,
+		     "[%c%c] %-21s %8d /%-6d  "
+		     "%8d /%-6d  %8d /%-6d",
+		     inactive_flag,
+		     allocation_flag,
+		     pv_name,
+		     pv->pe_total * pv->pe_size >> 1,
+		     pv->pe_total,
+		     pv->pe_allocated * pv->pe_size >> 1,
+		     pv->pe_allocated,
+		     (pv->pe_total - pv->pe_allocated) *
+		     pv->pe_size >> 1,
+		     pv->pe_total - pv->pe_allocated);
+	return sz;
+}
+
+static void _show_uuid(const char *src, char *b, char *e) {
+	int i;
+
+	e--;
+	for(i = 0; *src && (b != e); i++) {
+		if(i && !(i & 0x3))
+			*b++ = '-';
+		*b++ = *src++;
+	}
+	*b = '\0';
+}
--- linux/drivers/md/Makefile.orig	Fri Feb 16 13:56:28 2001
+++ linux/drivers/md/Makefile	Fri Feb 16 13:56:39 2001
@@ -6,7 +6,7 @@
 
 export-objs	:= md.o xor.o
 list-multi	:= lvm-mod.o
-lvm-mod-objs	:= lvm.o lvm-snap.o
+lvm-mod-objs	:= lvm.o lvm-snap.o lvm-fs.o
 
 # Note: link order is important.  All raid personalities
 # and xor.o must come before md.o, as they each initialise 
diff -ruN -X /home/joe/packages/dontdiff linux_2.4.1/drivers/md/lvm-snap.h linux/drivers/md/lvm-snap.h
--- linux_2.4.1/drivers/md/lvm-snap.h	Fri Feb 16 14:51:26 2001
+++ linux/drivers/md/lvm-snap.h	Thu Jan  1 01:00:00 1970
@@ -1,47 +0,0 @@
-/*
- * kernel/lvm-snap.h
- *
- * Copyright (C) 2001 Sistina Software
- *
- *
- * 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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * LVM 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.
- *
- */
-
-/*
- * Changelog
- *
- *    05/01/2001:Joe Thornber - Factored this file out of lvm.c
- *
- */
-
-#ifndef LVM_SNAP_H
-#define LVM_SNAP_H
-
-/* external snapshot calls */
-extern inline int lvm_get_blksize(kdev_t);
-extern int lvm_snapshot_alloc(lv_t *);
-extern void lvm_snapshot_fill_COW_page(vg_t *, lv_t *);
-extern int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *);
-extern int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);
-extern void lvm_snapshot_release(lv_t *); 
-extern int lvm_write_COW_table_block(vg_t *, lv_t *);
-extern inline void lvm_hash_link(lv_block_exception_t *, 
-				 kdev_t, ulong, lv_t *);
-extern int lvm_snapshot_alloc_hash_table(lv_t *);
-extern void lvm_drop_snapshot(lv_t *, const char *);
-
-#endif
--- linux/Documentation/ioctl-number.txt.orig	Mon Mar 12 10:16:51 2001
+++ linux/Documentation/ioctl-number.txt	Mon Mar 12 10:17:36 2001
@@ -186,3 +186,6 @@
 0xB1	00-1F	PPPoX			<mailto:mostrows@styx.uwaterloo.ca>
 0xCB	00-1F	CBM serial IEC bus	in development:
 					<mailto:michael.klein@puffin.lb.shuttle.de>
+
+0xFE	00-9F	Logical Volume Manager  <mailto:linux-lvm@sistina.com>
+

             reply	other threads:[~2001-07-05  0:20 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-07-05  0:20 Steven Lembark [this message]
2001-07-05  0:48 ` [linux-lvm] Unable to compile 2.4.6 Totoro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9880000.994292407@dizzy \
    --to=lembark@wrkhors.com \
    --cc=linux-lvm@sistina.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.