vfs_vnops.c revision 1.30
1/* $NetBSD: vfs_vnops.c,v 1.30 1998/07/28 18:37:48 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1982, 1986, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95 41 */ 42 43#include "fs_union.h" 44#include "opt_uvm.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/file.h> 50#include <sys/stat.h> 51#include <sys/buf.h> 52#include <sys/proc.h> 53#include <sys/mount.h> 54#include <sys/namei.h> 55#include <sys/vnode.h> 56#include <sys/ioctl.h> 57#include <sys/tty.h> 58#include <sys/poll.h> 59 60#include <vm/vm.h> 61 62#if defined(UVM) 63#include <uvm/uvm_extern.h> 64#endif 65 66#ifdef UNION 67#include <miscfs/union/union.h> 68#endif 69 70struct fileops vnops = 71 { vn_read, vn_write, vn_ioctl, vn_poll, vn_closefile }; 72 73/* 74 * Common code for vnode open operations. 75 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 76 */ 77int 78vn_open(ndp, fmode, cmode) 79 register struct nameidata *ndp; 80 int fmode, cmode; 81{ 82 register struct vnode *vp; 83 register struct proc *p = ndp->ni_cnd.cn_proc; 84 register struct ucred *cred = p->p_ucred; 85 struct vattr va; 86 int error; 87 88 if (fmode & O_CREAT) { 89 ndp->ni_cnd.cn_nameiop = CREATE; 90 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 91 if ((fmode & O_EXCL) == 0) 92 ndp->ni_cnd.cn_flags |= FOLLOW; 93 if ((error = namei(ndp)) != 0) 94 return (error); 95 if (ndp->ni_vp == NULL) { 96 VATTR_NULL(&va); 97 va.va_type = VREG; 98 va.va_mode = cmode; 99 if (fmode & O_EXCL) 100 va.va_vaflags |= VA_EXCLUSIVE; 101 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE); 102 error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, 103 &ndp->ni_cnd, &va); 104 if (error) 105 return (error); 106 fmode &= ~O_TRUNC; 107 vp = ndp->ni_vp; 108 } else { 109 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 110 if (ndp->ni_dvp == ndp->ni_vp) 111 vrele(ndp->ni_dvp); 112 else 113 vput(ndp->ni_dvp); 114 ndp->ni_dvp = NULL; 115 vp = ndp->ni_vp; 116 if (fmode & O_EXCL) { 117 error = EEXIST; 118 goto bad; 119 } 120 fmode &= ~O_CREAT; 121 } 122 } else { 123 ndp->ni_cnd.cn_nameiop = LOOKUP; 124 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF; 125 if ((error = namei(ndp)) != 0) 126 return (error); 127 vp = ndp->ni_vp; 128 } 129 if (vp->v_type == VSOCK) { 130 error = EOPNOTSUPP; 131 goto bad; 132 } 133 if ((fmode & O_CREAT) == 0) { 134 if (fmode & FREAD) { 135 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0) 136 goto bad; 137 } 138 if (fmode & (FWRITE | O_TRUNC)) { 139 if (vp->v_type == VDIR) { 140 error = EISDIR; 141 goto bad; 142 } 143 if ((error = vn_writechk(vp)) != 0 || 144 (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0) 145 goto bad; 146 } 147 } 148 if (fmode & O_TRUNC) { 149 VOP_UNLOCK(vp, 0); /* XXX */ 150 VOP_LEASE(vp, p, cred, LEASE_WRITE); 151 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX */ 152 VATTR_NULL(&va); 153 va.va_size = 0; 154 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0) 155 goto bad; 156 } 157 if ((error = VOP_OPEN(vp, fmode, cred, p)) != 0) 158 goto bad; 159 if (fmode & FWRITE) 160 vp->v_writecount++; 161 return (0); 162bad: 163 vput(vp); 164 return (error); 165} 166 167/* 168 * Check for write permissions on the specified vnode. 169 * Prototype text segments cannot be written. 170 */ 171int 172vn_writechk(vp) 173 register struct vnode *vp; 174{ 175 176 /* 177 * If there's shared text associated with 178 * the vnode, try to free it up once. If 179 * we fail, we can't allow writing. 180 */ 181#if defined(UVM) 182 if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp)) 183 return (ETXTBSY); 184#else 185 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 186 return (ETXTBSY); 187#endif 188 return (0); 189} 190 191/* 192 * Vnode close call 193 */ 194int 195vn_close(vp, flags, cred, p) 196 register struct vnode *vp; 197 int flags; 198 struct ucred *cred; 199 struct proc *p; 200{ 201 int error; 202 203 if (flags & FWRITE) 204 vp->v_writecount--; 205 error = VOP_CLOSE(vp, flags, cred, p); 206 vrele(vp); 207 return (error); 208} 209 210/* 211 * Package up an I/O request on a vnode into a uio and do it. 212 */ 213int 214vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p) 215 enum uio_rw rw; 216 struct vnode *vp; 217 caddr_t base; 218 int len; 219 off_t offset; 220 enum uio_seg segflg; 221 int ioflg; 222 struct ucred *cred; 223 size_t *aresid; 224 struct proc *p; 225{ 226 struct uio auio; 227 struct iovec aiov; 228 int error; 229 230 if ((ioflg & IO_NODELOCKED) == 0) 231 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 232 auio.uio_iov = &aiov; 233 auio.uio_iovcnt = 1; 234 aiov.iov_base = base; 235 aiov.iov_len = len; 236 auio.uio_resid = len; 237 auio.uio_offset = offset; 238 auio.uio_segflg = segflg; 239 auio.uio_rw = rw; 240 auio.uio_procp = p; 241 if (rw == UIO_READ) { 242 error = VOP_READ(vp, &auio, ioflg, cred); 243 } else { 244 error = VOP_WRITE(vp, &auio, ioflg, cred); 245 } 246 if (aresid) 247 *aresid = auio.uio_resid; 248 else 249 if (auio.uio_resid && error == 0) 250 error = EIO; 251 if ((ioflg & IO_NODELOCKED) == 0) 252 VOP_UNLOCK(vp, 0); 253 return (error); 254} 255 256int 257vn_readdir(fp, buf, segflg, count, done, p, cookies, ncookies) 258 struct file *fp; 259 char *buf; 260 int segflg, *done, *ncookies; 261 u_int count; 262 struct proc *p; 263 off_t **cookies; 264{ 265 struct vnode *vp = (struct vnode *)fp->f_data; 266 struct iovec aiov; 267 struct uio auio; 268 int error, eofflag; 269 270unionread: 271 if (vp->v_type != VDIR) 272 return (EINVAL); 273 aiov.iov_base = buf; 274 aiov.iov_len = count; 275 auio.uio_iov = &aiov; 276 auio.uio_iovcnt = 1; 277 auio.uio_rw = UIO_READ; 278 auio.uio_segflg = segflg; 279 auio.uio_procp = p; 280 auio.uio_resid = count; 281 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 282 auio.uio_offset = fp->f_offset; 283 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, cookies, 284 ncookies); 285 fp->f_offset = auio.uio_offset; 286 VOP_UNLOCK(vp, 0); 287 if (error) 288 return (error); 289 290#ifdef UNION 291{ 292 extern int (**union_vnodeop_p) __P((void *)); 293 extern struct vnode *union_dircache __P((struct vnode *)); 294 295 if (count == auio.uio_resid && (vp->v_op == union_vnodeop_p)) { 296 struct vnode *lvp; 297 298 lvp = union_dircache(vp); 299 if (lvp != NULLVP) { 300 struct vattr va; 301 302 /* 303 * If the directory is opaque, 304 * then don't show lower entries 305 */ 306 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 307 if (va.va_flags & OPAQUE) { 308 vput(lvp); 309 lvp = NULL; 310 } 311 } 312 313 if (lvp != NULLVP) { 314 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 315 if (error) { 316 vput(lvp); 317 return (error); 318 } 319 VOP_UNLOCK(lvp, 0); 320 fp->f_data = (caddr_t) lvp; 321 fp->f_offset = 0; 322 error = vn_close(vp, FREAD, fp->f_cred, p); 323 if (error) 324 return (error); 325 vp = lvp; 326 goto unionread; 327 } 328 } 329} 330#endif /* UNION */ 331 332 if (count == auio.uio_resid && (vp->v_flag & VROOT) && 333 (vp->v_mount->mnt_flag & MNT_UNION)) { 334 struct vnode *tvp = vp; 335 vp = vp->v_mount->mnt_vnodecovered; 336 VREF(vp); 337 fp->f_data = (caddr_t) vp; 338 fp->f_offset = 0; 339 vrele(tvp); 340 goto unionread; 341 } 342 *done = count - auio.uio_resid; 343 return error; 344} 345 346/* 347 * File table vnode read routine. 348 */ 349int 350vn_read(fp, offset, uio, cred, flags) 351 struct file *fp; 352 off_t *offset; 353 struct uio *uio; 354 struct ucred *cred; 355 int flags; 356{ 357 struct vnode *vp = (struct vnode *)fp->f_data; 358 int count, error; 359 360 VOP_LEASE(vp, uio->uio_procp, cred, LEASE_READ); 361 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 362 uio->uio_offset = *offset; 363 count = uio->uio_resid; 364 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, 365 cred); 366 if (flags & FOF_UPDATE_OFFSET) 367 *offset += count - uio->uio_resid; 368 VOP_UNLOCK(vp, 0); 369 return (error); 370} 371 372/* 373 * File table vnode write routine. 374 */ 375int 376vn_write(fp, offset, uio, cred, flags) 377 struct file *fp; 378 off_t *offset; 379 struct uio *uio; 380 struct ucred *cred; 381 int flags; 382{ 383 struct vnode *vp = (struct vnode *)fp->f_data; 384 int count, error, ioflag = IO_UNIT; 385 386 if (vp->v_type == VREG && (fp->f_flag & O_APPEND)) 387 ioflag |= IO_APPEND; 388 if (fp->f_flag & FNONBLOCK) 389 ioflag |= IO_NDELAY; 390 if (fp->f_flag & FFSYNC || 391 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) 392 ioflag |= IO_SYNC; 393 VOP_LEASE(vp, uio->uio_procp, cred, LEASE_WRITE); 394 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 395 uio->uio_offset = *offset; 396 count = uio->uio_resid; 397 error = VOP_WRITE(vp, uio, ioflag, cred); 398 if (flags & FOF_UPDATE_OFFSET) { 399 if (ioflag & IO_APPEND) 400 *offset = uio->uio_offset; 401 else 402 *offset += count - uio->uio_resid; 403 } 404 VOP_UNLOCK(vp, 0); 405 return (error); 406} 407 408/* 409 * File table vnode stat routine. 410 */ 411int 412vn_stat(vp, sb, p) 413 struct vnode *vp; 414 register struct stat *sb; 415 struct proc *p; 416{ 417 struct vattr va; 418 int error; 419 u_short mode; 420 421 error = VOP_GETATTR(vp, &va, p->p_ucred, p); 422 if (error) 423 return (error); 424 /* 425 * Copy from vattr table 426 */ 427 sb->st_dev = va.va_fsid; 428 sb->st_ino = va.va_fileid; 429 mode = va.va_mode; 430 switch (vp->v_type) { 431 case VREG: 432 mode |= S_IFREG; 433 break; 434 case VDIR: 435 mode |= S_IFDIR; 436 break; 437 case VBLK: 438 mode |= S_IFBLK; 439 break; 440 case VCHR: 441 mode |= S_IFCHR; 442 break; 443 case VLNK: 444 mode |= S_IFLNK; 445 break; 446 case VSOCK: 447 mode |= S_IFSOCK; 448 break; 449 case VFIFO: 450 mode |= S_IFIFO; 451 break; 452 default: 453 return (EBADF); 454 }; 455 sb->st_mode = mode; 456 sb->st_nlink = va.va_nlink; 457 sb->st_uid = va.va_uid; 458 sb->st_gid = va.va_gid; 459 sb->st_rdev = va.va_rdev; 460 sb->st_size = va.va_size; 461 sb->st_atimespec = va.va_atime; 462 sb->st_mtimespec = va.va_mtime; 463 sb->st_ctimespec = va.va_ctime; 464 sb->st_blksize = va.va_blocksize; 465 sb->st_flags = va.va_flags; 466 sb->st_gen = 0; 467 sb->st_blocks = va.va_bytes / S_BLKSIZE; 468 return (0); 469} 470 471/* 472 * File table vnode ioctl routine. 473 */ 474int 475vn_ioctl(fp, com, data, p) 476 struct file *fp; 477 u_long com; 478 caddr_t data; 479 struct proc *p; 480{ 481 register struct vnode *vp = ((struct vnode *)fp->f_data); 482 struct vattr vattr; 483 int error; 484 485 switch (vp->v_type) { 486 487 case VREG: 488 case VDIR: 489 if (com == FIONREAD) { 490 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 491 if (error) 492 return (error); 493 *(int *)data = vattr.va_size - fp->f_offset; 494 return (0); 495 } 496 if (com == FIONBIO || com == FIOASYNC) /* XXX */ 497 return (0); /* XXX */ 498 /* fall into ... */ 499 500 default: 501 return (ENOTTY); 502 503 case VFIFO: 504 case VCHR: 505 case VBLK: 506 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p); 507 if (error == 0 && com == TIOCSCTTY) { 508 if (p->p_session->s_ttyvp) 509 vrele(p->p_session->s_ttyvp); 510 p->p_session->s_ttyvp = vp; 511 VREF(vp); 512 } 513 return (error); 514 } 515} 516 517/* 518 * File table vnode poll routine. 519 */ 520int 521vn_poll(fp, events, p) 522 struct file *fp; 523 int events; 524 struct proc *p; 525{ 526 527 return (VOP_POLL(((struct vnode *)fp->f_data), events, p)); 528} 529 530/* 531 * Check that the vnode is still valid, and if so 532 * acquire requested lock. 533 */ 534int 535vn_lock(vp, flags) 536 struct vnode *vp; 537 int flags; 538{ 539 int error; 540 541 do { 542 if ((flags & LK_INTERLOCK) == 0) 543 simple_lock(&vp->v_interlock); 544 if (vp->v_flag & VXLOCK) { 545 vp->v_flag |= VXWANT; 546 simple_unlock(&vp->v_interlock); 547 tsleep((caddr_t)vp, PINOD, "vn_lock", 0); 548 error = ENOENT; 549 } else { 550 error = VOP_LOCK(vp, flags | LK_INTERLOCK); 551 if (error == 0) 552 return (error); 553 } 554 flags &= ~LK_INTERLOCK; 555 } while (flags & LK_RETRY); 556 return (error); 557} 558 559/* 560 * File table vnode close routine. 561 */ 562int 563vn_closefile(fp, p) 564 struct file *fp; 565 struct proc *p; 566{ 567 568 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag, 569 fp->f_cred, p)); 570} 571