From: Alex Hornung Date: Mon, 21 Dec 2009 08:22:46 +0000 (+0000) Subject: devfs - Introduce MPSAFE read/write/ioctl support X-Git-Tag: v2.7.1~255 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/3a1032a61f3ea2b7ca93c34278f5220f31a9b9a6 devfs - Introduce MPSAFE read/write/ioctl support * 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. --- diff --git a/sys/sys/device.h b/sys/sys/device.h index 537005bf85..5bdf6db5a9 100644 --- a/sys/sys/device.h +++ b/sys/sys/device.h @@ -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. diff --git a/sys/vfs/devfs/devfs_core.c b/sys/vfs/devfs/devfs_core.c index ecd6edfb80..cb0b72f21b 100644 --- a/sys/vfs/devfs/devfs_core.c +++ b/sys/vfs/devfs/devfs_core.c @@ -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"); diff --git a/sys/vfs/devfs/devfs_vnops.c b/sys/vfs/devfs/devfs_vnops.c index 0366df2aaf..0398422047 100644 --- a/sys/vfs/devfs/devfs_vnops.c +++ b/sys/vfs/devfs/devfs_vnops.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -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");