More Makefile cleanups, otherwise mainly noticeable are the netfilter fix
[davej-history.git] / drivers / md / lvm.c
blobea276c57c95ec4298b87eb5b8e88955f3afda52e
1 /*
2 * kernel/lvm.c
4 * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software
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
12 * LVM driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2, or (at your option)
15 * any later version.
17 * LVM driver is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with GNU CC; see the file COPYING. If not, write to
24 * the Free Software Foundation, 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
30 * Changelog
32 * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT
33 * and VG_STATUS_GET_NAMELIST
34 * 18/01/1998 - change lvm_chr_open/close lock handling
35 * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and
36 * - added LV_STATUS_BYINDEX ioctl
37 * - used lvm_status_byname_req_t and
38 * lvm_status_byindex_req_t vars
39 * 04/05/1998 - added multiple device support
40 * 08/05/1998 - added support to set/clear extendable flag in volume group
41 * 09/05/1998 - changed output of lvm_proc_get_global_info() because of
42 * support for free (eg. longer) logical volume names
43 * 12/05/1998 - added spin_locks (thanks to Pascal van Dam
44 * <pascal@ramoth.xs4all.nl>)
45 * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl()
46 * 26/05/1998 - reactivated verify_area by access_ok
47 * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go
48 * beyond 128/256 KB max allocation limit per call
49 * - #ifdef blocked spin_lock calls to avoid compile errors
50 * with 2.0.x
51 * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open()
52 * and use of LVM_VERSION_CODE instead of my own macros
53 * (thanks to Michael Marxmeier <mike@msede.com>)
54 * 07/07/1998 - added statistics in lvm_map()
55 * 08/07/1998 - saved statistics in lvm_do_lv_extend_reduce()
56 * 25/07/1998 - used __initfunc macro
57 * 02/08/1998 - changes for official char/block major numbers
58 * 07/08/1998 - avoided init_module() and cleanup_module() to be static
59 * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters
60 * to sum of LVs open (no matter how often each is)
61 * 01/09/1998 - fixed lvm_gendisk.part[] index error
62 * 07/09/1998 - added copying of lv_current_pe-array
63 * in LV_STATUS_BYINDEX ioctl
64 * 17/11/1998 - added KERN_* levels to printk
65 * 13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename
66 * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET
67 * by moving spinlock code from lvm_chr_open()
68 * to lvm_chr_ioctl()
69 * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl()
70 * - allowed LVM_RESET and retrieval commands to go ahead;
71 * only other update ioctls are blocked now
72 * - fixed pv->pe to NULL for pv_status
73 * - using lv_req structure in lvm_chr_ioctl() now
74 * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce()
75 * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE)
76 * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to
77 * handle lgoical volume private read ahead sector
78 * - implemented LV read_ahead handling with lvm_blk_read()
79 * and lvm_blk_write()
80 * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name()
81 * to be used in drivers/block/genhd.c by disk_name()
82 * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO
83 * - enhanced gendisk insert/remove handling
84 * 16/02/1999 - changed to dynamic block minor number allocation to
85 * have as much as 99 volume groups with 256 logical volumes
86 * as the grand total; this allows having 1 volume group with
87 * up to 256 logical volumes in it
88 * 21/02/1999 - added LV open count information to proc filesystem
89 * - substituted redundant LVM_RESET code by calls
90 * to lvm_do_vg_remove()
91 * 22/02/1999 - used schedule_timeout() to be more responsive
92 * in case of lvm_do_vg_remove() with lots of logical volumes
93 * 19/03/1999 - fixed NULL pointer bug in module_init/lvm_init
94 * 17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0)
95 * - enhanced lvm_hd_name support
96 * 03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and
97 * memcpy_tofs/memcpy_fromfs macro redefinitions
98 * 06/07/1999 - corrected reads/writes statistic counter copy in case
99 * of striped logical volume
100 * 28/07/1999 - implemented snapshot logical volumes
101 * - lvm_chr_ioctl
102 * - LV_STATUS_BYINDEX
103 * - LV_STATUS_BYNAME
104 * - lvm_do_lv_create
105 * - lvm_do_lv_remove
106 * - lvm_map
107 * - new lvm_snapshot_remap_block
108 * - new lvm_snapshot_remap_new_block
109 * 08/10/1999 - implemented support for multiple snapshots per
110 * original logical volume
111 * 12/10/1999 - support for 2.3.19
112 * 11/11/1999 - support for 2.3.28
113 * 21/11/1999 - changed lvm_map() interface to buffer_head based
114 * 19/12/1999 - support for 2.3.33
115 * 01/01/2000 - changed locking concept in lvm_map(),
116 * lvm_do_vg_create() and lvm_do_lv_remove()
117 * 15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl()
118 * 24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc.
119 * 29/01/2000 - used kmalloc/kfree again for all small structures
120 * 20/01/2000 - cleaned up lvm_chr_ioctl by moving code
121 * to seperated functions
122 * - avoided "/dev/" in proc filesystem output
123 * - avoided inline strings functions lvm_strlen etc.
124 * 14/02/2000 - support for 2.3.43
125 * - integrated Andrea Arcagneli's snapshot code
126 * 25/06/2000 - james (chip) , IKKHAYD! roffl
127 * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume support
128 * 06/09/2000 - added devfs support
129 * 07/09/2000 - changed IOP version to 9
130 * - started to add new char ioctl LV_STATUS_BYDEV_T to support
131 * getting an lv_t based on the dev_t of the Logical Volume
132 * 14/09/2000 - enhanced lvm_do_lv_create to upcall VFS functions
133 * to sync and lock, activate snapshot and unlock the FS
134 * (to support journaled filesystems)
135 * 18/09/2000 - hardsector size support
136 * 27/09/2000 - implemented lvm_do_lv_rename() and lvm_do_vg_rename()
137 * 30/10/2000 - added Andi Kleen's LV_BMAP ioctl to support LILO
138 * 01/11/2000 - added memory information on hash tables to
139 * lvm_proc_get_global_info()
140 * 02/11/2000 - implemented /proc/lvm/ hierarchy
141 * 07/12/2000 - make sure lvm_make_request_fn returns correct value - 0 or 1 - NeilBrown
146 static char *lvm_version = "LVM version 0.9 by Heinz Mauelshagen (13/11/2000)\n";
147 static char *lvm_short_version = "version 0.9 (13/11/2000)";
149 #define MAJOR_NR LVM_BLK_MAJOR
150 #define DEVICE_OFF(device)
152 /* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */
153 /* #define LVM_VFS_ENHANCEMENT */
155 #include <linux/config.h>
156 #include <linux/version.h>
158 #ifdef MODVERSIONS
159 #undef MODULE
160 #define MODULE
161 #include <linux/modversions.h>
162 #endif
164 #include <linux/module.h>
166 #include <linux/kernel.h>
167 #include <linux/vmalloc.h>
168 #include <linux/slab.h>
169 #include <linux/init.h>
171 #include <linux/hdreg.h>
172 #include <linux/stat.h>
173 #include <linux/fs.h>
174 #include <linux/proc_fs.h>
175 #include <linux/blkdev.h>
176 #include <linux/genhd.h>
177 #include <linux/locks.h>
178 #include <linux/smp_lock.h>
179 #include <asm/ioctl.h>
180 #include <asm/segment.h>
181 #include <asm/uaccess.h>
183 #ifdef CONFIG_KERNELD
184 #include <linux/kerneld.h>
185 #endif
187 #include <linux/blk.h>
188 #include <linux/blkpg.h>
190 #include <linux/errno.h>
191 #include <linux/lvm.h>
193 #define LVM_CORRECT_READ_AHEAD( a) \
194 if ( a < LVM_MIN_READ_AHEAD || \
195 a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD;
197 #ifndef WRITEA
198 # define WRITEA WRITE
199 #endif
202 * External function prototypes
204 #ifdef MODULE
205 int init_module(void);
206 void cleanup_module(void);
207 #else
208 extern int lvm_init(void);
209 #endif
211 static void lvm_dummy_device_request(request_queue_t *);
212 #define DEVICE_REQUEST lvm_dummy_device_request
214 static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*);
216 static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
217 static int lvm_blk_open(struct inode *, struct file *);
219 static int lvm_chr_open(struct inode *, struct file *);
221 static int lvm_chr_close(struct inode *, struct file *);
222 static int lvm_blk_close(struct inode *, struct file *);
223 static int lvm_user_bmap(struct inode *, struct lv_bmap *);
225 static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong);
227 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
228 int lvm_proc_read_vg_info(char *, char **, off_t, int, int *, void *);
229 int lvm_proc_read_lv_info(char *, char **, off_t, int, int *, void *);
230 int lvm_proc_read_pv_info(char *, char **, off_t, int, int *, void *);
231 static int lvm_proc_get_global_info(char *, char **, off_t, int, int *, void *);
232 void lvm_do_create_proc_entry_of_vg ( vg_t *);
233 inline void lvm_do_remove_proc_entry_of_vg ( vg_t *);
234 inline void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *);
235 inline void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *);
236 inline void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *);
237 inline void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *);
238 #endif
240 #ifdef LVM_HD_NAME
241 void lvm_hd_name(char *, int);
242 #endif
243 /* End external function prototypes */
247 * Internal function prototypes
249 static void lvm_init_vars(void);
251 /* external snapshot calls */
252 extern inline int lvm_get_blksize(kdev_t);
253 extern int lvm_snapshot_alloc(lv_t *);
254 extern void lvm_snapshot_fill_COW_page(vg_t *, lv_t *);
255 extern int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *);
256 extern int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);
257 extern void lvm_snapshot_release(lv_t *);
258 extern int lvm_write_COW_table_block(vg_t *, lv_t *);
259 extern inline void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *);
260 extern int lvm_snapshot_alloc_hash_table(lv_t *);
261 extern void lvm_drop_snapshot(lv_t *, char *);
263 #ifdef LVM_HD_NAME
264 extern void (*lvm_hd_name_ptr) (char *, int);
265 #endif
266 static int lvm_map(struct buffer_head *, int);
267 static int lvm_do_lock_lvm(void);
268 static int lvm_do_le_remap(vg_t *, void *);
270 static int lvm_do_pv_create(pv_t *, vg_t *, ulong);
271 static int lvm_do_pv_remove(vg_t *, ulong);
272 static int lvm_do_lv_create(int, char *, lv_t *);
273 static int lvm_do_lv_extend_reduce(int, char *, lv_t *);
274 static int lvm_do_lv_remove(int, char *, int);
275 static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *);
276 static int lvm_do_lv_status_byname(vg_t *r, void *);
277 static int lvm_do_lv_status_byindex(vg_t *, void *);
278 static int lvm_do_lv_status_bydev(vg_t *, void *);
280 static int lvm_do_pe_lock_unlock(vg_t *r, void *);
282 static int lvm_do_pv_change(vg_t*, void*);
283 static int lvm_do_pv_status(vg_t *, void *);
285 static int lvm_do_vg_create(int, void *);
286 static int lvm_do_vg_extend(vg_t *, void *);
287 static int lvm_do_vg_reduce(vg_t *, void *);
288 static int lvm_do_vg_rename(vg_t *, void *);
289 static int lvm_do_vg_remove(int);
290 static void lvm_geninit(struct gendisk *);
291 #ifdef LVM_GET_INODE
292 static struct inode *lvm_get_inode(int);
293 void lvm_clear_inode(struct inode *);
294 #endif
295 /* END Internal function prototypes */
298 /* volume group descriptor area pointers */
299 static vg_t *vg[ABS_MAX_VG];
301 #ifdef CONFIG_DEVFS_FS
302 static devfs_handle_t lvm_devfs_handle;
303 static devfs_handle_t vg_devfs_handle[MAX_VG];
304 static devfs_handle_t ch_devfs_handle[MAX_VG];
305 static devfs_handle_t lv_devfs_handle[MAX_LV];
306 #endif
308 static pv_t *pvp = NULL;
309 static lv_t *lvp = NULL;
310 static pe_t *pep = NULL;
311 static pe_t *pep1 = NULL;
312 static char *basename = NULL;
315 /* map from block minor number to VG and LV numbers */
316 typedef struct {
317 int vg_number;
318 int lv_number;
319 } vg_lv_map_t;
320 static vg_lv_map_t vg_lv_map[ABS_MAX_LV];
323 /* Request structures (lvm_chr_ioctl()) */
324 static pv_change_req_t pv_change_req;
325 static pv_flush_req_t pv_flush_req;
326 static pv_status_req_t pv_status_req;
327 static pe_lock_req_t pe_lock_req;
328 static le_remap_req_t le_remap_req;
329 static lv_req_t lv_req;
331 #ifdef LVM_TOTAL_RESET
332 static int lvm_reset_spindown = 0;
333 #endif
335 static char pv_name[NAME_LEN];
336 /* static char rootvg[NAME_LEN] = { 0, }; */
337 const char *const lvm_name = LVM_NAME;
338 static int lock = 0;
339 static int loadtime = 0;
340 static uint vg_count = 0;
341 static long lvm_chr_open_count = 0;
342 static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;
343 static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait);
344 static DECLARE_WAIT_QUEUE_HEAD(lvm_wait);
345 static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait);
347 static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED;
348 static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
350 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
351 static struct proc_dir_entry *lvm_proc_dir = NULL;
352 static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;
353 struct proc_dir_entry *pde = NULL;
354 #endif
356 static struct file_operations lvm_chr_fops =
358 open: lvm_chr_open,
359 release: lvm_chr_close,
360 ioctl: lvm_chr_ioctl,
363 #define BLOCK_DEVICE_OPERATIONS
364 /* block device operations structure needed for 2.3.38? and above */
365 static struct block_device_operations lvm_blk_dops =
367 open: lvm_blk_open,
368 release: lvm_blk_close,
369 ioctl: lvm_blk_ioctl,
373 /* gendisk structures */
374 static struct hd_struct lvm_hd_struct[MAX_LV];
375 static int lvm_blocksizes[MAX_LV] =
376 {0,};
377 static int lvm_size[MAX_LV] =
378 {0,};
379 static struct gendisk lvm_gendisk =
381 MAJOR_NR, /* major # */
382 LVM_NAME, /* name of major */
383 0, /* number of times minor is shifted
384 to get real minor */
385 1, /* maximum partitions per device */
386 lvm_hd_struct, /* partition table */
387 lvm_size, /* device size in blocks, copied
388 to block_size[] */
389 MAX_LV, /* number or real devices */
390 NULL, /* internal */
391 NULL, /* pointer to next gendisk struct (internal) */
395 #ifdef MODULE
397 * Module initialization...
399 int init_module(void)
400 #else
402 * Driver initialization...
404 #ifdef __initfunc
405 __initfunc(int lvm_init(void))
406 #else
407 int __init lvm_init(void)
408 #endif
409 #endif /* #ifdef MODULE */
411 struct gendisk *gendisk_ptr = NULL;
413 if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) {
414 printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name);
415 return -EIO;
417 #ifdef BLOCK_DEVICE_OPERATIONS
418 if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)
419 #else
420 if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0)
421 #endif
423 printk("%s -- register_blkdev failed\n", lvm_name);
424 if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0)
425 printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
426 return -EIO;
429 #ifdef CONFIG_DEVFS_FS
430 lvm_devfs_handle = devfs_register(
431 0 , "lvm", 0, 0, LVM_CHAR_MAJOR,
432 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
433 &lvm_chr_fops, NULL);
434 #endif
436 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
437 lvm_proc_dir = create_proc_entry (LVM_DIR, S_IFDIR, &proc_root);
438 if (lvm_proc_dir != NULL) {
439 lvm_proc_vg_subdir = create_proc_entry (LVM_VG_SUBDIR, S_IFDIR, lvm_proc_dir);
440 pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir);
441 if ( pde != NULL) pde->read_proc = &lvm_proc_get_global_info;
443 #endif
445 lvm_init_vars();
446 lvm_geninit(&lvm_gendisk);
448 /* insert our gendisk at the corresponding major */
449 if (gendisk_head != NULL) {
450 gendisk_ptr = gendisk_head;
451 while (gendisk_ptr->next != NULL &&
452 gendisk_ptr->major > lvm_gendisk.major) {
453 gendisk_ptr = gendisk_ptr->next;
455 lvm_gendisk.next = gendisk_ptr->next;
456 gendisk_ptr->next = &lvm_gendisk;
457 } else {
458 gendisk_head = &lvm_gendisk;
459 lvm_gendisk.next = NULL;
462 #ifdef LVM_HD_NAME
463 /* reference from drivers/block/genhd.c */
464 lvm_hd_name_ptr = lvm_hd_name;
465 #endif
467 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
468 blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn);
470 /* optional read root VGDA */
472 if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);
475 printk(KERN_INFO
476 "%s%s -- "
477 #ifdef MODULE
478 "Module"
479 #else
480 "Driver"
481 #endif
482 " successfully initialized\n",
483 lvm_version, lvm_name);
485 return 0;
486 } /* init_module() / lvm_init() */
489 #ifdef MODULE
491 * Module cleanup...
493 void cleanup_module(void)
495 struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL;
497 #ifdef CONFIG_DEVFS_FS
498 devfs_unregister (lvm_devfs_handle);
499 #endif
501 if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) {
502 printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name);
504 if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) {
505 printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name);
507 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
509 gendisk_ptr = gendisk_ptr_prev = gendisk_head;
510 while (gendisk_ptr != NULL) {
511 if (gendisk_ptr == &lvm_gendisk)
512 break;
513 gendisk_ptr_prev = gendisk_ptr;
514 gendisk_ptr = gendisk_ptr->next;
516 /* delete our gendisk from chain */
517 if (gendisk_ptr == &lvm_gendisk)
518 gendisk_ptr_prev->next = gendisk_ptr->next;
520 blk_size[MAJOR_NR] = NULL;
521 blksize_size[MAJOR_NR] = NULL;
522 hardsect_size[MAJOR_NR] = NULL;
524 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
525 remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
526 remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
527 remove_proc_entry(LVM_DIR, &proc_root);
528 #endif
530 #ifdef LVM_HD_NAME
531 /* reference from linux/drivers/block/genhd.c */
532 lvm_hd_name_ptr = NULL;
533 #endif
535 printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name);
537 return;
538 } /* void cleanup_module() */
539 #endif /* #ifdef MODULE */
543 * support function to initialize lvm variables
545 #ifdef __initfunc
546 __initfunc(void lvm_init_vars(void))
547 #else
548 void __init lvm_init_vars(void)
549 #endif
551 int v;
553 loadtime = CURRENT_TIME;
555 lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;
557 pe_lock_req.lock = UNLOCK_PE;
558 pe_lock_req.data.lv_dev = \
559 pe_lock_req.data.pv_dev = \
560 pe_lock_req.data.pv_offset = 0;
562 /* Initialize VG pointers */
563 for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL;
565 /* Initialize LV -> VG association */
566 for (v = 0; v < ABS_MAX_LV; v++) {
567 /* index ABS_MAX_VG never used for real VG */
568 vg_lv_map[v].vg_number = ABS_MAX_VG;
569 vg_lv_map[v].lv_number = -1;
572 return;
573 } /* lvm_init_vars() */
576 /********************************************************************
578 * Character device functions
580 ********************************************************************/
583 * character device open routine
585 static int lvm_chr_open(struct inode *inode,
586 struct file *file)
588 int minor = MINOR(inode->i_rdev);
590 #ifdef DEBUG
591 printk(KERN_DEBUG
592 "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n",
593 lvm_name, minor, VG_CHR(minor), file->f_mode, lock);
594 #endif
596 /* super user validation */
597 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
599 /* Group special file open */
600 if (VG_CHR(minor) > MAX_VG) return -ENXIO;
602 lvm_chr_open_count++;
604 MOD_INC_USE_COUNT;
606 return 0;
607 } /* lvm_chr_open() */
611 * character device i/o-control routine
613 * Only one changing process can do changing ioctl at one time,
614 * others will block.
617 static int lvm_chr_ioctl(struct inode *inode, struct file *file,
618 uint command, ulong a)
620 int minor = MINOR(inode->i_rdev);
621 uint extendable, l, v;
622 void *arg = (void *) a;
623 lv_t lv;
624 vg_t* vg_ptr = vg[VG_CHR(minor)];
626 /* otherwise cc will complain about unused variables */
627 (void) lvm_lock;
630 #ifdef DEBUG_IOCTL
631 printk(KERN_DEBUG
632 "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d "
633 "VG#: %d mode: 0x%X\n",
634 lvm_name, command, minor, VG_CHR(minor), file->f_mode);
635 #endif
637 #ifdef LVM_TOTAL_RESET
638 if (lvm_reset_spindown > 0) return -EACCES;
639 #endif
641 /* Main command switch */
642 switch (command) {
643 case LVM_LOCK_LVM:
644 /* lock the LVM */
645 return lvm_do_lock_lvm();
647 case LVM_GET_IOP_VERSION:
648 /* check lvm version to ensure driver/tools+lib
649 interoperability */
650 if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0)
651 return -EFAULT;
652 return 0;
654 #ifdef LVM_TOTAL_RESET
655 case LVM_RESET:
656 /* lock reset function */
657 lvm_reset_spindown = 1;
658 for (v = 0; v < ABS_MAX_VG; v++) {
659 if (vg[v] != NULL) lvm_do_vg_remove(v);
662 #ifdef MODULE
663 while (GET_USE_COUNT(&__this_module) < 1)
664 MOD_INC_USE_COUNT;
665 while (GET_USE_COUNT(&__this_module) > 1)
666 MOD_DEC_USE_COUNT;
667 #endif /* MODULE */
668 lock = 0; /* release lock */
669 wake_up_interruptible(&lvm_wait);
670 return 0;
671 #endif /* LVM_TOTAL_RESET */
674 case LE_REMAP:
675 /* remap a logical extent (after moving the physical extent) */
676 return lvm_do_le_remap(vg_ptr,arg);
678 case PE_LOCK_UNLOCK:
679 /* lock/unlock i/o to a physical extent to move it to another
680 physical volume (move's done in user space's pvmove) */
681 return lvm_do_pe_lock_unlock(vg_ptr,arg);
683 case VG_CREATE:
684 /* create a VGDA */
685 return lvm_do_vg_create(minor, arg);
687 case VG_EXTEND:
688 /* extend a volume group */
689 return lvm_do_vg_extend(vg_ptr, arg);
691 case VG_REDUCE:
692 /* reduce a volume group */
693 return lvm_do_vg_reduce(vg_ptr, arg);
695 case VG_RENAME:
696 /* rename a volume group */
697 return lvm_do_vg_rename(vg_ptr, arg);
699 case VG_REMOVE:
700 /* remove an inactive VGDA */
701 return lvm_do_vg_remove(minor);
704 case VG_SET_EXTENDABLE:
705 /* set/clear extendability flag of volume group */
706 if (vg_ptr == NULL) return -ENXIO;
707 if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0)
708 return -EFAULT;
710 if (extendable == VG_EXTENDABLE ||
711 extendable == ~VG_EXTENDABLE) {
712 if (extendable == VG_EXTENDABLE)
713 vg_ptr->vg_status |= VG_EXTENDABLE;
714 else
715 vg_ptr->vg_status &= ~VG_EXTENDABLE;
716 } else return -EINVAL;
717 return 0;
720 case VG_STATUS:
721 /* get volume group data (only the vg_t struct) */
722 if (vg_ptr == NULL) return -ENXIO;
723 if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0)
724 return -EFAULT;
725 return 0;
728 case VG_STATUS_GET_COUNT:
729 /* get volume group count */
730 if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0)
731 return -EFAULT;
732 return 0;
735 case VG_STATUS_GET_NAMELIST:
736 /* get volume group count */
737 for (l = v = 0; v < ABS_MAX_VG; v++) {
738 if (vg[v] != NULL) {
739 if (copy_to_user(arg + l * NAME_LEN,
740 vg[v]->vg_name,
741 NAME_LEN) != 0)
742 return -EFAULT;
743 l++;
746 return 0;
749 case LV_CREATE:
750 case LV_EXTEND:
751 case LV_REDUCE:
752 case LV_REMOVE:
753 case LV_RENAME:
754 /* create, extend, reduce, remove or rename a logical volume */
755 if (vg_ptr == NULL) return -ENXIO;
756 if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0)
757 return -EFAULT;
759 if (command != LV_REMOVE) {
760 if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0)
761 return -EFAULT;
763 switch (command) {
764 case LV_CREATE:
765 return lvm_do_lv_create(minor, lv_req.lv_name, &lv);
767 case LV_EXTEND:
768 case LV_REDUCE:
769 return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv);
770 case LV_REMOVE:
771 return lvm_do_lv_remove(minor, lv_req.lv_name, -1);
773 case LV_RENAME:
774 return lvm_do_lv_rename(vg_ptr, &lv_req, &lv);
780 case LV_STATUS_BYNAME:
781 /* get status of a logical volume by name */
782 return lvm_do_lv_status_byname(vg_ptr, arg);
785 case LV_STATUS_BYINDEX:
786 /* get status of a logical volume by index */
787 return lvm_do_lv_status_byindex(vg_ptr, arg);
790 case LV_STATUS_BYDEV:
791 return lvm_do_lv_status_bydev(vg_ptr, arg);
794 case PV_CHANGE:
795 /* change a physical volume */
796 return lvm_do_pv_change(vg_ptr,arg);
799 case PV_STATUS:
800 /* get physical volume data (pv_t structure only) */
801 return lvm_do_pv_status(vg_ptr,arg);
804 case PV_FLUSH:
805 /* physical volume buffer flush/invalidate */
806 if (copy_from_user(&pv_flush_req, arg,
807 sizeof(pv_flush_req)) != 0)
808 return -EFAULT;
810 fsync_dev(pv_flush_req.pv_dev);
811 invalidate_buffers(pv_flush_req.pv_dev);
812 return 0;
815 default:
816 printk(KERN_WARNING
817 "%s -- lvm_chr_ioctl: unknown command %x\n",
818 lvm_name, command);
819 return -EINVAL;
822 return 0;
823 } /* lvm_chr_ioctl */
827 * character device close routine
829 static int lvm_chr_close(struct inode *inode, struct file *file)
831 #ifdef DEBUG
832 int minor = MINOR(inode->i_rdev);
833 printk(KERN_DEBUG
834 "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor));
835 #endif
837 #ifdef LVM_TOTAL_RESET
838 if (lvm_reset_spindown > 0) {
839 lvm_reset_spindown = 0;
840 lvm_chr_open_count = 0;
842 #endif
844 if (lvm_chr_open_count > 0) lvm_chr_open_count--;
845 if (lock == current->pid) {
846 lock = 0; /* release lock */
847 wake_up_interruptible(&lvm_wait);
850 MOD_DEC_USE_COUNT;
852 return 0;
853 } /* lvm_chr_close() */
857 /********************************************************************
859 * Block device functions
861 ********************************************************************/
864 * block device open routine
866 static int lvm_blk_open(struct inode *inode, struct file *file)
868 int minor = MINOR(inode->i_rdev);
869 lv_t *lv_ptr;
870 vg_t *vg_ptr = vg[VG_BLK(minor)];
872 #ifdef DEBUG_LVM_BLK_OPEN
873 printk(KERN_DEBUG
874 "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n",
875 lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);
876 #endif
878 #ifdef LVM_TOTAL_RESET
879 if (lvm_reset_spindown > 0)
880 return -EPERM;
881 #endif
883 if (vg_ptr != NULL &&
884 (vg_ptr->vg_status & VG_ACTIVE) &&
885 (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL &&
886 LV_BLK(minor) >= 0 &&
887 LV_BLK(minor) < vg_ptr->lv_max) {
889 /* Check parallel LV spindown (LV remove) */
890 if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM;
892 /* Check inactive LV and open for read/write */
893 if (file->f_mode & O_RDWR) {
894 if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM;
895 if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES;
898 #ifndef BLOCK_DEVICE_OPERATIONS
899 file->f_op = &lvm_blk_fops;
900 #endif
902 /* be sure to increment VG counter */
903 if (lv_ptr->lv_open == 0) vg_ptr->lv_open++;
904 lv_ptr->lv_open++;
906 MOD_INC_USE_COUNT;
908 #ifdef DEBUG_LVM_BLK_OPEN
909 printk(KERN_DEBUG
910 "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n",
911 lvm_name, minor, VG_BLK(minor), LV_BLK(minor),
912 lv_ptr->lv_size);
913 #endif
915 return 0;
917 return -ENXIO;
918 } /* lvm_blk_open() */
922 * block device i/o-control routine
924 static int lvm_blk_ioctl(struct inode *inode, struct file *file,
925 uint command, ulong a)
927 int minor = MINOR(inode->i_rdev);
928 vg_t *vg_ptr = vg[VG_BLK(minor)];
929 lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
930 void *arg = (void *) a;
931 struct hd_geometry *hd = (struct hd_geometry *) a;
933 #ifdef DEBUG_IOCTL
934 printk(KERN_DEBUG
935 "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X "
936 "VG#: %dl LV#: %d\n",
937 lvm_name, minor, command, (ulong) arg,
938 VG_BLK(minor), LV_BLK(minor));
939 #endif
941 switch (command) {
942 case BLKGETSIZE:
943 /* return device size */
944 #ifdef DEBUG_IOCTL
945 printk(KERN_DEBUG
946 "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n",
947 lvm_name, lv_ptr->lv_size);
948 #endif
949 if (put_user(lv_ptr->lv_size, (long *)arg))
950 return -EFAULT;
951 break;
954 case BLKFLSBUF:
955 /* flush buffer cache */
956 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
958 #ifdef DEBUG_IOCTL
959 printk(KERN_DEBUG
960 "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name);
961 #endif
962 fsync_dev(inode->i_rdev);
963 invalidate_buffers(inode->i_rdev);
964 break;
967 case BLKRASET:
968 /* set read ahead for block device */
969 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
971 #ifdef DEBUG_IOCTL
972 printk(KERN_DEBUG
973 "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n",
974 lvm_name, (long) arg, MAJOR(inode->i_rdev), minor);
975 #endif
976 if ((long) arg < LVM_MIN_READ_AHEAD ||
977 (long) arg > LVM_MAX_READ_AHEAD)
978 return -EINVAL;
979 lv_ptr->lv_read_ahead = (long) arg;
980 break;
983 case BLKRAGET:
984 /* get current read ahead setting */
985 #ifdef DEBUG_IOCTL
986 printk(KERN_DEBUG
987 "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);
988 #endif
989 if (put_user(lv_ptr->lv_read_ahead, (long *)arg))
990 return -EFAULT;
991 break;
994 case HDIO_GETGEO:
995 /* get disk geometry */
996 #ifdef DEBUG_IOCTL
997 printk(KERN_DEBUG
998 "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);
999 #endif
1000 if (hd == NULL)
1001 return -EINVAL;
1003 unsigned char heads = 64;
1004 unsigned char sectors = 32;
1005 long start = 0;
1006 short cylinders = lv_ptr->lv_size / heads / sectors;
1008 if (copy_to_user((char *) &hd->heads, &heads,
1009 sizeof(heads)) != 0 ||
1010 copy_to_user((char *) &hd->sectors, &sectors,
1011 sizeof(sectors)) != 0 ||
1012 copy_to_user((short *) &hd->cylinders,
1013 &cylinders, sizeof(cylinders)) != 0 ||
1014 copy_to_user((long *) &hd->start, &start,
1015 sizeof(start)) != 0)
1016 return -EFAULT;
1019 #ifdef DEBUG_IOCTL
1020 printk(KERN_DEBUG
1021 "%s -- lvm_blk_ioctl -- cylinders: %d\n",
1022 lvm_name, lv_ptr->lv_size / heads / sectors);
1023 #endif
1024 break;
1027 case LV_SET_ACCESS:
1028 /* set access flags of a logical volume */
1029 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
1030 lv_ptr->lv_access = (ulong) arg;
1031 if ( lv_ptr->lv_access & LV_WRITE)
1032 set_device_ro(lv_ptr->lv_dev, 0);
1033 else
1034 set_device_ro(lv_ptr->lv_dev, 1);
1035 break;
1038 case LV_SET_STATUS:
1039 /* set status flags of a logical volume */
1040 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
1041 if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1)
1042 return -EPERM;
1043 lv_ptr->lv_status = (ulong) arg;
1044 break;
1046 case LV_BMAP:
1047 /* turn logical block into (dev_t, block). non privileged. */
1048 return lvm_user_bmap(inode, (struct lv_bmap *) arg);
1049 break;
1051 case LV_SET_ALLOCATION:
1052 /* set allocation flags of a logical volume */
1053 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
1054 lv_ptr->lv_allocation = (ulong) arg;
1055 break;
1057 case LV_SNAPSHOT_USE_RATE:
1058 if (!(lv_ptr->lv_access & LV_SNAPSHOT)) return -EPERM;
1060 lv_snapshot_use_rate_req_t lv_snapshot_use_rate_req;
1062 if (copy_from_user(&lv_snapshot_use_rate_req, arg,
1063 sizeof(lv_snapshot_use_rate_req_t)))
1064 return -EFAULT;
1065 if (lv_snapshot_use_rate_req.rate < 0 ||
1066 lv_snapshot_use_rate_req.rate > 100) return -EFAULT;
1068 switch (lv_snapshot_use_rate_req.block)
1070 case 0:
1071 lv_ptr->lv_snapshot_use_rate = lv_snapshot_use_rate_req.rate;
1072 if (lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end < lv_ptr->lv_snapshot_use_rate)
1073 interruptible_sleep_on (&lv_ptr->lv_snapshot_wait);
1074 break;
1076 case O_NONBLOCK:
1077 break;
1079 default:
1080 return -EFAULT;
1082 lv_snapshot_use_rate_req.rate = lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end;
1083 if (copy_to_user(arg, &lv_snapshot_use_rate_req,
1084 sizeof(lv_snapshot_use_rate_req_t)))
1085 return -EFAULT;
1087 break;
1089 default:
1090 printk(KERN_WARNING
1091 "%s -- lvm_blk_ioctl: unknown command %d\n",
1092 lvm_name, command);
1093 return -EINVAL;
1096 return 0;
1097 } /* lvm_blk_ioctl() */
1101 * block device close routine
1103 static int lvm_blk_close(struct inode *inode, struct file *file)
1105 int minor = MINOR(inode->i_rdev);
1106 vg_t *vg_ptr = vg[VG_BLK(minor)];
1107 lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];
1109 #ifdef DEBUG
1110 printk(KERN_DEBUG
1111 "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n",
1112 lvm_name, minor, VG_BLK(minor), LV_BLK(minor));
1113 #endif
1115 sync_dev(inode->i_rdev);
1116 if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
1117 lv_ptr->lv_open--;
1119 MOD_DEC_USE_COUNT;
1121 return 0;
1122 } /* lvm_blk_close() */
1125 static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result)
1127 struct buffer_head bh;
1128 unsigned long block;
1129 int err;
1131 if (get_user(block, &user_result->lv_block))
1132 return -EFAULT;
1134 memset(&bh,0,sizeof bh);
1135 bh.b_rsector = block;
1136 bh.b_dev = bh.b_rdev = inode->i_dev;
1137 bh.b_size = lvm_get_blksize(bh.b_dev);
1138 if ((err=lvm_map(&bh, READ)) < 0) {
1139 printk("lvm map failed: %d\n", err);
1140 return -EINVAL;
1143 return put_user( kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) ||
1144 put_user(bh.b_rsector, &user_result->lv_block) ? -EFAULT : 0;
1149 * provide VG info for proc filesystem use (global)
1151 int lvm_vg_info(vg_t *vg_ptr, char *buf) {
1152 int sz = 0;
1153 char inactive_flag = ' ';
1155 if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I';
1156 sz = sprintf(buf,
1157 "\nVG: %c%s [%d PV, %d LV/%d open] "
1158 " PE Size: %d KB\n"
1159 " Usage [KB/PE]: %d /%d total "
1160 "%d /%d used %d /%d free",
1161 inactive_flag,
1162 vg_ptr->vg_name,
1163 vg_ptr->pv_cur,
1164 vg_ptr->lv_cur,
1165 vg_ptr->lv_open,
1166 vg_ptr->pe_size >> 1,
1167 vg_ptr->pe_size * vg_ptr->pe_total >> 1,
1168 vg_ptr->pe_total,
1169 vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
1170 vg_ptr->pe_allocated,
1171 (vg_ptr->pe_total - vg_ptr->pe_allocated) *
1172 vg_ptr->pe_size >> 1,
1173 vg_ptr->pe_total - vg_ptr->pe_allocated);
1174 return sz;
1179 * provide LV info for proc filesystem use (global)
1181 int lvm_lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) {
1182 int sz = 0;
1183 char inactive_flag = 'A', allocation_flag = ' ',
1184 stripes_flag = ' ', rw_flag = ' ';
1186 if (!(lv_ptr->lv_status & LV_ACTIVE))
1187 inactive_flag = 'I';
1188 rw_flag = 'R';
1189 if (lv_ptr->lv_access & LV_WRITE)
1190 rw_flag = 'W';
1191 allocation_flag = 'D';
1192 if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
1193 allocation_flag = 'C';
1194 stripes_flag = 'L';
1195 if (lv_ptr->lv_stripes > 1)
1196 stripes_flag = 'S';
1197 sz += sprintf(buf+sz,
1198 "[%c%c%c%c",
1199 inactive_flag,
1200 rw_flag,
1201 allocation_flag,
1202 stripes_flag);
1203 if (lv_ptr->lv_stripes > 1)
1204 sz += sprintf(buf+sz, "%-2d",
1205 lv_ptr->lv_stripes);
1206 else
1207 sz += sprintf(buf+sz, " ");
1208 basename = strrchr(lv_ptr->lv_name, '/');
1209 if ( basename == 0) basename = lv_ptr->lv_name;
1210 else basename++;
1211 sz += sprintf(buf+sz, "] %-25s", basename);
1212 if (strlen(basename) > 25)
1213 sz += sprintf(buf+sz,
1214 "\n ");
1215 sz += sprintf(buf+sz, "%9d /%-6d ",
1216 lv_ptr->lv_size >> 1,
1217 lv_ptr->lv_size / vg_ptr->pe_size);
1219 if (lv_ptr->lv_open == 0)
1220 sz += sprintf(buf+sz, "close");
1221 else
1222 sz += sprintf(buf+sz, "%dx open",
1223 lv_ptr->lv_open);
1225 return sz;
1230 * provide PV info for proc filesystem use (global)
1232 int lvm_pv_info(pv_t *pv_ptr, char *buf) {
1233 int sz = 0;
1234 char inactive_flag = 'A', allocation_flag = ' ';
1235 char *pv_name = NULL;
1237 if (!(pv_ptr->pv_status & PV_ACTIVE))
1238 inactive_flag = 'I';
1239 allocation_flag = 'A';
1240 if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE))
1241 allocation_flag = 'N';
1242 pv_name = strrchr(pv_ptr->pv_name+1,'/');
1243 if ( pv_name == 0) pv_name = pv_ptr->pv_name;
1244 else pv_name++;
1245 sz = sprintf(buf,
1246 "[%c%c] %-21s %8d /%-6d "
1247 "%8d /%-6d %8d /%-6d",
1248 inactive_flag,
1249 allocation_flag,
1250 pv_name,
1251 pv_ptr->pe_total *
1252 pv_ptr->pe_size >> 1,
1253 pv_ptr->pe_total,
1254 pv_ptr->pe_allocated *
1255 pv_ptr->pe_size >> 1,
1256 pv_ptr->pe_allocated,
1257 (pv_ptr->pe_total -
1258 pv_ptr->pe_allocated) *
1259 pv_ptr->pe_size >> 1,
1260 pv_ptr->pe_total -
1261 pv_ptr->pe_allocated);
1262 return sz;
1266 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
1268 * Support functions /proc-Filesystem
1271 #define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz])
1274 * provide global LVM information
1276 static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int count, int *eof, void *data)
1278 int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter,
1279 lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds;
1280 static off_t sz;
1281 off_t sz_last;
1282 static char *buf = NULL;
1283 static char dummy_buf[160]; /* sized for 2 lines */
1284 vg_t *vg_ptr;
1285 lv_t *lv_ptr;
1286 pv_t *pv_ptr;
1289 #ifdef DEBUG_LVM_PROC_GET_INFO
1290 printk(KERN_DEBUG
1291 "%s - lvm_proc_get_global_info CALLED pos: %lu count: %d whence: %d\n",
1292 lvm_name, pos, count, whence);
1293 #endif
1295 MOD_INC_USE_COUNT;
1297 if (pos == 0 || buf == NULL) {
1298 sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \
1299 lv_open_total = pe_t_bytes = hash_table_bytes = \
1300 lv_block_exception_t_bytes = 0;
1302 /* search for activity */
1303 for (v = 0; v < ABS_MAX_VG; v++) {
1304 if ((vg_ptr = vg[v]) != NULL) {
1305 vg_counter++;
1306 pv_counter += vg_ptr->pv_cur;
1307 lv_counter += vg_ptr->lv_cur;
1308 if (vg_ptr->lv_cur > 0) {
1309 for (l = 0; l < vg[v]->lv_max; l++) {
1310 if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
1311 pe_t_bytes += lv_ptr->lv_allocated_le;
1312 hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size;
1313 if (lv_ptr->lv_block_exception != NULL)
1314 lv_block_exception_t_bytes += lv_ptr->lv_remap_end;
1315 if (lv_ptr->lv_open > 0) {
1316 lv_open_counter++;
1317 lv_open_total += lv_ptr->lv_open;
1324 pe_t_bytes *= sizeof(pe_t);
1325 lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
1327 if (buf != NULL) {
1328 #ifdef DEBUG_KFREE
1329 printk(KERN_DEBUG
1330 "%s -- vfree %d\n", lvm_name, __LINE__);
1331 #endif
1332 lock_kernel();
1333 vfree(buf);
1334 unlock_kernel();
1335 buf = NULL;
1337 /* 2 times: first to get size to allocate buffer,
1338 2nd to fill the malloced buffer */
1339 for (i = 0; i < 2; i++) {
1340 sz = 0;
1341 sz += sprintf(LVM_PROC_BUF,
1342 "LVM "
1343 #ifdef MODULE
1344 "module"
1345 #else
1346 "driver"
1347 #endif
1348 " %s\n\n"
1349 "Total: %d VG%s %d PV%s %d LV%s ",
1350 lvm_short_version,
1351 vg_counter, vg_counter == 1 ? "" : "s",
1352 pv_counter, pv_counter == 1 ? "" : "s",
1353 lv_counter, lv_counter == 1 ? "" : "s");
1354 sz += sprintf(LVM_PROC_BUF,
1355 "(%d LV%s open",
1356 lv_open_counter,
1357 lv_open_counter == 1 ? "" : "s");
1358 if (lv_open_total > 0)
1359 sz += sprintf(LVM_PROC_BUF,
1360 " %d times)\n",
1361 lv_open_total);
1362 else
1363 sz += sprintf(LVM_PROC_BUF, ")");
1364 sz += sprintf(LVM_PROC_BUF,
1365 "\nGlobal: %lu bytes malloced IOP version: %d ",
1366 vg_counter * sizeof(vg_t) +
1367 pv_counter * sizeof(pv_t) +
1368 lv_counter * sizeof(lv_t) +
1369 pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last,
1370 lvm_iop_version);
1372 seconds = CURRENT_TIME - loadtime;
1373 if (seconds < 0)
1374 loadtime = CURRENT_TIME + seconds;
1375 if (seconds / 86400 > 0) {
1376 sz += sprintf(LVM_PROC_BUF, "%d day%s ",
1377 seconds / 86400,
1378 seconds / 86400 == 0 ||
1379 seconds / 86400 > 1 ? "s" : "");
1381 sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
1382 (seconds % 86400) / 3600,
1383 (seconds % 3600) / 60,
1384 seconds % 60);
1386 if (vg_counter > 0) {
1387 for (v = 0; v < ABS_MAX_VG; v++) {
1388 /* volume group */
1389 if ((vg_ptr = vg[v]) != NULL) {
1390 sz += lvm_vg_info(vg_ptr, LVM_PROC_BUF);
1392 /* physical volumes */
1393 sz += sprintf(LVM_PROC_BUF,
1394 "\n PV%s ",
1395 vg_ptr->pv_cur == 1 ? ": " : "s:");
1396 c = 0;
1397 for (p = 0; p < vg_ptr->pv_max; p++) {
1398 if ((pv_ptr = vg_ptr->pv[p]) != NULL) {
1399 sz += lvm_pv_info(pv_ptr, LVM_PROC_BUF);
1401 c++;
1402 if (c < vg_ptr->pv_cur)
1403 sz += sprintf(LVM_PROC_BUF,
1404 "\n ");
1408 /* logical volumes */
1409 sz += sprintf(LVM_PROC_BUF,
1410 "\n LV%s ",
1411 vg_ptr->lv_cur == 1 ? ": " : "s:");
1412 c = 0;
1413 for (l = 0; l < vg_ptr->lv_max; l++) {
1414 if ((lv_ptr = vg_ptr->lv[l]) != NULL) {
1415 sz += lvm_lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF);
1416 c++;
1417 if (c < vg_ptr->lv_cur)
1418 sz += sprintf(LVM_PROC_BUF,
1419 "\n ");
1422 if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none");
1423 sz += sprintf(LVM_PROC_BUF, "\n");
1427 if (buf == NULL) {
1428 lock_kernel();
1429 buf = vmalloc(sz);
1430 unlock_kernel();
1431 if (buf == NULL) {
1432 sz = 0;
1433 MOD_DEC_USE_COUNT;
1434 return sprintf(page, "%s - vmalloc error at line %d\n",
1435 lvm_name, __LINE__);
1438 sz_last = sz;
1441 MOD_DEC_USE_COUNT;
1442 if (pos > sz - 1) {
1443 lock_kernel();
1444 vfree(buf);
1445 unlock_kernel();
1446 buf = NULL;
1447 return 0;
1449 *start = &buf[pos];
1450 if (sz - pos < count)
1451 return sz - pos;
1452 else
1453 return count;
1454 } /* lvm_proc_get_global_info() */
1455 #endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */
1459 * provide VG information
1461 int lvm_proc_read_vg_info(char *page, char **start, off_t off,
1462 int count, int *eof, void *data) {
1463 int sz = 0;
1464 vg_t *vg = data;
1466 sz += sprintf ( page+sz, "name: %s\n", vg->vg_name);
1467 sz += sprintf ( page+sz, "size: %u\n",
1468 vg->pe_total * vg->pe_size / 2);
1469 sz += sprintf ( page+sz, "access: %u\n", vg->vg_access);
1470 sz += sprintf ( page+sz, "status: %u\n", vg->vg_status);
1471 sz += sprintf ( page+sz, "number: %u\n", vg->vg_number);
1472 sz += sprintf ( page+sz, "LV max: %u\n", vg->lv_max);
1473 sz += sprintf ( page+sz, "LV current: %u\n", vg->lv_cur);
1474 sz += sprintf ( page+sz, "LV open: %u\n", vg->lv_open);
1475 sz += sprintf ( page+sz, "PV max: %u\n", vg->pv_max);
1476 sz += sprintf ( page+sz, "PV current: %u\n", vg->pv_cur);
1477 sz += sprintf ( page+sz, "PV active: %u\n", vg->pv_act);
1478 sz += sprintf ( page+sz, "PE size: %u\n", vg->pe_size / 2);
1479 sz += sprintf ( page+sz, "PE total: %u\n", vg->pe_total);
1480 sz += sprintf ( page+sz, "PE allocated: %u\n", vg->pe_allocated);
1481 sz += sprintf ( page+sz, "uuid: %s\n", vg->vg_uuid);
1483 return sz;
1488 * provide LV information
1490 int lvm_proc_read_lv_info(char *page, char **start, off_t off,
1491 int count, int *eof, void *data) {
1492 int sz = 0;
1493 lv_t *lv = data;
1495 sz += sprintf ( page+sz, "name: %s\n", lv->lv_name);
1496 sz += sprintf ( page+sz, "size: %u\n", lv->lv_size);
1497 sz += sprintf ( page+sz, "access: %u\n", lv->lv_access);
1498 sz += sprintf ( page+sz, "status: %u\n", lv->lv_status);
1499 sz += sprintf ( page+sz, "number: %u\n", lv->lv_number);
1500 sz += sprintf ( page+sz, "open: %u\n", lv->lv_open);
1501 sz += sprintf ( page+sz, "allocation: %u\n", lv->lv_allocation);
1502 sz += sprintf ( page+sz, "device: %02u:%02u\n",
1503 MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
1505 return sz;
1510 * provide PV information
1512 int lvm_proc_read_pv_info(char *page, char **start, off_t off,
1513 int count, int *eof, void *data) {
1514 int sz = 0;
1515 pv_t *pv = data;
1517 sz += sprintf ( page+sz, "name: %s\n", pv->pv_name);
1518 sz += sprintf ( page+sz, "size: %u\n", pv->pv_size);
1519 sz += sprintf ( page+sz, "status: %u\n", pv->pv_status);
1520 sz += sprintf ( page+sz, "number: %u\n", pv->pv_number);
1521 sz += sprintf ( page+sz, "allocatable: %u\n", pv->pv_allocatable);
1522 sz += sprintf ( page+sz, "LV current: %u\n", pv->lv_cur);
1523 sz += sprintf ( page+sz, "PE size: %u\n", pv->pe_size / 2);
1524 sz += sprintf ( page+sz, "PE total: %u\n", pv->pe_total);
1525 sz += sprintf ( page+sz, "PE allocated: %u\n", pv->pe_allocated);
1526 sz += sprintf ( page+sz, "device: %02u:%02u\n",
1527 MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
1528 sz += sprintf ( page+sz, "uuid: %s\n", pv->pv_uuid);
1531 return sz;
1536 * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c
1537 * (see init_module/lvm_init)
1539 static int lvm_map(struct buffer_head *bh, int rw)
1541 int minor = MINOR(bh->b_dev);
1542 int ret = 0;
1543 ulong index;
1544 ulong pe_start;
1545 ulong size = bh->b_size >> 9;
1546 ulong rsector_tmp = bh->b_blocknr * size;
1547 ulong rsector_sav;
1548 kdev_t rdev_tmp = bh->b_dev;
1549 kdev_t rdev_sav;
1550 vg_t *vg_this = vg[VG_BLK(minor)];
1551 lv_t *lv = vg_this->lv[LV_BLK(minor)];
1554 if (!(lv->lv_status & LV_ACTIVE)) {
1555 printk(KERN_ALERT
1556 "%s - lvm_map: ll_rw_blk for inactive LV %s\n",
1557 lvm_name, lv->lv_name);
1558 return -1;
1561 if ((rw == WRITE || rw == WRITEA) &&
1562 !(lv->lv_access & LV_WRITE)) {
1563 printk(KERN_CRIT
1564 "%s - lvm_map: ll_rw_blk write for readonly LV %s\n",
1565 lvm_name, lv->lv_name);
1566 return -1;
1568 #ifdef DEBUG_MAP
1569 printk(KERN_DEBUG
1570 "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu "
1571 "size:%lu\n",
1572 lvm_name, minor,
1573 MAJOR(rdev_tmp),
1574 MINOR(rdev_tmp),
1575 rsector_tmp, size);
1576 #endif
1578 if (rsector_tmp + size > lv->lv_size) {
1579 printk(KERN_ALERT
1580 "%s - lvm_map access beyond end of device; *rsector: "
1581 "%lu or size: %lu wrong for minor: %2d\n",
1582 lvm_name, rsector_tmp, size, minor);
1583 return -1;
1585 rsector_sav = rsector_tmp;
1586 rdev_sav = rdev_tmp;
1588 lvm_second_remap:
1589 /* linear mapping */
1590 if (lv->lv_stripes < 2) {
1591 /* get the index */
1592 index = rsector_tmp / vg_this->pe_size;
1593 pe_start = lv->lv_current_pe[index].pe;
1594 rsector_tmp = lv->lv_current_pe[index].pe +
1595 (rsector_tmp % vg_this->pe_size);
1596 rdev_tmp = lv->lv_current_pe[index].dev;
1598 #ifdef DEBUG_MAP
1599 printk(KERN_DEBUG
1600 "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n",
1601 index,
1602 lv->lv_current_pe[index].pe,
1603 MAJOR(rdev_tmp),
1604 MINOR(rdev_tmp),
1605 rsector_tmp);
1606 #endif
1608 /* striped mapping */
1609 } else {
1610 ulong stripe_index;
1611 ulong stripe_length;
1613 stripe_length = vg_this->pe_size * lv->lv_stripes;
1614 stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize;
1615 index = rsector_tmp / stripe_length +
1616 (stripe_index % lv->lv_stripes) *
1617 (lv->lv_allocated_le / lv->lv_stripes);
1618 pe_start = lv->lv_current_pe[index].pe;
1619 rsector_tmp = lv->lv_current_pe[index].pe +
1620 (rsector_tmp % stripe_length) -
1621 (stripe_index % lv->lv_stripes) * lv->lv_stripesize -
1622 stripe_index / lv->lv_stripes *
1623 (lv->lv_stripes - 1) * lv->lv_stripesize;
1624 rdev_tmp = lv->lv_current_pe[index].dev;
1627 #ifdef DEBUG_MAP
1628 printk(KERN_DEBUG
1629 "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n"
1630 "stripe_length: %ld stripe_index: %ld\n",
1631 index,
1632 lv->lv_current_pe[index].pe,
1633 MAJOR(rdev_tmp),
1634 MINOR(rdev_tmp),
1635 rsector_tmp,
1636 stripe_length,
1637 stripe_index);
1638 #endif
1640 /* handle physical extents on the move */
1641 if (pe_lock_req.lock == LOCK_PE) {
1642 if (rdev_tmp == pe_lock_req.data.pv_dev &&
1643 rsector_tmp >= pe_lock_req.data.pv_offset &&
1644 rsector_tmp < (pe_lock_req.data.pv_offset +
1645 vg_this->pe_size)) {
1646 sleep_on(&lvm_map_wait);
1647 rsector_tmp = rsector_sav;
1648 rdev_tmp = rdev_sav;
1649 goto lvm_second_remap;
1652 /* statistic */
1653 if (rw == WRITE || rw == WRITEA)
1654 lv->lv_current_pe[index].writes++;
1655 else
1656 lv->lv_current_pe[index].reads++;
1658 /* snapshot volume exception handling on physical device address base */
1659 if (lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)) {
1660 /* original logical volume */
1661 if (lv->lv_access & LV_SNAPSHOT_ORG) {
1662 if (rw == WRITE || rw == WRITEA)
1664 lv_t *lv_ptr;
1666 /* start with first snapshot and loop thrugh all of them */
1667 for (lv_ptr = lv->lv_snapshot_next;
1668 lv_ptr != NULL;
1669 lv_ptr = lv_ptr->lv_snapshot_next) {
1670 /* Check for inactive snapshot */
1671 if (!(lv_ptr->lv_status & LV_ACTIVE)) continue;
1672 down(&lv->lv_snapshot_org->lv_snapshot_sem);
1673 /* do we still have exception storage for this snapshot free? */
1674 if (lv_ptr->lv_block_exception != NULL) {
1675 rdev_sav = rdev_tmp;
1676 rsector_sav = rsector_tmp;
1677 if (!lvm_snapshot_remap_block(&rdev_tmp,
1678 &rsector_tmp,
1679 pe_start,
1680 lv_ptr)) {
1681 /* create a new mapping */
1682 if (!(ret = lvm_snapshot_COW(rdev_tmp,
1683 rsector_tmp,
1684 pe_start,
1685 rsector_sav,
1686 lv_ptr)))
1687 ret = lvm_write_COW_table_block(vg_this,
1688 lv_ptr);
1690 rdev_tmp = rdev_sav;
1691 rsector_tmp = rsector_sav;
1693 up(&lv->lv_snapshot_org->lv_snapshot_sem);
1696 } else {
1697 /* remap snapshot logical volume */
1698 down(&lv->lv_snapshot_sem);
1699 if (lv->lv_block_exception != NULL)
1700 lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv);
1701 up(&lv->lv_snapshot_sem);
1704 bh->b_rdev = rdev_tmp;
1705 bh->b_rsector = rsector_tmp;
1707 return ret;
1708 } /* lvm_map() */
1712 * internal support functions
1715 #ifdef LVM_HD_NAME
1717 * generate "hard disk" name
1719 void lvm_hd_name(char *buf, int minor)
1721 int len = 0;
1722 lv_t *lv_ptr;
1724 if (vg[VG_BLK(minor)] == NULL ||
1725 (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL)
1726 return;
1727 len = strlen(lv_ptr->lv_name) - 5;
1728 memcpy(buf, &lv_ptr->lv_name[5], len);
1729 buf[len] = 0;
1730 return;
1732 #endif
1736 * this one never should be called...
1738 static void lvm_dummy_device_request(request_queue_t * t)
1740 printk(KERN_EMERG
1741 "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n",
1742 lvm_name,
1743 MAJOR(CURRENT->rq_dev),
1744 MINOR(CURRENT->rq_dev),
1745 CURRENT->sector);
1746 return;
1751 * make request function
1753 static int lvm_make_request_fn(request_queue_t *q,
1754 int rw,
1755 struct buffer_head *bh)
1757 if (lvm_map(bh, rw)<0)
1758 return 0; /* failure, buffer_IO_error has been called, don't recurse */
1759 else
1760 return 1; /* all ok, mapping done, call lower level driver */
1764 /********************************************************************
1766 * Character device support functions
1768 ********************************************************************/
1770 * character device support function logical volume manager lock
1772 static int lvm_do_lock_lvm(void)
1774 lock_try_again:
1775 spin_lock(&lvm_lock);
1776 if (lock != 0 && lock != current->pid) {
1777 #ifdef DEBUG_IOCTL
1778 printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n",
1779 lvm_name, lock);
1780 #endif
1781 spin_unlock(&lvm_lock);
1782 interruptible_sleep_on(&lvm_wait);
1783 if (current->sigpending != 0)
1784 return -EINTR;
1785 #ifdef LVM_TOTAL_RESET
1786 if (lvm_reset_spindown > 0)
1787 return -EACCES;
1788 #endif
1789 goto lock_try_again;
1791 lock = current->pid;
1792 spin_unlock(&lvm_lock);
1793 return 0;
1794 } /* lvm_do_lock_lvm */
1798 * character device support function lock/unlock physical extend
1800 static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg)
1802 uint p;
1804 if (vg_ptr == NULL) return -ENXIO;
1805 if (copy_from_user(&pe_lock_req, arg,
1806 sizeof(pe_lock_req_t)) != 0) return -EFAULT;
1808 switch (pe_lock_req.lock) {
1809 case LOCK_PE:
1810 for (p = 0; p < vg_ptr->pv_max; p++) {
1811 if (vg_ptr->pv[p] != NULL &&
1812 pe_lock_req.data.pv_dev ==
1813 vg_ptr->pv[p]->pv_dev)
1814 break;
1816 if (p == vg_ptr->pv_max) return -ENXIO;
1818 pe_lock_req.lock = UNLOCK_PE;
1819 fsync_dev(pe_lock_req.data.lv_dev);
1820 pe_lock_req.lock = LOCK_PE;
1821 break;
1823 case UNLOCK_PE:
1824 pe_lock_req.lock = UNLOCK_PE;
1825 pe_lock_req.data.lv_dev = \
1826 pe_lock_req.data.pv_dev = \
1827 pe_lock_req.data.pv_offset = 0;
1828 wake_up(&lvm_map_wait);
1829 break;
1831 default:
1832 return -EINVAL;
1834 return 0;
1839 * character device support function logical extend remap
1841 static int lvm_do_le_remap(vg_t *vg_ptr, void *arg)
1843 uint l, le;
1844 lv_t *lv_ptr;
1846 if (vg_ptr == NULL) return -ENXIO;
1847 if (copy_from_user(&le_remap_req, arg,
1848 sizeof(le_remap_req_t)) != 0)
1849 return -EFAULT;
1851 for (l = 0; l < vg_ptr->lv_max; l++) {
1852 lv_ptr = vg_ptr->lv[l];
1853 if (lv_ptr != NULL &&
1854 strcmp(lv_ptr->lv_name,
1855 le_remap_req.lv_name) == 0) {
1856 for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
1857 if (lv_ptr->lv_current_pe[le].dev ==
1858 le_remap_req.old_dev &&
1859 lv_ptr->lv_current_pe[le].pe ==
1860 le_remap_req.old_pe) {
1861 lv_ptr->lv_current_pe[le].dev =
1862 le_remap_req.new_dev;
1863 lv_ptr->lv_current_pe[le].pe =
1864 le_remap_req.new_pe;
1865 return 0;
1868 return -EINVAL;
1871 return -ENXIO;
1872 } /* lvm_do_le_remap() */
1876 * character device support function VGDA create
1878 int lvm_do_vg_create(int minor, void *arg)
1880 int ret = 0;
1881 ulong l, ls = 0, p, size;
1882 lv_t lv;
1883 vg_t *vg_ptr;
1884 lv_t **snap_lv_ptr;
1886 if (vg[VG_CHR(minor)] != NULL) return -EPERM;
1888 if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) {
1889 printk(KERN_CRIT
1890 "%s -- VG_CREATE: kmalloc error VG at line %d\n",
1891 lvm_name, __LINE__);
1892 return -ENOMEM;
1894 /* get the volume group structure */
1895 if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) {
1896 kfree(vg_ptr);
1897 return -EFAULT;
1900 /* we are not that active so far... */
1901 vg_ptr->vg_status &= ~VG_ACTIVE;
1902 vg[VG_CHR(minor)] = vg_ptr;
1903 vg[VG_CHR(minor)]->pe_allocated = 0;
1905 if (vg_ptr->pv_max > ABS_MAX_PV) {
1906 printk(KERN_WARNING
1907 "%s -- Can't activate VG: ABS_MAX_PV too small\n",
1908 lvm_name);
1909 kfree(vg_ptr);
1910 vg[VG_CHR(minor)] = NULL;
1911 return -EPERM;
1913 if (vg_ptr->lv_max > ABS_MAX_LV) {
1914 printk(KERN_WARNING
1915 "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n",
1916 lvm_name, vg_ptr->lv_max);
1917 kfree(vg_ptr);
1918 vg_ptr = NULL;
1919 return -EPERM;
1922 /* get the physical volume structures */
1923 vg_ptr->pv_act = vg_ptr->pv_cur = 0;
1924 for (p = 0; p < vg_ptr->pv_max; p++) {
1925 /* user space address */
1926 if ((pvp = vg_ptr->pv[p]) != NULL) {
1927 ret = lvm_do_pv_create(pvp, vg_ptr, p);
1928 if ( ret != 0) {
1929 lvm_do_vg_remove(minor);
1930 return ret;
1935 size = vg_ptr->lv_max * sizeof(lv_t *);
1936 if ((snap_lv_ptr = vmalloc ( size)) == NULL) {
1937 printk(KERN_CRIT
1938 "%s -- VG_CREATE: vmalloc error snapshot LVs at line %d\n",
1939 lvm_name, __LINE__);
1940 lvm_do_vg_remove(minor);
1941 return -EFAULT;
1943 memset(snap_lv_ptr, 0, size);
1945 /* get the logical volume structures */
1946 vg_ptr->lv_cur = 0;
1947 for (l = 0; l < vg_ptr->lv_max; l++) {
1948 /* user space address */
1949 if ((lvp = vg_ptr->lv[l]) != NULL) {
1950 if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
1951 lvm_do_vg_remove(minor);
1952 return -EFAULT;
1954 if ( lv.lv_access & LV_SNAPSHOT) {
1955 snap_lv_ptr[ls] = lvp;
1956 vg_ptr->lv[l] = NULL;
1957 ls++;
1958 continue;
1960 vg_ptr->lv[l] = NULL;
1961 /* only create original logical volumes for now */
1962 if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
1963 lvm_do_vg_remove(minor);
1964 return -EFAULT;
1969 /* Second path to correct snapshot logical volumes which are not
1970 in place during first path above */
1971 for (l = 0; l < ls; l++) {
1972 lvp = snap_lv_ptr[l];
1973 if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) {
1974 lvm_do_vg_remove(minor);
1975 return -EFAULT;
1977 if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) {
1978 lvm_do_vg_remove(minor);
1979 return -EFAULT;
1983 #ifdef CONFIG_DEVFS_FS
1984 vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL);
1985 ch_devfs_handle[vg_ptr->vg_number] = devfs_register(
1986 vg_devfs_handle[vg_ptr->vg_number] , "group",
1987 DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number,
1988 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
1989 &lvm_chr_fops, NULL);
1990 #endif
1992 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
1993 lvm_do_create_proc_entry_of_vg ( vg_ptr);
1994 #endif
1996 vfree(snap_lv_ptr);
1998 vg_count++;
2001 MOD_INC_USE_COUNT;
2003 /* let's go active */
2004 vg_ptr->vg_status |= VG_ACTIVE;
2006 return 0;
2007 } /* lvm_do_vg_create() */
2011 * character device support function VGDA extend
2013 static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg)
2015 int ret = 0;
2016 uint p;
2017 pv_t *pv_ptr;
2019 if (vg_ptr == NULL) return -ENXIO;
2020 if (vg_ptr->pv_cur < vg_ptr->pv_max) {
2021 for (p = 0; p < vg_ptr->pv_max; p++) {
2022 if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) {
2023 ret = lvm_do_pv_create(arg, vg_ptr, p);
2024 lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr);
2025 if ( ret != 0) return ret;
2027 /* We don't need the PE list
2028 in kernel space like LVs pe_t list */
2029 pv_ptr->pe = NULL;
2030 vg_ptr->pv_cur++;
2031 vg_ptr->pv_act++;
2032 vg_ptr->pe_total +=
2033 pv_ptr->pe_total;
2034 #ifdef LVM_GET_INODE
2035 /* insert a dummy inode for fs_may_mount */
2036 pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev);
2037 #endif
2038 return 0;
2042 return -EPERM;
2043 } /* lvm_do_vg_extend() */
2047 * character device support function VGDA reduce
2049 static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) {
2050 uint p;
2051 pv_t *pv_ptr;
2053 if (vg_ptr == NULL) return -ENXIO;
2054 if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0)
2055 return -EFAULT;
2057 for (p = 0; p < vg_ptr->pv_max; p++) {
2058 pv_ptr = vg_ptr->pv[p];
2059 if (pv_ptr != NULL &&
2060 strcmp(pv_ptr->pv_name,
2061 pv_name) == 0) {
2062 if (pv_ptr->lv_cur > 0) return -EPERM;
2063 vg_ptr->pe_total -=
2064 pv_ptr->pe_total;
2065 vg_ptr->pv_cur--;
2066 vg_ptr->pv_act--;
2067 lvm_do_pv_remove(vg_ptr, p);
2068 /* Make PV pointer array contiguous */
2069 for (; p < vg_ptr->pv_max - 1; p++)
2070 vg_ptr->pv[p] = vg_ptr->pv[p + 1];
2071 vg_ptr->pv[p + 1] = NULL;
2072 return 0;
2075 return -ENXIO;
2076 } /* lvm_do_vg_reduce */
2080 * character device support function VG rename
2082 static int lvm_do_vg_rename(vg_t *vg_ptr, void *arg)
2084 int l = 0, p = 0, len = 0;
2085 char vg_name[NAME_LEN] = { 0,};
2086 char lv_name[NAME_LEN] = { 0,};
2087 char *ptr = NULL;
2088 lv_t *lv_ptr = NULL;
2089 pv_t *pv_ptr = NULL;
2091 if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0)
2092 return -EFAULT;
2094 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2095 lvm_do_remove_proc_entry_of_vg ( vg_ptr);
2096 #endif
2098 strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1);
2099 for ( l = 0; l < vg_ptr->lv_max; l++)
2101 if ((lv_ptr = vg_ptr->lv[l]) == NULL) continue;
2102 strncpy(lv_ptr->vg_name, vg_name, sizeof ( vg_name));
2103 ptr = strrchr(lv_ptr->lv_name, '/');
2104 if (ptr == NULL) ptr = lv_ptr->lv_name;
2105 strncpy(lv_name, ptr, sizeof ( lv_name));
2106 len = sizeof(LVM_DIR_PREFIX);
2107 strcpy(lv_ptr->lv_name, LVM_DIR_PREFIX);
2108 strncat(lv_ptr->lv_name, vg_name, NAME_LEN - len);
2109 len += strlen ( vg_name);
2110 strncat(lv_ptr->lv_name, lv_name, NAME_LEN - len);
2112 for ( p = 0; p < vg_ptr->pv_max; p++)
2114 if ( (pv_ptr = vg_ptr->pv[p]) == NULL) continue;
2115 strncpy(pv_ptr->vg_name, vg_name, NAME_LEN);
2118 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2119 lvm_do_create_proc_entry_of_vg ( vg_ptr);
2120 #endif
2122 return 0;
2123 } /* lvm_do_vg_rename */
2127 * character device support function VGDA remove
2129 static int lvm_do_vg_remove(int minor)
2131 int i;
2132 vg_t *vg_ptr = vg[VG_CHR(minor)];
2133 pv_t *pv_ptr;
2135 if (vg_ptr == NULL) return -ENXIO;
2137 #ifdef LVM_TOTAL_RESET
2138 if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0)
2139 #else
2140 if (vg_ptr->lv_open > 0)
2141 #endif
2142 return -EPERM;
2144 /* let's go inactive */
2145 vg_ptr->vg_status &= ~VG_ACTIVE;
2147 /* free LVs */
2148 /* first free snapshot logical volumes */
2149 for (i = 0; i < vg_ptr->lv_max; i++) {
2150 if (vg_ptr->lv[i] != NULL &&
2151 vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) {
2152 lvm_do_lv_remove(minor, NULL, i);
2153 current->state = TASK_UNINTERRUPTIBLE;
2154 schedule_timeout(1);
2157 /* then free the rest of the LVs */
2158 for (i = 0; i < vg_ptr->lv_max; i++) {
2159 if (vg_ptr->lv[i] != NULL) {
2160 lvm_do_lv_remove(minor, NULL, i);
2161 current->state = TASK_UNINTERRUPTIBLE;
2162 schedule_timeout(1);
2166 /* free PVs */
2167 for (i = 0; i < vg_ptr->pv_max; i++) {
2168 if ((pv_ptr = vg_ptr->pv[i]) != NULL) {
2169 #ifdef DEBUG_KFREE
2170 printk(KERN_DEBUG
2171 "%s -- kfree %d\n", lvm_name, __LINE__);
2172 #endif
2173 lvm_do_pv_remove(vg_ptr, i);
2177 #ifdef CONFIG_DEVFS_FS
2178 devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]);
2179 devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]);
2180 #endif
2182 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2183 lvm_do_remove_proc_entry_of_vg ( vg_ptr);
2184 #endif
2186 #ifdef DEBUG_KFREE
2187 printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
2188 #endif
2190 kfree(vg_ptr);
2191 vg[VG_CHR(minor)] = NULL;
2193 vg_count--;
2195 MOD_DEC_USE_COUNT;
2197 return 0;
2198 } /* lvm_do_vg_remove() */
2202 * character device support function physical volume create
2204 static int lvm_do_pv_create(pv_t *pvp, vg_t *vg_ptr, ulong p) {
2205 pv_t *pv_ptr = NULL;
2207 pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL);
2208 if (pv_ptr == NULL) {
2209 printk(KERN_CRIT
2210 "%s -- VG_CREATE: kmalloc error PV at line %d\n",
2211 lvm_name, __LINE__);
2212 return -ENOMEM;
2214 if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) {
2215 return -EFAULT;
2217 /* We don't need the PE list
2218 in kernel space as with LVs pe_t list (see below) */
2219 pv_ptr->pe = NULL;
2220 pv_ptr->pe_allocated = 0;
2221 pv_ptr->pv_status = PV_ACTIVE;
2222 vg_ptr->pv_act++;
2223 vg_ptr->pv_cur++;
2225 #ifdef LVM_GET_INODE
2226 /* insert a dummy inode for fs_may_mount */
2227 pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev);
2228 #endif
2230 return 0;
2231 } /* lvm_do_pv_create() */
2235 * character device support function physical volume create
2237 static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) {
2238 pv_t *pv_ptr = vg_ptr->pv[p];
2240 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2241 lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv_ptr);
2242 #endif
2243 vg_ptr->pe_total -=
2244 pv_ptr->pe_total;
2245 vg_ptr->pv_cur--;
2246 vg_ptr->pv_act--;
2247 #ifdef LVM_GET_INODE
2248 lvm_clear_inode(pv_ptr->inode);
2249 #endif
2250 kfree(pv_ptr);
2251 vg_ptr->pv[p] = NULL;
2253 return 0;
2258 * character device support function logical volume create
2260 static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
2262 int e, ret, l, le, l_new, p, size;
2263 ulong lv_status_save;
2264 lv_block_exception_t *lvbe = lv->lv_block_exception;
2265 vg_t *vg_ptr = vg[VG_CHR(minor)];
2266 lv_t *lv_ptr = NULL;
2268 if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
2269 if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK)
2270 return -EINVAL;
2272 for (l = 0; l < vg_ptr->lv_max; l++) {
2273 if (vg_ptr->lv[l] != NULL &&
2274 strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
2275 return -EEXIST;
2278 /* in case of lv_remove(), lv_create() pair */
2279 l_new = -1;
2280 if (vg_ptr->lv[lv->lv_number] == NULL)
2281 l_new = lv->lv_number;
2282 else {
2283 for (l = 0; l < vg_ptr->lv_max; l++) {
2284 if (vg_ptr->lv[l] == NULL)
2285 if (l_new == -1) l_new = l;
2288 if (l_new == -1) return -EPERM;
2289 else l = l_new;
2291 if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {;
2292 printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n",
2293 lvm_name, __LINE__);
2294 return -ENOMEM;
2296 /* copy preloaded LV */
2297 memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
2299 lv_status_save = lv_ptr->lv_status;
2300 lv_ptr->lv_status &= ~LV_ACTIVE;
2301 lv_ptr->lv_snapshot_org = \
2302 lv_ptr->lv_snapshot_prev = \
2303 lv_ptr->lv_snapshot_next = NULL;
2304 lv_ptr->lv_block_exception = NULL;
2305 lv_ptr->lv_iobuf = NULL;
2306 lv_ptr->lv_snapshot_hash_table = NULL;
2307 lv_ptr->lv_snapshot_hash_table_size = 0;
2308 lv_ptr->lv_snapshot_hash_mask = 0;
2309 lv_ptr->lv_COW_table_page = NULL;
2310 init_MUTEX(&lv_ptr->lv_snapshot_sem);
2311 lv_ptr->lv_snapshot_use_rate = 0;
2312 vg_ptr->lv[l] = lv_ptr;
2314 /* get the PE structures from user space if this
2315 is no snapshot logical volume */
2316 if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
2317 size = lv_ptr->lv_allocated_le * sizeof(pe_t);
2318 if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) {
2319 printk(KERN_CRIT
2320 "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte "
2321 "at line %d\n",
2322 lvm_name, size, __LINE__);
2323 #ifdef DEBUG_KFREE
2324 printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
2325 #endif
2326 kfree(lv_ptr);
2327 vg[VG_CHR(minor)]->lv[l] = NULL;
2328 return -ENOMEM;
2330 if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) {
2331 vfree(lv_ptr->lv_current_pe);
2332 kfree(lv_ptr);
2333 vg_ptr->lv[l] = NULL;
2334 return -EFAULT;
2336 /* correct the PE count in PVs */
2337 for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2338 vg_ptr->pe_allocated++;
2339 for (p = 0; p < vg_ptr->pv_cur; p++) {
2340 if (vg_ptr->pv[p]->pv_dev ==
2341 lv_ptr->lv_current_pe[le].dev)
2342 vg_ptr->pv[p]->pe_allocated++;
2345 } else {
2346 /* Get snapshot exception data and block list */
2347 if (lvbe != NULL) {
2348 lv_ptr->lv_snapshot_org =
2349 vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)];
2350 if (lv_ptr->lv_snapshot_org != NULL) {
2351 size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t);
2352 if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) {
2353 printk(KERN_CRIT
2354 "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION "
2355 "of %d byte at line %d\n",
2356 lvm_name, size, __LINE__);
2357 #ifdef DEBUG_KFREE
2358 printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
2359 #endif
2360 kfree(lv_ptr);
2361 vg_ptr->lv[l] = NULL;
2362 return -ENOMEM;
2364 if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) {
2365 vfree(lv_ptr->lv_block_exception);
2366 kfree(lv_ptr);
2367 vg[VG_CHR(minor)]->lv[l] = NULL;
2368 return -EFAULT;
2370 /* point to the original logical volume */
2371 lv_ptr = lv_ptr->lv_snapshot_org;
2373 lv_ptr->lv_snapshot_minor = 0;
2374 lv_ptr->lv_snapshot_org = lv_ptr;
2375 lv_ptr->lv_snapshot_prev = NULL;
2376 /* walk thrugh the snapshot list */
2377 while (lv_ptr->lv_snapshot_next != NULL)
2378 lv_ptr = lv_ptr->lv_snapshot_next;
2379 /* now lv_ptr points to the last existing snapshot in the chain */
2380 vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr;
2381 /* our new one now back points to the previous last in the chain
2382 which can be the original logical volume */
2383 lv_ptr = vg_ptr->lv[l];
2384 /* now lv_ptr points to our new last snapshot logical volume */
2385 lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org;
2386 lv_ptr->lv_snapshot_next = NULL;
2387 lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
2388 lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
2389 lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
2390 lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
2391 lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes;
2392 lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize;
2393 if ((ret = lvm_snapshot_alloc(lv_ptr)) != 0)
2395 vfree(lv_ptr->lv_block_exception);
2396 kfree(lv_ptr);
2397 vg[VG_CHR(minor)]->lv[l] = NULL;
2398 return ret;
2400 for ( e = 0; e < lv_ptr->lv_remap_ptr; e++)
2401 lvm_hash_link (lv_ptr->lv_block_exception + e, lv_ptr->lv_block_exception[e].rdev_org, lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
2402 /* need to fill the COW exception table data
2403 into the page for disk i/o */
2404 lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr);
2405 init_waitqueue_head(&lv_ptr->lv_snapshot_wait);
2406 } else {
2407 vfree(lv_ptr->lv_block_exception);
2408 kfree(lv_ptr);
2409 vg_ptr->lv[l] = NULL;
2410 return -EFAULT;
2412 } else {
2413 kfree(vg_ptr->lv[l]);
2414 vg_ptr->lv[l] = NULL;
2415 return -EINVAL;
2417 } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */
2419 lv_ptr = vg_ptr->lv[l];
2420 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
2421 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
2422 lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
2423 vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number;
2424 vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number;
2425 LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
2426 vg_ptr->lv_cur++;
2427 lv_ptr->lv_status = lv_status_save;
2429 #ifdef CONFIG_DEVFS_FS
2431 char *lv_tmp, *lv_buf = NULL;
2433 strtok(lv->lv_name, "/"); /* /dev */
2434 while((lv_tmp = strtok(NULL, "/")) != NULL)
2435 lv_buf = lv_tmp;
2437 lv_devfs_handle[lv->lv_number] = devfs_register(
2438 vg_devfs_handle[vg_ptr->vg_number], lv_buf,
2439 DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number,
2440 S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
2441 &lvm_blk_dops, NULL);
2443 #endif
2445 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2446 lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
2447 #endif
2449 /* optionally add our new snapshot LV */
2450 if (lv_ptr->lv_access & LV_SNAPSHOT) {
2451 /* sync the original logical volume */
2452 fsync_dev(lv_ptr->lv_snapshot_org->lv_dev);
2453 #ifdef LVM_VFS_ENHANCEMENT
2454 /* VFS function call to sync and lock the filesystem */
2455 fsync_dev_lockfs(lv_ptr->lv_snapshot_org->lv_dev);
2456 #endif
2457 lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG;
2458 lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG;
2459 /* put ourselve into the chain */
2460 lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr;
2463 /* activate the logical volume */
2464 lv_ptr->lv_status |= LV_ACTIVE;
2465 if ( lv_ptr->lv_access & LV_WRITE)
2466 set_device_ro(lv_ptr->lv_dev, 0);
2467 else
2468 set_device_ro(lv_ptr->lv_dev, 1);
2470 #ifdef LVM_VFS_ENHANCEMENT
2471 /* VFS function call to unlock the filesystem */
2472 if (lv_ptr->lv_access & LV_SNAPSHOT) {
2473 unlockfs(lv_ptr->lv_snapshot_org->lv_dev);
2475 #endif
2477 lv_ptr->vg = vg_ptr;
2479 return 0;
2480 } /* lvm_do_lv_create() */
2484 * character device support function logical volume remove
2486 static int lvm_do_lv_remove(int minor, char *lv_name, int l)
2488 uint le, p;
2489 vg_t *vg_ptr = vg[VG_CHR(minor)];
2490 lv_t *lv_ptr;
2492 if (l == -1) {
2493 for (l = 0; l < vg_ptr->lv_max; l++) {
2494 if (vg_ptr->lv[l] != NULL &&
2495 strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) {
2496 break;
2500 if (l == vg_ptr->lv_max) return -ENXIO;
2502 lv_ptr = vg_ptr->lv[l];
2503 #ifdef LVM_TOTAL_RESET
2504 if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0)
2505 #else
2506 if (lv_ptr->lv_open > 0)
2507 #endif
2508 return -EBUSY;
2510 /* check for deletion of snapshot source while
2511 snapshot volume still exists */
2512 if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) &&
2513 lv_ptr->lv_snapshot_next != NULL)
2514 return -EPERM;
2516 lv_ptr->lv_status |= LV_SPINDOWN;
2518 /* sync the buffers */
2519 fsync_dev(lv_ptr->lv_dev);
2521 lv_ptr->lv_status &= ~LV_ACTIVE;
2523 /* invalidate the buffers */
2524 invalidate_buffers(lv_ptr->lv_dev);
2526 /* reset generic hd */
2527 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1;
2528 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0;
2529 lvm_size[MINOR(lv_ptr->lv_dev)] = 0;
2531 /* reset VG/LV mapping */
2532 vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG;
2533 vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1;
2535 /* correct the PE count in PVs if this is no snapshot logical volume */
2536 if (!(lv_ptr->lv_access & LV_SNAPSHOT)) {
2537 /* only if this is no snapshot logical volume because
2538 we share the lv_current_pe[] structs with the
2539 original logical volume */
2540 for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2541 vg_ptr->pe_allocated--;
2542 for (p = 0; p < vg_ptr->pv_cur; p++) {
2543 if (vg_ptr->pv[p]->pv_dev ==
2544 lv_ptr->lv_current_pe[le].dev)
2545 vg_ptr->pv[p]->pe_allocated--;
2548 vfree(lv_ptr->lv_current_pe);
2549 /* LV_SNAPSHOT */
2550 } else {
2551 /* remove this snapshot logical volume from the chain */
2552 lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next;
2553 if (lv_ptr->lv_snapshot_next != NULL) {
2554 lv_ptr->lv_snapshot_next->lv_snapshot_prev =
2555 lv_ptr->lv_snapshot_prev;
2557 /* no more snapshots? */
2558 if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL)
2559 lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG;
2560 lvm_snapshot_release(lv_ptr);
2563 #ifdef CONFIG_DEVFS_FS
2564 devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]);
2565 #endif
2567 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2568 lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr);
2569 #endif
2571 #ifdef DEBUG_KFREE
2572 printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__);
2573 #endif
2574 kfree(lv_ptr);
2575 vg_ptr->lv[l] = NULL;
2576 vg_ptr->lv_cur--;
2577 return 0;
2578 } /* lvm_do_lv_remove() */
2582 * character device support function logical volume extend / reduce
2584 static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv)
2586 ulong end, l, le, p, size, old_allocated_le;
2587 vg_t *vg_ptr = vg[VG_CHR(minor)];
2588 lv_t *lv_ptr;
2589 pe_t *pe;
2591 if ((pep = lv->lv_current_pe) == NULL) return -EINVAL;
2593 for (l = 0; l < vg_ptr->lv_max; l++) {
2594 if (vg_ptr->lv[l] != NULL &&
2595 strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0)
2596 break;
2598 if (l == vg_ptr->lv_max) return -ENXIO;
2599 lv_ptr = vg_ptr->lv[l];
2601 /* check for active snapshot */
2602 if (lv->lv_access & LV_SNAPSHOT)
2604 ulong e;
2605 lv_block_exception_t *lvbe, *lvbe_old;
2606 struct list_head * lvs_hash_table_old;
2608 if (lv->lv_block_exception == NULL) return -ENXIO;
2609 size = lv->lv_remap_end * sizeof ( lv_block_exception_t);
2610 if ((lvbe = vmalloc(size)) == NULL)
2612 printk(KERN_CRIT
2613 "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_BLOCK_EXCEPTION "
2614 "of %lu Byte at line %d\n",
2615 lvm_name, size, __LINE__);
2616 return -ENOMEM;
2618 if (lv->lv_remap_end > lv_ptr->lv_remap_end)
2620 if (copy_from_user(lvbe, lv->lv_block_exception, size))
2622 vfree(lvbe);
2623 return -EFAULT;
2627 lvbe_old = lv_ptr->lv_block_exception;
2628 lvs_hash_table_old = lv_ptr->lv_snapshot_hash_table;
2630 /* we need to play on the safe side here... */
2631 down(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2632 if (lv_ptr->lv_block_exception == NULL ||
2633 lv_ptr->lv_remap_ptr > lv_ptr->lv_remap_end)
2635 up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2636 vfree(lvbe);
2637 return -EPERM;
2639 memcpy(lvbe,
2640 lv_ptr->lv_block_exception,
2641 (lv->lv_remap_end > lv_ptr->lv_remap_end ? lv_ptr->lv_remap_ptr : lv->lv_remap_end) * sizeof(lv_block_exception_t));
2643 lv_ptr->lv_block_exception = lvbe;
2644 lv_ptr->lv_remap_end = lv->lv_remap_end;
2645 if (lvm_snapshot_alloc_hash_table(lv_ptr) != 0)
2647 lvm_drop_snapshot(lv_ptr, "hash_alloc");
2648 up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2649 vfree(lvbe_old);
2650 vfree(lvs_hash_table_old);
2651 return 1;
2654 for (e = 0; e < lv_ptr->lv_remap_ptr; e++)
2655 lvm_hash_link (lv_ptr->lv_block_exception + e, lv_ptr->lv_block_exception[e].rdev_org, lv_ptr->lv_block_exception[e].rsector_org, lv_ptr);
2657 up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem);
2659 vfree(lvbe_old);
2660 vfree(lvs_hash_table_old);
2662 return 0;
2666 /* we drop in here in case it is an original logical volume */
2667 if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) {
2668 printk(KERN_CRIT
2669 "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE "
2670 "of %lu Byte at line %d\n",
2671 lvm_name, size, __LINE__);
2672 return -ENOMEM;
2674 /* get the PE structures from user space */
2675 if (copy_from_user(pe, pep, size)) {
2676 vfree(pe);
2677 return -EFAULT;
2680 #ifdef DEBUG
2681 printk(KERN_DEBUG
2682 "%s -- fsync_dev and "
2683 "invalidate_buffers for %s [%s] in %s\n",
2684 lvm_name, lv_ptr->lv_name,
2685 kdevname(lv_ptr->lv_dev),
2686 vg_ptr->vg_name);
2687 #endif
2689 /* reduce allocation counters on PV(s) */
2690 for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2691 vg_ptr->pe_allocated--;
2692 for (p = 0; p < vg_ptr->pv_cur; p++) {
2693 if (vg_ptr->pv[p]->pv_dev ==
2694 lv_ptr->lv_current_pe[le].dev) {
2695 vg_ptr->pv[p]->pe_allocated--;
2696 break;
2702 /* save pointer to "old" lv/pe pointer array */
2703 pep1 = lv_ptr->lv_current_pe;
2704 end = lv_ptr->lv_current_le;
2706 /* save open counter... */
2707 lv->lv_open = lv_ptr->lv_open;
2708 lv->lv_snapshot_prev = lv_ptr->lv_snapshot_prev;
2709 lv->lv_snapshot_next = lv_ptr->lv_snapshot_next;
2710 lv->lv_snapshot_org = lv_ptr->lv_snapshot_org;
2712 lv->lv_current_pe = pe;
2714 /* save # of old allocated logical extents */
2715 old_allocated_le = lv_ptr->lv_allocated_le;
2717 /* in case of shrinking -> let's flush */
2718 if ( end > lv->lv_current_le) fsync_dev(lv_ptr->lv_dev);
2720 /* copy preloaded LV */
2721 memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t));
2723 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0;
2724 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
2725 lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
2726 /* vg_lv_map array doesn't have to be changed here */
2728 LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead);
2730 /* save availiable i/o statistic data */
2731 /* linear logical volume */
2732 if (lv_ptr->lv_stripes < 2) {
2733 /* Check what last LE shall be used */
2734 if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le;
2735 for (le = 0; le < end; le++) {
2736 lv_ptr->lv_current_pe[le].reads += pep1[le].reads;
2737 lv_ptr->lv_current_pe[le].writes += pep1[le].writes;
2739 /* striped logical volume */
2740 } else {
2741 uint i, j, source, dest, end, old_stripe_size, new_stripe_size;
2743 old_stripe_size = old_allocated_le / lv_ptr->lv_stripes;
2744 new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes;
2745 end = old_stripe_size;
2746 if (end > new_stripe_size) end = new_stripe_size;
2747 for (i = source = dest = 0;
2748 i < lv_ptr->lv_stripes; i++) {
2749 for (j = 0; j < end; j++) {
2750 lv_ptr->lv_current_pe[dest + j].reads +=
2751 pep1[source + j].reads;
2752 lv_ptr->lv_current_pe[dest + j].writes +=
2753 pep1[source + j].writes;
2755 source += old_stripe_size;
2756 dest += new_stripe_size;
2760 /* extend the PE count in PVs */
2761 for (le = 0; le < lv_ptr->lv_allocated_le; le++) {
2762 vg_ptr->pe_allocated++;
2763 for (p = 0; p < vg_ptr->pv_cur; p++) {
2764 if (vg_ptr->pv[p]->pv_dev ==
2765 lv_ptr->lv_current_pe[le].dev) {
2766 vg_ptr->pv[p]->pe_allocated++;
2767 break;
2772 vfree ( pep1);
2773 pep1 = NULL;
2775 if (lv->lv_access & LV_SNAPSHOT_ORG)
2777 /* Correct the snapshot size information */
2778 while ((lv_ptr = lv_ptr->lv_snapshot_next) != NULL)
2780 lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe;
2781 lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le;
2782 lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le;
2783 lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size;
2784 lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size;
2785 lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1;
2789 return 0;
2790 } /* lvm_do_lv_extend_reduce() */
2794 * character device support function logical volume status by name
2796 static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg)
2798 uint l;
2799 ulong size;
2800 lv_t lv;
2801 lv_t *lv_ptr;
2802 lv_status_byname_req_t lv_status_byname_req;
2804 if (vg_ptr == NULL) return -ENXIO;
2805 if (copy_from_user(&lv_status_byname_req, arg,
2806 sizeof(lv_status_byname_req_t)) != 0)
2807 return -EFAULT;
2809 if (lv_status_byname_req.lv == NULL) return -EINVAL;
2810 if (copy_from_user(&lv, lv_status_byname_req.lv,
2811 sizeof(lv_t)) != 0)
2812 return -EFAULT;
2814 for (l = 0; l < vg_ptr->lv_max; l++) {
2815 lv_ptr = vg_ptr->lv[l];
2816 if (lv_ptr != NULL &&
2817 strcmp(lv_ptr->lv_name,
2818 lv_status_byname_req.lv_name) == 0) {
2819 if (copy_to_user(lv_status_byname_req.lv,
2820 lv_ptr,
2821 sizeof(lv_t)) != 0)
2822 return -EFAULT;
2824 if (lv.lv_current_pe != NULL) {
2825 size = lv_ptr->lv_allocated_le *
2826 sizeof(pe_t);
2827 if (copy_to_user(lv.lv_current_pe,
2828 lv_ptr->lv_current_pe,
2829 size) != 0)
2830 return -EFAULT;
2832 return 0;
2835 return -ENXIO;
2836 } /* lvm_do_lv_status_byname() */
2840 * character device support function logical volume status by index
2842 static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg)
2844 ulong size;
2845 lv_t lv;
2846 lv_t *lv_ptr;
2847 lv_status_byindex_req_t lv_status_byindex_req;
2849 if (vg_ptr == NULL) return -ENXIO;
2850 if (copy_from_user(&lv_status_byindex_req, arg,
2851 sizeof(lv_status_byindex_req)) != 0)
2852 return -EFAULT;
2854 if ((lvp = lv_status_byindex_req.lv) == NULL)
2855 return -EINVAL;
2856 if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL)
2857 return -ENXIO;
2859 if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0)
2860 return -EFAULT;
2862 if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0)
2863 return -EFAULT;
2865 if (lv.lv_current_pe != NULL) {
2866 size = lv_ptr->lv_allocated_le * sizeof(pe_t);
2867 if (copy_to_user(lv.lv_current_pe,
2868 lv_ptr->lv_current_pe,
2869 size) != 0)
2870 return -EFAULT;
2872 return 0;
2873 } /* lvm_do_lv_status_byindex() */
2877 * character device support function logical volume status by device number
2879 static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) {
2880 int l;
2881 lv_status_bydev_req_t lv_status_bydev_req;
2883 if (vg_ptr == NULL) return -ENXIO;
2884 if (copy_from_user(&lv_status_bydev_req, arg,
2885 sizeof(lv_status_bydev_req)) != 0)
2886 return -EFAULT;
2888 for ( l = 0; l < vg_ptr->lv_max; l++) {
2889 if ( vg_ptr->lv[l] == NULL) continue;
2890 if ( vg_ptr->lv[l]->lv_dev == lv_status_bydev_req.dev) break;
2893 if ( l == vg_ptr->lv_max) return -ENXIO;
2895 if (copy_to_user(lv_status_bydev_req.lv,
2896 vg_ptr->lv[l], sizeof(lv_t)) != 0)
2897 return -EFAULT;
2899 return 0;
2900 } /* lvm_do_lv_status_bydev() */
2904 * character device support function rename a logical volume
2906 static int lvm_do_lv_rename(vg_t *vg_ptr, lv_req_t *lv_req, lv_t *lv)
2908 int l = 0;
2909 int ret = 0;
2910 lv_t *lv_ptr = NULL;
2912 for (l = 0; l < vg_ptr->lv_max; l++)
2914 if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue;
2915 if (lv_ptr->lv_dev == lv->lv_dev)
2917 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2918 lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr);
2919 #endif
2920 strncpy(lv_ptr->lv_name,
2921 lv_req->lv_name,
2922 NAME_LEN);
2923 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
2924 lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
2925 #endif
2926 break;
2929 if (l == vg_ptr->lv_max) ret = -ENODEV;
2931 return ret;
2932 } /* lvm_do_lv_rename */
2936 * character device support function physical volume change
2938 static int lvm_do_pv_change(vg_t *vg_ptr, void *arg)
2940 uint p;
2941 pv_t *pv_ptr;
2942 #ifdef LVM_GET_INODE
2943 struct inode *inode_sav;
2944 #endif
2946 if (vg_ptr == NULL) return -ENXIO;
2947 if (copy_from_user(&pv_change_req, arg,
2948 sizeof(pv_change_req)) != 0)
2949 return -EFAULT;
2951 for (p = 0; p < vg_ptr->pv_max; p++) {
2952 pv_ptr = vg_ptr->pv[p];
2953 if (pv_ptr != NULL &&
2954 strcmp(pv_ptr->pv_name,
2955 pv_change_req.pv_name) == 0) {
2956 #ifdef LVM_GET_INODE
2957 inode_sav = pv_ptr->inode;
2958 #endif
2959 if (copy_from_user(pv_ptr,
2960 pv_change_req.pv,
2961 sizeof(pv_t)) != 0)
2962 return -EFAULT;
2964 /* We don't need the PE list
2965 in kernel space as with LVs pe_t list */
2966 pv_ptr->pe = NULL;
2967 #ifdef LVM_GET_INODE
2968 pv_ptr->inode = inode_sav;
2969 #endif
2970 return 0;
2973 return -ENXIO;
2974 } /* lvm_do_pv_change() */
2977 * character device support function get physical volume status
2979 static int lvm_do_pv_status(vg_t *vg_ptr, void *arg)
2981 uint p;
2982 pv_t *pv_ptr;
2984 if (vg_ptr == NULL) return -ENXIO;
2985 if (copy_from_user(&pv_status_req, arg,
2986 sizeof(pv_status_req)) != 0)
2987 return -EFAULT;
2989 for (p = 0; p < vg_ptr->pv_max; p++) {
2990 pv_ptr = vg_ptr->pv[p];
2991 if (pv_ptr != NULL &&
2992 strcmp(pv_ptr->pv_name,
2993 pv_status_req.pv_name) == 0) {
2994 if (copy_to_user(pv_status_req.pv,
2995 pv_ptr,
2996 sizeof(pv_t)) != 0)
2997 return -EFAULT;
2998 return 0;
3001 return -ENXIO;
3002 } /* lvm_do_pv_status() */
3007 * create a /proc entry for a logical volume
3009 inline void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) {
3010 char *basename;
3012 if ( vg_ptr->lv_subdir_pde != NULL) {
3013 basename = strrchr(lv_ptr->lv_name, '/');
3014 if (basename == NULL) basename = lv_ptr->lv_name;
3015 else basename++;
3016 pde = create_proc_entry(basename, S_IFREG,
3017 vg_ptr->lv_subdir_pde);
3018 if ( pde != NULL) {
3019 pde->read_proc = lvm_proc_read_lv_info;
3020 pde->data = lv_ptr;
3027 * remove a /proc entry for a logical volume
3029 inline void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) {
3030 char *basename;
3032 if ( vg_ptr->lv_subdir_pde != NULL) {
3033 basename = strrchr(lv_ptr->lv_name, '/');
3034 if (basename == NULL) basename = lv_ptr->lv_name;
3035 else basename++;
3036 remove_proc_entry(basename, vg_ptr->lv_subdir_pde);
3042 * create a /proc entry for a physical volume
3044 inline void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) {
3045 char *basename;
3047 basename = strrchr(pv_ptr->pv_name, '/');
3048 if (basename == NULL) basename = pv_ptr->pv_name;
3049 else basename++;
3050 pde = create_proc_entry(basename, S_IFREG, vg_ptr->pv_subdir_pde);
3051 if ( pde != NULL) {
3052 pde->read_proc = lvm_proc_read_pv_info;
3053 pde->data = pv_ptr;
3059 * remove a /proc entry for a physical volume
3061 inline void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) {
3062 char *basename;
3064 basename = strrchr(pv_ptr->pv_name, '/');
3065 if ( vg_ptr->pv_subdir_pde != NULL) {
3066 basename = strrchr(pv_ptr->pv_name, '/');
3067 if (basename == NULL) basename = pv_ptr->pv_name;
3068 else basename++;
3069 remove_proc_entry(basename, vg_ptr->pv_subdir_pde);
3075 * create a /proc entry for a volume group
3077 #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS
3078 void lvm_do_create_proc_entry_of_vg ( vg_t *vg_ptr) {
3079 int l, p;
3080 pv_t *pv_ptr;
3081 lv_t *lv_ptr;
3083 pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
3084 lvm_proc_vg_subdir);
3085 if ( pde != NULL) {
3086 vg_ptr->vg_dir_pde = pde;
3087 pde = create_proc_entry("group", S_IFREG,
3088 vg_ptr->vg_dir_pde);
3089 if ( pde != NULL) {
3090 pde->read_proc = lvm_proc_read_vg_info;
3091 pde->data = vg_ptr;
3093 vg_ptr->lv_subdir_pde =
3094 create_proc_entry(LVM_LV_SUBDIR, S_IFDIR,
3095 vg_ptr->vg_dir_pde);
3096 vg_ptr->pv_subdir_pde =
3097 create_proc_entry(LVM_PV_SUBDIR, S_IFDIR,
3098 vg_ptr->vg_dir_pde);
3101 if ( vg_ptr->pv_subdir_pde != NULL) {
3102 for ( l = 0; l < vg_ptr->lv_max; l++) {
3103 if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue;
3104 lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr);
3106 for ( p = 0; p < vg_ptr->pv_max; p++) {
3107 if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue;
3108 lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr);
3114 * remove a /proc entry for a volume group
3116 void lvm_do_remove_proc_entry_of_vg ( vg_t *vg_ptr) {
3117 int l, p;
3118 lv_t *lv_ptr;
3119 pv_t *pv_ptr;
3121 for ( l = 0; l < vg_ptr->lv_max; l++) {
3122 if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue;
3123 lvm_do_remove_proc_entry_of_lv ( vg_ptr, vg_ptr->lv[l]);
3125 for ( p = 0; p < vg_ptr->pv_max; p++) {
3126 if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue;
3127 lvm_do_remove_proc_entry_of_pv ( vg_ptr, vg_ptr->pv[p]);
3129 if ( vg_ptr->vg_dir_pde != NULL) {
3130 remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
3131 remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde);
3132 remove_proc_entry("group", vg_ptr->vg_dir_pde);
3133 remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir);
3136 #endif
3140 * support function initialize gendisk variables
3142 #ifdef __initfunc
3143 __initfunc(void lvm_geninit(struct gendisk *lvm_gdisk))
3144 #else
3145 void __init
3146 lvm_geninit(struct gendisk *lvm_gdisk)
3147 #endif
3149 int i = 0;
3151 #ifdef DEBUG_GENDISK
3152 printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name);
3153 #endif
3155 for (i = 0; i < MAX_LV; i++) {
3156 lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */
3157 lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0;
3158 lvm_blocksizes[i] = BLOCK_SIZE;
3161 blk_size[MAJOR_NR] = lvm_size;
3162 blksize_size[MAJOR_NR] = lvm_blocksizes;
3163 hardsect_size[MAJOR_NR] = lvm_blocksizes;
3165 return;
3166 } /* lvm_gen_init() */
3169 #ifdef LVM_GET_INODE
3171 * support function to get an empty inode
3173 * Gets an empty inode to be inserted into the inode hash,
3174 * so that a physical volume can't be mounted.
3175 * This is analog to drivers/block/md.c
3177 * Is this the real thing?
3180 struct inode *lvm_get_inode(int dev)
3182 struct inode *inode_this = NULL;
3184 /* Lock the device by inserting a dummy inode. */
3185 inode_this = get_empty_inode();
3186 inode_this->i_dev = dev;
3187 insert_inode_hash(inode_this);
3188 return inode_this;
3193 * support function to clear an inode
3196 void lvm_clear_inode(struct inode *inode)
3198 #ifdef I_FREEING
3199 inode->i_state |= I_FREEING;
3200 #endif
3201 clear_inode(inode);
3202 return;
3204 #endif /* #ifdef LVM_GET_INODE */