Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f83b0a4e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull pstore changes from Tony Luck:
 "A big part of this is the addition of compression to the generic
  pstore layer so that all backends can use the pitiful amounts of
  storage they control more effectively.  Three other small
  fixes/cleanups too.

* tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux:
  pstore/ram: (really) fix undefined usage of rounddown_pow_of_two
  pstore/ram: Read and write to the 'compressed' flag of pstore
  efi-pstore: Read and write to the 'compressed' flag of pstore
  erst: Read and write to the 'compressed' flag of pstore
  powerpc/pseries: Read and write to the 'compressed' flag of pstore
  pstore: Add file extension to pstore file if compressed
  pstore: Add decompression support to pstore
  pstore: Introduce new argument 'compressed' in the read callback
  pstore: Add compression support to pstore
  pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected
  pstore: Add new argument 'compressed' in pstore write callback
  powerpc/pseries: Remove (de)compression in nvram with pstore enabled
  pstore: d_alloc_name() doesn't return an ERR_PTR
  acpi/apei/erst: Add missing iounmap() on error in erst_exec_move_data()
parents 32dad03d 3bd11cf5
Loading
Loading
Loading
Loading
+21 −91
Original line number Diff line number Diff line
@@ -539,36 +539,6 @@ static int zip_oops(size_t text_len)
}

#ifdef CONFIG_PSTORE
/* Derived from logfs_uncompress */
int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
{
	int err, ret;

	ret = -EIO;
	err = zlib_inflateInit(&stream);
	if (err != Z_OK)
		goto error;

	stream.next_in = in;
	stream.avail_in = inlen;
	stream.total_in = 0;
	stream.next_out = out;
	stream.avail_out = outlen;
	stream.total_out = 0;

	err = zlib_inflate(&stream, Z_FINISH);
	if (err != Z_STREAM_END)
		goto error;

	err = zlib_inflateEnd(&stream);
	if (err != Z_OK)
		goto error;

	ret = stream.total_out;
error:
	return ret;
}

