Update patches
Subsystems (5)
cover Update patches
Hi!
I fixed diskdump patches except timer problem.
- Fix some codes which Arjan van de Ven pointed out
- Replace dev_t with block_device
Source code of tool(diskdumptuils) can be downloaded from
http://sourceforge.net/projects/lkdump
Regarding timer problem, please see previous mail I sent.
http://marc.theaimsgroup.com/?l=linux-kernel&m=108722344204595&w=2
In short, Timer problem is as follows.
Quoted 2 lines
What is a problem? Scsi driver uses timer/tasklet to complete I/O. But, diskdump disables interrupt, so timer/taslket doesn't work!
There are three ways to solve this problem so far.
(1) Redefine timer/taslket routines. This method was adopted in the first patch.
+#if defined(CONFIG_DISKDUMP) || defined(CONFIG_DISKDUMP_MODULE) +#undef add_timer
+#define add_timer diskdump_add_timer
+#undef del_timer_sync
+#define del_timer_sync diskdump_del_timer
+#undef del_timer
+#define del_timer diskdump_del_timer
+#undef mod_timer
+#define mod_timer diskdump_mod_timer
+
+#define tasklet_schedule diskdump_tasklet_schedule
+#endif
(2) Add new code into the timer/taslket routines themselves.
static inline void add_timer(struct timer_list * timer) {
- __mod_timer(timer, timer->expires);
+ if(crashdump_mode())
+ diskdump_add_timer(timer);
+ else
+ __mod_timer(timer, timer->expires);
}
int del_timer_sync(struct timer_list *timer)
{
tvec_base_t *base;
int i, ret = 0;
+ if(crashdump_mode()) {
+ diskdump_del_timer(timer);
+ return 0;
+ }
+
check_timer(timer);
int mod_timer(struct timer_list *timer, unsigned long expires) {
BUG_ON(!timer->function);
+ if(crashdump_mode()) {
+ diskdump_mod_timer(timer, expires);
+ return 0;
+ }
+
check_timer(timer);
static inline void tasklet_schedule(struct tasklet_struct *t) {
+ if(crashdump_mode()) {
+ diskdump_tasklet_schedule(t);
+ return;
+ }
+
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
__tasklet_schedule(t);
}
(3) Change polling handler of driver not to use timer/tasklet.
The method (1) was already rejected because of its ugliness. The method (3) needs many extra codes and makes handler of driver too big and complex. I think the method (2) is the simplest though it make common codes dirty.
Please feel free to comment.
Best Regards,
Takao Indoh
PATCH 1/4 Update patches
This is a patch for diskdump common layer.
arch/i386/kernel/nmi.c +1 -0
@@ -517,3 +517,4 @@EXPORT_SYMBOL (release_lapic_nmi);EXPORT_SYMBOL (disable_timer_nmi_watchdog);EXPORT_SYMBOL (enable_timer_nmi_watchdog); +EXPORT_SYMBOL (touch_nmi_watchdog);
arch/i386/kernel/reboot.c +2 -1
@@ -252,7 +252,8 @@* Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. */ -smp_send_stop (); +if (!crashdump_mode ()) +smp_send_stop ();#elif defined(CONFIG_X86_LOCAL_APIC )if (cpu_has_apic) {local_irq_disable ();
arch/i386/kernel/traps.c +3 -1
@@ -258,7 +258,8 @@int nl =0 ;console_verbose (); -spin_lock_irq (&die_lock); +if (!crashdump_mode ()) +spin_lock_irq (&die_lock);bust_spinlocks (1 );handle_BUG (regs);printk ("%s: %04lx [#%d]\n" , str, err &0xffff , ++die_counter);
@@ -277,6 +278,7 @@if (nl)printk ("\n" );show_registers (regs); +try_crashdump (regs);bust_spinlocks (0 );spin_unlock_irq (&die_lock);if (in_interrupt ())
arch/i386/mm/init.c +2 -1
@@ -168,7 +168,7 @@extern int is_available_memory (efi_memory_desc_t *); -static inline int page_is_ram (unsigned long pagenr) +int page_is_ram (unsigned long pagenr) {int i;unsigned long addr, end;
@@ -205,6 +205,7 @@ }return 0 ; } +EXPORT_SYMBOL (page_is_ram);#ifdef CONFIG_HIGHMEM pte_t *kmap_pte;
drivers/block/Kconfig +5 -0
@@ -346,6 +346,11 @@ your machine, or if you want to have a raid or loopback device bigger than 2TB. Otherwise say N. +config DISKDUMP + tristate "Disk dump support" + ---help--- + Disk dump support. + source "drivers/s390/block/Kconfig" endmenu
drivers/block/Makefile +1 -0
@@ -43,3 +43,4 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_CARMEL) += carmel.o +obj-$(CONFIG_DISKDUMP) += diskdump.o diskdumplib.o
drivers/block/diskdump.c +973 -0
973 lines not on this page · raw message
drivers/block/diskdumplib.c +203 -0
203 lines not on this page · raw message
drivers/block/genhd.c +25 -0
@@ -629,3 +629,28 @@ }EXPORT_SYMBOL (invalidate_partition); + +/* +* Dump stuff. +*/ +void (*diskdump_func) (struct pt_regs *regs,void *platform_arg) =NULL ; +EXPORT_SYMBOL_GPL (diskdump_func); + +int diskdump_register_hook (void (*dump_func) (struct pt_regs *,void *)) +{ +if (diskdump_func) +return -EEXIST ; + + diskdump_func = dump_func; + +return 0 ; +} + +EXPORT_SYMBOL_GPL (diskdump_register_hook); + +void diskdump_unregister_hook (void ) +{ + diskdump_func =NULL ; +} + +EXPORT_SYMBOL_GPL (diskdump_unregister_hook);
drivers/char/sysrq.c +14 -1
@@ -107,6 +107,19 @@ .action_msg = "Resetting", }; +/* crash sysrq handler */ +static void sysrq_handle_crash (int key,struct pt_regs *pt_regs, +struct tty_struct *tty) +{ + *( (char *)0 ) =0 ; +} + +static struct sysrq_key_op sysrq_crash_op = { + .handler = sysrq_handle_crash, + .help_msg ="Crash" , + .action_msg ="Crashing the kernel by request" , +}; +static void sysrq_handle_sync (int key,struct pt_regs *pt_regs,struct tty_struct *tty) {
@@ -235,7 +248,7 @@it is handled specially on the sparc and will never arrive */ /* b */ &sysrq_reboot_op, -/* c */ NULL , +/* c */ &sysrq_crash_op,/* d */ NULL ,/* e */ &sysrq_term_op, /* f */ NULL,
include/asm-i386/diskdump.h +82 -0
82 lines not on this page · raw message
include/asm-i386/kmap_types.h +2 -1
@@ -24,7 +24,8 @@ D(11) KM_IRQ1, D(12) KM_SOFTIRQ0, D(13) KM_SOFTIRQ1, -D(14) KM_TYPE_NR +D(14) KM_DISKDUMP, +D(15) KM_TYPE_NR };#undef D
include/linux/diskdump.h +157 -0
157 lines not on this page · raw message
include/linux/diskdumplib.h +67 -0
67 lines not on this page · raw message
include/linux/kernel.h +11 -0
@@ -112,6 +112,11 @@extern int system_state;/* See values below */ extern int tainted;extern const char *print_tainted (void ); +struct pt_regs ; +extern void try_crashdump (struct pt_regs *); +extern void (*diskdump_func) (struct pt_regs *regs,void *platform_arg); +extern int diskdump_mode; +#define crashdump_mode () (diskdump_mode)/* Values used for system_state */ #define SYSTEM_BOOTING 0
@@ -136,6 +141,12 @@ #define pr_info(fmt,arg...) \ printk(KERN_INFO fmt,##arg) +#define pr_err(fmt,arg...) \ + printk(KERN_ERR fmt,##arg) + +#define pr_warn(fmt,arg...) \ + printk(KERN_WARNING fmt,##arg) +/* * Display an IP address in readable format. */
kernel/panic.c +24 -0
@@ -23,8 +23,10 @@int panic_timeout;int panic_on_oops;int tainted; +int diskdump_mode =0 ;EXPORT_SYMBOL (panic_timeout); +EXPORT_SYMBOL_GPL (diskdump_mode);struct notifier_block *panic_notifier_list;
@@ -60,6 +62,8 @@vsnprintf (buf,sizeof (buf), fmt, args);va_end (args);printk (KERN_EMERG "Kernel panic: %s\n" ,buf); +if (diskdump_func) +BUG ();if (in_interrupt ())printk (KERN_EMERG "In interrupt handler - not syncing\n" );else if (!current->pid)
@@ -134,3 +138,23 @@snprintf (buf,sizeof (buf),"Not tainted" );return (buf); } + +/* +* Try crashdump. Diskdump is first, netdump is second. +* We clear diskdump_func before call of diskdump_func, so +* If double panic would occur in diskdump, netdump can handle +* it. +*/ +#include <asm/diskdump.h> +void try_crashdump (struct pt_regs *regs) +{ +void (*func)(struct pt_regs *,void *); + +if (diskdump_func) { + func = diskdump_func; + diskdump_func =NULL ; +platform_start_diskdump (func, regs); + } +if (panic_on_oops) +panic ("Fatal exception" ); +}
mm/bootmem.c +2 -0
@@ -16,6 +16,7 @@#include <linux/init.h> #include <linux/bootmem.h> #include <linux/mmzone.h> +#include <linux/module.h> #include <asm/dma.h> #include <asm/io.h>
@@ -26,6 +27,7 @@unsigned long max_low_pfn;unsigned long min_low_pfn;unsigned long max_pfn; +EXPORT_SYMBOL (max_pfn);/* return the number of _pages_ that will be allocated for the boot bitmap */ unsigned long __init bootmem_bootmap_pages (unsigned long pages)
PATCH 2/4 Update patches
In reply to Takao IndohThis is a patch for scsi common layer.
drivers/scsi/Kconfig +6 -0
@@ -55,6 +55,12 @@ In this case, do not compile the driver for your SCSI host adapter (below) as a module either. +config SCSI_DUMP + tristate "SCSI dump support" + depends on DISKDUMP && SCSI + help + SCSI dump support + config CHR_DEV_ST tristate "SCSI tape support" depends on SCSI
drivers/scsi/Makefile +2 -0
@@ -133,6 +133,8 @@ obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o +obj-$(CONFIG_SCSI_DUMP) += scsi_dump.o + scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ scsi_scan.o scsi_syms.o scsi_sysfs.o \
drivers/scsi/scsi.c +3 -0
@@ -691,6 +691,9 @@ {unsigned long flags; +if (crashdump_mode ()) +return ; +/* * We don't have to worry about this one timing out any more. * If we are unable to remove the timer, then the command
drivers/scsi/scsi_dump.c +579 -0
579 lines not on this page · raw message
drivers/scsi/scsi_error.c +3 -0
@@ -402,6 +402,9 @@**/ static void scsi_eh_done (struct scsi_cmnd *scmd) { +if (crashdump_mode ()) +return ; +/* * if the timeout handler is already running, then just set the * flag which says we finished late, and return. we have no
drivers/scsi/scsi_syms.c +3 -0
@@ -25,6 +25,7 @@#include "scsi.h" #include "scsi_logging.h" +#include "scsi_priv.h" /*
@@ -107,3 +108,5 @@*/ EXPORT_SYMBOL (scsi_add_timer);EXPORT_SYMBOL (scsi_delete_timer); + +EXPORT_SYMBOL (scsi_decide_disposition);
drivers/scsi/sd.c +18 -0
@@ -680,6 +680,24 @@ .revalidate_disk = sd_revalidate_disk, }; +#if defined(CONFIG_DISKDUMP ) || defined(CONFIG_DISKDUMP_MODULE ) +struct scsi_device *sd_find_scsi_device (struct block_device *bdev) +{ +struct gendisk *disk = bdev->bd_disk; + +/* Check whether dev is scsi or not */ +if (!disk || (disk->fops != &sd_fops)) +return NULL ; + +if (disk->private_data) +return scsi_disk (disk)->device; +else +return NULL ; +} + +EXPORT_SYMBOL (sd_find_scsi_device); +#endif +/** * sd_rw_intr - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command.
include/scsi/scsi_dump.h +31 -0
@@ -0,0 +1,31 @@ +#ifndef _SCSI_DUMP_H +#define _SCSI_DUMP_H + +/* +* linux/include/scsi/scsi_dump.h +* +* Copyright (C) 2004 FUJITSU LIMITED +* Written by Nobuhiro Tachino ([email protected]) +* +*/ +/* +* 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, 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. +* +*/ + +/* sd.c function */ +extern struct scsi_device *sd_find_scsi_device (struct block_device *); + +#endif /* _SCSI_DUMP_H */
include/scsi/scsi_host.h +41 -0
47 lines not on this page · raw message
PATCH 3/4 Update patches
In reply to Takao IndohThis is a patch for aic7xxx driver.
drivers/scsi/aic7xxx/aic7xxx_osm.c +45 -0
@@ -774,6 +774,10 @@static int ahc_linux_bus_reset (Scsi_Cmnd *);static int ahc_linux_dev_reset (Scsi_Cmnd *);static int ahc_linux_abort (Scsi_Cmnd *); +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +static int ahc_linux_sanity_check (struct scsi_device *); +static void ahc_linux_poll (struct scsi_device *); +#endif /* * Calculate a safe value for AHC_NSEG (as expressed through ahc_linux_nseg).
@@ -1313,6 +1317,10 @@ .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, .slave_destroy = ahc_linux_slave_destroy, +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) + .dump_sanity_check = ahc_linux_sanity_check, + .dump_poll = ahc_linux_poll, +#endif };/**************************** Tasklet Handler *********************************/
@@ -3863,6 +3871,42 @@return IRQ_RETVAL (ours); } +static int +ahc_linux_sanity_check (struct scsi_device *device) +{ +struct ahc_softc *ahc; +struct ahc_linux_device *dev; + + ahc = *(struct ahc_softc **)device->host->hostdata; + dev =ahc_linux_get_device (ahc, device->channel, + device->id, device->lun, +/*alloc*/ FALSE); +if (dev ==NULL ) +return -ENXIO ; +if (ahc->platform_data->qfrozen || dev->qfrozen) +return -EBUSY ; +if (spin_is_locked (&ahc->platform_data->spin_lock)) +return -EBUSY ; +return 0 ; +} + +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +static void +ahc_linux_poll (struct scsi_device *device) +{ +struct ahc_softc *ahc; +struct ahc_linux_device *dev; + + ahc = *(struct ahc_softc **)device->host->hostdata; +ahc_intr (ahc); +while ((dev =ahc_linux_next_device_to_run (ahc)) !=NULL ) { +TAILQ_REMOVE (&ahc->platform_data->device_runq, dev, links); + dev->flags &= ~AHC_DEV_ON_RUN_LIST ; +ahc_linux_check_device_queue (ahc, dev); + } +ahc_linux_run_complete_queue (ahc); +} +void ahc_platform_flushwork (struct ahc_softc *ahc) {
@@ -3870,6 +3914,7 @@while (ahc_linux_run_complete_queue (ahc) !=NULL ) ; } +#endif static struct ahc_linux_target *ahc_linux_alloc_target (struct ahc_softc *ahc,u_int channel,u_int target)
drivers/scsi/aic7xxx/aic7xxx_osm.h +19 -0
@@ -67,6 +67,7 @@#include <linux/smp_lock.h> #include <linux/version.h> #include <linux/module.h> +#include <linux/diskdumplib.h> #include <asm/byteorder.h> #include <asm/io.h>
@@ -82,6 +83,8 @@#include <linux/malloc.h> #endif +#include <scsi/scsi_dump.h> +/* Core SCSI definitions */ #define AIC_LIB_PREFIX ahc#include "scsi.h"
@@ -253,6 +256,22 @@*/ #define ahc_dmamap_sync (ahc, dma_tag, dmamap, offset, len, op) + +/******************************** Disk dump ***********************************/ +#if defined(CONFIG_DISKDUMP ) || defined(CONFIG_DISKDUMP_MODULE ) +#undef add_timer +#define add_timer diskdump_add_timer +#undef del_timer_sync +#define del_timer_sync diskdump_del_timer +#undef del_timer +#define del_timer diskdump_del_timer +#undef mod_timer +#define mod_timer diskdump_mod_timer + +#define tasklet_schedule diskdump_tasklet_schedule +#endif + +/************************** Timer DataStructures ******************************/ typedef struct timer_list ahc_timer_t ;
PATCH 4/4 Update patches
In reply to Takao IndohThis is a patch for aic79xx driver.
drivers/scsi/aic7xxx/aic79xx_osm.c +43 -0
@@ -786,6 +786,10 @@static int ahd_linux_bus_reset (Scsi_Cmnd *);static int ahd_linux_dev_reset (Scsi_Cmnd *);static int ahd_linux_abort (Scsi_Cmnd *); +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +static int ahd_linux_sanity_check (struct scsi_device *); +static void ahd_linux_poll (struct scsi_device *); +#endif /* * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg).
@@ -1684,6 +1688,10 @@ .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, .slave_destroy = ahd_linux_slave_destroy, +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) + .dump_sanity_check = ahd_linux_sanity_check, + .dump_poll = ahd_linux_poll, +#endif };/**************************** Tasklet Handler *********************************/
@@ -4190,6 +4198,41 @@return IRQ_RETVAL (ours); } +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +static int +ahd_linux_sanity_check (struct scsi_device *device) +{ +struct ahd_softc *ahd; +struct ahd_linux_device *dev; + + ahd = *(struct ahd_softc **)device->host->hostdata; + dev =ahd_linux_get_device (ahd, device->channel, + device->id, device->lun, +/*alloc*/ FALSE); + +if (dev ==NULL ) +return -ENXIO ; +if (ahd->platform_data->qfrozen || dev->qfrozen) +return -EBUSY ; +if (spin_is_locked (&ahd->platform_data->spin_lock)) +return -EBUSY ; +return 0 ; +} + +static void +ahd_linux_poll (struct scsi_device *device) +{ +struct ahd_softc *ahd; +int ours; + + ahd = *(struct ahd_softc **)device->host->hostdata; + ours =ahd_intr (ahd); +if (ahd_linux_next_device_to_run (ahd) !=NULL ) +ahd_schedule_runq (ahd); +ahd_linux_run_complete_queue (ahd); +} +#endif +void ahd_platform_flushwork (struct ahd_softc *ahd) {
drivers/scsi/aic7xxx/aic79xx_osm.h +21 -0
@@ -50,6 +50,9 @@#include <linux/smp_lock.h> #include <linux/version.h> #include <linux/module.h> +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +#include <linux/diskdumplib.h> +#endif #include <asm/byteorder.h> #include <asm/io.h>
@@ -65,6 +68,10 @@#include <linux/malloc.h> #endif +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +#include <scsi/scsi_dump.h> +#endif +/* Core SCSI definitions */ #define AIC_LIB_PREFIX ahd#include "scsi.h"
@@ -96,6 +103,20 @@/* No debugging code. */ #endif +/********************************** Disk Dump *********************************/ +#if defined(CONFIG_SCSI_DUMP ) || defined(CONFIG_SCSI_DUMP_MODULE ) +#undef add_timer +#define add_timer diskdump_add_timer +#undef del_timer_sync +#define del_timer_sync diskdump_del_timer +#undef del_timer +#define del_timer diskdump_del_timer +#undef mod_timer +#define mod_timer diskdump_mod_timer + +#define tasklet_schedule diskdump_tasklet_schedule +#endif +/********************************** Misc Macros *******************************/ #define roundup (x, y) ((((x)+((y)-1))/(y))*(y))#define powerof2 (x) ((((x)-1)&(x))==0)
Review
Quoted 7 lines · Takao Indoh
static inline void
tasklet_schedule(struct tasklet_struct *t){(quoted diff) +5
-0+ if(crashdump_mode()) { + diskdump_tasklet_schedule(t); + return; + } +
I would suggest
if (unlikely(crashdump_mode()))