static int __init ram_console_late_init(void)
{
	struct proc_dir_entry *entry;
	struct persistent_ram_zone *prz = ram_console_zone;

	if (!prz)
		return 0;

	if (persistent_ram_old_size(prz) == 0)
		return 0;

	entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
	if (!entry) {
		printk(KERN_ERR "ram_console: failed to create proc entry\n");
		persistent_ram_free_old(prz);
		return 0;
	}

	entry->proc_fops = &ram_console_file_ops;
	entry->size = persistent_ram_old_size(prz) +
		persistent_ram_ecc_string(prz, NULL, 0) +
		bootinfo_size;

	return 0;
}
예제 #2
0
static int __init ram_console_late_init(void)
{
	struct proc_dir_entry *entry;
	struct persistent_ram_zone *prz = ram_console_zone;
#if defined(CONFIG_HTC_DEBUG_RAMCONSOLE)
	bool is_last_bldr_ramdump_mode = false;
#endif

	if (!prz)
		return 0;

	if (persistent_ram_old_size(prz) == 0)
		return 0;

	entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
	if (!entry) {
		printk(KERN_ERR "ram_console: failed to create proc entry\n");
		persistent_ram_free_old(prz);
		return 0;
	}

#if defined(CONFIG_HTC_DEBUG_RAMCONSOLE)
	if (bl_old_log != NULL) {
		bl_old_log_buf = kmalloc(bl_old_log_size, GFP_KERNEL);
		if (bl_old_log_buf == NULL) {
			printk(KERN_ERR "[K] ram_console: failed to allocate buffer for last bootloader log, size: %zu\n", bl_old_log_size);
		} else {
			printk(KERN_INFO "[K] ram_console: allocate buffer for last bootloader log, size: %zu\n", bl_old_log_size);
			bldr_log_parser(bl_old_log, bl_old_log_buf, bl_old_log_size, &bl_old_log_buf_size);
			is_last_bldr_ramdump_mode = bldr_rst_msg_parser(bl_old_log_buf, bl_old_log_buf_size, true);
			if (is_last_bldr_ramdump_mode)
				printk(KERN_INFO "[K] ram_console: Found abnormal rst_msg pattern in last bootloader log\n");
		}
	}
	if (bl_log != NULL) {
		bl_log_buf = kmalloc(bl_log_size, GFP_KERNEL);
		if (bl_log_buf == NULL) {
			printk(KERN_ERR "[K] ram_console: failed to allocate buffer for bootloader log, size: %zu\n", bl_log_size);
		} else {
			printk(KERN_INFO "[K] ram_console: allocate buffer for bootloader log, size: %zu\n", bl_log_size);
			bldr_log_parser(bl_log, bl_log_buf, bl_log_size, &bl_log_buf_size);
			if (!is_last_bldr_ramdump_mode) {
				if (bldr_rst_msg_parser(bl_log_buf, bl_log_buf_size, false))
					printk(KERN_INFO "[K] ram_console: Found abnormal rst_msg pattern in bootloader log\n");
			}
		}
	}
#endif

	entry->proc_fops = &ram_console_file_ops;
	entry->size = persistent_ram_old_size(prz) +
		persistent_ram_ecc_string(prz, NULL, 0) +
		bootinfo_size;
#if defined(CONFIG_HTC_DEBUG_RAMCONSOLE)
	entry->size += bl_old_log_buf_size;
	entry->size += bl_log_buf_size;
#endif

	return 0;
}
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
				   int *count, struct timespec *time,
				   char **buf, struct pstore_info *psi)
{
	ssize_t size;
	ssize_t ecc_notice_size;
	struct ramoops_context *cxt = psi->data;
	struct persistent_ram_zone *prz;

	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
				   cxt->max_dump_cnt, id, type,
				   PSTORE_TYPE_DMESG, 1);
	if (!prz_ok(prz)) {
		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
		if (prz && !persistent_ram_old_size(prz))
			persistent_ram_annotation_merge(NULL);
	}
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
					   1, id, type, PSTORE_TYPE_FTRACE, 0);
	if (!prz_ok(prz)) {
		prz = ramoops_get_next_prz(&cxt->aprz, &cxt->annotate_read_cnt,
					1, id, type, PSTORE_TYPE_ANNOTATE, 0);
		persistent_ram_annotation_merge(prz);
	}
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
					   1, id, type, PSTORE_TYPE_PMSG, 0);
	if (!prz_ok(prz))
		return 0;

	/* TODO(kees): Bogus time for the moment. */
	time->tv_sec = 0;
	time->tv_nsec = 0;

	size = persistent_ram_old_size(prz);

	/* ECC correction notice */
	ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);

	*buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
	if (*buf == NULL)
		return -ENOMEM;

	memcpy(*buf, persistent_ram_old(prz), size);
	persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);

	return size + ecc_notice_size;
}
예제 #4
0
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
				   int *count, struct timespec *time,
				   char **buf, struct pstore_info *psi)
{
	ssize_t size;
	struct ramoops_context *cxt = psi->data;
	struct persistent_ram_zone *prz;

	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
				   cxt->max_dump_cnt, id, type,
				   PSTORE_TYPE_DMESG, 1);
	if (!prz)
		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
	if (!prz)
		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
					   1, id, type, PSTORE_TYPE_FTRACE, 0);
	if (!prz)
		return 0;

	/* TODO(kees): Bogus time for the moment. */
	time->tv_sec = 0;
	time->tv_nsec = 0;

	size = persistent_ram_old_size(prz);
	*buf = kmalloc(size, GFP_KERNEL);
	if (*buf == NULL)
		return -ENOMEM;
	memcpy(*buf, persistent_ram_old(prz), size);

	return size;
}
static int __devinit persistent_trace_probe(struct platform_device *pdev)
{
	struct dentry *d;
	int ret;

	persistent_trace = persistent_ram_init_ringbuffer(&pdev->dev, false);
	if (IS_ERR(persistent_trace)) {
		pr_err("persistent_trace: failed to init ringbuffer: %ld\n",
				PTR_ERR(persistent_trace));
		return PTR_ERR(persistent_trace);
	}

	ret = register_tracer(&persistent_tracer);
	if (ret)
		pr_err("persistent_trace: failed to register tracer");

	if (persistent_ram_old_size(persistent_trace) > 0) {
		d = debugfs_create_file("persistent_trace", S_IRUGO, NULL,
			NULL, &persistent_trace_old_fops);
		if (IS_ERR_OR_NULL(d))
			pr_err("persistent_trace: failed to create old file\n");
	}

	return 0;
}
예제 #6
0
파일: ram.c 프로젝트: acton393/linux
static struct persistent_ram_zone *
ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
		     u64 *id,
		     enum pstore_type_id *typep, enum pstore_type_id type,
		     bool update)
{
	struct persistent_ram_zone *prz;
	int i = (*c)++;

	if (i >= max)
		return NULL;

	prz = przs[i];
	if (!prz)
		return NULL;

	/* Update old/shadowed buffer. */
	if (update)
		persistent_ram_save_old(prz);

	if (!persistent_ram_old_size(prz))
		return NULL;

	*typep = type;
	*id = i;

	return prz;
}
예제 #7
0
static int __init ram_console_late_init(void)
{
	struct proc_dir_entry *entry;
	struct persistent_ram_zone *prz = ram_console_zone;
	/*Skies-2012/09/07, create proc file for crash status++*/
	struct proc_dir_entry *entry_cs;
	int size = 0;
	/*Skies-2012/09/07, create proc file for crash status--*/

	/*Skies-2012/09/07, create proc file for crash status++*/
	entry_cs = create_proc_entry("crash_status", S_IFREG|S_IRUGO/*|S_IWUGO*/, NULL);
	if (!entry_cs) {
            pr_err("%s: failed to create proc entry\n", __func__);
            return 0;
	}
	entry_cs->proc_fops = &crash_status_file_ops;
	entry_cs->size = CRASH_STATUS_CMD_SIZE;

	debug_info_buf = smem_get_entry(SMEM_ID_VENDOR0, &size);
	if (debug_info_buf != NULL) {
	    memcpy(&debug_info, debug_info_buf, sizeof(debug_info));
	}else {
	    return 0;
	}
	/*Skies-2012/09/07, create proc file for crash status--*/

	if (!prz)
		return 0;

	if (persistent_ram_old_size(prz) == 0)
		return 0;

	entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
	if (!entry) {
		printk(KERN_ERR "ram_console: failed to create proc entry\n");
		persistent_ram_free_old(prz);
		return 0;
	}

	entry->proc_fops = &ram_console_file_ops;
	entry->size = persistent_ram_old_size(prz) +
		persistent_ram_ecc_string(prz, NULL, 0) +
		bootinfo_size;

	return 0;
}
static ssize_t ram_console_read_old(struct file *file, char __user *buf,
                                    size_t len, loff_t *offset)
{
    loff_t pos = *offset;
    ssize_t count;
    struct persistent_ram_zone *prz = ram_console_zone;
    size_t old_log_size = persistent_ram_old_size(prz);
    const char *old_log = persistent_ram_old(prz);
    char *str;
    int ret;

#ifndef CONFIG_MACH_MSM8974_14001
//[email protected], 2014/01/16, Delete for solve the problem that can not read /proc/last_kmsg right.
    if (dmesg_restrict && !capable(CAP_SYSLOG))
        return -EPERM;
#endif  /* CONFIG_MACH_MSM8974_14001 */

    /* Main last_kmsg log */
    if (pos < old_log_size) {
        count = min(len, (size_t)(old_log_size - pos));
        if (copy_to_user(buf, old_log + pos, count))
            return -EFAULT;
        goto out;
    }

    /* ECC correction notice */
    pos -= old_log_size;
    count = persistent_ram_ecc_string(prz, NULL, 0);
    if (pos < count) {
        str = kmalloc(count, GFP_KERNEL);
        if (!str)
            return -ENOMEM;
        persistent_ram_ecc_string(prz, str, count + 1);
        count = min(len, (size_t)(count - pos));
        ret = copy_to_user(buf, str + pos, count);
        kfree(str);
        if (ret)
            return -EFAULT;
        goto out;
    }

    /* Boot info passed through pdata */
    pos -= count;
    if (pos < bootinfo_size) {
        count = min(len, (size_t)(bootinfo_size - pos));
        if (copy_to_user(buf, bootinfo + pos, count))
            return -EFAULT;
        goto out;
    }

    /* EOF */
    return 0;

out:
    *offset += count;
    return count;
}
예제 #9
0
static ssize_t ram_console_read_old(struct file *file, char __user *buf,
				    size_t len, loff_t *offset)
{
	loff_t pos = *offset;
	ssize_t count;
	struct persistent_ram_zone *prz = ram_console_zone;
	size_t old_log_size = persistent_ram_old_size(prz);
	const char *old_log = persistent_ram_old(prz);
	char *str;
	int ret;

/*<<Skies-2012/11/29, remove permission restriction*/
#if 0
	if (dmesg_restrict && !capable(CAP_SYSLOG))
		return -EPERM;
#endif
/*>>Skies-2012/11/29, remove permission restriction*/
	/* Main last_kmsg log */
	if (pos < old_log_size) {
		count = min(len, (size_t)(old_log_size - pos));
		if (copy_to_user(buf, old_log + pos, count))
			return -EFAULT;
		goto out;
	}

	/* ECC correction notice */
	pos -= old_log_size;
	count = persistent_ram_ecc_string(prz, NULL, 0);
	if (pos < count) {
		str = kmalloc(count, GFP_KERNEL);
		if (!str)
			return -ENOMEM;
		persistent_ram_ecc_string(prz, str, count + 1);
		count = min(len, (size_t)(count - pos));
		ret = copy_to_user(buf, str + pos, count);
		kfree(str);
		if (ret)
			return -EFAULT;
		goto out;
	}

	/* Boot info passed through pdata */
	pos -= count;
	if (pos < bootinfo_size) {
		count = min(len, (size_t)(bootinfo_size - pos));
		if (copy_to_user(buf, bootinfo + pos, count))
			return -EFAULT;
		goto out;
	}

	/* EOF */
	return 0;

out:
	*offset += count;
	return count;
}
예제 #10
0
static int __init ram_console_late_init(void)
{
	struct proc_dir_entry *entry;
	struct persistent_ram_zone *prz = ram_console_zone;

	persistent_ram_ext_oldbuf_merge(prz);

	if (!prz)
		return 0;

	if (persistent_ram_old_size(prz) == 0)
		return 0;

	if (!bootinfo) {
		bootinfo = kstrdup(boot_command_line, GFP_KERNEL);
		if (bootinfo) {
			bootinfo_size = strlen(bootinfo);
			bootreason_size = 1 +
				snprintf(NULL, 0, bootreason_label,
						bi_bootreason());
		}
	}

	entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
	if (!entry) {
		printk(KERN_ERR "ram_console: failed to create proc entry\n");
		persistent_ram_free_old(prz);
		return 0;
	}

	entry->proc_fops = &ram_console_file_ops;
	entry->size = persistent_ram_old_size(prz) +
		persistent_ram_ecc_string(prz, NULL, 0) +
		bootinfo_size +
		bootreason_size;

	return 0;
}
예제 #11
0
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
				   int *count, struct timespec *time,
				   char **buf, bool *compressed,
				   struct pstore_info *psi)
{
	ssize_t size;
	ssize_t ecc_notice_size;
	struct ramoops_context *cxt = psi->data;
	struct persistent_ram_zone *prz;

	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
				   cxt->max_dump_cnt, id, type,
				   PSTORE_TYPE_DMESG, 1);
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
	if (!prz_ok(prz)) {
		prz = ramoops_get_next_prz(&cxt->bprz, &cxt->bconsole_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
		/*pr_notice("pstore: pstore_read bprz type: %d count %d id %llx\n", *type, cxt->bconsole_read_cnt, *id);
		*id = 2;*/
	}
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
					   1, id, type, PSTORE_TYPE_FTRACE, 0);
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
					   1, id, type, PSTORE_TYPE_PMSG, 0);
	if (!prz_ok(prz))
		return 0;

	size = persistent_ram_old_size(prz);

	/* ECC correction notice */
	ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);

	*buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
	if (*buf == NULL)
		return -ENOMEM;

	memcpy(*buf, persistent_ram_old(prz), size);
	ramoops_read_kmsg_hdr(*buf, time, compressed);
	persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);

	return size + ecc_notice_size;
}
예제 #12
0
파일: ram.c 프로젝트: 383530895/linux
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
				   int *count, struct timespec *time,
				   char **buf, bool *compressed,
				   struct pstore_info *psi)
{
	ssize_t size;
	ssize_t ecc_notice_size;
	struct ramoops_context *cxt = psi->data;
	struct persistent_ram_zone *prz;
	int header_length;

	prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
				   cxt->max_dump_cnt, id, type,
				   PSTORE_TYPE_DMESG, 1);
	if (!prz)
		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
	if (!prz)
		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
					   1, id, type, PSTORE_TYPE_FTRACE, 0);
	if (!prz)
		return 0;

	if (!persistent_ram_old(prz))
		return 0;

	size = persistent_ram_old_size(prz);
	header_length = ramoops_read_kmsg_hdr(persistent_ram_old(prz), time,
			compressed);
	size -= header_length;

	/* ECC correction notice */
	ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);

	*buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
	if (*buf == NULL)
		return -ENOMEM;

	memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size);
	persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);

	return size + ecc_notice_size;
}
void *persistent_trace_seq_start(struct seq_file *s, loff_t *pos)
{
	struct persistent_trace_seq_data *data;

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

	data->ptr = persistent_ram_old(persistent_trace);
	data->size = persistent_ram_old_size(persistent_trace);
	data->off = data->size % REC_SIZE;

	data->off += *pos * REC_SIZE;

	if (data->off + REC_SIZE > data->size) {
		kfree(data);
		return NULL;
	}

	return data;

}
예제 #14
0
파일: ram.c 프로젝트: acton393/linux
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
				   int *count, struct timespec *time,
				   char **buf, bool *compressed,
				   ssize_t *ecc_notice_size,
				   struct pstore_info *psi)
{
	ssize_t size;
	struct ramoops_context *cxt = psi->data;
	struct persistent_ram_zone *prz = NULL;
	int header_length = 0;

	/* Ramoops headers provide time stamps for PSTORE_TYPE_DMESG, but
	 * PSTORE_TYPE_CONSOLE and PSTORE_TYPE_FTRACE don't currently have
	 * valid time stamps, so it is initialized to zero.
	 */
	time->tv_sec = 0;
	time->tv_nsec = 0;
	*compressed = false;

	/* Find the next valid persistent_ram_zone for DMESG */
	while (cxt->dump_read_cnt < cxt->max_dump_cnt && !prz) {
		prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
					   cxt->max_dump_cnt, id, type,
					   PSTORE_TYPE_DMESG, 1);
		if (!prz_ok(prz))
			continue;
		header_length = ramoops_read_kmsg_hdr(persistent_ram_old(prz),
						      time, compressed);
		/* Clear and skip this DMESG record if it has no valid header */
		if (!header_length) {
			persistent_ram_free_old(prz);
			persistent_ram_zap(prz);
			prz = NULL;
		}
	}

	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
					   1, id, type, PSTORE_TYPE_FTRACE, 0);
	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
					   1, id, type, PSTORE_TYPE_PMSG, 0);
	if (!prz_ok(prz))
		return 0;

	size = persistent_ram_old_size(prz) - header_length;

	/* ECC correction notice */
	*ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);

	*buf = kmalloc(size + *ecc_notice_size + 1, GFP_KERNEL);
	if (*buf == NULL)
		return -ENOMEM;

	memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size);
	persistent_ram_ecc_string(prz, *buf + size, *ecc_notice_size + 1);

	return size;
}
예제 #15
0
파일: ram.c 프로젝트: acton393/linux
static bool prz_ok(struct persistent_ram_zone *prz)
{
	return !!prz && !!(persistent_ram_old_size(prz) +
			   persistent_ram_ecc_string(prz, NULL, 0));
}
예제 #16
0
static ssize_t ram_console_read_old(struct file *file, char __user *buf,
				    size_t len, loff_t *offset)
{
	loff_t pos = *offset;
	ssize_t count;
	struct persistent_ram_zone *prz = ram_console_zone;
	size_t old_log_size = persistent_ram_old_size(prz);
	const char *old_log = persistent_ram_old(prz);
	char *str;
	int ret;

	if (dmesg_restrict && !capable(CAP_SYSLOG))
		return -EPERM;

#if defined(CONFIG_HTC_DEBUG_RAMCONSOLE)
	/* last bootloader log */
	if (pos < bl_old_log_buf_size) {
		count = min(len, (size_t)(bl_old_log_buf_size - pos));
		if (copy_to_user(buf, bl_old_log_buf + pos, count))
			return -EFAULT;
		goto out;
	}

	pos -= bl_old_log_buf_size;
#endif

	/* Main last_kmsg log */
	if (pos < old_log_size) {
		count = min(len, (size_t)(old_log_size - pos));
		if (copy_to_user(buf, old_log + pos, count))
			return -EFAULT;
		goto out;
	}

	/* ECC correction notice */
	pos -= old_log_size;
	count = persistent_ram_ecc_string(prz, NULL, 0);
	if (pos < count) {
		str = kmalloc(count, GFP_KERNEL);
		if (!str)
			return -ENOMEM;
		persistent_ram_ecc_string(prz, str, count + 1);
		count = min(len, (size_t)(count - pos));
		ret = copy_to_user(buf, str + pos, count);
		kfree(str);
		if (ret)
			return -EFAULT;
		goto out;
	}

	/* Append the boot reason required by Google */
	pos -= count;
	if (pos < rst_msg_buf_size) {
		count = min(len, (size_t)(rst_msg_buf_size - pos));
		if (copy_to_user(buf, rst_msg_buf + pos, count))
			return -EFAULT;
		goto out;
	}

	/* Boot info passed through pdata */
	pos -= rst_msg_buf_size;
	if (pos < bootinfo_size) {
		count = min(len, (size_t)(bootinfo_size - pos));
		if (copy_to_user(buf, bootinfo + pos, count))
			return -EFAULT;
		goto out;
	}

#if defined(CONFIG_HTC_DEBUG_RAMCONSOLE)
	/* bootloader log */
	pos -= bootinfo_size;
	if (pos < bl_log_buf_size) {
		count = min(len, (size_t)(bl_log_buf_size - pos));
		if (copy_to_user(buf, bl_log_buf + pos, count))
			return -EFAULT;
		goto out;
	}
#endif

	/* EOF */
	return 0;

out:
	*offset += count;
	return count;
}
예제 #17
0
파일: ram.c 프로젝트: forgivemyheart/linux
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
				   int *count, struct timespec *time,
				   char **buf, bool *compressed,
				   ssize_t *ecc_notice_size,
				   struct pstore_info *psi)
{
	ssize_t size = 0;
	struct ramoops_context *cxt = psi->data;
	struct persistent_ram_zone *prz = NULL;
	int header_length = 0;
	bool free_prz = false;

