[PATCH] extension: get socket receive queue into a file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



syslog() can be used to send messages to the system logger, and a socket is
used to do the deliverying. So such a situation may be existed that the message
is sent to the socket, but not received by syslogd yet. This module is used to
dump the messages left in the socket.

This module has been tested on RHEL5/6 x86/x64. The following program is used
to generate a kdump core that got log messages left in socket.

1. compile the following c program to a.out
<cut>

int main(int argc, char **argv)
{
    char buf[256];
    int i = 0;

    for (i = 0; i < 1; i++) {
        openlog("syslog", LOG_CONS , 0);
        sprintf(buf, "[TEST] a very long test message is appropriate, but I do "
                     "not know such a message (No.%d)\n", i);
        syslog(LOG_INFO, buf);
        closelog();
    }

    return 0;
}
<cut>

2. run the following bash code to panic and generate a kdump core
<cut>
i=0
while [[ $i -lt 1000 ]];do
    ./a.out &
    echo $i
    i=$((i+1))
done
echo c > /proc/sysrq-trigger
i=0
while [[ $i -lt 1000 ]];do
    ./a.out &
    echo $i
    i=$((i+1))
done
<cut>

3. run crash with the vmcore generated in step 2 and load sockq module. Then
run command like below to get left log message
<cut>
crash> ps | grep syslog
   1121      1   0  ffff880037ac2080  IN   0.2  249080   1740  rsyslogd
   1123      1   1  ffff880037a00040  RU   0.2  249080   1740  rsyslogd
   1124      1   1  ffff8800375f9540  IN   0.2  249080   1740  rsyslogd
crash> files 1121
PID: 1121   TASK: ffff880037ac2080  CPU: 0   COMMAND: "rsyslogd"
ROOT: /    CWD: /
 FD       FILE            DENTRY           INODE       TYPE PATH
  0 ffff88003e0d0b40 ffff88003ef29a80 ffff88003ef8c688 SOCK
  1 ffff88003d8f1140 ffff88003efc3800 ffff88003d3d44c0 REG  /var/log/messages
  2 ffff88003d859180 ffff88003efadb40 ffff88003d3d40c0 REG  /var/log/secure
  3 ffff88003d8590c0 ffff88003ef29b40 ffff88003ef917f8 REG  /proc/kmsg
  4 ffff88003dfd1b40 ffff88003d1a7500 ffff88003d004cc0 REG  /var/log/maillog
  5 ffff88003dee7180 ffff88003d0b6980 ffff88003d0048c0 REG  /var/log/cron

crash> sockq ffff88003e0d0b40 out
crash> cat out
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.48)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.44)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.12)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.13)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.21)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.21)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.18)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.1)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.18)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.18)
<14>Apr 17 16:32:56 syslog: [TEST] a very long test message is appropriate, but I do not know such a message (No.2)
crash>
<cut>

Signed-off-by: Qiao Nuohan <qiaonuohan@xxxxxxxxxxxxxx>
---
 extensions/sockq.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 203 insertions(+)
 create mode 100644 extensions/sockq.c

