diff options
Diffstat (limited to 'mm/damon/sysfs-schemes.c')
| -rw-r--r-- | mm/damon/sysfs-schemes.c | 150 | 
1 files changed, 117 insertions, 33 deletions
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index dd2fb5127009..53a90ac678fb 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -127,17 +127,17 @@ static const struct kobj_type damon_sysfs_scheme_region_ktype = {   *   * Once the tried regions update request is received, the request handling   * start function (damon_sysfs_scheme_update_regions_start()) sets the status - * of all schemes as 'idle' again, and register ->before_damos_apply() and - * ->after_sampling() callbacks. + * of all schemes as 'idle' again, and register ->before_damos_apply() + * callback.   *   * Then, the first followup ->before_damos_apply() callback   * (damon_sysfs_before_damos_apply()) sets the status 'started'.  The first - * ->after_sampling() callback (damon_sysfs_after_sampling()) after the call - * is called only after the scheme is completely applied - * to the given snapshot.  Hence the callback knows the situation by showing - * 'started' status, and sets the status as 'finished'.  Then, - * damon_sysfs_before_damos_apply() understands the situation by showing the - * 'finished' status and do nothing. + * ->after_sampling() or ->after_aggregation() callback + *  (damon_sysfs_cmd_request_callback()) after the call is called only after + *  the scheme is completely applied to the given snapshot.  Hence the callback + *  knows the situation by showing 'started' status, and sets the status as + *  'finished'.  Then, damon_sysfs_before_damos_apply() understands the + *  situation by showing the 'finished' status and do nothing.   *   * If DAMOS is not applied to any region due to any reasons including the   * access pattern, the watermarks, the quotas, and the filters, @@ -826,15 +826,48 @@ static const struct kobj_type damon_sysfs_watermarks_ktype = {  struct damos_sysfs_quota_goal {  	struct kobject kobj; +	enum damos_quota_goal_metric metric;  	unsigned long target_value;  	unsigned long current_value;  }; +/* This should match with enum damos_action */ +static const char * const damos_sysfs_quota_goal_metric_strs[] = { +	"user_input", +	"some_mem_psi_us", +}; +  static struct damos_sysfs_quota_goal *damos_sysfs_quota_goal_alloc(void)  {  	return kzalloc(sizeof(struct damos_sysfs_quota_goal), GFP_KERNEL);  } +static ssize_t target_metric_show(struct kobject *kobj, +		struct kobj_attribute *attr, char *buf) +{ +	struct damos_sysfs_quota_goal *goal = container_of(kobj, +			struct damos_sysfs_quota_goal, kobj); + +	return sysfs_emit(buf, "%s\n", +			damos_sysfs_quota_goal_metric_strs[goal->metric]); +} + +static ssize_t target_metric_store(struct kobject *kobj, +		struct kobj_attribute *attr, const char *buf, size_t count) +{ +	struct damos_sysfs_quota_goal *goal = container_of(kobj, +			struct damos_sysfs_quota_goal, kobj); +	enum damos_quota_goal_metric m; + +	for (m = 0; m < NR_DAMOS_QUOTA_GOAL_METRICS; m++) { +		if (sysfs_streq(buf, damos_sysfs_quota_goal_metric_strs[m])) { +			goal->metric = m; +			return count; +		} +	} +	return -EINVAL; +} +  static ssize_t target_value_show(struct kobject *kobj,  		struct kobj_attribute *attr, char *buf)  { @@ -880,6 +913,9 @@ static void damos_sysfs_quota_goal_release(struct kobject *kobj)  	kfree(container_of(kobj, struct damos_sysfs_quota_goal, kobj));  } +static struct kobj_attribute damos_sysfs_quota_goal_target_metric_attr = +		__ATTR_RW_MODE(target_metric, 0600); +  static struct kobj_attribute damos_sysfs_quota_goal_target_value_attr =  		__ATTR_RW_MODE(target_value, 0600); @@ -887,6 +923,7 @@ static struct kobj_attribute damos_sysfs_quota_goal_current_value_attr =  		__ATTR_RW_MODE(current_value, 0600);  static struct attribute *damos_sysfs_quota_goal_attrs[] = { +	&damos_sysfs_quota_goal_target_metric_attr.attr,  	&damos_sysfs_quota_goal_target_value_attr.attr,  	&damos_sysfs_quota_goal_current_value_attr.attr,  	NULL, @@ -1139,6 +1176,7 @@ struct damon_sysfs_quotas {  	unsigned long ms;  	unsigned long sz;  	unsigned long reset_interval_ms; +	unsigned long effective_sz;	/* Effective size quota in bytes */  };  static struct damon_sysfs_quotas *damon_sysfs_quotas_alloc(void) @@ -1252,6 +1290,15 @@ static ssize_t reset_interval_ms_store(struct kobject *kobj,  	return count;  } +static ssize_t effective_bytes_show(struct kobject *kobj, +		struct kobj_attribute *attr, char *buf) +{ +	struct damon_sysfs_quotas *quotas = container_of(kobj, +			struct damon_sysfs_quotas, kobj); + +	return sysfs_emit(buf, "%lu\n", quotas->effective_sz); +} +  static void damon_sysfs_quotas_release(struct kobject *kobj)  {  	kfree(container_of(kobj, struct damon_sysfs_quotas, kobj)); @@ -1266,10 +1313,14 @@ static struct kobj_attribute damon_sysfs_quotas_sz_attr =  static struct kobj_attribute damon_sysfs_quotas_reset_interval_ms_attr =  		__ATTR_RW_MODE(reset_interval_ms, 0600); +static struct kobj_attribute damon_sysfs_quotas_effective_bytes_attr = +		__ATTR_RO_MODE(effective_bytes, 0400); +  static struct attribute *damon_sysfs_quotas_attrs[] = {  	&damon_sysfs_quotas_ms_attr.attr,  	&damon_sysfs_quotas_sz_attr.attr,  	&damon_sysfs_quotas_reset_interval_ms_attr.attr, +	&damon_sysfs_quotas_effective_bytes_attr.attr,  	NULL,  };  ATTRIBUTE_GROUPS(damon_sysfs_quotas); @@ -1868,35 +1919,35 @@ static int damon_sysfs_set_scheme_filters(struct damos *scheme,  	return 0;  } -static unsigned long damos_sysfs_get_quota_score(void *arg) -{ -	return (unsigned long)arg; -} - -static void damos_sysfs_set_quota_score( +static int damos_sysfs_set_quota_score(  		struct damos_sysfs_quota_goals *sysfs_goals,  		struct damos_quota *quota)  { -	struct damos_sysfs_quota_goal *sysfs_goal; +	struct damos_quota_goal *goal, *next;  	int i; -	quota->get_score = NULL; -	quota->get_score_arg = (void *)0; +	damos_for_each_quota_goal_safe(goal, next, quota) +		damos_destroy_quota_goal(goal); +  	for (i = 0; i < sysfs_goals->nr; i++) { -		sysfs_goal = sysfs_goals->goals_arr[i]; +		struct damos_sysfs_quota_goal *sysfs_goal = +			sysfs_goals->goals_arr[i]; +  		if (!sysfs_goal->target_value)  			continue; -		/* Higher score makes scheme less aggressive */ -		quota->get_score_arg = (void *)max( -				(unsigned long)quota->get_score_arg, -				sysfs_goal->current_value * 10000 / +		goal = damos_new_quota_goal(sysfs_goal->metric,  				sysfs_goal->target_value); -		quota->get_score = damos_sysfs_get_quota_score; +		if (!goal) +			return -ENOMEM; +		if (sysfs_goal->metric == DAMOS_QUOTA_USER_INPUT) +			goal->current_value = sysfs_goal->current_value; +		damos_add_quota_goal(quota, goal);  	} +	return 0;  } -void damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes, +int damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,  		struct damon_ctx *ctx)  {  	struct damos *scheme; @@ -1904,12 +1955,41 @@ void damos_sysfs_set_quota_scores(struct damon_sysfs_schemes *sysfs_schemes,  	damon_for_each_scheme(scheme, ctx) {  		struct damon_sysfs_scheme *sysfs_scheme; +		int err; + +		/* user could have removed the scheme sysfs dir */ +		if (i >= sysfs_schemes->nr) +			break;  		sysfs_scheme = sysfs_schemes->schemes_arr[i]; -		damos_sysfs_set_quota_score(sysfs_scheme->quotas->goals, +		err = damos_sysfs_set_quota_score(sysfs_scheme->quotas->goals,  				&scheme->quota); +		if (err) +			/* kdamond will clean up schemes and terminated */ +			return err;  		i++;  	} +	return 0; +} + +void damos_sysfs_update_effective_quotas( +		struct damon_sysfs_schemes *sysfs_schemes, +		struct damon_ctx *ctx) +{ +	struct damos *scheme; +	int schemes_idx = 0; + +	damon_for_each_scheme(scheme, ctx) { +		struct damon_sysfs_quotas *sysfs_quotas; + +		/* user could have removed the scheme sysfs dir */ +		if (schemes_idx >= sysfs_schemes->nr) +			break; + +		sysfs_quotas = +			sysfs_schemes->schemes_arr[schemes_idx++]->quotas; +		sysfs_quotas->effective_sz = scheme->quota.esz; +	}  }  static struct damos *damon_sysfs_mk_scheme( @@ -1949,13 +2029,17 @@ static struct damos *damon_sysfs_mk_scheme(  		.low = sysfs_wmarks->low,  	}; -	damos_sysfs_set_quota_score(sysfs_quotas->goals, "a); -  	scheme = damon_new_scheme(&pattern, sysfs_scheme->action,  			sysfs_scheme->apply_interval_us, "a, &wmarks);  	if (!scheme)  		return NULL; +	err = damos_sysfs_set_quota_score(sysfs_quotas->goals, &scheme->quota); +	if (err) { +		damon_destroy_scheme(scheme); +		return NULL; +	} +  	err = damon_sysfs_set_scheme_filters(scheme, sysfs_filters);  	if (err) {  		damon_destroy_scheme(scheme); @@ -1991,7 +2075,11 @@ static void damon_sysfs_update_scheme(struct damos *scheme,  	scheme->quota.weight_nr_accesses = sysfs_weights->nr_accesses;  	scheme->quota.weight_age = sysfs_weights->age; -	damos_sysfs_set_quota_score(sysfs_quotas->goals, &scheme->quota); +	err = damos_sysfs_set_quota_score(sysfs_quotas->goals, &scheme->quota); +	if (err) { +		damon_destroy_scheme(scheme); +		return; +	}  	scheme->wmarks.metric = sysfs_wmarks->metric;  	scheme->wmarks.interval = sysfs_wmarks->interval_us; @@ -2118,7 +2206,7 @@ static int damon_sysfs_before_damos_apply(struct damon_ctx *ctx,   * callback is registered, damon_sysfs_lock should be held to ensure the   * regions directories exist.   */ -static int damon_sysfs_after_sampling(struct damon_ctx *ctx) +void damos_sysfs_mark_finished_regions_updates(struct damon_ctx *ctx)  {  	struct damon_sysfs_schemes *sysfs_schemes =  		damon_sysfs_schemes_for_damos_callback; @@ -2134,8 +2222,6 @@ static int damon_sysfs_after_sampling(struct damon_ctx *ctx)  			sysfs_regions->upd_status =  				DAMOS_TRIED_REGIONS_UPD_FINISHED;  	} - -	return 0;  }  /* Called from damon_sysfs_cmd_request_callback under damon_sysfs_lock */ @@ -2208,7 +2294,6 @@ int damon_sysfs_schemes_update_regions_start(  	damos_tried_regions_init_upd_status(sysfs_schemes, ctx);  	damos_regions_upd_total_bytes_only = total_bytes_only;  	ctx->callback.before_damos_apply = damon_sysfs_before_damos_apply; -	ctx->callback.after_sampling = damon_sysfs_after_sampling;  	return 0;  } @@ -2237,7 +2322,6 @@ int damon_sysfs_schemes_update_regions_stop(struct damon_ctx *ctx)  {  	damon_sysfs_schemes_for_damos_callback = NULL;  	ctx->callback.before_damos_apply = NULL; -	ctx->callback.after_sampling = NULL;  	damon_sysfs_schemes_region_idx = 0;  	return 0;  }  |