Whamcloud - gitweb
10e0cd39153eaeb310fc80bd280c177c05e545d1
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status_server.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2013, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/obdclass/lprocfs_status_server.c
33  */
34
35 #define DEBUG_SUBSYSTEM S_CLASS
36
37
38 #include <obd_class.h>
39 #include <lprocfs_status.h>
40 #include <lustre/lustre_idl.h>
41
42 #if defined(LPROCFS)
43
44 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
45 {
46         struct obd_device *obd = PDE_DATA(f->f_dentry->d_inode);
47
48         atomic_inc(&obd->obd_evict_inprogress);
49         return 0;
50 }
51
52 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
53 {
54         struct obd_device *obd = PDE_DATA(f->f_dentry->d_inode);
55
56         atomic_dec(&obd->obd_evict_inprogress);
57         wake_up(&obd->obd_evict_inprogress_waitq);
58
59         return 0;
60 }
61
62 #define BUFLEN (UUID_MAX + 5)
63
64 ssize_t
65 lprocfs_evict_client_seq_write(struct file *file, const char *buffer,
66                                size_t count, loff_t *off)
67 {
68         struct seq_file *m = file->private_data;
69         struct obd_device *obd = m->private;
70         char *tmpbuf, *kbuf;
71
72         OBD_ALLOC(kbuf, BUFLEN);
73         if (kbuf == NULL)
74                 return -ENOMEM;
75
76         /*
77          * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
78          * bytes into kbuf, to ensure that the string is NUL-terminated.
79          * UUID_MAX should include a trailing NUL already.
80          */
81         if (copy_from_user(kbuf, buffer,
82                            min_t(unsigned long, BUFLEN - 1, count))) {
83                 count = -EFAULT;
84                 goto out;
85         }
86         tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
87         class_incref(obd, __func__, current);
88
89         if (strncmp(tmpbuf, "nid:", 4) == 0)
90                 obd_export_evict_by_nid(obd, tmpbuf + 4);
91         else if (strncmp(tmpbuf, "uuid:", 5) == 0)
92                 obd_export_evict_by_uuid(obd, tmpbuf + 5);
93         else
94                 obd_export_evict_by_uuid(obd, tmpbuf);
95
96         class_decref(obd, __func__, current);
97
98 out:
99         OBD_FREE(kbuf, BUFLEN);
100         return count;
101 }
102 EXPORT_SYMBOL(lprocfs_evict_client_seq_write);
103
104 #ifndef HAVE_ONLY_PROCFS_SEQ
105 int lprocfs_wr_evict_client(struct file *file, const char __user *buffer,
106                             unsigned long count, void *data)
107 {
108         struct obd_device *obd = data;
109         char              *kbuf;
110         char              *tmpbuf;
111
112         OBD_ALLOC(kbuf, BUFLEN);
113         if (kbuf == NULL)
114                 return -ENOMEM;
115
116         /*
117          * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
118          * bytes into kbuf, to ensure that the string is NUL-terminated.
119          * UUID_MAX should include a trailing NUL already.
120          */
121         if (copy_from_user(kbuf, buffer,
122                            min_t(unsigned long, BUFLEN - 1, count))) {
123                 count = -EFAULT;
124                 goto out;
125         }
126         tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
127         class_incref(obd, __func__, current);
128
129         if (strncmp(tmpbuf, "nid:", 4) == 0)
130                 obd_export_evict_by_nid(obd, tmpbuf + 4);
131         else if (strncmp(tmpbuf, "uuid:", 5) == 0)
132                 obd_export_evict_by_uuid(obd, tmpbuf + 5);
133         else
134                 obd_export_evict_by_uuid(obd, tmpbuf);
135
136         class_decref(obd, __func__, current);
137 out:
138         OBD_FREE(kbuf, BUFLEN);
139         return count;
140 }
141 EXPORT_SYMBOL(lprocfs_wr_evict_client);
142
143 const struct file_operations lprocfs_evict_client_fops = {
144         .owner = THIS_MODULE,
145         .read = lprocfs_fops_read,
146         .write = lprocfs_fops_write,
147         .open = lprocfs_evict_client_open,
148         .release = lprocfs_evict_client_release,
149 };
150 EXPORT_SYMBOL(lprocfs_evict_client_fops);
151
152 /* Function that emulates snprintf but also has the side effect of advancing
153    the page pointer for the next write into the buffer, incrementing the total
154    length written to the buffer, and decrementing the size left in the
155    buffer. */
156 static int lprocfs_obd_snprintf(char **page, int end, int *len,
157                                 const char *format, ...)
158 {
159         va_list list;
160         int n;
161
162         if (*len >= end)
163                 return 0;
164
165         va_start(list, format);
166         n = vsnprintf(*page, end - *len, format, list);
167         va_end(list);
168
169         *page += n; *len += n;
170         return n;
171 }
172 #endif  /* HAVE_ONLY_PROCFS_SEQ */
173
174 #undef BUFLEN
175
176 int lprocfs_num_exports_seq_show(struct seq_file *m, void *data)
177 {
178         struct obd_device *obd = data;
179
180         LASSERT(obd != NULL);
181         return seq_printf(m, "%u\n", obd->obd_num_exports);
182 }
183 EXPORT_SYMBOL(lprocfs_num_exports_seq_show);
184
185 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
186 {
187         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
188                client_stat->nid_proc, client_stat->nid_stats);
189
190         LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
191                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
192                  atomic_read(&client_stat->nid_exp_ref_count));
193
194         if (client_stat->nid_proc)
195                 lprocfs_remove(&client_stat->nid_proc);
196
197         if (client_stat->nid_stats)
198                 lprocfs_free_stats(&client_stat->nid_stats);
199
200         if (client_stat->nid_ldlm_stats)
201                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
202
203         OBD_FREE_PTR(client_stat);
204         return;
205 }
206
207 void lprocfs_free_per_client_stats(struct obd_device *obd)
208 {
209         cfs_hash_t *hash = obd->obd_nid_stats_hash;
210         struct nid_stat *stat;
211         ENTRY;
212
213         /* we need extra list - because hash_exit called to early */
214         /* not need locking because all clients is died */
215         while (!list_empty(&obd->obd_nid_stats)) {
216                 stat = list_entry(obd->obd_nid_stats.next,
217                                   struct nid_stat, nid_list);
218                 list_del_init(&stat->nid_list);
219                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
220                 lprocfs_free_client_stats(stat);
221         }
222         EXIT;
223 }
224 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
225
226 int lprocfs_exp_nid_seq_show(struct seq_file *m, void *data)
227 {
228         struct obd_export *exp = m->private;
229         LASSERT(exp != NULL);
230         return seq_printf(m, "%s\n", obd_export_nid2str(exp));
231 }
232
233 int lprocfs_exp_print_uuid_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd,
234                                 struct hlist_node *hnode, void *cb_data)
235
236 {
237         struct obd_export *exp = cfs_hash_object(hs, hnode);
238         struct seq_file *m = cb_data;
239
240         if (exp->exp_nid_stats)
241                 seq_printf(m, "%s\n", obd_uuid2str(&exp->exp_client_uuid));
242         return 0;
243 }
244
245 int lprocfs_exp_uuid_seq_show(struct seq_file *m, void *data)
246 {
247         struct nid_stat *stats = m->private;
248         struct obd_device *obd = stats->nid_obd;
249
250         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
251                                 lprocfs_exp_print_uuid_seq, m);
252         return 0;
253 }
254 LPROC_SEQ_FOPS_RO(lprocfs_exp_uuid);
255
256 int lprocfs_exp_print_hash_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd,
257                                 struct hlist_node *hnode, void *cb_data)
258
259 {
260         struct seq_file *m = cb_data;
261         struct obd_export *exp = cfs_hash_object(hs, hnode);
262
263         if (exp->exp_lock_hash != NULL) {
264                 cfs_hash_debug_header_seq(m);
265                 cfs_hash_debug_str_seq(hs, m);
266         }
267         return 0;
268 }
269
270 int lprocfs_exp_hash_seq_show(struct seq_file *m, void *data)
271 {
272         struct nid_stat *stats = m->private;
273         struct obd_device *obd = stats->nid_obd;
274
275         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
276                                 lprocfs_exp_print_hash_seq, m);
277         return 0;
278 }
279 LPROC_SEQ_FOPS_RO(lprocfs_exp_hash);
280
281 int lprocfs_nid_stats_clear_seq_show(struct seq_file *m, void *data)
282 {
283         return seq_printf(m, "%s\n", "Write into this file to clear all nid "
284                           "stats and stale nid entries");
285 }
286 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_show);
287
288 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
289 {
290         struct nid_stat *stat = obj;
291         ENTRY;
292
293         CDEBUG(D_INFO, "refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
294         if (atomic_read(&stat->nid_exp_ref_count) == 1) {
295                 /* object has only hash references. */
296                 spin_lock(&stat->nid_obd->obd_nid_lock);
297                 list_move(&stat->nid_list, data);
298                 spin_unlock(&stat->nid_obd->obd_nid_lock);
299                 RETURN(1);
300         }
301         /* we has reference to object - only clear data*/
302         if (stat->nid_stats)
303                 lprocfs_clear_stats(stat->nid_stats);
304
305         RETURN(0);
306 }
307
308 ssize_t
309 lprocfs_nid_stats_clear_seq_write(struct file *file, const char *buffer,
310                                         size_t count, loff_t *off)
311 {
312         struct seq_file *m = file->private_data;
313         struct obd_device *obd = m->private;
314         struct nid_stat *client_stat;
315         struct list_head free_list;
316
317         INIT_LIST_HEAD(&free_list);
318         cfs_hash_cond_del(obd->obd_nid_stats_hash,
319                           lprocfs_nid_stats_clear_write_cb, &free_list);
320
321         while (!list_empty(&free_list)) {
322                 client_stat = list_entry(free_list.next, struct nid_stat,
323                                          nid_list);
324                 list_del_init(&client_stat->nid_list);
325                 lprocfs_free_client_stats(client_stat);
326         }
327         return count;
328 }
329 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_write);
330
331 #ifndef HAVE_ONLY_PROCFS_SEQ
332 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
333                            int *eof,  void *data)
334 {
335         struct obd_device *obd = data;
336
337         LASSERT(obd != NULL);
338         *eof = 1;
339         return snprintf(page, count, "%u\n", obd->obd_num_exports);
340 }
341 EXPORT_SYMBOL(lprocfs_rd_num_exports);
342
343 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
344                          int *eof,  void *data)
345 {
346         struct obd_export *exp = data;
347         LASSERT(exp != NULL);
348         *eof = 1;
349         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
350 }
351
352 struct exp_uuid_cb_data {
353         char                   *page;
354         int                     count;
355         int                    *eof;
356         int                    *len;
357 };
358
359 static void
360 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
361                             int count, int *eof, int *len)
362 {
363         cb_data->page = page;
364         cb_data->count = count;
365         cb_data->eof = eof;
366         cb_data->len = len;
367 }
368
369 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
370                            struct hlist_node *hnode, void *cb_data)
371
372 {
373         struct obd_export *exp = cfs_hash_object(hs, hnode);
374         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
375
376         if (exp->exp_nid_stats)
377                 *data->len += snprintf((data->page + *data->len),
378                                        data->count, "%s\n",
379                                        obd_uuid2str(&exp->exp_client_uuid));
380         return 0;
381 }
382
383 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
384                         int *eof,  void *data)
385 {
386         struct nid_stat *stats = (struct nid_stat *)data;
387         struct exp_uuid_cb_data cb_data;
388         struct obd_device *obd = stats->nid_obd;
389         int len = 0;
390
391         *eof = 1;
392         page[0] = '\0';
393         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
394         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
395                               lprocfs_exp_print_uuid, &cb_data);
396         return *cb_data.len;
397 }
398
399 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
400                            struct hlist_node *hnode, void *cb_data)
401
402 {
403         struct exp_uuid_cb_data *data = cb_data;
404         struct obd_export       *exp = cfs_hash_object(hs, hnode);
405
406         if (exp->exp_lock_hash != NULL) {
407                 if (!*data->len) {
408                         *data->len += cfs_hash_debug_header(data->page,
409                                                             data->count);
410                 }
411                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
412                                                  data->count);
413         }
414         return 0;
415 }
416
417 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
418                         int *eof,  void *data)
419 {
420         struct nid_stat *stats = (struct nid_stat *)data;
421         struct exp_uuid_cb_data cb_data;
422         struct obd_device *obd = stats->nid_obd;
423         int len = 0;
424
425         *eof = 1;
426         page[0] = '\0';
427         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
428
429         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
430                               lprocfs_exp_print_hash, &cb_data);
431         return *cb_data.len;
432 }
433
434 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
435                                         int count, int *eof,  void *data)
436 {
437         *eof = 1;
438         return snprintf(page, count, "%s\n",
439                         "Write into this file to clear all nid stats and "
440                         "stale nid entries");
441 }
442 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
443
444 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
445                                   unsigned long count, void *data)
446 {
447         struct obd_device *obd = (struct obd_device *)data;
448         struct nid_stat *client_stat;
449         struct list_head free_list;
450
451         INIT_LIST_HEAD(&free_list);
452         cfs_hash_cond_del(obd->obd_nid_stats_hash,
453                           lprocfs_nid_stats_clear_write_cb, &free_list);
454
455         while (!list_empty(&free_list)) {
456                 client_stat = list_entry(free_list.next, struct nid_stat,
457                                          nid_list);
458                 list_del_init(&client_stat->nid_list);
459                 lprocfs_free_client_stats(client_stat);
460         }
461
462         return count;
463 }
464 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
465 #endif
466
467 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
468 {
469         struct nid_stat *new_stat, *old_stat;
470         struct obd_device *obd = NULL;
471         struct proc_dir_entry *entry;
472         char *buffer = NULL;
473         int rc = 0;
474         ENTRY;
475
476         *newnid = 0;
477
478         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
479             !exp->exp_obd->obd_nid_stats_hash)
480                 RETURN(-EINVAL);
481
482         /* not test against zero because eric say:
483          * You may only test nid against another nid, or LNET_NID_ANY.
484          * Anything else is nonsense.*/
485         if (!nid || *nid == LNET_NID_ANY)
486                 RETURN(0);
487
488         spin_lock(&exp->exp_lock);
489         if (exp->exp_nid_stats != NULL) {
490                 spin_unlock(&exp->exp_lock);
491                 RETURN(-EALREADY);
492         }
493         spin_unlock(&exp->exp_lock);
494
495         obd = exp->exp_obd;
496
497         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
498
499         OBD_ALLOC_PTR(new_stat);
500         if (new_stat == NULL)
501                 RETURN(-ENOMEM);
502
503         new_stat->nid           = *nid;
504         new_stat->nid_obd       = exp->exp_obd;
505         /* we need set default refcount to 1 to balance obd_disconnect */
506         atomic_set(&new_stat->nid_exp_ref_count, 1);
507
508         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
509                                            nid, &new_stat->nid_hash);
510         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
511                old_stat, libcfs_nid2str(*nid),
512                atomic_read(&new_stat->nid_exp_ref_count));
513
514         /* Return -EALREADY here so that we know that the /proc
515          * entry already has been created */
516         if (old_stat != new_stat) {
517                 spin_lock(&exp->exp_lock);
518                 if (exp->exp_nid_stats) {
519                         LASSERT(exp->exp_nid_stats == old_stat);
520                         nidstat_putref(exp->exp_nid_stats);
521                 }
522                 exp->exp_nid_stats = old_stat;
523                 spin_unlock(&exp->exp_lock);
524                 GOTO(destroy_new, rc = -EALREADY);
525         }
526         /* not found - create */
527         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
528         if (buffer == NULL)
529                 GOTO(destroy_new, rc = -ENOMEM);
530
531         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
532 #ifndef HAVE_ONLY_PROCFS_SEQ
533         new_stat->nid_proc = lprocfs_register(buffer,
534                                               obd->obd_proc_exports_entry,
535                                               NULL, NULL);
536 #else
537         new_stat->nid_proc = lprocfs_seq_register(buffer,
538                                                   obd->obd_proc_exports_entry,
539                                                   NULL, NULL);
540 #endif
541         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
542
543         if (IS_ERR(new_stat->nid_proc)) {
544                 rc = PTR_ERR(new_stat->nid_proc);
545                 new_stat->nid_proc = NULL;
546                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
547                        obd->obd_name, libcfs_nid2str(*nid), rc);
548                 GOTO(destroy_new_ns, rc);
549         }
550
551 #ifndef HAVE_ONLY_PROCFS_SEQ
552         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
553                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
554 #else
555         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid", new_stat,
556                                    &lprocfs_exp_uuid_fops);
557 #endif
558         if (IS_ERR(entry)) {
559                 CWARN("Error adding the NID stats file\n");
560                 rc = PTR_ERR(entry);
561                 GOTO(destroy_new_ns, rc);
562         }
563
564 #ifndef HAVE_ONLY_PROCFS_SEQ
565         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
566                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
567 #else
568         entry = lprocfs_add_simple(new_stat->nid_proc, "hash", new_stat,
569                                    &lprocfs_exp_hash_fops);
570 #endif
571         if (IS_ERR(entry)) {
572                 CWARN("Error adding the hash file\n");
573                 rc = PTR_ERR(entry);
574                 GOTO(destroy_new_ns, rc);
575         }
576
577         spin_lock(&exp->exp_lock);
578         exp->exp_nid_stats = new_stat;
579         spin_unlock(&exp->exp_lock);
580         *newnid = 1;
581         /* protect competitive add to list, not need locking on destroy */
582         spin_lock(&obd->obd_nid_lock);
583         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
584         spin_unlock(&obd->obd_nid_lock);
585
586         RETURN(rc);
587
588 destroy_new_ns:
589         if (new_stat->nid_proc != NULL)
590                 lprocfs_remove(&new_stat->nid_proc);
591         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
592
593 destroy_new:
594         nidstat_putref(new_stat);
595         OBD_FREE_PTR(new_stat);
596         RETURN(rc);
597 }
598 EXPORT_SYMBOL(lprocfs_exp_setup);
599
600 int lprocfs_exp_cleanup(struct obd_export *exp)
601 {
602         struct nid_stat *stat = exp->exp_nid_stats;
603
604         if (!stat || !exp->exp_obd)
605                 RETURN(0);
606
607         nidstat_putref(exp->exp_nid_stats);
608         exp->exp_nid_stats = NULL;
609
610         return 0;
611 }
612 EXPORT_SYMBOL(lprocfs_exp_cleanup);
613
614 #define LPROCFS_OBD_OP_INIT(base, stats, op)                    \
615 do {                                                            \
616         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);   \
617         LASSERT(coffset < stats->ls_num);                       \
618         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");   \
619 } while (0)
620
621 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
622 {
623         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
624         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
625         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
626         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
627         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
628         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
629         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
630         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
631         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
632         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
633         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
634         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
635         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
636         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
637         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
638         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
639         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
640         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
641         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
642         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
643         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
644         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
645         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
646         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
647         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
648         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
649         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
650         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
651         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
652         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
653         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
654         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
655         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
656         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
657         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
658         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
659         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
660         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
661         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
662         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
663         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
664         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
670
671         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
672 }
673 EXPORT_SYMBOL(lprocfs_init_ops_stats);
674
675 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
676 {
677         struct lprocfs_stats *stats;
678         unsigned int num_stats;
679         int rc, i;
680
681         LASSERT(obd->obd_stats == NULL);
682         LASSERT(obd->obd_proc_entry != NULL);
683         LASSERT(obd->obd_cntr_base == 0);
684
685         num_stats = NUM_OBD_STATS + num_private_stats;
686         stats = lprocfs_alloc_stats(num_stats, 0);
687         if (stats == NULL)
688                 return -ENOMEM;
689
690         lprocfs_init_ops_stats(num_private_stats, stats);
691
692         for (i = num_private_stats; i < num_stats; i++) {
693                 /* If this LBUGs, it is likely that an obd
694                  * operation was added to struct obd_ops in
695                  * <obd.h>, and that the corresponding line item
696                  * LPROCFS_OBD_OP_INIT(.., .., opname)
697                  * is missing from the list above. */
698                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
699                          "Missing obd_stat initializer obd_op "
700                          "operation at offset %d.\n", i - num_private_stats);
701         }
702         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
703         if (rc < 0) {
704                 lprocfs_free_stats(&stats);
705         } else {
706                 obd->obd_stats  = stats;
707                 obd->obd_cntr_base = num_private_stats;
708         }
709         return rc;
710 }
711 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
712
713 void lprocfs_free_obd_stats(struct obd_device *obd)
714 {
715         if (obd->obd_stats)
716                 lprocfs_free_stats(&obd->obd_stats);
717 }
718 EXPORT_SYMBOL(lprocfs_free_obd_stats);
719
720 int lprocfs_hash_seq_show(struct seq_file *m, void *data)
721 {
722         struct obd_device *obd = m->private;
723         int c = 0;
724
725         if (obd == NULL)
726                 return 0;
727
728         c += cfs_hash_debug_header_seq(m);
729         c += cfs_hash_debug_str_seq(obd->obd_uuid_hash, m);
730         c += cfs_hash_debug_str_seq(obd->obd_nid_hash, m);
731         c += cfs_hash_debug_str_seq(obd->obd_nid_stats_hash, m);
732         return c;
733 }
734 EXPORT_SYMBOL(lprocfs_hash_seq_show);
735
736 int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
737 {
738         struct obd_device *obd = m->private;
739
740         LASSERT(obd != NULL);
741
742         seq_printf(m, "status: ");
743         if (obd->obd_max_recoverable_clients == 0) {
744                 seq_printf(m, "INACTIVE\n");
745                 goto out;
746         }
747
748         /* sampled unlocked, but really... */
749         if (obd->obd_recovering == 0) {
750                 seq_printf(m, "COMPLETE\n");
751                 seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
752                 seq_printf(m, "recovery_duration: %lu\n",
753                            obd->obd_recovery_end - obd->obd_recovery_start);
754                 /* Number of clients that have completed recovery */
755                 seq_printf(m, "completed_clients: %d/%d\n",
756                            obd->obd_max_recoverable_clients -
757                            obd->obd_stale_clients,
758                            obd->obd_max_recoverable_clients);
759                 seq_printf(m, "replayed_requests: %d\n",
760                            obd->obd_replayed_requests);
761                 seq_printf(m, "last_transno: "LPD64"\n",
762                            obd->obd_next_recovery_transno - 1);
763                 seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
764                            "ENABLED" : "DISABLED");
765                 seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
766                            "DISABLED" : "ENABLED");
767                 goto out;
768         }
769
770         seq_printf(m, "RECOVERING\n");
771         seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
772         seq_printf(m, "time_remaining: %lu\n",
773                    cfs_time_current_sec() >=
774                    obd->obd_recovery_start +
775                    obd->obd_recovery_timeout ? 0 :
776                    obd->obd_recovery_start +
777                    obd->obd_recovery_timeout -
778                    cfs_time_current_sec());
779         seq_printf(m, "connected_clients: %d/%d\n",
780                    atomic_read(&obd->obd_connected_clients),
781                    obd->obd_max_recoverable_clients);
782         /* Number of clients that have completed recovery */
783         seq_printf(m, "req_replay_clients: %d\n",
784                    atomic_read(&obd->obd_req_replay_clients));
785         seq_printf(m, "lock_repay_clients: %d\n",
786                    atomic_read(&obd->obd_lock_replay_clients));
787         seq_printf(m, "completed_clients: %d\n",
788                    atomic_read(&obd->obd_connected_clients) -
789                    atomic_read(&obd->obd_lock_replay_clients));
790         seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
791         seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
792         seq_printf(m, "queued_requests: %d\n",
793                    obd->obd_requests_queued_for_recovery);
794         seq_printf(m, "next_transno: "LPD64"\n",
795                    obd->obd_next_recovery_transno);
796 out:
797         return 0;
798 }
799 EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
800
801 int lprocfs_ir_factor_seq_show(struct seq_file *m, void *data)
802 {
803         struct obd_device *obd = m->private;
804
805         LASSERT(obd != NULL);
806         return seq_printf(m, "%d\n", obd->obd_recovery_ir_factor);
807 }
808 EXPORT_SYMBOL(lprocfs_ir_factor_seq_show);
809
810 ssize_t
811 lprocfs_ir_factor_seq_write(struct file *file, const char *buffer,
812                             size_t count, loff_t *off)
813 {
814         struct seq_file *m = file->private_data;
815         struct obd_device *obd = m->private;
816         int val, rc;
817
818         LASSERT(obd != NULL);
819         rc = lprocfs_write_helper(buffer, count, &val);
820         if (rc)
821                 return rc;
822
823         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
824                 return -EINVAL;
825
826         obd->obd_recovery_ir_factor = val;
827         return count;
828 }
829 EXPORT_SYMBOL(lprocfs_ir_factor_seq_write);
830
831 int lprocfs_recovery_time_soft_seq_show(struct seq_file *m, void *data)
832 {
833         struct obd_device *obd = m->private;
834
835         LASSERT(obd != NULL);
836         return seq_printf(m, "%d\n", obd->obd_recovery_timeout);
837 }
838 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_show);
839
840 ssize_t
841 lprocfs_recovery_time_soft_seq_write(struct file *file, const char *buffer,
842                                         size_t count, loff_t *off)
843 {
844         struct seq_file *m = file->private_data;
845         struct obd_device *obd = m->private;
846         int val, rc;
847
848         LASSERT(obd != NULL);
849         rc = lprocfs_write_helper(buffer, count, &val);
850         if (rc)
851                 return rc;
852
853         obd->obd_recovery_timeout = val;
854         return count;
855 }
856 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_write);
857
858 int lprocfs_recovery_time_hard_seq_show(struct seq_file *m, void *data)
859 {
860         struct obd_device *obd = m->private;
861
862         LASSERT(obd != NULL);
863         return seq_printf(m, "%u\n", obd->obd_recovery_time_hard);
864 }
865 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_show);
866
867 ssize_t
868 lprocfs_recovery_time_hard_seq_write(struct file *file, const char *buffer,
869                                      size_t count, loff_t *off)
870 {
871         struct seq_file *m = file->private_data;
872         struct obd_device *obd = m->private;
873         int val, rc;
874
875         LASSERT(obd != NULL);
876         rc = lprocfs_write_helper(buffer, count, &val);
877         if (rc)
878                 return rc;
879
880         obd->obd_recovery_time_hard = val;
881         return count;
882 }
883 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_write);
884
885 int lprocfs_target_instance_seq_show(struct seq_file *m, void *data)
886 {
887         struct obd_device *obd = m->private;
888         struct obd_device_target *target = &obd->u.obt;
889
890         LASSERT(obd != NULL);
891         LASSERT(target->obt_magic == OBT_MAGIC);
892         return seq_printf(m, "%u\n", obd->u.obt.obt_instance);
893 }
894 EXPORT_SYMBOL(lprocfs_target_instance_seq_show);
895
896 #ifndef HAVE_ONLY_PROCFS_SEQ
897 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
898                         int count, int *eof, void *data)
899 {
900         struct obd_device *obd = data;
901         int c = 0;
902
903         if (obd == NULL)
904                 return 0;
905
906         c += cfs_hash_debug_header(page, count);
907         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
908         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
909         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
910
911         return c;
912 }
913 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
914
915 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
916                                    int count, int *eof, void *data)
917 {
918         struct obd_device *obd = data;
919         int len = 0, size;
920
921         LASSERT(obd != NULL);
922         LASSERT(count >= 0);
923
924         /* Set start of user data returned to
925            page + off since the user may have
926            requested to read much smaller than
927            what we need to read */
928         *start = page + off;
929
930         /*
931          * We know we are allocated a page here.
932          * Also we know that this function will
933          * not need to write more than a page
934          * so we can truncate at PAGE_CACHE_SIZE.
935          */
936         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
937
938         /* Initialize the page */
939         memset(page, 0, size);
940
941         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
942                 goto out;
943         if (obd->obd_max_recoverable_clients == 0) {
944                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
945                         goto out;
946
947                 goto fclose;
948         }
949
950         /* sampled unlocked, but really... */
951         if (obd->obd_recovering == 0) {
952                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
953                         goto out;
954                 if (lprocfs_obd_snprintf(&page, size, &len,
955                                          "recovery_start: %lu\n",
956                                          obd->obd_recovery_start) <= 0)
957                         goto out;
958                 if (lprocfs_obd_snprintf(&page, size, &len,
959                                          "recovery_duration: %lu\n",
960                                          obd->obd_recovery_end -
961                                          obd->obd_recovery_start) <= 0)
962                         goto out;
963                 /* Number of clients that have completed recovery */
964                 if (lprocfs_obd_snprintf(&page, size, &len,
965                                          "completed_clients: %d/%d\n",
966                                          obd->obd_max_recoverable_clients -
967                                          obd->obd_stale_clients,
968                                          obd->obd_max_recoverable_clients) <= 0)
969                         goto out;
970                 if (lprocfs_obd_snprintf(&page, size, &len,
971                                          "replayed_requests: %d\n",
972                                          obd->obd_replayed_requests) <= 0)
973                         goto out;
974                 if (lprocfs_obd_snprintf(&page, size, &len,
975                                          "last_transno: "LPD64"\n",
976                                          obd->obd_next_recovery_transno - 1) <= 0)
977                         goto out;
978                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
979                                          obd->obd_version_recov ?
980                                          "ENABLED" : "DISABLED") <= 0)
981                         goto out;
982                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
983                                          obd->obd_no_ir ?
984                                          "DISABLED" : "ENABLED") <= 0)
985                         goto out;
986                 goto fclose;
987         }
988
989         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
990                 goto out;
991         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
992                                  obd->obd_recovery_start) <= 0)
993                 goto out;
994         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
995                                  cfs_time_current_sec() >=
996                                  obd->obd_recovery_start +
997                                  obd->obd_recovery_timeout ? 0 :
998                                  obd->obd_recovery_start +
999                                  obd->obd_recovery_timeout -
1000                                  cfs_time_current_sec()) <= 0)
1001                 goto out;
1002         if (lprocfs_obd_snprintf(&page, size, &len,
1003                                  "connected_clients: %d/%d\n",
1004                                  atomic_read(&obd->obd_connected_clients),
1005                                  obd->obd_max_recoverable_clients) <= 0)
1006                 goto out;
1007         /* Number of clients that have completed recovery */
1008         if (lprocfs_obd_snprintf(&page, size, &len, "req_replay_clients: %d\n",
1009                                  atomic_read(&obd->obd_req_replay_clients))
1010                 <= 0)
1011                 goto out;
1012         if (lprocfs_obd_snprintf(&page, size, &len, "lock_repay_clients: %d\n",
1013                                  atomic_read(&obd->obd_lock_replay_clients))
1014                 <= 0)
1015                 goto out;
1016         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d\n",
1017                                  atomic_read(&obd->obd_connected_clients) -
1018                                  atomic_read(&obd->obd_lock_replay_clients))
1019                 <= 0)
1020                 goto out;
1021         if (lprocfs_obd_snprintf(&page, size, &len, "evicted_clients: %d\n",
1022                                  obd->obd_stale_clients) <= 0)
1023                 goto out;
1024         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n",
1025                                  obd->obd_replayed_requests) <= 0)
1026                 goto out;
1027         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1028                                  obd->obd_requests_queued_for_recovery) <= 0)
1029                 goto out;
1030
1031         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1032                                  obd->obd_next_recovery_transno) <= 0)
1033                 goto out;
1034
1035 fclose:
1036         *eof = 1;
1037 out:
1038         return min(count, len - (int)off);
1039 }
1040 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1041
1042 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
1043                              int count, int *eof, void *data)
1044 {
1045         struct obd_device *obd = (struct obd_device *)data;
1046         LASSERT(obd != NULL);
1047
1048         return snprintf(page, count, "%d\n",
1049                         obd->obd_recovery_ir_factor);
1050 }
1051 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
1052
1053 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
1054                              unsigned long count, void *data)
1055 {
1056         struct obd_device *obd = (struct obd_device *)data;
1057         int val, rc;
1058         LASSERT(obd != NULL);
1059
1060         rc = lprocfs_write_helper(buffer, count, &val);
1061         if (rc)
1062                 return rc;
1063
1064         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
1065                 return -EINVAL;
1066
1067         obd->obd_recovery_ir_factor = val;
1068         return count;
1069 }
1070 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
1071
1072 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
1073                                       int count, int *eof, void *data)
1074 {
1075         struct obd_device *obd = (struct obd_device *)data;
1076         LASSERT(obd != NULL);
1077
1078         return snprintf(page, count, "%d\n",
1079                         obd->obd_recovery_timeout);
1080 }
1081 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
1082
1083 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
1084                                       unsigned long count, void *data)
1085 {
1086         struct obd_device *obd = (struct obd_device *)data;
1087         int val, rc;
1088         LASSERT(obd != NULL);
1089
1090         rc = lprocfs_write_helper(buffer, count, &val);
1091         if (rc)
1092                 return rc;
1093
1094         obd->obd_recovery_timeout = val;
1095         return count;
1096 }
1097 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
1098
1099 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
1100                                       int count, int *eof, void *data)
1101 {
1102         struct obd_device *obd = data;
1103         LASSERT(obd != NULL);
1104
1105         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
1106 }
1107 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
1108
1109 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
1110                                       unsigned long count, void *data)
1111 {
1112         struct obd_device *obd = data;
1113         int val, rc;
1114         LASSERT(obd != NULL);
1115
1116         rc = lprocfs_write_helper(buffer, count, &val);
1117         if (rc)
1118                 return rc;
1119
1120         obd->obd_recovery_time_hard = val;
1121         return count;
1122 }
1123 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
1124
1125 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
1126                                int count, int *eof, void *data)
1127 {
1128         struct obd_device *obd = (struct obd_device *)data;
1129         struct obd_device_target *target = &obd->u.obt;
1130
1131         LASSERT(obd != NULL);
1132         LASSERT(target->obt_magic == OBT_MAGIC);
1133         *eof = 1;
1134         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
1135 }
1136 EXPORT_SYMBOL(lprocfs_target_rd_instance);
1137 #endif /* HAVE_ONLY_PROCFS_SEQ */
1138 #endif /* LPROCFS*/