File: /usr/src/linux/drivers/md/lvm.c

1     /*
2      * kernel/lvm.c
3      *
4      * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Sistina Software
5      *
6      * February-November 1997
7      * April-May,July-August,November 1998
8      * January-March,May,July,September,October 1999
9      * January,February,July,September-November 2000
10      * January 2001
11      *
12      *
13      * LVM driver is free software; you can redistribute it and/or modify
14      * it under the terms of the GNU General Public License as published by
15      * the Free Software Foundation; either version 2, or (at your option)
16      * any later version.
17      *
18      * LVM driver is distributed in the hope that it will be useful,
19      * but WITHOUT ANY WARRANTY; without even the implied warranty of
20      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21      * GNU General Public License for more details.
22      *
23      * You should have received a copy of the GNU General Public License
24      * along with GNU CC; see the file COPYING.  If not, write to
25      * the Free Software Foundation, 59 Temple Place - Suite 330,
26      * Boston, MA 02111-1307, USA.
27      *
28      */
29     
30     /*
31      * Changelog
32      *
33      *    09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT
34      *                 and VG_STATUS_GET_NAMELIST
35      *    18/01/1998 - change lvm_chr_open/close lock handling
36      *    30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and
37      *               - added   LV_STATUS_BYINDEX ioctl
38      *               - used lvm_status_byname_req_t and
39      *                      lvm_status_byindex_req_t vars
40      *    04/05/1998 - added multiple device support
41      *    08/05/1998 - added support to set/clear extendable flag in volume group
42      *    09/05/1998 - changed output of lvm_proc_get_global_info() because of
43      *                 support for free (eg. longer) logical volume names
44      *    12/05/1998 - added spin_locks (thanks to Pascal van Dam
45      *                 <pascal@ramoth.xs4all.nl>)
46      *    25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl()
47      *    26/05/1998 - reactivated verify_area by access_ok
48      *    07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go
49      *                 beyond 128/256 KB max allocation limit per call
50      *               - #ifdef blocked spin_lock calls to avoid compile errors
51      *                 with 2.0.x
52      *    11/06/1998 - another enhancement to spinlock code in lvm_chr_open()
53      *                 and use of LVM_VERSION_CODE instead of my own macros
54      *                 (thanks to  Michael Marxmeier <mike@msede.com>)
55      *    07/07/1998 - added statistics in lvm_map()
56      *    08/07/1998 - saved statistics in lvm_do_lv_extend_reduce()
57      *    25/07/1998 - used __initfunc macro
58      *    02/08/1998 - changes for official char/block major numbers
59      *    07/08/1998 - avoided init_module() and cleanup_module() to be static
60      *    30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters
61      *                 to sum of LVs open (no matter how often each is)
62      *    01/09/1998 - fixed lvm_gendisk.part[] index error
63      *    07/09/1998 - added copying of lv_current_pe-array
64      *                 in LV_STATUS_BYINDEX ioctl
65      *    17/11/1998 - added KERN_* levels to printk
66      *    13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename
67      *    07/02/1999 - fixed spinlock handling bug in case of LVM_RESET
68      *                 by moving spinlock code from lvm_chr_open()
69      *                 to lvm_chr_ioctl()
70      *               - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl()
71      *               - allowed LVM_RESET and retrieval commands to go ahead;
72      *                 only other update ioctls are blocked now
73      *               - fixed pv->pe to NULL for pv_status
74      *               - using lv_req structure in lvm_chr_ioctl() now
75      *               - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce()
76      *                 caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE)
77      *    09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to
78      *                 handle lgoical volume private read ahead sector
79      *               - implemented LV read_ahead handling with lvm_blk_read()
80      *                 and lvm_blk_write()
81      *    10/02/1999 - implemented 2.[12].* support function lvm_hd_name()
82      *                 to be used in drivers/block/genhd.c by disk_name()
83      *    12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO
84      *               - enhanced gendisk insert/remove handling
85      *    16/02/1999 - changed to dynamic block minor number allocation to
86      *                 have as much as 99 volume groups with 256 logical volumes
87      *                 as the grand total; this allows having 1 volume group with
88      *                 up to 256 logical volumes in it
89      *    21/02/1999 - added LV open count information to proc filesystem
90      *               - substituted redundant LVM_RESET code by calls
91      *                 to lvm_do_vg_remove()
92      *    22/02/1999 - used schedule_timeout() to be more responsive
93      *                 in case of lvm_do_vg_remove() with lots of logical volumes
94      *    19/03/1999 - fixed NULL pointer bug in module_init/lvm_init
95      *    17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0)
96      *               - enhanced lvm_hd_name support
97      *    03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and
98      *                 memcpy_tofs/memcpy_fromfs macro redefinitions
99      *    06/07/1999 - corrected reads/writes statistic counter copy in case
100      *                 of striped logical volume
101      *    28/07/1999 - implemented snapshot logical volumes
102      *                 - lvm_chr_ioctl
103      *                   - LV_STATUS_BYINDEX
104      *                   - LV_STATUS_BYNAME
105      *                 - lvm_do_lv_create
106      *                 - lvm_do_lv_remove
107      *                 - lvm_map
108      *                 - new lvm_snapshot_remap_block
109      *                 - new lvm_snapshot_remap_new_block
110      *    08/10/1999 - implemented support for multiple snapshots per
111      *                 original logical volume
112      *    12/10/1999 - support for 2.3.19
113      *    11/11/1999 - support for 2.3.28
114      *    21/11/1999 - changed lvm_map() interface to buffer_head based
115      *    19/12/1999 - support for 2.3.33
116      *    01/01/2000 - changed locking concept in lvm_map(),
117      *                 lvm_do_vg_create() and lvm_do_lv_remove()
118      *    15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl()
119      *    24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc.
120      *    29/01/2000 - used kmalloc/kfree again for all small structures
121      *    20/01/2000 - cleaned up lvm_chr_ioctl by moving code
122      *                 to seperated functions
123      *               - avoided "/dev/" in proc filesystem output
124      *               - avoided inline strings functions lvm_strlen etc.
125      *    14/02/2000 - support for 2.3.43
126      *               - integrated Andrea Arcagneli's snapshot code
127      *    25/06/2000 - james (chip) , IKKHAYD! roffl
128      *    26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume support
129      *    06/09/2000 - added devfs support
130      *    07/09/2000 - changed IOP version to 9
131      *               - started to add new char ioctl LV_STATUS_BYDEV_T to support
132      *                 getting an lv_t based on the dev_t of the Logical Volume
133      *    14/09/2000 - enhanced lvm_do_lv_create to upcall VFS functions
134      *                 to sync and lock, activate snapshot and unlock the FS
135      *                 (to support journaled filesystems)
136      *    18/09/2000 - hardsector size support
137      *    27/09/2000 - implemented lvm_do_lv_rename() and lvm_do_vg_rename()
138      *    30/10/2000 - added Andi Kleen's LV_BMAP ioctl to support LILO
139      *    01/11/2000 - added memory information on hash tables to
140      *                 lvm_proc_get_global_info()
141      *    02/11/2000 - implemented /proc/lvm/ hierarchy
142      *    22/11/2000 - changed lvm_do_create_proc_entry_of_pv () to work
143      *                 with devfs
144      *    26/11/2000 - corrected #ifdef locations for PROC_FS
145      *    28/11/2000 - fixed lvm_do_vg_extend() NULL pointer BUG
146      *               - fixed lvm_do_create_proc_entry_of_pv() buffer tampering BUG
147      *    08/01/2001 - Removed conditional compiles related to PROC_FS,
148      *                 procfs is always supported now. (JT)
149      *    12/01/2001 - avoided flushing logical volume in case of shrinking
150      *                 because of unecessary overhead in case of heavy updates
151      *    05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it
152      *		   destroys stacking devices. call b_end_io on failed maps.
153      *		   (Jens Axboe)
154      *
155      */
156     
157     
158     static char *lvm_version = "LVM version 0.9.1_beta2  by Heinz Mauelshagen  (18/01/2001)\n";
159     static char *lvm_short_version = "version 0.9.1_beta2 (18/01/2001)";
160     
161     #define MAJOR_NR	LVM_BLK_MAJOR
162     #define	DEVICE_OFF(device)
163     
164     /* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
165     /* #define	LVM_VFS_ENHANCEMENT */
166     
167     #include <linux/config.h>
168     #include <linux/version.h>
169     #include <linux/module.h>
170     
171     #include <linux/kernel.h>
172     #include <linux/vmalloc.h>
173     #include <linux/slab.h>
174     #include <linux/init.h>
175     
176     #include <linux/hdreg.h>
177     #include <linux/stat.h>
178     #include <linux/fs.h>
179     #include <linux/proc_fs.h>
180     #include <linux/blkdev.h>
181     #include <linux/genhd.h>
182     #include <linux/locks.h>
183     #include <linux/smp_lock.h>
184     #include <asm/ioctl.h>
185     #include <asm/segment.h>
186     #include <asm/uaccess.h>
187     
188     #ifdef CONFIG_KERNELD
189     #include <linux/kerneld.h>
190     #endif
191     
192     #include <linux/blk.h>
193     #include <linux/blkpg.h>
194     
195     #include <linux/errno.h>
196     #include <linux/lvm.h>
197     
198     #include "lvm-snap.h"
199     
200     #define	LVM_CORRECT_READ_AHEAD(a)		\
201     do {						\
202     	if ((a) < LVM_MIN_READ_AHEAD ||		\
203     	    (a) > LVM_MAX_READ_AHEAD)		\
204     		(a) = LVM_DEFAULT_READ_AHEAD;	\
205     	read_ahead[MAJOR_NR] = (a);		\
206     } while(0)
207     
208     #ifndef WRITEA
209     #  define WRITEA WRITE
210     #endif
211     
212     /* debug macros */
213     #ifdef DEBUG_IOCTL
214     #define P_IOCTL(fmt, args...) printk(KERN_DEBUG "lvm ioctl: " fmt, ## args)
215     #else
216     #define P_IOCTL(fmt, args...)
217     #endif
218     
219     #ifdef DEBUG_MAP
220     #define P_MAP(fmt, args...) printk(KERN_DEBUG "lvm map: " fmt, ## args)
221     #else
222     #define P_MAP(fmt, args...)
223     #endif
224     
225     #ifdef DEBUG_KFREE
226     #define P_KFREE(fmt, args...) printk(KERN_DEBUG "lvm kfree: " fmt, ## args)
227     #else
228     #define P_KFREE(fmt, args...)
229     #endif
230     
231     /*
232      * External function prototypes
233      */
234     static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*);
235     
236     static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
237     static int lvm_blk_open(struct inode *, struct file *);
238     
239     static int lvm_chr_open(struct inode *, struct file *);
240     
241     static int lvm_chr_close(struct inode *, struct file *);
242     static int lvm_blk_close(struct inode *, struct file *);
243     static int lvm_user_bmap(struct inode *, struct lv_bmap *);
244     
245     static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong);
246     
247     int lvm_proc_read_vg_info(char *, char **, off_t, int, int *, void *);
248     int lvm_proc_read_lv_info(char *, char **, off_t, int, int *, void *);
249     int lvm_proc_read_pv_info(char *, char **, off_t, int, int *, void *);
250     static int lvm_proc_get_global_info(char *, char **, off_t, int, int *, void *);
251     
252     void lvm_do_create_devfs_entry_of_vg ( vg_t *);
253     
254     void lvm_do_create_proc_entry_of_vg ( vg_t *);
255     void lvm_do_remove_proc_entry_of_vg ( vg_t *);
256     void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *);
257     void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *);
258     void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *);
259     void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *);
260     
261     /* End external function prototypes */
262     
263     
264     /*
265      * Internal function prototypes
266      */
267     static void lvm_cleanup(void);
268     static void lvm_init_vars(void);
269     
270     #ifdef LVM_HD_NAME
271     extern void (*lvm_hd_name_ptr) (char *, int);
272     #endif
273     static int lvm_map(struct buffer_head *, int);
274     static int lvm_do_lock_lvm(void);
275     static int lvm_do_le_remap(vg_t *, void *);
276     
277     static int lvm_do_pv_create(pv_t *, vg_t *, ulong);
278     static int lvm_do_pv_remove(vg_t *, ulong);
279     static int lvm_do_lv_create(int, char *, lv_t *);
280     static int lvm_do_lv_extend_reduce(int, char *, lv_t *);
281     static int lvm_do_lv_remove(int, char *, int);
282     static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *);
283     static int lvm_do_lv_status_byname(vg_t *r, void *);
284     static int lvm_do_lv_status_byindex(vg_t *, void *);
285     static int lvm_do_lv_status_bydev(vg_t *, void *);
286     
287     static int lvm_do_pe_lock_unlock(vg_t *r, void *);
288     
289     static int lvm_do_pv_change(vg_t*, void*);
290     static int lvm_do_pv_status(vg_t *, void *);
291     
292     static int lvm_do_vg_create(int, void *);
293     static int lvm_do_vg_extend(vg_t *, void *);
294     static int lvm_do_vg_reduce(vg_t *, void *);
295     static int lvm_do_vg_rename(vg_t *, void *);
296     static int lvm_do_vg_remove(int);
297     static void lvm_geninit(struct gendisk *);
298     static char *lvm_show_uuid ( char *);
299     #ifdef LVM_HD_NAME
300     void lvm_hd_name(char *, int);
301     #endif
302     /* END Internal function prototypes */
303     
304     
305     /* volume group descriptor area pointers */
306     static vg_t *vg[ABS_MAX_VG];
307     
308     static devfs_handle_t lvm_devfs_handle;
309     static devfs_handle_t vg_devfs_handle[MAX_VG];
310     static devfs_handle_t ch_devfs_handle[MAX_VG];
311     static devfs_handle_t lv_devfs_handle[MAX_LV];
312     
313     static pv_t *pvp = NULL;
314     static lv_t *lvp = NULL;
315     static pe_t *pep = NULL;
316     static pe_t *pep1 = NULL;
317     static char *basename = NULL;
318     
319     
320     /* map from block minor number to VG and LV numbers */
321     typedef struct {
322     	int vg_number;
323     	int lv_number;
324     } vg_lv_map_t;
325     static vg_lv_map_t vg_lv_map[ABS_MAX_LV];
326     
327     
328     /* Request structures (lvm_chr_ioctl()) */
329     static pv_change_req_t pv_change_req;
330     static pv_flush_req_t pv_flush_req;
331     static pv_status_req_t pv_status_req;
332     static pe_lock_req_t pe_lock_req;
333     static le_remap_req_t le_remap_req;
334     static lv_req_t lv_req;
335     
336     #ifdef LVM_TOTAL_RESET
337     static int lvm_reset_spindown = 0;
338     #endif
339     
340     static char pv_name[NAME_LEN];
341     /* static char rootvg[NAME_LEN] = { 0, }; */
342     const char *const lvm_name = LVM_NAME;
343     static int lock = 0;
344     static int loadtime = 0;
345     static uint vg_count = 0;
346     static long lvm_chr_open_count = 0;
347     static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
348     static DECLARE_WAIT_QUEUE_HEAD(lvm_wait);
349     static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait);
350     
351     static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED;
352     static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
353     
354     static struct proc_dir_entry *lvm_proc_dir = NULL;
355     static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;
356     struct proc_dir_entry *pde = NULL;
357     
358     static struct file_operations lvm_chr_fops =
359     {
360     	open:		lvm_chr_open,
361     	release:	lvm_chr_close,
362     	ioctl:		lvm_chr_ioctl,
363     };
364     
365     
366     /* block device operations structure needed for 2.3.38? and above */
367     static struct block_device_operations lvm_blk_dops =
368     {
369     	open: 		lvm_blk_open,
370     	release:	lvm_blk_close,
371     	ioctl:		lvm_blk_ioctl,
372     };
373     
374     
375     /* gendisk structures */
376     static struct hd_struct lvm_hd_struct[MAX_LV];
377     static int lvm_blocksizes[MAX_LV] =
378     {0,};
379     static int lvm_size[MAX_LV] =
380     {0,};
381     static struct gendisk lvm_gendisk =
382     {
383     	major:		MAJOR_NR,
384     	major_name:	LVM_NAME,
385     	minor_shift:	0,
386     	max_p:		1,
387     	part:		lvm_hd_struct,
388     	sizes:		lvm_size,
389     	nr_real:	MAX_LV,
390     };
391     
392     /*
393      * Driver initialization...
394      */
395     int lvm_init(void)
396     {
397     	if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) {
398     		printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name);
399     		return -EIO;
400     	}
401     	if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)
402     	{
403     		printk("%s -- register_blkdev failed\n", lvm_name);
404     		if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
405     			printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
406     		return -EIO;
407     	}
408     
409     	lvm_devfs_handle = devfs_register(
410     		0 , "lvm", 0, 0, LVM_CHAR_MAJOR,
411     		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
412     		&lvm_chr_fops, NULL);
413     
414     	lvm_proc_dir = create_proc_entry (LVM_DIR, S_IFDIR, &proc_root);
415     	if (lvm_proc_dir != NULL) {
416     		lvm_proc_vg_subdir = create_proc_entry (LVM_VG_SUBDIR, S_IFDIR, lvm_proc_dir);
417     		pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir);
418     		if ( pde != NULL) pde->read_proc = &lvm_proc_get_global_info;
419     	}
420     
421     	lvm_init_vars();
422     	lvm_geninit(&lvm_gendisk);
423     
424     	add_gendisk(&lvm_gendisk);
425     
426     #ifdef LVM_HD_NAME
427     	/* reference from drivers/block/genhd.c */
428     	lvm_hd_name_ptr = lvm_hd_name;
429     #endif
430     
431     	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
432     
433     
434     	/* optional read root VGDA */
435     /*
436        if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);
437     */
438     
439     	printk(KERN_INFO
440     	       "%s%s -- "
441     #ifdef MODULE
442     	       "Module"
443     #else
444     	       "Driver"
445     #endif
446     	       " successfully initialized\n",
447     	       lvm_version, lvm_name);
448     
449     	return 0;
450     } /* lvm_init() */
451     
452     
453     /*
454      * cleanup...
455      */
456     static void lvm_cleanup(void)
457     {
458     	devfs_unregister (lvm_devfs_handle);
459     
460     	if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) {
461     		printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
462     	}
463     	if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) {
464     		printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name);
465     	}
466     
467     
468     	del_gendisk(&lvm_gendisk);
469     
470     	blk_size[MAJOR_NR] = NULL;
471     	blksize_size[MAJOR_NR] = NULL;
472     	hardsect_size[MAJOR_NR] = NULL;
473     
474     	remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
475     	remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
476     	remove_proc_entry(LVM_DIR, &proc_root);
477     
478     #ifdef LVM_HD_NAME
479     	/* reference from linux/drivers/block/genhd.c */
480     	lvm_hd_name_ptr = NULL;
481     #endif
482     
483     	printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
484     
485     	return;
486     }	/* lvm_cleanup() */
487     
488     
489     /*
490      * support function to initialize lvm variables
491      */
492     void __init lvm_init_vars(void)
493     {
494     	int v;
495     
496     	loadtime = CURRENT_TIME;
497     
498     	lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
499     
500     	pe_lock_req.lock = UNLOCK_PE;
501     	pe_lock_req.data.lv_dev = 
502     	pe_lock_req.data.pv_dev = 
503     	pe_lock_req.data.pv_offset = 0;
504     
505     	/* Initialize VG pointers */
506     	for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL;
507     
508     	/* Initialize LV -> VG association */
509     	for (v = 0; v < ABS_MAX_LV; v++) {
510     		/* index ABS_MAX_VG never used for real VG */
511     		vg_lv_map[v].vg_number = ABS_MAX_VG;
512     		vg_lv_map[v].lv_number = -1;
513     	}
514     
515     	return;
516     } /* lvm_init_vars() */
517     
518     
519     /********************************************************************
520      *
521      * Character device functions
522      *
523      ********************************************************************/
524     
525     /*
526      * character device open routine
527      */
528     static int lvm_chr_open(struct inode *inode,
529     			struct file *file)
530     {
531     	int minor = MINOR(inode->i_rdev);
532     
533     #ifdef DEBUG
534     	printk(KERN_DEBUG
535     	 "%s -- lvm_chr_open MINOR: %d  VG#: %d  mode: 0x%X  lock: %d\n",
536     	       lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
537     #endif
538     
539     	/* super user validation */
540     	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
541     
542     	/* Group special file open */
543     	if (VG_CHR(minor) > MAX_VG) return -ENXIO;
544     
545     	lvm_chr_open_count++;
546     
547     	MOD_INC_USE_COUNT;
548     
549     	return 0;
550     } /* lvm_chr_open() */
551     
552     
553     /*
554      * character device i/o-control routine
555      *
556      * Only one changing process can do changing ioctl at one time,
557      * others will block.
558      *
559      */
560     static int lvm_chr_ioctl(struct inode *inode, struct file *file,
561     			 uint command, ulong a)
562     {
563     	int minor = MINOR(inode->i_rdev);
564     	uint extendable, l, v;
565     	void *arg = (void *) a;
566     	lv_t lv;
567     	vg_t* vg_ptr = vg[VG_CHR(minor)];
568     
569     	/* otherwise cc will complain about unused variables */
570     	(void) lvm_lock;
571     
572     	P_IOCTL("%s -- lvm_chr_ioctl: command: 0x%X  MINOR: %d  "
573     		"VG#: %d  mode: 0x%X\n",
574     		lvm_name, command, minor, VG_CHR(minor), file->f_mode);
575     
576     #ifdef LVM_TOTAL_RESET
577     	if (lvm_reset_spindown > 0) return -EACCES;
578     #endif
579     
580     	/* Main command switch */
581     	switch (command) {
582     	case LVM_LOCK_LVM:
583     		/* lock the LVM */
584     		return lvm_do_lock_lvm();
585     
586     	case LVM_GET_IOP_VERSION:
587     		/* check lvm version to ensure driver/tools+lib
588     		   interoperability */
589     		if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0)
590     			return -EFAULT;
591     		return 0;
592     
593     #ifdef LVM_TOTAL_RESET
594     	case LVM_RESET:
595     		/* lock reset function */
596     		lvm_reset_spindown = 1;
597     		for (v = 0; v < ABS_MAX_VG; v++) {
598     			if (vg[v] != NULL) lvm_do_vg_remove(v);
599     		}
600     
601     #ifdef MODULE
602     		while (GET_USE_COUNT(&__this_module) < 1)
603     			MOD_INC_USE_COUNT;
604     		while (GET_USE_COUNT(&__this_module) > 1)
605     			MOD_DEC_USE_COUNT;
606     #endif /* MODULE */
607     		lock = 0;	/* release lock */
608     		wake_up_interruptible(&lvm_wait);
609     		return 0;
610     #endif /* LVM_TOTAL_RESET */
611     
612     
613     	case LE_REMAP:
614     		/* remap a logical extent (after moving the physical extent) */
615     		return lvm_do_le_remap(vg_ptr,arg);
616     
617     	case PE_LOCK_UNLOCK:
618     		/* lock/unlock i/o to a physical extent to move it to another
619     		   physical volume (move's done in user space's pvmove) */
620     		return lvm_do_pe_lock_unlock(vg_ptr,arg);
621     
622     	case VG_CREATE:
623     		/* create a VGDA */
624     		return lvm_do_vg_create(minor, arg);
625     
626     	case VG_EXTEND:
627     		/* extend a volume group */
628     		return lvm_do_vg_extend(vg_ptr, arg);
629     
630     	case VG_REDUCE:
631     		/* reduce a volume group */
632     		return lvm_do_vg_reduce(vg_ptr, arg);
633     
634     	case VG_RENAME:
635     		/* rename a volume group */
636     		return lvm_do_vg_rename(vg_ptr, arg);
637     
638     	case VG_REMOVE:
639     		/* remove an inactive VGDA */
640     		return lvm_do_vg_remove(minor);
641     
642     
643     	case VG_SET_EXTENDABLE:
644     		/* set/clear extendability flag of volume group */
645     		if (vg_ptr == NULL) return -ENXIO;
646     		if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
647     			return -EFAULT;
648     
649     		if (extendable == VG_EXTENDABLE ||
650     		    extendable == ~VG_EXTENDABLE) {
651     			if (extendable == VG_EXTENDABLE)
652     				vg_ptr->vg_status |= VG_EXTENDABLE;
653     			else
654     				vg_ptr->vg_status &= ~VG_EXTENDABLE;
655     		} else return -EINVAL;
656     		return 0;
657     
658     
659     	case VG_STATUS:
660     		/* get volume group data (only the vg_t struct) */
661     		if (vg_ptr == NULL) return -ENXIO;
662     		if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
663     			return -EFAULT;
664     		return 0;
665     
666     
667     	case VG_STATUS_GET_COUNT:
668     		/* get volume group count */
669     		if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0)
670     			return -EFAULT;
671     		return 0;
672     
673     
674     	case VG_STATUS_GET_NAMELIST:
675     		/* get volume group count */
676     		for (l = v = 0; v < ABS_MAX_VG; v++) {
677     			if (vg[v] != NULL) {
678     				if (copy_to_user(arg + l * NAME_LEN,
679     						 vg[v]->vg_name,
680     						 NAME_LEN) != 0)
681     					return -EFAULT;
682     				l++;
683     			}
684     		}
685     		return 0;
686     
687     
688     	case LV_CREATE:
689     	case LV_EXTEND:
690     	case LV_REDUCE:
691     	case LV_REMOVE:
692     	case LV_RENAME:
693     		/* create, extend, reduce, remove or rename a logical volume */
694     		if (vg_ptr == NULL) return -ENXIO;
695     		if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
696     			return -EFAULT;
697     
698     		if (command != LV_REMOVE) {
699     			if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0)
700     				return -EFAULT;
701     		}
702     		switch (command) {
703     		case LV_CREATE:
704     			return lvm_do_lv_create(minor, lv_req.lv_name, &lv);
705     
706     		case LV_EXTEND:
707     		case LV_REDUCE:
708     			return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv);
709     		case LV_REMOVE:
710     			return lvm_do_lv_remove(minor, lv_req.lv_name, -1);
711     
712     		case LV_RENAME:
713     			return lvm_do_lv_rename(vg_ptr, &lv_req, &lv);
714     		}
715     
716     
717     
718     
719     	case LV_STATUS_BYNAME:
720     		/* get status of a logical volume by name */
721     		return lvm_do_lv_status_byname(vg_ptr, arg);
722     
723     
724     	case LV_STATUS_BYINDEX:
725     		/* get status of a logical volume by index */
726     		return lvm_do_lv_status_byindex(vg_ptr, arg);
727     
728     
729     	case LV_STATUS_BYDEV:
730     		return lvm_do_lv_status_bydev(vg_ptr, arg);
731     
732     
733     	case PV_CHANGE:
734     		/* change a physical volume */
735     		return lvm_do_pv_change(vg_ptr,arg);
736     
737     
738     	case PV_STATUS:
739     		/* get physical volume data (pv_t structure only) */
740     		return lvm_do_pv_status(vg_ptr,arg);
741     
742     
743     	case PV_FLUSH:
744     		/* physical volume buffer flush/invalidate */
745     		if (copy_from_user(&pv_flush_req, arg,
746     				   sizeof(pv_flush_req)) != 0)
747     			return -EFAULT;
748     
749     		fsync_dev(pv_flush_req.pv_dev);
750     		invalidate_buffers(pv_flush_req.pv_dev);
751     		return 0;
752     
753     
754     	default:
755     		printk(KERN_WARNING
756     		       "%s -- lvm_chr_ioctl: unknown command %x\n",
757     		       lvm_name, command);
758     		return -EINVAL;
759     	}
760     
761     	return 0;
762     } /* lvm_chr_ioctl */
763     
764     
765     /*
766      * character device close routine
767      */
768     static int lvm_chr_close(struct inode *inode, struct file *file)
769     {
770     #ifdef DEBUG
771     	int minor = MINOR(inode->i_rdev);
772     	printk(KERN_DEBUG
773     	     "%s -- lvm_chr_close   VG#: %d\n", lvm_name, VG_CHR(minor));
774     #endif
775     
776     #ifdef LVM_TOTAL_RESET
777     	if (lvm_reset_spindown > 0) {
778     		lvm_reset_spindown = 0;
779     		lvm_chr_open_count = 0;
780     	}
781     #endif
782     
783     	if (lvm_chr_open_count > 0) lvm_chr_open_count--;
784     	if (lock == current->pid) {
785     		lock = 0;	/* release lock */
786     		wake_up_interruptible(&lvm_wait);
787     	}
788     
789     	MOD_DEC_USE_COUNT;
790     
791     	return 0;
792     } /* lvm_chr_close() */
793     
794     
795     
796     /********************************************************************
797      *
798      * Block device functions
799      *
800      ********************************************************************/
801     
802     /*
803      * block device open routine
804      */
805     static int lvm_blk_open(struct inode *inode, struct file *file)
806     {
807     	int minor = MINOR(inode->i_rdev);
808     	lv_t *lv_ptr;
809     	vg_t *vg_ptr = vg[VG_BLK(minor)];
810     
811     #ifdef DEBUG_LVM_BLK_OPEN
812     	printk(KERN_DEBUG
813     	  "%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  mode: 0x%X\n",
814     	    lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);
815     #endif
816     
817     #ifdef LVM_TOTAL_RESET
818     	if (lvm_reset_spindown > 0)
819     		return -EPERM;
820     #endif
821     
822     	if (vg_ptr != NULL &&
823     	    (vg_ptr->vg_status & VG_ACTIVE) &&
824     	    (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL &&
825     	    LV_BLK(minor) >= 0 &&
826     	    LV_BLK(minor) < vg_ptr->lv_max) {
827     
828     		/* Check parallel LV spindown (LV remove) */
829     		if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;
830     
831     		/* Check inactive LV and open for read/write */
832     		if (!(lv_ptr->lv_status & LV_ACTIVE))
833     			return -EPERM;
834     		if (!(lv_ptr->lv_access & LV_WRITE) &&
835     		    (file->f_mode & FMODE_WRITE))
836     			return -EACCES;
837     
838     
839                     /* be sure to increment VG counter */
840     		if (lv_ptr->lv_open == 0) vg_ptr->lv_open++;
841     		lv_ptr->lv_open++;
842     
843     		MOD_INC_USE_COUNT;
844     
845     #ifdef DEBUG_LVM_BLK_OPEN
846     		printk(KERN_DEBUG
847     		       "%s -- lvm_blk_open MINOR: %d  VG#: %d  LV#: %d  size: %d\n",
848     		       lvm_name, minor, VG_BLK(minor), LV_BLK(minor),
849     		       lv_ptr->lv_size);
850     #endif
851     
852     		return 0;
853     	}
854     	return -ENXIO;
855     } /* lvm_blk_open() */
856     
857     
858     /*
859      * block device i/o-control routine
860      */
861     static int lvm_blk_ioctl(struct inode *inode, struct file *file,
862     			 uint command, ulong a)
863     {
864     	int minor = MINOR(inode->i_rdev);
865     	vg_t *vg_ptr = vg[VG_BLK(minor)];
866     	lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
867     	void *arg = (void *) a;
868     	struct hd_geometry *hd = (struct hd_geometry *) a;
869     
870     	P_IOCTL("%s -- lvm_blk_ioctl MINOR: %d  command: 0x%X  arg: %X  "
871     		"VG#: %dl  LV#: %d\n",
872     		lvm_name, minor, command, (ulong) arg,
873     		VG_BLK(minor), LV_BLK(minor));
874     
875     	switch (command) {
876     	case BLKGETSIZE:
877     		/* return device size */
878     		P_IOCTL("%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n",
879     			lvm_name, lv_ptr->lv_size);
880     		if (put_user(lv_ptr->lv_size, (long *)arg))
881     			return -EFAULT;
882     		break;
883     
884     	case BLKGETSIZE64:
885     		if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg))
886     			return -EFAULT;
887     		break;
888     
889     
890     	case BLKFLSBUF:
891     		/* flush buffer cache */
892     		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
893     
894     		P_IOCTL("%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name);
895     
896     		fsync_dev(inode->i_rdev);
897     		invalidate_buffers(inode->i_rdev);
898     		break;
899     
900     
901     	case BLKRASET:
902     		/* set read ahead for block device */
903     		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
904     
905     		P_IOCTL("%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n",
906     			lvm_name, (long) arg, MAJOR(inode->i_rdev), minor);
907     
908     		if ((long) arg < LVM_MIN_READ_AHEAD ||
909     		    (long) arg > LVM_MAX_READ_AHEAD)
910     			return -EINVAL;
911     		lv_ptr->lv_read_ahead = (long) arg;
912     		read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead;
913     		break;
914     
915     
916     	case BLKRAGET:
917     		/* get current read ahead setting */
918     		P_IOCTL("%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
919     		if (put_user(lv_ptr->lv_read_ahead, (long *)arg))
920     			return -EFAULT;
921     		break;
922     
923     
924     	case HDIO_GETGEO:
925     		/* get disk geometry */
926     		P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
927     		if (hd == NULL)
928     			return -EINVAL;
929     		{
930     			unsigned char heads = 64;
931     			unsigned char sectors = 32;
932     			long start = 0;
933     			short cylinders = lv_ptr->lv_size / heads / sectors;
934     
935     			if (copy_to_user((char *) &hd->heads, &heads,
936     					 sizeof(heads)) != 0 ||
937     			    copy_to_user((char *) &hd->sectors, &sectors,
938     					 sizeof(sectors)) != 0 ||
939     			    copy_to_user((short *) &hd->cylinders,
940     				   &cylinders, sizeof(cylinders)) != 0 ||
941     			    copy_to_user((long *) &hd->start, &start,
942     					 sizeof(start)) != 0)
943     				return -EFAULT;
944     		}
945     
946     		P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n",
947     			lvm_name, lv_ptr->lv_size / heads / sectors);
948     		break;
949     
950     
951     	case LV_SET_ACCESS:
952     		/* set access flags of a logical volume */
953     		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
954     		lv_ptr->lv_access = (ulong) arg;
955     		if ( lv_ptr->lv_access & LV_WRITE)
956     			set_device_ro(lv_ptr->lv_dev, 0);
957     		else
958     			set_device_ro(lv_ptr->lv_dev, 1);
959     		break;
960     
961     
962     	case LV_SET_STATUS:
963     		/* set status flags of a logical volume */
964     		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
965     		if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
966     			return -EPERM;
967     		lv_ptr->lv_status = (ulong) arg;
968     		break;
969     
970     	case LV_BMAP:
971     		/* turn logical block into (dev_t, block). non privileged. */
972     		/* don't bmap a snapshot, since the mapping can change */
973     		if (lv_ptr->lv_access & LV_SNAPSHOT)
974     			return -EPERM;
975     
976     		return lvm_user_bmap(inode, (struct lv_bmap *) arg);
977     		break;
978     
979     	case LV_SET_ALLOCATION:
980     		/* set allocation flags of a logical volume */
981     		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
982     		lv_ptr->lv_allocation = (ulong) arg;
983     		break;
984     
985     	case LV_SNAPSHOT_USE_RATE:
986     		if (!(lv_ptr->lv_access & LV_SNAPSHOT)) return -EPERM;
987     		{
988     			lv_snapshot_use_rate_req_t	lv_snapshot_use_rate_req;
989     
990     			if (copy_from_user(&lv_snapshot_use_rate_req, arg,
991     					   sizeof(lv_snapshot_use_rate_req_t)))
992     				return -EFAULT;
993     			if (lv_snapshot_use_rate_req.rate < 0 ||
994     			    lv_snapshot_use_rate_req.rate  > 100) return -EFAULT;
995     
996     			switch (lv_snapshot_use_rate_req.block)
997     			{
998     			case 0:
999     				lv_ptr->lv_snapshot_use_rate = lv_snapshot_use_rate_req.rate;
1000     				if (lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end < lv_ptr->lv_snapshot_use_rate)
1001     					interruptible_sleep_on (&lv_ptr->lv_snapshot_wait);
1002     				break;
1003     
1004     			case O_NONBLOCK:
1005     				break;
1006     
1007     			default:
1008     				return -EFAULT;
1009     			}
1010     			lv_snapshot_use_rate_req.rate = lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end;
1011     			if (copy_to_user(arg, &lv_snapshot_use_rate_req,
1012     					 sizeof(lv_snapshot_use_rate_req_t)))
1013     				return -EFAULT;
1014     		}
1015     		break;
1016     
1017     	default:
1018     		printk(KERN_WARNING
1019     		       "%s -- lvm_blk_ioctl: unknown command %d\n",
1020     		       lvm_name, command);
1021     		return -EINVAL;
1022     	}
1023     
1024     	return 0;
1025     } /* lvm_blk_ioctl() */
1026     
1027     
1028     /*
1029      * block device close routine
1030      */
1031     static int lvm_blk_close(struct inode *inode, struct file *file)
1032     {
1033     	int minor = MINOR(inode->i_rdev);
1034     	vg_t *vg_ptr = vg[VG_BLK(minor)];
1035     	lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
1036     
1037     #ifdef DEBUG
1038     	printk(KERN_DEBUG
1039     	       "%s -- lvm_blk_close MINOR: %d  VG#: %d  LV#: %d\n",
1040     	       lvm_name, minor, VG_BLK(minor), LV_BLK(minor));
1041     #endif
1042     
1043     	if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
1044     	lv_ptr->lv_open--;
1045     
1046     	MOD_DEC_USE_COUNT;
1047     
1048     	return 0;
1049     } /* lvm_blk_close() */
1050     
1051     
1052     static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result)
1053     {
1054     	struct buffer_head bh;
1055     	unsigned long block;
1056     	int err;
1057     
1058     	if (get_user(block, &user_result->lv_block))
1059     		return -EFAULT;
1060     
1061     	memset(&bh,0,sizeof bh);
1062     	bh.b_blocknr = block;
1063     	bh.b_dev = bh.b_rdev = inode->i_rdev;
1064     	bh.b_size = lvm_get_blksize(bh.b_dev);
1065     	if ((err=lvm_map(&bh, READ)) < 0)  {
1066     		printk("lvm map failed: %d\n", err);
1067     		return -EINVAL;
1068     	}
1069     
1070     	return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) ||
1071     	       put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block) ?
1072     	       -EFAULT : 0;
1073     }
1074     
1075     
1076     /*
1077      * provide VG info for proc filesystem use (global)
1078      */
1079     int lvm_vg_info(vg_t *vg_ptr, char *buf) {
1080     	int sz = 0;
1081     	char inactive_flag = ' ';
1082     
1083     	if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
1084     	sz = sprintf(buf,
1085     		     "\nVG: %c%s  [%d PV, %d LV/%d open] "
1086     		     " PE Size: %d KB\n"
1087     		     "  Usage [KB/PE]: %d /%d total  "
1088     		     "%d /%d used  %d /%d free",
1089     		     inactive_flag,
1090     		     vg_ptr->vg_name,
1091     		     vg_ptr->pv_cur,
1092     		     vg_ptr->lv_cur,
1093     		     vg_ptr->lv_open,
1094     	     	     vg_ptr->pe_size >> 1,
1095     		     vg_ptr->pe_size * vg_ptr->pe_total >> 1,
1096     		     vg_ptr->pe_total,
1097     		     vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
1098     	     	     vg_ptr->pe_allocated,
1099     		     (vg_ptr->pe_total - vg_ptr->pe_allocated) *
1100     	     	     vg_ptr->pe_size >> 1,
1101     		     vg_ptr->pe_total - vg_ptr->pe_allocated);
1102     	return sz;
1103     }
1104     
1105     
1106     /*
1107      * provide LV info for proc filesystem use (global)
1108      */
1109     int lvm_lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) {
1110     	int sz = 0;
1111     	char inactive_flag = 'A', allocation_flag = ' ',
1112     	     stripes_flag = ' ', rw_flag = ' ';
1113     
1114     	if (!(lv_ptr->lv_status & LV_ACTIVE))
1115     		inactive_flag = 'I';
1116     	rw_flag = 'R';
1117     	if (lv_ptr->lv_access & LV_WRITE)
1118     		rw_flag = 'W';
1119     	allocation_flag = 'D';
1120     	if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
1121     		allocation_flag = 'C';
1122     	stripes_flag = 'L';
1123     	if (lv_ptr->lv_stripes > 1)
1124     		stripes_flag = 'S';
1125     	sz += sprintf(buf+sz,
1126     		      "[%c%c%c%c",
1127     		      inactive_flag,
1128     	 rw_flag,
1129     		      allocation_flag,
1130     		      stripes_flag);
1131     	if (lv_ptr->lv_stripes > 1)
1132     		sz += sprintf(buf+sz, "%-2d",
1133     			      lv_ptr->lv_stripes);
1134     	else
1135     		sz += sprintf(buf+sz, "  ");
1136     	basename = strrchr(lv_ptr->lv_name, '/');
1137     	if ( basename == 0) basename = lv_ptr->lv_name;
1138     	else                basename++;
1139     	sz += sprintf(buf+sz, "] %-25s", basename);
1140     	if (strlen(basename) > 25)
1141     		sz += sprintf(buf+sz,
1142     			      "\n                              ");
1143     	sz += sprintf(buf+sz, "%9d /%-6d   ",
1144     		      lv_ptr->lv_size >> 1,
1145     		      lv_ptr->lv_size / vg_ptr->pe_size);
1146     
1147     	if (lv_ptr->lv_open == 0)
1148     		sz += sprintf(buf+sz, "close");
1149     	else
1150     		sz += sprintf(buf+sz, "%dx open",
1151     			      lv_ptr->lv_open);
1152     
1153     	return sz;
1154     }
1155     
1156     
1157     /*
1158      * provide PV info for proc filesystem use (global)
1159      */
1160     int lvm_pv_info(pv_t *pv_ptr, char *buf) {
1161     	int sz = 0;
1162     	char inactive_flag = 'A', allocation_flag = ' ';
1163     	char *pv_name = NULL;
1164     
1165     	if (!(pv_ptr->pv_status & PV_ACTIVE))
1166     		inactive_flag = 'I';
1167     	allocation_flag = 'A';
1168     	if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE))
1169     		allocation_flag = 'N';
1170     	pv_name = strrchr(pv_ptr->pv_name+1,'/');
1171     	if ( pv_name == 0) pv_name = pv_ptr->pv_name;
1172     	else               pv_name++;
1173     	sz = sprintf(buf,
1174     		     "[%c%c] %-21s %8d /%-6d  "
1175     		     "%8d /%-6d  %8d /%-6d",
1176     		     inactive_flag,
1177     		     allocation_flag,
1178     		     pv_name,
1179     		     pv_ptr->pe_total *
1180     		     pv_ptr->pe_size >> 1,
1181     		     pv_ptr->pe_total,
1182     		     pv_ptr->pe_allocated *
1183     		     pv_ptr->pe_size >> 1,
1184     		     pv_ptr->pe_allocated,
1185     		     (pv_ptr->pe_total -
1186     		      pv_ptr->pe_allocated) *
1187     		     pv_ptr->pe_size >> 1,
1188     		     pv_ptr->pe_total -
1189     		     pv_ptr->pe_allocated);
1190     	return sz;
1191     }
1192     
1193     
1194     /*
1195      * Support functions /proc-Filesystem
1196      */
1197     
1198     #define  LVM_PROC_BUF   ( i == 0 ? dummy_buf : &buf[sz])
1199     
1200     /*
1201      * provide global LVM information
1202      */
1203     static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int count, int *eof, void *data)
1204     {
1205     	int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
1206     	 lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds;
1207     	static off_t sz;
1208     	off_t sz_last;
1209     	static char *buf = NULL;
1210     	static char dummy_buf[160];	/* sized for 2 lines */
1211     	vg_t *vg_ptr;
1212     	lv_t *lv_ptr;
1213     	pv_t *pv_ptr;
1214     
1215     
1216     #ifdef DEBUG_LVM_PROC_GET_INFO
1217     	printk(KERN_DEBUG
1218     	       "%s - lvm_proc_get_global_info CALLED  pos: %lu  count: %d  whence: %d\n",
1219     	       lvm_name, pos, count, whence);
1220     #endif
1221     
1222     	MOD_INC_USE_COUNT;
1223     
1224     	if (pos == 0 || buf == NULL) {
1225     		sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = 
1226     		lv_open_total = pe_t_bytes = hash_table_bytes = 
1227     		lv_block_exception_t_bytes = 0;
1228     
1229     		/* search for activity */
1230     		for (v = 0; v < ABS_MAX_VG; v++) {
1231     			if ((vg_ptr = vg[v]) != NULL) {
1232     				vg_counter++;
1233     				pv_counter += vg_ptr->pv_cur;
1234     				lv_counter += vg_ptr->lv_cur;
1235     				if (vg_ptr->lv_cur > 0) {
1236     					for (l = 0; l < vg[v]->lv_max; l++) {
1237     						if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
1238     							pe_t_bytes += lv_ptr->lv_allocated_le;
1239     							hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size;
1240     							if (lv_ptr->lv_block_exception != NULL)
1241     								lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
1242     							if (lv_ptr->lv_open > 0) {
1243     								lv_open_counter++;
1244     								lv_open_total += lv_ptr->lv_open;
1245     							}
1246     						}
1247     					}
1248     				}
1249     			}
1250     		}
1251     		pe_t_bytes *= sizeof(pe_t);
1252     		lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
1253     
1254     		if (buf != NULL) {
1255     			P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__);
1256     			lock_kernel();
1257     			vfree(buf);
1258     			unlock_kernel();
1259     			buf = NULL;
1260     		}
1261     		/* 2 times: first to get size to allocate buffer,
1262     		   2nd to fill the malloced buffer */
1263     		for (i = 0; i < 2; i++) {
1264     			sz = 0;
1265     			sz += sprintf(LVM_PROC_BUF,
1266     				      "LVM "
1267     #ifdef MODULE
1268     				      "module"
1269     #else
1270     				      "driver"
1271     #endif
1272     				      " %s\n\n"
1273     				    "Total:  %d VG%s  %d PV%s  %d LV%s ",
1274     				      lvm_short_version,
1275     				  vg_counter, vg_counter == 1 ? "" : "s",
1276     				  pv_counter, pv_counter == 1 ? "" : "s",
1277     				 lv_counter, lv_counter == 1 ? "" : "s");
1278     			sz += sprintf(LVM_PROC_BUF,
1279     				      "(%d LV%s open",
1280     				      lv_open_counter,
1281     				      lv_open_counter == 1 ? "" : "s");
1282     			if (lv_open_total > 0)
1283     				sz += sprintf(LVM_PROC_BUF,
1284     					      " %d times)\n",
1285     					      lv_open_total);
1286     			else
1287     				sz += sprintf(LVM_PROC_BUF, ")");
1288     			sz += sprintf(LVM_PROC_BUF,
1289     				      "\nGlobal: %lu bytes malloced   IOP version: %d   ",
1290     				      vg_counter * sizeof(vg_t) +
1291     				      pv_counter * sizeof(pv_t) +
1292     				      lv_counter * sizeof(lv_t) +
1293     				      pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last,
1294     				      lvm_iop_version);
1295     
1296     			seconds = CURRENT_TIME - loadtime;
1297     			if (seconds < 0)
1298     				loadtime = CURRENT_TIME + seconds;
1299     			if (seconds / 86400 > 0) {
1300     				sz += sprintf(LVM_PROC_BUF, "%d day%s ",
1301     					      seconds / 86400,
1302     					      seconds / 86400 == 0 ||
1303     					 seconds / 86400 > 1 ? "s" : "");
1304     			}
1305     			sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
1306     				      (seconds % 86400) / 3600,
1307     				      (seconds % 3600) / 60,
1308     				      seconds % 60);
1309     
1310     			if (vg_counter > 0) {
1311     				for (v = 0; v < ABS_MAX_VG; v++) {
1312     					/* volume group */
1313     					if ((vg_ptr = vg[v]) != NULL) {
1314     						sz += lvm_vg_info(vg_ptr, LVM_PROC_BUF);
1315     
1316     						/* physical volumes */
1317     						sz += sprintf(LVM_PROC_BUF,
1318     							      "\n  PV%s ",
1319     							      vg_ptr->pv_cur == 1 ? ": " : "s:");
1320     						c = 0;
1321     						for (p = 0; p < vg_ptr->pv_max; p++) {
1322     							if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
1323     								sz += lvm_pv_info(pv_ptr, LVM_PROC_BUF);
1324     
1325     								c++;
1326     								if (c < vg_ptr->pv_cur)
1327     									sz += sprintf(LVM_PROC_BUF,
1328     										      "\n       ");
1329     							}
1330     						}
1331     
1332     						/* logical volumes */
1333     						sz += sprintf(LVM_PROC_BUF,
1334     							   "\n    LV%s ",
1335     							      vg_ptr->lv_cur == 1 ? ": " : "s:");
1336     						c = 0;
1337     						for (l = 0; l < vg_ptr->lv_max; l++) {
1338     							if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
1339     								sz += lvm_lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF);
1340     								c++;
1341     								if (c < vg_ptr->lv_cur)
1342     									sz += sprintf(LVM_PROC_BUF,
1343     										      "\n         ");
1344     							}
1345     						}
1346     						if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
1347     						sz += sprintf(LVM_PROC_BUF, "\n");
1348     					}
1349     				}
1350     			}
1351     			if (buf == NULL) {
1352     				lock_kernel();
1353     				buf = vmalloc(sz);
1354     				unlock_kernel();
1355     				if (buf == NULL) {
1356     					sz = 0;
1357     					MOD_DEC_USE_COUNT;
1358     					return sprintf(page, "%s - vmalloc error at line %d\n",
1359     						     lvm_name, __LINE__);
1360     				}
1361     			}
1362     			sz_last = sz;
1363     		}
1364     	}
1365     	MOD_DEC_USE_COUNT;
1366     	if (pos > sz - 1) {
1367     		lock_kernel();
1368     		vfree(buf);
1369     		unlock_kernel();
1370     		buf = NULL;
1371     		return 0;
1372     	}
1373     	*start = &buf[pos];
1374     	if (sz - pos < count)
1375     		return sz - pos;
1376     	else
1377     		return count;
1378     } /* lvm_proc_get_global_info() */
1379     
1380     
1381     /*
1382      * provide VG information
1383      */
1384     int lvm_proc_read_vg_info(char *page, char **start, off_t off,
1385     			  int count, int *eof, void *data) {
1386     	int sz = 0;
1387     	vg_t *vg = data;
1388     
1389     	sz += sprintf ( page+sz, "name:         %s\n", vg->vg_name);
1390     	sz += sprintf ( page+sz, "size:         %u\n",
1391     		        vg->pe_total * vg->pe_size / 2);
1392     	sz += sprintf ( page+sz, "access:       %u\n", vg->vg_access);
1393     	sz += sprintf ( page+sz, "status:       %u\n", vg->vg_status);
1394     	sz += sprintf ( page+sz, "number:       %u\n", vg->vg_number);
1395     	sz += sprintf ( page+sz, "LV max:       %u\n", vg->lv_max);
1396     	sz += sprintf ( page+sz, "LV current:   %u\n", vg->lv_cur);
1397     	sz += sprintf ( page+sz, "LV open:      %u\n", vg->lv_open);
1398     	sz += sprintf ( page+sz, "PV max:       %u\n", vg->pv_max);
1399     	sz += sprintf ( page+sz, "PV current:   %u\n", vg->pv_cur);
1400     	sz += sprintf ( page+sz, "PV active:    %u\n", vg->pv_act);
1401     	sz += sprintf ( page+sz, "PE size:      %u\n", vg->pe_size / 2);
1402     	sz += sprintf ( page+sz, "PE total:     %u\n", vg->pe_total);
1403     	sz += sprintf ( page+sz, "PE allocated: %u\n", vg->pe_allocated);
1404     	sz += sprintf ( page+sz, "uuid:         %s\n", lvm_show_uuid(vg->vg_uuid));
1405     
1406     	return sz;
1407     }
1408     
1409     
1410     /*
1411      * provide LV information
1412      */
1413     int lvm_proc_read_lv_info(char *page, char **start, off_t off,
1414     			  int count, int *eof, void *data) {
1415     	int sz = 0;
1416     	lv_t *lv = data;
1417     
1418     	sz += sprintf ( page+sz, "name:         %s\n", lv->lv_name);
1419     	sz += sprintf ( page+sz, "size:         %u\n", lv->lv_size);
1420     	sz += sprintf ( page+sz, "access:       %u\n", lv->lv_access);
1421     	sz += sprintf ( page+sz, "status:       %u\n", lv->lv_status);
1422     	sz += sprintf ( page+sz, "number:       %u\n", lv->lv_number);
1423     	sz += sprintf ( page+sz, "open:         %u\n", lv->lv_open);
1424     	sz += sprintf ( page+sz, "allocation:   %u\n", lv->lv_allocation);
1425     	sz += sprintf ( page+sz, "device:       %02u:%02u\n",
1426                             MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
1427     
1428     	return sz;
1429     }
1430     
1431     
1432     /*
1433      * provide PV information
1434      */
1435     int lvm_proc_read_pv_info(char *page, char **start, off_t off,
1436     			  int count, int *eof, void *data) {
1437     	int sz = 0;
1438     	pv_t *pv = data;
1439     
1440     	sz += sprintf ( page+sz, "name:         %s\n", pv->pv_name);
1441     	sz += sprintf ( page+sz, "size:         %u\n", pv->pv_size);
1442     	sz += sprintf ( page+sz, "status:       %u\n", pv->pv_status);
1443     	sz += sprintf ( page+sz, "number:       %u\n", pv->pv_number);
1444     	sz += sprintf ( page+sz, "allocatable:  %u\n", pv->pv_allocatable);
1445     	sz += sprintf ( page+sz, "LV current:   %u\n", pv->lv_cur);
1446     	sz += sprintf ( page+sz, "PE size:      %u\n", pv->pe_size / 2);
1447     	sz += sprintf ( page+sz, "PE total:     %u\n", pv->pe_total);
1448     	sz += sprintf ( page+sz, "PE allocated: %u\n", pv->pe_allocated);
1449     	sz += sprintf ( page+sz, "device:       %02u:%02u\n",
1450                             MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
1451     	sz += sprintf ( page+sz, "uuid:         %s\n", lvm_show_uuid(pv->pv_uuid));
1452     
1453     
1454     	return sz;
1455     }
1456     
1457     
1458     /*
1459      * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c
1460      * (see init_module/lvm_init)
1461      */
1462     static int lvm_map(struct buffer_head *bh, int rw)
1463     {
1464     	int minor = MINOR(bh->b_rdev);
1465     	int ret = 0;
1466     	ulong index;
1467     	ulong pe_start;
1468     	ulong size = bh->b_size >> 9;
1469     	ulong rsector_tmp = bh->b_rsector;
1470     	ulong rsector_sav;
1471     	kdev_t rdev_tmp = bh->b_rdev;
1472     	kdev_t rdev_sav;
1473     	vg_t *vg_this = vg[VG_BLK(minor)];
1474     	lv_t *lv = vg_this->lv[LV_BLK(minor)];
1475     
1476     
1477     	if (!(lv->lv_status & LV_ACTIVE)) {
1478     		printk(KERN_ALERT
1479     		       "%s - lvm_map: ll_rw_blk for inactive LV %s\n",
1480     		       lvm_name, lv->lv_name);
1481     		return -1;
1482     	}
1483     
1484     	if ((rw == WRITE || rw == WRITEA) &&
1485     	    !(lv->lv_access & LV_WRITE)) {
1486     		printk(KERN_CRIT
1487     		    "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
1488     		       lvm_name, lv->lv_name);
1489     		return -1;
1490     	}
1491     
1492     	P_MAP("%s - lvm_map minor:%d  *rdev: %02d:%02d  *rsector: %lu  "
1493     	      "size:%lu\n",
1494     	      lvm_name, minor,
1495     	      MAJOR(rdev_tmp),
1496     	      MINOR(rdev_tmp),
1497     	      rsector_tmp, size);
1498     
1499     	if (rsector_tmp + size > lv->lv_size) {
1500     		printk(KERN_ALERT
1501     		       "%s - lvm_map access beyond end of device; *rsector: "
1502                            "%lu or size: %lu wrong for minor: %2d\n",
1503                            lvm_name, rsector_tmp, size, minor);
1504     		return -1;
1505     	}
1506     	rsector_sav = rsector_tmp;
1507     	rdev_sav = rdev_tmp;
1508     
1509     lvm_second_remap:
1510     	/* linear mapping */
1511     	if (lv->lv_stripes < 2) {
1512     		/* get the index */
1513     		index = rsector_tmp / vg_this->pe_size;
1514     		pe_start = lv->lv_current_pe[index].pe;
1515     		rsector_tmp = lv->lv_current_pe[index].pe +
1516     		    (rsector_tmp % vg_this->pe_size);
1517     		rdev_tmp = lv->lv_current_pe[index].dev;
1518     
1519     		P_MAP("lv_current_pe[%ld].pe: %ld  rdev: %02d:%02d  "
1520     		      "rsector:%ld\n",
1521     		       index,
1522     		       lv->lv_current_pe[index].pe,
1523     		       MAJOR(rdev_tmp),
1524     		       MINOR(rdev_tmp),
1525     		       rsector_tmp);
1526     
1527     		/* striped mapping */
1528     	} else {
1529     		ulong stripe_index;
1530     		ulong stripe_length;
1531     
1532     		stripe_length = vg_this->pe_size * lv->lv_stripes;
1533     		stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize;
1534     		index = rsector_tmp / stripe_length +
1535     		    (stripe_index % lv->lv_stripes) *
1536     		    (lv->lv_allocated_le / lv->lv_stripes);
1537     		pe_start = lv->lv_current_pe[index].pe;
1538     		rsector_tmp = lv->lv_current_pe[index].pe +
1539     		    (rsector_tmp % stripe_length) -
1540     		    (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
1541     		    stripe_index / lv->lv_stripes *
1542     		    (lv->lv_stripes - 1) * lv->lv_stripesize;
1543     		rdev_tmp = lv->lv_current_pe[index].dev;
1544     	}
1545     
1546     	P_MAP("lv_current_pe[%ld].pe: %ld  rdev: %02d:%02d  rsector:%ld\n"
1547     	       "stripe_length: %ld  stripe_index: %ld\n",
1548     	       index,
1549     	       lv->lv_current_pe[index].pe,
1550     	       MAJOR(rdev_tmp),
1551     	       MINOR(rdev_tmp),
1552     	       rsector_tmp,
1553     	       stripe_length,
1554     	       stripe_index);
1555     
1556     	/* handle physical extents on the move */
1557     	if (pe_lock_req.lock == LOCK_PE) {
1558     		if (rdev_tmp == pe_lock_req.data.pv_dev &&
1559     		    rsector_tmp >= pe_lock_req.data.pv_offset &&
1560     		    rsector_tmp < (pe_lock_req.data.pv_offset +
1561     				   vg_this->pe_size)) {
1562     			sleep_on(&lvm_map_wait);
1563     			rsector_tmp = rsector_sav;
1564     			rdev_tmp = rdev_sav;
1565     			goto lvm_second_remap;
1566     		}
1567     	}
1568     	/* statistic */
1569     	if (rw == WRITE || rw == WRITEA)
1570     		lv->lv_current_pe[index].writes++;
1571     	else
1572     		lv->lv_current_pe[index].reads++;
1573     
1574     	/* snapshot volume exception handling on physical device address base */
1575     	if (lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)) {
1576     		/* original logical volume */
1577     		if (lv->lv_access & LV_SNAPSHOT_ORG) {
1578     			/* Serializes the access to the lv_snapshot_next list */
1579     			down(&lv->lv_snapshot_sem);
1580     			if (rw == WRITE || rw == WRITEA)
1581     			{
1582     				lv_t *lv_ptr;
1583     
1584     				/* start with first snapshot and loop thrugh all of them */
1585     				for (lv_ptr = lv->lv_snapshot_next;
1586     				     lv_ptr != NULL;
1587     				     lv_ptr = lv_ptr->lv_snapshot_next) {
1588     					/* Check for inactive snapshot */
1589     					if (!(lv_ptr->lv_status & LV_ACTIVE)) continue;
1590     					/* Serializes the COW with the accesses to the snapshot device */
1591     					down(&lv_ptr->lv_snapshot_sem);
1592     					/* do we still have exception storage for this snapshot free? */
1593     					if (lv_ptr->lv_block_exception != NULL) {
1594     						rdev_sav = rdev_tmp;
1595     						rsector_sav = rsector_tmp;
1596     						if (!lvm_snapshot_remap_block(&rdev_tmp,
1597     									      &rsector_tmp,
1598     									      pe_start,
1599     									      lv_ptr)) {
1600     							/* create a new mapping */
1601     							if (!(ret = lvm_snapshot_COW(rdev_tmp,
1602     									       	     rsector_tmp,
1603     									             pe_start,
1604     									             rsector_sav,
1605     									             lv_ptr)))
1606     								ret = lvm_write_COW_table_block(vg_this,
1607     												lv_ptr);
1608     						}
1609     						rdev_tmp = rdev_sav;
1610     						rsector_tmp = rsector_sav;
1611     					}
1612     					up(&lv_ptr->lv_snapshot_sem);
1613     				}
1614     			}
1615     			up(&lv->lv_snapshot_sem);
1616     		} else {
1617     			/* remap snapshot logical volume */
1618     			down(&lv->lv_snapshot_sem);
1619     			if (lv->lv_block_exception != NULL)
1620     				lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv);
1621     			up(&lv->lv_snapshot_sem);
1622     		}
1623     	}
1624     	bh->b_rdev = rdev_tmp;
1625     	bh->b_rsector = rsector_tmp;
1626     
1627     	return ret;
1628     } /* lvm_map() */
1629     
1630     
1631     /*
1632      * internal support functions
1633      */
1634     
1635     #ifdef LVM_HD_NAME
1636     /*
1637      * generate "hard disk" name
1638      */
1639     void lvm_hd_name(char *buf, int minor)
1640     {
1641     	int len = 0;
1642     	lv_t *lv_ptr;
1643     
1644     	if (vg[VG_BLK(minor)] == NULL ||
1645     	    (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL)
1646     		return;
1647     	len = strlen(lv_ptr->lv_name) - 5;
1648     	memcpy(buf, &lv_ptr->lv_name[5], len);
1649     	buf[len] = 0;
1650     	return;
1651     }
1652     #endif
1653     
1654     
1655     /*
1656      * make request function
1657      */
1658     static int lvm_make_request_fn(request_queue_t *q,
1659     			       int rw,
1660     			       struct buffer_head *bh)
1661     {
1662     	if (lvm_map(bh, rw) >= 0)
1663     		return 1;
1664     
1665     	buffer_IO_error(bh);
1666     	return 0;
1667     }
1668     
1669     
1670     /********************************************************************
1671      *
1672      * Character device support functions
1673      *
1674      ********************************************************************/
1675     /*
1676      * character device support function logical volume manager lock
1677      */
1678     static int lvm_do_lock_lvm(void)
1679     {
1680     lock_try_again:
1681     	spin_lock(&lvm_lock);
1682     	if (lock != 0 && lock != current->pid) {
1683     		P_IOCTL("lvm_do_lock_lvm: %s is locked by pid %d ...\n",
1684     			lvm_name, lock);
1685     		spin_unlock(&lvm_lock);
1686     		interruptible_sleep_on(&lvm_wait);
1687     		if (current->sigpending != 0)
1688     			return -EINTR;
1689     #ifdef LVM_TOTAL_RESET
1690     		if (lvm_reset_spindown > 0)
1691     			return -EACCES;
1692     #endif
1693     		goto lock_try_again;
1694     	}
1695     	lock = current->pid;
1696     	spin_unlock(&lvm_lock);
1697     	return 0;
1698     } /* lvm_do_lock_lvm */
1699     
1700     
1701     /*
1702      * character device support function lock/unlock physical extend
1703      */
1704     static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
1705     {
1706     	uint p;
1707     
1708     	if (vg_ptr == NULL) return -ENXIO;
1709     	if (copy_from_user(&pe_lock_req, arg,
1710     			   sizeof(pe_lock_req_t)) != 0) return -EFAULT;
1711     
1712     	switch (pe_lock_req.lock) {
1713     	case LOCK_PE:
1714     		for (p = 0; p < vg_ptr->pv_max; p++) {
1715     			if (vg_ptr->pv[p] != NULL &&
1716     			    pe_lock_req.data.pv_dev ==
1717     			    vg_ptr->pv[p]->pv_dev)
1718     				break;
1719     		}
1720     		if (p == vg_ptr->pv_max) return -ENXIO;
1721     
1722     		pe_lock_req.lock = UNLOCK_PE;
1723     		fsync_dev(pe_lock_req.data.lv_dev);
1724     		pe_lock_req.lock = LOCK_PE;
1725     		break;
1726     
1727     	case UNLOCK_PE:
1728     		pe_lock_req.lock = UNLOCK_PE;
1729     		pe_lock_req.data.lv_dev = 
1730     		pe_lock_req.data.pv_dev = 
1731     		pe_lock_req.data.pv_offset = 0;
1732     		wake_up(&lvm_map_wait);
1733     		break;
1734     
1735     	default:
1736     		return -EINVAL;
1737     	}
1738     	return 0;
1739     }
1740     
1741     
1742     /*
1743      * character device support function logical extend remap
1744      */
1745     static int lvm_do_le_remap(vg_t *vg_ptr, void *arg)
1746     {
1747     	uint l, le;
1748     	lv_t *lv_ptr;
1749     
1750     	if (vg_ptr == NULL) return -ENXIO;
1751     	if (copy_from_user(&le_remap_req, arg,
1752     			   sizeof(le_remap_req_t)) != 0)
1753     		return -EFAULT;
1754     
1755     	for (l = 0; l < vg_ptr->lv_max; l++) {
1756     		lv_ptr = vg_ptr->lv[l];
1757     		if (lv_ptr != NULL &&
1758     		    strcmp(lv_ptr->lv_name,
1759     			       le_remap_req.lv_name) == 0) {
1760     			for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
1761     				if (lv_ptr->lv_current_pe[le].dev ==
1762     				    le_remap_req.old_dev &&
1763     				    lv_ptr->lv_current_pe[le].pe ==
1764     				    le_remap_req.old_pe) {
1765     					lv_ptr->lv_current_pe[le].dev =
1766     					    le_remap_req.new_dev;
1767     					lv_ptr->lv_current_pe[le].pe =
1768     					    le_remap_req.new_pe;
1769     					return 0;
1770     				}
1771     			}
1772     			return -EINVAL;
1773     		}
1774     	}
1775     	return -ENXIO;
1776     } /* lvm_do_le_remap() */
1777     
1778     
1779     /*
1780      * character device support function VGDA create
1781      */
1782     int lvm_do_vg_create(int minor, void *arg)
1783     {
1784     	int ret = 0;
1785     	ulong l, ls = 0, p, size;
1786     	lv_t lv;
1787     	vg_t *vg_ptr;
1788     	lv_t **snap_lv_ptr;
1789     
1790     	if (vg[VG_CHR(minor)] != NULL) return -EPERM;
1791     
1792     	if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
1793     		printk(KERN_CRIT
1794     		       "%s -- VG_CREATE: kmalloc error VG at line %d\n",
1795     		       lvm_name, __LINE__);
1796     		return -ENOMEM;
1797     	}
1798     	/* get the volume group structure */
1799     	if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
1800     		kfree(vg_ptr);
1801     		return -EFAULT;
1802     	}
1803     
1804     	/* we are not that active so far... */
1805     	vg_ptr->vg_status &= ~VG_ACTIVE;
1806     	vg[VG_CHR(minor)] = vg_ptr;
1807     	vg[VG_CHR(minor)]->pe_allocated = 0;
1808     
1809     	if (vg_ptr->pv_max > ABS_MAX_PV) {
1810     		printk(KERN_WARNING
1811     		       "%s -- Can't activate VG: ABS_MAX_PV too small\n",
1812     		       lvm_name);
1813     		kfree(vg_ptr);
1814     		vg[VG_CHR(minor)] = NULL;
1815     		return -EPERM;
1816     	}
1817     	if (vg_ptr->lv_max > ABS_MAX_LV) {
1818     		printk(KERN_WARNING
1819     		"%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
1820     		       lvm_name, vg_ptr->lv_max);
1821     		kfree(vg_ptr);
1822     		vg_ptr = NULL;
1823     		return -EPERM;
1824     	}
1825     
1826     	/* get the physical volume structures */
1827     	vg_ptr->pv_act = vg_ptr->pv_cur = 0;
1828     	for (p = 0; p < vg_ptr->pv_max; p++) {
1829     		/* user space address */
1830     		if ((pvp = vg_ptr->pv[p]) != NULL) {
1831     			ret = lvm_do_pv_create(pvp, vg_ptr, p);
1832     			if ( ret != 0) {
1833     				lvm_do_vg_remove(minor);
1834     				return ret;
1835     			}
1836     		}
1837     	}
1838     
1839     	size = vg_ptr->lv_max * sizeof(lv_t *);
1840     	if ((snap_lv_ptr = vmalloc ( size)) == NULL) {
1841     		printk(KERN_CRIT
1842     		       "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n",
1843     		       lvm_name, __LINE__);
1844     		lvm_do_vg_remove(minor);
1845     		return -EFAULT;
1846     	}
1847     	memset(snap_lv_ptr, 0, size);
1848     
1849     	/* get the logical volume structures */
1850     	vg_ptr->lv_cur = 0;
1851     	for (l = 0; l < vg_ptr->lv_max; l++) {
1852     		/* user space address */
1853     		if ((lvp = vg_ptr->lv[l]) != NULL) {
1854     			if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
1855     				lvm_do_vg_remove(minor);
1856     				return -EFAULT;
1857     			}
1858     			if ( lv.lv_access & LV_SNAPSHOT) {
1859     				snap_lv_ptr[ls] = lvp;
1860     				vg_ptr->lv[l] = NULL;
1861     				ls++;
1862     				continue;
1863     			}
1864     			vg_ptr->lv[l] = NULL;
1865     			/* only create original logical volumes for now */
1866     			if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
1867     				lvm_do_vg_remove(minor);
1868     				return -EFAULT;
1869     			}
1870     		}
1871     	}
1872     
1873     	lvm_do_create_devfs_entry_of_vg ( vg_ptr);
1874     
1875     	/* Second path to correct snapshot logical volumes which are not
1876     	   in place during first path above */
1877     	for (l = 0; l < ls; l++) {
1878     		lvp = snap_lv_ptr[l];
1879     		if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
1880     			lvm_do_vg_remove(minor);
1881     			return -EFAULT;
1882     		}
1883     		if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
1884     			lvm_do_vg_remove(minor);
1885     			return -EFAULT;
1886     		}
1887     	}
1888     
1889     	lvm_do_create_proc_entry_of_vg ( vg_ptr);
1890     
1891     	vfree(snap_lv_ptr);
1892     
1893     	vg_count++;
1894     
1895     
1896     	MOD_INC_USE_COUNT;
1897     
1898     	/* let's go active */
1899     	vg_ptr->vg_status |= VG_ACTIVE;
1900     
1901     	return 0;
1902     } /* lvm_do_vg_create() */
1903     
1904     
1905     /*
1906      * character device support function VGDA extend
1907      */
1908     static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg)
1909     {
1910     	int ret = 0;
1911     	uint p;
1912     	pv_t *pv_ptr;
1913     
1914     	if (vg_ptr == NULL) return -ENXIO;
1915     	if (vg_ptr->pv_cur < vg_ptr->pv_max) {
1916     		for (p = 0; p < vg_ptr->pv_max; p++) {
1917     			if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) {
1918     				ret = lvm_do_pv_create(arg, vg_ptr, p);
1919     				if ( ret != 0) return ret;
1920     				pv_ptr = vg_ptr->pv[p];
1921     				vg_ptr->pe_total += pv_ptr->pe_total;
1922     				lvm_do_create_proc_entry_of_pv(vg_ptr, pv_ptr);
1923     				return 0;
1924     			}
1925     		}
1926     	}
1927     	return -EPERM;
1928     } /* lvm_do_vg_extend() */
1929     
1930     
1931     /*
1932      * character device support function VGDA reduce
1933      */
1934     static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) {
1935     	uint p;
1936     	pv_t *pv_ptr;
1937     
1938     	if (vg_ptr == NULL) return -ENXIO;
1939     	if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0)
1940     		return -EFAULT;
1941     
1942     	for (p = 0; p < vg_ptr->pv_max; p++) {
1943     		pv_ptr = vg_ptr->pv[p];
1944     		if (pv_ptr != NULL &&
1945     		    strcmp(pv_ptr->pv_name,
1946     			       pv_name) == 0) {
1947     			if (pv_ptr->lv_cur > 0) return -EPERM;
1948     			lvm_do_pv_remove(vg_ptr, p);
1949     			/* Make PV pointer array contiguous */
1950     			for (; p < vg_ptr->pv_max - 1; p++)
1951     				vg_ptr->pv[p] = vg_ptr->pv[p + 1];
1952     			vg_ptr->pv[p + 1] = NULL;
1953     			return 0;
1954     		}
1955     	}
1956     	return -ENXIO;
1957     } /* lvm_do_vg_reduce */
1958     
1959     
1960     /*
1961      * character device support function VG rename
1962      */
1963     static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg)
1964     {
1965     	int l = 0, p = 0, len = 0;
1966     	char vg_name[NAME_LEN] = { 0,};
1967     	char lv_name[NAME_LEN] = { 0,};
1968     	char *ptr = NULL;
1969     	lv_t *lv_ptr = NULL;
1970     	pv_t *pv_ptr = NULL;
1971     
1972     	if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0)
1973     		return -EFAULT;
1974     
1975     	lvm_do_remove_proc_entry_of_vg ( vg_ptr);
1976     
1977     	strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1);
1978     	for ( l = 0; l < vg_ptr->lv_max; l++)
1979     	{
1980     		if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue;
1981     		strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name));
1982     		ptr = strrchr(lv_ptr->lv_name, '/');
1983     		if (ptr == NULL) ptr = lv_ptr->lv_name;
1984     		strncpy(lv_name, ptr, sizeof ( lv_name));
1985     		len = sizeof(LVM_DIR_PREFIX);
1986     		strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX);
1987     		strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len);
1988     		len += strlen ( vg_name);
1989     		strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len);
1990     	}
1991     	for ( p = 0; p < vg_ptr->pv_max; p++)
1992     	{
1993     		if ( (pv_ptr = vg_ptr->pv[p]) == NULL) continue;
1994     		strncpy(pv_ptr->vg_name, vg_name, NAME_LEN);
1995     	}
1996     
1997     	lvm_do_create_proc_entry_of_vg ( vg_ptr);
1998     
1999     	return 0;
2000     } /* lvm_do_vg_rename */
2001     
2002     
2003     /*
2004      * character device support function VGDA remove
2005      */
2006     static int lvm_do_vg_remove(int minor)
2007     {
2008     	int i;
2009     	vg_t *vg_ptr = vg[VG_CHR(minor)];
2010     	pv_t *pv_ptr;
2011     
2012     	if (vg_ptr == NULL) return -ENXIO;
2013     
2014     #ifdef LVM_TOTAL_RESET
2015     	if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0)
2016     #else
2017     	if (vg_ptr->lv_open > 0)
2018     #endif
2019     		return -EPERM;
2020     
2021     	/* let's go inactive */
2022     	vg_ptr->vg_status &= ~VG_ACTIVE;
2023     
2024     	/* free LVs */
2025     	/* first free snapshot logical volumes */
2026     	for (i = 0; i < vg_ptr->lv_max; i++) {
2027     		if (vg_ptr->lv[i] != NULL &&
2028     		    vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) {
2029     			lvm_do_lv_remove(minor, NULL, i);
2030     			current->state = TASK_UNINTERRUPTIBLE;
2031     			schedule_timeout(1);
2032     		}
2033     	}
2034     	/* then free the rest of the LVs */
2035     	for (i = 0; i < vg_ptr->lv_max; i++) {
2036     		if (vg_ptr->lv[i] != NULL) {
2037     			lvm_do_lv_remove(minor, NULL, i);
2038     			current->state = TASK_UNINTERRUPTIBLE;
2039     			schedule_timeout(1);
2040     		}
2041     	}
2042     
2043     	/* free PVs */
2044     	for (i = 0; i < vg_ptr->pv_max; i++) {
2045     		if ((pv_ptr = vg_ptr->pv[i]) != NULL) {
2046     			P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
2047     			lvm_do_pv_remove(vg_ptr, i);
2048     		}
2049     	}
2050     
2051     	devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]);
2052     	devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]);
2053     
2054     	lvm_do_remove_proc_entry_of_vg ( vg_ptr);
2055     
2056     	P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
2057     	kfree(vg_ptr);
2058     	vg[VG_CHR(minor)] = NULL;
2059     
2060     	vg_count--;
2061     
2062     	MOD_DEC_USE_COUNT;
2063     
2064     	return 0;
2065     } /* lvm_do_vg_remove() */
2066     
2067     
2068     /*
2069      * character device support function physical volume create
2070      */
2071     static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) {
2072     	pv_t *pv_ptr = NULL;
2073     
2074     	pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL);
2075     	if (pv_ptr == NULL) {
2076     		printk(KERN_CRIT
2077     		       "%s -- VG_CREATE: kmalloc error PV at line %d\n",
2078     		       lvm_name, __LINE__);
2079     		return -ENOMEM;
2080     	}
2081     	if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) {
2082     		return -EFAULT;
2083     	}
2084     	/* We don't need the PE list
2085     	   in kernel space as with LVs pe_t list (see below) */
2086     	pv_ptr->pe = NULL;
2087     	pv_ptr->pe_allocated = 0;
2088     	pv_ptr->pv_status = PV_ACTIVE;
2089     	vg_ptr->pv_act++;
2090     	vg_ptr->pv_cur++;
2091     
2092     	return 0;
2093     } /* lvm_do_pv_create() */
2094     
2095     
2096     /*
2097      * character device support function physical volume create
2098      */
2099     static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) {
2100     	pv_t *pv_ptr = vg_ptr->pv[p];
2101     
2102     	lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv_ptr);
2103     	vg_ptr->pe_total -= pv_ptr->pe_total;
2104     	vg_ptr->pv_cur--;
2105     	vg_ptr->pv_act--;
2106     #ifdef LVM_GET_INODE
2107     	lvm_clear_inode(pv_ptr->inode);
2108     #endif
2109     	kfree(pv_ptr);
2110     	vg_ptr->pv[p] = NULL;
2111     
2112     	return 0;
2113     }
2114     
2115     
2116     /*
2117      * character device support function logical volume create
2118      */
2119     static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
2120     {
2121     	int e, ret, l, le, l_new, p, size;
2122     	ulong lv_status_save;
2123     	lv_block_exception_t *lvbe = lv->lv_block_exception;
2124     	vg_t *vg_ptr = vg[VG_CHR(minor)];
2125     	lv_t *lv_ptr = NULL;
2126     
2127     	if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
2128     	if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK)
2129     		return -EINVAL;
2130     
2131     	for (l = 0; l < vg_ptr->lv_max; l++) {
2132     		if (vg_ptr->lv[l] != NULL &&
2133     		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
2134     			return -EEXIST;
2135     	}
2136     
2137     	/* in case of lv_remove(), lv_create() pair */
2138     	l_new = -1;
2139     	if (vg_ptr->lv[lv->lv_number] == NULL)
2140     		l_new = lv->lv_number;
2141     	else {
2142     		for (l = 0; l < vg_ptr->lv_max; l++) {
2143     			if (vg_ptr->lv[l] == NULL)
2144     				if (l_new == -1) l_new = l;
2145     		}
2146     	}
2147     	if (l_new == -1) return -EPERM;
2148     	else             l = l_new;
2149     
2150     	if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {;
2151     		printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n",
2152     		       lvm_name, __LINE__);
2153     		return -ENOMEM;
2154     	}
2155     	/* copy preloaded LV */
2156     	memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
2157     
2158     	lv_status_save = lv_ptr->lv_status;
2159     	lv_ptr->lv_status &= ~LV_ACTIVE;
2160     	lv_ptr->lv_snapshot_org = 
2161     	lv_ptr->lv_snapshot_prev = 
2162     	lv_ptr->lv_snapshot_next = NULL;
2163     	lv_ptr->lv_block_exception = NULL;
2164     	lv_ptr->lv_iobuf = NULL;
2165     	lv_ptr->lv_snapshot_hash_table = NULL;
2166     	lv_ptr->lv_snapshot_hash_table_size = 0;
2167     	lv_ptr->lv_snapshot_hash_mask = 0;
2168     	lv_ptr->lv_COW_table_page = NULL;
2169     	init_MUTEX(&lv_ptr->lv_snapshot_sem);
2170     	lv_ptr->lv_snapshot_use_rate = 0;
2171     	vg_ptr->lv[l] = lv_ptr;
2172     
2173     	/* get the PE structures from user space if this
2174     	   is no snapshot logical volume */
2175     	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
2176     		size = lv_ptr->lv_allocated_le * sizeof(pe_t);
2177     		if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
2178     			printk(KERN_CRIT
2179     			       "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
2180     			       "at line %d\n",
2181     			       lvm_name, size, __LINE__);
2182     			P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
2183     			kfree(lv_ptr);
2184     			vg_ptr->lv[l] = NULL;
2185     			return -ENOMEM;
2186     		}
2187     		if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) {
2188     			vfree(lv_ptr->lv_current_pe);
2189     			kfree(lv_ptr);
2190     			vg_ptr->lv[l] = NULL;
2191     			return -EFAULT;
2192     		}
2193     		/* correct the PE count in PVs */
2194     		for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2195     			vg_ptr->pe_allocated++;
2196     			for (p = 0; p < vg_ptr->pv_cur; p++) {
2197     				if (vg_ptr->pv[p]->pv_dev ==
2198     				    lv_ptr->lv_current_pe[le].dev)
2199     					vg_ptr->pv[p]->pe_allocated++;
2200     			}
2201     		}
2202     	} else {
2203     		/* Get snapshot exception data and block list */
2204     		if (lvbe != NULL) {
2205     			lv_ptr->lv_snapshot_org =
2206     			    vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
2207     			if (lv_ptr->lv_snapshot_org != NULL) {
2208     				size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
2209     				if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
2210     					printk(KERN_CRIT
2211     					       "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
2212     					       "of %d byte at line %d\n",
2213     					       lvm_name, size, __LINE__);
2214     					P_KFREE("%s -- kfree %d\n", lvm_name,
2215     						__LINE__);
2216     					kfree(lv_ptr);
2217     					vg_ptr->lv[l] = NULL;
2218     					return -ENOMEM;
2219     				}
2220     				if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) {
2221     					vfree(lv_ptr->lv_block_exception);
2222     					kfree(lv_ptr);
2223     					vg_ptr->lv[l] = NULL;
2224     					return -EFAULT;
2225     				}
2226     				/* point to the original logical volume */
2227     				lv_ptr = lv_ptr->lv_snapshot_org;
2228     
2229     				lv_ptr->lv_snapshot_minor = 0;
2230     				lv_ptr->lv_snapshot_org = lv_ptr;
2231     				/* our new one now back points to the previous last in the chain
2232     				   which can be the original logical volume */
2233     				lv_ptr = vg_ptr->lv[l];
2234     				/* now lv_ptr points to our new last snapshot logical volume */
2235     				lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
2236     				lv_ptr->lv_allocated_snapshot_le = lv_ptr->lv_allocated_le;
2237     				lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
2238     				lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
2239     				lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
2240     				lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes;
2241     				lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize;
2242     
2243     				/* Update the VG PE(s) used by snapshot reserve space. */
2244     				vg_ptr->pe_allocated += lv_ptr->lv_allocated_snapshot_le;
2245     
2246     				if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0)
2247     				{
2248     					vfree(lv_ptr->lv_block_exception);
2249     					kfree(lv_ptr);
2250     					vg_ptr->lv[l] = NULL;
2251     					return ret;
2252     				}
2253     				for ( e = 0; e < lv_ptr->lv_remap_ptr; e++)
2254     					lvm_hash_link (lv_ptr->lv_block_exception + e,
2255     						       lv_ptr->lv_block_exception[e].rdev_org,
2256     						       lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
2257     				/* need to fill the COW exception table data
2258     				   into the page for disk i/o */
2259     				lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr);
2260     				init_waitqueue_head(&lv_ptr->lv_snapshot_wait);
2261     			} else {
2262     				vfree(lv_ptr->lv_block_exception);
2263     				kfree(lv_ptr);
2264     				vg_ptr->lv[l] = NULL;
2265     				return -EFAULT;
2266     			}
2267     		} else {
2268     			kfree(vg_ptr->lv[l]);
2269     			vg_ptr->lv[l] = NULL;
2270     			return -EINVAL;
2271     		}
2272     	} /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
2273     
2274     	lv_ptr = vg_ptr->lv[l];
2275     	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
2276     	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
2277     	lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
2278     	vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number;
2279     	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number;
2280     	LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
2281     	vg_ptr->lv_cur++;
2282     	lv_ptr->lv_status = lv_status_save;
2283     
2284     	{
2285     	char *lv_tmp, *lv_buf = lv->lv_name;
2286     
2287     	strtok(lv->lv_name, "/");       /* /dev */
2288     	while((lv_tmp = strtok(NULL, "/")) != NULL)
2289     		lv_buf = lv_tmp;
2290     
2291     	lv_devfs_handle[lv->lv_number] = devfs_register(
2292     		vg_devfs_handle[vg_ptr->vg_number], lv_buf,
2293     		DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number,
2294     		S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
2295     		&lvm_blk_dops, NULL);
2296     	}
2297     
2298     	lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
2299     
2300     	/* optionally add our new snapshot LV */
2301     	if (lv_ptr->lv_access & LV_SNAPSHOT) {
2302     		lv_t *org = lv_ptr->lv_snapshot_org, *last;
2303     
2304     		/* sync the original logical volume */
2305     		fsync_dev(org->lv_dev);
2306     #ifdef	LVM_VFS_ENHANCEMENT
2307     		/* VFS function call to sync and lock the filesystem */
2308     		fsync_dev_lockfs(org->lv_dev);
2309     #endif
2310     
2311     		down(&org->lv_snapshot_sem);
2312     		org->lv_access |= LV_SNAPSHOT_ORG;
2313     		lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */
2314     
2315     		/* Link in the list of snapshot volumes */
2316     		for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next);
2317     		lv_ptr->lv_snapshot_prev = last;
2318     		last->lv_snapshot_next = lv_ptr;
2319     		up(&org->lv_snapshot_sem);
2320     	}
2321     
2322     	/* activate the logical volume */
2323     	lv_ptr->lv_status |= LV_ACTIVE;
2324     	if ( lv_ptr->lv_access & LV_WRITE)
2325     		set_device_ro(lv_ptr->lv_dev, 0);
2326     	else
2327     		set_device_ro(lv_ptr->lv_dev, 1);
2328     
2329     #ifdef	LVM_VFS_ENHANCEMENT
2330     /* VFS function call to unlock the filesystem */
2331     	if (lv_ptr->lv_access & LV_SNAPSHOT) {
2332     		unlockfs(lv_ptr->lv_snapshot_org->lv_dev);
2333     	}
2334     #endif
2335     
2336     	lv_ptr->vg = vg_ptr;
2337     
2338     	return 0;
2339     } /* lvm_do_lv_create() */
2340     
2341     
2342     /*
2343      * character device support function logical volume remove
2344      */
2345     static int lvm_do_lv_remove(int minor, char *lv_name, int l)
2346     {
2347     	uint le, p;
2348     	vg_t *vg_ptr = vg[VG_CHR(minor)];
2349     	lv_t *lv_ptr;
2350     
2351     	if (l == -1) {
2352     		for (l = 0; l < vg_ptr->lv_max; l++) {
2353     			if (vg_ptr->lv[l] != NULL &&
2354     			    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) {
2355     				break;
2356     			}
2357     		}
2358     	}
2359     	if (l == vg_ptr->lv_max) return -ENXIO;
2360     
2361     	lv_ptr = vg_ptr->lv[l];
2362     #ifdef LVM_TOTAL_RESET
2363     	if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0)
2364     #else
2365     	if (lv_ptr->lv_open > 0)
2366     #endif
2367     		return -EBUSY;
2368     
2369     	/* check for deletion of snapshot source while
2370     	   snapshot volume still exists */
2371     	if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) &&
2372     	    lv_ptr->lv_snapshot_next != NULL)
2373     		return -EPERM;
2374     
2375     	if (lv_ptr->lv_access & LV_SNAPSHOT) {
2376     		/*
2377     		 * Atomically make the the snapshot invisible
2378     		 * to the original lv before playing with it.
2379     		 */
2380     		lv_t * org = lv_ptr->lv_snapshot_org;
2381     		down(&org->lv_snapshot_sem);
2382     
2383     		/* remove this snapshot logical volume from the chain */
2384     		lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next;
2385     		if (lv_ptr->lv_snapshot_next != NULL) {
2386     			lv_ptr->lv_snapshot_next->lv_snapshot_prev =
2387     			    lv_ptr->lv_snapshot_prev;
2388     		}
2389     		up(&org->lv_snapshot_sem);
2390     
2391     		/* no more snapshots? */
2392     		if (!org->lv_snapshot_next)
2393     			org->lv_access &= ~LV_SNAPSHOT_ORG;
2394     		lvm_snapshot_release(lv_ptr);
2395     
2396     		/* Update the VG PE(s) used by snapshot reserve space. */
2397     		vg_ptr->pe_allocated -= lv_ptr->lv_allocated_snapshot_le;
2398     	}
2399     
2400     	lv_ptr->lv_status |= LV_SPINDOWN;
2401     
2402     	/* sync the buffers */
2403     	fsync_dev(lv_ptr->lv_dev);
2404     
2405     	lv_ptr->lv_status &= ~LV_ACTIVE;
2406     
2407     	/* invalidate the buffers */
2408     	invalidate_buffers(lv_ptr->lv_dev);
2409     
2410     	/* reset generic hd */
2411     	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1;
2412     	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0;
2413     	lvm_size[MINOR(lv_ptr->lv_dev)] = 0;
2414     
2415     	/* reset VG/LV mapping */
2416     	vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG;
2417     	vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1;
2418     
2419     	/* correct the PE count in PVs if this is not a snapshot
2420                logical volume */
2421     	if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
2422     		/* only if this is no snapshot logical volume because
2423     		   we share the lv_current_pe[] structs with the
2424     		   original logical volume */
2425     		for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2426     			vg_ptr->pe_allocated--;
2427     			for (p = 0; p < vg_ptr->pv_cur; p++) {
2428     				if (vg_ptr->pv[p]->pv_dev ==
2429     				    lv_ptr->lv_current_pe[le].dev)
2430     					vg_ptr->pv[p]->pe_allocated--;
2431     			}
2432     		}
2433     		vfree(lv_ptr->lv_current_pe);
2434     	}
2435     
2436     	devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]);
2437     
2438     	lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr);
2439     
2440     	P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__);
2441     	kfree(lv_ptr);
2442     	vg_ptr->lv[l] = NULL;
2443     	vg_ptr->lv_cur--;
2444     	return 0;
2445     } /* lvm_do_lv_remove() */
2446     
2447     
2448     /*
2449      * character device support function logical volume extend / reduce
2450      */
2451     static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv)
2452     {
2453     	ulong end, l, le, p, size, old_allocated_le;
2454     	vg_t *vg_ptr = vg[VG_CHR(minor)];
2455     	lv_t *lv_ptr;
2456     	pe_t *pe;
2457     
2458     	if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
2459     
2460     	for (l = 0; l < vg_ptr->lv_max; l++) {
2461     		if (vg_ptr->lv[l] != NULL &&
2462     		    strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
2463     			break;
2464     	}
2465     	if (l == vg_ptr->lv_max) return -ENXIO;
2466     	lv_ptr = vg_ptr->lv[l];
2467     
2468     	/* check for active snapshot */
2469     	if (lv->lv_access & LV_SNAPSHOT)
2470     	{
2471     		ulong e;
2472     		lv_block_exception_t *lvbe, *lvbe_old;
2473     		struct list_head * lvs_hash_table_old;
2474     
2475     		if (lv->lv_block_exception == NULL) return -ENXIO;
2476     		size = lv->lv_remap_end * sizeof ( lv_block_exception_t);
2477     		if ((lvbe = vmalloc(size)) == NULL)
2478     		{
2479     			printk(KERN_CRIT
2480     			"%s -- lvm_do_lv_extend_reduce: vmalloc error LV_BLOCK_EXCEPTION "
2481     			       "of %lu Byte at line %d\n",
2482     			       lvm_name, size, __LINE__);
2483     			return -ENOMEM;
2484     		}
2485     		if (lv->lv_remap_end > lv_ptr->lv_remap_end)
2486     		{
2487     			if (copy_from_user(lvbe, lv->lv_block_exception, size))
2488     			{
2489     				vfree(lvbe);
2490     				return -EFAULT;
2491     			}
2492     		}
2493     
2494     		lvbe_old = lv_ptr->lv_block_exception;
2495     		lvs_hash_table_old = lv_ptr->lv_snapshot_hash_table;
2496     
2497     		/* we need to play on the safe side here... */
2498     		down(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2499     		if (lv_ptr->lv_block_exception == NULL ||
2500     		    lv_ptr->lv_remap_ptr > lv_ptr->lv_remap_end)
2501     		{
2502     			up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2503     			vfree(lvbe);
2504     			return -EPERM;
2505     		}
2506     		memcpy(lvbe,
2507     		       lv_ptr->lv_block_exception,
2508     		       (lv->lv_remap_end > lv_ptr->lv_remap_end ?
2509     			lv_ptr->lv_remap_ptr : lv->lv_remap_end) * sizeof(lv_block_exception_t));
2510     
2511     		lv_ptr->lv_block_exception = lvbe;
2512     		lv_ptr->lv_remap_end = lv->lv_remap_end;
2513     		if (lvm_snapshot_alloc_hash_table(lv_ptr) != 0)
2514     		{
2515     			lvm_drop_snapshot(lv_ptr, "no memory for hash table");
2516     			up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2517     			vfree(lvbe_old);
2518     			vfree(lvs_hash_table_old);
2519     			return -ENOMEM;
2520     		}
2521     
2522     		for (e = 0; e < lv_ptr->lv_remap_ptr; e++)
2523     			lvm_hash_link (lv_ptr->lv_block_exception + e,
2524     				       lv_ptr->lv_block_exception[e].rdev_org,
2525     				       lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
2526     
2527     		up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2528     
2529     		vfree(lvbe_old);
2530     		vfree(lvs_hash_table_old);
2531     
2532     		return 0;
2533     	}
2534     
2535     
2536     	/* we drop in here in case it is an original logical volume */
2537     	if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) {
2538     		printk(KERN_CRIT
2539     		"%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE "
2540     		       "of %lu Byte at line %d\n",
2541     		       lvm_name, size, __LINE__);
2542     		return -ENOMEM;
2543     	}
2544     	/* get the PE structures from user space */
2545     	if (copy_from_user(pe, pep, size)) {
2546     		vfree(pe);
2547     		return -EFAULT;
2548     	}
2549     
2550     	/* reduce allocation counters on PV(s) */
2551     	for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2552     		vg_ptr->pe_allocated--;
2553     		for (p = 0; p < vg_ptr->pv_cur; p++) {
2554     			if (vg_ptr->pv[p]->pv_dev ==
2555     			lv_ptr->lv_current_pe[le].dev) {
2556     				vg_ptr->pv[p]->pe_allocated--;
2557     				break;
2558     			}
2559     		}
2560     	}
2561     
2562     
2563     	/* save pointer to "old" lv/pe pointer array */
2564     	pep1 = lv_ptr->lv_current_pe;
2565     	end = lv_ptr->lv_current_le;
2566     
2567     	/* save open counter... */
2568     	lv->lv_open = lv_ptr->lv_open;
2569     	lv->lv_snapshot_prev = lv_ptr->lv_snapshot_prev;
2570     	lv->lv_snapshot_next = lv_ptr->lv_snapshot_next;
2571     	lv->lv_snapshot_org  = lv_ptr->lv_snapshot_org;
2572     
2573     	lv->lv_current_pe = pe;
2574     
2575     	/* save # of old allocated logical extents */
2576     	old_allocated_le = lv_ptr->lv_allocated_le;
2577     
2578     	/* copy preloaded LV */
2579     	memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
2580     
2581     	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
2582     	lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
2583     	lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
2584     	/* vg_lv_map array doesn't have to be changed here */
2585     
2586     	LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
2587     
2588     	/* save availiable i/o statistic data */
2589     	/* linear logical volume */
2590     	if (lv_ptr->lv_stripes < 2) {
2591     		/* Check what last LE shall be used */
2592     		if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le;
2593     		for (le = 0; le < end; le++) {
2594     			lv_ptr->lv_current_pe[le].reads  += pep1[le].reads;
2595     			lv_ptr->lv_current_pe[le].writes += pep1[le].writes;
2596     		}
2597     		/* striped logical volume */
2598     	} else {
2599     		uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
2600     
2601     		old_stripe_size = old_allocated_le / lv_ptr->lv_stripes;
2602     		new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes;
2603     		end = old_stripe_size;
2604     		if (end > new_stripe_size) end = new_stripe_size;
2605     		for (i = source = dest = 0;
2606     		     i < lv_ptr->lv_stripes; i++) {
2607     			for (j = 0; j < end; j++) {
2608     				lv_ptr->lv_current_pe[dest + j].reads +=
2609     				    pep1[source + j].reads;
2610     				lv_ptr->lv_current_pe[dest + j].writes +=
2611     				    pep1[source + j].writes;
2612     			}
2613     			source += old_stripe_size;
2614     			dest += new_stripe_size;
2615     		}
2616     	}
2617     
2618     	/* extend the PE count in PVs */
2619     	for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2620     		vg_ptr->pe_allocated++;
2621     		for (p = 0; p < vg_ptr->pv_cur; p++) {
2622     			if (vg_ptr->pv[p]->pv_dev ==
2623                                 lv_ptr->lv_current_pe[le].dev) {
2624     				vg_ptr->pv[p]->pe_allocated++;
2625     				break;
2626     			}
2627     		}
2628     	}
2629     
2630     	vfree ( pep1);
2631     	pep1 = NULL;
2632     
2633     	if (lv->lv_access & LV_SNAPSHOT_ORG)
2634     	{
2635     		/* Correct the snapshot size information */
2636     		while ((lv_ptr = lv_ptr->lv_snapshot_next) != NULL)
2637     		{
2638     			lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
2639     			lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
2640     			lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
2641     			lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
2642     			lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
2643     			lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
2644     		}
2645     	}
2646     
2647     	return 0;
2648     } /* lvm_do_lv_extend_reduce() */
2649     
2650     
2651     /*
2652      * character device support function logical volume status by name
2653      */
2654     static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
2655     {
2656     	uint l;
2657     	ulong size;
2658     	lv_t lv;
2659     	lv_t *lv_ptr;
2660     	lv_status_byname_req_t lv_status_byname_req;
2661     
2662     	if (vg_ptr == NULL) return -ENXIO;
2663     	if (copy_from_user(&lv_status_byname_req, arg,
2664     			   sizeof(lv_status_byname_req_t)) != 0)
2665     		return -EFAULT;
2666     
2667     	if (lv_status_byname_req.lv == NULL) return -EINVAL;
2668     	if (copy_from_user(&lv, lv_status_byname_req.lv,
2669     			   sizeof(lv_t)) != 0)
2670     		return -EFAULT;
2671     
2672     	for (l = 0; l < vg_ptr->lv_max; l++) {
2673     		lv_ptr = vg_ptr->lv[l];
2674     		if (lv_ptr != NULL &&
2675     		    strcmp(lv_ptr->lv_name,
2676     			    lv_status_byname_req.lv_name) == 0) {
2677     			if (copy_to_user(lv_status_byname_req.lv,
2678     					 lv_ptr,
2679     					 sizeof(lv_t)) != 0)
2680     				return -EFAULT;
2681     
2682     			if (lv.lv_current_pe != NULL) {
2683     				size = lv_ptr->lv_allocated_le *
2684     				       sizeof(pe_t);
2685     				if (copy_to_user(lv.lv_current_pe,
2686     						 lv_ptr->lv_current_pe,
2687     						 size) != 0)
2688     					return -EFAULT;
2689     			}
2690     			return 0;
2691     		}
2692     	}
2693     	return -ENXIO;
2694     } /* lvm_do_lv_status_byname() */
2695     
2696     
2697     /*
2698      * character device support function logical volume status by index
2699      */
2700     static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
2701     {
2702     	ulong size;
2703     	lv_t lv;
2704     	lv_t *lv_ptr;
2705     	lv_status_byindex_req_t lv_status_byindex_req;
2706     
2707     	if (vg_ptr == NULL) return -ENXIO;
2708     	if (copy_from_user(&lv_status_byindex_req, arg,
2709     			   sizeof(lv_status_byindex_req)) != 0)
2710     		return -EFAULT;
2711     
2712     	if ((lvp = lv_status_byindex_req.lv) == NULL)
2713     		return -EINVAL;
2714     	if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
2715     		return -ENXIO;
2716     
2717     	if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0)
2718     		return -EFAULT;
2719     
2720     	if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0)
2721     		return -EFAULT;
2722     
2723     	if (lv.lv_current_pe != NULL) {
2724     		size = lv_ptr->lv_allocated_le * sizeof(pe_t);
2725     		if (copy_to_user(lv.lv_current_pe,
2726     			 	 lv_ptr->lv_current_pe,
2727     				 size) != 0)
2728     			return -EFAULT;
2729     	}
2730     	return 0;
2731     } /* lvm_do_lv_status_byindex() */
2732     
2733     
2734     /*
2735      * character device support function logical volume status by device number
2736      */
2737     static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) {
2738     	int l;
2739     	lv_status_bydev_req_t lv_status_bydev_req;
2740     
2741     	if (vg_ptr == NULL) return -ENXIO;
2742     	if (copy_from_user(&lv_status_bydev_req, arg,
2743     			   sizeof(lv_status_bydev_req)) != 0)
2744     		return -EFAULT;
2745     
2746     	for ( l = 0; l < vg_ptr->lv_max; l++) {
2747     		if ( vg_ptr->lv[l] == NULL) continue;
2748     		if ( vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) break;
2749     	}
2750     
2751     	if ( l == vg_ptr->lv_max) return -ENXIO;
2752     
2753     	if (copy_to_user(lv_status_bydev_req.lv,
2754     			 vg_ptr->lv[l], sizeof(lv_t)) != 0)
2755     		return -EFAULT;
2756     
2757     	return 0;
2758     } /* lvm_do_lv_status_bydev() */
2759     
2760     
2761     /*
2762      * character device support function rename a logical volume
2763      */
2764     static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv)
2765     {
2766     	int l = 0;
2767     	int ret = 0;
2768     	lv_t *lv_ptr = NULL;
2769     
2770     	for (l = 0; l < vg_ptr->lv_max; l++)
2771     	{
2772     		if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue;
2773     		if (lv_ptr->lv_dev == lv->lv_dev)
2774     		{
2775     			lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr);
2776     			strncpy(lv_ptr->lv_name,
2777     				lv_req->lv_name,
2778     				NAME_LEN);
2779     			lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
2780     			break;
2781     		}
2782     	}
2783     	if (l == vg_ptr->lv_max) ret = -ENODEV;
2784     
2785     	return ret;
2786     } /* lvm_do_lv_rename */
2787     
2788     
2789     /*
2790      * character device support function physical volume change
2791      */
2792     static int lvm_do_pv_change(vg_t *vg_ptr, void *arg)
2793     {
2794     	uint p;
2795     	pv_t *pv_ptr;
2796     #ifdef LVM_GET_INODE
2797     	struct inode *inode_sav;
2798     #endif
2799     
2800     	if (vg_ptr == NULL) return -ENXIO;
2801     	if (copy_from_user(&pv_change_req, arg,
2802     			   sizeof(pv_change_req)) != 0)
2803     		return -EFAULT;
2804     
2805     	for (p = 0; p < vg_ptr->pv_max; p++) {
2806     		pv_ptr = vg_ptr->pv[p];
2807     		if (pv_ptr != NULL &&
2808     		    strcmp(pv_ptr->pv_name,
2809     			       pv_change_req.pv_name) == 0) {
2810     #ifdef LVM_GET_INODE
2811     			inode_sav = pv_ptr->inode;
2812     #endif
2813     			if (copy_from_user(pv_ptr,
2814     					   pv_change_req.pv,
2815     					   sizeof(pv_t)) != 0)
2816     				return -EFAULT;
2817     
2818     			/* We don't need the PE list
2819     			   in kernel space as with LVs pe_t list */
2820     			pv_ptr->pe = NULL;
2821     #ifdef LVM_GET_INODE
2822     			pv_ptr->inode = inode_sav;
2823     #endif
2824     			return 0;
2825     		}
2826     	}
2827     	return -ENXIO;
2828     } /* lvm_do_pv_change() */
2829     
2830     /*
2831      * character device support function get physical volume status
2832      */
2833     static int lvm_do_pv_status(vg_t *vg_ptr, void *arg)
2834     {
2835     	uint p;
2836     	pv_t *pv_ptr;
2837     
2838     	if (vg_ptr == NULL) return -ENXIO;
2839     	if (copy_from_user(&pv_status_req, arg,
2840     			   sizeof(pv_status_req)) != 0)
2841     		return -EFAULT;
2842     
2843     	for (p = 0; p < vg_ptr->pv_max; p++) {
2844     		pv_ptr = vg_ptr->pv[p];
2845     		if (pv_ptr != NULL &&
2846     		    strcmp(pv_ptr->pv_name,
2847     			       pv_status_req.pv_name) == 0) {
2848     			if (copy_to_user(pv_status_req.pv,
2849     					 pv_ptr,
2850     				         sizeof(pv_t)) != 0)
2851     				return -EFAULT;
2852     			return 0;
2853     		}
2854     	}
2855     	return -ENXIO;
2856     } /* lvm_do_pv_status() */
2857     
2858     
2859     
2860     /*
2861      * create a devfs entry for a volume group
2862      */
2863     void lvm_do_create_devfs_entry_of_vg ( vg_t *vg_ptr) {
2864     	vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL);
2865     	ch_devfs_handle[vg_ptr->vg_number] = devfs_register(
2866     		vg_devfs_handle[vg_ptr->vg_number] , "group",
2867     		DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number,
2868     		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
2869     		&lvm_chr_fops, NULL);
2870     }
2871     
2872     
2873     /*
2874      * create a /proc entry for a logical volume
2875      */
2876     void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) {
2877     	char *basename;
2878     
2879     	if ( vg_ptr->lv_subdir_pde != NULL) {
2880     		basename = strrchr(lv_ptr->lv_name, '/');
2881     		if (basename == NULL) basename = lv_ptr->lv_name;
2882     		else		      basename++;
2883     		pde = create_proc_entry(basename, S_IFREG,
2884     					vg_ptr->lv_subdir_pde);
2885     		if ( pde != NULL) {
2886     			pde->read_proc = lvm_proc_read_lv_info;
2887     			pde->data = lv_ptr;
2888     		}
2889     	}
2890     }
2891     
2892     
2893     /*
2894      * remove a /proc entry for a logical volume
2895      */
2896     void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) {
2897     	char *basename;
2898     
2899     	if ( vg_ptr->lv_subdir_pde != NULL) {
2900     		basename = strrchr(lv_ptr->lv_name, '/');
2901     		if (basename == NULL) basename = lv_ptr->lv_name;
2902     		else		      basename++;
2903     		remove_proc_entry(basename, vg_ptr->lv_subdir_pde);
2904     	}
2905     }
2906     
2907     
2908     /*
2909      * create a /proc entry for a physical volume
2910      */
2911     void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) {
2912     	int offset = 0;
2913     	char *basename;
2914     	char buffer[NAME_LEN];
2915     
2916     	basename = pv_ptr->pv_name;
2917     	if (strncmp(basename, "/dev/", 5) == 0) offset = 5;
2918     	strncpy(buffer, basename + offset, sizeof(buffer));
2919     	basename = buffer;
2920     	while ( ( basename = strchr ( basename, '/')) != NULL) *basename = '_';
2921     	pde = create_proc_entry(buffer, S_IFREG, vg_ptr->pv_subdir_pde);
2922     	if ( pde != NULL) {
2923     		pde->read_proc = lvm_proc_read_pv_info;
2924     		pde->data = pv_ptr;
2925     	}
2926     }
2927     
2928     
2929     /*
2930      * remove a /proc entry for a physical volume
2931      */
2932     void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) {
2933     	char *basename;
2934     
2935     	basename = strrchr(pv_ptr->pv_name, '/');
2936     	if ( vg_ptr->pv_subdir_pde != NULL) {
2937     		basename = strrchr(pv_ptr->pv_name, '/');
2938     		if (basename == NULL) basename = pv_ptr->pv_name;
2939     		else		      basename++;
2940     		remove_proc_entry(basename, vg_ptr->pv_subdir_pde);
2941     	}
2942     }
2943     
2944     
2945     /*
2946      * create a /proc entry for a volume group
2947      */
2948     void lvm_do_create_proc_entry_of_vg ( vg_t *vg_ptr) {
2949     	int l, p;
2950     	pv_t *pv_ptr;
2951     	lv_t *lv_ptr;
2952     
2953     	pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
2954     				lvm_proc_vg_subdir);
2955     	if ( pde != NULL) {
2956     		vg_ptr->vg_dir_pde = pde;
2957     		pde = create_proc_entry("group", S_IFREG,
2958     					vg_ptr->vg_dir_pde);
2959     		if ( pde != NULL) {
2960     			pde->read_proc = lvm_proc_read_vg_info;
2961     			pde->data = vg_ptr;
2962     		}
2963                     pde = create_proc_entry(LVM_LV_SUBDIR, S_IFDIR,
2964                                             vg_ptr->vg_dir_pde);
2965                     if ( pde != NULL) {
2966                             vg_ptr->lv_subdir_pde = pde;
2967                             for ( l = 0; l < vg_ptr->lv_max; l++) {
2968     				if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue;
2969     				lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
2970                             }
2971                     }
2972                     pde = create_proc_entry(LVM_PV_SUBDIR, S_IFDIR,
2973                                             vg_ptr->vg_dir_pde);
2974                     if ( pde != NULL) {
2975                             vg_ptr->pv_subdir_pde = pde;
2976     			for ( p = 0; p < vg_ptr->pv_max; p++) {
2977     				if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue;
2978     				lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr);
2979                             }
2980                     }
2981             }
2982     }
2983     
2984     /*
2985      * remove a /proc entry for a volume group
2986      */
2987     void lvm_do_remove_proc_entry_of_vg ( vg_t *vg_ptr) {
2988     	int l, p;
2989     	lv_t *lv_ptr;
2990     	pv_t *pv_ptr;
2991     
2992     	for ( l = 0; l < vg_ptr->lv_max; l++) {
2993     		if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue;
2994     		lvm_do_remove_proc_entry_of_lv ( vg_ptr, vg_ptr->lv[l]);
2995     	}
2996     	for ( p = 0; p < vg_ptr->pv_max; p++) {
2997     		if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue;
2998     		lvm_do_remove_proc_entry_of_pv ( vg_ptr, vg_ptr->pv[p]);
2999     	}
3000     	if ( vg_ptr->vg_dir_pde != NULL) {
3001     		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
3002     		remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde);
3003     		remove_proc_entry("group", vg_ptr->vg_dir_pde);
3004     		remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir);
3005     	}
3006     }
3007     
3008     
3009     /*
3010      * support function initialize gendisk variables
3011      */
3012     void __init lvm_geninit(struct gendisk *lvm_gdisk)
3013     {
3014     	int i = 0;
3015     
3016     #ifdef DEBUG_GENDISK
3017     	printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name);
3018     #endif
3019     
3020     	for (i = 0; i < MAX_LV; i++) {
3021     		lvm_gendisk.part[i].start_sect = -1;	/* avoid partition check */
3022     		lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0;
3023     		lvm_blocksizes[i] = BLOCK_SIZE;
3024     	}
3025     
3026     	blk_size[MAJOR_NR] = lvm_size;
3027     	blksize_size[MAJOR_NR] = lvm_blocksizes;
3028     	hardsect_size[MAJOR_NR] = lvm_blocksizes;
3029     
3030     	return;
3031     } /* lvm_gen_init() */
3032     
3033     
3034     /*
3035      * return a pointer to a '-' padded uuid
3036      */
3037     static char *lvm_show_uuid ( char *uuidstr) {
3038     	int i, j;
3039     	static char uuid[NAME_LEN] = { 0, };
3040     
3041     	memset ( uuid, 0, NAME_LEN);
3042     
3043     	i = 6;
3044     	memcpy ( uuid, uuidstr, i);
3045     	uuidstr += i;
3046     
3047     	for ( j = 0; j < 6; j++) {
3048     		uuid[i++] = '-';
3049     		memcpy ( &uuid[i], uuidstr, 4);
3050     		uuidstr += 4;
3051     		i += 4;
3052     	}
3053     
3054     	memcpy ( &uuid[i], uuidstr, 2 );
3055     
3056     	return uuid;
3057     }
3058     
3059     module_init(lvm_init);
3060     module_exit(lvm_cleanup);
3061