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