dump - Make use of the new dumping
authorAlex Hornung <ahornung@gmail.com>
Sun, 6 Dec 2009 19:52:58 +0000 (19:52 +0000)
committerAlex Hornung <ahornung@gmail.com>
Sun, 6 Dec 2009 20:06:50 +0000 (20:06 +0000)
* Adapt our dumping infrastructure to the new dump type.

* Update all disk/raid dump methods (except aac) to work with the new
  dumps. These now don't take matters into their own hands and just write
  what they are told to.

20 files changed:
sys/bus/cam/scsi/scsi_da.c
sys/dev/disk/nata/ata-disk.c
sys/dev/disk/nata/ata-raid.c
sys/dev/raid/aac/aac_disk.c
sys/dev/raid/amr/amr_disk.c
sys/dev/raid/ida/ida_disk.c
sys/dev/raid/twe/twe_freebsd.c
sys/kern/kern_device.c
sys/kern/kern_shutdown.c
sys/kern/subr_disk.c
sys/platform/pc32/i386/machdep.c
sys/platform/pc32/include/md_var.h
sys/platform/pc32/include/pmap.h
sys/platform/pc64/include/md_var.h
sys/platform/pc64/include/pmap.h
sys/sys/device.h
sys/sys/disk.h
sys/sys/diskslice.h
sys/sys/kerneldump.h [new file with mode: 0644]
sys/sys/systm.h

index ebac23d..2f92554 100644 (file)
@@ -654,46 +654,28 @@ dadump(struct dev_dump_args *ap)
        struct      cam_periph *periph;
        struct      da_softc *softc;
        u_int       unit;
-       long        blkcnt;
-       vm_paddr_t  addr;       
+       u_int32_t   secsize;
        struct      ccb_scsiio csio;
-       int         dumppages = MAXDUMPPGS;
-       int         i;
-
-       /* toss any characters present prior to dump */
-       while (cncheckc() != -1)
-               ;
 
        unit = dkunit(dev);
        periph = cam_extend_get(daperiphs, unit);
-       if (periph == NULL) {
+       if (periph == NULL)
                return (ENXIO);
-       }
+
        softc = (struct da_softc *)periph->softc;
-       
        cam_periph_lock(periph);
+       secsize = softc->params.secsize; /* XXX: or ap->a_secsize? */
+
        if ((softc->flags & DA_FLAG_PACK_INVALID) != 0) {
                cam_periph_unlock(periph);
                return (ENXIO);
        }
 
-       addr = 0;       /* starting address */
-       blkcnt = howmany(PAGE_SIZE, ap->a_secsize);
-
-       while (ap->a_count > 0) {
-               caddr_t va = NULL;
-
-               if ((ap->a_count / blkcnt) < dumppages)
-                       dumppages = ap->a_count / blkcnt;
-
-               for (i = 0; i < dumppages; ++i) {
-                       vm_paddr_t a = addr + (i * PAGE_SIZE);
-                       if (is_physical_memory(a))
-                               va = pmap_kenter_temporary(trunc_page(a), i);
-                       else
-                               va = pmap_kenter_temporary(trunc_page(0), i);
-               }
-
+       /*
+        * because length == 0 means we are supposed to flush cache, we only
+        * try to write something if length > 0.
+        */
+       if (ap->a_length > 0) {
                xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1);
                csio.ccb_h.flags |= CAM_POLLED;
                csio.ccb_h.ccb_state = DA_CCB_DUMP;
@@ -704,10 +686,10 @@ dadump(struct dev_dump_args *ap)
                                /*read*/FALSE,
                                /*byte2*/0,
                                /*minimum_cmd_size*/ softc->minimum_cmd_size,
-                               ap->a_blkno,
-                               blkcnt * dumppages,
-                               /*data_ptr*/(u_int8_t *) va,
-                               /*dxfer_len*/blkcnt * ap->a_secsize * dumppages,
+                               ap->a_offset / secsize,
+                               ap->a_length / secsize,
+                               /*data_ptr*/(u_int8_t *) ap->a_virtual,
+                               /*dxfer_len*/ap->a_length,
                                /*sense_len*/SSD_FULL_SIZE,
                                DA_DEFAULT_TIMEOUT * 1000);             
                xpt_polled_action((union ccb *)&csio);
@@ -722,14 +704,8 @@ dadump(struct dev_dump_args *ap)
                                       csio.ccb_h.status, csio.scsi_status);
                        return(EIO);
                }
-               
-               if (dumpstatus(addr, (off_t)ap->a_count * softc->params.secsize) < 0)
-                       return (EINTR);
-
-               /* update block count */
-               ap->a_count -= blkcnt * dumppages;
-               ap->a_blkno += blkcnt * dumppages;
-               addr += PAGE_SIZE * dumppages;
+               cam_periph_unlock(periph);
+               return 0;
        }
 
        /*
index 362d801..9d2de14 100644 (file)
@@ -373,65 +373,44 @@ ad_done(struct ata_request *request)
 static int
 ad_dump(struct dev_dump_args *ap)
 {
-    device_t dev = ap->a_head.a_dev->si_drv1;
-    struct ata_device *atadev = device_get_softc(dev);
-    struct ata_request request;
-    vm_paddr_t addr = 0;
-    long blkcnt;
-    int dumppages = MAXDUMPPGS;
-    int error = 0;
-    int i;
-
-    blkcnt = howmany(PAGE_SIZE, ap->a_secsize);
-
-    while (ap->a_count > 0) {
-       caddr_t va = NULL;
-
-       if ((ap->a_count /blkcnt) < dumppages)
-           dumppages = ap->a_count / blkcnt;
-
-       for (i = 0; i < dumppages; ++i) {
-           vm_paddr_t a = addr + (i * PAGE_SIZE);
-           if (is_physical_memory(a))
-               va = pmap_kenter_temporary(trunc_page(a), i);
-           else
-               va = pmap_kenter_temporary(trunc_page(0), i);
+       device_t dev = ap->a_head.a_dev->si_drv1;
+       struct ata_device *atadev = device_get_softc(dev);
+       struct ata_request request;
+
+       /*
+        * 0 length means flush buffers and return
+        */
+       if (ap->a_length == 0) {
+               /* flush buffers to media */
+               if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
+                       return ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
+               else
+                       return ENXIO;
        }
 
        bzero(&request, sizeof(struct ata_request));
        request.dev = dev;
