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