lvm-fs.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:17k
- /*
- * kernel/lvm-fs.c
- *
- * Copyright (C) 2001 Sistina Software
- *
- * January,February 2001
- *
- * 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
- *
- * 11/01/2001 - First version (Joe Thornber)
- * 21/03/2001 - added display of stripes and stripe size (HM)
- * 04/10/2001 - corrected devfs_register() call in lvm_init_fs()
- * 11/04/2001 - don't devfs_register("lvm") as user-space always does it
- * 10/05/2001 - show more of PV name in /proc/lvm/global
- * 16/12/2001 - fix devfs unregister order and prevent duplicate unreg (REG)
- *
- */
- #include <linux/config.h>
- #include <linux/version.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/vmalloc.h>
- #include <linux/smp_lock.h>
- #include <linux/devfs_fs_kernel.h>
- #include <linux/proc_fs.h>
- #include <linux/init.h>
- #include <linux/lvm.h>
- #include "lvm-internal.h"
- static int _proc_read_vg(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- static int _proc_read_lv(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- static int _proc_read_pv(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- static int _proc_read_global(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- static int _vg_info(vg_t *vg_ptr, char *buf);
- static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf);
- static int _pv_info(pv_t *pv_ptr, char *buf);
- static void _show_uuid(const char *src, char *b, char *e);
- static 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];
- static struct proc_dir_entry *lvm_proc_dir = NULL;
- static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;
- /* inline functions */
- /* public interface */
- void __init lvm_init_fs() {
- struct proc_dir_entry *pde;
- /* Must create device node. Think about "devfs=only" situation */
- lvm_devfs_handle = devfs_register(
- 0 , "lvm", 0, LVM_CHAR_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
- &lvm_chr_fops, NULL);
- lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root);
- if (lvm_proc_dir) {
- 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 = _proc_read_global;
- }
- }
- void lvm_fin_fs() {
- devfs_unregister (lvm_devfs_handle);
- remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
- remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
- remove_proc_entry(LVM_DIR, &proc_root);
- }
- void lvm_fs_create_vg(vg_t *vg_ptr) {
- struct proc_dir_entry *pde;
- vg_devfs_handle[vg_ptr->vg_number] =
- devfs_mk_dir(0, vg_ptr->vg_name, NULL);
- ch_devfs_handle[vg_ptr->vg_number] = devfs_register(
- vg_devfs_handle[vg_ptr->vg_number] , "group",
- DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
- &lvm_chr_fops, NULL);
- vg_ptr->vg_dir_pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
- lvm_proc_vg_subdir);
- if((pde = create_proc_entry("group", S_IFREG, vg_ptr->vg_dir_pde))) {
- pde->read_proc = _proc_read_vg;
- pde->data = vg_ptr;
- }
- vg_ptr->lv_subdir_pde =
- create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
- vg_ptr->pv_subdir_pde =
- create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
- }
- void lvm_fs_remove_vg(vg_t *vg_ptr) {
- int i;
- devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]);
- ch_devfs_handle[vg_ptr->vg_number] = NULL;
- /* remove lv's */
- for(i = 0; i < vg_ptr->lv_max; i++)
- if(vg_ptr->lv[i]) lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]);
- /* remove pv's */
- for(i = 0; i < vg_ptr->pv_max; i++)
- if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
- /* must not remove directory before leaf nodes */
- devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
- vg_devfs_handle[vg_ptr->vg_number] = NULL;
- if(vg_ptr->vg_dir_pde) {
- remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
- vg_ptr->lv_subdir_pde = NULL;
- remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde);
- vg_ptr->pv_subdir_pde = NULL;
- remove_proc_entry("group", vg_ptr->vg_dir_pde);
- vg_ptr->vg_dir_pde = NULL;
- remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir);
- }
- }
- static inline const char *_basename(const char *str) {
- const char *name = strrchr(str, '/');
- name = name ? name + 1 : str;
- return name;
- }
- devfs_handle_t lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) {
- struct proc_dir_entry *pde;
- const char *name = _basename(lv->lv_name);
- lv_devfs_handle[MINOR(lv->lv_dev)] = devfs_register(
- vg_devfs_handle[vg_ptr->vg_number], name,
- DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, MINOR(lv->lv_dev),
- S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
- &lvm_blk_dops, NULL);
- if(vg_ptr->lv_subdir_pde &&
- (pde = create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) {
- pde->read_proc = _proc_read_lv;
- pde->data = lv;
- }
- return lv_devfs_handle[MINOR(lv->lv_dev)];
- }
- void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) {
- devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]);
- lv_devfs_handle[MINOR(lv->lv_dev)] = NULL;
- if(vg_ptr->lv_subdir_pde) {
- const char *name = _basename(lv->lv_name);
- remove_proc_entry(name, vg_ptr->lv_subdir_pde);
- }
- }
- static inline void _make_pv_name(const char *src, char *b, char *e) {
- int offset = strlen(LVM_DIR_PREFIX);
- if(strncmp(src, LVM_DIR_PREFIX, offset))
- offset = 0;
- e--;
- src += offset;
- while(*src && (b != e)) {
- *b++ = (*src == '/') ? '_' : *src;
- src++;
- }
- *b = ' ';
- }
- void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv) {
- struct proc_dir_entry *pde;
- char name[NAME_LEN];
- if(!vg_ptr->pv_subdir_pde)
- return;
- _make_pv_name(pv->pv_name, name, name + sizeof(name));
- if((pde = create_proc_entry(name, S_IFREG, vg_ptr->pv_subdir_pde))) {
- pde->read_proc = _proc_read_pv;
- pde->data = pv;
- }
- }
- void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) {
- char name[NAME_LEN];
- if(!vg_ptr->pv_subdir_pde)
- return;
- _make_pv_name(pv->pv_name, name, name + sizeof(name));
- remove_proc_entry(name, vg_ptr->pv_subdir_pde);
- }
- static int _proc_read_vg(char *page, char **start, off_t off,
- int count, int *eof, void *data) {
- int sz = 0;
- vg_t *vg_ptr = data;
- char uuid[NAME_LEN];
- sz += sprintf(page + sz, "name: %sn", vg_ptr->vg_name);
- sz += sprintf(page + sz, "size: %un",
- vg_ptr->pe_total * vg_ptr->pe_size / 2);
- sz += sprintf(page + sz, "access: %un", vg_ptr->vg_access);
- sz += sprintf(page + sz, "status: %un", vg_ptr->vg_status);
- sz += sprintf(page + sz, "number: %un", vg_ptr->vg_number);
- sz += sprintf(page + sz, "LV max: %un", vg_ptr->lv_max);
- sz += sprintf(page + sz, "LV current: %un", vg_ptr->lv_cur);
- sz += sprintf(page + sz, "LV open: %un", vg_ptr->lv_open);
- sz += sprintf(page + sz, "PV max: %un", vg_ptr->pv_max);
- sz += sprintf(page + sz, "PV current: %un", vg_ptr->pv_cur);
- sz += sprintf(page + sz, "PV active: %un", vg_ptr->pv_act);
- sz += sprintf(page + sz, "PE size: %un", vg_ptr->pe_size / 2);
- sz += sprintf(page + sz, "PE total: %un", vg_ptr->pe_total);
- sz += sprintf(page + sz, "PE allocated: %un", vg_ptr->pe_allocated);
- _show_uuid(vg_ptr->vg_uuid, uuid, uuid + sizeof(uuid));
- sz += sprintf(page + sz, "uuid: %sn", uuid);
- return sz;
- }
- static int _proc_read_lv(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: %sn", lv->lv_name);
- sz += sprintf(page + sz, "size: %un", lv->lv_size);
- sz += sprintf(page + sz, "access: %un", lv->lv_access);
- sz += sprintf(page + sz, "status: %un", lv->lv_status);
- sz += sprintf(page + sz, "number: %un", lv->lv_number);
- sz += sprintf(page + sz, "open: %un", lv->lv_open);
- sz += sprintf(page + sz, "allocation: %un", lv->lv_allocation);
- if(lv->lv_stripes > 1) {
- sz += sprintf(page + sz, "stripes: %un",
- lv->lv_stripes);
- sz += sprintf(page + sz, "stripesize: %un",
- lv->lv_stripesize);
- }
- sz += sprintf(page + sz, "device: %02u:%02un",
- MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
- return sz;
- }
- static int _proc_read_pv(char *page, char **start, off_t off,
- int count, int *eof, void *data) {
- int sz = 0;
- pv_t *pv = data;
- char uuid[NAME_LEN];
- sz += sprintf(page + sz, "name: %sn", pv->pv_name);
- sz += sprintf(page + sz, "size: %un", pv->pv_size);
- sz += sprintf(page + sz, "status: %un", pv->pv_status);
- sz += sprintf(page + sz, "number: %un", pv->pv_number);
- sz += sprintf(page + sz, "allocatable: %un", pv->pv_allocatable);
- sz += sprintf(page + sz, "LV current: %un", pv->lv_cur);
- sz += sprintf(page + sz, "PE size: %un", pv->pe_size / 2);
- sz += sprintf(page + sz, "PE total: %un", pv->pe_total);
- sz += sprintf(page + sz, "PE allocated: %un", pv->pe_allocated);
- sz += sprintf(page + sz, "device: %02u:%02un",
- MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
- _show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid));
- sz += sprintf(page + sz, "uuid: %sn", uuid);
- return sz;
- }
- static int _proc_read_global(char *page, char **start, off_t pos, int count,
- int *eof, void *data) {
- #define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz])
- 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: %dn",
- lvm_name, pos, count);
- #endif
- if(pos != 0 && buf != NULL)
- goto out;
- 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;
- /* get some statistics */
- 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) {
- P_KFREE("%s -- vfree %dn", lvm_name, __LINE__);
- 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
- " %snn"
- "Total: %d VG%s %d PV%s %d LV%s ",
- lvm_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 activen",
- (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 += _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 += _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 += _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;
- return sprintf(page, "%s - vmalloc error at line %dn",
- lvm_name, __LINE__);
- }
- }
- sz_last = sz;
- }
- out:
- 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;
- #undef LVM_PROC_BUF
- }
- /*
- * provide VG info for proc filesystem use (global)
- */
- static int _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 KBn"
- " 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)
- */
- static int _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 = ' ', *basename;
- 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, " ");
- /* FIXME: use _basename */
- 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)
- */
- static int _pv_info(pv_t *pv, char *buf) {
- int sz = 0;
- char inactive_flag = 'A', allocation_flag = ' ';
- char *pv_name = NULL;
- if (!(pv->pv_status & PV_ACTIVE))
- inactive_flag = 'I';
- allocation_flag = 'A';
- if (!(pv->pv_allocatable & PV_ALLOCATABLE))
- allocation_flag = 'N';
- pv_name = strchr(pv->pv_name+1,'/');
- if ( pv_name == 0) pv_name = pv->pv_name;
- else pv_name++;
- sz = sprintf(buf,
- "[%c%c] %-21s %8d /%-6d "
- "%8d /%-6d %8d /%-6d",
- inactive_flag,
- allocation_flag,
- pv_name,
- pv->pe_total * pv->pe_size >> 1,
- pv->pe_total,
- pv->pe_allocated * pv->pe_size >> 1,
- pv->pe_allocated,
- (pv->pe_total - pv->pe_allocated) *
- pv->pe_size >> 1,
- pv->pe_total - pv->pe_allocated);
- return sz;
- }
- static void _show_uuid(const char *src, char *b, char *e) {
- int i;
- e--;
- for(i = 0; *src && (b != e); i++) {
- if(i && !(i & 0x3))
- *b++ = '-';
- *b++ = *src++;
- }
- *b = ' ';
- }
- MODULE_LICENSE("GPL");