nfs_vnops.c revision 1.56 1 /* $NetBSD: nfs_vnops.c,v 1.56 1996/02/01 00:41:19 jtc 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. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)nfs_vnops.c 8.10 (Berkeley) 8/11/94
39 */
40
41 /*
42 * vnode op calls for sun nfs version 2
43 */
44
45 #include <sys/param.h>
46 #include <sys/proc.h>
47 #include <sys/kernel.h>
48 #include <sys/systm.h>
49 #include <sys/mount.h>
50 #include <sys/buf.h>
51 #include <sys/malloc.h>
52 #include <sys/mbuf.h>
53 #include <sys/conf.h>
54 #include <sys/namei.h>
55 #include <sys/vnode.h>
56 #include <sys/map.h>
57 #include <sys/dirent.h>
58 #include <sys/lockf.h>
59
60 #include <vm/vm.h>
61
62 #include <miscfs/specfs/specdev.h>
63 #include <miscfs/fifofs/fifo.h>
64
65 #include <nfs/rpcv2.h>
66 #include <nfs/nfsv2.h>
67 #include <nfs/nfs.h>
68 #include <nfs/nfsnode.h>
69 #include <nfs/nfsmount.h>
70 #include <nfs/xdr_subs.h>
71 #include <nfs/nfsm_subs.h>
72 #include <nfs/nqnfs.h>
73
74 /* Defs */
75 #define TRUE 1
76 #define FALSE 0
77
78 /*
79 * Global vfs data structures for nfs
80 */
81 int (**nfsv2_vnodeop_p)();
82 struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
83 { &vop_default_desc, vn_default_error },
84 { &vop_lookup_desc, nfs_lookup }, /* lookup */
85 { &vop_create_desc, nfs_create }, /* create */
86 { &vop_mknod_desc, nfs_mknod }, /* mknod */
87 { &vop_open_desc, nfs_open }, /* open */
88 { &vop_close_desc, nfs_close }, /* close */
89 { &vop_access_desc, nfs_access }, /* access */
90 { &vop_getattr_desc, nfs_getattr }, /* getattr */
91 { &vop_setattr_desc, nfs_setattr }, /* setattr */
92 { &vop_read_desc, nfs_read }, /* read */
93 { &vop_write_desc, nfs_write }, /* write */
94 { &vop_lease_desc, nfs_lease_check }, /* lease */
95 { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */
96 { &vop_select_desc, nfs_select }, /* select */
97 { &vop_mmap_desc, nfs_mmap }, /* mmap */
98 { &vop_fsync_desc, nfs_fsync }, /* fsync */
99 { &vop_seek_desc, nfs_seek }, /* seek */
100 { &vop_remove_desc, nfs_remove }, /* remove */
101 { &vop_link_desc, nfs_link }, /* link */
102 { &vop_rename_desc, nfs_rename }, /* rename */
103 { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */
104 { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */
105 { &vop_symlink_desc, nfs_symlink }, /* symlink */
106 { &vop_readdir_desc, nfs_readdir }, /* readdir */
107 { &vop_readlink_desc, nfs_readlink }, /* readlink */
108 { &vop_abortop_desc, nfs_abortop }, /* abortop */
109 { &vop_inactive_desc, nfs_inactive }, /* inactive */
110 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
111 { &vop_lock_desc, nfs_lock }, /* lock */
112 { &vop_unlock_desc, nfs_unlock }, /* unlock */
113 { &vop_bmap_desc, nfs_bmap }, /* bmap */
114 { &vop_strategy_desc, nfs_strategy }, /* strategy */
115 { &vop_print_desc, nfs_print }, /* print */
116 { &vop_islocked_desc, nfs_islocked }, /* islocked */
117 { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */
118 { &vop_advlock_desc, nfs_advlock }, /* advlock */
119 { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */
120 { &vop_valloc_desc, nfs_valloc }, /* valloc */
121 { &vop_reallocblks_desc, nfs_reallocblks }, /* reallocblks */
122 { &vop_vfree_desc, nfs_vfree }, /* vfree */
123 { &vop_truncate_desc, nfs_truncate }, /* truncate */
124 { &vop_update_desc, nfs_update }, /* update */
125 { &vop_bwrite_desc, vn_bwrite },
126 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
127 };
128 struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
129 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
130
131 /*
132 * Special device vnode ops
133 */
134 int (**spec_nfsv2nodeop_p)();
135 struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
136 { &vop_default_desc, vn_default_error },
137 { &vop_lookup_desc, spec_lookup }, /* lookup */
138 { &vop_create_desc, spec_create }, /* create */
139 { &vop_mknod_desc, spec_mknod }, /* mknod */
140 { &vop_open_desc, spec_open }, /* open */
141 { &vop_close_desc, nfsspec_close }, /* close */
142 { &vop_access_desc, nfsspec_access }, /* access */
143 { &vop_getattr_desc, nfs_getattr }, /* getattr */
144 { &vop_setattr_desc, nfs_setattr }, /* setattr */
145 { &vop_read_desc, nfsspec_read }, /* read */
146 { &vop_write_desc, nfsspec_write }, /* write */
147 { &vop_lease_desc, spec_lease_check }, /* lease */
148 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
149 { &vop_select_desc, spec_select }, /* select */
150 { &vop_mmap_desc, spec_mmap }, /* mmap */
151 { &vop_fsync_desc, nfs_fsync }, /* fsync */
152 { &vop_seek_desc, spec_seek }, /* seek */
153 { &vop_remove_desc, spec_remove }, /* remove */
154 { &vop_link_desc, spec_link }, /* link */
155 { &vop_rename_desc, spec_rename }, /* rename */
156 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
157 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
158 { &vop_symlink_desc, spec_symlink }, /* symlink */
159 { &vop_readdir_desc, spec_readdir }, /* readdir */
160 { &vop_readlink_desc, spec_readlink }, /* readlink */
161 { &vop_abortop_desc, spec_abortop }, /* abortop */
162 { &vop_inactive_desc, nfs_inactive }, /* inactive */
163 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
164 { &vop_lock_desc, nfs_lock }, /* lock */
165 { &vop_unlock_desc, nfs_unlock }, /* unlock */
166 { &vop_bmap_desc, spec_bmap }, /* bmap */
167 { &vop_strategy_desc, spec_strategy }, /* strategy */
168 { &vop_print_desc, nfs_print }, /* print */
169 { &vop_islocked_desc, nfs_islocked }, /* islocked */
170 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
171 { &vop_advlock_desc, spec_advlock }, /* advlock */
172 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
173 { &vop_valloc_desc, spec_valloc }, /* valloc */
174 { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
175 { &vop_vfree_desc, spec_vfree }, /* vfree */
176 { &vop_truncate_desc, spec_truncate }, /* truncate */
177 { &vop_update_desc, nfs_update }, /* update */
178 { &vop_bwrite_desc, vn_bwrite },
179 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
180 };
181 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
182 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
183
184 #ifdef FIFO
185 int (**fifo_nfsv2nodeop_p)();
186 struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
187 { &vop_default_desc, vn_default_error },
188 { &vop_lookup_desc, fifo_lookup }, /* lookup */
189 { &vop_create_desc, fifo_create }, /* create */
190 { &vop_mknod_desc, fifo_mknod }, /* mknod */
191 { &vop_open_desc, fifo_open }, /* open */
192 { &vop_close_desc, nfsfifo_close }, /* close */
193 { &vop_access_desc, nfsspec_access }, /* access */
194 { &vop_getattr_desc, nfs_getattr }, /* getattr */
195 { &vop_setattr_desc, nfs_setattr }, /* setattr */
196 { &vop_read_desc, nfsfifo_read }, /* read */
197 { &vop_write_desc, nfsfifo_write }, /* write */
198 { &vop_lease_desc, fifo_lease_check }, /* lease */
199 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
200 { &vop_select_desc, fifo_select }, /* select */
201 { &vop_mmap_desc, fifo_mmap }, /* mmap */
202 { &vop_fsync_desc, nfs_fsync }, /* fsync */
203 { &vop_seek_desc, fifo_seek }, /* seek */
204 { &vop_remove_desc, fifo_remove }, /* remove */
205 { &vop_link_desc, fifo_link }, /* link */
206 { &vop_rename_desc, fifo_rename }, /* rename */
207 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
208 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
209 { &vop_symlink_desc, fifo_symlink }, /* symlink */
210 { &vop_readdir_desc, fifo_readdir }, /* readdir */
211 { &vop_readlink_desc, fifo_readlink }, /* readlink */
212 { &vop_abortop_desc, fifo_abortop }, /* abortop */
213 { &vop_inactive_desc, nfs_inactive }, /* inactive */
214 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
215 { &vop_lock_desc, nfs_lock }, /* lock */
216 { &vop_unlock_desc, nfs_unlock }, /* unlock */
217 { &vop_bmap_desc, fifo_bmap }, /* bmap */
218 { &vop_strategy_desc, fifo_badop }, /* strategy */
219 { &vop_print_desc, nfs_print }, /* print */
220 { &vop_islocked_desc, nfs_islocked }, /* islocked */
221 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
222 { &vop_advlock_desc, fifo_advlock }, /* advlock */
223 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
224 { &vop_valloc_desc, fifo_valloc }, /* valloc */
225 { &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */
226 { &vop_vfree_desc, fifo_vfree }, /* vfree */
227 { &vop_truncate_desc, fifo_truncate }, /* truncate */
228 { &vop_update_desc, nfs_update }, /* update */
229 { &vop_bwrite_desc, vn_bwrite },
230 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
231 };
232 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
233 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
234 #endif /* FIFO */
235
236 void nqnfs_clientlease();
237
238 /*
239 * Global variables
240 */
241 extern u_int32_t nfs_procids[NFS_NPROCS];
242 extern u_int32_t nfs_xdrneg1;
243 extern u_int32_t nfs_prog, nfs_vers, nfs_true, nfs_false;
244 struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
245 int nfs_numasync = 0;
246 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
247
248 /*
249 * nfs null call from vfs.
250 */
251 int
252 nfs_null(vp, cred, procp)
253 struct vnode *vp;
254 struct ucred *cred;
255 struct proc *procp;
256 {
257 caddr_t bpos, dpos;
258 int error = 0;
259 struct mbuf *mreq, *mrep, *md, *mb;
260
261 nfsm_reqhead(vp, NFSPROC_NULL, 0);
262 nfsm_request(vp, NFSPROC_NULL, procp, cred);
263 nfsm_reqdone;
264 return (error);
265 }
266
267 /*
268 * nfs access vnode op.
269 * For nfs, just return ok. File accesses may fail later.
270 * For nqnfs, use the access rpc to check accessibility. If file modes are
271 * changed on the server, accesses might still fail later.
272 */
273 int
274 nfs_access(ap)
275 struct vop_access_args /* {
276 struct vnode *a_vp;
277 int a_mode;
278 struct ucred *a_cred;
279 struct proc *a_p;
280 } */ *ap;
281 {
282 register struct vnode *vp = ap->a_vp;
283 register u_int32_t *tl;
284 register caddr_t cp;
285 caddr_t bpos, dpos;
286 int error = 0;
287 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
288
289 /*
290 * For nqnfs, do an access rpc, otherwise you are stuck emulating
291 * ufs_access() locally using the vattr. This may not be correct,
292 * since the server may apply other access criteria such as
293 * client uid-->server uid mapping that we do not know about, but
294 * this is better than just returning anything that is lying about
295 * in the cache.
296 */
297 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
298 nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
299 nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
300 nfsm_fhtom(vp);
301 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
302 if (ap->a_mode & VREAD)
303 *tl++ = nfs_true;
304 else
305 *tl++ = nfs_false;
306 if (ap->a_mode & VWRITE)
307 *tl++ = nfs_true;
308 else
309 *tl++ = nfs_false;
310 if (ap->a_mode & VEXEC)
311 *tl = nfs_true;
312 else
313 *tl = nfs_false;
314 nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
315 nfsm_reqdone;
316 return (error);
317 } else
318 return (nfsspec_access(ap));
319 }
320
321 /*
322 * nfs open vnode op
323 * Check to see if the type is ok
324 * and that deletion is not in progress.
325 * For paged in text files, you will need to flush the page cache
326 * if consistency is lost.
327 */
328 /* ARGSUSED */
329 int
330 nfs_open(ap)
331 struct vop_open_args /* {
332 struct vnode *a_vp;
333 int a_mode;
334 struct ucred *a_cred;
335 struct proc *a_p;
336 } */ *ap;
337 {
338 register struct vnode *vp = ap->a_vp;
339 struct nfsnode *np = VTONFS(vp);
340 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
341 struct vattr vattr;
342 int error;
343
344 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
345 return (EACCES);
346 if (vp->v_flag & VTEXT) {
347 /*
348 * Get a valid lease. If cached data is stale, flush it.
349 */
350 if (nmp->nm_flag & NFSMNT_NQNFS) {
351 if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
352 do {
353 error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
354 } while (error == NQNFS_EXPIRED);
355 if (error)
356 return (error);
357 if (np->n_lrev != np->n_brev ||
358 (np->n_flag & NQNFSNONCACHE)) {
359 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
360 ap->a_p, 1)) == EINTR)
361 return (error);
362 (void) vnode_pager_uncache(vp);
363 np->n_brev = np->n_lrev;
364 }
365 }
366 } else {
367 if (np->n_flag & NMODIFIED) {
368 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
369 ap->a_p, 1)) == EINTR)
370 return (error);
371 (void) vnode_pager_uncache(vp);
372 np->n_attrstamp = 0;
373 np->n_direofoffset = 0;
374 if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
375 return (error);
376 np->n_mtime = vattr.va_mtime.tv_sec;
377 } else {
378 if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
379 return (error);
380 if (np->n_mtime != vattr.va_mtime.tv_sec) {
381 np->n_direofoffset = 0;
382 if ((error = nfs_vinvalbuf(vp, V_SAVE,
383 ap->a_cred, ap->a_p, 1)) == EINTR)
384 return (error);
385 (void) vnode_pager_uncache(vp);
386 np->n_mtime = vattr.va_mtime.tv_sec;
387 }
388 }
389 }
390 } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
391 np->n_attrstamp = 0; /* For Open/Close consistency */
392 return (0);
393 }
394
395 /*
396 * nfs close vnode op
397 * For reg files, invalidate any buffer cache entries.
398 */
399 /* ARGSUSED */
400 int
401 nfs_close(ap)
402 struct vop_close_args /* {
403 struct vnodeop_desc *a_desc;
404 struct vnode *a_vp;
405 int a_fflag;
406 struct ucred *a_cred;
407 struct proc *a_p;
408 } */ *ap;
409 {
410 register struct vnode *vp = ap->a_vp;
411 register struct nfsnode *np = VTONFS(vp);
412 int error = 0;
413
414 if (vp->v_type == VREG) {
415 if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
416 (np->n_flag & NMODIFIED)) {
417 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
418 np->n_attrstamp = 0;
419 }
420 if (np->n_flag & NWRITEERR) {
421 np->n_flag &= ~NWRITEERR;
422 error = np->n_error;
423 }
424 }
425 return (error);
426 }
427
428 /*
429 * nfs getattr call from vfs.
430 */
431 int
432 nfs_getattr(ap)
433 struct vop_getattr_args /* {
434 struct vnode *a_vp;
435 struct vattr *a_vap;
436 struct ucred *a_cred;
437 struct proc *a_p;
438 } */ *ap;
439 {
440 register struct vnode *vp = ap->a_vp;
441 register struct nfsnode *np = VTONFS(vp);
442 register caddr_t cp;
443 caddr_t bpos, dpos;
444 int error = 0;
445 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
446
447 /*
448 * Update local times for special files.
449 */
450 if (np->n_flag & (NACC | NUPD))
451 np->n_flag |= NCHG;
452 /*
453 * First look in the cache.
454 */
455 if (nfs_getattrcache(vp, ap->a_vap) == 0)
456 return (0);
457 nfsstats.rpccnt[NFSPROC_GETATTR]++;
458 nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
459 nfsm_fhtom(vp);
460 nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
461 nfsm_loadattr(vp, ap->a_vap);
462 nfsm_reqdone;
463 return (error);
464 }
465
466 /*
467 * nfs setattr call.
468 */
469 int
470 nfs_setattr(ap)
471 struct vop_setattr_args /* {
472 struct vnodeop_desc *a_desc;
473 struct vnode *a_vp;
474 struct vattr *a_vap;
475 struct ucred *a_cred;
476 struct proc *a_p;
477 } */ *ap;
478 {
479 register struct nfsv2_sattr *sp;
480 register caddr_t cp;
481 register int32_t t1;
482 caddr_t bpos, dpos, cp2;
483 u_int32_t *tl;
484 int error = 0, isnq;
485 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
486 register struct vnode *vp = ap->a_vp;
487 register struct nfsnode *np = VTONFS(vp);
488 register struct vattr *vap = ap->a_vap;
489 u_quad_t frev, tsize;
490
491 if (vap->va_size != VNOVAL) {
492 switch (vp->v_type) {
493 case VDIR:
494 return (EISDIR);
495 case VCHR:
496 case VBLK:
497 if (vap->va_mtime.tv_sec == VNOVAL &&
498 vap->va_atime.tv_sec == VNOVAL &&
499 vap->va_mode == (u_short)VNOVAL &&
500 vap->va_uid == VNOVAL &&
501 vap->va_gid == VNOVAL)
502 return (0);
503 vap->va_size = VNOVAL;
504 break;
505 default:
506 if (np->n_flag & NMODIFIED) {
507 if (vap->va_size == 0)
508 error = nfs_vinvalbuf(vp, 0,
509 ap->a_cred, ap->a_p, 1);
510 else
511 error = nfs_vinvalbuf(vp, V_SAVE,
512 ap->a_cred, ap->a_p, 1);
513 if (error)
514 return (error);
515 }
516 tsize = np->n_size;
517 np->n_size = np->n_vattr.va_size = vap->va_size;
518 vnode_pager_setsize(vp, (u_long)np->n_size);
519 }
520 } else if ((vap->va_mtime.tv_sec != VNOVAL ||
521 vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED)) {
522 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
523 if (error == EINTR)
524 return (error);
525 }
526 nfsstats.rpccnt[NFSPROC_SETATTR]++;
527 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
528 nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
529 nfsm_fhtom(vp);
530 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
531 if (vap->va_mode == (u_short)VNOVAL)
532 sp->sa_mode = nfs_xdrneg1;
533 else
534 sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
535 if (vap->va_uid == VNOVAL)
536 sp->sa_uid = nfs_xdrneg1;
537 else
538 sp->sa_uid = txdr_unsigned(vap->va_uid);
539 if (vap->va_gid == VNOVAL)
540 sp->sa_gid = nfs_xdrneg1;
541 else
542 sp->sa_gid = txdr_unsigned(vap->va_gid);
543 if (isnq) {
544 txdr_hyper(&vap->va_size, &sp->sa_nqsize);
545 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
546 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
547 sp->sa_nqflags = txdr_unsigned(vap->va_flags);
548 sp->sa_nqrdev = nfs_xdrneg1;
549 } else {
550 sp->sa_nfssize = txdr_unsigned(vap->va_size);
551 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
552 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
553 }
554 nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
555 nfsm_loadattr(vp, (struct vattr *)0);
556 if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
557 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
558 nfsm_dissect(tl, u_int32_t *, 2*NFSX_UNSIGNED);
559 fxdr_hyper(tl, &frev);
560 if (frev > np->n_brev)
561 np->n_brev = frev;
562 }
563 nfsm_reqdone;
564 if (error) {
565 np->n_size = np->n_vattr.va_size = tsize;
566 vnode_pager_setsize(vp, (u_long)np->n_size);
567 }
568 return (error);
569 }
570
571 /*
572 * nfs lookup call, one step at a time...
573 * First look in cache
574 * If not found, unlock the directory nfsnode and do the rpc
575 */
576 int
577 nfs_lookup(ap)
578 struct vop_lookup_args /* {
579 struct vnodeop_desc *a_desc;
580 struct vnode *a_dvp;
581 struct vnode **a_vpp;
582 struct componentname *a_cnp;
583 } */ *ap;
584 {
585 register struct componentname *cnp = ap->a_cnp;
586 register struct vnode *dvp = ap->a_dvp;
587 register struct vnode **vpp = ap->a_vpp;
588 register int flags = cnp->cn_flags;
589 register struct vnode *vdp;
590 register u_int32_t *tl;
591 register caddr_t cp;
592 register int32_t t1, t2;
593 struct nfsmount *nmp;
594 caddr_t bpos, dpos, cp2;
595 time_t reqtime;
596 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
597 struct vnode *newvp;
598 long len;
599 nfsv2fh_t *fhp;
600 struct nfsnode *np;
601 int lockparent, wantparent, error = 0;
602 int nqlflag, cachable;
603 u_quad_t frev;
604
605 *vpp = NULL;
606 if (dvp->v_type != VDIR)
607 return (ENOTDIR);
608 lockparent = flags & LOCKPARENT;
609 wantparent = flags & (LOCKPARENT|WANTPARENT);
610 nmp = VFSTONFS(dvp->v_mount);
611 np = VTONFS(dvp);
612 if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
613 struct vattr vattr;
614 int vpid;
615
616 vdp = *vpp;
617 vpid = vdp->v_id;
618 /*
619 * See the comment starting `Step through' in ufs/ufs_lookup.c
620 * for an explanation of the locking protocol
621 */
622 if (dvp == vdp) {
623 VREF(vdp);
624 error = 0;
625 } else
626 error = vget(vdp, 1);
627 if (!error) {
628 if (vpid == vdp->v_id) {
629 if (nmp->nm_flag & NFSMNT_NQNFS) {
630 if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
631 cachehit:
632 nfsstats.lookupcache_hits++;
633 if (cnp->cn_nameiop != LOOKUP &&
634 (flags & ISLASTCN))
635 cnp->cn_flags |= SAVENAME;
636 return (0);
637 } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
638 if (np->n_lrev != np->n_brev ||
639 (np->n_flag & NMODIFIED)) {
640 np->n_direofoffset = 0;
641 cache_purge(dvp);
642 error = nfs_vinvalbuf(dvp, 0,
643 cnp->cn_cred, cnp->cn_proc,
644 1);
645 if (error == EINTR)
646 return (error);
647 np->n_brev = np->n_lrev;
648 } else
649 goto cachehit;
650 }
651 } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
652 vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime)
653 goto cachehit;
654 cache_purge(vdp);
655 }
656 vrele(vdp);
657 }
658 *vpp = NULLVP;
659 }
660 error = 0;
661 nfsstats.lookupcache_misses++;
662 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
663 len = cnp->cn_namelen;
664 nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
665
666 /*
667 * For nqnfs optionally piggyback a getlease request for the name
668 * being looked up.
669 */
670 if (nmp->nm_flag & NFSMNT_NQNFS) {
671 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
672 if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
673 ((cnp->cn_flags & MAKEENTRY) &&
674 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
675 *tl = txdr_unsigned(nmp->nm_leaseterm);
676 else
677 *tl = 0;
678 }
679 nfsm_fhtom(dvp);
680 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
681 reqtime = time.tv_sec;
682 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
683 nfsmout:
684 if (error) {
685 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
686 (flags & ISLASTCN) && error == ENOENT)
687 error = EJUSTRETURN;
688 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
689 cnp->cn_flags |= SAVENAME;
690 return (error);
691 }
692 if (nmp->nm_flag & NFSMNT_NQNFS) {
693 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
694 if (*tl) {
695 nqlflag = fxdr_unsigned(int, *tl);
696 nfsm_dissect(tl, u_int32_t *, 4*NFSX_UNSIGNED);
697 cachable = fxdr_unsigned(int, *tl++);
698 reqtime += fxdr_unsigned(int, *tl++);
699 fxdr_hyper(tl, &frev);
700 } else
701 nqlflag = 0;
702 }
703 nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
704
705 /*
706 * Handle RENAME case...
707 */
708 if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
709 if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
710 m_freem(mrep);
711 return (EISDIR);
712 }
713 if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
714 m_freem(mrep);
715 return (error);
716 }
717 newvp = NFSTOV(np);
718 if (error =
719 nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
720 vrele(newvp);
721 m_freem(mrep);
722 return (error);
723 }
724 *vpp = newvp;
725 m_freem(mrep);
726 cnp->cn_flags |= SAVENAME;
727 return (0);
728 }
729
730 if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
731 VREF(dvp);
732 newvp = dvp;
733 } else {
734 if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
735 m_freem(mrep);
736 return (error);
737 }
738 newvp = NFSTOV(np);
739 }
740 if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
741 vrele(newvp);
742 m_freem(mrep);
743 return (error);
744 }
745 m_freem(mrep);
746 *vpp = newvp;
747 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
748 cnp->cn_flags |= SAVENAME;
749 if ((cnp->cn_flags & MAKEENTRY) &&
750 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
751 if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
752 np->n_ctime = np->n_vattr.va_ctime.tv_sec;
753 else if (nqlflag && reqtime > time.tv_sec)
754 nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
755 frev);
756 cache_enter(dvp, *vpp, cnp);
757 }
758 return (0);
759 }
760
761 /*
762 * nfs read call.
763 * Just call nfs_bioread() to do the work.
764 */
765 int
766 nfs_read(ap)
767 struct vop_read_args /* {
768 struct vnode *a_vp;
769 struct uio *a_uio;
770 int a_ioflag;
771 struct ucred *a_cred;
772 } */ *ap;
773 {
774 register struct vnode *vp = ap->a_vp;
775
776 if (vp->v_type != VREG)
777 return (EPERM);
778 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
779 }
780
781 /*
782 * nfs readlink call
783 */
784 int
785 nfs_readlink(ap)
786 struct vop_readlink_args /* {
787 struct vnode *a_vp;
788 struct uio *a_uio;
789 struct ucred *a_cred;
790 } */ *ap;
791 {
792 register struct vnode *vp = ap->a_vp;
793
794 if (vp->v_type != VLNK)
795 return (EPERM);
796 return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
797 }
798
799 /*
800 * Do a readlink rpc.
801 * Called by nfs_doio() from below the buffer cache.
802 */
803 int
804 nfs_readlinkrpc(vp, uiop, cred)
805 register struct vnode *vp;
806 struct uio *uiop;
807 struct ucred *cred;
808 {
809 register u_int32_t *tl;
810 register caddr_t cp;
811 register int32_t t1;
812 caddr_t bpos, dpos, cp2;
813 int error = 0;
814 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
815 long len;
816
817 nfsstats.rpccnt[NFSPROC_READLINK]++;
818 nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
819 nfsm_fhtom(vp);
820 nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
821 nfsm_strsiz(len, NFS_MAXPATHLEN);
822 nfsm_mtouio(uiop, len);
823 nfsm_reqdone;
824 return (error);
825 }
826
827 /*
828 * nfs read rpc call
829 * Ditto above
830 */
831 int
832 nfs_readrpc(vp, uiop, cred)
833 register struct vnode *vp;
834 struct uio *uiop;
835 struct ucred *cred;
836 {
837 register u_int32_t *tl;
838 register caddr_t cp;
839 register int32_t t1;
840 caddr_t bpos, dpos, cp2;
841 int error = 0;
842 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
843 struct nfsmount *nmp;
844 long len, retlen, tsiz;
845
846 nmp = VFSTONFS(vp->v_mount);
847 tsiz = uiop->uio_resid;
848 if (uiop->uio_offset + tsiz > 0xffffffff &&
849 (nmp->nm_flag & NFSMNT_NQNFS) == 0)
850 return (EFBIG);
851 while (tsiz > 0) {
852 nfsstats.rpccnt[NFSPROC_READ]++;
853 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
854 nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
855 nfsm_fhtom(vp);
856 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED*3);
857 if (nmp->nm_flag & NFSMNT_NQNFS) {
858 txdr_hyper(&uiop->uio_offset, tl);
859 *(tl + 2) = txdr_unsigned(len);
860 } else {
861 *tl++ = txdr_unsigned(uiop->uio_offset);
862 *tl++ = txdr_unsigned(len);
863 *tl = 0;
864 }
865 nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
866 nfsm_loadattr(vp, (struct vattr *)0);
867 nfsm_strsiz(retlen, nmp->nm_rsize);
868 nfsm_mtouio(uiop, retlen);
869 m_freem(mrep);
870 if (retlen < len)
871 tsiz = 0;
872 else
873 tsiz -= len;
874 }
875 nfsmout:
876 return (error);
877 }
878
879 /*
880 * nfs write call
881 */
882 int
883 nfs_writerpc(vp, uiop, cred, ioflags)
884 register struct vnode *vp;
885 struct uio *uiop;
886 struct ucred *cred;
887 int ioflags;
888 {
889 register u_int32_t *tl;
890 register caddr_t cp;
891 register int32_t t1;
892 caddr_t bpos, dpos, cp2;
893 int error = 0;
894 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
895 struct nfsmount *nmp;
896 struct nfsnode *np = VTONFS(vp);
897 u_quad_t frev;
898 long len, tsiz;
899
900 nmp = VFSTONFS(vp->v_mount);
901 tsiz = uiop->uio_resid;
902 if (uiop->uio_offset + tsiz > 0xffffffff &&
903 (nmp->nm_flag & NFSMNT_NQNFS) == 0)
904 return (EFBIG);
905 while (tsiz > 0) {
906 nfsstats.rpccnt[NFSPROC_WRITE]++;
907 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
908 nfsm_reqhead(vp, NFSPROC_WRITE,
909 NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
910 nfsm_fhtom(vp);
911 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 4);
912 if (nmp->nm_flag & NFSMNT_NQNFS) {
913 txdr_hyper(&uiop->uio_offset, tl);
914 tl += 2;
915 *tl++ = 0;
916 *tl = txdr_unsigned(len);
917 } else {
918 register u_int32_t x;
919 /* Set both "begin" and "current" to non-garbage. */
920 x = txdr_unsigned((u_int32_t)uiop->uio_offset);
921 *tl++ = x; /* "begin offset" */
922 *tl++ = x; /* "current offset" */
923 x = txdr_unsigned(len);
924 *tl++ = x; /* total to this offset */
925 *tl = x; /* size of this write */
926 }
927 nfsm_uiotom(uiop, len);
928 nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
929 nfsm_loadattr(vp, (struct vattr *)0);
930 if (nmp->nm_flag & NFSMNT_MYWRITE)
931 VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
932 else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
933 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
934 nfsm_dissect(tl, u_int32_t *, 2*NFSX_UNSIGNED);
935 fxdr_hyper(tl, &frev);
936 if (frev > np->n_brev)
937 np->n_brev = frev;
938 }
939 m_freem(mrep);
940 tsiz -= len;
941 }
942 nfsmout:
943 if (error)
944 uiop->uio_resid = tsiz;
945 return (error);
946 }
947
948 /*
949 * nfs mknod call
950 * This is a kludge. Use a create rpc but with the IFMT bits of the mode
951 * set to specify the file type and the size field for rdev.
952 */
953 /* ARGSUSED */
954 int
955 nfs_mknod(ap)
956 struct vop_mknod_args /* {
957 struct vnode *a_dvp;
958 struct vnode **a_vpp;
959 struct componentname *a_cnp;
960 struct vattr *a_vap;
961 } */ *ap;
962 {
963 register struct vnode *dvp = ap->a_dvp;
964 register struct vattr *vap = ap->a_vap;
965 register struct componentname *cnp = ap->a_cnp;
966 register struct nfsv2_sattr *sp;
967 register u_int32_t *tl;
968 register caddr_t cp;
969 register int32_t t1, t2;
970 struct vnode *newvp;
971 char *cp2;
972 caddr_t bpos, dpos;
973 int error = 0, isnq;
974 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
975 u_int32_t rdev;
976
977 if (vap->va_type == VCHR || vap->va_type == VBLK)
978 rdev = txdr_unsigned(vap->va_rdev);
979 #ifdef FIFO
980 else if (vap->va_type == VFIFO)
981 rdev = 0xffffffff;
982 #endif /* FIFO */
983 else {
984 VOP_ABORTOP(dvp, cnp);
985 vput(dvp);
986 return (EOPNOTSUPP);
987 }
988 newvp = NULLVP;
989 nfsstats.rpccnt[NFSPROC_CREATE]++;
990 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
991 nfsm_reqhead(dvp, NFSPROC_CREATE,
992 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
993 nfsm_fhtom(dvp);
994 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
995 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
996 sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
997 sp->sa_uid = nfs_xdrneg1;
998 sp->sa_gid = nfs_xdrneg1;
999 if (isnq) {
1000 sp->sa_nqrdev = rdev;
1001 sp->sa_nqflags = 0;
1002 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1003 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1004 } else {
1005 sp->sa_nfssize = rdev;
1006 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1007 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1008 }
1009 nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1010 nfsm_mtofh(dvp, newvp);
1011 nfsm_reqdone;
1012 if (!error && (cnp->cn_flags & MAKEENTRY))
1013 cache_enter(dvp, newvp, cnp);
1014 FREE(cnp->cn_pnbuf, M_NAMEI);
1015 VTONFS(dvp)->n_flag |= NMODIFIED;
1016 VTONFS(dvp)->n_attrstamp = 0;
1017 vrele(dvp);
1018 if (newvp != NULLVP)
1019 vrele(newvp);
1020 return (error);
1021 }
1022
1023 /*
1024 * nfs file create call
1025 */
1026 int
1027 nfs_create(ap)
1028 struct vop_create_args /* {
1029 struct vnode *a_dvp;
1030 struct vnode **a_vpp;
1031 struct componentname *a_cnp;
1032 struct vattr *a_vap;
1033 } */ *ap;
1034 {
1035 register struct vnode *dvp = ap->a_dvp;
1036 register struct vattr *vap = ap->a_vap;
1037 register struct componentname *cnp = ap->a_cnp;
1038 register struct nfsv2_sattr *sp;
1039 register u_int32_t *tl;
1040 register caddr_t cp;
1041 register int32_t t1, t2;
1042 caddr_t bpos, dpos, cp2;
1043 int error = 0, isnq;
1044 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1045
1046 nfsstats.rpccnt[NFSPROC_CREATE]++;
1047 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
1048 nfsm_reqhead(dvp, NFSPROC_CREATE,
1049 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
1050 nfsm_fhtom(dvp);
1051 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1052 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
1053 sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
1054 sp->sa_uid = nfs_xdrneg1;
1055 sp->sa_gid = nfs_xdrneg1;
1056 if (isnq) {
1057 u_quad_t qval = 0;
1058
1059 txdr_hyper(&qval, &sp->sa_nqsize);
1060 sp->sa_nqrdev = nfs_xdrneg1;
1061 sp->sa_nqflags = 0;
1062 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1063 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1064 } else {
1065 sp->sa_nfssize = 0;
1066 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1067 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1068 }
1069 nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1070 nfsm_mtofh(dvp, *ap->a_vpp);
1071 nfsm_reqdone;
1072 if (!error && (cnp->cn_flags & MAKEENTRY))
1073 cache_enter(dvp, *ap->a_vpp, cnp);
1074 FREE(cnp->cn_pnbuf, M_NAMEI);
1075 VTONFS(dvp)->n_flag |= NMODIFIED;
1076 VTONFS(dvp)->n_attrstamp = 0;
1077 vrele(dvp);
1078 return (error);
1079 }
1080
1081 /*
1082 * nfs file remove call
1083 * To try and make nfs semantics closer to ufs semantics, a file that has
1084 * other processes using the vnode is renamed instead of removed and then
1085 * removed later on the last close.
1086 * - If v_usecount > 1
1087 * If a rename is not already in the works
1088 * call nfs_sillyrename() to set it up
1089 * else
1090 * do the remove rpc
1091 */
1092 int
1093 nfs_remove(ap)
1094 struct vop_remove_args /* {
1095 struct vnodeop_desc *a_desc;
1096 struct vnode * a_dvp;
1097 struct vnode * a_vp;
1098 struct componentname * a_cnp;
1099 } */ *ap;
1100 {
1101 register struct vnode *vp = ap->a_vp;
1102 register struct vnode *dvp = ap->a_dvp;
1103 register struct componentname *cnp = ap->a_cnp;
1104 register struct nfsnode *np = VTONFS(vp);
1105 register u_int32_t *tl;
1106 register caddr_t cp;
1107 register int32_t t2;
1108 caddr_t bpos, dpos;
1109 int error = 0;
1110 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1111 struct vattr vattr;
1112
1113 if (vp->v_usecount > 1) {
1114 if (!np->n_sillyrename)
1115 error = nfs_sillyrename(dvp, vp, cnp);
1116 else if (VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc)
1117 == 0 && vattr.va_nlink > 1)
1118 /*
1119 * If we already have a silly name but there are more
1120 * than one links, just proceed with the NFS remove
1121 * request, as the bits will remain available (modulo
1122 * network races). This avoids silently ignoring the
1123 * attempted removal of a non-silly entry.
1124 */
1125 goto doit;
1126 } else {
1127 doit:
1128 /*
1129 * Purge the name cache so that the chance of a lookup for
1130 * the name succeeding while the remove is in progress is
1131 * minimized. Without node locking it can still happen, such
1132 * that an I/O op returns ESTALE, but since you get this if
1133 * another host removes the file..
1134 */
1135 cache_purge(vp);
1136 /*
1137 * Throw away biocache buffers. Mainly to avoid
1138 * unnecessary delayed writes.
1139 */
1140 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1141 if (error == EINTR)
1142 return (error);
1143 /* Do the rpc */
1144 nfsstats.rpccnt[NFSPROC_REMOVE]++;
1145 nfsm_reqhead(dvp, NFSPROC_REMOVE,
1146 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1147 nfsm_fhtom(dvp);
1148 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1149 nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
1150 nfsm_reqdone;
1151 FREE(cnp->cn_pnbuf, M_NAMEI);
1152 VTONFS(dvp)->n_flag |= NMODIFIED;
1153 VTONFS(dvp)->n_attrstamp = 0;
1154 /*
1155 * Kludge City: If the first reply to the remove rpc is lost..
1156 * the reply to the retransmitted request will be ENOENT
1157 * since the file was in fact removed
1158 * Therefore, we cheat and return success.
1159 */
1160 if (error == ENOENT)
1161 error = 0;
1162 }
1163 np->n_attrstamp = 0;
1164 vrele(dvp);
1165 vrele(vp);
1166 return (error);
1167 }
1168
1169 /*
1170 * nfs file remove rpc called from nfs_inactive
1171 */
1172 int
1173 nfs_removeit(sp)
1174 register struct sillyrename *sp;
1175 {
1176 register u_int32_t *tl;
1177 register caddr_t cp;
1178 register int32_t t2;
1179 caddr_t bpos, dpos;
1180 int error = 0;
1181 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1182
1183 nfsstats.rpccnt[NFSPROC_REMOVE]++;
1184 nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
1185 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
1186 nfsm_fhtom(sp->s_dvp);
1187 nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
1188 nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
1189 nfsm_reqdone;
1190 VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
1191 VTONFS(sp->s_dvp)->n_attrstamp = 0;
1192 return (error);
1193 }
1194
1195 /*
1196 * nfs file rename call
1197 */
1198 int
1199 nfs_rename(ap)
1200 struct vop_rename_args /* {
1201 struct vnode *a_fdvp;
1202 struct vnode *a_fvp;
1203 struct componentname *a_fcnp;
1204 struct vnode *a_tdvp;
1205 struct vnode *a_tvp;
1206 struct componentname *a_tcnp;
1207 } */ *ap;
1208 {
1209 register struct vnode *fvp = ap->a_fvp;
1210 register struct vnode *tvp = ap->a_tvp;
1211 register struct vnode *fdvp = ap->a_fdvp;
1212 register struct vnode *tdvp = ap->a_tdvp;
1213 register struct componentname *tcnp = ap->a_tcnp;
1214 register struct componentname *fcnp = ap->a_fcnp;
1215 register u_int32_t *tl;
1216 register caddr_t cp;
1217 register int32_t t2;
1218 caddr_t bpos, dpos;
1219 int error = 0;
1220 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1221
1222 /* Check for cross-device rename */
1223 if ((fvp->v_mount != tdvp->v_mount) ||
1224 (tvp && (fvp->v_mount != tvp->v_mount))) {
1225 error = EXDEV;
1226 goto out;
1227 }
1228
1229
1230 nfsstats.rpccnt[NFSPROC_RENAME]++;
1231 nfsm_reqhead(fdvp, NFSPROC_RENAME,
1232 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
1233 nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
1234 nfsm_fhtom(fdvp);
1235 nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
1236 nfsm_fhtom(tdvp);
1237 nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
1238 nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
1239 nfsm_reqdone;
1240 VTONFS(fdvp)->n_flag |= NMODIFIED;
1241 VTONFS(fdvp)->n_attrstamp = 0;
1242 VTONFS(tdvp)->n_flag |= NMODIFIED;
1243 VTONFS(tdvp)->n_attrstamp = 0;
1244 if (fvp->v_type == VDIR) {
1245 if (tvp != NULL && tvp->v_type == VDIR)
1246 cache_purge(tdvp);
1247 cache_purge(fdvp);
1248 }
1249 out:
1250 if (tdvp == tvp)
1251 vrele(tdvp);
1252 else
1253 vput(tdvp);
1254 if (tvp)
1255 vput(tvp);
1256 vrele(fdvp);
1257 vrele(fvp);
1258 /*
1259 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1260 */
1261 if (error == ENOENT)
1262 error = 0;
1263 return (error);
1264 }
1265
1266 /*
1267 * nfs file rename rpc called from nfs_remove() above
1268 */
1269 int
1270 nfs_renameit(sdvp, scnp, sp)
1271 struct vnode *sdvp;
1272 struct componentname *scnp;
1273 register struct sillyrename *sp;
1274 {
1275 register u_int32_t *tl;
1276 register caddr_t cp;
1277 register int32_t t2;
1278 caddr_t bpos, dpos;
1279 int error = 0;
1280 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1281
1282 nfsstats.rpccnt[NFSPROC_RENAME]++;
1283 nfsm_reqhead(sdvp, NFSPROC_RENAME,
1284 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
1285 nfsm_rndup(sp->s_namlen));
1286 nfsm_fhtom(sdvp);
1287 nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
1288 nfsm_fhtom(sdvp);
1289 nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
1290 nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
1291 nfsm_reqdone;
1292 FREE(scnp->cn_pnbuf, M_NAMEI);
1293 VTONFS(sdvp)->n_flag |= NMODIFIED;
1294 VTONFS(sdvp)->n_attrstamp = 0;
1295 return (error);
1296 }
1297
1298 /*
1299 * nfs hard link create call
1300 */
1301 int
1302 nfs_link(ap)
1303 struct vop_link_args /* {
1304 struct vnode *a_vp;
1305 struct vnode *a_tdvp;
1306 struct componentname *a_cnp;
1307 } */ *ap;
1308 {
1309 register struct vnode *vp = ap->a_vp;
1310 register struct vnode *tdvp = ap->a_tdvp;
1311 register struct componentname *cnp = ap->a_cnp;
1312 register u_int32_t *tl;
1313 register caddr_t cp;
1314 register int32_t t2;
1315 caddr_t bpos, dpos;
1316 int error = 0;
1317 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1318
1319 if (vp->v_mount != tdvp->v_mount) {
1320 /*VOP_ABORTOP(vp, cnp);*/
1321 if (tdvp == vp)
1322 vrele(vp);
1323 else
1324 vput(vp);
1325 return (EXDEV);
1326 }
1327
1328 /*
1329 * Push all writes to the server, so that the attribute cache
1330 * doesn't get "out of sync" with the server.
1331 * XXX There should be a better way!
1332 */
1333 VOP_FSYNC(tdvp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
1334
1335 nfsstats.rpccnt[NFSPROC_LINK]++;
1336 nfsm_reqhead(tdvp, NFSPROC_LINK,
1337 NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1338 nfsm_fhtom(tdvp);
1339 nfsm_fhtom(vp);
1340 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1341 nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
1342 nfsm_reqdone;
1343 FREE(cnp->cn_pnbuf, M_NAMEI);
1344 VTONFS(tdvp)->n_attrstamp = 0;
1345 VTONFS(vp)->n_flag |= NMODIFIED;
1346 VTONFS(vp)->n_attrstamp = 0;
1347 vrele(vp);
1348 /*
1349 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1350 */
1351 if (error == EEXIST)
1352 error = 0;
1353 return (error);
1354 }
1355
1356 /*
1357 * nfs symbolic link create call
1358 */
1359 /* start here */
1360 int
1361 nfs_symlink(ap)
1362 struct vop_symlink_args /* {
1363 struct vnode *a_dvp;
1364 struct vnode **a_vpp;
1365 struct componentname *a_cnp;
1366 struct vattr *a_vap;
1367 char *a_target;
1368 } */ *ap;
1369 {
1370 register struct vnode *dvp = ap->a_dvp;
1371 register struct vattr *vap = ap->a_vap;
1372 register struct componentname *cnp = ap->a_cnp;
1373 register struct nfsv2_sattr *sp;
1374 register u_int32_t *tl;
1375 register caddr_t cp;
1376 register int32_t t2;
1377 caddr_t bpos, dpos;
1378 int slen, error = 0, isnq;
1379 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1380
1381 nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1382 slen = strlen(ap->a_target);
1383 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
1384 nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
1385 nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
1386 nfsm_fhtom(dvp);
1387 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1388 nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
1389 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
1390 sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
1391 sp->sa_uid = nfs_xdrneg1;
1392 sp->sa_gid = nfs_xdrneg1;
1393 if (isnq) {
1394 quad_t qval = -1;
1395
1396 txdr_hyper(&qval, &sp->sa_nqsize);
1397 sp->sa_nqflags = 0;
1398 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1399 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1400 } else {
1401 sp->sa_nfssize = nfs_xdrneg1;
1402 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1403 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1404 }
1405 nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
1406 nfsm_reqdone;
1407 FREE(cnp->cn_pnbuf, M_NAMEI);
1408 VTONFS(dvp)->n_flag |= NMODIFIED;
1409 VTONFS(dvp)->n_attrstamp = 0;
1410 vrele(dvp);
1411 /*
1412 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1413 */
1414 if (error == EEXIST)
1415 error = 0;
1416 return (error);
1417 }
1418
1419 /*
1420 * nfs make dir call
1421 */
1422 int
1423 nfs_mkdir(ap)
1424 struct vop_mkdir_args /* {
1425 struct vnode *a_dvp;
1426 struct vnode **a_vpp;
1427 struct componentname *a_cnp;
1428 struct vattr *a_vap;
1429 } */ *ap;
1430 {
1431 register struct vnode *dvp = ap->a_dvp;
1432 register struct vattr *vap = ap->a_vap;
1433 register struct componentname *cnp = ap->a_cnp;
1434 register struct vnode **vpp = ap->a_vpp;
1435 register struct nfsv2_sattr *sp;
1436 register u_int32_t *tl;
1437 register caddr_t cp;
1438 register int32_t t1, t2;
1439 register int len;
1440 caddr_t bpos, dpos, cp2;
1441 int error = 0, firsttry = 1, isnq;
1442 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1443
1444 len = cnp->cn_namelen;
1445 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
1446 nfsstats.rpccnt[NFSPROC_MKDIR]++;
1447 nfsm_reqhead(dvp, NFSPROC_MKDIR,
1448 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
1449 nfsm_fhtom(dvp);
1450 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1451 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
1452 sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
1453 sp->sa_uid = nfs_xdrneg1;
1454 sp->sa_gid = nfs_xdrneg1;
1455 if (isnq) {
1456 quad_t qval = -1;
1457
1458 txdr_hyper(&qval, &sp->sa_nqsize);
1459 sp->sa_nqflags = 0;
1460 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1461 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1462 } else {
1463 sp->sa_nfssize = nfs_xdrneg1;
1464 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1465 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1466 }
1467 nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
1468 nfsm_mtofh(dvp, *vpp);
1469 nfsm_reqdone;
1470 VTONFS(dvp)->n_flag |= NMODIFIED;
1471 VTONFS(dvp)->n_attrstamp = 0;
1472 /*
1473 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1474 * if we can succeed in looking up the directory.
1475 * "firsttry" is necessary since the macros may "goto nfsmout" which
1476 * is above the if on errors. (Ugh)
1477 */
1478 if (error == EEXIST && firsttry) {
1479 firsttry = 0;
1480 error = 0;
1481 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1482 *vpp = NULL;
1483 nfsm_reqhead(dvp, NFSPROC_LOOKUP,
1484 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1485 nfsm_fhtom(dvp);
1486 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1487 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
1488 nfsm_mtofh(dvp, *vpp);
1489 if ((*vpp)->v_type != VDIR) {
1490 vput(*vpp);
1491 error = EEXIST;
1492 }
1493 m_freem(mrep);
1494 }
1495 FREE(cnp->cn_pnbuf, M_NAMEI);
1496 vrele(dvp);
1497 return (error);
1498 }
1499
1500 /*
1501 * nfs remove directory call
1502 */
1503 int
1504 nfs_rmdir(ap)
1505 struct vop_rmdir_args /* {
1506 struct vnode *a_dvp;
1507 struct vnode *a_vp;
1508 struct componentname *a_cnp;
1509 } */ *ap;
1510 {
1511 register struct vnode *vp = ap->a_vp;
1512 register struct vnode *dvp = ap->a_dvp;
1513 register struct componentname *cnp = ap->a_cnp;
1514 register u_int32_t *tl;
1515 register caddr_t cp;
1516 register int32_t t2;
1517 caddr_t bpos, dpos;
1518 int error = 0;
1519 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1520
1521 if (dvp == vp) {
1522 vrele(dvp);
1523 vrele(dvp);
1524 FREE(cnp->cn_pnbuf, M_NAMEI);
1525 return (EINVAL);
1526 }
1527 nfsstats.rpccnt[NFSPROC_RMDIR]++;
1528 nfsm_reqhead(dvp, NFSPROC_RMDIR,
1529 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1530 nfsm_fhtom(dvp);
1531 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1532 nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
1533 nfsm_reqdone;
1534 FREE(cnp->cn_pnbuf, M_NAMEI);
1535 VTONFS(dvp)->n_flag |= NMODIFIED;
1536 VTONFS(dvp)->n_attrstamp = 0;
1537 cache_purge(dvp);
1538 cache_purge(vp);
1539 vrele(vp);
1540 vrele(dvp);
1541 /*
1542 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1543 */
1544 if (error == ENOENT)
1545 error = 0;
1546 return (error);
1547 }
1548
1549 /*
1550 * nfs readdir call
1551 * Although cookie is defined as opaque, I translate it to/from net byte
1552 * order so that it looks more sensible. This appears consistent with the
1553 * Ultrix implementation of NFS.
1554 */
1555 int
1556 nfs_readdir(ap)
1557 struct vop_readdir_args /* {
1558 struct vnode *a_vp;
1559 struct uio *a_uio;
1560 struct ucred *a_cred;
1561 int *a_eofflag;
1562 u_long *a_cookies;
1563 int a_ncookies;
1564 } */ *ap;
1565 {
1566 register struct vnode *vp = ap->a_vp;
1567 register struct nfsnode *np = VTONFS(vp);
1568 register struct uio *uio = ap->a_uio;
1569 char *base = uio->uio_iov->iov_base;
1570 int tresid, error;
1571 struct vattr vattr;
1572
1573 if (vp->v_type != VDIR)
1574 return (EPERM);
1575 /*
1576 * First, check for hit on the EOF offset cache
1577 */
1578 if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
1579 (np->n_flag & NMODIFIED) == 0) {
1580 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
1581 if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
1582 nfsstats.direofcache_hits++;
1583 return (0);
1584 }
1585 } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
1586 np->n_mtime == vattr.va_mtime.tv_sec) {
1587 nfsstats.direofcache_hits++;
1588 return (0);
1589 }
1590 }
1591
1592 /*
1593 * Call nfs_bioread() to do the real work.
1594 */
1595 tresid = uio->uio_resid;
1596 error = nfs_bioread(vp, uio, 0, ap->a_cred);
1597
1598 if (!error && uio->uio_resid == tresid)
1599 nfsstats.direofcache_misses++;
1600
1601 if (!error && ap->a_cookies) {
1602 struct dirent *dp;
1603 u_long *cptr, *cookies = ap->a_cookies;
1604 int ncookies = ap->a_ncookies;
1605
1606 /*
1607 * Only the NFS server and emulations use cookies, and they
1608 * load the directory block into system space, so we can
1609 * just look at it directly.
1610 */
1611 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1612 panic("ufs_readdir: lost in space");
1613 while (ncookies-- && base < uio->uio_iov->iov_base) {
1614 dp = (struct dirent *) base;
1615 if (dp->d_reclen == 0)
1616 break;
1617 cptr = (u_long *)((caddr_t)dp + dp->d_reclen -
1618 sizeof(u_long));
1619 *(cookies++) = *cptr;
1620 base += dp->d_reclen;
1621 }
1622 uio->uio_resid += (uio->uio_iov->iov_base - base);
1623 uio->uio_iov->iov_len += (uio->uio_iov->iov_base - base);
1624 uio->uio_iov->iov_base = base;
1625 }
1626
1627 return (error);
1628 }
1629
1630 /*
1631 * Readdir rpc call.
1632 * Called from below the buffer cache by nfs_doio().
1633 */
1634 int
1635 nfs_readdirrpc(vp, uiop, cred)
1636 register struct vnode *vp;
1637 struct uio *uiop;
1638 struct ucred *cred;
1639 {
1640 register long len;
1641 register struct dirent *dp;
1642 register u_int32_t *tl;
1643 register caddr_t cp;
1644 register int32_t t1;
1645 long tlen, lastlen;
1646 caddr_t bpos, dpos, cp2;
1647 int error = 0;
1648 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1649 struct mbuf *md2;
1650 caddr_t dpos2;
1651 int siz;
1652 int more_dirs = 1;
1653 u_long off, savoff;
1654 struct dirent *savdp;
1655 struct nfsmount *nmp;
1656 struct nfsnode *np = VTONFS(vp);
1657 long tresid, extra;
1658
1659 nmp = VFSTONFS(vp->v_mount);
1660 extra = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1661 uiop->uio_resid -= extra;
1662 tresid = uiop->uio_resid;
1663 /*
1664 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
1665 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
1666 * The stopping criteria is EOF or buffer full.
1667 */
1668 while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
1669 nfsstats.rpccnt[NFSPROC_READDIR]++;
1670 nfsm_reqhead(vp, NFSPROC_READDIR,
1671 NFSX_FH + 2 * NFSX_UNSIGNED);
1672 nfsm_fhtom(vp);
1673 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1674 off = (u_long)uiop->uio_offset;
1675 *tl++ = txdr_unsigned(off);
1676 *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1677 nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
1678 nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
1679 siz = 0;
1680 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1681 more_dirs = fxdr_unsigned(int, *tl);
1682
1683 /* Save the position so that we can do nfsm_mtouio() later */
1684 dpos2 = dpos;
1685 md2 = md;
1686
1687 /* loop thru the dir entries, doctoring them to 4bsd form */
1688 #ifdef lint
1689 dp = (struct dirent *)0;
1690 #endif /* lint */
1691 while (more_dirs && siz < uiop->uio_resid) {
1692 savoff = off; /* Hold onto offset and dp */
1693 savdp = dp;
1694 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1695 dp = (struct dirent *)tl;
1696 dp->d_fileno = fxdr_unsigned(u_int32_t, *tl++);
1697 len = fxdr_unsigned(int, *tl);
1698 if (len <= 0 || len > NFS_MAXNAMLEN) {
1699 error = EBADRPC;
1700 m_freem(mrep);
1701 goto nfsmout;
1702 }
1703 dp->d_namlen = (u_char)len;
1704 dp->d_type = DT_UNKNOWN;
1705 nfsm_adv(len); /* Point past name */
1706 tlen = nfsm_rndup(len);
1707 /*
1708 * This should not be necessary, but some servers have
1709 * broken XDR such that these bytes are not null filled.
1710 */
1711 if (tlen != len) {
1712 *dpos = '\0'; /* Null-terminate */
1713 nfsm_adv(tlen - len);
1714 len = tlen;
1715 }
1716 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1717 off = fxdr_unsigned(u_int32_t, *tl);
1718 *tl++ = 0; /* Ensures null termination of name */
1719 more_dirs = fxdr_unsigned(int, *tl);
1720 *tl = off; /* Store offset for cookie retrieval */
1721 dp->d_reclen = len + 4 * NFSX_UNSIGNED;
1722 siz += dp->d_reclen;
1723 }
1724 /*
1725 * If at end of rpc data, get the eof boolean
1726 */
1727 if (!more_dirs) {
1728 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1729 more_dirs = (fxdr_unsigned(int, *tl) == 0);
1730
1731 /*
1732 * If at EOF, cache directory offset
1733 */
1734 if (!more_dirs)
1735 np->n_direofoffset = off;
1736 }
1737 /*
1738 * If there is too much to fit in the data buffer, use savoff and
1739 * savdp to trim off the last record.
1740 * --> we are not at eof
1741 */
1742 if (siz > uiop->uio_resid) {
1743 off = savoff;
1744 siz -= dp->d_reclen;
1745 dp = savdp;
1746 more_dirs = 0; /* Paranoia */
1747 }
1748 if (siz > 0) {
1749 lastlen = dp->d_reclen;
1750 md = md2;
1751 dpos = dpos2;
1752 nfsm_mtouio(uiop, siz);
1753 uiop->uio_offset = (off_t)off;
1754 } else
1755 more_dirs = 0; /* Ugh, never happens, but in case.. */
1756 m_freem(mrep);
1757 }
1758 /*
1759 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
1760 * by increasing d_reclen for the last record.
1761 */
1762 if (uiop->uio_resid < tresid) {
1763 len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1764 if (len > 0) {
1765 dp = (struct dirent *)
1766 (uiop->uio_iov->iov_base - lastlen);
1767 dp->d_reclen += len;
1768 *(u_long *)((caddr_t)dp + dp->d_reclen -
1769 sizeof(u_long)) = off;
1770 uiop->uio_iov->iov_base += len;
1771 uiop->uio_iov->iov_len -= len;
1772 uiop->uio_resid -= len;
1773 }
1774 }
1775 nfsmout:
1776 uiop->uio_resid += extra;
1777 return (error);
1778 }
1779
1780 /*
1781 * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
1782 */
1783 int
1784 nfs_readdirlookrpc(vp, uiop, cred)
1785 struct vnode *vp;
1786 register struct uio *uiop;
1787 struct ucred *cred;
1788 {
1789 register int len;
1790 register struct dirent *dp;
1791 register u_int32_t *tl;
1792 register caddr_t cp;
1793 register int32_t t1;
1794 caddr_t bpos, dpos, cp2;
1795 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1796 struct nameidata nami, *ndp = &nami;
1797 struct componentname *cnp = &ndp->ni_cnd;
1798 u_long off, endoff, fileno;
1799 time_t reqtime, ltime;
1800 struct nfsmount *nmp;
1801 struct nfsnode *np;
1802 struct vnode *newvp;
1803 nfsv2fh_t *fhp;
1804 u_quad_t frev;
1805 int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
1806 int cachable;
1807
1808 if (uiop->uio_iovcnt != 1)
1809 panic("nfs rdirlook");
1810 nmp = VFSTONFS(vp->v_mount);
1811 tresid = uiop->uio_resid;
1812 ndp->ni_dvp = vp;
1813 newvp = NULLVP;
1814 /*
1815 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
1816 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
1817 * The stopping criteria is EOF or buffer full.
1818 */
1819 while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
1820 nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
1821 nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
1822 NFSX_FH + 3 * NFSX_UNSIGNED);
1823 nfsm_fhtom(vp);
1824 nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1825 off = (u_long)uiop->uio_offset;
1826 *tl++ = txdr_unsigned(off);
1827 *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1828 nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
1829 if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
1830 *tl = txdr_unsigned(nmp->nm_leaseterm);
1831 else
1832 *tl = 0;
1833 reqtime = time.tv_sec;
1834 nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
1835 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1836 more_dirs = fxdr_unsigned(int, *tl);
1837
1838 /* loop thru the dir entries, doctoring them to 4bsd form */
1839 bigenough = 1;
1840 while (more_dirs && bigenough) {
1841 doit = 1;
1842 nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1843 if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
1844 cachable = fxdr_unsigned(int, *tl++);
1845 ltime = reqtime + fxdr_unsigned(int, *tl++);
1846 fxdr_hyper(tl, &frev);
1847 }
1848 nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
1849 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
1850 VREF(vp);
1851 newvp = vp;
1852 np = VTONFS(vp);
1853 } else {
1854 if (error = nfs_nget(vp->v_mount, fhp, &np))
1855 doit = 0;
1856 newvp = NFSTOV(np);
1857 }
1858 if (error = nfs_loadattrcache(&newvp, &md, &dpos,
1859 (struct vattr *)0))
1860 doit = 0;
1861 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1862 fileno = fxdr_unsigned(u_int32_t, *tl++);
1863 len = fxdr_unsigned(int, *tl);
1864 if (len <= 0 || len > NFS_MAXNAMLEN) {
1865 error = EBADRPC;
1866 m_freem(mrep);
1867 goto nfsmout;
1868 }
1869 tlen = (len + 4) & ~0x3;
1870 if ((tlen + DIRHDSIZ) > uiop->uio_resid)
1871 bigenough = 0;
1872 if (bigenough && doit) {
1873 dp = (struct dirent *)uiop->uio_iov->iov_base;
1874 dp->d_fileno = fileno;
1875 dp->d_namlen = len;
1876 dp->d_reclen = tlen + DIRHDSIZ;
1877 dp->d_type =
1878 IFTODT(VTTOIF(np->n_vattr.va_type));
1879 uiop->uio_resid -= DIRHDSIZ;
1880 uiop->uio_iov->iov_base += DIRHDSIZ;
1881 uiop->uio_iov->iov_len -= DIRHDSIZ;
1882 cnp->cn_nameptr = uiop->uio_iov->iov_base;
1883 cnp->cn_namelen = len;
1884 ndp->ni_vp = newvp;
1885 nfsm_mtouio(uiop, len);
1886 cp = uiop->uio_iov->iov_base;
1887 tlen -= len;
1888 for (i = 0; i < tlen; i++)
1889 *cp++ = '\0';
1890 uiop->uio_iov->iov_base += tlen;
1891 uiop->uio_iov->iov_len -= tlen;
1892 uiop->uio_resid -= tlen;
1893 cnp->cn_hash = 0;
1894 for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
1895 cnp->cn_hash += (unsigned char)*cp * i;
1896 if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
1897 ltime > time.tv_sec)
1898 nqnfs_clientlease(nmp, np, NQL_READ,
1899 cachable, ltime, frev);
1900 if (cnp->cn_namelen <= NCHNAMLEN)
1901 cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
1902 } else {
1903 nfsm_adv(nfsm_rndup(len));
1904 }
1905 if (newvp != NULLVP) {
1906 vrele(newvp);
1907 newvp = NULLVP;
1908 }
1909 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1910 if (bigenough)
1911 endoff = off = fxdr_unsigned(u_int32_t, *tl++);
1912 else
1913 endoff = fxdr_unsigned(u_int32_t, *tl++);
1914 more_dirs = fxdr_unsigned(int, *tl);
1915 *tl = endoff; /* Store offset for cookies. */
1916 }
1917 /*
1918 * If at end of rpc data, get the eof boolean
1919 */
1920 if (!more_dirs) {
1921 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1922 more_dirs = (fxdr_unsigned(int, *tl) == 0);
1923
1924 /*
1925 * If at EOF, cache directory offset
1926 */
1927 if (!more_dirs)
1928 VTONFS(vp)->n_direofoffset = endoff;
1929 }
1930 if (uiop->uio_resid < tresid)
1931 uiop->uio_offset = (off_t)off;
1932 else
1933 more_dirs = 0;
1934 m_freem(mrep);
1935 }
1936 /*
1937 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
1938 * by increasing d_reclen for the last record.
1939 */
1940 if (uiop->uio_resid < tresid) {
1941 len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1942 if (len > 0) {
1943 dp->d_reclen += len;
1944 *(u_long *)((caddr_t)dp + dp->d_reclen -
1945 sizeof(u_long)) = off;
1946 uiop->uio_iov->iov_base += len;
1947 uiop->uio_iov->iov_len -= len;
1948 uiop->uio_resid -= len;
1949 }
1950 }
1951 nfsmout:
1952 if (newvp != NULLVP)
1953 vrele(newvp);
1954 return (error);
1955 }
1956 static char hextoasc[] = "0123456789abcdef";
1957
1958 /*
1959 * Silly rename. To make the NFS filesystem that is stateless look a little
1960 * more like the "ufs" a remove of an active vnode is translated to a rename
1961 * to a funny looking filename that is removed by nfs_inactive on the
1962 * nfsnode. There is the potential for another process on a different client
1963 * to create the same funny name between the nfs_lookitup() fails and the
1964 * nfs_rename() completes, but...
1965 */
1966 int
1967 nfs_sillyrename(dvp, vp, cnp)
1968 struct vnode *dvp, *vp;
1969 struct componentname *cnp;
1970 {
1971 register struct nfsnode *np;
1972 register struct sillyrename *sp;
1973 int error;
1974 short pid;
1975
1976 cache_purge(dvp);
1977 np = VTONFS(vp);
1978 #ifdef SILLYSEPARATE
1979 MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
1980 M_NFSREQ, M_WAITOK);
1981 #else
1982 sp = &np->n_silly;
1983 #endif
1984 sp->s_cred = crdup(cnp->cn_cred);
1985 sp->s_dvp = dvp;
1986 VREF(dvp);
1987
1988 /* Fudge together a funny name */
1989 pid = cnp->cn_proc->p_pid;
1990 bcopy(".nfsAxxxx4.4", sp->s_name, 13);
1991 sp->s_namlen = 12;
1992 sp->s_name[8] = hextoasc[pid & 0xf];
1993 sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
1994 sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
1995 sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
1996
1997 /* Try lookitups until we get one that isn't there */
1998 while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
1999 sp->s_name[4]++;
2000 if (sp->s_name[4] > 'z') {
2001 error = EINVAL;
2002 goto bad;
2003 }
2004 }
2005 if (error = nfs_renameit(dvp, cnp, sp))
2006 goto bad;
2007 nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
2008 np->n_sillyrename = sp;
2009 return (0);
2010 bad:
2011 vrele(sp->s_dvp);
2012 crfree(sp->s_cred);
2013 #ifdef SILLYSEPARATE
2014 free((caddr_t)sp, M_NFSREQ);
2015 #endif
2016 return (error);
2017 }
2018
2019 /*
2020 * Look up a file name for silly rename stuff.
2021 * Just like nfs_lookup() except that it doesn't load returned values
2022 * into the nfsnode table.
2023 * If fhp != NULL it copies the returned file handle out
2024 */
2025 int
2026 nfs_lookitup(sp, fhp, procp)
2027 register struct sillyrename *sp;
2028 nfsv2fh_t *fhp;
2029 struct proc *procp;
2030 {
2031 register struct vnode *vp = sp->s_dvp;
2032 register u_int32_t *tl;
2033 register caddr_t cp;
2034 register int32_t t1, t2;
2035 caddr_t bpos, dpos, cp2;
2036 int error = 0, isnq;
2037 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2038 long len;
2039
2040 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
2041 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
2042 len = sp->s_namlen;
2043 nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
2044 if (isnq) {
2045 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
2046 *tl = 0;
2047 }
2048 nfsm_fhtom(vp);
2049 nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
2050 nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
2051 if (fhp != NULL) {
2052 if (isnq)
2053 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
2054 nfsm_dissect(cp, caddr_t, NFSX_FH);
2055 bcopy(cp, (caddr_t)fhp, NFSX_FH);
2056 }
2057 nfsm_reqdone;
2058 return (error);
2059 }
2060
2061 /*
2062 * Kludge City..
2063 * - make nfs_bmap() essentially a no-op that does no translation
2064 * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
2065 * after mapping the physical addresses into Kernel Virtual space in the
2066 * nfsiobuf area.
2067 * (Maybe I could use the process's page mapping, but I was concerned that
2068 * Kernel Write might not be enabled and also figured copyout() would do
2069 * a lot more work than bcopy() and also it currently happens in the
2070 * context of the swapper process (2).
2071 */
2072 int
2073 nfs_bmap(ap)
2074 struct vop_bmap_args /* {
2075 struct vnode *a_vp;
2076 daddr_t a_bn;
2077 struct vnode **a_vpp;
2078 daddr_t *a_bnp;
2079 int *a_runp;
2080 } */ *ap;
2081 {
2082 register struct vnode *vp = ap->a_vp;
2083
2084 if (ap->a_vpp != NULL)
2085 *ap->a_vpp = vp;
2086 if (ap->a_bnp != NULL)
2087 *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
2088 return (0);
2089 }
2090
2091 /*
2092 * Strategy routine.
2093 * For async requests when nfsiod(s) are running, queue the request by
2094 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
2095 * request.
2096 */
2097 int
2098 nfs_strategy(ap)
2099 struct vop_strategy_args *ap;
2100 {
2101 register struct buf *bp = ap->a_bp;
2102 struct ucred *cr;
2103 struct proc *p;
2104 int error = 0;
2105
2106 if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC))
2107 panic("nfs physio/async");
2108 if (bp->b_flags & B_ASYNC)
2109 p = (struct proc *)0;
2110 else
2111 p = curproc; /* XXX */
2112 if (bp->b_flags & B_READ)
2113 cr = bp->b_rcred;
2114 else
2115 cr = bp->b_wcred;
2116 /*
2117 * If the op is asynchronous and an i/o daemon is waiting
2118 * queue the request, wake it up and wait for completion
2119 * otherwise just do it ourselves.
2120 */
2121 if ((bp->b_flags & B_ASYNC) == 0 ||
2122 nfs_asyncio(bp, NOCRED))
2123 error = nfs_doio(bp, cr, p);
2124 return (error);
2125 }
2126
2127 /*
2128 * Mmap a file
2129 *
2130 * NB Currently unsupported.
2131 */
2132 /* ARGSUSED */
2133 int
2134 nfs_mmap(ap)
2135 struct vop_mmap_args /* {
2136 struct vnode *a_vp;
2137 int a_fflags;
2138 struct ucred *a_cred;
2139 struct proc *a_p;
2140 } */ *ap;
2141 {
2142
2143 return (EINVAL);
2144 }
2145
2146 /*
2147 * Flush all the blocks associated with a vnode.
2148 * Walk through the buffer pool and push any dirty pages
2149 * associated with the vnode.
2150 */
2151 /* ARGSUSED */
2152 int
2153 nfs_fsync(ap)
2154 struct vop_fsync_args /* {
2155 struct vnodeop_desc *a_desc;
2156 struct vnode * a_vp;
2157 struct ucred * a_cred;
2158 int a_waitfor;
2159 struct proc * a_p;
2160 } */ *ap;
2161 {
2162 register struct vnode *vp = ap->a_vp;
2163 register struct nfsnode *np = VTONFS(vp);
2164 register struct buf *bp;
2165 struct buf *nbp;
2166 struct nfsmount *nmp;
2167 int s, error = 0, slptimeo = 0, slpflag = 0;
2168
2169 nmp = VFSTONFS(vp->v_mount);
2170 if (nmp->nm_flag & NFSMNT_INT)
2171 slpflag = PCATCH;
2172 loop:
2173 s = splbio();
2174 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2175 nbp = bp->b_vnbufs.le_next;
2176 if (bp->b_flags & B_BUSY) {
2177 if (ap->a_waitfor != MNT_WAIT)
2178 continue;
2179 bp->b_flags |= B_WANTED;
2180 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
2181 "nfsfsync", slptimeo);
2182 splx(s);
2183 if (error) {
2184 if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
2185 return (EINTR);
2186 if (slpflag == PCATCH) {
2187 slpflag = 0;
2188 slptimeo = 2 * hz;
2189 }
2190 }
2191 goto loop;
2192 }
2193 if ((bp->b_flags & B_DELWRI) == 0)
2194 panic("nfs_fsync: not dirty");
2195 bremfree(bp);
2196 bp->b_flags |= B_BUSY;
2197 splx(s);
2198 bp->b_flags |= B_ASYNC;
2199 VOP_BWRITE(bp);
2200 goto loop;
2201 }
2202 splx(s);
2203 if (ap->a_waitfor == MNT_WAIT) {
2204 while (vp->v_numoutput) {
2205 vp->v_flag |= VBWAIT;
2206 error = tsleep((caddr_t)&vp->v_numoutput,
2207 slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
2208 if (error) {
2209 if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
2210 return (EINTR);
2211 if (slpflag == PCATCH) {
2212 slpflag = 0;
2213 slptimeo = 2 * hz;
2214 }
2215 }
2216 }
2217 if (vp->v_dirtyblkhd.lh_first) {
2218 #ifdef DIAGNOSTIC
2219 vprint("nfs_fsync: dirty", vp);
2220 #endif
2221 goto loop;
2222 }
2223 }
2224 if (np->n_flag & NWRITEERR) {
2225 error = np->n_error;
2226 np->n_flag &= ~NWRITEERR;
2227 }
2228 return (error);
2229 }
2230
2231 /*
2232 * Return POSIX pathconf information applicable to nfs.
2233 *
2234 * Currently the NFS protocol does not support getting such
2235 * information from the remote server.
2236 */
2237 /* ARGSUSED */
2238 nfs_pathconf(ap)
2239 struct vop_pathconf_args /* {
2240 struct vnode *a_vp;
2241 int a_name;
2242 register_t *a_retval;
2243 } */ *ap;
2244 {
2245
2246 return (EINVAL);
2247 }
2248
2249 /*
2250 * NFS advisory byte-level locks.
2251 */
2252 int
2253 nfs_advlock(ap)
2254 struct vop_advlock_args /* {
2255 struct vnode *a_vp;
2256 caddr_t a_id;
2257 int a_op;
2258 struct flock *a_fl;
2259 int a_flags;
2260 } */ *ap;
2261 {
2262 register struct nfsnode *np = VTONFS(ap->a_vp);
2263
2264 return (lf_advlock(&np->n_lockf, np->n_size, ap->a_id, ap->a_op,
2265 ap->a_fl, ap->a_flags));
2266 }
2267
2268 /*
2269 * Print out the contents of an nfsnode.
2270 */
2271 int
2272 nfs_print(ap)
2273 struct vop_print_args /* {
2274 struct vnode *a_vp;
2275 } */ *ap;
2276 {
2277 register struct vnode *vp = ap->a_vp;
2278 register struct nfsnode *np = VTONFS(vp);
2279
2280 printf("tag VT_NFS, fileid %d fsid 0x%x",
2281 np->n_vattr.va_fileid, np->n_vattr.va_fsid);
2282 #ifdef FIFO
2283 if (vp->v_type == VFIFO)
2284 fifo_printinfo(vp);
2285 #endif /* FIFO */
2286 printf("\n");
2287 }
2288
2289 /*
2290 * NFS directory offset lookup.
2291 * Currently unsupported.
2292 */
2293 int
2294 nfs_blkatoff(ap)
2295 struct vop_blkatoff_args /* {
2296 struct vnode *a_vp;
2297 off_t a_offset;
2298 char **a_res;
2299 struct buf **a_bpp;
2300 } */ *ap;
2301 {
2302
2303 return (EOPNOTSUPP);
2304 }
2305
2306 /*
2307 * NFS flat namespace allocation.
2308 * Currently unsupported.
2309 */
2310 int
2311 nfs_valloc(ap)
2312 struct vop_valloc_args /* {
2313 struct vnode *a_pvp;
2314 int a_mode;
2315 struct ucred *a_cred;
2316 struct vnode **a_vpp;
2317 } */ *ap;
2318 {
2319
2320 return (EOPNOTSUPP);
2321 }
2322
2323 /*
2324 * NFS flat namespace free.
2325 * Currently unsupported.
2326 */
2327 int
2328 nfs_vfree(ap)
2329 struct vop_vfree_args /* {
2330 struct vnode *a_pvp;
2331 ino_t a_ino;
2332 int a_mode;
2333 } */ *ap;
2334 {
2335
2336 return (EOPNOTSUPP);
2337 }
2338
2339 /*
2340 * NFS file truncation.
2341 */
2342 int
2343 nfs_truncate(ap)
2344 struct vop_truncate_args /* {
2345 struct vnode *a_vp;
2346 off_t a_length;
2347 int a_flags;
2348 struct ucred *a_cred;
2349 struct proc *a_p;
2350 } */ *ap;
2351 {
2352
2353 /* Use nfs_setattr */
2354 printf("nfs_truncate: need to implement!!");
2355 return (EOPNOTSUPP);
2356 }
2357
2358 /*
2359 * NFS update.
2360 */
2361 int
2362 nfs_update(ap)
2363 struct vop_update_args /* {
2364 struct vnode *a_vp;
2365 struct timeval *a_ta;
2366 struct timeval *a_tm;
2367 int a_waitfor;
2368 } */ *ap;
2369 {
2370
2371 /* Use nfs_setattr */
2372 printf("nfs_update: need to implement!!");
2373 return (EOPNOTSUPP);
2374 }
2375
2376 /*
2377 * nfs special file access vnode op.
2378 * Essentially just get vattr and then imitate iaccess() since the device is
2379 * local to the client.
2380 */
2381 int
2382 nfsspec_access(ap)
2383 struct vop_access_args /* {
2384 struct vnode *a_vp;
2385 int a_mode;
2386 struct ucred *a_cred;
2387 struct proc *a_p;
2388 } */ *ap;
2389 {
2390 struct vattr va;
2391 int error;
2392
2393 if (error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred, ap->a_p))
2394 return (error);
2395
2396 return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode,
2397 ap->a_cred));
2398 }
2399
2400 /*
2401 * Read wrapper for special devices.
2402 */
2403 int
2404 nfsspec_read(ap)
2405 struct vop_read_args /* {
2406 struct vnode *a_vp;
2407 struct uio *a_uio;
2408 int a_ioflag;
2409 struct ucred *a_cred;
2410 } */ *ap;
2411 {
2412 register struct nfsnode *np = VTONFS(ap->a_vp);
2413
2414 /*
2415 * Set access flag.
2416 */
2417 np->n_flag |= NACC;
2418 np->n_atim = time;
2419 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
2420 }
2421
2422 /*
2423 * Write wrapper for special devices.
2424 */
2425 int
2426 nfsspec_write(ap)
2427 struct vop_write_args /* {
2428 struct vnode *a_vp;
2429 struct uio *a_uio;
2430 int a_ioflag;
2431 struct ucred *a_cred;
2432 } */ *ap;
2433 {
2434 register struct nfsnode *np = VTONFS(ap->a_vp);
2435
2436 /*
2437 * Set update flag.
2438 */
2439 np->n_flag |= NUPD;
2440 np->n_mtim = time;
2441 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
2442 }
2443
2444 /*
2445 * Close wrapper for special devices.
2446 *
2447 * Update the times on the nfsnode then do device close.
2448 */
2449 int
2450 nfsspec_close(ap)
2451 struct vop_close_args /* {
2452 struct vnode *a_vp;
2453 int a_fflag;
2454 struct ucred *a_cred;
2455 struct proc *a_p;
2456 } */ *ap;
2457 {
2458 register struct vnode *vp = ap->a_vp;
2459 register struct nfsnode *np = VTONFS(vp);
2460 struct vattr vattr;
2461
2462 if (np->n_flag & (NACC | NUPD)) {
2463 np->n_flag |= NCHG;
2464 if (vp->v_usecount == 1 &&
2465 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
2466 VATTR_NULL(&vattr);
2467 if (np->n_flag & NACC) {
2468 vattr.va_atime.tv_sec = np->n_atim.tv_sec;
2469 vattr.va_atime.tv_nsec =
2470 np->n_atim.tv_usec * 1000;
2471 }
2472 if (np->n_flag & NUPD) {
2473 vattr.va_mtime.tv_sec = np->n_mtim.tv_sec;
2474 vattr.va_mtime.tv_nsec =
2475 np->n_mtim.tv_usec * 1000;
2476 }
2477 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
2478 }
2479 }
2480 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
2481 }
2482
2483 #ifdef FIFO
2484 /*
2485 * Read wrapper for fifos.
2486 */
2487 int
2488 nfsfifo_read(ap)
2489 struct vop_read_args /* {
2490 struct vnode *a_vp;
2491 struct uio *a_uio;
2492 int a_ioflag;
2493 struct ucred *a_cred;
2494 } */ *ap;
2495 {
2496 extern int (**fifo_vnodeop_p)();
2497 register struct nfsnode *np = VTONFS(ap->a_vp);
2498
2499 /*
2500 * Set access flag.
2501 */
2502 np->n_flag |= NACC;
2503 np->n_atim = time;
2504 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
2505 }
2506
2507 /*
2508 * Write wrapper for fifos.
2509 */
2510 int
2511 nfsfifo_write(ap)
2512 struct vop_write_args /* {
2513 struct vnode *a_vp;
2514 struct uio *a_uio;
2515 int a_ioflag;
2516 struct ucred *a_cred;
2517 } */ *ap;
2518 {
2519 extern int (**fifo_vnodeop_p)();
2520 register struct nfsnode *np = VTONFS(ap->a_vp);
2521
2522 /*
2523 * Set update flag.
2524 */
2525 np->n_flag |= NUPD;
2526 np->n_mtim = time;
2527 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
2528 }
2529
2530 /*
2531 * Close wrapper for fifos.
2532 *
2533 * Update the times on the nfsnode then do fifo close.
2534 */
2535 int
2536 nfsfifo_close(ap)
2537 struct vop_close_args /* {
2538 struct vnode *a_vp;
2539 int a_fflag;
2540 struct ucred *a_cred;
2541 struct proc *a_p;
2542 } */ *ap;
2543 {
2544 register struct vnode *vp = ap->a_vp;
2545 register struct nfsnode *np = VTONFS(vp);
2546 struct vattr vattr;
2547 extern int (**fifo_vnodeop_p)();
2548
2549 if (np->n_flag & (NACC | NUPD)) {
2550 if (np->n_flag & NACC)
2551 np->n_atim = time;
2552 if (np->n_flag & NUPD)
2553 np->n_mtim = time;
2554 np->n_flag |= NCHG;
2555 if (vp->v_usecount == 1 &&
2556 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
2557 VATTR_NULL(&vattr);
2558 if (np->n_flag & NACC) {
2559 vattr.va_atime.tv_sec = np->n_atim.tv_sec;
2560 vattr.va_atime.tv_nsec =
2561 np->n_atim.tv_usec * 1000;
2562 }
2563 if (np->n_flag & NUPD) {
2564 vattr.va_mtime.tv_sec = np->n_mtim.tv_sec;
2565 vattr.va_mtime.tv_nsec =
2566 np->n_mtim.tv_usec * 1000;
2567 }
2568 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
2569 }
2570 }
2571 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
2572 }
2573 #endif /* FIFO */
2574