pass indication of idempotency through to the nfsm_request routine;
[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 *
f5f6c13e 20 * @(#)nfs_vnops.c 7.26 (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"
36c3043b 36#include "../ufs/dir.h"
a2907882
KM
37#include "malloc.h"
38#include "mbuf.h"
39#include "uio.h"
40#include "ucred.h"
41#include "namei.h"
42#include "errno.h"
43#include "file.h"
44#include "conf.h"
45#include "vnode.h"
46#include "../ufs/inode.h"
9238aa59 47#include "map.h"
a2907882
KM
48#include "nfsv2.h"
49#include "nfs.h"
50#include "nfsnode.h"
51#include "nfsmount.h"
52#include "xdr_subs.h"
53#include "nfsm_subs.h"
9238aa59 54#include "nfsiom.h"
a2907882
KM
55
56/* Defs */
57#define TRUE 1
58#define FALSE 0
59
60/* Global vars */
61int nfs_lookup(),
62 nfs_create(),
f67785e5 63 nfs_mknod(),
a2907882
KM
64 nfs_open(),
65 nfs_close(),
66 nfs_access(),
67 nfs_getattr(),
68 nfs_setattr(),
69 nfs_read(),
70 nfs_write(),
71 vfs_noop(),
72 vfs_nullop(),
73 nfs_remove(),
74 nfs_link(),
75 nfs_rename(),
76 nfs_mkdir(),
77 nfs_rmdir(),
78 nfs_symlink(),
79 nfs_readdir(),
80 nfs_readlink(),
81 nfs_abortop(),
82 nfs_lock(),
83 nfs_unlock(),
84 nfs_bmap(),
85 nfs_strategy(),
9238aa59 86 nfs_fsync(),
8c7139ba 87 nfs_inactive(),
d002709d 88 nfs_reclaim(),
2bde67fd
KM
89 nfs_print(),
90 nfs_islocked();
a2907882
KM
91
92struct vnodeops nfsv2_vnodeops = {
d002709d
KM
93 nfs_lookup, /* lookup */
94 nfs_create, /* create */
95 nfs_mknod, /* mknod */
96 nfs_open, /* open */
97 nfs_close, /* close */
98 nfs_access, /* access */
99 nfs_getattr, /* getattr */
100 nfs_setattr, /* setattr */
101 nfs_read, /* read */
102 nfs_write, /* write */
103 vfs_noop, /* ioctl */
104 vfs_noop, /* select */
105 vfs_noop, /* mmap */
106 nfs_fsync, /* fsync */
107 vfs_nullop, /* seek */
108 nfs_remove, /* remove */
109 nfs_link, /* link */
110 nfs_rename, /* rename */
111 nfs_mkdir, /* mkdir */
112 nfs_rmdir, /* rmdir */
113 nfs_symlink, /* symlink */
114 nfs_readdir, /* readdir */
115 nfs_readlink, /* readlink */
116 nfs_abortop, /* abortop */
117 nfs_inactive, /* inactive */
118 nfs_reclaim, /* reclaim */
119 nfs_lock, /* lock */
120 nfs_unlock, /* unlock */
121 nfs_bmap, /* bmap */
122 nfs_strategy, /* strategy */
123 nfs_print, /* print */
2bde67fd 124 nfs_islocked, /* islocked */
a2907882
KM
125};
126
127/* Special device vnode ops */
8a1675f3
KM
128int spec_lookup(),
129 spec_open(),
130 spec_read(),
131 spec_write(),
132 spec_strategy(),
d002709d 133 spec_bmap(),
8a1675f3
KM
134 spec_ioctl(),
135 spec_select(),
136 spec_close(),
137 spec_badop(),
138 spec_nullop();
a2907882 139
8a1675f3 140struct vnodeops spec_nfsv2nodeops = {
9106dc18
KM
141 spec_lookup, /* lookup */
142 spec_badop, /* create */
143 spec_badop, /* mknod */
144 spec_open, /* open */
145 spec_close, /* close */
146 nfs_access, /* access */
147 nfs_getattr, /* getattr */
148 nfs_setattr, /* setattr */
149 spec_read, /* read */
150 spec_write, /* write */
151 spec_ioctl, /* ioctl */
152 spec_select, /* select */
153 spec_badop, /* mmap */
154 spec_nullop, /* fsync */
155 spec_badop, /* seek */
156 spec_badop, /* remove */
157 spec_badop, /* link */
158 spec_badop, /* rename */
159 spec_badop, /* mkdir */
160 spec_badop, /* rmdir */
161 spec_badop, /* symlink */
162 spec_badop, /* readdir */
163 spec_badop, /* readlink */
164 spec_badop, /* abortop */
165 nfs_inactive, /* inactive */
166 nfs_reclaim, /* reclaim */
167 nfs_lock, /* lock */
168 nfs_unlock, /* unlock */
d002709d 169 spec_bmap, /* bmap */
9106dc18 170 spec_strategy, /* strategy */
d002709d 171 nfs_print, /* print */
2bde67fd 172 nfs_islocked, /* islocked */
a2907882
KM
173};
174
175extern u_long nfs_procids[NFS_NPROCS];
176extern u_long nfs_prog, nfs_vers;
a2907882 177extern char nfsiobuf[MAXPHYS+NBPG];
f5f6c13e 178extern int nonidempotent[NFS_NPROCS];
9238aa59 179struct map nfsmap[NFS_MSIZ];
a2907882 180enum vtype v_type[NFLNK+1];
9238aa59 181struct buf nfs_bqueue; /* Queue head for nfsiod's */
ffe6f482
KM
182int nfs_asyncdaemons = 0;
183struct proc *nfs_iodwant[MAX_ASYNCDAEMON];
9238aa59 184static int nfsmap_want = 0;
a2907882
KM
185
186/*
187 * nfs null call from vfs.
188 */
189nfs_null(vp, cred)
190 struct vnode *vp;
191 struct ucred *cred;
192{
13576453
KM
193 caddr_t bpos, dpos;
194 u_long xid;
195 int error = 0;
196 struct mbuf *mreq, *mrep, *md, *mb;
a2907882
KM
197
198 nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
f5f6c13e 199 nfsm_request(vp, nonidempotent[NFSPROC_NULL]);
a2907882
KM
200 nfsm_reqdone;
201 return (error);
202}
203
204/*
205 * nfs access vnode op.
206 * Essentially just get vattr and then imitate iaccess()
207 */
208nfs_access(vp, mode, cred)
209 struct vnode *vp;
210 int mode;
211 register struct ucred *cred;
212{
213 register struct vattr *vap;
214 register gid_t *gp;
215 struct vattr vattr;
216 register int i;
217 int error;
218
219 /*
220 * If you're the super-user,
221 * you always get access.
222 */
223 if (cred->cr_uid == 0)
224 return (0);
225 vap = &vattr;
9238aa59
RM
226 if (error = nfs_getattr(vp, vap, cred))
227 return (error);
a2907882
KM
228 /*
229 * Access check is based on only one of owner, group, public.
230 * If not owner, then check group. If not a member of the
231 * group, then check public access.
232 */
233 if (cred->cr_uid != vap->va_uid) {
234 mode >>= 3;
235 gp = cred->cr_groups;
236 for (i = 0; i < cred->cr_ngroups; i++, gp++)
237 if (vap->va_gid == *gp)
238 goto found;
239 mode >>= 3;
240found:
241 ;
242 }
243 if ((vap->va_mode & mode) != 0)
244 return (0);
245 return (EACCES);
246}
247
248/*
249 * nfs open vnode op
250 * Just check to see if the type is ok
251 */
13576453 252/* ARGSUSED */
a2907882
KM
253nfs_open(vp, mode, cred)
254 struct vnode *vp;
255 int mode;
256 struct ucred *cred;
257{
258 register enum vtype vtyp;
259
260 vtyp = vp->v_type;
261 if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
262 return (0);
263 else
264 return (EACCES);
265}
266
267/*
268 * nfs close vnode op
9238aa59 269 * For reg files, invalidate any buffer cache entries.
a2907882 270 */
13576453 271/* ARGSUSED */
a2907882
KM
272nfs_close(vp, fflags, cred)
273 register struct vnode *vp;
274 int fflags;
275 struct ucred *cred;
276{
13576453 277 register struct nfsnode *np = VTONFS(vp);
ffe6f482 278 int error = 0;
a2907882 279
fe53c871 280 if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) ||
ffe6f482 281 ((np->n_flag & NBUFFERED) && np->n_sillyrename))) {
8a1675f3 282 nfs_lock(vp);
ffe6f482 283 np->n_flag &= ~(NMODIFIED|NBUFFERED);
e8540f59 284 vinvalbuf(vp, TRUE);
ffe6f482
KM
285 if (np->n_flag & NWRITEERR) {
286 np->n_flag &= ~NWRITEERR;
e8540f59 287 error = np->n_error;
ffe6f482 288 }
8a1675f3 289 nfs_unlock(vp);
9238aa59 290 }
a2907882
KM
291 return (error);
292}
293
294/*
295 * nfs getattr call from vfs.
296 */
297nfs_getattr(vp, vap, cred)
13576453
KM
298 register struct vnode *vp;
299 struct vattr *vap;
a2907882
KM
300 struct ucred *cred;
301{
13576453
KM
302 register caddr_t cp;
303 register long t1;
304 caddr_t bpos, dpos;
305 u_long xid;
306 int error = 0;
307 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
308
309 /* First look in the cache.. */
310 if (nfs_getattrcache(vp, vap) == 0)
311 return (0);
312 nfsstats.rpccnt[NFSPROC_GETATTR]++;
313 nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
314 nfsm_fhtom(vp);
f5f6c13e 315 nfsm_request(vp, nonidempotent[NFSPROC_GETATTR]);
a2907882
KM
316 nfsm_loadattr(vp, vap);
317 nfsm_reqdone;
318 return (error);
319}
320
321/*
322 * nfs setattr call.
323 */
324nfs_setattr(vp, vap, cred)
13576453 325 register struct vnode *vp;
a2907882
KM
326 register struct vattr *vap;
327 struct ucred *cred;
328{
9238aa59 329 register struct nfsv2_sattr *sp;
13576453
KM
330 register caddr_t cp;
331 register long t1;
332 caddr_t bpos, dpos;
333 u_long xid;
334 int error = 0;
335 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
00b72154 336 struct nfsnode *np;
a2907882
KM
337
338 nfsstats.rpccnt[NFSPROC_SETATTR]++;
339 nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
340 nfsm_fhtom(vp);
9238aa59 341 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
a2907882 342 if (vap->va_mode == 0xffff)
9238aa59 343 sp->sa_mode = VNOVAL;
a2907882 344 else
9238aa59 345 sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
a2907882 346 if (vap->va_uid == 0xffff)
9238aa59 347 sp->sa_uid = VNOVAL;
a2907882 348 else
9238aa59 349 sp->sa_uid = txdr_unsigned(vap->va_uid);
a2907882 350 if (vap->va_gid == 0xffff)
9238aa59 351 sp->sa_gid = VNOVAL;
a2907882 352 else
9238aa59
RM
353 sp->sa_gid = txdr_unsigned(vap->va_gid);
354 sp->sa_size = txdr_unsigned(vap->va_size);
00b72154
KM
355 if (vap->va_size != VNOVAL) {
356 np = VTONFS(vp);
357 if (np->n_flag & NMODIFIED) {
358 np->n_flag &= ~NMODIFIED;
fe53c871 359 vinvalbuf(vp, TRUE);
00b72154
KM
360 }
361 }
e8540f59
KM
362 sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
363 sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
9238aa59 364 txdr_time(&vap->va_mtime, &sp->sa_mtime);
f5f6c13e 365 nfsm_request(vp, nonidempotent[NFSPROC_SETATTR]);
a2907882
KM
366 nfsm_loadattr(vp, (struct vattr *)0);
367 /* should we fill in any vap fields ?? */
368 nfsm_reqdone;
369 return (error);
370}
371
372/*
373 * nfs lookup call, one step at a time...
374 * First look in cache
375 * If not found, unlock the directory nfsnode and do the rpc
376 */
377nfs_lookup(vp, ndp)
378 register struct vnode *vp;
379 register struct nameidata *ndp;
380{
381 register struct vnode *vdp;
13576453
KM
382 register u_long *p;
383 register caddr_t cp;
384 register long t1, t2;
385 caddr_t bpos, dpos, cp2;
386 u_long xid;
387 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
388 struct vnode *newvp;
389 long len;
390 nfsv2fh_t *fhp;
391 struct nfsnode *np;
13576453 392 int lockparent, wantparent, flag, error = 0;
a2907882
KM
393
394 ndp->ni_dvp = vp;
395 ndp->ni_vp = NULL;
396 if (vp->v_type != VDIR)
397 return (ENOTDIR);
398 lockparent = ndp->ni_nameiop & LOCKPARENT;
399 flag = ndp->ni_nameiop & OPFLAG;
400 wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
ffe6f482 401 if ((error = cache_lookup(ndp)) && error != ENOENT) {
9238aa59
RM
402 struct vattr vattr;
403 int vpid;
404
8a1675f3
KM
405 if (vp == ndp->ni_rdir && ndp->ni_isdotdot)
406 panic("nfs_lookup: .. through root");
407 vdp = ndp->ni_vp;
9238aa59 408 vpid = vdp->v_id;
a2907882 409 /*
9238aa59
RM
410 * See the comment starting `Step through' in ufs/ufs_lookup.c
411 * for an explanation of the locking protocol
a2907882
KM
412 */
413 if (vp == vdp) {
36c3043b 414 VREF(vdp);
8a1675f3 415 error = 0;
a2907882
KM
416 } else if (ndp->ni_isdotdot) {
417 nfs_unlock(vp);
8a1675f3 418 error = vget(vdp);
a2907882 419 } else {
8a1675f3 420 error = vget(vdp);
a2907882
KM
421 nfs_unlock(vp);
422 }
8a1675f3
KM
423 if (!error) {
424 if (vpid == vdp->v_id &&
425 !nfs_getattr(vdp, &vattr, ndp->ni_cred)) {
426 nfsstats.lookupcache_hits++;
427 return (0);
428 } else {
429 nfs_nput(vdp);
430 }
9238aa59 431 }
9238aa59 432 ndp->ni_vp = (struct vnode *)0;
e8540f59
KM
433 } else
434 nfs_unlock(vp);
ffe6f482 435 error = 0;
a2907882 436 nfsstats.lookupcache_misses++;
a2907882
KM
437 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
438 len = ndp->ni_namelen;
439 nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
440 nfsm_fhtom(vp);
441 nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
f5f6c13e 442 nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]);
a2907882
KM
443nfsmout:
444 if (error) {
e8540f59
KM
445 if (lockparent || (flag != CREATE && flag != RENAME) ||
446 *ndp->ni_next != 0)
447 nfs_lock(vp);
a2907882
KM
448 return (ENOENT);
449 }
450 nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
451
452 /*
453 * Handle DELETE and RENAME cases...
454 */
455 if (flag == DELETE && *ndp->ni_next == 0) {
456 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
36c3043b 457 VREF(vp);
a2907882
KM
458 newvp = vp;
459 np = VTONFS(vp);
460 } else {
461 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
e8540f59 462 nfs_lock(vp);
a2907882
KM
463 m_freem(mrep);
464 return (error);
465 }
466 newvp = NFSTOV(np);
467 }
f67785e5
KM
468 if (error =
469 nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
e8540f59 470 nfs_lock(vp);
a2907882
KM
471 if (newvp != vp)
472 nfs_nput(newvp);
473 else
36c3043b 474 vrele(vp);
a2907882
KM
475 m_freem(mrep);
476 return (error);
477 }
a2907882 478 ndp->ni_vp = newvp;
e8540f59
KM
479 if (lockparent || vp == newvp)
480 nfs_lock(vp);
a2907882
KM
481 m_freem(mrep);
482 return (0);
483 }
484
485 if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
486 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
e8540f59 487 nfs_lock(vp);
a2907882
KM
488 m_freem(mrep);
489 return (EISDIR);
490 }
491 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
e8540f59 492 nfs_lock(vp);
a2907882
KM
493 m_freem(mrep);
494 return (error);
495 }
496 newvp = NFSTOV(np);
f67785e5
KM
497 if (error =
498 nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
e8540f59 499 nfs_lock(vp);
36c3043b 500 nfs_nput(newvp);
a2907882
KM
501 m_freem(mrep);
502 return (error);
503 }
504 ndp->ni_vp = newvp;
e8540f59
KM
505 if (lockparent)
506 nfs_lock(vp);
a2907882
KM
507 return (0);
508 }
509
510 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
36c3043b 511 VREF(vp);
a2907882
KM
512 newvp = vp;
513 np = VTONFS(vp);
514 } else if (ndp->ni_isdotdot) {
a2907882
KM
515 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
516 nfs_lock(vp);
517 m_freem(mrep);
518 return (error);
519 }
a2907882
KM
520 newvp = NFSTOV(np);
521 } else {
522 if (error = nfs_nget(vp->v_mount, fhp, &np)) {
e8540f59 523 nfs_lock(vp);
a2907882
KM
524 m_freem(mrep);
525 return (error);
526 }
527 newvp = NFSTOV(np);
528 }
f67785e5 529 if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
e8540f59 530 nfs_lock(vp);
a2907882
KM
531 if (newvp != vp)
532 nfs_nput(newvp);
533 else
36c3043b 534 vrele(vp);
a2907882
KM
535 m_freem(mrep);
536 return (error);
537 }
538 m_freem(mrep);
a2907882 539
e8540f59
KM
540 if (vp == newvp || (lockparent && *ndp->ni_next == '\0'))
541 nfs_lock(vp);
a2907882 542 ndp->ni_vp = newvp;
a2907882
KM
543 if (error == 0 && ndp->ni_makeentry)
544 cache_enter(ndp);
a2907882
KM
545 return (error);
546}
547
548/*
549 * nfs readlink call
550 */
551nfs_readlink(vp, uiop, cred)
13576453 552 register struct vnode *vp;
a2907882
KM
553 struct uio *uiop;
554 struct ucred *cred;
555{
13576453
KM
556 register u_long *p;
557 register caddr_t cp;
558 register long t1;
559 caddr_t bpos, dpos, cp2;
560 u_long xid;
561 int error = 0;
562 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
563 long len;
564
565 nfsstats.rpccnt[NFSPROC_READLINK]++;
566 nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
567 nfsm_fhtom(vp);
f5f6c13e 568 nfsm_request(vp, nonidempotent[NFSPROC_READLINK]);
a2907882
KM
569 nfsm_strsiz(len, NFS_MAXPATHLEN);
570 nfsm_mtouio(uiop, len);
571 nfsm_reqdone;
572 return (error);
573}
574
575/*
576 * nfs read call
577 */
f8428623 578nfs_readrpc(vp, uiop, cred)
13576453 579 register struct vnode *vp;
a2907882 580 struct uio *uiop;
a2907882
KM
581 struct ucred *cred;
582{
13576453
KM
583 register u_long *p;
584 register caddr_t cp;
585 register long t1;
586 caddr_t bpos, dpos, cp2;
587 u_long xid;
588 int error = 0;
589 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
590 struct nfsmount *nmp;
591 long len, retlen, tsiz;
592
593 nmp = vfs_to_nfs(vp->v_mount);
594 tsiz = uiop->uio_resid;
a2907882
KM
595 while (tsiz > 0) {
596 nfsstats.rpccnt[NFSPROC_READ]++;
597 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
598 nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
599 nfsm_fhtom(vp);
600 nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
f8428623 601 *p++ = txdr_unsigned(uiop->uio_offset);
a2907882
KM
602 *p++ = txdr_unsigned(len);
603 *p = 0;
f5f6c13e 604 nfsm_request(vp, nonidempotent[NFSPROC_READ]);
a2907882
KM
605 nfsm_loadattr(vp, (struct vattr *)0);
606 nfsm_strsiz(retlen, nmp->nm_rsize);
607 nfsm_mtouio(uiop, retlen);
608 m_freem(mrep);
a2907882
KM
609 if (retlen < len)
610 tsiz = 0;
611 else
612 tsiz -= len;
613 }
614nfsmout:
a2907882
KM
615 return (error);
616}
617
618/*
619 * nfs write call
620 */
f8428623 621nfs_writerpc(vp, uiop, cred)
13576453 622 register struct vnode *vp;
a2907882 623 struct uio *uiop;
a2907882
KM
624 struct ucred *cred;
625{
13576453
KM
626 register u_long *p;
627 register caddr_t cp;
628 register long t1;
629 caddr_t bpos, dpos;
630 u_long xid;
631 int error = 0;
632 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
633 struct nfsmount *nmp;
634 long len, tsiz;
a2907882
KM
635
636 nmp = vfs_to_nfs(vp->v_mount);
637 tsiz = uiop->uio_resid;
a2907882
KM
638 while (tsiz > 0) {
639 nfsstats.rpccnt[NFSPROC_WRITE]++;
640 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
641 nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
642 NFSX_FH+NFSX_UNSIGNED*4);
643 nfsm_fhtom(vp);
644 nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
f8428623 645 *(p+1) = txdr_unsigned(uiop->uio_offset);
a2907882
KM
646 *(p+3) = txdr_unsigned(len);
647 nfsm_uiotom(uiop, len);
f5f6c13e 648 nfsm_request(vp, nonidempotent[NFSPROC_WRITE]);
a2907882
KM
649 nfsm_loadattr(vp, (struct vattr *)0);
650 m_freem(mrep);
651 tsiz -= len;
a2907882
KM
652 }
653nfsmout:
a2907882
KM
654 return (error);
655}
656
f67785e5
KM
657/*
658 * nfs mknod call
659 * This call is currently not supported.
660 */
661/* ARGSUSED */
662nfs_mknod(ndp, vap, cred)
663 struct nameidata *ndp;
664 struct ucred *cred;
665 struct vattr *vap;
666{
667
668 nfs_abortop(ndp);
669 return (EOPNOTSUPP);
670}
671
a2907882
KM
672/*
673 * nfs file create call
674 */
675nfs_create(ndp, vap)
676 register struct nameidata *ndp;
677 register struct vattr *vap;
678{
9238aa59 679 register struct nfsv2_sattr *sp;
13576453
KM
680 register u_long *p;
681 register caddr_t cp;
682 register long t1, t2;
683 caddr_t bpos, dpos, cp2;
684 u_long xid;
685 int error = 0;
686 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
687
688 nfsstats.rpccnt[NFSPROC_CREATE]++;
689 nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
690 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
691 nfsm_fhtom(ndp->ni_dvp);
692 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
9238aa59
RM
693 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
694 sp->sa_mode = vtonfs_mode(VREG, vap->va_mode);
695 sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
696 sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
697 sp->sa_size = txdr_unsigned(0);
a2907882 698 /* or should these be VNOVAL ?? */
9238aa59
RM
699 txdr_time(&vap->va_atime, &sp->sa_atime);
700 txdr_time(&vap->va_mtime, &sp->sa_mtime);
f5f6c13e 701 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_CREATE]);
a2907882
KM
702 nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
703 nfsm_reqdone;
704 nfs_nput(ndp->ni_dvp);
705 return (error);
706}
707
708/*
709 * nfs file remove call
ffe6f482
KM
710 * To try and make nfs semantics closer to vfs semantics, a file that has
711 * other references to the vnode is renamed instead of removed and then
712 * removed later on the last close.
713 * Unfortunately you must flush the buffer cache and cmap to get rid of
714 * all extraneous vnode references before you check the reference cnt.
715 * 1 - If the file could have blocks in the buffer cache
716 * flush them out and invalidate them
717 * mpurge the vnode to flush out cmap references
718 * (This is necessary to update the vnode ref cnt as well as sensible
719 * for actual removes, to free up the buffers)
1f7e9641 720 * 2 - If v_usecount > 1
ffe6f482
KM
721 * If a rename is not already in the works
722 * call nfs_sillyrename() to set it up
723 * else
724 * do the remove rpc
a2907882
KM
725 */
726nfs_remove(ndp)
727 register struct nameidata *ndp;
728{
ffe6f482
KM
729 register struct vnode *vp = ndp->ni_vp;
730 register struct nfsnode *np = VTONFS(ndp->ni_vp);
13576453
KM
731 register u_long *p;
732 register caddr_t cp;
733 register long t1, t2;
734 caddr_t bpos, dpos;
735 u_long xid;
736 int error = 0;
737 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 738
ffe6f482
KM
739 if (vp->v_type == VREG) {
740 if (np->n_flag & (NMODIFIED|NBUFFERED)) {
741 np->n_flag &= ~(NMODIFIED|NBUFFERED);
fe53c871 742 vinvalbuf(vp, TRUE);
ffe6f482 743 }
e8540f59
KM
744 if (np->n_flag & NPAGEDON) {
745 np->n_flag &= ~NPAGEDON;
ffe6f482 746 mpurge(vp); /* In case cmap entries still ref it */
e8540f59 747 }
ffe6f482 748 }
1f7e9641 749 if (vp->v_usecount > 1) {
ffe6f482
KM
750 if (!np->n_sillyrename)
751 error = nfs_sillyrename(ndp, REMOVE);
752 } else {
a2907882
KM
753 nfsstats.rpccnt[NFSPROC_REMOVE]++;
754 nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
755 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
756 nfsm_fhtom(ndp->ni_dvp);
757 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 758 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
a2907882 759 nfsm_reqdone;
e8540f59
KM
760 /*
761 * Kludge City: If the first reply to the remove rpc is lost..
762 * the reply to the retransmitted request will be ENOENT
763 * since the file was in fact removed
764 * Therefore, we cheat and return success.
765 */
766 if (error == ENOENT)
767 error = 0;
a2907882 768 }
86dea069 769 np->n_attrstamp = 0;
f5f6c13e
KM
770 if (ndp->ni_dvp == vp)
771 vrele(vp);
a2907882 772 else
f5f6c13e
KM
773 nfs_nput(ndp->ni_dvp);
774 nfs_nput(vp);
a2907882
KM
775 return (error);
776}
777
778/*
779 * nfs file remove rpc called from nfs_inactive
780 */
781nfs_removeit(ndp)
782 register struct nameidata *ndp;
783{
13576453
KM
784 register u_long *p;
785 register caddr_t cp;
786 register long t1, t2;
787 caddr_t bpos, dpos;
788 u_long xid;
789 int error = 0;
790 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
791
792 nfsstats.rpccnt[NFSPROC_REMOVE]++;
793 nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
794 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
795 nfsm_fhtom(ndp->ni_dvp);
796 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 797 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
a2907882
KM
798 nfsm_reqdone;
799 return (error);
800}
801
802/*
803 * nfs file rename call
804 */
805nfs_rename(sndp, tndp)
806 register struct nameidata *sndp, *tndp;
807{
13576453
KM
808 register u_long *p;
809 register caddr_t cp;
810 register long t1, t2;
811 caddr_t bpos, dpos;
812 u_long xid;
813 int error = 0;
814 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
815
816 nfsstats.rpccnt[NFSPROC_RENAME]++;
817 nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
818 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
819 nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
820 nfsm_fhtom(sndp->ni_dvp);
821 nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
822 nfsm_fhtom(tndp->ni_dvp);
823 nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
f5f6c13e 824 nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
a2907882 825 nfsm_reqdone;
a2907882
KM
826 if (sndp->ni_vp->v_type == VDIR) {
827 if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
828 cache_purge(tndp->ni_dvp);
829 cache_purge(sndp->ni_dvp);
830 }
a2907882
KM
831 nfs_abortop(sndp);
832 nfs_abortop(tndp);
f5f6c13e
KM
833 /*
834 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
835 */
836 if (error == ENOENT)
837 error = 0;
a2907882
KM
838 return (error);
839}
840
841/*
842 * nfs file rename rpc called from above
843 */
844nfs_renameit(sndp, tndp)
845 register struct nameidata *sndp, *tndp;
846{
13576453
KM
847 register u_long *p;
848 register caddr_t cp;
849 register long t1, t2;
850 caddr_t bpos, dpos;
851 u_long xid;
852 int error = 0;
853 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
854
855 nfsstats.rpccnt[NFSPROC_RENAME]++;
856 nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
857 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
858 nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
859 nfsm_fhtom(sndp->ni_dvp);
860 nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
861 nfsm_fhtom(tndp->ni_dvp);
862 nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
f5f6c13e 863 nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
a2907882
KM
864 nfsm_reqdone;
865 return (error);
866}
867
868/*
869 * nfs hard link create call
870 */
871nfs_link(vp, ndp)
13576453 872 register struct vnode *vp;
a2907882
KM
873 register struct nameidata *ndp;
874{
13576453
KM
875 register u_long *p;
876 register caddr_t cp;
877 register long t1, t2;
878 caddr_t bpos, dpos;
879 u_long xid;
880 int error = 0;
881 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 882
36c3043b
KM
883 if (ndp->ni_dvp != vp)
884 nfs_lock(vp);
a2907882
KM
885 nfsstats.rpccnt[NFSPROC_LINK]++;
886 nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
887 NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
888 nfsm_fhtom(vp);
889 nfsm_fhtom(ndp->ni_dvp);
890 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 891 nfsm_request(vp, nonidempotent[NFSPROC_LINK]);
a2907882 892 nfsm_reqdone;
86dea069 893 VTONFS(vp)->n_attrstamp = 0;
36c3043b
KM
894 if (ndp->ni_dvp != vp)
895 nfs_unlock(vp);
a2907882 896 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
897 /*
898 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
899 */
900 if (error == EEXIST)
901 error = 0;
a2907882
KM
902 return (error);
903}
904
905/*
906 * nfs symbolic link create call
907 */
908nfs_symlink(ndp, vap, nm)
909 struct nameidata *ndp;
910 struct vattr *vap;
911 char *nm; /* is this the path ?? */
912{
9238aa59 913 register struct nfsv2_sattr *sp;
13576453
KM
914 register u_long *p;
915 register caddr_t cp;
916 register long t1, t2;
917 caddr_t bpos, dpos;
918 u_long xid;
919 int error = 0;
920 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
921
922 nfsstats.rpccnt[NFSPROC_SYMLINK]++;
923 nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
924 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED);
925 nfsm_fhtom(ndp->ni_dvp);
926 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
927 nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
9238aa59
RM
928 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
929 sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
930 sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
931 sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
932 sp->sa_size = txdr_unsigned(VNOVAL);
f5f6c13e 933 txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */
9238aa59 934 txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */
f5f6c13e 935 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]);
a2907882
KM
936 nfsm_reqdone;
937 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
938 /*
939 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
940 */
941 if (error == EEXIST)
942 error = 0;
a2907882
KM
943 return (error);
944}
945
946/*
947 * nfs make dir call
948 */
949nfs_mkdir(ndp, vap)
13576453 950 register struct nameidata *ndp;
a2907882
KM
951 struct vattr *vap;
952{
9238aa59 953 register struct nfsv2_sattr *sp;
13576453
KM
954 register u_long *p;
955 register caddr_t cp;
956 register long t1, t2;
957 caddr_t bpos, dpos, cp2;
958 u_long xid;
959 int error = 0;
960 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
961
962 nfsstats.rpccnt[NFSPROC_MKDIR]++;
963 nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
964 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
965 nfsm_fhtom(ndp->ni_dvp);
966 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
9238aa59
RM
967 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
968 sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
969 sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
970 sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
971 sp->sa_size = txdr_unsigned(VNOVAL);
f5f6c13e 972 txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */
9238aa59 973 txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */
f5f6c13e 974 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_MKDIR]);
a2907882
KM
975 nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
976 nfsm_reqdone;
a2907882 977 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
978 /*
979 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
980 */
981 if (error == EEXIST)
982 error = 0;
a2907882
KM
983 return (error);
984}
985
986/*
987 * nfs remove directory call
988 */
989nfs_rmdir(ndp)
990 register struct nameidata *ndp;
991{
13576453
KM
992 register u_long *p;
993 register caddr_t cp;
994 register long t1, t2;
995 caddr_t bpos, dpos;
996 u_long xid;
997 int error = 0;
998 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
999
1000 if (ndp->ni_dvp == ndp->ni_vp) {
1001 vrele(ndp->ni_dvp);
1002 nfs_nput(ndp->ni_dvp);
1003 return (EINVAL);
1004 }
a2907882
KM
1005 nfsstats.rpccnt[NFSPROC_RMDIR]++;
1006 nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
1007 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
1008 nfsm_fhtom(ndp->ni_dvp);
1009 nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
f5f6c13e 1010 nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_RMDIR]);
a2907882 1011 nfsm_reqdone;
9238aa59
RM
1012 cache_purge(ndp->ni_dvp);
1013 cache_purge(ndp->ni_vp);
9238aa59
RM
1014 nfs_nput(ndp->ni_vp);
1015 nfs_nput(ndp->ni_dvp);
f5f6c13e
KM
1016 /*
1017 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1018 */
1019 if (error == ENOENT)
1020 error = 0;
a2907882
KM
1021 return (error);
1022}
1023
1024/*
1025 * nfs readdir call
1026 * Although cookie is defined as opaque, I translate it to/from net byte
1027 * order so that it looks more sensible. This appears consistent with the
1028 * Ultrix implementation of NFS.
1029 */
f8428623 1030nfs_readdir(vp, uiop, cred)
13576453 1031 register struct vnode *vp;
a2907882 1032 struct uio *uiop;
a2907882
KM
1033 struct ucred *cred;
1034{
1035 register long len;
1036 register struct direct *dp;
13576453
KM
1037 register u_long *p;
1038 register caddr_t cp;
1039 register long t1;
1040 caddr_t bpos, dpos, cp2;
1041 u_long xid;
1042 int error = 0;
1043 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1044 struct mbuf *md2;
1045 caddr_t dpos2;
1046 int siz;
574a968b 1047 int more_dirs;
a2907882
KM
1048 off_t off, savoff;
1049 struct direct *savdp;
1050
a2907882
KM
1051 nfsstats.rpccnt[NFSPROC_READDIR]++;
1052 nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
1053 nfsm_fhtom(vp);
1054 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
f8428623 1055 *p++ = txdr_unsigned(uiop->uio_offset);
a2907882 1056 *p = txdr_unsigned(uiop->uio_resid);
f5f6c13e 1057 nfsm_request(vp, nonidempotent[NFSPROC_READDIR]);
a2907882
KM
1058 siz = 0;
1059 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
1060 more_dirs = fxdr_unsigned(int, *p);
1061
1062 /* Save the position so that we can do nfsm_mtouio() later */
1063 dpos2 = dpos;
1064 md2 = md;
1065
1066 /* loop thru the dir entries, doctoring them to 4bsd form */
13576453
KM
1067 savoff = off = 0;
1068 savdp = dp = NULL;
a2907882
KM
1069 while (more_dirs && siz < uiop->uio_resid) {
1070 savoff = off; /* Hold onto offset and dp */
1071 savdp = dp;
1072 nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
1073 dp = (struct direct *)p;
1074 dp->d_ino = fxdr_unsigned(u_long, *p++);
1075 len = fxdr_unsigned(int, *p);
1076 if (len <= 0 || len > NFS_MAXNAMLEN) {
1077 error = EBADRPC;
1078 m_freem(mrep);
1079 goto nfsmout;
1080 }
1081 dp->d_namlen = (u_short)len;
1082 len = nfsm_rndup(len);
1083 nfsm_adv(len);
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}