diff options
Diffstat (limited to 'xlators/features/bit-rot/src/bitd/bit-rot-scrub.c')
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot-scrub.c | 545 |
1 files changed, 375 insertions, 170 deletions
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c index d95008ca9a2..c0421d0ac02 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c +++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c @@ -19,6 +19,7 @@ #include "bit-rot-scrub.h" #include <pthread.h> #include "bit-rot-bitd-messages.h" +#include "bit-rot-scrub-status.h" struct br_scrubbers { pthread_t scrubthread; @@ -74,20 +75,6 @@ bitd_fetch_signature (xlator_t *this, br_child_t *child, } -static void -br_inc_unsigned_file_count (xlator_t *this) -{ - br_private_t *priv = NULL; - - priv = this->private; - - pthread_mutex_lock (&priv->scrub_stat.lock); - { - priv->scrub_stat.unsigned_files++; - } - pthread_mutex_unlock (&priv->scrub_stat.lock); -} - /** * POST COMPUTE CHECK * @@ -101,7 +88,8 @@ int32_t bitd_scrub_post_compute_check (xlator_t *this, br_child_t *child, fd_t *fd, unsigned long version, - br_isignature_out_t **signature) + br_isignature_out_t **signature, + br_scrub_stats_t *scrub_stat) { int32_t ret = 0; size_t signlen = 0; @@ -109,8 +97,10 @@ bitd_scrub_post_compute_check (xlator_t *this, br_isignature_out_t *signptr = NULL; ret = bitd_fetch_signature (this, child, fd, &xattr, &signptr); - if (ret < 0) + if (ret < 0) { + br_inc_unsigned_file_count (scrub_stat); goto out; + } /** * Either the object got dirtied during the time the signature was @@ -121,7 +111,7 @@ bitd_scrub_post_compute_check (xlator_t *this, * The log entry looks pretty ugly, but helps in debugging.. */ if (signptr->stale || (signptr->version != version)) { - br_inc_unsigned_file_count (this); + br_inc_unsigned_file_count (scrub_stat); gf_msg_debug (this->name, 0, "<STAGE: POST> Object [GFID: %s] " "either has a stale signature OR underwent " "signing during checksumming {Stale: %d | " @@ -149,15 +139,18 @@ bitd_scrub_post_compute_check (xlator_t *this, static int32_t bitd_signature_staleness (xlator_t *this, br_child_t *child, fd_t *fd, - int *stale, unsigned long *version) + int *stale, unsigned long *version, + br_scrub_stats_t *scrub_stat) { int32_t ret = -1; dict_t *xattr = NULL; br_isignature_out_t *signptr = NULL; ret = bitd_fetch_signature (this, child, fd, &xattr, &signptr); - if (ret < 0) + if (ret < 0) { + br_inc_unsigned_file_count (scrub_stat); goto out; + } /** * save verison for validation in post compute stage @@ -182,7 +175,8 @@ bitd_signature_staleness (xlator_t *this, */ int32_t bitd_scrub_pre_compute_check (xlator_t *this, br_child_t *child, - fd_t *fd, unsigned long *version) + fd_t *fd, unsigned long *version, + br_scrub_stats_t *scrub_stat) { int stale = 0; int32_t ret = -1; @@ -194,9 +188,10 @@ bitd_scrub_pre_compute_check (xlator_t *this, br_child_t *child, goto out; } - ret = bitd_signature_staleness (this, child, fd, &stale, version); + ret = bitd_signature_staleness (this, child, fd, &stale, version, + scrub_stat); if (!ret && stale) { - br_inc_unsigned_file_count (this); + br_inc_unsigned_file_count (scrub_stat); gf_msg_debug (this->name, 0, "<STAGE: PRE> Object [GFID: %s] " "has stale signature", uuid_utoa (fd->inode->gfid)); @@ -272,16 +267,6 @@ bitd_compare_ckum (xlator_t *this, return ret; } -static void -br_inc_scrubbed_file (br_private_t *priv) -{ - pthread_mutex_lock (&priv->scrub_stat.lock); - { - priv->scrub_stat.scrubbed_files++; - } - pthread_mutex_unlock (&priv->scrub_stat.lock); -} - /** * "The Scrubber" * @@ -374,7 +359,8 @@ br_scrubber_scrub_begin (xlator_t *this, struct br_fsscan_entry *fsentry) * - presence of bad object * - signature staleness */ - ret = bitd_scrub_pre_compute_check (this, child, fd, &signedversion); + ret = bitd_scrub_pre_compute_check (this, child, fd, &signedversion, + &priv->scrub_stat); if (ret) goto unrefd; /* skip this object */ @@ -397,8 +383,8 @@ br_scrubber_scrub_begin (xlator_t *this, struct br_fsscan_entry *fsentry) * perform post compute checks as an object's signature may have * become stale while scrubber calculated checksum. */ - ret = bitd_scrub_post_compute_check (this, child, - fd, signedversion, &sign); + ret = bitd_scrub_post_compute_check (this, child, fd, signedversion, + &sign, &priv->scrub_stat); if (ret) goto free_md; @@ -406,7 +392,7 @@ br_scrubber_scrub_begin (xlator_t *this, struct br_fsscan_entry *fsentry) linked_inode, entry, fd, child, &loc); /* Increment of total number of scrubbed file counter */ - br_inc_scrubbed_file (priv); + br_inc_scrubbed_file (&priv->scrub_stat); GF_FREE (sign); /* alloced on post-compute */ @@ -560,171 +546,215 @@ br_fsscanner_handle_entry (xlator_t *subvol, } int32_t -br_fsscan_deactivate (xlator_t *this, br_child_t *child) +br_fsscan_deactivate (xlator_t *this) { int ret = 0; br_private_t *priv = NULL; br_scrub_state_t nstate = 0; - struct br_scanfs *fsscan = NULL; + struct br_monitor *scrub_monitor = NULL; priv = this->private; - fsscan = &child->fsscan; + scrub_monitor = &priv->scrub_monitor; - ret = gf_tw_del_timer (priv->timer_wheel, fsscan->timer); + ret = gf_tw_del_timer (priv->timer_wheel, scrub_monitor->timer); if (ret == 0) { nstate = BR_SCRUB_STATE_STALLED; gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, - "Brick [%s] is under active scrubbing. Pausing scrub..", - child->brick_path); + "Volume is under active scrubbing. Pausing scrub.."); } else { nstate = BR_SCRUB_STATE_PAUSED; gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, - "Scrubber paused [Brick: %s]", child->brick_path); + "Scrubber paused"); } - _br_child_set_scrub_state (child, nstate); + _br_monitor_set_scrub_state (scrub_monitor, nstate); return 0; } + static void -br_update_scrub_start_time (xlator_t *this, struct timeval *tv) +br_scrubber_log_time (xlator_t *this, const char *sfx) { - br_private_t *priv = NULL; - static int child; + char timestr[1024] = {0,}; + struct timeval tv = {0,}; + br_private_t *priv = NULL; priv = this->private; + gettimeofday (&tv, NULL); + gf_time_fmt (timestr, sizeof (timestr), tv.tv_sec, gf_timefmt_FT); - /* Setting scrubber starting time for first child only */ - if (child == 0) { - pthread_mutex_lock (&priv->scrub_stat.lock); - { - priv->scrub_stat.scrub_start_tv.tv_sec = tv->tv_sec; - } - pthread_mutex_unlock (&priv->scrub_stat.lock); + if (strcasecmp (sfx, "started") == 0) { + br_update_scrub_start_time (&priv->scrub_stat, &tv); + gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_START, + "Scrubbing %s at %s", sfx, timestr); + } else { + br_update_scrub_finish_time (&priv->scrub_stat, timestr, &tv); + gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_FINISH, + "Scrubbing %s at %s", sfx, timestr); } +} - if (++child == priv->up_children) { - child = 0; +static void +br_fsscanner_log_time (xlator_t *this, br_child_t *child, const char *sfx) +{ + char timestr[1024] = {0,}; + struct timeval tv = {0,}; + + gettimeofday (&tv, NULL); + gf_time_fmt (timestr, sizeof (timestr), tv.tv_sec, gf_timefmt_FT); + + if (strcasecmp (sfx, "started") == 0) { + gf_msg_debug (this->name, 0, "Scrubbing \"%s\" %s at %s", + child->brick_path, sfx, timestr); + } else { + gf_msg_debug (this->name, 0, "Scrubbing \"%s\" %s at %s", + child->brick_path, sfx, timestr); } } +void +br_child_set_scrub_state (br_child_t *child, gf_boolean_t state) +{ + child->active_scrubbing = state; +} + static void -br_update_scrub_finish_time (xlator_t *this, char *timestr, struct timeval *tv) +br_fsscanner_wait_until_kicked (xlator_t *this, br_child_t *child) { - br_private_t *priv = NULL; - static int child; + br_private_t *priv = NULL; + struct br_monitor *scrub_monitor = NULL; priv = this->private; + scrub_monitor = &priv->scrub_monitor; - /*Setting scrubber finishing time at time time of last child operation*/ - if (++child == priv->up_children) { - pthread_mutex_lock (&priv->scrub_stat.lock); - { - priv->scrub_stat.scrub_end_tv.tv_sec = tv->tv_sec; - - priv->scrub_stat.scrub_duration = - priv->scrub_stat.scrub_end_tv.tv_sec - - priv->scrub_stat.scrub_start_tv.tv_sec; - - strncpy (priv->scrub_stat.last_scrub_time, timestr, - sizeof (priv->scrub_stat.last_scrub_time)); + pthread_cleanup_push (_br_lock_cleaner, &scrub_monitor->wakelock); + pthread_mutex_lock (&scrub_monitor->wakelock); + { + while (!scrub_monitor->kick) + pthread_cond_wait (&scrub_monitor->wakecond, + &scrub_monitor->wakelock); - child = 0; + /* Child lock is to synchronize with disconnect events */ + pthread_cleanup_push (_br_lock_cleaner, &child->lock); + LOCK (&child->lock); + { + scrub_monitor->active_child_count++; + br_child_set_scrub_state (child, _gf_true); } - pthread_mutex_unlock (&priv->scrub_stat.lock); + UNLOCK (&child->lock); + pthread_cleanup_pop (0); } + pthread_mutex_unlock (&scrub_monitor->wakelock); + pthread_cleanup_pop (0); } static void -br_fsscanner_log_time (xlator_t *this, br_child_t *child, const char *sfx) +br_scrubber_entry_control (xlator_t *this) { - char timestr[1024] = {0,}; - struct timeval tv = {0,}; + br_private_t *priv = NULL; + struct br_monitor *scrub_monitor = NULL; - gettimeofday (&tv, NULL); - gf_time_fmt (timestr, sizeof (timestr), tv.tv_sec, gf_timefmt_FT); + priv = this->private; + scrub_monitor = &priv->scrub_monitor; - if (strcasecmp (sfx, "started") == 0) { - br_update_scrub_start_time (this, &tv); - gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_START, - "Scrubbing \"%s\" %s at %s", child->brick_path, sfx, - timestr); - } else { - br_update_scrub_finish_time (this, timestr, &tv); - gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_FINISH, - "Scrubbing \"%s\" %s at %s", child->brick_path, sfx, - timestr); + LOCK (&scrub_monitor->lock); + { + /* Move the state to BR_SCRUB_STATE_ACTIVE */ + if (scrub_monitor->state == BR_SCRUB_STATE_PENDING) + scrub_monitor->state = BR_SCRUB_STATE_ACTIVE; + br_scrubber_log_time (this, "started"); } + UNLOCK (&scrub_monitor->lock); } static void -br_fsscanner_wait_until_kicked (xlator_t *this, struct br_scanfs *fsscan) +br_scrubber_exit_control (xlator_t *this) { - static int i; - br_private_t *priv = NULL; + br_private_t *priv = NULL; + struct br_monitor *scrub_monitor = NULL; priv = this->private; + scrub_monitor = &priv->scrub_monitor; - pthread_cleanup_push (_br_lock_cleaner, &fsscan->wakelock); - pthread_mutex_lock (&fsscan->wakelock); + LOCK (&scrub_monitor->lock); { - while (!fsscan->kick) - pthread_cond_wait (&fsscan->wakecond, - &fsscan->wakelock); - - /* resetting total number of scrubbed file when scrubbing - * done for all of its children */ - if (i == priv->up_children) { - pthread_mutex_lock (&priv->scrub_stat.lock); - { - priv->scrub_stat.scrubbed_files = 0; - priv->scrub_stat.unsigned_files = 0; - i = 0; - } - pthread_mutex_unlock (&priv->scrub_stat.lock); - } - ++i; + br_scrubber_log_time (this, "finished"); - fsscan->kick = _gf_false; + if (scrub_monitor->state == BR_SCRUB_STATE_ACTIVE) { + (void) br_fsscan_activate (this); + } else { + gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, + "Volume waiting to get rescheduled.."); + } } - pthread_mutex_unlock (&fsscan->wakelock); - pthread_cleanup_pop (0); + UNLOCK (&scrub_monitor->lock); } static void br_fsscanner_entry_control (xlator_t *this, br_child_t *child) { - struct br_scanfs *fsscan = &child->fsscan; - - LOCK (&child->lock); - { - if (fsscan->state == BR_SCRUB_STATE_PENDING) - fsscan->state = BR_SCRUB_STATE_ACTIVE; br_fsscanner_log_time (this, child, "started"); - } - UNLOCK (&child->lock); } static void br_fsscanner_exit_control (xlator_t *this, br_child_t *child) { - struct br_scanfs *fsscan = &child->fsscan; + br_private_t *priv = NULL; + struct br_monitor *scrub_monitor = NULL; - LOCK (&child->lock); + priv = this->private; + scrub_monitor = &priv->scrub_monitor; + + if (!_br_is_child_connected (child)) { + gf_msg (this->name, GF_LOG_WARNING, 0, BRB_MSG_SCRUB_INFO, + "Brick [%s] disconnected while scrubbing. Scrubbing " + "might be incomplete", child->brick_path); + } + + br_fsscanner_log_time (this, child, "finished"); + + pthread_cleanup_push (_br_lock_cleaner, &scrub_monitor->wakelock); + pthread_mutex_lock (&scrub_monitor->wakelock); { - fsscan->over = _gf_true; - br_fsscanner_log_time (this, child, "finished"); + scrub_monitor->active_child_count--; + pthread_cleanup_push (_br_lock_cleaner, &child->lock); + LOCK (&child->lock); + { + br_child_set_scrub_state (child, _gf_false); + } + UNLOCK (&child->lock); + pthread_cleanup_pop (0); - if (fsscan->state == BR_SCRUB_STATE_ACTIVE) { - (void) br_fsscan_activate (this, child); + if (scrub_monitor->active_child_count == 0) { + /* The last child has finished scrubbing. + * Set the kick to false and wake up other + * children who are waiting for the last + * child to complete scrubbing. + */ + scrub_monitor->kick = _gf_false; + pthread_cond_broadcast (&scrub_monitor->wakecond); + + /* Signal monitor thread waiting for the all + * the children to finish scrubbing. + */ + pthread_cleanup_push (_br_lock_cleaner, + &scrub_monitor->donelock); + pthread_mutex_lock (&scrub_monitor->donelock); + { + scrub_monitor->done = _gf_true; + pthread_cond_signal (&scrub_monitor->donecond); + } + pthread_mutex_unlock (&scrub_monitor->donelock); + pthread_cleanup_pop (0); } else { - gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, - "Brick [%s] waiting to get rescheduled..", - child->brick_path); + while (scrub_monitor->active_child_count) + pthread_cond_wait (&scrub_monitor->wakecond, + &scrub_monitor->wakelock); } } - UNLOCK (&child->lock); + pthread_mutex_unlock (&scrub_monitor->wakelock); + pthread_cleanup_pop (0); } void * @@ -743,7 +773,7 @@ br_fsscanner (void *arg) loc.inode = child->table->root; while (1) { - br_fsscanner_wait_until_kicked (this, fsscan); + br_fsscanner_wait_until_kicked (this, child); { /* precursor for scrub */ br_fsscanner_entry_control (this, child); @@ -775,22 +805,29 @@ br_kickstart_scanner (struct gf_tw_timer_list *timer, void *data, unsigned long calltime) { xlator_t *this = NULL; - br_child_t *child = data; - struct br_scanfs *fsscan = NULL; + struct br_monitor *scrub_monitor = data; + br_private_t *priv = NULL; - THIS = this = child->this; - fsscan = &child->fsscan; + THIS = this = scrub_monitor->this; + priv = this->private; + + /* Reset scrub statistics */ + priv->scrub_stat.scrubbed_files = 0; + priv->scrub_stat.unsigned_files = 0; + + /* Moves state from PENDING to ACTIVE */ + (void) br_scrubber_entry_control (this); /* kickstart scanning.. */ - pthread_mutex_lock (&fsscan->wakelock); + pthread_mutex_lock (&scrub_monitor->wakelock); { - fsscan->kick = _gf_true; - pthread_cond_signal (&fsscan->wakecond); + scrub_monitor->kick = _gf_true; + GF_ASSERT (scrub_monitor->active_child_count == 0); + pthread_cond_broadcast (&scrub_monitor->wakecond); } - pthread_mutex_unlock (&fsscan->wakelock); + pthread_mutex_unlock (&scrub_monitor->wakelock); return; - } static uint32_t @@ -834,22 +871,22 @@ br_fsscan_calculate_timeout (scrub_freq_t freq) } int32_t -br_fsscan_schedule (xlator_t *this, br_child_t *child) +br_fsscan_schedule (xlator_t *this) { uint32_t timo = 0; br_private_t *priv = NULL; struct timeval tv = {0,}; char timestr[1024] = {0,}; - struct br_scanfs *fsscan = NULL; struct br_scrubber *fsscrub = NULL; struct gf_tw_timer_list *timer = NULL; + struct br_monitor *scrub_monitor = NULL; priv = this->private; - fsscan = &child->fsscan; fsscrub = &priv->fsscrub; + scrub_monitor = &priv->scrub_monitor; (void) gettimeofday (&tv, NULL); - fsscan->boot = tv.tv_sec; + scrub_monitor->boot = tv.tv_sec; timo = br_fsscan_calculate_timeout (fsscrub->frequency); if (timo == 0) { @@ -858,25 +895,25 @@ br_fsscan_schedule (xlator_t *this, br_child_t *child) goto error_return; } - fsscan->timer = GF_CALLOC (1, sizeof (*fsscan->timer), + scrub_monitor->timer = GF_CALLOC (1, sizeof (*scrub_monitor->timer), gf_br_stub_mt_br_scanner_freq_t); - if (!fsscan->timer) + if (!scrub_monitor->timer) goto error_return; - timer = fsscan->timer; + timer = scrub_monitor->timer; INIT_LIST_HEAD (&timer->entry); - timer->data = child; + timer->data = scrub_monitor; timer->expires = timo; timer->function = br_kickstart_scanner; gf_tw_add_timer (priv->timer_wheel, timer); - _br_child_set_scrub_state (child, BR_SCRUB_STATE_PENDING); + _br_monitor_set_scrub_state (scrub_monitor, BR_SCRUB_STATE_PENDING); gf_time_fmt (timestr, sizeof (timestr), - (fsscan->boot + timo), gf_timefmt_FT); - gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, "Scrubbing for " - "%s scheduled to run at %s", child->brick_path, timestr); + (scrub_monitor->boot + timo), gf_timefmt_FT); + gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, "Scrubbing is " + "scheduled to run at %s", timestr); return 0; @@ -885,18 +922,18 @@ br_fsscan_schedule (xlator_t *this, br_child_t *child) } int32_t -br_fsscan_activate (xlator_t *this, br_child_t *child) +br_fsscan_activate (xlator_t *this) { uint32_t timo = 0; char timestr[1024] = {0,}; struct timeval now = {0,}; br_private_t *priv = NULL; - struct br_scanfs *fsscan = NULL; struct br_scrubber *fsscrub = NULL; + struct br_monitor *scrub_monitor = NULL; priv = this->private; - fsscan = &child->fsscan; fsscrub = &priv->fsscrub; + scrub_monitor = &priv->scrub_monitor; (void) gettimeofday (&now, NULL); timo = br_fsscan_calculate_timeout (fsscrub->frequency); @@ -906,32 +943,37 @@ br_fsscan_activate (xlator_t *this, br_child_t *child) return -1; } - fsscan->over = _gf_false; + pthread_mutex_lock (&scrub_monitor->donelock); + { + scrub_monitor->done = _gf_false; + } + pthread_mutex_unlock (&scrub_monitor->donelock); + gf_time_fmt (timestr, sizeof (timestr), (now.tv_sec + timo), gf_timefmt_FT); - (void) gf_tw_mod_timer (priv->timer_wheel, fsscan->timer, timo); + (void) gf_tw_mod_timer (priv->timer_wheel, scrub_monitor->timer, timo); - _br_child_set_scrub_state (child, BR_SCRUB_STATE_PENDING); - gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, "Scrubbing for " - "%s rescheduled to run at %s", child->brick_path, timestr); + _br_monitor_set_scrub_state (scrub_monitor, BR_SCRUB_STATE_PENDING); + gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, "Scrubbing is " + "rescheduled to run at %s", timestr); return 0; } int32_t -br_fsscan_reschedule (xlator_t *this, br_child_t *child) +br_fsscan_reschedule (xlator_t *this) { int32_t ret = 0; uint32_t timo = 0; char timestr[1024] = {0,}; struct timeval now = {0,}; br_private_t *priv = NULL; - struct br_scanfs *fsscan = NULL; struct br_scrubber *fsscrub = NULL; + struct br_monitor *scrub_monitor = NULL; priv = this->private; - fsscan = &child->fsscan; fsscrub = &priv->fsscrub; + scrub_monitor = &priv->scrub_monitor; if (!fsscrub->frequency_reconf) return 0; @@ -947,17 +989,21 @@ br_fsscan_reschedule (xlator_t *this, br_child_t *child) gf_time_fmt (timestr, sizeof (timestr), (now.tv_sec + timo), gf_timefmt_FT); - fsscan->over = _gf_false; - ret = gf_tw_mod_timer_pending (priv->timer_wheel, fsscan->timer, timo); + pthread_mutex_lock (&scrub_monitor->donelock); + { + scrub_monitor->done = _gf_false; + } + pthread_mutex_unlock (&scrub_monitor->donelock); + + ret = gf_tw_mod_timer_pending (priv->timer_wheel, scrub_monitor->timer, timo); if (ret == 0) gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, - "Scrubber for %s is currently running and would be " - "rescheduled after completion", child->brick_path); + "Scrubber is currently running and would be " + "rescheduled after completion"); else { - _br_child_set_scrub_state (child, BR_SCRUB_STATE_PENDING); + _br_monitor_set_scrub_state (scrub_monitor, BR_SCRUB_STATE_PENDING); gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, - "Scrubbing for %s rescheduled to run at %s", - child->brick_path, timestr); + "Scrubbing rescheduled to run at %s", timestr); } return 0; @@ -1723,15 +1769,174 @@ out: return ret; } +static int +wait_for_scrub_to_finish (xlator_t *this) +{ + int ret = -1; + br_private_t *priv = NULL; + struct br_monitor *scrub_monitor = NULL; + + priv = this->private; + scrub_monitor = &priv->scrub_monitor; + + GF_VALIDATE_OR_GOTO ("bit-rot", scrub_monitor, out); + GF_VALIDATE_OR_GOTO ("bit-rot", this, out); + + gf_msg (this->name, GF_LOG_INFO, 0, BRB_MSG_SCRUB_INFO, + "Waiting for all children to start and finish scrub"); + + pthread_mutex_lock (&scrub_monitor->donelock); + { + while (!scrub_monitor->done) + pthread_cond_wait (&scrub_monitor->donecond, + &scrub_monitor->donelock); + } + pthread_mutex_unlock (&scrub_monitor->donelock); + ret = 0; +out: + return ret; +} + +/** + * This function is executed in a separate thread. This is scrubber monitor + * thread that takes care of state machine. + */ +void * +br_monitor_thread (void *arg) +{ + int32_t ret = 0; + xlator_t *this = NULL; + br_private_t *priv = NULL; + struct br_monitor *scrub_monitor = NULL; + + this = arg; + priv = this->private; + + /* + * Since, this is the topmost xlator, THIS has to be set by bit-rot + * xlator itself (STACK_WIND wont help in this case). Also it has + * to be done for each thread that gets spawned. Otherwise, a new + * thread will get global_xlator's pointer when it does "THIS". + */ + THIS = this; + + scrub_monitor = &priv->scrub_monitor; + + pthread_mutex_lock (&scrub_monitor->mutex); + { + while (!scrub_monitor->inited) + pthread_cond_wait (&scrub_monitor->cond, + &scrub_monitor->mutex); + } + pthread_mutex_unlock (&scrub_monitor->mutex); + + /* this needs to be serialized with reconfigure() */ + pthread_mutex_lock (&priv->lock); + { + ret = br_scrub_state_machine (this); + } + pthread_mutex_unlock (&priv->lock); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, -ret, + BRB_MSG_SSM_FAILED, + "Scrub state machine failed"); + goto out; + } + + while (1) { + /* Wait for all children to finish scrubbing */ + ret = wait_for_scrub_to_finish (this); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, -ret, + BRB_MSG_SCRUB_WAIT_FAILED, + "Scrub wait failed"); + goto out; + } + + /* scrub exit criteria: Move the state to PENDING */ + br_scrubber_exit_control (this); + } + +out: + return NULL; +} + +static void +br_set_scrub_state (struct br_monitor *scrub_monitor, br_scrub_state_t state) +{ + LOCK (&scrub_monitor->lock); + { + _br_monitor_set_scrub_state (scrub_monitor, state); + } + UNLOCK (&scrub_monitor->lock); +} + +int32_t +br_scrubber_monitor_init (xlator_t *this, br_private_t *priv) +{ + struct br_monitor *scrub_monitor = NULL; + int ret = 0; + + scrub_monitor = &priv->scrub_monitor; + + LOCK_INIT (&scrub_monitor->lock); + scrub_monitor->this = this; + + scrub_monitor->inited = _gf_false; + pthread_mutex_init (&scrub_monitor->mutex, NULL); + pthread_cond_init (&scrub_monitor->cond, NULL); + + scrub_monitor->kick = _gf_false; + scrub_monitor->active_child_count = 0; + pthread_mutex_init (&scrub_monitor->wakelock, NULL); + pthread_cond_init (&scrub_monitor->wakecond, NULL); + + scrub_monitor->done = _gf_false; + pthread_mutex_init (&scrub_monitor->donelock, NULL); + pthread_cond_init (&scrub_monitor->donecond, NULL); + + /* Set the state to INACTIVE */ + br_set_scrub_state (&priv->scrub_monitor, BR_SCRUB_STATE_INACTIVE); + + /* Start the monitor thread */ + ret = gf_thread_create (&scrub_monitor->thread, NULL, br_monitor_thread, this); + if (ret != 0) { + gf_msg (this->name, GF_LOG_ERROR, -ret, + BRB_MSG_SPAWN_FAILED, "monitor thread creation failed"); + ret = -1; + goto err; + } + + return 0; +err: + pthread_mutex_destroy (&scrub_monitor->mutex); + pthread_cond_destroy (&scrub_monitor->cond); + + pthread_mutex_destroy (&scrub_monitor->wakelock); + pthread_cond_destroy (&scrub_monitor->wakecond); + + pthread_mutex_destroy (&scrub_monitor->donelock); + pthread_cond_destroy (&scrub_monitor->donecond); + + LOCK_DESTROY (&scrub_monitor->lock); + + return ret; +} + int32_t br_scrubber_init (xlator_t *this, br_private_t *priv) { struct br_scrubber *fsscrub = NULL; + int ret = 0; priv->tbf = br_tbf_init (NULL, 0); if (!priv->tbf) return -1; + ret = br_scrubber_monitor_init (this, priv); + if (ret) + return -1; + fsscrub = &priv->fsscrub; fsscrub->this = this; |