Date: Wed, 21 Aug 2013 17:36:02 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r254602 - in head/sys: fs/devfs kern sys Message-ID: <201308211736.r7LHa2qD078858@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Wed Aug 21 17:36:01 2013 New Revision: 254602 URL: http://svnweb.freebsd.org/changeset/base/254602 Log: Make the seek a method of the struct fileops. Tested by: pho Sponsored by: The FreeBSD Foundation Modified: head/sys/fs/devfs/devfs_vnops.c head/sys/kern/vfs_syscalls.c head/sys/kern/vfs_vnops.c head/sys/sys/file.h Modified: head/sys/fs/devfs/devfs_vnops.c ============================================================================== --- head/sys/fs/devfs/devfs_vnops.c Wed Aug 21 17:23:24 2013 (r254601) +++ head/sys/fs/devfs/devfs_vnops.c Wed Aug 21 17:36:01 2013 (r254602) @@ -1697,6 +1697,7 @@ static struct fileops devfs_ops_f = { .fo_chmod = vn_chmod, .fo_chown = vn_chown, .fo_sendfile = vn_sendfile, + .fo_seek = vn_seek, .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; Modified: head/sys/kern/vfs_syscalls.c ============================================================================== --- head/sys/kern/vfs_syscalls.c Wed Aug 21 17:23:24 2013 (r254601) +++ head/sys/kern/vfs_syscalls.c Wed Aug 21 17:36:01 2013 (r254602) @@ -1879,77 +1879,15 @@ sys_lseek(td, uap) int whence; } */ *uap; { - struct ucred *cred = td->td_ucred; struct file *fp; - struct vnode *vp; - struct vattr vattr; - off_t foffset, offset, size; - int error, noneg; + int error; AUDIT_ARG_FD(uap->fd); if ((error = fget(td, uap->fd, CAP_SEEK, &fp)) != 0) return (error); - if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) { - fdrop(fp, td); - return (ESPIPE); - } - vp = fp->f_vnode; - foffset = foffset_lock(fp, 0); - noneg = (vp->v_type != VCHR); - offset = uap->offset; - switch (uap->whence) { - case L_INCR: - if (noneg && - (foffset < 0 || - (offset > 0 && foffset > OFF_MAX - offset))) { - error = EOVERFLOW; - break; - } - offset += foffset; - break; - case L_XTND: - vn_lock(vp, LK_SHARED | LK_RETRY); - error = VOP_GETATTR(vp, &vattr, cred); - VOP_UNLOCK(vp, 0); - if (error) - break; - - /* - * If the file references a disk device, then fetch - * the media size and use that to determine the ending - * offset. - */ - if (vattr.va_size == 0 && vp->v_type == VCHR && - fo_ioctl(fp, DIOCGMEDIASIZE, &size, cred, td) == 0) - vattr.va_size = size; - if (noneg && - (vattr.va_size > OFF_MAX || - (offset > 0 && vattr.va_size > OFF_MAX - offset))) { - error = EOVERFLOW; - break; - } - offset += vattr.va_size; - break; - case L_SET: - break; - case SEEK_DATA: - error = fo_ioctl(fp, FIOSEEKDATA, &offset, cred, td); - break; - case SEEK_HOLE: - error = fo_ioctl(fp, FIOSEEKHOLE, &offset, cred, td); - break; - default: - error = EINVAL; - } - if (error == 0 && noneg && offset < 0) - error = EINVAL; - if (error != 0) - goto drop; - VFS_KNOTE_UNLOCKED(vp, 0); - *(off_t *)(td->td_retval) = offset; -drop: + error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ? + fo_seek(fp, uap->offset, uap->whence, td) : ESPIPE; fdrop(fp, td); - foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0); return (error); } Modified: head/sys/kern/vfs_vnops.c ============================================================================== --- head/sys/kern/vfs_vnops.c Wed Aug 21 17:23:24 2013 (r254601) +++ head/sys/kern/vfs_vnops.c Wed Aug 21 17:36:01 2013 (r254602) @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/disk.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/kdb.h> @@ -101,6 +102,7 @@ struct fileops vnops = { .fo_chmod = vn_chmod, .fo_chown = vn_chown, .fo_sendfile = vn_sendfile, + .fo_seek = vn_seek, .fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE }; @@ -2010,3 +2012,72 @@ unlock: *off = noff; return (error); } + +int +vn_seek(struct file *fp, off_t offset, int whence, struct thread *td) +{ + struct ucred *cred; + struct vnode *vp; + struct vattr vattr; + off_t foffset, size; + int error, noneg; + + cred = td->td_ucred; + vp = fp->f_vnode; + foffset = foffset_lock(fp, 0); + noneg = (vp->v_type != VCHR); + error = 0; + switch (whence) { + case L_INCR: + if (noneg && + (foffset < 0 || + (offset > 0 && foffset > OFF_MAX - offset))) { + error = EOVERFLOW; + break; + } + offset += foffset; + break; + case L_XTND: + vn_lock(vp, LK_SHARED | LK_RETRY); + error = VOP_GETATTR(vp, &vattr, cred); + VOP_UNLOCK(vp, 0); + if (error) + break; + + /* + * If the file references a disk device, then fetch + * the media size and use that to determine the ending + * offset. + */ + if (vattr.va_size == 0 && vp->v_type == VCHR && + fo_ioctl(fp, DIOCGMEDIASIZE, &size, cred, td) == 0) + vattr.va_size = size; + if (noneg && + (vattr.va_size > OFF_MAX || + (offset > 0 && vattr.va_size > OFF_MAX - offset))) { + error = EOVERFLOW; + break; + } + offset += vattr.va_size; + break; + case L_SET: + break; + case SEEK_DATA: + error = fo_ioctl(fp, FIOSEEKDATA, &offset, cred, td); + break; + case SEEK_HOLE: + error = fo_ioctl(fp, FIOSEEKHOLE, &offset, cred, td); + break; + default: + error = EINVAL; + } + if (error == 0 && noneg && offset < 0) + error = EINVAL; + if (error != 0) + goto drop; + VFS_KNOTE_UNLOCKED(vp, 0); + *(off_t *)(td->td_retval) = offset; +drop: + foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0); + return (error); +} Modified: head/sys/sys/file.h ============================================================================== --- head/sys/sys/file.h Wed Aug 21 17:23:24 2013 (r254601) +++ head/sys/sys/file.h Wed Aug 21 17:36:01 2013 (r254602) @@ -108,6 +108,8 @@ typedef int fo_chown_t(struct file *fp, typedef int fo_sendfile_t(struct file *fp, int sockfd, struct uio *hdr_uio, struct uio *trl_uio, off_t offset, size_t nbytes, off_t *sent, int flags, int kflags, struct thread *td); +typedef int fo_seek_t(struct file *fp, off_t offset, int whence, + struct thread *td); typedef int fo_flags_t; struct fileops { @@ -122,6 +124,7 @@ struct fileops { fo_chmod_t *fo_chmod; fo_chown_t *fo_chown; fo_sendfile_t *fo_sendfile; + fo_seek_t *fo_seek; fo_flags_t fo_flags; /* DFLAG_* below */ }; @@ -242,6 +245,7 @@ fo_chown_t invfo_chown; fo_sendfile_t invfo_sendfile; fo_sendfile_t vn_sendfile; +fo_seek_t vn_seek; void finit(struct file *, u_int, short, void *, struct fileops *); int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp); @@ -370,6 +374,13 @@ fo_sendfile(struct file *fp, int sockfd, nbytes, sent, flags, kflags, td)); } +static __inline int +fo_seek(struct file *fp, off_t offset, int whence, struct thread *td) +{ + + return ((*fp->f_ops->fo_seek)(fp, offset, whence, td)); +} + #endif /* _KERNEL */ #endif /* !SYS_FILE_H */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308211736.r7LHa2qD078858>