Re: Error seeking in /dev/kmem

G.W. Wettstein (greg@wind.enjellic.com)
Tue, 16 Feb 1999 03:37:53 -0600


On Feb 16, 1:19am, "Francis A. Vidal" wrote:
} Subject: Error seeking in /dev/kmem

> hi all,

Good morning Francis, thank you for the note.

> i'm running redhat linux 5.0 with kernel 2.2.1 / sysklogd-1.3-26 /
> glibc-2.0.7-19 / gcc-2.8.0-2. ever since i changed the kernel to 2.2.x, i
> found error messages in /var/log/messages:
>
> Feb 15 23:43:35 atlas syslogd 1.3-3: restart.
> Feb 15 23:43:35 atlas kernel: klogd 1.3-3, log source = /proc/kmsg started.
> Feb 15 23:43:35 atlas kernel: Loaded 4922 symbols from /boot/System.map.
> Feb 15 23:43:35 atlas kernel: Symbols match kernel version 2.2.1.
> Feb 15 23:43:35 atlas kernel: Error seeking in /dev/kmem
> Feb 15 23:43:35 atlas kernel: Error adding kernel module table entry.

> i already searched the archives at http://www.egroups.com but could not
> find any solution regarding this problem.

The problem arises from the fact that the kernel memory layout changed
in 2.2.x. This requires that the kernel use llseek when trying to
read /dev/kmem for the kernel module symbols.

I am inserting my current set of patches against the stock 1.3 version
of sysklogd which is on most of the archive sites in this note. This
will produce a tested version of sysklogd which I am running on
production servers with 2.2.1 right now. This patch set also contains
fixes for the syslogd signal problem and the fprintf/fputs problem
with % signs.

Please let me know if you have any problems with this.

Cut here to begin removal of kernel patch. --------------------------------
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/Makefile sysklogd-1.3/Makefile
--- v1.3-3/sysklogd-1.3/Makefile Fri Feb 6 00:22:28 1998
+++ sysklogd-1.3/Makefile Sun Oct 4 03:16:57 1998
@@ -3,8 +3,10 @@
CC= gcc
#CFLAGS= -g -DSYSV -Wall
#LDFLAGS= -g
-CFLAGS= -O2 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce -m486 -malign-jumps=2
-LDFLAGS= -s
+CDEBUG= -g
+COPTS= -O2 -fomit-frame-pointer -fno-strength-reduce -m486 -malign-jumps=2
+CFLAGS= -DSYSV -Wall ${COPTS} ${CDEBUG}
+LDFLAGS= #-s

# Look where your install program is.
INSTALL = /usr/bin/install
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/NEWS sysklogd-1.3/NEWS
--- v1.3-3/sysklogd-1.3/NEWS Fri Feb 6 00:22:28 1998
+++ sysklogd-1.3/NEWS Sun Oct 4 10:23:05 1998
@@ -1,3 +1,25 @@
+Version 1.3 Patch Level 4
+General. ------------------------------------------------------------------
+Updated Makefile to segregate compiler optimization flags into a separate
+variable.
+
+Remedied general dumbness of using fprintf on fixed strings instead of
+fputs.
+
+syslogd ------------------------------------------------------------------
+Added RedHat patch to use library routines to access utmp file rather
+than direct I/O.
+
+Changed signal which is sent to parent process from SIGINT to SIGALRM.
+This prevents an auto-backgrounding process from incorrectly exiting with
+a non-zero error value.
+
+Added 'stunning' capability to syslogd. Sending SIGTSTP will cause
+syslogd to suspending logging. SIGCONT resumes logging including
+output of all messages received while syslogd was stunned. Useful for
+people who worry about consistency during log cycling.
+
+
Version 1.3 Patch Level 3

General. ------------------------------------------------------------------
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/ksym.c sysklogd-1.3/ksym.c
--- v1.3-3/sysklogd-1.3/ksym.c Fri Feb 6 00:22:29 1998
+++ sysklogd-1.3/ksym.c Thu Oct 8 05:54:58 1998
@@ -334,14 +334,14 @@
{
case -1:
if ( debugging )
- fprintf(stderr, "Symbol table has incorrect " \
- "version number.\n");
+ fputs("Symbol table has incorrect version "
+ "number.\n", stderr);
break;

case 0:
if ( debugging )
- fprintf(stderr, "No version information " \
- "found.\n");
+ fputs("No version information found.\n", \
+ stderr);
if ( file == (char *) 0 )
{
if ( debugging )
@@ -351,8 +351,8 @@
break;
case 1:
if ( debugging )
- fprintf(stderr, "Found table with " \
- "matching version number.\n");
+ fputs("Found table with matching version " \
+ "number.\n", stderr);
return(*mf);
break;
}
@@ -367,7 +367,7 @@
* encountered.
*/
if ( debugging )
- fprintf(stderr, "End of search list encountered.\n");
+ fputs("End of search list encountered.\n", stderr);
return(file);
}

@@ -564,7 +564,8 @@
}
last = sym_array[lp].name;
}
-
+ /*DEBUG*/
+ fputs("Calling LookupModuleSymbol\n", stderr);
if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 )
return(last);

@@ -634,7 +635,7 @@
*elp = el,
*symbol;

- auto int value;
+ auto unsigned long int value;

auto struct symbol sym;

@@ -686,14 +687,14 @@
}
dlm = *kp;
*kp = '\0';
- value = strtol(sl+1, (char **) 0, 16);
+ value = strtoul(sl+1, (char **) 0, 16);
if ( (symbol = LookupSymbol(value, &sym)) == (char *) 0 )
symbol = sl;

strcat(elp, symbol);
elp += strlen(symbol);
if ( debugging )
- fprintf(stderr, "Symbol: %s = %x = %s, %d/%d\n", \
+ fprintf(stderr, "Symbol: %s = %lx = %s, %d/%d\n", \
sl+1, value, \
(sym.size==0) ? symbol+1 : symbol, \
sym.offset, sym.size);
@@ -769,6 +770,8 @@
fputs("ksym: Error loading system map.\n", stderr);
return(1);
}
+
+ InitMsyms();

while ( !feof(stdin) )
{
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/ksym_mod.c sysklogd-1.3/ksym_mod.c
--- v1.3-3/sysklogd-1.3/ksym_mod.c Fri Feb 6 00:22:29 1998
+++ sysklogd-1.3/ksym_mod.c Tue Feb 9 14:18:04 1999
@@ -67,7 +67,7 @@


/*
- * The following bit uses some kernel/library magic to product what
+ * The following bit uses some kernel/library magic to produce what
* looks like a function call to user level code. This function is
* actually a system call in disguise. The purpose of the getsyms
* call is to return a current copy of the in-kernel symbol table.
@@ -93,6 +93,8 @@
int num_syms;

char *name;
+ /*DEBUG*/
+ unsigned long size;
struct module module;
};

@@ -335,13 +337,15 @@
{
/*
* A symbol which consists of a # sign only
- * signifies a a resident kernel segment. When we
+ * signifies a resident kernel segment. When we
* hit one of these we are done reading the
* module list.
*/
have_modules = 1;
return(1);
}
+ /*DEBUB*/
+ fprintf(stderr, "Processing module: %s\n", symbol);
/* Allocate space for the module. */
sym_array_modules = (struct Module *) \
realloc(sym_array_modules, \
@@ -358,7 +362,7 @@
Syslog(LOG_WARNING, "Error opening /dev/kmem\n");
return(1);
}
- if ( lseek(memfd, address, SEEK_SET) < 0 )
+ if ( llseek(memfd, address, SEEK_SET) < 0 )
{
Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n");
return(0);
@@ -372,6 +376,25 @@
return(0);
}
close(memfd);
+ /*DEBUG*/
+#if 0
+ {
+ auto struct module *dp;
+ dp = &sym_array_modules[num_modules].module;
+ fprintf(stderr, "Module address: %lx\n", address);
+ fprintf(stderr, "Struct size: %lu\n", \
+ sym_array_modules[num_modules].module.size_of_struct);
+#if 0
+ fprintf(stderr, "Struct size: %lu, Name: %s, " \
+ "size: %lu\n", dp->size_of_struct, dp->name, \
+ dp->size);
+#else
+ fprintf(stderr, "Struct size: %lu, Size: %lu\n", \
+ dp->size_of_struct, dp->size);
+ sym_array_modules[num_modules].size = dp->size;
+#endif
+ }
+#endif

/* Save the module name. */
mp->name = (char *) malloc(strlen(&symbol[1]) + 1);
@@ -487,7 +510,9 @@

auto struct Module *mp;

-
+ /*DEBUG*/
+ fprintf(stderr, "\tLookupModule: %lx num_modules = %d\n", value, \
+ num_modules);
sym->size = 0;
sym->offset = 0;
if ( num_modules == 0 )
@@ -505,6 +530,8 @@
nsym < mp->num_syms;
++nsym)
{
+ /*DEBUG*/
+ fprintf(stderr, "Looking at %s\n", mp->sym_array[nsym].name);
if ( mp->sym_array[nsym].value > value )
{
sym->offset = value - last->value;
@@ -512,6 +539,16 @@
last->value;
return(last->name);
}
+ /* Check for fault address = symbol address. */
+ if ( nsym == (mp->num_syms - 1) &&
+ mp->sym_array[nsym].value == value )
+ {
+ sym->offset = value - \
+ mp->sym_array[nsym].value;
+ sym->size = 0;
+ return(mp->sym_array[nsym].name);
+ }
+
last = &mp->sym_array[nsym];
}

