aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_shutdown.c
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2017-10-18 15:38:05 +0000
committerMark Johnston <markj@FreeBSD.org>2017-10-18 15:38:05 +0000
commit46fcd1af63db2837bd91d56481030f5b8a3eb13e (patch)
treec1a50a8895135a9d1963c5e96557eaf947c05070 /sys/kern/kern_shutdown.c
parente5accd3ca17c0d0061f2ad9a5b68c48efe255efe (diff)
downloadsrc-46fcd1af63db2837bd91d56481030f5b8a3eb13e.tar.gz
src-46fcd1af63db2837bd91d56481030f5b8a3eb13e.zip
Move kernel dump offset tracking into MI code.
All of the kernel dump implementations keep track of the current offset ("dumplo") within the dump device. However, except for textdumps, they all write the dump sequentially, so we can reduce code duplication by having the MI code keep track of the current offset. The new dump_append() API can be used to write at the current offset. This is needed to implement support for kernel dump compression in the MI kernel dump code. Also simplify dump_encrypted_write() somewhat: use dump_write() instead of duplicating its bounds checks, and get rid of the redundant offset tracking. Reviewed by: cem Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D11722
Notes
Notes: svn path=/head/; revision=324722
Diffstat (limited to 'sys/kern/kern_shutdown.c')
-rw-r--r--sys/kern/kern_shutdown.c126
1 files changed, 55 insertions, 71 deletions
diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c
index 168da47170af..36c275809add 100644
--- a/sys/kern/kern_shutdown.c
+++ b/sys/kern/kern_shutdown.c
@@ -157,7 +157,6 @@ struct kerneldumpcrypto {
uint8_t kdc_iv[KERNELDUMP_IV_MAX_SIZE];
keyInstance kdc_ki;
cipherInstance kdc_ci;
- off_t kdc_nextoffset;
uint32_t kdc_dumpkeysize;
struct kerneldumpkey kdc_dumpkey[];
};
@@ -931,8 +930,6 @@ kerneldumpcrypto_init(struct kerneldumpcrypto *kdc)
goto out;
}
- kdc->kdc_nextoffset = 0;
-
kdk = kdc->kdc_dumpkey;
memcpy(kdk->kdk_iv, kdc->kdc_iv, sizeof(kdk->kdk_iv));
out:
@@ -1024,24 +1021,20 @@ dump_check_bounds(struct dumperinfo *di, off_t offset, size_t length)
(uintmax_t)length, (intmax_t)di->mediasize);
return (ENOSPC);
}
+ if (length % di->blocksize != 0) {
+ printf("Attempt to write partial block of length %ju.\n",
+ (uintmax_t)length);
+ return (EINVAL);
+ }
+ if (offset % di->blocksize != 0) {
+ printf("Attempt to write at unaligned offset %jd.\n",
+ (intmax_t)offset);
+ return (EINVAL);
+ }
return (0);
}
-/* Call dumper with bounds checking. */
-static int
-dump_raw_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
- off_t offset, size_t length)
-{
- int error;
-
- error = dump_check_bounds(di, offset, length);
- if (error != 0)
- return (error);
-
- return (di->dumper(di->priv, virtual, physical, offset, length));
-}
-
#ifdef EKCD
static int
dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *buf, size_t size)
@@ -1067,40 +1060,16 @@ dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *buf, size_t size)
/* Encrypt data and call dumper. */
static int
-dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
- off_t offset, size_t length)
+dump_encrypted_write(struct dumperinfo *di, void *virtual,
+ vm_offset_t physical, off_t offset, size_t length)
{
static uint8_t buf[KERNELDUMP_BUFFER_SIZE];
struct kerneldumpcrypto *kdc;
int error;
size_t nbytes;
- off_t nextoffset;
kdc = di->kdc;
- error = dump_check_bounds(di, offset, length);
- if (error != 0)
- return (error);
-
- /* Signal completion. */
- if (virtual == NULL && physical == 0 && offset == 0 && length == 0) {
- return (di->dumper(di->priv, virtual, physical, offset,
- length));
- }
-
- /* Data have to be aligned to block size. */
- if ((length % di->blocksize) != 0)
- return (EINVAL);
-
- /*
- * Data have to be written continuously becase we're encrypting using
- * CBC mode which has this assumption.
- */
- if (kdc->kdc_nextoffset != 0 && kdc->kdc_nextoffset != offset)
- return (EINVAL);
-
- nextoffset = offset + (off_t)length;
-
while (length > 0) {
nbytes = MIN(length, sizeof(buf));
bcopy(virtual, buf, nbytes);
@@ -1108,7 +1077,7 @@ dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
if (dump_encrypt(kdc, buf, nbytes) != 0)
return (EIO);
- error = di->dumper(di->priv, buf, physical, offset, nbytes);
+ error = dump_write(di, buf, physical, offset, nbytes);
if (error != 0)
return (error);
@@ -1117,8 +1086,6 @@ dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
length -= nbytes;
}
- kdc->kdc_nextoffset = nextoffset;
-
return (0);
}
@@ -1131,26 +1098,11 @@ dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset)
if (kdc == NULL)
return (0);
- return (dump_raw_write(di, kdc->kdc_dumpkey, physical, offset,
+ return (dump_write(di, kdc->kdc_dumpkey, physical, offset,
kdc->kdc_dumpkeysize));
}
#endif /* EKCD */
-int
-dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
- off_t offset, size_t length)
-{
-
-#ifdef EKCD
- if (di->kdc != NULL) {
- return (dump_encrypted_write(di, virtual, physical, offset,
- length));
- }
-#endif
-
- return (dump_raw_write(di, virtual, physical, offset, length));
-}
-
static int
dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
vm_offset_t physical, off_t offset)
@@ -1170,7 +1122,7 @@ dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
memcpy(buf, kdh, hdrsz);
}
- return (dump_raw_write(di, buf, physical, offset, di->blocksize));
+ return (dump_write(di, buf, physical, offset, di->blocksize));
}
/*
@@ -1185,7 +1137,7 @@ dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh,
* key.
*/
int
-dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t *dumplop)
+dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
uint64_t dumpsize;
uint32_t keysize;
@@ -1204,33 +1156,65 @@ dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t *dumplop)
if (di->mediasize < SIZEOF_METADATA + dumpsize)
return (E2BIG);
- *dumplop = di->mediaoffset + di->mediasize - dumpsize;
+ di->dumpoff = di->mediaoffset + di->mediasize - dumpsize;
- error = dump_write_header(di, kdh, 0, *dumplop);
+ error = dump_write_header(di, kdh, 0, di->dumpoff);
if (error != 0)
return (error);
- *dumplop += di->blocksize;
+ di->dumpoff += di->blocksize;
#ifdef EKCD
- error = dump_write_key(di, 0, *dumplop);
+ error = dump_write_key(di, 0, di->dumpoff);
if (error != 0)
return (error);
- *dumplop += keysize;
+ di->dumpoff += keysize;
#endif
return (0);
}
+/* Write to the dump device at the current dump offset. */
+int
+dump_append(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+ size_t length)
+{
+ int error;
+
+#ifdef EKCD
+ if (di->kdc != NULL)
+ error = dump_encrypted_write(di, virtual, physical, di->dumpoff,
+ length);
+ else
+#endif
+ error = dump_write(di, virtual, physical, di->dumpoff, length);
+ if (error == 0)
+ di->dumpoff += length;
+ return (error);
+}
+
+/* Perform a raw write to the dump device at the specified offset. */
+int
+dump_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
+ off_t offset, size_t length)
+{
+ int error;
+
+ error = dump_check_bounds(di, offset, length);
+ if (error != 0)
+ return (error);
+ return (di->dumper(di->priv, virtual, physical, offset, length));
+}
+
/*
* Write the trailing kernel dump header and signal to the lower layers that the
* dump has completed.
*/
int
-dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh, off_t dumplo)
+dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh)
{
int error;
- error = dump_write_header(di, kdh, 0, dumplo);
+ error = dump_write_header(di, kdh, 0, di->dumpoff);
if (error != 0)
return (error);