Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Implements pstore backend driver that write to block (or non-block) storage
  4 * devices, using the pstore/zone API.
  5 */
  6
  7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8
  9#include <linux/kernel.h>
 10#include <linux/module.h>
 11#include "../../block/blk.h"
 12#include <linux/blkdev.h>
 13#include <linux/string.h>
 14#include <linux/of.h>
 15#include <linux/of_address.h>
 16#include <linux/platform_device.h>
 17#include <linux/pstore_blk.h>
 18#include <linux/mount.h>
 19#include <linux/uio.h>
 20
 21static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE;
 22module_param(kmsg_size, long, 0400);
 23MODULE_PARM_DESC(kmsg_size, "kmsg dump record size in kbytes");
 24
 25static int max_reason = CONFIG_PSTORE_BLK_MAX_REASON;
 26module_param(max_reason, int, 0400);
 27MODULE_PARM_DESC(max_reason,
 28		 "maximum reason for kmsg dump (default 2: Oops and Panic)");
 29
 30#if IS_ENABLED(CONFIG_PSTORE_PMSG)
 31static long pmsg_size = CONFIG_PSTORE_BLK_PMSG_SIZE;
 32#else
 33static long pmsg_size = -1;
 34#endif
 35module_param(pmsg_size, long, 0400);
 36MODULE_PARM_DESC(pmsg_size, "pmsg size in kbytes");
 37
 38#if IS_ENABLED(CONFIG_PSTORE_CONSOLE)
 39static long console_size = CONFIG_PSTORE_BLK_CONSOLE_SIZE;
 40#else
 41static long console_size = -1;
 42#endif
 43module_param(console_size, long, 0400);
 44MODULE_PARM_DESC(console_size, "console size in kbytes");
 45
 46#if IS_ENABLED(CONFIG_PSTORE_FTRACE)
 47static long ftrace_size = CONFIG_PSTORE_BLK_FTRACE_SIZE;
 48#else
 49static long ftrace_size = -1;
 50#endif
 51module_param(ftrace_size, long, 0400);
 52MODULE_PARM_DESC(ftrace_size, "ftrace size in kbytes");
 53
 54static bool best_effort;
 55module_param(best_effort, bool, 0400);
 56MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require storage driver pstore support, default: off)");
 57
 58/*
 59 * blkdev - the block device to use for pstore storage
 60 *
 61 * Usually, this will be a partition of a block device.
 62 *
 63 * blkdev accepts the following variants:
 64 * 1) <hex_major><hex_minor> device number in hexadecimal representation,
 65 *    with no leading 0x, for example b302.
 66 * 2) /dev/<disk_name> represents the device number of disk
 67 * 3) /dev/<disk_name><decimal> represents the device number
 68 *    of partition - device number of disk plus the partition number
 69 * 4) /dev/<disk_name>p<decimal> - same as the above, that form is
 70 *    used when disk name of partitioned disk ends on a digit.
 71 * 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
 72 *    unique id of a partition if the partition table provides it.
 73 *    The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
 74 *    partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
 75 *    filled hex representation of the 32-bit "NT disk signature", and PP
 76 *    is a zero-filled hex representation of the 1-based partition number.
 77 * 6) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
 78 *    a partition with a known unique id.
 79 * 7) <major>:<minor> major and minor number of the device separated by
 80 *    a colon.
 81 */
 82static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV;
 83module_param_string(blkdev, blkdev, 80, 0400);
 84MODULE_PARM_DESC(blkdev, "block device for pstore storage");
 85
 86/*
 87 * All globals must only be accessed under the pstore_blk_lock
 88 * during the register/unregister functions.
 89 */
 90static DEFINE_MUTEX(pstore_blk_lock);
 91static struct block_device *psblk_bdev;
 92static struct pstore_zone_info *pstore_zone_info;
 93static pstore_blk_panic_write_op blkdev_panic_write;
 94
 95struct bdev_info {
 96	dev_t devt;
 97	sector_t nr_sects;
 98	sector_t start_sect;
 99};
