summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2012-06-30 02:42:12 +0200
committerKay Sievers <kay@vrfy.org>2012-06-30 02:42:12 +0200
commit5c6aabade287c2694c54becea61f18423cc90fff (patch)
tree38d0bede304868ee30b247618935330ebc4a3879
parent87194496259865729be1fccde58309002ce851c0 (diff)
downloadpatches-5c6aabade287c2694c54becea61f18423cc90fff.tar.gz
kmsg_dump is merged
-rw-r--r--kmsg_dump.patch594
-rw-r--r--series1
-rw-r--r--test-modules.patch20
3 files changed, 2 insertions, 613 deletions
diff --git a/kmsg_dump.patch b/kmsg_dump.patch
deleted file mode 100644
index e706dca..0000000
--- a/kmsg_dump.patch
+++ /dev/null
@@ -1,594 +0,0 @@
----
- arch/powerpc/platforms/pseries/nvram.c | 61 -------
- arch/x86/platform/mrst/early_printk_mrst.c | 13 -
- drivers/mtd/mtdoops.c | 22 --
- fs/pstore/platform.c | 34 +---
- include/linux/kmsg_dump.h | 45 ++++-
- kernel/printk.c | 222 +++++++++++++++++++++++++----
- 6 files changed, 259 insertions(+), 138 deletions(-)
-
---- a/arch/powerpc/platforms/pseries/nvram.c
-+++ b/arch/powerpc/platforms/pseries/nvram.c
-@@ -68,9 +68,7 @@ static const char *pseries_nvram_os_part
- };
-
- static void oops_to_nvram(struct kmsg_dumper *dumper,
-- enum kmsg_dump_reason reason,
-- const char *old_msgs, unsigned long old_len,
-- const char *new_msgs, unsigned long new_len);
-+ enum kmsg_dump_reason reason);
-
- static struct kmsg_dumper nvram_kmsg_dumper = {
- .dump = oops_to_nvram
-@@ -504,28 +502,6 @@ int __init pSeries_nvram_init(void)
- }
-
- /*
-- * Try to capture the last capture_len bytes of the printk buffer. Return
-- * the amount actually captured.
-- */
--static size_t capture_last_msgs(const char *old_msgs, size_t old_len,
-- const char *new_msgs, size_t new_len,
-- char *captured, size_t capture_len)
--{
-- if (new_len >= capture_len) {
-- memcpy(captured, new_msgs + (new_len - capture_len),
-- capture_len);
-- return capture_len;
-- } else {
-- /* Grab the end of old_msgs. */
-- size_t old_tail_len = min(old_len, capture_len - new_len);
-- memcpy(captured, old_msgs + (old_len - old_tail_len),
-- old_tail_len);
-- memcpy(captured + old_tail_len, new_msgs, new_len);
-- return old_tail_len + new_len;
-- }
--}
--
--/*
- * Are we using the ibm,rtas-log for oops/panic reports? And if so,
- * would logging this oops/panic overwrite an RTAS event that rtas_errd
- * hasn't had a chance to read and process? Return 1 if so, else 0.
-@@ -541,27 +517,6 @@ static int clobbering_unread_rtas_event(
- NVRAM_RTAS_READ_TIMEOUT);
- }
-
--/* Squeeze out each line's <n> severity prefix. */
--static size_t elide_severities(char *buf, size_t len)
--{
-- char *in, *out, *buf_end = buf + len;
-- /* Assume a <n> at the very beginning marks the start of a line. */
-- int newline = 1;
--
-- in = out = buf;
-- while (in < buf_end) {
-- if (newline && in+3 <= buf_end &&
-- *in == '<' && isdigit(in[1]) && in[2] == '>') {
-- in += 3;
-- newline = 0;
-- } else {
-- newline = (*in == '\n');
-- *out++ = *in++;
-- }
-- }
-- return out - buf;
--}
--
- /* Derived from logfs_compress() */
- static int nvram_compress(const void *in, void *out, size_t inlen,
- size_t outlen)
-@@ -619,9 +574,7 @@ static int zip_oops(size_t text_len)
- * partition. If that's too much, go back and capture uncompressed text.
- */
- static void oops_to_nvram(struct kmsg_dumper *dumper,
-- enum kmsg_dump_reason reason,
-- const char *old_msgs, unsigned long old_len,
-- const char *new_msgs, unsigned long new_len)
-+ enum kmsg_dump_reason reason)
- {
- static unsigned int oops_count = 0;
- static bool panicking = false;
-@@ -660,14 +613,14 @@ static void oops_to_nvram(struct kmsg_du
- return;
-
- if (big_oops_buf) {
-- text_len = capture_last_msgs(old_msgs, old_len,
-- new_msgs, new_len, big_oops_buf, big_oops_buf_sz);
-- text_len = elide_severities(big_oops_buf, text_len);
-+ kmsg_dump_get_buffer(dumper, false,
-+ big_oops_buf, big_oops_buf_sz, &text_len);
- rc = zip_oops(text_len);
- }
- if (rc != 0) {
-- text_len = capture_last_msgs(old_msgs, old_len,
-- new_msgs, new_len, oops_data, oops_data_sz);
-+ kmsg_dump_rewind(dumper);
-+ kmsg_dump_get_buffer(dumper, true,
-+ oops_data, oops_data_sz, &text_len);
- err_type = ERR_TYPE_KERNEL_PANIC;
- *oops_len = (u16) text_len;
- }
---- a/arch/x86/platform/mrst/early_printk_mrst.c
-+++ b/arch/x86/platform/mrst/early_printk_mrst.c
-@@ -110,19 +110,16 @@ static struct kmsg_dumper dw_dumper;
- static int dumper_registered;
-
- static void dw_kmsg_dump(struct kmsg_dumper *dumper,
-- enum kmsg_dump_reason reason,
-- const char *s1, unsigned long l1,
-- const char *s2, unsigned long l2)
-+ enum kmsg_dump_reason reason)
- {
-- int i;
-+ static char line[1024];
-+ size_t len;
-
- /* When run to this, we'd better re-init the HW */
- mrst_early_console_init();
-
-- for (i = 0; i < l1; i++)
-- early_mrst_console.write(&early_mrst_console, s1 + i, 1);
-- for (i = 0; i < l2; i++)
-- early_mrst_console.write(&early_mrst_console, s2 + i, 1);
-+ while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
-+ early_mrst_console.write(&early_mrst_console, line, len);
- }
-
- /* Set the ratio rate to 115200, 8n1, IRQ disabled */
---- a/drivers/mtd/mtdoops.c
-+++ b/drivers/mtd/mtdoops.c
-@@ -304,32 +304,17 @@ static void find_next_position(struct mt
- }
-
- static void mtdoops_do_dump(struct kmsg_dumper *dumper,
-- enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
-- const char *s2, unsigned long l2)
-+ enum kmsg_dump_reason reason)
- {
- struct mtdoops_context *cxt = container_of(dumper,
- struct mtdoops_context, dump);
-- unsigned long s1_start, s2_start;
-- unsigned long l1_cpy, l2_cpy;
-- char *dst;
--
-- if (reason != KMSG_DUMP_OOPS &&
-- reason != KMSG_DUMP_PANIC)
-- return;
-
- /* Only dump oopses if dump_oops is set */
- if (reason == KMSG_DUMP_OOPS && !dump_oops)
- return;
-
-- dst = cxt->oops_buf + MTDOOPS_HEADER_SIZE; /* Skip the header */
-- l2_cpy = min(l2, record_size - MTDOOPS_HEADER_SIZE);
-- l1_cpy = min(l1, record_size - MTDOOPS_HEADER_SIZE - l2_cpy);
--
-- s2_start = l2 - l2_cpy;
-- s1_start = l1 - l1_cpy;
--
-- memcpy(dst, s1 + s1_start, l1_cpy);
-- memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
-+ kmsg_dump_get_buffer(dumper, true, cxt->oops_buf + MTDOOPS_HEADER_SIZE,
-+ record_size - MTDOOPS_HEADER_SIZE, NULL);
-
- /* Panics must be written immediately */
- if (reason != KMSG_DUMP_OOPS)
-@@ -375,6 +360,7 @@ static void mtdoops_notify_add(struct mt
- return;
- }
-
-+ cxt->dump.max_reason = KMSG_DUMP_OOPS;
- cxt->dump.dump = mtdoops_do_dump;
- err = kmsg_dump_register(&cxt->dump);
- if (err) {
---- a/fs/pstore/platform.c
-+++ b/fs/pstore/platform.c
-@@ -94,20 +94,15 @@ static const char *get_reason_str(enum k
- * as we can from the end of the buffer.
- */
- static void pstore_dump(struct kmsg_dumper *dumper,
-- enum kmsg_dump_reason reason,
-- const char *s1, unsigned long l1,
-- const char *s2, unsigned long l2)
-+ enum kmsg_dump_reason reason)
- {
-- unsigned long s1_start, s2_start;
-- unsigned long l1_cpy, l2_cpy;
-- unsigned long size, total = 0;
-- char *dst;
-+ unsigned long total = 0;
- const char *why;
- u64 id;
-- int hsize, ret;
- unsigned int part = 1;
- unsigned long flags = 0;
- int is_locked = 0;
-+ int ret;
-
- why = get_reason_str(reason);
-
-@@ -119,30 +114,25 @@ static void pstore_dump(struct kmsg_dump
- spin_lock_irqsave(&psinfo->buf_lock, flags);
- oopscount++;
- while (total < kmsg_bytes) {
-+ char *dst;
-+ unsigned long size;
-+ int hsize;
-+ size_t len;
-+
- dst = psinfo->buf;
- hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
- size = psinfo->bufsize - hsize;
- dst += hsize;
-
-- l2_cpy = min(l2, size);
-- l1_cpy = min(l1, size - l2_cpy);
--
-- if (l1_cpy + l2_cpy == 0)
-+ if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len))
- break;
-
-- s2_start = l2 - l2_cpy;
-- s1_start = l1 - l1_cpy;
--
-- memcpy(dst, s1 + s1_start, l1_cpy);
-- memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
--
- ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
-- hsize + l1_cpy + l2_cpy, psinfo);
-+ hsize + len, psinfo);
- if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
- pstore_new_entry = 1;
-- l1 -= l1_cpy;
-- l2 -= l2_cpy;
-- total += l1_cpy + l2_cpy;
-+
-+ total += hsize + len;
- part++;
- }
- if (in_nmi()) {
---- a/include/linux/kmsg_dump.h
-+++ b/include/linux/kmsg_dump.h
-@@ -21,6 +21,7 @@
- * is passed to the kernel.
- */
- enum kmsg_dump_reason {
-+ KMSG_DUMP_UNDEF,
- KMSG_DUMP_PANIC,
- KMSG_DUMP_OOPS,
- KMSG_DUMP_EMERG,
-@@ -31,23 +32,37 @@ enum kmsg_dump_reason {
-
- /**
- * struct kmsg_dumper - kernel crash message dumper structure
-- * @dump: The callback which gets called on crashes. The buffer is passed
-- * as two sections, where s1 (length l1) contains the older
-- * messages and s2 (length l2) contains the newer.
- * @list: Entry in the dumper list (private)
-+ * @dump: Call into dumping code which will retrieve the data with
-+ * through the record iterator
-+ * @max_reason: filter for highest reason number that should be dumped
- * @registered: Flag that specifies if this is already registered
- */
- struct kmsg_dumper {
-- void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
-- const char *s1, unsigned long l1,
-- const char *s2, unsigned long l2);
- struct list_head list;
-- int registered;
-+ void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason);
-+ enum kmsg_dump_reason max_reason;
-+ bool active;
-+ bool registered;
-+
-+ /* private state of the kmsg iterator */
-+ u32 cur_idx;
-+ u32 next_idx;
-+ u64 cur_seq;
-+ u64 next_seq;
- };
-
- #ifdef CONFIG_PRINTK
- void kmsg_dump(enum kmsg_dump_reason reason);
-
-+bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
-+ char *line, size_t size, size_t *len);
-+
-+bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
-+ char *buf, size_t size, size_t *len);
-+
-+void kmsg_dump_rewind(struct kmsg_dumper *dumper);
-+
- int kmsg_dump_register(struct kmsg_dumper *dumper);
-
- int kmsg_dump_unregister(struct kmsg_dumper *dumper);
-@@ -56,6 +71,22 @@ static inline void kmsg_dump(enum kmsg_d
- {
- }
-
-+bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
-+ const char *line, size_t size, size_t *len)
-+{
-+ return false;
-+}
-+
-+bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
-+ char *buf, size_t size, size_t *len)
-+{
-+ return false;
-+}
-+
-+void kmsg_dump_rewind(struct kmsg_dumper *dumper)
-+{
-+}
-+
- static inline int kmsg_dump_register(struct kmsg_dumper *dumper)
- {
- return -EINVAL;
---- a/kernel/printk.c
-+++ b/kernel/printk.c
-@@ -909,7 +909,7 @@ static int syslog_print_all(char __user
- /*
- * Find first record that fits, including all following records,
- * into the user-provided buffer for this dump.
-- */
-+ */
- seq = clear_seq;
- idx = clear_idx;
- while (seq < log_next_seq) {
-@@ -919,6 +919,8 @@ static int syslog_print_all(char __user
- idx = log_next(idx);
- seq++;
- }
-+
-+ /* move first record forward until length fits into the buffer */
- seq = clear_seq;
- idx = clear_idx;
- while (len > size && seq < log_next_seq) {
-@@ -929,7 +931,7 @@ static int syslog_print_all(char __user
- seq++;
- }
-
-- /* last message in this dump */
-+ /* last message fitting into this dump */
- next_seq = log_next_seq;
-
- len = 0;
-@@ -2300,48 +2302,210 @@ module_param_named(always_kmsg_dump, alw
- * kmsg_dump - dump kernel log to kernel message dumpers.
- * @reason: the reason (oops, panic etc) for dumping
- *
-- * Iterate through each of the dump devices and call the oops/panic
-- * callbacks with the log buffer.
-+ * Call each of the registered dumper's dump() callback, which can
-+ * retrieve the kmsg records with kmsg_dump_get_line() or
-+ * kmsg_dump_get_buffer().
- */
- void kmsg_dump(enum kmsg_dump_reason reason)
- {
-- u64 idx;
- struct kmsg_dumper *dumper;
-- const char *s1, *s2;
-- unsigned long l1, l2;
- unsigned long flags;
-
- if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
- return;
-
-- /* Theoretically, the log could move on after we do this, but
-- there's not a lot we can do about that. The new messages
-- will overwrite the start of what we dump. */
-+ rcu_read_lock();
-+ list_for_each_entry_rcu(dumper, &dump_list, list) {
-+ if (dumper->max_reason && reason > dumper->max_reason)
-+ continue;
-+
-+ /* initialize iterator with data about the stored records */
-+ dumper->active = true;
-+
-+ raw_spin_lock_irqsave(&logbuf_lock, flags);
-+ dumper->cur_seq = clear_seq;
-+ dumper->cur_idx = clear_idx;
-+ dumper->next_seq = log_next_seq;
-+ dumper->next_idx = log_next_idx;
-+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-+
-+ /* invoke dumper which will iterate over records */
-+ dumper->dump(dumper, reason);
-+
-+ /* reset iterator */
-+ dumper->active = false;
-+ }
-+ rcu_read_unlock();
-+}
-+
-+/**
-+ * kmsg_dump_get_line - retrieve one kmsg log line
-+ * @dumper: registered kmsg dumper
-+ * @syslog: include the "<4>" prefixes
-+ * @line: buffer to copy the line to
-+ * @size: maximum size of the buffer
-+ * @len: length of line placed into buffer
-+ *
-+ * Start at the beginning of the kmsg buffer, with the oldest kmsg
-+ * record, and copy one record into the provided buffer.
-+ *
-+ * Consecutive calls will return the next available record moving
-+ * towards the end of the buffer with the youngest messages.
-+ *
-+ * A return value of FALSE indicate that there are no more records to
-+ * read.
-+ */
-+bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
-+ char *line, size_t size, size_t *len)
-+{
-+ unsigned long flags;
-+ struct log *msg;
-+ size_t l = 0;
-+ bool ret = false;
-+
-+ if (!dumper->active)
-+ goto out;
-
- raw_spin_lock_irqsave(&logbuf_lock, flags);
-- if (syslog_seq < log_first_seq)
-- idx = syslog_idx;
-- else
-- idx = log_first_idx;
--
-- if (idx > log_next_idx) {
-- s1 = log_buf;
-- l1 = log_next_idx;
-+ if (dumper->cur_seq < log_first_seq) {
-+ /* messages are gone, move to first available one */
-+ dumper->cur_seq = log_first_seq;
-+ dumper->cur_idx = log_first_idx;
-+ }
-
-- s2 = log_buf + idx;
-- l2 = log_buf_len - idx;
-- } else {
-- s1 = "";
-- l1 = 0;
-+ /* last entry */
-+ if (dumper->cur_seq >= log_next_seq) {
-+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-+ goto out;
-+ }
-
-- s2 = log_buf + idx;
-- l2 = log_next_idx - idx;
-+ msg = log_from_idx(dumper->cur_idx);
-+ l = msg_print_text(msg, syslog,
-+ line, size);
-+
-+ dumper->cur_idx = log_next(dumper->cur_idx);
-+ dumper->cur_seq++;
-+ ret = true;
-+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-+out:
-+ if (len)
-+ *len = l;
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
-+
-+/**
-+ * kmsg_dump_get_buffer - copy kmsg log lines
-+ * @dumper: registered kmsg dumper
-+ * @syslog: include the "<4>" prefixes
-+ * @line: buffer to copy the line to
-+ * @size: maximum size of the buffer
-+ * @len: length of line placed into buffer
-+ *
-+ * Start at the end of the kmsg buffer and fill the provided buffer
-+ * with as many of the the *youngest* kmsg records that fit into it.
-+ * If the buffer is large enough, all available kmsg records will be
-+ * copied with a single call.
-+ *
-+ * Consecutive calls will fill the buffer with the next block of
-+ * available older records, not including the earlier retrieved ones.
-+ *
-+ * A return value of FALSE indicate that there are no more records to
-+ * read.
-+ */
-+bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
-+ char *buf, size_t size, size_t *len)
-+{
-+ unsigned long flags;
-+ u64 seq;
-+ u32 idx;
-+ u64 next_seq;
-+ u32 next_idx;
-+ size_t l = 0;
-+ bool ret = false;
-+
-+ if (!dumper->active)
-+ goto out;
-+
-+ raw_spin_lock_irqsave(&logbuf_lock, flags);
-+ if (dumper->cur_seq < log_first_seq) {
-+ /* messages are gone, move to first available one */
-+ dumper->cur_seq = log_first_seq;
-+ dumper->cur_idx = log_first_idx;
-+ }
-+
-+ /* last entry */
-+ if (dumper->cur_seq >= dumper->next_seq) {
-+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-+ goto out;
-+ }
-+
-+ /* calculate length of entire buffer */
-+ seq = dumper->cur_seq;
-+ idx = dumper->cur_idx;
-+ while (seq < dumper->next_seq) {
-+ struct log *msg = log_from_idx(idx);
-+
-+ l += msg_print_text(msg, true, NULL, 0);
-+ idx = log_next(idx);
-+ seq++;
-+ }
-+
-+ /* move first record forward until length fits into the buffer */
-+ seq = dumper->cur_seq;
-+ idx = dumper->cur_idx;
-+ while (l > size && seq < dumper->next_seq) {
-+ struct log *msg = log_from_idx(idx);
-+
-+ l -= msg_print_text(msg, true, NULL, 0);
-+ idx = log_next(idx);
-+ seq++;
-+ }
-+
-+ /* last message in next interation */
-+ next_seq = seq;
-+ next_idx = idx;
-+
-+ l = 0;
-+ while (seq < dumper->next_seq) {
-+ struct log *msg = log_from_idx(idx);
-+
-+ l += msg_print_text(msg, syslog,
-+ buf + l, size - l);
-+
-+ idx = log_next(idx);
-+ seq++;
- }
-+
-+ dumper->next_seq = next_seq;
-+ dumper->next_idx = next_idx;
-+ ret = true;
- raw_spin_unlock_irqrestore(&logbuf_lock, flags);
-+out:
-+ if (len)
-+ *len = l;
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
-
-- rcu_read_lock();
-- list_for_each_entry_rcu(dumper, &dump_list, list)
-- dumper->dump(dumper, reason, s1, l1, s2, l2);
-- rcu_read_unlock();
-+/**
-+ * kmsg_dump_rewind - reset the interator
-+ * @dumper: registered kmsg dumper
-+ *
-+ * Reset the dumper's iterator so that kmsg_dump_get_line() and
-+ * kmsg_dump_get_buffer() can be called again and used multiple
-+ * times within the same dumper.dump() callback.
-+ */
-+void kmsg_dump_rewind(struct kmsg_dumper *dumper)
-+{
-+ unsigned long flags;
-+
-+ raw_spin_lock_irqsave(&logbuf_lock, flags);
-+ dumper->cur_seq = clear_seq;
-+ dumper->cur_idx = clear_idx;
-+ dumper->next_seq = log_next_seq;
-+ dumper->next_idx = log_next_idx;
-+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
- }
-+EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
- #endif
diff --git a/series b/series
index 5f8e567..a9dd8aa 100644
--- a/series
+++ b/series
@@ -1,2 +1 @@
test-modules.patch
-kmsg_dump.patch
diff --git a/test-modules.patch b/test-modules.patch
index 2d622b6..bba8207 100644
--- a/test-modules.patch
+++ b/test-modules.patch
@@ -1,25 +1,9 @@
---
- drivers/misc/Kconfig | 6 +++
drivers/misc/Makefile | 2 +
drivers/misc/dump-test.c | 72 +++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/printk-race.c | 70 +++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 150 insertions(+)
+ 3 files changed, 144 insertions(+)
---- a/drivers/misc/Kconfig
-+++ b/drivers/misc/Kconfig
-@@ -508,6 +508,12 @@ config USB_SWITCH_FSA9480
- stereo and mono audio, video, microphone and UART data to use
- a common connector port.
-
-+config PRINTK_RACE
-+ tristate "printk race test"
-+ help
-+ Prints tests strings which race agains each other and
-+ get interleaved or not.
-+
- source "drivers/misc/c2port/Kconfig"
- source "drivers/misc/eeprom/Kconfig"
- source "drivers/misc/cb710/Kconfig"
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -51,3 +51,5 @@ obj-y += carma/
@@ -162,7 +146,7 @@
+
+ schedule_work(&a_work);
+ schedule_work(&c_work);
-+ schedule_work(&x_work);
++ //schedule_work(&x_work);
+
+ flush_work_sync(&a_work);
+ flush_work_sync(&c_work);