aboutsummaryrefslogtreecommitdiff
path: root/sbin/nvmecontrol/logpage.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/nvmecontrol/logpage.c')
-rw-r--r--sbin/nvmecontrol/logpage.c266
1 files changed, 105 insertions, 161 deletions
diff --git a/sbin/nvmecontrol/logpage.c b/sbin/nvmecontrol/logpage.c
index 725815edc475..023adf8f2d6a 100644
--- a/sbin/nvmecontrol/logpage.c
+++ b/sbin/nvmecontrol/logpage.c
@@ -6,6 +6,7 @@
*
* Copyright (C) 2012-2013 Intel Corporation
* All rights reserved.
+ * Copyright (C) 2016-2023 Warner Losh <imp@FreeBSD.org>
* Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +31,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ioccom.h>
@@ -190,11 +190,11 @@ get_log_buffer(uint32_t size)
void
read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp,
- uint16_t lsi, uint8_t rae, void *payload, uint32_t payload_size)
+ uint16_t lsi, uint8_t rae, uint64_t lpo, uint8_t csi, uint8_t ot,
+ uint16_t uuid_index, void *payload, uint32_t payload_size)
{
struct nvme_pt_command pt;
- struct nvme_error_information_entry *err_entry;
- u_int i, err_pages, numd;
+ u_int numd;
numd = payload_size / sizeof(uint32_t) - 1;
memset(&pt, 0, sizeof(pt));
@@ -208,9 +208,12 @@ read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp,
pt.cmd.cdw11 = htole32(
((uint32_t)lsi << 16) | /* LSI */
(numd >> 16)); /* NUMDU */
- pt.cmd.cdw12 = 0; /* LPOL */
- pt.cmd.cdw13 = 0; /* LPOU */
- pt.cmd.cdw14 = 0; /* UUID Index */
+ pt.cmd.cdw12 = htole32(lpo & 0xffffffff); /* LPOL */
+ pt.cmd.cdw13 = htole32(lpo >> 32); /* LPOU */
+ pt.cmd.cdw14 = htole32(
+ (csi << 24) | /* CSI */
+ (ot << 23) | /* OT */
+ uuid_index); /* UUID Index */
pt.buf = payload;
pt.len = payload_size;
pt.is_read = 1;
@@ -218,49 +221,6 @@ read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp,
if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
err(EX_IOERR, "get log page request failed");
- /* Convert data to host endian */
- switch (log_page) {
- case NVME_LOG_ERROR:
- err_entry = (struct nvme_error_information_entry *)payload;
- err_pages = payload_size / sizeof(struct nvme_error_information_entry);
- for (i = 0; i < err_pages; i++)
- nvme_error_information_entry_swapbytes(err_entry++);
- break;
- case NVME_LOG_HEALTH_INFORMATION:
- nvme_health_information_page_swapbytes(
- (struct nvme_health_information_page *)payload);
- break;
- case NVME_LOG_FIRMWARE_SLOT:
- nvme_firmware_page_swapbytes(
- (struct nvme_firmware_page *)payload);
- break;
- case NVME_LOG_CHANGED_NAMESPACE:
- nvme_ns_list_swapbytes((struct nvme_ns_list *)payload);
- break;
- case NVME_LOG_DEVICE_SELF_TEST:
- nvme_device_self_test_swapbytes(
- (struct nvme_device_self_test_page *)payload);
- break;
- case NVME_LOG_COMMAND_EFFECT:
- nvme_command_effects_page_swapbytes(
- (struct nvme_command_effects_page *)payload);
- break;
- case NVME_LOG_RES_NOTIFICATION:
- nvme_res_notification_page_swapbytes(
- (struct nvme_res_notification_page *)payload);
- break;
- case NVME_LOG_SANITIZE_STATUS:
- nvme_sanitize_status_page_swapbytes(
- (struct nvme_sanitize_status_page *)payload);
- break;
- case INTEL_LOG_TEMP_STATS:
- intel_log_temp_stats_swapbytes(
- (struct intel_log_temp_stats *)payload);
- break;
- default:
- break;
- }
-
if (nvme_completion_is_error(&pt.cpl))
errx(EX_IOERR, "get log page request returned error");
}
@@ -276,17 +236,17 @@ print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, ui
printf("Error Information Log\n");
printf("=====================\n");
- if (entry->error_count == 0) {
+ if (letoh(entry->error_count) == 0) {
printf("No error entries found\n");
return;
}
- nentries = size/sizeof(struct nvme_error_information_entry);
+ nentries = size / sizeof(struct nvme_error_information_entry);
for (i = 0; i < nentries; i++, entry++) {
- if (entry->error_count == 0)
+ if (letoh(entry->error_count) == 0)
break;
- status = entry->status;
+ status = letoh(entry->status);
p = NVME_STATUS_GET_P(status);
sc = NVME_STATUS_GET_SC(status);
@@ -296,9 +256,9 @@ print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, ui
printf("Entry %02d\n", i + 1);
printf("=========\n");
- printf(" Error count: %ju\n", entry->error_count);
- printf(" Submission queue ID: %u\n", entry->sqid);
- printf(" Command ID: %u\n", entry->cid);
+ printf(" Error count: %ju\n", letoh(entry->error_count));
+ printf(" Submission queue ID: %u\n", letoh(entry->sqid));
+ printf(" Command ID: %u\n", letoh(entry->cid));
/* TODO: Export nvme_status_string structures from kernel? */
printf(" Status:\n");
printf(" Phase tag: %d\n", p);
@@ -306,13 +266,13 @@ print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, ui
printf(" Status code type: %d\n", sct);
printf(" More: %d\n", m);
printf(" DNR: %d\n", dnr);
- printf(" Error location: %u\n", entry->error_location);
- printf(" LBA: %ju\n", entry->lba);
- printf(" Namespace ID: %u\n", entry->nsid);
- printf(" Vendor specific info: %u\n", entry->vendor_specific);
- printf(" Transport type: %u\n", entry->trtype);
- printf(" Command specific info:%ju\n", entry->csi);
- printf(" Transport specific: %u\n", entry->ttsi);
+ printf(" Error location: %u\n", letoh(entry->error_location));
+ printf(" LBA: %ju\n", letoh(entry->lba));
+ printf(" Namespace ID: %u\n", letoh(entry->nsid));
+ printf(" Vendor specific info: %u\n", letoh(entry->vendor_specific));
+ printf(" Transport type: %u\n", letoh(entry->trtype));
+ printf(" Command specific info:%ju\n", letoh(entry->csi));
+ printf(" Transport specific: %u\n", letoh(entry->ttsi));
}
}
@@ -336,7 +296,7 @@ print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, u
uint8_t warning;
int i;
- warning = health->critical_warning;
+ warning = letoh(health->critical_warning);
printf("SMART/Health Information Log\n");
printf("============================\n");
@@ -353,13 +313,13 @@ print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, u
printf(" Volatile memory backup: %d\n",
!!(warning & NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP));
printf("Temperature: ");
- print_temp_K(health->temperature);
+ print_temp_K(letoh(health->temperature));
printf("Available spare: %u\n",
- health->available_spare);
+ letoh(health->available_spare));
printf("Available spare threshold: %u\n",
- health->available_spare_threshold);
+ letoh(health->available_spare_threshold));
printf("Percentage used: %u\n",
- health->percentage_used);
+ letoh(health->percentage_used));
printf("Data units (512,000 byte) read: %s\n",
uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf)));
@@ -382,18 +342,18 @@ print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, u
printf("No. error info log entries: %s\n",
uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf)));
- printf("Warning Temp Composite Time: %d\n", health->warning_temp_time);
- printf("Error Temp Composite Time: %d\n", health->error_temp_time);
+ printf("Warning Temp Composite Time: %d\n", letoh(health->warning_temp_time));
+ printf("Error Temp Composite Time: %d\n", letoh(health->error_temp_time));
for (i = 0; i < 8; i++) {
- if (health->temp_sensor[i] == 0)
+ if (letoh(health->temp_sensor[i]) == 0)
continue;
printf("Temperature Sensor %d: ", i + 1);
- print_temp_K(health->temp_sensor[i]);
+ print_temp_K(letoh(health->temp_sensor[i]));
}
- printf("Temperature 1 Transition Count: %d\n", health->tmt1tc);
- printf("Temperature 2 Transition Count: %d\n", health->tmt2tc);
- printf("Total Time For Temperature 1: %d\n", health->ttftmt1);
- printf("Total Time For Temperature 2: %d\n", health->ttftmt2);
+ printf("Temperature 1 Transition Count: %d\n", letoh(health->tmt1tc));
+ printf("Temperature 2 Transition Count: %d\n", letoh(health->tmt2tc));
+ printf("Total Time For Temperature 1: %d\n", letoh(health->ttftmt1));
+ printf("Total Time For Temperature 2: %d\n", letoh(health->ttftmt2));
}
static void
@@ -406,13 +366,10 @@ print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t
uint16_t oacs_fw;
uint8_t fw_num_slots;
- afi_slot = fw->afi >> NVME_FIRMWARE_PAGE_AFI_SLOT_SHIFT;
- afi_slot &= NVME_FIRMWARE_PAGE_AFI_SLOT_MASK;
+ afi_slot = NVMEV(NVME_FIRMWARE_PAGE_AFI_SLOT, fw->afi);
- oacs_fw = (cdata->oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) &
- NVME_CTRLR_DATA_OACS_FIRMWARE_MASK;
- fw_num_slots = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT) &
- NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK;
+ oacs_fw = NVMEV(NVME_CTRLR_DATA_OACS_FIRMWARE, cdata->oacs);
+ fw_num_slots = NVMEV(NVME_CTRLR_DATA_FRMW_NUM_SLOTS, cdata->frmw);
printf("Firmware Slot Log\n");
printf("=================\n");
@@ -429,15 +386,10 @@ print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t
else
status = "Inactive";
- if (fw->revision[i] == 0LLU)
+ if (fw->revision[i][0] == '\0')
printf("Empty\n");
else
- if (isprint(*(char *)&fw->revision[i]))
- printf("[%s] %.8s\n", status,
- (char *)&fw->revision[i]);
- else
- printf("[%s] %016jx\n", status,
- fw->revision[i]);
+ printf("[%s] %.8s\n", status, fw->revision[i]);
}
}
@@ -452,8 +404,8 @@ print_log_ns(const struct nvme_controller_data *cdata __unused, void *buf,
printf("Changed Namespace List\n");
printf("======================\n");
- for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
- printf("%08x\n", nsl->ns[i]);
+ for (i = 0; i < nitems(nsl->ns) && letoh(nsl->ns[i]) != 0; i++) {
+ printf("%08x\n", letoh(nsl->ns[i]));
}
}
@@ -471,42 +423,28 @@ print_log_command_effects(const struct nvme_controller_data *cdata __unused,
printf(" Command\tLBCC\tNCC\tNIC\tCCC\tCSE\tUUID\n");
for (i = 0; i < 255; i++) {
- s = ce->acs[i];
- if (((s >> NVME_CE_PAGE_CSUP_SHIFT) &
- NVME_CE_PAGE_CSUP_MASK) == 0)
+ s = letoh(ce->acs[i]);
+ if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0)
continue;
printf("Admin\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i,
- ((s >> NVME_CE_PAGE_LBCC_SHIFT) &
- NVME_CE_PAGE_LBCC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_NCC_SHIFT) &
- NVME_CE_PAGE_NCC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_NIC_SHIFT) &
- NVME_CE_PAGE_NIC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_CCC_SHIFT) &
- NVME_CE_PAGE_CCC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_CSE_SHIFT) &
- NVME_CE_PAGE_CSE_MASK),
- ((s >> NVME_CE_PAGE_UUID_SHIFT) &
- NVME_CE_PAGE_UUID_MASK) ? "Yes" : "No");
+ NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_CSE, s),
+ NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No");
}
for (i = 0; i < 255; i++) {
- s = ce->iocs[i];
- if (((s >> NVME_CE_PAGE_CSUP_SHIFT) &
- NVME_CE_PAGE_CSUP_MASK) == 0)
+ s = letoh(ce->iocs[i]);
+ if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0)
continue;
printf("I/O\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i,
- ((s >> NVME_CE_PAGE_LBCC_SHIFT) &
- NVME_CE_PAGE_LBCC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_NCC_SHIFT) &
- NVME_CE_PAGE_NCC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_NIC_SHIFT) &
- NVME_CE_PAGE_NIC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_CCC_SHIFT) &
- NVME_CE_PAGE_CCC_MASK) ? "Yes" : "No",
- ((s >> NVME_CE_PAGE_CSE_SHIFT) &
- NVME_CE_PAGE_CSE_MASK),
- ((s >> NVME_CE_PAGE_UUID_SHIFT) &
- NVME_CE_PAGE_UUID_MASK) ? "Yes" : "No");
+ NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No",
+ NVMEV(NVME_CE_PAGE_CSE, s),
+ NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No");
}
}
@@ -520,9 +458,10 @@ print_log_res_notification(const struct nvme_controller_data *cdata __unused,
printf("Reservation Notification\n");
printf("========================\n");
- printf("Log Page Count: %ju\n", rn->log_page_count);
+ printf("Log Page Count: %ju\n",
+ (uintmax_t)letoh(rn->log_page_count));
printf("Log Page Type: ");
- switch (rn->log_page_type) {
+ switch (letoh(rn->log_page_type)) {
case 0:
printf("Empty Log Page\n");
break;
@@ -536,11 +475,11 @@ print_log_res_notification(const struct nvme_controller_data *cdata __unused,
printf("Reservation Preempted\n");
break;
default:
- printf("Unknown %x\n", rn->log_page_type);
+ printf("Unknown %x\n", letoh(rn->log_page_type));
break;
};
- printf("Number of Available Log Pages: %d\n", rn->available_log_pages);
- printf("Namespace ID: 0x%x\n", rn->nsid);
+ printf("Number of Available Log Pages: %d\n", letoh(rn->available_log_pages));
+ printf("Namespace ID: 0x%x\n", letoh(rn->nsid));
}
static void
@@ -549,16 +488,18 @@ print_log_sanitize_status(const struct nvme_controller_data *cdata __unused,
{
struct nvme_sanitize_status_page *ss;
u_int p;
+ uint16_t sprog, sstat;
ss = (struct nvme_sanitize_status_page *)buf;
printf("Sanitize Status\n");
printf("===============\n");
+ sprog = letoh(ss->sprog);
printf("Sanitize Progress: %u%% (%u/65535)\n",
- (ss->sprog * 100 + 32768) / 65536, ss->sprog);
+ (sprog * 100 + 32768) / 65536, sprog);
printf("Sanitize Status: ");
- switch ((ss->sstat >> NVME_SS_PAGE_SSTAT_STATUS_SHIFT) &
- NVME_SS_PAGE_SSTAT_STATUS_MASK) {
+ sstat = letoh(ss->sstat);
+ switch (NVMEV(NVME_SS_PAGE_SSTAT_STATUS, sstat)) {
case NVME_SS_PAGE_SSTAT_STATUS_NEVER:
printf("Never sanitized");
break;
@@ -575,24 +516,22 @@ print_log_sanitize_status(const struct nvme_controller_data *cdata __unused,
printf("Completed with deallocation");
break;
default:
- printf("Unknown");
+ printf("Unknown 0x%x", sstat);
break;
}
- p = (ss->sstat >> NVME_SS_PAGE_SSTAT_PASSES_SHIFT) &
- NVME_SS_PAGE_SSTAT_PASSES_MASK;
+ p = NVMEV(NVME_SS_PAGE_SSTAT_PASSES, sstat);
if (p > 0)
printf(", %d passes", p);
- if ((ss->sstat >> NVME_SS_PAGE_SSTAT_GDE_SHIFT) &
- NVME_SS_PAGE_SSTAT_GDE_MASK)
+ if (NVMEV(NVME_SS_PAGE_SSTAT_GDE, sstat) != 0)
printf(", Global Data Erased");
printf("\n");
- printf("Sanitize Command Dword 10: 0x%x\n", ss->scdw10);
- printf("Time For Overwrite: %u sec\n", ss->etfo);
- printf("Time For Block Erase: %u sec\n", ss->etfbe);
- printf("Time For Crypto Erase: %u sec\n", ss->etfce);
- printf("Time For Overwrite No-Deallocate: %u sec\n", ss->etfownd);
- printf("Time For Block Erase No-Deallocate: %u sec\n", ss->etfbewnd);
- printf("Time For Crypto Erase No-Deallocate: %u sec\n", ss->etfcewnd);
+ printf("Sanitize Command Dword 10: 0x%x\n", letoh(ss->scdw10));
+ printf("Time For Overwrite: %u sec\n", letoh(ss->etfo));
+ printf("Time For Block Erase: %u sec\n", letoh(ss->etfbe));
+ printf("Time For Crypto Erase: %u sec\n", letoh(ss->etfce));
+ printf("Time For Overwrite No-Deallocate: %u sec\n", letoh(ss->etfownd));
+ printf("Time For Block Erase No-Deallocate: %u sec\n", letoh(ss->etfbewnd));
+ printf("Time For Crypto Erase No-Deallocate: %u sec\n", letoh(ss->etfcewnd));
}
static const char *
@@ -616,13 +555,14 @@ print_log_self_test_status(const struct nvme_controller_data *cdata __unused,
{
struct nvme_device_self_test_page *dst;
uint32_t r;
+ uint16_t vs;
dst = buf;
printf("Device Self-test Status\n");
printf("=======================\n");
printf("Current Operation: ");
- switch (dst->curr_operation) {
+ switch (letoh(dst->curr_operation)) {
case 0x0:
printf("No device self-test operation in progress\n");
break;
@@ -636,19 +576,20 @@ print_log_self_test_status(const struct nvme_controller_data *cdata __unused,
printf("Vendor specific\n");
break;
default:
- printf("Reserved (0x%x)\n", dst->curr_operation);
+ printf("Reserved (0x%x)\n", letoh(dst->curr_operation));
}
- if (dst->curr_operation != 0)
- printf("Current Completion: %u%%\n", dst->curr_compl & 0x7f);
+ if (letoh(dst->curr_operation) != 0)
+ printf("Current Completion: %u%%\n", letoh(dst->curr_compl) & 0x7f);
printf("Results\n");
for (r = 0; r < 20; r++) {
uint64_t failing_lba;
- uint8_t code, res;
+ uint8_t code, res, status;
- code = (dst->result[r].status >> 4) & 0xf;
- res = dst->result[r].status & 0xf;
+ status = letoh(dst->result[r].status);
+ code = (status >> 4) & 0xf;
+ res = status & 0xf;
if (res == 0xf)
continue;
@@ -673,21 +614,24 @@ print_log_self_test_status(const struct nvme_controller_data *cdata __unused,
printf(" Reserved status 0x%x", res);
if (res == 7)
- printf(" starting in segment %u", dst->result[r].segment_num);
+ printf(" starting in segment %u",
+ letoh(dst->result[r].segment_num));
#define BIT(b) (1 << (b))
- if (dst->result[r].valid_diag_info & BIT(0))
- printf(" NSID=0x%x", dst->result[r].nsid);
- if (dst->result[r].valid_diag_info & BIT(1)) {
+ if (letoh(dst->result[r].valid_diag_info) & BIT(0))
+ printf(" NSID=0x%x", letoh(dst->result[r].nsid));
+ if (letoh(dst->result[r].valid_diag_info) & BIT(1)) {
memcpy(&failing_lba, dst->result[r].failing_lba,
sizeof(failing_lba));
- printf(" FLBA=0x%jx", failing_lba);
+ printf(" FLBA=0x%jx", (uintmax_t)letoh(failing_lba));
}
- if (dst->result[r].valid_diag_info & BIT(2))
- printf(" SCT=0x%x", dst->result[r].status_code_type);
- if (dst->result[r].valid_diag_info & BIT(3))
- printf(" SC=0x%x", dst->result[r].status_code);
+ if (letoh(dst->result[r].valid_diag_info) & BIT(2))
+ printf(" SCT=0x%x", letoh(dst->result[r].status_code_type));
+ if (letoh(dst->result[r].valid_diag_info) & BIT(3))
+ printf(" SC=0x%x", letoh(dst->result[r].status_code));
#undef BIT
+ memcpy(&vs, dst->result[r].vendor_specific, sizeof(vs));
+ printf(" VENDOR_SPECIFIC=0x%x", letoh(vs));
printf("\n");
}
}
@@ -805,8 +749,7 @@ logpage(const struct cmd *f, int argc, char *argv[])
if (read_controller_data(fd, &cdata))
errx(EX_IOERR, "Identify request failed");
- ns_smart = (cdata.lpa >> NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT) &
- NVME_CTRLR_DATA_LPA_NS_SMART_MASK;
+ ns_smart = NVMEV(NVME_CTRLR_DATA_LPA_NS_SMART, cdata.lpa);
/*
* The log page attributes indicate whether or not the controller
@@ -855,7 +798,8 @@ logpage(const struct cmd *f, int argc, char *argv[])
/* Read the log page */
buf = get_log_buffer(size);
- read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae, buf, size);
+ read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae,
+ 0, 0, 0, 0, buf, size);
print_fn(&cdata, buf, size);
close(fd);