-       /* request.bio = NULL; */
-       request.timeout = ATA_DEFAULT_TIMEOUT;
-       request.retries = 2;
-       request.data = va;
-       request.bytecount = dumppages * PAGE_SIZE;
-       request.u.ata.lba = ap->a_blkno;
-       request.u.ata.count = request.bytecount / DEV_BSIZE;
+
+       request.data = ap->a_virtual;
+       request.bytecount = ap->a_length;
        request.transfersize = min(request.bytecount, atadev->max_iosize);
-       request.flags = ATA_R_WRITE | ATA_R_AT_HEAD;
+       request.flags = ATA_R_WRITE;
+
        if (atadev->mode >= ATA_DMA) {
-           request.u.ata.command = ATA_WRITE_DMA;
-           request.flags |= ATA_DMA;
+               request.u.ata.command = ATA_WRITE_DMA;
+               request.flags |= ATA_DMA;
        } else if (request.transfersize > DEV_BSIZE)
-           request.u.ata.command = ATA_WRITE_MUL;
+               request.u.ata.command = ATA_WRITE_MUL;
        else
-           request.u.ata.command = ATA_WRITE;
-       ata_queue_request(&request);
-       if (request.result)
-           return request.result;
-
-       if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0)
-           return EINTR;
+               request.u.ata.command = ATA_WRITE;
+       request.u.ata.lba = ap->a_offset / DEV_BSIZE;
+       request.u.ata.count = request.bytecount / DEV_BSIZE;
 
-       ap->a_blkno += blkcnt * dumppages;
-       ap->a_count -= blkcnt * dumppages;
-       addr += PAGE_SIZE * dumppages;
-    }
+       request.timeout = ATA_DEFAULT_TIMEOUT;
+       request.retries = 2;
 
-    /* flush buffers to media */
-    if (atadev->param.support.command2 & ATA_SUPPORT_FLUSHCACHE)
-       error = ata_controlcmd(dev, ATA_FLUSHCACHE, 0, 0, 0);
-    return error;
+       ata_queue_request(&request);
+       return request.result;
 }
 
 static void
index 1231066..4ae5464 100644 (file)
@@ -868,28 +868,20 @@ ata_raid_done(struct ata_request *request)
 static int
 ata_raid_dump(struct dev_dump_args *ap)
 {
-    struct ar_softc *rdp = ap->a_head.a_dev->si_drv1;
-    struct buf dbuf;
-    vm_paddr_t addr = 0;
-    long blkcnt;
-    int dumppages = MAXDUMPPGS;
-    int error = 0;
-    int i, disk;
-
-    blkcnt = howmany(PAGE_SIZE, ap->a_secsize);
-
-    while (ap->a_count > 0) {
-       caddr_t va = NULL;
-       
-       if ((ap->a_count / blkcnt) < dumppages)
-           dumppages = ap->a_count / blkcnt;
-
-       for (i = 0; i < dumppages; ++i) {
-           vm_paddr_t a = addr + (i * PAGE_SIZE);
-           if (is_physical_memory(a))
-               va = pmap_kenter_temporary(trunc_page(a), i);
-           else
-               va = pmap_kenter_temporary(trunc_page(0), i);
+       struct ar_softc *rdp = ap->a_head.a_dev->si_drv1;
+       struct buf dbuf;
+       int error = 0;
+       int disk;
+
+       if (ap->a_length == 0) {
+               /* flush subdisk buffers to media */
+               for (disk = 0, error = 0; disk < rdp->total_disks; disk++) {
+                       if (rdp->disks[disk].dev) {
+                               error |= ata_controlcmd(rdp->disks[disk].dev,
+                                               ATA_FLUSHCACHE, 0, 0, 0);
+                       }
+               }
+               return (error ? EIO : 0);
        }
 
        bzero(&dbuf, sizeof(struct buf));
@@ -897,12 +889,12 @@ ata_raid_dump(struct dev_dump_args *ap)
        BUF_LOCK(&dbuf, LK_EXCLUSIVE);
        initbufbio(&dbuf);
        /* bio_offset is byte granularity, convert block granularity a_blkno */
-       dbuf.b_bio1.bio_offset = (off_t)(ap->a_blkno << DEV_BSHIFT);
+       dbuf.b_bio1.bio_offset = ap->a_offset;
        dbuf.b_bio1.bio_caller_info1.ptr = (void *)rdp;
        dbuf.b_bio1.bio_flags |= BIO_SYNC;
        dbuf.b_bio1.bio_done = biodone_sync;
-       dbuf.b_bcount = dumppages * PAGE_SIZE;
-       dbuf.b_data = va;
+       dbuf.b_bcount = ap->a_length;
+       dbuf.b_data = ap->a_virtual;
        dbuf.b_cmd = BUF_CMD_WRITE;
        dev_dstrategy(rdp->cdev, &dbuf.b_bio1);
        /* wait for completion, unlock the buffer, check status */
@@ -912,20 +904,7 @@ ata_raid_dump(struct dev_dump_args *ap)
        }
        BUF_UNLOCK(&dbuf);
 
-       if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0)
-           return(EINTR);
-
-       ap->a_blkno += blkcnt * dumppages;
-       ap->a_count -= blkcnt * dumppages;
-       addr += PAGE_SIZE * dumppages;
-    }
-
-    /* flush subdisk buffers to media */
-    for (disk = 0; disk < rdp->total_disks; disk++)
-       if (rdp->disks[disk].dev)
-           error |= ata_controlcmd(rdp->disks[disk].dev, ATA_FLUSHCACHE, 0, 0,
-                                   0);
-    return (error ? EIO : 0);
+       return 0;
 }
 
 static void
