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