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