On 2014-03-16 13:55, Ryusuke Konishi wrote: > On Sun, 16 Mar 2014 11:49:16 +0100, Andreas Rohner wrote: >> This patch implements the cost-benefit and greedy GC policies. These are >> well known policies for log-structured file systems [1]. >> >> * Greedy: >> Select the segments with the most free space. >> * Cost-Benefit: >> Perform a cost-benefit analysis, whereby the free space gained is >> weighed against the cost of collecting the segment. >> >> Since especially cost-benefit needed more information than was available >> in nilfs_suinfo, a few extra parameters were added to the policy >> callback function prototype. The policy threshold was removed, since it >> served no real purpose. The flag p_comparison was added to indicate how >> the importance values should be interpreted. For example for the >> timestamp policy smaller values mean older timestamps, which is better. >> For greedy and cost-benefit on the other hand higher values are better. >> nilfs_cleanerd_select_segments() was updated accordingly. >> >> [1] Mendel Rosenblum and John K. Ousterhout. The design and implementa- >> tion of a log-structured file system. ACM Trans. Comput. Syst., >> 10(1):26–52, February 1992. >> >> Signed-off-by: Andreas Rohner <andreas.rohner@xxxxxxx> >> --- >> include/nilfs2_fs.h | 9 ++++- >> sbin/cleanerd/cldconfig.c | 100 +++++++++++++++++++++++++++++++++++++++++++--- >> sbin/cleanerd/cldconfig.h | 18 +++++---- >> sbin/cleanerd/cleanerd.c | 56 ++++++++++++++++---------- >> 4 files changed, 149 insertions(+), 34 deletions(-) >> >> diff --git a/include/nilfs2_fs.h b/include/nilfs2_fs.h >> index a16ad4c..967c2af 100644 >> --- a/include/nilfs2_fs.h >> +++ b/include/nilfs2_fs.h >> @@ -483,7 +483,7 @@ struct nilfs_dat_entry { >> __le64 de_blocknr; >> __le64 de_start; >> __le64 de_end; >> - __le64 de_rsv; >> + __le64 de_ss; >> }; >> >> /** >> @@ -612,11 +612,13 @@ struct nilfs_cpfile_header { >> * @su_lastmod: last modified timestamp >> * @su_nblocks: number of blocks in segment >> * @su_flags: flags >> + * @su_lastdec: last decrement of su_nblocks timestamp >> */ >> struct nilfs_segment_usage { >> __le64 su_lastmod; >> __le32 su_nblocks; >> __le32 su_flags; >> + __le64 su_lastdec; >> }; >> >> /* segment usage flag */ >> @@ -659,6 +661,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su) >> su->su_lastmod = cpu_to_le64(0); >> su->su_nblocks = cpu_to_le32(0); >> su->su_flags = cpu_to_le32(0); >> + su->su_lastdec = cpu_to_le64(0); >> } >> >> static inline int >> @@ -690,11 +693,13 @@ struct nilfs_sufile_header { >> * @sui_lastmod: timestamp of last modification >> * @sui_nblocks: number of written blocks in segment >> * @sui_flags: segment usage flags >> + * @sui_lastdec: last decrement of sui_nblocks timestamp >> */ >> struct nilfs_suinfo { >> __u64 sui_lastmod; >> __u32 sui_nblocks; >> __u32 sui_flags; >> + __u64 sui_lastdec; >> }; >> >> #define NILFS_SUINFO_FNS(flag, name) \ >> @@ -732,6 +737,7 @@ enum { >> NILFS_SUINFO_UPDATE_LASTMOD, >> NILFS_SUINFO_UPDATE_NBLOCKS, >> NILFS_SUINFO_UPDATE_FLAGS, >> + NILFS_SUINFO_UPDATE_LASTDEC, >> __NR_NILFS_SUINFO_UPDATE_FIELDS, >> }; >> >> @@ -755,6 +761,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup) \ >> NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod) >> NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks) >> NILFS_SUINFO_UPDATE_FNS(FLAGS, flags) >> +NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec) >> >> enum { >> NILFS_CHECKPOINT, >> diff --git a/sbin/cleanerd/cldconfig.c b/sbin/cleanerd/cldconfig.c >> index c8b197b..ade974a 100644 >> --- a/sbin/cleanerd/cldconfig.c >> +++ b/sbin/cleanerd/cldconfig.c >> @@ -380,7 +380,10 @@ nilfs_cldconfig_handle_clean_check_interval(struct nilfs_cldconfig *config, >> } >> >> static unsigned long long >> -nilfs_cldconfig_selection_policy_timestamp(const struct nilfs_suinfo *si) >> +nilfs_cldconfig_selection_policy_timestamp(struct nilfs *nilfs, >> + const struct nilfs_sustat *sustat, >> + const struct nilfs_suinfo *si, >> + __u64 prottime) >> { >> return si->sui_lastmod; >> } >> @@ -391,14 +394,101 @@ nilfs_cldconfig_handle_selection_policy_timestamp(struct nilfs_cldconfig *config >> { >> config->cf_selection_policy.p_importance = >> NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE; >> - config->cf_selection_policy.p_threshold = >> - NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD; >> + config->cf_selection_policy.p_comparison = >> + NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER; >> + return 0; >> +} >> + >> +static unsigned long long >> +nilfs_cldconfig_selection_policy_greedy(struct nilfs *nilfs, >> + const struct nilfs_sustat *sustat, >> + const struct nilfs_suinfo *si, >> + __u64 prottime) >> +{ >> + __u32 value, max_blocks = nilfs_get_blocks_per_segment(nilfs); >> + >> + if (max_blocks < si->sui_nblocks) >> + return 0; >> + >> + value = max_blocks - si->sui_nblocks; >> + >> + /* >> + * the value of sui_nblocks is probably not accurate >> + * because blocks inside the protection period are not >> + * considered to be dead >> + */ >> + if (si->sui_lastdec >= prottime) >> + value >>= 4; >> + >> + return value; >> +} >> + >> +static int >> +nilfs_cldconfig_handle_selection_policy_greedy(struct nilfs_cldconfig *config, >> + char **tokens, size_t ntoks) >> +{ >> + config->cf_selection_policy.p_importance = >> + nilfs_cldconfig_selection_policy_greedy; >> + config->cf_selection_policy.p_comparison = >> + NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER; >> + return 0; >> +} >> + >> +static unsigned long long >> +nilfs_cldconfig_selection_policy_cost_benefit(struct nilfs *nilfs, >> + const struct nilfs_sustat *sustat, >> + const struct nilfs_suinfo *si, >> + __u64 prottime) >> +{ >> + __u32 free_blocks, cleaning_cost; >> + unsigned long long value, age; >> + >> + free_blocks = nilfs_get_blocks_per_segment(nilfs) - si->sui_nblocks; >> + /* read the whole segment + write the live blocks */ >> + cleaning_cost = 2 * si->sui_nblocks; >> + /* >> + * multiply by 1000 to convert age to milliseconds >> + * (higher precision for division) >> + */ >> + age = (sustat->ss_nongc_ctime - si->sui_lastmod) * 1000; >> + >> + if (sustat->ss_nongc_ctime < si->sui_lastmod) >> + return 0; >> + >> + if (cleaning_cost == 0) >> + cleaning_cost = 1; >> + >> + >> + value = (age * free_blocks) / cleaning_cost; >> + >> + /* >> + * the value of sui_nblocks is probably not accurate >> + * because blocks inside the protection period are not >> + * considered to be dead >> + */ >> + if (si->sui_lastdec >= prottime) >> + value >>= 4; >> + >> + return value; >> +} >> + >> +static int >> +nilfs_cldconfig_handle_selection_policy_cost_benefit( >> + struct nilfs_cldconfig *config, >> + char **tokens, size_t ntoks) >> +{ >> + config->cf_selection_policy.p_importance = >> + nilfs_cldconfig_selection_policy_cost_benefit; >> + config->cf_selection_policy.p_comparison = >> + NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER; >> return 0; >> } >> >> static const struct nilfs_cldconfig_polhandle >> nilfs_cldconfig_polhandle_table[] = { >> {"timestamp", nilfs_cldconfig_handle_selection_policy_timestamp}, >> + {"greedy", nilfs_cldconfig_handle_selection_policy_greedy}, >> + {"cost-benefit", nilfs_cldconfig_handle_selection_policy_cost_benefit}, >> }; >> >> #define NILFS_CLDCONFIG_NPOLHANDLES \ >> @@ -688,8 +778,8 @@ static void nilfs_cldconfig_set_default(struct nilfs_cldconfig *config, >> >> config->cf_selection_policy.p_importance = >> NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE; >> - config->cf_selection_policy.p_threshold = >> - NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD; >> + config->cf_selection_policy.p_comparison = >> + NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER; >> config->cf_protection_period.tv_sec = NILFS_CLDCONFIG_PROTECTION_PERIOD; >> config->cf_protection_period.tv_usec = 0; >> >> diff --git a/sbin/cleanerd/cldconfig.h b/sbin/cleanerd/cldconfig.h >> index 0a598d5..95d2fde 100644 >> --- a/sbin/cleanerd/cldconfig.h >> +++ b/sbin/cleanerd/cldconfig.h >> @@ -30,16 +30,21 @@ >> #include <sys/time.h> >> #include <syslog.h> >> >> +struct nilfs; >> +struct nilfs_sustat; >> struct nilfs_suinfo; >> >> /** >> * struct nilfs_selection_policy - >> - * @p_importance: >> - * @p_threshold: >> + * @p_importance: function to calculate the importance for the policy >> + * @p_comparison: flag that indicates how to sort the importance >> */ >> struct nilfs_selection_policy { >> - unsigned long long (*p_importance)(const struct nilfs_suinfo *); >> - unsigned long long p_threshold; >> + unsigned long long (*p_importance)(struct nilfs *nilfs, >> + const struct nilfs_sustat *sustat, >> + const struct nilfs_suinfo *, >> + __u64 prottime); >> + int p_comparison; >> }; >> >> /** >> @@ -113,7 +118,8 @@ struct nilfs_cldconfig { >> >> #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE \ >> nilfs_cldconfig_selection_policy_timestamp >> -#define NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD 0 >> +#define NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER 0 >> +#define NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER 1 >> #define NILFS_CLDCONFIG_PROTECTION_PERIOD 3600 >> #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS 10 >> #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS_UNIT NILFS_SIZE_UNIT_PERCENT >> @@ -135,8 +141,6 @@ struct nilfs_cldconfig { >> >> #define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX 32 >> >> -struct nilfs; >> - >> int nilfs_cldconfig_read(struct nilfs_cldconfig *config, const char *path, >> struct nilfs *nilfs); >> >> diff --git a/sbin/cleanerd/cleanerd.c b/sbin/cleanerd/cleanerd.c >> index 17de87b..8df3a07 100644 >> --- a/sbin/cleanerd/cleanerd.c >> +++ b/sbin/cleanerd/cleanerd.c >> @@ -417,7 +417,7 @@ static void nilfs_cleanerd_destroy(struct nilfs_cleanerd *cleanerd) >> free(cleanerd); >> } >> >> -static int nilfs_comp_segimp(const void *elem1, const void *elem2) >> +static int nilfs_comp_segimp_asc(const void *elem1, const void *elem2) >> { >> const struct nilfs_segimp *segimp1 = elem1, *segimp2 = elem2; >> >> @@ -429,6 +429,18 @@ static int nilfs_comp_segimp(const void *elem1, const void *elem2) >> return (segimp1->si_segnum < segimp2->si_segnum) ? -1 : 1; >> } >> >> +static int nilfs_comp_segimp_desc(const void *elem1, const void *elem2) >> +{ >> + const struct nilfs_segimp *segimp1 = elem1, *segimp2 = elem2; >> + >> + if (segimp1->si_importance > segimp2->si_importance) >> + return -1; >> + else if (segimp1->si_importance < segimp2->si_importance) >> + return 1; >> + >> + return (segimp1->si_segnum < segimp2->si_segnum) ? -1 : 1; >> +} >> + >> static int nilfs_cleanerd_automatic_suspend(struct nilfs_cleanerd *cleanerd) >> { >> return cleanerd->config.cf_min_clean_segments > 0; >> @@ -579,7 +591,7 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd, >> __u64 segnum; >> size_t count, nsegs; >> ssize_t nssegs, n; >> - unsigned long long imp, thr; >> + unsigned long long imp; >> int i; >> >> nsegs = nilfs_cleanerd_ncleansegs(cleanerd); >> @@ -600,11 +612,8 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd, >> prottime = tv2.tv_sec; >> oldest = tv.tv_sec; >> >> - /* The segments that have larger importance than thr are not >> - * selected. */ >> - thr = (config->cf_selection_policy.p_threshold != 0) ? >> - config->cf_selection_policy.p_threshold : >> - sustat->ss_nongc_ctime; >> + /* sui_lastdec may not be set by nilfs_get_suinfo */ >> + memset(si, 0, sizeof(si)); >> >> for (segnum = 0; segnum < sustat->ss_nsegs; segnum += n) { >> count = min_t(__u64, sustat->ss_nsegs - segnum, >> @@ -615,22 +624,23 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd, >> goto out; >> } >> for (i = 0; i < n; i++) { >> - if (!nilfs_suinfo_reclaimable(&si[i])) >> + if (!nilfs_suinfo_reclaimable(&si[i]) || >> + si[i].sui_lastmod >= sustat->ss_nongc_ctime) >> continue; >> >> - imp = config->cf_selection_policy.p_importance(&si[i]); >> - if (imp < thr) { >> - if (si[i].sui_lastmod < oldest) >> - oldest = si[i].sui_lastmod; >> - if (si[i].sui_lastmod < prottime) { >> - sm = nilfs_vector_get_new_element(smv); >> - if (sm == NULL) { >> - nssegs = -1; >> - goto out; >> - } >> - sm->si_segnum = segnum + i; >> - sm->si_importance = imp; >> + imp = config->cf_selection_policy.p_importance(nilfs, >> + sustat, &si[i], prottime); >> + >> + if (si[i].sui_lastmod < oldest) >> + oldest = si[i].sui_lastmod; >> + if (si[i].sui_lastmod < prottime) { >> + sm = nilfs_vector_get_new_element(smv); >> + if (sm == NULL) { >> + nssegs = -1; >> + goto out; >> } >> + sm->si_segnum = segnum + i; >> + sm->si_importance = imp; >> } >> } >> if (n == 0) { >> @@ -642,7 +652,11 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd, >> break; >> } >> } >> - nilfs_vector_sort(smv, nilfs_comp_segimp); >> + if (config->cf_selection_policy.p_comparison == >> + NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER) >> + nilfs_vector_sort(smv, nilfs_comp_segimp_asc); >> + else >> + nilfs_vector_sort(smv, nilfs_comp_segimp_desc); >> >> nssegs = (nilfs_vector_get_size(smv) < nsegs) ? >> nilfs_vector_get_size(smv) : nsegs; >> -- >> 1.9.0 > > scripts/checkpatch.pl detected the following coding style issues: > > ERROR: code indent should use tabs where possible > #171: FILE: sbin/cleanerd/cldconfig.c:404: > +^I^I^I^I const struct nilfs_sustat *sustat,$ > > ERROR: code indent should use tabs where possible > #172: FILE: sbin/cleanerd/cldconfig.c:405: > +^I^I^I^I const struct nilfs_suinfo *si,$ > > ERROR: code indent should use tabs where possible > #173: FILE: sbin/cleanerd/cldconfig.c:406: > +^I^I^I^I __u64 prottime)$ > > > Please mind it next time. (You don't have to resubmit the whole series > now for this). Normally I execute checkpatch.pl automatically via the pre-commit hook. For some reason the pre-commit hook got overwritten in my local repo. I am sorry for that. > I would like to first understand this series, but I am very busy > recently. (Also, I am still pending review of Vycheslav's xattr > patchset.) So, let me go forward a little bit at a time. Ok no problem. Regards, Andreas Rohner -- To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html