-#define seq_page_flag(seq, page, flag, has_flags) do { \
- if (test_bit(PG_##flag, &(page)->flags)) { \
- if (!has_flags) \
- has_flags = 1; \
- else \
- seq_putc(seq, '|'); \
- seq_puts(seq, #flag); \
- } \
- } while(0);
-
-static void *llite_dump_pgcache_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct ll_async_page *dummy_llap = seq->private;
-
- if (dummy_llap->llap_magic == 2)
- return NULL;
-
- return (void *)1;
-}
-
-static int llite_dump_pgcache_seq_show(struct seq_file *seq, void *v)
-{
- struct ll_async_page *llap, *dummy_llap = seq->private;
- struct ll_sb_info *sbi = dummy_llap->llap_cookie;
-
- /* 2.4 doesn't seem to have SEQ_START_TOKEN, so we implement
- * it in our own state */
- if (dummy_llap->llap_magic == 0) {
- seq_printf(seq, "gener | llap cookie origin wq du | page "
- "inode index count [ page flags ]\n");
- return 0;
- }
-
- spin_lock(&sbi->ll_lock);
-
- llap = llite_pglist_next_llap(sbi, &dummy_llap->llap_pglist_item);
- if (llap != NULL) {
- int has_flags = 0;
- struct page *page = llap->llap_page;
-
- LASSERTF(llap->llap_origin < LLAP__ORIGIN_MAX, "%u\n",
- llap->llap_origin);
-
- seq_printf(seq, "%5lu | %p %p %s %s %s | %p %p %lu %u [",
- sbi->ll_pglist_gen,
- llap, llap->llap_cookie,
- llap_origins[llap->llap_origin],
- llap->llap_write_queued ? "wq" : "- ",
- llap->llap_defer_uptodate ? "du" : "- ",
- page, page->mapping->host, page->index,
- page_count(page));
- seq_page_flag(seq, page, locked, has_flags);
- seq_page_flag(seq, page, error, has_flags);
- seq_page_flag(seq, page, referenced, has_flags);
- seq_page_flag(seq, page, uptodate, has_flags);
- seq_page_flag(seq, page, dirty, has_flags);
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12))
- seq_page_flag(seq, page, highmem, has_flags);
-#endif
- if (!has_flags)
- seq_puts(seq, "-]\n");
- else
- seq_puts(seq, "]\n");
- }
-
- spin_unlock(&sbi->ll_lock);
-
- return 0;
-}
-
-static void *llite_dump_pgcache_seq_next(struct seq_file *seq, void *v,
- loff_t *pos)
-{
- struct ll_async_page *llap, *dummy_llap = seq->private;
- struct ll_sb_info *sbi = dummy_llap->llap_cookie;
-
- /* bail if we just displayed the banner */
- if (dummy_llap->llap_magic == 0) {
- dummy_llap->llap_magic = 1;
- return dummy_llap;
- }
-
- /* we've just displayed the llap that is after us in the list.
- * we advance to a position beyond it, returning null if there
- * isn't another llap in the list beyond that new position. */
- spin_lock(&sbi->ll_lock);
- llap = llite_pglist_next_llap(sbi, &dummy_llap->llap_pglist_item);
- list_del_init(&dummy_llap->llap_pglist_item);
- if (llap) {
- list_add(&dummy_llap->llap_pglist_item,&llap->llap_pglist_item);
- llap =llite_pglist_next_llap(sbi,&dummy_llap->llap_pglist_item);
- }
- spin_unlock(&sbi->ll_lock);
-
- ++*pos;
- if (llap == NULL) {
- dummy_llap->llap_magic = 2;
- return NULL;
- }
- return dummy_llap;
-}
-
-static void null_stop(struct seq_file *seq, void *v)
-{
-}
-
-struct seq_operations llite_dump_pgcache_seq_sops = {
- .start = llite_dump_pgcache_seq_start,
- .stop = null_stop,
- .next = llite_dump_pgcache_seq_next,
- .show = llite_dump_pgcache_seq_show,
-};
-
-/* we're displaying llaps in a list_head list. we don't want to hold a lock
- * while we walk the entire list, and we don't want to have to seek into
- * the right position in the list as an app advances with many syscalls. we
- * allocate a dummy llap and hang it off file->private. its position in
- * the list records where the app is currently displaying. this way our
- * seq .start and .stop don't actually do anything. .next returns null
- * when the dummy hits the end of the list which eventually leads to .release
- * where we tear down. this kind of displaying is super-racey, so we put
- * a generation counter on the list so the output shows when the list
- * changes between reads.
- */
-static int llite_dump_pgcache_seq_open(struct inode *inode, struct file *file)
-{
- struct proc_dir_entry *dp = PDE(inode);
- struct ll_async_page *dummy_llap;
- struct seq_file *seq;
- struct ll_sb_info *sbi = dp->data;
- int rc = -ENOMEM;
-
- LPROCFS_ENTRY_AND_CHECK(dp);
-
- OBD_ALLOC_GFP(dummy_llap, sizeof(*dummy_llap), GFP_KERNEL);
- if (dummy_llap == NULL)
- GOTO(out, rc);
-
- dummy_llap->llap_page = NULL;
- dummy_llap->llap_cookie = sbi;
- dummy_llap->llap_magic = 0;
-
- rc = seq_open(file, &llite_dump_pgcache_seq_sops);
- if (rc) {
- OBD_FREE(dummy_llap, sizeof(*dummy_llap));
- GOTO(out, rc);
- }
- seq = file->private_data;
- seq->private = dummy_llap;
-
- spin_lock(&sbi->ll_lock);
- list_add(&dummy_llap->llap_pglist_item, &sbi->ll_pglist);
- spin_unlock(&sbi->ll_lock);
-
-out:
- if (rc)
- LPROCFS_EXIT();
- return rc;
-}
-
-static int llite_dump_pgcache_seq_release(struct inode *inode,
- struct file *file)
-{
- struct seq_file *seq = file->private_data;
- struct ll_async_page *dummy_llap = seq->private;
- struct ll_sb_info *sbi = dummy_llap->llap_cookie;
-
- spin_lock(&sbi->ll_lock);
- if (!list_empty(&dummy_llap->llap_pglist_item))
- list_del_init(&dummy_llap->llap_pglist_item);
- spin_unlock(&sbi->ll_lock);
- OBD_FREE(dummy_llap, sizeof(*dummy_llap));
-
- return lprocfs_seq_release(inode, file);
-}
-
-struct file_operations llite_dump_pgcache_fops = {
- .owner = THIS_MODULE,
- .open = llite_dump_pgcache_seq_open,
- .read = seq_read,
- .release = llite_dump_pgcache_seq_release,
-};
-
-static int ll_ra_stats_seq_show(struct seq_file *seq, void *v)
-{
- struct timeval now;
- struct ll_sb_info *sbi = seq->private;
- struct ll_ra_info *ra = &sbi->ll_ra_info;
- int i;
- static char *ra_stat_strings[] = {
- [RA_STAT_HIT] = "hits",
- [RA_STAT_MISS] = "misses",
- [RA_STAT_DISTANT_READPAGE] = "readpage not consecutive",
- [RA_STAT_MISS_IN_WINDOW] = "miss inside window",
- [RA_STAT_FAILED_GRAB_PAGE] = "failed grab_cache_page",
- [RA_STAT_FAILED_MATCH] = "failed lock match",
- [RA_STAT_DISCARDED] = "read but discarded",
- [RA_STAT_ZERO_LEN] = "zero length file",
- [RA_STAT_ZERO_WINDOW] = "zero size window",
- [RA_STAT_EOF] = "read-ahead to EOF",
- [RA_STAT_MAX_IN_FLIGHT] = "hit max r-a issue",
- [RA_STAT_WRONG_GRAB_PAGE] = "wrong page from grab_cache_page",
- };
-
- do_gettimeofday(&now);
-
- spin_lock(&sbi->ll_lock);
-
- seq_printf(seq, "snapshot_time: %lu.%lu (secs.usecs)\n",
- now.tv_sec, now.tv_usec);
- seq_printf(seq, "pending issued pages: %lu\n",
- ra->ra_cur_pages);
-
- for(i = 0; i < _NR_RA_STAT; i++)
- seq_printf(seq, "%-25s %lu\n", ra_stat_strings[i],
- ra->ra_stats[i]);
-
- spin_unlock(&sbi->ll_lock);
-
- return 0;
-}
-
-static ssize_t ll_ra_stats_seq_write(struct file *file, const char *buf,
- size_t len, loff_t *off)
-{
- struct seq_file *seq = file->private_data;
- struct ll_sb_info *sbi = seq->private;
- struct ll_ra_info *ra = &sbi->ll_ra_info;
-
- spin_lock(&sbi->ll_lock);
- memset(ra->ra_stats, 0, sizeof(ra->ra_stats));
- spin_unlock(&sbi->ll_lock);
-
- return len;
-}
-
-LPROC_SEQ_FOPS(ll_ra_stats);
-