This patch adds a lock free, yet safe way of storing MCA/INIT logs. You will not end up with logs mixed up from different MCAs. The MCAs/INITs are rare. There is no use wasting much permanent resources. Should you see a burst of events, they are not uncorrelated. Only the recovered events are treated. Should you miss one, you'll see it later :-) With the others, you will not be able to store them on disk anyway. There are IA64_MAX_MCA_INIT_BUFS log buffers for the MCA, and another IA64_MAX_MCA_INIT_BUFS log buffers for the INIT handler. IA64_MAX_MCA_INIT_BUFS >= 2. There is no per CPU log buffer. The first (IA64_MAX_MCA_INIT_BUFS - 1) logs and the very last one are stored only. The last one gets overwritten if there are too many logs there. The admin. info. is in a structure ia64_mca_init_buf_t, see in mca.h. Handling the first (IA64_MAX_MCA_INIT_BUFS - 1) log buffers is straight forward: you increment an atomic variable (_b_cnt) and you use as index to _buf[IA64_MAX_MCA_INIT_BUFS - 1]. Having completed the log, you set the corresponding validity bit (_valid). Otherwise you race (incl. with the nested handlers) for the last buffer: - Increment the atomic generation counter (_gen_cnt). - You own the last log buffer while no one else has got a higher generation count. - The log data is broken up into 4-byte chunks and they are stamped with the generation count. They are written together as an atomic64_t into the last buffer (*_last_buf)[] by use of a compare-and-swap primitive to make sure that no one with higher generation count has passed by in the mean time. - (*_last_buf)[0] is a marker: * Before writing the log data into the rest of (*->_last_buf)[], you set the marker to say "not done" (LAST_LOG_DONE bit off). * Having finished, you set the marker to say "done" (LAST_LOG_DONE bit on). This is how the code backs down if someone writes the same buffer with a higher generation count: do { tmp = atomic64_read(p); // p => las log buffer /* * If you can see a higher generation count than yours, * then you are not the last - bail out. */ if (GET_GEN_CNT(tmp) > gen_cnt) return -1; } while (cmpxchg_rel(p, tmp, COMPOSE_AT_VAL(gen_cnt, value)) != tmp); The code does not assume that the rendezvous always works. The salinfo side verifies that every element of the last log buffer is of the same generation. If there is no log left, it clears _b_cnt. There is no "shift" of the logs in the buffers at the salinfo side. Well, the the old code is not cleaned up and the integration into the salinfo side in not yet quit smooth, but you can judge the idea... Thanks, Zoltan Menyhart