inode.c 10.9 KB
Newer Older
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
/*
 * Persistent Storage - ramfs parts.
 *
 * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/fsnotify.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/time.h>
#include <linux/init.h>
27
#include <linux/list.h>
28 29
#include <linux/string.h>
#include <linux/mount.h>
30
#include <linux/seq_file.h>
31
#include <linux/ramfs.h>
32
#include <linux/parser.h>
33 34 35 36
#include <linux/sched.h>
#include <linux/magic.h>
#include <linux/pstore.h>
#include <linux/slab.h>
37
#include <linux/spinlock.h>
38
#include <linux/uaccess.h>
39
#include <linux/syslog.h>
40 41 42 43 44

#include "internal.h"

#define	PSTORE_NAMELEN	64

45 46 47
static DEFINE_SPINLOCK(allpstore_lock);
static LIST_HEAD(allpstore);

48
struct pstore_private {
49
	struct list_head list;
50
	struct pstore_info *psi;
51 52
	enum pstore_type_id type;
	u64	id;
53
	int	count;
T
Tony Luck 已提交
54 55
	ssize_t	size;
	char	data[];
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
struct pstore_ftrace_seq_data {
	const void *ptr;
	size_t off;
	size_t size;
};

#define REC_SIZE sizeof(struct pstore_ftrace_record)

static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos)
{
	struct pstore_private *ps = s->private;
	struct pstore_ftrace_seq_data *data;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return NULL;

	data->off = ps->size % REC_SIZE;
	data->off += *pos * REC_SIZE;
	if (data->off + REC_SIZE > ps->size) {
		kfree(data);
		return NULL;
	}

	return data;

}

static void pstore_ftrace_seq_stop(struct seq_file *s, void *v)
{
	kfree(v);
}

static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	struct pstore_private *ps = s->private;
	struct pstore_ftrace_seq_data *data = v;

	data->off += REC_SIZE;
	if (data->off + REC_SIZE > ps->size)
		return NULL;

	(*pos)++;
	return data;
}

static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
{
	struct pstore_private *ps = s->private;
	struct pstore_ftrace_seq_data *data = v;
	struct pstore_ftrace_record *rec = (void *)(ps->data + data->off);

	seq_printf(s, "%d %08lx  %08lx  %pf <- %pF\n",
		pstore_ftrace_decode_cpu(rec), rec->ip, rec->parent_ip,
		(void *)rec->ip, (void *)rec->parent_ip);

	return 0;
}

static const struct seq_operations pstore_ftrace_seq_ops = {
	.start	= pstore_ftrace_seq_start,
	.next	= pstore_ftrace_seq_next,
	.stop	= pstore_ftrace_seq_stop,
	.show	= pstore_ftrace_seq_show,
};

124 125 126 127 128 129 130 131 132 133 134 135
static int pstore_check_syslog_permissions(struct pstore_private *ps)
{
	switch (ps->type) {
	case PSTORE_TYPE_DMESG:
	case PSTORE_TYPE_CONSOLE:
		return check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
			SYSLOG_FROM_READER);
	default:
		return 0;
	}
}

T
Tony Luck 已提交
136 137 138
static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
139 140
	struct seq_file *sf = file->private_data;
	struct pstore_private *ps = sf->private;
T
Tony Luck 已提交
141

142 143
	if (ps->type == PSTORE_TYPE_FTRACE)
		return seq_read(file, userbuf, count, ppos);
T
Tony Luck 已提交
144 145 146
	return simple_read_from_buffer(userbuf, count, ppos, ps->data, ps->size);
}

147 148 149 150 151 152 153
static int pstore_file_open(struct inode *inode, struct file *file)
{
	struct pstore_private *ps = inode->i_private;
	struct seq_file *sf;
	int err;
	const struct seq_operations *sops = NULL;

154 155 156 157
	err = pstore_check_syslog_permissions(ps);
	if (err)
		return err;

158 159 160 161 162 163 164 165 166 167 168 169 170
	if (ps->type == PSTORE_TYPE_FTRACE)
		sops = &pstore_ftrace_seq_ops;

	err = seq_open(file, sops);
	if (err < 0)
		return err;

	sf = file->private_data;
	sf->private = ps;

	return 0;
}

171
static loff_t pstore_file_llseek(struct file *file, loff_t off, int whence)
172 173 174 175
{
	struct seq_file *sf = file->private_data;

	if (sf->op)
176 177
		return seq_lseek(file, off, whence);
	return default_llseek(file, off, whence);
178 179
}

T
Tony Luck 已提交
180
static const struct file_operations pstore_file_operations = {
181 182 183 184
	.open		= pstore_file_open,
	.read		= pstore_file_read,
	.llseek		= pstore_file_llseek,
	.release	= seq_release,
T
Tony Luck 已提交
185
};
186 187 188 189 190 191 192

/*
 * When a file is unlinked from our file system we call the
 * platform driver to erase the record from persistent store.
 */
