Whamcloud - gitweb
8584b1baefac7d5b28c75816750a9664b6b388ee
[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, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/obdclass/lprocfs_status_server.c
32  */
33
34 #define DEBUG_SUBSYSTEM S_CLASS
35
36 #include <linux/kobject.h>
37 #include <linux/sysfs.h>
38
39 #include <obd_class.h>
40 #include <lprocfs_status.h>
41 #include <lustre_nodemap.h>
42
43 #define MAX_STRING_SIZE 128
44
45 struct dentry *ldebugfs_add_symlink(const char *name, const char *target,
46                                     const char *format, ...)
47 {
48         struct dentry *entry = NULL;
49         struct dentry *parent;
50         struct qstr dname;
51         va_list ap;
52         char *dest;
53
54         if (!target || !format)
55                 return NULL;
56
57         dname.name = target;
58         dname.len = strlen(dname.name);
59         dname.hash = ll_full_name_hash(debugfs_lustre_root,
60                                        dname.name, dname.len);
61         parent = d_lookup(debugfs_lustre_root, &dname);
62         if (!parent)
63                 return NULL;
64
65         OBD_ALLOC_WAIT(dest, MAX_STRING_SIZE + 1);
66         if (!dest)
67                 goto no_entry;
68
69         va_start(ap, format);
70         vsnprintf(dest, MAX_STRING_SIZE, format, ap);
71         va_end(ap);
72
73         entry = debugfs_create_symlink(name, parent, dest);
74
75         OBD_FREE(dest, MAX_STRING_SIZE + 1);
76 no_entry:
77         dput(parent);
78         return entry;
79 }
80 EXPORT_SYMBOL(ldebugfs_add_symlink);
81
82 #ifdef CONFIG_PROC_FS
83
84 int lprocfs_evict_client_open(struct inode *inode, struct file *f)
85 {
86         struct obd_device *obd = PDE_DATA(file_inode(f));
87
88         atomic_inc(&obd->obd_evict_inprogress);
89         return 0;
90 }
91
92 int lprocfs_evict_client_release(struct inode *inode, struct file *f)
93 {
94         struct obd_device *obd = PDE_DATA(file_inode(f));
95
96         atomic_dec(&obd->obd_evict_inprogress);
97         wake_up(&obd->obd_evict_inprogress_waitq);
98
99         return 0;
100 }
101
102 #define BUFLEN (UUID_MAX + 5)
103
104 ssize_t
105 lprocfs_evict_client_seq_write(struct file *file, const char __user *buffer,
106                                size_t count, loff_t *off)
107 {
108         struct seq_file *m = file->private_data;
109         struct obd_device *obd = m->private;
110         char *tmpbuf, *kbuf;
111
112         OBD_ALLOC(kbuf, BUFLEN);
113         if (kbuf == NULL)
114                 return -ENOMEM;
115
116         /*
117          * OBD_ALLOC() will zero kbuf, but we only copy BUFLEN - 1
118          * bytes into kbuf, to ensure that the string is NUL-terminated.
119          * UUID_MAX should include a trailing NUL already.
120          */
121         if (copy_from_user(kbuf, buffer,
122                            min_t(unsigned long, BUFLEN - 1, count))) {
123                 count = -EFAULT;
124                 goto out;
125         }
126         tmpbuf = skip_spaces(kbuf);
127         tmpbuf = strsep(&tmpbuf, " \t\n\f\v\r");
128         class_incref(obd, __func__, current);
129
130         if (strncmp(tmpbuf, "nid:", 4) == 0)
131                 obd_export_evict_by_nid(obd, tmpbuf + 4);
132         else if (strncmp(tmpbuf, "uuid:", 5) == 0)
133                 obd_export_evict_by_uuid(obd, tmpbuf + 5);
134         else
135                 obd_export_evict_by_uuid(obd, tmpbuf);
136
137         class_decref(obd, __func__, current);
138
139 out:
140         OBD_FREE(kbuf, BUFLEN);
141         return count;
142 }
143 EXPORT_SYMBOL(lprocfs_evict_client_seq_write);
144
145 #undef BUFLEN
146
147 ssize_t num_exports_show(struct kobject *kobj, struct attribute *attr,
148                          char *buf)
149 {
150         struct obd_device *obd = container_of(kobj, struct obd_device,
151                                               obd_kset.kobj);
152
153         return scnprintf(buf, PAGE_SIZE, "%u\n", obd->obd_num_exports);
154 }
155 EXPORT_SYMBOL(num_exports_show);
156
157 static int obd_export_flags2str(struct obd_export *exp, struct seq_file *m)
158 {
159         bool first = true;
160
161         flag2str(exp, failed);
162         flag2str(exp, in_recovery);
163         flag2str(exp, disconnected);
164         flag2str(exp, connecting);
165         flag2str(exp, no_recovery);
166
167         return 0;
168 }
169
170 static int
171 lprocfs_exp_print_export_seq(struct obd_export *exp, void *cb_data)
172 {
173         struct seq_file         *m = cb_data;
174         struct obd_device       *obd;
175         struct obd_connect_data *ocd;
176
177         LASSERT(exp != NULL);
178         if (exp->exp_nid_stats == NULL)
179                 goto out;
180         obd = exp->exp_obd;
181         ocd = &exp->exp_connect_data;
182
183         seq_printf(m, "%s:\n"
184                    "    name: %s\n"
185                    "    client: %s\n"
186                    "    connect_flags: [ ",
187                    obd_uuid2str(&exp->exp_client_uuid),
188                    obd->obd_name,
189                    obd_export_nid2str(exp));
190         obd_connect_seq_flags2str(m, ocd->ocd_connect_flags,
191                                   ocd->ocd_connect_flags2, ", ");
192         seq_printf(m, " ]\n");
193         obd_connect_data_seqprint(m, ocd);
194         seq_printf(m, "    export_flags: [ ");
195         obd_export_flags2str(exp, m);
196         seq_printf(m, " ]\n");
197
198         if (obd->obd_type &&
199             strcmp(obd->obd_type->typ_name, "obdfilter") == 0) {
200                 struct filter_export_data *fed = &exp->exp_filter_data;
201
202                 seq_printf(m, "    grant:\n");
203                 seq_printf(m, "       granted: %ld\n",
204                         fed->fed_ted.ted_grant);
205                 seq_printf(m, "       dirty: %ld\n",
206                         fed->fed_ted.ted_dirty);
207                 seq_printf(m, "       pending: %ld\n",
208                         fed->fed_ted.ted_pending);
209         }
210
211 out:
212         return 0;
213 }
214
215 /**
216  * RPC connections are composed of an import and an export. Using the
217  * lctl utility we can extract important information about the state.
218  * The lprocfs_exp_export_seq_show routine displays the state information
219  * for the export.
220  *
221  * \param[in] m         seq file
222  * \param[in] data      unused
223  *
224  * \retval              0 on success
225  *
226  * The format of the export state information is like:
227  * a793e354-49c0-aa11-8c4f-a4f2b1a1a92b:
228  *     name: MGS
229  *     client: 10.211.55.10@tcp
230  *     connect_flags: [ version, barrier, adaptive_timeouts, ... ]
231  *     connect_data:
232  *        flags: 0x2000011005002020
233  *        instance: 0
234  *        target_version: 2.10.51.0
235  *        export_flags: [ ... ]
236  *
237  */
238 static int lprocfs_exp_export_seq_show(struct seq_file *m, void *data)
239 {
240         struct nid_stat *stats = m->private;
241
242         return obd_nid_export_for_each(stats->nid_obd, stats->nid,
243                                        lprocfs_exp_print_export_seq, m);
244 }
245 LPROC_SEQ_FOPS_RO(lprocfs_exp_export);
246
247 static void lprocfs_free_client_stats(struct nid_stat *client_stat)
248 {
249         CDEBUG(D_CONFIG, "stat %p - data %p/%p\n", client_stat,
250                client_stat->nid_proc, client_stat->nid_stats);
251
252         LASSERTF(atomic_read(&client_stat->nid_exp_ref_count) == 0,
253                  "nid %s:count %d\n", libcfs_nid2str(client_stat->nid),
254                  atomic_read(&client_stat->nid_exp_ref_count));
255
256         if (client_stat->nid_proc)
257                 lprocfs_remove(&client_stat->nid_proc);
258
259         if (client_stat->nid_stats)
260                 lprocfs_free_stats(&client_stat->nid_stats);
261
262         if (client_stat->nid_ldlm_stats)
263                 lprocfs_free_stats(&client_stat->nid_ldlm_stats);
264
265         OBD_FREE_PTR(client_stat);
266 }
267
268 void lprocfs_free_per_client_stats(struct obd_device *obd)
269 {
270         struct cfs_hash *hash = obd->obd_nid_stats_hash;
271         struct nid_stat *stat;
272         ENTRY;
273
274         /* we need extra list - because hash_exit called to early */
275         /* not need locking because all clients is died */
276         while (!list_empty(&obd->obd_nid_stats)) {
277                 stat = list_entry(obd->obd_nid_stats.next,
278                                   struct nid_stat, nid_list);
279                 list_del_init(&stat->nid_list);
280                 cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
281                 lprocfs_free_client_stats(stat);
282         }
283         EXIT;
284 }
285 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
286
287 static int
288 lprocfs_exp_print_nodemap_seq(struct obd_export *exp, void *cb_data)
289 {
290         struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap;
291         struct seq_file *m = cb_data;
292
293         if (nodemap)
294                 seq_printf(m, "%s\n", nodemap->nm_name);
295         return 0;
296 }
297
298 static int
299 lprocfs_exp_nodemap_seq_show(struct seq_file *m, void *data)
300 {
301         struct nid_stat *stats = m->private;
302
303         return obd_nid_export_for_each(stats->nid_obd, stats->nid,
304                                        lprocfs_exp_print_nodemap_seq, m);
305 }
306 LPROC_SEQ_FOPS_RO(lprocfs_exp_nodemap);
307
308 static int
309 lprocfs_exp_print_uuid_seq(struct obd_export *exp, void *cb_data)
310 {
311         struct seq_file *m = cb_data;
312
313         if (exp->exp_nid_stats)
314                 seq_printf(m, "%s\n", obd_uuid2str(&exp->exp_client_uuid));
315         return 0;
316 }
317
318 static int lprocfs_exp_uuid_seq_show(struct seq_file *m, void *data)
319 {
320         struct nid_stat *stats = m->private;
321
322         return obd_nid_export_for_each(stats->nid_obd, stats->nid,
323                                        lprocfs_exp_print_uuid_seq, m);
324 }
325 LPROC_SEQ_FOPS_RO(lprocfs_exp_uuid);
326
327 #define HASH_NAME_LEN   16
328
329 static void ldebugfs_rhash_seq_show(const char *name, struct rhashtable *ht,
330                                     struct seq_file *m)
331 {
332         unsigned int max_size = ht->p.max_size ? ht->p.max_size : UINT_MAX;
333         struct bucket_table *tbl;
334         int dist[8] = { 0, };
335         int maxdep = 0;
336         int i;
337
338         rcu_read_lock();
339         tbl = rht_dereference(ht->tbl, ht);
340         for (i = 0; i < tbl->size; i++) {
341                 struct rhash_head *pos;
342                 int count = 0;
343
344                 rht_for_each(pos, tbl, i)
345                         count++;
346
347                 if (count)
348                         maxdep = max(maxdep, count);
349
350                 dist[min(fls(count), 7)]++;
351         }
352
353         seq_printf(m, "%-*s %5d %5d %10u %d.%03d 0.300 0.750 0x%03x %7d %7d %7d ",
354                    HASH_NAME_LEN, name, tbl->size, ht->p.min_size, max_size,
355                    atomic_read(&ht->nelems) / tbl->size,
356                    atomic_read(&ht->nelems) * 1000 / tbl->size,
357                    ht->p.automatic_shrinking, 0,
358                    atomic_read(&ht->nelems), maxdep);
359         rcu_read_unlock();
360
361         for (i = 0; i < 8; i++)
362                 seq_printf(m, "%d%c",  dist[i], (i == 7) ? '\n' : '/');
363 }
364
365 static int
366 lprocfs_exp_print_hash_seq(struct obd_export *exp, void *cb_data)
367
368 {
369         struct obd_device *obd = exp->exp_obd;
370         struct seq_file *m = cb_data;
371
372         if (exp->exp_lock_hash != NULL) {
373                 seq_printf(m, "%-*s   cur   min        max theta t-min t-max flags rehash   count distribution\n",
374                            HASH_NAME_LEN, "name");
375                 ldebugfs_rhash_seq_show("NID_HASH", &obd->obd_nid_hash.ht, m);
376         }
377         return 0;
378 }
379
380 static int lprocfs_exp_hash_seq_show(struct seq_file *m, void *data)
381 {
382         struct nid_stat *stats = m->private;
383
384         return obd_nid_export_for_each(stats->nid_obd, stats->nid,
385                                        lprocfs_exp_print_hash_seq, m);
386 }
387 LPROC_SEQ_FOPS_RO(lprocfs_exp_hash);
388
389 int lprocfs_exp_print_replydata_seq(struct obd_export *exp, void *cb_data)
390
391 {
392         struct seq_file *m = cb_data;
393         struct tg_export_data *ted = &exp->exp_target_data;
394
395         seq_printf(m, "reply_cnt: %d\n"
396                    "reply_max: %d\n"
397                    "reply_released_by_xid: %d\n"
398                    "reply_released_by_tag: %d\n\n",
399                    ted->ted_reply_cnt,
400                    ted->ted_reply_max,
401                    ted->ted_release_xid,
402                    ted->ted_release_tag);
403         return 0;
404 }
405
406 int lprocfs_exp_replydata_seq_show(struct seq_file *m, void *data)
407 {
408         struct nid_stat *stats = m->private;
409
410         return obd_nid_export_for_each(stats->nid_obd, stats->nid,
411                                        lprocfs_exp_print_replydata_seq, m);
412 }
413 LPROC_SEQ_FOPS_RO(lprocfs_exp_replydata);
414
415 int lprocfs_exp_print_fmd_count_seq(struct obd_export *exp, void *cb_data)
416 {
417         struct seq_file *m = cb_data;
418         struct tg_export_data *ted = &exp->exp_target_data;
419
420         seq_printf(m, "%d\n", ted->ted_fmd_count);
421
422         return 0;
423 }
424
425 int lprocfs_exp_fmd_count_seq_show(struct seq_file *m, void *data)
426 {
427         struct nid_stat *stats = m->private;
428
429         return obd_nid_export_for_each(stats->nid_obd, stats->nid,
430                                        lprocfs_exp_print_fmd_count_seq, m);
431 }
432 LPROC_SEQ_FOPS_RO(lprocfs_exp_fmd_count);
433
434 int lprocfs_nid_stats_clear_seq_show(struct seq_file *m, void *data)
435 {
436         seq_puts(m, "Write into this file to clear all nid stats and stale nid entries\n");
437         return 0;
438 }
439 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_show);
440
441 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
442 {
443         struct nid_stat *stat = obj;
444         ENTRY;
445
446         CDEBUG(D_INFO, "refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
447         if (atomic_read(&stat->nid_exp_ref_count) == 1) {
448                 /* object has only hash references. */
449                 spin_lock(&stat->nid_obd->obd_nid_lock);
450                 list_move(&stat->nid_list, data);
451                 spin_unlock(&stat->nid_obd->obd_nid_lock);
452                 RETURN(1);
453         }
454         /* we has reference to object - only clear data*/
455         if (stat->nid_stats)
456                 lprocfs_clear_stats(stat->nid_stats);
457
458         RETURN(0);
459 }
460
461 ssize_t
462 lprocfs_nid_stats_clear_seq_write(struct file *file, const char __user *buffer,
463                                         size_t count, loff_t *off)
464 {
465         struct seq_file *m = file->private_data;
466         struct obd_device *obd = m->private;
467         struct nid_stat *client_stat;
468         LIST_HEAD(free_list);
469
470         cfs_hash_cond_del(obd->obd_nid_stats_hash,
471                           lprocfs_nid_stats_clear_write_cb, &free_list);
472
473         while (!list_empty(&free_list)) {
474                 client_stat = list_entry(free_list.next, struct nid_stat,
475                                          nid_list);
476                 list_del_init(&client_stat->nid_list);
477                 lprocfs_free_client_stats(client_stat);
478         }
479         return count;
480 }
481 EXPORT_SYMBOL(lprocfs_nid_stats_clear_seq_write);
482
483 int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid)
484 {
485         struct nid_stat *new_stat, *old_stat;
486         struct obd_device *obd = NULL;
487         struct proc_dir_entry *entry;
488         char nidstr[LNET_NIDSTR_SIZE];
489         int rc = 0;
490         ENTRY;
491
492         if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
493             !exp->exp_obd->obd_nid_stats_hash)
494                 RETURN(-EINVAL);
495
496         /* not test against zero because eric say:
497          * You may only test nid against another nid, or LNET_NID_ANY.
498          * Anything else is nonsense.*/
499         if (nid == NULL || *nid == LNET_NID_ANY)
500                 RETURN(-EALREADY);
501
502         libcfs_nid2str_r(*nid, nidstr, sizeof(nidstr));
503
504         spin_lock(&exp->exp_lock);
505         if (exp->exp_nid_stats != NULL) {
506                 spin_unlock(&exp->exp_lock);
507                 RETURN(-EALREADY);
508         }
509         spin_unlock(&exp->exp_lock);
510
511         obd = exp->exp_obd;
512
513         CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash);
514
515         OBD_ALLOC_PTR(new_stat);
516         if (new_stat == NULL)
517                 RETURN(-ENOMEM);
518
519         new_stat->nid     = *nid;
520         new_stat->nid_obd = exp->exp_obd;
521         /* we need set default refcount to 1 to balance obd_disconnect */
522         atomic_set(&new_stat->nid_exp_ref_count, 1);
523
524         old_stat = cfs_hash_findadd_unique(obd->obd_nid_stats_hash,
525                                            nid, &new_stat->nid_hash);
526         CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
527                old_stat, nidstr, atomic_read(&old_stat->nid_exp_ref_count));
528
529         /* Return -EALREADY here so that we know that the /proc
530          * entry already has been created */
531         if (old_stat != new_stat) {
532                 spin_lock(&exp->exp_lock);
533                 if (exp->exp_nid_stats) {
534                         LASSERT(exp->exp_nid_stats == old_stat);
535                         nidstat_putref(exp->exp_nid_stats);
536                 }
537                 exp->exp_nid_stats = old_stat;
538                 spin_unlock(&exp->exp_lock);
539                 GOTO(destroy_new, rc = -EALREADY);
540         }
541         /* not found - create */
542         new_stat->nid_proc = lprocfs_register(nidstr,
543                                               obd->obd_proc_exports_entry,
544                                               NULL, NULL);
545
546         if (IS_ERR(new_stat->nid_proc)) {
547                 rc = PTR_ERR(new_stat->nid_proc);
548                 new_stat->nid_proc = NULL;
549                 CERROR("%s: cannot create proc entry for export %s: rc = %d\n",
550                        obd->obd_name, nidstr, rc);
551                 GOTO(destroy_new_ns, rc);
552         }
553
554         entry = lprocfs_add_simple(new_stat->nid_proc, "nodemap", new_stat,
555                                    &lprocfs_exp_nodemap_fops);
556         if (IS_ERR(entry)) {
557                 rc = PTR_ERR(entry);
558                 CWARN("%s: error adding the nodemap file: rc = %d\n",
559                       obd->obd_name, rc);
560                 GOTO(destroy_new_ns, rc);
561         }
562
563         entry = lprocfs_add_simple(new_stat->nid_proc, "uuid", new_stat,
564                                    &lprocfs_exp_uuid_fops);
565         if (IS_ERR(entry)) {
566                 rc = PTR_ERR(entry);
567                 CWARN("%s: error adding the NID stats file: rc = %d\n",
568                       obd->obd_name, rc);
569                 GOTO(destroy_new_ns, rc);
570         }
571
572         entry = lprocfs_add_simple(new_stat->nid_proc, "hash", new_stat,
573                                    &lprocfs_exp_hash_fops);
574         if (IS_ERR(entry)) {
575                 rc = PTR_ERR(entry);
576                 CWARN("%s: error adding the hash file: rc = %d\n",
577                       obd->obd_name, rc);
578                 GOTO(destroy_new_ns, rc);
579         }
580
581         entry = lprocfs_add_simple(new_stat->nid_proc, "export",
582                                    new_stat, &lprocfs_exp_export_fops);
583         if (IS_ERR(entry)) {
584                 rc = PTR_ERR(entry);
585                 CWARN("%s: error adding the export file: rc = %d\n",
586                       obd->obd_name, rc);
587                 GOTO(destroy_new_ns, rc);
588         }
589
590         entry = lprocfs_add_simple(new_stat->nid_proc, "reply_data", new_stat,
591                                    &lprocfs_exp_replydata_fops);
592         if (IS_ERR(entry)) {
593                 rc = PTR_ERR(entry);
594                 CWARN("%s: error adding the reply_data file: rc = %d\n",
595                       obd->obd_name, rc);
596                 GOTO(destroy_new_ns, rc);
597         }
598
599         entry = lprocfs_add_simple(new_stat->nid_proc, "fmd_count", new_stat,
600                                    &lprocfs_exp_fmd_count_fops);
601         if (IS_ERR(entry)) {
602                 rc = PTR_ERR(entry);
603                 CWARN("%s: error adding the fmd_count file: rc = %d\n",
604                       obd->obd_name, rc);
605                 GOTO(destroy_new_ns, rc);
606         }
607
608         spin_lock(&exp->exp_lock);
609         exp->exp_nid_stats = new_stat;
610         spin_unlock(&exp->exp_lock);
611
612         /* protect competitive add to list, not need locking on destroy */
613         spin_lock(&obd->obd_nid_lock);
614         list_add(&new_stat->nid_list, &obd->obd_nid_stats);
615         spin_unlock(&obd->obd_nid_lock);
616
617         RETURN(0);
618
619 destroy_new_ns:
620         if (new_stat->nid_proc != NULL)
621                 lprocfs_remove(&new_stat->nid_proc);
622         cfs_hash_del(obd->obd_nid_stats_hash, nid, &new_stat->nid_hash);
623
624 destroy_new:
625         nidstat_putref(new_stat);
626         OBD_FREE_PTR(new_stat);
627         RETURN(rc);
628 }
629 EXPORT_SYMBOL(lprocfs_exp_setup);
630
631 int lprocfs_exp_cleanup(struct obd_export *exp)
632 {
633         struct nid_stat *stat = exp->exp_nid_stats;
634
635         if (!stat || !exp->exp_obd)
636                 RETURN(0);
637
638         nidstat_putref(exp->exp_nid_stats);
639         exp->exp_nid_stats = NULL;
640
641         return 0;
642 }
643
644 int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned int num_stats)
645 {
646         struct lprocfs_stats *stats;
647         int rc;
648
649         LASSERT(obd->obd_stats == NULL);
650         LASSERT(obd->obd_proc_entry != NULL);
651
652         stats = lprocfs_alloc_stats(num_stats, 0);
653         if (stats == NULL)
654                 return -ENOMEM;
655
656         rc = lprocfs_register_stats(obd->obd_proc_entry, "stats", stats);
657         if (rc < 0)
658                 lprocfs_free_stats(&stats);
659         else
660                 obd->obd_stats = stats;
661
662         return rc;
663 }
664 EXPORT_SYMBOL(lprocfs_alloc_obd_stats);
665
666 void lprocfs_free_obd_stats(struct obd_device *obd)
667 {
668         if (obd->obd_stats)
669                 lprocfs_free_stats(&obd->obd_stats);
670 }
671 EXPORT_SYMBOL(lprocfs_free_obd_stats);
672
673 int lprocfs_hash_seq_show(struct seq_file *m, void *data)
674 {
675         struct obd_device *obd = m->private;
676
677         if (obd == NULL)
678                 return 0;
679
680         /* header for rhashtable state */
681         seq_printf(m, "%-*s   cur   min        max theta t-min t-max flags  rehash   count  maxdep distribution\n",
682                    HASH_NAME_LEN, "name");
683         ldebugfs_rhash_seq_show("UUID_HASH", &obd->obd_uuid_hash, m);
684         ldebugfs_rhash_seq_show("NID_HASH", &obd->obd_nid_hash.ht, m);
685
686         cfs_hash_debug_header(m);
687         cfs_hash_debug_str(obd->obd_nid_stats_hash, m);
688         return 0;
689 }
690 EXPORT_SYMBOL(lprocfs_hash_seq_show);
691
692 int lprocfs_recovery_status_seq_show(struct seq_file *m, void *data)
693 {
694         struct obd_device *obd = m->private;
695         struct target_distribute_txn_data *tdtd;
696
697         LASSERT(obd != NULL);
698
699         seq_printf(m, "status: ");
700         if (atomic_read(&obd->obd_max_recoverable_clients) == 0) {
701                 seq_printf(m, "INACTIVE\n");
702                 goto out;
703         }
704
705         /* There is gap between client data read from storage and setting
706          * obd_recovering so check obd_recovery_end as well to make sure
707          * recovery is really finished
708          */
709         if (obd->obd_recovery_end > 0 && !obd->obd_recovering) {
710                 seq_printf(m, "COMPLETE\n");
711                 seq_printf(m, "recovery_start: %lld\n",
712                            (s64)ktime_get_real_seconds() -
713                            (ktime_get_seconds() - obd->obd_recovery_start));
714                 seq_printf(m, "recovery_duration: %lld\n",
715                            obd->obd_recovery_end ?
716                            obd->obd_recovery_end - obd->obd_recovery_start :
717                            ktime_get_seconds() - obd->obd_recovery_start);
718                 /* Number of clients that have completed recovery */
719                 seq_printf(m, "completed_clients: %d/%d\n",
720                            atomic_read(&obd->obd_max_recoverable_clients) -
721                            obd->obd_stale_clients,
722                            atomic_read(&obd->obd_max_recoverable_clients));
723                 seq_printf(m, "replayed_requests: %d\n",
724                            obd->obd_replayed_requests);
725                 seq_printf(m, "last_transno: %lld\n",
726                            obd->obd_next_recovery_transno - 1);
727                 seq_printf(m, "VBR: %s\n", obd->obd_version_recov ?
728                            "ENABLED" : "DISABLED");
729                 seq_printf(m, "IR: %s\n", obd->obd_no_ir ?
730                            "DISABLED" : "ENABLED");
731                 goto out;
732         }
733
734         tdtd = obd->u.obt.obt_lut->lut_tdtd;
735         if (tdtd && tdtd->tdtd_show_update_logs_retrievers) {
736                 char *buf;
737                 int size = 0;
738                 int count = 0;
739
740                 buf = tdtd->tdtd_show_update_logs_retrievers(
741                         tdtd->tdtd_show_retrievers_cbdata,
742                         &size, &count);
743                 if (count > 0) {
744                         seq_printf(m, "WAITING\n");
745                         seq_printf(m, "non-ready MDTs: %s\n",
746                                    buf ? buf : "unknown (not enough RAM)");
747                         seq_printf(m, "recovery_start: %lld\n",
748                                    (s64)ktime_get_real_seconds() -
749                                    (ktime_get_seconds() -
750                                     obd->obd_recovery_start));
751                         seq_printf(m, "time_waited: %lld\n",
752                                    (s64)(ktime_get_seconds() -
753                                          obd->obd_recovery_start));
754                 }
755
756                 if (buf != NULL)
757                         OBD_FREE(buf, size);
758
759                 if (likely(count > 0))
760                         goto out;
761         }
762
763         /* recovery won't start until the clients connect */
764         if (obd->obd_recovery_start == 0) {
765                 seq_printf(m, "WAITING_FOR_CLIENTS\n");
766                 goto out;
767         }
768
769         seq_printf(m, "RECOVERING\n");
770         seq_printf(m, "recovery_start: %lld\n", (s64)ktime_get_real_seconds() -
771                    (ktime_get_seconds() - obd->obd_recovery_start));
772         seq_printf(m, "time_remaining: %lld\n",
773                    ktime_get_seconds() >=
774                    obd->obd_recovery_start +
775                    obd->obd_recovery_timeout ? 0 :
776                    (s64)(obd->obd_recovery_start +
777                          obd->obd_recovery_timeout -
778                          ktime_get_seconds()));
779         seq_printf(m, "connected_clients: %d/%d\n",
780                    atomic_read(&obd->obd_connected_clients),
781                    atomic_read(&obd->obd_max_recoverable_clients));
782         /* Number of clients that have completed recovery */
783         seq_printf(m, "req_replay_clients: %d\n",
784                    atomic_read(&obd->obd_req_replay_clients));
785         seq_printf(m, "lock_repay_clients: %d\n",
786                    atomic_read(&obd->obd_lock_replay_clients));
787         seq_printf(m, "completed_clients: %d\n",
788                    atomic_read(&obd->obd_connected_clients) -
789                    atomic_read(&obd->obd_lock_replay_clients));
790         seq_printf(m, "evicted_clients: %d\n", obd->obd_stale_clients);
791         seq_printf(m, "replayed_requests: %d\n", obd->obd_replayed_requests);
792         seq_printf(m, "queued_requests: %d\n",
793                    obd->obd_requests_queued_for_recovery);
794         seq_printf(m, "next_transno: %lld\n",
795                    obd->obd_next_recovery_transno);
796 out:
797         return 0;
798 }
799 EXPORT_SYMBOL(lprocfs_recovery_status_seq_show);
800
801 ssize_t ir_factor_show(struct kobject *kobj, struct attribute *attr,
802                        char *buf)
803 {
804         struct obd_device *obd = container_of(kobj, struct obd_device,
805                                               obd_kset.kobj);
806
807         return scnprintf(buf, PAGE_SIZE, "%d\n", obd->obd_recovery_ir_factor);
808 }
809 EXPORT_SYMBOL(ir_factor_show);
810
811 ssize_t ir_factor_store(struct kobject *kobj, struct attribute *attr,
812                         const char *buffer, size_t count)
813 {
814         struct obd_device *obd = container_of(kobj, struct obd_device,
815                                               obd_kset.kobj);
816         int val;
817         int rc;
818
819         rc = kstrtoint(buffer, 10, &val);
820         if (rc)
821                 return rc;
822
823         if (val < OBD_IR_FACTOR_MIN || val > OBD_IR_FACTOR_MAX)
824                 return -EINVAL;
825
826         obd->obd_recovery_ir_factor = val;
827         return count;
828 }
829 EXPORT_SYMBOL(ir_factor_store);
830
831 int lprocfs_checksum_dump_seq_show(struct seq_file *m, void *data)
832 {
833         struct obd_device *obd = m->private;
834
835         LASSERT(obd != NULL);
836         seq_printf(m, "%d\n", obd->obd_checksum_dump);
837         return 0;
838 }
839 EXPORT_SYMBOL(lprocfs_checksum_dump_seq_show);
840
841 ssize_t
842 lprocfs_checksum_dump_seq_write(struct file *file, const char __user *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         bool val;
848         int rc;
849
850         LASSERT(obd != NULL);
851         rc = kstrtobool_from_user(buffer, count, &val);
852         if (rc)
853                 return rc;
854
855         obd->obd_checksum_dump = val;
856         return count;
857 }
858 EXPORT_SYMBOL(lprocfs_checksum_dump_seq_write);
859
860 ssize_t recovery_time_soft_show(struct kobject *kobj, struct attribute *attr,
861                                 char *buf)
862 {
863         struct obd_device *obd = container_of(kobj, struct obd_device,
864                                               obd_kset.kobj);
865
866         return scnprintf(buf, PAGE_SIZE, "%d\n", obd->obd_recovery_timeout);
867 }
868 EXPORT_SYMBOL(recovery_time_soft_show);
869
870 ssize_t recovery_time_soft_store(struct kobject *kobj,
871                                  struct attribute *attr,
872                                  const char *buffer, size_t count)
873 {
874         struct obd_device *obd = container_of(kobj, struct obd_device,
875                                               obd_kset.kobj);
876         unsigned int val;
877         int rc;
878
879         rc = kstrtouint(buffer, 0, &val);
880         if (rc)
881                 return rc;
882
883         obd->obd_recovery_timeout = val;
884         return count;
885 }
886 EXPORT_SYMBOL(recovery_time_soft_store);
887
888 ssize_t recovery_time_hard_show(struct kobject *kobj, struct attribute *attr,
889                                 char *buf)
890 {
891         struct obd_device *obd = container_of(kobj, struct obd_device,
892                                               obd_kset.kobj);
893
894         return scnprintf(buf, PAGE_SIZE, "%d\n", obd->obd_recovery_time_hard);
895 }
896 EXPORT_SYMBOL(recovery_time_hard_show);
897
898 ssize_t recovery_time_hard_store(struct kobject *kobj,
899                                  struct attribute *attr,
900                                  const char *buffer, size_t count)
901 {
902         struct obd_device *obd = container_of(kobj, struct obd_device,
903                                               obd_kset.kobj);
904         unsigned int val;
905         int rc;
906
907         rc = kstrtouint(buffer, 0, &val);
908         if (rc)
909                 return rc;
910
911         obd->obd_recovery_time_hard = val;
912         return count;
913 }
914 EXPORT_SYMBOL(recovery_time_hard_store);
915
916 ssize_t instance_show(struct kobject *kobj, struct attribute *attr,
917                       char *buf)
918 {
919         struct obd_device *obd = container_of(kobj, struct obd_device,
920                                               obd_kset.kobj);
921         struct obd_device_target *target = &obd->u.obt;
922
923         LASSERT(target->obt_magic == OBT_MAGIC);
924         return scnprintf(buf, PAGE_SIZE, "%u\n", obd->u.obt.obt_instance);
925 }
926 EXPORT_SYMBOL(instance_show);
927
928 #endif /* CONFIG_PROC_FS*/