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