~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/cpu/mce/genpool.c

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * MCE event pool management in MCE context
  4  *
  5  * Copyright (C) 2015 Intel Corp.
  6  * Author: Chen, Gong <gong.chen@linux.intel.com>
  7  */
  8 #include <linux/smp.h>
  9 #include <linux/mm.h>
 10 #include <linux/genalloc.h>
 11 #include <linux/llist.h>
 12 #include "internal.h"
 13 
 14 /*
 15  * printk() is not safe in MCE context. This is a lock-less memory allocator
 16  * used to save error information organized in a lock-less list.
 17  *
 18  * This memory pool is only to be used to save MCE records in MCE context.
 19  * MCE events are rare, so a fixed size memory pool should be enough. Use
 20  * 2 pages to save MCE events for now (~80 MCE records at most).
 21  */
 22 #define MCE_POOLSZ      (2 * PAGE_SIZE)
 23 
 24 static struct gen_pool *mce_evt_pool;
 25 static LLIST_HEAD(mce_event_llist);
 26 static char gen_pool_buf[MCE_POOLSZ];
 27 
 28 /*
 29  * Compare the record "t" with each of the records on list "l" to see if
 30  * an equivalent one is present in the list.
 31  */
 32 static bool is_duplicate_mce_record(struct mce_evt_llist *t, struct mce_evt_llist *l)
 33 {
 34         struct mce_evt_llist *node;
 35         struct mce *m1, *m2;
 36 
 37         m1 = &t->mce;
 38 
 39         llist_for_each_entry(node, &l->llnode, llnode) {
 40                 m2 = &node->mce;
 41 
 42                 if (!mce_cmp(m1, m2))
 43                         return true;
 44         }
 45         return false;
 46 }
 47 
 48 /*
 49  * The system has panicked - we'd like to peruse the list of MCE records
 50  * that have been queued, but not seen by anyone yet.  The list is in
 51  * reverse time order, so we need to reverse it. While doing that we can
 52  * also drop duplicate records (these were logged because some banks are
 53  * shared between cores or by all threads on a socket).
 54  */
 55 struct llist_node *mce_gen_pool_prepare_records(void)
 56 {
 57         struct llist_node *head;
 58         LLIST_HEAD(new_head);
 59         struct mce_evt_llist *node, *t;
 60 
 61         head = llist_del_all(&mce_event_llist);
 62         if (!head)
 63                 return NULL;
 64 
 65         /* squeeze out duplicates while reversing order */
 66         llist_for_each_entry_safe(node, t, head, llnode) {
 67                 if (!is_duplicate_mce_record(node, t))
 68                         llist_add(&node->llnode, &new_head);
 69         }
 70 
 71         return new_head.first;
 72 }
 73 
 74 void mce_gen_pool_process(struct work_struct *__unused)
 75 {
 76         struct llist_node *head;
 77         struct mce_evt_llist *node, *tmp;
 78         struct mce *mce;
 79 
 80         head = llist_del_all(&mce_event_llist);
 81         if (!head)
 82                 return;
 83 
 84         head = llist_reverse_order(head);
 85         llist_for_each_entry_safe(node, tmp, head, llnode) {
 86                 mce = &node->mce;
 87                 blocking_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
 88                 gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
 89         }
 90 }
 91 
 92 bool mce_gen_pool_empty(void)
 93 {
 94         return llist_empty(&mce_event_llist);
 95 }
 96 
 97 int mce_gen_pool_add(struct mce *mce)
 98 {
 99         struct mce_evt_llist *node;
100 
101         if (filter_mce(mce))
102                 return -EINVAL;
103 
104         if (!mce_evt_pool)
105                 return -EINVAL;
106 
107         node = (void *)gen_pool_alloc(mce_evt_pool, sizeof(*node));
108         if (!node) {
109                 pr_warn_ratelimited("MCE records pool full!\n");
110                 return -ENOMEM;
111         }
112 
113         memcpy(&node->mce, mce, sizeof(*mce));
114         llist_add(&node->llnode, &mce_event_llist);
115 
116         return 0;
117 }
118 
119 static int mce_gen_pool_create(void)
120 {
121         struct gen_pool *tmpp;
122         int ret = -ENOMEM;
123 
124         tmpp = gen_pool_create(ilog2(sizeof(struct mce_evt_llist)), -1);
125         if (!tmpp)
126                 goto out;
127 
128         ret = gen_pool_add(tmpp, (unsigned long)gen_pool_buf, MCE_POOLSZ, -1);
129         if (ret) {
130                 gen_pool_destroy(tmpp);
131                 goto out;
132         }
133 
134         mce_evt_pool = tmpp;
135 
136 out:
137         return ret;
138 }
139 
140 int mce_gen_pool_init(void)
141 {
142         /* Just init mce_gen_pool once. */
143         if (mce_evt_pool)
144                 return 0;
145 
146         return mce_gen_pool_create();
147 }
148 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp