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