1 /*
2  * kernel/lvm-fs.c
3  *
4  * Copyright (C) 2001-2002 Sistina Software
5  *
6  * January-May,December 2001
7  * May 2002
8  *
9  * LVM driver is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2, or (at your option)
12  * any later version.
13  *
14  * LVM driver is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with GNU CC; see the file COPYING.  If not, write to
21  * the Free Software Foundation, 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25 
26 /*
27  * Changelog
28  *
29  *    11/01/2001 - First version (Joe Thornber)
30  *    21/03/2001 - added display of stripes and stripe size (HM)
31  *    04/10/2001 - corrected devfs_register() call in lvm_init_fs()
32  *    11/04/2001 - don't devfs_register("lvm") as user-space always does it
33  *    10/05/2001 - show more of PV name in /proc/lvm/global
34  *    16/12/2001 - fix devfs unregister order and prevent duplicate unreg (REG)
35  *
36  */
37 
38 #include <linux/config.h>
39 #include <linux/version.h>
40 
41 #include <linux/kernel.h>
42 #include <linux/vmalloc.h>
43 #include <linux/smp_lock.h>
44 
45 #include <linux/devfs_fs_kernel.h>
46 #include <linux/proc_fs.h>
47 #include <linux/init.h>
48 #include <linux/lvm.h>
49 
50 #include "lvm-internal.h"
51 
52 
53 static int _proc_read_vg(char *page, char **start, off_t off,
54 			 int count, int *eof, void *data);
55 static int _proc_read_lv(char *page, char **start, off_t off,
56 			 int count, int *eof, void *data);
57 static int _proc_read_pv(char *page, char **start, off_t off,
58 			 int count, int *eof, void *data);
59 static int _proc_read_global(char *page, char **start, off_t off,
60 			     int count, int *eof, void *data);
61 
62 static int _vg_info(vg_t * vg_ptr, char *buf);
63 static int _lv_info(vg_t * vg_ptr, lv_t * lv_ptr, char *buf);
64 static int _pv_info(pv_t * pv_ptr, char *buf);
65 
66 static void _show_uuid(const char *src, char *b, char *e);
67 
68 #if 0
69 static devfs_handle_t lvm_devfs_handle;
70 #endif
71 static devfs_handle_t vg_devfs_handle[MAX_VG];
72 static devfs_handle_t ch_devfs_handle[MAX_VG];
73 static devfs_handle_t lv_devfs_handle[MAX_LV];
74 
75 static struct proc_dir_entry *lvm_proc_dir = NULL;
76 static struct proc_dir_entry *lvm_proc_vg_subdir = NULL;
77 
78 /* inline functions */
79 
80 /* public interface */
lvm_init_fs()81 void __init lvm_init_fs()
82 {
83 	struct proc_dir_entry *pde;
84 
85 /* User-space has already registered this */
86 #if 0
87 	lvm_devfs_handle = devfs_register(0, "lvm", 0, LVM_CHAR_MAJOR, 0,
88 					  S_IFCHR | S_IRUSR | S_IWUSR |
89 					  S_IRGRP, &lvm_chr_fops, NULL);
90 #endif
91 	lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root);
92 	if (lvm_proc_dir) {
93 		lvm_proc_vg_subdir =
94 		    create_proc_entry(LVM_VG_SUBDIR, S_IFDIR,
95 				      lvm_proc_dir);
96 		pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir);
97 		if (pde != NULL)
98 			pde->read_proc = _proc_read_global;
99 	}
100 }
101 
lvm_fin_fs()102 void lvm_fin_fs()
103 {
104 #if 0
105 	devfs_unregister(lvm_devfs_handle);
106 #endif
107 	remove_proc_entry(LVM_GLOBAL, lvm_proc_dir);
108 	remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir);
109 	remove_proc_entry(LVM_DIR, &proc_root);
110 }
111 
lvm_fs_create_vg(vg_t * vg_ptr)112 void lvm_fs_create_vg(vg_t * vg_ptr)
113 {
114 	struct proc_dir_entry *pde;
115 
116 	if (!vg_ptr)
117 		return;
118 
119 	vg_devfs_handle[vg_ptr->vg_number] =
120 	    devfs_mk_dir(0, vg_ptr->vg_name, NULL);
121 
122 	ch_devfs_handle[vg_ptr->vg_number] =
123 	    devfs_register(vg_devfs_handle[vg_ptr->vg_number], "group",
124 			   DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR,
125 			   vg_ptr->vg_number,
126 			   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
127 			   &lvm_chr_fops, NULL);
128 
129 	vg_ptr->vg_dir_pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR,
130 					       lvm_proc_vg_subdir);
131 
132 	if ((pde =
133 	     create_proc_entry("group", S_IFREG, vg_ptr->vg_dir_pde))) {
134 		pde->read_proc = _proc_read_vg;
135 		pde->data = vg_ptr;
136 	}
137 
138 	vg_ptr->lv_subdir_pde =
139 	    create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
140 
141 	vg_ptr->pv_subdir_pde =
142 	    create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde);
143 }
144 
lvm_fs_remove_vg(vg_t * vg_ptr)145 void lvm_fs_remove_vg(vg_t * vg_ptr)
146 {
147 	int i;
148 
149 	if (!vg_ptr)
150 		return;
151 
152 	devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]);
153 	ch_devfs_handle[vg_ptr->vg_number] = NULL;
154 
155 	/* remove lv's */
156 	for (i = 0; i < vg_ptr->lv_max; i++)
157 		if (vg_ptr->lv[i])
158 			lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]);
159 
160 	/* must not remove directory before leaf nodes */
161 	devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]);
162 	vg_devfs_handle[vg_ptr->vg_number] = NULL;
163 
164 	/* remove pv's */
165 	for (i = 0; i < vg_ptr->pv_max; i++)
166 		if (vg_ptr->pv[i])
167 			lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]);
168 
169 	if (vg_ptr->vg_dir_pde) {
170 		remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde);
171 		vg_ptr->lv_subdir_pde = NULL;
172 
173 		remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde);
174 		vg_ptr->pv_subdir_pde = NULL;
175 
176 		remove_proc_entry("group", vg_ptr->vg_dir_pde);
177 		vg_ptr->vg_dir_pde = NULL;
178 
179 		remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir);
180 	}
181 }
182 
183 
_basename(const char * str)184 static inline const char *_basename(const char *str)
185 {
186 	const char *name = strrchr(str, '/');
187 	name = name ? name + 1 : str;
188 	return name;
189 }
190 
lvm_fs_create_lv(vg_t * vg_ptr,lv_t * lv)191 devfs_handle_t lvm_fs_create_lv(vg_t * vg_ptr, lv_t * lv)
192 {
193 	struct proc_dir_entry *pde;
194 	const char *name;
195 
196 	if (!vg_ptr || !lv)
197 		return NULL;
198 
199 	name = _basename(lv->lv_name);
200 
201 	lv_devfs_handle[MINOR(lv->lv_dev)] =
202 	    devfs_register(vg_devfs_handle[vg_ptr->vg_number], name,
203 			   DEVFS_FL_DEFAULT, LVM_BLK_MAJOR,
204 			   MINOR(lv->lv_dev),
205 			   S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
206 			   &lvm_blk_dops, NULL);
207 
208 	if (vg_ptr->lv_subdir_pde &&
209 	    (pde =
210 	     create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) {
211 		pde->read_proc = _proc_read_lv;
212 		pde->data = lv;
213 	}
214 	return lv_devfs_handle[MINOR(lv->lv_dev)];
215 }
216 
lvm_fs_remove_lv(vg_t * vg_ptr,lv_t * lv)217 void lvm_fs_remove_lv(vg_t * vg_ptr, lv_t * lv)
218 {
219 
220 	if (!vg_ptr || !lv)
221 		return;
222 
223 	devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]);
224 	lv_devfs_handle[MINOR(lv->lv_dev)] = NULL;
225 
226 	if (vg_ptr->lv_subdir_pde) {
227 		const char *name = _basename(lv->lv_name);
228 		remove_proc_entry(name, vg_ptr->lv_subdir_pde);
229 	}
230 }
231 
232 
_make_pv_name(const char * src,char * b,char * e)233 static inline void _make_pv_name(const char *src, char *b, char *e)
234 {
235 	int offset = strlen(LVM_DIR_PREFIX);
236 	if (strncmp(src, LVM_DIR_PREFIX, offset))
237 		offset = 0;
238 
239 	e--;
240 	src += offset;
241 	while (*src && (b != e)) {
242 		*b++ = (*src == '/') ? '_' : *src;
243 		src++;
244 	}
245 	*b = '\0';
246 }
247 
lvm_fs_create_pv(vg_t * vg_ptr,pv_t * pv)248 void lvm_fs_create_pv(vg_t * vg_ptr, pv_t * pv)
249 {
250 	struct proc_dir_entry *pde;
251 	char name[NAME_LEN];
252 
253 	if (!vg_ptr || !pv)
254 		return;
255 
256 	if (!vg_ptr->pv_subdir_pde)
257 		return;
258 
259 	_make_pv_name(pv->pv_name, name, name + sizeof(name));
260 	if ((pde =
261 	     create_proc_entry(name, S_IFREG, vg_ptr->pv_subdir_pde))) {
262 		pde->read_proc = _proc_read_pv;
263 		pde->data = pv;
264 	}
265 }
266 
lvm_fs_remove_pv(vg_t * vg_ptr,pv_t * pv)267 void lvm_fs_remove_pv(vg_t * vg_ptr, pv_t * pv)
268 {
269 	char name[NAME_LEN];
270 
271 	if (!vg_ptr || !pv)
272 		return;
273 
274 	if (!vg_ptr->pv_subdir_pde)
275 		return;
276 
277 	_make_pv_name(pv->pv_name, name, name + sizeof(name));
278 	remove_proc_entry(name, vg_ptr->pv_subdir_pde);
279 }
280 
281 
_proc_read_vg(char * page,char ** start,off_t off,int count,int * eof,void * data)282 static int _proc_read_vg(char *page, char **start, off_t off,
283 			 int count, int *eof, void *data)
284 {
285 	int sz = 0;
286 	vg_t *vg_ptr = data;
287 	char uuid[NAME_LEN];
288 
289 	sz += sprintf(page + sz, "name:         %s\n", vg_ptr->vg_name);
290 	sz += sprintf(page + sz, "size:         %u\n",
291 		      vg_ptr->pe_total * vg_ptr->pe_size / 2);
292 	sz += sprintf(page + sz, "access:       %u\n", vg_ptr->vg_access);
293 	sz += sprintf(page + sz, "status:       %u\n", vg_ptr->vg_status);
294 	sz += sprintf(page + sz, "number:       %u\n", vg_ptr->vg_number);
295 	sz += sprintf(page + sz, "LV max:       %u\n", vg_ptr->lv_max);
296 	sz += sprintf(page + sz, "LV current:   %u\n", vg_ptr->lv_cur);
297 	sz += sprintf(page + sz, "LV open:      %u\n", vg_ptr->lv_open);
298 	sz += sprintf(page + sz, "PV max:       %u\n", vg_ptr->pv_max);
299 	sz += sprintf(page + sz, "PV current:   %u\n", vg_ptr->pv_cur);
300 	sz += sprintf(page + sz, "PV active:    %u\n", vg_ptr->pv_act);
301 	sz +=
302 	    sprintf(page + sz, "PE size:      %u\n", vg_ptr->pe_size / 2);
303 	sz += sprintf(page + sz, "PE total:     %u\n", vg_ptr->pe_total);
304 	sz +=
305 	    sprintf(page + sz, "PE allocated: %u\n", vg_ptr->pe_allocated);
306 
307 	_show_uuid(vg_ptr->vg_uuid, uuid, uuid + sizeof(uuid));
308 	sz += sprintf(page + sz, "uuid:         %s\n", uuid);
309 
310 	return sz;
311 }
312 
_proc_read_lv(char * page,char ** start,off_t off,int count,int * eof,void * data)313 static int _proc_read_lv(char *page, char **start, off_t off,
314 			 int count, int *eof, void *data)
315 {
316 	int sz = 0;
317 	lv_t *lv = data;
318 
319 	sz += sprintf(page + sz, "name:         %s\n", lv->lv_name);
320 	sz += sprintf(page + sz, "size:         %u\n", lv->lv_size);
321 	sz += sprintf(page + sz, "access:       %u\n", lv->lv_access);
322 	sz += sprintf(page + sz, "status:       %u\n", lv->lv_status);
323 	sz += sprintf(page + sz, "number:       %u\n", lv->lv_number);
324 	sz += sprintf(page + sz, "open:         %u\n", lv->lv_open);
325 	sz += sprintf(page + sz, "allocation:   %u\n", lv->lv_allocation);
326 	if (lv->lv_stripes > 1) {
327 		sz += sprintf(page + sz, "stripes:      %u\n",
328 			      lv->lv_stripes);
329 		sz += sprintf(page + sz, "stripesize:   %u\n",
330 			      lv->lv_stripesize);
331 	}
332 	sz += sprintf(page + sz, "device:       %02u:%02u\n",
333 		      MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
334 
335 	return sz;
336 }
337 
_proc_read_pv(char * page,char ** start,off_t off,int count,int * eof,void * data)338 static int _proc_read_pv(char *page, char **start, off_t off,
339 			 int count, int *eof, void *data)
340 {
341 	int sz = 0;
342 	pv_t *pv = data;
343 	char uuid[NAME_LEN];
344 
345 	sz += sprintf(page + sz, "name:         %s\n", pv->pv_name);
346 	sz += sprintf(page + sz, "size:         %u\n", pv->pv_size);
347 	sz += sprintf(page + sz, "status:       %u\n", pv->pv_status);
348 	sz += sprintf(page + sz, "number:       %u\n", pv->pv_number);
349 	sz += sprintf(page + sz, "allocatable:  %u\n", pv->pv_allocatable);
350 	sz += sprintf(page + sz, "LV current:   %u\n", pv->lv_cur);
351 	sz += sprintf(page + sz, "PE size:      %u\n", pv->pe_size / 2);
352 	sz += sprintf(page + sz, "PE total:     %u\n", pv->pe_total);
353 	sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated);
354 	sz += sprintf(page + sz, "device:       %02u:%02u\n",
355 		      MAJOR(pv->pv_dev), MINOR(pv->pv_dev));
356 
357 	_show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid));
358 	sz += sprintf(page + sz, "uuid:         %s\n", uuid);
359 
360 	return sz;
361 }
362 
_proc_read_global(char * page,char ** start,off_t pos,int count,int * eof,void * data)363 static int _proc_read_global(char *page, char **start, off_t pos,
364 			     int count, int *eof, void *data)
365 {
366 
367 #define  LVM_PROC_BUF   ( i == 0 ? dummy_buf : &buf[sz])
368 
369 	int c, i, l, p, v, vg_counter, pv_counter, lv_counter,
370 	    lv_open_counter, lv_open_total, pe_t_bytes, hash_table_bytes,
371 	    lv_block_exception_t_bytes, seconds;
372 	static off_t sz;
373 	off_t sz_last;
374 	static char *buf = NULL;
375 	static char dummy_buf[160];	/* sized for 2 lines */
376 	vg_t *vg_ptr;
377 	lv_t *lv_ptr;
378 	pv_t *pv_ptr;
379 
380 
381 #ifdef DEBUG_LVM_PROC_GET_INFO
382 	printk(KERN_DEBUG
383 	       "%s - lvm_proc_get_global_info CALLED  pos: %lu  count: %d\n",
384 	       lvm_name, pos, count);
385 #endif
386 
387 	if (pos != 0 && buf != NULL)
388 		goto out;
389 
390 	sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter =
391 	    lv_open_total = pe_t_bytes = hash_table_bytes =
392 	    lv_block_exception_t_bytes = 0;
393 
394 	/* get some statistics */
395 	for (v = 0; v < ABS_MAX_VG; v++) {
396 		if ((vg_ptr = vg[v]) != NULL) {
397 			vg_counter++;
398 			pv_counter += vg_ptr->pv_cur;
399 			lv_counter += vg_ptr->lv_cur;
400 			if (vg_ptr->lv_cur > 0) {
401 				for (l = 0; l < vg[v]->lv_max; l++) {
402 					if ((lv_ptr =
403 					     vg_ptr->lv[l]) != NULL) {
404 						pe_t_bytes +=
405 						    lv_ptr->
406 						    lv_allocated_le;
407 						hash_table_bytes +=
408 						    lv_ptr->
409 						    lv_snapshot_hash_table_size;
410 						if (lv_ptr->
411 						    lv_block_exception !=
412 						    NULL)
413 							lv_block_exception_t_bytes
414 							    +=
415 							    lv_ptr->
416 							    lv_remap_end;
417 						if (lv_ptr->lv_open > 0) {
418 							lv_open_counter++;
419 							lv_open_total +=
420 							    lv_ptr->
421 							    lv_open;
422 						}
423 					}
424 				}
425 			}
426 		}
427 	}
428 
429 	pe_t_bytes *= sizeof(pe_t);
430 	lv_block_exception_t_bytes *= sizeof(lv_block_exception_t);
431 
432 	if (buf != NULL) {
433 		P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__);
434 		lock_kernel();
435 		vfree(buf);
436 		unlock_kernel();
437 		buf = NULL;
438 	}
439 	/* 2 times: first to get size to allocate buffer,
440 	   2nd to fill the malloced buffer */
441 	for (i = 0; i < 2; i++) {
442 		sz = 0;
443 		sz += sprintf(LVM_PROC_BUF, "LVM "
444 #ifdef MODULE
445 			      "module"
446 #else
447 			      "driver"
448 #endif
449 			      " %s\n\n"
450 			      "Total:  %d VG%s  %d PV%s  %d LV%s ",
451 			      lvm_version,
452 			      vg_counter, vg_counter == 1 ? "" : "s",
453 			      pv_counter, pv_counter == 1 ? "" : "s",
454 			      lv_counter, lv_counter == 1 ? "" : "s");
455 		sz += sprintf(LVM_PROC_BUF,
456 			      "(%d LV%s open",
457 			      lv_open_counter,
458 			      lv_open_counter == 1 ? "" : "s");
459 		if (lv_open_total > 0)
460 			sz += sprintf(LVM_PROC_BUF,
461 				      " %d times)\n", lv_open_total);
462 		else
463 			sz += sprintf(LVM_PROC_BUF, ")");
464 		sz += sprintf(LVM_PROC_BUF,
465 			      "\nGlobal: %lu bytes malloced   IOP version: %d   ",
466 			      vg_counter * sizeof(vg_t) +
467 			      pv_counter * sizeof(pv_t) +
468 			      lv_counter * sizeof(lv_t) +
469 			      pe_t_bytes + hash_table_bytes +
470 			      lv_block_exception_t_bytes + sz_last,
471 			      lvm_iop_version);
472 
473 		seconds = CURRENT_TIME - loadtime;
474 		if (seconds < 0)
475 			loadtime = CURRENT_TIME + seconds;
476 		if (seconds / 86400 > 0) {
477 			sz += sprintf(LVM_PROC_BUF, "%d day%s ",
478 				      seconds / 86400,
479 				      seconds / 86400 == 0 ||
480 				      seconds / 86400 > 1 ? "s" : "");
481 		}
482 		sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n",
483 			      (seconds % 86400) / 3600,
484 			      (seconds % 3600) / 60, seconds % 60);
485 
486 		if (vg_counter > 0) {
487 			for (v = 0; v < ABS_MAX_VG; v++) {
488 				/* volume group */
489 				if ((vg_ptr = vg[v]) != NULL) {
490 					sz +=
491 					    _vg_info(vg_ptr, LVM_PROC_BUF);
492 
493 					/* physical volumes */
494 					sz += sprintf(LVM_PROC_BUF,
495 						      "\n  PV%s ",
496 						      vg_ptr->pv_cur ==
497 						      1 ? ": " : "s:");
498 					c = 0;
499 					for (p = 0; p < vg_ptr->pv_max;
500 					     p++) {
501 						if ((pv_ptr =
502 						     vg_ptr->pv[p]) !=
503 						    NULL) {
504 							sz +=
505 							    _pv_info
506 							    (pv_ptr,
507 							     LVM_PROC_BUF);
508 
509 							c++;
510 							if (c <
511 							    vg_ptr->pv_cur)
512 								sz +=
513 								    sprintf
514 								    (LVM_PROC_BUF,
515 								     "\n       ");
516 						}
517 					}
518 
519 					/* logical volumes */
520 					sz += sprintf(LVM_PROC_BUF,
521 						      "\n    LV%s ",
522 						      vg_ptr->lv_cur ==
523 						      1 ? ": " : "s:");
524 					c = 0;
525 					for (l = 0; l < vg_ptr->lv_max;
526 					     l++) {
527 						if ((lv_ptr =
528 						     vg_ptr->lv[l]) !=
529 						    NULL) {
530 							sz +=
531 							    _lv_info
532 							    (vg_ptr,
533 							     lv_ptr,
534 							     LVM_PROC_BUF);
535 							c++;
536 							if (c <
537 							    vg_ptr->lv_cur)
538 								sz +=
539 								    sprintf
540 								    (LVM_PROC_BUF,
541 								     "\n         ");
542 						}
543 					}
544 					if (vg_ptr->lv_cur == 0)
545 						sz +=
546 						    sprintf(LVM_PROC_BUF,
547 							    "none");
548 					sz += sprintf(LVM_PROC_BUF, "\n");
549 				}
550 			}
551 		}
552 		if (buf == NULL) {
553 			lock_kernel();
554 			buf = vmalloc(sz);
555 			unlock_kernel();
556 			if (buf == NULL) {
557 				sz = 0;
558 				return sprintf(page,
559 					       "%s - vmalloc error at line %d\n",
560 					       lvm_name, __LINE__);
561 			}
562 		}
563 		sz_last = sz;
564 	}
565 
566       out:
567 	if (pos > sz - 1) {
568 		lock_kernel();
569 		vfree(buf);
570 		unlock_kernel();
571 		buf = NULL;
572 		return 0;
573 	}
574 	*start = &buf[pos];
575 	if (sz - pos < count)
576 		return sz - pos;
577 	else
578 		return count;
579 
580 #undef LVM_PROC_BUF
581 }
582 
583 /*
584  * provide VG info for proc filesystem use (global)
585  */
_vg_info(vg_t * vg_ptr,char * buf)586 static int _vg_info(vg_t * vg_ptr, char *buf)
587 {
588 	int sz = 0;
589 	char inactive_flag = ' ';
590 
591 	if (!(vg_ptr->vg_status & VG_ACTIVE))
592 		inactive_flag = 'I';
593 	sz = sprintf(buf,
594 		     "\nVG: %c%s  [%d PV, %d LV/%d open] "
595 		     " PE Size: %d KB\n"
596 		     "  Usage [KB/PE]: %d /%d total  "
597 		     "%d /%d used  %d /%d free",
598 		     inactive_flag,
599 		     vg_ptr->vg_name,
600 		     vg_ptr->pv_cur,
601 		     vg_ptr->lv_cur,
602 		     vg_ptr->lv_open,
603 		     vg_ptr->pe_size >> 1,
604 		     vg_ptr->pe_size * vg_ptr->pe_total >> 1,
605 		     vg_ptr->pe_total,
606 		     vg_ptr->pe_allocated * vg_ptr->pe_size >> 1,
607 		     vg_ptr->pe_allocated,
608 		     (vg_ptr->pe_total - vg_ptr->pe_allocated) *
609 		     vg_ptr->pe_size >> 1,
610 		     vg_ptr->pe_total - vg_ptr->pe_allocated);
611 	return sz;
612 }
613 
614 
615 /*
616  * provide LV info for proc filesystem use (global)
617  */
_lv_info(vg_t * vg_ptr,lv_t * lv_ptr,char * buf)618 static int _lv_info(vg_t * vg_ptr, lv_t * lv_ptr, char *buf)
619 {
620 	int sz = 0;
621 	char inactive_flag = 'A', allocation_flag = ' ',
622 	    stripes_flag = ' ', rw_flag = ' ', *basename;
623 
624 	if (!(lv_ptr->lv_status & LV_ACTIVE))
625 		inactive_flag = 'I';
626 	rw_flag = 'R';
627 	if (lv_ptr->lv_access & LV_WRITE)
628 		rw_flag = 'W';
629 	allocation_flag = 'D';
630 	if (lv_ptr->lv_allocation & LV_CONTIGUOUS)
631 		allocation_flag = 'C';
632 	stripes_flag = 'L';
633 	if (lv_ptr->lv_stripes > 1)
634 		stripes_flag = 'S';
635 	sz += sprintf(buf + sz,
636 		      "[%c%c%c%c",
637 		      inactive_flag,
638 		      rw_flag, allocation_flag, stripes_flag);
639 	if (lv_ptr->lv_stripes > 1)
640 		sz += sprintf(buf + sz, "%-2d", lv_ptr->lv_stripes);
641 	else
642 		sz += sprintf(buf + sz, "  ");
643 
644 	/* FIXME: use _basename */
645 	basename = strrchr(lv_ptr->lv_name, '/');
646 	if (basename == 0)
647 		basename = lv_ptr->lv_name;
648 	else
649 		basename++;
650 	sz += sprintf(buf + sz, "] %-25s", basename);
651 	if (strlen(basename) > 25)
652 		sz += sprintf(buf + sz,
653 			      "\n                              ");
654 	sz += sprintf(buf + sz, "%9d /%-6d   ",
655 		      lv_ptr->lv_size >> 1,
656 		      lv_ptr->lv_size / vg_ptr->pe_size);
657 
658 	if (lv_ptr->lv_open == 0)
659 		sz += sprintf(buf + sz, "close");
660 	else
661 		sz += sprintf(buf + sz, "%dx open", lv_ptr->lv_open);
662 
663 	return sz;
664 }
665 
666 
667 /*
668  * provide PV info for proc filesystem use (global)
669  */
_pv_info(pv_t * pv,char * buf)670 static int _pv_info(pv_t * pv, char *buf)
671 {
672 	int sz = 0;
673 	char inactive_flag = 'A', allocation_flag = ' ';
674 	char *pv_name = NULL;
675 
676 	if (!(pv->pv_status & PV_ACTIVE))
677 		inactive_flag = 'I';
678 	allocation_flag = 'A';
679 	if (!(pv->pv_allocatable & PV_ALLOCATABLE))
680 		allocation_flag = 'N';
681 	pv_name = strchr(pv->pv_name + 1, '/');
682 	if (pv_name == 0)
683 		pv_name = pv->pv_name;
684 	else
685 		pv_name++;
686 	sz = sprintf(buf,
687 		     "[%c%c] %-21s %8d /%-6d  "
688 		     "%8d /%-6d  %8d /%-6d",
689 		     inactive_flag,
690 		     allocation_flag,
691 		     pv_name,
692 		     pv->pe_total * pv->pe_size >> 1,
693 		     pv->pe_total,
694 		     pv->pe_allocated * pv->pe_size >> 1,
695 		     pv->pe_allocated,
696 		     (pv->pe_total - pv->pe_allocated) *
697 		     pv->pe_size >> 1, pv->pe_total - pv->pe_allocated);
698 	return sz;
699 }
700 
_show_uuid(const char * src,char * b,char * e)701 static void _show_uuid(const char *src, char *b, char *e)
702 {
703 	int i;
704 
705 	e--;
706 	for (i = 0; *src && (b != e); i++) {
707 		if (i && !(i & 0x3))
708 			*b++ = '-';
709 		*b++ = *src++;
710 	}
711 	*b = '\0';
712 }
713