📄 lvm.c
字号:
/* * kernel/lvm.c * * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software * * February-November 1997 * April-May,July-August,November 1998 * January-March,May,July,September,October 1999 * January,February,July,September-November 2000 * * * LVM driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * LVM driver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * *//* * Changelog * * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT * and VG_STATUS_GET_NAMELIST * 18/01/1998 - change lvm_chr_open/close lock handling * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and * - added LV_STATUS_BYINDEX ioctl * - used lvm_status_byname_req_t and * lvm_status_byindex_req_t vars * 04/05/1998 - added multiple device support * 08/05/1998 - added support to set/clear extendable flag in volume group * 09/05/1998 - changed output of lvm_proc_get_global_info() because of * support for free (eg. longer) logical volume names * 12/05/1998 - added spin_locks (thanks to Pascal van Dam * <pascal@ramoth.xs4all.nl>) * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() * 26/05/1998 - reactivated verify_area by access_ok * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go * beyond 128/256 KB max allocation limit per call * - #ifdef blocked spin_lock calls to avoid compile errors * with 2.0.x * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open() * and use of LVM_VERSION_CODE instead of my own macros * (thanks to Michael Marxmeier <mike@msede.com>) * 07/07/1998 - added statistics in lvm_map() * 08/07/1998 - saved statistics in lvm_do_lv_extend_reduce() * 25/07/1998 - used __initfunc macro * 02/08/1998 - changes for official char/block major numbers * 07/08/1998 - avoided init_module() and cleanup_module() to be static * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters * to sum of LVs open (no matter how often each is) * 01/09/1998 - fixed lvm_gendisk.part[] index error * 07/09/1998 - added copying of lv_current_pe-array * in LV_STATUS_BYINDEX ioctl * 17/11/1998 - added KERN_* levels to printk * 13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET * by moving spinlock code from lvm_chr_open() * to lvm_chr_ioctl() * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl() * - allowed LVM_RESET and retrieval commands to go ahead; * only other update ioctls are blocked now * - fixed pv->pe to NULL for pv_status * - using lv_req structure in lvm_chr_ioctl() now * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce() * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE) * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to * handle lgoical volume private read ahead sector * - implemented LV read_ahead handling with lvm_blk_read() * and lvm_blk_write() * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name() * to be used in drivers/block/genhd.c by disk_name() * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO * - enhanced gendisk insert/remove handling * 16/02/1999 - changed to dynamic block minor number allocation to * have as much as 99 volume groups with 256 logical volumes * as the grand total; this allows having 1 volume group with * up to 256 logical volumes in it * 21/02/1999 - added LV open count information to proc filesystem * - substituted redundant LVM_RESET code by calls * to lvm_do_vg_remove() * 22/02/1999 - used schedule_timeout() to be more responsive * in case of lvm_do_vg_remove() with lots of logical volumes * 19/03/1999 - fixed NULL pointer bug in module_init/lvm_init * 17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0) * - enhanced lvm_hd_name support * 03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and * memcpy_tofs/memcpy_fromfs macro redefinitions * 06/07/1999 - corrected reads/writes statistic counter copy in case * of striped logical volume * 28/07/1999 - implemented snapshot logical volumes * - lvm_chr_ioctl * - LV_STATUS_BYINDEX * - LV_STATUS_BYNAME * - lvm_do_lv_create * - lvm_do_lv_remove * - lvm_map * - new lvm_snapshot_remap_block * - new lvm_snapshot_remap_new_block * 08/10/1999 - implemented support for multiple snapshots per * original logical volume * 12/10/1999 - support for 2.3.19 * 11/11/1999 - support for 2.3.28 * 21/11/1999 - changed lvm_map() interface to buffer_head based * 19/12/1999 - support for 2.3.33 * 01/01/2000 - changed locking concept in lvm_map(), * lvm_do_vg_create() and lvm_do_lv_remove() * 15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl() * 24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc. * 29/01/2000 - used kmalloc/kfree again for all small structures * 20/01/2000 - cleaned up lvm_chr_ioctl by moving code * to seperated functions * - avoided "/dev/" in proc filesystem output * - avoided inline strings functions lvm_strlen etc. * 14/02/2000 - support for 2.3.43 * - integrated Andrea Arcagneli's snapshot code * 25/06/2000 - james (chip) , IKKHAYD! roffl * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume support * 06/09/2000 - added devfs support * 07/09/2000 - changed IOP version to 9 * - started to add new char ioctl LV_STATUS_BYDEV_T to support * getting an lv_t based on the dev_t of the Logical Volume * 14/09/2000 - enhanced lvm_do_lv_create to upcall VFS functions * to sync and lock, activate snapshot and unlock the FS * (to support journaled filesystems) * 18/09/2000 - hardsector size support * 27/09/2000 - implemented lvm_do_lv_rename() and lvm_do_vg_rename() * 30/10/2000 - added Andi Kleen's LV_BMAP ioctl to support LILO * 01/11/2000 - added memory information on hash tables to * lvm_proc_get_global_info() * 02/11/2000 - implemented /proc/lvm/ hierarchy * 07/12/2000 - make sure lvm_make_request_fn returns correct value - 0 or 1 - NeilBrown * */static char *lvm_version = "LVM version 0.9 by Heinz Mauelshagen (13/11/2000)\n";static char *lvm_short_version = "version 0.9 (13/11/2000)";#define MAJOR_NR LVM_BLK_MAJOR#define DEVICE_OFF(device)/* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() *//* #define LVM_VFS_ENHANCEMENT */#include <linux/config.h>#include <linux/version.h>#ifdef MODVERSIONS#undef MODULE#define MODULE#include <linux/modversions.h>#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/hdreg.h>#include <linux/stat.h>#include <linux/fs.h>#include <linux/proc_fs.h>#include <linux/blkdev.h>#include <linux/genhd.h>#include <linux/locks.h>#include <linux/smp_lock.h>#include <asm/ioctl.h>#include <asm/segment.h>#include <asm/uaccess.h>#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endif#include <linux/blk.h>#include <linux/blkpg.h>#include <linux/errno.h>#include <linux/lvm.h>#define LVM_CORRECT_READ_AHEAD( a) \ if ( a < LVM_MIN_READ_AHEAD || \ a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD;#ifndef WRITEA# define WRITEA WRITE#endif/* * External function prototypes */#ifdef MODULEint init_module(void);void cleanup_module(void);#elseextern int lvm_init(void);#endifstatic void lvm_dummy_device_request(request_queue_t *);#define DEVICE_REQUEST lvm_dummy_device_requeststatic int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*);static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);static int lvm_blk_open(struct inode *, struct file *);static int lvm_chr_open(struct inode *, struct file *);static int lvm_chr_close(struct inode *, struct file *);static int lvm_blk_close(struct inode *, struct file *);static int lvm_user_bmap(struct inode *, struct lv_bmap *);static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong);#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FSint lvm_proc_read_vg_info(char *, char **, off_t, int, int *, void *);int lvm_proc_read_lv_info(char *, char **, off_t, int, int *, void *);int lvm_proc_read_pv_info(char *, char **, off_t, int, int *, void *);static int lvm_proc_get_global_info(char *, char **, off_t, int, int *, void *);void lvm_do_create_proc_entry_of_vg ( vg_t *);inline void lvm_do_remove_proc_entry_of_vg ( vg_t *);inline void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *);inline void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *);inline void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *);inline void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *);#endif#ifdef LVM_HD_NAMEvoid lvm_hd_name(char *, int);#endif/* End external function prototypes *//* * Internal function prototypes */static void lvm_init_vars(void);/* external snapshot calls */extern inline int lvm_get_blksize(kdev_t);extern int lvm_snapshot_alloc(lv_t *);extern void lvm_snapshot_fill_COW_page(vg_t *, lv_t *);extern int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *);extern int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *);extern void lvm_snapshot_release(lv_t *); extern int lvm_write_COW_table_block(vg_t *, lv_t *);extern inline void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *);extern int lvm_snapshot_alloc_hash_table(lv_t *);extern void lvm_drop_snapshot(lv_t *, char *);#ifdef LVM_HD_NAMEextern void (*lvm_hd_name_ptr) (char *, int);#endifstatic int lvm_map(struct buffer_head *, int);static int lvm_do_lock_lvm(void);static int lvm_do_le_remap(vg_t *, void *);static int lvm_do_pv_create(pv_t *, vg_t *, ulong);static int lvm_do_pv_remove(vg_t *, ulong);static int lvm_do_lv_create(int, char *, lv_t *);static int lvm_do_lv_extend_reduce(int, char *, lv_t *);static int lvm_do_lv_remove(int, char *, int);static int lvm_do_lv_rename(vg_t *, lv_req_t *, lv_t *);static int lvm_do_lv_status_byname(vg_t *r, void *);static int lvm_do_lv_status_byindex(vg_t *, void *);static int lvm_do_lv_status_bydev(vg_t *, void *);static int lvm_do_pe_lock_unlock(vg_t *r, void *);static int lvm_do_pv_change(vg_t*, void*);static int lvm_do_pv_status(vg_t *, void *);static int lvm_do_vg_create(int, void *);static int lvm_do_vg_extend(vg_t *, void *);static int lvm_do_vg_reduce(vg_t *, void *);static int lvm_do_vg_rename(vg_t *, void *);static int lvm_do_vg_remove(int);static void lvm_geninit(struct gendisk *);#ifdef LVM_GET_INODEstatic struct inode *lvm_get_inode(int);void lvm_clear_inode(struct inode *);#endif/* END Internal function prototypes *//* volume group descriptor area pointers */static vg_t *vg[ABS_MAX_VG];#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t lvm_devfs_handle;static devfs_handle_t vg_devfs_handle[MAX_VG];static devfs_handle_t ch_devfs_handle[MAX_VG];static devfs_handle_t lv_devfs_handle[MAX_LV];#endifstatic pv_t *pvp = NULL;static lv_t *lvp = NULL;static pe_t *pep = NULL;static pe_t *pep1 = NULL;static char *basename = NULL;/* map from block minor number to VG and LV numbers */typedef struct { int vg_number; int lv_number;} vg_lv_map_t;static vg_lv_map_t vg_lv_map[ABS_MAX_LV];/* Request structures (lvm_chr_ioctl()) */static pv_change_req_t pv_change_req;static pv_flush_req_t pv_flush_req;static pv_status_req_t pv_status_req;static pe_lock_req_t pe_lock_req;static le_remap_req_t le_remap_req;static lv_req_t lv_req;#ifdef LVM_TOTAL_RESETstatic int lvm_reset_spindown = 0;#endifstatic char pv_name[NAME_LEN];/* static char rootvg[NAME_LEN] = { 0, }; */const char *const lvm_name = LVM_NAME;static int lock = 0;static int loadtime = 0;static uint vg_count = 0;static long lvm_chr_open_count = 0;static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION;static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait);static DECLARE_WAIT_QUEUE_HEAD(lvm_wait);static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait);static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED;static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED;#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FSstatic struct proc_dir_entry *lvm_proc_dir = NULL;static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;struct proc_dir_entry *pde = NULL;#endifstatic struct file_operations lvm_chr_fops ={ open: lvm_chr_open, release: lvm_chr_close, ioctl: lvm_chr_ioctl,};#define BLOCK_DEVICE_OPERATIONS/* block device operations structure needed for 2.3.38? and above */static struct block_device_operations lvm_blk_dops ={ open: lvm_blk_open, release: lvm_blk_close, ioctl: lvm_blk_ioctl,};/* gendisk structures */static struct hd_struct lvm_hd_struct[MAX_LV];static int lvm_blocksizes[MAX_LV] ={0,};static int lvm_size[MAX_LV] ={0,};static struct gendisk lvm_gendisk ={ MAJOR_NR, /* major # */ LVM_NAME, /* name of major */ 0, /* number of times minor is shifted to get real minor */ 1, /* maximum partitions per device */ lvm_hd_struct, /* partition table */ lvm_size, /* device size in blocks, copied to block_size[] */ MAX_LV, /* number or real devices */ NULL, /* internal */ NULL, /* pointer to next gendisk struct (internal) */};#ifdef MODULE/* * Module initialization... */int init_module(void)#else/* * Driver initialization... */#ifdef __initfunc__initfunc(int lvm_init(void))#elseint __init lvm_init(void)#endif#endif /* #ifdef MODULE */{ struct gendisk *gendisk_ptr = NULL; if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) { printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); return -EIO; }#ifdef BLOCK_DEVICE_OPERATIONS if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0)#else if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0)#endif { printk("%s -- register_blkdev failed\n", lvm_name); if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); return -EIO; }#ifdef CONFIG_DEVFS_FS lvm_devfs_handle = devfs_register( 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &lvm_chr_fops, NULL);#endif#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS lvm_proc_dir = create_proc_entry (LVM_DIR, S_IFDIR, &proc_root); if (lvm_proc_dir != NULL) { lvm_proc_vg_subdir = create_proc_entry (LVM_VG_SUBDIR, S_IFDIR, lvm_proc_dir); pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir); if ( pde != NULL) pde->read_proc = &lvm_proc_get_global_info; }#endif lvm_init_vars(); lvm_geninit(&lvm_gendisk); /* insert our gendisk at the corresponding major */ if (gendisk_head != NULL) { gendisk_ptr = gendisk_head; while (gendisk_ptr->next != NULL && gendisk_ptr->major > lvm_gendisk.major) { gendisk_ptr = gendisk_ptr->next; } lvm_gendisk.next = gendisk_ptr->next; gendisk_ptr->next = &lvm_gendisk; } else { gendisk_head = &lvm_gendisk; lvm_gendisk.next = NULL; }#ifdef LVM_HD_NAME /* reference from drivers/block/genhd.c */ lvm_hd_name_ptr = lvm_hd_name;#endif blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); /* optional read root VGDA *//* if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg);*/ printk(KERN_INFO "%s%s -- "#ifdef MODULE "Module"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -