Date: Sun, 7 Jun 2009 11:22:37 GMT From: Zhao Shuai <zhaoshuai@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 163701 for review Message-ID: <200906071122.n57BMb1A086187@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=163701 Change 163701 by zhaoshuai@zhaoshuai on 2009/06/07 11:21:54 add O_NONBLOCK handling in fifo_open() Affected files ... .. //depot/projects/soc2009/fifo/sys/fs/fifofs/fifo_vnops.c#9 edit Differences ... ==== //depot/projects/soc2009/fifo/sys/fs/fifofs/fifo_vnops.c#9 (text+ko) ==== @@ -40,6 +40,8 @@ #include <sys/filedesc.h> #include <sys/filio.h> #include <sys/fcntl.h> +#include <sys/kernel.h> +#include <sys/lock.h> #include <sys/mutex.h> #include <sys/unistd.h> #include <sys/vnode.h> @@ -114,6 +116,9 @@ .vop_write = VOP_PANIC, }; +struct mtx fifo_mtx; +MTX_SYSINIT(fifo, &fifo_mtx, "fifo mutex", MTX_DEF); + /* * Open called to set up a new instance of a fifo or * to find an active instance of a fifo. @@ -155,15 +160,77 @@ /* * General access to fi_readers and fi_writers is protected using * the vnode lock. + * + * Protect the increment of fi_readers and fi_writers and the + * associated calls to wakeup() with the fifo mutex in addition + * to the vnode lock. This allows the vnode lock to be dropped + * for the msleep() calls below, and using the fifo mutex with + * msleep() prevents the wakeup from being missed. */ - if (ap->a_mode & FREAD) + mtx_lock(&fifo_mtx); + if (ap->a_mode & FREAD) { fip->fi_readers++; + if (fip->fi_readers == 1 && fip->fi_writers > 0) + wakeup(&fip->fi_writers); + } if (ap->a_mode & FWRITE) { if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) return (ENXIO); fip->fi_writers++; + if (fip->fi_writers == 1 && fip->fi_readers > 0) + wakeup(&fip->fi_readers); } - + if ((ap->a_mode & O_NONBLOCK) == 0) { + if ((ap->a_mode & FREAD) && fip->fi_writers == 0) { + VOP_UNLOCK(vp, 0); + error = msleep(&fip->fi_readers, &fifo_mtx, + PDROP | PCATCH, "fifoor", 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if (error) { + fip->fi_readers--; + if (fip->fi_readers == 0) { + generic_pipe_close(fip->fi_rpipe); + if (fip->fi_writers == 0) { + generic_pipe_close(fip->fi_wpipe); + vp->v_fifoinfo = NULL; + free(fip, M_VNODE); + } + } + return (error); + } + mtx_lock(&fifo_mtx); + /* + * We must have got woken up because we had a writer. + * That (and not still having one) is the condition + * that we must wait for. + */ + } + if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) { + VOP_UNLOCK(vp, 0); + error = msleep(&fip->fi_writers, &fifo_mtx, + PDROP | PCATCH, "fifoow", 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if (error) { + fip->fi_writers--; + if (fip->fi_writers == 0) { + generic_pipe_close(fip->fi_wpipe); + if (fip->fi_readers == 0) { + generic_pipe_close(fip->fi_rpipe); + vp->v_fifoinfo = NULL; + free(fip, M_VNODE); + } + } + return (error); + } + /* + * We must have got woken up because we had + * a reader. That (and not still having one) + * is the condition that we must wait for. + */ + mtx_lock(&fifo_mtx); + } + } + mtx_unlock(&fifo_mtx); KASSERT(fp != NULL, ("can't fifo/vnode bypass")); KASSERT(fp->f_ops == &badfileops, ("not badfileops in fifo_open")); finit(fp, fp->f_flag, DTYPE_FIFO, fip, &fifo_ops_f);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906071122.n57BMb1A086187>