static int vnop_remove_9p(struct vnop_remove_args *ap) { vnode_t dvp, vp; node_9p *dnp, *np; int e; TRACE(); dvp = ap->a_dvp; vp = ap->a_vp; dnp = NTO9P(dvp); np = NTO9P(vp); if (dvp == vp) { panic("parent == node"); return EINVAL; } if (ISSET(ap->a_flags, VNODE_REMOVE_NODELETEBUSY) && vnode_isinuse(vp, 0)) return EBUSY; nlock_9p(dnp, NODE_LCK_EXCLUSIVE); nlock_9p(np, NODE_LCK_EXCLUSIVE); if ((e=remove_9p(np->nmp, np->fid))) goto error; cache_purge(vp); vnode_recycle(vp); error: nunlock_9p(np); nunlock_9p(dnp); return e; }
static int vnop_read_9p(struct vnop_read_args *ap) { node_9p *np; vnode_t vp; uio_t uio; int e; TRACE(); vp = ap->a_vp; uio = ap->a_uio; np = NTO9P(vp); if (vnode_isdir(vp)) return EISDIR; if (uio_offset(uio) < 0) return EINVAL; if (uio_resid(uio) == 0) return 0; nlock_9p(np, NODE_LCK_SHARED); if (vnode_isnocache(vp) || ISSET(ap->a_ioflag, IO_NOCACHE)) { if (ISSET(np->flags, NODE_MMAPPED)) ubc_msync(vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY|UBC_SYNC); else cluster_push(vp, IO_SYNC); ubc_msync(vp, uio_offset(uio), uio_offset(uio)+uio_resid(uio), NULL, UBC_INVALIDATE); e = nread_9p(np, uio); } else e = cluster_read(vp, uio, np->dir.length, ap->a_ioflag); nunlock_9p(np); return e; }
static int vnop_write_9p(struct vnop_write_args *ap) { vnode_t vp; node_9p *np; uio_t uio; user_ssize_t resid; off_t eof, zh, zt, off; int e, flag; TRACE(); vp = ap->a_vp; uio = ap->a_uio; np = NTO9P(vp); if (vnode_isdir(vp)) return EISDIR; off = uio_offset(uio); if (off < 0) return EINVAL; resid = uio_resid(uio); if (resid == 0) return 0; flag = ap->a_ioflag; if (ISSET(flag, IO_APPEND)) { off = np->dir.length; uio_setoffset(uio, off); } nlock_9p(np, NODE_LCK_EXCLUSIVE); if (vnode_isnocache(vp) || ISSET(flag, IO_NOCACHE)) { ubc_msync(vp, uio_offset(uio), uio_offset(uio)+uio_resid(uio), NULL, UBC_PUSHDIRTY|UBC_SYNC); ubc_msync(vp, uio_offset(uio), uio_offset(uio)+uio_resid(uio), NULL, UBC_INVALIDATE); e = nwrite_9p(np, uio); } else { zh = zt = 0; eof = MAX(np->dir.length, resid+off); if (eof > np->dir.length) { if (off > np->dir.length) { zh = np->dir.length; SET(flag, IO_HEADZEROFILL); } zt = (eof + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64; if (zt > eof) { zt = eof; SET(flag, IO_TAILZEROFILL); } } e = cluster_write(vp, uio, np->dir.length, eof, zh, zt, flag); if (e==0 && eof>np->dir.length) { np->dirtimer = 0; np->dir.length = eof; ubc_setsize(vp, eof); } } nunlock_9p(np); return e; }
static int vnop_fsync_9p(struct vnop_fsync_args *ap) { node_9p *np; dir_9p d; int e; TRACE(); if (!vnode_isreg(ap->a_vp)) return 0; np = NTO9P(ap->a_vp); nlock_9p(np, NODE_LCK_EXCLUSIVE); if (ubc_getsize(ap->a_vp)>0 && !vnode_isnocache(ap->a_vp)) { if (ISSET(np->flags, NODE_MMAPPED)) ubc_msync(np->vp, 0, ubc_getsize(np->vp), NULL, UBC_PUSHDIRTY|UBC_SYNC); else cluster_push(np->vp, IO_SYNC); } e = 0; /* only sync write fids */ if (np->openfid[OWRITE].fid!=NOFID || np->openfid[ORDWR].fid!=NOFID) { nulldir(&d); e = wstat_9p(np->nmp, np->fid, &d); } nunlock_9p(np); return e; }
static int vnop_close_9p(struct vnop_close_args *ap) { openfid_9p *op; node_9p *np; int e; TRACE(); e = 0; np = NTO9P(ap->a_vp); nlock_9p(np, NODE_LCK_EXCLUSIVE); op = ofidget(np, ap->a_fflag); if (op->fid == NOFID) { e = EBADF; goto error; } if (OSDecrementAtomic(&op->ref) == 1) { if (ISSET(np->flags, NODE_MMAPPED)) ubc_msync(np->vp, 0, ubc_getsize(np->vp), NULL, UBC_PUSHDIRTY|UBC_SYNC); else cluster_push(np->vp, IO_CLOSE); /* root gets clunk in vfs_unmount_9p() */ if (!ISSET(np->nmp->flags, F_UNMOUNTING)) e = clunk_9p(np->nmp, op->fid); op->fid = NOFID; } error: nunlock_9p(np); return e; }
static int vnop_getattr_9p(struct vnop_getattr_args *ap) { struct vnode_attr *vap; struct timespec ts; node_9p *np; enum vtype type; dev_t rdev; int e, dotu; TRACE(); e = 0; np = NTO9P(ap->a_vp); /* exclusive, because we modify np->dir */ nlock_9p(np, NODE_LCK_EXCLUSIVE); if ((e=ngetdir_9p(np))) goto error; dotu = ISSET(np->nmp->flags, F_DOTU); ts.tv_nsec = 0; vap = ap->a_vap; VATTR_RETURN(vap, va_rdev, np->dir.dev); VATTR_RETURN(vap, va_nlink, 1); VATTR_RETURN(vap, va_data_size, np->dir.length); VATTR_RETURN(vap, va_iosize, np->iounit); if (dotu) { VATTR_RETURN(vap, va_uid, np->dir.uidnum); VATTR_RETURN(vap, va_gid, np->dir.gidnum); } else { VATTR_RETURN(vap, va_uid, np->nmp->uid); VATTR_RETURN(vap, va_gid, np->nmp->gid); } VATTR_RETURN(vap, va_mode, np->dir.mode & 0777); VATTR_RETURN(vap, va_flags, 0); ts.tv_sec = np->dir.atime; VATTR_RETURN(vap, va_access_time, ts); ts.tv_sec = np->dir.mtime; VATTR_RETURN(vap, va_modify_time, ts); VATTR_RETURN(vap, va_fileid, QTOI(np->dir.qid)); VATTR_RETURN(vap, va_linkid, QTOI(np->dir.qid)); VATTR_RETURN(vap, va_fsid, vfs_statfs(np->nmp->mp)->f_fsid.val[0]); VATTR_RETURN(vap, va_filerev, np->dir.qid.vers); VATTR_RETURN(vap, va_gen, 0); VATTR_RETURN(vap, va_encoding, 0x7E); /* utf-8 */ dirvtype_9p(&np->dir, dotu, &type, &rdev); VATTR_RETURN(vap, va_type, type); VATTR_RETURN(vap, va_rdev, rdev); /* if (VATTR_IS_ACTIVE(vap, va_name) && !vnode_isvroot(ap->a_vp)) { strlcpy(vap->va_name, dp->name, MAXPATHLEN); VATTR_SET_SUPPORTED(vap, va_name); } */ error: nunlock_9p(np); return e; }
static int vnop_rename_9p(struct vnop_rename_args *ap) { struct componentname *tcnp; vnode_t fdvp, tdvp, fvp; node_9p *fdnp, *fnp; dir_9p d; char *s; int e; TRACE(); fdvp = ap->a_fdvp; tdvp = ap->a_tdvp; fvp = ap->a_fvp; tcnp = ap->a_tcnp; fdnp = NTO9P(fdvp); fnp = NTO9P(fvp); if (fdvp!=tdvp || NTO9P(fdvp)!=NTO9P(tdvp)) return ENOTSUP; nlock_9p(fdnp, NODE_LCK_EXCLUSIVE); nlock_9p(fnp, NODE_LCK_EXCLUSIVE); nulldir(&d); e = ENOMEM; s = malloc_9p(tcnp->cn_namelen+1); if (s == NULL) goto error; bcopy(tcnp->cn_nameptr, s, tcnp->cn_namelen); s[tcnp->cn_namelen] = 0; d.name = s; e = wstat_9p(fnp->nmp, fnp->fid, &d); free_9p(s); if (e == 0) { cache_purge(fvp); cache_purge(fdvp); } error: nunlock_9p(fnp); nunlock_9p(fdnp); return e; }
static int vnop_mnomap_9p(struct vnop_mnomap_args *ap) { node_9p *np; TRACE(); np = NTO9P(ap->a_vp); nlock_9p(np, NODE_LCK_EXCLUSIVE); CLR(np->flags, NODE_MMAPPED); nunlock_9p(np); return 0; }
static int vnop_pathconf_9p(struct vnop_pathconf_args *ap) { node_9p *np; TRACE(); np = NTO9P(ap->a_vp); switch (ap->a_name) { case _PC_LINK_MAX: *ap->a_retval = 1; return 0; case _PC_NAME_MAX: *ap->a_retval = NAME_MAX; return 0; case _PC_PATH_MAX: *ap->a_retval = PATH_MAX; return 0; case _PC_PIPE_BUF: nlock_9p(np, NODE_LCK_SHARED); *ap->a_retval = np->iounit; nunlock_9p(np); return 0; case _PC_CHOWN_RESTRICTED: case _PC_NO_TRUNC: *ap->a_retval = 0; return 0; case _PC_NAME_CHARS_MAX: *ap->a_retval = NAME_MAX; return 0; case _PC_CASE_SENSITIVE: case _PC_CASE_PRESERVING: *ap->a_retval = 1; return 0; default: *ap->a_retval = -1; return EINVAL; } }
static int vfs_vget_9p(struct mount *mp, ino64_t ino, vnode_t *vpp, vfs_context_t ctx) { vnode_t vp; qid_9p qid; int e; TRACE(); qid.path = ITOP(ino); qid.type = ITOT(ino); *vpp = NULL; if ((e=nget_9p(MTO9P(mp), NOFID, qid, NULL, &vp, NULL, ctx))) return e; nunlock_9p(NTO9P(vp)); if ((e=vnode_get(vp))) return e; *vpp = vp; return 0; }
static int vnop_reclaim_9p(struct vnop_reclaim_args *ap) { vnode_t vp; node_9p *np; TRACE(); vp = ap->a_vp; np = NTO9P(vp); nlock_9p(np, NODE_LCK_EXCLUSIVE); { SET(np->flags, NODE_RECL); ndel_9p(np); /* balance the ref added in nget_9p() */ vnode_removefsref(vp); vnode_clearfsnode(vp); cache_purge(vp); } nunlock_9p(np); /* root gets clunk in vfs_unmount_9p() */ if (!ISSET(np->nmp->flags, F_UNMOUNTING)) clunk_9p(np->nmp, np->fid); /* free it */ CLR(np->flags, NODE_RECL); if (ISSET(np->flags, NODE_WAITRECL)) { CLR(np->flags, NODE_WAITRECL); wakeup(np); } lck_rw_free(np->lck, lck_grp_9p); free_9p(np->direntries); free_9p(np); return 0; }
static int vnop_readlink_9p(struct vnop_readlink_args *ap) { node_9p *np; uio_t uio; int e; TRACE(); e = 0; np = NTO9P(ap->a_vp); uio = ap->a_uio; if (!ISSET(np->nmp->flags, F_DOTU)) return ENOTSUP; nlock_9p(np, NODE_LCK_EXCLUSIVE); if ((e=ngetdir_9p(np))) goto error; e = uiomove(np->dir.ext, strlen(np->dir.ext), uio); error: nunlock_9p(np); return e; }
__private_extern__ int nget_9p(mount_9p *nmp, fid_9p fid, qid_9p qid, vnode_t dvp, vnode_t *vpp, struct componentname *cnp, vfs_context_t ctx) { #pragma unused(ctx) struct vnode_fsparam fsp; struct hnode_9p *nhp; node_9p *np; uint32_t vid; int e, i; TRACE(); nhp = HASH9P(nmp, qid.path); loop: lck_mtx_lock(nmp->nodelck); LIST_FOREACH (np, nhp, next) { if(np->dir.qid.path != qid.path) continue; if (ISSET(np->flags, NODE_INIT)) { SET(np->flags, NODE_WAITINIT); msleep(np, nmp->nodelck, PINOD|PDROP, "nget_9p_init", NULL); goto loop; } if (ISSET(np->flags, NODE_RECL)) { SET(np->flags, NODE_WAITRECL); msleep(np, nmp->nodelck, PINOD|PDROP, "nget_9p_reclaim", NULL); goto loop; } vid = vnode_vid(np->vp); lck_mtx_unlock(nmp->nodelck); if (vnode_getwithvid(np->vp, vid)) goto loop; nlock_9p(np, NODE_LCK_EXCLUSIVE); if (dvp && cnp && ISSET(cnp->cn_flags, MAKEENTRY) && np->dir.qid.vers!=0) { // DEBUG("caching %s", np->dir->name); cache_enter(dvp, np->vp, cnp); } else { // DEBUG("not in cache qid=%d %s", qid.vers, np->dir->name); } *vpp = np->vp; return 0; } if (fid == NOFID) return EFAULT; np = malloc_9p(sizeof(*np)); if (np == NULL) { err0: lck_mtx_unlock(nmp->nodelck); return ENOMEM; } np->lck = lck_rw_alloc_init(lck_grp_9p, LCK_ATTR_NULL); if (np->lck == NULL) { free_9p(np); goto err0; } np->nmp = nmp; np->fid = fid; np->dir.qid = qid; for (i=0; i<3; i++) np->openfid[i].fid = NOFID; SET(np->flags, NODE_INIT); LIST_INSERT_HEAD(nhp, np, next); nlock_9p(np, NODE_LCK_EXCLUSIVE); lck_mtx_unlock(nmp->nodelck); if ((e=ngetdir_9p(np))) { err1: nunlock_9p(np); lck_mtx_lock(nmp->nodelck); LIST_REMOVE(np, next); CLR(np->flags, NODE_INIT); if (ISSET(np->flags, NODE_WAITINIT)) { CLR(np->flags, NODE_WAITINIT); wakeup(np); } lck_mtx_unlock(nmp->nodelck); lck_rw_free(np->lck, lck_grp_9p); free_9p(np); return e; } fsp.vnfs_mp = nmp->mp; fsp.vnfs_str = fsname; fsp.vnfs_dvp = dvp; fsp.vnfs_fsnode = np; fsp.vnfs_vops = vnode_op_9p; fsp.vnfs_markroot = dvp==NULL? TRUE: FALSE; fsp.vnfs_marksystem = FALSE; fsp.vnfs_filesize = np->dir.length; fsp.vnfs_cnp = cnp; fsp.vnfs_flags = VNFS_ADDFSREF; dirvtype_9p(&np->dir, ISSET(nmp->flags, F_DOTU), &fsp.vnfs_vtype, &fsp.vnfs_rdev); if (!dvp || !cnp || !ISSET(cnp->cn_flags, MAKEENTRY) || qid.vers==0) SET(fsp.vnfs_flags, VNFS_NOCACHE); if ((e=vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &fsp, &np->vp))) goto err1; vnode_settag(np->vp, VT_OTHER); lck_mtx_lock(nmp->nodelck); CLR(np->flags, NODE_INIT); if (ISSET(np->flags, NODE_WAITINIT)) { CLR(np->flags, NODE_WAITINIT); wakeup(np); } lck_mtx_unlock(nmp->nodelck); *vpp = np->vp; return 0; }
static int vnop_readdir_9p(struct vnop_readdir_args *ap) { struct direntry de64; struct dirent de32; vnode_t vp; node_9p *np; dir_9p *dp; fid_9p fid; off_t off; uio_t uio; uint32_t i, nd, nlen, plen; void *p; int e; TRACE(); vp = ap->a_vp; uio = ap->a_uio; np = NTO9P(vp); if (!vnode_isdir(vp)) return ENOTDIR; if (ISSET(ap->a_flags, VNODE_READDIR_REQSEEKOFF)) return EINVAL; off = uio_offset(uio); if (off < 0) return EINVAL; if (uio_resid(uio) == 0) return 0; e = 0; nlock_9p(np, NODE_LCK_EXCLUSIVE); fid = np->openfid[OREAD].fid; if (fid == NOFID) { e = EBADF; goto error; } if (ap->a_eofflag) ap->a_eofflag = 0; if (off == 0 || np->direntries==NULL) { if((e=readdirs_9p(np->nmp, fid, &np->direntries, &np->ndirentries))) goto error; if (np->ndirentries && np->direntries==NULL) panic("bug in readdir"); } dp = np->direntries; nd = np->ndirentries; for (i=off; i<nd; i++) { if (ISSET(ap->a_flags, VNODE_READDIR_EXTENDED)) { bzero(&de64, sizeof(de64)); de64.d_ino = QTOI(dp[i].qid); de64.d_type = dp[i].mode&DMDIR? DT_DIR: DT_REG; nlen = strlen(dp[i].name); de64.d_namlen = MIN(nlen, sizeof(de64.d_name)-1); bcopy(dp[i].name, de64.d_name, de64.d_namlen); de64.d_reclen = DIRENT64_LEN(de64.d_namlen); plen = de64.d_reclen; p = &de64; } else { bzero(&de32, sizeof(de32)); de32.d_ino = QTOI(dp[i].qid); de32.d_type = dp[i].mode&DMDIR? DT_DIR: DT_REG; nlen = strlen(dp[i].name); de32.d_namlen = MIN(nlen, sizeof(de32.d_name)-1); bcopy(dp[i].name, de32.d_name, de32.d_namlen); de32.d_reclen = DIRENT32_LEN(de32.d_namlen); plen = de32.d_reclen; p = &de32; } if (uio_resid(uio) < plen) break; if ((e=uiomove(p, plen, uio))) goto error; } uio_setoffset(uio, i); if (ap->a_numdirent) *ap->a_numdirent = i - off; if (i==nd && ap->a_eofflag) { *ap->a_eofflag = 1; free_9p(np->direntries); np->direntries = NULL; np->ndirentries = 0; } error: nunlock_9p(np); return e; }
static int vnop_lookup_9p(struct vnop_lookup_args *ap) { struct componentname *cnp; node_9p *dnp; vnode_t *vpp, dvp; fid_9p fid; qid_9p qid; int e; TRACE(); dvp = ap->a_dvp; vpp = ap->a_vpp; cnp = ap->a_cnp; dnp = NTO9P(dvp); if(!vnode_isdir(dvp)) return ENOTDIR; if (isdotdot(cnp) && vnode_isvroot(dvp)) return EIO; if (islastcn(cnp) && !isop(cnp, LOOKUP) && vnode_vfsisrdonly(dvp)) return EROFS; if (isdot(cnp)) { if (islastcn(cnp) && isop(cnp, RENAME)) return EISDIR; if ((e=vnode_get(dvp))) return e; *vpp = dvp; return 0; } if (isdotdot(cnp)) { *vpp = vnode_getparent(dvp); if (*vpp == NULL) return ENOENT; return 0; } e = cache_lookup(dvp, vpp, cnp); if (e == -1) /* found */ return 0; if (e != 0) /* errno */ return e; /* not in cache */ nlock_9p(dnp, NODE_LCK_EXCLUSIVE); e = walk_9p(dnp->nmp, dnp->fid, cnp->cn_nameptr, cnp->cn_namelen, &fid, &qid); if (e) { if (islastcn(cnp)) { if (isop(cnp, CREATE) || isop(cnp, RENAME)) e = EJUSTRETURN; else if (ismkentry(cnp) && dnp->dir.qid.vers!=0) cache_enter(dvp, NULL, cnp); } goto error; } e = nget_9p(dnp->nmp, fid, qid, dvp, vpp, cnp, ap->a_context); if (e || *vpp==NULL || NTO9P(*vpp)->fid!=fid) clunk_9p(dnp->nmp, fid); if (*vpp) nunlock_9p(NTO9P(*vpp)); error: nunlock_9p(dnp); return e; }
static int ncreate_9p(vnode_t dvp, vnode_t *vpp, struct componentname *cnp, struct vnode_attr *vap, vfs_context_t ctx, char *target) { openfid_9p *op; mount_9p *nmp; node_9p *dnp, *np; uint32_t perm, iounit; uint8_t mode; fid_9p fid, openfid; qid_9p qid; char *ext, buf[64]; int e; dnp = NTO9P(dvp); nmp = dnp->nmp; fid = NOFID; openfid = NOFID; *vpp = NULL; if (vnode_vfsisrdonly(dvp)) return EROFS; if (!ISSET(nmp->flags, F_DOTU) && vap->va_type!=VREG && vap->va_type!=VDIR) return ENOTSUP; if (!ISSET(nmp->flags, FLAG_DSSTORE) && strncmp(".DS_Store", cnp->cn_nameptr, cnp->cn_namelen)==0) return EINVAL; ext = ""; mode = ORDWR; perm = MAKEIMODE(vap->va_type, vap->va_mode) & 0777; switch (vap->va_type) { case VREG: break; case VDIR: mode = OREAD; SET(perm, DMDIR); break; case VBLK: case VCHR: SET(perm, DMDEVICE); snprintf(buf, sizeof(buf), "%c %d %d", vap->va_type==VBLK?'b':'c', vap->va_rdev>>20, vap->va_rdev&((1<<20) - 1)); ext = buf; break; case VFIFO: SET(perm, DMNAMEDPIPE); break; case VSOCK: SET(perm, DMSOCKET); break; case VLNK: SET(perm, DMSYMLINK); ext = target; break; default: return EINVAL; } if (ISSET(vap->va_vaflags, VA_EXCLUSIVE)) SET(mode, OEXCL); nlock_9p(dnp, NODE_LCK_EXCLUSIVE); if ((e=walk_9p(nmp, dnp->fid, NULL, 0, &openfid, &qid))) goto error; if ((e=create_9p(nmp, openfid, cnp->cn_nameptr, cnp->cn_namelen, mode, perm, ext, &qid, &iounit))) goto error; if ((e=walk_9p(nmp, dnp->fid, cnp->cn_nameptr, cnp->cn_namelen, &fid, &qid))) goto error; if ((e=nget_9p(nmp, fid, qid, dvp, vpp, cnp, ctx))) goto error; cache_purge_negatives(dvp); np = NTO9P(*vpp); np->iounit = iounit; op = &np->openfid[vap->va_type==VDIR? OREAD: ORDWR]; op->fid = openfid; OSIncrementAtomic(&op->ref); nunlock_9p(np); nunlock_9p(dnp); return 0; error: clunk_9p(nmp, openfid); clunk_9p(nmp, fid); nunlock_9p(dnp); return e; }
static int vnop_open_9p(struct vnop_open_args *ap) { openfid_9p *op; node_9p *np; fid_9p fid; qid_9p qid; uint32_t iounit; int e, flags, mode; TRACE(); flags = 0; if (ap->a_mode) flags = OFLAGS(ap->a_mode); mode = flags & O_ACCMODE; CLR(flags, O_ACCMODE); CLR(flags, O_DIRECTORY|O_NONBLOCK|O_NOFOLLOW); CLR(flags, O_APPEND); /* locks implemented on the vfs layer */ CLR(flags, O_EXLOCK|O_SHLOCK); if (ISSET(flags, O_TRUNC)) { SET(mode, OTRUNC); CLR(flags, O_TRUNC); } if (ISSET(flags, O_CLOEXEC)) { SET(mode, OCEXEC); CLR(flags, O_CLOEXEC); } if (ISSET(flags, O_EXCL)) { SET(mode, OEXCL); CLR(flags, O_EXCL); } /* vnop_creat just called */ CLR(flags, O_CREAT); if (ISSET(flags, O_EVTONLY)) CLR(flags, O_EVTONLY); if (ISSET(flags, FNOCACHE)) CLR(flags, FNOCACHE); if (ISSET(flags, FNORDAHEAD)) CLR(flags, FNORDAHEAD); if (flags) { DEBUG("unexpected open mode %x", flags); return ENOTSUP; } np = NTO9P(ap->a_vp); nlock_9p(np, NODE_LCK_EXCLUSIVE); op = ofidget(np, ap->a_mode); if (op->fid == NOFID) { if ((e=walk_9p(np->nmp, np->fid, NULL, 0, &fid, &qid))) goto error; if ((e=open_9p(np->nmp, fid, mode, &qid, &iounit))) goto error; np->iounit = iounit; op->fid = fid; } /* no cache for dirs, .u or synthetic files */ if (!vnode_isreg(np->vp) || np->dir.qid.vers==0) { vnode_setnocache(np->vp); vnode_setnoreadahead(np->vp); } OSIncrementAtomic(&op->ref); nunlock_9p(np); return 0; error: clunk_9p(np->nmp, fid); nunlock_9p(np); return e; }
static int vnop_setattr_9p(struct vnop_setattr_args *ap) { struct vnode_attr *vap; vnode_t vp; node_9p *np; dir_9p d; int e; TRACE(); vp = ap->a_vp; vap = ap->a_vap; np = NTO9P(vp); if (vnode_vfsisrdonly(vp)) return EROFS; if (vnode_isvroot(vp)) return EACCES; nulldir(&d); if (VATTR_IS_ACTIVE(vap, va_data_size)) { if (vnode_isdir(vp)) return EISDIR; d.length = vap->va_data_size; } VATTR_SET_SUPPORTED(vap, va_data_size); if (VATTR_IS_ACTIVE(vap, va_access_time)) d.atime = vap->va_access_time.tv_sec; VATTR_SET_SUPPORTED(vap, va_access_time); if (VATTR_IS_ACTIVE(vap, va_modify_time)) d.mtime = vap->va_modify_time.tv_sec; VATTR_SET_SUPPORTED(vap, va_modify_time); if (VATTR_IS_ACTIVE(vap, va_mode)) { d.mode = vap->va_mode & 0777; if (vnode_isdir(vp)) SET(d.mode, DMDIR); if (ISSET(np->nmp->flags, F_DOTU)) { switch (vnode_vtype(vp)) { case VBLK: case VCHR: SET(d.mode, DMDEVICE); break; case VLNK: SET(d.mode, DMSYMLINK); break; case VSOCK: SET(d.mode, DMSOCKET); break; case VFIFO: SET(d.mode, DMNAMEDPIPE); break; default: break; } } } VATTR_SET_SUPPORTED(vap, va_mode); nlock_9p(np, NODE_LCK_EXCLUSIVE); e = wstat_9p(np->nmp, np->fid, &d); np->dirtimer = 0; if (e==0 && d.length!=~0) ubc_setsize(vp, d.length); nunlock_9p(np); return e; }
static int vfs_mount_9p(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t ctx) { #pragma unused(devvp) struct sockaddr *addr, *authaddr; struct vfsstatfs *sp; char authkey[DESKEYLEN+1]; kauth_cred_t cred; user_args_9p args; mount_9p *nmp; size_t size; fid_9p fid; qid_9p qid; char *vers; int e; TRACE(); nmp = NULL; addr = NULL; authaddr = NULL; fid = NOFID; if (vfs_isupdate(mp)) return ENOTSUP; if (vfs_context_is64bit(ctx)) { if ((e=copyin(data, &args, sizeof(args)))) goto error; } else { args_9p args32; if ((e=copyin(data, &args32, sizeof(args32)))) goto error; args.spec = CAST_USER_ADDR_T(args32.spec); args.addr = CAST_USER_ADDR_T(args32.addr); args.addrlen = args32.addrlen; args.authaddr = CAST_USER_ADDR_T(args32.authaddr); args.authaddrlen = args32.authaddrlen; args.volume = CAST_USER_ADDR_T(args32.volume); args.uname = CAST_USER_ADDR_T(args32.uname); args.aname = CAST_USER_ADDR_T(args32.aname); args.authkey = CAST_USER_ADDR_T(args32.authkey); args.flags = args32.flags; } e = ENOMEM; nmp = malloc_9p(sizeof(*nmp)); if (nmp == NULL) return e; nmp->mp = mp; TAILQ_INIT(&nmp->req); nmp->lck = lck_mtx_alloc_init(lck_grp_9p, LCK_ATTR_NULL); nmp->reqlck = lck_mtx_alloc_init(lck_grp_9p, LCK_ATTR_NULL); nmp->nodelck = lck_mtx_alloc_init(lck_grp_9p, LCK_ATTR_NULL); nmp->node = hashinit(desiredvnodes, M_TEMP, &nmp->nodelen); if (nmp->lck==NULL || nmp->reqlck==NULL || nmp->nodelck==NULL || nmp->node==NULL) goto error; if ((e=nameget_9p(args.volume, &nmp->volume))) goto error; if ((e=nameget_9p(args.uname, &nmp->uname))) goto error; if ((e=nameget_9p(args.aname, &nmp->aname))) goto error; cred = vfs_context_ucred(ctx); if (IS_VALID_CRED(cred)) { nmp->uid = kauth_cred_getuid(cred); nmp->gid = kauth_cred_getgid(cred); } else { nmp->uid = KAUTH_UID_NONE; nmp->gid = KAUTH_GID_NONE; } vfs_getnewfsid(mp); vfs_setfsprivate(mp, nmp); nmp->flags = args.flags; if ((e=addrget_9p(args.addr, args.addrlen, &addr))) goto error; if ((e=connect_9p(nmp, addr))) goto error; vers = VERSION9P; if (ISSET(nmp->flags, FLAG_DOTU)) vers = VERSION9PDOTU; if ((e=version_9p(nmp, vers, &nmp->version))) goto error; if (ISSET(nmp->flags, FLAG_DOTU) && strcmp(VERSION9PDOTU, nmp->version)==0) SET(nmp->flags, F_DOTU); nmp->afid = NOFID; if (args.authaddr && args.authaddrlen && args.authkey) { if ((e=copyin(args.authkey, authkey, DESKEYLEN))) goto error; if ((e=addrget_9p(args.authaddr, args.authaddrlen, &authaddr))) goto error; if ((e=auth_9p(nmp, nmp->uname, nmp->aname, nmp->uid, &nmp->afid, &qid))) goto error; if (nmp->afid!=NOFID && (e=authp9any_9p(nmp, nmp->afid, authaddr, nmp->uname, authkey))) goto error; bzero(authkey, DESKEYLEN); } if ((e=attach_9p(nmp, nmp->uname, nmp->aname, nmp->afid, nmp->uid, &fid, &qid))) goto error; if ((e=nget_9p(nmp, fid, qid, NULL, &nmp->root, NULL, ctx))) goto error; nunlock_9p(NTO9P(nmp->root)); e = vnode_ref(nmp->root); vnode_put(nmp->root); if (e) goto error; vfs_setauthopaque(mp); vfs_clearauthopaqueaccess(mp); vfs_setlocklocal(mp); // init stats sp = vfs_statfs(nmp->mp); copyinstr(args.spec, sp->f_mntfromname, MNAMELEN-1, &size); bzero(sp->f_mntfromname+size, MNAMELEN-size); sp->f_bsize = PAGE_SIZE; sp->f_iosize = nmp->msize-IOHDRSZ; sp->f_blocks = sp->f_bfree = sp->f_bavail = sp->f_bused = 0; sp->f_files = 65535; sp->f_ffree = sp->f_files-2; sp->f_flags = vfs_flags(mp); free_9p(addr); free_9p(authaddr); return 0; error: bzero(authkey, DESKEYLEN); free_9p(addr); free_9p(authaddr); if (nmp->so) { clunk_9p(nmp, fid); disconnect_9p(nmp); } freemount_9p(nmp); vfs_setfsprivate(mp, NULL); return e; }