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