summaryrefslogtreecommitdiffstats
path: root/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
diff options
context:
space:
mode:
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.c373
1 files changed, 208 insertions, 165 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