cpuset_setithread and PROC_LOCK vs. thread_lock usage: Is this correct?

Mark Millard markmi at dsl-only.net
Tue May 30 01:48:37 UTC 2017


[FYI: The source referenced is from head
-r317820.]

In the process of trying to get evidence
related to a periodic/random kernel panic
for TARGET_ARCH=powerpc I ran into what
follows. I've no evidence that it is tied
to the panics. It is just something that
I read that looked a little odd to me.

But it looked like a good thing to ask
about, at least based on my level of
ignorance of such things for the kernel.
(The more I learn the better.)

I normally see the likes of:

                thread_lock(td);
                tdset = td->td_cpuset;

and:

        thread_lock(td);
        error = cpuset_shadow(td->td_cpuset, nset, mask);

but in cpuset_setithread the comments read like
a PROC_LOCK is in use instead:

int
cpuset_setithread(lwpid_t id, int cpu)
{
. . .
        struct proc *p;
. . .
        error = cpuset_which(CPU_WHICH_TID, id, &p, &td, &old_set);
        if (error != 0 || ((cs_id = alloc_unr(cpuset_unr)) == CPUSET_INVALID))
                goto out;

        /* cpuset_which() returns with PROC_LOCK held. */
        old_set = td->td_cpuset;
. . .

That seems true for !error but is a different
lock than used elsewhere (those thread_lock's).

cpuset_which does seem to end up with the PROC_LOCK
as indicated:

int
cpuset_which(cpuwhich_t which, id_t id, struct proc **pp, struct thread **tdp,
    struct cpuset **setp)
{
. . .
        case CPU_WHICH_TID:
                if (id == -1) {
                        PROC_LOCK(curproc);
                        p = curproc;
                        td = curthread;
                        break;
                }
                td = tdfind(id, -1);
                if (td == NULL)
                        return (ESRCH);
                p = td->td_proc;
                break;
. . .
        error = p_cansched(curthread, p);
        if (error) {
                PROC_UNLOCK(p);
                return (error);
        }
        if (td == NULL)
                td = FIRST_THREAD_IN_PROC(p);
        *pp = p;
        *tdp = td;
        return (0);
}

(tdfind does rw_rlock on tidhash_lock,
PROC_LOCK on td->td_proc. It only
PROC_UNLOCK's for PRS_NEW and
is comments to return with the proc
lock held. No thread_lock's involved.)

So it appears to me that in cpuset_setithread :

        /* cpuset_which() returns with PROC_LOCK held. */
        old_set = td->td_cpuset;

might happen with no thread_lock protecting the
td use (say to avoid reading during updates). (This
might also apply to what old_set points to.)

Similarly for:

cpuset_setithread(lwpid_t id, int cpu)
{
. . .
        struct cpuset *parent, *old_set;
. . .
        error = cpuset_shadow(parent, nset, &mask);
. . .

it does not appear that a thread_lock is involved
around the cpuset_shadow operation, unlike
elsewhere.

Is this lack of thread_lock involvement in fact
okay for some reason in each case?

===
Mark Millard
markmi at dsl-only.net



More information about the freebsd-hackers mailing list