add previous create time for name cache consistency
[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 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
23ec03dc 20 * @(#)nfs_vnops.c 7.29 (Berkeley) %G%
a2907882
KM
21 */
22
23/*
24 * vnode op calls for sun nfs version 2
25 */
26
27#include "machine/pte.h"
28#include "machine/mtpr.h"
a2907882
KM
29#include "param.h"
30#include "user.h"
31#include "proc.h"
32#include "mount.h"
33#include "buf.h"
34#include "vm.h"
a2907882
KM
35#include "malloc.h"
36#include "mbuf.h"
a2907882
KM
37#include "errno.h"
38#include "file.h"
39#include "conf.h"
40#include "vnode.h"
9238aa59 41#include "map.h"
a2907882
KM
42#include "nfsv2.h"
43#include "nfs.h"
44#include "nfsnode.h"
45#include "nfsmount.h"
46#include "xdr_subs.h"
47#include "nfsm_subs.h"
9238aa59 48#include "nfsiom.h"
a2907882
KM
49
50/* Defs */
51#define TRUE 1
52#define FALSE 0
53
54/* Global vars */
55int nfs_lookup(),
56 nfs_create(),
f67785e5 57 nfs_mknod(),
a2907882
KM
58 nfs_open(),
59 nfs_close(),
60 nfs_access(),
61 nfs_getattr(),
62 nfs_setattr(),
63 nfs_read(),
64 nfs_write(),
65 vfs_noop(),
66 vfs_nullop(),
67 nfs_remove(),
68 nfs_link(),
69 nfs_rename(),
70 nfs_mkdir(),
71 nfs_rmdir(),
72 nfs_symlink(),
73 nfs_readdir(),
74 nfs_readlink(),
75 nfs_abortop(),
76 nfs_lock(),
77 nfs_unlock(),
78 nfs_bmap(),
79 nfs_strategy(),
9238aa59 80 nfs_fsync(),
8c7139ba 81 nfs_inactive(),
d002709d 82 nfs_reclaim(),
2bde67fd
KM
83 nfs_print(),
84 nfs_islocked();
a2907882
KM
85
86struct vnodeops nfsv2_vnodeops = {
d002709d
KM
87 nfs_lookup, /* lookup */
88 nfs_create, /* create */
89 nfs_mknod, /* mknod */
90 nfs_open, /* open */
91 nfs_close, /* close */
92 nfs_access, /* access */
93 nfs_getattr, /* getattr */
94 nfs_setattr, /* setattr */
95 nfs_read, /* read */
96 nfs_write, /* write */
97 vfs_noop, /* ioctl */
98 vfs_noop, /* select */
99 vfs_noop, /* mmap */
100 nfs_fsync, /* fsync */
101 vfs_nullop, /* seek */
102 nfs_remove, /* remove */
103 nfs_link, /* link */
104 nfs_rename, /* rename */
105 nfs_mkdir, /* mkdir */
106 nfs_rmdir, /* rmdir */
107 nfs_symlink, /* symlink */
108 nfs_readdir, /* readdir */
109 nfs_readlink, /* readlink */
110 nfs_abortop, /* abortop */
111 nfs_inactive, /* inactive */
112 nfs_reclaim, /* reclaim */
113 nfs_lock, /* lock */
114 nfs_unlock, /* unlock */
115 nfs_bmap, /* bmap */
116 nfs_strategy, /* strategy */
117 nfs_print, /* print */
2bde67fd 118 nfs_islocked, /* islocked */
a2907882
KM
119};
120
121/* Special device vnode ops */
8a1675f3
KM
122int spec_lookup(),
123 spec_open(),
124 spec_read(),
125 spec_write(),
126 spec_strategy(),
d002709d 127 spec_bmap(),
8a1675f3
KM
128 spec_ioctl(),
129 spec_select(),
130 spec_close(),
131 spec_badop(),
132 spec_nullop();
a2907882 133
8a1675f3 134struct vnodeops spec_nfsv2nodeops = {
9106dc18
KM
135 spec_lookup, /* lookup */
136 spec_badop, /* create */
137 spec_badop, /* mknod */
138 spec_open, /* open */
139 spec_close, /* close */
140 nfs_access, /* access */
141 nfs_getattr, /* getattr */
142 nfs_setattr, /* setattr */
143 spec_read, /* read */
144 spec_write, /* write */
145 spec_ioctl, /* ioctl */
146 spec_select, /* select */
147 spec_badop, /* mmap */
148 spec_nullop, /* fsync */
149 spec_badop, /* seek */
150 spec_badop, /* remove */
151 spec_badop, /* link */
152 spec_badop, /* rename */
153 spec_badop, /* mkdir */
154 spec_badop, /* rmdir */
155 spec_badop, /* symlink */
156 spec_badop, /* readdir */
157 spec_badop, /* readlink */
158 spec_badop, /* abortop */
159 nfs_inactive, /* inactive */
160 nfs_reclaim, /* reclaim */
161 nfs_lock, /* lock */
162 nfs_unlock, /* unlock */
d002709d 163 spec_bmap, /* bmap */
9106dc18 164 spec_strategy, /* strategy */
d002709d 165 nfs_print, /* print */
2bde67fd 166 nfs_islocked, /* islocked */
a2907882
KM
167};
168
169extern u_long nfs_procids[NFS_NPROCS];
170extern u_long nfs_prog, nfs_vers;
a2907882 171extern char nfsiobuf[MAXPHYS+NBPG];
f5f6c13e 172extern int nonidempotent[NFS_NPROCS];
9238aa59 173struct map nfsmap[NFS_MSIZ];
a2907882 174enum vtype v_type[NFLNK+1];
9238aa59 175struct buf nfs_bqueue; /* Queue head for nfsiod's */
ffe6f482
KM
176int nfs_asyncdaemons = 0;
177struct proc *nfs_iodwant[MAX_ASYNCDAEMON];
9238aa59 178static int nfsmap_want = 0;
a2907882
KM
179
180/*
181 * nfs null call from vfs.
182 */
183nfs_null(vp, cred)
184 struct vnode *vp;
185 struct ucred *cred;
186{
13576453
KM
187 caddr_t bpos, dpos;
188 u_long xid;
189 int error = 0;
190 struct mbuf *mreq, *mrep, *md, *mb;
a2907882
KM
191
192 nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
f5f6c13e 193 nfsm_request(vp, nonidempotent[NFSPROC_NULL]);
a2907882
KM
194 nfsm_reqdone;
195 return (error);
196}
197
198/*
199 * nfs access vnode op.
200 * Essentially just get vattr and then imitate iaccess()
201 */
202nfs_access(vp, mode, cred)
203 struct vnode *vp;
204 int mode;
205 register struct ucred *cred;
206{
207 register struct vattr *vap;
208 register gid_t *gp;
209 struct vattr vattr;
210 register int i;
211 int error;
212
213 /*
214 * If you're the super-user,
215 * you always get access.
216 */
217 if (cred->cr_uid == 0)
218 return (0);
219 vap = &vattr;
9238aa59
RM
220 if (error = nfs_getattr(vp, vap, cred))
221 return (error);
a2907882
KM
222 /*
223 * Access check is based on only one of owner, group, public.
224 * If not owner, then check group. If not a member of the
225 * group, then check public access.
226 */
227 if (cred->cr_uid != vap->va_uid) {
228 mode >>= 3;
229 gp = cred->cr_groups;
230 for (i = 0; i < cred->cr_ngroups; i++, gp++)
231 if (vap->va_gid == *gp)
232 goto found;
233 mode >>= 3;
234found:
235 ;
236 }
237 if ((vap->va_mode & mode) != 0)
238 return (0);
239 return (EACCES);
240}
241
242/*
243 * nfs open vnode op
244 * Just check to see if the type is ok
245 */
13576453 246/* ARGSUSED */
a2907882
KM
247nfs_open(vp, mode, cred)
248 struct vnode *vp;
249 int mode;
250 struct ucred *cred;
251{
252 register enum vtype vtyp;
253
254 vtyp = vp->v_type;
255 if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
256 return (0);
257 else
258 return (EACCES);
259}
260
261/*
262 * nfs close vnode op
9238aa59 263 * For reg files, invalidate any buffer cache entries.
a2907882 264 */
13576453 265/* ARGSUSED */
a2907882
KM
266nfs_close(vp, fflags, cred)
267 register struct vnode *vp;
268 int fflags;
269 struct ucred *cred;
270{
13576453 271 register struct nfsnode *np = VTONFS(vp);
ffe6f482 272 int error = 0;
a2907882 273
fe53c871 274 if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) ||
ffe6f482 275 ((np->n_flag & NBUFFERED) && np->n_sillyrename))) {
8a1675f3 276 nfs_lock(vp);
ffe6f482 277 np->n_flag &= ~(NMODIFIED|NBUFFERED);
e8540f59 278 vinvalbuf(vp, TRUE);
ffe6f482
KM
279 if (np->n_flag & NWRITEERR) {
280 np->n_flag &= ~NWRITEERR;
e8540f59 281 error = np->n_error;
ffe6f482 282 }
8a1675f3 283 nfs_unlock(vp);
9238aa59 284 }
a2907882
KM
285 return (error);
286}
287
288/*
289 * nfs getattr call from vfs.
290 */
291nfs_getattr(vp, vap, cred)
13576453
KM
292 register struct vnode *vp;
293 struct vattr *vap;
a2907882
KM
294 struct ucred *cred;
295{
13576453
KM
296 register caddr_t cp;
297 register long t1;
298 caddr_t bpos, dpos;
299 u_long xid;
300 int error = 0;
301 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
302
303 /* First look in the cache.. */
304 if (nfs_getattrcache(vp, vap) == 0)
305 return (0);
306 nfsstats.rpccnt[NFSPROC_GETATTR]++;
307 nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
308 nfsm_fhtom(vp);
f5f6c13e 309 nfsm_request(vp, nonidempotent[NFSPROC_GETATTR]);
a2907882
KM
310 nfsm_loadattr(vp, vap);
311 nfsm_reqdone;
312 return (error);
313}
314
315/*
316 * nfs setattr call.
317 */
318nfs_setattr(vp, vap, cred)
13576453 319 register struct vnode *vp;
a2907882
KM
320 register struct vattr *vap;
321 struct ucred *cred;
322{
9238aa59 323 register struct nfsv2_sattr *sp;
13576453
KM
324 register caddr_t cp;
325 register long t1;
326 caddr_t bpos, dpos;
327 u_long xid;
328 int error = 0;
329 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
00b72154 330 struct nfsnode *np;
a2907882
KM
331
332 nfsstats.rpccnt[NFSPROC_SETATTR]++;
333 nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
334 nfsm_fhtom(vp);
9238aa59 335 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
a2907882 336 if (vap->va_mode == 0xffff)
9238aa59 337 sp->sa_mode = VNOVAL;
a2907882 338 else
9238aa59 339 sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
a2907882 340 if (vap->va_uid == 0xffff)
9238aa59 341 sp->sa_uid = VNOVAL;
a2907882 342 else
9238aa59 343 sp->sa_uid = txdr_unsigned(vap->va_uid);
a2907882 344 if (vap->va_gid == 0xffff)
9238aa59 345 sp->sa_gid = VNOVAL;
a2907882 346 else
9238aa59
RM
347 sp->sa_gid = txdr_unsigned(vap->va_gid);
348 sp->sa_size = txdr_unsigned(vap->va_size);
00b72154
KM
349 if (vap->va_size != VNOVAL) {
350 np = VTONFS(vp);
351 if (np->n_flag & NMODIFIED) {
352 np->n_flag &= ~NMODIFIED;
fe53c871 353 vinvalbuf(vp, TRUE);
00b72154
KM
354 }
355 }
e8540f59
KM
356 sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
357 sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
9238aa59 358 txdr_time(&vap->va_mtime, &sp->sa_mtime);
f5f6c13e 359 nfsm_request(vp, nonidempotent[NFSPROC_SETATTR]);
a2907882
KM
360 nfsm_loadattr(vp, (struct vattr *)0);
361 /* should we fill in any vap fields ?? */
362 nfsm_reqdone;
363 return (error);
364}
365
366/*
367 * nfs lookup call, one step at a time...
368 * First look in cache
369 * If not found, unlock the directory nfsnode and do the rpc
370 */
371nfs_lookup(vp, ndp)
372 register struct vnode *vp;
373 register struct nameidata *ndp;
374{
375 register struct vnode *vdp;
13576453
KM
376 register u_long *p;
377 register caddr_t cp;
378 register long t1, t2;
379 caddr_t bpos, dpos, cp2;
380 u_long xid;
381 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
382 struct vnode *newvp;
383 long len;
384 nfsv2fh_t *fhp;
385 struct nfsnode *np;
13576453 386 int lockparent, wantparent, flag, error = 0;
a2907882
KM
387
388 ndp->ni_dvp = vp;
389 ndp->ni_vp = NULL;
390 if (vp->v_type != VDIR)
391 return (ENOTDIR);
392 lockparent = ndp->ni_nameiop & LOCKPARENT;
393 flag = ndp->ni_nameiop & OPFLAG;
394 wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
ffe6f482 395 if ((error = cache_lookup(ndp)) && error != ENOENT) {
9238aa59
RM
396 struct vattr vattr;
397 int vpid;
398
8a1675f3
KM
399 if (vp == ndp->ni_rdir && ndp->ni_isdotdot)
400 panic("nfs_lookup: .. through root");
401 vdp = ndp->ni_vp;
9238aa59 402 vpid = vdp->v_id;
a2907882 403 /*
9238aa59
RM
404 * See the comment starting `Step through' in ufs/ufs_lookup.c
405 * for an explanation of the locking protocol
a2907882
KM
406 */
407 if (vp == vdp) {
36c3043b 408 VREF(vdp);
8a1675f3 409 error = 0;
a2907882
KM
410 } else if (ndp->ni_isdotdot) {
411 nfs_unlock(vp);
8a1675f3 412 error = vget(vdp);
a2907882 413 } else {
8a1675f3 414 error = vget(vdp);
a2907882
KM
415 nfs_unlock(vp);
416 }
8a1675f3
KM
417 if (!error) {
418 if (vpid == vdp->v_id &&
419 !nfs_getattr(vdp, &vattr, ndp->ni_cred)) {
420 nfsstats.lookupcache_hits++;
421 return (0);
422 } else {
423 nfs_nput(vdp);
424 }
9238aa59 425 }
9238aa59 426 ndp->ni_vp = (struct vnode *)0;
e8540f59
KM
427 } else
428 nfs_unlock(vp);
ffe6f482 429 error = 0;
a2907882 430 nfsstats.lookupcache_misses++;
a2907882
KM
431 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
432 len = ndp->ni_namelen;
433 nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
434 nfsm_fhtom(vp);
435 nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
f5f6c13e 436 nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]);
a2907882
KM
437nfsmout:
438 if (error) {
e8540f59
KM
439 if (lockparent || (flag != CREATE && flag != RENAME) ||
440 *ndp->ni_next != 0)
441 nfs_lock(vp);
a2907882
KM
442 return (ENOENT);
443 }
444 nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
445
446 /*
447 * Handle DELETE and RENAME cases...
448 */
449 if (flag == DELETE && *ndp->ni_next == 0) {
450 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
36c3043b 451 VREF(vp);
a2907882
KM
452 newvp = vp;
453 np = VTONFS(vp);
454 } else {
455 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
e8540f59 456 nfs_lock(vp);
a2907882
KM
457 m_freem(mrep);
458 return (error);
459 }
460 newvp = NFSTOV(np);
461 }
f67785e5
KM
462 if (error =
463 nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
e8540f59 464 nfs_lock(vp);
a2907882
KM
465 if (newvp != vp)
466 nfs_nput(newvp);
467 else
36c3043b 468 vrele(vp);
a2907882
KM
469 m_freem(mrep);
470 return (error);
471 }
a2907882 472 ndp->ni_vp = newvp;
e8540f59
KM
473 if (lockparent || vp == newvp)
474 nfs_lock(vp);
a2907882
KM
475 m_freem(mrep);
476 return (0);
477 }
478
479 if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
480 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
e8540f59 481 nfs_lock(vp);
a2907882
KM
482 m_freem(mrep);
483 return (EISDIR);
484 }
485 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
e8540f59 486 nfs_lock(vp);
a2907882
KM
487 m_freem(mrep);
488 return (error);
489 }
490 newvp = NFSTOV(np);
f67785e5
KM
491 if (error =
492 nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
e8540f59 493 nfs_lock(vp);
36c3043b 494 nfs_nput(newvp);
a2907882
KM
495 m_freem(mrep);
496 return (error);
497 }
498 ndp->ni_vp = newvp;
e8540f59
KM
499 if (lockparent)
500 nfs_lock(vp);
a2907882
KM
501 return (0);
502 }
503
504 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
36c3043b 505 VREF(vp);
a2907882
KM
506 newvp = vp;
507 np = VTONFS(vp);
508 } else if (ndp->ni_isdotdot) {
a2907882
KM
509 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
510 nfs_lock(vp);
511 m_freem(mrep);
512 return (error);
513 }
a2907882
KM
514 newvp = NFSTOV(np);
515 } else {
516 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
e8540f59 517 nfs_lock(vp);
a2907882
KM
518 m_freem(mrep);
519 return (error);
520 }
521 newvp = NFSTOV(np);
522 }
f67785e5 523 if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
e8540f59 524 nfs_lock(vp);
a2907882
KM
525 if (newvp != vp)
526 nfs_nput(newvp);
527 else
36c3043b 528 vrele(vp);
a2907882
KM
529 m_freem(mrep);
530 return (error);
531 }
532 m_freem(mrep);
a2907882 533
e8540f59
KM
534 if (vp == newvp || (lockparent && *ndp->ni_next == '\0'))
535 nfs_lock(vp);
a2907882 536 ndp->ni_vp = newvp;
a2907882
KM
537 if (error == 0 && ndp->ni_makeentry)
538 cache_enter(ndp);
a2907882
KM
539 return (error);
540}
541
542/*
543 * nfs readlink call
544 */
545nfs_readlink(vp, uiop, cred)
13576453 546 register struct vnode *vp;
a2907882
KM
547 struct uio *uiop;
548 struct ucred *cred;
549{
13576453
KM
550 register u_long *p;
551 register caddr_t cp;
552 register long t1;
553 caddr_t bpos, dpos, cp2;
554 u_long xid;
555 int error = 0;
556 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
557 long len;
558
559 nfsstats.rpccnt[NFSPROC_READLINK]++;
560 nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
561 nfsm_fhtom(vp);
f5f6c13e 562 nfsm_request(vp, nonidempotent[NFSPROC_READLINK]);
a2907882
KM
563 nfsm_strsiz(len, NFS_MAXPATHLEN);
564 nfsm_mtouio(uiop, len);
565 nfsm_reqdone;
566 return (error);
567}
568
569/*
570 * nfs read call
571 */
f8428623 572nfs_readrpc(vp, uiop, cred)
13576453 573 register struct vnode *vp;
a2907882 574 struct uio *uiop;
a2907882
KM
575 struct ucred *cred;
576{
13576453
KM
577 register u_long *p;
578 register caddr_t cp;
579 register long t1;
580 caddr_t bpos, dpos, cp2;
581 u_long xid;
582 int error = 0;
583 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
584 struct nfsmount *nmp;
585 long len, retlen, tsiz;
586
587 nmp = vfs_to_nfs(vp->v_mount);
588 tsiz = uiop->uio_resid;
a2907882
KM
589 while (tsiz > 0) {
590 nfsstats.rpccnt[NFSPROC_READ]++;
591 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
592 nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
593 nfsm_fhtom(vp);
594 nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
f8428623 595 *p++ = txdr_unsigned(uiop->uio_offset);
a2907882
KM
596 *p++ = txdr_unsigned(len);
597 *p = 0;
f5f6c13e 598 nfsm_request(vp, nonidempotent[NFSPROC_READ]);
a2907882
KM
599 nfsm_loadattr(vp, (struct vattr *)0);
600 nfsm_strsiz(retlen, nmp->nm_rsize);
601 nfsm_mtouio(uiop, retlen);
602 m_freem(mrep);
a2907882
KM
603 if (retlen < len)
604 tsiz = 0;
605 else
606 tsiz -= len;
607 }
608nfsmout:
a2907882
KM
609 return (error);
610}
611
612/*
613 * nfs write call
614 */
f8428623 615nfs_writerpc(vp, uiop, cred)
13576453 616 register struct vnode *vp;
a2907882 617 struct uio *uiop;
a2907882
KM
618 struct ucred *cred;
619{
13576453
KM
620 register u_long *p;
621 register caddr_t cp;
622 register long t1;
623 caddr_t bpos, dpos;
624 u_long xid;
625 int error = 0;
626 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
627 struct nfsmount *nmp;
628 long len, tsiz;
a2907882
KM
629
630 nmp = vfs_to_nfs(vp->v_mount);
631 tsiz = uiop->uio_resid;
a2907882
KM
632 while (tsiz > 0) {
633 nfsstats.rpccnt[NFSPROC_WRITE]++;
634 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
635 nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
636 NFSX_FH+NFSX_UNSIGNED*4);
637 nfsm_fhtom(vp);
638 nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
f8428623 639 *(p+1) = txdr_unsigned(uiop->uio_offset);
a2907882
KM
640 *(p+3) = txdr_unsigned(len);
641 nfsm_uiotom(uiop, len);
f5f6c13e 642 nfsm_request(vp, nonidempotent[NFSPROC_WRITE]);
a2907882
KM
643 nfsm_loadattr(vp, (struct vattr *)0);
644 m_freem(mrep);
645 tsiz -= len;
a2907882
KM
646 }
647nfsmout:
a2907882
KM
648 return (error);
649}
650
f67785e5
KM
651/*
652 * nfs mknod call
653 * This call is currently not supported.
654 */
655/* ARGSUSED */
656nfs_mknod(ndp, vap, cred)
657 struct nameidata *ndp;
658 struct ucred *cred;
659 struct vattr *vap;
660{
661
662 nfs_abortop(ndp);
663 return (EOPNOTSUPP);
664}
665
a2907882
KM
666/*
667 * nfs file create call
668 */
669nfs_create(ndp, vap)
670 register struct nameidata *ndp;
671 register struct vattr *vap;
672{
9238aa59 673 register struct nfsv2_sattr *sp;
13576453
KM
674 register u_long *p;
675 register caddr_t cp;
676 register long t1, t2;
677 caddr_t bpos, dpos, cp2;
678 u_long xid;
679 int error = 0;
680 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
681
682 nfsstats.rpccnt[NFSPROC_CREATE]++;
683 nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
684 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
685 nfsm_fhtom(ndp->ni_dvp);
686 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
9238aa59
RM
687 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
688 sp->sa_mode = vtonfs_mode(VREG, vap->va_mode);
689 sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
690 sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
691 sp->sa_size = txdr_unsigned(0);
a2907882 692 /* or should these be VNOVAL ?? */
9238aa59
RM
693 txdr_time(&vap->va_atime, &sp->sa_atime);
694 txdr_time(&vap->va_mtime, &sp->sa_mtime);
f5f6c13e 695 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_CREATE]);
a2907882
KM
696 nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
697 nfsm_reqdone;
698 nfs_nput(ndp->ni_dvp);
699 return (error);
700}
701
702/*
703 * nfs file remove call
ffe6f482
KM
704 * To try and make nfs semantics closer to vfs semantics, a file that has
705 * other references to the vnode is renamed instead of removed and then
706 * removed later on the last close.
707 * Unfortunately you must flush the buffer cache and cmap to get rid of
708 * all extraneous vnode references before you check the reference cnt.
709 * 1 - If the file could have blocks in the buffer cache
710 * flush them out and invalidate them
711 * mpurge the vnode to flush out cmap references
712 * (This is necessary to update the vnode ref cnt as well as sensible
713 * for actual removes, to free up the buffers)
1f7e9641 714 * 2 - If v_usecount > 1
ffe6f482
KM
715 * If a rename is not already in the works
716 * call nfs_sillyrename() to set it up
717 * else
718 * do the remove rpc
a2907882
KM
719 */
720nfs_remove(ndp)
721 register struct nameidata *ndp;
722{
ffe6f482
KM
723 register struct vnode *vp = ndp->ni_vp;
724 register struct nfsnode *np = VTONFS(ndp->ni_vp);
13576453
KM
725 register u_long *p;
726 register caddr_t cp;
727 register long t1, t2;
728 caddr_t bpos, dpos;
729 u_long xid;
730 int error = 0;
731 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 732
ffe6f482
KM
733 if (vp->v_type == VREG) {
734 if (np->n_flag & (NMODIFIED|NBUFFERED)) {
735 np->n_flag &= ~(NMODIFIED|NBUFFERED);
fe53c871 736 vinvalbuf(vp, TRUE);
ffe6f482 737 }
e8540f59
KM
738 if (np->n_flag & NPAGEDON) {
739 np->n_flag &= ~NPAGEDON;
ffe6f482 740 mpurge(vp); /* In case cmap entries still ref it */
e8540f59 741 }
ffe6f482 742 }
1f7e9641 743 if (vp->v_usecount > 1) {
ffe6f482
KM
744 if (!np->n_sillyrename)
745 error = nfs_sillyrename(ndp, REMOVE);
746 } else {
a2907882
KM
747 nfsstats.rpccnt[NFSPROC_REMOVE]++;
748 nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
749 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
750 nfsm_fhtom(ndp->ni_dvp);
751 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 752 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
a2907882 753 nfsm_reqdone;
e8540f59
KM
754 /*
755 * Kludge City: If the first reply to the remove rpc is lost..
756 * the reply to the retransmitted request will be ENOENT
757 * since the file was in fact removed
758 * Therefore, we cheat and return success.
759 */
760 if (error == ENOENT)
761 error = 0;
a2907882 762 }
86dea069 763 np->n_attrstamp = 0;
f5f6c13e
KM
764 if (ndp->ni_dvp == vp)
765 vrele(vp);
a2907882 766 else
f5f6c13e
KM
767 nfs_nput(ndp->ni_dvp);
768 nfs_nput(vp);
a2907882
KM
769 return (error);
770}
771
772/*
773 * nfs file remove rpc called from nfs_inactive
774 */
775nfs_removeit(ndp)
776 register struct nameidata *ndp;
777{
13576453
KM
778 register u_long *p;
779 register caddr_t cp;
780 register long t1, t2;
781 caddr_t bpos, dpos;
782 u_long xid;
783 int error = 0;
784 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
785
786 nfsstats.rpccnt[NFSPROC_REMOVE]++;
787 nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
788 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
789 nfsm_fhtom(ndp->ni_dvp);
790 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 791 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
a2907882
KM
792 nfsm_reqdone;
793 return (error);
794}
795
796/*
797 * nfs file rename call
798 */
799nfs_rename(sndp, tndp)
800 register struct nameidata *sndp, *tndp;
801{
13576453
KM
802 register u_long *p;
803 register caddr_t cp;
804 register long t1, t2;
805 caddr_t bpos, dpos;
806 u_long xid;
807 int error = 0;
808 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
809
810 nfsstats.rpccnt[NFSPROC_RENAME]++;
811 nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
812 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
813 nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
814 nfsm_fhtom(sndp->ni_dvp);
815 nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
816 nfsm_fhtom(tndp->ni_dvp);
817 nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
f5f6c13e 818 nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
a2907882 819 nfsm_reqdone;
a2907882
KM
820 if (sndp->ni_vp->v_type == VDIR) {
821 if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
822 cache_purge(tndp->ni_dvp);
823 cache_purge(sndp->ni_dvp);
824 }
a2907882
KM
825 nfs_abortop(sndp);
826 nfs_abortop(tndp);
f5f6c13e
KM
827 /*
828 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
829 */
830 if (error == ENOENT)
831 error = 0;
a2907882
KM
832 return (error);
833}
834
835/*
836 * nfs file rename rpc called from above
837 */
838nfs_renameit(sndp, tndp)
839 register struct nameidata *sndp, *tndp;
840{
13576453
KM
841 register u_long *p;
842 register caddr_t cp;
843 register long t1, t2;
844 caddr_t bpos, dpos;
845 u_long xid;
846 int error = 0;
847 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
848
849 nfsstats.rpccnt[NFSPROC_RENAME]++;
850 nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
851 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
852 nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
853 nfsm_fhtom(sndp->ni_dvp);
854 nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
855 nfsm_fhtom(tndp->ni_dvp);
856 nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
f5f6c13e 857 nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
a2907882
KM
858 nfsm_reqdone;
859 return (error);
860}
861
862/*
863 * nfs hard link create call
864 */
865nfs_link(vp, ndp)
13576453 866 register struct vnode *vp;
a2907882
KM
867 register struct nameidata *ndp;
868{
13576453
KM
869 register u_long *p;
870 register caddr_t cp;
871 register long t1, t2;
872 caddr_t bpos, dpos;
873 u_long xid;
874 int error = 0;
875 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 876
36c3043b
KM
877 if (ndp->ni_dvp != vp)
878 nfs_lock(vp);
a2907882
KM
879 nfsstats.rpccnt[NFSPROC_LINK]++;
880 nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
881 NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
882 nfsm_fhtom(vp);
883 nfsm_fhtom(ndp->ni_dvp);
884 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 885 nfsm_request(vp, nonidempotent[NFSPROC_LINK]);
a2907882 886 nfsm_reqdone;
86dea069 887 VTONFS(vp)->n_attrstamp = 0;
36c3043b
KM
888 if (ndp->ni_dvp != vp)
889 nfs_unlock(vp);
a2907882 890 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
891 /*
892 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
893 */
894 if (error == EEXIST)
895 error = 0;
a2907882
KM
896 return (error);
897}
898
899/*
900 * nfs symbolic link create call
901 */
902nfs_symlink(ndp, vap, nm)
903 struct nameidata *ndp;
904 struct vattr *vap;
905 char *nm; /* is this the path ?? */
906{
9238aa59 907 register struct nfsv2_sattr *sp;
13576453
KM
908 register u_long *p;
909 register caddr_t cp;
910 register long t1, t2;
911 caddr_t bpos, dpos;
912 u_long xid;
913 int error = 0;
914 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
915
916 nfsstats.rpccnt[NFSPROC_SYMLINK]++;
917 nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
918 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED);
919 nfsm_fhtom(ndp->ni_dvp);
920 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
921 nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
9238aa59
RM
922 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
923 sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
924 sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
925 sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
926 sp->sa_size = txdr_unsigned(VNOVAL);
f5f6c13e 927 txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */
9238aa59 928 txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */
f5f6c13e 929 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]);
a2907882
KM
930 nfsm_reqdone;
931 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
932 /*
933 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
934 */
935 if (error == EEXIST)
936 error = 0;
a2907882
KM
937 return (error);
938}
939
940/*
941 * nfs make dir call
942 */
943nfs_mkdir(ndp, vap)
13576453 944 register struct nameidata *ndp;
a2907882
KM
945 struct vattr *vap;
946{
9238aa59 947 register struct nfsv2_sattr *sp;
13576453
KM
948 register u_long *p;
949 register caddr_t cp;
950 register long t1, t2;
951 caddr_t bpos, dpos, cp2;
952 u_long xid;
953 int error = 0;
954 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
955
956 nfsstats.rpccnt[NFSPROC_MKDIR]++;
957 nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
958 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
959 nfsm_fhtom(ndp->ni_dvp);
960 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
9238aa59
RM
961 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
962 sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
963 sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
964 sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
965 sp->sa_size = txdr_unsigned(VNOVAL);
f5f6c13e 966 txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */
9238aa59 967 txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */
f5f6c13e 968 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_MKDIR]);
a2907882
KM
969 nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
970 nfsm_reqdone;
a2907882 971 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
972 /*
973 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
974 */
975 if (error == EEXIST)
976 error = 0;
a2907882
KM
977 return (error);
978}
979
980/*
981 * nfs remove directory call
982 */
983nfs_rmdir(ndp)
984 register struct nameidata *ndp;
985{
13576453
KM
986 register u_long *p;
987 register caddr_t cp;
988 register long t1, t2;
989 caddr_t bpos, dpos;
990 u_long xid;
991 int error = 0;
992 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
993
994 if (ndp->ni_dvp == ndp->ni_vp) {
995 vrele(ndp->ni_dvp);
996 nfs_nput(ndp->ni_dvp);
997 return (EINVAL);
998 }
a2907882
KM
999 nfsstats.rpccnt[NFSPROC_RMDIR]++;
1000 nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
1001 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
1002 nfsm_fhtom(ndp->ni_dvp);
1003 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 1004 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_RMDIR]);
a2907882 1005 nfsm_reqdone;
9238aa59
RM
1006 cache_purge(ndp->ni_dvp);
1007 cache_purge(ndp->ni_vp);
9238aa59
RM
1008 nfs_nput(ndp->ni_vp);
1009 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
1010 /*
1011 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1012 */
1013 if (error == ENOENT)
1014 error = 0;
a2907882
KM
1015 return (error);
1016}
1017
1018/*
1019 * nfs readdir call
1020 * Although cookie is defined as opaque, I translate it to/from net byte
1021 * order so that it looks more sensible. This appears consistent with the
1022 * Ultrix implementation of NFS.
1023 */
f8428623 1024nfs_readdir(vp, uiop, cred)
13576453 1025 register struct vnode *vp;
a2907882 1026 struct uio *uiop;
a2907882
KM
1027 struct ucred *cred;
1028{
1029 register long len;
1030 register struct direct *dp;
13576453
KM
1031 register u_long *p;
1032 register caddr_t cp;
1033 register long t1;
1389ccec 1034 long tlen;
13576453
KM
1035 caddr_t bpos, dpos, cp2;
1036 u_long xid;
1037 int error = 0;
1038 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1039 struct mbuf *md2;
1040 caddr_t dpos2;
1041 int siz;
574a968b 1042 int more_dirs;
a2907882
KM
1043 off_t off, savoff;
1044 struct direct *savdp;
1045
a2907882
KM
1046 nfsstats.rpccnt[NFSPROC_READDIR]++;
1047 nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
1048 nfsm_fhtom(vp);
1049 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
f8428623 1050 *p++ = txdr_unsigned(uiop->uio_offset);
a2907882 1051 *p = txdr_unsigned(uiop->uio_resid);
f5f6c13e 1052 nfsm_request(vp, nonidempotent[NFSPROC_READDIR]);
a2907882
KM
1053 siz = 0;
1054 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
1055 more_dirs = fxdr_unsigned(int, *p);
1056
1057 /* Save the position so that we can do nfsm_mtouio() later */
1058 dpos2 = dpos;
1059 md2 = md;
1060
1061 /* loop thru the dir entries, doctoring them to 4bsd form */
13576453
KM
1062 savoff = off = 0;
1063 savdp = dp = NULL;
a2907882
KM
1064 while (more_dirs && siz < uiop->uio_resid) {
1065 savoff = off; /* Hold onto offset and dp */
1066 savdp = dp;
1067 nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
1068 dp = (struct direct *)p;
1069 dp->d_ino = fxdr_unsigned(u_long, *p++);
1070 len = fxdr_unsigned(int, *p);
1071 if (len <= 0 || len > NFS_MAXNAMLEN) {
1072 error = EBADRPC;
1073 m_freem(mrep);
1074 goto nfsmout;
1075 }
1076 dp->d_namlen = (u_short)len;
1389ccec
KM
1077 nfsm_adv(len); /* Point past name */
1078 tlen = nfsm_rndup(len);
1079 if (tlen != len) { /* If name not on rounded boundary */
1080 *dpos = '\0'; /* Null-terminate */
1081 nfsm_adv(tlen - len);
1082 len = tlen;
1083 }
a2907882
KM
1084 nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
1085 off = fxdr_unsigned(off_t, *p);
1086 *p++ = 0; /* Ensures null termination of name */
1087 more_dirs = fxdr_unsigned(int, *p);
1088 dp->d_reclen = len+4*NFSX_UNSIGNED;
1089 siz += dp->d_reclen;
1090 }
1091 /*
1092 * If at end of rpc data, get the eof boolean
1093 */
574a968b 1094 if (!more_dirs)
a2907882 1095 nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
a2907882
KM
1096 /*
1097 * If there is too much to fit in the data buffer, use savoff and
1098 * savdp to trim off the last record.
1099 * --> we are not at eof
1100 */
1101 if (siz > uiop->uio_resid) {
a2907882
KM
1102 off = savoff;
1103 siz -= dp->d_reclen;
1104 dp = savdp;
1105 }
1106 if (siz > 0) {
a2907882
KM
1107 md = md2;
1108 dpos = dpos2;
1109 nfsm_mtouio(uiop, siz);
f8428623 1110 uiop->uio_offset = off;
a2907882
KM
1111 }
1112 nfsm_reqdone;
a2907882
KM
1113 return (error);
1114}
1115
1116/*
1117 * nfs statfs call
1118 * (Actually a vfsop, not a vnode op)
1119 */
1120nfs_statfs(mp, sbp)
1121 struct mount *mp;
1122 register struct statfs *sbp;
1123{
13576453 1124 register struct vnode *vp;
9238aa59 1125 register struct nfsv2_statfs *sfp;
13576453
KM
1126 register caddr_t cp;
1127 register long t1;
1128 caddr_t bpos, dpos, cp2;
1129 u_long xid;
1130 int error = 0;
1131 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
9238aa59 1132 struct nfsmount *nmp;
a2907882
KM
1133 struct ucred *cred;
1134 struct nfsnode *np;
a2907882
KM
1135
1136 nmp = vfs_to_nfs(mp);
1137 if (error = nfs_nget(mp, &nmp->nm_fh, &np))
1138 return (error);
1139 vp = NFSTOV(np);
1140 nfsstats.rpccnt[NFSPROC_STATFS]++;
1141 cred = crget();
1142 cred->cr_ngroups = 1;
1143 nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
1144 nfsm_fhtom(vp);
f5f6c13e 1145 nfsm_request(vp, nonidempotent[NFSPROC_STATFS]);
9238aa59 1146 nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
a2907882 1147 sbp->f_type = MOUNT_NFS;
e8540f59 1148 sbp->f_flags = nmp->nm_flag;
9238aa59
RM
1149 sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize);
1150 sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize);
1151 sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
1152 sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
1153 sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
0b9c4686
KM
1154 sbp->f_files = 0;
1155 sbp->f_ffree = 0;
e8540f59
KM
1156 sbp->f_fsid.val[0] = mp->m_fsid.val[0];
1157 sbp->f_fsid.val[1] = mp->m_fsid.val[1];
a2907882
KM
1158 bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN);
1159 bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN);
1160 nfsm_reqdone;
1161 nfs_nput(vp);
1162 crfree(cred);
1163 return (error);
1164}
1165
13576453 1166static char hextoasc[] = "0123456789abcdef";
a2907882
KM
1167
1168/*
1169 * Silly rename. To make the NFS filesystem that is stateless look a little
1170 * more like the "ufs" a remove of an active vnode is translated to a rename
1171 * to a funny looking filename that is removed by nfs_inactive on the
1172 * nfsnode. There is the potential for another process on a different client
1173 * to create the same funny name between the nfs_lookitup() fails and the
1174 * nfs_rename() completes, but...
1175 */
1176nfs_sillyrename(ndp, flag)
13576453 1177 register struct nameidata *ndp;
a2907882
KM
1178 int flag;
1179{
1180 register struct nfsnode *np;
1181 register struct sillyrename *sp;
1182 register struct nameidata *tndp;
1183 int error;
1184 short pid;
1185
1186 np = VTONFS(ndp->ni_dvp);
ffe6f482 1187 cache_purge(ndp->ni_dvp);
a2907882 1188 MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
9238aa59 1189 M_TEMP, M_WAITOK);
a2907882
KM
1190 sp->s_flag = flag;
1191 bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
1192 np = VTONFS(ndp->ni_vp);
1193 tndp = &sp->s_namei;
1194 tndp->ni_cred = crdup(ndp->ni_cred);
1195
1196 /* Fudge together a funny name */
1197 pid = u.u_procp->p_pid;
1198 bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13);
1199 tndp->ni_dent.d_namlen = 12;
13576453
KM
1200 tndp->ni_dent.d_name[8] = hextoasc[pid & 0xf];
1201 tndp->ni_dent.d_name[7] = hextoasc[(pid >> 4) & 0xf];
1202 tndp->ni_dent.d_name[6] = hextoasc[(pid >> 8) & 0xf];
1203 tndp->ni_dent.d_name[5] = hextoasc[(pid >> 12) & 0xf];
a2907882
KM
1204
1205 /* Try lookitups until we get one that isn't there */
1206 while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) {
1207 tndp->ni_dent.d_name[4]++;
1208 if (tndp->ni_dent.d_name[4] > 'z') {
1209 error = EINVAL;
1210 goto bad;
1211 }
1212 }
1213 if (error = nfs_renameit(ndp, tndp))
1214 goto bad;
1215 nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh);
1216 np->n_sillyrename = sp;
1217 return (0);
1218bad:
9238aa59 1219 crfree(tndp->ni_cred);
a2907882
KM
1220 free((caddr_t)sp, M_TEMP);
1221 return (error);
1222}
1223
1224/*
1225 * Look up a file name for silly rename stuff.
1226 * Just like nfs_lookup() except that it doesn't load returned values
1227 * into the nfsnode table.
1228 * If fhp != NULL it copies the returned file handle out
1229 */
1230nfs_lookitup(vp, ndp, fhp)
1231 register struct vnode *vp;
1232 register struct nameidata *ndp;
1233 nfsv2fh_t *fhp;
1234{
13576453
KM
1235 register u_long *p;
1236 register caddr_t cp;
1237 register long t1, t2;
1238 caddr_t bpos, dpos, cp2;
1239 u_long xid;
1240 int error = 0;
1241 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1242 long len;
1243
1244 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1245 ndp->ni_dvp = vp;
1246 ndp->ni_vp = NULL;
1247 len = ndp->ni_dent.d_namlen;
1248 nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1249 nfsm_fhtom(vp);
1250 nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN);
f5f6c13e 1251 nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]);
a2907882
KM
1252 if (fhp != NULL) {
1253 nfsm_disect(cp, caddr_t, NFSX_FH);
1254 bcopy(cp, (caddr_t)fhp, NFSX_FH);
1255 }
1256 nfsm_reqdone;
1257 return (error);
1258}
1259
1260/*
1261 * Kludge City..
1262 * - make nfs_bmap() essentially a no-op that does no translation
1263 * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit
1264 * after mapping the physical addresses into Kernel Virtual space in the
1265 * nfsiobuf area.
1266 * (Maybe I could use the process's page mapping, but I was concerned that
1267 * Kernel Write might not be enabled and also figured copyout() would do
1268 * a lot more work than bcopy() and also it currently happens in the
1269 * context of the swapper process (2).
1270 */
1271nfs_bmap(vp, bn, vpp, bnp)
1272 struct vnode *vp;
1273 daddr_t bn;
1274 struct vnode **vpp;
1275 daddr_t *bnp;
1276{
1277 if (vpp != NULL)
1278 *vpp = vp;
1279 if (bnp != NULL)
1280 *bnp = bn * btodb(vp->v_mount->m_bsize);
1281 return (0);
1282}
1283
1284/*
9238aa59
RM
1285 * Strategy routine for phys. i/o
1286 * If the biod's are running, queue a request
1287 * otherwise just call nfs_doio() to get it done
a2907882
KM
1288 */
1289nfs_strategy(bp)
1290 register struct buf *bp;
9238aa59
RM
1291{
1292 register struct buf *dp;
ffe6f482 1293 register int i;
9238aa59
RM
1294 struct proc *rp;
1295 int error = 0;
ffe6f482 1296 int fnd = 0;
9238aa59
RM
1297
1298 /*
1299 * If an i/o daemon is waiting
1300 * queue the request, wake it up and wait for completion
1301 * otherwise just do it ourselves
1302 */
ffe6f482
KM
1303 for (i = 0; i < nfs_asyncdaemons; i++) {
1304 if (rp = nfs_iodwant[i]) {
1305 /*
1306 * Ensure that the async_daemon is still waiting here
1307 */
1308 if (rp->p_stat != SSLEEP ||
1309 rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) {
1310 nfs_iodwant[i] = (struct proc *)0;
1311 continue;
1312 }
1313 dp = &nfs_bqueue;
1314 if (dp->b_actf == NULL) {
1315 dp->b_actl = bp;
1316 bp->b_actf = dp;
1317 } else {
1318 dp->b_actf->b_actl = bp;
1319 bp->b_actf = dp->b_actf;
1320 }
1321 dp->b_actf = bp;
1322 bp->b_actl = dp;
1323 fnd++;
1324 nfs_iodwant[i] = (struct proc *)0;
1325 wakeup((caddr_t)&nfs_iodwant[i]);
1326 break;
9238aa59 1327 }
ffe6f482
KM
1328 }
1329 if (!fnd)
9238aa59
RM
1330 error = nfs_doio(bp);
1331 return (error);
1332}
1333
1334/*
1335 * Fun and games with i/o
1336 * Essentially play ubasetup() and disk interrupt service routine by
1337 * mapping the data buffer into kernel virtual space and doing the
1338 * nfs read or write rpc's from it.
1339 * If the biod's are not running, this is just called from nfs_strategy(),
1340 * otherwise it is called by the biod's to do what would normally be
1341 * partially disk interrupt driven.
1342 */
1343nfs_doio(bp)
1344 register struct buf *bp;
a2907882
KM
1345{
1346 register struct pte *pte, *ppte;
1347 register caddr_t vaddr;
1348 register struct uio *uiop;
a2907882 1349 register struct vnode *vp;
ffe6f482 1350 struct nfsnode *np;
9238aa59
RM
1351 struct ucred *cr;
1352 int npf, npf2;
1353 int reg;
1354 caddr_t vbase;
a2907882
KM
1355 unsigned v;
1356 struct proc *rp;
1357 int o, error;
a2907882
KM
1358 struct uio uio;
1359 struct iovec io;
1360
1361 vp = bp->b_vp;
a2907882
KM
1362 uiop = &uio;
1363 uiop->uio_iov = &io;
1364 uiop->uio_iovcnt = 1;
a2907882 1365 uiop->uio_segflg = UIO_SYSSPACE;
e8540f59 1366
a2907882 1367 /*
9238aa59
RM
1368 * For phys i/o, map the b_addr into kernel virtual space using
1369 * the Nfsiomap pte's
1370 * Also, add a temporary b_rcred for reading using the process's uid
1371 * and a guess at a group
a2907882 1372 */
9238aa59 1373 if (bp->b_flags & B_PHYS) {
ffe6f482 1374 VTONFS(vp)->n_flag |= NPAGEDON;
9238aa59
RM
1375 bp->b_rcred = cr = crget();
1376 rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc;
1377 cr->cr_uid = rp->p_uid;
1378 cr->cr_gid = 0; /* Anything ?? */
1379 cr->cr_ngroups = 1;
e8540f59
KM
1380 o = (int)bp->b_un.b_addr & PGOFSET;
1381 npf2 = npf = btoc(bp->b_bcount + o);
1382
9238aa59
RM
1383 /*
1384 * Get some mapping page table entries
1385 */
1386 while ((reg = rmalloc(nfsmap, (long)npf)) == 0) {
1387 nfsmap_want++;
1388 sleep((caddr_t)&nfsmap_want, PZERO-1);
1389 }
1390 reg--;
e8540f59
KM
1391 if (bp->b_flags & B_PAGET)
1392 pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
9238aa59 1393 else {
e8540f59 1394 v = btop(bp->b_un.b_addr);
9238aa59
RM
1395 if (bp->b_flags & B_UAREA)
1396 pte = &rp->p_addr[v];
1397 else
1398 pte = vtopte(rp, v);
1399 }
e8540f59 1400
9238aa59
RM
1401 /*
1402 * Play vmaccess() but with the Nfsiomap page table
1403 */
1404 ppte = &Nfsiomap[reg];
1405 vbase = vaddr = &nfsiobuf[reg*NBPG];
1406 while (npf != 0) {
1407 mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW));
a2907882 1408#if defined(tahoe)
9238aa59 1409 mtpr(P1DC, vaddr);
a2907882 1410#endif
9238aa59
RM
1411 ppte++;
1412 pte++;
1413 vaddr += NBPG;
1414 --npf;
1415 }
e8540f59
KM
1416
1417 /*
1418 * And do the i/o rpc
1419 */
9238aa59 1420 io.iov_base = vbase+o;
e8540f59 1421 io.iov_len = uiop->uio_resid = bp->b_bcount;
589be24d 1422 uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
e8540f59
KM
1423 if (bp->b_flags & B_READ) {
1424 uiop->uio_rw = UIO_READ;
1425 nfsstats.read_physios++;
1426 bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred);
1427 } else {
1428 uiop->uio_rw = UIO_WRITE;
1429 nfsstats.write_physios++;
1430 bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred);
ffe6f482 1431 }
e8540f59
KM
1432
1433 /*
1434 * Finally, release pte's used by physical i/o
1435 */
9238aa59
RM
1436 crfree(cr);
1437 rmfree(nfsmap, (long)npf2, (long)++reg);
1438 if (nfsmap_want) {
1439 nfsmap_want = 0;
1440 wakeup((caddr_t)&nfsmap_want);
1441 }
e8540f59
KM
1442 } else {
1443 if (bp->b_flags & B_READ) {
1444 io.iov_len = uiop->uio_resid = bp->b_bcount;
589be24d 1445 uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
e8540f59
KM
1446 io.iov_base = bp->b_un.b_addr;
1447 uiop->uio_rw = UIO_READ;
1448 nfsstats.read_bios++;
1449 bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred);
1450 } else {
1451 io.iov_len = uiop->uio_resid = bp->b_dirtyend
1452 - bp->b_dirtyoff;
589be24d 1453 uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
e8540f59
KM
1454 + bp->b_dirtyoff;
1455 io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
1456 uiop->uio_rw = UIO_WRITE;
1457 nfsstats.write_bios++;
1458 bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred);
1459 if (error) {
1460 np = VTONFS(vp);
1461 np->n_error = error;
1462 np->n_flag |= NWRITEERR;
1463 }
1464 bp->b_dirtyoff = bp->b_dirtyend = 0;
1465 }
9238aa59 1466 }
e8540f59
KM
1467 if (error)
1468 bp->b_flags |= B_ERROR;
1469 bp->b_resid = uiop->uio_resid;
a2907882 1470 biodone(bp);
9238aa59
RM
1471 return (error);
1472}
1473
1474/*
1475 * Flush all the blocks associated with a vnode.
1476 * Walk through the buffer pool and push any dirty pages
1477 * associated with the vnode.
1478 */
13576453 1479/* ARGSUSED */
f8428623 1480nfs_fsync(vp, fflags, cred, waitfor)
9238aa59
RM
1481 register struct vnode *vp;
1482 int fflags;
1483 struct ucred *cred;
f8428623 1484 int waitfor;
9238aa59
RM
1485{
1486 register struct nfsnode *np = VTONFS(vp);
e8540f59 1487 int error = 0;
9238aa59 1488
9238aa59
RM
1489 if (np->n_flag & NMODIFIED) {
1490 np->n_flag &= ~NMODIFIED;
e8540f59 1491 vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
9238aa59 1492 }
e8540f59
KM
1493 if (!error && (np->n_flag & NWRITEERR))
1494 error = np->n_error;
a2907882
KM
1495 return (error);
1496}
d002709d
KM
1497
1498/*
1499 * Print out the contents of an nfsnode.
1500 */
1501nfs_print(vp)
1502 struct vnode *vp;
1503{
1504 register struct nfsnode *np = VTONFS(vp);
1505
1506 printf("tag VT_NFS, fileid %d fsid 0x%x%s\n",
1507 np->n_vattr.va_fileid, np->n_vattr.va_fsid,
1508 (np->n_flag & NLOCKED) ? " (LOCKED)" : "");
1a1dbccb
KM
1509 if (np->n_lockholder == 0)
1510 return;
1511 printf("\towner pid %d", np->n_lockholder);
1512 if (np->n_lockwaiter)
1513 printf(" waiting pid %d", np->n_lockwaiter);
1514 printf("\n");
d002709d 1515}