Annotation of sys/nfs/nfs_vnops.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: nfs_vnops.c,v 1.75 2007/06/01 23:47:57 deraadt Exp $ */
! 2: /* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to Berkeley by
! 9: * Rick Macklem at The University of Guelph.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
! 36: */
! 37:
! 38:
! 39: /*
! 40: * vnode op calls for Sun NFS version 2 and 3
! 41: */
! 42:
! 43: #include <sys/param.h>
! 44: #include <sys/proc.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/resourcevar.h>
! 48: #include <sys/poll.h>
! 49: #include <sys/proc.h>
! 50: #include <sys/mount.h>
! 51: #include <sys/buf.h>
! 52: #include <sys/malloc.h>
! 53: #include <sys/pool.h>
! 54: #include <sys/mbuf.h>
! 55: #include <sys/conf.h>
! 56: #include <sys/namei.h>
! 57: #include <sys/vnode.h>
! 58: #include <sys/dirent.h>
! 59: #include <sys/fcntl.h>
! 60: #include <sys/lockf.h>
! 61: #include <sys/hash.h>
! 62:
! 63: #include <uvm/uvm_extern.h>
! 64:
! 65: #include <miscfs/specfs/specdev.h>
! 66: #include <miscfs/fifofs/fifo.h>
! 67:
! 68: #include <nfs/rpcv2.h>
! 69: #include <nfs/nfsproto.h>
! 70: #include <nfs/nfs.h>
! 71: #include <nfs/nfsnode.h>
! 72: #include <nfs/nfsmount.h>
! 73: #include <nfs/xdr_subs.h>
! 74: #include <nfs/nfsm_subs.h>
! 75: #include <nfs/nfs_var.h>
! 76:
! 77: #include <net/if.h>
! 78: #include <netinet/in.h>
! 79: #include <netinet/in_var.h>
! 80:
! 81: /* Defs */
! 82: #define TRUE 1
! 83: #define FALSE 0
! 84:
! 85: /*
! 86: * Global vfs data structures for nfs
! 87: */
! 88: int (**nfsv2_vnodeop_p)(void *);
! 89: struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
! 90: { &vop_default_desc, vn_default_error },
! 91: { &vop_lookup_desc, nfs_lookup }, /* lookup */
! 92: { &vop_create_desc, nfs_create }, /* create */
! 93: { &vop_mknod_desc, nfs_mknod }, /* mknod */
! 94: { &vop_open_desc, nfs_open }, /* open */
! 95: { &vop_close_desc, nfs_close }, /* close */
! 96: { &vop_access_desc, nfs_access }, /* access */
! 97: { &vop_getattr_desc, nfs_getattr }, /* getattr */
! 98: { &vop_setattr_desc, nfs_setattr }, /* setattr */
! 99: { &vop_read_desc, nfs_read }, /* read */
! 100: { &vop_write_desc, nfs_write }, /* write */
! 101: { &vop_ioctl_desc, nfs_ioctl }, /* ioctl */
! 102: { &vop_poll_desc, nfs_poll }, /* poll */
! 103: { &vop_kqfilter_desc, nfs_kqfilter }, /* kqfilter */
! 104: { &vop_revoke_desc, nfs_revoke }, /* revoke */
! 105: { &vop_fsync_desc, nfs_fsync }, /* fsync */
! 106: { &vop_remove_desc, nfs_remove }, /* remove */
! 107: { &vop_link_desc, nfs_link }, /* link */
! 108: { &vop_rename_desc, nfs_rename }, /* rename */
! 109: { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */
! 110: { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */
! 111: { &vop_symlink_desc, nfs_symlink }, /* symlink */
! 112: { &vop_readdir_desc, nfs_readdir }, /* readdir */
! 113: { &vop_readlink_desc, nfs_readlink }, /* readlink */
! 114: { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
! 115: { &vop_inactive_desc, nfs_inactive }, /* inactive */
! 116: { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
! 117: { &vop_lock_desc, nfs_lock }, /* lock */
! 118: { &vop_unlock_desc, nfs_unlock }, /* unlock */
! 119: { &vop_bmap_desc, nfs_bmap }, /* bmap */
! 120: { &vop_strategy_desc, nfs_strategy }, /* strategy */
! 121: { &vop_print_desc, nfs_print }, /* print */
! 122: { &vop_islocked_desc, nfs_islocked }, /* islocked */
! 123: { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */
! 124: { &vop_advlock_desc, nfs_advlock }, /* advlock */
! 125: { &vop_bwrite_desc, nfs_bwrite },
! 126: { NULL, NULL }
! 127: };
! 128: struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
! 129: { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
! 130:
! 131: /*
! 132: * Special device vnode ops
! 133: */
! 134: int (**spec_nfsv2nodeop_p)(void *);
! 135: struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
! 136: { &vop_default_desc, spec_vnoperate },
! 137: { &vop_close_desc, nfsspec_close }, /* close */
! 138: { &vop_access_desc, nfsspec_access }, /* access */
! 139: { &vop_getattr_desc, nfs_getattr }, /* getattr */
! 140: { &vop_setattr_desc, nfs_setattr }, /* setattr */
! 141: { &vop_read_desc, nfsspec_read }, /* read */
! 142: { &vop_write_desc, nfsspec_write }, /* write */
! 143: { &vop_fsync_desc, nfs_fsync }, /* fsync */
! 144: { &vop_inactive_desc, nfs_inactive }, /* inactive */
! 145: { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */
! 146: { &vop_lock_desc, nfs_lock }, /* lock */
! 147: { &vop_unlock_desc, nfs_unlock }, /* unlock */
! 148: { &vop_print_desc, nfs_print }, /* print */
! 149: { &vop_islocked_desc, nfs_islocked }, /* islocked */
! 150: { NULL, NULL }
! 151: };
! 152: struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
! 153: { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
! 154:
! 155: #ifdef FIFO
! 156: int (**fifo_nfsv2nodeop_p)(void *);
! 157: struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
! 158: { &vop_default_desc, fifo_vnoperate },
! 159: { &vop_close_desc, nfsfifo_close }, /* close */
! 160: { &vop_access_desc, nfsspec_access }, /* access */
! 161: { &vop_getattr_desc, nfs_getattr }, /* getattr */
! 162: { &vop_setattr_desc, nfs_setattr }, /* setattr */
! 163: { &vop_read_desc, nfsfifo_read }, /* read */
! 164: { &vop_write_desc, nfsfifo_write }, /* write */
! 165: { &vop_fsync_desc, nfs_fsync }, /* fsync */
! 166: { &vop_inactive_desc, nfs_inactive }, /* inactive */
! 167: { &vop_reclaim_desc, nfsfifo_reclaim }, /* reclaim */
! 168: { &vop_lock_desc, nfs_lock }, /* lock */
! 169: { &vop_unlock_desc, nfs_unlock }, /* unlock */
! 170: { &vop_print_desc, nfs_print }, /* print */
! 171: { &vop_islocked_desc, nfs_islocked }, /* islocked */
! 172: { &vop_bwrite_desc, vop_generic_bwrite },
! 173: { NULL, NULL }
! 174: };
! 175: struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
! 176: { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
! 177: #endif /* FIFO */
! 178:
! 179: /*
! 180: * Global variables
! 181: */
! 182: extern u_int32_t nfs_true, nfs_false;
! 183: extern u_int32_t nfs_xdrneg1;
! 184: extern struct nfsstats nfsstats;
! 185: extern nfstype nfsv3_type[9];
! 186: struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
! 187: int nfs_numasync = 0;
! 188:
! 189: /*
! 190: * nfs null call from vfs.
! 191: */
! 192: int
! 193: nfs_null(vp, cred, procp)
! 194: struct vnode *vp;
! 195: struct ucred *cred;
! 196: struct proc *procp;
! 197: {
! 198: caddr_t bpos, dpos;
! 199: int error = 0;
! 200: struct mbuf *mreq, *mrep, *md, *mb;
! 201:
! 202: nfsm_reqhead(vp, NFSPROC_NULL, 0);
! 203: nfsm_request(vp, NFSPROC_NULL, procp, cred);
! 204: nfsm_reqdone;
! 205: return (error);
! 206: }
! 207:
! 208: /*
! 209: * nfs access vnode op.
! 210: * For nfs version 2, just return ok. File accesses may fail later.
! 211: * For nfs version 3, use the access rpc to check accessibility. If file modes
! 212: * are changed on the server, accesses might still fail later.
! 213: */
! 214: int
! 215: nfs_access(v)
! 216: void *v;
! 217: {
! 218: struct vop_access_args *ap = v;
! 219: struct vnode *vp = ap->a_vp;
! 220: u_int32_t *tl;
! 221: caddr_t cp;
! 222: int32_t t1, t2;
! 223: caddr_t bpos, dpos, cp2;
! 224: int error = 0, attrflag;
! 225: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 226: u_int32_t mode, rmode;
! 227: int v3 = NFS_ISV3(vp);
! 228:
! 229: /*
! 230: * Disallow write attempts on filesystems mounted read-only;
! 231: * unless the file is a socket, fifo, or a block or character
! 232: * device resident on the filesystem.
! 233: */
! 234: if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
! 235: switch (vp->v_type) {
! 236: case VREG:
! 237: case VDIR:
! 238: case VLNK:
! 239: return (EROFS);
! 240: default:
! 241: break;
! 242: }
! 243: }
! 244: /*
! 245: * For nfs v3, do an access rpc, otherwise you are stuck emulating
! 246: * ufs_access() locally using the vattr. This may not be correct,
! 247: * since the server may apply other access criteria such as
! 248: * client uid-->server uid mapping that we do not know about, but
! 249: * this is better than just returning anything that is lying about
! 250: * in the cache.
! 251: */
! 252: if (v3) {
! 253: nfsstats.rpccnt[NFSPROC_ACCESS]++;
! 254: nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
! 255: nfsm_fhtom(vp, v3);
! 256: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 257: if (ap->a_mode & VREAD)
! 258: mode = NFSV3ACCESS_READ;
! 259: else
! 260: mode = 0;
! 261: if (vp->v_type == VDIR) {
! 262: if (ap->a_mode & VWRITE)
! 263: mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
! 264: NFSV3ACCESS_DELETE);
! 265: if (ap->a_mode & VEXEC)
! 266: mode |= NFSV3ACCESS_LOOKUP;
! 267: } else {
! 268: if (ap->a_mode & VWRITE)
! 269: mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
! 270: if (ap->a_mode & VEXEC)
! 271: mode |= NFSV3ACCESS_EXECUTE;
! 272: }
! 273: *tl = txdr_unsigned(mode);
! 274: nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
! 275: nfsm_postop_attr(vp, attrflag);
! 276: if (!error) {
! 277: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 278: rmode = fxdr_unsigned(u_int32_t, *tl);
! 279: /*
! 280: * The NFS V3 spec does not clarify whether or not
! 281: * the returned access bits can be a superset of
! 282: * the ones requested, so...
! 283: */
! 284: if ((rmode & mode) != mode)
! 285: error = EACCES;
! 286: }
! 287: nfsm_reqdone;
! 288: return (error);
! 289: } else
! 290: return (nfsspec_access(ap));
! 291: }
! 292:
! 293: /*
! 294: * nfs open vnode op
! 295: * Check to see if the type is ok
! 296: * and that deletion is not in progress.
! 297: * For paged in text files, you will need to flush the page cache
! 298: * if consistency is lost.
! 299: */
! 300: /* ARGSUSED */
! 301: int
! 302: nfs_open(v)
! 303: void *v;
! 304: {
! 305: struct vop_open_args *ap = v;
! 306: struct vnode *vp = ap->a_vp;
! 307: struct nfsnode *np = VTONFS(vp);
! 308: struct vattr vattr;
! 309: int error;
! 310:
! 311: if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
! 312: #ifdef DIAGNOSTIC
! 313: printf("open eacces vtyp=%d\n",vp->v_type);
! 314: #endif
! 315: return (EACCES);
! 316: }
! 317:
! 318: /*
! 319: * Initialize read and write creds here, for swapfiles
! 320: * and other paths that don't set the creds themselves.
! 321: */
! 322:
! 323: if (ap->a_mode & FREAD) {
! 324: if (np->n_rcred) {
! 325: crfree(np->n_rcred);
! 326: }
! 327: np->n_rcred = ap->a_cred;
! 328: crhold(np->n_rcred);
! 329: }
! 330: if (ap->a_mode & FWRITE) {
! 331: if (np->n_wcred) {
! 332: crfree(np->n_wcred);
! 333: }
! 334: np->n_wcred = ap->a_cred;
! 335: crhold(np->n_wcred);
! 336: }
! 337:
! 338: if (np->n_flag & NMODIFIED) {
! 339: if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
! 340: ap->a_p, 1)) == EINTR)
! 341: return (error);
! 342: uvm_vnp_uncache(vp);
! 343: np->n_attrstamp = 0;
! 344: if (vp->v_type == VDIR)
! 345: np->n_direofoffset = 0;
! 346: error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
! 347: if (error)
! 348: return (error);
! 349: np->n_mtime = vattr.va_mtime.tv_sec;
! 350: } else {
! 351: error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
! 352: if (error)
! 353: return (error);
! 354: if (np->n_mtime != vattr.va_mtime.tv_sec) {
! 355: if (vp->v_type == VDIR)
! 356: np->n_direofoffset = 0;
! 357: if ((error = nfs_vinvalbuf(vp, V_SAVE,
! 358: ap->a_cred, ap->a_p, 1)) == EINTR)
! 359: return (error);
! 360: uvm_vnp_uncache(vp);
! 361: np->n_mtime = vattr.va_mtime.tv_sec;
! 362: }
! 363: }
! 364: np->n_attrstamp = 0; /* For Open/Close consistency */
! 365: return (0);
! 366: }
! 367:
! 368: /*
! 369: * nfs close vnode op
! 370: * What an NFS client should do upon close after writing is a debatable issue.
! 371: * Most NFS clients push delayed writes to the server upon close, basically for
! 372: * two reasons:
! 373: * 1 - So that any write errors may be reported back to the client process
! 374: * doing the close system call. By far the two most likely errors are
! 375: * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
! 376: * 2 - To put a worst case upper bound on cache inconsistency between
! 377: * multiple clients for the file.
! 378: * There is also a consistency problem for Version 2 of the protocol w.r.t.
! 379: * not being able to tell if other clients are writing a file concurrently,
! 380: * since there is no way of knowing if the changed modify time in the reply
! 381: * is only due to the write for this client.
! 382: * (NFS Version 3 provides weak cache consistency data in the reply that
! 383: * should be sufficient to detect and handle this case.)
! 384: *
! 385: * The current code does the following:
! 386: * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
! 387: * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
! 388: * or commit them (this satisfies 1 and 2 except for the
! 389: * case where the server crashes after this close but
! 390: * before the commit RPC, which is felt to be "good
! 391: * enough". Changing the last argument to nfs_flush() to
! 392: * a 1 would force a commit operation, if it is felt a
! 393: * commit is necessary now.
! 394: */
! 395: /* ARGSUSED */
! 396: int
! 397: nfs_close(v)
! 398: void *v;
! 399: {
! 400: struct vop_close_args *ap = v;
! 401: struct vnode *vp = ap->a_vp;
! 402: struct nfsnode *np = VTONFS(vp);
! 403: int error = 0;
! 404:
! 405: if (vp->v_type == VREG) {
! 406: if (np->n_flag & NMODIFIED) {
! 407: if (NFS_ISV3(vp)) {
! 408: error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
! 409: np->n_flag &= ~NMODIFIED;
! 410: } else
! 411: error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
! 412: np->n_attrstamp = 0;
! 413: }
! 414: if (np->n_flag & NWRITEERR) {
! 415: np->n_flag &= ~NWRITEERR;
! 416: error = np->n_error;
! 417: }
! 418: }
! 419: return (error);
! 420: }
! 421:
! 422: /*
! 423: * nfs getattr call from vfs.
! 424: */
! 425: int
! 426: nfs_getattr(v)
! 427: void *v;
! 428: {
! 429: struct vop_getattr_args *ap = v;
! 430: struct vnode *vp = ap->a_vp;
! 431: struct nfsnode *np = VTONFS(vp);
! 432: caddr_t cp;
! 433: u_int32_t *tl;
! 434: int32_t t1, t2;
! 435: caddr_t bpos, dpos;
! 436: int error = 0;
! 437: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 438: int v3 = NFS_ISV3(vp);
! 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(v3));
! 452: nfsm_fhtom(vp, v3);
! 453: nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
! 454: if (!error)
! 455: nfsm_loadattr(vp, ap->a_vap);
! 456: nfsm_reqdone;
! 457: return (error);
! 458: }
! 459:
! 460: /*
! 461: * nfs setattr call.
! 462: */
! 463: int
! 464: nfs_setattr(v)
! 465: void *v;
! 466: {
! 467: struct vop_setattr_args *ap = v;
! 468: struct vnode *vp = ap->a_vp;
! 469: struct nfsnode *np = VTONFS(vp);
! 470: struct vattr *vap = ap->a_vap;
! 471: int error = 0;
! 472: u_quad_t tsize = 0;
! 473:
! 474: /*
! 475: * Setting of flags is not supported.
! 476: */
! 477: if (vap->va_flags != VNOVAL)
! 478: return (EOPNOTSUPP);
! 479:
! 480: /*
! 481: * Disallow write attempts if the filesystem is mounted read-only.
! 482: */
! 483: if ((vap->va_uid != (uid_t)VNOVAL ||
! 484: vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
! 485: vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
! 486: (vp->v_mount->mnt_flag & MNT_RDONLY))
! 487: return (EROFS);
! 488: if (vap->va_size != VNOVAL) {
! 489: switch (vp->v_type) {
! 490: case VDIR:
! 491: return (EISDIR);
! 492: case VCHR:
! 493: case VBLK:
! 494: case VSOCK:
! 495: case VFIFO:
! 496: if (vap->va_mtime.tv_sec == VNOVAL &&
! 497: vap->va_atime.tv_sec == VNOVAL &&
! 498: vap->va_mode == (mode_t)VNOVAL &&
! 499: vap->va_uid == (uid_t)VNOVAL &&
! 500: vap->va_gid == (gid_t)VNOVAL)
! 501: return (0);
! 502: vap->va_size = VNOVAL;
! 503: break;
! 504: default:
! 505: /*
! 506: * Disallow write attempts if the filesystem is
! 507: * mounted read-only.
! 508: */
! 509: if (vp->v_mount->mnt_flag & MNT_RDONLY)
! 510: return (EROFS);
! 511: if (vap->va_size == 0)
! 512: error = nfs_vinvalbuf(vp, 0,
! 513: ap->a_cred, ap->a_p, 1);
! 514: else
! 515: error = nfs_vinvalbuf(vp, V_SAVE,
! 516: ap->a_cred, ap->a_p, 1);
! 517: if (error)
! 518: return (error);
! 519: tsize = np->n_size;
! 520: np->n_size = np->n_vattr.va_size = vap->va_size;
! 521: uvm_vnp_setsize(vp, np->n_size);
! 522: };
! 523: } else if ((vap->va_mtime.tv_sec != VNOVAL ||
! 524: vap->va_atime.tv_sec != VNOVAL) &&
! 525: vp->v_type == VREG &&
! 526: (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
! 527: ap->a_p, 1)) == EINTR)
! 528: return (error);
! 529: error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
! 530: if (error && vap->va_size != VNOVAL) {
! 531: np->n_size = np->n_vattr.va_size = tsize;
! 532: uvm_vnp_setsize(vp, np->n_size);
! 533: }
! 534:
! 535: VN_KNOTE(vp, NOTE_ATTRIB); /* XXX setattrrpc? */
! 536:
! 537: return (error);
! 538: }
! 539:
! 540: /*
! 541: * Do an nfs setattr rpc.
! 542: */
! 543: int
! 544: nfs_setattrrpc(vp, vap, cred, procp)
! 545: struct vnode *vp;
! 546: struct vattr *vap;
! 547: struct ucred *cred;
! 548: struct proc *procp;
! 549: {
! 550: struct nfsv2_sattr *sp;
! 551: caddr_t cp;
! 552: int32_t t1, t2;
! 553: caddr_t bpos, dpos, cp2;
! 554: u_int32_t *tl;
! 555: int error = 0, wccflag = NFSV3_WCCRATTR;
! 556: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 557: int v3 = NFS_ISV3(vp);
! 558:
! 559: nfsstats.rpccnt[NFSPROC_SETATTR]++;
! 560: nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
! 561: nfsm_fhtom(vp, v3);
! 562: if (v3) {
! 563: nfsm_v3attrbuild(vap, TRUE);
! 564: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 565: *tl = nfs_false;
! 566: } else {
! 567: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 568: if (vap->va_mode == (mode_t)VNOVAL)
! 569: sp->sa_mode = nfs_xdrneg1;
! 570: else
! 571: sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
! 572: if (vap->va_uid == (uid_t)VNOVAL)
! 573: sp->sa_uid = nfs_xdrneg1;
! 574: else
! 575: sp->sa_uid = txdr_unsigned(vap->va_uid);
! 576: if (vap->va_gid == (gid_t)VNOVAL)
! 577: sp->sa_gid = nfs_xdrneg1;
! 578: else
! 579: sp->sa_gid = txdr_unsigned(vap->va_gid);
! 580: sp->sa_size = txdr_unsigned(vap->va_size);
! 581: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
! 582: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
! 583: }
! 584: nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
! 585: if (v3) {
! 586: nfsm_wcc_data(vp, wccflag);
! 587: } else
! 588: nfsm_loadattr(vp, (struct vattr *)0);
! 589: nfsm_reqdone;
! 590: return (error);
! 591: }
! 592:
! 593: /*
! 594: * nfs lookup call, one step at a time...
! 595: * First look in cache
! 596: * If not found, unlock the directory nfsnode and do the rpc
! 597: */
! 598: int
! 599: nfs_lookup(v)
! 600: void *v;
! 601: {
! 602: struct vop_lookup_args *ap = v;
! 603: struct componentname *cnp = ap->a_cnp;
! 604: struct vnode *dvp = ap->a_dvp;
! 605: struct vnode **vpp = ap->a_vpp;
! 606: struct proc *p = cnp->cn_proc;
! 607: int flags;
! 608: struct vnode *newvp;
! 609: u_int32_t *tl;
! 610: caddr_t cp;
! 611: int32_t t1, t2;
! 612: struct nfsmount *nmp;
! 613: caddr_t bpos, dpos, cp2;
! 614: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 615: long len;
! 616: nfsfh_t *fhp;
! 617: struct nfsnode *np;
! 618: int lockparent, wantparent, error = 0, attrflag, fhsize;
! 619: int v3 = NFS_ISV3(dvp);
! 620:
! 621: cnp->cn_flags &= ~PDIRUNLOCK;
! 622: flags = cnp->cn_flags;
! 623:
! 624: *vpp = NULLVP;
! 625: if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
! 626: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
! 627: return (EROFS);
! 628: if (dvp->v_type != VDIR)
! 629: return (ENOTDIR);
! 630: lockparent = flags & LOCKPARENT;
! 631: wantparent = flags & (LOCKPARENT|WANTPARENT);
! 632: nmp = VFSTONFS(dvp->v_mount);
! 633: np = VTONFS(dvp);
! 634:
! 635: /*
! 636: * Before tediously performing a linear scan of the directory,
! 637: * check the name cache to see if the directory/name pair
! 638: * we are looking for is known already.
! 639: * If the directory/name pair is found in the name cache,
! 640: * we have to ensure the directory has not changed from
! 641: * the time the cache entry has been created. If it has,
! 642: * the cache entry has to be ignored.
! 643: */
! 644: if ((error = cache_lookup(dvp, vpp, cnp)) >= 0) {
! 645: struct vattr vattr;
! 646: int err2;
! 647:
! 648: if (error && error != ENOENT) {
! 649: *vpp = NULLVP;
! 650: return (error);
! 651: }
! 652:
! 653: if (cnp->cn_flags & PDIRUNLOCK) {
! 654: err2 = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
! 655: if (err2 != 0) {
! 656: *vpp = NULLVP;
! 657: return (err2);
! 658: }
! 659: cnp->cn_flags &= ~PDIRUNLOCK;
! 660: }
! 661:
! 662: err2 = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
! 663: if (err2 != 0) {
! 664: if (error == 0) {
! 665: if (*vpp != dvp)
! 666: vput(*vpp);
! 667: else
! 668: vrele(*vpp);
! 669: }
! 670: *vpp = NULLVP;
! 671: return (err2);
! 672: }
! 673:
! 674: if (error == ENOENT) {
! 675: if (!VOP_GETATTR(dvp, &vattr, cnp->cn_cred,
! 676: cnp->cn_proc) && vattr.va_mtime.tv_sec ==
! 677: VTONFS(dvp)->n_ctime)
! 678: return (ENOENT);
! 679: cache_purge(dvp);
! 680: np->n_ctime = 0;
! 681: goto dorpc;
! 682: }
! 683:
! 684: newvp = *vpp;
! 685: if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
! 686: && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime)
! 687: {
! 688: nfsstats.lookupcache_hits++;
! 689: if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
! 690: cnp->cn_flags |= SAVENAME;
! 691: if ((!lockparent || !(flags & ISLASTCN)) &&
! 692: newvp != dvp)
! 693: VOP_UNLOCK(dvp, 0, p);
! 694: return (0);
! 695: }
! 696: cache_purge(newvp);
! 697: if (newvp != dvp)
! 698: vput(newvp);
! 699: else
! 700: vrele(newvp);
! 701: *vpp = NULLVP;
! 702: }
! 703: dorpc:
! 704: error = 0;
! 705: newvp = NULLVP;
! 706: nfsstats.lookupcache_misses++;
! 707: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
! 708: len = cnp->cn_namelen;
! 709: nfsm_reqhead(dvp, NFSPROC_LOOKUP,
! 710: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
! 711: nfsm_fhtom(dvp, v3);
! 712: nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
! 713: nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
! 714: if (error) {
! 715: nfsm_postop_attr(dvp, attrflag);
! 716: m_freem(mrep);
! 717: goto nfsmout;
! 718: }
! 719: nfsm_getfh(fhp, fhsize, v3);
! 720:
! 721: /*
! 722: * Handle RENAME case...
! 723: */
! 724: if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
! 725: if (NFS_CMPFH(np, fhp, fhsize)) {
! 726: m_freem(mrep);
! 727: return (EISDIR);
! 728: }
! 729: error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
! 730: if (error) {
! 731: m_freem(mrep);
! 732: return (error);
! 733: }
! 734: newvp = NFSTOV(np);
! 735: if (v3) {
! 736: nfsm_postop_attr(newvp, attrflag);
! 737: nfsm_postop_attr(dvp, attrflag);
! 738: } else
! 739: nfsm_loadattr(newvp, (struct vattr *)0);
! 740: *vpp = newvp;
! 741: m_freem(mrep);
! 742: cnp->cn_flags |= SAVENAME;
! 743: if (!lockparent) {
! 744: VOP_UNLOCK(dvp, 0, p);
! 745: cnp->cn_flags |= PDIRUNLOCK;
! 746: }
! 747: return (0);
! 748: }
! 749:
! 750: /*
! 751: * The postop attr handling is duplicated for each if case,
! 752: * because it should be done while dvp is locked (unlocking
! 753: * dvp is different for each case).
! 754: */
! 755:
! 756: if (NFS_CMPFH(np, fhp, fhsize)) {
! 757: VREF(dvp);
! 758: newvp = dvp;
! 759: if (v3) {
! 760: nfsm_postop_attr(newvp, attrflag);
! 761: nfsm_postop_attr(dvp, attrflag);
! 762: } else
! 763: nfsm_loadattr(newvp, (struct vattr *)0);
! 764: } else if (flags & ISDOTDOT) {
! 765: VOP_UNLOCK(dvp, 0, p);
! 766: cnp->cn_flags |= PDIRUNLOCK;
! 767:
! 768: error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
! 769: if (error) {
! 770: if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
! 771: cnp->cn_flags &= ~PDIRUNLOCK;
! 772: m_freem(mrep);
! 773: return (error);
! 774: }
! 775: newvp = NFSTOV(np);
! 776:
! 777: if (v3) {
! 778: nfsm_postop_attr(newvp, attrflag);
! 779: nfsm_postop_attr(dvp, attrflag);
! 780: } else
! 781: nfsm_loadattr(newvp, (struct vattr *)0);
! 782:
! 783: if (lockparent && (flags & ISLASTCN)) {
! 784: if ((error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
! 785: m_freem(mrep);
! 786: vput(newvp);
! 787: return error;
! 788: }
! 789: cnp->cn_flags &= ~PDIRUNLOCK;
! 790: }
! 791:
! 792: } else {
! 793: error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
! 794: if (error) {
! 795: m_freem(mrep);
! 796: return error;
! 797: }
! 798: newvp = NFSTOV(np);
! 799: if (v3) {
! 800: nfsm_postop_attr(newvp, attrflag);
! 801: nfsm_postop_attr(dvp, attrflag);
! 802: } else
! 803: nfsm_loadattr(newvp, (struct vattr *)0);
! 804: if (!lockparent || !(flags & ISLASTCN)) {
! 805: VOP_UNLOCK(dvp, 0, p);
! 806: cnp->cn_flags |= PDIRUNLOCK;
! 807: }
! 808: }
! 809: if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
! 810: cnp->cn_flags |= SAVENAME;
! 811: if ((cnp->cn_flags & MAKEENTRY) &&
! 812: (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
! 813: np->n_ctime = np->n_vattr.va_ctime.tv_sec;
! 814: cache_enter(dvp, newvp, cnp);
! 815: }
! 816: *vpp = newvp;
! 817: nfsm_reqdone;
! 818: if (error) {
! 819: /*
! 820: * We get here only because of errors returned by
! 821: * the RPC. Otherwise we'll have returned above
! 822: * (the nfsm_* macros will jump to nfsm_reqdone
! 823: * on error).
! 824: */
! 825: if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) &&
! 826: cnp->cn_nameiop != CREATE) {
! 827: if (VTONFS(dvp)->n_ctime == 0)
! 828: VTONFS(dvp)->n_ctime =
! 829: VTONFS(dvp)->n_vattr.va_mtime.tv_sec;
! 830: cache_enter(dvp, NULL, cnp);
! 831: }
! 832: if (newvp != NULLVP) {
! 833: vrele(newvp);
! 834: if (newvp != dvp)
! 835: VOP_UNLOCK(newvp, 0, p);
! 836: }
! 837: if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
! 838: (flags & ISLASTCN) && error == ENOENT) {
! 839: if (dvp->v_mount->mnt_flag & MNT_RDONLY)
! 840: error = EROFS;
! 841: else
! 842: error = EJUSTRETURN;
! 843: }
! 844: if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
! 845: cnp->cn_flags |= SAVENAME;
! 846: *vpp = NULL;
! 847: }
! 848: return (error);
! 849: }
! 850:
! 851: /*
! 852: * nfs read call.
! 853: * Just call nfs_bioread() to do the work.
! 854: */
! 855: int
! 856: nfs_read(v)
! 857: void *v;
! 858: {
! 859: struct vop_read_args *ap = v;
! 860: struct vnode *vp = ap->a_vp;
! 861:
! 862: if (vp->v_type != VREG)
! 863: return (EPERM);
! 864: return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
! 865: }
! 866:
! 867: /*
! 868: * nfs readlink call
! 869: */
! 870: int
! 871: nfs_readlink(v)
! 872: void *v;
! 873: {
! 874: struct vop_readlink_args *ap = v;
! 875: struct vnode *vp = ap->a_vp;
! 876:
! 877: if (vp->v_type != VLNK)
! 878: return (EPERM);
! 879: return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
! 880: }
! 881:
! 882: /*
! 883: * Do a readlink rpc.
! 884: * Called by nfs_doio() from below the buffer cache.
! 885: */
! 886: int
! 887: nfs_readlinkrpc(vp, uiop, cred)
! 888: struct vnode *vp;
! 889: struct uio *uiop;
! 890: struct ucred *cred;
! 891: {
! 892: u_int32_t *tl;
! 893: caddr_t cp;
! 894: int32_t t1, t2;
! 895: caddr_t bpos, dpos, cp2;
! 896: int error = 0, len, attrflag;
! 897: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 898: int v3 = NFS_ISV3(vp);
! 899:
! 900: nfsstats.rpccnt[NFSPROC_READLINK]++;
! 901: nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
! 902: nfsm_fhtom(vp, v3);
! 903: nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
! 904: if (v3)
! 905: nfsm_postop_attr(vp, attrflag);
! 906: if (!error) {
! 907: nfsm_strsiz(len, NFS_MAXPATHLEN);
! 908: nfsm_mtouio(uiop, len);
! 909: }
! 910: nfsm_reqdone;
! 911: return (error);
! 912: }
! 913:
! 914: /*
! 915: * nfs read rpc call
! 916: * Ditto above
! 917: */
! 918: int
! 919: nfs_readrpc(vp, uiop)
! 920: struct vnode *vp;
! 921: struct uio *uiop;
! 922: {
! 923: u_int32_t *tl;
! 924: caddr_t cp;
! 925: int32_t t1, t2;
! 926: caddr_t bpos, dpos, cp2;
! 927: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 928: struct nfsmount *nmp;
! 929: int error = 0, len, retlen, tsiz, eof, attrflag;
! 930: int v3 = NFS_ISV3(vp);
! 931:
! 932: #ifndef nolint
! 933: eof = 0;
! 934: #endif
! 935: nmp = VFSTONFS(vp->v_mount);
! 936: tsiz = uiop->uio_resid;
! 937: if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
! 938: return (EFBIG);
! 939: while (tsiz > 0) {
! 940: nfsstats.rpccnt[NFSPROC_READ]++;
! 941: len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
! 942: nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
! 943: nfsm_fhtom(vp, v3);
! 944: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 3);
! 945: if (v3) {
! 946: txdr_hyper(uiop->uio_offset, tl);
! 947: *(tl + 2) = txdr_unsigned(len);
! 948: } else {
! 949: *tl++ = txdr_unsigned(uiop->uio_offset);
! 950: *tl++ = txdr_unsigned(len);
! 951: *tl = 0;
! 952: }
! 953: nfsm_request(vp, NFSPROC_READ, uiop->uio_procp,
! 954: VTONFS(vp)->n_rcred);
! 955: if (v3) {
! 956: nfsm_postop_attr(vp, attrflag);
! 957: if (error) {
! 958: m_freem(mrep);
! 959: goto nfsmout;
! 960: }
! 961: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 962: eof = fxdr_unsigned(int, *(tl + 1));
! 963: } else
! 964: nfsm_loadattr(vp, (struct vattr *)0);
! 965: nfsm_strsiz(retlen, nmp->nm_rsize);
! 966: nfsm_mtouio(uiop, retlen);
! 967: m_freem(mrep);
! 968: tsiz -= retlen;
! 969: if (v3) {
! 970: if (eof || retlen == 0)
! 971: tsiz = 0;
! 972: } else if (retlen < len)
! 973: tsiz = 0;
! 974: }
! 975: nfsmout:
! 976: return (error);
! 977: }
! 978:
! 979: /*
! 980: * nfs write call
! 981: */
! 982: int
! 983: nfs_writerpc(vp, uiop, iomode, must_commit)
! 984: struct vnode *vp;
! 985: struct uio *uiop;
! 986: int *iomode, *must_commit;
! 987: {
! 988: u_int32_t *tl;
! 989: caddr_t cp;
! 990: int32_t t1, t2, backup;
! 991: caddr_t bpos, dpos, cp2;
! 992: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 993: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 994: int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
! 995: int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
! 996:
! 997: #ifndef DIAGNOSTIC
! 998: if (uiop->uio_iovcnt != 1)
! 999: panic("nfs: writerpc iovcnt > 1");
! 1000: #endif
! 1001: *must_commit = 0;
! 1002: tsiz = uiop->uio_resid;
! 1003: if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
! 1004: return (EFBIG);
! 1005: while (tsiz > 0) {
! 1006: nfsstats.rpccnt[NFSPROC_WRITE]++;
! 1007: len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
! 1008: nfsm_reqhead(vp, NFSPROC_WRITE,
! 1009: NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
! 1010: nfsm_fhtom(vp, v3);
! 1011: if (v3) {
! 1012: nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
! 1013: txdr_hyper(uiop->uio_offset, tl);
! 1014: tl += 2;
! 1015: *tl++ = txdr_unsigned(len);
! 1016: *tl++ = txdr_unsigned(*iomode);
! 1017: *tl = txdr_unsigned(len);
! 1018: } else {
! 1019: u_int32_t x;
! 1020:
! 1021: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
! 1022: /* Set both "begin" and "current" to non-garbage. */
! 1023: x = txdr_unsigned((u_int32_t)uiop->uio_offset);
! 1024: *tl++ = x; /* "begin offset" */
! 1025: *tl++ = x; /* "current offset" */
! 1026: x = txdr_unsigned(len);
! 1027: *tl++ = x; /* total to this offset */
! 1028: *tl = x; /* size of this write */
! 1029:
! 1030: }
! 1031: nfsm_uiotom(uiop, len);
! 1032: nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp,
! 1033: VTONFS(vp)->n_wcred);
! 1034: if (v3) {
! 1035: wccflag = NFSV3_WCCCHK;
! 1036: nfsm_wcc_data(vp, wccflag);
! 1037: if (!error) {
! 1038: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED
! 1039: + NFSX_V3WRITEVERF);
! 1040: rlen = fxdr_unsigned(int, *tl++);
! 1041: if (rlen == 0) {
! 1042: error = NFSERR_IO;
! 1043: break;
! 1044: } else if (rlen < len) {
! 1045: backup = len - rlen;
! 1046: (char *)uiop->uio_iov->iov_base -= backup;
! 1047: uiop->uio_iov->iov_len += backup;
! 1048: uiop->uio_offset -= backup;
! 1049: uiop->uio_resid += backup;
! 1050: len = rlen;
! 1051: }
! 1052: commit = fxdr_unsigned(int, *tl++);
! 1053:
! 1054: /*
! 1055: * Return the lowest committment level
! 1056: * obtained by any of the RPCs.
! 1057: */
! 1058: if (committed == NFSV3WRITE_FILESYNC)
! 1059: committed = commit;
! 1060: else if (committed == NFSV3WRITE_DATASYNC &&
! 1061: commit == NFSV3WRITE_UNSTABLE)
! 1062: committed = commit;
! 1063: if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
! 1064: bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
! 1065: NFSX_V3WRITEVERF);
! 1066: nmp->nm_flag |= NFSMNT_HASWRITEVERF;
! 1067: } else if (bcmp((caddr_t)tl,
! 1068: (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
! 1069: *must_commit = 1;
! 1070: bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
! 1071: NFSX_V3WRITEVERF);
! 1072: }
! 1073: }
! 1074: } else
! 1075: nfsm_loadattr(vp, (struct vattr *)0);
! 1076: if (wccflag)
! 1077: VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
! 1078: m_freem(mrep);
! 1079: tsiz -= len;
! 1080: }
! 1081: nfsmout:
! 1082: *iomode = committed;
! 1083: if (error)
! 1084: uiop->uio_resid = tsiz;
! 1085: return (error);
! 1086: }
! 1087:
! 1088: /*
! 1089: * nfs mknod rpc
! 1090: * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
! 1091: * mode set to specify the file type and the size field for rdev.
! 1092: */
! 1093: int
! 1094: nfs_mknodrpc(dvp, vpp, cnp, vap)
! 1095: struct vnode *dvp;
! 1096: struct vnode **vpp;
! 1097: struct componentname *cnp;
! 1098: struct vattr *vap;
! 1099: {
! 1100: struct nfsv2_sattr *sp;
! 1101: u_int32_t *tl;
! 1102: caddr_t cp;
! 1103: int32_t t1, t2;
! 1104: struct vnode *newvp = (struct vnode *)0;
! 1105: struct nfsnode *np;
! 1106: char *cp2;
! 1107: caddr_t bpos, dpos;
! 1108: int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
! 1109: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1110: u_int32_t rdev;
! 1111: int v3 = NFS_ISV3(dvp);
! 1112:
! 1113: if (vap->va_type == VCHR || vap->va_type == VBLK)
! 1114: rdev = txdr_unsigned(vap->va_rdev);
! 1115: else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
! 1116: rdev = nfs_xdrneg1;
! 1117: else {
! 1118: VOP_ABORTOP(dvp, cnp);
! 1119: vput(dvp);
! 1120: return (EOPNOTSUPP);
! 1121: }
! 1122: nfsstats.rpccnt[NFSPROC_MKNOD]++;
! 1123: nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
! 1124: + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
! 1125: nfsm_fhtom(dvp, v3);
! 1126: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
! 1127: if (v3) {
! 1128: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 1129: *tl++ = vtonfsv3_type(vap->va_type);
! 1130: nfsm_v3attrbuild(vap, FALSE);
! 1131: if (vap->va_type == VCHR || vap->va_type == VBLK) {
! 1132: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 1133: *tl++ = txdr_unsigned(major(vap->va_rdev));
! 1134: *tl = txdr_unsigned(minor(vap->va_rdev));
! 1135: }
! 1136: } else {
! 1137: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 1138: sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
! 1139: sp->sa_uid = nfs_xdrneg1;
! 1140: sp->sa_gid = nfs_xdrneg1;
! 1141: sp->sa_size = rdev;
! 1142: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
! 1143: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
! 1144: }
! 1145: nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
! 1146: if (!error) {
! 1147: nfsm_mtofh(dvp, newvp, v3, gotvp);
! 1148: if (!gotvp) {
! 1149: if (newvp) {
! 1150: vrele(newvp);
! 1151: newvp = (struct vnode *)0;
! 1152: }
! 1153: error = nfs_lookitup(dvp, cnp->cn_nameptr,
! 1154: cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
! 1155: if (!error)
! 1156: newvp = NFSTOV(np);
! 1157: }
! 1158: }
! 1159: if (v3)
! 1160: nfsm_wcc_data(dvp, wccflag);
! 1161: nfsm_reqdone;
! 1162: if (error) {
! 1163: if (newvp)
! 1164: vrele(newvp);
! 1165: } else {
! 1166: if (cnp->cn_flags & MAKEENTRY)
! 1167: cache_enter(dvp, newvp, cnp);
! 1168: *vpp = newvp;
! 1169: }
! 1170: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1171: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1172: if (!wccflag)
! 1173: VTONFS(dvp)->n_attrstamp = 0;
! 1174: vrele(dvp);
! 1175: return (error);
! 1176: }
! 1177:
! 1178: /*
! 1179: * nfs mknod vop
! 1180: * just call nfs_mknodrpc() to do the work.
! 1181: */
! 1182: /* ARGSUSED */
! 1183: int
! 1184: nfs_mknod(v)
! 1185: void *v;
! 1186: {
! 1187: struct vop_mknod_args *ap = v;
! 1188: struct vnode *newvp;
! 1189: int error;
! 1190:
! 1191: error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
! 1192: if (!error)
! 1193: vrele(newvp);
! 1194:
! 1195: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
! 1196:
! 1197: return (error);
! 1198: }
! 1199:
! 1200: static u_long create_verf;
! 1201: /*
! 1202: * nfs file create call
! 1203: */
! 1204: int
! 1205: nfs_create(v)
! 1206: void *v;
! 1207: {
! 1208: struct vop_create_args *ap = v;
! 1209: struct vnode *dvp = ap->a_dvp;
! 1210: struct vattr *vap = ap->a_vap;
! 1211: struct componentname *cnp = ap->a_cnp;
! 1212: struct nfsv2_sattr *sp;
! 1213: u_int32_t *tl;
! 1214: caddr_t cp;
! 1215: int32_t t1, t2;
! 1216: struct nfsnode *np = (struct nfsnode *)0;
! 1217: struct vnode *newvp = (struct vnode *)0;
! 1218: caddr_t bpos, dpos, cp2;
! 1219: int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
! 1220: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1221: int v3 = NFS_ISV3(dvp);
! 1222:
! 1223: /*
! 1224: * Oops, not for me..
! 1225: */
! 1226: if (vap->va_type == VSOCK)
! 1227: return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
! 1228:
! 1229: #ifdef VA_EXCLUSIVE
! 1230: if (vap->va_vaflags & VA_EXCLUSIVE)
! 1231: fmode |= O_EXCL;
! 1232: #endif
! 1233: again:
! 1234: nfsstats.rpccnt[NFSPROC_CREATE]++;
! 1235: nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
! 1236: nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
! 1237: nfsm_fhtom(dvp, v3);
! 1238: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
! 1239: if (v3) {
! 1240: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 1241: if (fmode & O_EXCL) {
! 1242: *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
! 1243: nfsm_build(tl, u_int32_t *, NFSX_V3CREATEVERF);
! 1244: if (TAILQ_FIRST(&in_ifaddr))
! 1245: *tl++ = TAILQ_FIRST(&in_ifaddr)->ia_addr.sin_addr.s_addr;
! 1246: else
! 1247: *tl++ = create_verf;
! 1248: *tl = ++create_verf;
! 1249: } else {
! 1250: *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
! 1251: nfsm_v3attrbuild(vap, FALSE);
! 1252: }
! 1253: } else {
! 1254: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 1255: sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
! 1256: sp->sa_uid = nfs_xdrneg1;
! 1257: sp->sa_gid = nfs_xdrneg1;
! 1258: sp->sa_size = 0;
! 1259: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
! 1260: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
! 1261: }
! 1262: nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
! 1263: if (!error) {
! 1264: nfsm_mtofh(dvp, newvp, v3, gotvp);
! 1265: if (!gotvp) {
! 1266: if (newvp) {
! 1267: vrele(newvp);
! 1268: newvp = (struct vnode *)0;
! 1269: }
! 1270: error = nfs_lookitup(dvp, cnp->cn_nameptr,
! 1271: cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
! 1272: if (!error)
! 1273: newvp = NFSTOV(np);
! 1274: }
! 1275: }
! 1276: if (v3)
! 1277: nfsm_wcc_data(dvp, wccflag);
! 1278: nfsm_reqdone;
! 1279: if (error) {
! 1280: if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
! 1281: fmode &= ~O_EXCL;
! 1282: goto again;
! 1283: }
! 1284: if (newvp)
! 1285: vrele(newvp);
! 1286: } else if (v3 && (fmode & O_EXCL))
! 1287: error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
! 1288: if (!error) {
! 1289: if (cnp->cn_flags & MAKEENTRY)
! 1290: cache_enter(dvp, newvp, cnp);
! 1291: *ap->a_vpp = newvp;
! 1292: }
! 1293: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1294: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1295: if (!wccflag)
! 1296: VTONFS(dvp)->n_attrstamp = 0;
! 1297: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
! 1298: vrele(dvp);
! 1299: return (error);
! 1300: }
! 1301:
! 1302: /*
! 1303: * nfs file remove call
! 1304: * To try and make nfs semantics closer to ufs semantics, a file that has
! 1305: * other processes using the vnode is renamed instead of removed and then
! 1306: * removed later on the last close.
! 1307: * - If v_usecount > 1
! 1308: * If a rename is not already in the works
! 1309: * call nfs_sillyrename() to set it up
! 1310: * else
! 1311: * do the remove rpc
! 1312: */
! 1313: int
! 1314: nfs_remove(v)
! 1315: void *v;
! 1316: {
! 1317: struct vop_remove_args *ap = v;
! 1318: struct vnode *vp = ap->a_vp;
! 1319: struct vnode *dvp = ap->a_dvp;
! 1320: struct componentname *cnp = ap->a_cnp;
! 1321: struct nfsnode *np = VTONFS(vp);
! 1322: int error = 0;
! 1323: struct vattr vattr;
! 1324:
! 1325: #ifndef DIAGNOSTIC
! 1326: if ((cnp->cn_flags & HASBUF) == 0)
! 1327: panic("nfs_remove: no name");
! 1328: if (vp->v_usecount < 1)
! 1329: panic("nfs_remove: bad v_usecount");
! 1330: #endif
! 1331: if (vp->v_type == VDIR)
! 1332: error = EPERM;
! 1333: else if (vp->v_usecount == 1 || (np->n_sillyrename &&
! 1334: VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
! 1335: vattr.va_nlink > 1)) {
! 1336: /*
! 1337: * Purge the name cache so that the chance of a lookup for
! 1338: * the name succeeding while the remove is in progress is
! 1339: * minimized. Without node locking it can still happen, such
! 1340: * that an I/O op returns ESTALE, but since you get this if
! 1341: * another host removes the file..
! 1342: */
! 1343: cache_purge(vp);
! 1344: /*
! 1345: * throw away biocache buffers, mainly to avoid
! 1346: * unnecessary delayed writes later.
! 1347: */
! 1348: error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
! 1349: /* Do the rpc */
! 1350: if (error != EINTR)
! 1351: error = nfs_removerpc(dvp, cnp->cn_nameptr,
! 1352: cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
! 1353: /*
! 1354: * Kludge City: If the first reply to the remove rpc is lost..
! 1355: * the reply to the retransmitted request will be ENOENT
! 1356: * since the file was in fact removed
! 1357: * Therefore, we cheat and return success.
! 1358: */
! 1359: if (error == ENOENT)
! 1360: error = 0;
! 1361: } else if (!np->n_sillyrename)
! 1362: error = nfs_sillyrename(dvp, vp, cnp);
! 1363: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1364: np->n_attrstamp = 0;
! 1365: vrele(dvp);
! 1366: vrele(vp);
! 1367:
! 1368: VN_KNOTE(vp, NOTE_DELETE);
! 1369: VN_KNOTE(dvp, NOTE_WRITE);
! 1370:
! 1371: return (error);
! 1372: }
! 1373:
! 1374: /*
! 1375: * nfs file remove rpc called from nfs_inactive
! 1376: */
! 1377: int
! 1378: nfs_removeit(sp)
! 1379: struct sillyrename *sp;
! 1380: {
! 1381:
! 1382: return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
! 1383: (struct proc *)0));
! 1384: }
! 1385:
! 1386: /*
! 1387: * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
! 1388: */
! 1389: int
! 1390: nfs_removerpc(dvp, name, namelen, cred, proc)
! 1391: struct vnode *dvp;
! 1392: char *name;
! 1393: int namelen;
! 1394: struct ucred *cred;
! 1395: struct proc *proc;
! 1396: {
! 1397: u_int32_t *tl;
! 1398: caddr_t cp;
! 1399: int32_t t1, t2;
! 1400: caddr_t bpos, dpos, cp2;
! 1401: int error = 0, wccflag = NFSV3_WCCRATTR;
! 1402: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1403: int v3 = NFS_ISV3(dvp);
! 1404:
! 1405: nfsstats.rpccnt[NFSPROC_REMOVE]++;
! 1406: nfsm_reqhead(dvp, NFSPROC_REMOVE,
! 1407: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
! 1408: nfsm_fhtom(dvp, v3);
! 1409: nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
! 1410: nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
! 1411: if (v3)
! 1412: nfsm_wcc_data(dvp, wccflag);
! 1413: nfsm_reqdone;
! 1414: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1415: if (!wccflag)
! 1416: VTONFS(dvp)->n_attrstamp = 0;
! 1417: return (error);
! 1418: }
! 1419:
! 1420: /*
! 1421: * nfs file rename call
! 1422: */
! 1423: int
! 1424: nfs_rename(v)
! 1425: void *v;
! 1426: {
! 1427: struct vop_rename_args *ap = v;
! 1428: struct vnode *fvp = ap->a_fvp;
! 1429: struct vnode *tvp = ap->a_tvp;
! 1430: struct vnode *fdvp = ap->a_fdvp;
! 1431: struct vnode *tdvp = ap->a_tdvp;
! 1432: struct componentname *tcnp = ap->a_tcnp;
! 1433: struct componentname *fcnp = ap->a_fcnp;
! 1434: int error;
! 1435:
! 1436: #ifndef DIAGNOSTIC
! 1437: if ((tcnp->cn_flags & HASBUF) == 0 ||
! 1438: (fcnp->cn_flags & HASBUF) == 0)
! 1439: panic("nfs_rename: no name");
! 1440: #endif
! 1441: /* Check for cross-device rename */
! 1442: if ((fvp->v_mount != tdvp->v_mount) ||
! 1443: (tvp && (fvp->v_mount != tvp->v_mount))) {
! 1444: error = EXDEV;
! 1445: goto out;
! 1446: }
! 1447:
! 1448: /*
! 1449: * If the tvp exists and is in use, sillyrename it before doing the
! 1450: * rename of the new file over it.
! 1451: */
! 1452: if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
! 1453: tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
! 1454: VN_KNOTE(tvp, NOTE_DELETE);
! 1455: vrele(tvp);
! 1456: tvp = NULL;
! 1457: }
! 1458:
! 1459: error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
! 1460: tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
! 1461: tcnp->cn_proc);
! 1462:
! 1463: VN_KNOTE(fdvp, NOTE_WRITE);
! 1464: VN_KNOTE(tdvp, NOTE_WRITE);
! 1465:
! 1466: if (fvp->v_type == VDIR) {
! 1467: if (tvp != NULL && tvp->v_type == VDIR)
! 1468: cache_purge(tdvp);
! 1469: cache_purge(fdvp);
! 1470: }
! 1471: out:
! 1472: if (tdvp == tvp)
! 1473: vrele(tdvp);
! 1474: else
! 1475: vput(tdvp);
! 1476: if (tvp)
! 1477: vput(tvp);
! 1478: vrele(fdvp);
! 1479: vrele(fvp);
! 1480: /*
! 1481: * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
! 1482: */
! 1483: if (error == ENOENT)
! 1484: error = 0;
! 1485: return (error);
! 1486: }
! 1487:
! 1488: /*
! 1489: * nfs file rename rpc called from nfs_remove() above
! 1490: */
! 1491: int
! 1492: nfs_renameit(sdvp, scnp, sp)
! 1493: struct vnode *sdvp;
! 1494: struct componentname *scnp;
! 1495: struct sillyrename *sp;
! 1496: {
! 1497: return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
! 1498: sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
! 1499: }
! 1500:
! 1501: /*
! 1502: * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
! 1503: */
! 1504: int
! 1505: nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
! 1506: struct vnode *fdvp;
! 1507: char *fnameptr;
! 1508: int fnamelen;
! 1509: struct vnode *tdvp;
! 1510: char *tnameptr;
! 1511: int tnamelen;
! 1512: struct ucred *cred;
! 1513: struct proc *proc;
! 1514: {
! 1515: u_int32_t *tl;
! 1516: caddr_t cp;
! 1517: int32_t t1, t2;
! 1518: caddr_t bpos, dpos, cp2;
! 1519: int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
! 1520: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1521: int v3 = NFS_ISV3(fdvp);
! 1522:
! 1523: nfsstats.rpccnt[NFSPROC_RENAME]++;
! 1524: nfsm_reqhead(fdvp, NFSPROC_RENAME,
! 1525: (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
! 1526: nfsm_rndup(tnamelen));
! 1527: nfsm_fhtom(fdvp, v3);
! 1528: nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
! 1529: nfsm_fhtom(tdvp, v3);
! 1530: nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
! 1531: nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
! 1532: if (v3) {
! 1533: nfsm_wcc_data(fdvp, fwccflag);
! 1534: nfsm_wcc_data(tdvp, twccflag);
! 1535: }
! 1536: nfsm_reqdone;
! 1537: VTONFS(fdvp)->n_flag |= NMODIFIED;
! 1538: VTONFS(tdvp)->n_flag |= NMODIFIED;
! 1539: if (!fwccflag)
! 1540: VTONFS(fdvp)->n_attrstamp = 0;
! 1541: if (!twccflag)
! 1542: VTONFS(tdvp)->n_attrstamp = 0;
! 1543: return (error);
! 1544: }
! 1545:
! 1546: /*
! 1547: * nfs hard link create call
! 1548: */
! 1549: int
! 1550: nfs_link(v)
! 1551: void *v;
! 1552: {
! 1553: struct vop_link_args *ap = v;
! 1554: struct vnode *vp = ap->a_vp;
! 1555: struct vnode *dvp = ap->a_dvp;
! 1556: struct componentname *cnp = ap->a_cnp;
! 1557: u_int32_t *tl;
! 1558: caddr_t cp;
! 1559: int32_t t1, t2;
! 1560: caddr_t bpos, dpos, cp2;
! 1561: int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
! 1562: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1563: int v3;
! 1564:
! 1565: if (dvp->v_mount != vp->v_mount) {
! 1566: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1567: if (vp == dvp)
! 1568: vrele(dvp);
! 1569: else
! 1570: vput(dvp);
! 1571: return (EXDEV);
! 1572: }
! 1573:
! 1574: /*
! 1575: * Push all writes to the server, so that the attribute cache
! 1576: * doesn't get "out of sync" with the server.
! 1577: * XXX There should be a better way!
! 1578: */
! 1579: VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
! 1580:
! 1581: v3 = NFS_ISV3(vp);
! 1582: nfsstats.rpccnt[NFSPROC_LINK]++;
! 1583: nfsm_reqhead(vp, NFSPROC_LINK,
! 1584: NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
! 1585: nfsm_fhtom(vp, v3);
! 1586: nfsm_fhtom(dvp, v3);
! 1587: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
! 1588: nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
! 1589: if (v3) {
! 1590: nfsm_postop_attr(vp, attrflag);
! 1591: nfsm_wcc_data(dvp, wccflag);
! 1592: }
! 1593: nfsm_reqdone;
! 1594: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1595: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1596: if (!attrflag)
! 1597: VTONFS(vp)->n_attrstamp = 0;
! 1598: if (!wccflag)
! 1599: VTONFS(dvp)->n_attrstamp = 0;
! 1600:
! 1601: VN_KNOTE(vp, NOTE_LINK);
! 1602: VN_KNOTE(dvp, NOTE_WRITE);
! 1603: vput(dvp);
! 1604: /*
! 1605: * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
! 1606: */
! 1607: if (error == EEXIST)
! 1608: error = 0;
! 1609: return (error);
! 1610: }
! 1611:
! 1612: /*
! 1613: * nfs symbolic link create call
! 1614: */
! 1615: int
! 1616: nfs_symlink(v)
! 1617: void *v;
! 1618: {
! 1619: struct vop_symlink_args *ap = v;
! 1620: struct vnode *dvp = ap->a_dvp;
! 1621: struct vattr *vap = ap->a_vap;
! 1622: struct componentname *cnp = ap->a_cnp;
! 1623: struct nfsv2_sattr *sp;
! 1624: u_int32_t *tl;
! 1625: caddr_t cp;
! 1626: int32_t t1, t2;
! 1627: caddr_t bpos, dpos, cp2;
! 1628: int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
! 1629: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1630: struct vnode *newvp = (struct vnode *)0;
! 1631: int v3 = NFS_ISV3(dvp);
! 1632:
! 1633: nfsstats.rpccnt[NFSPROC_SYMLINK]++;
! 1634: slen = strlen(ap->a_target);
! 1635: nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
! 1636: nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
! 1637: nfsm_fhtom(dvp, v3);
! 1638: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
! 1639: if (v3)
! 1640: nfsm_v3attrbuild(vap, FALSE);
! 1641: nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
! 1642: if (!v3) {
! 1643: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 1644: sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
! 1645: sp->sa_uid = nfs_xdrneg1;
! 1646: sp->sa_gid = nfs_xdrneg1;
! 1647: sp->sa_size = nfs_xdrneg1;
! 1648: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
! 1649: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
! 1650: }
! 1651: nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
! 1652: if (v3) {
! 1653: if (!error)
! 1654: nfsm_mtofh(dvp, newvp, v3, gotvp);
! 1655: nfsm_wcc_data(dvp, wccflag);
! 1656: }
! 1657: nfsm_reqdone;
! 1658: if (newvp)
! 1659: vrele(newvp);
! 1660: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1661: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1662: if (!wccflag)
! 1663: VTONFS(dvp)->n_attrstamp = 0;
! 1664: VN_KNOTE(dvp, NOTE_WRITE);
! 1665: vrele(dvp);
! 1666: /*
! 1667: * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
! 1668: */
! 1669: if (error == EEXIST)
! 1670: error = 0;
! 1671: return (error);
! 1672: }
! 1673:
! 1674: /*
! 1675: * nfs make dir call
! 1676: */
! 1677: int
! 1678: nfs_mkdir(v)
! 1679: void *v;
! 1680: {
! 1681: struct vop_mkdir_args *ap = v;
! 1682: struct vnode *dvp = ap->a_dvp;
! 1683: struct vattr *vap = ap->a_vap;
! 1684: struct componentname *cnp = ap->a_cnp;
! 1685: struct nfsv2_sattr *sp;
! 1686: u_int32_t *tl;
! 1687: caddr_t cp;
! 1688: int32_t t1, t2;
! 1689: int len;
! 1690: struct nfsnode *np = (struct nfsnode *)0;
! 1691: struct vnode *newvp = (struct vnode *)0;
! 1692: caddr_t bpos, dpos, cp2;
! 1693: int error = 0, wccflag = NFSV3_WCCRATTR;
! 1694: int gotvp = 0;
! 1695: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1696: int v3 = NFS_ISV3(dvp);
! 1697:
! 1698: len = cnp->cn_namelen;
! 1699: nfsstats.rpccnt[NFSPROC_MKDIR]++;
! 1700: nfsm_reqhead(dvp, NFSPROC_MKDIR,
! 1701: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
! 1702: nfsm_fhtom(dvp, v3);
! 1703: nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
! 1704: if (v3) {
! 1705: nfsm_v3attrbuild(vap, FALSE);
! 1706: } else {
! 1707: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
! 1708: sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
! 1709: sp->sa_uid = nfs_xdrneg1;
! 1710: sp->sa_gid = nfs_xdrneg1;
! 1711: sp->sa_size = nfs_xdrneg1;
! 1712: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
! 1713: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
! 1714: }
! 1715: nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
! 1716: if (!error)
! 1717: nfsm_mtofh(dvp, newvp, v3, gotvp);
! 1718: if (v3)
! 1719: nfsm_wcc_data(dvp, wccflag);
! 1720: nfsm_reqdone;
! 1721: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1722: if (!wccflag)
! 1723: VTONFS(dvp)->n_attrstamp = 0;
! 1724: /*
! 1725: * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
! 1726: * if we can succeed in looking up the directory.
! 1727: */
! 1728: if (error == EEXIST || (!error && !gotvp)) {
! 1729: if (newvp) {
! 1730: vrele(newvp);
! 1731: newvp = (struct vnode *)0;
! 1732: }
! 1733: error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
! 1734: cnp->cn_proc, &np);
! 1735: if (!error) {
! 1736: newvp = NFSTOV(np);
! 1737: if (newvp->v_type != VDIR)
! 1738: error = EEXIST;
! 1739: }
! 1740: }
! 1741: if (error) {
! 1742: if (newvp)
! 1743: vrele(newvp);
! 1744: } else {
! 1745: VN_KNOTE(dvp, NOTE_WRITE|NOTE_LINK);
! 1746: *ap->a_vpp = newvp;
! 1747: }
! 1748: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1749: vrele(dvp);
! 1750: return (error);
! 1751: }
! 1752:
! 1753: /*
! 1754: * nfs remove directory call
! 1755: */
! 1756: int
! 1757: nfs_rmdir(v)
! 1758: void *v;
! 1759: {
! 1760: struct vop_rmdir_args *ap = v;
! 1761: struct vnode *vp = ap->a_vp;
! 1762: struct vnode *dvp = ap->a_dvp;
! 1763: struct componentname *cnp = ap->a_cnp;
! 1764: u_int32_t *tl;
! 1765: caddr_t cp;
! 1766: int32_t t1, t2;
! 1767: caddr_t bpos, dpos, cp2;
! 1768: int error = 0, wccflag = NFSV3_WCCRATTR;
! 1769: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1770: int v3 = NFS_ISV3(dvp);
! 1771:
! 1772: if (dvp == vp) {
! 1773: vrele(dvp);
! 1774: vrele(dvp);
! 1775: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1776: return (EINVAL);
! 1777: }
! 1778: nfsstats.rpccnt[NFSPROC_RMDIR]++;
! 1779: nfsm_reqhead(dvp, NFSPROC_RMDIR,
! 1780: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
! 1781: nfsm_fhtom(dvp, v3);
! 1782: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
! 1783: nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
! 1784: if (v3)
! 1785: nfsm_wcc_data(dvp, wccflag);
! 1786: nfsm_reqdone;
! 1787: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1788: VTONFS(dvp)->n_flag |= NMODIFIED;
! 1789: if (!wccflag)
! 1790: VTONFS(dvp)->n_attrstamp = 0;
! 1791:
! 1792: VN_KNOTE(dvp, NOTE_WRITE|NOTE_LINK);
! 1793: VN_KNOTE(vp, NOTE_DELETE);
! 1794:
! 1795: cache_purge(dvp);
! 1796: cache_purge(vp);
! 1797: vrele(vp);
! 1798: vrele(dvp);
! 1799: /*
! 1800: * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
! 1801: */
! 1802: if (error == ENOENT)
! 1803: error = 0;
! 1804: return (error);
! 1805: }
! 1806:
! 1807:
! 1808: /*
! 1809: * The readdir logic below has a big design bug. It stores the NFS cookie in
! 1810: * the returned uio->uio_offset but does not store the verifier (it cannot).
! 1811: * Instead, the code stores the verifier in the nfsnode and applies that
! 1812: * verifies to all cookies, no matter what verifier was originally with
! 1813: * the cookie.
! 1814: *
! 1815: * From a practical standpoint, this is not a problem since almost all
! 1816: * NFS servers do not change the validity of cookies across deletes
! 1817: * and inserts.
! 1818: */
! 1819:
! 1820: struct nfs_dirent {
! 1821: u_int32_t cookie[2];
! 1822: struct dirent dirent;
! 1823: };
! 1824:
! 1825: #define NFS_DIRHDSIZ (sizeof (struct nfs_dirent) - (MAXNAMLEN + 1))
! 1826: #define NFS_DIRENT_OVERHEAD offsetof(struct nfs_dirent, dirent)
! 1827:
! 1828: /*
! 1829: * nfs readdir call
! 1830: */
! 1831: int
! 1832: nfs_readdir(v)
! 1833: void *v;
! 1834: {
! 1835: struct vop_readdir_args *ap = v;
! 1836: struct vnode *vp = ap->a_vp;
! 1837: struct nfsnode *np = VTONFS(vp);
! 1838: struct uio *uio = ap->a_uio;
! 1839: int tresid, error;
! 1840: struct vattr vattr;
! 1841: u_long *cookies = NULL;
! 1842: int ncookies = 0, cnt;
! 1843: u_int64_t newoff = uio->uio_offset;
! 1844: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 1845: struct uio readdir_uio;
! 1846: struct iovec readdir_iovec;
! 1847: struct proc * p = uio->uio_procp;
! 1848: int done = 0, eof = 0;
! 1849: struct ucred *cred = ap->a_cred;
! 1850: void *data;
! 1851:
! 1852: if (vp->v_type != VDIR)
! 1853: return (EPERM);
! 1854: /*
! 1855: * First, check for hit on the EOF offset cache
! 1856: */
! 1857: if (np->n_direofoffset != 0 &&
! 1858: uio->uio_offset == np->n_direofoffset) {
! 1859: if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
! 1860: np->n_mtime == vattr.va_mtime.tv_sec) {
! 1861: nfsstats.direofcache_hits++;
! 1862: *ap->a_eofflag = 1;
! 1863: return (0);
! 1864: }
! 1865: }
! 1866:
! 1867: if (uio->uio_resid < NFS_FABLKSIZE)
! 1868: return (EINVAL);
! 1869:
! 1870: tresid = uio->uio_resid;
! 1871:
! 1872: if (uio->uio_rw != UIO_READ)
! 1873: return (EINVAL);
! 1874:
! 1875: if (ap->a_cookies) {
! 1876: ncookies = uio->uio_resid / 20;
! 1877:
! 1878: MALLOC(cookies, u_long *, sizeof(*cookies) * ncookies,
! 1879: M_TEMP, M_WAITOK);
! 1880: *ap->a_ncookies = ncookies;
! 1881: *ap->a_cookies = cookies;
! 1882: }
! 1883:
! 1884: if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
! 1885: (void)nfs_fsinfo(nmp, vp, cred, p);
! 1886:
! 1887: cnt = 5;
! 1888:
! 1889: MALLOC(data, void *, NFS_DIRBLKSIZ, M_TEMP,
! 1890: M_WAITOK);
! 1891:
! 1892: do {
! 1893: struct nfs_dirent *ndp = data;
! 1894:
! 1895: readdir_iovec.iov_len = NFS_DIRBLKSIZ;
! 1896: readdir_iovec.iov_base = data;
! 1897: readdir_uio.uio_offset = newoff;
! 1898: readdir_uio.uio_iov = &readdir_iovec;
! 1899: readdir_uio.uio_iovcnt = 1;
! 1900: readdir_uio.uio_segflg = UIO_SYSSPACE;
! 1901: readdir_uio.uio_rw = UIO_READ;
! 1902: readdir_uio.uio_resid = NFS_DIRBLKSIZ;
! 1903: readdir_uio.uio_procp = curproc;
! 1904:
! 1905: if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
! 1906: error = nfs_readdirplusrpc(vp, &readdir_uio, cred,
! 1907: &eof);
! 1908: if (error == NFSERR_NOTSUPP)
! 1909: nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
! 1910: }
! 1911: if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
! 1912: error = nfs_readdirrpc(vp, &readdir_uio, cred, &eof);
! 1913:
! 1914: if (error == NFSERR_BAD_COOKIE)
! 1915: error = EINVAL;
! 1916:
! 1917: while (error == 0 &&
! 1918: (ap->a_cookies == NULL || ncookies != 0) &&
! 1919: ndp < (struct nfs_dirent *)readdir_iovec.iov_base) {
! 1920: struct dirent *dp = &ndp->dirent;
! 1921: int reclen = dp->d_reclen;
! 1922:
! 1923: dp->d_reclen -= NFS_DIRENT_OVERHEAD;
! 1924:
! 1925: if (uio->uio_resid < dp->d_reclen) {
! 1926: eof = 0;
! 1927: done = 1;
! 1928: break;
! 1929: }
! 1930:
! 1931: error = uiomove((caddr_t)dp, dp->d_reclen, uio);
! 1932: if (error)
! 1933: break;
! 1934:
! 1935: newoff = fxdr_hyper(&ndp->cookie[0]);
! 1936:
! 1937: if (ap->a_cookies != NULL) {
! 1938: *cookies = newoff;
! 1939: cookies++;
! 1940: ncookies--;
! 1941: }
! 1942:
! 1943: ndp = (struct nfs_dirent *)((u_int8_t *)ndp + reclen);
! 1944: }
! 1945: } while (!error && !done && !eof && cnt--);
! 1946:
! 1947: FREE(data, M_TEMP);
! 1948: data = NULL;
! 1949:
! 1950: if (ap->a_cookies) {
! 1951: if (error) {
! 1952: FREE(*ap->a_cookies, M_TEMP);
! 1953: *ap->a_cookies = NULL;
! 1954: *ap->a_ncookies = 0;
! 1955: } else {
! 1956: *ap->a_ncookies -= ncookies;
! 1957: }
! 1958: }
! 1959:
! 1960: if (!error)
! 1961: uio->uio_offset = newoff;
! 1962:
! 1963: if (!error && (eof || uio->uio_resid == tresid)) {
! 1964: nfsstats.direofcache_misses++;
! 1965: *ap->a_eofflag = 1;
! 1966: return (0);
! 1967: }
! 1968:
! 1969: *ap->a_eofflag = 0;
! 1970: return (error);
! 1971: }
! 1972:
! 1973:
! 1974: /*
! 1975: * The function below stuff the cookies in after the name
! 1976: */
! 1977:
! 1978: /*
! 1979: * Readdir rpc call.
! 1980: */
! 1981: int
! 1982: nfs_readdirrpc(struct vnode *vp,
! 1983: struct uio *uiop,
! 1984: struct ucred *cred,
! 1985: int *end_of_directory)
! 1986: {
! 1987: int len, left;
! 1988: struct nfs_dirent *ndp = NULL;
! 1989: struct dirent *dp = NULL;
! 1990: u_int32_t *tl;
! 1991: caddr_t cp;
! 1992: int32_t t1, t2;
! 1993: caddr_t bpos, dpos, cp2;
! 1994: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 1995: nfsuint64 cookie;
! 1996: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 1997: struct nfsnode *dnp = VTONFS(vp);
! 1998: u_quad_t fileno;
! 1999: int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
! 2000: int attrflag;
! 2001: int v3 = NFS_ISV3(vp);
! 2002:
! 2003: #ifndef DIAGNOSTIC
! 2004: if (uiop->uio_iovcnt != 1 ||
! 2005: (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
! 2006: panic("nfs readdirrpc bad uio");
! 2007: #endif
! 2008:
! 2009: txdr_hyper(uiop->uio_offset, &cookie.nfsuquad[0]);
! 2010:
! 2011: /*
! 2012: * Loop around doing readdir rpc's of size nm_readdirsize
! 2013: * truncated to a multiple of NFS_READDIRBLKSIZ.
! 2014: * The stopping criteria is EOF or buffer full.
! 2015: */
! 2016: while (more_dirs && bigenough) {
! 2017: nfsstats.rpccnt[NFSPROC_READDIR]++;
! 2018: nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
! 2019: NFSX_READDIR(v3));
! 2020: nfsm_fhtom(vp, v3);
! 2021: if (v3) {
! 2022: nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
! 2023: *tl++ = cookie.nfsuquad[0];
! 2024: *tl++ = cookie.nfsuquad[1];
! 2025: if (cookie.nfsuquad[0] == 0 &&
! 2026: cookie.nfsuquad[1] == 0) {
! 2027: *tl++ = 0;
! 2028: *tl++ = 0;
! 2029: } else {
! 2030: *tl++ = dnp->n_cookieverf.nfsuquad[0];
! 2031: *tl++ = dnp->n_cookieverf.nfsuquad[1];
! 2032: }
! 2033: } else {
! 2034: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 2035: *tl++ = cookie.nfsuquad[1];
! 2036: }
! 2037: *tl = txdr_unsigned(nmp->nm_readdirsize);
! 2038: nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
! 2039: if (v3) {
! 2040: nfsm_postop_attr(vp, attrflag);
! 2041: if (!error) {
! 2042: nfsm_dissect(tl, u_int32_t *,
! 2043: 2 * NFSX_UNSIGNED);
! 2044: dnp->n_cookieverf.nfsuquad[0] = *tl++;
! 2045: dnp->n_cookieverf.nfsuquad[1] = *tl;
! 2046: } else {
! 2047: m_freem(mrep);
! 2048: goto nfsmout;
! 2049: }
! 2050: }
! 2051: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2052: more_dirs = fxdr_unsigned(int, *tl);
! 2053:
! 2054: /* loop thru the dir entries, doctoring them to 4bsd form */
! 2055: while (more_dirs && bigenough) {
! 2056: if (v3) {
! 2057: nfsm_dissect(tl, u_int32_t *,
! 2058: 3 * NFSX_UNSIGNED);
! 2059: fileno = fxdr_hyper(tl);
! 2060: len = fxdr_unsigned(int, *(tl + 2));
! 2061: } else {
! 2062: nfsm_dissect(tl, u_int32_t *,
! 2063: 2 * NFSX_UNSIGNED);
! 2064: fileno = fxdr_unsigned(u_quad_t, *tl++);
! 2065: len = fxdr_unsigned(int, *tl);
! 2066: }
! 2067: if (len <= 0 || len > NFS_MAXNAMLEN) {
! 2068: error = EBADRPC;
! 2069: m_freem(mrep);
! 2070: goto nfsmout;
! 2071: }
! 2072: tlen = nfsm_rndup(len + 1);
! 2073: left = NFS_READDIRBLKSIZ - blksiz;
! 2074: if ((tlen + NFS_DIRHDSIZ) > left) {
! 2075: dp->d_reclen += left;
! 2076: uiop->uio_iov->iov_base += left;
! 2077: uiop->uio_iov->iov_len -= left;
! 2078: uiop->uio_resid -= left;
! 2079: blksiz = 0;
! 2080: }
! 2081: if ((tlen + NFS_DIRHDSIZ) > uiop->uio_resid)
! 2082: bigenough = 0;
! 2083: if (bigenough) {
! 2084: ndp = (struct nfs_dirent *)
! 2085: uiop->uio_iov->iov_base;
! 2086: dp = &ndp->dirent;
! 2087: dp->d_fileno = (int)fileno;
! 2088: dp->d_namlen = len;
! 2089: dp->d_reclen = tlen + NFS_DIRHDSIZ;
! 2090: dp->d_type = DT_UNKNOWN;
! 2091: blksiz += dp->d_reclen;
! 2092: if (blksiz == NFS_READDIRBLKSIZ)
! 2093: blksiz = 0;
! 2094: uiop->uio_resid -= NFS_DIRHDSIZ;
! 2095: (char *)uiop->uio_iov->iov_base += NFS_DIRHDSIZ;
! 2096: uiop->uio_iov->iov_len -= NFS_DIRHDSIZ;
! 2097: nfsm_mtouio(uiop, len);
! 2098: cp = uiop->uio_iov->iov_base;
! 2099: tlen -= len;
! 2100: *cp = '\0'; /* null terminate */
! 2101: uiop->uio_iov->iov_base += tlen;
! 2102: uiop->uio_iov->iov_len -= tlen;
! 2103: uiop->uio_resid -= tlen;
! 2104: } else
! 2105: nfsm_adv(nfsm_rndup(len));
! 2106: if (v3) {
! 2107: nfsm_dissect(tl, u_int32_t *,
! 2108: 3 * NFSX_UNSIGNED);
! 2109: } else {
! 2110: nfsm_dissect(tl, u_int32_t *,
! 2111: 2 * NFSX_UNSIGNED);
! 2112: }
! 2113: if (bigenough) {
! 2114: if (v3) {
! 2115: ndp->cookie[0] = cookie.nfsuquad[0] =
! 2116: *tl++;
! 2117: } else
! 2118: ndp->cookie[0] = 0;
! 2119:
! 2120: ndp->cookie[1] = cookie.nfsuquad[1] = *tl++;
! 2121: } else if (v3)
! 2122: tl += 2;
! 2123: else
! 2124: tl++;
! 2125: more_dirs = fxdr_unsigned(int, *tl);
! 2126: }
! 2127: /*
! 2128: * If at end of rpc data, get the eof boolean
! 2129: */
! 2130: if (!more_dirs) {
! 2131: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2132: more_dirs = (fxdr_unsigned(int, *tl) == 0);
! 2133: }
! 2134: m_freem(mrep);
! 2135: }
! 2136: /*
! 2137: * Fill last record, iff any, out to a multiple of NFS_READDIRBLKSIZ
! 2138: * by increasing d_reclen for the last record.
! 2139: */
! 2140: if (blksiz > 0) {
! 2141: left = NFS_READDIRBLKSIZ - blksiz;
! 2142: dp->d_reclen += left;
! 2143: (char *)uiop->uio_iov->iov_base += left;
! 2144: uiop->uio_iov->iov_len -= left;
! 2145: uiop->uio_resid -= left;
! 2146: }
! 2147:
! 2148: /*
! 2149: * We are now either at the end of the directory or have filled the
! 2150: * block.
! 2151: */
! 2152: if (bigenough) {
! 2153: dnp->n_direofoffset = fxdr_hyper(&cookie.nfsuquad[0]);
! 2154: if (end_of_directory) *end_of_directory = 1;
! 2155: } else {
! 2156: if (uiop->uio_resid > 0)
! 2157: printf("EEK! readdirrpc resid > 0\n");
! 2158: }
! 2159:
! 2160: nfsmout:
! 2161: return (error);
! 2162: }
! 2163:
! 2164: /*
! 2165: * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
! 2166: */
! 2167: int
! 2168: nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
! 2169: int *end_of_directory)
! 2170: {
! 2171: int len, left;
! 2172: struct nfs_dirent *ndirp = NULL;
! 2173: struct dirent *dp = NULL;
! 2174: u_int32_t *tl;
! 2175: caddr_t cp;
! 2176: int32_t t1, t2;
! 2177: struct vnode *newvp;
! 2178: caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
! 2179: struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
! 2180: struct nameidata nami, *ndp = &nami;
! 2181: struct componentname *cnp = &ndp->ni_cnd;
! 2182: nfsuint64 cookie;
! 2183: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 2184: struct nfsnode *dnp = VTONFS(vp), *np;
! 2185: nfsfh_t *fhp;
! 2186: u_quad_t fileno;
! 2187: int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
! 2188: int attrflag, fhsize;
! 2189:
! 2190: #ifndef DIAGNOSTIC
! 2191: if (uiop->uio_iovcnt != 1 ||
! 2192: (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
! 2193: panic("nfs readdirplusrpc bad uio");
! 2194: #endif
! 2195: ndp->ni_dvp = vp;
! 2196: newvp = NULLVP;
! 2197:
! 2198: txdr_hyper(uiop->uio_offset, &cookie.nfsuquad[0]);
! 2199:
! 2200: /*
! 2201: * Loop around doing readdir rpc's of size nm_readdirsize
! 2202: * truncated to a multiple of NFS_READDIRBLKSIZ.
! 2203: * The stopping criteria is EOF or buffer full.
! 2204: */
! 2205: while (more_dirs && bigenough) {
! 2206: nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
! 2207: nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
! 2208: NFSX_FH(1) + 6 * NFSX_UNSIGNED);
! 2209: nfsm_fhtom(vp, 1);
! 2210: nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
! 2211: *tl++ = cookie.nfsuquad[0];
! 2212: *tl++ = cookie.nfsuquad[1];
! 2213: if (cookie.nfsuquad[0] == 0 &&
! 2214: cookie.nfsuquad[1] == 0) {
! 2215: *tl++ = 0;
! 2216: *tl++ = 0;
! 2217: } else {
! 2218: *tl++ = dnp->n_cookieverf.nfsuquad[0];
! 2219: *tl++ = dnp->n_cookieverf.nfsuquad[1];
! 2220: }
! 2221: *tl++ = txdr_unsigned(nmp->nm_readdirsize);
! 2222: *tl = txdr_unsigned(nmp->nm_rsize);
! 2223: nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
! 2224: nfsm_postop_attr(vp, attrflag);
! 2225: if (error) {
! 2226: m_freem(mrep);
! 2227: goto nfsmout;
! 2228: }
! 2229: nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
! 2230: dnp->n_cookieverf.nfsuquad[0] = *tl++;
! 2231: dnp->n_cookieverf.nfsuquad[1] = *tl++;
! 2232: more_dirs = fxdr_unsigned(int, *tl);
! 2233:
! 2234: /* loop thru the dir entries, doctoring them to 4bsd form */
! 2235: while (more_dirs && bigenough) {
! 2236: nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
! 2237: fileno = fxdr_hyper(tl);
! 2238: len = fxdr_unsigned(int, *(tl + 2));
! 2239: if (len <= 0 || len > NFS_MAXNAMLEN) {
! 2240: error = EBADRPC;
! 2241: m_freem(mrep);
! 2242: goto nfsmout;
! 2243: }
! 2244: tlen = nfsm_rndup(len + 1);
! 2245: left = NFS_READDIRBLKSIZ - blksiz;
! 2246: if ((tlen + NFS_DIRHDSIZ) > left) {
! 2247: dp->d_reclen += left;
! 2248: (char *)uiop->uio_iov->iov_base += left;
! 2249: uiop->uio_iov->iov_len -= left;
! 2250: uiop->uio_resid -= left;
! 2251: blksiz = 0;
! 2252: }
! 2253: if ((tlen + NFS_DIRHDSIZ) > uiop->uio_resid)
! 2254: bigenough = 0;
! 2255: if (bigenough) {
! 2256: ndirp = (struct nfs_dirent *)
! 2257: uiop->uio_iov->iov_base;
! 2258: dp = &ndirp->dirent;
! 2259: dp->d_fileno = (int)fileno;
! 2260: dp->d_namlen = len;
! 2261: dp->d_reclen = tlen + NFS_DIRHDSIZ;
! 2262: dp->d_type = DT_UNKNOWN;
! 2263: blksiz += dp->d_reclen;
! 2264: if (blksiz == NFS_READDIRBLKSIZ)
! 2265: blksiz = 0;
! 2266: uiop->uio_resid -= NFS_DIRHDSIZ;
! 2267: (char *)uiop->uio_iov->iov_base += NFS_DIRHDSIZ;
! 2268: uiop->uio_iov->iov_len -= NFS_DIRHDSIZ;
! 2269: cnp->cn_nameptr = uiop->uio_iov->iov_base;
! 2270: cnp->cn_namelen = len;
! 2271: nfsm_mtouio(uiop, len);
! 2272: cp = uiop->uio_iov->iov_base;
! 2273: tlen -= len;
! 2274: *cp = '\0';
! 2275: uiop->uio_iov->iov_base += tlen;
! 2276: uiop->uio_iov->iov_len -= tlen;
! 2277: uiop->uio_resid -= tlen;
! 2278: } else
! 2279: nfsm_adv(nfsm_rndup(len));
! 2280: nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
! 2281: if (bigenough) {
! 2282: ndirp->cookie[0] = cookie.nfsuquad[0] = *tl++;
! 2283: ndirp->cookie[1] = cookie.nfsuquad[1] = *tl++;
! 2284: } else
! 2285: tl += 2;
! 2286:
! 2287: /*
! 2288: * Since the attributes are before the file handle
! 2289: * (sigh), we must skip over the attributes and then
! 2290: * come back and get them.
! 2291: */
! 2292: attrflag = fxdr_unsigned(int, *tl);
! 2293: if (attrflag) {
! 2294: dpossav1 = dpos;
! 2295: mdsav1 = md;
! 2296: nfsm_adv(NFSX_V3FATTR);
! 2297: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2298: doit = fxdr_unsigned(int, *tl);
! 2299: if (doit) {
! 2300: nfsm_getfh(fhp, fhsize, 1);
! 2301: if (NFS_CMPFH(dnp, fhp, fhsize)) {
! 2302: VREF(vp);
! 2303: newvp = vp;
! 2304: np = dnp;
! 2305: } else {
! 2306: error = nfs_nget(vp->v_mount, fhp,
! 2307: fhsize, &np);
! 2308: if (error)
! 2309: doit = 0;
! 2310: else
! 2311: newvp = NFSTOV(np);
! 2312: }
! 2313: }
! 2314: if (doit && bigenough) {
! 2315: dpossav2 = dpos;
! 2316: dpos = dpossav1;
! 2317: mdsav2 = md;
! 2318: md = mdsav1;
! 2319: nfsm_loadattr(newvp, (struct vattr *)0);
! 2320: dpos = dpossav2;
! 2321: md = mdsav2;
! 2322: dp->d_type =
! 2323: IFTODT(VTTOIF(np->n_vattr.va_type));
! 2324: if (cnp->cn_namelen <= NCHNAMLEN) {
! 2325: ndp->ni_vp = newvp;
! 2326: cnp->cn_hash =
! 2327: hash32_str(cnp->cn_nameptr,
! 2328: HASHINIT);
! 2329: cache_enter(ndp->ni_dvp, ndp->ni_vp,
! 2330: cnp);
! 2331: }
! 2332: }
! 2333: } else {
! 2334: /* Just skip over the file handle */
! 2335: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2336: i = fxdr_unsigned(int, *tl);
! 2337: nfsm_adv(nfsm_rndup(i));
! 2338: }
! 2339: if (newvp != NULLVP) {
! 2340: vrele(newvp);
! 2341: newvp = NULLVP;
! 2342: }
! 2343: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2344: more_dirs = fxdr_unsigned(int, *tl);
! 2345: }
! 2346: /*
! 2347: * If at end of rpc data, get the eof boolean
! 2348: */
! 2349: if (!more_dirs) {
! 2350: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
! 2351: more_dirs = (fxdr_unsigned(int, *tl) == 0);
! 2352: }
! 2353: m_freem(mrep);
! 2354: }
! 2355: /*
! 2356: * Fill last record, iff any, out to a multiple of NFS_READDIRBLKSIZ
! 2357: * by increasing d_reclen for the last record.
! 2358: */
! 2359: if (blksiz > 0) {
! 2360: left = NFS_READDIRBLKSIZ - blksiz;
! 2361: dp->d_reclen += left;
! 2362: (char *)uiop->uio_iov->iov_base += left;
! 2363: uiop->uio_iov->iov_len -= left;
! 2364: uiop->uio_resid -= left;
! 2365: }
! 2366:
! 2367: /*
! 2368: * We are now either at the end of the directory or have filled the
! 2369: * block.
! 2370: */
! 2371: if (bigenough) {
! 2372: dnp->n_direofoffset = fxdr_hyper(&cookie.nfsuquad[0]);
! 2373: if (end_of_directory) *end_of_directory = 1;
! 2374: } else {
! 2375: if (uiop->uio_resid > 0)
! 2376: printf("EEK! readdirplusrpc resid > 0\n");
! 2377: }
! 2378:
! 2379: nfsmout:
! 2380: if (newvp != NULLVP)
! 2381: vrele(newvp);
! 2382: return (error);
! 2383: }
! 2384:
! 2385: /*
! 2386: * Silly rename. To make the NFS filesystem that is stateless look a little
! 2387: * more like the "ufs" a remove of an active vnode is translated to a rename
! 2388: * to a funny looking filename that is removed by nfs_inactive on the
! 2389: * nfsnode. There is the potential for another process on a different client
! 2390: * to create the same funny name between the nfs_lookitup() fails and the
! 2391: * nfs_rename() completes, but...
! 2392: */
! 2393: int
! 2394: nfs_sillyrename(dvp, vp, cnp)
! 2395: struct vnode *dvp, *vp;
! 2396: struct componentname *cnp;
! 2397: {
! 2398: struct sillyrename *sp;
! 2399: struct nfsnode *np;
! 2400: int error;
! 2401:
! 2402: cache_purge(dvp);
! 2403: np = VTONFS(vp);
! 2404: MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
! 2405: M_NFSREQ, M_WAITOK);
! 2406: sp->s_cred = crdup(cnp->cn_cred);
! 2407: sp->s_dvp = dvp;
! 2408: VREF(dvp);
! 2409:
! 2410: if (vp->v_type == VDIR) {
! 2411: #ifdef DIAGNOSTIC
! 2412: printf("nfs: sillyrename dir\n");
! 2413: #endif
! 2414: error = EINVAL;
! 2415: goto bad;
! 2416: }
! 2417:
! 2418: /* Fudge together a funny name */
! 2419: sp->s_namlen = snprintf(sp->s_name, sizeof sp->s_name,
! 2420: ".nfsA%05x4.4", cnp->cn_proc->p_pid);
! 2421: if (sp->s_namlen > sizeof sp->s_name)
! 2422: sp->s_namlen = strlen(sp->s_name);
! 2423:
! 2424: /* Try lookitups until we get one that isn't there */
! 2425: while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
! 2426: cnp->cn_proc, (struct nfsnode **)0) == 0) {
! 2427: sp->s_name[4]++;
! 2428: if (sp->s_name[4] > 'z') {
! 2429: error = EINVAL;
! 2430: goto bad;
! 2431: }
! 2432: }
! 2433: error = nfs_renameit(dvp, cnp, sp);
! 2434: if (error)
! 2435: goto bad;
! 2436: error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
! 2437: cnp->cn_proc, &np);
! 2438: np->n_sillyrename = sp;
! 2439: return (0);
! 2440: bad:
! 2441: vrele(sp->s_dvp);
! 2442: crfree(sp->s_cred);
! 2443: FREE((caddr_t)sp, M_NFSREQ);
! 2444: return (error);
! 2445: }
! 2446:
! 2447: /*
! 2448: * Look up a file name and optionally either update the file handle or
! 2449: * allocate an nfsnode, depending on the value of npp.
! 2450: * npp == NULL --> just do the lookup
! 2451: * *npp == NULL --> allocate a new nfsnode and make sure attributes are
! 2452: * handled too
! 2453: * *npp != NULL --> update the file handle in the vnode
! 2454: */
! 2455: int
! 2456: nfs_lookitup(dvp, name, len, cred, procp, npp)
! 2457: struct vnode *dvp;
! 2458: char *name;
! 2459: int len;
! 2460: struct ucred *cred;
! 2461: struct proc *procp;
! 2462: struct nfsnode **npp;
! 2463: {
! 2464: u_int32_t *tl;
! 2465: caddr_t cp;
! 2466: int32_t t1, t2;
! 2467: struct vnode *newvp = (struct vnode *)0;
! 2468: struct nfsnode *np, *dnp = VTONFS(dvp);
! 2469: caddr_t bpos, dpos, cp2;
! 2470: int error = 0, fhlen, attrflag;
! 2471: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 2472: nfsfh_t *nfhp;
! 2473: int v3 = NFS_ISV3(dvp);
! 2474:
! 2475: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
! 2476: nfsm_reqhead(dvp, NFSPROC_LOOKUP,
! 2477: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
! 2478: nfsm_fhtom(dvp, v3);
! 2479: nfsm_strtom(name, len, NFS_MAXNAMLEN);
! 2480: nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
! 2481: if (npp && !error) {
! 2482: nfsm_getfh(nfhp, fhlen, v3);
! 2483: if (*npp) {
! 2484: np = *npp;
! 2485: if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
! 2486: free((caddr_t)np->n_fhp, M_NFSBIGFH);
! 2487: np->n_fhp = &np->n_fh;
! 2488: } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
! 2489: np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
! 2490: bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
! 2491: np->n_fhsize = fhlen;
! 2492: newvp = NFSTOV(np);
! 2493: } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
! 2494: VREF(dvp);
! 2495: newvp = dvp;
! 2496: } else {
! 2497: error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
! 2498: if (error) {
! 2499: m_freem(mrep);
! 2500: return (error);
! 2501: }
! 2502: newvp = NFSTOV(np);
! 2503: }
! 2504: if (v3) {
! 2505: nfsm_postop_attr(newvp, attrflag);
! 2506: if (!attrflag && *npp == NULL) {
! 2507: m_freem(mrep);
! 2508: vrele(newvp);
! 2509: return (ENOENT);
! 2510: }
! 2511: } else
! 2512: nfsm_loadattr(newvp, (struct vattr *)0);
! 2513: }
! 2514: nfsm_reqdone;
! 2515: if (npp && *npp == NULL) {
! 2516: if (error) {
! 2517: if (newvp)
! 2518: vrele(newvp);
! 2519: } else
! 2520: *npp = np;
! 2521: }
! 2522: return (error);
! 2523: }
! 2524:
! 2525: /*
! 2526: * Nfs Version 3 commit rpc
! 2527: */
! 2528: int
! 2529: nfs_commit(vp, offset, cnt, procp)
! 2530: struct vnode *vp;
! 2531: u_quad_t offset;
! 2532: int cnt;
! 2533: struct proc *procp;
! 2534: {
! 2535: caddr_t cp;
! 2536: u_int32_t *tl;
! 2537: int32_t t1, t2;
! 2538: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 2539: caddr_t bpos, dpos, cp2;
! 2540: int error = 0, wccflag = NFSV3_WCCRATTR;
! 2541: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
! 2542:
! 2543: if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
! 2544: return (0);
! 2545: nfsstats.rpccnt[NFSPROC_COMMIT]++;
! 2546: nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
! 2547: nfsm_fhtom(vp, 1);
! 2548: nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
! 2549: txdr_hyper(offset, tl);
! 2550: tl += 2;
! 2551: *tl = txdr_unsigned(cnt);
! 2552: nfsm_request(vp, NFSPROC_COMMIT, procp, VTONFS(vp)->n_wcred);
! 2553: nfsm_wcc_data(vp, wccflag);
! 2554: if (!error) {
! 2555: nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF);
! 2556: if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
! 2557: NFSX_V3WRITEVERF)) {
! 2558: bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
! 2559: NFSX_V3WRITEVERF);
! 2560: error = NFSERR_STALEWRITEVERF;
! 2561: }
! 2562: }
! 2563: nfsm_reqdone;
! 2564: return (error);
! 2565: }
! 2566:
! 2567: /*
! 2568: * Kludge City..
! 2569: * - make nfs_bmap() essentially a no-op that does no translation
! 2570: * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
! 2571: * (Maybe I could use the process's page mapping, but I was concerned that
! 2572: * Kernel Write might not be enabled and also figured copyout() would do
! 2573: * a lot more work than bcopy() and also it currently happens in the
! 2574: * context of the swapper process (2).
! 2575: */
! 2576: int
! 2577: nfs_bmap(v)
! 2578: void *v;
! 2579: {
! 2580: struct vop_bmap_args *ap = v;
! 2581: struct vnode *vp = ap->a_vp;
! 2582:
! 2583: if (ap->a_vpp != NULL)
! 2584: *ap->a_vpp = vp;
! 2585: if (ap->a_bnp != NULL)
! 2586: *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
! 2587: return (0);
! 2588: }
! 2589:
! 2590: /*
! 2591: * Strategy routine.
! 2592: * For async requests when nfsiod(s) are running, queue the request by
! 2593: * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
! 2594: * request.
! 2595: */
! 2596: int
! 2597: nfs_strategy(v)
! 2598: void *v;
! 2599: {
! 2600: struct vop_strategy_args *ap = v;
! 2601: struct buf *bp = ap->a_bp;
! 2602: struct proc *p;
! 2603: int error = 0;
! 2604:
! 2605: if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC))
! 2606: panic("nfs physio/async");
! 2607: if (bp->b_flags & B_ASYNC)
! 2608: p = NULL;
! 2609: else
! 2610: p = curproc; /* XXX */
! 2611: /*
! 2612: * If the op is asynchronous and an i/o daemon is waiting
! 2613: * queue the request, wake it up and wait for completion
! 2614: * otherwise just do it ourselves.
! 2615: */
! 2616: if ((bp->b_flags & B_ASYNC) == 0 || nfs_asyncio(bp))
! 2617: error = nfs_doio(bp, p);
! 2618: return (error);
! 2619: }
! 2620:
! 2621: /*
! 2622: * fsync vnode op. Just call nfs_flush() with commit == 1.
! 2623: */
! 2624: /* ARGSUSED */
! 2625: int
! 2626: nfs_fsync(v)
! 2627: void *v;
! 2628: {
! 2629: struct vop_fsync_args *ap = v;
! 2630:
! 2631: return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
! 2632: }
! 2633:
! 2634: /*
! 2635: * Flush all the blocks associated with a vnode.
! 2636: * Walk through the buffer pool and push any dirty pages
! 2637: * associated with the vnode.
! 2638: */
! 2639: int
! 2640: nfs_flush(vp, cred, waitfor, p, commit)
! 2641: struct vnode *vp;
! 2642: struct ucred *cred;
! 2643: int waitfor;
! 2644: struct proc *p;
! 2645: int commit;
! 2646: {
! 2647: struct nfsnode *np = VTONFS(vp);
! 2648: struct buf *bp;
! 2649: int i;
! 2650: struct buf *nbp;
! 2651: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 2652: int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
! 2653: int passone = 1;
! 2654: u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
! 2655: #ifndef NFS_COMMITBVECSIZ
! 2656: #define NFS_COMMITBVECSIZ 20
! 2657: #endif
! 2658: struct buf *bvec[NFS_COMMITBVECSIZ];
! 2659:
! 2660: if (nmp->nm_flag & NFSMNT_INT)
! 2661: slpflag = PCATCH;
! 2662: if (!commit)
! 2663: passone = 0;
! 2664: /*
! 2665: * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
! 2666: * server, but nas not been committed to stable storage on the server
! 2667: * yet. On the first pass, the byte range is worked out and the commit
! 2668: * rpc is done. On the second pass, nfs_writebp() is called to do the
! 2669: * job.
! 2670: */
! 2671: again:
! 2672: bvecpos = 0;
! 2673: if (NFS_ISV3(vp) && commit) {
! 2674: s = splbio();
! 2675: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) {
! 2676: nbp = LIST_NEXT(bp, b_vnbufs);
! 2677: if (bvecpos >= NFS_COMMITBVECSIZ)
! 2678: break;
! 2679: if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
! 2680: != (B_DELWRI | B_NEEDCOMMIT))
! 2681: continue;
! 2682: bremfree(bp);
! 2683: bp->b_flags |= (B_BUSY | B_WRITEINPROG);
! 2684: /*
! 2685: * A list of these buffers is kept so that the
! 2686: * second loop knows which buffers have actually
! 2687: * been committed. This is necessary, since there
! 2688: * may be a race between the commit rpc and new
! 2689: * uncommitted writes on the file.
! 2690: */
! 2691: bvec[bvecpos++] = bp;
! 2692: toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
! 2693: bp->b_dirtyoff;
! 2694: if (toff < off)
! 2695: off = toff;
! 2696: toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
! 2697: if (toff > endoff)
! 2698: endoff = toff;
! 2699: }
! 2700: splx(s);
! 2701: }
! 2702: if (bvecpos > 0) {
! 2703: /*
! 2704: * Commit data on the server, as required.
! 2705: */
! 2706: retv = nfs_commit(vp, off, (int)(endoff - off), p);
! 2707: if (retv == NFSERR_STALEWRITEVERF)
! 2708: nfs_clearcommit(vp->v_mount);
! 2709: /*
! 2710: * Now, either mark the blocks I/O done or mark the
! 2711: * blocks dirty, depending on whether the commit
! 2712: * succeeded.
! 2713: */
! 2714: for (i = 0; i < bvecpos; i++) {
! 2715: bp = bvec[i];
! 2716: bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
! 2717: if (retv)
! 2718: brelse(bp);
! 2719: else {
! 2720: s = splbio();
! 2721: buf_undirty(bp);
! 2722: vp->v_numoutput++;
! 2723: bp->b_flags |= B_ASYNC;
! 2724: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR);
! 2725: bp->b_dirtyoff = bp->b_dirtyend = 0;
! 2726: biodone(bp);
! 2727: splx(s);
! 2728: }
! 2729: }
! 2730: }
! 2731:
! 2732: /*
! 2733: * Start/do any write(s) that are required.
! 2734: */
! 2735: loop:
! 2736: s = splbio();
! 2737: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) {
! 2738: nbp = LIST_NEXT(bp, b_vnbufs);
! 2739: if (bp->b_flags & B_BUSY) {
! 2740: if (waitfor != MNT_WAIT || passone)
! 2741: continue;
! 2742: bp->b_flags |= B_WANTED;
! 2743: error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
! 2744: "nfsfsync", slptimeo);
! 2745: splx(s);
! 2746: if (error) {
! 2747: if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
! 2748: return (EINTR);
! 2749: if (slpflag == PCATCH) {
! 2750: slpflag = 0;
! 2751: slptimeo = 2 * hz;
! 2752: }
! 2753: }
! 2754: goto loop;
! 2755: }
! 2756: if ((bp->b_flags & B_DELWRI) == 0)
! 2757: panic("nfs_fsync: not dirty");
! 2758: if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
! 2759: continue;
! 2760: bremfree(bp);
! 2761: if (passone || !commit)
! 2762: bp->b_flags |= (B_BUSY|B_ASYNC);
! 2763: else
! 2764: bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
! 2765: splx(s);
! 2766: VOP_BWRITE(bp);
! 2767: goto loop;
! 2768: }
! 2769: splx(s);
! 2770: if (passone) {
! 2771: passone = 0;
! 2772: goto again;
! 2773: }
! 2774: if (waitfor == MNT_WAIT) {
! 2775: loop2:
! 2776: s = splbio();
! 2777: error = vwaitforio(vp, slpflag, "nfs_fsync", slptimeo);
! 2778: splx(s);
! 2779: if (error) {
! 2780: if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
! 2781: return (EINTR);
! 2782: if (slpflag == PCATCH) {
! 2783: slpflag = 0;
! 2784: slptimeo = 2 * hz;
! 2785: }
! 2786: goto loop2;
! 2787: }
! 2788:
! 2789: if (LIST_FIRST(&vp->v_dirtyblkhd) && commit) {
! 2790: #if 0
! 2791: vprint("nfs_fsync: dirty", vp);
! 2792: #endif
! 2793: goto loop;
! 2794: }
! 2795: }
! 2796: if (np->n_flag & NWRITEERR) {
! 2797: error = np->n_error;
! 2798: np->n_flag &= ~NWRITEERR;
! 2799: }
! 2800: return (error);
! 2801: }
! 2802:
! 2803: /*
! 2804: * Return POSIX pathconf information applicable to nfs.
! 2805: *
! 2806: * The NFS V2 protocol doesn't support this, so just return EINVAL
! 2807: * for V2.
! 2808: */
! 2809: /* ARGSUSED */
! 2810: int
! 2811: nfs_pathconf(v)
! 2812: void *v;
! 2813: {
! 2814: #if 0
! 2815: struct vop_pathconf_args *ap = v;
! 2816: #endif
! 2817:
! 2818: return (EINVAL);
! 2819: }
! 2820:
! 2821: /*
! 2822: * NFS advisory byte-level locks.
! 2823: */
! 2824: int
! 2825: nfs_advlock(v)
! 2826: void *v;
! 2827: {
! 2828: struct vop_advlock_args *ap = v;
! 2829: struct nfsnode *np = VTONFS(ap->a_vp);
! 2830:
! 2831: return (lf_advlock(&np->n_lockf, np->n_size, ap->a_id, ap->a_op,
! 2832: ap->a_fl, ap->a_flags));
! 2833: }
! 2834:
! 2835: /*
! 2836: * Print out the contents of an nfsnode.
! 2837: */
! 2838: int
! 2839: nfs_print(v)
! 2840: void *v;
! 2841: {
! 2842: struct vop_print_args *ap = v;
! 2843: struct vnode *vp = ap->a_vp;
! 2844: struct nfsnode *np = VTONFS(vp);
! 2845:
! 2846: printf("tag VT_NFS, fileid %ld fsid 0x%lx",
! 2847: np->n_vattr.va_fileid, np->n_vattr.va_fsid);
! 2848: #ifdef FIFO
! 2849: if (vp->v_type == VFIFO)
! 2850: fifo_printinfo(vp);
! 2851: #endif
! 2852: printf("\n");
! 2853: return (0);
! 2854: }
! 2855:
! 2856: /*
! 2857: * Just call nfs_writebp() with the force argument set to 1.
! 2858: */
! 2859: int
! 2860: nfs_bwrite(v)
! 2861: void *v;
! 2862: {
! 2863: struct vop_bwrite_args *ap = v;
! 2864:
! 2865: return (nfs_writebp(ap->a_bp, 1));
! 2866: }
! 2867:
! 2868: /*
! 2869: * This is a clone of vop_generic_bwrite(), except that B_WRITEINPROG isn't set unless
! 2870: * the force flag is one and it also handles the B_NEEDCOMMIT flag.
! 2871: */
! 2872: int
! 2873: nfs_writebp(bp, force)
! 2874: struct buf *bp;
! 2875: int force;
! 2876: {
! 2877: int oldflags = bp->b_flags, retv = 1;
! 2878: struct proc *p = curproc; /* XXX */
! 2879: off_t off;
! 2880: size_t cnt;
! 2881: int s;
! 2882: struct vnode *vp;
! 2883: struct nfsnode *np;
! 2884:
! 2885: if(!(bp->b_flags & B_BUSY))
! 2886: panic("bwrite: buffer is not busy???");
! 2887:
! 2888: vp = bp->b_vp;
! 2889: np = VTONFS(vp);
! 2890:
! 2891: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR);
! 2892:
! 2893: s = splbio();
! 2894: buf_undirty(bp);
! 2895:
! 2896: if ((oldflags & B_ASYNC) && !(oldflags & B_DELWRI) && p)
! 2897: ++p->p_stats->p_ru.ru_oublock;
! 2898:
! 2899: bp->b_vp->v_numoutput++;
! 2900: splx(s);
! 2901:
! 2902: /*
! 2903: * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
! 2904: * an actual write will have to be scheduled via. VOP_STRATEGY().
! 2905: * If B_WRITEINPROG is already set, then push it with a write anyhow.
! 2906: */
! 2907: if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) {
! 2908: off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
! 2909: cnt = bp->b_dirtyend - bp->b_dirtyoff;
! 2910:
! 2911: rw_enter_write(&np->n_commitlock);
! 2912: if (!(bp->b_flags & B_NEEDCOMMIT)) {
! 2913: rw_exit_write(&np->n_commitlock);
! 2914: return (0);
! 2915: }
! 2916:
! 2917: /*
! 2918: * If it's already been commited by somebody else,
! 2919: * bail.
! 2920: */
! 2921: if (!nfs_in_committed_range(vp, bp)) {
! 2922: int pushedrange = 0;
! 2923: /*
! 2924: * Since we're going to do this, push as much
! 2925: * as we can.
! 2926: */
! 2927:
! 2928: if (nfs_in_tobecommitted_range(vp, bp)) {
! 2929: pushedrange = 1;
! 2930: off = np->n_pushlo;
! 2931: cnt = np->n_pushhi - np->n_pushlo;
! 2932: }
! 2933:
! 2934: bp->b_flags |= B_WRITEINPROG;
! 2935: retv = nfs_commit(bp->b_vp, off, cnt, bp->b_proc);
! 2936: bp->b_flags &= ~B_WRITEINPROG;
! 2937:
! 2938: if (retv == 0) {
! 2939: if (pushedrange)
! 2940: nfs_merge_commit_ranges(vp);
! 2941: else
! 2942: nfs_add_committed_range(vp, bp);
! 2943: }
! 2944: } else
! 2945: retv = 0; /* It has already been commited. */
! 2946:
! 2947: rw_exit_write(&np->n_commitlock);
! 2948: if (!retv) {
! 2949: bp->b_dirtyoff = bp->b_dirtyend = 0;
! 2950: bp->b_flags &= ~B_NEEDCOMMIT;
! 2951: s = splbio();
! 2952: biodone(bp);
! 2953: splx(s);
! 2954: } else if (retv == NFSERR_STALEWRITEVERF)
! 2955: nfs_clearcommit(bp->b_vp->v_mount);
! 2956: }
! 2957: if (retv) {
! 2958: if (force)
! 2959: bp->b_flags |= B_WRITEINPROG;
! 2960: VOP_STRATEGY(bp);
! 2961: }
! 2962:
! 2963: if( (oldflags & B_ASYNC) == 0) {
! 2964: int rtval = biowait(bp);
! 2965: if (!(oldflags & B_DELWRI) && p) {
! 2966: ++p->p_stats->p_ru.ru_oublock;
! 2967: }
! 2968: brelse(bp);
! 2969: return (rtval);
! 2970: }
! 2971:
! 2972: return (0);
! 2973: }
! 2974:
! 2975: /*
! 2976: * nfs special file access vnode op.
! 2977: * Essentially just get vattr and then imitate iaccess() since the device is
! 2978: * local to the client.
! 2979: */
! 2980: int
! 2981: nfsspec_access(v)
! 2982: void *v;
! 2983: {
! 2984: struct vop_access_args *ap = v;
! 2985: struct vattr va;
! 2986: struct vnode *vp = ap->a_vp;
! 2987: int error;
! 2988:
! 2989: /*
! 2990: * Disallow write attempts on filesystems mounted read-only;
! 2991: * unless the file is a socket, fifo, or a block or character
! 2992: * device resident on the filesystem.
! 2993: */
! 2994: if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
! 2995: switch (vp->v_type) {
! 2996: case VREG:
! 2997: case VDIR:
! 2998: case VLNK:
! 2999: return (EROFS);
! 3000: default:
! 3001: break;
! 3002: }
! 3003: }
! 3004:
! 3005: error = VOP_GETATTR(vp, &va, ap->a_cred, ap->a_p);
! 3006: if (error)
! 3007: return (error);
! 3008:
! 3009: return (vaccess(va.va_mode, va.va_uid, va.va_gid, ap->a_mode,
! 3010: ap->a_cred));
! 3011: }
! 3012:
! 3013: /* ARGSUSED */
! 3014: int
! 3015: nfs_poll(v)
! 3016: void *v;
! 3017: {
! 3018: struct vop_poll_args *ap = v;
! 3019:
! 3020: /*
! 3021: * We should really check to see if I/O is possible.
! 3022: */
! 3023: return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
! 3024: }
! 3025:
! 3026: /*
! 3027: * Read wrapper for special devices.
! 3028: */
! 3029: int
! 3030: nfsspec_read(v)
! 3031: void *v;
! 3032: {
! 3033: struct vop_read_args *ap = v;
! 3034: struct nfsnode *np = VTONFS(ap->a_vp);
! 3035:
! 3036: /*
! 3037: * Set access flag.
! 3038: */
! 3039: np->n_flag |= NACC;
! 3040: getnanotime(&np->n_atim);
! 3041: return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
! 3042: }
! 3043:
! 3044: /*
! 3045: * Write wrapper for special devices.
! 3046: */
! 3047: int
! 3048: nfsspec_write(v)
! 3049: void *v;
! 3050: {
! 3051: struct vop_write_args *ap = v;
! 3052: struct nfsnode *np = VTONFS(ap->a_vp);
! 3053:
! 3054: /*
! 3055: * Set update flag.
! 3056: */
! 3057: np->n_flag |= NUPD;
! 3058: getnanotime(&np->n_mtim);
! 3059: return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
! 3060: }
! 3061:
! 3062: /*
! 3063: * Close wrapper for special devices.
! 3064: *
! 3065: * Update the times on the nfsnode then do device close.
! 3066: */
! 3067: int
! 3068: nfsspec_close(v)
! 3069: void *v;
! 3070: {
! 3071: struct vop_close_args *ap = v;
! 3072: struct vnode *vp = ap->a_vp;
! 3073: struct nfsnode *np = VTONFS(vp);
! 3074: struct vattr vattr;
! 3075:
! 3076: if (np->n_flag & (NACC | NUPD)) {
! 3077: np->n_flag |= NCHG;
! 3078: if (vp->v_usecount == 1 &&
! 3079: (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
! 3080: VATTR_NULL(&vattr);
! 3081: if (np->n_flag & NACC)
! 3082: vattr.va_atime = np->n_atim;
! 3083: if (np->n_flag & NUPD)
! 3084: vattr.va_mtime = np->n_mtim;
! 3085: (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
! 3086: }
! 3087: }
! 3088: return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
! 3089: }
! 3090:
! 3091: #ifdef FIFO
! 3092: /*
! 3093: * Read wrapper for fifos.
! 3094: */
! 3095: int
! 3096: nfsfifo_read(v)
! 3097: void *v;
! 3098: {
! 3099: struct vop_read_args *ap = v;
! 3100: extern int (**fifo_vnodeop_p)(void *);
! 3101: struct nfsnode *np = VTONFS(ap->a_vp);
! 3102:
! 3103: /*
! 3104: * Set access flag.
! 3105: */
! 3106: np->n_flag |= NACC;
! 3107: getnanotime(&np->n_atim);
! 3108: return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
! 3109: }
! 3110:
! 3111: /*
! 3112: * Write wrapper for fifos.
! 3113: */
! 3114: int
! 3115: nfsfifo_write(v)
! 3116: void *v;
! 3117: {
! 3118: struct vop_write_args *ap = v;
! 3119: extern int (**fifo_vnodeop_p)(void *);
! 3120: struct nfsnode *np = VTONFS(ap->a_vp);
! 3121:
! 3122: /*
! 3123: * Set update flag.
! 3124: */
! 3125: np->n_flag |= NUPD;
! 3126: getnanotime(&np->n_mtim);
! 3127: return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
! 3128: }
! 3129:
! 3130: /*
! 3131: * Close wrapper for fifos.
! 3132: *
! 3133: * Update the times on the nfsnode then do fifo close.
! 3134: */
! 3135: int
! 3136: nfsfifo_close(v)
! 3137: void *v;
! 3138: {
! 3139: struct vop_close_args *ap = v;
! 3140: struct vnode *vp = ap->a_vp;
! 3141: struct nfsnode *np = VTONFS(vp);
! 3142: struct vattr vattr;
! 3143: extern int (**fifo_vnodeop_p)(void *);
! 3144:
! 3145: if (np->n_flag & (NACC | NUPD)) {
! 3146: if (np->n_flag & NACC) {
! 3147: getnanotime(&np->n_atim);
! 3148: }
! 3149: if (np->n_flag & NUPD) {
! 3150: getnanotime(&np->n_mtim);
! 3151: }
! 3152: np->n_flag |= NCHG;
! 3153: if (vp->v_usecount == 1 &&
! 3154: (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
! 3155: VATTR_NULL(&vattr);
! 3156: if (np->n_flag & NACC)
! 3157: vattr.va_atime = np->n_atim;
! 3158: if (np->n_flag & NUPD)
! 3159: vattr.va_mtime = np->n_mtim;
! 3160: (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
! 3161: }
! 3162: }
! 3163: return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
! 3164: }
! 3165:
! 3166: int
! 3167: nfsfifo_reclaim(void *v)
! 3168: {
! 3169: fifo_reclaim(v);
! 3170: return (nfs_reclaim(v));
! 3171: }
! 3172: #endif /* ! FIFO */
CVSweb