Whamcloud - gitweb
Branch b1_4_newconfig2
[fs/lustre-release.git] / lustre / llite / lproc_llite.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22 #define DEBUG_SUBSYSTEM S_LLITE
23
24 #include <linux/version.h>
25 #include <linux/lustre_lite.h>
26 #include <linux/lprocfs_status.h>
27 #include <linux/seq_file.h>
28 #include <linux/obd_support.h>
29
30 #include "llite_internal.h"
31
32 struct proc_dir_entry *proc_lustre_fs_root;
33
34 #ifdef LPROCFS
35 /* /proc/lustre/llite mount point registration */
36 struct file_operations llite_dump_pgcache_fops;
37 struct file_operations ll_ra_stats_fops;
38
39 long long mnt_instance;
40
41 static int ll_rd_blksize(char *page, char **start, off_t off, int count,
42                          int *eof, void *data)
43 {
44         struct super_block *sb = (struct super_block *)data;
45         struct obd_statfs osfs;
46         int rc;
47
48         LASSERT(sb != NULL);
49         rc = ll_statfs_internal(sb, &osfs, jiffies - HZ);
50         if (!rc) {
51               *eof = 1;
52               rc = snprintf(page, count, "%u\n", osfs.os_bsize);
53         }
54
55         return rc;
56 }
57
58 static int ll_rd_kbytestotal(char *page, char **start, off_t off, int count,
59                              int *eof, void *data)
60 {
61         struct super_block *sb = (struct super_block *)data;
62         struct obd_statfs osfs;
63         int rc;
64
65         LASSERT(sb != NULL);
66         rc = ll_statfs_internal(sb, &osfs, jiffies - HZ);
67         if (!rc) {
68                 __u32 blk_size = osfs.os_bsize >> 10;
69                 __u64 result = osfs.os_blocks;
70
71                 while (blk_size >>= 1)
72                         result <<= 1;
73
74                 *eof = 1;
75                 rc = snprintf(page, count, LPU64"\n", result);
76         }
77         return rc;
78
79 }
80
81 static int ll_rd_kbytesfree(char *page, char **start, off_t off, int count,
82                             int *eof, void *data)
83 {
84         struct super_block *sb = (struct super_block *)data;
85         struct obd_statfs osfs;
86         int rc;
87
88         LASSERT(sb != NULL);
89         rc = ll_statfs_internal(sb, &osfs, jiffies - HZ);
90         if (!rc) {
91                 __u32 blk_size = osfs.os_bsize >> 10;
92                 __u64 result = osfs.os_bfree;
93
94                 while (blk_size >>= 1)
95                         result <<= 1;
96
97                 *eof = 1;
98                 rc = snprintf(page, count, LPU64"\n", result);
99         }
100         return rc;
101 }
102
103 static int ll_rd_kbytesavail(char *page, char **start, off_t off, int count,
104                              int *eof, void *data)
105 {
106         struct super_block *sb = (struct super_block *)data;
107         struct obd_statfs osfs;
108         int rc;
109
110         LASSERT(sb != NULL);
111         rc = ll_statfs_internal(sb, &osfs, jiffies - HZ);
112         if (!rc) {
113                 __u32 blk_size = osfs.os_bsize >> 10;
114                 __u64 result = osfs.os_bavail;
115
116                 while (blk_size >>= 1)
117                         result <<= 1;
118
119                 *eof = 1;
120                 rc = snprintf(page, count, LPU64"\n", result);
121         }
122         return rc;
123 }
124
125 static int ll_rd_filestotal(char *page, char **start, off_t off, int count,
126                             int *eof, void *data)
127 {
128         struct super_block *sb = (struct super_block *)data;
129         struct obd_statfs osfs;
130         int rc;
131
132         LASSERT(sb != NULL);
133         rc = ll_statfs_internal(sb, &osfs, jiffies - HZ);
134         if (!rc) {
135                  *eof = 1;
136                  rc = snprintf(page, count, LPU64"\n", osfs.os_files);
137         }
138         return rc;
139 }
140
141 static int ll_rd_filesfree(char *page, char **start, off_t off, int count,
142                            int *eof, void *data)
143 {
144         struct super_block *sb = (struct super_block *)data;
145         struct obd_statfs osfs;
146         int rc;
147
148         LASSERT(sb != NULL);
149         rc = ll_statfs_internal(sb, &osfs, jiffies - HZ);
150         if (!rc) {
151                  *eof = 1;
152                  rc = snprintf(page, count, LPU64"\n", osfs.os_ffree);
153         }
154         return rc;
155
156 }
157
158 static int ll_rd_fstype(char *page, char **start, off_t off, int count,
159                         int *eof, void *data)
160 {
161         struct super_block *sb = (struct super_block*)data;
162
163         LASSERT(sb != NULL);
164         *eof = 1;
165         return snprintf(page, count, "%s\n", sb->s_type->name);
166 }
167
168 static int ll_rd_sb_uuid(char *page, char **start, off_t off, int count,
169                          int *eof, void *data)
170 {
171         struct super_block *sb = (struct super_block *)data;
172
173         LASSERT(sb != NULL);
174         *eof = 1;
175         return snprintf(page, count, "%s\n", ll_s2sbi(sb)->ll_sb_uuid.uuid);
176 }
177
178 static int ll_rd_max_readahead_mb(char *page, char **start, off_t off,
179                                    int count, int *eof, void *data)
180 {
181         struct super_block *sb = data;
182         struct ll_sb_info *sbi = ll_s2sbi(sb);
183         unsigned val;
184
185         spin_lock(&sbi->ll_lock);
186         val = sbi->ll_ra_info.ra_max_pages >> (20 - PAGE_CACHE_SHIFT);
187         spin_unlock(&sbi->ll_lock);
188
189         return snprintf(page, count, "%u\n", val);
190 }
191
192 static int ll_wr_max_readahead_mb(struct file *file, const char *buffer,
193                                    unsigned long count, void *data)
194 {
195         struct super_block *sb = data;
196         struct ll_sb_info *sbi = ll_s2sbi(sb);
197         int val, rc;
198
199         rc = lprocfs_write_helper(buffer, count, &val);
200         if (rc)
201                 return rc;
202
203         if (val < 0 || val > (num_physpages >> (20 - PAGE_CACHE_SHIFT - 1))) {
204                 CERROR("can't set readahead more than %lu MB\n",
205                         num_physpages >> (20 - PAGE_CACHE_SHIFT - 1));
206                 return -ERANGE;
207         }
208
209         spin_lock(&sbi->ll_lock);
210         sbi->ll_ra_info.ra_max_pages = val << (20 - PAGE_CACHE_SHIFT);
211         spin_unlock(&sbi->ll_lock);
212
213         return count;
214 }
215
216 static int ll_rd_max_cached_mb(char *page, char **start, off_t off,
217                                int count, int *eof, void *data)
218 {
219         struct super_block *sb = data;
220         struct ll_sb_info *sbi = ll_s2sbi(sb);
221         unsigned val;
222
223         spin_lock(&sbi->ll_lock);
224         val = sbi->ll_async_page_max >> (20 - PAGE_CACHE_SHIFT);
225         spin_unlock(&sbi->ll_lock);
226
227         return snprintf(page, count, "%u\n", val);
228 }
229
230 static int ll_wr_max_cached_mb(struct file *file, const char *buffer,
231                                   unsigned long count, void *data)
232 {
233         struct super_block *sb = data;
234         struct ll_sb_info *sbi = ll_s2sbi(sb);
235         int val, rc;
236
237         rc = lprocfs_write_helper(buffer, count, &val);
238         if (rc)
239                 return rc;
240
241         if (val < 0 || val > (num_physpages >> (20 - PAGE_CACHE_SHIFT))) {
242                 CERROR("can't set max cache more than %lu MB\n",
243                         num_physpages >> (20 - PAGE_CACHE_SHIFT));
244                 return -ERANGE;
245         }
246
247         spin_lock(&sbi->ll_lock);
248         sbi->ll_async_page_max = val << (20 - PAGE_CACHE_SHIFT);
249         spin_unlock(&sbi->ll_lock);
250
251         if (sbi->ll_async_page_count >= sbi->ll_async_page_max)
252                 llap_shrink_cache(sbi, 0);
253
254         return count;
255 }
256
257 static int ll_rd_checksum(char *page, char **start, off_t off,
258                           int count, int *eof, void *data)
259 {
260         struct super_block *sb = data;
261         struct ll_sb_info *sbi = ll_s2sbi(sb);
262
263         return snprintf(page, count, "%u\n",
264                         (sbi->ll_flags & LL_SBI_CHECKSUM) ? 1 : 0);
265 }
266
267 static int ll_wr_checksum(struct file *file, const char *buffer,
268                           unsigned long count, void *data)
269 {
270         struct super_block *sb = data;
271         struct ll_sb_info *sbi = ll_s2sbi(sb);
272         int val, rc;
273
274         rc = lprocfs_write_helper(buffer, count, &val);
275         if (rc)
276                 return rc;
277
278         if (val)
279                 sbi->ll_flags |= LL_SBI_CHECKSUM;
280         else
281                 sbi->ll_flags &= ~LL_SBI_CHECKSUM;
282
283         rc = obd_set_info(sbi->ll_osc_exp, strlen("checksum"), "checksum",
284                           sizeof(val), &val);
285         if (rc)
286                 CWARN("Failed to set OSC checksum flags: %d\n", rc);
287
288         return count;
289 }
290
291 static struct lprocfs_vars lprocfs_obd_vars[] = {
292         { "uuid",         ll_rd_sb_uuid,          0, 0 },
293         //{ "mntpt_path",   ll_rd_path,             0, 0 },
294         { "fstype",       ll_rd_fstype,           0, 0 },
295         { "blocksize",    ll_rd_blksize,          0, 0 },
296         { "kbytestotal",  ll_rd_kbytestotal,      0, 0 },
297         { "kbytesfree",   ll_rd_kbytesfree,       0, 0 },
298         { "kbytesavail",  ll_rd_kbytesavail,      0, 0 },
299         { "filestotal",   ll_rd_filestotal,       0, 0 },
300         { "filesfree",    ll_rd_filesfree,        0, 0 },
301         //{ "filegroups",   lprocfs_rd_filegroups,  0, 0 },
302         { "max_read_ahead_mb", ll_rd_max_readahead_mb,
303                                ll_wr_max_readahead_mb, 0 },
304         { "max_cached_mb", ll_rd_max_cached_mb, ll_wr_max_cached_mb, 0 },
305         { "checksum_pages", ll_rd_checksum, ll_wr_checksum, 0 },
306         { 0 }
307 };
308
309 #define MAX_STRING_SIZE 128
310
311 struct llite_file_opcode {
312         __u32       opcode;
313         __u32       type;
314         const char *opname;
315 } llite_opcode_table[LPROC_LL_FILE_OPCODES] = {
316         /* file operation */
317         { LPROC_LL_DIRTY_HITS,     LPROCFS_TYPE_REGS, "dirty_pages_hits" },
318         { LPROC_LL_DIRTY_MISSES,   LPROCFS_TYPE_REGS, "dirty_pages_misses" },
319         { LPROC_LL_WB_WRITEPAGE,   LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
320                                    "writeback_from_writepage" },
321         { LPROC_LL_WB_PRESSURE,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
322                                    "writeback_from_pressure" },
323         { LPROC_LL_WB_OK,          LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
324                                    "writeback_ok_pages" },
325         { LPROC_LL_WB_FAIL,        LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
326                                    "writeback_failed_pages" },
327         { LPROC_LL_READ_BYTES,     LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
328                                    "read_bytes" },
329         { LPROC_LL_WRITE_BYTES,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_BYTES,
330                                    "write_bytes" },
331         { LPROC_LL_BRW_READ,       LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
332                                    "brw_read" },
333         { LPROC_LL_BRW_WRITE,      LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
334                                    "brw_write" },
335
336         { LPROC_LL_IOCTL,          LPROCFS_TYPE_REGS, "ioctl" },
337         { LPROC_LL_OPEN,           LPROCFS_TYPE_REGS, "open" },
338         { LPROC_LL_RELEASE,        LPROCFS_TYPE_REGS, "close" },
339         { LPROC_LL_MAP,            LPROCFS_TYPE_REGS, "mmap" },
340         { LPROC_LL_LLSEEK,         LPROCFS_TYPE_REGS, "seek" },
341         { LPROC_LL_FSYNC,          LPROCFS_TYPE_REGS, "fsync" },
342         /* inode operation */
343         { LPROC_LL_SETATTR,        LPROCFS_TYPE_REGS, "setattr" },
344         { LPROC_LL_TRUNC,          LPROCFS_TYPE_REGS, "punch" },
345 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
346         { LPROC_LL_GETATTR,        LPROCFS_TYPE_REGS, "getattr" },
347 #else
348         { LPROC_LL_REVALIDATE,     LPROCFS_TYPE_REGS, "getattr" },
349 #endif
350         /* special inode operation */
351         { LPROC_LL_STAFS,          LPROCFS_TYPE_REGS, "statfs" },
352         { LPROC_LL_ALLOC_INODE,    LPROCFS_TYPE_REGS, "alloc_inode" },
353         { LPROC_LL_DIRECT_READ,    LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
354                                    "direct_read" },
355         { LPROC_LL_DIRECT_WRITE,   LPROCFS_CNTR_AVGMINMAX|LPROCFS_TYPE_PAGES,
356                                    "direct_write" },
357
358 };
359
360 int lprocfs_register_mountpoint(struct proc_dir_entry *parent,
361                                 struct super_block *sb, char *osc, char *mdc)
362 {
363         struct lprocfs_vars lvars[2];
364         struct ll_sb_info *sbi = ll_s2sbi(sb);
365         struct obd_device *obd;
366         char name[MAX_STRING_SIZE + 1];
367         int err, id;
368         struct lprocfs_stats *svc_stats = NULL;
369         struct proc_dir_entry *entry;
370         ENTRY;
371
372         memset(lvars, 0, sizeof(lvars));
373
374         name[MAX_STRING_SIZE] = '\0';
375         lvars[0].name = name;
376
377         LASSERT(sbi != NULL);
378         LASSERT(mdc != NULL);
379         LASSERT(osc != NULL);
380
381         /* Mount info */
382         snprintf(name, MAX_STRING_SIZE, "fs%llu", mnt_instance);
383
384         mnt_instance++;
385         sbi->ll_proc_root = lprocfs_register(name, parent, NULL, NULL);
386         if (IS_ERR(sbi->ll_proc_root)) {
387                 err = PTR_ERR(sbi->ll_proc_root);
388                 sbi->ll_proc_root = NULL;
389                 RETURN(err);
390         }
391
392         entry = create_proc_entry("dump_page_cache", 0444, sbi->ll_proc_root);
393         if (entry == NULL)
394                 GOTO(out, err = -ENOMEM);
395         entry->proc_fops = &llite_dump_pgcache_fops;
396         entry->data = sbi;
397
398         entry = create_proc_entry("read_ahead_stats", 0444, sbi->ll_proc_root);
399         if (entry == NULL)
400                 GOTO(out, err = -ENOMEM);
401         entry->proc_fops = &ll_ra_stats_fops;
402         entry->data = sbi;
403
404         svc_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES);
405         if (svc_stats == NULL) {
406                 err = -ENOMEM;
407                 goto out;
408         }
409         /* do counter init */
410         for (id = 0; id < LPROC_LL_FILE_OPCODES; id++) {
411                 __u32 type = llite_opcode_table[id].type;
412                 void *ptr = NULL;
413                 if (type & LPROCFS_TYPE_REGS)
414                         ptr = "regs";
415                 else {
416                         if (type & LPROCFS_TYPE_BYTES)
417                                 ptr = "bytes";
418                         else {
419                                 if (type & LPROCFS_TYPE_PAGES)
420                                         ptr = "pages";
421                         }
422                 }
423                 lprocfs_counter_init(svc_stats, llite_opcode_table[id].opcode,
424                                      (type & LPROCFS_CNTR_AVGMINMAX),
425                                      llite_opcode_table[id].opname, ptr);
426         }
427         err = lprocfs_register_stats(sbi->ll_proc_root, "stats", svc_stats);
428         if (err)
429                 goto out;
430         else
431                 sbi->ll_stats = svc_stats;
432         /* need place to keep svc_stats */
433
434         /* Static configuration info */
435         err = lprocfs_add_vars(sbi->ll_proc_root, lprocfs_obd_vars, sb);
436         if (err)
437                 goto out;
438
439         /* MDC info */
440         obd = class_name2obd(mdc);
441
442         LASSERT(obd != NULL);
443         LASSERT(obd->obd_type != NULL);
444         LASSERT(obd->obd_type->typ_name != NULL);
445
446         snprintf(name, MAX_STRING_SIZE, "%s/common_name",
447                  obd->obd_type->typ_name);
448         lvars[0].read_fptr = lprocfs_rd_name;
449         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
450         if (err)
451                 goto out;
452
453         snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name);
454         lvars[0].read_fptr = lprocfs_rd_uuid;
455         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
456         if (err)
457                 goto out;
458
459         /* OSC */
460         obd = class_name2obd(osc);
461
462         LASSERT(obd != NULL);
463         LASSERT(obd->obd_type != NULL);
464         LASSERT(obd->obd_type->typ_name != NULL);
465
466         snprintf(name, MAX_STRING_SIZE, "%s/common_name",
467                  obd->obd_type->typ_name);
468         lvars[0].read_fptr = lprocfs_rd_name;
469         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
470         if (err)
471                 goto out;
472
473         snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name);
474         lvars[0].read_fptr = lprocfs_rd_uuid;
475         err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);
476 out:
477         if (err) {
478                 if (svc_stats)
479                         lprocfs_free_stats(svc_stats);
480                 if (sbi->ll_proc_root)
481                         lprocfs_remove(sbi->ll_proc_root);
482         }
483         RETURN(err);
484 }
485
486 void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi)
487 {
488         if (sbi->ll_proc_root) {
489                 struct proc_dir_entry *file_stats =
490                         lprocfs_srch(sbi->ll_proc_root, "stats");
491
492                 if (file_stats) {
493                         lprocfs_free_stats(sbi->ll_stats);
494                         lprocfs_remove(file_stats);
495                 }
496         }
497 }
498 #undef MAX_STRING_SIZE
499
500 #define seq_page_flag(seq, page, flag, has_flags) do {                  \
501                 if (test_bit(PG_##flag, &(page)->flags)) {              \
502                         if (!has_flags)                                 \
503                                 has_flags = 1;                          \
504                         else                                            \
505                                 seq_putc(seq, '|');                     \
506                         seq_puts(seq, #flag);                           \
507                 }                                                       \
508         } while(0);
509
510 static void *llite_dump_pgcache_seq_start(struct seq_file *seq, loff_t *pos)
511 {
512         struct ll_async_page *dummy_llap = seq->private;
513
514         if (dummy_llap->llap_magic == 2)
515                 return NULL;
516
517         return (void *)1;
518 }
519
520 static int llite_dump_pgcache_seq_show(struct seq_file *seq, void *v)
521 {
522         struct ll_async_page *llap, *dummy_llap = seq->private;
523         struct ll_sb_info *sbi = dummy_llap->llap_cookie;
524
525         /* 2.4 doesn't seem to have SEQ_START_TOKEN, so we implement
526          * it in our own state */
527         if (dummy_llap->llap_magic == 0) {
528                 seq_printf(seq, "gener |  llap  cookie  origin wq du | page "
529                                 "inode index count [ page flags ]\n");
530                 return 0;
531         }
532
533         spin_lock(&sbi->ll_lock);
534
535         llap = llite_pglist_next_llap(sbi, &dummy_llap->llap_pglist_item);
536         if (llap != NULL)  {
537                 int has_flags = 0;
538                 struct page *page = llap->llap_page;
539
540                 LASSERTF(llap->llap_origin < LLAP__ORIGIN_MAX, "%u\n",
541                          llap->llap_origin);
542
543                 seq_printf(seq, "%5lu | %p %p %s %s %s | %p %p %lu %u [",
544                            sbi->ll_pglist_gen,
545                            llap, llap->llap_cookie,
546                            llap_origins[llap->llap_origin],
547                            llap->llap_write_queued ? "wq" : "- ",
548                            llap->llap_defer_uptodate ? "du" : "- ",
549                            page, page->mapping->host, page->index,
550                            page_count(page));
551                 seq_page_flag(seq, page, locked, has_flags);
552                 seq_page_flag(seq, page, error, has_flags);
553                 seq_page_flag(seq, page, referenced, has_flags);
554                 seq_page_flag(seq, page, uptodate, has_flags);
555                 seq_page_flag(seq, page, dirty, has_flags);
556                 seq_page_flag(seq, page, highmem, has_flags);
557                 if (!has_flags)
558                         seq_puts(seq, "-]\n");
559                 else 
560                         seq_puts(seq, "]\n");
561         }
562
563         spin_unlock(&sbi->ll_lock);
564
565         return 0;
566 }
567
568 static void *llite_dump_pgcache_seq_next(struct seq_file *seq, void *v, 
569                                          loff_t *pos)
570 {
571         struct ll_async_page *llap, *dummy_llap = seq->private;
572         struct ll_sb_info *sbi = dummy_llap->llap_cookie;
573
574         /* bail if we just displayed the banner */
575         if (dummy_llap->llap_magic == 0) {
576                 dummy_llap->llap_magic = 1;
577                 return dummy_llap;
578         }
579
580         /* we've just displayed the llap that is after us in the list.
581          * we advance to a position beyond it, returning null if there
582          * isn't another llap in the list beyond that new position. */
583         spin_lock(&sbi->ll_lock);
584         llap = llite_pglist_next_llap(sbi, &dummy_llap->llap_pglist_item);
585         list_del_init(&dummy_llap->llap_pglist_item);
586         if (llap) {
587                 list_add(&dummy_llap->llap_pglist_item,&llap->llap_pglist_item);
588                 llap =llite_pglist_next_llap(sbi,&dummy_llap->llap_pglist_item);
589         }
590         spin_unlock(&sbi->ll_lock);
591
592         ++*pos;
593         if (llap == NULL) {
594                 dummy_llap->llap_magic = 2;
595                 return NULL;
596         }
597         return dummy_llap;
598 }
599
600 static void llite_dump_pgcache_seq_stop(struct seq_file *seq, void *v)
601 {
602 }
603
604 struct seq_operations llite_dump_pgcache_seq_sops = {
605         .start = llite_dump_pgcache_seq_start,
606         .stop = llite_dump_pgcache_seq_stop,
607         .next = llite_dump_pgcache_seq_next,
608         .show = llite_dump_pgcache_seq_show,
609 };
610
611 /* we're displaying llaps in a list_head list.  we don't want to hold a lock
612  * while we walk the entire list, and we don't want to have to seek into
613  * the right position in the list as an app advances with many syscalls.  we
614  * allocate a dummy llap and hang it off file->private.  its position in
615  * the list records where the app is currently displaying.  this way our
616  * seq .start and .stop don't actually do anything.  .next returns null
617  * when the dummy hits the end of the list which eventually leads to .release
618  * where we tear down.  this kind of displaying is super-racey, so we put
619  * a generation counter on the list so the output shows when the list
620  * changes between reads.
621  */
622 static int llite_dump_pgcache_seq_open(struct inode *inode, struct file *file)
623 {
624         struct proc_dir_entry *dp = PDE(inode);
625         struct ll_async_page *dummy_llap;
626         struct seq_file *seq;
627         struct ll_sb_info *sbi = dp->data;
628         int rc;
629
630         OBD_ALLOC_GFP(dummy_llap, sizeof(*dummy_llap), GFP_KERNEL);
631         if (dummy_llap == NULL)
632                 return -ENOMEM;
633         dummy_llap->llap_page = NULL;
634         dummy_llap->llap_cookie = sbi;
635         dummy_llap->llap_magic = 0;
636
637         rc = seq_open(file, &llite_dump_pgcache_seq_sops);
638         if (rc) {
639                 OBD_FREE(dummy_llap, sizeof(*dummy_llap));
640                 return rc;
641         }
642         seq = file->private_data;
643         seq->private = dummy_llap;
644
645         spin_lock(&sbi->ll_lock);
646         list_add(&dummy_llap->llap_pglist_item, &sbi->ll_pglist);
647         spin_unlock(&sbi->ll_lock);
648
649         return 0;
650 }
651
652 static int llite_dump_pgcache_seq_release(struct inode *inode,
653                                           struct file *file)
654 {
655         struct seq_file *seq = file->private_data;
656         struct ll_async_page *dummy_llap = seq->private;
657         struct ll_sb_info *sbi = dummy_llap->llap_cookie;
658
659         spin_lock(&sbi->ll_lock);
660         if (!list_empty(&dummy_llap->llap_pglist_item))
661                 list_del_init(&dummy_llap->llap_pglist_item);
662         spin_unlock(&sbi->ll_lock);
663         OBD_FREE(dummy_llap, sizeof(*dummy_llap));
664
665         return seq_release(inode, file);
666 }
667
668 struct file_operations llite_dump_pgcache_fops = {
669         .owner   = THIS_MODULE,
670         .open    = llite_dump_pgcache_seq_open,
671         .read    = seq_read,
672         .release = llite_dump_pgcache_seq_release,
673 };
674
675 static int ll_ra_stats_seq_show(struct seq_file *seq, void *v)
676 {
677         struct timeval now;
678         struct ll_sb_info *sbi = seq->private;
679         struct ll_ra_info *ra = &sbi->ll_ra_info;
680         int i;
681         static char *ra_stat_strings[] = {
682                 [RA_STAT_HIT] = "hits",
683                 [RA_STAT_MISS] = "misses",
684                 [RA_STAT_DISTANT_READPAGE] = "readpage not consecutive",
685                 [RA_STAT_MISS_IN_WINDOW] = "miss inside window",
686                 [RA_STAT_FAILED_GRAB_PAGE] = "failed grab_cache_page",
687                 [RA_STAT_FAILED_MATCH] = "failed lock match",
688                 [RA_STAT_DISCARDED] = "read but discarded",
689                 [RA_STAT_ZERO_LEN] = "zero length file",
690                 [RA_STAT_ZERO_WINDOW] = "zero size window",
691                 [RA_STAT_EOF] = "read-ahead to EOF",
692                 [RA_STAT_MAX_IN_FLIGHT] = "hit max r-a issue",
693         };
694
695         do_gettimeofday(&now);
696
697         spin_lock(&sbi->ll_lock);
698
699         seq_printf(seq, "snapshot_time:         %lu.%lu (secs.usecs)\n",
700                    now.tv_sec, now.tv_usec);
701         seq_printf(seq, "pending issued pages:           %lu\n",
702                    ra->ra_cur_pages);
703
704         for(i = 0; i < _NR_RA_STAT; i++)
705                 seq_printf(seq, "%-25s %lu\n", ra_stat_strings[i], 
706                            ra->ra_stats[i]);
707
708         spin_unlock(&sbi->ll_lock);
709
710         return 0;
711 }
712
713 static void *ll_ra_stats_seq_start(struct seq_file *p, loff_t *pos)
714 {
715         if (*pos == 0)
716                 return (void *)1;
717         return NULL;
718 }
719 static void *ll_ra_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
720 {
721         ++*pos;
722         return NULL;
723 }
724 static void ll_ra_stats_seq_stop(struct seq_file *p, void *v)
725 {
726 }
727 struct seq_operations ll_ra_stats_seq_sops = {
728         .start = ll_ra_stats_seq_start,
729         .stop = ll_ra_stats_seq_stop,
730         .next = ll_ra_stats_seq_next,
731         .show = ll_ra_stats_seq_show,
732 };
733
734 static int ll_ra_stats_seq_open(struct inode *inode, struct file *file)
735 {
736         struct proc_dir_entry *dp = PDE(inode);
737         struct seq_file *seq;
738         int rc;
739
740         rc = seq_open(file, &ll_ra_stats_seq_sops);
741         if (rc)
742                 return rc;
743         seq = file->private_data;
744         seq->private = dp->data;
745         return 0;
746 }
747
748 static ssize_t ll_ra_stats_seq_write(struct file *file, const char *buf,
749                                        size_t len, loff_t *off)
750 {
751         struct seq_file *seq = file->private_data;
752         struct ll_sb_info *sbi = seq->private;
753         struct ll_ra_info *ra = &sbi->ll_ra_info;
754
755         spin_lock(&sbi->ll_lock);
756         memset(ra->ra_stats, 0, sizeof(ra->ra_stats));
757         spin_unlock(&sbi->ll_lock);
758
759         return len;
760 }
761
762 struct file_operations ll_ra_stats_fops = {
763         .owner   = THIS_MODULE,
764         .open    = ll_ra_stats_seq_open,
765         .read    = seq_read,
766         .write   = ll_ra_stats_seq_write,
767         .llseek  = seq_lseek,
768         .release = seq_release,
769 };
770
771 #endif /* LPROCFS */