void identify(int argc, char *argv[]) { char *target; if (argc < 2) identify_usage(); while (getopt(argc, argv, "vx") != -1) ; /* Check that a controller or namespace was specified. */ if (optind >= argc) identify_usage(); target = argv[optind]; optreset = 1; optind = 1; /* * If device node contains "ns", we consider it a namespace, * otherwise, consider it a controller. */ if (strstr(target, NVME_NS_PREFIX) == NULL) identify_ctrlr(argc, argv); else identify_ns(argc, argv); }
static void identify_ctrlr(int argc, char *argv[]) { struct nvme_controller_data cdata; int ch, fd, hexflag = 0, hexlength; int verboseflag = 0; while ((ch = getopt(argc, argv, "vx")) != -1) { switch ((char)ch) { case 'v': verboseflag = 1; break; case 'x': hexflag = 1; break; default: identify_usage(); } } /* Check that a controller was specified. */ if (optind >= argc) identify_usage(); open_dev(argv[optind], &fd, 1, 1); read_controller_data(fd, &cdata); close(fd); if (hexflag == 1) { if (verboseflag == 1) hexlength = sizeof(struct nvme_controller_data); else hexlength = offsetof(struct nvme_controller_data, reserved5); print_hex(&cdata, hexlength); exit(0); } if (verboseflag == 1) { fprintf(stderr, "-v not currently supported without -x\n"); identify_usage(); } print_controller(&cdata); exit(0); }
static void identify_ns(int argc, char *argv[]) { struct nvme_namespace_data nsdata; char path[64]; int ch, fd, hexflag = 0, hexlength, nsid; int verboseflag = 0; while ((ch = getopt(argc, argv, "vx")) != -1) { switch ((char)ch) { case 'v': verboseflag = 1; break; case 'x': hexflag = 1; break; default: identify_usage(); } } /* Check that a namespace was specified. */ if (optind >= argc) identify_usage(); /* * Check if the specified device node exists before continuing. * This is a cleaner check for cases where the correct controller * is specified, but an invalid namespace on that controller. */ open_dev(argv[optind], &fd, 1, 1); close(fd); /* * We send IDENTIFY commands to the controller, not the namespace, * since it is an admin cmd. The namespace ID will be specified in * the IDENTIFY command itself. So parse the namespace's device node * string to get the controller substring and namespace ID. */ parse_ns_str(argv[optind], path, &nsid); open_dev(path, &fd, 1, 1); read_namespace_data(fd, nsid, &nsdata); close(fd); if (hexflag == 1) { if (verboseflag == 1) hexlength = sizeof(struct nvme_namespace_data); else hexlength = offsetof(struct nvme_namespace_data, reserved6); print_hex(&nsdata, hexlength); exit(0); } if (verboseflag == 1) { fprintf(stderr, "-v not currently supported without -x\n"); identify_usage(); } print_namespace(&nsdata); exit(0); }
void ot_recover(void *nvm_start) { int i=0; uint16_t n; uint64_t current_slot = 0; uint64_t last_used_slot = 0; nvm_chunk_header_t *chunk_hdr = (nvm_chunk_header_t*) first_chunk; nvm_object_table_entry_t *nvm_entry = NULL; object_table_entry_t *entry = NULL; nvm_huge_header_t *nvm_huge = NULL; nvm_block_header_t *nvm_block = NULL; nvm_run_header_t *nvm_run = NULL; uint16_t bit_idx = 0; uint8_t bitmap_idx = 0; char bitmask = 0; char state = -1; int keep = 0; void *ptr = NULL; while (1) { for (i=0; i<63; ++i) { keep = 0; nvm_entry = &chunk_hdr->object_table[i]; if (nvm_entry->state == STATE_INITIALIZED) { /* entry is marked as initialized, so we can keep it */ keep = 1; } else if (nvm_entry->state == STATE_INITIALIZING) { /* crash occurred during activation but after writing the entry, check corresponding header */ /* if header is in state PREFREE, ACTIVATING or INITIALIZED, it is/will be recovered and the entry can persist */ ptr = (void*) ((uintptr_t)nvm_start + nvm_entry->ptr); state = identify_usage(ptr); if (state == USAGE_HUGE) { nvm_huge = (nvm_huge_header_t*) ((uintptr_t)ptr - sizeof(nvm_huge_header_t)); if (nvm_huge->state == STATE_PREFREE || nvm_huge->state == STATE_ACTIVATING || nvm_huge->state == STATE_INITIALIZED) { keep = 1; } } else if (state == USAGE_BLOCK) { nvm_block = (nvm_block_header_t*) ((uintptr_t)ptr - sizeof(nvm_block_header_t)); if (nvm_block->state == STATE_PREFREE || nvm_block->state == STATE_ACTIVATING || nvm_block->state == STATE_INITIALIZED) { keep = 1; } } else if (state == USAGE_RUN) { /* for runs, we also need to check that the bit index is the correct one */ nvm_run = (nvm_run_header_t*) ((uintptr_t)ptr & ~(BLOCK_SIZE-1)); bit_idx = ((uintptr_t)ptr - (uintptr_t)(nvm_run+1)) / nvm_run->n_bytes; bitmask = 1 << (bit_idx % 8); bitmap_idx = bit_idx / 8; if ((nvm_run->state == STATE_PREFREE && (nvm_run->bitmap[bitmap_idx] & bitmask) != 0) || (nvm_run->state == STATE_ACTIVATING && nvm_run->bit_idx == bit_idx) || (nvm_run->state == STATE_INITIALIZED && (nvm_run->bitmap[bitmap_idx] & bitmask) != 0)) { keep = 1; } } if (keep) { nvm_entry->state = STATE_INITIALIZED; } else { memset(nvm_entry, 0, sizeof(nvm_object_table_entry_t)); } PERSIST(nvm_entry); } if (keep) { /* if we keep the entry, create its volatile counterpart */ entry = malloc(sizeof(object_table_entry_t)); memcpy(entry->id, nvm_entry->id, MAX_ID_LENGTH); entry->slot = current_slot; entry->data_ptr = NVM_REL_TO_ABS(first_chunk, nvm_entry->ptr); entry->nvm_entry = nvm_entry; /* add the unused slots we found since the last valid entry to the slot buffer */ for (n=last_used_slot+1; n<current_slot; ++n) { slot_buffer[slot_buffer_next_idx++] = n; ++slot_buffer_tail_idx; ++slot_buffer_n_free; } last_used_slot = current_slot; HASHMAP_INSERT(entry->id, entry); } ++current_slot; } if (chunk_hdr->next_ot_chunk) { chunk_hdr = (nvm_chunk_header_t*) NVM_REL_TO_ABS(first_chunk, chunk_hdr->next_ot_chunk); } else { break; } } next_nvm_slot = last_used_slot+1; }