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.22 (Berkeley) 06/21/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 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 error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred); 333 if (error == 0 && com == TIOCSCTTY) { 334 u.u_procp->p_session->s_ttyvp = vp; 335 VREF(vp); 336 } 337 return (error); 338 } 339 } 340 341 /* 342 * Vnode select call 343 */ 344 vn_select(fp, which) 345 struct file *fp; 346 int which; 347 { 348 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 349 u.u_cred)); 350 } 351 352 /* 353 * Vnode close call 354 */ 355 vn_close(fp) 356 register struct file *fp; 357 { 358 struct vnode *vp = ((struct vnode *)fp->f_data); 359 int error; 360 361 if (fp->f_flag & (FSHLOCK|FEXLOCK)) 362 vn_unlock(fp, FSHLOCK|FEXLOCK); 363 /* 364 * Must delete vnode reference from this file entry 365 * before VOP_CLOSE, so that only other references 366 * will prevent close. 367 */ 368 fp->f_data = (caddr_t) 0; 369 error = VOP_CLOSE(vp, fp->f_flag, u.u_cred); 370 vrele(vp); 371 return (error); 372 } 373 374 /* 375 * Place an advisory lock on a vnode. 376 * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries 377 */ 378 vn_lock(fp, cmd) 379 register struct file *fp; 380 int cmd; 381 { 382 register int priority = PLOCK; 383 register struct vnode *vp = (struct vnode *)fp->f_data; 384 int error = 0; 385 static char lockstr[] = "flock"; 386 387 if ((cmd & LOCK_EX) == 0) 388 priority += 4; 389 priority |= PCATCH; 390 391 /* 392 * If there's a exclusive lock currently applied 393 * to the file, then we've gotta wait for the 394 * lock with everyone else. 395 */ 396 again: 397 while (vp->v_flag & VEXLOCK) { 398 /* 399 * If we're holding an exclusive 400 * lock, then release it. 401 */ 402 if (fp->f_flag & FEXLOCK) { 403 vn_unlock(fp, FEXLOCK); 404 continue; 405 } 406 if (cmd & LOCK_NB) 407 return (EWOULDBLOCK); 408 vp->v_flag |= VLWAIT; 409 if (error = tsleep((caddr_t)&vp->v_exlockc, priority, 410 lockstr, 0)) 411 return (error); 412 } 413 if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) { 414 /* 415 * Must wait for any shared locks to finish 416 * before we try to apply a exclusive lock. 417 * 418 * If we're holding a shared 419 * lock, then release it. 420 */ 421 if (fp->f_flag & FSHLOCK) { 422 vn_unlock(fp, FSHLOCK); 423 goto again; 424 } 425 if (cmd & LOCK_NB) 426 return (EWOULDBLOCK); 427 vp->v_flag |= VLWAIT; 428 if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH, 429 lockstr, 0) == 0) 430 return (error); 431 } 432 if (fp->f_flag & FEXLOCK) 433 panic("vn_lock"); 434 if (cmd & LOCK_EX) { 435 cmd &= ~LOCK_SH; 436 vp->v_exlockc++; 437 vp->v_flag |= VEXLOCK; 438 fp->f_flag |= FEXLOCK; 439 } 440 if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) { 441 vp->v_shlockc++; 442 vp->v_flag |= VSHLOCK; 443 fp->f_flag |= FSHLOCK; 444 } 445 return (0); 446 } 447 448 /* 449 * Unlock a file. 450 */ 451 vn_unlock(fp, kind) 452 register struct file *fp; 453 int kind; 454 { 455 register struct vnode *vp = (struct vnode *)fp->f_data; 456 int flags; 457 458 kind &= fp->f_flag; 459 if (vp == NULL || kind == 0) 460 return; 461 flags = vp->v_flag; 462 if (kind & FSHLOCK) { 463 if ((flags & VSHLOCK) == 0) 464 panic("vn_unlock: SHLOCK"); 465 if (--vp->v_shlockc == 0) { 466 vp->v_flag &= ~VSHLOCK; 467 if (flags & VLWAIT) 468 wakeup((caddr_t)&vp->v_shlockc); 469 } 470 fp->f_flag &= ~FSHLOCK; 471 } 472 if (kind & FEXLOCK) { 473 if ((flags & VEXLOCK) == 0) 474 panic("vn_unlock: EXLOCK"); 475 if (--vp->v_exlockc == 0) { 476 vp->v_flag &= ~(VEXLOCK|VLWAIT); 477 if (flags & VLWAIT) 478 wakeup((caddr_t)&vp->v_exlockc); 479 } 480 fp->f_flag &= ~FEXLOCK; 481 } 482 } 483 484 /* 485 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 486 * - look up fsid in mount list (if not found ret error) 487 * - get vp by calling VFS_FHTOVP() macro 488 * - if lockflag lock it with VOP_LOCK() 489 */ 490 vn_fhtovp(fhp, lockflag, vpp) 491 fhandle_t *fhp; 492 int lockflag; 493 struct vnode **vpp; 494 { 495 register struct mount *mp; 496 497 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 498 return (ESTALE); 499 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 500 return (ESTALE); 501 if (!lockflag) 502 VOP_UNLOCK(*vpp); 503 return (0); 504 } 505 506 /* 507 * Noop 508 */ 509 vfs_noop() 510 { 511 512 return (ENXIO); 513 } 514 515 /* 516 * Null op 517 */ 518 vfs_nullop() 519 { 520 521 return (0); 522 } 523