Hello!
I've got idea that it would be nice to have ability to
load arbitrary sysrq functionality on the fly.
E.g. if I am just awaiting nasty kernel panic, and I
do not have serial/whatever console, I'll load
'dump to floppy' module that activates via sysrq-d
(I've seen one some time ago in l-k) and happily
dumps panic message to floppy. (or call whatever
diagnostic function...)
Or even I can unload SAK sysrq module, and no one use it
to kill my console-locking program and insert it back,
when I need it (Yes, I know that sysctl interface
to sysrq exists in -ac tree, that's just somewhat wider idea)
Attached is 'demo version' of patch, that only adds new API
to kernel without converting current sysrqs to use it.
And also sample module to show basic work.
If people thinks that it is useful I'll convert old-style
sysrqs to new API and, optionally, make 'em loadable modules
(configurable of course)
Bye,
Oleg
--ELM930441895-424-0_
Content-Type: text/plain
Content-Disposition: attachment; filename=sysrq.patch
Content-Description: /tmp/sysrq.patch
Content-Transfer-Encoding: 7bit
--- linux/drivers/char/sysrq.c.orig Sun Jun 27 02:58:20 1999
+++ linux/drivers/char/sysrq.c Sun Jun 27 03:08:19 1999
@@ -33,6 +33,66 @@
extern int console_loglevel;
extern struct vfsmount *vfsmntlist;
+#ifdef CONFIG_SYSRQ_MODULES
+#include <linux/module.h>
+unsigned char num_sysrqs=0; /* Who ever needs more than 256 sysrqs? ;) */
+struct sysrq_struct *loaded_sysrqs=NULL;
+#define SYSRQ_ALLOCATION_SIZE (PAGE_SIZE)
+#define SYSRQS_PER_PAGE (SYSRQ_ALLOCATION_SIZE/sizeof(struct sysrq_struct))
+
+int register_sysrq(int key, void (*handler)(void), char *message, char *helper)
+{
+ int i;
+
+ if (!loaded_sysrqs) {
+ loaded_sysrqs=(struct sysrq_struct *)get_free_page(GFP_KERNEL);
+ if (!loaded_sysrqs) {
+ printk(KERN_ALERT "register_sysrq: unable to allocate memory\n");
+ return 0;
+ }
+ }
+ if (num_sysrqs > SYSRQS_PER_PAGE || num_sysrqs == 255) {
+ printk(KERN_ALERT "register_sysrq: No more space to sysrqs\n");
+ return 0;
+ }
+ for (i=0;i<num_sysrqs;i++) {
+ if (loaded_sysrqs[i].key == key) {
+ printk(KERN_ALERT "register_sysrq: there is sysrq for key '%c' already\n",key);
+ return 0;
+ }
+ }
+ loaded_sysrqs[num_sysrqs].key=key;
+ loaded_sysrqs[num_sysrqs].handler=handler;
+ loaded_sysrqs[num_sysrqs].message=message;
+ loaded_sysrqs[num_sysrqs].helper=helper;
+ num_sysrqs++;
+
+ return 1;
+}
+
+int unregister_sysrq(int key, void (*handler)(void))
+{
+ int i,result=0;
+
+ if (!loaded_sysrqs || !num_sysrqs) {
+ printk(KERN_ALERT "unregister_sysrq: There is no SysRQs to unregister\n");
+ return 1;
+ }
+ for (i=0;i<num_sysrqs;i++) {
+ if (loaded_sysrqs[i].key == key && loaded_sysrqs[i].handler==handler) {
+ num_sysrqs--;
+ for ( ; i < num_sysrqs ; i++)
+ loaded_sysrqs[i] = loaded_sysrqs[i+1];
+ result=1;
+ }
+ }
+ if ( !num_sysrqs )
+ free_page((unsigned long)loaded_sysrqs);
+
+ return result;
+}
+#endif
+
/* Send a signal to all user processes */
static void send_sig_all(int sig, int even_init)
@@ -57,7 +117,9 @@
struct kbd_struct *kbd, struct tty_struct *tty)
{
int orig_log_level = console_loglevel;
-
+#ifdef CONFIG_SYSRQ_MODULES
+ int i=0;
+#endif
if (!key)
return;
@@ -131,6 +193,18 @@
orig_log_level = 8;
break;
default: /* Unknown: help */
+#ifdef CONFIG_SYSRQ_MODULES
+ if (loaded_sysrqs)
+ for (i=0; i<num_sysrqs; i++) {
+ if (loaded_sysrqs[i].key==key) {
+ printk("%s\n",loaded_sysrqs[i].message);
+ loaded_sysrqs[i].handler();
+ break;
+ }
+ }
+
+ if (i<num_sysrqs) break;
+#endif
if (kbd)
printk("unRaw ");
#ifdef CONFIG_VT
@@ -141,8 +215,14 @@
#ifdef CONFIG_APM
"Off "
#endif
- "Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n");
+ "Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL");
/* Don't use 'A' as it's handled specially on the Sparc */
+#ifdef CONFIG_SYSRQ_MODULES
+ if (loaded_sysrqs)
+ for (i=0; i<num_sysrqs; i++)
+ printk(" %s",loaded_sysrqs[i].helper);
+#endif
+ printk("\n");
}
console_loglevel = orig_log_level;
@@ -254,3 +334,8 @@
unlock_kernel();
printk(KERN_INFO "Done.\n");
}
+
+#ifdef CONFIG_SYSRQ_MODULES
+EXPORT_SYMBOL(register_sysrq);
+EXPORT_SYMBOL(unregister_sysrq);
+#endif
--- linux/include/linux/sysrq.h.orig Sun Apr 18 13:33:16 1999
+++ linux/include/linux/sysrq.h Sun Jun 27 02:06:53 1999
@@ -36,3 +36,16 @@
#else
#define CHECK_EMERGENCY_SYNC
#endif
+
+#ifdef CONFIG_SYSRQ_MODULES
+struct sysrq_struct {
+ int key; /* Key to activate */
+ void (*handler)(void); /* Function to run */
+ char *message; /* Message to print befor executing handler */
+ char *helper; /* Short help message */
+};
+
+ int register_sysrq(int key, void (*handler)(void), char *message, char *helper);
+int unregister_sysrq(int key, void (*handler)(void));
+
+#endif
--- linux/arch/i386/config.in.orig Sun Jun 27 02:49:19 1999
+++ linux/arch/i386/config.in Sun Jun 27 01:55:11 1999
@@ -205,5 +205,8 @@
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+if [ "$CONFIG_MAGIC_SYSRQ" != "n" ]; then
+ bool 'Loadable Magic SysRqs' CONFIG_SYSRQ_MODULES
+fi
endmenu
--ELM930441895-424-0_
Content-Type: text/plain
Content-Disposition: attachment; filename=sysrq.c
Content-Description: sysrq.c
Content-Transfer-Encoding: 7bit
/*
Sample sysrq module. Compile with:
gcc -D__KERNEL__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o sysrq.o sysrq.c
*/
#include <linux/module.h>
#include <linux/sysrq.h>
void demo_handler(void) {
printk("This is a demo SysRq module in run\n");
}
int init_module(void)
{
if (!register_sysrq('d',&demo_handler,"Demo SysRq module","Demo") ) return -1;
return 0;
}
void cleanup_module(void)
{
unregister_sysrq('d',&demo_handler);
}
--ELM930441895-424-0_--
-
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/