Whamcloud - gitweb
b=21574 define ptlrpc_pinger_commit_expected for liblustre
[fs/lustre-release.git] / lustre / obdfilter / lproc_obdfilter.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36 #define DEBUG_SUBSYSTEM S_CLASS
37
38 #include <linux/version.h>
39 #include <lprocfs_status.h>
40 #include <obd.h>
41 #include <linux/seq_file.h>
42 #include <linux/version.h>
43
44 #include "filter_internal.h"
45
46 #ifdef LPROCFS
47 static int lprocfs_filter_rd_groups(char *page, char **start, off_t off,
48                                     int count, int *eof, void *data)
49 {
50         *eof = 1;
51         return snprintf(page, count, "%u\n", FILTER_GROUPS);
52 }
53
54 static int lprocfs_filter_rd_tot_dirty(char *page, char **start, off_t off,
55                                        int count, int *eof, void *data)
56 {
57         struct obd_device *obd = (struct obd_device *)data;
58
59         LASSERT(obd != NULL);
60         *eof = 1;
61         return snprintf(page, count, LPU64"\n", obd->u.filter.fo_tot_dirty);
62 }
63
64 static int lprocfs_filter_rd_tot_granted(char *page, char **start, off_t off,
65                                          int count, int *eof, void *data)
66 {
67         struct obd_device *obd = (struct obd_device *)data;
68
69         LASSERT(obd != NULL);
70         *eof = 1;
71         return snprintf(page, count, LPU64"\n", obd->u.filter.fo_tot_granted);
72 }
73
74 static int lprocfs_filter_rd_tot_pending(char *page, char **start, off_t off,
75                                          int count, int *eof, void *data)
76 {
77         struct obd_device *obd = (struct obd_device *)data;
78
79         LASSERT(obd != NULL);
80         *eof = 1;
81         return snprintf(page, count, LPU64"\n", obd->u.filter.fo_tot_pending);
82 }
83
84 static int lprocfs_filter_rd_mntdev(char *page, char **start, off_t off,
85                                     int count, int *eof, void *data)
86 {
87         struct obd_device *obd = (struct obd_device *)data;
88
89         LASSERT(obd != NULL);
90         LASSERT(obd->u.filter.fo_vfsmnt->mnt_devname);
91         *eof = 1;
92         return snprintf(page, count, "%s\n",
93                         obd->u.filter.fo_vfsmnt->mnt_devname);
94 }
95
96 static int lprocfs_filter_rd_last_id(char *page, char **start, off_t off,
97                                      int count, int *eof, void *data)
98 {
99         struct obd_device *obd = data;
100
101         if (obd == NULL || !obd->obd_set_up || obd->obd_stopping)
102                 return 0;
103
104         return snprintf(page, count, LPU64"\n",
105                         filter_last_id(&obd->u.filter, 0));
106 }
107
108 int lprocfs_filter_rd_readcache(char *page, char **start, off_t off, int count,
109                                 int *eof, void *data)
110 {
111         struct obd_device *obd = data;
112         int rc;
113
114         rc = snprintf(page, count, LPU64"\n",
115                       obd->u.filter.fo_readcache_max_filesize);
116         return rc;
117 }
118
119 int lprocfs_filter_wr_readcache(struct file *file, const char *buffer,
120                                 unsigned long count, void *data)
121 {
122         struct obd_device *obd = data;
123         __u64 val;
124         int rc;
125
126         rc = lprocfs_write_u64_helper(buffer, count, &val);
127         if (rc)
128                 return rc;
129
130         obd->u.filter.fo_readcache_max_filesize = val;
131         return count;
132 }
133
134 int lprocfs_filter_rd_fmd_max_num(char *page, char **start, off_t off,
135                                   int count, int *eof, void *data)
136 {
137         struct obd_device *obd = data;
138         int rc;
139
140         rc = snprintf(page, count, "%u\n", obd->u.filter.fo_fmd_max_num);
141         return rc;
142 }
143
144 int lprocfs_filter_wr_fmd_max_num(struct file *file, const char *buffer,
145                                   unsigned long count, void *data)
146 {
147         struct obd_device *obd = data;
148         int val;
149         int rc;
150
151         rc = lprocfs_write_helper(buffer, count, &val);
152         if (rc)
153                 return rc;
154
155         if (val > 65536 || val < 1)
156                 return -EINVAL;
157
158         obd->u.filter.fo_fmd_max_num = val;
159         return count;
160 }
161
162 int lprocfs_filter_rd_fmd_max_age(char *page, char **start, off_t off,
163                                   int count, int *eof, void *data)
164 {
165         struct obd_device *obd = data;
166         int rc;
167
168         rc = snprintf(page, count, "%u\n", obd->u.filter.fo_fmd_max_age / HZ);
169         return rc;
170 }
171
172 int lprocfs_filter_wr_fmd_max_age(struct file *file, const char *buffer,
173                                   unsigned long count, void *data)
174 {
175         struct obd_device *obd = data;
176         int val;
177         int rc;
178
179         rc = lprocfs_write_helper(buffer, count, &val);
180         if (rc)
181                 return rc;
182
183         if (val > 65536 || val < 1)
184                 return -EINVAL;
185
186         obd->u.filter.fo_fmd_max_age = val * HZ;
187         return count;
188 }
189
190 static int lprocfs_filter_rd_cache(char *page, char **start, off_t off,
191                                    int count, int *eof, void *data)
192 {
193         struct obd_device *obd = (struct obd_device *)data;
194         LASSERT(obd != NULL);
195
196         return snprintf(page, count, "%u\n", obd->u.filter.fo_read_cache);
197 }
198
199 static int lprocfs_filter_wr_cache(struct file *file, const char *buffer,
200                      unsigned long count, void *data)
201 {
202         struct obd_device *obd = (struct obd_device *)data;
203         int val, rc;
204         LASSERT(obd != NULL);
205
206         rc = lprocfs_write_helper(buffer, count, &val);
207
208         if (rc)
209                 return rc;
210
211         obd->u.filter.fo_read_cache = val;
212         return count;
213 }
214
215 static int lprocfs_filter_rd_wcache(char *page, char **start, off_t off,
216                                    int count, int *eof, void *data)
217 {
218         struct obd_device *obd = (struct obd_device *)data;
219         LASSERT(obd != NULL);
220
221         return snprintf(page, count, "%u\n", obd->u.filter.fo_writethrough_cache);
222 }
223
224 static int lprocfs_filter_wr_wcache(struct file *file, const char *buffer,
225                      unsigned long count, void *data)
226 {
227         struct obd_device *obd = (struct obd_device *)data;
228         int val, rc;
229         LASSERT(obd != NULL);
230
231         rc = lprocfs_write_helper(buffer, count, &val);
232
233         if (rc)
234                 return rc;
235
236         obd->u.filter.fo_writethrough_cache = val;
237         return count;
238 }
239
240 int lprocfs_filter_rd_syncjournal(char *page, char **start, off_t off,
241                                   int count, int *eof, void *data)
242 {
243         struct obd_device *obd = data;
244         int rc;
245
246         rc = snprintf(page, count, "%u\n", obd->u.filter.fo_syncjournal);
247         return rc;
248 }
249
250 int lprocfs_filter_wr_syncjournal(struct file *file, const char *buffer,
251                                   unsigned long count, void *data)
252 {
253         struct obd_device *obd = data;
254         int val;
255         int rc;
256
257         rc = lprocfs_write_helper(buffer, count, &val);
258         if (rc)
259                 return rc;
260
261         if (val < 0)
262                 return -EINVAL;
263
264         obd->u.filter.fo_syncjournal = !!val;
265         return count;
266 }
267
268 int lprocfs_filter_rd_degraded(char *page, char **start, off_t off,
269                                int count, int *eof, void *data)
270 {
271         struct obd_device *obd = data;
272
273         return snprintf(page, count, "%u\n", obd->u.filter.fo_raid_degraded);
274 }
275
276 int lprocfs_filter_wr_degraded(struct file *file, const char *buffer,
277                                unsigned long count, void *data)
278 {
279         struct obd_device *obd = data;
280         int val, rc;
281
282         rc = lprocfs_write_helper(buffer, count, &val);
283         if (rc)
284                 return rc;
285
286         spin_lock(&obd->obd_osfs_lock);
287         obd->u.filter.fo_raid_degraded = !!val;
288         spin_unlock(&obd->obd_osfs_lock);
289         return count;
290 }
291
292 static struct lprocfs_vars lprocfs_filter_obd_vars[] = {
293         { "uuid",         lprocfs_rd_uuid,          0, 0 },
294         { "blocksize",    lprocfs_rd_blksize,       0, 0 },
295         { "kbytestotal",  lprocfs_rd_kbytestotal,   0, 0 },
296         { "kbytesfree",   lprocfs_rd_kbytesfree,    0, 0 },
297         { "kbytesavail",  lprocfs_rd_kbytesavail,   0, 0 },
298         { "filestotal",   lprocfs_rd_filestotal,    0, 0 },
299         { "filesfree",    lprocfs_rd_filesfree,     0, 0 },
300         { "filegroups",   lprocfs_filter_rd_groups, 0, 0 },
301         { "fstype",       lprocfs_rd_fstype,        0, 0 },
302         { "mntdev",       lprocfs_filter_rd_mntdev, 0, 0 },
303         { "last_id",      lprocfs_filter_rd_last_id,0, 0 },
304         { "tot_dirty",    lprocfs_filter_rd_tot_dirty,   0, 0 },
305         { "tot_pending",  lprocfs_filter_rd_tot_pending, 0, 0 },
306         { "tot_granted",  lprocfs_filter_rd_tot_granted, 0, 0 },
307         { "recovery_status",    lprocfs_obd_rd_recovery_status, 0, 0 },
308         { "recovery_time_soft", lprocfs_obd_rd_recovery_time_soft,
309                                 lprocfs_obd_wr_recovery_time_soft, 0},
310         { "recovery_time_hard", lprocfs_obd_rd_recovery_time_hard,
311                                 lprocfs_obd_wr_recovery_time_hard, 0},
312         { "hash_stats",   lprocfs_obd_rd_hash,      0, 0 },
313         { "evict_client", 0, lprocfs_wr_evict_client, 0,
314                                 &lprocfs_evict_client_fops},
315         { "num_exports",  lprocfs_rd_num_exports,   0, 0 },
316         { "readcache_max_filesize",
317                           lprocfs_filter_rd_readcache,
318                           lprocfs_filter_wr_readcache, 0 },
319 #ifdef HAVE_QUOTA_SUPPORT
320         { "quota_bunit_sz", lprocfs_quota_rd_bunit,
321                             lprocfs_quota_wr_bunit, 0},
322         { "quota_btune_sz", lprocfs_quota_rd_btune,
323                             lprocfs_quota_wr_btune, 0},
324         { "quota_iunit_sz", lprocfs_quota_rd_iunit,
325                             lprocfs_quota_wr_iunit, 0},
326         { "quota_itune_sz", lprocfs_quota_rd_itune,
327                             lprocfs_quota_wr_itune, 0},
328         { "quota_type",     lprocfs_quota_rd_type,
329                             lprocfs_quota_wr_type, 0},
330         { "quota_switch_seconds",  lprocfs_quota_rd_switch_seconds,
331                                    lprocfs_quota_wr_switch_seconds, 0 },
332 #endif
333         { "client_cache_count", lprocfs_filter_rd_fmd_max_num,
334                           lprocfs_filter_wr_fmd_max_num, 0 },
335         { "client_cache_seconds", lprocfs_filter_rd_fmd_max_age,
336                           lprocfs_filter_wr_fmd_max_age, 0 },
337         { "read_cache_enable", lprocfs_filter_rd_cache, lprocfs_filter_wr_cache, 0},
338         { "writethrough_cache_enable", lprocfs_filter_rd_wcache,
339                           lprocfs_filter_wr_wcache, 0},
340 #ifdef HAVE_DELAYED_RECOVERY
341         { "stale_export_age", lprocfs_obd_rd_stale_export_age,
342                               lprocfs_obd_wr_stale_export_age, 0},
343         { "flush_stale_exports", 0, lprocfs_obd_wr_flush_stale_exports, 0 },
344 #endif
345         { "sync_journal", lprocfs_filter_rd_syncjournal,
346                           lprocfs_filter_wr_syncjournal, 0 },
347         { "degraded",     lprocfs_filter_rd_degraded,
348                           lprocfs_filter_wr_degraded, 0 },
349         { 0 }
350 };
351
352 static struct lprocfs_vars lprocfs_filter_module_vars[] = {
353         { "num_refs",     lprocfs_rd_numrefs,       0, 0 },
354         { 0 }
355 };
356
357 void filter_tally(struct obd_export *exp, struct page **pages, int nr_pages,
358                   unsigned long *blocks, int blocks_per_page, int wr)
359 {
360         struct filter_obd *filter = &exp->exp_obd->u.filter;
361         struct page *last_page = NULL;
362         unsigned long *last_block = NULL;
363         unsigned long discont_pages = 0;
364         unsigned long discont_blocks = 0;
365         int i;
366
367         if (nr_pages == 0)
368                 return;
369
370         lprocfs_oh_tally_log2(&filter->fo_filter_stats.hist[BRW_R_PAGES + wr],
371                               nr_pages);
372         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats)
373                 lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->
374                                         hist[BRW_R_PAGES + wr], nr_pages);
375
376         while (nr_pages-- > 0) {
377                 if (last_page && (*pages)->index != (last_page->index + 1))
378                         discont_pages++;
379                 last_page = *pages;
380                 pages++;
381                 for (i = 0; i < blocks_per_page; i++) {
382                         if (last_block && *blocks != (*last_block + 1))
383                                 discont_blocks++;
384                         last_block = blocks++;
385                 }
386         }
387
388         lprocfs_oh_tally(&filter->fo_filter_stats.hist[BRW_R_DISCONT_PAGES +wr],
389                          discont_pages);
390         lprocfs_oh_tally(&filter->fo_filter_stats.hist[BRW_R_DISCONT_BLOCKS+wr],
391                          discont_blocks);
392
393         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats) {
394                 lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->
395                                         hist[BRW_R_DISCONT_PAGES + wr],
396                                       discont_pages);
397                 lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->
398                                         hist[BRW_R_DISCONT_BLOCKS + wr],
399                                       discont_blocks);
400         }
401 }
402
403 #define pct(a,b) (b ? a * 100 / b : 0)
404
405 static void display_brw_stats(struct seq_file *seq, char *name, char *units,
406         struct obd_histogram *read, struct obd_histogram *write, int log2)
407 {
408         unsigned long read_tot, write_tot, r, w, read_cum = 0, write_cum = 0;
409         int i;
410
411         seq_printf(seq, "\n%26s read      |     write\n", " ");
412         seq_printf(seq, "%-22s %-5s %% cum %% |  %-5s %% cum %%\n",
413                    name, units, units);
414
415         read_tot = lprocfs_oh_sum(read);
416         write_tot = lprocfs_oh_sum(write);
417         for (i = 0; i < OBD_HIST_MAX; i++) {
418                 r = read->oh_buckets[i];
419                 w = write->oh_buckets[i];
420                 read_cum += r;
421                 write_cum += w;
422                 if (read_cum == 0 && write_cum == 0)
423                         continue;
424
425                 if (!log2)
426                         seq_printf(seq, "%u", i);
427                 else if (i < 10)
428                         seq_printf(seq, "%u", 1<<i);
429                 else if (i < 20)
430                         seq_printf(seq, "%uK", 1<<(i-10));
431                 else
432                         seq_printf(seq, "%uM", 1<<(i-20));
433
434                 seq_printf(seq, ":\t\t%10lu %3lu %3lu   | %4lu %3lu %3lu\n",
435                            r, pct(r, read_tot), pct(read_cum, read_tot),
436                            w, pct(w, write_tot), pct(write_cum, write_tot));
437
438                 if (read_cum == read_tot && write_cum == write_tot)
439                         break;
440         }
441 }
442
443 static void brw_stats_show(struct seq_file *seq, struct brw_stats *brw_stats)
444 {
445         struct timeval now;
446
447         /* this sampling races with updates */
448         do_gettimeofday(&now);
449         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
450                    now.tv_sec, now.tv_usec);
451
452         display_brw_stats(seq, "pages per bulk r/w", "rpcs",
453                           &brw_stats->hist[BRW_R_PAGES],
454                           &brw_stats->hist[BRW_W_PAGES], 1);
455
456         display_brw_stats(seq, "discontiguous pages", "rpcs",
457                           &brw_stats->hist[BRW_R_DISCONT_PAGES],
458                           &brw_stats->hist[BRW_W_DISCONT_PAGES], 0);
459
460         display_brw_stats(seq, "discontiguous blocks", "rpcs",
461                           &brw_stats->hist[BRW_R_DISCONT_BLOCKS],
462                           &brw_stats->hist[BRW_W_DISCONT_BLOCKS], 0);
463
464         display_brw_stats(seq, "disk fragmented I/Os", "ios",
465                           &brw_stats->hist[BRW_R_DIO_FRAGS],
466                           &brw_stats->hist[BRW_W_DIO_FRAGS], 0);
467
468         display_brw_stats(seq, "disk I/Os in flight", "ios",
469                           &brw_stats->hist[BRW_R_RPC_HIST],
470                           &brw_stats->hist[BRW_W_RPC_HIST], 0);
471
472         {
473                 char title[24];
474                 sprintf(title, "I/O time (1/%ds)", HZ);
475                 display_brw_stats(seq, title, "ios",
476                                   &brw_stats->hist[BRW_R_IO_TIME],
477                                   &brw_stats->hist[BRW_W_IO_TIME], 1);
478         }
479
480         display_brw_stats(seq, "disk I/O size", "ios",
481                           &brw_stats->hist[BRW_R_DISK_IOSIZE],
482                           &brw_stats->hist[BRW_W_DISK_IOSIZE], 1);
483 }
484
485 #undef pct
486
487 static int filter_brw_stats_seq_show(struct seq_file *seq, void *v)
488 {
489         struct obd_device *dev = seq->private;
490         struct filter_obd *filter = &dev->u.filter;
491
492         brw_stats_show(seq, &filter->fo_filter_stats);
493
494         return 0;
495 }
496
497 static ssize_t filter_brw_stats_seq_write(struct file *file, const char *buf,
498                                        size_t len, loff_t *off)
499 {
500         struct seq_file *seq = file->private_data;
501         struct obd_device *dev = seq->private;
502         struct filter_obd *filter = &dev->u.filter;
503         int i;
504
505         for (i = 0; i < BRW_LAST; i++)
506                 lprocfs_oh_clear(&filter->fo_filter_stats.hist[i]);
507
508         return len;
509 }
510
511 LPROC_SEQ_FOPS(filter_brw_stats);
512
513 int lproc_filter_attach_seqstat(struct obd_device *dev)
514 {
515         return lprocfs_obd_seq_create(dev, "brw_stats", 0444,
516                                       &filter_brw_stats_fops, dev);
517 }
518
519 void lprocfs_filter_init_vars(struct lprocfs_static_vars *lvars)
520 {
521     lvars->module_vars  = lprocfs_filter_module_vars;
522     lvars->obd_vars     = lprocfs_filter_obd_vars;
523 }
524
525 static int filter_per_nid_stats_seq_show(struct seq_file *seq, void *v)
526 {
527         nid_stat_t * stat = seq->private;
528
529         if (stat->nid_brw_stats)
530                 brw_stats_show(seq, stat->nid_brw_stats);
531
532         return 0;
533 }
534
535 static ssize_t filter_per_nid_stats_seq_write(struct file *file,
536                                               const char *buf, size_t len,
537                                               loff_t *off)
538 {
539         struct seq_file *seq  = file->private_data;
540         nid_stat_t      *stat = seq->private;
541         int i;
542
543         if (stat->nid_brw_stats)
544                 for (i = 0; i < BRW_LAST; i++)
545                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
546
547         return len;
548 }
549
550 LPROC_SEQ_FOPS(filter_per_nid_stats);
551
552 #endif /* LPROCFS */