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