Whamcloud - gitweb
LU-673 llite: Add some metadata stats, fix some file stats.
[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_READ_BYTES,     LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
699                                    "read_bytes" },
700         { LPROC_LL_WRITE_BYTES,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
701                                    "write_bytes" },
702         { LPROC_LL_BRW_READ,       LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
703                                    "brw_read" },
704         { LPROC_LL_BRW_WRITE,      LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
705                                    "brw_write" },
706         { LPROC_LL_OSC_READ,       LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
707                                    "osc_read" },
708         { LPROC_LL_OSC_WRITE,      LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
709                                    "osc_write" },
710         { LPROC_LL_IOCTL,          LPROCFS_TYPE_REGS, "ioctl" },
711         { LPROC_LL_OPEN,           LPROCFS_TYPE_REGS, "open" },
712         { LPROC_LL_RELEASE,        LPROCFS_TYPE_REGS, "close" },
713         { LPROC_LL_MAP,            LPROCFS_TYPE_REGS, "mmap" },
714         { LPROC_LL_LLSEEK,         LPROCFS_TYPE_REGS, "seek" },
715         { LPROC_LL_FSYNC,          LPROCFS_TYPE_REGS, "fsync" },
716         { LPROC_LL_READDIR,        LPROCFS_TYPE_REGS, "readdir" },
717         /* inode operation */
718         { LPROC_LL_SETATTR,        LPROCFS_TYPE_REGS, "setattr" },
719         { LPROC_LL_TRUNC,          LPROCFS_TYPE_REGS, "truncate" },
720         { LPROC_LL_FLOCK,          LPROCFS_TYPE_REGS, "flock" },
721         { LPROC_LL_GETATTR,        LPROCFS_TYPE_REGS, "getattr" },
722         /* dir inode operation */
723         { LPROC_LL_CREATE,         LPROCFS_TYPE_REGS, "create" },
724         { LPROC_LL_LINK,           LPROCFS_TYPE_REGS, "link" },
725         { LPROC_LL_UNLINK,         LPROCFS_TYPE_REGS, "unlink" },
726         { LPROC_LL_SYMLINK,        LPROCFS_TYPE_REGS, "symlink" },
727         { LPROC_LL_MKDIR,          LPROCFS_TYPE_REGS, "mkdir" },
728         { LPROC_LL_RMDIR,          LPROCFS_TYPE_REGS, "rmdir" },
729         { LPROC_LL_MKNOD,          LPROCFS_TYPE_REGS, "mknod" },
730         { LPROC_LL_RENAME,         LPROCFS_TYPE_REGS, "rename" },
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 };
740
741 void ll_stats_ops_tally(struct ll_sb_info *sbi, int op, int count)
742 {
743         if (!sbi->ll_stats)
744                 return;
745         if (sbi->ll_stats_track_type == STATS_TRACK_ALL)
746                 lprocfs_counter_add(sbi->ll_stats, op, count);
747         else if (sbi->ll_stats_track_type == STATS_TRACK_PID &&
748                  sbi->ll_stats_track_id == current->pid)
749                 lprocfs_counter_add(sbi->ll_stats, op, count);
750         else if (sbi->ll_stats_track_type == STATS_TRACK_PPID &&
751                  sbi->ll_stats_track_id == current->parent->pid)
752                 lprocfs_counter_add(sbi->ll_stats, op, count);
753         else if (sbi->ll_stats_track_type == STATS_TRACK_GID &&
754                  sbi->ll_stats_track_id == cfs_curproc_gid())
755                 lprocfs_counter_add(sbi->ll_stats, op, count);
756 }
757 EXPORT_SYMBOL(ll_stats_ops_tally);
758
759 static const char *ra_stat_string[] = {
760         [RA_STAT_HIT] = "hits",
761         [RA_STAT_MISS] = "misses",
762         [RA_STAT_DISTANT_READPAGE] = "readpage not consecutive",
763         [RA_STAT_MISS_IN_WINDOW] = "miss inside window",
764         [RA_STAT_FAILED_GRAB_PAGE] = "failed grab_cache_page",
765         [RA_STAT_FAILED_MATCH] = "failed lock match",
766         [RA_STAT_DISCARDED] = "read but discarded",
767         [RA_STAT_ZERO_LEN] = "zero length file",
768         [RA_STAT_ZERO_WINDOW] = "zero size window",
769         [RA_STAT_EOF] = "read-ahead to EOF",
770         [RA_STAT_MAX_IN_FLIGHT] = "hit max r-a issue",
771         [RA_STAT_WRONG_GRAB_PAGE] = "wrong page from grab_cache_page",
772 };
773
774
775 int lprocfs_register_mountpoint(struct proc_dir_entry *parent,
776                                 struct super_block *sb, char *osc, char *mdc)
777 {
778         struct lprocfs_vars lvars[2];
779         struct lustre_sb_info *lsi = s2lsi(sb);
780         struct ll_sb_info *sbi = ll_s2sbi(sb);
781         struct obd_device *obd;
782         char name[MAX_STRING_SIZE + 1], *ptr;
783         int err, id, len, rc;
784         ENTRY;
785
786         memset(lvars, 0, sizeof(lvars));
787
788         name[MAX_STRING_SIZE] = '\0';
789         lvars[0].name = name;
790
791         LASSERT(sbi != NULL);
792         LASSERT(mdc != NULL);
793         LASSERT(osc != NULL);
794
795         /* Get fsname */
796         len = strlen(lsi->lsi_lmd->lmd_profile);
797         ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-');
798         if (ptr && (strcmp(ptr, "-client") == 0))
799                 len -= 7;
800
801         /* Mount info */
802         snprintf(name, MAX_STRING_SIZE, "%.*s-%p", len,
803                  lsi->lsi_lmd->lmd_profile, sb);
804
805         sbi->ll_proc_root = lprocfs_register(name, parent, NULL, NULL);
806         if (IS_ERR(sbi->ll_proc_root)) {
807                 err = PTR_ERR(sbi->ll_proc_root);
808                 sbi->ll_proc_root = NULL;
809                 RETURN(err);
810         }
811
812         rc = lprocfs_seq_create(sbi->ll_proc_root, "dump_page_cache", 0444,
813                                 &vvp_dump_pgcache_file_ops, sbi);
814         if (rc)
815                 CWARN("Error adding the dump_page_cache file\n");
816
817         rc = lprocfs_seq_create(sbi->ll_proc_root, "extents_stats", 0644,
818                                 &ll_rw_extents_stats_fops, sbi);
819         if (rc)
820                 CWARN("Error adding the extent_stats file\n");
821
822         rc = lprocfs_seq_create(sbi->ll_proc_root, "extents_stats_per_process",
823                                 0644, &ll_rw_extents_stats_pp_fops, sbi);
824         if (rc)
825                 CWARN("Error adding the extents_stats_per_process file\n");
826
827         rc = lprocfs_seq_create(sbi->ll_proc_root, "offset_stats", 0644,
828                                 &ll_rw_offset_stats_fops, sbi);
829         if (rc)
830                 CWARN("Error adding the offset_stats file\n");
831
832         /* File operations stats */
833         sbi->ll_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES,
834                                             LPROCFS_STATS_FLAG_NONE);
835         if (sbi->ll_stats == NULL)
836                 GOTO(out, err = -ENOMEM);
837         /* do counter init */
838         for (id = 0; id < LPROC_LL_FILE_OPCODES; id++) {
839                 __u32 type = llite_opcode_table[id].type;
840                 void *ptr = NULL;
841                 if (type & LPROCFS_TYPE_REGS)
842                         ptr = "regs";
843                 else if (type & LPROCFS_TYPE_BYTES)
844                         ptr = "bytes";
845                 else if (type & LPROCFS_TYPE_PAGES)
846                         ptr = "pages";
847                 lprocfs_counter_init(sbi->ll_stats,
848                                      llite_opcode_table[id].opcode,
849                                      (type & LPROCFS_CNTR_AVGMINMAX),
850                                      llite_opcode_table[id].opname, ptr);
851         }
852         err = lprocfs_register_stats(sbi->ll_proc_root, "stats", sbi->ll_stats);
853         if (err)
854                 GOTO(out, err);
855
856         sbi->ll_ra_stats = lprocfs_alloc_stats(ARRAY_SIZE(ra_stat_string),
857                                                LPROCFS_STATS_FLAG_NONE);
858         if (sbi->ll_ra_stats == NULL)
859                 GOTO(out, err = -ENOMEM);
860
861         for (id = 0; id < ARRAY_SIZE(ra_stat_string); id++)
862                 lprocfs_counter_init(sbi->ll_ra_stats, id, 0,
863                                      ra_stat_string[id], "pages");
864         err = lprocfs_register_stats(sbi->ll_proc_root, "read_ahead_stats",
865                                      sbi->ll_ra_stats);
866         if (err)
867                 GOTO(out, err);
868
869
870         err = lprocfs_add_vars(sbi->ll_proc_root, lprocfs_llite_obd_vars, sb);
871         if (err)
872                 GOTO(out, err);
873
874         /* MDC info */
875         obd = class_name2obd(mdc);
876
877         LASSERT(obd != NULL);
878         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
879         LASSERT(obd->obd_type->typ_name != NULL);
880
881         snprintf(name, MAX_STRING_SIZE, "%s/common_name",
882                  obd->obd_type->typ_name);
883         lvars[0].read_fptr = lprocfs_rd_name;
884         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
885         if (err)
886                 GOTO(out, err);
887
888         snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name);
889         lvars[0].read_fptr = lprocfs_rd_uuid;
890         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
891         if (err)
892                 GOTO(out, err);
893
894         /* OSC */
895         obd = class_name2obd(osc);
896
897         LASSERT(obd != NULL);
898         LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
899         LASSERT(obd->obd_type->typ_name != NULL);
900
901         snprintf(name, MAX_STRING_SIZE, "%s/common_name",
902                  obd->obd_type->typ_name);
903         lvars[0].read_fptr = lprocfs_rd_name;
904         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
905         if (err)
906                 GOTO(out, err);
907
908         snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name);
909         lvars[0].read_fptr = lprocfs_rd_uuid;
910         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
911 out:
912         if (err) {
913                 lprocfs_remove(&sbi->ll_proc_root);
914                 lprocfs_free_stats(&sbi->ll_ra_stats);
915                 lprocfs_free_stats(&sbi->ll_stats);
916         }
917         RETURN(err);
918 }
919
920 void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi)
921 {
922         if (sbi->ll_proc_root) {
923                 lprocfs_remove(&sbi->ll_proc_root);
924                 lprocfs_free_stats(&sbi->ll_ra_stats);
925                 lprocfs_free_stats(&sbi->ll_stats);
926         }
927 }
928 #undef MAX_STRING_SIZE
929
930 #define pct(a,b) (b ? a * 100 / b : 0)
931
932 static void ll_display_extents_info(struct ll_rw_extents_info *io_extents,
933                                    struct seq_file *seq, int which)
934 {
935         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
936         unsigned long start, end, r, w;
937         char *unitp = "KMGTPEZY";
938         int i, units = 10;
939         struct per_process_info *pp_info = &io_extents->pp_extents[which];
940
941         read_cum = 0;
942         write_cum = 0;
943         start = 0;
944
945         for(i = 0; i < LL_HIST_MAX; i++) {
946                 read_tot += pp_info->pp_r_hist.oh_buckets[i];
947                 write_tot += pp_info->pp_w_hist.oh_buckets[i];
948         }
949
950         for(i = 0; i < LL_HIST_MAX; i++) {
951                 r = pp_info->pp_r_hist.oh_buckets[i];
952                 w = pp_info->pp_w_hist.oh_buckets[i];
953                 read_cum += r;
954                 write_cum += w;
955                 end = 1 << (i + LL_HIST_START - units);
956                 seq_printf(seq, "%4lu%c - %4lu%c%c: %14lu %4lu %4lu  | "
957                            "%14lu %4lu %4lu\n", start, *unitp, end, *unitp,
958                            (i == LL_HIST_MAX - 1) ? '+' : ' ',
959                            r, pct(r, read_tot), pct(read_cum, read_tot),
960                            w, pct(w, write_tot), pct(write_cum, write_tot));
961                 start = end;
962                 if (start == 1<<10) {
963                         start = 1;
964                         units += 10;
965                         unitp++;
966                 }
967                 if (read_cum == read_tot && write_cum == write_tot)
968                         break;
969         }
970 }
971
972 static int ll_rw_extents_stats_pp_seq_show(struct seq_file *seq, void *v)
973 {
974         struct timeval now;
975         struct ll_sb_info *sbi = seq->private;
976         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
977         int k;
978
979         cfs_gettimeofday(&now);
980
981         if (!sbi->ll_rw_stats_on) {
982                 seq_printf(seq, "disabled\n"
983                                 "write anything in this file to activate, "
984                                 "then 0 or \"[D/d]isabled\" to deactivate\n");
985                 return 0;
986         }
987         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
988                    now.tv_sec, now.tv_usec);
989         seq_printf(seq, "%15s %19s       | %20s\n", " ", "read", "write");
990         seq_printf(seq, "%13s   %14s %4s %4s  | %14s %4s %4s\n",
991                    "extents", "calls", "%", "cum%",
992                    "calls", "%", "cum%");
993         cfs_spin_lock(&sbi->ll_pp_extent_lock);
994         for(k = 0; k < LL_PROCESS_HIST_MAX; k++) {
995                 if(io_extents->pp_extents[k].pid != 0) {
996                         seq_printf(seq, "\nPID: %d\n",
997                                    io_extents->pp_extents[k].pid);
998                         ll_display_extents_info(io_extents, seq, k);
999                 }
1000         }
1001         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1002         return 0;
1003 }
1004
1005 static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
1006                                                 const char *buf, size_t len,
1007                                                 loff_t *off)
1008 {
1009         struct seq_file *seq = file->private_data;
1010         struct ll_sb_info *sbi = seq->private;
1011         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1012         int i;
1013         int value = 1, rc = 0;
1014
1015         rc = lprocfs_write_helper(buf, len, &value);
1016         if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
1017                        strcmp(buf, "Disabled") == 0))
1018                 value = 0;
1019
1020         if (value == 0)
1021                 sbi->ll_rw_stats_on = 0;
1022         else
1023                 sbi->ll_rw_stats_on = 1;
1024
1025         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1026         for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1027                 io_extents->pp_extents[i].pid = 0;
1028                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist);
1029                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist);
1030         }
1031         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1032         return len;
1033 }
1034
1035 LPROC_SEQ_FOPS(ll_rw_extents_stats_pp);
1036
1037 static int ll_rw_extents_stats_seq_show(struct seq_file *seq, void *v)
1038 {
1039         struct timeval now;
1040         struct ll_sb_info *sbi = seq->private;
1041         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1042
1043         cfs_gettimeofday(&now);
1044
1045         if (!sbi->ll_rw_stats_on) {
1046                 seq_printf(seq, "disabled\n"
1047                                 "write anything in this file to activate, "
1048                                 "then 0 or \"[D/d]isabled\" to deactivate\n");
1049                 return 0;
1050         }
1051         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
1052                    now.tv_sec, now.tv_usec);
1053
1054         seq_printf(seq, "%15s %19s       | %20s\n", " ", "read", "write");
1055         seq_printf(seq, "%13s   %14s %4s %4s  | %14s %4s %4s\n",
1056                    "extents", "calls", "%", "cum%",
1057                    "calls", "%", "cum%");
1058         cfs_spin_lock(&sbi->ll_lock);
1059         ll_display_extents_info(io_extents, seq, LL_PROCESS_HIST_MAX);
1060         cfs_spin_unlock(&sbi->ll_lock);
1061
1062         return 0;
1063 }
1064
1065 static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf,
1066                                         size_t len, loff_t *off)
1067 {
1068         struct seq_file *seq = file->private_data;
1069         struct ll_sb_info *sbi = seq->private;
1070         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1071         int i;
1072         int value = 1, rc = 0;
1073
1074         rc = lprocfs_write_helper(buf, len, &value);
1075         if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
1076                        strcmp(buf, "Disabled") == 0))
1077                 value = 0;
1078
1079         if (value == 0)
1080                 sbi->ll_rw_stats_on = 0;
1081         else
1082                 sbi->ll_rw_stats_on = 1;
1083         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1084         for(i = 0; i <= LL_PROCESS_HIST_MAX; i++)
1085         {
1086                 io_extents->pp_extents[i].pid = 0;
1087                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist);
1088                 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist);
1089         }
1090         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1091
1092         return len;
1093 }
1094
1095 LPROC_SEQ_FOPS(ll_rw_extents_stats);
1096
1097 void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
1098                        struct ll_file_data *file, loff_t pos,
1099                        size_t count, int rw)
1100 {
1101         int i, cur = -1;
1102         struct ll_rw_process_info *process;
1103         struct ll_rw_process_info *offset;
1104         int *off_count = &sbi->ll_rw_offset_entry_count;
1105         int *process_count = &sbi->ll_offset_process_count;
1106         struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
1107
1108         if(!sbi->ll_rw_stats_on)
1109                 return;
1110         process = sbi->ll_rw_process_info;
1111         offset = sbi->ll_rw_offset_info;
1112
1113         cfs_spin_lock(&sbi->ll_pp_extent_lock);
1114         /* Extent statistics */
1115         for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1116                 if(io_extents->pp_extents[i].pid == pid) {
1117                         cur = i;
1118                         break;
1119                 }
1120         }
1121
1122         if (cur == -1) {
1123                 /* new process */
1124                 sbi->ll_extent_process_count =
1125                         (sbi->ll_extent_process_count + 1) % LL_PROCESS_HIST_MAX;
1126                 cur = sbi->ll_extent_process_count;
1127                 io_extents->pp_extents[cur].pid = pid;
1128                 lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_r_hist);
1129                 lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_w_hist);
1130         }
1131
1132         for(i = 0; (count >= (1 << LL_HIST_START << i)) &&
1133              (i < (LL_HIST_MAX - 1)); i++);
1134         if (rw == 0) {
1135                 io_extents->pp_extents[cur].pp_r_hist.oh_buckets[i]++;
1136                 io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_r_hist.oh_buckets[i]++;
1137         } else {
1138                 io_extents->pp_extents[cur].pp_w_hist.oh_buckets[i]++;
1139                 io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_w_hist.oh_buckets[i]++;
1140         }
1141         cfs_spin_unlock(&sbi->ll_pp_extent_lock);
1142
1143         cfs_spin_lock(&sbi->ll_process_lock);
1144         /* Offset statistics */
1145         for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1146                 if (process[i].rw_pid == pid) {
1147                         if (process[i].rw_last_file != file) {
1148                                 process[i].rw_range_start = pos;
1149                                 process[i].rw_last_file_pos = pos + count;
1150                                 process[i].rw_smallest_extent = count;
1151                                 process[i].rw_largest_extent = count;
1152                                 process[i].rw_offset = 0;
1153                                 process[i].rw_last_file = file;
1154                                 cfs_spin_unlock(&sbi->ll_process_lock);
1155                                 return;
1156                         }
1157                         if (process[i].rw_last_file_pos != pos) {
1158                                 *off_count =
1159                                     (*off_count + 1) % LL_OFFSET_HIST_MAX;
1160                                 offset[*off_count].rw_op = process[i].rw_op;
1161                                 offset[*off_count].rw_pid = pid;
1162                                 offset[*off_count].rw_range_start =
1163                                         process[i].rw_range_start;
1164                                 offset[*off_count].rw_range_end =
1165                                         process[i].rw_last_file_pos;
1166                                 offset[*off_count].rw_smallest_extent =
1167                                         process[i].rw_smallest_extent;
1168                                 offset[*off_count].rw_largest_extent =
1169                                         process[i].rw_largest_extent;
1170                                 offset[*off_count].rw_offset =
1171                                         process[i].rw_offset;
1172                                 process[i].rw_op = rw;
1173                                 process[i].rw_range_start = pos;
1174                                 process[i].rw_smallest_extent = count;
1175                                 process[i].rw_largest_extent = count;
1176                                 process[i].rw_offset = pos -
1177                                         process[i].rw_last_file_pos;
1178                         }
1179                         if(process[i].rw_smallest_extent > count)
1180                                 process[i].rw_smallest_extent = count;
1181                         if(process[i].rw_largest_extent < count)
1182                                 process[i].rw_largest_extent = count;
1183                         process[i].rw_last_file_pos = pos + count;
1184                         cfs_spin_unlock(&sbi->ll_process_lock);
1185                         return;
1186                 }
1187         }
1188         *process_count = (*process_count + 1) % LL_PROCESS_HIST_MAX;
1189         process[*process_count].rw_pid = pid;
1190         process[*process_count].rw_op = rw;
1191         process[*process_count].rw_range_start = pos;
1192         process[*process_count].rw_last_file_pos = pos + count;
1193         process[*process_count].rw_smallest_extent = count;
1194         process[*process_count].rw_largest_extent = count;
1195         process[*process_count].rw_offset = 0;
1196         process[*process_count].rw_last_file = file;
1197         cfs_spin_unlock(&sbi->ll_process_lock);
1198 }
1199
1200 static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
1201 {
1202         struct timeval now;
1203         struct ll_sb_info *sbi = seq->private;
1204         struct ll_rw_process_info *offset = sbi->ll_rw_offset_info;
1205         struct ll_rw_process_info *process = sbi->ll_rw_process_info;
1206         int i;
1207
1208         cfs_gettimeofday(&now);
1209
1210         if (!sbi->ll_rw_stats_on) {
1211                 seq_printf(seq, "disabled\n"
1212                                 "write anything in this file to activate, "
1213                                 "then 0 or \"[D/d]isabled\" to deactivate\n");
1214                 return 0;
1215         }
1216         cfs_spin_lock(&sbi->ll_process_lock);
1217
1218         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
1219                    now.tv_sec, now.tv_usec);
1220         seq_printf(seq, "%3s %10s %14s %14s %17s %17s %14s\n",
1221                    "R/W", "PID", "RANGE START", "RANGE END",
1222                    "SMALLEST EXTENT", "LARGEST EXTENT", "OFFSET");
1223         /* We stored the discontiguous offsets here; print them first */
1224         for(i = 0; i < LL_OFFSET_HIST_MAX; i++) {
1225                 if (offset[i].rw_pid != 0)
1226                         seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
1227                                    offset[i].rw_op ? 'W' : 'R',
1228                                    offset[i].rw_pid,
1229                                    offset[i].rw_range_start,
1230                                    offset[i].rw_range_end,
1231                                    (unsigned long)offset[i].rw_smallest_extent,
1232                                    (unsigned long)offset[i].rw_largest_extent,
1233                                    offset[i].rw_offset);
1234         }
1235         /* Then print the current offsets for each process */
1236         for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
1237                 if (process[i].rw_pid != 0)
1238                         seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
1239                                    process[i].rw_op ? 'W' : 'R',
1240                                    process[i].rw_pid,
1241                                    process[i].rw_range_start,
1242                                    process[i].rw_last_file_pos,
1243                                    (unsigned long)process[i].rw_smallest_extent,
1244                                    (unsigned long)process[i].rw_largest_extent,
1245                                    process[i].rw_offset);
1246         }
1247         cfs_spin_unlock(&sbi->ll_process_lock);
1248
1249         return 0;
1250 }
1251
1252 static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf,
1253                                        size_t len, loff_t *off)
1254 {
1255         struct seq_file *seq = file->private_data;
1256         struct ll_sb_info *sbi = seq->private;
1257         struct ll_rw_process_info *process_info = sbi->ll_rw_process_info;
1258         struct ll_rw_process_info *offset_info = sbi->ll_rw_offset_info;
1259         int value = 1, rc = 0;
1260
1261         rc = lprocfs_write_helper(buf, len, &value);
1262
1263         if (rc < 0 && (strcmp(buf, "disabled") == 0 ||
1264                            strcmp(buf, "Disabled") == 0))
1265                 value = 0;
1266
1267         if (value == 0)
1268                 sbi->ll_rw_stats_on = 0;
1269         else
1270                 sbi->ll_rw_stats_on = 1;
1271
1272         cfs_spin_lock(&sbi->ll_process_lock);
1273         sbi->ll_offset_process_count = 0;
1274         sbi->ll_rw_offset_entry_count = 0;
1275         memset(process_info, 0, sizeof(struct ll_rw_process_info) *
1276                LL_PROCESS_HIST_MAX);
1277         memset(offset_info, 0, sizeof(struct ll_rw_process_info) *
1278                LL_OFFSET_HIST_MAX);
1279         cfs_spin_unlock(&sbi->ll_process_lock);
1280
1281         return len;
1282 }
1283
1284 LPROC_SEQ_FOPS(ll_rw_offset_stats);
1285
1286 void lprocfs_llite_init_vars(struct lprocfs_static_vars *lvars)
1287 {
1288     lvars->module_vars  = NULL;
1289     lvars->obd_vars     = lprocfs_llite_obd_vars;
1290 }
1291 #endif /* LPROCFS */