	/* Ramoops headers provide time stamps for PSTORE_TYPE_DMESG, but
	 * PSTORE_TYPE_CONSOLE and PSTORE_TYPE_FTRACE don't currently have
	 * valid time stamps, so it is initialized to zero.
	 */
	time->tv_sec = 0;
	time->tv_nsec = 0;
	*compressed = false;

	/* Find the next valid persistent_ram_zone for DMESG */
	while (cxt->dump_read_cnt < cxt->max_dump_cnt && !prz) {
		prz = ramoops_get_next_prz(cxt->dprzs, &cxt->dump_read_cnt,
					   cxt->max_dump_cnt, id, type,
					   PSTORE_TYPE_DMESG, 1);
		if (!prz_ok(prz))
			continue;
		header_length = ramoops_read_kmsg_hdr(persistent_ram_old(prz),
						      time, compressed);
		/* Clear and skip this DMESG record if it has no valid header */
		if (!header_length) {
			persistent_ram_free_old(prz);
			persistent_ram_zap(prz);
			prz = NULL;
		}
	}

	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
					   1, id, type, PSTORE_TYPE_CONSOLE, 0);

	if (!prz_ok(prz))
		prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
					   1, id, type, PSTORE_TYPE_PMSG, 0);

	/* ftrace is last since it may want to dynamically allocate memory. */
	if (!prz_ok(prz)) {
		if (!(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)) {
			prz = ramoops_get_next_prz(cxt->fprzs,
					&cxt->ftrace_read_cnt, 1, id, type,
					PSTORE_TYPE_FTRACE, 0);
		} else {
			/*
			 * Build a new dummy record which combines all the
			 * per-cpu records including metadata and ecc info.
			 */
			struct persistent_ram_zone *tmp_prz, *prz_next;

			tmp_prz = kzalloc(sizeof(struct persistent_ram_zone),
					  GFP_KERNEL);
			if (!tmp_prz)
				return -ENOMEM;
			free_prz = true;

			while (cxt->ftrace_read_cnt < cxt->max_ftrace_cnt) {
				prz_next = ramoops_get_next_prz(cxt->fprzs,
						&cxt->ftrace_read_cnt,
						cxt->max_ftrace_cnt, id,
						type, PSTORE_TYPE_FTRACE, 0);

				if (!prz_ok(prz_next))
					continue;

				tmp_prz->ecc_info = prz_next->ecc_info;
				tmp_prz->corrected_bytes +=
						prz_next->corrected_bytes;
				tmp_prz->bad_blocks += prz_next->bad_blocks;
				size = ftrace_log_combine(tmp_prz, prz_next);
				if (size)
					goto out;
			}
			*id = 0;
			prz = tmp_prz;
		}
	}

	if (!prz_ok(prz)) {
		size = 0;
		goto out;
	}

	size = persistent_ram_old_size(prz) - header_length;

	/* ECC correction notice */
	*ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);

	*buf = kmalloc(size + *ecc_notice_size + 1, GFP_KERNEL);
	if (*buf == NULL) {
		size = -ENOMEM;
		goto out;
	}

	memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size);

	persistent_ram_ecc_string(prz, *buf + size, *ecc_notice_size + 1);

