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