@@ -525,6 +562,7 @@
* If it is in this range we can at least return the
* name of the module.
*/
+#if 0
if ( (void *) value >= mp->module.addr &&
(void *) value <= (mp->module.addr + \
mp->module.size * 4096) )
@@ -561,6 +599,7 @@
sym->offset = (void *) value - mp->module.addr;
return(mp->name);
}
+#endif
}

/* It has been a hopeless exercise. */
@@ -593,7 +632,7 @@

if ( !InitMsyms() )
{
- fprintf(stderr, "Cannot load module symbols.\n");
+ fputs("Cannot load module symbols.\n", stderr);
return(1);
}

diff -u --recursive --new-file v1.3-3/sysklogd-1.3/ksym_query.c sysklogd-1.3/ksym_query.c
--- v1.3-3/sysklogd-1.3/ksym_query.c Wed Dec 31 18:00:00 1969
+++ sysklogd-1.3/ksym_query.c Sat Oct 24 08:41:52 1998
@@ -0,0 +1,76 @@
+/*
+ ksym_query.c - functions for querying module information.
+ Copyright (c) 1998 Dr. G.W. Wettstein, Enjellic Systems Development
+
+ This file is part of the sysklogd package, a kernel and system log daemon.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <linux/module.h>
+
+
+#define __LIBRARY__
+#include <asm/unistd.h>
+#if !defined(__NR_query_module)
+# if defined(__i386__)
+# define __NR_query_module 167
+# elif defined(__alpha__)
+# define __NR_query_module 347
+# elif defined(__sparc__)
+# define __NR_query_module 184
+# endif
+#endif
+#define __NR_getinfo __NR_query_module
+
+_syscall5(int, getinfo, const char *, name, int, which,
+ void *, buf, size_t, bufsize, size_t *, ret);
+
+#undef __LIBRARY__
+extern int getinfo(const char *, int, void *, size_t, size_t *);
+
+#if defined(TEST)
+
+extern int main(int, char **);
+
+#include <stdio.h>
+
+extern int main(int argc, char *argv[])
+
+{
+ auto struct module_info bufr;
+ auto int retn;
+ auto size_t r;
+
+ memset(&bufr, '\0', sizeof(bufr));
+ retn = getinfo("oops", QM_INFO, &bufr, sizeof(bufr), &r);
+ printf("retn = %d\n", retn);
+ if ( retn != 0 )
+ {
+ fprintf(stderr, "Error on getinfo: %d\n", retn);
+ return(1);
+ }
+
+ puts("Module info:\n");
+ printf("\tAddress: %lx/%lu\n", bufr.addr, bufr.addr);
+ printf("\tSize: %lu\n", bufr.size);
+ printf("\tFlags: %lx\n", bufr.flags);
+ printf("\tUse: %ld\n", bufr.usecount);
+
+ return(0);
+}
+#endif
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/oops.c sysklogd-1.3/oops.c
--- v1.3-3/sysklogd-1.3/oops.c Fri Feb 6 00:22:29 1998
+++ sysklogd-1.3/oops.c Wed Oct 21 04:34:45 1998
@@ -16,7 +16,12 @@
#include <linux/errno.h>
#include <linux/fs.h>

+/* New. */
+#define EXPORT_SYMTAB
+#include <linux/version.h>
+#include <linux/module.h>
/* Standard module stuff. */
+#if 0
#if defined(NEW_MODULES)
#include <linux/module.h>
#else
@@ -24,6 +29,7 @@
#include <linux/version.h>
char kernel_version[] = UTS_RELEASE;
#endif
+#endif


static int major = 32;
@@ -34,6 +40,7 @@
static int oops_open(struct inode * node, struct file * file);
static void oops(void);

+#if LINUX_VERSION_CODE <= 131107
static struct symbol_table these_symbols = {
#include <linux/symtab_begin.h>
X(oops_open),
@@ -41,6 +48,11 @@
X(oops),
#include <linux/symtab_end.h>
};
+#else
+EXPORT_SYMBOL(oops_open);
+EXPORT_SYMBOL(oops_ioctl);
+EXPORT_SYMBOL(oops);
+#endif

