diff -ur nfs.orig/nfs_node.c nfs/nfs_node.c --- nfs.orig/nfs_node.c 2006-04-03 12:20:15.000000000 -0500 +++ nfs/nfs_node.c 2006-04-05 03:12:36.000000000 -0500 @@ -213,13 +213,8 @@ np = VTONFS(ap->a_vp); if (prtactive && ap->a_vp->v_usecount != 0) vprint("nfs_inactive: pushing active", ap->a_vp); - if (ap->a_vp->v_type != VDIR) { - sp = np->n_sillyrename; - np->n_sillyrename = NULL; - } else { - sp = NULL; - } - if (sp) { + sp = &np->n_sillyrename; + if (ap->a_vp->v_type != VDIR && sp->s_ncp != NULL) { /* * We need a reference to keep the vnode from being * recycled by getnewvnode while we do the I/O @@ -238,10 +233,13 @@ /* * Remove the silly file that was rename'd earlier */ - nfs_removeit(sp); + cache_lock(sp->s_ncp); + /* XXX shouln't we lock s_ncp->nc_parent->nc_vp first? */ + nfs_removerpc(sp->s_ncp, sp->s_cred); + cache_setunresolved(sp->s_ncp); + cache_put(sp->s_ncp); crfree(sp->s_cred); - vrele(sp->s_dvp); - FREE((caddr_t)sp, M_NFSREQ); + sp->s_ncp = NULL; } np->n_flag &= ~(NWRITEERR | NACC | NUPD | NCHG | NLOCKED | NWANTED); diff -ur nfs.orig/nfs_vnops.c nfs/nfs_vnops.c --- nfs.orig/nfs_vnops.c 2006-04-03 12:20:15.000000000 -0500 +++ nfs/nfs_vnops.c 2006-04-06 00:13:00.000000000 -0500 @@ -112,9 +112,6 @@ static int nfsfifo_close (struct vop_close_args *); #define nfs_poll vop_nopoll static int nfs_setattrrpc (struct vnode *,struct vattr *,struct ucred *,struct thread *); -static int nfs_lookup (struct vop_old_lookup_args *); -static int nfs_create (struct vop_old_create_args *); -static int nfs_mknod (struct vop_old_mknod_args *); static int nfs_open (struct vop_open_args *); static int nfs_close (struct vop_close_args *); static int nfs_access (struct vop_access_args *); @@ -123,18 +120,12 @@ static int nfs_read (struct vop_read_args *); static int nfs_mmap (struct vop_mmap_args *); static int nfs_fsync (struct vop_fsync_args *); -static int nfs_remove (struct vop_old_remove_args *); -static int nfs_link (struct vop_old_link_args *); -static int nfs_rename (struct vop_old_rename_args *); -static int nfs_mkdir (struct vop_old_mkdir_args *); -static int nfs_rmdir (struct vop_old_rmdir_args *); -static int nfs_symlink (struct vop_old_symlink_args *); static int nfs_readdir (struct vop_readdir_args *); static int nfs_bmap (struct vop_bmap_args *); static int nfs_strategy (struct vop_strategy_args *); static int nfs_lookitup (struct vnode *, const char *, int, struct ucred *, struct thread *, struct nfsnode **); -static int nfs_sillyrename (struct vnode *,struct vnode *,struct componentname *); +static int nfs_sillyrename (struct namecache *, struct ucred *); static int nfsspec_access (struct vop_access_args *); static int nfs_readlink (struct vop_readlink_args *); static int nfs_print (struct vop_print_args *); @@ -142,6 +133,15 @@ static int nfs_bwrite (struct vop_bwrite_args *); static int nfs_nresolve (struct vop_nresolve_args *); +static int nfs_nlookupdotdot (struct vop_nlookupdotdot_args *); +static int nfs_ncreate (struct vop_ncreate_args *); +static int nfs_nmknod (struct vop_nmknod_args *); +static int nfs_nremove (struct vop_nremove_args *); +static int nfs_nlink (struct vop_nlink_args *); +static int nfs_nrename (struct vop_nrename_args *); +static int nfs_nmkdir (struct vop_nmkdir_args *); +static int nfs_nrmdir (struct vop_nrmdir_args *); +static int nfs_nsymlink (struct vop_nsymlink_args *); /* * Global vfs data structures for nfs */ @@ -152,7 +152,6 @@ { &vop_bmap_desc, (vnodeopv_entry_t) nfs_bmap }, { &vop_bwrite_desc, (vnodeopv_entry_t) nfs_bwrite }, { &vop_close_desc, (vnodeopv_entry_t) nfs_close }, - { &vop_old_create_desc, (vnodeopv_entry_t) nfs_create }, { &vop_fsync_desc, (vnodeopv_entry_t) nfs_fsync }, { &vop_getattr_desc, (vnodeopv_entry_t) nfs_getattr }, { &vop_getpages_desc, (vnodeopv_entry_t) nfs_getpages }, @@ -160,11 +159,7 @@ { &vop_inactive_desc, (vnodeopv_entry_t) nfs_inactive }, { &vop_islocked_desc, (vnodeopv_entry_t) vop_stdislocked }, { &vop_lease_desc, vop_null }, - { &vop_old_link_desc, (vnodeopv_entry_t) nfs_link }, { &vop_lock_desc, (vnodeopv_entry_t) vop_stdlock }, - { &vop_old_lookup_desc, (vnodeopv_entry_t) nfs_lookup }, - { &vop_old_mkdir_desc, (vnodeopv_entry_t) nfs_mkdir }, - { &vop_old_mknod_desc, (vnodeopv_entry_t) nfs_mknod }, { &vop_mmap_desc, (vnodeopv_entry_t) nfs_mmap }, { &vop_open_desc, (vnodeopv_entry_t) nfs_open }, { &vop_poll_desc, (vnodeopv_entry_t) nfs_poll }, @@ -173,16 +168,21 @@ { &vop_readdir_desc, (vnodeopv_entry_t) nfs_readdir }, { &vop_readlink_desc, (vnodeopv_entry_t) nfs_readlink }, { &vop_reclaim_desc, (vnodeopv_entry_t) nfs_reclaim }, - { &vop_old_remove_desc, (vnodeopv_entry_t) nfs_remove }, - { &vop_old_rename_desc, (vnodeopv_entry_t) nfs_rename }, - { &vop_old_rmdir_desc, (vnodeopv_entry_t) nfs_rmdir }, { &vop_setattr_desc, (vnodeopv_entry_t) nfs_setattr }, { &vop_strategy_desc, (vnodeopv_entry_t) nfs_strategy }, - { &vop_old_symlink_desc, (vnodeopv_entry_t) nfs_symlink }, { &vop_unlock_desc, (vnodeopv_entry_t) vop_stdunlock }, { &vop_write_desc, (vnodeopv_entry_t) nfs_write }, { &vop_nresolve_desc, (vnodeopv_entry_t) nfs_nresolve }, + { &vop_nlookupdotdot_desc, (vnodeopv_entry_t) nfs_nlookupdotdot }, + { &vop_ncreate_desc, (vnodeopv_entry_t) nfs_ncreate }, + { &vop_nmknod_desc, (vnodeopv_entry_t) nfs_nmknod }, + { &vop_nremove_desc, (vnodeopv_entry_t) nfs_nremove }, + { &vop_nlink_desc, (vnodeopv_entry_t) nfs_nlink }, + { &vop_nrename_desc, (vnodeopv_entry_t) nfs_nrename }, + { &vop_nmkdir_desc, (vnodeopv_entry_t) nfs_nmkdir }, + { &vop_nrmdir_desc, (vnodeopv_entry_t) nfs_nrmdir }, + { &vop_nsymlink_desc, (vnodeopv_entry_t) nfs_nsymlink }, { NULL, NULL } }; @@ -225,19 +225,8 @@ { NULL, NULL } }; -static int nfs_mknodrpc (struct vnode *dvp, struct vnode **vpp, - struct componentname *cnp, - struct vattr *vap); -static int nfs_removerpc (struct vnode *dvp, const char *name, - int namelen, - struct ucred *cred, struct thread *td); -static int nfs_renamerpc (struct vnode *fdvp, const char *fnameptr, - int fnamelen, struct vnode *tdvp, - const char *tnameptr, int tnamelen, - struct ucred *cred, struct thread *td); -static int nfs_renameit (struct vnode *sdvp, - struct componentname *scnp, - struct sillyrename *sp); +static int nfs_renamerpc (struct namecache *fncp, struct namecache *tncp, + struct ucred *cred); /* * Global variables @@ -853,8 +842,8 @@ } /* - * NEW API CALL - replaces nfs_lookup(). However, we cannot remove - * nfs_lookup() until all remaining new api calls are implemented. + * nfs_nresolve { struct namecache *a_ncp, + * struct ucred *a_cred } * * Resolve a namecache entry. This function is passed a locked ncp and * must call cache_setvp() on it as appropriate to resolve the entry. @@ -872,7 +861,6 @@ int attrflag; int fhsize; int error; - int len; int v3; /******NFSM MACROS********/ struct mbuf *mb, *mrep, *mreq, *mb2, *md; @@ -892,12 +880,11 @@ v3 = NFS_ISV3(dvp); nfsstats.lookupcache_misses++; nfsstats.rpccnt[NFSPROC_LOOKUP]++; - len = ncp->nc_nlen; nfsm_reqhead(dvp, NFSPROC_LOOKUP, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen)); nfsm_fhtom(dvp, v3); - nfsm_strtom(ncp->nc_name, len, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_LOOKUP, td, ap->a_cred); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); + nfsm_request(dvp, NFSPROC_LOOKUP, td, cred); if (error) { /* * Cache negatve lookups to reduce NFS traffic, but use @@ -971,6 +958,91 @@ } /* + * nfs_nlookupdotdot { struct vnode *a_dvp, + * struct vnode **a_vpp, + * struct ucred *a_cred } + * + * Lookup the vnode representing the parent directory of the specified + * directory vnode. a_dvp should not be locked. If no error occurs *a_vpp + * will contained the parent vnode, locked and refd, else *a_vpp will be NULL. + * + * This function is designed to aid NFS server-side operations and is + * used by cache_fromdvp() to create a consistent, connected namecache + * topology. + * + * XXX The utility of this function is questionable, since re-exporting + * an NFS doesn't work. + * + */ +static int +nfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap) +{ + struct thread *td = curthread; + struct nfsnode *np; + struct vnode *dvp; + struct vnode *nvp; + nfsfh_t *fhp; + int attrflag; + int fhsize; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; + u_int32_t *tl; + int32_t t1, t2; + int error; /* set by nfsm_*, which may jump to nfsmout: */ + + *ap->a_vpp = NULL; + + dvp = ap->a_dvp; + if ((error = vget(dvp, LK_SHARED, td)) != 0) + return (error); + if (dvp->v_type != VDIR) { + vput(dvp); + return (ENOTDIR); + } + + v3 = NFS_ISV3(dvp); + nfsstats.lookupcache_misses++; + nfsstats.rpccnt[NFSPROC_LOOKUP]++; + nfsm_reqhead(dvp, NFSPROC_LOOKUP, + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(2)); + nfsm_fhtom(dvp, v3); + nfsm_strtom("..", (u_char)2, NFS_MAXNAMLEN); + nfsm_request(dvp, NFSPROC_LOOKUP, td, ap->a_cred); + if (error) { + nfsm_postop_attr(dvp, attrflag, NFS_LATTR_NOSHRINK); + m_freem(mrep); + goto nfsmout; + } + + /* + * Success, get the file handle, do various checks, and load + * post-operation data from the reply packet. + */ + nfsm_getfh(fhp, fhsize, v3); + + /* nfs_nget() locks and refs the vnode */ + error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); + if (error) { + m_freem(mrep); + goto nfsmout; /* NOTE: return error from nget */ + } + nvp = NFSTOV(np); + if (v3) { + nfsm_postop_attr(nvp, attrflag, NFS_LATTR_NOSHRINK); + nfsm_postop_attr(dvp, attrflag, NFS_LATTR_NOSHRINK); + } else { + nfsm_loadattr(nvp, NULL); + } + *ap->a_vpp = nvp; + m_freem(mrep); +nfsmout: + vput(dvp); + return (error); +} + +/* * 'cached' nfs directory lookup * * NOTE: cannot be removed until NFS implements all the new n*() API calls. @@ -978,6 +1050,7 @@ * nfs_lookup(struct vnodeop_desc *a_desc, struct vnode *a_dvp, * struct vnode **a_vpp, struct componentname *a_cnp) */ +#if 0 static int nfs_lookup(struct vop_old_lookup_args *ap) { @@ -1108,7 +1181,7 @@ } else nfsm_loadattr(newvp, (struct vattr *)0); #if 0 - /* XXX MOVE TO nfs_nremove() */ + /* XXX MOVE TO nfs_nremove(). n_ctime is used nowhere; remove it? */ if ((cnp->cn_flags & CNP_MAKEENTRY) && cnp->cn_nameiop != NAMEI_DELETE) { np->n_ctime = np->n_vattr.va_ctime.tv_sec; /* XXX */ @@ -1137,6 +1210,7 @@ } return (error); } +#endif /* * nfs read call. @@ -1392,43 +1466,70 @@ } /* - * nfs mknod rpc + * nfs_nmknod { struct namecache *a_ncp, + * struct vnode *a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap } + * + * nfs mknod vop * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the * mode set to specify the file type and the size field for rdev. */ static int -nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, - struct vattr *vap) +nfs_nmknod(struct vop_nmknod_args *ap) { + struct thread *td = curthread; + struct namecache *ncp = ap->a_ncp; + struct ucred *cred = ap->a_cred; + struct vattr *vap = ap->a_vap; + struct vnode *dvp; struct nfsv2_sattr *sp; - u_int32_t *tl; - caddr_t cp; - int32_t t1, t2; - struct vnode *newvp = (struct vnode *)0; - struct nfsnode *np = (struct nfsnode *)0; + struct vnode *newvp = NULL; + struct nfsnode *np = NULL; struct vattr vattr; - char *cp2; - caddr_t bpos, dpos; - int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; + int wccflag = NFSV3_WCCRATTR, gotvp = 0; u_int32_t rdev; - int v3 = NFS_ISV3(dvp); + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; + u_int32_t *tl; + int32_t t1, t2; + int error; /* set by nfsm_*, which may jump to nfsmout: */ + + *ap->a_vpp = NULL; if (vap->va_type == VCHR || vap->va_type == VBLK) rdev = txdr_unsigned(vap->va_rdev); else if (vap->va_type == VFIFO || vap->va_type == VSOCK) rdev = nfs_xdrneg1; - else { + else return (EOPNOTSUPP); + + KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0); + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return (error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return(EROFS); } - if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_td)) != 0) { + + if ((error = VOP_GETATTR(dvp, &vattr, td)) != 0) { + vput(dvp); return (error); } + + /* nfsm functions assume that error is zero! */ + v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_MKNOD]++; nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED + - + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); + nfsm_rndup(ncp->nc_nlen) + NFSX_SATTR(v3)); nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); if (v3) { nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); *tl++ = vtonfsv3_type(vap->va_type); @@ -1447,17 +1548,17 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_td, cnp->cn_cred); - if (!error) { + nfsm_request(dvp, NFSPROC_MKNOD, td, cred); + if (error == 0) { nfsm_mtofh(dvp, newvp, v3, gotvp); - if (!gotvp) { + if (gotvp == 0) { if (newvp) { vput(newvp); - newvp = (struct vnode *)0; + newvp = NULL; } - error = nfs_lookitup(dvp, cnp->cn_nameptr, - cnp->cn_namelen, cnp->cn_cred, cnp->cn_td, &np); - if (!error) + error = nfs_lookitup(dvp, ncp->nc_name, ncp->nc_nlen, + cred, td, &np); + if (error == 0) newvp = NFSTOV(np); } } @@ -1469,70 +1570,85 @@ if (newvp) vput(newvp); } else { - *vpp = newvp; + cache_setunresolved(ncp); + cache_setvp(ncp, newvp); + *ap->a_vpp = newvp; } VTONFS(dvp)->n_flag |= NLMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; + vput(dvp); return (error); } -/* - * nfs mknod vop - * just call nfs_mknodrpc() to do the work. - * - * nfs_mknod(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap) - */ -/* ARGSUSED */ -static int -nfs_mknod(struct vop_old_mknod_args *ap) -{ - return nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap); -} - static u_long create_verf; /* - * nfs file create call + * nfs_ncreate { struct namecache *a_ncp, + * struct vnode **a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap } * - * nfs_create(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap) + * nfs file create call */ static int -nfs_create(struct vop_old_create_args *ap) +nfs_ncreate(struct vop_ncreate_args *ap) { - struct vnode *dvp = ap->a_dvp; + struct thread *td = curthread; + struct namecache *ncp; + struct vnode *dvp; + struct ucred *cred = ap->a_cred; struct vattr *vap = ap->a_vap; - struct componentname *cnp = ap->a_cnp; struct nfsv2_sattr *sp; + struct nfsnode *np = NULL; + struct vnode *newvp = NULL; + int wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0; + struct vattr vattr; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; u_int32_t *tl; - caddr_t cp; int32_t t1, t2; - struct nfsnode *np = (struct nfsnode *)0; - struct vnode *newvp = (struct vnode *)0; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct vattr vattr; - int v3 = NFS_ISV3(dvp); + int error; /* set by nfsm_*, which may jump to nfsmout: */ + + ncp = ap->a_ncp; /* locked namecache node */ /* * Oops, not for me.. */ - if (vap->va_type == VSOCK) - return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); + if (vap->va_type == VSOCK) { + printf("nfs_ncreate() calling nfs_mknodrpc() instead\n"); + /* XXX This assumes vop_ncreate_args == vop_nmknod_args */ + return (nfs_nmknod(ap)); + } + + *ap->a_vpp = NULL; - if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_td)) != 0) { + KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0); + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return (error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return (EROFS); + } + + if ((error = VOP_GETATTR(dvp, &vattr, td)) != 0) { + vput(dvp); return (error); } if (vap->va_vaflags & VA_EXCLUSIVE) fmode |= O_EXCL; + v3 = NFS_ISV3(dvp); again: nfsstats.rpccnt[NFSPROC_CREATE]++; nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED + - nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); + nfsm_rndup(ncp->nc_nlen) + NFSX_SATTR(v3)); nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); if (v3) { nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); if (fmode & O_EXCL) { @@ -1558,17 +1674,17 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_td, cnp->cn_cred); - if (!error) { + nfsm_request(dvp, NFSPROC_CREATE, td, cred); + if (error == 0) { nfsm_mtofh(dvp, newvp, v3, gotvp); - if (!gotvp) { + if (gotvp == 0) { if (newvp) { vput(newvp); - newvp = (struct vnode *)0; + newvp = NULL; } - error = nfs_lookitup(dvp, cnp->cn_nameptr, - cnp->cn_namelen, cnp->cn_cred, cnp->cn_td, &np); - if (!error) + error = nfs_lookitup(dvp, ncp->nc_name, + ncp->nc_nlen, cred, td, &np); + if (error == 0) newvp = NFSTOV(np); } } @@ -1596,9 +1712,9 @@ vfs_timestamp(&vap->va_mtime); if (vap->va_atime.tv_sec == VNOVAL) vap->va_atime = vap->va_mtime; - error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_td); + error = nfs_setattrrpc(newvp, vap, cred, td); } - if (!error) { + if (error == 0) { /* * The new np may have enough info for access * checks, make sure rucred and wucred are @@ -1606,18 +1722,24 @@ */ np = VTONFS(newvp); if (np->n_rucred == NULL) - np->n_rucred = crhold(cnp->cn_cred); + np->n_rucred = crhold(cred); if (np->n_wucred == NULL) - np->n_wucred = crhold(cnp->cn_cred); + np->n_wucred = crhold(cred); + cache_setunresolved(ncp); + cache_setvp(ncp, newvp); *ap->a_vpp = newvp; } VTONFS(dvp)->n_flag |= NLMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; + vput(dvp); return (error); } /* + * nfs_nremove { struct namecache *a_ncp, + * struct ucred *a_cred } + * * nfs file remove call * To try and make nfs semantics closer to ufs semantics, a file that has * other processes using the vnode is renamed instead of removed and then @@ -1627,83 +1749,88 @@ * call nfs_sillyrename() to set it up * else * do the remove rpc - * - * nfs_remove(struct vnodeop_desc *a_desc, struct vnode *a_dvp, - * struct vnode *a_vp, struct componentname *a_cnp) */ static int -nfs_remove(struct vop_old_remove_args *ap) +nfs_nremove(struct vop_nremove_args *ap) { - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - struct nfsnode *np = VTONFS(vp); + struct thread *td = curthread; + struct namecache *ncp; + struct ucred *cred; + struct vnode *dvp, *vp; int error = 0; struct vattr vattr; -#ifndef DIAGNOSTIC - if (vp->v_usecount < 1) - panic("nfs_remove: bad v_usecount"); -#endif - if (vp->v_type == VDIR) - error = EPERM; - else if (vp->v_usecount == 1 || (np->n_sillyrename && - VOP_GETATTR(vp, &vattr, cnp->cn_td) == 0 && + ncp = ap->a_ncp; /* locked namecache node */ + cred = ap->a_cred; + + vp = ncp->nc_vp; + + KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0); + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return (error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return (EROFS); + } + + if (vp->v_usecount == 0 || (VTONFS(vp)->n_sillyrename.s_ncp != NULL && + VOP_GETATTR(vp, &vattr, td) == 0 && vattr.va_nlink > 1)) { /* * throw away biocache buffers, mainly to avoid * unnecessary delayed writes later. */ - error = nfs_vinvalbuf(vp, 0, cnp->cn_td, 1); + error = nfs_vinvalbuf(vp, 0, td, 1); /* Do the rpc */ - if (error != EINTR) - error = nfs_removerpc(dvp, cnp->cn_nameptr, - cnp->cn_namelen, cnp->cn_cred, cnp->cn_td); - /* - * Kludge City: If the first reply to the remove rpc is lost.. - * the reply to the retransmitted request will be ENOENT - * since the file was in fact removed - * Therefore, we cheat and return success. - */ - if (error == ENOENT) - error = 0; - } else if (!np->n_sillyrename) { - error = nfs_sillyrename(dvp, vp, cnp); + if (error != EINTR) { + error = nfs_removerpc(ncp, cred); + if (error == 0) + cache_setunresolved(ncp); + } + } else if (VTONFS(vp)->n_sillyrename.s_ncp == NULL) { + error = nfs_sillyrename(ncp, cred); } - np->n_attrstamp = 0; + /* + * Kludge City: If the first reply to the remove rpc is lost.. + * the reply to the retransmitted request will be ENOENT + * since the file was in fact removed + * Therefore, we cheat and return success. + */ + if (error == ENOENT && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM) + error = 0; + vput(dvp); return (error); } /* - * nfs file remove rpc called from nfs_inactive + * Nfs remove rpc, called from nfs_nremove() and nfs_inactive(). */ int -nfs_removeit(struct sillyrename *sp) -{ - return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, - sp->s_cred, NULL)); -} - -/* - * Nfs remove rpc, called from nfs_remove() and nfs_removeit(). - */ -static int -nfs_removerpc(struct vnode *dvp, const char *name, int namelen, - struct ucred *cred, struct thread *td) +nfs_removerpc(struct namecache *ncp, struct ucred *cred) { + struct thread *td = curthread; + struct vnode *dvp; + int wccflag = NFSV3_WCCRATTR; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; u_int32_t *tl; - caddr_t cp; int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(dvp); + int error = 0; /* set by nfsm_*, which may jump to nfsmout: */ + dvp = ncp->nc_parent->nc_vp; /* locked directory vnode */ + + v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_REMOVE]++; nfsm_reqhead(dvp, NFSPROC_REMOVE, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen)); + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen)); nfsm_fhtom(dvp, v3); - nfsm_strtom(name, namelen, NFS_MAXNAMLEN); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); nfsm_request(dvp, NFSPROC_REMOVE, td, cred); if (v3) nfsm_wcc_data(dvp, wccflag); @@ -1716,23 +1843,47 @@ } /* - * nfs file rename call + * nfs_nrename { struct namecache *a_fncp, + * struct namecache *a_tncp, + * struct ucred *a_cred } * - * nfs_rename(struct vnode *a_fdvp, struct vnode *a_fvp, - * struct componentname *a_fcnp, struct vnode *a_tdvp, - * struct vnode *a_tvp, struct componentname *a_tcnp) + * nfs file rename call */ static int -nfs_rename(struct vop_old_rename_args *ap) -{ - struct vnode *fvp = ap->a_fvp; - struct vnode *tvp = ap->a_tvp; - struct vnode *fdvp = ap->a_fdvp; - struct vnode *tdvp = ap->a_tdvp; - struct componentname *tcnp = ap->a_tcnp; - struct componentname *fcnp = ap->a_fcnp; +nfs_nrename(struct vop_nrename_args *ap) +{ + struct thread *td = curthread; + struct namecache *fncp, *tncp; + struct ucred *cred; + struct vnode *fdvp, *fvp, *tdvp, *tvp; int error; + fncp = ap->a_fncp; + tncp = ap->a_tncp; + cred = ap->a_cred; + + fvp = fncp->nc_vp; + tvp = tncp->nc_vp; + + KKASSERT((fncp->nc_flag & NCF_MOUNTPT) == 0); + KKASSERT((tncp->nc_flag & NCF_MOUNTPT) == 0); + + KKASSERT(fncp->nc_parent && fncp->nc_parent->nc_vp); + fdvp = fncp->nc_parent->nc_vp; + vref(fdvp); + + KKASSERT(tncp->nc_parent && tncp->nc_parent->nc_vp); + tdvp = tncp->nc_parent->nc_vp; + if ((error = vget(tdvp, LK_EXCLUSIVE, td)) != 0) { + vrele(fdvp); + return (error); + } + + if (fdvp->v_mount->mnt_flag & MNT_RDONLY) { + error = EROFS; + goto out; + } + /* Check for cross-device rename */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { @@ -1749,84 +1900,64 @@ * often. */ - VOP_FSYNC(fvp, MNT_WAIT, fcnp->cn_td); - if (tvp) - VOP_FSYNC(tvp, MNT_WAIT, tcnp->cn_td); + VOP_FSYNC(fvp, MNT_WAIT, td); + if (tvp) { + VOP_FSYNC(tvp, MNT_WAIT, td); - /* - * If the tvp exists and is in use, sillyrename it before doing the - * rename of the new file over it. - * - * XXX Can't sillyrename a directory. - * - * We do not attempt to do any namecache purges in this old API - * routine. The new API compat functions have access to the actual - * namecache structures and will do it for us. - */ - if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename && - tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { - vput(tvp); - tvp = NULL; - } else if (tvp) { - ; + /* + * If the tvp is in use, sillyrename it before doing the + * rename of the new file over it. + * + * XXX Can't sillyrename a directory. + */ + if (tvp->v_usecount > 0 && tvp->v_type != VDIR) + error = nfs_sillyrename(tncp, cred); } - error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, - tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, - tcnp->cn_td); + if (error == 0) + error = nfs_renamerpc(fncp, tncp, cred); -out: - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fdvp); - vrele(fvp); /* * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. */ - if (error == ENOENT) + if (error == ENOENT && VFSTONFS(tvp->v_mount)->nm_sotype == SOCK_DGRAM) error = 0; +out: + vput(tdvp); + vrele(fdvp); return (error); } /* - * nfs file rename rpc called from nfs_remove() above - */ -static int -nfs_renameit(struct vnode *sdvp, struct componentname *scnp, - struct sillyrename *sp) -{ - return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, - sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_td)); -} - -/* - * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). + * Do an nfs rename rpc. Called from nfs_nrename() and nfs_inactive(). */ static int -nfs_renamerpc(struct vnode *fdvp, const char *fnameptr, int fnamelen, - struct vnode *tdvp, const char *tnameptr, int tnamelen, - struct ucred *cred, struct thread *td) +nfs_renamerpc(struct namecache *fncp, struct namecache *tncp, + struct ucred *cred) { + struct thread *td = curthread; + struct vnode *fdvp, *tdvp, *vp; + int fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; u_int32_t *tl; - caddr_t cp; int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(fdvp); + int error = 0; /* set by nfsm_*, which may jump to nfsmout: */ + + fdvp = fncp->nc_parent->nc_vp; /* locked source directory vnode */ + tdvp = tncp->nc_parent->nc_vp; /* locked target directory vnode */ + v3 = NFS_ISV3(fdvp); nfsstats.rpccnt[NFSPROC_RENAME]++; nfsm_reqhead(fdvp, NFSPROC_RENAME, - (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + - nfsm_rndup(tnamelen)); + (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fncp->nc_nlen) + + nfsm_rndup(tncp->nc_nlen)); nfsm_fhtom(fdvp, v3); - nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN); + nfsm_strtom(fncp->nc_name, fncp->nc_nlen, NFS_MAXNAMLEN); nfsm_fhtom(tdvp, v3); - nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN); + nfsm_strtom(tncp->nc_name, tncp->nc_nlen, NFS_MAXNAMLEN); nfsm_request(fdvp, NFSPROC_RENAME, td, cred); if (v3) { nfsm_wcc_data(fdvp, fwccflag); @@ -1840,30 +1971,56 @@ VTONFS(fdvp)->n_attrstamp = 0; if (!twccflag) VTONFS(tdvp)->n_attrstamp = 0; + if (error == 0) { + vp = fncp->nc_vp; + vref(vp); + cache_rename(fncp, tncp); + cache_setvp(tncp, vp); + vrele(vp); + } return (error); } /* + * nfs_nlink { struct namecache *a_ncp, + * struct vnode *a_vp, + * struct ucred *a_cred } + * * nfs hard link create call * - * nfs_link(struct vnode *a_tdvp, struct vnode *a_vp, - * struct componentname *a_cnp) + * The passed vp is locked and represents the source. + * The passed ncp is locked and represents the target to create. */ static int -nfs_link(struct vop_old_link_args *ap) +nfs_nlink(struct vop_nlink_args *ap) { + struct thread *td = curthread; + struct namecache *ncp; + struct vnode *dvp; struct vnode *vp = ap->a_vp; - struct vnode *tdvp = ap->a_tdvp; - struct componentname *cnp = ap->a_cnp; + struct ucred *cred = ap->a_cred; + int wccflag = NFSV3_WCCRATTR, attrflag = 0; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; u_int32_t *tl; - caddr_t cp; int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3; + int error; /* set by nfsm_*, which may jump to nfsmout: */ - if (vp->v_mount != tdvp->v_mount) { + ncp = ap->a_ncp; /* locked namecache node */ + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return (error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return (EROFS); + } + if (vp->v_mount != dvp->v_mount) { + vput(dvp); return (EXDEV); } @@ -1872,64 +2029,92 @@ * doesn't get "out of sync" with the server. * XXX There should be a better way! */ - VOP_FSYNC(vp, MNT_WAIT, cnp->cn_td); + VOP_FSYNC(vp, MNT_WAIT, td); v3 = NFS_ISV3(vp); nfsstats.rpccnt[NFSPROC_LINK]++; nfsm_reqhead(vp, NFSPROC_LINK, - NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); + NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen)); nfsm_fhtom(vp, v3); - nfsm_fhtom(tdvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(vp, NFSPROC_LINK, cnp->cn_td, cnp->cn_cred); + nfsm_fhtom(dvp, v3); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); + nfsm_request(vp, NFSPROC_LINK, td, cred); if (v3) { nfsm_postop_attr(vp, attrflag, NFS_LATTR_NOSHRINK); - nfsm_wcc_data(tdvp, wccflag); + nfsm_wcc_data(dvp, wccflag); } m_freem(mrep); nfsmout: - VTONFS(tdvp)->n_flag |= NLMODIFIED; + VTONFS(dvp)->n_flag |= NLMODIFIED; if (!attrflag) VTONFS(vp)->n_attrstamp = 0; if (!wccflag) - VTONFS(tdvp)->n_attrstamp = 0; + VTONFS(dvp)->n_attrstamp = 0; /* * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. */ - if (error == EEXIST) + if (error == EEXIST && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM) error = 0; + if (error == 0) { + cache_setunresolved(ncp); + cache_setvp(ncp, vp); + } + vput(dvp); return (error); } /* + * nfs_nsymlink { struct namecache *a_ncp, + * struct vnode **a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap, + * char *a_target } + * * nfs symbolic link create call * - * nfs_symlink(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap, - * char *a_target) + * The passed ncp is locked and represents the symlink to create, while + * a_target represents the target of the symlink. On success, the vnode of + * the new symlink is returned in a_vpp; NULL on failure. */ static int -nfs_symlink(struct vop_old_symlink_args *ap) +nfs_nsymlink(struct vop_nsymlink_args *ap) { - struct vnode *dvp = ap->a_dvp; + struct thread *td = curthread; + struct namecache *ncp; + struct vnode *dvp; + struct ucred *cred = ap->a_cred; struct vattr *vap = ap->a_vap; - struct componentname *cnp = ap->a_cnp; struct nfsv2_sattr *sp; + int slen, wccflag = NFSV3_WCCRATTR, gotvp = 0; + struct vnode *newvp = NULL; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; u_int32_t *tl; - caddr_t cp; int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - struct vnode *newvp = (struct vnode *)0; - int v3 = NFS_ISV3(dvp); + int error; /* set by nfsm_*, which may jump to nfsmout: */ + *ap->a_vpp = NULL; + ncp = ap->a_ncp; /* locked namecache node */ + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return(error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return(EROFS); + } + + v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_SYMLINK]++; slen = strlen(ap->a_target); nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED + - nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); + nfsm_rndup(ncp->nc_nlen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); if (v3) { nfsm_v3attrbuild(vap, FALSE); } @@ -1951,7 +2136,7 @@ * a file handle that can be converted into newvp without having * to do an extra lookup rpc. */ - nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_td, cnp->cn_cred); + nfsm_request(dvp, NFSPROC_SYMLINK, td, cred); if (v3) { if (error == 0) nfsm_mtofh(dvp, newvp, v3, gotvp); @@ -1969,7 +2154,7 @@ * If we get an EEXIST error, silently convert it to no-error * in case of an NFS retry. */ - if (error == EEXIST) + if (error == EEXIST && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM) error = 0; /* @@ -1981,58 +2166,81 @@ if (error == 0 && newvp == NULL) { struct nfsnode *np = NULL; - error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, - cnp->cn_cred, cnp->cn_td, &np); - if (!error) + error = nfs_lookitup(dvp, ncp->nc_name, ncp->nc_nlen, + cred, td, &np); + if (error == 0) newvp = NFSTOV(np); } if (error) { if (newvp) vput(newvp); } else { - *ap->a_vpp = newvp; + cache_setunresolved(ncp); + cache_setvp(ncp, newvp); + *ap->a_vpp = newvp; /* referenced locked vnode */ } VTONFS(dvp)->n_flag |= NLMODIFIED; if (!wccflag) VTONFS(dvp)->n_attrstamp = 0; + vput(dvp); return (error); } /* - * nfs make dir call + * nfs_nmkdir { struct namecache *a_ncp, + * struct vnode **a_vpp, + * struct ucred *a_cred, + * struct vattr *a_vap } * - * nfs_mkdir(struct vnode *a_dvp, struct vnode **a_vpp, - * struct componentname *a_cnp, struct vattr *a_vap) + * nfs make dir call */ static int -nfs_mkdir(struct vop_old_mkdir_args *ap) +nfs_nmkdir(struct vop_nmkdir_args *ap) { - struct vnode *dvp = ap->a_dvp; + struct thread *td = curthread; + struct namecache *ncp; + struct vnode *dvp; + struct ucred *cred = ap->a_cred; struct vattr *vap = ap->a_vap; - struct componentname *cnp = ap->a_cnp; struct nfsv2_sattr *sp; - u_int32_t *tl; - caddr_t cp; - int32_t t1, t2; int len; - struct nfsnode *np = (struct nfsnode *)0; - struct vnode *newvp = (struct vnode *)0; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - int gotvp = 0; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; + struct nfsnode *np = NULL; + struct vnode *newvp = NULL; + int gotvp = 0, wccflag = NFSV3_WCCRATTR; struct vattr vattr; - int v3 = NFS_ISV3(dvp); + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; + u_int32_t *tl; + int32_t t1, t2; + int error; /* set by nfsm_*, which may jump to nfsmout: */ + + *ap->a_vpp = NULL; + ncp = ap->a_ncp; /* locked namecache node */ - if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_td)) != 0) { + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return(error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return(EROFS); + } + + if ((error = VOP_GETATTR(dvp, &vattr, td)) != 0) { + vput(dvp); return (error); } - len = cnp->cn_namelen; + + len = ncp->nc_nlen; + v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_MKDIR]++; nfsm_reqhead(dvp, NFSPROC_MKDIR, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); + nfsm_strtom(ncp->nc_name, len, NFS_MAXNAMLEN); if (v3) { nfsm_v3attrbuild(vap, FALSE); } else { @@ -2044,8 +2252,8 @@ txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); } - nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_td, cnp->cn_cred); - if (!error) + nfsm_request(dvp, NFSPROC_MKDIR, td, cred); + if (error == 0) nfsm_mtofh(dvp, newvp, v3, gotvp); if (v3) nfsm_wcc_data(dvp, wccflag); @@ -2058,14 +2266,15 @@ * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry * if we can succeed in looking up the directory. */ - if (error == EEXIST || (!error && !gotvp)) { + if (error == EEXIST && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM) + error = 0; + if (error == 0 && gotvp == 0) { if (newvp) { - vrele(newvp); - newvp = (struct vnode *)0; + vput(newvp); + newvp = NULL; } - error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred, - cnp->cn_td, &np); - if (!error) { + error = nfs_lookitup(dvp, ncp->nc_name, len, cred, td, &np); + if (error == 0) { newvp = NFSTOV(np); if (newvp->v_type != VDIR) error = EEXIST; @@ -2073,40 +2282,60 @@ } if (error) { if (newvp) - vrele(newvp); - } else - *ap->a_vpp = newvp; + vput(newvp); + } else { + cache_setunresolved(ncp); + cache_setvp(ncp, newvp); + *ap->a_vpp = newvp; /* referenced locked vnode */ + } + vput(dvp); return (error); } /* - * nfs remove directory call + * nfs_nrmdir { struct namecache *a_ncp, + * struct ucred *a_cred } * - * nfs_rmdir(struct vnode *a_dvp, struct vnode *a_vp, - * struct componentname *a_cnp) + * nfs remove directory call */ static int -nfs_rmdir(struct vop_old_rmdir_args *ap) +nfs_nrmdir(struct vop_nrmdir_args *ap) { - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; + struct thread *td = curthread; + struct namecache *ncp; + struct vnode *dvp; + struct ucred *cred = ap->a_cred; + int wccflag = NFSV3_WCCRATTR; + int v3; + /******NFSM MACROS********/ + struct mbuf *mb, *mrep, *mreq, *mb2, *md; + caddr_t bpos, dpos, cp, cp2; u_int32_t *tl; - caddr_t cp; int32_t t1, t2; - caddr_t bpos, dpos, cp2; - int error = 0, wccflag = NFSV3_WCCRATTR; - struct mbuf *mreq, *mrep, *md, *mb, *mb2; - int v3 = NFS_ISV3(dvp); + int error; /* set by nfsm_*, which may jump to nfsmout: */ - if (dvp == vp) - return (EINVAL); + ncp = ap->a_ncp; /* locked namecache node */ + + KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0); + + KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp); + dvp = ncp->nc_parent->nc_vp; + + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) + return (error); + + if (dvp->v_mount->mnt_flag & MNT_RDONLY) { + vput(dvp); + return (EROFS); + } + + v3 = NFS_ISV3(dvp); nfsstats.rpccnt[NFSPROC_RMDIR]++; nfsm_reqhead(dvp, NFSPROC_RMDIR, - NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); + NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen)); nfsm_fhtom(dvp, v3); - nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); - nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_td, cnp->cn_cred); + nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN); + nfsm_request(dvp, NFSPROC_RMDIR, td, cred); if (v3) nfsm_wcc_data(dvp, wccflag); m_freem(mrep); @@ -2117,8 +2346,11 @@ /* * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. */ - if (error == ENOENT) + if (error == ENOENT && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM) error = 0; + if (error == 0) + cache_inval(ncp, CINV_DESTROY); + vput(dvp); return (error); } @@ -2659,52 +2891,53 @@ * nfs_rename() completes, but... */ static int -nfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) +nfs_sillyrename(struct namecache *ncp, struct ucred *cred) { - struct sillyrename *sp; + struct thread *td = curthread; + struct nlcomponent snlc; + struct namecache *sncp; + struct vnode *vp, *dvp; struct nfsnode *np; + struct sillyrename *sp; + char sname[20]; int error; - /* - * We previously purged dvp instead of vp. I don't know why, it - * completely destroys performance. We can't do it anyway with the - * new VFS API since we would be breaking the namecache topology. - */ - cache_purge(vp); /* XXX */ - np = VTONFS(vp); + vp = ncp->nc_vp; #ifndef DIAGNOSTIC if (vp->v_type == VDIR) panic("nfs: sillyrename dir"); #endif - MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), - M_NFSREQ, M_WAITOK); - sp->s_cred = crdup(cnp->cn_cred); - sp->s_dvp = dvp; - vref(dvp); /* Fudge together a funny name */ - sp->s_namlen = sprintf(sp->s_name, ".nfsA%08x4.4", (int)cnp->cn_td); + snlc.nlc_namelen = sprintf(sname, ".nfsA%08x4.4", (int)td); + snlc.nlc_nameptr = sname; + for (;;) { + sncp = cache_nlookup(ncp->nc_parent, &snlc); + error = cache_resolve(sncp, cred); + if (error == ENOENT) + break; + cache_put(sncp); + if (++sname[4] > 'z') + return (EINVAL); /* XXX remove the file instead? */ + } - /* Try lookitups until we get one that isn't there */ - while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, - cnp->cn_td, (struct nfsnode **)0) == 0) { - sp->s_name[4]++; - if (sp->s_name[4] > 'z') { - error = EINVAL; - goto bad; + error = nfs_renamerpc(ncp, sncp, cred); + if (error == 0) { + dvp = ncp->nc_parent->nc_vp; /* locked directory vnode */ + np = VTONFS(vp); + + error = nfs_lookitup(dvp, sncp->nc_name, sncp->nc_nlen, cred, + td, &np); + if (error == 0) { + sp = &(VTONFS(vp)->n_sillyrename); + sp->s_ncp = sncp; + sp->s_cred = crdup(cred); + cache_unlock(sncp); + return (error); } } - error = nfs_renameit(dvp, cnp, sp); - if (error) - goto bad; - error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, - cnp->cn_td, &np); - np->n_sillyrename = sp; - return (0); -bad: - vrele(sp->s_dvp); - crfree(sp->s_cred); - free((caddr_t)sp, M_NFSREQ); + cache_setunresolved(sncp); + cache_put(sncp); return (error); } diff -ur nfs.orig/nfsnode.h nfs/nfsnode.h --- nfs.orig/nfsnode.h 2006-04-03 12:20:15.000000000 -0500 +++ nfs/nfsnode.h 2006-04-03 13:18:49.000000000 -0500 @@ -53,12 +53,11 @@ * can be removed by nfs_inactive() */ struct sillyrename { - struct ucred *s_cred; - struct vnode *s_dvp; - long s_namlen; - char s_name[20]; + struct namecache *s_ncp; + struct ucred *s_cred; }; + /* * Entries of directories in the buffer cache. */ @@ -134,7 +133,7 @@ off_t nd_direof; /* Dir. EOF offset cache */ } n_un2; union { - struct sillyrename *nf_silly; /* Ptr to silly rename struct */ + struct sillyrename nf_silly; /* silly rename struct */ LIST_HEAD(, nfsdmap) nd_cook; /* cookies */ } n_un3; short n_fhsize; /* size in bytes, of fh */ @@ -232,7 +231,7 @@ int nfs_flush (struct vnode *, int, struct thread *, int); /* other stuff */ -int nfs_removeit (struct sillyrename *); +int nfs_removerpc (struct namecache *ncp, struct ucred *cred); int nfs_nget (struct mount *,nfsfh_t *,int,struct nfsnode **); nfsuint64 *nfs_getcookie (struct nfsnode *, off_t, int); void nfs_invaldir (struct vnode *);