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