index dab948b..85812d0 100644 (file)
@@ -224,6 +224,9 @@ aac_disk_strategy(struct dev_strategy_args *ap)
 static int
 aac_disk_dump(struct dev_dump_args *ap)
 {
+       kprintf("dumps on aac are currently broken, not dumping\n");
+       return (ENXIO);
+#if 0
        cdev_t dev = ap->a_head.a_dev;
        struct aac_disk *ad;
        struct aac_softc *sc;
@@ -290,6 +293,7 @@ retry:
        }
 
        return (0);
+#endif
 }
 
 /*
index ae378e2..96bec12 100644 (file)
@@ -185,12 +185,8 @@ amrd_dump(struct dev_dump_args *ap)
     cdev_t dev = ap->a_head.a_dev;
     struct amrd_softc  *amrd_sc = (struct amrd_softc *)dev->si_drv1;
     struct amr_softc   *amr_sc;
-    vm_paddr_t         addr = 0;
-    long               blkcnt;
-    int                        dumppages = MAXDUMPPGS;
     int                        error = 0;
     int                        driveno;
-    int                        i;
 
     debug_called(1);
 
@@ -199,36 +195,15 @@ amrd_dump(struct dev_dump_args *ap)
     if (!amrd_sc || !amr_sc)
        return(ENXIO);
 
-    blkcnt = howmany(PAGE_SIZE, ap->a_secsize);
-
     driveno = amrd_sc->amrd_drive - amr_sc->amr_drive;
 
-    while (ap->a_count > 0) {
-       caddr_t va = NULL;
-
-       if ((ap->a_count / blkcnt) < dumppages)
-           dumppages = ap->a_count / blkcnt;
-
-       for (i = 0; i < dumppages; ++i) {
-           vm_paddr_t a = addr + (i * PAGE_SIZE);
-           if (is_physical_memory(a))
-               va = pmap_kenter_temporary(trunc_page(a), i);
-           else
-               va = pmap_kenter_temporary(trunc_page(0), i);
-       }
-
-       if ((error = amr_dump_blocks(amr_sc, driveno, ap->a_blkno, (void *)va,
-                                     (PAGE_SIZE * dumppages) / AMR_BLKSIZE)) != 0)
+    if (ap->a_length > 0) {
+       if ((error = amr_dump_blocks(amr_sc,driveno,ap->a_offset / AMR_BLKSIZE,
+           (void *)ap->a_virtual,(int) ap->a_length / AMR_BLKSIZE  )) != 0)
                return(error);
-
-       if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0)
-           return(EINTR);
-
-       ap->a_blkno += blkcnt * dumppages;
-       ap->a_count -= blkcnt * dumppages;
-       addr += PAGE_SIZE * dumppages;
     }
-    return (0);
+    return(0);
+
 }
 /*
  * Read/write routine for a buffer.  Finds the proper unit, range checks
index 940738d..9a01d58 100644 (file)
@@ -197,44 +197,21 @@ idad_dump(struct dev_dump_args *ap)
 {
        cdev_t dev = ap->a_head.a_dev;
        struct idad_softc *drv;
-       long blkcnt;
-       int i, error, dumppages;
-        caddr_t va;
-       vm_offset_t addr, a;
+       int error = 0;
 
        drv = idad_getsoftc(dev);
        if (drv == NULL)
                return (ENXIO);
 
-       addr = 0;
-       blkcnt = howmany(PAGE_SIZE, ap->a_secsize);
+       drv->controller->flags &= ~IDA_INTERRUPTS;
 
-       while (ap->a_count > 0) {
-               va = NULL;
-
-               dumppages = imin(ap->a_count / blkcnt, MAXDUMPPGS); 
-
-               for (i = 0; i < dumppages; i++) {
-                       a = addr + (i * PAGE_SIZE);
-                       if (is_physical_memory(a))
-                               va = pmap_kenter_temporary(trunc_page(a), i);
-                       else
-                               va = pmap_kenter_temporary(trunc_page(0), i);
-               }
-
-               error = ida_command(drv->controller, CMD_WRITE, va,
-                   PAGE_SIZE * dumppages, drv->drive, ap->a_blkno, DMA_DATA_OUT);
-               if (error)
-                       return (error);
-
-               if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0)
-                       return (EINTR);
-
-               ap->a_blkno += blkcnt * dumppages;
-               ap->a_count -= blkcnt * dumppages;
-               addr += PAGE_SIZE * dumppages;
+       if (ap->a_length > 0) {
+               error = ida_command(drv->controller, CMD_WRITE, ap->a_virtual,
+                   ap->a_length, drv->drive, ap->a_offset / DEV_BSIZE, DMA_DATA_OUT);
        }
-       return (0);
+       drv->controller->flags |= IDA_INTERRUPTS;
+       return (error);
+
 }
 
 void
index ff05f42..66adb27 100644 (file)
@@ -722,42 +722,16 @@ twed_dump(struct dev_dump_args *ap)
     cdev_t dev = ap->a_head.a_dev;
     struct twed_softc  *twed_sc = (struct twed_softc *)dev->si_drv1;
     struct twe_softc   *twe_sc  = (struct twe_softc *)twed_sc->twed_controller;
-    vm_paddr_t         addr = 0;
-    long               blkcnt;
-    int                        dumppages = MAXDUMPPGS;
     int                        error;
-    int                        i;
 
     if (!twed_sc || !twe_sc)
        return(ENXIO);
 
-    blkcnt = howmany(PAGE_SIZE, ap->a_secsize);
-
-    while (ap->a_count > 0) {
-       caddr_t va = NULL;
-
-       if ((ap->a_count / blkcnt) < dumppages)
-           dumppages = ap->a_count / blkcnt;
-
-       for (i = 0; i < dumppages; ++i) {
-           vm_paddr_t a = addr + (i * PAGE_SIZE);
-           if (is_physical_memory(a))
-               va = pmap_kenter_temporary(trunc_page(a), i);
-           else
-               va = pmap_kenter_temporary(trunc_page(0), i);
-       }
-
-       if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit, ap->a_blkno, va, 
-                                    (PAGE_SIZE * dumppages) / TWE_BLOCK_SIZE)) != 0)
+    if (ap->a_length > 0) {
+       if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit,
+                                    ap->a_offset / TWE_BLOCK_SIZE,
+                                    ap->a_virtual, ap->a_length / TWE_BLOCK_SIZE)) != 0)
            return(error);
-
-
-       if (dumpstatus(addr, (off_t)ap->a_count * DEV_BSIZE) < 0)
-           return(EINTR);
-
-       ap->a_blkno += blkcnt * dumppages;
-       ap->a_count -= blkcnt * dumppages;
-       addr += PAGE_SIZE * dumppages;
     }
     return(0);
 }
index 4332d1c..f50d864 100644 (file)
@@ -273,7 +273,8 @@ dev_dstrategy_chain(cdev_t dev, struct bio *bio)
  * forwarding the message.
  */
 int
