void switchlink_db_init() { tommy_trie_inplace_init(&switchlink_db_handle_obj_map); tommy_trie_inplace_init(&switchlink_db_interface_obj_map); tommy_trie_inplace_init(&switchlink_db_bridge_obj_map); tommy_hashlin_init(&switchlink_db_mac_obj_hash); tommy_list_init(&switchlink_db_mac_obj_list); tommy_list_init(&switchlink_db_neigh_obj_list); tommy_list_init(&switchlink_db_ecmp_obj_list); tommy_list_init(&switchlink_db_route_obj_list); }
switch_handle_t switch_api_ecmp_create(switch_device_t device) { switch_handle_t nhop_handle; switch_nhop_info_t *nhop_info = NULL; switch_ecmp_info_t *ecmp_info = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; nhop_handle = switch_nhop_create(); nhop_info = switch_nhop_get(nhop_handle); if (!nhop_info) { return SWITCH_API_INVALID_HANDLE; } nhop_info->type = SWITCH_NHOP_INDEX_TYPE_ECMP; ecmp_info = &(SWITCH_NHOP_ECMP_INFO(nhop_info)); memset(ecmp_info, 0, sizeof(switch_ecmp_info_t)); ecmp_info->hw_entry = SWITCH_HW_INVALID_HANDLE; ecmp_info->count = 0; tommy_list_init(&(ecmp_info->members)); #ifdef SWITCH_PD status = switch_pd_ecmp_group_create(device, &(ecmp_info->pd_group_hdl)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } #endif return nhop_handle; }
switch_handle_t switch_api_stp_group_create(switch_device_t device, switch_stp_mode_t stp_mode) { switch_handle_t stg_handle; switch_stp_info_t *stp_info = NULL; stg_handle = switch_stg_handle_create(); stp_info = switch_api_stp_get_internal(stg_handle); if (!stp_info) { // No memory return 0; } tommy_list_init(&(stp_info->vlan_list)); tommy_list_init(&(stp_info->port_list)); return stg_handle; }
cheap_tcam_t *cheap_tcam_create(int key_size, cheap_tcam_priority_fn get_priority, cheap_tcam_cmp_fn cmp) { cheap_tcam_t *tcam = malloc(sizeof(cheap_tcam_t)); tcam->key_size = key_size; tcam->get_priority = get_priority; tcam->cmp = cmp; tcam->masked_key = malloc(key_size); tommy_list_init(&tcam->hashmaps); return tcam; }
/* * @function: switch_api_router_mac_group_create * Creates a RMAC Group * @return: Returns rmac group id if success */ switch_handle_t switch_api_router_mac_group_create(switch_device_t device) { switch_rmac_info_t *rmac_info = NULL; switch_handle_t rmac_handle; _switch_handle_create(SWITCH_HANDLE_TYPE_MY_MAC, switch_rmac_info_t, switch_rmac_array, NULL, rmac_handle); rmac_info = switch_api_rmac_info_get_internal(rmac_handle); tommy_list_init(&(rmac_info->rmac_list)); return rmac_handle; }
struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev, int skip) { struct snapraid_disk* disk; disk = malloc_nofail(sizeof(struct snapraid_disk)); pathcpy(disk->name, sizeof(disk->name), name); pathimport(disk->dir, sizeof(disk->dir), dir); /* ensure that the dir terminate with "/" if it isn't empty */ pathslash(disk->dir, sizeof(disk->dir)); disk->smartctl[0] = 0; disk->device = dev; disk->tick = 0; disk->total_blocks = 0; disk->free_blocks = 0; disk->first_free_block = 0; disk->has_volatile_inodes = 0; disk->has_unreliable_physical = 0; disk->has_different_uuid = 0; disk->has_unsupported_uuid = 0; disk->had_empty_uuid = 0; disk->mapping_idx = -1; disk->skip_access = skip; tommy_list_init(&disk->filelist); tommy_list_init(&disk->deletedlist); tommy_hashdyn_init(&disk->inodeset); tommy_hashdyn_init(&disk->pathset); tommy_hashdyn_init(&disk->stampset); tommy_list_init(&disk->linklist); tommy_hashdyn_init(&disk->linkset); tommy_list_init(&disk->dirlist); tommy_hashdyn_init(&disk->dirset); tommy_tree_init(&disk->fs_parity, chunk_parity_compare); tommy_tree_init(&disk->fs_file, chunk_file_compare); disk->fs_last = 0; return disk; }
phash_pool pcore_hash_init(const puint8 type) { plog_dbg("%s(): Инициализация пула типа %d", __PRETTY_FUNCTION__, type); phash_pool pool = pmalloc_check(__PRETTY_FUNCTION__, sizeof(struct s_phash_pool)); if (!pool) { return NULL; } pool->type = type; tommy_list *list = pmalloc_check(__PRETTY_FUNCTION__, sizeof(tommy_list)); if (!list) { free(pool); return NULL; } void *hash_struct; switch (type) { case PHASH_FAST_SEARCH: hash_struct = pmalloc_check(__PRETTY_FUNCTION__, sizeof(tommy_hashdyn)); if (!hash_struct) { free(pool); free(list); return NULL; } tommy_hashdyn_init(hash_struct); break; case PHASH_FAST_INSERT: default: hash_struct = pmalloc_check(__PRETTY_FUNCTION__, sizeof(tommy_hashtable)); if (!hash_struct) { free(pool); free(list); return NULL; } tommy_hashtable_init(hash_struct, 1024); break; } tommy_list_init(list); pool->list = list; pool->hash_struct = hash_struct; plog_dbg("%s(): Пул 0x%08X успешно создан", __PRETTY_FUNCTION__, pool); return pool; }
static switch_status_t switch_l3_insert_into_vrf_list( switch_l3_hash_t *hash_entry) { switch_vrf_route_list_t *vrf_route_list = NULL; void *temp = NULL; switch_ip_addr_t ip_addr; switch_handle_t vrf_handle = 0; memset(&ip_addr, 0, sizeof(switch_ip_addr_t)); switch_l3_hash_key_decode(hash_entry, &vrf_handle, &ip_addr); if (ip_addr.type == SWITCH_API_IP_ADDR_V4) { JLG(temp, switch_vrf_v4_routes, vrf_handle); } else { JLG(temp, switch_vrf_v6_routes, vrf_handle); } if (!temp) { vrf_route_list = switch_malloc(sizeof(switch_vrf_route_list_t), 1); if (!vrf_route_list) { SWITCH_API_ERROR("%s:%d: No memory!", __FUNCTION__, __LINE__); return SWITCH_STATUS_NO_MEMORY; } tommy_list_init(&(vrf_route_list->routes)); vrf_route_list->num_entries = 0; if (ip_addr.type == SWITCH_API_IP_ADDR_V4) { JLI(temp, switch_vrf_v4_routes, vrf_handle); } else { JLI(temp, switch_vrf_v6_routes, vrf_handle); } *(unsigned long *)temp = (unsigned long)(vrf_route_list); } vrf_route_list = (switch_vrf_route_list_t *)(*(unsigned long *)temp); tommy_list_insert_tail( &(vrf_route_list->routes), &(hash_entry->vrf_route_node), hash_entry); vrf_route_list->num_entries++; return SWITCH_STATUS_SUCCESS; }
void state_device(struct snapraid_state* state, int operation, tommy_list* filterlist_disk) { tommy_node* i; unsigned j; tommy_list high; tommy_list low; int ret; switch (operation) { case DEVICE_UP : msg_progress("Spinup...\n"); break; case DEVICE_DOWN : msg_progress("Spindown...\n"); break; } tommy_list_init(&high); tommy_list_init(&low); /* for all disks */ for (i = state->disklist; i != 0; i = i->next) { struct snapraid_disk* disk = i->data; devinfo_t* entry; if (filterlist_disk != 0 && filter_path(filterlist_disk, 0, disk->name, 0) != 0) continue; entry = calloc_nofail(1, sizeof(devinfo_t)); entry->device = disk->device; pathcpy(entry->name, sizeof(entry->name), disk->name); pathcpy(entry->mount, sizeof(entry->mount), disk->dir); pathcpy(entry->smartctl, sizeof(entry->smartctl), disk->smartctl); tommy_list_insert_tail(&high, &entry->node, entry); } /* for all parities */ for (j = 0; j < state->level; ++j) { devinfo_t* entry; if (filterlist_disk != 0 && filter_path(filterlist_disk, 0, lev_config_name(j), 0) != 0) continue; entry = calloc_nofail(1, sizeof(devinfo_t)); entry->device = state->parity[j].device; pathcpy(entry->name, sizeof(entry->name), lev_config_name(j)); pathcpy(entry->mount, sizeof(entry->mount), state->parity[j].path); pathcpy(entry->smartctl, sizeof(entry->smartctl), state->parity[j].smartctl); pathcut(entry->mount); /* remove the parity file */ tommy_list_insert_tail(&high, &entry->node, entry); } if (state->opt.fake_device) { ret = devtest(&low, operation); } else { int others = operation == DEVICE_SMART; ret = devquery(&high, &low, operation, others); } /* if the list is empty, it's not supported in this platform */ if (ret == 0 && tommy_list_empty(&low)) ret = -1; if (ret != 0) { const char* ope = 0; switch (operation) { case DEVICE_UP : ope = "Spinup"; break; case DEVICE_DOWN : ope = "Spindown"; break; case DEVICE_LIST : ope = "Device listing"; break; case DEVICE_SMART : ope = "Smart"; break; } log_fatal("%s is unsupported in this platform.\n", ope); } else { if (operation == DEVICE_LIST) { for (i = tommy_list_head(&low); i != 0; i = i->next) { devinfo_t* devinfo = i->data; devinfo_t* parent = devinfo->parent; #ifdef _WIN32 printf("%" PRIu64 "\t%s\t%08" PRIx64 "\t%s\t%s\n", devinfo->device, devinfo->wfile, parent->device, parent->wfile, parent->name); #else printf("%u:%u\t%s\t%u:%u\t%s\t%s\n", major(devinfo->device), minor(devinfo->device), devinfo->file, major(parent->device), minor(parent->device), parent->file, parent->name); #endif } } if (operation == DEVICE_SMART) state_smart(state->level + tommy_list_count(&state->disklist), &low); } tommy_list_foreach(&high, free); tommy_list_foreach(&low, free); }
void init_hash_table(void *ht, void *ll) { tommy_hashlin_init(ht); tommy_list_init(ll); }
switch_status_t switch_packet_init(switch_device_t device) { switch_status_t status = SWITCH_STATUS_SUCCESS; tommy_list_init(&packet_rx_filter_list); tommy_list_init(&packet_tx_filter_list); return status; }
switch_handle_t switch_api_ecmp_create_with_members(switch_device_t device, uint32_t member_count, switch_handle_t *nhop_handle) { switch_nhop_info_t *nhop_info = NULL; switch_spath_info_t *spath_info = NULL; switch_interface_info_t *intf_info = NULL; switch_ecmp_info_t *ecmp_info = NULL; switch_ecmp_member_t *ecmp_member = NULL; switch_handle_t ecmp_handle; switch_status_t status = SWITCH_STATUS_SUCCESS; uint32_t index = 0; ecmp_handle = switch_api_ecmp_create(device); nhop_info = switch_nhop_get(ecmp_handle); if (!nhop_info) { return SWITCH_API_INVALID_HANDLE; } ecmp_info = &(SWITCH_NHOP_ECMP_INFO(nhop_info)); tommy_list_init(&ecmp_info->members); #ifdef SWITCH_PD status = switch_pd_ecmp_group_create(device, &(ecmp_info->pd_group_hdl)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } #endif for (index = 0; index < member_count; index++) { if (!SWITCH_NHOP_HANDLE_VALID(nhop_handle[index])) { return SWITCH_STATUS_INVALID_HANDLE; } ecmp_member = switch_malloc(sizeof(switch_ecmp_member_t), 1); if (!ecmp_member) { // TODO: Cleanup memory return SWITCH_API_INVALID_HANDLE; } ecmp_member->nhop_handle = nhop_handle[index]; ecmp_member->mbr_hdl = 0; nhop_info = switch_nhop_get(ecmp_member->nhop_handle); if (!nhop_info) { return SWITCH_API_INVALID_HANDLE; } spath_info = &(SWITCH_NHOP_SPATH_INFO(nhop_info)); intf_info = switch_api_interface_get(spath_info->nhop_key.intf_handle); if (!intf_info) { return SWITCH_API_INVALID_HANDLE; } nhop_info->ref_count++; #ifdef SWITCH_PD status = switch_pd_ecmp_member_add(device, ecmp_info->pd_group_hdl, handle_to_id(ecmp_member->nhop_handle), intf_info, &(ecmp_member->mbr_hdl)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } if (SWITCH_INTF_IS_PORT_L3(intf_info) && intf_info->bd_handle) { status = switch_pd_urpf_bd_table_add_entry(device, handle_to_id(ecmp_handle), handle_to_id(intf_info->bd_handle), &(ecmp_member->urpf_hw_entry)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } } #endif tommy_list_insert_head(&ecmp_info->members, &(ecmp_member->node), ecmp_member); } #ifdef SWITCH_PD status = switch_pd_ecmp_group_table_add_entry_with_selector(device, handle_to_id(ecmp_handle), ecmp_info->pd_group_hdl, &(ecmp_info->hw_entry)); if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } #endif ecmp_info->count = member_count; if (status != SWITCH_STATUS_SUCCESS) { return SWITCH_API_INVALID_HANDLE; } return ecmp_handle; }
switch_handle_t switch_api_sflow_session_create( switch_device_t device, switch_api_sflow_session_info_t *api_sflow_info) { #ifdef P4_SFLOW_ENABLE switch_handle_t sflow_handle = SWITCH_API_INVALID_HANDLE; switch_sflow_info_t *sflow_info = NULL; switch_status_t status = SWITCH_STATUS_FAILURE; // Parameter validation if (api_sflow_info->collector_type != SFLOW_COLLECTOR_TYPE_CPU) { // Only sflow via cpu is supported at this time return SWITCH_API_INVALID_HANDLE; } else if (!switch_port_is_cpu_port(api_sflow_info->egress_port_hdl)) { return SWITCH_API_INVALID_HANDLE; } if (api_sflow_info->sample_mode != SWITCH_SFLOW_SAMPLE_PKT) { // single packet per notificaiton - other modes are TBD return SWITCH_API_INVALID_HANDLE; } if (api_sflow_info->sample_rate == 0) { return SWITCH_API_INVALID_HANDLE; } sflow_handle = switch_sflow_handle_create(); if (sflow_handle == SWITCH_API_INVALID_HANDLE) { return sflow_handle; } sflow_info = switch_sflow_info_get(sflow_handle); if (!sflow_info) { return SWITCH_API_INVALID_HANDLE; } sflow_info->session_id = handle_to_id(sflow_handle); sflow_info->api_info = *api_sflow_info; tommy_list_init(&sflow_info->match_list); sflow_info->mirror_hdl = SWITCH_API_INVALID_HANDLE; sflow_info->mirror_table_ent_hdl = SWITCH_HW_INVALID_HANDLE; sflow_info->ing_take_sample_table_ent_hdl = SWITCH_HW_INVALID_HANDLE; // Create a mirror session to send sampled pkts to CPU. // SWITCH_CPU_MIRROR_SESSION_ID mirror-session can be used, except // it does not truncate the packet. sFlow may not need entire packet. // CPU can perform tuncation as well, but this makes it a bit easier // for CPU if (api_sflow_info->collector_type == SFLOW_COLLECTOR_TYPE_CPU) { switch_api_mirror_info_t api_mirror_info; memset(&api_mirror_info, 0, sizeof(switch_api_mirror_info_t)); api_mirror_info.mirror_type = SWITCH_MIRROR_TYPE_LOCAL; // mirror session id is allocated by the mirroring api api_mirror_info.session_type = SWITCH_MIRROR_SESSION_TYPE_SIMPLE; api_mirror_info.egress_port = CPU_PORT_ID; api_mirror_info.direction = SWITCH_API_DIRECTION_BOTH; api_mirror_info.max_pkt_len = api_sflow_info->extract_len; sflow_info->mirror_hdl = switch_api_mirror_session_create(device, &api_mirror_info); if (sflow_info->mirror_hdl == SWITCH_API_INVALID_HANDLE) { goto error_return; } } else { assert(0); } status = switch_pd_sflow_session_create(device, sflow_info); if (status != SWITCH_STATUS_SUCCESS) { goto error_return; } return sflow_handle; error_return: switch_api_sflow_session_delete(device, sflow_handle, false); return SWITCH_API_INVALID_HANDLE; #else (void)device; (void)api_sflow_info; return SWITCH_API_INVALID_HANDLE; #endif }
int main(int argc, char* argv[]) { int c; struct snapraid_option opt; char conf[PATH_MAX]; struct snapraid_state state; int operation; block_off_t blockstart; block_off_t blockcount; int ret; tommy_list filterlist_file; tommy_list filterlist_disk; int filter_missing; int filter_error; int plan; int olderthan; char* e; const char* command; const char* import_timestamp; const char* import_content; const char* log_file; int lock; const char* gen_conf; const char* run; int speedtest; int period; time_t t; struct tm* tm; int i; /* defaults */ config(conf, sizeof(conf), argv[0]); memset(&opt, 0, sizeof(opt)); opt.io_error_limit = 100; blockstart = 0; blockcount = 0; tommy_list_init(&filterlist_file); tommy_list_init(&filterlist_disk); period = 1000; filter_missing = 0; filter_error = 0; plan = SCRUB_AUTO; olderthan = SCRUB_AUTO; import_timestamp = 0; import_content = 0; log_file = 0; lock = 0; gen_conf = 0; speedtest = 0; run = 0; opterr = 0; while ((c = #if HAVE_GETOPT_LONG getopt_long(argc, argv, OPTIONS, long_options, 0)) #else getopt(argc, argv, OPTIONS)) #endif != EOF) { switch (c) { case 'c' : pathimport(conf, sizeof(conf), optarg); break; case 'f' : { struct snapraid_filter* filter = filter_alloc_file(1, optarg); if (!filter) { /* LCOV_EXCL_START */ log_fatal("Invalid filter specification '%s'\n", optarg); log_fatal("Filters using relative paths are not supported. Ensure to add an initial slash\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } tommy_list_insert_tail(&filterlist_file, &filter->node, filter); } break; case 'd' : { struct snapraid_filter* filter = filter_alloc_disk(1, optarg); if (!filter) { /* LCOV_EXCL_START */ log_fatal("Invalid filter specification '%s'\n", optarg); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } tommy_list_insert_tail(&filterlist_disk, &filter->node, filter); } break; case 'm' : filter_missing = 1; opt.expected_missing = 1; break; case 'e' : /* when processing only error, we filter both files and blocks */ /* and we apply fixes only to synced ones */ filter_error = 1; opt.badonly = 1; opt.syncedonly = 1; break; case 'p' : if (strcmp(optarg, "bad") == 0) { plan = SCRUB_BAD; } else if (strcmp(optarg, "new") == 0) { plan = SCRUB_NEW; } else if (strcmp(optarg, "full") == 0) { plan = SCRUB_FULL; } else { plan = strtoul(optarg, &e, 10); if (!e || *e || plan > 100) { /* LCOV_EXCL_START */ log_fatal("Invalid plan/percentage '%s'\n", optarg); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } break; case 'o' : olderthan = strtoul(optarg, &e, 10); if (!e || *e || olderthan > 1000) { /* LCOV_EXCL_START */ log_fatal("Invalid number of days '%s'\n", optarg); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } break; case 'S' : blockstart = strtoul(optarg, &e, 0); if (!e || *e) { /* LCOV_EXCL_START */ log_fatal("Invalid start position '%s'\n", optarg); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } break; case 'B' : blockcount = strtoul(optarg, &e, 0); if (!e || *e) { /* LCOV_EXCL_START */ log_fatal("Invalid count number '%s'\n", optarg); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } break; case 'L' : opt.io_error_limit = strtoul(optarg, &e, 0); if (!e || *e) { /* LCOV_EXCL_START */ log_fatal("Invalid error limit number '%s'\n", optarg); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } break; case 'i' : if (import_timestamp) { /* LCOV_EXCL_START */ log_fatal("Import directory '%s' already specified as '%s'\n", optarg, import_timestamp); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } import_timestamp = optarg; break; case OPT_TEST_IMPORT_CONTENT : if (import_content) { /* LCOV_EXCL_START */ log_fatal("Import directory '%s' already specified as '%s'\n", optarg, import_content); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } import_content = optarg; break; case 'l' : if (log_file) { /* LCOV_EXCL_START */ log_fatal("Log file '%s' already specified as '%s'\n", optarg, log_file); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } log_file = optarg; break; case 'Z' : opt.force_zero = 1; break; case 'E' : opt.force_empty = 1; break; case 'U' : opt.force_uuid = 1; break; case 'D' : opt.force_device = 1; break; case 'N' : opt.force_nocopy = 1; break; case 'F' : opt.force_full = 1; break; case 'a' : opt.auditonly = 1; break; case 'h' : opt.prehash = 1; break; case 'v' : ++msg_level; break; case 'q' : --msg_level; break; case 'G' : opt.gui = 1; break; case 'H' : usage(); exit(EXIT_SUCCESS); case 'V' : version(); exit(EXIT_SUCCESS); case 'T' : speedtest = 1; break; case 'C' : gen_conf = optarg; break; case OPT_TEST_KILL_AFTER_SYNC : opt.kill_after_sync = 1; break; case OPT_TEST_EXPECT_UNRECOVERABLE : opt.expect_unrecoverable = 1; break; case OPT_TEST_EXPECT_RECOVERABLE : opt.expect_recoverable = 1; break; case OPT_TEST_SKIP_SELF : opt.skip_self = 1; break; case OPT_TEST_SKIP_SIGN : opt.skip_sign = 1; break; case OPT_TEST_SKIP_FALLOCATE : opt.skip_fallocate = 1; break; case OPT_TEST_SKIP_SEQUENTIAL : opt.skip_sequential = 1; break; case OPT_TEST_SKIP_DEVICE : opt.skip_device = 1; period = 50; /* reduce period of the speed test */ break; case OPT_TEST_SKIP_CONTENT_CHECK : opt.skip_content_check = 1; break; case OPT_TEST_SKIP_PARITY_ACCESS : opt.skip_parity_access = 1; break; case OPT_TEST_SKIP_DISK_ACCESS : opt.skip_disk_access = 1; break; case OPT_TEST_FORCE_MURMUR3 : opt.force_murmur3 = 1; break; case OPT_TEST_FORCE_SPOOKY2 : opt.force_spooky2 = 1; break; case OPT_TEST_SKIP_LOCK : opt.skip_lock = 1; break; case OPT_TEST_FORCE_ORDER_PHYSICAL : opt.force_order = SORT_PHYSICAL; break; case OPT_TEST_FORCE_ORDER_INODE : opt.force_order = SORT_INODE; break; case OPT_TEST_FORCE_ORDER_ALPHA : opt.force_order = SORT_ALPHA; break; case OPT_TEST_FORCE_ORDER_DIR : opt.force_order = SORT_DIR; break; case OPT_TEST_FORCE_SCRUB_AT : opt.force_scrub_at = atoi(optarg); break; case OPT_TEST_FORCE_SCRUB_EVEN : opt.force_scrub_even = 1; break; case OPT_TEST_FORCE_CONTENT_WRITE : opt.force_content_write = 1; break; case OPT_TEST_EXPECT_FAILURE : /* invert the exit codes */ exit_success = 1; exit_failure = 0; break; case OPT_TEST_EXPECT_NEED_SYNC : /* invert the exit codes */ exit_success = 1; exit_sync_needed = 0; break; case OPT_TEST_RUN : run = optarg; break; case OPT_TEST_FORCE_SCAN_WINFIND : opt.force_scan_winfind = 1; break; case OPT_TEST_FORCE_PROGRESS : opt.force_progress = 1; break; case OPT_TEST_FORCE_AUTOSAVE_AT : opt.force_autosave_at = atoi(optarg); break; case OPT_TEST_FAKE_DEVICE : opt.fake_device = 1; break; case OPT_NO_WARNINGS : opt.no_warnings = 1; break; default : /* LCOV_EXCL_START */ log_fatal("Unknown option '%c'\n", (char)c); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } os_init(opt.force_scan_winfind); raid_init(); crc32c_init(); if (speedtest != 0) { speed(period); os_done(); exit(EXIT_SUCCESS); } if (gen_conf != 0) { generate_configuration(gen_conf); os_done(); exit(EXIT_SUCCESS); } if (optind + 1 != argc) { /* LCOV_EXCL_START */ usage(); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } command = argv[optind]; if (strcmp(command, "diff") == 0) { operation = OPERATION_DIFF; } else if (strcmp(argv[optind], "sync") == 0) { operation = OPERATION_SYNC; } else if (strcmp(argv[optind], "check") == 0) { operation = OPERATION_CHECK; } else if (strcmp(argv[optind], "fix") == 0) { operation = OPERATION_FIX; } else if (strcmp(argv[optind], "test-dry") == 0) { operation = OPERATION_DRY; } else if (strcmp(argv[optind], "dup") == 0) { operation = OPERATION_DUP; } else if (strcmp(argv[optind], "list") == 0) { operation = OPERATION_LIST; } else if (strcmp(argv[optind], "pool") == 0) { operation = OPERATION_POOL; } else if (strcmp(argv[optind], "rehash") == 0) { operation = OPERATION_REHASH; } else if (strcmp(argv[optind], "scrub") == 0) { operation = OPERATION_SCRUB; } else if (strcmp(argv[optind], "status") == 0) { operation = OPERATION_STATUS; } else if (strcmp(argv[optind], "test-rewrite") == 0) { operation = OPERATION_REWRITE; } else if (strcmp(argv[optind], "test-read") == 0) { operation = OPERATION_READ; } else if (strcmp(argv[optind], "test-nano") == 0) { operation = OPERATION_NANO; } else if (strcmp(argv[optind], "up") == 0) { operation = OPERATION_SPINUP; } else if (strcmp(argv[optind], "down") == 0) { operation = OPERATION_SPINDOWN; } else if (strcmp(argv[optind], "devices") == 0) { operation = OPERATION_DEVICES; } else if (strcmp(argv[optind], "smart") == 0) { operation = OPERATION_SMART; } else { /* LCOV_EXCL_START */ log_fatal("Unknown command '%s'\n", argv[optind]); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } /* check options compatibility */ switch (operation) { case OPERATION_CHECK : break; default : if (opt.auditonly) { /* LCOV_EXCL_START */ log_fatal("You cannot use -a, --audit-only with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } switch (operation) { case OPERATION_FIX : break; default : if (opt.force_device) { /* LCOV_EXCL_START */ log_fatal("You cannot use -D, --force-device with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } switch (operation) { case OPERATION_SYNC : case OPERATION_CHECK : case OPERATION_FIX : break; default : if (opt.force_nocopy) { /* LCOV_EXCL_START */ log_fatal("You cannot use -N, --force-nocopy with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } switch (operation) { case OPERATION_SYNC : break; default : if (opt.prehash) { /* LCOV_EXCL_START */ log_fatal("You cannot use -h, --pre-hash with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } if (opt.force_full) { /* LCOV_EXCL_START */ log_fatal("You cannot use -F, --force-full with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } if (opt.force_full && opt.force_nocopy) { /* LCOV_EXCL_START */ log_fatal("You cannot use the -F, --force-full and -N, --force-nocopy options at the same time\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } if (opt.prehash && opt.force_nocopy) { /* LCOV_EXCL_START */ log_fatal("You cannot use the -h, --pre-hash and -N, --force-nocopy options at the same time\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } switch (operation) { case OPERATION_CHECK : case OPERATION_FIX : case OPERATION_DRY : break; default : if (!tommy_list_empty(&filterlist_file)) { /* LCOV_EXCL_START */ log_fatal("You cannot use -f, --filter with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } if (!tommy_list_empty(&filterlist_disk)) { /* LCOV_EXCL_START */ log_fatal("You cannot use -d, --filter-disk with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } if (filter_missing != 0) { /* LCOV_EXCL_START */ log_fatal("You cannot use -m, --filter-missing with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } if (filter_error != 0) { /* LCOV_EXCL_START */ log_fatal("You cannot use -e, --filter-error with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } /* errors must be always fixed on all disks */ /* becasue we don't keep the information on what disk is the error */ if (filter_error != 0 && !tommy_list_empty(&filterlist_disk)) { /* LCOV_EXCL_START */ log_fatal("You cannot use -e, --filter-error and -d, --filter-disk at the same time\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } switch (operation) { case OPERATION_CHECK : case OPERATION_FIX : break; default : if (import_timestamp != 0 || import_content != 0) { /* LCOV_EXCL_START */ log_fatal("You cannot import with the '%s' command\n", command); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } switch (operation) { case OPERATION_LIST : case OPERATION_DUP : case OPERATION_STATUS : case OPERATION_REWRITE : case OPERATION_READ : case OPERATION_REHASH : case OPERATION_SPINUP : /* we want to do it in different threads to avoid blocking */ /* avoid to check and access data disks if not needed */ opt.skip_disk_access = 1; break; } switch (operation) { case OPERATION_DIFF : case OPERATION_LIST : case OPERATION_DUP : case OPERATION_POOL : case OPERATION_STATUS : case OPERATION_REWRITE : case OPERATION_READ : case OPERATION_REHASH : case OPERATION_NANO : case OPERATION_SPINUP : /* we want to do it in different threads to avoid blocking */ /* avoid to check and access parity disks if not needed */ opt.skip_parity_access = 1; break; } switch (operation) { case OPERATION_FIX : case OPERATION_CHECK : /* avoid to stop processing if a content file is not accessible */ opt.skip_content_access = 1; break; } switch (operation) { case OPERATION_DIFF : case OPERATION_LIST : case OPERATION_DUP : case OPERATION_POOL : case OPERATION_NANO : case OPERATION_SPINUP : case OPERATION_SPINDOWN : case OPERATION_DEVICES : case OPERATION_SMART : opt.skip_self = 1; break; } switch (operation) { case OPERATION_DEVICES : case OPERATION_SMART : /* we may need to use these commands during operations */ opt.skip_lock = 1; break; } /* open the log file */ log_open(log_file); /* print generic info into the log */ t = time(0); tm = localtime(&t); log_tag("version:%s\n", PACKAGE_VERSION); log_tag("unixtime:%" PRIi64 "\n", (int64_t)t); if (tm) { char datetime[64]; strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", tm); log_tag("time:%s\n", datetime); } log_tag("command:%s\n", command); for (i = 0; i < argc; ++i) log_tag("argv:%u:%s\n", i, argv[i]); log_flush(); if (!opt.skip_self) selftest(); state_init(&state); /* read the configuration file */ state_config(&state, conf, command, &opt, &filterlist_disk); /* set the raid mode */ raid_mode(state.raid_mode); #if HAVE_LOCKFILE /* create the lock file */ if (!opt.skip_lock && state.lockfile[0]) { lock = lock_lock(state.lockfile); if (lock == -1) { /* LCOV_EXCL_START */ if (errno != EWOULDBLOCK) { log_fatal("Error creating the lock file '%s'. %s.\n", state.lockfile, strerror(errno)); } else { log_fatal("The lock file '%s' is already locked!\n", state.lockfile); log_fatal("SnapRAID is already in use!\n"); } exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } #else (void)lock; #endif if (operation == OPERATION_DIFF) { state_read(&state); ret = state_diff(&state); /* abort if sync needed */ if (ret > 0) exit(EXIT_SYNC_NEEDED); } else if (operation == OPERATION_SYNC) { /* in the next state read ensures to clear all the past hashes in case */ /* we are reading from an incomplete sync */ /* The undeterminated hash are only for CHG/DELETED blocks for which we don't */ /* know if the previous interrupted sync was able to update or not the parity. */ /* The sync process instead needs to trust this information because it's used */ /* to avoid to recompute the parity if all the input are equals as before. */ /* In these cases we don't know if the old state is still the one */ /* stored inside the parity, because after an aborted sync, the parity */ /* may be or may be not have been updated with the data that may be now */ /* deleted. Then we reset the hash to a bogus value. */ /* An example for CHG blocks is: */ /* - One file is added creating a CHG block with ZERO state */ /* - Sync aborted after updating the parity to the new state, */ /* but without saving the content file representing this new BLK state. */ /* - File is now deleted after the aborted sync */ /* - Sync again, deleting the blocks overt the CHG ones */ /* with the hash of CHG blocks not represeting the real parity state */ /* An example for DELETED blocks is: */ /* - One file is deleted creating DELETED blocks */ /* - Sync aborted after, updating the parity to the new state, */ /* but without saving the content file representing this new EMPTY state. */ /* - Another file is added again over the DELETE ones */ /* with the hash of DELETED blocks not represeting the real parity state */ state.clear_past_hash = 1; state_read(&state); state_scan(&state); /* refresh the size info before the content write */ state_refresh(&state); memory(); /* intercept signals while operating */ signal_init(); /* save the new state before the sync */ /* this allow to recover the case of the changes in the array after an aborted sync. */ /* for example, think at this case: */ /* - add some files at the array */ /* - run a sync command, it will recompute the parity adding the new files */ /* - abort the sync command before it stores the new content file */ /* - delete the not yet synced files from the array */ /* - run a new sync command */ /* the new sync command has now way to know that the parity file was modified */ /* because the files triggering these changes are now deleted */ /* and they aren't listed in the content file */ if (state.need_write) state_write(&state); /* run a test command if required */ if (run != 0) { ret = system(run); /* ignore error */ if (ret != 0) { /* LCOV_EXCL_START */ log_fatal("Error in running command '%s'.\n", run); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } /* waits some time to ensure that any concurrent modification done at the files, */ /* using the same mtime read by the scan process, will be read by sync. */ /* Note that any later modification done, potentially not read by sync, will have */ /* a different mtime, and it will be syncronized at the next sync. */ /* The worst case is the FAT filesystem with a two seconds resolution for mtime. */ /* If you don't use FAT, the wait is not needed, because most filesystems have now */ /* at least microseconds resolution, but better to be safe. */ if (!opt.skip_self) sleep(2); ret = state_sync(&state, blockstart, blockcount); /* save the new state if required */ if (!opt.kill_after_sync && (state.need_write || state.opt.force_content_write)) state_write(&state); /* abort if required */ if (ret != 0) { /* LCOV_EXCL_START */ exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } else if (operation == OPERATION_DRY) { state_read(&state); /* filter */ state_skip(&state); state_filter(&state, &filterlist_file, &filterlist_disk, filter_missing, filter_error); memory(); /* intercept signals while operating */ signal_init(); state_dry(&state, blockstart, blockcount); } else if (operation == OPERATION_REHASH) { state_read(&state); /* intercept signals while operating */ signal_init(); state_rehash(&state); /* save the new state if required */ if (state.need_write) state_write(&state); } else if (operation == OPERATION_SCRUB) { state_read(&state); memory(); /* intercept signals while operating */ signal_init(); ret = state_scrub(&state, plan, olderthan); /* save the new state if required */ if (state.need_write || state.opt.force_content_write) state_write(&state); /* abort if required */ if (ret != 0) { /* LCOV_EXCL_START */ exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } else if (operation == OPERATION_REWRITE) { state_read(&state); /* intercept signals while operating */ signal_init(); state_write(&state); memory(); } else if (operation == OPERATION_READ) { state_read(&state); memory(); } else if (operation == OPERATION_NANO) { state_read(&state); state_nano(&state); /* intercept signals while operating */ signal_init(); state_write(&state); memory(); } else if (operation == OPERATION_SPINUP) { state_device(&state, DEVICE_UP); } else if (operation == OPERATION_SPINDOWN) { state_device(&state, DEVICE_DOWN); } else if (operation == OPERATION_DEVICES) { state_device(&state, DEVICE_LIST); } else if (operation == OPERATION_SMART) { state_device(&state, DEVICE_SMART); } else if (operation == OPERATION_STATUS) { state_read(&state); memory(); state_status(&state); } else if (operation == OPERATION_DUP) { state_read(&state); state_dup(&state); } else if (operation == OPERATION_LIST) { state_read(&state); state_list(&state); } else if (operation == OPERATION_POOL) { state_read(&state); state_pool(&state); } else { state_read(&state); /* if we are also trying to recover */ if (!state.opt.auditonly) { /* import the user specified dirs */ if (import_timestamp != 0) state_search(&state, import_timestamp); if (import_content != 0) state_import(&state, import_content); /* import from all the array */ if (!state.opt.force_nocopy) state_search_array(&state); } /* filter */ state_skip(&state); state_filter(&state, &filterlist_file, &filterlist_disk, filter_missing, filter_error); memory(); /* intercept signals while operating */ signal_init(); if (operation == OPERATION_CHECK) { ret = state_check(&state, 0, blockstart, blockcount); } else { /* it's fix */ ret = state_check(&state, 1, blockstart, blockcount); } /* abort if required */ if (ret != 0) { /* LCOV_EXCL_START */ exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } /* close log file */ log_close(log_file); #if HAVE_LOCKFILE if (!opt.skip_lock && state.lockfile[0]) { if (lock_unlock(lock) == -1) { /* LCOV_EXCL_START */ log_fatal("Error closing the lock file '%s'. %s.\n", state.lockfile, strerror(errno)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } } #endif state_done(&state); tommy_list_foreach(&filterlist_file, (tommy_foreach_func*)filter_free); tommy_list_foreach(&filterlist_disk, (tommy_foreach_func*)filter_free); os_done(); return EXIT_SUCCESS; }
void test_hashlin(void) { tommy_list list; tommy_hashlin hashlin; struct object_hash* HASH; unsigned i, n; tommy_node* p; unsigned limit; unsigned count; HASH = malloc(MAX * sizeof(struct object_hash)); for(i=0;i<MAX;++i) { HASH[i].value = i; } START("hashlin stack"); limit = 10 * sqrt(MAX); for(n=0;n<limit;++n) { tommy_list_init(&list); tommy_hashlin_init(&hashlin); /* insert */ for(i=0;i<n;++i) { tommy_list_insert_head(&list, &HASH[i].node, &HASH[i]); tommy_hashlin_insert(&hashlin, &HASH[i].hashnode, &HASH[i], HASH[i].value); } count = 0; tommy_hashlin_foreach_arg(&hashlin, count_arg, &count); if (count != n) abort(); /* remove */ p = tommy_list_head(&list); while (p) { struct object_hash* obj = p->data; p = p->next; tommy_hashlin_remove_existing(&hashlin, &obj->hashnode); } tommy_hashlin_done(&hashlin); } STOP(); START("hashlin queue"); limit = sqrt(MAX) / 8; for(n=0;n<limit;++n) { tommy_list_init(&list); tommy_hashlin_init(&hashlin); /* insert first run */ for(i=0;i<n;++i) { tommy_list_insert_head(&list, &HASH[i].node, &HASH[i]); tommy_hashlin_insert(&hashlin, &HASH[i].hashnode, &HASH[i], HASH[i].value); } count = 0; tommy_hashlin_foreach_arg(&hashlin, count_arg, &count); if (count != n) abort(); /* insert all the others */ for(;i<MAX;++i) { struct object_hash* obj; /* insert one */ tommy_list_insert_head(&list, &HASH[i].node, &HASH[i]); tommy_hashlin_insert(&hashlin, &HASH[i].hashnode, &HASH[i], HASH[i].value); /* remove one */ p = tommy_list_head(&list); obj = p->data; tommy_list_remove_existing(&list, p); tommy_hashlin_remove_existing(&hashlin, &obj->hashnode); } /* remove remaining */ p = tommy_list_head(&list); while (p) { struct object_hash* obj = p->data; p = p->next; tommy_hashlin_remove_existing(&hashlin, &obj->hashnode); } tommy_hashlin_done(&hashlin); } STOP(); }