📄 lvm.c
字号:
lvm_name, __LINE__); } } sz_last = sz; } } MOD_DEC_USE_COUNT; if (pos > sz - 1) { lock_kernel(); vfree(buf); unlock_kernel(); buf = NULL; return 0; } *start = &buf[pos]; if (sz - pos < count) return sz - pos; else return count;} /* lvm_proc_get_global_info() */#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS *//* * provide VG information */int lvm_proc_read_vg_info(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; vg_t *vg = data; sz += sprintf ( page+sz, "name: %s\n", vg->vg_name); sz += sprintf ( page+sz, "size: %u\n", vg->pe_total * vg->pe_size / 2); sz += sprintf ( page+sz, "access: %u\n", vg->vg_access); sz += sprintf ( page+sz, "status: %u\n", vg->vg_status); sz += sprintf ( page+sz, "number: %u\n", vg->vg_number); sz += sprintf ( page+sz, "LV max: %u\n", vg->lv_max); sz += sprintf ( page+sz, "LV current: %u\n", vg->lv_cur); sz += sprintf ( page+sz, "LV open: %u\n", vg->lv_open); sz += sprintf ( page+sz, "PV max: %u\n", vg->pv_max); sz += sprintf ( page+sz, "PV current: %u\n", vg->pv_cur); sz += sprintf ( page+sz, "PV active: %u\n", vg->pv_act); sz += sprintf ( page+sz, "PE size: %u\n", vg->pe_size / 2); sz += sprintf ( page+sz, "PE total: %u\n", vg->pe_total); sz += sprintf ( page+sz, "PE allocated: %u\n", vg->pe_allocated); sz += sprintf ( page+sz, "uuid: %s\n", vg->vg_uuid); return sz;}/* * provide LV information */int lvm_proc_read_lv_info(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; lv_t *lv = data; sz += sprintf ( page+sz, "name: %s\n", lv->lv_name); sz += sprintf ( page+sz, "size: %u\n", lv->lv_size); sz += sprintf ( page+sz, "access: %u\n", lv->lv_access); sz += sprintf ( page+sz, "status: %u\n", lv->lv_status); sz += sprintf ( page+sz, "number: %u\n", lv->lv_number); sz += sprintf ( page+sz, "open: %u\n", lv->lv_open); sz += sprintf ( page+sz, "allocation: %u\n", lv->lv_allocation); sz += sprintf ( page+sz, "device: %02u:%02u\n", MAJOR(lv->lv_dev), MINOR(lv->lv_dev)); return sz;}/* * provide PV information */int lvm_proc_read_pv_info(char *page, char **start, off_t off, int count, int *eof, void *data) { int sz = 0; pv_t *pv = data; sz += sprintf ( page+sz, "name: %s\n", pv->pv_name); sz += sprintf ( page+sz, "size: %u\n", pv->pv_size); sz += sprintf ( page+sz, "status: %u\n", pv->pv_status); sz += sprintf ( page+sz, "number: %u\n", pv->pv_number); sz += sprintf ( page+sz, "allocatable: %u\n", pv->pv_allocatable); sz += sprintf ( page+sz, "LV current: %u\n", pv->lv_cur); sz += sprintf ( page+sz, "PE size: %u\n", pv->pe_size / 2); sz += sprintf ( page+sz, "PE total: %u\n", pv->pe_total); sz += sprintf ( page+sz, "PE allocated: %u\n", pv->pe_allocated); sz += sprintf ( page+sz, "device: %02u:%02u\n", MAJOR(pv->pv_dev), MINOR(pv->pv_dev)); sz += sprintf ( page+sz, "uuid: %s\n", pv->pv_uuid); return sz;}/* * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c * (see init_module/lvm_init) */static int lvm_map(struct buffer_head *bh, int rw){ int minor = MINOR(bh->b_dev); int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; ulong rsector_tmp = bh->b_blocknr * size; ulong rsector_sav; kdev_t rdev_tmp = bh->b_dev; kdev_t rdev_sav; vg_t *vg_this = vg[VG_BLK(minor)]; lv_t *lv = vg_this->lv[LV_BLK(minor)]; if (!(lv->lv_status & LV_ACTIVE)) { printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", lvm_name, lv->lv_name); return -1; } if ((rw == WRITE || rw == WRITEA) && !(lv->lv_access & LV_WRITE)) { printk(KERN_CRIT "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", lvm_name, lv->lv_name); return -1; }#ifdef DEBUG_MAP printk(KERN_DEBUG "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " "size:%lu\n", lvm_name, minor, MAJOR(rdev_tmp), MINOR(rdev_tmp), rsector_tmp, size);#endif if (rsector_tmp + size > lv->lv_size) { printk(KERN_ALERT "%s - lvm_map access beyond end of device; *rsector: " "%lu or size: %lu wrong for minor: %2d\n", lvm_name, rsector_tmp, size, minor); return -1; } rsector_sav = rsector_tmp; rdev_sav = rdev_tmp;lvm_second_remap: /* linear mapping */ if (lv->lv_stripes < 2) { /* get the index */ index = rsector_tmp / vg_this->pe_size; pe_start = lv->lv_current_pe[index].pe; rsector_tmp = lv->lv_current_pe[index].pe + (rsector_tmp % vg_this->pe_size); rdev_tmp = lv->lv_current_pe[index].dev;#ifdef DEBUG_MAP printk(KERN_DEBUG "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n", index, lv->lv_current_pe[index].pe, MAJOR(rdev_tmp), MINOR(rdev_tmp), rsector_tmp);#endif /* striped mapping */ } else { ulong stripe_index; ulong stripe_length; stripe_length = vg_this->pe_size * lv->lv_stripes; stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize; index = rsector_tmp / stripe_length + (stripe_index % lv->lv_stripes) * (lv->lv_allocated_le / lv->lv_stripes); pe_start = lv->lv_current_pe[index].pe; rsector_tmp = lv->lv_current_pe[index].pe + (rsector_tmp % stripe_length) - (stripe_index % lv->lv_stripes) * lv->lv_stripesize - stripe_index / lv->lv_stripes * (lv->lv_stripes - 1) * lv->lv_stripesize; rdev_tmp = lv->lv_current_pe[index].dev; }#ifdef DEBUG_MAP printk(KERN_DEBUG "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" "stripe_length: %ld stripe_index: %ld\n", index, lv->lv_current_pe[index].pe, MAJOR(rdev_tmp), MINOR(rdev_tmp), rsector_tmp, stripe_length, stripe_index);#endif /* handle physical extents on the move */ if (pe_lock_req.lock == LOCK_PE) { if (rdev_tmp == pe_lock_req.data.pv_dev && rsector_tmp >= pe_lock_req.data.pv_offset && rsector_tmp < (pe_lock_req.data.pv_offset + vg_this->pe_size)) { sleep_on(&lvm_map_wait); rsector_tmp = rsector_sav; rdev_tmp = rdev_sav; goto lvm_second_remap; } } /* statistic */ if (rw == WRITE || rw == WRITEA) lv->lv_current_pe[index].writes++; else lv->lv_current_pe[index].reads++; /* snapshot volume exception handling on physical device address base */ if (lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)) { /* original logical volume */ if (lv->lv_access & LV_SNAPSHOT_ORG) { if (rw == WRITE || rw == WRITEA) { lv_t *lv_ptr; /* start with first snapshot and loop thrugh all of them */ for (lv_ptr = lv->lv_snapshot_next; lv_ptr != NULL; lv_ptr = lv_ptr->lv_snapshot_next) { /* Check for inactive snapshot */ if (!(lv_ptr->lv_status & LV_ACTIVE)) continue; down(&lv->lv_snapshot_org->lv_snapshot_sem); /* do we still have exception storage for this snapshot free? */ if (lv_ptr->lv_block_exception != NULL) { rdev_sav = rdev_tmp; rsector_sav = rsector_tmp; if (!lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv_ptr)) { /* create a new mapping */ if (!(ret = lvm_snapshot_COW(rdev_tmp, rsector_tmp, pe_start, rsector_sav, lv_ptr))) ret = lvm_write_COW_table_block(vg_this, lv_ptr); } rdev_tmp = rdev_sav; rsector_tmp = rsector_sav; } up(&lv->lv_snapshot_org->lv_snapshot_sem); } } } else { /* remap snapshot logical volume */ down(&lv->lv_snapshot_sem); if (lv->lv_block_exception != NULL) lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv); up(&lv->lv_snapshot_sem); } } bh->b_rdev = rdev_tmp; bh->b_rsector = rsector_tmp; return ret;} /* lvm_map() *//* * internal support functions */#ifdef LVM_HD_NAME/* * generate "hard disk" name */void lvm_hd_name(char *buf, int minor){ int len = 0; lv_t *lv_ptr; if (vg[VG_BLK(minor)] == NULL || (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL) return; len = strlen(lv_ptr->lv_name) - 5; memcpy(buf, &lv_ptr->lv_name[5], len); buf[len] = 0; return;}#endif/* * this one never should be called... */static void lvm_dummy_device_request(request_queue_t * t){ printk(KERN_EMERG "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n", lvm_name, MAJOR(CURRENT->rq_dev), MINOR(CURRENT->rq_dev), CURRENT->sector); return;}/* * make request function */static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh){ if (lvm_map(bh, rw)<0) return 0; /* failure, buffer_IO_error has been called, don't recurse */ else return 1; /* all ok, mapping done, call lower level driver */}/******************************************************************** * * Character device support functions * ********************************************************************//* * character device support function logical volume manager lock */static int lvm_do_lock_lvm(void){lock_try_again: spin_lock(&lvm_lock); if (lock != 0 && lock != current->pid) {#ifdef DEBUG_IOCTL printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n", lvm_name, lock);#endif spin_unlock(&lvm_lock); interruptible_sleep_on(&lvm_wait); if (current->sigpending != 0) return -EINTR;#ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) return -EACCES;#endif goto lock_try_again; } lock = current->pid; spin_unlock(&lvm_lock); return 0;} /* lvm_do_lock_lvm *//* * character device support function lock/unlock physical extend */static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg){ uint p; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&pe_lock_req, arg, sizeof(pe_lock_req_t)) != 0) return -EFAULT; switch (pe_lock_req.lock) { case LOCK_PE: for (p = 0; p < vg_ptr->pv_max; p++) { if (vg_ptr->pv[p] != NULL && pe_lock_req.data.pv_dev == vg_ptr->pv[p]->pv_dev) break; } if (p == vg_ptr->pv_max) return -ENXIO; pe_lock_req.lock = UNLOCK_PE; fsync_dev(pe_lock_req.data.lv_dev); pe_lock_req.lock = LOCK_PE; break; case UNLOCK_PE: 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; wake_up(&lvm_map_wait); break; default: return -EINVAL; } return 0;}/* * character device support function logical extend remap */static int lvm_do_le_remap(vg_t *vg_ptr, void *arg){ uint l, le; lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&le_remap_req, arg, sizeof(le_remap_req_t)) != 0) return -EFAULT; for (l = 0; l < vg_ptr->lv_max; l++) { lv_ptr = vg_ptr->lv[l]; if (lv_ptr != NULL && strcmp(lv_ptr->lv_name, le_remap_req.lv_name) == 0) { for (le = 0; le < lv_ptr->lv_allocated_le; le++) { if (lv_ptr->lv_current_pe[le].dev == le_remap_req.old_dev && lv_ptr->lv_current_pe[le].pe == le_remap_req.old_pe) { lv_ptr->lv_current_pe[le].dev = le_remap_req.new_dev; lv_ptr->lv_current_pe[le].pe = le_remap_req.new_pe; return 0; } } return -EINVAL; } } return -ENXIO;} /* lvm_do_le_remap() *//* * character device support function VGDA create */int lvm_do_vg_create(int minor, void *arg){ int ret = 0; ulong l, ls = 0, p, size; lv_t lv; vg_t *vg_ptr; lv_t **snap_lv_ptr; if (vg[VG_CHR(minor)] != NULL) return -EPERM; if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error VG at line %d\n", lvm_name, __LINE__); return -ENOMEM; } /* get the volume group structure */ if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { kfree(vg_ptr); return -EFAULT; } /* we are not that active so far... */ vg_ptr->vg_status &= ~VG_ACTIVE; vg[VG_CHR(minor)] = vg_ptr; vg[VG_CHR(minor)]->pe_allocated = 0; if (vg_ptr->pv_max > ABS_MAX_PV) { printk(KERN_WARNING "%s -- Can't activate VG: ABS_MAX_PV too small\n", lvm_name); kfree(vg_ptr); vg[VG_CHR(minor)] = NULL; return -EPERM; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -