2022-12-28 13:14:56

by Qiujun Huang

[permalink] [raw]
Subject: [PATCH]pstore/zone: Preallocate zone buffer for psz_kmsg_write_record

The case found when triggering a panic_on_oom, pstore fails to dump
kmsg.
Partly fixed by: commit 99b3b837855b ("pstore/zone: Use GFP_ATOMIC to
allocate zone buffer"). After the patch, it also fails sometimes. As I use
64k as kmsg_size, it's hard to get 4-order free pages sometimes at this
case. So it's better to preallocate the buffer.

Signed-off-by: Qiujun Huang <[email protected]>
---
fs/pstore/zone.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c
index 2770746bb7aa..86e47dbc9d53 100644
--- a/fs/pstore/zone.c
+++ b/fs/pstore/zone.c
@@ -136,6 +136,7 @@ struct psz_context {
struct mutex pstore_zone_info_lock;
struct pstore_zone_info *pstore_zone_info;
struct pstore_info pstore;
+ struct psz_buffer *kmsg_buf_swap;
};
static struct psz_context pstore_zone_cxt;

@@ -758,14 +759,11 @@ static inline int notrace psz_kmsg_write_record(struct psz_context *cxt,
if (unlikely(!zone))
return -ENOSPC;

- /* avoid destroying old data, allocate a new one */
+ /* avoid destroying old data, use the swap buffer */
len = zone->buffer_size + sizeof(*zone->buffer);
zone->oldbuf = zone->buffer;
- zone->buffer = kzalloc(len, GFP_ATOMIC);
- if (!zone->buffer) {
- zone->buffer = zone->oldbuf;
- return -ENOMEM;
- }
+ zone->buffer = cxt->kmsg_buf_swap;
+ memset(zone->buffer, 0, len);
zone->buffer->sig = zone->oldbuf->sig;

pr_debug("write %s to zone id %d\n", zone->name, zonenum);
@@ -776,15 +774,14 @@ static inline int notrace psz_kmsg_write_record(struct psz_context *cxt,
if (likely(!ret || ret != -ENOMSG)) {
cxt->kmsg_write_cnt = zonenum + 1;
cxt->kmsg_write_cnt %= cxt->kmsg_max_cnt;
- /* no need to try next zone, free last zone buffer */
- kfree(zone->oldbuf);
+ /* no need to try next zone, put last one to swap buffer */
+ cxt->kmsg_buf_swap = zone->oldbuf;
zone->oldbuf = NULL;
return ret;
}

pr_debug("zone %u may be broken, try next dmesg zone\n",
zonenum);
- kfree(zone->buffer);
zone->buffer = zone->oldbuf;
zone->oldbuf = NULL;
}
@@ -1373,6 +1370,12 @@ int register_pstore_zone(struct pstore_zone_info *info)
err = -ENOMEM;
goto fail_free;
}
+
+ cxt->kmsg_buf_swap = kzalloc(info->kmsg_size, GFP_KERNEL);
+ if (!cxt->kmsg_buf_swap) {
+ err = -ENOMEM;
+ goto fail_free;
+ }
}
cxt->pstore.data = cxt;

@@ -1411,6 +1414,8 @@ int register_pstore_zone(struct pstore_zone_info *info)
return 0;

fail_free:
+ kfree(cxt->kmsg_buf_swap);
+ cxt->kmsg_buf_swap = NULL;
kfree(cxt->pstore.buf);
cxt->pstore.buf = NULL;
cxt->pstore.bufsize = 0;
@@ -1445,6 +1450,9 @@ void unregister_pstore_zone(struct pstore_zone_info *info)
flush_delayed_work(&psz_cleaner);

/* Clean up allocations. */
+ kfree(cxt->kmsg_buf_swap);
+ cxt->kmsg_buf_swap = NULL;
+
kfree(cxt->pstore.buf);
cxt->pstore.buf = NULL;
cxt->pstore.bufsize = 0;
--
2.30.2