vfs_vnops.c revision 1.10
1/* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)vfs_vnops.c 7.33 (Berkeley) 6/27/91 39 * $Id: vfs_vnops.c,v 1.10 1994/05/17 04:22:06 cgd Exp $ 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/file.h> 46#include <sys/stat.h> 47#include <sys/buf.h> 48#include <sys/proc.h> 49#include <sys/mount.h> 50#include <sys/namei.h> 51#include <sys/vnode.h> 52#include <sys/ioctl.h> 53#include <sys/tty.h> 54 55struct fileops vnops = 56 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile }; 57 58/* 59 * Common code for vnode open operations. 60 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 61 */ 62vn_open(ndp, p, fmode, cmode) 63 register struct nameidata *ndp; 64 struct proc *p; 65 int fmode, cmode; 66{ 67 register struct vnode *vp; 68 register struct ucred *cred = p->p_ucred; 69 struct vattr vat; 70 struct vattr *vap = &vat; 71 int error; 72 73 if (fmode & O_CREAT) { 74 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 75 if ((fmode & O_EXCL) == 0) 76 ndp->ni_nameiop |= FOLLOW; 77 if (error = namei(ndp, p)) 78 return (error); 79 if (ndp->ni_vp == NULL) { 80 VATTR_NULL(vap); 81 vap->va_type = VREG; 82 vap->va_mode = cmode; 83 if (error = VOP_CREATE(ndp, vap, p)) 84 return (error); 85 fmode &= ~O_TRUNC; 86 vp = ndp->ni_vp; 87 } else { 88 VOP_ABORTOP(ndp); 89 if (ndp->ni_dvp == ndp->ni_vp) 90 vrele(ndp->ni_dvp); 91 else 92 vput(ndp->ni_dvp); 93 ndp->ni_dvp = NULL; 94 vp = ndp->ni_vp; 95 if (fmode & O_EXCL) { 96 error = EEXIST; 97 goto bad; 98 } 99 fmode &= ~O_CREAT; 100 } 101 } else { 102 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 103 if (error = namei(ndp, p)) 104 return (error); 105 vp = ndp->ni_vp; 106 } 107 if (vp->v_type == VSOCK) { 108 error = EOPNOTSUPP; 109 goto bad; 110 } 111 if ((fmode & O_CREAT) == 0) { 112 if (fmode & FREAD) { 113 if (error = VOP_ACCESS(vp, VREAD, cred, p)) 114 goto bad; 115 } 116 if (fmode & (FWRITE | O_TRUNC)) { 117 if (vp->v_type == VDIR) { 118 error = EISDIR; 119 goto bad; 120 } 121 if ((error = vn_writechk(vp)) || 122 (error = VOP_ACCESS(vp, VWRITE, cred, p))) 123 goto bad; 124 } 125 } 126 if (fmode & O_TRUNC) { 127 VATTR_NULL(vap); 128 vap->va_size = 0; 129 if (error = VOP_SETATTR(vp, vap, cred, p)) 130 goto bad; 131 } 132 if (error = VOP_OPEN(vp, fmode, cred, p)) 133 goto bad; 134 if (fmode & FWRITE) 135 vp->v_writecount++; 136 return (0); 137bad: 138 vput(vp); 139 return (error); 140} 141 142/* 143 * Check for write permissions on the specified vnode. 144 * The read-only status of the file system is checked. 145 * Also, prototype text segments cannot be written. 146 */ 147vn_writechk(vp) 148 register struct vnode *vp; 149{ 150 151 /* 152 * Disallow write attempts on read-only file systems; 153 * unless the file is a socket or a block or character 154 * device resident on the file system. 155 */ 156 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 157 switch (vp->v_type) { 158 case VREG: case VDIR: case VLNK: 159 return (EROFS); 160 } 161 } 162 /* 163 * If there's shared text associated with 164 * the vnode, try to free it up once. If 165 * we fail, we can't allow writing. 166 */ 167 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 168 return (ETXTBSY); 169 return (0); 170} 171 172/* 173 * Vnode close call 174 */ 175vn_close(vp, flags, cred, p) 176 register struct vnode *vp; 177 int flags; 178 struct ucred *cred; 179 struct proc *p; 180{ 181 int error; 182 183 if (flags & FWRITE) 184 vp->v_writecount--; 185 error = VOP_CLOSE(vp, flags, cred, p); 186 vrele(vp); 187 return (error); 188} 189 190/* 191 * Package up an I/O request on a vnode into a uio and do it. 192 * [internal interface to file i/o for kernel only] 193 */ 194vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 195 enum uio_rw rw; 196 struct vnode *vp; 197 caddr_t base; 198 int len; 199 off_t offset; 200 enum uio_seg segflg; 201 int ioflg; 202 struct ucred *cred; 203 int *aresid; 204 struct proc *p; 205{ 206 struct uio auio; 207 struct iovec aiov; 208 int error; 209 210 if ((ioflg & IO_NODELOCKED) == 0) 211 VOP_LOCK(vp); 212 auio.uio_iov = &aiov; 213 auio.uio_iovcnt = 1; 214 aiov.iov_base = base; 215 aiov.iov_len = len; 216 auio.uio_resid = len; 217 auio.uio_offset = offset; 218 auio.uio_segflg = segflg; 219 auio.uio_rw = rw; 220 auio.uio_procp = p; 221 if (rw == UIO_READ) 222 error = VOP_READ(vp, &auio, ioflg, cred); 223 else 224 error = VOP_WRITE(vp, &auio, ioflg, cred); 225 if (aresid) 226 *aresid = auio.uio_resid; 227 else 228 if (auio.uio_resid && error == 0) 229 error = EIO; 230 if ((ioflg & IO_NODELOCKED) == 0) 231 VOP_UNLOCK(vp); 232 return (error); 233} 234 235/* 236 * File table vnode read routine. 237 */ 238vn_read(fp, uio, cred) 239 struct file *fp; 240 struct uio *uio; 241 struct ucred *cred; 242{ 243 register struct vnode *vp = (struct vnode *)fp->f_data; 244 int count, error; 245 246 VOP_LOCK(vp); 247 uio->uio_offset = fp->f_offset; 248 count = uio->uio_resid; 249 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 250 cred); 251 fp->f_offset += count - uio->uio_resid; 252 VOP_UNLOCK(vp); 253 return (error); 254} 255 256/* 257 * File table vnode write routine. 258 */ 259vn_write(fp, uio, cred) 260 struct file *fp; 261 struct uio *uio; 262 struct ucred *cred; 263{ 264 register struct vnode *vp = (struct vnode *)fp->f_data; 265 int count, error, ioflag = 0; 266 267 if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 268 ioflag |= IO_APPEND; 269 if (fp->f_flag & FNONBLOCK) 270 ioflag |= IO_NDELAY; 271 VOP_LOCK(vp); 272 uio->uio_offset = fp->f_offset; 273 count = uio->uio_resid; 274 error = VOP_WRITE(vp, uio, ioflag, cred); 275 if (ioflag & IO_APPEND) 276 fp->f_offset = uio->uio_offset; 277 else 278 fp->f_offset += count - uio->uio_resid; 279 VOP_UNLOCK(vp); 280 return (error); 281} 282 283/* 284 * File table vnode stat routine. 285 */ 286vn_stat(vp, sb, p) 287 struct vnode *vp; 288 register struct stat *sb; 289 struct proc *p; 290{ 291 struct vattr vattr; 292 register struct vattr *vap; 293 int error; 294 u_short mode; 295 296 vap = &vattr; 297 error = VOP_GETATTR(vp, vap, p->p_ucred, p); 298 if (error) 299 return (error); 300 /* 301 * Copy from vattr table 302 */ 303 sb->st_dev = vap->va_fsid; 304 sb->st_ino = vap->va_fileid; 305 mode = vap->va_mode&~S_IFMT; 306 switch (vp->v_type) { 307 case VREG: 308 mode |= S_IFREG; 309 break; 310 case VDIR: 311 mode |= S_IFDIR; 312 break; 313 case VBLK: 314 mode |= S_IFBLK; 315 break; 316 case VCHR: 317 mode |= S_IFCHR; 318 break; 319 case VLNK: 320 mode |= S_IFLNK; 321 break; 322 case VSOCK: 323 mode |= S_IFSOCK; 324 break; 325 case VFIFO: 326 mode |= S_IFIFO; 327 break; 328 default: 329 return (EBADF); 330 }; 331 sb->st_mode = mode; 332 sb->st_nlink = vap->va_nlink; 333 sb->st_uid = vap->va_uid; 334 sb->st_gid = vap->va_gid; 335 sb->st_rdev = vap->va_rdev; 336 sb->st_size = vap->va_size; 337 sb->st_atimespec = vap->va_atime; 338 sb->st_mtimespec = vap->va_mtime; 339 sb->st_ctimespec = vap->va_ctime; 340 sb->st_blksize = vap->va_blocksize; 341 sb->st_flags = vap->va_flags; 342 sb->st_gen = vap->va_gen; 343 sb->st_blocks = vap->va_bytes / S_BLKSIZE; 344 return (0); 345} 346 347/* 348 * File table vnode ioctl routine. 349 */ 350vn_ioctl(fp, com, data, p) 351 struct file *fp; 352 int com; 353 caddr_t data; 354 struct proc *p; 355{ 356 register struct vnode *vp = ((struct vnode *)fp->f_data); 357 struct vattr vattr; 358 int error; 359 360 switch (vp->v_type) { 361 362 case VREG: 363 case VDIR: 364 if (com == FIONREAD) { 365 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 366 return (error); 367 *(int *)data = vattr.va_size - fp->f_offset; 368 return (0); 369 } 370 if (com == FIONBIO || com == FIOASYNC) /* XXX */ 371 return (0); /* XXX */ 372 /* fall into ... */ 373 374 default: 375 return (ENOTTY); 376 377 case VFIFO: 378 case VCHR: 379 case VBLK: 380 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 381 if (error == 0 && com == TIOCSCTTY) { 382 p->p_session->s_ttyvp = vp; 383 VREF(vp); 384 } 385 return (error); 386 } 387} 388 389/* 390 * File table vnode select routine. 391 */ 392vn_select(fp, which, p) 393 struct file *fp; 394 int which; 395 struct proc *p; 396{ 397 398 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 399 fp->f_cred, p)); 400} 401 402/* 403 * File table vnode close routine. 404 */ 405vn_closefile(fp, p) 406 struct file *fp; 407 struct proc *p; 408{ 409 410 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 411 fp->f_cred, p)); 412} 413 414/* 415 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 416 * - look up fsid in mount list (if not found ret error) 417 * - get vp by calling VFS_FHTOVP() macro 418 * - if lockflag lock it with VOP_LOCK() 419 */ 420vn_fhtovp(fhp, lockflag, vpp) 421 fhandle_t *fhp; 422 int lockflag; 423 struct vnode **vpp; 424{ 425 register struct mount *mp; 426 427 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 428 return (ESTALE); 429 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 430 return (ESTALE); 431 if (!lockflag) 432 VOP_UNLOCK(*vpp); 433 return (0); 434} 435