[PATCH v2] pstore: Adjust buffer size for compression for smaller registered buffers
When backends (ex: efivars) have smaller registered buffers, the big_oops_buf is quite too big for them as number of repeated occurences in the text captured will be less. Patch takes care of adjusting the buffer size based on the registered buffer size. cmpr values has been arrived after doing experiments with plain text for buffers of size 1k - 4k (Smaller the buffer size repeated occurence will be less) and with sample crash log for buffers ranging from 4k - 10k. Reported-by: Seiji Aguchi seiji.agu...@hds.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- Changes from v1: Retain the cmpr = 45 for buffers ranging of size 4k - 10k. 45 seems to work. I added an additional headroom of 3%. Revert it back to 45. fs/pstore/platform.c | 23 ++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 4ffb7ab..57b4219 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -195,8 +195,29 @@ error: static void allocate_buf_for_compression(void) { size_t size; + size_t cmpr; + + switch (psinfo-bufsize) { + /* buffer range for efivars */ + case 1000 ... 2000: + cmpr = 56; + break; + case 2001 ... 3000: + cmpr = 54; + break; + case 3001 ... 3999: + cmpr = 52; + break; + /* buffer range for nvram, erst */ + case 4000 ... 1: + cmpr = 45; + break; + default: + cmpr = 60; + break; + } - big_oops_buf_sz = (psinfo-bufsize * 100) / 45; + big_oops_buf_sz = (psinfo-bufsize * 100) / cmpr; big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); if (big_oops_buf) { size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL), ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v2] pstore: Adjust buffer size for compression for smaller registered buffers
On Thursday 12 September 2013 11:13 PM, Luck, Tony wrote: + default: + cmpr = 60; + break; + } Is this the right default? It may be a good choice for a backend with a really tiny buffer (1 ... 999). But less good for a (theoretical) backend with a larger buffer (10001 ... infinity and beyond). Which are you trying to catch here? Trying to catch lower buffers and also tried till 23k ( 10k * 100/45) of text with a sample crash logit achieved a good compression of 25%. Since the upper limit is not known and compression behavior is not tested above 10k chose to keep a higher default of 60. -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 1/3] pstore: Adjust buffer size for compression for smaller registered buffers
When backends (ex: efivars) have smaller registered buffers, the big_oops_buf is quite too big for them as number of repeated occurences in the text captured will be less. Patch takes care of adjusting the buffer size based on the registered buffer size. cmpr values has been arrived after doing experiments with plain text for buffers of size 1k - 4k (Smaller the buffer size repeated occurence will be less) and with sample crash log for buffers ranging from 4k - 10k. Reported-by: Seiji Aguchi seiji.agu...@hds.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c | 23 ++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 4ffb7ab..4efaa75 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -195,8 +195,29 @@ error: static void allocate_buf_for_compression(void) { size_t size; + size_t cmpr; + + switch (psinfo-bufsize) { + /* buffer range for efivars */ + case 1000 ... 2000: + cmpr = 56; + break; + case 2001 ... 3000: + cmpr = 54; + break; + case 3001 ... 3999: + cmpr = 52; + break; + /* buffer range for nvram, erst */ + case 4000 ... 1: + cmpr = 48; + break; + default: + cmpr = 60; + break; + } - big_oops_buf_sz = (psinfo-bufsize * 100) / 45; + big_oops_buf_sz = (psinfo-bufsize * 100) / cmpr; big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); if (big_oops_buf) { size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL), ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/3] pstore: Use zlib_inflateInit2 instead of zlib_inflateInit
Since zlib_deflateInit2() is used for specifying window bit during compression, zlib_inflateInit2() is appropriate for decompression. Reported-by: Seiji Aguchi seiji.agu...@hds.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 4efaa75..18924c7 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -168,7 +168,7 @@ static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen) int err, ret; ret = -EIO; - err = zlib_inflateInit(stream); + err = zlib_inflateInit2(stream, WINDOW_BITS); if (err != Z_OK) goto error; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [RFC PATCH v2 04/11] pstore: Add compression support to pstore
On Wednesday 04 September 2013 07:14 AM, Seiji Aguchi wrote: Aruna, Sorry for the late response. Seiji, Could you let us know the efivars buffer size with which the pstore is registered when the failure occurred. I looked into the issue today. I added some debug message just before pstore_compress(). As you can see below, the buffer size is a fixed value(1024). Therefore, the size doesn't seem to be related to the failure directly. Also, in the failure case, zlib_deflate() returns Z_OK and stream.avail_out is zero. So, I thought big_oops_buf_sz is too big in my environment. And then, I tuned big_oops_buf_sz to (psinfo-bufsize * 100) / 53. Seiji, Thank you for the analysis. The reason behind compression failure is the size of big_oops_buf which is too big for efivars case. I will do some experiments with different kind of texts for buffer size 1024 to check if 100/53 suits for all the cases. At the same time, while looking into this issue, I had two concerns about current cording. 1) In pstore_decompress(), why not use zlib_inflateInit2() instead of zlib_inflateInit()? If you use zlib_deflateInit2() for specifying window_bit at compressing time, zlib_inflateInit2() seems to be appropriate for decompressing. (Please see a comment about inflateInit2() in include/linux/zlib.h and source code of crypto/deflate.c) Yes this can be changed to zlib_inflateInit2(). 2) As looking at crypto/deflate.c, stream-workspace is kzalloced at the beginning of compressing/decompressing time. So, in pstore case, stream.workspace must be initialized to 0 with memset() in pstore_compress()/decompress(). Hmm.. I don't think this is a issue. If you see fs/logfs/compr.c from which I derived the compression algorithms for pstore as well, they have not initialized stream.workspace. Since the space will be overwritten during the calculation, I dont think it will matter. The above 2 things you have suggested are good to have. But the reason behind compression failure is the big_oops_buf_sz which is too big for efivars. I did three things above, tuning big_oops_buf_sz, using zlib_inflateInit2() and initializing stream.workspace , in my environment. As a result, compressions/decmpressions of all entries succeeded with efivars driver. snip Panic#2 Part1 4[ 75.665020] [811af59c] SyS_write+0x4c/0xa0 4[ 75.665020] [8168be82] system_call_fastpath+0x16/0x1b 4[ 75.665020] Code: ef e8 ff f7 ff ff eb d8 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 0f 1f 44 00 00 55 c7 05 cc f3 c9 00 01 00 00 00 48 89 e5 0f ae f8 c6 04 25 00 00 00 00 01 5d c3 0f 1f 44 00 00 55 31 c0 c7 05 5e 1[ 75.665020] RIP [813d3946] sysrq_handle_crash+0x16/0x20 4[ 75.665020] RSP 88007852de80 4[ 75.665020] CR2: 4[ 75.665020] ---[ end trace 97bb4a1f8d3fe7b2 ]--- 3[ 75.665020] pstore_dump hsize=13 len=2155 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=13 len=2246 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore: compression failed for Part 2 returned -5 3[ 75.665020] pstore: Capture uncompressed oops/panic report of Part 2 3[ 75.665020] pstore_dump hsize=13 len=2239 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=13 len=2231 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=13 len=2185 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore: compression failed for Part 5 returned -5 3[ 75.665020] pstore: Capture uncompressed oops/panic report of Part 5 3[ 75.665020] pstore_dump hsize=13 len=2234 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=13 len=2208 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=13 len=2218 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=13 len= big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore: compression failed for Part 9 returned -5 3[ 75.665020] pstore: Capture uncompressed oops/panic report of Part 9 3[ 75.665020] pstore_dump hsize=14 len=2256 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=14 len=2219 big_oops_buf_sz=2275 psinfo-bufsize=1024 3[ 75.665020] pstore_dump hsize=14 len=2226 big_oops_buf_sz=2275 psinfo-bufsize=1024 0[ 75.665020] Kernel panic - not syncing: Fatal exception 3[ 75.665020] drm_kms_helper: panic occurred, switching back to text console snip Seiji ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [RFC PATCH v2 06/11] pstore: Add decompression support to pstore
On Friday 23 August 2013 04:34 AM, Seiji Aguchi wrote: -Original Message- From: linux-kernel-ow...@vger.kernel.org [mailto:linux-kernel-ow...@vger.kernel.org] On Behalf Of Aruna Balakrishnaiah Sent: Friday, August 16, 2013 9:18 AM To: linuxppc-...@ozlabs.org; tony.l...@intel.com; linux-ker...@vger.kernel.org; keesc...@chromium.org Cc: jkeni...@linux.vnet.ibm.com; ana...@in.ibm.com; b...@kernel.crashing.org; cbouatmai...@gmail.com; mah...@linux.vnet.ibm.com; ccr...@android.com Subject: [RFC PATCH v2 06/11] pstore: Add decompression support to pstore Based on the flag 'compressed' set or not, pstore will decompress the data returning a plain text file. If decompression fails for a particular record it will have the compressed data in the file which can be decompressed with 'openssl' command line tool. If the decompression fails and openssl doesn't work, the worst case is that users can't read the entry. In that case, pstore is meaningless at all. If decompression fails and openssl doesn't work. We have python module zlib to decompress the zlib data. zlib.decompress() should do the trick. Also, for users who want to get a single panic message, a compression is not needed. So, I think we still have to support non-compression mode. (IMO, pstore can take kdump as a model. Kdump supports both compression and non-compression mode.) But, if you think my comment is outside this patchset, it's OK. We can make it with a separate patch. Seiji ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [RFC PATCH v2 04/11] pstore: Add compression support to pstore
On Friday 23 August 2013 04:47 AM, Luck, Tony wrote: 1[ 383.209057] RIP [813d3946] sysrq_handle_crash+0x16/0x20 4[ 383.209057] RSP 88006f551e80 4[ 383.209057] CR2: 4[ 383.209057] ---[ end trace 04a1cddad37b4b33 ]--- 3[ 383.209057] pstore: compression failed for Part 2 returned -5 3[ 383.209057] pstore: Capture uncompressed oops/panic report of Part 2 3[ 383.209057] pstore: compression failed for Part 5 returned -5 Interesting. With ERST backend I didn't see these messages. Traces in pstore recovered files go as far as the line before the ---[ end trace 04a1cddad37b4b33 ]--- Why the difference depending on which back end is in use? But I agree that we shouldn't have these messages. They use up space in the persistent store that could be better used saving some more lines from earlier in the console log. Yeah. We can remove these messages as it will add to the space consumed. But it would be good to know why the compression failed with efivars case. Seiji, Could you let us know the efivars buffer size with which the pstore is registered when the failure occurred. Regards, Aruna -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 00/11] Add (de)compression support to pstore
Changes from v1: - Allocate compression workspace during initialisation as per Tony's suggestion - Copy the recent messages from big_oops_buf to psinfo-buf when compression fails, since the printk buffer would be fetched for compression calling it again when compression fails would have moved the iterator of printk buffer which results in fetching old contents. The patchset adds compression and decompression support to pstore. As the non-volatile storage space is limited, adding compression support results in capturing more data within limited space. Size of dmesg file in a powerpc/pseries box with nvram's oops partition (to store oops-log) size 4k: Without compression: dmesg-nvram-1: ~ 4k (3980) WIth compression: dmesg-nvram-1: ~8.8k (8844) Writing to persistent store Compression will reduce the size of oops/panic report to atmost 45% of its original size. (Based on experiments done while providing compression support to nvram by Jim keniston). Hence buffer of size ( (100/45 approx 2.22) *registered_buffer is allocated). The compression parameters selected based on some experiments: compression_level = 6, window_bits = 12, memory_level = 4 achieved a significant compression. Data is compressed from the bigger buffer to registered buffer which is returned to backends. Pstore will indicate that with a flag 'compressed' which is passed to backends. Using this flag, backends will add a flag in their header to indicate the data is compressed or not while writing to persistent store. Reading from persistent store - When backends read data from persistent store it will use the flag added by it while writing to persistent store to determine if the data is compressed or not. Using the information, it will set the flag in pstore's read call back. Pstore will decompress the data based on the flag and writes decompressed data to the file. Test results: Have tested the patches on powerpc/pseries. Needs testing with erst backend, efivars and persistent ram. --- Aruna Balakrishnaiah (11): powerpc/pseries: Remove (de)compression in nvram with pstore enabled pstore: Add new argument 'compressed' in pstore write callback pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected pstore: Add compression support to pstore pstore: Introduce new argument 'compressed' in the read callback pstore: Add decompression support to pstore pstore: Add file extension to pstore file if compressed powerpc/pseries: Read and write to the 'compressed' flag of pstore erst: Read and write to the 'compressed' flag of pstore efi-pstore: Read and write to the 'compressed' flag of pstore pstore/ram: Read and write to the 'compressed' flag of pstore arch/powerpc/platforms/pseries/nvram.c | 112 +++-- drivers/acpi/apei/erst.c | 21 ++- drivers/firmware/efi/efi-pstore.c | 27 +++- fs/pstore/Kconfig |2 fs/pstore/inode.c |7 + fs/pstore/internal.h |5 - fs/pstore/platform.c | 212 ++-- fs/pstore/ram.c| 41 +- include/linux/pstore.h |6 - 9 files changed, 299 insertions(+), 134 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 01/11] powerpc/pseries: Remove (de)compression in nvram with pstore enabled
(De)compression support is provided in pstore in subsequent patches which needs an additional argument 'compressed' to determine if the data is compressed or not. This patch will take care of removing (de)compression in nvram with pstore which was making use of 'hsize' argument in pstore write as 'hsize' will be removed in the subsequent patch. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 102 1 file changed, 12 insertions(+), 90 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 6a5f2b1..b966458 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -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 */ @@ -611,30 +581,8 @@ 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 - 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; @@ -655,7 +603,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, 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 +667,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) { @@ -740,24 +687,6 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, return -ENOMEM; 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; - } - } return length; } @@ -777,13 +706,8 @@ static int nvram_pstore_init(void) { int rc = 0; - if (big_oops_buf) { - nvram_pstore_info.buf = big_oops_buf
[RFC PATCH v2 03/11] pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected
Pstore will make use of deflate and inflate algorithm to compress and decompress the data. So when Pstore is enabled select zlib_deflate and zlib_inflate. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/Kconfig |2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index ca71db6..983d951 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -1,6 +1,8 @@ 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 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 02/11] pstore: Add new argument 'compressed' in pstore write callback
Addition of new argument 'compressed' in the write call back will help the backend to know if the data passed from pstore is compressed or not (In case where compression fails.). If compressed, the backend can add a tag indicating the data is compressed while writing to persistent store. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |4 ++-- drivers/acpi/apei/erst.c |4 ++-- drivers/firmware/efi/efi-pstore.c |2 +- fs/pstore/platform.c |7 --- fs/pstore/ram.c|2 +- include/linux/pstore.h |4 ++-- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index b966458..dbe5dad 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -554,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 * @@ -565,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; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 88d0b0f..5e90796 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -935,7 +935,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, 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); @@ -1055,7 +1055,7 @@ out: } 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 *) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 73de5a9..fab6892 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -103,7 +103,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]; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 422962a..20fa686 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -149,6 +149,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long size; int hsize; size_t len; + bool compressed = false; dst = psinfo-buf; hsize = sprintf(dst, %s#%d Part%d\n, why, oopscount, part); @@ -159,7 +160,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, break; ret = psinfo-write(PSTORE_TYPE_DMESG, reason, id, part, - oopscount, hsize, hsize + len, psinfo); + oopscount, compressed, hsize + len, psinfo); if (ret == 0 reason == KMSG_DUMP_OOPS pstore_is_mounted()) pstore_new_entry = 1; @@ -221,10 +222,10 @@ static void pstore_register_console(void) {} static int pstore_write_compat(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, - size_t hsize, size_t size
[RFC PATCH v2 04/11] pstore: Add compression support to pstore
Add compression support to pstore which will help in capturing more data. Initially, pstore will make a call to kmsg_dump with a bigger buffer and will pass the size of bigger buffer to kmsg_dump and then compress the data to registered buffer of registered size. In case compression fails, pstore will capture the uncompressed data by making a call again to kmsg_dump with registered_buffer of registered size. Pstore will indicate the data is compressed or not with a flag in the write callback. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c | 148 +++--- 1 file changed, 139 insertions(+), 9 deletions(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 20fa686..56218cb 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -26,6 +26,7 @@ #include linux/console.h #include linux/module.h #include linux/pstore.h +#include linux/zlib.h #include linux/string.h #include linux/timer.h #include linux/slab.h @@ -65,6 +66,15 @@ struct pstore_info *psinfo; static char *backend; +/* Compression parameters */ +#define COMPR_LEVEL 6 +#define WINDOW_BITS 12 +#define MEM_LEVEL 4 +static struct z_stream_s stream; + +static char *big_oops_buf; +static size_t big_oops_buf_sz; + /* How much of the console log to snapshot */ static unsigned long kmsg_bytes = 10240; @@ -117,6 +127,91 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason) } EXPORT_SYMBOL_GPL(pstore_cannot_block_path); +/* Derived from logfs_compress() */ +static int pstore_compress(const void *in, void *out, size_t inlen, + size_t outlen) +{ + int err, ret; + + ret = -EIO; + err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, + MEM_LEVEL, Z_DEFAULT_STRATEGY); + 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_deflate(stream, Z_FINISH); + if (err != Z_STREAM_END) + goto error; + + err = zlib_deflateEnd(stream); + if (err != Z_OK) + goto error; + + if (stream.total_out = stream.total_in) + goto error; + + ret = stream.total_out; +error: + return ret; +} + +static void allocate_buf_for_compression(void) +{ + size_t size; + + big_oops_buf_sz = (psinfo-bufsize * 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); + if (!stream.workspace) { + pr_err(pstore: No memory for compression workspace; + skipping compression\n); + kfree(big_oops_buf); + big_oops_buf = NULL; + } + } else { + pr_err(No memory for uncompressed data; + skipping compression\n); + stream.workspace = NULL; + } + +} + +/* + * Called when compression fails, since the printk buffer + * would be fetched for compression calling it again when + * compression fails would have moved the iterator of + * printk buffer which results in fetching old contents. + * Copy the recent messages from big_oops_buf to psinfo-buf + */ +static size_t copy_kmsg_to_buffer(int hsize, size_t len) +{ + size_t total_len; + size_t diff; + + total_len = hsize + len; + + if (total_len psinfo-bufsize) { + diff = total_len - psinfo-bufsize + hsize; + memcpy(psinfo-buf, big_oops_buf, hsize); + memcpy(psinfo-buf + hsize, big_oops_buf + diff, + psinfo-bufsize - hsize); + total_len = psinfo-bufsize; + } else + memcpy(psinfo-buf, big_oops_buf, total_len); + + return total_len; +} + /* * callback from kmsg_dump. (s2,l2) has the most recently * written bytes, older bytes are in (s1,l1). Save as much @@ -148,23 +243,56 @@ static void pstore_dump(struct kmsg_dumper *dumper, char *dst; unsigned long size; int hsize; + int zipped_len = -1; size_t len; - bool compressed = false; + bool compressed; + size_t total_len; - dst = psinfo-buf; - hsize = sprintf(dst, %s#%d Part%d\n, why, oopscount, part); - size = psinfo-bufsize - hsize; - dst += hsize; + if (big_oops_buf) { + dst = big_oops_buf
[RFC PATCH v2 05/11] pstore: Introduce new argument 'compressed' in the read callback
Backends will set the flag 'compressed' after reading the log from persistent store to indicate the data being returned to pstore is compressed or not. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |2 +- drivers/acpi/apei/erst.c |4 ++-- drivers/firmware/efi/efi-pstore.c |3 ++- fs/pstore/platform.c |4 +++- fs/pstore/ram.c|3 ++- include/linux/pstore.h |2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index dbe5dad..6c4dc52a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -598,7 +598,7 @@ 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; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 5e90796..b0dca8e 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -933,7 +933,7 @@ 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, bool compressed, size_t size, struct pstore_info *psi); @@ -989,7 +989,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; diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index fab6892..9a5425f 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -87,7 +87,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; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 56218cb..6418eb7 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -428,6 +428,7 @@ void pstore_get_records(int quiet) enum pstore_type_id type; struct timespec time; int failed = 0, rc; + boolcompressed; if (!psi) return; @@ -436,7 +437,8 @@ void pstore_get_records(int quiet) if (psi-open psi-open(psi)) goto out; - while ((size = psi-read(id, type, count, time, buf, psi)) 0) { + while ((size = psi-read(id, type, count, time, buf, compressed, + psi)) 0) { rc = pstore_mkfile(type, psi-name, id, count, buf, (size_t)size, time, psi); kfree(buf); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fe7188f..2927223 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -133,7 +133,8 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, - char **buf, struct pstore_info *psi) + char **buf, bool *compressed, + struct pstore_info *psi) { ssize_t size; ssize_t ecc_notice_size; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index abfca4f..abd437d 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -55,7 +55,7 @@ struct pstore_info { int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, - struct pstore_info *psi
[RFC PATCH v2 06/11] pstore: Add decompression support to pstore
Based on the flag 'compressed' set or not, pstore will decompress the data returning a plain text file. If decompression fails for a particular record it will have the compressed data in the file which can be decompressed with 'openssl' command line tool. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c | 53 -- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 6418eb7..0195cca0 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -162,6 +162,36 @@ error: return ret; } +/* Derived from logfs_uncompress */ +int pstore_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 void allocate_buf_for_compression(void) { size_t size; @@ -429,6 +459,7 @@ void pstore_get_records(int quiet) struct timespec time; int failed = 0, rc; boolcompressed; + int unzipped_len = -1; if (!psi) return; @@ -439,10 +470,28 @@ void pstore_get_records(int quiet) while ((size = psi-read(id, type, count, time, buf, compressed, psi)) 0) { + if (compressed (type == PSTORE_TYPE_DMESG)) { + if (big_oops_buf) + unzipped_len = pstore_decompress(buf, + big_oops_buf, size, + big_oops_buf_sz); + + if (unzipped_len 0) { + buf = big_oops_buf; + size = unzipped_len; + } else { + pr_err(pstore: decompression failed; + returned %d\n, unzipped_len); + } + } rc = pstore_mkfile(type, psi-name, id, count, buf, (size_t)size, time, psi); - kfree(buf); - buf = NULL; + if (unzipped_len 0) { + /* Free buffer other than big oops */ + kfree(buf); + buf = NULL; + } else + unzipped_len = -1; if (rc (rc != -EEXIST || !quiet)) failed++; } ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 09/11] erst: Read and write to the 'compressed' flag of pstore
In pstore write, set the section type to CPER_SECTION_TYPE_DMESG_COMPR if the data is compressed. In pstore read, read the section type and update the 'compressed' flag accordingly. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- drivers/acpi/apei/erst.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index b0dca8e..62df189 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -956,6 +956,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) @@ -1034,7 +1037,12 @@ skip: } 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, @@ -1085,7 +1093,10 @@ 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: - rcd-sec_hdr.section_type = CPER_SECTION_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: rcd-sec_hdr.section_type = CPER_SECTION_TYPE_MCE; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 11/11] pstore/ram: Read and write to the 'compressed' flag of pstore
In pstore write, add character 'C'(compressed) or 'D'(decompressed) in the header while writing to Ram persistent buffer. In pstore read, read the header and update the 'compressed' flag accordingly. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/ram.c | 36 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 2927223..4027c20 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -131,6 +131,27 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, return prz; } +static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time, + bool *compressed) +{ + char data_type; + + if (sscanf(buffer, RAMOOPS_KERNMSG_HDR %lu.%lu-%c\n, + time-tv_sec, time-tv_nsec, data_type) == 3) { + if (data_type == 'C') + *compressed = true; + else + *compressed = false; + } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR %lu.%lu\n, + time-tv_sec, time-tv_nsec) == 2) { + *compressed = false; + } else { + time-tv_sec = 0; + time-tv_nsec = 0; + *compressed = false; + } +} + static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, bool *compressed, @@ -153,10 +174,6 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 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); /* ECC correction notice */ @@ -167,12 +184,14 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 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; } -static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) +static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz, +bool compressed) { char *hdr; struct timespec timestamp; @@ -183,8 +202,9 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) timestamp.tv_sec = 0; timestamp.tv_nsec = 0; } - hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR %lu.%lu\n, - (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000)); + hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR %lu.%lu-%c\n, + (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000), + compressed ? 'C' : 'D'); WARN_ON_ONCE(!hdr); len = hdr ? strlen(hdr) : 0; persistent_ram_write(prz, hdr, len); @@ -243,7 +263,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, prz = cxt-przs[cxt-dump_write_cnt]; - hlen = ramoops_write_kmsg_hdr(prz); + hlen = ramoops_write_kmsg_hdr(prz, compressed); if (size + hlen prz-buffer_size) size = prz-buffer_size - hlen; persistent_ram_write(prz, buf, size); ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 10/11] efi-pstore: Read and write to the 'compressed' flag of pstore
In pstore write, Efi will add a character 'C'(compressed) or D'(decompressed) in its header while writing to persistent store. In pstore read, read the header and update the 'compressed' flag accordingly. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- drivers/firmware/efi/efi-pstore.c | 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 9a5425f..5002d50 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -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; @@ -96,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, @@ -112,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]; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 08/11] powerpc/pseries: Read and write to the 'compressed' flag of pstore
If data returned from pstore is compressed, nvram's write callback will add a flag ERR_TYPE_KERNEL_PANIC_GZ indicating the data is compressed while writing to nvram. If the data read from nvram is compressed, nvram's read callback will set the flag 'compressed'. The patch adds backward compatibilty with old format oops header when reading from pstore. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |8 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 6c4dc52a..d276cd3 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -581,6 +581,9 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-report_length = (u16) size; oops_hdr-timestamp = get_seconds(); + if (compressed) + err_type = ERR_TYPE_KERNEL_PANIC_GZ; + rc = nvram_write_os_partition(oops_log_partition, oops_buf, (int) (sizeof(*oops_hdr) + size), err_type, count); @@ -687,6 +690,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, return -ENOMEM; memcpy(*buf, buff + hdr_size, length); kfree(buff); + + if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) + *compressed = true; + else + *compressed = false; return length; } ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[RFC PATCH v2 07/11] pstore: Add file extension to pstore file if compressed
In case decompression fails, add a .enc.z to indicate the file has compressed data. This will help user space utilities to figure out the file contents. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/inode.c|7 --- fs/pstore/internal.h |5 +++-- fs/pstore/platform.c |4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 71bf5f4..519d278 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -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); diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 937d820..3b3d305 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -50,8 +50,9 @@ extern struct pstore_info *psinfo; extern voidpstore_set_kmsg_bytes(int); extern voidpstore_get_records(int); extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, - int count, char *data, size_t size, - struct timespec time, struct pstore_info *psi); + int count, char *data, bool compressed, + size_t size, struct timespec time, + struct pstore_info *psi); extern int pstore_is_mounted(void); #endif diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 0195cca0..cf0b53f 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -479,13 +479,15 @@ void pstore_get_records(int quiet) if (unzipped_len 0) { buf = big_oops_buf; size = unzipped_len; + compressed = false; } else { pr_err(pstore: decompression failed; returned %d\n, unzipped_len); + compressed = true; } } rc = pstore_mkfile(type, psi-name, id, count, buf, - (size_t)size, time, psi); + compressed, (size_t)size, time, psi); if (unzipped_len 0) { /* Free buffer other than big oops */ kfree(buf); ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 00/11] Add compression support to pstore
On Thursday 08 August 2013 09:38 AM, Aruna Balakrishnaiah wrote: Hi Tony, On Thursday 08 August 2013 03:52 AM, Tony Luck wrote: On Tue, Aug 6, 2013 at 10:35 PM, Tony Luck tony.l...@gmail.com wrote: ERST is at the whim of the BIOS writer (the ACPI standard doesn't provide any suggestions on record sizes). My systems support ~6K record size. Off by a little - 7896 bytes on my current machine. efivars has, IIRC, a 1k limit coded in the Linux back end. My memory was correct for this one. Adding a little tracing to pstore_getrecords() I see this: pstore: inflated 3880 bytes compressed to 17459 bytes pstore: inflated 2567 bytes compressed to 17531 bytes pstore: inflated 4018 bytes compressed to 17488 bytes Which isn't at all what I expected. The ERST backend advertised a bufsize of 7896, and I have the default kmsg_bytes of 10240. So on my forced panic the code decided to create a three part pstore dump. The sum of the pieces is close to, but a little over the target of 10K. But I don't understand why the compressed sizes are so much smaller that the ERST backend block size. The sizes of compressed text depends on the nature of uncompressed data that is captured from kmsg_dump, considering the worst case of plain text based on experiments 45% was thecompression achieved. So we chose a buffer of size psinfo-bufsize * 100/45. If the uncompressed data captured was more of plain text nature then it would take up size close to ERST backend block size. Thats the reason you see compressed data of 2.5k to 4.0k. 2.5k would have more repeated occurrences than 4.0k. The sum of 3 pstore records should not have exceeded kmsg_bytes. Is it after adding total_len in the fix patch? Will take a look at it. The sum of first two records is less than kmsg_bytes, so it captures the 3rd record. Only after 3rd record is captured and written total is evaluated against kmsg_bytes when itexceeds the limit it stops capturing the next one. This shall happen even without compression right? If total is checked before write this can be avoided. - Aruna The uncompressed sizes appear to be close to constant. The compression ratios vary from 14% to 23% Why do we get three small parts instead of two bigger ones close the the 7896 ERST bufsize? Same explanation as given above. -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/2] powerpc/pseries: Add backward compatibilty to read old kernel oops-log
Older kernels has just length information in their header. Handle it while reading old kernel oops log from pstore. Applies on top of powerpc/pseries: Fix buffer overflow when reading from pstore Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 18 ++ 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 893f360..6a5f2b1 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -720,15 +720,25 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { int length, unzipped_len; + size_t hdr_size; oops_hdr = (struct oops_log_info *)buff; - length = oops_hdr-report_length; + if (oops_hdr-version OOPS_HDR_VERSION) { + /* Old format oops header had 2-byte record size */ + hdr_size = sizeof(u16); + length = oops_hdr-version; + time-tv_sec = 0; + time-tv_nsec = 0; + } else { + hdr_size = sizeof(*oops_hdr); + length = oops_hdr-report_length; + time-tv_sec = oops_hdr-timestamp; + time-tv_nsec = 0; + } *buf = kmalloc(length, GFP_KERNEL); if (*buf == NULL) return -ENOMEM; - memcpy(*buf, buff + sizeof(*oops_hdr), length); - time-tv_sec = oops_hdr-timestamp; - time-tv_nsec = 0; + memcpy(*buf, buff + hdr_size, length); kfree(buff); if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) { ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 1/2] powerpc/pseries: Fix buffer overflow when reading from pstore
When reading from pstore there is a buffer overflow during decompression due to the header added in unzip_oops. Remove unzip_oops and call pstore_decompress directly in nvram_pstore_read. Allocate buffer of size report_length of the oops header as header will not be deallocated in pstore. Since we have 'openssl' command line tool to decompress the compressed data, dump the compressed data in case decompression fails instead of not dumping anything. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 70 +++- 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 9f8671a..893f360 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -569,35 +569,6 @@ error: return ret; } -static int unzip_oops(char *oops_buf, char *big_buf) -{ - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; - u64 timestamp = oops_hdr-timestamp; - char *big_oops_data = NULL; - char *oops_data_buf = NULL; - size_t big_oops_data_sz; - int unzipped_len; - - big_oops_data = big_buf + sizeof(struct oops_log_info); - big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); - oops_data_buf = oops_buf + sizeof(struct oops_log_info); - - unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, - oops_hdr-report_length, - big_oops_data_sz); - - if (unzipped_len 0) { - pr_err(nvram: decompression failed; returned %d\n, - unzipped_len); - return -1; - } - oops_hdr = (struct oops_log_info *)big_buf; - oops_hdr-version = OOPS_HDR_VERSION; - oops_hdr-report_length = (u16) unzipped_len; - oops_hdr-timestamp = timestamp; - return 0; -} - static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -685,10 +656,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; char *buff = NULL, *big_buff = NULL; - int rc, sig = 0; + int sig = 0; loff_t p; -read_partition: read_type++; switch (nvram_type_ids[read_type]) { @@ -749,30 +719,36 @@ read_partition: *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { + int length, unzipped_len; + oops_hdr = (struct oops_log_info *)buff; - *buf = buff + sizeof(*oops_hdr); + length = oops_hdr-report_length; + *buf = kmalloc(length, GFP_KERNEL); + if (*buf == NULL) + return -ENOMEM; + memcpy(*buf, buff + sizeof(*oops_hdr), length); + time-tv_sec = oops_hdr-timestamp; + time-tv_nsec = 0; + kfree(buff); if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) { big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL); if (!big_buff) return -ENOMEM; - rc = unzip_oops(buff, big_buff); + unzipped_len = nvram_decompress(*buf, big_buff, + length, big_oops_buf_sz); - if (rc != 0) { - kfree(buff); + if (unzipped_len 0) { + pr_err(nvram: decompression failed, returned + rc %d\n, unzipped_len); kfree(big_buff); - goto read_partition; + } else { + *buf = big_buff; + length = unzipped_len; } - - oops_hdr = (struct oops_log_info *)big_buff; - *buf = big_buff + sizeof(*oops_hdr); - kfree(buff); } - - time-tv_sec = oops_hdr-timestamp; - time-tv_nsec = 0; - return oops_hdr-report_length; + return length; } *buf = buff; @@ -816,6 +792,7 @@ 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) { @@ -844,8 +821,9 @@ 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
Re: [PATCH 00/11] Add compression support to pstore
Hi Tony, On Thursday 08 August 2013 03:52 AM, Tony Luck wrote: On Tue, Aug 6, 2013 at 10:35 PM, Tony Luck tony.l...@gmail.com wrote: ERST is at the whim of the BIOS writer (the ACPI standard doesn't provide any suggestions on record sizes). My systems support ~6K record size. Off by a little - 7896 bytes on my current machine. efivars has, IIRC, a 1k limit coded in the Linux back end. My memory was correct for this one. Adding a little tracing to pstore_getrecords() I see this: pstore: inflated 3880 bytes compressed to 17459 bytes pstore: inflated 2567 bytes compressed to 17531 bytes pstore: inflated 4018 bytes compressed to 17488 bytes Which isn't at all what I expected. The ERST backend advertised a bufsize of 7896, and I have the default kmsg_bytes of 10240. So on my forced panic the code decided to create a three part pstore dump. The sum of the pieces is close to, but a little over the target of 10K. But I don't understand why the compressed sizes are so much smaller that the ERST backend block size. The sizes of compressed text depends on the nature of uncompressed data that is captured from kmsg_dump, considering the worst case of plain text based on experiments 45% was thecompression achieved. So we chose a buffer of size psinfo-bufsize * 100/45. If the uncompressed data captured was more of plain text nature then it would take up size close to ERST backend block size. Thats the reason you see compressed data of 2.5k to 4.0k. 2.5k would have more repeated occurrences than 4.0k. The sum of 3 pstore records should not have exceeded kmsg_bytes. Is it after adding total_len in the fix patch? Will take a look at it. The uncompressed sizes appear to be close to constant. The compression ratios vary from 14% to 23% Why do we get three small parts instead of two bigger ones close the the 7896 ERST bufsize? Same explanation as given above. -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 00/11] Add compression support to pstore
On Wednesday 07 August 2013 11:00 PM, Tony Luck wrote: Oh - one more thing - and my apologies for not spotting this before: dst = allocate_buf_for_compression(big_buf_sz); No - you may not call kmalloc() in oops/panic context. Please pre-allocate everything you need in some initialization code to make sure that we don't fail in the panic path because we can't get the memory we need. -Tony Sure. I had this in mind. At the same time memory consumed for compression is quite high. For the compression parameters used, workspace will be 30k and big_buf will be 17.5k for the record size of 7896 that you have mentioned. So total memory consumed for compression and decompression will close 47.5k. When we preallocate, we can use the same big_buf for compression as well as decompression. Also workspace will be one for both. By allocating max of inflate workspace size and deflate workspace size. We can save memory here. If pre-allocating close to 50k of buffer is not a issue. We can go ahead with this approach. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 00/11] Add compression support to pstore
On Wednesday 07 August 2013 05:06 AM, Tony Luck wrote: On Mon, Aug 5, 2013 at 2:20 PM, Tony Luck tony.l...@gmail.com wrote: Still have problems booting if there are any compressed images in ERST to be inflated. So I took another look at this part of the code ... and saw a couple of issues: while ((size = psi-read(id, type, count, time, buf, compressed, psi)) 0) { if (compressed (type == PSTORE_TYPE_DMESG)) { big_buf_sz = (psinfo-bufsize * 100) / 45; big_buf = allocate_buf_for_decompression(big_buf_sz); if (big_buf || stream.workspace) Did you mean here rather that ||? Yes right, it should be . unzipped_len = pstore_decompress(buf, big_buf, size, big_buf_sz); Need an else here to set unzipped_len to -1 (or set it to -1 down at the bottom of the loop ready for next time around. if (unzipped_len 0) { buf = big_buf; This sets us up for problems. First, you just overwrote the address of the buffer that psi-read allocated - so we have a memory leak. But worse than that we now double free the same buffer below when we kfree(buf) and then kfree(big_buf) size = unzipped_len; compressed = false; } else { pr_err(pstore: decompression failed; returned %d\n, unzipped_len); compressed = true; } } rc = pstore_mkfile(type, psi-name, id, count, buf, compressed, (size_t)size, time, psi); kfree(buf); kfree(stream.workspace); kfree(big_buf); buf = NULL; stream.workspace = NULL; big_buf = NULL; if (rc (rc != -EEXIST || !quiet)) failed++; } See attached patch that fixes these - but the code still looks like it could be cleaned up a bit more. The patch looks right. I will clean it up. Does the issue still persist after this? -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 00/11] Add compression support to pstore
Hi Tony, On Wednesday 07 August 2013 08:55 AM, Tony Luck wrote: On Tue, Aug 6, 2013 at 6:58 PM, Aruna Balakrishnaiah ar...@linux.vnet.ibm.com wrote: The patch looks right. I will clean it up. Does the issue still persist after this? Things seem to be working - but testing has hardly been extensive (just a couple of forced panics). I do have one other question. In this code: if (compressed (type == PSTORE_TYPE_DMESG)) { big_buf_sz = (psinfo-bufsize * 100) / 45; Where does the magic multiply by 1.45 come from? Is that always enough for the decompression of dmesg type data to succeed? I had this in my cover letter of the series, posting the same from it Writing to persistent store Compression will reduce the size of oops/panic report to atmost 45% of its original size. (Based on experiments done while providing compression support to nvram by Jim keniston). Hence buffer of size ( (100/45 approx 2.22) *registered_buffer is allocated). The compression parameters selected based on some experiments: compression_level = 6, window_bits = 12, memory_level = 4 which achieved a significant compression of 12 % of uncompressed buffer size tried upto 36k. Data is compressed from the bigger buffer to registered buffer which is returned to backends. Pstore will indicate that with a flag 'compressed' which is passed to backends. Using this flag, backends will add a flag in their header to indicate the data is compressed or not while writing to persistent store. The significant compression that I have mentioned had repeated occurrences in the text. When I tried with plain text I saw compression of around 45% with compression parameters I have used. If the record size is fixed across all the backends then it would be easy to come up with a pre defined set of compression parameters as well as the buffer size of compressed/decompressed data based on experiments. In power as of now, the maximum size of the record is 4k. So compression support on power was provided with multiply (100/45) considering the maximum record size to be 4k. How is it with erst and efivars? - Aruna -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 00/11] Add compression support to pstore
je 8126d368 pstore_mkfile+0xd8 8126d314: 44 39 71 18 cmp %r14d,0x18(%rcx)GP fault here 8126d318: 75 ee jne 8126d308 pstore_mkfile+0x78 8126d31a: 4c 39 69 20 cmp%r13,0x20(%rcx) 8126d31e: 75 e8 jne 8126d308 pstore_mkfile+0x78 8126d320: 48 39 59 10 cmp%rbx,0x10(%rcx) 8126d324: 75 e2 jne 8126d308 pstore_mkfile+0x78 8126d326: 48 89 c6mov%rax,%rsi 8126d329: 48 c7 c7 e8 a7 0a 82mov$0x820aa7e8,%rdi 8126d330: e8 1b 0d 39 00 callq 815fe050 _raw_spin_unlock_irqrestore Booting a vanilla v3.11-rc4 kernel I can see the files pstore - but they still seem to have corruption/missing data at the end when I decode with openssl zlib -d :-( So start by peering at the path that I applied to make sure I didn't mess up. Strangely I am not ablereproduce this on power or on system-x. With system-x I was able to loga single record and decompression did not give me any junk characters at the end. Not sure if its the header which is missing.If it was I should have encountered same issue on Power too. Please give a final try with the patch I have attached and I will dig into this more tomorrow. Patch to be applied on top of my patch series (without your fix patch). - Aruna -Tony commit 35b489152ae8f673fa79e7eeffc0bc8503c608b6 Author: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Date: Tue Aug 6 00:08:35 2013 +0530 pstore: fix for the junk characters at the end Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 8f3e5f0..3446c99 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -283,7 +283,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long size, big_buf_sz; int hsize = 0; int zipped_len = -1; - size_t len; + size_t len, total_len; bool compressed; big_buf_sz = (psinfo-bufsize * 100) / 45; @@ -293,9 +293,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, hsize = sprintf(dst, %s#%d Part%d\n, why, oopscount, part); size = big_buf_sz - hsize; - dst += hsize; - if (!kmsg_dump_get_buffer(dumper, true, dst, + if (!kmsg_dump_get_buffer(dumper, true, dst + hsize, size, len)) break; @@ -313,17 +312,18 @@ static void pstore_dump(struct kmsg_dumper *dumper, if (!kmsg_dump_get_buffer(dumper, true, dst, size, len)) break; + total_len = hsize + len; } else { compressed = true; - len = zipped_len; + total_len = zipped_len; } ret = psinfo-write(PSTORE_TYPE_DMESG, reason, id, part, -oopscount, compressed, hsize + len, psinfo); +oopscount, compressed, total_len, psinfo); if (ret == 0 reason == KMSG_DUMP_OOPS pstore_is_mounted()) pstore_new_entry = 1; - total += hsize + len; + total += total_len; part++; } if (pstore_cannot_block_path(reason)) { ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 00/11] Add compression support to pstore
Hi Tony/Kees, Could you please review and let me know your comments!! Regards, Aruna On Monday 15 July 2013 10:25 PM, Aruna Balakrishnaiah wrote: The patchset adds compression support to pstore. As the non-volatile storage space is limited, adding compression support results in capturing more data within limited space. Size of dmesg file in a powerpc/pseries box with nvram's oops partition (to store oops-log) size 4k: Without compression: dmesg-nvram-1: ~ 4k (3980) WIth compression: dmesg-nvram-1: ~8.8k (8844) Writing to persistent store Compression will reduce the size of oops/panic report to atmost 45% of its original size. (Based on experiments done while providing compression support to nvram by Jim keniston). Hence buffer of size ( (100/45 approx 2.22) *registered_buffer is allocated). The compression parameters selected based on some experiments: compression_level = 6, window_bits = 12, memory_level = 4 which achieved a significant compression of 12 % of uncompressed buffer size tried upto 36k. Data is compressed from the bigger buffer to registered buffer which is returned to backends. Pstore will indicate that with a flag 'compressed' which is passed to backends. Using this flag, backends will add a flag in their header to indicate the data is compressed or not while writing to persistent store. Reading from persistent store - When backends read data from persistent store it will use the flag added by it while writing to persistent store to determine if the data is compressed or not. Using the information, it will set the flag in pstore's read call back. Pstore will decompress the data based on the flag and writes decompressed data to the file. Test results: Have tested the patches on powerpc/pseries. On Intel have only tested with erst backend. Efi-pstore and RAM persistent buffer requires testing. --- Aruna Balakrishnaiah (11): powerpc/pseries: Remove (de)compression in nvram with pstore enabled pstore: Add new argument 'compressed' in pstore write callback pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected pstore: Add compression support to pstore pstore: Introduce new argument 'compressed' in the read callback pstore: Provide decompression support to pstore pstore: Add file extension to pstore file if compressed powerpc/pseries: Read and write to the 'compressed' flag of pstore erst: Read and write to the 'compressed' flag of pstore efi-pstore: Read and write to the 'compressed' flag of pstore pstore/ram: Read and write to the 'compressed' flag of pstore arch/powerpc/platforms/pseries/nvram.c | 131 drivers/acpi/apei/erst.c | 21 ++- drivers/firmware/efi/efi-pstore.c | 27 +++- fs/pstore/Kconfig |2 fs/pstore/inode.c |9 + fs/pstore/internal.h |5 - fs/pstore/platform.c | 214 ++-- fs/pstore/ram.c| 41 +- include/linux/pstore.h |6 - 9 files changed, 307 insertions(+), 149 deletions(-) ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 00/11] Add compression support to pstore
The patchset adds compression support to pstore. As the non-volatile storage space is limited, adding compression support results in capturing more data within limited space. Size of dmesg file in a powerpc/pseries box with nvram's oops partition (to store oops-log) size 4k: Without compression: dmesg-nvram-1: ~ 4k (3980) WIth compression: dmesg-nvram-1: ~8.8k (8844) Writing to persistent store Compression will reduce the size of oops/panic report to atmost 45% of its original size. (Based on experiments done while providing compression support to nvram by Jim keniston). Hence buffer of size ( (100/45 approx 2.22) *registered_buffer is allocated). The compression parameters selected based on some experiments: compression_level = 6, window_bits = 12, memory_level = 4 which achieved a significant compression of 12 % of uncompressed buffer size tried upto 36k. Data is compressed from the bigger buffer to registered buffer which is returned to backends. Pstore will indicate that with a flag 'compressed' which is passed to backends. Using this flag, backends will add a flag in their header to indicate the data is compressed or not while writing to persistent store. Reading from persistent store - When backends read data from persistent store it will use the flag added by it while writing to persistent store to determine if the data is compressed or not. Using the information, it will set the flag in pstore's read call back. Pstore will decompress the data based on the flag and writes decompressed data to the file. Test results: Have tested the patches on powerpc/pseries. On Intel have only tested with erst backend. Efi-pstore and RAM persistent buffer requires testing. --- Aruna Balakrishnaiah (11): powerpc/pseries: Remove (de)compression in nvram with pstore enabled pstore: Add new argument 'compressed' in pstore write callback pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected pstore: Add compression support to pstore pstore: Introduce new argument 'compressed' in the read callback pstore: Provide decompression support to pstore pstore: Add file extension to pstore file if compressed powerpc/pseries: Read and write to the 'compressed' flag of pstore erst: Read and write to the 'compressed' flag of pstore efi-pstore: Read and write to the 'compressed' flag of pstore pstore/ram: Read and write to the 'compressed' flag of pstore arch/powerpc/platforms/pseries/nvram.c | 131 drivers/acpi/apei/erst.c | 21 ++- drivers/firmware/efi/efi-pstore.c | 27 +++- fs/pstore/Kconfig |2 fs/pstore/inode.c |9 + fs/pstore/internal.h |5 - fs/pstore/platform.c | 214 ++-- fs/pstore/ram.c| 41 +- include/linux/pstore.h |6 - 9 files changed, 307 insertions(+), 149 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 01/11] powerpc/pseries: Remove (de)compression in nvram with pstore enabled
(De)compression support is provided in pstore in subsequent patches which needs an additional argument 'compressed' to determine if the data is compressed or not. This patch will take care of removing (de)compression in nvram with pstore which was making use of 'hsize' argument in pstore write as 'hsize' will be removed in the subsequent patch. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 40 1 file changed, 40 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 9f8671a..07c3c07 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -640,27 +640,6 @@ 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 - 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); @@ -751,25 +730,6 @@ read_partition: if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { oops_hdr = (struct oops_log_info *)buff; *buf = buff + sizeof(*oops_hdr); - - if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) { - big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL); - if (!big_buff) - return -ENOMEM; - - rc = unzip_oops(buff, big_buff); - - if (rc != 0) { - kfree(buff); - kfree(big_buff); - goto read_partition; - } - - oops_hdr = (struct oops_log_info *)big_buff; - *buf = big_buff + sizeof(*oops_hdr); - kfree(buff); - } - time-tv_sec = oops_hdr-timestamp; time-tv_nsec = 0; return oops_hdr-report_length; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 02/11] pstore: Add new argument 'compressed' in pstore write callback
Addition of new argument 'compressed' in the write call back will help the backend to know if the data passed from pstore is compressed or not (In case where compression fails.). If compressed, the backend can add a tag indicating the data is compressed while writing to persistent store. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |4 ++-- drivers/acpi/apei/erst.c |4 ++-- drivers/firmware/efi/efi-pstore.c |2 +- fs/pstore/platform.c |7 --- fs/pstore/ram.c|2 +- include/linux/pstore.h |4 ++-- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 07c3c07..c5c9d78 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -613,7 +613,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 * @@ -624,7 +624,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; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 88d0b0f..5e90796 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -935,7 +935,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, 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); @@ -1055,7 +1055,7 @@ out: } 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 *) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 73de5a9..fab6892 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -103,7 +103,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]; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 422962a..20fa686 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -149,6 +149,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long size; int hsize; size_t len; + bool compressed = false; dst = psinfo-buf; hsize = sprintf(dst, %s#%d Part%d\n, why, oopscount, part); @@ -159,7 +160,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, break; ret = psinfo-write(PSTORE_TYPE_DMESG, reason, id, part, - oopscount, hsize, hsize + len, psinfo); + oopscount, compressed, hsize + len, psinfo); if (ret == 0 reason == KMSG_DUMP_OOPS pstore_is_mounted()) pstore_new_entry = 1; @@ -221,10 +222,10 @@ static void pstore_register_console(void) {} static int pstore_write_compat(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, - size_t hsize, size_t size
[PATCH 03/11] pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected
Pstore will make use of deflate and inflate algorithm to compress and decompress the data. So when Pstore is enabled select zlib_deflate and zlib_inflate. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/Kconfig |2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig index ca71db6..983d951 100644 --- a/fs/pstore/Kconfig +++ b/fs/pstore/Kconfig @@ -1,6 +1,8 @@ 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 ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 05/11] pstore: Introduce new argument 'compressed' in the read callback
Backends will set the flag 'compressed' after reading the log from persistent store to indicate the data being returned to pstore is compressed or not. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |2 +- drivers/acpi/apei/erst.c |4 ++-- drivers/firmware/efi/efi-pstore.c |3 ++- fs/pstore/platform.c |4 +++- fs/pstore/ram.c|3 ++- include/linux/pstore.h |2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index c5c9d78..1ddc266 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -658,7 +658,7 @@ 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; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 5e90796..b0dca8e 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -933,7 +933,7 @@ 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, bool compressed, size_t size, struct pstore_info *psi); @@ -989,7 +989,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; diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index fab6892..9a5425f 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -87,7 +87,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; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 5b95524..b1faf25 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -404,6 +404,7 @@ void pstore_get_records(int quiet) enum pstore_type_id type; struct timespec time; int failed = 0, rc; + boolcompressed; if (!psi) return; @@ -412,7 +413,8 @@ void pstore_get_records(int quiet) if (psi-open psi-open(psi)) goto out; - while ((size = psi-read(id, type, count, time, buf, psi)) 0) { + while ((size = psi-read(id, type, count, time, buf, compressed, + psi)) 0) { rc = pstore_mkfile(type, psi-name, id, count, buf, (size_t)size, time, psi); kfree(buf); diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index fe7188f..2927223 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -133,7 +133,8 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, - char **buf, struct pstore_info *psi) + char **buf, bool *compressed, + struct pstore_info *psi) { ssize_t size; ssize_t ecc_notice_size; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index abfca4f..abd437d 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -55,7 +55,7 @@ struct pstore_info { int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, - struct pstore_info *psi); + bool
[PATCH 04/11] pstore: Add compression support to pstore
Add compression support to pstore which will help in capturing more data. Initially, pstore will make a call to kmsg_dump with a bigger buffer and will pass the size of bigger buffer to kmsg_dump and then compress the data to registered buffer of registered size. In case compression fails, pstore will capture the uncompressed data by making a call again to kmsg_dump with registered_buffer of registered size. Pstore will indicate the data is compressed or not with a flag in the write callback. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c | 124 ++ 1 file changed, 115 insertions(+), 9 deletions(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 20fa686..5b95524 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -26,6 +26,7 @@ #include linux/console.h #include linux/module.h #include linux/pstore.h +#include linux/zlib.h #include linux/string.h #include linux/timer.h #include linux/slab.h @@ -65,6 +66,12 @@ struct pstore_info *psinfo; static char *backend; +/* Compression parameters */ +#define COMPR_LEVEL 6 +#define WINDOW_BITS 12 +#define MEM_LEVEL 4 +static struct z_stream_s stream; + /* How much of the console log to snapshot */ static unsigned long kmsg_bytes = 10240; @@ -117,6 +124,80 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason) } EXPORT_SYMBOL_GPL(pstore_cannot_block_path); +/* Derived from logfs_compress() */ +static int pstore_compress(const void *in, void *out, size_t inlen, + size_t outlen) +{ + int err, ret; + + ret = -EIO; + err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, + MEM_LEVEL, Z_DEFAULT_STRATEGY); + 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_deflate(stream, Z_FINISH); + if (err != Z_STREAM_END) + goto error; + + err = zlib_deflateEnd(stream); + if (err != Z_OK) + goto error; + + if (stream.total_out = stream.total_in) + goto error; + + ret = stream.total_out; +error: + return ret; +} + +/* Compress the text from dst into psinfo-buf. */ +static int zip_data(char *dst, size_t text_len) +{ + int zipped_len = pstore_compress(dst, psinfo-buf, text_len, +psinfo-bufsize); + + kfree(dst); + kfree(stream.workspace); + if (zipped_len 0) { + pr_err(pstore: compression failed; returned %d\n, zipped_len); + pr_err(pstore: logging uncompressed oops/panic report\n); + return -1; + } + + return zipped_len; +} + +static char *allocate_buf_for_compression(unsigned long big_buf_sz) +{ + char *big_buf; + + big_buf = kmalloc(big_buf_sz, GFP_KERNEL); + if (big_buf) { + stream.workspace = kmalloc(zlib_deflate_workspacesize( + WINDOW_BITS, MEM_LEVEL), GFP_KERNEL); + if (!stream.workspace) { + pr_err(pstore: No memory for compression workspace; + skipping compression\n); + kfree(big_buf); + big_buf = NULL; + } + } else { + pr_err(No memory for uncompressed data; + skipping compression\n); + stream.workspace = NULL; + } + + return big_buf; +} /* * callback from kmsg_dump. (s2,l2) has the most recently * written bytes, older bytes are in (s1,l1). Save as much @@ -146,18 +227,43 @@ static void pstore_dump(struct kmsg_dumper *dumper, oopscount++; while (total kmsg_bytes) { char *dst; - unsigned long size; - int hsize; + unsigned long size, big_buf_sz; + int hsize = 0; + int zipped_len = -1; size_t len; - bool compressed = false; + bool compressed; + + big_buf_sz = (psinfo-bufsize * 100) / 45; + dst = allocate_buf_for_compression(big_buf_sz); - dst = psinfo-buf; - hsize = sprintf(dst, %s#%d Part%d\n, why, oopscount, part); - size = psinfo-bufsize - hsize; - dst += hsize; + if (dst) { + hsize = sprintf(dst, %s#%d Part%d\n, why, + oopscount, part); + size = big_buf_sz - hsize; + dst += hsize; - if (!kmsg_dump_get_buffer(dumper, true, dst, size, len
[PATCH 07/11] pstore: Add file extension to pstore file if compressed
In case decompression fails, add a .enc.z to indicate the file has compressed data. This will help user space utilities to figure out the file contents. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/inode.c|9 + fs/pstore/internal.h |5 +++-- fs/pstore/platform.c |4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 71bf5f4..259e92c 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -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); @@ -328,7 +329,7 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, break; case PSTORE_TYPE_PPC_RTAS: sprintf(name, rtas-%s-%lld, psname, id); - break; + break; case PSTORE_TYPE_PPC_OF: sprintf(name, powerpc-ofw-%s-%lld, psname, id); break; diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 937d820..3b3d305 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -50,8 +50,9 @@ extern struct pstore_info *psinfo; extern voidpstore_set_kmsg_bytes(int); extern voidpstore_get_records(int); extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, - int count, char *data, size_t size, - struct timespec time, struct pstore_info *psi); + int count, char *data, bool compressed, + size_t size, struct timespec time, + struct pstore_info *psi); extern int pstore_is_mounted(void); #endif diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 119db58..8f3e5f0 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -481,13 +481,15 @@ void pstore_get_records(int quiet) if (unzipped_len 0) { buf = big_buf; size = unzipped_len; + compressed = false; } else { pr_err(pstore: decompression failed; returned %d\n, unzipped_len); + compressed = true; } } rc = pstore_mkfile(type, psi-name, id, count, buf, - (size_t)size, time, psi); + compressed, (size_t)size, time, psi); kfree(buf); kfree(stream.workspace); kfree(big_buf); ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 06/11] pstore: Provide decompression support to pstore
Based on the flag 'compressed' set or not, pstore will decompress the data returning a plain text file. If decompression fails for a particular record it will have the compressed data in the file which can be decompressed with 'openssl' command line tool. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 59 - fs/pstore/platform.c | 77 2 files changed, 76 insertions(+), 60 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 1ddc266..78c6f45 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -539,65 +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 unzip_oops(char *oops_buf, char *big_buf) -{ - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; - u64 timestamp = oops_hdr-timestamp; - char *big_oops_data = NULL; - char *oops_data_buf = NULL; - size_t big_oops_data_sz; - int unzipped_len; - - big_oops_data = big_buf + sizeof(struct oops_log_info); - big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); - oops_data_buf = oops_buf + sizeof(struct oops_log_info); - - unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, - oops_hdr-report_length, - big_oops_data_sz); - - if (unzipped_len 0) { - pr_err(nvram: decompression failed; returned %d\n, - unzipped_len); - return -1; - } - oops_hdr = (struct oops_log_info *)big_buf; - oops_hdr-version = OOPS_HDR_VERSION; - oops_hdr-report_length = (u16) unzipped_len; - oops_hdr-timestamp = timestamp; - return 0; -} - static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index b1faf25..119db58 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -198,6 +198,59 @@ static char *allocate_buf_for_compression(unsigned long big_buf_sz) return big_buf; } + +static char *allocate_buf_for_decompression(unsigned long size) +{ + char *big_buf; + + big_buf = kmalloc(size, GFP_KERNEL); + if (big_buf) { + stream.workspace = kmalloc(zlib_inflate_workspacesize(), + GFP_KERNEL); + if (!stream.workspace) { + pr_err(pstore: No memory for decompression workspace; + skipping decompression\n); + kfree(big_buf); + big_buf = NULL; + } + } else { + pr_err(No memory for decompressed data; + skipping decompression\n); + stream.workspace = NULL; + } + + return big_buf; +} + +/* Derived from logfs_uncompress */ +int pstore_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; +} /* * callback from kmsg_dump. (s2,l2) has the most recently * written bytes, older bytes are in (s1,l1). Save as much @@ -398,12 +451,14 @@ void pstore_get_records(int quiet) { struct pstore_info *psi = psinfo; char*buf = NULL; - ssize_t size; + char*big_buf = NULL; + ssize_t size, big_buf_sz; u64
[PATCH 08/11] powerpc/pseries: Read and write to the 'compressed' flag of pstore
If data returned from pstore is compressed, nvram's write callback will add a flag ERR_TYPE_KERNEL_PANIC_GZ indicating the data is compressed while writing to nvram. If the data read from nvram is compressed, nvram's read callback will set the flag 'compressed'. The patch adds backward compatibilty with old format oops header when reading from pstore. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 34 +--- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 78c6f45..6f383eb 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -581,6 +581,9 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-report_length = (u16) size; oops_hdr-timestamp = get_seconds(); + 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); @@ -604,11 +607,10 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, 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; - int rc, sig = 0; + char *buff = NULL; + int sig = 0; loff_t p; -read_partition: read_type++; switch (nvram_type_ids[read_type]) { @@ -669,14 +671,32 @@ read_partition: *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { + u16 length; oops_hdr = (struct oops_log_info *)buff; - *buf = buff + sizeof(*oops_hdr); - time-tv_sec = oops_hdr-timestamp; - time-tv_nsec = 0; - return oops_hdr-report_length; + + /* Provide backward compatibility with old format headers */ + if (oops_hdr-version OOPS_HDR_VERSION) { + *buf = buff + sizeof(u16); + length = oops_hdr-version; + time-tv_sec = 0; + time-tv_nsec = 0; + } else { + *buf = buff + sizeof(*oops_hdr); + length = oops_hdr-report_length; + time-tv_sec = oops_hdr-timestamp; + time-tv_nsec = 0; + } + + if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) + *compressed = true; + else + *compressed = false; + + return length; } *buf = buff; + *compressed = false; return part-size; } ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 09/11] erst: Read and write to the 'compressed' flag of pstore
In pstore write, set the section type to CPER_SECTION_TYPE_DMESG_COMPR if the data is compressed. In pstore read, read the section type and update the 'compressed' flag accordingly. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- drivers/acpi/apei/erst.c | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index b0dca8e..62df189 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -956,6 +956,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) @@ -1034,7 +1037,12 @@ skip: } 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, @@ -1085,7 +1093,10 @@ 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: - rcd-sec_hdr.section_type = CPER_SECTION_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: rcd-sec_hdr.section_type = CPER_SECTION_TYPE_MCE; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 10/11] efi-pstore: Read and write to the 'compressed' flag of pstore
In pstore write, Efi will add a character 'C'(compressed) or D'(decompressed) in its header while writing to persistent store. In pstore read, read the header and update the 'compressed' flag accordingly. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- drivers/firmware/efi/efi-pstore.c | 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 9a5425f..5002d50 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -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; @@ -96,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, @@ -112,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]; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 11/11] pstore/ram: Read and write to the 'compressed' flag of pstore
In pstore write, add character 'C'(compressed) or 'D'(decompressed) in the header while writing to Ram persistent buffer. In pstore read, read the header and update the 'compressed' flag accordingly. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/ram.c | 36 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 2927223..4027c20 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -131,6 +131,27 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, return prz; } +static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time, + bool *compressed) +{ + char data_type; + + if (sscanf(buffer, RAMOOPS_KERNMSG_HDR %lu.%lu-%c\n, + time-tv_sec, time-tv_nsec, data_type) == 3) { + if (data_type == 'C') + *compressed = true; + else + *compressed = false; + } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR %lu.%lu\n, + time-tv_sec, time-tv_nsec) == 2) { + *compressed = false; + } else { + time-tv_sec = 0; + time-tv_nsec = 0; + *compressed = false; + } +} + static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, bool *compressed, @@ -153,10 +174,6 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 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); /* ECC correction notice */ @@ -167,12 +184,14 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 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; } -static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) +static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz, +bool compressed) { char *hdr; struct timespec timestamp; @@ -183,8 +202,9 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) timestamp.tv_sec = 0; timestamp.tv_nsec = 0; } - hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR %lu.%lu\n, - (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000)); + hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR %lu.%lu-%c\n, + (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000), + compressed ? 'C' : 'D'); WARN_ON_ONCE(!hdr); len = hdr ? strlen(hdr) : 0; persistent_ram_write(prz, hdr, len); @@ -243,7 +263,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, prz = cxt-przs[cxt-dump_write_cnt]; - hlen = ramoops_write_kmsg_hdr(prz); + hlen = ramoops_write_kmsg_hdr(prz, compressed); if (size + hlen prz-buffer_size) size = prz-buffer_size - hlen; persistent_ram_write(prz, buf, size); ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH] Add hsize argument in write_buf call of pstore_ftrace_call
Incorporate the addition of hsize argument in write_buf callback of pstore. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/ftrace.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/pstore/ftrace.c b/fs/pstore/ftrace.c index 43b1280..76a4eeb 100644 --- a/fs/pstore/ftrace.c +++ b/fs/pstore/ftrace.c @@ -44,7 +44,7 @@ static void notrace pstore_ftrace_call(unsigned long ip, rec.parent_ip = parent_ip; pstore_ftrace_encode_cpu(rec, raw_smp_processor_id()); psinfo-write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)rec, - sizeof(rec), psinfo); + 0, sizeof(rec), psinfo); local_irq_restore(flags); } ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 0/3] Nvram-to-pstore: compression support for oops data
Changes from v1: - Add header size argument in the pstore write callback instead of a separate API to return header size. The patchset takes care of compressing oops messages while writing to NVRAM, so that more oops data can be captured in the given space. big_oops_buf (2.22 * oops_data_sz) is allocated for compression. oops_data_sz is oops header size less of oops partition size. Pstore will internally call kmsg_dump to capture messages from printk buffer. While returning the data to nvram it adds is own header. For compression: Register pstore with big_oops_buf. In case compression fails, copy header added by pstore and last oops_data_sz bytes (recent messages) of big_oops_buf to nvram for which we need to know header size. patch 01/03 adds an additional argument for header size in pstore_write callback. pstore read callback of nvram will read the compressed data and return the decompressed data so that dmesg file (under /dev/pstore) is readable. In case decompression fails, instead of having the compressed data (junk) in the dmesg file it will skip and continue reading other partitions. This results in absence of dmesg file but will still have files relating to other parititons. --- Aruna Balakrishnaiah (3): Pass header size in the pstore write callback powerpc/pseries: Re-organise the oops compression code powerpc/pseries: Support compression of oops text via pstore arch/powerpc/platforms/pseries/nvram.c | 239 +++- drivers/acpi/apei/erst.c |4 - drivers/firmware/efi/efi-pstore.c |2 fs/pstore/platform.c | 10 + fs/pstore/ram.c|3 include/linux/pstore.h |8 + 6 files changed, 187 insertions(+), 79 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 2/3] powerpc/pseries: Re-organise the oops compression code
nvram_compress() and zip_oops() is used by the nvram_pstore_write API to compress oops messages hence re-organise the functions accordingly to avoid forward declarations. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 104 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 3f0e7d6..588bab5 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -486,6 +486,58 @@ static int clobbering_unread_rtas_event(void) NVRAM_RTAS_READ_TIMEOUT); } +/* Derived from logfs_compress() */ +static int nvram_compress(const void *in, void *out, size_t inlen, + size_t outlen) +{ + int err, ret; + + ret = -EIO; + err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, + MEM_LEVEL, Z_DEFAULT_STRATEGY); + 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_deflate(stream, Z_FINISH); + if (err != Z_STREAM_END) + goto error; + + err = zlib_deflateEnd(stream); + if (err != Z_OK) + goto error; + + if (stream.total_out = stream.total_in) + goto error; + + ret = stream.total_out; +error: + return ret; +} + +/* Compress the text from big_oops_buf into oops_buf. */ +static int zip_oops(size_t text_len) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, + oops_data_sz); + if (zipped_len 0) { + pr_err(nvram: compression failed; returned %d\n, zipped_len); + pr_err(nvram: logging uncompressed oops/panic report\n); + return -1; + } + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); + return 0; +} + #ifdef CONFIG_PSTORE static int nvram_pstore_open(struct pstore_info *psi) { @@ -759,58 +811,6 @@ int __init pSeries_nvram_init(void) } -/* Derived from logfs_compress() */ -static int nvram_compress(const void *in, void *out, size_t inlen, - size_t outlen) -{ - int err, ret; - - ret = -EIO; - err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, - MEM_LEVEL, Z_DEFAULT_STRATEGY); - 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_deflate(stream, Z_FINISH); - if (err != Z_STREAM_END) - goto error; - - err = zlib_deflateEnd(stream); - if (err != Z_OK) - goto error; - - if (stream.total_out = stream.total_in) - goto error; - - ret = stream.total_out; -error: - return ret; -} - -/* Compress the text from big_oops_buf into oops_buf. */ -static int zip_oops(size_t text_len) -{ - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; - int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, - oops_data_sz); - if (zipped_len 0) { - pr_err(nvram: compression failed; returned %d\n, zipped_len); - pr_err(nvram: logging uncompressed oops/panic report\n); - return -1; - } - oops_hdr-version = OOPS_HDR_VERSION; - oops_hdr-report_length = (u16) zipped_len; - oops_hdr-timestamp = get_seconds(); - return 0; -} - /* * This is our kmsg_dump callback, called after an oops or panic report * has been written to the printk buffer. We want to capture as much ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 1/3] Pass header size in the pstore write callback
Header size is needed to distinguish between header and the dump data. Incorporate the addition of new argument (hsize) in the pstore write callback. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |4 +++- drivers/acpi/apei/erst.c |4 ++-- drivers/firmware/efi/efi-pstore.c |2 +- fs/pstore/platform.c | 10 ++ fs/pstore/ram.c|3 ++- include/linux/pstore.h |8 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 14cc486..3f0e7d6 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -502,6 +502,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 * @size: number of bytes written to the registered buffer * @psi:registered pstore_info structure * @@ -512,7 +513,8 @@ 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 size, struct pstore_info *psi) + size_t hsize, size_t size, + struct pstore_info *psi) { int rc; struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 6d894bf..a9cf960 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -935,7 +935,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, struct timespec *time, char **buf, 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, + u64 *id, unsigned int part, int count, size_t hsize, 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); @@ -1055,7 +1055,7 @@ out: } static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, - u64 *id, unsigned int part, int count, + u64 *id, unsigned int part, int count, size_t hsize, size_t size, struct pstore_info *psi) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 202d2c8..452800e0 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -104,7 +104,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 size, + unsigned int part, int count, size_t hsize, size_t size, struct pstore_info *psi) { char name[DUMP_NAME_LEN]; diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 86d1038..4637ec4 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -159,7 +159,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, break; ret = psinfo-write(PSTORE_TYPE_DMESG, reason, id, part, - oopscount, hsize + len, psinfo); + oopscount, hsize, hsize + len, psinfo); if (ret == 0 reason == KMSG_DUMP_OOPS pstore_is_mounted()) pstore_new_entry = 1; @@ -196,7 +196,7 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c) spin_lock_irqsave(psinfo-buf_lock, flags); } memcpy(psinfo-buf, s, c); - psinfo-write(PSTORE_TYPE_CONSOLE, 0, id, 0, 0, c, psinfo); + psinfo-write(PSTORE_TYPE_CONSOLE, 0, id, 0, 0, 0, c, psinfo); spin_unlock_irqrestore(psinfo-buf_lock, flags); s += c; c = e - s; @@ -221,9 +221,11 @@ static void pstore_register_console(void) {} static int pstore_write_compat(enum pstore_type_id type, enum kmsg_dump_reason reason, u64 *id, unsigned int part, int count, - size_t size, struct pstore_info *psi
[PATCH v2 3/3] powerpc/pseries: Support compression of oops text via pstore
The patch set supports compression of oops messages while writing to NVRAM, this helps in capturing more of oops data to lnx,oops-log. The pstore file for oops messages will be in decompressed format making it readable. In case compression fails, the patch takes care of copying the header added by pstore and last oops_data_sz bytes of big_oops_buf to NVRAM so that we have recent oops messages in lnx,oops-log. In case decompression fails, it will result in absence of oops file but still have files (in /dev/pstore) for other partitions. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 131 +--- 1 file changed, 117 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 588bab5..9f8671a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -539,6 +539,65 @@ 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 unzip_oops(char *oops_buf, char *big_buf) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + u64 timestamp = oops_hdr-timestamp; + char *big_oops_data = NULL; + char *oops_data_buf = NULL; + size_t big_oops_data_sz; + int unzipped_len; + + big_oops_data = big_buf + sizeof(struct oops_log_info); + big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); + oops_data_buf = oops_buf + sizeof(struct oops_log_info); + + unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, + oops_hdr-report_length, + big_oops_data_sz); + + if (unzipped_len 0) { + pr_err(nvram: decompression failed; returned %d\n, + unzipped_len); + return -1; + } + oops_hdr = (struct oops_log_info *)big_buf; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) unzipped_len; + oops_hdr-timestamp = timestamp; + return 0; +} + static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -569,6 +628,7 @@ static int nvram_pstore_write(enum pstore_type_id type, struct pstore_info *psi) { int rc; + unsigned int err_type = ERR_TYPE_KERNEL_PANIC; struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; /* part 1 has the recent messages from printk buffer */ @@ -579,8 +639,30 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-version = OOPS_HDR_VERSION; 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 + err_type = ERR_TYPE_KERNEL_PANIC_GZ; + } + rc = nvram_write_os_partition(oops_log_partition, oops_buf, - (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + (int) (sizeof(*oops_hdr) + oops_hdr-report_length), err_type, count); if (rc != 0) @@ -602,10 +684,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct oops_log_info *oops_hdr; unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; - char *buff = NULL; - int sig = 0; + char *buff
Re: [PATCH 3/3] powerpc/pseries: Support compression of oops text via pstore
Hi Tony, On Tuesday 25 June 2013 09:32 PM, Luck, Tony wrote: Introducing headersize in pstore_write() API would need changes at multiple places whereits being called. The idea is to move the compression support to pstore infrastructure so that other platforms could also make use of it. Any thoughts on the back/forward compatibility as we switch to compressed pstore data? E.g. imagine I have a system installed with some Linux distribution with a kernel too old to know about compressed pstore. I use that machine to run the latest kernels that do compression ... and one fine day one of them crashes hard - logging in compressed form to pstore. Now I boot my distro kernel to pick up the pieces ... what do I see in /sys/fs/pstore/*? Some compressed files? Can I read them with some tool? This somewhat of a corner case - but not completely unrealistic ... I'd at least like to be reassured that the old kernel won't choke when it sees the compressed blobs. openssl command line tool can be used to decompress the compressed data of the pstore file in the above scenario. Usage: cat file | openssl zlib -d -Tony ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 3/3] powerpc/pseries: Support compression of oops text via pstore
Hi Kees, On Monday 24 June 2013 11:27 PM, Kees Cook wrote: On Sun, Jun 23, 2013 at 11:23 PM, Aruna Balakrishnaiah ar...@linux.vnet.ibm.com wrote: The patch set supports compression of oops messages while writing to NVRAM, this helps in capturing more of oops data to lnx,oops-log. The pstore file for oops messages will be in decompressed format making it readable. In case compression fails, the patch takes care of copying the header added by pstore and last oops_data_sz bytes of big_oops_buf to NVRAM so that we have recent oops messages in lnx,oops-log. In case decompression fails, it will result in absence of oops file but still have files (in /dev/pstore) for other partitions. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 132 +--- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 0159d74..b5ba5e2 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -539,6 +539,65 @@ 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 unzip_oops(char *oops_buf, char *big_buf) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + u64 timestamp = oops_hdr-timestamp; + char *big_oops_data = NULL; + char *oops_data_buf = NULL; + size_t big_oops_data_sz; + int unzipped_len; + + big_oops_data = big_buf + sizeof(struct oops_log_info); + big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); + oops_data_buf = oops_buf + sizeof(struct oops_log_info); + + unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, + oops_hdr-report_length, + big_oops_data_sz); + + if (unzipped_len 0) { + pr_err(nvram: decompression failed; returned %d\n, + unzipped_len); + return -1; + } + oops_hdr = (struct oops_log_info *)big_buf; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) unzipped_len; + oops_hdr-timestamp = timestamp; + return 0; +} + static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -567,6 +626,7 @@ static int nvram_pstore_write(enum pstore_type_id type, size_t size, struct pstore_info *psi) { int rc; + unsigned int err_type = ERR_TYPE_KERNEL_PANIC; struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; /* part 1 has the recent messages from printk buffer */ @@ -577,8 +637,31 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-version = OOPS_HDR_VERSION; 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) { + int hsize = pstore_get_header_size(); I think I would rather see the API to pstore_write() changed to include explicit details about header sizes. Mkaing hsize a global seems unwise, since it's not strictly going to be a constant value. It could change between calls to the writer, for example. Introducing headersize in pstore_write() API would need changes at multiple places whereits being called. The idea is to move the compression support to pstore infrastructure so that other platforms could also make use of it. Once the compression support gets in, header size argument in pstore_write() will have to be deprecated. Till the time compression support for pstore goes in, can't we call pstore_header_size before every write call to knowthe header size. Beyond that, this all seems sensible, though it would be kind of cool to move this compression logic into the pstore core so it would get used by default (or through a module parameter). -Kees
[RESEND PATCH 0/3] Nvram-to-pstore: compression support for oops data
The patchset takes care of compressing oops messages while writing to NVRAM, so that more oops data can be captured in the given space. big_oops_buf (2.22 * oops_data_sz) is allocated for compression. oops_data_sz is oops header size less of oops partition size. Pstore will internally call kmsg_dump to capture messages from printk buffer. While returning the data to nvram it adds is own header. For compression: Register pstore with big_oops_buf. In case compression fails, copy header added by pstore and last oops_data_sz bytes (recent messages) of big_oops_buf to nvram for which we need to know header size. patch 01/03 will add a function in pstore to return the header size. pstore read callback of nvram will read the compressed data and return the decompressed data so that dmesg file (under /dev/pstore) is readable. In case decompression fails, instead of having the compressed data (junk) in the dmesg file it will skip and continue reading other partitions. This results in absence of dmesg file but will still have files relating to other parititons. --- Aruna Balakrishnaiah (3): Retreive header size from pstore powerpc/pseries: Re-organise the oops compression code powerpc/pseries: Support compression of oops text via pstore arch/powerpc/platforms/pseries/nvram.c | 236 +++- fs/pstore/platform.c |7 + include/linux/pstore.h |6 + 3 files changed, 182 insertions(+), 67 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/3] powerpc/pseries: Re-organise the oops compression code
nvram_compress() and zip_oops() is used by the nvram_pstore_write API to compress oops messages hence re-organise the functions accordingly to avoid forward declarations. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 104 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 14cc486..0159d74 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -486,6 +486,58 @@ static int clobbering_unread_rtas_event(void) NVRAM_RTAS_READ_TIMEOUT); } +/* Derived from logfs_compress() */ +static int nvram_compress(const void *in, void *out, size_t inlen, + size_t outlen) +{ + int err, ret; + + ret = -EIO; + err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, + MEM_LEVEL, Z_DEFAULT_STRATEGY); + 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_deflate(stream, Z_FINISH); + if (err != Z_STREAM_END) + goto error; + + err = zlib_deflateEnd(stream); + if (err != Z_OK) + goto error; + + if (stream.total_out = stream.total_in) + goto error; + + ret = stream.total_out; +error: + return ret; +} + +/* Compress the text from big_oops_buf into oops_buf. */ +static int zip_oops(size_t text_len) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, + oops_data_sz); + if (zipped_len 0) { + pr_err(nvram: compression failed; returned %d\n, zipped_len); + pr_err(nvram: logging uncompressed oops/panic report\n); + return -1; + } + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); + return 0; +} + #ifdef CONFIG_PSTORE static int nvram_pstore_open(struct pstore_info *psi) { @@ -757,58 +809,6 @@ int __init pSeries_nvram_init(void) } -/* Derived from logfs_compress() */ -static int nvram_compress(const void *in, void *out, size_t inlen, - size_t outlen) -{ - int err, ret; - - ret = -EIO; - err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, - MEM_LEVEL, Z_DEFAULT_STRATEGY); - 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_deflate(stream, Z_FINISH); - if (err != Z_STREAM_END) - goto error; - - err = zlib_deflateEnd(stream); - if (err != Z_OK) - goto error; - - if (stream.total_out = stream.total_in) - goto error; - - ret = stream.total_out; -error: - return ret; -} - -/* Compress the text from big_oops_buf into oops_buf. */ -static int zip_oops(size_t text_len) -{ - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; - int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, - oops_data_sz); - if (zipped_len 0) { - pr_err(nvram: compression failed; returned %d\n, zipped_len); - pr_err(nvram: logging uncompressed oops/panic report\n); - return -1; - } - oops_hdr-version = OOPS_HDR_VERSION; - oops_hdr-report_length = (u16) zipped_len; - oops_hdr-timestamp = get_seconds(); - return 0; -} - /* * This is our kmsg_dump callback, called after an oops or panic report * has been written to the printk buffer. We want to capture as much ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 1/3] Retreive header size from pstore
pstore_get_header_size will return the size of the header added by pstore while logging messages to the registered buffer. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c |7 ++- include/linux/pstore.h |6 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 86d1038..e8260ea 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -49,6 +49,7 @@ MODULE_PARM_DESC(update_ms, milliseconds before pstore updates its content corruption on Oopses)); static int pstore_new_entry; +static int hsize; static void pstore_timefunc(unsigned long); static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0); @@ -68,6 +69,11 @@ static char *backend; /* How much of the console log to snapshot */ static unsigned long kmsg_bytes = 10240; +int pstore_get_header_size(void) +{ + return hsize; +} + void pstore_set_kmsg_bytes(int bytes) { kmsg_bytes = bytes; @@ -147,7 +153,6 @@ static void pstore_dump(struct kmsg_dumper *dumper, while (total kmsg_bytes) { char *dst; unsigned long size; - int hsize; size_t len; dst = psinfo-buf; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 656699f..f43b64f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -73,6 +73,7 @@ struct pstore_info { #ifdef CONFIG_PSTORE extern int pstore_register(struct pstore_info *); extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); +extern int pstore_get_header_size(void); #else static inline int pstore_register(struct pstore_info *psi) @@ -84,6 +85,11 @@ pstore_cannot_block_path(enum kmsg_dump_reason reason) { return false; } +static inline int +pstore_get_header_size(void) +{ + return 0; +} #endif #endif /*_LINUX_PSTORE_H*/ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 3/3] powerpc/pseries: Support compression of oops text via pstore
The patch set supports compression of oops messages while writing to NVRAM, this helps in capturing more of oops data to lnx,oops-log. The pstore file for oops messages will be in decompressed format making it readable. In case compression fails, the patch takes care of copying the header added by pstore and last oops_data_sz bytes of big_oops_buf to NVRAM so that we have recent oops messages in lnx,oops-log. In case decompression fails, it will result in absence of oops file but still have files (in /dev/pstore) for other partitions. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 132 +--- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 0159d74..b5ba5e2 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -539,6 +539,65 @@ 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 unzip_oops(char *oops_buf, char *big_buf) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + u64 timestamp = oops_hdr-timestamp; + char *big_oops_data = NULL; + char *oops_data_buf = NULL; + size_t big_oops_data_sz; + int unzipped_len; + + big_oops_data = big_buf + sizeof(struct oops_log_info); + big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); + oops_data_buf = oops_buf + sizeof(struct oops_log_info); + + unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, + oops_hdr-report_length, + big_oops_data_sz); + + if (unzipped_len 0) { + pr_err(nvram: decompression failed; returned %d\n, + unzipped_len); + return -1; + } + oops_hdr = (struct oops_log_info *)big_buf; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) unzipped_len; + oops_hdr-timestamp = timestamp; + return 0; +} + static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -567,6 +626,7 @@ static int nvram_pstore_write(enum pstore_type_id type, size_t size, struct pstore_info *psi) { int rc; + unsigned int err_type = ERR_TYPE_KERNEL_PANIC; struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; /* part 1 has the recent messages from printk buffer */ @@ -577,8 +637,31 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-version = OOPS_HDR_VERSION; 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) { + int hsize = pstore_get_header_size(); + 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 + err_type = ERR_TYPE_KERNEL_PANIC_GZ; + } + rc = nvram_write_os_partition(oops_log_partition, oops_buf, - (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + (int) (sizeof(*oops_hdr) + oops_hdr-report_length), err_type, count); if (rc != 0) @@ -600,10 +683,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct oops_log_info *oops_hdr; unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part
[PATCH v2] powerpc/pseries: Enable PSTORE in pseries_defconfig
Since now we have pstore support for nvram in pseries, enable it in the default config. With this config option enabled, pstore infra-structure will be used to read/write the messages from/to nvram. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/configs/pseries_defconfig |1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index c4dfbaf..9630a50 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -347,3 +347,4 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y CONFIG_VHOST_NET=m +CONFIG_PSTORE=y ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH] powerpc/pseries: Enable PSTORE in pseries_defconfig
Hi Michael, On Monday 24 June 2013 06:51 AM, Michael Neuling wrote: Enable PSTORE in pseries_defconfig Please add a why to your changelogs eg. Now we have pstore support for nvram on pseries, enable it in the default config Why you are changing something is more important than what, since you can always determine what is being changed, by looking at the diff. The why will be long forgotten. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/configs/pseries_defconfig |1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index c4dfbaf..9630a50 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -347,3 +347,4 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y CONFIG_VHOST_NET=m +CONFIG_PSTORE=y This should really be added in the right location on the config, not just at the end. ie. Sorry, I overlooked this commentin my v2 patch. Will resend. @@ -296,6 +293,7 @@ CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y +CONFIG_PSTORE=y CONFIG_NFS_FS=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v3] powerpc/pseries: Enable PSTORE in pseries_defconfig
Since now we have pstore support for nvram in pseries, enable it in the default config. With this config option enabled, pstore infra-structure will be used to read/write the messages from/to nvram. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- v3: Move pstore config to right place v2: Change patch description arch/powerpc/configs/pseries_defconfig |1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index c4dfbaf..bea8587 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -296,6 +296,7 @@ CONFIG_SQUASHFS=m CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y +CONFIG_PSTORE=y CONFIG_NFS_FS=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH] powerpc/pseries: Enable PSTORE in pseries_defconfig
Enable PSTORE in pseries_defconfig Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/configs/pseries_defconfig |1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index c4dfbaf..9630a50 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -347,3 +347,4 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=y CONFIG_VHOST_NET=m +CONFIG_PSTORE=y ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v4 0/8] Nvram-to-pstore
Hi Michael, On Wednesday 19 June 2013 11:45 AM, Michael Neuling wrote: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com wrote: Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose each partition in NVRAM as a separate file in /dev/pstore. For instance, Oops messages will be stored in a file named [dmesg-nvram-2]. Changes from v3: - Change filename prefix for of-config and common partition Changes from v2: - Fix renaming of pstore type ids in nvram.c Changes from v1: - Reduce #ifdefs by and remove forward declarations of pstore callbacks - Handle return value of nvram_write_os_partition - Remove empty pstore callbacks and register pstore only when pstore is configured When booted on pHyp, I see /dev/nvram but not /dev/pstore, even if I turn on CONFIG_PSTORE. Is there something else I need to add? You need to mount pstore to access the files. # mkdir /dev/pstore # mount -t pstore - /dev/pstore to unmount # umount /dev/pstore References: http://lwn.net/Articles/421297/ Documentation/ABI/testing/pstore Should we update pseries_defconfig to include CONFIG_PSTORE (which it doesn't include currently)? Maybe turn on panic/oops via CONFIG_PSTORE_RAM too? Yes. We should enable CONFIG_PSTORE by default in pseries_defconfig. We need not enable CONFIG_PSTORE_RAM for our case. Its for systems with persistent RAM. Other than that, the series looks clean. It's passes my build and boot tests. I've not reviewed the contents of the patches. Mikey --- Aruna Balakrishnaiah (8): powerpc/pseries: Remove syslog prefix in uncompressed oops text powerpc/pseries: Add version and timestamp to oops header powerpc/pseries: Introduce generic read function to read nvram-partitions powerpc/pseries: Read/Write oops nvram partition via pstore powerpc/pseries: Read rtas partition via pstore powerpc/pseries: Distinguish between a os-partition and non-os partition powerpc/pseries: Read of-config partition via pstore powerpc/pseries: Read common partition via pstore arch/powerpc/platforms/pseries/nvram.c | 353 +++- fs/pstore/inode.c |9 + include/linux/pstore.h |4 3 files changed, 313 insertions(+), 53 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v3 0/8] Nvram-to-pstore
Hi Ben, On Saturday 01 June 2013 10:55 AM, Benjamin Herrenschmidt wrote: Another question... Should the core pstore fail to unlink partitions that don't have an -erase callback ? IE. Why would you let anyone erase the OFW common partition for example ? That means that userspace tools can no longer manipulate it but we certainly don't want to remove it from the nvram itself. Since I do not have a callback for erase in nvram, pstore simply unlinks the file and will not delete the partition. That leads to a deeper concern. Looking at how efi-pstore works, it looks like they create a file for each var. This looks like something valuable we could do for something like the common partition since typically it's made of name,value pairs. However, pstore is a flat space, while we have patitions which themselves can be organized in name,value pairs (some at least) I wonder if it's time to introduce pstore directories... Or do we stick to our special tools to interpret/change the name,value pairs ? Since pstore infrastructure creates the file in read-only mode creating files for name, value pairs will not be useful to us. So for now, we need to stick to our tools to interpret/change the name,value pairs. And also, pstore filenames are controlled by pstore infrastructure so that would need quite some changes in the pstore infrastructure. I think for now it would be better to dump the contents of common partition as it is. Also do we want to add an ability to resize partitions ? Possibly based on how much is written to them ? Yes it will be good to that. If your fine with patchset apart from the filenames of-config and common partitions. I will post the next version of it with powerpc prefix. Cheers, Ben. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v3 0/8] Nvram-to-pstore
On Wednesday 05 June 2013 03:13 PM, Benjamin Herrenschmidt wrote: On Wed, 2013-06-05 at 14:30 +0530, Aruna Balakrishnaiah wrote: Hi Ben, On Saturday 01 June 2013 10:55 AM, Benjamin Herrenschmidt wrote: Another question... Should the core pstore fail to unlink partitions that don't have an -erase callback ? IE. Why would you let anyone erase the OFW common partition for example ? That means that userspace tools can no longer manipulate it but we certainly don't want to remove it from the nvram itself. Since I do not have a callback for erase in nvram, pstore simply unlinks the file and will not delete the partition. Right. My point is that it should probably refuse to unlink the file too. What's the point in letting the user remove the file, potentially making tools not working anymore, without any way to bring it back other than a reboot ? unlink makes sense if it also removes the partition. If it doesn't it should just fail. Right, makes sense. Will create a patch to fix it in pstore. That leads to a deeper concern. Looking at how efi-pstore works, it looks like they create a file for each var. This looks like something valuable we could do for something like the common partition since typically it's made of name,value pairs. However, pstore is a flat space, while we have patitions which themselves can be organized in name,value pairs (some at least) I wonder if it's time to introduce pstore directories... Or do we stick to our special tools to interpret/change the name,value pairs ? Since pstore infrastructure creates the file in read-only mode creating files for name, value pairs will not be useful to us. So for now, we need to stick to our tools to interpret/change the name,value pairs. And also, pstore filenames are controlled by pstore infrastructure so that would need quite some changes in the pstore infrastructure. I think for now it would be better to dump the contents of common partition as it is. Ok. Also do we want to add an ability to resize partitions ? Possibly based on how much is written to them ? Yes it will be good to that. If your fine with patchset apart from the filenames of-config and common partitions. I will post the next version of it with powerpc prefix. Yes, I'm ok with it. Cheers, Ben. Cheers, Ben. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v4 0/8] Nvram-to-pstore
Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose each partition in NVRAM as a separate file in /dev/pstore. For instance, Oops messages will be stored in a file named [dmesg-nvram-2]. Changes from v3: - Change filename prefix for of-config and common partition Changes from v2: - Fix renaming of pstore type ids in nvram.c Changes from v1: - Reduce #ifdefs by and remove forward declarations of pstore callbacks - Handle return value of nvram_write_os_partition - Remove empty pstore callbacks and register pstore only when pstore is configured --- Aruna Balakrishnaiah (8): powerpc/pseries: Remove syslog prefix in uncompressed oops text powerpc/pseries: Add version and timestamp to oops header powerpc/pseries: Introduce generic read function to read nvram-partitions powerpc/pseries: Read/Write oops nvram partition via pstore powerpc/pseries: Read rtas partition via pstore powerpc/pseries: Distinguish between a os-partition and non-os partition powerpc/pseries: Read of-config partition via pstore powerpc/pseries: Read common partition via pstore arch/powerpc/platforms/pseries/nvram.c | 353 +++- fs/pstore/inode.c |9 + include/linux/pstore.h |4 3 files changed, 313 insertions(+), 53 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v4 2/8] powerpc/pseries: Add version and timestamp to oops header
Introduce version and timestamp information in the oops header. oops_log_info (oops header) holds version (to distinguish between old and new format oops header), length of the oops text (compressed or uncompressed) and timestamp. The version field will sit in the same place as the length in old headers. version is assigned 5000 (greater than oops partition size) so that existing tools will refuse to dump new style partitions as the length is too large. The updated tools will work with both old and new format headers. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 57 +--- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index e54a8b7..742735a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -29,6 +29,13 @@ /* Max bytes to read/write in one go */ #define NVRW_CNT 0x20 +/* + * Set oops header version to distingush between old and new format header. + * lnx,oops-log partition max size is 4000, header version 4000 will + * help in identifying new header. + */ +#define OOPS_HDR_VERSION 5000 + static unsigned int nvram_size; static int nvram_fetch, nvram_store; static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ @@ -67,6 +74,12 @@ static const char *pseries_nvram_os_partitions[] = { NULL }; +struct oops_log_info { + u16 version; + u16 report_length; + u64 timestamp; +} __attribute__((packed)); + static void oops_to_nvram(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason); @@ -83,28 +96,28 @@ static unsigned long last_unread_rtas_event;/* timestamp */ * big_oops_buf[] holds the uncompressed text we're capturing. * - * oops_buf[] holds the compressed text, preceded by a prefix. - * The prefix is just a u16 holding the length of the compressed* text. - * (*Or uncompressed, if compression fails.) oops_buf[] gets written - * to NVRAM. + * oops_buf[] holds the compressed text, preceded by a oops header. + * oops header has u16 holding the version of oops header (to differentiate + * between old and new format header) followed by u16 holding the length of + * the compressed* text (*Or uncompressed, if compression fails.) and u64 + * holding the timestamp. oops_buf[] gets written to NVRAM. * - * oops_len points to the prefix. oops_data points to the compressed text. + * oops_log_info points to the header. oops_data points to the compressed text. * * +- oops_buf - * | +- oops_data - * v v - * ++---+ - * | length| text | - * | (2 bytes) | (oops_data_sz bytes) | - * ++---+ + * | +- oops_data + * v v + * +---+---+---++ + * | version | length| timestamp | text | + * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) | + * +---+---+---++ * ^ - * +- oops_len + * +- oops_log_info * * We preallocate these buffers during init to avoid kmalloc during oops/panic. */ static size_t big_oops_buf_sz; static char *big_oops_buf, *oops_buf; -static u16 *oops_len; static char *oops_data; static size_t oops_data_sz; @@ -425,9 +438,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) oops_log_partition.name); return; } - oops_len = (u16*) oops_buf; - oops_data = oops_buf + sizeof(u16); - oops_data_sz = oops_log_partition.size - sizeof(u16); + oops_data = oops_buf + sizeof(struct oops_log_info); + oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); /* * Figure compression (preceded by elimination of each line's n @@ -555,6 +567,7 @@ error: /* Compress the text from big_oops_buf into oops_buf. */ static int zip_oops(size_t text_len) { + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, oops_data_sz); if (zipped_len 0) { @@ -562,7 +575,9 @@ static int zip_oops(size_t text_len) pr_err(nvram: logging uncompressed oops/panic report\n); return -1; } - *oops_len = (u16) zipped_len; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); return 0; } @@ -576,6 +591,7
[PATCH v4 1/8] powerpc/pseries: Remove syslog prefix in uncompressed oops text
Removal of syslog prefix in the uncompressed oops text will help in capturing more oops data. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 8733a86..e54a8b7 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -619,7 +619,7 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, } if (rc != 0) { kmsg_dump_rewind(dumper); - kmsg_dump_get_buffer(dumper, true, + kmsg_dump_get_buffer(dumper, false, oops_data, oops_data_sz, text_len); err_type = ERR_TYPE_KERNEL_PANIC; *oops_len = (u16) text_len; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v4 3/8] powerpc/pseries: Introduce generic read function to read nvram-partitions
Introduce generic read function to read nvram partitions other than rtas. nvram_read_error_log will be retained which is used to read rtas partition from rtasd. nvram_read_partition is the generic read function to read from any nvram partition. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 32 ++-- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 742735a..088f023 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -293,34 +293,35 @@ int nvram_write_error_log(char * buff, int length, return rc; } -/* nvram_read_error_log +/* nvram_read_partition * - * Reads nvram for error log for at most 'length' + * Reads nvram partition for at most 'length' */ -int nvram_read_error_log(char * buff, int length, - unsigned int * err_type, unsigned int * error_log_cnt) +int nvram_read_partition(struct nvram_os_partition *part, char *buff, + int length, unsigned int *err_type, + unsigned int *error_log_cnt) { int rc; loff_t tmp_index; struct err_log_info info; - if (rtas_log_partition.index == -1) + if (part-index == -1) return -1; - if (length rtas_log_partition.size) - length = rtas_log_partition.size; + if (length part-size) + length = part-size; - tmp_index = rtas_log_partition.index; + tmp_index = part-index; rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); return rc; } rc = ppc_md.nvram_read(buff, length, tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); return rc; } @@ -330,6 +331,17 @@ int nvram_read_error_log(char * buff, int length, return 0; } +/* nvram_read_error_log + * + * Reads nvram for error log for at most 'length' + */ +int nvram_read_error_log(char *buff, int length, + unsigned int *err_type, unsigned int *error_log_cnt) +{ + return nvram_read_partition(rtas_log_partition, buff, length, + err_type, error_log_cnt); +} + /* This doesn't actually zero anything, but it sets the event_logged * word to tell that this event is safely in syslog. */ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v4 4/8] powerpc/pseries: Read/Write oops nvram partition via pstore
IBM's p series machines provide persistent storage for LPARs through NVRAM. NVRAM's lnx,oops-log partition is used to log oops messages. Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose oops partition in NVRAM as a separate file in /dev/pstore. For instance, Oops messages will be stored in a file named [dmesg-nvram-2]. In case pstore registration fails it will fall back to kmsg_dump mechanism. This patch will read/write the oops messages from/to this partition via pstore. Signed-off-by: Jim Keniston jkeni...@us.ibm.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 172 +--- 1 file changed, 157 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 088f023..9edec8e 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,6 +18,7 @@ #include linux/spinlock.h #include linux/slab.h #include linux/kmsg_dump.h +#include linux/pstore.h #include linux/ctype.h #include linux/zlib.h #include asm/uaccess.h @@ -127,6 +128,14 @@ static size_t oops_data_sz; #define MEM_LEVEL 4 static struct z_stream_s stream; +#ifdef CONFIG_PSTORE +static enum pstore_type_id nvram_type_ids[] = { + PSTORE_TYPE_DMESG, + -1 +}; +static int read_type; +#endif + static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) { unsigned int i; @@ -430,6 +439,149 @@ static int __init pseries_nvram_init_os_partition(struct nvram_os_partition return 0; } +/* + * Are we using the ibm,rtas-log for oops/panic reports? And if so, + * would logging this oops/panic overwrite an RTAS event that rtas_errd + * hasn't had a chance to read and process? Return 1 if so, else 0. + * + * We assume that if rtas_errd hasn't read the RTAS event in + * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to. + */ +static int clobbering_unread_rtas_event(void) +{ + return (oops_log_partition.index == rtas_log_partition.index +last_unread_rtas_event +get_seconds() - last_unread_rtas_event = + NVRAM_RTAS_READ_TIMEOUT); +} + +#ifdef CONFIG_PSTORE +static int nvram_pstore_open(struct pstore_info *psi) +{ + /* Reset the iterator to start reading partitions again */ + read_type = -1; + return 0; +} + +/** + * nvram_pstore_write - pstore write callback for nvram + * @type: Type of message logged + * @reason: reason behind dump (oops/panic) + * @id: identifier to indicate the write performed + * @part: pstore writes data to registered buffer in parts, + * part number will indicate the same. + * @count: Indicates oops count + * @size: number of bytes written to the registered buffer + * @psi:registered pstore_info structure + * + * Called by pstore_dump() when an oops or panic report is logged in the + * printk buffer. + * Returns 0 on successful write. + */ +static int nvram_pstore_write(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, int count, + size_t size, struct pstore_info *psi) +{ + int rc; + struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; + + /* part 1 has the recent messages from printk buffer */ + if (part 1 || type != PSTORE_TYPE_DMESG || + clobbering_unread_rtas_event()) + return -1; + + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) size; + oops_hdr-timestamp = get_seconds(); + rc = nvram_write_os_partition(oops_log_partition, oops_buf, + (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + count); + + if (rc != 0) + return rc; + + *id = part; + return 0; +} + +/* + * Reads the oops/panic report. + * Returns the length of the data we read from each partition. + * Returns 0 if we've been called before. + */ +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, + int *count, struct timespec *time, char **buf, + struct pstore_info *psi) +{ + struct oops_log_info *oops_hdr; + unsigned int err_type, id_no; + struct nvram_os_partition *part = NULL; + char *buff = NULL; + + read_type++; + + switch (nvram_type_ids[read_type]) { + case PSTORE_TYPE_DMESG: + part = oops_log_partition; + *type
[PATCH v4 6/8] powerpc/pseries: Distinguish between a os-partition and non-os partition
Introduce os_partition member in nvram_os_partition structure to identify if the partition is an os partition or not. This will be useful to handle non-os partitions of-config and common. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 78d72f0..714ed8a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -53,20 +53,23 @@ struct nvram_os_partition { int min_size; /* minimum acceptable size (0 means req_size) */ long size; /* size of data portion (excluding err_log_info) */ long index; /* offset of data portion of partition */ + bool os_partition; /* partition initialized by OS, not FW */ }; static struct nvram_os_partition rtas_log_partition = { .name = ibm,rtas-log, .req_size = 2079, .min_size = 1055, - .index = -1 + .index = -1, + .os_partition = true }; static struct nvram_os_partition oops_log_partition = { .name = lnx,oops-log, .req_size = 4000, .min_size = 2000, - .index = -1 + .index = -1, + .os_partition = true }; static const char *pseries_nvram_os_partitions[] = { ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v4 7/8] powerpc/pseries: Read of-config partition via pstore
This patch set exploits the pstore subsystem to read details of of-config partition in NVRAM to a separate file in /dev/pstore. For instance, of-config partition details will be stored in a file named [of-nvram-5]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 55 +++- fs/pstore/inode.c |3 ++ include/linux/pstore.h |1 + 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 714ed8a..f7392f6 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -132,9 +132,16 @@ static size_t oops_data_sz; static struct z_stream_s stream; #ifdef CONFIG_PSTORE +static struct nvram_os_partition of_config_partition = { + .name = of-config, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_PPC_RTAS, + PSTORE_TYPE_PPC_OF, -1 }; static int read_type; @@ -332,10 +339,15 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, tmp_index = part-index; - rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); - if (rc = 0) { - pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); - return rc; + if (part-os_partition) { + rc = ppc_md.nvram_read((char *)info, + sizeof(struct err_log_info), + tmp_index); + if (rc = 0) { + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, + rc); + return rc; + } } rc = ppc_md.nvram_read(buff, length, tmp_index); @@ -344,8 +356,10 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, return rc; } - *error_log_cnt = info.seq_num; - *err_type = info.error_type; + if (part-os_partition) { + *error_log_cnt = info.seq_num; + *err_type = info.error_type; + } return 0; } @@ -516,7 +530,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report and ibm,rtas-log partition. + * Reads the oops/panic report, rtas and of-config partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -525,9 +539,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct pstore_info *psi) { struct oops_log_info *oops_hdr; - unsigned int err_type, id_no; + unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; char *buff = NULL; + int sig = 0; + loff_t p; read_type++; @@ -542,10 +558,29 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = last_rtas_event; time-tv_nsec = 0; break; + case PSTORE_TYPE_PPC_OF: + sig = NVRAM_SIG_OF; + part = of_config_partition; + *type = PSTORE_TYPE_PPC_OF; + *id = PSTORE_TYPE_PPC_OF; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } + if (!part-os_partition) { + p = nvram_find_partition(part-name, sig, size); + if (p = 0) { + pr_err(nvram: Failed to find partition %s, + err %d\n, part-name, (int)p); + return 0; + } + part-index = p; + part-size = size; + } + buff = kmalloc(part-size, GFP_KERNEL); if (!buff) @@ -557,7 +592,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, } *count = 0; - *id = id_no; + + if (part-os_partition) + *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { oops_hdr = (struct oops_log_info *)buff; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index ec24f9c..73148ae 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -327,6 +327,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_RTAS: sprintf(name, rtas-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_OF: + sprintf(name, powerpc-ofw-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown
[PATCH v4 8/8] powerpc/pseries: Read common partition via pstore
This patch exploits pstore subsystem to read details of common partition in NVRAM to a separate file in /dev/pstore. For instance, common partition details will be stored in a file named [common-nvram-6]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 17 - fs/pstore/inode.c |3 +++ include/linux/pstore.h |1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index f7392f6..14cc486 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -138,10 +138,17 @@ static struct nvram_os_partition of_config_partition = { .os_partition = false }; +static struct nvram_os_partition common_partition = { + .name = common, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_PPC_RTAS, PSTORE_TYPE_PPC_OF, + PSTORE_TYPE_PPC_COMMON, -1 }; static int read_type; @@ -530,7 +537,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report, rtas and of-config partition. + * Reads the oops/panic report, rtas, of-config and common partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -566,6 +573,14 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = 0; time-tv_nsec = 0; break; + case PSTORE_TYPE_PPC_COMMON: + sig = NVRAM_SIG_SYS; + part = common_partition; + *type = PSTORE_TYPE_PPC_COMMON; + *id = PSTORE_TYPE_PPC_COMMON; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 73148ae..08c3d76 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -330,6 +330,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_OF: sprintf(name, powerpc-ofw-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_COMMON: + sprintf(name, powerpc-common-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 615dc18..656699f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -38,6 +38,7 @@ enum pstore_type_id { /* PPC64 partition types */ PSTORE_TYPE_PPC_RTAS= 4, PSTORE_TYPE_PPC_OF = 5, + PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_UNKNOWN = 255 }; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [RFC PATCH 0/3] Nvram-to-pstore: compression support for oops data
Hi Ben, There is no change in this patchset and it applies cleanly on top of v4 of Nvram-to-pstorepatches. The patchset takes care of compressing oops messages while writing to NVRAM, so that more oops data can be captured in the given space. big_oops_buf (2.22 * oops_data_sz) is allocated for compression. oops_data_sz is oops header size less of oops partition size. Pstore will internally call kmsg_dump to capture messages from printk buffer. While returning the data to nvram it adds is own header. For compression: Register pstore with big_oops_buf. In case compression fails, copy header added by pstore and last oops_data_sz bytes (recent messages) of big_oops_buf to nvram for which we need to know header size. patch 01/03 will add a function in pstore to return the header size. pstore read callback of nvram will read the compressed data and return the decompressed data so that dmesg file (under /dev/pstore) is readable. In case decompression fails, instead of having the compressed data (junk) in the dmesg file it will skip and continue reading other partitions. This results in absence of dmesg file but will still have files relating to other parititons. --- Aruna Balakrishnaiah (3): Retreive header size from pstore. powerpc/pseries: Re-organise the oops compression code powerpc/pseries: Support compression of oops text via pstore arch/powerpc/platforms/pseries/nvram.c | 236 +++- fs/pstore/platform.c |7 + include/linux/pstore.h |6 + 3 files changed, 182 insertions(+), 67 deletions(-) ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v3 8/8] powerpc/pseries: Read common partition via pstore
On Saturday 01 June 2013 10:22 AM, Benjamin Herrenschmidt wrote: On Thu, 2013-04-25 at 15:49 +0530, Aruna Balakrishnaiah wrote: diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 8d4fb65..88cc050 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -330,6 +330,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_OF: sprintf(name, of-%s-%lld, psname, id); break; Call this powerpc-ofw-... Does it even contain something we use in Linux at all ? Last I looked we only used the common one right ? Also it's format afaik is defined in the CHRP bindings so it's not generic OFW stuff, hence the powerpc prefix. + case PSTORE_TYPE_PPC_COMMON: + sprintf(name, common-%s-%lld, psname, id); + break; Same deal, call that powerpc-common Sure. Will change it to powerpc prefix. case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 615dc18..656699f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -38,6 +38,7 @@ enum pstore_type_id { /* PPC64 partition types */ PSTORE_TYPE_PPC_RTAS= 4, PSTORE_TYPE_PPC_OF = 5, + PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_UNKNOWN = 255 }; Do we expose anything else or keep it hidden ? We are exposing oops, rtas, of-config and common partition of nvram. Cheers, Ben. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 3/3] powerpc/pseries: Support compression of oops text via pstore
Hi Ben, On Saturday 01 June 2013 10:24 AM, Benjamin Herrenschmidt wrote: On Fri, 2013-04-26 at 15:26 +0530, Aruna Balakrishnaiah wrote: The patch set supports compression of oops messages while writing to NVRAM, this helps in capturing more of oops data to lnx,oops-log. The pstore file for oops messages will be in decompressed format making it readable. In case compression fails, the patch takes care of copying the header added by pstore and last oops_data_sz bytes of big_oops_buf to NVRAM so that we have recent oops messages in lnx,oops-log. In case decompression fails, it will result in absence of oops file but still have files (in /dev/pstore) for other partitions. Any reason that isn't handled by pstore itself rather than here ? Ie make a flag indicating that the partition supports compression and have pstore do it (so we don't compress everything such as ofw common etc...) Cheers, Ben. Since pstore does not have the compression support, I planned to reuse the existing compression code in nvram but later we can add compression support to pstore so that other platforms can make use of it. Regards, Aruna Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 132 +--- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 0159d74..b5ba5e2 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -539,6 +539,65 @@ 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 unzip_oops(char *oops_buf, char *big_buf) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + u64 timestamp = oops_hdr-timestamp; + char *big_oops_data = NULL; + char *oops_data_buf = NULL; + size_t big_oops_data_sz; + int unzipped_len; + + big_oops_data = big_buf + sizeof(struct oops_log_info); + big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); + oops_data_buf = oops_buf + sizeof(struct oops_log_info); + + unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, + oops_hdr-report_length, + big_oops_data_sz); + + if (unzipped_len 0) { + pr_err(nvram: decompression failed; returned %d\n, + unzipped_len); + return -1; + } + oops_hdr = (struct oops_log_info *)big_buf; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) unzipped_len; + oops_hdr-timestamp = timestamp; + return 0; +} + static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -567,6 +626,7 @@ static int nvram_pstore_write(enum pstore_type_id type, size_t size, struct pstore_info *psi) { int rc; + unsigned int err_type = ERR_TYPE_KERNEL_PANIC; struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; /* part 1 has the recent messages from printk buffer */ @@ -577,8 +637,31 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-version = OOPS_HDR_VERSION; 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) { + int hsize = pstore_get_header_size(); + 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
[PATCH 1/3] Retreive header size from pstore.
pstore_get_header_size will return the size of the header added by pstore while logging messages to the registered buffer. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- fs/pstore/platform.c |7 ++- include/linux/pstore.h |6 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 86d1038..e8260ea 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -49,6 +49,7 @@ MODULE_PARM_DESC(update_ms, milliseconds before pstore updates its content corruption on Oopses)); static int pstore_new_entry; +static int hsize; static void pstore_timefunc(unsigned long); static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0); @@ -68,6 +69,11 @@ static char *backend; /* How much of the console log to snapshot */ static unsigned long kmsg_bytes = 10240; +int pstore_get_header_size(void) +{ + return hsize; +} + void pstore_set_kmsg_bytes(int bytes) { kmsg_bytes = bytes; @@ -147,7 +153,6 @@ static void pstore_dump(struct kmsg_dumper *dumper, while (total kmsg_bytes) { char *dst; unsigned long size; - int hsize; size_t len; dst = psinfo-buf; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 656699f..f43b64f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -73,6 +73,7 @@ struct pstore_info { #ifdef CONFIG_PSTORE extern int pstore_register(struct pstore_info *); extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); +extern int pstore_get_header_size(void); #else static inline int pstore_register(struct pstore_info *psi) @@ -84,6 +85,11 @@ pstore_cannot_block_path(enum kmsg_dump_reason reason) { return false; } +static inline int +pstore_get_header_size(void) +{ + return 0; +} #endif #endif /*_LINUX_PSTORE_H*/ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/3] powerpc/pseries: Re-organise the oops compression code
nvram_compress() and zip_oops() is used by the nvram_pstore_write API to compress oops messages hence re-organise the functions accordingly to avoid forward declarations. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 104 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 14cc486..0159d74 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -486,6 +486,58 @@ static int clobbering_unread_rtas_event(void) NVRAM_RTAS_READ_TIMEOUT); } +/* Derived from logfs_compress() */ +static int nvram_compress(const void *in, void *out, size_t inlen, + size_t outlen) +{ + int err, ret; + + ret = -EIO; + err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, + MEM_LEVEL, Z_DEFAULT_STRATEGY); + 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_deflate(stream, Z_FINISH); + if (err != Z_STREAM_END) + goto error; + + err = zlib_deflateEnd(stream); + if (err != Z_OK) + goto error; + + if (stream.total_out = stream.total_in) + goto error; + + ret = stream.total_out; +error: + return ret; +} + +/* Compress the text from big_oops_buf into oops_buf. */ +static int zip_oops(size_t text_len) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, + oops_data_sz); + if (zipped_len 0) { + pr_err(nvram: compression failed; returned %d\n, zipped_len); + pr_err(nvram: logging uncompressed oops/panic report\n); + return -1; + } + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); + return 0; +} + #ifdef CONFIG_PSTORE static int nvram_pstore_open(struct pstore_info *psi) { @@ -757,58 +809,6 @@ int __init pSeries_nvram_init(void) } -/* Derived from logfs_compress() */ -static int nvram_compress(const void *in, void *out, size_t inlen, - size_t outlen) -{ - int err, ret; - - ret = -EIO; - err = zlib_deflateInit2(stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, - MEM_LEVEL, Z_DEFAULT_STRATEGY); - 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_deflate(stream, Z_FINISH); - if (err != Z_STREAM_END) - goto error; - - err = zlib_deflateEnd(stream); - if (err != Z_OK) - goto error; - - if (stream.total_out = stream.total_in) - goto error; - - ret = stream.total_out; -error: - return ret; -} - -/* Compress the text from big_oops_buf into oops_buf. */ -static int zip_oops(size_t text_len) -{ - struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; - int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, - oops_data_sz); - if (zipped_len 0) { - pr_err(nvram: compression failed; returned %d\n, zipped_len); - pr_err(nvram: logging uncompressed oops/panic report\n); - return -1; - } - oops_hdr-version = OOPS_HDR_VERSION; - oops_hdr-report_length = (u16) zipped_len; - oops_hdr-timestamp = get_seconds(); - return 0; -} - /* * This is our kmsg_dump callback, called after an oops or panic report * has been written to the printk buffer. We want to capture as much ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 3/3] powerpc/pseries: Support compression of oops text via pstore
The patch set supports compression of oops messages while writing to NVRAM, this helps in capturing more of oops data to lnx,oops-log. The pstore file for oops messages will be in decompressed format making it readable. In case compression fails, the patch takes care of copying the header added by pstore and last oops_data_sz bytes of big_oops_buf to NVRAM so that we have recent oops messages in lnx,oops-log. In case decompression fails, it will result in absence of oops file but still have files (in /dev/pstore) for other partitions. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 132 +--- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 0159d74..b5ba5e2 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -539,6 +539,65 @@ 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 unzip_oops(char *oops_buf, char *big_buf) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; + u64 timestamp = oops_hdr-timestamp; + char *big_oops_data = NULL; + char *oops_data_buf = NULL; + size_t big_oops_data_sz; + int unzipped_len; + + big_oops_data = big_buf + sizeof(struct oops_log_info); + big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info); + oops_data_buf = oops_buf + sizeof(struct oops_log_info); + + unzipped_len = nvram_decompress(oops_data_buf, big_oops_data, + oops_hdr-report_length, + big_oops_data_sz); + + if (unzipped_len 0) { + pr_err(nvram: decompression failed; returned %d\n, + unzipped_len); + return -1; + } + oops_hdr = (struct oops_log_info *)big_buf; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) unzipped_len; + oops_hdr-timestamp = timestamp; + return 0; +} + static int nvram_pstore_open(struct pstore_info *psi) { /* Reset the iterator to start reading partitions again */ @@ -567,6 +626,7 @@ static int nvram_pstore_write(enum pstore_type_id type, size_t size, struct pstore_info *psi) { int rc; + unsigned int err_type = ERR_TYPE_KERNEL_PANIC; struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; /* part 1 has the recent messages from printk buffer */ @@ -577,8 +637,31 @@ static int nvram_pstore_write(enum pstore_type_id type, oops_hdr-version = OOPS_HDR_VERSION; 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) { + int hsize = pstore_get_header_size(); + 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 + err_type = ERR_TYPE_KERNEL_PANIC_GZ; + } + rc = nvram_write_os_partition(oops_log_partition, oops_buf, - (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + (int) (sizeof(*oops_hdr) + oops_hdr-report_length), err_type, count); if (rc != 0) @@ -600,10 +683,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct oops_log_info *oops_hdr; unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part
[PATCH v3 0/8] Nvram-to-pstore
Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose each partition in NVRAM as a separate file in /dev/pstore. For instance Oops messages will stored in a file named [dmesg-nvram-2]. Changes from v2: - Fix renaming of pstore type ids in nvram.c Changes from v1: - Reduce #ifdefs by and remove forward declarations of pstore callbacks - Handle return value of nvram_write_os_partition - Remove empty pstore callbacks and register pstore only when pstore is configured --- Aruna Balakrishnaiah (8): powerpc/pseries: Remove syslog prefix in uncompressed oops text powerpc/pseries: Add version and timestamp to oops header powerpc/pseries: Introduce generic read function to read nvram-partitions powerpc/pseries: Read/Write oops nvram partition via pstore powerpc/pseries: Read rtas partition via pstore powerpc/pseries: Distinguish between a os-partition and non-os partition powerpc/pseries: Read of-config partition via pstore powerpc/pseries: Read common partition via pstore arch/powerpc/platforms/pseries/nvram.c | 353 +++- fs/pstore/inode.c |9 + include/linux/pstore.h |4 3 files changed, 313 insertions(+), 53 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v3 1/8] powerpc/pseries: Remove syslog prefix in uncompressed oops text
Removal of syslog prefix in the uncompressed oops text will help in capturing more oops data. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 8733a86..e54a8b7 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -619,7 +619,7 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, } if (rc != 0) { kmsg_dump_rewind(dumper); - kmsg_dump_get_buffer(dumper, true, + kmsg_dump_get_buffer(dumper, false, oops_data, oops_data_sz, text_len); err_type = ERR_TYPE_KERNEL_PANIC; *oops_len = (u16) text_len; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v3 2/8] powerpc/pseries: Add version and timestamp to oops header
Introduce version and timestamp information in the oops header. oops_log_info (oops header) holds version (to distinguish between old and new format oops header), length of the oops text (compressed or uncompressed) and timestamp. The version field will sit in the same place as the length in old headers. version is assigned 5000 (greater than oops partition size) so that existing tools will refuse to dump new style partitions as the length is too large. The updated tools will work with both old and new format headers. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 57 +--- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index e54a8b7..742735a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -29,6 +29,13 @@ /* Max bytes to read/write in one go */ #define NVRW_CNT 0x20 +/* + * Set oops header version to distingush between old and new format header. + * lnx,oops-log partition max size is 4000, header version 4000 will + * help in identifying new header. + */ +#define OOPS_HDR_VERSION 5000 + static unsigned int nvram_size; static int nvram_fetch, nvram_store; static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ @@ -67,6 +74,12 @@ static const char *pseries_nvram_os_partitions[] = { NULL }; +struct oops_log_info { + u16 version; + u16 report_length; + u64 timestamp; +} __attribute__((packed)); + static void oops_to_nvram(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason); @@ -83,28 +96,28 @@ static unsigned long last_unread_rtas_event;/* timestamp */ * big_oops_buf[] holds the uncompressed text we're capturing. * - * oops_buf[] holds the compressed text, preceded by a prefix. - * The prefix is just a u16 holding the length of the compressed* text. - * (*Or uncompressed, if compression fails.) oops_buf[] gets written - * to NVRAM. + * oops_buf[] holds the compressed text, preceded by a oops header. + * oops header has u16 holding the version of oops header (to differentiate + * between old and new format header) followed by u16 holding the length of + * the compressed* text (*Or uncompressed, if compression fails.) and u64 + * holding the timestamp. oops_buf[] gets written to NVRAM. * - * oops_len points to the prefix. oops_data points to the compressed text. + * oops_log_info points to the header. oops_data points to the compressed text. * * +- oops_buf - * | +- oops_data - * v v - * ++---+ - * | length| text | - * | (2 bytes) | (oops_data_sz bytes) | - * ++---+ + * | +- oops_data + * v v + * +---+---+---++ + * | version | length| timestamp | text | + * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) | + * +---+---+---++ * ^ - * +- oops_len + * +- oops_log_info * * We preallocate these buffers during init to avoid kmalloc during oops/panic. */ static size_t big_oops_buf_sz; static char *big_oops_buf, *oops_buf; -static u16 *oops_len; static char *oops_data; static size_t oops_data_sz; @@ -425,9 +438,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) oops_log_partition.name); return; } - oops_len = (u16*) oops_buf; - oops_data = oops_buf + sizeof(u16); - oops_data_sz = oops_log_partition.size - sizeof(u16); + oops_data = oops_buf + sizeof(struct oops_log_info); + oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); /* * Figure compression (preceded by elimination of each line's n @@ -555,6 +567,7 @@ error: /* Compress the text from big_oops_buf into oops_buf. */ static int zip_oops(size_t text_len) { + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, oops_data_sz); if (zipped_len 0) { @@ -562,7 +575,9 @@ static int zip_oops(size_t text_len) pr_err(nvram: logging uncompressed oops/panic report\n); return -1; } - *oops_len = (u16) zipped_len; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); return 0; } @@ -576,6 +591,7
[PATCH v3 3/8] powerpc/pseries: Introduce generic read function to read nvram-partitions
Introduce generic read function to read nvram partitions other than rtas. nvram_read_error_log will be retained which is used to read rtas partition from rtasd. nvram_read_partition is the generic read function to read from any nvram partition. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 32 ++-- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 742735a..088f023 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -293,34 +293,35 @@ int nvram_write_error_log(char * buff, int length, return rc; } -/* nvram_read_error_log +/* nvram_read_partition * - * Reads nvram for error log for at most 'length' + * Reads nvram partition for at most 'length' */ -int nvram_read_error_log(char * buff, int length, - unsigned int * err_type, unsigned int * error_log_cnt) +int nvram_read_partition(struct nvram_os_partition *part, char *buff, + int length, unsigned int *err_type, + unsigned int *error_log_cnt) { int rc; loff_t tmp_index; struct err_log_info info; - if (rtas_log_partition.index == -1) + if (part-index == -1) return -1; - if (length rtas_log_partition.size) - length = rtas_log_partition.size; + if (length part-size) + length = part-size; - tmp_index = rtas_log_partition.index; + tmp_index = part-index; rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); return rc; } rc = ppc_md.nvram_read(buff, length, tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); return rc; } @@ -330,6 +331,17 @@ int nvram_read_error_log(char * buff, int length, return 0; } +/* nvram_read_error_log + * + * Reads nvram for error log for at most 'length' + */ +int nvram_read_error_log(char *buff, int length, + unsigned int *err_type, unsigned int *error_log_cnt) +{ + return nvram_read_partition(rtas_log_partition, buff, length, + err_type, error_log_cnt); +} + /* This doesn't actually zero anything, but it sets the event_logged * word to tell that this event is safely in syslog. */ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v3 4/8] powerpc/pseries: Read/Write oops nvram partition via pstore
IBM's p series machines provide persistent storage for LPARs through NVRAM. NVRAM's lnx,oops-log partition is used to log oops messages. Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose oops partition in NVRAM as a separate file in /dev/pstore. For instance, Oops messages will be stored in a file named [dmesg-nvram-2]. In case pstore registration fails it will fall back to kmsg_dump mechanism. This patch will read/write the oops messages from/to this partition via pstore. Signed-off-by: Jim Keniston jkeni...@us.ibm.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 172 +--- 1 file changed, 157 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 088f023..9edec8e 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,6 +18,7 @@ #include linux/spinlock.h #include linux/slab.h #include linux/kmsg_dump.h +#include linux/pstore.h #include linux/ctype.h #include linux/zlib.h #include asm/uaccess.h @@ -127,6 +128,14 @@ static size_t oops_data_sz; #define MEM_LEVEL 4 static struct z_stream_s stream; +#ifdef CONFIG_PSTORE +static enum pstore_type_id nvram_type_ids[] = { + PSTORE_TYPE_DMESG, + -1 +}; +static int read_type; +#endif + static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) { unsigned int i; @@ -430,6 +439,149 @@ static int __init pseries_nvram_init_os_partition(struct nvram_os_partition return 0; } +/* + * Are we using the ibm,rtas-log for oops/panic reports? And if so, + * would logging this oops/panic overwrite an RTAS event that rtas_errd + * hasn't had a chance to read and process? Return 1 if so, else 0. + * + * We assume that if rtas_errd hasn't read the RTAS event in + * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to. + */ +static int clobbering_unread_rtas_event(void) +{ + return (oops_log_partition.index == rtas_log_partition.index +last_unread_rtas_event +get_seconds() - last_unread_rtas_event = + NVRAM_RTAS_READ_TIMEOUT); +} + +#ifdef CONFIG_PSTORE +static int nvram_pstore_open(struct pstore_info *psi) +{ + /* Reset the iterator to start reading partitions again */ + read_type = -1; + return 0; +} + +/** + * nvram_pstore_write - pstore write callback for nvram + * @type: Type of message logged + * @reason: reason behind dump (oops/panic) + * @id: identifier to indicate the write performed + * @part: pstore writes data to registered buffer in parts, + * part number will indicate the same. + * @count: Indicates oops count + * @size: number of bytes written to the registered buffer + * @psi:registered pstore_info structure + * + * Called by pstore_dump() when an oops or panic report is logged in the + * printk buffer. + * Returns 0 on successful write. + */ +static int nvram_pstore_write(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, int count, + size_t size, struct pstore_info *psi) +{ + int rc; + struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; + + /* part 1 has the recent messages from printk buffer */ + if (part 1 || type != PSTORE_TYPE_DMESG || + clobbering_unread_rtas_event()) + return -1; + + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) size; + oops_hdr-timestamp = get_seconds(); + rc = nvram_write_os_partition(oops_log_partition, oops_buf, + (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + count); + + if (rc != 0) + return rc; + + *id = part; + return 0; +} + +/* + * Reads the oops/panic report. + * Returns the length of the data we read from each partition. + * Returns 0 if we've been called before. + */ +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, + int *count, struct timespec *time, char **buf, + struct pstore_info *psi) +{ + struct oops_log_info *oops_hdr; + unsigned int err_type, id_no; + struct nvram_os_partition *part = NULL; + char *buff = NULL; + + read_type++; + + switch (nvram_type_ids[read_type]) { + case PSTORE_TYPE_DMESG: + part = oops_log_partition; + *type
[PATCH v3 5/8] powerpc/pseries: Read rtas partition via pstore
This patch set exploits the pstore subsystem to read details of rtas partition in NVRAM to a separate file in /dev/pstore. For instance, rtas details will be stored in a file named [rtas-nvram-4]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 33 +--- fs/pstore/inode.c |3 +++ include/linux/pstore.h |2 ++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 9edec8e..78d72f0 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -131,9 +131,11 @@ static struct z_stream_s stream; #ifdef CONFIG_PSTORE static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, + PSTORE_TYPE_PPC_RTAS, -1 }; static int read_type; +static unsigned long last_rtas_event; #endif static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) @@ -297,8 +299,13 @@ int nvram_write_error_log(char * buff, int length, { int rc = nvram_write_os_partition(rtas_log_partition, buff, length, err_type, error_log_cnt); - if (!rc) + if (!rc) { last_unread_rtas_event = get_seconds(); +#ifdef CONFIG_PSTORE + last_rtas_event = get_seconds(); +#endif + } + return rc; } @@ -506,7 +513,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report. + * Reads the oops/panic report and ibm,rtas-log partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -526,6 +533,12 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, part = oops_log_partition; *type = PSTORE_TYPE_DMESG; break; + case PSTORE_TYPE_PPC_RTAS: + part = rtas_log_partition; + *type = PSTORE_TYPE_PPC_RTAS; + time-tv_sec = last_rtas_event; + time-tv_nsec = 0; + break; default: return 0; } @@ -542,11 +555,17 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, *count = 0; *id = id_no; - oops_hdr = (struct oops_log_info *)buff; - *buf = buff + sizeof(*oops_hdr); - time-tv_sec = oops_hdr-timestamp; - time-tv_nsec = 0; - return oops_hdr-report_length; + + if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { + oops_hdr = (struct oops_log_info *)buff; + *buf = buff + sizeof(*oops_hdr); + time-tv_sec = oops_hdr-timestamp; + time-tv_nsec = 0; + return oops_hdr-report_length; + } + + *buf = buff; + return part-size; } static struct pstore_info nvram_pstore_info = { diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index e4bcb2c..ec24f9c 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -324,6 +324,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_MCE: sprintf(name, mce-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_RTAS: + sprintf(name, rtas-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 75d0176..d7a8fe9 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -35,6 +35,8 @@ enum pstore_type_id { PSTORE_TYPE_MCE = 1, PSTORE_TYPE_CONSOLE = 2, PSTORE_TYPE_FTRACE = 3, + /* PPC64 partition types */ + PSTORE_TYPE_PPC_RTAS= 4, PSTORE_TYPE_UNKNOWN = 255 }; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v3 7/8] powerpc/pseries: Read of-config partition via pstore
This patch set exploits the pstore subsystem to read details of of-config partition in NVRAM to a separate file in /dev/pstore. For instance, of-config partition details will be stored in a file named [of-nvram-5]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 55 +++- fs/pstore/inode.c |3 ++ include/linux/pstore.h |1 + 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 714ed8a..f7392f6 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -132,9 +132,16 @@ static size_t oops_data_sz; static struct z_stream_s stream; #ifdef CONFIG_PSTORE +static struct nvram_os_partition of_config_partition = { + .name = of-config, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_PPC_RTAS, + PSTORE_TYPE_PPC_OF, -1 }; static int read_type; @@ -332,10 +339,15 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, tmp_index = part-index; - rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); - if (rc = 0) { - pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); - return rc; + if (part-os_partition) { + rc = ppc_md.nvram_read((char *)info, + sizeof(struct err_log_info), + tmp_index); + if (rc = 0) { + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, + rc); + return rc; + } } rc = ppc_md.nvram_read(buff, length, tmp_index); @@ -344,8 +356,10 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, return rc; } - *error_log_cnt = info.seq_num; - *err_type = info.error_type; + if (part-os_partition) { + *error_log_cnt = info.seq_num; + *err_type = info.error_type; + } return 0; } @@ -516,7 +530,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report and ibm,rtas-log partition. + * Reads the oops/panic report, rtas and of-config partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -525,9 +539,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct pstore_info *psi) { struct oops_log_info *oops_hdr; - unsigned int err_type, id_no; + unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; char *buff = NULL; + int sig = 0; + loff_t p; read_type++; @@ -542,10 +558,29 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = last_rtas_event; time-tv_nsec = 0; break; + case PSTORE_TYPE_PPC_OF: + sig = NVRAM_SIG_OF; + part = of_config_partition; + *type = PSTORE_TYPE_PPC_OF; + *id = PSTORE_TYPE_PPC_OF; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } + if (!part-os_partition) { + p = nvram_find_partition(part-name, sig, size); + if (p = 0) { + pr_err(nvram: Failed to find partition %s, + err %d\n, part-name, (int)p); + return 0; + } + part-index = p; + part-size = size; + } + buff = kmalloc(part-size, GFP_KERNEL); if (!buff) @@ -557,7 +592,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, } *count = 0; - *id = id_no; + + if (part-os_partition) + *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { oops_hdr = (struct oops_log_info *)buff; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index ec24f9c..8d4fb65 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -327,6 +327,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_RTAS: sprintf(name, rtas-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_OF: + sprintf(name, of-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld
[PATCH v3 6/8] powerpc/pseries: Distinguish between a os-partition and non-os partition
Introduce os_partition member in nvram_os_partition structure to identify if the partition is an os partition or not. This will be useful to handle non-os partitions of-config and common. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 78d72f0..714ed8a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -53,20 +53,23 @@ struct nvram_os_partition { int min_size; /* minimum acceptable size (0 means req_size) */ long size; /* size of data portion (excluding err_log_info) */ long index; /* offset of data portion of partition */ + bool os_partition; /* partition initialized by OS, not FW */ }; static struct nvram_os_partition rtas_log_partition = { .name = ibm,rtas-log, .req_size = 2079, .min_size = 1055, - .index = -1 + .index = -1, + .os_partition = true }; static struct nvram_os_partition oops_log_partition = { .name = lnx,oops-log, .req_size = 4000, .min_size = 2000, - .index = -1 + .index = -1, + .os_partition = true }; static const char *pseries_nvram_os_partitions[] = { ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v3 8/8] powerpc/pseries: Read common partition via pstore
This patch exploits pstore subsystem to read details of common partition in NVRAM to a separate file in /dev/pstore. For instance, common partition details will be stored in a file named [common-nvram-6]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 17 - fs/pstore/inode.c |3 +++ include/linux/pstore.h |1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index f7392f6..14cc486 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -138,10 +138,17 @@ static struct nvram_os_partition of_config_partition = { .os_partition = false }; +static struct nvram_os_partition common_partition = { + .name = common, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_PPC_RTAS, PSTORE_TYPE_PPC_OF, + PSTORE_TYPE_PPC_COMMON, -1 }; static int read_type; @@ -530,7 +537,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report, rtas and of-config partition. + * Reads the oops/panic report, rtas, of-config and common partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -566,6 +573,14 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = 0; time-tv_nsec = 0; break; + case PSTORE_TYPE_PPC_COMMON: + sig = NVRAM_SIG_SYS; + part = common_partition; + *type = PSTORE_TYPE_PPC_COMMON; + *id = PSTORE_TYPE_PPC_COMMON; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 8d4fb65..88cc050 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -330,6 +330,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_OF: sprintf(name, of-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_COMMON: + sprintf(name, common-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 615dc18..656699f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -38,6 +38,7 @@ enum pstore_type_id { /* PPC64 partition types */ PSTORE_TYPE_PPC_RTAS= 4, PSTORE_TYPE_PPC_OF = 5, + PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_UNKNOWN = 255 }; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 0/8] powerpc/pseries: Nvram-to-pstore
Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose each partition in NVRAM as a separate file in /dev/pstore. For instance Oops messages will stored in a file named [dmesg-nvram-2]. Changes from v1: - Reduce #ifdefs by and remove forward declarations of pstore callbacks - Handle return value of nvram_write_os_partition - Remove empty pstore callbacks and register pstore only when pstore is configured --- Aruna Balakrishnaiah (8): powerpc/pseries: Remove syslog prefix in uncompressed oops text powerpc/pseries: Add version and timestamp to oops header powerpc/pseries: Introduce generic read function to read nvram-partitions powerpc/pseries: Read/Write oops nvram partition via pstore powerpc/pseries: Read rtas partition via pstore powerpc/pseries: Distinguish between a os-partition and non-os partition powerpc/pseries: Read of-config partition via pstore powerpc/pseries: Read common partition via pstore arch/powerpc/platforms/pseries/nvram.c | 353 +++- fs/pstore/inode.c |9 + include/linux/pstore.h |4 3 files changed, 313 insertions(+), 53 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 1/8] powerpc/pseries: Remove syslog prefix in uncompressed oops text
Removal of syslog prefix in the uncompressed oops text will help in capturing more oops data. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 8733a86..e54a8b7 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -619,7 +619,7 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, } if (rc != 0) { kmsg_dump_rewind(dumper); - kmsg_dump_get_buffer(dumper, true, + kmsg_dump_get_buffer(dumper, false, oops_data, oops_data_sz, text_len); err_type = ERR_TYPE_KERNEL_PANIC; *oops_len = (u16) text_len; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 2/8] powerpc/pseries: Add version and timestamp to oops header
Introduce version and timestamp information in the oops header. oops_log_info (oops header) holds version (to distinguish between old and new format oops header), length of the oops text (compressed or uncompressed) and timestamp. The version field will sit in the same place as the length in old headers. version is assigned 5000 (greater than oops partition size) so that existing tools will refuse to dump new style partitions as the length is too large. The updated tools will work with both old and new format headers. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 57 +--- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index e54a8b7..742735a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -29,6 +29,13 @@ /* Max bytes to read/write in one go */ #define NVRW_CNT 0x20 +/* + * Set oops header version to distingush between old and new format header. + * lnx,oops-log partition max size is 4000, header version 4000 will + * help in identifying new header. + */ +#define OOPS_HDR_VERSION 5000 + static unsigned int nvram_size; static int nvram_fetch, nvram_store; static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ @@ -67,6 +74,12 @@ static const char *pseries_nvram_os_partitions[] = { NULL }; +struct oops_log_info { + u16 version; + u16 report_length; + u64 timestamp; +} __attribute__((packed)); + static void oops_to_nvram(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason); @@ -83,28 +96,28 @@ static unsigned long last_unread_rtas_event;/* timestamp */ * big_oops_buf[] holds the uncompressed text we're capturing. * - * oops_buf[] holds the compressed text, preceded by a prefix. - * The prefix is just a u16 holding the length of the compressed* text. - * (*Or uncompressed, if compression fails.) oops_buf[] gets written - * to NVRAM. + * oops_buf[] holds the compressed text, preceded by a oops header. + * oops header has u16 holding the version of oops header (to differentiate + * between old and new format header) followed by u16 holding the length of + * the compressed* text (*Or uncompressed, if compression fails.) and u64 + * holding the timestamp. oops_buf[] gets written to NVRAM. * - * oops_len points to the prefix. oops_data points to the compressed text. + * oops_log_info points to the header. oops_data points to the compressed text. * * +- oops_buf - * | +- oops_data - * v v - * ++---+ - * | length| text | - * | (2 bytes) | (oops_data_sz bytes) | - * ++---+ + * | +- oops_data + * v v + * +---+---+---++ + * | version | length| timestamp | text | + * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) | + * +---+---+---++ * ^ - * +- oops_len + * +- oops_log_info * * We preallocate these buffers during init to avoid kmalloc during oops/panic. */ static size_t big_oops_buf_sz; static char *big_oops_buf, *oops_buf; -static u16 *oops_len; static char *oops_data; static size_t oops_data_sz; @@ -425,9 +438,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) oops_log_partition.name); return; } - oops_len = (u16*) oops_buf; - oops_data = oops_buf + sizeof(u16); - oops_data_sz = oops_log_partition.size - sizeof(u16); + oops_data = oops_buf + sizeof(struct oops_log_info); + oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); /* * Figure compression (preceded by elimination of each line's n @@ -555,6 +567,7 @@ error: /* Compress the text from big_oops_buf into oops_buf. */ static int zip_oops(size_t text_len) { + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, oops_data_sz); if (zipped_len 0) { @@ -562,7 +575,9 @@ static int zip_oops(size_t text_len) pr_err(nvram: logging uncompressed oops/panic report\n); return -1; } - *oops_len = (u16) zipped_len; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); return 0; } @@ -576,6 +591,7
[PATCH v2 3/8] powerpc/pseries: Introduce generic read function to read nvram-partitions
Introduce generic read function to read nvram partitions other than rtas. nvram_read_error_log will be retained which is used to read rtas partition from rtasd. nvram_read_partition is the generic read function to read from any nvram partition. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 32 ++-- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 742735a..088f023 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -293,34 +293,35 @@ int nvram_write_error_log(char * buff, int length, return rc; } -/* nvram_read_error_log +/* nvram_read_partition * - * Reads nvram for error log for at most 'length' + * Reads nvram partition for at most 'length' */ -int nvram_read_error_log(char * buff, int length, - unsigned int * err_type, unsigned int * error_log_cnt) +int nvram_read_partition(struct nvram_os_partition *part, char *buff, + int length, unsigned int *err_type, + unsigned int *error_log_cnt) { int rc; loff_t tmp_index; struct err_log_info info; - if (rtas_log_partition.index == -1) + if (part-index == -1) return -1; - if (length rtas_log_partition.size) - length = rtas_log_partition.size; + if (length part-size) + length = part-size; - tmp_index = rtas_log_partition.index; + tmp_index = part-index; rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); return rc; } rc = ppc_md.nvram_read(buff, length, tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); return rc; } @@ -330,6 +331,17 @@ int nvram_read_error_log(char * buff, int length, return 0; } +/* nvram_read_error_log + * + * Reads nvram for error log for at most 'length' + */ +int nvram_read_error_log(char *buff, int length, + unsigned int *err_type, unsigned int *error_log_cnt) +{ + return nvram_read_partition(rtas_log_partition, buff, length, + err_type, error_log_cnt); +} + /* This doesn't actually zero anything, but it sets the event_logged * word to tell that this event is safely in syslog. */ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 4/8] powerpc/pseries: Read/Write oops nvram partition via pstore
IBM's p series machines provide persistent storage for LPARs through NVRAM. NVRAM's lnx,oops-log partition is used to log oops messages. Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose oops partition in NVRAM as a separate file in /dev/pstore. For instance, Oops messages will be stored in a file named [dmesg-nvram-2]. In case pstore registration fails it will fall back to kmsg_dump mechanism. This patch will read/write the oops messages from/to this partition via pstore. Signed-off-by: Jim Keniston jkeni...@us.ibm.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 172 +--- 1 file changed, 157 insertions(+), 15 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 088f023..9edec8e 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,6 +18,7 @@ #include linux/spinlock.h #include linux/slab.h #include linux/kmsg_dump.h +#include linux/pstore.h #include linux/ctype.h #include linux/zlib.h #include asm/uaccess.h @@ -127,6 +128,14 @@ static size_t oops_data_sz; #define MEM_LEVEL 4 static struct z_stream_s stream; +#ifdef CONFIG_PSTORE +static enum pstore_type_id nvram_type_ids[] = { + PSTORE_TYPE_DMESG, + -1 +}; +static int read_type; +#endif + static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) { unsigned int i; @@ -430,6 +439,149 @@ static int __init pseries_nvram_init_os_partition(struct nvram_os_partition return 0; } +/* + * Are we using the ibm,rtas-log for oops/panic reports? And if so, + * would logging this oops/panic overwrite an RTAS event that rtas_errd + * hasn't had a chance to read and process? Return 1 if so, else 0. + * + * We assume that if rtas_errd hasn't read the RTAS event in + * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to. + */ +static int clobbering_unread_rtas_event(void) +{ + return (oops_log_partition.index == rtas_log_partition.index +last_unread_rtas_event +get_seconds() - last_unread_rtas_event = + NVRAM_RTAS_READ_TIMEOUT); +} + +#ifdef CONFIG_PSTORE +static int nvram_pstore_open(struct pstore_info *psi) +{ + /* Reset the iterator to start reading partitions again */ + read_type = -1; + return 0; +} + +/** + * nvram_pstore_write - pstore write callback for nvram + * @type: Type of message logged + * @reason: reason behind dump (oops/panic) + * @id: identifier to indicate the write performed + * @part: pstore writes data to registered buffer in parts, + * part number will indicate the same. + * @count: Indicates oops count + * @size: number of bytes written to the registered buffer + * @psi:registered pstore_info structure + * + * Called by pstore_dump() when an oops or panic report is logged in the + * printk buffer. + * Returns 0 on successful write. + */ +static int nvram_pstore_write(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, int count, + size_t size, struct pstore_info *psi) +{ + int rc; + struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; + + /* part 1 has the recent messages from printk buffer */ + if (part 1 || type != PSTORE_TYPE_DMESG || + clobbering_unread_rtas_event()) + return -1; + + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) size; + oops_hdr-timestamp = get_seconds(); + rc = nvram_write_os_partition(oops_log_partition, oops_buf, + (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + count); + + if (rc != 0) + return rc; + + *id = part; + return 0; +} + +/* + * Reads the oops/panic report. + * Returns the length of the data we read from each partition. + * Returns 0 if we've been called before. + */ +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, + int *count, struct timespec *time, char **buf, + struct pstore_info *psi) +{ + struct oops_log_info *oops_hdr; + unsigned int err_type, id_no; + struct nvram_os_partition *part = NULL; + char *buff = NULL; + + read_type++; + + switch (nvram_type_ids[read_type]) { + case PSTORE_TYPE_DMESG: + part = oops_log_partition; + *type
[PATCH v2 5/8] powerpc/pseries: Read rtas partition via pstore
This patch set exploits the pstore subsystem to read details of rtas partition in NVRAM to a separate file in /dev/pstore. For instance, rtas details will be stored in a file named [rtas-nvram-4]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 33 +--- fs/pstore/inode.c |3 +++ include/linux/pstore.h |2 ++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 9edec8e..8a7eefb 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -131,9 +131,11 @@ static struct z_stream_s stream; #ifdef CONFIG_PSTORE static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, + PSTORE_TYPE_RTAS, -1 }; static int read_type; +static unsigned long last_rtas_event; #endif static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) @@ -297,8 +299,13 @@ int nvram_write_error_log(char * buff, int length, { int rc = nvram_write_os_partition(rtas_log_partition, buff, length, err_type, error_log_cnt); - if (!rc) + if (!rc) { last_unread_rtas_event = get_seconds(); +#ifdef CONFIG_PSTORE + last_rtas_event = get_seconds(); +#endif + } + return rc; } @@ -506,7 +513,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report. + * Reads the oops/panic report and ibm,rtas-log partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -526,6 +533,12 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, part = oops_log_partition; *type = PSTORE_TYPE_DMESG; break; + case PSTORE_TYPE_RTAS: + part = rtas_log_partition; + *type = PSTORE_TYPE_RTAS; + time-tv_sec = last_rtas_event; + time-tv_nsec = 0; + break; default: return 0; } @@ -542,11 +555,17 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, *count = 0; *id = id_no; - oops_hdr = (struct oops_log_info *)buff; - *buf = buff + sizeof(*oops_hdr); - time-tv_sec = oops_hdr-timestamp; - time-tv_nsec = 0; - return oops_hdr-report_length; + + if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { + oops_hdr = (struct oops_log_info *)buff; + *buf = buff + sizeof(*oops_hdr); + time-tv_sec = oops_hdr-timestamp; + time-tv_nsec = 0; + return oops_hdr-report_length; + } + + *buf = buff; + return part-size; } static struct pstore_info nvram_pstore_info = { diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index e4bcb2c..ec24f9c 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -324,6 +324,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_MCE: sprintf(name, mce-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_RTAS: + sprintf(name, rtas-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 75d0176..d7a8fe9 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -35,6 +35,8 @@ enum pstore_type_id { PSTORE_TYPE_MCE = 1, PSTORE_TYPE_CONSOLE = 2, PSTORE_TYPE_FTRACE = 3, + /* PPC64 partition types */ + PSTORE_TYPE_PPC_RTAS= 4, PSTORE_TYPE_UNKNOWN = 255 }; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 6/8] powerpc/pseries: Distinguish between a os-partition and non-os partition
Introduce os_partition member in nvram_os_partition structure to identify if the partition is an os partition or not. This will be useful to handle non-os partitions of-config and common. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 8a7eefb..b118382 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -53,20 +53,23 @@ struct nvram_os_partition { int min_size; /* minimum acceptable size (0 means req_size) */ long size; /* size of data portion (excluding err_log_info) */ long index; /* offset of data portion of partition */ + bool os_partition; /* partition initialized by OS, not FW */ }; static struct nvram_os_partition rtas_log_partition = { .name = ibm,rtas-log, .req_size = 2079, .min_size = 1055, - .index = -1 + .index = -1, + .os_partition = true }; static struct nvram_os_partition oops_log_partition = { .name = lnx,oops-log, .req_size = 4000, .min_size = 2000, - .index = -1 + .index = -1, + .os_partition = true }; static const char *pseries_nvram_os_partitions[] = { ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH v2 7/8] powerpc/pseries: Read of-config partition via pstore
This patch set exploits the pstore subsystem to read details of of-config partition in NVRAM to a separate file in /dev/pstore. For instance, of-config partition details will be stored in a file named [of-nvram-5]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 55 +++- fs/pstore/inode.c |3 ++ include/linux/pstore.h |1 + 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index b118382..de448af 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -132,9 +132,16 @@ static size_t oops_data_sz; static struct z_stream_s stream; #ifdef CONFIG_PSTORE +static struct nvram_os_partition of_config_partition = { + .name = of-config, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_RTAS, + PSTORE_TYPE_OF, -1 }; static int read_type; @@ -332,10 +339,15 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, tmp_index = part-index; - rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); - if (rc = 0) { - pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); - return rc; + if (part-os_partition) { + rc = ppc_md.nvram_read((char *)info, + sizeof(struct err_log_info), + tmp_index); + if (rc = 0) { + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, + rc); + return rc; + } } rc = ppc_md.nvram_read(buff, length, tmp_index); @@ -344,8 +356,10 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, return rc; } - *error_log_cnt = info.seq_num; - *err_type = info.error_type; + if (part-os_partition) { + *error_log_cnt = info.seq_num; + *err_type = info.error_type; + } return 0; } @@ -516,7 +530,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report and ibm,rtas-log partition. + * Reads the oops/panic report, rtas and of-config partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -525,9 +539,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct pstore_info *psi) { struct oops_log_info *oops_hdr; - unsigned int err_type, id_no; + unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; char *buff = NULL; + int sig = 0; + loff_t p; read_type++; @@ -542,10 +558,29 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = last_rtas_event; time-tv_nsec = 0; break; + case PSTORE_TYPE_OF: + sig = NVRAM_SIG_OF; + part = of_config_partition; + *type = PSTORE_TYPE_OF; + *id = PSTORE_TYPE_OF; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } + if (!part-os_partition) { + p = nvram_find_partition(part-name, sig, size); + if (p = 0) { + pr_err(nvram: Failed to find partition %s, + err %d\n, part-name, (int)p); + return 0; + } + part-index = p; + part-size = size; + } + buff = kmalloc(part-size, GFP_KERNEL); if (!buff) @@ -557,7 +592,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, } *count = 0; - *id = id_no; + + if (part-os_partition) + *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { oops_hdr = (struct oops_log_info *)buff; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index ec24f9c..8d4fb65 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -327,6 +327,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_RTAS: sprintf(name, rtas-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_OF: + sprintf(name, of-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id
[PATCH v2 8/8] powerpc/pseries: Read common partition via pstore
This patch exploits pstore subsystem to read details of common partition in NVRAM to a separate file in /dev/pstore. For instance, common partition details will be stored in a file named [common-nvram-6]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 17 - fs/pstore/inode.c |3 +++ include/linux/pstore.h |1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index de448af..8417816 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -138,10 +138,17 @@ static struct nvram_os_partition of_config_partition = { .os_partition = false }; +static struct nvram_os_partition common_partition = { + .name = common, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_RTAS, PSTORE_TYPE_OF, + PSTORE_TYPE_COMMON, -1 }; static int read_type; @@ -530,7 +537,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report, rtas and of-config partition. + * Reads the oops/panic report, rtas, of-config and common partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -566,6 +573,14 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = 0; time-tv_nsec = 0; break; + case PSTORE_TYPE_COMMON: + sig = NVRAM_SIG_SYS; + part = common_partition; + *type = PSTORE_TYPE_COMMON; + *id = PSTORE_TYPE_COMMON; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 8d4fb65..88cc050 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -330,6 +330,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_OF: sprintf(name, of-%s-%lld, psname, id); break; + case PSTORE_TYPE_PPC_COMMON: + sprintf(name, common-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 615dc18..656699f 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -38,6 +38,7 @@ enum pstore_type_id { /* PPC64 partition types */ PSTORE_TYPE_PPC_RTAS= 4, PSTORE_TYPE_PPC_OF = 5, + PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_UNKNOWN = 255 }; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v2 7/8] powerpc/pseries: Read of-config partition via pstore
On Thursday 25 April 2013 02:13 AM, Kees Cook wrote: Hi Kees, On Tue, Apr 23, 2013 at 11:20 PM, Aruna Balakrishnaiah ar...@linux.vnet.ibm.com wrote: This patch set exploits the pstore subsystem to read details of of-config partition in NVRAM to a separate file in /dev/pstore. For instance, of-config partition details will be stored in a file named [of-nvram-5]. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 55 +++- fs/pstore/inode.c |3 ++ include/linux/pstore.h |1 + 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index b118382..de448af 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -132,9 +132,16 @@ static size_t oops_data_sz; static struct z_stream_s stream; #ifdef CONFIG_PSTORE +static struct nvram_os_partition of_config_partition = { + .name = of-config, + .index = -1, + .os_partition = false +}; + static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, PSTORE_TYPE_RTAS, + PSTORE_TYPE_OF, -1 }; static int read_type; @@ -332,10 +339,15 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, tmp_index = part-index; - rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); - if (rc = 0) { - pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, rc); - return rc; + if (part-os_partition) { + rc = ppc_md.nvram_read((char *)info, + sizeof(struct err_log_info), + tmp_index); + if (rc = 0) { + pr_err(%s: Failed nvram_read (%d)\n, __FUNCTION__, + rc); + return rc; + } } rc = ppc_md.nvram_read(buff, length, tmp_index); @@ -344,8 +356,10 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, return rc; } - *error_log_cnt = info.seq_num; - *err_type = info.error_type; + if (part-os_partition) { + *error_log_cnt = info.seq_num; + *err_type = info.error_type; + } return 0; } @@ -516,7 +530,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report and ibm,rtas-log partition. + * Reads the oops/panic report, rtas and of-config partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -525,9 +539,11 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, struct pstore_info *psi) { struct oops_log_info *oops_hdr; - unsigned int err_type, id_no; + unsigned int err_type, id_no, size = 0; struct nvram_os_partition *part = NULL; char *buff = NULL; + int sig = 0; + loff_t p; read_type++; @@ -542,10 +558,29 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, time-tv_sec = last_rtas_event; time-tv_nsec = 0; break; + case PSTORE_TYPE_OF: + sig = NVRAM_SIG_OF; + part = of_config_partition; + *type = PSTORE_TYPE_OF; + *id = PSTORE_TYPE_OF; + time-tv_sec = 0; + time-tv_nsec = 0; + break; default: return 0; } + if (!part-os_partition) { + p = nvram_find_partition(part-name, sig, size); + if (p = 0) { + pr_err(nvram: Failed to find partition %s, + err %d\n, part-name, (int)p); + return 0; + } + part-index = p; + part-size = size; + } + buff = kmalloc(part-size, GFP_KERNEL); if (!buff) @@ -557,7 +592,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, } *count = 0; - *id = id_no; + + if (part-os_partition) + *id = id_no; if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { oops_hdr = (struct oops_log_info *)buff; diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index ec24f9c..8d4fb65 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -327,6 +327,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_PPC_RTAS: sprintf(name, rtas-%s-%lld, psname, id); break; + case
Re: [PATCH v2 0/8] powerpc/pseries: Nvram-to-pstore
Hi Kees, On Thursday 25 April 2013 02:15 AM, Kees Cook wrote: On Tue, Apr 23, 2013 at 11:19 PM, Aruna Balakrishnaiah ar...@linux.vnet.ibm.com wrote: Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose each partition in NVRAM as a separate file in /dev/pstore. For instance Oops messages will stored in a file named [dmesg-nvram-2]. Changes from v1: - Reduce #ifdefs by and remove forward declarations of pstore callbacks - Handle return value of nvram_write_os_partition - Remove empty pstore callbacks and register pstore only when pstore is configured --- Aruna Balakrishnaiah (8): powerpc/pseries: Remove syslog prefix in uncompressed oops text powerpc/pseries: Add version and timestamp to oops header powerpc/pseries: Introduce generic read function to read nvram-partitions powerpc/pseries: Read/Write oops nvram partition via pstore powerpc/pseries: Read rtas partition via pstore powerpc/pseries: Distinguish between a os-partition and non-os partition powerpc/pseries: Read of-config partition via pstore powerpc/pseries: Read common partition via pstore arch/powerpc/platforms/pseries/nvram.c | 353 +++- fs/pstore/inode.c |9 + include/linux/pstore.h |4 3 files changed, 313 insertions(+), 53 deletions(-) This series looks good! Other than the naming conventions (are these new pstore types really PPC-only?) I think it's a fine addition. Thanks! The new pstore types are PPC specific. Hence it would be better to have the (_PPC) in the type ids so that other does not end up using these ids. -Kees -- Kees Cook Chrome OS Security ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 4/8] Read/Write oops nvram partition via pstore
Hi Michael, Thanks for reviewing my patches. On Monday 15 April 2013 01:25 PM, Michael Ellerman wrote: On Wed, Apr 10, 2013 at 12:53:03PM +0530, Aruna Balakrishnaiah wrote: This patch exploits pstore infrastructure in power systems. IBM's system p machines provide persistent storage for LPARs In the kernel we use pseries instead of system p. Sure, will change it. through NVRAM. NVRAM's lnx,oops-log partition is used to log oops messages. In case pstore registration fails it will fall back to kmsg_dump mechanism. What are the implications of falling back to kmsg_dump()? Logging oops messages to nvram should not fail in case pstore registration fails. So it falls back to existing kmsg_dump infrastructure where oops_to_nvram will be called. The users would need to use existing tools to read nvram data as it is now. Is there any reason we would not want to enable CONFIG_PSTORE ? ie. should the pseries platform just select it? Since current patchset does not support compression, selecting PSTORE by default will lose the existing compression feature. Once the compression feature for PSTORE is in place we can make PSTORE as default on power. I will post the compression patches soon. The reason for posting it separately is stated below. diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 6701b71..82d32a2 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,6 +18,7 @@ #include linux/spinlock.h #include linux/slab.h #include linux/kmsg_dump.h +#include linux/pstore.h #include linux/ctype.h #include linux/zlib.h #include asm/uaccess.h @@ -87,6 +88,25 @@ static struct kmsg_dumper nvram_kmsg_dumper = { .dump = oops_to_nvram }; +static int nvram_pstore_open(struct pstore_info *psi); + +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, + int *count, struct timespec *time, char **buf, + 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 size, + struct pstore_info *psi); I think you should be able to rearrange this so that you don't need the forward declarations. Sure. This would result in moving the callback functions just before pstore registration for which I need to move clobbering_unread_rtas_event() which is used by nvram_pstore_write. + +static struct pstore_info nvram_pstore_info = { + .owner = THIS_MODULE, + .name = nvram, + .open = nvram_pstore_open, + .read = nvram_pstore_read, + .write = nvram_pstore_write, +}; + /* See clobbering_unread_rtas_event() */ #define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */ static unsigned long last_unread_rtas_event; /* timestamp */ @@ -121,6 +141,13 @@ static char *big_oops_buf, *oops_buf; static char *oops_data; static size_t oops_data_sz; +#ifdef CONFIG_PSTORE If we are going to have CONFIG_PSTORE #ifdefs in this file, I don't see why there can't be just a single block of code that is #ifdef'ed, rather than several like you have. Sure. I will have one #ifdef for declarations and one for function definitions. +static enum pstore_type_id nvram_type_ids[] = { + PSTORE_TYPE_DMESG, + -1 +}; +static int read_type; I don't understand what you're doing with read_type. It looks fishy. read_type is an iterator to traverse the partition types. It is to know which partition we need to read. +#endif /* Compression parameters */ #define COMPR_LEVEL 6 #define WINDOW_BITS 12 @@ -455,6 +482,23 @@ 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); + nvram_pstore_info.buf = oops_data; + nvram_pstore_info.bufsize = oops_data_sz; + + rc = pstore_register(nvram_pstore_info); + + if (rc != 0) { + pr_err(nvram: pstore_register() failed, defaults to + kmsg_dump; returned %d\n, rc); + goto kmsg_dump; You don't need the goto. Yeah, my bad. Will fix it. + } else { + /*TODO: Support compression when pstore is configured */ What is the issue here? Currently with this patchset, pstore is not supporting compression of oops-messages since it involves some changes in the pstore framework. big_oops_buf will hold the large part of oops data which will be compressed and put to oops_buf. big_oops_buf: (1.45 of oops_partition_size) _ | header | oops-text | |_|_| header is added by the pstore. So in case compression fails: we would need to log the header + last few bytes of big_oops_buf
Re: [PATCH 5/8] Read rtas partition via pstore
On Monday 15 April 2013 01:31 PM, Michael Ellerman wrote: On Wed, Apr 10, 2013 at 12:53:27PM +0530, Aruna Balakrishnaiah wrote: This patch exploits pstore infrastructure to read the details from NVRAM's rtas partition. Does that mean it's exposed in the pstore filesystem? Yeah thats right. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 33 +--- fs/pstore/inode.c |3 +++ include/linux/pstore.h |2 ++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 82d32a2..d420b1d 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -144,9 +144,11 @@ static size_t oops_data_sz; #ifdef CONFIG_PSTORE static enum pstore_type_id nvram_type_ids[] = { PSTORE_TYPE_DMESG, + PSTORE_TYPE_RTAS, -1 }; static int read_type; +static unsigned long last_rtas_event; #endif /* Compression parameters */ #define COMPR_LEVEL 6 @@ -315,8 +317,13 @@ int nvram_write_error_log(char * buff, int length, { int rc = nvram_write_os_partition(rtas_log_partition, buff, length, err_type, error_log_cnt); - if (!rc) + if (!rc) { last_unread_rtas_event = get_seconds(); +#ifdef CONFIG_PSTORE + last_rtas_event = get_seconds(); +#endif + } + return rc; } @@ -745,7 +752,7 @@ static int nvram_pstore_write(enum pstore_type_id type, } /* - * Reads the oops/panic report. + * Reads the oops/panic report and ibm,rtas-log partition. * Returns the length of the data we read from each partition. * Returns 0 if we've been called before. */ @@ -765,6 +772,12 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, part = oops_log_partition; *type = PSTORE_TYPE_DMESG; break; + case PSTORE_TYPE_RTAS: + part = rtas_log_partition; + *type = PSTORE_TYPE_RTAS; + time-tv_sec = last_rtas_event; + time-tv_nsec = 0; + break; default: return 0; } @@ -781,11 +794,17 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, *count = 0; *id = id_no; - oops_hdr = (struct oops_log_info *)buff; - *buf = buff + sizeof(*oops_hdr); - time-tv_sec = oops_hdr-timestamp; - time-tv_nsec = 0; - return oops_hdr-report_length; + + if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) { + oops_hdr = (struct oops_log_info *)buff; + *buf = buff + sizeof(*oops_hdr); + time-tv_sec = oops_hdr-timestamp; + time-tv_nsec = 0; + return oops_hdr-report_length; + } + + *buf = buff; + return part-size; } #else static int nvram_pstore_open(struct pstore_info *psi) diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index e4bcb2c..59b1454 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -324,6 +324,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, case PSTORE_TYPE_MCE: sprintf(name, mce-%s-%lld, psname, id); break; + case PSTORE_TYPE_RTAS: + sprintf(name, rtas-%s-%lld, psname, id); + break; case PSTORE_TYPE_UNKNOWN: sprintf(name, unknown-%s-%lld, psname, id); break; diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 75d0176..4eb94c9 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -35,6 +35,8 @@ enum pstore_type_id { PSTORE_TYPE_MCE = 1, PSTORE_TYPE_CONSOLE = 2, PSTORE_TYPE_FTRACE = 3, + /* PPC64 partition types */ + PSTORE_TYPE_RTAS= 10, PSTORE_TYPE_UNKNOWN = 255 I think you should probably just continue at 4, and call it PSTORE_TYPE_PPC_RTAS. But you must get an ACK from the pstore maintainers for this and the previous hunk, and I don't see them on CC. Sure, will add them on cc in my next version of the patches. cheers ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH 4/8] Read/Write oops nvram partition via pstore
On Tuesday 16 April 2013 12:44 PM, Benjamin Herrenschmidt wrote: On Tue, 2013-04-16 at 11:50 +0530, Aruna Balakrishnaiah wrote: Sure. I will have one #ifdef for declarations and one for function definitions. Declarations generally don't need #ifdef's Sorry by declarations I meant variable declarations (used by pstore) not function declarations. Cheers, Ben. ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 0/8] Nvram-to-pstore
Currently the kernel provides the contents of p-series NVRAM only as a simple stream of bytes via /dev/nvram, which must be interpreted in user space by the nvram command in the powerpc-utils package. This patch set exploits the pstore subsystem to expose each partition in NVRAM as a separate file in /dev/pstore. For instance Oops messages will stored in a file named [dmesg-nvram-2]. --- Aruna Balakrishnaiah (8): Remove syslog prefix in uncompressed oops text Add version and timestamp to oops header Introduce generic read function to read nvram-partitions Read/Write oops nvram partition via pstore Read rtas partition via pstore Distinguish between a os-partition and non-os partition Read of-config partition via pstore Read common partition via pstore arch/powerpc/platforms/pseries/nvram.c | 329 fs/pstore/inode.c |9 + include/linux/pstore.h |4 3 files changed, 304 insertions(+), 38 deletions(-) -- ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 1/8] Remove syslog prefix in uncompressed oops text
Removal of syslog prefix in the uncompressed oops text will help in capturing more oops data. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 8733a86..e54a8b7 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -619,7 +619,7 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, } if (rc != 0) { kmsg_dump_rewind(dumper); - kmsg_dump_get_buffer(dumper, true, + kmsg_dump_get_buffer(dumper, false, oops_data, oops_data_sz, text_len); err_type = ERR_TYPE_KERNEL_PANIC; *oops_len = (u16) text_len; ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 2/8] Add version and timestamp to oops header
Introduce version and timestamp information in the oops header. oops_log_info (oops header) holds version (to distinguish between old and new format oops header), length of the oops text (compressed or uncompressed) and timestamp. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 57 +--- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index e54a8b7..742735a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -29,6 +29,13 @@ /* Max bytes to read/write in one go */ #define NVRW_CNT 0x20 +/* + * Set oops header version to distingush between old and new format header. + * lnx,oops-log partition max size is 4000, header version 4000 will + * help in identifying new header. + */ +#define OOPS_HDR_VERSION 5000 + static unsigned int nvram_size; static int nvram_fetch, nvram_store; static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ @@ -67,6 +74,12 @@ static const char *pseries_nvram_os_partitions[] = { NULL }; +struct oops_log_info { + u16 version; + u16 report_length; + u64 timestamp; +} __attribute__((packed)); + static void oops_to_nvram(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason); @@ -83,28 +96,28 @@ static unsigned long last_unread_rtas_event;/* timestamp */ * big_oops_buf[] holds the uncompressed text we're capturing. * - * oops_buf[] holds the compressed text, preceded by a prefix. - * The prefix is just a u16 holding the length of the compressed* text. - * (*Or uncompressed, if compression fails.) oops_buf[] gets written - * to NVRAM. + * oops_buf[] holds the compressed text, preceded by a oops header. + * oops header has u16 holding the version of oops header (to differentiate + * between old and new format header) followed by u16 holding the length of + * the compressed* text (*Or uncompressed, if compression fails.) and u64 + * holding the timestamp. oops_buf[] gets written to NVRAM. * - * oops_len points to the prefix. oops_data points to the compressed text. + * oops_log_info points to the header. oops_data points to the compressed text. * * +- oops_buf - * | +- oops_data - * v v - * ++---+ - * | length| text | - * | (2 bytes) | (oops_data_sz bytes) | - * ++---+ + * | +- oops_data + * v v + * +---+---+---++ + * | version | length| timestamp | text | + * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) | + * +---+---+---++ * ^ - * +- oops_len + * +- oops_log_info * * We preallocate these buffers during init to avoid kmalloc during oops/panic. */ static size_t big_oops_buf_sz; static char *big_oops_buf, *oops_buf; -static u16 *oops_len; static char *oops_data; static size_t oops_data_sz; @@ -425,9 +438,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) oops_log_partition.name); return; } - oops_len = (u16*) oops_buf; - oops_data = oops_buf + sizeof(u16); - oops_data_sz = oops_log_partition.size - sizeof(u16); + oops_data = oops_buf + sizeof(struct oops_log_info); + oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); /* * Figure compression (preceded by elimination of each line's n @@ -555,6 +567,7 @@ error: /* Compress the text from big_oops_buf into oops_buf. */ static int zip_oops(size_t text_len) { + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, oops_data_sz); if (zipped_len 0) { @@ -562,7 +575,9 @@ static int zip_oops(size_t text_len) pr_err(nvram: logging uncompressed oops/panic report\n); return -1; } - *oops_len = (u16) zipped_len; + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) zipped_len; + oops_hdr-timestamp = get_seconds(); return 0; } @@ -576,6 +591,7 @@ static int zip_oops(size_t text_len) static void oops_to_nvram(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) { + struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; static unsigned int oops_count = 0; static bool
[PATCH 3/8] Introduce generic read function to read nvram-partitions
Introduce generic read function to read nvram partitions other than rtas. nvram_read_error_log will be retained which is used to read rtas partition from rtasd. nvram_read_partition is the generic read function to read from any nvram partition. Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com Reviewed-by: Jim Keniston jkeni...@us.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 34 +++- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 742735a..6701b71 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -293,34 +293,37 @@ int nvram_write_error_log(char * buff, int length, return rc; } -/* nvram_read_error_log +/* nvram_read_partition * - * Reads nvram for error log for at most 'length' + * Reads nvram partition for at most 'length' */ -int nvram_read_error_log(char * buff, int length, - unsigned int * err_type, unsigned int * error_log_cnt) +int nvram_read_partition(struct nvram_os_partition *part, char *buff, + int length, unsigned int *err_type, + unsigned int *error_log_cnt) { int rc; loff_t tmp_index; struct err_log_info info; - if (rtas_log_partition.index == -1) + if (part-index == -1) return -1; - if (length rtas_log_partition.size) - length = rtas_log_partition.size; + if (length part-size) + length = part-size; - tmp_index = rtas_log_partition.index; + tmp_index = part-index; rc = ppc_md.nvram_read((char *)info, sizeof(struct err_log_info), tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + printk(KERN_ERR nvram_read_partition: + Failed nvram_read (%d)\n, rc); return rc; } rc = ppc_md.nvram_read(buff, length, tmp_index); if (rc = 0) { - printk(KERN_ERR nvram_read_error_log: Failed nvram_read (%d)\n, rc); + printk(KERN_ERR nvram_read_partition: + Failed nvram_read (%d)\n, rc); return rc; } @@ -330,6 +333,17 @@ int nvram_read_error_log(char * buff, int length, return 0; } +/* nvram_read_error_log + * + * Reads nvram for error log for at most 'length' + */ +int nvram_read_error_log(char *buff, int length, + unsigned int *err_type, unsigned int *error_log_cnt) +{ + return nvram_read_partition(rtas_log_partition, buff, length, + err_type, error_log_cnt); +} + /* This doesn't actually zero anything, but it sets the event_logged * word to tell that this event is safely in syslog. */ ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
[PATCH 4/8] Read/Write oops nvram partition via pstore
This patch exploits pstore infrastructure in power systems. IBM's system p machines provide persistent storage for LPARs through NVRAM. NVRAM's lnx,oops-log partition is used to log oops messages. In case pstore registration fails it will fall back to kmsg_dump mechanism. This patch will read/write the oops messages from/to this partition via pstore. Signed-off-by: Jim Keniston jkeni...@us.ibm.com Signed-off-by: Aruna Balakrishnaiah ar...@linux.vnet.ibm.com --- arch/powerpc/platforms/pseries/nvram.c | 145 1 file changed, 145 insertions(+) diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 6701b71..82d32a2 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,6 +18,7 @@ #include linux/spinlock.h #include linux/slab.h #include linux/kmsg_dump.h +#include linux/pstore.h #include linux/ctype.h #include linux/zlib.h #include asm/uaccess.h @@ -87,6 +88,25 @@ static struct kmsg_dumper nvram_kmsg_dumper = { .dump = oops_to_nvram }; +static int nvram_pstore_open(struct pstore_info *psi); + +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, + int *count, struct timespec *time, char **buf, + 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 size, + struct pstore_info *psi); + +static struct pstore_info nvram_pstore_info = { + .owner = THIS_MODULE, + .name = nvram, + .open = nvram_pstore_open, + .read = nvram_pstore_read, + .write = nvram_pstore_write, +}; + /* See clobbering_unread_rtas_event() */ #define NVRAM_RTAS_READ_TIMEOUT 5 /* seconds */ static unsigned long last_unread_rtas_event; /* timestamp */ @@ -121,6 +141,13 @@ static char *big_oops_buf, *oops_buf; static char *oops_data; static size_t oops_data_sz; +#ifdef CONFIG_PSTORE +static enum pstore_type_id nvram_type_ids[] = { + PSTORE_TYPE_DMESG, + -1 +}; +static int read_type; +#endif /* Compression parameters */ #define COMPR_LEVEL 6 #define WINDOW_BITS 12 @@ -455,6 +482,23 @@ 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); + nvram_pstore_info.buf = oops_data; + nvram_pstore_info.bufsize = oops_data_sz; + + rc = pstore_register(nvram_pstore_info); + + if (rc != 0) { + pr_err(nvram: pstore_register() failed, defaults to + kmsg_dump; returned %d\n, rc); + goto kmsg_dump; + } else { + /*TODO: Support compression when pstore is configured */ + pr_info(nvram: Compression of oops text supported only when + pstore is not configured); + return; + } + +kmsg_dump: /* * Figure compression (preceded by elimination of each line's n * severity prefix) will reduce the oops/panic report to at most @@ -663,3 +707,104 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, spin_unlock_irqrestore(lock, flags); } + +#ifdef CONFIG_PSTORE +static int nvram_pstore_open(struct pstore_info *psi) +{ + read_type = -1; + return 0; +} + +/* + * Called by pstore_dump() when an oops or panic report is logged to the printk + * buffer. @size bytes have been written to oops_buf, starting after the + * oops_log_info header. + */ +static int nvram_pstore_write(enum pstore_type_id type, + enum kmsg_dump_reason reason, + u64 *id, unsigned int part, int count, + size_t size, struct pstore_info *psi) +{ + struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf; + + /* part 1 has the recent messages from printk buffer */ + if (part 1 || clobbering_unread_rtas_event()) + return -1; + + BUG_ON(type != PSTORE_TYPE_DMESG); + BUG_ON(sizeof(*oops_hdr) + size oops_log_partition.size); + oops_hdr-version = OOPS_HDR_VERSION; + oops_hdr-report_length = (u16) size; + oops_hdr-timestamp = get_seconds(); + (void) nvram_write_os_partition(oops_log_partition, oops_buf, + (int) (sizeof(*oops_hdr) + size), ERR_TYPE_KERNEL_PANIC, + count); + *id = part; + + return 0; +} + +/* + * Reads the oops/panic report. + * Returns the length of the data we read from each partition. + * Returns 0 if we've been called before. + */ +static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, + int *count