-
Notifications
You must be signed in to change notification settings - Fork 228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
don't panic the kernel upon a device error #4414
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import { insistKernelType } from './parseKernelSlots.js'; | |
import { insistVatType, parseVatSlot } from '../parseVatSlots.js'; | ||
import { insistCapData } from '../capdata.js'; | ||
import { kdebug } from './kdebug.js'; | ||
import { insistValidVatstoreKey } from './vatTranslator.js'; | ||
|
||
/* | ||
* Return a function that converts KernelInvocation objects into | ||
|
@@ -37,23 +38,38 @@ function makeDRTranslator(deviceID, kernelKeeper) { | |
const deviceKeeper = kernelKeeper.allocateDeviceKeeperIfNeeded(deviceID); | ||
const { mapDeviceSlotToKernelSlot } = deviceKeeper; | ||
|
||
/** | ||
* | ||
* @param { DeviceInvocationResult } deviceInvocationResult | ||
* @returns { KernelSyscallResult } | ||
*/ | ||
function deviceResultToKernelResult(deviceInvocationResult) { | ||
// deviceInvocationResult is ['ok', capdata] | ||
const [successFlag, devData] = deviceInvocationResult; | ||
assert(successFlag === 'ok'); | ||
insistCapData(devData); | ||
const kData = { | ||
...devData, | ||
slots: devData.slots.map(slot => mapDeviceSlotToKernelSlot(slot)), | ||
}; | ||
return harden(['ok', kData]); | ||
if (successFlag === 'ok') { | ||
insistCapData(devData); | ||
const kData = { | ||
...devData, | ||
slots: devData.slots.map(slot => mapDeviceSlotToKernelSlot(slot)), | ||
}; | ||
return harden(['ok', kData]); | ||
} else { | ||
assert.equal(successFlag, 'error'); | ||
assert.typeof(devData, 'string'); | ||
return harden([successFlag, devData]); | ||
} | ||
} | ||
return deviceResultToKernelResult; | ||
} | ||
|
||
/* | ||
/** | ||
* return a function that converts DeviceSyscall objects into KernelSyscall | ||
* objects | ||
* | ||
* @param { string } deviceID | ||
* @param { string } deviceName | ||
* @param { * } kernelKeeper | ||
* @returns { (dsc: DeviceSyscallObject) => KernelSyscallObject } | ||
*/ | ||
export function makeDSTranslator(deviceID, deviceName, kernelKeeper) { | ||
const deviceKeeper = kernelKeeper.allocateDeviceKeeperIfNeeded(deviceID); | ||
|
@@ -81,14 +97,67 @@ export function makeDSTranslator(deviceID, deviceName, kernelKeeper) { | |
return ks; | ||
} | ||
|
||
function translateVatstoreGet(key) { | ||
insistValidVatstoreKey(key); | ||
kdebug(`syscall[${deviceID}].vatstoreGet(${key})`); | ||
return harden(['vatstoreGet', deviceID, key]); | ||
} | ||
|
||
function translateVatstoreSet(key, value) { | ||
insistValidVatstoreKey(key); | ||
assert.typeof(value, 'string'); | ||
kdebug(`syscall[${deviceID}].vatstoreSet(${key},${value})`); | ||
return harden(['vatstoreSet', deviceID, key, value]); | ||
} | ||
|
||
function translateVatstoreGetAfter(priorKey, lowerBound, upperBound) { | ||
if (priorKey !== '') { | ||
insistValidVatstoreKey(priorKey); | ||
} | ||
insistValidVatstoreKey(lowerBound); | ||
if (upperBound) { | ||
insistValidVatstoreKey(upperBound); | ||
} | ||
kdebug( | ||
`syscall[${deviceID}].vatstoreGetAfter(${priorKey}, ${lowerBound}, ${upperBound})`, | ||
); | ||
return harden([ | ||
'vatstoreGetAfter', | ||
deviceID, | ||
priorKey, | ||
lowerBound, | ||
upperBound, | ||
]); | ||
} | ||
|
||
function translateVatstoreDelete(key) { | ||
insistValidVatstoreKey(key); | ||
kdebug(`syscall[${deviceID}].vatstoreDelete(${key})`); | ||
return harden(['vatstoreDelete', deviceID, key]); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like there's quite a bit of code duplication with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, maybe. For now, devices don't get the same syscalls as vats: they don't do promises, so But in the long run, yeah, we want devices to be more like vats, and at that point it'll make sense to drop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking more along the lines of a syscall translator that's parameterized according to whether it thinks it's doing the job for a vat or a device, which would allow differences between the two to be accommodated but would allow the 95% that's the same to be a single piece of code to maintain. |
||
|
||
// vsc is [type, ...args] | ||
// ksc is: | ||
// ['send', ktarget, kmsg] | ||
/** | ||
* Convert syscalls from device space to kernel space | ||
* | ||
* @param { DeviceSyscallObject } vsc | ||
* @returns { KernelSyscallObject } | ||
*/ | ||
function deviceSyscallToKernelSyscall(vsc) { | ||
const [type, ...args] = vsc; | ||
switch (type) { | ||
case 'sendOnly': | ||
return translateSendOnly(...args); // becomes ['send' .. result=null] | ||
case 'vatstoreGet': | ||
return translateVatstoreGet(...args); | ||
case 'vatstoreSet': | ||
return translateVatstoreSet(...args); | ||
case 'vatstoreGetAfter': | ||
return translateVatstoreGetAfter(...args); | ||
case 'vatstoreDelete': | ||
return translateVatstoreDelete(...args); | ||
default: | ||
assert.fail(X`unknown deviceSyscall type ${type}`); | ||
} | ||
|
@@ -97,6 +166,30 @@ export function makeDSTranslator(deviceID, deviceName, kernelKeeper) { | |
return deviceSyscallToKernelSyscall; | ||
} | ||
|
||
function kernelResultToDeviceResult(type, kres) { | ||
const [successFlag, resultData] = kres; | ||
assert(successFlag === 'ok', 'unexpected KSR error'); | ||
switch (type) { | ||
case 'vatstoreGet': | ||
if (resultData) { | ||
assert.typeof(resultData, 'string'); | ||
return harden(['ok', resultData]); | ||
} else { | ||
return harden(['ok', undefined]); | ||
} | ||
case 'vatstoreGetAfter': | ||
if (resultData) { | ||
assert(Array.isArray(resultData)); | ||
return harden(['ok', resultData]); | ||
} else { | ||
return harden(['ok', undefined]); | ||
} | ||
default: | ||
assert(resultData === null); | ||
return harden(['ok', null]); | ||
} | ||
} | ||
|
||
export function makeDeviceTranslators(deviceID, deviceName, kernelKeeper) { | ||
return harden({ | ||
kernelInvocationToDeviceInvocation: makeKDTranslator( | ||
|
@@ -109,6 +202,6 @@ export function makeDeviceTranslators(deviceID, deviceName, kernelKeeper) { | |
deviceName, | ||
kernelKeeper, | ||
), | ||
// no syscall results translator: devices cannot do syscall.callNow() | ||
kernelResultToDeviceResult, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this assert. What is the meaning of the 3rd argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the message emitted if the assertion fails (or at least I think that's what it's for), so the developer at the console can figure out why it threw without going back and inserting a
console.log
.optDetails
seems to be the official name. The default foroptDetails
reports the two values being compared, in this case "2" and whatever.length
is. In the failure mode I ran into, where my raw device returned{ body: .., slots: ..}
instead of['ok', { body, slots }]
, the assertion printedundefined !== 2
, which didn't help me very much.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also thought the 3rd arg was the message string, which is why I am puzzled because
deviceResults
is not a string.