Whamcloud - gitweb
LU-1146 build: batch update copyright messages
[fs/lustre-release.git] / lustre / llite / lproc_llite.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  * Copyright (c) 2012, Whamcloud, Inc.
33  */
34 /*
35  * This file is part of Lustre, http://www.lustre.org/
36  * Lustre is a trademark of Sun Microsystems, Inc.
37  */
38 #define DEBUG_SUBSYSTEM S_LLITE
39
40 #include <linux/version.h>
41 #include <lustre_lite.h>
42 #include <lprocfs_status.h>
43 #include <linux/seq_file.h>
44 #include <obd_support.h>
45
46 #include "llite_internal.h"
47
48 struct proc_dir_entry *proc_lustre_fs_root;
49
50 #ifdef LPROCFS
51 /* /proc/lustre/llite mount point registration */
52 extern struct file_operations vvp_dump_pgcache_file_ops;
53 struct file_operations ll_rw_extents_stats_fops;
54 struct file_operations ll_rw_extents_stats_pp_fops;
55 struct file_operations ll_rw_offset_stats_fops;
56
57 static int ll_rd_blksize(char *page, char **start, off_t off, int count,
58                          int *eof, void *data)
59 {
60         struct super_block *sb = (struct super_block *)data;
61         struct obd_statfs osfs;
62         int rc;
63
64         LASSERT(sb != NULL);
65         rc = ll_statfs_internal(sb, &osfs,
66                                 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
67                                 OBD_STATFS_NODELAY);
68         if (!rc) {
69               *eof = 1;
70               rc = snprintf(page, count, "%u\n", osfs.os_bsize);
71         }
72
73         return rc;
74 }
75
76 static int ll_rd_kbytestotal(char *page, char **start, off_t off, int count,
77                              int *eof, void *data)
78 {
79         struct super_block *sb = (struct super_block *)data;
80         struct obd_statfs osfs;
81         int rc;
82
83         LASSERT(sb != NULL);
84         rc = ll_statfs_internal(sb, &osfs,
85                                 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
86                                 OBD_STATFS_NODELAY);
87         if (!rc) {
88                 __u32 blk_size = osfs.os_bsize >> 10;
89                 __u64 result = osfs.os_blocks;
90
91                 while (blk_size >>= 1)
92                         result <<= 1;
93
94                 *eof = 1;
95                 rc = snprintf(page, count, LPU64"\n", result);
96         }
97         return rc;
98
99 }
100
101 static int ll_rd_kbytesfree(char *page, char **start, off_t off, int count,
102                             int *eof, void *data)
103 {
104         struct super_block *sb = (struct super_block *)data;
105         struct obd_statfs osfs;
106         int rc;
107
108         LASSERT(sb != NULL);
109         rc = ll_statfs_internal(sb, &osfs,
110                                 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
111                                 OBD_STATFS_NODELAY);
112         if (!rc) {
113                 __u32 blk_size = osfs.os_bsize >> 10;
114                 __u64 result = osfs.os_bfree;
115
116                 while (blk_size >>= 1)
117                         result <<= 1;
118
119                 *eof = 1;
120                 rc = snprintf(page, count, LPU64"\n", result);
121         }
122         return rc;
123 }
124
125 static int ll_rd_kbytesavail(char *page, char **start, off_t off, int count,
126                              int *eof, void *data)
127 {
128         struct super_block *sb = (struct super_block *)data;
129         struct obd_statfs osfs;
130         int rc;
131
132         LASSERT(sb != NULL);
133         rc = ll_statfs_internal(sb, &osfs,
134                                 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
135                                 OBD_STATFS_NODELAY);
136         if (!rc) {
137                 __u32 blk_size = osfs.os_bsize >> 10;
138                 __u64 result = osfs.os_bavail;
139
140                 while (blk_size >>= 1)
141                         result <<= 1;
142
143                 *eof = 1;
144                 rc = snprintf(page, count, LPU64"\n", result);
145         }
146         return rc;
147 }
148
149 static int ll_rd_filestotal(char *page, char **start, off_t off, int count,
150                             int *eof, void *data)
151 {
152         struct super_block *sb = (struct super_block *)data;
153         struct obd_statfs osfs;
154         int rc;
155
156         LASSERT(sb != NULL);
157         rc = ll_statfs_internal(sb, &osfs,
158                                 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
159                                 OBD_STATFS_NODELAY);
160         if (!rc) {
161                  *eof = 1;
162                  rc = snprintf(page, count, LPU64"\n", osfs.os_files);
163         }
164         return rc;
165 }
166
167 static int ll_rd_filesfree(char *page, char **start, off_t off, int count,
168                            int *eof, void *data)
169 {
170         struct super_block *sb = (struct super_block *)data;
171         struct obd_statfs osfs;
172         int rc;
173
174         LASSERT(sb != NULL);
175         rc = ll_statfs_internal(sb, &osfs,
176                                 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
177                                 OBD_STATFS_NODELAY);
178         if (!rc) {
179                  *eof = 1;
180                  rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
181         }
182         return rc;
183
184 }
185
186 static int ll_rd_client_type(char *page, char **start, off_t off, int count,
187                             int *eof, void *data)
188 {
189         struct ll_sb_info *sbi = ll_s2sbi((struct super_block *)data);
190         int rc;
191
192         LASSERT(sbi != NULL);
193
194         *eof = 1;
195         if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
196                 rc = snprintf(page, count, "remote client\n");
197         else
198                 rc = snprintf(page, count, "local client\n");
199
200         return rc;
201 }
202
203 static int ll_rd_fstype(char *page, char **start, off_t off, int count,
204                         int *eof, void *data)
205 {
206         struct super_block *sb = (struct super_block*)data;
207
208         LASSERT(sb != NULL);
209         *eof = 1;
210         return snprintf(page, count, "%s\n", sb->s_type->name);
211 }
212
213 static int ll_rd_sb_uuid(char *page, char **start, off_t off, int count,
214                          int *eof, void *data)
215 {
216         struct super_block *sb = (struct super_block *)data;
217
218         LASSERT(sb != NULL);
219         *eof = 1;
220         return snprintf(page, count, "%s\n", ll_s2sbi(sb)->ll_sb_uuid.uuid);
221 }
222
223 static int ll_rd_site_stats(char *page, char **start, off_t off,
224                             int count, int *eof, void *data)
225 {
226         struct super_block *sb = data;
227
228         /*
229          * See description of statistical counters in struct cl_site, and
230          * struct lu_site.
231          */
232         return cl_site_stats_print(lu2cl_site(ll_s2sbi(sb)->ll_site),
233                                    page, count);
234 }
235
236 static int ll_rd_max_readahead_mb(char *page, char **start, off_t off,
237                                    int count, int *eof, void *data)
238 {
239         struct super_block *sb = data;
240         struct ll_sb_info *sbi = ll_s2sbi(sb);
241         long pages_number;
242         int mult;
243
244         cfs_spin_lock(&sbi->ll_lock);
245         pages_number = sbi->ll_ra_info.ra_max_pages;
246         cfs_spin_unlock(&sbi->ll_lock);
247
248         mult = 1 << (20 - PAGE_CACHE_SHIFT);
249         return lprocfs_read_frac_helper(page, count, pages_number, mult);
250 }
251
252 static int ll_wr_max_readahead_mb(struct file *file, const char *buffer,
253                                   unsigned long count, void *data)
254 {
255         struct super_block *sb = data;
256         struct ll_sb_info *sbi = ll_s2sbi(sb);
257         int mult, rc, pages_number;
258
259         mult = 1 << (20 - CFS_PAGE_SHIFT);
260         rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
261         if (rc)
262                 return rc;
263
264         if (pages_number < 0 || pages_number > cfs_num_physpages / 2) {
265                 CERROR("can't set file readahead more than %lu MB\n",
266                        cfs_num_physpages >> (20 - CFS_PAGE_SHIFT + 1)); /*1/2 of RAM*/
267                 return -ERANGE;
268         }
269
270         cfs_spin_lock(&sbi->ll_lock);
271         sbi->ll_ra_info.ra_max_pages = pages_number;
272         cfs_spin_unlock(&sbi->ll_lock);
273
274         return count;
275 }
276
277 static int ll_rd_max_readahead_per_file_mb(char *page, char **start, off_t off,
278                                            int count, int *eof, void *data)
279 {
280         struct super_block *sb = data;
281         struct ll_sb_info *sbi = ll_s2sbi(sb);
282         long pages_number;
283         int mult;
284
285         cfs_spin_lock(&sbi->ll_lock);
286         pages_number = sbi->ll_ra_info.ra_max_pages_per_file;
287         cfs_spin_unlock(&sbi->ll_lock);
288
289         mult = 1 << (20 - CFS_PAGE_SHIFT);
290         return lprocfs_read_frac_helper(page, count, pages_number, mult);
291 }
292
293 static int ll_wr_max_readahead_per_file_mb(struct file *file, const char *buffer,
294                                           unsigned long count, void *data)
295 {
296         struct super_block *sb = data;
297         struct ll_sb_info *sbi = ll_s2sbi(sb);
298         int mult, rc, pages_number;
299
300         mult = 1 << (20 - CFS_PAGE_SHIFT);
301         rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
302         if (rc)
303                 return rc;
304
305         if (pages_number < 0 ||
306                 pages_number > sbi->ll_ra_info.ra_max_pages) {
307                 CERROR("can't set file readahead more than"
308                        "max_read_ahead_mb %lu MB\n",
309                        sbi->ll_ra_info.ra_max_pages);
310                 return -ERANGE;
311         }
312
313         cfs_spin_lock(&sbi->ll_lock);
314         sbi->ll_ra_info.ra_max_pages_per_file = pages_number;
315         cfs_spin_unlock(&sbi->ll_lock);
316
317         return count;
318 }
319
320 static int ll_rd_max_read_ahead_whole_mb(char *page, char **start, off_t off,
321                                          int count, int *eof, void *data)
322 {
323         struct super_block *sb = data;
324         struct ll_sb_info *sbi = ll_s2sbi(sb);
325         long pages_number;
326         int mult;
327
328         cfs_spin_lock(&sbi->ll_lock);
329         pages_number = sbi->ll_ra_info.ra_max_read_ahead_whole_pages;
330         cfs_spin_unlock(&sbi->ll_lock);
331
332         mult = 1 << (20 - CFS_PAGE_SHIFT);
333         return lprocfs_read_frac_helper(page, count, pages_number, mult);
334 }
335
336 static int ll_wr_max_read_ahead_whole_mb(struct file *file, const char *buffer,
337                                          unsigned long count, void *data)
338 {
339         struct super_block *sb = data;
340         struct ll_sb_info *sbi = ll_s2sbi(sb);
341         int mult, rc, pages_number;
342
343         mult = 1 << (20 - CFS_PAGE_SHIFT);
344         rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
345         if (rc)
346                 return rc;
347
348         /* Cap this at the current max readahead window size, the readahead
349          * algorithm does this anyway so it's pointless to set it larger. */
350         if (pages_number < 0 ||
351             pages_number > sbi->ll_ra_info.ra_max_pages_per_file) {
352                 CERROR("can't set max_read_ahead_whole_mb more than "
353                        "max_read_ahead_per_file_mb: %lu\n",
354                         sbi->ll_ra_info.ra_max_pages_per_file >> (20 - CFS_PAGE_SHIFT));
355                 return -ERANGE;
356         }
357
358         cfs_spin_lock(&sbi->ll_lock);
359         sbi->ll_ra_info.ra_max_read_ahead_whole_pages = pages_number;
360         cfs_spin_unlock(&sbi->ll_lock);
361
362         return count;
363 }
364
365 static int ll_rd_max_cached_mb(char *page, char **start, off_t off,
366                                int count, int *eof, void *data)
367 {
368         struct super_block *sb = data;
369         struct ll_sb_info *sbi = ll_s2sbi(sb);
370         long pages_number;
371         int mult;
372
373         cfs_spin_lock(&sbi->ll_lock);
374         pages_number = sbi->ll_async_page_max;
375         cfs_spin_unlock(&sbi->ll_lock);
376
377         mult = 1 << (20 - CFS_PAGE_SHIFT);
378         return lprocfs_read_frac_helper(page, count, pages_number, mult);;
379 }
380
381 static int ll_wr_max_cached_mb(struct file *file, const char *buffer,
382                                unsigned long count, void *data)
383 {
384         struct super_block *sb = data;
385         struct ll_sb_info *sbi = ll_s2sbi(sb);
386         int mult, rc, pages_number;
387
388         mult = 1 << (20 - CFS_PAGE_SHIFT);
389         rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
390         if (rc)
391                 return rc;
392
393         if (pages_number < 0 || pages_number > cfs_num_physpages) {
394                 CERROR("can't set max cache more than %lu MB\n",
395                         cfs_num_physpages >> (20 - CFS_PAGE_SHIFT));
396                 return -ERANGE;
397         }
398
399         cfs_spin_lock(&sbi->ll_lock);
400         sbi->ll_async_page_max = pages_number ;
401         cfs_spin_unlock(&sbi->ll_lock);
402
403         if (!sbi->ll_dt_exp)
404                 /* Not set up yet, don't call llap_shrink_cache */
405                 return count;
406
407         return count;
408 }
409
410 static int ll_rd_checksum(char *page, char **start, off_t off,
411                           int count, int *eof, void *data)
412 {
413         struct super_block *sb = data;
414         struct ll_sb_info *sbi = ll_s2sbi(sb);
415
416         return snprintf(page, count, "%u\n",
417                         (sbi->ll_flags & LL_SBI_CHECKSUM) ? 1 : 0);
418 }
419
420 static int ll_wr_checksum(struct file *file, const char *buffer,
421                           unsigned long count, void *data)
422 {
423         struct super_block *sb = data;
424         struct ll_sb_info *sbi = ll_s2sbi(sb);
425         int val, rc;
426
427         if (!sbi->ll_dt_exp)
428                 /* Not set up yet */
429                 return -EAGAIN;
430
431         rc = lprocfs_write_helper(buffer, count, &val);
432         if (rc)
433                 return rc;
434         if (val)
435                 sbi->ll_flags |= LL_SBI_CHECKSUM;
436         else
437                 sbi->ll_flags &= ~LL_SBI_CHECKSUM;
438
439         rc = obd_set_info_async(sbi->ll_dt_exp, sizeof(KEY_CHECKSUM),
440                                 KEY_CHECKSUM, sizeof(val), &val, NULL);
441         if (rc)
442                 CWARN("Failed to set OSC checksum flags: %d\n", rc);
443
444         return count;
445 }
446
447 static int ll_rd_max_rw_chunk(char *page, char **start, off_t off,
448                           int count, int *eof, void *data)
449 {
450         struct super_block *sb = data;
451
452         return snprintf(page, count, "%lu\n", ll_s2sbi(sb)->ll_max_rw_chunk);
453 }
454
455 static int ll_wr_max_rw_chunk(struct file *file, const char *buffer,
456                           unsigned long count, void *data)
457 {
458         struct super_block *sb = data;
459         int rc, val;
460
461         rc = lprocfs_write_helper(buffer, count, &val);
462         if (rc)
463                 return rc;
464         ll_s2sbi(sb)->ll_max_rw_chunk = val;
465         return count;
466 }
467
468 static int ll_rd_track_id(char *page, int count, void *data,
469                           enum stats_track_type type)
470 {
471         struct super_block *sb = data;
472
473         if (ll_s2sbi(sb)->ll_stats_track_type == type) {
474                 return snprintf(page, count, "%d\n",
475                                 ll_s2sbi(sb)->ll_stats_track_id);
476
477         } else if (ll_s2sbi(sb)->ll_stats_track_type == STATS_TRACK_ALL) {
478                 return snprintf(page, count, "0 (all)\n");
479         } else {
480                 return snprintf(page, count, "untracked\n");
481         }
482 }
483
484 static int ll_wr_track_id(const char *buffer, unsigned long count, void *data,
485                           enum stats_track_type type)
486 {
487         struct super_block *sb = data;
488         int rc, pid;
489
490         rc = lprocfs_write_helper(buffer, count, &pid);
491         if (rc)
492                 return rc;
493         ll_s2sbi(sb)->ll_stats_track_id = pid;
494         if (pid == 0)
495                 ll_s2sbi(sb)->ll_stats_track_type = STATS_TRACK_ALL;
496         else
497                 ll_s2sbi(sb)->ll_stats_track_type = type;
498         lprocfs_clear_stats(ll_s2sbi(sb)->ll_stats);
499         return count;
500 }
501
502 static int ll_rd_track_pid(char *page, char **start, off_t off,
503                           int count, int *eof, void *data)
504 {
505         return (ll_rd_track_id(page, count, data, STATS_TRACK_PID));
506 }
507
508 static int ll_wr_track_pid(struct file *file, const char *buffer,
509                           unsigned long count, void *data)
510 {
511         return (ll_wr_track_id(buffer, count, data, STATS_TRACK_PID));
512 }
513
514 static int ll_rd_track_ppid(char *page, char **start, off_t off,
515                           int count, int *eof, void *data)
516 {
517         return (ll_rd_track_id(page, count, data, STATS_TRACK_PPID));
518 }
519
520 static int ll_wr_track_ppid(struct file *file, const char *buffer,
521                           unsigned long count, void *data)
522 {
523         return (ll_wr_track_id(buffer, count, data, STATS_TRACK_PPID));
524 }
525
526 static int ll_rd_track_gid(char *page, char **start, off_t off,
527                           int count, int *eof, void *data)
528 {
529         return (ll_rd_track_id(page, count, data, STATS_TRACK_GID));
530 }
531
532 static int ll_wr_track_gid(struct file *file, const char *buffer,
533                           unsigned long count, void *data)
534 {
535         return (ll_wr_track_id(buffer, count, data, STATS_TRACK_GID));
536 }
537
538 static int ll_rd_statahead_max(char *page, char **start, off_t off,
539                                int count, int *eof, void *data)
540 {
541         struct super_block *sb = data;
542         struct ll_sb_info *sbi = ll_s2sbi(sb);
543
544         return snprintf(page, count, "%u\n", sbi->ll_sa_max);
545 }
546
547 static int ll_wr_statahead_max(struct file *file, const char *buffer,
548                                unsigned long count, void *data)
549 {
550         struct super_block *sb = data;
551         struct ll_sb_info *sbi = ll_s2sbi(sb);
552         int val, rc;
553
554         rc = lprocfs_write_helper(buffer, count, &val);
555         if (rc)
556                 return rc;
557
558         if (val >= 0 && val <= LL_SA_RPC_MAX)
559                 sbi->ll_sa_max = val;
560         else
561                 CERROR("Bad statahead_max value %d. Valid values are in the "
562                        "range [0, %d]\n", val, LL_SA_RPC_MAX);
563
564         return count;
565 }
566
567 static int ll_rd_statahead_agl(char *page, char **start, off_t off,
568                                int count, int *eof, void *data)
569 {
570         struct super_block *sb = data;
571         struct ll_sb_info *sbi = ll_s2sbi(sb);
572
573         return snprintf(page, count, "%u\n",
574                         sbi->ll_flags & LL_SBI_AGL_ENABLED ? 1 : 0);
575 }
576
577 static int ll_wr_statahead_agl(struct file *file, const char *buffer,
578                                unsigned long count, void *data)
579 {
580         struct super_block *sb = data;
581         struct ll_sb_info *sbi = ll_s2sbi(sb);
582         int val, rc;
583
584         rc = lprocfs_write_helper(buffer, count, &val);
585         if (rc)
586                 return rc;
587
588         if (val)
589                 sbi->ll_flags |= LL_SBI_AGL_ENABLED;
590         else
591                 sbi->ll_flags &= ~LL_SBI_AGL_ENABLED;
592
593         return count;
594 }
595
596 static int ll_rd_statahead_stats(char *page, char **start, off_t off,
597                                  int count, int *eof, void *data)
598 {
599         struct super_block *sb = data;
600         struct ll_sb_info *sbi = ll_s2sbi(sb);
601
602         return snprintf(page, count,
603                         "statahead total: %u\n"
604                         "statahead wrong: %u\n"
605                         "agl total: %u\n",
606                         atomic_read(&sbi->ll_sa_total),
607                         atomic_read(&sbi->ll_sa_wrong),
608                         atomic_read(&sbi->ll_agl_total));
609 }
610
611 static int ll_rd_lazystatfs(char *page, char **start, off_t off,
612                             int count, int *eof, void *data)
613 {
614         struct super_block *sb = data;
615         struct ll_sb_info *sbi = ll_s2sbi(sb);
616
617         return snprintf(page, count, "%u\n",
618                         (sbi->ll_flags & LL_SBI_LAZYSTATFS) ? 1 : 0);
619 }
620
621 static int ll_wr_lazystatfs(struct file *file, const char *buffer,
622                             unsigned long count, void *data)
623 {
624         struct super_block *sb = data;
625         struct ll_sb_info *sbi = ll_s2sbi(sb);
626         int val, rc;
627
628         rc = lprocfs_write_helper(buffer, count, &val);
629         if (rc)
630                 return rc;
631
632         if (val)
633                 sbi->ll_flags |= LL_SBI_LAZYSTATFS;
634         else
635                 sbi->ll_flags &= ~LL_SBI_LAZYSTATFS;
636
637         return count;
638 }
639
640 static int ll_rd_maxea_size(char *page, char **start, off_t off,
641                             int count, int *eof, void *data)
642 {
643         struct super_block *sb = data;
644         struct ll_sb_info *sbi = ll_s2sbi(sb);
645         unsigned int ealen;
646         int rc;
647
648         rc = ll_get_max_mdsize(sbi, &ealen);
649         if (rc)
650                 return rc;
651
652         return snprintf(page, count, "%u\n", ealen);
653 }
654
655 static struct lprocfs_vars lprocfs_llite_obd_vars[] = {
656         { "uuid",         ll_rd_sb_uuid,          0, 0 },
657         //{ "mntpt_path",   ll_rd_path,             0, 0 },
658         { "fstype",       ll_rd_fstype,           0, 0 },
659         { "site",         ll_rd_site_stats,       0, 0 },
660         { "blocksize",    ll_rd_blksize,          0, 0 },
661         { "kbytestotal",  ll_rd_kbytestotal,      0, 0 },
662         { "kbytesfree",   ll_rd_kbytesfree,       0, 0 },
663         { "kbytesavail",  ll_rd_kbytesavail,      0, 0 },
664         { "filestotal",   ll_rd_filestotal,       0, 0 },
665         { "filesfree",    ll_rd_filesfree,        0, 0 },
666         { "client_type",  ll_rd_client_type,      0, 0 },
667         //{ "filegroups",   lprocfs_rd_filegroups,  0, 0 },
668         { "max_read_ahead_mb", ll_rd_max_readahead_mb,
669                                ll_wr_max_readahead_mb, 0 },
670         { "max_read_ahead_per_file_mb", ll_rd_max_readahead_per_file_mb,
671                                         ll_wr_max_readahead_per_file_mb, 0 },
672         { "max_read_ahead_whole_mb", ll_rd_max_read_ahead_whole_mb,
673                                      ll_wr_max_read_ahead_whole_mb, 0 },
674         { "max_cached_mb",    ll_rd_max_cached_mb, ll_wr_max_cached_mb, 0 },
675         { "checksum_pages",   ll_rd_checksum, ll_wr_checksum, 0 },
676         { "max_rw_chunk",     ll_rd_max_rw_chunk, ll_wr_max_rw_chunk, 0 },
677         { "stats_track_pid",  ll_rd_track_pid, ll_wr_track_pid, 0 },
678         { "stats_track_ppid", ll_rd_track_ppid, ll_wr_track_ppid, 0 },
679         { "stats_track_gid",  ll_rd_track_gid, ll_wr_track_gid, 0 },
680         { "statahead_max",    ll_rd_statahead_max, ll_wr_statahead_max, 0 },
681         { "statahead_agl",    ll_rd_statahead_agl, ll_wr_statahead_agl, 0 },
682         { "statahead_stats",  ll_rd_statahead_stats, 0, 0 },
683         { "lazystatfs",       ll_rd_lazystatfs, ll_wr_lazystatfs, 0 },
684         { "max_easize",       ll_rd_maxea_size, 0, 0 },
685         { 0 }
686 };
687
688 #define MAX_STRING_SIZE 128
689
690 struct llite_file_opcode {
691         __u32       opcode;
692         __u32       type;
693         const char *opname;
694 } llite_opcode_table[LPROC_LL_FILE_OPCODES] = {
695         /* file operation */
696         { LPROC_LL_DIRTY_HITS,     LPROCFS_TYPE_REGS, "dirty_pages_hits" },
697         { LPROC_LL_DIRTY_MISSES,   LPROCFS_TYPE_REGS, "dirty_pages_misses" },
698         { LPROC_LL_WB_WRITEPAGE,   LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
699                                    "writeback_from_writepage" },
700         { LPROC_LL_WB_PRESSURE,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
701                                    "writeback_from_pressure" },
702         { LPROC_LL_WB_OK,          LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
703                                    "writeback_ok_pages" },
704         { LPROC_LL_WB_FAIL,        LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
705                                    "writeback_failed_pages" },
706         { LPROC_LL_READ_BYTES,     LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
707                                    "read_bytes" },
708         { LPROC_LL_WRITE_BYTES,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
709                                    "write_bytes" },
710         { LPROC_LL_BRW_READ,       LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
711                                    "brw_read" },
712         { LPROC_LL_BRW_WRITE,      LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
713                                    "brw_write" },
714         { LPROC_LL_OSC_READ,       LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
715                                    "osc_read" },
716         { LPROC_LL_OSC_WRITE,      LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
717                                    "osc_write" },
718
719         { LPROC_LL_IOCTL,          LPROCFS_TYPE_REGS, "ioctl" },
720         { LPROC_LL_OPEN,           LPROCFS_TYPE_REGS, "open" },
721         { LPROC_LL_RELEASE,        LPROCFS_TYPE_REGS, "close" },
722         { LPROC_LL_MAP,            LPROCFS_TYPE_REGS, "mmap" },
723         { LPROC_LL_LLSEEK,         LPROCFS_TYPE_REGS, "seek" },
724         { LPROC_LL_FSYNC,          LPROCFS_TYPE_REGS, "fsync" },
725         /* inode operation */
726         { LPROC_LL_SETATTR,        LPROCFS_TYPE_REGS, "setattr" },
727         { LPROC_LL_TRUNC,          LPROCFS_TYPE_REGS, "truncate" },
728         { LPROC_LL_LOCKLESS_TRUNC, LPROCFS_TYPE_REGS, "lockless_truncate"},
729         { LPROC_LL_FLOCK,          LPROCFS_TYPE_REGS, "flock" },
730         { LPROC_LL_GETATTR,        LPROCFS_TYPE_REGS, "getattr" },
731         /* special inode operation */
732         { LPROC_LL_STAFS,          LPROCFS_TYPE_REGS, "statfs" },
733         { LPROC_LL_ALLOC_INODE,    LPROCFS_TYPE_REGS, "alloc_inode" },
734         { LPROC_LL_SETXATTR,       LPROCFS_TYPE_REGS, "setxattr" },
735         { LPROC_LL_GETXATTR,       LPROCFS_TYPE_REGS, "getxattr" },
736         { LPROC_LL_LISTXATTR,      LPROCFS_TYPE_REGS, "listxattr" },
737         { LPROC_LL_REMOVEXATTR,    LPROCFS_TYPE_REGS, "removexattr" },
738         { LPROC_LL_INODE_PERM,     LPROCFS_TYPE_REGS, "inode_permission" },
739         { LPROC_LL_DIRECT_READ,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
740                                    "direct_read" },
741         { LPROC_LL_DIRECT_WRITE,   LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
742                                    "direct_write" },
743         { LPROC_LL_LOCKLESS_READ,  LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
744                                    "lockless_read_bytes" },
745         { LPROC_LL_LOCKLESS_WRITE, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
746                                    "lockless_write_bytes" },
747
748 };
749
750 void ll_stats_ops_tally(struct ll_sb_info *sbi, int op, int count)
751 {
752         if (!sbi->ll_stats)
753                 return;
754         if (sbi->ll_stats_track_type == STATS_TRACK_ALL)
755                 lprocfs_counter_add(sbi->ll_stats, op, count);
756         else if (sbi->ll_stats_track_type == STATS_TRACK_PID &&
757                  sbi->ll_stats_track_id == current->pid)
758                 lprocfs_counter_add(sbi->ll_stats, op, count);
759         else if (sbi->ll_stats_track_type == STATS_TRACK_PPID &&
760                  sbi->ll_stats_track_id == current->parent->pid)
761                 lprocfs_counter_add(sbi->ll_stats, op, count);
762         else if (sbi->ll_stats_track_type == STATS_TRACK_GID &&
763                  sbi->ll_stats_track_id == cfs_curproc_gid())
764                 lprocfs_counter_add(sbi->ll_stats, op, count);
765 }
766 EXPORT_SYMBOL(ll_stats_ops_tally);
767
768 static const char *ra_stat_string[] = {
769         [RA_STAT_HIT] = "hits",
770         [RA_STAT_MISS] = "misses",
771         [RA_STAT_DISTANT_READPAGE] = "readpage not consecutive",
772         [RA_STAT_MISS_IN_WINDOW] = "miss inside window",
773         [RA_STAT_FAILED_GRAB_PAGE] = "failed grab_cache_page",
774         [RA_STAT_FAILED_MATCH] = "failed lock match",
775         [RA_STAT_DISCARDED] = "read but discarded",
776         [RA_STAT_ZERO_LEN] = "zero length file",
777         [RA_STAT_ZERO_WINDOW] = "zero size window",
778         [RA_STAT_EOF] = "read-ahead to EOF",
779         [RA_STAT_MAX_IN_FLIGHT] = "hit max r-a issue",
780         [RA_STAT_WRONG_GRAB_PAGE] = "wrong page from grab_cache_page",
781 };
782
783
784 int lprocfs_register_mountpoint(struct proc_dir_entry *parent,
785                                 struct super_block *sb, char *osc, char *mdc)
786 {
787         struct lprocfs_vars lvars[2];
788         struct lustre_sb_info *lsi = s2lsi(sb);
789         struct ll_sb_info *sbi = ll_s2sbi(sb);
790         struct obd_device *obd;
791         char name[MAX_STRING_SIZE + 1], *ptr;
792         int err, id, len, rc;
793         ENTRY;
794
795         memset(lvars, 0, sizeof(lvars));
796
797         name[MAX_STRING_SIZE] = '\0';
798         lvars[0].name = name;
799
800         LASSERT(sbi != NULL);
801         LASSERT(mdc != NULL);
802         LASSERT(osc != NULL);
803
804         /* Get fsname */
805         len = strlen(lsi->lsi_lmd->lmd_profile);
806         ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-');
807         if (ptr && (strcmp(ptr, "-client") == 0))
808                 len -= 7;
809
810         /* Mount info */
811         snprintf(name, MAX_STRING_SIZE, "%.*s-%p", len,
812                  lsi->lsi_lmd->lmd_profile, sb);
813
814         sbi->ll_proc_root = lprocfs_register(name, parent, NULL, NULL);
815         if (IS_ERR(sbi->ll_proc_root)) {
816                 err = PTR_ERR(sbi->ll_proc_root);
817                 sbi->ll_proc_root = NULL;
818                 RETURN(err);
819         }
820
821         rc = lprocfs_seq_create(sbi->ll_proc_root, "dump_page_cache", 0444,
822                                 &vvp_dump_pgcache_file_ops, sbi);
823         if (rc)
824                 CWARN("Error adding the dump_page_cache file\n");
825
826         rc = lprocfs_seq_create(sbi->ll_proc_root, "extents_stats", 0644,
827                                 &ll_rw_extents_stats_fops, sbi);
828         if (rc)
829                 CWARN("Error adding the extent_stats file\n");
830
831         rc = lprocfs_seq_create(sbi->ll_proc_root, "extents_stats_per_process",
832                                 0644, &ll_rw_extents_stats_pp_fops, sbi);
833         if (rc)
834                 CWARN("Error adding the extents_stats_per_process file\n");
835
836         rc = lprocfs_seq_create(sbi->ll_proc_root, "offset_stats", 0644,
837                                 &ll_rw_offset_stats_fops, sbi);
838         if (rc)
839                 CWARN("Error adding the offset_stats file\n");
840
841         /* File operations stats */
842         sbi->ll_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES,
843                                             LPROCFS_STATS_FLAG_NONE);
844         if (sbi->ll_stats == NULL)
845                 GOTO(out, err = -ENOMEM);
846         /* do counter init */
847         for (id = 0; id < LPROC_LL_FILE_OPCODES; id++) {
848                 __u32 type = llite_opcode_table[id].type;
849                 void *ptr = NULL;
850                 if (type & LPROCFS_TYPE_REGS)
851                         ptr = "regs";
852                 else if (type & LPROCFS_TYPE_BYTES)
853                         ptr = "bytes";
854                 else if (type & LPROCFS_TYPE_PAGES)
855                         ptr = "pages";
856                 lprocfs_counter_init(sbi->ll_stats,
857                                      llite_opcode_table[id].opcode,
858                                      (type & LPROCFS_CNTR_AVGMINMAX),
859                                      llite_opcode_table[id].opname, ptr);
860         }
861         err = lprocfs_register_stats(sbi->ll_proc_root, "stats", sbi->ll_stats);
862         if (err)
863                 GOTO(out, err);
864
865         sbi->ll_ra_stats = lprocfs_alloc_stats(ARRAY_SIZE(ra_stat_string),
866                                                LPROCFS_STATS_FLAG_NONE);
867         if (sbi->ll_ra_stats == NULL)
868                 GOTO(out, err = -ENOMEM);
869
870         for (id = 0; id < ARRAY_SIZE(ra_stat_string); id++)
871                 lprocfs_counter_init(sbi->ll_ra_stats, id, 0,
872                                      ra_stat_string[id], "pages");
873         err = lprocfs_register_stats(sbi->ll_proc_root, "read_ahead_stats",
874                                      sbi->ll_ra_stats);
875         if (err)
876                 GOTO(out, err);
877
878
879         err = lprocfs_add_vars(sbi->ll_proc_root, lprocfs_llite_obd_vars, sb);
880         if (err)
881                 GOTO(out, err);
882
883         /* MDC info */
884         obd = class_name2obd(mdc);
885
886         LASSERT(obd != NULL);
887         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
888         LASSERT(obd->obd_type->typ_name != NULL);
889
890         snprintf(name, MAX_STRING_SIZE, "%s/common_name",
891                  obd->obd_type->typ_name);
892         lvars[0].read_fptr = lprocfs_rd_name;
893         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
894         if (err)
895                 GOTO(out, err);
896
897         snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name);
898         lvars[0].read_fptr = lprocfs_rd_uuid;
899         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
900         if (err)
901                 GOTO(out, err);
902
903         /* OSC */
904         obd = class_name2obd(osc);
905
906         LASSERT(obd != NULL);
907         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
908         LASSERT(obd->obd_type->typ_name != NULL);
909
910         snprintf(name, MAX_STRING_SIZE, "%s/common_name",
911                  obd->obd_type->typ_name);
912         lvars[0].read_fptr = lprocfs_rd_name;
913         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
914         if (err)
915                 GOTO(out, err);
916
917         snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name);
918         lvars[0].read_fptr = lprocfs_rd_uuid;
919         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
920 out:
921         if (err) {
922                 lprocfs_remove(&sbi->ll_proc_root);
923                 lprocfs_free_stats(&sbi->ll_ra_stats);
924                 lprocfs_free_stats(&sbi->ll_stats);
925         }
926         RETURN(err);
927 }
928
929 void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi)
930 {
931         if (sbi->ll_proc_root) {
932                 lprocfs_remove(&sbi->ll_proc_root);
933                 lprocfs_free_stats(&sbi->ll_ra_stats);
934                 lprocfs_free_stats(&sbi->ll_stats);
935         }
936 }
937 #undef MAX_STRING_SIZE
938
939 #define pct(a,b) (b ? a * 100 / b : 0)
940
941 static void ll_display_extents_info(struct ll_rw_extents_info *io_extents,
942                                    struct seq_file *seq, int which)
943 {
944         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
945         unsigned long start, end, r, w;
946         char *unitp = "KMGTPEZY";
947         int i, units = 10;
948         struct per_process_info *pp_info = &io_extents->pp_extents[which];
949
950         read_cum = 0;
951         write_cum = 0;
952         start = 0;
953
954         for(i = 0; i < LL_HIST_MAX; i++) {
955                 read_tot += pp_info->pp_r_hist.oh_buckets[i];
956                 write_tot += pp_info->pp_w_hist.oh_buckets[i];
957         }
958
959         for(i = 0; i < LL_HIST_MAX; i++) {
960                 r = pp_info->pp_r_hist.oh_buckets[i];
961                 w = pp_info->pp_w_hist.oh_buckets[i];
962                 read_cum += r;
963                 write_cum += w;
964                 end = 1 << (i + LL_HIST_START - units);
965                 seq_printf(seq, "%4lu%c - %4lu%c%c: %14lu %4lu %4lu  | "
966                            "%14lu %4lu %4lu\n", start, *unitp, end, *unitp,
967                            (i == LL_HIST_MAX - 1) ? '+' : ' ',
968                            r, pct(r, read_tot), pct(read_cum, read_tot),
969                            w, pct(w, write_tot), pct(write_cum, write_tot));
970                 start = end;
971                 if (start == 1<<10) {
972                         start = 1;
973                         units += 10;
974                         unitp++;
975                 }
976                 if (read_cum == read_tot && write_cum == write_tot)
977                         break;
978         }
979 }
980
981 static int ll_rw_extents_stats_pp_seq_show(struct seq_file *seq, void *v)
982 {
983         struct timeval now;
984         struct ll_sb_info *sbi = seq->private;
985         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
986         int k;
987
988         cfs_gettimeofday(&now);
989
990         if (!sbi->ll_rw_stats_on) {
991                 seq_printf(seq, "disabled\n"
992                                 "write anything in this file to activate, "
993                                 "then 0 or \"[D/d]isabled\" to deactivate\n");
994                 return 0;
995         }
996         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
997                    now.tv_sec, now.tv_usec);
998         seq_printf(seq, "%15s %19s       | %20s\n", " ", "read", "write");
999         seq_printf(seq, "%13s   %14s %4s %4s  | %14s %4s %4s\n",
1000                    "extents", "calls", "%", "cum%",
1001                    "calls", "%", "cum%");
1002         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1003         for(k = 0; k < LL_PROCESS_HIST_MAX; k++) {
1004                 if(io_extents->pp_extents[k].pid != 0) {
1005                         seq_printf(seq, "\nPID: %d\n",
1006                                    io_extents->pp_extents[k].pid);
1007                         ll_display_extents_info(io_extents, seq, k);
1008                 }
1009         }
1010         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1011         return 0;
1012 }
1013
1014 static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
1015                                                 const char *buf, size_t len,
1016                                                 loff_t *off)
1017 {
1018         struct seq_file *seq = file->private_data;
1019         struct ll_sb_info *sbi = seq->private;
1020         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1021         int i;
1022         int value = 1, rc = 0;
1023
1024         rc = lprocfs_write_helper(buf, len, &value);
1025         if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
1026                        strcmp(buf, "Disabled") == 0))
1027                 value = 0;
1028
1029         if (value == 0)
1030                 sbi->ll_rw_stats_on = 0;
1031         else
1032                 sbi->ll_rw_stats_on = 1;
1033
1034         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1035         for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1036                 io_extents->pp_extents[i].pid = 0;
1037                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist);
1038                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist);
1039         }
1040         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1041         return len;
1042 }
1043
1044 LPROC_SEQ_FOPS(ll_rw_extents_stats_pp);
1045
1046 static int ll_rw_extents_stats_seq_show(struct seq_file *seq, void *v)
1047 {
1048         struct timeval now;
1049         struct ll_sb_info *sbi = seq->private;
1050         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1051
1052         cfs_gettimeofday(&now);
1053
1054         if (!sbi->ll_rw_stats_on) {
1055                 seq_printf(seq, "disabled\n"
1056                                 "write anything in this file to activate, "
1057                                 "then 0 or \"[D/d]isabled\" to deactivate\n");
1058                 return 0;
1059         }
1060         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
1061                    now.tv_sec, now.tv_usec);
1062
1063         seq_printf(seq, "%15s %19s       | %20s\n", " ", "read", "write");
1064         seq_printf(seq, "%13s   %14s %4s %4s  | %14s %4s %4s\n",
1065                    "extents", "calls", "%", "cum%",
1066                    "calls", "%", "cum%");
1067         cfs_spin_lock(&sbi->ll_lock);
1068         ll_display_extents_info(io_extents, seq, LL_PROCESS_HIST_MAX);
1069         cfs_spin_unlock(&sbi->ll_lock);
1070
1071         return 0;
1072 }
1073
1074 static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf,
1075                                         size_t len, loff_t *off)
1076 {
1077         struct seq_file *seq = file->private_data;
1078         struct ll_sb_info *sbi = seq->private;
1079         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1080         int i;
1081         int value = 1, rc = 0;
1082
1083         rc = lprocfs_write_helper(buf, len, &value);
1084         if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
1085                        strcmp(buf, "Disabled") == 0))
1086                 value = 0;
1087
1088         if (value == 0)
1089                 sbi->ll_rw_stats_on = 0;
1090         else
1091                 sbi->ll_rw_stats_on = 1;
1092         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1093         for(i = 0; i <= LL_PROCESS_HIST_MAX; i++)
1094         {
1095                 io_extents->pp_extents[i].pid = 0;
1096                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist);
1097                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist);
1098         }
1099         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1100
1101         return len;
1102 }
1103
1104 LPROC_SEQ_FOPS(ll_rw_extents_stats);
1105
1106 void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
1107                        struct ll_file_data *file, loff_t pos,
1108                        size_t count, int rw)
1109 {
1110         int i, cur = -1;
1111         struct ll_rw_process_info *process;
1112         struct ll_rw_process_info *offset;
1113         int *off_count = &sbi->ll_rw_offset_entry_count;
1114         int *process_count = &sbi->ll_offset_process_count;
1115         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1116
1117         if(!sbi->ll_rw_stats_on)
1118                 return;
1119         process = sbi->ll_rw_process_info;
1120         offset = sbi->ll_rw_offset_info;
1121
1122         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1123         /* Extent statistics */
1124         for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1125                 if(io_extents->pp_extents[i].pid == pid) {
1126                         cur = i;
1127                         break;
1128                 }
1129         }
1130
1131         if (cur == -1) {
1132                 /* new process */
1133                 sbi->ll_extent_process_count =
1134                         (sbi->ll_extent_process_count + 1) % LL_PROCESS_HIST_MAX;
1135                 cur = sbi->ll_extent_process_count;
1136                 io_extents->pp_extents[cur].pid = pid;
1137                 lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_r_hist);
1138                 lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_w_hist);
1139         }
1140
1141         for(i = 0; (count >= (1 << LL_HIST_START << i)) &&
1142              (i < (LL_HIST_MAX - 1)); i++);
1143         if (rw == 0) {
1144                 io_extents->pp_extents[cur].pp_r_hist.oh_buckets[i]++;
1145                 io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_r_hist.oh_buckets[i]++;
1146         } else {
1147                 io_extents->pp_extents[cur].pp_w_hist.oh_buckets[i]++;
1148                 io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_w_hist.oh_buckets[i]++;
1149         }
1150         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1151
1152         cfs_spin_lock(&sbi->ll_process_lock);
1153         /* Offset statistics */
1154         for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1155                 if (process[i].rw_pid == pid) {
1156                         if (process[i].rw_last_file != file) {
1157                                 process[i].rw_range_start = pos;
1158                                 process[i].rw_last_file_pos = pos + count;
1159                                 process[i].rw_smallest_extent = count;
1160                                 process[i].rw_largest_extent = count;
1161                                 process[i].rw_offset = 0;
1162                                 process[i].rw_last_file = file;
1163                                 cfs_spin_unlock(&sbi->ll_process_lock);
1164                                 return;
1165                         }
1166                         if (process[i].rw_last_file_pos != pos) {
1167                                 *off_count =
1168                                     (*off_count + 1) % LL_OFFSET_HIST_MAX;
1169                                 offset[*off_count].rw_op = process[i].rw_op;
1170                                 offset[*off_count].rw_pid = pid;
1171                                 offset[*off_count].rw_range_start =
1172                                         process[i].rw_range_start;
1173                                 offset[*off_count].rw_range_end =
1174                                         process[i].rw_last_file_pos;
1175                                 offset[*off_count].rw_smallest_extent =
1176                                         process[i].rw_smallest_extent;
1177                                 offset[*off_count].rw_largest_extent =
1178                                         process[i].rw_largest_extent;
1179                                 offset[*off_count].rw_offset =
1180                                         process[i].rw_offset;
1181                                 process[i].rw_op = rw;
1182                                 process[i].rw_range_start = pos;
1183                                 process[i].rw_smallest_extent = count;
1184                                 process[i].rw_largest_extent = count;
1185                                 process[i].rw_offset = pos -
1186                                         process[i].rw_last_file_pos;
1187                         }
1188                         if(process[i].rw_smallest_extent > count)
1189                                 process[i].rw_smallest_extent = count;
1190                         if(process[i].rw_largest_extent < count)
1191                                 process[i].rw_largest_extent = count;
1192                         process[i].rw_last_file_pos = pos + count;
1193                         cfs_spin_unlock(&sbi->ll_process_lock);
1194                         return;
1195                 }
1196         }
1197         *process_count = (*process_count + 1) % LL_PROCESS_HIST_MAX;
1198         process[*process_count].rw_pid = pid;
1199         process[*process_count].rw_op = rw;
1200         process[*process_count].rw_range_start = pos;
1201         process[*process_count].rw_last_file_pos = pos + count;
1202         process[*process_count].rw_smallest_extent = count;
1203         process[*process_count].rw_largest_extent = count;
1204         process[*process_count].rw_offset = 0;
1205         process[*process_count].rw_last_file = file;
1206         cfs_spin_unlock(&sbi->ll_process_lock);
1207 }
1208
1209 static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
1210 {
1211         struct timeval now;
1212         struct ll_sb_info *sbi = seq->private;
1213         struct ll_rw_process_info *offset = sbi->ll_rw_offset_info;
1214         struct ll_rw_process_info *process = sbi->ll_rw_process_info;
1215         int i;
1216
1217         cfs_gettimeofday(&now);
1218
1219         if (!sbi->ll_rw_stats_on) {
1220                 seq_printf(seq, "disabled\n"
1221                                 "write anything in this file to activate, "
1222                                 "then 0 or \"[D/d]isabled\" to deactivate\n");
1223                 return 0;
1224         }
1225         cfs_spin_lock(&sbi->ll_process_lock);
1226
1227         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
1228                    now.tv_sec, now.tv_usec);
1229         seq_printf(seq, "%3s %10s %14s %14s %17s %17s %14s\n",
1230                    "R/W", "PID", "RANGE START", "RANGE END",
1231                    "SMALLEST EXTENT", "LARGEST EXTENT", "OFFSET");
1232         /* We stored the discontiguous offsets here; print them first */
1233         for(i = 0; i < LL_OFFSET_HIST_MAX; i++) {
1234                 if (offset[i].rw_pid != 0)
1235                         seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
1236                                    offset[i].rw_op ? 'W' : 'R',
1237                                    offset[i].rw_pid,
1238                                    offset[i].rw_range_start,
1239                                    offset[i].rw_range_end,
1240                                    (unsigned long)offset[i].rw_smallest_extent,
1241                                    (unsigned long)offset[i].rw_largest_extent,
1242                                    offset[i].rw_offset);
1243         }
1244         /* Then print the current offsets for each process */
1245         for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1246                 if (process[i].rw_pid != 0)
1247                         seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
1248                                    process[i].rw_op ? 'W' : 'R',
1249                                    process[i].rw_pid,
1250                                    process[i].rw_range_start,
1251                                    process[i].rw_last_file_pos,
1252                                    (unsigned long)process[i].rw_smallest_extent,
1253                                    (unsigned long)process[i].rw_largest_extent,
1254                                    process[i].rw_offset);
1255         }
1256         cfs_spin_unlock(&sbi->ll_process_lock);
1257
1258         return 0;
1259 }
1260
1261 static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf,
1262                                        size_t len, loff_t *off)
1263 {
1264         struct seq_file *seq = file->private_data;
1265         struct ll_sb_info *sbi = seq->private;
1266         struct ll_rw_process_info *process_info = sbi->ll_rw_process_info;
1267         struct ll_rw_process_info *offset_info = sbi->ll_rw_offset_info;
1268         int value = 1, rc = 0;
1269
1270         rc = lprocfs_write_helper(buf, len, &value);
1271
1272         if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
1273                            strcmp(buf, "Disabled") == 0))
1274                 value = 0;
1275
1276         if (value == 0)
1277                 sbi->ll_rw_stats_on = 0;
1278         else
1279                 sbi->ll_rw_stats_on = 1;
1280
1281         cfs_spin_lock(&sbi->ll_process_lock);
1282         sbi->ll_offset_process_count = 0;
1283         sbi->ll_rw_offset_entry_count = 0;
1284         memset(process_info, 0, sizeof(struct ll_rw_process_info) *
1285                LL_PROCESS_HIST_MAX);
1286         memset(offset_info, 0, sizeof(struct ll_rw_process_info) *
1287                LL_OFFSET_HIST_MAX);
1288         cfs_spin_unlock(&sbi->ll_process_lock);
1289
1290         return len;
1291 }
1292
1293 LPROC_SEQ_FOPS(ll_rw_offset_stats);
1294
1295 void lprocfs_llite_init_vars(struct lprocfs_static_vars *lvars)
1296 {
1297     lvars->module_vars  = NULL;
1298     lvars->obd_vars     = lprocfs_llite_obd_vars;
1299 }
1300 #endif /* LPROCFS */