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