out:
	if (free_prz) {
		kfree(prz->old_log);
		kfree(prz);
	}

	return size;
}
예제 #18
0
static ssize_t ram_console_read_old(struct file *file, char __user *buf,
				    size_t len, loff_t *offset)
{
	loff_t pos = *offset;
	ssize_t count;
	struct persistent_ram_zone *prz = ram_console_zone;
	size_t old_log_size = persistent_ram_old_size(prz);
	const char *old_log = persistent_ram_old(prz);
	char *str;
	int ret;

	if (dmesg_restrict && !capable(CAP_SYSLOG))
		return -EPERM;

	/* Main last_kmsg log */
	if (pos < old_log_size) {
		count = min(len, (size_t)(old_log_size - pos));
		if (copy_to_user(buf, old_log + pos, count))
			return -EFAULT;
		goto out;
	}

	/* ECC correction notice */
	pos -= old_log_size;
	count = persistent_ram_ecc_string(prz, NULL, 0);
	if (pos < count) {
		str = kmalloc(count, GFP_KERNEL);
		if (!str)
			return -ENOMEM;
		persistent_ram_ecc_string(prz, str, count + 1);
		count = min(len, (size_t)(count - pos));
		ret = copy_to_user(buf, str + pos, count);
		kfree(str);
		str = NULL;
		if (ret)
			return -EFAULT;
		goto out;
	}

	/* bootreason label */
	pos -= count;
	count = 1 + snprintf(NULL, 0, bootreason_label, bi_bootreason());
	if (pos < count) {
		str = kmalloc(count, GFP_KERNEL);
		if (!str)
			return -ENOMEM;
		snprintf(str, count, bootreason_label, bi_bootreason());
		count = min(len, (size_t)(count - pos));
		ret = copy_to_user(buf, str + pos, count);
		kfree(str);
		if (ret)
			return -EFAULT;
		goto out;
	}

	/* Boot info passed through cmdline */
	pos -= count;
	if (pos < (bootinfo_size)) {
		count = min(len, (size_t)(bootinfo_size  - pos));
		if (copy_to_user(buf, bootinfo + pos, count))
			return -EFAULT;
		goto out;
	}

	/* EOF */
	return 0;

out:
	*offset += count;
	return count;
}