static int pstore_unlink(struct inode *dir, struct dentry *dentry)
{
193
	struct pstore_private *p = d_inode(dentry)->i_private;
194 195 196 197 198
	int err;

	err = pstore_check_syslog_permissions(p);
	if (err)
		return err;
199

200
	if (p->psi->erase)
201
		p->psi->erase(p->type, p->id, p->count,
202
			      d_inode(dentry)->i_ctime, p->psi);
203 204
	else
		return -EPERM;
205 206 207 208

	return simple_unlink(dir, dentry);
}

T
Tony Luck 已提交
209 210
static void pstore_evict_inode(struct inode *inode)
{
211 212 213
	struct pstore_private	*p = inode->i_private;
	unsigned long		flags;

214
	clear_inode(inode);
215 216 217 218 219 220
	if (p) {
		spin_lock_irqsave(&allpstore_lock, flags);
		list_del(&p->list);
		spin_unlock_irqrestore(&allpstore_lock, flags);
		kfree(p);
	}
T
Tony Luck 已提交
221 222
}

223 224 225 226 227
static const struct inode_operations pstore_dir_inode_operations = {
	.lookup		= simple_lookup,
	.unlink		= pstore_unlink,
};

A
Al Viro 已提交
228
static struct inode *pstore_get_inode(struct super_block *sb)
T
Tony Luck 已提交
229 230 231 232
{
	struct inode *inode = new_inode(sb);
	if (inode) {
		inode->i_ino = get_next_ino();
233
		inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
T
Tony Luck 已提交
234 235 236 237
	}
	return inode;
}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
enum {
	Opt_kmsg_bytes, Opt_err
};

static const match_table_t tokens = {
	{Opt_kmsg_bytes, "kmsg_bytes=%u"},
	{Opt_err, NULL}
};

static void parse_options(char *options)
{
	char		*p;
	substring_t	args[MAX_OPT_ARGS];
	int		option;

	if (!options)
		return;

	while ((p = strsep(&options, ",")) != NULL) {
		int token;

		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_kmsg_bytes:
			if (!match_int(&args[0], &option))
				pstore_set_kmsg_bytes(option);
			break;
		}
	}
}

static int pstore_remount(struct super_block *sb, int *flags, char *data)
{
274
	sync_filesystem(sb);
275 276 277 278 279
	parse_options(data);

	return 0;
}

280 281 282
static const struct super_operations pstore_ops = {
	.statfs		= simple_statfs,
	.drop_inode	= generic_delete_inode,
T
Tony Luck 已提交
283
	.evict_inode	= pstore_evict_inode,
284
	.remount_fs	= pstore_remount,
285 286 287 288 289
	.show_options	= generic_show_options,
};

static struct super_block *pstore_sb;

290
bool pstore_is_mounted(void)
291
{
T
Tony Luck 已提交
292
	return pstore_sb != NULL;
293 294 295 296 297 298 299
}

/*
 * Make a regular file in the root directory of our file system.
 * Load it up with "size" bytes of data from "buf".
 * Set the mtime & ctime to the date that this record was originally stored.
 */
300
int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
301 302
		  char *data, bool compressed, size_t size,
		  struct timespec time, struct pstore_info *psi)
303 304 305 306
{
	struct dentry		*root = pstore_sb->s_root;
	struct dentry		*dentry;
	struct inode		*inode;
307
	int			rc = 0;
308
	char			name[PSTORE_NAMELEN];
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
	struct pstore_private	*private, *pos;
	unsigned long		flags;

	spin_lock_irqsave(&allpstore_lock, flags);
	list_for_each_entry(pos, &allpstore, list) {
		if (pos->type == type &&
		    pos->id == id &&
		    pos->psi == psi) {
			rc = -EEXIST;
			break;
		}
	}
	spin_unlock_irqrestore(&allpstore_lock, flags);
	if (rc)
		return rc;
324 325

	rc = -ENOMEM;
A
Al Viro 已提交
326
	inode = pstore_get_inode(pstore_sb);
327 328
	if (!inode)
		goto fail;
A
Al Viro 已提交
329 330
	inode->i_mode = S_IFREG | 0444;
	inode->i_fop = &pstore_file_operations;
T
Tony Luck 已提交
331
	private = kmalloc(sizeof *private + size, GFP_KERNEL);
332 333
	if (!private)
		goto fail_alloc;
334
	private->type = type;
335
	private->id = id;
336
	private->count = count;
337
	private->psi = psi;
338 339 340

	switch (type) {
	case PSTORE_TYPE_DMESG:
341 342
		scnprintf(name, sizeof(name), "dmesg-%s-%lld%s",
			  psname, id, compressed ? ".enc.z" : "");
343
		break;
344
	case PSTORE_TYPE_CONSOLE:
345
		scnprintf(name, sizeof(name), "console-%s-%lld", psname, id);
346
		break;
347
	case PSTORE_TYPE_FTRACE:
348
		scnprintf(name, sizeof(name), "ftrace-%s-%lld", psname, id);
349
		break;
350
	case PSTORE_TYPE_MCE:
351
		scnprintf(name, sizeof(name), "mce-%s-%lld", psname, id);
352
		break;
353
	case PSTORE_TYPE_PPC_RTAS:
354
		scnprintf(name, sizeof(name), "rtas-%s-%lld", psname, id);
355
		break;
356
	case PSTORE_TYPE_PPC_OF:
357 358
		scnprintf(name, sizeof(name), "powerpc-ofw-%s-%lld",
			  psname, id);
359
		break;
360
	case PSTORE_TYPE_PPC_COMMON:
361 362
		scnprintf(name, sizeof(name), "powerpc-common-%s-%lld",
			  psname, id);
363
		break;
364 365 366
	case PSTORE_TYPE_PMSG:
		scnprintf(name, sizeof(name), "pmsg-%s-%lld", psname, id);
		break;
367 368 369
	case PSTORE_TYPE_PPC_OPAL:
		sprintf(name, "powerpc-opal-%s-%lld", psname, id);
		break;
370
	case PSTORE_TYPE_UNKNOWN:
371
		scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id);
372 373
		break;
	default:
374 375
		scnprintf(name, sizeof(name), "type%d-%s-%lld",
			  type, psname, id);
376 377 378
		break;
	}

