/* * Copyright (C) 2005-2015 Junjiro R. Okajima */ /* * magic sysrq hanlder */ /* #include */ #include #include "aufs.h" /* ---------------------------------------------------------------------- */ static void sysrq_sb(struct super_block *sb) { char *plevel; struct au_sbinfo *sbinfo; struct file *file; struct au_sphlhead *files; struct au_finfo *finfo; plevel = au_plevel; au_plevel = KERN_WARNING; /* since we define pr_fmt, call printk directly */ #define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) sbinfo = au_sbi(sb); printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); pr("superblock\n"); au_dpri_sb(sb); #if 0 pr("root dentry\n"); au_dpri_dentry(sb->s_root); pr("root inode\n"); au_dpri_inode(d_inode(sb->s_root)); #endif #if 0 do { int err, i, j, ndentry; struct au_dcsub_pages dpages; struct au_dpage *dpage; err = au_dpages_init(&dpages, GFP_ATOMIC); if (unlikely(err)) break; err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); if (!err) for (i = 0; i < dpages.ndpage; i++) { dpage = dpages.dpages + i; ndentry = dpage->ndentry; for (j = 0; j < ndentry; j++) au_dpri_dentry(dpage->dentries[j]); } au_dpages_free(&dpages); } while (0); #endif #if 1 { struct inode *i; pr("isolated inode\n"); spin_lock(&sb->s_inode_list_lock); list_for_each_entry(i, &sb->s_inodes, i_sb_list) { spin_lock(&i->i_lock); if (1 || hlist_empty(&i->i_dentry)) au_dpri_inode(i); spin_unlock(&i->i_lock); } spin_unlock(&sb->s_inode_list_lock); } #endif pr("files\n"); files = &au_sbi(sb)->si_files; spin_lock(&files->spin); hlist_for_each_entry(finfo, &files->head, fi_hlist) { umode_t mode; file = finfo->fi_file; mode = file_inode(file)->i_mode; if (!special_file(mode)) au_dpri_file(file); } spin_unlock(&files->spin); pr("done\n"); #undef pr au_plevel = plevel; } /* ---------------------------------------------------------------------- */ /* module parameter */ static char *aufs_sysrq_key = "a"; module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); static void au_sysrq(int key __maybe_unused) { struct au_sbinfo *sbinfo; lockdep_off(); au_sbilist_lock(); list_for_each_entry(sbinfo, &au_sbilist.head, si_list) sysrq_sb(sbinfo->si_sb); au_sbilist_unlock(); lockdep_on(); } static struct sysrq_key_op au_sysrq_op = { .handler = au_sysrq, .help_msg = "Aufs", .action_msg = "Aufs", .enable_mask = SYSRQ_ENABLE_DUMP }; /* ---------------------------------------------------------------------- */ int __init au_sysrq_init(void) { int err; char key; err = -1; key = *aufs_sysrq_key; if ('a' <= key && key <= 'z') err = register_sysrq_key(key, &au_sysrq_op); if (unlikely(err)) pr_err("err %d, sysrq=%c\n", err, key); return err; } void au_sysrq_fin(void) { int err; err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); if (unlikely(err)) pr_err("err %d (ignored)\n", err); }