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