📄 lvm.c
字号:
#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name);#endif 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;#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", lvm_name, (long) arg, MAJOR(inode->i_rdev), minor);#endif 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 */#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name);#endif if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) return -EFAULT; break; case HDIO_GETGEO: /* get disk geometry */#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name);#endif 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; }#ifdef DEBUG_IOCTL printk(KERN_DEBUG "%s -- lvm_blk_ioctl -- cylinders: %d\n", lvm_name, lv_ptr->lv_size / heads / sectors);#endif break; case LV_SET_ACCESS: /* set access flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; lv_ptr->lv_access = (ulong) arg; if ( lv_ptr->lv_access & LV_WRITE) set_device_ro(lv_ptr->lv_dev, 0); else set_device_ro(lv_ptr->lv_dev, 1); break; case LV_SET_STATUS: /* set status flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) return -EPERM; lv_ptr->lv_status = (ulong) arg; break; case LV_BMAP: /* turn logical block into (dev_t, block). non privileged. */ return lvm_user_bmap(inode, (struct lv_bmap *) arg); break; case LV_SET_ALLOCATION: /* set allocation flags of a logical volume */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; lv_ptr->lv_allocation = (ulong) arg; break; case LV_SNAPSHOT_USE_RATE: if (!(lv_ptr->lv_access & LV_SNAPSHOT)) return -EPERM; { lv_snapshot_use_rate_req_t lv_snapshot_use_rate_req; if (copy_from_user(&lv_snapshot_use_rate_req, arg, sizeof(lv_snapshot_use_rate_req_t))) return -EFAULT; if (lv_snapshot_use_rate_req.rate < 0 || lv_snapshot_use_rate_req.rate > 100) return -EFAULT; switch (lv_snapshot_use_rate_req.block) { case 0: lv_ptr->lv_snapshot_use_rate = lv_snapshot_use_rate_req.rate; if (lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end < lv_ptr->lv_snapshot_use_rate) interruptible_sleep_on (&lv_ptr->lv_snapshot_wait); break; case O_NONBLOCK: break; default: return -EFAULT; } lv_snapshot_use_rate_req.rate = lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end; if (copy_to_user(arg, &lv_snapshot_use_rate_req, sizeof(lv_snapshot_use_rate_req_t))) return -EFAULT; } break; default: printk(KERN_WARNING "%s -- lvm_blk_ioctl: unknown command %d\n", lvm_name, command); return -EINVAL; } return 0;} /* lvm_blk_ioctl() *//* * block device close routine */static int lvm_blk_close(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); vg_t *vg_ptr = vg[VG_BLK(minor)]; lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)];#ifdef DEBUG printk(KERN_DEBUG "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n", lvm_name, minor, VG_BLK(minor), LV_BLK(minor));#endif sync_dev(inode->i_rdev); if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; lv_ptr->lv_open--; MOD_DEC_USE_COUNT; return 0;} /* lvm_blk_close() */static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result){ struct buffer_head bh; unsigned long block; int err; if (get_user(block, &user_result->lv_block)) return -EFAULT; memset(&bh,0,sizeof bh); bh.b_rsector = block; bh.b_dev = bh.b_rdev = inode->i_dev; bh.b_size = lvm_get_blksize(bh.b_dev); if ((err=lvm_map(&bh, READ)) < 0) { printk("lvm map failed: %d\n", err); return -EINVAL; } return put_user( kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || put_user(bh.b_rsector, &user_result->lv_block) ? -EFAULT : 0;} /* * provide VG info for proc filesystem use (global) */int lvm_vg_info(vg_t *vg_ptr, char *buf) { int sz = 0; char inactive_flag = ' '; if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I'; sz = sprintf(buf, "\nVG: %c%s [%d PV, %d LV/%d open] " " PE Size: %d KB\n" " Usage [KB/PE]: %d /%d total " "%d /%d used %d /%d free", inactive_flag, vg_ptr->vg_name, vg_ptr->pv_cur, vg_ptr->lv_cur, vg_ptr->lv_open, vg_ptr->pe_size >> 1, vg_ptr->pe_size * vg_ptr->pe_total >> 1, vg_ptr->pe_total, vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, vg_ptr->pe_allocated, (vg_ptr->pe_total - vg_ptr->pe_allocated) * vg_ptr->pe_size >> 1, vg_ptr->pe_total - vg_ptr->pe_allocated); return sz;}/* * provide LV info for proc filesystem use (global) */int lvm_lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) { int sz = 0; char inactive_flag = 'A', allocation_flag = ' ', stripes_flag = ' ', rw_flag = ' '; if (!(lv_ptr->lv_status & LV_ACTIVE)) inactive_flag = 'I'; rw_flag = 'R'; if (lv_ptr->lv_access & LV_WRITE) rw_flag = 'W'; allocation_flag = 'D'; if (lv_ptr->lv_allocation & LV_CONTIGUOUS) allocation_flag = 'C'; stripes_flag = 'L'; if (lv_ptr->lv_stripes > 1) stripes_flag = 'S'; sz += sprintf(buf+sz, "[%c%c%c%c", inactive_flag, rw_flag, allocation_flag, stripes_flag); if (lv_ptr->lv_stripes > 1) sz += sprintf(buf+sz, "%-2d", lv_ptr->lv_stripes); else sz += sprintf(buf+sz, " "); basename = strrchr(lv_ptr->lv_name, '/'); if ( basename == 0) basename = lv_ptr->lv_name; else basename++; sz += sprintf(buf+sz, "] %-25s", basename); if (strlen(basename) > 25) sz += sprintf(buf+sz, "\n "); sz += sprintf(buf+sz, "%9d /%-6d ", lv_ptr->lv_size >> 1, lv_ptr->lv_size / vg_ptr->pe_size); if (lv_ptr->lv_open == 0) sz += sprintf(buf+sz, "close"); else sz += sprintf(buf+sz, "%dx open", lv_ptr->lv_open); return sz;}/* * provide PV info for proc filesystem use (global) */int lvm_pv_info(pv_t *pv_ptr, char *buf) { int sz = 0; char inactive_flag = 'A', allocation_flag = ' '; char *pv_name = NULL; if (!(pv_ptr->pv_status & PV_ACTIVE)) inactive_flag = 'I'; allocation_flag = 'A'; if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE)) allocation_flag = 'N'; pv_name = strrchr(pv_ptr->pv_name+1,'/'); if ( pv_name == 0) pv_name = pv_ptr->pv_name; else pv_name++; sz = sprintf(buf, "[%c%c] %-21s %8d /%-6d " "%8d /%-6d %8d /%-6d", inactive_flag, allocation_flag, pv_name, pv_ptr->pe_total * pv_ptr->pe_size >> 1, pv_ptr->pe_total, pv_ptr->pe_allocated * pv_ptr->pe_size >> 1, pv_ptr->pe_allocated, (pv_ptr->pe_total - pv_ptr->pe_allocated) * pv_ptr->pe_size >> 1, pv_ptr->pe_total - pv_ptr->pe_allocated); return sz;}#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS/* * Support functions /proc-Filesystem */#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz])/* * provide global LVM information */static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int count, int *eof, void *data){ int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds; static off_t sz; off_t sz_last; static char *buf = NULL; static char dummy_buf[160]; /* sized for 2 lines */ vg_t *vg_ptr; lv_t *lv_ptr; pv_t *pv_ptr;#ifdef DEBUG_LVM_PROC_GET_INFO printk(KERN_DEBUG "%s - lvm_proc_get_global_info CALLED pos: %lu count: %d whence: %d\n", lvm_name, pos, count, whence);#endif MOD_INC_USE_COUNT; if (pos == 0 || buf == NULL) { sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \ lv_open_total = pe_t_bytes = hash_table_bytes = \ lv_block_exception_t_bytes = 0; /* search for activity */ for (v = 0; v < ABS_MAX_VG; v++) { if ((vg_ptr = vg[v]) != NULL) { vg_counter++; pv_counter += vg_ptr->pv_cur; lv_counter += vg_ptr->lv_cur; if (vg_ptr->lv_cur > 0) { for (l = 0; l < vg[v]->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL) { pe_t_bytes += lv_ptr->lv_allocated_le; hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size; if (lv_ptr->lv_block_exception != NULL) lv_block_exception_t_bytes += lv_ptr->lv_remap_end; if (lv_ptr->lv_open > 0) { lv_open_counter++; lv_open_total += lv_ptr->lv_open; } } } } } } pe_t_bytes *= sizeof(pe_t); lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); if (buf != NULL) {#ifdef DEBUG_KFREE printk(KERN_DEBUG "%s -- vfree %d\n", lvm_name, __LINE__);#endif lock_kernel(); vfree(buf); unlock_kernel(); buf = NULL; } /* 2 times: first to get size to allocate buffer, 2nd to fill the malloced buffer */ for (i = 0; i < 2; i++) { sz = 0; sz += sprintf(LVM_PROC_BUF, "LVM "#ifdef MODULE "module"#else "driver"#endif " %s\n\n" "Total: %d VG%s %d PV%s %d LV%s ", lvm_short_version, vg_counter, vg_counter == 1 ? "" : "s", pv_counter, pv_counter == 1 ? "" : "s", lv_counter, lv_counter == 1 ? "" : "s"); sz += sprintf(LVM_PROC_BUF, "(%d LV%s open", lv_open_counter, lv_open_counter == 1 ? "" : "s"); if (lv_open_total > 0) sz += sprintf(LVM_PROC_BUF, " %d times)\n", lv_open_total); else sz += sprintf(LVM_PROC_BUF, ")"); sz += sprintf(LVM_PROC_BUF, "\nGlobal: %lu bytes malloced IOP version: %d ", vg_counter * sizeof(vg_t) + pv_counter * sizeof(pv_t) + lv_counter * sizeof(lv_t) + pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last, lvm_iop_version); seconds = CURRENT_TIME - loadtime; if (seconds < 0) loadtime = CURRENT_TIME + seconds; if (seconds / 86400 > 0) { sz += sprintf(LVM_PROC_BUF, "%d day%s ", seconds / 86400, seconds / 86400 == 0 || seconds / 86400 > 1 ? "s" : ""); } sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", (seconds % 86400) / 3600, (seconds % 3600) / 60, seconds % 60); if (vg_counter > 0) { for (v = 0; v < ABS_MAX_VG; v++) { /* volume group */ if ((vg_ptr = vg[v]) != NULL) { sz += lvm_vg_info(vg_ptr, LVM_PROC_BUF); /* physical volumes */ sz += sprintf(LVM_PROC_BUF, "\n PV%s ", vg_ptr->pv_cur == 1 ? ": " : "s:"); c = 0; for (p = 0; p < vg_ptr->pv_max; p++) { if ((pv_ptr = vg_ptr->pv[p]) != NULL) { sz += lvm_pv_info(pv_ptr, LVM_PROC_BUF); c++; if (c < vg_ptr->pv_cur) sz += sprintf(LVM_PROC_BUF, "\n "); } } /* logical volumes */ sz += sprintf(LVM_PROC_BUF, "\n LV%s ", vg_ptr->lv_cur == 1 ? ": " : "s:"); c = 0; for (l = 0; l < vg_ptr->lv_max; l++) { if ((lv_ptr = vg_ptr->lv[l]) != NULL) { sz += lvm_lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF); c++; if (c < vg_ptr->lv_cur) sz += sprintf(LVM_PROC_BUF, "\n "); } } if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none"); sz += sprintf(LVM_PROC_BUF, "\n"); } } } if (buf == NULL) { lock_kernel(); buf = vmalloc(sz); unlock_kernel(); if (buf == NULL) { sz = 0; MOD_DEC_USE_COUNT; return sprintf(page, "%s - vmalloc error at line %d\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -