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, §ors,
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