aboutsummaryrefslogtreecommitdiffstats
path: root/fs/aufs/sysrq.c
blob: fc8aa4a2839f65a3e2f859d27a27f33e34913bed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2005-2020 Junjiro R. Okajima
 *
 * This program, aufs is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * 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;
	struct inode *i;

	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 /* reserved */
	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

	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);
	}
	spin_unlock(&sb->s_inode_list_lock);

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