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