1 1.325 schmonz /* $NetBSD: nfs_vnops.c,v 1.325 2023/12/10 18:16:08 schmonz Exp $ */ 2 1.34 cgd 3 1.1 cgd /* 4 1.32 mycroft * Copyright (c) 1989, 1993 5 1.32 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Rick Macklem at The University of Guelph. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.177 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd * 34 1.89 fvdl * @(#)nfs_vnops.c 8.19 (Berkeley) 7/31/95 35 1.1 cgd */ 36 1.1 cgd 37 1.1 cgd /* 38 1.59 fvdl * vnode op calls for Sun NFS version 2 and 3 39 1.1 cgd */ 40 1.143 lukem 41 1.143 lukem #include <sys/cdefs.h> 42 1.325 schmonz __KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.325 2023/12/10 18:16:08 schmonz Exp $"); 43 1.1 cgd 44 1.268 ad #ifdef _KERNEL_OPT 45 1.119 bjh21 #include "opt_nfs.h" 46 1.124 chs #include "opt_uvmhist.h" 47 1.268 ad #endif 48 1.119 bjh21 49 1.16 mycroft #include <sys/param.h> 50 1.16 mycroft #include <sys/proc.h> 51 1.16 mycroft #include <sys/kernel.h> 52 1.16 mycroft #include <sys/systm.h> 53 1.59 fvdl #include <sys/resourcevar.h> 54 1.16 mycroft #include <sys/mount.h> 55 1.16 mycroft #include <sys/buf.h> 56 1.253 yamt #include <sys/condvar.h> 57 1.232 blymn #include <sys/disk.h> 58 1.16 mycroft #include <sys/malloc.h> 59 1.264 yamt #include <sys/kmem.h> 60 1.16 mycroft #include <sys/mbuf.h> 61 1.253 yamt #include <sys/mutex.h> 62 1.16 mycroft #include <sys/namei.h> 63 1.16 mycroft #include <sys/vnode.h> 64 1.32 mycroft #include <sys/dirent.h> 65 1.59 fvdl #include <sys/fcntl.h> 66 1.147 lukem #include <sys/hash.h> 67 1.32 mycroft #include <sys/lockf.h> 68 1.75 mycroft #include <sys/stat.h> 69 1.95 kleink #include <sys/unistd.h> 70 1.236 elad #include <sys/kauth.h> 71 1.293 tls #include <sys/cprng.h> 72 1.31 cgd 73 1.317 riastrad #ifdef UVMHIST 74 1.317 riastrad #include <uvm/uvm.h> 75 1.317 riastrad #endif 76 1.87 mrg #include <uvm/uvm_extern.h> 77 1.317 riastrad #include <uvm/uvm_stat.h> 78 1.87 mrg 79 1.64 mycroft #include <miscfs/fifofs/fifo.h> 80 1.64 mycroft #include <miscfs/genfs/genfs.h> 81 1.244 yamt #include <miscfs/genfs/genfs_node.h> 82 1.32 mycroft #include <miscfs/specfs/specdev.h> 83 1.32 mycroft 84 1.32 mycroft #include <nfs/rpcv2.h> 85 1.59 fvdl #include <nfs/nfsproto.h> 86 1.16 mycroft #include <nfs/nfs.h> 87 1.16 mycroft #include <nfs/nfsnode.h> 88 1.16 mycroft #include <nfs/nfsmount.h> 89 1.16 mycroft #include <nfs/xdr_subs.h> 90 1.16 mycroft #include <nfs/nfsm_subs.h> 91 1.58 christos #include <nfs/nfs_var.h> 92 1.27 pk 93 1.59 fvdl #include <net/if.h> 94 1.59 fvdl #include <netinet/in.h> 95 1.59 fvdl #include <netinet/in_var.h> 96 1.1 cgd 97 1.1 cgd /* 98 1.1 cgd * Global vfs data structures for nfs 99 1.1 cgd */ 100 1.271 dsl int (**nfsv2_vnodeop_p)(void *); 101 1.127 jdolecek const struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { 102 1.32 mycroft { &vop_default_desc, vn_default_error }, 103 1.318 dholland { &vop_parsepath_desc, genfs_parsepath }, /* parsepath */ 104 1.64 mycroft { &vop_lookup_desc, nfs_lookup }, /* lookup */ 105 1.64 mycroft { &vop_create_desc, nfs_create }, /* create */ 106 1.64 mycroft { &vop_mknod_desc, nfs_mknod }, /* mknod */ 107 1.64 mycroft { &vop_open_desc, nfs_open }, /* open */ 108 1.64 mycroft { &vop_close_desc, nfs_close }, /* close */ 109 1.64 mycroft { &vop_access_desc, nfs_access }, /* access */ 110 1.315 christos { &vop_accessx_desc, genfs_accessx }, /* accessx */ 111 1.64 mycroft { &vop_getattr_desc, nfs_getattr }, /* getattr */ 112 1.64 mycroft { &vop_setattr_desc, nfs_setattr }, /* setattr */ 113 1.64 mycroft { &vop_read_desc, nfs_read }, /* read */ 114 1.64 mycroft { &vop_write_desc, nfs_write }, /* write */ 115 1.306 dholland { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ 116 1.306 dholland { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ 117 1.105 wrstuden { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 118 1.320 dholland { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ 119 1.320 dholland { &vop_poll_desc, genfs_poll }, /* poll */ 120 1.156 jdolecek { &vop_kqfilter_desc, nfs_kqfilter }, /* kqfilter */ 121 1.320 dholland { &vop_revoke_desc, genfs_revoke }, /* revoke */ 122 1.320 dholland { &vop_mmap_desc, genfs_mmap }, /* mmap */ 123 1.64 mycroft { &vop_fsync_desc, nfs_fsync }, /* fsync */ 124 1.320 dholland { &vop_seek_desc, genfs_seek }, /* seek */ 125 1.64 mycroft { &vop_remove_desc, nfs_remove }, /* remove */ 126 1.64 mycroft { &vop_link_desc, nfs_link }, /* link */ 127 1.64 mycroft { &vop_rename_desc, nfs_rename }, /* rename */ 128 1.64 mycroft { &vop_mkdir_desc, nfs_mkdir }, /* mkdir */ 129 1.64 mycroft { &vop_rmdir_desc, nfs_rmdir }, /* rmdir */ 130 1.64 mycroft { &vop_symlink_desc, nfs_symlink }, /* symlink */ 131 1.64 mycroft { &vop_readdir_desc, nfs_readdir }, /* readdir */ 132 1.64 mycroft { &vop_readlink_desc, nfs_readlink }, /* readlink */ 133 1.320 dholland { &vop_abortop_desc, genfs_abortop }, /* abortop */ 134 1.64 mycroft { &vop_inactive_desc, nfs_inactive }, /* inactive */ 135 1.64 mycroft { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 136 1.320 dholland { &vop_lock_desc, genfs_lock }, /* lock */ 137 1.64 mycroft { &vop_unlock_desc, nfs_unlock }, /* unlock */ 138 1.64 mycroft { &vop_bmap_desc, nfs_bmap }, /* bmap */ 139 1.64 mycroft { &vop_strategy_desc, nfs_strategy }, /* strategy */ 140 1.64 mycroft { &vop_print_desc, nfs_print }, /* print */ 141 1.320 dholland { &vop_islocked_desc, genfs_islocked }, /* islocked */ 142 1.64 mycroft { &vop_pathconf_desc, nfs_pathconf }, /* pathconf */ 143 1.64 mycroft { &vop_advlock_desc, nfs_advlock }, /* advlock */ 144 1.213 yamt { &vop_bwrite_desc, genfs_badop }, /* bwrite */ 145 1.124 chs { &vop_getpages_desc, nfs_getpages }, /* getpages */ 146 1.138 chs { &vop_putpages_desc, genfs_putpages }, /* putpages */ 147 1.124 chs { NULL, NULL } 148 1.1 cgd }; 149 1.127 jdolecek const struct vnodeopv_desc nfsv2_vnodeop_opv_desc = 150 1.32 mycroft { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; 151 1.1 cgd 152 1.1 cgd /* 153 1.1 cgd * Special device vnode ops 154 1.1 cgd */ 155 1.271 dsl int (**spec_nfsv2nodeop_p)(void *); 156 1.127 jdolecek const struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { 157 1.32 mycroft { &vop_default_desc, vn_default_error }, 158 1.319 dholland GENFS_SPECOP_ENTRIES, 159 1.64 mycroft { &vop_close_desc, nfsspec_close }, /* close */ 160 1.64 mycroft { &vop_access_desc, nfsspec_access }, /* access */ 161 1.315 christos { &vop_accessx_desc, genfs_accessx }, /* accessx */ 162 1.64 mycroft { &vop_getattr_desc, nfs_getattr }, /* getattr */ 163 1.64 mycroft { &vop_setattr_desc, nfs_setattr }, /* setattr */ 164 1.64 mycroft { &vop_read_desc, nfsspec_read }, /* read */ 165 1.64 mycroft { &vop_write_desc, nfsspec_write }, /* write */ 166 1.105 wrstuden { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 167 1.124 chs { &vop_fsync_desc, spec_fsync }, /* fsync */ 168 1.64 mycroft { &vop_inactive_desc, nfs_inactive }, /* inactive */ 169 1.64 mycroft { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 170 1.320 dholland { &vop_lock_desc, genfs_lock }, /* lock */ 171 1.64 mycroft { &vop_unlock_desc, nfs_unlock }, /* unlock */ 172 1.64 mycroft { &vop_print_desc, nfs_print }, /* print */ 173 1.320 dholland { &vop_islocked_desc, genfs_islocked }, /* islocked */ 174 1.320 dholland { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 175 1.124 chs { NULL, NULL } 176 1.1 cgd }; 177 1.127 jdolecek const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = 178 1.32 mycroft { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; 179 1.1 cgd 180 1.271 dsl int (**fifo_nfsv2nodeop_p)(void *); 181 1.127 jdolecek const struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { 182 1.32 mycroft { &vop_default_desc, vn_default_error }, 183 1.319 dholland GENFS_FIFOOP_ENTRIES, 184 1.64 mycroft { &vop_close_desc, nfsfifo_close }, /* close */ 185 1.64 mycroft { &vop_access_desc, nfsspec_access }, /* access */ 186 1.315 christos { &vop_accessx_desc, genfs_accessx }, /* accessx */ 187 1.64 mycroft { &vop_getattr_desc, nfs_getattr }, /* getattr */ 188 1.64 mycroft { &vop_setattr_desc, nfs_setattr }, /* setattr */ 189 1.64 mycroft { &vop_read_desc, nfsfifo_read }, /* read */ 190 1.64 mycroft { &vop_write_desc, nfsfifo_write }, /* write */ 191 1.105 wrstuden { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 192 1.64 mycroft { &vop_fsync_desc, nfs_fsync }, /* fsync */ 193 1.64 mycroft { &vop_inactive_desc, nfs_inactive }, /* inactive */ 194 1.64 mycroft { &vop_reclaim_desc, nfs_reclaim }, /* reclaim */ 195 1.320 dholland { &vop_lock_desc, genfs_lock }, /* lock */ 196 1.64 mycroft { &vop_unlock_desc, nfs_unlock }, /* unlock */ 197 1.319 dholland { &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ 198 1.64 mycroft { &vop_print_desc, nfs_print }, /* print */ 199 1.320 dholland { &vop_islocked_desc, genfs_islocked }, /* islocked */ 200 1.213 yamt { &vop_bwrite_desc, genfs_badop }, /* bwrite */ 201 1.124 chs { NULL, NULL } 202 1.1 cgd }; 203 1.127 jdolecek const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = 204 1.32 mycroft { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; 205 1.1 cgd 206 1.239 yamt static int nfs_linkrpc(struct vnode *, struct vnode *, const char *, 207 1.239 yamt size_t, kauth_cred_t, struct lwp *); 208 1.252 christos static void nfs_writerpc_extfree(struct mbuf *, void *, size_t, void *); 209 1.167 yamt 210 1.1 cgd /* 211 1.32 mycroft * Global variables 212 1.1 cgd */ 213 1.59 fvdl extern u_int32_t nfs_true, nfs_false; 214 1.55 mycroft extern u_int32_t nfs_xdrneg1; 215 1.157 matt extern const nfstype nfsv3_type[9]; 216 1.150 matt 217 1.1 cgd int nfs_numasync = 0; 218 1.225 christos #define DIRHDSIZ _DIRENT_NAMEOFF(dp) 219 1.225 christos #define UIO_ADVANCE(uio, siz) \ 220 1.225 christos (void)((uio)->uio_resid -= (siz), \ 221 1.225 christos (uio)->uio_iov->iov_base = (char *)(uio)->uio_iov->iov_base + (siz), \ 222 1.225 christos (uio)->uio_iov->iov_len -= (siz)) 223 1.1 cgd 224 1.188 yamt static void nfs_cache_enter(struct vnode *, struct vnode *, 225 1.188 yamt struct componentname *); 226 1.188 yamt 227 1.188 yamt static void 228 1.188 yamt nfs_cache_enter(struct vnode *dvp, struct vnode *vp, 229 1.188 yamt struct componentname *cnp) 230 1.188 yamt { 231 1.215 yamt struct nfsnode *dnp = VTONFS(dvp); 232 1.188 yamt 233 1.295 rmind if ((cnp->cn_flags & MAKEENTRY) == 0) { 234 1.295 rmind return; 235 1.295 rmind } 236 1.188 yamt if (vp != NULL) { 237 1.188 yamt struct nfsnode *np = VTONFS(vp); 238 1.188 yamt 239 1.188 yamt np->n_ctime = np->n_vattr->va_ctime.tv_sec; 240 1.215 yamt } 241 1.188 yamt 242 1.215 yamt if (!timespecisset(&dnp->n_nctime)) 243 1.215 yamt dnp->n_nctime = dnp->n_vattr->va_mtime; 244 1.188 yamt 245 1.297 dholland cache_enter(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); 246 1.188 yamt } 247 1.188 yamt 248 1.1 cgd /* 249 1.1 cgd * nfs null call from vfs. 250 1.1 cgd */ 251 1.32 mycroft int 252 1.272 dsl nfs_null(struct vnode *vp, kauth_cred_t cred, struct lwp *l) 253 1.1 cgd { 254 1.252 christos char *bpos, *dpos; 255 1.1 cgd int error = 0; 256 1.300 martin struct mbuf *mreq, *mrep, *md, *mb __unused; 257 1.165 drochner struct nfsnode *np = VTONFS(vp); 258 1.220 perry 259 1.165 drochner nfsm_reqhead(np, NFSPROC_NULL, 0); 260 1.230 christos nfsm_request(np, NFSPROC_NULL, l, cred); 261 1.1 cgd nfsm_reqdone; 262 1.1 cgd return (error); 263 1.1 cgd } 264 1.1 cgd 265 1.1 cgd /* 266 1.1 cgd * nfs access vnode op. 267 1.59 fvdl * For nfs version 2, just return ok. File accesses may fail later. 268 1.59 fvdl * For nfs version 3, use the access rpc to check accessibility. If file modes 269 1.59 fvdl * are changed on the server, accesses might still fail later. 270 1.1 cgd */ 271 1.32 mycroft int 272 1.272 dsl nfs_access(void *v) 273 1.58 christos { 274 1.32 mycroft struct vop_access_args /* { 275 1.32 mycroft struct vnode *a_vp; 276 1.315 christos accmode_t a_accmode; 277 1.236 elad kauth_cred_t a_cred; 278 1.58 christos } */ *ap = v; 279 1.110 augustss struct vnode *vp = ap->a_vp; 280 1.200 christos #ifndef NFS_V2_ONLY 281 1.110 augustss u_int32_t *tl; 282 1.252 christos char *cp; 283 1.110 augustss int32_t t1, t2; 284 1.252 christos char *bpos, *dpos, *cp2; 285 1.200 christos int error = 0, attrflag; 286 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 287 1.59 fvdl u_int32_t mode, rmode; 288 1.119 bjh21 const int v3 = NFS_ISV3(vp); 289 1.200 christos #endif 290 1.200 christos int cachevalid; 291 1.108 fvdl struct nfsnode *np = VTONFS(vp); 292 1.227 christos struct nfsmount *nmp = VFSTONFS(vp->v_mount); 293 1.108 fvdl 294 1.108 fvdl cachevalid = (np->n_accstamp != -1 && 295 1.257 yamt (time_uptime - np->n_accstamp) < nfs_attrtimeo(nmp, np) && 296 1.236 elad np->n_accuid == kauth_cred_geteuid(ap->a_cred)); 297 1.108 fvdl 298 1.108 fvdl /* 299 1.108 fvdl * Check access cache first. If this request has been made for this 300 1.108 fvdl * uid shortly before, use the cached result. 301 1.108 fvdl */ 302 1.118 fvdl if (cachevalid) { 303 1.118 fvdl if (!np->n_accerror) { 304 1.315 christos if ((np->n_accmode & ap->a_accmode) == ap->a_accmode) 305 1.118 fvdl return np->n_accerror; 306 1.315 christos } else if ((np->n_accmode & ap->a_accmode) == np->n_accmode) 307 1.118 fvdl return np->n_accerror; 308 1.118 fvdl } 309 1.1 cgd 310 1.200 christos #ifndef NFS_V2_ONLY 311 1.1 cgd /* 312 1.59 fvdl * For nfs v3, do an access rpc, otherwise you are stuck emulating 313 1.32 mycroft * ufs_access() locally using the vattr. This may not be correct, 314 1.32 mycroft * since the server may apply other access criteria such as 315 1.32 mycroft * client uid-->server uid mapping that we do not know about, but 316 1.32 mycroft * this is better than just returning anything that is lying about 317 1.32 mycroft * in the cache. 318 1.32 mycroft */ 319 1.59 fvdl if (v3) { 320 1.59 fvdl nfsstats.rpccnt[NFSPROC_ACCESS]++; 321 1.165 drochner nfsm_reqhead(np, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED); 322 1.165 drochner nfsm_fhtom(np, v3); 323 1.59 fvdl nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 324 1.315 christos if (ap->a_accmode & VREAD) 325 1.59 fvdl mode = NFSV3ACCESS_READ; 326 1.32 mycroft else 327 1.59 fvdl mode = 0; 328 1.74 mycroft if (vp->v_type != VDIR) { 329 1.315 christos if (ap->a_accmode & VWRITE) 330 1.74 mycroft mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 331 1.315 christos if (ap->a_accmode & VEXEC) 332 1.74 mycroft mode |= NFSV3ACCESS_EXECUTE; 333 1.74 mycroft } else { 334 1.315 christos if (ap->a_accmode & VWRITE) 335 1.59 fvdl mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 336 1.59 fvdl NFSV3ACCESS_DELETE); 337 1.315 christos if (ap->a_accmode & VEXEC) 338 1.59 fvdl mode |= NFSV3ACCESS_LOOKUP; 339 1.59 fvdl } 340 1.59 fvdl *tl = txdr_unsigned(mode); 341 1.260 pooka nfsm_request(np, NFSPROC_ACCESS, curlwp, ap->a_cred); 342 1.153 yamt nfsm_postop_attr(vp, attrflag, 0); 343 1.59 fvdl if (!error) { 344 1.59 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 345 1.59 fvdl rmode = fxdr_unsigned(u_int32_t, *tl); 346 1.59 fvdl /* 347 1.59 fvdl * The NFS V3 spec does not clarify whether or not 348 1.59 fvdl * the returned access bits can be a superset of 349 1.59 fvdl * the ones requested, so... 350 1.59 fvdl */ 351 1.59 fvdl if ((rmode & mode) != mode) 352 1.59 fvdl error = EACCES; 353 1.59 fvdl } 354 1.32 mycroft nfsm_reqdone; 355 1.32 mycroft } else 356 1.200 christos #endif 357 1.32 mycroft return (nfsspec_access(ap)); 358 1.200 christos #ifndef NFS_V2_ONLY 359 1.71 fvdl /* 360 1.71 fvdl * Disallow write attempts on filesystems mounted read-only; 361 1.71 fvdl * unless the file is a socket, fifo, or a block or character 362 1.71 fvdl * device resident on the filesystem. 363 1.71 fvdl */ 364 1.315 christos if (!error && (ap->a_accmode & VWRITE) && 365 1.108 fvdl (vp->v_mount->mnt_flag & MNT_RDONLY)) { 366 1.71 fvdl switch (vp->v_type) { 367 1.71 fvdl case VREG: 368 1.71 fvdl case VDIR: 369 1.71 fvdl case VLNK: 370 1.108 fvdl error = EROFS; 371 1.71 fvdl default: 372 1.71 fvdl break; 373 1.71 fvdl } 374 1.71 fvdl } 375 1.108 fvdl 376 1.108 fvdl if (!error || error == EACCES) { 377 1.108 fvdl /* 378 1.108 fvdl * If we got the same result as for a previous, 379 1.108 fvdl * different request, OR it in. Don't update 380 1.108 fvdl * the timestamp in that case. 381 1.108 fvdl */ 382 1.149 fvdl if (cachevalid && np->n_accstamp != -1 && 383 1.149 fvdl error == np->n_accerror) { 384 1.118 fvdl if (!error) 385 1.315 christos np->n_accmode |= ap->a_accmode; 386 1.315 christos else if ((np->n_accmode & ap->a_accmode) == ap->a_accmode) 387 1.315 christos np->n_accmode = ap->a_accmode; 388 1.118 fvdl } else { 389 1.237 kardel np->n_accstamp = time_uptime; 390 1.236 elad np->n_accuid = kauth_cred_geteuid(ap->a_cred); 391 1.315 christos np->n_accmode = ap->a_accmode; 392 1.108 fvdl np->n_accerror = error; 393 1.108 fvdl } 394 1.108 fvdl } 395 1.108 fvdl 396 1.108 fvdl return (error); 397 1.200 christos #endif 398 1.1 cgd } 399 1.1 cgd 400 1.1 cgd /* 401 1.1 cgd * nfs open vnode op 402 1.32 mycroft * Check to see if the type is ok 403 1.32 mycroft * and that deletion is not in progress. 404 1.32 mycroft * For paged in text files, you will need to flush the page cache 405 1.32 mycroft * if consistency is lost. 406 1.1 cgd */ 407 1.1 cgd /* ARGSUSED */ 408 1.32 mycroft int 409 1.272 dsl nfs_open(void *v) 410 1.58 christos { 411 1.32 mycroft struct vop_open_args /* { 412 1.32 mycroft struct vnode *a_vp; 413 1.32 mycroft int a_mode; 414 1.236 elad kauth_cred_t a_cred; 415 1.58 christos } */ *ap = v; 416 1.110 augustss struct vnode *vp = ap->a_vp; 417 1.32 mycroft struct nfsnode *np = VTONFS(vp); 418 1.32 mycroft int error; 419 1.1 cgd 420 1.59 fvdl if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) { 421 1.1 cgd return (EACCES); 422 1.59 fvdl } 423 1.124 chs 424 1.126 chs if (ap->a_mode & FREAD) { 425 1.184 fvdl if (np->n_rcred != NULL) 426 1.236 elad kauth_cred_free(np->n_rcred); 427 1.126 chs np->n_rcred = ap->a_cred; 428 1.236 elad kauth_cred_hold(np->n_rcred); 429 1.126 chs } 430 1.125 chs if (ap->a_mode & FWRITE) { 431 1.184 fvdl if (np->n_wcred != NULL) 432 1.236 elad kauth_cred_free(np->n_wcred); 433 1.125 chs np->n_wcred = ap->a_cred; 434 1.236 elad kauth_cred_hold(np->n_wcred); 435 1.125 chs } 436 1.125 chs 437 1.260 pooka error = nfs_flushstalebuf(vp, ap->a_cred, curlwp, 0); 438 1.247 yamt if (error) 439 1.247 yamt return error; 440 1.247 yamt 441 1.247 yamt NFS_INVALIDATE_ATTRCACHE(np); /* For Open/Close consistency */ 442 1.247 yamt 443 1.32 mycroft return (0); 444 1.1 cgd } 445 1.1 cgd 446 1.1 cgd /* 447 1.1 cgd * nfs close vnode op 448 1.59 fvdl * What an NFS client should do upon close after writing is a debatable issue. 449 1.59 fvdl * Most NFS clients push delayed writes to the server upon close, basically for 450 1.59 fvdl * two reasons: 451 1.59 fvdl * 1 - So that any write errors may be reported back to the client process 452 1.59 fvdl * doing the close system call. By far the two most likely errors are 453 1.59 fvdl * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure. 454 1.59 fvdl * 2 - To put a worst case upper bound on cache inconsistency between 455 1.59 fvdl * multiple clients for the file. 456 1.59 fvdl * There is also a consistency problem for Version 2 of the protocol w.r.t. 457 1.59 fvdl * not being able to tell if other clients are writing a file concurrently, 458 1.59 fvdl * since there is no way of knowing if the changed modify time in the reply 459 1.59 fvdl * is only due to the write for this client. 460 1.59 fvdl * (NFS Version 3 provides weak cache consistency data in the reply that 461 1.59 fvdl * should be sufficient to detect and handle this case.) 462 1.59 fvdl * 463 1.59 fvdl * The current code does the following: 464 1.59 fvdl * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers 465 1.59 fvdl * for NFS Version 3 - flush dirty buffers to the server but don't invalidate 466 1.59 fvdl * or commit them (this satisfies 1 and 2 except for the 467 1.59 fvdl * case where the server crashes after this close but 468 1.59 fvdl * before the commit RPC, which is felt to be "good 469 1.59 fvdl * enough". Changing the last argument to nfs_flush() to 470 1.59 fvdl * a 1 would force a commit operation, if it is felt a 471 1.59 fvdl * commit is necessary now. 472 1.1 cgd */ 473 1.1 cgd /* ARGSUSED */ 474 1.32 mycroft int 475 1.272 dsl nfs_close(void *v) 476 1.58 christos { 477 1.32 mycroft struct vop_close_args /* { 478 1.32 mycroft struct vnodeop_desc *a_desc; 479 1.32 mycroft struct vnode *a_vp; 480 1.32 mycroft int a_fflag; 481 1.236 elad kauth_cred_t a_cred; 482 1.58 christos } */ *ap = v; 483 1.110 augustss struct vnode *vp = ap->a_vp; 484 1.110 augustss struct nfsnode *np = VTONFS(vp); 485 1.1 cgd int error = 0; 486 1.124 chs UVMHIST_FUNC("nfs_close"); UVMHIST_CALLED(ubchist); 487 1.1 cgd 488 1.32 mycroft if (vp->v_type == VREG) { 489 1.248 yamt if (np->n_flag & NMODIFIED) { 490 1.200 christos #ifndef NFS_V2_ONLY 491 1.59 fvdl if (NFS_ISV3(vp)) { 492 1.260 pooka error = nfs_flush(vp, ap->a_cred, MNT_WAIT, curlwp, 0); 493 1.59 fvdl np->n_flag &= ~NMODIFIED; 494 1.59 fvdl } else 495 1.200 christos #endif 496 1.260 pooka error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 1); 497 1.185 yamt NFS_INVALIDATE_ATTRCACHE(np); 498 1.32 mycroft } 499 1.32 mycroft if (np->n_flag & NWRITEERR) { 500 1.32 mycroft np->n_flag &= ~NWRITEERR; 501 1.32 mycroft error = np->n_error; 502 1.32 mycroft } 503 1.1 cgd } 504 1.124 chs UVMHIST_LOG(ubchist, "returning %d", error,0,0,0); 505 1.1 cgd return (error); 506 1.1 cgd } 507 1.1 cgd 508 1.1 cgd /* 509 1.1 cgd * nfs getattr call from vfs. 510 1.1 cgd */ 511 1.32 mycroft int 512 1.272 dsl nfs_getattr(void *v) 513 1.58 christos { 514 1.32 mycroft struct vop_getattr_args /* { 515 1.32 mycroft struct vnode *a_vp; 516 1.32 mycroft struct vattr *a_vap; 517 1.236 elad kauth_cred_t a_cred; 518 1.58 christos } */ *ap = v; 519 1.110 augustss struct vnode *vp = ap->a_vp; 520 1.110 augustss struct nfsnode *np = VTONFS(vp); 521 1.252 christos char *cp; 522 1.110 augustss u_int32_t *tl; 523 1.110 augustss int32_t t1, t2; 524 1.252 christos char *bpos, *dpos; 525 1.1 cgd int error = 0; 526 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 527 1.119 bjh21 const int v3 = NFS_ISV3(vp); 528 1.220 perry 529 1.32 mycroft /* 530 1.32 mycroft * Update local times for special files. 531 1.32 mycroft */ 532 1.32 mycroft if (np->n_flag & (NACC | NUPD)) 533 1.32 mycroft np->n_flag |= NCHG; 534 1.181 yamt 535 1.181 yamt /* 536 1.181 yamt * if we have delayed truncation, do it now. 537 1.181 yamt */ 538 1.181 yamt nfs_delayedtruncate(vp); 539 1.181 yamt 540 1.32 mycroft /* 541 1.32 mycroft * First look in the cache. 542 1.32 mycroft */ 543 1.32 mycroft if (nfs_getattrcache(vp, ap->a_vap) == 0) 544 1.1 cgd return (0); 545 1.1 cgd nfsstats.rpccnt[NFSPROC_GETATTR]++; 546 1.165 drochner nfsm_reqhead(np, NFSPROC_GETATTR, NFSX_FH(v3)); 547 1.165 drochner nfsm_fhtom(np, v3); 548 1.260 pooka nfsm_request(np, NFSPROC_GETATTR, curlwp, ap->a_cred); 549 1.81 fvdl if (!error) { 550 1.153 yamt nfsm_loadattr(vp, ap->a_vap, 0); 551 1.81 fvdl if (vp->v_type == VDIR && 552 1.81 fvdl ap->a_vap->va_blocksize < NFS_DIRFRAGSIZ) 553 1.81 fvdl ap->a_vap->va_blocksize = NFS_DIRFRAGSIZ; 554 1.81 fvdl } 555 1.1 cgd nfsm_reqdone; 556 1.1 cgd return (error); 557 1.1 cgd } 558 1.1 cgd 559 1.1 cgd /* 560 1.1 cgd * nfs setattr call. 561 1.1 cgd */ 562 1.32 mycroft int 563 1.272 dsl nfs_setattr(void *v) 564 1.58 christos { 565 1.32 mycroft struct vop_setattr_args /* { 566 1.32 mycroft struct vnodeop_desc *a_desc; 567 1.32 mycroft struct vnode *a_vp; 568 1.32 mycroft struct vattr *a_vap; 569 1.236 elad kauth_cred_t a_cred; 570 1.58 christos } */ *ap = v; 571 1.110 augustss struct vnode *vp = ap->a_vp; 572 1.110 augustss struct nfsnode *np = VTONFS(vp); 573 1.110 augustss struct vattr *vap = ap->a_vap; 574 1.59 fvdl int error = 0; 575 1.59 fvdl u_quad_t tsize = 0; 576 1.1 cgd 577 1.59 fvdl /* 578 1.71 fvdl * Setting of flags is not supported. 579 1.71 fvdl */ 580 1.71 fvdl if (vap->va_flags != VNOVAL) 581 1.71 fvdl return (EOPNOTSUPP); 582 1.71 fvdl 583 1.71 fvdl /* 584 1.59 fvdl * Disallow write attempts if the filesystem is mounted read-only. 585 1.59 fvdl */ 586 1.71 fvdl if ((vap->va_uid != (uid_t)VNOVAL || 587 1.59 fvdl vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 588 1.59 fvdl vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && 589 1.59 fvdl (vp->v_mount->mnt_flag & MNT_RDONLY)) 590 1.59 fvdl return (EROFS); 591 1.35 mycroft if (vap->va_size != VNOVAL) { 592 1.266 yamt if (vap->va_size > VFSTONFS(vp->v_mount)->nm_maxfilesize) { 593 1.266 yamt return EFBIG; 594 1.266 yamt } 595 1.59 fvdl switch (vp->v_type) { 596 1.59 fvdl case VDIR: 597 1.59 fvdl return (EISDIR); 598 1.59 fvdl case VCHR: 599 1.59 fvdl case VBLK: 600 1.59 fvdl case VSOCK: 601 1.59 fvdl case VFIFO: 602 1.56 jtc if (vap->va_mtime.tv_sec == VNOVAL && 603 1.56 jtc vap->va_atime.tv_sec == VNOVAL && 604 1.84 christos vap->va_mode == (mode_t)VNOVAL && 605 1.59 fvdl vap->va_uid == (uid_t)VNOVAL && 606 1.59 fvdl vap->va_gid == (gid_t)VNOVAL) 607 1.35 mycroft return (0); 608 1.59 fvdl vap->va_size = VNOVAL; 609 1.59 fvdl break; 610 1.59 fvdl default: 611 1.59 fvdl /* 612 1.59 fvdl * Disallow write attempts if the filesystem is 613 1.59 fvdl * mounted read-only. 614 1.59 fvdl */ 615 1.59 fvdl if (vp->v_mount->mnt_flag & MNT_RDONLY) 616 1.59 fvdl return (EROFS); 617 1.244 yamt genfs_node_wrlock(vp); 618 1.87 mrg uvm_vnp_setsize(vp, vap->va_size); 619 1.148 fvdl tsize = np->n_size; 620 1.148 fvdl np->n_size = vap->va_size; 621 1.59 fvdl if (vap->va_size == 0) 622 1.59 fvdl error = nfs_vinvalbuf(vp, 0, 623 1.260 pooka ap->a_cred, curlwp, 1); 624 1.59 fvdl else 625 1.59 fvdl error = nfs_vinvalbuf(vp, V_SAVE, 626 1.260 pooka ap->a_cred, curlwp, 1); 627 1.71 fvdl if (error) { 628 1.148 fvdl uvm_vnp_setsize(vp, tsize); 629 1.244 yamt genfs_node_unlock(vp); 630 1.59 fvdl return (error); 631 1.71 fvdl } 632 1.148 fvdl np->n_vattr->va_size = vap->va_size; 633 1.71 fvdl } 634 1.242 drochner } else { 635 1.242 drochner /* 636 1.242 drochner * flush files before setattr because a later write of 637 1.242 drochner * cached data might change timestamps or reset sugid bits 638 1.242 drochner */ 639 1.242 drochner if ((vap->va_mtime.tv_sec != VNOVAL || 640 1.242 drochner vap->va_atime.tv_sec != VNOVAL || 641 1.242 drochner vap->va_mode != VNOVAL) && 642 1.242 drochner vp->v_type == VREG && 643 1.242 drochner (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, 644 1.260 pooka curlwp, 1)) == EINTR) 645 1.242 drochner return (error); 646 1.242 drochner } 647 1.260 pooka error = nfs_setattrrpc(vp, vap, ap->a_cred, curlwp); 648 1.244 yamt if (vap->va_size != VNOVAL) { 649 1.244 yamt if (error) { 650 1.244 yamt np->n_size = np->n_vattr->va_size = tsize; 651 1.244 yamt uvm_vnp_setsize(vp, np->n_size); 652 1.244 yamt } 653 1.244 yamt genfs_node_unlock(vp); 654 1.32 mycroft } 655 1.59 fvdl return (error); 656 1.59 fvdl } 657 1.59 fvdl 658 1.59 fvdl /* 659 1.59 fvdl * Do an nfs setattr rpc. 660 1.59 fvdl */ 661 1.59 fvdl int 662 1.272 dsl nfs_setattrrpc(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, struct lwp *l) 663 1.59 fvdl { 664 1.110 augustss struct nfsv2_sattr *sp; 665 1.252 christos char *cp; 666 1.110 augustss int32_t t1, t2; 667 1.252 christos char *bpos, *dpos; 668 1.59 fvdl u_int32_t *tl; 669 1.200 christos int error = 0; 670 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 671 1.119 bjh21 const int v3 = NFS_ISV3(vp); 672 1.165 drochner struct nfsnode *np = VTONFS(vp); 673 1.200 christos #ifndef NFS_V2_ONLY 674 1.200 christos int wccflag = NFSV3_WCCRATTR; 675 1.252 christos char *cp2; 676 1.200 christos #endif 677 1.59 fvdl 678 1.1 cgd nfsstats.rpccnt[NFSPROC_SETATTR]++; 679 1.165 drochner nfsm_reqhead(np, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3)); 680 1.165 drochner nfsm_fhtom(np, v3); 681 1.200 christos #ifndef NFS_V2_ONLY 682 1.59 fvdl if (v3) { 683 1.251 thorpej nfsm_v3attrbuild(vap, true); 684 1.59 fvdl nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 685 1.59 fvdl *tl = nfs_false; 686 1.24 mycroft } else { 687 1.200 christos #endif 688 1.59 fvdl nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 689 1.84 christos if (vap->va_mode == (mode_t)VNOVAL) 690 1.59 fvdl sp->sa_mode = nfs_xdrneg1; 691 1.59 fvdl else 692 1.59 fvdl sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode); 693 1.59 fvdl if (vap->va_uid == (uid_t)VNOVAL) 694 1.59 fvdl sp->sa_uid = nfs_xdrneg1; 695 1.59 fvdl else 696 1.59 fvdl sp->sa_uid = txdr_unsigned(vap->va_uid); 697 1.59 fvdl if (vap->va_gid == (gid_t)VNOVAL) 698 1.59 fvdl sp->sa_gid = nfs_xdrneg1; 699 1.59 fvdl else 700 1.59 fvdl sp->sa_gid = txdr_unsigned(vap->va_gid); 701 1.59 fvdl sp->sa_size = txdr_unsigned(vap->va_size); 702 1.59 fvdl txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 703 1.59 fvdl txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 704 1.200 christos #ifndef NFS_V2_ONLY 705 1.59 fvdl } 706 1.200 christos #endif 707 1.230 christos nfsm_request(np, NFSPROC_SETATTR, l, cred); 708 1.200 christos #ifndef NFS_V2_ONLY 709 1.59 fvdl if (v3) { 710 1.251 thorpej nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, false); 711 1.59 fvdl } else 712 1.200 christos #endif 713 1.244 yamt nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC); 714 1.32 mycroft nfsm_reqdone; 715 1.1 cgd return (error); 716 1.1 cgd } 717 1.1 cgd 718 1.1 cgd /* 719 1.1 cgd * nfs lookup call, one step at a time... 720 1.1 cgd * First look in cache 721 1.274 yamt * If not found, do the rpc. 722 1.1 cgd */ 723 1.32 mycroft int 724 1.272 dsl nfs_lookup(void *v) 725 1.58 christos { 726 1.304 hannken struct vop_lookup_v2_args /* { 727 1.32 mycroft struct vnodeop_desc *a_desc; 728 1.32 mycroft struct vnode *a_dvp; 729 1.32 mycroft struct vnode **a_vpp; 730 1.32 mycroft struct componentname *a_cnp; 731 1.58 christos } */ *ap = v; 732 1.89 fvdl struct componentname *cnp = ap->a_cnp; 733 1.89 fvdl struct vnode *dvp = ap->a_dvp; 734 1.89 fvdl struct vnode **vpp = ap->a_vpp; 735 1.102 wrstuden int flags; 736 1.89 fvdl struct vnode *newvp; 737 1.89 fvdl u_int32_t *tl; 738 1.252 christos char *cp; 739 1.89 fvdl int32_t t1, t2; 740 1.252 christos char *bpos, *dpos, *cp2; 741 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 742 1.1 cgd long len; 743 1.59 fvdl nfsfh_t *fhp; 744 1.1 cgd struct nfsnode *np; 745 1.296 dholland int cachefound; 746 1.246 chs int error = 0, attrflag, fhsize; 747 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 748 1.128 fvdl 749 1.102 wrstuden flags = cnp->cn_flags; 750 1.1 cgd 751 1.60 jtk *vpp = NULLVP; 752 1.128 fvdl newvp = NULLVP; 753 1.59 fvdl if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) && 754 1.59 fvdl (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 755 1.59 fvdl return (EROFS); 756 1.32 mycroft if (dvp->v_type != VDIR) 757 1.1 cgd return (ENOTDIR); 758 1.108 fvdl 759 1.198 yamt /* 760 1.198 yamt * RFC1813(nfsv3) 3.2 says clients should handle "." by themselves. 761 1.198 yamt */ 762 1.198 yamt if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 763 1.260 pooka error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred); 764 1.198 yamt if (error) 765 1.198 yamt return error; 766 1.198 yamt if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) 767 1.198 yamt return EISDIR; 768 1.282 pooka vref(dvp); 769 1.198 yamt *vpp = dvp; 770 1.198 yamt return 0; 771 1.198 yamt } 772 1.198 yamt 773 1.32 mycroft np = VTONFS(dvp); 774 1.106 jdolecek 775 1.106 jdolecek /* 776 1.270 yamt * Before performing an RPC, check the name cache to see if 777 1.270 yamt * the directory/name pair we are looking for is known already. 778 1.106 jdolecek * If the directory/name pair is found in the name cache, 779 1.106 jdolecek * we have to ensure the directory has not changed from 780 1.106 jdolecek * the time the cache entry has been created. If it has, 781 1.220 perry * the cache entry has to be ignored. 782 1.106 jdolecek */ 783 1.297 dholland cachefound = cache_lookup_raw(dvp, cnp->cn_nameptr, cnp->cn_namelen, 784 1.297 dholland cnp->cn_flags, NULL, vpp); 785 1.203 yamt KASSERT(dvp != *vpp); 786 1.275 yamt KASSERT((cnp->cn_flags & ISWHITEOUT) == 0); 787 1.296 dholland if (cachefound) { 788 1.1 cgd struct vattr vattr; 789 1.108 fvdl 790 1.296 dholland error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred); 791 1.296 dholland if (error != 0) { 792 1.296 dholland if (*vpp != NULLVP) 793 1.296 dholland vrele(*vpp); 794 1.108 fvdl *vpp = NULLVP; 795 1.128 fvdl return error; 796 1.128 fvdl } 797 1.128 fvdl 798 1.260 pooka if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred) 799 1.260 pooka || timespeccmp(&vattr.va_mtime, 800 1.215 yamt &VTONFS(dvp)->n_nctime, !=)) { 801 1.296 dholland if (*vpp != NULLVP) { 802 1.215 yamt vrele(*vpp); 803 1.215 yamt *vpp = NULLVP; 804 1.203 yamt } 805 1.297 dholland cache_purge1(dvp, NULL, 0, PURGE_CHILDREN); 806 1.178 yamt timespecclear(&np->n_nctime); 807 1.82 fvdl goto dorpc; 808 1.82 fvdl } 809 1.82 fvdl 810 1.296 dholland if (*vpp == NULLVP) { 811 1.296 dholland /* namecache gave us a negative result */ 812 1.298 macallan error = ENOENT; 813 1.215 yamt goto noentry; 814 1.215 yamt } 815 1.215 yamt 816 1.274 yamt /* 817 1.274 yamt * investigate the vnode returned by cache_lookup_raw. 818 1.274 yamt * if it isn't appropriate, do an rpc. 819 1.274 yamt */ 820 1.59 fvdl newvp = *vpp; 821 1.278 yamt if ((flags & ISDOTDOT) != 0) { 822 1.284 hannken VOP_UNLOCK(dvp); 823 1.278 yamt } 824 1.304 hannken error = vn_lock(newvp, LK_SHARED); 825 1.278 yamt if ((flags & ISDOTDOT) != 0) { 826 1.278 yamt vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 827 1.278 yamt } 828 1.278 yamt if (error != 0) { 829 1.278 yamt /* newvp has been reclaimed. */ 830 1.278 yamt vrele(newvp); 831 1.278 yamt *vpp = NULLVP; 832 1.278 yamt goto dorpc; 833 1.278 yamt } 834 1.260 pooka if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred) 835 1.203 yamt && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) { 836 1.106 jdolecek nfsstats.lookupcache_hits++; 837 1.190 yamt KASSERT(newvp->v_type != VNON); 838 1.304 hannken VOP_UNLOCK(newvp); 839 1.106 jdolecek return (0); 840 1.1 cgd } 841 1.297 dholland cache_purge1(newvp, NULL, 0, PURGE_PARENTS); 842 1.278 yamt vput(newvp); 843 1.32 mycroft *vpp = NULLVP; 844 1.32 mycroft } 845 1.82 fvdl dorpc: 846 1.199 yamt #if 0 847 1.192 yamt /* 848 1.192 yamt * because nfsv3 has the same CREATE semantics as ours, 849 1.192 yamt * we don't have to perform LOOKUPs beforehand. 850 1.192 yamt * 851 1.192 yamt * XXX ideally we can do the same for nfsv2 in the case of !O_EXCL. 852 1.192 yamt * XXX although we have no way to know if O_EXCL is requested or not. 853 1.192 yamt */ 854 1.192 yamt 855 1.196 yamt if (v3 && cnp->cn_nameiop == CREATE && 856 1.196 yamt (flags & (ISLASTCN|ISDOTDOT)) == ISLASTCN && 857 1.193 yamt (dvp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 858 1.192 yamt return (EJUSTRETURN); 859 1.192 yamt } 860 1.199 yamt #endif /* 0 */ 861 1.192 yamt 862 1.1 cgd error = 0; 863 1.59 fvdl newvp = NULLVP; 864 1.1 cgd nfsstats.lookupcache_misses++; 865 1.1 cgd nfsstats.rpccnt[NFSPROC_LOOKUP]++; 866 1.32 mycroft len = cnp->cn_namelen; 867 1.165 drochner nfsm_reqhead(np, NFSPROC_LOOKUP, 868 1.59 fvdl NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); 869 1.165 drochner nfsm_fhtom(np, v3); 870 1.32 mycroft nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 871 1.261 pooka nfsm_request(np, NFSPROC_LOOKUP, curlwp, cnp->cn_cred); 872 1.1 cgd if (error) { 873 1.153 yamt nfsm_postop_attr(dvp, attrflag, 0); 874 1.59 fvdl m_freem(mrep); 875 1.59 fvdl goto nfsmout; 876 1.32 mycroft } 877 1.59 fvdl nfsm_getfh(fhp, fhsize, v3); 878 1.1 cgd 879 1.1 cgd /* 880 1.32 mycroft * Handle RENAME case... 881 1.1 cgd */ 882 1.246 chs if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) { 883 1.59 fvdl if (NFS_CMPFH(np, fhp, fhsize)) { 884 1.1 cgd m_freem(mrep); 885 1.1 cgd return (EISDIR); 886 1.1 cgd } 887 1.175 fvdl error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); 888 1.59 fvdl if (error) { 889 1.1 cgd m_freem(mrep); 890 1.128 fvdl return error; 891 1.1 cgd } 892 1.1 cgd newvp = NFSTOV(np); 893 1.200 christos #ifndef NFS_V2_ONLY 894 1.59 fvdl if (v3) { 895 1.153 yamt nfsm_postop_attr(newvp, attrflag, 0); 896 1.153 yamt nfsm_postop_attr(dvp, attrflag, 0); 897 1.59 fvdl } else 898 1.200 christos #endif 899 1.153 yamt nfsm_loadattr(newvp, (struct vattr *)0, 0); 900 1.32 mycroft *vpp = newvp; 901 1.1 cgd m_freem(mrep); 902 1.190 yamt goto validate; 903 1.1 cgd } 904 1.1 cgd 905 1.128 fvdl /* 906 1.128 fvdl * The postop attr handling is duplicated for each if case, 907 1.128 fvdl * because it should be done while dvp is locked (unlocking 908 1.128 fvdl * dvp is different for each case). 909 1.128 fvdl */ 910 1.128 fvdl 911 1.59 fvdl if (NFS_CMPFH(np, fhp, fhsize)) { 912 1.128 fvdl /* 913 1.309 hannken * As we handle "." lookup locally, this is 914 1.274 yamt * a broken server. 915 1.128 fvdl */ 916 1.309 hannken m_freem(mrep); 917 1.309 hannken return EBADRPC; 918 1.128 fvdl } else if (flags & ISDOTDOT) { 919 1.128 fvdl /* 920 1.128 fvdl * ".." lookup 921 1.128 fvdl */ 922 1.284 hannken VOP_UNLOCK(dvp); 923 1.175 fvdl error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); 924 1.246 chs vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 925 1.128 fvdl if (error) { 926 1.128 fvdl m_freem(mrep); 927 1.128 fvdl return error; 928 1.128 fvdl } 929 1.128 fvdl newvp = NFSTOV(np); 930 1.128 fvdl 931 1.200 christos #ifndef NFS_V2_ONLY 932 1.128 fvdl if (v3) { 933 1.153 yamt nfsm_postop_attr(newvp, attrflag, 0); 934 1.153 yamt nfsm_postop_attr(dvp, attrflag, 0); 935 1.128 fvdl } else 936 1.200 christos #endif 937 1.153 yamt nfsm_loadattr(newvp, (struct vattr *)0, 0); 938 1.1 cgd } else { 939 1.128 fvdl /* 940 1.128 fvdl * Other lookups. 941 1.128 fvdl */ 942 1.175 fvdl error = nfs_nget(dvp->v_mount, fhp, fhsize, &np); 943 1.59 fvdl if (error) { 944 1.1 cgd m_freem(mrep); 945 1.128 fvdl return error; 946 1.1 cgd } 947 1.1 cgd newvp = NFSTOV(np); 948 1.200 christos #ifndef NFS_V2_ONLY 949 1.128 fvdl if (v3) { 950 1.153 yamt nfsm_postop_attr(newvp, attrflag, 0); 951 1.153 yamt nfsm_postop_attr(dvp, attrflag, 0); 952 1.128 fvdl } else 953 1.200 christos #endif 954 1.153 yamt nfsm_loadattr(newvp, (struct vattr *)0, 0); 955 1.1 cgd } 956 1.295 rmind if (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)) { 957 1.188 yamt nfs_cache_enter(dvp, newvp, cnp); 958 1.1 cgd } 959 1.59 fvdl *vpp = newvp; 960 1.59 fvdl nfsm_reqdone; 961 1.59 fvdl if (error) { 962 1.128 fvdl /* 963 1.128 fvdl * We get here only because of errors returned by 964 1.128 fvdl * the RPC. Otherwise we'll have returned above 965 1.128 fvdl * (the nfsm_* macros will jump to nfsm_reqdone 966 1.128 fvdl * on error). 967 1.128 fvdl */ 968 1.295 rmind if (error == ENOENT && cnp->cn_nameiop != CREATE) { 969 1.188 yamt nfs_cache_enter(dvp, NULL, cnp); 970 1.82 fvdl } 971 1.128 fvdl if (newvp != NULLVP) { 972 1.246 chs if (newvp == dvp) { 973 1.246 chs vrele(newvp); 974 1.246 chs } else { 975 1.246 chs vput(newvp); 976 1.246 chs } 977 1.128 fvdl } 978 1.203 yamt noentry: 979 1.59 fvdl if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 980 1.59 fvdl (flags & ISLASTCN) && error == ENOENT) { 981 1.203 yamt if (dvp->v_mount->mnt_flag & MNT_RDONLY) { 982 1.59 fvdl error = EROFS; 983 1.203 yamt } else { 984 1.59 fvdl error = EJUSTRETURN; 985 1.203 yamt } 986 1.59 fvdl } 987 1.128 fvdl *vpp = NULL; 988 1.190 yamt return error; 989 1.190 yamt } 990 1.190 yamt 991 1.190 yamt validate: 992 1.190 yamt /* 993 1.190 yamt * make sure we have valid type and size. 994 1.190 yamt */ 995 1.190 yamt 996 1.190 yamt newvp = *vpp; 997 1.190 yamt if (newvp->v_type == VNON) { 998 1.190 yamt struct vattr vattr; /* dummy */ 999 1.190 yamt 1000 1.190 yamt KASSERT(VTONFS(newvp)->n_attrstamp == 0); 1001 1.260 pooka error = VOP_GETATTR(newvp, &vattr, cnp->cn_cred); 1002 1.190 yamt if (error) { 1003 1.190 yamt vput(newvp); 1004 1.190 yamt *vpp = NULL; 1005 1.190 yamt } 1006 1.59 fvdl } 1007 1.304 hannken if (error) 1008 1.304 hannken return error; 1009 1.304 hannken if (newvp != dvp) 1010 1.304 hannken VOP_UNLOCK(newvp); 1011 1.304 hannken return 0; 1012 1.1 cgd } 1013 1.1 cgd 1014 1.1 cgd /* 1015 1.1 cgd * nfs read call. 1016 1.1 cgd * Just call nfs_bioread() to do the work. 1017 1.1 cgd */ 1018 1.32 mycroft int 1019 1.272 dsl nfs_read(void *v) 1020 1.58 christos { 1021 1.32 mycroft struct vop_read_args /* { 1022 1.32 mycroft struct vnode *a_vp; 1023 1.32 mycroft struct uio *a_uio; 1024 1.32 mycroft int a_ioflag; 1025 1.236 elad kauth_cred_t a_cred; 1026 1.58 christos } */ *ap = v; 1027 1.110 augustss struct vnode *vp = ap->a_vp; 1028 1.32 mycroft 1029 1.1 cgd if (vp->v_type != VREG) 1030 1.229 yamt return EISDIR; 1031 1.81 fvdl return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0)); 1032 1.1 cgd } 1033 1.1 cgd 1034 1.1 cgd /* 1035 1.1 cgd * nfs readlink call 1036 1.1 cgd */ 1037 1.32 mycroft int 1038 1.272 dsl nfs_readlink(void *v) 1039 1.58 christos { 1040 1.32 mycroft struct vop_readlink_args /* { 1041 1.32 mycroft struct vnode *a_vp; 1042 1.32 mycroft struct uio *a_uio; 1043 1.236 elad kauth_cred_t a_cred; 1044 1.58 christos } */ *ap = v; 1045 1.110 augustss struct vnode *vp = ap->a_vp; 1046 1.224 yamt struct nfsnode *np = VTONFS(vp); 1047 1.32 mycroft 1048 1.1 cgd if (vp->v_type != VLNK) 1049 1.1 cgd return (EPERM); 1050 1.224 yamt 1051 1.224 yamt if (np->n_rcred != NULL) { 1052 1.236 elad kauth_cred_free(np->n_rcred); 1053 1.224 yamt } 1054 1.224 yamt np->n_rcred = ap->a_cred; 1055 1.236 elad kauth_cred_hold(np->n_rcred); 1056 1.224 yamt 1057 1.81 fvdl return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0)); 1058 1.1 cgd } 1059 1.1 cgd 1060 1.1 cgd /* 1061 1.1 cgd * Do a readlink rpc. 1062 1.1 cgd * Called by nfs_doio() from below the buffer cache. 1063 1.1 cgd */ 1064 1.32 mycroft int 1065 1.272 dsl nfs_readlinkrpc(struct vnode *vp, struct uio *uiop, kauth_cred_t cred) 1066 1.1 cgd { 1067 1.110 augustss u_int32_t *tl; 1068 1.252 christos char *cp; 1069 1.110 augustss int32_t t1, t2; 1070 1.252 christos char *bpos, *dpos, *cp2; 1071 1.200 christos int error = 0; 1072 1.169 yamt uint32_t len; 1073 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1074 1.119 bjh21 const int v3 = NFS_ISV3(vp); 1075 1.165 drochner struct nfsnode *np = VTONFS(vp); 1076 1.200 christos #ifndef NFS_V2_ONLY 1077 1.200 christos int attrflag; 1078 1.200 christos #endif 1079 1.1 cgd 1080 1.1 cgd nfsstats.rpccnt[NFSPROC_READLINK]++; 1081 1.165 drochner nfsm_reqhead(np, NFSPROC_READLINK, NFSX_FH(v3)); 1082 1.165 drochner nfsm_fhtom(np, v3); 1083 1.231 yamt nfsm_request(np, NFSPROC_READLINK, curlwp, cred); 1084 1.200 christos #ifndef NFS_V2_ONLY 1085 1.59 fvdl if (v3) 1086 1.153 yamt nfsm_postop_attr(vp, attrflag, 0); 1087 1.200 christos #endif 1088 1.59 fvdl if (!error) { 1089 1.200 christos #ifndef NFS_V2_ONLY 1090 1.169 yamt if (v3) { 1091 1.169 yamt nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED); 1092 1.169 yamt len = fxdr_unsigned(uint32_t, *tl); 1093 1.292 christos if (len > NFS_MAXPATHLEN) { 1094 1.169 yamt /* 1095 1.169 yamt * this pathname is too long for us. 1096 1.169 yamt */ 1097 1.169 yamt m_freem(mrep); 1098 1.169 yamt /* Solaris returns EINVAL. should we follow? */ 1099 1.169 yamt error = ENAMETOOLONG; 1100 1.169 yamt goto nfsmout; 1101 1.169 yamt } 1102 1.200 christos } else 1103 1.200 christos #endif 1104 1.200 christos { 1105 1.169 yamt nfsm_strsiz(len, NFS_MAXPATHLEN); 1106 1.169 yamt } 1107 1.59 fvdl nfsm_mtouio(uiop, len); 1108 1.59 fvdl } 1109 1.1 cgd nfsm_reqdone; 1110 1.1 cgd return (error); 1111 1.1 cgd } 1112 1.1 cgd 1113 1.1 cgd /* 1114 1.1 cgd * nfs read rpc call 1115 1.1 cgd * Ditto above 1116 1.1 cgd */ 1117 1.32 mycroft int 1118 1.272 dsl nfs_readrpc(struct vnode *vp, struct uio *uiop) 1119 1.1 cgd { 1120 1.110 augustss u_int32_t *tl; 1121 1.252 christos char *cp; 1122 1.110 augustss int32_t t1, t2; 1123 1.252 christos char *bpos, *dpos, *cp2; 1124 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1125 1.1 cgd struct nfsmount *nmp; 1126 1.301 nisimura int error = 0, len, retlen, tsiz, eof __unused, byte_count; 1127 1.119 bjh21 const int v3 = NFS_ISV3(vp); 1128 1.165 drochner struct nfsnode *np = VTONFS(vp); 1129 1.200 christos #ifndef NFS_V2_ONLY 1130 1.200 christos int attrflag; 1131 1.200 christos #endif 1132 1.1 cgd 1133 1.59 fvdl #ifndef nolint 1134 1.59 fvdl eof = 0; 1135 1.59 fvdl #endif 1136 1.1 cgd nmp = VFSTONFS(vp->v_mount); 1137 1.1 cgd tsiz = uiop->uio_resid; 1138 1.80 fvdl if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) 1139 1.32 mycroft return (EFBIG); 1140 1.232 blymn iostat_busy(nmp->nm_stats); 1141 1.232 blymn byte_count = 0; /* count bytes actually transferred */ 1142 1.1 cgd while (tsiz > 0) { 1143 1.1 cgd nfsstats.rpccnt[NFSPROC_READ]++; 1144 1.1 cgd len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz; 1145 1.165 drochner nfsm_reqhead(np, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3); 1146 1.165 drochner nfsm_fhtom(np, v3); 1147 1.59 fvdl nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1148 1.200 christos #ifndef NFS_V2_ONLY 1149 1.59 fvdl if (v3) { 1150 1.98 fair txdr_hyper(uiop->uio_offset, tl); 1151 1.32 mycroft *(tl + 2) = txdr_unsigned(len); 1152 1.200 christos } else 1153 1.200 christos #endif 1154 1.200 christos { 1155 1.32 mycroft *tl++ = txdr_unsigned(uiop->uio_offset); 1156 1.32 mycroft *tl++ = txdr_unsigned(len); 1157 1.32 mycroft *tl = 0; 1158 1.32 mycroft } 1159 1.231 yamt nfsm_request(np, NFSPROC_READ, curlwp, np->n_rcred); 1160 1.200 christos #ifndef NFS_V2_ONLY 1161 1.59 fvdl if (v3) { 1162 1.153 yamt nfsm_postop_attr(vp, attrflag, NAC_NOTRUNC); 1163 1.59 fvdl if (error) { 1164 1.59 fvdl m_freem(mrep); 1165 1.59 fvdl goto nfsmout; 1166 1.59 fvdl } 1167 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1168 1.59 fvdl eof = fxdr_unsigned(int, *(tl + 1)); 1169 1.59 fvdl } else 1170 1.200 christos #endif 1171 1.153 yamt nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC); 1172 1.1 cgd nfsm_strsiz(retlen, nmp->nm_rsize); 1173 1.1 cgd nfsm_mtouio(uiop, retlen); 1174 1.1 cgd m_freem(mrep); 1175 1.59 fvdl tsiz -= retlen; 1176 1.232 blymn byte_count += retlen; 1177 1.200 christos #ifndef NFS_V2_ONLY 1178 1.59 fvdl if (v3) { 1179 1.59 fvdl if (eof || retlen == 0) 1180 1.59 fvdl tsiz = 0; 1181 1.200 christos } else 1182 1.200 christos #endif 1183 1.200 christos if (retlen < len) 1184 1.1 cgd tsiz = 0; 1185 1.1 cgd } 1186 1.1 cgd nfsmout: 1187 1.232 blymn iostat_unbusy(nmp->nm_stats, byte_count, 1); 1188 1.1 cgd return (error); 1189 1.1 cgd } 1190 1.1 cgd 1191 1.171 yamt struct nfs_writerpc_context { 1192 1.253 yamt kmutex_t nwc_lock; 1193 1.253 yamt kcondvar_t nwc_cv; 1194 1.253 yamt int nwc_mbufcount; 1195 1.171 yamt }; 1196 1.171 yamt 1197 1.1 cgd /* 1198 1.170 yamt * free mbuf used to refer protected pages while write rpc call. 1199 1.171 yamt * called at splvm. 1200 1.167 yamt */ 1201 1.167 yamt static void 1202 1.252 christos nfs_writerpc_extfree(struct mbuf *m, void *tbuf, size_t size, void *arg) 1203 1.167 yamt { 1204 1.171 yamt struct nfs_writerpc_context *ctx = arg; 1205 1.170 yamt 1206 1.170 yamt KASSERT(m != NULL); 1207 1.171 yamt KASSERT(ctx != NULL); 1208 1.258 ad pool_cache_put(mb_cache, m); 1209 1.253 yamt mutex_enter(&ctx->nwc_lock); 1210 1.171 yamt if (--ctx->nwc_mbufcount == 0) { 1211 1.253 yamt cv_signal(&ctx->nwc_cv); 1212 1.171 yamt } 1213 1.253 yamt mutex_exit(&ctx->nwc_lock); 1214 1.167 yamt } 1215 1.167 yamt 1216 1.167 yamt /* 1217 1.1 cgd * nfs write call 1218 1.1 cgd */ 1219 1.32 mycroft int 1220 1.272 dsl nfs_writerpc(struct vnode *vp, struct uio *uiop, int *iomode, bool pageprotected, bool *stalewriteverfp) 1221 1.1 cgd { 1222 1.110 augustss u_int32_t *tl; 1223 1.252 christos char *cp; 1224 1.173 yamt int32_t t1, t2; 1225 1.252 christos char *bpos, *dpos; 1226 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1227 1.59 fvdl struct nfsmount *nmp = VFSTONFS(vp->v_mount); 1228 1.200 christos int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR; 1229 1.119 bjh21 const int v3 = NFS_ISV3(vp); 1230 1.119 bjh21 int committed = NFSV3WRITE_FILESYNC; 1231 1.165 drochner struct nfsnode *np = VTONFS(vp); 1232 1.171 yamt struct nfs_writerpc_context ctx; 1233 1.253 yamt int byte_count; 1234 1.173 yamt size_t origresid; 1235 1.200 christos #ifndef NFS_V2_ONLY 1236 1.252 christos char *cp2; 1237 1.200 christos int rlen, commit; 1238 1.200 christos #endif 1239 1.171 yamt 1240 1.125 chs if (vp->v_mount->mnt_flag & MNT_RDONLY) { 1241 1.125 chs panic("writerpc readonly vp %p", vp); 1242 1.125 chs } 1243 1.1 cgd 1244 1.142 bjh21 #ifdef DIAGNOSTIC 1245 1.59 fvdl if (uiop->uio_iovcnt != 1) 1246 1.59 fvdl panic("nfs: writerpc iovcnt > 1"); 1247 1.59 fvdl #endif 1248 1.1 cgd tsiz = uiop->uio_resid; 1249 1.80 fvdl if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) 1250 1.289 cegger return EFBIG; 1251 1.289 cegger 1252 1.289 cegger mutex_init(&ctx.nwc_lock, MUTEX_DRIVER, IPL_VM); 1253 1.289 cegger cv_init(&ctx.nwc_cv, "nfsmblk"); 1254 1.289 cegger ctx.nwc_mbufcount = 1; 1255 1.289 cegger 1256 1.173 yamt retry: 1257 1.173 yamt origresid = uiop->uio_resid; 1258 1.173 yamt KASSERT(origresid == uiop->uio_iov->iov_len); 1259 1.232 blymn iostat_busy(nmp->nm_stats); 1260 1.232 blymn byte_count = 0; /* count of bytes actually written */ 1261 1.1 cgd while (tsiz > 0) { 1262 1.173 yamt uint32_t datalen; /* data bytes need to be allocated in mbuf */ 1263 1.308 chs size_t backup; 1264 1.251 thorpej bool stalewriteverf = false; 1265 1.167 yamt 1266 1.1 cgd nfsstats.rpccnt[NFSPROC_WRITE]++; 1267 1.311 riastrad len = uimin(tsiz, nmp->nm_wsize); 1268 1.167 yamt datalen = pageprotected ? 0 : nfsm_rndup(len); 1269 1.165 drochner nfsm_reqhead(np, NFSPROC_WRITE, 1270 1.167 yamt NFSX_FH(v3) + 5 * NFSX_UNSIGNED + datalen); 1271 1.165 drochner nfsm_fhtom(np, v3); 1272 1.200 christos #ifndef NFS_V2_ONLY 1273 1.59 fvdl if (v3) { 1274 1.59 fvdl nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1275 1.98 fair txdr_hyper(uiop->uio_offset, tl); 1276 1.32 mycroft tl += 2; 1277 1.59 fvdl *tl++ = txdr_unsigned(len); 1278 1.59 fvdl *tl++ = txdr_unsigned(*iomode); 1279 1.50 gwr *tl = txdr_unsigned(len); 1280 1.200 christos } else 1281 1.200 christos #endif 1282 1.200 christos { 1283 1.110 augustss u_int32_t x; 1284 1.59 fvdl 1285 1.59 fvdl nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1286 1.50 gwr /* Set both "begin" and "current" to non-garbage. */ 1287 1.50 gwr x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1288 1.59 fvdl *tl++ = x; /* "begin offset" */ 1289 1.59 fvdl *tl++ = x; /* "current offset" */ 1290 1.50 gwr x = txdr_unsigned(len); 1291 1.59 fvdl *tl++ = x; /* total to this offset */ 1292 1.59 fvdl *tl = x; /* size of this write */ 1293 1.59 fvdl 1294 1.32 mycroft } 1295 1.167 yamt if (pageprotected) { 1296 1.167 yamt /* 1297 1.167 yamt * since we know pages can't be modified during i/o, 1298 1.167 yamt * no need to copy them for us. 1299 1.167 yamt */ 1300 1.167 yamt struct mbuf *m; 1301 1.167 yamt struct iovec *iovp = uiop->uio_iov; 1302 1.167 yamt 1303 1.167 yamt m = m_get(M_WAIT, MT_DATA); 1304 1.170 yamt MCLAIM(m, &nfs_mowner); 1305 1.170 yamt MEXTADD(m, iovp->iov_base, len, M_MBUF, 1306 1.171 yamt nfs_writerpc_extfree, &ctx); 1307 1.167 yamt m->m_flags |= M_EXT_ROMAP; 1308 1.167 yamt m->m_len = len; 1309 1.167 yamt mb->m_next = m; 1310 1.167 yamt /* 1311 1.167 yamt * no need to maintain mb and bpos here 1312 1.167 yamt * because no one care them later. 1313 1.167 yamt */ 1314 1.167 yamt #if 0 1315 1.167 yamt mb = m; 1316 1.252 christos bpos = mtod(void *, mb) + mb->m_len; 1317 1.167 yamt #endif 1318 1.225 christos UIO_ADVANCE(uiop, len); 1319 1.167 yamt uiop->uio_offset += len; 1320 1.253 yamt mutex_enter(&ctx.nwc_lock); 1321 1.171 yamt ctx.nwc_mbufcount++; 1322 1.253 yamt mutex_exit(&ctx.nwc_lock); 1323 1.183 yamt nfs_zeropad(mb, 0, nfsm_padlen(len)); 1324 1.167 yamt } else { 1325 1.167 yamt nfsm_uiotom(uiop, len); 1326 1.167 yamt } 1327 1.231 yamt nfsm_request(np, NFSPROC_WRITE, curlwp, np->n_wcred); 1328 1.200 christos #ifndef NFS_V2_ONLY 1329 1.59 fvdl if (v3) { 1330 1.59 fvdl wccflag = NFSV3_WCCCHK; 1331 1.216 yamt nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, !error); 1332 1.59 fvdl if (!error) { 1333 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1334 1.59 fvdl + NFSX_V3WRITEVERF); 1335 1.59 fvdl rlen = fxdr_unsigned(int, *tl++); 1336 1.59 fvdl if (rlen == 0) { 1337 1.59 fvdl error = NFSERR_IO; 1338 1.80 fvdl m_freem(mrep); 1339 1.59 fvdl break; 1340 1.59 fvdl } else if (rlen < len) { 1341 1.59 fvdl backup = len - rlen; 1342 1.225 christos UIO_ADVANCE(uiop, -backup); 1343 1.59 fvdl uiop->uio_offset -= backup; 1344 1.59 fvdl len = rlen; 1345 1.59 fvdl } 1346 1.59 fvdl commit = fxdr_unsigned(int, *tl++); 1347 1.59 fvdl 1348 1.59 fvdl /* 1349 1.324 andvar * Return the lowest commitment level 1350 1.59 fvdl * obtained by any of the RPCs. 1351 1.59 fvdl */ 1352 1.59 fvdl if (committed == NFSV3WRITE_FILESYNC) 1353 1.59 fvdl committed = commit; 1354 1.59 fvdl else if (committed == NFSV3WRITE_DATASYNC && 1355 1.59 fvdl commit == NFSV3WRITE_UNSTABLE) 1356 1.59 fvdl committed = commit; 1357 1.254 yamt mutex_enter(&nmp->nm_lock); 1358 1.81 fvdl if ((nmp->nm_iflag & NFSMNT_HASWRITEVERF) == 0){ 1359 1.166 yamt memcpy(nmp->nm_writeverf, tl, 1360 1.166 yamt NFSX_V3WRITEVERF); 1361 1.166 yamt nmp->nm_iflag |= NFSMNT_HASWRITEVERF; 1362 1.166 yamt } else if ((nmp->nm_iflag & 1363 1.166 yamt NFSMNT_STALEWRITEVERF) || 1364 1.166 yamt memcmp(tl, nmp->nm_writeverf, 1365 1.166 yamt NFSX_V3WRITEVERF)) { 1366 1.166 yamt memcpy(nmp->nm_writeverf, tl, 1367 1.166 yamt NFSX_V3WRITEVERF); 1368 1.173 yamt /* 1369 1.173 yamt * note NFSMNT_STALEWRITEVERF 1370 1.220 perry * if we're the first thread to 1371 1.173 yamt * notice it. 1372 1.173 yamt */ 1373 1.173 yamt if ((nmp->nm_iflag & 1374 1.173 yamt NFSMNT_STALEWRITEVERF) == 0) { 1375 1.251 thorpej stalewriteverf = true; 1376 1.173 yamt nmp->nm_iflag |= 1377 1.173 yamt NFSMNT_STALEWRITEVERF; 1378 1.173 yamt } 1379 1.59 fvdl } 1380 1.254 yamt mutex_exit(&nmp->nm_lock); 1381 1.59 fvdl } 1382 1.59 fvdl } else 1383 1.200 christos #endif 1384 1.172 yamt nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC); 1385 1.59 fvdl if (wccflag) 1386 1.180 yamt VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr->va_mtime; 1387 1.1 cgd m_freem(mrep); 1388 1.80 fvdl if (error) 1389 1.80 fvdl break; 1390 1.1 cgd tsiz -= len; 1391 1.232 blymn byte_count += len; 1392 1.173 yamt if (stalewriteverf) { 1393 1.251 thorpej *stalewriteverfp = true; 1394 1.251 thorpej stalewriteverf = false; 1395 1.173 yamt if (committed == NFSV3WRITE_UNSTABLE && 1396 1.173 yamt len != origresid) { 1397 1.173 yamt /* 1398 1.173 yamt * if our write requests weren't atomic but 1399 1.173 yamt * unstable, datas in previous iterations 1400 1.173 yamt * might have already been lost now. 1401 1.173 yamt * then, we should resend them to nfsd. 1402 1.173 yamt */ 1403 1.173 yamt backup = origresid - tsiz; 1404 1.225 christos UIO_ADVANCE(uiop, -backup); 1405 1.173 yamt uiop->uio_offset -= backup; 1406 1.173 yamt tsiz = origresid; 1407 1.173 yamt goto retry; 1408 1.173 yamt } 1409 1.173 yamt } 1410 1.171 yamt } 1411 1.210 yamt nfsmout: 1412 1.232 blymn iostat_unbusy(nmp->nm_stats, byte_count, 0); 1413 1.171 yamt if (pageprotected) { 1414 1.171 yamt /* 1415 1.171 yamt * wait until mbufs go away. 1416 1.171 yamt * retransmitted mbufs can survive longer than rpc requests 1417 1.171 yamt * themselves. 1418 1.171 yamt */ 1419 1.253 yamt mutex_enter(&ctx.nwc_lock); 1420 1.171 yamt ctx.nwc_mbufcount--; 1421 1.171 yamt while (ctx.nwc_mbufcount > 0) { 1422 1.253 yamt cv_wait(&ctx.nwc_cv, &ctx.nwc_lock); 1423 1.171 yamt } 1424 1.253 yamt mutex_exit(&ctx.nwc_lock); 1425 1.1 cgd } 1426 1.255 yamt mutex_destroy(&ctx.nwc_lock); 1427 1.255 yamt cv_destroy(&ctx.nwc_cv); 1428 1.59 fvdl *iomode = committed; 1429 1.32 mycroft if (error) 1430 1.32 mycroft uiop->uio_resid = tsiz; 1431 1.1 cgd return (error); 1432 1.1 cgd } 1433 1.1 cgd 1434 1.1 cgd /* 1435 1.59 fvdl * nfs mknod rpc 1436 1.59 fvdl * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1437 1.59 fvdl * mode set to specify the file type and the size field for rdev. 1438 1.1 cgd */ 1439 1.32 mycroft int 1440 1.272 dsl nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap) 1441 1.58 christos { 1442 1.110 augustss struct nfsv2_sattr *sp; 1443 1.110 augustss u_int32_t *tl; 1444 1.252 christos char *cp; 1445 1.110 augustss int32_t t1, t2; 1446 1.59 fvdl struct vnode *newvp = (struct vnode *)0; 1447 1.165 drochner struct nfsnode *dnp, *np; 1448 1.32 mycroft char *cp2; 1449 1.252 christos char *bpos, *dpos; 1450 1.59 fvdl int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0; 1451 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1452 1.53 cgd u_int32_t rdev; 1453 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 1454 1.1 cgd 1455 1.1 cgd if (vap->va_type == VCHR || vap->va_type == VBLK) 1456 1.1 cgd rdev = txdr_unsigned(vap->va_rdev); 1457 1.59 fvdl else if (vap->va_type == VFIFO || vap->va_type == VSOCK) 1458 1.59 fvdl rdev = nfs_xdrneg1; 1459 1.1 cgd else { 1460 1.32 mycroft VOP_ABORTOP(dvp, cnp); 1461 1.1 cgd return (EOPNOTSUPP); 1462 1.1 cgd } 1463 1.59 fvdl nfsstats.rpccnt[NFSPROC_MKNOD]++; 1464 1.165 drochner dnp = VTONFS(dvp); 1465 1.165 drochner nfsm_reqhead(dnp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED + 1466 1.59 fvdl + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); 1467 1.165 drochner nfsm_fhtom(dnp, v3); 1468 1.32 mycroft nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 1469 1.200 christos #ifndef NFS_V2_ONLY 1470 1.59 fvdl if (v3) { 1471 1.101 fvdl nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1472 1.59 fvdl *tl++ = vtonfsv3_type(vap->va_type); 1473 1.251 thorpej nfsm_v3attrbuild(vap, false); 1474 1.59 fvdl if (vap->va_type == VCHR || vap->va_type == VBLK) { 1475 1.59 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1476 1.59 fvdl *tl++ = txdr_unsigned(major(vap->va_rdev)); 1477 1.59 fvdl *tl = txdr_unsigned(minor(vap->va_rdev)); 1478 1.59 fvdl } 1479 1.200 christos } else 1480 1.200 christos #endif 1481 1.200 christos { 1482 1.59 fvdl nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1483 1.59 fvdl sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1484 1.59 fvdl sp->sa_uid = nfs_xdrneg1; 1485 1.59 fvdl sp->sa_gid = nfs_xdrneg1; 1486 1.59 fvdl sp->sa_size = rdev; 1487 1.59 fvdl txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 1488 1.59 fvdl txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 1489 1.59 fvdl } 1490 1.261 pooka nfsm_request(dnp, NFSPROC_MKNOD, curlwp, cnp->cn_cred); 1491 1.59 fvdl if (!error) { 1492 1.175 fvdl nfsm_mtofh(dvp, newvp, v3, gotvp); 1493 1.59 fvdl if (!gotvp) { 1494 1.59 fvdl error = nfs_lookitup(dvp, cnp->cn_nameptr, 1495 1.261 pooka cnp->cn_namelen, cnp->cn_cred, curlwp, &np); 1496 1.59 fvdl if (!error) 1497 1.59 fvdl newvp = NFSTOV(np); 1498 1.59 fvdl } 1499 1.32 mycroft } 1500 1.200 christos #ifndef NFS_V2_ONLY 1501 1.59 fvdl if (v3) 1502 1.216 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 1503 1.200 christos #endif 1504 1.1 cgd nfsm_reqdone; 1505 1.59 fvdl if (error) { 1506 1.59 fvdl if (newvp) 1507 1.128 fvdl vput(newvp); 1508 1.59 fvdl } else { 1509 1.295 rmind nfs_cache_enter(dvp, newvp, cnp); 1510 1.59 fvdl *vpp = newvp; 1511 1.303 hannken VOP_UNLOCK(newvp); 1512 1.59 fvdl } 1513 1.32 mycroft VTONFS(dvp)->n_flag |= NMODIFIED; 1514 1.59 fvdl if (!wccflag) 1515 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 1516 1.59 fvdl return (error); 1517 1.59 fvdl } 1518 1.59 fvdl 1519 1.59 fvdl /* 1520 1.59 fvdl * nfs mknod vop 1521 1.59 fvdl * just call nfs_mknodrpc() to do the work. 1522 1.59 fvdl */ 1523 1.59 fvdl /* ARGSUSED */ 1524 1.59 fvdl int 1525 1.272 dsl nfs_mknod(void *v) 1526 1.59 fvdl { 1527 1.303 hannken struct vop_mknod_v3_args /* { 1528 1.59 fvdl struct vnode *a_dvp; 1529 1.59 fvdl struct vnode **a_vpp; 1530 1.59 fvdl struct componentname *a_cnp; 1531 1.59 fvdl struct vattr *a_vap; 1532 1.59 fvdl } */ *ap = v; 1533 1.203 yamt struct vnode *dvp = ap->a_dvp; 1534 1.203 yamt struct componentname *cnp = ap->a_cnp; 1535 1.59 fvdl int error; 1536 1.59 fvdl 1537 1.203 yamt error = nfs_mknodrpc(dvp, ap->a_vpp, cnp, ap->a_vap); 1538 1.203 yamt if (error == 0 || error == EEXIST) 1539 1.297 dholland cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0); 1540 1.1 cgd return (error); 1541 1.1 cgd } 1542 1.1 cgd 1543 1.1 cgd /* 1544 1.1 cgd * nfs file create call 1545 1.1 cgd */ 1546 1.32 mycroft int 1547 1.272 dsl nfs_create(void *v) 1548 1.58 christos { 1549 1.303 hannken struct vop_create_v3_args /* { 1550 1.32 mycroft struct vnode *a_dvp; 1551 1.32 mycroft struct vnode **a_vpp; 1552 1.32 mycroft struct componentname *a_cnp; 1553 1.32 mycroft struct vattr *a_vap; 1554 1.58 christos } */ *ap = v; 1555 1.110 augustss struct vnode *dvp = ap->a_dvp; 1556 1.110 augustss struct vattr *vap = ap->a_vap; 1557 1.110 augustss struct componentname *cnp = ap->a_cnp; 1558 1.110 augustss struct nfsv2_sattr *sp; 1559 1.110 augustss u_int32_t *tl; 1560 1.252 christos char *cp; 1561 1.110 augustss int32_t t1, t2; 1562 1.165 drochner struct nfsnode *dnp, *np = (struct nfsnode *)0; 1563 1.59 fvdl struct vnode *newvp = (struct vnode *)0; 1564 1.252 christos char *bpos, *dpos, *cp2; 1565 1.262 yamt int error, wccflag = NFSV3_WCCRATTR, gotvp = 0; 1566 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1567 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 1568 1.262 yamt u_int32_t excl_mode = NFSV3CREATE_UNCHECKED; 1569 1.59 fvdl 1570 1.59 fvdl /* 1571 1.59 fvdl * Oops, not for me.. 1572 1.59 fvdl */ 1573 1.59 fvdl if (vap->va_type == VSOCK) 1574 1.59 fvdl return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap)); 1575 1.1 cgd 1576 1.204 yamt KASSERT(vap->va_type == VREG); 1577 1.204 yamt 1578 1.59 fvdl #ifdef VA_EXCLUSIVE 1579 1.262 yamt if (vap->va_vaflags & VA_EXCLUSIVE) { 1580 1.262 yamt excl_mode = NFSV3CREATE_EXCLUSIVE; 1581 1.262 yamt } 1582 1.59 fvdl #endif 1583 1.59 fvdl again: 1584 1.103 thorpej error = 0; 1585 1.1 cgd nfsstats.rpccnt[NFSPROC_CREATE]++; 1586 1.165 drochner dnp = VTONFS(dvp); 1587 1.165 drochner nfsm_reqhead(dnp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED + 1588 1.59 fvdl nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3)); 1589 1.165 drochner nfsm_fhtom(dnp, v3); 1590 1.32 mycroft nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 1591 1.200 christos #ifndef NFS_V2_ONLY 1592 1.59 fvdl if (v3) { 1593 1.59 fvdl nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1594 1.262 yamt if (excl_mode == NFSV3CREATE_EXCLUSIVE) { 1595 1.101 fvdl *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE); 1596 1.101 fvdl nfsm_build(tl, u_int32_t *, NFSX_V3CREATEVERF); 1597 1.293 tls *tl++ = cprng_fast32(); 1598 1.293 tls *tl = cprng_fast32(); 1599 1.59 fvdl } else { 1600 1.262 yamt *tl = txdr_unsigned(excl_mode); 1601 1.251 thorpej nfsm_v3attrbuild(vap, false); 1602 1.59 fvdl } 1603 1.200 christos } else 1604 1.200 christos #endif 1605 1.200 christos { 1606 1.59 fvdl nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1607 1.59 fvdl sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1608 1.59 fvdl sp->sa_uid = nfs_xdrneg1; 1609 1.59 fvdl sp->sa_gid = nfs_xdrneg1; 1610 1.59 fvdl sp->sa_size = 0; 1611 1.59 fvdl txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 1612 1.59 fvdl txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 1613 1.32 mycroft } 1614 1.261 pooka nfsm_request(dnp, NFSPROC_CREATE, curlwp, cnp->cn_cred); 1615 1.59 fvdl if (!error) { 1616 1.175 fvdl nfsm_mtofh(dvp, newvp, v3, gotvp); 1617 1.59 fvdl if (!gotvp) { 1618 1.59 fvdl error = nfs_lookitup(dvp, cnp->cn_nameptr, 1619 1.261 pooka cnp->cn_namelen, cnp->cn_cred, curlwp, &np); 1620 1.59 fvdl if (!error) 1621 1.59 fvdl newvp = NFSTOV(np); 1622 1.59 fvdl } 1623 1.59 fvdl } 1624 1.200 christos #ifndef NFS_V2_ONLY 1625 1.59 fvdl if (v3) 1626 1.216 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 1627 1.200 christos #endif 1628 1.1 cgd nfsm_reqdone; 1629 1.59 fvdl if (error) { 1630 1.238 yamt /* 1631 1.238 yamt * nfs_request maps NFSERR_NOTSUPP to ENOTSUP. 1632 1.238 yamt */ 1633 1.262 yamt if (v3 && error == ENOTSUP) { 1634 1.262 yamt if (excl_mode == NFSV3CREATE_EXCLUSIVE) { 1635 1.262 yamt excl_mode = NFSV3CREATE_GUARDED; 1636 1.262 yamt goto again; 1637 1.262 yamt } else if (excl_mode == NFSV3CREATE_GUARDED) { 1638 1.262 yamt excl_mode = NFSV3CREATE_UNCHECKED; 1639 1.262 yamt goto again; 1640 1.262 yamt } 1641 1.59 fvdl } 1642 1.262 yamt } else if (v3 && (excl_mode == NFSV3CREATE_EXCLUSIVE)) { 1643 1.237 kardel struct timespec ts; 1644 1.237 kardel 1645 1.237 kardel getnanotime(&ts); 1646 1.204 yamt 1647 1.204 yamt /* 1648 1.204 yamt * make sure that we'll update timestamps as 1649 1.204 yamt * most server implementations use them to store 1650 1.204 yamt * the create verifier. 1651 1.204 yamt * 1652 1.204 yamt * XXX it's better to use TOSERVER always. 1653 1.204 yamt */ 1654 1.204 yamt 1655 1.237 kardel if (vap->va_atime.tv_sec == VNOVAL) 1656 1.237 kardel vap->va_atime = ts; 1657 1.237 kardel if (vap->va_mtime.tv_sec == VNOVAL) 1658 1.237 kardel vap->va_mtime = ts; 1659 1.204 yamt 1660 1.261 pooka error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, curlwp); 1661 1.204 yamt } 1662 1.203 yamt if (error == 0) { 1663 1.59 fvdl if (cnp->cn_flags & MAKEENTRY) 1664 1.188 yamt nfs_cache_enter(dvp, newvp, cnp); 1665 1.203 yamt else 1666 1.297 dholland cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0); 1667 1.59 fvdl *ap->a_vpp = newvp; 1668 1.303 hannken VOP_UNLOCK(newvp); 1669 1.203 yamt } else { 1670 1.203 yamt if (newvp) 1671 1.203 yamt vput(newvp); 1672 1.203 yamt if (error == EEXIST) 1673 1.297 dholland cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0); 1674 1.59 fvdl } 1675 1.32 mycroft VTONFS(dvp)->n_flag |= NMODIFIED; 1676 1.59 fvdl if (!wccflag) 1677 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 1678 1.1 cgd return (error); 1679 1.1 cgd } 1680 1.1 cgd 1681 1.1 cgd /* 1682 1.1 cgd * nfs file remove call 1683 1.1 cgd * To try and make nfs semantics closer to ufs semantics, a file that has 1684 1.1 cgd * other processes using the vnode is renamed instead of removed and then 1685 1.1 cgd * removed later on the last close. 1686 1.314 ad * - If vrefcnt(vp) > 1 1687 1.1 cgd * If a rename is not already in the works 1688 1.1 cgd * call nfs_sillyrename() to set it up 1689 1.1 cgd * else 1690 1.1 cgd * do the remove rpc 1691 1.1 cgd */ 1692 1.32 mycroft int 1693 1.272 dsl nfs_remove(void *v) 1694 1.58 christos { 1695 1.321 thorpej struct vop_remove_v3_args /* { 1696 1.32 mycroft struct vnodeop_desc *a_desc; 1697 1.32 mycroft struct vnode * a_dvp; 1698 1.32 mycroft struct vnode * a_vp; 1699 1.32 mycroft struct componentname * a_cnp; 1700 1.321 thorpej nlink_t ctx_vp_new_nlink; 1701 1.58 christos } */ *ap = v; 1702 1.110 augustss struct vnode *vp = ap->a_vp; 1703 1.110 augustss struct vnode *dvp = ap->a_dvp; 1704 1.110 augustss struct componentname *cnp = ap->a_cnp; 1705 1.110 augustss struct nfsnode *np = VTONFS(vp); 1706 1.1 cgd int error = 0; 1707 1.38 pk struct vattr vattr; 1708 1.1 cgd 1709 1.59 fvdl #ifndef DIAGNOSTIC 1710 1.314 ad if (vrefcnt(vp) < 1) 1711 1.314 ad panic("nfs_remove: bad vrefcnt(vp)"); 1712 1.59 fvdl #endif 1713 1.77 fvdl if (vp->v_type == VDIR) 1714 1.77 fvdl error = EPERM; 1715 1.314 ad else if (vrefcnt(vp) == 1 || (np->n_sillyrename && 1716 1.260 pooka VOP_GETATTR(vp, &vattr, cnp->cn_cred) == 0 && 1717 1.59 fvdl vattr.va_nlink > 1)) { 1718 1.32 mycroft /* 1719 1.32 mycroft * Purge the name cache so that the chance of a lookup for 1720 1.32 mycroft * the name succeeding while the remove is in progress is 1721 1.32 mycroft * minimized. Without node locking it can still happen, such 1722 1.32 mycroft * that an I/O op returns ESTALE, but since you get this if 1723 1.32 mycroft * another host removes the file.. 1724 1.32 mycroft */ 1725 1.32 mycroft cache_purge(vp); 1726 1.32 mycroft /* 1727 1.59 fvdl * throw away biocache buffers, mainly to avoid 1728 1.59 fvdl * unnecessary delayed writes later. 1729 1.32 mycroft */ 1730 1.261 pooka error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, curlwp, 1); 1731 1.32 mycroft /* Do the rpc */ 1732 1.59 fvdl if (error != EINTR) 1733 1.59 fvdl error = nfs_removerpc(dvp, cnp->cn_nameptr, 1734 1.261 pooka cnp->cn_namelen, cnp->cn_cred, curlwp); 1735 1.59 fvdl } else if (!np->n_sillyrename) 1736 1.251 thorpej error = nfs_sillyrename(dvp, vp, cnp, false); 1737 1.321 thorpej if (error == 0 && nfs_getattrcache(vp, &vattr) == 0) { 1738 1.321 thorpej ap->ctx_vp_new_nlink = vattr.va_nlink - 1; 1739 1.321 thorpej if (vattr.va_nlink == 1) 1740 1.321 thorpej np->n_flag |= NREMOVED; 1741 1.176 yamt } 1742 1.185 yamt NFS_INVALIDATE_ATTRCACHE(np); 1743 1.152 thorpej if (dvp == vp) 1744 1.152 thorpej vrele(vp); 1745 1.152 thorpej else 1746 1.152 thorpej vput(vp); 1747 1.1 cgd return (error); 1748 1.1 cgd } 1749 1.1 cgd 1750 1.1 cgd /* 1751 1.1 cgd * nfs file remove rpc called from nfs_inactive 1752 1.1 cgd */ 1753 1.32 mycroft int 1754 1.272 dsl nfs_removeit(struct sillyrename *sp) 1755 1.1 cgd { 1756 1.59 fvdl 1757 1.59 fvdl return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred, 1758 1.230 christos (struct lwp *)0)); 1759 1.59 fvdl } 1760 1.59 fvdl 1761 1.59 fvdl /* 1762 1.59 fvdl * Nfs remove rpc, called from nfs_remove() and nfs_removeit(). 1763 1.59 fvdl */ 1764 1.59 fvdl int 1765 1.272 dsl nfs_removerpc(struct vnode *dvp, const char *name, int namelen, kauth_cred_t cred, struct lwp *l) 1766 1.59 fvdl { 1767 1.110 augustss u_int32_t *tl; 1768 1.252 christos char *cp; 1769 1.200 christos #ifndef NFS_V2_ONLY 1770 1.200 christos int32_t t1; 1771 1.252 christos char *cp2; 1772 1.200 christos #endif 1773 1.200 christos int32_t t2; 1774 1.252 christos char *bpos, *dpos; 1775 1.59 fvdl int error = 0, wccflag = NFSV3_WCCRATTR; 1776 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1777 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 1778 1.234 christos int rexmit = 0; 1779 1.165 drochner struct nfsnode *dnp = VTONFS(dvp); 1780 1.1 cgd 1781 1.1 cgd nfsstats.rpccnt[NFSPROC_REMOVE]++; 1782 1.165 drochner nfsm_reqhead(dnp, NFSPROC_REMOVE, 1783 1.59 fvdl NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen)); 1784 1.165 drochner nfsm_fhtom(dnp, v3); 1785 1.59 fvdl nfsm_strtom(name, namelen, NFS_MAXNAMLEN); 1786 1.230 christos nfsm_request1(dnp, NFSPROC_REMOVE, l, cred, &rexmit); 1787 1.200 christos #ifndef NFS_V2_ONLY 1788 1.59 fvdl if (v3) 1789 1.216 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 1790 1.200 christos #endif 1791 1.1 cgd nfsm_reqdone; 1792 1.59 fvdl VTONFS(dvp)->n_flag |= NMODIFIED; 1793 1.59 fvdl if (!wccflag) 1794 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 1795 1.197 yamt /* 1796 1.197 yamt * Kludge City: If the first reply to the remove rpc is lost.. 1797 1.197 yamt * the reply to the retransmitted request will be ENOENT 1798 1.197 yamt * since the file was in fact removed 1799 1.197 yamt * Therefore, we cheat and return success. 1800 1.197 yamt */ 1801 1.197 yamt if (rexmit && error == ENOENT) 1802 1.197 yamt error = 0; 1803 1.1 cgd return (error); 1804 1.1 cgd } 1805 1.1 cgd 1806 1.1 cgd /* 1807 1.1 cgd * nfs file rename call 1808 1.1 cgd */ 1809 1.32 mycroft int 1810 1.272 dsl nfs_rename(void *v) 1811 1.58 christos { 1812 1.321 thorpej struct vop_rename_args /* { 1813 1.32 mycroft struct vnode *a_fdvp; 1814 1.32 mycroft struct vnode *a_fvp; 1815 1.32 mycroft struct componentname *a_fcnp; 1816 1.32 mycroft struct vnode *a_tdvp; 1817 1.32 mycroft struct vnode *a_tvp; 1818 1.32 mycroft struct componentname *a_tcnp; 1819 1.58 christos } */ *ap = v; 1820 1.111 augustss struct vnode *fvp = ap->a_fvp; 1821 1.111 augustss struct vnode *tvp = ap->a_tvp; 1822 1.111 augustss struct vnode *fdvp = ap->a_fdvp; 1823 1.111 augustss struct vnode *tdvp = ap->a_tdvp; 1824 1.111 augustss struct componentname *tcnp = ap->a_tcnp; 1825 1.111 augustss struct componentname *fcnp = ap->a_fcnp; 1826 1.59 fvdl int error; 1827 1.17 cgd 1828 1.17 cgd /* Check for cross-device rename */ 1829 1.17 cgd if ((fvp->v_mount != tdvp->v_mount) || 1830 1.17 cgd (tvp && (fvp->v_mount != tvp->v_mount))) { 1831 1.17 cgd error = EXDEV; 1832 1.17 cgd goto out; 1833 1.17 cgd } 1834 1.1 cgd 1835 1.59 fvdl /* 1836 1.59 fvdl * If the tvp exists and is in use, sillyrename it before doing the 1837 1.59 fvdl * rename of the new file over it. 1838 1.240 yamt * 1839 1.240 yamt * Have sillyrename use link instead of rename if possible, 1840 1.240 yamt * so that we don't lose the file if the rename fails, and so 1841 1.240 yamt * that there's no window when the "to" file doesn't exist. 1842 1.59 fvdl */ 1843 1.314 ad if (tvp && vrefcnt(tvp) > 1 && !VTONFS(tvp)->n_sillyrename && 1844 1.251 thorpej tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp, true)) { 1845 1.156 jdolecek VN_KNOTE(tvp, NOTE_DELETE); 1846 1.130 enami vput(tvp); 1847 1.59 fvdl tvp = NULL; 1848 1.59 fvdl } 1849 1.59 fvdl 1850 1.59 fvdl error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, 1851 1.59 fvdl tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred, 1852 1.261 pooka curlwp); 1853 1.32 mycroft 1854 1.156 jdolecek VN_KNOTE(fdvp, NOTE_WRITE); 1855 1.156 jdolecek VN_KNOTE(tdvp, NOTE_WRITE); 1856 1.203 yamt if (error == 0 || error == EEXIST) { 1857 1.203 yamt if (fvp->v_type == VDIR) 1858 1.203 yamt cache_purge(fvp); 1859 1.203 yamt else 1860 1.297 dholland cache_purge1(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen, 1861 1.297 dholland 0); 1862 1.32 mycroft if (tvp != NULL && tvp->v_type == VDIR) 1863 1.203 yamt cache_purge(tvp); 1864 1.203 yamt else 1865 1.297 dholland cache_purge1(tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, 1866 1.297 dholland 0); 1867 1.1 cgd } 1868 1.17 cgd out: 1869 1.32 mycroft if (tdvp == tvp) 1870 1.32 mycroft vrele(tdvp); 1871 1.1 cgd else 1872 1.32 mycroft vput(tdvp); 1873 1.32 mycroft if (tvp) 1874 1.32 mycroft vput(tvp); 1875 1.32 mycroft vrele(fdvp); 1876 1.32 mycroft vrele(fvp); 1877 1.1 cgd return (error); 1878 1.1 cgd } 1879 1.1 cgd 1880 1.1 cgd /* 1881 1.1 cgd * nfs file rename rpc called from nfs_remove() above 1882 1.1 cgd */ 1883 1.32 mycroft int 1884 1.272 dsl nfs_renameit(struct vnode *sdvp, struct componentname *scnp, struct sillyrename *sp) 1885 1.1 cgd { 1886 1.59 fvdl return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, 1887 1.261 pooka sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, curlwp)); 1888 1.59 fvdl } 1889 1.59 fvdl 1890 1.59 fvdl /* 1891 1.59 fvdl * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit(). 1892 1.59 fvdl */ 1893 1.59 fvdl int 1894 1.272 dsl nfs_renamerpc(struct vnode *fdvp, const char *fnameptr, int fnamelen, struct vnode *tdvp, const char *tnameptr, int tnamelen, kauth_cred_t cred, struct lwp *l) 1895 1.59 fvdl { 1896 1.111 augustss u_int32_t *tl; 1897 1.252 christos char *cp; 1898 1.200 christos #ifndef NFS_V2_ONLY 1899 1.200 christos int32_t t1; 1900 1.252 christos char *cp2; 1901 1.200 christos #endif 1902 1.200 christos int32_t t2; 1903 1.252 christos char *bpos, *dpos; 1904 1.59 fvdl int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR; 1905 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 1906 1.119 bjh21 const int v3 = NFS_ISV3(fdvp); 1907 1.234 christos int rexmit = 0; 1908 1.165 drochner struct nfsnode *fdnp = VTONFS(fdvp); 1909 1.1 cgd 1910 1.1 cgd nfsstats.rpccnt[NFSPROC_RENAME]++; 1911 1.165 drochner nfsm_reqhead(fdnp, NFSPROC_RENAME, 1912 1.59 fvdl (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) + 1913 1.59 fvdl nfsm_rndup(tnamelen)); 1914 1.165 drochner nfsm_fhtom(fdnp, v3); 1915 1.59 fvdl nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN); 1916 1.165 drochner nfsm_fhtom(VTONFS(tdvp), v3); 1917 1.59 fvdl nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN); 1918 1.230 christos nfsm_request1(fdnp, NFSPROC_RENAME, l, cred, &rexmit); 1919 1.200 christos #ifndef NFS_V2_ONLY 1920 1.59 fvdl if (v3) { 1921 1.216 yamt nfsm_wcc_data(fdvp, fwccflag, 0, !error); 1922 1.216 yamt nfsm_wcc_data(tdvp, twccflag, 0, !error); 1923 1.59 fvdl } 1924 1.200 christos #endif 1925 1.1 cgd nfsm_reqdone; 1926 1.59 fvdl VTONFS(fdvp)->n_flag |= NMODIFIED; 1927 1.59 fvdl VTONFS(tdvp)->n_flag |= NMODIFIED; 1928 1.59 fvdl if (!fwccflag) 1929 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(fdvp)); 1930 1.59 fvdl if (!twccflag) 1931 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(tdvp)); 1932 1.197 yamt /* 1933 1.197 yamt * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 1934 1.197 yamt */ 1935 1.197 yamt if (rexmit && error == ENOENT) 1936 1.197 yamt error = 0; 1937 1.1 cgd return (error); 1938 1.1 cgd } 1939 1.1 cgd 1940 1.240 yamt /* 1941 1.240 yamt * NFS link RPC, called from nfs_link. 1942 1.240 yamt * Assumes dvp and vp locked, and leaves them that way. 1943 1.240 yamt */ 1944 1.240 yamt 1945 1.239 yamt static int 1946 1.239 yamt nfs_linkrpc(struct vnode *dvp, struct vnode *vp, const char *name, 1947 1.239 yamt size_t namelen, kauth_cred_t cred, struct lwp *l) 1948 1.239 yamt { 1949 1.239 yamt u_int32_t *tl; 1950 1.252 christos char *cp; 1951 1.239 yamt #ifndef NFS_V2_ONLY 1952 1.239 yamt int32_t t1; 1953 1.252 christos char *cp2; 1954 1.239 yamt #endif 1955 1.239 yamt int32_t t2; 1956 1.252 christos char *bpos, *dpos; 1957 1.239 yamt int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0; 1958 1.239 yamt struct mbuf *mreq, *mrep, *md, *mb; 1959 1.239 yamt const int v3 = NFS_ISV3(dvp); 1960 1.239 yamt int rexmit = 0; 1961 1.239 yamt struct nfsnode *np = VTONFS(vp); 1962 1.239 yamt 1963 1.239 yamt nfsstats.rpccnt[NFSPROC_LINK]++; 1964 1.239 yamt nfsm_reqhead(np, NFSPROC_LINK, 1965 1.239 yamt NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(namelen)); 1966 1.239 yamt nfsm_fhtom(np, v3); 1967 1.239 yamt nfsm_fhtom(VTONFS(dvp), v3); 1968 1.239 yamt nfsm_strtom(name, namelen, NFS_MAXNAMLEN); 1969 1.239 yamt nfsm_request1(np, NFSPROC_LINK, l, cred, &rexmit); 1970 1.239 yamt #ifndef NFS_V2_ONLY 1971 1.239 yamt if (v3) { 1972 1.239 yamt nfsm_postop_attr(vp, attrflag, 0); 1973 1.239 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 1974 1.239 yamt } 1975 1.239 yamt #endif 1976 1.239 yamt nfsm_reqdone; 1977 1.239 yamt 1978 1.239 yamt VTONFS(dvp)->n_flag |= NMODIFIED; 1979 1.239 yamt if (!attrflag) 1980 1.239 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(vp)); 1981 1.239 yamt if (!wccflag) 1982 1.239 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 1983 1.239 yamt 1984 1.239 yamt /* 1985 1.239 yamt * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 1986 1.239 yamt */ 1987 1.239 yamt if (rexmit && error == EEXIST) 1988 1.239 yamt error = 0; 1989 1.239 yamt 1990 1.239 yamt return error; 1991 1.239 yamt } 1992 1.239 yamt 1993 1.1 cgd /* 1994 1.1 cgd * nfs hard link create call 1995 1.1 cgd */ 1996 1.32 mycroft int 1997 1.272 dsl nfs_link(void *v) 1998 1.58 christos { 1999 1.307 riastrad struct vop_link_v2_args /* { 2000 1.57 mycroft struct vnode *a_dvp; 2001 1.32 mycroft struct vnode *a_vp; 2002 1.32 mycroft struct componentname *a_cnp; 2003 1.58 christos } */ *ap = v; 2004 1.111 augustss struct vnode *vp = ap->a_vp; 2005 1.111 augustss struct vnode *dvp = ap->a_dvp; 2006 1.111 augustss struct componentname *cnp = ap->a_cnp; 2007 1.323 christos int error = 0, abrt = 1; 2008 1.1 cgd 2009 1.290 rmind error = vn_lock(vp, LK_EXCLUSIVE); 2010 1.323 christos if (error != 0) 2011 1.323 christos goto out; 2012 1.32 mycroft 2013 1.322 christos error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_ADD_LINK, vp, 2014 1.322 christos dvp, 0); 2015 1.323 christos if (error) 2016 1.323 christos goto out1; 2017 1.322 christos 2018 1.323 christos abrt = 0; 2019 1.36 mycroft /* 2020 1.36 mycroft * Push all writes to the server, so that the attribute cache 2021 1.36 mycroft * doesn't get "out of sync" with the server. 2022 1.36 mycroft * XXX There should be a better way! 2023 1.36 mycroft */ 2024 1.260 pooka VOP_FSYNC(vp, cnp->cn_cred, FSYNC_WAIT, 0, 0); 2025 1.36 mycroft 2026 1.239 yamt error = nfs_linkrpc(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen, 2027 1.261 pooka cnp->cn_cred, curlwp); 2028 1.239 yamt 2029 1.290 rmind if (error == 0) { 2030 1.297 dholland cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0); 2031 1.290 rmind } 2032 1.323 christos out1: 2033 1.290 rmind VOP_UNLOCK(vp); 2034 1.323 christos out: 2035 1.323 christos if (abrt) 2036 1.323 christos VOP_ABORTOP(dvp, cnp); 2037 1.1 cgd return (error); 2038 1.1 cgd } 2039 1.1 cgd 2040 1.1 cgd /* 2041 1.1 cgd * nfs symbolic link create call 2042 1.1 cgd */ 2043 1.32 mycroft int 2044 1.272 dsl nfs_symlink(void *v) 2045 1.58 christos { 2046 1.303 hannken struct vop_symlink_v3_args /* { 2047 1.32 mycroft struct vnode *a_dvp; 2048 1.32 mycroft struct vnode **a_vpp; 2049 1.32 mycroft struct componentname *a_cnp; 2050 1.32 mycroft struct vattr *a_vap; 2051 1.32 mycroft char *a_target; 2052 1.58 christos } */ *ap = v; 2053 1.111 augustss struct vnode *dvp = ap->a_dvp; 2054 1.111 augustss struct vattr *vap = ap->a_vap; 2055 1.111 augustss struct componentname *cnp = ap->a_cnp; 2056 1.111 augustss struct nfsv2_sattr *sp; 2057 1.111 augustss u_int32_t *tl; 2058 1.252 christos char *cp; 2059 1.111 augustss int32_t t1, t2; 2060 1.252 christos char *bpos, *dpos, *cp2; 2061 1.59 fvdl int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp; 2062 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2063 1.59 fvdl struct vnode *newvp = (struct vnode *)0; 2064 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 2065 1.233 christos int rexmit = 0; 2066 1.165 drochner struct nfsnode *dnp = VTONFS(dvp); 2067 1.1 cgd 2068 1.135 assar *ap->a_vpp = NULL; 2069 1.1 cgd nfsstats.rpccnt[NFSPROC_SYMLINK]++; 2070 1.32 mycroft slen = strlen(ap->a_target); 2071 1.165 drochner nfsm_reqhead(dnp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED + 2072 1.59 fvdl nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3)); 2073 1.165 drochner nfsm_fhtom(dnp, v3); 2074 1.32 mycroft nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 2075 1.200 christos #ifndef NFS_V2_ONlY 2076 1.101 fvdl if (v3) 2077 1.251 thorpej nfsm_v3attrbuild(vap, false); 2078 1.200 christos #endif 2079 1.32 mycroft nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN); 2080 1.200 christos #ifndef NFS_V2_ONlY 2081 1.59 fvdl if (!v3) { 2082 1.59 fvdl nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 2083 1.59 fvdl sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode); 2084 1.59 fvdl sp->sa_uid = nfs_xdrneg1; 2085 1.59 fvdl sp->sa_gid = nfs_xdrneg1; 2086 1.59 fvdl sp->sa_size = nfs_xdrneg1; 2087 1.59 fvdl txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 2088 1.59 fvdl txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 2089 1.32 mycroft } 2090 1.200 christos #endif 2091 1.261 pooka nfsm_request1(dnp, NFSPROC_SYMLINK, curlwp, cnp->cn_cred, 2092 1.197 yamt &rexmit); 2093 1.200 christos #ifndef NFS_V2_ONlY 2094 1.59 fvdl if (v3) { 2095 1.59 fvdl if (!error) 2096 1.175 fvdl nfsm_mtofh(dvp, newvp, v3, gotvp); 2097 1.216 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 2098 1.59 fvdl } 2099 1.200 christos #endif 2100 1.1 cgd nfsm_reqdone; 2101 1.135 assar /* 2102 1.135 assar * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2103 1.135 assar */ 2104 1.197 yamt if (rexmit && error == EEXIST) 2105 1.135 assar error = 0; 2106 1.203 yamt if (error == 0 || error == EEXIST) 2107 1.297 dholland cache_purge1(dvp, cnp->cn_nameptr, cnp->cn_namelen, 0); 2108 1.135 assar if (error == 0 && newvp == NULL) { 2109 1.135 assar struct nfsnode *np = NULL; 2110 1.135 assar 2111 1.135 assar error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen, 2112 1.261 pooka cnp->cn_cred, curlwp, &np); 2113 1.135 assar if (error == 0) 2114 1.135 assar newvp = NFSTOV(np); 2115 1.135 assar } 2116 1.135 assar if (error) { 2117 1.135 assar if (newvp != NULL) 2118 1.135 assar vput(newvp); 2119 1.135 assar } else { 2120 1.135 assar *ap->a_vpp = newvp; 2121 1.303 hannken VOP_UNLOCK(newvp); 2122 1.135 assar } 2123 1.32 mycroft VTONFS(dvp)->n_flag |= NMODIFIED; 2124 1.59 fvdl if (!wccflag) 2125 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 2126 1.1 cgd return (error); 2127 1.1 cgd } 2128 1.1 cgd 2129 1.1 cgd /* 2130 1.1 cgd * nfs make dir call 2131 1.1 cgd */ 2132 1.32 mycroft int 2133 1.272 dsl nfs_mkdir(void *v) 2134 1.58 christos { 2135 1.303 hannken struct vop_mkdir_v3_args /* { 2136 1.32 mycroft struct vnode *a_dvp; 2137 1.32 mycroft struct vnode **a_vpp; 2138 1.32 mycroft struct componentname *a_cnp; 2139 1.32 mycroft struct vattr *a_vap; 2140 1.58 christos } */ *ap = v; 2141 1.111 augustss struct vnode *dvp = ap->a_dvp; 2142 1.111 augustss struct vattr *vap = ap->a_vap; 2143 1.111 augustss struct componentname *cnp = ap->a_cnp; 2144 1.111 augustss struct nfsv2_sattr *sp; 2145 1.111 augustss u_int32_t *tl; 2146 1.252 christos char *cp; 2147 1.111 augustss int32_t t1, t2; 2148 1.111 augustss int len; 2149 1.165 drochner struct nfsnode *dnp = VTONFS(dvp), *np = (struct nfsnode *)0; 2150 1.59 fvdl struct vnode *newvp = (struct vnode *)0; 2151 1.252 christos char *bpos, *dpos, *cp2; 2152 1.59 fvdl int error = 0, wccflag = NFSV3_WCCRATTR; 2153 1.59 fvdl int gotvp = 0; 2154 1.234 christos int rexmit = 0; 2155 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2156 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 2157 1.1 cgd 2158 1.32 mycroft len = cnp->cn_namelen; 2159 1.1 cgd nfsstats.rpccnt[NFSPROC_MKDIR]++; 2160 1.165 drochner nfsm_reqhead(dnp, NFSPROC_MKDIR, 2161 1.59 fvdl NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3)); 2162 1.165 drochner nfsm_fhtom(dnp, v3); 2163 1.32 mycroft nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN); 2164 1.200 christos #ifndef NFS_V2_ONLY 2165 1.59 fvdl if (v3) { 2166 1.251 thorpej nfsm_v3attrbuild(vap, false); 2167 1.200 christos } else 2168 1.200 christos #endif 2169 1.200 christos { 2170 1.59 fvdl nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 2171 1.59 fvdl sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode); 2172 1.59 fvdl sp->sa_uid = nfs_xdrneg1; 2173 1.59 fvdl sp->sa_gid = nfs_xdrneg1; 2174 1.59 fvdl sp->sa_size = nfs_xdrneg1; 2175 1.59 fvdl txdr_nfsv2time(&vap->va_atime, &sp->sa_atime); 2176 1.59 fvdl txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime); 2177 1.32 mycroft } 2178 1.261 pooka nfsm_request1(dnp, NFSPROC_MKDIR, curlwp, cnp->cn_cred, &rexmit); 2179 1.59 fvdl if (!error) 2180 1.175 fvdl nfsm_mtofh(dvp, newvp, v3, gotvp); 2181 1.59 fvdl if (v3) 2182 1.216 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 2183 1.1 cgd nfsm_reqdone; 2184 1.32 mycroft VTONFS(dvp)->n_flag |= NMODIFIED; 2185 1.59 fvdl if (!wccflag) 2186 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 2187 1.1 cgd /* 2188 1.1 cgd * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry 2189 1.1 cgd * if we can succeed in looking up the directory. 2190 1.1 cgd */ 2191 1.197 yamt if ((rexmit && error == EEXIST) || (!error && !gotvp)) { 2192 1.59 fvdl if (newvp) { 2193 1.128 fvdl vput(newvp); 2194 1.59 fvdl newvp = (struct vnode *)0; 2195 1.59 fvdl } 2196 1.59 fvdl error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred, 2197 1.261 pooka curlwp, &np); 2198 1.59 fvdl if (!error) { 2199 1.59 fvdl newvp = NFSTOV(np); 2200 1.195 yamt if (newvp->v_type != VDIR || newvp == dvp) 2201 1.59 fvdl error = EEXIST; 2202 1.1 cgd } 2203 1.1 cgd } 2204 1.59 fvdl if (error) { 2205 1.195 yamt if (newvp) { 2206 1.195 yamt if (dvp != newvp) 2207 1.195 yamt vput(newvp); 2208 1.195 yamt else 2209 1.195 yamt vrele(newvp); 2210 1.195 yamt } 2211 1.82 fvdl } else { 2212 1.295 rmind nfs_cache_enter(dvp, newvp, cnp); 2213 1.59 fvdl *ap->a_vpp = newvp; 2214 1.303 hannken VOP_UNLOCK(newvp); 2215 1.82 fvdl } 2216 1.1 cgd return (error); 2217 1.1 cgd } 2218 1.1 cgd 2219 1.1 cgd /* 2220 1.1 cgd * nfs remove directory call 2221 1.1 cgd */ 2222 1.32 mycroft int 2223 1.272 dsl nfs_rmdir(void *v) 2224 1.58 christos { 2225 1.310 riastrad struct vop_rmdir_v2_args /* { 2226 1.32 mycroft struct vnode *a_dvp; 2227 1.32 mycroft struct vnode *a_vp; 2228 1.32 mycroft struct componentname *a_cnp; 2229 1.58 christos } */ *ap = v; 2230 1.111 augustss struct vnode *vp = ap->a_vp; 2231 1.111 augustss struct vnode *dvp = ap->a_dvp; 2232 1.111 augustss struct componentname *cnp = ap->a_cnp; 2233 1.111 augustss u_int32_t *tl; 2234 1.252 christos char *cp; 2235 1.200 christos #ifndef NFS_V2_ONLY 2236 1.200 christos int32_t t1; 2237 1.252 christos char *cp2; 2238 1.200 christos #endif 2239 1.200 christos int32_t t2; 2240 1.252 christos char *bpos, *dpos; 2241 1.59 fvdl int error = 0, wccflag = NFSV3_WCCRATTR; 2242 1.234 christos int rexmit = 0; 2243 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2244 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 2245 1.165 drochner struct nfsnode *dnp; 2246 1.1 cgd 2247 1.32 mycroft if (dvp == vp) { 2248 1.310 riastrad vrele(vp); 2249 1.1 cgd return (EINVAL); 2250 1.1 cgd } 2251 1.1 cgd nfsstats.rpccnt[NFSPROC_RMDIR]++; 2252 1.165 drochner dnp = VTONFS(dvp); 2253 1.165 drochner nfsm_reqhead(dnp, NFSPROC_RMDIR, 2254 1.59 fvdl NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen)); 2255 1.165 drochner nfsm_fhtom(dnp, v3); 2256 1.32 mycroft nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN); 2257 1.261 pooka nfsm_request1(dnp, NFSPROC_RMDIR, curlwp, cnp->cn_cred, &rexmit); 2258 1.200 christos #ifndef NFS_V2_ONLY 2259 1.59 fvdl if (v3) 2260 1.216 yamt nfsm_wcc_data(dvp, wccflag, 0, !error); 2261 1.200 christos #endif 2262 1.1 cgd nfsm_reqdone; 2263 1.32 mycroft VTONFS(dvp)->n_flag |= NMODIFIED; 2264 1.59 fvdl if (!wccflag) 2265 1.185 yamt NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp)); 2266 1.32 mycroft cache_purge(vp); 2267 1.129 fvdl vput(vp); 2268 1.1 cgd /* 2269 1.1 cgd * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2270 1.1 cgd */ 2271 1.197 yamt if (rexmit && error == ENOENT) 2272 1.1 cgd error = 0; 2273 1.1 cgd return (error); 2274 1.1 cgd } 2275 1.1 cgd 2276 1.1 cgd /* 2277 1.1 cgd * nfs readdir call 2278 1.1 cgd */ 2279 1.32 mycroft int 2280 1.272 dsl nfs_readdir(void *v) 2281 1.58 christos { 2282 1.32 mycroft struct vop_readdir_args /* { 2283 1.32 mycroft struct vnode *a_vp; 2284 1.32 mycroft struct uio *a_uio; 2285 1.236 elad kauth_cred_t a_cred; 2286 1.32 mycroft int *a_eofflag; 2287 1.89 fvdl off_t **a_cookies; 2288 1.89 fvdl int *a_ncookies; 2289 1.58 christos } */ *ap = v; 2290 1.111 augustss struct vnode *vp = ap->a_vp; 2291 1.111 augustss struct uio *uio = ap->a_uio; 2292 1.85 fvdl struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2293 1.52 ghudson char *base = uio->uio_iov->iov_base; 2294 1.1 cgd int tresid, error; 2295 1.81 fvdl size_t count, lost; 2296 1.90 fvdl struct dirent *dp; 2297 1.90 fvdl off_t *cookies = NULL; 2298 1.90 fvdl int ncookies = 0, nc; 2299 1.32 mycroft 2300 1.1 cgd if (vp->v_type != VDIR) 2301 1.1 cgd return (EPERM); 2302 1.81 fvdl 2303 1.81 fvdl lost = uio->uio_resid & (NFS_DIRFRAGSIZ - 1); 2304 1.81 fvdl count = uio->uio_resid - lost; 2305 1.81 fvdl if (count <= 0) 2306 1.81 fvdl return (EINVAL); 2307 1.81 fvdl 2308 1.1 cgd /* 2309 1.1 cgd * Call nfs_bioread() to do the real work. 2310 1.1 cgd */ 2311 1.81 fvdl tresid = uio->uio_resid = count; 2312 1.81 fvdl error = nfs_bioread(vp, uio, 0, ap->a_cred, 2313 1.81 fvdl ap->a_cookies ? NFSBIO_CACHECOOKIES : 0); 2314 1.1 cgd 2315 1.90 fvdl if (!error && ap->a_cookies) { 2316 1.90 fvdl ncookies = count / 16; 2317 1.116 thorpej cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK); 2318 1.90 fvdl *ap->a_cookies = cookies; 2319 1.90 fvdl } 2320 1.90 fvdl 2321 1.59 fvdl if (!error && uio->uio_resid == tresid) { 2322 1.81 fvdl uio->uio_resid += lost; 2323 1.1 cgd nfsstats.direofcache_misses++; 2324 1.90 fvdl if (ap->a_cookies) 2325 1.90 fvdl *ap->a_ncookies = 0; 2326 1.59 fvdl *ap->a_eofflag = 1; 2327 1.59 fvdl return (0); 2328 1.59 fvdl } 2329 1.52 ghudson 2330 1.52 ghudson if (!error && ap->a_cookies) { 2331 1.52 ghudson /* 2332 1.52 ghudson * Only the NFS server and emulations use cookies, and they 2333 1.52 ghudson * load the directory block into system space, so we can 2334 1.52 ghudson * just look at it directly. 2335 1.52 ghudson */ 2336 1.231 yamt if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace) || 2337 1.231 yamt uio->uio_iovcnt != 1) 2338 1.59 fvdl panic("nfs_readdir: lost in space"); 2339 1.91 kleink for (nc = 0; ncookies-- && 2340 1.91 kleink base < (char *)uio->uio_iov->iov_base; nc++){ 2341 1.52 ghudson dp = (struct dirent *) base; 2342 1.52 ghudson if (dp->d_reclen == 0) 2343 1.52 ghudson break; 2344 1.85 fvdl if (nmp->nm_flag & NFSMNT_XLATECOOKIE) 2345 1.85 fvdl *(cookies++) = (off_t)NFS_GETCOOKIE32(dp); 2346 1.85 fvdl else 2347 1.85 fvdl *(cookies++) = NFS_GETCOOKIE(dp); 2348 1.52 ghudson base += dp->d_reclen; 2349 1.52 ghudson } 2350 1.91 kleink uio->uio_resid += 2351 1.252 christos ((char *)uio->uio_iov->iov_base - base); 2352 1.91 kleink uio->uio_iov->iov_len += 2353 1.252 christos ((char *)uio->uio_iov->iov_base - base); 2354 1.52 ghudson uio->uio_iov->iov_base = base; 2355 1.90 fvdl *ap->a_ncookies = nc; 2356 1.52 ghudson } 2357 1.52 ghudson 2358 1.81 fvdl uio->uio_resid += lost; 2359 1.59 fvdl *ap->a_eofflag = 0; 2360 1.1 cgd return (error); 2361 1.1 cgd } 2362 1.1 cgd 2363 1.1 cgd /* 2364 1.1 cgd * Readdir rpc call. 2365 1.1 cgd * Called from below the buffer cache by nfs_doio(). 2366 1.1 cgd */ 2367 1.32 mycroft int 2368 1.272 dsl nfs_readdirrpc(struct vnode *vp, struct uio *uiop, kauth_cred_t cred) 2369 1.1 cgd { 2370 1.111 augustss int len, left; 2371 1.111 augustss struct dirent *dp = NULL; 2372 1.111 augustss u_int32_t *tl; 2373 1.252 christos char *cp; 2374 1.111 augustss int32_t t1, t2; 2375 1.252 christos char *bpos, *dpos, *cp2; 2376 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2377 1.59 fvdl struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2378 1.59 fvdl struct nfsnode *dnp = VTONFS(vp); 2379 1.59 fvdl u_quad_t fileno; 2380 1.225 christos int error = 0, more_dirs = 1, blksiz = 0, bigenough = 1; 2381 1.200 christos #ifndef NFS_V2_ONLY 2382 1.200 christos int attrflag; 2383 1.200 christos #endif 2384 1.200 christos int nrpcs = 0, reclen; 2385 1.119 bjh21 const int v3 = NFS_ISV3(vp); 2386 1.59 fvdl 2387 1.81 fvdl #ifdef DIAGNOSTIC 2388 1.81 fvdl /* 2389 1.81 fvdl * Should be called from buffer cache, so only amount of 2390 1.81 fvdl * NFS_DIRBLKSIZ will be requested. 2391 1.81 fvdl */ 2392 1.219 yamt if (uiop->uio_iovcnt != 1 || uiop->uio_resid != NFS_DIRBLKSIZ) 2393 1.59 fvdl panic("nfs readdirrpc bad uio"); 2394 1.59 fvdl #endif 2395 1.1 cgd 2396 1.1 cgd /* 2397 1.59 fvdl * Loop around doing readdir rpc's of size nm_readdirsize 2398 1.81 fvdl * truncated to a multiple of NFS_DIRFRAGSIZ. 2399 1.1 cgd * The stopping criteria is EOF or buffer full. 2400 1.1 cgd */ 2401 1.59 fvdl while (more_dirs && bigenough) { 2402 1.85 fvdl /* 2403 1.85 fvdl * Heuristic: don't bother to do another RPC to further 2404 1.85 fvdl * fill up this block if there is not much room left. (< 50% 2405 1.85 fvdl * of the readdir RPC size). This wastes some buffer space 2406 1.85 fvdl * but can save up to 50% in RPC calls. 2407 1.85 fvdl */ 2408 1.85 fvdl if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) { 2409 1.85 fvdl bigenough = 0; 2410 1.85 fvdl break; 2411 1.85 fvdl } 2412 1.1 cgd nfsstats.rpccnt[NFSPROC_READDIR]++; 2413 1.165 drochner nfsm_reqhead(dnp, NFSPROC_READDIR, NFSX_FH(v3) + 2414 1.59 fvdl NFSX_READDIR(v3)); 2415 1.165 drochner nfsm_fhtom(dnp, v3); 2416 1.200 christos #ifndef NFS_V2_ONLY 2417 1.59 fvdl if (v3) { 2418 1.59 fvdl nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2419 1.81 fvdl if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) { 2420 1.81 fvdl txdr_swapcookie3(uiop->uio_offset, tl); 2421 1.81 fvdl } else { 2422 1.81 fvdl txdr_cookie3(uiop->uio_offset, tl); 2423 1.81 fvdl } 2424 1.81 fvdl tl += 2; 2425 1.325 schmonz if (uiop->uio_offset == 0) { 2426 1.325 schmonz *tl++ = 0; 2427 1.325 schmonz *tl++ = 0; 2428 1.325 schmonz } else { 2429 1.325 schmonz *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2430 1.325 schmonz *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2431 1.325 schmonz } 2432 1.200 christos } else 2433 1.200 christos #endif 2434 1.200 christos { 2435 1.59 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2436 1.81 fvdl *tl++ = txdr_unsigned(uiop->uio_offset); 2437 1.59 fvdl } 2438 1.59 fvdl *tl = txdr_unsigned(nmp->nm_readdirsize); 2439 1.231 yamt nfsm_request(dnp, NFSPROC_READDIR, curlwp, cred); 2440 1.85 fvdl nrpcs++; 2441 1.200 christos #ifndef NFS_V2_ONLY 2442 1.59 fvdl if (v3) { 2443 1.153 yamt nfsm_postop_attr(vp, attrflag, 0); 2444 1.59 fvdl if (!error) { 2445 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2446 1.59 fvdl 2 * NFSX_UNSIGNED); 2447 1.59 fvdl dnp->n_cookieverf.nfsuquad[0] = *tl++; 2448 1.59 fvdl dnp->n_cookieverf.nfsuquad[1] = *tl; 2449 1.59 fvdl } else { 2450 1.59 fvdl m_freem(mrep); 2451 1.59 fvdl goto nfsmout; 2452 1.59 fvdl } 2453 1.59 fvdl } 2454 1.200 christos #endif 2455 1.53 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2456 1.1 cgd more_dirs = fxdr_unsigned(int, *tl); 2457 1.220 perry 2458 1.1 cgd /* loop thru the dir entries, doctoring them to 4bsd form */ 2459 1.59 fvdl while (more_dirs && bigenough) { 2460 1.200 christos #ifndef NFS_V2_ONLY 2461 1.59 fvdl if (v3) { 2462 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2463 1.59 fvdl 3 * NFSX_UNSIGNED); 2464 1.98 fair fileno = fxdr_hyper(tl); 2465 1.59 fvdl len = fxdr_unsigned(int, *(tl + 2)); 2466 1.200 christos } else 2467 1.200 christos #endif 2468 1.200 christos { 2469 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2470 1.59 fvdl 2 * NFSX_UNSIGNED); 2471 1.59 fvdl fileno = fxdr_unsigned(u_quad_t, *tl++); 2472 1.59 fvdl len = fxdr_unsigned(int, *tl); 2473 1.59 fvdl } 2474 1.1 cgd if (len <= 0 || len > NFS_MAXNAMLEN) { 2475 1.1 cgd error = EBADRPC; 2476 1.1 cgd m_freem(mrep); 2477 1.1 cgd goto nfsmout; 2478 1.1 cgd } 2479 1.225 christos /* for cookie stashing */ 2480 1.225 christos reclen = _DIRENT_RECLEN(dp, len) + 2 * sizeof(off_t); 2481 1.81 fvdl left = NFS_DIRFRAGSIZ - blksiz; 2482 1.86 thorpej if (reclen > left) { 2483 1.211 yamt memset(uiop->uio_iov->iov_base, 0, left); 2484 1.59 fvdl dp->d_reclen += left; 2485 1.225 christos UIO_ADVANCE(uiop, left); 2486 1.59 fvdl blksiz = 0; 2487 1.81 fvdl NFS_STASHCOOKIE(dp, uiop->uio_offset); 2488 1.59 fvdl } 2489 1.86 thorpej if (reclen > uiop->uio_resid) 2490 1.59 fvdl bigenough = 0; 2491 1.59 fvdl if (bigenough) { 2492 1.225 christos int tlen; 2493 1.225 christos 2494 1.59 fvdl dp = (struct dirent *)uiop->uio_iov->iov_base; 2495 1.225 christos dp->d_fileno = fileno; 2496 1.59 fvdl dp->d_namlen = len; 2497 1.86 thorpej dp->d_reclen = reclen; 2498 1.59 fvdl dp->d_type = DT_UNKNOWN; 2499 1.225 christos blksiz += reclen; 2500 1.81 fvdl if (blksiz == NFS_DIRFRAGSIZ) 2501 1.59 fvdl blksiz = 0; 2502 1.225 christos UIO_ADVANCE(uiop, DIRHDSIZ); 2503 1.59 fvdl nfsm_mtouio(uiop, len); 2504 1.225 christos tlen = reclen - (DIRHDSIZ + len); 2505 1.225 christos (void)memset(uiop->uio_iov->iov_base, 0, tlen); 2506 1.225 christos UIO_ADVANCE(uiop, tlen); 2507 1.59 fvdl } else 2508 1.59 fvdl nfsm_adv(nfsm_rndup(len)); 2509 1.200 christos #ifndef NFS_V2_ONLY 2510 1.59 fvdl if (v3) { 2511 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2512 1.59 fvdl 3 * NFSX_UNSIGNED); 2513 1.220 perry } else 2514 1.200 christos #endif 2515 1.200 christos { 2516 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 2517 1.59 fvdl 2 * NFSX_UNSIGNED); 2518 1.1 cgd } 2519 1.59 fvdl if (bigenough) { 2520 1.200 christos #ifndef NFS_V2_ONLY 2521 1.81 fvdl if (v3) { 2522 1.81 fvdl if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) 2523 1.81 fvdl uiop->uio_offset = 2524 1.81 fvdl fxdr_swapcookie3(tl); 2525 1.81 fvdl else 2526 1.220 perry uiop->uio_offset = 2527 1.81 fvdl fxdr_cookie3(tl); 2528 1.81 fvdl } 2529 1.200 christos else 2530 1.200 christos #endif 2531 1.200 christos { 2532 1.81 fvdl uiop->uio_offset = 2533 1.81 fvdl fxdr_unsigned(off_t, *tl); 2534 1.81 fvdl } 2535 1.81 fvdl NFS_STASHCOOKIE(dp, uiop->uio_offset); 2536 1.81 fvdl } 2537 1.81 fvdl if (v3) 2538 1.59 fvdl tl += 2; 2539 1.59 fvdl else 2540 1.59 fvdl tl++; 2541 1.1 cgd more_dirs = fxdr_unsigned(int, *tl); 2542 1.1 cgd } 2543 1.1 cgd /* 2544 1.1 cgd * If at end of rpc data, get the eof boolean 2545 1.1 cgd */ 2546 1.1 cgd if (!more_dirs) { 2547 1.53 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2548 1.1 cgd more_dirs = (fxdr_unsigned(int, *tl) == 0); 2549 1.219 yamt 2550 1.219 yamt /* 2551 1.219 yamt * kludge: if we got no entries, treat it as EOF. 2552 1.219 yamt * some server sometimes send a reply without any 2553 1.219 yamt * entries or EOF. 2554 1.219 yamt * although it might mean the server has very long name, 2555 1.219 yamt * we can't handle such entries anyway. 2556 1.219 yamt */ 2557 1.219 yamt 2558 1.219 yamt if (uiop->uio_resid >= NFS_DIRBLKSIZ) 2559 1.219 yamt more_dirs = 0; 2560 1.1 cgd } 2561 1.1 cgd m_freem(mrep); 2562 1.1 cgd } 2563 1.1 cgd /* 2564 1.81 fvdl * Fill last record, iff any, out to a multiple of NFS_DIRFRAGSIZ 2565 1.1 cgd * by increasing d_reclen for the last record. 2566 1.1 cgd */ 2567 1.59 fvdl if (blksiz > 0) { 2568 1.81 fvdl left = NFS_DIRFRAGSIZ - blksiz; 2569 1.211 yamt memset(uiop->uio_iov->iov_base, 0, left); 2570 1.59 fvdl dp->d_reclen += left; 2571 1.81 fvdl NFS_STASHCOOKIE(dp, uiop->uio_offset); 2572 1.225 christos UIO_ADVANCE(uiop, left); 2573 1.59 fvdl } 2574 1.59 fvdl 2575 1.59 fvdl /* 2576 1.59 fvdl * We are now either at the end of the directory or have filled the 2577 1.59 fvdl * block. 2578 1.59 fvdl */ 2579 1.218 yamt if (bigenough) { 2580 1.59 fvdl dnp->n_direofoffset = uiop->uio_offset; 2581 1.218 yamt dnp->n_flag |= NEOFVALID; 2582 1.218 yamt } 2583 1.1 cgd nfsmout: 2584 1.1 cgd return (error); 2585 1.1 cgd } 2586 1.1 cgd 2587 1.200 christos #ifndef NFS_V2_ONLY 2588 1.32 mycroft /* 2589 1.59 fvdl * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc(). 2590 1.32 mycroft */ 2591 1.32 mycroft int 2592 1.272 dsl nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, kauth_cred_t cred) 2593 1.32 mycroft { 2594 1.111 augustss int len, left; 2595 1.111 augustss struct dirent *dp = NULL; 2596 1.111 augustss u_int32_t *tl; 2597 1.252 christos char *cp; 2598 1.111 augustss int32_t t1, t2; 2599 1.79 fvdl struct vnode *newvp; 2600 1.252 christos char *bpos, *dpos, *cp2; 2601 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2602 1.32 mycroft struct nameidata nami, *ndp = &nami; 2603 1.32 mycroft struct componentname *cnp = &ndp->ni_cnd; 2604 1.59 fvdl struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2605 1.59 fvdl struct nfsnode *dnp = VTONFS(vp), *np; 2606 1.59 fvdl nfsfh_t *fhp; 2607 1.59 fvdl u_quad_t fileno; 2608 1.225 christos int error = 0, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i; 2609 1.86 thorpej int attrflag, fhsize, nrpcs = 0, reclen; 2610 1.79 fvdl struct nfs_fattr fattr, *fp; 2611 1.59 fvdl 2612 1.81 fvdl #ifdef DIAGNOSTIC 2613 1.219 yamt if (uiop->uio_iovcnt != 1 || uiop->uio_resid != NFS_DIRBLKSIZ) 2614 1.59 fvdl panic("nfs readdirplusrpc bad uio"); 2615 1.59 fvdl #endif 2616 1.32 mycroft ndp->ni_dvp = vp; 2617 1.32 mycroft newvp = NULLVP; 2618 1.59 fvdl 2619 1.59 fvdl /* 2620 1.59 fvdl * Loop around doing readdir rpc's of size nm_readdirsize 2621 1.81 fvdl * truncated to a multiple of NFS_DIRFRAGSIZ. 2622 1.32 mycroft * The stopping criteria is EOF or buffer full. 2623 1.32 mycroft */ 2624 1.59 fvdl while (more_dirs && bigenough) { 2625 1.85 fvdl if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) { 2626 1.85 fvdl bigenough = 0; 2627 1.85 fvdl break; 2628 1.85 fvdl } 2629 1.59 fvdl nfsstats.rpccnt[NFSPROC_READDIRPLUS]++; 2630 1.165 drochner nfsm_reqhead(dnp, NFSPROC_READDIRPLUS, 2631 1.59 fvdl NFSX_FH(1) + 6 * NFSX_UNSIGNED); 2632 1.165 drochner nfsm_fhtom(dnp, 1); 2633 1.59 fvdl nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2634 1.81 fvdl if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) { 2635 1.81 fvdl txdr_swapcookie3(uiop->uio_offset, tl); 2636 1.81 fvdl } else { 2637 1.81 fvdl txdr_cookie3(uiop->uio_offset, tl); 2638 1.81 fvdl } 2639 1.81 fvdl tl += 2; 2640 1.325 schmonz if (uiop->uio_offset == 0) { 2641 1.325 schmonz *tl++ = 0; 2642 1.325 schmonz *tl++ = 0; 2643 1.325 schmonz } else { 2644 1.325 schmonz *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2645 1.325 schmonz *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2646 1.325 schmonz } 2647 1.59 fvdl *tl++ = txdr_unsigned(nmp->nm_readdirsize); 2648 1.59 fvdl *tl = txdr_unsigned(nmp->nm_rsize); 2649 1.231 yamt nfsm_request(dnp, NFSPROC_READDIRPLUS, curlwp, cred); 2650 1.153 yamt nfsm_postop_attr(vp, attrflag, 0); 2651 1.59 fvdl if (error) { 2652 1.59 fvdl m_freem(mrep); 2653 1.59 fvdl goto nfsmout; 2654 1.59 fvdl } 2655 1.85 fvdl nrpcs++; 2656 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2657 1.59 fvdl dnp->n_cookieverf.nfsuquad[0] = *tl++; 2658 1.59 fvdl dnp->n_cookieverf.nfsuquad[1] = *tl++; 2659 1.32 mycroft more_dirs = fxdr_unsigned(int, *tl); 2660 1.220 perry 2661 1.32 mycroft /* loop thru the dir entries, doctoring them to 4bsd form */ 2662 1.32 mycroft while (more_dirs && bigenough) { 2663 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2664 1.98 fair fileno = fxdr_hyper(tl); 2665 1.59 fvdl len = fxdr_unsigned(int, *(tl + 2)); 2666 1.32 mycroft if (len <= 0 || len > NFS_MAXNAMLEN) { 2667 1.32 mycroft error = EBADRPC; 2668 1.32 mycroft m_freem(mrep); 2669 1.32 mycroft goto nfsmout; 2670 1.32 mycroft } 2671 1.225 christos /* for cookie stashing */ 2672 1.226 yamt reclen = _DIRENT_RECLEN(dp, len) + 2 * sizeof(off_t); 2673 1.81 fvdl left = NFS_DIRFRAGSIZ - blksiz; 2674 1.86 thorpej if (reclen > left) { 2675 1.86 thorpej /* 2676 1.86 thorpej * DIRFRAGSIZ is aligned, no need to align 2677 1.86 thorpej * again here. 2678 1.86 thorpej */ 2679 1.211 yamt memset(uiop->uio_iov->iov_base, 0, left); 2680 1.59 fvdl dp->d_reclen += left; 2681 1.225 christos UIO_ADVANCE(uiop, left); 2682 1.81 fvdl NFS_STASHCOOKIE(dp, uiop->uio_offset); 2683 1.59 fvdl blksiz = 0; 2684 1.59 fvdl } 2685 1.86 thorpej if (reclen > uiop->uio_resid) 2686 1.32 mycroft bigenough = 0; 2687 1.59 fvdl if (bigenough) { 2688 1.225 christos int tlen; 2689 1.225 christos 2690 1.32 mycroft dp = (struct dirent *)uiop->uio_iov->iov_base; 2691 1.225 christos dp->d_fileno = fileno; 2692 1.32 mycroft dp->d_namlen = len; 2693 1.86 thorpej dp->d_reclen = reclen; 2694 1.59 fvdl dp->d_type = DT_UNKNOWN; 2695 1.225 christos blksiz += reclen; 2696 1.81 fvdl if (blksiz == NFS_DIRFRAGSIZ) 2697 1.59 fvdl blksiz = 0; 2698 1.225 christos UIO_ADVANCE(uiop, DIRHDSIZ); 2699 1.32 mycroft nfsm_mtouio(uiop, len); 2700 1.225 christos tlen = reclen - (DIRHDSIZ + len); 2701 1.225 christos (void)memset(uiop->uio_iov->iov_base, 0, tlen); 2702 1.225 christos UIO_ADVANCE(uiop, tlen); 2703 1.225 christos cnp->cn_nameptr = dp->d_name; 2704 1.225 christos cnp->cn_namelen = dp->d_namlen; 2705 1.59 fvdl } else 2706 1.59 fvdl nfsm_adv(nfsm_rndup(len)); 2707 1.59 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2708 1.59 fvdl if (bigenough) { 2709 1.81 fvdl if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) 2710 1.81 fvdl uiop->uio_offset = 2711 1.81 fvdl fxdr_swapcookie3(tl); 2712 1.81 fvdl else 2713 1.81 fvdl uiop->uio_offset = 2714 1.81 fvdl fxdr_cookie3(tl); 2715 1.81 fvdl NFS_STASHCOOKIE(dp, uiop->uio_offset); 2716 1.81 fvdl } 2717 1.81 fvdl tl += 2; 2718 1.59 fvdl 2719 1.59 fvdl /* 2720 1.59 fvdl * Since the attributes are before the file handle 2721 1.59 fvdl * (sigh), we must skip over the attributes and then 2722 1.59 fvdl * come back and get them. 2723 1.59 fvdl */ 2724 1.59 fvdl attrflag = fxdr_unsigned(int, *tl); 2725 1.59 fvdl if (attrflag) { 2726 1.79 fvdl nfsm_dissect(fp, struct nfs_fattr *, NFSX_V3FATTR); 2727 1.97 perry memcpy(&fattr, fp, NFSX_V3FATTR); 2728 1.59 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2729 1.59 fvdl doit = fxdr_unsigned(int, *tl); 2730 1.59 fvdl if (doit) { 2731 1.59 fvdl nfsm_getfh(fhp, fhsize, 1); 2732 1.59 fvdl if (NFS_CMPFH(dnp, fhp, fhsize)) { 2733 1.282 pooka vref(vp); 2734 1.59 fvdl newvp = vp; 2735 1.59 fvdl np = dnp; 2736 1.59 fvdl } else { 2737 1.191 yamt error = nfs_nget1(vp->v_mount, fhp, 2738 1.191 yamt fhsize, &np, LK_NOWAIT); 2739 1.79 fvdl if (!error) 2740 1.59 fvdl newvp = NFSTOV(np); 2741 1.59 fvdl } 2742 1.79 fvdl if (!error) { 2743 1.153 yamt nfs_loadattrcache(&newvp, &fattr, 0, 0); 2744 1.208 yamt if (bigenough) { 2745 1.208 yamt dp->d_type = 2746 1.208 yamt IFTODT(VTTOIF(np->n_vattr->va_type)); 2747 1.312 christos ndp->ni_vp = newvp; 2748 1.312 christos nfs_cache_enter(ndp->ni_dvp, 2749 1.312 christos ndp->ni_vp, cnp); 2750 1.208 yamt } 2751 1.79 fvdl } 2752 1.209 yamt error = 0; 2753 1.79 fvdl } 2754 1.32 mycroft } else { 2755 1.59 fvdl /* Just skip over the file handle */ 2756 1.59 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2757 1.59 fvdl i = fxdr_unsigned(int, *tl); 2758 1.59 fvdl nfsm_adv(nfsm_rndup(i)); 2759 1.32 mycroft } 2760 1.32 mycroft if (newvp != NULLVP) { 2761 1.220 perry if (newvp == vp) 2762 1.220 perry vrele(newvp); 2763 1.220 perry else 2764 1.151 tls vput(newvp); 2765 1.59 fvdl newvp = NULLVP; 2766 1.32 mycroft } 2767 1.59 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2768 1.32 mycroft more_dirs = fxdr_unsigned(int, *tl); 2769 1.32 mycroft } 2770 1.32 mycroft /* 2771 1.32 mycroft * If at end of rpc data, get the eof boolean 2772 1.32 mycroft */ 2773 1.32 mycroft if (!more_dirs) { 2774 1.53 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2775 1.32 mycroft more_dirs = (fxdr_unsigned(int, *tl) == 0); 2776 1.219 yamt 2777 1.219 yamt /* 2778 1.219 yamt * kludge: see a comment in nfs_readdirrpc. 2779 1.219 yamt */ 2780 1.219 yamt 2781 1.219 yamt if (uiop->uio_resid >= NFS_DIRBLKSIZ) 2782 1.219 yamt more_dirs = 0; 2783 1.32 mycroft } 2784 1.32 mycroft m_freem(mrep); 2785 1.32 mycroft } 2786 1.32 mycroft /* 2787 1.81 fvdl * Fill last record, iff any, out to a multiple of NFS_DIRFRAGSIZ 2788 1.32 mycroft * by increasing d_reclen for the last record. 2789 1.32 mycroft */ 2790 1.59 fvdl if (blksiz > 0) { 2791 1.81 fvdl left = NFS_DIRFRAGSIZ - blksiz; 2792 1.211 yamt memset(uiop->uio_iov->iov_base, 0, left); 2793 1.59 fvdl dp->d_reclen += left; 2794 1.81 fvdl NFS_STASHCOOKIE(dp, uiop->uio_offset); 2795 1.225 christos UIO_ADVANCE(uiop, left); 2796 1.59 fvdl } 2797 1.59 fvdl 2798 1.59 fvdl /* 2799 1.59 fvdl * We are now either at the end of the directory or have filled the 2800 1.59 fvdl * block. 2801 1.59 fvdl */ 2802 1.218 yamt if (bigenough) { 2803 1.59 fvdl dnp->n_direofoffset = uiop->uio_offset; 2804 1.218 yamt dnp->n_flag |= NEOFVALID; 2805 1.218 yamt } 2806 1.32 mycroft nfsmout: 2807 1.128 fvdl if (newvp != NULLVP) { 2808 1.151 tls if(newvp == vp) 2809 1.151 tls vrele(newvp); 2810 1.151 tls else 2811 1.151 tls vput(newvp); 2812 1.128 fvdl } 2813 1.32 mycroft return (error); 2814 1.32 mycroft } 2815 1.200 christos #endif 2816 1.200 christos 2817 1.1 cgd /* 2818 1.1 cgd * Silly rename. To make the NFS filesystem that is stateless look a little 2819 1.1 cgd * more like the "ufs" a remove of an active vnode is translated to a rename 2820 1.1 cgd * to a funny looking filename that is removed by nfs_inactive on the 2821 1.1 cgd * nfsnode. There is the potential for another process on a different client 2822 1.1 cgd * to create the same funny name between the nfs_lookitup() fails and the 2823 1.1 cgd * nfs_rename() completes, but... 2824 1.1 cgd */ 2825 1.32 mycroft int 2826 1.273 dsl nfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, bool dolink) 2827 1.1 cgd { 2828 1.111 augustss struct sillyrename *sp; 2829 1.59 fvdl struct nfsnode *np; 2830 1.1 cgd int error; 2831 1.280 apb pid_t pid; 2832 1.1 cgd 2833 1.32 mycroft cache_purge(dvp); 2834 1.32 mycroft np = VTONFS(vp); 2835 1.59 fvdl #ifndef DIAGNOSTIC 2836 1.59 fvdl if (vp->v_type == VDIR) 2837 1.59 fvdl panic("nfs: sillyrename dir"); 2838 1.59 fvdl #endif 2839 1.264 yamt sp = kmem_alloc(sizeof(*sp), KM_SLEEP); 2840 1.236 elad sp->s_cred = kauth_cred_dup(cnp->cn_cred); 2841 1.32 mycroft sp->s_dvp = dvp; 2842 1.282 pooka vref(dvp); 2843 1.1 cgd 2844 1.1 cgd /* Fudge together a funny name */ 2845 1.261 pooka pid = curlwp->l_proc->p_pid; 2846 1.97 perry memcpy(sp->s_name, ".nfsAxxxx4.4", 13); 2847 1.1 cgd sp->s_namlen = 12; 2848 1.221 christos sp->s_name[8] = hexdigits[pid & 0xf]; 2849 1.221 christos sp->s_name[7] = hexdigits[(pid >> 4) & 0xf]; 2850 1.221 christos sp->s_name[6] = hexdigits[(pid >> 8) & 0xf]; 2851 1.221 christos sp->s_name[5] = hexdigits[(pid >> 12) & 0xf]; 2852 1.1 cgd 2853 1.1 cgd /* Try lookitups until we get one that isn't there */ 2854 1.59 fvdl while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 2855 1.261 pooka curlwp, (struct nfsnode **)0) == 0) { 2856 1.1 cgd sp->s_name[4]++; 2857 1.1 cgd if (sp->s_name[4] > 'z') { 2858 1.1 cgd error = EINVAL; 2859 1.1 cgd goto bad; 2860 1.1 cgd } 2861 1.1 cgd } 2862 1.239 yamt if (dolink) { 2863 1.239 yamt error = nfs_linkrpc(dvp, vp, sp->s_name, sp->s_namlen, 2864 1.261 pooka sp->s_cred, curlwp); 2865 1.239 yamt /* 2866 1.239 yamt * nfs_request maps NFSERR_NOTSUPP to ENOTSUP. 2867 1.239 yamt */ 2868 1.239 yamt if (error == ENOTSUP) { 2869 1.239 yamt error = nfs_renameit(dvp, cnp, sp); 2870 1.239 yamt } 2871 1.239 yamt } else { 2872 1.239 yamt error = nfs_renameit(dvp, cnp, sp); 2873 1.239 yamt } 2874 1.59 fvdl if (error) 2875 1.1 cgd goto bad; 2876 1.59 fvdl error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred, 2877 1.261 pooka curlwp, &np); 2878 1.1 cgd np->n_sillyrename = sp; 2879 1.1 cgd return (0); 2880 1.1 cgd bad: 2881 1.1 cgd vrele(sp->s_dvp); 2882 1.236 elad kauth_cred_free(sp->s_cred); 2883 1.264 yamt kmem_free(sp, sizeof(*sp)); 2884 1.1 cgd return (error); 2885 1.1 cgd } 2886 1.1 cgd 2887 1.1 cgd /* 2888 1.59 fvdl * Look up a file name and optionally either update the file handle or 2889 1.59 fvdl * allocate an nfsnode, depending on the value of npp. 2890 1.59 fvdl * npp == NULL --> just do the lookup 2891 1.59 fvdl * *npp == NULL --> allocate a new nfsnode and make sure attributes are 2892 1.59 fvdl * handled too 2893 1.59 fvdl * *npp != NULL --> update the file handle in the vnode 2894 1.1 cgd */ 2895 1.32 mycroft int 2896 1.272 dsl nfs_lookitup(struct vnode *dvp, const char *name, int len, kauth_cred_t cred, struct lwp *l, struct nfsnode **npp) 2897 1.1 cgd { 2898 1.111 augustss u_int32_t *tl; 2899 1.252 christos char *cp; 2900 1.111 augustss int32_t t1, t2; 2901 1.59 fvdl struct vnode *newvp = (struct vnode *)0; 2902 1.59 fvdl struct nfsnode *np, *dnp = VTONFS(dvp); 2903 1.252 christos char *bpos, *dpos, *cp2; 2904 1.305 hannken int error = 0, ofhlen, fhlen; 2905 1.200 christos #ifndef NFS_V2_ONLY 2906 1.200 christos int attrflag; 2907 1.200 christos #endif 2908 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2909 1.305 hannken nfsfh_t *ofhp, *nfhp; 2910 1.119 bjh21 const int v3 = NFS_ISV3(dvp); 2911 1.1 cgd 2912 1.1 cgd nfsstats.rpccnt[NFSPROC_LOOKUP]++; 2913 1.165 drochner nfsm_reqhead(dnp, NFSPROC_LOOKUP, 2914 1.59 fvdl NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len)); 2915 1.165 drochner nfsm_fhtom(dnp, v3); 2916 1.59 fvdl nfsm_strtom(name, len, NFS_MAXNAMLEN); 2917 1.230 christos nfsm_request(dnp, NFSPROC_LOOKUP, l, cred); 2918 1.59 fvdl if (npp && !error) { 2919 1.59 fvdl nfsm_getfh(nfhp, fhlen, v3); 2920 1.59 fvdl if (*npp) { 2921 1.59 fvdl np = *npp; 2922 1.305 hannken newvp = NFSTOV(np); 2923 1.305 hannken ofhlen = np->n_fhsize; 2924 1.305 hannken ofhp = kmem_alloc(ofhlen, KM_SLEEP); 2925 1.305 hannken memcpy(ofhp, np->n_fhp, ofhlen); 2926 1.305 hannken error = vcache_rekey_enter(newvp->v_mount, newvp, 2927 1.305 hannken ofhp, ofhlen, nfhp, fhlen); 2928 1.305 hannken if (error) { 2929 1.305 hannken kmem_free(ofhp, ofhlen); 2930 1.305 hannken m_freem(mrep); 2931 1.305 hannken return error; 2932 1.305 hannken } 2933 1.59 fvdl if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) { 2934 1.264 yamt kmem_free(np->n_fhp, np->n_fhsize); 2935 1.59 fvdl np->n_fhp = &np->n_fh; 2936 1.235 christos } 2937 1.235 christos #if NFS_SMALLFH < NFSX_V3FHMAX 2938 1.264 yamt else if (np->n_fhsize <= NFS_SMALLFH && fhlen > NFS_SMALLFH) 2939 1.264 yamt np->n_fhp = kmem_alloc(fhlen, KM_SLEEP); 2940 1.235 christos #endif 2941 1.264 yamt memcpy(np->n_fhp, nfhp, fhlen); 2942 1.59 fvdl np->n_fhsize = fhlen; 2943 1.305 hannken vcache_rekey_exit(newvp->v_mount, newvp, 2944 1.305 hannken ofhp, ofhlen, np->n_fhp, fhlen); 2945 1.305 hannken kmem_free(ofhp, ofhlen); 2946 1.59 fvdl } else if (NFS_CMPFH(dnp, nfhp, fhlen)) { 2947 1.282 pooka vref(dvp); 2948 1.59 fvdl newvp = dvp; 2949 1.194 yamt np = dnp; 2950 1.59 fvdl } else { 2951 1.175 fvdl error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np); 2952 1.59 fvdl if (error) { 2953 1.59 fvdl m_freem(mrep); 2954 1.59 fvdl return (error); 2955 1.59 fvdl } 2956 1.59 fvdl newvp = NFSTOV(np); 2957 1.59 fvdl } 2958 1.200 christos #ifndef NFS_V2_ONLY 2959 1.59 fvdl if (v3) { 2960 1.153 yamt nfsm_postop_attr(newvp, attrflag, 0); 2961 1.59 fvdl if (!attrflag && *npp == NULL) { 2962 1.59 fvdl m_freem(mrep); 2963 1.128 fvdl vput(newvp); 2964 1.59 fvdl return (ENOENT); 2965 1.59 fvdl } 2966 1.59 fvdl } else 2967 1.200 christos #endif 2968 1.153 yamt nfsm_loadattr(newvp, (struct vattr *)0, 0); 2969 1.59 fvdl } 2970 1.59 fvdl nfsm_reqdone; 2971 1.59 fvdl if (npp && *npp == NULL) { 2972 1.59 fvdl if (error) { 2973 1.59 fvdl if (newvp) 2974 1.128 fvdl vput(newvp); 2975 1.59 fvdl } else 2976 1.59 fvdl *npp = np; 2977 1.32 mycroft } 2978 1.59 fvdl return (error); 2979 1.59 fvdl } 2980 1.59 fvdl 2981 1.200 christos #ifndef NFS_V2_ONLY 2982 1.59 fvdl /* 2983 1.59 fvdl * Nfs Version 3 commit rpc 2984 1.59 fvdl */ 2985 1.59 fvdl int 2986 1.272 dsl nfs_commit(struct vnode *vp, off_t offset, uint32_t cnt, struct lwp *l) 2987 1.59 fvdl { 2988 1.252 christos char *cp; 2989 1.111 augustss u_int32_t *tl; 2990 1.111 augustss int32_t t1, t2; 2991 1.111 augustss struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2992 1.252 christos char *bpos, *dpos, *cp2; 2993 1.59 fvdl int error = 0, wccflag = NFSV3_WCCRATTR; 2994 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 2995 1.165 drochner struct nfsnode *np; 2996 1.120 fvdl 2997 1.166 yamt KASSERT(NFS_ISV3(vp)); 2998 1.166 yamt 2999 1.160 yamt #ifdef NFS_DEBUG_COMMIT 3000 1.120 fvdl printf("commit %lu - %lu\n", (unsigned long)offset, 3001 1.120 fvdl (unsigned long)(offset + cnt)); 3002 1.120 fvdl #endif 3003 1.220 perry 3004 1.254 yamt mutex_enter(&nmp->nm_lock); 3005 1.166 yamt if ((nmp->nm_iflag & NFSMNT_HASWRITEVERF) == 0) { 3006 1.254 yamt mutex_exit(&nmp->nm_lock); 3007 1.59 fvdl return (0); 3008 1.166 yamt } 3009 1.254 yamt mutex_exit(&nmp->nm_lock); 3010 1.59 fvdl nfsstats.rpccnt[NFSPROC_COMMIT]++; 3011 1.165 drochner np = VTONFS(vp); 3012 1.165 drochner nfsm_reqhead(np, NFSPROC_COMMIT, NFSX_FH(1)); 3013 1.165 drochner nfsm_fhtom(np, 1); 3014 1.59 fvdl nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3015 1.98 fair txdr_hyper(offset, tl); 3016 1.59 fvdl tl += 2; 3017 1.59 fvdl *tl = txdr_unsigned(cnt); 3018 1.230 christos nfsm_request(np, NFSPROC_COMMIT, l, np->n_wcred); 3019 1.251 thorpej nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, false); 3020 1.59 fvdl if (!error) { 3021 1.59 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF); 3022 1.254 yamt mutex_enter(&nmp->nm_lock); 3023 1.166 yamt if ((nmp->nm_iflag & NFSMNT_STALEWRITEVERF) || 3024 1.166 yamt memcmp(nmp->nm_writeverf, tl, NFSX_V3WRITEVERF)) { 3025 1.166 yamt memcpy(nmp->nm_writeverf, tl, NFSX_V3WRITEVERF); 3026 1.59 fvdl error = NFSERR_STALEWRITEVERF; 3027 1.166 yamt nmp->nm_iflag |= NFSMNT_STALEWRITEVERF; 3028 1.59 fvdl } 3029 1.254 yamt mutex_exit(&nmp->nm_lock); 3030 1.1 cgd } 3031 1.1 cgd nfsm_reqdone; 3032 1.1 cgd return (error); 3033 1.1 cgd } 3034 1.200 christos #endif 3035 1.1 cgd 3036 1.1 cgd /* 3037 1.1 cgd * Kludge City.. 3038 1.1 cgd * - make nfs_bmap() essentially a no-op that does no translation 3039 1.59 fvdl * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc 3040 1.1 cgd * (Maybe I could use the process's page mapping, but I was concerned that 3041 1.1 cgd * Kernel Write might not be enabled and also figured copyout() would do 3042 1.97 perry * a lot more work than memcpy() and also it currently happens in the 3043 1.1 cgd * context of the swapper process (2). 3044 1.1 cgd */ 3045 1.32 mycroft int 3046 1.272 dsl nfs_bmap(void *v) 3047 1.58 christos { 3048 1.32 mycroft struct vop_bmap_args /* { 3049 1.32 mycroft struct vnode *a_vp; 3050 1.32 mycroft daddr_t a_bn; 3051 1.32 mycroft struct vnode **a_vpp; 3052 1.32 mycroft daddr_t *a_bnp; 3053 1.32 mycroft int *a_runp; 3054 1.58 christos } */ *ap = v; 3055 1.111 augustss struct vnode *vp = ap->a_vp; 3056 1.139 chs int bshift = vp->v_mount->mnt_fs_bshift - vp->v_mount->mnt_dev_bshift; 3057 1.32 mycroft 3058 1.32 mycroft if (ap->a_vpp != NULL) 3059 1.32 mycroft *ap->a_vpp = vp; 3060 1.32 mycroft if (ap->a_bnp != NULL) 3061 1.139 chs *ap->a_bnp = ap->a_bn << bshift; 3062 1.138 chs if (ap->a_runp != NULL) 3063 1.138 chs *ap->a_runp = 1024 * 1024; /* XXX */ 3064 1.1 cgd return (0); 3065 1.1 cgd } 3066 1.1 cgd 3067 1.1 cgd /* 3068 1.32 mycroft * Strategy routine. 3069 1.32 mycroft * For async requests when nfsiod(s) are running, queue the request by 3070 1.32 mycroft * calling nfs_asyncio(), otherwise just all nfs_doio() to do the 3071 1.32 mycroft * request. 3072 1.1 cgd */ 3073 1.32 mycroft int 3074 1.272 dsl nfs_strategy(void *v) 3075 1.1 cgd { 3076 1.58 christos struct vop_strategy_args *ap = v; 3077 1.111 augustss struct buf *bp = ap->a_bp; 3078 1.1 cgd int error = 0; 3079 1.1 cgd 3080 1.33 pk if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC)) 3081 1.33 pk panic("nfs physio/async"); 3082 1.124 chs 3083 1.1 cgd /* 3084 1.1 cgd * If the op is asynchronous and an i/o daemon is waiting 3085 1.1 cgd * queue the request, wake it up and wait for completion 3086 1.1 cgd * otherwise just do it ourselves. 3087 1.1 cgd */ 3088 1.223 christos if ((bp->b_flags & B_ASYNC) == 0 || nfs_asyncio(bp)) 3089 1.223 christos error = nfs_doio(bp); 3090 1.1 cgd return (error); 3091 1.1 cgd } 3092 1.1 cgd 3093 1.1 cgd /* 3094 1.59 fvdl * fsync vnode op. Just call nfs_flush() with commit == 1. 3095 1.1 cgd */ 3096 1.1 cgd /* ARGSUSED */ 3097 1.32 mycroft int 3098 1.272 dsl nfs_fsync(void *v) 3099 1.58 christos { 3100 1.32 mycroft struct vop_fsync_args /* { 3101 1.32 mycroft struct vnodeop_desc *a_desc; 3102 1.32 mycroft struct vnode * a_vp; 3103 1.236 elad kauth_cred_t a_cred; 3104 1.92 kleink int a_flags; 3105 1.120 fvdl off_t offlo; 3106 1.120 fvdl off_t offhi; 3107 1.230 christos struct lwp * a_l; 3108 1.58 christos } */ *ap = v; 3109 1.59 fvdl 3110 1.186 yamt struct vnode *vp = ap->a_vp; 3111 1.186 yamt 3112 1.186 yamt if (vp->v_type != VREG) 3113 1.186 yamt return 0; 3114 1.186 yamt 3115 1.186 yamt return (nfs_flush(vp, ap->a_cred, 3116 1.260 pooka (ap->a_flags & FSYNC_WAIT) != 0 ? MNT_WAIT : 0, curlwp, 1)); 3117 1.59 fvdl } 3118 1.59 fvdl 3119 1.59 fvdl /* 3120 1.124 chs * Flush all the data associated with a vnode. 3121 1.59 fvdl */ 3122 1.59 fvdl int 3123 1.245 yamt nfs_flush(struct vnode *vp, kauth_cred_t cred, int waitfor, struct lwp *l, 3124 1.245 yamt int commit) 3125 1.59 fvdl { 3126 1.111 augustss struct nfsnode *np = VTONFS(vp); 3127 1.124 chs int error; 3128 1.124 chs int flushflags = PGO_ALLPAGES|PGO_CLEANIT|PGO_SYNCIO; 3129 1.124 chs UVMHIST_FUNC("nfs_flush"); UVMHIST_CALLED(ubchist); 3130 1.1 cgd 3131 1.313 ad rw_enter(vp->v_uobj.vmobjlock, RW_WRITER); 3132 1.145 chs error = VOP_PUTPAGES(vp, 0, 0, flushflags); 3133 1.32 mycroft if (np->n_flag & NWRITEERR) { 3134 1.1 cgd error = np->n_error; 3135 1.32 mycroft np->n_flag &= ~NWRITEERR; 3136 1.32 mycroft } 3137 1.124 chs UVMHIST_LOG(ubchist, "returning %d", error,0,0,0); 3138 1.1 cgd return (error); 3139 1.1 cgd } 3140 1.1 cgd 3141 1.1 cgd /* 3142 1.32 mycroft * Return POSIX pathconf information applicable to nfs. 3143 1.32 mycroft * 3144 1.95 kleink * N.B. The NFS V2 protocol doesn't support this RPC. 3145 1.32 mycroft */ 3146 1.32 mycroft /* ARGSUSED */ 3147 1.58 christos int 3148 1.272 dsl nfs_pathconf(void *v) 3149 1.58 christos { 3150 1.32 mycroft struct vop_pathconf_args /* { 3151 1.32 mycroft struct vnode *a_vp; 3152 1.32 mycroft int a_name; 3153 1.41 cgd register_t *a_retval; 3154 1.58 christos } */ *ap = v; 3155 1.95 kleink struct nfsv3_pathconf *pcp; 3156 1.95 kleink struct vnode *vp = ap->a_vp; 3157 1.159 matt struct mbuf *mreq, *mrep, *md, *mb; 3158 1.95 kleink int32_t t1, t2; 3159 1.95 kleink u_int32_t *tl; 3160 1.252 christos char *bpos, *dpos, *cp, *cp2; 3161 1.95 kleink int error = 0, attrflag; 3162 1.146 christos #ifndef NFS_V2_ONLY 3163 1.146 christos struct nfsmount *nmp; 3164 1.99 kleink unsigned int l; 3165 1.99 kleink u_int64_t maxsize; 3166 1.146 christos #endif 3167 1.119 bjh21 const int v3 = NFS_ISV3(vp); 3168 1.165 drochner struct nfsnode *np = VTONFS(vp); 3169 1.95 kleink 3170 1.95 kleink switch (ap->a_name) { 3171 1.95 kleink /* Names that can be resolved locally. */ 3172 1.95 kleink case _PC_PIPE_BUF: 3173 1.95 kleink *ap->a_retval = PIPE_BUF; 3174 1.95 kleink break; 3175 1.95 kleink case _PC_SYNC_IO: 3176 1.95 kleink *ap->a_retval = 1; 3177 1.95 kleink break; 3178 1.95 kleink /* Names that cannot be resolved locally; do an RPC, if possible. */ 3179 1.95 kleink case _PC_LINK_MAX: 3180 1.95 kleink case _PC_NAME_MAX: 3181 1.95 kleink case _PC_CHOWN_RESTRICTED: 3182 1.95 kleink case _PC_NO_TRUNC: 3183 1.95 kleink if (!v3) { 3184 1.96 kleink error = EINVAL; 3185 1.95 kleink break; 3186 1.95 kleink } 3187 1.95 kleink nfsstats.rpccnt[NFSPROC_PATHCONF]++; 3188 1.165 drochner nfsm_reqhead(np, NFSPROC_PATHCONF, NFSX_FH(1)); 3189 1.165 drochner nfsm_fhtom(np, 1); 3190 1.165 drochner nfsm_request(np, NFSPROC_PATHCONF, 3191 1.241 ad curlwp, curlwp->l_cred); /* XXX */ 3192 1.153 yamt nfsm_postop_attr(vp, attrflag, 0); 3193 1.95 kleink if (!error) { 3194 1.95 kleink nfsm_dissect(pcp, struct nfsv3_pathconf *, 3195 1.95 kleink NFSX_V3PATHCONF); 3196 1.95 kleink switch (ap->a_name) { 3197 1.95 kleink case _PC_LINK_MAX: 3198 1.95 kleink *ap->a_retval = 3199 1.95 kleink fxdr_unsigned(register_t, pcp->pc_linkmax); 3200 1.95 kleink break; 3201 1.95 kleink case _PC_NAME_MAX: 3202 1.95 kleink *ap->a_retval = 3203 1.95 kleink fxdr_unsigned(register_t, pcp->pc_namemax); 3204 1.95 kleink break; 3205 1.95 kleink case _PC_CHOWN_RESTRICTED: 3206 1.95 kleink *ap->a_retval = 3207 1.95 kleink (pcp->pc_chownrestricted == nfs_true); 3208 1.95 kleink break; 3209 1.95 kleink case _PC_NO_TRUNC: 3210 1.95 kleink *ap->a_retval = 3211 1.95 kleink (pcp->pc_notrunc == nfs_true); 3212 1.95 kleink break; 3213 1.95 kleink } 3214 1.95 kleink } 3215 1.95 kleink nfsm_reqdone; 3216 1.99 kleink break; 3217 1.99 kleink case _PC_FILESIZEBITS: 3218 1.146 christos #ifndef NFS_V2_ONLY 3219 1.99 kleink if (v3) { 3220 1.99 kleink nmp = VFSTONFS(vp->v_mount); 3221 1.99 kleink if ((nmp->nm_iflag & NFSMNT_GOTFSINFO) == 0) 3222 1.99 kleink if ((error = nfs_fsinfo(nmp, vp, 3223 1.241 ad curlwp->l_cred, curlwp)) != 0) /* XXX */ 3224 1.99 kleink break; 3225 1.99 kleink for (l = 0, maxsize = nmp->nm_maxfilesize; 3226 1.99 kleink (maxsize >> l) > 0; l++) 3227 1.99 kleink ; 3228 1.99 kleink *ap->a_retval = l + 1; 3229 1.146 christos } else 3230 1.146 christos #endif 3231 1.146 christos { 3232 1.99 kleink *ap->a_retval = 32; /* NFS V2 limitation */ 3233 1.99 kleink } 3234 1.95 kleink break; 3235 1.95 kleink default: 3236 1.316 christos error = genfs_pathconf(ap); 3237 1.95 kleink break; 3238 1.95 kleink } 3239 1.32 mycroft 3240 1.95 kleink return (error); 3241 1.32 mycroft } 3242 1.32 mycroft 3243 1.32 mycroft /* 3244 1.1 cgd * NFS advisory byte-level locks. 3245 1.1 cgd */ 3246 1.32 mycroft int 3247 1.272 dsl nfs_advlock(void *v) 3248 1.58 christos { 3249 1.32 mycroft struct vop_advlock_args /* { 3250 1.32 mycroft struct vnode *a_vp; 3251 1.252 christos void *a_id; 3252 1.32 mycroft int a_op; 3253 1.32 mycroft struct flock *a_fl; 3254 1.32 mycroft int a_flags; 3255 1.58 christos } */ *ap = v; 3256 1.111 augustss struct nfsnode *np = VTONFS(ap->a_vp); 3257 1.1 cgd 3258 1.115 jdolecek return lf_advlock(ap, &np->n_lockf, np->n_size); 3259 1.1 cgd } 3260 1.1 cgd 3261 1.1 cgd /* 3262 1.1 cgd * Print out the contents of an nfsnode. 3263 1.1 cgd */ 3264 1.17 cgd int 3265 1.272 dsl nfs_print(void *v) 3266 1.58 christos { 3267 1.32 mycroft struct vop_print_args /* { 3268 1.32 mycroft struct vnode *a_vp; 3269 1.58 christos } */ *ap = v; 3270 1.111 augustss struct vnode *vp = ap->a_vp; 3271 1.111 augustss struct nfsnode *np = VTONFS(vp); 3272 1.1 cgd 3273 1.269 christos printf("tag VT_NFS, fileid %lld fsid 0x%llx", 3274 1.269 christos (unsigned long long)np->n_vattr->va_fileid, 3275 1.269 christos (unsigned long long)np->n_vattr->va_fsid); 3276 1.1 cgd if (vp->v_type == VFIFO) 3277 1.283 pooka VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v); 3278 1.67 christos printf("\n"); 3279 1.59 fvdl return (0); 3280 1.32 mycroft } 3281 1.32 mycroft 3282 1.32 mycroft /* 3283 1.153 yamt * nfs unlock wrapper. 3284 1.153 yamt */ 3285 1.153 yamt int 3286 1.153 yamt nfs_unlock(void *v) 3287 1.153 yamt { 3288 1.153 yamt struct vop_unlock_args /* { 3289 1.153 yamt struct vnode *a_vp; 3290 1.153 yamt int a_flags; 3291 1.153 yamt } */ *ap = v; 3292 1.153 yamt struct vnode *vp = ap->a_vp; 3293 1.153 yamt 3294 1.155 yamt /* 3295 1.155 yamt * VOP_UNLOCK can be called by nfs_loadattrcache 3296 1.155 yamt * with v_data == 0. 3297 1.155 yamt */ 3298 1.155 yamt if (VTONFS(vp)) { 3299 1.155 yamt nfs_delayedtruncate(vp); 3300 1.155 yamt } 3301 1.153 yamt 3302 1.153 yamt return genfs_unlock(v); 3303 1.59 fvdl } 3304 1.59 fvdl 3305 1.59 fvdl /* 3306 1.32 mycroft * nfs special file access vnode op. 3307 1.32 mycroft * Essentially just get vattr and then imitate iaccess() since the device is 3308 1.32 mycroft * local to the client. 3309 1.3 glass */ 3310 1.32 mycroft int 3311 1.272 dsl nfsspec_access(void *v) 3312 1.58 christos { 3313 1.32 mycroft struct vop_access_args /* { 3314 1.32 mycroft struct vnode *a_vp; 3315 1.315 christos accmode_t a_accmode; 3316 1.236 elad kauth_cred_t a_cred; 3317 1.230 christos struct lwp *a_l; 3318 1.58 christos } */ *ap = v; 3319 1.46 mycroft struct vattr va; 3320 1.59 fvdl struct vnode *vp = ap->a_vp; 3321 1.32 mycroft int error; 3322 1.3 glass 3323 1.260 pooka error = VOP_GETATTR(vp, &va, ap->a_cred); 3324 1.71 fvdl if (error) 3325 1.71 fvdl return (error); 3326 1.71 fvdl 3327 1.59 fvdl /* 3328 1.59 fvdl * Disallow write attempts on filesystems mounted read-only; 3329 1.59 fvdl * unless the file is a socket, fifo, or a block or character 3330 1.59 fvdl * device resident on the filesystem. 3331 1.59 fvdl */ 3332 1.315 christos if ((ap->a_accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 3333 1.59 fvdl switch (vp->v_type) { 3334 1.59 fvdl case VREG: 3335 1.59 fvdl case VDIR: 3336 1.59 fvdl case VLNK: 3337 1.59 fvdl return (EROFS); 3338 1.59 fvdl default: 3339 1.59 fvdl break; 3340 1.59 fvdl } 3341 1.59 fvdl } 3342 1.46 mycroft 3343 1.315 christos return kauth_authorize_vnode(ap->a_cred, KAUTH_ACCESS_ACTION( 3344 1.315 christos ap->a_accmode, va.va_type, va.va_mode), vp, NULL, genfs_can_access( 3345 1.315 christos vp, ap->a_cred, va.va_uid, va.va_gid, va.va_mode, NULL, 3346 1.315 christos ap->a_accmode)); 3347 1.3 glass } 3348 1.22 pk 3349 1.22 pk /* 3350 1.22 pk * Read wrapper for special devices. 3351 1.22 pk */ 3352 1.32 mycroft int 3353 1.272 dsl nfsspec_read(void *v) 3354 1.58 christos { 3355 1.32 mycroft struct vop_read_args /* { 3356 1.32 mycroft struct vnode *a_vp; 3357 1.32 mycroft struct uio *a_uio; 3358 1.32 mycroft int a_ioflag; 3359 1.236 elad kauth_cred_t a_cred; 3360 1.58 christos } */ *ap = v; 3361 1.111 augustss struct nfsnode *np = VTONFS(ap->a_vp); 3362 1.32 mycroft 3363 1.32 mycroft /* 3364 1.32 mycroft * Set access flag. 3365 1.32 mycroft */ 3366 1.32 mycroft np->n_flag |= NACC; 3367 1.237 kardel getnanotime(&np->n_atim); 3368 1.32 mycroft return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap)); 3369 1.22 pk } 3370 1.22 pk 3371 1.22 pk /* 3372 1.22 pk * Write wrapper for special devices. 3373 1.22 pk */ 3374 1.32 mycroft int 3375 1.272 dsl nfsspec_write(void *v) 3376 1.58 christos { 3377 1.32 mycroft struct vop_write_args /* { 3378 1.32 mycroft struct vnode *a_vp; 3379 1.32 mycroft struct uio *a_uio; 3380 1.32 mycroft int a_ioflag; 3381 1.236 elad kauth_cred_t a_cred; 3382 1.58 christos } */ *ap = v; 3383 1.111 augustss struct nfsnode *np = VTONFS(ap->a_vp); 3384 1.32 mycroft 3385 1.32 mycroft /* 3386 1.32 mycroft * Set update flag. 3387 1.32 mycroft */ 3388 1.32 mycroft np->n_flag |= NUPD; 3389 1.237 kardel getnanotime(&np->n_mtim); 3390 1.32 mycroft return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap)); 3391 1.22 pk } 3392 1.22 pk 3393 1.22 pk /* 3394 1.22 pk * Close wrapper for special devices. 3395 1.22 pk * 3396 1.32 mycroft * Update the times on the nfsnode then do device close. 3397 1.22 pk */ 3398 1.32 mycroft int 3399 1.272 dsl nfsspec_close(void *v) 3400 1.58 christos { 3401 1.32 mycroft struct vop_close_args /* { 3402 1.32 mycroft struct vnode *a_vp; 3403 1.32 mycroft int a_fflag; 3404 1.236 elad kauth_cred_t a_cred; 3405 1.230 christos struct lwp *a_l; 3406 1.58 christos } */ *ap = v; 3407 1.111 augustss struct vnode *vp = ap->a_vp; 3408 1.111 augustss struct nfsnode *np = VTONFS(vp); 3409 1.32 mycroft struct vattr vattr; 3410 1.32 mycroft 3411 1.32 mycroft if (np->n_flag & (NACC | NUPD)) { 3412 1.32 mycroft np->n_flag |= NCHG; 3413 1.314 ad if (vrefcnt(vp) == 1 && 3414 1.32 mycroft (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 3415 1.282 pooka vattr_null(&vattr); 3416 1.59 fvdl if (np->n_flag & NACC) 3417 1.59 fvdl vattr.va_atime = np->n_atim; 3418 1.59 fvdl if (np->n_flag & NUPD) 3419 1.59 fvdl vattr.va_mtime = np->n_mtim; 3420 1.260 pooka (void)VOP_SETATTR(vp, &vattr, ap->a_cred); 3421 1.32 mycroft } 3422 1.22 pk } 3423 1.32 mycroft return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); 3424 1.22 pk } 3425 1.22 pk 3426 1.22 pk /* 3427 1.32 mycroft * Read wrapper for fifos. 3428 1.22 pk */ 3429 1.32 mycroft int 3430 1.272 dsl nfsfifo_read(void *v) 3431 1.58 christos { 3432 1.32 mycroft struct vop_read_args /* { 3433 1.32 mycroft struct vnode *a_vp; 3434 1.32 mycroft struct uio *a_uio; 3435 1.32 mycroft int a_ioflag; 3436 1.236 elad kauth_cred_t a_cred; 3437 1.58 christos } */ *ap = v; 3438 1.111 augustss struct nfsnode *np = VTONFS(ap->a_vp); 3439 1.32 mycroft 3440 1.22 pk /* 3441 1.32 mycroft * Set access flag. 3442 1.22 pk */ 3443 1.32 mycroft np->n_flag |= NACC; 3444 1.237 kardel getnanotime(&np->n_atim); 3445 1.32 mycroft return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap)); 3446 1.22 pk } 3447 1.22 pk 3448 1.22 pk /* 3449 1.32 mycroft * Write wrapper for fifos. 3450 1.22 pk */ 3451 1.32 mycroft int 3452 1.272 dsl nfsfifo_write(void *v) 3453 1.58 christos { 3454 1.32 mycroft struct vop_write_args /* { 3455 1.32 mycroft struct vnode *a_vp; 3456 1.32 mycroft struct uio *a_uio; 3457 1.32 mycroft int a_ioflag; 3458 1.236 elad kauth_cred_t a_cred; 3459 1.58 christos } */ *ap = v; 3460 1.111 augustss struct nfsnode *np = VTONFS(ap->a_vp); 3461 1.32 mycroft 3462 1.22 pk /* 3463 1.32 mycroft * Set update flag. 3464 1.22 pk */ 3465 1.32 mycroft np->n_flag |= NUPD; 3466 1.237 kardel getnanotime(&np->n_mtim); 3467 1.32 mycroft return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap)); 3468 1.22 pk } 3469 1.22 pk 3470 1.22 pk /* 3471 1.32 mycroft * Close wrapper for fifos. 3472 1.22 pk * 3473 1.32 mycroft * Update the times on the nfsnode then do fifo close. 3474 1.22 pk */ 3475 1.32 mycroft int 3476 1.272 dsl nfsfifo_close(void *v) 3477 1.58 christos { 3478 1.32 mycroft struct vop_close_args /* { 3479 1.32 mycroft struct vnode *a_vp; 3480 1.32 mycroft int a_fflag; 3481 1.236 elad kauth_cred_t a_cred; 3482 1.230 christos struct lwp *a_l; 3483 1.58 christos } */ *ap = v; 3484 1.111 augustss struct vnode *vp = ap->a_vp; 3485 1.111 augustss struct nfsnode *np = VTONFS(vp); 3486 1.32 mycroft struct vattr vattr; 3487 1.32 mycroft 3488 1.32 mycroft if (np->n_flag & (NACC | NUPD)) { 3489 1.237 kardel struct timespec ts; 3490 1.237 kardel 3491 1.237 kardel getnanotime(&ts); 3492 1.237 kardel if (np->n_flag & NACC) 3493 1.237 kardel np->n_atim = ts; 3494 1.237 kardel if (np->n_flag & NUPD) 3495 1.237 kardel np->n_mtim = ts; 3496 1.32 mycroft np->n_flag |= NCHG; 3497 1.314 ad if (vrefcnt(vp) == 1 && 3498 1.32 mycroft (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 3499 1.282 pooka vattr_null(&vattr); 3500 1.59 fvdl if (np->n_flag & NACC) 3501 1.59 fvdl vattr.va_atime = np->n_atim; 3502 1.59 fvdl if (np->n_flag & NUPD) 3503 1.59 fvdl vattr.va_mtime = np->n_mtim; 3504 1.260 pooka (void)VOP_SETATTR(vp, &vattr, ap->a_cred); 3505 1.32 mycroft } 3506 1.22 pk } 3507 1.32 mycroft return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); 3508 1.22 pk } 3509