@@ -68,6 +68,7 @@ static DECLARE_WORK(pstore_work, pstore_dowork);
* the filesystem mount/unmount routines.
*/
static DEFINE_MUTEX(psinfo_lock);
+static DEFINE_MUTEX(ps_dmr_lock);
struct pstore_info *psinfo;
static char *backend;
@@ -99,6 +100,12 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
static void *compress_workspace;
+static LIST_HEAD(rec_list);
+struct rec_list_t {
+ struct pstore_record rec;
+ struct list_head list;
+};
+
/*
* Compression is only used for dmesg output, which consists of low-entropy
* ASCII text, and so we can assume worst-case 60%.
@@ -271,6 +278,66 @@ void pstore_record_init(struct pstore_record *record,
record->time = ns_to_timespec64(ktime_get_real_fast_ns());
}
+int pstore_register_core_area(const char *handle, void *area, size_t size)
+{
+ struct rec_list_t *rec_element = kzalloc(sizeof (*rec_element), GFP_KERNEL);
+ struct pstore_record *record = &rec_element->rec;
+ int ret;
+
+ if (!psinfo || !psinfo->register_dmr) {
+ pr_err("No pstore available ! Bailing out.\n");
+ return -EAGAIN;
+ }
+
+ pstore_record_init(record, psinfo);
+ record->type = PSTORE_TYPE_DMAPPED;
+ record->buf = area;
+ record->size = size;
+
+ if (handle) {
+ record->priv = kmalloc(8, GFP_KERNEL);
+ strncpy(record->priv, handle, 8);
+ }
+
+ mutex_lock(&ps_dmr_lock);
+
+ ret = psinfo->register_dmr(record);
+ if (!ret)
+ list_add(&rec_element->list, &rec_list);
+
+ mutex_unlock(&ps_dmr_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pstore_register_core_area);
+
+int pstore_unregister_core_area(const char *handle, void *area, size_t size)
+{
+ struct rec_list_t *rec_element, *tmp;
+ int ret;
+
+ if (!psinfo || !psinfo->unregister_dmr)
+ return -EAGAIN;
+
+ mutex_lock(&ps_dmr_lock);
+ list_for_each_entry_safe(rec_element, tmp, &rec_list, list) {
+ struct pstore_record *record;
+
+ record = &rec_element->rec;
+
+ if (record->buf == area) {
+ ret = psinfo->unregister_dmr(record);
+ list_del(&rec_element->list);
+ mutex_unlock(&ps_dmr_lock);
+ return 0;
+ }
+ }
+
+ mutex_unlock(&ps_dmr_lock);
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(pstore_unregister_core_area);
+
/*
* callback from kmsg_dump. Save as much as we can (up to kmsg_bytes) from the
* end of the buffer.
@@ -35,6 +35,7 @@ struct psz_buffer {
uint32_t sig;
atomic_t datalen;
atomic_t start;
+ void *data_ptr;
uint8_t data[];
};
@@ -822,6 +823,38 @@ static int notrace psz_kmsg_write(struct psz_context *cxt,
return 0;
}
+static int notrace psz_register_dmr_record(struct pstore_zone *zone,
+ struct pstore_record *record)
+{
+ struct pstore_zone_info *info = pstore_zone_cxt.pstore_zone_info;
+ int ret;
+
+ if (!info->register_dmr)
+ return -ENOTSUPP;
+
+ zone->buffer->data_ptr = record->buf;
+ atomic_set(&zone->buffer->datalen, record->size);
+
+ ret = info->register_dmr(record->priv, record->id, record->buf,
+ record->size);
+ if (!ret)
+ atomic_set(&zone->dirty, true);
+ return ret;
+}
+
+static int psz_unregister_dmr_zone(struct pstore_zone *zone)
+{
+ struct pstore_zone_info *info = pstore_zone_cxt.pstore_zone_info;
+ if (!info->unregister_dmr)
+ return -ENOTSUPP;
+
+ info->unregister_dmr(zone->buffer->data_ptr,
+ atomic_read(&zone->buffer->datalen));
+
+ atomic_set(&zone->dirty, false);
+ return 0;
+}
+
static int notrace psz_record_write(struct pstore_zone *zone,
struct pstore_record *record)
{
@@ -906,6 +939,48 @@ static int notrace psz_pstore_write(struct pstore_record *record)
}
}
+static int pstore_unregister_dmr(struct pstore_record *record)
+{
+ struct psz_context *cxt = record->psi->data;
+ int c = 0;
+
+ if (!cxt->dmszs)
+ return -ENODEV;
+
+ while (c < cxt->dmapped_max_cnt) {
+ if (!atomic_read(&cxt->dmszs[c]->dirty))
+ continue;
+
+ if (cxt->dmszs[c]->buffer->data_ptr == record->buf)
+ return psz_unregister_dmr_zone(cxt->dmszs[c]);
+ c++;
+ }
+
+ return -ENOENT;
+}
+
+static int pstore_register_dmr(struct pstore_record *record)
+{
+ struct psz_context *cxt = record->psi->data;
+ int c = 0;
+
+ if (!cxt->dmszs)
+ return -ENODEV;
+
+ while (c < cxt->dmapped_max_cnt) {
+ if (!atomic_read(&cxt->dmszs[c]->dirty))
+ break;
+ c++;
+ }
+
+ if (c == cxt->dmapped_max_cnt)
+ return -ENOSPC;
+
+ record->id = c;
+
+ return psz_register_dmr_record(cxt->dmszs[c], record);
+}
+
static struct pstore_zone *psz_read_next_zone(struct psz_context *cxt)
{
struct pstore_zone *zone = NULL;
@@ -1110,6 +1185,8 @@ static struct psz_context pstore_zone_cxt = {
.read = psz_pstore_read,
.write = psz_pstore_write,
.erase = psz_pstore_erase,
+ .register_dmr = pstore_register_dmr,
+ .unregister_dmr = pstore_unregister_dmr,
},
};
@@ -290,4 +290,20 @@ pstore_ftrace_write_timestamp(struct pstore_ftrace_record *rec, u64 val)
}
#endif
+#ifdef CONFIG_PSTORE
+int pstore_register_core_area(const char *handle, void *area, size_t size);
+int pstore_unregister_core_area(const char *handle, void *area, size_t size);
+#else
+static inline int pstore_register_core_area(const char *handle, void *area,
+ size_t size)
+{
+ return 0;
+}
+static inline int pstore_unregister_core_area(const char *handle, void *area,
+ size_t size)
+{
+ return 0;
+}
+#endif
+
#endif /*_LINUX_PSTORE_H*/
Implement core area registration mechanism. Implement directly mapped zone corespoding to core areas. Signed-off-by: Eugen Hristev <eugen.hristev@linaro.org> --- fs/pstore/platform.c | 67 ++++++++++++++++++++++++++++++++++++ fs/pstore/zone.c | 77 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pstore.h | 16 +++++++++ 3 files changed, 160 insertions(+)