-dev_ddump(cdev_t dev)
+dev_ddump(cdev_t dev, void *virtual, vm_offset_t physical, off_t offset,
+    size_t length)
 {
        struct dev_dump_args ap;
 
@@ -282,6 +283,10 @@ dev_ddump(cdev_t dev)
        ap.a_count = 0;
        ap.a_blkno = 0;
        ap.a_secsize = 0;
+       ap.a_virtual = virtual;
+       ap.a_physical = physical;
+       ap.a_offset = offset;
+       ap.a_length = length;
        return(dev->si_ops->d_dump(&ap));
 }
 
index 7e89212..b4d4f94 100644 (file)
@@ -50,6 +50,7 @@
 #include <sys/systm.h>
 #include <sys/eventhandler.h>
 #include <sys/buf.h>
+#include <sys/disk.h>
 #include <sys/diskslice.h>
 #include <sys/reboot.h>
 #include <sys/proc.h>
@@ -58,6 +59,7 @@
 #include <sys/stat.h>          /* S_IFCHR      */
 #include <sys/vnode.h>
 #include <sys/kernel.h>
+#include <sys/kerneldump.h>
 #include <sys/kthread.h>
 #include <sys/malloc.h>
 #include <sys/mount.h>
@@ -69,6 +71,7 @@
 #include <sys/device.h>
 #include <sys/cons.h>
 #include <sys/shm.h>
+#include <sys/kerneldump.h>
 #include <sys/kern_syscall.h>
 #include <vm/vm_map.h>
 #include <vm/pmap.h>
 #include <sys/thread2.h>
 #include <sys/buf2.h>
 
-#include <machine/pcb.h>
 #include <machine/clock.h>
 #include <machine/md_var.h>
 #include <machine/smp.h>               /* smp_active_mask, cpuid */
 #include <machine/vmparam.h>
+#include <machine/thread.h>
 
 #include <sys/signalvar.h>
 
@@ -141,6 +144,8 @@ watchdog_tickle_fn wdog_tickler = NULL;
 const char *panicstr;
 
 int dumping;                           /* system is dumping */
+static struct dumperinfo dumper;       /* selected dumper */
+
 #ifdef SMP
 u_int panic_cpu_interlock;             /* panic interlock */
 globaldata_t panic_cpu_gd;             /* which cpu took the panic */
@@ -155,7 +160,6 @@ int dumplo;                         /* OBSOLETE - savecore compat */
 u_int64_t dumplo64;
 
 static void boot (int) __dead2;
-static void dumpsys (void);
 static int setdumpdev (cdev_t dev);
 static void poweroff_wait (void *, int);
 static void print_uptime (void);
@@ -216,8 +220,8 @@ shutdown_nice(int howto)
        return;
 }
 static int     waittime = -1;
-static struct thread *dumpthread;
-static struct pcb dumppcb;
+struct pcb dumppcb;
+struct thread *dumpthread;
 
 static void
 print_uptime(void)
@@ -374,8 +378,11 @@ boot(int howto)
         * Dump before doing post_sync shutdown ops
         */
        crit_enter();
-       if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold)
-               dumpsys();
+       if ((howto & (RB_HALT|RB_DUMP)) == RB_DUMP && !cold &&
+           dumper.dumper != NULL && !dumping) {
+               dumping++;
+               dumpsys(&dumper);
+       }
 
        /*
         * Ok, now do things that assume all filesystem activity has
@@ -554,28 +561,45 @@ shutdown_cleanup_proc(struct proc *p)
  * Mark it as used so that gcc doesn't optimize it away.
  */
 __attribute__((__used__))
-       static u_long const dumpmag = 0x8fca0101UL;     
+       static u_long const dumpmag = 0x8fca0101UL;
 
-static int     dumpsize = 0;           /* also for savecore */
+__attribute__((__used__))
+       static int      dumpsize = 0;           /* also for savecore */
 
 static int     dodump = 1;
 
 SYSCTL_INT(_machdep, OID_AUTO, do_dump, CTLFLAG_RW, &dodump, 0,
     "Try to perform coredump on kernel panic");
 
+void
+mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver,
+    uint64_t dumplen, uint32_t blksz)
+{
+       bzero(kdh, sizeof(*kdh));
+       strncpy(kdh->magic, magic, sizeof(kdh->magic));
+       strncpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture));
+       kdh->version = htod32(KERNELDUMPVERSION);
+       kdh->architectureversion = htod32(archver);
+       kdh->dumplength = htod64(dumplen);
+       kdh->dumptime = htod64(time_second);
+       kdh->blocksize = htod32(blksz);
+       strncpy(kdh->hostname, hostname, sizeof(kdh->hostname));
+       strncpy(kdh->versionstring, version, sizeof(kdh->versionstring));
+       if (panicstr != NULL)
+               strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring));
+       kdh->parity = kerneldump_parity(kdh);
+}
+
 static int
 setdumpdev(cdev_t dev)
 {
-       struct partinfo pinfo;
-       u_int64_t newdumplo;
        int error;
        int doopen;
 
        if (dev == NULL) {
-               dumpdev = dev;
+               disk_dumpconf(NULL, 0/*off*/);
                return (0);
        }
-       bzero(&pinfo, sizeof(pinfo));
 
        /*
         * We have to open the device before we can perform ioctls on it,
@@ -589,22 +613,10 @@ setdumpdev(cdev_t dev)
                if (error)
                        return (error);
        }
-       error = dev_dioctl(dev, DIOCGPART, (void *)&pinfo, 0,
-                          proc0.p_ucred, NULL);
-       if (doopen)
-               dev_dclose(dev, FREAD, S_IFCHR);
-       if (error || pinfo.media_blocks == 0 || pinfo.media_blksize == 0)
-               return (ENXIO);
-
-       newdumplo = pinfo.media_blocks - 
-                   ((u_int64_t)Maxmem * PAGE_SIZE / DEV_BSIZE);
-       if ((int64_t)newdumplo < (int64_t)pinfo.reserved_blocks)
-               return (ENOSPC);
-       dumpdev = dev;
-       dumplo64 = newdumplo;
-       return (0);
-}
+       error = disk_dumpconf(dev, 1/*on*/);
 
+       return error;
+}
 
 /* ARGSUSED */
 static void dump_conf (void *dummy);
@@ -643,90 +655,6 @@ sysctl_kern_dumpdev(SYSCTL_HANDLER_ARGS)
 SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
        0, sizeof dumpdev, sysctl_kern_dumpdev, "T,udev_t", "");
 
-/*
- * Doadump comes here after turning off memory management and
- * getting on the dump stack, either when called above, or by
- * the auto-restart code.
- */
-static void
-dumpsys(void)
-{
-       int     error;
-
-       savectx(&dumppcb);
-       dumpthread = curthread;
-       if (dumping++) {
-               kprintf("Dump already in progress, bailing...\n");
-               return;
-       }
-       if (!dodump)
-               return;
-       if (dumpdev == NULL)
-               return;
-       dumpsize = Maxmem;
-       kprintf("\ndumping to dev %s, blockno %lld\n",
-               devtoname(dumpdev),
-               (long long)dumplo64);
-       kprintf("dump ");
-       error = dev_ddump(dumpdev);
-       if (error == 0) {
-               kprintf("succeeded\n");
-               return;
-       }
-       kprintf("failed, reason: ");
-       switch (error) {
-       case ENOSYS:
-       case ENODEV:
-               kprintf("device doesn't support a dump routine\n");
-               break;
-
-       case ENXIO:
-               kprintf("device bad\n");
-               break;
-
-       case EFAULT:
-               kprintf("device not ready\n");
-               break;
-
-       case EINVAL:
-               kprintf("area improper\n");
-               break;
-
-       case EIO:
-               kprintf("i/o error\n");
-               break;
-
-       case EINTR:
-               kprintf("aborted from console\n");
-               break;
-
-       default:
-               kprintf("unknown, error = %d\n", error);
-               break;
-       }
-}
-
-int
-dumpstatus(vm_offset_t addr, off_t count)
-{
-       int c;
-
-       if (addr % (1024 * 1024) == 0) {
-#ifdef HW_WDOG
-               if (wdog_tickler)
-                       (*wdog_tickler)();
-#endif   
-               kprintf("%ld ", (long)(count / (1024 * 1024)));
-       }
-
-       if ((c = cncheckc()) == 0x03)
-               return -1;
-       else if (c != -1)
-               kprintf("[CTRL-C to abort] ");
-       
-       return 0;
-}
-
 /*
  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
  * and then reboots.  If we are called twice, then we avoid trying to sync
@@ -868,3 +796,19 @@ shutdown_kproc(void *arg, int howto)
        else
                kprintf("stopped\n");
 }
+
+/* Registration of dumpers */
+int
+set_dumper(struct dumperinfo *di)
+{
+       if (di == NULL) {
+               bzero(&dumper, sizeof(dumper));
+               return 0;
+       }
+
+       if (dumper.dumper != NULL)
+               return (EBUSY);
+
+       dumper = *di;
+       return 0;
+}
index c4fb4f1..7d36b5e 100644 (file)
@@ -93,6 +93,7 @@
 #include <sys/diskslice.h>
 #include <sys/diskmbr.h>
 #include <sys/disk.h>
+#include <sys/kerneldump.h>
 #include <sys/malloc.h>
 #include <sys/sysctl.h>
 #include <machine/md_var.h>
@@ -621,7 +622,7 @@ disk_destroy(struct disk *disk)
 }
 
 int
-disk_dumpcheck(cdev_t dev, u_int64_t *count, u_int64_t *blkno, u_int *secsize)
+disk_dumpcheck(cdev_t dev, u_int64_t *size, u_int64_t *blkno, u_int32_t *secsize)
 {
        struct partinfo pinfo;
        int error;
@@ -631,18 +632,47 @@ disk_dumpcheck(cdev_t dev, u_int64_t *count, u_int64_t *blkno, u_int *secsize)
                           proc0.p_ucred, NULL);
        if (error)
                return (error);
+
        if (pinfo.media_blksize == 0)
                return (ENXIO);
-       *count = (u_int64_t)Maxmem * PAGE_SIZE / pinfo.media_blksize;
-       if (dumplo64 < pinfo.reserved_blocks ||
-           dumplo64 + *count > pinfo.media_blocks) {
-               return (ENOSPC);
-       }
-       *blkno = dumplo64 + pinfo.media_offset / pinfo.media_blksize;
-       *secsize = pinfo.media_blksize;
+
+       if (blkno) /* XXX: make sure this reserved stuff is right */
+               *blkno = pinfo.reserved_blocks +
+                       pinfo.media_offset / pinfo.media_blksize;
+       if (secsize)
+               *secsize = pinfo.media_blksize;
+       if (size)
+               *size = (pinfo.media_blocks - pinfo.reserved_blocks);
+
        return (0);
 }
 
+int
+disk_dumpconf(cdev_t dev, u_int onoff)
+{
+       struct dumperinfo di;
+       u_int64_t       size, blkno;
+       u_int32_t       secsize;
+       int error;
+
+       if (!onoff)
+               return set_dumper(NULL);
+
+       error = disk_dumpcheck(dev, &size, &blkno, &secsize);
+
+       if (error)
+               return ENXIO;
+
+       bzero(&di, sizeof(struct dumperinfo));
+       di.dumper = diskdump;
+       di.priv = dev;
+       di.blocksize = secsize;
+       di.mediaoffset = blkno * DEV_BSIZE;
+       di.mediasize = size * DEV_BSIZE;
+
+       return set_dumper(&di);
+}
+
 void
 disk_unprobe(struct disk *disk)
 {
@@ -808,6 +838,7 @@ diskioctl(struct dev_ioctl_args *ap)
        cdev_t dev = ap->a_head.a_dev;
        struct disk *dp;
        int error;
+       u_int u;
 
        dp = dev->si_disk;
        if (dp == NULL)
@@ -820,6 +851,11 @@ diskioctl(struct dev_ioctl_args *ap)
                    "diskioctl: &dp->d_slice is: %x, %x\n",
                    &dp->d_slice, dp->d_slice);
 
+       if (ap->a_cmd == DIOCGKERNELDUMP) {
+               u = *(u_int *)ap->a_data;
+               return disk_dumpconf(dev, u);
+       }
+
        error = dsioctl(dev, ap->a_cmd, ap->a_data, ap->a_fflag,
                        &dp->d_slice, &dp->d_info);
 
@@ -915,9 +951,21 @@ diskdump(struct dev_dump_args *ap)
 {
        cdev_t dev = ap->a_head.a_dev;
        struct disk *dp = dev->si_disk;
+       u_int64_t size, offset;
        int error;
 
-       error = disk_dumpcheck(dev, &ap->a_count, &ap->a_blkno, &ap->a_secsize);
+       error = disk_dumpcheck(dev, &size, &ap->a_blkno, &ap->a_secsize);
+       /* XXX: this should probably go in disk_dumpcheck somehow */
+       if (ap->a_length != 0) {
+               size *= DEV_BSIZE;
+               offset = ap->a_blkno * DEV_BSIZE;
+               if ((ap->a_offset < offset) ||
+                   (ap->a_offset + ap->a_length - offset > size)) {
+                       kprintf("Attempt to write outside dump device boundaries.\n");
+                       error = ENOSPC;
+               }
+       }
+
        if (error == 0) {
                ap->a_head.a_dev = dp->d_rawdev;
                error = dev_doperate(&ap->a_head);
index 324b761..5272025 100644 (file)
@@ -195,6 +195,8 @@ SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_INT|CTLFLAG_RD,
 vm_paddr_t Maxmem = 0;
 
 vm_paddr_t phys_avail[PHYSMAP_ENTRIES*2+2];
+vm_paddr_t dump_avail[PHYSMAP_ENTRIES*2+2];
+
 
 static vm_offset_t buffer_sva, buffer_eva;
 vm_offset_t clean_sva, clean_eva;
@@ -1382,7 +1384,7 @@ sdtossd(struct segment_descriptor *sd, struct soft_segment_descriptor *ssd)
 static void
 getmemsize(int first)
 {
-       int i, physmap_idx, pa_indx;
+       int i, physmap_idx, pa_indx, da_indx;
        int hasbrokenint12;
        u_int basemem, extmem;
        struct vm86frame vmf;
@@ -1653,8 +1655,11 @@ physmap_done:
         */
        physmap[0] = PAGE_SIZE;         /* mask off page 0 */
        pa_indx = 0;
+       da_indx = 1;
        phys_avail[pa_indx++] = physmap[0];
        phys_avail[pa_indx] = physmap[0];
+       dump_avail[da_indx] = physmap[0];
+
        pte = CMAP1;
 
        /*
@@ -1675,18 +1680,19 @@ physmap_done:
                if (physmap[i + 1] < end)
                        end = trunc_page(physmap[i + 1]);
                for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) {
-                       int tmp, page_bad;
+                       int tmp, page_bad, full;
 #if 0
                        int *ptr = 0;
 #else
                        int *ptr = (int *)CADDR1;
 #endif
+                       full = FALSE;
 
                        /*
                         * block out kernel memory as not available.
                         */
                        if (pa >= 0x100000 && pa < first)
-                               continue;
+                               goto do_dump_avail;
        
                        /*
                         * block out dcons buffer
@@ -1694,7 +1700,7 @@ physmap_done:
                        if (dcons_addr > 0
                            && pa >= trunc_page(dcons_addr)
                            && pa < dcons_addr + dcons_size)
-                               continue;
+                               goto do_dump_avail;
 
                        page_bad = FALSE;
 
@@ -1762,12 +1768,29 @@ physmap_done:
                                if (pa_indx >= PHYSMAP_ENTRIES*2) {
                                        kprintf("Too many holes in the physical address space, giving up\n");
                                        pa_indx--;
-                                       break;
+                                       full = TRUE;
+                                       goto do_dump_avail;
                                }
                                phys_avail[pa_indx++] = pa;     /* start */
                                phys_avail[pa_indx] = pa + PAGE_SIZE;   /* end */
                        }
                        physmem++;
+do_dump_avail:
+                       if (dump_avail[da_indx] == pa) {
+                               dump_avail[da_indx] += PAGE_SIZE;
+                       } else {
+                               da_indx++;
+                               if (da_indx >= PHYSMAP_ENTRIES*2) {
+                                       da_indx--;
+                                       goto do_next;
+                               }
+                               dump_avail[da_indx++] = pa;     /* start */
+                               dump_avail[da_indx] = pa + PAGE_SIZE; /* end */
+                       }
+do_next:
+                       if (full)
+                               break;
+
                }
        }
        *pte = 0;
