1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)vfs_vnops.c 7.17 (Berkeley) 03/26/90 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "user.h" 23 #include "kernel.h" 24 #include "file.h" 25 #include "stat.h" 26 #include "buf.h" 27 #include "proc.h" 28 #include "uio.h" 29 #include "socket.h" 30 #include "socketvar.h" 31 #include "mount.h" 32 #include "vnode.h" 33 #include "ioctl.h" 34 #include "tty.h" 35 #include "tsleep.h" 36 37 int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close(); 38 struct fileops vnops = 39 { vn_read, vn_write, vn_ioctl, vn_select, vn_close }; 40 41 /* 42 * Common code for vnode open operations. 43 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 44 */ 45 vn_open(ndp, fmode, cmode) 46 register struct nameidata *ndp; 47 int fmode, cmode; 48 { 49 register struct vnode *vp; 50 struct vattr vat; 51 struct vattr *vap = &vat; 52 int error; 53 54 if (fmode & FCREAT) { 55 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 56 if ((fmode & FEXCL) == 0) 57 ndp->ni_nameiop |= FOLLOW; 58 if (error = namei(ndp)) 59 return (error); 60 if (ndp->ni_vp == NULL) { 61 vattr_null(vap); 62 vap->va_type = VREG; 63 vap->va_mode = cmode; 64 if (error = VOP_CREATE(ndp, vap)) 65 return (error); 66 fmode &= ~FTRUNC; 67 vp = ndp->ni_vp; 68 } else { 69 if (ndp->ni_dvp == ndp->ni_vp) 70 vrele(ndp->ni_dvp); 71 else if (ndp->ni_dvp != NULL) 72 vput(ndp->ni_dvp); 73 ndp->ni_dvp = NULL; 74 vp = ndp->ni_vp; 75 if (fmode & FEXCL) { 76 error = EEXIST; 77 goto bad; 78 } 79 fmode &= ~FCREAT; 80 } 81 } else { 82 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 83 if (error = namei(ndp)) 84 return (error); 85 vp = ndp->ni_vp; 86 } 87 if (vp->v_type == VSOCK) { 88 error = EOPNOTSUPP; 89 goto bad; 90 } 91 if ((fmode & FCREAT) == 0) { 92 if (fmode & FREAD) { 93 if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred)) 94 goto bad; 95 } 96 if (fmode & (FWRITE|FTRUNC)) { 97 if (vp->v_type == VDIR) { 98 error = EISDIR; 99 goto bad; 100 } 101 if ((error = vn_writechk(vp)) || 102 (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 103 goto bad; 104 } 105 } 106 if (fmode & FTRUNC) { 107 vattr_null(vap); 108 vap->va_size = 0; 109 if (error = VOP_SETATTR(vp, vap, ndp->ni_cred)) 110 goto bad; 111 } 112 VOP_UNLOCK(vp); 113 if (setjmp(&u.u_qsave)) { 114 if (error == 0) 115 error = EINTR; 116 return (error); 117 } 118 error = VOP_OPEN(vp, fmode, ndp->ni_cred); 119 if (error) 120 vrele(vp); 121 return (error); 122 123 bad: 124 vput(vp); 125 return(error); 126 } 127 128 /* 129 * Check for write permissions on the specified vnode. 130 * The read-only status of the file system is checked. 131 * Also, prototype text segments cannot be written. 132 */ 133 vn_writechk(vp) 134 register struct vnode *vp; 135 { 136 137 /* 138 * Disallow write attempts on read-only file systems; 139 * unless the file is a socket or a block or character 140 * device resident on the file system. 141 */ 142 if ((vp->v_mount->m_flag & M_RDONLY) && vp->v_type != VCHR && 143 vp->v_type != VBLK && vp->v_type != VSOCK) 144 return (EROFS); 145 /* 146 * If there's shared text associated with 147 * the vnode, try to free it up once. If 148 * we fail, we can't allow writing. 149 */ 150 if (vp->v_flag & VTEXT) 151 xrele(vp); 152 if (vp->v_flag & VTEXT) 153 return (ETXTBSY); 154 return (0); 155 } 156 157 /* 158 * Vnode version of rdwri() for calls on file systems. 159 */ 160 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid) 161 enum uio_rw rw; 162 struct vnode *vp; 163 caddr_t base; 164 int len; 165 off_t offset; 166 enum uio_seg segflg; 167 int ioflg; 168 struct ucred *cred; 169 int *aresid; 170 { 171 struct uio auio; 172 struct iovec aiov; 173 int error; 174 175 if ((ioflg & IO_NODELOCKED) == 0) 176 VOP_LOCK(vp); 177 auio.uio_iov = &aiov; 178 auio.uio_iovcnt = 1; 179 aiov.iov_base = base; 180 aiov.iov_len = len; 181 auio.uio_resid = len; 182 auio.uio_offset = offset; 183 auio.uio_segflg = segflg; 184 auio.uio_rw = rw; 185 if (rw == UIO_READ) 186 error = VOP_READ(vp, &auio, ioflg, cred); 187 else 188 error = VOP_WRITE(vp, &auio, ioflg, cred); 189 if (aresid) 190 *aresid = auio.uio_resid; 191 else 192 if (auio.uio_resid && error == 0) 193 error = EIO; 194 if ((ioflg & IO_NODELOCKED) == 0) 195 VOP_UNLOCK(vp); 196 return (error); 197 } 198 199 vn_read(fp, uio, cred) 200 struct file *fp; 201 struct uio *uio; 202 struct ucred *cred; 203 { 204 register struct vnode *vp = (struct vnode *)fp->f_data; 205 int count, error; 206 207 VOP_LOCK(vp); 208 uio->uio_offset = fp->f_offset; 209 count = uio->uio_resid; 210 error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred); 211 fp->f_offset += count - uio->uio_resid; 212 VOP_UNLOCK(vp); 213 return (error); 214 } 215 216 vn_write(fp, uio, cred) 217 struct file *fp; 218 struct uio *uio; 219 struct ucred *cred; 220 { 221 register struct vnode *vp = (struct vnode *)fp->f_data; 222 int count, error, ioflag = 0; 223 224 if (vp->v_type == VREG && (fp->f_flag & FAPPEND)) 225 ioflag |= IO_APPEND; 226 if (fp->f_flag & FNDELAY) 227 ioflag |= IO_NDELAY; 228 VOP_LOCK(vp); 229 uio->uio_offset = fp->f_offset; 230 count = uio->uio_resid; 231 error = VOP_WRITE(vp, uio, ioflag, cred); 232 if (ioflag & IO_APPEND) 233 fp->f_offset = uio->uio_offset; 234 else 235 fp->f_offset += count - uio->uio_resid; 236 VOP_UNLOCK(vp); 237 return (error); 238 } 239 240 /* 241 * Get stat info for a vnode. 242 */ 243 vn_stat(vp, sb) 244 struct vnode *vp; 245 register struct stat *sb; 246 { 247 struct vattr vattr; 248 register struct vattr *vap; 249 int error; 250 u_short mode; 251 252 vap = &vattr; 253 error = VOP_GETATTR(vp, vap, u.u_cred); 254 if (error) 255 return (error); 256 /* 257 * Copy from vattr table 258 */ 259 sb->st_dev = vap->va_fsid; 260 sb->st_ino = vap->va_fileid; 261 mode = vap->va_mode; 262 switch (vp->v_type) { 263 case VREG: 264 mode |= S_IFREG; 265 break; 266 case VDIR: 267 mode |= S_IFDIR; 268 break; 269 case VBLK: 270 mode |= S_IFBLK; 271 break; 272 case VCHR: 273 mode |= S_IFCHR; 274 break; 275 case VLNK: 276 mode |= S_IFLNK; 277 break; 278 case VSOCK: 279 mode |= S_IFSOCK; 280 break; 281 case VFIFO: 282 mode |= S_IFIFO; 283 break; 284 default: 285 return (EBADF); 286 }; 287 sb->st_mode = mode; 288 sb->st_nlink = vap->va_nlink; 289 sb->st_uid = vap->va_uid; 290 sb->st_gid = vap->va_gid; 291 sb->st_rdev = vap->va_rdev; 292 sb->st_size = vap->va_size; 293 sb->st_atime = vap->va_atime.tv_sec; 294 sb->st_spare1 = 0; 295 sb->st_mtime = vap->va_mtime.tv_sec; 296 sb->st_spare2 = 0; 297 sb->st_ctime = vap->va_ctime.tv_sec; 298 sb->st_spare3 = 0; 299 sb->st_blksize = vap->va_blocksize; 300 sb->st_flags = vap->va_flags; 301 sb->st_gen = vap->va_gen; 302 sb->st_blocks = vap->va_bytes / S_BLKSIZE; 303 return (0); 304 } 305 306 /* 307 * Vnode ioctl call 308 */ 309 vn_ioctl(fp, com, data) 310 struct file *fp; 311 int com; 312 caddr_t data; 313 { 314 register struct vnode *vp = ((struct vnode *)fp->f_data); 315 struct vattr vattr; 316 int error; 317 318 switch (vp->v_type) { 319 320 case VREG: 321 case VDIR: 322 if (com == FIONREAD) { 323 if (error = VOP_GETATTR(vp, &vattr, u.u_cred)) 324 return (error); 325 *(off_t *)data = vattr.va_size - fp->f_offset; 326 return (0); 327 } 328 if (com == FIONBIO || com == FIOASYNC) /* XXX */ 329 return (0); /* XXX */ 330 /* fall into ... */ 331 332 default: 333 return (ENOTTY); 334 335 case VFIFO: 336 case VCHR: 337 case VBLK: 338 u.u_r.r_val1 = 0; 339 if (setjmp(&u.u_qsave)) { 340 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) 341 return(EINTR); 342 u.u_eosys = RESTARTSYS; 343 return (0); 344 } 345 error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred); 346 if (error == 0 && com == TIOCSCTTY) { 347 u.u_procp->p_session->s_ttyvp = vp; 348 VREF(vp); 349 } 350 return (error); 351 } 352 } 353 354 /* 355 * Vnode select call 356 */ 357 vn_select(fp, which) 358 struct file *fp; 359 int which; 360 { 361 return(VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 362 u.u_cred)); 363 } 364 365 /* 366 * Vnode close call 367 */ 368 vn_close(fp) 369 register struct file *fp; 370 { 371 struct vnode *vp = ((struct vnode *)fp->f_data); 372 int error; 373 374 if (fp->f_flag & (FSHLOCK|FEXLOCK)) 375 vn_unlock(fp, FSHLOCK|FEXLOCK); 376 /* 377 * Must delete vnode reference from this file entry 378 * before VOP_CLOSE, so that only other references 379 * will prevent close. 380 */ 381 fp->f_data = (caddr_t) 0; 382 error = VOP_CLOSE(vp, fp->f_flag, u.u_cred); 383 vrele(vp); 384 return (error); 385 } 386 387 /* 388 * Place an advisory lock on a vnode. 389 * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries 390 */ 391 vn_lock(fp, cmd) 392 register struct file *fp; 393 int cmd; 394 { 395 register int priority = PLOCK; 396 register struct vnode *vp = (struct vnode *)fp->f_data; 397 398 if ((cmd & LOCK_EX) == 0) 399 priority += 4; 400 if (setjmp(&u.u_qsave)) { 401 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0) 402 return(EINTR); 403 u.u_eosys = RESTARTSYS; 404 return (0); 405 } 406 /* 407 * If there's a exclusive lock currently applied 408 * to the file, then we've gotta wait for the 409 * lock with everyone else. 410 */ 411 again: 412 while (vp->v_flag & VEXLOCK) { 413 /* 414 * If we're holding an exclusive 415 * lock, then release it. 416 */ 417 if (fp->f_flag & FEXLOCK) { 418 vn_unlock(fp, FEXLOCK); 419 continue; 420 } 421 if (cmd & LOCK_NB) 422 return (EWOULDBLOCK); 423 vp->v_flag |= VLWAIT; 424 tsleep((caddr_t)&vp->v_exlockc, priority, SLP_EXLCK, 0); 425 } 426 if ((cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) { 427 /* 428 * Must wait for any shared locks to finish 429 * before we try to apply a exclusive lock. 430 * 431 * If we're holding a shared 432 * lock, then release it. 433 */ 434 if (fp->f_flag & FSHLOCK) { 435 vn_unlock(fp, FSHLOCK); 436 goto again; 437 } 438 if (cmd & LOCK_NB) 439 return (EWOULDBLOCK); 440 vp->v_flag |= VLWAIT; 441 tsleep((caddr_t)&vp->v_shlockc, PLOCK, SLP_SHLCK, 0); 442 goto again; 443 } 444 if (fp->f_flag & FEXLOCK) 445 panic("vn_lock"); 446 if (cmd & LOCK_EX) { 447 cmd &= ~LOCK_SH; 448 vp->v_exlockc++; 449 vp->v_flag |= VEXLOCK; 450 fp->f_flag |= FEXLOCK; 451 } 452 if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { 453 vp->v_shlockc++; 454 vp->v_flag |= VSHLOCK; 455 fp->f_flag |= FSHLOCK; 456 } 457 return (0); 458 } 459 460 /* 461 * Unlock a file. 462 */ 463 vn_unlock(fp, kind) 464 register struct file *fp; 465 int kind; 466 { 467 register struct vnode *vp = (struct vnode *)fp->f_data; 468 int flags; 469 470 kind &= fp->f_flag; 471 if (vp == NULL || kind == 0) 472 return; 473 flags = vp->v_flag; 474 if (kind & FSHLOCK) { 475 if ((flags & VSHLOCK) == 0) 476 panic("vn_unlock: SHLOCK"); 477 if (--vp->v_shlockc == 0) { 478 vp->v_flag &= ~VSHLOCK; 479 if (flags & VLWAIT) 480 wakeup((caddr_t)&vp->v_shlockc); 481 } 482 fp->f_flag &= ~FSHLOCK; 483 } 484 if (kind & FEXLOCK) { 485 if ((flags & VEXLOCK) == 0) 486 panic("vn_unlock: EXLOCK"); 487 if (--vp->v_exlockc == 0) { 488 vp->v_flag &= ~(VEXLOCK|VLWAIT); 489 if (flags & VLWAIT) 490 wakeup((caddr_t)&vp->v_exlockc); 491 } 492 fp->f_flag &= ~FEXLOCK; 493 } 494 } 495 496 /* 497 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 498 * - look up fsid in mount list (if not found ret error) 499 * - get vp by calling VFS_FHTOVP() macro 500 * - if lockflag lock it with VOP_LOCK() 501 */ 502 vn_fhtovp(fhp, lockflag, vpp) 503 fhandle_t *fhp; 504 int lockflag; 505 struct vnode **vpp; 506 { 507 register struct mount *mp; 508 509 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 510 return (ESTALE); 511 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 512 return (ESTALE); 513 if (!lockflag) 514 VOP_UNLOCK(*vpp); 515 return (0); 516 } 517 518 /* 519 * Noop 520 */ 521 vfs_noop() 522 { 523 524 return (ENXIO); 525 } 526 527 /* 528 * Null op 529 */ 530 vfs_nullop() 531 { 532 533 return (0); 534 } 535