Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 09 Oct 2001 11:29:23 -0700 (PDT)
From:      John Baldwin <jhb@FreeBSD.org>
To:        arch@FreeBSD.org
Subject:   ucred API
Message-ID:  <XFMail.011009112923.jhb@FreeBSD.org>

next in thread | raw e-mail | index | archive | help
Hey all.  I'd like to make the following changes to the ucred API in the
interests of making the locking more sane.  The changes will occur in 2 stages.

Stage 1:
    - Add a new function crshared(cr) that returns true if ucred cr's
      refcount is greater than 1.
    - Change crhold(cr) to return a pointer to the ucred it bumped the
      reference of.  Thus, the following code:

        cr = foo->f_cred;
        crhold(cr);

      becomes:

        cr = crhold(foo->f_cred);

      (suggested by Terry L.)
    - Change the crcopy() function to actually copy the contents of one
      ucred to another.  This is much more lock friendly as having crcopy()
      block on malloc introduces locking problems.  Before code:

        PROC_LOCK(p);
        cred = p->p_ucred);
        PROC_UNLOCK(p);                         /* XXX: race */
        p->p_ucred = crcopy(cred);              /* XXX: can block! */
        PROC_LOCK(p);
        p->p_ucred = cred;
        ...
        PROC_UNLOCK(p);

      New code:

        newcred = crget();
        PROC_LOCK(p);
        oldcred = p->p_ucred;
        error = suser(oldcred);
        if (error == 0) {
                crcopy(newcred, oldcred);
                ....
                p->p_ucred = newcred;
                newcred = oldcred;
        }
        PROC_UNLOCK(p);
        crfree(newcred);

        Which doesn't block during the critical section and can make all
        the access checks and changes as one "atomic" change.

Stage 2:
    - Add a per-thread reference to the ucred that is created on syscall
      entry and released on syscall exit.  It is also created and released
      if needed on trap enter/exit.  It is _not_ created for interrupts since
      interrupts should not care about the ucred of their borrowed context.
      The per-thread ucred reference will then point to a ucred that won't
      ever change (setuid, etc. update the per-process ucred) and thus won't
      need any locking.  Almost all references to ucreds for suser(), VOP's
      etc. will use the thread reference.  This will ensure that a thread's
      ucred will be the same for an entire syscall which will close many
      races involving multithreaded programs and ucreds.  The only place where
      the per-process ucred will be used for access checks is places that
      modify the ucred as we want to ensure there is no race of one thread
      making a credential change it isn't qualified to make due to it performing
      its access checks on a stale ucred before updating the master ucred.

I've talked with Robert Watson about these already and they sound good to him. 
Any objections?

-- 

John Baldwin <jhb@FreeBSD.org> -- http://www.FreeBSD.org/~jhb/
PGP Key: http://www.baldwin.cx/~john/pgpkey.asc
"Power Users Use the Power to Serve!"  -  http://www.FreeBSD.org/

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?XFMail.011009112923.jhb>