nfs_vnops.c revision 1.1.1.4 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.19 (Berkeley) 7/31/95
37 */
38
39
40 /*
41 * vnode op calls for Sun NFS version 2 and 3
42 */
43
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/resourcevar.h>
48 #include <sys/proc.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/dirent.h>
57 #include <sys/fcntl.h>
58 #include <ufs/ufs/dir.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/nfsproto.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 #include <net/if.h>
75 #include <netinet/in.h>
76 #include <netinet/in_var.h>
77
78 /* Defs */
79 #define TRUE 1
80 #define FALSE 0
81
82 /*
83 * Global vfs data structures for nfs
84 */
85 int (**nfsv2_vnodeop_p)();
86 struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
87 { &vop_default_desc, vn_default_error },
88 { &vop_lookup_desc, nfs_lookup }, /* lookup */
89 { &vop_create_desc, nfs_create }, /* create */
90 { &vop_mknod_desc, nfs_mknod }, /* mknod */
91 { &vop_open_desc, nfs_open }, /* open */
92 { &vop_close_desc, nfs_close }, /* close */
93 { &vop_access_desc, nfs_access }, /* access */
94 { &vop_getattr_desc, nfs_getattr }, /* getattr */
95 { &vop_setattr_desc, nfs_setattr }, /* setattr */
96 { &vop_read_desc, nfs_read }, /* read */
97 { &vop_write_desc, nfs_write }, /* write */
98 { &vop_lease_desc, nfs_lease_check }, /* lease */
99 { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */
100 { &vop_select_desc, nfs_select }, /* select */
101 { &vop_revoke_desc, nfs_revoke }, /* revoke */
102 { &vop_mmap_desc, nfs_mmap }, /* mmap */
103 { &vop_fsync_desc, nfs_fsync }, /* fsync */
104 { &vop_seek_desc, nfs_seek }, /* seek */
105 { &vop_remove_desc, nfs_remove }, /* remove */
106 { &vop_link_desc, nfs_link }, /* link */
107 { &vop_rename_desc, nfs_rename }, /* rename */
108 { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */
109 { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */
110 { &vop_symlink_desc, nfs_symlink }, /* symlink */
111 { &vop_readdir_desc, nfs_readdir }, /* readdir */
112 { &vop_readlink_desc, nfs_readlink }, /* readlink */
113 { &vop_abortop_desc, nfs_abortop }, /* abortop */
114 { &vop_inactive_desc, nfs_inactive }, /* inactive */
115 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
116 { &vop_lock_desc, nfs_lock }, /* lock */
117 { &vop_unlock_desc, nfs_unlock }, /* unlock */
118 { &vop_bmap_desc, nfs_bmap }, /* bmap */
119 { &vop_strategy_desc, nfs_strategy }, /* strategy */
120 { &vop_print_desc, nfs_print }, /* print */
121 { &vop_islocked_desc, nfs_islocked }, /* islocked */
122 { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */
123 { &vop_advlock_desc, nfs_advlock }, /* advlock */
124 { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */
125 { &vop_valloc_desc, nfs_valloc }, /* valloc */
126 { &vop_reallocblks_desc, nfs_reallocblks }, /* reallocblks */
127 { &vop_vfree_desc, nfs_vfree }, /* vfree */
128 { &vop_truncate_desc, nfs_truncate }, /* truncate */
129 { &vop_update_desc, nfs_update }, /* update */
130 { &vop_bwrite_desc, nfs_bwrite },
131 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
132 };
133 struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
134 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
135
136 /*
137 * Special device vnode ops
138 */
139 int (**spec_nfsv2nodeop_p)();
140 struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
141 { &vop_default_desc, vn_default_error },
142 { &vop_lookup_desc, spec_lookup }, /* lookup */
143 { &vop_create_desc, spec_create }, /* create */
144 { &vop_mknod_desc, spec_mknod }, /* mknod */
145 { &vop_open_desc, spec_open }, /* open */
146 { &vop_close_desc, nfsspec_close }, /* close */
147 { &vop_access_desc, nfsspec_access }, /* access */
148 { &vop_getattr_desc, nfs_getattr }, /* getattr */
149 { &vop_setattr_desc, nfs_setattr }, /* setattr */
150 { &vop_read_desc, nfsspec_read }, /* read */
151 { &vop_write_desc, nfsspec_write }, /* write */
152 { &vop_lease_desc, spec_lease_check }, /* lease */
153 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
154 { &vop_select_desc, spec_select }, /* select */
155 { &vop_revoke_desc, spec_revoke }, /* revoke */
156 { &vop_mmap_desc, spec_mmap }, /* mmap */
157 { &vop_fsync_desc, nfs_fsync }, /* fsync */
158 { &vop_seek_desc, spec_seek }, /* seek */
159 { &vop_remove_desc, spec_remove }, /* remove */
160 { &vop_link_desc, spec_link }, /* link */
161 { &vop_rename_desc, spec_rename }, /* rename */
162 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
163 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
164 { &vop_symlink_desc, spec_symlink }, /* symlink */
165 { &vop_readdir_desc, spec_readdir }, /* readdir */
166 { &vop_readlink_desc, spec_readlink }, /* readlink */
167 { &vop_abortop_desc, spec_abortop }, /* abortop */
168 { &vop_inactive_desc, nfs_inactive }, /* inactive */
169 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
170 { &vop_lock_desc, nfs_lock }, /* lock */
171 { &vop_unlock_desc, nfs_unlock }, /* unlock */
172 { &vop_bmap_desc, spec_bmap }, /* bmap */
173 { &vop_strategy_desc, spec_strategy }, /* strategy */
174 { &vop_print_desc, nfs_print }, /* print */
175 { &vop_islocked_desc, nfs_islocked }, /* islocked */
176 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
177 { &vop_advlock_desc, spec_advlock }, /* advlock */
178 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
179 { &vop_valloc_desc, spec_valloc }, /* valloc */
180 { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
181 { &vop_vfree_desc, spec_vfree }, /* vfree */
182 { &vop_truncate_desc, spec_truncate }, /* truncate */
183 { &vop_update_desc, nfs_update }, /* update */
184 { &vop_bwrite_desc, vn_bwrite },
185 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
186 };
187 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
188 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
189
190 int (**fifo_nfsv2nodeop_p)();
191 struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
192 { &vop_default_desc, vn_default_error },
193 { &vop_lookup_desc, fifo_lookup }, /* lookup */
194 { &vop_create_desc, fifo_create }, /* create */
195 { &vop_mknod_desc, fifo_mknod }, /* mknod */
196 { &vop_open_desc, fifo_open }, /* open */
197 { &vop_close_desc, nfsfifo_close }, /* close */
198 { &vop_access_desc, nfsspec_access }, /* access */
199 { &vop_getattr_desc, nfs_getattr }, /* getattr */
200 { &vop_setattr_desc, nfs_setattr }, /* setattr */
201 { &vop_read_desc, nfsfifo_read }, /* read */
202 { &vop_write_desc, nfsfifo_write }, /* write */
203 { &vop_lease_desc, fifo_lease_check }, /* lease */
204 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
205 { &vop_select_desc, fifo_select }, /* select */
206 { &vop_revoke_desc, fifo_revoke }, /* revoke */
207 { &vop_mmap_desc, fifo_mmap }, /* mmap */
208 { &vop_fsync_desc, nfs_fsync }, /* fsync */
209 { &vop_seek_desc, fifo_seek }, /* seek */
210 { &vop_remove_desc, fifo_remove }, /* remove */
211 { &vop_link_desc, fifo_link }, /* link */
212 { &vop_rename_desc, fifo_rename }, /* rename */
213 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
214 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
215 { &vop_symlink_desc, fifo_symlink }, /* symlink */
216 { &vop_readdir_desc, fifo_readdir }, /* readdir */
217 { &vop_readlink_desc, fifo_readlink }, /* readlink */
218 { &vop_abortop_desc, fifo_abortop }, /* abortop */
219 { &vop_inactive_desc, nfs_inactive }, /* inactive */
220 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
221 { &vop_lock_desc, nfs_lock }, /* lock */
222 { &vop_unlock_desc, nfs_unlock }, /* unlock */
223 { &vop_bmap_desc, fifo_bmap }, /* bmap */
224 { &vop_strategy_desc, fifo_badop }, /* strategy */
225 { &vop_print_desc, nfs_print }, /* print */
226 { &vop_islocked_desc, nfs_islocked }, /* islocked */
227 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
228 { &vop_advlock_desc, fifo_advlock }, /* advlock */
229 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
230 { &vop_valloc_desc, fifo_valloc }, /* valloc */
231 { &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */
232 { &vop_vfree_desc, fifo_vfree }, /* vfree */
233 { &vop_truncate_desc, fifo_truncate }, /* truncate */
234 { &vop_update_desc, nfs_update }, /* update */
235 { &vop_bwrite_desc, vn_bwrite },
236 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
237 };
238 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
239 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
240
241 void nqnfs_clientlease();
242 int nfs_commit();
243
244 /*
245 * Global variables
246 */
247 extern u_long nfs_true, nfs_false;
248 extern struct nfsstats nfsstats;
249 extern nfstype nfsv3_type[9];
250 struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
251 int nfs_numasync = 0;
252 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
253
254 /*
255 * nfs null call from vfs.
256 */
257 int
258 nfs_null(vp, cred, procp)
259 struct vnode *vp;
260 struct ucred *cred;
261 struct proc *procp;
262 {
263 caddr_t bpos, dpos;
264 int error = 0;
265 struct mbuf *mreq, *mrep, *md, *mb;
266
267 nfsm_reqhead(vp, NFSPROC_NULL, 0);
268 nfsm_request(vp, NFSPROC_NULL, procp, cred);
269 nfsm_reqdone;
270 return (error);
271 }
272
273 /*
274 * nfs access vnode op.
275 * For nfs version 2, just return ok. File accesses may fail later.
276 * For nfs version 3, use the access rpc to check accessibility. If file modes
277 * are changed on the server, accesses might still fail later.
278 */
279 int
280 nfs_access(ap)
281 struct vop_access_args /* {
282 struct vnode *a_vp;
283 int a_mode;
284 struct ucred *a_cred;
285 struct proc *a_p;
286 } */ *ap;
287 {
288 register struct vnode *vp = ap->a_vp;
289 register u_long *tl;
290 register caddr_t cp;
291 register int t1, t2;
292 caddr_t bpos, dpos, cp2;
293 int error = 0, attrflag;
294 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
295 u_long mode, rmode;
296 int v3 = NFS_ISV3(vp);
297
298 /*
299 * Disallow write attempts on filesystems mounted read-only;
300 * unless the file is a socket, fifo, or a block or character
301 * device resident on the filesystem.
302 */
303 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
304 switch (vp->v_type) {
305 case VREG: case VDIR: case VLNK:
306 return (EROFS);
307 }
308 }
309 /*
310 * For nfs v3, do an access rpc, otherwise you are stuck emulating
311 * ufs_access() locally using the vattr. This may not be correct,
312 * since the server may apply other access criteria such as
313 * client uid-->server uid mapping that we do not know about, but
314 * this is better than just returning anything that is lying about
315 * in the cache.
316 */
317 if (v3) {
318 nfsstats.rpccnt[NFSPROC_ACCESS]++;
319 nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
320 nfsm_fhtom(vp, v3);
321 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
322 if (ap->a_mode & VREAD)
323 mode = NFSV3ACCESS_READ;
324 else
325 mode = 0;
326 if (vp->v_type == VDIR) {
327 if (ap->a_mode & VWRITE)
328 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
329 NFSV3ACCESS_DELETE);
330 if (ap->a_mode & VEXEC)
331 mode |= NFSV3ACCESS_LOOKUP;
332 } else {
333 if (ap->a_mode & VWRITE)
334 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
335 if (ap->a_mode & VEXEC)
336 mode |= NFSV3ACCESS_EXECUTE;
337 }
338 *tl = txdr_unsigned(mode);
339 nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
340 nfsm_postop_attr(vp, attrflag);
341 if (!error) {
342 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
343 rmode = fxdr_unsigned(u_long, *tl);
344 /*
345 * The NFS V3 spec does not clarify whether or not
346 * the returned access bits can be a superset of
347 * the ones requested, so...
348 */
349 if ((rmode & mode) != mode)
350 error = EACCES;
351 }
352 nfsm_reqdone;
353 return (error);
354 } else
355 return (nfsspec_access(ap));
356 }
357
358 /*
359 * nfs open vnode op
360 * Check to see if the type is ok
361 * and that deletion is not in progress.
362 * For paged in text files, you will need to flush the page cache
363 * if consistency is lost.
364 */
365 /* ARGSUSED */
366 int
367 nfs_open(ap)
368 struct vop_open_args /* {
369 struct vnode *a_vp;
370 int a_mode;
371 struct ucred *a_cred;
372 struct proc *a_p;
373 } */ *ap;
374 {
375 register struct vnode *vp = ap->a_vp;
376 struct nfsnode *np = VTONFS(vp);
377 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
378 struct vattr vattr;
379 int error;
380
381 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
382 { printf("open eacces vtyp=%d\n",vp->v_type);
383 return (EACCES);
384 }
385 /*
386 * Get a valid lease. If cached data is stale, flush it.
387 */
388 if (nmp->nm_flag & NFSMNT_NQNFS) {
389 if (NQNFS_CKINVALID(vp, np, ND_READ)) {
390 do {
391 error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
392 ap->a_p);
393 } while (error == NQNFS_EXPIRED);
394 if (error)
395 return (error);
396 if (np->n_lrev != np->n_brev ||
397 (np->n_flag & NQNFSNONCACHE)) {
398 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
399 ap->a_p, 1)) == EINTR)
400 return (error);
401 (void) vnode_pager_uncache(vp);
402 np->n_brev = np->n_lrev;
403 }
404 }
405 } else {
406 if (np->n_flag & NMODIFIED) {
407 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
408 ap->a_p, 1)) == EINTR)
409 return (error);
410 (void) vnode_pager_uncache(vp);
411 np->n_attrstamp = 0;
412 if (vp->v_type == VDIR)
413 np->n_direofoffset = 0;
414 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
415 if (error)
416 return (error);
417 np->n_mtime = vattr.va_mtime.ts_sec;
418 } else {
419 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
420 if (error)
421 return (error);
422 if (np->n_mtime != vattr.va_mtime.ts_sec) {
423 if (vp->v_type == VDIR)
424 np->n_direofoffset = 0;
425 if ((error = nfs_vinvalbuf(vp, V_SAVE,
426 ap->a_cred, ap->a_p, 1)) == EINTR)
427 return (error);
428 (void) vnode_pager_uncache(vp);
429 np->n_mtime = vattr.va_mtime.ts_sec;
430 }
431 }
432 }
433 if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
434 np->n_attrstamp = 0; /* For Open/Close consistency */
435 return (0);
436 }
437
438 /*
439 * nfs close vnode op
440 * What an NFS client should do upon close after writing is a debatable issue.
441 * Most NFS clients push delayed writes to the server upon close, basically for
442 * two reasons:
443 * 1 - So that any write errors may be reported back to the client process
444 * doing the close system call. By far the two most likely errors are
445 * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
446 * 2 - To put a worst case upper bound on cache inconsistency between
447 * multiple clients for the file.
448 * There is also a consistency problem for Version 2 of the protocol w.r.t.
449 * not being able to tell if other clients are writing a file concurrently,
450 * since there is no way of knowing if the changed modify time in the reply
451 * is only due to the write for this client.
452 * (NFS Version 3 provides weak cache consistency data in the reply that
453 * should be sufficient to detect and handle this case.)
454 *
455 * The current code does the following:
456 * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
457 * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
458 * or commit them (this satisfies 1 and 2 except for the
459 * case where the server crashes after this close but
460 * before the commit RPC, which is felt to be "good
461 * enough". Changing the last argument to nfs_flush() to
462 * a 1 would force a commit operation, if it is felt a
463 * commit is necessary now.
464 * for NQNFS - do nothing now, since 2 is dealt with via leases and
465 * 1 should be dealt with via an fsync() system call for
466 * cases where write errors are important.
467 */
468 /* ARGSUSED */
469 int
470 nfs_close(ap)
471 struct vop_close_args /* {
472 struct vnodeop_desc *a_desc;
473 struct vnode *a_vp;
474 int a_fflag;
475 struct ucred *a_cred;
476 struct proc *a_p;
477 } */ *ap;
478 {
479 register struct vnode *vp = ap->a_vp;
480 register struct nfsnode *np = VTONFS(vp);
481 int error = 0;
482
483 if (vp->v_type == VREG) {
484 if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
485 (np->n_flag & NMODIFIED)) {
486 if (NFS_ISV3(vp)) {
487 error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
488 np->n_flag &= ~NMODIFIED;
489 } else
490 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
491 np->n_attrstamp = 0;
492 }
493 if (np->n_flag & NWRITEERR) {
494 np->n_flag &= ~NWRITEERR;
495 error = np->n_error;
496 }
497 }
498 return (error);
499 }
500
501 /*
502 * nfs getattr call from vfs.
503 */
504 int
505 nfs_getattr(ap)
506 struct vop_getattr_args /* {
507 struct vnode *a_vp;
508 struct vattr *a_vap;
509 struct ucred *a_cred;
510 struct proc *a_p;
511 } */ *ap;
512 {
513 register struct vnode *vp = ap->a_vp;
514 register struct nfsnode *np = VTONFS(vp);
515 register caddr_t cp;
516 register u_long *tl;
517 register int t1, t2;
518 caddr_t bpos, dpos;
519 int error = 0;
520 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
521 int v3 = NFS_ISV3(vp);
522
523 /*
524 * Update local times for special files.
525 */
526 if (np->n_flag & (NACC | NUPD))
527 np->n_flag |= NCHG;
528 /*
529 * First look in the cache.
530 */
531 if (nfs_getattrcache(vp, ap->a_vap) == 0)
532 return (0);
533 nfsstats.rpccnt[NFSPROC_GETATTR]++;
534 nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
535 nfsm_fhtom(vp, v3);
536 nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
537 if (!error)
538 nfsm_loadattr(vp, ap->a_vap);
539 nfsm_reqdone;
540 return (error);
541 }
542
543 /*
544 * nfs setattr call.
545 */
546 int
547 nfs_setattr(ap)
548 struct vop_setattr_args /* {
549 struct vnodeop_desc *a_desc;
550 struct vnode *a_vp;
551 struct vattr *a_vap;
552 struct ucred *a_cred;
553 struct proc *a_p;
554 } */ *ap;
555 {
556 register struct vnode *vp = ap->a_vp;
557 register struct nfsnode *np = VTONFS(vp);
558 register struct vattr *vap = ap->a_vap;
559 int error = 0;
560 u_quad_t tsize;
561
562 #ifndef nolint
563 tsize = (u_quad_t)0;
564 #endif
565 /*
566 * Disallow write attempts if the filesystem is mounted read-only.
567 */
568 if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
569 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.ts_sec != VNOVAL ||
570 vap->va_mtime.ts_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
571 (vp->v_mount->mnt_flag & MNT_RDONLY))
572 return (EROFS);
573 if (vap->va_size != VNOVAL) {
574 switch (vp->v_type) {
575 case VDIR:
576 return (EISDIR);
577 case VCHR:
578 case VBLK:
579 case VSOCK:
580 case VFIFO:
581 if (vap->va_mtime.ts_sec == VNOVAL &&
582 vap->va_atime.ts_sec == VNOVAL &&
583 vap->va_mode == (u_short)VNOVAL &&
584 vap->va_uid == (uid_t)VNOVAL &&
585 vap->va_gid == (gid_t)VNOVAL)
586 return (0);
587 vap->va_size = VNOVAL;
588 break;
589 default:
590 /*
591 * Disallow write attempts if the filesystem is
592 * mounted read-only.
593 */
594 if (vp->v_mount->mnt_flag & MNT_RDONLY)
595 return (EROFS);
596 if (vap->va_size == 0)
597 error = nfs_vinvalbuf(vp, 0,
598 ap->a_cred, ap->a_p, 1);
599 else
600 error = nfs_vinvalbuf(vp, V_SAVE,
601 ap->a_cred, ap->a_p, 1);
602 if (error)
603 return (error);
604 tsize = np->n_size;
605 np->n_size = np->n_vattr.va_size = vap->va_size;
606 vnode_pager_setsize(vp, (u_long)np->n_size);
607 };
608 } else if ((vap->va_mtime.ts_sec != VNOVAL ||
609 vap->va_atime.ts_sec != VNOVAL) &&
610 vp->v_type == VREG &&
611 (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
612 ap->a_p, 1)) == EINTR)
613 return (error);
614 error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
615 if (error && vap->va_size != VNOVAL) {
616 np->n_size = np->n_vattr.va_size = tsize;
617 vnode_pager_setsize(vp, (u_long)np->n_size);
618 }
619 return (error);
620 }
621
622 /*
623 * Do an nfs setattr rpc.
624 */
625 int
626 nfs_setattrrpc(vp, vap, cred, procp)
627 register struct vnode *vp;
628 register struct vattr *vap;
629 struct ucred *cred;
630 struct proc *procp;
631 {
632 register struct nfsv2_sattr *sp;
633 register caddr_t cp;
634 register long t1, t2;
635 caddr_t bpos, dpos, cp2;
636 u_long *tl;
637 int error = 0, wccflag = NFSV3_WCCRATTR;
638 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
639 u_quad_t frev;
640 int v3 = NFS_ISV3(vp);
641
642 nfsstats.rpccnt[NFSPROC_SETATTR]++;
643 nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
644 nfsm_fhtom(vp, v3);
645 if (v3) {
646 if (vap->va_mode != (u_short)VNOVAL) {
647 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
648 *tl++ = nfs_true;
649 *tl = txdr_unsigned(vap->va_mode);
650 } else {
651 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
652 *tl = nfs_false;
653 }
654 if (vap->va_uid != (uid_t)VNOVAL) {
655 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
656 *tl++ = nfs_true;
657 *tl = txdr_unsigned(vap->va_uid);
658 } else {
659 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
660 *tl = nfs_false;
661 }
662 if (vap->va_gid != (gid_t)VNOVAL) {
663 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
664 *tl++ = nfs_true;
665 *tl = txdr_unsigned(vap->va_gid);
666 } else {
667 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
668 *tl = nfs_false;
669 }
670 if (vap->va_size != VNOVAL) {
671 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
672 *tl++ = nfs_true;
673 txdr_hyper(&vap->va_size, tl);
674 } else {
675 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
676 *tl = nfs_false;
677 }
678 if (vap->va_atime.ts_sec != VNOVAL) {
679 if (vap->va_atime.ts_sec != time.tv_sec) {
680 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
681 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
682 txdr_nfsv3time(&vap->va_atime, tl);
683 } else {
684 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
685 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
686 }
687 } else {
688 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
689 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
690 }
691 if (vap->va_mtime.ts_sec != VNOVAL) {
692 if (vap->va_mtime.ts_sec != time.tv_sec) {
693 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
694 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
695 txdr_nfsv3time(&vap->va_atime, tl);
696 } else {
697 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
698 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
699 }
700 } else {
701 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
702 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
703 }
704 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
705 *tl = nfs_false;
706 } else {
707 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
708 if (vap->va_mode == (u_short)VNOVAL)
709 sp->sa_mode = VNOVAL;
710 else
711 sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
712 if (vap->va_uid == (uid_t)VNOVAL)
713 sp->sa_uid = VNOVAL;
714 else
715 sp->sa_uid = txdr_unsigned(vap->va_uid);
716 if (vap->va_gid == (gid_t)VNOVAL)
717 sp->sa_gid = VNOVAL;
718 else
719 sp->sa_gid = txdr_unsigned(vap->va_gid);
720 sp->sa_size = txdr_unsigned(vap->va_size);
721 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
722 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
723 }
724 nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
725 if (v3) {
726 nfsm_wcc_data(vp, wccflag);
727 } else
728 nfsm_loadattr(vp, (struct vattr *)0);
729 nfsm_reqdone;
730 return (error);
731 }
732
733 /*
734 * nfs lookup call, one step at a time...
735 * First look in cache
736 * If not found, unlock the directory nfsnode and do the rpc
737 */
738 int
739 nfs_lookup(ap)
740 struct vop_lookup_args /* {
741 struct vnodeop_desc *a_desc;
742 struct vnode *a_dvp;
743 struct vnode **a_vpp;
744 struct componentname *a_cnp;
745 } */ *ap;
746 {
747 register struct componentname *cnp = ap->a_cnp;
748 register struct vnode *dvp = ap->a_dvp;
749 register struct vnode **vpp = ap->a_vpp;
750 register int flags = cnp->cn_flags;
751 register struct proc *p = cnp->cn_proc;
752 register struct vnode *newvp;
753 register u_long *tl;
754 register caddr_t cp;
755 register long t1, t2;
756 struct nfsmount *nmp;
757 caddr_t bpos, dpos, cp2;
758 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
759 long len;
760 nfsfh_t *fhp;
761 struct nfsnode *np;
762 int lockparent, wantparent, error = 0, attrflag, fhsize;
763 int v3 = NFS_ISV3(dvp);
764
765 if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
766 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
767 return (EROFS);
768 *vpp = NULLVP;
769 if (dvp->v_type != VDIR)
770 return (ENOTDIR);
771 lockparent = flags & LOCKPARENT;
772 wantparent = flags & (LOCKPARENT|WANTPARENT);
773 nmp = VFSTONFS(dvp->v_mount);
774 np = VTONFS(dvp);
775 if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
776 struct vattr vattr;
777 int vpid;
778
779 newvp = *vpp;
780 vpid = newvp->v_id;
781 /*
782 * See the comment starting `Step through' in ufs/ufs_lookup.c
783 * for an explanation of the locking protocol
784 */
785 if (dvp == newvp) {
786 VREF(newvp);
787 error = 0;
788 } else
789 error = vget(newvp, LK_EXCLUSIVE, p);
790 if (!error) {
791 if (vpid == newvp->v_id) {
792 if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
793 && vattr.va_ctime.ts_sec == VTONFS(newvp)->n_ctime) {
794 nfsstats.lookupcache_hits++;
795 if (cnp->cn_nameiop != LOOKUP &&
796 (flags & ISLASTCN))
797 cnp->cn_flags |= SAVENAME;
798 return (0);
799 }
800 cache_purge(newvp);
801 }
802 vrele(newvp);
803 }
804 *vpp = NULLVP;
805 }
806 error = 0;
807 newvp = NULLVP;
808 nfsstats.lookupcache_misses++;
809 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
810 len = cnp->cn_namelen;
811 nfsm_reqhead(dvp, NFSPROC_LOOKUP,
812 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
813 nfsm_fhtom(dvp, v3);
814 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
815 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
816 if (error) {
817 nfsm_postop_attr(dvp, attrflag);
818 m_freem(mrep);
819 goto nfsmout;
820 }
821 nfsm_getfh(fhp, fhsize, v3);
822
823 /*
824 * Handle RENAME case...
825 */
826 if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
827 if (NFS_CMPFH(np, fhp, fhsize)) {
828 m_freem(mrep);
829 return (EISDIR);
830 }
831 if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
832 m_freem(mrep);
833 return (error);
834 }
835 newvp = NFSTOV(np);
836 if (v3) {
837 nfsm_postop_attr(newvp, attrflag);
838 nfsm_postop_attr(dvp, attrflag);
839 } else
840 nfsm_loadattr(newvp, (struct vattr *)0);
841 *vpp = newvp;
842 m_freem(mrep);
843 cnp->cn_flags |= SAVENAME;
844 return (0);
845 }
846
847 if (NFS_CMPFH(np, fhp, fhsize)) {
848 VREF(dvp);
849 newvp = dvp;
850 } else {
851 if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
852 m_freem(mrep);
853 return (error);
854 }
855 newvp = NFSTOV(np);
856 }
857 if (v3) {
858 nfsm_postop_attr(newvp, attrflag);
859 nfsm_postop_attr(dvp, attrflag);
860 } else
861 nfsm_loadattr(newvp, (struct vattr *)0);
862 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
863 cnp->cn_flags |= SAVENAME;
864 if ((cnp->cn_flags & MAKEENTRY) &&
865 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
866 np->n_ctime = np->n_vattr.va_ctime.ts_sec;
867 cache_enter(dvp, newvp, cnp);
868 }
869 *vpp = newvp;
870 nfsm_reqdone;
871 if (error) {
872 if (newvp != NULLVP)
873 vrele(newvp);
874 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
875 (flags & ISLASTCN) && error == ENOENT) {
876 if (dvp->v_mount->mnt_flag & MNT_RDONLY)
877 error = EROFS;
878 else
879 error = EJUSTRETURN;
880 }
881 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
882 cnp->cn_flags |= SAVENAME;
883 }
884 return (error);
885 }
886
887 /*
888 * nfs read call.
889 * Just call nfs_bioread() to do the work.
890 */
891 int
892 nfs_read(ap)
893 struct vop_read_args /* {
894 struct vnode *a_vp;
895 struct uio *a_uio;
896 int a_ioflag;
897 struct ucred *a_cred;
898 } */ *ap;
899 {
900 register struct vnode *vp = ap->a_vp;
901
902 if (vp->v_type != VREG)
903 return (EPERM);
904 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
905 }
906
907 /*
908 * nfs readlink call
909 */
910 int
911 nfs_readlink(ap)
912 struct vop_readlink_args /* {
913 struct vnode *a_vp;
914 struct uio *a_uio;
915 struct ucred *a_cred;
916 } */ *ap;
917 {
918 register struct vnode *vp = ap->a_vp;
919
920 if (vp->v_type != VLNK)
921 return (EPERM);
922 return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
923 }
924
925 /*
926 * Do a readlink rpc.
927 * Called by nfs_doio() from below the buffer cache.
928 */
929 int
930 nfs_readlinkrpc(vp, uiop, cred)
931 register struct vnode *vp;
932 struct uio *uiop;
933 struct ucred *cred;
934 {
935 register u_long *tl;
936 register caddr_t cp;
937 register long t1, t2;
938 caddr_t bpos, dpos, cp2;
939 int error = 0, len, attrflag;
940 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
941 int v3 = NFS_ISV3(vp);
942
943 nfsstats.rpccnt[NFSPROC_READLINK]++;
944 nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
945 nfsm_fhtom(vp, v3);
946 nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
947 if (v3)
948 nfsm_postop_attr(vp, attrflag);
949 if (!error) {
950 nfsm_strsiz(len, NFS_MAXPATHLEN);
951 nfsm_mtouio(uiop, len);
952 }
953 nfsm_reqdone;
954 return (error);
955 }
956
957 /*
958 * nfs read rpc call
959 * Ditto above
960 */
961 int
962 nfs_readrpc(vp, uiop, cred)
963 register struct vnode *vp;
964 struct uio *uiop;
965 struct ucred *cred;
966 {
967 register u_long *tl;
968 register caddr_t cp;
969 register long t1, t2;
970 caddr_t bpos, dpos, cp2;
971 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
972 struct nfsmount *nmp;
973 int error = 0, len, retlen, tsiz, eof, attrflag;
974 int v3 = NFS_ISV3(vp);
975
976 #ifndef nolint
977 eof = 0;
978 #endif
979 nmp = VFSTONFS(vp->v_mount);
980 tsiz = uiop->uio_resid;
981 if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
982 return (EFBIG);
983 while (tsiz > 0) {
984 nfsstats.rpccnt[NFSPROC_READ]++;
985 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
986 nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
987 nfsm_fhtom(vp, v3);
988 nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
989 if (v3) {
990 txdr_hyper(&uiop->uio_offset, tl);
991 *(tl + 2) = txdr_unsigned(len);
992 } else {
993 *tl++ = txdr_unsigned(uiop->uio_offset);
994 *tl++ = txdr_unsigned(len);
995 *tl = 0;
996 }
997 nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
998 if (v3) {
999 nfsm_postop_attr(vp, attrflag);
1000 if (error) {
1001 m_freem(mrep);
1002 goto nfsmout;
1003 }
1004 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1005 eof = fxdr_unsigned(int, *(tl + 1));
1006 } else
1007 nfsm_loadattr(vp, (struct vattr *)0);
1008 nfsm_strsiz(retlen, nmp->nm_rsize);
1009 nfsm_mtouio(uiop, retlen);
1010 m_freem(mrep);
1011 tsiz -= retlen;
1012 if (v3) {
1013 if (eof || retlen == 0)
1014 tsiz = 0;
1015 } else if (retlen < len)
1016 tsiz = 0;
1017 }
1018 nfsmout:
1019 return (error);
1020 }
1021
1022 /*
1023 * nfs write call
1024 */
1025 int
1026 nfs_writerpc(vp, uiop, cred, iomode, must_commit)
1027 register struct vnode *vp;
1028 register struct uio *uiop;
1029 struct ucred *cred;
1030 int *iomode, *must_commit;
1031 {
1032 register u_long *tl;
1033 register caddr_t cp;
1034 register int t1, t2, backup;
1035 caddr_t bpos, dpos, cp2;
1036 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1037 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1038 struct nfsnode *np = VTONFS(vp);
1039 u_quad_t frev;
1040 int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
1041 int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
1042
1043 #ifndef DIAGNOSTIC
1044 if (uiop->uio_iovcnt != 1)
1045 panic("nfs: writerpc iovcnt > 1");
1046 #endif
1047 *must_commit = 0;
1048 tsiz = uiop->uio_resid;
1049 if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
1050 return (EFBIG);
1051 while (tsiz > 0) {
1052 nfsstats.rpccnt[NFSPROC_WRITE]++;
1053 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
1054 nfsm_reqhead(vp, NFSPROC_WRITE,
1055 NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
1056 nfsm_fhtom(vp, v3);
1057 if (v3) {
1058 nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
1059 txdr_hyper(&uiop->uio_offset, tl);
1060 tl += 2;
1061 *tl++ = txdr_unsigned(len);
1062 *tl++ = txdr_unsigned(*iomode);
1063 } else {
1064 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1065 *++tl = txdr_unsigned(uiop->uio_offset);
1066 tl += 2;
1067 }
1068 *tl = txdr_unsigned(len);
1069 nfsm_uiotom(uiop, len);
1070 nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
1071 if (v3) {
1072 wccflag = NFSV3_WCCCHK;
1073 nfsm_wcc_data(vp, wccflag);
1074 if (!error) {
1075 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
1076 NFSX_V3WRITEVERF);
1077 rlen = fxdr_unsigned(int, *tl++);
1078 if (rlen == 0) {
1079 error = NFSERR_IO;
1080 break;
1081 } else if (rlen < len) {
1082 backup = len - rlen;
1083 uiop->uio_iov->iov_base -= backup;
1084 uiop->uio_iov->iov_len += backup;
1085 uiop->uio_offset -= backup;
1086 uiop->uio_resid += backup;
1087 len = rlen;
1088 }
1089 commit = fxdr_unsigned(int, *tl++);
1090
1091 /*
1092 * Return the lowest committment level
1093 * obtained by any of the RPCs.
1094 */
1095 if (committed == NFSV3WRITE_FILESYNC)
1096 committed = commit;
1097 else if (committed == NFSV3WRITE_DATASYNC &&
1098 commit == NFSV3WRITE_UNSTABLE)
1099 committed = commit;
1100 if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
1101 bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1102 NFSX_V3WRITEVERF);
1103 nmp->nm_flag |= NFSMNT_HASWRITEVERF;
1104 } else if (bcmp((caddr_t)tl,
1105 (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
1106 *must_commit = 1;
1107 bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1108 NFSX_V3WRITEVERF);
1109 }
1110 }
1111 } else
1112 nfsm_loadattr(vp, (struct vattr *)0);
1113 if (wccflag)
1114 VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
1115 m_freem(mrep);
1116 tsiz -= len;
1117 }
1118 nfsmout:
1119 *iomode = committed;
1120 if (error)
1121 uiop->uio_resid = tsiz;
1122 return (error);
1123 }
1124
1125 /*
1126 * nfs mknod rpc
1127 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1128 * mode set to specify the file type and the size field for rdev.
1129 */
1130 int
1131 nfs_mknodrpc(dvp, vpp, cnp, vap)
1132 register struct vnode *dvp;
1133 register struct vnode **vpp;
1134 register struct componentname *cnp;
1135 register struct vattr *vap;
1136 {
1137 register struct nfsv2_sattr *sp;
1138 register struct nfsv3_sattr *sp3;
1139 register u_long *tl;
1140 register caddr_t cp;
1141 register long t1, t2;
1142 struct vnode *newvp = (struct vnode *)0;
1143 struct nfsnode *np;
1144 struct vattr vattr;
1145 char *cp2;
1146 caddr_t bpos, dpos;
1147 int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
1148 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1149 u_long rdev;
1150 int v3 = NFS_ISV3(dvp);
1151
1152 if (vap->va_type == VCHR || vap->va_type == VBLK)
1153 rdev = txdr_unsigned(vap->va_rdev);
1154 else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
1155 rdev = 0xffffffff;
1156 else {
1157 VOP_ABORTOP(dvp, cnp);
1158 vput(dvp);
1159 return (EOPNOTSUPP);
1160 }
1161 if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
1162 VOP_ABORTOP(dvp, cnp);
1163 vput(dvp);
1164 return (error);
1165 }
1166 nfsstats.rpccnt[NFSPROC_MKNOD]++;
1167 nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
1168 + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1169 nfsm_fhtom(dvp, v3);
1170 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1171 if (v3) {
1172 nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
1173 *tl++ = vtonfsv3_type(vap->va_type);
1174 sp3 = (struct nfsv3_sattr *)tl;
1175 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1176 if (vap->va_type == VCHR || vap->va_type == VBLK) {
1177 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1178 *tl++ = txdr_unsigned(major(vap->va_rdev));
1179 *tl = txdr_unsigned(minor(vap->va_rdev));
1180 }
1181 } else {
1182 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1183 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1184 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1185 sp->sa_gid = txdr_unsigned(vattr.va_gid);
1186 sp->sa_size = rdev;
1187 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1188 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1189 }
1190 nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
1191 if (!error) {
1192 nfsm_mtofh(dvp, newvp, v3, gotvp);
1193 if (!gotvp) {
1194 if (newvp) {
1195 vrele(newvp);
1196 newvp = (struct vnode *)0;
1197 }
1198 error = nfs_lookitup(dvp, cnp->cn_nameptr,
1199 cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1200 if (!error)
1201 newvp = NFSTOV(np);
1202 }
1203 }
1204 if (v3)
1205 nfsm_wcc_data(dvp, wccflag);
1206 nfsm_reqdone;
1207 if (error) {
1208 if (newvp)
1209 vrele(newvp);
1210 } else {
1211 if (cnp->cn_flags & MAKEENTRY)
1212 cache_enter(dvp, newvp, cnp);
1213 *vpp = newvp;
1214 }
1215 FREE(cnp->cn_pnbuf, M_NAMEI);
1216 VTONFS(dvp)->n_flag |= NMODIFIED;
1217 if (!wccflag)
1218 VTONFS(dvp)->n_attrstamp = 0;
1219 vrele(dvp);
1220 return (error);
1221 }
1222
1223 /*
1224 * nfs mknod vop
1225 * just call nfs_mknodrpc() to do the work.
1226 */
1227 /* ARGSUSED */
1228 int
1229 nfs_mknod(ap)
1230 struct vop_mknod_args /* {
1231 struct vnode *a_dvp;
1232 struct vnode **a_vpp;
1233 struct componentname *a_cnp;
1234 struct vattr *a_vap;
1235 } */ *ap;
1236 {
1237 struct vnode *newvp;
1238 int error;
1239
1240 error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
1241 if (!error)
1242 vrele(newvp);
1243 return (error);
1244 }
1245
1246 static u_long create_verf;
1247 /*
1248 * nfs file create call
1249 */
1250 int
1251 nfs_create(ap)
1252 struct vop_create_args /* {
1253 struct vnode *a_dvp;
1254 struct vnode **a_vpp;
1255 struct componentname *a_cnp;
1256 struct vattr *a_vap;
1257 } */ *ap;
1258 {
1259 register struct vnode *dvp = ap->a_dvp;
1260 register struct vattr *vap = ap->a_vap;
1261 register struct componentname *cnp = ap->a_cnp;
1262 register struct nfsv2_sattr *sp;
1263 register struct nfsv3_sattr *sp3;
1264 register u_long *tl;
1265 register caddr_t cp;
1266 register long t1, t2;
1267 struct nfsnode *np = (struct nfsnode *)0;
1268 struct vnode *newvp = (struct vnode *)0;
1269 caddr_t bpos, dpos, cp2;
1270 int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
1271 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1272 struct vattr vattr;
1273 int v3 = NFS_ISV3(dvp);
1274
1275 /*
1276 * Oops, not for me..
1277 */
1278 if (vap->va_type == VSOCK)
1279 return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
1280
1281 if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
1282 VOP_ABORTOP(dvp, cnp);
1283 vput(dvp);
1284 return (error);
1285 }
1286 if (vap->va_vaflags & VA_EXCLUSIVE)
1287 fmode |= O_EXCL;
1288 again:
1289 nfsstats.rpccnt[NFSPROC_CREATE]++;
1290 nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
1291 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1292 nfsm_fhtom(dvp, v3);
1293 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1294 if (v3) {
1295 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1296 if (fmode & O_EXCL) {
1297 *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
1298 nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
1299 if (in_ifaddr)
1300 *tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr;
1301 else
1302 *tl++ = create_verf;
1303 *tl = ++create_verf;
1304 } else {
1305 *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
1306 nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
1307 sp3 = (struct nfsv3_sattr *)tl;
1308 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1309 }
1310 } else {
1311 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1312 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1313 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1314 sp->sa_gid = txdr_unsigned(vattr.va_gid);
1315 sp->sa_size = 0;
1316 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1317 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1318 }
1319 nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1320 if (!error) {
1321 nfsm_mtofh(dvp, newvp, v3, gotvp);
1322 if (!gotvp) {
1323 if (newvp) {
1324 vrele(newvp);
1325 newvp = (struct vnode *)0;
1326 }
1327 error = nfs_lookitup(dvp, cnp->cn_nameptr,
1328 cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1329 if (!error)
1330 newvp = NFSTOV(np);
1331 }
1332 }
1333 if (v3)
1334 nfsm_wcc_data(dvp, wccflag);
1335 nfsm_reqdone;
1336 if (error) {
1337 if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
1338 fmode &= ~O_EXCL;
1339 goto again;
1340 }
1341 if (newvp)
1342 vrele(newvp);
1343 } else if (v3 && (fmode & O_EXCL))
1344 error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
1345 if (!error) {
1346 if (cnp->cn_flags & MAKEENTRY)
1347 cache_enter(dvp, newvp, cnp);
1348 *ap->a_vpp = newvp;
1349 }
1350 FREE(cnp->cn_pnbuf, M_NAMEI);
1351 VTONFS(dvp)->n_flag |= NMODIFIED;
1352 if (!wccflag)
1353 VTONFS(dvp)->n_attrstamp = 0;
1354 vrele(dvp);
1355 return (error);
1356 }
1357
1358 /*
1359 * nfs file remove call
1360 * To try and make nfs semantics closer to ufs semantics, a file that has
1361 * other processes using the vnode is renamed instead of removed and then
1362 * removed later on the last close.
1363 * - If v_usecount > 1
1364 * If a rename is not already in the works
1365 * call nfs_sillyrename() to set it up
1366 * else
1367 * do the remove rpc
1368 */
1369 int
1370 nfs_remove(ap)
1371 struct vop_remove_args /* {
1372 struct vnodeop_desc *a_desc;
1373 struct vnode * a_dvp;
1374 struct vnode * a_vp;
1375 struct componentname * a_cnp;
1376 } */ *ap;
1377 {
1378 register struct vnode *vp = ap->a_vp;
1379 register struct vnode *dvp = ap->a_dvp;
1380 register struct componentname *cnp = ap->a_cnp;
1381 register struct nfsnode *np = VTONFS(vp);
1382 register u_long *tl;
1383 register caddr_t cp;
1384 register long t2;
1385 caddr_t bpos, dpos;
1386 int error = 0;
1387 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1388 struct vattr vattr;
1389 int v3 = NFS_ISV3(dvp);
1390
1391 #ifndef DIAGNOSTIC
1392 if ((cnp->cn_flags & HASBUF) == 0)
1393 panic("nfs_remove: no name");
1394 if (vp->v_usecount < 1)
1395 panic("nfs_remove: bad v_usecount");
1396 #endif
1397 if (vp->v_usecount == 1 || (np->n_sillyrename &&
1398 VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
1399 vattr.va_nlink > 1)) {
1400 /*
1401 * Purge the name cache so that the chance of a lookup for
1402 * the name succeeding while the remove is in progress is
1403 * minimized. Without node locking it can still happen, such
1404 * that an I/O op returns ESTALE, but since you get this if
1405 * another host removes the file..
1406 */
1407 cache_purge(vp);
1408 /*
1409 * throw away biocache buffers, mainly to avoid
1410 * unnecessary delayed writes later.
1411 */
1412 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1413 /* Do the rpc */
1414 if (error != EINTR)
1415 error = nfs_removerpc(dvp, cnp->cn_nameptr,
1416 cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
1417 /*
1418 * Kludge City: If the first reply to the remove rpc is lost..
1419 * the reply to the retransmitted request will be ENOENT
1420 * since the file was in fact removed
1421 * Therefore, we cheat and return success.
1422 */
1423 if (error == ENOENT)
1424 error = 0;
1425 } else if (!np->n_sillyrename)
1426 error = nfs_sillyrename(dvp, vp, cnp);
1427 FREE(cnp->cn_pnbuf, M_NAMEI);
1428 np->n_attrstamp = 0;
1429 vrele(dvp);
1430 vrele(vp);
1431 return (error);
1432 }
1433
1434 /*
1435 * nfs file remove rpc called from nfs_inactive
1436 */
1437 int
1438 nfs_removeit(sp)
1439 register struct sillyrename *sp;
1440 {
1441
1442 return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
1443 (struct proc *)0));
1444 }
1445
1446 /*
1447 * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
1448 */
1449 int
1450 nfs_removerpc(dvp, name, namelen, cred, proc)
1451 register struct vnode *dvp;
1452 char *name;
1453 int namelen;
1454 struct ucred *cred;
1455 struct proc *proc;
1456 {
1457 register u_long *tl;
1458 register caddr_t cp;
1459 register long t1, t2;
1460 caddr_t bpos, dpos, cp2;
1461 int error = 0, wccflag = NFSV3_WCCRATTR;
1462 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1463 int v3 = NFS_ISV3(dvp);
1464
1465 nfsstats.rpccnt[NFSPROC_REMOVE]++;
1466 nfsm_reqhead(dvp, NFSPROC_REMOVE,
1467 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
1468 nfsm_fhtom(dvp, v3);
1469 nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
1470 nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
1471 if (v3)
1472 nfsm_wcc_data(dvp, wccflag);
1473 nfsm_reqdone;
1474 VTONFS(dvp)->n_flag |= NMODIFIED;
1475 if (!wccflag)
1476 VTONFS(dvp)->n_attrstamp = 0;
1477 return (error);
1478 }
1479
1480 /*
1481 * nfs file rename call
1482 */
1483 int
1484 nfs_rename(ap)
1485 struct vop_rename_args /* {
1486 struct vnode *a_fdvp;
1487 struct vnode *a_fvp;
1488 struct componentname *a_fcnp;
1489 struct vnode *a_tdvp;
1490 struct vnode *a_tvp;
1491 struct componentname *a_tcnp;
1492 } */ *ap;
1493 {
1494 register struct vnode *fvp = ap->a_fvp;
1495 register struct vnode *tvp = ap->a_tvp;
1496 register struct vnode *fdvp = ap->a_fdvp;
1497 register struct vnode *tdvp = ap->a_tdvp;
1498 register struct componentname *tcnp = ap->a_tcnp;
1499 register struct componentname *fcnp = ap->a_fcnp;
1500 int error;
1501
1502 #ifndef DIAGNOSTIC
1503 if ((tcnp->cn_flags & HASBUF) == 0 ||
1504 (fcnp->cn_flags & HASBUF) == 0)
1505 panic("nfs_rename: no name");
1506 #endif
1507 /* Check for cross-device rename */
1508 if ((fvp->v_mount != tdvp->v_mount) ||
1509 (tvp && (fvp->v_mount != tvp->v_mount))) {
1510 error = EXDEV;
1511 goto out;
1512 }
1513
1514 /*
1515 * If the tvp exists and is in use, sillyrename it before doing the
1516 * rename of the new file over it.
1517 */
1518 if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
1519 !nfs_sillyrename(tdvp, tvp, tcnp)) {
1520 vrele(tvp);
1521 tvp = NULL;
1522 }
1523
1524 error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
1525 tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
1526 tcnp->cn_proc);
1527
1528 if (fvp->v_type == VDIR) {
1529 if (tvp != NULL && tvp->v_type == VDIR)
1530 cache_purge(tdvp);
1531 cache_purge(fdvp);
1532 }
1533 out:
1534 if (tdvp == tvp)
1535 vrele(tdvp);
1536 else
1537 vput(tdvp);
1538 if (tvp)
1539 vput(tvp);
1540 vrele(fdvp);
1541 vrele(fvp);
1542 /*
1543 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1544 */
1545 if (error == ENOENT)
1546 error = 0;
1547 return (error);
1548 }
1549
1550 /*
1551 * nfs file rename rpc called from nfs_remove() above
1552 */
1553 int
1554 nfs_renameit(sdvp, scnp, sp)
1555 struct vnode *sdvp;
1556 struct componentname *scnp;
1557 register struct sillyrename *sp;
1558 {
1559 return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
1560 sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
1561 }
1562
1563 /*
1564 * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
1565 */
1566 int
1567 nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
1568 register struct vnode *fdvp;
1569 char *fnameptr;
1570 int fnamelen;
1571 register struct vnode *tdvp;
1572 char *tnameptr;
1573 int tnamelen;
1574 struct ucred *cred;
1575 struct proc *proc;
1576 {
1577 register u_long *tl;
1578 register caddr_t cp;
1579 register long t1, t2;
1580 caddr_t bpos, dpos, cp2;
1581 int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
1582 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1583 int v3 = NFS_ISV3(fdvp);
1584
1585 nfsstats.rpccnt[NFSPROC_RENAME]++;
1586 nfsm_reqhead(fdvp, NFSPROC_RENAME,
1587 (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
1588 nfsm_rndup(tnamelen));
1589 nfsm_fhtom(fdvp, v3);
1590 nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
1591 nfsm_fhtom(tdvp, v3);
1592 nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
1593 nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
1594 if (v3) {
1595 nfsm_wcc_data(fdvp, fwccflag);
1596 nfsm_wcc_data(tdvp, twccflag);
1597 }
1598 nfsm_reqdone;
1599 VTONFS(fdvp)->n_flag |= NMODIFIED;
1600 VTONFS(tdvp)->n_flag |= NMODIFIED;
1601 if (!fwccflag)
1602 VTONFS(fdvp)->n_attrstamp = 0;
1603 if (!twccflag)
1604 VTONFS(tdvp)->n_attrstamp = 0;
1605 return (error);
1606 }
1607
1608 /*
1609 * nfs hard link create call
1610 */
1611 int
1612 nfs_link(ap)
1613 struct vop_link_args /* {
1614 struct vnode *a_tdvp;
1615 struct vnode *a_vp;
1616 struct componentname *a_cnp;
1617 } */ *ap;
1618 {
1619 register struct vnode *vp = ap->a_vp;
1620 register struct vnode *tdvp = ap->a_tdvp;
1621 register struct componentname *cnp = ap->a_cnp;
1622 register u_long *tl;
1623 register caddr_t cp;
1624 register long t1, t2;
1625 caddr_t bpos, dpos, cp2;
1626 int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
1627 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1628 int v3 = NFS_ISV3(vp);
1629
1630 if (vp->v_mount != tdvp->v_mount) {
1631 /*VOP_ABORTOP(vp, cnp);*/
1632 if (tdvp == vp)
1633 vrele(tdvp);
1634 else
1635 vput(tdvp);
1636 return (EXDEV);
1637 }
1638
1639 /*
1640 * Push all writes to the server, so that the attribute cache
1641 * doesn't get "out of sync" with the server.
1642 * XXX There should be a better way!
1643 */
1644 VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
1645
1646 nfsstats.rpccnt[NFSPROC_LINK]++;
1647 nfsm_reqhead(vp, NFSPROC_LINK,
1648 NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1649 nfsm_fhtom(vp, v3);
1650 nfsm_fhtom(tdvp, v3);
1651 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1652 nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
1653 if (v3) {
1654 nfsm_postop_attr(vp, attrflag);
1655 nfsm_wcc_data(tdvp, wccflag);
1656 }
1657 nfsm_reqdone;
1658 FREE(cnp->cn_pnbuf, M_NAMEI);
1659 VTONFS(tdvp)->n_flag |= NMODIFIED;
1660 if (!attrflag)
1661 VTONFS(vp)->n_attrstamp = 0;
1662 if (!wccflag)
1663 VTONFS(tdvp)->n_attrstamp = 0;
1664 vrele(tdvp);
1665 /*
1666 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1667 */
1668 if (error == EEXIST)
1669 error = 0;
1670 return (error);
1671 }
1672
1673 /*
1674 * nfs symbolic link create call
1675 */
1676 int
1677 nfs_symlink(ap)
1678 struct vop_symlink_args /* {
1679 struct vnode *a_dvp;
1680 struct vnode **a_vpp;
1681 struct componentname *a_cnp;
1682 struct vattr *a_vap;
1683 char *a_target;
1684 } */ *ap;
1685 {
1686 register struct vnode *dvp = ap->a_dvp;
1687 register struct vattr *vap = ap->a_vap;
1688 register struct componentname *cnp = ap->a_cnp;
1689 register struct nfsv2_sattr *sp;
1690 register struct nfsv3_sattr *sp3;
1691 register u_long *tl;
1692 register caddr_t cp;
1693 register long t1, t2;
1694 caddr_t bpos, dpos, cp2;
1695 int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
1696 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1697 struct vnode *newvp = (struct vnode *)0;
1698 int v3 = NFS_ISV3(dvp);
1699
1700 nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1701 slen = strlen(ap->a_target);
1702 nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
1703 nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
1704 nfsm_fhtom(dvp, v3);
1705 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1706 if (v3) {
1707 nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1708 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
1709 cnp->cn_cred->cr_gid);
1710 }
1711 nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
1712 if (!v3) {
1713 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1714 sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
1715 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1716 sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
1717 sp->sa_size = -1;
1718 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1719 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1720 }
1721 nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
1722 if (v3) {
1723 if (!error)
1724 nfsm_mtofh(dvp, newvp, v3, gotvp);
1725 nfsm_wcc_data(dvp, wccflag);
1726 }
1727 nfsm_reqdone;
1728 if (newvp)
1729 vrele(newvp);
1730 FREE(cnp->cn_pnbuf, M_NAMEI);
1731 VTONFS(dvp)->n_flag |= NMODIFIED;
1732 if (!wccflag)
1733 VTONFS(dvp)->n_attrstamp = 0;
1734 vrele(dvp);
1735 /*
1736 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1737 */
1738 if (error == EEXIST)
1739 error = 0;
1740 return (error);
1741 }
1742
1743 /*
1744 * nfs make dir call
1745 */
1746 int
1747 nfs_mkdir(ap)
1748 struct vop_mkdir_args /* {
1749 struct vnode *a_dvp;
1750 struct vnode **a_vpp;
1751 struct componentname *a_cnp;
1752 struct vattr *a_vap;
1753 } */ *ap;
1754 {
1755 register struct vnode *dvp = ap->a_dvp;
1756 register struct vattr *vap = ap->a_vap;
1757 register struct componentname *cnp = ap->a_cnp;
1758 register struct nfsv2_sattr *sp;
1759 register struct nfsv3_sattr *sp3;
1760 register u_long *tl;
1761 register caddr_t cp;
1762 register long t1, t2;
1763 register int len;
1764 struct nfsnode *np = (struct nfsnode *)0;
1765 struct vnode *newvp = (struct vnode *)0;
1766 caddr_t bpos, dpos, cp2;
1767 nfsfh_t *fhp;
1768 int error = 0, wccflag = NFSV3_WCCRATTR, attrflag;
1769 int fhsize, gotvp = 0;
1770 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1771 struct vattr vattr;
1772 int v3 = NFS_ISV3(dvp);
1773
1774 if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
1775 VOP_ABORTOP(dvp, cnp);
1776 vput(dvp);
1777 return (error);
1778 }
1779 len = cnp->cn_namelen;
1780 nfsstats.rpccnt[NFSPROC_MKDIR]++;
1781 nfsm_reqhead(dvp, NFSPROC_MKDIR,
1782 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
1783 nfsm_fhtom(dvp, v3);
1784 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1785 if (v3) {
1786 nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1787 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1788 } else {
1789 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1790 sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
1791 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1792 sp->sa_gid = txdr_unsigned(vattr.va_gid);
1793 sp->sa_size = -1;
1794 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1795 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1796 }
1797 nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
1798 if (!error)
1799 nfsm_mtofh(dvp, newvp, v3, gotvp);
1800 if (v3)
1801 nfsm_wcc_data(dvp, wccflag);
1802 nfsm_reqdone;
1803 VTONFS(dvp)->n_flag |= NMODIFIED;
1804 if (!wccflag)
1805 VTONFS(dvp)->n_attrstamp = 0;
1806 /*
1807 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1808 * if we can succeed in looking up the directory.
1809 */
1810 if (error == EEXIST || (!error && !gotvp)) {
1811 if (newvp) {
1812 vrele(newvp);
1813 newvp = (struct vnode *)0;
1814 }
1815 error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
1816 cnp->cn_proc, &np);
1817 if (!error) {
1818 newvp = NFSTOV(np);
1819 if (newvp->v_type != VDIR)
1820 error = EEXIST;
1821 }
1822 }
1823 if (error) {
1824 if (newvp)
1825 vrele(newvp);
1826 } else
1827 *ap->a_vpp = newvp;
1828 FREE(cnp->cn_pnbuf, M_NAMEI);
1829 vrele(dvp);
1830 return (error);
1831 }
1832
1833 /*
1834 * nfs remove directory call
1835 */
1836 int
1837 nfs_rmdir(ap)
1838 struct vop_rmdir_args /* {
1839 struct vnode *a_dvp;
1840 struct vnode *a_vp;
1841 struct componentname *a_cnp;
1842 } */ *ap;
1843 {
1844 register struct vnode *vp = ap->a_vp;
1845 register struct vnode *dvp = ap->a_dvp;
1846 register struct componentname *cnp = ap->a_cnp;
1847 register u_long *tl;
1848 register caddr_t cp;
1849 register long t1, t2;
1850 caddr_t bpos, dpos, cp2;
1851 int error = 0, wccflag = NFSV3_WCCRATTR;
1852 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1853 int v3 = NFS_ISV3(dvp);
1854
1855 if (dvp == vp) {
1856 vrele(dvp);
1857 vrele(dvp);
1858 FREE(cnp->cn_pnbuf, M_NAMEI);
1859 return (EINVAL);
1860 }
1861 nfsstats.rpccnt[NFSPROC_RMDIR]++;
1862 nfsm_reqhead(dvp, NFSPROC_RMDIR,
1863 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1864 nfsm_fhtom(dvp, v3);
1865 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1866 nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
1867 if (v3)
1868 nfsm_wcc_data(dvp, wccflag);
1869 nfsm_reqdone;
1870 FREE(cnp->cn_pnbuf, M_NAMEI);
1871 VTONFS(dvp)->n_flag |= NMODIFIED;
1872 if (!wccflag)
1873 VTONFS(dvp)->n_attrstamp = 0;
1874 cache_purge(dvp);
1875 cache_purge(vp);
1876 vrele(vp);
1877 vrele(dvp);
1878 /*
1879 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1880 */
1881 if (error == ENOENT)
1882 error = 0;
1883 return (error);
1884 }
1885
1886 /*
1887 * nfs readdir call
1888 */
1889 int
1890 nfs_readdir(ap)
1891 struct vop_readdir_args /* {
1892 struct vnode *a_vp;
1893 struct uio *a_uio;
1894 struct ucred *a_cred;
1895 } */ *ap;
1896 {
1897 register struct vnode *vp = ap->a_vp;
1898 register struct nfsnode *np = VTONFS(vp);
1899 register struct uio *uio = ap->a_uio;
1900 int tresid, error;
1901 struct vattr vattr;
1902
1903 if (vp->v_type != VDIR)
1904 return (EPERM);
1905 /*
1906 * First, check for hit on the EOF offset cache
1907 */
1908 if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
1909 (np->n_flag & NMODIFIED) == 0) {
1910 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
1911 if (NQNFS_CKCACHABLE(vp, ND_READ)) {
1912 nfsstats.direofcache_hits++;
1913 return (0);
1914 }
1915 } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
1916 np->n_mtime == vattr.va_mtime.ts_sec) {
1917 nfsstats.direofcache_hits++;
1918 return (0);
1919 }
1920 }
1921
1922 /*
1923 * Call nfs_bioread() to do the real work.
1924 */
1925 tresid = uio->uio_resid;
1926 error = nfs_bioread(vp, uio, 0, ap->a_cred);
1927
1928 if (!error && uio->uio_resid == tresid)
1929 nfsstats.direofcache_misses++;
1930 return (error);
1931 }
1932
1933 /*
1934 * Readdir rpc call.
1935 * Called from below the buffer cache by nfs_doio().
1936 */
1937 int
1938 nfs_readdirrpc(vp, uiop, cred)
1939 struct vnode *vp;
1940 register struct uio *uiop;
1941 struct ucred *cred;
1942 {
1943 register int len, left;
1944 register struct dirent *dp;
1945 register u_long *tl;
1946 register caddr_t cp;
1947 register long t1, t2;
1948 register nfsuint64 *cookiep;
1949 caddr_t bpos, dpos, cp2;
1950 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1951 nfsuint64 cookie;
1952 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1953 struct nfsnode *dnp = VTONFS(vp);
1954 nfsfh_t *fhp;
1955 u_quad_t frev, fileno;
1956 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1, i;
1957 int cachable, attrflag, fhsize;
1958 int v3 = NFS_ISV3(vp);
1959
1960 #ifndef nolint
1961 dp = (struct dirent *)0;
1962 #endif
1963 #ifndef DIAGNOSTIC
1964 if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
1965 (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
1966 panic("nfs readdirrpc bad uio");
1967 #endif
1968
1969 /*
1970 * If there is no cookie, assume end of directory.
1971 */
1972 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
1973 if (cookiep)
1974 cookie = *cookiep;
1975 else
1976 return (0);
1977 /*
1978 * Loop around doing readdir rpc's of size nm_readdirsize
1979 * truncated to a multiple of DIRBLKSIZ.
1980 * The stopping criteria is EOF or buffer full.
1981 */
1982 while (more_dirs && bigenough) {
1983 nfsstats.rpccnt[NFSPROC_READDIR]++;
1984 nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
1985 NFSX_READDIR(v3));
1986 nfsm_fhtom(vp, v3);
1987 if (v3) {
1988 nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
1989 *tl++ = cookie.nfsuquad[0];
1990 *tl++ = cookie.nfsuquad[1];
1991 *tl++ = dnp->n_cookieverf.nfsuquad[0];
1992 *tl++ = dnp->n_cookieverf.nfsuquad[1];
1993 } else {
1994 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1995 *tl++ = cookie.nfsuquad[0];
1996 }
1997 *tl = txdr_unsigned(nmp->nm_readdirsize);
1998 nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
1999 if (v3) {
2000 nfsm_postop_attr(vp, attrflag);
2001 if (!error) {
2002 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2003 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2004 dnp->n_cookieverf.nfsuquad[1] = *tl;
2005 } else {
2006 m_freem(mrep);
2007 goto nfsmout;
2008 }
2009 }
2010 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2011 more_dirs = fxdr_unsigned(int, *tl);
2012
2013 /* loop thru the dir entries, doctoring them to 4bsd form */
2014 while (more_dirs && bigenough) {
2015 if (v3) {
2016 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2017 fxdr_hyper(tl, &fileno);
2018 len = fxdr_unsigned(int, *(tl + 2));
2019 } else {
2020 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2021 fileno = fxdr_unsigned(u_quad_t, *tl++);
2022 len = fxdr_unsigned(int, *tl);
2023 }
2024 if (len <= 0 || len > NFS_MAXNAMLEN) {
2025 error = EBADRPC;
2026 m_freem(mrep);
2027 goto nfsmout;
2028 }
2029 tlen = nfsm_rndup(len);
2030 if (tlen == len)
2031 tlen += 4; /* To ensure null termination */
2032 left = DIRBLKSIZ - blksiz;
2033 if ((tlen + DIRHDSIZ) > left) {
2034 dp->d_reclen += left;
2035 uiop->uio_iov->iov_base += left;
2036 uiop->uio_iov->iov_len -= left;
2037 uiop->uio_offset += left;
2038 uiop->uio_resid -= left;
2039 blksiz = 0;
2040 }
2041 if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2042 bigenough = 0;
2043 if (bigenough) {
2044 dp = (struct dirent *)uiop->uio_iov->iov_base;
2045 dp->d_fileno = (int)fileno;
2046 dp->d_namlen = len;
2047 dp->d_reclen = tlen + DIRHDSIZ;
2048 dp->d_type = DT_UNKNOWN;
2049 blksiz += dp->d_reclen;
2050 if (blksiz == DIRBLKSIZ)
2051 blksiz = 0;
2052 uiop->uio_offset += DIRHDSIZ;
2053 uiop->uio_resid -= DIRHDSIZ;
2054 uiop->uio_iov->iov_base += DIRHDSIZ;
2055 uiop->uio_iov->iov_len -= DIRHDSIZ;
2056 nfsm_mtouio(uiop, len);
2057 cp = uiop->uio_iov->iov_base;
2058 tlen -= len;
2059 *cp = '\0'; /* null terminate */
2060 uiop->uio_iov->iov_base += tlen;
2061 uiop->uio_iov->iov_len -= tlen;
2062 uiop->uio_offset += tlen;
2063 uiop->uio_resid -= tlen;
2064 } else
2065 nfsm_adv(nfsm_rndup(len));
2066 if (v3) {
2067 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2068 } else {
2069 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2070 }
2071 if (bigenough) {
2072 cookie.nfsuquad[0] = *tl++;
2073 if (v3)
2074 cookie.nfsuquad[1] = *tl++;
2075 } else if (v3)
2076 tl += 2;
2077 else
2078 tl++;
2079 more_dirs = fxdr_unsigned(int, *tl);
2080 }
2081 /*
2082 * If at end of rpc data, get the eof boolean
2083 */
2084 if (!more_dirs) {
2085 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2086 more_dirs = (fxdr_unsigned(int, *tl) == 0);
2087 }
2088 m_freem(mrep);
2089 }
2090 /*
2091 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2092 * by increasing d_reclen for the last record.
2093 */
2094 if (blksiz > 0) {
2095 left = DIRBLKSIZ - blksiz;
2096 dp->d_reclen += left;
2097 uiop->uio_iov->iov_base += left;
2098 uiop->uio_iov->iov_len -= left;
2099 uiop->uio_offset += left;
2100 uiop->uio_resid -= left;
2101 }
2102
2103 /*
2104 * We are now either at the end of the directory or have filled the
2105 * block.
2106 */
2107 if (bigenough)
2108 dnp->n_direofoffset = uiop->uio_offset;
2109 else {
2110 if (uiop->uio_resid > 0)
2111 printf("EEK! readdirrpc resid > 0\n");
2112 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2113 *cookiep = cookie;
2114 }
2115 nfsmout:
2116 return (error);
2117 }
2118
2119 /*
2120 * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
2121 */
2122 int
2123 nfs_readdirplusrpc(vp, uiop, cred)
2124 struct vnode *vp;
2125 register struct uio *uiop;
2126 struct ucred *cred;
2127 {
2128 register int len, left;
2129 register struct dirent *dp;
2130 register u_long *tl;
2131 register caddr_t cp;
2132 register long t1, t2;
2133 register struct vnode *newvp;
2134 register nfsuint64 *cookiep;
2135 caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
2136 struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
2137 struct nameidata nami, *ndp = &nami;
2138 struct componentname *cnp = &ndp->ni_cnd;
2139 nfsuint64 cookie;
2140 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2141 struct nfsnode *dnp = VTONFS(vp), *np;
2142 nfsfh_t *fhp;
2143 u_quad_t frev, fileno;
2144 int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2145 int cachable, attrflag, fhsize;
2146
2147 #ifndef nolint
2148 dp = (struct dirent *)0;
2149 #endif
2150 #ifndef DIAGNOSTIC
2151 if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
2152 (uiop->uio_resid & (DIRBLKSIZ - 1)))
2153 panic("nfs readdirplusrpc bad uio");
2154 #endif
2155 ndp->ni_dvp = vp;
2156 newvp = NULLVP;
2157
2158 /*
2159 * If there is no cookie, assume end of directory.
2160 */
2161 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2162 if (cookiep)
2163 cookie = *cookiep;
2164 else
2165 return (0);
2166 /*
2167 * Loop around doing readdir rpc's of size nm_readdirsize
2168 * truncated to a multiple of DIRBLKSIZ.
2169 * The stopping criteria is EOF or buffer full.
2170 */
2171 while (more_dirs && bigenough) {
2172 nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
2173 nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
2174 NFSX_FH(1) + 6 * NFSX_UNSIGNED);
2175 nfsm_fhtom(vp, 1);
2176 nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
2177 *tl++ = cookie.nfsuquad[0];
2178 *tl++ = cookie.nfsuquad[1];
2179 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2180 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2181 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
2182 *tl = txdr_unsigned(nmp->nm_rsize);
2183 nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
2184 nfsm_postop_attr(vp, attrflag);
2185 if (error) {
2186 m_freem(mrep);
2187 goto nfsmout;
2188 }
2189 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2190 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2191 dnp->n_cookieverf.nfsuquad[1] = *tl++;
2192 more_dirs = fxdr_unsigned(int, *tl);
2193
2194 /* loop thru the dir entries, doctoring them to 4bsd form */
2195 while (more_dirs && bigenough) {
2196 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2197 fxdr_hyper(tl, &fileno);
2198 len = fxdr_unsigned(int, *(tl + 2));
2199 if (len <= 0 || len > NFS_MAXNAMLEN) {
2200 error = EBADRPC;
2201 m_freem(mrep);
2202 goto nfsmout;
2203 }
2204 tlen = nfsm_rndup(len);
2205 if (tlen == len)
2206 tlen += 4; /* To ensure null termination*/
2207 left = DIRBLKSIZ - blksiz;
2208 if ((tlen + DIRHDSIZ) > left) {
2209 dp->d_reclen += left;
2210 uiop->uio_iov->iov_base += left;
2211 uiop->uio_iov->iov_len -= left;
2212 uiop->uio_offset += left;
2213 uiop->uio_resid -= left;
2214 blksiz = 0;
2215 }
2216 if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2217 bigenough = 0;
2218 if (bigenough) {
2219 dp = (struct dirent *)uiop->uio_iov->iov_base;
2220 dp->d_fileno = (int)fileno;
2221 dp->d_namlen = len;
2222 dp->d_reclen = tlen + DIRHDSIZ;
2223 dp->d_type = DT_UNKNOWN;
2224 blksiz += dp->d_reclen;
2225 if (blksiz == DIRBLKSIZ)
2226 blksiz = 0;
2227 uiop->uio_offset += DIRHDSIZ;
2228 uiop->uio_resid -= DIRHDSIZ;
2229 uiop->uio_iov->iov_base += DIRHDSIZ;
2230 uiop->uio_iov->iov_len -= DIRHDSIZ;
2231 cnp->cn_nameptr = uiop->uio_iov->iov_base;
2232 cnp->cn_namelen = len;
2233 nfsm_mtouio(uiop, len);
2234 cp = uiop->uio_iov->iov_base;
2235 tlen -= len;
2236 *cp = '\0';
2237 uiop->uio_iov->iov_base += tlen;
2238 uiop->uio_iov->iov_len -= tlen;
2239 uiop->uio_offset += tlen;
2240 uiop->uio_resid -= tlen;
2241 } else
2242 nfsm_adv(nfsm_rndup(len));
2243 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2244 if (bigenough) {
2245 cookie.nfsuquad[0] = *tl++;
2246 cookie.nfsuquad[1] = *tl++;
2247 } else
2248 tl += 2;
2249
2250 /*
2251 * Since the attributes are before the file handle
2252 * (sigh), we must skip over the attributes and then
2253 * come back and get them.
2254 */
2255 attrflag = fxdr_unsigned(int, *tl);
2256 if (attrflag) {
2257 dpossav1 = dpos;
2258 mdsav1 = md;
2259 nfsm_adv(NFSX_V3FATTR);
2260 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2261 doit = fxdr_unsigned(int, *tl);
2262 if (doit) {
2263 nfsm_getfh(fhp, fhsize, 1);
2264 if (NFS_CMPFH(dnp, fhp, fhsize)) {
2265 VREF(vp);
2266 newvp = vp;
2267 np = dnp;
2268 } else {
2269 if (error = nfs_nget(vp->v_mount, fhp,
2270 fhsize, &np))
2271 doit = 0;
2272 else
2273 newvp = NFSTOV(np);
2274 }
2275 }
2276 if (doit) {
2277 dpossav2 = dpos;
2278 dpos = dpossav1;
2279 mdsav2 = md;
2280 md = mdsav1;
2281 nfsm_loadattr(newvp, (struct vattr *)0);
2282 dpos = dpossav2;
2283 md = mdsav2;
2284 dp->d_type =
2285 IFTODT(VTTOIF(np->n_vattr.va_type));
2286 ndp->ni_vp = newvp;
2287 cnp->cn_hash = 0;
2288 for (cp = cnp->cn_nameptr, i = 1; i <= len;
2289 i++, cp++)
2290 cnp->cn_hash += (unsigned char)*cp * i;
2291 if (cnp->cn_namelen <= NCHNAMLEN)
2292 cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2293 }
2294 } else {
2295 /* Just skip over the file handle */
2296 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2297 i = fxdr_unsigned(int, *tl);
2298 nfsm_adv(nfsm_rndup(i));
2299 }
2300 if (newvp != NULLVP) {
2301 vrele(newvp);
2302 newvp = NULLVP;
2303 }
2304 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2305 more_dirs = fxdr_unsigned(int, *tl);
2306 }
2307 /*
2308 * If at end of rpc data, get the eof boolean
2309 */
2310 if (!more_dirs) {
2311 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2312 more_dirs = (fxdr_unsigned(int, *tl) == 0);
2313 }
2314 m_freem(mrep);
2315 }
2316 /*
2317 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
2318 * by increasing d_reclen for the last record.
2319 */
2320 if (blksiz > 0) {
2321 left = DIRBLKSIZ - blksiz;
2322 dp->d_reclen += left;
2323 uiop->uio_iov->iov_base += left;
2324 uiop->uio_iov->iov_len -= left;
2325 uiop->uio_offset += left;
2326 uiop->uio_resid -= left;
2327 }
2328
2329 /*
2330 * We are now either at the end of the directory or have filled the
2331 * block.
2332 */
2333 if (bigenough)
2334 dnp->n_direofoffset = uiop->uio_offset;
2335 else {
2336 if (uiop->uio_resid > 0)
2337 printf("EEK! readdirplusrpc resid > 0\n");
2338 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2339 *cookiep = cookie;
2340 }
2341 nfsmout:
2342 if (newvp != NULLVP)
2343 vrele(newvp);
2344 return (error);
2345 }
2346 static char hextoasc[] = "0123456789abcdef";
2347
2348 /*
2349 * Silly rename. To make the NFS filesystem that is stateless look a little
2350 * more like the "ufs" a remove of an active vnode is translated to a rename
2351 * to a funny looking filename that is removed by nfs_inactive on the
2352 * nfsnode. There is the potential for another process on a different client
2353 * to create the same funny name between the nfs_lookitup() fails and the
2354 * nfs_rename() completes, but...
2355 */
2356 int
2357 nfs_sillyrename(dvp, vp, cnp)
2358 struct vnode *dvp, *vp;
2359 struct componentname *cnp;
2360 {
2361 register struct sillyrename *sp;
2362 struct nfsnode *np;
2363 int error;
2364 short pid;
2365
2366 cache_purge(dvp);
2367 np = VTONFS(vp);
2368 #ifndef DIAGNOSTIC
2369 if (vp->v_type == VDIR)
2370 panic("nfs: sillyrename dir");
2371 #endif
2372 MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
2373 M_NFSREQ, M_WAITOK);
2374 sp->s_cred = crdup(cnp->cn_cred);
2375 sp->s_dvp = dvp;
2376 VREF(dvp);
2377
2378 /* Fudge together a funny name */
2379 pid = cnp->cn_proc->p_pid;
2380 bcopy(".nfsAxxxx4.4", sp->s_name, 13);
2381 sp->s_namlen = 12;
2382 sp->s_name[8] = hextoasc[pid & 0xf];
2383 sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
2384 sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
2385 sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
2386
2387 /* Try lookitups until we get one that isn't there */
2388 while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2389 cnp->cn_proc, (struct nfsnode **)0) == 0) {
2390 sp->s_name[4]++;
2391 if (sp->s_name[4] > 'z') {
2392 error = EINVAL;
2393 goto bad;
2394 }
2395 }
2396 if (error = nfs_renameit(dvp, cnp, sp))
2397 goto bad;
2398 error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2399 cnp->cn_proc, &np);
2400 np->n_sillyrename = sp;
2401 return (0);
2402 bad:
2403 vrele(sp->s_dvp);
2404 crfree(sp->s_cred);
2405 free((caddr_t)sp, M_NFSREQ);
2406 return (error);
2407 }
2408
2409 /*
2410 * Look up a file name and optionally either update the file handle or
2411 * allocate an nfsnode, depending on the value of npp.
2412 * npp == NULL --> just do the lookup
2413 * *npp == NULL --> allocate a new nfsnode and make sure attributes are
2414 * handled too
2415 * *npp != NULL --> update the file handle in the vnode
2416 */
2417 int
2418 nfs_lookitup(dvp, name, len, cred, procp, npp)
2419 register struct vnode *dvp;
2420 char *name;
2421 int len;
2422 struct ucred *cred;
2423 struct proc *procp;
2424 struct nfsnode **npp;
2425 {
2426 register u_long *tl;
2427 register caddr_t cp;
2428 register long t1, t2;
2429 struct vnode *newvp = (struct vnode *)0;
2430 struct nfsnode *np, *dnp = VTONFS(dvp);
2431 caddr_t bpos, dpos, cp2;
2432 int error = 0, fhlen, attrflag;
2433 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2434 nfsfh_t *nfhp;
2435 int v3 = NFS_ISV3(dvp);
2436
2437 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
2438 nfsm_reqhead(dvp, NFSPROC_LOOKUP,
2439 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
2440 nfsm_fhtom(dvp, v3);
2441 nfsm_strtom(name, len, NFS_MAXNAMLEN);
2442 nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
2443 if (npp && !error) {
2444 nfsm_getfh(nfhp, fhlen, v3);
2445 if (*npp) {
2446 np = *npp;
2447 if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
2448 free((caddr_t)np->n_fhp, M_NFSBIGFH);
2449 np->n_fhp = &np->n_fh;
2450 } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
2451 np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
2452 bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
2453 np->n_fhsize = fhlen;
2454 newvp = NFSTOV(np);
2455 } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
2456 VREF(dvp);
2457 newvp = dvp;
2458 } else {
2459 error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
2460 if (error) {
2461 m_freem(mrep);
2462 return (error);
2463 }
2464 newvp = NFSTOV(np);
2465 }
2466 if (v3) {
2467 nfsm_postop_attr(newvp, attrflag);
2468 if (!attrflag && *npp == NULL) {
2469 m_freem(mrep);
2470 vrele(newvp);
2471 return (ENOENT);
2472 }
2473 } else
2474 nfsm_loadattr(newvp, (struct vattr *)0);
2475 }
2476 nfsm_reqdone;
2477 if (npp && *npp == NULL) {
2478 if (error) {
2479 if (newvp)
2480 vrele(newvp);
2481 } else
2482 *npp = np;
2483 }
2484 return (error);
2485 }
2486
2487 /*
2488 * Nfs Version 3 commit rpc
2489 */
2490 int
2491 nfs_commit(vp, offset, cnt, cred, procp)
2492 register struct vnode *vp;
2493 u_quad_t offset;
2494 int cnt;
2495 struct ucred *cred;
2496 struct proc *procp;
2497 {
2498 register caddr_t cp;
2499 register u_long *tl;
2500 register int t1, t2;
2501 register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2502 caddr_t bpos, dpos, cp2;
2503 int error = 0, wccflag = NFSV3_WCCRATTR;
2504 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2505
2506 if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
2507 return (0);
2508 nfsstats.rpccnt[NFSPROC_COMMIT]++;
2509 nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
2510 nfsm_fhtom(vp, 1);
2511 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
2512 txdr_hyper(&offset, tl);
2513 tl += 2;
2514 *tl = txdr_unsigned(cnt);
2515 nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
2516 nfsm_wcc_data(vp, wccflag);
2517 if (!error) {
2518 nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
2519 if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
2520 NFSX_V3WRITEVERF)) {
2521 bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
2522 NFSX_V3WRITEVERF);
2523 error = NFSERR_STALEWRITEVERF;
2524 }
2525 }
2526 nfsm_reqdone;
2527 return (error);
2528 }
2529
2530 /*
2531 * Kludge City..
2532 * - make nfs_bmap() essentially a no-op that does no translation
2533 * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
2534 * (Maybe I could use the process's page mapping, but I was concerned that
2535 * Kernel Write might not be enabled and also figured copyout() would do
2536 * a lot more work than bcopy() and also it currently happens in the
2537 * context of the swapper process (2).
2538 */
2539 int
2540 nfs_bmap(ap)
2541 struct vop_bmap_args /* {
2542 struct vnode *a_vp;
2543 daddr_t a_bn;
2544 struct vnode **a_vpp;
2545 daddr_t *a_bnp;
2546 int *a_runp;
2547 } */ *ap;
2548 {
2549 register struct vnode *vp = ap->a_vp;
2550
2551 if (ap->a_vpp != NULL)
2552 *ap->a_vpp = vp;
2553 if (ap->a_bnp != NULL)
2554 *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
2555 return (0);
2556 }
2557
2558 /*
2559 * Strategy routine.
2560 * For async requests when nfsiod(s) are running, queue the request by
2561 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
2562 * request.
2563 */
2564 int
2565 nfs_strategy(ap)
2566 struct vop_strategy_args *ap;
2567 {
2568 register struct buf *bp = ap->a_bp;
2569 struct ucred *cr;
2570 struct proc *p;
2571 int error = 0;
2572
2573 if (bp->b_flags & B_PHYS)
2574 panic("nfs physio");
2575 if (bp->b_flags & B_ASYNC)
2576 p = (struct proc *)0;
2577 else
2578 p = curproc; /* XXX */
2579 if (bp->b_flags & B_READ)
2580 cr = bp->b_rcred;
2581 else
2582 cr = bp->b_wcred;
2583 /*
2584 * If the op is asynchronous and an i/o daemon is waiting
2585 * queue the request, wake it up and wait for completion
2586 * otherwise just do it ourselves.
2587 */
2588 if ((bp->b_flags & B_ASYNC) == 0 ||
2589 nfs_asyncio(bp, NOCRED))
2590 error = nfs_doio(bp, cr, p);
2591 return (error);
2592 }
2593
2594 /*
2595 * Mmap a file
2596 *
2597 * NB Currently unsupported.
2598 */
2599 /* ARGSUSED */
2600 int
2601 nfs_mmap(ap)
2602 struct vop_mmap_args /* {
2603 struct vnode *a_vp;
2604 int a_fflags;
2605 struct ucred *a_cred;
2606 struct proc *a_p;
2607 } */ *ap;
2608 {
2609
2610 return (EINVAL);
2611 }
2612
2613 /*
2614 * fsync vnode op. Just call nfs_flush() with commit == 1.
2615 */
2616 /* ARGSUSED */
2617 int
2618 nfs_fsync(ap)
2619 struct vop_fsync_args /* {
2620 struct vnodeop_desc *a_desc;
2621 struct vnode * a_vp;
2622 struct ucred * a_cred;
2623 int a_waitfor;
2624 struct proc * a_p;
2625 } */ *ap;
2626 {
2627
2628 return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
2629 }
2630
2631 /*
2632 * Flush all the blocks associated with a vnode.
2633 * Walk through the buffer pool and push any dirty pages
2634 * associated with the vnode.
2635 */
2636 int
2637 nfs_flush(vp, cred, waitfor, p, commit)
2638 register struct vnode *vp;
2639 struct ucred *cred;
2640 int waitfor;
2641 struct proc *p;
2642 int commit;
2643 {
2644 register struct nfsnode *np = VTONFS(vp);
2645 register struct buf *bp;
2646 register int i;
2647 struct buf *nbp;
2648 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2649 int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
2650 int passone = 1;
2651 u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
2652 #ifndef NFS_COMMITBVECSIZ
2653 #define NFS_COMMITBVECSIZ 20
2654 #endif
2655 struct buf *bvec[NFS_COMMITBVECSIZ];
2656
2657 if (nmp->nm_flag & NFSMNT_INT)
2658 slpflag = PCATCH;
2659 if (!commit)
2660 passone = 0;
2661 /*
2662 * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
2663 * server, but nas not been committed to stable storage on the server
2664 * yet. On the first pass, the byte range is worked out and the commit
2665 * rpc is done. On the second pass, nfs_writebp() is called to do the
2666 * job.
2667 */
2668 again:
2669 bvecpos = 0;
2670 if (NFS_ISV3(vp) && commit) {
2671 s = splbio();
2672 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2673 nbp = bp->b_vnbufs.le_next;
2674 if (bvecpos >= NFS_COMMITBVECSIZ)
2675 break;
2676 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2677 != (B_DELWRI | B_NEEDCOMMIT))
2678 continue;
2679 bremfree(bp);
2680 bp->b_flags |= (B_BUSY | B_WRITEINPROG);
2681 /*
2682 * A list of these buffers is kept so that the
2683 * second loop knows which buffers have actually
2684 * been committed. This is necessary, since there
2685 * may be a race between the commit rpc and new
2686 * uncommitted writes on the file.
2687 */
2688 bvec[bvecpos++] = bp;
2689 toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2690 bp->b_dirtyoff;
2691 if (toff < off)
2692 off = toff;
2693 toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
2694 if (toff > endoff)
2695 endoff = toff;
2696 }
2697 splx(s);
2698 }
2699 if (bvecpos > 0) {
2700 /*
2701 * Commit data on the server, as required.
2702 */
2703 retv = nfs_commit(vp, off, (int)(endoff - off), cred, p);
2704 if (retv == NFSERR_STALEWRITEVERF)
2705 nfs_clearcommit(vp->v_mount);
2706 /*
2707 * Now, either mark the blocks I/O done or mark the
2708 * blocks dirty, depending on whether the commit
2709 * succeeded.
2710 */
2711 for (i = 0; i < bvecpos; i++) {
2712 bp = bvec[i];
2713 bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
2714 if (retv) {
2715 brelse(bp);
2716 } else {
2717 vp->v_numoutput++;
2718 bp->b_flags |= B_ASYNC;
2719 bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
2720 bp->b_dirtyoff = bp->b_dirtyend = 0;
2721 reassignbuf(bp, vp);
2722 biodone(bp);
2723 }
2724 }
2725 }
2726
2727 /*
2728 * Start/do any write(s) that are required.
2729 */
2730 loop:
2731 s = splbio();
2732 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2733 nbp = bp->b_vnbufs.le_next;
2734 if (bp->b_flags & B_BUSY) {
2735 if (waitfor != MNT_WAIT || passone)
2736 continue;
2737 bp->b_flags |= B_WANTED;
2738 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
2739 "nfsfsync", slptimeo);
2740 splx(s);
2741 if (error) {
2742 if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
2743 return (EINTR);
2744 if (slpflag == PCATCH) {
2745 slpflag = 0;
2746 slptimeo = 2 * hz;
2747 }
2748 }
2749 goto loop;
2750 }
2751 if ((bp->b_flags & B_DELWRI) == 0)
2752 panic("nfs_fsync: not dirty");
2753 if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
2754 continue;
2755 bremfree(bp);
2756 if (passone || !commit)
2757 bp->b_flags |= (B_BUSY|B_ASYNC);
2758 else
2759 bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
2760 splx(s);
2761 VOP_BWRITE(bp);
2762 goto loop;
2763 }
2764 splx(s);
2765 if (passone) {
2766 passone = 0;
2767 goto again;
2768 }
2769 if (waitfor == MNT_WAIT) {
2770 while (vp->v_numoutput) {
2771 vp->v_flag |= VBWAIT;
2772 error = tsleep((caddr_t)&vp->v_numoutput,
2773 slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
2774 if (error) {
2775 if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
2776 return (EINTR);
2777 if (slpflag == PCATCH) {
2778 slpflag = 0;
2779 slptimeo = 2 * hz;
2780 }
2781 }
2782 }
2783 if (vp->v_dirtyblkhd.lh_first && commit) {
2784 #ifndef DIAGNOSTIC
2785 vprint("nfs_fsync: dirty", vp);
2786 #endif
2787 goto loop;
2788 }
2789 }
2790 if (np->n_flag & NWRITEERR) {
2791 error = np->n_error;
2792 np->n_flag &= ~NWRITEERR;
2793 }
2794 return (error);
2795 }
2796
2797 /*
2798 * Return POSIX pathconf information applicable to nfs.
2799 *
2800 * The NFS V2 protocol doesn't support this, so just return EINVAL
2801 * for V2.
2802 */
2803 /* ARGSUSED */
2804 int
2805 nfs_pathconf(ap)
2806 struct vop_pathconf_args /* {
2807 struct vnode *a_vp;
2808 int a_name;
2809 int *a_retval;
2810 } */ *ap;
2811 {
2812
2813 return (EINVAL);
2814 }
2815
2816 /*
2817 * NFS advisory byte-level locks.
2818 * Currently unsupported.
2819 */
2820 int
2821 nfs_advlock(ap)
2822 struct vop_advlock_args /* {
2823 struct vnode *a_vp;
2824 caddr_t a_id;
2825 int a_op;
2826 struct flock *a_fl;
2827 int a_flags;
2828 } */ *ap;
2829 {
2830
2831 return (EOPNOTSUPP);
2832 }
2833
2834 /*
2835 * Print out the contents of an nfsnode.
2836 */
2837 int
2838 nfs_print(ap)
2839 struct vop_print_args /* {
2840 struct vnode *a_vp;
2841 } */ *ap;
2842 {
2843 register struct vnode *vp = ap->a_vp;
2844 register struct nfsnode *np = VTONFS(vp);
2845
2846 printf("tag VT_NFS, fileid %ld fsid 0x%lx",
2847 np->n_vattr.va_fileid, np->n_vattr.va_fsid);
2848 if (vp->v_type == VFIFO)
2849 fifo_printinfo(vp);
2850 printf("\n");
2851 return (0);
2852 }
2853
2854 /*
2855 * NFS directory offset lookup.
2856 * Currently unsupported.
2857 */
2858 int
2859 nfs_blkatoff(ap)
2860 struct vop_blkatoff_args /* {
2861 struct vnode *a_vp;
2862 off_t a_offset;
2863 char **a_res;
2864 struct buf **a_bpp;
2865 } */ *ap;
2866 {
2867
2868 return (EOPNOTSUPP);
2869 }
2870
2871 /*
2872 * NFS flat namespace allocation.
2873 * Currently unsupported.
2874 */
2875 int
2876 nfs_valloc(ap)
2877 struct vop_valloc_args /* {
2878 struct vnode *a_pvp;
2879 int a_mode;
2880 struct ucred *a_cred;
2881 struct vnode **a_vpp;
2882 } */ *ap;
2883 {
2884
2885 return (EOPNOTSUPP);
2886 }
2887
2888 /*
2889 * NFS flat namespace free.
2890 * Currently unsupported.
2891 */
2892 int
2893 nfs_vfree(ap)
2894 struct vop_vfree_args /* {
2895 struct vnode *a_pvp;
2896 ino_t a_ino;
2897 int a_mode;
2898 } */ *ap;
2899 {
2900
2901 return (EOPNOTSUPP);
2902 }
2903
2904 /*
2905 * NFS file truncation.
2906 */
2907 int
2908 nfs_truncate(ap)
2909 struct vop_truncate_args /* {
2910 struct vnode *a_vp;
2911 off_t a_length;
2912 int a_flags;
2913 struct ucred *a_cred;
2914 struct proc *a_p;
2915 } */ *ap;
2916 {
2917
2918 /* Use nfs_setattr */
2919 printf("nfs_truncate: need to implement!!");
2920 return (EOPNOTSUPP);
2921 }
2922
2923 /*
2924 * NFS update.
2925 */
2926 int
2927 nfs_update(ap)
2928 struct vop_update_args /* {
2929 struct vnode *a_vp;
2930 struct timeval *a_ta;
2931 struct timeval *a_tm;
2932 int a_waitfor;
2933 } */ *ap;
2934 {
2935
2936 /* Use nfs_setattr */
2937 printf("nfs_update: need to implement!!");
2938 return (EOPNOTSUPP);
2939 }
2940
2941 /*
2942 * Just call nfs_writebp() with the force argument set to 1.
2943 */
2944 int
2945 nfs_bwrite(ap)
2946 struct vop_bwrite_args /* {
2947 struct vnode *a_bp;
2948 } */ *ap;
2949 {
2950
2951 return (nfs_writebp(ap->a_bp, 1));
2952 }
2953
2954 /*
2955 * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
2956 * the force flag is one and it also handles the B_NEEDCOMMIT flag.
2957 */
2958 int
2959 nfs_writebp(bp, force)
2960 register struct buf *bp;
2961 int force;
2962 {
2963 register int oldflags = bp->b_flags, retv = 1;
2964 register struct proc *p = curproc; /* XXX */
2965 off_t off;
2966
2967 if(!(bp->b_flags & B_BUSY))
2968 panic("bwrite: buffer is not busy???");
2969
2970 bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
2971
2972 if (oldflags & B_ASYNC) {
2973 if (oldflags & B_DELWRI) {
2974 reassignbuf(bp, bp->b_vp);
2975 } else if (p) {
2976 ++p->p_stats->p_ru.ru_oublock;
2977 }
2978 }
2979 bp->b_vp->v_numoutput++;
2980
2981 /*
2982 * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
2983 * an actual write will have to be scheduled via. VOP_STRATEGY().
2984 * If B_WRITEINPROG is already set, then push it with a write anyhow.
2985 */
2986 if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) {
2987 off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
2988 bp->b_flags |= B_WRITEINPROG;
2989 retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
2990 bp->b_wcred, bp->b_proc);
2991 bp->b_flags &= ~B_WRITEINPROG;
2992 if (!retv) {
2993 bp->b_dirtyoff = bp->b_dirtyend = 0;
2994 bp->b_flags &= ~B_NEEDCOMMIT;
2995 biodone(bp);
2996 } else if (retv == NFSERR_STALEWRITEVERF)
2997 nfs_clearcommit(bp->b_vp->v_mount);
2998 }
2999 if (retv) {
3000 if (force)
3001 bp->b_flags |= B_WRITEINPROG;
3002 VOP_STRATEGY(bp);
3003 }
3004
3005 if( (oldflags & B_ASYNC) == 0) {
3006 int rtval = biowait(bp);
3007 if (oldflags & B_DELWRI) {
3008 reassignbuf(bp, bp->b_vp);
3009 } else if (p) {
3010 ++p->p_stats->p_ru.ru_oublock;
3011 }
3012 brelse(bp);
3013 return (rtval);
3014 }
3015
3016 return (0);
3017 }
3018
3019 /*
3020 * nfs special file access vnode op.
3021 * Essentially just get vattr and then imitate iaccess() since the device is
3022 * local to the client.
3023 */
3024 int
3025 nfsspec_access(ap)
3026 struct vop_access_args /* {
3027 struct vnode *a_vp;
3028 int a_mode;
3029 struct ucred *a_cred;
3030 struct proc *a_p;
3031 } */ *ap;
3032 {
3033 register struct vattr *vap;
3034 register gid_t *gp;
3035 register struct ucred *cred = ap->a_cred;
3036 struct vnode *vp = ap->a_vp;
3037 mode_t mode = ap->a_mode;
3038 struct vattr vattr;
3039 register int i;
3040 int error;
3041
3042 /*
3043 * Disallow write attempts on filesystems mounted read-only;
3044 * unless the file is a socket, fifo, or a block or character
3045 * device resident on the filesystem.
3046 */
3047 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3048 switch (vp->v_type) {
3049 case VREG: case VDIR: case VLNK:
3050 return (EROFS);
3051 }
3052 }
3053 /*
3054 * If you're the super-user,
3055 * you always get access.
3056 */
3057 if (cred->cr_uid == 0)
3058 return (0);
3059 vap = &vattr;
3060 error = VOP_GETATTR(vp, vap, cred, ap->a_p);
3061 if (error)
3062 return (error);
3063 /*
3064 * Access check is based on only one of owner, group, public.
3065 * If not owner, then check group. If not a member of the
3066 * group, then check public access.
3067 */
3068 if (cred->cr_uid != vap->va_uid) {
3069 mode >>= 3;
3070 gp = cred->cr_groups;
3071 for (i = 0; i < cred->cr_ngroups; i++, gp++)
3072 if (vap->va_gid == *gp)
3073 goto found;
3074 mode >>= 3;
3075 found:
3076 ;
3077 }
3078 error = (vap->va_mode & mode) == mode ? 0 : EACCES;
3079 return (error);
3080 }
3081
3082 /*
3083 * Read wrapper for special devices.
3084 */
3085 int
3086 nfsspec_read(ap)
3087 struct vop_read_args /* {
3088 struct vnode *a_vp;
3089 struct uio *a_uio;
3090 int a_ioflag;
3091 struct ucred *a_cred;
3092 } */ *ap;
3093 {
3094 register struct nfsnode *np = VTONFS(ap->a_vp);
3095
3096 /*
3097 * Set access flag.
3098 */
3099 np->n_flag |= NACC;
3100 np->n_atim.ts_sec = time.tv_sec;
3101 np->n_atim.ts_nsec = time.tv_usec * 1000;
3102 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
3103 }
3104
3105 /*
3106 * Write wrapper for special devices.
3107 */
3108 int
3109 nfsspec_write(ap)
3110 struct vop_write_args /* {
3111 struct vnode *a_vp;
3112 struct uio *a_uio;
3113 int a_ioflag;
3114 struct ucred *a_cred;
3115 } */ *ap;
3116 {
3117 register struct nfsnode *np = VTONFS(ap->a_vp);
3118
3119 /*
3120 * Set update flag.
3121 */
3122 np->n_flag |= NUPD;
3123 np->n_mtim.ts_sec = time.tv_sec;
3124 np->n_mtim.ts_nsec = time.tv_usec * 1000;
3125 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
3126 }
3127
3128 /*
3129 * Close wrapper for special devices.
3130 *
3131 * Update the times on the nfsnode then do device close.
3132 */
3133 int
3134 nfsspec_close(ap)
3135 struct vop_close_args /* {
3136 struct vnode *a_vp;
3137 int a_fflag;
3138 struct ucred *a_cred;
3139 struct proc *a_p;
3140 } */ *ap;
3141 {
3142 register struct vnode *vp = ap->a_vp;
3143 register struct nfsnode *np = VTONFS(vp);
3144 struct vattr vattr;
3145
3146 if (np->n_flag & (NACC | NUPD)) {
3147 np->n_flag |= NCHG;
3148 if (vp->v_usecount == 1 &&
3149 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3150 VATTR_NULL(&vattr);
3151 if (np->n_flag & NACC)
3152 vattr.va_atime = np->n_atim;
3153 if (np->n_flag & NUPD)
3154 vattr.va_mtime = np->n_mtim;
3155 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
3156 }
3157 }
3158 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
3159 }
3160
3161 /*
3162 * Read wrapper for fifos.
3163 */
3164 int
3165 nfsfifo_read(ap)
3166 struct vop_read_args /* {
3167 struct vnode *a_vp;
3168 struct uio *a_uio;
3169 int a_ioflag;
3170 struct ucred *a_cred;
3171 } */ *ap;
3172 {
3173 extern int (**fifo_vnodeop_p)();
3174 register struct nfsnode *np = VTONFS(ap->a_vp);
3175
3176 /*
3177 * Set access flag.
3178 */
3179 np->n_flag |= NACC;
3180 np->n_atim.ts_sec = time.tv_sec;
3181 np->n_atim.ts_nsec = time.tv_usec * 1000;
3182 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
3183 }
3184
3185 /*
3186 * Write wrapper for fifos.
3187 */
3188 int
3189 nfsfifo_write(ap)
3190 struct vop_write_args /* {
3191 struct vnode *a_vp;
3192 struct uio *a_uio;
3193 int a_ioflag;
3194 struct ucred *a_cred;
3195 } */ *ap;
3196 {
3197 extern int (**fifo_vnodeop_p)();
3198 register struct nfsnode *np = VTONFS(ap->a_vp);
3199
3200 /*
3201 * Set update flag.
3202 */
3203 np->n_flag |= NUPD;
3204 np->n_mtim.ts_sec = time.tv_sec;
3205 np->n_mtim.ts_nsec = time.tv_usec * 1000;
3206 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
3207 }
3208
3209 /*
3210 * Close wrapper for fifos.
3211 *
3212 * Update the times on the nfsnode then do fifo close.
3213 */
3214 int
3215 nfsfifo_close(ap)
3216 struct vop_close_args /* {
3217 struct vnode *a_vp;
3218 int a_fflag;
3219 struct ucred *a_cred;
3220 struct proc *a_p;
3221 } */ *ap;
3222 {
3223 register struct vnode *vp = ap->a_vp;
3224 register struct nfsnode *np = VTONFS(vp);
3225 struct vattr vattr;
3226 extern int (**fifo_vnodeop_p)();
3227
3228 if (np->n_flag & (NACC | NUPD)) {
3229 if (np->n_flag & NACC) {
3230 np->n_atim.ts_sec = time.tv_sec;
3231 np->n_atim.ts_nsec = time.tv_usec * 1000;
3232 }
3233 if (np->n_flag & NUPD) {
3234 np->n_mtim.ts_sec = time.tv_sec;
3235 np->n_mtim.ts_nsec = time.tv_usec * 1000;
3236 }
3237 np->n_flag |= NCHG;
3238 if (vp->v_usecount == 1 &&
3239 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3240 VATTR_NULL(&vattr);
3241 if (np->n_flag & NACC)
3242 vattr.va_atime = np->n_atim;
3243 if (np->n_flag & NUPD)
3244 vattr.va_mtime = np->n_mtim;
3245 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
3246 }
3247 }
3248 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
3249 }
3250