100
101#define check_size(name, alignsize) ({				\
102	long _##name_ = (name);					\
103	_##name_ = _##name_ <= 0 ? 0 : (_##name_ * 1024);	\
104	if (_##name_ & ((alignsize) - 1)) {			\
105		pr_info(#name " must align to %d\n",		\
106				(alignsize));			\
107		_##name_ = ALIGN(name, (alignsize));		\
108	}							\
109	_##name_;						\
110})
111
112static int __register_pstore_device(struct pstore_device_info *dev)
113{
114	int ret;
115
116	lockdep_assert_held(&pstore_blk_lock);
117
118	if (!dev || !dev->total_size || !dev->read || !dev->write)
119		return -EINVAL;
120
121	/* someone already registered before */
122	if (pstore_zone_info)
123		return -EBUSY;
124
125	pstore_zone_info = kzalloc(sizeof(struct pstore_zone_info), GFP_KERNEL);
126	if (!pstore_zone_info)
127		return -ENOMEM;
128
129	/* zero means not limit on which backends to attempt to store. */
130	if (!dev->flags)
131		dev->flags = UINT_MAX;
132
133#define verify_size(name, alignsize, enabled) {				\
134		long _##name_;						\
135		if (enabled)						\
136			_##name_ = check_size(name, alignsize);		\
137		else							\
138			_##name_ = 0;					\
139		name = _##name_ / 1024;					\
140		pstore_zone_info->name = _##name_;			\
141	}
142
143	verify_size(kmsg_size, 4096, dev->flags & PSTORE_FLAGS_DMESG);
144	verify_size(pmsg_size, 4096, dev->flags & PSTORE_FLAGS_PMSG);
145	verify_size(console_size, 4096, dev->flags & PSTORE_FLAGS_CONSOLE);
146	verify_size(ftrace_size, 4096, dev->flags & PSTORE_FLAGS_FTRACE);
147#undef verify_size
148
149	pstore_zone_info->total_size = dev->total_size;
150	pstore_zone_info->max_reason = max_reason;
151	pstore_zone_info->read = dev->read;
152	pstore_zone_info->write = dev->write;
153	pstore_zone_info->erase = dev->erase;
154	pstore_zone_info->panic_write = dev->panic_write;
155	pstore_zone_info->name = KBUILD_MODNAME;
156	pstore_zone_info->owner = THIS_MODULE;
157
158	ret = register_pstore_zone(pstore_zone_info);
159	if (ret) {
160		kfree(pstore_zone_info);
161		pstore_zone_info = NULL;
162	}
163	return ret;
164}
165/**
166 * register_pstore_device() - register non-block device to pstore/blk
167 *
168 * @dev: non-block device information
169 *
170 * Return:
171 * * 0		- OK
172 * * Others	- something error.
173 */
174int register_pstore_device(struct pstore_device_info *dev)
175{
176	int ret;
177
178	mutex_lock(&pstore_blk_lock);
179	ret = __register_pstore_device(dev);
180	mutex_unlock(&pstore_blk_lock);
181
182	return ret;
183}
184EXPORT_SYMBOL_GPL(register_pstore_device);
185
186static void __unregister_pstore_device(struct pstore_device_info *dev)
187{
188	lockdep_assert_held(&pstore_blk_lock);
189	if (pstore_zone_info && pstore_zone_info->read == dev->read) {
190		unregister_pstore_zone(pstore_zone_info);
191		kfree(pstore_zone_info);
192		pstore_zone_info = NULL;
193	}
194}
195
196/**
197 * unregister_pstore_device() - unregister non-block device from pstore/blk
198 *
199 * @dev: non-block device information
200 */
201void unregister_pstore_device(struct pstore_device_info *dev)
202{
203	mutex_lock(&pstore_blk_lock);
204	__unregister_pstore_device(dev);
205	mutex_unlock(&pstore_blk_lock);
206}
207EXPORT_SYMBOL_GPL(unregister_pstore_device);
208
209/**
210 * psblk_get_bdev() - open block device
211 *
212 * @holder:	Exclusive holder identifier
213 * @info:	Information about bdev to fill in
214 *
215 * Return: pointer to block device on success and others on error.
216 *
217 * On success, the returned block_device has reference count of one.
218 */
219static struct block_device *psblk_get_bdev(void *holder,
220					   struct bdev_info *info)
221{
222	struct block_device *bdev = ERR_PTR(-ENODEV);
223	fmode_t mode = FMODE_READ | FMODE_WRITE;
224	sector_t nr_sects;
225
226	lockdep_assert_held(&pstore_blk_lock);
227
228	if (pstore_zone_info)
229		return ERR_PTR(-EBUSY);
230
231	if (!blkdev[0])
232		return ERR_PTR(-ENODEV);
233
234	if (holder)
235		mode |= FMODE_EXCL;
236	bdev = blkdev_get_by_path(blkdev, mode, holder);
237	if (IS_ERR(bdev)) {
238		dev_t devt;
239
240		devt = name_to_dev_t(blkdev);
241		if (devt == 0)
242			return ERR_PTR(-ENODEV);
243		bdev = blkdev_get_by_dev(devt, mode, holder);
244		if (IS_ERR(bdev))
245			return bdev;
246	}
247
248	nr_sects = part_nr_sects_read(bdev->bd_part);
249	if (!nr_sects) {
250		pr_err("not enough space for '%s'\n", blkdev);
251		blkdev_put(bdev, mode);
252		return ERR_PTR(-ENOSPC);
253	}
254
255	if (info) {
256		info->devt = bdev->bd_dev;
257		info->nr_sects = nr_sects;
258		info->start_sect = get_start_sect(bdev);
259	}
260
261	return bdev;
262}
263
264static void psblk_put_bdev(struct block_device *bdev, void *holder)
265{
266	fmode_t mode = FMODE_READ | FMODE_WRITE;
267
268	lockdep_assert_held(&pstore_blk_lock);
269
270	if (!bdev)
271		return;
272
273	if (holder)
274		mode |= FMODE_EXCL;
275	blkdev_put(bdev, mode);
276}
277
278static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos)
279{
280	struct block_device *bdev = psblk_bdev;
281	struct file file;
282	struct kiocb kiocb;
283	struct iov_iter iter;
284	struct kvec iov = {.iov_base = buf, .iov_len = bytes};
285
286	if (!bdev)
287		return -ENODEV;
288
289	memset(&file, 0, sizeof(struct file));
290	file.f_mapping = bdev->bd_inode->i_mapping;
291	file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
292	file.f_inode = bdev->bd_inode;
293	file_ra_state_init(&file.f_ra, file.f_mapping);
294
295	init_sync_kiocb(&kiocb, &file);
296	kiocb.ki_pos = pos;
297	iov_iter_kvec(&iter, READ, &iov, 1, bytes);
298
299	return generic_file_read_iter(&kiocb, &iter);
300}
301
302static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes,
303		loff_t pos)
304{
305	struct block_device *bdev = psblk_bdev;
306	struct iov_iter iter;
307	struct kiocb kiocb;
308	struct file file;
309	ssize_t ret;
310	struct kvec iov = {.iov_base = (void *)buf, .iov_len = bytes};
311
312	if (!bdev)
313		return -ENODEV;
314
315	/* Console/Ftrace backend may handle buffer until flush dirty zones */
316	if (in_interrupt() || irqs_disabled())
317		return -EBUSY;
318
319	memset(&file, 0, sizeof(struct file));
320	file.f_mapping = bdev->bd_inode->i_mapping;
321	file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
322	file.f_inode = bdev->bd_inode;
323
324	init_sync_kiocb(&kiocb, &file);
325	kiocb.ki_pos = pos;
326	iov_iter_kvec(&iter, WRITE, &iov, 1, bytes);
327
328	inode_lock(bdev->bd_inode);
329	ret = generic_write_checks(&kiocb, &iter);
330	if (ret > 0)
331		ret = generic_perform_write(&file, &iter, pos);
332	inode_unlock(bdev->bd_inode);
333
334	if (likely(ret > 0)) {
335		const struct file_operations f_op = {.fsync = blkdev_fsync};
336
337		file.f_op = &f_op;
338		kiocb.ki_pos += ret;
339		ret = generic_write_sync(&kiocb, ret);
340	}
341	return ret;
342}
343
344static ssize_t psblk_blk_panic_write(const char *buf, size_t size,
345		loff_t off)
346{
347	int ret;
348
349	if (!blkdev_panic_write)
350		return -EOPNOTSUPP;
351
352	/* size and off must align to SECTOR_SIZE for block device */
353	ret = blkdev_panic_write(buf, off >> SECTOR_SHIFT,
354			size >> SECTOR_SHIFT);
355	/* try next zone */
356	if (ret == -ENOMSG)
357		return ret;
358	return ret ? -EIO : size;
359}
360
361static int __register_pstore_blk(struct pstore_blk_info *info)
362{
363	char bdev_name[BDEVNAME_SIZE];
364	struct block_device *bdev;
365	struct pstore_device_info dev;
366	struct bdev_info binfo;
367	void *holder = blkdev;
368	int ret = -ENODEV;
369
370	lockdep_assert_held(&pstore_blk_lock);
371
372	/* hold bdev exclusively */
373	memset(&binfo, 0, sizeof(binfo));
374	bdev = psblk_get_bdev(holder, &binfo);
375	if (IS_ERR(bdev)) {
376		pr_err("failed to open '%s'!\n", blkdev);
377		return PTR_ERR(bdev);
378	}
379
380	/* only allow driver matching the @blkdev */
381	if (!binfo.devt || (!best_effort &&
382			    MAJOR(binfo.devt) != info->major)) {
383		pr_debug("invalid major %u (expect %u)\n",
384				info->major, MAJOR(binfo.devt));
385		ret = -ENODEV;
386		goto err_put_bdev;
387	}
388
389	/* psblk_bdev must be assigned before register to pstore/blk */
390	psblk_bdev = bdev;
391	blkdev_panic_write = info->panic_write;
392
393	/* Copy back block device details. */
394	info->devt = binfo.devt;
395	info->nr_sects = binfo.nr_sects;
396	info->start_sect = binfo.start_sect;
397
398	memset(&dev, 0, sizeof(dev));
399	dev.total_size = info->nr_sects << SECTOR_SHIFT;
400	dev.flags = info->flags;
401	dev.read = psblk_generic_blk_read;
402	dev.write = psblk_generic_blk_write;
403	dev.erase = NULL;
404	dev.panic_write = info->panic_write ? psblk_blk_panic_write : NULL;
405
406	ret = __register_pstore_device(&dev);
407	if (ret)
408		goto err_put_bdev;
409
410	bdevname(bdev, bdev_name);
411	pr_info("attached %s%s\n", bdev_name,
412		info->panic_write ? "" : " (no dedicated panic_write!)");
413	return 0;
414
415err_put_bdev:
416	psblk_bdev = NULL;
417	blkdev_panic_write = NULL;
418	psblk_put_bdev(bdev, holder);
419	return ret;
420}
421
422/**
423 * register_pstore_blk() - register block device to pstore/blk
424 *
425 * @info: details on the desired block device interface
426 *
427 * Return:
428 * * 0		- OK
429 * * Others	- something error.
430 */
431int register_pstore_blk(struct pstore_blk_info *info)
432{
433	int ret;
434
435	mutex_lock(&pstore_blk_lock);
436	ret = __register_pstore_blk(info);
437	mutex_unlock(&pstore_blk_lock);
438
439	return ret;
440}
441EXPORT_SYMBOL_GPL(register_pstore_blk);
442
443static void __unregister_pstore_blk(unsigned int major)
444{
445	struct pstore_device_info dev = { .read = psblk_generic_blk_read };
446	void *holder = blkdev;
447
448	lockdep_assert_held(&pstore_blk_lock);
449	if (psblk_bdev && MAJOR(psblk_bdev->bd_dev) == major) {
450		__unregister_pstore_device(&dev);
451		psblk_put_bdev(psblk_bdev, holder);
452		blkdev_panic_write = NULL;
453		psblk_bdev = NULL;
454	}
455}
456
457/**
458 * unregister_pstore_blk() - unregister block device from pstore/blk
459 *
460 * @major: the major device number of device
461 */
462void unregister_pstore_blk(unsigned int major)
463{
464	mutex_lock(&pstore_blk_lock);
465	__unregister_pstore_blk(major);
466	mutex_unlock(&pstore_blk_lock);
467}
468EXPORT_SYMBOL_GPL(unregister_pstore_blk);
469
470/* get information of pstore/blk */
471int pstore_blk_get_config(struct pstore_blk_config *info)
472{
473	strncpy(info->device, blkdev, 80);
474	info->max_reason = max_reason;
475	info->kmsg_size = check_size(kmsg_size, 4096);
476	info->pmsg_size = check_size(pmsg_size, 4096);
477	info->ftrace_size = check_size(ftrace_size, 4096);
478	info->console_size = check_size(console_size, 4096);
479
480	return 0;
481}
482EXPORT_SYMBOL_GPL(pstore_blk_get_config);
483
484static int __init pstore_blk_init(void)
485{
486	struct pstore_blk_info info = { };
487	int ret = 0;
488
489	mutex_lock(&pstore_blk_lock);
490	if (!pstore_zone_info && best_effort && blkdev[0])
491		ret = __register_pstore_blk(&info);
492	mutex_unlock(&pstore_blk_lock);
493
494	return ret;
495}
496late_initcall(pstore_blk_init);
497
498static void __exit pstore_blk_exit(void)
499{
500	mutex_lock(&pstore_blk_lock);
501	if (psblk_bdev)
502		__unregister_pstore_blk(MAJOR(psblk_bdev->bd_dev));
503	else {
504		struct pstore_device_info dev = { };
505
506		if (pstore_zone_info)
507			dev.read = pstore_zone_info->read;
508		__unregister_pstore_device(&dev);
509	}
510	mutex_unlock(&pstore_blk_lock);
511}
512module_exit(pstore_blk_exit);
513
514MODULE_LICENSE("GPL");
515MODULE_AUTHOR("WeiXiong Liao <liaoweixiong@allwinnertech.com>");
516MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
517MODULE_DESCRIPTION("pstore backend for block devices");