/* * test == 1: fetch oids * test == 2: fetch cids * test == 3: fetch pids * test == 4: fetch pids when each pid has some objs */ static void time_obj_fetch(struct osd_device *osd, int numobj, int numiter, int test) { int ret = 0; int i = 0, j = 0, k = 0; uint64_t start, end; uint64_t *ids = NULL; uint64_t usedlen = 0, addlen = 0, contid = 0; int numpid = 0; uint8_t *cp = 0; double *t = 0; double mu, sd; const char *func = NULL; if (test < 1 || test > 4) return; t = Calloc(numiter, sizeof(*t)); ids = Calloc(numobj, sizeof(*ids)); if (!t || !ids) return; cp = (uint8_t *)ids; /* run pilot tests */ switch (test) { case 1: { ret = obj_insert(osd->dbc, 20, 11, 128); assert(ret == 0); ret = obj_get_oids_in_pid(osd->dbc, 20, 0, sizeof(*ids)*1, cp, &usedlen, &addlen, &contid); assert(ret == 0); assert(get_ntohll(cp) == 11); assert(usedlen == 8), usedlen = 0; assert(addlen == 8), addlen = 0; assert(contid == 0); ids[0] = 0; ret = obj_delete_pid(osd->dbc, 20); assert(ret == 0); func = "getoids"; break; } case 2: { ret = obj_insert(osd->dbc, 20, 11, 64); assert(ret == 0); ret = obj_get_cids_in_pid(osd->dbc, 20, 0, sizeof(*ids)*1, cp, &usedlen, &addlen, &contid); assert(ret == 0); assert(get_ntohll(cp) == 11); assert(usedlen == 8), usedlen = 0; assert(addlen == 8), addlen = 0; assert(contid == 0); ids[0] = 0; ret = obj_delete_pid(osd->dbc, 20); assert(ret == 0); func = "getcids"; break; } case 3: case 4: { ret = obj_insert(osd->dbc, 20, 0, 2); assert(ret == 0); ret = obj_insert(osd->dbc, 10, 0, 2); assert(ret == 0); ret = obj_get_all_pids(osd->dbc, 0, sizeof(*ids)*2, cp, &usedlen, &addlen, &contid); assert(ret == 0); assert(get_ntohll(cp) == 20 || get_ntohll(cp) == 10); assert(get_ntohll(cp+8) == 20 || get_ntohll(cp+8) == 10); assert(usedlen == 2*sizeof(*ids)); assert(addlen == usedlen); assert(contid == 0); ids[0] = ids[1] = 0; ret = obj_delete_pid(osd->dbc, 20); assert(ret == 0); ret = obj_delete_pid(osd->dbc, 10); assert(ret == 0); if (test == 3) func = "getpids"; else func = "getfullpids"; break; } default: fprintf(stderr, "1 <= test <= 4\n"); exit(1); } for (i = 0; i < numiter; i++) { switch (test) { case 1: case 2: { for (j = 0; j < numobj; j++) { if (test == 1) { ret = obj_insert(osd->dbc, 1, j, USEROBJECT); } else { ret = obj_insert(osd->dbc, 1, j, COLLECTION); } assert(ret == 0); } cp = (uint8_t *)ids; usedlen = addlen = contid = 0; if (test == 1) { rdtsc(start); ret = obj_get_oids_in_pid(osd->dbc, 1, 0, numobj*sizeof(*ids), cp, &usedlen, &addlen, &contid); rdtsc(end); } else { rdtsc(start); ret = obj_get_cids_in_pid(osd->dbc, 1, 0, numobj*sizeof(*ids), cp, &usedlen, &addlen, &contid); rdtsc(end); } assert(usedlen == numobj * sizeof(*ids)); assert(addlen == usedlen); assert(contid == 0); ret = obj_delete_pid(osd->dbc, 1); assert(ret == 0); break; } case 3: for (j = 0; j < numobj; j++) { ret = obj_insert(osd->dbc, j+1, 0, PARTITION); assert(ret == 0); } cp = (uint8_t *)ids; usedlen = addlen = contid = 0; rdtsc(start); ret = obj_get_all_pids(osd->dbc, 0, sizeof(*ids)*numobj, cp, &usedlen, &addlen, &contid); rdtsc(end); assert(ret == 0); assert(usedlen == numobj*sizeof(*ids)); assert(addlen == usedlen); assert(contid == 0); for (j = 0; j < numobj; j++) { ret = obj_delete_pid(osd->dbc, j+1); assert(ret == 0); } case 4: { numpid = numobj/32; if (numobj % 32 != 0) numpid++; for (j = 0; j < numpid; j++) { ret = obj_insert(osd->dbc, j+1, 0, PARTITION); assert(ret == 0); for (k = 1; k < 32+1; k++) { ret = obj_insert(osd->dbc, j+1, k, USEROBJECT); assert(ret == 0); } } cp = (uint8_t *)ids; usedlen = addlen = contid = 0; rdtsc(start); ret = obj_get_all_pids(osd->dbc, 0, sizeof(*ids)*numobj, cp, &usedlen, &addlen, &contid); rdtsc(end); assert(ret == 0); assert(usedlen == numpid*sizeof(*ids)); assert(addlen == usedlen); assert(contid == 0); for (j = 0; j < numpid; j++) { ret = obj_delete_pid(osd->dbc, j+1); assert(ret == 0); } numpid = 0; break; } default: fprintf(stderr, "1 <= test <= 4\n"); exit(1); } t[i] = (double) (end - start) / mhz; start = end = 0; } mu = mean(t, numiter); sd = stddev(t, mu, numiter); printf("%s numiter %d numobj %d test, %d avg %lf +- %lf us\n", func, numiter, numobj, test, mu, sd); free(t); free(ids); }
static uint64_t obj_create_any(int fd, uint64_t pid) { struct osd_command command; struct attribute_list attr = { .type = ATTR_GET, .page = CUR_CMD_ATTR_PG, .number = CCAP_OID, .len = 8, }; int ret; uint64_t oid; osd_command_set_create(&command, pid, 0, 0); osd_command_attr_build(&command, &attr, 1); ret = osd_submit_and_wait(fd, &command); if (ret) { osd_error_xerrno(ret, "%s: submit_and_wait failed", __func__); exit(1); } ret = osd_command_attr_resolve(&command); if (ret) { osd_error_xerrno(ret, "%s: attr_resolve failed", __func__); exit(1); } oid = get_ntohll(command.attr[0].val); osd_command_attr_free(&command); return oid; } static void obj_remove(int fd, uint64_t pid, uint64_t oid) { struct osd_command command; int ret; osd_command_set_remove(&command, pid, oid); ret = osd_submit_and_wait(fd, &command); if (ret) { osd_error_xerrno(ret, "%s: submit_and_wait failed", __func__); exit(1); } } static void read_bw(int fd, uint64_t pid, uint64_t oid, size_t sz, int iters, int dosync) { int i = 0; int ret = 0; uint64_t start, end, delta, total_start, total_stop; double mhz = get_mhz(); double time = 0.0; double max_time = 0.0; double min_time = 0.0; double *b = NULL; void *buf = NULL; size_t total_size; buf = malloc(sz); b = malloc(iters * sizeof(*b)); if (!buf || !b) osd_error_fatal("out of memory"); /* warm up */ if (iters > 5) for (i=0; i<5; i++) { ret = read_osd(fd, pid, oid, buf, sz, 0); assert(ret == 0); } memset(buf, '\0', sz); MPI_Barrier(MPI_COMM_WORLD); rdtsc(total_start); for (i=0; i< iters; i++) { if (dosync) { rdtsc(start); ret = read_osd(fd, pid, oid, buf, sz, 0); rdtsc(end); assert(ret == 0); delta = end - start; rdtsc(start); ret = flush_object(fd, pid, oid, 2); rdtsc(end); assert(ret == 0); delta += (end - start); } else { rdtsc(start); ret = read_osd(fd, pid, oid, buf, sz, 0); rdtsc(end); assert(ret == 0); delta = end - start; } time = ((double)delta)/mhz; /* time in usec */ b[i] = sz/time; /* BW in MegaBytes/sec */ } MPI_Barrier(MPI_COMM_WORLD); /*everyone is done reading*/ rdtsc(total_stop); unsigned int j; for (j=0; j<sz; j++) { char *c = (char *)buf + j; if (*c != 'D') { printf("[%d] ERROR READING BUFF (%c)\n", rank, *c); } } #if 1 delta = total_stop - total_start; time = ((double)delta)/mhz; /*time in usec*/ ret = MPI_Reduce(&time, &max_time, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); if (ret != MPI_SUCCESS) { printf("MPI ERROR\n"); } ret = MPI_Reduce(&time, &min_time, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); if (ret != MPI_SUCCESS) { printf("MPI ERROR\n"); } if (rank == 0) { total_size = sz * iters * numproc; /*total bytes moved*/ printf("read %3d %3lu %7.3lf --- Discrep %.0f is %.1f%%\n", numproc, sz>>10, total_size/max_time, max_time - min_time, 100. * (max_time - min_time) / max_time); }
void test_create(struct osd_device *osd) { int ret = 0; struct osd_command cmd; int senselen_out; uint8_t sense_out[OSD_MAX_SENSE]; uint8_t *data_out = NULL; const void *data_in; uint64_t data_out_len, data_in_len; uint8_t *cp = NULL; uint8_t pad = 0; uint32_t len = 0; /* create partition + empty getpage_setlist */ ret = osd_command_set_create_partition(&cmd, PARTITION_PID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 1 object */ ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* remove the object */ ret = osd_command_set_remove(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); struct attribute_list attr = { ATTR_GET_PAGE, CUR_CMD_ATTR_PG, 0, NULL, CCAP_TOTAL_LEN, 0 }; /* create 5 objects & get ccap */ ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, 0, 5); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(get_ntohl(&data_out[0]) == CUR_CMD_ATTR_PG); assert(get_ntohl(&data_out[4]) == CCAP_TOTAL_LEN - 8); assert(data_out[CCAP_OBJT_OFF] == USEROBJECT); assert(get_ntohll(&data_out[CCAP_PID_OFF]) == USEROBJECT_PID_LB); assert(get_ntohll(&data_out[CCAP_APPADDR_OFF]) == 0); uint64_t i = get_ntohll(&data_out[CCAP_OID_OFF]); assert (i == (USEROBJECT_PID_LB + 5 - 1)); free(data_out); data_out = NULL; data_out_len = 0; i -= (5-1); /* remove 5 objects */ for (;i < USEROBJECT_OID_LB + 5; i++) { ret = osd_command_set_remove(&cmd, USEROBJECT_PID_LB, i); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } /* create 5 objects, set 2 attr on each */ char str1[MAXNAMELEN], str2[MAXNAMELEN]; sprintf(str1, "Madhuri Dixit Rocks!!"); sprintf(str2, "A ciggarate a day, kills a moron anyway."); struct attribute_list setattr[] = { {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 111, str1, strlen(str1)+1, 0 }, {ATTR_SET, USEROBJECT_PG+LUN_PG_LB+1, 321, str2, strlen(str2)+1, 0 } }; ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, 0, 5); assert(ret == 0); ret = osd_command_attr_build(&cmd, setattr, 2); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* remove 5 objects and get previously set attributes for each */ struct attribute_list getattr[] = { {ATTR_GET, USEROBJECT_PG+LUN_PG_LB+1, 321, NULL, strlen(str2), 0 }, {ATTR_GET, USEROBJECT_PG+LUN_PG_LB, 111, NULL, strlen(str1), 0 } }; for (i = USEROBJECT_OID_LB; i < (USEROBJECT_OID_LB + 5); i++) { ret = osd_command_set_remove(&cmd, USEROBJECT_PID_LB, i); assert(ret == 0); ret = osd_command_attr_build(&cmd, getattr, 2); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out[0] == RTRVD_SET_ATTR_LIST); len = get_ntohl(&data_out[4]); assert(len > 0); cp = &data_out[8]; assert(get_ntohl(&cp[LE_PAGE_OFF]) == USEROBJECT_PG+LUN_PG_LB+1); assert(get_ntohl(&cp[LE_NUMBER_OFF]) == 321); len = get_ntohs(&cp[LE_LEN_OFF]); assert((uint32_t)len == (strlen(str2)+1)); assert(memcmp(&cp[LE_VAL_OFF], str2, len) == 0); cp += len + LE_VAL_OFF; pad = (0x8 - ((uintptr_t)cp & 0x7)) & 0x7; while (pad--) assert(*cp == 0), cp++; assert(get_ntohl(&cp[LE_PAGE_OFF]) == USEROBJECT_PG+LUN_PG_LB); assert(get_ntohl(&cp[LE_NUMBER_OFF]) == 111); len = get_ntohs(&cp[LE_LEN_OFF]); assert((uint32_t)len == (strlen(str1)+1)); assert(memcmp(&cp[LE_VAL_OFF], str1, len) == 0); cp += len + LE_VAL_OFF; pad = (0x8 - ((uintptr_t)cp & 0x7)) & 0x7; while (pad--) assert(*cp == 0), cp++; } free(data_out); data_out = NULL; data_out_len = 0; /* get all attributes in a page for an object */ ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 1); assert(ret == 0); setattr[0].page = USEROBJECT_PG+LUN_PG_LB+11; setattr[1].page = USEROBJECT_PG+LUN_PG_LB+11; ret = osd_command_attr_build(&cmd, setattr, 2); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); struct attribute_list getallattr[] = { { ATTR_GET, USEROBJECT_PG+LUN_PG_LB+11, ATTRNUM_GETALL, NULL, 1024, 0, }, }; ret = osd_command_set_get_attributes(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); ret = osd_command_attr_build(&cmd, getallattr, 1); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out[0] == RTRVD_SET_ATTR_LIST); len = get_ntohl(&data_out[4]); assert(len > 0); cp = &data_out[8]; assert(get_ntohl(&cp[LE_PAGE_OFF]) == USEROBJECT_PG+LUN_PG_LB+11); assert(get_ntohl(&cp[LE_NUMBER_OFF]) == 111); len = get_ntohs(&cp[LE_LEN_OFF]); assert((uint32_t)len == (strlen(str1)+1)); assert(memcmp(&cp[LE_VAL_OFF], str1, len) == 0); cp += len + LE_VAL_OFF; pad = (0x8 - ((uintptr_t)cp & 0x7)) & 0x7; while (pad--) assert(*cp == 0), cp++; assert(get_ntohl(&cp[LE_PAGE_OFF]) == USEROBJECT_PG+LUN_PG_LB+11); assert(get_ntohl(&cp[LE_NUMBER_OFF]) == 321); len = get_ntohs(&cp[LE_LEN_OFF]); assert((uint32_t)len == (strlen(str2)+1)); assert(memcmp(&cp[LE_VAL_OFF], str2, len) == 0); cp += len + LE_VAL_OFF; pad = (0x8 - ((uintptr_t)cp & 0x7)) & 0x7; while (pad--) assert(*cp == 0), cp++; free(data_out); data_out = NULL; data_out_len = 0; ret = osd_command_set_remove(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* remove partition */ ret = osd_command_set_remove_partition(&cmd, PARTITION_PID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); free(cmd.attr_malloc); }
/* only to be used by test_set_one_attr */ static void set_one_attr_int(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, uint64_t val) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; uint64_t attrval; int ret; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = 8, .val = &attrval, }; set_htonll(&attrval, val); ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } static void set_one_attr_val(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, const void *val, uint16_t len) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; int ret,i; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = len, .val = (void *)(uintptr_t) val, }; ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); /* output cdbfmt , length , value */ printf("cdbfmt is: %x \n", cmd.cdb[11]); printf("length is: %x \n", cmd.cdb[61]); printf("value is: "); for(i=0; i<=len; i++){ printf("%c", cmd.cdb[62+i]); } printf("\n"); } static void test_set_one_attr (struct osd_device *osd) { struct osd_command cmd; uint64_t pid = USEROBJECT_PID_LB; uint64_t oid = USEROBJECT_OID_LB; uint8_t *data_out = NULL; uint64_t data_out_len; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int ret; uint32_t page = USEROBJECT_PG + LUN_PG_LB; /* create a partition*/ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* creat one object */ ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* these cases should not generate error */ set_one_attr_val(osd, pid, oid, page, 1, "test", 5); set_one_attr_val(osd, pid, oid, page, 1, "test_set_one_attr", 18); set_one_attr_int(osd, pid, oid, page, 1, 10); set_one_attr_int(osd, pid, oid, page, 1, 20); /* these cases must generate error */ /* set_one_attr_val(osd, pid, oid, page, 1, "ttest_set_one_attr", 19); */ /* set_one_attr_val(osd, pid, oid, page, 1, "", 0); */ } /* only to be used by test_osd_query */ static void set_attr_int(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, uint64_t val) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; uint64_t attrval; int ret; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = 8, .val = &attrval, }; set_htonll(&attrval, val); ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } static void set_attr_val(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, const void *val, uint16_t len) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; int ret; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = len, .val = (void *)(uintptr_t) val, }; ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } static void set_qce(uint8_t *cp, uint32_t page, uint32_t number, uint16_t min_len, const void *min_val, uint16_t max_len, const void *max_val) { uint16_t len = 4 + 4 + 2 + min_len + 2 + max_len; set_htons(&cp[2], len); set_htonl(&cp[4], page); set_htonl(&cp[8], number); set_htons(&cp[12], min_len); memcpy(&cp[14], min_val, min_len); set_htons(&cp[14+min_len], max_len); memcpy(&cp[16+min_len], max_val, max_len); } static int ismember(uint64_t needle, uint64_t *hay, uint64_t haysz) { while (haysz--) if (needle == hay[haysz]) return 1; return 0; } static void check_results(uint8_t *matches, uint64_t matchlen, uint64_t *idlist, uint64_t idlistlen) { uint32_t add_len = get_ntohll(&matches[0]); assert(add_len == (5+8*idlistlen)); assert(matches[12] == (0x21 << 2)); assert(matchlen == add_len+8); add_len -= 5; matches += MIN_ML_LEN; while (add_len) { assert(ismember(get_ntohll(matches), idlist, 8)); matches += 8; add_len -= 8; } } void test_query(struct osd_device *osd) { struct osd_command cmd; uint64_t pid = PARTITION_PID_LB; uint64_t cid = COLLECTION_OID_LB; uint64_t oid = USEROBJECT_OID_LB + 1; /* leave room for cid */ uint8_t *data_out = NULL; uint64_t data_out_len; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int i, ret; /* create a collection and stick some objects in it */ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* but don't put all of the objects in the collection */ for (i=0; i<10; i++) { uint64_t attrval; struct attribute_list attr = { .type = ATTR_SET, .page = USER_COLL_PG, .number = 1, .len = 8, .val = &attrval, }; set_htonll(&attrval, cid); ret = osd_command_set_create(&cmd, pid, oid + i, 1); assert(ret == 0); if (!(i == 2 || i == 8)) { ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); } ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } /* * Set some random attributes for querying. */ uint32_t page = USEROBJECT_PG + LUN_PG_LB; set_attr_int(osd, pid, oid, page, 1, 4); set_attr_int(osd, pid, oid+1, page, 1, 49); set_attr_int(osd, pid, oid+1, page, 2, 130); set_attr_int(osd, pid, oid+2, page, 1, 20); set_attr_int(osd, pid, oid+3, page, 1, 101); set_attr_int(osd, pid, oid+4, page, 1, 59); set_attr_int(osd, pid, oid+4, page, 2, 37); set_attr_int(osd, pid, oid+5, page, 1, 75); set_attr_int(osd, pid, oid+6, page, 1, 200); set_attr_int(osd, pid, oid+7, page, 1, 67); set_attr_int(osd, pid, oid+8, page, 1, 323); set_attr_int(osd, pid, oid+8, page, 2, 44); set_attr_int(osd, pid, oid+9, page, 1, 1); set_attr_int(osd, pid, oid+9, page, 2, 19); /* * Various queries. */ /* run without query criteria */ uint8_t buf[1024], *cp, *matches; uint32_t qll; uint64_t matchlen; uint64_t idlist[8]; qll = MINQLISTLEN; memset(buf, 0, 1024); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid; idlist[1] = oid+1; idlist[2] = oid+3; idlist[3] = oid+4; idlist[4] = oid+5; idlist[5] = oid+6; idlist[6] = oid+7; idlist[7] = oid+9; check_results(matches, matchlen, idlist, 8); free(matches); matches = NULL; matchlen = 0; /* run one query without min/max constraints */ qll = 0; memset(buf, 0, 1024); cp = buf; set_qce(&cp[4], page, 2, 0, NULL, 0, NULL); qll += 4 + (4+4+4+2+2); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; idlist[1] = oid+4; idlist[2] = oid+9; check_results(matches, matchlen, idlist, 3); free(matches); matches = NULL; matchlen = 0; /* run one query with criteria */ uint64_t min, max; qll = 0; min = 40, max= 80; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; idlist[1] = oid+4; idlist[2] = oid+5; idlist[3] = oid+7; check_results(matches, matchlen, idlist, 4); free(matches); matches = NULL; matchlen = 0; /* run union of two query criteria */ qll = 0; /* first query */ min = 100, max = 180; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; /* UNION */ set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ min = 200, max = 323; set_htonll(&min, min); set_htonll(&max, max); set_qce(cp, page, 1, sizeof(min), &min, sizeof(max), &max); qll += (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+3; idlist[1] = oid+6; check_results(matches, matchlen, idlist, 2); free(matches); matches = NULL; matchlen = 0; /* run intersection of 2 query criteria */ qll = 0; /* first query */ min = 4, max = 100; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x1; /* INTERSECTION */ set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ min = 10, max = 400; set_htonll(&min, min); set_htonll(&max, max); set_qce(cp, page, 2, sizeof(min), &min, sizeof(max), &max); qll += (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; idlist[1] = oid+4; check_results(matches, matchlen, idlist, 2); free(matches); matches = NULL; matchlen = 0; /* run union of 3 query criteria, with missing min/max */ qll = 0; /* first query */ min = 130, max = 130; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; /* UNION */ set_qce(&cp[4], page, 2, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ min = 150; set_htonll(&min, min); set_qce(cp, page, 1, sizeof(min), &min, 0, NULL); qll += (4+4+4+2+sizeof(min)+2+0); cp += (4+4+4+2+sizeof(min)+2+0); /* third query */ max = 10; set_htonll(&max, max); set_qce(cp, page, 1, 0, NULL, sizeof(max), &max); qll += (4+4+4+2+0+2+sizeof(max)); cp += (4+4+4+2+0+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[3] = oid; idlist[4] = oid+1; idlist[5] = oid+6; idlist[2] = oid+9; check_results(matches, matchlen, idlist, 4); free(matches); matches = NULL; matchlen = 0; /* set some attributes with text values */ set_attr_val(osd, pid, oid, page, 1, "hello", 6); set_attr_val(osd, pid, oid+1, page, 1, "cat", 4); set_attr_int(osd, pid, oid+1, page, 2, 130); set_attr_int(osd, pid, oid+2, page, 1, 20); set_attr_val(osd, pid, oid+3, page, 1, "zebra", 6); set_attr_int(osd, pid, oid+4, page, 1, 59); set_attr_int(osd, pid, oid+4, page, 2, 37); set_attr_int(osd, pid, oid+5, page, 1, 75); set_attr_val(osd, pid, oid+6, page, 1, "keema", 6); set_attr_int(osd, pid, oid+7, page, 1, 67); set_attr_int(osd, pid, oid+8, page, 1, 323); set_attr_int(osd, pid, oid+8, page, 2, 44); set_attr_int(osd, pid, oid+9, page, 1, 1); set_attr_val(osd, pid, oid+9, page, 2, "hotelling", 10); /* run queries on different datatypes, with diff min max lengths */ qll = 0; /* first query */ min = 41, max = 169; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; /* UNION */ set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ set_qce(cp, page, 1, 3, "ab", 5, "keta"); qll += (4+4+4+2+2+2+5); cp += (4+4+4+2+2+2+5); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[3] = oid; idlist[4] = oid+1; idlist[0] = oid+4; idlist[1] = oid+5; idlist[5] = oid+6; idlist[2] = oid+7; check_results(matches, matchlen, idlist, 6); free(matches); matches = NULL; matchlen = 0; /* run intersection of 3 query criteria, with missing min/max */ qll = 0; /* first query */ memset(buf, 0, 1024); cp = buf; cp[0] = 0x1; /* INTERSECTION */ set_qce(&cp[4], page, 1, 2, "a", 3, "zz"); qll += 4 + (4+4+4+2+2+2+3); cp += 4 + (4+4+4+2+2+2+3); /* second query */ min = 140; set_htonll(&min, min); set_qce(cp, page, 1, sizeof(min), &min, 0, NULL); qll += (4+4+4+2+sizeof(min)+2+0); cp += (4+4+4+2+sizeof(min)+2+0); /* third query */ set_qce(cp, page, 2, 0, NULL, 6, "alpha"); qll += (4+4+4+2+0+2+6); cp += (4+4+4+2+0+2+6); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; check_results(matches, matchlen, idlist, 1); free(matches); matches = NULL; matchlen = 0; /* run intersection of 2 query criteria with empty result */ qll = 0; /* first query */ memset(buf, 0, 1024); cp = buf; cp[0] = 0x1; /* INTERSECTION */ set_qce(&cp[4], page, 1, 3, "aa", 4, "zzz"); qll += 4 + (4+4+4+2+3+2+4); cp += 4 + (4+4+4+2+3+2+4); /* second query */ min = 50; max = 80; set_htonll(&min, min); set_htonll(&max, max); set_qce(cp, page, 1, sizeof(min), &min, sizeof(max), &max); qll += (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); check_results(matches, matchlen, idlist, 0); free(matches); matches = NULL; matchlen = 0; /* * Cleanup. */ for (i=0; i<10; i++) { ret = osd_command_set_remove(&cmd, pid, oid + i); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); ret = osd_command_set_remove_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } struct test_attr { uint8_t type; uint64_t oid; uint32_t page; uint32_t number; uint64_t intval; uint16_t valen; const void *val; }; static void ismember_attr(struct test_attr *attr, size_t sz, uint64_t oid, uint32_t page, uint32_t number, uint64_t valen, const void *val) { size_t i = 0; for (i = 0; i < sz; i++) { if (attr[i].oid == oid && attr[i].page == page && attr[i].number == number) { assert(valen <= attr[i].valen); if (attr[i].type == 1) { if (valen == attr[i].valen) assert(attr[i].intval == get_ntohll(val)); } else { assert(memcmp(attr[i].val, val, valen) == 0); } return; } } fprintf(stderr, "unknown attr: oid: %llu, page %u, number %u\n", llu(oid), page, number); assert(0); /* unknown attr */ } static void test_oids_with_attr(struct osd_device *osd, uint64_t pid, struct attribute_list *getattr, int numattr, uint64_t alloc_len, uint64_t exp_data_out_len, uint64_t exp_add_len, uint64_t exp_cont_id, uint8_t exp_odf, struct test_attr *attrs, size_t attrs_sz) { int ret = 0; struct osd_command cmd; uint8_t *cp = NULL; uint32_t page = 0, number = 0; uint64_t data_in_len, data_out_len; const void *data_in; uint8_t *data_out = NULL; uint64_t oid = 0; uint8_t sense_out[OSD_MAX_SENSE]; uint16_t len = 0; int senselen_out; uint32_t attr_list_len = 0; /* execute list with attr, alloc length less than required */ ret = osd_command_set_list(&cmd, pid, 0, alloc_len, 0, 1); assert(ret == 0); ret = osd_command_attr_build(&cmd, getattr, numattr); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cp = data_out; assert(data_out_len == exp_data_out_len); assert(get_ntohll(cp) == exp_add_len); cp += 8; assert(get_ntohll(cp) == exp_cont_id); cp += 8; assert(get_ntohl(cp) == 0); cp += 7; assert(cp[0] == exp_odf); cp += 1; oid = 0; attr_list_len = 0; len = 0; data_out_len -= 24; while (data_out_len > 0) { oid = get_ntohll(cp); cp += 12; attr_list_len = get_ntohl(cp); cp += 4; data_out_len -= 16; while (attr_list_len > 0) { page = get_ntohl(cp); cp += 4; number = get_ntohl(cp); cp += 4; len = get_ntohs(cp); cp += 2; attr_list_len -= (4+4+2); data_out_len -= (4+4+2); if (len > attr_list_len) { len = attr_list_len; } ismember_attr(attrs, attrs_sz, oid, page, number, len, cp); cp += len; cp += (roundup8(2+len) - (2+len)); data_out_len -= len; data_out_len -= (roundup8(2+len) - (2+len)); attr_list_len -= len; attr_list_len -= (roundup8(2+len) - (2+len)); } } free(data_out); data_out = NULL; osd_command_attr_free(&cmd); } void test_list(struct osd_device *osd) { struct osd_command cmd; uint64_t pid = PARTITION_PID_LB; uint64_t cid = 0; uint64_t oid = 0; uint8_t *data_out = NULL; uint8_t *cp; uint32_t page = 0, number = 0; uint64_t data_out_len; uint64_t idlist[64]; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int i, ret; /* create partition */ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create collection */ ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 6 objects */ ret = osd_command_set_create(&cmd, pid, 0, 6); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create another collection */ ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 4 objects */ ret = osd_command_set_create(&cmd, pid, 0, 4); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* set attributes on userobjects */ page = USEROBJECT_PG + LUN_PG_LB; number = 1; oid = COLLECTION_OID_LB + 1; struct test_attr attrs[] = { {1, oid, page, number, 1, 8, NULL}, {1, oid, page+1, number+1, 768, 8, NULL}, {2, oid, page+2, number+2, 0, 5, "sudo"}, {1, oid+1, page+1, number+1, 56, 8, NULL}, {1, oid+1, page+2, number+2, 68, 8, NULL}, {2, oid+2, page+2, number+2, 0, 9, "deadbeef"}, {1, oid+3, page+3, number+3, 1, 8, NULL}, {1, oid+3, page+1, number+1, 111, 8, NULL}, {2, oid+3, page+4, number+4, 0, 5, "sudo"}, {1, oid+3, page+2, number+2, 11, 8, NULL}, {1, oid+3, page+5, number+5, 111111, 8, NULL}, {2, oid+4, page+4, number+4, 0, 6, "milli"}, {2, oid+4, page+5, number+5, 0, 10, "kilometer"}, {2, oid+4, page+3, number+3, 0, 11, "hectameter"}, {2, oid+5, page+1, number+1, 0, 12, "zzzzzzhhhhh"}, {2, oid+5, page+2, number+2, 0, 2, "b"}, {1, oid+5, page+3, number+3, 6, 8, NULL}, {1, oid+7, page+1, number+1, 486, 8, NULL}, {1, oid+7, page+4, number+4, 586, 8, NULL}, {1, oid+7, page+2, number+2, 686, 8, NULL}, {1, oid+8, page, number, 4, 8, NULL}, {2, oid+9, page+1, number+1, 0, 14, "setting these"}, {2, oid+9, page+2, number+2, 0, 11, "attributes"}, {2, oid+9, page+3, number+3, 0, 8, "made me"}, {2, oid+9, page+4, number+4, 0, 12, "mad! really"}, {1, oid+10, page+1, number+1, 1234567890, 8, NULL}, {2, oid+10, page, number, 0, 6, "DelTa"}, }; for (i = 0; i < ARRAY_SIZE(attrs); i++) { if (attrs[i].type == 1) { set_attr_int(osd, pid, attrs[i].oid, attrs[i].page, attrs[i].number, attrs[i].intval); } else { set_attr_val(osd, pid, attrs[i].oid, attrs[i].page, attrs[i].number, attrs[i].val, attrs[i].valen); } } /* set some attributes on collections */ page = COLLECTION_PG + LUN_PG_LB; cid = COLLECTION_OID_LB; set_attr_int(osd, pid, cid, page, 1, 1); set_attr_int(osd, pid, cid+7, page, 2, 2); /* execute list command. get only oids first */ ret = osd_command_set_list(&cmd, pid, 0, 4096, 0, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cp = data_out; assert(get_ntohll(cp) == 10*8+16); assert(data_out_len == 10*8+24); cp += 8; assert(get_ntohll(cp) == 0); cp += 8; assert(get_ntohl(cp) == 0); cp += 7; assert(cp[0] == (0x21 << 2)); cp += 1; data_out_len -= 24; oid = COLLECTION_OID_LB + 1; for (i = 0; i < 6; i++) idlist[i] = oid + i; oid = COLLECTION_OID_LB + 1 + i + 1; for (i = 0; i < 4; i++) idlist[6+i] = oid + i; while (data_out_len > 0) { assert(ismember(get_ntohll(cp), idlist, 10)); cp += 8; data_out_len -= 8; } free(data_out); data_out = NULL; osd_command_attr_free(&cmd); /* execute list command with less space */ ret = osd_command_set_list(&cmd, pid, 0, 72, 0, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cp = data_out; assert(get_ntohll(cp) == 10*8+16); assert(data_out_len == 72); cp += 8; assert(get_ntohll(cp) == COLLECTION_OID_LB + 8); cp += 8; assert(get_ntohl(cp) == 0); cp += 7; assert(cp[0] == (0x21 << 2)); cp += 1; data_out_len -= 24; oid = COLLECTION_OID_LB + 1; for (i = 0; i < 6; i++) idlist[i] = oid + i; for (i = 0; i < 4; i++) idlist[6+i] = 0; while (data_out_len > 0) { assert(ismember(get_ntohll(cp), idlist, 10)); cp += 8; data_out_len -= 8; } free(data_out); data_out = NULL; osd_command_attr_free(&cmd); page = USEROBJECT_PG + LUN_PG_LB; number = 1; struct attribute_list getattr[] = { {ATTR_GET, page, number, NULL, 0, 0}, {ATTR_GET, page+1, number+1, NULL, 0, 0}, {ATTR_GET, page+2, number+2, NULL, 0, 0}, {ATTR_GET, page+3, number+3, NULL, 0, 0}, {ATTR_GET, page+4, number+4, NULL, 0, 0}, {ATTR_GET, page+5, number+5, NULL, 0, 0}, }; /* execute list with attr */ test_oids_with_attr(osd, pid, getattr, 6, 4096, 792, 784, 0, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 200, 200, 784, 65539, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 208, 208, 784, 65539, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 216, 208, 784, 65539, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 544, 536, 784, 65544, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 688, 688, 784, 65546, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 680, 680, 784, 65546, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* clean up */ oid = USEROBJECT_OID_LB; for (i=0; i<12; i++) { if (i == 0 || i == 7) continue; ret = osd_command_set_remove(&cmd, pid, oid + i); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } cid = COLLECTION_OID_LB; ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cid = COLLECTION_OID_LB + 7; ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); ret = osd_command_set_remove_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } static void test_attr_vals(uint8_t *cp, struct attribute_list *attrs, size_t sz) { size_t i = 0; uint32_t page = 0; uint32_t num = 0; uint16_t len = 0; uint32_t list_len = 0; assert((cp[0] & 0x0F) == 0x9); cp += 4; list_len = get_ntohl(cp); cp += 4; while (list_len > 0) { page = get_ntohl(cp); cp += 4; num = get_ntohl(cp); cp += 4; len = get_ntohs(cp); cp += 2; for (i = 0; i < sz; i++) { if (!(attrs[i].page==page && attrs[i].number==num)) continue; assert(len == attrs[i].len); if (len == 8) { assert(get_ntohll(attrs[i].val) == get_ntohll(cp)); } else if (len != 0) { assert(memcmp(attrs[i].val, cp, len) == 0); } break; } assert(i < sz); if (len == 0) { cp += (roundup8(10) - 10); list_len -= roundup8(4+4+2); } else { cp += len; cp += (roundup8(2+len) - (2+len)); list_len -= roundup8(4+4+2+len); } } assert(list_len == 0); }
void test_set_member_attributes(struct osd_device *osd) { struct osd_command cmd; uint64_t pid = PARTITION_PID_LB; uint64_t cid = COLLECTION_OID_LB; uint64_t oid = 0; uint8_t *data_out = NULL; uint32_t page = 0; const void *data_in; uint64_t data_out_len, data_in_len; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int i, ret; data_out = NULL; data_out_len = 0; /* create partition */ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create collection */ ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 100 objects */ ret = osd_command_set_create(&cmd, pid, 0, 100); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(osd->ccap.oid == (USEROBJECT_OID_LB + 100)); /* put odd objects into the collection */ oid = USEROBJECT_OID_LB + 1; for (i = 0; i < 100; i += 2) { uint64_t attrval; struct attribute_list attr = { .type = ATTR_SET, .page = USER_COLL_PG, .number = 1, .len = sizeof(attrval), .val = &attrval, }; set_htonll(&attrval, cid); ret = osd_command_set_set_attributes(&cmd, pid, oid + i); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } /* set attr on collection members */ uint64_t val1 = 123454321, val2 = 987654, val3 = 59999999; char str1[MAXNAMELEN], str2[MAXNAMELEN], str3[MAXNAMELEN]; set_htonll(&val1, val1); set_htonll(&val2, val2); set_htonll(&val3, val3); sprintf(str1, "GoMtI"); sprintf(str2, "DeViL"); sprintf(str3, "homeopath"); page = USEROBJECT_PG + LUN_PG_LB; struct attribute_list attrs[] = { {ATTR_SET, page+1, 2, str1, strlen(str1)+1, 0}, {ATTR_SET, page+21, 4, &val1, sizeof(val1), 0}, {ATTR_SET, page+5, 55, &val2, sizeof(val2), 0}, {ATTR_SET, page+666, 66, str2, strlen(str2)+1, 0}, {ATTR_SET, page+10, 10, str3, strlen(str3)+1, 0}, {ATTR_SET, page+2, 3, &val3, sizeof(val3), 0}, }; ret = osd_command_set_set_member_attributes(&cmd, pid, cid); assert(ret == 0); ret = osd_command_attr_build(&cmd, attrs, 6); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); /* randomly select 5 objects, get their attrs and test */ for (i = 0; i < 6; i++) { attrs[i].type = ATTR_GET; } srand(time(0)); for (i = 0; i < 5; i++) { int r = (int)(50.0 * (rand()/(RAND_MAX+1.0))); oid = USEROBJECT_OID_LB + 1 + 2*r; ret = osd_command_set_get_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, attrs, 6); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); test_attr_vals(data_out, attrs, 6); osd_command_attr_free(&cmd); } free(data_out); data_out = NULL; data_out_len = 0; /* clean up */ oid = USEROBJECT_OID_LB + 1; for (i=0; i<100; i++) { ret = osd_command_set_remove(&cmd, pid, oid + i); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } cid = COLLECTION_OID_LB; ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); ret = osd_command_set_remove_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } void test_atomics(struct osd_device *osd) { int ret = 0; struct osd_command cmd; int senselen_out; uint8_t sense_out[OSD_MAX_SENSE]; uint8_t *cp = NULL; uint8_t *data_out = NULL; void *data_in = NULL; uint64_t data_out_len, data_in_len; /* create partition + empty getpage_setlist */ ret = osd_command_set_create_partition(&cmd, PARTITION_PID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 1 object */ ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* cas */ ret = osd_command_set_cas(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 8UL, 0); assert(ret == 0); data_in = Malloc(1024); assert(data_in != NULL); cp = data_in; set_htonll(&cp[0], 0UL); set_htonll(&cp[8], 5UL); data_in_len = 16; data_out = NULL; data_out_len = 0; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(get_ntohll(&data_out[0]) == 0UL); free(data_out); data_out = NULL; data_out_len = 0; ret = osd_command_set_cas(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 8UL, 0); assert(ret == 0); cp = data_in; set_htonll(&cp[0], 5UL); set_htonll(&cp[8], 0UL); data_in_len = 16; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(get_ntohll(&data_out[0]) == 5UL); free(data_out); data_out = NULL; data_out_len = 0; /* fa */ ret = osd_command_set_fa(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 8UL, 0); assert(ret == 0); cp = data_in; set_htonll(&cp[0], 4UL); data_in_len = 8; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(get_ntohll(&data_out[0]) == 0UL); free(data_out); data_out = NULL; data_out_len = 0; ret = osd_command_set_fa(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 8UL, 0); assert(ret == 0); cp = data_in; set_htonll(&cp[0], 16UL); data_in_len = 8; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(get_ntohll(&data_out[0]) == 4UL); free(data_out); data_out = NULL; data_out_len = 0; ret = osd_command_set_fa(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 8UL, 0); assert(ret == 0); cp = data_in; set_htonll(&cp[0], -20L); data_in_len = 8; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(get_ntohll(&data_out[0]) == 20UL); free(data_out); data_out = NULL; data_out_len = 0; ret = osd_command_set_fa(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 8UL, 0); assert(ret == 0); cp = data_in; set_htonll(&cp[0], 1L); data_in_len = 8; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(get_ntohll(&data_out[0]) == 0UL); free(data_out); data_out = NULL; data_out_len = 0; free(data_in); /* gen_cas */ ret = osd_command_set_gen_cas(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); char str1[MAXNAMELEN]; sprintf(str1, "some arbit string"); struct attribute_list attr[] = { {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 1, NULL, 0, 0}, {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 1, str1, strlen(str1)+1, 0 }, {ATTR_RESULT, USEROBJECT_PG+LUN_PG_LB, 1, NULL, 0, 0} }; ret = osd_command_attr_build(&cmd, attr, 3); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); assert(data_out_len == 24); attr[2].len = 0; test_attr_vals(data_out, &attr[2], 1); osd_command_attr_free(&cmd); free(data_out); data_out = NULL; data_out_len = 0; ret = osd_command_set_gen_cas(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); char str2[MAXNAMELEN]; sprintf(str2, "a diff str"); struct attribute_list attr1[] = { {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 1, str1, strlen(str1)+1, 0 }, {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 1, str2, strlen(str2)+1, 0 }, {ATTR_RESULT, USEROBJECT_PG+LUN_PG_LB, 1, str1, strlen(str1)+1, 0 } }; ret = osd_command_attr_build(&cmd, attr1, 3); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); test_attr_vals(data_out, &attr1[2], 1); osd_command_attr_free(&cmd); free(data_out); data_out = NULL; data_out_len = 0; /* cond setattr */ ret = osd_command_set_cond_setattr(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); char str3[MAXNAMELEN]; sprintf(str3, "setattr str"); struct attribute_list attr2[] = { {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 1, str2, strlen(str2)+1, 0 }, /* cmp */ {ATTR_SET, USEROBJECT_PG+LUN_PG_LB, 1, str1, strlen(str1)+1, 0 }, /* swap */ {ATTR_SET, USEROBJECT_PG+LUN_PG_LB+100, 23, str3, strlen(str3)+1, 0 }, {ATTR_RESULT, USEROBJECT_PG+LUN_PG_LB, 1, str2, strlen(str2)+1, 0 } }; ret = osd_command_attr_build(&cmd, attr2, 4); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); test_attr_vals(data_out, &attr2[3], 1); osd_command_attr_free(&cmd); free(data_out); data_out = NULL; data_out_len = 0; attr2[2].type = ATTR_GET; ret = osd_command_set_get_attributes(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr2[2], 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); assert(data_out != NULL); test_attr_vals(data_out, &attr2[2], 1); osd_command_attr_free(&cmd); free(data_out); data_out = NULL; data_out_len = 0; /* clean up */ ret = osd_command_set_remove(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); ret = osd_command_set_remove_partition(&cmd, PARTITION_PID_LB); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); }
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,