1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)vfs_vnops.c 7.28 (Berkeley) 03/19/91 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "kernel.h" 13 #include "file.h" 14 #include "stat.h" 15 #include "buf.h" 16 #include "proc.h" 17 #include "mount.h" 18 #include "vnode.h" 19 #include "ioctl.h" 20 #include "tty.h" 21 22 int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close(); 23 struct fileops vnops = 24 { vn_read, vn_write, vn_ioctl, vn_select, vn_close }; 25 26 /* 27 * Common code for vnode open operations. 28 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine. 29 */ 30 vn_open(ndp, p, fmode, cmode) 31 register struct nameidata *ndp; 32 struct proc *p; 33 int fmode, cmode; 34 { 35 register struct vnode *vp; 36 register struct ucred *cred = p->p_ucred; 37 struct vattr vat; 38 struct vattr *vap = &vat; 39 int error; 40 41 if (fmode & FCREAT) { 42 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF; 43 if ((fmode & FEXCL) == 0) 44 ndp->ni_nameiop |= FOLLOW; 45 if (error = namei(ndp, p)) 46 return (error); 47 if (ndp->ni_vp == NULL) { 48 VATTR_NULL(vap); 49 vap->va_type = VREG; 50 vap->va_mode = cmode; 51 if (error = VOP_CREATE(ndp, vap)) 52 return (error); 53 fmode &= ~FTRUNC; 54 vp = ndp->ni_vp; 55 } else { 56 if (ndp->ni_dvp == ndp->ni_vp) 57 vrele(ndp->ni_dvp); 58 else 59 vput(ndp->ni_dvp); 60 ndp->ni_dvp = NULL; 61 vp = ndp->ni_vp; 62 if (fmode & FEXCL) { 63 error = EEXIST; 64 goto bad; 65 } 66 fmode &= ~FCREAT; 67 } 68 } else { 69 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 70 if (error = namei(ndp, p)) 71 return (error); 72 vp = ndp->ni_vp; 73 } 74 if (vp->v_type == VSOCK) { 75 error = EOPNOTSUPP; 76 goto bad; 77 } 78 if ((fmode & FCREAT) == 0) { 79 if (fmode & FREAD) { 80 if (error = VOP_ACCESS(vp, VREAD, cred)) 81 goto bad; 82 } 83 if (fmode & (FWRITE|FTRUNC)) { 84 if (vp->v_type == VDIR) { 85 error = EISDIR; 86 goto bad; 87 } 88 if ((error = vn_writechk(vp)) || 89 (error = VOP_ACCESS(vp, VWRITE, cred))) 90 goto bad; 91 } 92 } 93 if (fmode & FTRUNC) { 94 VATTR_NULL(vap); 95 vap->va_size = 0; 96 if (error = VOP_SETATTR(vp, vap, cred)) 97 goto bad; 98 } 99 VOP_UNLOCK(vp); 100 error = VOP_OPEN(vp, fmode, cred); 101 if (error) 102 vrele(vp); 103 return (error); 104 105 bad: 106 vput(vp); 107 return (error); 108 } 109 110 /* 111 * Check for write permissions on the specified vnode. 112 * The read-only status of the file system is checked. 113 * Also, prototype text segments cannot be written. 114 */ 115 vn_writechk(vp) 116 register struct vnode *vp; 117 { 118 119 /* 120 * Disallow write attempts on read-only file systems; 121 * unless the file is a socket or a block or character 122 * device resident on the file system. 123 */ 124 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125 switch (vp->v_type) { 126 case VREG: case VDIR: case VLNK: 127 return (EROFS); 128 } 129 } 130 /* 131 * If there's shared text associated with 132 * the vnode, try to free it up once. If 133 * we fail, we can't allow writing. 134 */ 135 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 136 return (ETXTBSY); 137 return (0); 138 } 139 140 /* 141 * Vnode version of rdwri() for calls on file systems. 142 */ 143 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid) 144 enum uio_rw rw; 145 struct vnode *vp; 146 caddr_t base; 147 int len; 148 off_t offset; 149 enum uio_seg segflg; 150 int ioflg; 151 struct ucred *cred; 152 int *aresid; 153 { 154 struct uio auio; 155 struct iovec aiov; 156 int error; 157 158 if ((ioflg & IO_NODELOCKED) == 0) 159 VOP_LOCK(vp); 160 auio.uio_iov = &aiov; 161 auio.uio_iovcnt = 1; 162 aiov.iov_base = base; 163 aiov.iov_len = len; 164 auio.uio_resid = len; 165 auio.uio_offset = offset; 166 auio.uio_segflg = segflg; 167 auio.uio_rw = rw; 168 if (rw == UIO_READ) 169 error = VOP_READ(vp, &auio, ioflg, cred); 170 else 171 error = VOP_WRITE(vp, &auio, ioflg, cred); 172 if (aresid) 173 *aresid = auio.uio_resid; 174 else 175 if (auio.uio_resid && error == 0) 176 error = EIO; 177 if ((ioflg & IO_NODELOCKED) == 0) 178 VOP_UNLOCK(vp); 179 return (error); 180 } 181 182 vn_read(fp, uio, cred) 183 struct file *fp; 184 struct uio *uio; 185 struct ucred *cred; 186 { 187 register struct vnode *vp = (struct vnode *)fp->f_data; 188 int count, error; 189 190 VOP_LOCK(vp); 191 uio->uio_offset = fp->f_offset; 192 count = uio->uio_resid; 193 error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred); 194 fp->f_offset += count - uio->uio_resid; 195 VOP_UNLOCK(vp); 196 return (error); 197 } 198 199 vn_write(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, ioflag = 0; 206 207 if (vp->v_type == VREG && (fp->f_flag & FAPPEND)) 208 ioflag |= IO_APPEND; 209 if (fp->f_flag & FNDELAY) 210 ioflag |= IO_NDELAY; 211 VOP_LOCK(vp); 212 uio->uio_offset = fp->f_offset; 213 count = uio->uio_resid; 214 error = VOP_WRITE(vp, uio, ioflag, cred); 215 if (ioflag & IO_APPEND) 216 fp->f_offset = uio->uio_offset; 217 else 218 fp->f_offset += count - uio->uio_resid; 219 VOP_UNLOCK(vp); 220 return (error); 221 } 222 223 /* 224 * Get stat info for a vnode. 225 */ 226 vn_stat(vp, sb) 227 struct vnode *vp; 228 register struct stat *sb; 229 { 230 struct vattr vattr; 231 struct proc *p = curproc; /* XXX */ 232 register struct vattr *vap; 233 int error; 234 u_short mode; 235 236 vap = &vattr; 237 error = VOP_GETATTR(vp, vap, p->p_ucred); 238 if (error) 239 return (error); 240 /* 241 * Copy from vattr table 242 */ 243 sb->st_dev = vap->va_fsid; 244 sb->st_ino = vap->va_fileid; 245 mode = vap->va_mode; 246 switch (vp->v_type) { 247 case VREG: 248 mode |= S_IFREG; 249 break; 250 case VDIR: 251 mode |= S_IFDIR; 252 break; 253 case VBLK: 254 mode |= S_IFBLK; 255 break; 256 case VCHR: 257 mode |= S_IFCHR; 258 break; 259 case VLNK: 260 mode |= S_IFLNK; 261 break; 262 case VSOCK: 263 mode |= S_IFSOCK; 264 break; 265 case VFIFO: 266 mode |= S_IFIFO; 267 break; 268 default: 269 return (EBADF); 270 }; 271 sb->st_mode = mode; 272 sb->st_nlink = vap->va_nlink; 273 sb->st_uid = vap->va_uid; 274 sb->st_gid = vap->va_gid; 275 sb->st_rdev = vap->va_rdev; 276 sb->st_size = vap->va_size; 277 sb->st_atime = vap->va_atime.tv_sec; 278 sb->st_spare1 = 0; 279 sb->st_mtime = vap->va_mtime.tv_sec; 280 sb->st_spare2 = 0; 281 sb->st_ctime = vap->va_ctime.tv_sec; 282 sb->st_spare3 = 0; 283 sb->st_blksize = vap->va_blocksize; 284 sb->st_flags = vap->va_flags; 285 sb->st_gen = vap->va_gen; 286 sb->st_blocks = vap->va_bytes / S_BLKSIZE; 287 return (0); 288 } 289 290 /* 291 * Vnode ioctl call 292 */ 293 vn_ioctl(fp, com, data) 294 struct file *fp; 295 int com; 296 caddr_t data; 297 { 298 register struct vnode *vp = ((struct vnode *)fp->f_data); 299 struct proc *p = curproc; /* XXX */ 300 struct vattr vattr; 301 int error; 302 303 switch (vp->v_type) { 304 305 case VREG: 306 case VDIR: 307 if (com == FIONREAD) { 308 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred)) 309 return (error); 310 *(off_t *)data = vattr.va_size - fp->f_offset; 311 return (0); 312 } 313 if (com == FIONBIO || com == FIOASYNC) /* XXX */ 314 return (0); /* XXX */ 315 /* fall into ... */ 316 317 default: 318 return (ENOTTY); 319 320 case VFIFO: 321 case VCHR: 322 case VBLK: 323 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred); 324 if (error == 0 && com == TIOCSCTTY) { 325 p->p_session->s_ttyvp = vp; 326 VREF(vp); 327 } 328 return (error); 329 } 330 } 331 332 /* 333 * Vnode select call 334 */ 335 vn_select(fp, which) 336 struct file *fp; 337 int which; 338 { 339 struct proc *p = curproc; /* XXX */ 340 341 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag, 342 p->p_ucred)); 343 } 344 345 /* 346 * Vnode close call 347 */ 348 vn_close(fp) 349 register struct file *fp; 350 { 351 struct vnode *vp = ((struct vnode *)fp->f_data); 352 int error; 353 354 /* 355 * Must delete vnode reference from this file entry 356 * before VOP_CLOSE, so that only other references 357 * will prevent close. 358 */ 359 fp->f_data = (caddr_t) 0; 360 error = VOP_CLOSE(vp, fp->f_flag, fp->f_cred); 361 vrele(vp); 362 return (error); 363 } 364 365 /* 366 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked) 367 * - look up fsid in mount list (if not found ret error) 368 * - get vp by calling VFS_FHTOVP() macro 369 * - if lockflag lock it with VOP_LOCK() 370 */ 371 vn_fhtovp(fhp, lockflag, vpp) 372 fhandle_t *fhp; 373 int lockflag; 374 struct vnode **vpp; 375 { 376 register struct mount *mp; 377 378 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 379 return (ESTALE); 380 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 381 return (ESTALE); 382 if (!lockflag) 383 VOP_UNLOCK(*vpp); 384 return (0); 385 } 386