📄 lproc_llite.c
字号:
entry = create_proc_entry("extents_stats_per_process", 0644, sbi->ll_proc_root); if (entry == NULL) GOTO(out, err = -ENOMEM); entry->proc_fops = &ll_rw_extents_stats_pp_fops; entry->data = sbi; entry = create_proc_entry("offset_stats", 0644, sbi->ll_proc_root); if (entry == NULL) GOTO(out, err = -ENOMEM); entry->proc_fops = &ll_rw_offset_stats_fops; entry->data = sbi; /* File operations stats */ sbi->ll_stats = lprocfs_alloc_stats(LPROC_LL_FILE_OPCODES, LPROCFS_STATS_FLAG_PERCPU); if (sbi->ll_stats == NULL) GOTO(out, err = -ENOMEM); /* do counter init */ for (id = 0; id < LPROC_LL_FILE_OPCODES; id++) { __u32 type = llite_opcode_table[id].type; void *ptr = NULL; if (type & LPROCFS_TYPE_REGS) ptr = "regs"; else if (type & LPROCFS_TYPE_BYTES) ptr = "bytes"; else if (type & LPROCFS_TYPE_PAGES) ptr = "pages"; lprocfs_counter_init(sbi->ll_stats, llite_opcode_table[id].opcode, (type & LPROCFS_CNTR_AVGMINMAX), llite_opcode_table[id].opname, ptr); } err = lprocfs_register_stats(sbi->ll_proc_root, "stats", sbi->ll_stats); if (err) GOTO(out, err); err = lprocfs_add_vars(sbi->ll_proc_root, lprocfs_llite_obd_vars, sb); if (err) GOTO(out, err); /* MDC info */ obd = class_name2obd(mdc); LASSERT(obd != NULL); LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); LASSERT(obd->obd_type->typ_name != NULL); snprintf(name, MAX_STRING_SIZE, "%s/common_name", obd->obd_type->typ_name); lvars[0].read_fptr = lprocfs_rd_name; err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd); if (err) GOTO(out, err); snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name); lvars[0].read_fptr = lprocfs_rd_uuid; err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd); if (err) GOTO(out, err); /* OSC */ obd = class_name2obd(osc); LASSERT(obd != NULL); LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC); LASSERT(obd->obd_type->typ_name != NULL); snprintf(name, MAX_STRING_SIZE, "%s/common_name", obd->obd_type->typ_name); lvars[0].read_fptr = lprocfs_rd_name; err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd); if (err) GOTO(out, err); snprintf(name, MAX_STRING_SIZE, "%s/uuid", obd->obd_type->typ_name); lvars[0].read_fptr = lprocfs_rd_uuid; err = lprocfs_add_vars(sbi->ll_proc_root, lvars, obd);out: if (err) { lprocfs_remove(&sbi->ll_proc_root); lprocfs_free_stats(&sbi->ll_stats); } RETURN(err);}void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi){ if (sbi->ll_proc_root) { lprocfs_remove(&sbi->ll_proc_root); lprocfs_free_stats(&sbi->ll_stats); }}#undef MAX_STRING_SIZE#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 wb | 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 %s | %p %lu/%u(%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" : "- ", PageWriteback(page) ? "wb" : "-", page, page->mapping->host->i_ino, page->mapping->host->i_generation, 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 seq_page_flag(seq, page, writeback, has_flags); 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_PTR_WAIT(dummy_llap); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -