Implement crashdump support on NVME
MFC after: 3 days Sponsored by: Netflix, Inc.
This commit is contained in:
parent
f9f6c123cd
commit
ff355c7557
@ -47,6 +47,7 @@ struct nvd_disk;
|
||||
|
||||
static disk_ioctl_t nvd_ioctl;
|
||||
static disk_strategy_t nvd_strategy;
|
||||
static dumper_t nvd_dump;
|
||||
|
||||
static void nvd_done(void *arg, const struct nvme_completion *cpl);
|
||||
|
||||
@ -226,6 +227,26 @@ nvd_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
nvd_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
|
||||
{
|
||||
struct nvd_disk *ndisk;
|
||||
struct disk *dp;
|
||||
int error;
|
||||
|
||||
dp = arg;
|
||||
ndisk = dp->d_drv1;
|
||||
|
||||
if (len > 0) {
|
||||
if ((error = nvme_ns_dump(ndisk->ns, virt, offset, len)) != 0)
|
||||
return (error);
|
||||
} else {
|
||||
/* XXX sync to stable storage */
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
nvd_done(void *arg, const struct nvme_completion *cpl)
|
||||
{
|
||||
@ -302,6 +323,7 @@ nvd_new_disk(struct nvme_namespace *ns, void *ctrlr_arg)
|
||||
disk = disk_alloc();
|
||||
disk->d_strategy = nvd_strategy;
|
||||
disk->d_ioctl = nvd_ioctl;
|
||||
disk->d_dump = nvd_dump;
|
||||
disk->d_name = NVD_STR;
|
||||
disk->d_drv1 = ndisk;
|
||||
|
||||
|
@ -876,6 +876,8 @@ int nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload,
|
||||
void *cb_arg);
|
||||
int nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn,
|
||||
void *cb_arg);
|
||||
int nvme_ns_dump(struct nvme_namespace *ns, void *virt, off_t offset,
|
||||
size_t len);
|
||||
|
||||
/* Registration functions */
|
||||
struct nvme_consumer * nvme_register_consumer(nvme_cons_ns_fn_t ns_fn,
|
||||
|
@ -151,3 +151,47 @@ nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, void *cb_arg)
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Timeout = 1 sec */
|
||||
#define NVD_DUMP_TIMEOUT 100000
|
||||
|
||||
int
|
||||
nvme_ns_dump(struct nvme_namespace *ns, void *virt, off_t offset, size_t len)
|
||||
{
|
||||
struct nvme_completion_poll_status status;
|
||||
struct nvme_request *req;
|
||||
struct nvme_command *cmd;
|
||||
uint64_t lba, lba_count;
|
||||
int i;
|
||||
|
||||
status.done = FALSE;
|
||||
req = nvme_allocate_request_vaddr(virt, len, nvme_completion_poll_cb,
|
||||
&status);
|
||||
if (req == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
cmd = &req->cmd;
|
||||
cmd->opc = NVME_OPC_WRITE;
|
||||
cmd->nsid = ns->id;
|
||||
|
||||
lba = offset / nvme_ns_get_sector_size(ns);
|
||||
lba_count = len / nvme_ns_get_sector_size(ns);
|
||||
|
||||
*(uint64_t *)&cmd->cdw10 = lba;
|
||||
cmd->cdw12 = lba_count - 1;
|
||||
|
||||
nvme_ctrlr_submit_io_request(ns->ctrlr, req);
|
||||
if (req->qpair == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
i = 0;
|
||||
while ((i++ < NVD_DUMP_TIMEOUT) && (status.done == FALSE)) {
|
||||
DELAY(10);
|
||||
nvme_qpair_process_completions(req->qpair);
|
||||
}
|
||||
|
||||
if (status.done == FALSE)
|
||||
return (ETIMEDOUT);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user