📄 nfs_vnodeops.c
字号:
vp->g_size = vap->va_size; } vattr_to_sattr(vap, &args.saa_sa); args.saa_fh = *vtofh(vp); error = rfscall(vtomi(vp), RFS_SETATTR, xdr_saargs, (caddr_t)&args, xdr_attrstat, (caddr_t)ns, cred); if (!error) { error = geterrno(ns->ns_status); if (!error) { nfs_attrcache(vp, &ns->ns_attr, SFLUSH); } else { check_stale_fh(error, vp); } } } kmem_free(ns, KM_NFS); return (error);}intnfs_readlink(vp, uiop, cred) struct vnode *vp; struct uio *uiop; struct ucred *cred;{ int error; struct nfsrdlnres rl; if(vp->v_type != VLNK) return (ENXIO); kmem_alloc(rl.rl_data, char *, (u_int)NFS_MAXPATHLEN, KM_NFS); error = rfscall(vtomi(vp), RFS_READLINK, xdr_fhandle, (caddr_t)vtofh(vp), xdr_rdlnres, (caddr_t)&rl, cred); if (!error) { error = geterrno(rl.rl_status); if (!error) { error = uiomove(rl.rl_data, (int)rl.rl_count, UIO_READ, uiop); } else { check_stale_fh(error, vp); } } kmem_free(rl.rl_data, KM_NFS); return (error);}int nfs_fsync_size = 16;intnfs_fsync(vp) struct vnode *vp;{ register struct rnode *rp = vtor(vp); register int offset, blksize; register long lastlbn; struct nfsattrstat *ns; int error; int need_lock = 0; /* Do nothing if the file is not dirty */ if (rp->r_flags & RDIRTY) { /* First off, synchronize processes by locking vp */ if (glocked((struct gnode *)vp) != LK_TRUE) { need_lock = 1; gfs_lock((struct gnode *)vp); } if (!(rp->r_flags & RDIRTY)) { /* someone beat us to it */ if (need_lock) { gfs_unlock((struct gnode *)vp); } else { panic("nfs_fsync: lost RDIRTY"); } return (rp->r_error); } /* * Now that we have the gnode locked, we can reset the * RDIRTY flag when we are done since no * writes can occur "behind" us while we are flushing. * * This flag is used by nfs_attrcache() to determine if the * delayed write block completions that we are flushing * are allowed to update the g_size field with the server's * notion of file size. * * If we reset the flag before we are done, there may be an * orphaned delayed write block at the end of the file * (the loop terminates early because the g_size field * is down-sized). If this happens, then the next sync() * may get left holding the bag with a buffer for a gnode * that has been inactive'd. */ blksize = vtoblksz(vp); lastlbn = howmany((unsigned long)vp->g_size, (unsigned long)blksize); if (lastlbn < nfs_fsync_size) { /* small file - synchronous writes */ error = u.u_error; /* save state */ for (offset = 0; offset < vp->g_size; offset += blksize) { blkflush(vp->g_dev, (daddr_t)(offset/DEV_BSIZE), (long)blksize, vp); } /* * If there were writes performed above by blkflush() * they were synchronous, and geterror() posted any * error directly into u.u_error. To make this * policy work like the one below, remove any * change to u.u_error caused by us. */ if (u.u_error) { rp->r_error = u.u_error; if (!error) u.u_error = 0; } } else { /* large file - asynchronous writes */ bflush(NODEV, vp, 1); /* sync delayed writes */ /* * If there were writes performed above by bflush() * they were asynchronous, and nfswrite() posted * any error in rp->r_error. If an asynch write error * occurred prior to this routine being called * (or during the call), then all remaing dirty * buffers are "tossed" in nfs_strategy() or * nfswrite(). */ } /* * NB: Note that the file has been flushed. * All writes to this file, including writes handed off * to biods prior to or during this invocation, * have been accounted for. * Since the biods would pile up sleeping on gp * (in nfs_attrcache()) until we unlock it, nfswrite() * doesn't call nfs_attrcache() for async writes. * Thus, we are not put in a race with nfs_attrcache() * which could result in confused file attributes * (most probably size). * * We ensure that when this call completes * the file attributes are up to date with any * writes that we have pushed out. We go directly to the * wire (holding gp locked) to get current ones. */ kmem_alloc(ns, struct nfsattrstat *, (u_int)sizeof(*ns), KM_NFS); error = rfscall(vtomi(vp), RFS_GETATTR, xdr_fhandle, (caddr_t)vtofh(vp), xdr_attrstat, (caddr_t)ns, u.u_cred); if (!error) { error = geterrno(ns->ns_status); if (!error) { nfs_attrcache(vp, &ns->ns_attr, NOFLUSH); } else { check_stale_fh(error, vp); } } kmem_free(ns, KM_NFS); rp->r_flags &= ~RDIRTY; /* open the gate in nfs_attrcache() */ if (need_lock) gfs_unlock((struct gnode *)vp); } return (rp->r_error);}/* * Make an NFS gnode inactive. * Weirdness: if the file was removed while it was open it got * renamed (by nfs_remove) instead. Here we remove the renamed * file. Note: the gnode must be in a consistent state when this * routine is called, since we may block in rfscall. *//*ARGSUSED*/intnfs_inactive(vp, cred) struct vnode *vp; struct ucred *cred;{ register struct rnode *rp = vtor(vp); int error; struct nfsdiropargs da; enum nfsstat status; if (rp->r_unlname != NULL) { setdiropargs(&da, rp->r_unlname, rp->r_unldvp); error = rfscall(vtomi(rp->r_unldvp), RFS_REMOVE, xdr_diropargs, (caddr_t)&da, xdr_enum, (caddr_t)&status, rp->r_unlcred); if (!error) { error = geterrno(status); } VN_RELE(rp->r_unldvp); kmem_free((caddr_t)rp->r_unlname, KM_NFS); crfree(rp->r_unlcred); rp->r_unldvp = NULL; rp->r_unlname = NULL; rp->r_unlcred = NULL; } if (rp->r_cred) { crfree(rp->r_cred); rp->r_cred = NULL; } return (0);}/* * Remote file system operations having to do with directory manipulation. */intnfs_lookup(dvp, nm, vpp, cred) struct vnode *dvp; char *nm; struct vnode **vpp; struct ucred *cred;{ int error; struct nfsdiropargs da; struct nfsdiropres *dr; /* * Before checking dnlc, call getattr to be * sure directory hasn't changed. getattr * will purge dnlc if a change has occurred. */ if (error = nfs_getattr(dvp, cred)) { *vpp = (struct vnode *)0; return (error); } *vpp = (struct vnode *) dnlc_lookup(dvp, nm, cred); if (*vpp) { nfs_lock(dvp); /* synchronize with any other process */ /* that has vp locked before the check, */ /* where it may be temporarily unlocked */ if (access(dvp, GEXEC)) { /* must be able to scan the dir */ nfs_unlock(dvp); return (u.u_error); } nfs_unlock(dvp); return (0); } kmem_alloc(dr, struct nfsdiropres *, (u_int)sizeof(*dr), KM_NFS); setdiropargs(&da, nm, dvp); error = rfscall(vtomi(dvp), RFS_LOOKUP, xdr_diropargs, (caddr_t)&da, xdr_diropres, (caddr_t)dr, cred); if (!error) { error = geterrno(dr->dr_status); check_stale_fh(error, dvp); } if (!error) { *vpp = makenfsnode(&dr->dr_fhandle, &dr->dr_attr, dvp->v_vfsp, ((struct gnode *) dvp)->g_mp); if(*vpp == NULL) error = u.u_error; else if (nfs_dnlc) dnlc_enter(dvp, nm, *vpp, cred); } else { *vpp = (struct vnode *)0; } kmem_free(dr, KM_NFS); return (error);}/*ARGSUSED*/intnfs_create(dvp, nm, va, exclusive, vpp, cred) struct vnode *dvp; char *nm; struct vattr *va; enum vcexcl exclusive; struct vnode **vpp; struct ucred *cred;{ int error; struct nfscreatargs args; struct nfsdiropres *dr; if (exclusive == EXCL) { /* * This is buggy: there is a race between the lookup and the * create. We should send the exclusive flag over the wire. */ error = nfs_lookup(dvp, nm, vpp, cred); if (error != ENOENT) { if (*vpp) VN_RELE(*vpp); return (error ? error : EEXIST); } } *vpp = (struct vnode *)0; kmem_alloc(dr, struct nfsdiropres *, (u_int)sizeof(*dr), KM_NFS); setdiropargs(&args.ca_da, nm, dvp); /* * This is a completely gross hack to make mknod * work over the wire until we can wack the protocol */#define IFCHR 0020000 /* character special */#define IFBLK 0060000 /* block special */#define IFSOCK 0140000 /* socket */ if (va->va_type == VCHR) { va->va_mode |= IFCHR; va->va_size = (u_long)va->va_rdev; } else if (va->va_type == VBLK) { va->va_mode |= IFBLK; va->va_size = (u_long)va->va_rdev; } else if (va->va_type == VFIFO) { /* xtra kludge for namedpipe */ va->va_mode = (va->va_mode & ~GFMT) | IFCHR; va->va_size = (u_long)NFS_FIFO_DEV; /* blech */ } else if (va->va_type == VSOCK) { va->va_mode |= IFSOCK; } vattr_to_sattr(va, &args.ca_sa); dnlc_remove(dvp, nm); error = rfscall(vtomi(dvp), RFS_CREATE, xdr_creatargs, (caddr_t)&args, xdr_diropres, (caddr_t)dr, cred); nfsattr_inval(dvp); if (!error) { error = geterrno(dr->dr_status); if (error) { check_stale_fh(error, dvp); } else { *vpp = makenfsnode(&dr->dr_fhandle, &dr->dr_attr, dvp->v_vfsp, ((struct gnode *)dvp)->g_mp); if (*vpp != NULL) { ((struct gnode *)*vpp)->g_size = 0; if (nfs_dnlc) { dnlc_enter(dvp, nm, *vpp, cred); } } else error = u.u_error; } } kmem_free(dr, KM_NFS); return (error);}/* * Weirdness: if the vnode to be removed is open * we rename it instead of removing it and nfs_inactive * will remove the new name. */intnfs_remove(dvp, vp, nm, cred) struct vnode *dvp; struct vnode *vp; char *nm; struct ucred *cred;{ register struct rnode *rp = vtor(vp); int error; struct nfsdiropargs da; enum nfsstat status; char *tmpname; status = NFS_OK; /* * We need to flush the name cache so we can * check the real reference count on the vnode */ dnlc_purge_vp(vp); if (((struct gnode *)vp)->g_count > 1 && rp->r_unlname == NULL) { tmpname = newname(nm); error = nfs_rename(dvp, nm, dvp, tmpname, cred); if (error) { kmem_free(tmpname, KM_NFS); } else { VN_HOLD(dvp); rp->r_unldvp = dvp; rp->r_unlname = tmpname; if (rp->r_unlcred != NULL) { crfree(rp->r_unlcred); } crhold(cred); rp->r_unlcred = cred; } } else { setdiropargs(&da, nm, dvp); error = rfscall(vtomi(dvp), RFS_REMOVE, xdr_diropargs, (caddr_t)&da, xdr_enum, (caddr_t)&status, cred); nfsattr_inval(dvp); /* mod time changed */ nfsattr_inval(vp); /* link count changed */ check_stale_fh(error ? error : geterrno(error), dvp); } if (!error) { error = geterrno(status); } return (error);}intnfs_link(vp, tdvp, tnm, cred) struct vnode *vp; struct vnode *tdvp; char *tnm; struct ucred *cred;{ int error; struct nfslinkargs args; enum nfsstat status; args.la_from = *vtofh(vp); setdiropargs(&args.la_to, tnm, tdvp); error = rfscall(vtomi(vp), RFS_LINK, xdr_linkargs, (caddr_t)&args, xdr_enum, (caddr_t)&status, cred); nfsattr_inval(tdvp); /* mod time changed */ nfsattr_inval(vp); /* link count changed */ if (!error) { error = geterrno(status); check_stale_fh(error, vp); check_stale_fh(error, tdvp); } return (error);}intnfs_rename(odvp, onm, ndvp, nnm, cred) struct vnode *odvp; char *onm; struct vnode *ndvp; char *nnm; struct ucred *cred;{ int error; enum nfsstat status; struct nfsrnmargs args; if (!bcmp(onm, ".", 2) || !bcmp(onm, "..", 3) || !bcmp(nnm, ".", 3) || !bcmp(nnm, "..", 3)) { error = EINVAL; } else { dnlc_remove(odvp, onm); dnlc_remove(ndvp, nnm); setdiropargs(&args.rna_from, onm, odvp); setdiropargs(&args.rna_to, nnm, ndvp); error = rfscall(vtomi(odvp), RFS_RENAME, xdr_rnmargs, (caddr_t)&args, xdr_enum, (caddr_t)&status, cred); nfsattr_inval(odvp); /* mod time changed */ nfsattr_inval(ndvp); /* mod time changed */ if (!error) { error = geterrno(status); check_stale_fh(error, odvp); check_stale_fh(error, ndvp); } } return (error);}intnfs_mkdir(dvp, nm, va, vpp, cred) struct vnode *dvp; char *nm; register struct vattr *va; struct vnode **vpp; struct ucred *cred;{ int error; struct nfscreatargs args; struct nfsdiropres *dr; kmem_alloc(dr, struct nfsdiropres *, (u_int)sizeof(*dr), KM_NFS); setdiropargs(&args.ca_da, nm, dvp); vattr_to_sattr(va, &args.ca_sa); dnlc_remove(dvp, nm); error = rfscall(vtomi(dvp), RFS_MKDIR, xdr_creatargs, (caddr_t)&args, xdr_diropres, (caddr_t)dr, cred); nfsattr_inval(dvp); /* mod time changed */ if (!error) { error = geterrno(dr->dr_status); check_stale_fh(error, dvp); } if (!error) { /* * Due to a 4.0 reference port fiasco, the attributes that * come back on a mkdir may not be correct. Use them only * to set the vnode type in makenfsnode, then invalidate them. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -