Whamcloud - gitweb
92effc90d52f3022701a782f220c03d07c5b5952
[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 (c) 2002, 2010, Oracle and/or its affiliates. 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         struct obd_device *obd = (struct obd_device *)data;
51         *eof = 1;
52         return snprintf(page, count, "%u\n", obd->u.filter.fo_group_count);
53 }
54
55 static int lprocfs_filter_rd_tot_dirty(char *page, char **start, off_t off,
56                                        int count, int *eof, void *data)
57 {
58         struct obd_device *obd = (struct obd_device *)data;
59
60         LASSERT(obd != NULL);
61         *eof = 1;
62         return snprintf(page, count, LPU64"\n", obd->u.filter.fo_tot_dirty);
63 }
64
65 static int lprocfs_filter_rd_tot_granted(char *page, char **start, off_t off,
66                                          int count, int *eof, void *data)
67 {
68         struct obd_device *obd = (struct obd_device *)data;
69
70         LASSERT(obd != NULL);
71         *eof = 1;
72         return snprintf(page, count, LPU64"\n", obd->u.filter.fo_tot_granted);
73 }
74
75 static int lprocfs_filter_rd_tot_pending(char *page, char **start, off_t off,
76                                          int count, int *eof, void *data)
77 {
78         struct obd_device *obd = (struct obd_device *)data;
79
80         LASSERT(obd != NULL);
81         *eof = 1;
82         return snprintf(page, count, LPU64"\n", obd->u.filter.fo_tot_pending);
83 }
84
85 static int lprocfs_filter_rd_last_id(char *page, char **start, off_t off,
86                                      int count, int *eof, void *data)
87 {
88         struct obd_device *obd = data;
89         struct filter_obd *filter = &obd->u.filter;
90         int retval = 0, rc, i;
91
92         if (obd == NULL || !obd->obd_set_up || obd->obd_stopping)
93                 return 0;
94         rc = snprintf(page, count, LPU64"\n",filter_last_id(filter, 0));
95         if (rc < 0)
96                 return rc;
97         page += rc;
98         count -= rc;
99         retval += rc;
100
101         for (i = FID_SEQ_OST_MDT1; i < filter->fo_group_count; i++) {
102                 rc = snprintf(page, count, LPU64"\n",filter_last_id(filter, i));
103                 if (rc < 0) {
104                         retval = rc;
105                         break;
106                 }
107                 page += rc;
108                 count -= rc;
109                 retval += rc;
110         }
111         return retval;
112 }
113
114 int lprocfs_filter_rd_readcache(char *page, char **start, off_t off, int count,
115                                 int *eof, void *data)
116 {
117         struct obd_device *obd = data;
118         int rc;
119
120         rc = snprintf(page, count, LPU64"\n",
121                       obd->u.filter.fo_readcache_max_filesize);
122         return rc;
123 }
124
125 int lprocfs_filter_wr_readcache(struct file *file, const char *buffer,
126                                 unsigned long count, void *data)
127 {
128         struct obd_device *obd = data;
129         __u64 val;
130         int rc;
131
132         rc = lprocfs_write_u64_helper(buffer, count, &val);
133         if (rc)
134                 return rc;
135
136         obd->u.filter.fo_readcache_max_filesize = val;
137         return count;
138 }
139
140 int lprocfs_filter_rd_fmd_max_num(char *page, char **start, off_t off,
141                                   int count, int *eof, void *data)
142 {
143         struct obd_device *obd = data;
144         int rc;
145
146         rc = snprintf(page, count, "%u\n", obd->u.filter.fo_fmd_max_num);
147         return rc;
148 }
149
150 int lprocfs_filter_wr_fmd_max_num(struct file *file, const char *buffer,
151                                   unsigned long count, void *data)
152 {
153         struct obd_device *obd = data;
154         int val;
155         int rc;
156
157         rc = lprocfs_write_helper(buffer, count, &val);
158         if (rc)
159                 return rc;
160
161         if (val > 65536 || val < 1)
162                 return -EINVAL;
163
164         obd->u.filter.fo_fmd_max_num = val;
165         return count;
166 }
167
168 int lprocfs_filter_rd_fmd_max_age(char *page, char **start, off_t off,
169                                   int count, int *eof, void *data)
170 {
171         struct obd_device *obd = data;
172         int rc;
173
174         rc = snprintf(page, count, "%u\n",
175                       obd->u.filter.fo_fmd_max_age / CFS_HZ);
176         return rc;
177 }
178
179 int lprocfs_filter_wr_fmd_max_age(struct file *file, const char *buffer,
180                                   unsigned long count, void *data)
181 {
182         struct obd_device *obd = data;
183         int val;
184         int rc;
185
186         rc = lprocfs_write_helper(buffer, count, &val);
187         if (rc)
188                 return rc;
189
190         if (val > 65536 || val < 1)
191                 return -EINVAL;
192
193         obd->u.filter.fo_fmd_max_age = val * CFS_HZ;
194         return count;
195 }
196
197 static int lprocfs_filter_rd_capa(char *page, char **start, off_t off,
198                                   int count, int *eof, void *data)
199 {
200         struct obd_device *obd = data;
201         int rc;
202
203         rc = snprintf(page, count, "capability on: %s\n",
204                       obd->u.filter.fo_fl_oss_capa ? "oss" : "");
205         return rc;
206 }
207
208 static int lprocfs_filter_wr_capa(struct file *file, const char *buffer,
209                                   unsigned long count, void *data)
210 {
211         struct obd_device *obd = data;
212         int val, rc;
213
214         rc = lprocfs_write_helper(buffer, count, &val);
215         if (rc)
216                 return rc;
217
218         if (val & ~0x1) {
219                 CERROR("invalid capability mode, only 0/1 are accepted.\n"
220                        " 1: enable oss fid capability\n"
221                        " 0: disable oss fid capability\n");
222                 return -EINVAL;
223         }
224
225         obd->u.filter.fo_fl_oss_capa = val;
226         LCONSOLE_INFO("OSS %s %s fid capability.\n", obd->obd_name,
227                       val ? "enabled" : "disabled");
228         return count;
229 }
230
231 static int lprocfs_filter_rd_capa_count(char *page, char **start, off_t off,
232                                         int count, int *eof, void *data)
233 {
234         return snprintf(page, count, "%d %d\n",
235                         capa_count[CAPA_SITE_CLIENT],
236                         capa_count[CAPA_SITE_SERVER]);
237 }
238
239 static int lprocfs_rd_sec_level(char *page, char **start, off_t off,
240                                 int count, int *eof, void *data)
241 {
242         struct obd_device *obd = data;
243
244         return snprintf(page, count, "%d\n", obd->u.filter.fo_sec_level);
245 }
246
247 static int lprocfs_wr_sec_level(struct file *file, const char *buffer,
248                                 unsigned long count, void *data)
249 {
250         struct obd_device *obd = data;
251         int val, rc;
252
253         rc = lprocfs_write_helper(buffer, count, &val);
254         if (rc)
255                 return rc;
256
257         if (val > LUSTRE_SEC_ALL || val < LUSTRE_SEC_NONE)
258                 return -EINVAL;
259
260         if (val == LUSTRE_SEC_SPECIFY) {
261                 CWARN("security level %d will be supported in future.\n",
262                       LUSTRE_SEC_SPECIFY);
263                 return -EINVAL;
264         }
265
266         obd->u.filter.fo_sec_level = val;
267         return count;
268 }
269
270 static int lprocfs_filter_rd_cache(char *page, char **start, off_t off,
271                                    int count, int *eof, void *data)
272 {
273         struct obd_device *obd = (struct obd_device *)data;
274         LASSERT(obd != NULL);
275
276         return snprintf(page, count, "%u\n", obd->u.filter.fo_read_cache);
277 }
278
279 static int lprocfs_filter_wr_cache(struct file *file, const char *buffer,
280                      unsigned long count, void *data)
281 {
282         struct obd_device *obd = (struct obd_device *)data;
283         int val, rc;
284         LASSERT(obd != NULL);
285
286         rc = lprocfs_write_helper(buffer, count, &val);
287
288         if (rc)
289                 return rc;
290
291         cfs_spin_lock_bh(&obd->obd_processing_task_lock);
292         obd->u.filter.fo_read_cache = val;
293         cfs_spin_unlock_bh(&obd->obd_processing_task_lock);
294         return count;
295 }
296
297 static int lprocfs_filter_rd_wcache(char *page, char **start, off_t off,
298                                    int count, int *eof, void *data)
299 {
300         struct obd_device *obd = (struct obd_device *)data;
301         LASSERT(obd != NULL);
302
303         return snprintf(page, count, "%u\n", obd->u.filter.fo_writethrough_cache);
304 }
305
306 static int lprocfs_filter_wr_wcache(struct file *file, const char *buffer,
307                      unsigned long count, void *data)
308 {
309         struct obd_device *obd = (struct obd_device *)data;
310         int val, rc;
311         LASSERT(obd != NULL);
312
313         rc = lprocfs_write_helper(buffer, count, &val);
314
315         if (rc)
316                 return rc;
317
318         cfs_spin_lock_bh(&obd->obd_processing_task_lock);
319         obd->u.filter.fo_writethrough_cache = val;
320         cfs_spin_unlock_bh(&obd->obd_processing_task_lock);
321         return count;
322 }
323
324 static int lprocfs_filter_rd_mds_sync(char *page, char **start, off_t off,
325                                       int count, int *eof, void *data)
326 {
327         struct obd_device *obd = (struct obd_device *)data;
328         LASSERT(obd != NULL);
329
330         return snprintf(page, count, "%u\n", obd->u.filter.fo_mds_ost_sync);
331 }
332
333 int lprocfs_filter_rd_degraded(char *page, char **start, off_t off,
334                                int count, int *eof, void *data)
335 {
336         struct obd_device *obd = data;
337
338         return snprintf(page, count, "%u\n", obd->u.filter.fo_raid_degraded);
339 }
340
341 int lprocfs_filter_wr_degraded(struct file *file, const char *buffer,
342                                unsigned long count, void *data)
343 {
344         struct obd_device *obd = data;
345         int val, rc;
346
347         rc = lprocfs_write_helper(buffer, count, &val);
348         if (rc)
349                 return rc;
350
351         cfs_spin_lock(&obd->obd_osfs_lock);
352         obd->u.filter.fo_raid_degraded = !!val;
353         cfs_spin_unlock(&obd->obd_osfs_lock);
354         return count;
355 }
356
357 static struct lprocfs_vars lprocfs_filter_obd_vars[] = {
358         { "uuid",         lprocfs_rd_uuid,          0, 0 },
359         { "blocksize",    lprocfs_rd_blksize,       0, 0 },
360         { "kbytestotal",  lprocfs_rd_kbytestotal,   0, 0 },
361         { "kbytesfree",   lprocfs_rd_kbytesfree,    0, 0 },
362         { "kbytesavail",  lprocfs_rd_kbytesavail,   0, 0 },
363         { "filestotal",   lprocfs_rd_filestotal,    0, 0 },
364         { "filesfree",    lprocfs_rd_filesfree,     0, 0 },
365         { "filegroups",   lprocfs_filter_rd_groups, 0, 0 },
366         { "fstype",       lprocfs_rd_fstype,        0, 0 },
367         { "mntdev",       lprocfs_obd_rd_mntdev,    0, 0 },
368         { "last_id",      lprocfs_filter_rd_last_id,0, 0 },
369         { "tot_dirty",    lprocfs_filter_rd_tot_dirty,   0, 0 },
370         { "tot_pending",  lprocfs_filter_rd_tot_pending, 0, 0 },
371         { "tot_granted",  lprocfs_filter_rd_tot_granted, 0, 0 },
372         { "hash_stats",   lprocfs_obd_rd_hash,      0, 0 },
373         { "recovery_status",    lprocfs_obd_rd_recovery_status, 0, 0 },
374         { "recovery_time_soft", lprocfs_obd_rd_recovery_time_soft,
375                                 lprocfs_obd_wr_recovery_time_soft, 0},
376         { "recovery_time_hard", lprocfs_obd_rd_recovery_time_hard,
377                                 lprocfs_obd_wr_recovery_time_hard, 0},
378         { "evict_client", 0, lprocfs_wr_evict_client, 0,
379                                 &lprocfs_evict_client_fops},
380         { "num_exports",  lprocfs_rd_num_exports,   0, 0 },
381         { "readcache_max_filesize",
382                           lprocfs_filter_rd_readcache,
383                           lprocfs_filter_wr_readcache, 0 },
384 #ifdef HAVE_QUOTA_SUPPORT
385         { "quota_type",     lprocfs_quota_rd_type,
386                             lprocfs_quota_wr_type, 0},
387 #endif
388         { "client_cache_count", lprocfs_filter_rd_fmd_max_num,
389                           lprocfs_filter_wr_fmd_max_num, 0 },
390         { "client_cache_seconds", lprocfs_filter_rd_fmd_max_age,
391                           lprocfs_filter_wr_fmd_max_age, 0 },
392         { "capa",         lprocfs_filter_rd_capa,
393                           lprocfs_filter_wr_capa, 0 },
394         { "capa_count",   lprocfs_filter_rd_capa_count, 0, 0 },
395         { "sec_level",    lprocfs_rd_sec_level,
396                           lprocfs_wr_sec_level,            0 },
397         { "read_cache_enable", lprocfs_filter_rd_cache, lprocfs_filter_wr_cache, 0},
398         { "writethrough_cache_enable", lprocfs_filter_rd_wcache,
399                           lprocfs_filter_wr_wcache, 0},
400         { "mds_sync",     lprocfs_filter_rd_mds_sync, 0, 0},
401         { "degraded",     lprocfs_filter_rd_degraded,
402                           lprocfs_filter_wr_degraded, 0 },
403         { 0 }
404 };
405
406 static struct lprocfs_vars lprocfs_filter_module_vars[] = {
407         { "num_refs",     lprocfs_rd_numrefs,       0, 0 },
408         { 0 }
409 };
410
411 void filter_tally(struct obd_export *exp, struct page **pages, int nr_pages,
412                   unsigned long *blocks, int blocks_per_page, int wr)
413 {
414         struct filter_obd *filter = &exp->exp_obd->u.filter;
415         struct page *last_page = NULL;
416         unsigned long *last_block = NULL;
417         unsigned long discont_pages = 0;
418         unsigned long discont_blocks = 0;
419         int i;
420
421         if (nr_pages == 0)
422                 return;
423
424         lprocfs_oh_tally_log2(&filter->fo_filter_stats.hist[BRW_R_PAGES + wr],
425                               nr_pages);
426         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats)
427                 lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->
428                                         hist[BRW_R_PAGES + wr], nr_pages);
429
430         while (nr_pages-- > 0) {
431                 if (last_page && (*pages)->index != (last_page->index + 1))
432                         discont_pages++;
433                 last_page = *pages;
434                 pages++;
435                 for (i = 0; i < blocks_per_page; i++) {
436                         if (last_block && *blocks != (*last_block + 1))
437                                 discont_blocks++;
438                         last_block = blocks++;
439                 }
440         }
441
442         lprocfs_oh_tally(&filter->fo_filter_stats.hist[BRW_R_DISCONT_PAGES +wr],
443                          discont_pages);
444         lprocfs_oh_tally(&filter->fo_filter_stats.hist[BRW_R_DISCONT_BLOCKS+wr],
445                          discont_blocks);
446
447         if (exp->exp_nid_stats && exp->exp_nid_stats->nid_brw_stats) {
448                 lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->
449                                         hist[BRW_R_DISCONT_PAGES + wr],
450                                       discont_pages);
451                 lprocfs_oh_tally_log2(&exp->exp_nid_stats->nid_brw_stats->
452                                         hist[BRW_R_DISCONT_BLOCKS + wr],
453                                       discont_blocks);
454         }
455 }
456
457 #define pct(a,b) (b ? a * 100 / b : 0)
458
459 static void display_brw_stats(struct seq_file *seq, char *name, char *units,
460         struct obd_histogram *read, struct obd_histogram *write, int log2)
461 {
462         unsigned long read_tot, write_tot, r, w, read_cum = 0, write_cum = 0;
463         int i;
464
465         seq_printf(seq, "\n%26s read      |     write\n", " ");
466         seq_printf(seq, "%-22s %-5s %% cum %% |  %-5s %% cum %%\n",
467                    name, units, units);
468
469         read_tot = lprocfs_oh_sum(read);
470         write_tot = lprocfs_oh_sum(write);
471         for (i = 0; i < OBD_HIST_MAX; i++) {
472                 r = read->oh_buckets[i];
473                 w = write->oh_buckets[i];
474                 read_cum += r;
475                 write_cum += w;
476                 if (read_cum == 0 && write_cum == 0)
477                         continue;
478
479                 if (!log2)
480                         seq_printf(seq, "%u", i);
481                 else if (i < 10)
482                         seq_printf(seq, "%u", 1<<i);
483                 else if (i < 20)
484                         seq_printf(seq, "%uK", 1<<(i-10));
485                 else
486                         seq_printf(seq, "%uM", 1<<(i-20));
487
488                 seq_printf(seq, ":\t\t%10lu %3lu %3lu   | %4lu %3lu %3lu\n",
489                            r, pct(r, read_tot), pct(read_cum, read_tot),
490                            w, pct(w, write_tot), pct(write_cum, write_tot));
491
492                 if (read_cum == read_tot && write_cum == write_tot)
493                         break;
494         }
495 }
496
497 static void brw_stats_show(struct seq_file *seq, struct brw_stats *brw_stats)
498 {
499         struct timeval now;
500
501         /* this sampling races with updates */
502         cfs_gettimeofday(&now);
503         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
504                    now.tv_sec, now.tv_usec);
505
506         display_brw_stats(seq, "pages per bulk r/w", "rpcs",
507                           &brw_stats->hist[BRW_R_PAGES],
508                           &brw_stats->hist[BRW_W_PAGES], 1);
509
510         display_brw_stats(seq, "discontiguous pages", "rpcs",
511                           &brw_stats->hist[BRW_R_DISCONT_PAGES],
512                           &brw_stats->hist[BRW_W_DISCONT_PAGES], 0);
513
514         display_brw_stats(seq, "discontiguous blocks", "rpcs",
515                           &brw_stats->hist[BRW_R_DISCONT_BLOCKS],
516                           &brw_stats->hist[BRW_W_DISCONT_BLOCKS], 0);
517
518         display_brw_stats(seq, "disk fragmented I/Os", "ios",
519                           &brw_stats->hist[BRW_R_DIO_FRAGS],
520                           &brw_stats->hist[BRW_W_DIO_FRAGS], 0);
521
522         display_brw_stats(seq, "disk I/Os in flight", "ios",
523                           &brw_stats->hist[BRW_R_RPC_HIST],
524                           &brw_stats->hist[BRW_W_RPC_HIST], 0);
525
526         {
527                 char title[24];
528                 sprintf(title, "I/O time (1/%ds)", CFS_HZ);
529                 display_brw_stats(seq, title, "ios",
530                                   &brw_stats->hist[BRW_R_IO_TIME],
531                                   &brw_stats->hist[BRW_W_IO_TIME], 1);
532         }
533
534         display_brw_stats(seq, "disk I/O size", "ios",
535                           &brw_stats->hist[BRW_R_DISK_IOSIZE],
536                           &brw_stats->hist[BRW_W_DISK_IOSIZE], 1);
537 }
538
539 #undef pct
540
541 static int filter_brw_stats_seq_show(struct seq_file *seq, void *v)
542 {
543         struct obd_device *dev = seq->private;
544         struct filter_obd *filter = &dev->u.filter;
545
546         brw_stats_show(seq, &filter->fo_filter_stats);
547
548         return 0;
549 }
550
551 static ssize_t filter_brw_stats_seq_write(struct file *file, const char *buf,
552                                        size_t len, loff_t *off)
553 {
554         struct seq_file *seq = file->private_data;
555         struct obd_device *dev = seq->private;
556         struct filter_obd *filter = &dev->u.filter;
557         int i;
558
559         for (i = 0; i < BRW_LAST; i++)
560                 lprocfs_oh_clear(&filter->fo_filter_stats.hist[i]);
561
562         return len;
563 }
564
565 LPROC_SEQ_FOPS(filter_brw_stats);
566
567 int lproc_filter_attach_seqstat(struct obd_device *dev)
568 {
569         return lprocfs_obd_seq_create(dev, "brw_stats", 0444,
570                                       &filter_brw_stats_fops, dev);
571 }
572
573 void lprocfs_filter_init_vars(struct lprocfs_static_vars *lvars)
574 {
575     lvars->module_vars  = lprocfs_filter_module_vars;
576     lvars->obd_vars     = lprocfs_filter_obd_vars;
577 }
578
579 static int filter_per_nid_stats_seq_show(struct seq_file *seq, void *v)
580 {
581         nid_stat_t * stat = seq->private;
582
583         if (stat->nid_brw_stats)
584                 brw_stats_show(seq, stat->nid_brw_stats);
585
586         return 0;
587 }
588
589 static ssize_t filter_per_nid_stats_seq_write(struct file *file,
590                                               const char *buf, size_t len,
591                                               loff_t *off)
592 {
593         struct seq_file *seq  = file->private_data;
594         nid_stat_t      *stat = seq->private;
595         int i;
596
597         if (stat->nid_brw_stats)
598                 for (i = 0; i < BRW_LAST; i++)
599                         lprocfs_oh_clear(&stat->nid_brw_stats->hist[i]);
600
601         return len;
602 }
603
604 LPROC_SEQ_FOPS(filter_per_nid_stats);
605 #endif /* LPROCFS */