#include #include #include #include #include #include #include void print_page(struct page *page) { printk(KERN_DEBUG "%lu\t%u\t%u\t%c%c%c%c%c\n", page->index, page_count(page), page_mapcount(page), PageUptodate(page) ? 'U' : '_', PageDirty(page) ? 'D' : '_', PageWriteback(page) ? 'W' : '_', PagePrivate(page) ? 'P' : '_', PageLocked(page) ? 'L' : '_'); } void print_writeback_control(struct writeback_control *wbc) { printk(KERN_DEBUG "global dirty %lu writeback %lu nfs %lu\n" "wbc flags %c%c towrite %ld skipped %ld\n", global_page_state(NR_FILE_DIRTY), global_page_state(NR_WRITEBACK), global_page_state(NR_UNSTABLE_NFS), wbc->encountered_congestion ? 'C':'_', wbc->more_io ? 'M':'_', wbc->nr_to_write, wbc->pages_skipped); } void print_inode_pages(struct inode *inode) { struct address_space *mapping = inode->i_mapping; struct pagevec pvec; int nr_pages; int i; pgoff_t index = 0; struct dentry *dentry; int dcount; char *dname; nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY, (pgoff_t)PAGEVEC_SIZE); if (list_empty(&inode->i_dentry)) { dname = ""; dcount = 0; } else { dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); dname = dentry->d_iname; dcount = atomic_read(&dentry->d_count); } printk(KERN_DEBUG "inode %lu(%s/%s) count %d,%d size %llu pages %lu\n", inode->i_ino, inode->i_sb->s_id, dname, atomic_read(&inode->i_count), dcount, i_size_read(inode), mapping->nrpages ); for (i = 0; i < nr_pages; i++) print_page(pvec.pages[i]); } int handler_pre(struct kprobe *p, struct pt_regs *regs) { static int count = 0; if (count++ < 10) dump_stack(); return 0; } void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags) { } static struct kprobe my_kprobe = { .pre_handler = handler_pre, .post_handler = handler_post, .symbol_name = "submit_bio" }; static int jdo_ext2_writepage(struct page *page, struct writeback_control *wbc) { struct inode * const inode = page->mapping->host; if (!i_size_read(inode)) { printk(KERN_DEBUG "ext2_writepage:\n"); print_page(page); print_writeback_control(wbc); } jprobe_return(); return 0; } static struct jprobe jprobe_ext2_writepage = { .entry = jdo_ext2_writepage, .kp.symbol_name = "ext2_writepage" }; static void jdo_requeue_io(struct inode *inode) { if (!i_size_read(inode)) { printk(KERN_DEBUG "requeue_io:\n"); print_inode_pages(inode); } jprobe_return(); } static struct jprobe jprobe_requeue_io = { .entry = jdo_requeue_io, .kp.symbol_name = "requeue_io" }; static int setup_kprobe(struct kprobe *kprobe) { int ret = register_kprobe(kprobe); printk("register_kprobe(%s) = %d\n", kprobe->symbol_name, ret); return ret; } static int setup_jprobe(struct jprobe *jprobe) { int ret = register_jprobe(jprobe); printk("register_jprobe(%s) = %d\n", jprobe->kp.symbol_name, ret); return ret; } static int __init jprobe_init(void) { int ret; ret = setup_jprobe(&jprobe_ext2_writepage); if (ret) return -1; ret = setup_jprobe(&jprobe_requeue_io); if (ret) return -1; ret = setup_kprobe(&my_kprobe); if (ret) return -1; return 0; } static void __exit jprobe_exit(void) { unregister_kprobe(&my_kprobe); unregister_jprobe(&jprobe_requeue_io); unregister_jprobe(&jprobe_ext2_writepage); } module_init(jprobe_init) module_exit(jprobe_exit) MODULE_LICENSE("GPL");