📄 lvm.c
字号:
return;} /* lvm_cleanup() *//* * support function to initialize lvm variables */static void __init lvm_init_vars(void){ 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 = 0; pe_lock_req.data.pv_dev = 0; 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 * ********************************************************************/#define MODE_TO_STR(mode) (mode) & FMODE_READ ? "READ" : "", \ (mode) & FMODE_WRITE ? "WRITE" : ""/* * character device open routine */static int lvm_chr_open(struct inode *inode, struct file *file){ unsigned int minor = MINOR(inode->i_rdev); P_DEV("chr_open MINOR: %d VG#: %d mode: %s%s lock: %d\n", minor, VG_CHR(minor), MODE_TO_STR(file->f_mode), lock); /* super user validation */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; spin_lock(&lvm_lock); if(lock == current->pid) _lock_open_count++; spin_unlock(&lvm_lock); 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; P_IOCTL("chr MINOR: %d command: 0x%X arg: %p VG#: %d mode: %s%s\n", minor, command, arg, VG_CHR(minor), MODE_TO_STR(file->f_mode));#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_OLD: /* create a VGDA */ return lvm_do_vg_create(arg, minor); case VG_CREATE: /* create a VGDA, assume VG number is filled in */ return lvm_do_vg_create(arg, -1); 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 names */ 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: /* get status of a logical volume by device */ 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 */ return lvm_do_pv_flush(arg); default: printk(KERN_WARNING "%s -- lvm_chr_ioctl: unknown command 0x%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){ P_DEV("chr_close MINOR: %d VG#: %d\n", MINOR(inode->i_rdev), VG_CHR(MINOR(inode->i_rdev)));#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--; spin_lock(&lvm_lock); if(lock == current->pid) { if(!_lock_open_count) { P_DEV("chr_close: unlocking LVM for pid %d\n", lock); lock = 0; wake_up_interruptible(&lvm_wait); } else _lock_open_count--; } spin_unlock(&lvm_lock); 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)]; P_DEV("blk_open MINOR: %d VG#: %d LV#: %d mode: %s%s\n", minor, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode));#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 */ /* We need to be able to "read" an inactive LV to re-activate it again */ if ((file->f_mode & FMODE_WRITE) && (!(lv_ptr->lv_status & LV_ACTIVE))) return -EPERM; if (!(lv_ptr->lv_access & LV_WRITE) && (file->f_mode & FMODE_WRITE)) return -EACCES; /* be sure to increment VG counter */ if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; lv_ptr->lv_open++; MOD_INC_USE_COUNT; P_DEV("blk_open OK, LV size %d\n", lv_ptr->lv_size); 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; P_IOCTL("blk MINOR: %d command: 0x%X arg: %p VG#: %d LV#: %d " "mode: %s%s\n", minor, command, arg, VG_BLK(minor), LV_BLK(minor), MODE_TO_STR(file->f_mode)); switch (command) { case BLKSSZGET: /* get block device sector size as needed e.g. by fdisk */ return put_user(get_hardsect_size(inode->i_rdev), (int *) arg); case BLKGETSIZE: /* return device size */ P_IOCTL("BLKGETSIZE: %u\n", lv_ptr->lv_size); if (put_user(lv_ptr->lv_size, (unsigned long *)arg)) return -EFAULT; break; case BLKGETSIZE64: if (put_user((u64)lv_ptr->lv_size << 9, (u64 *)arg)) return -EFAULT; break; case BLKFLSBUF: /* flush buffer cache */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; P_IOCTL("BLKFLSBUF\n"); fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); break; case BLKRASET: /* set read ahead for block device */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; P_IOCTL("BLKRASET: %ld sectors for %s\n", (long) arg, kdevname(inode->i_rdev)); if ((long) arg < LVM_MIN_READ_AHEAD || (long) arg > LVM_MAX_READ_AHEAD) return -EINVAL; lv_ptr->lv_read_ahead = (long) arg; break; case BLKRAGET: /* get current read ahead setting */ P_IOCTL("BLKRAGET %d\n", lv_ptr->lv_read_ahead); if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) return -EFAULT; break; case HDIO_GETGEO: /* get disk geometry */ P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); if (hd == NULL) return -EINVAL; { unsigned char heads = 64; unsigned char sectors = 32; long start = 0; short cylinders = lv_ptr->lv_size / heads / sectors; if (copy_to_user((char *) &hd->heads, &heads, sizeof(heads)) != 0 || copy_to_user((char *) &hd->sectors, §ors, sizeof(sectors)) != 0 || copy_to_user((short *) &hd->cylinders, &cylinders, sizeof(cylinders)) != 0 || copy_to_user((long *) &hd->start, &start, sizeof(start)) != 0) return -EFAULT; P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n", lvm_name, cylinders); } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -