ksysfs.c 6.3 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * kernel/ksysfs.c - sysfs attributes in /sys/kernel, which
 * 		     are not related to any other subsystem
 *
 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
 * 
 * This file is release under the GPLv2
 *
 */

#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
14
#include <linux/export.h>
Linus Torvalds's avatar
Linus Torvalds committed
15
#include <linux/init.h>
16
#include <linux/kexec.h>
17
#include <linux/profile.h>
18
#include <linux/stat.h>
19
#include <linux/sched.h>
20
#include <linux/capability.h>
21
#include <linux/compiler.h>
Linus Torvalds's avatar
Linus Torvalds committed
22

23
#include <linux/rcupdate.h>	/* rcu_expedited and rcu_normal */
24

Linus Torvalds's avatar
Linus Torvalds committed
25
#define KERNEL_ATTR_RO(_name) \
26
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
Linus Torvalds's avatar
Linus Torvalds committed
27 28

#define KERNEL_ATTR_RW(_name) \
29
static struct kobj_attribute _name##_attr = \
Linus Torvalds's avatar
Linus Torvalds committed
30 31
	__ATTR(_name, 0644, _name##_show, _name##_store)

32
/* current uevent sequence number */
33 34
static ssize_t uevent_seqnum_show(struct kobject *kobj,
				  struct kobj_attribute *attr, char *buf)
Linus Torvalds's avatar
Linus Torvalds committed
35
{
36
	return sprintf(buf, "%llu\n", (unsigned long long)uevent_seqnum);
Linus Torvalds's avatar
Linus Torvalds committed
37
}
38 39
KERNEL_ATTR_RO(uevent_seqnum);

40
#ifdef CONFIG_UEVENT_HELPER
41
/* uevent helper program, used during early boot */
42 43
static ssize_t uevent_helper_show(struct kobject *kobj,
				  struct kobj_attribute *attr, char *buf)
44
{
45
	return sprintf(buf, "%s\n", uevent_helper);
46
}
47 48 49
static ssize_t uevent_helper_store(struct kobject *kobj,
				   struct kobj_attribute *attr,
				   const char *buf, size_t count)
50
{
51
	if (count+1 > UEVENT_HELPER_PATH_LEN)
52
		return -ENOENT;
53
	memcpy(uevent_helper, buf, count);
54 55 56
	uevent_helper[count] = '\0';
	if (count && uevent_helper[count-1] == '\n')
		uevent_helper[count-1] = '\0';
57 58 59
	return count;
}
KERNEL_ATTR_RW(uevent_helper);
60
#endif
Linus Torvalds's avatar
Linus Torvalds committed
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
#ifdef CONFIG_PROFILING
static ssize_t profiling_show(struct kobject *kobj,
				  struct kobj_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", prof_on);
}
static ssize_t profiling_store(struct kobject *kobj,
				   struct kobj_attribute *attr,
				   const char *buf, size_t count)
{
	int ret;

	if (prof_on)
		return -EEXIST;
	/*
	 * This eventually calls into get_option() which
	 * has a ton of callers and is not const.  It is
	 * easiest to cast it away here.
	 */
	profile_setup((char *)buf);
	ret = profile_init();
	if (ret)
		return ret;
	ret = create_proc_profile();
	if (ret)
		return ret;
	return count;
}
KERNEL_ATTR_RW(profiling);
#endif

93
#ifdef CONFIG_KEXEC_CORE
94 95
static ssize_t kexec_loaded_show(struct kobject *kobj,
				 struct kobj_attribute *attr, char *buf)
96
{
97
	return sprintf(buf, "%d\n", !!kexec_image);
98 99 100
}
KERNEL_ATTR_RO(kexec_loaded);

101 102
static ssize_t kexec_crash_loaded_show(struct kobject *kobj,
				       struct kobj_attribute *attr, char *buf)
103
{
104
	return sprintf(buf, "%d\n", kexec_crash_loaded());
105 106
}
KERNEL_ATTR_RO(kexec_crash_loaded);
Ken'ichi Ohmichi's avatar
Ken'ichi Ohmichi committed
107

108 109 110 111 112 113 114 115 116 117 118 119
static ssize_t kexec_crash_size_show(struct kobject *kobj,
				       struct kobj_attribute *attr, char *buf)
{
	return sprintf(buf, "%zu\n", crash_get_memory_size());
}
static ssize_t kexec_crash_size_store(struct kobject *kobj,
				   struct kobj_attribute *attr,
				   const char *buf, size_t count)
{
	unsigned long cnt;
	int ret;

120
	if (kstrtoul(buf, 0, &cnt))
121 122 123 124 125 126 127
		return -EINVAL;

	ret = crash_shrink_memory(cnt);
	return ret < 0 ? ret : count;
}
KERNEL_ATTR_RW(kexec_crash_size);

128 129 130 131
#endif /* CONFIG_KEXEC_CORE */

#ifdef CONFIG_CRASH_CORE

132 133
static ssize_t vmcoreinfo_show(struct kobject *kobj,
			       struct kobj_attribute *attr, char *buf)
Ken'ichi Ohmichi's avatar
Ken'ichi Ohmichi committed
134
{
135 136
	phys_addr_t vmcore_base = paddr_vmcoreinfo_note();
	return sprintf(buf, "%pa %x\n", &vmcore_base,
137
			(unsigned int)VMCOREINFO_NOTE_SIZE);
Ken'ichi Ohmichi's avatar
Ken'ichi Ohmichi committed
138 139 140
}
KERNEL_ATTR_RO(vmcoreinfo);

141
#endif /* CONFIG_CRASH_CORE */
142

143 144 145 146 147 148 149 150
/* whether file capabilities are enabled */
static ssize_t fscaps_show(struct kobject *kobj,
				  struct kobj_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", file_caps_enabled);
}
KERNEL_ATTR_RO(fscaps);

151
#ifndef CONFIG_TINY_RCU
152 153 154 155
int rcu_expedited;
static ssize_t rcu_expedited_show(struct kobject *kobj,
				  struct kobj_attribute *attr, char *buf)
{
156
	return sprintf(buf, "%d\n", READ_ONCE(rcu_expedited));
157 158 159 160 161 162 163 164 165 166 167 168
}
static ssize_t rcu_expedited_store(struct kobject *kobj,
				   struct kobj_attribute *attr,
				   const char *buf, size_t count)
{
	if (kstrtoint(buf, 0, &rcu_expedited))
		return -EINVAL;

	return count;
}
KERNEL_ATTR_RW(rcu_expedited);

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
int rcu_normal;
static ssize_t rcu_normal_show(struct kobject *kobj,
			       struct kobj_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", READ_ONCE(rcu_normal));
}
static ssize_t rcu_normal_store(struct kobject *kobj,
				struct kobj_attribute *attr,
				const char *buf, size_t count)
{
	if (kstrtoint(buf, 0, &rcu_normal))
		return -EINVAL;

	return count;
}
KERNEL_ATTR_RW(rcu_normal);
185
#endif /* #ifndef CONFIG_TINY_RCU */
186

Roland McGrath's avatar
Roland McGrath committed
187 188 189
/*
 * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
 */
190 191
extern const void __start_notes __weak;
extern const void __stop_notes __weak;
Roland McGrath's avatar
Roland McGrath committed
192 193
#define	notes_size (&__stop_notes - &__start_notes)

194 195
static ssize_t notes_read(struct file *filp, struct kobject *kobj,
			  struct bin_attribute *bin_attr,
Roland McGrath's avatar
Roland McGrath committed
196 197 198 199 200 201
			  char *buf, loff_t off, size_t count)
{
	memcpy(buf, &__start_notes + off, count);
	return count;
}

202
static struct bin_attribute notes_attr __ro_after_init  = {
Roland McGrath's avatar
Roland McGrath committed
203 204 205 206 207 208 209
	.attr = {
		.name = "notes",
		.mode = S_IRUGO,
	},
	.read = &notes_read,
};

210 211
struct kobject *kernel_kobj;
EXPORT_SYMBOL_GPL(kernel_kobj);
Linus Torvalds's avatar
Linus Torvalds committed
212 213

static struct attribute * kernel_attrs[] = {
214
	&fscaps_attr.attr,
215
	&uevent_seqnum_attr.attr,
216
#ifdef CONFIG_UEVENT_HELPER
217
	&uevent_helper_attr.attr,
218
#endif
219 220 221
#ifdef CONFIG_PROFILING
	&profiling_attr.attr,
#endif
222
#ifdef CONFIG_KEXEC_CORE
223 224
	&kexec_loaded_attr.attr,
	&kexec_crash_loaded_attr.attr,
225
	&kexec_crash_size_attr.attr,
226 227
#endif
#ifdef CONFIG_CRASH_CORE
Ken'ichi Ohmichi's avatar
Ken'ichi Ohmichi committed
228
	&vmcoreinfo_attr.attr,
Linus Torvalds's avatar
Linus Torvalds committed
229
#endif
230
#ifndef CONFIG_TINY_RCU
231
	&rcu_expedited_attr.attr,
232
	&rcu_normal_attr.attr,
233
#endif
Linus Torvalds's avatar
Linus Torvalds committed
234 235 236
	NULL
};

237
static const struct attribute_group kernel_attr_group = {
Linus Torvalds's avatar
Linus Torvalds committed
238 239 240 241 242
	.attrs = kernel_attrs,
};

static int __init ksysfs_init(void)
{
243
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
244

245 246
	kernel_kobj = kobject_create_and_add("kernel", NULL);
	if (!kernel_kobj) {
247 248 249
		error = -ENOMEM;
		goto exit;
	}
250
	error = sysfs_create_group(kernel_kobj, &kernel_attr_group);
251 252 253 254
	if (error)
		goto kset_exit;

	if (notes_size > 0) {
Roland McGrath's avatar
Roland McGrath committed
255
		notes_attr.size = notes_size;
256
		error = sysfs_create_bin_file(kernel_kobj, &notes_attr);
257 258
		if (error)
			goto group_exit;
Roland McGrath's avatar
Roland McGrath committed
259 260
	}

261 262 263
	return 0;

group_exit:
264
	sysfs_remove_group(kernel_kobj, &kernel_attr_group);
265
kset_exit:
266
	kobject_put(kernel_kobj);
267
exit:
Linus Torvalds's avatar
Linus Torvalds committed
268 269 270 271
	return error;
}

core_initcall(ksysfs_init);