diff -ur nilfs2-utils.orig/man/nilfs_cleanerd.conf.5 nilfs2-utils/man/nilfs_cleanerd.conf.5 --- nilfs2-utils.orig/man/nilfs_cleanerd.conf.5 2010-03-14 15:11:30.916690347 +0100 +++ nilfs2-utils/man/nilfs_cleanerd.conf.5 2010-03-15 22:15:58.320507660 +0100 @@ -25,6 +25,23 @@ and their blocks whose duration time is less than the value. The default value is 3600, meaning one hour. .TP +.B min_clean_segments +Specify the minimum number of clean segments. A value of 0 means +normal cleaner operation. A value greater than 0 means pause cleaning +until less than min_clean_segments are available. The default value +is 100. +.TP +.B max_clean_segments +Specify the maximum number of clean segments. If min_clean_segments is +0, this value is ignored. If more than max_clean_segments are available +cleaning is paused until less than min_clean_segments are available. +The default value is 200. +.TP +.B clean_check_interval +Specify the interval to wait between checks of min_clean_segments. +If min_clean_segments is 0, this value is ignored. +The default value is 60. +.TP .B selection_policy Specify the GC policy. At present, only the `\fBtimestamp\fP' policy, which reclaims segments in order from oldest to newest, is support. diff -ur nilfs2-utils.orig/sbin/cleanerd/cldconfig.c nilfs2-utils/sbin/cleanerd/cldconfig.c --- nilfs2-utils.orig/sbin/cleanerd/cldconfig.c 2010-03-14 15:11:30.916690347 +0100 +++ nilfs2-utils/sbin/cleanerd/cldconfig.c 2010-03-15 20:20:22.364435601 +0100 @@ -90,6 +90,87 @@ return 0; } +static int +nilfs_cldconfig_handle_min_clean_segments(struct nilfs_cldconfig *config, + char **tokens, size_t ntoks) +{ + __u64 n; + char *endptr; + + if (check_tokens(tokens, ntoks, 2, 2) < 0) + return 0; + + errno = 0; + n = strtoull(tokens[1], &endptr, 10); + if (*endptr != '\0') { + syslog(LOG_WARNING, "%s: %s: not a number", + tokens[0], tokens[1]); + return 0; + } + if ((n == ULLONG_MAX) && (errno == ERANGE)) { + syslog(LOG_WARNING, "%s: %s: number too large", + tokens[0], tokens[1]); + return 0; + } + + config->cf_min_clean_segments = n; + return 0; +} + +static int +nilfs_cldconfig_handle_max_clean_segments(struct nilfs_cldconfig *config, + char **tokens, size_t ntoks) +{ + __u64 n; + char *endptr; + + if (check_tokens(tokens, ntoks, 2, 2) < 0) + return 0; + + errno = 0; + n = strtoull(tokens[1], &endptr, 10); + if (*endptr != '\0') { + syslog(LOG_WARNING, "%s: %s: not a number", + tokens[0], tokens[1]); + return 0; + } + if ((n == ULLONG_MAX) && (errno == ERANGE)) { + syslog(LOG_WARNING, "%s: %s: number too large", + tokens[0], tokens[1]); + return 0; + } + + config->cf_max_clean_segments = n; + return 0; +} + +static int +nilfs_cldconfig_handle_clean_check_interval(struct nilfs_cldconfig *config, + char **tokens, size_t ntoks) +{ + time_t period; + char *endptr; + + if (check_tokens(tokens, ntoks, 2, 2) < 0) + return 0; + + errno = 0; + period = strtoul(tokens[1], &endptr, 10); + if (*endptr != '\0') { + syslog(LOG_WARNING, "%s: %s: not a number", + tokens[0], tokens[1]); + return 0; + } + if ((period == ULONG_MAX) && (errno == ERANGE)) { + syslog(LOG_WARNING, "%s: %s: number too large", + tokens[0], tokens[1]); + return 0; + } + + config->cf_clean_check_interval = period; + return 0; +} + static unsigned long long nilfs_cldconfig_selection_policy_timestamp(const struct nilfs_suinfo *si) { @@ -277,6 +358,9 @@ static const struct nilfs_cldconfig_keyword nilfs_cldconfig_keyword_table[] = { {"protection_period", nilfs_cldconfig_handle_protection_period}, + {"min_clean_segments", nilfs_cldconfig_handle_min_clean_segments}, + {"max_clean_segments", nilfs_cldconfig_handle_max_clean_segments}, + {"clean_check_interval",nilfs_cldconfig_handle_clean_check_interval}, {"selection_policy", nilfs_cldconfig_handle_selection_policy}, {"nsegments_per_clean", nilfs_cldconfig_handle_nsegments_per_clean}, {"cleaning_interval", nilfs_cldconfig_handle_cleaning_interval}, @@ -313,6 +397,9 @@ config->cf_selection_policy.p_threshold = NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD; config->cf_protection_period = NILFS_CLDCONFIG_PROTECTION_PERIOD; + config->cf_min_clean_segments = NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS; + config->cf_max_clean_segments = NILFS_CLDCONFIG_MAX_CLEAN_SEGMENTS; + config->cf_clean_check_interval = NILFS_CLDCONFIG_CLEAN_CHECK_INTERVAL; config->cf_nsegments_per_clean = NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN; config->cf_cleaning_interval = NILFS_CLDCONFIG_CLEANING_INTERVAL; config->cf_retry_interval = NILFS_CLDCONFIG_RETRY_INTERVAL; diff -ur nilfs2-utils.orig/sbin/cleanerd/cldconfig.h nilfs2-utils/sbin/cleanerd/cldconfig.h --- nilfs2-utils.orig/sbin/cleanerd/cldconfig.h 2010-03-14 15:11:30.916690347 +0100 +++ nilfs2-utils/sbin/cleanerd/cldconfig.h 2010-03-15 21:58:16.208614224 +0100 @@ -42,6 +42,9 @@ * struct nilfs_cldconfig - * @cf_selection_policy: * @cf_protection_period: + * @cf_min_clean_segments: + * @cf_max_clean_segments: + * @cf_clean_check_interval: * @cf_nsegments_per_clean * @cf_cleaning_interval: * @cf_use_mmap: @@ -50,6 +53,9 @@ struct nilfs_cldconfig { struct nilfs_selection_policy cf_selection_policy; time_t cf_protection_period; + __u64 cf_min_clean_segments; + __u64 cf_max_clean_segments; + time_t cf_clean_check_interval; int cf_nsegments_per_clean; time_t cf_cleaning_interval; time_t cf_retry_interval; @@ -61,6 +67,9 @@ nilfs_cldconfig_selection_policy_timestamp #define NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD 0 #define NILFS_CLDCONFIG_PROTECTION_PERIOD 3600 +#define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS 100 +#define NILFS_CLDCONFIG_MAX_CLEAN_SEGMENTS 200 +#define NILFS_CLDCONFIG_CLEAN_CHECK_INTERVAL 60 #define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN 2 #define NILFS_CLDCONFIG_CLEANING_INTERVAL 5 #define NILFS_CLDCONFIG_RETRY_INTERVAL 60 diff -ur nilfs2-utils.orig/sbin/cleanerd/cleanerd.c nilfs2-utils/sbin/cleanerd/cleanerd.c --- nilfs2-utils.orig/sbin/cleanerd/cleanerd.c 2010-03-14 15:11:30.916690347 +0100 +++ nilfs2-utils/sbin/cleanerd/cleanerd.c 2010-03-17 19:59:36.845402863 +0100 @@ -1198,9 +1198,17 @@ if (ret < 0) return -1; - cleanerd->c_running = 1; cleanerd->c_ncleansegs = cleanerd->c_config.cf_nsegments_per_clean; + if (cleanerd->c_config.cf_min_clean_segments > 0) { + syslog(LOG_INFO, "cleaner paused"); + cleanerd->c_running = 0; + timeout.tv_sec = cleanerd->c_config.cf_clean_check_interval; + timeout.tv_nsec = 0; + } + else + cleanerd->c_running = 1; + while (1) { if (sigprocmask(SIG_BLOCK, &sigset, NULL) < 0) { syslog(LOG_ERR, "cannot set signal mask: %m"); @@ -1220,10 +1228,32 @@ syslog(LOG_ERR, "cannot get segment usage stat: %m"); return -1; } + + if (cleanerd->c_config.cf_min_clean_segments > 0) { + if (cleanerd->c_running) { + if (sustat.ss_ncleansegs > cleanerd->c_config.cf_max_clean_segments) { + syslog(LOG_INFO, "cleaner paused"); + cleanerd->c_running = 0; + timeout.tv_sec = cleanerd->c_config.cf_clean_check_interval; + timeout.tv_nsec = 0; + goto sleep; + } + } + else { + if (sustat.ss_ncleansegs < cleanerd->c_config.cf_min_clean_segments) { + syslog(LOG_INFO, "cleaner resumed"); + cleanerd->c_running = 1; + } + else + goto sleep; + } + } + if (sustat.ss_nongc_ctime != prev_nongc_ctime) { cleanerd->c_running = 1; prev_nongc_ctime = sustat.ss_nongc_ctime; } + if (!cleanerd->c_running) goto sleep; diff -ur nilfs2-utils.orig/sbin/cleanerd/nilfs_cleanerd.conf nilfs2-utils/sbin/cleanerd/nilfs_cleanerd.conf --- nilfs2-utils.orig/sbin/cleanerd/nilfs_cleanerd.conf 2010-03-14 15:11:30.916690347 +0100 +++ nilfs2-utils/sbin/cleanerd/nilfs_cleanerd.conf 2010-03-15 21:44:02.995587453 +0100 @@ -7,6 +7,17 @@ # Protection period in second. protection_period 3600 +# Minium number of clean segements +# 0 = normal cleaner behaviour +# >0 = start cleaning if less segments are available +min_clean_segments 100 + +# Maximum number of clean segments +max_clean_segments 200 + +# Clean segment check interval in seconds +clean_check_interval 60 + # Segment selection policy. # In NILFS version 2.0.0, only the timestamp policy is supported. selection_policy timestamp # timestamp in ascend order