Whamcloud - gitweb
0e3e998caeb1353e0fe315ad7ac411333ad67494
[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.gnu.org/licenses/gpl-2.0.html
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) 2014, 2016, 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 #include <linux/kobject.h>
38 #include <linux/sysfs.h>
39
40 #include <obd_class.h>
41 #include <lprocfs_status.h>
42 #include <lustre_nodemap.h>
43
44 #ifdef CONFIG_PROC_FS
45
46 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
47 {
48         struct obd_device *obd = PDE_DATA(file_inode(f));
49
50         atomic_inc(&obd->obd_evict_inprogress);
51         return 0;
52 }
53
54 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
55 {
56         struct obd_device *obd = PDE_DATA(file_inode(f));
57
58         atomic_dec(&obd->obd_evict_inprogress);
59         wake_up(&obd->obd_evict_inprogress_waitq);
60
61         return 0;
62 }
63
64 #define BUFLEN (UUID_MAX + 5)
65
66 ssize_t
67 lprocfs_evict_client_seq_write(struct file *file, const char __user *buffer,
68                                size_t count, loff_t *off)
69 {
70         struct seq_file *m = file->private_data;
71         struct obd_device *obd = m->private;
72         char *tmpbuf, *kbuf;
73
74         OBD_ALLOC(kbuf, BUFLEN);
75         if (kbuf == NULL)
76                 return -ENOMEM;
77
78         /*
79          * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
80          * bytes into kbuf, to ensure that the string is NUL-terminated.
81          * UUID_MAX should include a trailing NUL already.
82          */
83         if (copy_from_user(kbuf, buffer,
84                            min_t(unsigned long, BUFLEN - 1, count))) {
85                 count = -EFAULT;
86                 goto out;
87         }
88         tmpbuf = cfs_firststr(kbuf, min_t(unsigned long, BUFLEN - 1, count));
89         class_incref(obd, __func__, current);
90
91         if (strncmp(tmpbuf, "nid:", 4) == 0)
92                 obd_export_evict_by_nid(obd, tmpbuf + 4);
93         else if (strncmp(tmpbuf, "uuid:", 5) == 0)
94                 obd_export_evict_by_uuid(obd, tmpbuf + 5);
95         else
96                 obd_export_evict_by_uuid(obd, tmpbuf);
97
98         class_decref(obd, __func__, current);
99
100 out:
101         OBD_FREE(kbuf, BUFLEN);
102         return count;
103 }
104 EXPORT_SYMBOL(lprocfs_evict_client_seq_write);
105
106 #undef BUFLEN
107
108 int lprocfs_num_exports_seq_show(struct seq_file *m, void *data)
109 {
110         struct obd_device *obd = data;
111
112         LASSERT(obd != NULL);
113         seq_printf(m, "%u\n", obd->obd_num_exports);
114         return 0;
115 }
116 EXPORT_SYMBOL(lprocfs_num_exports_seq_show);
117
118 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
119 {
120         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
121                client_stat->nid_proc, client_stat->nid_stats);
122
123         LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
124                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
125                  atomic_read(&client_stat->nid_exp_ref_count));
126
127         if (client_stat->nid_proc)
128                 lprocfs_remove(&client_stat->nid_proc);
129
130         if (client_stat->nid_stats)
131                 lprocfs_free_stats(&client_stat->nid_stats);
132
133         if (client_stat->nid_ldlm_stats)
134                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
135
136         OBD_FREE_PTR(client_stat);
137         return;
138 }
139
140 void lprocfs_free_per_client_stats(struct obd_device *obd)
141 {
142         struct cfs_hash *hash = obd->obd_nid_stats_hash;
143         struct nid_stat *stat;
144         ENTRY;
145
146         /* we need extra list - because hash_exit called to early */
147         /* not need locking because all clients is died */
148         while (!list_empty(&obd->obd_nid_stats)) {
149                 stat = list_entry(obd->obd_nid_stats.next,
150                                   struct nid_stat, nid_list);
151                 list_del_init(&stat->nid_list);
152                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
153                 lprocfs_free_client_stats(stat);
154         }
155         EXIT;
156 }
157 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
158
159 static int
160 lprocfs_exp_print_uuid_seq(struct cfs_hash *hs, struct cfs_hash_bd *bd,
161                            struct hlist_node *hnode, void *cb_data)
162 {
163         struct seq_file *m = cb_data;
164         struct obd_export *exp = cfs_hash_object(hs, hnode);
165
166         if (exp->exp_nid_stats != NULL)
167                 seq_printf(m, "%s\n", obd_uuid2str(&exp->exp_client_uuid));
168         return 0;
169 }
170
171 static int
172 lprocfs_exp_print_nodemap_seq(struct cfs_hash *hs, struct cfs_hash_bd *bd,
173                               struct hlist_node *hnode, void *cb_data)
174 {
175         struct seq_file *m = cb_data;
176         struct obd_export *exp = cfs_hash_object(hs, hnode);
177         struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap;
178
179         if (nodemap != NULL)
180                 seq_printf(m, "%s\n", nodemap->nm_name);
181         return 0;
182 }
183
184 static int
185 lprocfs_exp_nodemap_seq_show(struct seq_file *m, void *data)
186 {
187         struct nid_stat *stats = m->private;
188         struct obd_device *obd = stats->nid_obd;
189
190         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
191                               lprocfs_exp_print_nodemap_seq, m);
192         return 0;
193 }
194 LPROC_SEQ_FOPS_RO(lprocfs_exp_nodemap);
195
196 static int lprocfs_exp_uuid_seq_show(struct seq_file *m, void *data)
197 {
198         struct nid_stat *stats = m->private;
199         struct obd_device *obd = stats->nid_obd;
200
201         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
202                                 lprocfs_exp_print_uuid_seq, m);
203         return 0;
204 }
205 LPROC_SEQ_FOPS_RO(lprocfs_exp_uuid);
206
207 static int
208 lprocfs_exp_print_hash_seq(struct cfs_hash *hs, struct cfs_hash_bd *bd,
209                            struct hlist_node *hnode, void *cb_data)
210
211 {
212         struct seq_file *m = cb_data;
213         struct obd_export *exp = cfs_hash_object(hs, hnode);
214
215         if (exp->exp_lock_hash != NULL) {
216                 cfs_hash_debug_header(m);
217                 cfs_hash_debug_str(hs, m);
218         }
219         return 0;
220 }
221
222 static int lprocfs_exp_hash_seq_show(struct seq_file *m, void *data)
223 {
224         struct nid_stat *stats = m->private;
225         struct obd_device *obd = stats->nid_obd;
226
227         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
228                                 lprocfs_exp_print_hash_seq, m);
229         return 0;
230 }
231 LPROC_SEQ_FOPS_RO(lprocfs_exp_hash);
232
233 int lprocfs_exp_print_replydata_seq(struct cfs_hash *hs, struct cfs_hash_bd *bd,
234                                     struct hlist_node *hnode, void *cb_data)
235
236 {
237         struct obd_export *exp = cfs_hash_object(hs, hnode);
238         struct seq_file *m = cb_data;
239         struct tg_export_data *ted = &exp->exp_target_data;
240
241         seq_printf(m, "reply_cnt: %d\n"
242                    "reply_max: %d\n"
243                    "reply_released_by_xid: %d\n"
244                    "reply_released_by_tag: %d\n\n",
245                    ted->ted_reply_cnt,
246                    ted->ted_reply_max,
247                    ted->ted_release_xid,
248                    ted->ted_release_tag);
249         return 0;
250 }
251
252 int lprocfs_exp_replydata_seq_show(struct seq_file *m, void *data)
253 {
254         struct nid_stat *stats = m->private;
255         struct obd_device *obd = stats->nid_obd;
256
257         cfs_hash_for_each_key(obd->obd_nid_hash, &stats->nid,
258                                 lprocfs_exp_print_replydata_seq, m);
259         return 0;
260 }
261 LPROC_SEQ_FOPS_RO(lprocfs_exp_replydata);
262
263 int lprocfs_nid_stats_clear_seq_show(struct seq_file *m, void *data)
264 {
265         seq_puts(m, "Write into this file to clear all nid stats and stale nid entries\n");
266         return 0;
267 }
268 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_show);
269
270 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
271 {
272         struct nid_stat *stat = obj;
273         ENTRY;
274
275         CDEBUG(D_INFO, "refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
276         if (atomic_read(&stat->nid_exp_ref_count) == 1) {
277                 /* object has only hash references. */
278                 spin_lock(&stat->nid_obd->obd_nid_lock);
279                 list_move(&stat->nid_list, data);
280                 spin_unlock(&stat->nid_obd->obd_nid_lock);
281                 RETURN(1);
282         }
283         /* we has reference to object - only clear data*/
284         if (stat->nid_stats)
285                 lprocfs_clear_stats(stat->nid_stats);
286
287         RETURN(0);
288 }
289
290 ssize_t
291 lprocfs_nid_stats_clear_seq_write(struct file *file, const char __user *buffer,
292                                         size_t count, loff_t *off)
293 {
294         struct seq_file *m = file->private_data;
295         struct obd_device *obd = m->private;
296         struct nid_stat *client_stat;
297         struct list_head free_list;
298
299         INIT_LIST_HEAD(&free_list);
300         cfs_hash_cond_del(obd->obd_nid_stats_hash,
301                           lprocfs_nid_stats_clear_write_cb, &free_list);
302
303         while (!list_empty(&free_list)) {
304                 client_stat = list_entry(free_list.next, struct nid_stat,
305                                          nid_list);
306                 list_del_init(&client_stat->nid_list);
307                 lprocfs_free_client_stats(client_stat);
308         }
309         return count;
310 }
311 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_write);
312
313 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid)
314 {
315         struct nid_stat *new_stat, *old_stat;
316         struct obd_device *obd = NULL;
317         struct proc_dir_entry *entry;
318         char nidstr[LNET_NIDSTR_SIZE];
319         int rc = 0;
320         ENTRY;
321
322         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
323             !exp->exp_obd->obd_nid_stats_hash)
324                 RETURN(-EINVAL);
325
326         /* not test against zero because eric say:
327          * You may only test nid against another nid, or LNET_NID_ANY.
328          * Anything else is nonsense.*/
329         if (nid == NULL || *nid == LNET_NID_ANY)
330                 RETURN(-EALREADY);
331
332         libcfs_nid2str_r(*nid, nidstr, sizeof(nidstr));
333
334         spin_lock(&exp->exp_lock);
335         if (exp->exp_nid_stats != NULL) {
336                 spin_unlock(&exp->exp_lock);
337                 RETURN(-EALREADY);
338         }
339         spin_unlock(&exp->exp_lock);
340
341         obd = exp->exp_obd;
342
343         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
344
345         OBD_ALLOC_PTR(new_stat);
346         if (new_stat == NULL)
347                 RETURN(-ENOMEM);
348
349         new_stat->nid     = *nid;
350         new_stat->nid_obd = exp->exp_obd;
351         /* we need set default refcount to 1 to balance obd_disconnect */
352         atomic_set(&new_stat->nid_exp_ref_count, 1);
353
354         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
355                                            nid, &new_stat->nid_hash);
356         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
357                old_stat, nidstr, atomic_read(&old_stat->nid_exp_ref_count));
358
359         /* Return -EALREADY here so that we know that the /proc
360          * entry already has been created */
361         if (old_stat != new_stat) {
362                 spin_lock(&exp->exp_lock);
363                 if (exp->exp_nid_stats) {
364                         LASSERT(exp->exp_nid_stats == old_stat);
365                         nidstat_putref(exp->exp_nid_stats);
366                 }
367                 exp->exp_nid_stats = old_stat;
368                 spin_unlock(&exp->exp_lock);
369                 GOTO(destroy_new, rc = -EALREADY);
370         }
371         /* not found - create */
372         new_stat->nid_proc = lprocfs_register(nidstr,
373                                               obd->obd_proc_exports_entry,
374                                               NULL, NULL);
375
376         if (IS_ERR(new_stat->nid_proc)) {
377                 rc = PTR_ERR(new_stat->nid_proc);
378                 new_stat->nid_proc = NULL;
379                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
380                        obd->obd_name, nidstr, rc);
381                 GOTO(destroy_new_ns, rc);
382         }
383
384         entry = lprocfs_add_simple(new_stat->nid_proc, "nodemap", new_stat,
385                                    &lprocfs_exp_nodemap_fops);
386         if (IS_ERR(entry)) {
387                 rc = PTR_ERR(entry);
388                 CWARN("Error adding the nodemap file: rc = %d\n", rc);
389                 GOTO(destroy_new_ns, rc);
390         }
391
392         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid", new_stat,
393                                    &lprocfs_exp_uuid_fops);
394         if (IS_ERR(entry)) {
395                 rc = PTR_ERR(entry);
396                 CWARN("Error adding the NID stats file: rc = %d\n", rc);
397                 GOTO(destroy_new_ns, rc);
398         }
399
400         entry = lprocfs_add_simple(new_stat->nid_proc, "hash", new_stat,
401                                    &lprocfs_exp_hash_fops);
402         if (IS_ERR(entry)) {
403                 rc = PTR_ERR(entry);
404                 CWARN("Error adding the hash file: rc = %d\n", rc);
405                 GOTO(destroy_new_ns, rc);
406         }
407
408         entry = lprocfs_add_simple(new_stat->nid_proc, "reply_data", new_stat,
409                                    &lprocfs_exp_replydata_fops);
410         if (IS_ERR(entry)) {
411                 rc = PTR_ERR(entry);
412                 CWARN("%s: Error adding the reply_data file: rc = %d\n",
413                       obd->obd_name, rc);
414                 GOTO(destroy_new_ns, rc);
415         }
416
417         spin_lock(&exp->exp_lock);
418         exp->exp_nid_stats = new_stat;
419         spin_unlock(&exp->exp_lock);
420
421         /* protect competitive add to list, not need locking on destroy */
422         spin_lock(&obd->obd_nid_lock);
423         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
424         spin_unlock(&obd->obd_nid_lock);
425
426         RETURN(0);
427
428 destroy_new_ns:
429         if (new_stat->nid_proc != NULL)
430                 lprocfs_remove(&new_stat->nid_proc);
431         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
432
433 destroy_new:
434         nidstat_putref(new_stat);
435         OBD_FREE_PTR(new_stat);
436         RETURN(rc);
437 }
438 EXPORT_SYMBOL(lprocfs_exp_setup);
439
440 int lprocfs_exp_cleanup(struct obd_export *exp)
441 {
442         struct nid_stat *stat = exp->exp_nid_stats;
443
444         if (!stat || !exp->exp_obd)
445                 RETURN(0);
446
447         nidstat_putref(exp->exp_nid_stats);
448         exp->exp_nid_stats = NULL;
449
450         return 0;
451 }
452
453 #define LPROCFS_OBD_OP_INIT(base, stats, op)                    \
454 do {                                                            \
455         unsigned int coffset = base + OBD_COUNTER_OFFSET(op);   \
456         LASSERT(coffset < stats->ls_num);                       \
457         lprocfs_counter_init(stats, coffset, 0, #op, "reqs");   \
458 } while (0)
459
460 void lprocfs_init_ops_stats(int num_private_stats, struct lprocfs_stats *stats)
461 {
462         LPROCFS_OBD_OP_INIT(num_private_stats, stats, iocontrol);
463         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_info);
464         LPROCFS_OBD_OP_INIT(num_private_stats, stats, set_info_async);
465         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setup);
466         LPROCFS_OBD_OP_INIT(num_private_stats, stats, precleanup);
467         LPROCFS_OBD_OP_INIT(num_private_stats, stats, cleanup);
468         LPROCFS_OBD_OP_INIT(num_private_stats, stats, process_config);
469         LPROCFS_OBD_OP_INIT(num_private_stats, stats, postrecov);
470         LPROCFS_OBD_OP_INIT(num_private_stats, stats, add_conn);
471         LPROCFS_OBD_OP_INIT(num_private_stats, stats, del_conn);
472         LPROCFS_OBD_OP_INIT(num_private_stats, stats, connect);
473         LPROCFS_OBD_OP_INIT(num_private_stats, stats, reconnect);
474         LPROCFS_OBD_OP_INIT(num_private_stats, stats, disconnect);
475         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_init);
476         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_fini);
477         LPROCFS_OBD_OP_INIT(num_private_stats, stats, fid_alloc);
478         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs);
479         LPROCFS_OBD_OP_INIT(num_private_stats, stats, statfs_async);
480         LPROCFS_OBD_OP_INIT(num_private_stats, stats, create);
481         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy);
482         LPROCFS_OBD_OP_INIT(num_private_stats, stats, setattr);
483         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getattr);
484         LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw);
485         LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw);
486         LPROCFS_OBD_OP_INIT(num_private_stats, stats, init_export);
487         LPROCFS_OBD_OP_INIT(num_private_stats, stats, destroy_export);
488         LPROCFS_OBD_OP_INIT(num_private_stats, stats, import_event);
489         LPROCFS_OBD_OP_INIT(num_private_stats, stats, notify);
490         LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
491         LPROCFS_OBD_OP_INIT(num_private_stats, stats, get_uuid);
492         LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
493         LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
494         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_new);
495         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_rem);
496         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_add);
497         LPROCFS_OBD_OP_INIT(num_private_stats, stats, pool_del);
498         LPROCFS_OBD_OP_INIT(num_private_stats, stats, getref);
499         LPROCFS_OBD_OP_INIT(num_private_stats, stats, putref);
500
501         CLASSERT(NUM_OBD_STATS == OBD_COUNTER_OFFSET(putref) + 1);
502 }
503 EXPORT_SYMBOL(lprocfs_init_ops_stats);
504
505 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats)
506 {
507         struct lprocfs_stats *stats;
508         unsigned int num_stats;
509         int rc, i;
510
511         LASSERT(obd->obd_stats == NULL);
512         LASSERT(obd->obd_proc_entry != NULL);
513         LASSERT(obd->obd_cntr_base == 0);
514
515         num_stats = NUM_OBD_STATS + num_private_stats;
516         stats = lprocfs_alloc_stats(num_stats, 0);
517         if (stats == NULL)
518                 return -ENOMEM;
519
520         lprocfs_init_ops_stats(num_private_stats, stats);
521
522         for (i = num_private_stats; i < num_stats; i++) {
523                 /* If this LBUGs, it is likely that an obd
524                  * operation was added to struct obd_ops in
525                  * <obd.h>, and that the corresponding line item
526                  * LPROCFS_OBD_OP_INIT(.., .., opname)
527                  * is missing from the list above. */
528                 LASSERTF(stats->ls_cnt_header[i].lc_name != NULL,
529                          "Missing obd_stat initializer obd_op "
530                          "operation at offset %d.\n", i - num_private_stats);
531         }
532         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
533         if (rc < 0) {
534                 lprocfs_free_stats(&stats);
535         } else {
536                 obd->obd_stats  = stats;
537                 obd->obd_cntr_base = num_private_stats;
538         }
539         return rc;
540 }
541 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
542
543 void lprocfs_free_obd_stats(struct obd_device *obd)
544 {
545         if (obd->obd_stats)
546                 lprocfs_free_stats(&obd->obd_stats);
547 }
548 EXPORT_SYMBOL(lprocfs_free_obd_stats);
549
550 int lprocfs_hash_seq_show(struct seq_file *m, void *data)
551 {
552         struct obd_device *obd = m->private;
553
554         if (obd == NULL)
555                 return 0;
556
557         cfs_hash_debug_header(m);
558         cfs_hash_debug_str(obd->obd_uuid_hash, m);
559         cfs_hash_debug_str(obd->obd_nid_hash, m);
560         cfs_hash_debug_str(obd->obd_nid_stats_hash, m);
561         return 0;
562 }
563 EXPORT_SYMBOL(lprocfs_hash_seq_show);
564
565 int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
566 {
567         struct obd_device *obd = m->private;
568         struct target_distribute_txn_data *tdtd;
569
570         LASSERT(obd != NULL);
571
572         seq_printf(m, "status: ");
573         if (obd->obd_max_recoverable_clients == 0) {
574                 seq_printf(m, "INACTIVE\n");
575                 goto out;
576         }
577
578         /* sampled unlocked, but really... */
579         if (obd->obd_recovering == 0) {
580                 seq_printf(m, "COMPLETE\n");
581                 seq_printf(m, "recovery_start: %lld\n",
582                            (s64)obd->obd_recovery_start);
583                 seq_printf(m, "recovery_duration: %lld\n",
584                            obd->obd_recovery_end ?
585                            obd->obd_recovery_end - obd->obd_recovery_start :
586                            ktime_get_real_seconds() - obd->obd_recovery_start);
587                 /* Number of clients that have completed recovery */
588                 seq_printf(m, "completed_clients: %d/%d\n",
589                            obd->obd_max_recoverable_clients -
590                            obd->obd_stale_clients,
591                            obd->obd_max_recoverable_clients);
592                 seq_printf(m, "replayed_requests: %d\n",
593                            obd->obd_replayed_requests);
594                 seq_printf(m, "last_transno: %lld\n",
595                            obd->obd_next_recovery_transno - 1);
596                 seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
597                            "ENABLED" : "DISABLED");
598                 seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
599                            "DISABLED" : "ENABLED");
600                 goto out;
601         }
602
603         tdtd = obd->u.obt.obt_lut->lut_tdtd;
604         if (tdtd && tdtd->tdtd_show_update_logs_retrievers) {
605                 char *buf;
606                 int size = 0;
607                 int count = 0;
608
609                 buf = tdtd->tdtd_show_update_logs_retrievers(
610                         tdtd->tdtd_show_retrievers_cbdata,
611                         &size, &count);
612                 if (count > 0) {
613                         seq_printf(m, "WAITING\n");
614                         seq_printf(m, "non-ready MDTs: %s\n",
615                                    buf ? buf : "unknown (not enough RAM)");
616                         seq_printf(m, "recovery_start: %lld\n",
617                                    (s64)obd->obd_recovery_start);
618                         seq_printf(m, "time_waited: %lld\n",
619                                    (s64)(ktime_get_real_seconds() -
620                                          obd->obd_recovery_start));
621                 }
622
623                 if (buf != NULL)
624                         OBD_FREE(buf, size);
625
626                 if (likely(count > 0))
627                         goto out;
628         }
629
630         /* recovery won't start until the clients connect */
631         if (obd->obd_recovery_start == 0) {
632                 seq_printf(m, "WAITING_FOR_CLIENTS\n");
633                 goto out;
634         }
635
636         seq_printf(m, "RECOVERING\n");
637         seq_printf(m, "recovery_start: %lld\n", (s64)obd->obd_recovery_start);
638         seq_printf(m, "time_remaining: %lld\n",
639                    ktime_get_real_seconds() >=
640                    obd->obd_recovery_start +
641                    obd->obd_recovery_timeout ? 0 :
642                    (s64)(obd->obd_recovery_start +
643                          obd->obd_recovery_timeout -
644                          ktime_get_real_seconds()));
645         seq_printf(m, "connected_clients: %d/%d\n",
646                    atomic_read(&obd->obd_connected_clients),
647                    obd->obd_max_recoverable_clients);
648         /* Number of clients that have completed recovery */
649         seq_printf(m, "req_replay_clients: %d\n",
650                    atomic_read(&obd->obd_req_replay_clients));
651         seq_printf(m, "lock_repay_clients: %d\n",
652                    atomic_read(&obd->obd_lock_replay_clients));
653         seq_printf(m, "completed_clients: %d\n",
654                    atomic_read(&obd->obd_connected_clients) -
655                    atomic_read(&obd->obd_lock_replay_clients));
656         seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
657         seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
658         seq_printf(m, "queued_requests: %d\n",
659                    obd->obd_requests_queued_for_recovery);
660         seq_printf(m, "next_transno: %lld\n",
661                    obd->obd_next_recovery_transno);
662 out:
663         return 0;
664 }
665 EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
666
667 int lprocfs_ir_factor_seq_show(struct seq_file *m, void *data)
668 {
669         struct obd_device *obd = m->private;
670
671         LASSERT(obd != NULL);
672         seq_printf(m, "%d\n", obd->obd_recovery_ir_factor);
673         return 0;
674 }
675 EXPORT_SYMBOL(lprocfs_ir_factor_seq_show);
676
677 ssize_t
678 lprocfs_ir_factor_seq_write(struct file *file, const char __user *buffer,
679                             size_t count, loff_t *off)
680 {
681         struct seq_file *m = file->private_data;
682         struct obd_device *obd = m->private;
683         int rc;
684         __s64 val;
685
686         LASSERT(obd != NULL);
687         rc = lprocfs_str_to_s64(buffer, count, &val);
688         if (rc)
689                 return rc;
690
691         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
692                 return -EINVAL;
693
694         obd->obd_recovery_ir_factor = val;
695         return count;
696 }
697 EXPORT_SYMBOL(lprocfs_ir_factor_seq_write);
698
699 int lprocfs_checksum_dump_seq_show(struct seq_file *m, void *data)
700 {
701         struct obd_device *obd = m->private;
702
703         LASSERT(obd != NULL);
704         seq_printf(m, "%d\n", obd->obd_checksum_dump);
705         return 0;
706 }
707 EXPORT_SYMBOL(lprocfs_checksum_dump_seq_show);
708
709 ssize_t
710 lprocfs_checksum_dump_seq_write(struct file *file, const char __user *buffer,
711                             size_t count, loff_t *off)
712 {
713         struct seq_file *m = file->private_data;
714         struct obd_device *obd = m->private;
715         int rc;
716         __s64 val;
717
718         LASSERT(obd != NULL);
719         rc = lprocfs_str_to_s64(buffer, count, &val);
720         if (rc)
721                 return rc;
722
723         obd->obd_checksum_dump = !!val;
724         return count;
725 }
726 EXPORT_SYMBOL(lprocfs_checksum_dump_seq_write);
727
728 int lprocfs_recovery_time_soft_seq_show(struct seq_file *m, void *data)
729 {
730         struct obd_device *obd = m->private;
731
732         LASSERT(obd != NULL);
733         seq_printf(m, "%llu\n", obd->obd_recovery_timeout);
734         return 0;
735 }
736 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_show);
737
738 ssize_t
739 lprocfs_recovery_time_soft_seq_write(struct file *file,
740                                      const char __user *buffer,
741                                      size_t count, loff_t *off)
742 {
743         struct seq_file *m = file->private_data;
744         struct obd_device *obd = m->private;
745         int rc;
746         __s64 val;
747
748         LASSERT(obd != NULL);
749         rc = lprocfs_str_to_s64(buffer, count, &val);
750         if (rc)
751                 return rc;
752         if (val < 0 || val > INT_MAX)
753                 return -ERANGE;
754
755         obd->obd_recovery_timeout = val;
756         return count;
757 }
758 EXPORT_SYMBOL(lprocfs_recovery_time_soft_seq_write);
759
760 int lprocfs_recovery_time_hard_seq_show(struct seq_file *m, void *data)
761 {
762         struct obd_device *obd = m->private;
763
764         LASSERT(obd != NULL);
765         seq_printf(m, "%lld\n", obd->obd_recovery_time_hard);
766         return 0;
767 }
768 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_show);
769
770 ssize_t
771 lprocfs_recovery_time_hard_seq_write(struct file *file,
772                                      const char __user *buffer,
773                                      size_t count, loff_t *off)
774 {
775         struct seq_file *m = file->private_data;
776         struct obd_device *obd = m->private;
777         int rc;
778         __s64 val;
779
780         LASSERT(obd != NULL);
781         rc = lprocfs_str_to_s64(buffer, count, &val);
782         if (rc)
783                 return rc;
784         if (val < 0 || val > INT_MAX)
785                 return -ERANGE;
786
787         obd->obd_recovery_time_hard = val;
788         return count;
789 }
790 EXPORT_SYMBOL(lprocfs_recovery_time_hard_seq_write);
791
792 int lprocfs_target_instance_seq_show(struct seq_file *m, void *data)
793 {
794         struct obd_device *obd = m->private;
795         struct obd_device_target *target = &obd->u.obt;
796
797         LASSERT(obd != NULL);
798         LASSERT(target->obt_magic == OBT_MAGIC);
799         seq_printf(m, "%u\n", obd->u.obt.obt_instance);
800         return 0;
801 }
802 EXPORT_SYMBOL(lprocfs_target_instance_seq_show);
803
804 #endif /* CONFIG_PROC_FS*/