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_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; /* 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; }
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; }
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; }
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; }
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; }
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; }