index 6b56fe0..07b936f 100644 (file)
@@ -63,6 +63,8 @@ extern        u_int   cyrix_did;
 extern char    kstack[];
 extern char    sigcode[];
 extern int     szsigcode;
+extern  uint32_t *vm_page_dump;
+extern  int     vm_page_dump_size;
 
 typedef void alias_for_inthand_t (u_int cs, u_int ef, u_int esp, u_int ss);
 struct lwp;
@@ -72,6 +74,7 @@ struct  dbreg;
 struct  mdglobaldata;
 struct  thread;
 struct __mcontext;
+struct  dumperinfo;
 
 void   busdma_swi (void);
 void   cpu_gdinit (struct mdglobaldata *gd, int cpu);
@@ -94,6 +97,8 @@ void  doreti_popl_fs (void) __asm(__STRING(doreti_popl_fs));
 void   doreti_popl_fs_fault (void) __asm(__STRING(doreti_popl_fs_fault));
 void   doreti_popl_gs (void) __asm(__STRING(doreti_popl_gs));
 void   doreti_popl_gs_fault (void) __asm(__STRING(doreti_popl_gs_fault));
+void    dump_add_page(vm_paddr_t);
+void    dump_drop_page(vm_paddr_t);
 void   enable_sse (void);
 void   fillw (int /*u_short*/ pat, void *base, size_t cnt);
 #if 0
@@ -118,5 +123,5 @@ int     user_dbreg_trap (void);
 int     npxdna(void);
 void   npxpush(struct __mcontext *mctx);
 void   npxpop(struct __mcontext *mctx);
-
+void    minidumpsys(struct dumperinfo *);
 #endif /* !_MACHINE_MD_VAR_H_ */
index 9d7dda8..f512940 100644 (file)
@@ -234,6 +234,7 @@ extern struct ppro_vmtrr PPro_vmtrr[NPPROVMTRR];
 
 extern caddr_t CADDR1;
 extern pt_entry_t *CMAP1;
+extern vm_paddr_t dump_avail[];
 extern vm_paddr_t avail_end;
 extern vm_paddr_t avail_start;
 extern vm_offset_t clean_eva;
index f7f24b0..3edc80b 100644 (file)
@@ -60,6 +60,9 @@ extern        u_int   cpu_vendor_id;
 extern char    kstack[];
 extern char    sigcode[];
 extern int     szsigcode;
+extern uint64_t *vm_page_dump;
+extern int     vm_page_dump_size;
+
 
 typedef void alias_for_inthand_t(u_int cs, u_int ef, u_int esp, u_int ss);
 struct thread;
@@ -67,6 +70,7 @@ struct        reg;
 struct fpreg;
 struct  dbreg;
 struct __mcontext;
+struct dumperinfo;
 
 void   busdma_swi(void);
 void   cpu_gdinit (struct mdglobaldata *gd, int cpu);
@@ -91,5 +95,8 @@ void  cpu_kthread_restore (void);/* cannot be called from C */
 void   cpu_exit_switch (struct thread *next);
 
 void   syscall2 (struct trapframe *);
+void    minidumpsys(struct dumperinfo *);
+void   dump_add_page(vm_paddr_t);
+void   dump_drop_page(vm_paddr_t);
 
 #endif /* !_MACHINE_MD_VAR_H_ */
index 4e615e3..87da724 100644 (file)
@@ -243,6 +243,7 @@ extern struct ppro_vmtrr PPro_vmtrr[NPPROVMTRR];
 
 extern caddr_t CADDR1;
 extern pt_entry_t *CMAP1;
+extern vm_paddr_t dump_avail[];
 extern vm_paddr_t avail_end;
 extern vm_paddr_t avail_start;
 extern vm_offset_t clean_eva;