diff --git a/extensions/sockq.c b/extensions/sockq.c
new file mode 100644
index 0000000..3784413
--- /dev/null
+++ b/extensions/sockq.c
@@ -0,0 +1,203 @@
+/* sockq.c - sockq extension module for crash
+ *
+ * Copyright (C) 2014 FUJITSU LIMITED
+ * Author: Qiao Nuohan <qiaonuohan@xxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "defs.h"      /* From the crash source top-level directory */
+
+void sockq_init(void);      /* constructor function */
+void sockq_fini(void);      /* destructor function (optional) */
+
+void cmd_sockq(void);       /* Declare the commands and their help data. */
+char *help_sockq[];
+
+static struct command_table_entry command_table[] = {
+    { "sockq", cmd_sockq, help_sockq, 0},       /* One or more commands, */
+    { NULL },                                   /* terminated by NULL, */
+};
+
+char *help_sockq[] = {
+"sockq",                                    /* command name */
+"get socket receive queue into a file",     /* short description */
+"file_address outfile",                     /* argument synopsis */
+
+"  This command gets the data from the socket receive queue.",
+" ",
+"    file_address       A hexadecimal value of socket's file structure address.",
+"    outfile            A name of output file. If the file already exists,",
+"                       it is overwritten.",
+NULL
+};
+
+void __attribute__((constructor))
+sockq_init(void) /* Register the command set. */
+{
+    register_extension(command_table);
+}
+
+/*
+ *  This function is called if the shared object is unloaded.
+ *  If desired, perform any cleanups here.
+ */
+void __attribute__((destructor))
+sockq_fini(void) { }
+
+static int
+get_member_data(ulonglong addr, char *name, char *member, void* buf)
+{
+    ulong member_offset;
+
+    member_offset = MEMBER_OFFSET(name, member);
+
+    if (!readmem(addr + member_offset, KVADDR, buf,
+        MEMBER_SIZE(name, member), name, FAULT_ON_ERROR))
+        return FALSE;
+
+    return TRUE;
+}
+
+/*
+ * write receive data in the specified file
+ */
+static int
+write_data(int fd, char *buf, ulong addr, ulong size)
+{
+    ulong wsize;
+
+    while (size > 0) {
+    /* size of the buffer is pagesize */
+        wsize =  (size > PAGESIZE()) ? PAGESIZE() : size;
+
+        if (!readmem(addr, KVADDR, buf, wsize, "vaddr", FAULT_ON_ERROR)) {
+            fprintf(fp, "cannot read data from packet buffer\n");
+            return 1;
+        }
+
+        if (write(fd, buf, wsize) < 0) {
+            fprintf(fp, "cannot write data in a file\n");
+            return 1;
+        }
+
+        addr += wsize;
+        size -= wsize;
+    }
+
+    return 0;
+}
+
+int
+do_sockq(ulong file_addr, char *output_file, int fd)
+{
+    int rc = 1;
+    ulong pd, sk;
+    uint qlen;
+    char *buf = NULL;
+    ulong next, head;
+    unsigned int len;
+    ulong wnext;
+
+    if (!get_member_data(file_addr, "file", "private_data", &pd)) {
+        fprintf(fp, "cannot get private_datad of file structure\n");
+        goto cleanup;
+    }
+
+    if (!get_member_data(pd, "socket", "sk", &sk)) {
+        fprintf(fp, "cannot get sk of socket structure\n");
+        goto cleanup;
+    }
+
+    if (!get_member_data(sk + MEMBER_OFFSET("sock", "sk_receive_queue"),
+                         "sk_buff_head", "next", &next)) {
+        fprintf(fp, "cannot get the first queue of sock structure\n");
+        goto cleanup;
+    }
+
+    if (!get_member_data(sk + MEMBER_OFFSET("sock", "sk_receive_queue"),
+                         "sk_buff_head", "qlen", &qlen)) {
+        fprintf(fp, "cannot get the number of queue list\n");
+        goto cleanup;
+    }
+
+    /* create a output file */
+    if (output_file != NULL &&
+        (fd = open(output_file,
+                   O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+        fprintf(fp, "cannot create %s\n", output_file);
+        goto cleanup;
+    }
+
+    if (qlen == 0) {
+        /* receive queue is empty */
+        rc = 0;
+        goto cleanup;
+    }
+
+    /* get work area */
+    buf = GETBUF(PAGESIZE());
+
+    while (qlen-- > 0) {
+        /* get packet buffer are info */
+        if (!get_member_data(next, "sk_buff", "head", &head)) {
+            fprintf(fp, "cannot head of sk_buff structure\n");
+            goto cleanup;
+        }
+
+        if (!get_member_data(next, "sk_buff", "len", &len)) {
+            fprintf(fp, "cannot tail of sk_buff structure\n");
+            goto cleanup;
+        }
+
+        /* write data in the output file */
+        if (write_data(fd, buf, head, len))
+            goto cleanup;
+
+        /* next receive queue */
+        wnext = next;
+        if (!get_member_data(wnext, "sk_buff", "next", &next)) {
+            fprintf(fp, "cannot get next of sk_buff structure\n");
+            goto cleanup;
+        }
+    }
+
+    /* all process normally ends */
+    rc = 0;
+
+cleanup:
+    if (output_file != NULL)
+        close(fd);
+    if (buf)
+        FREEBUF(buf);
+
+    return rc;
+}
+
+void
+cmd_sockq(void)
+{
+    ulong file_addr;
+
+    if (argcnt != 3)
+        cmd_usage(pc->curcmd, SYNOPSIS);
+
+    optind++;
+    file_addr = htol(args[optind], FAULT_ON_ERROR, NULL);
+
+    optind++;
+    if (strlen(args[optind]) > PATH_MAX) {
+    fprintf(fp, "cannot create specified output file\n");
+    return;
+    }
+
+    do_sockq(file_addr, args[optind], -1);
+}
-- 
1.8.5.3

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility




[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux