Update patches
Subsystems (7)
cover Update patches
Hi all,
I improved the patches which I posted on 7th Jul.
- Improve sysfs interface code
- Bug fix related to eh_timeout of scsi_cmd
Source code can be downloaded from
http://sourceforge.net/projects/lkdump
Quoted 16 lines · Arjan van de Ven
Quoted 15 lines · Takao Indoh
Hi,
Now I am fixing diskdump according to comments by you and Christoph.
Quoted 6 lines · Arjan van de Ven
Quoted 3 lines
(quoted diff) +2
-0+#ifdef CONFIG_PROC_FS +static int proc_ioctl(struct inode *inode, struct file *file, unsignedint cmd, unsigned long param)
ehhh this looks evil
Do you mean I should use not ioctl but the following style?
Quoted 7 lines
Quoted 2 lines
echo "add
/dev/hda1" >/proc/diskdump
echo "delete/dev/hda1" >/proc/diskdumpwell no since
/dev/hdais pointless; major/minor pairs maybe. But why in /proc???? it sounds like a sysfs job to me, where you probably want to represent a dump relationship with a symlink, and use "rm" to remove an entry..
As I wrote in the previous mail, I replaced proc interface with sysfs.
If you want to add a new dump device /dev/sda3,
# echo 3 > /sys/block/sda/device/dump
If you want to remove the dump device /dev/sda3,
# echo -3 > /sys/block/sda/device/dump
I added a new attribute "dump" to the /sys/block/sdX/device.
drivers/scsi/scsi_sysfs.c +3 -0
@@ -11,6 +11,7 @@#include <linux/init.h> #include <linux/blkdev.h> #include <linux/device.h> +#include <linux/diskdump.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h>
@@ -375,6 +376,7 @@DEVICE_ATTR (state,S_IRUGO |S_IWUSR , show_state_field, store_state_field); +DEVICE_ATTR (dump,S_IRUGO |S_IWUSR , diskdump_sysfs_show, diskdump_sysfs_store);/* Default template for device attributes. May NOT be modified */ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -389,6 +391,7 @@ &dev_attr_delete, &dev_attr_state, &dev_attr_timeout, + &dev_attr_dump, NULL };
diskdump_sysfs_show/store is the sysfs handler of diskdump. These functions passes struct device to the diskdump module. Diskdump changes "struct device" to "struct scsi_device" like this:
+static void *scsi_dump_probe(struct device *dev)
+{
+ struct scsi_device *sdev;
+
+ if ((dev->bus == NULL) || (dev->bus->name == NULL) ||
+ strncmp(dev->bus->name, "scsi", 4))
+ return NULL;
+
+ sdev = to_scsi_device(dev);
+ if (!sdev->host->hostt->dump_poll)
+ return NULL;
+
+ return sdev;
+}
I used device->bus->name to confirm device is scsi device or not.
Please 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
@@ -524,3 +524,4 @@EXPORT_SYMBOL (release_lapic_nmi);EXPORT_SYMBOL (disable_timer_nmi_watchdog);EXPORT_SYMBOL (enable_timer_nmi_watchdog); +EXPORT_SYMBOL_GPL (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/smp.c +1 -1
@@ -520,7 +520,7 @@return 0 ;/* Can deadlock when called with interrupts disabled */ -WARN_ON (irqs_disabled ()); +WARN_ON (irqs_disabled () && !crashdump_mode ()); data.func = func; data.info = info;
arch/i386/kernel/traps.c +10 -1
@@ -294,6 +294,7 @@ }spinlock_t die_lock =SPIN_LOCK_UNLOCKED ; +static int die_owner =-1 ;void die (const char * str,struct pt_regs * regs,long err) {
@@ -301,7 +302,13 @@int nl =0 ;console_verbose (); -spin_lock_irq (&die_lock); +local_irq_disable (); +if (!spin_trylock (&die_lock)) { +if (smp_processor_id () != die_owner) +spin_lock (&die_lock); +/* allow recursive die to fall through */ + } + die_owner =smp_processor_id ();bust_spinlocks (1 );handle_BUG (regs);printk (KERN_ALERT "%s: %04lx [#%d]\n" , str, err &0xffff , ++die_counter);
@@ -320,7 +327,9 @@if (nl)printk ("\n" );show_registers (regs); +try_crashdump (regs);bust_spinlocks (0 ); + die_owner =-1 ;spin_unlock_irq (&die_lock);if (in_interrupt ())panic ("Fatal exception 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
@@ -347,6 +347,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
drivers/block/diskdump.c +895 -0
895 lines not on this page · raw message
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
@@ -23,7 +23,8 @@ D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_DISKDUMP, +D(14) KM_TYPE_NR };#undef D
include/linux/diskdump.h +172 -0
172 lines not on this page · raw message
include/linux/interrupt.h +4 -0
@@ -246,4 +246,8 @@extern int probe_irq_off (unsigned long );/* returns 0 or negative on failure */ extern unsigned int probe_irq_mask (unsigned long );/* returns mask of ISA interrupts */ + +extern void dump_clear_tasklet (void ); +extern void dump_run_tasklet (void ); +#endif
include/linux/kernel.h +11 -0
@@ -111,6 +111,11 @@extern int panic_on_oops;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 () unlikely(diskdump_mode)/* Values used for system_state */ extern enum system_states {
@@ -139,6 +144,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. */
include/linux/timer.h +3 -0
@@ -99,4 +99,7 @@extern void run_local_timers (void );extern void it_real_fn (unsigned long ); +extern void dump_clear_timers (void ); +extern void dump_run_timers (void ); +#endif
include/linux/workqueue.h +3 -0
@@ -84,4 +84,7 @@ return ret; } +extern void dump_clear_workqueue (void ); +extern void dump_run_workqueue (void ); +#endif
kernel/Makefile +1 -1
@@ -7,7 +7,7 @@ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o intermodule.o extable.o params.o posix-timers.o \ - kthread.o + kthread.o dump.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
kernel/dump.c +246 -0
246 lines not on this page · raw message
kernel/panic.c +2 -0
@@ -60,6 +60,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)
kernel/softirq.c +32 -0
@@ -314,6 +314,38 @@EXPORT_SYMBOL (tasklet_kill); +struct tasklet_head saved_tasklet; + +void dump_clear_tasklet (void ) +{ + saved_tasklet.list =__get_cpu_var (tasklet_vec).list; +__get_cpu_var (tasklet_vec).list =NULL ; +} + +EXPORT_SYMBOL (dump_clear_tasklet); + +void dump_run_tasklet (void ) +{ +struct tasklet_struct *list; + + list =__get_cpu_var (tasklet_vec).list; +__get_cpu_var (tasklet_vec).list =NULL ; + +while (list) { +struct tasklet_struct *t = list; + list = list->next; + +if (!atomic_read (&t->count) && + (test_and_clear_bit (TASKLET_STATE_SCHED , &t->state))) + t->func (t->data); + + t->next =__get_cpu_var (tasklet_vec).list; +__get_cpu_var (tasklet_vec).list = t; + } +} + +EXPORT_SYMBOL (dump_run_tasklet); +void __init softirq_init (void ) {open_softirq (TASKLET_SOFTIRQ , tasklet_action,NULL );
kernel/timer.c +33 -4
@@ -31,6 +31,7 @@#include <linux/time.h> #include <linux/jiffies.h> #include <linux/cpu.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -423,8 +424,9 @@static inline void __run_timers (tvec_base_t *base) {struct timer_list *timer; +unsigned long flags; -spin_lock_irq (&base->lock); +spin_lock_irqsave (&base->lock, flags);while (time_after_eq (jiffies, base->timer_jiffies)) {struct list_head work_list =LIST_HEAD_INIT (work_list);struct list_head *head = &work_list;
@@ -453,14 +455,14 @@set_running_timer (base, timer);smp_wmb (); timer->base =NULL ; -spin_unlock_irq (&base->lock); +spin_unlock_irqrestore (&base->lock, flags);fn (data);spin_lock_irq (&base->lock); goto repeat; } }set_running_timer (base,NULL ); -spin_unlock_irq (&base->lock); +spin_unlock_irqrestore (&base->lock, flags); }#ifdef CONFIG_NO_IDLE_HZ
@@ -1105,6 +1107,12 @@struct timer_list timer;unsigned long expire; +if (crashdump_mode ()) { +mdelay (timeout); +set_current_state (TASK_RUNNING ); +return timeout; + } +switch (timeout) {case MAX_SCHEDULE_TIMEOUT :
@@ -1308,7 +1316,7 @@return 0 ; } -static void __devinit init_timers_cpu (int cpu) +static void /* __devinit */ init_timers_cpu (int cpu) {int j;tvec_base_t *base;
@@ -1327,6 +1335,27 @@ base->timer_jiffies = jiffies; } +static tvec_base_t saved_tvec_base; + +void dump_clear_timers (void ) +{ +tvec_base_t *base = &per_cpu (tvec_bases,smp_processor_id ()); + +memcpy (&saved_tvec_base, base,sizeof (saved_tvec_base)); +init_timers_cpu (smp_processor_id ()); +} + +EXPORT_SYMBOL (dump_clear_timers); + +void dump_run_timers (void ) +{ +tvec_base_t *base = &__get_cpu_var (tvec_bases); + +__run_timers (base); +} + +EXPORT_SYMBOL (dump_run_timers); +#ifdef CONFIG_HOTPLUG_CPU static int migrate_timer_list (tvec_base_t *new_base,struct list_head *head) {
kernel/workqueue.c +34 -0
@@ -424,6 +424,37 @@ } +struct cpu_workqueue_struct saved_cwq; + +void dump_clear_workqueue (void ) +{ +int cpu =smp_processor_id (); +struct cpu_workqueue_struct *cwq = keventd_wq->cpu_wq + cpu; + +memcpy (&saved_cwq, cwq,sizeof (saved_cwq)); +spin_lock_init (&cwq->lock); +INIT_LIST_HEAD (&cwq->worklist); +init_waitqueue_head (&cwq->more_work); +init_waitqueue_head (&cwq->work_done); +} + +void dump_run_workqueue (void ) +{ +struct cpu_workqueue_struct *cwq; + + cwq = keventd_wq->cpu_wq +smp_processor_id (); +while (!list_empty (&cwq->worklist)) { +struct work_struct *work =list_entry (cwq->worklist.next, + struct work_struct, entry); +void (*f) (void *) = work->func; +void *data = work->data; + +list_del_init (cwq->worklist.next); +clear_bit (0 , &work->pending); +f (data); + } +} +#ifdef CONFIG_HOTPLUG_CPU /* Take the work from this (downed) CPU. */ static void take_over_work (struct workqueue_struct *wq,unsigned int cpu)
@@ -507,3 +538,6 @@EXPORT_SYMBOL (schedule_delayed_work);EXPORT_SYMBOL (flush_scheduled_work); +EXPORT_SYMBOL (dump_clear_workqueue); +EXPORT_SYMBOL (dump_run_workqueue); +
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
@@ -136,6 +136,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 +598 -0
598 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/scsi_sysfs.c +3 -0
@@ -11,6 +11,7 @@#include <linux/init.h> #include <linux/blkdev.h> #include <linux/device.h> +#include <linux/diskdump.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h>
@@ -375,6 +376,7 @@DEVICE_ATTR (state,S_IRUGO |S_IWUSR , show_state_field, store_state_field); +DEVICE_ATTR (dump,S_IRUGO |S_IWUSR , diskdump_sysfs_show, diskdump_sysfs_store);/* Default template for device attributes. May NOT be modified */ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -389,6 +391,7 @@ &dev_attr_delete, &dev_attr_state, &dev_attr_timeout, + &dev_attr_dump, NULL };
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 +39 -0
@@ -774,6 +774,8 @@static int ahc_linux_bus_reset (Scsi_Cmnd *);static int ahc_linux_dev_reset (Scsi_Cmnd *);static int ahc_linux_abort (Scsi_Cmnd *); +static int ahc_linux_sanity_check (struct scsi_device *); +static void ahc_linux_poll (struct scsi_device *);/* * Calculate a safe value for AHC_NSEG (as expressed through ahc_linux_nseg).
@@ -1315,6 +1317,8 @@ .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, .slave_destroy = ahc_linux_slave_destroy, + .dump_sanity_check = ahc_linux_sanity_check, + .dump_poll = ahc_linux_poll, };/**************************** Tasklet Handler *********************************/
@@ -3868,6 +3872,41 @@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 ; +} + +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) {
PATCH 4/4 Update patches
In reply to Takao IndohThis is a patch for aic79xx driver.
drivers/scsi/aic7xxx/aic79xx_osm.c +37 -0
@@ -786,6 +786,8 @@static int ahd_linux_bus_reset (Scsi_Cmnd *);static int ahd_linux_dev_reset (Scsi_Cmnd *);static int ahd_linux_abort (Scsi_Cmnd *); +static int ahd_linux_sanity_check (struct scsi_device *); +static void ahd_linux_poll (struct scsi_device *);/* * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg).
@@ -1684,6 +1686,8 @@ .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, .slave_destroy = ahd_linux_slave_destroy, + .dump_sanity_check = ahd_linux_sanity_check, + .dump_poll = ahd_linux_poll, };/**************************** Tasklet Handler *********************************/
@@ -4191,6 +4195,39 @@return IRQ_RETVAL (ours); } +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); +} +void ahd_platform_flushwork (struct ahd_softc *ahd) {