Question

The latest kref document from linux kernel can be found: https://www.kernel.org/doc/Documentation/kref.txt

The first example in this document is repeated as following:

void data_release(struct kref *ref)
{
    struct my_data *data = container_of(ref, struct my_data, refcount);
    kfree(data);
}

void more_data_handling(void *cb_data)
{
    struct my_data *data = cb_data;
    .
    . do stuff with data here
    .
    kref_put(&data->refcount, data_release);
}

int my_data_handler(void)
{
    int rv = 0;
    struct my_data *data;
    struct task_struct *task;
    data = kmalloc(sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;
    kref_init(&data->refcount);

    kref_get(&data->refcount);
    task = kthread_run(more_data_handling, data, "more_data_handling");
    if (task == ERR_PTR(-ENOMEM)) {
        rv = -ENOMEM;
        goto out;
    }

    .
    . do stuff with data here
    .
 out:
    kref_put(&data->refcount, data_release);
    return rv;
}

In my_data_handler, kref_init() already put 1 to refcount, and kref_get() next made the refcount 2. But if kthread_run fails, only one kref_put will take place (right after the out tag), it renders the refcount to be 1 at last, and the data will never be freed.

I also noticed that there once was a kref_put before goto out in the document before 2009, but it was removed by a patch (https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/Documentation/kref.txt?id=8f1ecc9fbc5b223e4f5d5bb8bcd6f5672c4bc4b6), which claimed that this kref_put was redudent.

Was it helpful?

Solution

You are 100% correct. kref_init starts with refcount 1, and its up to my_data_handler thread to kref_put() it. kref_get() increase the refcount to 2 in order to keep the data alive for "more_data_handling" thread. Its "more_data_handling" thread responsibility to kref_put() that.

In the edge case where the thread failed to open and thus can not take care of its responsibilities, Its my_data_handler() responsibility to kref_put() once for the failed "more_data_handling" thread and again for itself.

I urge you to send an email, to the original author, the person removing the needed kref_put, and to kernel mailing list.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top