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