Implement core area registration mechanism.
Implement directly mapped zone corespoding to core areas.

Signed-off-by: Eugen Hristev <[email protected]>
---
 fs/pstore/platform.c   | 67 ++++++++++++++++++++++++++++++++++++
 fs/pstore/zone.c       | 77 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/pstore.h | 16 +++++++++
 3 files changed, 160 insertions(+)

diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index e20e60b88727..32448d9dd316 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -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.
diff --git a/fs/pstore/zone.c b/fs/pstore/zone.c
index affa4370208c..f9e2dc4252ea 100644
--- a/fs/pstore/zone.c
+++ b/fs/pstore/zone.c
@@ -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,
        },
 };
 
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 8360d94c96b6..85f3f964b268 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -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*/
-- 
2.43.0


Reply via email to