/* driver specific module definitions */
static struct file_operations oops_fops1 = {
@@ -96,7 +108,9 @@
}

printk("oops: Registering symbols.\n");
+#if 0
register_symtab(&these_symbols);
+#endif

return 0;
}
@@ -106,7 +120,7 @@
cleanup_module(void)
{
/* driver specific cleanups, ususally "unregister_*()" */
- printk("oops: Module unloadeding.\n");
+ printk("oops: Module unloading.\n");
if (unregister_chrdev(major, "oops") != 0)
printk("cleanup_module failed\n");
else
@@ -115,4 +129,5 @@
return;

}
+
#endif /* MODULE */
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/oops_test.c sysklogd-1.3/oops_test.c
--- v1.3-3/sysklogd-1.3/oops_test.c Fri Feb 6 00:22:30 1998
+++ sysklogd-1.3/oops_test.c Fri Feb 6 01:29:06 1998
@@ -29,7 +29,7 @@

if ( argc != 2 )
{
- fprintf(stderr, "No oops device specified.\n");
+ fputs("No oops device specified.\n", stderr);
return(1);
}

@@ -41,7 +41,7 @@

if ( ioctl(fd, 1, 0) < 0 )
{
- fprintf(stderr, "Failed on oops.\n");
+ fputs("Failed on oops.\n", stderr);
return(1);
}

diff -u --recursive --new-file v1.3-3/sysklogd-1.3/pidfile.c sysklogd-1.3/pidfile.c
--- v1.3-3/sysklogd-1.3/pidfile.c Fri Feb 6 00:22:30 1998
+++ sysklogd-1.3/pidfile.c Fri Feb 6 01:29:43 1998
@@ -101,7 +101,7 @@
}

