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