📄 lvm.c
字号:
#else "Driver"#endif " successfully initialized\n", lvm_version, lvm_name); return 0;} /* init_module() / lvm_init() */#ifdef MODULE/* * Module cleanup... */void cleanup_module(void){ struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL;#ifdef CONFIG_DEVFS_FS devfs_unregister (lvm_devfs_handle);#endif if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); } if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) { printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name); } blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); gendisk_ptr = gendisk_ptr_prev = gendisk_head; while (gendisk_ptr != NULL) { if (gendisk_ptr == &lvm_gendisk) break; gendisk_ptr_prev = gendisk_ptr; gendisk_ptr = gendisk_ptr->next; } /* delete our gendisk from chain */ if (gendisk_ptr == &lvm_gendisk) gendisk_ptr_prev->next = gendisk_ptr->next; blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL;#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS remove_proc_entry(LVM_GLOBAL, lvm_proc_dir); remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir); remove_proc_entry(LVM_DIR, &proc_root);#endif#ifdef LVM_HD_NAME /* reference from linux/drivers/block/genhd.c */ lvm_hd_name_ptr = NULL;#endif printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); return;} /* void cleanup_module() */#endif /* #ifdef MODULE *//* * support function to initialize lvm variables */#ifdef __initfunc__initfunc(void lvm_init_vars(void))#elsevoid __init lvm_init_vars(void)#endif{ int v; loadtime = CURRENT_TIME; lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; pe_lock_req.lock = UNLOCK_PE; pe_lock_req.data.lv_dev = \ pe_lock_req.data.pv_dev = \ pe_lock_req.data.pv_offset = 0; /* Initialize VG pointers */ for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL; /* Initialize LV -> VG association */ for (v = 0; v < ABS_MAX_LV; v++) { /* index ABS_MAX_VG never used for real VG */ vg_lv_map[v].vg_number = ABS_MAX_VG; vg_lv_map[v].lv_number = -1; } return;} /* lvm_init_vars() *//******************************************************************** * * Character device functions * ********************************************************************//* * character device open routine */static int lvm_chr_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev);#ifdef DEBUG printk(KERN_DEBUG "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", lvm_name, minor, VG_CHR(minor), file->f_mode, lock);#endif /* super user validation */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; lvm_chr_open_count++; MOD_INC_USE_COUNT; return 0;} /* lvm_chr_open() *//* * character device i/o-control routine * * Only one changing process can do changing ioctl at one time, * others will block. * */static int lvm_chr_ioctl(struct inode *inode, struct file *file, uint command, ulong a){ int minor = MINOR(inode->i_rdev); uint extendable, l, v; void *arg = (void *) a; lv_t lv; vg_t* vg_ptr = vg[VG_CHR(minor)]; /* otherwise cc will complain about unused variables */ (void) lvm_lock;#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " "VG#: %d mode: 0x%X\n", lvm_name, command, minor, VG_CHR(minor), file->f_mode);#endif#ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) return -EACCES;#endif /* Main command switch */ switch (command) { case LVM_LOCK_LVM: /* lock the LVM */ return lvm_do_lock_lvm(); case LVM_GET_IOP_VERSION: /* check lvm version to ensure driver/tools+lib interoperability */ if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0) return -EFAULT; return 0;#ifdef LVM_TOTAL_RESET case LVM_RESET: /* lock reset function */ lvm_reset_spindown = 1; for (v = 0; v < ABS_MAX_VG; v++) { if (vg[v] != NULL) lvm_do_vg_remove(v); }#ifdef MODULE while (GET_USE_COUNT(&__this_module) < 1) MOD_INC_USE_COUNT; while (GET_USE_COUNT(&__this_module) > 1) MOD_DEC_USE_COUNT;#endif /* MODULE */ lock = 0; /* release lock */ wake_up_interruptible(&lvm_wait); return 0;#endif /* LVM_TOTAL_RESET */ case LE_REMAP: /* remap a logical extent (after moving the physical extent) */ return lvm_do_le_remap(vg_ptr,arg); case PE_LOCK_UNLOCK: /* lock/unlock i/o to a physical extent to move it to another physical volume (move's done in user space's pvmove) */ return lvm_do_pe_lock_unlock(vg_ptr,arg); case VG_CREATE: /* create a VGDA */ return lvm_do_vg_create(minor, arg); case VG_EXTEND: /* extend a volume group */ return lvm_do_vg_extend(vg_ptr, arg); case VG_REDUCE: /* reduce a volume group */ return lvm_do_vg_reduce(vg_ptr, arg); case VG_RENAME: /* rename a volume group */ return lvm_do_vg_rename(vg_ptr, arg); case VG_REMOVE: /* remove an inactive VGDA */ return lvm_do_vg_remove(minor); case VG_SET_EXTENDABLE: /* set/clear extendability flag of volume group */ if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0) return -EFAULT; if (extendable == VG_EXTENDABLE || extendable == ~VG_EXTENDABLE) { if (extendable == VG_EXTENDABLE) vg_ptr->vg_status |= VG_EXTENDABLE; else vg_ptr->vg_status &= ~VG_EXTENDABLE; } else return -EINVAL; return 0; case VG_STATUS: /* get volume group data (only the vg_t struct) */ if (vg_ptr == NULL) return -ENXIO; if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) return -EFAULT; return 0; case VG_STATUS_GET_COUNT: /* get volume group count */ if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0) return -EFAULT; return 0; case VG_STATUS_GET_NAMELIST: /* get volume group count */ for (l = v = 0; v < ABS_MAX_VG; v++) { if (vg[v] != NULL) { if (copy_to_user(arg + l * NAME_LEN, vg[v]->vg_name, NAME_LEN) != 0) return -EFAULT; l++; } } return 0; case LV_CREATE: case LV_EXTEND: case LV_REDUCE: case LV_REMOVE: case LV_RENAME: /* create, extend, reduce, remove or rename a logical volume */ if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0) return -EFAULT; if (command != LV_REMOVE) { if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0) return -EFAULT; } switch (command) { case LV_CREATE: return lvm_do_lv_create(minor, lv_req.lv_name, &lv); case LV_EXTEND: case LV_REDUCE: return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv); case LV_REMOVE: return lvm_do_lv_remove(minor, lv_req.lv_name, -1); case LV_RENAME: return lvm_do_lv_rename(vg_ptr, &lv_req, &lv); } case LV_STATUS_BYNAME: /* get status of a logical volume by name */ return lvm_do_lv_status_byname(vg_ptr, arg); case LV_STATUS_BYINDEX: /* get status of a logical volume by index */ return lvm_do_lv_status_byindex(vg_ptr, arg); case LV_STATUS_BYDEV: return lvm_do_lv_status_bydev(vg_ptr, arg); case PV_CHANGE: /* change a physical volume */ return lvm_do_pv_change(vg_ptr,arg); case PV_STATUS: /* get physical volume data (pv_t structure only) */ return lvm_do_pv_status(vg_ptr,arg); case PV_FLUSH: /* physical volume buffer flush/invalidate */ if (copy_from_user(&pv_flush_req, arg, sizeof(pv_flush_req)) != 0) return -EFAULT; fsync_dev(pv_flush_req.pv_dev); invalidate_buffers(pv_flush_req.pv_dev); return 0; default: printk(KERN_WARNING "%s -- lvm_chr_ioctl: unknown command %x\n", lvm_name, command); return -EINVAL; } return 0;} /* lvm_chr_ioctl *//* * character device close routine */static int lvm_chr_close(struct inode *inode, struct file *file){#ifdef DEBUG int minor = MINOR(inode->i_rdev); printk(KERN_DEBUG "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor));#endif#ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) { lvm_reset_spindown = 0; lvm_chr_open_count = 0; }#endif if (lvm_chr_open_count > 0) lvm_chr_open_count--; if (lock == current->pid) { lock = 0; /* release lock */ wake_up_interruptible(&lvm_wait); } MOD_DEC_USE_COUNT; return 0;} /* lvm_chr_close() *//******************************************************************** * * Block device functions * ********************************************************************//* * block device open routine */static int lvm_blk_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); lv_t *lv_ptr; vg_t *vg_ptr = vg[VG_BLK(minor)];#ifdef DEBUG_LVM_BLK_OPEN printk(KERN_DEBUG "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode);#endif#ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) return -EPERM;#endif if (vg_ptr != NULL && (vg_ptr->vg_status & VG_ACTIVE) && (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL && LV_BLK(minor) >= 0 && LV_BLK(minor) < vg_ptr->lv_max) { /* Check parallel LV spindown (LV remove) */ if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ if (file->f_mode & O_RDWR) { if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM; if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; }#ifndef BLOCK_DEVICE_OPERATIONS file->f_op = &lvm_blk_fops;#endif /* be sure to increment VG counter */ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; lv_ptr->lv_open++; MOD_INC_USE_COUNT;#ifdef DEBUG_LVM_BLK_OPEN printk(KERN_DEBUG "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n", lvm_name, minor, VG_BLK(minor), LV_BLK(minor), lv_ptr->lv_size);#endif return 0; } return -ENXIO;} /* lvm_blk_open() *//* * block device i/o-control routine */static int lvm_blk_ioctl(struct inode *inode, struct file *file, uint command, ulong a){ int minor = MINOR(inode->i_rdev); vg_t *vg_ptr = vg[VG_BLK(minor)]; lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; void *arg = (void *) a; struct hd_geometry *hd = (struct hd_geometry *) a;#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " "VG#: %dl LV#: %d\n", lvm_name, minor, command, (ulong) arg, VG_BLK(minor), LV_BLK(minor));#endif switch (command) { case BLKGETSIZE: /* return device size */#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n", lvm_name, lv_ptr->lv_size);#endif if (put_user(lv_ptr->lv_size, (long *)arg)) return -EFAULT; break; case BLKFLSBUF: /* flush buffer cache */ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -