Whamcloud - gitweb
LU-5331 obdclass: serialize lu_site purge
[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 list_head free_list = LIST_HEAD_INIT(free_list);
316         struct seq_file *m = file->private_data;
317         struct obd_device *obd = m->private;
318         struct nid_stat *client_stat;
319
320         cfs_hash_cond_del(obd->obd_nid_stats_hash,
321                           lprocfs_nid_stats_clear_write_cb, &free_list);
322
323         while (!list_empty(&free_list)) {
324                 client_stat = list_entry(free_list.next, struct nid_stat,
325                                          nid_list);
326                 list_del_init(&client_stat->nid_list);
327                 lprocfs_free_client_stats(client_stat);
328         }
329         return count;
330 }
331 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_write);
332
333 #ifndef HAVE_ONLY_PROCFS_SEQ
334 int lprocfs_rd_num_exports(char *page, char **start, off_t off, int count,
335                            int *eof,  void *data)
336 {
337         struct obd_device *obd = data;
338
339         LASSERT(obd != NULL);
340         *eof = 1;
341         return snprintf(page, count, "%u\n", obd->obd_num_exports);
342 }
343 EXPORT_SYMBOL(lprocfs_rd_num_exports);
344
345 int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
346                          int *eof,  void *data)
347 {
348         struct obd_export *exp = data;
349         LASSERT(exp != NULL);
350         *eof = 1;
351         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
352 }
353
354 struct exp_uuid_cb_data {
355         char                   *page;
356         int                     count;
357         int                    *eof;
358         int                    *len;
359 };
360
361 static void
362 lprocfs_exp_rd_cb_data_init(struct exp_uuid_cb_data *cb_data, char *page,
363                             int count, int *eof, int *len)
364 {
365         cb_data->page = page;
366         cb_data->count = count;
367         cb_data->eof = eof;
368         cb_data->len = len;
369 }
370
371 int lprocfs_exp_print_uuid(cfs_hash_t *hs, cfs_hash_bd_t *bd,
372                            struct hlist_node *hnode, void *cb_data)
373
374 {
375         struct obd_export *exp = cfs_hash_object(hs, hnode);
376         struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
377
378         if (exp->exp_nid_stats)
379                 *data->len += snprintf((data->page + *data->len),
380                                        data->count, "%s\n",
381                                        obd_uuid2str(&exp->exp_client_uuid));
382         return 0;
383 }
384
385 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
386                         int *eof,  void *data)
387 {
388         struct nid_stat *stats = (struct nid_stat *)data;
389         struct exp_uuid_cb_data cb_data;
390         struct obd_device *obd = stats->nid_obd;
391         int len = 0;
392
393         *eof = 1;
394         page[0] = '\0';
395         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
396         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
397                               lprocfs_exp_print_uuid, &cb_data);
398         return *cb_data.len;
399 }
400
401 int lprocfs_exp_print_hash(cfs_hash_t *hs, cfs_hash_bd_t *bd,
402                            struct hlist_node *hnode, void *cb_data)
403
404 {
405         struct exp_uuid_cb_data *data = cb_data;
406         struct obd_export       *exp = cfs_hash_object(hs, hnode);
407
408         if (exp->exp_lock_hash != NULL) {
409                 if (!*data->len) {
410                         *data->len += cfs_hash_debug_header(data->page,
411                                                             data->count);
412                 }
413                 *data->len += cfs_hash_debug_str(hs, data->page + *data->len,
414                                                  data->count);
415         }
416         return 0;
417 }
418
419 int lprocfs_exp_rd_hash(char *page, char **start, off_t off, int count,
420                         int *eof,  void *data)
421 {
422         struct nid_stat *stats = (struct nid_stat *)data;
423         struct exp_uuid_cb_data cb_data;
424         struct obd_device *obd = stats->nid_obd;
425         int len = 0;
426
427         *eof = 1;
428         page[0] = '\0';
429         lprocfs_exp_rd_cb_data_init(&cb_data, page, count, eof, &len);
430
431         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
432                               lprocfs_exp_print_hash, &cb_data);
433         return *cb_data.len;
434 }
435
436 int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
437                                         int count, int *eof,  void *data)
438 {
439         *eof = 1;
440         return snprintf(page, count, "%s\n",
441                         "Write into this file to clear all nid stats and "
442                         "stale nid entries");
443 }
444 EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
445
446 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
447                                   unsigned long count, void *data)
448 {
449         struct list_head free_list = LIST_HEAD_INIT(free_list);
450         struct obd_device *obd = (struct obd_device *)data;
451         struct nid_stat *client_stat;
452
453         cfs_hash_cond_del(obd->obd_nid_stats_hash,
454                           lprocfs_nid_stats_clear_write_cb, &free_list);
455
456         while (!list_empty(&free_list)) {
457                 client_stat = list_entry(free_list.next, struct nid_stat,
458                                              nid_list);
459                 list_del_init(&client_stat->nid_list);
460                 lprocfs_free_client_stats(client_stat);
461         }
462
463         return count;
464 }
465 EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
466 #endif
467
468 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
469 {
470         struct nid_stat *new_stat, *old_stat;
471         struct obd_device *obd = NULL;
472         struct proc_dir_entry *entry;
473         char *buffer = NULL;
474         int rc = 0;
475         ENTRY;
476
477         *newnid = 0;
478
479         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
480             !exp->exp_obd->obd_nid_stats_hash)
481                 RETURN(-EINVAL);
482
483         /* not test against zero because eric say:
484          * You may only test nid against another nid, or LNET_NID_ANY.
485          * Anything else is nonsense.*/
486         if (!nid || *nid == LNET_NID_ANY)
487                 RETURN(0);
488
489         spin_lock(&exp->exp_lock);
490         if (exp->exp_nid_stats != NULL) {
491                 spin_unlock(&exp->exp_lock);
492                 RETURN(-EALREADY);
493         }
494         spin_unlock(&exp->exp_lock);
495
496         obd = exp->exp_obd;
497
498         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
499
500         OBD_ALLOC_PTR(new_stat);
501         if (new_stat == NULL)
502                 RETURN(-ENOMEM);
503
504         new_stat->nid           = *nid;
505         new_stat->nid_obd       = exp->exp_obd;
506         /* we need set default refcount to 1 to balance obd_disconnect */
507         atomic_set(&new_stat->nid_exp_ref_count, 1);
508
509         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
510                                            nid, &new_stat->nid_hash);
511         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
512                old_stat, libcfs_nid2str(*nid),
513                atomic_read(&new_stat->nid_exp_ref_count));
514
515         /* Return -EALREADY here so that we know that the /proc
516          * entry already has been created */
517         if (old_stat != new_stat) {
518                 spin_lock(&exp->exp_lock);
519                 if (exp->exp_nid_stats) {
520                         LASSERT(exp->exp_nid_stats == old_stat);
521                         nidstat_putref(exp->exp_nid_stats);
522                 }
523                 exp->exp_nid_stats = old_stat;
524                 spin_unlock(&exp->exp_lock);
525                 GOTO(destroy_new, rc = -EALREADY);
526         }
527         /* not found - create */
528         OBD_ALLOC(buffer, LNET_NIDSTR_SIZE);
529         if (buffer == NULL)
530                 GOTO(destroy_new, rc = -ENOMEM);
531
532         memcpy(buffer, libcfs_nid2str(*nid), LNET_NIDSTR_SIZE);
533 #ifndef HAVE_ONLY_PROCFS_SEQ
534         new_stat->nid_proc = lprocfs_register(buffer,
535                                               obd->obd_proc_exports_entry,
536                                               NULL, NULL);
537 #else
538         new_stat->nid_proc = lprocfs_seq_register(buffer,
539                                                   obd->obd_proc_exports_entry,
540                                                   NULL, NULL);
541 #endif
542         OBD_FREE(buffer, LNET_NIDSTR_SIZE);
543
544         if (IS_ERR(new_stat->nid_proc)) {
545                 rc = PTR_ERR(new_stat->nid_proc);
546                 new_stat->nid_proc = NULL;
547                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
548                        obd->obd_name, libcfs_nid2str(*nid), rc);
549                 GOTO(destroy_new_ns, rc);
550         }
551
552 #ifndef HAVE_ONLY_PROCFS_SEQ
553         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
554                                    lprocfs_exp_rd_uuid, NULL, new_stat, NULL);
555 #else
556         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid", new_stat,
557                                    &lprocfs_exp_uuid_fops);
558 #endif
559         if (IS_ERR(entry)) {
560                 CWARN("Error adding the NID stats file\n");
561                 rc = PTR_ERR(entry);
562                 GOTO(destroy_new_ns, rc);
563         }
564
565 #ifndef HAVE_ONLY_PROCFS_SEQ
566         entry = lprocfs_add_simple(new_stat->nid_proc, "hash",
567                                    lprocfs_exp_rd_hash, NULL, new_stat, NULL);
568 #else
569         entry = lprocfs_add_simple(new_stat->nid_proc, "hash", new_stat,
570                                    &lprocfs_exp_hash_fops);
571 #endif
572         if (IS_ERR(entry)) {
573                 CWARN("Error adding the hash file\n");
574                 rc = PTR_ERR(entry);
575                 GOTO(destroy_new_ns, rc);
576         }
577
578         spin_lock(&exp->exp_lock);
579         exp->exp_nid_stats = new_stat;
580         spin_unlock(&exp->exp_lock);
581         *newnid = 1;
582         /* protect competitive add to list, not need locking on destroy */
583         spin_lock(&obd->obd_nid_lock);
584         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
585         spin_unlock(&obd->obd_nid_lock);
586
587         RETURN(rc);
588
589 destroy_new_ns:
590         if (new_stat->nid_proc != NULL)
591                 lprocfs_remove(&new_stat->nid_proc);
592         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
593
594 destroy_new:
595         nidstat_putref(new_stat);
596         OBD_FREE_PTR(new_stat);
597         RETURN(rc);
598 }
599 EXPORT_SYMBOL(lprocfs_exp_setup);
600
601 int lprocfs_exp_cleanup(struct obd_export *exp)
602 {
603         struct nid_stat *stat = exp->exp_nid_stats;
604
605         if (!stat || !exp->exp_obd)
606                 RETURN(0);
607
608         nidstat_putref(exp->exp_nid_stats);
609         exp->exp_nid_stats = NULL;
610
611         return 0;
612 }
613 EXPORT_SYMBOL(lprocfs_exp_cleanup);
614
615 #define LPROCFS_OBD_OP_INIT(base, stats, op)                    \
616 do {                                                            \
617         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);   \
618         LASSERT(coffset < stats->ls_num);                       \
619         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");   \
620 } while (0)
621
622 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
623 {
624         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
625         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
626         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
627         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
628         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
629         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
630         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
631         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
632         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
633         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
634         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
635         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
636         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
637         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
638         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
639         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
640         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
641         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
642         LPROCFS_OBD_OP_INIT(num_private_stats, stats, packmd);
643         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpackmd);
644         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
645         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
646         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
647         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
648         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
649         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
650         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
651         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
652         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
653         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
654         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
655         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
656         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
657         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
658         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
659         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
660         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
661         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
662         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
663         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
664         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
670         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
671
672         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
673 }
674 EXPORT_SYMBOL(lprocfs_init_ops_stats);
675
676 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
677 {
678         struct lprocfs_stats *stats;
679         unsigned int num_stats;
680         int rc, i;
681
682         LASSERT(obd->obd_stats == NULL);
683         LASSERT(obd->obd_proc_entry != NULL);
684         LASSERT(obd->obd_cntr_base == 0);
685
686         num_stats = NUM_OBD_STATS + num_private_stats;
687         stats = lprocfs_alloc_stats(num_stats, 0);
688         if (stats == NULL)
689                 return -ENOMEM;
690
691         lprocfs_init_ops_stats(num_private_stats, stats);
692
693         for (i = num_private_stats; i < num_stats; i++) {
694                 /* If this LBUGs, it is likely that an obd
695                  * operation was added to struct obd_ops in
696                  * <obd.h>, and that the corresponding line item
697                  * LPROCFS_OBD_OP_INIT(.., .., opname)
698                  * is missing from the list above. */
699                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
700                          "Missing obd_stat initializer obd_op "
701                          "operation at offset %d.\n", i - num_private_stats);
702         }
703         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
704         if (rc < 0) {
705                 lprocfs_free_stats(&stats);
706         } else {
707                 obd->obd_stats  = stats;
708                 obd->obd_cntr_base = num_private_stats;
709         }
710         return rc;
711 }
712 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
713
714 void lprocfs_free_obd_stats(struct obd_device *obd)
715 {
716         if (obd->obd_stats)
717                 lprocfs_free_stats(&obd->obd_stats);
718 }
719 EXPORT_SYMBOL(lprocfs_free_obd_stats);
720
721 int lprocfs_hash_seq_show(struct seq_file *m, void *data)
722 {
723         struct obd_device *obd = m->private;
724         int c = 0;
725
726         if (obd == NULL)
727                 return 0;
728
729         c += cfs_hash_debug_header_seq(m);
730         c += cfs_hash_debug_str_seq(obd->obd_uuid_hash, m);
731         c += cfs_hash_debug_str_seq(obd->obd_nid_hash, m);
732         c += cfs_hash_debug_str_seq(obd->obd_nid_stats_hash, m);
733         return c;
734 }
735 EXPORT_SYMBOL(lprocfs_hash_seq_show);
736
737 int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
738 {
739         struct obd_device *obd = m->private;
740
741         LASSERT(obd != NULL);
742
743         seq_printf(m, "status: ");
744         if (obd->obd_max_recoverable_clients == 0) {
745                 seq_printf(m, "INACTIVE\n");
746                 goto out;
747         }
748
749         /* sampled unlocked, but really... */
750         if (obd->obd_recovering == 0) {
751                 seq_printf(m, "COMPLETE\n");
752                 seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
753                 seq_printf(m, "recovery_duration: %lu\n",
754                            obd->obd_recovery_end - obd->obd_recovery_start);
755                 /* Number of clients that have completed recovery */
756                 seq_printf(m, "completed_clients: %d/%d\n",
757                            obd->obd_max_recoverable_clients -
758                            obd->obd_stale_clients,
759                            obd->obd_max_recoverable_clients);
760                 seq_printf(m, "replayed_requests: %d\n",
761                            obd->obd_replayed_requests);
762                 seq_printf(m, "last_transno: "LPD64"\n",
763                            obd->obd_next_recovery_transno - 1);
764                 seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
765                            "ENABLED" : "DISABLED");
766                 seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
767                            "DISABLED" : "ENABLED");
768                 goto out;
769         }
770
771         seq_printf(m, "RECOVERING\n");
772         seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
773         seq_printf(m, "time_remaining: %lu\n",
774                    cfs_time_current_sec() >=
775                    obd->obd_recovery_start +
776                    obd->obd_recovery_timeout ? 0 :
777                    obd->obd_recovery_start +
778                    obd->obd_recovery_timeout -
779                    cfs_time_current_sec());
780         seq_printf(m, "connected_clients: %d/%d\n",
781                    atomic_read(&obd->obd_connected_clients),
782                    obd->obd_max_recoverable_clients);
783         /* Number of clients that have completed recovery */
784         seq_printf(m, "req_replay_clients: %d\n",
785                    atomic_read(&obd->obd_req_replay_clients));
786         seq_printf(m, "lock_repay_clients: %d\n",
787                    atomic_read(&obd->obd_lock_replay_clients));
788         seq_printf(m, "completed_clients: %d\n",
789                    atomic_read(&obd->obd_connected_clients) -
790                    atomic_read(&obd->obd_lock_replay_clients));
791         seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
792         seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
793         seq_printf(m, "queued_requests: %d\n",
794                    obd->obd_requests_queued_for_recovery);
795         seq_printf(m, "next_transno: "LPD64"\n",
796                    obd->obd_next_recovery_transno);
797 out:
798         return 0;
799 }
800 EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
801
802 int lprocfs_ir_factor_seq_show(struct seq_file *m, void *data)
803 {
804         struct obd_device *obd = m->private;
805
806         LASSERT(obd != NULL);
807         return seq_printf(m, "%d\n", obd->obd_recovery_ir_factor);
808 }
809 EXPORT_SYMBOL(lprocfs_ir_factor_seq_show);
810
811 ssize_t
812 lprocfs_ir_factor_seq_write(struct file *file, const char *buffer,
813                             size_t count, loff_t *off)
814 {
815         struct seq_file *m = file->private_data;
816         struct obd_device *obd = m->private;
817         int val, rc;
818
819         LASSERT(obd != NULL);
820         rc = lprocfs_write_helper(buffer, count, &val);
821         if (rc)
822                 return rc;
823
824         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
825                 return -EINVAL;
826
827         obd->obd_recovery_ir_factor = val;
828         return count;
829 }
830 EXPORT_SYMBOL(lprocfs_ir_factor_seq_write);
831
832 int lprocfs_recovery_time_soft_seq_show(struct seq_file *m, void *data)
833 {
834         struct obd_device *obd = m->private;
835
836         LASSERT(obd != NULL);
837         return seq_printf(m, "%d\n", obd->obd_recovery_timeout);
838 }
839 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_show);
840
841 ssize_t
842 lprocfs_recovery_time_soft_seq_write(struct file *file, const char *buffer,
843                                         size_t count, loff_t *off)
844 {
845         struct seq_file *m = file->private_data;
846         struct obd_device *obd = m->private;
847         int val, rc;
848
849         LASSERT(obd != NULL);
850         rc = lprocfs_write_helper(buffer, count, &val);
851         if (rc)
852                 return rc;
853
854         obd->obd_recovery_timeout = val;
855         return count;
856 }
857 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_write);
858
859 int lprocfs_recovery_time_hard_seq_show(struct seq_file *m, void *data)
860 {
861         struct obd_device *obd = m->private;
862
863         LASSERT(obd != NULL);
864         return seq_printf(m, "%u\n", obd->obd_recovery_time_hard);
865 }
866 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_show);
867
868 ssize_t
869 lprocfs_recovery_time_hard_seq_write(struct file *file, const char *buffer,
870                                      size_t count, loff_t *off)
871 {
872         struct seq_file *m = file->private_data;
873         struct obd_device *obd = m->private;
874         int val, rc;
875
876         LASSERT(obd != NULL);
877         rc = lprocfs_write_helper(buffer, count, &val);
878         if (rc)
879                 return rc;
880
881         obd->obd_recovery_time_hard = val;
882         return count;
883 }
884 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_write);
885
886 int lprocfs_target_instance_seq_show(struct seq_file *m, void *data)
887 {
888         struct obd_device *obd = m->private;
889         struct obd_device_target *target = &obd->u.obt;
890
891         LASSERT(obd != NULL);
892         LASSERT(target->obt_magic == OBT_MAGIC);
893         return seq_printf(m, "%u\n", obd->u.obt.obt_instance);
894 }
895 EXPORT_SYMBOL(lprocfs_target_instance_seq_show);
896
897 #ifndef HAVE_ONLY_PROCFS_SEQ
898 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
899                         int count, int *eof, void *data)
900 {
901         struct obd_device *obd = data;
902         int c = 0;
903
904         if (obd == NULL)
905                 return 0;
906
907         c += cfs_hash_debug_header(page, count);
908         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
909         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
910         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
911
912         return c;
913 }
914 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
915
916 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
917                                    int count, int *eof, void *data)
918 {
919         struct obd_device *obd = data;
920         int len = 0, size;
921
922         LASSERT(obd != NULL);
923         LASSERT(count >= 0);
924
925         /* Set start of user data returned to
926            page + off since the user may have
927            requested to read much smaller than
928            what we need to read */
929         *start = page + off;
930
931         /*
932          * We know we are allocated a page here.
933          * Also we know that this function will
934          * not need to write more than a page
935          * so we can truncate at PAGE_CACHE_SIZE.
936          */
937         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
938
939         /* Initialize the page */
940         memset(page, 0, size);
941
942         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
943                 goto out;
944         if (obd->obd_max_recoverable_clients == 0) {
945                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
946                         goto out;
947
948                 goto fclose;
949         }
950
951         /* sampled unlocked, but really... */
952         if (obd->obd_recovering == 0) {
953                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
954                         goto out;
955                 if (lprocfs_obd_snprintf(&page, size, &len,
956                                          "recovery_start: %lu\n",
957                                          obd->obd_recovery_start) <= 0)
958                         goto out;
959                 if (lprocfs_obd_snprintf(&page, size, &len,
960                                          "recovery_duration: %lu\n",
961                                          obd->obd_recovery_end -
962                                          obd->obd_recovery_start) <= 0)
963                         goto out;
964                 /* Number of clients that have completed recovery */
965                 if (lprocfs_obd_snprintf(&page, size, &len,
966                                          "completed_clients: %d/%d\n",
967                                          obd->obd_max_recoverable_clients -
968                                          obd->obd_stale_clients,
969                                          obd->obd_max_recoverable_clients) <= 0)
970                         goto out;
971                 if (lprocfs_obd_snprintf(&page, size, &len,
972                                          "replayed_requests: %d\n",
973                                          obd->obd_replayed_requests) <= 0)
974                         goto out;
975                 if (lprocfs_obd_snprintf(&page, size, &len,
976                                          "last_transno: "LPD64"\n",
977                                          obd->obd_next_recovery_transno - 1) <= 0)
978                         goto out;
979                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
980                                          obd->obd_version_recov ?
981                                          "ENABLED" : "DISABLED") <= 0)
982                         goto out;
983                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
984                                          obd->obd_no_ir ?
985                                          "DISABLED" : "ENABLED") <= 0)
986                         goto out;
987                 goto fclose;
988         }
989
990         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
991                 goto out;
992         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
993                                  obd->obd_recovery_start) <= 0)
994                 goto out;
995         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
996                                  cfs_time_current_sec() >=
997                                  obd->obd_recovery_start +
998                                  obd->obd_recovery_timeout ? 0 :
999                                  obd->obd_recovery_start +
1000                                  obd->obd_recovery_timeout -
1001                                  cfs_time_current_sec()) <= 0)
1002                 goto out;
1003         if (lprocfs_obd_snprintf(&page, size, &len,
1004                                  "connected_clients: %d/%d\n",
1005                                  atomic_read(&obd->obd_connected_clients),
1006                                  obd->obd_max_recoverable_clients) <= 0)
1007                 goto out;
1008         /* Number of clients that have completed recovery */
1009         if (lprocfs_obd_snprintf(&page, size, &len, "req_replay_clients: %d\n",
1010                                  atomic_read(&obd->obd_req_replay_clients))
1011                 <= 0)
1012                 goto out;
1013         if (lprocfs_obd_snprintf(&page, size, &len, "lock_repay_clients: %d\n",
1014                                  atomic_read(&obd->obd_lock_replay_clients))
1015                 <= 0)
1016                 goto out;
1017         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d\n",
1018                                  atomic_read(&obd->obd_connected_clients) -
1019                                  atomic_read(&obd->obd_lock_replay_clients))
1020                 <= 0)
1021                 goto out;
1022         if (lprocfs_obd_snprintf(&page, size, &len, "evicted_clients: %d\n",
1023                                  obd->obd_stale_clients) <= 0)
1024                 goto out;
1025         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n",
1026                                  obd->obd_replayed_requests) <= 0)
1027                 goto out;
1028         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1029                                  obd->obd_requests_queued_for_recovery) <= 0)
1030                 goto out;
1031
1032         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1033                                  obd->obd_next_recovery_transno) <= 0)
1034                 goto out;
1035
1036 fclose:
1037         *eof = 1;
1038 out:
1039         return min(count, len - (int)off);
1040 }
1041 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1042
1043 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
1044                              int count, int *eof, void *data)
1045 {
1046         struct obd_device *obd = (struct obd_device *)data;
1047         LASSERT(obd != NULL);
1048
1049         return snprintf(page, count, "%d\n",
1050                         obd->obd_recovery_ir_factor);
1051 }
1052 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
1053
1054 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
1055                              unsigned long count, void *data)
1056 {
1057         struct obd_device *obd = (struct obd_device *)data;
1058         int val, rc;
1059         LASSERT(obd != NULL);
1060
1061         rc = lprocfs_write_helper(buffer, count, &val);
1062         if (rc)
1063                 return rc;
1064
1065         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
1066                 return -EINVAL;
1067
1068         obd->obd_recovery_ir_factor = val;
1069         return count;
1070 }
1071 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
1072
1073 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
1074                                       int count, int *eof, void *data)
1075 {
1076         struct obd_device *obd = (struct obd_device *)data;
1077         LASSERT(obd != NULL);
1078
1079         return snprintf(page, count, "%d\n",
1080                         obd->obd_recovery_timeout);
1081 }
1082 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
1083
1084 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
1085                                       unsigned long count, void *data)
1086 {
1087         struct obd_device *obd = (struct obd_device *)data;
1088         int val, rc;
1089         LASSERT(obd != NULL);
1090
1091         rc = lprocfs_write_helper(buffer, count, &val);
1092         if (rc)
1093                 return rc;
1094
1095         obd->obd_recovery_timeout = val;
1096         return count;
1097 }
1098 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
1099
1100 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
1101                                       int count, int *eof, void *data)
1102 {
1103         struct obd_device *obd = data;
1104         LASSERT(obd != NULL);
1105
1106         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
1107 }
1108 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
1109
1110 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
1111                                       unsigned long count, void *data)
1112 {
1113         struct obd_device *obd = data;
1114         int val, rc;
1115         LASSERT(obd != NULL);
1116
1117         rc = lprocfs_write_helper(buffer, count, &val);
1118         if (rc)
1119                 return rc;
1120
1121         obd->obd_recovery_time_hard = val;
1122         return count;
1123 }
1124 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
1125
1126 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
1127                                int count, int *eof, void *data)
1128 {
1129         struct obd_device *obd = (struct obd_device *)data;
1130         struct obd_device_target *target = &obd->u.obt;
1131
1132         LASSERT(obd != NULL);
1133         LASSERT(target->obt_magic == OBT_MAGIC);
1134         *eof = 1;
1135         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
1136 }
1137 EXPORT_SYMBOL(lprocfs_target_rd_instance);
1138 #endif /* HAVE_ONLY_PROCFS_SEQ */
1139 #endif /* LPROCFS*/