1 1.4 pgoyette /* $NetBSD: nfs_clvnops.c,v 1.4 2016/12/13 22:17:33 pgoyette Exp $ */ 2 1.1 dholland /*- 3 1.1 dholland * Copyright (c) 1989, 1993 4 1.1 dholland * The Regents of the University of California. All rights reserved. 5 1.1 dholland * 6 1.1 dholland * This code is derived from software contributed to Berkeley by 7 1.1 dholland * Rick Macklem at The University of Guelph. 8 1.1 dholland * 9 1.1 dholland * Redistribution and use in source and binary forms, with or without 10 1.1 dholland * modification, are permitted provided that the following conditions 11 1.1 dholland * are met: 12 1.1 dholland * 1. Redistributions of source code must retain the above copyright 13 1.1 dholland * notice, this list of conditions and the following disclaimer. 14 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 dholland * notice, this list of conditions and the following disclaimer in the 16 1.1 dholland * documentation and/or other materials provided with the distribution. 17 1.1 dholland * 4. Neither the name of the University nor the names of its contributors 18 1.1 dholland * may be used to endorse or promote products derived from this software 19 1.1 dholland * without specific prior written permission. 20 1.1 dholland * 21 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 1.1 dholland * SUCH DAMAGE. 32 1.1 dholland * 33 1.1 dholland * from nfs_vnops.c 8.16 (Berkeley) 5/27/95 34 1.1 dholland */ 35 1.1 dholland 36 1.1 dholland #include <sys/cdefs.h> 37 1.3 pgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsclient/nfs_clvnops.c 304026 2016-08-12 22:44:59Z rmacklem "); */ 38 1.4 pgoyette __RCSID("$NetBSD: nfs_clvnops.c,v 1.4 2016/12/13 22:17:33 pgoyette Exp $"); 39 1.1 dholland 40 1.1 dholland /* 41 1.1 dholland * vnode op calls for Sun NFS version 2, 3 and 4 42 1.1 dholland */ 43 1.1 dholland 44 1.4 pgoyette #ifdef _KERNEL_OPT 45 1.4 pgoyette #include "opt_dtrace.h" 46 1.1 dholland #include "opt_inet.h" 47 1.4 pgoyette #endif 48 1.1 dholland 49 1.1 dholland #include <sys/param.h> 50 1.1 dholland #include <sys/kernel.h> 51 1.1 dholland #include <sys/systm.h> 52 1.1 dholland #include <sys/resourcevar.h> 53 1.1 dholland #include <sys/proc.h> 54 1.1 dholland #include <sys/mount.h> 55 1.1 dholland #include <sys/bio.h> 56 1.1 dholland #include <sys/buf.h> 57 1.1 dholland #include <sys/jail.h> 58 1.1 dholland #include <sys/malloc.h> 59 1.1 dholland #include <sys/mbuf.h> 60 1.1 dholland #include <sys/namei.h> 61 1.1 dholland #include <sys/socket.h> 62 1.1 dholland #include <sys/vnode.h> 63 1.1 dholland #include <sys/dirent.h> 64 1.1 dholland #include <sys/fcntl.h> 65 1.1 dholland #include <sys/lockf.h> 66 1.1 dholland #include <sys/stat.h> 67 1.1 dholland #include <sys/sysctl.h> 68 1.1 dholland #include <sys/signalvar.h> 69 1.1 dholland 70 1.1 dholland #include <vm/vm.h> 71 1.1 dholland #include <vm/vm_extern.h> 72 1.1 dholland #include <vm/vm_object.h> 73 1.1 dholland 74 1.4 pgoyette #include <fs/nfs/common/nfsport.h> 75 1.4 pgoyette #include <fs/nfs/client/nfsnode.h> 76 1.4 pgoyette #include <fs/nfs/client/nfsmount.h> 77 1.4 pgoyette #include <fs/nfs/client/nfs.h> 78 1.4 pgoyette #include <fs/nfs/client/nfs_kdtrace.h> 79 1.1 dholland 80 1.1 dholland #include <net/if.h> 81 1.1 dholland #include <netinet/in.h> 82 1.1 dholland #include <netinet/in_var.h> 83 1.1 dholland 84 1.4 pgoyette #include <fs/nfs/common/nfs_lock.h> 85 1.1 dholland 86 1.1 dholland #ifdef KDTRACE_HOOKS 87 1.1 dholland #include <sys/dtrace_bsd.h> 88 1.1 dholland 89 1.1 dholland dtrace_nfsclient_accesscache_flush_probe_func_t 90 1.1 dholland dtrace_nfscl_accesscache_flush_done_probe; 91 1.1 dholland uint32_t nfscl_accesscache_flush_done_id; 92 1.1 dholland 93 1.1 dholland dtrace_nfsclient_accesscache_get_probe_func_t 94 1.1 dholland dtrace_nfscl_accesscache_get_hit_probe, 95 1.1 dholland dtrace_nfscl_accesscache_get_miss_probe; 96 1.1 dholland uint32_t nfscl_accesscache_get_hit_id; 97 1.1 dholland uint32_t nfscl_accesscache_get_miss_id; 98 1.1 dholland 99 1.1 dholland dtrace_nfsclient_accesscache_load_probe_func_t 100 1.1 dholland dtrace_nfscl_accesscache_load_done_probe; 101 1.1 dholland uint32_t nfscl_accesscache_load_done_id; 102 1.1 dholland #endif /* !KDTRACE_HOOKS */ 103 1.1 dholland 104 1.1 dholland /* Defs */ 105 1.1 dholland #define TRUE 1 106 1.1 dholland #define FALSE 0 107 1.1 dholland 108 1.3 pgoyette extern struct nfsstatsv1 nfsstatsv1; 109 1.1 dholland extern int nfsrv_useacl; 110 1.1 dholland extern int nfscl_debuglevel; 111 1.1 dholland MALLOC_DECLARE(M_NEWNFSREQ); 112 1.1 dholland 113 1.1 dholland /* 114 1.1 dholland * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these 115 1.1 dholland * calls are not in getblk() and brelse() so that they would not be necessary 116 1.1 dholland * here. 117 1.1 dholland */ 118 1.1 dholland #ifndef B_VMIO 119 1.1 dholland #define vfs_busy_pages(bp, f) 120 1.1 dholland #endif 121 1.1 dholland 122 1.1 dholland static vop_read_t nfsfifo_read; 123 1.1 dholland static vop_write_t nfsfifo_write; 124 1.1 dholland static vop_close_t nfsfifo_close; 125 1.1 dholland static int nfs_setattrrpc(struct vnode *, struct vattr *, struct ucred *, 126 1.1 dholland struct thread *); 127 1.1 dholland static vop_lookup_t nfs_lookup; 128 1.1 dholland static vop_create_t nfs_create; 129 1.1 dholland static vop_mknod_t nfs_mknod; 130 1.1 dholland static vop_open_t nfs_open; 131 1.1 dholland static vop_pathconf_t nfs_pathconf; 132 1.1 dholland static vop_close_t nfs_close; 133 1.1 dholland static vop_access_t nfs_access; 134 1.1 dholland static vop_getattr_t nfs_getattr; 135 1.1 dholland static vop_setattr_t nfs_setattr; 136 1.1 dholland static vop_read_t nfs_read; 137 1.1 dholland static vop_fsync_t nfs_fsync; 138 1.1 dholland static vop_remove_t nfs_remove; 139 1.1 dholland static vop_link_t nfs_link; 140 1.1 dholland static vop_rename_t nfs_rename; 141 1.1 dholland static vop_mkdir_t nfs_mkdir; 142 1.1 dholland static vop_rmdir_t nfs_rmdir; 143 1.1 dholland static vop_symlink_t nfs_symlink; 144 1.1 dholland static vop_readdir_t nfs_readdir; 145 1.1 dholland static vop_strategy_t nfs_strategy; 146 1.1 dholland static int nfs_lookitup(struct vnode *, char *, int, 147 1.1 dholland struct ucred *, struct thread *, struct nfsnode **); 148 1.1 dholland static int nfs_sillyrename(struct vnode *, struct vnode *, 149 1.1 dholland struct componentname *); 150 1.1 dholland static vop_access_t nfsspec_access; 151 1.1 dholland static vop_readlink_t nfs_readlink; 152 1.1 dholland static vop_print_t nfs_print; 153 1.1 dholland static vop_advlock_t nfs_advlock; 154 1.1 dholland static vop_advlockasync_t nfs_advlockasync; 155 1.1 dholland static vop_getacl_t nfs_getacl; 156 1.1 dholland static vop_setacl_t nfs_setacl; 157 1.1 dholland 158 1.1 dholland /* 159 1.1 dholland * Global vfs data structures for nfs 160 1.1 dholland */ 161 1.1 dholland struct vop_vector newnfs_vnodeops = { 162 1.1 dholland .vop_default = &default_vnodeops, 163 1.1 dholland .vop_access = nfs_access, 164 1.1 dholland .vop_advlock = nfs_advlock, 165 1.1 dholland .vop_advlockasync = nfs_advlockasync, 166 1.1 dholland .vop_close = nfs_close, 167 1.1 dholland .vop_create = nfs_create, 168 1.1 dholland .vop_fsync = nfs_fsync, 169 1.1 dholland .vop_getattr = nfs_getattr, 170 1.1 dholland .vop_getpages = ncl_getpages, 171 1.1 dholland .vop_putpages = ncl_putpages, 172 1.1 dholland .vop_inactive = ncl_inactive, 173 1.1 dholland .vop_link = nfs_link, 174 1.1 dholland .vop_lookup = nfs_lookup, 175 1.1 dholland .vop_mkdir = nfs_mkdir, 176 1.1 dholland .vop_mknod = nfs_mknod, 177 1.1 dholland .vop_open = nfs_open, 178 1.1 dholland .vop_pathconf = nfs_pathconf, 179 1.1 dholland .vop_print = nfs_print, 180 1.1 dholland .vop_read = nfs_read, 181 1.1 dholland .vop_readdir = nfs_readdir, 182 1.1 dholland .vop_readlink = nfs_readlink, 183 1.1 dholland .vop_reclaim = ncl_reclaim, 184 1.1 dholland .vop_remove = nfs_remove, 185 1.1 dholland .vop_rename = nfs_rename, 186 1.1 dholland .vop_rmdir = nfs_rmdir, 187 1.1 dholland .vop_setattr = nfs_setattr, 188 1.1 dholland .vop_strategy = nfs_strategy, 189 1.1 dholland .vop_symlink = nfs_symlink, 190 1.1 dholland .vop_write = ncl_write, 191 1.1 dholland .vop_getacl = nfs_getacl, 192 1.1 dholland .vop_setacl = nfs_setacl, 193 1.1 dholland }; 194 1.1 dholland 195 1.1 dholland struct vop_vector newnfs_fifoops = { 196 1.1 dholland .vop_default = &fifo_specops, 197 1.1 dholland .vop_access = nfsspec_access, 198 1.1 dholland .vop_close = nfsfifo_close, 199 1.1 dholland .vop_fsync = nfs_fsync, 200 1.1 dholland .vop_getattr = nfs_getattr, 201 1.1 dholland .vop_inactive = ncl_inactive, 202 1.1 dholland .vop_print = nfs_print, 203 1.1 dholland .vop_read = nfsfifo_read, 204 1.1 dholland .vop_reclaim = ncl_reclaim, 205 1.1 dholland .vop_setattr = nfs_setattr, 206 1.1 dholland .vop_write = nfsfifo_write, 207 1.1 dholland }; 208 1.1 dholland 209 1.1 dholland static int nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, 210 1.1 dholland struct componentname *cnp, struct vattr *vap); 211 1.1 dholland static int nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name, 212 1.1 dholland int namelen, struct ucred *cred, struct thread *td); 213 1.1 dholland static int nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, 214 1.1 dholland char *fnameptr, int fnamelen, struct vnode *tdvp, struct vnode *tvp, 215 1.1 dholland char *tnameptr, int tnamelen, struct ucred *cred, struct thread *td); 216 1.1 dholland static int nfs_renameit(struct vnode *sdvp, struct vnode *svp, 217 1.1 dholland struct componentname *scnp, struct sillyrename *sp); 218 1.1 dholland 219 1.1 dholland /* 220 1.1 dholland * Global variables 221 1.1 dholland */ 222 1.1 dholland #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 223 1.1 dholland 224 1.1 dholland SYSCTL_DECL(_vfs_nfs); 225 1.1 dholland 226 1.1 dholland static int nfsaccess_cache_timeout = NFS_MAXATTRTIMO; 227 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW, 228 1.1 dholland &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout"); 229 1.1 dholland 230 1.1 dholland static int nfs_prime_access_cache = 0; 231 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, prime_access_cache, CTLFLAG_RW, 232 1.1 dholland &nfs_prime_access_cache, 0, 233 1.1 dholland "Prime NFS ACCESS cache when fetching attributes"); 234 1.1 dholland 235 1.1 dholland static int newnfs_commit_on_close = 0; 236 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_on_close, CTLFLAG_RW, 237 1.1 dholland &newnfs_commit_on_close, 0, "write+commit on close, else only write"); 238 1.1 dholland 239 1.1 dholland static int nfs_clean_pages_on_close = 1; 240 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, clean_pages_on_close, CTLFLAG_RW, 241 1.1 dholland &nfs_clean_pages_on_close, 0, "NFS clean dirty pages on close"); 242 1.1 dholland 243 1.1 dholland int newnfs_directio_enable = 0; 244 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_directio_enable, CTLFLAG_RW, 245 1.1 dholland &newnfs_directio_enable, 0, "Enable NFS directio"); 246 1.1 dholland 247 1.1 dholland int nfs_keep_dirty_on_error; 248 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_keep_dirty_on_error, CTLFLAG_RW, 249 1.1 dholland &nfs_keep_dirty_on_error, 0, "Retry pageout if error returned"); 250 1.1 dholland 251 1.1 dholland /* 252 1.1 dholland * This sysctl allows other processes to mmap a file that has been opened 253 1.1 dholland * O_DIRECT by a process. In general, having processes mmap the file while 254 1.1 dholland * Direct IO is in progress can lead to Data Inconsistencies. But, we allow 255 1.1 dholland * this by default to prevent DoS attacks - to prevent a malicious user from 256 1.1 dholland * opening up files O_DIRECT preventing other users from mmap'ing these 257 1.1 dholland * files. "Protected" environments where stricter consistency guarantees are 258 1.1 dholland * required can disable this knob. The process that opened the file O_DIRECT 259 1.1 dholland * cannot mmap() the file, because mmap'ed IO on an O_DIRECT open() is not 260 1.1 dholland * meaningful. 261 1.1 dholland */ 262 1.1 dholland int newnfs_directio_allow_mmap = 1; 263 1.1 dholland SYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_directio_allow_mmap, CTLFLAG_RW, 264 1.1 dholland &newnfs_directio_allow_mmap, 0, "Enable mmaped IO on file with O_DIRECT opens"); 265 1.1 dholland 266 1.1 dholland #define NFSACCESS_ALL (NFSACCESS_READ | NFSACCESS_MODIFY \ 267 1.1 dholland | NFSACCESS_EXTEND | NFSACCESS_EXECUTE \ 268 1.1 dholland | NFSACCESS_DELETE | NFSACCESS_LOOKUP) 269 1.1 dholland 270 1.1 dholland /* 271 1.1 dholland * SMP Locking Note : 272 1.1 dholland * The list of locks after the description of the lock is the ordering 273 1.1 dholland * of other locks acquired with the lock held. 274 1.1 dholland * np->n_mtx : Protects the fields in the nfsnode. 275 1.1 dholland VM Object Lock 276 1.1 dholland VI_MTX (acquired indirectly) 277 1.1 dholland * nmp->nm_mtx : Protects the fields in the nfsmount. 278 1.1 dholland rep->r_mtx 279 1.1 dholland * ncl_iod_mutex : Global lock, protects shared nfsiod state. 280 1.1 dholland * nfs_reqq_mtx : Global lock, protects the nfs_reqq list. 281 1.1 dholland nmp->nm_mtx 282 1.1 dholland rep->r_mtx 283 1.1 dholland * rep->r_mtx : Protects the fields in an nfsreq. 284 1.1 dholland */ 285 1.1 dholland 286 1.1 dholland static int 287 1.1 dholland nfs34_access_otw(struct vnode *vp, int wmode, struct thread *td, 288 1.1 dholland struct ucred *cred, u_int32_t *retmode) 289 1.1 dholland { 290 1.1 dholland int error = 0, attrflag, i, lrupos; 291 1.1 dholland u_int32_t rmode; 292 1.1 dholland struct nfsnode *np = VTONFS(vp); 293 1.1 dholland struct nfsvattr nfsva; 294 1.1 dholland 295 1.1 dholland error = nfsrpc_accessrpc(vp, wmode, cred, td, &nfsva, &attrflag, 296 1.1 dholland &rmode, NULL); 297 1.1 dholland if (attrflag) 298 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 299 1.1 dholland if (!error) { 300 1.1 dholland lrupos = 0; 301 1.1 dholland mtx_lock(&np->n_mtx); 302 1.1 dholland for (i = 0; i < NFS_ACCESSCACHESIZE; i++) { 303 1.1 dholland if (np->n_accesscache[i].uid == cred->cr_uid) { 304 1.1 dholland np->n_accesscache[i].mode = rmode; 305 1.1 dholland np->n_accesscache[i].stamp = time_second; 306 1.1 dholland break; 307 1.1 dholland } 308 1.1 dholland if (i > 0 && np->n_accesscache[i].stamp < 309 1.1 dholland np->n_accesscache[lrupos].stamp) 310 1.1 dholland lrupos = i; 311 1.1 dholland } 312 1.1 dholland if (i == NFS_ACCESSCACHESIZE) { 313 1.1 dholland np->n_accesscache[lrupos].uid = cred->cr_uid; 314 1.1 dholland np->n_accesscache[lrupos].mode = rmode; 315 1.1 dholland np->n_accesscache[lrupos].stamp = time_second; 316 1.1 dholland } 317 1.1 dholland mtx_unlock(&np->n_mtx); 318 1.1 dholland if (retmode != NULL) 319 1.1 dholland *retmode = rmode; 320 1.1 dholland KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, rmode, 0); 321 1.1 dholland } else if (NFS_ISV4(vp)) { 322 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 323 1.1 dholland } 324 1.1 dholland #ifdef KDTRACE_HOOKS 325 1.1 dholland if (error != 0) 326 1.1 dholland KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, 0, 327 1.1 dholland error); 328 1.1 dholland #endif 329 1.1 dholland return (error); 330 1.1 dholland } 331 1.1 dholland 332 1.1 dholland /* 333 1.1 dholland * nfs access vnode op. 334 1.1 dholland * For nfs version 2, just return ok. File accesses may fail later. 335 1.1 dholland * For nfs version 3, use the access rpc to check accessibility. If file modes 336 1.1 dholland * are changed on the server, accesses might still fail later. 337 1.1 dholland */ 338 1.1 dholland static int 339 1.1 dholland nfs_access(struct vop_access_args *ap) 340 1.1 dholland { 341 1.1 dholland struct vnode *vp = ap->a_vp; 342 1.1 dholland int error = 0, i, gotahit; 343 1.1 dholland u_int32_t mode, wmode, rmode; 344 1.1 dholland int v34 = NFS_ISV34(vp); 345 1.1 dholland struct nfsnode *np = VTONFS(vp); 346 1.1 dholland 347 1.1 dholland /* 348 1.1 dholland * Disallow write attempts on filesystems mounted read-only; 349 1.1 dholland * unless the file is a socket, fifo, or a block or character 350 1.1 dholland * device resident on the filesystem. 351 1.1 dholland */ 352 1.1 dholland if ((ap->a_accmode & (VWRITE | VAPPEND | VWRITE_NAMED_ATTRS | 353 1.1 dholland VDELETE_CHILD | VWRITE_ATTRIBUTES | VDELETE | VWRITE_ACL | 354 1.1 dholland VWRITE_OWNER)) != 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) != 0) { 355 1.1 dholland switch (vp->v_type) { 356 1.1 dholland case VREG: 357 1.1 dholland case VDIR: 358 1.1 dholland case VLNK: 359 1.1 dholland return (EROFS); 360 1.1 dholland default: 361 1.1 dholland break; 362 1.1 dholland } 363 1.1 dholland } 364 1.1 dholland /* 365 1.1 dholland * For nfs v3 or v4, check to see if we have done this recently, and if 366 1.1 dholland * so return our cached result instead of making an ACCESS call. 367 1.1 dholland * If not, do an access rpc, otherwise you are stuck emulating 368 1.1 dholland * ufs_access() locally using the vattr. This may not be correct, 369 1.1 dholland * since the server may apply other access criteria such as 370 1.1 dholland * client uid-->server uid mapping that we do not know about. 371 1.1 dholland */ 372 1.1 dholland if (v34) { 373 1.1 dholland if (ap->a_accmode & VREAD) 374 1.1 dholland mode = NFSACCESS_READ; 375 1.1 dholland else 376 1.1 dholland mode = 0; 377 1.1 dholland if (vp->v_type != VDIR) { 378 1.1 dholland if (ap->a_accmode & VWRITE) 379 1.1 dholland mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 380 1.1 dholland if (ap->a_accmode & VAPPEND) 381 1.1 dholland mode |= NFSACCESS_EXTEND; 382 1.1 dholland if (ap->a_accmode & VEXEC) 383 1.1 dholland mode |= NFSACCESS_EXECUTE; 384 1.1 dholland if (ap->a_accmode & VDELETE) 385 1.1 dholland mode |= NFSACCESS_DELETE; 386 1.1 dholland } else { 387 1.1 dholland if (ap->a_accmode & VWRITE) 388 1.1 dholland mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 389 1.1 dholland if (ap->a_accmode & VAPPEND) 390 1.1 dholland mode |= NFSACCESS_EXTEND; 391 1.1 dholland if (ap->a_accmode & VEXEC) 392 1.1 dholland mode |= NFSACCESS_LOOKUP; 393 1.1 dholland if (ap->a_accmode & VDELETE) 394 1.1 dholland mode |= NFSACCESS_DELETE; 395 1.1 dholland if (ap->a_accmode & VDELETE_CHILD) 396 1.1 dholland mode |= NFSACCESS_MODIFY; 397 1.1 dholland } 398 1.1 dholland /* XXX safety belt, only make blanket request if caching */ 399 1.1 dholland if (nfsaccess_cache_timeout > 0) { 400 1.1 dholland wmode = NFSACCESS_READ | NFSACCESS_MODIFY | 401 1.1 dholland NFSACCESS_EXTEND | NFSACCESS_EXECUTE | 402 1.1 dholland NFSACCESS_DELETE | NFSACCESS_LOOKUP; 403 1.1 dholland } else { 404 1.1 dholland wmode = mode; 405 1.1 dholland } 406 1.1 dholland 407 1.1 dholland /* 408 1.1 dholland * Does our cached result allow us to give a definite yes to 409 1.1 dholland * this request? 410 1.1 dholland */ 411 1.1 dholland gotahit = 0; 412 1.1 dholland mtx_lock(&np->n_mtx); 413 1.1 dholland for (i = 0; i < NFS_ACCESSCACHESIZE; i++) { 414 1.1 dholland if (ap->a_cred->cr_uid == np->n_accesscache[i].uid) { 415 1.1 dholland if (time_second < (np->n_accesscache[i].stamp 416 1.1 dholland + nfsaccess_cache_timeout) && 417 1.1 dholland (np->n_accesscache[i].mode & mode) == mode) { 418 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.accesscache_hits); 419 1.1 dholland gotahit = 1; 420 1.1 dholland } 421 1.1 dholland break; 422 1.1 dholland } 423 1.1 dholland } 424 1.1 dholland mtx_unlock(&np->n_mtx); 425 1.1 dholland #ifdef KDTRACE_HOOKS 426 1.1 dholland if (gotahit != 0) 427 1.1 dholland KDTRACE_NFS_ACCESSCACHE_GET_HIT(vp, 428 1.1 dholland ap->a_cred->cr_uid, mode); 429 1.1 dholland else 430 1.1 dholland KDTRACE_NFS_ACCESSCACHE_GET_MISS(vp, 431 1.1 dholland ap->a_cred->cr_uid, mode); 432 1.1 dholland #endif 433 1.1 dholland if (gotahit == 0) { 434 1.1 dholland /* 435 1.1 dholland * Either a no, or a don't know. Go to the wire. 436 1.1 dholland */ 437 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.accesscache_misses); 438 1.1 dholland error = nfs34_access_otw(vp, wmode, ap->a_td, 439 1.1 dholland ap->a_cred, &rmode); 440 1.1 dholland if (!error && 441 1.1 dholland (rmode & mode) != mode) 442 1.1 dholland error = EACCES; 443 1.1 dholland } 444 1.1 dholland return (error); 445 1.1 dholland } else { 446 1.1 dholland if ((error = nfsspec_access(ap)) != 0) { 447 1.1 dholland return (error); 448 1.1 dholland } 449 1.1 dholland /* 450 1.1 dholland * Attempt to prevent a mapped root from accessing a file 451 1.1 dholland * which it shouldn't. We try to read a byte from the file 452 1.1 dholland * if the user is root and the file is not zero length. 453 1.1 dholland * After calling nfsspec_access, we should have the correct 454 1.1 dholland * file size cached. 455 1.1 dholland */ 456 1.1 dholland mtx_lock(&np->n_mtx); 457 1.1 dholland if (ap->a_cred->cr_uid == 0 && (ap->a_accmode & VREAD) 458 1.1 dholland && VTONFS(vp)->n_size > 0) { 459 1.1 dholland struct iovec aiov; 460 1.1 dholland struct uio auio; 461 1.1 dholland char buf[1]; 462 1.1 dholland 463 1.1 dholland mtx_unlock(&np->n_mtx); 464 1.1 dholland aiov.iov_base = buf; 465 1.1 dholland aiov.iov_len = 1; 466 1.1 dholland auio.uio_iov = &aiov; 467 1.1 dholland auio.uio_iovcnt = 1; 468 1.1 dholland auio.uio_offset = 0; 469 1.1 dholland auio.uio_resid = 1; 470 1.1 dholland auio.uio_segflg = UIO_SYSSPACE; 471 1.1 dholland auio.uio_rw = UIO_READ; 472 1.1 dholland auio.uio_td = ap->a_td; 473 1.1 dholland 474 1.1 dholland if (vp->v_type == VREG) 475 1.1 dholland error = ncl_readrpc(vp, &auio, ap->a_cred); 476 1.1 dholland else if (vp->v_type == VDIR) { 477 1.1 dholland char* bp; 478 1.1 dholland bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK); 479 1.1 dholland aiov.iov_base = bp; 480 1.1 dholland aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ; 481 1.1 dholland error = ncl_readdirrpc(vp, &auio, ap->a_cred, 482 1.1 dholland ap->a_td); 483 1.1 dholland free(bp, M_TEMP); 484 1.1 dholland } else if (vp->v_type == VLNK) 485 1.1 dholland error = ncl_readlinkrpc(vp, &auio, ap->a_cred); 486 1.1 dholland else 487 1.1 dholland error = EACCES; 488 1.1 dholland } else 489 1.1 dholland mtx_unlock(&np->n_mtx); 490 1.1 dholland return (error); 491 1.1 dholland } 492 1.1 dholland } 493 1.1 dholland 494 1.1 dholland 495 1.1 dholland /* 496 1.1 dholland * nfs open vnode op 497 1.1 dholland * Check to see if the type is ok 498 1.1 dholland * and that deletion is not in progress. 499 1.1 dholland * For paged in text files, you will need to flush the page cache 500 1.1 dholland * if consistency is lost. 501 1.1 dholland */ 502 1.1 dholland /* ARGSUSED */ 503 1.1 dholland static int 504 1.1 dholland nfs_open(struct vop_open_args *ap) 505 1.1 dholland { 506 1.1 dholland struct vnode *vp = ap->a_vp; 507 1.1 dholland struct nfsnode *np = VTONFS(vp); 508 1.1 dholland struct vattr vattr; 509 1.1 dholland int error; 510 1.1 dholland int fmode = ap->a_mode; 511 1.1 dholland struct ucred *cred; 512 1.1 dholland 513 1.1 dholland if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 514 1.1 dholland return (EOPNOTSUPP); 515 1.1 dholland 516 1.1 dholland /* 517 1.1 dholland * For NFSv4, we need to do the Open Op before cache validation, 518 1.1 dholland * so that we conform to RFC3530 Sec. 9.3.1. 519 1.1 dholland */ 520 1.1 dholland if (NFS_ISV4(vp)) { 521 1.1 dholland error = nfsrpc_open(vp, fmode, ap->a_cred, ap->a_td); 522 1.1 dholland if (error) { 523 1.1 dholland error = nfscl_maperr(ap->a_td, error, (uid_t)0, 524 1.1 dholland (gid_t)0); 525 1.1 dholland return (error); 526 1.1 dholland } 527 1.1 dholland } 528 1.1 dholland 529 1.1 dholland /* 530 1.1 dholland * Now, if this Open will be doing reading, re-validate/flush the 531 1.1 dholland * cache, so that Close/Open coherency is maintained. 532 1.1 dholland */ 533 1.1 dholland mtx_lock(&np->n_mtx); 534 1.1 dholland if (np->n_flag & NMODIFIED) { 535 1.1 dholland mtx_unlock(&np->n_mtx); 536 1.1 dholland error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 537 1.1 dholland if (error == EINTR || error == EIO) { 538 1.1 dholland if (NFS_ISV4(vp)) 539 1.1 dholland (void) nfsrpc_close(vp, 0, ap->a_td); 540 1.1 dholland return (error); 541 1.1 dholland } 542 1.1 dholland mtx_lock(&np->n_mtx); 543 1.1 dholland np->n_attrstamp = 0; 544 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 545 1.1 dholland if (vp->v_type == VDIR) 546 1.1 dholland np->n_direofoffset = 0; 547 1.1 dholland mtx_unlock(&np->n_mtx); 548 1.1 dholland error = VOP_GETATTR(vp, &vattr, ap->a_cred); 549 1.1 dholland if (error) { 550 1.1 dholland if (NFS_ISV4(vp)) 551 1.1 dholland (void) nfsrpc_close(vp, 0, ap->a_td); 552 1.1 dholland return (error); 553 1.1 dholland } 554 1.1 dholland mtx_lock(&np->n_mtx); 555 1.1 dholland np->n_mtime = vattr.va_mtime; 556 1.1 dholland if (NFS_ISV4(vp)) 557 1.1 dholland np->n_change = vattr.va_filerev; 558 1.1 dholland } else { 559 1.1 dholland mtx_unlock(&np->n_mtx); 560 1.1 dholland error = VOP_GETATTR(vp, &vattr, ap->a_cred); 561 1.1 dholland if (error) { 562 1.1 dholland if (NFS_ISV4(vp)) 563 1.1 dholland (void) nfsrpc_close(vp, 0, ap->a_td); 564 1.1 dholland return (error); 565 1.1 dholland } 566 1.1 dholland mtx_lock(&np->n_mtx); 567 1.1 dholland if ((NFS_ISV4(vp) && np->n_change != vattr.va_filerev) || 568 1.1 dholland NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { 569 1.1 dholland if (vp->v_type == VDIR) 570 1.1 dholland np->n_direofoffset = 0; 571 1.1 dholland mtx_unlock(&np->n_mtx); 572 1.1 dholland error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 573 1.1 dholland if (error == EINTR || error == EIO) { 574 1.1 dholland if (NFS_ISV4(vp)) 575 1.1 dholland (void) nfsrpc_close(vp, 0, ap->a_td); 576 1.1 dholland return (error); 577 1.1 dholland } 578 1.1 dholland mtx_lock(&np->n_mtx); 579 1.1 dholland np->n_mtime = vattr.va_mtime; 580 1.1 dholland if (NFS_ISV4(vp)) 581 1.1 dholland np->n_change = vattr.va_filerev; 582 1.1 dholland } 583 1.1 dholland } 584 1.1 dholland 585 1.1 dholland /* 586 1.1 dholland * If the object has >= 1 O_DIRECT active opens, we disable caching. 587 1.1 dholland */ 588 1.1 dholland if (newnfs_directio_enable && (fmode & O_DIRECT) && 589 1.1 dholland (vp->v_type == VREG)) { 590 1.1 dholland if (np->n_directio_opens == 0) { 591 1.1 dholland mtx_unlock(&np->n_mtx); 592 1.1 dholland error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 593 1.1 dholland if (error) { 594 1.1 dholland if (NFS_ISV4(vp)) 595 1.1 dholland (void) nfsrpc_close(vp, 0, ap->a_td); 596 1.1 dholland return (error); 597 1.1 dholland } 598 1.1 dholland mtx_lock(&np->n_mtx); 599 1.1 dholland np->n_flag |= NNONCACHE; 600 1.1 dholland } 601 1.1 dholland np->n_directio_opens++; 602 1.1 dholland } 603 1.1 dholland 604 1.1 dholland /* If opened for writing via NFSv4.1 or later, mark that for pNFS. */ 605 1.1 dholland if (NFSHASPNFS(VFSTONFS(vp->v_mount)) && (fmode & FWRITE) != 0) 606 1.1 dholland np->n_flag |= NWRITEOPENED; 607 1.1 dholland 608 1.1 dholland /* 609 1.1 dholland * If this is an open for writing, capture a reference to the 610 1.1 dholland * credentials, so they can be used by ncl_putpages(). Using 611 1.1 dholland * these write credentials is preferable to the credentials of 612 1.1 dholland * whatever thread happens to be doing the VOP_PUTPAGES() since 613 1.1 dholland * the write RPCs are less likely to fail with EACCES. 614 1.1 dholland */ 615 1.1 dholland if ((fmode & FWRITE) != 0) { 616 1.1 dholland cred = np->n_writecred; 617 1.1 dholland np->n_writecred = crhold(ap->a_cred); 618 1.1 dholland } else 619 1.1 dholland cred = NULL; 620 1.1 dholland mtx_unlock(&np->n_mtx); 621 1.1 dholland 622 1.1 dholland if (cred != NULL) 623 1.1 dholland crfree(cred); 624 1.1 dholland vnode_create_vobject(vp, vattr.va_size, ap->a_td); 625 1.1 dholland return (0); 626 1.1 dholland } 627 1.1 dholland 628 1.1 dholland /* 629 1.1 dholland * nfs close vnode op 630 1.1 dholland * What an NFS client should do upon close after writing is a debatable issue. 631 1.1 dholland * Most NFS clients push delayed writes to the server upon close, basically for 632 1.1 dholland * two reasons: 633 1.1 dholland * 1 - So that any write errors may be reported back to the client process 634 1.1 dholland * doing the close system call. By far the two most likely errors are 635 1.1 dholland * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. 636 1.1 dholland * 2 - To put a worst case upper bound on cache inconsistency between 637 1.1 dholland * multiple clients for the file. 638 1.1 dholland * There is also a consistency problem for Version 2 of the protocol w.r.t. 639 1.1 dholland * not being able to tell if other clients are writing a file concurrently, 640 1.1 dholland * since there is no way of knowing if the changed modify time in the reply 641 1.1 dholland * is only due to the write for this client. 642 1.1 dholland * (NFS Version 3 provides weak cache consistency data in the reply that 643 1.1 dholland * should be sufficient to detect and handle this case.) 644 1.1 dholland * 645 1.1 dholland * The current code does the following: 646 1.1 dholland * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers 647 1.1 dholland * for NFS Version 3 - flush dirty buffers to the server but don't invalidate 648 1.1 dholland * or commit them (this satisfies 1 and 2 except for the 649 1.1 dholland * case where the server crashes after this close but 650 1.1 dholland * before the commit RPC, which is felt to be "good 651 1.1 dholland * enough". Changing the last argument to ncl_flush() to 652 1.1 dholland * a 1 would force a commit operation, if it is felt a 653 1.1 dholland * commit is necessary now. 654 1.1 dholland * for NFS Version 4 - flush the dirty buffers and commit them, if 655 1.1 dholland * nfscl_mustflush() says this is necessary. 656 1.1 dholland * It is necessary if there is no write delegation held, 657 1.1 dholland * in order to satisfy open/close coherency. 658 1.1 dholland * If the file isn't cached on local stable storage, 659 1.1 dholland * it may be necessary in order to detect "out of space" 660 1.1 dholland * errors from the server, if the write delegation 661 1.1 dholland * issued by the server doesn't allow the file to grow. 662 1.1 dholland */ 663 1.1 dholland /* ARGSUSED */ 664 1.1 dholland static int 665 1.1 dholland nfs_close(struct vop_close_args *ap) 666 1.1 dholland { 667 1.1 dholland struct vnode *vp = ap->a_vp; 668 1.1 dholland struct nfsnode *np = VTONFS(vp); 669 1.1 dholland struct nfsvattr nfsva; 670 1.1 dholland struct ucred *cred; 671 1.1 dholland int error = 0, ret, localcred = 0; 672 1.1 dholland int fmode = ap->a_fflag; 673 1.1 dholland 674 1.1 dholland if ((vp->v_mount->mnt_kern_flag & MNTK_UNMOUNTF)) 675 1.1 dholland return (0); 676 1.1 dholland /* 677 1.1 dholland * During shutdown, a_cred isn't valid, so just use root. 678 1.1 dholland */ 679 1.1 dholland if (ap->a_cred == NOCRED) { 680 1.1 dholland cred = newnfs_getcred(); 681 1.1 dholland localcred = 1; 682 1.1 dholland } else { 683 1.1 dholland cred = ap->a_cred; 684 1.1 dholland } 685 1.1 dholland if (vp->v_type == VREG) { 686 1.1 dholland /* 687 1.1 dholland * Examine and clean dirty pages, regardless of NMODIFIED. 688 1.1 dholland * This closes a major hole in close-to-open consistency. 689 1.1 dholland * We want to push out all dirty pages (and buffers) on 690 1.1 dholland * close, regardless of whether they were dirtied by 691 1.1 dholland * mmap'ed writes or via write(). 692 1.1 dholland */ 693 1.1 dholland if (nfs_clean_pages_on_close && vp->v_object) { 694 1.1 dholland VM_OBJECT_WLOCK(vp->v_object); 695 1.1 dholland vm_object_page_clean(vp->v_object, 0, 0, 0); 696 1.1 dholland VM_OBJECT_WUNLOCK(vp->v_object); 697 1.1 dholland } 698 1.1 dholland mtx_lock(&np->n_mtx); 699 1.1 dholland if (np->n_flag & NMODIFIED) { 700 1.1 dholland mtx_unlock(&np->n_mtx); 701 1.1 dholland if (NFS_ISV3(vp)) { 702 1.1 dholland /* 703 1.1 dholland * Under NFSv3 we have dirty buffers to dispose of. We 704 1.1 dholland * must flush them to the NFS server. We have the option 705 1.1 dholland * of waiting all the way through the commit rpc or just 706 1.1 dholland * waiting for the initial write. The default is to only 707 1.1 dholland * wait through the initial write so the data is in the 708 1.1 dholland * server's cache, which is roughly similar to the state 709 1.1 dholland * a standard disk subsystem leaves the file in on close(). 710 1.1 dholland * 711 1.1 dholland * We cannot clear the NMODIFIED bit in np->n_flag due to 712 1.1 dholland * potential races with other processes, and certainly 713 1.1 dholland * cannot clear it if we don't commit. 714 1.1 dholland * These races occur when there is no longer the old 715 1.1 dholland * traditional vnode locking implemented for Vnode Ops. 716 1.1 dholland */ 717 1.1 dholland int cm = newnfs_commit_on_close ? 1 : 0; 718 1.1 dholland error = ncl_flush(vp, MNT_WAIT, cred, ap->a_td, cm, 0); 719 1.1 dholland /* np->n_flag &= ~NMODIFIED; */ 720 1.1 dholland } else if (NFS_ISV4(vp)) { 721 1.1 dholland if (nfscl_mustflush(vp) != 0) { 722 1.1 dholland int cm = newnfs_commit_on_close ? 1 : 0; 723 1.1 dholland error = ncl_flush(vp, MNT_WAIT, cred, ap->a_td, 724 1.1 dholland cm, 0); 725 1.1 dholland /* 726 1.1 dholland * as above w.r.t races when clearing 727 1.1 dholland * NMODIFIED. 728 1.1 dholland * np->n_flag &= ~NMODIFIED; 729 1.1 dholland */ 730 1.1 dholland } 731 1.1 dholland } else 732 1.1 dholland error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1); 733 1.1 dholland mtx_lock(&np->n_mtx); 734 1.1 dholland } 735 1.1 dholland /* 736 1.1 dholland * Invalidate the attribute cache in all cases. 737 1.1 dholland * An open is going to fetch fresh attrs any way, other procs 738 1.1 dholland * on this node that have file open will be forced to do an 739 1.1 dholland * otw attr fetch, but this is safe. 740 1.1 dholland * --> A user found that their RPC count dropped by 20% when 741 1.1 dholland * this was commented out and I can't see any requirement 742 1.1 dholland * for it, so I've disabled it when negative lookups are 743 1.1 dholland * enabled. (What does this have to do with negative lookup 744 1.1 dholland * caching? Well nothing, except it was reported by the 745 1.1 dholland * same user that needed negative lookup caching and I wanted 746 1.1 dholland * there to be a way to disable it to see if it 747 1.1 dholland * is the cause of some caching/coherency issue that might 748 1.1 dholland * crop up.) 749 1.1 dholland */ 750 1.1 dholland if (VFSTONFS(vp->v_mount)->nm_negnametimeo == 0) { 751 1.1 dholland np->n_attrstamp = 0; 752 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 753 1.1 dholland } 754 1.1 dholland if (np->n_flag & NWRITEERR) { 755 1.1 dholland np->n_flag &= ~NWRITEERR; 756 1.1 dholland error = np->n_error; 757 1.1 dholland } 758 1.1 dholland mtx_unlock(&np->n_mtx); 759 1.1 dholland } 760 1.1 dholland 761 1.1 dholland if (NFS_ISV4(vp)) { 762 1.1 dholland /* 763 1.1 dholland * Get attributes so "change" is up to date. 764 1.1 dholland */ 765 1.3 pgoyette if (error == 0 && nfscl_mustflush(vp) != 0 && 766 1.3 pgoyette vp->v_type == VREG && 767 1.3 pgoyette (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOCTO) == 0) { 768 1.1 dholland ret = nfsrpc_getattr(vp, cred, ap->a_td, &nfsva, 769 1.1 dholland NULL); 770 1.1 dholland if (!ret) { 771 1.1 dholland np->n_change = nfsva.na_filerev; 772 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 773 1.1 dholland NULL, 0, 0); 774 1.1 dholland } 775 1.1 dholland } 776 1.1 dholland 777 1.1 dholland /* 778 1.1 dholland * and do the close. 779 1.1 dholland */ 780 1.1 dholland ret = nfsrpc_close(vp, 0, ap->a_td); 781 1.1 dholland if (!error && ret) 782 1.1 dholland error = ret; 783 1.1 dholland if (error) 784 1.1 dholland error = nfscl_maperr(ap->a_td, error, (uid_t)0, 785 1.1 dholland (gid_t)0); 786 1.1 dholland } 787 1.1 dholland if (newnfs_directio_enable) 788 1.1 dholland KASSERT((np->n_directio_asyncwr == 0), 789 1.1 dholland ("nfs_close: dirty unflushed (%d) directio buffers\n", 790 1.1 dholland np->n_directio_asyncwr)); 791 1.1 dholland if (newnfs_directio_enable && (fmode & O_DIRECT) && (vp->v_type == VREG)) { 792 1.1 dholland mtx_lock(&np->n_mtx); 793 1.1 dholland KASSERT((np->n_directio_opens > 0), 794 1.1 dholland ("nfs_close: unexpectedly value (0) of n_directio_opens\n")); 795 1.1 dholland np->n_directio_opens--; 796 1.1 dholland if (np->n_directio_opens == 0) 797 1.1 dholland np->n_flag &= ~NNONCACHE; 798 1.1 dholland mtx_unlock(&np->n_mtx); 799 1.1 dholland } 800 1.1 dholland if (localcred) 801 1.1 dholland NFSFREECRED(cred); 802 1.1 dholland return (error); 803 1.1 dholland } 804 1.1 dholland 805 1.1 dholland /* 806 1.1 dholland * nfs getattr call from vfs. 807 1.1 dholland */ 808 1.1 dholland static int 809 1.1 dholland nfs_getattr(struct vop_getattr_args *ap) 810 1.1 dholland { 811 1.1 dholland struct vnode *vp = ap->a_vp; 812 1.1 dholland struct thread *td = curthread; /* XXX */ 813 1.1 dholland struct nfsnode *np = VTONFS(vp); 814 1.1 dholland int error = 0; 815 1.1 dholland struct nfsvattr nfsva; 816 1.1 dholland struct vattr *vap = ap->a_vap; 817 1.1 dholland struct vattr vattr; 818 1.1 dholland 819 1.1 dholland /* 820 1.1 dholland * Update local times for special files. 821 1.1 dholland */ 822 1.1 dholland mtx_lock(&np->n_mtx); 823 1.1 dholland if (np->n_flag & (NACC | NUPD)) 824 1.1 dholland np->n_flag |= NCHG; 825 1.1 dholland mtx_unlock(&np->n_mtx); 826 1.1 dholland /* 827 1.1 dholland * First look in the cache. 828 1.1 dholland */ 829 1.1 dholland if (ncl_getattrcache(vp, &vattr) == 0) { 830 1.1 dholland vap->va_type = vattr.va_type; 831 1.1 dholland vap->va_mode = vattr.va_mode; 832 1.1 dholland vap->va_nlink = vattr.va_nlink; 833 1.1 dholland vap->va_uid = vattr.va_uid; 834 1.1 dholland vap->va_gid = vattr.va_gid; 835 1.1 dholland vap->va_fsid = vattr.va_fsid; 836 1.1 dholland vap->va_fileid = vattr.va_fileid; 837 1.1 dholland vap->va_size = vattr.va_size; 838 1.1 dholland vap->va_blocksize = vattr.va_blocksize; 839 1.1 dholland vap->va_atime = vattr.va_atime; 840 1.1 dholland vap->va_mtime = vattr.va_mtime; 841 1.1 dholland vap->va_ctime = vattr.va_ctime; 842 1.1 dholland vap->va_gen = vattr.va_gen; 843 1.1 dholland vap->va_flags = vattr.va_flags; 844 1.1 dholland vap->va_rdev = vattr.va_rdev; 845 1.1 dholland vap->va_bytes = vattr.va_bytes; 846 1.1 dholland vap->va_filerev = vattr.va_filerev; 847 1.1 dholland /* 848 1.1 dholland * Get the local modify time for the case of a write 849 1.1 dholland * delegation. 850 1.1 dholland */ 851 1.1 dholland nfscl_deleggetmodtime(vp, &vap->va_mtime); 852 1.1 dholland return (0); 853 1.1 dholland } 854 1.1 dholland 855 1.1 dholland if (NFS_ISV34(vp) && nfs_prime_access_cache && 856 1.1 dholland nfsaccess_cache_timeout > 0) { 857 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.accesscache_misses); 858 1.1 dholland nfs34_access_otw(vp, NFSACCESS_ALL, td, ap->a_cred, NULL); 859 1.1 dholland if (ncl_getattrcache(vp, ap->a_vap) == 0) { 860 1.1 dholland nfscl_deleggetmodtime(vp, &ap->a_vap->va_mtime); 861 1.1 dholland return (0); 862 1.1 dholland } 863 1.1 dholland } 864 1.1 dholland error = nfsrpc_getattr(vp, ap->a_cred, td, &nfsva, NULL); 865 1.1 dholland if (!error) 866 1.1 dholland error = nfscl_loadattrcache(&vp, &nfsva, vap, NULL, 0, 0); 867 1.1 dholland if (!error) { 868 1.1 dholland /* 869 1.1 dholland * Get the local modify time for the case of a write 870 1.1 dholland * delegation. 871 1.1 dholland */ 872 1.1 dholland nfscl_deleggetmodtime(vp, &vap->va_mtime); 873 1.1 dholland } else if (NFS_ISV4(vp)) { 874 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 875 1.1 dholland } 876 1.1 dholland return (error); 877 1.1 dholland } 878 1.1 dholland 879 1.1 dholland /* 880 1.1 dholland * nfs setattr call. 881 1.1 dholland */ 882 1.1 dholland static int 883 1.1 dholland nfs_setattr(struct vop_setattr_args *ap) 884 1.1 dholland { 885 1.1 dholland struct vnode *vp = ap->a_vp; 886 1.1 dholland struct nfsnode *np = VTONFS(vp); 887 1.1 dholland struct thread *td = curthread; /* XXX */ 888 1.1 dholland struct vattr *vap = ap->a_vap; 889 1.1 dholland int error = 0; 890 1.1 dholland u_quad_t tsize; 891 1.1 dholland 892 1.1 dholland #ifndef nolint 893 1.1 dholland tsize = (u_quad_t)0; 894 1.1 dholland #endif 895 1.1 dholland 896 1.1 dholland /* 897 1.1 dholland * Setting of flags and marking of atimes are not supported. 898 1.1 dholland */ 899 1.1 dholland if (vap->va_flags != VNOVAL) 900 1.1 dholland return (EOPNOTSUPP); 901 1.1 dholland 902 1.1 dholland /* 903 1.1 dholland * Disallow write attempts if the filesystem is mounted read-only. 904 1.1 dholland */ 905 1.1 dholland if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL || 906 1.1 dholland vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 907 1.1 dholland vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && 908 1.1 dholland (vp->v_mount->mnt_flag & MNT_RDONLY)) 909 1.1 dholland return (EROFS); 910 1.1 dholland if (vap->va_size != VNOVAL) { 911 1.1 dholland switch (vp->v_type) { 912 1.1 dholland case VDIR: 913 1.1 dholland return (EISDIR); 914 1.1 dholland case VCHR: 915 1.1 dholland case VBLK: 916 1.1 dholland case VSOCK: 917 1.1 dholland case VFIFO: 918 1.1 dholland if (vap->va_mtime.tv_sec == VNOVAL && 919 1.1 dholland vap->va_atime.tv_sec == VNOVAL && 920 1.1 dholland vap->va_mode == (mode_t)VNOVAL && 921 1.1 dholland vap->va_uid == (uid_t)VNOVAL && 922 1.1 dholland vap->va_gid == (gid_t)VNOVAL) 923 1.1 dholland return (0); 924 1.1 dholland vap->va_size = VNOVAL; 925 1.1 dholland break; 926 1.1 dholland default: 927 1.1 dholland /* 928 1.1 dholland * Disallow write attempts if the filesystem is 929 1.1 dholland * mounted read-only. 930 1.1 dholland */ 931 1.1 dholland if (vp->v_mount->mnt_flag & MNT_RDONLY) 932 1.1 dholland return (EROFS); 933 1.1 dholland /* 934 1.1 dholland * We run vnode_pager_setsize() early (why?), 935 1.1 dholland * we must set np->n_size now to avoid vinvalbuf 936 1.1 dholland * V_SAVE races that might setsize a lower 937 1.1 dholland * value. 938 1.1 dholland */ 939 1.1 dholland mtx_lock(&np->n_mtx); 940 1.1 dholland tsize = np->n_size; 941 1.1 dholland mtx_unlock(&np->n_mtx); 942 1.1 dholland error = ncl_meta_setsize(vp, ap->a_cred, td, 943 1.1 dholland vap->va_size); 944 1.1 dholland mtx_lock(&np->n_mtx); 945 1.1 dholland if (np->n_flag & NMODIFIED) { 946 1.1 dholland tsize = np->n_size; 947 1.1 dholland mtx_unlock(&np->n_mtx); 948 1.1 dholland if (vap->va_size == 0) 949 1.1 dholland error = ncl_vinvalbuf(vp, 0, td, 1); 950 1.1 dholland else 951 1.1 dholland error = ncl_vinvalbuf(vp, V_SAVE, td, 1); 952 1.1 dholland if (error) { 953 1.1 dholland vnode_pager_setsize(vp, tsize); 954 1.1 dholland return (error); 955 1.1 dholland } 956 1.1 dholland /* 957 1.1 dholland * Call nfscl_delegmodtime() to set the modify time 958 1.1 dholland * locally, as required. 959 1.1 dholland */ 960 1.1 dholland nfscl_delegmodtime(vp); 961 1.1 dholland } else 962 1.1 dholland mtx_unlock(&np->n_mtx); 963 1.1 dholland /* 964 1.1 dholland * np->n_size has already been set to vap->va_size 965 1.1 dholland * in ncl_meta_setsize(). We must set it again since 966 1.1 dholland * nfs_loadattrcache() could be called through 967 1.1 dholland * ncl_meta_setsize() and could modify np->n_size. 968 1.1 dholland */ 969 1.1 dholland mtx_lock(&np->n_mtx); 970 1.1 dholland np->n_vattr.na_size = np->n_size = vap->va_size; 971 1.1 dholland mtx_unlock(&np->n_mtx); 972 1.3 pgoyette } 973 1.1 dholland } else { 974 1.1 dholland mtx_lock(&np->n_mtx); 975 1.1 dholland if ((vap->va_mtime.tv_sec != VNOVAL || vap->va_atime.tv_sec != VNOVAL) && 976 1.1 dholland (np->n_flag & NMODIFIED) && vp->v_type == VREG) { 977 1.1 dholland mtx_unlock(&np->n_mtx); 978 1.1 dholland if ((error = ncl_vinvalbuf(vp, V_SAVE, td, 1)) != 0 && 979 1.1 dholland (error == EINTR || error == EIO)) 980 1.1 dholland return (error); 981 1.1 dholland } else 982 1.1 dholland mtx_unlock(&np->n_mtx); 983 1.1 dholland } 984 1.1 dholland error = nfs_setattrrpc(vp, vap, ap->a_cred, td); 985 1.1 dholland if (error && vap->va_size != VNOVAL) { 986 1.1 dholland mtx_lock(&np->n_mtx); 987 1.1 dholland np->n_size = np->n_vattr.na_size = tsize; 988 1.1 dholland vnode_pager_setsize(vp, tsize); 989 1.1 dholland mtx_unlock(&np->n_mtx); 990 1.1 dholland } 991 1.1 dholland return (error); 992 1.1 dholland } 993 1.1 dholland 994 1.1 dholland /* 995 1.1 dholland * Do an nfs setattr rpc. 996 1.1 dholland */ 997 1.1 dholland static int 998 1.1 dholland nfs_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred, 999 1.1 dholland struct thread *td) 1000 1.1 dholland { 1001 1.1 dholland struct nfsnode *np = VTONFS(vp); 1002 1.1 dholland int error, ret, attrflag, i; 1003 1.1 dholland struct nfsvattr nfsva; 1004 1.1 dholland 1005 1.1 dholland if (NFS_ISV34(vp)) { 1006 1.1 dholland mtx_lock(&np->n_mtx); 1007 1.1 dholland for (i = 0; i < NFS_ACCESSCACHESIZE; i++) 1008 1.1 dholland np->n_accesscache[i].stamp = 0; 1009 1.1 dholland np->n_flag |= NDELEGMOD; 1010 1.1 dholland mtx_unlock(&np->n_mtx); 1011 1.1 dholland KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp); 1012 1.1 dholland } 1013 1.1 dholland error = nfsrpc_setattr(vp, vap, NULL, cred, td, &nfsva, &attrflag, 1014 1.1 dholland NULL); 1015 1.1 dholland if (attrflag) { 1016 1.1 dholland ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1017 1.1 dholland if (ret && !error) 1018 1.1 dholland error = ret; 1019 1.1 dholland } 1020 1.1 dholland if (error && NFS_ISV4(vp)) 1021 1.1 dholland error = nfscl_maperr(td, error, vap->va_uid, vap->va_gid); 1022 1.1 dholland return (error); 1023 1.1 dholland } 1024 1.1 dholland 1025 1.1 dholland /* 1026 1.1 dholland * nfs lookup call, one step at a time... 1027 1.1 dholland * First look in cache 1028 1.1 dholland * If not found, unlock the directory nfsnode and do the rpc 1029 1.1 dholland */ 1030 1.1 dholland static int 1031 1.1 dholland nfs_lookup(struct vop_lookup_args *ap) 1032 1.1 dholland { 1033 1.1 dholland struct componentname *cnp = ap->a_cnp; 1034 1.1 dholland struct vnode *dvp = ap->a_dvp; 1035 1.1 dholland struct vnode **vpp = ap->a_vpp; 1036 1.1 dholland struct mount *mp = dvp->v_mount; 1037 1.1 dholland int flags = cnp->cn_flags; 1038 1.1 dholland struct vnode *newvp; 1039 1.1 dholland struct nfsmount *nmp; 1040 1.1 dholland struct nfsnode *np, *newnp; 1041 1.1 dholland int error = 0, attrflag, dattrflag, ltype, ncticks; 1042 1.1 dholland struct thread *td = cnp->cn_thread; 1043 1.1 dholland struct nfsfh *nfhp; 1044 1.1 dholland struct nfsvattr dnfsva, nfsva; 1045 1.1 dholland struct vattr vattr; 1046 1.1 dholland struct timespec nctime; 1047 1.1 dholland 1048 1.1 dholland *vpp = NULLVP; 1049 1.1 dholland if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && 1050 1.1 dholland (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 1051 1.1 dholland return (EROFS); 1052 1.1 dholland if (dvp->v_type != VDIR) 1053 1.1 dholland return (ENOTDIR); 1054 1.1 dholland nmp = VFSTONFS(mp); 1055 1.1 dholland np = VTONFS(dvp); 1056 1.1 dholland 1057 1.1 dholland /* For NFSv4, wait until any remove is done. */ 1058 1.1 dholland mtx_lock(&np->n_mtx); 1059 1.1 dholland while (NFSHASNFSV4(nmp) && (np->n_flag & NREMOVEINPROG)) { 1060 1.1 dholland np->n_flag |= NREMOVEWANT; 1061 1.1 dholland (void) msleep((caddr_t)np, &np->n_mtx, PZERO, "nfslkup", 0); 1062 1.1 dholland } 1063 1.1 dholland mtx_unlock(&np->n_mtx); 1064 1.1 dholland 1065 1.1 dholland if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1066 1.1 dholland return (error); 1067 1.1 dholland error = cache_lookup(dvp, vpp, cnp, &nctime, &ncticks); 1068 1.1 dholland if (error > 0 && error != ENOENT) 1069 1.1 dholland return (error); 1070 1.1 dholland if (error == -1) { 1071 1.1 dholland /* 1072 1.1 dholland * Lookups of "." are special and always return the 1073 1.1 dholland * current directory. cache_lookup() already handles 1074 1.1 dholland * associated locking bookkeeping, etc. 1075 1.1 dholland */ 1076 1.1 dholland if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 1077 1.1 dholland /* XXX: Is this really correct? */ 1078 1.1 dholland if (cnp->cn_nameiop != LOOKUP && 1079 1.1 dholland (flags & ISLASTCN)) 1080 1.1 dholland cnp->cn_flags |= SAVENAME; 1081 1.1 dholland return (0); 1082 1.1 dholland } 1083 1.1 dholland 1084 1.1 dholland /* 1085 1.1 dholland * We only accept a positive hit in the cache if the 1086 1.1 dholland * change time of the file matches our cached copy. 1087 1.1 dholland * Otherwise, we discard the cache entry and fallback 1088 1.1 dholland * to doing a lookup RPC. We also only trust cache 1089 1.1 dholland * entries for less than nm_nametimeo seconds. 1090 1.1 dholland * 1091 1.1 dholland * To better handle stale file handles and attributes, 1092 1.1 dholland * clear the attribute cache of this node if it is a 1093 1.1 dholland * leaf component, part of an open() call, and not 1094 1.1 dholland * locally modified before fetching the attributes. 1095 1.1 dholland * This should allow stale file handles to be detected 1096 1.1 dholland * here where we can fall back to a LOOKUP RPC to 1097 1.1 dholland * recover rather than having nfs_open() detect the 1098 1.1 dholland * stale file handle and failing open(2) with ESTALE. 1099 1.1 dholland */ 1100 1.1 dholland newvp = *vpp; 1101 1.1 dholland newnp = VTONFS(newvp); 1102 1.1 dholland if (!(nmp->nm_flag & NFSMNT_NOCTO) && 1103 1.1 dholland (flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) && 1104 1.1 dholland !(newnp->n_flag & NMODIFIED)) { 1105 1.1 dholland mtx_lock(&newnp->n_mtx); 1106 1.1 dholland newnp->n_attrstamp = 0; 1107 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp); 1108 1.1 dholland mtx_unlock(&newnp->n_mtx); 1109 1.1 dholland } 1110 1.1 dholland if (nfscl_nodeleg(newvp, 0) == 0 || 1111 1.1 dholland ((u_int)(ticks - ncticks) < (nmp->nm_nametimeo * hz) && 1112 1.1 dholland VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 && 1113 1.1 dholland timespeccmp(&vattr.va_ctime, &nctime, ==))) { 1114 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits); 1115 1.1 dholland if (cnp->cn_nameiop != LOOKUP && 1116 1.1 dholland (flags & ISLASTCN)) 1117 1.1 dholland cnp->cn_flags |= SAVENAME; 1118 1.1 dholland return (0); 1119 1.1 dholland } 1120 1.1 dholland cache_purge(newvp); 1121 1.1 dholland if (dvp != newvp) 1122 1.1 dholland vput(newvp); 1123 1.1 dholland else 1124 1.1 dholland vrele(newvp); 1125 1.1 dholland *vpp = NULLVP; 1126 1.1 dholland } else if (error == ENOENT) { 1127 1.1 dholland if (dvp->v_iflag & VI_DOOMED) 1128 1.1 dholland return (ENOENT); 1129 1.1 dholland /* 1130 1.1 dholland * We only accept a negative hit in the cache if the 1131 1.1 dholland * modification time of the parent directory matches 1132 1.1 dholland * the cached copy in the name cache entry. 1133 1.1 dholland * Otherwise, we discard all of the negative cache 1134 1.1 dholland * entries for this directory. We also only trust 1135 1.1 dholland * negative cache entries for up to nm_negnametimeo 1136 1.1 dholland * seconds. 1137 1.1 dholland */ 1138 1.1 dholland if ((u_int)(ticks - ncticks) < (nmp->nm_negnametimeo * hz) && 1139 1.1 dholland VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 && 1140 1.1 dholland timespeccmp(&vattr.va_mtime, &nctime, ==)) { 1141 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.lookupcache_hits); 1142 1.1 dholland return (ENOENT); 1143 1.1 dholland } 1144 1.1 dholland cache_purge_negative(dvp); 1145 1.1 dholland } 1146 1.1 dholland 1147 1.1 dholland error = 0; 1148 1.1 dholland newvp = NULLVP; 1149 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.lookupcache_misses); 1150 1.1 dholland error = nfsrpc_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 1151 1.1 dholland cnp->cn_cred, td, &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 1152 1.1 dholland NULL); 1153 1.1 dholland if (dattrflag) 1154 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1155 1.1 dholland if (error) { 1156 1.1 dholland if (newvp != NULLVP) { 1157 1.1 dholland vput(newvp); 1158 1.1 dholland *vpp = NULLVP; 1159 1.1 dholland } 1160 1.1 dholland 1161 1.1 dholland if (error != ENOENT) { 1162 1.1 dholland if (NFS_ISV4(dvp)) 1163 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, 1164 1.1 dholland (gid_t)0); 1165 1.1 dholland return (error); 1166 1.1 dholland } 1167 1.1 dholland 1168 1.1 dholland /* The requested file was not found. */ 1169 1.1 dholland if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 1170 1.1 dholland (flags & ISLASTCN)) { 1171 1.1 dholland /* 1172 1.1 dholland * XXX: UFS does a full VOP_ACCESS(dvp, 1173 1.1 dholland * VWRITE) here instead of just checking 1174 1.1 dholland * MNT_RDONLY. 1175 1.1 dholland */ 1176 1.1 dholland if (mp->mnt_flag & MNT_RDONLY) 1177 1.1 dholland return (EROFS); 1178 1.1 dholland cnp->cn_flags |= SAVENAME; 1179 1.1 dholland return (EJUSTRETURN); 1180 1.1 dholland } 1181 1.1 dholland 1182 1.3 pgoyette if ((cnp->cn_flags & MAKEENTRY) != 0 && dattrflag) { 1183 1.1 dholland /* 1184 1.1 dholland * Cache the modification time of the parent 1185 1.1 dholland * directory from the post-op attributes in 1186 1.1 dholland * the name cache entry. The negative cache 1187 1.1 dholland * entry will be ignored once the directory 1188 1.1 dholland * has changed. Don't bother adding the entry 1189 1.1 dholland * if the directory has already changed. 1190 1.1 dholland */ 1191 1.1 dholland mtx_lock(&np->n_mtx); 1192 1.1 dholland if (timespeccmp(&np->n_vattr.na_mtime, 1193 1.1 dholland &dnfsva.na_mtime, ==)) { 1194 1.1 dholland mtx_unlock(&np->n_mtx); 1195 1.1 dholland cache_enter_time(dvp, NULL, cnp, 1196 1.1 dholland &dnfsva.na_mtime, NULL); 1197 1.1 dholland } else 1198 1.1 dholland mtx_unlock(&np->n_mtx); 1199 1.1 dholland } 1200 1.1 dholland return (ENOENT); 1201 1.1 dholland } 1202 1.1 dholland 1203 1.1 dholland /* 1204 1.1 dholland * Handle RENAME case... 1205 1.1 dholland */ 1206 1.1 dholland if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) { 1207 1.1 dholland if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) { 1208 1.1 dholland FREE((caddr_t)nfhp, M_NFSFH); 1209 1.1 dholland return (EISDIR); 1210 1.1 dholland } 1211 1.1 dholland error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL, 1212 1.1 dholland LK_EXCLUSIVE); 1213 1.1 dholland if (error) 1214 1.1 dholland return (error); 1215 1.1 dholland newvp = NFSTOV(np); 1216 1.1 dholland if (attrflag) 1217 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1218 1.1 dholland 0, 1); 1219 1.1 dholland *vpp = newvp; 1220 1.1 dholland cnp->cn_flags |= SAVENAME; 1221 1.1 dholland return (0); 1222 1.1 dholland } 1223 1.1 dholland 1224 1.1 dholland if (flags & ISDOTDOT) { 1225 1.1 dholland ltype = NFSVOPISLOCKED(dvp); 1226 1.1 dholland error = vfs_busy(mp, MBF_NOWAIT); 1227 1.1 dholland if (error != 0) { 1228 1.1 dholland vfs_ref(mp); 1229 1.1 dholland NFSVOPUNLOCK(dvp, 0); 1230 1.1 dholland error = vfs_busy(mp, 0); 1231 1.1 dholland NFSVOPLOCK(dvp, ltype | LK_RETRY); 1232 1.1 dholland vfs_rel(mp); 1233 1.1 dholland if (error == 0 && (dvp->v_iflag & VI_DOOMED)) { 1234 1.1 dholland vfs_unbusy(mp); 1235 1.1 dholland error = ENOENT; 1236 1.1 dholland } 1237 1.1 dholland if (error != 0) 1238 1.1 dholland return (error); 1239 1.1 dholland } 1240 1.1 dholland NFSVOPUNLOCK(dvp, 0); 1241 1.1 dholland error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL, 1242 1.1 dholland cnp->cn_lkflags); 1243 1.1 dholland if (error == 0) 1244 1.1 dholland newvp = NFSTOV(np); 1245 1.1 dholland vfs_unbusy(mp); 1246 1.1 dholland if (newvp != dvp) 1247 1.1 dholland NFSVOPLOCK(dvp, ltype | LK_RETRY); 1248 1.1 dholland if (dvp->v_iflag & VI_DOOMED) { 1249 1.1 dholland if (error == 0) { 1250 1.1 dholland if (newvp == dvp) 1251 1.1 dholland vrele(newvp); 1252 1.1 dholland else 1253 1.1 dholland vput(newvp); 1254 1.1 dholland } 1255 1.1 dholland error = ENOENT; 1256 1.1 dholland } 1257 1.1 dholland if (error != 0) 1258 1.1 dholland return (error); 1259 1.1 dholland if (attrflag) 1260 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1261 1.1 dholland 0, 1); 1262 1.1 dholland } else if (NFS_CMPFH(np, nfhp->nfh_fh, nfhp->nfh_len)) { 1263 1.1 dholland FREE((caddr_t)nfhp, M_NFSFH); 1264 1.1 dholland VREF(dvp); 1265 1.1 dholland newvp = dvp; 1266 1.1 dholland if (attrflag) 1267 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1268 1.1 dholland 0, 1); 1269 1.1 dholland } else { 1270 1.1 dholland error = nfscl_nget(mp, dvp, nfhp, cnp, td, &np, NULL, 1271 1.1 dholland cnp->cn_lkflags); 1272 1.1 dholland if (error) 1273 1.1 dholland return (error); 1274 1.1 dholland newvp = NFSTOV(np); 1275 1.1 dholland if (attrflag) 1276 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1277 1.1 dholland 0, 1); 1278 1.1 dholland else if ((flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) && 1279 1.1 dholland !(np->n_flag & NMODIFIED)) { 1280 1.1 dholland /* 1281 1.1 dholland * Flush the attribute cache when opening a 1282 1.1 dholland * leaf node to ensure that fresh attributes 1283 1.1 dholland * are fetched in nfs_open() since we did not 1284 1.1 dholland * fetch attributes from the LOOKUP reply. 1285 1.1 dholland */ 1286 1.1 dholland mtx_lock(&np->n_mtx); 1287 1.1 dholland np->n_attrstamp = 0; 1288 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp); 1289 1.1 dholland mtx_unlock(&np->n_mtx); 1290 1.1 dholland } 1291 1.1 dholland } 1292 1.1 dholland if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) 1293 1.1 dholland cnp->cn_flags |= SAVENAME; 1294 1.1 dholland if ((cnp->cn_flags & MAKEENTRY) && 1295 1.1 dholland (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)) && 1296 1.1 dholland attrflag != 0 && (newvp->v_type != VDIR || dattrflag != 0)) 1297 1.1 dholland cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, 1298 1.1 dholland newvp->v_type != VDIR ? NULL : &dnfsva.na_ctime); 1299 1.1 dholland *vpp = newvp; 1300 1.1 dholland return (0); 1301 1.1 dholland } 1302 1.1 dholland 1303 1.1 dholland /* 1304 1.1 dholland * nfs read call. 1305 1.1 dholland * Just call ncl_bioread() to do the work. 1306 1.1 dholland */ 1307 1.1 dholland static int 1308 1.1 dholland nfs_read(struct vop_read_args *ap) 1309 1.1 dholland { 1310 1.1 dholland struct vnode *vp = ap->a_vp; 1311 1.1 dholland 1312 1.1 dholland switch (vp->v_type) { 1313 1.1 dholland case VREG: 1314 1.1 dholland return (ncl_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); 1315 1.1 dholland case VDIR: 1316 1.1 dholland return (EISDIR); 1317 1.1 dholland default: 1318 1.1 dholland return (EOPNOTSUPP); 1319 1.1 dholland } 1320 1.1 dholland } 1321 1.1 dholland 1322 1.1 dholland /* 1323 1.1 dholland * nfs readlink call 1324 1.1 dholland */ 1325 1.1 dholland static int 1326 1.1 dholland nfs_readlink(struct vop_readlink_args *ap) 1327 1.1 dholland { 1328 1.1 dholland struct vnode *vp = ap->a_vp; 1329 1.1 dholland 1330 1.1 dholland if (vp->v_type != VLNK) 1331 1.1 dholland return (EINVAL); 1332 1.1 dholland return (ncl_bioread(vp, ap->a_uio, 0, ap->a_cred)); 1333 1.1 dholland } 1334 1.1 dholland 1335 1.1 dholland /* 1336 1.1 dholland * Do a readlink rpc. 1337 1.1 dholland * Called by ncl_doio() from below the buffer cache. 1338 1.1 dholland */ 1339 1.1 dholland int 1340 1.1 dholland ncl_readlinkrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) 1341 1.1 dholland { 1342 1.1 dholland int error, ret, attrflag; 1343 1.1 dholland struct nfsvattr nfsva; 1344 1.1 dholland 1345 1.1 dholland error = nfsrpc_readlink(vp, uiop, cred, uiop->uio_td, &nfsva, 1346 1.1 dholland &attrflag, NULL); 1347 1.1 dholland if (attrflag) { 1348 1.1 dholland ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1349 1.1 dholland if (ret && !error) 1350 1.1 dholland error = ret; 1351 1.1 dholland } 1352 1.1 dholland if (error && NFS_ISV4(vp)) 1353 1.1 dholland error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); 1354 1.1 dholland return (error); 1355 1.1 dholland } 1356 1.1 dholland 1357 1.1 dholland /* 1358 1.1 dholland * nfs read rpc call 1359 1.1 dholland * Ditto above 1360 1.1 dholland */ 1361 1.1 dholland int 1362 1.1 dholland ncl_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) 1363 1.1 dholland { 1364 1.1 dholland int error, ret, attrflag; 1365 1.1 dholland struct nfsvattr nfsva; 1366 1.1 dholland struct nfsmount *nmp; 1367 1.1 dholland 1368 1.1 dholland nmp = VFSTONFS(vnode_mount(vp)); 1369 1.1 dholland error = EIO; 1370 1.1 dholland attrflag = 0; 1371 1.1 dholland if (NFSHASPNFS(nmp)) 1372 1.1 dholland error = nfscl_doiods(vp, uiop, NULL, NULL, 1373 1.1 dholland NFSV4OPEN_ACCESSREAD, cred, uiop->uio_td); 1374 1.1 dholland NFSCL_DEBUG(4, "readrpc: aft doiods=%d\n", error); 1375 1.1 dholland if (error != 0) 1376 1.1 dholland error = nfsrpc_read(vp, uiop, cred, uiop->uio_td, &nfsva, 1377 1.1 dholland &attrflag, NULL); 1378 1.1 dholland if (attrflag) { 1379 1.1 dholland ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1380 1.1 dholland if (ret && !error) 1381 1.1 dholland error = ret; 1382 1.1 dholland } 1383 1.1 dholland if (error && NFS_ISV4(vp)) 1384 1.1 dholland error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); 1385 1.1 dholland return (error); 1386 1.1 dholland } 1387 1.1 dholland 1388 1.1 dholland /* 1389 1.1 dholland * nfs write call 1390 1.1 dholland */ 1391 1.1 dholland int 1392 1.1 dholland ncl_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, 1393 1.1 dholland int *iomode, int *must_commit, int called_from_strategy) 1394 1.1 dholland { 1395 1.1 dholland struct nfsvattr nfsva; 1396 1.1 dholland int error, attrflag, ret; 1397 1.1 dholland struct nfsmount *nmp; 1398 1.1 dholland 1399 1.1 dholland nmp = VFSTONFS(vnode_mount(vp)); 1400 1.1 dholland error = EIO; 1401 1.1 dholland attrflag = 0; 1402 1.1 dholland if (NFSHASPNFS(nmp)) 1403 1.1 dholland error = nfscl_doiods(vp, uiop, iomode, must_commit, 1404 1.1 dholland NFSV4OPEN_ACCESSWRITE, cred, uiop->uio_td); 1405 1.1 dholland NFSCL_DEBUG(4, "writerpc: aft doiods=%d\n", error); 1406 1.1 dholland if (error != 0) 1407 1.1 dholland error = nfsrpc_write(vp, uiop, iomode, must_commit, cred, 1408 1.1 dholland uiop->uio_td, &nfsva, &attrflag, NULL, 1409 1.1 dholland called_from_strategy); 1410 1.1 dholland if (attrflag) { 1411 1.1 dholland if (VTONFS(vp)->n_flag & ND_NFSV4) 1412 1.1 dholland ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 1, 1413 1.1 dholland 1); 1414 1.1 dholland else 1415 1.1 dholland ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1416 1.1 dholland 1); 1417 1.1 dholland if (ret && !error) 1418 1.1 dholland error = ret; 1419 1.1 dholland } 1420 1.1 dholland if (DOINGASYNC(vp)) 1421 1.1 dholland *iomode = NFSWRITE_FILESYNC; 1422 1.1 dholland if (error && NFS_ISV4(vp)) 1423 1.1 dholland error = nfscl_maperr(uiop->uio_td, error, (uid_t)0, (gid_t)0); 1424 1.1 dholland return (error); 1425 1.1 dholland } 1426 1.1 dholland 1427 1.1 dholland /* 1428 1.1 dholland * nfs mknod rpc 1429 1.1 dholland * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1430 1.1 dholland * mode set to specify the file type and the size field for rdev. 1431 1.1 dholland */ 1432 1.1 dholland static int 1433 1.1 dholland nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 1434 1.1 dholland struct vattr *vap) 1435 1.1 dholland { 1436 1.1 dholland struct nfsvattr nfsva, dnfsva; 1437 1.1 dholland struct vnode *newvp = NULL; 1438 1.1 dholland struct nfsnode *np = NULL, *dnp; 1439 1.1 dholland struct nfsfh *nfhp; 1440 1.1 dholland struct vattr vattr; 1441 1.1 dholland int error = 0, attrflag, dattrflag; 1442 1.1 dholland u_int32_t rdev; 1443 1.1 dholland 1444 1.1 dholland if (vap->va_type == VCHR || vap->va_type == VBLK) 1445 1.1 dholland rdev = vap->va_rdev; 1446 1.1 dholland else if (vap->va_type == VFIFO || vap->va_type == VSOCK) 1447 1.1 dholland rdev = 0xffffffff; 1448 1.1 dholland else 1449 1.1 dholland return (EOPNOTSUPP); 1450 1.1 dholland if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 1451 1.1 dholland return (error); 1452 1.1 dholland error = nfsrpc_mknod(dvp, cnp->cn_nameptr, cnp->cn_namelen, vap, 1453 1.1 dholland rdev, vap->va_type, cnp->cn_cred, cnp->cn_thread, &dnfsva, 1454 1.1 dholland &nfsva, &nfhp, &attrflag, &dattrflag, NULL); 1455 1.1 dholland if (!error) { 1456 1.1 dholland if (!nfhp) 1457 1.1 dholland (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, 1458 1.1 dholland cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, 1459 1.1 dholland &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 1460 1.1 dholland NULL); 1461 1.1 dholland if (nfhp) 1462 1.1 dholland error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, 1463 1.1 dholland cnp->cn_thread, &np, NULL, LK_EXCLUSIVE); 1464 1.1 dholland } 1465 1.1 dholland if (dattrflag) 1466 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1467 1.1 dholland if (!error) { 1468 1.1 dholland newvp = NFSTOV(np); 1469 1.1 dholland if (attrflag != 0) { 1470 1.1 dholland error = nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1471 1.1 dholland 0, 1); 1472 1.1 dholland if (error != 0) 1473 1.1 dholland vput(newvp); 1474 1.1 dholland } 1475 1.1 dholland } 1476 1.1 dholland if (!error) { 1477 1.1 dholland *vpp = newvp; 1478 1.1 dholland } else if (NFS_ISV4(dvp)) { 1479 1.1 dholland error = nfscl_maperr(cnp->cn_thread, error, vap->va_uid, 1480 1.1 dholland vap->va_gid); 1481 1.1 dholland } 1482 1.1 dholland dnp = VTONFS(dvp); 1483 1.1 dholland mtx_lock(&dnp->n_mtx); 1484 1.1 dholland dnp->n_flag |= NMODIFIED; 1485 1.1 dholland if (!dattrflag) { 1486 1.1 dholland dnp->n_attrstamp = 0; 1487 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 1488 1.1 dholland } 1489 1.1 dholland mtx_unlock(&dnp->n_mtx); 1490 1.1 dholland return (error); 1491 1.1 dholland } 1492 1.1 dholland 1493 1.1 dholland /* 1494 1.1 dholland * nfs mknod vop 1495 1.1 dholland * just call nfs_mknodrpc() to do the work. 1496 1.1 dholland */ 1497 1.1 dholland /* ARGSUSED */ 1498 1.1 dholland static int 1499 1.1 dholland nfs_mknod(struct vop_mknod_args *ap) 1500 1.1 dholland { 1501 1.1 dholland return (nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap)); 1502 1.1 dholland } 1503 1.1 dholland 1504 1.1 dholland static struct mtx nfs_cverf_mtx; 1505 1.1 dholland MTX_SYSINIT(nfs_cverf_mtx, &nfs_cverf_mtx, "NFS create verifier mutex", 1506 1.1 dholland MTX_DEF); 1507 1.1 dholland 1508 1.1 dholland static nfsquad_t 1509 1.1 dholland nfs_get_cverf(void) 1510 1.1 dholland { 1511 1.1 dholland static nfsquad_t cverf; 1512 1.1 dholland nfsquad_t ret; 1513 1.1 dholland static int cverf_initialized = 0; 1514 1.1 dholland 1515 1.1 dholland mtx_lock(&nfs_cverf_mtx); 1516 1.1 dholland if (cverf_initialized == 0) { 1517 1.1 dholland cverf.lval[0] = arc4random(); 1518 1.1 dholland cverf.lval[1] = arc4random(); 1519 1.1 dholland cverf_initialized = 1; 1520 1.1 dholland } else 1521 1.1 dholland cverf.qval++; 1522 1.1 dholland ret = cverf; 1523 1.1 dholland mtx_unlock(&nfs_cverf_mtx); 1524 1.1 dholland 1525 1.1 dholland return (ret); 1526 1.1 dholland } 1527 1.1 dholland 1528 1.1 dholland /* 1529 1.1 dholland * nfs file create call 1530 1.1 dholland */ 1531 1.1 dholland static int 1532 1.1 dholland nfs_create(struct vop_create_args *ap) 1533 1.1 dholland { 1534 1.1 dholland struct vnode *dvp = ap->a_dvp; 1535 1.1 dholland struct vattr *vap = ap->a_vap; 1536 1.1 dholland struct componentname *cnp = ap->a_cnp; 1537 1.1 dholland struct nfsnode *np = NULL, *dnp; 1538 1.1 dholland struct vnode *newvp = NULL; 1539 1.1 dholland struct nfsmount *nmp; 1540 1.1 dholland struct nfsvattr dnfsva, nfsva; 1541 1.1 dholland struct nfsfh *nfhp; 1542 1.1 dholland nfsquad_t cverf; 1543 1.1 dholland int error = 0, attrflag, dattrflag, fmode = 0; 1544 1.1 dholland struct vattr vattr; 1545 1.1 dholland 1546 1.1 dholland /* 1547 1.1 dholland * Oops, not for me.. 1548 1.1 dholland */ 1549 1.1 dholland if (vap->va_type == VSOCK) 1550 1.1 dholland return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); 1551 1.1 dholland 1552 1.1 dholland if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 1553 1.1 dholland return (error); 1554 1.1 dholland if (vap->va_vaflags & VA_EXCLUSIVE) 1555 1.1 dholland fmode |= O_EXCL; 1556 1.1 dholland dnp = VTONFS(dvp); 1557 1.1 dholland nmp = VFSTONFS(vnode_mount(dvp)); 1558 1.1 dholland again: 1559 1.1 dholland /* For NFSv4, wait until any remove is done. */ 1560 1.1 dholland mtx_lock(&dnp->n_mtx); 1561 1.1 dholland while (NFSHASNFSV4(nmp) && (dnp->n_flag & NREMOVEINPROG)) { 1562 1.1 dholland dnp->n_flag |= NREMOVEWANT; 1563 1.1 dholland (void) msleep((caddr_t)dnp, &dnp->n_mtx, PZERO, "nfscrt", 0); 1564 1.1 dholland } 1565 1.1 dholland mtx_unlock(&dnp->n_mtx); 1566 1.1 dholland 1567 1.1 dholland cverf = nfs_get_cverf(); 1568 1.1 dholland error = nfsrpc_create(dvp, cnp->cn_nameptr, cnp->cn_namelen, 1569 1.1 dholland vap, cverf, fmode, cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, 1570 1.1 dholland &nfhp, &attrflag, &dattrflag, NULL); 1571 1.1 dholland if (!error) { 1572 1.1 dholland if (nfhp == NULL) 1573 1.1 dholland (void) nfsrpc_lookup(dvp, cnp->cn_nameptr, 1574 1.1 dholland cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread, 1575 1.1 dholland &dnfsva, &nfsva, &nfhp, &attrflag, &dattrflag, 1576 1.1 dholland NULL); 1577 1.1 dholland if (nfhp != NULL) 1578 1.1 dholland error = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, 1579 1.1 dholland cnp->cn_thread, &np, NULL, LK_EXCLUSIVE); 1580 1.1 dholland } 1581 1.1 dholland if (dattrflag) 1582 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1583 1.1 dholland if (!error) { 1584 1.1 dholland newvp = NFSTOV(np); 1585 1.1 dholland if (attrflag == 0) 1586 1.1 dholland error = nfsrpc_getattr(newvp, cnp->cn_cred, 1587 1.1 dholland cnp->cn_thread, &nfsva, NULL); 1588 1.1 dholland if (error == 0) 1589 1.1 dholland error = nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 1590 1.1 dholland 0, 1); 1591 1.1 dholland } 1592 1.1 dholland if (error) { 1593 1.1 dholland if (newvp != NULL) { 1594 1.1 dholland vput(newvp); 1595 1.1 dholland newvp = NULL; 1596 1.1 dholland } 1597 1.1 dholland if (NFS_ISV34(dvp) && (fmode & O_EXCL) && 1598 1.1 dholland error == NFSERR_NOTSUPP) { 1599 1.1 dholland fmode &= ~O_EXCL; 1600 1.1 dholland goto again; 1601 1.1 dholland } 1602 1.1 dholland } else if (NFS_ISV34(dvp) && (fmode & O_EXCL)) { 1603 1.1 dholland if (nfscl_checksattr(vap, &nfsva)) { 1604 1.1 dholland error = nfsrpc_setattr(newvp, vap, NULL, cnp->cn_cred, 1605 1.1 dholland cnp->cn_thread, &nfsva, &attrflag, NULL); 1606 1.1 dholland if (error && (vap->va_uid != (uid_t)VNOVAL || 1607 1.1 dholland vap->va_gid != (gid_t)VNOVAL)) { 1608 1.1 dholland /* try again without setting uid/gid */ 1609 1.1 dholland vap->va_uid = (uid_t)VNOVAL; 1610 1.1 dholland vap->va_gid = (uid_t)VNOVAL; 1611 1.1 dholland error = nfsrpc_setattr(newvp, vap, NULL, 1612 1.1 dholland cnp->cn_cred, cnp->cn_thread, &nfsva, 1613 1.1 dholland &attrflag, NULL); 1614 1.1 dholland } 1615 1.1 dholland if (attrflag) 1616 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 1617 1.1 dholland NULL, 0, 1); 1618 1.1 dholland if (error != 0) 1619 1.1 dholland vput(newvp); 1620 1.1 dholland } 1621 1.1 dholland } 1622 1.1 dholland if (!error) { 1623 1.1 dholland if ((cnp->cn_flags & MAKEENTRY) && attrflag) 1624 1.1 dholland cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, 1625 1.1 dholland NULL); 1626 1.1 dholland *ap->a_vpp = newvp; 1627 1.1 dholland } else if (NFS_ISV4(dvp)) { 1628 1.1 dholland error = nfscl_maperr(cnp->cn_thread, error, vap->va_uid, 1629 1.1 dholland vap->va_gid); 1630 1.1 dholland } 1631 1.1 dholland mtx_lock(&dnp->n_mtx); 1632 1.1 dholland dnp->n_flag |= NMODIFIED; 1633 1.1 dholland if (!dattrflag) { 1634 1.1 dholland dnp->n_attrstamp = 0; 1635 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 1636 1.1 dholland } 1637 1.1 dholland mtx_unlock(&dnp->n_mtx); 1638 1.1 dholland return (error); 1639 1.1 dholland } 1640 1.1 dholland 1641 1.1 dholland /* 1642 1.1 dholland * nfs file remove call 1643 1.1 dholland * To try and make nfs semantics closer to ufs semantics, a file that has 1644 1.1 dholland * other processes using the vnode is renamed instead of removed and then 1645 1.1 dholland * removed later on the last close. 1646 1.1 dholland * - If v_usecount > 1 1647 1.1 dholland * If a rename is not already in the works 1648 1.1 dholland * call nfs_sillyrename() to set it up 1649 1.1 dholland * else 1650 1.1 dholland * do the remove rpc 1651 1.1 dholland */ 1652 1.1 dholland static int 1653 1.1 dholland nfs_remove(struct vop_remove_args *ap) 1654 1.1 dholland { 1655 1.1 dholland struct vnode *vp = ap->a_vp; 1656 1.1 dholland struct vnode *dvp = ap->a_dvp; 1657 1.1 dholland struct componentname *cnp = ap->a_cnp; 1658 1.1 dholland struct nfsnode *np = VTONFS(vp); 1659 1.1 dholland int error = 0; 1660 1.1 dholland struct vattr vattr; 1661 1.1 dholland 1662 1.1 dholland KASSERT((cnp->cn_flags & HASBUF) != 0, ("nfs_remove: no name")); 1663 1.1 dholland KASSERT(vrefcnt(vp) > 0, ("nfs_remove: bad v_usecount")); 1664 1.1 dholland if (vp->v_type == VDIR) 1665 1.1 dholland error = EPERM; 1666 1.1 dholland else if (vrefcnt(vp) == 1 || (np->n_sillyrename && 1667 1.1 dholland VOP_GETATTR(vp, &vattr, cnp->cn_cred) == 0 && 1668 1.1 dholland vattr.va_nlink > 1)) { 1669 1.1 dholland /* 1670 1.1 dholland * Purge the name cache so that the chance of a lookup for 1671 1.1 dholland * the name succeeding while the remove is in progress is 1672 1.1 dholland * minimized. Without node locking it can still happen, such 1673 1.1 dholland * that an I/O op returns ESTALE, but since you get this if 1674 1.1 dholland * another host removes the file.. 1675 1.1 dholland */ 1676 1.1 dholland cache_purge(vp); 1677 1.1 dholland /* 1678 1.1 dholland * throw away biocache buffers, mainly to avoid 1679 1.1 dholland * unnecessary delayed writes later. 1680 1.1 dholland */ 1681 1.1 dholland error = ncl_vinvalbuf(vp, 0, cnp->cn_thread, 1); 1682 1.1 dholland /* Do the rpc */ 1683 1.1 dholland if (error != EINTR && error != EIO) 1684 1.1 dholland error = nfs_removerpc(dvp, vp, cnp->cn_nameptr, 1685 1.1 dholland cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread); 1686 1.1 dholland /* 1687 1.1 dholland * Kludge City: If the first reply to the remove rpc is lost.. 1688 1.1 dholland * the reply to the retransmitted request will be ENOENT 1689 1.1 dholland * since the file was in fact removed 1690 1.1 dholland * Therefore, we cheat and return success. 1691 1.1 dholland */ 1692 1.1 dholland if (error == ENOENT) 1693 1.1 dholland error = 0; 1694 1.1 dholland } else if (!np->n_sillyrename) 1695 1.1 dholland error = nfs_sillyrename(dvp, vp, cnp); 1696 1.1 dholland mtx_lock(&np->n_mtx); 1697 1.1 dholland np->n_attrstamp = 0; 1698 1.1 dholland mtx_unlock(&np->n_mtx); 1699 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 1700 1.1 dholland return (error); 1701 1.1 dholland } 1702 1.1 dholland 1703 1.1 dholland /* 1704 1.1 dholland * nfs file remove rpc called from nfs_inactive 1705 1.1 dholland */ 1706 1.1 dholland int 1707 1.1 dholland ncl_removeit(struct sillyrename *sp, struct vnode *vp) 1708 1.1 dholland { 1709 1.1 dholland /* 1710 1.1 dholland * Make sure that the directory vnode is still valid. 1711 1.1 dholland * XXX we should lock sp->s_dvp here. 1712 1.1 dholland */ 1713 1.1 dholland if (sp->s_dvp->v_type == VBAD) 1714 1.1 dholland return (0); 1715 1.1 dholland return (nfs_removerpc(sp->s_dvp, vp, sp->s_name, sp->s_namlen, 1716 1.1 dholland sp->s_cred, NULL)); 1717 1.1 dholland } 1718 1.1 dholland 1719 1.1 dholland /* 1720 1.1 dholland * Nfs remove rpc, called from nfs_remove() and ncl_removeit(). 1721 1.1 dholland */ 1722 1.1 dholland static int 1723 1.1 dholland nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name, 1724 1.1 dholland int namelen, struct ucred *cred, struct thread *td) 1725 1.1 dholland { 1726 1.1 dholland struct nfsvattr dnfsva; 1727 1.1 dholland struct nfsnode *dnp = VTONFS(dvp); 1728 1.1 dholland int error = 0, dattrflag; 1729 1.1 dholland 1730 1.1 dholland mtx_lock(&dnp->n_mtx); 1731 1.1 dholland dnp->n_flag |= NREMOVEINPROG; 1732 1.1 dholland mtx_unlock(&dnp->n_mtx); 1733 1.1 dholland error = nfsrpc_remove(dvp, name, namelen, vp, cred, td, &dnfsva, 1734 1.1 dholland &dattrflag, NULL); 1735 1.1 dholland mtx_lock(&dnp->n_mtx); 1736 1.1 dholland if ((dnp->n_flag & NREMOVEWANT)) { 1737 1.1 dholland dnp->n_flag &= ~(NREMOVEWANT | NREMOVEINPROG); 1738 1.1 dholland mtx_unlock(&dnp->n_mtx); 1739 1.1 dholland wakeup((caddr_t)dnp); 1740 1.1 dholland } else { 1741 1.1 dholland dnp->n_flag &= ~NREMOVEINPROG; 1742 1.1 dholland mtx_unlock(&dnp->n_mtx); 1743 1.1 dholland } 1744 1.1 dholland if (dattrflag) 1745 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 1746 1.1 dholland mtx_lock(&dnp->n_mtx); 1747 1.1 dholland dnp->n_flag |= NMODIFIED; 1748 1.1 dholland if (!dattrflag) { 1749 1.1 dholland dnp->n_attrstamp = 0; 1750 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 1751 1.1 dholland } 1752 1.1 dholland mtx_unlock(&dnp->n_mtx); 1753 1.1 dholland if (error && NFS_ISV4(dvp)) 1754 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1755 1.1 dholland return (error); 1756 1.1 dholland } 1757 1.1 dholland 1758 1.1 dholland /* 1759 1.1 dholland * nfs file rename call 1760 1.1 dholland */ 1761 1.1 dholland static int 1762 1.1 dholland nfs_rename(struct vop_rename_args *ap) 1763 1.1 dholland { 1764 1.1 dholland struct vnode *fvp = ap->a_fvp; 1765 1.1 dholland struct vnode *tvp = ap->a_tvp; 1766 1.1 dholland struct vnode *fdvp = ap->a_fdvp; 1767 1.1 dholland struct vnode *tdvp = ap->a_tdvp; 1768 1.1 dholland struct componentname *tcnp = ap->a_tcnp; 1769 1.1 dholland struct componentname *fcnp = ap->a_fcnp; 1770 1.1 dholland struct nfsnode *fnp = VTONFS(ap->a_fvp); 1771 1.1 dholland struct nfsnode *tdnp = VTONFS(ap->a_tdvp); 1772 1.1 dholland struct nfsv4node *newv4 = NULL; 1773 1.1 dholland int error; 1774 1.1 dholland 1775 1.1 dholland KASSERT((tcnp->cn_flags & HASBUF) != 0 && 1776 1.1 dholland (fcnp->cn_flags & HASBUF) != 0, ("nfs_rename: no name")); 1777 1.1 dholland /* Check for cross-device rename */ 1778 1.1 dholland if ((fvp->v_mount != tdvp->v_mount) || 1779 1.1 dholland (tvp && (fvp->v_mount != tvp->v_mount))) { 1780 1.1 dholland error = EXDEV; 1781 1.1 dholland goto out; 1782 1.1 dholland } 1783 1.1 dholland 1784 1.1 dholland if (fvp == tvp) { 1785 1.3 pgoyette printf("nfs_rename: fvp == tvp (can't happen)\n"); 1786 1.1 dholland error = 0; 1787 1.1 dholland goto out; 1788 1.1 dholland } 1789 1.1 dholland if ((error = NFSVOPLOCK(fvp, LK_EXCLUSIVE)) != 0) 1790 1.1 dholland goto out; 1791 1.1 dholland 1792 1.1 dholland /* 1793 1.1 dholland * We have to flush B_DELWRI data prior to renaming 1794 1.1 dholland * the file. If we don't, the delayed-write buffers 1795 1.1 dholland * can be flushed out later after the file has gone stale 1796 1.1 dholland * under NFSV3. NFSV2 does not have this problem because 1797 1.1 dholland * ( as far as I can tell ) it flushes dirty buffers more 1798 1.1 dholland * often. 1799 1.1 dholland * 1800 1.1 dholland * Skip the rename operation if the fsync fails, this can happen 1801 1.1 dholland * due to the server's volume being full, when we pushed out data 1802 1.1 dholland * that was written back to our cache earlier. Not checking for 1803 1.1 dholland * this condition can result in potential (silent) data loss. 1804 1.1 dholland */ 1805 1.1 dholland error = VOP_FSYNC(fvp, MNT_WAIT, fcnp->cn_thread); 1806 1.1 dholland NFSVOPUNLOCK(fvp, 0); 1807 1.1 dholland if (!error && tvp) 1808 1.1 dholland error = VOP_FSYNC(tvp, MNT_WAIT, tcnp->cn_thread); 1809 1.1 dholland if (error) 1810 1.1 dholland goto out; 1811 1.1 dholland 1812 1.1 dholland /* 1813 1.1 dholland * If the tvp exists and is in use, sillyrename it before doing the 1814 1.1 dholland * rename of the new file over it. 1815 1.1 dholland * XXX Can't sillyrename a directory. 1816 1.1 dholland */ 1817 1.1 dholland if (tvp && vrefcnt(tvp) > 1 && !VTONFS(tvp)->n_sillyrename && 1818 1.1 dholland tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) { 1819 1.1 dholland vput(tvp); 1820 1.1 dholland tvp = NULL; 1821 1.1 dholland } 1822 1.1 dholland 1823 1.1 dholland error = nfs_renamerpc(fdvp, fvp, fcnp->cn_nameptr, fcnp->cn_namelen, 1824 1.1 dholland tdvp, tvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, 1825 1.1 dholland tcnp->cn_thread); 1826 1.1 dholland 1827 1.1 dholland if (error == 0 && NFS_ISV4(tdvp)) { 1828 1.1 dholland /* 1829 1.1 dholland * For NFSv4, check to see if it is the same name and 1830 1.1 dholland * replace the name, if it is different. 1831 1.1 dholland */ 1832 1.1 dholland MALLOC(newv4, struct nfsv4node *, 1833 1.1 dholland sizeof (struct nfsv4node) + 1834 1.1 dholland tdnp->n_fhp->nfh_len + tcnp->cn_namelen - 1, 1835 1.1 dholland M_NFSV4NODE, M_WAITOK); 1836 1.1 dholland mtx_lock(&tdnp->n_mtx); 1837 1.1 dholland mtx_lock(&fnp->n_mtx); 1838 1.1 dholland if (fnp->n_v4 != NULL && fvp->v_type == VREG && 1839 1.1 dholland (fnp->n_v4->n4_namelen != tcnp->cn_namelen || 1840 1.1 dholland NFSBCMP(tcnp->cn_nameptr, NFS4NODENAME(fnp->n_v4), 1841 1.1 dholland tcnp->cn_namelen) || 1842 1.1 dholland tdnp->n_fhp->nfh_len != fnp->n_v4->n4_fhlen || 1843 1.1 dholland NFSBCMP(tdnp->n_fhp->nfh_fh, fnp->n_v4->n4_data, 1844 1.1 dholland tdnp->n_fhp->nfh_len))) { 1845 1.1 dholland #ifdef notdef 1846 1.1 dholland { char nnn[100]; int nnnl; 1847 1.1 dholland nnnl = (tcnp->cn_namelen < 100) ? tcnp->cn_namelen : 99; 1848 1.1 dholland bcopy(tcnp->cn_nameptr, nnn, nnnl); 1849 1.1 dholland nnn[nnnl] = '\0'; 1850 1.1 dholland printf("ren replace=%s\n",nnn); 1851 1.1 dholland } 1852 1.1 dholland #endif 1853 1.1 dholland FREE((caddr_t)fnp->n_v4, M_NFSV4NODE); 1854 1.1 dholland fnp->n_v4 = newv4; 1855 1.1 dholland newv4 = NULL; 1856 1.1 dholland fnp->n_v4->n4_fhlen = tdnp->n_fhp->nfh_len; 1857 1.1 dholland fnp->n_v4->n4_namelen = tcnp->cn_namelen; 1858 1.1 dholland NFSBCOPY(tdnp->n_fhp->nfh_fh, fnp->n_v4->n4_data, 1859 1.1 dholland tdnp->n_fhp->nfh_len); 1860 1.1 dholland NFSBCOPY(tcnp->cn_nameptr, 1861 1.1 dholland NFS4NODENAME(fnp->n_v4), tcnp->cn_namelen); 1862 1.1 dholland } 1863 1.1 dholland mtx_unlock(&tdnp->n_mtx); 1864 1.1 dholland mtx_unlock(&fnp->n_mtx); 1865 1.1 dholland if (newv4 != NULL) 1866 1.1 dholland FREE((caddr_t)newv4, M_NFSV4NODE); 1867 1.1 dholland } 1868 1.1 dholland 1869 1.1 dholland if (fvp->v_type == VDIR) { 1870 1.1 dholland if (tvp != NULL && tvp->v_type == VDIR) 1871 1.1 dholland cache_purge(tdvp); 1872 1.1 dholland cache_purge(fdvp); 1873 1.1 dholland } 1874 1.1 dholland 1875 1.1 dholland out: 1876 1.1 dholland if (tdvp == tvp) 1877 1.1 dholland vrele(tdvp); 1878 1.1 dholland else 1879 1.1 dholland vput(tdvp); 1880 1.1 dholland if (tvp) 1881 1.1 dholland vput(tvp); 1882 1.1 dholland vrele(fdvp); 1883 1.1 dholland vrele(fvp); 1884 1.1 dholland /* 1885 1.1 dholland * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 1886 1.1 dholland */ 1887 1.1 dholland if (error == ENOENT) 1888 1.1 dholland error = 0; 1889 1.1 dholland return (error); 1890 1.1 dholland } 1891 1.1 dholland 1892 1.1 dholland /* 1893 1.1 dholland * nfs file rename rpc called from nfs_remove() above 1894 1.1 dholland */ 1895 1.1 dholland static int 1896 1.1 dholland nfs_renameit(struct vnode *sdvp, struct vnode *svp, struct componentname *scnp, 1897 1.1 dholland struct sillyrename *sp) 1898 1.1 dholland { 1899 1.1 dholland 1900 1.1 dholland return (nfs_renamerpc(sdvp, svp, scnp->cn_nameptr, scnp->cn_namelen, 1901 1.1 dholland sdvp, NULL, sp->s_name, sp->s_namlen, scnp->cn_cred, 1902 1.1 dholland scnp->cn_thread)); 1903 1.1 dholland } 1904 1.1 dholland 1905 1.1 dholland /* 1906 1.1 dholland * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). 1907 1.1 dholland */ 1908 1.1 dholland static int 1909 1.1 dholland nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, char *fnameptr, 1910 1.1 dholland int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr, 1911 1.1 dholland int tnamelen, struct ucred *cred, struct thread *td) 1912 1.1 dholland { 1913 1.1 dholland struct nfsvattr fnfsva, tnfsva; 1914 1.1 dholland struct nfsnode *fdnp = VTONFS(fdvp); 1915 1.1 dholland struct nfsnode *tdnp = VTONFS(tdvp); 1916 1.1 dholland int error = 0, fattrflag, tattrflag; 1917 1.1 dholland 1918 1.1 dholland error = nfsrpc_rename(fdvp, fvp, fnameptr, fnamelen, tdvp, tvp, 1919 1.1 dholland tnameptr, tnamelen, cred, td, &fnfsva, &tnfsva, &fattrflag, 1920 1.1 dholland &tattrflag, NULL, NULL); 1921 1.1 dholland mtx_lock(&fdnp->n_mtx); 1922 1.1 dholland fdnp->n_flag |= NMODIFIED; 1923 1.1 dholland if (fattrflag != 0) { 1924 1.1 dholland mtx_unlock(&fdnp->n_mtx); 1925 1.1 dholland (void) nfscl_loadattrcache(&fdvp, &fnfsva, NULL, NULL, 0, 1); 1926 1.1 dholland } else { 1927 1.1 dholland fdnp->n_attrstamp = 0; 1928 1.1 dholland mtx_unlock(&fdnp->n_mtx); 1929 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(fdvp); 1930 1.1 dholland } 1931 1.1 dholland mtx_lock(&tdnp->n_mtx); 1932 1.1 dholland tdnp->n_flag |= NMODIFIED; 1933 1.1 dholland if (tattrflag != 0) { 1934 1.1 dholland mtx_unlock(&tdnp->n_mtx); 1935 1.1 dholland (void) nfscl_loadattrcache(&tdvp, &tnfsva, NULL, NULL, 0, 1); 1936 1.1 dholland } else { 1937 1.1 dholland tdnp->n_attrstamp = 0; 1938 1.1 dholland mtx_unlock(&tdnp->n_mtx); 1939 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp); 1940 1.1 dholland } 1941 1.1 dholland if (error && NFS_ISV4(fdvp)) 1942 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1943 1.1 dholland return (error); 1944 1.1 dholland } 1945 1.1 dholland 1946 1.1 dholland /* 1947 1.1 dholland * nfs hard link create call 1948 1.1 dholland */ 1949 1.1 dholland static int 1950 1.1 dholland nfs_link(struct vop_link_args *ap) 1951 1.1 dholland { 1952 1.1 dholland struct vnode *vp = ap->a_vp; 1953 1.1 dholland struct vnode *tdvp = ap->a_tdvp; 1954 1.1 dholland struct componentname *cnp = ap->a_cnp; 1955 1.1 dholland struct nfsnode *np, *tdnp; 1956 1.1 dholland struct nfsvattr nfsva, dnfsva; 1957 1.1 dholland int error = 0, attrflag, dattrflag; 1958 1.1 dholland 1959 1.1 dholland /* 1960 1.1 dholland * Push all writes to the server, so that the attribute cache 1961 1.1 dholland * doesn't get "out of sync" with the server. 1962 1.1 dholland * XXX There should be a better way! 1963 1.1 dholland */ 1964 1.1 dholland VOP_FSYNC(vp, MNT_WAIT, cnp->cn_thread); 1965 1.1 dholland 1966 1.1 dholland error = nfsrpc_link(tdvp, vp, cnp->cn_nameptr, cnp->cn_namelen, 1967 1.1 dholland cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, &attrflag, 1968 1.1 dholland &dattrflag, NULL); 1969 1.1 dholland tdnp = VTONFS(tdvp); 1970 1.1 dholland mtx_lock(&tdnp->n_mtx); 1971 1.1 dholland tdnp->n_flag |= NMODIFIED; 1972 1.1 dholland if (dattrflag != 0) { 1973 1.1 dholland mtx_unlock(&tdnp->n_mtx); 1974 1.1 dholland (void) nfscl_loadattrcache(&tdvp, &dnfsva, NULL, NULL, 0, 1); 1975 1.1 dholland } else { 1976 1.1 dholland tdnp->n_attrstamp = 0; 1977 1.1 dholland mtx_unlock(&tdnp->n_mtx); 1978 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp); 1979 1.1 dholland } 1980 1.1 dholland if (attrflag) 1981 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 1982 1.1 dholland else { 1983 1.1 dholland np = VTONFS(vp); 1984 1.1 dholland mtx_lock(&np->n_mtx); 1985 1.1 dholland np->n_attrstamp = 0; 1986 1.1 dholland mtx_unlock(&np->n_mtx); 1987 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 1988 1.1 dholland } 1989 1.1 dholland /* 1990 1.1 dholland * If negative lookup caching is enabled, I might as well 1991 1.1 dholland * add an entry for this node. Not necessary for correctness, 1992 1.1 dholland * but if negative caching is enabled, then the system 1993 1.1 dholland * must care about lookup caching hit rate, so... 1994 1.1 dholland */ 1995 1.1 dholland if (VFSTONFS(vp->v_mount)->nm_negnametimeo != 0 && 1996 1.1 dholland (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && error == 0) { 1997 1.1 dholland cache_enter_time(tdvp, vp, cnp, &nfsva.na_ctime, NULL); 1998 1.1 dholland } 1999 1.1 dholland if (error && NFS_ISV4(vp)) 2000 1.1 dholland error = nfscl_maperr(cnp->cn_thread, error, (uid_t)0, 2001 1.1 dholland (gid_t)0); 2002 1.1 dholland return (error); 2003 1.1 dholland } 2004 1.1 dholland 2005 1.1 dholland /* 2006 1.1 dholland * nfs symbolic link create call 2007 1.1 dholland */ 2008 1.1 dholland static int 2009 1.1 dholland nfs_symlink(struct vop_symlink_args *ap) 2010 1.1 dholland { 2011 1.1 dholland struct vnode *dvp = ap->a_dvp; 2012 1.1 dholland struct vattr *vap = ap->a_vap; 2013 1.1 dholland struct componentname *cnp = ap->a_cnp; 2014 1.1 dholland struct nfsvattr nfsva, dnfsva; 2015 1.1 dholland struct nfsfh *nfhp; 2016 1.1 dholland struct nfsnode *np = NULL, *dnp; 2017 1.1 dholland struct vnode *newvp = NULL; 2018 1.1 dholland int error = 0, attrflag, dattrflag, ret; 2019 1.1 dholland 2020 1.1 dholland vap->va_type = VLNK; 2021 1.1 dholland error = nfsrpc_symlink(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2022 1.1 dholland ap->a_target, vap, cnp->cn_cred, cnp->cn_thread, &dnfsva, 2023 1.1 dholland &nfsva, &nfhp, &attrflag, &dattrflag, NULL); 2024 1.1 dholland if (nfhp) { 2025 1.1 dholland ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread, 2026 1.1 dholland &np, NULL, LK_EXCLUSIVE); 2027 1.1 dholland if (!ret) 2028 1.1 dholland newvp = NFSTOV(np); 2029 1.1 dholland else if (!error) 2030 1.1 dholland error = ret; 2031 1.1 dholland } 2032 1.1 dholland if (newvp != NULL) { 2033 1.1 dholland if (attrflag) 2034 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 2035 1.1 dholland 0, 1); 2036 1.1 dholland } else if (!error) { 2037 1.1 dholland /* 2038 1.1 dholland * If we do not have an error and we could not extract the 2039 1.1 dholland * newvp from the response due to the request being NFSv2, we 2040 1.1 dholland * have to do a lookup in order to obtain a newvp to return. 2041 1.1 dholland */ 2042 1.1 dholland error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2043 1.1 dholland cnp->cn_cred, cnp->cn_thread, &np); 2044 1.1 dholland if (!error) 2045 1.1 dholland newvp = NFSTOV(np); 2046 1.1 dholland } 2047 1.1 dholland if (error) { 2048 1.1 dholland if (newvp) 2049 1.1 dholland vput(newvp); 2050 1.1 dholland if (NFS_ISV4(dvp)) 2051 1.1 dholland error = nfscl_maperr(cnp->cn_thread, error, 2052 1.1 dholland vap->va_uid, vap->va_gid); 2053 1.1 dholland } else { 2054 1.1 dholland *ap->a_vpp = newvp; 2055 1.1 dholland } 2056 1.1 dholland 2057 1.1 dholland dnp = VTONFS(dvp); 2058 1.1 dholland mtx_lock(&dnp->n_mtx); 2059 1.1 dholland dnp->n_flag |= NMODIFIED; 2060 1.1 dholland if (dattrflag != 0) { 2061 1.1 dholland mtx_unlock(&dnp->n_mtx); 2062 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2063 1.1 dholland } else { 2064 1.1 dholland dnp->n_attrstamp = 0; 2065 1.1 dholland mtx_unlock(&dnp->n_mtx); 2066 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 2067 1.1 dholland } 2068 1.1 dholland /* 2069 1.1 dholland * If negative lookup caching is enabled, I might as well 2070 1.1 dholland * add an entry for this node. Not necessary for correctness, 2071 1.1 dholland * but if negative caching is enabled, then the system 2072 1.1 dholland * must care about lookup caching hit rate, so... 2073 1.1 dholland */ 2074 1.1 dholland if (VFSTONFS(dvp->v_mount)->nm_negnametimeo != 0 && 2075 1.1 dholland (cnp->cn_flags & MAKEENTRY) && attrflag != 0 && error == 0) { 2076 1.1 dholland cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, NULL); 2077 1.1 dholland } 2078 1.1 dholland return (error); 2079 1.1 dholland } 2080 1.1 dholland 2081 1.1 dholland /* 2082 1.1 dholland * nfs make dir call 2083 1.1 dholland */ 2084 1.1 dholland static int 2085 1.1 dholland nfs_mkdir(struct vop_mkdir_args *ap) 2086 1.1 dholland { 2087 1.1 dholland struct vnode *dvp = ap->a_dvp; 2088 1.1 dholland struct vattr *vap = ap->a_vap; 2089 1.1 dholland struct componentname *cnp = ap->a_cnp; 2090 1.1 dholland struct nfsnode *np = NULL, *dnp; 2091 1.1 dholland struct vnode *newvp = NULL; 2092 1.1 dholland struct vattr vattr; 2093 1.1 dholland struct nfsfh *nfhp; 2094 1.1 dholland struct nfsvattr nfsva, dnfsva; 2095 1.1 dholland int error = 0, attrflag, dattrflag, ret; 2096 1.1 dholland 2097 1.1 dholland if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred)) != 0) 2098 1.1 dholland return (error); 2099 1.1 dholland vap->va_type = VDIR; 2100 1.1 dholland error = nfsrpc_mkdir(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2101 1.1 dholland vap, cnp->cn_cred, cnp->cn_thread, &dnfsva, &nfsva, &nfhp, 2102 1.1 dholland &attrflag, &dattrflag, NULL); 2103 1.1 dholland dnp = VTONFS(dvp); 2104 1.1 dholland mtx_lock(&dnp->n_mtx); 2105 1.1 dholland dnp->n_flag |= NMODIFIED; 2106 1.1 dholland if (dattrflag != 0) { 2107 1.1 dholland mtx_unlock(&dnp->n_mtx); 2108 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2109 1.1 dholland } else { 2110 1.1 dholland dnp->n_attrstamp = 0; 2111 1.1 dholland mtx_unlock(&dnp->n_mtx); 2112 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 2113 1.1 dholland } 2114 1.1 dholland if (nfhp) { 2115 1.1 dholland ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread, 2116 1.1 dholland &np, NULL, LK_EXCLUSIVE); 2117 1.1 dholland if (!ret) { 2118 1.1 dholland newvp = NFSTOV(np); 2119 1.1 dholland if (attrflag) 2120 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, 2121 1.1 dholland NULL, 0, 1); 2122 1.1 dholland } else if (!error) 2123 1.1 dholland error = ret; 2124 1.1 dholland } 2125 1.1 dholland if (!error && newvp == NULL) { 2126 1.1 dholland error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2127 1.1 dholland cnp->cn_cred, cnp->cn_thread, &np); 2128 1.1 dholland if (!error) { 2129 1.1 dholland newvp = NFSTOV(np); 2130 1.1 dholland if (newvp->v_type != VDIR) 2131 1.1 dholland error = EEXIST; 2132 1.1 dholland } 2133 1.1 dholland } 2134 1.1 dholland if (error) { 2135 1.1 dholland if (newvp) 2136 1.1 dholland vput(newvp); 2137 1.1 dholland if (NFS_ISV4(dvp)) 2138 1.1 dholland error = nfscl_maperr(cnp->cn_thread, error, 2139 1.1 dholland vap->va_uid, vap->va_gid); 2140 1.1 dholland } else { 2141 1.1 dholland /* 2142 1.1 dholland * If negative lookup caching is enabled, I might as well 2143 1.1 dholland * add an entry for this node. Not necessary for correctness, 2144 1.1 dholland * but if negative caching is enabled, then the system 2145 1.1 dholland * must care about lookup caching hit rate, so... 2146 1.1 dholland */ 2147 1.1 dholland if (VFSTONFS(dvp->v_mount)->nm_negnametimeo != 0 && 2148 1.1 dholland (cnp->cn_flags & MAKEENTRY) && 2149 1.1 dholland attrflag != 0 && dattrflag != 0) 2150 1.1 dholland cache_enter_time(dvp, newvp, cnp, &nfsva.na_ctime, 2151 1.1 dholland &dnfsva.na_ctime); 2152 1.1 dholland *ap->a_vpp = newvp; 2153 1.1 dholland } 2154 1.1 dholland return (error); 2155 1.1 dholland } 2156 1.1 dholland 2157 1.1 dholland /* 2158 1.1 dholland * nfs remove directory call 2159 1.1 dholland */ 2160 1.1 dholland static int 2161 1.1 dholland nfs_rmdir(struct vop_rmdir_args *ap) 2162 1.1 dholland { 2163 1.1 dholland struct vnode *vp = ap->a_vp; 2164 1.1 dholland struct vnode *dvp = ap->a_dvp; 2165 1.1 dholland struct componentname *cnp = ap->a_cnp; 2166 1.1 dholland struct nfsnode *dnp; 2167 1.1 dholland struct nfsvattr dnfsva; 2168 1.1 dholland int error, dattrflag; 2169 1.1 dholland 2170 1.1 dholland if (dvp == vp) 2171 1.1 dholland return (EINVAL); 2172 1.1 dholland error = nfsrpc_rmdir(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2173 1.1 dholland cnp->cn_cred, cnp->cn_thread, &dnfsva, &dattrflag, NULL); 2174 1.1 dholland dnp = VTONFS(dvp); 2175 1.1 dholland mtx_lock(&dnp->n_mtx); 2176 1.1 dholland dnp->n_flag |= NMODIFIED; 2177 1.1 dholland if (dattrflag != 0) { 2178 1.1 dholland mtx_unlock(&dnp->n_mtx); 2179 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2180 1.1 dholland } else { 2181 1.1 dholland dnp->n_attrstamp = 0; 2182 1.1 dholland mtx_unlock(&dnp->n_mtx); 2183 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp); 2184 1.1 dholland } 2185 1.1 dholland 2186 1.1 dholland cache_purge(dvp); 2187 1.1 dholland cache_purge(vp); 2188 1.1 dholland if (error && NFS_ISV4(dvp)) 2189 1.1 dholland error = nfscl_maperr(cnp->cn_thread, error, (uid_t)0, 2190 1.1 dholland (gid_t)0); 2191 1.1 dholland /* 2192 1.1 dholland * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2193 1.1 dholland */ 2194 1.1 dholland if (error == ENOENT) 2195 1.1 dholland error = 0; 2196 1.1 dholland return (error); 2197 1.1 dholland } 2198 1.1 dholland 2199 1.1 dholland /* 2200 1.1 dholland * nfs readdir call 2201 1.1 dholland */ 2202 1.1 dholland static int 2203 1.1 dholland nfs_readdir(struct vop_readdir_args *ap) 2204 1.1 dholland { 2205 1.1 dholland struct vnode *vp = ap->a_vp; 2206 1.1 dholland struct nfsnode *np = VTONFS(vp); 2207 1.1 dholland struct uio *uio = ap->a_uio; 2208 1.3 pgoyette ssize_t tresid, left; 2209 1.1 dholland int error = 0; 2210 1.1 dholland struct vattr vattr; 2211 1.1 dholland 2212 1.1 dholland if (ap->a_eofflag != NULL) 2213 1.1 dholland *ap->a_eofflag = 0; 2214 1.1 dholland if (vp->v_type != VDIR) 2215 1.1 dholland return(EPERM); 2216 1.1 dholland 2217 1.1 dholland /* 2218 1.1 dholland * First, check for hit on the EOF offset cache 2219 1.1 dholland */ 2220 1.1 dholland if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset && 2221 1.1 dholland (np->n_flag & NMODIFIED) == 0) { 2222 1.1 dholland if (VOP_GETATTR(vp, &vattr, ap->a_cred) == 0) { 2223 1.1 dholland mtx_lock(&np->n_mtx); 2224 1.1 dholland if ((NFS_ISV4(vp) && np->n_change == vattr.va_filerev) || 2225 1.1 dholland !NFS_TIMESPEC_COMPARE(&np->n_mtime, &vattr.va_mtime)) { 2226 1.1 dholland mtx_unlock(&np->n_mtx); 2227 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.direofcache_hits); 2228 1.1 dholland if (ap->a_eofflag != NULL) 2229 1.1 dholland *ap->a_eofflag = 1; 2230 1.1 dholland return (0); 2231 1.1 dholland } else 2232 1.1 dholland mtx_unlock(&np->n_mtx); 2233 1.1 dholland } 2234 1.1 dholland } 2235 1.1 dholland 2236 1.1 dholland /* 2237 1.3 pgoyette * NFS always guarantees that directory entries don't straddle 2238 1.3 pgoyette * DIRBLKSIZ boundaries. As such, we need to limit the size 2239 1.3 pgoyette * to an exact multiple of DIRBLKSIZ, to avoid copying a partial 2240 1.3 pgoyette * directory entry. 2241 1.3 pgoyette */ 2242 1.3 pgoyette left = uio->uio_resid % DIRBLKSIZ; 2243 1.3 pgoyette if (left == uio->uio_resid) 2244 1.3 pgoyette return (EINVAL); 2245 1.3 pgoyette uio->uio_resid -= left; 2246 1.3 pgoyette 2247 1.3 pgoyette /* 2248 1.1 dholland * Call ncl_bioread() to do the real work. 2249 1.1 dholland */ 2250 1.1 dholland tresid = uio->uio_resid; 2251 1.1 dholland error = ncl_bioread(vp, uio, 0, ap->a_cred); 2252 1.1 dholland 2253 1.1 dholland if (!error && uio->uio_resid == tresid) { 2254 1.3 pgoyette NFSINCRGLOBAL(nfsstatsv1.direofcache_misses); 2255 1.1 dholland if (ap->a_eofflag != NULL) 2256 1.1 dholland *ap->a_eofflag = 1; 2257 1.1 dholland } 2258 1.3 pgoyette 2259 1.3 pgoyette /* Add the partial DIRBLKSIZ (left) back in. */ 2260 1.3 pgoyette uio->uio_resid += left; 2261 1.1 dholland return (error); 2262 1.1 dholland } 2263 1.1 dholland 2264 1.1 dholland /* 2265 1.1 dholland * Readdir rpc call. 2266 1.1 dholland * Called from below the buffer cache by ncl_doio(). 2267 1.1 dholland */ 2268 1.1 dholland int 2269 1.1 dholland ncl_readdirrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, 2270 1.1 dholland struct thread *td) 2271 1.1 dholland { 2272 1.1 dholland struct nfsvattr nfsva; 2273 1.1 dholland nfsuint64 *cookiep, cookie; 2274 1.1 dholland struct nfsnode *dnp = VTONFS(vp); 2275 1.1 dholland struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2276 1.1 dholland int error = 0, eof, attrflag; 2277 1.1 dholland 2278 1.1 dholland KASSERT(uiop->uio_iovcnt == 1 && 2279 1.1 dholland (uiop->uio_offset & (DIRBLKSIZ - 1)) == 0 && 2280 1.1 dholland (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 2281 1.1 dholland ("nfs readdirrpc bad uio")); 2282 1.1 dholland 2283 1.1 dholland /* 2284 1.1 dholland * If there is no cookie, assume directory was stale. 2285 1.1 dholland */ 2286 1.1 dholland ncl_dircookie_lock(dnp); 2287 1.1 dholland cookiep = ncl_getcookie(dnp, uiop->uio_offset, 0); 2288 1.1 dholland if (cookiep) { 2289 1.1 dholland cookie = *cookiep; 2290 1.1 dholland ncl_dircookie_unlock(dnp); 2291 1.1 dholland } else { 2292 1.1 dholland ncl_dircookie_unlock(dnp); 2293 1.1 dholland return (NFSERR_BAD_COOKIE); 2294 1.1 dholland } 2295 1.1 dholland 2296 1.1 dholland if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) 2297 1.1 dholland (void)ncl_fsinfo(nmp, vp, cred, td); 2298 1.1 dholland 2299 1.1 dholland error = nfsrpc_readdir(vp, uiop, &cookie, cred, td, &nfsva, 2300 1.1 dholland &attrflag, &eof, NULL); 2301 1.1 dholland if (attrflag) 2302 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 2303 1.1 dholland 2304 1.1 dholland if (!error) { 2305 1.1 dholland /* 2306 1.1 dholland * We are now either at the end of the directory or have filled 2307 1.1 dholland * the block. 2308 1.1 dholland */ 2309 1.1 dholland if (eof) 2310 1.1 dholland dnp->n_direofoffset = uiop->uio_offset; 2311 1.1 dholland else { 2312 1.1 dholland if (uiop->uio_resid > 0) 2313 1.3 pgoyette printf("EEK! readdirrpc resid > 0\n"); 2314 1.1 dholland ncl_dircookie_lock(dnp); 2315 1.1 dholland cookiep = ncl_getcookie(dnp, uiop->uio_offset, 1); 2316 1.1 dholland *cookiep = cookie; 2317 1.1 dholland ncl_dircookie_unlock(dnp); 2318 1.1 dholland } 2319 1.1 dholland } else if (NFS_ISV4(vp)) { 2320 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2321 1.1 dholland } 2322 1.1 dholland return (error); 2323 1.1 dholland } 2324 1.1 dholland 2325 1.1 dholland /* 2326 1.1 dholland * NFS V3 readdir plus RPC. Used in place of ncl_readdirrpc(). 2327 1.1 dholland */ 2328 1.1 dholland int 2329 1.1 dholland ncl_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, 2330 1.1 dholland struct thread *td) 2331 1.1 dholland { 2332 1.1 dholland struct nfsvattr nfsva; 2333 1.1 dholland nfsuint64 *cookiep, cookie; 2334 1.1 dholland struct nfsnode *dnp = VTONFS(vp); 2335 1.1 dholland struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2336 1.1 dholland int error = 0, attrflag, eof; 2337 1.1 dholland 2338 1.1 dholland KASSERT(uiop->uio_iovcnt == 1 && 2339 1.1 dholland (uiop->uio_offset & (DIRBLKSIZ - 1)) == 0 && 2340 1.1 dholland (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 2341 1.1 dholland ("nfs readdirplusrpc bad uio")); 2342 1.1 dholland 2343 1.1 dholland /* 2344 1.1 dholland * If there is no cookie, assume directory was stale. 2345 1.1 dholland */ 2346 1.1 dholland ncl_dircookie_lock(dnp); 2347 1.1 dholland cookiep = ncl_getcookie(dnp, uiop->uio_offset, 0); 2348 1.1 dholland if (cookiep) { 2349 1.1 dholland cookie = *cookiep; 2350 1.1 dholland ncl_dircookie_unlock(dnp); 2351 1.1 dholland } else { 2352 1.1 dholland ncl_dircookie_unlock(dnp); 2353 1.1 dholland return (NFSERR_BAD_COOKIE); 2354 1.1 dholland } 2355 1.1 dholland 2356 1.1 dholland if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) 2357 1.1 dholland (void)ncl_fsinfo(nmp, vp, cred, td); 2358 1.1 dholland error = nfsrpc_readdirplus(vp, uiop, &cookie, cred, td, &nfsva, 2359 1.1 dholland &attrflag, &eof, NULL); 2360 1.1 dholland if (attrflag) 2361 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 2362 1.1 dholland 2363 1.1 dholland if (!error) { 2364 1.1 dholland /* 2365 1.1 dholland * We are now either at end of the directory or have filled the 2366 1.1 dholland * the block. 2367 1.1 dholland */ 2368 1.1 dholland if (eof) 2369 1.1 dholland dnp->n_direofoffset = uiop->uio_offset; 2370 1.1 dholland else { 2371 1.1 dholland if (uiop->uio_resid > 0) 2372 1.3 pgoyette printf("EEK! readdirplusrpc resid > 0\n"); 2373 1.1 dholland ncl_dircookie_lock(dnp); 2374 1.1 dholland cookiep = ncl_getcookie(dnp, uiop->uio_offset, 1); 2375 1.1 dholland *cookiep = cookie; 2376 1.1 dholland ncl_dircookie_unlock(dnp); 2377 1.1 dholland } 2378 1.1 dholland } else if (NFS_ISV4(vp)) { 2379 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2380 1.1 dholland } 2381 1.1 dholland return (error); 2382 1.1 dholland } 2383 1.1 dholland 2384 1.1 dholland /* 2385 1.1 dholland * Silly rename. To make the NFS filesystem that is stateless look a little 2386 1.1 dholland * more like the "ufs" a remove of an active vnode is translated to a rename 2387 1.1 dholland * to a funny looking filename that is removed by nfs_inactive on the 2388 1.1 dholland * nfsnode. There is the potential for another process on a different client 2389 1.1 dholland * to create the same funny name between the nfs_lookitup() fails and the 2390 1.1 dholland * nfs_rename() completes, but... 2391 1.1 dholland */ 2392 1.1 dholland static int 2393 1.1 dholland nfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) 2394 1.1 dholland { 2395 1.1 dholland struct sillyrename *sp; 2396 1.1 dholland struct nfsnode *np; 2397 1.1 dholland int error; 2398 1.1 dholland short pid; 2399 1.1 dholland unsigned int lticks; 2400 1.1 dholland 2401 1.1 dholland cache_purge(dvp); 2402 1.1 dholland np = VTONFS(vp); 2403 1.1 dholland KASSERT(vp->v_type != VDIR, ("nfs: sillyrename dir")); 2404 1.1 dholland MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename), 2405 1.1 dholland M_NEWNFSREQ, M_WAITOK); 2406 1.1 dholland sp->s_cred = crhold(cnp->cn_cred); 2407 1.1 dholland sp->s_dvp = dvp; 2408 1.1 dholland VREF(dvp); 2409 1.1 dholland 2410 1.1 dholland /* 2411 1.1 dholland * Fudge together a funny name. 2412 1.3 pgoyette * Changing the format of the funny name to accommodate more 2413 1.1 dholland * sillynames per directory. 2414 1.1 dholland * The name is now changed to .nfs.<ticks>.<pid>.4, where ticks is 2415 1.1 dholland * CPU ticks since boot. 2416 1.1 dholland */ 2417 1.1 dholland pid = cnp->cn_thread->td_proc->p_pid; 2418 1.1 dholland lticks = (unsigned int)ticks; 2419 1.1 dholland for ( ; ; ) { 2420 1.2 christos sp->s_namlen = snprintf(sp->s_name, sizeof(sp->s_name), 2421 1.1 dholland ".nfs.%08x.%04x4.4", lticks, 2422 1.1 dholland pid); 2423 1.1 dholland if (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 2424 1.1 dholland cnp->cn_thread, NULL)) 2425 1.1 dholland break; 2426 1.1 dholland lticks++; 2427 1.1 dholland } 2428 1.1 dholland error = nfs_renameit(dvp, vp, cnp, sp); 2429 1.1 dholland if (error) 2430 1.1 dholland goto bad; 2431 1.1 dholland error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 2432 1.1 dholland cnp->cn_thread, &np); 2433 1.1 dholland np->n_sillyrename = sp; 2434 1.1 dholland return (0); 2435 1.1 dholland bad: 2436 1.1 dholland vrele(sp->s_dvp); 2437 1.1 dholland crfree(sp->s_cred); 2438 1.1 dholland free((caddr_t)sp, M_NEWNFSREQ); 2439 1.1 dholland return (error); 2440 1.1 dholland } 2441 1.1 dholland 2442 1.1 dholland /* 2443 1.1 dholland * Look up a file name and optionally either update the file handle or 2444 1.1 dholland * allocate an nfsnode, depending on the value of npp. 2445 1.1 dholland * npp == NULL --> just do the lookup 2446 1.1 dholland * *npp == NULL --> allocate a new nfsnode and make sure attributes are 2447 1.1 dholland * handled too 2448 1.1 dholland * *npp != NULL --> update the file handle in the vnode 2449 1.1 dholland */ 2450 1.1 dholland static int 2451 1.1 dholland nfs_lookitup(struct vnode *dvp, char *name, int len, struct ucred *cred, 2452 1.1 dholland struct thread *td, struct nfsnode **npp) 2453 1.1 dholland { 2454 1.1 dholland struct vnode *newvp = NULL, *vp; 2455 1.1 dholland struct nfsnode *np, *dnp = VTONFS(dvp); 2456 1.1 dholland struct nfsfh *nfhp, *onfhp; 2457 1.1 dholland struct nfsvattr nfsva, dnfsva; 2458 1.1 dholland struct componentname cn; 2459 1.1 dholland int error = 0, attrflag, dattrflag; 2460 1.1 dholland u_int hash; 2461 1.1 dholland 2462 1.1 dholland error = nfsrpc_lookup(dvp, name, len, cred, td, &dnfsva, &nfsva, 2463 1.1 dholland &nfhp, &attrflag, &dattrflag, NULL); 2464 1.1 dholland if (dattrflag) 2465 1.1 dholland (void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1); 2466 1.1 dholland if (npp && !error) { 2467 1.1 dholland if (*npp != NULL) { 2468 1.1 dholland np = *npp; 2469 1.1 dholland vp = NFSTOV(np); 2470 1.1 dholland /* 2471 1.1 dholland * For NFSv4, check to see if it is the same name and 2472 1.1 dholland * replace the name, if it is different. 2473 1.1 dholland */ 2474 1.1 dholland if (np->n_v4 != NULL && nfsva.na_type == VREG && 2475 1.1 dholland (np->n_v4->n4_namelen != len || 2476 1.1 dholland NFSBCMP(name, NFS4NODENAME(np->n_v4), len) || 2477 1.1 dholland dnp->n_fhp->nfh_len != np->n_v4->n4_fhlen || 2478 1.1 dholland NFSBCMP(dnp->n_fhp->nfh_fh, np->n_v4->n4_data, 2479 1.1 dholland dnp->n_fhp->nfh_len))) { 2480 1.1 dholland #ifdef notdef 2481 1.1 dholland { char nnn[100]; int nnnl; 2482 1.1 dholland nnnl = (len < 100) ? len : 99; 2483 1.1 dholland bcopy(name, nnn, nnnl); 2484 1.1 dholland nnn[nnnl] = '\0'; 2485 1.1 dholland printf("replace=%s\n",nnn); 2486 1.1 dholland } 2487 1.1 dholland #endif 2488 1.1 dholland FREE((caddr_t)np->n_v4, M_NFSV4NODE); 2489 1.1 dholland MALLOC(np->n_v4, struct nfsv4node *, 2490 1.1 dholland sizeof (struct nfsv4node) + 2491 1.1 dholland dnp->n_fhp->nfh_len + len - 1, 2492 1.1 dholland M_NFSV4NODE, M_WAITOK); 2493 1.1 dholland np->n_v4->n4_fhlen = dnp->n_fhp->nfh_len; 2494 1.1 dholland np->n_v4->n4_namelen = len; 2495 1.1 dholland NFSBCOPY(dnp->n_fhp->nfh_fh, np->n_v4->n4_data, 2496 1.1 dholland dnp->n_fhp->nfh_len); 2497 1.1 dholland NFSBCOPY(name, NFS4NODENAME(np->n_v4), len); 2498 1.1 dholland } 2499 1.1 dholland hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, 2500 1.1 dholland FNV1_32_INIT); 2501 1.1 dholland onfhp = np->n_fhp; 2502 1.1 dholland /* 2503 1.1 dholland * Rehash node for new file handle. 2504 1.1 dholland */ 2505 1.1 dholland vfs_hash_rehash(vp, hash); 2506 1.1 dholland np->n_fhp = nfhp; 2507 1.1 dholland if (onfhp != NULL) 2508 1.1 dholland FREE((caddr_t)onfhp, M_NFSFH); 2509 1.1 dholland newvp = NFSTOV(np); 2510 1.1 dholland } else if (NFS_CMPFH(dnp, nfhp->nfh_fh, nfhp->nfh_len)) { 2511 1.1 dholland FREE((caddr_t)nfhp, M_NFSFH); 2512 1.1 dholland VREF(dvp); 2513 1.1 dholland newvp = dvp; 2514 1.1 dholland } else { 2515 1.1 dholland cn.cn_nameptr = name; 2516 1.1 dholland cn.cn_namelen = len; 2517 1.1 dholland error = nfscl_nget(dvp->v_mount, dvp, nfhp, &cn, td, 2518 1.1 dholland &np, NULL, LK_EXCLUSIVE); 2519 1.1 dholland if (error) 2520 1.1 dholland return (error); 2521 1.1 dholland newvp = NFSTOV(np); 2522 1.1 dholland } 2523 1.1 dholland if (!attrflag && *npp == NULL) { 2524 1.1 dholland if (newvp == dvp) 2525 1.1 dholland vrele(newvp); 2526 1.1 dholland else 2527 1.1 dholland vput(newvp); 2528 1.1 dholland return (ENOENT); 2529 1.1 dholland } 2530 1.1 dholland if (attrflag) 2531 1.1 dholland (void) nfscl_loadattrcache(&newvp, &nfsva, NULL, NULL, 2532 1.1 dholland 0, 1); 2533 1.1 dholland } 2534 1.1 dholland if (npp && *npp == NULL) { 2535 1.1 dholland if (error) { 2536 1.1 dholland if (newvp) { 2537 1.1 dholland if (newvp == dvp) 2538 1.1 dholland vrele(newvp); 2539 1.1 dholland else 2540 1.1 dholland vput(newvp); 2541 1.1 dholland } 2542 1.1 dholland } else 2543 1.1 dholland *npp = np; 2544 1.1 dholland } 2545 1.1 dholland if (error && NFS_ISV4(dvp)) 2546 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2547 1.1 dholland return (error); 2548 1.1 dholland } 2549 1.1 dholland 2550 1.1 dholland /* 2551 1.1 dholland * Nfs Version 3 and 4 commit rpc 2552 1.1 dholland */ 2553 1.1 dholland int 2554 1.1 dholland ncl_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred, 2555 1.1 dholland struct thread *td) 2556 1.1 dholland { 2557 1.1 dholland struct nfsvattr nfsva; 2558 1.1 dholland struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2559 1.1 dholland int error, attrflag; 2560 1.1 dholland 2561 1.1 dholland mtx_lock(&nmp->nm_mtx); 2562 1.1 dholland if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0) { 2563 1.1 dholland mtx_unlock(&nmp->nm_mtx); 2564 1.1 dholland return (0); 2565 1.1 dholland } 2566 1.1 dholland mtx_unlock(&nmp->nm_mtx); 2567 1.1 dholland error = nfsrpc_commit(vp, offset, cnt, cred, td, &nfsva, 2568 1.1 dholland &attrflag, NULL); 2569 1.1 dholland if (attrflag != 0) 2570 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 2571 1.1 dholland 0, 1); 2572 1.1 dholland if (error != 0 && NFS_ISV4(vp)) 2573 1.1 dholland error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 2574 1.1 dholland return (error); 2575 1.1 dholland } 2576 1.1 dholland 2577 1.1 dholland /* 2578 1.1 dholland * Strategy routine. 2579 1.1 dholland * For async requests when nfsiod(s) are running, queue the request by 2580 1.1 dholland * calling ncl_asyncio(), otherwise just all ncl_doio() to do the 2581 1.1 dholland * request. 2582 1.1 dholland */ 2583 1.1 dholland static int 2584 1.1 dholland nfs_strategy(struct vop_strategy_args *ap) 2585 1.1 dholland { 2586 1.1 dholland struct buf *bp = ap->a_bp; 2587 1.1 dholland struct ucred *cr; 2588 1.1 dholland 2589 1.1 dholland KASSERT(!(bp->b_flags & B_DONE), 2590 1.1 dholland ("nfs_strategy: buffer %p unexpectedly marked B_DONE", bp)); 2591 1.1 dholland BUF_ASSERT_HELD(bp); 2592 1.1 dholland 2593 1.1 dholland if (bp->b_iocmd == BIO_READ) 2594 1.1 dholland cr = bp->b_rcred; 2595 1.1 dholland else 2596 1.1 dholland cr = bp->b_wcred; 2597 1.1 dholland 2598 1.1 dholland /* 2599 1.1 dholland * If the op is asynchronous and an i/o daemon is waiting 2600 1.1 dholland * queue the request, wake it up and wait for completion 2601 1.1 dholland * otherwise just do it ourselves. 2602 1.1 dholland */ 2603 1.1 dholland if ((bp->b_flags & B_ASYNC) == 0 || 2604 1.1 dholland ncl_asyncio(VFSTONFS(ap->a_vp->v_mount), bp, NOCRED, curthread)) 2605 1.1 dholland (void) ncl_doio(ap->a_vp, bp, cr, curthread, 1); 2606 1.1 dholland return (0); 2607 1.1 dholland } 2608 1.1 dholland 2609 1.1 dholland /* 2610 1.1 dholland * fsync vnode op. Just call ncl_flush() with commit == 1. 2611 1.1 dholland */ 2612 1.1 dholland /* ARGSUSED */ 2613 1.1 dholland static int 2614 1.1 dholland nfs_fsync(struct vop_fsync_args *ap) 2615 1.1 dholland { 2616 1.1 dholland 2617 1.1 dholland if (ap->a_vp->v_type != VREG) { 2618 1.1 dholland /* 2619 1.1 dholland * For NFS, metadata is changed synchronously on the server, 2620 1.1 dholland * so there is nothing to flush. Also, ncl_flush() clears 2621 1.1 dholland * the NMODIFIED flag and that shouldn't be done here for 2622 1.1 dholland * directories. 2623 1.1 dholland */ 2624 1.1 dholland return (0); 2625 1.1 dholland } 2626 1.1 dholland return (ncl_flush(ap->a_vp, ap->a_waitfor, NULL, ap->a_td, 1, 0)); 2627 1.1 dholland } 2628 1.1 dholland 2629 1.1 dholland /* 2630 1.1 dholland * Flush all the blocks associated with a vnode. 2631 1.1 dholland * Walk through the buffer pool and push any dirty pages 2632 1.1 dholland * associated with the vnode. 2633 1.1 dholland * If the called_from_renewthread argument is TRUE, it has been called 2634 1.1 dholland * from the NFSv4 renew thread and, as such, cannot block indefinitely 2635 1.1 dholland * waiting for a buffer write to complete. 2636 1.1 dholland */ 2637 1.1 dholland int 2638 1.1 dholland ncl_flush(struct vnode *vp, int waitfor, struct ucred *cred, struct thread *td, 2639 1.1 dholland int commit, int called_from_renewthread) 2640 1.1 dholland { 2641 1.1 dholland struct nfsnode *np = VTONFS(vp); 2642 1.1 dholland struct buf *bp; 2643 1.1 dholland int i; 2644 1.1 dholland struct buf *nbp; 2645 1.1 dholland struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2646 1.1 dholland int error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos; 2647 1.1 dholland int passone = 1, trycnt = 0; 2648 1.1 dholland u_quad_t off, endoff, toff; 2649 1.1 dholland struct ucred* wcred = NULL; 2650 1.1 dholland struct buf **bvec = NULL; 2651 1.1 dholland struct bufobj *bo; 2652 1.1 dholland #ifndef NFS_COMMITBVECSIZ 2653 1.1 dholland #define NFS_COMMITBVECSIZ 20 2654 1.1 dholland #endif 2655 1.1 dholland struct buf *bvec_on_stack[NFS_COMMITBVECSIZ]; 2656 1.1 dholland int bvecsize = 0, bveccount; 2657 1.1 dholland 2658 1.1 dholland if (called_from_renewthread != 0) 2659 1.1 dholland slptimeo = hz; 2660 1.1 dholland if (nmp->nm_flag & NFSMNT_INT) 2661 1.1 dholland slpflag = PCATCH; 2662 1.1 dholland if (!commit) 2663 1.1 dholland passone = 0; 2664 1.1 dholland bo = &vp->v_bufobj; 2665 1.1 dholland /* 2666 1.1 dholland * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the 2667 1.1 dholland * server, but has not been committed to stable storage on the server 2668 1.1 dholland * yet. On the first pass, the byte range is worked out and the commit 2669 1.1 dholland * rpc is done. On the second pass, ncl_writebp() is called to do the 2670 1.1 dholland * job. 2671 1.1 dholland */ 2672 1.1 dholland again: 2673 1.1 dholland off = (u_quad_t)-1; 2674 1.1 dholland endoff = 0; 2675 1.1 dholland bvecpos = 0; 2676 1.1 dholland if (NFS_ISV34(vp) && commit) { 2677 1.1 dholland if (bvec != NULL && bvec != bvec_on_stack) 2678 1.1 dholland free(bvec, M_TEMP); 2679 1.1 dholland /* 2680 1.1 dholland * Count up how many buffers waiting for a commit. 2681 1.1 dholland */ 2682 1.1 dholland bveccount = 0; 2683 1.1 dholland BO_LOCK(bo); 2684 1.1 dholland TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 2685 1.1 dholland if (!BUF_ISLOCKED(bp) && 2686 1.1 dholland (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 2687 1.1 dholland == (B_DELWRI | B_NEEDCOMMIT)) 2688 1.1 dholland bveccount++; 2689 1.1 dholland } 2690 1.1 dholland /* 2691 1.1 dholland * Allocate space to remember the list of bufs to commit. It is 2692 1.1 dholland * important to use M_NOWAIT here to avoid a race with nfs_write. 2693 1.1 dholland * If we can't get memory (for whatever reason), we will end up 2694 1.1 dholland * committing the buffers one-by-one in the loop below. 2695 1.1 dholland */ 2696 1.1 dholland if (bveccount > NFS_COMMITBVECSIZ) { 2697 1.1 dholland /* 2698 1.1 dholland * Release the vnode interlock to avoid a lock 2699 1.1 dholland * order reversal. 2700 1.1 dholland */ 2701 1.1 dholland BO_UNLOCK(bo); 2702 1.1 dholland bvec = (struct buf **) 2703 1.1 dholland malloc(bveccount * sizeof(struct buf *), 2704 1.1 dholland M_TEMP, M_NOWAIT); 2705 1.1 dholland BO_LOCK(bo); 2706 1.1 dholland if (bvec == NULL) { 2707 1.1 dholland bvec = bvec_on_stack; 2708 1.1 dholland bvecsize = NFS_COMMITBVECSIZ; 2709 1.1 dholland } else 2710 1.1 dholland bvecsize = bveccount; 2711 1.1 dholland } else { 2712 1.1 dholland bvec = bvec_on_stack; 2713 1.1 dholland bvecsize = NFS_COMMITBVECSIZ; 2714 1.1 dholland } 2715 1.1 dholland TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 2716 1.1 dholland if (bvecpos >= bvecsize) 2717 1.1 dholland break; 2718 1.1 dholland if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { 2719 1.1 dholland nbp = TAILQ_NEXT(bp, b_bobufs); 2720 1.1 dholland continue; 2721 1.1 dholland } 2722 1.1 dholland if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) != 2723 1.1 dholland (B_DELWRI | B_NEEDCOMMIT)) { 2724 1.1 dholland BUF_UNLOCK(bp); 2725 1.1 dholland nbp = TAILQ_NEXT(bp, b_bobufs); 2726 1.1 dholland continue; 2727 1.1 dholland } 2728 1.1 dholland BO_UNLOCK(bo); 2729 1.1 dholland bremfree(bp); 2730 1.1 dholland /* 2731 1.1 dholland * Work out if all buffers are using the same cred 2732 1.1 dholland * so we can deal with them all with one commit. 2733 1.1 dholland * 2734 1.1 dholland * NOTE: we are not clearing B_DONE here, so we have 2735 1.1 dholland * to do it later on in this routine if we intend to 2736 1.1 dholland * initiate I/O on the bp. 2737 1.1 dholland * 2738 1.1 dholland * Note: to avoid loopback deadlocks, we do not 2739 1.1 dholland * assign b_runningbufspace. 2740 1.1 dholland */ 2741 1.1 dholland if (wcred == NULL) 2742 1.1 dholland wcred = bp->b_wcred; 2743 1.1 dholland else if (wcred != bp->b_wcred) 2744 1.1 dholland wcred = NOCRED; 2745 1.1 dholland vfs_busy_pages(bp, 1); 2746 1.1 dholland 2747 1.1 dholland BO_LOCK(bo); 2748 1.1 dholland /* 2749 1.1 dholland * bp is protected by being locked, but nbp is not 2750 1.1 dholland * and vfs_busy_pages() may sleep. We have to 2751 1.1 dholland * recalculate nbp. 2752 1.1 dholland */ 2753 1.1 dholland nbp = TAILQ_NEXT(bp, b_bobufs); 2754 1.1 dholland 2755 1.1 dholland /* 2756 1.1 dholland * A list of these buffers is kept so that the 2757 1.1 dholland * second loop knows which buffers have actually 2758 1.1 dholland * been committed. This is necessary, since there 2759 1.1 dholland * may be a race between the commit rpc and new 2760 1.1 dholland * uncommitted writes on the file. 2761 1.1 dholland */ 2762 1.1 dholland bvec[bvecpos++] = bp; 2763 1.1 dholland toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + 2764 1.1 dholland bp->b_dirtyoff; 2765 1.1 dholland if (toff < off) 2766 1.1 dholland off = toff; 2767 1.1 dholland toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff); 2768 1.1 dholland if (toff > endoff) 2769 1.1 dholland endoff = toff; 2770 1.1 dholland } 2771 1.1 dholland BO_UNLOCK(bo); 2772 1.1 dholland } 2773 1.1 dholland if (bvecpos > 0) { 2774 1.1 dholland /* 2775 1.1 dholland * Commit data on the server, as required. 2776 1.1 dholland * If all bufs are using the same wcred, then use that with 2777 1.1 dholland * one call for all of them, otherwise commit each one 2778 1.1 dholland * separately. 2779 1.1 dholland */ 2780 1.1 dholland if (wcred != NOCRED) 2781 1.1 dholland retv = ncl_commit(vp, off, (int)(endoff - off), 2782 1.1 dholland wcred, td); 2783 1.1 dholland else { 2784 1.1 dholland retv = 0; 2785 1.1 dholland for (i = 0; i < bvecpos; i++) { 2786 1.1 dholland off_t off, size; 2787 1.1 dholland bp = bvec[i]; 2788 1.1 dholland off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + 2789 1.1 dholland bp->b_dirtyoff; 2790 1.1 dholland size = (u_quad_t)(bp->b_dirtyend 2791 1.1 dholland - bp->b_dirtyoff); 2792 1.1 dholland retv = ncl_commit(vp, off, (int)size, 2793 1.1 dholland bp->b_wcred, td); 2794 1.1 dholland if (retv) break; 2795 1.1 dholland } 2796 1.1 dholland } 2797 1.1 dholland 2798 1.1 dholland if (retv == NFSERR_STALEWRITEVERF) 2799 1.1 dholland ncl_clearcommit(vp->v_mount); 2800 1.1 dholland 2801 1.1 dholland /* 2802 1.1 dholland * Now, either mark the blocks I/O done or mark the 2803 1.1 dholland * blocks dirty, depending on whether the commit 2804 1.1 dholland * succeeded. 2805 1.1 dholland */ 2806 1.1 dholland for (i = 0; i < bvecpos; i++) { 2807 1.1 dholland bp = bvec[i]; 2808 1.1 dholland bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 2809 1.1 dholland if (retv) { 2810 1.1 dholland /* 2811 1.1 dholland * Error, leave B_DELWRI intact 2812 1.1 dholland */ 2813 1.1 dholland vfs_unbusy_pages(bp); 2814 1.1 dholland brelse(bp); 2815 1.1 dholland } else { 2816 1.1 dholland /* 2817 1.1 dholland * Success, remove B_DELWRI ( bundirty() ). 2818 1.1 dholland * 2819 1.1 dholland * b_dirtyoff/b_dirtyend seem to be NFS 2820 1.1 dholland * specific. We should probably move that 2821 1.1 dholland * into bundirty(). XXX 2822 1.1 dholland */ 2823 1.1 dholland bufobj_wref(bo); 2824 1.1 dholland bp->b_flags |= B_ASYNC; 2825 1.1 dholland bundirty(bp); 2826 1.1 dholland bp->b_flags &= ~B_DONE; 2827 1.1 dholland bp->b_ioflags &= ~BIO_ERROR; 2828 1.1 dholland bp->b_dirtyoff = bp->b_dirtyend = 0; 2829 1.1 dholland bufdone(bp); 2830 1.1 dholland } 2831 1.1 dholland } 2832 1.1 dholland } 2833 1.1 dholland 2834 1.1 dholland /* 2835 1.1 dholland * Start/do any write(s) that are required. 2836 1.1 dholland */ 2837 1.1 dholland loop: 2838 1.1 dholland BO_LOCK(bo); 2839 1.1 dholland TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 2840 1.1 dholland if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) { 2841 1.1 dholland if (waitfor != MNT_WAIT || passone) 2842 1.1 dholland continue; 2843 1.1 dholland 2844 1.1 dholland error = BUF_TIMELOCK(bp, 2845 1.1 dholland LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, 2846 1.1 dholland BO_LOCKPTR(bo), "nfsfsync", slpflag, slptimeo); 2847 1.1 dholland if (error == 0) { 2848 1.1 dholland BUF_UNLOCK(bp); 2849 1.1 dholland goto loop; 2850 1.1 dholland } 2851 1.1 dholland if (error == ENOLCK) { 2852 1.1 dholland error = 0; 2853 1.1 dholland goto loop; 2854 1.1 dholland } 2855 1.1 dholland if (called_from_renewthread != 0) { 2856 1.1 dholland /* 2857 1.1 dholland * Return EIO so the flush will be retried 2858 1.1 dholland * later. 2859 1.1 dholland */ 2860 1.1 dholland error = EIO; 2861 1.1 dholland goto done; 2862 1.1 dholland } 2863 1.1 dholland if (newnfs_sigintr(nmp, td)) { 2864 1.1 dholland error = EINTR; 2865 1.1 dholland goto done; 2866 1.1 dholland } 2867 1.1 dholland if (slpflag == PCATCH) { 2868 1.1 dholland slpflag = 0; 2869 1.1 dholland slptimeo = 2 * hz; 2870 1.1 dholland } 2871 1.1 dholland goto loop; 2872 1.1 dholland } 2873 1.1 dholland if ((bp->b_flags & B_DELWRI) == 0) 2874 1.1 dholland panic("nfs_fsync: not dirty"); 2875 1.1 dholland if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) { 2876 1.1 dholland BUF_UNLOCK(bp); 2877 1.1 dholland continue; 2878 1.1 dholland } 2879 1.1 dholland BO_UNLOCK(bo); 2880 1.1 dholland bremfree(bp); 2881 1.1 dholland if (passone || !commit) 2882 1.1 dholland bp->b_flags |= B_ASYNC; 2883 1.1 dholland else 2884 1.1 dholland bp->b_flags |= B_ASYNC; 2885 1.1 dholland bwrite(bp); 2886 1.1 dholland if (newnfs_sigintr(nmp, td)) { 2887 1.1 dholland error = EINTR; 2888 1.1 dholland goto done; 2889 1.1 dholland } 2890 1.1 dholland goto loop; 2891 1.1 dholland } 2892 1.1 dholland if (passone) { 2893 1.1 dholland passone = 0; 2894 1.1 dholland BO_UNLOCK(bo); 2895 1.1 dholland goto again; 2896 1.1 dholland } 2897 1.1 dholland if (waitfor == MNT_WAIT) { 2898 1.1 dholland while (bo->bo_numoutput) { 2899 1.1 dholland error = bufobj_wwait(bo, slpflag, slptimeo); 2900 1.1 dholland if (error) { 2901 1.1 dholland BO_UNLOCK(bo); 2902 1.1 dholland if (called_from_renewthread != 0) { 2903 1.1 dholland /* 2904 1.1 dholland * Return EIO so that the flush will be 2905 1.1 dholland * retried later. 2906 1.1 dholland */ 2907 1.1 dholland error = EIO; 2908 1.1 dholland goto done; 2909 1.1 dholland } 2910 1.1 dholland error = newnfs_sigintr(nmp, td); 2911 1.1 dholland if (error) 2912 1.1 dholland goto done; 2913 1.1 dholland if (slpflag == PCATCH) { 2914 1.1 dholland slpflag = 0; 2915 1.1 dholland slptimeo = 2 * hz; 2916 1.1 dholland } 2917 1.1 dholland BO_LOCK(bo); 2918 1.1 dholland } 2919 1.1 dholland } 2920 1.1 dholland if (bo->bo_dirty.bv_cnt != 0 && commit) { 2921 1.1 dholland BO_UNLOCK(bo); 2922 1.1 dholland goto loop; 2923 1.1 dholland } 2924 1.1 dholland /* 2925 1.1 dholland * Wait for all the async IO requests to drain 2926 1.1 dholland */ 2927 1.1 dholland BO_UNLOCK(bo); 2928 1.1 dholland mtx_lock(&np->n_mtx); 2929 1.1 dholland while (np->n_directio_asyncwr > 0) { 2930 1.1 dholland np->n_flag |= NFSYNCWAIT; 2931 1.1 dholland error = newnfs_msleep(td, &np->n_directio_asyncwr, 2932 1.1 dholland &np->n_mtx, slpflag | (PRIBIO + 1), 2933 1.1 dholland "nfsfsync", 0); 2934 1.1 dholland if (error) { 2935 1.1 dholland if (newnfs_sigintr(nmp, td)) { 2936 1.1 dholland mtx_unlock(&np->n_mtx); 2937 1.1 dholland error = EINTR; 2938 1.1 dholland goto done; 2939 1.1 dholland } 2940 1.1 dholland } 2941 1.1 dholland } 2942 1.1 dholland mtx_unlock(&np->n_mtx); 2943 1.1 dholland } else 2944 1.1 dholland BO_UNLOCK(bo); 2945 1.1 dholland if (NFSHASPNFS(nmp)) { 2946 1.1 dholland nfscl_layoutcommit(vp, td); 2947 1.1 dholland /* 2948 1.1 dholland * Invalidate the attribute cache, since writes to a DS 2949 1.1 dholland * won't update the size attribute. 2950 1.1 dholland */ 2951 1.1 dholland mtx_lock(&np->n_mtx); 2952 1.1 dholland np->n_attrstamp = 0; 2953 1.1 dholland } else 2954 1.1 dholland mtx_lock(&np->n_mtx); 2955 1.1 dholland if (np->n_flag & NWRITEERR) { 2956 1.1 dholland error = np->n_error; 2957 1.1 dholland np->n_flag &= ~NWRITEERR; 2958 1.1 dholland } 2959 1.1 dholland if (commit && bo->bo_dirty.bv_cnt == 0 && 2960 1.1 dholland bo->bo_numoutput == 0 && np->n_directio_asyncwr == 0) 2961 1.1 dholland np->n_flag &= ~NMODIFIED; 2962 1.1 dholland mtx_unlock(&np->n_mtx); 2963 1.1 dholland done: 2964 1.1 dholland if (bvec != NULL && bvec != bvec_on_stack) 2965 1.1 dholland free(bvec, M_TEMP); 2966 1.1 dholland if (error == 0 && commit != 0 && waitfor == MNT_WAIT && 2967 1.1 dholland (bo->bo_dirty.bv_cnt != 0 || bo->bo_numoutput != 0 || 2968 1.1 dholland np->n_directio_asyncwr != 0) && trycnt++ < 5) { 2969 1.1 dholland /* try, try again... */ 2970 1.1 dholland passone = 1; 2971 1.1 dholland wcred = NULL; 2972 1.1 dholland bvec = NULL; 2973 1.1 dholland bvecsize = 0; 2974 1.1 dholland printf("try%d\n", trycnt); 2975 1.1 dholland goto again; 2976 1.1 dholland } 2977 1.1 dholland return (error); 2978 1.1 dholland } 2979 1.1 dholland 2980 1.1 dholland /* 2981 1.1 dholland * NFS advisory byte-level locks. 2982 1.1 dholland */ 2983 1.1 dholland static int 2984 1.1 dholland nfs_advlock(struct vop_advlock_args *ap) 2985 1.1 dholland { 2986 1.1 dholland struct vnode *vp = ap->a_vp; 2987 1.1 dholland struct ucred *cred; 2988 1.1 dholland struct nfsnode *np = VTONFS(ap->a_vp); 2989 1.1 dholland struct proc *p = (struct proc *)ap->a_id; 2990 1.1 dholland struct thread *td = curthread; /* XXX */ 2991 1.1 dholland struct vattr va; 2992 1.1 dholland int ret, error = EOPNOTSUPP; 2993 1.1 dholland u_quad_t size; 2994 1.1 dholland 2995 1.1 dholland if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) { 2996 1.1 dholland if (vp->v_type != VREG) 2997 1.1 dholland return (EINVAL); 2998 1.1 dholland if ((ap->a_flags & F_POSIX) != 0) 2999 1.1 dholland cred = p->p_ucred; 3000 1.1 dholland else 3001 1.1 dholland cred = td->td_ucred; 3002 1.1 dholland NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3003 1.1 dholland if (vp->v_iflag & VI_DOOMED) { 3004 1.1 dholland NFSVOPUNLOCK(vp, 0); 3005 1.1 dholland return (EBADF); 3006 1.1 dholland } 3007 1.1 dholland 3008 1.1 dholland /* 3009 1.1 dholland * If this is unlocking a write locked region, flush and 3010 1.1 dholland * commit them before unlocking. This is required by 3011 1.1 dholland * RFC3530 Sec. 9.3.2. 3012 1.1 dholland */ 3013 1.1 dholland if (ap->a_op == F_UNLCK && 3014 1.1 dholland nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id, 3015 1.1 dholland ap->a_flags)) 3016 1.1 dholland (void) ncl_flush(vp, MNT_WAIT, cred, td, 1, 0); 3017 1.1 dholland 3018 1.1 dholland /* 3019 1.1 dholland * Loop around doing the lock op, while a blocking lock 3020 1.1 dholland * must wait for the lock op to succeed. 3021 1.1 dholland */ 3022 1.1 dholland do { 3023 1.1 dholland ret = nfsrpc_advlock(vp, np->n_size, ap->a_op, 3024 1.1 dholland ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags); 3025 1.1 dholland if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && 3026 1.1 dholland ap->a_op == F_SETLK) { 3027 1.1 dholland NFSVOPUNLOCK(vp, 0); 3028 1.1 dholland error = nfs_catnap(PZERO | PCATCH, ret, 3029 1.1 dholland "ncladvl"); 3030 1.1 dholland if (error) 3031 1.1 dholland return (EINTR); 3032 1.1 dholland NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3033 1.1 dholland if (vp->v_iflag & VI_DOOMED) { 3034 1.1 dholland NFSVOPUNLOCK(vp, 0); 3035 1.1 dholland return (EBADF); 3036 1.1 dholland } 3037 1.1 dholland } 3038 1.1 dholland } while (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) && 3039 1.1 dholland ap->a_op == F_SETLK); 3040 1.1 dholland if (ret == NFSERR_DENIED) { 3041 1.1 dholland NFSVOPUNLOCK(vp, 0); 3042 1.1 dholland return (EAGAIN); 3043 1.1 dholland } else if (ret == EINVAL || ret == EBADF || ret == EINTR) { 3044 1.1 dholland NFSVOPUNLOCK(vp, 0); 3045 1.1 dholland return (ret); 3046 1.1 dholland } else if (ret != 0) { 3047 1.1 dholland NFSVOPUNLOCK(vp, 0); 3048 1.1 dholland return (EACCES); 3049 1.1 dholland } 3050 1.1 dholland 3051 1.1 dholland /* 3052 1.1 dholland * Now, if we just got a lock, invalidate data in the buffer 3053 1.1 dholland * cache, as required, so that the coherency conforms with 3054 1.1 dholland * RFC3530 Sec. 9.3.2. 3055 1.1 dholland */ 3056 1.1 dholland if (ap->a_op == F_SETLK) { 3057 1.1 dholland if ((np->n_flag & NMODIFIED) == 0) { 3058 1.1 dholland np->n_attrstamp = 0; 3059 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 3060 1.1 dholland ret = VOP_GETATTR(vp, &va, cred); 3061 1.1 dholland } 3062 1.1 dholland if ((np->n_flag & NMODIFIED) || ret || 3063 1.1 dholland np->n_change != va.va_filerev) { 3064 1.1 dholland (void) ncl_vinvalbuf(vp, V_SAVE, td, 1); 3065 1.1 dholland np->n_attrstamp = 0; 3066 1.1 dholland KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); 3067 1.1 dholland ret = VOP_GETATTR(vp, &va, cred); 3068 1.1 dholland if (!ret) { 3069 1.1 dholland np->n_mtime = va.va_mtime; 3070 1.1 dholland np->n_change = va.va_filerev; 3071 1.1 dholland } 3072 1.1 dholland } 3073 1.3 pgoyette /* Mark that a file lock has been acquired. */ 3074 1.3 pgoyette mtx_lock(&np->n_mtx); 3075 1.3 pgoyette np->n_flag |= NHASBEENLOCKED; 3076 1.3 pgoyette mtx_unlock(&np->n_mtx); 3077 1.1 dholland } 3078 1.1 dholland NFSVOPUNLOCK(vp, 0); 3079 1.1 dholland return (0); 3080 1.1 dholland } else if (!NFS_ISV4(vp)) { 3081 1.1 dholland error = NFSVOPLOCK(vp, LK_SHARED); 3082 1.1 dholland if (error) 3083 1.1 dholland return (error); 3084 1.1 dholland if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { 3085 1.1 dholland size = VTONFS(vp)->n_size; 3086 1.1 dholland NFSVOPUNLOCK(vp, 0); 3087 1.1 dholland error = lf_advlock(ap, &(vp->v_lockf), size); 3088 1.1 dholland } else { 3089 1.1 dholland if (nfs_advlock_p != NULL) 3090 1.1 dholland error = nfs_advlock_p(ap); 3091 1.1 dholland else { 3092 1.1 dholland NFSVOPUNLOCK(vp, 0); 3093 1.1 dholland error = ENOLCK; 3094 1.1 dholland } 3095 1.1 dholland } 3096 1.3 pgoyette if (error == 0 && ap->a_op == F_SETLK) { 3097 1.3 pgoyette error = NFSVOPLOCK(vp, LK_SHARED); 3098 1.3 pgoyette if (error == 0) { 3099 1.3 pgoyette /* Mark that a file lock has been acquired. */ 3100 1.3 pgoyette mtx_lock(&np->n_mtx); 3101 1.3 pgoyette np->n_flag |= NHASBEENLOCKED; 3102 1.3 pgoyette mtx_unlock(&np->n_mtx); 3103 1.3 pgoyette NFSVOPUNLOCK(vp, 0); 3104 1.3 pgoyette } 3105 1.3 pgoyette } 3106 1.1 dholland } 3107 1.1 dholland return (error); 3108 1.1 dholland } 3109 1.1 dholland 3110 1.1 dholland /* 3111 1.1 dholland * NFS advisory byte-level locks. 3112 1.1 dholland */ 3113 1.1 dholland static int 3114 1.1 dholland nfs_advlockasync(struct vop_advlockasync_args *ap) 3115 1.1 dholland { 3116 1.1 dholland struct vnode *vp = ap->a_vp; 3117 1.1 dholland u_quad_t size; 3118 1.1 dholland int error; 3119 1.1 dholland 3120 1.1 dholland if (NFS_ISV4(vp)) 3121 1.1 dholland return (EOPNOTSUPP); 3122 1.1 dholland error = NFSVOPLOCK(vp, LK_SHARED); 3123 1.1 dholland if (error) 3124 1.1 dholland return (error); 3125 1.1 dholland if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) { 3126 1.1 dholland size = VTONFS(vp)->n_size; 3127 1.1 dholland NFSVOPUNLOCK(vp, 0); 3128 1.1 dholland error = lf_advlockasync(ap, &(vp->v_lockf), size); 3129 1.1 dholland } else { 3130 1.1 dholland NFSVOPUNLOCK(vp, 0); 3131 1.1 dholland error = EOPNOTSUPP; 3132 1.1 dholland } 3133 1.1 dholland return (error); 3134 1.1 dholland } 3135 1.1 dholland 3136 1.1 dholland /* 3137 1.1 dholland * Print out the contents of an nfsnode. 3138 1.1 dholland */ 3139 1.1 dholland static int 3140 1.1 dholland nfs_print(struct vop_print_args *ap) 3141 1.1 dholland { 3142 1.1 dholland struct vnode *vp = ap->a_vp; 3143 1.1 dholland struct nfsnode *np = VTONFS(vp); 3144 1.1 dholland 3145 1.3 pgoyette printf("\tfileid %ld fsid 0x%x", np->n_vattr.na_fileid, 3146 1.3 pgoyette np->n_vattr.na_fsid); 3147 1.1 dholland if (vp->v_type == VFIFO) 3148 1.1 dholland fifo_printinfo(vp); 3149 1.1 dholland printf("\n"); 3150 1.1 dholland return (0); 3151 1.1 dholland } 3152 1.1 dholland 3153 1.1 dholland /* 3154 1.1 dholland * This is the "real" nfs::bwrite(struct buf*). 3155 1.1 dholland * We set B_CACHE if this is a VMIO buffer. 3156 1.1 dholland */ 3157 1.1 dholland int 3158 1.1 dholland ncl_writebp(struct buf *bp, int force __unused, struct thread *td) 3159 1.1 dholland { 3160 1.1 dholland int s; 3161 1.1 dholland int oldflags = bp->b_flags; 3162 1.1 dholland #if 0 3163 1.1 dholland int retv = 1; 3164 1.1 dholland off_t off; 3165 1.1 dholland #endif 3166 1.1 dholland 3167 1.1 dholland BUF_ASSERT_HELD(bp); 3168 1.1 dholland 3169 1.1 dholland if (bp->b_flags & B_INVAL) { 3170 1.1 dholland brelse(bp); 3171 1.1 dholland return(0); 3172 1.1 dholland } 3173 1.1 dholland 3174 1.1 dholland bp->b_flags |= B_CACHE; 3175 1.1 dholland 3176 1.1 dholland /* 3177 1.1 dholland * Undirty the bp. We will redirty it later if the I/O fails. 3178 1.1 dholland */ 3179 1.1 dholland 3180 1.1 dholland s = splbio(); 3181 1.1 dholland bundirty(bp); 3182 1.1 dholland bp->b_flags &= ~B_DONE; 3183 1.1 dholland bp->b_ioflags &= ~BIO_ERROR; 3184 1.1 dholland bp->b_iocmd = BIO_WRITE; 3185 1.1 dholland 3186 1.1 dholland bufobj_wref(bp->b_bufobj); 3187 1.1 dholland curthread->td_ru.ru_oublock++; 3188 1.1 dholland splx(s); 3189 1.1 dholland 3190 1.1 dholland /* 3191 1.1 dholland * Note: to avoid loopback deadlocks, we do not 3192 1.1 dholland * assign b_runningbufspace. 3193 1.1 dholland */ 3194 1.1 dholland vfs_busy_pages(bp, 1); 3195 1.1 dholland 3196 1.1 dholland BUF_KERNPROC(bp); 3197 1.1 dholland bp->b_iooffset = dbtob(bp->b_blkno); 3198 1.1 dholland bstrategy(bp); 3199 1.1 dholland 3200 1.1 dholland if( (oldflags & B_ASYNC) == 0) { 3201 1.1 dholland int rtval = bufwait(bp); 3202 1.1 dholland 3203 1.1 dholland if (oldflags & B_DELWRI) { 3204 1.1 dholland s = splbio(); 3205 1.1 dholland reassignbuf(bp); 3206 1.1 dholland splx(s); 3207 1.1 dholland } 3208 1.1 dholland brelse(bp); 3209 1.1 dholland return (rtval); 3210 1.1 dholland } 3211 1.1 dholland 3212 1.1 dholland return (0); 3213 1.1 dholland } 3214 1.1 dholland 3215 1.1 dholland /* 3216 1.1 dholland * nfs special file access vnode op. 3217 1.1 dholland * Essentially just get vattr and then imitate iaccess() since the device is 3218 1.1 dholland * local to the client. 3219 1.1 dholland */ 3220 1.1 dholland static int 3221 1.1 dholland nfsspec_access(struct vop_access_args *ap) 3222 1.1 dholland { 3223 1.1 dholland struct vattr *vap; 3224 1.1 dholland struct ucred *cred = ap->a_cred; 3225 1.1 dholland struct vnode *vp = ap->a_vp; 3226 1.1 dholland accmode_t accmode = ap->a_accmode; 3227 1.1 dholland struct vattr vattr; 3228 1.1 dholland int error; 3229 1.1 dholland 3230 1.1 dholland /* 3231 1.1 dholland * Disallow write attempts on filesystems mounted read-only; 3232 1.1 dholland * unless the file is a socket, fifo, or a block or character 3233 1.1 dholland * device resident on the filesystem. 3234 1.1 dholland */ 3235 1.1 dholland if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 3236 1.1 dholland switch (vp->v_type) { 3237 1.1 dholland case VREG: 3238 1.1 dholland case VDIR: 3239 1.1 dholland case VLNK: 3240 1.1 dholland return (EROFS); 3241 1.1 dholland default: 3242 1.1 dholland break; 3243 1.1 dholland } 3244 1.1 dholland } 3245 1.1 dholland vap = &vattr; 3246 1.1 dholland error = VOP_GETATTR(vp, vap, cred); 3247 1.1 dholland if (error) 3248 1.1 dholland goto out; 3249 1.1 dholland error = vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, 3250 1.1 dholland accmode, cred, NULL); 3251 1.1 dholland out: 3252 1.1 dholland return error; 3253 1.1 dholland } 3254 1.1 dholland 3255 1.1 dholland /* 3256 1.1 dholland * Read wrapper for fifos. 3257 1.1 dholland */ 3258 1.1 dholland static int 3259 1.1 dholland nfsfifo_read(struct vop_read_args *ap) 3260 1.1 dholland { 3261 1.1 dholland struct nfsnode *np = VTONFS(ap->a_vp); 3262 1.1 dholland int error; 3263 1.1 dholland 3264 1.1 dholland /* 3265 1.1 dholland * Set access flag. 3266 1.1 dholland */ 3267 1.1 dholland mtx_lock(&np->n_mtx); 3268 1.1 dholland np->n_flag |= NACC; 3269 1.1 dholland vfs_timestamp(&np->n_atim); 3270 1.1 dholland mtx_unlock(&np->n_mtx); 3271 1.1 dholland error = fifo_specops.vop_read(ap); 3272 1.1 dholland return error; 3273 1.1 dholland } 3274 1.1 dholland 3275 1.1 dholland /* 3276 1.1 dholland * Write wrapper for fifos. 3277 1.1 dholland */ 3278 1.1 dholland static int 3279 1.1 dholland nfsfifo_write(struct vop_write_args *ap) 3280 1.1 dholland { 3281 1.1 dholland struct nfsnode *np = VTONFS(ap->a_vp); 3282 1.1 dholland 3283 1.1 dholland /* 3284 1.1 dholland * Set update flag. 3285 1.1 dholland */ 3286 1.1 dholland mtx_lock(&np->n_mtx); 3287 1.1 dholland np->n_flag |= NUPD; 3288 1.1 dholland vfs_timestamp(&np->n_mtim); 3289 1.1 dholland mtx_unlock(&np->n_mtx); 3290 1.1 dholland return(fifo_specops.vop_write(ap)); 3291 1.1 dholland } 3292 1.1 dholland 3293 1.1 dholland /* 3294 1.1 dholland * Close wrapper for fifos. 3295 1.1 dholland * 3296 1.1 dholland * Update the times on the nfsnode then do fifo close. 3297 1.1 dholland */ 3298 1.1 dholland static int 3299 1.1 dholland nfsfifo_close(struct vop_close_args *ap) 3300 1.1 dholland { 3301 1.1 dholland struct vnode *vp = ap->a_vp; 3302 1.1 dholland struct nfsnode *np = VTONFS(vp); 3303 1.1 dholland struct vattr vattr; 3304 1.1 dholland struct timespec ts; 3305 1.1 dholland 3306 1.1 dholland mtx_lock(&np->n_mtx); 3307 1.1 dholland if (np->n_flag & (NACC | NUPD)) { 3308 1.1 dholland vfs_timestamp(&ts); 3309 1.1 dholland if (np->n_flag & NACC) 3310 1.1 dholland np->n_atim = ts; 3311 1.1 dholland if (np->n_flag & NUPD) 3312 1.1 dholland np->n_mtim = ts; 3313 1.1 dholland np->n_flag |= NCHG; 3314 1.1 dholland if (vrefcnt(vp) == 1 && 3315 1.1 dholland (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 3316 1.1 dholland VATTR_NULL(&vattr); 3317 1.1 dholland if (np->n_flag & NACC) 3318 1.1 dholland vattr.va_atime = np->n_atim; 3319 1.1 dholland if (np->n_flag & NUPD) 3320 1.1 dholland vattr.va_mtime = np->n_mtim; 3321 1.1 dholland mtx_unlock(&np->n_mtx); 3322 1.1 dholland (void)VOP_SETATTR(vp, &vattr, ap->a_cred); 3323 1.1 dholland goto out; 3324 1.1 dholland } 3325 1.1 dholland } 3326 1.1 dholland mtx_unlock(&np->n_mtx); 3327 1.1 dholland out: 3328 1.1 dholland return (fifo_specops.vop_close(ap)); 3329 1.1 dholland } 3330 1.1 dholland 3331 1.1 dholland /* 3332 1.1 dholland * Just call ncl_writebp() with the force argument set to 1. 3333 1.1 dholland * 3334 1.1 dholland * NOTE: B_DONE may or may not be set in a_bp on call. 3335 1.1 dholland */ 3336 1.1 dholland static int 3337 1.1 dholland nfs_bwrite(struct buf *bp) 3338 1.1 dholland { 3339 1.1 dholland 3340 1.1 dholland return (ncl_writebp(bp, 1, curthread)); 3341 1.1 dholland } 3342 1.1 dholland 3343 1.1 dholland struct buf_ops buf_ops_newnfs = { 3344 1.1 dholland .bop_name = "buf_ops_nfs", 3345 1.1 dholland .bop_write = nfs_bwrite, 3346 1.1 dholland .bop_strategy = bufstrategy, 3347 1.1 dholland .bop_sync = bufsync, 3348 1.1 dholland .bop_bdflush = bufbdflush, 3349 1.1 dholland }; 3350 1.1 dholland 3351 1.1 dholland static int 3352 1.1 dholland nfs_getacl(struct vop_getacl_args *ap) 3353 1.1 dholland { 3354 1.1 dholland int error; 3355 1.1 dholland 3356 1.1 dholland if (ap->a_type != ACL_TYPE_NFS4) 3357 1.1 dholland return (EOPNOTSUPP); 3358 1.1 dholland error = nfsrpc_getacl(ap->a_vp, ap->a_cred, ap->a_td, ap->a_aclp, 3359 1.1 dholland NULL); 3360 1.1 dholland if (error > NFSERR_STALE) { 3361 1.1 dholland (void) nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); 3362 1.1 dholland error = EPERM; 3363 1.1 dholland } 3364 1.1 dholland return (error); 3365 1.1 dholland } 3366 1.1 dholland 3367 1.1 dholland static int 3368 1.1 dholland nfs_setacl(struct vop_setacl_args *ap) 3369 1.1 dholland { 3370 1.1 dholland int error; 3371 1.1 dholland 3372 1.1 dholland if (ap->a_type != ACL_TYPE_NFS4) 3373 1.1 dholland return (EOPNOTSUPP); 3374 1.1 dholland error = nfsrpc_setacl(ap->a_vp, ap->a_cred, ap->a_td, ap->a_aclp, 3375 1.1 dholland NULL); 3376 1.1 dholland if (error > NFSERR_STALE) { 3377 1.1 dholland (void) nfscl_maperr(ap->a_td, error, (uid_t)0, (gid_t)0); 3378 1.1 dholland error = EPERM; 3379 1.1 dholland } 3380 1.1 dholland return (error); 3381 1.1 dholland } 3382 1.1 dholland 3383 1.1 dholland /* 3384 1.1 dholland * Return POSIX pathconf information applicable to nfs filesystems. 3385 1.1 dholland */ 3386 1.1 dholland static int 3387 1.1 dholland nfs_pathconf(struct vop_pathconf_args *ap) 3388 1.1 dholland { 3389 1.1 dholland struct nfsv3_pathconf pc; 3390 1.1 dholland struct nfsvattr nfsva; 3391 1.1 dholland struct vnode *vp = ap->a_vp; 3392 1.1 dholland struct thread *td = curthread; 3393 1.1 dholland int attrflag, error; 3394 1.1 dholland 3395 1.3 pgoyette if ((NFS_ISV34(vp) && (ap->a_name == _PC_LINK_MAX || 3396 1.1 dholland ap->a_name == _PC_NAME_MAX || ap->a_name == _PC_CHOWN_RESTRICTED || 3397 1.3 pgoyette ap->a_name == _PC_NO_TRUNC)) || 3398 1.3 pgoyette (NFS_ISV4(vp) && ap->a_name == _PC_ACL_NFS4)) { 3399 1.1 dholland /* 3400 1.1 dholland * Since only the above 4 a_names are returned by the NFSv3 3401 1.1 dholland * Pathconf RPC, there is no point in doing it for others. 3402 1.3 pgoyette * For NFSv4, the Pathconf RPC (actually a Getattr Op.) can 3403 1.3 pgoyette * be used for _PC_NFS4_ACL as well. 3404 1.1 dholland */ 3405 1.1 dholland error = nfsrpc_pathconf(vp, &pc, td->td_ucred, td, &nfsva, 3406 1.1 dholland &attrflag, NULL); 3407 1.1 dholland if (attrflag != 0) 3408 1.1 dholland (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 3409 1.1 dholland 1); 3410 1.1 dholland if (error != 0) 3411 1.1 dholland return (error); 3412 1.1 dholland } else { 3413 1.1 dholland /* 3414 1.1 dholland * For NFSv2 (or NFSv3 when not one of the above 4 a_names), 3415 1.1 dholland * just fake them. 3416 1.1 dholland */ 3417 1.1 dholland pc.pc_linkmax = LINK_MAX; 3418 1.1 dholland pc.pc_namemax = NFS_MAXNAMLEN; 3419 1.1 dholland pc.pc_notrunc = 1; 3420 1.1 dholland pc.pc_chownrestricted = 1; 3421 1.1 dholland pc.pc_caseinsensitive = 0; 3422 1.1 dholland pc.pc_casepreserving = 1; 3423 1.1 dholland error = 0; 3424 1.1 dholland } 3425 1.1 dholland switch (ap->a_name) { 3426 1.1 dholland case _PC_LINK_MAX: 3427 1.1 dholland *ap->a_retval = pc.pc_linkmax; 3428 1.1 dholland break; 3429 1.1 dholland case _PC_NAME_MAX: 3430 1.1 dholland *ap->a_retval = pc.pc_namemax; 3431 1.1 dholland break; 3432 1.1 dholland case _PC_PATH_MAX: 3433 1.1 dholland *ap->a_retval = PATH_MAX; 3434 1.1 dholland break; 3435 1.1 dholland case _PC_PIPE_BUF: 3436 1.1 dholland *ap->a_retval = PIPE_BUF; 3437 1.1 dholland break; 3438 1.1 dholland case _PC_CHOWN_RESTRICTED: 3439 1.1 dholland *ap->a_retval = pc.pc_chownrestricted; 3440 1.1 dholland break; 3441 1.1 dholland case _PC_NO_TRUNC: 3442 1.1 dholland *ap->a_retval = pc.pc_notrunc; 3443 1.1 dholland break; 3444 1.1 dholland case _PC_ACL_EXTENDED: 3445 1.1 dholland *ap->a_retval = 0; 3446 1.1 dholland break; 3447 1.1 dholland case _PC_ACL_NFS4: 3448 1.1 dholland if (NFS_ISV4(vp) && nfsrv_useacl != 0 && attrflag != 0 && 3449 1.1 dholland NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) 3450 1.1 dholland *ap->a_retval = 1; 3451 1.1 dholland else 3452 1.1 dholland *ap->a_retval = 0; 3453 1.1 dholland break; 3454 1.1 dholland case _PC_ACL_PATH_MAX: 3455 1.1 dholland if (NFS_ISV4(vp)) 3456 1.1 dholland *ap->a_retval = ACL_MAX_ENTRIES; 3457 1.1 dholland else 3458 1.1 dholland *ap->a_retval = 3; 3459 1.1 dholland break; 3460 1.1 dholland case _PC_MAC_PRESENT: 3461 1.1 dholland *ap->a_retval = 0; 3462 1.1 dholland break; 3463 1.1 dholland case _PC_ASYNC_IO: 3464 1.1 dholland /* _PC_ASYNC_IO should have been handled by upper layers. */ 3465 1.1 dholland KASSERT(0, ("_PC_ASYNC_IO should not get here")); 3466 1.1 dholland error = EINVAL; 3467 1.1 dholland break; 3468 1.1 dholland case _PC_PRIO_IO: 3469 1.1 dholland *ap->a_retval = 0; 3470 1.1 dholland break; 3471 1.1 dholland case _PC_SYNC_IO: 3472 1.1 dholland *ap->a_retval = 0; 3473 1.1 dholland break; 3474 1.1 dholland case _PC_ALLOC_SIZE_MIN: 3475 1.1 dholland *ap->a_retval = vp->v_mount->mnt_stat.f_bsize; 3476 1.1 dholland break; 3477 1.1 dholland case _PC_FILESIZEBITS: 3478 1.1 dholland if (NFS_ISV34(vp)) 3479 1.1 dholland *ap->a_retval = 64; 3480 1.1 dholland else 3481 1.1 dholland *ap->a_retval = 32; 3482 1.1 dholland break; 3483 1.1 dholland case _PC_REC_INCR_XFER_SIZE: 3484 1.1 dholland *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; 3485 1.1 dholland break; 3486 1.1 dholland case _PC_REC_MAX_XFER_SIZE: 3487 1.1 dholland *ap->a_retval = -1; /* means ``unlimited'' */ 3488 1.1 dholland break; 3489 1.1 dholland case _PC_REC_MIN_XFER_SIZE: 3490 1.1 dholland *ap->a_retval = vp->v_mount->mnt_stat.f_iosize; 3491 1.1 dholland break; 3492 1.1 dholland case _PC_REC_XFER_ALIGN: 3493 1.1 dholland *ap->a_retval = PAGE_SIZE; 3494 1.1 dholland break; 3495 1.1 dholland case _PC_SYMLINK_MAX: 3496 1.1 dholland *ap->a_retval = NFS_MAXPATHLEN; 3497 1.1 dholland break; 3498 1.1 dholland 3499 1.1 dholland default: 3500 1.1 dholland error = EINVAL; 3501 1.1 dholland break; 3502 1.1 dholland } 3503 1.1 dholland return (error); 3504 1.1 dholland } 3505 1.1 dholland 3506