pid = getpid();
- if (!fprintf(f,"%d\n", pid)) {
+ if (!fprintf(f, "%d\n", pid)) {
printf("Can't write pid , %s.\n", strerror(errno));
close(fd);
return 0;
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/syslog-tst.conf sysklogd-1.3/syslog-tst.conf
--- v1.3-3/sysklogd-1.3/syslog-tst.conf Fri Feb 6 00:22:30 1998
+++ sysklogd-1.3/syslog-tst.conf Sun Oct 4 03:39:10 1998
@@ -0,0 +1 @@
+*.* /u/usr/sources/bin/sysklogd/sysklogd-1.3/Syslog.Output
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/syslogd.c sysklogd-1.3/syslogd.c
--- v1.3-3/sysklogd-1.3/syslogd.c Fri Feb 6 00:22:30 1998
+++ sysklogd-1.3/syslogd.c Fri Nov 13 02:21:22 1998
@@ -277,6 +277,20 @@
* (Edvard.Tuinder@praseodymium.cistron.nl) for putting me on the
* trail of this bug. I am amazed that we didn't catch this one
* before now.
+ *
+ * Sun Oct 4 03:06:05 CDT 1998: Dr. Wettstein
+ * Integrated patches from RedHat to use library routines for
+ * UTMP access than than direct file I/O.
+ *
+ * Changed signal handling routines to prevent auto-background
+ * process from incorrectly exiting with a non-zero error value.
+ *
+ * Sun Oct 4 10:23:37 CDT 1998: Dr. Wettstein
+ * Added support for 'stunning' syslogd. Signalling the daemon
+ * with SIGTSTP will cause log output to be suspended. The main
+ * select loop will emit a message that logging is suspended
+ * every 10 TIMERINTVL seconds to remind someone who may have
+ * forgotten that they suspended logging.
*/


@@ -552,6 +566,8 @@
char **LocalHosts = NULL; /* these hosts are logged with their hostname */
int NoHops = 1; /* Can we bounce syslog messages through an
intermediate host. */
+int stunned = 0; /* Flag to indicate that logging is currently
+ suspended. */

extern int errno, sys_nerr;
extern char *sys_errlist[];
@@ -581,6 +597,8 @@
static void dprintf(char *, ...);
static void allocate_log(void);
void sighup_handler();
+void stun_daemon();
+void unstun_daemon();


int main(argc, argv)
@@ -664,12 +682,17 @@
if (!check_pid(PidFile))
{
quitpid = getpid();
- if (fork())
+ if ( fork() )
{
- /* We try to wait the end of initialization */
+ /*
+ * This is the parent process. We will
+ * wait for the end of the initialization.
+ */
sleep(10);
exit(0);
}
+
+ /* Child process continueing with initialization. */
num_fds = getdtablesize();
for (i= 0; i < num_fds; i++)
(void) close(i);
@@ -752,6 +775,8 @@
(void) signal(SIGCHLD, reapchild);
(void) signal(SIGALRM, domark);
(void) signal(SIGUSR1, Debug ? debug_switch : SIG_IGN);
+ (void) signal(SIGTSTP, stun_daemon);
+ (void) signal(SIGCONT, unstun_daemon);
(void) alarm(TIMERINTVL);
(void) unlink(LogName);

@@ -829,7 +854,7 @@
}

if (quitpid) {
- kill(quitpid, SIGINT);
+ kill(quitpid, SIGALRM);
}

/* Main loop begins here. */
@@ -867,6 +892,16 @@
}
nfds = select(FD_SETSIZE, (fd_set *) &readfds, (fd_set *) NULL,
(fd_set *) NULL, (struct timeval *) NULL);
+ if ( stunned )
+ {
+ if ( (stunned++ % 10) == 0 )
+ {
+ errno = 0;
+ logerror("Logging suspended.");
+ }
+ pause();
+ dprintf("Looping after stunned pause.\n");
+ }
if ( restart )
{
dprintf("\nReceived SIGHUP, reloading syslogd.\n");
@@ -905,7 +940,8 @@
dprintf("\n");
}
for (fd= 0; fd < FD_SETSIZE; ++fd)
- if ( FD_ISSET(fd, &readfds) && FD_ISSET(fd, &unixm) ) {
+ if ( !stunned && FD_ISSET(fd, &readfds) && \
+ FD_ISSET(fd, &unixm) ) {
dprintf("Message from UNIX socket #%d.\n", fd);
memset(line, '\0', sizeof(line));
i = read(fd, line, MAXLINE);
@@ -1579,20 +1615,17 @@
char p[6 + UNAMESZ];
register int i;
int ttyf, len;
- FILE *uf;
static int reenter = 0;
struct utmp ut;
+ struct utmp *uptr;
char greetings[200];

if (reenter++)
return;

/* open the user login file */
- if ((uf = fopen(UTMP_FILE, "r")) == NULL) {
- logerror(UTMP_FILE);
- reenter = 0;
- return;
- }
+ utmpname(_PATH_UTMP);
+ setutent();

/*
* Might as well fork instead of using nonblocking I/O
@@ -1612,7 +1645,8 @@
len = strlen(greetings);

/* scan the user login file */
- while (fread((char *) &ut, sizeof(ut), 1, uf) == 1) {
+ while ((uptr = getutent())) {
+ memcpy(&ut, uptr, sizeof(ut));
/* is this slot used? */
if (ut.ut_name[0] == '\0')
continue;
@@ -1664,7 +1698,7 @@
exit(0);
}
/* close the user login file */
- (void) fclose(uf);
+ endutent();
reenter = 0;
}

@@ -2338,5 +2372,30 @@
{
restart = 1;
signal(SIGHUP, sighup_handler);
+ return;
+}
+
+/*
+ * The following two functions implement signal handling for the 'stun'
+ * capability. The main work of logging suspension is done by a
+ * clause in the main select loop which checks for the global stunned
+ * variable.
+ */
+
+void stun_daemon()
+
+{
+ dprintf("Logging suspended.\n");
+ stunned = 1;
+ signal(SIGTSTP, stun_daemon);
+ return;
+}
+
+void unstun_daemon()
+
+{
+ dprintf("Logging resumed after suspension.\n");
+ stunned = 0;
+ signal(SIGCONT, unstun_daemon);
return;
}
diff -u --recursive --new-file v1.3-3/sysklogd-1.3/version.h sysklogd-1.3/version.h
--- v1.3-3/sysklogd-1.3/version.h Fri Feb 6 00:22:30 1998
+++ sysklogd-1.3/version.h Thu Feb 12 01:57:38 1998
@@ -1,2 +1,2 @@
#define VERSION "1.3"
-#define PATCHLEVEL "3"
+#define PATCHLEVEL "4"
Cut here to complete removal of kernel patch.------------------------------

> francis vidal university of st. la salle, bacolod city, philippines

}-- End of excerpt from "Francis A. Vidal"

As always,
Dr. G.W. Wettstein Enjellic Systems Development - Specialists in
4206 N. 19th Ave. intranet based enterprise information solutions.
Fargo, ND 58102 WWW: http://www.enjellic.com
Phone: 701-281-1686 EMAIL: greg@wind.enjellic.com
------------------------------------------------------------------------------
"Intel engineering seem to have misheard Intel marketing strategy. The
phrase was 'Divide and conquer' not 'Divide and cock up'".
-- Alan Cox

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/