added mtd driver
[linux-2.4.git] / drivers / md / lvm-fs.c
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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  */
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  */
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  */
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
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 }