12061Sjkh// SPDX-License-Identifier: GPL-2.0-only 250479Speter/* 32061Sjkh * Copyright 2023 Red Hat 438666Sjb */ 532427Sjb 6111131Sru#include "index-session.h" 7111131Sru 8217733Sbz#include <linux/atomic.h> 9217733Sbz 1038666Sjb#include "logger.h" 1138666Sjb#include "memory-alloc.h" 1238666Sjb#include "time-utils.h" 13159363Strhodes 1464049Salex#include "funnel-requestqueue.h" 1564049Salex#include "index.h" 16116679Ssimokawa#include "index-layout.h" 1766071Smarkm 18116679Ssimokawa/* 1973504Sobrien * The index session contains a lock (the request_mutex) which ensures that only one thread can 20204661Simp * change the state of its index at a time. The state field indicates the current state of the 21158962Snetchild * index through a set of descriptive flags. The request_mutex must be notified whenever a 22223148Sru * non-transient state flag is cleared. The request_mutex is also used to count the number of 23169597Sdes * requests currently in progress so that they can be drained when suspending or closing the index. 24169597Sdes * 25169597Sdes * If the index session is suspended shortly after opening an index, it may have to suspend during 26169597Sdes * a rebuild. Depending on the size of the index, a rebuild may take a significant amount of time, 27169597Sdes * so UDS allows the rebuild to be paused in order to suspend the session in a timely manner. When 28169597Sdes * the index session is resumed, the rebuild can continue from where it left off. If the index 29169597Sdes * session is shut down with a suspended rebuild, the rebuild progress is abandoned and the rebuild 30169597Sdes * will start from the beginning the next time the index is loaded. The mutex and status fields in 31217815Sbz * the index_load_context are used to record the state of any interrupted rebuild. 32217815Sbz */ 33218524Sjhb 3432427Sjbenum index_session_flag_bit { 3538666Sjb IS_FLAG_BIT_START = 8, 36108451Sschweikh /* The session has started loading an index but not completed it. */ 3738666Sjb IS_FLAG_BIT_LOADING = IS_FLAG_BIT_START, 3838666Sjb /* The session has loaded an index, which can handle requests. */ 3938666Sjb IS_FLAG_BIT_LOADED, 4038666Sjb /* The session's index has been permanently disabled. */ 4117308Speter IS_FLAG_BIT_DISABLED, 42217273Simp /* The session's index is suspended. */ 43217294Simp IS_FLAG_BIT_SUSPENDED, 4419175Sbde /* The session is handling some index state change. */ 4596205Sjwd IS_FLAG_BIT_WAITING, 46217297Simp /* The session's index is closing and draining requests. */ 47217297Simp IS_FLAG_BIT_CLOSING, 4838042Sbde /* The session is being destroyed and is draining requests. */ 4996205Sjwd IS_FLAG_BIT_DESTROYING, 5096205Sjwd}; 5138042Sbde 5296205Sjwdenum index_session_flag { 53159363Strhodes IS_FLAG_LOADED = (1 << IS_FLAG_BIT_LOADED), 54159363Strhodes IS_FLAG_LOADING = (1 << IS_FLAG_BIT_LOADING), 5517308Speter IS_FLAG_DISABLED = (1 << IS_FLAG_BIT_DISABLED), 5696205Sjwd IS_FLAG_SUSPENDED = (1 << IS_FLAG_BIT_SUSPENDED), 5796205Sjwd IS_FLAG_WAITING = (1 << IS_FLAG_BIT_WAITING), 5817308Speter IS_FLAG_CLOSING = (1 << IS_FLAG_BIT_CLOSING), 59148330Snetchild IS_FLAG_DESTROYING = (1 << IS_FLAG_BIT_DESTROYING), 60148330Snetchild}; 61148330Snetchild 62148330Snetchild/* Release a reference to an index session. */ 63159831Sobrienstatic void release_index_session(struct uds_index_session *index_session) 64148330Snetchild{ 65148330Snetchild mutex_lock(&index_session->request_mutex); 66148330Snetchild if (--index_session->request_count == 0) 67148330Snetchild uds_broadcast_cond(&index_session->request_cond); 68220512Sdougb mutex_unlock(&index_session->request_mutex); 69148330Snetchild} 70148330Snetchild 7196205Sjwd/* 7296205Sjwd * Acquire a reference to the index session for an asynchronous index request. The reference must 7396205Sjwd * eventually be released with a corresponding call to release_index_session(). 74162147Sru */ 75162147Srustatic int get_index_session(struct uds_index_session *index_session) 7698723Sdillon{ 7798723Sdillon unsigned int state; 7898723Sdillon int result = UDS_SUCCESS; 7938666Sjb 8038666Sjb mutex_lock(&index_session->request_mutex); 8117308Speter index_session->request_count++; 82123311Speter state = index_session->state; 83123311Speter mutex_unlock(&index_session->request_mutex); 84123311Speter 85123311Speter if (state == IS_FLAG_LOADED) { 86175833Sjhb return UDS_SUCCESS; 87175833Sjhb } else if (state & IS_FLAG_DISABLED) { 88169597Sdes result = UDS_DISABLED; 89169597Sdes } else if ((state & IS_FLAG_LOADING) || 90169597Sdes (state & IS_FLAG_SUSPENDED) || 91169597Sdes (state & IS_FLAG_WAITING)) { 92219177Snwhitehorn result = -EBUSY; 93219177Snwhitehorn } else { 94158962Snetchild result = UDS_NO_INDEX; 95219177Snwhitehorn } 96219177Snwhitehorn 97158962Snetchild release_index_session(index_session); 98156840Sru return result; 99123311Speter} 100137288Speter 101209128Srajint uds_launch_request(struct uds_request *request) 102209128Sraj{ 103156740Sru size_t internal_size; 1042061Sjkh int result; 10597769Sru 10697252Sru if (request->callback == NULL) { 107119579Sru vdo_log_error("missing required callback"); 10897252Sru return -EINVAL; 10995730Sru } 11095793Sru 111111617Sru switch (request->type) { 11295730Sru case UDS_DELETE: 113116679Ssimokawa case UDS_POST: 11495730Sru case UDS_QUERY: 115116679Ssimokawa case UDS_QUERY_NO_UPDATE: 11695730Sru case UDS_UPDATE: 117110035Sru break; 118107516Sru default: 119138921Sru vdo_log_error("received invalid callback type"); 120156145Syar return -EINVAL; 121138921Sru } 122133942Sru 123133942Sru /* Reset all internal fields before processing. */ 124156145Syar internal_size = 125133942Sru sizeof(struct uds_request) - offsetof(struct uds_request, zone_number); 126110035Sru // FIXME should be using struct_group for this instead 127117234Sru memset((char *) request + sizeof(*request) - internal_size, 0, internal_size); 128110035Sru 129117229Sru result = get_index_session(request->session); 130218206Simp if (result != UDS_SUCCESS) 13154324Smarcel return result; 132218130Simp 133218130Simp request->found = false; 134221869Sattilio request->unbatched = false; 135218130Simp request->index = request->session->index; 136218130Simp 137218130Simp uds_enqueue_request(request, STAGE_TRIAGE); 138218130Simp return UDS_SUCCESS; 139218130Simp} 140218130Simp 141218130Simpstatic void enter_callback_stage(struct uds_request *request) 142218130Simp{ 143218130Simp if (request->status != UDS_SUCCESS) { 144218130Simp /* All request errors are considered unrecoverable */ 145218130Simp mutex_lock(&request->session->request_mutex); 146218130Simp request->session->state |= IS_FLAG_DISABLED; 147218130Simp mutex_unlock(&request->session->request_mutex); 148218130Simp } 149218130Simp 150218130Simp uds_request_queue_enqueue(request->session->callback_queue, request); 151218130Simp} 152218130Simp 153218130Simpstatic inline void count_once(u64 *count_ptr) 154218130Simp{ 155218130Simp WRITE_ONCE(*count_ptr, READ_ONCE(*count_ptr) + 1); 156218130Simp} 157218130Simp 158218130Simpstatic void update_session_stats(struct uds_request *request) 159218130Simp{ 160218130Simp struct session_stats *session_stats = &request->session->stats; 161218130Simp 162218130Simp count_once(&session_stats->requests); 163218130Simp 16417308Speter switch (request->type) { 165119519Smarcel case UDS_POST: 166119519Smarcel if (request->found) 167119519Smarcel count_once(&session_stats->posts_found); 168119519Smarcel else 169119519Smarcel count_once(&session_stats->posts_not_found); 170119519Smarcel 171119579Sru if (request->location == UDS_LOCATION_IN_OPEN_CHAPTER) 172119519Smarcel count_once(&session_stats->posts_found_open_chapter); 173119519Smarcel else if (request->location == UDS_LOCATION_IN_DENSE) 174119519Smarcel count_once(&session_stats->posts_found_dense); 175119519Smarcel else if (request->location == UDS_LOCATION_IN_SPARSE) 176119519Smarcel count_once(&session_stats->posts_found_sparse); 177126031Sgad break; 178126024Sgad 179126024Sgad case UDS_UPDATE: 180126024Sgad if (request->found) 181126024Sgad count_once(&session_stats->updates_found); 182126024Sgad else 183126024Sgad count_once(&session_stats->updates_not_found); 184126024Sgad break; 185227879Sgjb 186126024Sgad case UDS_DELETE: 187126024Sgad if (request->found) 188227879Sgjb count_once(&session_stats->deletions_found); 189227879Sgjb else 190227879Sgjb count_once(&session_stats->deletions_not_found); 191126024Sgad break; 192126024Sgad 193126031Sgad case UDS_QUERY: 194126024Sgad case UDS_QUERY_NO_UPDATE: 195126024Sgad if (request->found) 196126024Sgad count_once(&session_stats->queries_found); 197172744Sdelphij else 198126024Sgad count_once(&session_stats->queries_not_found); 199126024Sgad break; 200126024Sgad 201133376Sharti default: 202126024Sgad request->status = VDO_ASSERT(false, "unknown request type: %d", 203126024Sgad request->type); 204172744Sdelphij } 205126024Sgad} 206126024Sgad 207125885Sgadstatic void handle_callbacks(struct uds_request *request) 208125885Sgad{ 20938666Sjb struct uds_index_session *index_session = request->session; 21017308Speter 211119519Smarcel if (request->status == UDS_SUCCESS) 212119579Sru update_session_stats(request); 213218206Simp 2142302Spaul request->status = uds_status_to_errno(request->status); 21539206Sjkh request->callback(request); 21639206Sjkh release_index_session(index_session); 21739206Sjkh} 218133945Sru 219220556Sbzstatic int __must_check make_empty_index_session(struct uds_index_session **index_session_ptr) 220177609Sru{ 221177609Sru int result; 222177609Sru struct uds_index_session *session; 223133945Sru 224132358Smarkm result = vdo_allocate(1, struct uds_index_session, __func__, &session); 22517308Speter if (result != VDO_SUCCESS) 22654324Smarcel return result; 22754324Smarcel 228132234Smarcel mutex_init(&session->request_mutex); 229132234Smarcel uds_init_cond(&session->request_cond); 230132234Smarcel mutex_init(&session->load_context.mutex); 231132234Smarcel uds_init_cond(&session->load_context.cond); 23254324Smarcel 23354324Smarcel result = uds_make_request_queue("callbackW", &handle_callbacks, 23454324Smarcel &session->callback_queue); 235118531Sru if (result != UDS_SUCCESS) { 23654324Smarcel vdo_free(session); 23754324Smarcel return result; 23854324Smarcel } 23954324Smarcel 24054324Smarcel *index_session_ptr = session; 24154324Smarcel return UDS_SUCCESS; 242133376Sharti} 24354324Smarcel 244133376Shartiint uds_create_index_session(struct uds_index_session **session) 245133376Sharti{ 24654324Smarcel if (session == NULL) { 24754324Smarcel vdo_log_error("missing session pointer"); 24854324Smarcel return -EINVAL; 24954324Smarcel } 25054324Smarcel 251133376Sharti return uds_status_to_errno(make_empty_index_session(session)); 25254324Smarcel} 25354324Smarcel 25454324Smarcelstatic int __must_check start_loading_index_session(struct uds_index_session *index_session) 255118531Sru{ 256118531Sru int result; 25754324Smarcel 258132234Smarcel mutex_lock(&index_session->request_mutex); 259132234Smarcel if (index_session->state & IS_FLAG_SUSPENDED) { 260132234Smarcel vdo_log_info("Index session is suspended"); 261132234Smarcel result = -EBUSY; 262132234Smarcel } else if (index_session->state != 0) { 263132588Skensmith vdo_log_info("Index is already loaded"); 264132358Smarkm result = -EBUSY; 265132234Smarcel } else { 266132358Smarkm index_session->state |= IS_FLAG_LOADING; 267132234Smarcel result = UDS_SUCCESS; 268132234Smarcel } 269132234Smarcel mutex_unlock(&index_session->request_mutex); 27054324Smarcel return result; 27154324Smarcel} 27295730Sru 27395730Srustatic void finish_loading_index_session(struct uds_index_session *index_session, 27495730Sru int result) 27595730Sru{ 27695730Sru mutex_lock(&index_session->request_mutex); 27795730Sru index_session->state &= ~IS_FLAG_LOADING; 27895730Sru if (result == UDS_SUCCESS) 27938666Sjb index_session->state |= IS_FLAG_LOADED; 280107374Sru 28117308Speter uds_broadcast_cond(&index_session->request_cond); 28255678Smarcel mutex_unlock(&index_session->request_mutex); 283143032Sharti} 284138515Sharti 285117793Srustatic int initialize_index_session(struct uds_index_session *index_session, 286110035Sru enum uds_open_index_type open_type) 287174564Simp{ 288110035Sru int result; 2892061Sjkh struct uds_configuration *config; 29017308Speter 291107516Sru result = uds_make_configuration(&index_session->parameters, &config); 292174539Simp if (result != UDS_SUCCESS) { 293174539Simp vdo_log_error_strerror(result, "Failed to allocate config"); 29455678Smarcel return result; 295107516Sru } 296107516Sru 297107516Sru memset(&index_session->stats, 0, sizeof(index_session->stats)); 298174564Simp result = uds_make_index(config, open_type, &index_session->load_context, 299107516Sru enter_callback_stage, &index_session->index); 300139112Sru if (result != UDS_SUCCESS) 301164470Sjb vdo_log_error_strerror(result, "Failed to make index"); 302107516Sru else 303122204Skris uds_log_configuration(config); 30455678Smarcel 30555678Smarcel uds_free_configuration(config); 306116696Sru return result; 30755678Smarcel} 308133376Sharti 309107516Srustatic const char *get_open_type_string(enum uds_open_index_type open_type) 310107516Sru{ 311107516Sru switch (open_type) { 312107516Sru case UDS_CREATE: 31355678Smarcel return "creating index"; 314185499Salfred case UDS_LOAD: 315218524Sjhb return "loading or rebuilding index"; 316185499Salfred case UDS_NO_REBUILD: 317218524Sjhb return "loading index"; 318218524Sjhb default: 319218524Sjhb return "unknown open method"; 32055678Smarcel } 321111131Sru} 322111131Sru 323111131Sru/* 324133945Sru * Open an index under the given session. This operation will fail if the 325111131Sru * index session is suspended, or if there is already an open index. 326111131Sru */ 327217125Simpint uds_open_index(enum uds_open_index_type open_type, 328221869Sattilio const struct uds_parameters *parameters, 329216520Snwhitehorn struct uds_index_session *session) 330221216Sjhb{ 331216520Snwhitehorn int result; 332216520Snwhitehorn char name[BDEVNAME_SIZE]; 333216520Snwhitehorn 334216520Snwhitehorn if (parameters == NULL) { 335216520Snwhitehorn vdo_log_error("missing required parameters"); 336168280Smarcel return -EINVAL; 337218524Sjhb } 338218524Sjhb if (parameters->bdev == NULL) { 339218524Sjhb vdo_log_error("missing required block device"); 340218524Sjhb return -EINVAL; 341218524Sjhb } 342219137Sjhb if (session == NULL) { 343218524Sjhb vdo_log_error("missing required session pointer"); 344217125Simp return -EINVAL; 345217815Sbz } 346217125Simp 347217125Simp result = start_loading_index_session(session); 348217125Simp if (result != UDS_SUCCESS) 349217125Simp return uds_status_to_errno(result); 350217125Simp 351217125Simp session->parameters = *parameters; 352185499Salfred format_dev_t(name, parameters->bdev->bd_dev); 353217735Sbz vdo_log_info("%s: %s", get_open_type_string(open_type), name); 354185499Salfred 355185499Salfred result = initialize_index_session(session, open_type); 356185499Salfred if (result != UDS_SUCCESS) 357185499Salfred vdo_log_error_strerror(result, "Failed %s", 358185499Salfred get_open_type_string(open_type)); 359133945Sru 360133945Sru finish_loading_index_session(session, result); 361103985Sphk return uds_status_to_errno(result); 362103985Sphk} 363103985Sphk 364185499Salfredstatic void wait_for_no_requests_in_progress(struct uds_index_session *index_session) 365217754Sbz{ 366185499Salfred mutex_lock(&index_session->request_mutex); 367168280Smarcel while (index_session->request_count > 0) { 368162147Sru uds_wait_cond(&index_session->request_cond, 369162147Sru &index_session->request_mutex); 370216520Snwhitehorn } 371216520Snwhitehorn mutex_unlock(&index_session->request_mutex); 372216520Snwhitehorn} 373179232Sjb 374216520Snwhitehornstatic int __must_check save_index(struct uds_index_session *index_session) 375216520Snwhitehorn{ 376216520Snwhitehorn wait_for_no_requests_in_progress(index_session); 377218524Sjhb return uds_save_index(index_session->index); 378185250Sdes} 379218524Sjhb 380162147Srustatic void suspend_rebuild(struct uds_index_session *session) 381216520Snwhitehorn{ 382218524Sjhb mutex_lock(&session->load_context.mutex); 383218524Sjhb switch (session->load_context.status) { 384218524Sjhb case INDEX_OPENING: 385216520Snwhitehorn session->load_context.status = INDEX_SUSPENDING; 386218524Sjhb 387216520Snwhitehorn /* Wait until the index indicates that it is not replaying. */ 388179232Sjb while ((session->load_context.status != INDEX_SUSPENDED) && 389205290Sdougb (session->load_context.status != INDEX_READY)) { 390219137Sjhb uds_wait_cond(&session->load_context.cond, 391219137Sjhb &session->load_context.mutex); 392185250Sdes } 393185499Salfred 394185499Salfred break; 395103985Sphk 396201815Sbz case INDEX_READY: 397201815Sbz /* Index load does not need to be suspended. */ 398205290Sdougb break; 399201815Sbz 400201815Sbz case INDEX_SUSPENDED: 401201815Sbz case INDEX_SUSPENDING: 402202095Sbz case INDEX_FREEING: 403202095Sbz default: 404202095Sbz /* These cases should not happen. */ 405219137Sjhb VDO_ASSERT_LOG_ONLY(false, "Bad load context state %u", 406201815Sbz session->load_context.status); 407201815Sbz break; 408201815Sbz } 409148154Sru mutex_unlock(&session->load_context.mutex); 410219137Sjhb} 411219137Sjhb 412216934Simp/* 413216934Simp * Suspend index operation, draining all current index requests and preventing new index requests 414216934Simp * from starting. Optionally saves all index data before returning. 415216934Simp */ 416216520Snwhitehornint uds_suspend_index_session(struct uds_index_session *session, bool save) 417216520Snwhitehorn{ 418185250Sdes int result = UDS_SUCCESS; 419185250Sdes bool no_work = false; 420201815Sbz bool rebuilding = false; 421216520Snwhitehorn 422148154Sru /* Wait for any current index state change to complete. */ 423201815Sbz mutex_lock(&session->request_mutex); 424201815Sbz while (session->state & IS_FLAG_CLOSING) 425201815Sbz uds_wait_cond(&session->request_cond, &session->request_mutex); 426148154Sru 427133945Sru if ((session->state & IS_FLAG_WAITING) || (session->state & IS_FLAG_DESTROYING)) { 428133945Sru no_work = true; 429103985Sphk vdo_log_info("Index session is already changing state"); 430118531Sru result = -EBUSY; 431118531Sru } else if (session->state & IS_FLAG_SUSPENDED) { 432103985Sphk no_work = true; 433185499Salfred } else if (session->state & IS_FLAG_LOADING) { 434185499Salfred session->state |= IS_FLAG_WAITING; 435185499Salfred rebuilding = true; 436185499Salfred } else if (session->state & IS_FLAG_LOADED) { 437185499Salfred session->state |= IS_FLAG_WAITING; 438185499Salfred } else { 439133945Sru no_work = true; 440185499Salfred session->state |= IS_FLAG_SUSPENDED; 441 uds_broadcast_cond(&session->request_cond); 442 } 443 mutex_unlock(&session->request_mutex); 444 445 if (no_work) 446 return uds_status_to_errno(result); 447 448 if (rebuilding) 449 suspend_rebuild(session); 450 else if (save) 451 result = save_index(session); 452 else 453 result = uds_flush_index_session(session); 454 455 mutex_lock(&session->request_mutex); 456 session->state &= ~IS_FLAG_WAITING; 457 session->state |= IS_FLAG_SUSPENDED; 458 uds_broadcast_cond(&session->request_cond); 459 mutex_unlock(&session->request_mutex); 460 return uds_status_to_errno(result); 461} 462 463static int replace_device(struct uds_index_session *session, struct block_device *bdev) 464{ 465 int result; 466 467 result = uds_replace_index_storage(session->index, bdev); 468 if (result != UDS_SUCCESS) 469 return result; 470 471 session->parameters.bdev = bdev; 472 return UDS_SUCCESS; 473} 474 475/* 476 * Resume index operation after being suspended. If the index is suspended and the supplied block 477 * device differs from the current backing store, the index will start using the new backing store. 478 */ 479int uds_resume_index_session(struct uds_index_session *session, 480 struct block_device *bdev) 481{ 482 int result = UDS_SUCCESS; 483 bool no_work = false; 484 bool resume_replay = false; 485 486 mutex_lock(&session->request_mutex); 487 if (session->state & IS_FLAG_WAITING) { 488 vdo_log_info("Index session is already changing state"); 489 no_work = true; 490 result = -EBUSY; 491 } else if (!(session->state & IS_FLAG_SUSPENDED)) { 492 /* If not suspended, just succeed. */ 493 no_work = true; 494 result = UDS_SUCCESS; 495 } else { 496 session->state |= IS_FLAG_WAITING; 497 if (session->state & IS_FLAG_LOADING) 498 resume_replay = true; 499 } 500 mutex_unlock(&session->request_mutex); 501 502 if (no_work) 503 return result; 504 505 if ((session->index != NULL) && (bdev != session->parameters.bdev)) { 506 result = replace_device(session, bdev); 507 if (result != UDS_SUCCESS) { 508 mutex_lock(&session->request_mutex); 509 session->state &= ~IS_FLAG_WAITING; 510 uds_broadcast_cond(&session->request_cond); 511 mutex_unlock(&session->request_mutex); 512 return uds_status_to_errno(result); 513 } 514 } 515 516 if (resume_replay) { 517 mutex_lock(&session->load_context.mutex); 518 switch (session->load_context.status) { 519 case INDEX_SUSPENDED: 520 session->load_context.status = INDEX_OPENING; 521 /* Notify the index to start replaying again. */ 522 uds_broadcast_cond(&session->load_context.cond); 523 break; 524 525 case INDEX_READY: 526 /* There is no index rebuild to resume. */ 527 break; 528 529 case INDEX_OPENING: 530 case INDEX_SUSPENDING: 531 case INDEX_FREEING: 532 default: 533 /* These cases should not happen; do nothing. */ 534 VDO_ASSERT_LOG_ONLY(false, "Bad load context state %u", 535 session->load_context.status); 536 break; 537 } 538 mutex_unlock(&session->load_context.mutex); 539 } 540 541 mutex_lock(&session->request_mutex); 542 session->state &= ~IS_FLAG_WAITING; 543 session->state &= ~IS_FLAG_SUSPENDED; 544 uds_broadcast_cond(&session->request_cond); 545 mutex_unlock(&session->request_mutex); 546 return UDS_SUCCESS; 547} 548 549static int save_and_free_index(struct uds_index_session *index_session) 550{ 551 int result = UDS_SUCCESS; 552 bool suspended; 553 struct uds_index *index = index_session->index; 554 555 if (index == NULL) 556 return UDS_SUCCESS; 557 558 mutex_lock(&index_session->request_mutex); 559 suspended = (index_session->state & IS_FLAG_SUSPENDED); 560 mutex_unlock(&index_session->request_mutex); 561 562 if (!suspended) { 563 result = uds_save_index(index); 564 if (result != UDS_SUCCESS) 565 vdo_log_warning_strerror(result, 566 "ignoring error from save_index"); 567 } 568 uds_free_index(index); 569 index_session->index = NULL; 570 571 /* 572 * Reset all index state that happens to be in the index 573 * session, so it doesn't affect any future index. 574 */ 575 mutex_lock(&index_session->load_context.mutex); 576 index_session->load_context.status = INDEX_OPENING; 577 mutex_unlock(&index_session->load_context.mutex); 578 579 mutex_lock(&index_session->request_mutex); 580 /* Only the suspend bit will remain relevant. */ 581 index_session->state &= IS_FLAG_SUSPENDED; 582 mutex_unlock(&index_session->request_mutex); 583 584 return result; 585} 586 587/* Save and close the current index. */ 588int uds_close_index(struct uds_index_session *index_session) 589{ 590 int result = UDS_SUCCESS; 591 592 /* Wait for any current index state change to complete. */ 593 mutex_lock(&index_session->request_mutex); 594 while ((index_session->state & IS_FLAG_WAITING) || 595 (index_session->state & IS_FLAG_CLOSING)) { 596 uds_wait_cond(&index_session->request_cond, 597 &index_session->request_mutex); 598 } 599 600 if (index_session->state & IS_FLAG_SUSPENDED) { 601 vdo_log_info("Index session is suspended"); 602 result = -EBUSY; 603 } else if ((index_session->state & IS_FLAG_DESTROYING) || 604 !(index_session->state & IS_FLAG_LOADED)) { 605 /* The index doesn't exist, hasn't finished loading, or is being destroyed. */ 606 result = UDS_NO_INDEX; 607 } else { 608 index_session->state |= IS_FLAG_CLOSING; 609 } 610 mutex_unlock(&index_session->request_mutex); 611 if (result != UDS_SUCCESS) 612 return uds_status_to_errno(result); 613 614 vdo_log_debug("Closing index"); 615 wait_for_no_requests_in_progress(index_session); 616 result = save_and_free_index(index_session); 617 vdo_log_debug("Closed index"); 618 619 mutex_lock(&index_session->request_mutex); 620 index_session->state &= ~IS_FLAG_CLOSING; 621 uds_broadcast_cond(&index_session->request_cond); 622 mutex_unlock(&index_session->request_mutex); 623 return uds_status_to_errno(result); 624} 625 626/* This will save and close an open index before destroying the session. */ 627int uds_destroy_index_session(struct uds_index_session *index_session) 628{ 629 int result; 630 bool load_pending = false; 631 632 vdo_log_debug("Destroying index session"); 633 634 /* Wait for any current index state change to complete. */ 635 mutex_lock(&index_session->request_mutex); 636 while ((index_session->state & IS_FLAG_WAITING) || 637 (index_session->state & IS_FLAG_CLOSING)) { 638 uds_wait_cond(&index_session->request_cond, 639 &index_session->request_mutex); 640 } 641 642 if (index_session->state & IS_FLAG_DESTROYING) { 643 mutex_unlock(&index_session->request_mutex); 644 vdo_log_info("Index session is already closing"); 645 return -EBUSY; 646 } 647 648 index_session->state |= IS_FLAG_DESTROYING; 649 load_pending = ((index_session->state & IS_FLAG_LOADING) && 650 (index_session->state & IS_FLAG_SUSPENDED)); 651 mutex_unlock(&index_session->request_mutex); 652 653 if (load_pending) { 654 /* Tell the index to terminate the rebuild. */ 655 mutex_lock(&index_session->load_context.mutex); 656 if (index_session->load_context.status == INDEX_SUSPENDED) { 657 index_session->load_context.status = INDEX_FREEING; 658 uds_broadcast_cond(&index_session->load_context.cond); 659 } 660 mutex_unlock(&index_session->load_context.mutex); 661 662 /* Wait until the load exits before proceeding. */ 663 mutex_lock(&index_session->request_mutex); 664 while (index_session->state & IS_FLAG_LOADING) { 665 uds_wait_cond(&index_session->request_cond, 666 &index_session->request_mutex); 667 } 668 mutex_unlock(&index_session->request_mutex); 669 } 670 671 wait_for_no_requests_in_progress(index_session); 672 result = save_and_free_index(index_session); 673 uds_request_queue_finish(index_session->callback_queue); 674 index_session->callback_queue = NULL; 675 vdo_log_debug("Destroyed index session"); 676 vdo_free(index_session); 677 return uds_status_to_errno(result); 678} 679 680/* Wait until all callbacks for index operations are complete. */ 681int uds_flush_index_session(struct uds_index_session *index_session) 682{ 683 wait_for_no_requests_in_progress(index_session); 684 uds_wait_for_idle_index(index_session->index); 685 return UDS_SUCCESS; 686} 687 688/* Statistics collection is intended to be thread-safe. */ 689static void collect_stats(const struct uds_index_session *index_session, 690 struct uds_index_stats *stats) 691{ 692 const struct session_stats *session_stats = &index_session->stats; 693 694 stats->current_time = ktime_to_seconds(current_time_ns(CLOCK_REALTIME)); 695 stats->posts_found = READ_ONCE(session_stats->posts_found); 696 stats->in_memory_posts_found = READ_ONCE(session_stats->posts_found_open_chapter); 697 stats->dense_posts_found = READ_ONCE(session_stats->posts_found_dense); 698 stats->sparse_posts_found = READ_ONCE(session_stats->posts_found_sparse); 699 stats->posts_not_found = READ_ONCE(session_stats->posts_not_found); 700 stats->updates_found = READ_ONCE(session_stats->updates_found); 701 stats->updates_not_found = READ_ONCE(session_stats->updates_not_found); 702 stats->deletions_found = READ_ONCE(session_stats->deletions_found); 703 stats->deletions_not_found = READ_ONCE(session_stats->deletions_not_found); 704 stats->queries_found = READ_ONCE(session_stats->queries_found); 705 stats->queries_not_found = READ_ONCE(session_stats->queries_not_found); 706 stats->requests = READ_ONCE(session_stats->requests); 707} 708 709int uds_get_index_session_stats(struct uds_index_session *index_session, 710 struct uds_index_stats *stats) 711{ 712 if (stats == NULL) { 713 vdo_log_error("received a NULL index stats pointer"); 714 return -EINVAL; 715 } 716 717 collect_stats(index_session, stats); 718 if (index_session->index != NULL) { 719 uds_get_index_stats(index_session->index, stats); 720 } else { 721 stats->entries_indexed = 0; 722 stats->memory_used = 0; 723 stats->collisions = 0; 724 stats->entries_discarded = 0; 725 } 726 727 return UDS_SUCCESS; 728} 729 730void uds_wait_cond(struct cond_var *cv, struct mutex *mutex) 731{ 732 DEFINE_WAIT(__wait); 733 734 prepare_to_wait(&cv->wait_queue, &__wait, TASK_IDLE); 735 mutex_unlock(mutex); 736 schedule(); 737 finish_wait(&cv->wait_queue, &__wait); 738 mutex_lock(mutex); 739} 740