diff options
Diffstat (limited to 'kernel/cgroup/misc.c')
| -rw-r--r-- | kernel/cgroup/misc.c | 80 | 
1 files changed, 74 insertions, 6 deletions
| diff --git a/kernel/cgroup/misc.c b/kernel/cgroup/misc.c index 79a3717a5803..0e26068995a6 100644 --- a/kernel/cgroup/misc.c +++ b/kernel/cgroup/misc.c @@ -121,6 +121,30 @@ static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg,  		  misc_res_name[type]);  } +static void misc_cg_update_watermark(struct misc_res *res, u64 new_usage) +{ +	u64 old; + +	while (true) { +		old = atomic64_read(&res->watermark); +		if (new_usage <= old) +			break; +		if (atomic64_cmpxchg(&res->watermark, old, new_usage) == old) +			break; +	} +} + +static void misc_cg_event(enum misc_res_type type, struct misc_cg *cg) +{ +	atomic64_inc(&cg->res[type].events_local); +	cgroup_file_notify(&cg->events_local_file); + +	for (; parent_misc(cg); cg = parent_misc(cg)) { +		atomic64_inc(&cg->res[type].events); +		cgroup_file_notify(&cg->events_file); +	} +} +  /**   * misc_cg_try_charge() - Try charging the misc cgroup.   * @type: Misc res type to charge. @@ -159,14 +183,12 @@ int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount)  			ret = -EBUSY;  			goto err_charge;  		} +		misc_cg_update_watermark(res, new_usage);  	}  	return 0;  err_charge: -	for (j = i; j; j = parent_misc(j)) { -		atomic64_inc(&j->res[type].events); -		cgroup_file_notify(&j->events_file); -	} +	misc_cg_event(type, i);  	for (j = cg; j != i; j = parent_misc(j))  		misc_cg_cancel_charge(type, j, amount); @@ -308,6 +330,29 @@ static int misc_cg_current_show(struct seq_file *sf, void *v)  }  /** + * misc_cg_peak_show() - Show the peak usage of the misc cgroup. + * @sf: Interface file + * @v: Arguments passed + * + * Context: Any context. + * Return: 0 to denote successful print. + */ +static int misc_cg_peak_show(struct seq_file *sf, void *v) +{ +	int i; +	u64 watermark; +	struct misc_cg *cg = css_misc(seq_css(sf)); + +	for (i = 0; i < MISC_CG_RES_TYPES; i++) { +		watermark = atomic64_read(&cg->res[i].watermark); +		if (READ_ONCE(misc_res_capacity[i]) || watermark) +			seq_printf(sf, "%s %llu\n", misc_res_name[i], watermark); +	} + +	return 0; +} + +/**   * misc_cg_capacity_show() - Show the total capacity of misc res on the host.   * @sf: Interface file   * @v: Arguments passed @@ -331,20 +376,33 @@ static int misc_cg_capacity_show(struct seq_file *sf, void *v)  	return 0;  } -static int misc_events_show(struct seq_file *sf, void *v) +static int __misc_events_show(struct seq_file *sf, bool local)  {  	struct misc_cg *cg = css_misc(seq_css(sf));  	u64 events;  	int i;  	for (i = 0; i < MISC_CG_RES_TYPES; i++) { -		events = atomic64_read(&cg->res[i].events); +		if (local) +			events = atomic64_read(&cg->res[i].events_local); +		else +			events = atomic64_read(&cg->res[i].events);  		if (READ_ONCE(misc_res_capacity[i]) || events)  			seq_printf(sf, "%s.max %llu\n", misc_res_name[i], events);  	}  	return 0;  } +static int misc_events_show(struct seq_file *sf, void *v) +{ +	return __misc_events_show(sf, false); +} + +static int misc_events_local_show(struct seq_file *sf, void *v) +{ +	return __misc_events_show(sf, true); +} +  /* Misc cgroup interface files */  static struct cftype misc_cg_files[] = {  	{ @@ -358,6 +416,10 @@ static struct cftype misc_cg_files[] = {  		.seq_show = misc_cg_current_show,  	},  	{ +		.name = "peak", +		.seq_show = misc_cg_peak_show, +	}, +	{  		.name = "capacity",  		.seq_show = misc_cg_capacity_show,  		.flags = CFTYPE_ONLY_ON_ROOT, @@ -368,6 +430,12 @@ static struct cftype misc_cg_files[] = {  		.file_offset = offsetof(struct misc_cg, events_file),  		.seq_show = misc_events_show,  	}, +	{ +		.name = "events.local", +		.flags = CFTYPE_NOT_ON_ROOT, +		.file_offset = offsetof(struct misc_cg, events_local_file), +		.seq_show = misc_events_local_show, +	},  	{}  }; |