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