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