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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
| 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 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)nfs_node.c 8.6 (Berkeley) 5/22/95
|
37 * $FreeBSD: head/sys/nfsclient/nfs_node.c 83366 2001-09-12 08:38:13Z julian $
| |
38 */ 39
| 37 */ 38
|
| 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_node.c 83651 2001-09-18 23:32:09Z peter $");
|
40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/fnv_hash.h> 44#include <sys/lock.h> 45#include <sys/malloc.h> 46#include <sys/mount.h> 47#include <sys/namei.h> 48#include <sys/proc.h> 49#include <sys/socket.h> 50#include <sys/sysctl.h> 51#include <sys/vnode.h> 52 53#include <vm/vm_zone.h> 54 55#include <nfs/rpcv2.h> 56#include <nfs/nfsproto.h>
| 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/fnv_hash.h> 45#include <sys/lock.h> 46#include <sys/malloc.h> 47#include <sys/mount.h> 48#include <sys/namei.h> 49#include <sys/proc.h> 50#include <sys/socket.h> 51#include <sys/sysctl.h> 52#include <sys/vnode.h> 53 54#include <vm/vm_zone.h> 55 56#include <nfs/rpcv2.h> 57#include <nfs/nfsproto.h>
|
57#include 58#include 59#include
| 58#include <nfsclient/nfs.h> 59#include <nfsclient/nfsnode.h> 60#include <nfsclient/nfsmount.h>
|
60 61static vm_zone_t nfsnode_zone; 62static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; 63static u_long nfsnodehash;
| 61 62static vm_zone_t nfsnode_zone; 63static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl; 64static u_long nfsnodehash;
|
| 65static int nfs_node_hash_lock;
|
64 65#define TRUE 1 66#define FALSE 0 67
| 66 67#define TRUE 1 68#define FALSE 0 69
|
| 70SYSCTL_DECL(_debug_hashstat); 71
|
68/* 69 * Grab an atomic snapshot of the nfsnode hash chain lengths 70 */
| 72/* 73 * Grab an atomic snapshot of the nfsnode hash chain lengths 74 */
|
71SYSCTL_DECL(_debug_hashstat);
| |
72static int 73sysctl_debug_hashstat_rawnfsnode(SYSCTL_HANDLER_ARGS) 74{ 75 int error; 76 struct nfsnodehashhead *nnpp; 77 struct nfsnode *nnp; 78 int n_nfsnode; 79 int count; 80 81 n_nfsnode = nfsnodehash + 1; /* nfsnodehash = max index, not count */ 82 if (!req->oldptr) 83 return SYSCTL_OUT(req, 0, n_nfsnode * sizeof(int)); 84 85 /* Scan hash tables for applicable entries */ 86 for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) { 87 count = 0; 88 LIST_FOREACH(nnp, nnpp, n_hash) { 89 count++; 90 } 91 error = SYSCTL_OUT(req, (caddr_t)&count, sizeof(count)); 92 if (error) 93 return (error); 94 } 95 return (0); 96}
| 75static int 76sysctl_debug_hashstat_rawnfsnode(SYSCTL_HANDLER_ARGS) 77{ 78 int error; 79 struct nfsnodehashhead *nnpp; 80 struct nfsnode *nnp; 81 int n_nfsnode; 82 int count; 83 84 n_nfsnode = nfsnodehash + 1; /* nfsnodehash = max index, not count */ 85 if (!req->oldptr) 86 return SYSCTL_OUT(req, 0, n_nfsnode * sizeof(int)); 87 88 /* Scan hash tables for applicable entries */ 89 for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) { 90 count = 0; 91 LIST_FOREACH(nnp, nnpp, n_hash) { 92 count++; 93 } 94 error = SYSCTL_OUT(req, (caddr_t)&count, sizeof(count)); 95 if (error) 96 return (error); 97 } 98 return (0); 99}
|
97SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnfsnode, CTLTYPE_INT|CTLFLAG_RD, 98 0, 0, sysctl_debug_hashstat_rawnfsnode, "S,int", "nfsnode chain lengths");
| 100SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnfsnode, CTLTYPE_INT|CTLFLAG_RD, 0, 0, 101 sysctl_debug_hashstat_rawnfsnode, "S,int", "nfsnode chain lengths");
|
99 100static int 101sysctl_debug_hashstat_nfsnode(SYSCTL_HANDLER_ARGS) 102{ 103 int error; 104 struct nfsnodehashhead *nnpp; 105 struct nfsnode *nnp; 106 int n_nfsnode; 107 int count, maxlength, used, pct; 108 109 if (!req->oldptr) 110 return SYSCTL_OUT(req, 0, 4 * sizeof(int)); 111 112 n_nfsnode = nfsnodehash + 1; /* nfsnodehash = max index, not count */ 113 used = 0; 114 maxlength = 0; 115 116 /* Scan hash tables for applicable entries */ 117 for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) { 118 count = 0; 119 LIST_FOREACH(nnp, nnpp, n_hash) { 120 count++; 121 } 122 if (count) 123 used++; 124 if (maxlength < count) 125 maxlength = count; 126 } 127 n_nfsnode = nfsnodehash + 1; 128 pct = (used * 100 * 100) / n_nfsnode; 129 error = SYSCTL_OUT(req, (caddr_t)&n_nfsnode, sizeof(n_nfsnode)); 130 if (error) 131 return (error); 132 error = SYSCTL_OUT(req, (caddr_t)&used, sizeof(used)); 133 if (error) 134 return (error); 135 error = SYSCTL_OUT(req, (caddr_t)&maxlength, sizeof(maxlength)); 136 if (error) 137 return (error); 138 error = SYSCTL_OUT(req, (caddr_t)&pct, sizeof(pct)); 139 if (error) 140 return (error); 141 return (0); 142} 143SYSCTL_PROC(_debug_hashstat, OID_AUTO, nfsnode, CTLTYPE_INT|CTLFLAG_RD, 144 0, 0, sysctl_debug_hashstat_nfsnode, "I", "nfsnode chain lengths"); 145 146/* 147 * Initialize hash links for nfsnodes 148 * and build nfsnode free list. 149 */ 150void
| 102 103static int 104sysctl_debug_hashstat_nfsnode(SYSCTL_HANDLER_ARGS) 105{ 106 int error; 107 struct nfsnodehashhead *nnpp; 108 struct nfsnode *nnp; 109 int n_nfsnode; 110 int count, maxlength, used, pct; 111 112 if (!req->oldptr) 113 return SYSCTL_OUT(req, 0, 4 * sizeof(int)); 114 115 n_nfsnode = nfsnodehash + 1; /* nfsnodehash = max index, not count */ 116 used = 0; 117 maxlength = 0; 118 119 /* Scan hash tables for applicable entries */ 120 for (nnpp = nfsnodehashtbl; n_nfsnode > 0; n_nfsnode--, nnpp++) { 121 count = 0; 122 LIST_FOREACH(nnp, nnpp, n_hash) { 123 count++; 124 } 125 if (count) 126 used++; 127 if (maxlength < count) 128 maxlength = count; 129 } 130 n_nfsnode = nfsnodehash + 1; 131 pct = (used * 100 * 100) / n_nfsnode; 132 error = SYSCTL_OUT(req, (caddr_t)&n_nfsnode, sizeof(n_nfsnode)); 133 if (error) 134 return (error); 135 error = SYSCTL_OUT(req, (caddr_t)&used, sizeof(used)); 136 if (error) 137 return (error); 138 error = SYSCTL_OUT(req, (caddr_t)&maxlength, sizeof(maxlength)); 139 if (error) 140 return (error); 141 error = SYSCTL_OUT(req, (caddr_t)&pct, sizeof(pct)); 142 if (error) 143 return (error); 144 return (0); 145} 146SYSCTL_PROC(_debug_hashstat, OID_AUTO, nfsnode, CTLTYPE_INT|CTLFLAG_RD, 147 0, 0, sysctl_debug_hashstat_nfsnode, "I", "nfsnode chain lengths"); 148 149/* 150 * Initialize hash links for nfsnodes 151 * and build nfsnode free list. 152 */ 153void
|
151nfs_nhinit()
| 154nfs_nhinit(void)
|
152{
| 155{
|
| 156
|
153 nfsnode_zone = zinit("NFSNODE", sizeof(struct nfsnode), 0, 0, 1); 154 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSHASH, &nfsnodehash); 155} 156 157/* 158 * Look up a vnode/nfsnode by file handle. 159 * Callers must check for mount points!! 160 * In all cases, a pointer to a 161 * nfsnode structure is returned. 162 */
| 157 nfsnode_zone = zinit("NFSNODE", sizeof(struct nfsnode), 0, 0, 1); 158 nfsnodehashtbl = hashinit(desiredvnodes, M_NFSHASH, &nfsnodehash); 159} 160 161/* 162 * Look up a vnode/nfsnode by file handle. 163 * Callers must check for mount points!! 164 * In all cases, a pointer to a 165 * nfsnode structure is returned. 166 */
|
163static int nfs_node_hash_lock; 164
| |
165int
| 167int
|
166nfs_nget(mntp, fhp, fhsize, npp) 167 struct mount *mntp; 168 register nfsfh_t *fhp; 169 int fhsize; 170 struct nfsnode **npp;
| 168nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp)
|
171{ 172 struct thread *td = curthread; /* XXX */ 173 struct nfsnode *np, *np2; 174 struct nfsnodehashhead *nhpp;
| 169{ 170 struct thread *td = curthread; /* XXX */ 171 struct nfsnode *np, *np2; 172 struct nfsnodehashhead *nhpp;
|
175 register struct vnode *vp;
| 173 struct vnode *vp;
|
176 struct vnode *nvp; 177 int error; 178 int rsflags; 179 struct nfsmount *nmp; 180 181 /* 182 * Calculate nfs mount point and figure out whether the rslock should 183 * be interruptable or not. 184 */ 185 nmp = VFSTONFS(mntp); 186 if (nmp->nm_flag & NFSMNT_INT) 187 rsflags = PCATCH; 188 else 189 rsflags = 0; 190 191retry: 192 nhpp = NFSNOHASH(fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT)); 193loop:
| 174 struct vnode *nvp; 175 int error; 176 int rsflags; 177 struct nfsmount *nmp; 178 179 /* 180 * Calculate nfs mount point and figure out whether the rslock should 181 * be interruptable or not. 182 */ 183 nmp = VFSTONFS(mntp); 184 if (nmp->nm_flag & NFSMNT_INT) 185 rsflags = PCATCH; 186 else 187 rsflags = 0; 188 189retry: 190 nhpp = NFSNOHASH(fnv_32_buf(fhp->fh_bytes, fhsize, FNV1_32_INIT)); 191loop:
|
194 for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
| 192 LIST_FOREACH(np, nhpp, n_hash) {
|
195 if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || 196 bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) 197 continue; 198 vp = NFSTOV(np); 199 if (vget(vp, LK_EXCLUSIVE, td)) 200 goto loop; 201 *npp = np; 202 return(0); 203 } 204 /* 205 * Obtain a lock to prevent a race condition if the getnewvnode() 206 * or MALLOC() below happens to block. 207 */ 208 if (nfs_node_hash_lock) { 209 while (nfs_node_hash_lock) { 210 nfs_node_hash_lock = -1; 211 tsleep(&nfs_node_hash_lock, PVM, "nfsngt", 0); 212 } 213 goto loop; 214 } 215 nfs_node_hash_lock = 1; 216 217 /* 218 * Allocate before getnewvnode since doing so afterward 219 * might cause a bogus v_data pointer to get dereferenced 220 * elsewhere if zalloc should block. 221 */ 222 np = zalloc(nfsnode_zone);
| 193 if (mntp != NFSTOV(np)->v_mount || np->n_fhsize != fhsize || 194 bcmp((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize)) 195 continue; 196 vp = NFSTOV(np); 197 if (vget(vp, LK_EXCLUSIVE, td)) 198 goto loop; 199 *npp = np; 200 return(0); 201 } 202 /* 203 * Obtain a lock to prevent a race condition if the getnewvnode() 204 * or MALLOC() below happens to block. 205 */ 206 if (nfs_node_hash_lock) { 207 while (nfs_node_hash_lock) { 208 nfs_node_hash_lock = -1; 209 tsleep(&nfs_node_hash_lock, PVM, "nfsngt", 0); 210 } 211 goto loop; 212 } 213 nfs_node_hash_lock = 1; 214 215 /* 216 * Allocate before getnewvnode since doing so afterward 217 * might cause a bogus v_data pointer to get dereferenced 218 * elsewhere if zalloc should block. 219 */ 220 np = zalloc(nfsnode_zone);
|
223
| 221
|
224 error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); 225 if (error) { 226 if (nfs_node_hash_lock < 0) 227 wakeup(&nfs_node_hash_lock); 228 nfs_node_hash_lock = 0; 229 *npp = 0; 230 zfree(nfsnode_zone, np); 231 return (error); 232 } 233 vp = nvp; 234 bzero((caddr_t)np, sizeof *np); 235 vp->v_data = np; 236 np->n_vnode = vp; 237 /* 238 * Insert the nfsnode in the hash queue for its new file handle 239 */
| 222 error = getnewvnode(VT_NFS, mntp, nfsv2_vnodeop_p, &nvp); 223 if (error) { 224 if (nfs_node_hash_lock < 0) 225 wakeup(&nfs_node_hash_lock); 226 nfs_node_hash_lock = 0; 227 *npp = 0; 228 zfree(nfsnode_zone, np); 229 return (error); 230 } 231 vp = nvp; 232 bzero((caddr_t)np, sizeof *np); 233 vp->v_data = np; 234 np->n_vnode = vp; 235 /* 236 * Insert the nfsnode in the hash queue for its new file handle 237 */
|
240 for (np2 = nhpp->lh_first; np2 != 0; np2 = np2->n_hash.le_next) {
| 238 LIST_FOREACH(np2, nhpp, n_hash) {
|
241 if (mntp != NFSTOV(np2)->v_mount || np2->n_fhsize != fhsize || 242 bcmp((caddr_t)fhp, (caddr_t)np2->n_fhp, fhsize)) 243 continue; 244 vrele(vp); 245 if (nfs_node_hash_lock < 0) 246 wakeup(&nfs_node_hash_lock); 247 nfs_node_hash_lock = 0; 248 zfree(nfsnode_zone, np); 249 goto retry; 250 } 251 LIST_INSERT_HEAD(nhpp, np, n_hash); 252 if (fhsize > NFS_SMALLFH) { 253 MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK); 254 } else 255 np->n_fhp = &np->n_fh; 256 bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); 257 np->n_fhsize = fhsize; 258 lockinit(&np->n_rslock, PVFS | rsflags, "nfrslk", 0, LK_NOPAUSE); 259 lockinit(&vp->v_lock, PVFS, "nfsnlk", 0, LK_NOPAUSE); 260 *npp = np; 261 262 if (nfs_node_hash_lock < 0) 263 wakeup(&nfs_node_hash_lock); 264 nfs_node_hash_lock = 0; 265 266 /* 267 * Lock the new nfsnode. 268 */ 269 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 270 271 return (0); 272} 273 274int
| 239 if (mntp != NFSTOV(np2)->v_mount || np2->n_fhsize != fhsize || 240 bcmp((caddr_t)fhp, (caddr_t)np2->n_fhp, fhsize)) 241 continue; 242 vrele(vp); 243 if (nfs_node_hash_lock < 0) 244 wakeup(&nfs_node_hash_lock); 245 nfs_node_hash_lock = 0; 246 zfree(nfsnode_zone, np); 247 goto retry; 248 } 249 LIST_INSERT_HEAD(nhpp, np, n_hash); 250 if (fhsize > NFS_SMALLFH) { 251 MALLOC(np->n_fhp, nfsfh_t *, fhsize, M_NFSBIGFH, M_WAITOK); 252 } else 253 np->n_fhp = &np->n_fh; 254 bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); 255 np->n_fhsize = fhsize; 256 lockinit(&np->n_rslock, PVFS | rsflags, "nfrslk", 0, LK_NOPAUSE); 257 lockinit(&vp->v_lock, PVFS, "nfsnlk", 0, LK_NOPAUSE); 258 *npp = np; 259 260 if (nfs_node_hash_lock < 0) 261 wakeup(&nfs_node_hash_lock); 262 nfs_node_hash_lock = 0; 263 264 /* 265 * Lock the new nfsnode. 266 */ 267 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 268 269 return (0); 270} 271 272int
|
275nfs_inactive(ap) 276 struct vop_inactive_args /* { 277 struct vnode *a_vp; 278 struct thread *a_td; 279 } */ *ap;
| 273nfs_inactive(struct vop_inactive_args *ap)
|
280{
| 274{
|
281 register struct nfsnode *np; 282 register struct sillyrename *sp;
| 275 struct nfsnode *np; 276 struct sillyrename *sp;
|
283 struct thread *td = curthread; /* XXX */ 284 285 np = VTONFS(ap->a_vp); 286 if (prtactive && ap->a_vp->v_usecount != 0) 287 vprint("nfs_inactive: pushing active", ap->a_vp); 288 if (ap->a_vp->v_type != VDIR) { 289 sp = np->n_sillyrename; 290 np->n_sillyrename = (struct sillyrename *)0; 291 } else 292 sp = (struct sillyrename *)0; 293 if (sp) { 294 /* 295 * We need a reference to keep the vnode from being 296 * recycled by getnewvnode while we do the I/O 297 * associated with discarding the buffers unless we 298 * are being forcibly unmounted in which case we already 299 * have our own reference. 300 */ 301 if (ap->a_vp->v_usecount > 0) 302 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1); 303 else if (vget(ap->a_vp, 0, td)) 304 panic("nfs_inactive: lost vnode"); 305 else { 306 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1); 307 vrele(ap->a_vp); 308 } 309 /* 310 * Remove the silly file that was rename'd earlier 311 */ 312 nfs_removeit(sp); 313 crfree(sp->s_cred); 314 vrele(sp->s_dvp); 315 FREE((caddr_t)sp, M_NFSREQ); 316 }
| 277 struct thread *td = curthread; /* XXX */ 278 279 np = VTONFS(ap->a_vp); 280 if (prtactive && ap->a_vp->v_usecount != 0) 281 vprint("nfs_inactive: pushing active", ap->a_vp); 282 if (ap->a_vp->v_type != VDIR) { 283 sp = np->n_sillyrename; 284 np->n_sillyrename = (struct sillyrename *)0; 285 } else 286 sp = (struct sillyrename *)0; 287 if (sp) { 288 /* 289 * We need a reference to keep the vnode from being 290 * recycled by getnewvnode while we do the I/O 291 * associated with discarding the buffers unless we 292 * are being forcibly unmounted in which case we already 293 * have our own reference. 294 */ 295 if (ap->a_vp->v_usecount > 0) 296 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1); 297 else if (vget(ap->a_vp, 0, td)) 298 panic("nfs_inactive: lost vnode"); 299 else { 300 (void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, td, 1); 301 vrele(ap->a_vp); 302 } 303 /* 304 * Remove the silly file that was rename'd earlier 305 */ 306 nfs_removeit(sp); 307 crfree(sp->s_cred); 308 vrele(sp->s_dvp); 309 FREE((caddr_t)sp, M_NFSREQ); 310 }
|
317 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT | NQNFSEVICTED | 318 NQNFSNONCACHE | NQNFSWRITE);
| 311 np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
|
319 VOP_UNLOCK(ap->a_vp, 0, ap->a_td); 320 return (0); 321} 322 323/* 324 * Reclaim an nfsnode so that it can be used for other purposes. 325 */ 326int
| 312 VOP_UNLOCK(ap->a_vp, 0, ap->a_td); 313 return (0); 314} 315 316/* 317 * Reclaim an nfsnode so that it can be used for other purposes. 318 */ 319int
|
327nfs_reclaim(ap) 328 struct vop_reclaim_args /* { 329 struct vnode *a_vp; 330 } */ *ap;
| 320nfs_reclaim(struct vop_reclaim_args *ap)
|
331{
| 321{
|
332 register struct vnode *vp = ap->a_vp; 333 register struct nfsnode *np = VTONFS(vp); 334 register struct nfsmount *nmp = VFSTONFS(vp->v_mount); 335 register struct nfsdmap *dp, *dp2;
| 322 struct vnode *vp = ap->a_vp; 323 struct nfsnode *np = VTONFS(vp); 324 struct nfsdmap *dp, *dp2;
|
336 337 if (prtactive && vp->v_usecount != 0) 338 vprint("nfs_reclaim: pushing active", vp); 339
| 325 326 if (prtactive && vp->v_usecount != 0) 327 vprint("nfs_reclaim: pushing active", vp); 328
|
340 if (np->n_hash.le_prev != NULL)
| 329 if (np->n_hash.le_prev != NULL) /* XXX beware */
|
341 LIST_REMOVE(np, n_hash); 342 343 /*
| 330 LIST_REMOVE(np, n_hash); 331 332 /*
|
344 * For nqnfs, take it off the timer queue as required. 345 */ 346 if ((nmp->nm_flag & NFSMNT_NQNFS) && TAILQ_NEXT(np, n_timer) != 0) { 347 TAILQ_REMOVE(&nmp->nm_timerhead, np, n_timer); 348 } 349 350 /*
| |
351 * Free up any directory cookie structures and 352 * large file handle structures that might be associated with 353 * this nfs node. 354 */ 355 if (vp->v_type == VDIR) {
| 333 * Free up any directory cookie structures and 334 * large file handle structures that might be associated with 335 * this nfs node. 336 */ 337 if (vp->v_type == VDIR) {
|
356 dp = np->n_cookies.lh_first;
| 338 dp = LIST_FIRST(&np->n_cookies);
|
357 while (dp) { 358 dp2 = dp;
| 339 while (dp) { 340 dp2 = dp;
|
359 dp = dp->ndm_list.le_next;
| 341 dp = LIST_NEXT(dp, ndm_list);
|
360 FREE((caddr_t)dp2, M_NFSDIROFF); 361 } 362 } 363 if (np->n_fhsize > NFS_SMALLFH) { 364 FREE((caddr_t)np->n_fhp, M_NFSBIGFH); 365 } 366 367 lockdestroy(&np->n_rslock); 368 369 cache_purge(vp); 370 zfree(nfsnode_zone, vp->v_data); 371 vp->v_data = (void *)0; 372 return (0); 373} 374 375#if 0 376/* 377 * Lock an nfsnode 378 */ 379int
| 342 FREE((caddr_t)dp2, M_NFSDIROFF); 343 } 344 } 345 if (np->n_fhsize > NFS_SMALLFH) { 346 FREE((caddr_t)np->n_fhp, M_NFSBIGFH); 347 } 348 349 lockdestroy(&np->n_rslock); 350 351 cache_purge(vp); 352 zfree(nfsnode_zone, vp->v_data); 353 vp->v_data = (void *)0; 354 return (0); 355} 356 357#if 0 358/* 359 * Lock an nfsnode 360 */ 361int
|
380nfs_lock(ap) 381 struct vop_lock_args /* { 382 struct vnode *a_vp; 383 } */ *ap;
| 362nfs_lock(struct vop_lock_args *ap)
|
384{
| 363{
|
385 register struct vnode *vp = ap->a_vp;
| 364 struct vnode *vp = ap->a_vp;
|
386 387 /* 388 * Ugh, another place where interruptible mounts will get hung. 389 * If you make this sleep interruptible, then you have to fix all 390 * the VOP_LOCK() calls to expect interruptibility. 391 */ 392 while (vp->v_flag & VXLOCK) { 393 vp->v_flag |= VXWANT; 394 (void) tsleep((caddr_t)vp, PINOD, "nfslck", 0); 395 } 396 if (vp->v_tag == VT_NON) 397 return (ENOENT); 398 399#if 0 400 /* 401 * Only lock regular files. If a server crashed while we were 402 * holding a directory lock, we could easily end up sleeping 403 * until the server rebooted while holding a lock on the root. 404 * Locks are only needed for protecting critical sections in 405 * VMIO at the moment. 406 * New vnodes will have type VNON but they should be locked 407 * since they may become VREG. This is checked in loadattrcache 408 * and unwanted locks are released there. 409 */ 410 if (vp->v_type == VREG || vp->v_type == VNON) { 411 while (np->n_flag & NLOCKED) { 412 np->n_flag |= NWANTED; 413 (void) tsleep((caddr_t) np, PINOD, "nfslck2", 0); 414 /* 415 * If the vnode has transmuted into a VDIR while we 416 * were asleep, then skip the lock. 417 */ 418 if (vp->v_type != VREG && vp->v_type != VNON) 419 return (0); 420 } 421 np->n_flag |= NLOCKED; 422 } 423#endif 424 425 return (0); 426} 427 428/* 429 * Unlock an nfsnode 430 */ 431int
| 365 366 /* 367 * Ugh, another place where interruptible mounts will get hung. 368 * If you make this sleep interruptible, then you have to fix all 369 * the VOP_LOCK() calls to expect interruptibility. 370 */ 371 while (vp->v_flag & VXLOCK) { 372 vp->v_flag |= VXWANT; 373 (void) tsleep((caddr_t)vp, PINOD, "nfslck", 0); 374 } 375 if (vp->v_tag == VT_NON) 376 return (ENOENT); 377 378#if 0 379 /* 380 * Only lock regular files. If a server crashed while we were 381 * holding a directory lock, we could easily end up sleeping 382 * until the server rebooted while holding a lock on the root. 383 * Locks are only needed for protecting critical sections in 384 * VMIO at the moment. 385 * New vnodes will have type VNON but they should be locked 386 * since they may become VREG. This is checked in loadattrcache 387 * and unwanted locks are released there. 388 */ 389 if (vp->v_type == VREG || vp->v_type == VNON) { 390 while (np->n_flag & NLOCKED) { 391 np->n_flag |= NWANTED; 392 (void) tsleep((caddr_t) np, PINOD, "nfslck2", 0); 393 /* 394 * If the vnode has transmuted into a VDIR while we 395 * were asleep, then skip the lock. 396 */ 397 if (vp->v_type != VREG && vp->v_type != VNON) 398 return (0); 399 } 400 np->n_flag |= NLOCKED; 401 } 402#endif 403 404 return (0); 405} 406 407/* 408 * Unlock an nfsnode 409 */ 410int
|
432nfs_unlock(ap) 433 struct vop_unlock_args /* { 434 struct vnode *a_vp; 435 } */ *ap;
| 411nfs_unlock(struct vop_unlock_args *ap)
|
436{ 437#if 0 438 struct vnode* vp = ap->a_vp; 439 struct nfsnode* np = VTONFS(vp); 440 441 if (vp->v_type == VREG || vp->v_type == VNON) { 442 if (!(np->n_flag & NLOCKED)) 443 panic("nfs_unlock: nfsnode not locked"); 444 np->n_flag &= ~NLOCKED; 445 if (np->n_flag & NWANTED) { 446 np->n_flag &= ~NWANTED; 447 wakeup((caddr_t) np); 448 } 449 } 450#endif 451 452 return (0); 453} 454 455/* 456 * Check for a locked nfsnode 457 */ 458int
| 412{ 413#if 0 414 struct vnode* vp = ap->a_vp; 415 struct nfsnode* np = VTONFS(vp); 416 417 if (vp->v_type == VREG || vp->v_type == VNON) { 418 if (!(np->n_flag & NLOCKED)) 419 panic("nfs_unlock: nfsnode not locked"); 420 np->n_flag &= ~NLOCKED; 421 if (np->n_flag & NWANTED) { 422 np->n_flag &= ~NWANTED; 423 wakeup((caddr_t) np); 424 } 425 } 426#endif 427 428 return (0); 429} 430 431/* 432 * Check for a locked nfsnode 433 */ 434int
|
459nfs_islocked(ap) 460 struct vop_islocked_args /* { 461 struct vnode *a_vp; 462 struct thread *a_td; 463 } */ *ap;
| 435nfs_islocked(struct vop_islocked_args *ap)
|
464{
| 436{
|
| 437
|
465 return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0; 466} 467#endif 468
| 438 return VTONFS(ap->a_vp)->n_flag & NLOCKED ? 1 : 0; 439} 440#endif 441
|