static int nvram_pstore_open(struct pstore_info *psi)
{
	/* Reset the iterator to start reading partitions again */
@@ -584,7 +554,7 @@ static int nvram_pstore_open(struct pstore_info *psi)
 * @part:               pstore writes data to registered buffer in parts,
 *                      part number will indicate the same.
 * @count:              Indicates oops count
 * @hsize:              Size of header added by pstore
 * @compressed:         Flag to indicate the log is compressed
 * @size:               number of bytes written to the registered buffer
 * @psi:                registered pstore_info structure
 *
@@ -595,7 +565,7 @@ static int nvram_pstore_open(struct pstore_info *psi)
static int nvram_pstore_write(enum pstore_type_id type,
				enum kmsg_dump_reason reason,
				u64 *id, unsigned int part, int count,
				size_t hsize, size_t size,
				bool compressed, size_t size,
				struct pstore_info *psi)
{
	int rc;
@@ -611,30 +581,11 @@ static int nvram_pstore_write(enum pstore_type_id type,
	oops_hdr->report_length = (u16) size;
	oops_hdr->timestamp = get_seconds();

	if (big_oops_buf) {
		rc = zip_oops(size);
		/*
		 * If compression fails copy recent log messages from
		 * big_oops_buf to oops_data.
		 */
		if (rc != 0) {
			size_t diff = size - oops_data_sz + hsize;

			if (size > oops_data_sz) {
				memcpy(oops_data, big_oops_buf, hsize);
				memcpy(oops_data + hsize, big_oops_buf + diff,
					oops_data_sz - hsize);

				oops_hdr->report_length = (u16) oops_data_sz;
			} else
				memcpy(oops_data, big_oops_buf, size);
		} else
	if (compressed)
		err_type = ERR_TYPE_KERNEL_PANIC_GZ;
	}

	rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
		(int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
		count);
		(int) (sizeof(*oops_hdr) + size), err_type, count);

	if (rc != 0)
		return rc;
@@ -650,12 +601,12 @@ static int nvram_pstore_write(enum pstore_type_id type,
 */
static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
				int *count, struct timespec *time, char **buf,
				struct pstore_info *psi)
				bool *compressed, struct pstore_info *psi)
{
	struct oops_log_info *oops_hdr;
	unsigned int err_type, id_no, size = 0;
	struct nvram_os_partition *part = NULL;
	char *buff = NULL, *big_buff = NULL;
	char *buff = NULL;
	int sig = 0;
	loff_t p;

@@ -719,8 +670,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
		*id = id_no;

	if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
		int length, unzipped_len;
		size_t hdr_size;
		size_t length, hdr_size;

		oops_hdr = (struct oops_log_info *)buff;
		if (oops_hdr->version < OOPS_HDR_VERSION) {
@@ -741,23 +691,10 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
		memcpy(*buf, buff + hdr_size, length);
		kfree(buff);

		if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
			big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
			if (!big_buff)
				return -ENOMEM;

			unzipped_len = nvram_decompress(*buf, big_buff,
						length, big_oops_buf_sz);

			if (unzipped_len < 0) {
				pr_err("nvram: decompression failed, returned "
					"rc %d\n", unzipped_len);
				kfree(big_buff);
			} else {
				*buf = big_buff;
				length = unzipped_len;
			}
		}
		if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
			*compressed = true;
		else
			*compressed = false;
		return length;
	}

@@ -777,13 +714,8 @@ static int nvram_pstore_init(void)
{
	int rc = 0;

	if (big_oops_buf) {
		nvram_pstore_info.buf = big_oops_buf;
		nvram_pstore_info.bufsize = big_oops_buf_sz;
	} else {
	nvram_pstore_info.buf = oops_data;
	nvram_pstore_info.bufsize = oops_data_sz;
	}

	rc = pstore_register(&nvram_pstore_info);
	if (rc != 0)
@@ -802,7 +734,6 @@ static int nvram_pstore_init(void)
static void __init nvram_init_oops_partition(int rtas_partition_exists)
{
	int rc;
	size_t size;

	rc = pseries_nvram_init_os_partition(&oops_log_partition);
	if (rc != 0) {
@@ -823,6 +754,11 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
	oops_data = oops_buf + sizeof(struct oops_log_info);
	oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);

	rc = nvram_pstore_init();

	if (!rc)
		return;

	/*
	 * Figure compression (preceded by elimination of each line's <n>
	 * severity prefix) will reduce the oops/panic report to at most
@@ -831,9 +767,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
	big_oops_buf_sz = (oops_data_sz * 100) / 45;
	big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
	if (big_oops_buf) {
		size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
			zlib_inflate_workspacesize());
		stream.workspace = kmalloc(size, GFP_KERNEL);
		stream.workspace =  kmalloc(zlib_deflate_workspacesize(
					WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
		if (!stream.workspace) {
			pr_err("nvram: No memory for compression workspace; "
				"skipping compression of %s partition data\n",
@@ -847,11 +782,6 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
		stream.workspace = NULL;
	}

	rc = nvram_pstore_init();

	if (!rc)
		return;

	rc = kmsg_dump_register(&nvram_kmsg_dumper);
	if (rc != 0) {
		pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
+19 −6
Original line number Diff line number Diff line
@@ -284,8 +284,10 @@ static int erst_exec_move_data(struct apei_exec_context *ctx,
	if (!src)
		return -ENOMEM;
	dst = ioremap(ctx->dst_base + offset, ctx->var2);
	if (!dst)
	if (!dst) {
		iounmap(src);
		return -ENOMEM;
	}

	memmove(dst, src, ctx->var2);

@@ -933,9 +935,9 @@ static int erst_open_pstore(struct pstore_info *psi);
static int erst_close_pstore(struct pstore_info *psi);
static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
			   struct timespec *time, char **buf,
			   struct pstore_info *psi);
			   bool *compressed, struct pstore_info *psi);
static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
		       u64 *id, unsigned int part, int count, size_t hsize,
		       u64 *id, unsigned int part, int count, bool compressed,
		       size_t size, struct pstore_info *psi);
static int erst_clearer(enum pstore_type_id type, u64 id, int count,
			struct timespec time, struct pstore_info *psi);
@@ -956,6 +958,9 @@ static struct pstore_info erst_info = {
#define CPER_SECTION_TYPE_DMESG						\
	UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54,	\
		0x94, 0x19, 0xeb, 0x12)
#define CPER_SECTION_TYPE_DMESG_Z					\
	UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d,	\
		0x34, 0xdd, 0xfa, 0xc6)
#define CPER_SECTION_TYPE_MCE						\
	UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96,	\
		0x04, 0x4a, 0x38, 0xfc)
@@ -989,7 +994,7 @@ static int erst_close_pstore(struct pstore_info *psi)

static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
			   struct timespec *time, char **buf,
			   struct pstore_info *psi)
			   bool *compressed, struct pstore_info *psi)
{
	int rc;
	ssize_t len = 0;
@@ -1034,7 +1039,12 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
	}
	memcpy(*buf, rcd->data, len - sizeof(*rcd));
	*id = record_id;
	*compressed = false;
	if (uuid_le_cmp(rcd->sec_hdr.section_type,
			CPER_SECTION_TYPE_DMESG_Z) == 0) {
		*type = PSTORE_TYPE_DMESG;
		*compressed = true;
	} else if (uuid_le_cmp(rcd->sec_hdr.section_type,
			CPER_SECTION_TYPE_DMESG) == 0)
		*type = PSTORE_TYPE_DMESG;
	else if (uuid_le_cmp(rcd->sec_hdr.section_type,
@@ -1055,7 +1065,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
}

static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
		       u64 *id, unsigned int part, int count, size_t hsize,
		       u64 *id, unsigned int part, int count, bool compressed,
		       size_t size, struct pstore_info *psi)
{
	struct cper_pstore_record *rcd = (struct cper_pstore_record *)
@@ -1085,6 +1095,9 @@ static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
	rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
	switch (type) {
	case PSTORE_TYPE_DMESG:
		if (compressed)
			rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG_Z;
		else
			rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
		break;
	case PSTORE_TYPE_MCE:
+21 −6
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ struct pstore_read_data {
	enum pstore_type_id *type;
	int *count;
	struct timespec *timespec;
	bool *compressed;
	char **buf;
};

@@ -42,7 +43,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
{
	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
	struct pstore_read_data *cb_data = data;
	char name[DUMP_NAME_LEN];
	char name[DUMP_NAME_LEN], data_type;
	int i;
	int cnt;
	unsigned int part;
@@ -54,12 +55,23 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
	for (i = 0; i < DUMP_NAME_LEN; i++)
		name[i] = entry->var.VariableName[i];

	if (sscanf(name, "dump-type%u-%u-%d-%lu",
	if (sscanf(name, "dump-type%u-%u-%d-%lu-%c",
		   cb_data->type, &part, &cnt, &time, &data_type) == 5) {
		*cb_data->id = part;
		*cb_data->count = cnt;
		cb_data->timespec->tv_sec = time;
		cb_data->timespec->tv_nsec = 0;
		if (data_type == 'C')
			*cb_data->compressed = true;
		else
			*cb_data->compressed = false;
	} else if (sscanf(name, "dump-type%u-%u-%d-%lu",
		   cb_data->type, &part, &cnt, &time) == 4) {
		*cb_data->id = part;
		*cb_data->count = cnt;
		cb_data->timespec->tv_sec = time;
		cb_data->timespec->tv_nsec = 0;
		*cb_data->compressed = false;
	} else if (sscanf(name, "dump-type%u-%u-%lu",
			  cb_data->type, &part, &time) == 3) {
		/*
@@ -71,6 +83,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
		*cb_data->count = 0;
		cb_data->timespec->tv_sec = time;
		cb_data->timespec->tv_nsec = 0;
		*cb_data->compressed = false;
	} else
		return 0;

@@ -87,7 +100,8 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)

static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
			       int *count, struct timespec *timespec,
			       char **buf, struct pstore_info *psi)
			       char **buf, bool *compressed,
			       struct pstore_info *psi)
{
	struct pstore_read_data data;

@@ -95,6 +109,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
	data.type = type;
	data.count = count;
	data.timespec = timespec;
	data.compressed = compressed;
	data.buf = buf;

	return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data,
@@ -103,7 +118,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,

static int efi_pstore_write(enum pstore_type_id type,
		enum kmsg_dump_reason reason, u64 *id,
		unsigned int part, int count, size_t hsize, size_t size,
		unsigned int part, int count, bool compressed, size_t size,
		struct pstore_info *psi)
{
	char name[DUMP_NAME_LEN];
@@ -111,8 +126,8 @@ static int efi_pstore_write(enum pstore_type_id type,
	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
	int i, ret = 0;

	sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count,
		get_seconds());
	sprintf(name, "dump-type%u-%u-%d-%lu-%c", type, part, count,
		get_seconds(), compressed ? 'C' : 'D');

	for (i = 0; i < DUMP_NAME_LEN; i++)
		efi_name[i] = name[i];
+2 −0
Original line number Diff line number Diff line
config PSTORE
	bool "Persistent store support"
	default n
	select ZLIB_DEFLATE
	select ZLIB_INFLATE
	help
	   This option enables generic access to platform level
	   persistent storage via "pstore" filesystem that can
+5 −5
Original line number Diff line number Diff line
@@ -275,8 +275,8 @@ int pstore_is_mounted(void)
 * Set the mtime & ctime to the date that this record was originally stored.
 */
int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
		  char *data, size_t size, struct timespec time,
		  struct pstore_info *psi)
		  char *data, bool compressed, size_t size,
		  struct timespec time, struct pstore_info *psi)
{
	struct dentry		*root = pstore_sb->s_root;
	struct dentry		*dentry;
@@ -315,7 +315,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,

	switch (type) {
	case PSTORE_TYPE_DMESG:
		sprintf(name, "dmesg-%s-%lld", psname, id);
		sprintf(name, "dmesg-%s-%lld%s", psname, id,
						compressed ? ".enc.z" : "");
		break;
	case PSTORE_TYPE_CONSOLE:
		sprintf(name, "console-%s", psname);
@@ -345,9 +346,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,

	mutex_lock(&root->d_inode->i_mutex);

	rc = -ENOSPC;
	dentry = d_alloc_name(root, name);
	if (IS_ERR(dentry))
	if (!dentry)
		goto fail_lockedalloc;

	memcpy(private->data, data, size);
Loading