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