1 1.126 hannken /* $NetBSD: nfs_node.c,v 1.126 2020/05/01 08:43:00 hannken Exp $ */ 2 1.12 cgd 3 1.1 cgd /* 4 1.9 mycroft * Copyright (c) 1989, 1993 5 1.9 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Rick Macklem at The University of Guelph. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.70 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd * 34 1.16 fvdl * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95 35 1.1 cgd */ 36 1.47 lukem 37 1.47 lukem #include <sys/cdefs.h> 38 1.126 hannken __KERNEL_RCSID(0, "$NetBSD: nfs_node.c,v 1.126 2020/05/01 08:43:00 hannken Exp $"); 39 1.1 cgd 40 1.107 ad #ifdef _KERNEL_OPT 41 1.35 bjh21 #include "opt_nfs.h" 42 1.107 ad #endif 43 1.16 fvdl 44 1.4 mycroft #include <sys/param.h> 45 1.4 mycroft #include <sys/systm.h> 46 1.4 mycroft #include <sys/proc.h> 47 1.4 mycroft #include <sys/mount.h> 48 1.4 mycroft #include <sys/namei.h> 49 1.4 mycroft #include <sys/vnode.h> 50 1.4 mycroft #include <sys/kernel.h> 51 1.28 thorpej #include <sys/pool.h> 52 1.22 fvdl #include <sys/lock.h> 53 1.48 lukem #include <sys/hash.h> 54 1.84 elad #include <sys/kauth.h> 55 1.1 cgd 56 1.9 mycroft #include <nfs/rpcv2.h> 57 1.16 fvdl #include <nfs/nfsproto.h> 58 1.4 mycroft #include <nfs/nfs.h> 59 1.4 mycroft #include <nfs/nfsnode.h> 60 1.4 mycroft #include <nfs/nfsmount.h> 61 1.15 christos #include <nfs/nfs_var.h> 62 1.1 cgd 63 1.104 pooka struct pool nfs_node_pool; 64 1.104 pooka struct pool nfs_vattr_pool; 65 1.108 ad static struct workqueue *nfs_sillyworkq; 66 1.28 thorpej 67 1.108 ad static void nfs_gop_size(struct vnode *, off_t, off_t *, int); 68 1.108 ad static int nfs_gop_alloc(struct vnode *, off_t, off_t, int, kauth_cred_t); 69 1.108 ad static int nfs_gop_write(struct vnode *, struct vm_page **, int, int); 70 1.108 ad static void nfs_sillyworker(struct work *, void *); 71 1.46 chs 72 1.80 yamt static const struct genfs_ops nfs_genfsops = { 73 1.80 yamt .gop_size = nfs_gop_size, 74 1.80 yamt .gop_alloc = nfs_gop_alloc, 75 1.80 yamt .gop_write = nfs_gop_write, 76 1.123 chs .gop_putrange = genfs_gop_putrange, 77 1.46 chs }; 78 1.46 chs 79 1.1 cgd /* 80 1.105 matt * Reinitialize inode hash table. 81 1.1 cgd */ 82 1.15 christos void 83 1.110 cegger nfs_node_init(void) 84 1.1 cgd { 85 1.108 ad 86 1.104 pooka pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, 0, 0, "nfsnodepl", 87 1.104 pooka &pool_allocator_nointr, IPL_NONE); 88 1.104 pooka pool_init(&nfs_vattr_pool, sizeof(struct vattr), 0, 0, 0, "nfsvapl", 89 1.104 pooka &pool_allocator_nointr, IPL_NONE); 90 1.108 ad if (workqueue_create(&nfs_sillyworkq, "nfssilly", nfs_sillyworker, 91 1.108 ad NULL, PRI_NONE, IPL_NONE, 0) != 0) { 92 1.108 ad panic("nfs_node_init"); 93 1.108 ad } 94 1.31 jdolecek } 95 1.31 jdolecek 96 1.31 jdolecek /* 97 1.105 matt * Free resources previously allocated in nfs_node_reinit(). 98 1.45 chs */ 99 1.105 matt void 100 1.110 cegger nfs_node_done(void) 101 1.105 matt { 102 1.108 ad 103 1.105 matt pool_destroy(&nfs_node_pool); 104 1.105 matt pool_destroy(&nfs_vattr_pool); 105 1.108 ad workqueue_destroy(nfs_sillyworkq); 106 1.105 matt } 107 1.105 matt 108 1.1 cgd /* 109 1.118 hannken * Initialize this vnode / nfs node pair. 110 1.118 hannken * Caller assures no other thread will try to load this node. 111 1.1 cgd */ 112 1.15 christos int 113 1.118 hannken nfs_loadvnode(struct mount *mp, struct vnode *vp, 114 1.118 hannken const void *key, size_t key_len, const void **new_key) 115 1.1 cgd { 116 1.118 hannken int fhsize = key_len; 117 1.118 hannken const nfsfh_t *fhp = key; 118 1.105 matt struct nfsnode *np; 119 1.1 cgd 120 1.118 hannken /* Aloocate and initialize the nfsnode. */ 121 1.28 thorpej np = pool_get(&nfs_node_pool, PR_WAITOK); 122 1.38 chs memset(np, 0, sizeof *np); 123 1.16 fvdl if (fhsize > NFS_SMALLFH) { 124 1.98 yamt np->n_fhp = kmem_alloc(fhsize, KM_SLEEP); 125 1.16 fvdl } else 126 1.16 fvdl np->n_fhp = &np->n_fh; 127 1.118 hannken vp->v_tag = VT_NFS; 128 1.118 hannken vp->v_type = VNON; 129 1.118 hannken vp->v_op = nfsv2_vnodeop_p; 130 1.118 hannken vp->v_data = np; 131 1.38 chs memcpy(np->n_fhp, fhp, fhsize); 132 1.16 fvdl np->n_fhsize = fhsize; 133 1.30 fvdl np->n_accstamp = -1; 134 1.28 thorpej np->n_vattr = pool_get(&nfs_vattr_pool, PR_WAITOK); 135 1.118 hannken np->n_vnode = vp; 136 1.71 fvdl 137 1.118 hannken /* Initialize genfs node. */ 138 1.100 ad genfs_node_init(vp, &nfs_genfsops); 139 1.71 fvdl /* 140 1.124 msaitoh * Initialize read/write creds to useful values. VOP_OPEN will 141 1.71 fvdl * overwrite these. 142 1.71 fvdl */ 143 1.85 ad np->n_rcred = curlwp->l_cred; 144 1.84 elad kauth_cred_hold(np->n_rcred); 145 1.85 ad np->n_wcred = curlwp->l_cred; 146 1.84 elad kauth_cred_hold(np->n_wcred); 147 1.74 yamt NFS_INVALIDATE_ATTRCACHE(np); 148 1.74 yamt uvm_vnp_setsize(vp, 0); 149 1.118 hannken *new_key = np->n_fhp; 150 1.118 hannken return 0; 151 1.118 hannken } 152 1.118 hannken 153 1.118 hannken /* 154 1.118 hannken * Look up a vnode/nfsnode by file handle. 155 1.118 hannken * Callers must check for mount points!! 156 1.118 hannken * In all cases, a pointer to a 157 1.118 hannken * nfsnode structure is returned. 158 1.118 hannken */ 159 1.118 hannken int 160 1.118 hannken nfs_nget1(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, 161 1.118 hannken int lkflags) 162 1.118 hannken { 163 1.118 hannken int error; 164 1.118 hannken struct vnode *vp; 165 1.100 ad 166 1.118 hannken error = vcache_get(mntp, fhp, fhsize, &vp); 167 1.118 hannken if (error) 168 1.118 hannken return error; 169 1.118 hannken error = vn_lock(vp, LK_EXCLUSIVE | lkflags); 170 1.118 hannken if (error) { 171 1.118 hannken vrele(vp); 172 1.118 hannken return error; 173 1.118 hannken } 174 1.118 hannken *npp = VTONFS(vp); 175 1.118 hannken return 0; 176 1.1 cgd } 177 1.1 cgd 178 1.15 christos int 179 1.109 dsl nfs_inactive(void *v) 180 1.15 christos { 181 1.120 riastrad struct vop_inactive_v2_args /* { 182 1.9 mycroft struct vnode *a_vp; 183 1.97 ad bool *a_recycle; 184 1.15 christos } */ *ap = v; 185 1.33 augustss struct nfsnode *np; 186 1.33 augustss struct sillyrename *sp; 187 1.40 fvdl struct vnode *vp = ap->a_vp; 188 1.1 cgd 189 1.126 hannken /* If we have a delayed truncation, do it now. */ 190 1.126 hannken nfs_delayedtruncate(vp); 191 1.126 hannken 192 1.40 fvdl np = VTONFS(vp); 193 1.40 fvdl if (vp->v_type != VDIR) { 194 1.16 fvdl sp = np->n_sillyrename; 195 1.18 fvdl np->n_sillyrename = (struct sillyrename *)0; 196 1.18 fvdl } else 197 1.44 fvdl sp = NULL; 198 1.44 fvdl if (sp != NULL) 199 1.97 ad nfs_vinvalbuf(vp, 0, sp->s_cred, curlwp, 1); 200 1.97 ad *ap->a_recycle = (np->n_flag & NREMOVED) != 0; 201 1.94 yamt np->n_flag &= 202 1.94 yamt (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NEOFVALID | NTRUNCDELAYED); 203 1.76 yamt 204 1.76 yamt if (vp->v_type == VDIR && np->n_dircache) 205 1.78 yamt nfs_invaldircache(vp, 206 1.78 yamt NFS_INVALDIRCACHE_FORCE | NFS_INVALDIRCACHE_KEEPEOF); 207 1.76 yamt 208 1.44 fvdl if (sp != NULL) { 209 1.108 ad workqueue_enqueue(nfs_sillyworkq, &sp->s_work, NULL); 210 1.1 cgd } 211 1.59 fvdl 212 1.1 cgd return (0); 213 1.1 cgd } 214 1.1 cgd 215 1.1 cgd /* 216 1.1 cgd * Reclaim an nfsnode so that it can be used for other purposes. 217 1.1 cgd */ 218 1.15 christos int 219 1.109 dsl nfs_reclaim(void *v) 220 1.15 christos { 221 1.121 riastrad struct vop_reclaim_v2_args /* { 222 1.9 mycroft struct vnode *a_vp; 223 1.15 christos } */ *ap = v; 224 1.33 augustss struct vnode *vp = ap->a_vp; 225 1.33 augustss struct nfsnode *np = VTONFS(vp); 226 1.1 cgd 227 1.121 riastrad VOP_UNLOCK(vp); 228 1.121 riastrad 229 1.16 fvdl /* 230 1.16 fvdl * Free up any directory cookie structures and 231 1.16 fvdl * large file handle structures that might be associated with 232 1.16 fvdl * this nfs node. 233 1.16 fvdl */ 234 1.103 tron if (vp->v_type == VDIR && np->n_dircache != NULL) { 235 1.103 tron nfs_invaldircache(vp, NFS_INVALDIRCACHE_FORCE); 236 1.102 ad hashdone(np->n_dircache, HASH_LIST, nfsdirhashmask); 237 1.103 tron } 238 1.65 yamt KASSERT(np->n_dirgens == NULL); 239 1.59 fvdl 240 1.59 fvdl if (np->n_fhsize > NFS_SMALLFH) 241 1.98 yamt kmem_free(np->n_fhp, np->n_fhsize); 242 1.16 fvdl 243 1.28 thorpej pool_put(&nfs_vattr_pool, np->n_vattr); 244 1.59 fvdl if (np->n_rcred) 245 1.84 elad kauth_cred_free(np->n_rcred); 246 1.59 fvdl 247 1.59 fvdl if (np->n_wcred) 248 1.84 elad kauth_cred_free(np->n_wcred); 249 1.59 fvdl 250 1.90 yamt if (vp->v_type == VREG) { 251 1.90 yamt mutex_destroy(&np->n_commitlock); 252 1.90 yamt } 253 1.91 ad genfs_node_destroy(vp); 254 1.90 yamt pool_put(&nfs_node_pool, np); 255 1.38 chs vp->v_data = NULL; 256 1.1 cgd return (0); 257 1.46 chs } 258 1.46 chs 259 1.46 chs void 260 1.87 yamt nfs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) 261 1.46 chs { 262 1.83 yamt 263 1.46 chs *eobp = MAX(size, vp->v_size); 264 1.46 chs } 265 1.46 chs 266 1.46 chs int 267 1.87 yamt nfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags, 268 1.87 yamt kauth_cred_t cred) 269 1.46 chs { 270 1.87 yamt 271 1.46 chs return 0; 272 1.53 chs } 273 1.53 chs 274 1.53 chs int 275 1.53 chs nfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags) 276 1.53 chs { 277 1.53 chs int i; 278 1.53 chs 279 1.125 ad rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 280 1.53 chs for (i = 0; i < npages; i++) { 281 1.53 chs pmap_page_protect(pgs[i], VM_PROT_READ); 282 1.53 chs } 283 1.125 ad rw_exit(vp->v_uobj.vmobjlock); 284 1.116 rmind 285 1.53 chs return genfs_gop_write(vp, pgs, npages, flags); 286 1.1 cgd } 287 1.108 ad 288 1.108 ad /* 289 1.108 ad * Remove a silly file that was rename'd earlier 290 1.108 ad */ 291 1.108 ad static void 292 1.108 ad nfs_sillyworker(struct work *work, void *arg) 293 1.108 ad { 294 1.108 ad struct sillyrename *sp; 295 1.108 ad int error; 296 1.108 ad 297 1.108 ad sp = (struct sillyrename *)work; 298 1.108 ad error = vn_lock(sp->s_dvp, LK_EXCLUSIVE); 299 1.108 ad if (error || sp->s_dvp->v_data == NULL) { 300 1.108 ad /* XXX should recover */ 301 1.108 ad printf("%s: vp=%p error=%d\n", __func__, sp->s_dvp, error); 302 1.108 ad if (error == 0) { 303 1.108 ad vput(sp->s_dvp); 304 1.108 ad } else { 305 1.108 ad vrele(sp->s_dvp); 306 1.108 ad } 307 1.108 ad } else { 308 1.108 ad nfs_removeit(sp); 309 1.108 ad vput(sp->s_dvp); 310 1.108 ad } 311 1.108 ad kauth_cred_free(sp->s_cred); 312 1.108 ad kmem_free(sp, sizeof(*sp)); 313 1.108 ad } 314