vprintk_emit() is too long. Let's move the text formatting and
the text analyze into a separate function.

I am not super happy with the result. The primary aim is to reduce
future mistakes when backporting fixes in this code to older stable
kernel releases. Therefore I want to keep the changes in the code
at minimum. Especially, I want to avoid conversion of @text into
"char **" because it is harder to read.

Well, there is one exception. @level is accessed via a pointer.
It looks safe because compiler warns about type mismatch when
the access is not updated. Also it used only in a very
simple code.

Better ideas are welcome!

This patch just shuffles the code. There is no change in
the functionality.

Signed-off-by: Petr Mladek <[email protected]>
---
 kernel/printk/printk.c | 122 +++++++++++++++++++++++++++++++------------------
 1 file changed, 78 insertions(+), 44 deletions(-)

diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 91b8043044ac..7d009144f97f 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1740,13 +1740,85 @@ static int vprintk_delayed_warnings(void)
        return printed_len;
 }
 
+/**
+ * vprintk_format_and_analyze - format and analyze the text message
+ * @fmt: text format
+ * @args: argumetns used to generate the formated text
+ * @dict: pointer to the message dictionary
+ * @facility: syslog facility
+ * @level: syslog level; might be replaced by the one found in the fomatted 
text
+ * @ftext: pointer to the formatted text after the syslog prefix
+ * @ftext_len: length of the formatted text without the syslog prefix
+ *
+ * This function modifies the global textbuf and therefore it must be called
+ * under lockbuf_lock!
+ */
+static enum log_flags vprinkt_format_and_analyze(const char *fmt, va_list args,
+                                                const char *dict, int facility,
+                                                int *level,
+                                                char **ftext,
+                                                size_t *ftext_len)
+{
+       char *text = textbuf;
+       size_t text_len;
+       enum log_flags lflags = 0;
+
+       /*
+        * The printf needs to come first; we need the syslog
+        * prefix which might be passed-in as a parameter.
+        */
+       text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
+
+       /* mark and strip a trailing newline */
+       if (text_len && text[text_len-1] == '\n') {
+               text_len--;
+               lflags |= LOG_NEWLINE;
+       }
+
+       /* strip kernel syslog prefix and extract log level or control flags */
+       if (facility == 0) {
+               int kern_level = printk_get_level(text);
+
+               if (kern_level) {
+                       const char *end_of_header = printk_skip_level(text);
+
+                       switch (kern_level) {
+                       case '0' ... '7':
+                               if (*level == LOGLEVEL_DEFAULT)
+                                       *level = kern_level - '0';
+                               /* fallthrough */
+                       case 'd':       /* KERN_DEFAULT */
+                               lflags |= LOG_PREFIX;
+                       }
+                       /*
+                        * No need to check length here because vscnprintf
+                        * put '\0' at the end of the string. Only valid and
+                        * newly printed level is detected.
+                        */
+                       text_len -= end_of_header - text;
+                       text = (char *)end_of_header;
+               }
+       }
+
+       if (*level == LOGLEVEL_DEFAULT)
+               *level = default_message_loglevel;
+
+       if (dict)
+               lflags |= LOG_PREFIX|LOG_NEWLINE;
+
+       *ftext = text;
+       *ftext_len = text_len;
+
+       return lflags;
+}
+
 asmlinkage int vprintk_emit(int facility, int level,
                            const char *dict, size_t dictlen,
                            const char *fmt, va_list args)
 {
-       char *text = textbuf;
-       size_t text_len = 0;
-       enum log_flags lflags = 0;
+       char *text;
+       size_t text_len;
+       enum log_flags lflags;
        unsigned long flags;
        int this_cpu;
        int printed_len = 0;
@@ -1808,47 +1880,9 @@ asmlinkage int vprintk_emit(int facility, int level,
 
        printed_len += vprintk_delayed_warnings();
 
-       /*
-        * The printf needs to come first; we need the syslog
-        * prefix which might be passed-in as a parameter.
-        */
-       text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
-
-       /* mark and strip a trailing newline */
-       if (text_len && text[text_len-1] == '\n') {
-               text_len--;
-               lflags |= LOG_NEWLINE;
-       }
-
-       /* strip kernel syslog prefix and extract log level or control flags */
-       if (facility == 0) {
-               int kern_level = printk_get_level(text);
-
-               if (kern_level) {
-                       const char *end_of_header = printk_skip_level(text);
-                       switch (kern_level) {
-                       case '0' ... '7':
-                               if (level == LOGLEVEL_DEFAULT)
-                                       level = kern_level - '0';
-                               /* fallthrough */
-                       case 'd':       /* KERN_DEFAULT */
-                               lflags |= LOG_PREFIX;
-                       }
-                       /*
-                        * No need to check length here because vscnprintf
-                        * put '\0' at the end of the string. Only valid and
-                        * newly printed level is detected.
-                        */
-                       text_len -= end_of_header - text;
-                       text = (char *)end_of_header;
-               }
-       }
-
-       if (level == LOGLEVEL_DEFAULT)
-               level = default_message_loglevel;
-
-       if (dict)
-               lflags |= LOG_PREFIX|LOG_NEWLINE;
+       lflags = vprinkt_format_and_analyze(fmt, args, dict, facility,
+                                           &level,
+                                           &text, &text_len);
 
        if (!(lflags & LOG_NEWLINE)) {
                /*
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to