A
Al Viro 已提交
379
	inode_lock(d_inode(root));
380 381

	dentry = d_alloc_name(root, name);
382
	if (!dentry)
383 384
		goto fail_lockedalloc;

T
Tony Luck 已提交
385 386
	memcpy(private->data, data, size);
	inode->i_size = private->size = size;
387 388 389 390 391 392

	inode->i_private = private;

	if (time.tv_sec)
		inode->i_mtime = inode->i_ctime = time;

T
Tony Luck 已提交
393
	d_add(dentry, inode);
394

395 396 397 398
	spin_lock_irqsave(&allpstore_lock, flags);
	list_add(&private->list, &allpstore);
	spin_unlock_irqrestore(&allpstore_lock, flags);

A
Al Viro 已提交
399
	inode_unlock(d_inode(root));
T
Tony Luck 已提交
400 401

	return 0;
402 403

fail_lockedalloc:
A
Al Viro 已提交
404
	inode_unlock(d_inode(root));
405 406 407 408 409 410 411 412
	kfree(private);
fail_alloc:
	iput(inode);

fail:
	return rc;
}

413
static int pstore_fill_super(struct super_block *sb, void *data, int silent)
414
{
A
Al Viro 已提交
415
	struct inode *inode;
416 417 418 419 420 421

	save_mount_options(sb, data);

	pstore_sb = sb;

	sb->s_maxbytes		= MAX_LFS_FILESIZE;
422 423
	sb->s_blocksize		= PAGE_SIZE;
	sb->s_blocksize_bits	= PAGE_SHIFT;
424 425 426 427
	sb->s_magic		= PSTOREFS_MAGIC;
	sb->s_op		= &pstore_ops;
	sb->s_time_gran		= 1;

428 429
	parse_options(data);

A
Al Viro 已提交
430
	inode = pstore_get_inode(sb);
A
Al Viro 已提交
431
	if (inode) {
A
Al Viro 已提交
432
		inode->i_mode = S_IFDIR | 0755;
A
Al Viro 已提交
433
		inode->i_op = &pstore_dir_inode_operations;
A
Al Viro 已提交
434 435
		inode->i_fop = &simple_dir_operations;
		inc_nlink(inode);
436
	}
A
Al Viro 已提交
437 438 439
	sb->s_root = d_make_root(inode);
	if (!sb->s_root)
		return -ENOMEM;
440

441
	pstore_get_records(0);
442 443 444 445

	return 0;
}

T
Tony Luck 已提交
446 447
static struct dentry *pstore_mount(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data)
448
{
T
Tony Luck 已提交
449
	return mount_single(fs_type, flags, data, pstore_fill_super);
450 451 452 453 454 455 456 457 458
}

static void pstore_kill_sb(struct super_block *sb)
{
	kill_litter_super(sb);
	pstore_sb = NULL;
}

static struct file_system_type pstore_fs_type = {
G
Geliang Tang 已提交
459
	.owner          = THIS_MODULE,
460
	.name		= "pstore",
T
Tony Luck 已提交
461
	.mount		= pstore_mount,
462 463 464 465 466
	.kill_sb	= pstore_kill_sb,
};

static int __init init_pstore_fs(void)
{
467
	int err;
468 469

	/* Create a convenient mount point for people to access pstore */
470 471
	err = sysfs_create_mount_point(fs_kobj, "pstore");
	if (err)
472 473 474 475
		goto out;

	err = register_filesystem(&pstore_fs_type);
	if (err < 0)
476
		sysfs_remove_mount_point(fs_kobj, "pstore");
477 478 479

out:
	return err;
480 481 482
}
module_init(init_pstore_fs)

G
Geliang Tang 已提交
483 484 485 486 487 488 489
static void __exit exit_pstore_fs(void)
{
	unregister_filesystem(&pstore_fs_type);
	sysfs_remove_mount_point(fs_kobj, "pstore");
}
module_exit(exit_pstore_fs)

490 491
MODULE_AUTHOR("Tony Luck <tony.luck@intel.com>");
MODULE_LICENSE("GPL");