Changeset d1d355f in mainline
- Timestamp:
- 2025-05-06T21:30:30Z (5 weeks ago)
- Children:
- c2f0160
- Parents:
- 40f56a4
- Location:
- uspace
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/hrctl/hrctl.c
r40f56a4 rd1d355f 43 43 #include <str_error.h> 44 44 45 #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" 45 /* #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" */ 46 47 #define NAME "hrctl" 46 48 47 49 static void usage(void); 48 static errno_t fill_config_devs(int, char **, int,hr_config_t *);50 static errno_t fill_config_devs(int, char **, hr_config_t *); 49 51 static errno_t load_config(const char *, hr_config_t *); 50 52 51 53 static const char usage_str[] = 52 "Usage: hrctl [OPTION]... -n <dev_no> <devices>...\n"54 "Usage: hrctl [OPTION]...\n" 53 55 "\n" 54 56 "Options:\n" 55 " -h, --help display this message and exit\n"56 " -C, --create-file=PATH create an array from file,\n"57 " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n"58 " -A, --auto-assemble try to auto assemble all valid arrays\n"59 " -s, --status display status of active arrays\n"60 " -H, --hotspare=DEV add hotspare extent\n"61 " - D, --destroy destroy/disassemble an active array\n"62 " -F, --fail-extent fail an extent, use with -D and set it before\n"63 " -c, --create=NAME create new array\n"64 " -a, --assemble try to assemble from specified extents\n"65 " -n non-zero number of devices\n"66 " - l, --level=LEVEL set the RAID level,\n"67 " valid values: 0, 1, 4, 5\n"68 " -0 striping\n"69 " -1 mirroring\n"70 " - 4 parity on one extent\n"71 " -5 distributed parity\n"72 " \n"73 " When specifying name for creation or assembly, the device name\n"74 " is automatically prepended with \"devices/\" prefix.\n"57 " -h, --help Display this message and exit.\n" 58 "\n" 59 " -c, --create Create a volume, options:\n" 60 " name {-l , --level level} device... manual device specification, or\n" 61 " -f configuration.sif create from configuration file.\n" 62 "\n" 63 " -a, --assemble Assemble volume(s), options:\n" 64 " [device...] manual device specification, or\n" 65 " [-f configuration.sif] assemble from configuration file, or\n" 66 " no option is automatic assembly.\n" 67 "\n" 68 " -d, --disassemble Deactivate/disassemble, options:\n" 69 " [volume] specific volume, or\n" 70 " all volumes with no specified option.\n" 71 "\n" 72 " -m, --modify volume Modify a volume, options:\n" 73 " -f, --fail index fail an extent, or\n" 74 " -h, --hotspare device add hotspare.\n" 75 "\n" 76 " -s, --status Display status of active volumes.\n" 75 77 "\n" 76 78 "Example usage:\n" 77 " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" 78 " - creates new mirroring RAID device named /hr0 consisting\n" 79 " of 2 drives\n" 80 " hrctl --assemble -n 2 devices/\\hw\\0 devices/\\hw\\1\n" 81 " - assembles RAID devices from specified extents,\n" 82 " that were previously in an (active) array\n" 83 " hrctl devices/hr0 --hotspare=devices/disk10\n" 84 " - adds \"devices/disk10\" as hotspare extent\n" 85 " hrctl -F 0 -D devices/hr0\n" 86 " - marks first extent as FAILED\n" 79 "\t\thrctl --create hr0 --level 5 disk1 disk2 disk3\n" 80 "\t\thrctl -c hr0 -l 5 disk1 disk2 disk3\n" 81 "\t\thrctl -c -f cfg.sif\n" 82 "\t\thrctl --assemble disk1 disk2 disk3\n" 83 "\t\thrctl -a\n" 84 "\t\thrctl -d devices/hr0\n" 85 "\t\thrctl -d\n" 86 "\t\thrctl --modify devices/hr0 --fail 0\n" 87 "\t\thrctl --modify devices/hr0 --hotspare disk4\n" 88 "\t\thrctl -s\n" 89 "\n" 90 "Volume service names are automatically prepended with \"devices/\" prefix.\n" 91 "\n" 87 92 "Limitations:\n" 88 " - device name must be less than 32 characters in size\n"; 89 90 static struct option const long_options[] = { 91 { "help", no_argument, 0, 'h' }, 92 { "status", no_argument, 0, 's' }, 93 { "assemble", no_argument, 0, 'a' }, 94 { "create", required_argument, 0, 'c' }, 95 { "level", required_argument, 0, 'l' }, 96 { "create-file", required_argument, 0, 'C' }, 97 { "auto-assemble", no_argument, 0, 'A' }, 98 { "destroy", required_argument, 0, 'D' }, 99 { "fail-extent", required_argument, 0, 'F' }, 100 { "hotspare", required_argument, 0, 'H' }, 101 { 0, 0, 0, 0 } 102 }; 93 "\t- volume name must be shorter than 32 characters\n"; 103 94 104 95 static void usage(void) … … 107 98 } 108 99 109 static errno_t fill_config_devs(int argc, char **argv, int optind, 110 hr_config_t *cfg) 100 static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg) 111 101 { 112 102 errno_t rc; 113 103 size_t i; 114 104 115 for (i = 0; i < cfg->dev_no; i++) {105 for (i = 0; i < HR_MAX_EXTENTS; i++) { 116 106 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0); 117 107 if (rc == ENOENT) { 118 printf( "hrctl: no device \"%s\", marking as missing\n",108 printf(NAME ": device \"%s\" not found, aborting\n", 119 109 argv[optind]); 120 cfg->devs[i] = 0;110 return ENOENT; 121 111 } else if (rc != EOK) { 122 printf( "hrctl: error resolving device \"%s\", aborting\n",112 printf(NAME ": error resolving device \"%s\", aborting\n", 123 113 argv[optind]); 124 114 return EINVAL; 125 115 } 126 116 127 optind++; 128 } 117 if (++optind >= argc) 118 break; 119 } 120 121 if (optind < argc) { 122 printf(NAME ": too many devices specified, max = %u\n", 123 HR_MAX_EXTENTS); 124 return ELIMIT; 125 } 126 127 cfg->dev_no = i; 129 128 130 129 return EOK; … … 226 225 } 227 226 227 static int handle_create(int argc, char **argv) 228 { 229 if (optind >= argc) { 230 printf(NAME ": no arguments to --create\n"); 231 return EXIT_FAILURE; 232 } 233 234 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); 235 if (vol_config == NULL) { 236 printf(NAME ": not enough memory"); 237 return ENOMEM; 238 } 239 240 if (str_cmp(argv[optind], "-f") == 0) { 241 if (++optind >= argc) { 242 printf(NAME ": not enough arguments\n"); 243 goto error; 244 } 245 const char *config_path = argv[optind++]; 246 errno_t rc = load_config(config_path, vol_config); 247 if (rc != EOK) { 248 printf(NAME ": config parsing failed\n"); 249 goto error; 250 } 251 } else { 252 /* we need name + --level + arg + at least one extent */ 253 if (optind + 3 >= argc) { 254 printf(NAME ": not enough arguments\n"); 255 goto error; 256 } 257 258 const char *name = argv[optind++]; 259 if (str_size(name) >= HR_DEVNAME_LEN) { 260 printf(NAME ": devname must be less then 32 bytes.\n"); 261 goto error; 262 } 263 264 str_cpy(vol_config->devname, HR_DEVNAME_LEN, name); 265 266 const char *level_opt = argv[optind++]; 267 if (str_cmp(level_opt, "--level") != 0 && 268 str_cmp(level_opt, "-l") != 0) { 269 printf(NAME ": unknown option \"%s\"\n", level_opt); 270 goto error; 271 } 272 273 vol_config->level = strtol(argv[optind++], NULL, 10); 274 275 errno_t rc = fill_config_devs(argc, argv, vol_config); 276 if (rc != EOK) 277 goto error; 278 } 279 280 if (optind < argc) { 281 printf(NAME ": unexpected arguments\n"); 282 goto error; 283 } 284 285 hr_t *hr; 286 errno_t rc = hr_sess_init(&hr); 287 if (rc != EOK) { 288 printf(NAME ": server session init failed: %s\n", 289 str_error(rc)); 290 goto error; 291 } 292 293 rc = hr_create(hr, vol_config); 294 if (rc != EOK) { 295 printf(NAME ": creation failed: %s\n", 296 str_error(rc)); 297 goto error; 298 } 299 300 hr_sess_destroy(hr); 301 302 free(vol_config); 303 return EXIT_SUCCESS; 304 error: 305 free(vol_config); 306 return EXIT_FAILURE; 307 } 308 309 static int handle_assemble(int argc, char **argv) 310 { 311 if (optind >= argc) { 312 size_t cnt; 313 errno_t rc = hr_auto_assemble(&cnt); 314 if (rc != EOK) { 315 /* XXX: here have own error codes */ 316 printf("hrctl: auto assemble rc: %s\n", str_error(rc)); 317 return EXIT_FAILURE; 318 } 319 320 printf(NAME ": auto assembled %zu volumes\n", cnt); 321 return EXIT_SUCCESS; 322 } 323 324 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); 325 if (vol_config == NULL) { 326 printf(NAME ": not enough memory"); 327 return ENOMEM; 328 } 329 330 if (str_cmp(argv[optind], "-f") == 0) { 331 if (++optind >= argc) { 332 printf(NAME ": not enough arguments\n"); 333 goto error; 334 } 335 const char *config_path = argv[optind++]; 336 errno_t rc = load_config(config_path, vol_config); 337 if (rc != EOK) { 338 printf(NAME ": config parsing failed\n"); 339 goto error; 340 } 341 if (optind < argc) { 342 printf(NAME ": unexpected arguments\n"); 343 goto error; 344 } 345 } else { 346 errno_t rc = fill_config_devs(argc, argv, vol_config); 347 if (rc != EOK) 348 goto error; 349 } 350 351 hr_t *hr; 352 errno_t rc = hr_sess_init(&hr); 353 if (rc != EOK) { 354 printf(NAME ": server session init failed: %s\n", 355 str_error(rc)); 356 goto error; 357 } 358 359 size_t cnt; 360 rc = hr_assemble(hr, vol_config, &cnt); 361 if (rc != EOK) { 362 printf(NAME ": assmeble failed: %s\n", str_error(rc)); 363 goto error; 364 } 365 366 printf("hrctl: auto assembled %zu volumes\n", cnt); 367 368 hr_sess_destroy(hr); 369 370 free(vol_config); 371 return EXIT_SUCCESS; 372 error: 373 free(vol_config); 374 return EXIT_FAILURE; 375 } 376 377 static int handle_disassemble(int argc, char **argv) 378 { 379 if (optind >= argc) { 380 errno_t rc = hr_stop_all(); 381 if (rc != EOK) { 382 printf(NAME ": stopping some volumes failed: %s\n", 383 str_error(rc)); 384 return EXIT_FAILURE; 385 } 386 return EXIT_SUCCESS; 387 } 388 389 if (optind + 1 < argc) { 390 printf(NAME ": only 1 device can be manually specified\n"); 391 return EXIT_FAILURE; 392 } 393 394 const char *devname = argv[optind++]; 395 396 errno_t rc = hr_stop(devname); 397 if (rc != EOK) { 398 printf(NAME ": disassembly of device \"%s\" failed: %s\n", 399 devname, str_error(rc)); 400 return EXIT_FAILURE; 401 } 402 403 return EXIT_SUCCESS; 404 } 405 406 static int handle_modify(int argc, char **argv) 407 { 408 if (optind >= argc) { 409 printf(NAME ": no arguments to --modify\n"); 410 return EXIT_FAILURE; 411 } 412 413 const char *volname = argv[optind++]; 414 415 /* at least 1 option and its agument */ 416 if (optind + 1 >= argc) { 417 printf(NAME ": not enough arguments\n"); 418 return EXIT_FAILURE; 419 } 420 421 if (optind + 2 < argc) { 422 printf(NAME ": unexpected arguments\n"); 423 return EXIT_FAILURE; 424 } 425 426 if (str_cmp(argv[optind], "--fail") == 0 || 427 str_cmp(argv[optind], "-f") == 0) { 428 optind++; 429 unsigned long extent = strtol(argv[optind++], NULL, 10); 430 errno_t rc = hr_fail_extent(volname, extent); 431 if (rc != EOK) { 432 printf(NAME ": failing extent failed: %s\n", 433 str_error(rc)); 434 return EXIT_FAILURE; 435 } 436 } else if (str_cmp(argv[optind], "--hotspare") == 0 || 437 str_cmp(argv[optind], "-h") == 0) { 438 optind++; 439 errno_t rc = hr_add_hotspare(volname, argv[optind++]); 440 if (rc != EOK) { 441 printf(NAME ": adding hotspare failed: %s\n", 442 str_error(rc)); 443 return EXIT_FAILURE; 444 } 445 } else { 446 printf(NAME ": unknown argument\n"); 447 return EXIT_FAILURE; 448 } 449 450 return EXIT_SUCCESS; 451 } 452 453 static int handle_status(int argc, char **argv) 454 { 455 (void)argc; 456 (void)argv; 457 458 errno_t rc = hr_print_status(); 459 if (rc != EOK) { 460 printf(NAME ": status printing failed: %s\n", str_error(rc)); 461 return EXIT_FAILURE; 462 } 463 464 return EXIT_SUCCESS; 465 } 466 228 467 int main(int argc, char **argv) 229 468 { 230 errno_t rc; 231 int retval, c; 232 bool create, assemble; 233 long fail_extent = -1; 234 hr_t *hr = NULL; 235 hr_config_t *cfg; 236 237 cfg = calloc(1, sizeof(hr_config_t)); 238 if (cfg == NULL) 239 return 1; 240 241 retval = 0; 242 cfg->level = HR_LVL_UNKNOWN; 243 cfg->dev_no = 0; 244 create = assemble = false; 469 int rc = EXIT_SUCCESS; 470 int c; 245 471 246 472 if (argc < 2) { 247 goto bad; 473 rc = EXIT_FAILURE; 474 goto end; 248 475 } 249 476 … … 252 479 optind = 0; 253 480 481 struct option const top_level_opts[] = { 482 { "help", no_argument, 0, 'h' }, 483 { "create", no_argument, 0, 'c' }, 484 { "assemble", no_argument, 0, 'a' }, 485 { "disassemble", no_argument, 0, 'd' }, 486 { "modify", no_argument, 0, 'm' }, 487 { "status", no_argument, 0, 's' }, 488 { 0, 0, 0, 0 } 489 }; 490 254 491 while (c != -1) { 255 c = getopt_long(argc, argv, "hsC:c:Aal:0145Ln:D:F:H:", 256 long_options, NULL); 492 c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); 257 493 switch (c) { 494 case 'h': 495 usage(); 496 return EXIT_SUCCESS; 497 case 'c': 498 rc = handle_create(argc, argv); 499 goto end; 500 case 'a': 501 rc = handle_assemble(argc, argv); 502 goto end; 503 case 'd': 504 rc = handle_disassemble(argc, argv); 505 goto end; 506 case 'm': 507 rc = handle_modify(argc, argv); 508 goto end; 258 509 case 's': 259 free(cfg); 260 rc = hr_print_status(); 261 if (rc != EOK) 262 return 1; 263 return 0; 264 case 'C': 265 /* only support 1 array inside config for now XXX */ 266 rc = load_config(optarg, cfg); 267 if (rc != EOK) { 268 printf("hrctl: failed to load config\n"); 269 free(cfg); 270 return 1; 271 } 272 create = true; 273 goto skip; 274 case 'c': 275 if (str_size(optarg) > sizeof(cfg->devname) - 1) { 276 printf("hrctl: device name too long\n"); 277 free(cfg); 278 return 1; 279 } 280 str_cpy(cfg->devname, sizeof(cfg->devname), optarg); 281 create = true; 282 break; 283 case 'A': 284 size_t cnt; 285 rc = hr_auto_assemble(&cnt); 286 if (rc != EOK) { 287 /* XXX: here have own error codes */ 288 printf("hrctl: auto assemble rc: %s\n", 289 str_error(rc)); 290 } else { 291 printf("hrctl: auto assembled %zu volumes\n", 292 cnt); 293 } 294 return rc; 295 case 'a': 296 /* 297 * XXX: redo this, no devname, only svc ids... 298 * 299 * find some other way to rename the arrays..., 300 * 301 * some metadata editation tool... something like 302 * fdisk but can only change devnames on inactive 303 * extents... 304 */ 305 306 /* 307 * XXX: remake whole parsing, don't allow -a 308 * to have any levels set or anything 309 */ 310 assemble = true; 311 break; 312 case 'D': 313 rc = hr_stop(optarg, fail_extent); 314 free(cfg); 315 if (rc != EOK) { 316 printf("hrctl: got %s\n", str_error(rc)); 317 return rc; 318 } 319 return 0; 320 case 'F': 321 fail_extent = strtol(optarg, NULL, 10); 322 break; 323 case 'l': 324 if (cfg->level != HR_LVL_UNKNOWN) 325 goto bad; 326 cfg->level = strtol(optarg, NULL, 10); 327 break; 328 case '0': 329 if (cfg->level != HR_LVL_UNKNOWN) 330 goto bad; 331 cfg->level = HR_LVL_0; 332 break; 333 case '1': 334 if (cfg->level != HR_LVL_UNKNOWN) 335 goto bad; 336 cfg->level = HR_LVL_1; 337 break; 338 case '4': 339 if (cfg->level != HR_LVL_UNKNOWN) 340 goto bad; 341 cfg->level = HR_LVL_4; 342 break; 343 case '5': 344 if (cfg->level != HR_LVL_UNKNOWN) 345 goto bad; 346 cfg->level = HR_LVL_5; 347 break; 348 case 'n': 349 cfg->dev_no = strtol(optarg, NULL, 10); 350 if ((int)cfg->dev_no + optind != argc) 351 goto bad; 352 rc = fill_config_devs(argc, argv, optind, cfg); 353 if (rc != EOK) { 354 free(cfg); 355 return 1; 356 } 357 goto skip; 358 case 'H': 359 if (optind != 3 && argc != 4) 360 goto bad; 361 362 service_id_t hotspare; 363 service_id_t vol_svc_id; 364 365 rc = loc_service_get_id(argv[1], &vol_svc_id, 0); 366 if (rc != EOK) { 367 printf("hrctl: error resolving volume \"%s\", " 368 "aborting extent addition\n", argv[1]); 369 goto bad; 370 } 371 372 rc = loc_service_get_id(optarg, &hotspare, 0); 373 if (rc != EOK) { 374 printf("hrctl: error resolving device \"%s\", " 375 "aborting extent addition\n", optarg); 376 goto bad; 377 } 378 379 rc = hr_add_hotspare(vol_svc_id, hotspare); 380 if (rc != EOK) 381 printf("hrctl: hr_add_hotspare() rc: %s\n", 382 str_error(rc)); 383 384 free(cfg); 385 if (rc != EOK) 386 return 1; 387 else 388 return 0; 389 case 'h': 510 rc = handle_status(argc, argv); 511 goto end; 390 512 default: 391 usage(); 392 free(cfg); 393 return 0; 394 } 395 } 396 397 skip: 398 if ((create && assemble) || (!create && !assemble)) 399 goto bad; 400 401 if (create && cfg->level == HR_LVL_UNKNOWN) { 402 printf("hrctl: invalid level, exiting\n"); 403 goto bad; 404 } 405 406 if (cfg->dev_no > HR_MAX_EXTENTS) { 407 printf("hrctl: too many devices, exiting\n"); 408 goto bad; 409 } 410 411 if (cfg->dev_no == 0) { 412 printf("hrctl: invalid number of devices, exiting\n"); 413 goto bad; 414 } 415 416 rc = hr_sess_init(&hr); 417 if (rc != EOK) { 418 printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc)); 419 retval = 1; 420 goto end; 421 } 422 423 if (create) { 424 rc = hr_create(hr, cfg); 425 printf("hrctl: hr_create() rc: %s\n", str_error(rc)); 426 } else if (assemble) { 427 size_t assembled_cnt = 0; 428 rc = hr_assemble(hr, cfg, &assembled_cnt); 429 if (rc != EOK) { 430 /* XXX: here have own error codes */ 431 printf("hrctl: auto assemble rc: %s\n", str_error(rc)); 432 } else { 433 printf("hrctl: auto assembled %zu volumes\n", 434 assembled_cnt); 435 } 436 513 goto end; 514 } 437 515 } 438 516 439 517 end: 440 free(cfg); 441 hr_sess_destroy(hr); 442 return retval; 443 bad: 444 free(cfg); 445 printf("hrctl: bad usage, try hrctl --help\n"); 446 return 1; 518 if (rc != EXIT_SUCCESS) 519 printf(NAME ": use --help to see usage\n"); 520 return rc; 447 521 } 448 522 -
uspace/lib/device/include/hr.h
r40f56a4 rd1d355f 125 125 extern errno_t hr_assemble(hr_t *, hr_config_t *, size_t *); 126 126 extern errno_t hr_auto_assemble(size_t *); 127 extern errno_t hr_stop(const char *, long); 128 extern errno_t hr_add_hotspare(service_id_t, service_id_t); 127 extern errno_t hr_stop(const char *); 128 extern errno_t hr_stop_all(void); 129 extern errno_t hr_fail_extent(const char *, unsigned long); 130 extern errno_t hr_add_hotspare(const char *, const char *); 129 131 extern errno_t hr_print_status(void); 130 132 extern const char *hr_get_vol_status_msg(hr_vol_status_t); -
uspace/lib/device/include/ipc/hr.h
r40f56a4 rd1d355f 43 43 HR_AUTO_ASSEMBLE, 44 44 HR_STOP, 45 HR_STOP_ALL, 46 HR_FAIL_EXTENT, 45 47 HR_ADD_HOTSPARE, 46 48 HR_STATUS -
uspace/lib/device/src/hr.c
r40f56a4 rd1d355f 109 109 async_exchange_end(exch); 110 110 async_wait_for(req, &retval); 111 if (retval != EOK) 112 return retval; 113 114 return EOK; 111 return retval; 115 112 } 116 113 … … 269 266 } 270 267 271 errno_t hr_stop(const char *devname , long extent)268 errno_t hr_stop(const char *devname) 272 269 { 273 270 hr_t *hr; … … 289 286 goto error; 290 287 } 291 rc = async_req_2_0(exch, HR_STOP, svc_id, extent); 288 289 rc = async_req_1_0(exch, HR_STOP, svc_id); 292 290 async_exchange_end(exch); 293 291 error: … … 296 294 } 297 295 298 errno_t hr_ add_hotspare(service_id_t vol_svc_id, service_id_t hs_svc_id)296 errno_t hr_stop_all(void) 299 297 { 300 298 hr_t *hr; 301 errno_t rc; 302 async_exch_t *exch; 299 async_exch_t *exch; 300 errno_t rc; 301 302 rc = hr_sess_init(&hr); 303 if (rc != EOK) 304 return rc; 305 306 exch = async_exchange_begin(hr->sess); 307 if (exch == NULL) { 308 rc = EINVAL; 309 goto error; 310 } 311 312 rc = async_req_0_0(exch, HR_STOP_ALL); 313 async_exchange_end(exch); 314 error: 315 hr_sess_destroy(hr); 316 return rc; 317 } 318 319 errno_t hr_fail_extent(const char *volume_name, unsigned long extent) 320 { 321 hr_t *hr; 322 errno_t rc; 323 async_exch_t *exch; 324 service_id_t vol_svc_id; 325 326 rc = loc_service_get_id(volume_name, &vol_svc_id, 0); 327 if (rc != EOK) 328 return rc; 329 330 rc = hr_sess_init(&hr); 331 if (rc != EOK) 332 return rc; 333 334 exch = async_exchange_begin(hr->sess); 335 if (exch == NULL) { 336 rc = EINVAL; 337 goto error; 338 } 339 340 rc = async_req_2_0(exch, HR_FAIL_EXTENT, vol_svc_id, extent); 341 async_exchange_end(exch); 342 error: 343 hr_sess_destroy(hr); 344 return rc; 345 } 346 347 errno_t hr_add_hotspare(const char *volume_name, const char *hotspare) 348 { 349 hr_t *hr; 350 errno_t rc; 351 async_exch_t *exch; 352 service_id_t vol_svc_id, hs_svc_id; 353 354 rc = loc_service_get_id(volume_name, &vol_svc_id, 0); 355 if (rc != EOK) 356 return rc; 357 358 rc = loc_service_get_id(hotspare, &hs_svc_id, 0); 359 if (rc != EOK) 360 return rc; 303 361 304 362 rc = hr_sess_init(&hr); -
uspace/srv/bd/hr/hr.c
r40f56a4 rd1d355f 61 61 static void hr_auto_assemble_srv(ipc_call_t *); 62 62 static void hr_stop_srv(ipc_call_t *); 63 static void hr_stop_all_srv(ipc_call_t *); 63 64 static void hr_add_hotspare_srv(ipc_call_t *); 64 65 static void hr_print_status_srv(ipc_call_t *); … … 163 164 fibril_rwlock_write_unlock(&hr_volumes_lock); 164 165 165 HR_DEBUG("created volume \"%s\" (%" PRIun ")\n", vol->devname, 166 vol->svc_id); 166 HR_NOTE("created volume \"%s\"\n", vol->devname); 167 167 168 168 free(cfg); … … 275 275 errno_t rc = EOK; 276 276 service_id_t svc_id; 277 long fail_extent;278 277 hr_volume_t *vol; 279 278 280 279 svc_id = ipc_get_arg1(icall); 281 fail_extent = (long)ipc_get_arg2(icall);282 280 283 281 vol = hr_get_volume(svc_id); … … 287 285 } 288 286 289 if (fail_extent == -1) { 290 rc = hr_remove_volume(svc_id); 291 if (rc != EOK) { 292 async_answer_0(icall, rc); 293 return; 287 rc = hr_remove_volume(vol); 288 289 async_answer_0(icall, rc); 290 } 291 292 static void hr_stop_all_srv(ipc_call_t *icall) 293 { 294 HR_DEBUG("%s()", __func__); 295 296 hr_volume_t *vol; 297 errno_t rc = EOK; 298 299 while (true) { 300 fibril_rwlock_write_lock(&hr_volumes_lock); 301 if (list_empty(&hr_volumes)) { 302 fibril_rwlock_write_unlock(&hr_volumes_lock); 303 break; 294 304 } 295 } else { 296 fibril_rwlock_write_lock(&vol->states_lock); 297 fibril_rwlock_read_lock(&vol->extents_lock); 298 299 /* TODO: maybe expose extent state callbacks */ 300 hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); 301 hr_mark_vol_state_dirty(vol); 302 303 fibril_rwlock_read_unlock(&vol->extents_lock); 304 fibril_rwlock_write_unlock(&vol->states_lock); 305 306 vol->hr_ops.status_event(vol); 307 } 308 async_answer_0(icall, rc); 305 306 vol = list_pop(&hr_volumes, hr_volume_t, lvolumes); 307 308 fibril_rwlock_write_unlock(&hr_volumes_lock); 309 310 rc = hr_remove_volume(vol); 311 if (rc != EOK) 312 break; 313 } 314 315 async_answer_0(icall, rc); 316 } 317 318 static void hr_fail_extent_srv(ipc_call_t *icall) 319 { 320 HR_DEBUG("%s()", __func__); 321 322 service_id_t svc_id; 323 size_t fail_extent; 324 hr_volume_t *vol; 325 326 svc_id = (service_id_t)ipc_get_arg1(icall); 327 fail_extent = (size_t)ipc_get_arg2(icall); 328 329 vol = hr_get_volume(svc_id); 330 if (vol == NULL) { 331 async_answer_0(icall, ENOENT); 332 return; 333 } 334 335 fibril_rwlock_write_lock(&vol->states_lock); 336 fibril_rwlock_read_lock(&vol->extents_lock); 337 338 hr_update_ext_status(vol, fail_extent, HR_EXT_FAILED); 339 hr_mark_vol_state_dirty(vol); 340 341 fibril_rwlock_read_unlock(&vol->extents_lock); 342 fibril_rwlock_write_unlock(&vol->states_lock); 343 344 vol->hr_ops.status_event(vol); 345 346 async_answer_0(icall, EOK); 309 347 } 310 348 … … 438 476 hr_stop_srv(&call); 439 477 break; 478 case HR_STOP_ALL: 479 hr_stop_all_srv(&call); 480 break; 481 case HR_FAIL_EXTENT: 482 hr_fail_extent_srv(&call); 483 break; 440 484 case HR_ADD_HOTSPARE: 441 485 hr_add_hotspare_srv(&call); -
uspace/srv/bd/hr/util.c
r40f56a4 rd1d355f 162 162 void hr_destroy_vol_struct(hr_volume_t *vol) 163 163 { 164 HR_DEBUG("%s()", __func__); 165 164 166 if (vol == NULL) 165 167 return; … … 173 175 hr_volume_t *hr_get_volume(service_id_t svc_id) 174 176 { 175 HR_DEBUG(" hr_get_volume(): (%" PRIun ")\n", svc_id);177 HR_DEBUG("%s()", __func__); 176 178 177 179 hr_volume_t *rvol = NULL; … … 189 191 } 190 192 191 errno_t hr_remove_volume(service_id_t svc_id) 192 { 193 HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); 194 195 errno_t rc; 193 errno_t hr_remove_volume(hr_volume_t *vol) 194 { 195 HR_DEBUG("%s()", __func__); 196 196 197 197 fibril_rwlock_write_lock(&hr_volumes_lock); 198 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { 199 if (vol->svc_id == svc_id) { 200 int open_cnt = atomic_load_explicit(&vol->open_cnt, 201 memory_order_relaxed); 202 /* 203 * The "atomicity" of this if condition is provided 204 * by the write lock - no new bd connection can 205 * come, because we need to get the bd_srvs_t from 206 * volume, which we get from the list. 207 * (see hr_client_conn() in hr.c) 208 */ 209 if (open_cnt > 0) { 210 fibril_rwlock_write_unlock(&hr_volumes_lock); 211 return EBUSY; 212 } 213 list_remove(&vol->lvolumes); 214 fibril_rwlock_write_unlock(&hr_volumes_lock); 215 216 vol->meta_ops->save(vol, NO_STATE_CALLBACK); 217 218 hr_destroy_vol_struct(vol); 219 220 rc = loc_service_unregister(hr_srv, svc_id); 221 return rc; 222 } 223 } 198 199 int open_cnt = atomic_load_explicit(&vol->open_cnt, 200 memory_order_relaxed); 201 /* 202 * The atomicity of this if condition (and this whole 203 * operation) is provided by the write lock - no new 204 * bd connection can come, because we need to get the 205 * bd_srvs_t from the volume, which we get from the list. 206 * (see hr_client_conn() in hr.c) 207 */ 208 if (open_cnt > 0) { 209 fibril_rwlock_write_unlock(&hr_volumes_lock); 210 return EBUSY; 211 } 212 213 list_remove(&vol->lvolumes); 224 214 225 215 fibril_rwlock_write_unlock(&hr_volumes_lock); 226 return ENOENT; 216 217 /* save metadata, but we don't care about states anymore */ 218 (void)vol->meta_ops->save(vol, NO_STATE_CALLBACK); 219 220 service_id_t svc_id = vol->svc_id; 221 222 HR_NOTE("deactivating volume \"%s\"\n", vol->devname); 223 224 hr_destroy_vol_struct(vol); 225 226 errno_t rc = loc_service_unregister(hr_srv, svc_id); 227 return rc; 227 228 } 228 229 … … 836 837 goto error; 837 838 838 fibril_rwlock_write_lock(&hr_volumes_lock);839 840 839 /* 841 840 * XXX: register it here … … 852 851 */ 853 852 rc = hr_register_volume(vol); 854 if (rc != EOK) { 855 fibril_rwlock_write_unlock(&hr_volumes_lock); 856 goto error; 857 } 853 if (rc != EOK) 854 goto error; 858 855 859 856 (void)vol->meta_ops->save(vol, WITH_STATE_CALLBACK); 860 857 858 fibril_rwlock_write_lock(&hr_volumes_lock); 861 859 list_append(&vol->lvolumes, &hr_volumes); 862 863 860 fibril_rwlock_write_unlock(&hr_volumes_lock); 861 862 HR_NOTE("assembled volume \"%s\"\n", vol->devname); 864 863 865 864 return EOK; -
uspace/srv/bd/hr/util.h
r40f56a4 rd1d355f 71 71 extern void hr_destroy_vol_struct(hr_volume_t *); 72 72 extern hr_volume_t *hr_get_volume(service_id_t); 73 extern errno_t hr_remove_volume( service_id_t);73 extern errno_t hr_remove_volume(hr_volume_t *); 74 74 extern errno_t hr_init_extents_from_cfg(hr_volume_t *, hr_config_t *); 75 75 extern void hr_fini_devs(hr_volume_t *);
Note:
See TracChangeset
for help on using the changeset viewer.