index 3262285..537005b 100644 (file)
@@ -138,13 +138,18 @@ struct dev_strategy_args {
 };
 
 /*
- * void d_dump(cdev_t dev)
+ * void d_dump(cdev_t dev, void *virtual, vm_offset_t physical,
+               off_t offset, size_t length)
  */
 struct dev_dump_args {
        struct dev_generic_args a_head;
        u_int64_t       a_count;
        u_int64_t       a_blkno;
        u_int           a_secsize;
+       void            *a_virtual;
+       vm_offset_t     a_physical;
+       off_t           a_offset;
+       size_t          a_length;
 };
 
 /*
@@ -307,7 +312,8 @@ void dev_dstrategy(cdev_t dev, struct bio *bio);
 void dev_dstrategy_chain(cdev_t dev, struct bio *bio);
 int dev_dioctl(cdev_t dev, u_long cmd, caddr_t data, int fflag,
                struct ucred *cred, struct sysmsg *msg);
-int dev_ddump(cdev_t dev);
+int dev_ddump(cdev_t dev, void *virtual, vm_offset_t physical, off_t offset,
+    size_t length);
 int64_t dev_dpsize(cdev_t dev);
 int dev_dread(cdev_t dev, struct uio *uio, int ioflag);
 int dev_dwrite(cdev_t dev, struct uio *uio, int ioflag);
index 6e010f5..6211a1f 100644 (file)
@@ -143,6 +143,7 @@ void disk_destroy (struct disk *disk);
 void disk_setdiskinfo (struct disk *disk, struct disk_info *info);
 void disk_setdiskinfo_sync(struct disk *disk, struct disk_info *info);
 int disk_dumpcheck (cdev_t dev, u_int64_t *count, u_int64_t *blkno, u_int *secsize);
+int disk_dumpconf(cdev_t dev, u_int onoff);
 struct disk *disk_enumerate (struct disk *disk);
 void disk_invalidate (struct disk *disk);
 void disk_unprobe(struct disk *disk);
index a3e2a7c..8d316d4 100644 (file)
@@ -94,6 +94,7 @@
 #define DIOCWLABEL             _IOW('d', 109, int)
 #define        DIOCGSLICEINFO          _IOR('d', 111, struct diskslices)
 #define        DIOCSYNCSLICEINFO       _IOW('d', 112, int)
+#define DIOCGKERNELDUMP                _IOW('d', 133, u_int)   /* Set/Clear kernel dumps */
 #define        MAX_SLICES              16
 
 /*
diff --git a/sys/sys/kerneldump.h b/sys/sys/kerneldump.h
new file mode 100644 (file)
index 0000000..da9c588
--- /dev/null
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2002 Poul-Henning Kamp
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Poul-Henning Kamp
+ * and NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_KERNELDUMP_H
+#define _SYS_KERNELDUMP_H
+
+#include <machine/endian.h>
+#include <machine/pcb.h>
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define        dtoh32(x)       __bswap32(x)
+#define        dtoh64(x)       __bswap64(x)
+#define        htod32(x)       __bswap32(x)
+#define        htod64(x)       __bswap64(x)
+#elif BYTE_ORDER == BIG_ENDIAN
+#define        dtoh32(x)       (x)
+#define        dtoh64(x)       (x)
+#define        htod32(x)       (x)
+#define        htod64(x)       (x)
+#endif
+struct thread;
+
+extern struct thread *dumpthread;
+extern struct pcb dumppcb;
+
+/*
+ * All uintX_t fields are in dump byte order, which is the same as
+ * network byte order. Use the macros defined above to read or
+ * write the fields.
+ */
+struct kerneldumpheader {
+       char            magic[20];
+#define        KERNELDUMPMAGIC         "DragonFly Kern Dump"
+#define        TEXTDUMPMAGIC           "DragonFly Text Dump"
+#define        KERNELDUMPMAGIC_CLEARED "Cleared Kernel Dump"
+       char            architecture[12];
+       uint32_t        version;
+#define        KERNELDUMPVERSION       1
+       uint32_t        architectureversion;
+#define        KERNELDUMP_AMD64_VERSION        2
+#define        KERNELDUMP_I386_VERSION         2
+#define        KERNELDUMP_TEXT_VERSION         1
+       uint64_t        dumplength;             /* excl headers */
+       uint64_t        dumptime;
+       uint32_t        blocksize;
+       char            hostname[64];
+       char            versionstring[192];
+       char            panicstring[192];
+       uint32_t        parity;
+};
+
+/*
+ * Parity calculation is endian insensitive.
+ */
+static __inline u_int32_t
+kerneldump_parity(struct kerneldumpheader *kdhp)
+{
+       uint32_t *up, parity;
+       u_int i;
+
+       up = (uint32_t *)kdhp;
+       parity = 0;
+       for (i = 0; i < sizeof *kdhp; i += sizeof *up)
+               parity ^= *up++;
+       return (parity);
+}
+
+#ifdef _KERNEL
+void mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver,
+    uint64_t dumplen, uint32_t blksz);
+
+
+typedef int dumper_t(
+       void *_priv,            /* Private to the driver. */
+       void *_virtual,         /* Virtual (mapped) address. */
+       vm_offset_t _physical,  /* Physical address of virtual. */
+       off_t _offset,          /* Byte-offset to write at. */
+       size_t _length);        /* Number of bytes to dump. */
+
+
+struct dumperinfo {
+       void    *dumper;        /* Dumping function. */
+       void    *priv;          /* Private parts. */
+       u_int   blocksize;      /* Size of block in bytes. */
+       u_int   maxiosize;      /* Max size allowed for an individual I/O */
+       off_t   mediaoffset;    /* Initial offset in bytes. */
+       off_t   mediasize;      /* Space available in bytes. */
+};
+
+int set_dumper(struct dumperinfo *);
+int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t);
+void dumpsys(struct dumperinfo *);
+
+#endif
+
+
+#endif /* _SYS_KERNELDUMP_H */
index f42dc93..e4e1806 100644 (file)
@@ -75,7 +75,6 @@ extern u_char curpriority;    /* priority of current process */
 extern int physmem;            /* physical memory */
 
 extern cdev_t dumpdev;         /* dump device */
-extern int dumplo;             /* OBSOLETE */
 extern u_int64_t dumplo64;     /* block number into dumpdev, start of dump */
 
 extern cdev_t rootdev;         /* root device */
@@ -145,7 +144,6 @@ void        Debugger (const char *msg);
 void   print_backtrace(void);
 void   mi_gdinit (struct globaldata *gd, int cpu);
 void   mi_proc0init(struct globaldata *gd, struct user *proc0paddr);
-int    dumpstatus (vm_offset_t addr, off_t count);
 int    nullop (void);
 int    seltrue (cdev_t dev, int which);
 int    ureadc (int, struct uio *);