Whamcloud - gitweb
LU-1330 obdclass: splits server-side procfs handling
[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, attach);
628         LPROCFS_OBD_OP_INIT(num_private_stats, stats, detach);
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, create_async);
648         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
649         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
650         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr_async);
651         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
652         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr_async);
653         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
654         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
655         LPROCFS_OBD_OP_INIT(num_private_stats, stats, change_cbdata);
656         LPROCFS_OBD_OP_INIT(num_private_stats, stats, find_cbdata);
657         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
658         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
659         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_init);
660         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_connect);
661         LPROCFS_OBD_OP_INIT(num_private_stats, stats, llog_finish);
662         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pin);
663         LPROCFS_OBD_OP_INIT(num_private_stats, stats, unpin);
664         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
665         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
666         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
667         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
668         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
669         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
670         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
671         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
672         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
673         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
674         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
675         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
676         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
677
678         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
679 }
680 EXPORT_SYMBOL(lprocfs_init_ops_stats);
681
682 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
683 {
684         struct lprocfs_stats *stats;
685         unsigned int num_stats;
686         int rc, i;
687
688         LASSERT(obd->obd_stats == NULL);
689         LASSERT(obd->obd_proc_entry != NULL);
690         LASSERT(obd->obd_cntr_base == 0);
691
692         num_stats = NUM_OBD_STATS + num_private_stats;
693         stats = lprocfs_alloc_stats(num_stats, 0);
694         if (stats == NULL)
695                 return -ENOMEM;
696
697         lprocfs_init_ops_stats(num_private_stats, stats);
698
699         for (i = num_private_stats; i < num_stats; i++) {
700                 /* If this LBUGs, it is likely that an obd
701                  * operation was added to struct obd_ops in
702                  * <obd.h>, and that the corresponding line item
703                  * LPROCFS_OBD_OP_INIT(.., .., opname)
704                  * is missing from the list above. */
705                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
706                          "Missing obd_stat initializer obd_op "
707                          "operation at offset %d.\n", i - num_private_stats);
708         }
709         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
710         if (rc < 0) {
711                 lprocfs_free_stats(&stats);
712         } else {
713                 obd->obd_stats  = stats;
714                 obd->obd_cntr_base = num_private_stats;
715         }
716         return rc;
717 }
718 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
719
720 void lprocfs_free_obd_stats(struct obd_device *obd)
721 {
722         if (obd->obd_stats)
723                 lprocfs_free_stats(&obd->obd_stats);
724 }
725 EXPORT_SYMBOL(lprocfs_free_obd_stats);
726
727 int lprocfs_hash_seq_show(struct seq_file *m, void *data)
728 {
729         struct obd_device *obd = m->private;
730         int c = 0;
731
732         if (obd == NULL)
733                 return 0;
734
735         c += cfs_hash_debug_header_seq(m);
736         c += cfs_hash_debug_str_seq(obd->obd_uuid_hash, m);
737         c += cfs_hash_debug_str_seq(obd->obd_nid_hash, m);
738         c += cfs_hash_debug_str_seq(obd->obd_nid_stats_hash, m);
739         return c;
740 }
741 EXPORT_SYMBOL(lprocfs_hash_seq_show);
742
743 int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
744 {
745         struct obd_device *obd = m->private;
746
747         LASSERT(obd != NULL);
748
749         seq_printf(m, "status: ");
750         if (obd->obd_max_recoverable_clients == 0) {
751                 seq_printf(m, "INACTIVE\n");
752                 goto out;
753         }
754
755         /* sampled unlocked, but really... */
756         if (obd->obd_recovering == 0) {
757                 seq_printf(m, "COMPLETE\n");
758                 seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
759                 seq_printf(m, "recovery_duration: %lu\n",
760                            obd->obd_recovery_end - obd->obd_recovery_start);
761                 /* Number of clients that have completed recovery */
762                 seq_printf(m, "completed_clients: %d/%d\n",
763                            obd->obd_max_recoverable_clients -
764                            obd->obd_stale_clients,
765                            obd->obd_max_recoverable_clients);
766                 seq_printf(m, "replayed_requests: %d\n",
767                            obd->obd_replayed_requests);
768                 seq_printf(m, "last_transno: "LPD64"\n",
769                            obd->obd_next_recovery_transno - 1);
770                 seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
771                            "ENABLED" : "DISABLED");
772                 seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
773                            "DISABLED" : "ENABLED");
774                 goto out;
775         }
776
777         seq_printf(m, "RECOVERING\n");
778         seq_printf(m, "recovery_start: %lu\n", obd->obd_recovery_start);
779         seq_printf(m, "time_remaining: %lu\n",
780                    cfs_time_current_sec() >=
781                    obd->obd_recovery_start +
782                    obd->obd_recovery_timeout ? 0 :
783                    obd->obd_recovery_start +
784                    obd->obd_recovery_timeout -
785                    cfs_time_current_sec());
786         seq_printf(m, "connected_clients: %d/%d\n",
787                    atomic_read(&obd->obd_connected_clients),
788                    obd->obd_max_recoverable_clients);
789         /* Number of clients that have completed recovery */
790         seq_printf(m, "req_replay_clients: %d\n",
791                    atomic_read(&obd->obd_req_replay_clients));
792         seq_printf(m, "lock_repay_clients: %d\n",
793                    atomic_read(&obd->obd_lock_replay_clients));
794         seq_printf(m, "completed_clients: %d\n",
795                    atomic_read(&obd->obd_connected_clients) -
796                    atomic_read(&obd->obd_lock_replay_clients));
797         seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
798         seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
799         seq_printf(m, "queued_requests: %d\n",
800                    obd->obd_requests_queued_for_recovery);
801         seq_printf(m, "next_transno: "LPD64"\n",
802                    obd->obd_next_recovery_transno);
803 out:
804         return 0;
805 }
806 EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
807
808 int lprocfs_ir_factor_seq_show(struct seq_file *m, void *data)
809 {
810         struct obd_device *obd = m->private;
811
812         LASSERT(obd != NULL);
813         return seq_printf(m, "%d\n", obd->obd_recovery_ir_factor);
814 }
815 EXPORT_SYMBOL(lprocfs_ir_factor_seq_show);
816
817 ssize_t
818 lprocfs_ir_factor_seq_write(struct file *file, const char *buffer,
819                             size_t count, loff_t *off)
820 {
821         struct seq_file *m = file->private_data;
822         struct obd_device *obd = m->private;
823         int val, rc;
824
825         LASSERT(obd != NULL);
826         rc = lprocfs_write_helper(buffer, count, &val);
827         if (rc)
828                 return rc;
829
830         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
831                 return -EINVAL;
832
833         obd->obd_recovery_ir_factor = val;
834         return count;
835 }
836 EXPORT_SYMBOL(lprocfs_ir_factor_seq_write);
837
838 int lprocfs_recovery_time_soft_seq_show(struct seq_file *m, void *data)
839 {
840         struct obd_device *obd = m->private;
841
842         LASSERT(obd != NULL);
843         return seq_printf(m, "%d\n", obd->obd_recovery_timeout);
844 }
845 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_show);
846
847 ssize_t
848 lprocfs_recovery_time_soft_seq_write(struct file *file, const char *buffer,
849                                         size_t count, loff_t *off)
850 {
851         struct seq_file *m = file->private_data;
852         struct obd_device *obd = m->private;
853         int val, rc;
854
855         LASSERT(obd != NULL);
856         rc = lprocfs_write_helper(buffer, count, &val);
857         if (rc)
858                 return rc;
859
860         obd->obd_recovery_timeout = val;
861         return count;
862 }
863 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_write);
864
865 int lprocfs_recovery_time_hard_seq_show(struct seq_file *m, void *data)
866 {
867         struct obd_device *obd = m->private;
868
869         LASSERT(obd != NULL);
870         return seq_printf(m, "%u\n", obd->obd_recovery_time_hard);
871 }
872 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_show);
873
874 ssize_t
875 lprocfs_recovery_time_hard_seq_write(struct file *file, const char *buffer,
876                                      size_t count, loff_t *off)
877 {
878         struct seq_file *m = file->private_data;
879         struct obd_device *obd = m->private;
880         int val, rc;
881
882         LASSERT(obd != NULL);
883         rc = lprocfs_write_helper(buffer, count, &val);
884         if (rc)
885                 return rc;
886
887         obd->obd_recovery_time_hard = val;
888         return count;
889 }
890 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_write);
891
892 int lprocfs_target_instance_seq_show(struct seq_file *m, void *data)
893 {
894         struct obd_device *obd = m->private;
895         struct obd_device_target *target = &obd->u.obt;
896
897         LASSERT(obd != NULL);
898         LASSERT(target->obt_magic == OBT_MAGIC);
899         return seq_printf(m, "%u\n", obd->u.obt.obt_instance);
900 }
901 EXPORT_SYMBOL(lprocfs_target_instance_seq_show);
902
903 #ifndef HAVE_ONLY_PROCFS_SEQ
904 int lprocfs_obd_rd_hash(char *page, char **start, off_t off,
905                         int count, int *eof, void *data)
906 {
907         struct obd_device *obd = data;
908         int c = 0;
909
910         if (obd == NULL)
911                 return 0;
912
913         c += cfs_hash_debug_header(page, count);
914         c += cfs_hash_debug_str(obd->obd_uuid_hash, page + c, count - c);
915         c += cfs_hash_debug_str(obd->obd_nid_hash, page + c, count - c);
916         c += cfs_hash_debug_str(obd->obd_nid_stats_hash, page+c, count-c);
917
918         return c;
919 }
920 EXPORT_SYMBOL(lprocfs_obd_rd_hash);
921
922 int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
923                                    int count, int *eof, void *data)
924 {
925         struct obd_device *obd = data;
926         int len = 0, size;
927
928         LASSERT(obd != NULL);
929         LASSERT(count >= 0);
930
931         /* Set start of user data returned to
932            page + off since the user may have
933            requested to read much smaller than
934            what we need to read */
935         *start = page + off;
936
937         /*
938          * We know we are allocated a page here.
939          * Also we know that this function will
940          * not need to write more than a page
941          * so we can truncate at PAGE_CACHE_SIZE.
942          */
943         size = min(count + (int)off + 1, (int)PAGE_CACHE_SIZE);
944
945         /* Initialize the page */
946         memset(page, 0, size);
947
948         if (lprocfs_obd_snprintf(&page, size, &len, "status: ") <= 0)
949                 goto out;
950         if (obd->obd_max_recoverable_clients == 0) {
951                 if (lprocfs_obd_snprintf(&page, size, &len, "INACTIVE\n") <= 0)
952                         goto out;
953
954                 goto fclose;
955         }
956
957         /* sampled unlocked, but really... */
958         if (obd->obd_recovering == 0) {
959                 if (lprocfs_obd_snprintf(&page, size, &len, "COMPLETE\n") <= 0)
960                         goto out;
961                 if (lprocfs_obd_snprintf(&page, size, &len,
962                                          "recovery_start: %lu\n",
963                                          obd->obd_recovery_start) <= 0)
964                         goto out;
965                 if (lprocfs_obd_snprintf(&page, size, &len,
966                                          "recovery_duration: %lu\n",
967                                          obd->obd_recovery_end -
968                                          obd->obd_recovery_start) <= 0)
969                         goto out;
970                 /* Number of clients that have completed recovery */
971                 if (lprocfs_obd_snprintf(&page, size, &len,
972                                          "completed_clients: %d/%d\n",
973                                          obd->obd_max_recoverable_clients -
974                                          obd->obd_stale_clients,
975                                          obd->obd_max_recoverable_clients) <= 0)
976                         goto out;
977                 if (lprocfs_obd_snprintf(&page, size, &len,
978                                          "replayed_requests: %d\n",
979                                          obd->obd_replayed_requests) <= 0)
980                         goto out;
981                 if (lprocfs_obd_snprintf(&page, size, &len,
982                                          "last_transno: "LPD64"\n",
983                                          obd->obd_next_recovery_transno - 1) <= 0)
984                         goto out;
985                 if (lprocfs_obd_snprintf(&page, size, &len, "VBR: %s\n",
986                                          obd->obd_version_recov ?
987                                          "ENABLED" : "DISABLED") <= 0)
988                         goto out;
989                 if (lprocfs_obd_snprintf(&page, size, &len, "IR: %s\n",
990                                          obd->obd_no_ir ?
991                                          "DISABLED" : "ENABLED") <= 0)
992                         goto out;
993                 goto fclose;
994         }
995
996         if (lprocfs_obd_snprintf(&page, size, &len, "RECOVERING\n") <= 0)
997                 goto out;
998         if (lprocfs_obd_snprintf(&page, size, &len, "recovery_start: %lu\n",
999                                  obd->obd_recovery_start) <= 0)
1000                 goto out;
1001         if (lprocfs_obd_snprintf(&page, size, &len, "time_remaining: %lu\n",
1002                                  cfs_time_current_sec() >=
1003                                  obd->obd_recovery_start +
1004                                  obd->obd_recovery_timeout ? 0 :
1005                                  obd->obd_recovery_start +
1006                                  obd->obd_recovery_timeout -
1007                                  cfs_time_current_sec()) <= 0)
1008                 goto out;
1009         if (lprocfs_obd_snprintf(&page, size, &len,
1010                                  "connected_clients: %d/%d\n",
1011                                  atomic_read(&obd->obd_connected_clients),
1012                                  obd->obd_max_recoverable_clients) <= 0)
1013                 goto out;
1014         /* Number of clients that have completed recovery */
1015         if (lprocfs_obd_snprintf(&page, size, &len, "req_replay_clients: %d\n",
1016                                  atomic_read(&obd->obd_req_replay_clients))
1017                 <= 0)
1018                 goto out;
1019         if (lprocfs_obd_snprintf(&page, size, &len, "lock_repay_clients: %d\n",
1020                                  atomic_read(&obd->obd_lock_replay_clients))
1021                 <= 0)
1022                 goto out;
1023         if (lprocfs_obd_snprintf(&page, size, &len, "completed_clients: %d\n",
1024                                  atomic_read(&obd->obd_connected_clients) -
1025                                  atomic_read(&obd->obd_lock_replay_clients))
1026                 <= 0)
1027                 goto out;
1028         if (lprocfs_obd_snprintf(&page, size, &len, "evicted_clients: %d\n",
1029                                  obd->obd_stale_clients) <= 0)
1030                 goto out;
1031         if (lprocfs_obd_snprintf(&page, size, &len, "replayed_requests: %d\n",
1032                                  obd->obd_replayed_requests) <= 0)
1033                 goto out;
1034         if (lprocfs_obd_snprintf(&page, size, &len, "queued_requests: %d\n",
1035                                  obd->obd_requests_queued_for_recovery) <= 0)
1036                 goto out;
1037
1038         if (lprocfs_obd_snprintf(&page, size, &len, "next_transno: "LPD64"\n",
1039                                  obd->obd_next_recovery_transno) <= 0)
1040                 goto out;
1041
1042 fclose:
1043         *eof = 1;
1044 out:
1045         return min(count, len - (int)off);
1046 }
1047 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_status);
1048
1049 int lprocfs_obd_rd_ir_factor(char *page, char **start, off_t off,
1050                              int count, int *eof, void *data)
1051 {
1052         struct obd_device *obd = (struct obd_device *)data;
1053         LASSERT(obd != NULL);
1054
1055         return snprintf(page, count, "%d\n",
1056                         obd->obd_recovery_ir_factor);
1057 }
1058 EXPORT_SYMBOL(lprocfs_obd_rd_ir_factor);
1059
1060 int lprocfs_obd_wr_ir_factor(struct file *file, const char *buffer,
1061                              unsigned long count, void *data)
1062 {
1063         struct obd_device *obd = (struct obd_device *)data;
1064         int val, rc;
1065         LASSERT(obd != NULL);
1066
1067         rc = lprocfs_write_helper(buffer, count, &val);
1068         if (rc)
1069                 return rc;
1070
1071         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
1072                 return -EINVAL;
1073
1074         obd->obd_recovery_ir_factor = val;
1075         return count;
1076 }
1077 EXPORT_SYMBOL(lprocfs_obd_wr_ir_factor);
1078
1079 int lprocfs_obd_rd_recovery_time_soft(char *page, char **start, off_t off,
1080                                       int count, int *eof, void *data)
1081 {
1082         struct obd_device *obd = (struct obd_device *)data;
1083         LASSERT(obd != NULL);
1084
1085         return snprintf(page, count, "%d\n",
1086                         obd->obd_recovery_timeout);
1087 }
1088 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_soft);
1089
1090 int lprocfs_obd_wr_recovery_time_soft(struct file *file, const char *buffer,
1091                                       unsigned long count, void *data)
1092 {
1093         struct obd_device *obd = (struct obd_device *)data;
1094         int val, rc;
1095         LASSERT(obd != NULL);
1096
1097         rc = lprocfs_write_helper(buffer, count, &val);
1098         if (rc)
1099                 return rc;
1100
1101         obd->obd_recovery_timeout = val;
1102         return count;
1103 }
1104 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_soft);
1105
1106 int lprocfs_obd_rd_recovery_time_hard(char *page, char **start, off_t off,
1107                                       int count, int *eof, void *data)
1108 {
1109         struct obd_device *obd = data;
1110         LASSERT(obd != NULL);
1111
1112         return snprintf(page, count, "%u\n", obd->obd_recovery_time_hard);
1113 }
1114 EXPORT_SYMBOL(lprocfs_obd_rd_recovery_time_hard);
1115
1116 int lprocfs_obd_wr_recovery_time_hard(struct file *file, const char *buffer,
1117                                       unsigned long count, void *data)
1118 {
1119         struct obd_device *obd = data;
1120         int val, rc;
1121         LASSERT(obd != NULL);
1122
1123         rc = lprocfs_write_helper(buffer, count, &val);
1124         if (rc)
1125                 return rc;
1126
1127         obd->obd_recovery_time_hard = val;
1128         return count;
1129 }
1130 EXPORT_SYMBOL(lprocfs_obd_wr_recovery_time_hard);
1131
1132 int lprocfs_target_rd_instance(char *page, char **start, off_t off,
1133                                int count, int *eof, void *data)
1134 {
1135         struct obd_device *obd = (struct obd_device *)data;
1136         struct obd_device_target *target = &obd->u.obt;
1137
1138         LASSERT(obd != NULL);
1139         LASSERT(target->obt_magic == OBT_MAGIC);
1140         *eof = 1;
1141         return snprintf(page, count, "%u\n", obd->u.obt.obt_instance);
1142 }
1143 EXPORT_SYMBOL(lprocfs_target_rd_instance);
1144 #endif /* HAVE_ONLY_PROCFS_SEQ */
1145 #endif /* LPROCFS*/