devfs - Introduce MPSAFE read/write/ioctl support
authorAlex Hornung <ahornung@gmail.com>
Mon, 21 Dec 2009 08:22:46 +0000 (08:22 +0000)
committerAlex Hornung <ahornung@gmail.com>
Mon, 21 Dec 2009 08:31:20 +0000 (08:31 +0000)
* Add D_MPSAFE_READ, D_MPSAFE_WRITE and D_MPSAFE_IOCTL defines for use
  with the dev_ops structure to mark the read,write and/or ioctl methods
  as mpsafe.

* Change devfs so that it won't acquire the mplock for
  read/writes/ioctls that are marked as MPSAFE.

* Add some statistics under sysctl vfs.devfs about the number of read
  and writes done with the mplock and without it.

* While here, MPSAFE specf_stat in devfs so it doesn't acquire the
  mplock anymore as it doesn't even need it.

sys/sys/device.h
sys/vfs/devfs/devfs_core.c
sys/vfs/devfs/devfs_vnops.c

index 537005b..5bdf6db 100644 (file)
@@ -260,6 +260,9 @@ struct dev_ops {
 #define D_TRACKCLOSE   0x00080000      /* track all closes */
 #define D_MASTER       0x00100000      /* used by pty/tty code */
 #define D_KQFILTER     0x00200000      /* has kqfilter entry */
+#define D_MPSAFE_READ  0x00400000      /* doesn't require mplock for reads */
+#define D_MPSAFE_WRITE 0x00800000      /* doesn't require mplock for writes */
+#define D_MPSAFE_IOCTL 0x01000000      /* doesn't require mplock for ioctls */
 
 /*
  * A union of all possible argument structures.
index ecd6edf..cb0b72f 100644 (file)
@@ -2368,7 +2368,7 @@ devfs_sysctl_devname_helper(SYSCTL_HANDLER_ARGS)
 SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
                        NULL, 0, devfs_sysctl_devname_helper, "", "helper for devname(3)");
 
-static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "devfs");
+SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "devfs");
 TUNABLE_INT("vfs.devfs.debug", &devfs_debug_enable);
 SYSCTL_INT(_vfs_devfs, OID_AUTO, debug, CTLFLAG_RW, &devfs_debug_enable,
                0, "Enable DevFS debugging");
index 0366df2..0398422 100644 (file)
@@ -57,6 +57,7 @@
 #include <sys/ttycom.h>
 #include <sys/tty.h>
 #include <sys/diskslice.h>
+#include <sys/sysctl.h>
 #include <sys/devfs.h>
 #include <sys/pioctl.h>
 
@@ -115,6 +116,8 @@ static __inline int sequential_heuristic(struct uio *, struct file *);
 
 extern struct lock devfs_lock;
 
+static int mpsafe_reads, mpsafe_writes, mplock_reads, mplock_writes;
+
 /*
  * devfs vnode operations for regular files
  */
@@ -1027,28 +1030,31 @@ devfs_specf_read(struct file *fp, struct uio *uio,
        int error;
        cdev_t dev;
 
-       get_mplock();
        KASSERT(uio->uio_td == curthread,
                ("uio_td %p is not td %p", uio->uio_td, curthread));
 
+       if (uio->uio_resid == 0)
+               return 0;
+
        vp = (struct vnode *)fp->f_data;
-       if (vp == NULL || vp->v_type == VBAD) {
-               error = EBADF;
-               goto done;
-       }
+       if (vp == NULL || vp->v_type == VBAD)
+               return EBADF;
+
        node = DEVFS_NODE(vp);
 
-       if ((dev = vp->v_rdev) == NULL) {
-               error = EBADF;
-               goto done;
+       if ((dev = vp->v_rdev) == NULL)
+               return EBADF;
+
+       /* only acquire mplock for devices that require it */
+       if (!(dev_dflags(dev) & D_MPSAFE_READ)) {
+               atomic_add_int(&mplock_reads, 1);
+               get_mplock();
+       } else {
+               atomic_add_int(&mpsafe_reads, 1);
        }
 
        reference_dev(dev);
 
-       if (uio->uio_resid == 0) {
-               error = 0;
-               goto done;
-       }
        if ((flags & O_FOFFSET) == 0)
                uio->uio_offset = fp->f_offset;
 
@@ -1077,8 +1083,10 @@ devfs_specf_read(struct file *fp, struct uio *uio,
        if ((flags & O_FOFFSET) == 0)
                fp->f_offset = uio->uio_offset;
        fp->f_nextoff = uio->uio_offset;
-done:
-       rel_mplock();
+
+       if (!(dev_dflags(dev) & D_MPSAFE_READ))
+               rel_mplock();
+
        return (error);
 }
 
@@ -1093,24 +1101,31 @@ devfs_specf_write(struct file *fp, struct uio *uio,
        int error;
        cdev_t dev;
 
-       get_mplock();
        KASSERT(uio->uio_td == curthread,
                ("uio_td %p is not p %p", uio->uio_td, curthread));
 
        vp = (struct vnode *)fp->f_data;
-       if (vp == NULL || vp->v_type == VBAD) {
-               error = EBADF;
-               goto done;
-       }
+       if (vp == NULL || vp->v_type == VBAD)
+               return EBADF;
+
        node = DEVFS_NODE(vp);
+
        if (vp->v_type == VREG)
                bwillwrite(uio->uio_resid);
+
        vp = (struct vnode *)fp->f_data;
 
-       if ((dev = vp->v_rdev) == NULL) {
-               error = EBADF;
-               goto done;
+       if ((dev = vp->v_rdev) == NULL)
+               return EBADF;
+
+       /* only acquire mplock for devices that require it */
+       if (!(dev_dflags(dev) & D_MPSAFE_WRITE)) {
+               atomic_add_int(&mplock_writes, 1);
+               get_mplock();
+       } else {
+               atomic_add_int(&mpsafe_writes, 1);
        }
+
        reference_dev(dev);
 
        if ((flags & O_FOFFSET) == 0)
@@ -1159,8 +1174,9 @@ devfs_specf_write(struct file *fp, struct uio *uio,
        if ((flags & O_FOFFSET) == 0)
                fp->f_offset = uio->uio_offset;
        fp->f_nextoff = uio->uio_offset;
-done:
-       rel_mplock();
+
+       if (!(dev_dflags(dev) & D_MPSAFE_WRITE))
+               rel_mplock();
        return (error);
 }
 
@@ -1169,27 +1185,24 @@ static int
 devfs_specf_stat(struct file *fp, struct stat *sb, struct ucred *cred)
 {
        struct vnode *vp;
+       struct vattr vattr;
+       struct vattr *vap;
+       u_short mode;
+       cdev_t dev;
        int error;
 
-       get_mplock();
        vp = (struct vnode *)fp->f_data;
+       if (vp == NULL || vp->v_type == VBAD)
+               return EBADF;
+
        error = vn_stat(vp, sb, cred);
-       if (error) {
-               rel_mplock();
+       if (error)
                return (error);
-       }
-
-       struct vattr vattr;
-       struct vattr *vap;
-       u_short mode;
-       cdev_t dev;
 
        vap = &vattr;
        error = VOP_GETATTR(vp, vap);
-       if (error) {
-               rel_mplock();
+       if (error)
                return (error);
-       }
 
        /*
         * Zero the spare stat fields
@@ -1216,6 +1229,7 @@ devfs_specf_stat(struct file *fp, struct stat *sb, struct ucred *cred)
                sb->st_nlink = (nlink_t)-1;
        else
                sb->st_nlink = vap->va_nlink;
+
        sb->st_uid = vap->va_uid;
        sb->st_gid = vap->va_gid;
        sb->st_rdev = dev2udev(DEVFS_NODE(vp)->d_dev);
@@ -1263,7 +1277,6 @@ devfs_specf_stat(struct file *fp, struct stat *sb, struct ucred *cred)
 
        sb->st_blocks = vap->va_bytes / S_BLKSIZE;
 
-       rel_mplock();
        return (0);
 }
 
@@ -1350,12 +1363,12 @@ devfs_specf_ioctl(struct file *fp, u_long com, caddr_t data,
        size_t namlen;
        const char *name;
 
-       get_mplock();
        vp = ((struct vnode *)fp->f_data);
-       if ((dev = vp->v_rdev) == NULL) {
-               error = EBADF;          /* device was revoked */
-               goto out;
-       }
+
+       if ((dev = vp->v_rdev) == NULL)
+               return EBADF;           /* device was revoked */
+
+       reference_dev(dev);
 
        node = DEVFS_NODE(vp);
 
@@ -1384,9 +1397,13 @@ devfs_specf_ioctl(struct file *fp, u_long com, caddr_t data,
                            "ioctl stuff: error: %d\n", error);
                goto out;
        }
-       reference_dev(dev);
+
+       /* only acquire mplock for devices that require it */
+       if (!(dev_dflags(dev) & D_MPSAFE_IOCTL))
+               get_mplock();
+
        error = dev_dioctl(dev, com, data, fp->f_flag, ucred, msg);
-       release_dev(dev);
+
 #if 0
        if (node) {
                nanotime(&node->atime);
@@ -1394,6 +1411,9 @@ devfs_specf_ioctl(struct file *fp, u_long com, caddr_t data,
        }
 #endif
 
+       if (!(dev_dflags(dev) & D_MPSAFE_IOCTL))
+               rel_mplock();
+
        if (com == TIOCSCTTY) {
                devfs_debug(DEVFS_DEBUG_DEBUG,
                            "devfs_specf_ioctl: got TIOCSCTTY on %s\n",
@@ -1431,7 +1451,7 @@ devfs_specf_ioctl(struct file *fp, u_long com, caddr_t data,
        }
 
 out:
-       rel_mplock();
+       release_dev(dev);
        devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_specf_ioctl() finished! \n");
        return (error);
 }
@@ -2080,3 +2100,14 @@ sequential_heuristic(struct uio *uio, struct file *fp)
                fp->f_seqcount = 0;
        return(0);
 }
+
+extern SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "devfs");
+
+SYSCTL_INT(_vfs_devfs, OID_AUTO, mpsafe_writes, CTLFLAG_RD, &mpsafe_writes,
+               0, "mpsafe writes");
+SYSCTL_INT(_vfs_devfs, OID_AUTO, mplock_writes, CTLFLAG_RD, &mplock_writes,
+               0, "non-mpsafe writes");
+SYSCTL_INT(_vfs_devfs, OID_AUTO, mpsafe_reads, CTLFLAG_RD, &mpsafe_reads,
+               0, "mpsafe reads");
+SYSCTL_INT(_vfs_devfs, OID_AUTO, mplock_reads, CTLFLAG_RD, &mplock_reads,
+               0, "non-mpsafe reads");