lproc_llite.c revision b9c98cfa717c3912595cee424ba9d9b98db9ced1
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 <lustre_lite.h> 39#include <lprocfs_status.h> 40#include <linux/seq_file.h> 41#include <obd_support.h> 42 43#include "llite_internal.h" 44 45/* /proc/lustre/llite mount point registration */ 46extern struct file_operations vvp_dump_pgcache_file_ops; 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, LPU64"\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, LPU64"\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, LPU64"\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, LPU64"\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, LPU64"\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, const char *buffer, 371 size_t count, loff_t *off) 372{ 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; 377 int diff = 0; 378 int nrpages = 0; 379 380 mult = 1 << (20 - PAGE_CACHE_SHIFT); 381 buffer = lprocfs_find_named_value(buffer, "max_cached_mb:", &count); 382 rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult); 383 if (rc) 384 return rc; 385 386 if (pages_number < 0 || pages_number > totalram_pages) { 387 CERROR("%s: can't set max cache more than %lu MB\n", 388 ll_get_fsname(sb, NULL, 0), 389 totalram_pages >> (20 - PAGE_CACHE_SHIFT)); 390 return -ERANGE; 391 } 392 393 if (sbi->ll_dt_exp == NULL) 394 return -ENODEV; 395 396 spin_lock(&sbi->ll_lock); 397 diff = pages_number - cache->ccc_lru_max; 398 spin_unlock(&sbi->ll_lock); 399 400 /* easy - add more LRU slots. */ 401 if (diff >= 0) { 402 atomic_add(diff, &cache->ccc_lru_left); 403 GOTO(out, rc = 0); 404 } 405 406 diff = -diff; 407 while (diff > 0) { 408 int tmp; 409 410 /* reduce LRU budget from free slots. */ 411 do { 412 int ov, nv; 413 414 ov = atomic_read(&cache->ccc_lru_left); 415 if (ov == 0) 416 break; 417 418 nv = ov > diff ? ov - diff : 0; 419 rc = atomic_cmpxchg(&cache->ccc_lru_left, ov, nv); 420 if (likely(ov == rc)) { 421 diff -= ov - nv; 422 nrpages += ov - nv; 423 break; 424 } 425 } while (1); 426 427 if (diff <= 0) 428 break; 429 430 /* difficult - have to ask OSCs to drop LRU slots. */ 431 tmp = diff << 1; 432 rc = obd_set_info_async(NULL, sbi->ll_dt_exp, 433 sizeof(KEY_CACHE_LRU_SHRINK), 434 KEY_CACHE_LRU_SHRINK, 435 sizeof(tmp), &tmp, NULL); 436 if (rc < 0) 437 break; 438 } 439 440out: 441 if (rc >= 0) { 442 spin_lock(&sbi->ll_lock); 443 cache->ccc_lru_max = pages_number; 444 spin_unlock(&sbi->ll_lock); 445 rc = count; 446 } else { 447 atomic_add(nrpages, &cache->ccc_lru_left); 448 } 449 return rc; 450} 451LPROC_SEQ_FOPS(ll_max_cached_mb); 452 453static int ll_checksum_seq_show(struct seq_file *m, void *v) 454{ 455 struct super_block *sb = m->private; 456 struct ll_sb_info *sbi = ll_s2sbi(sb); 457 458 return seq_printf(m, "%u\n", (sbi->ll_flags & LL_SBI_CHECKSUM) ? 1 : 0); 459} 460 461static ssize_t ll_checksum_seq_write(struct file *file, const char *buffer, 462 size_t count, loff_t *off) 463{ 464 struct super_block *sb = ((struct seq_file *)file->private_data)->private; 465 struct ll_sb_info *sbi = ll_s2sbi(sb); 466 int val, rc; 467 468 if (!sbi->ll_dt_exp) 469 /* Not set up yet */ 470 return -EAGAIN; 471 472 rc = lprocfs_write_helper(buffer, count, &val); 473 if (rc) 474 return rc; 475 if (val) 476 sbi->ll_flags |= LL_SBI_CHECKSUM; 477 else 478 sbi->ll_flags &= ~LL_SBI_CHECKSUM; 479 480 rc = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CHECKSUM), 481 KEY_CHECKSUM, sizeof(val), &val, NULL); 482 if (rc) 483 CWARN("Failed to set OSC checksum flags: %d\n", rc); 484 485 return count; 486} 487LPROC_SEQ_FOPS(ll_checksum); 488 489static int ll_max_rw_chunk_seq_show(struct seq_file *m, void *v) 490{ 491 struct super_block *sb = m->private; 492 493 return seq_printf(m, "%lu\n", ll_s2sbi(sb)->ll_max_rw_chunk); 494} 495 496static ssize_t ll_max_rw_chunk_seq_write(struct file *file, const char *buffer, 497 size_t count, loff_t *off) 498{ 499 struct super_block *sb = ((struct seq_file *)file->private_data)->private; 500 int rc, val; 501 502 rc = lprocfs_write_helper(buffer, count, &val); 503 if (rc) 504 return rc; 505 ll_s2sbi(sb)->ll_max_rw_chunk = val; 506 return count; 507} 508LPROC_SEQ_FOPS(ll_max_rw_chunk); 509 510static int ll_rd_track_id(struct seq_file *m, enum stats_track_type type) 511{ 512 struct super_block *sb = m->private; 513 514 if (ll_s2sbi(sb)->ll_stats_track_type == type) { 515 return seq_printf(m, "%d\n", 516 ll_s2sbi(sb)->ll_stats_track_id); 517 518 } else if (ll_s2sbi(sb)->ll_stats_track_type == STATS_TRACK_ALL) { 519 return seq_printf(m, "0 (all)\n"); 520 } else { 521 return seq_printf(m, "untracked\n"); 522 } 523} 524 525static int ll_wr_track_id(const char *buffer, unsigned long count, void *data, 526 enum stats_track_type type) 527{ 528 struct super_block *sb = data; 529 int rc, pid; 530 531 rc = lprocfs_write_helper(buffer, count, &pid); 532 if (rc) 533 return rc; 534 ll_s2sbi(sb)->ll_stats_track_id = pid; 535 if (pid == 0) 536 ll_s2sbi(sb)->ll_stats_track_type = STATS_TRACK_ALL; 537 else 538 ll_s2sbi(sb)->ll_stats_track_type = type; 539 lprocfs_clear_stats(ll_s2sbi(sb)->ll_stats); 540 return count; 541} 542 543static int ll_track_pid_seq_show(struct seq_file *m, void *v) 544{ 545 return ll_rd_track_id(m, STATS_TRACK_PID); 546} 547 548static ssize_t ll_track_pid_seq_write(struct file *file, const char *buffer, 549 size_t count, loff_t *off) 550{ 551 struct seq_file *seq = file->private_data; 552 return ll_wr_track_id(buffer, count, seq->private, STATS_TRACK_PID); 553} 554LPROC_SEQ_FOPS(ll_track_pid); 555 556static int ll_track_ppid_seq_show(struct seq_file *m, void *v) 557{ 558 return ll_rd_track_id(m, STATS_TRACK_PPID); 559} 560 561static ssize_t ll_track_ppid_seq_write(struct file *file, const char *buffer, 562 size_t count, loff_t *off) 563{ 564 struct seq_file *seq = file->private_data; 565 return ll_wr_track_id(buffer, count, seq->private, STATS_TRACK_PPID); 566} 567LPROC_SEQ_FOPS(ll_track_ppid); 568 569static int ll_track_gid_seq_show(struct seq_file *m, void *v) 570{ 571 return ll_rd_track_id(m, STATS_TRACK_GID); 572} 573 574static ssize_t ll_track_gid_seq_write(struct file *file, const char *buffer, 575 size_t count, loff_t *off) 576{ 577 struct seq_file *seq = file->private_data; 578 return ll_wr_track_id(buffer, count, seq->private, STATS_TRACK_GID); 579} 580LPROC_SEQ_FOPS(ll_track_gid); 581 582static int ll_statahead_max_seq_show(struct seq_file *m, void *v) 583{ 584 struct super_block *sb = m->private; 585 struct ll_sb_info *sbi = ll_s2sbi(sb); 586 587 return seq_printf(m, "%u\n", sbi->ll_sa_max); 588} 589 590static ssize_t ll_statahead_max_seq_write(struct file *file, const char *buffer, 591 size_t count, loff_t *off) 592{ 593 struct super_block *sb = ((struct seq_file *)file->private_data)->private; 594 struct ll_sb_info *sbi = ll_s2sbi(sb); 595 int val, rc; 596 597 rc = lprocfs_write_helper(buffer, count, &val); 598 if (rc) 599 return rc; 600 601 if (val >= 0 && val <= LL_SA_RPC_MAX) 602 sbi->ll_sa_max = val; 603 else 604 CERROR("Bad statahead_max value %d. Valid values are in the " 605 "range [0, %d]\n", val, LL_SA_RPC_MAX); 606 607 return count; 608} 609LPROC_SEQ_FOPS(ll_statahead_max); 610 611static int ll_statahead_agl_seq_show(struct seq_file *m, void *v) 612{ 613 struct super_block *sb = m->private; 614 struct ll_sb_info *sbi = ll_s2sbi(sb); 615 616 return seq_printf(m, "%u\n", 617 sbi->ll_flags & LL_SBI_AGL_ENABLED ? 1 : 0); 618} 619 620static ssize_t ll_statahead_agl_seq_write(struct file *file, const char *buffer, 621 size_t count, loff_t *off) 622{ 623 struct super_block *sb = ((struct seq_file *)file->private_data)->private; 624 struct ll_sb_info *sbi = ll_s2sbi(sb); 625 int val, rc; 626 627 rc = lprocfs_write_helper(buffer, count, &val); 628 if (rc) 629 return rc; 630 631 if (val) 632 sbi->ll_flags |= LL_SBI_AGL_ENABLED; 633 else 634 sbi->ll_flags &= ~LL_SBI_AGL_ENABLED; 635 636 return count; 637} 638LPROC_SEQ_FOPS(ll_statahead_agl); 639 640static int ll_statahead_stats_seq_show(struct seq_file *m, void *v) 641{ 642 struct super_block *sb = m->private; 643 struct ll_sb_info *sbi = ll_s2sbi(sb); 644 645 return seq_printf(m, 646 "statahead total: %u\n" 647 "statahead wrong: %u\n" 648 "agl total: %u\n", 649 atomic_read(&sbi->ll_sa_total), 650 atomic_read(&sbi->ll_sa_wrong), 651 atomic_read(&sbi->ll_agl_total)); 652} 653LPROC_SEQ_FOPS_RO(ll_statahead_stats); 654 655static int ll_lazystatfs_seq_show(struct seq_file *m, void *v) 656{ 657 struct super_block *sb = m->private; 658 struct ll_sb_info *sbi = ll_s2sbi(sb); 659 660 return seq_printf(m, "%u\n", 661 (sbi->ll_flags & LL_SBI_LAZYSTATFS) ? 1 : 0); 662} 663 664static ssize_t ll_lazystatfs_seq_write(struct file *file, const char *buffer, 665 size_t count, loff_t *off) 666{ 667 struct super_block *sb = ((struct seq_file *)file->private_data)->private; 668 struct ll_sb_info *sbi = ll_s2sbi(sb); 669 int val, rc; 670 671 rc = lprocfs_write_helper(buffer, count, &val); 672 if (rc) 673 return rc; 674 675 if (val) 676 sbi->ll_flags |= LL_SBI_LAZYSTATFS; 677 else 678 sbi->ll_flags &= ~LL_SBI_LAZYSTATFS; 679 680 return count; 681} 682LPROC_SEQ_FOPS(ll_lazystatfs); 683 684static int ll_maxea_size_seq_show(struct seq_file *m, void *v) 685{ 686 struct super_block *sb = m->private; 687 struct ll_sb_info *sbi = ll_s2sbi(sb); 688 unsigned int ealen; 689 int rc; 690 691 rc = ll_get_max_mdsize(sbi, &ealen); 692 if (rc) 693 return rc; 694 695 return seq_printf(m, "%u\n", ealen); 696} 697LPROC_SEQ_FOPS_RO(ll_maxea_size); 698 699static int ll_sbi_flags_seq_show(struct seq_file *m, void *v) 700{ 701 const char *str[] = LL_SBI_FLAGS; 702 struct super_block *sb = m->private; 703 int flags = ll_s2sbi(sb)->ll_flags; 704 int i = 0; 705 706 while (flags != 0) { 707 if (ARRAY_SIZE(str) <= i) { 708 CERROR("%s: Revise array LL_SBI_FLAGS to match sbi " 709 "flags please.\n", ll_get_fsname(sb, NULL, 0)); 710 return -EINVAL; 711 } 712 713 if (flags & 0x1) 714 seq_printf(m, "%s ", str[i]); 715 flags >>= 1; 716 ++i; 717 } 718 seq_printf(m, "\b\n"); 719 return 0; 720} 721LPROC_SEQ_FOPS_RO(ll_sbi_flags); 722 723static int ll_xattr_cache_seq_show(struct seq_file *m, void *v) 724{ 725 struct super_block *sb = m->private; 726 struct ll_sb_info *sbi = ll_s2sbi(sb); 727 int rc; 728 729 rc = seq_printf(m, "%u\n", sbi->ll_xattr_cache_enabled); 730 731 return rc; 732} 733 734static ssize_t ll_xattr_cache_seq_write(struct file *file, const char *buffer, 735 size_t count, loff_t *off) 736{ 737 struct seq_file *seq = file->private_data; 738 struct super_block *sb = seq->private; 739 struct ll_sb_info *sbi = ll_s2sbi(sb); 740 int val, rc; 741 742 rc = lprocfs_write_helper(buffer, count, &val); 743 if (rc) 744 return rc; 745 746 if (val != 0 && val != 1) 747 return -ERANGE; 748 749 if (val == 1 && !(sbi->ll_flags & LL_SBI_XATTR_CACHE)) 750 return -ENOTSUPP; 751 752 sbi->ll_xattr_cache_enabled = val; 753 754 return count; 755} 756LPROC_SEQ_FOPS(ll_xattr_cache); 757 758static struct lprocfs_vars lprocfs_llite_obd_vars[] = { 759 { "uuid", &ll_sb_uuid_fops, 0, 0 }, 760 //{ "mntpt_path", ll_rd_path, 0, 0 }, 761 { "fstype", &ll_fstype_fops, 0, 0 }, 762 { "site", &ll_site_stats_fops, 0, 0 }, 763 { "blocksize", &ll_blksize_fops, 0, 0 }, 764 { "kbytestotal", &ll_kbytestotal_fops, 0, 0 }, 765 { "kbytesfree", &ll_kbytesfree_fops, 0, 0 }, 766 { "kbytesavail", &ll_kbytesavail_fops, 0, 0 }, 767 { "filestotal", &ll_filestotal_fops, 0, 0 }, 768 { "filesfree", &ll_filesfree_fops, 0, 0 }, 769 { "client_type", &ll_client_type_fops, 0, 0 }, 770 //{ "filegroups", lprocfs_rd_filegroups, 0, 0 }, 771 { "max_read_ahead_mb", &ll_max_readahead_mb_fops, 0 }, 772 { "max_read_ahead_per_file_mb", &ll_max_readahead_per_file_mb_fops, 0 }, 773 { "max_read_ahead_whole_mb", &ll_max_read_ahead_whole_mb_fops, 0 }, 774 { "max_cached_mb", &ll_max_cached_mb_fops, 0 }, 775 { "checksum_pages", &ll_checksum_fops, 0 }, 776 { "max_rw_chunk", &ll_max_rw_chunk_fops, 0 }, 777 { "stats_track_pid", &ll_track_pid_fops, 0 }, 778 { "stats_track_ppid", &ll_track_ppid_fops, 0 }, 779 { "stats_track_gid", &ll_track_gid_fops, 0 }, 780 { "statahead_max", &ll_statahead_max_fops, 0 }, 781 { "statahead_agl", &ll_statahead_agl_fops, 0 }, 782 { "statahead_stats", &ll_statahead_stats_fops, 0, 0 }, 783 { "lazystatfs", &ll_lazystatfs_fops, 0 }, 784 { "max_easize", &ll_maxea_size_fops, 0, 0 }, 785 { "sbi_flags", &ll_sbi_flags_fops, 0, 0 }, 786 { "xattr_cache", &ll_xattr_cache_fops, 0, 0 }, 787 { 0 } 788}; 789 790#define MAX_STRING_SIZE 128 791 792struct llite_file_opcode { 793 __u32 opcode; 794 __u32 type; 795 const char *opname; 796} llite_opcode_table[LPROC_LL_FILE_OPCODES] = { 797 /* file operation */ 798 { LPROC_LL_DIRTY_HITS, LPROCFS_TYPE_REGS, "dirty_pages_hits" }, 799 { LPROC_LL_DIRTY_MISSES, LPROCFS_TYPE_REGS, "dirty_pages_misses" }, 800 { LPROC_LL_READ_BYTES, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES, 801 "read_bytes" }, 802 { LPROC_LL_WRITE_BYTES, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES, 803 "write_bytes" }, 804 { LPROC_LL_BRW_READ, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES, 805 "brw_read" }, 806 { LPROC_LL_BRW_WRITE, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES, 807 "brw_write" }, 808 { LPROC_LL_OSC_READ, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES, 809 "osc_read" }, 810 { LPROC_LL_OSC_WRITE, LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES, 811 "osc_write" }, 812 { LPROC_LL_IOCTL, LPROCFS_TYPE_REGS, "ioctl" }, 813 { LPROC_LL_OPEN, LPROCFS_TYPE_REGS, "open" }, 814 { LPROC_LL_RELEASE, LPROCFS_TYPE_REGS, "close" }, 815 { LPROC_LL_MAP, LPROCFS_TYPE_REGS, "mmap" }, 816 { LPROC_LL_LLSEEK, LPROCFS_TYPE_REGS, "seek" }, 817 { LPROC_LL_FSYNC, LPROCFS_TYPE_REGS, "fsync" }, 818 { LPROC_LL_READDIR, LPROCFS_TYPE_REGS, "readdir" }, 819 /* inode operation */ 820 { LPROC_LL_SETATTR, LPROCFS_TYPE_REGS, "setattr" }, 821 { LPROC_LL_TRUNC, LPROCFS_TYPE_REGS, "truncate" }, 822 { LPROC_LL_FLOCK, LPROCFS_TYPE_REGS, "flock" }, 823 { LPROC_LL_GETATTR, LPROCFS_TYPE_REGS, "getattr" }, 824 /* dir inode operation */ 825 { LPROC_LL_CREATE, LPROCFS_TYPE_REGS, "create" }, 826 { LPROC_LL_LINK, LPROCFS_TYPE_REGS, "link" }, 827 { LPROC_LL_UNLINK, LPROCFS_TYPE_REGS, "unlink" }, 828 { LPROC_LL_SYMLINK, LPROCFS_TYPE_REGS, "symlink" }, 829 { LPROC_LL_MKDIR, LPROCFS_TYPE_REGS, "mkdir" }, 830 { LPROC_LL_RMDIR, LPROCFS_TYPE_REGS, "rmdir" }, 831 { LPROC_LL_MKNOD, LPROCFS_TYPE_REGS, "mknod" }, 832 { LPROC_LL_RENAME, LPROCFS_TYPE_REGS, "rename" }, 833 /* special inode operation */ 834 { LPROC_LL_STAFS, LPROCFS_TYPE_REGS, "statfs" }, 835 { LPROC_LL_ALLOC_INODE, LPROCFS_TYPE_REGS, "alloc_inode" }, 836 { LPROC_LL_SETXATTR, LPROCFS_TYPE_REGS, "setxattr" }, 837 { LPROC_LL_GETXATTR, LPROCFS_TYPE_REGS, "getxattr" }, 838 { LPROC_LL_GETXATTR_HITS, LPROCFS_TYPE_REGS, "getxattr_hits" }, 839 { LPROC_LL_LISTXATTR, LPROCFS_TYPE_REGS, "listxattr" }, 840 { LPROC_LL_REMOVEXATTR, LPROCFS_TYPE_REGS, "removexattr" }, 841 { LPROC_LL_INODE_PERM, LPROCFS_TYPE_REGS, "inode_permission" }, 842}; 843 844void ll_stats_ops_tally(struct ll_sb_info *sbi, int op, int count) 845{ 846 if (!sbi->ll_stats) 847 return; 848 if (sbi->ll_stats_track_type == STATS_TRACK_ALL) 849 lprocfs_counter_add(sbi->ll_stats, op, count); 850 else if (sbi->ll_stats_track_type == STATS_TRACK_PID && 851 sbi->ll_stats_track_id == current->pid) 852 lprocfs_counter_add(sbi->ll_stats, op, count); 853 else if (sbi->ll_stats_track_type == STATS_TRACK_PPID && 854 sbi->ll_stats_track_id == current->parent->pid) 855 lprocfs_counter_add(sbi->ll_stats, op, count); 856 else if (sbi->ll_stats_track_type == STATS_TRACK_GID && 857 sbi->ll_stats_track_id == 858 from_kgid(&init_user_ns, current_gid())) 859 lprocfs_counter_add(sbi->ll_stats, op, count); 860} 861EXPORT_SYMBOL(ll_stats_ops_tally); 862 863static const char *ra_stat_string[] = { 864 [RA_STAT_HIT] = "hits", 865 [RA_STAT_MISS] = "misses", 866 [RA_STAT_DISTANT_READPAGE] = "readpage not consecutive", 867 [RA_STAT_MISS_IN_WINDOW] = "miss inside window", 868 [RA_STAT_FAILED_GRAB_PAGE] = "failed grab_cache_page", 869 [RA_STAT_FAILED_MATCH] = "failed lock match", 870 [RA_STAT_DISCARDED] = "read but discarded", 871 [RA_STAT_ZERO_LEN] = "zero length file", 872 [RA_STAT_ZERO_WINDOW] = "zero size window", 873 [RA_STAT_EOF] = "read-ahead to EOF", 874 [RA_STAT_MAX_IN_FLIGHT] = "hit max r-a issue", 875 [RA_STAT_WRONG_GRAB_PAGE] = "wrong page from grab_cache_page", 876}; 877 878LPROC_SEQ_FOPS_RO_TYPE(llite, name); 879LPROC_SEQ_FOPS_RO_TYPE(llite, uuid); 880 881int lprocfs_register_mountpoint(struct proc_dir_entry *parent, 882 struct super_block *sb, char *osc, char *mdc) 883{ 884 struct lprocfs_vars lvars[2]; 885 struct lustre_sb_info *lsi = s2lsi(sb); 886 struct ll_sb_info *sbi = ll_s2sbi(sb); 887 struct obd_device *obd; 888 struct proc_dir_entry *dir; 889 char name[MAX_STRING_SIZE + 1], *ptr; 890 int err, id, len, rc; 891 892 memset(lvars, 0, sizeof(lvars)); 893 894 name[MAX_STRING_SIZE] = '\0'; 895 lvars[0].name = name; 896 897 LASSERT(sbi != NULL); 898 LASSERT(mdc != NULL); 899 LASSERT(osc != NULL); 900 901 /* Get fsname */ 902 len = strlen(lsi->lsi_lmd->lmd_profile); 903 ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-'); 904 if (ptr && (strcmp(ptr, "-client") == 0)) 905 len -= 7; 906 907 /* Mount info */ 908 snprintf(name, MAX_STRING_SIZE, "%.*s-%p", len, 909 lsi->lsi_lmd->lmd_profile, sb); 910 911 sbi->ll_proc_root = lprocfs_register(name, parent, NULL, NULL); 912 if (IS_ERR(sbi->ll_proc_root)) { 913 err = PTR_ERR(sbi->ll_proc_root); 914 sbi->ll_proc_root = NULL; 915 return err; 916 } 917 918 rc = lprocfs_seq_create(sbi->ll_proc_root, "dump_page_cache", 0444, 919 &vvp_dump_pgcache_file_ops, sbi); 920 if (rc) 921 CWARN("Error adding the dump_page_cache file\n"); 922 923 rc = lprocfs_seq_create(sbi->ll_proc_root, "extents_stats", 0644, 924 &ll_rw_extents_stats_fops, sbi); 925 if (rc) 926 CWARN("Error adding the extent_stats file\n"); 927 928 rc = lprocfs_seq_create(sbi->ll_proc_root, "extents_stats_per_process", 929 0644, &ll_rw_extents_stats_pp_fops, sbi); 930 if (rc) 931 CWARN("Error adding the extents_stats_per_process file\n"); 932 933 rc = lprocfs_seq_create(sbi->ll_proc_root, "offset_stats", 0644, 934 &ll_rw_offset_stats_fops, sbi); 935 if (rc) 936 CWARN("Error adding the offset_stats file\n"); 937 938 /* File operations stats */ 939 sbi->ll_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES, 940 LPROCFS_STATS_FLAG_NONE); 941 if (sbi->ll_stats == NULL) 942 GOTO(out, err = -ENOMEM); 943 /* do counter init */ 944 for (id = 0; id < LPROC_LL_FILE_OPCODES; id++) { 945 __u32 type = llite_opcode_table[id].type; 946 void *ptr = NULL; 947 if (type & LPROCFS_TYPE_REGS) 948 ptr = "regs"; 949 else if (type & LPROCFS_TYPE_BYTES) 950 ptr = "bytes"; 951 else if (type & LPROCFS_TYPE_PAGES) 952 ptr = "pages"; 953 lprocfs_counter_init(sbi->ll_stats, 954 llite_opcode_table[id].opcode, 955 (type & LPROCFS_CNTR_AVGMINMAX), 956 llite_opcode_table[id].opname, ptr); 957 } 958 err = lprocfs_register_stats(sbi->ll_proc_root, "stats", sbi->ll_stats); 959 if (err) 960 GOTO(out, err); 961 962 sbi->ll_ra_stats = lprocfs_alloc_stats(ARRAY_SIZE(ra_stat_string), 963 LPROCFS_STATS_FLAG_NONE); 964 if (sbi->ll_ra_stats == NULL) 965 GOTO(out, err = -ENOMEM); 966 967 for (id = 0; id < ARRAY_SIZE(ra_stat_string); id++) 968 lprocfs_counter_init(sbi->ll_ra_stats, id, 0, 969 ra_stat_string[id], "pages"); 970 err = lprocfs_register_stats(sbi->ll_proc_root, "read_ahead_stats", 971 sbi->ll_ra_stats); 972 if (err) 973 GOTO(out, err); 974 975 976 err = lprocfs_add_vars(sbi->ll_proc_root, lprocfs_llite_obd_vars, sb); 977 if (err) 978 GOTO(out, err); 979 980 /* MDC info */ 981 obd = class_name2obd(mdc); 982 983 LASSERT(obd != NULL); 984 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); 985 LASSERT(obd->obd_type->typ_name != NULL); 986 987 dir = proc_mkdir(obd->obd_type->typ_name, sbi->ll_proc_root); 988 if (dir == NULL) 989 GOTO(out, err = -ENOMEM); 990 991 snprintf(name, MAX_STRING_SIZE, "common_name"); 992 lvars[0].fops = &llite_name_fops; 993 err = lprocfs_add_vars(dir, lvars, obd); 994 if (err) 995 GOTO(out, err); 996 997 snprintf(name, MAX_STRING_SIZE, "uuid"); 998 lvars[0].fops = &llite_uuid_fops; 999 err = lprocfs_add_vars(dir, lvars, obd); 1000 if (err) 1001 GOTO(out, err); 1002 1003 /* OSC */ 1004 obd = class_name2obd(osc); 1005 1006 LASSERT(obd != NULL); 1007 LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); 1008 LASSERT(obd->obd_type->typ_name != NULL); 1009 1010 dir = proc_mkdir(obd->obd_type->typ_name, sbi->ll_proc_root); 1011 if (dir == NULL) 1012 GOTO(out, err = -ENOMEM); 1013 1014 snprintf(name, MAX_STRING_SIZE, "common_name"); 1015 lvars[0].fops = &llite_name_fops; 1016 err = lprocfs_add_vars(dir, lvars, obd); 1017 if (err) 1018 GOTO(out, err); 1019 1020 snprintf(name, MAX_STRING_SIZE, "uuid"); 1021 lvars[0].fops = &llite_uuid_fops; 1022 err = lprocfs_add_vars(dir, lvars, obd); 1023out: 1024 if (err) { 1025 lprocfs_remove(&sbi->ll_proc_root); 1026 lprocfs_free_stats(&sbi->ll_ra_stats); 1027 lprocfs_free_stats(&sbi->ll_stats); 1028 } 1029 return err; 1030} 1031 1032void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi) 1033{ 1034 if (sbi->ll_proc_root) { 1035 lprocfs_remove(&sbi->ll_proc_root); 1036 lprocfs_free_stats(&sbi->ll_ra_stats); 1037 lprocfs_free_stats(&sbi->ll_stats); 1038 } 1039} 1040#undef MAX_STRING_SIZE 1041 1042#define pct(a,b) (b ? a * 100 / b : 0) 1043 1044static void ll_display_extents_info(struct ll_rw_extents_info *io_extents, 1045 struct seq_file *seq, int which) 1046{ 1047 unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum; 1048 unsigned long start, end, r, w; 1049 char *unitp = "KMGTPEZY"; 1050 int i, units = 10; 1051 struct per_process_info *pp_info = &io_extents->pp_extents[which]; 1052 1053 read_cum = 0; 1054 write_cum = 0; 1055 start = 0; 1056 1057 for(i = 0; i < LL_HIST_MAX; i++) { 1058 read_tot += pp_info->pp_r_hist.oh_buckets[i]; 1059 write_tot += pp_info->pp_w_hist.oh_buckets[i]; 1060 } 1061 1062 for(i = 0; i < LL_HIST_MAX; i++) { 1063 r = pp_info->pp_r_hist.oh_buckets[i]; 1064 w = pp_info->pp_w_hist.oh_buckets[i]; 1065 read_cum += r; 1066 write_cum += w; 1067 end = 1 << (i + LL_HIST_START - units); 1068 seq_printf(seq, "%4lu%c - %4lu%c%c: %14lu %4lu %4lu | " 1069 "%14lu %4lu %4lu\n", start, *unitp, end, *unitp, 1070 (i == LL_HIST_MAX - 1) ? '+' : ' ', 1071 r, pct(r, read_tot), pct(read_cum, read_tot), 1072 w, pct(w, write_tot), pct(write_cum, write_tot)); 1073 start = end; 1074 if (start == 1<<10) { 1075 start = 1; 1076 units += 10; 1077 unitp++; 1078 } 1079 if (read_cum == read_tot && write_cum == write_tot) 1080 break; 1081 } 1082} 1083 1084static int ll_rw_extents_stats_pp_seq_show(struct seq_file *seq, void *v) 1085{ 1086 struct timeval now; 1087 struct ll_sb_info *sbi = seq->private; 1088 struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info; 1089 int k; 1090 1091 do_gettimeofday(&now); 1092 1093 if (!sbi->ll_rw_stats_on) { 1094 seq_printf(seq, "disabled\n" 1095 "write anything in this file to activate, " 1096 "then 0 or \"[D/d]isabled\" to deactivate\n"); 1097 return 0; 1098 } 1099 seq_printf(seq, "snapshot_time: %lu.%lu (secs.usecs)\n", 1100 now.tv_sec, (unsigned long)now.tv_usec); 1101 seq_printf(seq, "%15s %19s | %20s\n", " ", "read", "write"); 1102 seq_printf(seq, "%13s %14s %4s %4s | %14s %4s %4s\n", 1103 "extents", "calls", "%", "cum%", 1104 "calls", "%", "cum%"); 1105 spin_lock(&sbi->ll_pp_extent_lock); 1106 for (k = 0; k < LL_PROCESS_HIST_MAX; k++) { 1107 if (io_extents->pp_extents[k].pid != 0) { 1108 seq_printf(seq, "\nPID: %d\n", 1109 io_extents->pp_extents[k].pid); 1110 ll_display_extents_info(io_extents, seq, k); 1111 } 1112 } 1113 spin_unlock(&sbi->ll_pp_extent_lock); 1114 return 0; 1115} 1116 1117static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file, 1118 const char *buf, size_t len, 1119 loff_t *off) 1120{ 1121 struct seq_file *seq = file->private_data; 1122 struct ll_sb_info *sbi = seq->private; 1123 struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info; 1124 int i; 1125 int value = 1, rc = 0; 1126 1127 rc = lprocfs_write_helper(buf, len, &value); 1128 if (rc < 0 && (strcmp(buf, "disabled") == 0 || 1129 strcmp(buf, "Disabled") == 0)) 1130 value = 0; 1131 1132 if (value == 0) 1133 sbi->ll_rw_stats_on = 0; 1134 else 1135 sbi->ll_rw_stats_on = 1; 1136 1137 spin_lock(&sbi->ll_pp_extent_lock); 1138 for (i = 0; i < LL_PROCESS_HIST_MAX; i++) { 1139 io_extents->pp_extents[i].pid = 0; 1140 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist); 1141 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist); 1142 } 1143 spin_unlock(&sbi->ll_pp_extent_lock); 1144 return len; 1145} 1146 1147LPROC_SEQ_FOPS(ll_rw_extents_stats_pp); 1148 1149static int ll_rw_extents_stats_seq_show(struct seq_file *seq, void *v) 1150{ 1151 struct timeval now; 1152 struct ll_sb_info *sbi = seq->private; 1153 struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info; 1154 1155 do_gettimeofday(&now); 1156 1157 if (!sbi->ll_rw_stats_on) { 1158 seq_printf(seq, "disabled\n" 1159 "write anything in this file to activate, " 1160 "then 0 or \"[D/d]isabled\" to deactivate\n"); 1161 return 0; 1162 } 1163 seq_printf(seq, "snapshot_time: %lu.%lu (secs.usecs)\n", 1164 now.tv_sec, (unsigned long)now.tv_usec); 1165 1166 seq_printf(seq, "%15s %19s | %20s\n", " ", "read", "write"); 1167 seq_printf(seq, "%13s %14s %4s %4s | %14s %4s %4s\n", 1168 "extents", "calls", "%", "cum%", 1169 "calls", "%", "cum%"); 1170 spin_lock(&sbi->ll_lock); 1171 ll_display_extents_info(io_extents, seq, LL_PROCESS_HIST_MAX); 1172 spin_unlock(&sbi->ll_lock); 1173 1174 return 0; 1175} 1176 1177static ssize_t ll_rw_extents_stats_seq_write(struct file *file, const char *buf, 1178 size_t len, loff_t *off) 1179{ 1180 struct seq_file *seq = file->private_data; 1181 struct ll_sb_info *sbi = seq->private; 1182 struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info; 1183 int i; 1184 int value = 1, rc = 0; 1185 1186 rc = lprocfs_write_helper(buf, len, &value); 1187 if (rc < 0 && (strcmp(buf, "disabled") == 0 || 1188 strcmp(buf, "Disabled") == 0)) 1189 value = 0; 1190 1191 if (value == 0) 1192 sbi->ll_rw_stats_on = 0; 1193 else 1194 sbi->ll_rw_stats_on = 1; 1195 spin_lock(&sbi->ll_pp_extent_lock); 1196 for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) { 1197 io_extents->pp_extents[i].pid = 0; 1198 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist); 1199 lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist); 1200 } 1201 spin_unlock(&sbi->ll_pp_extent_lock); 1202 1203 return len; 1204} 1205 1206LPROC_SEQ_FOPS(ll_rw_extents_stats); 1207 1208void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid, 1209 struct ll_file_data *file, loff_t pos, 1210 size_t count, int rw) 1211{ 1212 int i, cur = -1; 1213 struct ll_rw_process_info *process; 1214 struct ll_rw_process_info *offset; 1215 int *off_count = &sbi->ll_rw_offset_entry_count; 1216 int *process_count = &sbi->ll_offset_process_count; 1217 struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info; 1218 1219 if(!sbi->ll_rw_stats_on) 1220 return; 1221 process = sbi->ll_rw_process_info; 1222 offset = sbi->ll_rw_offset_info; 1223 1224 spin_lock(&sbi->ll_pp_extent_lock); 1225 /* Extent statistics */ 1226 for(i = 0; i < LL_PROCESS_HIST_MAX; i++) { 1227 if(io_extents->pp_extents[i].pid == pid) { 1228 cur = i; 1229 break; 1230 } 1231 } 1232 1233 if (cur == -1) { 1234 /* new process */ 1235 sbi->ll_extent_process_count = 1236 (sbi->ll_extent_process_count + 1) % LL_PROCESS_HIST_MAX; 1237 cur = sbi->ll_extent_process_count; 1238 io_extents->pp_extents[cur].pid = pid; 1239 lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_r_hist); 1240 lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_w_hist); 1241 } 1242 1243 for(i = 0; (count >= (1 << LL_HIST_START << i)) && 1244 (i < (LL_HIST_MAX - 1)); i++); 1245 if (rw == 0) { 1246 io_extents->pp_extents[cur].pp_r_hist.oh_buckets[i]++; 1247 io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_r_hist.oh_buckets[i]++; 1248 } else { 1249 io_extents->pp_extents[cur].pp_w_hist.oh_buckets[i]++; 1250 io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_w_hist.oh_buckets[i]++; 1251 } 1252 spin_unlock(&sbi->ll_pp_extent_lock); 1253 1254 spin_lock(&sbi->ll_process_lock); 1255 /* Offset statistics */ 1256 for (i = 0; i < LL_PROCESS_HIST_MAX; i++) { 1257 if (process[i].rw_pid == pid) { 1258 if (process[i].rw_last_file != file) { 1259 process[i].rw_range_start = pos; 1260 process[i].rw_last_file_pos = pos + count; 1261 process[i].rw_smallest_extent = count; 1262 process[i].rw_largest_extent = count; 1263 process[i].rw_offset = 0; 1264 process[i].rw_last_file = file; 1265 spin_unlock(&sbi->ll_process_lock); 1266 return; 1267 } 1268 if (process[i].rw_last_file_pos != pos) { 1269 *off_count = 1270 (*off_count + 1) % LL_OFFSET_HIST_MAX; 1271 offset[*off_count].rw_op = process[i].rw_op; 1272 offset[*off_count].rw_pid = pid; 1273 offset[*off_count].rw_range_start = 1274 process[i].rw_range_start; 1275 offset[*off_count].rw_range_end = 1276 process[i].rw_last_file_pos; 1277 offset[*off_count].rw_smallest_extent = 1278 process[i].rw_smallest_extent; 1279 offset[*off_count].rw_largest_extent = 1280 process[i].rw_largest_extent; 1281 offset[*off_count].rw_offset = 1282 process[i].rw_offset; 1283 process[i].rw_op = rw; 1284 process[i].rw_range_start = pos; 1285 process[i].rw_smallest_extent = count; 1286 process[i].rw_largest_extent = count; 1287 process[i].rw_offset = pos - 1288 process[i].rw_last_file_pos; 1289 } 1290 if(process[i].rw_smallest_extent > count) 1291 process[i].rw_smallest_extent = count; 1292 if(process[i].rw_largest_extent < count) 1293 process[i].rw_largest_extent = count; 1294 process[i].rw_last_file_pos = pos + count; 1295 spin_unlock(&sbi->ll_process_lock); 1296 return; 1297 } 1298 } 1299 *process_count = (*process_count + 1) % LL_PROCESS_HIST_MAX; 1300 process[*process_count].rw_pid = pid; 1301 process[*process_count].rw_op = rw; 1302 process[*process_count].rw_range_start = pos; 1303 process[*process_count].rw_last_file_pos = pos + count; 1304 process[*process_count].rw_smallest_extent = count; 1305 process[*process_count].rw_largest_extent = count; 1306 process[*process_count].rw_offset = 0; 1307 process[*process_count].rw_last_file = file; 1308 spin_unlock(&sbi->ll_process_lock); 1309} 1310 1311static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v) 1312{ 1313 struct timeval now; 1314 struct ll_sb_info *sbi = seq->private; 1315 struct ll_rw_process_info *offset = sbi->ll_rw_offset_info; 1316 struct ll_rw_process_info *process = sbi->ll_rw_process_info; 1317 int i; 1318 1319 do_gettimeofday(&now); 1320 1321 if (!sbi->ll_rw_stats_on) { 1322 seq_printf(seq, "disabled\n" 1323 "write anything in this file to activate, " 1324 "then 0 or \"[D/d]isabled\" to deactivate\n"); 1325 return 0; 1326 } 1327 spin_lock(&sbi->ll_process_lock); 1328 1329 seq_printf(seq, "snapshot_time: %lu.%lu (secs.usecs)\n", 1330 now.tv_sec, (unsigned long)now.tv_usec); 1331 seq_printf(seq, "%3s %10s %14s %14s %17s %17s %14s\n", 1332 "R/W", "PID", "RANGE START", "RANGE END", 1333 "SMALLEST EXTENT", "LARGEST EXTENT", "OFFSET"); 1334 /* We stored the discontiguous offsets here; print them first */ 1335 for(i = 0; i < LL_OFFSET_HIST_MAX; i++) { 1336 if (offset[i].rw_pid != 0) 1337 seq_printf(seq, 1338 "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu", 1339 offset[i].rw_op == READ ? 'R' : 'W', 1340 offset[i].rw_pid, 1341 offset[i].rw_range_start, 1342 offset[i].rw_range_end, 1343 (unsigned long)offset[i].rw_smallest_extent, 1344 (unsigned long)offset[i].rw_largest_extent, 1345 offset[i].rw_offset); 1346 } 1347 /* Then print the current offsets for each process */ 1348 for(i = 0; i < LL_PROCESS_HIST_MAX; i++) { 1349 if (process[i].rw_pid != 0) 1350 seq_printf(seq, 1351 "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu", 1352 process[i].rw_op == READ ? 'R' : 'W', 1353 process[i].rw_pid, 1354 process[i].rw_range_start, 1355 process[i].rw_last_file_pos, 1356 (unsigned long)process[i].rw_smallest_extent, 1357 (unsigned long)process[i].rw_largest_extent, 1358 process[i].rw_offset); 1359 } 1360 spin_unlock(&sbi->ll_process_lock); 1361 1362 return 0; 1363} 1364 1365static ssize_t ll_rw_offset_stats_seq_write(struct file *file, const char *buf, 1366 size_t len, loff_t *off) 1367{ 1368 struct seq_file *seq = file->private_data; 1369 struct ll_sb_info *sbi = seq->private; 1370 struct ll_rw_process_info *process_info = sbi->ll_rw_process_info; 1371 struct ll_rw_process_info *offset_info = sbi->ll_rw_offset_info; 1372 int value = 1, rc = 0; 1373 1374 rc = lprocfs_write_helper(buf, len, &value); 1375 1376 if (rc < 0 && (strcmp(buf, "disabled") == 0 || 1377 strcmp(buf, "Disabled") == 0)) 1378 value = 0; 1379 1380 if (value == 0) 1381 sbi->ll_rw_stats_on = 0; 1382 else 1383 sbi->ll_rw_stats_on = 1; 1384 1385 spin_lock(&sbi->ll_process_lock); 1386 sbi->ll_offset_process_count = 0; 1387 sbi->ll_rw_offset_entry_count = 0; 1388 memset(process_info, 0, sizeof(struct ll_rw_process_info) * 1389 LL_PROCESS_HIST_MAX); 1390 memset(offset_info, 0, sizeof(struct ll_rw_process_info) * 1391 LL_OFFSET_HIST_MAX); 1392 spin_unlock(&sbi->ll_process_lock); 1393 1394 return len; 1395} 1396 1397LPROC_SEQ_FOPS(ll_rw_offset_stats); 1398 1399void lprocfs_llite_init_vars(struct lprocfs_static_vars *lvars) 1400{ 1401 lvars->module_vars = NULL; 1402 lvars->obd_vars = lprocfs_llite_obd_vars; 1403} 1404