]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/lustre/lustre/osc/lproc_osc.c
Merge branch 'x86/mce' into x86/ras
[karo-tx-linux.git] / drivers / staging / lustre / lustre / osc / lproc_osc.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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
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 <asm/statfs.h>
40 #include <obd_cksum.h>
41 #include <obd_class.h>
42 #include <lprocfs_status.h>
43 #include <linux/seq_file.h>
44 #include "osc_internal.h"
45
46 #ifdef LPROCFS
47 static int osc_active_seq_show(struct seq_file *m, void *v)
48 {
49         struct obd_device *dev = m->private;
50         int rc;
51
52         LPROCFS_CLIMP_CHECK(dev);
53         rc = seq_printf(m, "%d\n", !dev->u.cli.cl_import->imp_deactive);
54         LPROCFS_CLIMP_EXIT(dev);
55         return rc;
56 }
57
58 static ssize_t osc_active_seq_write(struct file *file, const char *buffer,
59                                     size_t count, loff_t *off)
60 {
61         struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
62         int val, rc;
63
64         rc = lprocfs_write_helper(buffer, count, &val);
65         if (rc)
66                 return rc;
67         if (val < 0 || val > 1)
68                 return -ERANGE;
69
70         /* opposite senses */
71         if (dev->u.cli.cl_import->imp_deactive == val)
72                 rc = ptlrpc_set_import_active(dev->u.cli.cl_import, val);
73         else
74                 CDEBUG(D_CONFIG, "activate %d: ignoring repeat request\n", val);
75
76         return count;
77 }
78 LPROC_SEQ_FOPS(osc_active);
79
80 static int osc_max_rpcs_in_flight_seq_show(struct seq_file *m, void *v)
81 {
82         struct obd_device *dev = m->private;
83         struct client_obd *cli = &dev->u.cli;
84         int rc;
85
86         client_obd_list_lock(&cli->cl_loi_list_lock);
87         rc = seq_printf(m, "%u\n", cli->cl_max_rpcs_in_flight);
88         client_obd_list_unlock(&cli->cl_loi_list_lock);
89         return rc;
90 }
91
92 static ssize_t osc_max_rpcs_in_flight_seq_write(struct file *file,
93                         const char *buffer, size_t count, loff_t *off)
94 {
95         struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
96         struct client_obd *cli = &dev->u.cli;
97         struct ptlrpc_request_pool *pool = cli->cl_import->imp_rq_pool;
98         int val, rc;
99
100         rc = lprocfs_write_helper(buffer, count, &val);
101         if (rc)
102                 return rc;
103
104         if (val < 1 || val > OSC_MAX_RIF_MAX)
105                 return -ERANGE;
106
107         LPROCFS_CLIMP_CHECK(dev);
108         if (pool && val > cli->cl_max_rpcs_in_flight)
109                 pool->prp_populate(pool, val-cli->cl_max_rpcs_in_flight);
110
111         client_obd_list_lock(&cli->cl_loi_list_lock);
112         cli->cl_max_rpcs_in_flight = val;
113         client_obd_list_unlock(&cli->cl_loi_list_lock);
114
115         LPROCFS_CLIMP_EXIT(dev);
116         return count;
117 }
118 LPROC_SEQ_FOPS(osc_max_rpcs_in_flight);
119
120 static int osc_max_dirty_mb_seq_show(struct seq_file *m, void *v)
121 {
122         struct obd_device *dev = m->private;
123         struct client_obd *cli = &dev->u.cli;
124         long val;
125         int mult;
126
127         client_obd_list_lock(&cli->cl_loi_list_lock);
128         val = cli->cl_dirty_max;
129         client_obd_list_unlock(&cli->cl_loi_list_lock);
130
131         mult = 1 << 20;
132         return lprocfs_seq_read_frac_helper(m, val, mult);
133 }
134
135 static ssize_t osc_max_dirty_mb_seq_write(struct file *file, const char *buffer,
136                                       size_t count, loff_t *off)
137 {
138         struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
139         struct client_obd *cli = &dev->u.cli;
140         int pages_number, mult, rc;
141
142         mult = 1 << (20 - PAGE_CACHE_SHIFT);
143         rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
144         if (rc)
145                 return rc;
146
147         if (pages_number <= 0 ||
148             pages_number > OSC_MAX_DIRTY_MB_MAX << (20 - PAGE_CACHE_SHIFT) ||
149             pages_number > num_physpages / 4) /* 1/4 of RAM */
150                 return -ERANGE;
151
152         client_obd_list_lock(&cli->cl_loi_list_lock);
153         cli->cl_dirty_max = (obd_count)(pages_number << PAGE_CACHE_SHIFT);
154         osc_wake_cache_waiters(cli);
155         client_obd_list_unlock(&cli->cl_loi_list_lock);
156
157         return count;
158 }
159 LPROC_SEQ_FOPS(osc_max_dirty_mb);
160
161 static int osc_cached_mb_seq_show(struct seq_file *m, void *v)
162 {
163         struct obd_device *dev = m->private;
164         struct client_obd *cli = &dev->u.cli;
165         int shift = 20 - PAGE_CACHE_SHIFT;
166         int rc;
167
168         rc = seq_printf(m,
169                       "used_mb: %d\n"
170                       "busy_cnt: %d\n",
171                       (atomic_read(&cli->cl_lru_in_list) +
172                         atomic_read(&cli->cl_lru_busy)) >> shift,
173                       atomic_read(&cli->cl_lru_busy));
174
175         return rc;
176 }
177
178 /* shrink the number of caching pages to a specific number */
179 static ssize_t osc_cached_mb_seq_write(struct file *file, const char *buffer,
180                                    size_t count, loff_t *off)
181 {
182         struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
183         struct client_obd *cli = &dev->u.cli;
184         int pages_number, mult, rc;
185
186         mult = 1 << (20 - PAGE_CACHE_SHIFT);
187         buffer = lprocfs_find_named_value(buffer, "used_mb:", &count);
188         rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
189         if (rc)
190                 return rc;
191
192         if (pages_number < 0)
193                 return -ERANGE;
194
195         rc = atomic_read(&cli->cl_lru_in_list) - pages_number;
196         if (rc > 0)
197                 (void)osc_lru_shrink(cli, rc);
198
199         return count;
200 }
201 LPROC_SEQ_FOPS(osc_cached_mb);
202
203 static int osc_cur_dirty_bytes_seq_show(struct seq_file *m, void *v)
204 {
205         struct obd_device *dev = m->private;
206         struct client_obd *cli = &dev->u.cli;
207         int rc;
208
209         client_obd_list_lock(&cli->cl_loi_list_lock);
210         rc = seq_printf(m, "%lu\n", cli->cl_dirty);
211         client_obd_list_unlock(&cli->cl_loi_list_lock);
212         return rc;
213 }
214 LPROC_SEQ_FOPS_RO(osc_cur_dirty_bytes);
215
216 static int osc_cur_grant_bytes_seq_show(struct seq_file *m, void *v)
217 {
218         struct obd_device *dev = m->private;
219         struct client_obd *cli = &dev->u.cli;
220         int rc;
221
222         client_obd_list_lock(&cli->cl_loi_list_lock);
223         rc = seq_printf(m, "%lu\n", cli->cl_avail_grant);
224         client_obd_list_unlock(&cli->cl_loi_list_lock);
225         return rc;
226 }
227
228 static ssize_t osc_cur_grant_bytes_seq_write(struct file *file, const char *buffer,
229                                   size_t count, loff_t *off)
230 {
231         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
232         struct client_obd *cli = &obd->u.cli;
233         int             rc;
234         __u64         val;
235
236         if (obd == NULL)
237                 return 0;
238
239         rc = lprocfs_write_u64_helper(buffer, count, &val);
240         if (rc)
241                 return rc;
242
243         /* this is only for shrinking grant */
244         client_obd_list_lock(&cli->cl_loi_list_lock);
245         if (val >= cli->cl_avail_grant) {
246                 client_obd_list_unlock(&cli->cl_loi_list_lock);
247                 return 0;
248         }
249         client_obd_list_unlock(&cli->cl_loi_list_lock);
250
251         LPROCFS_CLIMP_CHECK(obd);
252         if (cli->cl_import->imp_state == LUSTRE_IMP_FULL)
253                 rc = osc_shrink_grant_to_target(cli, val);
254         LPROCFS_CLIMP_EXIT(obd);
255         if (rc)
256                 return rc;
257         return count;
258 }
259 LPROC_SEQ_FOPS(osc_cur_grant_bytes);
260
261 static int osc_cur_lost_grant_bytes_seq_show(struct seq_file *m, void *v)
262 {
263         struct obd_device *dev = m->private;
264         struct client_obd *cli = &dev->u.cli;
265         int rc;
266
267         client_obd_list_lock(&cli->cl_loi_list_lock);
268         rc = seq_printf(m, "%lu\n", cli->cl_lost_grant);
269         client_obd_list_unlock(&cli->cl_loi_list_lock);
270         return rc;
271 }
272 LPROC_SEQ_FOPS_RO(osc_cur_lost_grant_bytes);
273
274 static int osc_grant_shrink_interval_seq_show(struct seq_file *m, void *v)
275 {
276         struct obd_device *obd = m->private;
277
278         if (obd == NULL)
279                 return 0;
280         return seq_printf(m, "%d\n",
281                         obd->u.cli.cl_grant_shrink_interval);
282 }
283
284 static ssize_t osc_grant_shrink_interval_seq_write(struct file *file,
285                                 const char *buffer, size_t count, loff_t *off)
286 {
287         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
288         int val, rc;
289
290         if (obd == NULL)
291                 return 0;
292
293         rc = lprocfs_write_helper(buffer, count, &val);
294         if (rc)
295                 return rc;
296
297         if (val <= 0)
298                 return -ERANGE;
299
300         obd->u.cli.cl_grant_shrink_interval = val;
301
302         return count;
303 }
304 LPROC_SEQ_FOPS(osc_grant_shrink_interval);
305
306 static int osc_checksum_seq_show(struct seq_file *m, void *v)
307 {
308         struct obd_device *obd = m->private;
309
310         if (obd == NULL)
311                 return 0;
312
313         return seq_printf(m, "%d\n",
314                         obd->u.cli.cl_checksum ? 1 : 0);
315 }
316
317 static ssize_t osc_checksum_seq_write(struct file *file, const char *buffer,
318                            size_t count, loff_t *off)
319 {
320         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
321         int val, rc;
322
323         if (obd == NULL)
324                 return 0;
325
326         rc = lprocfs_write_helper(buffer, count, &val);
327         if (rc)
328                 return rc;
329
330         obd->u.cli.cl_checksum = (val ? 1 : 0);
331
332         return count;
333 }
334 LPROC_SEQ_FOPS(osc_checksum);
335
336 static int osc_checksum_type_seq_show(struct seq_file *m, void *v)
337 {
338         struct obd_device *obd = m->private;
339         int i;
340         DECLARE_CKSUM_NAME;
341
342         if (obd == NULL)
343                 return 0;
344
345         for (i = 0; i < ARRAY_SIZE(cksum_name); i++) {
346                 if (((1 << i) & obd->u.cli.cl_supp_cksum_types) == 0)
347                         continue;
348                 if (obd->u.cli.cl_cksum_type == (1 << i))
349                         seq_printf(m, "[%s] ", cksum_name[i]);
350                 else
351                         seq_printf(m, "%s ", cksum_name[i]);
352         }
353         seq_printf(m, "\n");
354         return 0;
355 }
356
357 static ssize_t osc_checksum_type_seq_write(struct file *file, const char *buffer,
358                                 size_t count, loff_t *off)
359 {
360         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
361         int i;
362         DECLARE_CKSUM_NAME;
363         char kernbuf[10];
364
365         if (obd == NULL)
366                 return 0;
367
368         if (count > sizeof(kernbuf) - 1)
369                 return -EINVAL;
370         if (copy_from_user(kernbuf, buffer, count))
371                 return -EFAULT;
372         if (count > 0 && kernbuf[count - 1] == '\n')
373                 kernbuf[count - 1] = '\0';
374         else
375                 kernbuf[count] = '\0';
376
377         for (i = 0; i < ARRAY_SIZE(cksum_name); i++) {
378                 if (((1 << i) & obd->u.cli.cl_supp_cksum_types) == 0)
379                         continue;
380                 if (!strcmp(kernbuf, cksum_name[i])) {
381                        obd->u.cli.cl_cksum_type = 1 << i;
382                        return count;
383                 }
384         }
385         return -EINVAL;
386 }
387 LPROC_SEQ_FOPS(osc_checksum_type);
388
389 static int osc_resend_count_seq_show(struct seq_file *m, void *v)
390 {
391         struct obd_device *obd = m->private;
392
393         return seq_printf(m, "%u\n", atomic_read(&obd->u.cli.cl_resends));
394 }
395
396 static ssize_t osc_resend_count_seq_write(struct file *file, const char *buffer,
397                                size_t count, loff_t *off)
398 {
399         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
400         int val, rc;
401
402         rc = lprocfs_write_helper(buffer, count, &val);
403         if (rc)
404                 return rc;
405
406         if (val < 0)
407                return -EINVAL;
408
409         atomic_set(&obd->u.cli.cl_resends, val);
410
411         return count;
412 }
413 LPROC_SEQ_FOPS(osc_resend_count);
414
415 static int osc_contention_seconds_seq_show(struct seq_file *m, void *v)
416 {
417         struct obd_device *obd = m->private;
418         struct osc_device *od  = obd2osc_dev(obd);
419
420         return seq_printf(m, "%u\n", od->od_contention_time);
421 }
422
423 static ssize_t osc_contention_seconds_seq_write(struct file *file, const char *buffer,
424                                      size_t count, loff_t *off)
425 {
426         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
427         struct osc_device *od  = obd2osc_dev(obd);
428
429         return lprocfs_write_helper(buffer, count, &od->od_contention_time) ?:
430                 count;
431 }
432 LPROC_SEQ_FOPS(osc_contention_seconds);
433
434 static int osc_lockless_truncate_seq_show(struct seq_file *m, void *v)
435 {
436         struct obd_device *obd = m->private;
437         struct osc_device *od  = obd2osc_dev(obd);
438
439         return seq_printf(m, "%u\n", od->od_lockless_truncate);
440 }
441
442 static ssize_t osc_lockless_truncate_seq_write(struct file *file, const char *buffer,
443                                     size_t count, loff_t *off)
444 {
445         struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
446         struct osc_device *od  = obd2osc_dev(obd);
447
448         return lprocfs_write_helper(buffer, count, &od->od_lockless_truncate) ?:
449                 count;
450 }
451 LPROC_SEQ_FOPS(osc_lockless_truncate);
452
453 static int osc_destroys_in_flight_seq_show(struct seq_file *m, void *v)
454 {
455         struct obd_device *obd = m->private;
456         return seq_printf(m, "%u\n",
457                         atomic_read(&obd->u.cli.cl_destroy_in_flight));
458 }
459 LPROC_SEQ_FOPS_RO(osc_destroys_in_flight);
460
461 static int osc_obd_max_pages_per_rpc_seq_show(struct seq_file *m, void *v)
462 {
463         return lprocfs_obd_rd_max_pages_per_rpc(m, m->private);
464 }
465
466 static ssize_t osc_obd_max_pages_per_rpc_seq_write(struct file *file,
467                                 const char *buffer, size_t count, loff_t *off)
468 {
469         struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
470         struct client_obd *cli = &dev->u.cli;
471         struct obd_connect_data *ocd = &cli->cl_import->imp_connect_data;
472         int chunk_mask, rc;
473         __u64 val;
474
475         rc = lprocfs_write_u64_helper(buffer, count, &val);
476         if (rc)
477                 return rc;
478
479         /* if the max_pages is specified in bytes, convert to pages */
480         if (val >= ONE_MB_BRW_SIZE)
481                 val >>= PAGE_CACHE_SHIFT;
482
483         LPROCFS_CLIMP_CHECK(dev);
484
485         chunk_mask = ~((1 << (cli->cl_chunkbits - PAGE_CACHE_SHIFT)) - 1);
486         /* max_pages_per_rpc must be chunk aligned */
487         val = (val + ~chunk_mask) & chunk_mask;
488         if (val == 0 || val > ocd->ocd_brw_size >> PAGE_CACHE_SHIFT) {
489                 LPROCFS_CLIMP_EXIT(dev);
490                 return -ERANGE;
491         }
492         client_obd_list_lock(&cli->cl_loi_list_lock);
493         cli->cl_max_pages_per_rpc = val;
494         client_obd_list_unlock(&cli->cl_loi_list_lock);
495
496         LPROCFS_CLIMP_EXIT(dev);
497         return count;
498 }
499 LPROC_SEQ_FOPS(osc_obd_max_pages_per_rpc);
500
501 LPROC_SEQ_FOPS_RO_TYPE(osc, uuid);
502 LPROC_SEQ_FOPS_RO_TYPE(osc, connect_flags);
503 LPROC_SEQ_FOPS_RO_TYPE(osc, blksize);
504 LPROC_SEQ_FOPS_RO_TYPE(osc, kbytestotal);
505 LPROC_SEQ_FOPS_RO_TYPE(osc, kbytesfree);
506 LPROC_SEQ_FOPS_RO_TYPE(osc, kbytesavail);
507 LPROC_SEQ_FOPS_RO_TYPE(osc, filestotal);
508 LPROC_SEQ_FOPS_RO_TYPE(osc, filesfree);
509 LPROC_SEQ_FOPS_RO_TYPE(osc, server_uuid);
510 LPROC_SEQ_FOPS_RO_TYPE(osc, conn_uuid);
511 LPROC_SEQ_FOPS_RO_TYPE(osc, timeouts);
512 LPROC_SEQ_FOPS_RO_TYPE(osc, state);
513
514 LPROC_SEQ_FOPS_WR_ONLY(osc, ping);
515
516 LPROC_SEQ_FOPS_RW_TYPE(osc, import);
517 LPROC_SEQ_FOPS_RW_TYPE(osc, pinger_recov);
518
519 static struct lprocfs_vars lprocfs_osc_obd_vars[] = {
520         { "uuid",            &osc_uuid_fops,    0, 0 },
521         { "ping",            &osc_ping_fops,    0, 0222 },
522         { "connect_flags",   &osc_connect_flags_fops, 0, 0 },
523         { "blocksize",       &osc_blksize_fops,     0, 0 },
524         { "kbytestotal",     &osc_kbytestotal_fops, 0, 0 },
525         { "kbytesfree",      &osc_kbytesfree_fops,  0, 0 },
526         { "kbytesavail",     &osc_kbytesavail_fops, 0, 0 },
527         { "filestotal",      &osc_filestotal_fops,  0, 0 },
528         { "filesfree",       &osc_filesfree_fops,   0, 0 },
529         //{ "filegroups",      lprocfs_rd_filegroups,  0, 0 },
530         { "ost_server_uuid", &osc_server_uuid_fops, 0, 0 },
531         { "ost_conn_uuid",   &osc_conn_uuid_fops, 0, 0 },
532         { "active",          &osc_active_fops, 0 },
533         { "max_pages_per_rpc", &osc_obd_max_pages_per_rpc_fops, 0 },
534         { "max_rpcs_in_flight", &osc_max_rpcs_in_flight_fops, 0 },
535         { "destroys_in_flight", &osc_destroys_in_flight_fops, 0, 0 },
536         { "max_dirty_mb",    &osc_max_dirty_mb_fops, 0 },
537         { "osc_cached_mb",   &osc_cached_mb_fops, 0 },
538         { "cur_dirty_bytes", &osc_cur_dirty_bytes_fops, 0, 0 },
539         { "cur_grant_bytes", &osc_cur_grant_bytes_fops, 0 },
540         { "cur_lost_grant_bytes", &osc_cur_lost_grant_bytes_fops, 0, 0},
541         { "grant_shrink_interval", &osc_grant_shrink_interval_fops, 0 },
542         { "checksums",       &osc_checksum_fops, 0 },
543         { "checksum_type",   &osc_checksum_type_fops, 0 },
544         { "resend_count",    &osc_resend_count_fops, 0},
545         { "timeouts",        &osc_timeouts_fops, 0, 0 },
546         { "contention_seconds", &osc_contention_seconds_fops, 0 },
547         { "lockless_truncate",  &osc_lockless_truncate_fops, 0 },
548         { "import",             &osc_import_fops, 0 },
549         { "state",              &osc_state_fops, 0, 0 },
550         { "pinger_recov",       &osc_pinger_recov_fops, 0 },
551         { 0 }
552 };
553
554 LPROC_SEQ_FOPS_RO_TYPE(osc, numrefs);
555 static struct lprocfs_vars lprocfs_osc_module_vars[] = {
556         { "num_refs",   &osc_numrefs_fops,     0, 0 },
557         { 0 }
558 };
559
560 #define pct(a,b) (b ? a * 100 / b : 0)
561
562 static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
563 {
564         struct timeval now;
565         struct obd_device *dev = seq->private;
566         struct client_obd *cli = &dev->u.cli;
567         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
568         int i;
569
570         do_gettimeofday(&now);
571
572         client_obd_list_lock(&cli->cl_loi_list_lock);
573
574         seq_printf(seq, "snapshot_time:  %lu.%lu (secs.usecs)\n",
575                    now.tv_sec, now.tv_usec);
576         seq_printf(seq, "read RPCs in flight:  %d\n",
577                    cli->cl_r_in_flight);
578         seq_printf(seq, "write RPCs in flight: %d\n",
579                    cli->cl_w_in_flight);
580         seq_printf(seq, "pending write pages:  %d\n",
581                    atomic_read(&cli->cl_pending_w_pages));
582         seq_printf(seq, "pending read pages:   %d\n",
583                    atomic_read(&cli->cl_pending_r_pages));
584
585         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
586         seq_printf(seq, "pages per rpc   rpcs   %% cum %% |");
587         seq_printf(seq, "       rpcs   %% cum %%\n");
588
589         read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
590         write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
591
592         read_cum = 0;
593         write_cum = 0;
594         for (i = 0; i < OBD_HIST_MAX; i++) {
595                 unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
596                 unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
597                 read_cum += r;
598                 write_cum += w;
599                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n",
600                                  1 << i, r, pct(r, read_tot),
601                                  pct(read_cum, read_tot), w,
602                                  pct(w, write_tot),
603                                  pct(write_cum, write_tot));
604                 if (read_cum == read_tot && write_cum == write_tot)
605                         break;
606         }
607
608         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
609         seq_printf(seq, "rpcs in flight rpcs   %% cum %% |");
610         seq_printf(seq, "       rpcs   %% cum %%\n");
611
612         read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
613         write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
614
615         read_cum = 0;
616         write_cum = 0;
617         for (i = 0; i < OBD_HIST_MAX; i++) {
618                 unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
619                 unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
620                 read_cum += r;
621                 write_cum += w;
622                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n",
623                                  i, r, pct(r, read_tot),
624                                  pct(read_cum, read_tot), w,
625                                  pct(w, write_tot),
626                                  pct(write_cum, write_tot));
627                 if (read_cum == read_tot && write_cum == write_tot)
628                         break;
629         }
630
631         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
632         seq_printf(seq, "offset         rpcs   %% cum %% |");
633         seq_printf(seq, "       rpcs   %% cum %%\n");
634
635         read_tot = lprocfs_oh_sum(&cli->cl_read_offset_hist);
636         write_tot = lprocfs_oh_sum(&cli->cl_write_offset_hist);
637
638         read_cum = 0;
639         write_cum = 0;
640         for (i = 0; i < OBD_HIST_MAX; i++) {
641                 unsigned long r = cli->cl_read_offset_hist.oh_buckets[i];
642                 unsigned long w = cli->cl_write_offset_hist.oh_buckets[i];
643                 read_cum += r;
644                 write_cum += w;
645                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n",
646                            (i == 0) ? 0 : 1 << (i - 1),
647                            r, pct(r, read_tot), pct(read_cum, read_tot),
648                            w, pct(w, write_tot), pct(write_cum, write_tot));
649                 if (read_cum == read_tot && write_cum == write_tot)
650                         break;
651         }
652
653         client_obd_list_unlock(&cli->cl_loi_list_lock);
654
655         return 0;
656 }
657 #undef pct
658
659 static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
660                                        size_t len, loff_t *off)
661 {
662         struct seq_file *seq = file->private_data;
663         struct obd_device *dev = seq->private;
664         struct client_obd *cli = &dev->u.cli;
665
666         lprocfs_oh_clear(&cli->cl_read_rpc_hist);
667         lprocfs_oh_clear(&cli->cl_write_rpc_hist);
668         lprocfs_oh_clear(&cli->cl_read_page_hist);
669         lprocfs_oh_clear(&cli->cl_write_page_hist);
670         lprocfs_oh_clear(&cli->cl_read_offset_hist);
671         lprocfs_oh_clear(&cli->cl_write_offset_hist);
672
673         return len;
674 }
675
676 LPROC_SEQ_FOPS(osc_rpc_stats);
677
678 static int osc_stats_seq_show(struct seq_file *seq, void *v)
679 {
680         struct timeval now;
681         struct obd_device *dev = seq->private;
682         struct osc_stats *stats = &obd2osc_dev(dev)->od_stats;
683
684         do_gettimeofday(&now);
685
686         seq_printf(seq, "snapshot_time:  %lu.%lu (secs.usecs)\n",
687                    now.tv_sec, now.tv_usec);
688         seq_printf(seq, "lockless_write_bytes\t\t"LPU64"\n",
689                    stats->os_lockless_writes);
690         seq_printf(seq, "lockless_read_bytes\t\t"LPU64"\n",
691                    stats->os_lockless_reads);
692         seq_printf(seq, "lockless_truncate\t\t"LPU64"\n",
693                    stats->os_lockless_truncates);
694         return 0;
695 }
696
697 static ssize_t osc_stats_seq_write(struct file *file, const char *buf,
698                                    size_t len, loff_t *off)
699 {
700         struct seq_file *seq = file->private_data;
701         struct obd_device *dev = seq->private;
702         struct osc_stats *stats = &obd2osc_dev(dev)->od_stats;
703
704         memset(stats, 0, sizeof(*stats));
705         return len;
706 }
707
708 LPROC_SEQ_FOPS(osc_stats);
709
710 int lproc_osc_attach_seqstat(struct obd_device *dev)
711 {
712         int rc;
713
714         rc = lprocfs_seq_create(dev->obd_proc_entry, "osc_stats", 0644,
715                                 &osc_stats_fops, dev);
716         if (rc == 0)
717                 rc = lprocfs_obd_seq_create(dev, "rpc_stats", 0644,
718                                             &osc_rpc_stats_fops, dev);
719
720         return rc;
721 }
722
723 void lprocfs_osc_init_vars(struct lprocfs_static_vars *lvars)
724 {
725         lvars->module_vars = lprocfs_osc_module_vars;
726         lvars->obd_vars    = lprocfs_osc_obd_vars;
727 }
728 #endif /* LPROCFS */