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