1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5 * Author: Hariharan Thantry <thantry@users.sourceforge.net>
7 * This file is part of Lustre, http://www.lustre.org.
9 * Lustre is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * Lustre is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Lustre; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #define DEBUG_SUBSYSTEM S_CLASS
26 #include <linux/config.h>
27 #include <linux/module.h>
28 #include <linux/version.h>
29 #include <linux/slab.h>
30 #include <linux/types.h>
31 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
32 #include <asm/statfs.h>
34 #include <linux/seq_file.h>
37 #include <liblustre.h>
40 #include <linux/obd_class.h>
41 #include <linux/lprocfs_status.h>
45 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
48 struct proc_dir_entry* temp;
54 while (temp != NULL) {
55 if (!strcmp(temp->name, name))
63 /* lprocfs API calls */
65 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
68 if ((root == NULL) || (list == NULL))
72 struct proc_dir_entry *cur_root, *proc;
73 char *pathcopy, *cur, *next;
74 int pathsize = strlen(list->name)+1;
79 /* need copy of path for strsep */
80 OBD_ALLOC(pathcopy, pathsize);
85 strcpy(pathcopy, list->name);
87 while (cur_root && (cur = strsep(&next, "/"))) {
88 if (*cur =='\0') /* skip double/trailing "/" */
91 proc = lprocfs_srch(cur_root, cur);
92 CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
93 cur_root->name, cur, next,
94 (proc ? "exists" : "new"));
96 cur_root = (proc ? proc :
97 proc_mkdir(cur, cur_root));
99 proc = create_proc_entry(cur, 0444, cur_root);
102 OBD_FREE(pathcopy, pathsize);
104 if ((cur_root == NULL) || (proc == NULL)) {
105 CERROR("LprocFS: No memory to create /proc entry %s",
110 proc->read_proc = list->read_fptr;
111 proc->write_proc = list->write_fptr;
112 proc->data = (list->data ? list->data : data);
118 void lprocfs_remove(struct proc_dir_entry* root)
120 struct proc_dir_entry *temp = root;
121 struct proc_dir_entry *rm_entry;
122 struct proc_dir_entry *parent;
124 LASSERT(root != NULL);
125 parent = root->parent;
126 LASSERT(parent != NULL);
134 remove_proc_entry(rm_entry->name, rm_entry->parent);
140 struct proc_dir_entry *lprocfs_register(const char *name,
141 struct proc_dir_entry *parent,
142 struct lprocfs_vars *list, void *data)
144 struct proc_dir_entry *newchild;
146 newchild = lprocfs_srch(parent, name);
148 CERROR(" Lproc: Attempting to register %s more than once \n",
150 return ERR_PTR(-EALREADY);
153 newchild = proc_mkdir(name, parent);
154 if (newchild && list) {
155 int rc = lprocfs_add_vars(newchild, list, data);
157 lprocfs_remove(newchild);
164 /* Generic callbacks */
166 int lprocfs_rd_u64(char *page, char **start, off_t off,
167 int count, int *eof, void *data)
169 LASSERT(data != NULL);
171 return snprintf(page, count, LPU64"\n", *(__u64 *)data);
174 int lprocfs_rd_uuid(char* page, char **start, off_t off, int count,
175 int *eof, void *data)
177 struct obd_device* dev = (struct obd_device*)data;
179 LASSERT(dev != NULL);
181 return snprintf(page, count, "%s\n", dev->obd_uuid.uuid);
184 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
185 int *eof, void *data)
187 struct obd_device* dev = (struct obd_device *)data;
189 LASSERT(dev != NULL);
190 LASSERT(dev->obd_name != NULL);
192 return snprintf(page, count, "%s\n", dev->obd_name);
195 int lprocfs_rd_blksize(char* page, char **start, off_t off, int count,
196 int *eof, struct statfs *sfs)
198 LASSERT(sfs != NULL);
200 return snprintf(page, count, "%lu\n", sfs->f_bsize);
203 int lprocfs_rd_kbytestotal(char* page, char **start, off_t off, int count,
204 int *eof, struct statfs *sfs)
209 LASSERT(sfs != NULL);
210 blk_size = sfs->f_bsize >> 10;
211 result = sfs->f_blocks;
213 while (blk_size >>= 1)
217 return snprintf(page, count, LPU64"\n", result);
220 int lprocfs_rd_kbytesfree(char* page, char **start, off_t off, int count,
221 int *eof, struct statfs *sfs)
226 LASSERT(sfs != NULL);
227 blk_size = sfs->f_bsize >> 10;
228 result = sfs->f_bfree;
230 while (blk_size >>= 1)
234 return snprintf(page, count, LPU64"\n", result);
237 int lprocfs_rd_filestotal(char* page, char **start, off_t off, int count,
238 int *eof, struct statfs *sfs)
240 LASSERT(sfs != NULL);
242 return snprintf(page, count, "%ld\n", sfs->f_files);
245 int lprocfs_rd_filesfree(char* page, char **start, off_t off, int count,
246 int *eof, struct statfs *sfs)
248 LASSERT(sfs != NULL);
250 return snprintf(page, count, "%ld\n", sfs->f_ffree);
253 int lprocfs_rd_filegroups(char* page, char **start, off_t off, int count,
254 int *eof, struct statfs *sfs)
257 return snprintf(page, count, "unimplemented\n");
260 int lprocfs_rd_server_uuid(char* page, char **start, off_t off, int count,
261 int *eof, void *data)
263 struct obd_device *obd = (struct obd_device *)data;
264 struct client_obd *cli;
266 LASSERT(obd != NULL);
269 return snprintf(page, count, "%s\n",
270 cli->cl_import->imp_target_uuid.uuid);
273 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
274 int *eof, void *data)
276 struct obd_device *obd = (struct obd_device*)data;
277 struct ptlrpc_connection *conn;
279 LASSERT(obd != NULL);
280 conn = obd->u.cli.cl_import->imp_connection;
281 LASSERT(conn != NULL);
283 return snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
286 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
287 int *eof, void *data)
289 struct obd_type* class = (struct obd_type*) data;
291 LASSERT(class != NULL);
293 return snprintf(page, count, "%d\n", class->typ_refcnt);
296 int lprocfs_obd_attach(struct obd_device *dev, struct lprocfs_vars *list)
300 LASSERT(dev != NULL);
301 LASSERT(dev->obd_type != NULL);
302 LASSERT(dev->obd_type->typ_procroot != NULL);
304 dev->obd_proc_entry = lprocfs_register(dev->obd_name,
305 dev->obd_type->typ_procroot,
307 if (IS_ERR(dev->obd_proc_entry)) {
308 rc = PTR_ERR(dev->obd_proc_entry);
309 dev->obd_proc_entry = NULL;
314 int lprocfs_obd_detach(struct obd_device *dev)
316 if (dev && dev->obd_proc_entry) {
317 lprocfs_remove(dev->obd_proc_entry);
318 dev->obd_proc_entry = NULL;
323 struct lprocfs_counters* lprocfs_alloc_counters(unsigned int num)
325 struct lprocfs_counters* cntrs;
330 csize = offsetof(struct lprocfs_counters, cntr[num]);
331 OBD_ALLOC(cntrs, csize);
338 void lprocfs_free_counters(struct lprocfs_counters* cntrs)
341 int csize = offsetof(struct lprocfs_counters, cntr[cntrs->num]); OBD_FREE(cntrs, csize);
345 /* Reset counter under lock */
346 int lprocfs_counter_write(struct file *file, const char *buffer,
347 unsigned long count, void *data)
349 struct lprocfs_counters *cntrs = (struct lprocfs_counters*) data;
351 LASSERT(cntrs != NULL);
353 for (i = 0; i < cntrs->num; i++) {
354 struct lprocfs_counter *cntr = &(cntrs->cntr[i]);
355 spinlock_t *lock = (cntr->config & LPROCFS_CNTR_EXTERNALLOCK) ?
356 cntr->l.external : &cntr->l.internal;
361 cntr->min = (~(__u64)0);
369 static void *lprocfs_counters_seq_start(struct seq_file *p, loff_t *pos)
371 struct lprocfs_counters *cntrs = p->private;
372 return (*pos >= cntrs->num) ? NULL : (void*) &cntrs->cntr[*pos];
375 static void lprocfs_counters_seq_stop(struct seq_file *p, void *v)
379 static void *lprocfs_counters_seq_next(struct seq_file *p, void *v,
382 struct lprocfs_counters *cntrs = p->private;
384 return (*pos >= cntrs->num) ? NULL : (void*) &(cntrs->cntr[*pos]);
387 /* seq file export of one lprocfs counter */
388 static int lprocfs_counters_seq_show(struct seq_file *p, void *v)
390 struct lprocfs_counters *cntrs = p->private;
391 struct lprocfs_counter *cntr = v;
393 struct lprocfs_counter c;
396 if (cntr == &(cntrs->cntr[0])) {
398 do_gettimeofday(&now);
399 rc = seq_printf(p, "%-25s %lu.%lu secs.usecs\n",
400 "snapshot_time", now.tv_sec, now.tv_usec);
405 /* Take a snapshot of the counter under lock */
406 lock = (cntr->config & LPROCFS_CNTR_EXTERNALLOCK) ?
407 cntr->l.external : &cntr->l.internal;
410 c.count = cntr->count;
414 c.sumsquare = cntr->sumsquare;
418 rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->name, c.count,
423 if ((cntr->config & LPROCFS_CNTR_AVGMINMAX) && (c.count > 0)) {
424 rc = seq_printf(p, " "LPU64" "LPU64" "LPU64, c.min,c.max,c.sum);
427 if (cntr->config & LPROCFS_CNTR_STDDEV)
428 rc = seq_printf(p, " "LPU64, c.sumsquare);
432 rc = seq_printf(p, "\n");
434 return (rc < 0) ? rc : 0;
437 struct seq_operations lprocfs_counters_seq_sops = {
438 .start = lprocfs_counters_seq_start,
439 .stop = lprocfs_counters_seq_stop,
440 .next = lprocfs_counters_seq_next,
441 .show = lprocfs_counters_seq_show,
444 static int lprocfs_counters_seq_open(struct inode *inode, struct file *file)
446 struct proc_dir_entry *dp = inode->u.generic_ip;
447 struct seq_file *seq;
450 rc = seq_open(file, &lprocfs_counters_seq_sops);
453 seq = file->private_data;
454 seq->private = dp->data;
458 struct file_operations lprocfs_counters_seq_fops = {
459 .open = lprocfs_counters_seq_open,
462 .release = seq_release,
465 int lprocfs_register_counters(struct proc_dir_entry *root, const char* name,
466 struct lprocfs_counters *cntrs)
468 struct proc_dir_entry *entry;
469 LASSERT(root != NULL);
471 entry = create_proc_entry(name, 0444, root);
474 entry->proc_fops = &lprocfs_counters_seq_fops;
475 entry->data = (void*) cntrs;
476 entry->write_proc = lprocfs_counter_write;
480 #define LPROCFS_OBD_OP_INIT(base, cntrs, op) \
482 unsigned int coffset = base + OBD_COUNTER_OFFSET(op); \
483 LASSERT(coffset < cntrs->num); \
484 LPROCFS_COUNTER_INIT(&cntrs->cntr[coffset], 0, NULL, #op, "reqs"); \
488 int lprocfs_alloc_obd_counters(struct obd_device *obddev,
489 unsigned int num_private_counters)
491 struct lprocfs_counters* obdops_cntrs;
492 unsigned int num_counters;
495 LASSERT(obddev->counters == NULL);
496 LASSERT(obddev->obd_proc_entry != NULL);
497 LASSERT(obddev->cntr_base == 0);
499 num_counters = 1 + OBD_COUNTER_OFFSET(san_preprw)+num_private_counters;
500 obdops_cntrs = lprocfs_alloc_counters(num_counters);
504 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, iocontrol);
505 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, get_info);
506 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, set_info);
507 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, attach);
508 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, detach);
509 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, setup);
510 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, cleanup);
511 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, connect);
512 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, disconnect);
513 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, statfs);
514 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, syncfs);
515 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, packmd);
516 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, unpackmd);
517 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, preallocate);
518 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, create);
519 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, destroy);
520 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, setattr);
521 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, getattr);
522 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, getattr_async);
523 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, open);
524 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, close);
525 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, brw);
526 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, brw_async);
527 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, punch);
528 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, sync);
529 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, migrate);
530 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, copy);
531 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, iterate);
532 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, preprw);
533 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, commitrw);
534 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, enqueue);
535 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, match);
536 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, cancel);
537 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, cancel_unused);
538 LPROCFS_OBD_OP_INIT(num_private_counters, obdops_cntrs, san_preprw);
540 for (i = num_private_counters; i < num_counters; i++) {
541 /* If this assertion failed, it is likely that an obd
542 * operation was added to struct obd_ops in
543 * <linux/obd.h>, and that the corresponding line item
544 * LPROCFS_OBD_OP_INIT(.., .., opname)
545 * is missing from the list above. */
546 LASSERT(obdops_cntrs->cntr[i].name != NULL);
548 rc = lprocfs_register_counters(obddev->obd_proc_entry, "obd_stats",
551 lprocfs_free_counters(obdops_cntrs);
553 obddev->counters = obdops_cntrs;
554 obddev->cntr_base = num_private_counters;
559 void lprocfs_free_obd_counters(struct obd_device *obddev)
561 struct lprocfs_counters* obdops_cntrs = obddev->counters;
562 if (obdops_cntrs != NULL) {
563 obddev->counters = NULL;
564 lprocfs_free_counters(obdops_cntrs);
570 EXPORT_SYMBOL(lprocfs_register);
571 EXPORT_SYMBOL(lprocfs_remove);
572 EXPORT_SYMBOL(lprocfs_add_vars);
573 EXPORT_SYMBOL(lprocfs_obd_attach);
574 EXPORT_SYMBOL(lprocfs_obd_detach);
575 EXPORT_SYMBOL(lprocfs_alloc_counters);
576 EXPORT_SYMBOL(lprocfs_free_counters);
577 EXPORT_SYMBOL(lprocfs_register_counters);
578 EXPORT_SYMBOL(lprocfs_alloc_obd_counters);
579 EXPORT_SYMBOL(lprocfs_free_obd_counters);
581 EXPORT_SYMBOL(lprocfs_rd_u64);
582 EXPORT_SYMBOL(lprocfs_rd_uuid);
583 EXPORT_SYMBOL(lprocfs_rd_name);
584 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
585 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
586 EXPORT_SYMBOL(lprocfs_rd_numrefs);
588 EXPORT_SYMBOL(lprocfs_rd_blksize);
589 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
590 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
591 EXPORT_SYMBOL(lprocfs_rd_filestotal);
592 EXPORT_SYMBOL(lprocfs_rd_filesfree);
593 EXPORT_SYMBOL(lprocfs_rd_filegroups);