clear hash pointers when nfsd's terminate (from Macklem)
[unix-history] / usr / src / sys / nfs / nfs_vnops.c
CommitLineData
a2907882
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
dbf0c423 8 * %sccs.include.redist.c%
a2907882 9 *
428b1f40 10 * @(#)nfs_vnops.c 7.103 (Berkeley) %G%
a2907882
KM
11 */
12
13/*
14 * vnode op calls for sun nfs version 2
15 */
16
400a1380
KM
17#include <sys/param.h>
18#include <sys/proc.h>
19#include <sys/kernel.h>
20#include <sys/systm.h>
21#include <sys/mount.h>
22#include <sys/buf.h>
23#include <sys/malloc.h>
24#include <sys/mbuf.h>
25#include <sys/conf.h>
26#include <sys/namei.h>
27#include <sys/vnode.h>
400a1380 28#include <sys/map.h>
2cf9602a 29#include <sys/dirent.h>
058dee65 30
400a1380
KM
31#include <vm/vm.h>
32
cad92b22
KM
33#include <miscfs/specfs/specdev.h>
34#include <miscfs/fifofs/fifo.h>
35
400a1380
KM
36#include <nfs/rpcv2.h>
37#include <nfs/nfsv2.h>
38#include <nfs/nfs.h>
39#include <nfs/nfsnode.h>
40#include <nfs/nfsmount.h>
41#include <nfs/xdr_subs.h>
42#include <nfs/nfsm_subs.h>
43#include <nfs/nqnfs.h>
a2907882
KM
44
45/* Defs */
46#define TRUE 1
47#define FALSE 0
48
26cb2431
KM
49/*
50 * Global vfs data structures for nfs
51 */
9342689a
JH
52int (**nfsv2_vnodeop_p)();
53struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
54 { &vop_default_desc, vn_default_error },
d40530c6
KM
55 { &vop_lookup_desc, nfs_lookup }, /* lookup */
56 { &vop_create_desc, nfs_create }, /* create */
9342689a
JH
57 { &vop_mknod_desc, nfs_mknod }, /* mknod */
58 { &vop_open_desc, nfs_open }, /* open */
59 { &vop_close_desc, nfs_close }, /* close */
d40530c6
KM
60 { &vop_access_desc, nfs_access }, /* access */
61 { &vop_getattr_desc, nfs_getattr }, /* getattr */
62 { &vop_setattr_desc, nfs_setattr }, /* setattr */
9342689a
JH
63 { &vop_read_desc, nfs_read }, /* read */
64 { &vop_write_desc, nfs_write }, /* write */
65 { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */
d40530c6 66 { &vop_select_desc, nfs_select }, /* select */
9342689a
JH
67 { &vop_mmap_desc, nfs_mmap }, /* mmap */
68 { &vop_fsync_desc, nfs_fsync }, /* fsync */
69 { &vop_seek_desc, nfs_seek }, /* seek */
d40530c6 70 { &vop_remove_desc, nfs_remove }, /* remove */
9342689a 71 { &vop_link_desc, nfs_link }, /* link */
d40530c6 72 { &vop_rename_desc, nfs_rename }, /* rename */
9342689a
JH
73 { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */
74 { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */
d40530c6
KM
75 { &vop_symlink_desc, nfs_symlink }, /* symlink */
76 { &vop_readdir_desc, nfs_readdir }, /* readdir */
77 { &vop_readlink_desc, nfs_readlink }, /* readlink */
78 { &vop_abortop_desc, nfs_abortop }, /* abortop */
79 { &vop_inactive_desc, nfs_inactive }, /* inactive */
80 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
9342689a 81 { &vop_lock_desc, nfs_lock }, /* lock */
d40530c6 82 { &vop_unlock_desc, nfs_unlock }, /* unlock */
9342689a 83 { &vop_bmap_desc, nfs_bmap }, /* bmap */
d40530c6 84 { &vop_strategy_desc, nfs_strategy }, /* strategy */
9342689a 85 { &vop_print_desc, nfs_print }, /* print */
d40530c6
KM
86 { &vop_islocked_desc, nfs_islocked }, /* islocked */
87 { &vop_advlock_desc, nfs_advlock }, /* advlock */
88 { &vop_blkatoff_desc, nfs_blkatoff }, /* blkatoff */
d40530c6 89 { &vop_valloc_desc, nfs_valloc }, /* valloc */
9342689a 90 { &vop_vfree_desc, nfs_vfree }, /* vfree */
d40530c6
KM
91 { &vop_truncate_desc, nfs_truncate }, /* truncate */
92 { &vop_update_desc, nfs_update }, /* update */
428b1f40 93 { &vop_bwrite_desc, vn_bwrite },
9342689a 94 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
a2907882 95};
9342689a
JH
96struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
97 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
a2907882 98
26cb2431
KM
99/*
100 * Special device vnode ops
101 */
9342689a
JH
102int (**spec_nfsv2nodeop_p)();
103struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
104 { &vop_default_desc, vn_default_error },
d40530c6
KM
105 { &vop_lookup_desc, spec_lookup }, /* lookup */
106 { &vop_create_desc, spec_create }, /* create */
107 { &vop_mknod_desc, spec_mknod }, /* mknod */
9342689a 108 { &vop_open_desc, spec_open }, /* open */
d40530c6 109 { &vop_close_desc, nfsspec_close }, /* close */
b330a7ec 110 { &vop_access_desc, nfsspec_access }, /* access */
d40530c6
KM
111 { &vop_getattr_desc, nfs_getattr }, /* getattr */
112 { &vop_setattr_desc, nfs_setattr }, /* setattr */
113 { &vop_read_desc, nfsspec_read }, /* read */
114 { &vop_write_desc, nfsspec_write }, /* write */
115 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
116 { &vop_select_desc, spec_select }, /* select */
9342689a 117 { &vop_mmap_desc, spec_mmap }, /* mmap */
575dc6d4 118 { &vop_fsync_desc, nfs_fsync }, /* fsync */
9342689a 119 { &vop_seek_desc, spec_seek }, /* seek */
d40530c6 120 { &vop_remove_desc, spec_remove }, /* remove */
9342689a 121 { &vop_link_desc, spec_link }, /* link */
d40530c6
KM
122 { &vop_rename_desc, spec_rename }, /* rename */
123 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
124 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
125 { &vop_symlink_desc, spec_symlink }, /* symlink */
126 { &vop_readdir_desc, spec_readdir }, /* readdir */
127 { &vop_readlink_desc, spec_readlink }, /* readlink */
128 { &vop_abortop_desc, spec_abortop }, /* abortop */
129 { &vop_inactive_desc, nfs_inactive }, /* inactive */
130 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
9342689a 131 { &vop_lock_desc, nfs_lock }, /* lock */
d40530c6 132 { &vop_unlock_desc, nfs_unlock }, /* unlock */
9342689a 133 { &vop_bmap_desc, spec_bmap }, /* bmap */
d40530c6 134 { &vop_strategy_desc, spec_strategy }, /* strategy */
9342689a 135 { &vop_print_desc, nfs_print }, /* print */
d40530c6
KM
136 { &vop_islocked_desc, nfs_islocked }, /* islocked */
137 { &vop_advlock_desc, spec_advlock }, /* advlock */
138 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
d40530c6
KM
139 { &vop_valloc_desc, spec_valloc }, /* valloc */
140 { &vop_vfree_desc, spec_vfree }, /* vfree */
141 { &vop_truncate_desc, spec_truncate }, /* truncate */
142 { &vop_update_desc, nfs_update }, /* update */
428b1f40 143 { &vop_bwrite_desc, vn_bwrite },
9342689a 144 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
a2907882 145};
9342689a
JH
146struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
147 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
a2907882 148
b2d955e4 149#ifdef FIFO
9342689a
JH
150int (**fifo_nfsv2nodeop_p)();
151struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
152 { &vop_default_desc, vn_default_error },
d40530c6
KM
153 { &vop_lookup_desc, fifo_lookup }, /* lookup */
154 { &vop_create_desc, fifo_create }, /* create */
155 { &vop_mknod_desc, fifo_mknod }, /* mknod */
9342689a 156 { &vop_open_desc, fifo_open }, /* open */
d40530c6 157 { &vop_close_desc, nfsfifo_close }, /* close */
b330a7ec 158 { &vop_access_desc, nfsspec_access }, /* access */
d40530c6
KM
159 { &vop_getattr_desc, nfs_getattr }, /* getattr */
160 { &vop_setattr_desc, nfs_setattr }, /* setattr */
161 { &vop_read_desc, nfsfifo_read }, /* read */
162 { &vop_write_desc, nfsfifo_write }, /* write */
163 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
164 { &vop_select_desc, fifo_select }, /* select */
9342689a 165 { &vop_mmap_desc, fifo_mmap }, /* mmap */
575dc6d4 166 { &vop_fsync_desc, nfs_fsync }, /* fsync */
9342689a 167 { &vop_seek_desc, fifo_seek }, /* seek */
d40530c6 168 { &vop_remove_desc, fifo_remove }, /* remove */
9342689a 169 { &vop_link_desc, fifo_link }, /* link */
d40530c6
KM
170 { &vop_rename_desc, fifo_rename }, /* rename */
171 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
172 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
173 { &vop_symlink_desc, fifo_symlink }, /* symlink */
174 { &vop_readdir_desc, fifo_readdir }, /* readdir */
175 { &vop_readlink_desc, fifo_readlink }, /* readlink */
176 { &vop_abortop_desc, fifo_abortop }, /* abortop */
177 { &vop_inactive_desc, nfs_inactive }, /* inactive */
178 { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
9342689a 179 { &vop_lock_desc, nfs_lock }, /* lock */
d40530c6 180 { &vop_unlock_desc, nfs_unlock }, /* unlock */
9342689a 181 { &vop_bmap_desc, fifo_bmap }, /* bmap */
d40530c6 182 { &vop_strategy_desc, fifo_badop }, /* strategy */
9342689a 183 { &vop_print_desc, nfs_print }, /* print */
d40530c6
KM
184 { &vop_islocked_desc, nfs_islocked }, /* islocked */
185 { &vop_advlock_desc, fifo_advlock }, /* advlock */
186 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
d40530c6
KM
187 { &vop_valloc_desc, fifo_valloc }, /* valloc */
188 { &vop_vfree_desc, fifo_vfree }, /* vfree */
189 { &vop_truncate_desc, fifo_truncate }, /* truncate */
190 { &vop_update_desc, nfs_update }, /* update */
428b1f40 191 { &vop_bwrite_desc, vn_bwrite },
9342689a 192 { (struct vnodeop_desc*)NULL, (int(*)())NULL }
b2d955e4 193};
9342689a
JH
194struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
195 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
b2d955e4
KM
196#endif /* FIFO */
197
41f343df
KM
198void nqnfs_clientlease();
199
26cb2431 200/*
2c5b44a2 201 * Global variables
26cb2431 202 */
a2907882 203extern u_long nfs_procids[NFS_NPROCS];
b330a7ec 204extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
a2907882 205extern char nfsiobuf[MAXPHYS+NBPG];
f0f1cbaa 206struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
1c89915d 207int nfs_numasync = 0;
677be99d 208/* Queue head for nfsiod's */
36c41e6e 209struct queue_entry nfs_bufq;
2cf9602a 210#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
a2907882
KM
211
212/*
213 * nfs null call from vfs.
214 */
cfef4373 215int
2c5b44a2 216nfs_null(vp, cred, procp)
a2907882
KM
217 struct vnode *vp;
218 struct ucred *cred;
2c5b44a2 219 struct proc *procp;
a2907882 220{
13576453 221 caddr_t bpos, dpos;
13576453
KM
222 int error = 0;
223 struct mbuf *mreq, *mrep, *md, *mb;
a2907882 224
2c5b44a2
KM
225 nfsm_reqhead(vp, NFSPROC_NULL, 0);
226 nfsm_request(vp, NFSPROC_NULL, procp, cred);
a2907882
KM
227 nfsm_reqdone;
228 return (error);
229}
230
231/*
232 * nfs access vnode op.
b330a7ec
KM
233 * For nfs, just return ok. File accesses may fail later.
234 * For nqnfs, use the access rpc to check accessibility. If file modes are
235 * changed on the server, accesses might still fail later.
a2907882 236 */
cfef4373 237int
d40530c6 238nfs_access(ap)
f43a11b8
KM
239 struct vop_access_args /* {
240 struct vnode *a_vp;
241 int a_mode;
242 struct ucred *a_cred;
243 struct proc *a_p;
244 } */ *ap;
a2907882 245{
b330a7ec
KM
246 register struct vnode *vp = ap->a_vp;
247 register u_long *tl;
248 register caddr_t cp;
249 caddr_t bpos, dpos;
250 int error = 0;
251 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
252
253 /*
716a55ca
KM
254 * For nqnfs, do an access rpc, otherwise you are stuck emulating
255 * ufs_access() locally using the vattr. This may not be correct,
256 * since the server may apply other access criteria such as
257 * client uid-->server uid mapping that we do not know about, but
258 * this is better than just returning anything that is lying about
259 * in the cache.
a2907882 260 */
b330a7ec
KM
261 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
262 nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
263 nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
264 nfsm_fhtom(vp);
265 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
266 if (ap->a_mode & VREAD)
267 *tl++ = nfs_true;
268 else
269 *tl++ = nfs_false;
270 if (ap->a_mode & VWRITE)
271 *tl++ = nfs_true;
272 else
273 *tl++ = nfs_false;
274 if (ap->a_mode & VEXEC)
275 *tl = nfs_true;
276 else
277 *tl = nfs_false;
278 nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
279 nfsm_reqdone;
9238aa59 280 return (error);
b330a7ec 281 } else
716a55ca 282 return (nfsspec_access(ap));
a2907882
KM
283}
284
285/*
286 * nfs open vnode op
41f343df 287 * Check to see if the type is ok
2c5b44a2 288 * and that deletion is not in progress.
41f343df
KM
289 * For paged in text files, you will need to flush the page cache
290 * if consistency is lost.
a2907882 291 */
13576453 292/* ARGSUSED */
cfef4373 293int
d40530c6 294nfs_open(ap)
f43a11b8
KM
295 struct vop_open_args /* {
296 struct vnode *a_vp;
297 int a_mode;
298 struct ucred *a_cred;
299 struct proc *a_p;
300 } */ *ap;
a2907882 301{
d40530c6 302 register struct vnode *vp = ap->a_vp;
41f343df
KM
303 struct nfsnode *np = VTONFS(vp);
304 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
305 struct vattr vattr;
306 int error;
a2907882 307
d40530c6 308 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
a2907882 309 return (EACCES);
41f343df
KM
310 if (vp->v_flag & VTEXT) {
311 /*
312 * Get a valid lease. If cached data is stale, flush it.
313 */
314 if (nmp->nm_flag & NFSMNT_NQNFS) {
315 if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
316 do {
317 error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
318 } while (error == NQNFS_EXPIRED);
319 if (error)
320 return (error);
321 if (np->n_lrev != np->n_brev) {
c33e9e8b
KM
322 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
323 ap->a_p, 1)) == EINTR)
324 return (error);
41f343df
KM
325 (void) vnode_pager_uncache(vp);
326 np->n_brev = np->n_lrev;
327 }
328 }
329 } else {
330 if (np->n_flag & NMODIFIED) {
c33e9e8b
KM
331 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
332 ap->a_p, 1)) == EINTR)
333 return (error);
41f343df
KM
334 (void) vnode_pager_uncache(vp);
335 np->n_attrstamp = 0;
336 np->n_direofoffset = 0;
337 if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
338 return (error);
339 np->n_mtime = vattr.va_mtime.ts_sec;
340 } else {
341 if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
342 return (error);
343 if (np->n_mtime != vattr.va_mtime.ts_sec) {
344 np->n_direofoffset = 0;
c33e9e8b
KM
345 if ((error = nfs_vinvalbuf(vp, V_SAVE,
346 ap->a_cred, ap->a_p, 1)) == EINTR)
347 return (error);
41f343df
KM
348 (void) vnode_pager_uncache(vp);
349 np->n_mtime = vattr.va_mtime.ts_sec;
350 }
351 }
352 }
353 } else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
354 np->n_attrstamp = 0; /* For Open/Close consistency */
2c5b44a2 355 return (0);
a2907882
KM
356}
357
358/*
359 * nfs close vnode op
9238aa59 360 * For reg files, invalidate any buffer cache entries.
a2907882 361 */
13576453 362/* ARGSUSED */
cfef4373 363int
d40530c6 364nfs_close(ap)
575dc6d4
KM
365 struct vop_close_args /* {
366 struct vnodeop_desc *a_desc;
367 struct vnode *a_vp;
368 int a_fflag;
369 struct ucred *a_cred;
370 struct proc *a_p;
371 } */ *ap;
a2907882 372{
d40530c6
KM
373 register struct vnode *vp = ap->a_vp;
374 register struct nfsnode *np = VTONFS(vp);
ffe6f482 375 int error = 0;
a2907882 376
d40530c6
KM
377 if (vp->v_type == VREG) {
378 if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
9b61ab4a 379 (np->n_flag & NMODIFIED)) {
c33e9e8b 380 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
f0f1cbaa 381 np->n_attrstamp = 0;
9b61ab4a
KM
382 }
383 if (np->n_flag & NWRITEERR) {
384 np->n_flag &= ~NWRITEERR;
385 error = np->n_error;
386 }
9238aa59 387 }
a2907882
KM
388 return (error);
389}
390
391/*
392 * nfs getattr call from vfs.
393 */
cfef4373 394int
a32db4fc 395nfs_getattr(ap)
f43a11b8
KM
396 struct vop_getattr_args /* {
397 struct vnode *a_vp;
398 struct vattr *a_vap;
399 struct ucred *a_cred;
400 struct proc *a_p;
401 } */ *ap;
a2907882 402{
a32db4fc
KM
403 register struct vnode *vp = ap->a_vp;
404 register struct nfsnode *np = VTONFS(vp);
13576453 405 register caddr_t cp;
13576453 406 caddr_t bpos, dpos;
13576453
KM
407 int error = 0;
408 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 409
a32db4fc
KM
410 /*
411 * Update local times for special files.
412 */
33092e85 413 if (np->n_flag & (NACC | NUPD))
a32db4fc 414 np->n_flag |= NCHG;
a32db4fc
KM
415 /*
416 * First look in the cache.
417 */
418 if (nfs_getattrcache(vp, ap->a_vap) == 0)
a2907882
KM
419 return (0);
420 nfsstats.rpccnt[NFSPROC_GETATTR]++;
a32db4fc
KM
421 nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
422 nfsm_fhtom(vp);
423 nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
424 nfsm_loadattr(vp, ap->a_vap);
a2907882
KM
425 nfsm_reqdone;
426 return (error);
427}
428
429/*
430 * nfs setattr call.
431 */
cfef4373 432int
d40530c6 433nfs_setattr(ap)
575dc6d4
KM
434 struct vop_setattr_args /* {
435 struct vnodeop_desc *a_desc;
436 struct vnode *a_vp;
437 struct vattr *a_vap;
438 struct ucred *a_cred;
439 struct proc *a_p;
440 } */ *ap;
a2907882 441{
9238aa59 442 register struct nfsv2_sattr *sp;
13576453
KM
443 register caddr_t cp;
444 register long t1;
2c5b44a2
KM
445 caddr_t bpos, dpos, cp2;
446 u_long *tl;
41f343df 447 int error = 0, isnq;
13576453 448 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
d40530c6
KM
449 register struct vnode *vp = ap->a_vp;
450 register struct nfsnode *np = VTONFS(vp);
451 register struct vattr *vap = ap->a_vap;
2c5b44a2 452 u_quad_t frev;
a2907882 453
c33e9e8b
KM
454 if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
455 vap->va_atime.ts_sec != VNOVAL) {
456 if (vap->va_size != VNOVAL) {
457 if (np->n_flag & NMODIFIED) {
458 if (vap->va_size == 0)
459 error = nfs_vinvalbuf(vp, 0, ap->a_cred,
460 ap->a_p, 1);
461 else
462 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
463 ap->a_p, 1);
464 if (error)
465 return (error);
466 }
467 np->n_size = np->n_vattr.va_size = vap->va_size;
468 vnode_pager_setsize(vp, (u_long)np->n_size);
469 } else if ((np->n_flag & NMODIFIED) &&
470 (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
471 ap->a_p, 1)) == EINTR)
472 return (error);
473 }
a2907882 474 nfsstats.rpccnt[NFSPROC_SETATTR]++;
41f343df
KM
475 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
476 nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
d40530c6 477 nfsm_fhtom(vp);
41f343df
KM
478 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
479 if (vap->va_mode == (u_short)-1)
9238aa59 480 sp->sa_mode = VNOVAL;
a2907882 481 else
d40530c6 482 sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
41f343df 483 if (vap->va_uid == (uid_t)-1)
9238aa59 484 sp->sa_uid = VNOVAL;
a2907882 485 else
d40530c6 486 sp->sa_uid = txdr_unsigned(vap->va_uid);
41f343df 487 if (vap->va_gid == (gid_t)-1)
9238aa59 488 sp->sa_gid = VNOVAL;
a2907882 489 else
d40530c6 490 sp->sa_gid = txdr_unsigned(vap->va_gid);
41f343df
KM
491 if (isnq) {
492 txdr_hyper(&vap->va_size, &sp->sa_nqsize);
493 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
494 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
495 sp->sa_nqflags = txdr_unsigned(vap->va_flags);
496 sp->sa_nqrdev = VNOVAL;
497 } else {
498 sp->sa_nfssize = txdr_unsigned(vap->va_size);
499 sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec);
500 sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags);
501 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
502 }
d40530c6
KM
503 nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
504 nfsm_loadattr(vp, (struct vattr *)0);
505 if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
506 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
2c5b44a2
KM
507 nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
508 fxdr_hyper(tl, &frev);
575dc6d4 509 if (frev > np->n_brev)
2c5b44a2
KM
510 np->n_brev = frev;
511 }
a2907882
KM
512 nfsm_reqdone;
513 return (error);
514}
515
516/*
517 * nfs lookup call, one step at a time...
518 * First look in cache
519 * If not found, unlock the directory nfsnode and do the rpc
520 */
cfef4373 521int
d40530c6 522nfs_lookup(ap)
575dc6d4
KM
523 struct vop_lookup_args /* {
524 struct vnodeop_desc *a_desc;
525 struct vnode *a_dvp;
526 struct vnode **a_vpp;
527 struct componentname *a_cnp;
528 } */ *ap;
a2907882 529{
d40530c6
KM
530 register struct componentname *cnp = ap->a_cnp;
531 register struct vnode *dvp = ap->a_dvp;
f43a11b8 532 register struct vnode **vpp = ap->a_vpp;
64a23bc1 533 register int flags = cnp->cn_flags;
a2907882 534 register struct vnode *vdp;
26cb2431 535 register u_long *tl;
13576453
KM
536 register caddr_t cp;
537 register long t1, t2;
2c5b44a2
KM
538 struct nfsmount *nmp;
539 struct nfsnode *tp;
13576453 540 caddr_t bpos, dpos, cp2;
2c5b44a2 541 time_t reqtime;
13576453 542 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
543 struct vnode *newvp;
544 long len;
545 nfsv2fh_t *fhp;
546 struct nfsnode *np;
cfef4373 547 int lockparent, wantparent, error = 0;
2c5b44a2
KM
548 int nqlflag, cachable;
549 u_quad_t frev;
a2907882 550
f43a11b8 551 *vpp = NULL;
d40530c6 552 if (dvp->v_type != VDIR)
a2907882 553 return (ENOTDIR);
64a23bc1
KM
554 lockparent = flags & LOCKPARENT;
555 wantparent = flags & (LOCKPARENT|WANTPARENT);
d40530c6
KM
556 nmp = VFSTONFS(dvp->v_mount);
557 np = VTONFS(dvp);
f43a11b8 558 if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
9238aa59
RM
559 struct vattr vattr;
560 int vpid;
561
f43a11b8 562 vdp = *vpp;
9238aa59 563 vpid = vdp->v_id;
a2907882 564 /*
9238aa59
RM
565 * See the comment starting `Step through' in ufs/ufs_lookup.c
566 * for an explanation of the locking protocol
a2907882 567 */
d40530c6 568 if (dvp == vdp) {
36c3043b 569 VREF(vdp);
8a1675f3 570 error = 0;
2c5b44a2 571 } else
8a1675f3 572 error = vget(vdp);
8a1675f3 573 if (!error) {
8c379a26 574 if (vpid == vdp->v_id) {
2c5b44a2 575 if (nmp->nm_flag & NFSMNT_NQNFS) {
41f343df
KM
576 if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
577 nfsstats.lookupcache_hits++;
578 if (cnp->cn_nameiop != LOOKUP &&
579 (flags & ISLASTCN))
580 cnp->cn_flags |= SAVENAME;
581 return (0);
582 } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
575dc6d4 583 if (np->n_lrev != np->n_brev ||
2c5b44a2
KM
584 (np->n_flag & NMODIFIED)) {
585 np->n_direofoffset = 0;
d40530c6 586 cache_purge(dvp);
c33e9e8b 587 error = nfs_vinvalbuf(dvp, 0,
78241003 588 cnp->cn_cred, cnp->cn_proc,
c33e9e8b
KM
589 1);
590 if (error == EINTR)
591 return (error);
2c5b44a2
KM
592 np->n_brev = np->n_lrev;
593 } else {
594 nfsstats.lookupcache_hits++;
d40530c6 595 if (cnp->cn_nameiop != LOOKUP &&
64a23bc1 596 (flags & ISLASTCN))
d40530c6 597 cnp->cn_flags |= SAVENAME;
2c5b44a2
KM
598 return (0);
599 }
600 }
d40530c6 601 } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
7e11a0c9 602 vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
8a1675f3 603 nfsstats.lookupcache_hits++;
d40530c6 604 if (cnp->cn_nameiop != LOOKUP &&
64a23bc1 605 (flags & ISLASTCN))
d40530c6 606 cnp->cn_flags |= SAVENAME;
8a1675f3 607 return (0);
8c379a26 608 }
58055488 609 cache_purge(vdp);
8a1675f3 610 }
2c5b44a2 611 vrele(vdp);
9238aa59 612 }
f43a11b8 613 *vpp = NULLVP;
2c5b44a2 614 }
ffe6f482 615 error = 0;
a2907882 616 nfsstats.lookupcache_misses++;
a2907882 617 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
d40530c6
KM
618 len = cnp->cn_namelen;
619 nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
2c5b44a2
KM
620
621 /*
622 * For nqnfs optionally piggyback a getlease request for the name
623 * being looked up.
624 */
625 if (nmp->nm_flag & NFSMNT_NQNFS) {
41f343df 626 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
2c5b44a2 627 if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
64a23bc1 628 ((cnp->cn_flags & MAKEENTRY) &&
41f343df 629 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
2c5b44a2 630 *tl = txdr_unsigned(nmp->nm_leaseterm);
41f343df 631 else
2c5b44a2 632 *tl = 0;
2c5b44a2 633 }
d40530c6
KM
634 nfsm_fhtom(dvp);
635 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
2c5b44a2 636 reqtime = time.tv_sec;
d40530c6 637 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
a2907882
KM
638nfsmout:
639 if (error) {
d40530c6 640 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
64a23bc1 641 (flags & ISLASTCN) && error == ENOENT)
44c7c48c 642 error = EJUSTRETURN;
64a23bc1 643 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
d40530c6 644 cnp->cn_flags |= SAVENAME;
b2f2eab2 645 return (error);
a2907882 646 }
2c5b44a2
KM
647 if (nmp->nm_flag & NFSMNT_NQNFS) {
648 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
649 if (*tl) {
650 nqlflag = fxdr_unsigned(int, *tl);
651 nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
652 cachable = fxdr_unsigned(int, *tl++);
653 reqtime += fxdr_unsigned(int, *tl++);
654 fxdr_hyper(tl, &frev);
655 } else
656 nqlflag = 0;
657 }
658 nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
a2907882
KM
659
660 /*
2c5b44a2 661 * Handle RENAME case...
a2907882 662 */
64a23bc1 663 if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
2c5b44a2 664 if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
a2907882
KM
665 m_freem(mrep);
666 return (EISDIR);
667 }
d40530c6 668 if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
a2907882
KM
669 m_freem(mrep);
670 return (error);
671 }
672 newvp = NFSTOV(np);
f67785e5
KM
673 if (error =
674 nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
2c5b44a2 675 vrele(newvp);
a2907882
KM
676 m_freem(mrep);
677 return (error);
678 }
f43a11b8 679 *vpp = newvp;
f5dffb64 680 m_freem(mrep);
d40530c6 681 cnp->cn_flags |= SAVENAME;
a2907882
KM
682 return (0);
683 }
684
2c5b44a2 685 if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
d40530c6
KM
686 VREF(dvp);
687 newvp = dvp;
a2907882 688 } else {
d40530c6 689 if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
a2907882
KM
690 m_freem(mrep);
691 return (error);
692 }
693 newvp = NFSTOV(np);
694 }
f67785e5 695 if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
2c5b44a2 696 vrele(newvp);
a2907882
KM
697 m_freem(mrep);
698 return (error);
699 }
700 m_freem(mrep);
f43a11b8 701 *vpp = newvp;
64a23bc1 702 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
d40530c6 703 cnp->cn_flags |= SAVENAME;
64a23bc1
KM
704 if ((cnp->cn_flags & MAKEENTRY) &&
705 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
2c5b44a2 706 if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
7e11a0c9 707 np->n_ctime = np->n_vattr.va_ctime.ts_sec;
41f343df
KM
708 else if (nqlflag && reqtime > time.tv_sec)
709 nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
710 frev);
f43a11b8 711 cache_enter(dvp, *vpp, cnp);
8c379a26 712 }
2c5b44a2 713 return (0);
a2907882
KM
714}
715
f0f1cbaa
KM
716/*
717 * nfs read call.
718 * Just call nfs_bioread() to do the work.
719 */
cfef4373 720int
d40530c6 721nfs_read(ap)
f43a11b8
KM
722 struct vop_read_args /* {
723 struct vnode *a_vp;
724 struct uio *a_uio;
725 int a_ioflag;
726 struct ucred *a_cred;
727 } */ *ap;
f0f1cbaa 728{
d40530c6
KM
729 register struct vnode *vp = ap->a_vp;
730
731 if (vp->v_type != VREG)
f0f1cbaa 732 return (EPERM);
d40530c6 733 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
f0f1cbaa
KM
734}
735
a2907882
KM
736/*
737 * nfs readlink call
738 */
cfef4373 739int
d40530c6 740nfs_readlink(ap)
f43a11b8
KM
741 struct vop_readlink_args /* {
742 struct vnode *a_vp;
743 struct uio *a_uio;
744 struct ucred *a_cred;
745 } */ *ap;
f0f1cbaa 746{
d40530c6
KM
747 register struct vnode *vp = ap->a_vp;
748
749 if (vp->v_type != VLNK)
f0f1cbaa 750 return (EPERM);
d40530c6 751 return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
f0f1cbaa
KM
752}
753
754/*
755 * Do a readlink rpc.
756 * Called by nfs_doio() from below the buffer cache.
757 */
cfef4373 758int
26cb2431 759nfs_readlinkrpc(vp, uiop, cred)
13576453 760 register struct vnode *vp;
a2907882
KM
761 struct uio *uiop;
762 struct ucred *cred;
763{
26cb2431 764 register u_long *tl;
13576453
KM
765 register caddr_t cp;
766 register long t1;
767 caddr_t bpos, dpos, cp2;
13576453
KM
768 int error = 0;
769 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
770 long len;
771
772 nfsstats.rpccnt[NFSPROC_READLINK]++;
2c5b44a2 773 nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
a2907882 774 nfsm_fhtom(vp);
2c5b44a2 775 nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
a2907882
KM
776 nfsm_strsiz(len, NFS_MAXPATHLEN);
777 nfsm_mtouio(uiop, len);
778 nfsm_reqdone;
779 return (error);
780}
781
782/*
f0f1cbaa
KM
783 * nfs read rpc call
784 * Ditto above
a2907882 785 */
cfef4373 786int
26cb2431 787nfs_readrpc(vp, uiop, cred)
13576453 788 register struct vnode *vp;
a2907882 789 struct uio *uiop;
a2907882
KM
790 struct ucred *cred;
791{
26cb2431 792 register u_long *tl;
13576453
KM
793 register caddr_t cp;
794 register long t1;
795 caddr_t bpos, dpos, cp2;
13576453
KM
796 int error = 0;
797 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
798 struct nfsmount *nmp;
799 long len, retlen, tsiz;
800
54fb9dc2 801 nmp = VFSTONFS(vp->v_mount);
a2907882 802 tsiz = uiop->uio_resid;
41f343df
KM
803 if (uiop->uio_offset + tsiz > 0xffffffff &&
804 (nmp->nm_flag & NFSMNT_NQNFS) == 0)
805 return (EFBIG);
a2907882
KM
806 while (tsiz > 0) {
807 nfsstats.rpccnt[NFSPROC_READ]++;
808 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
2c5b44a2 809 nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
a2907882 810 nfsm_fhtom(vp);
26cb2431 811 nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
41f343df
KM
812 if (nmp->nm_flag & NFSMNT_NQNFS) {
813 txdr_hyper(&uiop->uio_offset, tl);
814 *(tl + 2) = txdr_unsigned(len);
815 } else {
816 *tl++ = txdr_unsigned(uiop->uio_offset);
817 *tl++ = txdr_unsigned(len);
818 *tl = 0;
819 }
2c5b44a2 820 nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
a2907882
KM
821 nfsm_loadattr(vp, (struct vattr *)0);
822 nfsm_strsiz(retlen, nmp->nm_rsize);
823 nfsm_mtouio(uiop, retlen);
824 m_freem(mrep);
a2907882
KM
825 if (retlen < len)
826 tsiz = 0;
827 else
828 tsiz -= len;
829 }
830nfsmout:
a2907882
KM
831 return (error);
832}
833
834/*
835 * nfs write call
836 */
cfef4373 837int
41f343df 838nfs_writerpc(vp, uiop, cred, ioflags)
13576453 839 register struct vnode *vp;
a2907882 840 struct uio *uiop;
a2907882 841 struct ucred *cred;
41f343df 842 int ioflags;
a2907882 843{
26cb2431 844 register u_long *tl;
13576453
KM
845 register caddr_t cp;
846 register long t1;
2c5b44a2 847 caddr_t bpos, dpos, cp2;
13576453
KM
848 int error = 0;
849 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 850 struct nfsmount *nmp;
2c5b44a2
KM
851 struct nfsnode *np = VTONFS(vp);
852 u_quad_t frev;
a2907882 853 long len, tsiz;
a2907882 854
54fb9dc2 855 nmp = VFSTONFS(vp->v_mount);
a2907882 856 tsiz = uiop->uio_resid;
41f343df
KM
857 if (uiop->uio_offset + tsiz > 0xffffffff &&
858 (nmp->nm_flag & NFSMNT_NQNFS) == 0)
859 return (EFBIG);
a2907882
KM
860 while (tsiz > 0) {
861 nfsstats.rpccnt[NFSPROC_WRITE]++;
862 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
2c5b44a2
KM
863 nfsm_reqhead(vp, NFSPROC_WRITE,
864 NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
a2907882 865 nfsm_fhtom(vp);
41f343df
KM
866 nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
867 if (nmp->nm_flag & NFSMNT_NQNFS) {
868 txdr_hyper(&uiop->uio_offset, tl);
869 tl += 2;
870 if (ioflags & IO_APPEND)
871 *tl++ = txdr_unsigned(1);
872 else
873 *tl++ = 0;
874 } else {
875 *++tl = txdr_unsigned(uiop->uio_offset);
876 tl += 2;
877 }
878 *tl = txdr_unsigned(len);
a2907882 879 nfsm_uiotom(uiop, len);
2c5b44a2 880 nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
a2907882 881 nfsm_loadattr(vp, (struct vattr *)0);
2c5b44a2 882 if (nmp->nm_flag & NFSMNT_MYWRITE)
7e11a0c9 883 VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
2c5b44a2
KM
884 else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
885 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
886 nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
887 fxdr_hyper(tl, &frev);
575dc6d4 888 if (frev > np->n_brev)
2c5b44a2
KM
889 np->n_brev = frev;
890 }
a2907882
KM
891 m_freem(mrep);
892 tsiz -= len;
a2907882
KM
893 }
894nfsmout:
2c5b44a2
KM
895 if (error)
896 uiop->uio_resid = tsiz;
a2907882
KM
897 return (error);
898}
899
f67785e5
KM
900/*
901 * nfs mknod call
7c15c5df
KM
902 * This is a kludge. Use a create rpc but with the IFMT bits of the mode
903 * set to specify the file type and the size field for rdev.
f67785e5
KM
904 */
905/* ARGSUSED */
cfef4373 906int
d40530c6 907nfs_mknod(ap)
f43a11b8
KM
908 struct vop_mknod_args /* {
909 struct vnode *a_dvp;
910 struct vnode **a_vpp;
911 struct componentname *a_cnp;
912 struct vattr *a_vap;
913 } */ *ap;
f67785e5 914{
d40530c6
KM
915 register struct vnode *dvp = ap->a_dvp;
916 register struct vattr *vap = ap->a_vap;
917 register struct componentname *cnp = ap->a_cnp;
7c15c5df 918 register struct nfsv2_sattr *sp;
26cb2431 919 register u_long *tl;
7c15c5df 920 register caddr_t cp;
41f343df
KM
921 register long t1, t2;
922 struct vnode *newvp;
923 char *cp2;
7c15c5df 924 caddr_t bpos, dpos;
41f343df 925 int error = 0, isnq;
7c15c5df
KM
926 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
927 u_long rdev;
f67785e5 928
41f343df 929 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
d40530c6
KM
930 if (vap->va_type == VCHR || vap->va_type == VBLK)
931 rdev = txdr_unsigned(vap->va_rdev);
7c15c5df 932#ifdef FIFO
d40530c6 933 else if (vap->va_type == VFIFO)
7c15c5df
KM
934 rdev = 0xffffffff;
935#endif /* FIFO */
936 else {
d40530c6
KM
937 VOP_ABORTOP(dvp, cnp);
938 vput(dvp);
7c15c5df
KM
939 return (EOPNOTSUPP);
940 }
941 nfsstats.rpccnt[NFSPROC_CREATE]++;
d40530c6 942 nfsm_reqhead(dvp, NFSPROC_CREATE,
41f343df 943 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
d40530c6
KM
944 nfsm_fhtom(dvp);
945 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
41f343df 946 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
d40530c6
KM
947 sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
948 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
949 sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
41f343df
KM
950 if (isnq) {
951 sp->sa_nqrdev = rdev;
952 sp->sa_nqflags = 0;
953 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
954 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
955 } else {
956 sp->sa_nfssize = rdev;
957 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
958 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
959 }
d40530c6 960 nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
41f343df 961 nfsm_mtofh(dvp, newvp);
7c15c5df 962 nfsm_reqdone;
60579747 963 if (!error && (cnp->cn_flags & MAKEENTRY))
41f343df 964 cache_enter(dvp, newvp, cnp);
d40530c6
KM
965 FREE(cnp->cn_pnbuf, M_NAMEI);
966 VTONFS(dvp)->n_flag |= NMODIFIED;
967 vrele(dvp);
7c15c5df 968 return (error);
f67785e5
KM
969}
970
a2907882
KM
971/*
972 * nfs file create call
973 */
cfef4373 974int
d40530c6 975nfs_create(ap)
f43a11b8
KM
976 struct vop_create_args /* {
977 struct vnode *a_dvp;
978 struct vnode **a_vpp;
979 struct componentname *a_cnp;
980 struct vattr *a_vap;
981 } */ *ap;
a2907882 982{
d40530c6
KM
983 register struct vnode *dvp = ap->a_dvp;
984 register struct vattr *vap = ap->a_vap;
985 register struct componentname *cnp = ap->a_cnp;
9238aa59 986 register struct nfsv2_sattr *sp;
26cb2431 987 register u_long *tl;
13576453
KM
988 register caddr_t cp;
989 register long t1, t2;
990 caddr_t bpos, dpos, cp2;
41f343df 991 int error = 0, isnq;
13576453 992 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
993
994 nfsstats.rpccnt[NFSPROC_CREATE]++;
41f343df 995 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
d40530c6 996 nfsm_reqhead(dvp, NFSPROC_CREATE,
41f343df 997 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
d40530c6
KM
998 nfsm_fhtom(dvp);
999 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
41f343df 1000 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
d40530c6
KM
1001 sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
1002 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1003 sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
41f343df
KM
1004 if (isnq) {
1005 u_quad_t qval = 0;
1006
1007 txdr_hyper(&qval, &sp->sa_nqsize);
1008 sp->sa_nqflags = 0;
1009 sp->sa_nqrdev = -1;
1010 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1011 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1012 } else {
1013 sp->sa_nfssize = 0;
1014 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1015 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1016 }
d40530c6
KM
1017 nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1018 nfsm_mtofh(dvp, *ap->a_vpp);
a2907882 1019 nfsm_reqdone;
60579747 1020 if (!error && (cnp->cn_flags & MAKEENTRY))
41f343df 1021 cache_enter(dvp, *ap->a_vpp, cnp);
d40530c6
KM
1022 FREE(cnp->cn_pnbuf, M_NAMEI);
1023 VTONFS(dvp)->n_flag |= NMODIFIED;
1024 vrele(dvp);
a2907882
KM
1025 return (error);
1026}
1027
1028/*
1029 * nfs file remove call
f0f1cbaa
KM
1030 * To try and make nfs semantics closer to ufs semantics, a file that has
1031 * other processes using the vnode is renamed instead of removed and then
ffe6f482 1032 * removed later on the last close.
f0f1cbaa 1033 * - If v_usecount > 1
ffe6f482
KM
1034 * If a rename is not already in the works
1035 * call nfs_sillyrename() to set it up
1036 * else
1037 * do the remove rpc
a2907882 1038 */
cfef4373 1039int
d40530c6 1040nfs_remove(ap)
575dc6d4
KM
1041 struct vop_remove_args /* {
1042 struct vnodeop_desc *a_desc;
1043 struct vnode * a_dvp;
1044 struct vnode * a_vp;
1045 struct componentname * a_cnp;
1046 } */ *ap;
a2907882 1047{
d40530c6
KM
1048 register struct vnode *vp = ap->a_vp;
1049 register struct vnode *dvp = ap->a_dvp;
1050 register struct componentname *cnp = ap->a_cnp;
1051 register struct nfsnode *np = VTONFS(vp);
26cb2431 1052 register u_long *tl;
13576453 1053 register caddr_t cp;
2c5b44a2 1054 register long t2;
13576453 1055 caddr_t bpos, dpos;
13576453
KM
1056 int error = 0;
1057 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 1058
d40530c6 1059 if (vp->v_usecount > 1) {
ffe6f482 1060 if (!np->n_sillyrename)
d40530c6 1061 error = nfs_sillyrename(dvp, vp, cnp);
ffe6f482 1062 } else {
2c5b44a2
KM
1063 /*
1064 * Purge the name cache so that the chance of a lookup for
1065 * the name succeeding while the remove is in progress is
1066 * minimized. Without node locking it can still happen, such
1067 * that an I/O op returns ESTALE, but since you get this if
1068 * another host removes the file..
1069 */
d40530c6 1070 cache_purge(vp);
2c5b44a2
KM
1071 /*
1072 * Throw away biocache buffers. Mainly to avoid
1073 * unnecessary delayed writes.
1074 */
c33e9e8b
KM
1075 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1076 if (error == EINTR)
1077 return (error);
2c5b44a2 1078 /* Do the rpc */
a2907882 1079 nfsstats.rpccnt[NFSPROC_REMOVE]++;
d40530c6
KM
1080 nfsm_reqhead(dvp, NFSPROC_REMOVE,
1081 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1082 nfsm_fhtom(dvp);
1083 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1084 nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
a2907882 1085 nfsm_reqdone;
d40530c6
KM
1086 FREE(cnp->cn_pnbuf, M_NAMEI);
1087 VTONFS(dvp)->n_flag |= NMODIFIED;
e8540f59
KM
1088 /*
1089 * Kludge City: If the first reply to the remove rpc is lost..
1090 * the reply to the retransmitted request will be ENOENT
1091 * since the file was in fact removed
1092 * Therefore, we cheat and return success.
1093 */
1094 if (error == ENOENT)
1095 error = 0;
a2907882 1096 }
86dea069 1097 np->n_attrstamp = 0;
d40530c6
KM
1098 vrele(dvp);
1099 vrele(vp);
a2907882
KM
1100 return (error);
1101}
1102
1103/*
1104 * nfs file remove rpc called from nfs_inactive
1105 */
cfef4373 1106int
575dc6d4 1107nfs_removeit(sp)
a9b4ecb2 1108 register struct sillyrename *sp;
a2907882 1109{
26cb2431 1110 register u_long *tl;
13576453 1111 register caddr_t cp;
2c5b44a2 1112 register long t2;
13576453 1113 caddr_t bpos, dpos;
13576453
KM
1114 int error = 0;
1115 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1116
1117 nfsstats.rpccnt[NFSPROC_REMOVE]++;
2c5b44a2 1118 nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
a9b4ecb2
KM
1119 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
1120 nfsm_fhtom(sp->s_dvp);
1121 nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
575dc6d4 1122 nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
a2907882 1123 nfsm_reqdone;
a9b4ecb2 1124 VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
a2907882
KM
1125 return (error);
1126}
1127
1128/*
1129 * nfs file rename call
1130 */
cfef4373 1131int
d40530c6 1132nfs_rename(ap)
f43a11b8
KM
1133 struct vop_rename_args /* {
1134 struct vnode *a_fdvp;
1135 struct vnode *a_fvp;
1136 struct componentname *a_fcnp;
1137 struct vnode *a_tdvp;
1138 struct vnode *a_tvp;
1139 struct componentname *a_tcnp;
1140 } */ *ap;
a2907882 1141{
d40530c6
KM
1142 register struct vnode *fvp = ap->a_fvp;
1143 register struct vnode *tvp = ap->a_tvp;
1144 register struct vnode *fdvp = ap->a_fdvp;
1145 register struct vnode *tdvp = ap->a_tdvp;
1146 register struct componentname *tcnp = ap->a_tcnp;
1147 register struct componentname *fcnp = ap->a_fcnp;
26cb2431 1148 register u_long *tl;
13576453 1149 register caddr_t cp;
2c5b44a2 1150 register long t2;
13576453 1151 caddr_t bpos, dpos;
13576453
KM
1152 int error = 0;
1153 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 1154
73e2cfb7 1155 /* Check for cross-device rename */
d40530c6
KM
1156 if ((fvp->v_mount != tdvp->v_mount) ||
1157 (tvp && (fvp->v_mount != tvp->v_mount))) {
73e2cfb7
JSP
1158 error = EXDEV;
1159 goto out;
1160 }
1161
1162
a2907882 1163 nfsstats.rpccnt[NFSPROC_RENAME]++;
d40530c6
KM
1164 nfsm_reqhead(fdvp, NFSPROC_RENAME,
1165 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
1166 nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
1167 nfsm_fhtom(fdvp);
1168 nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
1169 nfsm_fhtom(tdvp);
1170 nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
1171 nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
a2907882 1172 nfsm_reqdone;
d40530c6
KM
1173 VTONFS(fdvp)->n_flag |= NMODIFIED;
1174 VTONFS(tdvp)->n_flag |= NMODIFIED;
1175 if (fvp->v_type == VDIR) {
1176 if (tvp != NULL && tvp->v_type == VDIR)
1177 cache_purge(tdvp);
1178 cache_purge(fdvp);
a2907882 1179 }
73e2cfb7 1180out:
d40530c6
KM
1181 if (tdvp == tvp)
1182 vrele(tdvp);
639383fa 1183 else
d40530c6
KM
1184 vput(tdvp);
1185 if (tvp)
1186 vput(tvp);
1187 vrele(fdvp);
1188 vrele(fvp);
f5f6c13e
KM
1189 /*
1190 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1191 */
1192 if (error == ENOENT)
1193 error = 0;
a2907882
KM
1194 return (error);
1195}
1196
1197/*
f0f1cbaa 1198 * nfs file rename rpc called from nfs_remove() above
a2907882 1199 */
cfef4373
JH
1200int
1201nfs_renameit(sdvp, scnp, sp)
1202 struct vnode *sdvp;
1203 struct componentname *scnp;
a9b4ecb2 1204 register struct sillyrename *sp;
a2907882 1205{
26cb2431 1206 register u_long *tl;
13576453 1207 register caddr_t cp;
2c5b44a2 1208 register long t2;
13576453 1209 caddr_t bpos, dpos;
13576453
KM
1210 int error = 0;
1211 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1212
1213 nfsstats.rpccnt[NFSPROC_RENAME]++;
cfef4373
JH
1214 nfsm_reqhead(sdvp, NFSPROC_RENAME,
1215 (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
2c5b44a2 1216 nfsm_rndup(sp->s_namlen));
cfef4373
JH
1217 nfsm_fhtom(sdvp);
1218 nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
1219 nfsm_fhtom(sdvp);
a9b4ecb2 1220 nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
cfef4373 1221 nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
a2907882 1222 nfsm_reqdone;
cfef4373
JH
1223 FREE(scnp->cn_pnbuf, M_NAMEI);
1224 VTONFS(sdvp)->n_flag |= NMODIFIED;
a2907882
KM
1225 return (error);
1226}
1227
1228/*
1229 * nfs hard link create call
1230 */
cfef4373 1231int
d40530c6 1232nfs_link(ap)
f43a11b8
KM
1233 struct vop_link_args /* {
1234 struct vnode *a_vp;
1235 struct vnode *a_tdvp;
1236 struct componentname *a_cnp;
1237 } */ *ap;
a2907882 1238{
d40530c6
KM
1239 register struct vnode *vp = ap->a_vp;
1240 register struct vnode *tdvp = ap->a_tdvp;
1241 register struct componentname *cnp = ap->a_cnp;
26cb2431 1242 register u_long *tl;
13576453 1243 register caddr_t cp;
2c5b44a2 1244 register long t2;
13576453 1245 caddr_t bpos, dpos;
13576453
KM
1246 int error = 0;
1247 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 1248
d40530c6
KM
1249 if (vp->v_mount != tdvp->v_mount) {
1250 /*VOP_ABORTOP(vp, cnp);*/
1251 if (tdvp == vp)
1252 vrele(vp);
73e2cfb7 1253 else
d40530c6 1254 vput(vp);
73e2cfb7
JSP
1255 return (EXDEV);
1256 }
1257
a2907882 1258 nfsstats.rpccnt[NFSPROC_LINK]++;
d40530c6
KM
1259 nfsm_reqhead(tdvp, NFSPROC_LINK,
1260 NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1261 nfsm_fhtom(tdvp);
1262 nfsm_fhtom(vp);
1263 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1264 nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
a2907882 1265 nfsm_reqdone;
d40530c6
KM
1266 FREE(cnp->cn_pnbuf, M_NAMEI);
1267 VTONFS(tdvp)->n_attrstamp = 0;
1268 VTONFS(vp)->n_flag |= NMODIFIED;
1269 vrele(vp);
f5f6c13e
KM
1270 /*
1271 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1272 */
1273 if (error == EEXIST)
1274 error = 0;
a2907882
KM
1275 return (error);
1276}
1277
1278/*
1279 * nfs symbolic link create call
1280 */
cfef4373
JH
1281/* start here */
1282int
d40530c6 1283nfs_symlink(ap)
f43a11b8
KM
1284 struct vop_symlink_args /* {
1285 struct vnode *a_dvp;
1286 struct vnode **a_vpp;
1287 struct componentname *a_cnp;
1288 struct vattr *a_vap;
1289 char *a_target;
1290 } */ *ap;
a2907882 1291{
d40530c6
KM
1292 register struct vnode *dvp = ap->a_dvp;
1293 register struct vattr *vap = ap->a_vap;
1294 register struct componentname *cnp = ap->a_cnp;
9238aa59 1295 register struct nfsv2_sattr *sp;
26cb2431 1296 register u_long *tl;
13576453 1297 register caddr_t cp;
2c5b44a2 1298 register long t2;
13576453 1299 caddr_t bpos, dpos;
41f343df 1300 int slen, error = 0, isnq;
13576453 1301 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1302
1303 nfsstats.rpccnt[NFSPROC_SYMLINK]++;
e1b76915 1304 slen = strlen(ap->a_target);
41f343df 1305 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
d40530c6 1306 nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
41f343df 1307 nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
d40530c6
KM
1308 nfsm_fhtom(dvp);
1309 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
e1b76915 1310 nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
41f343df 1311 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
d40530c6
KM
1312 sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
1313 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1314 sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
41f343df
KM
1315 if (isnq) {
1316 quad_t qval = -1;
1317
1318 txdr_hyper(&qval, &sp->sa_nqsize);
1319 sp->sa_nqflags = 0;
1320 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1321 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1322 } else {
1323 sp->sa_nfssize = -1;
1324 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1325 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1326 }
d40530c6 1327 nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
a2907882 1328 nfsm_reqdone;
d40530c6
KM
1329 FREE(cnp->cn_pnbuf, M_NAMEI);
1330 VTONFS(dvp)->n_flag |= NMODIFIED;
1331 vrele(dvp);
f5f6c13e
KM
1332 /*
1333 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1334 */
1335 if (error == EEXIST)
1336 error = 0;
a2907882
KM
1337 return (error);
1338}
1339
1340/*
1341 * nfs make dir call
1342 */
cfef4373 1343int
d40530c6 1344nfs_mkdir(ap)
f43a11b8
KM
1345 struct vop_mkdir_args /* {
1346 struct vnode *a_dvp;
1347 struct vnode **a_vpp;
1348 struct componentname *a_cnp;
1349 struct vattr *a_vap;
1350 } */ *ap;
a2907882 1351{
d40530c6
KM
1352 register struct vnode *dvp = ap->a_dvp;
1353 register struct vattr *vap = ap->a_vap;
1354 register struct componentname *cnp = ap->a_cnp;
f43a11b8 1355 register struct vnode **vpp = ap->a_vpp;
9238aa59 1356 register struct nfsv2_sattr *sp;
26cb2431 1357 register u_long *tl;
13576453
KM
1358 register caddr_t cp;
1359 register long t1, t2;
f0f1cbaa 1360 register int len;
13576453 1361 caddr_t bpos, dpos, cp2;
41f343df 1362 int error = 0, firsttry = 1, isnq;
13576453 1363 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 1364
d40530c6 1365 len = cnp->cn_namelen;
41f343df 1366 isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
a2907882 1367 nfsstats.rpccnt[NFSPROC_MKDIR]++;
d40530c6 1368 nfsm_reqhead(dvp, NFSPROC_MKDIR,
41f343df 1369 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
d40530c6
KM
1370 nfsm_fhtom(dvp);
1371 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
41f343df 1372 nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
d40530c6
KM
1373 sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
1374 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1375 sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
41f343df
KM
1376 if (isnq) {
1377 quad_t qval = -1;
1378
1379 txdr_hyper(&qval, &sp->sa_nqsize);
1380 sp->sa_nqflags = 0;
1381 txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1382 txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1383 } else {
1384 sp->sa_nfssize = -1;
1385 txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1386 txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1387 }
d40530c6 1388 nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
f43a11b8 1389 nfsm_mtofh(dvp, *vpp);
a2907882 1390 nfsm_reqdone;
d40530c6 1391 VTONFS(dvp)->n_flag |= NMODIFIED;
f5f6c13e 1392 /*
f0f1cbaa
KM
1393 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1394 * if we can succeed in looking up the directory.
1395 * "firsttry" is necessary since the macros may "goto nfsmout" which
1396 * is above the if on errors. (Ugh)
f5f6c13e 1397 */
f0f1cbaa
KM
1398 if (error == EEXIST && firsttry) {
1399 firsttry = 0;
f5f6c13e 1400 error = 0;
f0f1cbaa 1401 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
f43a11b8 1402 *vpp = NULL;
d40530c6 1403 nfsm_reqhead(dvp, NFSPROC_LOOKUP,
f0f1cbaa 1404 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
d40530c6
KM
1405 nfsm_fhtom(dvp);
1406 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1407 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
f43a11b8
KM
1408 nfsm_mtofh(dvp, *vpp);
1409 if ((*vpp)->v_type != VDIR) {
1410 vput(*vpp);
f0f1cbaa
KM
1411 error = EEXIST;
1412 }
1413 m_freem(mrep);
1414 }
d40530c6
KM
1415 FREE(cnp->cn_pnbuf, M_NAMEI);
1416 vrele(dvp);
a2907882
KM
1417 return (error);
1418}
1419
1420/*
1421 * nfs remove directory call
1422 */
cfef4373 1423int
d40530c6 1424nfs_rmdir(ap)
f43a11b8
KM
1425 struct vop_rmdir_args /* {
1426 struct vnode *a_dvp;
1427 struct vnode *a_vp;
1428 struct componentname *a_cnp;
1429 } */ *ap;
a2907882 1430{
d40530c6
KM
1431 register struct vnode *vp = ap->a_vp;
1432 register struct vnode *dvp = ap->a_dvp;
1433 register struct componentname *cnp = ap->a_cnp;
26cb2431 1434 register u_long *tl;
13576453 1435 register caddr_t cp;
2c5b44a2 1436 register long t2;
13576453 1437 caddr_t bpos, dpos;
13576453
KM
1438 int error = 0;
1439 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882 1440
d40530c6
KM
1441 if (dvp == vp) {
1442 vrele(dvp);
1443 vrele(dvp);
1444 FREE(cnp->cn_pnbuf, M_NAMEI);
a2907882
KM
1445 return (EINVAL);
1446 }
a2907882 1447 nfsstats.rpccnt[NFSPROC_RMDIR]++;
d40530c6
KM
1448 nfsm_reqhead(dvp, NFSPROC_RMDIR,
1449 NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1450 nfsm_fhtom(dvp);
1451 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1452 nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
a2907882 1453 nfsm_reqdone;
d40530c6
KM
1454 FREE(cnp->cn_pnbuf, M_NAMEI);
1455 VTONFS(dvp)->n_flag |= NMODIFIED;
1456 cache_purge(dvp);
1457 cache_purge(vp);
1458 vrele(vp);
1459 vrele(dvp);
f5f6c13e
KM
1460 /*
1461 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1462 */
1463 if (error == ENOENT)
1464 error = 0;
a2907882
KM
1465 return (error);
1466}
1467
1468/*
1469 * nfs readdir call
1470 * Although cookie is defined as opaque, I translate it to/from net byte
1471 * order so that it looks more sensible. This appears consistent with the
1472 * Ultrix implementation of NFS.
1473 */
cfef4373 1474int
d40530c6 1475nfs_readdir(ap)
f43a11b8
KM
1476 struct vop_readdir_args /* {
1477 struct vnode *a_vp;
1478 struct uio *a_uio;
1479 struct ucred *a_cred;
1480 } */ *ap;
f0f1cbaa 1481{
d40530c6
KM
1482 register struct vnode *vp = ap->a_vp;
1483 register struct nfsnode *np = VTONFS(vp);
1484 register struct uio *uio = ap->a_uio;
f0f1cbaa
KM
1485 int tresid, error;
1486 struct vattr vattr;
1487
d40530c6 1488 if (vp->v_type != VDIR)
f0f1cbaa
KM
1489 return (EPERM);
1490 /*
1491 * First, check for hit on the EOF offset cache
1492 */
d40530c6 1493 if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
2c5b44a2 1494 (np->n_flag & NMODIFIED) == 0) {
d40530c6
KM
1495 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
1496 if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
2c5b44a2
KM
1497 nfsstats.direofcache_hits++;
1498 return (0);
1499 }
d40530c6 1500 } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
7e11a0c9 1501 np->n_mtime == vattr.va_mtime.ts_sec) {
2c5b44a2
KM
1502 nfsstats.direofcache_hits++;
1503 return (0);
1504 }
f0f1cbaa
KM
1505 }
1506
1507 /*
1508 * Call nfs_bioread() to do the real work.
1509 */
d40530c6
KM
1510 tresid = uio->uio_resid;
1511 error = nfs_bioread(vp, uio, 0, ap->a_cred);
f0f1cbaa 1512
575dc6d4 1513 if (!error && uio->uio_resid == tresid)
f0f1cbaa 1514 nfsstats.direofcache_misses++;
f0f1cbaa
KM
1515 return (error);
1516}
1517
1518/*
1519 * Readdir rpc call.
1520 * Called from below the buffer cache by nfs_doio().
1521 */
cfef4373 1522int
26cb2431 1523nfs_readdirrpc(vp, uiop, cred)
f0f1cbaa
KM
1524 register struct vnode *vp;
1525 struct uio *uiop;
1526 struct ucred *cred;
a2907882
KM
1527{
1528 register long len;
2cf9602a 1529 register struct dirent *dp;
26cb2431 1530 register u_long *tl;
13576453
KM
1531 register caddr_t cp;
1532 register long t1;
f0f1cbaa 1533 long tlen, lastlen;
13576453 1534 caddr_t bpos, dpos, cp2;
13576453
KM
1535 int error = 0;
1536 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1537 struct mbuf *md2;
1538 caddr_t dpos2;
1539 int siz;
e49b1a6c 1540 int more_dirs = 1;
41f343df 1541 u_long off, savoff;
2cf9602a 1542 struct dirent *savdp;
e49b1a6c
KM
1543 struct nfsmount *nmp;
1544 struct nfsnode *np = VTONFS(vp);
1545 long tresid;
a2907882 1546
54fb9dc2 1547 nmp = VFSTONFS(vp->v_mount);
e49b1a6c 1548 tresid = uiop->uio_resid;
a2907882 1549 /*
e49b1a6c 1550 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
26cb2431 1551 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
f0f1cbaa 1552 * The stopping criteria is EOF or buffer full.
a2907882 1553 */
26cb2431 1554 while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
e49b1a6c 1555 nfsstats.rpccnt[NFSPROC_READDIR]++;
2c5b44a2 1556 nfsm_reqhead(vp, NFSPROC_READDIR,
41f343df 1557 NFSX_FH + 2 * NFSX_UNSIGNED);
e49b1a6c 1558 nfsm_fhtom(vp);
41f343df
KM
1559 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1560 off = (u_long)uiop->uio_offset;
1561 *tl++ = txdr_unsigned(off);
26cb2431
KM
1562 *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1563 nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
2c5b44a2 1564 nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
e49b1a6c 1565 siz = 0;
2c5b44a2 1566 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
26cb2431 1567 more_dirs = fxdr_unsigned(int, *tl);
e49b1a6c
KM
1568
1569 /* Save the position so that we can do nfsm_mtouio() later */
1570 dpos2 = dpos;
1571 md2 = md;
1572
1573 /* loop thru the dir entries, doctoring them to 4bsd form */
7c15c5df 1574#ifdef lint
2cf9602a 1575 dp = (struct dirent *)0;
7c15c5df 1576#endif /* lint */
e49b1a6c
KM
1577 while (more_dirs && siz < uiop->uio_resid) {
1578 savoff = off; /* Hold onto offset and dp */
1579 savdp = dp;
41f343df 1580 nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
2cf9602a
KM
1581 dp = (struct dirent *)tl;
1582 dp->d_fileno = fxdr_unsigned(u_long, *tl++);
26cb2431 1583 len = fxdr_unsigned(int, *tl);
e49b1a6c
KM
1584 if (len <= 0 || len > NFS_MAXNAMLEN) {
1585 error = EBADRPC;
1586 m_freem(mrep);
1587 goto nfsmout;
1588 }
36a0d247
KM
1589 dp->d_namlen = (u_char)len;
1590 dp->d_type = DT_UNKNOWN;
e49b1a6c
KM
1591 nfsm_adv(len); /* Point past name */
1592 tlen = nfsm_rndup(len);
1593 /*
1594 * This should not be necessary, but some servers have
1595 * broken XDR such that these bytes are not null filled.
1596 */
1597 if (tlen != len) {
1598 *dpos = '\0'; /* Null-terminate */
1599 nfsm_adv(tlen - len);
1600 len = tlen;
1601 }
41f343df 1602 nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
36a0d247 1603 off = fxdr_unsigned(u_long, *tl);
26cb2431
KM
1604 *tl++ = 0; /* Ensures null termination of name */
1605 more_dirs = fxdr_unsigned(int, *tl);
41f343df 1606 dp->d_reclen = len + 4 * NFSX_UNSIGNED;
e49b1a6c
KM
1607 siz += dp->d_reclen;
1608 }
1609 /*
1610 * If at end of rpc data, get the eof boolean
1611 */
1612 if (!more_dirs) {
2c5b44a2 1613 nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
26cb2431 1614 more_dirs = (fxdr_unsigned(int, *tl) == 0);
e49b1a6c
KM
1615
1616 /*
1617 * If at EOF, cache directory offset
1618 */
f0f1cbaa 1619 if (!more_dirs)
e49b1a6c 1620 np->n_direofoffset = off;
e49b1a6c
KM
1621 }
1622 /*
1623 * If there is too much to fit in the data buffer, use savoff and
1624 * savdp to trim off the last record.
1625 * --> we are not at eof
1626 */
1627 if (siz > uiop->uio_resid) {
1628 off = savoff;
1629 siz -= dp->d_reclen;
1630 dp = savdp;
1631 more_dirs = 0; /* Paranoia */
1632 }
1633 if (siz > 0) {
f0f1cbaa 1634 lastlen = dp->d_reclen;
e49b1a6c
KM
1635 md = md2;
1636 dpos = dpos2;
1637 nfsm_mtouio(uiop, siz);
41f343df 1638 uiop->uio_offset = (off_t)off;
e49b1a6c
KM
1639 } else
1640 more_dirs = 0; /* Ugh, never happens, but in case.. */
1641 m_freem(mrep);
a2907882 1642 }
f0f1cbaa 1643 /*
26cb2431 1644 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
f0f1cbaa
KM
1645 * by increasing d_reclen for the last record.
1646 */
1647 if (uiop->uio_resid < tresid) {
26cb2431 1648 len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
f0f1cbaa 1649 if (len > 0) {
2cf9602a 1650 dp = (struct dirent *)
f0f1cbaa
KM
1651 (uiop->uio_iov->iov_base - lastlen);
1652 dp->d_reclen += len;
1653 uiop->uio_iov->iov_base += len;
1654 uiop->uio_iov->iov_len -= len;
1655 uiop->uio_resid -= len;
1656 }
c79a85cd 1657 }
f0f1cbaa 1658nfsmout:
a2907882
KM
1659 return (error);
1660}
1661
2c5b44a2 1662/*
41f343df 1663 * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
2c5b44a2 1664 */
cfef4373 1665int
2c5b44a2
KM
1666nfs_readdirlookrpc(vp, uiop, cred)
1667 struct vnode *vp;
1668 register struct uio *uiop;
1669 struct ucred *cred;
1670{
1671 register int len;
2cf9602a 1672 register struct dirent *dp;
2c5b44a2
KM
1673 register u_long *tl;
1674 register caddr_t cp;
1675 register long t1;
1676 caddr_t bpos, dpos, cp2;
1677 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1678 struct nameidata nami, *ndp = &nami;
c5b4f497 1679 struct componentname *cnp = &ndp->ni_cnd;
41f343df 1680 u_long off, endoff, fileno;
2c5b44a2
KM
1681 time_t reqtime, ltime;
1682 struct nfsmount *nmp;
1683 struct nfsnode *np, *tp;
1684 struct vnode *newvp;
1685 nfsv2fh_t *fhp;
2c5b44a2
KM
1686 u_quad_t frev;
1687 int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
1688 int cachable;
1689
1690 if (uiop->uio_iovcnt != 1)
1691 panic("nfs rdirlook");
1692 nmp = VFSTONFS(vp->v_mount);
1693 tresid = uiop->uio_resid;
1694 ndp->ni_dvp = vp;
1695 newvp = NULLVP;
1696 /*
1697 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
1698 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
1699 * The stopping criteria is EOF or buffer full.
1700 */
1701 while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
1702 nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
1703 nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
41f343df 1704 NFSX_FH + 3 * NFSX_UNSIGNED);
2c5b44a2 1705 nfsm_fhtom(vp);
41f343df
KM
1706 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
1707 off = (u_long)uiop->uio_offset;
1708 *tl++ = txdr_unsigned(off);
2c5b44a2
KM
1709 *tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1710 nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
41f343df
KM
1711 if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
1712 *tl = txdr_unsigned(nmp->nm_leaseterm);
1713 else
1714 *tl = 0;
2c5b44a2
KM
1715 reqtime = time.tv_sec;
1716 nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
1717 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1718 more_dirs = fxdr_unsigned(int, *tl);
1719
1720 /* loop thru the dir entries, doctoring them to 4bsd form */
2c5b44a2
KM
1721 bigenough = 1;
1722 while (more_dirs && bigenough) {
1723 doit = 1;
41f343df
KM
1724 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1725 if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
1726 cachable = fxdr_unsigned(int, *tl++);
1727 ltime = reqtime + fxdr_unsigned(int, *tl++);
1728 fxdr_hyper(tl, &frev);
1729 }
2c5b44a2
KM
1730 nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
1731 if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
1732 VREF(vp);
1733 newvp = vp;
1734 np = VTONFS(vp);
1735 } else {
1736 if (error = nfs_nget(vp->v_mount, fhp, &np))
1737 doit = 0;
1738 newvp = NFSTOV(np);
1739 }
1740 if (error = nfs_loadattrcache(&newvp, &md, &dpos,
1741 (struct vattr *)0))
1742 doit = 0;
41f343df 1743 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2c5b44a2
KM
1744 fileno = fxdr_unsigned(u_long, *tl++);
1745 len = fxdr_unsigned(int, *tl);
1746 if (len <= 0 || len > NFS_MAXNAMLEN) {
1747 error = EBADRPC;
1748 m_freem(mrep);
1749 goto nfsmout;
1750 }
1751 tlen = (len + 4) & ~0x3;
1752 if ((tlen + DIRHDSIZ) > uiop->uio_resid)
1753 bigenough = 0;
1754 if (bigenough && doit) {
2cf9602a
KM
1755 dp = (struct dirent *)uiop->uio_iov->iov_base;
1756 dp->d_fileno = fileno;
2c5b44a2
KM
1757 dp->d_namlen = len;
1758 dp->d_reclen = tlen + DIRHDSIZ;
36a0d247
KM
1759 dp->d_type =
1760 IFTODT(VTTOIF(np->n_vattr.va_type));
2c5b44a2
KM
1761 uiop->uio_resid -= DIRHDSIZ;
1762 uiop->uio_iov->iov_base += DIRHDSIZ;
1763 uiop->uio_iov->iov_len -= DIRHDSIZ;
c5b4f497
JH
1764 cnp->cn_nameptr = uiop->uio_iov->iov_base;
1765 cnp->cn_namelen = len;
2c5b44a2
KM
1766 ndp->ni_vp = newvp;
1767 nfsm_mtouio(uiop, len);
1768 cp = uiop->uio_iov->iov_base;
1769 tlen -= len;
1770 for (i = 0; i < tlen; i++)
1771 *cp++ = '\0';
1772 uiop->uio_iov->iov_base += tlen;
1773 uiop->uio_iov->iov_len -= tlen;
1774 uiop->uio_resid -= tlen;
c5b4f497
JH
1775 cnp->cn_hash = 0;
1776 for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
1777 cnp->cn_hash += (unsigned char)*cp * i;
41f343df
KM
1778 if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
1779 ltime > time.tv_sec)
1780 nqnfs_clientlease(nmp, np, NQL_READ,
1781 cachable, ltime, frev);
60579747 1782 if (cnp->cn_namelen <= NCHNAMLEN)
c33e9e8b 1783 cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2c5b44a2
KM
1784 } else {
1785 nfsm_adv(nfsm_rndup(len));
1786 }
1787 if (newvp != NULLVP) {
1788 vrele(newvp);
1789 newvp = NULLVP;
1790 }
41f343df 1791 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2c5b44a2 1792 if (bigenough)
41f343df 1793 endoff = off = fxdr_unsigned(u_long, *tl++);
2c5b44a2 1794 else
41f343df 1795 endoff = fxdr_unsigned(u_long, *tl++);
2c5b44a2
KM
1796 more_dirs = fxdr_unsigned(int, *tl);
1797 }
1798 /*
1799 * If at end of rpc data, get the eof boolean
1800 */
1801 if (!more_dirs) {
1802 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1803 more_dirs = (fxdr_unsigned(int, *tl) == 0);
1804
1805 /*
1806 * If at EOF, cache directory offset
1807 */
1808 if (!more_dirs)
1809 VTONFS(vp)->n_direofoffset = endoff;
1810 }
1811 if (uiop->uio_resid < tresid)
41f343df 1812 uiop->uio_offset = (off_t)off;
2c5b44a2
KM
1813 else
1814 more_dirs = 0;
1815 m_freem(mrep);
1816 }
1817 /*
1818 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
1819 * by increasing d_reclen for the last record.
1820 */
1821 if (uiop->uio_resid < tresid) {
1822 len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1823 if (len > 0) {
1824 dp->d_reclen += len;
1825 uiop->uio_iov->iov_base += len;
1826 uiop->uio_iov->iov_len -= len;
1827 uiop->uio_resid -= len;
1828 }
1829 }
1830nfsmout:
1831 if (newvp != NULLVP)
1832 vrele(newvp);
1833 return (error);
1834}
13576453 1835static char hextoasc[] = "0123456789abcdef";
a2907882
KM
1836
1837/*
1838 * Silly rename. To make the NFS filesystem that is stateless look a little
1839 * more like the "ufs" a remove of an active vnode is translated to a rename
1840 * to a funny looking filename that is removed by nfs_inactive on the
1841 * nfsnode. There is the potential for another process on a different client
1842 * to create the same funny name between the nfs_lookitup() fails and the
1843 * nfs_rename() completes, but...
1844 */
cfef4373 1845int
c5b4f497 1846nfs_sillyrename(dvp, vp, cnp)
cfef4373
JH
1847 struct vnode *dvp, *vp;
1848 struct componentname *cnp;
a2907882
KM
1849{
1850 register struct nfsnode *np;
1851 register struct sillyrename *sp;
a2907882
KM
1852 int error;
1853 short pid;
1854
cfef4373
JH
1855 cache_purge(dvp);
1856 np = VTONFS(vp);
4999e85f 1857#ifdef SILLYSEPARATE
a2907882 1858 MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
a9b4ecb2 1859 M_NFSREQ, M_WAITOK);
4999e85f
KM
1860#else
1861 sp = &np->n_silly;
1862#endif
cfef4373
JH
1863 sp->s_cred = crdup(cnp->cn_cred);
1864 sp->s_dvp = dvp;
1865 VREF(dvp);
a2907882
KM
1866
1867 /* Fudge together a funny name */
cfef4373 1868 pid = cnp->cn_proc->p_pid;
a9b4ecb2
KM
1869 bcopy(".nfsAxxxx4.4", sp->s_name, 13);
1870 sp->s_namlen = 12;
1871 sp->s_name[8] = hextoasc[pid & 0xf];
1872 sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
1873 sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
1874 sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
a2907882
KM
1875
1876 /* Try lookitups until we get one that isn't there */
cfef4373 1877 while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
a9b4ecb2
KM
1878 sp->s_name[4]++;
1879 if (sp->s_name[4] > 'z') {
a2907882
KM
1880 error = EINVAL;
1881 goto bad;
1882 }
1883 }
cfef4373 1884 if (error = nfs_renameit(dvp, cnp, sp))
a2907882 1885 goto bad;
cfef4373 1886 nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
a2907882
KM
1887 np->n_sillyrename = sp;
1888 return (0);
1889bad:
a9b4ecb2
KM
1890 vrele(sp->s_dvp);
1891 crfree(sp->s_cred);
4999e85f 1892#ifdef SILLYSEPARATE
a9b4ecb2 1893 free((caddr_t)sp, M_NFSREQ);
4999e85f 1894#endif
a2907882
KM
1895 return (error);
1896}
1897
1898/*
1899 * Look up a file name for silly rename stuff.
1900 * Just like nfs_lookup() except that it doesn't load returned values
1901 * into the nfsnode table.
1902 * If fhp != NULL it copies the returned file handle out
1903 */
cfef4373 1904int
2c5b44a2 1905nfs_lookitup(sp, fhp, procp)
a9b4ecb2 1906 register struct sillyrename *sp;
a2907882 1907 nfsv2fh_t *fhp;
2c5b44a2 1908 struct proc *procp;
a2907882 1909{
a9b4ecb2 1910 register struct vnode *vp = sp->s_dvp;
26cb2431 1911 register u_long *tl;
13576453
KM
1912 register caddr_t cp;
1913 register long t1, t2;
1914 caddr_t bpos, dpos, cp2;
1915 u_long xid;
41f343df 1916 int error = 0, isnq;
13576453 1917 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
a2907882
KM
1918 long len;
1919
41f343df 1920 isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
a2907882 1921 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
a9b4ecb2 1922 len = sp->s_namlen;
2c5b44a2 1923 nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
41f343df
KM
1924 if (isnq) {
1925 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1926 *tl = 0;
1927 }
a2907882 1928 nfsm_fhtom(vp);
a9b4ecb2 1929 nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
2c5b44a2 1930 nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
a2907882 1931 if (fhp != NULL) {
41f343df
KM
1932 if (isnq)
1933 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2c5b44a2 1934 nfsm_dissect(cp, caddr_t, NFSX_FH);
a2907882
KM
1935 bcopy(cp, (caddr_t)fhp, NFSX_FH);
1936 }
1937 nfsm_reqdone;
1938 return (error);
1939}
1940
1941/*
1942 * Kludge City..
1943 * - make nfs_bmap() essentially a no-op that does no translation
f0f1cbaa 1944 * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
a2907882
KM
1945 * after mapping the physical addresses into Kernel Virtual space in the
1946 * nfsiobuf area.
1947 * (Maybe I could use the process's page mapping, but I was concerned that
1948 * Kernel Write might not be enabled and also figured copyout() would do
1949 * a lot more work than bcopy() and also it currently happens in the
1950 * context of the swapper process (2).
1951 */
cfef4373 1952int
d40530c6 1953nfs_bmap(ap)
f43a11b8
KM
1954 struct vop_bmap_args /* {
1955 struct vnode *a_vp;
1956 daddr_t a_bn;
1957 struct vnode **a_vpp;
1958 daddr_t *a_bnp;
f53571f7 1959 int *a_runp;
f43a11b8 1960 } */ *ap;
a2907882 1961{
d40530c6
KM
1962 register struct vnode *vp = ap->a_vp;
1963
e1b76915 1964 if (ap->a_vpp != NULL)
d40530c6 1965 *ap->a_vpp = vp;
e1b76915 1966 if (ap->a_bnp != NULL)
d40530c6 1967 *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
a2907882
KM
1968 return (0);
1969}
1970
1971/*
c33e9e8b
KM
1972 * Strategy routine.
1973 * For async requests when nfsiod(s) are running, queue the request by
1974 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
1975 * request.
a2907882 1976 */
cfef4373 1977int
d40530c6 1978nfs_strategy(ap)
c33e9e8b 1979 struct vop_strategy_args *ap;
9238aa59 1980{
d40530c6 1981 register struct buf *bp = ap->a_bp;
c33e9e8b
KM
1982 struct ucred *cr;
1983 struct proc *p;
9238aa59
RM
1984 int error = 0;
1985
c33e9e8b
KM
1986 if (bp->b_flags & B_PHYS)
1987 panic("nfs physio");
1988 if (bp->b_flags & B_ASYNC)
1989 p = (struct proc *)0;
1990 else
1991 p = curproc; /* XXX */
1992 if (bp->b_flags & B_READ)
1993 cr = bp->b_rcred;
1994 else
1995 cr = bp->b_wcred;
9238aa59 1996 /*
48531fd3 1997 * If the op is asynchronous and an i/o daemon is waiting
9238aa59 1998 * queue the request, wake it up and wait for completion
48531fd3 1999 * otherwise just do it ourselves.
9238aa59 2000 */
c33e9e8b
KM
2001 if ((bp->b_flags & B_ASYNC) == 0 ||
2002 nfs_asyncio(bp, NOCRED))
2003 error = nfs_doio(bp, cr, p);
9238aa59
RM
2004 return (error);
2005}
2006
26cb2431
KM
2007/*
2008 * Mmap a file
2009 *
2010 * NB Currently unsupported.
2011 */
2012/* ARGSUSED */
cfef4373 2013int
d40530c6 2014nfs_mmap(ap)
f43a11b8
KM
2015 struct vop_mmap_args /* {
2016 struct vnode *a_vp;
2017 int a_fflags;
2018 struct ucred *a_cred;
2019 struct proc *a_p;
2020 } */ *ap;
26cb2431
KM
2021{
2022
2023 return (EINVAL);
2024}
2025
9238aa59
RM
2026/*
2027 * Flush all the blocks associated with a vnode.
2028 * Walk through the buffer pool and push any dirty pages
2029 * associated with the vnode.
2030 */
13576453 2031/* ARGSUSED */
cfef4373 2032int
d40530c6 2033nfs_fsync(ap)
575dc6d4
KM
2034 struct vop_fsync_args /* {
2035 struct vnodeop_desc *a_desc;
2036 struct vnode * a_vp;
2037 struct ucred * a_cred;
2038 int a_waitfor;
2039 struct proc * a_p;
2040 } */ *ap;
9238aa59 2041{
575dc6d4
KM
2042 register struct vnode *vp = ap->a_vp;
2043 register struct nfsnode *np = VTONFS(vp);
2044 register struct buf *bp;
2045 struct buf *nbp;
c33e9e8b
KM
2046 struct nfsmount *nmp;
2047 int s, error = 0, slptimeo = 0, slpflag = 0;
575dc6d4 2048
c33e9e8b
KM
2049 nmp = VFSTONFS(vp->v_mount);
2050 if (nmp->nm_flag & NFSMNT_INT)
2051 slpflag = PCATCH;
575dc6d4
KM
2052loop:
2053 s = splbio();
36c41e6e
KM
2054 for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
2055 nbp = bp->b_vnbufs.qe_next;
c33e9e8b
KM
2056 if (bp->b_flags & B_BUSY) {
2057 if (ap->a_waitfor != MNT_WAIT)
2058 continue;
2059 bp->b_flags |= B_WANTED;
2060 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
2061 "nfsfsync", slptimeo);
2062 splx(s);
2063 if (error) {
2064 if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
2065 return (EINTR);
2066 if (slpflag == PCATCH) {
2067 slpflag = 0;
2068 slptimeo = 2 * hz;
2069 }
2070 }
2071 goto loop;
2072 }
575dc6d4
KM
2073 if ((bp->b_flags & B_DELWRI) == 0)
2074 panic("nfs_fsync: not dirty");
2075 bremfree(bp);
2076 bp->b_flags |= B_BUSY;
2077 splx(s);
c33e9e8b
KM
2078 bp->b_flags |= B_ASYNC;
2079 VOP_BWRITE(bp);
575dc6d4
KM
2080 goto loop;
2081 }
c33e9e8b 2082 splx(s);
575dc6d4
KM
2083 if (ap->a_waitfor == MNT_WAIT) {
2084 while (vp->v_numoutput) {
2085 vp->v_flag |= VBWAIT;
c33e9e8b
KM
2086 error = tsleep((caddr_t)&vp->v_numoutput,
2087 slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
2088 if (error) {
2089 if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
2090 return (EINTR);
2091 if (slpflag == PCATCH) {
2092 slpflag = 0;
2093 slptimeo = 2 * hz;
2094 }
2095 }
575dc6d4 2096 }
36c41e6e 2097 if (vp->v_dirtyblkhd.le_next) {
c33e9e8b 2098#ifdef DIAGNOSTIC
575dc6d4 2099 vprint("nfs_fsync: dirty", vp);
c33e9e8b 2100#endif
575dc6d4
KM
2101 goto loop;
2102 }
9238aa59 2103 }
9b61ab4a 2104 if (np->n_flag & NWRITEERR) {
e8540f59 2105 error = np->n_error;
9b61ab4a
KM
2106 np->n_flag &= ~NWRITEERR;
2107 }
a2907882
KM
2108 return (error);
2109}
d002709d 2110
a4128336
KM
2111/*
2112 * NFS advisory byte-level locks.
2113 * Currently unsupported.
2114 */
cfef4373 2115int
d40530c6 2116nfs_advlock(ap)
f43a11b8
KM
2117 struct vop_advlock_args /* {
2118 struct vnode *a_vp;
2119 caddr_t a_id;
2120 int a_op;
2121 struct flock *a_fl;
2122 int a_flags;
2123 } */ *ap;
a4128336
KM
2124{
2125
2126 return (EOPNOTSUPP);
2127}
2128
d002709d
KM
2129/*
2130 * Print out the contents of an nfsnode.
2131 */
cfef4373 2132int
d40530c6 2133nfs_print(ap)
f43a11b8
KM
2134 struct vop_print_args /* {
2135 struct vnode *a_vp;
2136 } */ *ap;
d002709d 2137{
d40530c6
KM
2138 register struct vnode *vp = ap->a_vp;
2139 register struct nfsnode *np = VTONFS(vp);
d002709d 2140
b2d955e4
KM
2141 printf("tag VT_NFS, fileid %d fsid 0x%x",
2142 np->n_vattr.va_fileid, np->n_vattr.va_fsid);
2143#ifdef FIFO
d40530c6
KM
2144 if (vp->v_type == VFIFO)
2145 fifo_printinfo(vp);
b2d955e4 2146#endif /* FIFO */
1a1dbccb 2147 printf("\n");
d002709d 2148}
9396df75
KM
2149
2150/*
2151 * NFS directory offset lookup.
2152 * Currently unsupported.
2153 */
cfef4373 2154int
d40530c6 2155nfs_blkatoff(ap)
f43a11b8
KM
2156 struct vop_blkatoff_args /* {
2157 struct vnode *a_vp;
2158 off_t a_offset;
2159 char **a_res;
2160 struct buf **a_bpp;
2161 } */ *ap;
9396df75
KM
2162{
2163
2164 return (EOPNOTSUPP);
2165}
2166
2167/*
2168 * NFS flat namespace allocation.
2169 * Currently unsupported.
2170 */
cfef4373 2171int
d40530c6 2172nfs_valloc(ap)
f43a11b8
KM
2173 struct vop_valloc_args /* {
2174 struct vnode *a_pvp;
2175 int a_mode;
2176 struct ucred *a_cred;
2177 struct vnode **a_vpp;
2178 } */ *ap;
9396df75
KM
2179{
2180
2181 return (EOPNOTSUPP);
2182}
2183
2184/*
2185 * NFS flat namespace free.
2186 * Currently unsupported.
2187 */
4c323403 2188int
d40530c6 2189nfs_vfree(ap)
f43a11b8
KM
2190 struct vop_vfree_args /* {
2191 struct vnode *a_pvp;
2192 ino_t a_ino;
2193 int a_mode;
2194 } */ *ap;
9396df75
KM
2195{
2196
4c323403 2197 return (EOPNOTSUPP);
9396df75
KM
2198}
2199
2200/*
2201 * NFS file truncation.
2202 */
cfef4373 2203int
d40530c6 2204nfs_truncate(ap)
f43a11b8
KM
2205 struct vop_truncate_args /* {
2206 struct vnode *a_vp;
2207 off_t a_length;
2208 int a_flags;
2209 struct ucred *a_cred;
2210 struct proc *a_p;
2211 } */ *ap;
9396df75
KM
2212{
2213
2214 /* Use nfs_setattr */
2215 printf("nfs_truncate: need to implement!!");
2216 return (EOPNOTSUPP);
2217}
2218
2219/*
2220 * NFS update.
2221 */
cfef4373 2222int
d40530c6 2223nfs_update(ap)
f43a11b8
KM
2224 struct vop_update_args /* {
2225 struct vnode *a_vp;
2226 struct timeval *a_ta;
2227 struct timeval *a_tm;
2228 int a_waitfor;
2229 } */ *ap;
9396df75
KM
2230{
2231
2232 /* Use nfs_setattr */
2233 printf("nfs_update: need to implement!!");
2234 return (EOPNOTSUPP);
2235}
9b61ab4a 2236
b330a7ec
KM
2237/*
2238 * nfs special file access vnode op.
2239 * Essentially just get vattr and then imitate iaccess() since the device is
2240 * local to the client.
2241 */
2242int
2243nfsspec_access(ap)
2244 struct vop_access_args /* {
2245 struct vnode *a_vp;
2246 int a_mode;
2247 struct ucred *a_cred;
2248 struct proc *a_p;
2249 } */ *ap;
2250{
2251 register struct vattr *vap;
2252 register gid_t *gp;
2253 register struct ucred *cred = ap->a_cred;
2254 mode_t mode = ap->a_mode;
2255 struct vattr vattr;
2256 register int i;
2257 int error;
2258
2259 /*
2260 * If you're the super-user,
2261 * you always get access.
2262 */
2263 if (cred->cr_uid == 0)
2264 return (0);
2265 vap = &vattr;
2266 if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
2267 return (error);
2268 /*
2269 * Access check is based on only one of owner, group, public.
2270 * If not owner, then check group. If not a member of the
2271 * group, then check public access.
2272 */
2273 if (cred->cr_uid != vap->va_uid) {
2274 mode >>= 3;
2275 gp = cred->cr_groups;
2276 for (i = 0; i < cred->cr_ngroups; i++, gp++)
2277 if (vap->va_gid == *gp)
2278 goto found;
2279 mode >>= 3;
2280found:
2281 ;
2282 }
716a55ca 2283 return ((vap->va_mode & mode) == mode ? 0 : EACCES);
b330a7ec
KM
2284}
2285
9b61ab4a
KM
2286/*
2287 * Read wrapper for special devices.
2288 */
2289int
2290nfsspec_read(ap)
f43a11b8
KM
2291 struct vop_read_args /* {
2292 struct vnode *a_vp;
2293 struct uio *a_uio;
2294 int a_ioflag;
2295 struct ucred *a_cred;
2296 } */ *ap;
9b61ab4a 2297{
8a0aec3d 2298 register struct nfsnode *np = VTONFS(ap->a_vp);
9b61ab4a
KM
2299
2300 /*
2301 * Set access flag.
2302 */
8a0aec3d
KM
2303 np->n_flag |= NACC;
2304 np->n_atim = time;
9b61ab4a
KM
2305 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
2306}
2307
2308/*
2309 * Write wrapper for special devices.
2310 */
2311int
2312nfsspec_write(ap)
f43a11b8
KM
2313 struct vop_write_args /* {
2314 struct vnode *a_vp;
2315 struct uio *a_uio;
2316 int a_ioflag;
2317 struct ucred *a_cred;
2318 } */ *ap;
9b61ab4a 2319{
8a0aec3d 2320 register struct nfsnode *np = VTONFS(ap->a_vp);
9b61ab4a
KM
2321
2322 /*
8a0aec3d 2323 * Set update flag.
9b61ab4a 2324 */
8a0aec3d
KM
2325 np->n_flag |= NUPD;
2326 np->n_mtim = time;
9b61ab4a
KM
2327 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
2328}
2329
2330/*
2331 * Close wrapper for special devices.
2332 *
2333 * Update the times on the nfsnode then do device close.
2334 */
2335int
2336nfsspec_close(ap)
f43a11b8
KM
2337 struct vop_close_args /* {
2338 struct vnode *a_vp;
2339 int a_fflag;
2340 struct ucred *a_cred;
2341 struct proc *a_p;
2342 } */ *ap;
9b61ab4a 2343{
d40530c6
KM
2344 register struct vnode *vp = ap->a_vp;
2345 register struct nfsnode *np = VTONFS(vp);
9b61ab4a 2346 struct vattr vattr;
9b61ab4a
KM
2347
2348 if (np->n_flag & (NACC | NUPD)) {
9b61ab4a 2349 np->n_flag |= NCHG;
d40530c6
KM
2350 if (vp->v_usecount == 1 &&
2351 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
9b61ab4a 2352 VATTR_NULL(&vattr);
7e11a0c9
KM
2353 if (np->n_flag & NACC) {
2354 vattr.va_atime.ts_sec = np->n_atim.tv_sec;
2355 vattr.va_atime.ts_nsec =
2356 np->n_atim.tv_usec * 1000;
2357 }
2358 if (np->n_flag & NUPD) {
2359 vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
2360 vattr.va_mtime.ts_nsec =
2361 np->n_mtim.tv_usec * 1000;
2362 }
d40530c6 2363 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
9b61ab4a
KM
2364 }
2365 }
2366 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
2367}
2368
2369#ifdef FIFO
2370/*
2371 * Read wrapper for fifos.
2372 */
2373int
2374nfsfifo_read(ap)
f43a11b8
KM
2375 struct vop_read_args /* {
2376 struct vnode *a_vp;
2377 struct uio *a_uio;
2378 int a_ioflag;
2379 struct ucred *a_cred;
2380 } */ *ap;
9b61ab4a
KM
2381{
2382 extern int (**fifo_vnodeop_p)();
8a0aec3d 2383 register struct nfsnode *np = VTONFS(ap->a_vp);
9b61ab4a
KM
2384
2385 /*
2386 * Set access flag.
2387 */
8a0aec3d
KM
2388 np->n_flag |= NACC;
2389 np->n_atim = time;
9b61ab4a
KM
2390 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
2391}
2392
2393/*
2394 * Write wrapper for fifos.
2395 */
2396int
2397nfsfifo_write(ap)
f43a11b8
KM
2398 struct vop_write_args /* {
2399 struct vnode *a_vp;
2400 struct uio *a_uio;
2401 int a_ioflag;
2402 struct ucred *a_cred;
2403 } */ *ap;
9b61ab4a
KM
2404{
2405 extern int (**fifo_vnodeop_p)();
8a0aec3d 2406 register struct nfsnode *np = VTONFS(ap->a_vp);
9b61ab4a
KM
2407
2408 /*
2409 * Set update flag.
2410 */
8a0aec3d
KM
2411 np->n_flag |= NUPD;
2412 np->n_mtim = time;
9b61ab4a
KM
2413 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
2414}
2415
2416/*
2417 * Close wrapper for fifos.
2418 *
2419 * Update the times on the nfsnode then do fifo close.
2420 */
2421int
2422nfsfifo_close(ap)
f43a11b8
KM
2423 struct vop_close_args /* {
2424 struct vnode *a_vp;
2425 int a_fflag;
2426 struct ucred *a_cred;
2427 struct proc *a_p;
2428 } */ *ap;
9b61ab4a 2429{
d40530c6
KM
2430 register struct vnode *vp = ap->a_vp;
2431 register struct nfsnode *np = VTONFS(vp);
9b61ab4a
KM
2432 struct vattr vattr;
2433 extern int (**fifo_vnodeop_p)();
2434
2435 if (np->n_flag & (NACC | NUPD)) {
2436 if (np->n_flag & NACC)
2437 np->n_atim = time;
2438 if (np->n_flag & NUPD)
2439 np->n_mtim = time;
2440 np->n_flag |= NCHG;
d40530c6
KM
2441 if (vp->v_usecount == 1 &&
2442 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
9b61ab4a 2443 VATTR_NULL(&vattr);
7e11a0c9
KM
2444 if (np->n_flag & NACC) {
2445 vattr.va_atime.ts_sec = np->n_atim.tv_sec;
2446 vattr.va_atime.ts_nsec =
2447 np->n_atim.tv_usec * 1000;
2448 }
2449 if (np->n_flag & NUPD) {
2450 vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
2451 vattr.va_mtime.ts_nsec =
2452 np->n_mtim.tv_usec * 1000;
2453 }
d40530c6 2454 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
9b61ab4a
KM
2455 }
2456 }
2457 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
2458}
2459#endif /* FIFO */