[Devel] [PATCH] mm: high order allocation detector

Nikita Yushchenko nikita.yushchenko at virtuozzo.com
Tue Aug 31 17:16:32 MSK 2021


>> +static void hoad_reset_counter(struct work_struct *work)
>> +{
>> +	struct hoad_order_info *hoi = container_of(work,
>> +			struct hoad_order_info, reset_counter_work.work);
>> +
>> +	atomic_set(&hoi->counter, 0);
> 
> Do we really need work to do such simple action? Why plain timer is not enough?

Ok, will convert to timer.

>> +static void hoad_send_uevent(struct work_struct *work)
>> +{
>> +	char order_string[16];
>> +	char *envp[] = { order_string, NULL };
> 
> Please, use new lines after declarations.

Ok

> 
>> +	sprintf(order_string, "ORDER=%d", hoad_uevent_order);
>> +	kobject_uevent_env(hoad_kobj, KOBJ_CHANGE, envp);
>> +}
>> +static DECLARE_WORK(hoad_send_uevent_work, hoad_send_uevent);
>> +
>> +static void hoad_resume(struct work_struct *work)
>> +{
>> +	hoad_uevent_order = 0;
> 
> The same is here: do we really need work here?

Ok, will convert to timer

>> +	if (oldhoi) {
>> +		synchronize_rcu();
>> +		cancel_delayed_work_sync(&oldhoi->reset_counter_work);
> 
> Why do we completely cancel this? We possible updated single order entity,
> don't other orders still need to be reset?

It is per-order, and accesses hoad_order_info container.
Cancelling one for 'oldhoi' before freeing 'oldhoi'.

After converting to timer, this situation will remain.

>> +			p += sprintf(p, "order %u: %u/%u in %u/%u msecs\n",
>> +					order, counter, hoi->max_allocs,
>> +					msecs, jiffies_to_msecs(hoi->interval));
> 
> Any guarantees all printed in this function data fits provided @buf?

Yes, buf is a full page, number of orders is limited (<20), this leaves >200 bytes per order, which is 
more than enough.

>> +		if (msecs > 1000 * 60 * 60 * 24 * 5)
> 
> Every magic number should be described with #define.

Do you want separate defines for every number?
Or things like "5 * MSECS_PER_DAY' can work?

> 
>> +			ret = -EINVAL;
>> +		else {
>> +do_resume:
>> +			d = msecs_to_jiffies(msecs);
>> +			hoad_resume_jiffies = jiffies + d;
>> +			cancel_delayed_work_sync(&hoad_resume_work);
>> +			schedule_delayed_work(&hoad_resume_work, d);
> 
> It looks like we may use mod_delayed_work(system_wq, ...) here instead of two calls above.

This will likely get changed to mod_timer()

>> +	}
>> +	else if (!strcmp(q, "resume")) {
> 
> Please, move this "else if" up to the same line with "}" bracket

Sure - looks like a typo

>> +		msecs = 0;
>> +		goto do_resume;
>> +	} else
>> +		ret = -EINVAL;
> 
> In case of you have "{}" brackets in a single branch of if-else, then every if, else if, else
> branch has to have "{}" brackets even if it's one liner.

Ok

>> +	struct kset *kset = kset = kset_create_and_add("hoad", NULL, mm_kobj);
> 
> 1)kset = kset is here.
> 2)New line is needed after declaration.

Ok

> 
>> +	if (!kset)
>> +		return -ENOMEM;
>> +	hoad_kobj = &kset->kobj;
>> +	hoad_kobj->kset = kset;
>> +
>> +	ret = sysfs_create_file(hoad_kobj, &hoad_control_attr.attr);
>> +	if (ret) {
>> +		hoad_kobj->kset = NULL;
>> +		hoad_kobj = NULL;
>> +		kset_put(kset);
>> +		return ret;
>> +	}
> 
> Why not:
> 
> 	ret = sysfs_create_file(hoad_kobj, &hoad_control_attr.attr);
> 	if (ret) {
> 		kset_put(kset);
> 		return ret;
> 	}
> 
> 	hoad_kobj = &kset->kobj;
> 	hoad_kobj->kset = kset;

I want to:
- use sysfs_create_file(hoad_kobj, ...), not sysfs_create_file(&kset->kobj, ...)
- group configuration together


> Also, as I see in kernel code, the pair bracket for kset_create_and_add() is kset_unregister().
> Why we use kset_put() instead?

Formally, in kset_create_and_add(), sysfs entry gets added and can be opened by other process. So must 
use refcount-based freeing.


More information about the Devel mailing list