1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 1989, 1993 3191783Srmacklem * The Regents of the University of California. All rights reserved. 4191783Srmacklem * 5191783Srmacklem * This code is derived from software contributed to Berkeley by 6191783Srmacklem * Rick Macklem at The University of Guelph. 7191783Srmacklem * 8191783Srmacklem * Redistribution and use in source and binary forms, with or without 9191783Srmacklem * modification, are permitted provided that the following conditions 10191783Srmacklem * are met: 11191783Srmacklem * 1. Redistributions of source code must retain the above copyright 12191783Srmacklem * notice, this list of conditions and the following disclaimer. 13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 14191783Srmacklem * notice, this list of conditions and the following disclaimer in the 15191783Srmacklem * documentation and/or other materials provided with the distribution. 16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors 17191783Srmacklem * may be used to endorse or promote products derived from this software 18191783Srmacklem * without specific prior written permission. 19191783Srmacklem * 20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30191783Srmacklem * SUCH DAMAGE. 31191783Srmacklem * 32191783Srmacklem * from nfs_vnops.c 8.16 (Berkeley) 5/27/95 33191783Srmacklem */ 34191783Srmacklem 35191783Srmacklem#include <sys/cdefs.h> 36191783Srmacklem__FBSDID("$FreeBSD$"); 37191783Srmacklem 38191783Srmacklem/* 39191783Srmacklem * vnode op calls for Sun NFS version 2, 3 and 4 40191783Srmacklem */ 41191783Srmacklem 42223280Srmacklem#include "opt_kdtrace.h" 43191783Srmacklem#include "opt_inet.h" 44191783Srmacklem 45191783Srmacklem#include <sys/param.h> 46191783Srmacklem#include <sys/kernel.h> 47191783Srmacklem#include <sys/systm.h> 48191783Srmacklem#include <sys/resourcevar.h> 49191783Srmacklem#include <sys/proc.h> 50191783Srmacklem#include <sys/mount.h> 51191783Srmacklem#include <sys/bio.h> 52191783Srmacklem#include <sys/buf.h> 53194368Sbz#include <sys/jail.h> 54191783Srmacklem#include <sys/malloc.h> 55191783Srmacklem#include <sys/mbuf.h> 56191783Srmacklem#include <sys/namei.h> 57191783Srmacklem#include <sys/socket.h> 58191783Srmacklem#include <sys/vnode.h> 59191783Srmacklem#include <sys/dirent.h> 60191783Srmacklem#include <sys/fcntl.h> 61191783Srmacklem#include <sys/lockf.h> 62191783Srmacklem#include <sys/stat.h> 63191783Srmacklem#include <sys/sysctl.h> 64191783Srmacklem#include <sys/signalvar.h> 65191783Srmacklem 66191783Srmacklem#include <vm/vm.h> 67191783Srmacklem#include <vm/vm_extern.h> 68191783Srmacklem#include <vm/vm_object.h> 69191783Srmacklem 70191783Srmacklem#include <fs/nfs/nfsport.h> 71191783Srmacklem#include <fs/nfsclient/nfsnode.h> 72191783Srmacklem#include <fs/nfsclient/nfsmount.h> 73191783Srmacklem#include <fs/nfsclient/nfs.h> 74223280Srmacklem#include <fs/nfsclient/nfs_kdtrace.h> 75191783Srmacklem 76191783Srmacklem#include <net/if.h> 77191783Srmacklem#include <netinet/in.h> 78191783Srmacklem#include <netinet/in_var.h> 79191783Srmacklem 80210455Srmacklem#include <nfs/nfs_lock.h> 81210455Srmacklem 82223280Srmacklem#ifdef KDTRACE_HOOKS 83223280Srmacklem#include <sys/dtrace_bsd.h> 84223280Srmacklem 85223280Srmacklemdtrace_nfsclient_accesscache_flush_probe_func_t 86223280Srmacklem dtrace_nfscl_accesscache_flush_done_probe; 87223280Srmacklemuint32_t nfscl_accesscache_flush_done_id; 88223280Srmacklem 89223280Srmacklemdtrace_nfsclient_accesscache_get_probe_func_t 90223280Srmacklem dtrace_nfscl_accesscache_get_hit_probe, 91223280Srmacklem dtrace_nfscl_accesscache_get_miss_probe; 92223280Srmacklemuint32_t nfscl_accesscache_get_hit_id; 93223280Srmacklemuint32_t nfscl_accesscache_get_miss_id; 94223280Srmacklem 95223280Srmacklemdtrace_nfsclient_accesscache_load_probe_func_t 96223280Srmacklem dtrace_nfscl_accesscache_load_done_probe; 97223280Srmacklemuint32_t nfscl_accesscache_load_done_id; 98223280Srmacklem#endif /* !KDTRACE_HOOKS */ 99223280Srmacklem 100191783Srmacklem/* Defs */ 101191783Srmacklem#define TRUE 1 102191783Srmacklem#define FALSE 0 103191783Srmacklem 104191783Srmacklemextern struct nfsstats newnfsstats; 105220611Srmacklemextern int nfsrv_useacl; 106191783SrmacklemMALLOC_DECLARE(M_NEWNFSREQ); 107191783Srmacklem 108191783Srmacklem/* 109191783Srmacklem * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these 110191783Srmacklem * calls are not in getblk() and brelse() so that they would not be necessary 111191783Srmacklem * here. 112191783Srmacklem */ 113191783Srmacklem#ifndef B_VMIO 114191783Srmacklem#define vfs_busy_pages(bp, f) 115191783Srmacklem#endif 116191783Srmacklem 117191783Srmacklemstatic vop_read_t nfsfifo_read; 118191783Srmacklemstatic vop_write_t nfsfifo_write; 119191783Srmacklemstatic vop_close_t nfsfifo_close; 120191783Srmacklemstatic int nfs_setattrrpc(struct vnode *, struct vattr *, struct ucred *, 121191783Srmacklem struct thread *); 122191783Srmacklemstatic vop_lookup_t nfs_lookup; 123191783Srmacklemstatic vop_create_t nfs_create; 124191783Srmacklemstatic vop_mknod_t nfs_mknod; 125191783Srmacklemstatic vop_open_t nfs_open; 126220611Srmacklemstatic vop_pathconf_t nfs_pathconf; 127191783Srmacklemstatic vop_close_t nfs_close; 128191783Srmacklemstatic vop_access_t nfs_access; 129191783Srmacklemstatic vop_getattr_t nfs_getattr; 130191783Srmacklemstatic vop_setattr_t nfs_setattr; 131191783Srmacklemstatic vop_read_t nfs_read; 132191783Srmacklemstatic vop_fsync_t nfs_fsync; 133191783Srmacklemstatic vop_remove_t nfs_remove; 134191783Srmacklemstatic vop_link_t nfs_link; 135191783Srmacklemstatic vop_rename_t nfs_rename; 136191783Srmacklemstatic vop_mkdir_t nfs_mkdir; 137191783Srmacklemstatic vop_rmdir_t nfs_rmdir; 138191783Srmacklemstatic vop_symlink_t nfs_symlink; 139191783Srmacklemstatic vop_readdir_t nfs_readdir; 140191783Srmacklemstatic vop_strategy_t nfs_strategy; 141191783Srmacklemstatic vop_lock1_t nfs_lock1; 142191783Srmacklemstatic int nfs_lookitup(struct vnode *, char *, int, 143191783Srmacklem struct ucred *, struct thread *, struct nfsnode **); 144191783Srmacklemstatic int nfs_sillyrename(struct vnode *, struct vnode *, 145191783Srmacklem struct componentname *); 146191783Srmacklemstatic vop_access_t nfsspec_access; 147191783Srmacklemstatic vop_readlink_t nfs_readlink; 148191783Srmacklemstatic vop_print_t nfs_print; 149191783Srmacklemstatic vop_advlock_t nfs_advlock; 150191783Srmacklemstatic vop_advlockasync_t nfs_advlockasync; 151191783Srmacklemstatic vop_getacl_t nfs_getacl; 152191783Srmacklemstatic vop_setacl_t nfs_setacl; 153191783Srmacklem 154191783Srmacklem/* 155191783Srmacklem * Global vfs data structures for nfs 156191783Srmacklem */ 157191783Srmacklemstruct vop_vector newnfs_vnodeops = { 158191783Srmacklem .vop_default = &default_vnodeops, 159191783Srmacklem .vop_access = nfs_access, 160191783Srmacklem .vop_advlock = nfs_advlock, 161191783Srmacklem .vop_advlockasync = nfs_advlockasync, 162191783Srmacklem .vop_close = nfs_close, 163191783Srmacklem .vop_create = nfs_create, 164191783Srmacklem .vop_fsync = nfs_fsync, 165191783Srmacklem .vop_getattr = nfs_getattr, 166191783Srmacklem .vop_getpages = ncl_getpages, 167191783Srmacklem .vop_putpages = ncl_putpages, 168191783Srmacklem .vop_inactive = ncl_inactive, 169191783Srmacklem .vop_link = nfs_link, 170191783Srmacklem .vop_lock1 = nfs_lock1, 171191783Srmacklem .vop_lookup = nfs_lookup, 172191783Srmacklem .vop_mkdir = nfs_mkdir, 173191783Srmacklem .vop_mknod = nfs_mknod, 174191783Srmacklem .vop_open = nfs_open, 175220611Srmacklem .vop_pathconf = nfs_pathconf, 176191783Srmacklem .vop_print = nfs_print, 177191783Srmacklem .vop_read = nfs_read, 178191783Srmacklem .vop_readdir = nfs_readdir, 179191783Srmacklem .vop_readlink = nfs_readlink, 180191783Srmacklem .vop_reclaim = ncl_reclaim, 181191783Srmacklem .vop_remove = nfs_remove, 182191783Srmacklem .vop_rename = nfs_rename, 183191783Srmacklem .vop_rmdir = nfs_rmdir, 184191783Srmacklem .vop_setattr = nfs_setattr, 185191783Srmacklem .vop_strategy = nfs_strategy, 186191783Srmacklem .vop_symlink = nfs_symlink, 187191783Srmacklem .vop_write = ncl_write, 188191783Srmacklem .vop_getacl = nfs_getacl, 189191783Srmacklem .vop_setacl = nfs_setacl, 190191783Srmacklem}; 191191783Srmacklem 192191783Srmacklemstruct vop_vector newnfs_fifoops = { 193191783Srmacklem .vop_default = &fifo_specops, 194191783Srmacklem .vop_access = nfsspec_access, 195191783Srmacklem .vop_close = nfsfifo_close, 196191783Srmacklem .vop_fsync = nfs_fsync, 197191783Srmacklem .vop_getattr = nfs_getattr, 198191783Srmacklem .vop_inactive = ncl_inactive, 199191783Srmacklem .vop_print = nfs_print, 200191783Srmacklem .vop_read = nfsfifo_read, 201191783Srmacklem .vop_reclaim = ncl_reclaim, 202191783Srmacklem .vop_setattr = nfs_setattr, 203191783Srmacklem .vop_write = nfsfifo_write, 204191783Srmacklem}; 205191783Srmacklem 206191783Srmacklemstatic int nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, 207191783Srmacklem struct componentname *cnp, struct vattr *vap); 208191783Srmacklemstatic int nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name, 209191783Srmacklem int namelen, struct ucred *cred, struct thread *td); 210191783Srmacklemstatic int nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, 211191783Srmacklem char *fnameptr, int fnamelen, struct vnode *tdvp, struct vnode *tvp, 212191783Srmacklem char *tnameptr, int tnamelen, struct ucred *cred, struct thread *td); 213191783Srmacklemstatic int nfs_renameit(struct vnode *sdvp, struct vnode *svp, 214191783Srmacklem struct componentname *scnp, struct sillyrename *sp); 215191783Srmacklem 216191783Srmacklem/* 217191783Srmacklem * Global variables 218191783Srmacklem */ 219191783Srmacklem#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 220191783Srmacklem 221221973SrmacklemSYSCTL_DECL(_vfs_nfs); 222191783Srmacklem 223191783Srmacklemstatic int nfsaccess_cache_timeout = NFS_MAXATTRTIMO; 224221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW, 225191783Srmacklem &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout"); 226191783Srmacklem 227191783Srmacklemstatic int nfs_prime_access_cache = 0; 228221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, prime_access_cache, CTLFLAG_RW, 229191783Srmacklem &nfs_prime_access_cache, 0, 230191783Srmacklem "Prime NFS ACCESS cache when fetching attributes"); 231191783Srmacklem 232191783Srmacklemstatic int newnfs_commit_on_close = 0; 233221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, commit_on_close, CTLFLAG_RW, 234191783Srmacklem &newnfs_commit_on_close, 0, "write+commit on close, else only write"); 235191783Srmacklem 236191783Srmacklemstatic int nfs_clean_pages_on_close = 1; 237221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, clean_pages_on_close, CTLFLAG_RW, 238191783Srmacklem &nfs_clean_pages_on_close, 0, "NFS clean dirty pages on close"); 239191783Srmacklem 240191783Srmacklemint newnfs_directio_enable = 0; 241221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_directio_enable, CTLFLAG_RW, 242191783Srmacklem &newnfs_directio_enable, 0, "Enable NFS directio"); 243191783Srmacklem 244233730Skibint nfs_keep_dirty_on_error; 245233730SkibSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_keep_dirty_on_error, CTLFLAG_RW, 246233730Skib &nfs_keep_dirty_on_error, 0, "Retry pageout if error returned"); 247233730Skib 248191783Srmacklem/* 249191783Srmacklem * This sysctl allows other processes to mmap a file that has been opened 250191783Srmacklem * O_DIRECT by a process. In general, having processes mmap the file while 251191783Srmacklem * Direct IO is in progress can lead to Data Inconsistencies. But, we allow 252191783Srmacklem * this by default to prevent DoS attacks - to prevent a malicious user from 253191783Srmacklem * opening up files O_DIRECT preventing other users from mmap'ing these 254191783Srmacklem * files. "Protected" environments where stricter consistency guarantees are 255191783Srmacklem * required can disable this knob. The process that opened the file O_DIRECT 256191783Srmacklem * cannot mmap() the file, because mmap'ed IO on an O_DIRECT open() is not 257191783Srmacklem * meaningful. 258191783Srmacklem */ 259191783Srmacklemint newnfs_directio_allow_mmap = 1; 260221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_directio_allow_mmap, CTLFLAG_RW, 261191783Srmacklem &newnfs_directio_allow_mmap, 0, "Enable mmaped IO on file with O_DIRECT opens"); 262191783Srmacklem 263191783Srmacklem#if 0 264221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_hits, CTLFLAG_RD, 265191783Srmacklem &newnfsstats.accesscache_hits, 0, "NFS ACCESS cache hit count"); 266191783Srmacklem 267221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_misses, CTLFLAG_RD, 268191783Srmacklem &newnfsstats.accesscache_misses, 0, "NFS ACCESS cache miss count"); 269191783Srmacklem#endif 270191783Srmacklem 271191783Srmacklem#define NFSACCESS_ALL (NFSACCESS_READ | NFSACCESS_MODIFY \ 272191783Srmacklem | NFSACCESS_EXTEND | NFSACCESS_EXECUTE \ 273191783Srmacklem | NFSACCESS_DELETE | NFSACCESS_LOOKUP) 274191783Srmacklem 275191783Srmacklem/* 276191783Srmacklem * SMP Locking Note : 277191783Srmacklem * The list of locks after the description of the lock is the ordering 278191783Srmacklem * of other locks acquired with the lock held. 279191783Srmacklem * np->n_mtx : Protects the fields in the nfsnode. 280191783Srmacklem VM Object Lock 281191783Srmacklem VI_MTX (acquired indirectly) 282191783Srmacklem * nmp->nm_mtx : Protects the fields in the nfsmount. 283191783Srmacklem rep->r_mtx 284191783Srmacklem * ncl_iod_mutex : Global lock, protects shared nfsiod state. 285191783Srmacklem * nfs_reqq_mtx : Global lock, protects the nfs_reqq list. 286191783Srmacklem nmp->nm_mtx 287191783Srmacklem rep->r_mtx 288191783Srmacklem * rep->r_mtx : Protects the fields in an nfsreq. 289191783Srmacklem */ 290191783Srmacklem 291191783Srmacklemstatic int 292191783Srmacklemnfs34_access_otw(struct vnode *vp, int wmode, struct thread *td, 293191783Srmacklem struct ucred *cred, u_int32_t *retmode) 294191783Srmacklem{ 295191783Srmacklem int error = 0, attrflag, i, lrupos; 296191783Srmacklem u_int32_t rmode; 297191783Srmacklem struct nfsnode *np = VTONFS(vp); 298191783Srmacklem struct nfsvattr nfsva; 299191783Srmacklem 300191783Srmacklem error = nfsrpc_accessrpc(vp, wmode, cred, td, &nfsva, &attrflag, 301191783Srmacklem &rmode, NULL); 302191783Srmacklem if (attrflag) 303191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 304191783Srmacklem if (!error) { 305191783Srmacklem lrupos = 0; 306191783Srmacklem mtx_lock(&np->n_mtx); 307191783Srmacklem for (i = 0; i < NFS_ACCESSCACHESIZE; i++) { 308191783Srmacklem if (np->n_accesscache[i].uid == cred->cr_uid) { 309191783Srmacklem np->n_accesscache[i].mode = rmode; 310191783Srmacklem np->n_accesscache[i].stamp = time_second; 311191783Srmacklem break; 312191783Srmacklem } 313191783Srmacklem if (i > 0 && np->n_accesscache[i].stamp < 314191783Srmacklem np->n_accesscache[lrupos].stamp) 315191783Srmacklem lrupos = i; 316191783Srmacklem } 317191783Srmacklem if (i == NFS_ACCESSCACHESIZE) { 318191783Srmacklem np->n_accesscache[lrupos].uid = cred->cr_uid; 319191783Srmacklem np->n_accesscache[lrupos].mode = rmode; 320191783Srmacklem np->n_accesscache[lrupos].stamp = time_second; 321191783Srmacklem } 322191783Srmacklem mtx_unlock(&np->n_mtx); 323191783Srmacklem if (retmode != NULL) 324191783Srmacklem *retmode = rmode; 325223280Srmacklem KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, rmode, 0); 326191783Srmacklem } else if (NFS_ISV4(vp)) { 327191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 328191783Srmacklem } 329223280Srmacklem#ifdef KDTRACE_HOOKS 330223280Srmacklem if (error != 0) 331223280Srmacklem KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, 0, 332223280Srmacklem error); 333223280Srmacklem#endif 334191783Srmacklem return (error); 335191783Srmacklem} 336191783Srmacklem 337191783Srmacklem/* 338191783Srmacklem * nfs access vnode op. 339191783Srmacklem * For nfs version 2, just return ok. File accesses may fail later. 340191783Srmacklem * For nfs version 3, use the access rpc to check accessibility. If file modes 341191783Srmacklem * are changed on the server, accesses might still fail later. 342191783Srmacklem */ 343191783Srmacklemstatic int 344191783Srmacklemnfs_access(struct vop_access_args *ap) 345191783Srmacklem{ 346191783Srmacklem struct vnode *vp = ap->a_vp; 347191783Srmacklem int error = 0, i, gotahit; 348191783Srmacklem u_int32_t mode, wmode, rmode; 349191783Srmacklem int v34 = NFS_ISV34(vp); 350191783Srmacklem struct nfsnode *np = VTONFS(vp); 351191783Srmacklem 352191783Srmacklem /* 353191783Srmacklem * Disallow write attempts on filesystems mounted read-only; 354191783Srmacklem * unless the file is a socket, fifo, or a block or character 355191783Srmacklem * device resident on the filesystem. 356191783Srmacklem */ 357200069Strasz if ((ap->a_accmode & (VWRITE | VAPPEND | VWRITE_NAMED_ATTRS | 358200069Strasz VDELETE_CHILD | VWRITE_ATTRIBUTES | VDELETE | VWRITE_ACL | 359200069Strasz VWRITE_OWNER)) != 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) { 360191783Srmacklem switch (vp->v_type) { 361191783Srmacklem case VREG: 362191783Srmacklem case VDIR: 363191783Srmacklem case VLNK: 364191783Srmacklem return (EROFS); 365191783Srmacklem default: 366191783Srmacklem break; 367191783Srmacklem } 368191783Srmacklem } 369191783Srmacklem /* 370191783Srmacklem * For nfs v3 or v4, check to see if we have done this recently, and if 371191783Srmacklem * so return our cached result instead of making an ACCESS call. 372191783Srmacklem * If not, do an access rpc, otherwise you are stuck emulating 373191783Srmacklem * ufs_access() locally using the vattr. This may not be correct, 374191783Srmacklem * since the server may apply other access criteria such as 375191783Srmacklem * client uid-->server uid mapping that we do not know about. 376191783Srmacklem */ 377191783Srmacklem if (v34) { 378191783Srmacklem if (ap->a_accmode & VREAD) 379191783Srmacklem mode = NFSACCESS_READ; 380191783Srmacklem else 381191783Srmacklem mode = 0; 382191783Srmacklem if (vp->v_type != VDIR) { 383191783Srmacklem if (ap->a_accmode & VWRITE) 384191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 385191783Srmacklem if (ap->a_accmode & VAPPEND) 386191783Srmacklem mode |= NFSACCESS_EXTEND; 387191783Srmacklem if (ap->a_accmode & VEXEC) 388191783Srmacklem mode |= NFSACCESS_EXECUTE; 389191783Srmacklem if (ap->a_accmode & VDELETE) 390191783Srmacklem mode |= NFSACCESS_DELETE; 391191783Srmacklem } else { 392191783Srmacklem if (ap->a_accmode & VWRITE) 393191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 394191783Srmacklem if (ap->a_accmode & VAPPEND) 395191783Srmacklem mode |= NFSACCESS_EXTEND; 396191783Srmacklem if (ap->a_accmode & VEXEC) 397191783Srmacklem mode |= NFSACCESS_LOOKUP; 398191783Srmacklem if (ap->a_accmode & VDELETE) 399191783Srmacklem mode |= NFSACCESS_DELETE; 400191783Srmacklem if (ap->a_accmode & VDELETE_CHILD) 401191783Srmacklem mode |= NFSACCESS_MODIFY; 402191783Srmacklem } 403191783Srmacklem /* XXX safety belt, only make blanket request if caching */ 404191783Srmacklem if (nfsaccess_cache_timeout > 0) { 405191783Srmacklem wmode = NFSACCESS_READ | NFSACCESS_MODIFY | 406191783Srmacklem NFSACCESS_EXTEND | NFSACCESS_EXECUTE | 407191783Srmacklem NFSACCESS_DELETE | NFSACCESS_LOOKUP; 408191783Srmacklem } else { 409191783Srmacklem wmode = mode; 410191783Srmacklem } 411191783Srmacklem 412191783Srmacklem /* 413191783Srmacklem * Does our cached result allow us to give a definite yes to 414191783Srmacklem * this request? 415191783Srmacklem */ 416191783Srmacklem gotahit = 0; 417191783Srmacklem mtx_lock(&np->n_mtx); 418191783Srmacklem for (i = 0; i < NFS_ACCESSCACHESIZE; i++) { 419191783Srmacklem if (ap->a_cred->cr_uid == np->n_accesscache[i].uid) { 420191783Srmacklem if (time_second < (np->n_accesscache[i].stamp 421191783Srmacklem + nfsaccess_cache_timeout) && 422191783Srmacklem (np->n_accesscache[i].mode & mode) == mode) { 423191783Srmacklem NFSINCRGLOBAL(newnfsstats.accesscache_hits); 424191783Srmacklem gotahit = 1; 425191783Srmacklem } 426191783Srmacklem break; 427191783Srmacklem } 428191783Srmacklem } 429191783Srmacklem mtx_unlock(&np->n_mtx); 430223280Srmacklem#ifdef KDTRACE_HOOKS 431223280Srmacklem if (gotahit != 0) 432223280Srmacklem KDTRACE_NFS_ACCESSCACHE_GET_HIT(vp, 433223280Srmacklem ap->a_cred->cr_uid, mode); 434223280Srmacklem else 435223280Srmacklem KDTRACE_NFS_ACCESSCACHE_GET_MISS(vp, 436223280Srmacklem ap->a_cred->cr_uid, mode); 437223280Srmacklem#endif 438191783Srmacklem if (gotahit == 0) { 439191783Srmacklem /* 440191783Srmacklem * Either a no, or a don't know. Go to the wire. 441191783Srmacklem */ 442191783Srmacklem NFSINCRGLOBAL(newnfsstats.accesscache_misses); 443191783Srmacklem error = nfs34_access_otw(vp, wmode, ap->a_td, 444191783Srmacklem ap->a_cred, &rmode); 445191783Srmacklem if (!error && 446191783Srmacklem (rmode & mode) != mode) 447191783Srmacklem error = EACCES; 448191783Srmacklem } 449191783Srmacklem return (error); 450191783Srmacklem } else { 451191783Srmacklem if ((error = nfsspec_access(ap)) != 0) { 452191783Srmacklem return (error); 453191783Srmacklem } 454191783Srmacklem /* 455191783Srmacklem * Attempt to prevent a mapped root from accessing a file 456191783Srmacklem * which it shouldn't. We try to read a byte from the file 457191783Srmacklem * if the user is root and the file is not zero length. 458191783Srmacklem * After calling nfsspec_access, we should have the correct 459191783Srmacklem * file size cached. 460191783Srmacklem */ 461191783Srmacklem mtx_lock(&np->n_mtx); 462191783Srmacklem if (ap->a_cred->cr_uid == 0 && (ap->a_accmode & VREAD) 463191783Srmacklem && VTONFS(vp)->n_size > 0) { 464191783Srmacklem struct iovec aiov; 465191783Srmacklem struct uio auio; 466191783Srmacklem char buf[1]; 467191783Srmacklem 468191783Srmacklem mtx_unlock(&np->n_mtx); 469191783Srmacklem aiov.iov_base = buf; 470191783Srmacklem aiov.iov_len = 1; 471191783Srmacklem auio.uio_iov = &aiov; 472191783Srmacklem auio.uio_iovcnt = 1; 473191783Srmacklem auio.uio_offset = 0; 474191783Srmacklem auio.uio_resid = 1; 475191783Srmacklem auio.uio_segflg = UIO_SYSSPACE; 476191783Srmacklem auio.uio_rw = UIO_READ; 477191783Srmacklem auio.uio_td = ap->a_td; 478191783Srmacklem 479191783Srmacklem if (vp->v_type == VREG) 480191783Srmacklem error = ncl_readrpc(vp, &auio, ap->a_cred); 481191783Srmacklem else if (vp->v_type == VDIR) { 482191783Srmacklem char* bp; 483191783Srmacklem bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK); 484191783Srmacklem aiov.iov_base = bp; 485191783Srmacklem aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ; 486191783Srmacklem error = ncl_readdirrpc(vp, &auio, ap->a_cred, 487191783Srmacklem ap->a_td); 488191783Srmacklem free(bp, M_TEMP); 489191783Srmacklem } else if (vp->v_type == VLNK) 490191783Srmacklem error = ncl_readlinkrpc(vp, &auio, ap->a_cred); 491191783Srmacklem else 492191783Srmacklem error = EACCES; 493191783Srmacklem } else 494191783Srmacklem mtx_unlock(&np->n_mtx); 495191783Srmacklem return (error); 496191783Srmacklem } 497191783Srmacklem} 498191783Srmacklem 499191783Srmacklem 500191783Srmacklem/* 501191783Srmacklem * nfs open vnode op 502191783Srmacklem * Check to see if the type is ok 503191783Srmacklem * and that deletion is not in progress. 504191783Srmacklem * For paged in text files, you will need to flush the page cache 505191783Srmacklem * if consistency is lost. 506191783Srmacklem */ 507191783Srmacklem/* ARGSUSED */ 508191783Srmacklemstatic int 509191783Srmacklemnfs_open(struct vop_open_args *ap) 510191783Srmacklem{ 511191783Srmacklem struct vnode *vp = ap->a_vp; 512191783Srmacklem struct nfsnode *np = VTONFS(vp); 513191783Srmacklem struct vattr vattr; 514191783Srmacklem int error; 515191783Srmacklem int fmode = ap->a_mode; 516236096Srmacklem struct ucred *cred; 517191783Srmacklem 518191783Srmacklem if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 519191783Srmacklem return (EOPNOTSUPP); 520191783Srmacklem 521191783Srmacklem /* 522191783Srmacklem * For NFSv4, we need to do the Open Op before cache validation, 523191783Srmacklem * so that we conform to RFC3530 Sec. 9.3.1. 524191783Srmacklem */ 525191783Srmacklem if (NFS_ISV4(vp)) { 526191783Srmacklem error = nfsrpc_open(vp, fmode, ap->a_cred, ap->a_td); 527191783Srmacklem if (error) { 528191783Srmacklem error = nfscl_maperr(ap->a_td, error, (uid_t)0, 529191783Srmacklem (gid_t)0); 530191783Srmacklem return (error); 531191783Srmacklem } 532191783Srmacklem } 533191783Srmacklem 534191783Srmacklem /* 535191783Srmacklem * Now, if this Open will be doing reading, re-validate/flush the 536191783Srmacklem * cache, so that Close/Open coherency is maintained. 537191783Srmacklem */ 538214513Srmacklem mtx_lock(&np->n_mtx); 539214513Srmacklem if (np->n_flag & NMODIFIED) { 540214513Srmacklem mtx_unlock(&np->n_mtx); 541214513Srmacklem error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 542214513Srmacklem if (error == EINTR || error == EIO) { 543214513Srmacklem if (NFS_ISV4(vp)) 544214513Srmacklem (void) nfsrpc_close(vp, 0, ap->a_td); 545214513Srmacklem return (error); 546214513Srmacklem } 547191783Srmacklem mtx_lock(&np->n_mtx); 548214513Srmacklem np->n_attrstamp = 0; 549223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 550214513Srmacklem if (vp->v_type == VDIR) 551214513Srmacklem np->n_direofoffset = 0; 552214513Srmacklem mtx_unlock(&np->n_mtx); 553214513Srmacklem error = VOP_GETATTR(vp, &vattr, ap->a_cred); 554214513Srmacklem if (error) { 555214513Srmacklem if (NFS_ISV4(vp)) 556214513Srmacklem (void) nfsrpc_close(vp, 0, ap->a_td); 557214513Srmacklem return (error); 558214513Srmacklem } 559214513Srmacklem mtx_lock(&np->n_mtx); 560214513Srmacklem np->n_mtime = vattr.va_mtime; 561214513Srmacklem if (NFS_ISV4(vp)) 562214513Srmacklem np->n_change = vattr.va_filerev; 563214513Srmacklem } else { 564214513Srmacklem mtx_unlock(&np->n_mtx); 565214513Srmacklem error = VOP_GETATTR(vp, &vattr, ap->a_cred); 566214513Srmacklem if (error) { 567214513Srmacklem if (NFS_ISV4(vp)) 568214513Srmacklem (void) nfsrpc_close(vp, 0, ap->a_td); 569214513Srmacklem return (error); 570214513Srmacklem } 571214513Srmacklem mtx_lock(&np->n_mtx); 572214513Srmacklem if ((NFS_ISV4(vp) && np->n_change != vattr.va_filerev) || 573214513Srmacklem NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { 574191783Srmacklem if (vp->v_type == VDIR) 575191783Srmacklem np->n_direofoffset = 0; 576210135Sjhb mtx_unlock(&np->n_mtx); 577214513Srmacklem error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 578214513Srmacklem if (error == EINTR || error == EIO) { 579191783Srmacklem if (NFS_ISV4(vp)) 580192337Srmacklem (void) nfsrpc_close(vp, 0, ap->a_td); 581191783Srmacklem return (error); 582191783Srmacklem } 583191783Srmacklem mtx_lock(&np->n_mtx); 584191783Srmacklem np->n_mtime = vattr.va_mtime; 585191783Srmacklem if (NFS_ISV4(vp)) 586191783Srmacklem np->n_change = vattr.va_filerev; 587191783Srmacklem } 588191783Srmacklem } 589191783Srmacklem 590191783Srmacklem /* 591191783Srmacklem * If the object has >= 1 O_DIRECT active opens, we disable caching. 592191783Srmacklem */ 593214513Srmacklem if (newnfs_directio_enable && (fmode & O_DIRECT) && 594214513Srmacklem (vp->v_type == VREG)) { 595191783Srmacklem if (np->n_directio_opens == 0) { 596214513Srmacklem mtx_unlock(&np->n_mtx); 597191783Srmacklem error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 598191783Srmacklem if (error) { 599191783Srmacklem if (NFS_ISV4(vp)) 600192337Srmacklem (void) nfsrpc_close(vp, 0, ap->a_td); 601191783Srmacklem return (error); 602191783Srmacklem } 603191783Srmacklem mtx_lock(&np->n_mtx); 604191783Srmacklem np->n_flag |= NNONCACHE; 605191783Srmacklem } 606191783Srmacklem np->n_directio_opens++; 607191783Srmacklem } 608236096Srmacklem 609236096Srmacklem /* 610236096Srmacklem * If this is an open for writing, capture a reference to the 611236096Srmacklem * credentials, so they can be used by ncl_putpages(). Using 612236096Srmacklem * these write credentials is preferable to the credentials of 613236096Srmacklem * whatever thread happens to be doing the VOP_PUTPAGES() since 614236096Srmacklem * the write RPCs are less likely to fail with EACCES. 615236096Srmacklem */ 616236096Srmacklem if ((fmode & FWRITE) != 0) { 617236096Srmacklem cred = np->n_writecred; 618236096Srmacklem np->n_writecred = crhold(ap->a_cred); 619236096Srmacklem } else 620236096Srmacklem cred = NULL; 621214513Srmacklem mtx_unlock(&np->n_mtx); 622236096Srmacklem if (cred != NULL) 623236096Srmacklem crfree(cred); 624191783Srmacklem vnode_create_vobject(vp, vattr.va_size, ap->a_td); 625191783Srmacklem return (0); 626191783Srmacklem} 627191783Srmacklem 628191783Srmacklem/* 629191783Srmacklem * nfs close vnode op 630191783Srmacklem * What an NFS client should do upon close after writing is a debatable issue. 631191783Srmacklem * Most NFS clients push delayed writes to the server upon close, basically for 632191783Srmacklem * two reasons: 633191783Srmacklem * 1 - So that any write errors may be reported back to the client process 634191783Srmacklem * doing the close system call. By far the two most likely errors are 635191783Srmacklem * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. 636191783Srmacklem * 2 - To put a worst case upper bound on cache inconsistency between 637191783Srmacklem * multiple clients for the file. 638191783Srmacklem * There is also a consistency problem for Version 2 of the protocol w.r.t. 639191783Srmacklem * not being able to tell if other clients are writing a file concurrently, 640191783Srmacklem * since there is no way of knowing if the changed modify time in the reply 641191783Srmacklem * is only due to the write for this client. 642191783Srmacklem * (NFS Version 3 provides weak cache consistency data in the reply that 643191783Srmacklem * should be sufficient to detect and handle this case.) 644191783Srmacklem * 645191783Srmacklem * The current code does the following: 646191783Srmacklem * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers 647191783Srmacklem * for NFS Version 3 - flush dirty buffers to the server but don't invalidate 648191783Srmacklem * or commit them (this satisfies 1 and 2 except for the 649191783Srmacklem * case where the server crashes after this close but 650191783Srmacklem * before the commit RPC, which is felt to be "good 651191783Srmacklem * enough". Changing the last argument to ncl_flush() to 652191783Srmacklem * a 1 would force a commit operation, if it is felt a 653191783Srmacklem * commit is necessary now. 654191783Srmacklem * for NFS Version 4 - flush the dirty buffers and commit them, if 655191783Srmacklem * nfscl_mustflush() says this is necessary. 656191783Srmacklem * It is necessary if there is no write delegation held, 657191783Srmacklem * in order to satisfy open/close coherency. 658191783Srmacklem * If the file isn't cached on local stable storage, 659191783Srmacklem * it may be necessary in order to detect "out of space" 660191783Srmacklem * errors from the server, if the write delegation 661191783Srmacklem * issued by the server doesn't allow the file to grow. 662191783Srmacklem */ 663191783Srmacklem/* ARGSUSED */ 664191783Srmacklemstatic int 665191783Srmacklemnfs_close(struct vop_close_args *ap) 666191783Srmacklem{ 667191783Srmacklem struct vnode *vp = ap->a_vp; 668191783Srmacklem struct nfsnode *np = VTONFS(vp); 669191783Srmacklem struct nfsvattr nfsva; 670191783Srmacklem struct ucred *cred; 671191783Srmacklem int error = 0, ret, localcred = 0; 672191783Srmacklem int fmode = ap->a_fflag; 673191783Srmacklem 674191783Srmacklem if ((vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF)) 675191783Srmacklem return (0); 676191783Srmacklem /* 677191783Srmacklem * During shutdown, a_cred isn't valid, so just use root. 678191783Srmacklem */ 679191783Srmacklem if (ap->a_cred == NOCRED) { 680191783Srmacklem cred = newnfs_getcred(); 681191783Srmacklem localcred = 1; 682191783Srmacklem } else { 683191783Srmacklem cred = ap->a_cred; 684191783Srmacklem } 685191783Srmacklem if (vp->v_type == VREG) { 686191783Srmacklem /* 687191783Srmacklem * Examine and clean dirty pages, regardless of NMODIFIED. 688191783Srmacklem * This closes a major hole in close-to-open consistency. 689191783Srmacklem * We want to push out all dirty pages (and buffers) on 690191783Srmacklem * close, regardless of whether they were dirtied by 691191783Srmacklem * mmap'ed writes or via write(). 692191783Srmacklem */ 693191783Srmacklem if (nfs_clean_pages_on_close && vp->v_object) { 694191783Srmacklem VM_OBJECT_LOCK(vp->v_object); 695191783Srmacklem vm_object_page_clean(vp->v_object, 0, 0, 0); 696191783Srmacklem VM_OBJECT_UNLOCK(vp->v_object); 697191783Srmacklem } 698191783Srmacklem mtx_lock(&np->n_mtx); 699191783Srmacklem if (np->n_flag & NMODIFIED) { 700191783Srmacklem mtx_unlock(&np->n_mtx); 701191783Srmacklem if (NFS_ISV3(vp)) { 702191783Srmacklem /* 703191783Srmacklem * Under NFSv3 we have dirty buffers to dispose of. We 704191783Srmacklem * must flush them to the NFS server. We have the option 705191783Srmacklem * of waiting all the way through the commit rpc or just 706191783Srmacklem * waiting for the initial write. The default is to only 707191783Srmacklem * wait through the initial write so the data is in the 708191783Srmacklem * server's cache, which is roughly similar to the state 709191783Srmacklem * a standard disk subsystem leaves the file in on close(). 710191783Srmacklem * 711191783Srmacklem * We cannot clear the NMODIFIED bit in np->n_flag due to 712191783Srmacklem * potential races with other processes, and certainly 713191783Srmacklem * cannot clear it if we don't commit. 714191783Srmacklem * These races occur when there is no longer the old 715191783Srmacklem * traditional vnode locking implemented for Vnode Ops. 716191783Srmacklem */ 717191783Srmacklem int cm = newnfs_commit_on_close ? 1 : 0; 718207082Srmacklem error = ncl_flush(vp, MNT_WAIT, cred, ap->a_td, cm, 0); 719191783Srmacklem /* np->n_flag &= ~NMODIFIED; */ 720195943Srmacklem } else if (NFS_ISV4(vp)) { 721210786Srmacklem if (nfscl_mustflush(vp) != 0) { 722195943Srmacklem int cm = newnfs_commit_on_close ? 1 : 0; 723195943Srmacklem error = ncl_flush(vp, MNT_WAIT, cred, ap->a_td, 724207082Srmacklem cm, 0); 725195943Srmacklem /* 726195943Srmacklem * as above w.r.t races when clearing 727195943Srmacklem * NMODIFIED. 728195943Srmacklem * np->n_flag &= ~NMODIFIED; 729195943Srmacklem */ 730195943Srmacklem } 731191783Srmacklem } else 732191783Srmacklem error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 733191783Srmacklem mtx_lock(&np->n_mtx); 734191783Srmacklem } 735191783Srmacklem /* 736191783Srmacklem * Invalidate the attribute cache in all cases. 737191783Srmacklem * An open is going to fetch fresh attrs any way, other procs 738191783Srmacklem * on this node that have file open will be forced to do an 739191783Srmacklem * otw attr fetch, but this is safe. 740191783Srmacklem * --> A user found that their RPC count dropped by 20% when 741191783Srmacklem * this was commented out and I can't see any requirement 742191783Srmacklem * for it, so I've disabled it when negative lookups are 743191783Srmacklem * enabled. (What does this have to do with negative lookup 744191783Srmacklem * caching? Well nothing, except it was reported by the 745191783Srmacklem * same user that needed negative lookup caching and I wanted 746203303Srmacklem * there to be a way to disable it to see if it 747191783Srmacklem * is the cause of some caching/coherency issue that might 748191783Srmacklem * crop up.) 749191783Srmacklem */ 750223280Srmacklem if (VFSTONFS(vp->v_mount)->nm_negnametimeo == 0) { 751191783Srmacklem np->n_attrstamp = 0; 752223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 753223280Srmacklem } 754191783Srmacklem if (np->n_flag & NWRITEERR) { 755191783Srmacklem np->n_flag &= ~NWRITEERR; 756191783Srmacklem error = np->n_error; 757191783Srmacklem } 758191783Srmacklem mtx_unlock(&np->n_mtx); 759191783Srmacklem } 760191783Srmacklem 761191783Srmacklem if (NFS_ISV4(vp)) { 762191783Srmacklem /* 763191783Srmacklem * Get attributes so "change" is up to date. 764191783Srmacklem */ 765265390Srmacklem if (error == 0 && nfscl_mustflush(vp) != 0 && 766265390Srmacklem vp->v_type == VREG && 767265390Srmacklem (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOCTO) == 0) { 768191783Srmacklem ret = nfsrpc_getattr(vp, cred, ap->a_td, &nfsva, 769191783Srmacklem NULL); 770191783Srmacklem if (!ret) { 771191783Srmacklem np->n_change = nfsva.na_filerev; 772191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 773191783Srmacklem NULL, 0, 0); 774191783Srmacklem } 775191783Srmacklem } 776191783Srmacklem 777191783Srmacklem /* 778191783Srmacklem * and do the close. 779191783Srmacklem */ 780192337Srmacklem ret = nfsrpc_close(vp, 0, ap->a_td); 781191783Srmacklem if (!error && ret) 782191783Srmacklem error = ret; 783191783Srmacklem if (error) 784191783Srmacklem error = nfscl_maperr(ap->a_td, error, (uid_t)0, 785191783Srmacklem (gid_t)0); 786191783Srmacklem } 787191783Srmacklem if (newnfs_directio_enable) 788191783Srmacklem KASSERT((np->n_directio_asyncwr == 0), 789191783Srmacklem ("nfs_close: dirty unflushed (%d) directio buffers\n", 790191783Srmacklem np->n_directio_asyncwr)); 791191783Srmacklem if (newnfs_directio_enable && (fmode & O_DIRECT) && (vp->v_type == VREG)) { 792191783Srmacklem mtx_lock(&np->n_mtx); 793191783Srmacklem KASSERT((np->n_directio_opens > 0), 794191783Srmacklem ("nfs_close: unexpectedly value (0) of n_directio_opens\n")); 795191783Srmacklem np->n_directio_opens--; 796191783Srmacklem if (np->n_directio_opens == 0) 797191783Srmacklem np->n_flag &= ~NNONCACHE; 798191783Srmacklem mtx_unlock(&np->n_mtx); 799191783Srmacklem } 800191783Srmacklem if (localcred) 801191783Srmacklem NFSFREECRED(cred); 802191783Srmacklem return (error); 803191783Srmacklem} 804191783Srmacklem 805191783Srmacklem/* 806191783Srmacklem * nfs getattr call from vfs. 807191783Srmacklem */ 808191783Srmacklemstatic int 809191783Srmacklemnfs_getattr(struct vop_getattr_args *ap) 810191783Srmacklem{ 811191783Srmacklem struct vnode *vp = ap->a_vp; 812191783Srmacklem struct thread *td = curthread; /* XXX */ 813191783Srmacklem struct nfsnode *np = VTONFS(vp); 814191783Srmacklem int error = 0; 815191783Srmacklem struct nfsvattr nfsva; 816191783Srmacklem struct vattr *vap = ap->a_vap; 817191783Srmacklem struct vattr vattr; 818191783Srmacklem 819191783Srmacklem /* 820191783Srmacklem * Update local times for special files. 821191783Srmacklem */ 822191783Srmacklem mtx_lock(&np->n_mtx); 823191783Srmacklem if (np->n_flag & (NACC | NUPD)) 824191783Srmacklem np->n_flag |= NCHG; 825191783Srmacklem mtx_unlock(&np->n_mtx); 826191783Srmacklem /* 827191783Srmacklem * First look in the cache. 828191783Srmacklem */ 829191783Srmacklem if (ncl_getattrcache(vp, &vattr) == 0) { 830191783Srmacklem vap->va_type = vattr.va_type; 831191783Srmacklem vap->va_mode = vattr.va_mode; 832191783Srmacklem vap->va_nlink = vattr.va_nlink; 833191783Srmacklem vap->va_uid = vattr.va_uid; 834191783Srmacklem vap->va_gid = vattr.va_gid; 835191783Srmacklem vap->va_fsid = vattr.va_fsid; 836191783Srmacklem vap->va_fileid = vattr.va_fileid; 837191783Srmacklem vap->va_size = vattr.va_size; 838191783Srmacklem vap->va_blocksize = vattr.va_blocksize; 839191783Srmacklem vap->va_atime = vattr.va_atime; 840191783Srmacklem vap->va_mtime = vattr.va_mtime; 841191783Srmacklem vap->va_ctime = vattr.va_ctime; 842191783Srmacklem vap->va_gen = vattr.va_gen; 843191783Srmacklem vap->va_flags = vattr.va_flags; 844191783Srmacklem vap->va_rdev = vattr.va_rdev; 845191783Srmacklem vap->va_bytes = vattr.va_bytes; 846191783Srmacklem vap->va_filerev = vattr.va_filerev; 847191783Srmacklem /* 848191783Srmacklem * Get the local modify time for the case of a write 849191783Srmacklem * delegation. 850191783Srmacklem */ 851191783Srmacklem nfscl_deleggetmodtime(vp, &vap->va_mtime); 852191783Srmacklem return (0); 853191783Srmacklem } 854191783Srmacklem 855191783Srmacklem if (NFS_ISV34(vp) && nfs_prime_access_cache && 856191783Srmacklem nfsaccess_cache_timeout > 0) { 857191783Srmacklem NFSINCRGLOBAL(newnfsstats.accesscache_misses); 858191783Srmacklem nfs34_access_otw(vp, NFSACCESS_ALL, td, ap->a_cred, NULL); 859191783Srmacklem if (ncl_getattrcache(vp, ap->a_vap) == 0) { 860191783Srmacklem nfscl_deleggetmodtime(vp, &ap->a_vap->va_mtime); 861191783Srmacklem return (0); 862191783Srmacklem } 863191783Srmacklem } 864191783Srmacklem error = nfsrpc_getattr(vp, ap->a_cred, td, &nfsva, NULL); 865191783Srmacklem if (!error) 866191783Srmacklem error = nfscl_loadattrcache(&vp, &nfsva, vap, NULL, 0, 0); 867191783Srmacklem if (!error) { 868191783Srmacklem /* 869191783Srmacklem * Get the local modify time for the case of a write 870191783Srmacklem * delegation. 871191783Srmacklem */ 872191783Srmacklem nfscl_deleggetmodtime(vp, &vap->va_mtime); 873191783Srmacklem } else if (NFS_ISV4(vp)) { 874191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 875191783Srmacklem } 876191783Srmacklem return (error); 877191783Srmacklem} 878191783Srmacklem 879191783Srmacklem/* 880191783Srmacklem * nfs setattr call. 881191783Srmacklem */ 882191783Srmacklemstatic int 883191783Srmacklemnfs_setattr(struct vop_setattr_args *ap) 884191783Srmacklem{ 885191783Srmacklem struct vnode *vp = ap->a_vp; 886191783Srmacklem struct nfsnode *np = VTONFS(vp); 887191783Srmacklem struct thread *td = curthread; /* XXX */ 888191783Srmacklem struct vattr *vap = ap->a_vap; 889191783Srmacklem int error = 0; 890191783Srmacklem u_quad_t tsize; 891191783Srmacklem 892191783Srmacklem#ifndef nolint 893191783Srmacklem tsize = (u_quad_t)0; 894191783Srmacklem#endif 895191783Srmacklem 896191783Srmacklem /* 897191783Srmacklem * Setting of flags and marking of atimes are not supported. 898191783Srmacklem */ 899191783Srmacklem if (vap->va_flags != VNOVAL) 900191783Srmacklem return (EOPNOTSUPP); 901191783Srmacklem 902191783Srmacklem /* 903191783Srmacklem * Disallow write attempts if the filesystem is mounted read-only. 904191783Srmacklem */ 905191783Srmacklem if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 906191783Srmacklem vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 907191783Srmacklem vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && 908191783Srmacklem (vp->v_mount->mnt_flag & MNT_RDONLY)) 909191783Srmacklem return (EROFS); 910191783Srmacklem if (vap->va_size != VNOVAL) { 911191783Srmacklem switch (vp->v_type) { 912191783Srmacklem case VDIR: 913191783Srmacklem return (EISDIR); 914191783Srmacklem case VCHR: 915191783Srmacklem case VBLK: 916191783Srmacklem case VSOCK: 917191783Srmacklem case VFIFO: 918191783Srmacklem if (vap->va_mtime.tv_sec == VNOVAL && 919191783Srmacklem vap->va_atime.tv_sec == VNOVAL && 920191783Srmacklem vap->va_mode == (mode_t)VNOVAL && 921191783Srmacklem vap->va_uid == (uid_t)VNOVAL && 922191783Srmacklem vap->va_gid == (gid_t)VNOVAL) 923191783Srmacklem return (0); 924191783Srmacklem vap->va_size = VNOVAL; 925191783Srmacklem break; 926191783Srmacklem default: 927191783Srmacklem /* 928191783Srmacklem * Disallow write attempts if the filesystem is 929191783Srmacklem * mounted read-only. 930191783Srmacklem */ 931191783Srmacklem if (vp->v_mount->mnt_flag & MNT_RDONLY) 932191783Srmacklem return (EROFS); 933191783Srmacklem /* 934191783Srmacklem * We run vnode_pager_setsize() early (why?), 935191783Srmacklem * we must set np->n_size now to avoid vinvalbuf 936191783Srmacklem * V_SAVE races that might setsize a lower 937191783Srmacklem * value. 938191783Srmacklem */ 939191783Srmacklem mtx_lock(&np->n_mtx); 940191783Srmacklem tsize = np->n_size; 941191783Srmacklem mtx_unlock(&np->n_mtx); 942191783Srmacklem error = ncl_meta_setsize(vp, ap->a_cred, td, 943191783Srmacklem vap->va_size); 944191783Srmacklem mtx_lock(&np->n_mtx); 945191783Srmacklem if (np->n_flag & NMODIFIED) { 946191783Srmacklem tsize = np->n_size; 947191783Srmacklem mtx_unlock(&np->n_mtx); 948191783Srmacklem if (vap->va_size == 0) 949191783Srmacklem error = ncl_vinvalbuf(vp, 0, td, 1); 950191783Srmacklem else 951191783Srmacklem error = ncl_vinvalbuf(vp, V_SAVE, td, 1); 952191783Srmacklem if (error) { 953191783Srmacklem vnode_pager_setsize(vp, tsize); 954191783Srmacklem return (error); 955191783Srmacklem } 956191783Srmacklem /* 957191783Srmacklem * Call nfscl_delegmodtime() to set the modify time 958191783Srmacklem * locally, as required. 959191783Srmacklem */ 960191783Srmacklem nfscl_delegmodtime(vp); 961191783Srmacklem } else 962191783Srmacklem mtx_unlock(&np->n_mtx); 963191783Srmacklem /* 964191783Srmacklem * np->n_size has already been set to vap->va_size 965191783Srmacklem * in ncl_meta_setsize(). We must set it again since 966191783Srmacklem * nfs_loadattrcache() could be called through 967191783Srmacklem * ncl_meta_setsize() and could modify np->n_size. 968191783Srmacklem */ 969191783Srmacklem mtx_lock(&np->n_mtx); 970191783Srmacklem np->n_vattr.na_size = np->n_size = vap->va_size; 971191783Srmacklem mtx_unlock(&np->n_mtx); 972191783Srmacklem }; 973191783Srmacklem } else { 974191783Srmacklem mtx_lock(&np->n_mtx); 975191783Srmacklem if ((vap->va_mtime.tv_sec != VNOVAL || vap->va_atime.tv_sec != VNOVAL) && 976191783Srmacklem (np->n_flag & NMODIFIED) && vp->v_type == VREG) { 977191783Srmacklem mtx_unlock(&np->n_mtx); 978191783Srmacklem if ((error = ncl_vinvalbuf(vp, V_SAVE, td, 1)) != 0 && 979191783Srmacklem (error == EINTR || error == EIO)) 980191783Srmacklem return (error); 981191783Srmacklem } else 982191783Srmacklem mtx_unlock(&np->n_mtx); 983191783Srmacklem } 984191783Srmacklem error = nfs_setattrrpc(vp, vap, ap->a_cred, td); 985191783Srmacklem if (error && vap->va_size != VNOVAL) { 986191783Srmacklem mtx_lock(&np->n_mtx); 987191783Srmacklem np->n_size = np->n_vattr.na_size = tsize; 988191783Srmacklem vnode_pager_setsize(vp, tsize); 989191783Srmacklem mtx_unlock(&np->n_mtx); 990191783Srmacklem } 991191783Srmacklem return (error); 992191783Srmacklem} 993191783Srmacklem 994191783Srmacklem/* 995191783Srmacklem * Do an nfs setattr rpc. 996191783Srmacklem */ 997191783Srmacklemstatic int 998191783Srmacklemnfs_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred, 999191783Srmacklem struct thread *td) 1000191783Srmacklem{ 1001191783Srmacklem struct nfsnode *np = VTONFS(vp); 1002191783Srmacklem int error, ret, attrflag, i; 1003191783Srmacklem struct nfsvattr nfsva; 1004191783Srmacklem 1005191783Srmacklem if (NFS_ISV34(vp)) { 1006191783Srmacklem mtx_lock(&np->n_mtx); 1007191783Srmacklem for (i = 0; i < NFS_ACCESSCACHESIZE; i++) 1008191783Srmacklem np->n_accesscache[i].stamp = 0; 1009191783Srmacklem np->n_flag |= NDELEGMOD; 1010191783Srmacklem mtx_unlock(&np->n_mtx); 1011223280Srmacklem KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp); 1012191783Srmacklem } 1013191783Srmacklem error = nfsrpc_setattr(vp, vap, NULL, cred, td, &nfsva, &attrflag, 1014191783Srmacklem NULL); 1015191783Srmacklem if (attrflag) { 1016191783Srmacklem ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1017191783Srmacklem if (ret && !error) 1018191783Srmacklem error = ret; 1019191783Srmacklem } 1020191783Srmacklem if (error && NFS_ISV4(vp)) 1021191783Srmacklem error = nfscl_maperr(td, error, vap->va_uid, vap->va_gid); 1022191783Srmacklem return (error); 1023191783Srmacklem} 1024191783Srmacklem 1025191783Srmacklem/* 1026191783Srmacklem * nfs lookup call, one step at a time... 1027191783Srmacklem * First look in cache 1028191783Srmacklem * If not found, unlock the directory nfsnode and do the rpc 1029191783Srmacklem */ 1030191783Srmacklemstatic int 1031191783Srmacklemnfs_lookup(struct vop_lookup_args *ap) 1032191783Srmacklem{ 1033191783Srmacklem struct componentname *cnp = ap->a_cnp; 1034191783Srmacklem struct vnode *dvp = ap->a_dvp; 1035191783Srmacklem struct vnode **vpp = ap->a_vpp; 1036194363Srmacklem struct mount *mp = dvp->v_mount; 1037191783Srmacklem int flags = cnp->cn_flags; 1038191783Srmacklem struct vnode *newvp; 1039191783Srmacklem struct nfsmount *nmp; 1040210135Sjhb struct nfsnode *np, *newnp; 1041233285Sjhb int error = 0, attrflag, dattrflag, ltype, ncticks; 1042191783Srmacklem struct thread *td = cnp->cn_thread; 1043191783Srmacklem struct nfsfh *nfhp; 1044191783Srmacklem struct nfsvattr dnfsva, nfsva; 1045203303Srmacklem struct vattr vattr; 1046233285Sjhb struct timespec nctime; 1047191783Srmacklem 1048191783Srmacklem *vpp = NULLVP; 1049194363Srmacklem if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && 1050191783Srmacklem (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 1051191783Srmacklem return (EROFS); 1052191783Srmacklem if (dvp->v_type != VDIR) 1053191783Srmacklem return (ENOTDIR); 1054194363Srmacklem nmp = VFSTONFS(mp); 1055191783Srmacklem np = VTONFS(dvp); 1056191783Srmacklem 1057191783Srmacklem /* For NFSv4, wait until any remove is done. */ 1058191783Srmacklem mtx_lock(&np->n_mtx); 1059191783Srmacklem while (NFSHASNFSV4(nmp) && (np->n_flag & NREMOVEINPROG)) { 1060191783Srmacklem np->n_flag |= NREMOVEWANT; 1061191783Srmacklem (void) msleep((caddr_t)np, &np->n_mtx, PZERO, "nfslkup", 0); 1062191783Srmacklem } 1063191783Srmacklem mtx_unlock(&np->n_mtx); 1064191783Srmacklem 1065191783Srmacklem if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1066191783Srmacklem return (error); 1067233285Sjhb error = cache_lookup_times(dvp, vpp, cnp, &nctime, &ncticks); 1068203303Srmacklem if (error > 0 && error != ENOENT) 1069203303Srmacklem return (error); 1070203303Srmacklem if (error == -1) { 1071203303Srmacklem /* 1072233285Sjhb * Lookups of "." are special and always return the 1073233285Sjhb * current directory. cache_lookup() already handles 1074233285Sjhb * associated locking bookkeeping, etc. 1075233285Sjhb */ 1076233285Sjhb if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 1077233285Sjhb /* XXX: Is this really correct? */ 1078233285Sjhb if (cnp->cn_nameiop != LOOKUP && 1079233285Sjhb (flags & ISLASTCN)) 1080233285Sjhb cnp->cn_flags |= SAVENAME; 1081233285Sjhb return (0); 1082233285Sjhb } 1083233285Sjhb 1084233285Sjhb /* 1085203303Srmacklem * We only accept a positive hit in the cache if the 1086203303Srmacklem * change time of the file matches our cached copy. 1087203303Srmacklem * Otherwise, we discard the cache entry and fallback 1088233326Sjhb * to doing a lookup RPC. We also only trust cache 1089233326Sjhb * entries for less than nm_nametimeo seconds. 1090210135Sjhb * 1091210135Sjhb * To better handle stale file handles and attributes, 1092210135Sjhb * clear the attribute cache of this node if it is a 1093210135Sjhb * leaf component, part of an open() call, and not 1094210135Sjhb * locally modified before fetching the attributes. 1095210135Sjhb * This should allow stale file handles to be detected 1096210135Sjhb * here where we can fall back to a LOOKUP RPC to 1097210135Sjhb * recover rather than having nfs_open() detect the 1098210135Sjhb * stale file handle and failing open(2) with ESTALE. 1099203303Srmacklem */ 1100203303Srmacklem newvp = *vpp; 1101210135Sjhb newnp = VTONFS(newvp); 1102221436Sru if (!(nmp->nm_flag & NFSMNT_NOCTO) && 1103221436Sru (flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) && 1104210135Sjhb !(newnp->n_flag & NMODIFIED)) { 1105210135Sjhb mtx_lock(&newnp->n_mtx); 1106210135Sjhb newnp->n_attrstamp = 0; 1107223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp); 1108210135Sjhb mtx_unlock(&newnp->n_mtx); 1109210135Sjhb } 1110203303Srmacklem if (nfscl_nodeleg(newvp, 0) == 0 || 1111233326Sjhb ((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) && 1112233326Sjhb VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 && 1113233285Sjhb timespeccmp(&vattr.va_ctime, &nctime, ==))) { 1114203303Srmacklem NFSINCRGLOBAL(newnfsstats.lookupcache_hits); 1115203303Srmacklem if (cnp->cn_nameiop != LOOKUP && 1116203303Srmacklem (flags & ISLASTCN)) 1117203303Srmacklem cnp->cn_flags |= SAVENAME; 1118203303Srmacklem return (0); 1119191783Srmacklem } 1120203303Srmacklem cache_purge(newvp); 1121203303Srmacklem if (dvp != newvp) 1122203303Srmacklem vput(newvp); 1123203303Srmacklem else 1124203303Srmacklem vrele(newvp); 1125203303Srmacklem *vpp = NULLVP; 1126203303Srmacklem } else if (error == ENOENT) { 1127203303Srmacklem if (dvp->v_iflag & VI_DOOMED) 1128203303Srmacklem return (ENOENT); 1129203303Srmacklem /* 1130203303Srmacklem * We only accept a negative hit in the cache if the 1131203303Srmacklem * modification time of the parent directory matches 1132233285Sjhb * the cached copy in the name cache entry. 1133233285Sjhb * Otherwise, we discard all of the negative cache 1134233285Sjhb * entries for this directory. We also only trust 1135233285Sjhb * negative cache entries for up to nm_negnametimeo 1136233285Sjhb * seconds. 1137203303Srmacklem */ 1138233285Sjhb if ((u_int)(ticks - ncticks) < (nmp->nm_negnametimeo * hz) && 1139203303Srmacklem VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 && 1140233285Sjhb timespeccmp(&vattr.va_mtime, &nctime, ==)) { 1141203303Srmacklem NFSINCRGLOBAL(newnfsstats.lookupcache_hits); 1142203303Srmacklem return (ENOENT); 1143203303Srmacklem } 1144203303Srmacklem cache_purge_negative(dvp); 1145191783Srmacklem } 1146203303Srmacklem 1147191783Srmacklem error = 0; 1148191783Srmacklem newvp = NULLVP; 1149191783Srmacklem NFSINCRGLOBAL(newnfsstats.lookupcache_misses); 1150191783Srmacklem error = nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 1151191783Srmacklem cnp->cn_cred, td, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 1152191783Srmacklem NULL); 1153191783Srmacklem if (dattrflag) 1154191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1155191783Srmacklem if (error) { 1156191783Srmacklem if (newvp != NULLVP) { 1157191783Srmacklem vput(newvp); 1158191783Srmacklem *vpp = NULLVP; 1159191783Srmacklem } 1160203303Srmacklem 1161203303Srmacklem if (error != ENOENT) { 1162203303Srmacklem if (NFS_ISV4(dvp)) 1163203303Srmacklem error = nfscl_maperr(td, error, (uid_t)0, 1164203303Srmacklem (gid_t)0); 1165203303Srmacklem return (error); 1166203303Srmacklem } 1167203303Srmacklem 1168203303Srmacklem /* The requested file was not found. */ 1169191783Srmacklem if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 1170203303Srmacklem (flags & ISLASTCN)) { 1171203303Srmacklem /* 1172203303Srmacklem * XXX: UFS does a full VOP_ACCESS(dvp, 1173203303Srmacklem * VWRITE) here instead of just checking 1174203303Srmacklem * MNT_RDONLY. 1175203303Srmacklem */ 1176194363Srmacklem if (mp->mnt_flag & MNT_RDONLY) 1177203303Srmacklem return (EROFS); 1178203303Srmacklem cnp->cn_flags |= SAVENAME; 1179203303Srmacklem return (EJUSTRETURN); 1180191783Srmacklem } 1181203303Srmacklem 1182233285Sjhb if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE && 1183233285Sjhb dattrflag) { 1184203303Srmacklem /* 1185233285Sjhb * Cache the modification time of the parent 1186233285Sjhb * directory from the post-op attributes in 1187233285Sjhb * the name cache entry. The negative cache 1188233285Sjhb * entry will be ignored once the directory 1189233285Sjhb * has changed. Don't bother adding the entry 1190233285Sjhb * if the directory has already changed. 1191203303Srmacklem */ 1192203303Srmacklem mtx_lock(&np->n_mtx); 1193233285Sjhb if (timespeccmp(&np->n_vattr.na_mtime, 1194233285Sjhb &dnfsva.na_mtime, ==)) { 1195203303Srmacklem mtx_unlock(&np->n_mtx); 1196233285Sjhb cache_enter_time(dvp, NULL, cnp, 1197233285Sjhb &dnfsva.na_mtime, NULL); 1198203303Srmacklem } else 1199203303Srmacklem mtx_unlock(&np->n_mtx); 1200203303Srmacklem } 1201203303Srmacklem return (ENOENT); 1202191783Srmacklem } 1203191783Srmacklem 1204191783Srmacklem /* 1205191783Srmacklem * Handle RENAME case... 1206191783Srmacklem */ 1207191783Srmacklem if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) { 1208191783Srmacklem if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) { 1209191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 1210191783Srmacklem return (EISDIR); 1211191783Srmacklem } 1212220732Srmacklem error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL, 1213220732Srmacklem LK_EXCLUSIVE); 1214191783Srmacklem if (error) 1215191783Srmacklem return (error); 1216191783Srmacklem newvp = NFSTOV(np); 1217191783Srmacklem if (attrflag) 1218191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1219191783Srmacklem 0, 1); 1220191783Srmacklem *vpp = newvp; 1221191783Srmacklem cnp->cn_flags |= SAVENAME; 1222191783Srmacklem return (0); 1223191783Srmacklem } 1224191783Srmacklem 1225194363Srmacklem if (flags & ISDOTDOT) { 1226224083Szack ltype = NFSVOPISLOCKED(dvp); 1227194363Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 1228194363Srmacklem if (error != 0) { 1229195641Srmacklem vfs_ref(mp); 1230224082Szack NFSVOPUNLOCK(dvp, 0); 1231194363Srmacklem error = vfs_busy(mp, 0); 1232224081Szack NFSVOPLOCK(dvp, ltype | LK_RETRY); 1233195641Srmacklem vfs_rel(mp); 1234194363Srmacklem if (error == 0 && (dvp->v_iflag & VI_DOOMED)) { 1235194363Srmacklem vfs_unbusy(mp); 1236194363Srmacklem error = ENOENT; 1237194363Srmacklem } 1238194363Srmacklem if (error != 0) 1239194363Srmacklem return (error); 1240194363Srmacklem } 1241224082Szack NFSVOPUNLOCK(dvp, 0); 1242220732Srmacklem error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL, 1243220732Srmacklem cnp->cn_lkflags); 1244194363Srmacklem if (error == 0) 1245194363Srmacklem newvp = NFSTOV(np); 1246194363Srmacklem vfs_unbusy(mp); 1247195704Srmacklem if (newvp != dvp) 1248224081Szack NFSVOPLOCK(dvp, ltype | LK_RETRY); 1249194363Srmacklem if (dvp->v_iflag & VI_DOOMED) { 1250194363Srmacklem if (error == 0) { 1251194363Srmacklem if (newvp == dvp) 1252194363Srmacklem vrele(newvp); 1253194363Srmacklem else 1254194363Srmacklem vput(newvp); 1255194363Srmacklem } 1256194363Srmacklem error = ENOENT; 1257194363Srmacklem } 1258194363Srmacklem if (error != 0) 1259191783Srmacklem return (error); 1260191783Srmacklem if (attrflag) 1261191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1262191783Srmacklem 0, 1); 1263191783Srmacklem } else if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) { 1264191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 1265191783Srmacklem VREF(dvp); 1266191783Srmacklem newvp = dvp; 1267191783Srmacklem if (attrflag) 1268191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1269191783Srmacklem 0, 1); 1270191783Srmacklem } else { 1271220732Srmacklem error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL, 1272220732Srmacklem cnp->cn_lkflags); 1273191783Srmacklem if (error) 1274191783Srmacklem return (error); 1275191783Srmacklem newvp = NFSTOV(np); 1276191783Srmacklem if (attrflag) 1277191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1278191783Srmacklem 0, 1); 1279210135Sjhb else if ((flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) && 1280210135Sjhb !(np->n_flag & NMODIFIED)) { 1281210135Sjhb /* 1282210135Sjhb * Flush the attribute cache when opening a 1283210135Sjhb * leaf node to ensure that fresh attributes 1284210135Sjhb * are fetched in nfs_open() since we did not 1285210135Sjhb * fetch attributes from the LOOKUP reply. 1286210135Sjhb */ 1287210135Sjhb mtx_lock(&np->n_mtx); 1288210135Sjhb np->n_attrstamp = 0; 1289223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp); 1290210135Sjhb mtx_unlock(&np->n_mtx); 1291210135Sjhb } 1292191783Srmacklem } 1293191783Srmacklem if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 1294191783Srmacklem cnp->cn_flags |= SAVENAME; 1295191783Srmacklem if ((cnp->cn_flags & MAKEENTRY) && 1296233285Sjhb (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)) && 1297233285Sjhb attrflag != 0 && (newvp->v_type != VDIR || dattrflag != 0)) 1298233285Sjhb cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, 1299233285Sjhb newvp->v_type != VDIR ? NULL : &dnfsva.na_ctime); 1300191783Srmacklem *vpp = newvp; 1301191783Srmacklem return (0); 1302191783Srmacklem} 1303191783Srmacklem 1304191783Srmacklem/* 1305191783Srmacklem * nfs read call. 1306191783Srmacklem * Just call ncl_bioread() to do the work. 1307191783Srmacklem */ 1308191783Srmacklemstatic int 1309191783Srmacklemnfs_read(struct vop_read_args *ap) 1310191783Srmacklem{ 1311191783Srmacklem struct vnode *vp = ap->a_vp; 1312191783Srmacklem 1313191783Srmacklem switch (vp->v_type) { 1314191783Srmacklem case VREG: 1315191783Srmacklem return (ncl_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 1316191783Srmacklem case VDIR: 1317191783Srmacklem return (EISDIR); 1318191783Srmacklem default: 1319191783Srmacklem return (EOPNOTSUPP); 1320191783Srmacklem } 1321191783Srmacklem} 1322191783Srmacklem 1323191783Srmacklem/* 1324191783Srmacklem * nfs readlink call 1325191783Srmacklem */ 1326191783Srmacklemstatic int 1327191783Srmacklemnfs_readlink(struct vop_readlink_args *ap) 1328191783Srmacklem{ 1329191783Srmacklem struct vnode *vp = ap->a_vp; 1330191783Srmacklem 1331191783Srmacklem if (vp->v_type != VLNK) 1332191783Srmacklem return (EINVAL); 1333191783Srmacklem return (ncl_bioread(vp, ap->a_uio, 0, ap->a_cred)); 1334191783Srmacklem} 1335191783Srmacklem 1336191783Srmacklem/* 1337191783Srmacklem * Do a readlink rpc. 1338191783Srmacklem * Called by ncl_doio() from below the buffer cache. 1339191783Srmacklem */ 1340191783Srmacklemint 1341191783Srmacklemncl_readlinkrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) 1342191783Srmacklem{ 1343191783Srmacklem int error, ret, attrflag; 1344191783Srmacklem struct nfsvattr nfsva; 1345191783Srmacklem 1346191783Srmacklem error = nfsrpc_readlink(vp, uiop, cred, uiop->uio_td, &nfsva, 1347191783Srmacklem &attrflag, NULL); 1348191783Srmacklem if (attrflag) { 1349191783Srmacklem ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1350191783Srmacklem if (ret && !error) 1351191783Srmacklem error = ret; 1352191783Srmacklem } 1353191783Srmacklem if (error && NFS_ISV4(vp)) 1354191783Srmacklem error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); 1355191783Srmacklem return (error); 1356191783Srmacklem} 1357191783Srmacklem 1358191783Srmacklem/* 1359191783Srmacklem * nfs read rpc call 1360191783Srmacklem * Ditto above 1361191783Srmacklem */ 1362191783Srmacklemint 1363191783Srmacklemncl_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) 1364191783Srmacklem{ 1365191783Srmacklem int error, ret, attrflag; 1366191783Srmacklem struct nfsvattr nfsva; 1367191783Srmacklem 1368191783Srmacklem error = nfsrpc_read(vp, uiop, cred, uiop->uio_td, &nfsva, &attrflag, 1369191783Srmacklem NULL); 1370191783Srmacklem if (attrflag) { 1371191783Srmacklem ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1372191783Srmacklem if (ret && !error) 1373191783Srmacklem error = ret; 1374191783Srmacklem } 1375191783Srmacklem if (error && NFS_ISV4(vp)) 1376191783Srmacklem error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); 1377191783Srmacklem return (error); 1378191783Srmacklem} 1379191783Srmacklem 1380191783Srmacklem/* 1381191783Srmacklem * nfs write call 1382191783Srmacklem */ 1383191783Srmacklemint 1384191783Srmacklemncl_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, 1385207082Srmacklem int *iomode, int *must_commit, int called_from_strategy) 1386191783Srmacklem{ 1387191783Srmacklem struct nfsvattr nfsva; 1388191783Srmacklem int error = 0, attrflag, ret; 1389191783Srmacklem 1390222289Srmacklem error = nfsrpc_write(vp, uiop, iomode, must_commit, cred, 1391207082Srmacklem uiop->uio_td, &nfsva, &attrflag, NULL, called_from_strategy); 1392191783Srmacklem if (attrflag) { 1393191783Srmacklem if (VTONFS(vp)->n_flag & ND_NFSV4) 1394191783Srmacklem ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 1, 1395191783Srmacklem 1); 1396191783Srmacklem else 1397191783Srmacklem ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1398191783Srmacklem 1); 1399191783Srmacklem if (ret && !error) 1400191783Srmacklem error = ret; 1401191783Srmacklem } 1402231936Skib if (DOINGASYNC(vp)) 1403191783Srmacklem *iomode = NFSWRITE_FILESYNC; 1404191783Srmacklem if (error && NFS_ISV4(vp)) 1405191783Srmacklem error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); 1406191783Srmacklem return (error); 1407191783Srmacklem} 1408191783Srmacklem 1409191783Srmacklem/* 1410191783Srmacklem * nfs mknod rpc 1411191783Srmacklem * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1412191783Srmacklem * mode set to specify the file type and the size field for rdev. 1413191783Srmacklem */ 1414191783Srmacklemstatic int 1415191783Srmacklemnfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 1416191783Srmacklem struct vattr *vap) 1417191783Srmacklem{ 1418191783Srmacklem struct nfsvattr nfsva, dnfsva; 1419191783Srmacklem struct vnode *newvp = NULL; 1420191783Srmacklem struct nfsnode *np = NULL, *dnp; 1421191783Srmacklem struct nfsfh *nfhp; 1422191783Srmacklem struct vattr vattr; 1423191783Srmacklem int error = 0, attrflag, dattrflag; 1424191783Srmacklem u_int32_t rdev; 1425191783Srmacklem 1426191783Srmacklem if (vap->va_type == VCHR || vap->va_type == VBLK) 1427191783Srmacklem rdev = vap->va_rdev; 1428191783Srmacklem else if (vap->va_type == VFIFO || vap->va_type == VSOCK) 1429191783Srmacklem rdev = 0xffffffff; 1430191783Srmacklem else 1431191783Srmacklem return (EOPNOTSUPP); 1432191783Srmacklem if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 1433191783Srmacklem return (error); 1434191783Srmacklem error = nfsrpc_mknod(dvp, cnp->cn_nameptr, cnp->cn_namelen, vap, 1435191783Srmacklem rdev, vap->va_type, cnp->cn_cred, cnp->cn_thread, &dnfsva, 1436191783Srmacklem &nfsva, &nfhp, &attrflag, &dattrflag, NULL); 1437191783Srmacklem if (!error) { 1438191783Srmacklem if (!nfhp) 1439191783Srmacklem (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, 1440191783Srmacklem cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, 1441191783Srmacklem &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 1442191783Srmacklem NULL); 1443191783Srmacklem if (nfhp) 1444191783Srmacklem error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, 1445220732Srmacklem cnp->cn_thread, &np, NULL, LK_EXCLUSIVE); 1446191783Srmacklem } 1447191783Srmacklem if (dattrflag) 1448191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1449191783Srmacklem if (!error) { 1450191783Srmacklem newvp = NFSTOV(np); 1451220763Srmacklem if (attrflag != 0) { 1452191783Srmacklem error = nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1453191783Srmacklem 0, 1); 1454220763Srmacklem if (error != 0) 1455220763Srmacklem vput(newvp); 1456220763Srmacklem } 1457191783Srmacklem } 1458191783Srmacklem if (!error) { 1459191783Srmacklem *vpp = newvp; 1460191783Srmacklem } else if (NFS_ISV4(dvp)) { 1461191783Srmacklem error = nfscl_maperr(cnp->cn_thread, error, vap->va_uid, 1462191783Srmacklem vap->va_gid); 1463191783Srmacklem } 1464191783Srmacklem dnp = VTONFS(dvp); 1465191783Srmacklem mtx_lock(&dnp->n_mtx); 1466191783Srmacklem dnp->n_flag |= NMODIFIED; 1467223280Srmacklem if (!dattrflag) { 1468191783Srmacklem dnp->n_attrstamp = 0; 1469223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 1470223280Srmacklem } 1471191783Srmacklem mtx_unlock(&dnp->n_mtx); 1472191783Srmacklem return (error); 1473191783Srmacklem} 1474191783Srmacklem 1475191783Srmacklem/* 1476191783Srmacklem * nfs mknod vop 1477191783Srmacklem * just call nfs_mknodrpc() to do the work. 1478191783Srmacklem */ 1479191783Srmacklem/* ARGSUSED */ 1480191783Srmacklemstatic int 1481191783Srmacklemnfs_mknod(struct vop_mknod_args *ap) 1482191783Srmacklem{ 1483191783Srmacklem return (nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap)); 1484191783Srmacklem} 1485191783Srmacklem 1486199189Sjhstatic struct mtx nfs_cverf_mtx; 1487199189SjhMTX_SYSINIT(nfs_cverf_mtx, &nfs_cverf_mtx, "NFS create verifier mutex", 1488199189Sjh MTX_DEF); 1489199189Sjh 1490199189Sjhstatic nfsquad_t 1491199189Sjhnfs_get_cverf(void) 1492199189Sjh{ 1493199189Sjh static nfsquad_t cverf; 1494199189Sjh nfsquad_t ret; 1495199189Sjh static int cverf_initialized = 0; 1496199189Sjh 1497199189Sjh mtx_lock(&nfs_cverf_mtx); 1498199189Sjh if (cverf_initialized == 0) { 1499199189Sjh cverf.lval[0] = arc4random(); 1500199189Sjh cverf.lval[1] = arc4random(); 1501199189Sjh cverf_initialized = 1; 1502199189Sjh } else 1503199189Sjh cverf.qval++; 1504199189Sjh ret = cverf; 1505199189Sjh mtx_unlock(&nfs_cverf_mtx); 1506199189Sjh 1507199189Sjh return (ret); 1508199189Sjh} 1509199189Sjh 1510191783Srmacklem/* 1511191783Srmacklem * nfs file create call 1512191783Srmacklem */ 1513191783Srmacklemstatic int 1514191783Srmacklemnfs_create(struct vop_create_args *ap) 1515191783Srmacklem{ 1516191783Srmacklem struct vnode *dvp = ap->a_dvp; 1517191783Srmacklem struct vattr *vap = ap->a_vap; 1518191783Srmacklem struct componentname *cnp = ap->a_cnp; 1519191783Srmacklem struct nfsnode *np = NULL, *dnp; 1520191783Srmacklem struct vnode *newvp = NULL; 1521191783Srmacklem struct nfsmount *nmp; 1522191783Srmacklem struct nfsvattr dnfsva, nfsva; 1523191783Srmacklem struct nfsfh *nfhp; 1524191783Srmacklem nfsquad_t cverf; 1525191783Srmacklem int error = 0, attrflag, dattrflag, fmode = 0; 1526191783Srmacklem struct vattr vattr; 1527191783Srmacklem 1528191783Srmacklem /* 1529191783Srmacklem * Oops, not for me.. 1530191783Srmacklem */ 1531191783Srmacklem if (vap->va_type == VSOCK) 1532191783Srmacklem return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); 1533191783Srmacklem 1534191783Srmacklem if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 1535191783Srmacklem return (error); 1536191783Srmacklem if (vap->va_vaflags & VA_EXCLUSIVE) 1537191783Srmacklem fmode |= O_EXCL; 1538191783Srmacklem dnp = VTONFS(dvp); 1539191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 1540191783Srmacklemagain: 1541191783Srmacklem /* For NFSv4, wait until any remove is done. */ 1542191783Srmacklem mtx_lock(&dnp->n_mtx); 1543191783Srmacklem while (NFSHASNFSV4(nmp) && (dnp->n_flag & NREMOVEINPROG)) { 1544191783Srmacklem dnp->n_flag |= NREMOVEWANT; 1545191783Srmacklem (void) msleep((caddr_t)dnp, &dnp->n_mtx, PZERO, "nfscrt", 0); 1546191783Srmacklem } 1547191783Srmacklem mtx_unlock(&dnp->n_mtx); 1548191783Srmacklem 1549199189Sjh cverf = nfs_get_cverf(); 1550191783Srmacklem error = nfsrpc_create(dvp, cnp->cn_nameptr, cnp->cn_namelen, 1551191783Srmacklem vap, cverf, fmode, cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, 1552191783Srmacklem &nfhp, &attrflag, &dattrflag, NULL); 1553191783Srmacklem if (!error) { 1554191783Srmacklem if (nfhp == NULL) 1555191783Srmacklem (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, 1556191783Srmacklem cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, 1557191783Srmacklem &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 1558191783Srmacklem NULL); 1559191783Srmacklem if (nfhp != NULL) 1560191783Srmacklem error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, 1561220732Srmacklem cnp->cn_thread, &np, NULL, LK_EXCLUSIVE); 1562191783Srmacklem } 1563191783Srmacklem if (dattrflag) 1564191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1565191783Srmacklem if (!error) { 1566191783Srmacklem newvp = NFSTOV(np); 1567235397Srmacklem if (attrflag == 0) 1568235397Srmacklem error = nfsrpc_getattr(newvp, cnp->cn_cred, 1569235397Srmacklem cnp->cn_thread, &nfsva, NULL); 1570235397Srmacklem if (error == 0) 1571191783Srmacklem error = nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1572191783Srmacklem 0, 1); 1573191783Srmacklem } 1574191783Srmacklem if (error) { 1575191783Srmacklem if (newvp != NULL) { 1576220763Srmacklem vput(newvp); 1577191783Srmacklem newvp = NULL; 1578191783Srmacklem } 1579191783Srmacklem if (NFS_ISV34(dvp) && (fmode & O_EXCL) && 1580191783Srmacklem error == NFSERR_NOTSUPP) { 1581191783Srmacklem fmode &= ~O_EXCL; 1582191783Srmacklem goto again; 1583191783Srmacklem } 1584191783Srmacklem } else if (NFS_ISV34(dvp) && (fmode & O_EXCL)) { 1585191783Srmacklem if (nfscl_checksattr(vap, &nfsva)) { 1586220762Srmacklem /* 1587220762Srmacklem * We are normally called with only a partially 1588220762Srmacklem * initialized VAP. Since the NFSv3 spec says that 1589220762Srmacklem * the server may use the file attributes to 1590220762Srmacklem * store the verifier, the spec requires us to do a 1591220762Srmacklem * SETATTR RPC. FreeBSD servers store the verifier in 1592220762Srmacklem * atime, but we can't really assume that all servers 1593220762Srmacklem * will so we ensure that our SETATTR sets both atime 1594220762Srmacklem * and mtime. 1595220762Srmacklem */ 1596220762Srmacklem if (vap->va_mtime.tv_sec == VNOVAL) 1597220762Srmacklem vfs_timestamp(&vap->va_mtime); 1598220762Srmacklem if (vap->va_atime.tv_sec == VNOVAL) 1599220762Srmacklem vap->va_atime = vap->va_mtime; 1600191783Srmacklem error = nfsrpc_setattr(newvp, vap, NULL, cnp->cn_cred, 1601191783Srmacklem cnp->cn_thread, &nfsva, &attrflag, NULL); 1602191783Srmacklem if (error && (vap->va_uid != (uid_t)VNOVAL || 1603191783Srmacklem vap->va_gid != (gid_t)VNOVAL)) { 1604191783Srmacklem /* try again without setting uid/gid */ 1605191783Srmacklem vap->va_uid = (uid_t)VNOVAL; 1606191783Srmacklem vap->va_gid = (uid_t)VNOVAL; 1607191783Srmacklem error = nfsrpc_setattr(newvp, vap, NULL, 1608191783Srmacklem cnp->cn_cred, cnp->cn_thread, &nfsva, 1609191783Srmacklem &attrflag, NULL); 1610191783Srmacklem } 1611191783Srmacklem if (attrflag) 1612191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 1613191783Srmacklem NULL, 0, 1); 1614224532Srmacklem if (error != 0) 1615224532Srmacklem vput(newvp); 1616191783Srmacklem } 1617191783Srmacklem } 1618191783Srmacklem if (!error) { 1619233285Sjhb if ((cnp->cn_flags & MAKEENTRY) && attrflag) 1620233285Sjhb cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, 1621233285Sjhb NULL); 1622191783Srmacklem *ap->a_vpp = newvp; 1623191783Srmacklem } else if (NFS_ISV4(dvp)) { 1624191783Srmacklem error = nfscl_maperr(cnp->cn_thread, error, vap->va_uid, 1625191783Srmacklem vap->va_gid); 1626191783Srmacklem } 1627191783Srmacklem mtx_lock(&dnp->n_mtx); 1628191783Srmacklem dnp->n_flag |= NMODIFIED; 1629223280Srmacklem if (!dattrflag) { 1630191783Srmacklem dnp->n_attrstamp = 0; 1631223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 1632223280Srmacklem } 1633191783Srmacklem mtx_unlock(&dnp->n_mtx); 1634191783Srmacklem return (error); 1635191783Srmacklem} 1636191783Srmacklem 1637191783Srmacklem/* 1638191783Srmacklem * nfs file remove call 1639191783Srmacklem * To try and make nfs semantics closer to ufs semantics, a file that has 1640191783Srmacklem * other processes using the vnode is renamed instead of removed and then 1641191783Srmacklem * removed later on the last close. 1642191783Srmacklem * - If v_usecount > 1 1643191783Srmacklem * If a rename is not already in the works 1644191783Srmacklem * call nfs_sillyrename() to set it up 1645191783Srmacklem * else 1646191783Srmacklem * do the remove rpc 1647191783Srmacklem */ 1648191783Srmacklemstatic int 1649191783Srmacklemnfs_remove(struct vop_remove_args *ap) 1650191783Srmacklem{ 1651191783Srmacklem struct vnode *vp = ap->a_vp; 1652191783Srmacklem struct vnode *dvp = ap->a_dvp; 1653191783Srmacklem struct componentname *cnp = ap->a_cnp; 1654191783Srmacklem struct nfsnode *np = VTONFS(vp); 1655191783Srmacklem int error = 0; 1656191783Srmacklem struct vattr vattr; 1657191783Srmacklem 1658209120Skib KASSERT((cnp->cn_flags & HASBUF) != 0, ("nfs_remove: no name")); 1659209120Skib KASSERT(vrefcnt(vp) > 0, ("nfs_remove: bad v_usecount")); 1660191783Srmacklem if (vp->v_type == VDIR) 1661191783Srmacklem error = EPERM; 1662191783Srmacklem else if (vrefcnt(vp) == 1 || (np->n_sillyrename && 1663191783Srmacklem VOP_GETATTR(vp, &vattr, cnp->cn_cred) == 0 && 1664191783Srmacklem vattr.va_nlink > 1)) { 1665191783Srmacklem /* 1666191783Srmacklem * Purge the name cache so that the chance of a lookup for 1667191783Srmacklem * the name succeeding while the remove is in progress is 1668191783Srmacklem * minimized. Without node locking it can still happen, such 1669191783Srmacklem * that an I/O op returns ESTALE, but since you get this if 1670191783Srmacklem * another host removes the file.. 1671191783Srmacklem */ 1672191783Srmacklem cache_purge(vp); 1673191783Srmacklem /* 1674191783Srmacklem * throw away biocache buffers, mainly to avoid 1675191783Srmacklem * unnecessary delayed writes later. 1676191783Srmacklem */ 1677191783Srmacklem error = ncl_vinvalbuf(vp, 0, cnp->cn_thread, 1); 1678191783Srmacklem /* Do the rpc */ 1679191783Srmacklem if (error != EINTR && error != EIO) 1680191783Srmacklem error = nfs_removerpc(dvp, vp, cnp->cn_nameptr, 1681191783Srmacklem cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread); 1682191783Srmacklem /* 1683191783Srmacklem * Kludge City: If the first reply to the remove rpc is lost.. 1684191783Srmacklem * the reply to the retransmitted request will be ENOENT 1685191783Srmacklem * since the file was in fact removed 1686191783Srmacklem * Therefore, we cheat and return success. 1687191783Srmacklem */ 1688191783Srmacklem if (error == ENOENT) 1689191783Srmacklem error = 0; 1690191783Srmacklem } else if (!np->n_sillyrename) 1691191783Srmacklem error = nfs_sillyrename(dvp, vp, cnp); 1692220762Srmacklem mtx_lock(&np->n_mtx); 1693191783Srmacklem np->n_attrstamp = 0; 1694220762Srmacklem mtx_unlock(&np->n_mtx); 1695223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 1696191783Srmacklem return (error); 1697191783Srmacklem} 1698191783Srmacklem 1699191783Srmacklem/* 1700191783Srmacklem * nfs file remove rpc called from nfs_inactive 1701191783Srmacklem */ 1702191783Srmacklemint 1703191783Srmacklemncl_removeit(struct sillyrename *sp, struct vnode *vp) 1704191783Srmacklem{ 1705191783Srmacklem /* 1706191783Srmacklem * Make sure that the directory vnode is still valid. 1707191783Srmacklem * XXX we should lock sp->s_dvp here. 1708191783Srmacklem */ 1709191783Srmacklem if (sp->s_dvp->v_type == VBAD) 1710191783Srmacklem return (0); 1711191783Srmacklem return (nfs_removerpc(sp->s_dvp, vp, sp->s_name, sp->s_namlen, 1712191783Srmacklem sp->s_cred, NULL)); 1713191783Srmacklem} 1714191783Srmacklem 1715191783Srmacklem/* 1716191783Srmacklem * Nfs remove rpc, called from nfs_remove() and ncl_removeit(). 1717191783Srmacklem */ 1718191783Srmacklemstatic int 1719191783Srmacklemnfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name, 1720191783Srmacklem int namelen, struct ucred *cred, struct thread *td) 1721191783Srmacklem{ 1722191783Srmacklem struct nfsvattr dnfsva; 1723191783Srmacklem struct nfsnode *dnp = VTONFS(dvp); 1724191783Srmacklem int error = 0, dattrflag; 1725191783Srmacklem 1726191783Srmacklem mtx_lock(&dnp->n_mtx); 1727191783Srmacklem dnp->n_flag |= NREMOVEINPROG; 1728191783Srmacklem mtx_unlock(&dnp->n_mtx); 1729191783Srmacklem error = nfsrpc_remove(dvp, name, namelen, vp, cred, td, &dnfsva, 1730191783Srmacklem &dattrflag, NULL); 1731191783Srmacklem mtx_lock(&dnp->n_mtx); 1732191783Srmacklem if ((dnp->n_flag & NREMOVEWANT)) { 1733191783Srmacklem dnp->n_flag &= ~(NREMOVEWANT | NREMOVEINPROG); 1734191783Srmacklem mtx_unlock(&dnp->n_mtx); 1735191783Srmacklem wakeup((caddr_t)dnp); 1736191783Srmacklem } else { 1737191783Srmacklem dnp->n_flag &= ~NREMOVEINPROG; 1738191783Srmacklem mtx_unlock(&dnp->n_mtx); 1739191783Srmacklem } 1740191783Srmacklem if (dattrflag) 1741191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1742191783Srmacklem mtx_lock(&dnp->n_mtx); 1743191783Srmacklem dnp->n_flag |= NMODIFIED; 1744223280Srmacklem if (!dattrflag) { 1745191783Srmacklem dnp->n_attrstamp = 0; 1746223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 1747223280Srmacklem } 1748191783Srmacklem mtx_unlock(&dnp->n_mtx); 1749191783Srmacklem if (error && NFS_ISV4(dvp)) 1750191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1751191783Srmacklem return (error); 1752191783Srmacklem} 1753191783Srmacklem 1754191783Srmacklem/* 1755191783Srmacklem * nfs file rename call 1756191783Srmacklem */ 1757191783Srmacklemstatic int 1758191783Srmacklemnfs_rename(struct vop_rename_args *ap) 1759191783Srmacklem{ 1760191783Srmacklem struct vnode *fvp = ap->a_fvp; 1761191783Srmacklem struct vnode *tvp = ap->a_tvp; 1762191783Srmacklem struct vnode *fdvp = ap->a_fdvp; 1763191783Srmacklem struct vnode *tdvp = ap->a_tdvp; 1764191783Srmacklem struct componentname *tcnp = ap->a_tcnp; 1765191783Srmacklem struct componentname *fcnp = ap->a_fcnp; 1766191783Srmacklem struct nfsnode *fnp = VTONFS(ap->a_fvp); 1767191783Srmacklem struct nfsnode *tdnp = VTONFS(ap->a_tdvp); 1768191783Srmacklem struct nfsv4node *newv4 = NULL; 1769191783Srmacklem int error; 1770191783Srmacklem 1771209120Skib KASSERT((tcnp->cn_flags & HASBUF) != 0 && 1772209120Skib (fcnp->cn_flags & HASBUF) != 0, ("nfs_rename: no name")); 1773191783Srmacklem /* Check for cross-device rename */ 1774191783Srmacklem if ((fvp->v_mount != tdvp->v_mount) || 1775191783Srmacklem (tvp && (fvp->v_mount != tvp->v_mount))) { 1776191783Srmacklem error = EXDEV; 1777191783Srmacklem goto out; 1778191783Srmacklem } 1779191783Srmacklem 1780191783Srmacklem if (fvp == tvp) { 1781191783Srmacklem ncl_printf("nfs_rename: fvp == tvp (can't happen)\n"); 1782191783Srmacklem error = 0; 1783191783Srmacklem goto out; 1784191783Srmacklem } 1785224081Szack if ((error = NFSVOPLOCK(fvp, LK_EXCLUSIVE)) != 0) 1786191783Srmacklem goto out; 1787191783Srmacklem 1788191783Srmacklem /* 1789191783Srmacklem * We have to flush B_DELWRI data prior to renaming 1790191783Srmacklem * the file. If we don't, the delayed-write buffers 1791191783Srmacklem * can be flushed out later after the file has gone stale 1792191783Srmacklem * under NFSV3. NFSV2 does not have this problem because 1793191783Srmacklem * ( as far as I can tell ) it flushes dirty buffers more 1794191783Srmacklem * often. 1795191783Srmacklem * 1796191783Srmacklem * Skip the rename operation if the fsync fails, this can happen 1797191783Srmacklem * due to the server's volume being full, when we pushed out data 1798191783Srmacklem * that was written back to our cache earlier. Not checking for 1799191783Srmacklem * this condition can result in potential (silent) data loss. 1800191783Srmacklem */ 1801191783Srmacklem error = VOP_FSYNC(fvp, MNT_WAIT, fcnp->cn_thread); 1802224082Szack NFSVOPUNLOCK(fvp, 0); 1803191783Srmacklem if (!error && tvp) 1804191783Srmacklem error = VOP_FSYNC(tvp, MNT_WAIT, tcnp->cn_thread); 1805191783Srmacklem if (error) 1806191783Srmacklem goto out; 1807191783Srmacklem 1808191783Srmacklem /* 1809191783Srmacklem * If the tvp exists and is in use, sillyrename it before doing the 1810191783Srmacklem * rename of the new file over it. 1811191783Srmacklem * XXX Can't sillyrename a directory. 1812191783Srmacklem */ 1813191783Srmacklem if (tvp && vrefcnt(tvp) > 1 && !VTONFS(tvp)->n_sillyrename && 1814191783Srmacklem tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { 1815191783Srmacklem vput(tvp); 1816191783Srmacklem tvp = NULL; 1817191783Srmacklem } 1818191783Srmacklem 1819191783Srmacklem error = nfs_renamerpc(fdvp, fvp, fcnp->cn_nameptr, fcnp->cn_namelen, 1820191783Srmacklem tdvp, tvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, 1821191783Srmacklem tcnp->cn_thread); 1822191783Srmacklem 1823220762Srmacklem if (error == 0 && NFS_ISV4(tdvp)) { 1824191783Srmacklem /* 1825191783Srmacklem * For NFSv4, check to see if it is the same name and 1826191783Srmacklem * replace the name, if it is different. 1827191783Srmacklem */ 1828191783Srmacklem MALLOC(newv4, struct nfsv4node *, 1829191783Srmacklem sizeof (struct nfsv4node) + 1830191783Srmacklem tdnp->n_fhp->nfh_len + tcnp->cn_namelen - 1, 1831191783Srmacklem M_NFSV4NODE, M_WAITOK); 1832191783Srmacklem mtx_lock(&tdnp->n_mtx); 1833191783Srmacklem mtx_lock(&fnp->n_mtx); 1834191783Srmacklem if (fnp->n_v4 != NULL && fvp->v_type == VREG && 1835191783Srmacklem (fnp->n_v4->n4_namelen != tcnp->cn_namelen || 1836191783Srmacklem NFSBCMP(tcnp->cn_nameptr, NFS4NODENAME(fnp->n_v4), 1837191783Srmacklem tcnp->cn_namelen) || 1838191783Srmacklem tdnp->n_fhp->nfh_len != fnp->n_v4->n4_fhlen || 1839191783Srmacklem NFSBCMP(tdnp->n_fhp->nfh_fh, fnp->n_v4->n4_data, 1840191783Srmacklem tdnp->n_fhp->nfh_len))) { 1841191783Srmacklem#ifdef notdef 1842191783Srmacklem{ char nnn[100]; int nnnl; 1843191783Srmacklemnnnl = (tcnp->cn_namelen < 100) ? tcnp->cn_namelen : 99; 1844191783Srmacklembcopy(tcnp->cn_nameptr, nnn, nnnl); 1845191783Srmacklemnnn[nnnl] = '\0'; 1846191783Srmacklemprintf("ren replace=%s\n",nnn); 1847191783Srmacklem} 1848191783Srmacklem#endif 1849191783Srmacklem FREE((caddr_t)fnp->n_v4, M_NFSV4NODE); 1850191783Srmacklem fnp->n_v4 = newv4; 1851191783Srmacklem newv4 = NULL; 1852191783Srmacklem fnp->n_v4->n4_fhlen = tdnp->n_fhp->nfh_len; 1853191783Srmacklem fnp->n_v4->n4_namelen = tcnp->cn_namelen; 1854191783Srmacklem NFSBCOPY(tdnp->n_fhp->nfh_fh, fnp->n_v4->n4_data, 1855191783Srmacklem tdnp->n_fhp->nfh_len); 1856191783Srmacklem NFSBCOPY(tcnp->cn_nameptr, 1857191783Srmacklem NFS4NODENAME(fnp->n_v4), tcnp->cn_namelen); 1858191783Srmacklem } 1859191783Srmacklem mtx_unlock(&tdnp->n_mtx); 1860191783Srmacklem mtx_unlock(&fnp->n_mtx); 1861191783Srmacklem if (newv4 != NULL) 1862191783Srmacklem FREE((caddr_t)newv4, M_NFSV4NODE); 1863191783Srmacklem } 1864191783Srmacklem 1865191783Srmacklem if (fvp->v_type == VDIR) { 1866191783Srmacklem if (tvp != NULL && tvp->v_type == VDIR) 1867191783Srmacklem cache_purge(tdvp); 1868191783Srmacklem cache_purge(fdvp); 1869191783Srmacklem } 1870191783Srmacklem 1871191783Srmacklemout: 1872191783Srmacklem if (tdvp == tvp) 1873191783Srmacklem vrele(tdvp); 1874191783Srmacklem else 1875191783Srmacklem vput(tdvp); 1876191783Srmacklem if (tvp) 1877191783Srmacklem vput(tvp); 1878191783Srmacklem vrele(fdvp); 1879191783Srmacklem vrele(fvp); 1880191783Srmacklem /* 1881191783Srmacklem * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 1882191783Srmacklem */ 1883191783Srmacklem if (error == ENOENT) 1884191783Srmacklem error = 0; 1885191783Srmacklem return (error); 1886191783Srmacklem} 1887191783Srmacklem 1888191783Srmacklem/* 1889191783Srmacklem * nfs file rename rpc called from nfs_remove() above 1890191783Srmacklem */ 1891191783Srmacklemstatic int 1892191783Srmacklemnfs_renameit(struct vnode *sdvp, struct vnode *svp, struct componentname *scnp, 1893191783Srmacklem struct sillyrename *sp) 1894191783Srmacklem{ 1895191783Srmacklem 1896191783Srmacklem return (nfs_renamerpc(sdvp, svp, scnp->cn_nameptr, scnp->cn_namelen, 1897191783Srmacklem sdvp, NULL, sp->s_name, sp->s_namlen, scnp->cn_cred, 1898191783Srmacklem scnp->cn_thread)); 1899191783Srmacklem} 1900191783Srmacklem 1901191783Srmacklem/* 1902191783Srmacklem * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). 1903191783Srmacklem */ 1904191783Srmacklemstatic int 1905191783Srmacklemnfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, char *fnameptr, 1906191783Srmacklem int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr, 1907191783Srmacklem int tnamelen, struct ucred *cred, struct thread *td) 1908191783Srmacklem{ 1909191783Srmacklem struct nfsvattr fnfsva, tnfsva; 1910191783Srmacklem struct nfsnode *fdnp = VTONFS(fdvp); 1911191783Srmacklem struct nfsnode *tdnp = VTONFS(tdvp); 1912191783Srmacklem int error = 0, fattrflag, tattrflag; 1913191783Srmacklem 1914191783Srmacklem error = nfsrpc_rename(fdvp, fvp, fnameptr, fnamelen, tdvp, tvp, 1915191783Srmacklem tnameptr, tnamelen, cred, td, &fnfsva, &tnfsva, &fattrflag, 1916191783Srmacklem &tattrflag, NULL, NULL); 1917191783Srmacklem mtx_lock(&fdnp->n_mtx); 1918191783Srmacklem fdnp->n_flag |= NMODIFIED; 1919220762Srmacklem if (fattrflag != 0) { 1920220762Srmacklem mtx_unlock(&fdnp->n_mtx); 1921220762Srmacklem (void) nfscl_loadattrcache(&fdvp, &fnfsva, NULL, NULL, 0, 1); 1922220762Srmacklem } else { 1923220762Srmacklem fdnp->n_attrstamp = 0; 1924220762Srmacklem mtx_unlock(&fdnp->n_mtx); 1925223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(fdvp); 1926220762Srmacklem } 1927191783Srmacklem mtx_lock(&tdnp->n_mtx); 1928191783Srmacklem tdnp->n_flag |= NMODIFIED; 1929220762Srmacklem if (tattrflag != 0) { 1930220762Srmacklem mtx_unlock(&tdnp->n_mtx); 1931191783Srmacklem (void) nfscl_loadattrcache(&tdvp, &tnfsva, NULL, NULL, 0, 1); 1932220762Srmacklem } else { 1933191783Srmacklem tdnp->n_attrstamp = 0; 1934220762Srmacklem mtx_unlock(&tdnp->n_mtx); 1935223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp); 1936220762Srmacklem } 1937191783Srmacklem if (error && NFS_ISV4(fdvp)) 1938191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1939191783Srmacklem return (error); 1940191783Srmacklem} 1941191783Srmacklem 1942191783Srmacklem/* 1943191783Srmacklem * nfs hard link create call 1944191783Srmacklem */ 1945191783Srmacklemstatic int 1946191783Srmacklemnfs_link(struct vop_link_args *ap) 1947191783Srmacklem{ 1948191783Srmacklem struct vnode *vp = ap->a_vp; 1949191783Srmacklem struct vnode *tdvp = ap->a_tdvp; 1950191783Srmacklem struct componentname *cnp = ap->a_cnp; 1951220762Srmacklem struct nfsnode *np, *tdnp; 1952191783Srmacklem struct nfsvattr nfsva, dnfsva; 1953191783Srmacklem int error = 0, attrflag, dattrflag; 1954191783Srmacklem 1955191783Srmacklem if (vp->v_mount != tdvp->v_mount) { 1956191783Srmacklem return (EXDEV); 1957191783Srmacklem } 1958191783Srmacklem 1959191783Srmacklem /* 1960191783Srmacklem * Push all writes to the server, so that the attribute cache 1961191783Srmacklem * doesn't get "out of sync" with the server. 1962191783Srmacklem * XXX There should be a better way! 1963191783Srmacklem */ 1964191783Srmacklem VOP_FSYNC(vp, MNT_WAIT, cnp->cn_thread); 1965191783Srmacklem 1966191783Srmacklem error = nfsrpc_link(tdvp, vp, cnp->cn_nameptr, cnp->cn_namelen, 1967191783Srmacklem cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, &attrflag, 1968191783Srmacklem &dattrflag, NULL); 1969191783Srmacklem tdnp = VTONFS(tdvp); 1970191783Srmacklem mtx_lock(&tdnp->n_mtx); 1971191783Srmacklem tdnp->n_flag |= NMODIFIED; 1972220762Srmacklem if (dattrflag != 0) { 1973220762Srmacklem mtx_unlock(&tdnp->n_mtx); 1974220762Srmacklem (void) nfscl_loadattrcache(&tdvp, &dnfsva, NULL, NULL, 0, 1); 1975220762Srmacklem } else { 1976220762Srmacklem tdnp->n_attrstamp = 0; 1977220762Srmacklem mtx_unlock(&tdnp->n_mtx); 1978223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp); 1979220762Srmacklem } 1980191783Srmacklem if (attrflag) 1981191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1982220762Srmacklem else { 1983220762Srmacklem np = VTONFS(vp); 1984220762Srmacklem mtx_lock(&np->n_mtx); 1985220762Srmacklem np->n_attrstamp = 0; 1986220762Srmacklem mtx_unlock(&np->n_mtx); 1987223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 1988220762Srmacklem } 1989191783Srmacklem /* 1990191783Srmacklem * If negative lookup caching is enabled, I might as well 1991191783Srmacklem * add an entry for this node. Not necessary for correctness, 1992191783Srmacklem * but if negative caching is enabled, then the system 1993191783Srmacklem * must care about lookup caching hit rate, so... 1994191783Srmacklem */ 1995203303Srmacklem if (VFSTONFS(vp->v_mount)->nm_negnametimeo != 0 && 1996233285Sjhb (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && error == 0) { 1997233285Sjhb cache_enter_time(tdvp, vp, cnp, &nfsva.na_ctime, NULL); 1998233285Sjhb } 1999191783Srmacklem if (error && NFS_ISV4(vp)) 2000191783Srmacklem error = nfscl_maperr(cnp->cn_thread, error, (uid_t)0, 2001191783Srmacklem (gid_t)0); 2002191783Srmacklem return (error); 2003191783Srmacklem} 2004191783Srmacklem 2005191783Srmacklem/* 2006191783Srmacklem * nfs symbolic link create call 2007191783Srmacklem */ 2008191783Srmacklemstatic int 2009191783Srmacklemnfs_symlink(struct vop_symlink_args *ap) 2010191783Srmacklem{ 2011191783Srmacklem struct vnode *dvp = ap->a_dvp; 2012191783Srmacklem struct vattr *vap = ap->a_vap; 2013191783Srmacklem struct componentname *cnp = ap->a_cnp; 2014191783Srmacklem struct nfsvattr nfsva, dnfsva; 2015191783Srmacklem struct nfsfh *nfhp; 2016191783Srmacklem struct nfsnode *np = NULL, *dnp; 2017191783Srmacklem struct vnode *newvp = NULL; 2018191783Srmacklem int error = 0, attrflag, dattrflag, ret; 2019191783Srmacklem 2020191783Srmacklem vap->va_type = VLNK; 2021191783Srmacklem error = nfsrpc_symlink(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2022191783Srmacklem ap->a_target, vap, cnp->cn_cred, cnp->cn_thread, &dnfsva, 2023191783Srmacklem &nfsva, &nfhp, &attrflag, &dattrflag, NULL); 2024191783Srmacklem if (nfhp) { 2025191783Srmacklem ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread, 2026220732Srmacklem &np, NULL, LK_EXCLUSIVE); 2027191783Srmacklem if (!ret) 2028191783Srmacklem newvp = NFSTOV(np); 2029191783Srmacklem else if (!error) 2030191783Srmacklem error = ret; 2031191783Srmacklem } 2032191783Srmacklem if (newvp != NULL) { 2033191783Srmacklem if (attrflag) 2034191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 2035191783Srmacklem 0, 1); 2036191783Srmacklem } else if (!error) { 2037191783Srmacklem /* 2038191783Srmacklem * If we do not have an error and we could not extract the 2039191783Srmacklem * newvp from the response due to the request being NFSv2, we 2040191783Srmacklem * have to do a lookup in order to obtain a newvp to return. 2041191783Srmacklem */ 2042191783Srmacklem error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2043191783Srmacklem cnp->cn_cred, cnp->cn_thread, &np); 2044191783Srmacklem if (!error) 2045191783Srmacklem newvp = NFSTOV(np); 2046191783Srmacklem } 2047191783Srmacklem if (error) { 2048191783Srmacklem if (newvp) 2049191783Srmacklem vput(newvp); 2050191783Srmacklem if (NFS_ISV4(dvp)) 2051191783Srmacklem error = nfscl_maperr(cnp->cn_thread, error, 2052191783Srmacklem vap->va_uid, vap->va_gid); 2053191783Srmacklem } else { 2054191783Srmacklem *ap->a_vpp = newvp; 2055191783Srmacklem } 2056191783Srmacklem 2057191783Srmacklem dnp = VTONFS(dvp); 2058191783Srmacklem mtx_lock(&dnp->n_mtx); 2059191783Srmacklem dnp->n_flag |= NMODIFIED; 2060220762Srmacklem if (dattrflag != 0) { 2061220762Srmacklem mtx_unlock(&dnp->n_mtx); 2062191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2063220762Srmacklem } else { 2064191783Srmacklem dnp->n_attrstamp = 0; 2065220762Srmacklem mtx_unlock(&dnp->n_mtx); 2066223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 2067220762Srmacklem } 2068233285Sjhb /* 2069233285Sjhb * If negative lookup caching is enabled, I might as well 2070233285Sjhb * add an entry for this node. Not necessary for correctness, 2071233285Sjhb * but if negative caching is enabled, then the system 2072233285Sjhb * must care about lookup caching hit rate, so... 2073233285Sjhb */ 2074233285Sjhb if (VFSTONFS(dvp->v_mount)->nm_negnametimeo != 0 && 2075233285Sjhb (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && error == 0) { 2076233285Sjhb cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, NULL); 2077233285Sjhb } 2078191783Srmacklem return (error); 2079191783Srmacklem} 2080191783Srmacklem 2081191783Srmacklem/* 2082191783Srmacklem * nfs make dir call 2083191783Srmacklem */ 2084191783Srmacklemstatic int 2085191783Srmacklemnfs_mkdir(struct vop_mkdir_args *ap) 2086191783Srmacklem{ 2087191783Srmacklem struct vnode *dvp = ap->a_dvp; 2088191783Srmacklem struct vattr *vap = ap->a_vap; 2089191783Srmacklem struct componentname *cnp = ap->a_cnp; 2090191783Srmacklem struct nfsnode *np = NULL, *dnp; 2091191783Srmacklem struct vnode *newvp = NULL; 2092191783Srmacklem struct vattr vattr; 2093191783Srmacklem struct nfsfh *nfhp; 2094191783Srmacklem struct nfsvattr nfsva, dnfsva; 2095191783Srmacklem int error = 0, attrflag, dattrflag, ret; 2096191783Srmacklem 2097220762Srmacklem if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred)) != 0) 2098191783Srmacklem return (error); 2099191783Srmacklem vap->va_type = VDIR; 2100191783Srmacklem error = nfsrpc_mkdir(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2101191783Srmacklem vap, cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, &nfhp, 2102191783Srmacklem &attrflag, &dattrflag, NULL); 2103191783Srmacklem dnp = VTONFS(dvp); 2104191783Srmacklem mtx_lock(&dnp->n_mtx); 2105191783Srmacklem dnp->n_flag |= NMODIFIED; 2106220762Srmacklem if (dattrflag != 0) { 2107220762Srmacklem mtx_unlock(&dnp->n_mtx); 2108191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2109220762Srmacklem } else { 2110191783Srmacklem dnp->n_attrstamp = 0; 2111220762Srmacklem mtx_unlock(&dnp->n_mtx); 2112223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 2113220762Srmacklem } 2114191783Srmacklem if (nfhp) { 2115191783Srmacklem ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread, 2116220732Srmacklem &np, NULL, LK_EXCLUSIVE); 2117191783Srmacklem if (!ret) { 2118191783Srmacklem newvp = NFSTOV(np); 2119191783Srmacklem if (attrflag) 2120191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 2121191783Srmacklem NULL, 0, 1); 2122191783Srmacklem } else if (!error) 2123191783Srmacklem error = ret; 2124191783Srmacklem } 2125191783Srmacklem if (!error && newvp == NULL) { 2126191783Srmacklem error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2127191783Srmacklem cnp->cn_cred, cnp->cn_thread, &np); 2128191783Srmacklem if (!error) { 2129191783Srmacklem newvp = NFSTOV(np); 2130191783Srmacklem if (newvp->v_type != VDIR) 2131191783Srmacklem error = EEXIST; 2132191783Srmacklem } 2133191783Srmacklem } 2134191783Srmacklem if (error) { 2135191783Srmacklem if (newvp) 2136191783Srmacklem vput(newvp); 2137191783Srmacklem if (NFS_ISV4(dvp)) 2138191783Srmacklem error = nfscl_maperr(cnp->cn_thread, error, 2139191783Srmacklem vap->va_uid, vap->va_gid); 2140191783Srmacklem } else { 2141191783Srmacklem /* 2142191783Srmacklem * If negative lookup caching is enabled, I might as well 2143191783Srmacklem * add an entry for this node. Not necessary for correctness, 2144191783Srmacklem * but if negative caching is enabled, then the system 2145191783Srmacklem * must care about lookup caching hit rate, so... 2146191783Srmacklem */ 2147203303Srmacklem if (VFSTONFS(dvp->v_mount)->nm_negnametimeo != 0 && 2148233285Sjhb (cnp->cn_flags & MAKEENTRY) && 2149233285Sjhb attrflag != 0 && dattrflag != 0) 2150233285Sjhb cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, 2151233285Sjhb &dnfsva.na_ctime); 2152191783Srmacklem *ap->a_vpp = newvp; 2153191783Srmacklem } 2154191783Srmacklem return (error); 2155191783Srmacklem} 2156191783Srmacklem 2157191783Srmacklem/* 2158191783Srmacklem * nfs remove directory call 2159191783Srmacklem */ 2160191783Srmacklemstatic int 2161191783Srmacklemnfs_rmdir(struct vop_rmdir_args *ap) 2162191783Srmacklem{ 2163191783Srmacklem struct vnode *vp = ap->a_vp; 2164191783Srmacklem struct vnode *dvp = ap->a_dvp; 2165191783Srmacklem struct componentname *cnp = ap->a_cnp; 2166191783Srmacklem struct nfsnode *dnp; 2167191783Srmacklem struct nfsvattr dnfsva; 2168191783Srmacklem int error, dattrflag; 2169191783Srmacklem 2170191783Srmacklem if (dvp == vp) 2171191783Srmacklem return (EINVAL); 2172191783Srmacklem error = nfsrpc_rmdir(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2173191783Srmacklem cnp->cn_cred, cnp->cn_thread, &dnfsva, &dattrflag, NULL); 2174191783Srmacklem dnp = VTONFS(dvp); 2175191783Srmacklem mtx_lock(&dnp->n_mtx); 2176191783Srmacklem dnp->n_flag |= NMODIFIED; 2177220762Srmacklem if (dattrflag != 0) { 2178220762Srmacklem mtx_unlock(&dnp->n_mtx); 2179191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2180220762Srmacklem } else { 2181191783Srmacklem dnp->n_attrstamp = 0; 2182220762Srmacklem mtx_unlock(&dnp->n_mtx); 2183223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 2184220762Srmacklem } 2185191783Srmacklem 2186191783Srmacklem cache_purge(dvp); 2187191783Srmacklem cache_purge(vp); 2188191783Srmacklem if (error && NFS_ISV4(dvp)) 2189191783Srmacklem error = nfscl_maperr(cnp->cn_thread, error, (uid_t)0, 2190191783Srmacklem (gid_t)0); 2191191783Srmacklem /* 2192191783Srmacklem * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2193191783Srmacklem */ 2194191783Srmacklem if (error == ENOENT) 2195191783Srmacklem error = 0; 2196191783Srmacklem return (error); 2197191783Srmacklem} 2198191783Srmacklem 2199191783Srmacklem/* 2200191783Srmacklem * nfs readdir call 2201191783Srmacklem */ 2202191783Srmacklemstatic int 2203191783Srmacklemnfs_readdir(struct vop_readdir_args *ap) 2204191783Srmacklem{ 2205191783Srmacklem struct vnode *vp = ap->a_vp; 2206191783Srmacklem struct nfsnode *np = VTONFS(vp); 2207191783Srmacklem struct uio *uio = ap->a_uio; 2208233353Skib ssize_t tresid; 2209233353Skib int error = 0; 2210191783Srmacklem struct vattr vattr; 2211191783Srmacklem 2212250996Srmacklem if (ap->a_eofflag != NULL) 2213250996Srmacklem *ap->a_eofflag = 0; 2214191783Srmacklem if (vp->v_type != VDIR) 2215191783Srmacklem return(EPERM); 2216191783Srmacklem 2217191783Srmacklem /* 2218191783Srmacklem * First, check for hit on the EOF offset cache 2219191783Srmacklem */ 2220191783Srmacklem if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset && 2221191783Srmacklem (np->n_flag & NMODIFIED) == 0) { 2222191783Srmacklem if (VOP_GETATTR(vp, &vattr, ap->a_cred) == 0) { 2223191783Srmacklem mtx_lock(&np->n_mtx); 2224191783Srmacklem if ((NFS_ISV4(vp) && np->n_change == vattr.va_filerev) || 2225191783Srmacklem !NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { 2226191783Srmacklem mtx_unlock(&np->n_mtx); 2227191783Srmacklem NFSINCRGLOBAL(newnfsstats.direofcache_hits); 2228250996Srmacklem if (ap->a_eofflag != NULL) 2229250996Srmacklem *ap->a_eofflag = 1; 2230191783Srmacklem return (0); 2231191783Srmacklem } else 2232191783Srmacklem mtx_unlock(&np->n_mtx); 2233191783Srmacklem } 2234191783Srmacklem } 2235191783Srmacklem 2236191783Srmacklem /* 2237191783Srmacklem * Call ncl_bioread() to do the real work. 2238191783Srmacklem */ 2239191783Srmacklem tresid = uio->uio_resid; 2240191783Srmacklem error = ncl_bioread(vp, uio, 0, ap->a_cred); 2241191783Srmacklem 2242250996Srmacklem if (!error && uio->uio_resid == tresid) { 2243191783Srmacklem NFSINCRGLOBAL(newnfsstats.direofcache_misses); 2244250996Srmacklem if (ap->a_eofflag != NULL) 2245250996Srmacklem *ap->a_eofflag = 1; 2246250996Srmacklem } 2247191783Srmacklem return (error); 2248191783Srmacklem} 2249191783Srmacklem 2250191783Srmacklem/* 2251191783Srmacklem * Readdir rpc call. 2252191783Srmacklem * Called from below the buffer cache by ncl_doio(). 2253191783Srmacklem */ 2254191783Srmacklemint 2255191783Srmacklemncl_readdirrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, 2256191783Srmacklem struct thread *td) 2257191783Srmacklem{ 2258191783Srmacklem struct nfsvattr nfsva; 2259191783Srmacklem nfsuint64 *cookiep, cookie; 2260191783Srmacklem struct nfsnode *dnp = VTONFS(vp); 2261191783Srmacklem struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2262191783Srmacklem int error = 0, eof, attrflag; 2263191783Srmacklem 2264209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2265209120Skib (uiop->uio_offset & (DIRBLKSIZ - 1)) == 0 && 2266209120Skib (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 2267209120Skib ("nfs readdirrpc bad uio")); 2268191783Srmacklem 2269191783Srmacklem /* 2270191783Srmacklem * If there is no cookie, assume directory was stale. 2271191783Srmacklem */ 2272191783Srmacklem ncl_dircookie_lock(dnp); 2273191783Srmacklem cookiep = ncl_getcookie(dnp, uiop->uio_offset, 0); 2274191783Srmacklem if (cookiep) { 2275191783Srmacklem cookie = *cookiep; 2276191783Srmacklem ncl_dircookie_unlock(dnp); 2277191783Srmacklem } else { 2278191783Srmacklem ncl_dircookie_unlock(dnp); 2279191783Srmacklem return (NFSERR_BAD_COOKIE); 2280191783Srmacklem } 2281191783Srmacklem 2282191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) 2283191783Srmacklem (void)ncl_fsinfo(nmp, vp, cred, td); 2284191783Srmacklem 2285191783Srmacklem error = nfsrpc_readdir(vp, uiop, &cookie, cred, td, &nfsva, 2286191783Srmacklem &attrflag, &eof, NULL); 2287191783Srmacklem if (attrflag) 2288191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 2289191783Srmacklem 2290191783Srmacklem if (!error) { 2291191783Srmacklem /* 2292191783Srmacklem * We are now either at the end of the directory or have filled 2293191783Srmacklem * the block. 2294191783Srmacklem */ 2295191783Srmacklem if (eof) 2296191783Srmacklem dnp->n_direofoffset = uiop->uio_offset; 2297191783Srmacklem else { 2298191783Srmacklem if (uiop->uio_resid > 0) 2299191783Srmacklem ncl_printf("EEK! readdirrpc resid > 0\n"); 2300191783Srmacklem ncl_dircookie_lock(dnp); 2301191783Srmacklem cookiep = ncl_getcookie(dnp, uiop->uio_offset, 1); 2302191783Srmacklem *cookiep = cookie; 2303191783Srmacklem ncl_dircookie_unlock(dnp); 2304191783Srmacklem } 2305191783Srmacklem } else if (NFS_ISV4(vp)) { 2306191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2307191783Srmacklem } 2308191783Srmacklem return (error); 2309191783Srmacklem} 2310191783Srmacklem 2311191783Srmacklem/* 2312191783Srmacklem * NFS V3 readdir plus RPC. Used in place of ncl_readdirrpc(). 2313191783Srmacklem */ 2314191783Srmacklemint 2315191783Srmacklemncl_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, 2316191783Srmacklem struct thread *td) 2317191783Srmacklem{ 2318191783Srmacklem struct nfsvattr nfsva; 2319191783Srmacklem nfsuint64 *cookiep, cookie; 2320191783Srmacklem struct nfsnode *dnp = VTONFS(vp); 2321191783Srmacklem struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2322191783Srmacklem int error = 0, attrflag, eof; 2323191783Srmacklem 2324209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2325209120Skib (uiop->uio_offset & (DIRBLKSIZ - 1)) == 0 && 2326209120Skib (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 2327209120Skib ("nfs readdirplusrpc bad uio")); 2328191783Srmacklem 2329191783Srmacklem /* 2330191783Srmacklem * If there is no cookie, assume directory was stale. 2331191783Srmacklem */ 2332191783Srmacklem ncl_dircookie_lock(dnp); 2333191783Srmacklem cookiep = ncl_getcookie(dnp, uiop->uio_offset, 0); 2334191783Srmacklem if (cookiep) { 2335191783Srmacklem cookie = *cookiep; 2336191783Srmacklem ncl_dircookie_unlock(dnp); 2337191783Srmacklem } else { 2338191783Srmacklem ncl_dircookie_unlock(dnp); 2339191783Srmacklem return (NFSERR_BAD_COOKIE); 2340191783Srmacklem } 2341191783Srmacklem 2342191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) 2343191783Srmacklem (void)ncl_fsinfo(nmp, vp, cred, td); 2344191783Srmacklem error = nfsrpc_readdirplus(vp, uiop, &cookie, cred, td, &nfsva, 2345191783Srmacklem &attrflag, &eof, NULL); 2346191783Srmacklem if (attrflag) 2347191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 2348191783Srmacklem 2349191783Srmacklem if (!error) { 2350191783Srmacklem /* 2351191783Srmacklem * We are now either at end of the directory or have filled the 2352191783Srmacklem * the block. 2353191783Srmacklem */ 2354191783Srmacklem if (eof) 2355191783Srmacklem dnp->n_direofoffset = uiop->uio_offset; 2356191783Srmacklem else { 2357191783Srmacklem if (uiop->uio_resid > 0) 2358191783Srmacklem ncl_printf("EEK! readdirplusrpc resid > 0\n"); 2359191783Srmacklem ncl_dircookie_lock(dnp); 2360191783Srmacklem cookiep = ncl_getcookie(dnp, uiop->uio_offset, 1); 2361191783Srmacklem *cookiep = cookie; 2362191783Srmacklem ncl_dircookie_unlock(dnp); 2363191783Srmacklem } 2364191783Srmacklem } else if (NFS_ISV4(vp)) { 2365191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2366191783Srmacklem } 2367191783Srmacklem return (error); 2368191783Srmacklem} 2369191783Srmacklem 2370191783Srmacklem/* 2371191783Srmacklem * Silly rename. To make the NFS filesystem that is stateless look a little 2372191783Srmacklem * more like the "ufs" a remove of an active vnode is translated to a rename 2373191783Srmacklem * to a funny looking filename that is removed by nfs_inactive on the 2374191783Srmacklem * nfsnode. There is the potential for another process on a different client 2375191783Srmacklem * to create the same funny name between the nfs_lookitup() fails and the 2376191783Srmacklem * nfs_rename() completes, but... 2377191783Srmacklem */ 2378191783Srmacklemstatic int 2379191783Srmacklemnfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 2380191783Srmacklem{ 2381191783Srmacklem struct sillyrename *sp; 2382191783Srmacklem struct nfsnode *np; 2383191783Srmacklem int error; 2384191783Srmacklem short pid; 2385191783Srmacklem unsigned int lticks; 2386191783Srmacklem 2387191783Srmacklem cache_purge(dvp); 2388191783Srmacklem np = VTONFS(vp); 2389209120Skib KASSERT(vp->v_type != VDIR, ("nfs: sillyrename dir")); 2390191783Srmacklem MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 2391191783Srmacklem M_NEWNFSREQ, M_WAITOK); 2392191783Srmacklem sp->s_cred = crhold(cnp->cn_cred); 2393191783Srmacklem sp->s_dvp = dvp; 2394191783Srmacklem VREF(dvp); 2395191783Srmacklem 2396191783Srmacklem /* 2397191783Srmacklem * Fudge together a funny name. 2398191783Srmacklem * Changing the format of the funny name to accomodate more 2399191783Srmacklem * sillynames per directory. 2400191783Srmacklem * The name is now changed to .nfs.<ticks>.<pid>.4, where ticks is 2401191783Srmacklem * CPU ticks since boot. 2402191783Srmacklem */ 2403191783Srmacklem pid = cnp->cn_thread->td_proc->p_pid; 2404191783Srmacklem lticks = (unsigned int)ticks; 2405191783Srmacklem for ( ; ; ) { 2406191783Srmacklem sp->s_namlen = sprintf(sp->s_name, 2407191783Srmacklem ".nfs.%08x.%04x4.4", lticks, 2408191783Srmacklem pid); 2409191783Srmacklem if (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 2410191783Srmacklem cnp->cn_thread, NULL)) 2411191783Srmacklem break; 2412191783Srmacklem lticks++; 2413191783Srmacklem } 2414191783Srmacklem error = nfs_renameit(dvp, vp, cnp, sp); 2415191783Srmacklem if (error) 2416191783Srmacklem goto bad; 2417191783Srmacklem error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 2418191783Srmacklem cnp->cn_thread, &np); 2419191783Srmacklem np->n_sillyrename = sp; 2420191783Srmacklem return (0); 2421191783Srmacklembad: 2422191783Srmacklem vrele(sp->s_dvp); 2423191783Srmacklem crfree(sp->s_cred); 2424191783Srmacklem free((caddr_t)sp, M_NEWNFSREQ); 2425191783Srmacklem return (error); 2426191783Srmacklem} 2427191783Srmacklem 2428191783Srmacklem/* 2429191783Srmacklem * Look up a file name and optionally either update the file handle or 2430191783Srmacklem * allocate an nfsnode, depending on the value of npp. 2431191783Srmacklem * npp == NULL --> just do the lookup 2432191783Srmacklem * *npp == NULL --> allocate a new nfsnode and make sure attributes are 2433191783Srmacklem * handled too 2434191783Srmacklem * *npp != NULL --> update the file handle in the vnode 2435191783Srmacklem */ 2436191783Srmacklemstatic int 2437191783Srmacklemnfs_lookitup(struct vnode *dvp, char *name, int len, struct ucred *cred, 2438191783Srmacklem struct thread *td, struct nfsnode **npp) 2439191783Srmacklem{ 2440191783Srmacklem struct vnode *newvp = NULL, *vp; 2441191783Srmacklem struct nfsnode *np, *dnp = VTONFS(dvp); 2442191783Srmacklem struct nfsfh *nfhp, *onfhp; 2443191783Srmacklem struct nfsvattr nfsva, dnfsva; 2444191783Srmacklem struct componentname cn; 2445191783Srmacklem int error = 0, attrflag, dattrflag; 2446191783Srmacklem u_int hash; 2447191783Srmacklem 2448191783Srmacklem error = nfsrpc_lookup(dvp, name, len, cred, td, &dnfsva, &nfsva, 2449191783Srmacklem &nfhp, &attrflag, &dattrflag, NULL); 2450191783Srmacklem if (dattrflag) 2451191783Srmacklem (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2452191783Srmacklem if (npp && !error) { 2453191783Srmacklem if (*npp != NULL) { 2454191783Srmacklem np = *npp; 2455191783Srmacklem vp = NFSTOV(np); 2456191783Srmacklem /* 2457191783Srmacklem * For NFSv4, check to see if it is the same name and 2458191783Srmacklem * replace the name, if it is different. 2459191783Srmacklem */ 2460191783Srmacklem if (np->n_v4 != NULL && nfsva.na_type == VREG && 2461191783Srmacklem (np->n_v4->n4_namelen != len || 2462191783Srmacklem NFSBCMP(name, NFS4NODENAME(np->n_v4), len) || 2463191783Srmacklem dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen || 2464191783Srmacklem NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data, 2465191783Srmacklem dnp->n_fhp->nfh_len))) { 2466191783Srmacklem#ifdef notdef 2467191783Srmacklem{ char nnn[100]; int nnnl; 2468191783Srmacklemnnnl = (len < 100) ? len : 99; 2469191783Srmacklembcopy(name, nnn, nnnl); 2470191783Srmacklemnnn[nnnl] = '\0'; 2471191783Srmacklemprintf("replace=%s\n",nnn); 2472191783Srmacklem} 2473191783Srmacklem#endif 2474191783Srmacklem FREE((caddr_t)np->n_v4, M_NFSV4NODE); 2475191783Srmacklem MALLOC(np->n_v4, struct nfsv4node *, 2476191783Srmacklem sizeof (struct nfsv4node) + 2477191783Srmacklem dnp->n_fhp->nfh_len + len - 1, 2478191783Srmacklem M_NFSV4NODE, M_WAITOK); 2479191783Srmacklem np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len; 2480191783Srmacklem np->n_v4->n4_namelen = len; 2481191783Srmacklem NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data, 2482191783Srmacklem dnp->n_fhp->nfh_len); 2483191783Srmacklem NFSBCOPY(name, NFS4NODENAME(np->n_v4), len); 2484191783Srmacklem } 2485191783Srmacklem hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, 2486191783Srmacklem FNV1_32_INIT); 2487191783Srmacklem onfhp = np->n_fhp; 2488191783Srmacklem /* 2489191783Srmacklem * Rehash node for new file handle. 2490191783Srmacklem */ 2491191783Srmacklem vfs_hash_rehash(vp, hash); 2492191783Srmacklem np->n_fhp = nfhp; 2493191783Srmacklem if (onfhp != NULL) 2494191783Srmacklem FREE((caddr_t)onfhp, M_NFSFH); 2495191783Srmacklem newvp = NFSTOV(np); 2496191783Srmacklem } else if (NFS_CMPFH(dnp, nfhp->nfh_fh, nfhp->nfh_len)) { 2497191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 2498191783Srmacklem VREF(dvp); 2499191783Srmacklem newvp = dvp; 2500191783Srmacklem } else { 2501191783Srmacklem cn.cn_nameptr = name; 2502191783Srmacklem cn.cn_namelen = len; 2503191783Srmacklem error = nfscl_nget(dvp->v_mount, dvp, nfhp, &cn, td, 2504220732Srmacklem &np, NULL, LK_EXCLUSIVE); 2505191783Srmacklem if (error) 2506191783Srmacklem return (error); 2507191783Srmacklem newvp = NFSTOV(np); 2508191783Srmacklem } 2509191783Srmacklem if (!attrflag && *npp == NULL) { 2510220764Srmacklem if (newvp == dvp) 2511220764Srmacklem vrele(newvp); 2512220764Srmacklem else 2513220764Srmacklem vput(newvp); 2514191783Srmacklem return (ENOENT); 2515191783Srmacklem } 2516191783Srmacklem if (attrflag) 2517191783Srmacklem (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 2518191783Srmacklem 0, 1); 2519191783Srmacklem } 2520191783Srmacklem if (npp && *npp == NULL) { 2521191783Srmacklem if (error) { 2522191783Srmacklem if (newvp) { 2523191783Srmacklem if (newvp == dvp) 2524191783Srmacklem vrele(newvp); 2525191783Srmacklem else 2526191783Srmacklem vput(newvp); 2527191783Srmacklem } 2528191783Srmacklem } else 2529191783Srmacklem *npp = np; 2530191783Srmacklem } 2531191783Srmacklem if (error && NFS_ISV4(dvp)) 2532191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2533191783Srmacklem return (error); 2534191783Srmacklem} 2535191783Srmacklem 2536191783Srmacklem/* 2537191783Srmacklem * Nfs Version 3 and 4 commit rpc 2538191783Srmacklem */ 2539191783Srmacklemint 2540191783Srmacklemncl_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred, 2541191783Srmacklem struct thread *td) 2542191783Srmacklem{ 2543191783Srmacklem struct nfsvattr nfsva; 2544191783Srmacklem struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2545191783Srmacklem int error, attrflag; 2546191783Srmacklem u_char verf[NFSX_VERF]; 2547191783Srmacklem 2548191783Srmacklem mtx_lock(&nmp->nm_mtx); 2549191783Srmacklem if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0) { 2550191783Srmacklem mtx_unlock(&nmp->nm_mtx); 2551191783Srmacklem return (0); 2552191783Srmacklem } 2553191783Srmacklem mtx_unlock(&nmp->nm_mtx); 2554191783Srmacklem error = nfsrpc_commit(vp, offset, cnt, cred, td, verf, &nfsva, 2555191783Srmacklem &attrflag, NULL); 2556191783Srmacklem if (!error) { 2557222291Srmacklem mtx_lock(&nmp->nm_mtx); 2558191783Srmacklem if (NFSBCMP((caddr_t)nmp->nm_verf, verf, NFSX_VERF)) { 2559191783Srmacklem NFSBCOPY(verf, (caddr_t)nmp->nm_verf, NFSX_VERF); 2560191783Srmacklem error = NFSERR_STALEWRITEVERF; 2561191783Srmacklem } 2562222291Srmacklem mtx_unlock(&nmp->nm_mtx); 2563191783Srmacklem if (!error && attrflag) 2564191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 2565191783Srmacklem 0, 1); 2566191783Srmacklem } else if (NFS_ISV4(vp)) { 2567191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2568191783Srmacklem } 2569191783Srmacklem return (error); 2570191783Srmacklem} 2571191783Srmacklem 2572191783Srmacklem/* 2573191783Srmacklem * Strategy routine. 2574191783Srmacklem * For async requests when nfsiod(s) are running, queue the request by 2575191783Srmacklem * calling ncl_asyncio(), otherwise just all ncl_doio() to do the 2576191783Srmacklem * request. 2577191783Srmacklem */ 2578191783Srmacklemstatic int 2579191783Srmacklemnfs_strategy(struct vop_strategy_args *ap) 2580191783Srmacklem{ 2581191783Srmacklem struct buf *bp = ap->a_bp; 2582191783Srmacklem struct ucred *cr; 2583191783Srmacklem 2584191783Srmacklem KASSERT(!(bp->b_flags & B_DONE), 2585191783Srmacklem ("nfs_strategy: buffer %p unexpectedly marked B_DONE", bp)); 2586191783Srmacklem BUF_ASSERT_HELD(bp); 2587191783Srmacklem 2588191783Srmacklem if (bp->b_iocmd == BIO_READ) 2589191783Srmacklem cr = bp->b_rcred; 2590191783Srmacklem else 2591191783Srmacklem cr = bp->b_wcred; 2592191783Srmacklem 2593191783Srmacklem /* 2594191783Srmacklem * If the op is asynchronous and an i/o daemon is waiting 2595191783Srmacklem * queue the request, wake it up and wait for completion 2596191783Srmacklem * otherwise just do it ourselves. 2597191783Srmacklem */ 2598191783Srmacklem if ((bp->b_flags & B_ASYNC) == 0 || 2599191783Srmacklem ncl_asyncio(VFSTONFS(ap->a_vp->v_mount), bp, NOCRED, curthread)) 2600207082Srmacklem (void) ncl_doio(ap->a_vp, bp, cr, curthread, 1); 2601191783Srmacklem return (0); 2602191783Srmacklem} 2603191783Srmacklem 2604191783Srmacklem/* 2605191783Srmacklem * fsync vnode op. Just call ncl_flush() with commit == 1. 2606191783Srmacklem */ 2607191783Srmacklem/* ARGSUSED */ 2608191783Srmacklemstatic int 2609191783Srmacklemnfs_fsync(struct vop_fsync_args *ap) 2610191783Srmacklem{ 2611229287Srmacklem 2612229287Srmacklem if (ap->a_vp->v_type != VREG) { 2613229287Srmacklem /* 2614229287Srmacklem * For NFS, metadata is changed synchronously on the server, 2615229287Srmacklem * so there is nothing to flush. Also, ncl_flush() clears 2616229287Srmacklem * the NMODIFIED flag and that shouldn't be done here for 2617229287Srmacklem * directories. 2618229287Srmacklem */ 2619229287Srmacklem return (0); 2620229287Srmacklem } 2621207082Srmacklem return (ncl_flush(ap->a_vp, ap->a_waitfor, NULL, ap->a_td, 1, 0)); 2622191783Srmacklem} 2623191783Srmacklem 2624191783Srmacklem/* 2625191783Srmacklem * Flush all the blocks associated with a vnode. 2626191783Srmacklem * Walk through the buffer pool and push any dirty pages 2627191783Srmacklem * associated with the vnode. 2628207082Srmacklem * If the called_from_renewthread argument is TRUE, it has been called 2629207082Srmacklem * from the NFSv4 renew thread and, as such, cannot block indefinitely 2630207082Srmacklem * waiting for a buffer write to complete. 2631191783Srmacklem */ 2632191783Srmacklemint 2633191783Srmacklemncl_flush(struct vnode *vp, int waitfor, struct ucred *cred, struct thread *td, 2634207082Srmacklem int commit, int called_from_renewthread) 2635191783Srmacklem{ 2636191783Srmacklem struct nfsnode *np = VTONFS(vp); 2637191783Srmacklem struct buf *bp; 2638191783Srmacklem int i; 2639191783Srmacklem struct buf *nbp; 2640191783Srmacklem struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2641191783Srmacklem int error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos; 2642191783Srmacklem int passone = 1, trycnt = 0; 2643191783Srmacklem u_quad_t off, endoff, toff; 2644191783Srmacklem struct ucred* wcred = NULL; 2645191783Srmacklem struct buf **bvec = NULL; 2646191783Srmacklem struct bufobj *bo; 2647191783Srmacklem#ifndef NFS_COMMITBVECSIZ 2648191783Srmacklem#define NFS_COMMITBVECSIZ 20 2649191783Srmacklem#endif 2650191783Srmacklem struct buf *bvec_on_stack[NFS_COMMITBVECSIZ]; 2651191783Srmacklem int bvecsize = 0, bveccount; 2652191783Srmacklem 2653207082Srmacklem if (called_from_renewthread != 0) 2654207082Srmacklem slptimeo = hz; 2655191783Srmacklem if (nmp->nm_flag & NFSMNT_INT) 2656195821Srmacklem slpflag = NFS_PCATCH; 2657191783Srmacklem if (!commit) 2658191783Srmacklem passone = 0; 2659191783Srmacklem bo = &vp->v_bufobj; 2660191783Srmacklem /* 2661191783Srmacklem * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the 2662191783Srmacklem * server, but has not been committed to stable storage on the server 2663191783Srmacklem * yet. On the first pass, the byte range is worked out and the commit 2664191783Srmacklem * rpc is done. On the second pass, ncl_writebp() is called to do the 2665191783Srmacklem * job. 2666191783Srmacklem */ 2667191783Srmacklemagain: 2668191783Srmacklem off = (u_quad_t)-1; 2669191783Srmacklem endoff = 0; 2670191783Srmacklem bvecpos = 0; 2671191783Srmacklem if (NFS_ISV34(vp) && commit) { 2672191783Srmacklem if (bvec != NULL && bvec != bvec_on_stack) 2673191783Srmacklem free(bvec, M_TEMP); 2674191783Srmacklem /* 2675191783Srmacklem * Count up how many buffers waiting for a commit. 2676191783Srmacklem */ 2677191783Srmacklem bveccount = 0; 2678191783Srmacklem BO_LOCK(bo); 2679191783Srmacklem TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 2680191783Srmacklem if (!BUF_ISLOCKED(bp) && 2681191783Srmacklem (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 2682191783Srmacklem == (B_DELWRI | B_NEEDCOMMIT)) 2683191783Srmacklem bveccount++; 2684191783Srmacklem } 2685191783Srmacklem /* 2686191783Srmacklem * Allocate space to remember the list of bufs to commit. It is 2687191783Srmacklem * important to use M_NOWAIT here to avoid a race with nfs_write. 2688191783Srmacklem * If we can't get memory (for whatever reason), we will end up 2689191783Srmacklem * committing the buffers one-by-one in the loop below. 2690191783Srmacklem */ 2691191783Srmacklem if (bveccount > NFS_COMMITBVECSIZ) { 2692191783Srmacklem /* 2693191783Srmacklem * Release the vnode interlock to avoid a lock 2694191783Srmacklem * order reversal. 2695191783Srmacklem */ 2696191783Srmacklem BO_UNLOCK(bo); 2697191783Srmacklem bvec = (struct buf **) 2698191783Srmacklem malloc(bveccount * sizeof(struct buf *), 2699191783Srmacklem M_TEMP, M_NOWAIT); 2700191783Srmacklem BO_LOCK(bo); 2701191783Srmacklem if (bvec == NULL) { 2702191783Srmacklem bvec = bvec_on_stack; 2703191783Srmacklem bvecsize = NFS_COMMITBVECSIZ; 2704191783Srmacklem } else 2705191783Srmacklem bvecsize = bveccount; 2706191783Srmacklem } else { 2707191783Srmacklem bvec = bvec_on_stack; 2708191783Srmacklem bvecsize = NFS_COMMITBVECSIZ; 2709191783Srmacklem } 2710191783Srmacklem TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 2711191783Srmacklem if (bvecpos >= bvecsize) 2712191783Srmacklem break; 2713191783Srmacklem if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { 2714191783Srmacklem nbp = TAILQ_NEXT(bp, b_bobufs); 2715191783Srmacklem continue; 2716191783Srmacklem } 2717191783Srmacklem if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) != 2718191783Srmacklem (B_DELWRI | B_NEEDCOMMIT)) { 2719191783Srmacklem BUF_UNLOCK(bp); 2720191783Srmacklem nbp = TAILQ_NEXT(bp, b_bobufs); 2721191783Srmacklem continue; 2722191783Srmacklem } 2723191783Srmacklem BO_UNLOCK(bo); 2724191783Srmacklem bremfree(bp); 2725191783Srmacklem /* 2726191783Srmacklem * Work out if all buffers are using the same cred 2727191783Srmacklem * so we can deal with them all with one commit. 2728191783Srmacklem * 2729191783Srmacklem * NOTE: we are not clearing B_DONE here, so we have 2730191783Srmacklem * to do it later on in this routine if we intend to 2731191783Srmacklem * initiate I/O on the bp. 2732191783Srmacklem * 2733191783Srmacklem * Note: to avoid loopback deadlocks, we do not 2734191783Srmacklem * assign b_runningbufspace. 2735191783Srmacklem */ 2736191783Srmacklem if (wcred == NULL) 2737191783Srmacklem wcred = bp->b_wcred; 2738191783Srmacklem else if (wcred != bp->b_wcred) 2739191783Srmacklem wcred = NOCRED; 2740191783Srmacklem vfs_busy_pages(bp, 1); 2741191783Srmacklem 2742191783Srmacklem BO_LOCK(bo); 2743191783Srmacklem /* 2744191783Srmacklem * bp is protected by being locked, but nbp is not 2745191783Srmacklem * and vfs_busy_pages() may sleep. We have to 2746191783Srmacklem * recalculate nbp. 2747191783Srmacklem */ 2748191783Srmacklem nbp = TAILQ_NEXT(bp, b_bobufs); 2749191783Srmacklem 2750191783Srmacklem /* 2751191783Srmacklem * A list of these buffers is kept so that the 2752191783Srmacklem * second loop knows which buffers have actually 2753191783Srmacklem * been committed. This is necessary, since there 2754191783Srmacklem * may be a race between the commit rpc and new 2755191783Srmacklem * uncommitted writes on the file. 2756191783Srmacklem */ 2757191783Srmacklem bvec[bvecpos++] = bp; 2758191783Srmacklem toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + 2759191783Srmacklem bp->b_dirtyoff; 2760191783Srmacklem if (toff < off) 2761191783Srmacklem off = toff; 2762191783Srmacklem toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff); 2763191783Srmacklem if (toff > endoff) 2764191783Srmacklem endoff = toff; 2765191783Srmacklem } 2766191783Srmacklem BO_UNLOCK(bo); 2767191783Srmacklem } 2768191783Srmacklem if (bvecpos > 0) { 2769191783Srmacklem /* 2770191783Srmacklem * Commit data on the server, as required. 2771191783Srmacklem * If all bufs are using the same wcred, then use that with 2772191783Srmacklem * one call for all of them, otherwise commit each one 2773191783Srmacklem * separately. 2774191783Srmacklem */ 2775191783Srmacklem if (wcred != NOCRED) 2776191783Srmacklem retv = ncl_commit(vp, off, (int)(endoff - off), 2777191783Srmacklem wcred, td); 2778191783Srmacklem else { 2779191783Srmacklem retv = 0; 2780191783Srmacklem for (i = 0; i < bvecpos; i++) { 2781191783Srmacklem off_t off, size; 2782191783Srmacklem bp = bvec[i]; 2783191783Srmacklem off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + 2784191783Srmacklem bp->b_dirtyoff; 2785191783Srmacklem size = (u_quad_t)(bp->b_dirtyend 2786191783Srmacklem - bp->b_dirtyoff); 2787191783Srmacklem retv = ncl_commit(vp, off, (int)size, 2788191783Srmacklem bp->b_wcred, td); 2789191783Srmacklem if (retv) break; 2790191783Srmacklem } 2791191783Srmacklem } 2792191783Srmacklem 2793191783Srmacklem if (retv == NFSERR_STALEWRITEVERF) 2794191783Srmacklem ncl_clearcommit(vp->v_mount); 2795191783Srmacklem 2796191783Srmacklem /* 2797191783Srmacklem * Now, either mark the blocks I/O done or mark the 2798191783Srmacklem * blocks dirty, depending on whether the commit 2799191783Srmacklem * succeeded. 2800191783Srmacklem */ 2801191783Srmacklem for (i = 0; i < bvecpos; i++) { 2802191783Srmacklem bp = bvec[i]; 2803191783Srmacklem bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 2804191783Srmacklem if (retv) { 2805191783Srmacklem /* 2806191783Srmacklem * Error, leave B_DELWRI intact 2807191783Srmacklem */ 2808191783Srmacklem vfs_unbusy_pages(bp); 2809191783Srmacklem brelse(bp); 2810191783Srmacklem } else { 2811191783Srmacklem /* 2812191783Srmacklem * Success, remove B_DELWRI ( bundirty() ). 2813191783Srmacklem * 2814191783Srmacklem * b_dirtyoff/b_dirtyend seem to be NFS 2815191783Srmacklem * specific. We should probably move that 2816191783Srmacklem * into bundirty(). XXX 2817191783Srmacklem */ 2818191783Srmacklem bufobj_wref(bo); 2819191783Srmacklem bp->b_flags |= B_ASYNC; 2820191783Srmacklem bundirty(bp); 2821191783Srmacklem bp->b_flags &= ~B_DONE; 2822191783Srmacklem bp->b_ioflags &= ~BIO_ERROR; 2823191783Srmacklem bp->b_dirtyoff = bp->b_dirtyend = 0; 2824191783Srmacklem bufdone(bp); 2825191783Srmacklem } 2826191783Srmacklem } 2827191783Srmacklem } 2828191783Srmacklem 2829191783Srmacklem /* 2830191783Srmacklem * Start/do any write(s) that are required. 2831191783Srmacklem */ 2832191783Srmacklemloop: 2833191783Srmacklem BO_LOCK(bo); 2834191783Srmacklem TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 2835191783Srmacklem if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { 2836191783Srmacklem if (waitfor != MNT_WAIT || passone) 2837191783Srmacklem continue; 2838191783Srmacklem 2839191783Srmacklem error = BUF_TIMELOCK(bp, 2840191783Srmacklem LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, 2841191783Srmacklem BO_MTX(bo), "nfsfsync", slpflag, slptimeo); 2842191783Srmacklem if (error == 0) { 2843191783Srmacklem BUF_UNLOCK(bp); 2844191783Srmacklem goto loop; 2845191783Srmacklem } 2846191783Srmacklem if (error == ENOLCK) { 2847191783Srmacklem error = 0; 2848191783Srmacklem goto loop; 2849191783Srmacklem } 2850207082Srmacklem if (called_from_renewthread != 0) { 2851207082Srmacklem /* 2852207082Srmacklem * Return EIO so the flush will be retried 2853207082Srmacklem * later. 2854207082Srmacklem */ 2855207082Srmacklem error = EIO; 2856207082Srmacklem goto done; 2857207082Srmacklem } 2858191783Srmacklem if (newnfs_sigintr(nmp, td)) { 2859191783Srmacklem error = EINTR; 2860191783Srmacklem goto done; 2861191783Srmacklem } 2862195821Srmacklem if (slpflag & PCATCH) { 2863191783Srmacklem slpflag = 0; 2864191783Srmacklem slptimeo = 2 * hz; 2865191783Srmacklem } 2866191783Srmacklem goto loop; 2867191783Srmacklem } 2868191783Srmacklem if ((bp->b_flags & B_DELWRI) == 0) 2869191783Srmacklem panic("nfs_fsync: not dirty"); 2870191783Srmacklem if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) { 2871191783Srmacklem BUF_UNLOCK(bp); 2872191783Srmacklem continue; 2873191783Srmacklem } 2874191783Srmacklem BO_UNLOCK(bo); 2875191783Srmacklem bremfree(bp); 2876191783Srmacklem if (passone || !commit) 2877191783Srmacklem bp->b_flags |= B_ASYNC; 2878191783Srmacklem else 2879191783Srmacklem bp->b_flags |= B_ASYNC; 2880191783Srmacklem bwrite(bp); 2881191783Srmacklem if (newnfs_sigintr(nmp, td)) { 2882191783Srmacklem error = EINTR; 2883191783Srmacklem goto done; 2884191783Srmacklem } 2885191783Srmacklem goto loop; 2886191783Srmacklem } 2887191783Srmacklem if (passone) { 2888191783Srmacklem passone = 0; 2889191783Srmacklem BO_UNLOCK(bo); 2890191783Srmacklem goto again; 2891191783Srmacklem } 2892191783Srmacklem if (waitfor == MNT_WAIT) { 2893191783Srmacklem while (bo->bo_numoutput) { 2894191783Srmacklem error = bufobj_wwait(bo, slpflag, slptimeo); 2895191783Srmacklem if (error) { 2896191783Srmacklem BO_UNLOCK(bo); 2897207082Srmacklem if (called_from_renewthread != 0) { 2898207082Srmacklem /* 2899207082Srmacklem * Return EIO so that the flush will be 2900207082Srmacklem * retried later. 2901207082Srmacklem */ 2902207082Srmacklem error = EIO; 2903207082Srmacklem goto done; 2904207082Srmacklem } 2905191783Srmacklem error = newnfs_sigintr(nmp, td); 2906191783Srmacklem if (error) 2907191783Srmacklem goto done; 2908195821Srmacklem if (slpflag & PCATCH) { 2909191783Srmacklem slpflag = 0; 2910191783Srmacklem slptimeo = 2 * hz; 2911191783Srmacklem } 2912191783Srmacklem BO_LOCK(bo); 2913191783Srmacklem } 2914191783Srmacklem } 2915191783Srmacklem if (bo->bo_dirty.bv_cnt != 0 && commit) { 2916191783Srmacklem BO_UNLOCK(bo); 2917191783Srmacklem goto loop; 2918191783Srmacklem } 2919191783Srmacklem /* 2920191783Srmacklem * Wait for all the async IO requests to drain 2921191783Srmacklem */ 2922191783Srmacklem BO_UNLOCK(bo); 2923191783Srmacklem mtx_lock(&np->n_mtx); 2924191783Srmacklem while (np->n_directio_asyncwr > 0) { 2925191783Srmacklem np->n_flag |= NFSYNCWAIT; 2926201029Srmacklem error = newnfs_msleep(td, &np->n_directio_asyncwr, 2927201029Srmacklem &np->n_mtx, slpflag | (PRIBIO + 1), 2928201029Srmacklem "nfsfsync", 0); 2929191783Srmacklem if (error) { 2930191783Srmacklem if (newnfs_sigintr(nmp, td)) { 2931191783Srmacklem mtx_unlock(&np->n_mtx); 2932191783Srmacklem error = EINTR; 2933191783Srmacklem goto done; 2934191783Srmacklem } 2935191783Srmacklem } 2936191783Srmacklem } 2937191783Srmacklem mtx_unlock(&np->n_mtx); 2938191783Srmacklem } else 2939191783Srmacklem BO_UNLOCK(bo); 2940191783Srmacklem mtx_lock(&np->n_mtx); 2941191783Srmacklem if (np->n_flag & NWRITEERR) { 2942191783Srmacklem error = np->n_error; 2943191783Srmacklem np->n_flag &= ~NWRITEERR; 2944191783Srmacklem } 2945191783Srmacklem if (commit && bo->bo_dirty.bv_cnt == 0 && 2946191783Srmacklem bo->bo_numoutput == 0 && np->n_directio_asyncwr == 0) 2947191783Srmacklem np->n_flag &= ~NMODIFIED; 2948191783Srmacklem mtx_unlock(&np->n_mtx); 2949191783Srmacklemdone: 2950191783Srmacklem if (bvec != NULL && bvec != bvec_on_stack) 2951191783Srmacklem free(bvec, M_TEMP); 2952191783Srmacklem if (error == 0 && commit != 0 && waitfor == MNT_WAIT && 2953191783Srmacklem (bo->bo_dirty.bv_cnt != 0 || bo->bo_numoutput != 0 || 2954191783Srmacklem np->n_directio_asyncwr != 0) && trycnt++ < 5) { 2955191783Srmacklem /* try, try again... */ 2956191783Srmacklem passone = 1; 2957191783Srmacklem wcred = NULL; 2958191783Srmacklem bvec = NULL; 2959191783Srmacklem bvecsize = 0; 2960191783Srmacklemprintf("try%d\n", trycnt); 2961191783Srmacklem goto again; 2962191783Srmacklem } 2963191783Srmacklem return (error); 2964191783Srmacklem} 2965191783Srmacklem 2966191783Srmacklem/* 2967191783Srmacklem * NFS advisory byte-level locks. 2968191783Srmacklem */ 2969191783Srmacklemstatic int 2970191783Srmacklemnfs_advlock(struct vop_advlock_args *ap) 2971191783Srmacklem{ 2972191783Srmacklem struct vnode *vp = ap->a_vp; 2973191783Srmacklem struct ucred *cred; 2974191783Srmacklem struct nfsnode *np = VTONFS(ap->a_vp); 2975191783Srmacklem struct proc *p = (struct proc *)ap->a_id; 2976191783Srmacklem struct thread *td = curthread; /* XXX */ 2977191783Srmacklem struct vattr va; 2978193837Srmacklem int ret, error = EOPNOTSUPP; 2979191783Srmacklem u_quad_t size; 2980191783Srmacklem 2981222722Srmacklem if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) { 2982229258Srmacklem if (vp->v_type != VREG) 2983229258Srmacklem return (EINVAL); 2984222722Srmacklem if ((ap->a_flags & F_POSIX) != 0) 2985222722Srmacklem cred = p->p_ucred; 2986222722Srmacklem else 2987222722Srmacklem cred = td->td_ucred; 2988224081Szack NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2989193837Srmacklem if (vp->v_iflag & VI_DOOMED) { 2990224082Szack NFSVOPUNLOCK(vp, 0); 2991193837Srmacklem return (EBADF); 2992193837Srmacklem } 2993191783Srmacklem 2994191783Srmacklem /* 2995191783Srmacklem * If this is unlocking a write locked region, flush and 2996191783Srmacklem * commit them before unlocking. This is required by 2997191783Srmacklem * RFC3530 Sec. 9.3.2. 2998191783Srmacklem */ 2999191783Srmacklem if (ap->a_op == F_UNLCK && 3000222719Srmacklem nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id, 3001222719Srmacklem ap->a_flags)) 3002207082Srmacklem (void) ncl_flush(vp, MNT_WAIT, cred, td, 1, 0); 3003191783Srmacklem 3004191783Srmacklem /* 3005191783Srmacklem * Loop around doing the lock op, while a blocking lock 3006191783Srmacklem * must wait for the lock op to succeed. 3007191783Srmacklem */ 3008191783Srmacklem do { 3009191783Srmacklem ret = nfsrpc_advlock(vp, np->n_size, ap->a_op, 3010222719Srmacklem ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags); 3011191783Srmacklem if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && 3012191783Srmacklem ap->a_op == F_SETLK) { 3013224082Szack NFSVOPUNLOCK(vp, 0); 3014207170Srmacklem error = nfs_catnap(PZERO | PCATCH, ret, 3015207170Srmacklem "ncladvl"); 3016191783Srmacklem if (error) 3017191783Srmacklem return (EINTR); 3018224081Szack NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3019193837Srmacklem if (vp->v_iflag & VI_DOOMED) { 3020224082Szack NFSVOPUNLOCK(vp, 0); 3021193837Srmacklem return (EBADF); 3022193837Srmacklem } 3023191783Srmacklem } 3024191783Srmacklem } while (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && 3025191783Srmacklem ap->a_op == F_SETLK); 3026191783Srmacklem if (ret == NFSERR_DENIED) { 3027224082Szack NFSVOPUNLOCK(vp, 0); 3028191783Srmacklem return (EAGAIN); 3029191783Srmacklem } else if (ret == EINVAL || ret == EBADF || ret == EINTR) { 3030224082Szack NFSVOPUNLOCK(vp, 0); 3031191783Srmacklem return (ret); 3032191783Srmacklem } else if (ret != 0) { 3033224082Szack NFSVOPUNLOCK(vp, 0); 3034191783Srmacklem return (EACCES); 3035191783Srmacklem } 3036191783Srmacklem 3037191783Srmacklem /* 3038191783Srmacklem * Now, if we just got a lock, invalidate data in the buffer 3039191783Srmacklem * cache, as required, so that the coherency conforms with 3040191783Srmacklem * RFC3530 Sec. 9.3.2. 3041191783Srmacklem */ 3042191783Srmacklem if (ap->a_op == F_SETLK) { 3043191783Srmacklem if ((np->n_flag & NMODIFIED) == 0) { 3044191783Srmacklem np->n_attrstamp = 0; 3045223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 3046191783Srmacklem ret = VOP_GETATTR(vp, &va, cred); 3047191783Srmacklem } 3048191783Srmacklem if ((np->n_flag & NMODIFIED) || ret || 3049191783Srmacklem np->n_change != va.va_filerev) { 3050191783Srmacklem (void) ncl_vinvalbuf(vp, V_SAVE, td, 1); 3051191783Srmacklem np->n_attrstamp = 0; 3052223280Srmacklem KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 3053191783Srmacklem ret = VOP_GETATTR(vp, &va, cred); 3054191783Srmacklem if (!ret) { 3055191783Srmacklem np->n_mtime = va.va_mtime; 3056191783Srmacklem np->n_change = va.va_filerev; 3057191783Srmacklem } 3058191783Srmacklem } 3059260170Srmacklem /* Mark that a file lock has been acquired. */ 3060260170Srmacklem mtx_lock(&np->n_mtx); 3061260170Srmacklem np->n_flag |= NHASBEENLOCKED; 3062260170Srmacklem mtx_unlock(&np->n_mtx); 3063191783Srmacklem } 3064224082Szack NFSVOPUNLOCK(vp, 0); 3065191783Srmacklem return (0); 3066191783Srmacklem } else if (!NFS_ISV4(vp)) { 3067224081Szack error = NFSVOPLOCK(vp, LK_SHARED); 3068191783Srmacklem if (error) 3069191783Srmacklem return (error); 3070191783Srmacklem if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { 3071191783Srmacklem size = VTONFS(vp)->n_size; 3072224082Szack NFSVOPUNLOCK(vp, 0); 3073191783Srmacklem error = lf_advlock(ap, &(vp->v_lockf), size); 3074191783Srmacklem } else { 3075214048Srmacklem if (nfs_advlock_p != NULL) 3076214048Srmacklem error = nfs_advlock_p(ap); 3077212362Srmacklem else { 3078224082Szack NFSVOPUNLOCK(vp, 0); 3079191783Srmacklem error = ENOLCK; 3080212362Srmacklem } 3081191783Srmacklem } 3082260170Srmacklem if (error == 0 && ap->a_op == F_SETLK) { 3083260170Srmacklem /* Mark that a file lock has been acquired. */ 3084260170Srmacklem mtx_lock(&np->n_mtx); 3085260170Srmacklem np->n_flag |= NHASBEENLOCKED; 3086260170Srmacklem mtx_unlock(&np->n_mtx); 3087260170Srmacklem } 3088191783Srmacklem } 3089191783Srmacklem return (error); 3090191783Srmacklem} 3091191783Srmacklem 3092191783Srmacklem/* 3093191783Srmacklem * NFS advisory byte-level locks. 3094191783Srmacklem */ 3095191783Srmacklemstatic int 3096191783Srmacklemnfs_advlockasync(struct vop_advlockasync_args *ap) 3097191783Srmacklem{ 3098191783Srmacklem struct vnode *vp = ap->a_vp; 3099191783Srmacklem u_quad_t size; 3100191783Srmacklem int error; 3101191783Srmacklem 3102191783Srmacklem if (NFS_ISV4(vp)) 3103191783Srmacklem return (EOPNOTSUPP); 3104224081Szack error = NFSVOPLOCK(vp, LK_SHARED); 3105191783Srmacklem if (error) 3106191783Srmacklem return (error); 3107191783Srmacklem if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { 3108191783Srmacklem size = VTONFS(vp)->n_size; 3109224082Szack NFSVOPUNLOCK(vp, 0); 3110191783Srmacklem error = lf_advlockasync(ap, &(vp->v_lockf), size); 3111191783Srmacklem } else { 3112224082Szack NFSVOPUNLOCK(vp, 0); 3113191783Srmacklem error = EOPNOTSUPP; 3114191783Srmacklem } 3115191783Srmacklem return (error); 3116191783Srmacklem} 3117191783Srmacklem 3118191783Srmacklem/* 3119191783Srmacklem * Print out the contents of an nfsnode. 3120191783Srmacklem */ 3121191783Srmacklemstatic int 3122191783Srmacklemnfs_print(struct vop_print_args *ap) 3123191783Srmacklem{ 3124191783Srmacklem struct vnode *vp = ap->a_vp; 3125191783Srmacklem struct nfsnode *np = VTONFS(vp); 3126191783Srmacklem 3127191783Srmacklem ncl_printf("\tfileid %ld fsid 0x%x", 3128191783Srmacklem np->n_vattr.na_fileid, np->n_vattr.na_fsid); 3129191783Srmacklem if (vp->v_type == VFIFO) 3130191783Srmacklem fifo_printinfo(vp); 3131191783Srmacklem printf("\n"); 3132191783Srmacklem return (0); 3133191783Srmacklem} 3134191783Srmacklem 3135191783Srmacklem/* 3136191783Srmacklem * This is the "real" nfs::bwrite(struct buf*). 3137191783Srmacklem * We set B_CACHE if this is a VMIO buffer. 3138191783Srmacklem */ 3139191783Srmacklemint 3140191783Srmacklemncl_writebp(struct buf *bp, int force __unused, struct thread *td) 3141191783Srmacklem{ 3142191783Srmacklem int s; 3143191783Srmacklem int oldflags = bp->b_flags; 3144191783Srmacklem#if 0 3145191783Srmacklem int retv = 1; 3146191783Srmacklem off_t off; 3147191783Srmacklem#endif 3148191783Srmacklem 3149191783Srmacklem BUF_ASSERT_HELD(bp); 3150191783Srmacklem 3151191783Srmacklem if (bp->b_flags & B_INVAL) { 3152191783Srmacklem brelse(bp); 3153191783Srmacklem return(0); 3154191783Srmacklem } 3155191783Srmacklem 3156191783Srmacklem bp->b_flags |= B_CACHE; 3157191783Srmacklem 3158191783Srmacklem /* 3159191783Srmacklem * Undirty the bp. We will redirty it later if the I/O fails. 3160191783Srmacklem */ 3161191783Srmacklem 3162191783Srmacklem s = splbio(); 3163191783Srmacklem bundirty(bp); 3164191783Srmacklem bp->b_flags &= ~B_DONE; 3165191783Srmacklem bp->b_ioflags &= ~BIO_ERROR; 3166191783Srmacklem bp->b_iocmd = BIO_WRITE; 3167191783Srmacklem 3168191783Srmacklem bufobj_wref(bp->b_bufobj); 3169191783Srmacklem curthread->td_ru.ru_oublock++; 3170191783Srmacklem splx(s); 3171191783Srmacklem 3172191783Srmacklem /* 3173191783Srmacklem * Note: to avoid loopback deadlocks, we do not 3174191783Srmacklem * assign b_runningbufspace. 3175191783Srmacklem */ 3176191783Srmacklem vfs_busy_pages(bp, 1); 3177191783Srmacklem 3178191783Srmacklem BUF_KERNPROC(bp); 3179191783Srmacklem bp->b_iooffset = dbtob(bp->b_blkno); 3180191783Srmacklem bstrategy(bp); 3181191783Srmacklem 3182191783Srmacklem if( (oldflags & B_ASYNC) == 0) { 3183191783Srmacklem int rtval = bufwait(bp); 3184191783Srmacklem 3185191783Srmacklem if (oldflags & B_DELWRI) { 3186191783Srmacklem s = splbio(); 3187191783Srmacklem reassignbuf(bp); 3188191783Srmacklem splx(s); 3189191783Srmacklem } 3190191783Srmacklem brelse(bp); 3191191783Srmacklem return (rtval); 3192191783Srmacklem } 3193191783Srmacklem 3194191783Srmacklem return (0); 3195191783Srmacklem} 3196191783Srmacklem 3197191783Srmacklem/* 3198191783Srmacklem * nfs special file access vnode op. 3199191783Srmacklem * Essentially just get vattr and then imitate iaccess() since the device is 3200191783Srmacklem * local to the client. 3201191783Srmacklem */ 3202191783Srmacklemstatic int 3203191783Srmacklemnfsspec_access(struct vop_access_args *ap) 3204191783Srmacklem{ 3205191783Srmacklem struct vattr *vap; 3206191783Srmacklem struct ucred *cred = ap->a_cred; 3207191783Srmacklem struct vnode *vp = ap->a_vp; 3208191783Srmacklem accmode_t accmode = ap->a_accmode; 3209191783Srmacklem struct vattr vattr; 3210191783Srmacklem int error; 3211191783Srmacklem 3212191783Srmacklem /* 3213191783Srmacklem * Disallow write attempts on filesystems mounted read-only; 3214191783Srmacklem * unless the file is a socket, fifo, or a block or character 3215191783Srmacklem * device resident on the filesystem. 3216191783Srmacklem */ 3217191783Srmacklem if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 3218191783Srmacklem switch (vp->v_type) { 3219191783Srmacklem case VREG: 3220191783Srmacklem case VDIR: 3221191783Srmacklem case VLNK: 3222191783Srmacklem return (EROFS); 3223191783Srmacklem default: 3224191783Srmacklem break; 3225191783Srmacklem } 3226191783Srmacklem } 3227191783Srmacklem vap = &vattr; 3228191783Srmacklem error = VOP_GETATTR(vp, vap, cred); 3229191783Srmacklem if (error) 3230191783Srmacklem goto out; 3231191783Srmacklem error = vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, 3232191783Srmacklem accmode, cred, NULL); 3233191783Srmacklemout: 3234191783Srmacklem return error; 3235191783Srmacklem} 3236191783Srmacklem 3237191783Srmacklem/* 3238191783Srmacklem * Read wrapper for fifos. 3239191783Srmacklem */ 3240191783Srmacklemstatic int 3241191783Srmacklemnfsfifo_read(struct vop_read_args *ap) 3242191783Srmacklem{ 3243191783Srmacklem struct nfsnode *np = VTONFS(ap->a_vp); 3244191783Srmacklem int error; 3245191783Srmacklem 3246191783Srmacklem /* 3247191783Srmacklem * Set access flag. 3248191783Srmacklem */ 3249191783Srmacklem mtx_lock(&np->n_mtx); 3250191783Srmacklem np->n_flag |= NACC; 3251247502Sjhb vfs_timestamp(&np->n_atim); 3252191783Srmacklem mtx_unlock(&np->n_mtx); 3253191783Srmacklem error = fifo_specops.vop_read(ap); 3254191783Srmacklem return error; 3255191783Srmacklem} 3256191783Srmacklem 3257191783Srmacklem/* 3258191783Srmacklem * Write wrapper for fifos. 3259191783Srmacklem */ 3260191783Srmacklemstatic int 3261191783Srmacklemnfsfifo_write(struct vop_write_args *ap) 3262191783Srmacklem{ 3263191783Srmacklem struct nfsnode *np = VTONFS(ap->a_vp); 3264191783Srmacklem 3265191783Srmacklem /* 3266191783Srmacklem * Set update flag. 3267191783Srmacklem */ 3268191783Srmacklem mtx_lock(&np->n_mtx); 3269191783Srmacklem np->n_flag |= NUPD; 3270247502Sjhb vfs_timestamp(&np->n_mtim); 3271191783Srmacklem mtx_unlock(&np->n_mtx); 3272191783Srmacklem return(fifo_specops.vop_write(ap)); 3273191783Srmacklem} 3274191783Srmacklem 3275191783Srmacklem/* 3276191783Srmacklem * Close wrapper for fifos. 3277191783Srmacklem * 3278191783Srmacklem * Update the times on the nfsnode then do fifo close. 3279191783Srmacklem */ 3280191783Srmacklemstatic int 3281191783Srmacklemnfsfifo_close(struct vop_close_args *ap) 3282191783Srmacklem{ 3283191783Srmacklem struct vnode *vp = ap->a_vp; 3284191783Srmacklem struct nfsnode *np = VTONFS(vp); 3285191783Srmacklem struct vattr vattr; 3286191783Srmacklem struct timespec ts; 3287191783Srmacklem 3288191783Srmacklem mtx_lock(&np->n_mtx); 3289191783Srmacklem if (np->n_flag & (NACC | NUPD)) { 3290247502Sjhb vfs_timestamp(&ts); 3291191783Srmacklem if (np->n_flag & NACC) 3292191783Srmacklem np->n_atim = ts; 3293191783Srmacklem if (np->n_flag & NUPD) 3294191783Srmacklem np->n_mtim = ts; 3295191783Srmacklem np->n_flag |= NCHG; 3296191783Srmacklem if (vrefcnt(vp) == 1 && 3297191783Srmacklem (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 3298191783Srmacklem VATTR_NULL(&vattr); 3299191783Srmacklem if (np->n_flag & NACC) 3300191783Srmacklem vattr.va_atime = np->n_atim; 3301191783Srmacklem if (np->n_flag & NUPD) 3302191783Srmacklem vattr.va_mtime = np->n_mtim; 3303191783Srmacklem mtx_unlock(&np->n_mtx); 3304191783Srmacklem (void)VOP_SETATTR(vp, &vattr, ap->a_cred); 3305191783Srmacklem goto out; 3306191783Srmacklem } 3307191783Srmacklem } 3308191783Srmacklem mtx_unlock(&np->n_mtx); 3309191783Srmacklemout: 3310191783Srmacklem return (fifo_specops.vop_close(ap)); 3311191783Srmacklem} 3312191783Srmacklem 3313191783Srmacklem/* 3314191783Srmacklem * Just call ncl_writebp() with the force argument set to 1. 3315191783Srmacklem * 3316191783Srmacklem * NOTE: B_DONE may or may not be set in a_bp on call. 3317191783Srmacklem */ 3318191783Srmacklemstatic int 3319191783Srmacklemnfs_bwrite(struct buf *bp) 3320191783Srmacklem{ 3321191783Srmacklem 3322191783Srmacklem return (ncl_writebp(bp, 1, curthread)); 3323191783Srmacklem} 3324191783Srmacklem 3325191783Srmacklemstruct buf_ops buf_ops_newnfs = { 3326191783Srmacklem .bop_name = "buf_ops_nfs", 3327191783Srmacklem .bop_write = nfs_bwrite, 3328191783Srmacklem .bop_strategy = bufstrategy, 3329191783Srmacklem .bop_sync = bufsync, 3330191783Srmacklem .bop_bdflush = bufbdflush, 3331191783Srmacklem}; 3332191783Srmacklem 3333191783Srmacklem/* 3334191783Srmacklem * Cloned from vop_stdlock(), and then the ugly hack added. 3335191783Srmacklem */ 3336191783Srmacklemstatic int 3337191783Srmacklemnfs_lock1(struct vop_lock1_args *ap) 3338191783Srmacklem{ 3339191783Srmacklem struct vnode *vp = ap->a_vp; 3340191783Srmacklem int error = 0; 3341191783Srmacklem 3342191783Srmacklem /* 3343191783Srmacklem * Since vfs_hash_get() calls vget() and it will no longer work 3344191783Srmacklem * for FreeBSD8 with flags == 0, I can only think of this horrible 3345191783Srmacklem * hack to work around it. I call vfs_hash_get() with LK_EXCLOTHER 3346191783Srmacklem * and then handle it here. All I want for this case is a v_usecount 3347191783Srmacklem * on the vnode to use for recovery, while another thread might 3348191783Srmacklem * hold a lock on the vnode. I have the other threads blocked, so 3349191783Srmacklem * there isn't any race problem. 3350191783Srmacklem */ 3351191783Srmacklem if ((ap->a_flags & LK_TYPE_MASK) == LK_EXCLOTHER) { 3352191783Srmacklem if ((ap->a_flags & LK_INTERLOCK) == 0) 3353191783Srmacklem panic("ncllock1"); 3354191783Srmacklem if ((vp->v_iflag & VI_DOOMED)) 3355191783Srmacklem error = ENOENT; 3356191783Srmacklem VI_UNLOCK(vp); 3357191783Srmacklem return (error); 3358191783Srmacklem } 3359191783Srmacklem return (_lockmgr_args(vp->v_vnlock, ap->a_flags, VI_MTX(vp), 3360191783Srmacklem LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, ap->a_file, 3361191783Srmacklem ap->a_line)); 3362191783Srmacklem} 3363191783Srmacklem 3364191783Srmacklemstatic int 3365191783Srmacklemnfs_getacl(struct vop_getacl_args *ap) 3366191783Srmacklem{ 3367191783Srmacklem int error; 3368191783Srmacklem 3369191783Srmacklem if (ap->a_type != ACL_TYPE_NFS4) 3370191783Srmacklem return (EOPNOTSUPP); 3371191783Srmacklem error = nfsrpc_getacl(ap->a_vp, ap->a_cred, ap->a_td, ap->a_aclp, 3372191783Srmacklem NULL); 3373191783Srmacklem if (error > NFSERR_STALE) { 3374191783Srmacklem (void) nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); 3375191783Srmacklem error = EPERM; 3376191783Srmacklem } 3377191783Srmacklem return (error); 3378191783Srmacklem} 3379191783Srmacklem 3380191783Srmacklemstatic int 3381191783Srmacklemnfs_setacl(struct vop_setacl_args *ap) 3382191783Srmacklem{ 3383191783Srmacklem int error; 3384191783Srmacklem 3385191783Srmacklem if (ap->a_type != ACL_TYPE_NFS4) 3386191783Srmacklem return (EOPNOTSUPP); 3387191783Srmacklem error = nfsrpc_setacl(ap->a_vp, ap->a_cred, ap->a_td, ap->a_aclp, 3388191783Srmacklem NULL); 3389191783Srmacklem if (error > NFSERR_STALE) { 3390191783Srmacklem (void) nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); 3391191783Srmacklem error = EPERM; 3392191783Srmacklem } 3393191783Srmacklem return (error); 3394191783Srmacklem} 3395220611Srmacklem 3396220611Srmacklem/* 3397220611Srmacklem * Return POSIX pathconf information applicable to nfs filesystems. 3398220611Srmacklem */ 3399220611Srmacklemstatic int 3400220611Srmacklemnfs_pathconf(struct vop_pathconf_args *ap) 3401220611Srmacklem{ 3402220611Srmacklem struct nfsv3_pathconf pc; 3403220611Srmacklem struct nfsvattr nfsva; 3404220611Srmacklem struct vnode *vp = ap->a_vp; 3405220611Srmacklem struct thread *td = curthread; 3406220611Srmacklem int attrflag, error; 3407220611Srmacklem 3408265721Srmacklem if ((NFS_ISV34(vp) && (ap->a_name == _PC_LINK_MAX || 3409222540Srmacklem ap->a_name == _PC_NAME_MAX || ap->a_name == _PC_CHOWN_RESTRICTED || 3410265721Srmacklem ap->a_name == _PC_NO_TRUNC)) || 3411265721Srmacklem (NFS_ISV4(vp) && ap->a_name == _PC_ACL_NFS4)) { 3412222540Srmacklem /* 3413222540Srmacklem * Since only the above 4 a_names are returned by the NFSv3 3414222540Srmacklem * Pathconf RPC, there is no point in doing it for others. 3415265721Srmacklem * For NFSv4, the Pathconf RPC (actually a Getattr Op.) can 3416265721Srmacklem * be used for _PC_NFS4_ACL as well. 3417222540Srmacklem */ 3418220611Srmacklem error = nfsrpc_pathconf(vp, &pc, td->td_ucred, td, &nfsva, 3419220611Srmacklem &attrflag, NULL); 3420220611Srmacklem if (attrflag != 0) 3421220611Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 3422220611Srmacklem 1); 3423220611Srmacklem if (error != 0) 3424220611Srmacklem return (error); 3425220611Srmacklem } else { 3426222540Srmacklem /* 3427222540Srmacklem * For NFSv2 (or NFSv3 when not one of the above 4 a_names), 3428222540Srmacklem * just fake them. 3429222540Srmacklem */ 3430220611Srmacklem pc.pc_linkmax = LINK_MAX; 3431220611Srmacklem pc.pc_namemax = NFS_MAXNAMLEN; 3432220611Srmacklem pc.pc_notrunc = 1; 3433220611Srmacklem pc.pc_chownrestricted = 1; 3434220611Srmacklem pc.pc_caseinsensitive = 0; 3435220611Srmacklem pc.pc_casepreserving = 1; 3436220611Srmacklem error = 0; 3437220611Srmacklem } 3438220611Srmacklem switch (ap->a_name) { 3439220611Srmacklem case _PC_LINK_MAX: 3440220611Srmacklem *ap->a_retval = pc.pc_linkmax; 3441220611Srmacklem break; 3442220611Srmacklem case _PC_NAME_MAX: 3443220611Srmacklem *ap->a_retval = pc.pc_namemax; 3444220611Srmacklem break; 3445220611Srmacklem case _PC_PATH_MAX: 3446220611Srmacklem *ap->a_retval = PATH_MAX; 3447220611Srmacklem break; 3448220611Srmacklem case _PC_PIPE_BUF: 3449220611Srmacklem *ap->a_retval = PIPE_BUF; 3450220611Srmacklem break; 3451220611Srmacklem case _PC_CHOWN_RESTRICTED: 3452220611Srmacklem *ap->a_retval = pc.pc_chownrestricted; 3453220611Srmacklem break; 3454220611Srmacklem case _PC_NO_TRUNC: 3455220611Srmacklem *ap->a_retval = pc.pc_notrunc; 3456220611Srmacklem break; 3457220611Srmacklem case _PC_ACL_EXTENDED: 3458220611Srmacklem *ap->a_retval = 0; 3459220611Srmacklem break; 3460220611Srmacklem case _PC_ACL_NFS4: 3461220611Srmacklem if (NFS_ISV4(vp) && nfsrv_useacl != 0 && attrflag != 0 && 3462220611Srmacklem NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) 3463220611Srmacklem *ap->a_retval = 1; 3464220611Srmacklem else 3465220611Srmacklem *ap->a_retval = 0; 3466220611Srmacklem break; 3467220611Srmacklem case _PC_ACL_PATH_MAX: 3468220611Srmacklem if (NFS_ISV4(vp)) 3469220611Srmacklem *ap->a_retval = ACL_MAX_ENTRIES; 3470220611Srmacklem else 3471220611Srmacklem *ap->a_retval = 3; 3472220611Srmacklem break; 3473220611Srmacklem case _PC_MAC_PRESENT: 3474220611Srmacklem *ap->a_retval = 0; 3475220611Srmacklem break; 3476220611Srmacklem case _PC_ASYNC_IO: 3477220611Srmacklem /* _PC_ASYNC_IO should have been handled by upper layers. */ 3478220611Srmacklem KASSERT(0, ("_PC_ASYNC_IO should not get here")); 3479220611Srmacklem error = EINVAL; 3480220611Srmacklem break; 3481220611Srmacklem case _PC_PRIO_IO: 3482220611Srmacklem *ap->a_retval = 0; 3483220611Srmacklem break; 3484220611Srmacklem case _PC_SYNC_IO: 3485220611Srmacklem *ap->a_retval = 0; 3486220611Srmacklem break; 3487220611Srmacklem case _PC_ALLOC_SIZE_MIN: 3488220611Srmacklem *ap->a_retval = vp->v_mount->mnt_stat.f_bsize; 3489220611Srmacklem break; 3490220611Srmacklem case _PC_FILESIZEBITS: 3491220611Srmacklem if (NFS_ISV34(vp)) 3492220611Srmacklem *ap->a_retval = 64; 3493220611Srmacklem else 3494220611Srmacklem *ap->a_retval = 32; 3495220611Srmacklem break; 3496220611Srmacklem case _PC_REC_INCR_XFER_SIZE: 3497220611Srmacklem *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; 3498220611Srmacklem break; 3499220611Srmacklem case _PC_REC_MAX_XFER_SIZE: 3500220611Srmacklem *ap->a_retval = -1; /* means ``unlimited'' */ 3501220611Srmacklem break; 3502220611Srmacklem case _PC_REC_MIN_XFER_SIZE: 3503220611Srmacklem *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; 3504220611Srmacklem break; 3505220611Srmacklem case _PC_REC_XFER_ALIGN: 3506220611Srmacklem *ap->a_retval = PAGE_SIZE; 3507220611Srmacklem break; 3508220611Srmacklem case _PC_SYMLINK_MAX: 3509220611Srmacklem *ap->a_retval = NFS_MAXPATHLEN; 3510220611Srmacklem break; 3511220611Srmacklem 3512220611Srmacklem default: 3513220611Srmacklem error = EINVAL; 3514220611Srmacklem break; 3515220611Srmacklem } 3516220611Srmacklem return (error); 3517220611Srmacklem} 3518220611Srmacklem 3519