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 | 373 | 
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  | 
