diff options
Diffstat (limited to 'xlators/features/bit-rot/src/bitd')
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot-scrub.c | 373 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot-scrub.h | 6 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot.c | 70 | ||||
-rw-r--r-- | xlators/features/bit-rot/src/bitd/bit-rot.h | 32 |
4 files changed, 301 insertions, 180 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 390148fdb06..26ad97a16e8 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c +++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c @@ -508,198 +508,217 @@ br_fsscanner_handle_entry (xlator_t *subvol, return -1; } -/*scrubber frequency tunable value in second (day * hour * minut * second)*/ -#define DAILY (1*24*60*60) -#define WEEKLY (7*24*60*60) -#define BIWEEKLY (14*24*60*60) -#define MONTHLY (30*24*60*60) - -struct timeval -br_scrubber_calc_freq (xlator_t *this) +static inline void +br_fsscanner_log_time (xlator_t *this, br_child_t *child, const char *sfx) { - br_private_t *priv = NULL; - struct timeval scrub_sec = {0,}; + struct timeval tv = {0,}; + char timestr[1024] = {0,}; - priv = this->private; + gettimeofday (&tv, NULL); + gf_time_fmt (timestr, sizeof (timestr), tv.tv_sec, gf_timefmt_FT); - /*By default scrubber frequency will be biweekly*/ - if (!strncmp (priv->scrub_freq, "daily", strlen("daily"))) { - scrub_sec.tv_sec = DAILY; - } else if (!strncmp (priv->scrub_freq, "weekly", strlen("weekly"))) { - scrub_sec.tv_sec = WEEKLY; - } else if (!strncmp (priv->scrub_freq, "monthly", strlen("monthly"))) { - scrub_sec.tv_sec = MONTHLY; - } else if (!strncmp (priv->scrub_freq, "biweekly", - strlen("biweekly"))) { - scrub_sec.tv_sec = BIWEEKLY; - } else { - gf_log (this->name, GF_LOG_ERROR, "Invalid scrub-frequency %s" - "value.", priv->scrub_freq); - scrub_sec.tv_sec = -1; - } + gf_log (this->name, GF_LOG_INFO, + "Scrubbing \"%s\" %s at %s", child->brick_path, sfx, timestr); +} - return scrub_sec; +static void +br_fsscanner_wait_until_kicked (struct br_scanfs *fsscan) +{ + pthread_mutex_lock (&fsscan->wakelock); + { + while (!fsscan->kick) + pthread_cond_wait (&fsscan->wakecond, + &fsscan->wakelock); + fsscan->kick = _gf_false; + } + pthread_mutex_unlock (&fsscan->wakelock); } -#define SCRUBBER_SLEEP(freq_diff, elapse_time) do { \ - \ - if (freq_diff < 0) { \ - return 0; \ - } else if (freq_diff <= DAILY) { \ - gf_log (this->name, GF_LOG_INFO, \ - "Scrubber is sleeping for %ld " \ - "sec", freq_diff); \ - sleep (freq_diff); \ - return 0; \ - } else { \ - gf_log (this->name, GF_LOG_INFO, \ - "Scrubber is sleeping for %ld " \ - "sec", freq_diff); \ - sleep (DAILY); \ - elapse_time += DAILY; \ - } \ - } while (0) - -static int -br_scrubber_sleep_check (struct timeval *begin, struct timeval *end, - xlator_t *this) +void * +br_fsscanner (void *arg) { - br_private_t *priv = NULL; - struct timeval elapse_time = {0,}; - struct timeval freq_diff = {0,}; - struct timeval scrub_sec = {0,}; - struct timeval temp = {0,}; + loc_t loc = {0,}; + br_child_t *child = NULL; + xlator_t *this = NULL; + br_private_t *priv = NULL; + struct br_scanfs *fsscan = NULL; + struct br_scrubber *fsscrub = NULL; + child = arg; + this = child->this; priv = this->private; - scrub_sec = br_scrubber_calc_freq (this); - if (scrub_sec.tv_sec == -1) { - gf_log (this->name, GF_LOG_ERROR, "Unable to calculate scrub " - "frequency %s value", priv->scrub_freq); - return -1; - } + fsscan = &child->fsscan; + fsscrub = &priv->fsscrub; - if ((end->tv_sec - begin->tv_sec) < scrub_sec.tv_sec) { - /* Sleep, if scrubber have completed its job before schedule - * scrub frequency based on current scrub frequency value */ - do { - scrub_sec = br_scrubber_calc_freq (this); - freq_diff.tv_sec = scrub_sec.tv_sec - (end->tv_sec - - begin->tv_sec) - - elapse_time.tv_sec; - SCRUBBER_SLEEP(freq_diff.tv_sec, elapse_time.tv_sec); - } while (1); - - - } else { - /* Sleep, if scrubber have completed its job after schedule - * scrub frequency based on current scrub frequency value */ - temp.tv_sec = (end->tv_sec - begin->tv_sec) % scrub_sec.tv_sec; - if (temp.tv_sec != 0) { - do { - scrub_sec = br_scrubber_calc_freq (this); - freq_diff.tv_sec = scrub_sec.tv_sec - - temp.tv_sec - - elapse_time.tv_sec; - SCRUBBER_SLEEP(freq_diff.tv_sec, - elapse_time.tv_sec); - } while (1); + THIS = this; + loc.inode = child->table->root; + + while (1) { + br_fsscanner_wait_until_kicked (fsscan); + { + /* log start time */ + br_fsscanner_log_time (this, child, "started"); + + /* scrub */ + (void) syncop_ftw (child->xl, + &loc, GF_CLIENT_PID_SCRUB, + child, br_fsscanner_handle_entry); + if (!list_empty (&fsscan->queued)) + wait_for_scrubbing (this, fsscan); + + /* log finish time */ + br_fsscanner_log_time (this, child, "finished"); } + br_fsscan_reschedule (this, child, fsscan, fsscrub, _gf_false); } - return 0; + return NULL; } -void * -br_fsscanner (void *arg) +void +br_kickstart_scanner (struct gf_tw_timer_list *timer, + void *data, unsigned long calltime) { - int32_t ret = -1; - loc_t loc = {0,}; - char timestr[1024] = {0,}; - xlator_t *this = NULL; - br_child_t *child = NULL; - struct br_scanfs *fsscan = NULL; - br_private_t *priv = NULL; - struct timeval elapse_time = {0,}; - struct timeval scrub_sec = {0,}; - struct timeval freq_diff = {0,}; + xlator_t *this = NULL; + br_child_t *child = data; + struct br_scanfs *fsscan = NULL; - child = arg; - this = child->this; + THIS = this = child->this; fsscan = &child->fsscan; - THIS = this; + /* kickstart scanning.. */ + pthread_mutex_lock (&fsscan->wakelock); + { + fsscan->kick = _gf_true; + pthread_cond_signal (&fsscan->wakecond); + } + pthread_mutex_unlock (&fsscan->wakelock); + + return; + +} + +static inline uint32_t +br_fsscan_calculate_delta (uint32_t boot, uint32_t now, uint32_t times) +{ + uint32_t secs = 0; + uint32_t diff = 0; + + diff = (now - boot); + secs = times * ((diff / times) + 1); + + return (secs - diff); +} + +#define BR_SCRUB_HOURLY (60 * 60) +#define BR_SCRUB_DAILY (1 * 24 * 60 * 60) +#define BR_SCRUB_WEEKLY (7 * 24 * 60 * 60) +#define BR_SCRUB_BIWEEKLY (14 * 24 * 60 * 60) +#define BR_SCRUB_MONTHLY (30 * 24 * 60 * 60) + +static unsigned int +br_fsscan_calculate_timeout (uint32_t boot, uint32_t now, scrub_freq_t freq) +{ + uint32_t timo = 0; + + switch (freq) { + case BR_FSSCRUB_FREQ_HOURLY: + timo = br_fsscan_calculate_delta (boot, now, BR_SCRUB_HOURLY); + break; + case BR_FSSCRUB_FREQ_DAILY: + timo = br_fsscan_calculate_delta (boot, now, BR_SCRUB_DAILY); + break; + case BR_FSSCRUB_FREQ_WEEKLY: + timo = br_fsscan_calculate_delta (boot, now, BR_SCRUB_WEEKLY); + break; + case BR_FSSCRUB_FREQ_BIWEEKLY: + timo = br_fsscan_calculate_delta (boot, now, BR_SCRUB_BIWEEKLY); + break; + case BR_FSSCRUB_FREQ_MONTHLY: + timo = br_fsscan_calculate_delta (boot, now, BR_SCRUB_MONTHLY); + } + + return timo; +} + +int32_t +br_fsscan_schedule (xlator_t *this, br_child_t *child, + struct br_scanfs *fsscan, struct br_scrubber *fsscrub) +{ + uint32_t timo = 0; + br_private_t *priv = NULL; + struct timeval tv = {0,}; + char timestr[1024] = {0,}; + struct gf_tw_timer_list *timer = NULL; priv = this->private; - loc.inode = child->table->root; + (void) gettimeofday (&tv, NULL); + fsscan->boot = tv.tv_sec; - /* Scrubber should start scrubbing the filesystem *after* the - * schedueled scrub-frequency has expired.*/ - do { - /*Calculate current scrub frequency value in second*/ - scrub_sec = br_scrubber_calc_freq (this); - if (scrub_sec.tv_sec == -1) { - gf_log (this->name, GF_LOG_ERROR, "Unable to calculate " - "scrub frequency %s value", priv->scrub_freq); - return NULL; - } + timo = br_fsscan_calculate_timeout (fsscan->boot, + fsscan->boot, fsscrub->frequency); - freq_diff.tv_sec = scrub_sec.tv_sec - elapse_time.tv_sec; + fsscan->timer = GF_CALLOC (1, sizeof (*fsscan->timer), + gf_br_stub_mt_br_scanner_freq_t); + if (!fsscan->timer) + goto error_return; - if (freq_diff.tv_sec < 0) { - break; - } else if (freq_diff.tv_sec == DAILY) { - sleep (DAILY); - break; - } else { - sleep (DAILY); - elapse_time.tv_sec += DAILY; - } + timer = fsscan->timer; + INIT_LIST_HEAD (&timer->entry); - } while (1); + timer->data = child; + timer->expires = timo; + timer->function = br_kickstart_scanner; + gf_tw_add_timer (priv->timer_wheel, timer); - while (1) { - /* log scrub start time */ - gettimeofday (&priv->tv_before_scrub, NULL); - gf_time_fmt (timestr, sizeof timestr, - priv->tv_before_scrub.tv_sec, gf_timefmt_FT); - gf_log (this->name, GF_LOG_INFO, - "Scrubbing \"%s\" started at %s", - child->brick_path, timestr); - - /* scrub */ - (void) syncop_ftw (child->xl, &loc, - GF_CLIENT_PID_SCRUB, - child, br_fsscanner_handle_entry); - if (!list_empty (&fsscan->queued)) - wait_for_scrubbing (this, fsscan); - - gettimeofday (&priv->tv_after_scrub, NULL); - /* log scrub finish time */ - gf_time_fmt (timestr, sizeof timestr, - priv->tv_after_scrub.tv_sec, gf_timefmt_FT); + gf_time_fmt (timestr, sizeof (timestr), + (fsscan->boot + timo), gf_timefmt_FT); + gf_log (this->name, GF_LOG_INFO, "Scrubbing for %s scheduled to " + "run at %s", child->brick_path, timestr); + + return 0; + + error_return: + return -1; +} + +int32_t +br_fsscan_reschedule (xlator_t *this, + br_child_t *child, struct br_scanfs *fsscan, + struct br_scrubber *fsscrub, gf_boolean_t pendingcheck) +{ + int32_t ret = 0; + uint32_t timo = 0; + char timestr[1024] = {0,}; + struct timeval now = {0,}; + br_private_t *priv = NULL; + + priv = this->private; + + (void) gettimeofday (&now, NULL); + timo = br_fsscan_calculate_timeout (fsscan->boot, + now.tv_sec, fsscrub->frequency); + + gf_time_fmt (timestr, sizeof (timestr), + (now.tv_sec + timo), gf_timefmt_FT); + + if (pendingcheck) + ret = gf_tw_mod_timer_pending (priv->timer_wheel, + fsscan->timer, timo); + else + ret = gf_tw_mod_timer (priv->timer_wheel, fsscan->timer, timo); + + if (!ret && pendingcheck) gf_log (this->name, GF_LOG_INFO, - "Scrubbing \"%s\" finished at %s", - child->brick_path, timestr); - - /* Scrubber should sleep if it have completed scrubbing - * of filesystem before the scheduled scrub-frequency*/ - ret = br_scrubber_sleep_check (&priv->tv_before_scrub, - &priv->tv_after_scrub, - this); - if (!ret) { - gf_log (this->name, GF_LOG_DEBUG, "scrubber is crawling" - " file system with scrubber frequency %s", - priv->scrub_freq); - } else { - gf_log (this->name, GF_LOG_ERROR, "Unable to perform " - "scrubber sleep check for scrubber frequency"); - return NULL; - } - } + "Scrubber for %s is currently running and would be " + "rescheduled after completion", child->brick_path); + else + gf_log (this->name, GF_LOG_INFO, "Scrubbing for %s rescheduled " + "to run at %s", child->brick_path, timestr); - return NULL; + return 0; } #define BR_SCRUB_THREAD_SCALE_LAZY 0 @@ -1092,10 +1111,34 @@ static int32_t br_scrubber_handle_freq (xlator_t *this, br_private_t *priv, dict_t *options) { int32_t ret = -1; + char *tmp = NULL; + scrub_freq_t frequency = BR_FSSCRUB_FREQ_HOURLY; + struct br_scrubber *fsscrub = NULL; - ret = br_scrubber_fetch_option (this, "scrub-freq", options, - &priv->scrub_freq); - return ret; + fsscrub = &priv->fsscrub; + + ret = br_scrubber_fetch_option (this, "scrub-freq", options, &tmp); + if (ret) + goto error_return; + + if (strcasecmp (tmp, "hourly") == 0) { + frequency = BR_FSSCRUB_FREQ_HOURLY; + } else if (strcasecmp (tmp, "daily") == 0) { + frequency = BR_FSSCRUB_FREQ_DAILY; + } else if (strcasecmp (tmp, "weekly") == 0) { + frequency = BR_FSSCRUB_FREQ_WEEKLY; + } else if (strcasecmp (tmp, "biweekly") == 0) { + frequency = BR_FSSCRUB_FREQ_BIWEEKLY; + } else if (strcasecmp (tmp, "monthly") == 0) { + frequency = BR_FSSCRUB_FREQ_MONTHLY; + } else + goto error_return; + + fsscrub->frequency = frequency; + return 0; + + error_return: + return -1; } int32_t diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h index 4f00020d66a..6c4254a397a 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h +++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.h @@ -16,6 +16,12 @@ void *br_fsscanner (void *); +int32_t br_fsscan_schedule (xlator_t *, br_child_t *, + struct br_scanfs *, struct br_scrubber *); +int32_t br_fsscan_reschedule (xlator_t *this, + br_child_t *child, struct br_scanfs *, + struct br_scrubber *, gf_boolean_t); + int32_t br_scrubber_handle_options (xlator_t *, br_private_t *, dict_t *); int32_t br_scrubber_init (xlator_t *, br_private_t *); diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.c b/xlators/features/bit-rot/src/bitd/bit-rot.c index 2652f02b4ea..e7cfe89e1dd 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot.c +++ b/xlators/features/bit-rot/src/bitd/bit-rot.c @@ -1135,6 +1135,11 @@ br_enact_scrubber (xlator_t *this, br_child_t *child) INIT_LIST_HEAD (&fsscan->queued); INIT_LIST_HEAD (&fsscan->ready); + /* init scheduler related variables */ + fsscan->kick = _gf_false; + pthread_mutex_init (&fsscan->wakelock, NULL); + pthread_cond_init (&fsscan->wakecond, NULL); + ret = gf_thread_create (&child->thread, NULL, br_fsscanner, child); if (ret != 0) { gf_log (this->name, GF_LOG_ALERT, "failed to spawn bitrot " @@ -1142,6 +1147,10 @@ br_enact_scrubber (xlator_t *this, br_child_t *child) goto error_return; } + ret = br_fsscan_schedule (this, child, fsscan, fsscrub); + if (ret) + goto error_return; + /** * Everything has been setup.. add this subvolume to scrubbers * list. @@ -1407,13 +1416,6 @@ br_init_signer (xlator_t *this, br_private_t *priv) if (ret) goto out; - priv->timer_wheel = glusterfs_global_timer_wheel (this); - if (!priv->timer_wheel) { - gf_log (this->name, GF_LOG_ERROR, - "global timer wheel unavailable"); - goto out; - } - pthread_cond_init (&priv->object_cond, NULL); priv->obj_queue = GF_CALLOC (1, sizeof (*priv->obj_queue), @@ -1568,6 +1570,13 @@ init (xlator_t *this) INIT_LIST_HEAD (&priv->children[i].list); INIT_LIST_HEAD (&priv->bricks); + priv->timer_wheel = glusterfs_global_timer_wheel (this); + if (!priv->timer_wheel) { + gf_log (this->name, GF_LOG_ERROR, + "global timer wheel unavailable"); + goto cleanup_mutex; + } + this->private = priv; if (!priv->iamscrubber) { @@ -1633,12 +1642,55 @@ fini (xlator_t *this) int reconfigure (xlator_t *this, dict_t *options) { - br_private_t *priv = this->private; + int i = 0; + int32_t ret = -1; + br_child_t *child = NULL; + br_private_t *priv = NULL; + struct br_scanfs *fsscan = NULL; + struct br_scrubber *fsscrub = NULL; + + priv = this->private; if (!priv->iamscrubber) return 0; - return br_scrubber_handle_options (this, priv, options); + ret = br_scrubber_handle_options (this, priv, options); + if (ret) + goto err; + + fsscrub = &priv->fsscrub; + + /* reschedule all _up_ subvolume(s) */ + pthread_mutex_lock (&priv->lock); + { + for (; i < priv->child_count; i++) { + child = &priv->children[i]; + if (!child->child_up) { + gf_log (this->name, GF_LOG_INFO, + "Brick %s is offline, skipping " + "rescheduling (scrub would auto- " + "schedule when brick is back online).", + child->brick_path); + continue; + } + + fsscan = &child->fsscan; + ret = br_fsscan_reschedule (this, child, + fsscan, fsscrub, _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Could not " + "reschedule scrubber for brick: %s. " + "Scubbing will continue according to " + "old frequency.", child->brick_path); + } + } + } + pthread_mutex_unlock (&priv->lock); + + return 0; + + err: + return -1; } struct xlator_fops fops; diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.h b/xlators/features/bit-rot/src/bitd/bit-rot.h index 6543be763d6..ec943e9131f 100644 --- a/xlators/features/bit-rot/src/bitd/bit-rot.h +++ b/xlators/features/bit-rot/src/bitd/bit-rot.h @@ -46,6 +46,14 @@ typedef enum scrub_throttle { BR_SCRUB_THROTTLE_STALLED = 3, } scrub_throttle_t; +typedef enum scrub_freq { + BR_FSSCRUB_FREQ_HOURLY = 1, + BR_FSSCRUB_FREQ_DAILY, + BR_FSSCRUB_FREQ_WEEKLY, + BR_FSSCRUB_FREQ_BIWEEKLY, + BR_FSSCRUB_FREQ_MONTHLY, +} scrub_freq_t; + #define signature_size(hl) (sizeof (br_isignature_t) + hl + 1) struct br_scanfs { @@ -57,6 +65,15 @@ struct br_scanfs { unsigned int entries; struct list_head queued; struct list_head ready; + + /* scheduler */ + uint32_t boot; + gf_boolean_t kick; + + pthread_mutex_t wakelock; + pthread_cond_t wakecond; + + struct gf_tw_timer_list *timer; }; struct br_child { @@ -98,13 +115,21 @@ struct br_scrubber { scrub_throttle_t throttle; + /** + * frequency of scanning for this subvolume. this should + * normally be per-child, but since all childs follow the + * same frequency for a volume, this option ends up here + * instead of br_child_t. + */ + scrub_freq_t frequency; + pthread_mutex_t mutex; pthread_cond_t cond; unsigned int nr_scrubbers; struct list_head scrubbers; - /* + /** * list of "rotatable" subvolume(s) undergoing scrubbing */ struct list_head scrublist; @@ -139,11 +164,6 @@ struct br_private { gf_boolean_t iamscrubber; /* function as a fs scrubber */ struct br_scrubber fsscrub; /* scrubbers for this subvolume */ - - char *scrub_freq; /* Scrubber frequency*/ - - struct timeval tv_before_scrub; /* time before starting scrubbing*/ - struct timeval tv_after_scrub; /* time after scrubbing completion*/ }; typedef struct br_private br_private_t; |