1 1.3 pgoyette /* $NetBSD: nfs_clnode.c,v 1.3 2016/12/13 22:17:33 pgoyette Exp $ */ 2 1.1 dholland /*- 3 1.1 dholland * Copyright (c) 1989, 1993 4 1.1 dholland * The Regents of the University of California. All rights reserved. 5 1.1 dholland * 6 1.1 dholland * This code is derived from software contributed to Berkeley by 7 1.1 dholland * Rick Macklem at The University of Guelph. 8 1.1 dholland * 9 1.1 dholland * Redistribution and use in source and binary forms, with or without 10 1.1 dholland * modification, are permitted provided that the following conditions 11 1.1 dholland * are met: 12 1.1 dholland * 1. Redistributions of source code must retain the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer. 14 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer in the 16 1.1 dholland * documentation and/or other materials provided with the distribution. 17 1.1 dholland * 4. Neither the name of the University nor the names of its contributors 18 1.1 dholland * may be used to endorse or promote products derived from this software 19 1.1 dholland * without specific prior written permission. 20 1.1 dholland * 21 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 dholland * SUCH DAMAGE. 32 1.1 dholland * 33 1.1 dholland * from nfs_node.c 8.6 (Berkeley) 5/22/95 34 1.1 dholland */ 35 1.1 dholland 36 1.1 dholland #include <sys/cdefs.h> 37 1.2 pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clnode.c 302210 2016-06-26 14:18:28Z kib "); */ 38 1.3 pgoyette __RCSID("$NetBSD: nfs_clnode.c,v 1.3 2016/12/13 22:17:33 pgoyette Exp $"); 39 1.1 dholland 40 1.1 dholland #include <sys/param.h> 41 1.1 dholland #include <sys/systm.h> 42 1.1 dholland #include <sys/fcntl.h> 43 1.1 dholland #include <sys/lock.h> 44 1.1 dholland #include <sys/malloc.h> 45 1.1 dholland #include <sys/mount.h> 46 1.1 dholland #include <sys/namei.h> 47 1.1 dholland #include <sys/proc.h> 48 1.1 dholland #include <sys/socket.h> 49 1.1 dholland #include <sys/sysctl.h> 50 1.1 dholland #include <sys/taskqueue.h> 51 1.1 dholland #include <sys/vnode.h> 52 1.1 dholland 53 1.1 dholland #include <vm/uma.h> 54 1.1 dholland 55 1.3 pgoyette #include <fs/nfs/common/nfsport.h> 56 1.3 pgoyette #include <fs/nfs/client/nfsnode.h> 57 1.3 pgoyette #include <fs/nfs/client/nfsmount.h> 58 1.3 pgoyette #include <fs/nfs/client/nfs.h> 59 1.3 pgoyette #include <fs/nfs/client/nfs_kdtrace.h> 60 1.1 dholland 61 1.3 pgoyette #include <fs/nfs/common/nfs_lock.h> 62 1.1 dholland 63 1.1 dholland extern struct vop_vector newnfs_vnodeops; 64 1.1 dholland extern struct buf_ops buf_ops_newnfs; 65 1.1 dholland MALLOC_DECLARE(M_NEWNFSREQ); 66 1.1 dholland 67 1.1 dholland uma_zone_t newnfsnode_zone; 68 1.1 dholland 69 1.2 pgoyette const char nfs_vnode_tag[] = "nfs"; 70 1.2 pgoyette 71 1.2 pgoyette static void nfs_freesillyrename(void *arg); 72 1.1 dholland 73 1.1 dholland void 74 1.1 dholland ncl_nhinit(void) 75 1.1 dholland { 76 1.1 dholland 77 1.1 dholland newnfsnode_zone = uma_zcreate("NCLNODE", sizeof(struct nfsnode), NULL, 78 1.1 dholland NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 79 1.1 dholland } 80 1.1 dholland 81 1.1 dholland void 82 1.1 dholland ncl_nhuninit(void) 83 1.1 dholland { 84 1.1 dholland uma_zdestroy(newnfsnode_zone); 85 1.1 dholland } 86 1.1 dholland 87 1.1 dholland /* 88 1.1 dholland * ONLY USED FOR THE ROOT DIRECTORY. nfscl_nget() does the rest. If this 89 1.1 dholland * function is going to be used to get Regular Files, code must be added 90 1.1 dholland * to fill in the "struct nfsv4node". 91 1.1 dholland * Look up a vnode/nfsnode by file handle. 92 1.1 dholland * Callers must check for mount points!! 93 1.1 dholland * In all cases, a pointer to a 94 1.1 dholland * nfsnode structure is returned. 95 1.1 dholland */ 96 1.1 dholland int 97 1.1 dholland ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp, 98 1.1 dholland int lkflags) 99 1.1 dholland { 100 1.1 dholland struct thread *td = curthread; /* XXX */ 101 1.1 dholland struct nfsnode *np; 102 1.1 dholland struct vnode *vp; 103 1.1 dholland struct vnode *nvp; 104 1.1 dholland int error; 105 1.1 dholland u_int hash; 106 1.1 dholland struct nfsmount *nmp; 107 1.1 dholland struct nfsfh *nfhp; 108 1.1 dholland 109 1.1 dholland nmp = VFSTONFS(mntp); 110 1.1 dholland *npp = NULL; 111 1.1 dholland 112 1.1 dholland hash = fnv_32_buf(fhp, fhsize, FNV1_32_INIT); 113 1.1 dholland 114 1.1 dholland MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize, 115 1.1 dholland M_NFSFH, M_WAITOK); 116 1.1 dholland bcopy(fhp, &nfhp->nfh_fh[0], fhsize); 117 1.1 dholland nfhp->nfh_len = fhsize; 118 1.1 dholland error = vfs_hash_get(mntp, hash, lkflags, 119 1.1 dholland td, &nvp, newnfs_vncmpf, nfhp); 120 1.1 dholland FREE(nfhp, M_NFSFH); 121 1.1 dholland if (error) 122 1.1 dholland return (error); 123 1.1 dholland if (nvp != NULL) { 124 1.1 dholland *npp = VTONFS(nvp); 125 1.1 dholland return (0); 126 1.1 dholland } 127 1.1 dholland np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO); 128 1.1 dholland 129 1.2 pgoyette error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp); 130 1.1 dholland if (error) { 131 1.1 dholland uma_zfree(newnfsnode_zone, np); 132 1.1 dholland return (error); 133 1.1 dholland } 134 1.1 dholland vp = nvp; 135 1.1 dholland KASSERT(vp->v_bufobj.bo_bsize != 0, ("ncl_nget: bo_bsize == 0")); 136 1.1 dholland vp->v_bufobj.bo_ops = &buf_ops_newnfs; 137 1.1 dholland vp->v_data = np; 138 1.1 dholland np->n_vnode = vp; 139 1.1 dholland /* 140 1.1 dholland * Initialize the mutex even if the vnode is going to be a loser. 141 1.1 dholland * This simplifies the logic in reclaim, which can then unconditionally 142 1.1 dholland * destroy the mutex (in the case of the loser, or if hash_insert 143 1.1 dholland * happened to return an error no special casing is needed). 144 1.1 dholland */ 145 1.1 dholland mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK); 146 1.1 dholland /* 147 1.1 dholland * NFS supports recursive and shared locking. 148 1.1 dholland */ 149 1.1 dholland lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); 150 1.1 dholland VN_LOCK_AREC(vp); 151 1.1 dholland VN_LOCK_ASHARE(vp); 152 1.1 dholland /* 153 1.1 dholland * Are we getting the root? If so, make sure the vnode flags 154 1.1 dholland * are correct 155 1.1 dholland */ 156 1.1 dholland if ((fhsize == nmp->nm_fhsize) && 157 1.1 dholland !bcmp(fhp, nmp->nm_fh, fhsize)) { 158 1.1 dholland if (vp->v_type == VNON) 159 1.1 dholland vp->v_type = VDIR; 160 1.1 dholland vp->v_vflag |= VV_ROOT; 161 1.1 dholland } 162 1.1 dholland 163 1.1 dholland MALLOC(np->n_fhp, struct nfsfh *, sizeof (struct nfsfh) + fhsize, 164 1.1 dholland M_NFSFH, M_WAITOK); 165 1.1 dholland bcopy(fhp, np->n_fhp->nfh_fh, fhsize); 166 1.1 dholland np->n_fhp->nfh_len = fhsize; 167 1.1 dholland error = insmntque(vp, mntp); 168 1.1 dholland if (error != 0) { 169 1.1 dholland *npp = NULL; 170 1.1 dholland FREE((caddr_t)np->n_fhp, M_NFSFH); 171 1.1 dholland mtx_destroy(&np->n_mtx); 172 1.1 dholland uma_zfree(newnfsnode_zone, np); 173 1.1 dholland return (error); 174 1.1 dholland } 175 1.1 dholland error = vfs_hash_insert(vp, hash, lkflags, 176 1.1 dholland td, &nvp, newnfs_vncmpf, np->n_fhp); 177 1.1 dholland if (error) 178 1.1 dholland return (error); 179 1.1 dholland if (nvp != NULL) { 180 1.1 dholland *npp = VTONFS(nvp); 181 1.1 dholland /* vfs_hash_insert() vput()'s the losing vnode */ 182 1.1 dholland return (0); 183 1.1 dholland } 184 1.1 dholland *npp = np; 185 1.1 dholland 186 1.1 dholland return (0); 187 1.1 dholland } 188 1.1 dholland 189 1.1 dholland /* 190 1.1 dholland * Do the vrele(sp->s_dvp) as a separate task in order to avoid a 191 1.1 dholland * deadlock because of a LOR when vrele() locks the directory vnode. 192 1.1 dholland */ 193 1.1 dholland static void 194 1.2 pgoyette nfs_freesillyrename(void *arg) 195 1.1 dholland { 196 1.1 dholland struct sillyrename *sp; 197 1.1 dholland 198 1.1 dholland sp = arg; 199 1.1 dholland vrele(sp->s_dvp); 200 1.1 dholland free(sp, M_NEWNFSREQ); 201 1.1 dholland } 202 1.1 dholland 203 1.2 pgoyette static void 204 1.2 pgoyette ncl_releasesillyrename(struct vnode *vp, struct thread *td) 205 1.2 pgoyette { 206 1.2 pgoyette struct nfsnode *np; 207 1.2 pgoyette struct sillyrename *sp; 208 1.2 pgoyette 209 1.2 pgoyette ASSERT_VOP_ELOCKED(vp, "releasesillyrename"); 210 1.2 pgoyette np = VTONFS(vp); 211 1.2 pgoyette mtx_assert(&np->n_mtx, MA_OWNED); 212 1.2 pgoyette if (vp->v_type != VDIR) { 213 1.2 pgoyette sp = np->n_sillyrename; 214 1.2 pgoyette np->n_sillyrename = NULL; 215 1.2 pgoyette } else 216 1.2 pgoyette sp = NULL; 217 1.2 pgoyette if (sp != NULL) { 218 1.2 pgoyette mtx_unlock(&np->n_mtx); 219 1.2 pgoyette (void) ncl_vinvalbuf(vp, 0, td, 1); 220 1.2 pgoyette /* 221 1.2 pgoyette * Remove the silly file that was rename'd earlier 222 1.2 pgoyette */ 223 1.2 pgoyette ncl_removeit(sp, vp); 224 1.2 pgoyette crfree(sp->s_cred); 225 1.2 pgoyette sysmon_task_queue_sched(0, nfs_freesillyrename, sp); 226 1.2 pgoyette mtx_lock(&np->n_mtx); 227 1.2 pgoyette } 228 1.2 pgoyette } 229 1.2 pgoyette 230 1.1 dholland int 231 1.1 dholland ncl_inactive(struct vop_inactive_args *ap) 232 1.1 dholland { 233 1.2 pgoyette struct vnode *vp = ap->a_vp; 234 1.1 dholland struct nfsnode *np; 235 1.1 dholland boolean_t retv; 236 1.1 dholland 237 1.1 dholland if (NFS_ISV4(vp) && vp->v_type == VREG) { 238 1.1 dholland /* 239 1.1 dholland * Since mmap()'d files do I/O after VOP_CLOSE(), the NFSv4 240 1.1 dholland * Close operations are delayed until now. Any dirty 241 1.1 dholland * buffers/pages must be flushed before the close, so that the 242 1.1 dholland * stateid is available for the writes. 243 1.1 dholland */ 244 1.1 dholland if (vp->v_object != NULL) { 245 1.1 dholland VM_OBJECT_WLOCK(vp->v_object); 246 1.1 dholland retv = vm_object_page_clean(vp->v_object, 0, 0, 247 1.1 dholland OBJPC_SYNC); 248 1.1 dholland VM_OBJECT_WUNLOCK(vp->v_object); 249 1.1 dholland } else 250 1.1 dholland retv = TRUE; 251 1.1 dholland if (retv == TRUE) { 252 1.1 dholland (void)ncl_flush(vp, MNT_WAIT, NULL, ap->a_td, 1, 0); 253 1.1 dholland (void)nfsrpc_close(vp, 1, ap->a_td); 254 1.1 dholland } 255 1.1 dholland } 256 1.1 dholland 257 1.2 pgoyette np = VTONFS(vp); 258 1.1 dholland mtx_lock(&np->n_mtx); 259 1.2 pgoyette ncl_releasesillyrename(vp, ap->a_td); 260 1.2 pgoyette 261 1.2 pgoyette /* 262 1.2 pgoyette * NMODIFIED means that there might be dirty/stale buffers 263 1.2 pgoyette * associated with the NFS vnode. None of the other flags are 264 1.2 pgoyette * meaningful after the vnode is unused. 265 1.2 pgoyette */ 266 1.1 dholland np->n_flag &= NMODIFIED; 267 1.1 dholland mtx_unlock(&np->n_mtx); 268 1.1 dholland return (0); 269 1.1 dholland } 270 1.1 dholland 271 1.1 dholland /* 272 1.1 dholland * Reclaim an nfsnode so that it can be used for other purposes. 273 1.1 dholland */ 274 1.1 dholland int 275 1.1 dholland ncl_reclaim(struct vop_reclaim_args *ap) 276 1.1 dholland { 277 1.1 dholland struct vnode *vp = ap->a_vp; 278 1.1 dholland struct nfsnode *np = VTONFS(vp); 279 1.1 dholland struct nfsdmap *dp, *dp2; 280 1.1 dholland 281 1.1 dholland /* 282 1.1 dholland * If the NLM is running, give it a chance to abort pending 283 1.1 dholland * locks. 284 1.1 dholland */ 285 1.1 dholland if (nfs_reclaim_p != NULL) 286 1.1 dholland nfs_reclaim_p(ap); 287 1.1 dholland 288 1.2 pgoyette mtx_lock(&np->n_mtx); 289 1.2 pgoyette ncl_releasesillyrename(vp, ap->a_td); 290 1.2 pgoyette mtx_unlock(&np->n_mtx); 291 1.2 pgoyette 292 1.1 dholland /* 293 1.1 dholland * Destroy the vm object and flush associated pages. 294 1.1 dholland */ 295 1.1 dholland vnode_destroy_vobject(vp); 296 1.1 dholland 297 1.1 dholland if (NFS_ISV4(vp) && vp->v_type == VREG) 298 1.1 dholland /* 299 1.1 dholland * We can now safely close any remaining NFSv4 Opens for 300 1.1 dholland * this file. Most opens will have already been closed by 301 1.1 dholland * ncl_inactive(), but there are cases where it is not 302 1.1 dholland * called, so we need to do it again here. 303 1.1 dholland */ 304 1.1 dholland (void) nfsrpc_close(vp, 1, ap->a_td); 305 1.1 dholland 306 1.1 dholland vfs_hash_remove(vp); 307 1.1 dholland 308 1.1 dholland /* 309 1.1 dholland * Call nfscl_reclaimnode() to save attributes in the delegation, 310 1.1 dholland * as required. 311 1.1 dholland */ 312 1.1 dholland if (vp->v_type == VREG) 313 1.1 dholland nfscl_reclaimnode(vp); 314 1.1 dholland 315 1.1 dholland /* 316 1.1 dholland * Free up any directory cookie structures and 317 1.1 dholland * large file handle structures that might be associated with 318 1.1 dholland * this nfs node. 319 1.1 dholland */ 320 1.1 dholland if (vp->v_type == VDIR) { 321 1.1 dholland dp = LIST_FIRST(&np->n_cookies); 322 1.1 dholland while (dp) { 323 1.1 dholland dp2 = dp; 324 1.1 dholland dp = LIST_NEXT(dp, ndm_list); 325 1.1 dholland FREE((caddr_t)dp2, M_NFSDIROFF); 326 1.1 dholland } 327 1.1 dholland } 328 1.1 dholland if (np->n_writecred != NULL) 329 1.1 dholland crfree(np->n_writecred); 330 1.1 dholland FREE((caddr_t)np->n_fhp, M_NFSFH); 331 1.1 dholland if (np->n_v4 != NULL) 332 1.1 dholland FREE((caddr_t)np->n_v4, M_NFSV4NODE); 333 1.1 dholland mtx_destroy(&np->n_mtx); 334 1.1 dholland uma_zfree(newnfsnode_zone, vp->v_data); 335 1.1 dholland vp->v_data = NULL; 336 1.1 dholland return (0); 337 1.1 dholland } 338 1.1 dholland 339 1.1 dholland /* 340 1.1 dholland * Invalidate both the access and attribute caches for this vnode. 341 1.1 dholland */ 342 1.1 dholland void 343 1.1 dholland ncl_invalcaches(struct vnode *vp) 344 1.1 dholland { 345 1.1 dholland struct nfsnode *np = VTONFS(vp); 346 1.1 dholland int i; 347 1.1 dholland 348 1.1 dholland mtx_lock(&np->n_mtx); 349 1.1 dholland for (i = 0; i < NFS_ACCESSCACHESIZE; i++) 350 1.1 dholland np->n_accesscache[i].stamp = 0; 351 1.1 dholland KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp); 352 1.1 dholland np->n_attrstamp = 0; 353 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 354 1.1 dholland mtx_unlock(&np->n_mtx); 355 1.1 dholland } 356