Mon Dec 29 00:14:39 2008 UTC ()
fix printf format.


(christos)
diff -r1.268 -r1.268.4.1 src/sys/nfs/nfs_vnops.c

cvs diff -r1.268 -r1.268.4.1 src/sys/nfs/nfs_vnops.c (expand / switch to unified diff)

--- src/sys/nfs/nfs_vnops.c 2008/11/19 18:36:10 1.268
+++ src/sys/nfs/nfs_vnops.c 2008/11/19 18:36:10 1.268.4.1
@@ -1,3661 +0,0 @@ @@ -1,3661 +0,0 @@
1/* $NetBSD: nfs_vnops.c,v 1.268 2008/11/19 18:36:10 ad Exp $ */ 
2 
3/* 
4 * Copyright (c) 1989, 1993 
5 * The Regents of the University of California. All rights reserved. 
6 * 
7 * This code is derived from software contributed to Berkeley by 
8 * Rick Macklem at The University of Guelph. 
9 * 
10 * Redistribution and use in source and binary forms, with or without 
11 * modification, are permitted provided that the following conditions 
12 * are met: 
13 * 1. Redistributions of source code must retain the above copyright 
14 * notice, this list of conditions and the following disclaimer. 
15 * 2. Redistributions in binary form must reproduce the above copyright 
16 * notice, this list of conditions and the following disclaimer in the 
17 * documentation and/or other materials provided with the distribution. 
18 * 3. Neither the name of the University nor the names of its contributors 
19 * may be used to endorse or promote products derived from this software 
20 * without specific prior written permission. 
21 * 
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
32 * SUCH DAMAGE. 
33 * 
34 * @(#)nfs_vnops.c 8.19 (Berkeley) 7/31/95 
35 */ 
36 
37/* 
38 * vnode op calls for Sun NFS version 2 and 3 
39 */ 
40 
41#include <sys/cdefs.h> 
42__KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.268 2008/11/19 18:36:10 ad Exp $"); 
43 
44#ifdef _KERNEL_OPT 
45#include "opt_nfs.h" 
46#include "opt_uvmhist.h" 
47#endif 
48 
49#include <sys/param.h> 
50#include <sys/proc.h> 
51#include <sys/kernel.h> 
52#include <sys/systm.h> 
53#include <sys/resourcevar.h> 
54#include <sys/mount.h> 
55#include <sys/buf.h> 
56#include <sys/condvar.h> 
57#include <sys/disk.h> 
58#include <sys/malloc.h> 
59#include <sys/kmem.h> 
60#include <sys/mbuf.h> 
61#include <sys/mutex.h> 
62#include <sys/namei.h> 
63#include <sys/vnode.h> 
64#include <sys/dirent.h> 
65#include <sys/fcntl.h> 
66#include <sys/hash.h> 
67#include <sys/lockf.h> 
68#include <sys/stat.h> 
69#include <sys/unistd.h> 
70#include <sys/kauth.h> 
71 
72#include <uvm/uvm_extern.h> 
73#include <uvm/uvm.h> 
74 
75#include <miscfs/fifofs/fifo.h> 
76#include <miscfs/genfs/genfs.h> 
77#include <miscfs/genfs/genfs_node.h> 
78#include <miscfs/specfs/specdev.h> 
79 
80#include <nfs/rpcv2.h> 
81#include <nfs/nfsproto.h> 
82#include <nfs/nfs.h> 
83#include <nfs/nfsnode.h> 
84#include <nfs/nfsmount.h> 
85#include <nfs/xdr_subs.h> 
86#include <nfs/nfsm_subs.h> 
87#include <nfs/nfs_var.h> 
88 
89#include <net/if.h> 
90#include <netinet/in.h> 
91#include <netinet/in_var.h> 
92 
93/* 
94 * Global vfs data structures for nfs 
95 */ 
96int (**nfsv2_vnodeop_p) __P((void *)); 
97const struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 
98 { &vop_default_desc, vn_default_error }, 
99 { &vop_lookup_desc, nfs_lookup }, /* lookup */ 
100 { &vop_create_desc, nfs_create }, /* create */ 
101 { &vop_mknod_desc, nfs_mknod }, /* mknod */ 
102 { &vop_open_desc, nfs_open }, /* open */ 
103 { &vop_close_desc, nfs_close }, /* close */ 
104 { &vop_access_desc, nfs_access }, /* access */ 
105 { &vop_getattr_desc, nfs_getattr }, /* getattr */ 
106 { &vop_setattr_desc, nfs_setattr }, /* setattr */ 
107 { &vop_read_desc, nfs_read }, /* read */ 
108 { &vop_write_desc, nfs_write }, /* write */ 
109 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 
110 { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */ 
111 { &vop_poll_desc, nfs_poll }, /* poll */ 
112 { &vop_kqfilter_desc, nfs_kqfilter }, /* kqfilter */ 
113 { &vop_revoke_desc, nfs_revoke }, /* revoke */ 
114 { &vop_mmap_desc, nfs_mmap }, /* mmap */ 
115 { &vop_fsync_desc, nfs_fsync }, /* fsync */ 
116 { &vop_seek_desc, nfs_seek }, /* seek */ 
117 { &vop_remove_desc, nfs_remove }, /* remove */ 
118 { &vop_link_desc, nfs_link }, /* link */ 
119 { &vop_rename_desc, nfs_rename }, /* rename */ 
120 { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 
121 { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 
122 { &vop_symlink_desc, nfs_symlink }, /* symlink */ 
123 { &vop_readdir_desc, nfs_readdir }, /* readdir */ 
124 { &vop_readlink_desc, nfs_readlink }, /* readlink */ 
125 { &vop_abortop_desc, nfs_abortop }, /* abortop */ 
126 { &vop_inactive_desc, nfs_inactive }, /* inactive */ 
127 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 
128 { &vop_lock_desc, nfs_lock }, /* lock */ 
129 { &vop_unlock_desc, nfs_unlock }, /* unlock */ 
130 { &vop_bmap_desc, nfs_bmap }, /* bmap */ 
131 { &vop_strategy_desc, nfs_strategy }, /* strategy */ 
132 { &vop_print_desc, nfs_print }, /* print */ 
133 { &vop_islocked_desc, nfs_islocked }, /* islocked */ 
134 { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */ 
135 { &vop_advlock_desc, nfs_advlock }, /* advlock */ 
136 { &vop_bwrite_desc, genfs_badop }, /* bwrite */ 
137 { &vop_getpages_desc, nfs_getpages }, /* getpages */ 
138 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 
139 { NULL, NULL } 
140}; 
141const struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 
142 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 
143 
144/* 
145 * Special device vnode ops 
146 */ 
147int (**spec_nfsv2nodeop_p) __P((void *)); 
148const struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 
149 { &vop_default_desc, vn_default_error }, 
150 { &vop_lookup_desc, spec_lookup }, /* lookup */ 
151 { &vop_create_desc, spec_create }, /* create */ 
152 { &vop_mknod_desc, spec_mknod }, /* mknod */ 
153 { &vop_open_desc, spec_open }, /* open */ 
154 { &vop_close_desc, nfsspec_close }, /* close */ 
155 { &vop_access_desc, nfsspec_access }, /* access */ 
156 { &vop_getattr_desc, nfs_getattr }, /* getattr */ 
157 { &vop_setattr_desc, nfs_setattr }, /* setattr */ 
158 { &vop_read_desc, nfsspec_read }, /* read */ 
159 { &vop_write_desc, nfsspec_write }, /* write */ 
160 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 
161 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 
162 { &vop_poll_desc, spec_poll }, /* poll */ 
163 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 
164 { &vop_revoke_desc, spec_revoke }, /* revoke */ 
165 { &vop_mmap_desc, spec_mmap }, /* mmap */ 
166 { &vop_fsync_desc, spec_fsync }, /* fsync */ 
167 { &vop_seek_desc, spec_seek }, /* seek */ 
168 { &vop_remove_desc, spec_remove }, /* remove */ 
169 { &vop_link_desc, spec_link }, /* link */ 
170 { &vop_rename_desc, spec_rename }, /* rename */ 
171 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 
172 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 
173 { &vop_symlink_desc, spec_symlink }, /* symlink */ 
174 { &vop_readdir_desc, spec_readdir }, /* readdir */ 
175 { &vop_readlink_desc, spec_readlink }, /* readlink */ 
176 { &vop_abortop_desc, spec_abortop }, /* abortop */ 
177 { &vop_inactive_desc, nfs_inactive }, /* inactive */ 
178 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 
179 { &vop_lock_desc, nfs_lock }, /* lock */ 
180 { &vop_unlock_desc, nfs_unlock }, /* unlock */ 
181 { &vop_bmap_desc, spec_bmap }, /* bmap */ 
182 { &vop_strategy_desc, spec_strategy }, /* strategy */ 
183 { &vop_print_desc, nfs_print }, /* print */ 
184 { &vop_islocked_desc, nfs_islocked }, /* islocked */ 
185 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 
186 { &vop_advlock_desc, spec_advlock }, /* advlock */ 
187 { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ 
188 { &vop_getpages_desc, spec_getpages }, /* getpages */ 
189 { &vop_putpages_desc, spec_putpages }, /* putpages */ 
190 { NULL, NULL } 
191}; 
192const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 
193 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 
194 
195int (**fifo_nfsv2nodeop_p) __P((void *)); 
196const struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 
197 { &vop_default_desc, vn_default_error }, 
198 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 
199 { &vop_create_desc, fifo_create }, /* create */ 
200 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 
201 { &vop_open_desc, fifo_open }, /* open */ 
202 { &vop_close_desc, nfsfifo_close }, /* close */ 
203 { &vop_access_desc, nfsspec_access }, /* access */ 
204 { &vop_getattr_desc, nfs_getattr }, /* getattr */ 
205 { &vop_setattr_desc, nfs_setattr }, /* setattr */ 
206 { &vop_read_desc, nfsfifo_read }, /* read */ 
207 { &vop_write_desc, nfsfifo_write }, /* write */ 
208 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 
209 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 
210 { &vop_poll_desc, fifo_poll }, /* poll */ 
211 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 
212 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 
213 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 
214 { &vop_fsync_desc, nfs_fsync }, /* fsync */ 
215 { &vop_seek_desc, fifo_seek }, /* seek */ 
216 { &vop_remove_desc, fifo_remove }, /* remove */ 
217 { &vop_link_desc, fifo_link }, /* link */ 
218 { &vop_rename_desc, fifo_rename }, /* rename */ 
219 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 
220 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 
221 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 
222 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 
223 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 
224 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 
225 { &vop_inactive_desc, nfs_inactive }, /* inactive */ 
226 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 
227 { &vop_lock_desc, nfs_lock }, /* lock */ 
228 { &vop_unlock_desc, nfs_unlock }, /* unlock */ 
229 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 
230 { &vop_strategy_desc, genfs_badop }, /* strategy */ 
231 { &vop_print_desc, nfs_print }, /* print */ 
232 { &vop_islocked_desc, nfs_islocked }, /* islocked */ 
233 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 
234 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 
235 { &vop_bwrite_desc, genfs_badop }, /* bwrite */ 
236 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 
237 { NULL, NULL } 
238}; 
239const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 
240 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 
241 
242static int nfs_linkrpc(struct vnode *, struct vnode *, const char *, 
243 size_t, kauth_cred_t, struct lwp *); 
244static void nfs_writerpc_extfree(struct mbuf *, void *, size_t, void *); 
245 
246/* 
247 * Global variables 
248 */ 
249extern u_int32_t nfs_true, nfs_false; 
250extern u_int32_t nfs_xdrneg1; 
251extern const nfstype nfsv3_type[9]; 
252 
253int nfs_numasync = 0; 
254#define DIRHDSIZ _DIRENT_NAMEOFF(dp) 
255#define UIO_ADVANCE(uio, siz) \ 
256 (void)((uio)->uio_resid -= (siz), \ 
257 (uio)->uio_iov->iov_base = (char *)(uio)->uio_iov->iov_base + (siz), \ 
258 (uio)->uio_iov->iov_len -= (siz)) 
259 
260static void nfs_cache_enter(struct vnode *, struct vnode *, 
261 struct componentname *); 
262 
263static void 
264nfs_cache_enter(struct vnode *dvp, struct vnode *vp, 
265 struct componentname *cnp) 
266{ 
267 struct nfsnode *dnp = VTONFS(dvp); 
268 
269 if (vp != NULL) { 
270 struct nfsnode *np = VTONFS(vp); 
271 
272 np->n_ctime = np->n_vattr->va_ctime.tv_sec; 
273 } 
274 
275 if (!timespecisset(&dnp->n_nctime)) 
276 dnp->n_nctime = dnp->n_vattr->va_mtime; 
277 
278 cache_enter(dvp, vp, cnp); 
279} 
280 
281/* 
282 * nfs null call from vfs. 
283 */ 
284int 
285nfs_null(vp, cred, l) 
286 struct vnode *vp; 
287 kauth_cred_t cred; 
288 struct lwp *l; 
289{ 
290 char *bpos, *dpos; 
291 int error = 0; 
292 struct mbuf *mreq, *mrep, *md, *mb; 
293 struct nfsnode *np = VTONFS(vp); 
294 
295 nfsm_reqhead(np, NFSPROC_NULL, 0); 
296 nfsm_request(np, NFSPROC_NULL, l, cred); 
297 nfsm_reqdone; 
298 return (error); 
299} 
300 
301/* 
302 * nfs access vnode op. 
303 * For nfs version 2, just return ok. File accesses may fail later. 
304 * For nfs version 3, use the access rpc to check accessibility. If file modes 
305 * are changed on the server, accesses might still fail later. 
306 */ 
307int 
308nfs_access(v) 
309 void *v; 
310{ 
311 struct vop_access_args /* { 
312 struct vnode *a_vp; 
313 int a_mode; 
314 kauth_cred_t a_cred; 
315 } */ *ap = v; 
316 struct vnode *vp = ap->a_vp; 
317#ifndef NFS_V2_ONLY 
318 u_int32_t *tl; 
319 char *cp; 
320 int32_t t1, t2; 
321 char *bpos, *dpos, *cp2; 
322 int error = 0, attrflag; 
323 struct mbuf *mreq, *mrep, *md, *mb; 
324 u_int32_t mode, rmode; 
325 const int v3 = NFS_ISV3(vp); 
326#endif 
327 int cachevalid; 
328 struct nfsnode *np = VTONFS(vp); 
329 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 
330 
331 cachevalid = (np->n_accstamp != -1 && 
332 (time_uptime - np->n_accstamp) < nfs_attrtimeo(nmp, np) && 
333 np->n_accuid == kauth_cred_geteuid(ap->a_cred)); 
334 
335 /* 
336 * Check access cache first. If this request has been made for this 
337 * uid shortly before, use the cached result. 
338 */ 
339 if (cachevalid) { 
340 if (!np->n_accerror) { 
341 if ((np->n_accmode & ap->a_mode) == ap->a_mode) 
342 return np->n_accerror; 
343 } else if ((np->n_accmode & ap->a_mode) == np->n_accmode) 
344 return np->n_accerror; 
345 } 
346 
347#ifndef NFS_V2_ONLY 
348 /* 
349 * For nfs v3, do an access rpc, otherwise you are stuck emulating 
350 * ufs_access() locally using the vattr. This may not be correct, 
351 * since the server may apply other access criteria such as 
352 * client uid-->server uid mapping that we do not know about, but 
353 * this is better than just returning anything that is lying about 
354 * in the cache. 
355 */ 
356 if (v3) { 
357 nfsstats.rpccnt[NFSPROC_ACCESS]++; 
358 nfsm_reqhead(np, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED); 
359 nfsm_fhtom(np, v3); 
360 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 
361 if (ap->a_mode & VREAD) 
362 mode = NFSV3ACCESS_READ; 
363 else 
364 mode = 0; 
365 if (vp->v_type != VDIR) { 
366 if (ap->a_mode & VWRITE) 
367 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 
368 if (ap->a_mode & VEXEC) 
369 mode |= NFSV3ACCESS_EXECUTE; 
370 } else { 
371 if (ap->a_mode & VWRITE) 
372 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 
373 NFSV3ACCESS_DELETE); 
374 if (ap->a_mode & VEXEC) 
375 mode |= NFSV3ACCESS_LOOKUP; 
376 } 
377 *tl = txdr_unsigned(mode); 
378 nfsm_request(np, NFSPROC_ACCESS, curlwp, ap->a_cred); 
379 nfsm_postop_attr(vp, attrflag, 0); 
380 if (!error) { 
381 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
382 rmode = fxdr_unsigned(u_int32_t, *tl); 
383 /* 
384 * The NFS V3 spec does not clarify whether or not 
385 * the returned access bits can be a superset of 
386 * the ones requested, so... 
387 */ 
388 if ((rmode & mode) != mode) 
389 error = EACCES; 
390 } 
391 nfsm_reqdone; 
392 } else 
393#endif 
394 return (nfsspec_access(ap)); 
395#ifndef NFS_V2_ONLY 
396 /* 
397 * Disallow write attempts on filesystems mounted read-only; 
398 * unless the file is a socket, fifo, or a block or character 
399 * device resident on the filesystem. 
400 */ 
401 if (!error && (ap->a_mode & VWRITE) && 
402 (vp->v_mount->mnt_flag & MNT_RDONLY)) { 
403 switch (vp->v_type) { 
404 case VREG: 
405 case VDIR: 
406 case VLNK: 
407 error = EROFS; 
408 default: 
409 break; 
410 } 
411 } 
412 
413 if (!error || error == EACCES) { 
414 /* 
415 * If we got the same result as for a previous, 
416 * different request, OR it in. Don't update 
417 * the timestamp in that case. 
418 */ 
419 if (cachevalid && np->n_accstamp != -1 && 
420 error == np->n_accerror) { 
421 if (!error) 
422 np->n_accmode |= ap->a_mode; 
423 else if ((np->n_accmode & ap->a_mode) == ap->a_mode) 
424 np->n_accmode = ap->a_mode; 
425 } else { 
426 np->n_accstamp = time_uptime; 
427 np->n_accuid = kauth_cred_geteuid(ap->a_cred); 
428 np->n_accmode = ap->a_mode; 
429 np->n_accerror = error; 
430 } 
431 } 
432 
433 return (error); 
434#endif 
435} 
436 
437/* 
438 * nfs open vnode op 
439 * Check to see if the type is ok 
440 * and that deletion is not in progress. 
441 * For paged in text files, you will need to flush the page cache 
442 * if consistency is lost. 
443 */ 
444/* ARGSUSED */ 
445int 
446nfs_open(v) 
447 void *v; 
448{ 
449 struct vop_open_args /* { 
450 struct vnode *a_vp; 
451 int a_mode; 
452 kauth_cred_t a_cred; 
453 } */ *ap = v; 
454 struct vnode *vp = ap->a_vp; 
455 struct nfsnode *np = VTONFS(vp); 
456 int error; 
457 
458 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) { 
459 return (EACCES); 
460 } 
461 
462 if (ap->a_mode & FREAD) { 
463 if (np->n_rcred != NULL) 
464 kauth_cred_free(np->n_rcred); 
465 np->n_rcred = ap->a_cred; 
466 kauth_cred_hold(np->n_rcred); 
467 } 
468 if (ap->a_mode & FWRITE) { 
469 if (np->n_wcred != NULL) 
470 kauth_cred_free(np->n_wcred); 
471 np->n_wcred = ap->a_cred; 
472 kauth_cred_hold(np->n_wcred); 
473 } 
474 
475 error = nfs_flushstalebuf(vp, ap->a_cred, curlwp, 0); 
476 if (error) 
477 return error; 
478 
479 NFS_INVALIDATE_ATTRCACHE(np); /* For Open/Close consistency */ 
480 
481 return (0); 
482} 
483 
484/* 
485 * nfs close vnode op 
486 * What an NFS client should do upon close after writing is a debatable issue. 
487 * Most NFS clients push delayed writes to the server upon close, basically for 
488 * two reasons: 
489 * 1 - So that any write errors may be reported back to the client process 
490 * doing the close system call. By far the two most likely errors are 
491 * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. 
492 * 2 - To put a worst case upper bound on cache inconsistency between 
493 * multiple clients for the file. 
494 * There is also a consistency problem for Version 2 of the protocol w.r.t. 
495 * not being able to tell if other clients are writing a file concurrently, 
496 * since there is no way of knowing if the changed modify time in the reply 
497 * is only due to the write for this client. 
498 * (NFS Version 3 provides weak cache consistency data in the reply that 
499 * should be sufficient to detect and handle this case.) 
500 * 
501 * The current code does the following: 
502 * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers 
503 * for NFS Version 3 - flush dirty buffers to the server but don't invalidate 
504 * or commit them (this satisfies 1 and 2 except for the 
505 * case where the server crashes after this close but 
506 * before the commit RPC, which is felt to be "good 
507 * enough". Changing the last argument to nfs_flush() to 
508 * a 1 would force a commit operation, if it is felt a 
509 * commit is necessary now. 
510 */ 
511/* ARGSUSED */ 
512int 
513nfs_close(v) 
514 void *v; 
515{ 
516 struct vop_close_args /* { 
517 struct vnodeop_desc *a_desc; 
518 struct vnode *a_vp; 
519 int a_fflag; 
520 kauth_cred_t a_cred; 
521 } */ *ap = v; 
522 struct vnode *vp = ap->a_vp; 
523 struct nfsnode *np = VTONFS(vp); 
524 int error = 0; 
525 UVMHIST_FUNC("nfs_close"); UVMHIST_CALLED(ubchist); 
526 
527 if (vp->v_type == VREG) { 
528 if (np->n_flag & NMODIFIED) { 
529#ifndef NFS_V2_ONLY 
530 if (NFS_ISV3(vp)) { 
531 error = nfs_flush(vp, ap->a_cred, MNT_WAIT, curlwp, 0); 
532 np->n_flag &= ~NMODIFIED; 
533 } else 
534#endif 
535 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 1); 
536 NFS_INVALIDATE_ATTRCACHE(np); 
537 } 
538 if (np->n_flag & NWRITEERR) { 
539 np->n_flag &= ~NWRITEERR; 
540 error = np->n_error; 
541 } 
542 } 
543 UVMHIST_LOG(ubchist, "returning %d", error,0,0,0); 
544 return (error); 
545} 
546 
547/* 
548 * nfs getattr call from vfs. 
549 */ 
550int 
551nfs_getattr(v) 
552 void *v; 
553{ 
554 struct vop_getattr_args /* { 
555 struct vnode *a_vp; 
556 struct vattr *a_vap; 
557 kauth_cred_t a_cred; 
558 } */ *ap = v; 
559 struct vnode *vp = ap->a_vp; 
560 struct nfsnode *np = VTONFS(vp); 
561 char *cp; 
562 u_int32_t *tl; 
563 int32_t t1, t2; 
564 char *bpos, *dpos; 
565 int error = 0; 
566 struct mbuf *mreq, *mrep, *md, *mb; 
567 const int v3 = NFS_ISV3(vp); 
568 
569 /* 
570 * Update local times for special files. 
571 */ 
572 if (np->n_flag & (NACC | NUPD)) 
573 np->n_flag |= NCHG; 
574 
575 /* 
576 * if we have delayed truncation, do it now. 
577 */ 
578 nfs_delayedtruncate(vp); 
579 
580 /* 
581 * First look in the cache. 
582 */ 
583 if (nfs_getattrcache(vp, ap->a_vap) == 0) 
584 return (0); 
585 nfsstats.rpccnt[NFSPROC_GETATTR]++; 
586 nfsm_reqhead(np, NFSPROC_GETATTR, NFSX_FH(v3)); 
587 nfsm_fhtom(np, v3); 
588 nfsm_request(np, NFSPROC_GETATTR, curlwp, ap->a_cred); 
589 if (!error) { 
590 nfsm_loadattr(vp, ap->a_vap, 0); 
591 if (vp->v_type == VDIR && 
592 ap->a_vap->va_blocksize < NFS_DIRFRAGSIZ) 
593 ap->a_vap->va_blocksize = NFS_DIRFRAGSIZ; 
594 } 
595 nfsm_reqdone; 
596 return (error); 
597} 
598 
599/* 
600 * nfs setattr call. 
601 */ 
602int 
603nfs_setattr(v) 
604 void *v; 
605{ 
606 struct vop_setattr_args /* { 
607 struct vnodeop_desc *a_desc; 
608 struct vnode *a_vp; 
609 struct vattr *a_vap; 
610 kauth_cred_t a_cred; 
611 } */ *ap = v; 
612 struct vnode *vp = ap->a_vp; 
613 struct nfsnode *np = VTONFS(vp); 
614 struct vattr *vap = ap->a_vap; 
615 int error = 0; 
616 u_quad_t tsize = 0; 
617 
618 /* 
619 * Setting of flags is not supported. 
620 */ 
621 if (vap->va_flags != VNOVAL) 
622 return (EOPNOTSUPP); 
623 
624 /* 
625 * Disallow write attempts if the filesystem is mounted read-only. 
626 */ 
627 if ((vap->va_uid != (uid_t)VNOVAL || 
628 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 
629 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && 
630 (vp->v_mount->mnt_flag & MNT_RDONLY)) 
631 return (EROFS); 
632 if (vap->va_size != VNOVAL) { 
633 if (vap->va_size > VFSTONFS(vp->v_mount)->nm_maxfilesize) { 
634 return EFBIG; 
635 } 
636 switch (vp->v_type) { 
637 case VDIR: 
638 return (EISDIR); 
639 case VCHR: 
640 case VBLK: 
641 case VSOCK: 
642 case VFIFO: 
643 if (vap->va_mtime.tv_sec == VNOVAL && 
644 vap->va_atime.tv_sec == VNOVAL && 
645 vap->va_mode == (mode_t)VNOVAL && 
646 vap->va_uid == (uid_t)VNOVAL && 
647 vap->va_gid == (gid_t)VNOVAL) 
648 return (0); 
649 vap->va_size = VNOVAL; 
650 break; 
651 default: 
652 /* 
653 * Disallow write attempts if the filesystem is 
654 * mounted read-only. 
655 */ 
656 if (vp->v_mount->mnt_flag & MNT_RDONLY) 
657 return (EROFS); 
658 genfs_node_wrlock(vp); 
659 uvm_vnp_setsize(vp, vap->va_size); 
660 tsize = np->n_size; 
661 np->n_size = vap->va_size; 
662 if (vap->va_size == 0) 
663 error = nfs_vinvalbuf(vp, 0, 
664 ap->a_cred, curlwp, 1); 
665 else 
666 error = nfs_vinvalbuf(vp, V_SAVE, 
667 ap->a_cred, curlwp, 1); 
668 if (error) { 
669 uvm_vnp_setsize(vp, tsize); 
670 genfs_node_unlock(vp); 
671 return (error); 
672 } 
673 np->n_vattr->va_size = vap->va_size; 
674 } 
675 } else { 
676 /* 
677 * flush files before setattr because a later write of 
678 * cached data might change timestamps or reset sugid bits 
679 */ 
680 if ((vap->va_mtime.tv_sec != VNOVAL || 
681 vap->va_atime.tv_sec != VNOVAL || 
682 vap->va_mode != VNOVAL) && 
683 vp->v_type == VREG && 
684 (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 
685 curlwp, 1)) == EINTR) 
686 return (error); 
687 } 
688 error = nfs_setattrrpc(vp, vap, ap->a_cred, curlwp); 
689 if (vap->va_size != VNOVAL) { 
690 if (error) { 
691 np->n_size = np->n_vattr->va_size = tsize; 
692 uvm_vnp_setsize(vp, np->n_size); 
693 } 
694 genfs_node_unlock(vp); 
695 } 
696 VN_KNOTE(vp, NOTE_ATTRIB); 
697 return (error); 
698} 
699 
700/* 
701 * Do an nfs setattr rpc. 
702 */ 
703int 
704nfs_setattrrpc(vp, vap, cred, l) 
705 struct vnode *vp; 
706 struct vattr *vap; 
707 kauth_cred_t cred; 
708 struct lwp *l; 
709{ 
710 struct nfsv2_sattr *sp; 
711 char *cp; 
712 int32_t t1, t2; 
713 char *bpos, *dpos; 
714 u_int32_t *tl; 
715 int error = 0; 
716 struct mbuf *mreq, *mrep, *md, *mb; 
717 const int v3 = NFS_ISV3(vp); 
718 struct nfsnode *np = VTONFS(vp); 
719#ifndef NFS_V2_ONLY 
720 int wccflag = NFSV3_WCCRATTR; 
721 char *cp2; 
722#endif 
723 
724 nfsstats.rpccnt[NFSPROC_SETATTR]++; 
725 nfsm_reqhead(np, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3)); 
726 nfsm_fhtom(np, v3); 
727#ifndef NFS_V2_ONLY 
728 if (v3) { 
729 nfsm_v3attrbuild(vap, true); 
730 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 
731 *tl = nfs_false; 
732 } else { 
733#endif 
734 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 
735 if (vap->va_mode == (mode_t)VNOVAL) 
736 sp->sa_mode = nfs_xdrneg1; 
737 else 
738 sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode); 
739 if (vap->va_uid == (uid_t)VNOVAL) 
740 sp->sa_uid = nfs_xdrneg1; 
741 else 
742 sp->sa_uid = txdr_unsigned(vap->va_uid); 
743 if (vap->va_gid == (gid_t)VNOVAL) 
744 sp->sa_gid = nfs_xdrneg1; 
745 else 
746 sp->sa_gid = txdr_unsigned(vap->va_gid); 
747 sp->sa_size = txdr_unsigned(vap->va_size); 
748 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 
749 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 
750#ifndef NFS_V2_ONLY 
751 } 
752#endif 
753 nfsm_request(np, NFSPROC_SETATTR, l, cred); 
754#ifndef NFS_V2_ONLY 
755 if (v3) { 
756 nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, false); 
757 } else 
758#endif 
759 nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC); 
760 nfsm_reqdone; 
761 return (error); 
762} 
763 
764/* 
765 * nfs lookup call, one step at a time... 
766 * First look in cache 
767 * If not found, unlock the directory nfsnode and do the rpc 
768 * 
769 * This code is full of lock/unlock statements and checks, because 
770 * we continue after cache_lookup has finished (we need to check 
771 * with the attr cache and do an rpc if it has timed out). This means 
772 * that the locking effects of cache_lookup have to be taken into 
773 * account. 
774 */ 
775int 
776nfs_lookup(v) 
777 void *v; 
778{ 
779 struct vop_lookup_args /* { 
780 struct vnodeop_desc *a_desc; 
781 struct vnode *a_dvp; 
782 struct vnode **a_vpp; 
783 struct componentname *a_cnp; 
784 } */ *ap = v; 
785 struct componentname *cnp = ap->a_cnp; 
786 struct vnode *dvp = ap->a_dvp; 
787 struct vnode **vpp = ap->a_vpp; 
788 int flags; 
789 struct vnode *newvp; 
790 u_int32_t *tl; 
791 char *cp; 
792 int32_t t1, t2; 
793 char *bpos, *dpos, *cp2; 
794 struct mbuf *mreq, *mrep, *md, *mb; 
795 long len; 
796 nfsfh_t *fhp; 
797 struct nfsnode *np; 
798 int error = 0, attrflag, fhsize; 
799 const int v3 = NFS_ISV3(dvp); 
800 
801 flags = cnp->cn_flags; 
802 
803 *vpp = NULLVP; 
804 newvp = NULLVP; 
805 if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 
806 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 
807 return (EROFS); 
808 if (dvp->v_type != VDIR) 
809 return (ENOTDIR); 
810 
811 /* 
812 * RFC1813(nfsv3) 3.2 says clients should handle "." by themselves. 
813 */ 
814 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 
815 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred); 
816 if (error) 
817 return error; 
818 if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) 
819 return EISDIR; 
820 VREF(dvp); 
821 *vpp = dvp; 
822 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 
823 cnp->cn_flags |= SAVENAME; 
824 return 0; 
825 } 
826 
827 np = VTONFS(dvp); 
828 
829 /* 
830 * Before tediously performing a linear scan of the directory, 
831 * check the name cache to see if the directory/name pair 
832 * we are looking for is known already. 
833 * If the directory/name pair is found in the name cache, 
834 * we have to ensure the directory has not changed from 
835 * the time the cache entry has been created. If it has, 
836 * the cache entry has to be ignored. 
837 */ 
838 error = cache_lookup_raw(dvp, vpp, cnp); 
839 KASSERT(dvp != *vpp); 
840 if (error >= 0) { 
841 struct vattr vattr; 
842 int err2; 
843 
844 if (error && error != ENOENT) { 
845 *vpp = NULLVP; 
846 return error; 
847 } 
848 
849 err2 = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred); 
850 if (err2 != 0) { 
851 if (error == 0) 
852 vrele(*vpp); 
853 *vpp = NULLVP; 
854 return err2; 
855 } 
856 
857 if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred) 
858 || timespeccmp(&vattr.va_mtime, 
859 &VTONFS(dvp)->n_nctime, !=)) { 
860 if (error == 0) { 
861 vrele(*vpp); 
862 *vpp = NULLVP; 
863 } 
864 cache_purge1(dvp, NULL, PURGE_CHILDREN); 
865 timespecclear(&np->n_nctime); 
866 goto dorpc; 
867 } 
868 
869 if (error == ENOENT) { 
870 goto noentry; 
871 } 
872 
873 newvp = *vpp; 
874 if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred) 
875 && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) { 
876 nfsstats.lookupcache_hits++; 
877 if ((flags & ISDOTDOT) != 0) { 
878 VOP_UNLOCK(dvp, 0); 
879 } 
880 error = vn_lock(newvp, LK_EXCLUSIVE); 
881 if ((flags & ISDOTDOT) != 0) { 
882 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 
883 } 
884 if (error) { 
885 /* newvp has been revoked. */ 
886 vrele(newvp); 
887 *vpp = NULL; 
888 return error; 
889 } 
890 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 
891 cnp->cn_flags |= SAVENAME; 
892 KASSERT(newvp->v_type != VNON); 
893 return (0); 
894 } 
895 cache_purge1(newvp, NULL, PURGE_PARENTS); 
896 vrele(newvp); 
897 *vpp = NULLVP; 
898 } 
899dorpc: 
900#if 0 
901 /* 
902 * because nfsv3 has the same CREATE semantics as ours, 
903 * we don't have to perform LOOKUPs beforehand. 
904 * 
905 * XXX ideally we can do the same for nfsv2 in the case of !O_EXCL. 
906 * XXX although we have no way to know if O_EXCL is requested or not. 
907 */ 
908 
909 if (v3 && cnp->cn_nameiop == CREATE && 
910 (flags & (ISLASTCN|ISDOTDOT)) == ISLASTCN && 
911 (dvp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 
912 cnp->cn_flags |= SAVENAME; 
913 return (EJUSTRETURN); 
914 } 
915#endif /* 0 */ 
916 
917 error = 0; 
918 newvp = NULLVP; 
919 nfsstats.lookupcache_misses++; 
920 nfsstats.rpccnt[NFSPROC_LOOKUP]++; 
921 len = cnp->cn_namelen; 
922 nfsm_reqhead(np, NFSPROC_LOOKUP, 
923 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); 
924 nfsm_fhtom(np, v3); 
925 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 
926 nfsm_request(np, NFSPROC_LOOKUP, curlwp, cnp->cn_cred); 
927 if (error) { 
928 nfsm_postop_attr(dvp, attrflag, 0); 
929 m_freem(mrep); 
930 goto nfsmout; 
931 } 
932 nfsm_getfh(fhp, fhsize, v3); 
933 
934 /* 
935 * Handle RENAME case... 
936 */ 
937 if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) { 
938 if (NFS_CMPFH(np, fhp, fhsize)) { 
939 m_freem(mrep); 
940 return (EISDIR); 
941 } 
942 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); 
943 if (error) { 
944 m_freem(mrep); 
945 return error; 
946 } 
947 newvp = NFSTOV(np); 
948#ifndef NFS_V2_ONLY 
949 if (v3) { 
950 nfsm_postop_attr(newvp, attrflag, 0); 
951 nfsm_postop_attr(dvp, attrflag, 0); 
952 } else 
953#endif 
954 nfsm_loadattr(newvp, (struct vattr *)0, 0); 
955 *vpp = newvp; 
956 m_freem(mrep); 
957 cnp->cn_flags |= SAVENAME; 
958 goto validate; 
959 } 
960 
961 /* 
962 * The postop attr handling is duplicated for each if case, 
963 * because it should be done while dvp is locked (unlocking 
964 * dvp is different for each case). 
965 */ 
966 
967 if (NFS_CMPFH(np, fhp, fhsize)) { 
968 /* 
969 * "." lookup 
970 */ 
971 VREF(dvp); 
972 newvp = dvp; 
973#ifndef NFS_V2_ONLY 
974 if (v3) { 
975 nfsm_postop_attr(newvp, attrflag, 0); 
976 nfsm_postop_attr(dvp, attrflag, 0); 
977 } else 
978#endif 
979 nfsm_loadattr(newvp, (struct vattr *)0, 0); 
980 } else if (flags & ISDOTDOT) { 
981 /* 
982 * ".." lookup 
983 */ 
984 VOP_UNLOCK(dvp, 0); 
985 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); 
986 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 
987 if (error) { 
988 m_freem(mrep); 
989 return error; 
990 } 
991 newvp = NFSTOV(np); 
992 
993#ifndef NFS_V2_ONLY 
994 if (v3) { 
995 nfsm_postop_attr(newvp, attrflag, 0); 
996 nfsm_postop_attr(dvp, attrflag, 0); 
997 } else 
998#endif 
999 nfsm_loadattr(newvp, (struct vattr *)0, 0); 
1000 } else { 
1001 /* 
1002 * Other lookups. 
1003 */ 
1004 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); 
1005 if (error) { 
1006 m_freem(mrep); 
1007 return error; 
1008 } 
1009 newvp = NFSTOV(np); 
1010#ifndef NFS_V2_ONLY 
1011 if (v3) { 
1012 nfsm_postop_attr(newvp, attrflag, 0); 
1013 nfsm_postop_attr(dvp, attrflag, 0); 
1014 } else 
1015#endif 
1016 nfsm_loadattr(newvp, (struct vattr *)0, 0); 
1017 } 
1018 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 
1019 cnp->cn_flags |= SAVENAME; 
1020 if ((cnp->cn_flags & MAKEENTRY) && 
1021 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { 
1022 nfs_cache_enter(dvp, newvp, cnp); 
1023 } 
1024 *vpp = newvp; 
1025 nfsm_reqdone; 
1026 if (error) { 
1027 /* 
1028 * We get here only because of errors returned by 
1029 * the RPC. Otherwise we'll have returned above 
1030 * (the nfsm_* macros will jump to nfsm_reqdone 
1031 * on error). 
1032 */ 
1033 if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) && 
1034 cnp->cn_nameiop != CREATE) { 
1035 nfs_cache_enter(dvp, NULL, cnp); 
1036 } 
1037 if (newvp != NULLVP) { 
1038 if (newvp == dvp) { 
1039 vrele(newvp); 
1040 } else { 
1041 vput(newvp); 
1042 } 
1043 } 
1044noentry: 
1045 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 
1046 (flags & ISLASTCN) && error == ENOENT) { 
1047 if (dvp->v_mount->mnt_flag & MNT_RDONLY) { 
1048 error = EROFS; 
1049 } else { 
1050 error = EJUSTRETURN; 
1051 cnp->cn_flags |= SAVENAME; 
1052 } 
1053 } 
1054 *vpp = NULL; 
1055 return error; 
1056 } 
1057 
1058validate: 
1059 /* 
1060 * make sure we have valid type and size. 
1061 */ 
1062 
1063 newvp = *vpp; 
1064 if (newvp->v_type == VNON) { 
1065 struct vattr vattr; /* dummy */ 
1066 
1067 KASSERT(VTONFS(newvp)->n_attrstamp == 0); 
1068 error = VOP_GETATTR(newvp, &vattr, cnp->cn_cred); 
1069 if (error) { 
1070 vput(newvp); 
1071 *vpp = NULL; 
1072 } 
1073 } 
1074 
1075 return error; 
1076} 
1077 
1078/* 
1079 * nfs read call. 
1080 * Just call nfs_bioread() to do the work. 
1081 */ 
1082int 
1083nfs_read(v) 
1084 void *v; 
1085{ 
1086 struct vop_read_args /* { 
1087 struct vnode *a_vp; 
1088 struct uio *a_uio; 
1089 int a_ioflag; 
1090 kauth_cred_t a_cred; 
1091 } */ *ap = v; 
1092 struct vnode *vp = ap->a_vp; 
1093 
1094 if (vp->v_type != VREG) 
1095 return EISDIR; 
1096 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0)); 
1097} 
1098 
1099/* 
1100 * nfs readlink call 
1101 */ 
1102int 
1103nfs_readlink(v) 
1104 void *v; 
1105{ 
1106 struct vop_readlink_args /* { 
1107 struct vnode *a_vp; 
1108 struct uio *a_uio; 
1109 kauth_cred_t a_cred; 
1110 } */ *ap = v; 
1111 struct vnode *vp = ap->a_vp; 
1112 struct nfsnode *np = VTONFS(vp); 
1113 
1114 if (vp->v_type != VLNK) 
1115 return (EPERM); 
1116 
1117 if (np->n_rcred != NULL) { 
1118 kauth_cred_free(np->n_rcred); 
1119 } 
1120 np->n_rcred = ap->a_cred; 
1121 kauth_cred_hold(np->n_rcred); 
1122 
1123 return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0)); 
1124} 
1125 
1126/* 
1127 * Do a readlink rpc. 
1128 * Called by nfs_doio() from below the buffer cache. 
1129 */ 
1130int 
1131nfs_readlinkrpc(vp, uiop, cred) 
1132 struct vnode *vp; 
1133 struct uio *uiop; 
1134 kauth_cred_t cred; 
1135{ 
1136 u_int32_t *tl; 
1137 char *cp; 
1138 int32_t t1, t2; 
1139 char *bpos, *dpos, *cp2; 
1140 int error = 0; 
1141 uint32_t len; 
1142 struct mbuf *mreq, *mrep, *md, *mb; 
1143 const int v3 = NFS_ISV3(vp); 
1144 struct nfsnode *np = VTONFS(vp); 
1145#ifndef NFS_V2_ONLY 
1146 int attrflag; 
1147#endif 
1148 
1149 nfsstats.rpccnt[NFSPROC_READLINK]++; 
1150 nfsm_reqhead(np, NFSPROC_READLINK, NFSX_FH(v3)); 
1151 nfsm_fhtom(np, v3); 
1152 nfsm_request(np, NFSPROC_READLINK, curlwp, cred); 
1153#ifndef NFS_V2_ONLY 
1154 if (v3) 
1155 nfsm_postop_attr(vp, attrflag, 0); 
1156#endif 
1157 if (!error) { 
1158#ifndef NFS_V2_ONLY 
1159 if (v3) { 
1160 nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED); 
1161 len = fxdr_unsigned(uint32_t, *tl); 
1162 if (len > MAXPATHLEN) { 
1163 /* 
1164 * this pathname is too long for us. 
1165 */ 
1166 m_freem(mrep); 
1167 /* Solaris returns EINVAL. should we follow? */ 
1168 error = ENAMETOOLONG; 
1169 goto nfsmout; 
1170 } 
1171 } else 
1172#endif 
1173 { 
1174 nfsm_strsiz(len, NFS_MAXPATHLEN); 
1175 } 
1176 nfsm_mtouio(uiop, len); 
1177 } 
1178 nfsm_reqdone; 
1179 return (error); 
1180} 
1181 
1182/* 
1183 * nfs read rpc call 
1184 * Ditto above 
1185 */ 
1186int 
1187nfs_readrpc(vp, uiop) 
1188 struct vnode *vp; 
1189 struct uio *uiop; 
1190{ 
1191 u_int32_t *tl; 
1192 char *cp; 
1193 int32_t t1, t2; 
1194 char *bpos, *dpos, *cp2; 
1195 struct mbuf *mreq, *mrep, *md, *mb; 
1196 struct nfsmount *nmp; 
1197 int error = 0, len, retlen, tsiz, eof, byte_count; 
1198 const int v3 = NFS_ISV3(vp); 
1199 struct nfsnode *np = VTONFS(vp); 
1200#ifndef NFS_V2_ONLY 
1201 int attrflag; 
1202#endif 
1203 
1204#ifndef nolint 
1205 eof = 0; 
1206#endif 
1207 nmp = VFSTONFS(vp->v_mount); 
1208 tsiz = uiop->uio_resid; 
1209 if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) 
1210 return (EFBIG); 
1211 iostat_busy(nmp->nm_stats); 
1212 byte_count = 0; /* count bytes actually transferred */ 
1213 while (tsiz > 0) { 
1214 nfsstats.rpccnt[NFSPROC_READ]++; 
1215 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 
1216 nfsm_reqhead(np, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3); 
1217 nfsm_fhtom(np, v3); 
1218 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 3); 
1219#ifndef NFS_V2_ONLY 
1220 if (v3) { 
1221 txdr_hyper(uiop->uio_offset, tl); 
1222 *(tl + 2) = txdr_unsigned(len); 
1223 } else 
1224#endif 
1225 { 
1226 *tl++ = txdr_unsigned(uiop->uio_offset); 
1227 *tl++ = txdr_unsigned(len); 
1228 *tl = 0; 
1229 } 
1230 nfsm_request(np, NFSPROC_READ, curlwp, np->n_rcred); 
1231#ifndef NFS_V2_ONLY 
1232 if (v3) { 
1233 nfsm_postop_attr(vp, attrflag, NAC_NOTRUNC); 
1234 if (error) { 
1235 m_freem(mrep); 
1236 goto nfsmout; 
1237 } 
1238 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 
1239 eof = fxdr_unsigned(int, *(tl + 1)); 
1240 } else 
1241#endif 
1242 nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC); 
1243 nfsm_strsiz(retlen, nmp->nm_rsize); 
1244 nfsm_mtouio(uiop, retlen); 
1245 m_freem(mrep); 
1246 tsiz -= retlen; 
1247 byte_count += retlen; 
1248#ifndef NFS_V2_ONLY 
1249 if (v3) { 
1250 if (eof || retlen == 0) 
1251 tsiz = 0; 
1252 } else 
1253#endif 
1254 if (retlen < len) 
1255 tsiz = 0; 
1256 } 
1257nfsmout: 
1258 iostat_unbusy(nmp->nm_stats, byte_count, 1); 
1259 return (error); 
1260} 
1261 
1262struct nfs_writerpc_context { 
1263 kmutex_t nwc_lock; 
1264 kcondvar_t nwc_cv; 
1265 int nwc_mbufcount; 
1266}; 
1267 
1268/* 
1269 * free mbuf used to refer protected pages while write rpc call. 
1270 * called at splvm. 
1271 */ 
1272static void 
1273nfs_writerpc_extfree(struct mbuf *m, void *tbuf, size_t size, void *arg) 
1274{ 
1275 struct nfs_writerpc_context *ctx = arg; 
1276 
1277 KASSERT(m != NULL); 
1278 KASSERT(ctx != NULL); 
1279 pool_cache_put(mb_cache, m); 
1280 mutex_enter(&ctx->nwc_lock); 
1281 if (--ctx->nwc_mbufcount == 0) { 
1282 cv_signal(&ctx->nwc_cv); 
1283 } 
1284 mutex_exit(&ctx->nwc_lock); 
1285} 
1286 
1287/* 
1288 * nfs write call 
1289 */ 
1290int 
1291nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverfp) 
1292 struct vnode *vp; 
1293 struct uio *uiop; 
1294 int *iomode; 
1295 bool pageprotected; 
1296 bool *stalewriteverfp; 
1297{ 
1298 u_int32_t *tl; 
1299 char *cp; 
1300 int32_t t1, t2; 
1301 char *bpos, *dpos; 
1302 struct mbuf *mreq, *mrep, *md, *mb; 
1303 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 
1304 int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR; 
1305 const int v3 = NFS_ISV3(vp); 
1306 int committed = NFSV3WRITE_FILESYNC; 
1307 struct nfsnode *np = VTONFS(vp); 
1308 struct nfs_writerpc_context ctx; 
1309 int byte_count; 
1310 struct lwp *l = NULL; 
1311 size_t origresid; 
1312#ifndef NFS_V2_ONLY 
1313 char *cp2; 
1314 int rlen, commit; 
1315#endif 
1316 
1317 mutex_init(&ctx.nwc_lock, MUTEX_DRIVER, IPL_VM); 
1318 cv_init(&ctx.nwc_cv, "nfsmblk"); 
1319 ctx.nwc_mbufcount = 1; 
1320 
1321 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 
1322 panic("writerpc readonly vp %p", vp); 
1323 } 
1324 
1325#ifdef DIAGNOSTIC 
1326 if (uiop->uio_iovcnt != 1) 
1327 panic("nfs: writerpc iovcnt > 1"); 
1328#endif 
1329 tsiz = uiop->uio_resid; 
1330 if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) 
1331 return (EFBIG); 
1332 if (pageprotected) { 
1333 l = curlwp; 
1334 uvm_lwp_hold(l); 
1335 } 
1336retry: 
1337 origresid = uiop->uio_resid; 
1338 KASSERT(origresid == uiop->uio_iov->iov_len); 
1339 iostat_busy(nmp->nm_stats); 
1340 byte_count = 0; /* count of bytes actually written */ 
1341 while (tsiz > 0) { 
1342 uint32_t datalen; /* data bytes need to be allocated in mbuf */ 
1343 uint32_t backup; 
1344 bool stalewriteverf = false; 
1345 
1346 nfsstats.rpccnt[NFSPROC_WRITE]++; 
1347 len = min(tsiz, nmp->nm_wsize); 
1348 datalen = pageprotected ? 0 : nfsm_rndup(len); 
1349 nfsm_reqhead(np, NFSPROC_WRITE, 
1350 NFSX_FH(v3) + 5 * NFSX_UNSIGNED + datalen); 
1351 nfsm_fhtom(np, v3); 
1352#ifndef NFS_V2_ONLY 
1353 if (v3) { 
1354 nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 
1355 txdr_hyper(uiop->uio_offset, tl); 
1356 tl += 2; 
1357 *tl++ = txdr_unsigned(len); 
1358 *tl++ = txdr_unsigned(*iomode); 
1359 *tl = txdr_unsigned(len); 
1360 } else 
1361#endif 
1362 { 
1363 u_int32_t x; 
1364 
1365 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 
1366 /* Set both "begin" and "current" to non-garbage. */ 
1367 x = txdr_unsigned((u_int32_t)uiop->uio_offset); 
1368 *tl++ = x; /* "begin offset" */ 
1369 *tl++ = x; /* "current offset" */ 
1370 x = txdr_unsigned(len); 
1371 *tl++ = x; /* total to this offset */ 
1372 *tl = x; /* size of this write */ 
1373 
1374 } 
1375 if (pageprotected) { 
1376 /* 
1377 * since we know pages can't be modified during i/o, 
1378 * no need to copy them for us. 
1379 */ 
1380 struct mbuf *m; 
1381 struct iovec *iovp = uiop->uio_iov; 
1382 
1383 m = m_get(M_WAIT, MT_DATA); 
1384 MCLAIM(m, &nfs_mowner); 
1385 MEXTADD(m, iovp->iov_base, len, M_MBUF, 
1386 nfs_writerpc_extfree, &ctx); 
1387 m->m_flags |= M_EXT_ROMAP; 
1388 m->m_len = len; 
1389 mb->m_next = m; 
1390 /* 
1391 * no need to maintain mb and bpos here 
1392 * because no one care them later. 
1393 */ 
1394#if 0 
1395 mb = m; 
1396 bpos = mtod(void *, mb) + mb->m_len; 
1397#endif 
1398 UIO_ADVANCE(uiop, len); 
1399 uiop->uio_offset += len; 
1400 mutex_enter(&ctx.nwc_lock); 
1401 ctx.nwc_mbufcount++; 
1402 mutex_exit(&ctx.nwc_lock); 
1403 nfs_zeropad(mb, 0, nfsm_padlen(len)); 
1404 } else { 
1405 nfsm_uiotom(uiop, len); 
1406 } 
1407 nfsm_request(np, NFSPROC_WRITE, curlwp, np->n_wcred); 
1408#ifndef NFS_V2_ONLY 
1409 if (v3) { 
1410 wccflag = NFSV3_WCCCHK; 
1411 nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, !error); 
1412 if (!error) { 
1413 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED 
1414 + NFSX_V3WRITEVERF); 
1415 rlen = fxdr_unsigned(int, *tl++); 
1416 if (rlen == 0) { 
1417 error = NFSERR_IO; 
1418 m_freem(mrep); 
1419 break; 
1420 } else if (rlen < len) { 
1421 backup = len - rlen; 
1422 UIO_ADVANCE(uiop, -backup); 
1423 uiop->uio_offset -= backup; 
1424 len = rlen; 
1425 } 
1426 commit = fxdr_unsigned(int, *tl++); 
1427 
1428 /* 
1429 * Return the lowest committment level 
1430 * obtained by any of the RPCs. 
1431 */ 
1432 if (committed == NFSV3WRITE_FILESYNC) 
1433 committed = commit; 
1434 else if (committed == NFSV3WRITE_DATASYNC && 
1435 commit == NFSV3WRITE_UNSTABLE) 
1436 committed = commit; 
1437 mutex_enter(&nmp->nm_lock); 
1438 if ((nmp->nm_iflag & NFSMNT_HASWRITEVERF) == 0){ 
1439 memcpy(nmp->nm_writeverf, tl, 
1440 NFSX_V3WRITEVERF); 
1441 nmp->nm_iflag |= NFSMNT_HASWRITEVERF; 
1442 } else if ((nmp->nm_iflag & 
1443 NFSMNT_STALEWRITEVERF) || 
1444 memcmp(tl, nmp->nm_writeverf, 
1445 NFSX_V3WRITEVERF)) { 
1446 memcpy(nmp->nm_writeverf, tl, 
1447 NFSX_V3WRITEVERF); 
1448 /* 
1449 * note NFSMNT_STALEWRITEVERF 
1450 * if we're the first thread to 
1451 * notice it. 
1452 */ 
1453 if ((nmp->nm_iflag & 
1454 NFSMNT_STALEWRITEVERF) == 0) { 
1455 stalewriteverf = true; 
1456 nmp->nm_iflag |= 
1457 NFSMNT_STALEWRITEVERF; 
1458 } 
1459 } 
1460 mutex_exit(&nmp->nm_lock); 
1461 } 
1462 } else 
1463#endif 
1464 nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC); 
1465 if (wccflag) 
1466 VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr->va_mtime; 
1467 m_freem(mrep); 
1468 if (error) 
1469 break; 
1470 tsiz -= len; 
1471 byte_count += len; 
1472 if (stalewriteverf) { 
1473 *stalewriteverfp = true; 
1474 stalewriteverf = false; 
1475 if (committed == NFSV3WRITE_UNSTABLE && 
1476 len != origresid) { 
1477 /* 
1478 * if our write requests weren't atomic but 
1479 * unstable, datas in previous iterations 
1480 * might have already been lost now. 
1481 * then, we should resend them to nfsd. 
1482 */ 
1483 backup = origresid - tsiz; 
1484 UIO_ADVANCE(uiop, -backup); 
1485 uiop->uio_offset -= backup; 
1486 tsiz = origresid; 
1487 goto retry; 
1488 } 
1489 } 
1490 } 
1491nfsmout: 
1492 iostat_unbusy(nmp->nm_stats, byte_count, 0); 
1493 if (pageprotected) { 
1494 /* 
1495 * wait until mbufs go away. 
1496 * retransmitted mbufs can survive longer than rpc requests 
1497 * themselves. 
1498 */ 
1499 mutex_enter(&ctx.nwc_lock); 
1500 ctx.nwc_mbufcount--; 
1501 while (ctx.nwc_mbufcount > 0) { 
1502 cv_wait(&ctx.nwc_cv, &ctx.nwc_lock); 
1503 } 
1504 mutex_exit(&ctx.nwc_lock); 
1505 uvm_lwp_rele(l); 
1506 } 
1507 mutex_destroy(&ctx.nwc_lock); 
1508 cv_destroy(&ctx.nwc_cv); 
1509 *iomode = committed; 
1510 if (error) 
1511 uiop->uio_resid = tsiz; 
1512 return (error); 
1513} 
1514 
1515/* 
1516 * nfs mknod rpc 
1517 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 
1518 * mode set to specify the file type and the size field for rdev. 
1519 */ 
1520int 
1521nfs_mknodrpc(dvp, vpp, cnp, vap) 
1522 struct vnode *dvp; 
1523 struct vnode **vpp; 
1524 struct componentname *cnp; 
1525 struct vattr *vap; 
1526{ 
1527 struct nfsv2_sattr *sp; 
1528 u_int32_t *tl; 
1529 char *cp; 
1530 int32_t t1, t2; 
1531 struct vnode *newvp = (struct vnode *)0; 
1532 struct nfsnode *dnp, *np; 
1533 char *cp2; 
1534 char *bpos, *dpos; 
1535 int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0; 
1536 struct mbuf *mreq, *mrep, *md, *mb; 
1537 u_int32_t rdev; 
1538 const int v3 = NFS_ISV3(dvp); 
1539 
1540 if (vap->va_type == VCHR || vap->va_type == VBLK) 
1541 rdev = txdr_unsigned(vap->va_rdev); 
1542 else if (vap->va_type == VFIFO || vap->va_type == VSOCK) 
1543 rdev = nfs_xdrneg1; 
1544 else { 
1545 VOP_ABORTOP(dvp, cnp); 
1546 vput(dvp); 
1547 return (EOPNOTSUPP); 
1548 } 
1549 nfsstats.rpccnt[NFSPROC_MKNOD]++; 
1550 dnp = VTONFS(dvp); 
1551 nfsm_reqhead(dnp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED + 
1552 + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); 
1553 nfsm_fhtom(dnp, v3); 
1554 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 
1555#ifndef NFS_V2_ONLY 
1556 if (v3) { 
1557 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 
1558 *tl++ = vtonfsv3_type(vap->va_type); 
1559 nfsm_v3attrbuild(vap, false); 
1560 if (vap->va_type == VCHR || vap->va_type == VBLK) { 
1561 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 
1562 *tl++ = txdr_unsigned(major(vap->va_rdev)); 
1563 *tl = txdr_unsigned(minor(vap->va_rdev)); 
1564 } 
1565 } else 
1566#endif 
1567 { 
1568 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 
1569 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 
1570 sp->sa_uid = nfs_xdrneg1; 
1571 sp->sa_gid = nfs_xdrneg1; 
1572 sp->sa_size = rdev; 
1573 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 
1574 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 
1575 } 
1576 nfsm_request(dnp, NFSPROC_MKNOD, curlwp, cnp->cn_cred); 
1577 if (!error) { 
1578 nfsm_mtofh(dvp, newvp, v3, gotvp); 
1579 if (!gotvp) { 
1580 error = nfs_lookitup(dvp, cnp->cn_nameptr, 
1581 cnp->cn_namelen, cnp->cn_cred, curlwp, &np); 
1582 if (!error) 
1583 newvp = NFSTOV(np); 
1584 } 
1585 } 
1586#ifndef NFS_V2_ONLY 
1587 if (v3) 
1588 nfsm_wcc_data(dvp, wccflag, 0, !error); 
1589#endif 
1590 nfsm_reqdone; 
1591 if (error) { 
1592 if (newvp) 
1593 vput(newvp); 
1594 } else { 
1595 if (cnp->cn_flags & MAKEENTRY) 
1596 nfs_cache_enter(dvp, newvp, cnp); 
1597 *vpp = newvp; 
1598 } 
1599 PNBUF_PUT(cnp->cn_pnbuf); 
1600 VTONFS(dvp)->n_flag |= NMODIFIED; 
1601 if (!wccflag) 
1602 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
1603 vput(dvp); 
1604 return (error); 
1605} 
1606 
1607/* 
1608 * nfs mknod vop 
1609 * just call nfs_mknodrpc() to do the work. 
1610 */ 
1611/* ARGSUSED */ 
1612int 
1613nfs_mknod(v) 
1614 void *v; 
1615{ 
1616 struct vop_mknod_args /* { 
1617 struct vnode *a_dvp; 
1618 struct vnode **a_vpp; 
1619 struct componentname *a_cnp; 
1620 struct vattr *a_vap; 
1621 } */ *ap = v; 
1622 struct vnode *dvp = ap->a_dvp; 
1623 struct componentname *cnp = ap->a_cnp; 
1624 int error; 
1625 
1626 error = nfs_mknodrpc(dvp, ap->a_vpp, cnp, ap->a_vap); 
1627 VN_KNOTE(dvp, NOTE_WRITE); 
1628 if (error == 0 || error == EEXIST) 
1629 cache_purge1(dvp, cnp, 0); 
1630 return (error); 
1631} 
1632 
1633/* 
1634 * nfs file create call 
1635 */ 
1636int 
1637nfs_create(v) 
1638 void *v; 
1639{ 
1640 struct vop_create_args /* { 
1641 struct vnode *a_dvp; 
1642 struct vnode **a_vpp; 
1643 struct componentname *a_cnp; 
1644 struct vattr *a_vap; 
1645 } */ *ap = v; 
1646 struct vnode *dvp = ap->a_dvp; 
1647 struct vattr *vap = ap->a_vap; 
1648 struct componentname *cnp = ap->a_cnp; 
1649 struct nfsv2_sattr *sp; 
1650 u_int32_t *tl; 
1651 char *cp; 
1652 int32_t t1, t2; 
1653 struct nfsnode *dnp, *np = (struct nfsnode *)0; 
1654 struct vnode *newvp = (struct vnode *)0; 
1655 char *bpos, *dpos, *cp2; 
1656 int error, wccflag = NFSV3_WCCRATTR, gotvp = 0; 
1657 struct mbuf *mreq, *mrep, *md, *mb; 
1658 const int v3 = NFS_ISV3(dvp); 
1659 u_int32_t excl_mode = NFSV3CREATE_UNCHECKED; 
1660 
1661 /* 
1662 * Oops, not for me.. 
1663 */ 
1664 if (vap->va_type == VSOCK) 
1665 return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); 
1666 
1667 KASSERT(vap->va_type == VREG); 
1668 
1669#ifdef VA_EXCLUSIVE 
1670 if (vap->va_vaflags & VA_EXCLUSIVE) { 
1671 excl_mode = NFSV3CREATE_EXCLUSIVE; 
1672 } 
1673#endif 
1674again: 
1675 error = 0; 
1676 nfsstats.rpccnt[NFSPROC_CREATE]++; 
1677 dnp = VTONFS(dvp); 
1678 nfsm_reqhead(dnp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED + 
1679 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); 
1680 nfsm_fhtom(dnp, v3); 
1681 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 
1682#ifndef NFS_V2_ONLY 
1683 if (v3) { 
1684 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 
1685 if (excl_mode == NFSV3CREATE_EXCLUSIVE) { 
1686 *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE); 
1687 nfsm_build(tl, u_int32_t *, NFSX_V3CREATEVERF); 
1688 *tl++ = arc4random(); 
1689 *tl = arc4random(); 
1690 } else { 
1691 *tl = txdr_unsigned(excl_mode); 
1692 nfsm_v3attrbuild(vap, false); 
1693 } 
1694 } else 
1695#endif 
1696 { 
1697 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 
1698 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 
1699 sp->sa_uid = nfs_xdrneg1; 
1700 sp->sa_gid = nfs_xdrneg1; 
1701 sp->sa_size = 0; 
1702 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 
1703 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 
1704 } 
1705 nfsm_request(dnp, NFSPROC_CREATE, curlwp, cnp->cn_cred); 
1706 if (!error) { 
1707 nfsm_mtofh(dvp, newvp, v3, gotvp); 
1708 if (!gotvp) { 
1709 error = nfs_lookitup(dvp, cnp->cn_nameptr, 
1710 cnp->cn_namelen, cnp->cn_cred, curlwp, &np); 
1711 if (!error) 
1712 newvp = NFSTOV(np); 
1713 } 
1714 } 
1715#ifndef NFS_V2_ONLY 
1716 if (v3) 
1717 nfsm_wcc_data(dvp, wccflag, 0, !error); 
1718#endif 
1719 nfsm_reqdone; 
1720 if (error) { 
1721 /* 
1722 * nfs_request maps NFSERR_NOTSUPP to ENOTSUP. 
1723 */ 
1724 if (v3 && error == ENOTSUP) { 
1725 if (excl_mode == NFSV3CREATE_EXCLUSIVE) { 
1726 excl_mode = NFSV3CREATE_GUARDED; 
1727 goto again; 
1728 } else if (excl_mode == NFSV3CREATE_GUARDED) { 
1729 excl_mode = NFSV3CREATE_UNCHECKED; 
1730 goto again; 
1731 } 
1732 } 
1733 } else if (v3 && (excl_mode == NFSV3CREATE_EXCLUSIVE)) { 
1734 struct timespec ts; 
1735 
1736 getnanotime(&ts); 
1737 
1738 /* 
1739 * make sure that we'll update timestamps as 
1740 * most server implementations use them to store 
1741 * the create verifier. 
1742 * 
1743 * XXX it's better to use TOSERVER always. 
1744 */ 
1745 
1746 if (vap->va_atime.tv_sec == VNOVAL) 
1747 vap->va_atime = ts; 
1748 if (vap->va_mtime.tv_sec == VNOVAL) 
1749 vap->va_mtime = ts; 
1750 
1751 error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, curlwp); 
1752 } 
1753 if (error == 0) { 
1754 if (cnp->cn_flags & MAKEENTRY) 
1755 nfs_cache_enter(dvp, newvp, cnp); 
1756 else 
1757 cache_purge1(dvp, cnp, 0); 
1758 *ap->a_vpp = newvp; 
1759 } else { 
1760 if (newvp) 
1761 vput(newvp); 
1762 if (error == EEXIST) 
1763 cache_purge1(dvp, cnp, 0); 
1764 } 
1765 PNBUF_PUT(cnp->cn_pnbuf); 
1766 VTONFS(dvp)->n_flag |= NMODIFIED; 
1767 if (!wccflag) 
1768 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
1769 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 
1770 vput(dvp); 
1771 return (error); 
1772} 
1773 
1774/* 
1775 * nfs file remove call 
1776 * To try and make nfs semantics closer to ufs semantics, a file that has 
1777 * other processes using the vnode is renamed instead of removed and then 
1778 * removed later on the last close. 
1779 * - If v_usecount > 1 
1780 * If a rename is not already in the works 
1781 * call nfs_sillyrename() to set it up 
1782 * else 
1783 * do the remove rpc 
1784 */ 
1785int 
1786nfs_remove(v) 
1787 void *v; 
1788{ 
1789 struct vop_remove_args /* { 
1790 struct vnodeop_desc *a_desc; 
1791 struct vnode * a_dvp; 
1792 struct vnode * a_vp; 
1793 struct componentname * a_cnp; 
1794 } */ *ap = v; 
1795 struct vnode *vp = ap->a_vp; 
1796 struct vnode *dvp = ap->a_dvp; 
1797 struct componentname *cnp = ap->a_cnp; 
1798 struct nfsnode *np = VTONFS(vp); 
1799 int error = 0; 
1800 struct vattr vattr; 
1801 
1802#ifndef DIAGNOSTIC 
1803 if ((cnp->cn_flags & HASBUF) == 0) 
1804 panic("nfs_remove: no name"); 
1805 if (vp->v_usecount < 1) 
1806 panic("nfs_remove: bad v_usecount"); 
1807#endif 
1808 if (vp->v_type == VDIR) 
1809 error = EPERM; 
1810 else if (vp->v_usecount == 1 || (np->n_sillyrename && 
1811 VOP_GETATTR(vp, &vattr, cnp->cn_cred) == 0 && 
1812 vattr.va_nlink > 1)) { 
1813 /* 
1814 * Purge the name cache so that the chance of a lookup for 
1815 * the name succeeding while the remove is in progress is 
1816 * minimized. Without node locking it can still happen, such 
1817 * that an I/O op returns ESTALE, but since you get this if 
1818 * another host removes the file.. 
1819 */ 
1820 cache_purge(vp); 
1821 /* 
1822 * throw away biocache buffers, mainly to avoid 
1823 * unnecessary delayed writes later. 
1824 */ 
1825 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, curlwp, 1); 
1826 /* Do the rpc */ 
1827 if (error != EINTR) 
1828 error = nfs_removerpc(dvp, cnp->cn_nameptr, 
1829 cnp->cn_namelen, cnp->cn_cred, curlwp); 
1830 } else if (!np->n_sillyrename) 
1831 error = nfs_sillyrename(dvp, vp, cnp, false); 
1832 PNBUF_PUT(cnp->cn_pnbuf); 
1833 if (!error && nfs_getattrcache(vp, &vattr) == 0 && 
1834 vattr.va_nlink == 1) { 
1835 np->n_flag |= NREMOVED; 
1836 } 
1837 NFS_INVALIDATE_ATTRCACHE(np); 
1838 VN_KNOTE(vp, NOTE_DELETE); 
1839 VN_KNOTE(dvp, NOTE_WRITE); 
1840 if (dvp == vp) 
1841 vrele(vp); 
1842 else 
1843 vput(vp); 
1844 vput(dvp); 
1845 return (error); 
1846} 
1847 
1848/* 
1849 * nfs file remove rpc called from nfs_inactive 
1850 */ 
1851int 
1852nfs_removeit(sp) 
1853 struct sillyrename *sp; 
1854{ 
1855 
1856 return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred, 
1857 (struct lwp *)0)); 
1858} 
1859 
1860/* 
1861 * Nfs remove rpc, called from nfs_remove() and nfs_removeit(). 
1862 */ 
1863int 
1864nfs_removerpc(dvp, name, namelen, cred, l) 
1865 struct vnode *dvp; 
1866 const char *name; 
1867 int namelen; 
1868 kauth_cred_t cred; 
1869 struct lwp *l; 
1870{ 
1871 u_int32_t *tl; 
1872 char *cp; 
1873#ifndef NFS_V2_ONLY 
1874 int32_t t1; 
1875 char *cp2; 
1876#endif 
1877 int32_t t2; 
1878 char *bpos, *dpos; 
1879 int error = 0, wccflag = NFSV3_WCCRATTR; 
1880 struct mbuf *mreq, *mrep, *md, *mb; 
1881 const int v3 = NFS_ISV3(dvp); 
1882 int rexmit = 0; 
1883 struct nfsnode *dnp = VTONFS(dvp); 
1884 
1885 nfsstats.rpccnt[NFSPROC_REMOVE]++; 
1886 nfsm_reqhead(dnp, NFSPROC_REMOVE, 
1887 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen)); 
1888 nfsm_fhtom(dnp, v3); 
1889 nfsm_strtom(name, namelen, NFS_MAXNAMLEN); 
1890 nfsm_request1(dnp, NFSPROC_REMOVE, l, cred, &rexmit); 
1891#ifndef NFS_V2_ONLY 
1892 if (v3) 
1893 nfsm_wcc_data(dvp, wccflag, 0, !error); 
1894#endif 
1895 nfsm_reqdone; 
1896 VTONFS(dvp)->n_flag |= NMODIFIED; 
1897 if (!wccflag) 
1898 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
1899 /* 
1900 * Kludge City: If the first reply to the remove rpc is lost.. 
1901 * the reply to the retransmitted request will be ENOENT 
1902 * since the file was in fact removed 
1903 * Therefore, we cheat and return success. 
1904 */ 
1905 if (rexmit && error == ENOENT) 
1906 error = 0; 
1907 return (error); 
1908} 
1909 
1910/* 
1911 * nfs file rename call 
1912 */ 
1913int 
1914nfs_rename(v) 
1915 void *v; 
1916{ 
1917 struct vop_rename_args /* { 
1918 struct vnode *a_fdvp; 
1919 struct vnode *a_fvp; 
1920 struct componentname *a_fcnp; 
1921 struct vnode *a_tdvp; 
1922 struct vnode *a_tvp; 
1923 struct componentname *a_tcnp; 
1924 } */ *ap = v; 
1925 struct vnode *fvp = ap->a_fvp; 
1926 struct vnode *tvp = ap->a_tvp; 
1927 struct vnode *fdvp = ap->a_fdvp; 
1928 struct vnode *tdvp = ap->a_tdvp; 
1929 struct componentname *tcnp = ap->a_tcnp; 
1930 struct componentname *fcnp = ap->a_fcnp; 
1931 int error; 
1932 
1933#ifndef DIAGNOSTIC 
1934 if ((tcnp->cn_flags & HASBUF) == 0 || 
1935 (fcnp->cn_flags & HASBUF) == 0) 
1936 panic("nfs_rename: no name"); 
1937#endif 
1938 /* Check for cross-device rename */ 
1939 if ((fvp->v_mount != tdvp->v_mount) || 
1940 (tvp && (fvp->v_mount != tvp->v_mount))) { 
1941 error = EXDEV; 
1942 goto out; 
1943 } 
1944 
1945 /* 
1946 * If the tvp exists and is in use, sillyrename it before doing the 
1947 * rename of the new file over it. 
1948 * 
1949 * Have sillyrename use link instead of rename if possible, 
1950 * so that we don't lose the file if the rename fails, and so 
1951 * that there's no window when the "to" file doesn't exist. 
1952 */ 
1953 if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename && 
1954 tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp, true)) { 
1955 VN_KNOTE(tvp, NOTE_DELETE); 
1956 vput(tvp); 
1957 tvp = NULL; 
1958 } 
1959 
1960 error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, 
1961 tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, 
1962 curlwp); 
1963 
1964 VN_KNOTE(fdvp, NOTE_WRITE); 
1965 VN_KNOTE(tdvp, NOTE_WRITE); 
1966 if (error == 0 || error == EEXIST) { 
1967 if (fvp->v_type == VDIR) 
1968 cache_purge(fvp); 
1969 else 
1970 cache_purge1(fdvp, fcnp, 0); 
1971 if (tvp != NULL && tvp->v_type == VDIR) 
1972 cache_purge(tvp); 
1973 else 
1974 cache_purge1(tdvp, tcnp, 0); 
1975 } 
1976out: 
1977 if (tdvp == tvp) 
1978 vrele(tdvp); 
1979 else 
1980 vput(tdvp); 
1981 if (tvp) 
1982 vput(tvp); 
1983 vrele(fdvp); 
1984 vrele(fvp); 
1985 return (error); 
1986} 
1987 
1988/* 
1989 * nfs file rename rpc called from nfs_remove() above 
1990 */ 
1991int 
1992nfs_renameit(sdvp, scnp, sp) 
1993 struct vnode *sdvp; 
1994 struct componentname *scnp; 
1995 struct sillyrename *sp; 
1996{ 
1997 return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, 
1998 sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, curlwp)); 
1999} 
2000 
2001/* 
2002 * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). 
2003 */ 
2004int 
2005nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, l) 
2006 struct vnode *fdvp; 
2007 const char *fnameptr; 
2008 int fnamelen; 
2009 struct vnode *tdvp; 
2010 const char *tnameptr; 
2011 int tnamelen; 
2012 kauth_cred_t cred; 
2013 struct lwp *l; 
2014{ 
2015 u_int32_t *tl; 
2016 char *cp; 
2017#ifndef NFS_V2_ONLY 
2018 int32_t t1; 
2019 char *cp2; 
2020#endif 
2021 int32_t t2; 
2022 char *bpos, *dpos; 
2023 int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; 
2024 struct mbuf *mreq, *mrep, *md, *mb; 
2025 const int v3 = NFS_ISV3(fdvp); 
2026 int rexmit = 0; 
2027 struct nfsnode *fdnp = VTONFS(fdvp); 
2028 
2029 nfsstats.rpccnt[NFSPROC_RENAME]++; 
2030 nfsm_reqhead(fdnp, NFSPROC_RENAME, 
2031 (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + 
2032 nfsm_rndup(tnamelen)); 
2033 nfsm_fhtom(fdnp, v3); 
2034 nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN); 
2035 nfsm_fhtom(VTONFS(tdvp), v3); 
2036 nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN); 
2037 nfsm_request1(fdnp, NFSPROC_RENAME, l, cred, &rexmit); 
2038#ifndef NFS_V2_ONLY 
2039 if (v3) { 
2040 nfsm_wcc_data(fdvp, fwccflag, 0, !error); 
2041 nfsm_wcc_data(tdvp, twccflag, 0, !error); 
2042 } 
2043#endif 
2044 nfsm_reqdone; 
2045 VTONFS(fdvp)->n_flag |= NMODIFIED; 
2046 VTONFS(tdvp)->n_flag |= NMODIFIED; 
2047 if (!fwccflag) 
2048 NFS_INVALIDATE_ATTRCACHE(VTONFS(fdvp)); 
2049 if (!twccflag) 
2050 NFS_INVALIDATE_ATTRCACHE(VTONFS(tdvp)); 
2051 /* 
2052 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 
2053 */ 
2054 if (rexmit && error == ENOENT) 
2055 error = 0; 
2056 return (error); 
2057} 
2058 
2059/* 
2060 * NFS link RPC, called from nfs_link. 
2061 * Assumes dvp and vp locked, and leaves them that way. 
2062 */ 
2063 
2064static int 
2065nfs_linkrpc(struct vnode *dvp, struct vnode *vp, const char *name, 
2066 size_t namelen, kauth_cred_t cred, struct lwp *l) 
2067{ 
2068 u_int32_t *tl; 
2069 char *cp; 
2070#ifndef NFS_V2_ONLY 
2071 int32_t t1; 
2072 char *cp2; 
2073#endif 
2074 int32_t t2; 
2075 char *bpos, *dpos; 
2076 int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0; 
2077 struct mbuf *mreq, *mrep, *md, *mb; 
2078 const int v3 = NFS_ISV3(dvp); 
2079 int rexmit = 0; 
2080 struct nfsnode *np = VTONFS(vp); 
2081 
2082 nfsstats.rpccnt[NFSPROC_LINK]++; 
2083 nfsm_reqhead(np, NFSPROC_LINK, 
2084 NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(namelen)); 
2085 nfsm_fhtom(np, v3); 
2086 nfsm_fhtom(VTONFS(dvp), v3); 
2087 nfsm_strtom(name, namelen, NFS_MAXNAMLEN); 
2088 nfsm_request1(np, NFSPROC_LINK, l, cred, &rexmit); 
2089#ifndef NFS_V2_ONLY 
2090 if (v3) { 
2091 nfsm_postop_attr(vp, attrflag, 0); 
2092 nfsm_wcc_data(dvp, wccflag, 0, !error); 
2093 } 
2094#endif 
2095 nfsm_reqdone; 
2096 
2097 VTONFS(dvp)->n_flag |= NMODIFIED; 
2098 if (!attrflag) 
2099 NFS_INVALIDATE_ATTRCACHE(VTONFS(vp)); 
2100 if (!wccflag) 
2101 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
2102 
2103 /* 
2104 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 
2105 */ 
2106 if (rexmit && error == EEXIST) 
2107 error = 0; 
2108 
2109 return error; 
2110} 
2111 
2112/* 
2113 * nfs hard link create call 
2114 */ 
2115int 
2116nfs_link(v) 
2117 void *v; 
2118{ 
2119 struct vop_link_args /* { 
2120 struct vnode *a_dvp; 
2121 struct vnode *a_vp; 
2122 struct componentname *a_cnp; 
2123 } */ *ap = v; 
2124 struct vnode *vp = ap->a_vp; 
2125 struct vnode *dvp = ap->a_dvp; 
2126 struct componentname *cnp = ap->a_cnp; 
2127 int error = 0; 
2128 
2129 if (dvp->v_mount != vp->v_mount) { 
2130 VOP_ABORTOP(dvp, cnp); 
2131 vput(dvp); 
2132 return (EXDEV); 
2133 } 
2134 if (dvp != vp) { 
2135 error = vn_lock(vp, LK_EXCLUSIVE); 
2136 if (error != 0) { 
2137 VOP_ABORTOP(dvp, cnp); 
2138 vput(dvp); 
2139 return error; 
2140 } 
2141 } 
2142 
2143 /* 
2144 * Push all writes to the server, so that the attribute cache 
2145 * doesn't get "out of sync" with the server. 
2146 * XXX There should be a better way! 
2147 */ 
2148 VOP_FSYNC(vp, cnp->cn_cred, FSYNC_WAIT, 0, 0); 
2149 
2150 error = nfs_linkrpc(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen, 
2151 cnp->cn_cred, curlwp); 
2152 
2153 if (error == 0) 
2154 cache_purge1(dvp, cnp, 0); 
2155 PNBUF_PUT(cnp->cn_pnbuf); 
2156 if (dvp != vp) 
2157 VOP_UNLOCK(vp, 0); 
2158 VN_KNOTE(vp, NOTE_LINK); 
2159 VN_KNOTE(dvp, NOTE_WRITE); 
2160 vput(dvp); 
2161 return (error); 
2162} 
2163 
2164/* 
2165 * nfs symbolic link create call 
2166 */ 
2167int 
2168nfs_symlink(v) 
2169 void *v; 
2170{ 
2171 struct vop_symlink_args /* { 
2172 struct vnode *a_dvp; 
2173 struct vnode **a_vpp; 
2174 struct componentname *a_cnp; 
2175 struct vattr *a_vap; 
2176 char *a_target; 
2177 } */ *ap = v; 
2178 struct vnode *dvp = ap->a_dvp; 
2179 struct vattr *vap = ap->a_vap; 
2180 struct componentname *cnp = ap->a_cnp; 
2181 struct nfsv2_sattr *sp; 
2182 u_int32_t *tl; 
2183 char *cp; 
2184 int32_t t1, t2; 
2185 char *bpos, *dpos, *cp2; 
2186 int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp; 
2187 struct mbuf *mreq, *mrep, *md, *mb; 
2188 struct vnode *newvp = (struct vnode *)0; 
2189 const int v3 = NFS_ISV3(dvp); 
2190 int rexmit = 0; 
2191 struct nfsnode *dnp = VTONFS(dvp); 
2192 
2193 *ap->a_vpp = NULL; 
2194 nfsstats.rpccnt[NFSPROC_SYMLINK]++; 
2195 slen = strlen(ap->a_target); 
2196 nfsm_reqhead(dnp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED + 
2197 nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); 
2198 nfsm_fhtom(dnp, v3); 
2199 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 
2200#ifndef NFS_V2_ONlY 
2201 if (v3) 
2202 nfsm_v3attrbuild(vap, false); 
2203#endif 
2204 nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 
2205#ifndef NFS_V2_ONlY 
2206 if (!v3) { 
2207 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 
2208 sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode); 
2209 sp->sa_uid = nfs_xdrneg1; 
2210 sp->sa_gid = nfs_xdrneg1; 
2211 sp->sa_size = nfs_xdrneg1; 
2212 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 
2213 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 
2214 } 
2215#endif 
2216 nfsm_request1(dnp, NFSPROC_SYMLINK, curlwp, cnp->cn_cred, 
2217 &rexmit); 
2218#ifndef NFS_V2_ONlY 
2219 if (v3) { 
2220 if (!error) 
2221 nfsm_mtofh(dvp, newvp, v3, gotvp); 
2222 nfsm_wcc_data(dvp, wccflag, 0, !error); 
2223 } 
2224#endif 
2225 nfsm_reqdone; 
2226 /* 
2227 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 
2228 */ 
2229 if (rexmit && error == EEXIST) 
2230 error = 0; 
2231 if (error == 0 || error == EEXIST) 
2232 cache_purge1(dvp, cnp, 0); 
2233 if (error == 0 && newvp == NULL) { 
2234 struct nfsnode *np = NULL; 
2235 
2236 error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 
2237 cnp->cn_cred, curlwp, &np); 
2238 if (error == 0) 
2239 newvp = NFSTOV(np); 
2240 } 
2241 if (error) { 
2242 if (newvp != NULL) 
2243 vput(newvp); 
2244 } else { 
2245 *ap->a_vpp = newvp; 
2246 } 
2247 PNBUF_PUT(cnp->cn_pnbuf); 
2248 VTONFS(dvp)->n_flag |= NMODIFIED; 
2249 if (!wccflag) 
2250 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
2251 VN_KNOTE(dvp, NOTE_WRITE); 
2252 vput(dvp); 
2253 return (error); 
2254} 
2255 
2256/* 
2257 * nfs make dir call 
2258 */ 
2259int 
2260nfs_mkdir(v) 
2261 void *v; 
2262{ 
2263 struct vop_mkdir_args /* { 
2264 struct vnode *a_dvp; 
2265 struct vnode **a_vpp; 
2266 struct componentname *a_cnp; 
2267 struct vattr *a_vap; 
2268 } */ *ap = v; 
2269 struct vnode *dvp = ap->a_dvp; 
2270 struct vattr *vap = ap->a_vap; 
2271 struct componentname *cnp = ap->a_cnp; 
2272 struct nfsv2_sattr *sp; 
2273 u_int32_t *tl; 
2274 char *cp; 
2275 int32_t t1, t2; 
2276 int len; 
2277 struct nfsnode *dnp = VTONFS(dvp), *np = (struct nfsnode *)0; 
2278 struct vnode *newvp = (struct vnode *)0; 
2279 char *bpos, *dpos, *cp2; 
2280 int error = 0, wccflag = NFSV3_WCCRATTR; 
2281 int gotvp = 0; 
2282 int rexmit = 0; 
2283 struct mbuf *mreq, *mrep, *md, *mb; 
2284 const int v3 = NFS_ISV3(dvp); 
2285 
2286 len = cnp->cn_namelen; 
2287 nfsstats.rpccnt[NFSPROC_MKDIR]++; 
2288 nfsm_reqhead(dnp, NFSPROC_MKDIR, 
2289 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); 
2290 nfsm_fhtom(dnp, v3); 
2291 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 
2292#ifndef NFS_V2_ONLY 
2293 if (v3) { 
2294 nfsm_v3attrbuild(vap, false); 
2295 } else 
2296#endif 
2297 { 
2298 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 
2299 sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode); 
2300 sp->sa_uid = nfs_xdrneg1; 
2301 sp->sa_gid = nfs_xdrneg1; 
2302 sp->sa_size = nfs_xdrneg1; 
2303 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 
2304 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 
2305 } 
2306 nfsm_request1(dnp, NFSPROC_MKDIR, curlwp, cnp->cn_cred, &rexmit); 
2307 if (!error) 
2308 nfsm_mtofh(dvp, newvp, v3, gotvp); 
2309 if (v3) 
2310 nfsm_wcc_data(dvp, wccflag, 0, !error); 
2311 nfsm_reqdone; 
2312 VTONFS(dvp)->n_flag |= NMODIFIED; 
2313 if (!wccflag) 
2314 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
2315 /* 
2316 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 
2317 * if we can succeed in looking up the directory. 
2318 */ 
2319 if ((rexmit && error == EEXIST) || (!error && !gotvp)) { 
2320 if (newvp) { 
2321 vput(newvp); 
2322 newvp = (struct vnode *)0; 
2323 } 
2324 error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred, 
2325 curlwp, &np); 
2326 if (!error) { 
2327 newvp = NFSTOV(np); 
2328 if (newvp->v_type != VDIR || newvp == dvp) 
2329 error = EEXIST; 
2330 } 
2331 } 
2332 if (error) { 
2333 if (newvp) { 
2334 if (dvp != newvp) 
2335 vput(newvp); 
2336 else 
2337 vrele(newvp); 
2338 } 
2339 } else { 
2340 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 
2341 if (cnp->cn_flags & MAKEENTRY) 
2342 nfs_cache_enter(dvp, newvp, cnp); 
2343 *ap->a_vpp = newvp; 
2344 } 
2345 PNBUF_PUT(cnp->cn_pnbuf); 
2346 vput(dvp); 
2347 return (error); 
2348} 
2349 
2350/* 
2351 * nfs remove directory call 
2352 */ 
2353int 
2354nfs_rmdir(v) 
2355 void *v; 
2356{ 
2357 struct vop_rmdir_args /* { 
2358 struct vnode *a_dvp; 
2359 struct vnode *a_vp; 
2360 struct componentname *a_cnp; 
2361 } */ *ap = v; 
2362 struct vnode *vp = ap->a_vp; 
2363 struct vnode *dvp = ap->a_dvp; 
2364 struct componentname *cnp = ap->a_cnp; 
2365 u_int32_t *tl; 
2366 char *cp; 
2367#ifndef NFS_V2_ONLY 
2368 int32_t t1; 
2369 char *cp2; 
2370#endif 
2371 int32_t t2; 
2372 char *bpos, *dpos; 
2373 int error = 0, wccflag = NFSV3_WCCRATTR; 
2374 int rexmit = 0; 
2375 struct mbuf *mreq, *mrep, *md, *mb; 
2376 const int v3 = NFS_ISV3(dvp); 
2377 struct nfsnode *dnp; 
2378 
2379 if (dvp == vp) { 
2380 vrele(dvp); 
2381 vput(dvp); 
2382 PNBUF_PUT(cnp->cn_pnbuf); 
2383 return (EINVAL); 
2384 } 
2385 nfsstats.rpccnt[NFSPROC_RMDIR]++; 
2386 dnp = VTONFS(dvp); 
2387 nfsm_reqhead(dnp, NFSPROC_RMDIR, 
2388 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); 
2389 nfsm_fhtom(dnp, v3); 
2390 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 
2391 nfsm_request1(dnp, NFSPROC_RMDIR, curlwp, cnp->cn_cred, &rexmit); 
2392#ifndef NFS_V2_ONLY 
2393 if (v3) 
2394 nfsm_wcc_data(dvp, wccflag, 0, !error); 
2395#endif 
2396 nfsm_reqdone; 
2397 PNBUF_PUT(cnp->cn_pnbuf); 
2398 VTONFS(dvp)->n_flag |= NMODIFIED; 
2399 if (!wccflag) 
2400 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 
2401 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 
2402 VN_KNOTE(vp, NOTE_DELETE); 
2403 cache_purge(vp); 
2404 vput(vp); 
2405 vput(dvp); 
2406 /* 
2407 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 
2408 */ 
2409 if (rexmit && error == ENOENT) 
2410 error = 0; 
2411 return (error); 
2412} 
2413 
2414/* 
2415 * nfs readdir call 
2416 */ 
2417int 
2418nfs_readdir(v) 
2419 void *v; 
2420{ 
2421 struct vop_readdir_args /* { 
2422 struct vnode *a_vp; 
2423 struct uio *a_uio; 
2424 kauth_cred_t a_cred; 
2425 int *a_eofflag; 
2426 off_t **a_cookies; 
2427 int *a_ncookies; 
2428 } */ *ap = v; 
2429 struct vnode *vp = ap->a_vp; 
2430 struct uio *uio = ap->a_uio; 
2431 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 
2432 char *base = uio->uio_iov->iov_base; 
2433 int tresid, error; 
2434 size_t count, lost; 
2435 struct dirent *dp; 
2436 off_t *cookies = NULL; 
2437 int ncookies = 0, nc; 
2438 
2439 if (vp->v_type != VDIR) 
2440 return (EPERM); 
2441 
2442 lost = uio->uio_resid & (NFS_DIRFRAGSIZ - 1); 
2443 count = uio->uio_resid - lost; 
2444 if (count <= 0) 
2445 return (EINVAL); 
2446 
2447 /* 
2448 * Call nfs_bioread() to do the real work. 
2449 */ 
2450 tresid = uio->uio_resid = count; 
2451 error = nfs_bioread(vp, uio, 0, ap->a_cred, 
2452 ap->a_cookies ? NFSBIO_CACHECOOKIES : 0); 
2453 
2454 if (!error && ap->a_cookies) { 
2455 ncookies = count / 16; 
2456 cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK); 
2457 *ap->a_cookies = cookies; 
2458 } 
2459 
2460 if (!error && uio->uio_resid == tresid) { 
2461 uio->uio_resid += lost; 
2462 nfsstats.direofcache_misses++; 
2463 if (ap->a_cookies) 
2464 *ap->a_ncookies = 0; 
2465 *ap->a_eofflag = 1; 
2466 return (0); 
2467 } 
2468 
2469 if (!error && ap->a_cookies) { 
2470 /* 
2471 * Only the NFS server and emulations use cookies, and they 
2472 * load the directory block into system space, so we can 
2473 * just look at it directly. 
2474 */ 
2475 if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace) || 
2476 uio->uio_iovcnt != 1) 
2477 panic("nfs_readdir: lost in space"); 
2478 for (nc = 0; ncookies-- && 
2479 base < (char *)uio->uio_iov->iov_base; nc++){ 
2480 dp = (struct dirent *) base; 
2481 if (dp->d_reclen == 0) 
2482 break; 
2483 if (nmp->nm_flag & NFSMNT_XLATECOOKIE) 
2484 *(cookies++) = (off_t)NFS_GETCOOKIE32(dp); 
2485 else 
2486 *(cookies++) = NFS_GETCOOKIE(dp); 
2487 base += dp->d_reclen; 
2488 } 
2489 uio->uio_resid += 
2490 ((char *)uio->uio_iov->iov_base - base); 
2491 uio->uio_iov->iov_len += 
2492 ((char *)uio->uio_iov->iov_base - base); 
2493 uio->uio_iov->iov_base = base; 
2494 *ap->a_ncookies = nc; 
2495 } 
2496 
2497 uio->uio_resid += lost; 
2498 *ap->a_eofflag = 0; 
2499 return (error); 
2500} 
2501 
2502/* 
2503 * Readdir rpc call. 
2504 * Called from below the buffer cache by nfs_doio(). 
2505 */ 
2506int 
2507nfs_readdirrpc(vp, uiop, cred) 
2508 struct vnode *vp; 
2509 struct uio *uiop; 
2510 kauth_cred_t cred; 
2511{ 
2512 int len, left; 
2513 struct dirent *dp = NULL; 
2514 u_int32_t *tl; 
2515 char *cp; 
2516 int32_t t1, t2; 
2517 char *bpos, *dpos, *cp2; 
2518 struct mbuf *mreq, *mrep, *md, *mb; 
2519 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 
2520 struct nfsnode *dnp = VTONFS(vp); 
2521 u_quad_t fileno; 
2522 int error = 0, more_dirs = 1, blksiz = 0, bigenough = 1; 
2523#ifndef NFS_V2_ONLY 
2524 int attrflag; 
2525#endif 
2526 int nrpcs = 0, reclen; 
2527 const int v3 = NFS_ISV3(vp); 
2528 
2529#ifdef DIAGNOSTIC 
2530 /* 
2531 * Should be called from buffer cache, so only amount of 
2532 * NFS_DIRBLKSIZ will be requested. 
2533 */ 
2534 if (uiop->uio_iovcnt != 1 || uiop->uio_resid != NFS_DIRBLKSIZ) 
2535 panic("nfs readdirrpc bad uio"); 
2536#endif 
2537 
2538 /* 
2539 * Loop around doing readdir rpc's of size nm_readdirsize 
2540 * truncated to a multiple of NFS_DIRFRAGSIZ. 
2541 * The stopping criteria is EOF or buffer full. 
2542 */ 
2543 while (more_dirs && bigenough) { 
2544 /* 
2545 * Heuristic: don't bother to do another RPC to further 
2546 * fill up this block if there is not much room left. (< 50% 
2547 * of the readdir RPC size). This wastes some buffer space 
2548 * but can save up to 50% in RPC calls. 
2549 */ 
2550 if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) { 
2551 bigenough = 0; 
2552 break; 
2553 } 
2554 nfsstats.rpccnt[NFSPROC_READDIR]++; 
2555 nfsm_reqhead(dnp, NFSPROC_READDIR, NFSX_FH(v3) + 
2556 NFSX_READDIR(v3)); 
2557 nfsm_fhtom(dnp, v3); 
2558#ifndef NFS_V2_ONLY 
2559 if (v3) { 
2560 nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 
2561 if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) { 
2562 txdr_swapcookie3(uiop->uio_offset, tl); 
2563 } else { 
2564 txdr_cookie3(uiop->uio_offset, tl); 
2565 } 
2566 tl += 2; 
2567 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 
2568 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 
2569 } else 
2570#endif 
2571 { 
2572 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 
2573 *tl++ = txdr_unsigned(uiop->uio_offset); 
2574 } 
2575 *tl = txdr_unsigned(nmp->nm_readdirsize); 
2576 nfsm_request(dnp, NFSPROC_READDIR, curlwp, cred); 
2577 nrpcs++; 
2578#ifndef NFS_V2_ONLY 
2579 if (v3) { 
2580 nfsm_postop_attr(vp, attrflag, 0); 
2581 if (!error) { 
2582 nfsm_dissect(tl, u_int32_t *, 
2583 2 * NFSX_UNSIGNED); 
2584 dnp->n_cookieverf.nfsuquad[0] = *tl++; 
2585 dnp->n_cookieverf.nfsuquad[1] = *tl; 
2586 } else { 
2587 m_freem(mrep); 
2588 goto nfsmout; 
2589 } 
2590 } 
2591#endif 
2592 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
2593 more_dirs = fxdr_unsigned(int, *tl); 
2594 
2595 /* loop thru the dir entries, doctoring them to 4bsd form */ 
2596 while (more_dirs && bigenough) { 
2597#ifndef NFS_V2_ONLY 
2598 if (v3) { 
2599 nfsm_dissect(tl, u_int32_t *, 
2600 3 * NFSX_UNSIGNED); 
2601 fileno = fxdr_hyper(tl); 
2602 len = fxdr_unsigned(int, *(tl + 2)); 
2603 } else 
2604#endif 
2605 { 
2606 nfsm_dissect(tl, u_int32_t *, 
2607 2 * NFSX_UNSIGNED); 
2608 fileno = fxdr_unsigned(u_quad_t, *tl++); 
2609 len = fxdr_unsigned(int, *tl); 
2610 } 
2611 if (len <= 0 || len > NFS_MAXNAMLEN) { 
2612 error = EBADRPC; 
2613 m_freem(mrep); 
2614 goto nfsmout; 
2615 } 
2616 /* for cookie stashing */ 
2617 reclen = _DIRENT_RECLEN(dp, len) + 2 * sizeof(off_t); 
2618 left = NFS_DIRFRAGSIZ - blksiz; 
2619 if (reclen > left) { 
2620 memset(uiop->uio_iov->iov_base, 0, left); 
2621 dp->d_reclen += left; 
2622 UIO_ADVANCE(uiop, left); 
2623 blksiz = 0; 
2624 NFS_STASHCOOKIE(dp, uiop->uio_offset); 
2625 } 
2626 if (reclen > uiop->uio_resid) 
2627 bigenough = 0; 
2628 if (bigenough) { 
2629 int tlen; 
2630 
2631 dp = (struct dirent *)uiop->uio_iov->iov_base; 
2632 dp->d_fileno = fileno; 
2633 dp->d_namlen = len; 
2634 dp->d_reclen = reclen; 
2635 dp->d_type = DT_UNKNOWN; 
2636 blksiz += reclen; 
2637 if (blksiz == NFS_DIRFRAGSIZ) 
2638 blksiz = 0; 
2639 UIO_ADVANCE(uiop, DIRHDSIZ); 
2640 nfsm_mtouio(uiop, len); 
2641 tlen = reclen - (DIRHDSIZ + len); 
2642 (void)memset(uiop->uio_iov->iov_base, 0, tlen); 
2643 UIO_ADVANCE(uiop, tlen); 
2644 } else 
2645 nfsm_adv(nfsm_rndup(len)); 
2646#ifndef NFS_V2_ONLY 
2647 if (v3) { 
2648 nfsm_dissect(tl, u_int32_t *, 
2649 3 * NFSX_UNSIGNED); 
2650 } else 
2651#endif 
2652 { 
2653 nfsm_dissect(tl, u_int32_t *, 
2654 2 * NFSX_UNSIGNED); 
2655 } 
2656 if (bigenough) { 
2657#ifndef NFS_V2_ONLY 
2658 if (v3) { 
2659 if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) 
2660 uiop->uio_offset = 
2661 fxdr_swapcookie3(tl); 
2662 else 
2663 uiop->uio_offset = 
2664 fxdr_cookie3(tl); 
2665 } 
2666 else 
2667#endif 
2668 { 
2669 uiop->uio_offset = 
2670 fxdr_unsigned(off_t, *tl); 
2671 } 
2672 NFS_STASHCOOKIE(dp, uiop->uio_offset); 
2673 } 
2674 if (v3) 
2675 tl += 2; 
2676 else 
2677 tl++; 
2678 more_dirs = fxdr_unsigned(int, *tl); 
2679 } 
2680 /* 
2681 * If at end of rpc data, get the eof boolean 
2682 */ 
2683 if (!more_dirs) { 
2684 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
2685 more_dirs = (fxdr_unsigned(int, *tl) == 0); 
2686 
2687 /* 
2688 * kludge: if we got no entries, treat it as EOF. 
2689 * some server sometimes send a reply without any 
2690 * entries or EOF. 
2691 * although it might mean the server has very long name, 
2692 * we can't handle such entries anyway. 
2693 */ 
2694 
2695 if (uiop->uio_resid >= NFS_DIRBLKSIZ) 
2696 more_dirs = 0; 
2697 } 
2698 m_freem(mrep); 
2699 } 
2700 /* 
2701 * Fill last record, iff any, out to a multiple of NFS_DIRFRAGSIZ 
2702 * by increasing d_reclen for the last record. 
2703 */ 
2704 if (blksiz > 0) { 
2705 left = NFS_DIRFRAGSIZ - blksiz; 
2706 memset(uiop->uio_iov->iov_base, 0, left); 
2707 dp->d_reclen += left; 
2708 NFS_STASHCOOKIE(dp, uiop->uio_offset); 
2709 UIO_ADVANCE(uiop, left); 
2710 } 
2711 
2712 /* 
2713 * We are now either at the end of the directory or have filled the 
2714 * block. 
2715 */ 
2716 if (bigenough) { 
2717 dnp->n_direofoffset = uiop->uio_offset; 
2718 dnp->n_flag |= NEOFVALID; 
2719 } 
2720nfsmout: 
2721 return (error); 
2722} 
2723 
2724#ifndef NFS_V2_ONLY 
2725/* 
2726 * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc(). 
2727 */ 
2728int 
2729nfs_readdirplusrpc(vp, uiop, cred) 
2730 struct vnode *vp; 
2731 struct uio *uiop; 
2732 kauth_cred_t cred; 
2733{ 
2734 int len, left; 
2735 struct dirent *dp = NULL; 
2736 u_int32_t *tl; 
2737 char *cp; 
2738 int32_t t1, t2; 
2739 struct vnode *newvp; 
2740 char *bpos, *dpos, *cp2; 
2741 struct mbuf *mreq, *mrep, *md, *mb; 
2742 struct nameidata nami, *ndp = &nami; 
2743 struct componentname *cnp = &ndp->ni_cnd; 
2744 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 
2745 struct nfsnode *dnp = VTONFS(vp), *np; 
2746 nfsfh_t *fhp; 
2747 u_quad_t fileno; 
2748 int error = 0, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i; 
2749 int attrflag, fhsize, nrpcs = 0, reclen; 
2750 struct nfs_fattr fattr, *fp; 
2751 
2752#ifdef DIAGNOSTIC 
2753 if (uiop->uio_iovcnt != 1 || uiop->uio_resid != NFS_DIRBLKSIZ) 
2754 panic("nfs readdirplusrpc bad uio"); 
2755#endif 
2756 ndp->ni_dvp = vp; 
2757 newvp = NULLVP; 
2758 
2759 /* 
2760 * Loop around doing readdir rpc's of size nm_readdirsize 
2761 * truncated to a multiple of NFS_DIRFRAGSIZ. 
2762 * The stopping criteria is EOF or buffer full. 
2763 */ 
2764 while (more_dirs && bigenough) { 
2765 if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) { 
2766 bigenough = 0; 
2767 break; 
2768 } 
2769 nfsstats.rpccnt[NFSPROC_READDIRPLUS]++; 
2770 nfsm_reqhead(dnp, NFSPROC_READDIRPLUS, 
2771 NFSX_FH(1) + 6 * NFSX_UNSIGNED); 
2772 nfsm_fhtom(dnp, 1); 
2773 nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 
2774 if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) { 
2775 txdr_swapcookie3(uiop->uio_offset, tl); 
2776 } else { 
2777 txdr_cookie3(uiop->uio_offset, tl); 
2778 } 
2779 tl += 2; 
2780 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 
2781 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 
2782 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 
2783 *tl = txdr_unsigned(nmp->nm_rsize); 
2784 nfsm_request(dnp, NFSPROC_READDIRPLUS, curlwp, cred); 
2785 nfsm_postop_attr(vp, attrflag, 0); 
2786 if (error) { 
2787 m_freem(mrep); 
2788 goto nfsmout; 
2789 } 
2790 nrpcs++; 
2791 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 
2792 dnp->n_cookieverf.nfsuquad[0] = *tl++; 
2793 dnp->n_cookieverf.nfsuquad[1] = *tl++; 
2794 more_dirs = fxdr_unsigned(int, *tl); 
2795 
2796 /* loop thru the dir entries, doctoring them to 4bsd form */ 
2797 while (more_dirs && bigenough) { 
2798 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 
2799 fileno = fxdr_hyper(tl); 
2800 len = fxdr_unsigned(int, *(tl + 2)); 
2801 if (len <= 0 || len > NFS_MAXNAMLEN) { 
2802 error = EBADRPC; 
2803 m_freem(mrep); 
2804 goto nfsmout; 
2805 } 
2806 /* for cookie stashing */ 
2807 reclen = _DIRENT_RECLEN(dp, len) + 2 * sizeof(off_t); 
2808 left = NFS_DIRFRAGSIZ - blksiz; 
2809 if (reclen > left) { 
2810 /* 
2811 * DIRFRAGSIZ is aligned, no need to align 
2812 * again here. 
2813 */ 
2814 memset(uiop->uio_iov->iov_base, 0, left); 
2815 dp->d_reclen += left; 
2816 UIO_ADVANCE(uiop, left); 
2817 NFS_STASHCOOKIE(dp, uiop->uio_offset); 
2818 blksiz = 0; 
2819 } 
2820 if (reclen > uiop->uio_resid) 
2821 bigenough = 0; 
2822 if (bigenough) { 
2823 int tlen; 
2824 
2825 dp = (struct dirent *)uiop->uio_iov->iov_base; 
2826 dp->d_fileno = fileno; 
2827 dp->d_namlen = len; 
2828 dp->d_reclen = reclen; 
2829 dp->d_type = DT_UNKNOWN; 
2830 blksiz += reclen; 
2831 if (blksiz == NFS_DIRFRAGSIZ) 
2832 blksiz = 0; 
2833 UIO_ADVANCE(uiop, DIRHDSIZ); 
2834 nfsm_mtouio(uiop, len); 
2835 tlen = reclen - (DIRHDSIZ + len); 
2836 (void)memset(uiop->uio_iov->iov_base, 0, tlen); 
2837 UIO_ADVANCE(uiop, tlen); 
2838 cnp->cn_nameptr = dp->d_name; 
2839 cnp->cn_namelen = dp->d_namlen; 
2840 } else 
2841 nfsm_adv(nfsm_rndup(len)); 
2842 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 
2843 if (bigenough) { 
2844 if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) 
2845 uiop->uio_offset = 
2846 fxdr_swapcookie3(tl); 
2847 else 
2848 uiop->uio_offset = 
2849 fxdr_cookie3(tl); 
2850 NFS_STASHCOOKIE(dp, uiop->uio_offset); 
2851 } 
2852 tl += 2; 
2853 
2854 /* 
2855 * Since the attributes are before the file handle 
2856 * (sigh), we must skip over the attributes and then 
2857 * come back and get them. 
2858 */ 
2859 attrflag = fxdr_unsigned(int, *tl); 
2860 if (attrflag) { 
2861 nfsm_dissect(fp, struct nfs_fattr *, NFSX_V3FATTR); 
2862 memcpy(&fattr, fp, NFSX_V3FATTR); 
2863 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
2864 doit = fxdr_unsigned(int, *tl); 
2865 if (doit) { 
2866 nfsm_getfh(fhp, fhsize, 1); 
2867 if (NFS_CMPFH(dnp, fhp, fhsize)) { 
2868 VREF(vp); 
2869 newvp = vp; 
2870 np = dnp; 
2871 } else { 
2872 error = nfs_nget1(vp->v_mount, fhp, 
2873 fhsize, &np, LK_NOWAIT); 
2874 if (!error) 
2875 newvp = NFSTOV(np); 
2876 } 
2877 if (!error) { 
2878 const char *xcp; 
2879 
2880 nfs_loadattrcache(&newvp, &fattr, 0, 0); 
2881 if (bigenough) { 
2882 dp->d_type = 
2883 IFTODT(VTTOIF(np->n_vattr->va_type)); 
2884 if (cnp->cn_namelen <= NCHNAMLEN) { 
2885 ndp->ni_vp = newvp; 
2886 xcp = cnp->cn_nameptr + 
2887 cnp->cn_namelen; 
2888 cnp->cn_hash = 
2889 namei_hash(cnp->cn_nameptr, &xcp); 
2890 nfs_cache_enter(ndp->ni_dvp, 
2891 ndp->ni_vp, cnp); 
2892 } 
2893 } 
2894 } 
2895 error = 0; 
2896 } 
2897 } else { 
2898 /* Just skip over the file handle */ 
2899 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
2900 i = fxdr_unsigned(int, *tl); 
2901 nfsm_adv(nfsm_rndup(i)); 
2902 } 
2903 if (newvp != NULLVP) { 
2904 if (newvp == vp) 
2905 vrele(newvp); 
2906 else 
2907 vput(newvp); 
2908 newvp = NULLVP; 
2909 } 
2910 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
2911 more_dirs = fxdr_unsigned(int, *tl); 
2912 } 
2913 /* 
2914 * If at end of rpc data, get the eof boolean 
2915 */ 
2916 if (!more_dirs) { 
2917 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 
2918 more_dirs = (fxdr_unsigned(int, *tl) == 0); 
2919 
2920 /* 
2921 * kludge: see a comment in nfs_readdirrpc. 
2922 */ 
2923 
2924 if (uiop->uio_resid >= NFS_DIRBLKSIZ) 
2925 more_dirs = 0; 
2926 } 
2927 m_freem(mrep); 
2928 } 
2929 /* 
2930 * Fill last record, iff any, out to a multiple of NFS_DIRFRAGSIZ 
2931 * by increasing d_reclen for the last record. 
2932 */ 
2933 if (blksiz > 0) { 
2934 left = NFS_DIRFRAGSIZ - blksiz; 
2935 memset(uiop->uio_iov->iov_base, 0, left); 
2936 dp->d_reclen += left; 
2937 NFS_STASHCOOKIE(dp, uiop->uio_offset); 
2938 UIO_ADVANCE(uiop, left); 
2939 } 
2940 
2941 /* 
2942 * We are now either at the end of the directory or have filled the 
2943 * block. 
2944 */ 
2945 if (bigenough) { 
2946 dnp->n_direofoffset = uiop->uio_offset; 
2947 dnp->n_flag |= NEOFVALID; 
2948 } 
2949nfsmout: 
2950 if (newvp != NULLVP) { 
2951 if(newvp == vp) 
2952 vrele(newvp); 
2953 else 
2954 vput(newvp); 
2955 } 
2956 return (error); 
2957} 
2958#endif 
2959 
2960/* 
2961 * Silly rename. To make the NFS filesystem that is stateless look a little 
2962 * more like the "ufs" a remove of an active vnode is translated to a rename 
2963 * to a funny looking filename that is removed by nfs_inactive on the 
2964 * nfsnode. There is the potential for another process on a different client 
2965 * to create the same funny name between the nfs_lookitup() fails and the 
2966 * nfs_rename() completes, but... 
2967 */ 
2968int 
2969nfs_sillyrename(dvp, vp, cnp, dolink) 
2970 struct vnode *dvp, *vp; 
2971 struct componentname *cnp; 
2972 bool dolink; 
2973{ 
2974 struct sillyrename *sp; 
2975 struct nfsnode *np; 
2976 int error; 
2977 short pid; 
2978 
2979 cache_purge(dvp); 
2980 np = VTONFS(vp); 
2981#ifndef DIAGNOSTIC 
2982 if (vp->v_type == VDIR) 
2983 panic("nfs: sillyrename dir"); 
2984#endif 
2985 sp = kmem_alloc(sizeof(*sp), KM_SLEEP); 
2986 sp->s_cred = kauth_cred_dup(cnp->cn_cred); 
2987 sp->s_dvp = dvp; 
2988 VREF(dvp); 
2989 
2990 /* Fudge together a funny name */ 
2991 pid = curlwp->l_proc->p_pid; 
2992 memcpy(sp->s_name, ".nfsAxxxx4.4", 13); 
2993 sp->s_namlen = 12; 
2994 sp->s_name[8] = hexdigits[pid & 0xf]; 
2995 sp->s_name[7] = hexdigits[(pid >> 4) & 0xf]; 
2996 sp->s_name[6] = hexdigits[(pid >> 8) & 0xf]; 
2997 sp->s_name[5] = hexdigits[(pid >> 12) & 0xf]; 
2998 
2999 /* Try lookitups until we get one that isn't there */ 
3000 while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 
3001 curlwp, (struct nfsnode **)0) == 0) { 
3002 sp->s_name[4]++; 
3003 if (sp->s_name[4] > 'z') { 
3004 error = EINVAL; 
3005 goto bad; 
3006 } 
3007 } 
3008 if (dolink) { 
3009 error = nfs_linkrpc(dvp, vp, sp->s_name, sp->s_namlen, 
3010 sp->s_cred, curlwp); 
3011 /* 
3012 * nfs_request maps NFSERR_NOTSUPP to ENOTSUP. 
3013 */ 
3014 if (error == ENOTSUP) { 
3015 error = nfs_renameit(dvp, cnp, sp); 
3016 } 
3017 } else { 
3018 error = nfs_renameit(dvp, cnp, sp); 
3019 } 
3020 if (error) 
3021 goto bad; 
3022 error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 
3023 curlwp, &np); 
3024 np->n_sillyrename = sp; 
3025 return (0); 
3026bad: 
3027 vrele(sp->s_dvp); 
3028 kauth_cred_free(sp->s_cred); 
3029 kmem_free(sp, sizeof(*sp)); 
3030 return (error); 
3031} 
3032 
3033/* 
3034 * Look up a file name and optionally either update the file handle or 
3035 * allocate an nfsnode, depending on the value of npp. 
3036 * npp == NULL --> just do the lookup 
3037 * *npp == NULL --> allocate a new nfsnode and make sure attributes are 
3038 * handled too 
3039 * *npp != NULL --> update the file handle in the vnode 
3040 */ 
3041int 
3042nfs_lookitup(dvp, name, len, cred, l, npp) 
3043 struct vnode *dvp; 
3044 const char *name; 
3045 int len; 
3046 kauth_cred_t cred; 
3047 struct lwp *l; 
3048 struct nfsnode **npp; 
3049{ 
3050 u_int32_t *tl; 
3051 char *cp; 
3052 int32_t t1, t2; 
3053 struct vnode *newvp = (struct vnode *)0; 
3054 struct nfsnode *np, *dnp = VTONFS(dvp); 
3055 char *bpos, *dpos, *cp2; 
3056 int error = 0, fhlen; 
3057#ifndef NFS_V2_ONLY 
3058 int attrflag; 
3059#endif 
3060 struct mbuf *mreq, *mrep, *md, *mb; 
3061 nfsfh_t *nfhp; 
3062 const int v3 = NFS_ISV3(dvp); 
3063 
3064 nfsstats.rpccnt[NFSPROC_LOOKUP]++; 
3065 nfsm_reqhead(dnp, NFSPROC_LOOKUP, 
3066 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); 
3067 nfsm_fhtom(dnp, v3); 
3068 nfsm_strtom(name, len, NFS_MAXNAMLEN); 
3069 nfsm_request(dnp, NFSPROC_LOOKUP, l, cred); 
3070 if (npp && !error) { 
3071 nfsm_getfh(nfhp, fhlen, v3); 
3072 if (*npp) { 
3073 np = *npp; 
3074 if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) { 
3075 kmem_free(np->n_fhp, np->n_fhsize); 
3076 np->n_fhp = &np->n_fh; 
3077 } 
3078#if NFS_SMALLFH < NFSX_V3FHMAX 
3079 else if (np->n_fhsize <= NFS_SMALLFH && fhlen > NFS_SMALLFH) 
3080 np->n_fhp = kmem_alloc(fhlen, KM_SLEEP); 
3081#endif 
3082 memcpy(np->n_fhp, nfhp, fhlen); 
3083 np->n_fhsize = fhlen; 
3084 newvp = NFSTOV(np); 
3085 } else if (NFS_CMPFH(dnp, nfhp, fhlen)) { 
3086 VREF(dvp); 
3087 newvp = dvp; 
3088 np = dnp; 
3089 } else { 
3090 error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np); 
3091 if (error) { 
3092 m_freem(mrep); 
3093 return (error); 
3094 } 
3095 newvp = NFSTOV(np); 
3096 } 
3097#ifndef NFS_V2_ONLY 
3098 if (v3) { 
3099 nfsm_postop_attr(newvp, attrflag, 0); 
3100 if (!attrflag && *npp == NULL) { 
3101 m_freem(mrep); 
3102 vput(newvp); 
3103 return (ENOENT); 
3104 } 
3105 } else 
3106#endif 
3107 nfsm_loadattr(newvp, (struct vattr *)0, 0); 
3108 } 
3109 nfsm_reqdone; 
3110 if (npp && *npp == NULL) { 
3111 if (error) { 
3112 if (newvp) 
3113 vput(newvp); 
3114 } else 
3115 *npp = np; 
3116 } 
3117 return (error); 
3118} 
3119 
3120#ifndef NFS_V2_ONLY 
3121/* 
3122 * Nfs Version 3 commit rpc 
3123 */ 
3124int 
3125nfs_commit(vp, offset, cnt, l) 
3126 struct vnode *vp; 
3127 off_t offset; 
3128 uint32_t cnt; 
3129 struct lwp *l; 
3130{ 
3131 char *cp; 
3132 u_int32_t *tl; 
3133 int32_t t1, t2; 
3134 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 
3135 char *bpos, *dpos, *cp2; 
3136 int error = 0, wccflag = NFSV3_WCCRATTR; 
3137 struct mbuf *mreq, *mrep, *md, *mb; 
3138 struct nfsnode *np; 
3139 
3140 KASSERT(NFS_ISV3(vp)); 
3141 
3142#ifdef NFS_DEBUG_COMMIT 
3143 printf("commit %lu - %lu\n", (unsigned long)offset, 
3144 (unsigned long)(offset + cnt)); 
3145#endif 
3146 
3147 mutex_enter(&nmp->nm_lock); 
3148 if ((nmp->nm_iflag & NFSMNT_HASWRITEVERF) == 0) { 
3149 mutex_exit(&nmp->nm_lock); 
3150 return (0); 
3151 } 
3152 mutex_exit(&nmp->nm_lock); 
3153 nfsstats.rpccnt[NFSPROC_COMMIT]++; 
3154 np = VTONFS(vp); 
3155 nfsm_reqhead(np, NFSPROC_COMMIT, NFSX_FH(1)); 
3156 nfsm_fhtom(np, 1); 
3157 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 
3158 txdr_hyper(offset, tl); 
3159 tl += 2; 
3160 *tl = txdr_unsigned(cnt); 
3161 nfsm_request(np, NFSPROC_COMMIT, l, np->n_wcred); 
3162 nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, false); 
3163 if (!error) { 
3164 nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF); 
3165 mutex_enter(&nmp->nm_lock); 
3166 if ((nmp->nm_iflag & NFSMNT_STALEWRITEVERF) || 
3167 memcmp(nmp->nm_writeverf, tl, NFSX_V3WRITEVERF)) { 
3168 memcpy(nmp->nm_writeverf, tl, NFSX_V3WRITEVERF); 
3169 error = NFSERR_STALEWRITEVERF; 
3170 nmp->nm_iflag |= NFSMNT_STALEWRITEVERF; 
3171 } 
3172 mutex_exit(&nmp->nm_lock); 
3173 } 
3174 nfsm_reqdone; 
3175 return (error); 
3176} 
3177#endif 
3178 
3179/* 
3180 * Kludge City.. 
3181 * - make nfs_bmap() essentially a no-op that does no translation 
3182 * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc 
3183 * (Maybe I could use the process's page mapping, but I was concerned that 
3184 * Kernel Write might not be enabled and also figured copyout() would do 
3185 * a lot more work than memcpy() and also it currently happens in the 
3186 * context of the swapper process (2). 
3187 */ 
3188int 
3189nfs_bmap(v) 
3190 void *v; 
3191{ 
3192 struct vop_bmap_args /* { 
3193 struct vnode *a_vp; 
3194 daddr_t a_bn; 
3195 struct vnode **a_vpp; 
3196 daddr_t *a_bnp; 
3197 int *a_runp; 
3198 } */ *ap = v; 
3199 struct vnode *vp = ap->a_vp; 
3200 int bshift = vp->v_mount->mnt_fs_bshift - vp->v_mount->mnt_dev_bshift; 
3201 
3202 if (ap->a_vpp != NULL) 
3203 *ap->a_vpp = vp; 
3204 if (ap->a_bnp != NULL) 
3205 *ap->a_bnp = ap->a_bn << bshift; 
3206 if (ap->a_runp != NULL) 
3207 *ap->a_runp = 1024 * 1024; /* XXX */ 
3208 return (0); 
3209} 
3210 
3211/* 
3212 * Strategy routine. 
3213 * For async requests when nfsiod(s) are running, queue the request by 
3214 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the 
3215 * request. 
3216 */ 
3217int 
3218nfs_strategy(v) 
3219 void *v; 
3220{ 
3221 struct vop_strategy_args *ap = v; 
3222 struct buf *bp = ap->a_bp; 
3223 int error = 0; 
3224 
3225 if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC)) 
3226 panic("nfs physio/async"); 
3227 
3228 /* 
3229 * If the op is asynchronous and an i/o daemon is waiting 
3230 * queue the request, wake it up and wait for completion 
3231 * otherwise just do it ourselves. 
3232 */ 
3233 if ((bp->b_flags & B_ASYNC) == 0 || nfs_asyncio(bp)) 
3234 error = nfs_doio(bp); 
3235 return (error); 
3236} 
3237 
3238/* 
3239 * fsync vnode op. Just call nfs_flush() with commit == 1. 
3240 */ 
3241/* ARGSUSED */ 
3242int 
3243nfs_fsync(v) 
3244 void *v; 
3245{ 
3246 struct vop_fsync_args /* { 
3247 struct vnodeop_desc *a_desc; 
3248 struct vnode * a_vp; 
3249 kauth_cred_t a_cred; 
3250 int a_flags; 
3251 off_t offlo; 
3252 off_t offhi; 
3253 struct lwp * a_l; 
3254 } */ *ap = v; 
3255 
3256 struct vnode *vp = ap->a_vp; 
3257 
3258 if (vp->v_type != VREG) 
3259 return 0; 
3260 
3261 return (nfs_flush(vp, ap->a_cred, 
3262 (ap->a_flags & FSYNC_WAIT) != 0 ? MNT_WAIT : 0, curlwp, 1)); 
3263} 
3264 
3265/* 
3266 * Flush all the data associated with a vnode. 
3267 */ 
3268int 
3269nfs_flush(struct vnode *vp, kauth_cred_t cred, int waitfor, struct lwp *l, 
3270 int commit) 
3271{ 
3272 struct nfsnode *np = VTONFS(vp); 
3273 int error; 
3274 int flushflags = PGO_ALLPAGES|PGO_CLEANIT|PGO_SYNCIO; 
3275 UVMHIST_FUNC("nfs_flush"); UVMHIST_CALLED(ubchist); 
3276 
3277 mutex_enter(&vp->v_interlock); 
3278 error = VOP_PUTPAGES(vp, 0, 0, flushflags); 
3279 if (np->n_flag & NWRITEERR) { 
3280 error = np->n_error; 
3281 np->n_flag &= ~NWRITEERR; 
3282 } 
3283 UVMHIST_LOG(ubchist, "returning %d", error,0,0,0); 
3284 return (error); 
3285} 
3286 
3287/* 
3288 * Return POSIX pathconf information applicable to nfs. 
3289 * 
3290 * N.B. The NFS V2 protocol doesn't support this RPC. 
3291 */ 
3292/* ARGSUSED */ 
3293int 
3294nfs_pathconf(v) 
3295 void *v; 
3296{ 
3297 struct vop_pathconf_args /* { 
3298 struct vnode *a_vp; 
3299 int a_name; 
3300 register_t *a_retval; 
3301 } */ *ap = v; 
3302 struct nfsv3_pathconf *pcp; 
3303 struct vnode *vp = ap->a_vp; 
3304 struct mbuf *mreq, *mrep, *md, *mb; 
3305 int32_t t1, t2; 
3306 u_int32_t *tl; 
3307 char *bpos, *dpos, *cp, *cp2; 
3308 int error = 0, attrflag; 
3309#ifndef NFS_V2_ONLY 
3310 struct nfsmount *nmp; 
3311 unsigned int l; 
3312 u_int64_t maxsize; 
3313#endif 
3314 const int v3 = NFS_ISV3(vp); 
3315 struct nfsnode *np = VTONFS(vp); 
3316 
3317 switch (ap->a_name) { 
3318 /* Names that can be resolved locally. */ 
3319 case _PC_PIPE_BUF: 
3320 *ap->a_retval = PIPE_BUF; 
3321 break; 
3322 case _PC_SYNC_IO: 
3323 *ap->a_retval = 1; 
3324 break; 
3325 /* Names that cannot be resolved locally; do an RPC, if possible. */ 
3326 case _PC_LINK_MAX: 
3327 case _PC_NAME_MAX: 
3328 case _PC_CHOWN_RESTRICTED: 
3329 case _PC_NO_TRUNC: 
3330 if (!v3) { 
3331 error = EINVAL; 
3332 break; 
3333 } 
3334 nfsstats.rpccnt[NFSPROC_PATHCONF]++; 
3335 nfsm_reqhead(np, NFSPROC_PATHCONF, NFSX_FH(1)); 
3336 nfsm_fhtom(np, 1); 
3337 nfsm_request(np, NFSPROC_PATHCONF, 
3338 curlwp, curlwp->l_cred); /* XXX */ 
3339 nfsm_postop_attr(vp, attrflag, 0); 
3340 if (!error) { 
3341 nfsm_dissect(pcp, struct nfsv3_pathconf *, 
3342 NFSX_V3PATHCONF); 
3343 switch (ap->a_name) { 
3344 case _PC_LINK_MAX: 
3345 *ap->a_retval = 
3346 fxdr_unsigned(register_t, pcp->pc_linkmax); 
3347 break; 
3348 case _PC_NAME_MAX: 
3349 *ap->a_retval = 
3350 fxdr_unsigned(register_t, pcp->pc_namemax); 
3351 break; 
3352 case _PC_CHOWN_RESTRICTED: 
3353 *ap->a_retval = 
3354 (pcp->pc_chownrestricted == nfs_true); 
3355 break; 
3356 case _PC_NO_TRUNC: 
3357 *ap->a_retval = 
3358 (pcp->pc_notrunc == nfs_true); 
3359 break; 
3360 } 
3361 } 
3362 nfsm_reqdone; 
3363 break; 
3364 case _PC_FILESIZEBITS: 
3365#ifndef NFS_V2_ONLY 
3366 if (v3) { 
3367 nmp = VFSTONFS(vp->v_mount); 
3368 if ((nmp->nm_iflag & NFSMNT_GOTFSINFO) == 0) 
3369 if ((error = nfs_fsinfo(nmp, vp, 
3370 curlwp->l_cred, curlwp)) != 0) /* XXX */ 
3371 break; 
3372 for (l = 0, maxsize = nmp->nm_maxfilesize; 
3373 (maxsize >> l) > 0; l++) 
3374 ; 
3375 *ap->a_retval = l + 1; 
3376 } else 
3377#endif 
3378 { 
3379 *ap->a_retval = 32; /* NFS V2 limitation */ 
3380 } 
3381 break; 
3382 default: 
3383 error = EINVAL; 
3384 break; 
3385 } 
3386 
3387 return (error); 
3388} 
3389 
3390/* 
3391 * NFS advisory byte-level locks. 
3392 */ 
3393int 
3394nfs_advlock(v) 
3395 void *v; 
3396{ 
3397 struct vop_advlock_args /* { 
3398 struct vnode *a_vp; 
3399 void *a_id; 
3400 int a_op; 
3401 struct flock *a_fl; 
3402 int a_flags; 
3403 } */ *ap = v; 
3404 struct nfsnode *np = VTONFS(ap->a_vp); 
3405 
3406 return lf_advlock(ap, &np->n_lockf, np->n_size); 
3407} 
3408 
3409/* 
3410 * Print out the contents of an nfsnode. 
3411 */ 
3412int 
3413nfs_print(v) 
3414 void *v; 
3415{ 
3416 struct vop_print_args /* { 
3417 struct vnode *a_vp; 
3418 } */ *ap = v; 
3419 struct vnode *vp = ap->a_vp; 
3420 struct nfsnode *np = VTONFS(vp); 
3421 
3422 printf("tag VT_NFS, fileid %lld fsid 0x%lx", 
3423 (unsigned long long)np->n_vattr->va_fileid, np->n_vattr->va_fsid); 
3424 if (vp->v_type == VFIFO) 
3425 fifo_printinfo(vp); 
3426 printf("\n"); 
3427 return (0); 
3428} 
3429 
3430/* 
3431 * nfs unlock wrapper. 
3432 */ 
3433int 
3434nfs_unlock(void *v) 
3435{ 
3436 struct vop_unlock_args /* { 
3437 struct vnode *a_vp; 
3438 int a_flags; 
3439 } */ *ap = v; 
3440 struct vnode *vp = ap->a_vp; 
3441 
3442 /* 
3443 * VOP_UNLOCK can be called by nfs_loadattrcache 
3444 * with v_data == 0. 
3445 */ 
3446 if (VTONFS(vp)) { 
3447 nfs_delayedtruncate(vp); 
3448 } 
3449 
3450 return genfs_unlock(v); 
3451} 
3452 
3453/* 
3454 * nfs special file access vnode op. 
3455 * Essentially just get vattr and then imitate iaccess() since the device is 
3456 * local to the client. 
3457 */ 
3458int 
3459nfsspec_access(v) 
3460 void *v; 
3461{ 
3462 struct vop_access_args /* { 
3463 struct vnode *a_vp; 
3464 int a_mode; 
3465 kauth_cred_t a_cred; 
3466 struct lwp *a_l; 
3467 } */ *ap = v; 
3468 struct vattr va; 
3469 struct vnode *vp = ap->a_vp; 
3470 int error; 
3471 
3472 error = VOP_GETATTR(vp, &va, ap->a_cred); 
3473 if (error) 
3474 return (error); 
3475 
3476 /* 
3477 * Disallow write attempts on filesystems mounted read-only; 
3478 * unless the file is a socket, fifo, or a block or character 
3479 * device resident on the filesystem. 
3480 */ 
3481 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 
3482 switch (vp->v_type) { 
3483 case VREG: 
3484 case VDIR: 
3485 case VLNK: 
3486 return (EROFS); 
3487 default: 
3488 break; 
3489 } 
3490 } 
3491 
3492 return (vaccess(va.va_type, va.va_mode, 
3493 va.va_uid, va.va_gid, ap->a_mode, ap->a_cred)); 
3494} 
3495 
3496/* 
3497 * Read wrapper for special devices. 
3498 */ 
3499int 
3500nfsspec_read(v) 
3501 void *v; 
3502{ 
3503 struct vop_read_args /* { 
3504 struct vnode *a_vp; 
3505 struct uio *a_uio; 
3506 int a_ioflag; 
3507 kauth_cred_t a_cred; 
3508 } */ *ap = v; 
3509 struct nfsnode *np = VTONFS(ap->a_vp); 
3510 
3511 /* 
3512 * Set access flag. 
3513 */ 
3514 np->n_flag |= NACC; 
3515 getnanotime(&np->n_atim); 
3516 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 
3517} 
3518 
3519/* 
3520 * Write wrapper for special devices. 
3521 */ 
3522int 
3523nfsspec_write(v) 
3524 void *v; 
3525{ 
3526 struct vop_write_args /* { 
3527 struct vnode *a_vp; 
3528 struct uio *a_uio; 
3529 int a_ioflag; 
3530 kauth_cred_t a_cred; 
3531 } */ *ap = v; 
3532 struct nfsnode *np = VTONFS(ap->a_vp); 
3533 
3534 /* 
3535 * Set update flag. 
3536 */ 
3537 np->n_flag |= NUPD; 
3538 getnanotime(&np->n_mtim); 
3539 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 
3540} 
3541 
3542/* 
3543 * Close wrapper for special devices. 
3544 * 
3545 * Update the times on the nfsnode then do device close. 
3546 */ 
3547int 
3548nfsspec_close(v) 
3549 void *v; 
3550{ 
3551 struct vop_close_args /* { 
3552 struct vnode *a_vp; 
3553 int a_fflag; 
3554 kauth_cred_t a_cred; 
3555 struct lwp *a_l; 
3556 } */ *ap = v; 
3557 struct vnode *vp = ap->a_vp; 
3558 struct nfsnode *np = VTONFS(vp); 
3559 struct vattr vattr; 
3560 
3561 if (np->n_flag & (NACC | NUPD)) { 
3562 np->n_flag |= NCHG; 
3563 if (vp->v_usecount == 1 && 
3564 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 
3565 VATTR_NULL(&vattr); 
3566 if (np->n_flag & NACC) 
3567 vattr.va_atime = np->n_atim; 
3568 if (np->n_flag & NUPD) 
3569 vattr.va_mtime = np->n_mtim; 
3570 (void)VOP_SETATTR(vp, &vattr, ap->a_cred); 
3571 } 
3572 } 
3573 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 
3574} 
3575 
3576/* 
3577 * Read wrapper for fifos. 
3578 */ 
3579int 
3580nfsfifo_read(v) 
3581 void *v; 
3582{ 
3583 struct vop_read_args /* { 
3584 struct vnode *a_vp; 
3585 struct uio *a_uio; 
3586 int a_ioflag; 
3587 kauth_cred_t a_cred; 
3588 } */ *ap = v; 
3589 struct nfsnode *np = VTONFS(ap->a_vp); 
3590 
3591 /* 
3592 * Set access flag. 
3593 */ 
3594 np->n_flag |= NACC; 
3595 getnanotime(&np->n_atim); 
3596 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 
3597} 
3598 
3599/* 
3600 * Write wrapper for fifos. 
3601 */ 
3602int 
3603nfsfifo_write(v) 
3604 void *v; 
3605{ 
3606 struct vop_write_args /* { 
3607 struct vnode *a_vp; 
3608 struct uio *a_uio; 
3609 int a_ioflag; 
3610 kauth_cred_t a_cred; 
3611 } */ *ap = v; 
3612 struct nfsnode *np = VTONFS(ap->a_vp); 
3613 
3614 /* 
3615 * Set update flag. 
3616 */ 
3617 np->n_flag |= NUPD; 
3618 getnanotime(&np->n_mtim); 
3619 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 
3620} 
3621 
3622/* 
3623 * Close wrapper for fifos. 
3624 * 
3625 * Update the times on the nfsnode then do fifo close. 
3626 */ 
3627int 
3628nfsfifo_close(v) 
3629 void *v; 
3630{ 
3631 struct vop_close_args /* { 
3632 struct vnode *a_vp; 
3633 int a_fflag; 
3634 kauth_cred_t a_cred; 
3635 struct lwp *a_l; 
3636 } */ *ap = v; 
3637 struct vnode *vp = ap->a_vp; 
3638 struct nfsnode *np = VTONFS(vp); 
3639 struct vattr vattr; 
3640 
3641 if (np->n_flag & (NACC | NUPD)) { 
3642 struct timespec ts; 
3643 
3644 getnanotime(&ts); 
3645 if (np->n_flag & NACC) 
3646 np->n_atim = ts; 
3647 if (np->n_flag & NUPD) 
3648 np->n_mtim = ts; 
3649 np->n_flag |= NCHG; 
3650 if (vp->v_usecount == 1 && 
3651 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 
3652 VATTR_NULL(&vattr); 
3653 if (np->n_flag & NACC) 
3654 vattr.va_atime = np->n_atim; 
3655 if (np->n_flag & NUPD) 
3656 vattr.va_mtime = np->n_mtim; 
3657 (void)VOP_SETATTR(vp, &vattr, ap->a_cred); 
3658 } 
3659 } 
3660 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 
3661}