/* NOTE: A copy of this code exists in Sparc/memory.s; if you change * anything here, check that code as well. */ int stk_restore_frame( word *globals ) { word *stktop, *hframe, *p; word retoffs, proc, codeaddr, codeptr, header; unsigned size; assert2(globals[ G_STKP ] == globals[ G_STKBOT ]); hframe = ptrof( globals[ G_CONT ] ); size = roundup8( sizefield( *hframe ) + 4 ); /* bytes to copy */ stktop = (word*)globals[ G_STKP ]; stktop -= size / 4; if (stktop < (word*)globals[ G_ETOP ]) { supremely_annoyingmsg( "Failed to create stack." ); return 0; } globals[ G_STKP ] = (word)stktop; globals[ G_STKUFLOW ] += 1; #if 0 annoyingmsg("Restore: %d", size); #endif /* copy the frame onto the stack */ p = stktop; while (size) { *p++ = *hframe++; *p++ = *hframe++; size -= 8; } /* Follow continuation chain. */ globals[ G_CONT ] = *(stktop+STK_DYNLINK); header = *(stktop+HC_HEADER); retoffs = *(stktop+HC_RETOFFSET); proc = *(stktop+HC_PROC); /* convert the header back to a fixnum */ *(stktop+STK_CONTSIZE) = sizefield(header); /* convert the return address */ if (proc != 0) { codeptr = *(ptrof( proc )+PROC_CODEPTR); if (tagof( codeptr ) == BVEC_TAG) { codeaddr = (word)ptrof( codeptr ); *(stktop+STK_RETADDR) = (codeaddr+4)+retoffs; } else { *(stktop+STK_RETADDR) = retoffs; } } else { *(stktop+STK_RETADDR) = retoffs; } return 1; }
static void test_le(uint32_t page, uint32_t num, uint16_t len, const void *val, uint8_t *cp) { uint8_t pad = 0; assert(get_ntohl(cp) == page), cp += 4; assert(get_ntohl(cp) == num), cp += 4; assert(get_ntohs(cp) == len), cp += 2; assert(memcmp(cp, val, len) == 0), cp += len; pad = roundup8(10+len) - (10+len); while (pad--) assert(*cp == 0), cp++; }
int stk_size_for_top_stack_frame( word *globals ) { #if OLD_GC_CODE return nativeint( *(word*)globals[ G_STKP ] )*sizeof( word ) + STACK_BASE_SIZE; #else int frame_size; if (globals[ G_STKP ] == globals[ G_STKBOT]) frame_size = sizefield( *ptrof( globals[ G_CONT ] ) ); else frame_size = *((word*)globals[ G_STKP ] + STK_CONTSIZE); return roundup8( frame_size + 4 ) + STACK_BASE_SIZE; #endif }
static void* visit_measuring_float( word *addr, int tag, void *accum ) { struct visit_measuring_float_data *data = (struct visit_measuring_float_data*)accum; word obj; bool marked; bool marked_via_remsets; int words; struct float_counts *type_counts; obj = tagptr( addr, tag ); marked = msfloat_object_marked_p( data->context, obj ); marked_via_remsets = msfloat_object_marked_p( data->context_incl_remsets, obj ); data->objs.total += 1 ; if (!marked && !marked_via_remsets) { data->objs.zzflt += 1; } if (!marked && marked_via_remsets) { data->objs.rsflt += 1; } switch (tag) { case PAIR_TAG: words = 2; break; case VEC_TAG: case BVEC_TAG: case PROC_TAG: words = roundup8( sizefield( *addr )+4 ) / 4; break; default: assert(0); } data->words.total += words; if (!marked && !marked_via_remsets) data->words.zzflt += words; if (!marked && marked_via_remsets) data->words.rsflt += words; return data; }
void stk_flush( word *globals ) { word *stktop, *stkbot, *first, *prev; word retaddr, codeaddr, codeptr, proc, size; unsigned framecount; assert2( tagof( globals[ G_REG0 ]) == PROC_TAG ); stktop = (word*)globals[ G_STKP ]; stkbot = (word*)globals[ G_STKBOT ]; stack_state.words_flushed += (stkbot-stktop); first = prev = 0; framecount = 0; while (stktop < stkbot) { size = *(stktop+STK_CONTSIZE); retaddr = *(stktop+STK_RETADDR); /* convert header to vector header */ assert2( size % 4 == 0 ); /* size must be words, a fixnum */ assert2( (s_word)size >= 12 ); /* 3-word minimum, and nonnegative */ *(stktop+HC_HEADER) = mkheader( size, VEC_HDR ); /* convert return address */ proc = *(stktop+STK_REG0); if (proc != 0) { assert2( tagof( proc ) == PROC_TAG ); codeptr = *(ptrof( proc )+PROC_CODEPTR); if (tagof( codeptr ) == BVEC_TAG) { codeaddr = (word)ptrof( codeptr ); *(stktop+HC_RETOFFSET) = retaddr-(codeaddr+4); } else { *(stktop+HC_RETOFFSET) = retaddr; } } else { *(stktop+HC_RETOFFSET) = retaddr; } /* chain things together */ if (first == 0) first = stktop; else *(prev+HC_DYNLINK) = (word)tagptr( stktop, VEC_TAG ); prev = stktop; framecount++; size = roundup8( size+4 ); stktop += size / 4; #if 0 annoyingmsg("Flush: %d", size ); #endif } if (prev != 0) *(prev+HC_DYNLINK) = globals[ G_CONT ]; if (first != 0) globals[ G_CONT ] = (word)tagptr( first, VEC_TAG ); globals[ G_STKBOT ] = globals[ G_STKP ]; stack_state.frames_flushed += framecount; }
/* * returns list of objects along with requested attributes * * return values: * -EINVAL: invalid argument * -EIO: prepare or some other sqlite function failed * OSD_ERROR: some other error * OSD_OK: success */ int mtq_list_oids_attr(struct db_context *dbc, uint64_t pid, uint64_t initial_oid, struct getattr_list *get_attr, uint64_t alloc_len, void *outdata, uint64_t *used_outlen, uint64_t *add_len, uint64_t *cont_id) { int ret = 0; char *cp = NULL; char *SQL = NULL; uint32_t i = 0; uint32_t factor = 2; /* this query uses space fast */ uint32_t attr_list_len = 0; /*XXX:SD see below */ uint32_t sqlen = 0; uint64_t oid = 0; uint32_t page; uint32_t number; uint16_t len; const void *val = NULL; sqlite3_stmt *stmt = NULL; uint8_t *head = NULL, *tail = NULL; const char *select_stmt = NULL; const char *obj = obj_getname(dbc); const char *attr = attr_getname(dbc); assert(dbc && dbc->db && get_attr && outdata && used_outlen && add_len && obj && attr); if (get_attr->sz == 0) { ret = -EINVAL; goto out; } SQL = Malloc(MAXSQLEN*factor); if (!SQL) { ret = -ENOMEM; goto out; } /* * For each attribute requested, create a select statement, * which will try to index into the attr table with a full key rather * than just (pid, oid) prefix key. Analogous to loop unrolling, we * unroll each requested attribute into its own select statement. */ select_stmt = "SELECT obj.oid as myoid, attr.page, " " attr.number, attr.value FROM %s as obj, %s as attr " " WHERE obj.pid = attr.pid AND obj.oid = attr.oid AND " " obj.pid = %llu AND obj.type = %u AND " " attr.page = %u AND attr.number = %u AND obj.oid >= %llu "; cp = SQL; sqlen = 0; sprintf(SQL, select_stmt, obj, attr, llu(pid), USEROBJECT, USER_TMSTMP_PG, 0, llu(initial_oid)); SQL = strcat(SQL, " UNION ALL "); sqlen += strlen(SQL); cp += sqlen; for (i = 0; i < get_attr->sz; i++) { sprintf(cp, select_stmt, obj, attr, llu(pid), USEROBJECT, get_attr->le[i].page, get_attr->le[i].number, llu(initial_oid)); if (i < (get_attr->sz - 1)) cp = strcat(cp, " UNION ALL "); sqlen += strlen(cp); if (sqlen > (MAXSQLEN*factor - 400)) { factor *= 2; SQL = realloc(SQL, MAXSQLEN*factor); if (!SQL) { ret = -ENOMEM; goto out; } } cp = SQL + sqlen; } sprintf(cp, " ORDER BY myoid; "); ret = sqlite3_prepare(dbc->db, SQL, strlen(SQL)+1, &stmt, NULL); if (ret != SQLITE_OK) { error_sql(dbc->db, "%s: sqlite3_prepare", __func__); goto out; } /* execute the statement */ head = tail = outdata; attr_list_len = 0; while(1) { ret = sqlite3_step(stmt); if (ret == SQLITE_BUSY) { continue; } else if (ret != SQLITE_ROW) { break; } /* for the rest of loop body ret == SQLITE_ROW */ /* * XXX:SD The spec is inconsistent in applying padding and * alignment rules. Here we make changes to the spec. In our * case object descriptor format header (table 79) is 16B * instead of 12B, and attributes list length field is 4B * instead of 2B as defined in spec, and starts at byte 12 * in the header (not 10). ODE is object descriptor entry. */ oid = sqlite3_column_int64(stmt, 0); page = sqlite3_column_int64(stmt, 1); number = sqlite3_column_int64(stmt, 2); len = sqlite3_column_bytes(stmt, 3); if (page == USER_TMSTMP_PG && number == 0) { /* look ahead in the buf to see if there is space */ if (alloc_len >= 16) { /* start attr list of 'this' ODE */ set_htonll(tail, oid); memset(tail + 8, 0, 4); /* reserved */ if (head != tail) { /* fill attr_list_len of prev ODE */ set_htonl(head, attr_list_len); head = tail; attr_list_len = 0; } alloc_len -= 16; tail += 16; head += 12; /* points to attr-list-len */ *used_outlen += 16; } else { if (head != tail) { /* fill attr_list_len of prev ODE */ set_htonl(head, attr_list_len); head = tail; attr_list_len = 0; } if (*cont_id == 0) *cont_id = oid; } /* handle overflow: osd2r01 Sec 6.14.2 */ if (*add_len + 16 > *add_len) { *add_len += 16; } else { /* terminate since add_len overflew */ *add_len = (uint64_t) -1; ret = SQLITE_DONE; break; } continue; } if (alloc_len >= 16) { /* osd_debug("%s: oid %llu, page %u, number %u, len %u", __func__, llu(oid), page, number, len); */ val = sqlite3_column_blob(stmt, 3); ret = le_pack_attr(tail, alloc_len, page, number, len, val); assert (ret != -EOVERFLOW); if (ret > 0) { alloc_len -= ret; tail += ret; attr_list_len += ret; *used_outlen += ret; if (alloc_len < 16){ set_htonl(head, attr_list_len); head = tail; attr_list_len = 0; if (*cont_id == 0) *cont_id = oid; } } else { goto out_finalize; } } else { if (head != tail) { /* fill attr_list_len of this ODE */ set_htonl(head, attr_list_len); head = tail; attr_list_len = 0; if (*cont_id == 0) *cont_id = oid; } } /* handle overflow: osd2r01 Sec 6.14.2 */ if ((*add_len + roundup8(4+4+2+len)) > *add_len) { *add_len += roundup8(4+4+2+len); } else { /* terminate since add_len overflew */ *add_len = (uint64_t) -1; ret = SQLITE_DONE; break; } } if (ret != SQLITE_DONE) { error_sql(dbc->db, "%s: query execution failed. SQL %s, " " add_len %llu attr_list_len %u", __func__, SQL, llu(*add_len), attr_list_len); goto out_finalize; } if (head != tail) { set_htonl(head, attr_list_len); head += (4 + attr_list_len); assert(head == tail); } ret = OSD_OK; /* success */ out_finalize: if (sqlite3_finalize(stmt) != SQLITE_OK) { ret = -EIO; error_sql(dbc->db, "%s: finalize", __func__); } out: free(SQL); return ret; }
static void time_attr(struct osd_device *osd, int numpg, int numattr, int numiter, int test, const char *func) { int ret = 0; int i = 0; uint64_t start, end; uint32_t usedlen = 0; uint8_t *cp = 0; uint64_t val = 0; double *t = 0; double mu, sd; struct list_entry *attr = NULL, *vattr = NULL; const uint32_t le_sz = roundup8(18), vle_sz = roundup8(50); const char uidp[] = " unidentified attributes page "; if (test < 1 || test > 9) return; t = Calloc(numiter, sizeof(*t)); attr = Calloc(numpg*numattr, le_sz); vattr = Calloc(numpg*numattr, vle_sz); if (!t || !attr) return; switch (test) { case 1: case 2: case 3: val = 4; ret = attr_set_attr(osd->dbc, 1, 1, 2, 22, &val, sizeof(val)); assert(ret == 0); usedlen = 0; memset(attr, 0, le_sz); ret = attr_get_attr(osd->dbc, 1, 1, 2, 22, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == 0); assert(usedlen == le_sz); cp = (uint8_t *)attr; test_le(2, 22, sizeof(val), &val, cp); ret = attr_delete_attr(osd->dbc, 1, 1, 2, 22); assert(ret == 0); usedlen = 0; memset(attr, 0, le_sz); ret = attr_get_attr(osd->dbc, 1, 1, 2, 22, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); break; case 4: case 5: case 6: if (numpg*numattr < 2) { fprintf(stderr, "numpg*numattr < 2\n"); return; } val = 200; ret = attr_set_attr(osd->dbc, 1, 1, 2, 22, &val, sizeof(val)); assert(ret == 0); val = 400; ret = attr_set_attr(osd->dbc, 1, 1, 4, 44, &val, sizeof(val)); assert(ret == 0); usedlen = 0; memset(attr, 0, 2*le_sz); ret = attr_get_all_attrs(osd->dbc, 1, 1, 2*le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == 0); assert(usedlen == 2*le_sz); val = 200; cp = (uint8_t *)attr; test_le(2, 22, sizeof(val), &val, cp); val = 400; cp += le_sz; test_le(4, 44, sizeof(val), &val, cp); ret = attr_delete_all(osd->dbc, 1, 1); assert(ret == 0); usedlen = 0; memset(attr, 0, 2*le_sz); ret = attr_get_attr(osd->dbc, 1, 1, 2, 22, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); ret = attr_get_attr(osd->dbc, 1, 1, 4, 44, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); break; case 7: if (numpg*numattr < 4) { fprintf(stderr, "numpg*numattr < 4\n"); goto out; } val = 200; ret = attr_set_attr(osd->dbc, 1, 1, 2, 22, &val, sizeof(val)); assert(ret == 0); val = 400; ret = attr_set_attr(osd->dbc, 1, 1, 4, 44, &val, sizeof(val)); assert(ret == 0); usedlen = 0; memset(vattr, 0, 2*vle_sz); ret = attr_get_dir_page(osd->dbc, 1, 1, USEROBJECT_PG, vle_sz*2, vattr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == 0); assert(usedlen == vle_sz*2); cp = (uint8_t *)vattr; test_le(USEROBJECT_PG, 2, sizeof(uidp), uidp, cp); cp += vle_sz; test_le(USEROBJECT_PG, 4, sizeof(uidp), uidp, cp); ret = attr_delete_all(osd->dbc, 1, 1); assert(ret == 0); usedlen = 0; memset(attr, 0, 2*le_sz); ret = attr_get_attr(osd->dbc, 1, 1, 2, 22, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); ret = attr_get_attr(osd->dbc, 1, 1, 4, 44, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); break; case 8: if (numpg*numattr < 4) { fprintf(stderr, "numpg*numattr < 4\n"); goto out; } for (i = 0; i < 4; i++) { val = i*100 + 1; ret = attr_set_attr(osd->dbc, 1, 1, i, 1, &val, sizeof(val)); assert(ret == 0); ret = attr_set_attr(osd->dbc, 1, 1, i, 2, &val, sizeof(val)); assert(ret == 0); } usedlen = 0; memset(attr, 0, 4*le_sz); ret = attr_get_for_all_pages(osd->dbc, 1, 1, 1, 4*le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == 0); assert(usedlen == 4*le_sz); cp = (uint8_t *)attr; for (i = 0; i < 4; i++) { val = i*100 + 1; test_le(i, 1, sizeof(val), &val, cp); cp += le_sz; } ret = attr_delete_all(osd->dbc, 1, 1); assert(ret == 0); usedlen = 0; memset(attr, 0, 4*le_sz); for (i = 0; i < 4; i++) { ret = attr_get_attr(osd->dbc, 1, 1, i, 1, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); ret = attr_get_attr(osd->dbc, 1, 1, i, 2, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); } break; case 9: if (numpg*numattr < 2) { fprintf(stderr, "numpg*numattr < 2\n"); goto out; } for (i = 0; i < 2; i++) { val = i*100 + 1; ret = attr_set_attr(osd->dbc, 1, 1, i, 1, &val, sizeof(val)); assert(ret == 0); ret = attr_set_attr(osd->dbc, 1, 1, i, 2, &val, sizeof(val)); assert(ret == 0); } usedlen = 0; memset(attr, 0, 2*le_sz); ret = attr_get_page_as_list(osd->dbc, 1, 1, 1, 2*le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == 0); assert(usedlen == 2*le_sz); cp = (uint8_t *)attr; val = 101; test_le(1, 1, 8, &val, cp); cp += le_sz; test_le(1, 2, 8, &val, cp); ret = attr_delete_all(osd->dbc, 1, 1); assert(ret == 0); usedlen = 0; memset(attr, 0, 2*le_sz); for (i = 0; i < 2; i++) { ret = attr_get_attr(osd->dbc, 1, 1, i, 1, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); ret = attr_get_attr(osd->dbc, 1, 1, i, 2, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); assert(ret == -ENOENT); } break; default: goto out; } for (i = 0; i < numiter; i++) { /* set up; time test no. 4 */ t[i] = 0.0; switch (test) { case 2: case 3: /* set one attr used to get/del */ val = 400; ret = attr_set_attr(osd->dbc, 2, 2, 1, 1, &val, sizeof(val)); assert(ret == 0); case 1: case 5: case 6: case 7: case 8: case 9: pre_create_attrs(osd, numpg, numattr); break; case 4: { int np, na; for (np = 1; np < numpg+1; np++) { for (na = 1; na < numattr+1; na++) { val = na; rdtsc(start); ret = attr_set_attr(osd->dbc, 1, 1, np, na, &val, sizeof(val)); rdtsc(end); assert(ret == 0); t[i] += (double)(end - start) / mhz; } } break; } default: goto out; } /* test */ switch (test) { case 1: val = 400; rdtsc(start); ret = attr_set_attr(osd->dbc, 2, 2, 1, 1, &val, sizeof(val)); rdtsc(end); assert(ret == 0); break; case 2: usedlen = 0; memset(attr, 0, le_sz); rdtsc(start); ret = attr_get_attr(osd->dbc, 2, 2, 1, 1, le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); rdtsc(end); assert(ret == 0); assert(usedlen == le_sz); break; case 3: usedlen = 0; memset(attr, 0, le_sz); rdtsc(start); ret = attr_delete_attr(osd->dbc, 2, 2, 1, 1); rdtsc(end); assert(ret == 0); break; case 4: break; case 5: rdtsc(start); ret = attr_get_all_attrs(osd->dbc, 1, 1, numpg*numattr*le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); rdtsc(end); assert(ret == 0); assert(usedlen == (numpg*numattr*le_sz)); break; case 6: rdtsc(start); ret = attr_delete_all(osd->dbc, 1, 1); rdtsc(end); assert(ret == 0); break; case 7: rdtsc(start); ret = attr_get_dir_page(osd->dbc, 1, 1, USEROBJECT_PG, numpg*vle_sz, vattr, RTRVD_SET_ATTR_LIST, &usedlen); rdtsc(end); assert(ret == 0); assert(usedlen == numpg*vle_sz); break; case 8: rdtsc(start); ret = attr_get_for_all_pages(osd->dbc, 1, 1, 1, numpg*le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); rdtsc(end); assert(ret == 0); assert(usedlen == numpg*le_sz); break; case 9: rdtsc(start); ret = attr_get_page_as_list(osd->dbc, 1, 1, 1, numattr*le_sz, attr, RTRVD_SET_ATTR_LIST, &usedlen); rdtsc(end); assert(ret == 0); assert(usedlen == numattr*le_sz); break; default: goto out; } if (test != 4) t[i] = (double) (end - start) / mhz; end = start = 0; /* cleanup */ switch (test) { case 1: case 2: ret = attr_delete_attr(osd->dbc, 2, 2, 1, 1); assert(ret == 0); case 3: case 4: case 5: break; case 6: case 7: case 8: case 9: ret = attr_delete_all(osd->dbc, 1, 1); assert(ret == 0); break; default: goto out; } } mu = mean(t, numiter); sd = stddev(t, mu, numiter); printf("%s numiter %d numpg %d numattr %d test %d avg %lf +- %lf " " us\n", func, numiter, numpg, numattr, test, mu, sd); out: free(t); free(attr); free(vattr); }
/* 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); }