On Wed, Jul 18, 2012 at 07:27:08PM +0200, Kay Sievers wrote: > On Wed, Jul 18, 2012 at 7:18 PM, Vivek Goyal <vgoyal at redhat.com> wrote: > > > Currently I am not exporting log "level" info as that is a bitfield and > > offsetof() bitfields can't be calculated. > > We could make the level the lower 3 bits of the byte, export the byte, > and define that only 3 bits of the byte are valid? Would that help? Yes, that should work. Here is the prototype patch which stores 5 bits of flag and 3 bits of level in a byte. I have not tested it yet, but if you like the approach, I will test it. Thanks Vivek --- kernel/printk.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) Index: linux-2.6/kernel/printk.c =================================================================== --- linux-2.6.orig/kernel/printk.c 2012-07-20 14:02:42.000000000 -0400 +++ linux-2.6/kernel/printk.c 2012-07-20 16:34:24.088964153 -0400 @@ -200,14 +200,19 @@ enum log_flags { LOG_CONT = 8, /* text is a fragment of a continuation line */ }; +#define LOG_FLAG_SHIFT 3 +#define LOG_LEVEL_MASK ((1 << LOG_FLAG_SHIFT) - 1) +#define LOG_FLAGS(log) ((log)->flags_level >> LOG_FLAG_SHIFT) +#define LOG_LEVEL(log) (((log)->flags_level) & LOG_LEVEL_MASK) + struct log { u64 ts_nsec; /* timestamp in nanoseconds */ u16 len; /* length of entire record */ u16 text_len; /* length of text buffer */ u16 dict_len; /* length of dictionary buffer */ u8 facility; /* syslog facility */ - u8 flags:5; /* internal record flags */ - u8 level:3; /* syslog level */ + u8 flags_level; /* 5 bit internal record flags, 3 bits syslog + * level */ }; /* @@ -342,8 +347,8 @@ static void log_store(int facility, int memcpy(log_dict(msg), dict, dict_len); msg->dict_len = dict_len; msg->facility = facility; - msg->level = level & 7; - msg->flags = flags & 0x1f; + msg->flags_level = level & 7; + msg->flags_level |= (flags & 0x1f) << LOG_FLAG_SHIFT; if (ts_nsec > 0) msg->ts_nsec = ts_nsec; else @@ -463,7 +468,8 @@ static ssize_t devkmsg_read(struct file ts_usec = msg->ts_nsec; do_div(ts_usec, 1000); len = sprintf(user->buf, "%u,%llu,%llu;", - (msg->facility << 3) | msg->level, user->seq, ts_usec); + (msg->facility << 3) | LOG_LEVEL(msg), user->seq, + ts_usec); /* escape non-printable characters */ for (i = 0; i < msg->text_len; i++) { @@ -655,6 +661,8 @@ void log_buf_kexec_setup(void) VMCOREINFO_OFFSET(log, len); VMCOREINFO_OFFSET(log, text_len); VMCOREINFO_OFFSET(log, dict_len); + VMCOREINFO_OFFSET(log, flags_level); + VMCOREINFO_LENGTH(log_level_bits, 3); } #endif @@ -831,7 +839,7 @@ static size_t print_time(u64 ts, char *b static size_t print_prefix(const struct log *msg, bool syslog, char *buf) { size_t len = 0; - unsigned int prefix = (msg->facility << 3) | msg->level; + unsigned int prefix = (msg->facility << 3) | LOG_LEVEL(msg); if (syslog) { if (buf) { @@ -860,14 +868,14 @@ static size_t msg_print_text(const struc bool newline = true; size_t len = 0; - if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)) + if ((prev & LOG_CONT) && !(LOG_FLAGS(msg) & LOG_PREFIX)) prefix = false; - if (msg->flags & LOG_CONT) { + if (LOG_FLAGS(msg) & LOG_CONT) { if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE)) prefix = false; - if (!(msg->flags & LOG_NEWLINE)) + if (!(LOG_FLAGS(msg) & LOG_NEWLINE)) newline = false; } @@ -944,7 +952,7 @@ static int syslog_print(char __user *buf /* message fits into buffer, move forward */ syslog_idx = log_next(syslog_idx); syslog_seq++; - syslog_prev = msg->flags; + syslog_prev = LOG_FLAGS(msg); n -= syslog_partial; syslog_partial = 0; } else if (!len){ @@ -1038,7 +1046,7 @@ static int syslog_print_all(char __user } idx = log_next(idx); seq++; - prev = msg->flags; + prev = LOG_FLAGS(msg); raw_spin_unlock_irq(&logbuf_lock); if (copy_to_user(buf + len, text, textlen)) @@ -1178,7 +1186,7 @@ int do_syslog(int type, char __user *buf error += msg_print_text(msg, prev, true, NULL, 0); idx = log_next(idx); seq++; - prev = msg->flags; + prev = LOG_FLAGS(msg); } error -= syslog_partial; } @@ -1979,6 +1987,7 @@ again: struct log *msg; size_t len; int level; + u16 log_flags; raw_spin_lock_irqsave(&logbuf_lock, flags); if (seen_seq != log_next_seq) { @@ -1997,7 +2006,7 @@ skip: break; msg = log_from_idx(console_idx); - if (msg->flags & LOG_NOCONS) { + if (LOG_FLAGS(msg) & LOG_NOCONS) { /* * Skip record we have buffered and already printed * directly to the console when we received it. @@ -2009,16 +2018,17 @@ skip: * CON_PRINTBUFFER console. Clear the flag so we * will properly dump everything later. */ - msg->flags &= ~LOG_NOCONS; + log_flags = LOG_FLAGS(msg) & ~ LOG_NOCONS; + msg->flags_level = log_flags << LOG_FLAG_SHIFT | LOG_LEVEL(msg); goto skip; } - level = msg->level; + level = LOG_LEVEL(msg); len = msg_print_text(msg, console_prev, false, text, sizeof(text)); console_idx = log_next(console_idx); console_seq++; - console_prev = msg->flags; + console_prev = LOG_FLAGS(msg); raw_spin_unlock(&logbuf_lock); stop_critical_timings(); /* don't trace print latency */ @@ -2645,7 +2655,7 @@ bool kmsg_dump_get_buffer(struct kmsg_du l += msg_print_text(msg, prev, true, NULL, 0); idx = log_next(idx); seq++; - prev = msg->flags; + prev = LOG_FLAGS(msg); } /* move first record forward until length fits into the buffer */ @@ -2658,7 +2668,7 @@ bool kmsg_dump_get_buffer(struct kmsg_du l -= msg_print_text(msg, prev, true, NULL, 0); idx = log_next(idx); seq++; - prev = msg->flags; + prev = LOG_FLAGS(msg); } /* last message in next interation */ @@ -2673,7 +2683,7 @@ bool kmsg_dump_get_buffer(struct kmsg_du l += msg_print_text(msg, prev, syslog, buf + l, size - l); idx = log_next(idx); seq++; - prev = msg->flags; + prev = LOG_FLAGS(msg); } dumper->next_seq = next_seq;