sysrq.c 2.92 KB
Newer Older
1
2
// SPDX-License-Identifier: GPL-2.0
/*
3
 * Copyright (C) 2005-2020 Junjiro R. Okajima
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 */

/*
 * magic sysrq handler
 */

/* #include <linux/sysrq.h> */
#include <linux/writeback.h>
#include "aufs.h"

/* ---------------------------------------------------------------------- */

static void sysrq_sb(struct super_block *sb)
{
	char *plevel;
	struct au_sbinfo *sbinfo;
	struct file *file;
	struct hlist_bl_head *files;
	struct hlist_bl_node *pos;
	struct au_finfo *finfo;
24
	struct inode *i;
25
26
27
28
29
30
31
32
33
34
35
36

	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);

37
#if 0 /* reserved */
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
	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

58
59
60
61
62
63
64
	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 (hlist_empty(&i->i_dentry))
			au_dpri_inode(i);
		spin_unlock(&i->i_lock);
65
	}
66
67
	spin_unlock(&sb->s_inode_list_lock);

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
	pr("files\n");
	files = &au_sbi(sb)->si_files;
	hlist_bl_lock(files);
	hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) {
		umode_t mode;

		file = finfo->fi_file;
		mode = file_inode(file)->i_mode;
		if (!special_file(mode))
			au_dpri_file(file);
	}
	hlist_bl_unlock(files);
	pr("done\n");

#undef pr
	au_plevel = plevel;
}

/* ---------------------------------------------------------------------- */

/* module parameter */
static char *aufs_sysrq_key = "a";
module_param_named(sysrq, aufs_sysrq_key, charp, 0444);
MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME);

static void au_sysrq(int key __maybe_unused)
{
	struct au_sbinfo *sbinfo;
	struct hlist_bl_node *pos;

	lockdep_off();
	au_sbilist_lock();
	hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, 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);
}