int osd_submit_and_wait(int fd, struct osd_command *command) { int ret; ret = osd_submit_command(fd, command); if (ret) { osd_error("%s: submit failed", __func__); return ret; } ret = osd_wait_this_response(fd, command); if (ret) { osd_error("%s: wait_response failed", __func__); return ret; } return 0; }
/* * osd_wait_response, plus verify that the command retrieved was the * one we expected, or error. */ int osd_wait_this_response(int fd, struct osd_command *command) { int ret; struct osd_command *cmp; ret = osd_wait_response(fd, &cmp); if (ret == 0) { if (cmp != command) { osd_error("%s: wrong command returned", __func__); ret = -EIO; } } return ret; }
int db_begin_txn(struct db_context *dbc) { int ret = 0; char *err = NULL; assert(dbc && dbc->db); ret = sqlite3_exec(dbc->db, "BEGIN TRANSACTION;", NULL, NULL, &err); if (ret != SQLITE_OK) { osd_error("pragma failed: %s", err); sqlite3_free(err); return OSD_ERROR; } return OSD_OK; }
int db_end_txn(struct db_context *dbc) { int ret = 0; char *err = NULL; TICK_TRACE(db_end_txn); assert(dbc && dbc->db); ret = sqlite3_exec(dbc->db, "END TRANSACTION;", NULL, NULL, &err); if (ret != SQLITE_OK) { osd_error("pragma failed: %s", err); return OSD_ERROR; } TICK_TRACE(db_end_txn); return OSD_OK; }
/* * returns: * OSD_ERROR: in case no table is found * OSD_OK: when all tables exist */ static int db_check_tables(struct db_context *dbc) { int i = 0; int ret = 0; char SQL[MAXSQLEN]; char *err = NULL; const char *tables[] = {"attr", "obj", "coll"}; struct array arr = {ARRAY_SIZE(tables), tables}; sprintf(SQL, "SELECT name FROM sqlite_master WHERE type='table' " " ORDER BY name;"); ret = sqlite3_exec(dbc->db, SQL, check_membership, &arr, &err); if (ret != SQLITE_OK) { osd_error("%s: query %s failed: %s", __func__, SQL, err); sqlite3_free(err); return OSD_ERROR; } return OSD_OK; }
int osd_wait_response(int fd, struct osd_command **out_command) { struct sg_io_v4 sg; struct osd_command *command; int ret; ret = read(fd, &sg, sizeof(sg)); if (ret < 0) { osd_error_errno("%s: read", __func__); return -errno; } if (ret != sizeof(sg)) { osd_error("%s: short read, %d not %zu", __func__, ret, sizeof(sg)); return -EPIPE; } command = (void *)(uintptr_t) sg.usr_ptr; if (command->inlen_alloc) command->inlen = command->inlen_alloc - sg.din_resid; command->status = sg.device_status; command->sense_len = sg.response_len; #ifndef KERNEL_SUPPORTS_BSG_IOVEC // copy from buffer to iovecs if (command->inlen_alloc && command->iov_inlen > 1) { sg_iovec_t *iov = (sg_iovec_t *) command->indata; uint8_t *buff = (uint8_t *) (uintptr_t) sg.din_xferp; int i; for (i=0; i<command->iov_inlen; i++) { memcpy(iov[i].iov_base, buff, iov[i].iov_len); buff += iov[i].iov_len; } free((void *) (uintptr_t) sg.din_xferp); } #endif *out_command = command; return 0; }
int db_print_pragma(struct db_context *dbc) { int ret = 0; char *err = NULL; char SQL[MAXSQLEN]; assert(dbc && dbc->db); sprintf(SQL, " PRAGMA synchronous;" " PRAGMA auto_vacuum;" " PRAGMA auto_vacuum;" " PRAGMA temp_store;" ); ret = sqlite3_exec(dbc->db, SQL, callback, NULL, &err); if (ret != SQLITE_OK) { osd_error("pragma failed: %s", err); sqlite3_free(err); return OSD_ERROR; } return OSD_OK; }
int db_exec_pragma(struct db_context *dbc) { int ret = 0; char *err = NULL; char SQL[MAXSQLEN]; assert(dbc && dbc->db); sprintf(SQL, "PRAGMA synchronous = OFF; " /* sync off */ "PRAGMA auto_vacuum = 1; " /* reduce db size on delete */ "PRAGMA count_changes = 0; " /* ignore count changes */ "PRAGMA temp_store = 0; " /* memory as scratchpad */ ); ret = sqlite3_exec(dbc->db, SQL, NULL, NULL, &err); if (ret != SQLITE_OK) { osd_error("pragma failed: %s", err); sqlite3_free(err); return OSD_ERROR; } return OSD_OK; }
static void init(void) { int ret; struct osd_drive_description *drive_list; int num_drives; printf("Initialization\n"); ret = osd_get_drive_list(&drive_list, &num_drives); if (ret < 0) { osd_error_errno("%s: get drive list", __func__); exit(1); } if (num_drives == 0) { osd_error("%s: No drives found: %d", __func__, num_drives); exit(1); } printf("Found %d Drives Now open drive #0\n", num_drives); fd = open(drive_list[0].chardev, O_RDWR); if (fd < 0) { osd_error_errno("%s: open %s", __func__, drive_list[0].chardev); exit(1); } }
static int bidi_test(int fd, uint64_t pid, uint64_t oid) { int ret; struct osd_command command; struct attribute_list *attr, attr_proto = { .page = 0x1, .number = 0x82, /* logical length (not used capacity) */ .len = sizeof(uint64_t), }; osd_info(__func__); ret = osd_command_set_get_attributes(&command, pid, oid); if (ret) { osd_error_xerrno(ret, "%s: get_attributes failed", __func__); printf("\n"); return 1; } ret = osd_command_attr_build(&command, &attr_proto, 1); if (ret) { osd_error_xerrno(ret, "%s: attr_build failed", __func__); printf("\n"); return 1; } memset(command.indata, 0xaa, command.inlen_alloc); ret = osd_submit_and_wait(fd, &command); if (ret) { osd_error_xerrno(ret, "%s: submit failed", __func__); printf("\n"); return 1; } printf("%s: status %u sense len %u inlen %zu\n", __func__, command.status, command.sense_len, command.inlen); /* verify retrieved list */ osd_hexdump(command.indata, command.inlen_alloc); ret = osd_command_attr_resolve(&command); if (ret) { osd_error("%s: attr_resolve failed", __func__); printf("\n"); exit(1); } attr = command.attr; if (attr->outlen != attr->len) { osd_error("%s: short attr outlen %d", __func__, attr->outlen); exit(1); } printf("%s: logical length 0x%016llx\n\n", __func__, llu(get_ntohll(attr->val))); osd_command_attr_free(&command); return 0; } static void iovec_write_test(int fd, uint64_t pid, uint64_t oid) { struct osd_command command; const char buf1[] = "If iovec_write_test works,"; const char buf2[] = " you will see this sentence."; char bufout[200]; struct bsg_iovec vec[2]; size_t tot_len; int ret; osd_info(__func__); vec[0].iov_base = (iov_base_t)(uintptr_t) buf1; vec[0].iov_len = sizeof(buf1)-1; vec[1].iov_base = (iov_base_t)(uintptr_t) buf2; vec[1].iov_len = sizeof(buf2); tot_len = sizeof(buf1)-1 + sizeof(buf2); memset(&command, 0, sizeof(command)); osd_command_set_write(&command, pid, oid, tot_len, 0); command.cdb_len = OSD_CDB_SIZE; command.outlen = tot_len; command.outdata = vec; command.iov_outlen = 2; ret = osd_submit_and_wait(fd, &command); if (ret) { osd_error("%s: submit_and_wait failed", __func__); return; } printf("%s: seemed to work\n", __func__); /* read it back, non-iov */ memset(&command, 0, sizeof(command)); memset(bufout, 0, sizeof(bufout)); osd_command_set_read(&command, pid, oid, sizeof(bufout), 0); command.cdb_len = OSD_CDB_SIZE; command.inlen_alloc = sizeof(bufout); command.indata = bufout; ret = osd_submit_and_wait(fd, &command); if (ret) osd_error("%s: submit_and_wait failed", __func__); printf("%s: read some bytes (%zu): %s\n\n", __func__, command.inlen, bufout); } static void iovec_read_test(int fd, uint64_t pid, uint64_t oid) { struct osd_command command; const char bufout[] = "A big line of data for iovec_read_test to get."; char buf1[21]; char buf2[100]; struct bsg_iovec vec[2]; size_t tot_len; int ret; /* write it, non-iov */ osd_info(__func__); memset(&command, 0, sizeof(command)); osd_command_set_write(&command, pid, oid, sizeof(bufout), 0); command.cdb_len = OSD_CDB_SIZE; command.outlen = sizeof(bufout); command.outdata = bufout; ret = osd_submit_and_wait(fd, &command); if (ret) { osd_error("%s: submit_and_wait failed", __func__); return; } memset(buf1, 0, sizeof(buf1)); memset(buf2, 0, sizeof(buf2)); vec[0].iov_base = (iov_base_t)(uintptr_t) buf1; vec[0].iov_len = sizeof(buf1)-1; vec[1].iov_base = (iov_base_t)(uintptr_t) buf2; vec[1].iov_len = sizeof(buf2); tot_len = sizeof(buf1)-1 + sizeof(buf2); memset(&command, 0, sizeof(command)); osd_command_set_read(&command, pid, oid, tot_len, 0); command.cdb_len = OSD_CDB_SIZE; command.inlen_alloc = tot_len; command.indata = vec; command.iov_inlen = 2; ret = osd_submit_and_wait(fd, &command); if (ret) { osd_error("%s: submit_and_wait failed", __func__); return; } buf1[sizeof(buf1)-1] = '\0'; /* terminate partial string */ printf("%s: read some bytes (%zu): %s + %s\n\n", __func__, command.inlen, buf1, buf2); } static void attr_test(int fd, uint64_t pid, uint64_t oid) { int i, ret; uint64_t len; uint8_t *ts; /* odd 6-byte timestamp */ const uint8_t data[] = "Some data."; /* const char attr_data[] = "An attribute.\n"; */ struct osd_command command; struct attribute_list *attr, attr_proto[] = { { .type = ATTR_GET, .page = 0x1, /* user info page */ .number = 0x82, /* logical length */ .len = sizeof(uint64_t), }, { .type = ATTR_GET,
/* * <0: error * ==0: success * ==1: new db opened, caller must initialize tables */ int osd_db_open(const char *path, struct osd_device *osd) { int ret; struct stat sb; char SQL[MAXSQLEN]; char *err = NULL; int is_new_db = 0; ret = stat(path, &sb); if (ret == 0) { if (!S_ISREG(sb.st_mode)) { osd_error("%s: path %s not a regular file %d", __func__, path, sb.st_mode); ret = 1; goto out; } } else { if (errno != ENOENT) { osd_error("%s: stat path %s", __func__, path); goto out; } /* sqlite3 will create it for us */ is_new_db = 1; } osd->handle->dbc = Calloc(1, sizeof(*osd->handle->dbc)); if (!osd->handle->dbc) { ret = -ENOMEM; goto out; } ret = sqlite3_open(path, &(osd->handle->dbc->db)); if (ret != SQLITE_OK) { osd_error("%s: open db %s", __func__, path); ret = OSD_ERROR; goto out_free_dbc; } if (is_new_db) { /* build tables from schema file */ ret = sqlite3_exec(osd->handle->dbc->db, osd_schema, NULL, NULL, &err); if (ret != SQLITE_OK) { sqlite3_free(err); ret = OSD_ERROR; goto out_close_db; } } else { /* existing db, check for tables */ ret = db_check_tables(osd->handle->dbc); if (ret != OSD_OK) goto out_close_db; } /* initialize dbc fields */ ret = db_initialize(osd->handle->dbc); if (ret != OSD_OK) { ret = OSD_ERROR; goto out_close_db; } if (is_new_db) ret = 1; goto out; out_close_db: sqlite3_close(osd->handle->dbc->db); out_free_dbc: free(osd->handle->dbc); osd->handle->dbc = NULL; out: return ret; }
int osd_submit_command(int fd, struct osd_command *command) { int ret; struct sg_io_v4 sg; memset(&sg, 0, sizeof(sg)); sg.guard = 'Q'; sg.request_len = command->cdb_len; sg.request = (uint64_t) (uintptr_t) command->cdb; sg.max_response_len = sizeof(command->sense); sg.response = (uint64_t) (uintptr_t) command->sense; if (command->outlen) { #ifdef KERNEL_SUPPORTS_BSG_IOVEC sg.dout_xfer_len = command->outlen; sg.dout_xferp = (uint64_t) (uintptr_t) command->outdata; sg.dout_iovec_count = command->iov_outlen; #else // The kernel doesn't support BSG iovecs mainly because // of a problem going from 32-bit user iovecs to a 64-bit kernel // So, just copy the iovecs into a new buffer and use that sg_iovec_t *iov = (sg_iovec_t *)(uintptr_t)command->outdata; if (command->iov_outlen == 0) { sg.dout_xfer_len = command->outlen; sg.dout_xferp = (uint64_t) (uintptr_t) command->outdata; } else if (command->iov_outlen == 1) { sg.dout_xfer_len = iov->iov_len; sg.dout_xferp = (uint64_t) (uintptr_t) iov->iov_base; } else { int i; uint8_t *buff = Malloc(command->outlen); sg.dout_xferp = (uint64_t) (uintptr_t) buff; for (i=0; i<command->iov_outlen; i++) { memcpy(buff, iov[i].iov_base, iov[i].iov_len); buff += iov[i].iov_len; } sg.dout_xfer_len = command->outlen; } sg.dout_iovec_count = 0; #endif } if (command->inlen_alloc) { #ifdef KERNEL_SUPPORTS_BSG_IOVEC sg.din_xfer_len = command->inlen_alloc; sg.din_xferp = (uint64_t) (uintptr_t) command->indata; sg.din_iovec_count = command->iov_inlen; #else if (command->iov_inlen == 0) { sg.din_xfer_len = command->inlen_alloc; sg.din_xferp = (uint64_t) (uintptr_t) command->indata; sg.din_iovec_count = command->iov_inlen; } else if (command->iov_inlen == 1) { sg_iovec_t *iov = (sg_iovec_t *)command->indata; sg.din_xfer_len = iov->iov_len; sg.din_xferp = (uint64_t) (uintptr_t) iov->iov_base; } else { sg.din_xfer_len = command->inlen_alloc; sg.din_xferp = (uint64_t) (uintptr_t) (uint8_t*) Malloc(command->inlen_alloc); } sg.din_iovec_count = 0; #endif } /* * Allow 30 sec for entire command. Some can be * slow, especially with debugging messages on. */ sg.timeout = 30000; sg.usr_ptr = (uint64_t) (uintptr_t) command; ret = write(fd, &sg, sizeof(sg)); #ifndef KERNEL_SUPPORTS_BSG_IOVEC if (command->outlen && command->iov_outlen > 1) { free((void *) (uintptr_t) sg.dout_xferp); } #endif if (ret < 0) { osd_error_errno("%s: write", __func__); return -errno; } if (ret != sizeof(sg)) { osd_error("%s: short write, %d not %zu", __func__, ret, sizeof(sg)); return -EIO; } return 0; }