4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
27 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 #define DEBUG_SUBSYSTEM S_LLITE
38 #include "../include/lustre_lite.h"
39 #include "../include/lprocfs_status.h"
40 #include <linux/seq_file.h>
41 #include "../include/obd_support.h"
43 #include "llite_internal.h"
44 #include "vvp_internal.h"
46 /* /proc/lustre/llite mount point registration */
47 static struct file_operations ll_rw_extents_stats_fops
;
48 static struct file_operations ll_rw_extents_stats_pp_fops
;
49 static struct file_operations ll_rw_offset_stats_fops
;
51 static int ll_blksize_seq_show(struct seq_file
*m
, void *v
)
53 struct super_block
*sb
= (struct super_block
*)m
->private;
54 struct obd_statfs osfs
;
58 rc
= ll_statfs_internal(sb
, &osfs
,
59 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
62 rc
= seq_printf(m
, "%u\n", osfs
.os_bsize
);
66 LPROC_SEQ_FOPS_RO(ll_blksize
);
68 static int ll_kbytestotal_seq_show(struct seq_file
*m
, void *v
)
70 struct super_block
*sb
= (struct super_block
*)m
->private;
71 struct obd_statfs osfs
;
75 rc
= ll_statfs_internal(sb
, &osfs
,
76 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
79 __u32 blk_size
= osfs
.os_bsize
>> 10;
80 __u64 result
= osfs
.os_blocks
;
82 while (blk_size
>>= 1)
85 rc
= seq_printf(m
, "%llu\n", result
);
89 LPROC_SEQ_FOPS_RO(ll_kbytestotal
);
91 static int ll_kbytesfree_seq_show(struct seq_file
*m
, void *v
)
93 struct super_block
*sb
= (struct super_block
*)m
->private;
94 struct obd_statfs osfs
;
98 rc
= ll_statfs_internal(sb
, &osfs
,
99 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
102 __u32 blk_size
= osfs
.os_bsize
>> 10;
103 __u64 result
= osfs
.os_bfree
;
105 while (blk_size
>>= 1)
108 rc
= seq_printf(m
, "%llu\n", result
);
112 LPROC_SEQ_FOPS_RO(ll_kbytesfree
);
114 static int ll_kbytesavail_seq_show(struct seq_file
*m
, void *v
)
116 struct super_block
*sb
= (struct super_block
*)m
->private;
117 struct obd_statfs osfs
;
121 rc
= ll_statfs_internal(sb
, &osfs
,
122 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
125 __u32 blk_size
= osfs
.os_bsize
>> 10;
126 __u64 result
= osfs
.os_bavail
;
128 while (blk_size
>>= 1)
131 rc
= seq_printf(m
, "%llu\n", result
);
135 LPROC_SEQ_FOPS_RO(ll_kbytesavail
);
137 static int ll_filestotal_seq_show(struct seq_file
*m
, void *v
)
139 struct super_block
*sb
= (struct super_block
*)m
->private;
140 struct obd_statfs osfs
;
144 rc
= ll_statfs_internal(sb
, &osfs
,
145 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
148 rc
= seq_printf(m
, "%llu\n", osfs
.os_files
);
151 LPROC_SEQ_FOPS_RO(ll_filestotal
);
153 static int ll_filesfree_seq_show(struct seq_file
*m
, void *v
)
155 struct super_block
*sb
= (struct super_block
*)m
->private;
156 struct obd_statfs osfs
;
160 rc
= ll_statfs_internal(sb
, &osfs
,
161 cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS
),
164 rc
= seq_printf(m
, "%llu\n", osfs
.os_ffree
);
167 LPROC_SEQ_FOPS_RO(ll_filesfree
);
169 static int ll_client_type_seq_show(struct seq_file
*m
, void *v
)
171 struct ll_sb_info
*sbi
= ll_s2sbi((struct super_block
*)m
->private);
174 LASSERT(sbi
!= NULL
);
176 if (sbi
->ll_flags
& LL_SBI_RMT_CLIENT
)
177 rc
= seq_printf(m
, "remote client\n");
179 rc
= seq_printf(m
, "local client\n");
183 LPROC_SEQ_FOPS_RO(ll_client_type
);
185 static int ll_fstype_seq_show(struct seq_file
*m
, void *v
)
187 struct super_block
*sb
= (struct super_block
*)m
->private;
190 return seq_printf(m
, "%s\n", sb
->s_type
->name
);
192 LPROC_SEQ_FOPS_RO(ll_fstype
);
194 static int ll_sb_uuid_seq_show(struct seq_file
*m
, void *v
)
196 struct super_block
*sb
= (struct super_block
*)m
->private;
199 return seq_printf(m
, "%s\n", ll_s2sbi(sb
)->ll_sb_uuid
.uuid
);
201 LPROC_SEQ_FOPS_RO(ll_sb_uuid
);
203 static int ll_site_stats_seq_show(struct seq_file
*m
, void *v
)
205 struct super_block
*sb
= m
->private;
208 * See description of statistical counters in struct cl_site, and
211 return cl_site_stats_print(lu2cl_site(ll_s2sbi(sb
)->ll_site
), m
);
213 LPROC_SEQ_FOPS_RO(ll_site_stats
);
215 static int ll_max_readahead_mb_seq_show(struct seq_file
*m
, void *v
)
217 struct super_block
*sb
= m
->private;
218 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
222 spin_lock(&sbi
->ll_lock
);
223 pages_number
= sbi
->ll_ra_info
.ra_max_pages
;
224 spin_unlock(&sbi
->ll_lock
);
226 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
227 return lprocfs_seq_read_frac_helper(m
, pages_number
, mult
);
230 static ssize_t
ll_max_readahead_mb_seq_write(struct file
*file
,
231 const char __user
*buffer
,
232 size_t count
, loff_t
*off
)
234 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
235 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
236 int mult
, rc
, pages_number
;
238 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
239 rc
= lprocfs_write_frac_helper(buffer
, count
, &pages_number
, mult
);
243 if (pages_number
< 0 || pages_number
> totalram_pages
/ 2) {
244 CERROR("can't set file readahead more than %lu MB\n",
245 totalram_pages
>> (20 - PAGE_CACHE_SHIFT
+ 1)); /*1/2 of RAM*/
249 spin_lock(&sbi
->ll_lock
);
250 sbi
->ll_ra_info
.ra_max_pages
= pages_number
;
251 spin_unlock(&sbi
->ll_lock
);
255 LPROC_SEQ_FOPS(ll_max_readahead_mb
);
257 static int ll_max_readahead_per_file_mb_seq_show(struct seq_file
*m
, void *v
)
259 struct super_block
*sb
= m
->private;
260 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
264 spin_lock(&sbi
->ll_lock
);
265 pages_number
= sbi
->ll_ra_info
.ra_max_pages_per_file
;
266 spin_unlock(&sbi
->ll_lock
);
268 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
269 return lprocfs_seq_read_frac_helper(m
, pages_number
, mult
);
272 static ssize_t
ll_max_readahead_per_file_mb_seq_write(struct file
*file
,
273 const char __user
*buffer
,
274 size_t count
, loff_t
*off
)
276 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
277 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
278 int mult
, rc
, pages_number
;
280 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
281 rc
= lprocfs_write_frac_helper(buffer
, count
, &pages_number
, mult
);
285 if (pages_number
< 0 ||
286 pages_number
> sbi
->ll_ra_info
.ra_max_pages
) {
287 CERROR("can't set file readahead more than max_read_ahead_mb %lu MB\n",
288 sbi
->ll_ra_info
.ra_max_pages
);
292 spin_lock(&sbi
->ll_lock
);
293 sbi
->ll_ra_info
.ra_max_pages_per_file
= pages_number
;
294 spin_unlock(&sbi
->ll_lock
);
298 LPROC_SEQ_FOPS(ll_max_readahead_per_file_mb
);
300 static int ll_max_read_ahead_whole_mb_seq_show(struct seq_file
*m
, void *unused
)
302 struct super_block
*sb
= m
->private;
303 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
307 spin_lock(&sbi
->ll_lock
);
308 pages_number
= sbi
->ll_ra_info
.ra_max_read_ahead_whole_pages
;
309 spin_unlock(&sbi
->ll_lock
);
311 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
312 return lprocfs_seq_read_frac_helper(m
, pages_number
, mult
);
315 static ssize_t
ll_max_read_ahead_whole_mb_seq_write(struct file
*file
,
316 const char __user
*buffer
,
317 size_t count
, loff_t
*off
)
319 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
320 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
321 int mult
, rc
, pages_number
;
323 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
324 rc
= lprocfs_write_frac_helper(buffer
, count
, &pages_number
, mult
);
328 /* Cap this at the current max readahead window size, the readahead
329 * algorithm does this anyway so it's pointless to set it larger. */
330 if (pages_number
< 0 ||
331 pages_number
> sbi
->ll_ra_info
.ra_max_pages_per_file
) {
332 CERROR("can't set max_read_ahead_whole_mb more than max_read_ahead_per_file_mb: %lu\n",
333 sbi
->ll_ra_info
.ra_max_pages_per_file
>> (20 - PAGE_CACHE_SHIFT
));
337 spin_lock(&sbi
->ll_lock
);
338 sbi
->ll_ra_info
.ra_max_read_ahead_whole_pages
= pages_number
;
339 spin_unlock(&sbi
->ll_lock
);
343 LPROC_SEQ_FOPS(ll_max_read_ahead_whole_mb
);
345 static int ll_max_cached_mb_seq_show(struct seq_file
*m
, void *v
)
347 struct super_block
*sb
= m
->private;
348 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
349 struct cl_client_cache
*cache
= &sbi
->ll_cache
;
350 int shift
= 20 - PAGE_CACHE_SHIFT
;
354 max_cached_mb
= cache
->ccc_lru_max
>> shift
;
355 unused_mb
= atomic_read(&cache
->ccc_lru_left
) >> shift
;
358 "max_cached_mb: %d\n"
361 "reclaim_count: %u\n",
362 atomic_read(&cache
->ccc_users
),
364 max_cached_mb
- unused_mb
,
366 cache
->ccc_lru_shrinkers
);
369 static ssize_t
ll_max_cached_mb_seq_write(struct file
*file
,
370 const char __user
*buffer
,
371 size_t count
, loff_t
*off
)
373 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
374 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
375 struct cl_client_cache
*cache
= &sbi
->ll_cache
;
376 int mult
, rc
, pages_number
;
381 if (count
>= sizeof(kernbuf
))
384 if (copy_from_user(kernbuf
, buffer
, count
))
388 mult
= 1 << (20 - PAGE_CACHE_SHIFT
);
389 buffer
+= lprocfs_find_named_value(kernbuf
, "max_cached_mb:", &count
) -
391 rc
= lprocfs_write_frac_helper(buffer
, count
, &pages_number
, mult
);
395 if (pages_number
< 0 || pages_number
> totalram_pages
) {
396 CERROR("%s: can't set max cache more than %lu MB\n",
397 ll_get_fsname(sb
, NULL
, 0),
398 totalram_pages
>> (20 - PAGE_CACHE_SHIFT
));
402 spin_lock(&sbi
->ll_lock
);
403 diff
= pages_number
- cache
->ccc_lru_max
;
404 spin_unlock(&sbi
->ll_lock
);
406 /* easy - add more LRU slots. */
408 atomic_add(diff
, &cache
->ccc_lru_left
);
417 /* reduce LRU budget from free slots. */
421 ov
= atomic_read(&cache
->ccc_lru_left
);
425 nv
= ov
> diff
? ov
- diff
: 0;
426 rc
= atomic_cmpxchg(&cache
->ccc_lru_left
, ov
, nv
);
427 if (likely(ov
== rc
)) {
437 if (sbi
->ll_dt_exp
== NULL
) { /* being initialized */
442 /* difficult - have to ask OSCs to drop LRU slots. */
444 rc
= obd_set_info_async(NULL
, sbi
->ll_dt_exp
,
445 sizeof(KEY_CACHE_LRU_SHRINK
),
446 KEY_CACHE_LRU_SHRINK
,
447 sizeof(tmp
), &tmp
, NULL
);
454 spin_lock(&sbi
->ll_lock
);
455 cache
->ccc_lru_max
= pages_number
;
456 spin_unlock(&sbi
->ll_lock
);
459 atomic_add(nrpages
, &cache
->ccc_lru_left
);
463 LPROC_SEQ_FOPS(ll_max_cached_mb
);
465 static int ll_checksum_seq_show(struct seq_file
*m
, void *v
)
467 struct super_block
*sb
= m
->private;
468 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
470 return seq_printf(m
, "%u\n", (sbi
->ll_flags
& LL_SBI_CHECKSUM
) ? 1 : 0);
473 static ssize_t
ll_checksum_seq_write(struct file
*file
,
474 const char __user
*buffer
,
475 size_t count
, loff_t
*off
)
477 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
478 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
485 rc
= lprocfs_write_helper(buffer
, count
, &val
);
489 sbi
->ll_flags
|= LL_SBI_CHECKSUM
;
491 sbi
->ll_flags
&= ~LL_SBI_CHECKSUM
;
493 rc
= obd_set_info_async(NULL
, sbi
->ll_dt_exp
, sizeof(KEY_CHECKSUM
),
494 KEY_CHECKSUM
, sizeof(val
), &val
, NULL
);
496 CWARN("Failed to set OSC checksum flags: %d\n", rc
);
500 LPROC_SEQ_FOPS(ll_checksum
);
502 static int ll_max_rw_chunk_seq_show(struct seq_file
*m
, void *v
)
504 struct super_block
*sb
= m
->private;
506 return seq_printf(m
, "%lu\n", ll_s2sbi(sb
)->ll_max_rw_chunk
);
509 static ssize_t
ll_max_rw_chunk_seq_write(struct file
*file
,
510 const char __user
*buffer
,
511 size_t count
, loff_t
*off
)
513 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
516 rc
= lprocfs_write_helper(buffer
, count
, &val
);
519 ll_s2sbi(sb
)->ll_max_rw_chunk
= val
;
522 LPROC_SEQ_FOPS(ll_max_rw_chunk
);
524 static int ll_rd_track_id(struct seq_file
*m
, enum stats_track_type type
)
526 struct super_block
*sb
= m
->private;
528 if (ll_s2sbi(sb
)->ll_stats_track_type
== type
) {
529 return seq_printf(m
, "%d\n",
530 ll_s2sbi(sb
)->ll_stats_track_id
);
532 } else if (ll_s2sbi(sb
)->ll_stats_track_type
== STATS_TRACK_ALL
) {
533 return seq_printf(m
, "0 (all)\n");
535 return seq_printf(m
, "untracked\n");
539 static int ll_wr_track_id(const char __user
*buffer
, unsigned long count
,
540 void *data
, enum stats_track_type type
)
542 struct super_block
*sb
= data
;
545 rc
= lprocfs_write_helper(buffer
, count
, &pid
);
548 ll_s2sbi(sb
)->ll_stats_track_id
= pid
;
550 ll_s2sbi(sb
)->ll_stats_track_type
= STATS_TRACK_ALL
;
552 ll_s2sbi(sb
)->ll_stats_track_type
= type
;
553 lprocfs_clear_stats(ll_s2sbi(sb
)->ll_stats
);
557 static int ll_track_pid_seq_show(struct seq_file
*m
, void *v
)
559 return ll_rd_track_id(m
, STATS_TRACK_PID
);
562 static ssize_t
ll_track_pid_seq_write(struct file
*file
,
563 const char __user
*buffer
,
564 size_t count
, loff_t
*off
)
566 struct seq_file
*seq
= file
->private_data
;
567 return ll_wr_track_id(buffer
, count
, seq
->private, STATS_TRACK_PID
);
569 LPROC_SEQ_FOPS(ll_track_pid
);
571 static int ll_track_ppid_seq_show(struct seq_file
*m
, void *v
)
573 return ll_rd_track_id(m
, STATS_TRACK_PPID
);
576 static ssize_t
ll_track_ppid_seq_write(struct file
*file
,
577 const char __user
*buffer
,
578 size_t count
, loff_t
*off
)
580 struct seq_file
*seq
= file
->private_data
;
581 return ll_wr_track_id(buffer
, count
, seq
->private, STATS_TRACK_PPID
);
583 LPROC_SEQ_FOPS(ll_track_ppid
);
585 static int ll_track_gid_seq_show(struct seq_file
*m
, void *v
)
587 return ll_rd_track_id(m
, STATS_TRACK_GID
);
590 static ssize_t
ll_track_gid_seq_write(struct file
*file
,
591 const char __user
*buffer
,
592 size_t count
, loff_t
*off
)
594 struct seq_file
*seq
= file
->private_data
;
595 return ll_wr_track_id(buffer
, count
, seq
->private, STATS_TRACK_GID
);
597 LPROC_SEQ_FOPS(ll_track_gid
);
599 static int ll_statahead_max_seq_show(struct seq_file
*m
, void *v
)
601 struct super_block
*sb
= m
->private;
602 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
604 return seq_printf(m
, "%u\n", sbi
->ll_sa_max
);
607 static ssize_t
ll_statahead_max_seq_write(struct file
*file
,
608 const char __user
*buffer
,
609 size_t count
, loff_t
*off
)
611 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
612 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
615 rc
= lprocfs_write_helper(buffer
, count
, &val
);
619 if (val
>= 0 && val
<= LL_SA_RPC_MAX
)
620 sbi
->ll_sa_max
= val
;
622 CERROR("Bad statahead_max value %d. Valid values are in the range [0, %d]\n",
627 LPROC_SEQ_FOPS(ll_statahead_max
);
629 static int ll_statahead_agl_seq_show(struct seq_file
*m
, void *v
)
631 struct super_block
*sb
= m
->private;
632 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
634 return seq_printf(m
, "%u\n",
635 sbi
->ll_flags
& LL_SBI_AGL_ENABLED
? 1 : 0);
638 static ssize_t
ll_statahead_agl_seq_write(struct file
*file
,
639 const char __user
*buffer
,
640 size_t count
, loff_t
*off
)
642 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
643 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
646 rc
= lprocfs_write_helper(buffer
, count
, &val
);
651 sbi
->ll_flags
|= LL_SBI_AGL_ENABLED
;
653 sbi
->ll_flags
&= ~LL_SBI_AGL_ENABLED
;
657 LPROC_SEQ_FOPS(ll_statahead_agl
);
659 static int ll_statahead_stats_seq_show(struct seq_file
*m
, void *v
)
661 struct super_block
*sb
= m
->private;
662 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
665 "statahead total: %u\n"
666 "statahead wrong: %u\n"
668 atomic_read(&sbi
->ll_sa_total
),
669 atomic_read(&sbi
->ll_sa_wrong
),
670 atomic_read(&sbi
->ll_agl_total
));
672 LPROC_SEQ_FOPS_RO(ll_statahead_stats
);
674 static int ll_lazystatfs_seq_show(struct seq_file
*m
, void *v
)
676 struct super_block
*sb
= m
->private;
677 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
679 return seq_printf(m
, "%u\n",
680 (sbi
->ll_flags
& LL_SBI_LAZYSTATFS
) ? 1 : 0);
683 static ssize_t
ll_lazystatfs_seq_write(struct file
*file
,
684 const char __user
*buffer
,
685 size_t count
, loff_t
*off
)
687 struct super_block
*sb
= ((struct seq_file
*)file
->private_data
)->private;
688 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
691 rc
= lprocfs_write_helper(buffer
, count
, &val
);
696 sbi
->ll_flags
|= LL_SBI_LAZYSTATFS
;
698 sbi
->ll_flags
&= ~LL_SBI_LAZYSTATFS
;
702 LPROC_SEQ_FOPS(ll_lazystatfs
);
704 static int ll_max_easize_seq_show(struct seq_file
*m
, void *v
)
706 struct super_block
*sb
= m
->private;
707 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
711 rc
= ll_get_max_mdsize(sbi
, &ealen
);
715 return seq_printf(m
, "%u\n", ealen
);
717 LPROC_SEQ_FOPS_RO(ll_max_easize
);
719 static int ll_defult_easize_seq_show(struct seq_file
*m
, void *v
)
721 struct super_block
*sb
= m
->private;
722 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
726 rc
= ll_get_default_mdsize(sbi
, &ealen
);
730 return seq_printf(m
, "%u\n", ealen
);
732 LPROC_SEQ_FOPS_RO(ll_defult_easize
);
734 static int ll_max_cookiesize_seq_show(struct seq_file
*m
, void *v
)
736 struct super_block
*sb
= m
->private;
737 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
738 unsigned int cookielen
;
741 rc
= ll_get_max_cookiesize(sbi
, &cookielen
);
745 return seq_printf(m
, "%u\n", cookielen
);
747 LPROC_SEQ_FOPS_RO(ll_max_cookiesize
);
749 static int ll_defult_cookiesize_seq_show(struct seq_file
*m
, void *v
)
751 struct super_block
*sb
= m
->private;
752 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
753 unsigned int cookielen
;
756 rc
= ll_get_default_cookiesize(sbi
, &cookielen
);
760 return seq_printf(m
, "%u\n", cookielen
);
762 LPROC_SEQ_FOPS_RO(ll_defult_cookiesize
);
764 static int ll_sbi_flags_seq_show(struct seq_file
*m
, void *v
)
766 const char *str
[] = LL_SBI_FLAGS
;
767 struct super_block
*sb
= m
->private;
768 int flags
= ll_s2sbi(sb
)->ll_flags
;
772 if (ARRAY_SIZE(str
) <= i
) {
773 CERROR("%s: Revise array LL_SBI_FLAGS to match sbi flags please.\n",
774 ll_get_fsname(sb
, NULL
, 0));
779 seq_printf(m
, "%s ", str
[i
]);
783 seq_printf(m
, "\b\n");
786 LPROC_SEQ_FOPS_RO(ll_sbi_flags
);
788 static int ll_xattr_cache_seq_show(struct seq_file
*m
, void *v
)
790 struct super_block
*sb
= m
->private;
791 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
794 rc
= seq_printf(m
, "%u\n", sbi
->ll_xattr_cache_enabled
);
799 static ssize_t
ll_xattr_cache_seq_write(struct file
*file
,
800 const char __user
*buffer
,
801 size_t count
, loff_t
*off
)
803 struct seq_file
*seq
= file
->private_data
;
804 struct super_block
*sb
= seq
->private;
805 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
808 rc
= lprocfs_write_helper(buffer
, count
, &val
);
812 if (val
!= 0 && val
!= 1)
815 if (val
== 1 && !(sbi
->ll_flags
& LL_SBI_XATTR_CACHE
))
818 sbi
->ll_xattr_cache_enabled
= val
;
822 LPROC_SEQ_FOPS(ll_xattr_cache
);
824 static struct lprocfs_vars lprocfs_llite_obd_vars
[] = {
825 { "uuid", &ll_sb_uuid_fops
, NULL
, 0 },
826 /* { "mntpt_path", ll_rd_path, 0, 0 }, */
827 { "fstype", &ll_fstype_fops
, NULL
, 0 },
828 { "site", &ll_site_stats_fops
, NULL
, 0 },
829 { "blocksize", &ll_blksize_fops
, NULL
, 0 },
830 { "kbytestotal", &ll_kbytestotal_fops
, NULL
, 0 },
831 { "kbytesfree", &ll_kbytesfree_fops
, NULL
, 0 },
832 { "kbytesavail", &ll_kbytesavail_fops
, NULL
, 0 },
833 { "filestotal", &ll_filestotal_fops
, NULL
, 0 },
834 { "filesfree", &ll_filesfree_fops
, NULL
, 0 },
835 { "client_type", &ll_client_type_fops
, NULL
, 0 },
836 /* { "filegroups", lprocfs_rd_filegroups, 0, 0 }, */
837 { "max_read_ahead_mb", &ll_max_readahead_mb_fops
, NULL
},
838 { "max_read_ahead_per_file_mb", &ll_max_readahead_per_file_mb_fops
,
840 { "max_read_ahead_whole_mb", &ll_max_read_ahead_whole_mb_fops
, NULL
},
841 { "max_cached_mb", &ll_max_cached_mb_fops
, NULL
},
842 { "checksum_pages", &ll_checksum_fops
, NULL
},
843 { "max_rw_chunk", &ll_max_rw_chunk_fops
, NULL
},
844 { "stats_track_pid", &ll_track_pid_fops
, NULL
},
845 { "stats_track_ppid", &ll_track_ppid_fops
, NULL
},
846 { "stats_track_gid", &ll_track_gid_fops
, NULL
},
847 { "statahead_max", &ll_statahead_max_fops
, NULL
},
848 { "statahead_agl", &ll_statahead_agl_fops
, NULL
},
849 { "statahead_stats", &ll_statahead_stats_fops
, NULL
, 0 },
850 { "lazystatfs", &ll_lazystatfs_fops
, NULL
},
851 { "max_easize", &ll_max_easize_fops
, NULL
, 0 },
852 { "default_easize", &ll_defult_easize_fops
, NULL
, 0 },
853 { "max_cookiesize", &ll_max_cookiesize_fops
, NULL
, 0 },
854 { "default_cookiesize", &ll_defult_cookiesize_fops
, NULL
, 0 },
855 { "sbi_flags", &ll_sbi_flags_fops
, NULL
, 0 },
856 { "xattr_cache", &ll_xattr_cache_fops
, NULL
, 0 },
860 #define MAX_STRING_SIZE 128
862 static const struct llite_file_opcode
{
866 } llite_opcode_table
[LPROC_LL_FILE_OPCODES
] = {
868 { LPROC_LL_DIRTY_HITS
, LPROCFS_TYPE_REGS
, "dirty_pages_hits" },
869 { LPROC_LL_DIRTY_MISSES
, LPROCFS_TYPE_REGS
, "dirty_pages_misses" },
870 { LPROC_LL_READ_BYTES
, LPROCFS_CNTR_AVGMINMAX
|LPROCFS_TYPE_BYTES
,
872 { LPROC_LL_WRITE_BYTES
, LPROCFS_CNTR_AVGMINMAX
|LPROCFS_TYPE_BYTES
,
874 { LPROC_LL_BRW_READ
, LPROCFS_CNTR_AVGMINMAX
|LPROCFS_TYPE_PAGES
,
876 { LPROC_LL_BRW_WRITE
, LPROCFS_CNTR_AVGMINMAX
|LPROCFS_TYPE_PAGES
,
878 { LPROC_LL_OSC_READ
, LPROCFS_CNTR_AVGMINMAX
|LPROCFS_TYPE_BYTES
,
880 { LPROC_LL_OSC_WRITE
, LPROCFS_CNTR_AVGMINMAX
|LPROCFS_TYPE_BYTES
,
882 { LPROC_LL_IOCTL
, LPROCFS_TYPE_REGS
, "ioctl" },
883 { LPROC_LL_OPEN
, LPROCFS_TYPE_REGS
, "open" },
884 { LPROC_LL_RELEASE
, LPROCFS_TYPE_REGS
, "close" },
885 { LPROC_LL_MAP
, LPROCFS_TYPE_REGS
, "mmap" },
886 { LPROC_LL_LLSEEK
, LPROCFS_TYPE_REGS
, "seek" },
887 { LPROC_LL_FSYNC
, LPROCFS_TYPE_REGS
, "fsync" },
888 { LPROC_LL_READDIR
, LPROCFS_TYPE_REGS
, "readdir" },
889 /* inode operation */
890 { LPROC_LL_SETATTR
, LPROCFS_TYPE_REGS
, "setattr" },
891 { LPROC_LL_TRUNC
, LPROCFS_TYPE_REGS
, "truncate" },
892 { LPROC_LL_FLOCK
, LPROCFS_TYPE_REGS
, "flock" },
893 { LPROC_LL_GETATTR
, LPROCFS_TYPE_REGS
, "getattr" },
894 /* dir inode operation */
895 { LPROC_LL_CREATE
, LPROCFS_TYPE_REGS
, "create" },
896 { LPROC_LL_LINK
, LPROCFS_TYPE_REGS
, "link" },
897 { LPROC_LL_UNLINK
, LPROCFS_TYPE_REGS
, "unlink" },
898 { LPROC_LL_SYMLINK
, LPROCFS_TYPE_REGS
, "symlink" },
899 { LPROC_LL_MKDIR
, LPROCFS_TYPE_REGS
, "mkdir" },
900 { LPROC_LL_RMDIR
, LPROCFS_TYPE_REGS
, "rmdir" },
901 { LPROC_LL_MKNOD
, LPROCFS_TYPE_REGS
, "mknod" },
902 { LPROC_LL_RENAME
, LPROCFS_TYPE_REGS
, "rename" },
903 /* special inode operation */
904 { LPROC_LL_STAFS
, LPROCFS_TYPE_REGS
, "statfs" },
905 { LPROC_LL_ALLOC_INODE
, LPROCFS_TYPE_REGS
, "alloc_inode" },
906 { LPROC_LL_SETXATTR
, LPROCFS_TYPE_REGS
, "setxattr" },
907 { LPROC_LL_GETXATTR
, LPROCFS_TYPE_REGS
, "getxattr" },
908 { LPROC_LL_GETXATTR_HITS
, LPROCFS_TYPE_REGS
, "getxattr_hits" },
909 { LPROC_LL_LISTXATTR
, LPROCFS_TYPE_REGS
, "listxattr" },
910 { LPROC_LL_REMOVEXATTR
, LPROCFS_TYPE_REGS
, "removexattr" },
911 { LPROC_LL_INODE_PERM
, LPROCFS_TYPE_REGS
, "inode_permission" },
914 void ll_stats_ops_tally(struct ll_sb_info
*sbi
, int op
, int count
)
918 if (sbi
->ll_stats_track_type
== STATS_TRACK_ALL
)
919 lprocfs_counter_add(sbi
->ll_stats
, op
, count
);
920 else if (sbi
->ll_stats_track_type
== STATS_TRACK_PID
&&
921 sbi
->ll_stats_track_id
== current
->pid
)
922 lprocfs_counter_add(sbi
->ll_stats
, op
, count
);
923 else if (sbi
->ll_stats_track_type
== STATS_TRACK_PPID
&&
924 sbi
->ll_stats_track_id
== current
->real_parent
->pid
)
925 lprocfs_counter_add(sbi
->ll_stats
, op
, count
);
926 else if (sbi
->ll_stats_track_type
== STATS_TRACK_GID
&&
927 sbi
->ll_stats_track_id
==
928 from_kgid(&init_user_ns
, current_gid()))
929 lprocfs_counter_add(sbi
->ll_stats
, op
, count
);
931 EXPORT_SYMBOL(ll_stats_ops_tally
);
933 static const char *ra_stat_string
[] = {
934 [RA_STAT_HIT
] = "hits",
935 [RA_STAT_MISS
] = "misses",
936 [RA_STAT_DISTANT_READPAGE
] = "readpage not consecutive",
937 [RA_STAT_MISS_IN_WINDOW
] = "miss inside window",
938 [RA_STAT_FAILED_GRAB_PAGE
] = "failed grab_cache_page",
939 [RA_STAT_FAILED_MATCH
] = "failed lock match",
940 [RA_STAT_DISCARDED
] = "read but discarded",
941 [RA_STAT_ZERO_LEN
] = "zero length file",
942 [RA_STAT_ZERO_WINDOW
] = "zero size window",
943 [RA_STAT_EOF
] = "read-ahead to EOF",
944 [RA_STAT_MAX_IN_FLIGHT
] = "hit max r-a issue",
945 [RA_STAT_WRONG_GRAB_PAGE
] = "wrong page from grab_cache_page",
948 LPROC_SEQ_FOPS_RO_TYPE(llite
, name
);
949 LPROC_SEQ_FOPS_RO_TYPE(llite
, uuid
);
951 int lprocfs_register_mountpoint(struct proc_dir_entry
*parent
,
952 struct super_block
*sb
, char *osc
, char *mdc
)
954 struct lprocfs_vars lvars
[2];
955 struct lustre_sb_info
*lsi
= s2lsi(sb
);
956 struct ll_sb_info
*sbi
= ll_s2sbi(sb
);
957 struct obd_device
*obd
;
958 struct proc_dir_entry
*dir
;
959 char name
[MAX_STRING_SIZE
+ 1], *ptr
;
960 int err
, id
, len
, rc
;
962 memset(lvars
, 0, sizeof(lvars
));
964 name
[MAX_STRING_SIZE
] = '\0';
965 lvars
[0].name
= name
;
967 LASSERT(sbi
!= NULL
);
968 LASSERT(mdc
!= NULL
);
969 LASSERT(osc
!= NULL
);
972 len
= strlen(lsi
->lsi_lmd
->lmd_profile
);
973 ptr
= strrchr(lsi
->lsi_lmd
->lmd_profile
, '-');
974 if (ptr
&& (strcmp(ptr
, "-client") == 0))
978 snprintf(name
, MAX_STRING_SIZE
, "%.*s-%p", len
,
979 lsi
->lsi_lmd
->lmd_profile
, sb
);
981 sbi
->ll_proc_root
= lprocfs_register(name
, parent
, NULL
, NULL
);
982 if (IS_ERR(sbi
->ll_proc_root
)) {
983 err
= PTR_ERR(sbi
->ll_proc_root
);
984 sbi
->ll_proc_root
= NULL
;
988 rc
= lprocfs_seq_create(sbi
->ll_proc_root
, "dump_page_cache", 0444,
989 &vvp_dump_pgcache_file_ops
, sbi
);
991 CWARN("Error adding the dump_page_cache file\n");
993 rc
= lprocfs_seq_create(sbi
->ll_proc_root
, "extents_stats", 0644,
994 &ll_rw_extents_stats_fops
, sbi
);
996 CWARN("Error adding the extent_stats file\n");
998 rc
= lprocfs_seq_create(sbi
->ll_proc_root
, "extents_stats_per_process",
999 0644, &ll_rw_extents_stats_pp_fops
, sbi
);
1001 CWARN("Error adding the extents_stats_per_process file\n");
1003 rc
= lprocfs_seq_create(sbi
->ll_proc_root
, "offset_stats", 0644,
1004 &ll_rw_offset_stats_fops
, sbi
);
1006 CWARN("Error adding the offset_stats file\n");
1008 /* File operations stats */
1009 sbi
->ll_stats
= lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES
,
1010 LPROCFS_STATS_FLAG_NONE
);
1011 if (sbi
->ll_stats
== NULL
) {
1015 /* do counter init */
1016 for (id
= 0; id
< LPROC_LL_FILE_OPCODES
; id
++) {
1017 __u32 type
= llite_opcode_table
[id
].type
;
1019 if (type
& LPROCFS_TYPE_REGS
)
1021 else if (type
& LPROCFS_TYPE_BYTES
)
1023 else if (type
& LPROCFS_TYPE_PAGES
)
1025 lprocfs_counter_init(sbi
->ll_stats
,
1026 llite_opcode_table
[id
].opcode
,
1027 (type
& LPROCFS_CNTR_AVGMINMAX
),
1028 llite_opcode_table
[id
].opname
, ptr
);
1030 err
= lprocfs_register_stats(sbi
->ll_proc_root
, "stats", sbi
->ll_stats
);
1034 sbi
->ll_ra_stats
= lprocfs_alloc_stats(ARRAY_SIZE(ra_stat_string
),
1035 LPROCFS_STATS_FLAG_NONE
);
1036 if (sbi
->ll_ra_stats
== NULL
) {
1041 for (id
= 0; id
< ARRAY_SIZE(ra_stat_string
); id
++)
1042 lprocfs_counter_init(sbi
->ll_ra_stats
, id
, 0,
1043 ra_stat_string
[id
], "pages");
1044 err
= lprocfs_register_stats(sbi
->ll_proc_root
, "read_ahead_stats",
1050 err
= lprocfs_add_vars(sbi
->ll_proc_root
, lprocfs_llite_obd_vars
, sb
);
1055 obd
= class_name2obd(mdc
);
1057 LASSERT(obd
!= NULL
);
1058 LASSERT(obd
->obd_magic
== OBD_DEVICE_MAGIC
);
1059 LASSERT(obd
->obd_type
->typ_name
!= NULL
);
1061 dir
= proc_mkdir(obd
->obd_type
->typ_name
, sbi
->ll_proc_root
);
1067 snprintf(name
, MAX_STRING_SIZE
, "common_name");
1068 lvars
[0].fops
= &llite_name_fops
;
1069 err
= lprocfs_add_vars(dir
, lvars
, obd
);
1073 snprintf(name
, MAX_STRING_SIZE
, "uuid");
1074 lvars
[0].fops
= &llite_uuid_fops
;
1075 err
= lprocfs_add_vars(dir
, lvars
, obd
);
1080 obd
= class_name2obd(osc
);
1082 LASSERT(obd
!= NULL
);
1083 LASSERT(obd
->obd_magic
== OBD_DEVICE_MAGIC
);
1084 LASSERT(obd
->obd_type
->typ_name
!= NULL
);
1086 dir
= proc_mkdir(obd
->obd_type
->typ_name
, sbi
->ll_proc_root
);
1092 snprintf(name
, MAX_STRING_SIZE
, "common_name");
1093 lvars
[0].fops
= &llite_name_fops
;
1094 err
= lprocfs_add_vars(dir
, lvars
, obd
);
1098 snprintf(name
, MAX_STRING_SIZE
, "uuid");
1099 lvars
[0].fops
= &llite_uuid_fops
;
1100 err
= lprocfs_add_vars(dir
, lvars
, obd
);
1103 lprocfs_remove(&sbi
->ll_proc_root
);
1104 lprocfs_free_stats(&sbi
->ll_ra_stats
);
1105 lprocfs_free_stats(&sbi
->ll_stats
);
1110 void lprocfs_unregister_mountpoint(struct ll_sb_info
*sbi
)
1112 if (sbi
->ll_proc_root
) {
1113 lprocfs_remove(&sbi
->ll_proc_root
);
1114 lprocfs_free_stats(&sbi
->ll_ra_stats
);
1115 lprocfs_free_stats(&sbi
->ll_stats
);
1118 #undef MAX_STRING_SIZE
1120 #define pct(a, b) (b ? a * 100 / b : 0)
1122 static void ll_display_extents_info(struct ll_rw_extents_info
*io_extents
,
1123 struct seq_file
*seq
, int which
)
1125 unsigned long read_tot
= 0, write_tot
= 0, read_cum
, write_cum
;
1126 unsigned long start
, end
, r
, w
;
1127 char *unitp
= "KMGTPEZY";
1129 struct per_process_info
*pp_info
= &io_extents
->pp_extents
[which
];
1135 for (i
= 0; i
< LL_HIST_MAX
; i
++) {
1136 read_tot
+= pp_info
->pp_r_hist
.oh_buckets
[i
];
1137 write_tot
+= pp_info
->pp_w_hist
.oh_buckets
[i
];
1140 for (i
= 0; i
< LL_HIST_MAX
; i
++) {
1141 r
= pp_info
->pp_r_hist
.oh_buckets
[i
];
1142 w
= pp_info
->pp_w_hist
.oh_buckets
[i
];
1145 end
= 1 << (i
+ LL_HIST_START
- units
);
1146 seq_printf(seq
, "%4lu%c - %4lu%c%c: %14lu %4lu %4lu | %14lu %4lu %4lu\n",
1147 start
, *unitp
, end
, *unitp
,
1148 (i
== LL_HIST_MAX
- 1) ? '+' : ' ',
1149 r
, pct(r
, read_tot
), pct(read_cum
, read_tot
),
1150 w
, pct(w
, write_tot
), pct(write_cum
, write_tot
));
1152 if (start
== 1<<10) {
1157 if (read_cum
== read_tot
&& write_cum
== write_tot
)
1162 static int ll_rw_extents_stats_pp_seq_show(struct seq_file
*seq
, void *v
)
1165 struct ll_sb_info
*sbi
= seq
->private;
1166 struct ll_rw_extents_info
*io_extents
= &sbi
->ll_rw_extents_info
;
1169 do_gettimeofday(&now
);
1171 if (!sbi
->ll_rw_stats_on
) {
1172 seq_printf(seq
, "disabled\n"
1173 "write anything in this file to activate, then 0 or \"[D/d]isabled\" to deactivate\n");
1176 seq_printf(seq
, "snapshot_time: %lu.%lu (secs.usecs)\n",
1177 now
.tv_sec
, (unsigned long)now
.tv_usec
);
1178 seq_printf(seq
, "%15s %19s | %20s\n", " ", "read", "write");
1179 seq_printf(seq
, "%13s %14s %4s %4s | %14s %4s %4s\n",
1180 "extents", "calls", "%", "cum%",
1181 "calls", "%", "cum%");
1182 spin_lock(&sbi
->ll_pp_extent_lock
);
1183 for (k
= 0; k
< LL_PROCESS_HIST_MAX
; k
++) {
1184 if (io_extents
->pp_extents
[k
].pid
!= 0) {
1185 seq_printf(seq
, "\nPID: %d\n",
1186 io_extents
->pp_extents
[k
].pid
);
1187 ll_display_extents_info(io_extents
, seq
, k
);
1190 spin_unlock(&sbi
->ll_pp_extent_lock
);
1194 static ssize_t
ll_rw_extents_stats_pp_seq_write(struct file
*file
,
1195 const char __user
*buf
,
1199 struct seq_file
*seq
= file
->private_data
;
1200 struct ll_sb_info
*sbi
= seq
->private;
1201 struct ll_rw_extents_info
*io_extents
= &sbi
->ll_rw_extents_info
;
1203 int value
= 1, rc
= 0;
1208 rc
= lprocfs_write_helper(buf
, len
, &value
);
1209 if (rc
< 0 && len
< 16) {
1212 if (copy_from_user(kernbuf
, buf
, len
))
1216 if (kernbuf
[len
- 1] == '\n')
1217 kernbuf
[len
- 1] = 0;
1219 if (strcmp(kernbuf
, "disabled") == 0 ||
1220 strcmp(kernbuf
, "Disabled") == 0)
1225 sbi
->ll_rw_stats_on
= 0;
1227 sbi
->ll_rw_stats_on
= 1;
1229 spin_lock(&sbi
->ll_pp_extent_lock
);
1230 for (i
= 0; i
< LL_PROCESS_HIST_MAX
; i
++) {
1231 io_extents
->pp_extents
[i
].pid
= 0;
1232 lprocfs_oh_clear(&io_extents
->pp_extents
[i
].pp_r_hist
);
1233 lprocfs_oh_clear(&io_extents
->pp_extents
[i
].pp_w_hist
);
1235 spin_unlock(&sbi
->ll_pp_extent_lock
);
1239 LPROC_SEQ_FOPS(ll_rw_extents_stats_pp
);
1241 static int ll_rw_extents_stats_seq_show(struct seq_file
*seq
, void *v
)
1244 struct ll_sb_info
*sbi
= seq
->private;
1245 struct ll_rw_extents_info
*io_extents
= &sbi
->ll_rw_extents_info
;
1247 do_gettimeofday(&now
);
1249 if (!sbi
->ll_rw_stats_on
) {
1250 seq_printf(seq
, "disabled\n"
1251 "write anything in this file to activate, then 0 or \"[D/d]isabled\" to deactivate\n");
1254 seq_printf(seq
, "snapshot_time: %lu.%lu (secs.usecs)\n",
1255 now
.tv_sec
, (unsigned long)now
.tv_usec
);
1257 seq_printf(seq
, "%15s %19s | %20s\n", " ", "read", "write");
1258 seq_printf(seq
, "%13s %14s %4s %4s | %14s %4s %4s\n",
1259 "extents", "calls", "%", "cum%",
1260 "calls", "%", "cum%");
1261 spin_lock(&sbi
->ll_lock
);
1262 ll_display_extents_info(io_extents
, seq
, LL_PROCESS_HIST_MAX
);
1263 spin_unlock(&sbi
->ll_lock
);
1268 static ssize_t
ll_rw_extents_stats_seq_write(struct file
*file
,
1269 const char __user
*buf
,
1270 size_t len
, loff_t
*off
)
1272 struct seq_file
*seq
= file
->private_data
;
1273 struct ll_sb_info
*sbi
= seq
->private;
1274 struct ll_rw_extents_info
*io_extents
= &sbi
->ll_rw_extents_info
;
1276 int value
= 1, rc
= 0;
1281 rc
= lprocfs_write_helper(buf
, len
, &value
);
1282 if (rc
< 0 && len
< 16) {
1285 if (copy_from_user(kernbuf
, buf
, len
))
1289 if (kernbuf
[len
- 1] == '\n')
1290 kernbuf
[len
- 1] = 0;
1292 if (strcmp(kernbuf
, "disabled") == 0 ||
1293 strcmp(kernbuf
, "Disabled") == 0)
1298 sbi
->ll_rw_stats_on
= 0;
1300 sbi
->ll_rw_stats_on
= 1;
1302 spin_lock(&sbi
->ll_pp_extent_lock
);
1303 for (i
= 0; i
<= LL_PROCESS_HIST_MAX
; i
++) {
1304 io_extents
->pp_extents
[i
].pid
= 0;
1305 lprocfs_oh_clear(&io_extents
->pp_extents
[i
].pp_r_hist
);
1306 lprocfs_oh_clear(&io_extents
->pp_extents
[i
].pp_w_hist
);
1308 spin_unlock(&sbi
->ll_pp_extent_lock
);
1312 LPROC_SEQ_FOPS(ll_rw_extents_stats
);
1314 void ll_rw_stats_tally(struct ll_sb_info
*sbi
, pid_t pid
,
1315 struct ll_file_data
*file
, loff_t pos
,
1316 size_t count
, int rw
)
1319 struct ll_rw_process_info
*process
;
1320 struct ll_rw_process_info
*offset
;
1321 int *off_count
= &sbi
->ll_rw_offset_entry_count
;
1322 int *process_count
= &sbi
->ll_offset_process_count
;
1323 struct ll_rw_extents_info
*io_extents
= &sbi
->ll_rw_extents_info
;
1325 if (!sbi
->ll_rw_stats_on
)
1327 process
= sbi
->ll_rw_process_info
;
1328 offset
= sbi
->ll_rw_offset_info
;
1330 spin_lock(&sbi
->ll_pp_extent_lock
);
1331 /* Extent statistics */
1332 for (i
= 0; i
< LL_PROCESS_HIST_MAX
; i
++) {
1333 if (io_extents
->pp_extents
[i
].pid
== pid
) {
1341 sbi
->ll_extent_process_count
=
1342 (sbi
->ll_extent_process_count
+ 1) % LL_PROCESS_HIST_MAX
;
1343 cur
= sbi
->ll_extent_process_count
;
1344 io_extents
->pp_extents
[cur
].pid
= pid
;
1345 lprocfs_oh_clear(&io_extents
->pp_extents
[cur
].pp_r_hist
);
1346 lprocfs_oh_clear(&io_extents
->pp_extents
[cur
].pp_w_hist
);
1349 for(i
= 0; (count
>= (1 << LL_HIST_START
<< i
)) &&
1350 (i
< (LL_HIST_MAX
- 1)); i
++);
1352 io_extents
->pp_extents
[cur
].pp_r_hist
.oh_buckets
[i
]++;
1353 io_extents
->pp_extents
[LL_PROCESS_HIST_MAX
].pp_r_hist
.oh_buckets
[i
]++;
1355 io_extents
->pp_extents
[cur
].pp_w_hist
.oh_buckets
[i
]++;
1356 io_extents
->pp_extents
[LL_PROCESS_HIST_MAX
].pp_w_hist
.oh_buckets
[i
]++;
1358 spin_unlock(&sbi
->ll_pp_extent_lock
);
1360 spin_lock(&sbi
->ll_process_lock
);
1361 /* Offset statistics */
1362 for (i
= 0; i
< LL_PROCESS_HIST_MAX
; i
++) {
1363 if (process
[i
].rw_pid
== pid
) {
1364 if (process
[i
].rw_last_file
!= file
) {
1365 process
[i
].rw_range_start
= pos
;
1366 process
[i
].rw_last_file_pos
= pos
+ count
;
1367 process
[i
].rw_smallest_extent
= count
;
1368 process
[i
].rw_largest_extent
= count
;
1369 process
[i
].rw_offset
= 0;
1370 process
[i
].rw_last_file
= file
;
1371 spin_unlock(&sbi
->ll_process_lock
);
1374 if (process
[i
].rw_last_file_pos
!= pos
) {
1376 (*off_count
+ 1) % LL_OFFSET_HIST_MAX
;
1377 offset
[*off_count
].rw_op
= process
[i
].rw_op
;
1378 offset
[*off_count
].rw_pid
= pid
;
1379 offset
[*off_count
].rw_range_start
=
1380 process
[i
].rw_range_start
;
1381 offset
[*off_count
].rw_range_end
=
1382 process
[i
].rw_last_file_pos
;
1383 offset
[*off_count
].rw_smallest_extent
=
1384 process
[i
].rw_smallest_extent
;
1385 offset
[*off_count
].rw_largest_extent
=
1386 process
[i
].rw_largest_extent
;
1387 offset
[*off_count
].rw_offset
=
1388 process
[i
].rw_offset
;
1389 process
[i
].rw_op
= rw
;
1390 process
[i
].rw_range_start
= pos
;
1391 process
[i
].rw_smallest_extent
= count
;
1392 process
[i
].rw_largest_extent
= count
;
1393 process
[i
].rw_offset
= pos
-
1394 process
[i
].rw_last_file_pos
;
1396 if (process
[i
].rw_smallest_extent
> count
)
1397 process
[i
].rw_smallest_extent
= count
;
1398 if (process
[i
].rw_largest_extent
< count
)
1399 process
[i
].rw_largest_extent
= count
;
1400 process
[i
].rw_last_file_pos
= pos
+ count
;
1401 spin_unlock(&sbi
->ll_process_lock
);
1405 *process_count
= (*process_count
+ 1) % LL_PROCESS_HIST_MAX
;
1406 process
[*process_count
].rw_pid
= pid
;
1407 process
[*process_count
].rw_op
= rw
;
1408 process
[*process_count
].rw_range_start
= pos
;
1409 process
[*process_count
].rw_last_file_pos
= pos
+ count
;
1410 process
[*process_count
].rw_smallest_extent
= count
;
1411 process
[*process_count
].rw_largest_extent
= count
;
1412 process
[*process_count
].rw_offset
= 0;
1413 process
[*process_count
].rw_last_file
= file
;
1414 spin_unlock(&sbi
->ll_process_lock
);
1417 static int ll_rw_offset_stats_seq_show(struct seq_file
*seq
, void *v
)
1420 struct ll_sb_info
*sbi
= seq
->private;
1421 struct ll_rw_process_info
*offset
= sbi
->ll_rw_offset_info
;
1422 struct ll_rw_process_info
*process
= sbi
->ll_rw_process_info
;
1425 do_gettimeofday(&now
);
1427 if (!sbi
->ll_rw_stats_on
) {
1428 seq_printf(seq
, "disabled\n"
1429 "write anything in this file to activate, then 0 or \"[D/d]isabled\" to deactivate\n");
1432 spin_lock(&sbi
->ll_process_lock
);
1434 seq_printf(seq
, "snapshot_time: %lu.%lu (secs.usecs)\n",
1435 now
.tv_sec
, (unsigned long)now
.tv_usec
);
1436 seq_printf(seq
, "%3s %10s %14s %14s %17s %17s %14s\n",
1437 "R/W", "PID", "RANGE START", "RANGE END",
1438 "SMALLEST EXTENT", "LARGEST EXTENT", "OFFSET");
1439 /* We stored the discontiguous offsets here; print them first */
1440 for (i
= 0; i
< LL_OFFSET_HIST_MAX
; i
++) {
1441 if (offset
[i
].rw_pid
!= 0)
1443 "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
1444 offset
[i
].rw_op
== READ
? 'R' : 'W',
1446 offset
[i
].rw_range_start
,
1447 offset
[i
].rw_range_end
,
1448 (unsigned long)offset
[i
].rw_smallest_extent
,
1449 (unsigned long)offset
[i
].rw_largest_extent
,
1450 offset
[i
].rw_offset
);
1452 /* Then print the current offsets for each process */
1453 for (i
= 0; i
< LL_PROCESS_HIST_MAX
; i
++) {
1454 if (process
[i
].rw_pid
!= 0)
1456 "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
1457 process
[i
].rw_op
== READ
? 'R' : 'W',
1459 process
[i
].rw_range_start
,
1460 process
[i
].rw_last_file_pos
,
1461 (unsigned long)process
[i
].rw_smallest_extent
,
1462 (unsigned long)process
[i
].rw_largest_extent
,
1463 process
[i
].rw_offset
);
1465 spin_unlock(&sbi
->ll_process_lock
);
1470 static ssize_t
ll_rw_offset_stats_seq_write(struct file
*file
,
1471 const char __user
*buf
,
1472 size_t len
, loff_t
*off
)
1474 struct seq_file
*seq
= file
->private_data
;
1475 struct ll_sb_info
*sbi
= seq
->private;
1476 struct ll_rw_process_info
*process_info
= sbi
->ll_rw_process_info
;
1477 struct ll_rw_process_info
*offset_info
= sbi
->ll_rw_offset_info
;
1478 int value
= 1, rc
= 0;
1483 rc
= lprocfs_write_helper(buf
, len
, &value
);
1485 if (rc
< 0 && len
< 16) {
1488 if (copy_from_user(kernbuf
, buf
, len
))
1492 if (kernbuf
[len
- 1] == '\n')
1493 kernbuf
[len
- 1] = 0;
1495 if (strcmp(kernbuf
, "disabled") == 0 ||
1496 strcmp(kernbuf
, "Disabled") == 0)
1501 sbi
->ll_rw_stats_on
= 0;
1503 sbi
->ll_rw_stats_on
= 1;
1505 spin_lock(&sbi
->ll_process_lock
);
1506 sbi
->ll_offset_process_count
= 0;
1507 sbi
->ll_rw_offset_entry_count
= 0;
1508 memset(process_info
, 0, sizeof(struct ll_rw_process_info
) *
1509 LL_PROCESS_HIST_MAX
);
1510 memset(offset_info
, 0, sizeof(struct ll_rw_process_info
) *
1511 LL_OFFSET_HIST_MAX
);
1512 spin_unlock(&sbi
->ll_process_lock
);
1517 LPROC_SEQ_FOPS(ll_rw_offset_stats
);
1519 void lprocfs_llite_init_vars(struct lprocfs_static_vars
*lvars
)
1521 lvars
->module_vars
= NULL
;
1522 lvars
->obd_vars
= lprocfs_llite_obd_vars
;