1 1.184 riastrad /* $NetBSD: nfs_serv.c,v 1.184 2023/03/23 19:53:01 riastradh Exp $ */ 2 1.16 cgd 3 1.1 cgd /* 4 1.15 mycroft * Copyright (c) 1989, 1993 5 1.15 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.81 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.42 fvdl * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95 35 1.1 cgd */ 36 1.1 cgd 37 1.1 cgd /* 38 1.23 fvdl * nfs version 2 and 3 server calls to vnode ops 39 1.1 cgd * - these routines generally have 3 phases 40 1.1 cgd * 1 - break down and validate rpc request in mbuf list 41 1.1 cgd * 2 - do the vnode ops for the request 42 1.1 cgd * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 43 1.1 cgd * 3 - build the rpc reply in an mbuf list 44 1.1 cgd * nb: 45 1.1 cgd * - do not mix the phases, since the nfsm_?? macros can return failures 46 1.1 cgd * on a bad rpc or similar and do not do any vrele() or vput()'s 47 1.1 cgd * 48 1.1 cgd * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 49 1.1 cgd * error number iff error != 0 whereas 50 1.1 cgd * returning an error from the server function implies a fatal error 51 1.1 cgd * such as a badly constructed rpc request that should be dropped without 52 1.1 cgd * a reply. 53 1.23 fvdl * For Version 3, nfsm_reply() does not return for the error case, since 54 1.23 fvdl * most version 3 rpcs return more than the status for error cases. 55 1.1 cgd */ 56 1.62 lukem 57 1.62 lukem #include <sys/cdefs.h> 58 1.184 riastrad __KERNEL_RCSID(0, "$NetBSD: nfs_serv.c,v 1.184 2023/03/23 19:53:01 riastradh Exp $"); 59 1.41 mrg 60 1.10 mycroft #include <sys/param.h> 61 1.10 mycroft #include <sys/systm.h> 62 1.10 mycroft #include <sys/proc.h> 63 1.10 mycroft #include <sys/file.h> 64 1.10 mycroft #include <sys/namei.h> 65 1.10 mycroft #include <sys/vnode.h> 66 1.10 mycroft #include <sys/mount.h> 67 1.177 hannken #include <sys/fstrans.h> 68 1.23 fvdl #include <sys/socket.h> 69 1.23 fvdl #include <sys/socketvar.h> 70 1.10 mycroft #include <sys/mbuf.h> 71 1.15 mycroft #include <sys/dirent.h> 72 1.15 mycroft #include <sys/stat.h> 73 1.23 fvdl #include <sys/kernel.h> 74 1.117 yamt #include <sys/hash.h> 75 1.109 elad #include <sys/kauth.h> 76 1.139 ad #include <sys/module.h> 77 1.139 ad #include <sys/syscall.h> 78 1.139 ad #include <sys/syscallargs.h> 79 1.139 ad #include <sys/syscallvar.h> 80 1.1 cgd 81 1.181 riastrad #include <uvm/uvm_extern.h> 82 1.181 riastrad #include <uvm/uvm_loan.h> 83 1.181 riastrad #include <uvm/uvm_page.h> 84 1.40 mrg 85 1.23 fvdl #include <nfs/nfsproto.h> 86 1.15 mycroft #include <nfs/rpcv2.h> 87 1.10 mycroft #include <nfs/nfs.h> 88 1.10 mycroft #include <nfs/xdr_subs.h> 89 1.10 mycroft #include <nfs/nfsm_subs.h> 90 1.22 christos #include <nfs/nfs_var.h> 91 1.1 cgd 92 1.139 ad MODULE(MODULE_CLASS_MISC, nfsserver, "nfs"); 93 1.139 ad 94 1.1 cgd /* Global vars */ 95 1.19 cgd extern u_int32_t nfs_xdrneg1; 96 1.19 cgd extern u_int32_t nfs_false, nfs_true; 97 1.135 matt extern const enum vtype nv3tov_type[8]; 98 1.23 fvdl extern struct nfsstats nfsstats; 99 1.66 matt extern const nfstype nfsv2_type[9]; 100 1.66 matt extern const nfstype nfsv3_type[9]; 101 1.23 fvdl int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000; 102 1.141 pooka bool nfsd_use_loan = true; /* use page-loan for READ OP */ 103 1.1 cgd 104 1.121 yamt #define nqsrv_getl(vp, rw) /* nothing */ 105 1.121 yamt 106 1.139 ad static const struct syscall_package nfsserver_syscalls[] = { 107 1.139 ad { SYS_nfssvc, 0, (sy_call_t *)sys_nfssvc }, 108 1.139 ad { 0, 0, NULL }, 109 1.139 ad }; 110 1.139 ad 111 1.139 ad static int 112 1.139 ad nfsserver_modcmd(modcmd_t cmd, void *arg) 113 1.139 ad { 114 1.139 ad extern struct vfs_hooks nfs_export_hooks; /* XXX */ 115 1.139 ad int error; 116 1.139 ad 117 1.139 ad switch (cmd) { 118 1.139 ad case MODULE_CMD_INIT: 119 1.139 ad error = syscall_establish(NULL, nfsserver_syscalls); 120 1.139 ad if (error != 0) { 121 1.139 ad return error; 122 1.139 ad } 123 1.139 ad nfs_init(); /* XXX for monolithic kernel */ 124 1.146 ad netexport_init(); 125 1.145 ad nfsrv_initcache(); /* Init the server request cache */ 126 1.139 ad nfsrv_init(0); /* Init server data structures */ 127 1.139 ad vfs_hooks_attach(&nfs_export_hooks); 128 1.139 ad nfs_timer_srvinit(nfsrv_timer); 129 1.139 ad return 0; 130 1.139 ad case MODULE_CMD_FINI: 131 1.139 ad error = syscall_disestablish(NULL, nfsserver_syscalls); 132 1.139 ad if (error != 0) { 133 1.139 ad return error; 134 1.139 ad } 135 1.146 ad /* 136 1.146 ad * Kill export list before detaching VFS hooks, so we 137 1.146 ad * we don't leak state due to a concurrent umount(). 138 1.146 ad */ 139 1.146 ad netexport_fini(); 140 1.146 ad vfs_hooks_detach(&nfs_export_hooks); 141 1.146 ad 142 1.146 ad /* Kill timer before server goes away. */ 143 1.139 ad nfs_timer_srvfini(); 144 1.145 ad nfsrv_fini(); 145 1.146 ad 146 1.146 ad /* Server uses server cache, so kill cache last. */ 147 1.139 ad nfsrv_finicache(); 148 1.165 christos nfs_fini(); 149 1.139 ad return 0; 150 1.168 christos case MODULE_CMD_AUTOUNLOAD: 151 1.168 christos if (netexport_hasexports()) 152 1.168 christos return EBUSY; 153 1.168 christos /*FALLTHROUGH*/ 154 1.139 ad default: 155 1.139 ad return ENOTTY; 156 1.139 ad } 157 1.139 ad } 158 1.139 ad 159 1.15 mycroft /* 160 1.23 fvdl * nfs v3 access service 161 1.15 mycroft */ 162 1.22 christos int 163 1.143 dsl nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 164 1.15 mycroft { 165 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 166 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 167 1.126 christos char *dpos = nfsd->nd_dpos; 168 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 169 1.15 mycroft struct vnode *vp; 170 1.117 yamt nfsrvfh_t nsfh; 171 1.54 augustss u_int32_t *tl; 172 1.54 augustss int32_t t1; 173 1.126 christos char *bpos; 174 1.23 fvdl int error = 0, rdonly, cache = 0, getret; 175 1.15 mycroft char *cp2; 176 1.166 martin struct mbuf *mb, *mreq __unused; 177 1.23 fvdl struct vattr va; 178 1.32 mycroft u_long inmode, testmode, outmode; 179 1.15 mycroft u_quad_t frev; 180 1.15 mycroft 181 1.117 yamt nfsm_srvmtofh(&nsfh); 182 1.23 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 183 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, &rdonly, 184 1.125 thorpej (nfsd->nd_flag & ND_KERBAUTH), false); 185 1.23 fvdl if (error) { 186 1.23 fvdl nfsm_reply(NFSX_UNSIGNED); 187 1.23 fvdl nfsm_srvpostop_attr(1, (struct vattr *)0); 188 1.23 fvdl return (0); 189 1.23 fvdl } 190 1.32 mycroft inmode = fxdr_unsigned(u_int32_t, *tl); 191 1.32 mycroft outmode = 0; 192 1.32 mycroft if ((inmode & NFSV3ACCESS_READ) && 193 1.99 christos nfsrv_access(vp, VREAD, cred, rdonly, lwp, 0) == 0) 194 1.32 mycroft outmode |= NFSV3ACCESS_READ; 195 1.32 mycroft if (vp->v_type != VDIR) { 196 1.32 mycroft testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 197 1.32 mycroft if (testmode && 198 1.99 christos nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 0) == 0) 199 1.32 mycroft outmode |= testmode; 200 1.32 mycroft if ((inmode & NFSV3ACCESS_EXECUTE) && 201 1.99 christos nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0) == 0) 202 1.32 mycroft outmode |= NFSV3ACCESS_EXECUTE; 203 1.32 mycroft } else { 204 1.32 mycroft testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 205 1.32 mycroft NFSV3ACCESS_DELETE); 206 1.32 mycroft if (testmode && 207 1.99 christos nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 0) == 0) 208 1.32 mycroft outmode |= testmode; 209 1.32 mycroft if ((inmode & NFSV3ACCESS_LOOKUP) && 210 1.99 christos nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0) == 0) 211 1.32 mycroft outmode |= NFSV3ACCESS_LOOKUP; 212 1.32 mycroft } 213 1.131 pooka getret = VOP_GETATTR(vp, &va, cred); 214 1.15 mycroft vput(vp); 215 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); 216 1.23 fvdl nfsm_srvpostop_attr(getret, &va); 217 1.23 fvdl nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 218 1.32 mycroft *tl = txdr_unsigned(outmode); 219 1.15 mycroft nfsm_srvdone; 220 1.15 mycroft } 221 1.15 mycroft 222 1.1 cgd /* 223 1.1 cgd * nfs getattr service 224 1.1 cgd */ 225 1.22 christos int 226 1.143 dsl nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 227 1.1 cgd { 228 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 229 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 230 1.126 christos char *dpos = nfsd->nd_dpos; 231 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 232 1.54 augustss struct nfs_fattr *fp; 233 1.1 cgd struct vattr va; 234 1.1 cgd struct vnode *vp; 235 1.117 yamt nfsrvfh_t nsfh; 236 1.54 augustss u_int32_t *tl; 237 1.54 augustss int32_t t1; 238 1.126 christos char *bpos; 239 1.103 christos int error = 0, rdonly, cache = 0; 240 1.1 cgd char *cp2; 241 1.166 martin struct mbuf *mb, *mreq __unused; 242 1.15 mycroft u_quad_t frev; 243 1.1 cgd 244 1.117 yamt nfsm_srvmtofh(&nsfh); 245 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, &rdonly, 246 1.125 thorpej (nfsd->nd_flag & ND_KERBAUTH), false); 247 1.23 fvdl if (error) { 248 1.1 cgd nfsm_reply(0); 249 1.23 fvdl return (0); 250 1.23 fvdl } 251 1.23 fvdl nqsrv_getl(vp, ND_READ); 252 1.131 pooka error = VOP_GETATTR(vp, &va, cred); 253 1.1 cgd vput(vp); 254 1.23 fvdl nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 255 1.23 fvdl if (error) 256 1.23 fvdl return (0); 257 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 258 1.23 fvdl nfsm_srvfillattr(&va, fp); 259 1.1 cgd nfsm_srvdone; 260 1.1 cgd } 261 1.1 cgd 262 1.1 cgd /* 263 1.1 cgd * nfs setattr service 264 1.1 cgd */ 265 1.22 christos int 266 1.143 dsl nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 267 1.1 cgd { 268 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 269 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 270 1.126 christos char *dpos = nfsd->nd_dpos; 271 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 272 1.23 fvdl struct vattr va, preat; 273 1.54 augustss struct nfsv2_sattr *sp; 274 1.54 augustss struct nfs_fattr *fp; 275 1.1 cgd struct vnode *vp; 276 1.117 yamt nfsrvfh_t nsfh; 277 1.54 augustss u_int32_t *tl; 278 1.54 augustss int32_t t1; 279 1.126 christos char *bpos; 280 1.103 christos int error = 0, rdonly, cache = 0, preat_ret = 1, postat_ret = 1; 281 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0; 282 1.1 cgd char *cp2; 283 1.166 martin struct mbuf *mb, *mreq __unused; 284 1.23 fvdl u_quad_t frev; 285 1.23 fvdl struct timespec guard; 286 1.1 cgd 287 1.108 mrg memset(&guard, 0, sizeof guard); /* XXX gcc */ 288 1.108 mrg 289 1.117 yamt nfsm_srvmtofh(&nsfh); 290 1.150 pooka vattr_null(&va); 291 1.23 fvdl if (v3) { 292 1.127 yamt nfsm_srvsattr(&va); 293 1.23 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 294 1.23 fvdl gcheck = fxdr_unsigned(int, *tl); 295 1.23 fvdl if (gcheck) { 296 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 297 1.23 fvdl fxdr_nfsv3time(tl, &guard); 298 1.23 fvdl } 299 1.23 fvdl } else { 300 1.23 fvdl nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 301 1.23 fvdl /* 302 1.23 fvdl * Nah nah nah nah na nah 303 1.23 fvdl * There is a bug in the Sun client that puts 0xffff in the mode 304 1.23 fvdl * field of sattr when it should put in 0xffffffff. The u_short 305 1.23 fvdl * doesn't sign extend. 306 1.23 fvdl * --> check the low order 2 bytes for 0xffff 307 1.23 fvdl */ 308 1.23 fvdl if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 309 1.23 fvdl va.va_mode = nfstov_mode(sp->sa_mode); 310 1.23 fvdl if (sp->sa_uid != nfs_xdrneg1) 311 1.23 fvdl va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 312 1.23 fvdl if (sp->sa_gid != nfs_xdrneg1) 313 1.23 fvdl va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 314 1.23 fvdl if (sp->sa_size != nfs_xdrneg1) 315 1.23 fvdl va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size); 316 1.23 fvdl if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { 317 1.15 mycroft #ifdef notyet 318 1.23 fvdl fxdr_nfsv2time(&sp->sa_atime, &va.va_atime); 319 1.15 mycroft #else 320 1.20 jtc va.va_atime.tv_sec = 321 1.23 fvdl fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec); 322 1.20 jtc va.va_atime.tv_nsec = 0; 323 1.15 mycroft #endif 324 1.15 mycroft } 325 1.23 fvdl if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) 326 1.23 fvdl fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime); 327 1.23 fvdl 328 1.23 fvdl } 329 1.23 fvdl 330 1.23 fvdl /* 331 1.23 fvdl * Now that we have all the fields, lets do it. 332 1.23 fvdl */ 333 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, &rdonly, 334 1.125 thorpej (nfsd->nd_flag & ND_KERBAUTH), false); 335 1.23 fvdl if (error) { 336 1.23 fvdl nfsm_reply(2 * NFSX_UNSIGNED); 337 1.23 fvdl nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va); 338 1.23 fvdl return (0); 339 1.23 fvdl } 340 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 341 1.23 fvdl if (v3) { 342 1.131 pooka error = preat_ret = VOP_GETATTR(vp, &preat, cred); 343 1.23 fvdl if (!error && gcheck && 344 1.23 fvdl (preat.va_ctime.tv_sec != guard.tv_sec || 345 1.23 fvdl preat.va_ctime.tv_nsec != guard.tv_nsec)) 346 1.23 fvdl error = NFSERR_NOT_SYNC; 347 1.23 fvdl if (error) { 348 1.23 fvdl vput(vp); 349 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 350 1.23 fvdl nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va); 351 1.23 fvdl return (0); 352 1.23 fvdl } 353 1.15 mycroft } 354 1.15 mycroft 355 1.1 cgd /* 356 1.182 andvar * If the size is being changed write access is required, otherwise 357 1.15 mycroft * just check for a read only file system. 358 1.1 cgd */ 359 1.18 mycroft if (va.va_size == ((u_quad_t)((quad_t) -1))) { 360 1.15 mycroft if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 361 1.15 mycroft error = EROFS; 362 1.15 mycroft goto out; 363 1.15 mycroft } 364 1.15 mycroft } else { 365 1.15 mycroft if (vp->v_type == VDIR) { 366 1.15 mycroft error = EISDIR; 367 1.15 mycroft goto out; 368 1.22 christos } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, 369 1.99 christos lwp, 0)) != 0) 370 1.15 mycroft goto out; 371 1.1 cgd } 372 1.131 pooka error = VOP_SETATTR(vp, &va, cred); 373 1.131 pooka postat_ret = VOP_GETATTR(vp, &va, cred); 374 1.23 fvdl if (!error) 375 1.23 fvdl error = postat_ret; 376 1.1 cgd out: 377 1.1 cgd vput(vp); 378 1.23 fvdl nfsm_reply(NFSX_WCCORFATTR(v3)); 379 1.23 fvdl if (v3) { 380 1.23 fvdl nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va); 381 1.23 fvdl return (0); 382 1.23 fvdl } else { 383 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 384 1.23 fvdl nfsm_srvfillattr(&va, fp); 385 1.15 mycroft } 386 1.1 cgd nfsm_srvdone; 387 1.1 cgd } 388 1.1 cgd 389 1.1 cgd /* 390 1.1 cgd * nfs lookup rpc 391 1.1 cgd */ 392 1.22 christos int 393 1.143 dsl nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 394 1.1 cgd { 395 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 396 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 397 1.126 christos char *dpos = nfsd->nd_dpos; 398 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 399 1.54 augustss struct nfs_fattr *fp; 400 1.35 fvdl struct nameidata nd, ind, *ndp = &nd; 401 1.152 dholland struct pathbuf *ipb = NULL; 402 1.23 fvdl struct vnode *vp, *dirp; 403 1.117 yamt nfsrvfh_t nsfh; 404 1.126 christos char *cp; 405 1.54 augustss u_int32_t *tl; 406 1.54 augustss int32_t t1; 407 1.126 christos char *bpos; 408 1.103 christos int error = 0, cache = 0, dirattr_ret = 1; 409 1.68 yamt uint32_t len; 410 1.35 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag; 411 1.1 cgd char *cp2; 412 1.166 martin struct mbuf *mb, *mreq __unused; 413 1.23 fvdl struct vattr va, dirattr; 414 1.23 fvdl u_quad_t frev; 415 1.1 cgd 416 1.117 yamt nfsm_srvmtofh(&nsfh); 417 1.23 fvdl nfsm_srvnamesiz(len); 418 1.35 fvdl 419 1.117 yamt pubflag = nfs_ispublicfh(&nsfh); 420 1.35 fvdl 421 1.15 mycroft nd.ni_cnd.cn_cred = cred; 422 1.15 mycroft nd.ni_cnd.cn_nameiop = LOOKUP; 423 1.155 dholland nd.ni_cnd.cn_flags = LOCKLEAF; 424 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 425 1.183 hannken &dirp, NULL, NULL, 426 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), pubflag); 427 1.35 fvdl 428 1.35 fvdl if (!error && pubflag) { 429 1.152 dholland if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL && 430 1.152 dholland (ipb = pathbuf_create(nfs_pub.np_index)) != NULL) { 431 1.35 fvdl /* 432 1.35 fvdl * Setup call to lookup() to see if we can find 433 1.35 fvdl * the index file. Arguably, this doesn't belong 434 1.35 fvdl * in a kernel.. Ugh. 435 1.35 fvdl */ 436 1.35 fvdl ind = nd; 437 1.151 hannken VOP_UNLOCK(nd.ni_vp); 438 1.152 dholland ind.ni_pathbuf = ipb; 439 1.153 dholland 440 1.153 dholland error = lookup_for_nfsd_index(&ind, nd.ni_vp); 441 1.35 fvdl if (!error) { 442 1.35 fvdl /* 443 1.35 fvdl * Found an index file. Get rid of 444 1.35 fvdl * the old references. 445 1.35 fvdl */ 446 1.94 perry if (dirp) 447 1.35 fvdl vrele(dirp); 448 1.35 fvdl dirp = nd.ni_vp; 449 1.35 fvdl ndp = &ind; 450 1.35 fvdl } else 451 1.35 fvdl error = 0; 452 1.35 fvdl } 453 1.35 fvdl /* 454 1.35 fvdl * If the public filehandle was used, check that this lookup 455 1.35 fvdl * didn't result in a filehandle outside the publicly exported 456 1.35 fvdl * filesystem. 457 1.35 fvdl */ 458 1.35 fvdl 459 1.35 fvdl if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) { 460 1.35 fvdl vput(nd.ni_vp); 461 1.35 fvdl error = EPERM; 462 1.35 fvdl } 463 1.35 fvdl } 464 1.35 fvdl 465 1.23 fvdl if (error) { 466 1.157 dholland if (nd.ni_pathbuf != NULL) { 467 1.157 dholland pathbuf_destroy(nd.ni_pathbuf); 468 1.157 dholland } 469 1.157 dholland if (ipb != NULL) { 470 1.157 dholland pathbuf_destroy(ipb); 471 1.157 dholland } 472 1.162 hannken if (dirp) { 473 1.162 hannken if (v3) { 474 1.162 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 475 1.162 hannken dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred); 476 1.162 hannken vput(dirp); 477 1.162 hannken } else 478 1.162 hannken vrele(dirp); 479 1.162 hannken } 480 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3)); 481 1.23 fvdl nfsm_srvpostop_attr(dirattr_ret, &dirattr); 482 1.23 fvdl return (0); 483 1.23 fvdl } 484 1.35 fvdl 485 1.35 fvdl nqsrv_getl(ndp->ni_startdir, ND_READ); 486 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 487 1.152 dholland if (ipb != NULL) { 488 1.152 dholland pathbuf_destroy(ipb); 489 1.152 dholland } 490 1.35 fvdl vp = ndp->ni_vp; 491 1.117 yamt error = nfsrv_composefh(vp, &nsfh, v3); 492 1.23 fvdl if (!error) 493 1.131 pooka error = VOP_GETATTR(vp, &va, cred); 494 1.23 fvdl vput(vp); 495 1.162 hannken if (dirp) { 496 1.162 hannken if (v3) { 497 1.162 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 498 1.162 hannken dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred); 499 1.162 hannken vput(dirp); 500 1.162 hannken } else 501 1.162 hannken vrele(dirp); 502 1.162 hannken } 503 1.117 yamt nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPORFATTR(v3) + 504 1.117 yamt NFSX_POSTOPATTR(v3)); 505 1.23 fvdl if (error) { 506 1.23 fvdl nfsm_srvpostop_attr(dirattr_ret, &dirattr); 507 1.23 fvdl return (0); 508 1.1 cgd } 509 1.117 yamt nfsm_srvfhtom(&nsfh, v3); 510 1.23 fvdl if (v3) { 511 1.23 fvdl nfsm_srvpostop_attr(0, &va); 512 1.23 fvdl nfsm_srvpostop_attr(dirattr_ret, &dirattr); 513 1.23 fvdl } else { 514 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 515 1.23 fvdl nfsm_srvfillattr(&va, fp); 516 1.15 mycroft } 517 1.1 cgd nfsm_srvdone; 518 1.1 cgd } 519 1.1 cgd 520 1.1 cgd /* 521 1.1 cgd * nfs readlink service 522 1.1 cgd */ 523 1.22 christos int 524 1.143 dsl nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 525 1.1 cgd { 526 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 527 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 528 1.126 christos char *dpos = nfsd->nd_dpos; 529 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 530 1.1 cgd struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 531 1.54 augustss struct iovec *ivp = iv; 532 1.54 augustss struct mbuf *mp; 533 1.54 augustss u_int32_t *tl; 534 1.54 augustss int32_t t1; 535 1.126 christos char *bpos; 536 1.103 christos int error = 0, rdonly, cache = 0, i, padlen, getret; 537 1.76 yamt uint32_t len; 538 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 539 1.1 cgd char *cp2; 540 1.166 martin struct mbuf *mb, *mp2 = NULL, *mp3 = NULL, *mreq __unused; 541 1.1 cgd struct vnode *vp; 542 1.23 fvdl struct vattr attr; 543 1.117 yamt nfsrvfh_t nsfh; 544 1.1 cgd struct uio io, *uiop = &io; 545 1.15 mycroft u_quad_t frev; 546 1.1 cgd 547 1.117 yamt nfsm_srvmtofh(&nsfh); 548 1.1 cgd len = 0; 549 1.1 cgd i = 0; 550 1.1 cgd while (len < NFS_MAXPATHLEN) { 551 1.67 matt mp = m_get(M_WAIT, MT_DATA); 552 1.67 matt MCLAIM(mp, &nfs_mowner); 553 1.67 matt m_clget(mp, M_WAIT); 554 1.1 cgd mp->m_len = NFSMSIZ(mp); 555 1.1 cgd if (len == 0) 556 1.1 cgd mp3 = mp2 = mp; 557 1.1 cgd else { 558 1.1 cgd mp2->m_next = mp; 559 1.1 cgd mp2 = mp; 560 1.1 cgd } 561 1.1 cgd if ((len+mp->m_len) > NFS_MAXPATHLEN) { 562 1.1 cgd mp->m_len = NFS_MAXPATHLEN-len; 563 1.1 cgd len = NFS_MAXPATHLEN; 564 1.1 cgd } else 565 1.1 cgd len += mp->m_len; 566 1.126 christos ivp->iov_base = mtod(mp, void *); 567 1.1 cgd ivp->iov_len = mp->m_len; 568 1.1 cgd i++; 569 1.1 cgd ivp++; 570 1.1 cgd } 571 1.1 cgd uiop->uio_iov = iv; 572 1.1 cgd uiop->uio_iovcnt = i; 573 1.1 cgd uiop->uio_offset = 0; 574 1.1 cgd uiop->uio_resid = len; 575 1.1 cgd uiop->uio_rw = UIO_READ; 576 1.101 yamt UIO_SETUP_SYSSPACE(uiop); 577 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 578 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 579 1.22 christos if (error) { 580 1.1 cgd m_freem(mp3); 581 1.23 fvdl nfsm_reply(2 * NFSX_UNSIGNED); 582 1.23 fvdl nfsm_srvpostop_attr(1, (struct vattr *)0); 583 1.23 fvdl return (0); 584 1.1 cgd } 585 1.1 cgd if (vp->v_type != VLNK) { 586 1.23 fvdl if (v3) 587 1.23 fvdl error = EINVAL; 588 1.23 fvdl else 589 1.23 fvdl error = ENXIO; 590 1.1 cgd goto out; 591 1.1 cgd } 592 1.23 fvdl nqsrv_getl(vp, ND_READ); 593 1.1 cgd error = VOP_READLINK(vp, uiop, cred); 594 1.1 cgd out: 595 1.131 pooka getret = VOP_GETATTR(vp, &attr, cred); 596 1.1 cgd vput(vp); 597 1.1 cgd if (error) 598 1.1 cgd m_freem(mp3); 599 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); 600 1.23 fvdl if (v3) { 601 1.23 fvdl nfsm_srvpostop_attr(getret, &attr); 602 1.23 fvdl if (error) 603 1.23 fvdl return (0); 604 1.23 fvdl } 605 1.76 yamt len -= uiop->uio_resid; 606 1.76 yamt padlen = nfsm_padlen(len); 607 1.174 hannken if (len == 0) { 608 1.174 hannken m_freem(mp3); 609 1.174 hannken mp3 = NULL; 610 1.174 hannken } else if (uiop->uio_resid || padlen) 611 1.76 yamt nfs_zeropad(mp3, uiop->uio_resid, padlen); 612 1.19 cgd nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 613 1.1 cgd *tl = txdr_unsigned(len); 614 1.1 cgd mb->m_next = mp3; 615 1.1 cgd nfsm_srvdone; 616 1.1 cgd } 617 1.1 cgd 618 1.1 cgd /* 619 1.1 cgd * nfs read service 620 1.1 cgd */ 621 1.22 christos int 622 1.143 dsl nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 623 1.1 cgd { 624 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 625 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 626 1.126 christos char *dpos = nfsd->nd_dpos; 627 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 628 1.54 augustss struct mbuf *m; 629 1.54 augustss struct nfs_fattr *fp; 630 1.54 augustss u_int32_t *tl; 631 1.54 augustss int32_t t1; 632 1.54 augustss int i; 633 1.126 christos char *bpos; 634 1.103 christos int error = 0, rdonly, cache = 0, getret; 635 1.68 yamt int v3 = (nfsd->nd_flag & ND_NFSV3); 636 1.76 yamt uint32_t reqlen, len, cnt, left; 637 1.76 yamt int padlen; 638 1.1 cgd char *cp2; 639 1.67 matt struct mbuf *mb, *mreq; 640 1.1 cgd struct vnode *vp; 641 1.117 yamt nfsrvfh_t nsfh; 642 1.1 cgd struct uio io, *uiop = &io; 643 1.18 mycroft struct vattr va; 644 1.1 cgd off_t off; 645 1.15 mycroft u_quad_t frev; 646 1.1 cgd 647 1.117 yamt nfsm_srvmtofh(&nsfh); 648 1.23 fvdl if (v3) { 649 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 650 1.48 fair off = fxdr_hyper(tl); 651 1.23 fvdl } else { 652 1.19 cgd nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 653 1.19 cgd off = (off_t)fxdr_unsigned(u_int32_t, *tl); 654 1.15 mycroft } 655 1.71 yamt nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED); 656 1.71 yamt reqlen = fxdr_unsigned(uint32_t, *tl); 657 1.71 yamt reqlen = MIN(reqlen, NFS_SRVMAXDATA(nfsd)); 658 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 659 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 660 1.23 fvdl if (error) { 661 1.23 fvdl nfsm_reply(2 * NFSX_UNSIGNED); 662 1.23 fvdl nfsm_srvpostop_attr(1, (struct vattr *)0); 663 1.23 fvdl return (0); 664 1.23 fvdl } 665 1.15 mycroft if (vp->v_type != VREG) { 666 1.23 fvdl if (v3) 667 1.23 fvdl error = EINVAL; 668 1.23 fvdl else 669 1.23 fvdl error = (vp->v_type == VDIR) ? EISDIR : EACCES; 670 1.1 cgd } 671 1.23 fvdl if (!error) { 672 1.23 fvdl nqsrv_getl(vp, ND_READ); 673 1.99 christos if ((error = nfsrv_access(vp, VREAD, cred, rdonly, lwp, 1)) != 0) 674 1.99 christos error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 1); 675 1.23 fvdl } 676 1.131 pooka getret = VOP_GETATTR(vp, &va, cred); 677 1.23 fvdl if (!error) 678 1.23 fvdl error = getret; 679 1.22 christos if (error) { 680 1.1 cgd vput(vp); 681 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3)); 682 1.23 fvdl nfsm_srvpostop_attr(getret, &va); 683 1.23 fvdl return (0); 684 1.1 cgd } 685 1.18 mycroft if (off >= va.va_size) 686 1.15 mycroft cnt = 0; 687 1.23 fvdl else if ((off + reqlen) > va.va_size) 688 1.76 yamt cnt = va.va_size - off; 689 1.23 fvdl else 690 1.23 fvdl cnt = reqlen; 691 1.23 fvdl nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); 692 1.23 fvdl if (v3) { 693 1.23 fvdl nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); 694 1.23 fvdl *tl++ = nfs_true; 695 1.23 fvdl fp = (struct nfs_fattr *)tl; 696 1.23 fvdl tl += (NFSX_V3FATTR / sizeof (u_int32_t)); 697 1.23 fvdl } else { 698 1.23 fvdl nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED); 699 1.23 fvdl fp = (struct nfs_fattr *)tl; 700 1.23 fvdl tl += (NFSX_V2FATTR / sizeof (u_int32_t)); 701 1.23 fvdl } 702 1.15 mycroft len = left = cnt; 703 1.73 yamt if (cnt > 0) { 704 1.72 yamt if (nfsd_use_loan) { 705 1.72 yamt struct vm_page **pgpp; 706 1.72 yamt voff_t pgoff = trunc_page(off); 707 1.87 yamt int npages; 708 1.87 yamt vaddr_t lva; 709 1.72 yamt 710 1.87 yamt npages = (round_page(off + cnt) - pgoff) >> PAGE_SHIFT; 711 1.87 yamt KASSERT(npages <= M_EXT_MAXPAGES); /* XXX */ 712 1.72 yamt 713 1.87 yamt /* allocate kva for mbuf data */ 714 1.163 matt lva = sokvaalloc(pgoff, npages << PAGE_SHIFT, 715 1.163 matt slp->ns_so); 716 1.72 yamt if (lva == 0) { 717 1.72 yamt /* fall back to VOP_READ */ 718 1.72 yamt goto loan_fail; 719 1.72 yamt } 720 1.72 yamt 721 1.87 yamt /* allocate mbuf */ 722 1.72 yamt m = m_get(M_WAIT, MT_DATA); 723 1.87 yamt MCLAIM(m, &nfs_mowner); 724 1.72 yamt pgpp = m->m_ext.ext_pgs; 725 1.75 yamt 726 1.87 yamt /* loan pages */ 727 1.87 yamt error = uvm_loanuobjpages(&vp->v_uobj, pgoff, npages, 728 1.87 yamt pgpp); 729 1.87 yamt if (error) { 730 1.87 yamt sokvafree(lva, npages << PAGE_SHIFT); 731 1.87 yamt m_free(m); 732 1.91 yamt if (error == EBUSY) 733 1.91 yamt goto loan_fail; 734 1.87 yamt goto read_error; 735 1.15 mycroft } 736 1.72 yamt 737 1.87 yamt /* associate kva to mbuf */ 738 1.87 yamt MEXTADD(m, (void *)(lva + ((vaddr_t)off & PAGE_MASK)), 739 1.87 yamt cnt, M_MBUF, soloanfree, slp->ns_so); 740 1.72 yamt m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP; 741 1.72 yamt m->m_len = cnt; 742 1.72 yamt 743 1.87 yamt /* map pages */ 744 1.87 yamt for (i = 0; i < npages; i++) { 745 1.87 yamt pmap_kenter_pa(lva, VM_PAGE_TO_PHYS(pgpp[i]), 746 1.148 cegger VM_PROT_READ, 0); 747 1.87 yamt lva += PAGE_SIZE; 748 1.87 yamt } 749 1.87 yamt 750 1.72 yamt pmap_update(pmap_kernel()); 751 1.87 yamt 752 1.72 yamt mb->m_next = m; 753 1.72 yamt mb = m; 754 1.72 yamt error = 0; 755 1.72 yamt uiop->uio_resid = 0; 756 1.72 yamt } else { 757 1.72 yamt struct iovec *iv; 758 1.72 yamt struct iovec *iv2; 759 1.72 yamt struct mbuf *m2; 760 1.72 yamt int siz; 761 1.72 yamt loan_fail: 762 1.72 yamt /* 763 1.72 yamt * Generate the mbuf list with the uio_iov ref. to it. 764 1.72 yamt */ 765 1.72 yamt i = 0; 766 1.72 yamt m = m2 = mb; 767 1.72 yamt while (left > 0) { 768 1.175 riastrad siz = uimin(M_TRAILINGSPACE(m), left); 769 1.72 yamt if (siz > 0) { 770 1.72 yamt left -= siz; 771 1.72 yamt i++; 772 1.72 yamt } 773 1.72 yamt if (left > 0) { 774 1.72 yamt m = m_get(M_WAIT, MT_DATA); 775 1.72 yamt MCLAIM(m, &nfs_mowner); 776 1.72 yamt m_clget(m, M_WAIT); 777 1.72 yamt m->m_len = 0; 778 1.72 yamt m2->m_next = m; 779 1.72 yamt m2 = m; 780 1.72 yamt } 781 1.72 yamt } 782 1.72 yamt iv = malloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK); 783 1.72 yamt uiop->uio_iov = iv2 = iv; 784 1.72 yamt m = mb; 785 1.72 yamt left = cnt; 786 1.72 yamt i = 0; 787 1.72 yamt while (left > 0) { 788 1.72 yamt if (m == NULL) 789 1.72 yamt panic("nfsrv_read iov"); 790 1.175 riastrad siz = uimin(M_TRAILINGSPACE(m), left); 791 1.72 yamt if (siz > 0) { 792 1.126 christos iv->iov_base = mtod(m, char *) + 793 1.72 yamt m->m_len; 794 1.72 yamt iv->iov_len = siz; 795 1.72 yamt m->m_len += siz; 796 1.72 yamt left -= siz; 797 1.72 yamt iv++; 798 1.72 yamt i++; 799 1.72 yamt } 800 1.72 yamt m = m->m_next; 801 1.23 fvdl } 802 1.72 yamt uiop->uio_iovcnt = i; 803 1.72 yamt uiop->uio_offset = off; 804 1.72 yamt uiop->uio_resid = cnt; 805 1.72 yamt uiop->uio_rw = UIO_READ; 806 1.101 yamt UIO_SETUP_SYSSPACE(uiop); 807 1.72 yamt error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 808 1.126 christos free((void *)iv2, M_TEMP); 809 1.23 fvdl } 810 1.72 yamt read_error: 811 1.131 pooka if (error || (getret = VOP_GETATTR(vp, &va, cred)) != 0){ 812 1.23 fvdl if (!error) 813 1.23 fvdl error = getret; 814 1.15 mycroft m_freem(mreq); 815 1.15 mycroft vput(vp); 816 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3)); 817 1.23 fvdl nfsm_srvpostop_attr(getret, &va); 818 1.23 fvdl return (0); 819 1.15 mycroft } 820 1.72 yamt } else { 821 1.15 mycroft uiop->uio_resid = 0; 822 1.72 yamt } 823 1.1 cgd vput(vp); 824 1.23 fvdl nfsm_srvfillattr(&va, fp); 825 1.1 cgd len -= uiop->uio_resid; 826 1.76 yamt padlen = nfsm_padlen(len); 827 1.76 yamt if (uiop->uio_resid || padlen) 828 1.76 yamt nfs_zeropad(mb, uiop->uio_resid, padlen); 829 1.23 fvdl if (v3) { 830 1.83 yamt /* count */ 831 1.23 fvdl *tl++ = txdr_unsigned(len); 832 1.83 yamt /* eof */ 833 1.83 yamt if (off + len >= va.va_size) 834 1.23 fvdl *tl++ = nfs_true; 835 1.23 fvdl else 836 1.23 fvdl *tl++ = nfs_false; 837 1.23 fvdl } 838 1.1 cgd *tl = txdr_unsigned(len); 839 1.1 cgd nfsm_srvdone; 840 1.1 cgd } 841 1.1 cgd 842 1.1 cgd /* 843 1.1 cgd * nfs write service 844 1.1 cgd */ 845 1.22 christos int 846 1.143 dsl nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 847 1.1 cgd { 848 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 849 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 850 1.126 christos char *dpos = nfsd->nd_dpos; 851 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 852 1.54 augustss struct iovec *ivp; 853 1.54 augustss int i, cnt; 854 1.54 augustss struct mbuf *mp; 855 1.54 augustss struct nfs_fattr *fp; 856 1.23 fvdl struct iovec *iv; 857 1.23 fvdl struct vattr va, forat; 858 1.54 augustss u_int32_t *tl; 859 1.54 augustss int32_t t1; 860 1.126 christos char *bpos; 861 1.103 christos int error = 0, rdonly, cache = 0, len, forat_ret = 1; 862 1.23 fvdl int ioflags, aftat_ret = 1, retlen, zeroing, adjust; 863 1.23 fvdl int stable = NFSV3WRITE_FILESYNC; 864 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 865 1.1 cgd char *cp2; 866 1.166 martin struct mbuf *mb, *mreq __unused; 867 1.1 cgd struct vnode *vp; 868 1.117 yamt nfsrvfh_t nsfh; 869 1.1 cgd struct uio io, *uiop = &io; 870 1.1 cgd off_t off; 871 1.15 mycroft u_quad_t frev; 872 1.1 cgd 873 1.23 fvdl if (mrep == NULL) { 874 1.23 fvdl *mrq = NULL; 875 1.23 fvdl return (0); 876 1.23 fvdl } 877 1.117 yamt nfsm_srvmtofh(&nsfh); 878 1.23 fvdl if (v3) { 879 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 880 1.48 fair off = fxdr_hyper(tl); 881 1.23 fvdl tl += 3; 882 1.23 fvdl stable = fxdr_unsigned(int, *tl++); 883 1.23 fvdl } else { 884 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 885 1.19 cgd off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 886 1.15 mycroft tl += 2; 887 1.15 mycroft } 888 1.23 fvdl retlen = len = fxdr_unsigned(int32_t, *tl); 889 1.23 fvdl cnt = i = 0; 890 1.23 fvdl 891 1.23 fvdl /* 892 1.23 fvdl * For NFS Version 2, it is not obvious what a write of zero length 893 1.23 fvdl * should do, but I might as well be consistent with Version 3, 894 1.23 fvdl * which is to return ok so long as there are no permission problems. 895 1.23 fvdl */ 896 1.23 fvdl if (len > 0) { 897 1.74 yamt zeroing = 1; 898 1.74 yamt mp = mrep; 899 1.74 yamt while (mp) { 900 1.74 yamt if (mp == md) { 901 1.74 yamt zeroing = 0; 902 1.126 christos adjust = dpos - mtod(mp, char *); 903 1.74 yamt mp->m_len -= adjust; 904 1.74 yamt if (mp->m_len > 0 && adjust > 0) 905 1.74 yamt NFSMADV(mp, adjust); 906 1.23 fvdl } 907 1.74 yamt if (zeroing) 908 1.74 yamt mp->m_len = 0; 909 1.74 yamt else if (mp->m_len > 0) { 910 1.74 yamt i += mp->m_len; 911 1.74 yamt if (i > len) { 912 1.74 yamt mp->m_len -= (i - len); 913 1.74 yamt zeroing = 1; 914 1.74 yamt } 915 1.74 yamt if (mp->m_len > 0) 916 1.74 yamt cnt++; 917 1.74 yamt } 918 1.74 yamt mp = mp->m_next; 919 1.23 fvdl } 920 1.23 fvdl } 921 1.23 fvdl if (len > NFS_MAXDATA || len < 0 || i < len) { 922 1.23 fvdl error = EIO; 923 1.23 fvdl nfsm_reply(2 * NFSX_UNSIGNED); 924 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 925 1.23 fvdl return (0); 926 1.1 cgd } 927 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 928 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 929 1.23 fvdl if (error) { 930 1.23 fvdl nfsm_reply(2 * NFSX_UNSIGNED); 931 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 932 1.23 fvdl return (0); 933 1.1 cgd } 934 1.23 fvdl if (v3) 935 1.131 pooka forat_ret = VOP_GETATTR(vp, &forat, cred); 936 1.15 mycroft if (vp->v_type != VREG) { 937 1.23 fvdl if (v3) 938 1.23 fvdl error = EINVAL; 939 1.23 fvdl else 940 1.23 fvdl error = (vp->v_type == VDIR) ? EISDIR : EACCES; 941 1.23 fvdl } 942 1.23 fvdl if (!error) { 943 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 944 1.99 christos error = nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 1); 945 1.15 mycroft } 946 1.22 christos if (error) { 947 1.1 cgd vput(vp); 948 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 949 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 950 1.23 fvdl return (0); 951 1.23 fvdl } 952 1.23 fvdl 953 1.23 fvdl if (len > 0) { 954 1.74 yamt ivp = malloc(cnt * sizeof (struct iovec), M_TEMP, M_WAITOK); 955 1.74 yamt uiop->uio_iov = iv = ivp; 956 1.74 yamt uiop->uio_iovcnt = cnt; 957 1.74 yamt mp = mrep; 958 1.74 yamt while (mp) { 959 1.74 yamt if (mp->m_len > 0) { 960 1.126 christos ivp->iov_base = mtod(mp, void *); 961 1.74 yamt ivp->iov_len = mp->m_len; 962 1.74 yamt ivp++; 963 1.74 yamt } 964 1.74 yamt mp = mp->m_next; 965 1.74 yamt } 966 1.74 yamt 967 1.74 yamt /* 968 1.74 yamt * XXX 969 1.74 yamt * The IO_METASYNC flag indicates that all metadata (and not 970 1.74 yamt * just enough to ensure data integrity) must be written to 971 1.74 yamt * stable storage synchronously. 972 1.74 yamt * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.) 973 1.74 yamt */ 974 1.74 yamt if (stable == NFSV3WRITE_UNSTABLE) 975 1.74 yamt ioflags = IO_NODELOCKED; 976 1.74 yamt else if (stable == NFSV3WRITE_DATASYNC) 977 1.74 yamt ioflags = (IO_SYNC | IO_NODELOCKED); 978 1.74 yamt else 979 1.74 yamt ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); 980 1.74 yamt uiop->uio_resid = len; 981 1.74 yamt uiop->uio_rw = UIO_WRITE; 982 1.74 yamt uiop->uio_offset = off; 983 1.101 yamt UIO_SETUP_SYSSPACE(uiop); 984 1.74 yamt error = VOP_WRITE(vp, uiop, ioflags, cred); 985 1.74 yamt nfsstats.srvvop_writes++; 986 1.74 yamt free(iv, M_TEMP); 987 1.23 fvdl } 988 1.131 pooka aftat_ret = VOP_GETATTR(vp, &va, cred); 989 1.23 fvdl vput(vp); 990 1.23 fvdl if (!error) 991 1.23 fvdl error = aftat_ret; 992 1.23 fvdl nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + 993 1.23 fvdl 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3)); 994 1.23 fvdl if (v3) { 995 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 996 1.23 fvdl if (error) 997 1.23 fvdl return (0); 998 1.23 fvdl nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 999 1.23 fvdl *tl++ = txdr_unsigned(retlen); 1000 1.23 fvdl if (stable == NFSV3WRITE_UNSTABLE) 1001 1.23 fvdl *tl++ = txdr_unsigned(stable); 1002 1.23 fvdl else 1003 1.23 fvdl *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); 1004 1.23 fvdl /* 1005 1.23 fvdl * Actually, there is no need to txdr these fields, 1006 1.23 fvdl * but it may make the values more human readable, 1007 1.23 fvdl * for debugging purposes. 1008 1.23 fvdl */ 1009 1.178 thorpej struct timeval btv; 1010 1.178 thorpej getmicroboottime(&btv); 1011 1.178 thorpej *tl++ = txdr_unsigned(btv.tv_sec); 1012 1.178 thorpej *tl = txdr_unsigned(btv.tv_usec); 1013 1.23 fvdl } else { 1014 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 1015 1.23 fvdl nfsm_srvfillattr(&va, fp); 1016 1.23 fvdl } 1017 1.23 fvdl nfsm_srvdone; 1018 1.23 fvdl } 1019 1.23 fvdl 1020 1.23 fvdl /* 1021 1.109 elad * XXX elad: the original NFSW_SAMECRED() macro also made sure the 1022 1.109 elad * two nd_flag fields of the descriptors contained 1023 1.109 elad * ND_KERBAUTH. 1024 1.109 elad */ 1025 1.109 elad static int 1026 1.109 elad nfsrv_samecred(kauth_cred_t cred1, kauth_cred_t cred2) 1027 1.109 elad { 1028 1.109 elad int i, do_ngroups; 1029 1.109 elad 1030 1.109 elad if (kauth_cred_geteuid(cred1) != kauth_cred_geteuid(cred2)) 1031 1.109 elad return (0); 1032 1.109 elad if (kauth_cred_ngroups(cred1) != kauth_cred_ngroups(cred2)) 1033 1.109 elad return (0); 1034 1.109 elad do_ngroups = kauth_cred_ngroups(cred1); 1035 1.109 elad for (i = 0; i < do_ngroups; i++) 1036 1.109 elad if (kauth_cred_group(cred1, i) != 1037 1.109 elad kauth_cred_group(cred2, i)) 1038 1.109 elad return (0); 1039 1.109 elad 1040 1.109 elad return (1); 1041 1.109 elad } 1042 1.109 elad 1043 1.117 yamt static struct nfsrvw_delayhash * 1044 1.117 yamt nfsrv_nwdelayhash(struct nfssvc_sock *slp, const nfsrvfh_t *nsfh) 1045 1.117 yamt { 1046 1.117 yamt uint32_t hash; 1047 1.117 yamt 1048 1.117 yamt hash = hash32_buf(NFSRVFH_DATA(nsfh), NFSRVFH_SIZE(nsfh), 1049 1.117 yamt HASH32_BUF_INIT); 1050 1.117 yamt return &slp->ns_wdelayhashtbl[hash % NFS_WDELAYHASHSIZ]; 1051 1.117 yamt } 1052 1.117 yamt 1053 1.109 elad /* 1054 1.23 fvdl * NFS write service with write gathering support. Called when 1055 1.23 fvdl * nfsrvw_procrastinate > 0. 1056 1.23 fvdl * See: Chet Juszczak, "Improving the Write Performance of an NFS Server", 1057 1.23 fvdl * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco, 1058 1.23 fvdl * Jan. 1994. 1059 1.23 fvdl */ 1060 1.23 fvdl int 1061 1.143 dsl nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 1062 1.23 fvdl { 1063 1.110 kardel struct timeval now; 1064 1.54 augustss struct iovec *ivp; 1065 1.54 augustss struct mbuf *mp; 1066 1.54 augustss struct nfsrv_descript *wp, *nfsd, *owp, *swp; 1067 1.54 augustss struct nfs_fattr *fp; 1068 1.54 augustss int i = 0; 1069 1.23 fvdl struct iovec *iov; 1070 1.23 fvdl struct nfsrvw_delayhash *wpp; 1071 1.109 elad kauth_cred_t cred; 1072 1.23 fvdl struct vattr va, forat; 1073 1.54 augustss u_int32_t *tl; 1074 1.54 augustss int32_t t1; 1075 1.126 christos char *bpos, *dpos; 1076 1.103 christos int error = 0, rdonly, cache = 0, len = 0, forat_ret = 1; 1077 1.132 yamt int ioflags, aftat_ret = 1, adjust, v3, zeroing; 1078 1.23 fvdl char *cp2; 1079 1.67 matt struct mbuf *mb, *mreq, *mrep, *md; 1080 1.23 fvdl struct vnode *vp; 1081 1.23 fvdl struct uio io, *uiop = &io; 1082 1.23 fvdl u_quad_t frev, cur_usec; 1083 1.23 fvdl 1084 1.23 fvdl *mrq = NULL; 1085 1.23 fvdl if (*ndp) { 1086 1.23 fvdl nfsd = *ndp; 1087 1.23 fvdl *ndp = NULL; 1088 1.23 fvdl mrep = nfsd->nd_mrep; 1089 1.23 fvdl md = nfsd->nd_md; 1090 1.23 fvdl dpos = nfsd->nd_dpos; 1091 1.109 elad cred = nfsd->nd_cr; 1092 1.23 fvdl v3 = (nfsd->nd_flag & ND_NFSV3); 1093 1.23 fvdl LIST_INIT(&nfsd->nd_coalesce); 1094 1.23 fvdl nfsd->nd_mreq = NULL; 1095 1.23 fvdl nfsd->nd_stable = NFSV3WRITE_FILESYNC; 1096 1.110 kardel getmicrotime(&now); 1097 1.110 kardel cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec; 1098 1.23 fvdl nfsd->nd_time = cur_usec + nfsrvw_procrastinate; 1099 1.94 perry 1100 1.23 fvdl /* 1101 1.23 fvdl * Now, get the write header.. 1102 1.23 fvdl */ 1103 1.23 fvdl nfsm_srvmtofh(&nfsd->nd_fh); 1104 1.23 fvdl if (v3) { 1105 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1106 1.48 fair nfsd->nd_off = fxdr_hyper(tl); 1107 1.23 fvdl tl += 3; 1108 1.23 fvdl nfsd->nd_stable = fxdr_unsigned(int, *tl++); 1109 1.23 fvdl } else { 1110 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1111 1.23 fvdl nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 1112 1.23 fvdl tl += 2; 1113 1.23 fvdl } 1114 1.23 fvdl len = fxdr_unsigned(int32_t, *tl); 1115 1.23 fvdl nfsd->nd_len = len; 1116 1.23 fvdl nfsd->nd_eoff = nfsd->nd_off + len; 1117 1.94 perry 1118 1.23 fvdl /* 1119 1.23 fvdl * Trim the header out of the mbuf list and trim off any trailing 1120 1.23 fvdl * junk so that the mbuf list has only the write data. 1121 1.23 fvdl */ 1122 1.23 fvdl zeroing = 1; 1123 1.23 fvdl i = 0; 1124 1.23 fvdl mp = mrep; 1125 1.23 fvdl while (mp) { 1126 1.23 fvdl if (mp == md) { 1127 1.23 fvdl zeroing = 0; 1128 1.126 christos adjust = dpos - mtod(mp, char *); 1129 1.23 fvdl mp->m_len -= adjust; 1130 1.23 fvdl if (mp->m_len > 0 && adjust > 0) 1131 1.23 fvdl NFSMADV(mp, adjust); 1132 1.23 fvdl } 1133 1.23 fvdl if (zeroing) 1134 1.23 fvdl mp->m_len = 0; 1135 1.23 fvdl else { 1136 1.23 fvdl i += mp->m_len; 1137 1.23 fvdl if (i > len) { 1138 1.23 fvdl mp->m_len -= (i - len); 1139 1.23 fvdl zeroing = 1; 1140 1.23 fvdl } 1141 1.23 fvdl } 1142 1.23 fvdl mp = mp->m_next; 1143 1.23 fvdl } 1144 1.23 fvdl if (len > NFS_MAXDATA || len < 0 || i < len) { 1145 1.23 fvdl nfsmout: 1146 1.23 fvdl m_freem(mrep); 1147 1.23 fvdl error = EIO; 1148 1.23 fvdl nfsm_writereply(2 * NFSX_UNSIGNED, v3); 1149 1.23 fvdl if (v3) 1150 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 1151 1.23 fvdl nfsd->nd_mreq = mreq; 1152 1.23 fvdl nfsd->nd_mrep = NULL; 1153 1.23 fvdl nfsd->nd_time = 0; 1154 1.23 fvdl } 1155 1.94 perry 1156 1.23 fvdl /* 1157 1.23 fvdl * Add this entry to the hash and time queues. 1158 1.23 fvdl */ 1159 1.23 fvdl owp = NULL; 1160 1.132 yamt mutex_enter(&nfsd_lock); 1161 1.70 yamt wp = LIST_FIRST(&slp->ns_tq); 1162 1.23 fvdl while (wp && wp->nd_time < nfsd->nd_time) { 1163 1.23 fvdl owp = wp; 1164 1.70 yamt wp = LIST_NEXT(wp, nd_tq); 1165 1.23 fvdl } 1166 1.23 fvdl if (owp) { 1167 1.23 fvdl LIST_INSERT_AFTER(owp, nfsd, nd_tq); 1168 1.23 fvdl } else { 1169 1.23 fvdl LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); 1170 1.23 fvdl } 1171 1.23 fvdl if (nfsd->nd_mrep) { 1172 1.117 yamt wpp = nfsrv_nwdelayhash(slp, &nfsd->nd_fh); 1173 1.23 fvdl owp = NULL; 1174 1.70 yamt wp = LIST_FIRST(wpp); 1175 1.117 yamt while (wp && nfsrv_comparefh(&nfsd->nd_fh, &wp->nd_fh)) { 1176 1.23 fvdl owp = wp; 1177 1.70 yamt wp = LIST_NEXT(wp, nd_hash); 1178 1.23 fvdl } 1179 1.23 fvdl while (wp && wp->nd_off < nfsd->nd_off && 1180 1.117 yamt !nfsrv_comparefh(&nfsd->nd_fh, &wp->nd_fh)) { 1181 1.23 fvdl owp = wp; 1182 1.70 yamt wp = LIST_NEXT(wp, nd_hash); 1183 1.23 fvdl } 1184 1.23 fvdl if (owp) { 1185 1.23 fvdl LIST_INSERT_AFTER(owp, nfsd, nd_hash); 1186 1.23 fvdl 1187 1.23 fvdl /* 1188 1.23 fvdl * Search the hash list for overlapping entries and 1189 1.23 fvdl * coalesce. 1190 1.23 fvdl */ 1191 1.23 fvdl for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) { 1192 1.70 yamt wp = LIST_NEXT(nfsd, nd_hash); 1193 1.109 elad if (nfsrv_samecred(owp->nd_cr, nfsd->nd_cr)) 1194 1.23 fvdl nfsrvw_coalesce(owp, nfsd); 1195 1.23 fvdl } 1196 1.23 fvdl } else { 1197 1.23 fvdl LIST_INSERT_HEAD(wpp, nfsd, nd_hash); 1198 1.23 fvdl } 1199 1.23 fvdl } 1200 1.132 yamt mutex_exit(&nfsd_lock); 1201 1.1 cgd } 1202 1.94 perry 1203 1.1 cgd /* 1204 1.23 fvdl * Now, do VOP_WRITE()s for any one(s) that need to be done now 1205 1.23 fvdl * and generate the associated reply mbuf list(s). 1206 1.1 cgd */ 1207 1.23 fvdl loop1: 1208 1.110 kardel getmicrotime(&now); 1209 1.110 kardel cur_usec = (u_quad_t)now.tv_sec * 1000000 + (u_quad_t)now.tv_usec; 1210 1.132 yamt mutex_enter(&nfsd_lock); 1211 1.70 yamt for (nfsd = LIST_FIRST(&slp->ns_tq); nfsd; nfsd = owp) { 1212 1.70 yamt owp = LIST_NEXT(nfsd, nd_tq); 1213 1.23 fvdl if (nfsd->nd_time > cur_usec) 1214 1.23 fvdl break; 1215 1.23 fvdl if (nfsd->nd_mreq) 1216 1.23 fvdl continue; 1217 1.23 fvdl LIST_REMOVE(nfsd, nd_tq); 1218 1.23 fvdl LIST_REMOVE(nfsd, nd_hash); 1219 1.132 yamt mutex_exit(&nfsd_lock); 1220 1.132 yamt 1221 1.23 fvdl mrep = nfsd->nd_mrep; 1222 1.23 fvdl nfsd->nd_mrep = NULL; 1223 1.109 elad cred = nfsd->nd_cr; 1224 1.23 fvdl v3 = (nfsd->nd_flag & ND_NFSV3); 1225 1.23 fvdl forat_ret = aftat_ret = 1; 1226 1.117 yamt error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, 1227 1.35 fvdl nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), 1228 1.125 thorpej false); 1229 1.23 fvdl if (!error) { 1230 1.23 fvdl if (v3) 1231 1.131 pooka forat_ret = VOP_GETATTR(vp, &forat, cred); 1232 1.23 fvdl if (vp->v_type != VREG) { 1233 1.23 fvdl if (v3) 1234 1.23 fvdl error = EINVAL; 1235 1.1 cgd else 1236 1.23 fvdl error = (vp->v_type == VDIR) ? EISDIR : EACCES; 1237 1.23 fvdl } 1238 1.23 fvdl } else 1239 1.23 fvdl vp = NULL; 1240 1.23 fvdl if (!error) { 1241 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 1242 1.99 christos error = nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 1); 1243 1.23 fvdl } 1244 1.94 perry 1245 1.23 fvdl if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) 1246 1.23 fvdl ioflags = IO_NODELOCKED; 1247 1.23 fvdl else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) 1248 1.23 fvdl ioflags = (IO_SYNC | IO_NODELOCKED); 1249 1.23 fvdl else 1250 1.23 fvdl ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED); 1251 1.23 fvdl uiop->uio_rw = UIO_WRITE; 1252 1.23 fvdl uiop->uio_offset = nfsd->nd_off; 1253 1.23 fvdl uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off; 1254 1.101 yamt UIO_SETUP_SYSSPACE(uiop); 1255 1.23 fvdl if (uiop->uio_resid > 0) { 1256 1.23 fvdl mp = mrep; 1257 1.23 fvdl i = 0; 1258 1.23 fvdl while (mp) { 1259 1.23 fvdl if (mp->m_len > 0) 1260 1.23 fvdl i++; 1261 1.23 fvdl mp = mp->m_next; 1262 1.23 fvdl } 1263 1.23 fvdl uiop->uio_iovcnt = i; 1264 1.56 thorpej iov = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK); 1265 1.23 fvdl uiop->uio_iov = ivp = iov; 1266 1.23 fvdl mp = mrep; 1267 1.23 fvdl while (mp) { 1268 1.23 fvdl if (mp->m_len > 0) { 1269 1.126 christos ivp->iov_base = mtod(mp, void *); 1270 1.23 fvdl ivp->iov_len = mp->m_len; 1271 1.23 fvdl ivp++; 1272 1.23 fvdl } 1273 1.1 cgd mp = mp->m_next; 1274 1.23 fvdl } 1275 1.23 fvdl if (!error) { 1276 1.128 hannken error = VOP_WRITE(vp, uiop, ioflags, cred); 1277 1.128 hannken nfsstats.srvvop_writes++; 1278 1.23 fvdl } 1279 1.126 christos free((void *)iov, M_TEMP); 1280 1.1 cgd } 1281 1.23 fvdl m_freem(mrep); 1282 1.23 fvdl if (vp) { 1283 1.131 pooka aftat_ret = VOP_GETATTR(vp, &va, cred); 1284 1.23 fvdl vput(vp); 1285 1.1 cgd } 1286 1.23 fvdl 1287 1.23 fvdl /* 1288 1.23 fvdl * Loop around generating replies for all write rpcs that have 1289 1.23 fvdl * now been completed. 1290 1.23 fvdl */ 1291 1.23 fvdl swp = nfsd; 1292 1.23 fvdl do { 1293 1.23 fvdl if (error) { 1294 1.23 fvdl nfsm_writereply(NFSX_WCCDATA(v3), v3); 1295 1.23 fvdl if (v3) { 1296 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 1297 1.23 fvdl } 1298 1.23 fvdl } else { 1299 1.23 fvdl nfsm_writereply(NFSX_PREOPATTR(v3) + 1300 1.23 fvdl NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED + 1301 1.23 fvdl NFSX_WRITEVERF(v3), v3); 1302 1.23 fvdl if (v3) { 1303 1.23 fvdl nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va); 1304 1.23 fvdl nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1305 1.23 fvdl *tl++ = txdr_unsigned(nfsd->nd_len); 1306 1.23 fvdl *tl++ = txdr_unsigned(swp->nd_stable); 1307 1.23 fvdl /* 1308 1.23 fvdl * Actually, there is no need to txdr these fields, 1309 1.23 fvdl * but it may make the values more human readable, 1310 1.23 fvdl * for debugging purposes. 1311 1.23 fvdl */ 1312 1.178 thorpej struct timeval btv; 1313 1.178 thorpej getmicroboottime(&btv); 1314 1.178 thorpej *tl++ = txdr_unsigned(btv.tv_sec); 1315 1.178 thorpej *tl = txdr_unsigned(btv.tv_usec); 1316 1.23 fvdl } else { 1317 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 1318 1.23 fvdl nfsm_srvfillattr(&va, fp); 1319 1.23 fvdl } 1320 1.23 fvdl } 1321 1.23 fvdl nfsd->nd_mreq = mreq; 1322 1.23 fvdl if (nfsd->nd_mrep) 1323 1.23 fvdl panic("nfsrv_write: nd_mrep not free"); 1324 1.23 fvdl 1325 1.23 fvdl /* 1326 1.23 fvdl * Done. Put it at the head of the timer queue so that 1327 1.23 fvdl * the final phase can return the reply. 1328 1.23 fvdl */ 1329 1.132 yamt mutex_enter(&nfsd_lock); 1330 1.23 fvdl if (nfsd != swp) { 1331 1.23 fvdl nfsd->nd_time = 0; 1332 1.23 fvdl LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq); 1333 1.23 fvdl } 1334 1.70 yamt nfsd = LIST_FIRST(&swp->nd_coalesce); 1335 1.23 fvdl if (nfsd) { 1336 1.23 fvdl LIST_REMOVE(nfsd, nd_tq); 1337 1.23 fvdl } 1338 1.132 yamt mutex_exit(&nfsd_lock); 1339 1.23 fvdl } while (nfsd); 1340 1.23 fvdl swp->nd_time = 0; 1341 1.132 yamt 1342 1.132 yamt mutex_enter(&nfsd_lock); 1343 1.23 fvdl LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq); 1344 1.132 yamt mutex_exit(&nfsd_lock); 1345 1.23 fvdl goto loop1; 1346 1.23 fvdl } 1347 1.132 yamt mutex_exit(&nfsd_lock); 1348 1.129 yamt nfs_timer_start(); 1349 1.23 fvdl 1350 1.23 fvdl /* 1351 1.23 fvdl * Search for a reply to return. 1352 1.23 fvdl */ 1353 1.132 yamt mutex_enter(&nfsd_lock); 1354 1.70 yamt LIST_FOREACH(nfsd, &slp->ns_tq, nd_tq) { 1355 1.23 fvdl if (nfsd->nd_mreq) { 1356 1.23 fvdl LIST_REMOVE(nfsd, nd_tq); 1357 1.23 fvdl *mrq = nfsd->nd_mreq; 1358 1.23 fvdl *ndp = nfsd; 1359 1.23 fvdl break; 1360 1.1 cgd } 1361 1.70 yamt } 1362 1.132 yamt mutex_exit(&nfsd_lock); 1363 1.23 fvdl return (0); 1364 1.23 fvdl } 1365 1.23 fvdl 1366 1.23 fvdl /* 1367 1.23 fvdl * Coalesce the write request nfsd into owp. To do this we must: 1368 1.23 fvdl * - remove nfsd from the queues 1369 1.23 fvdl * - merge nfsd->nd_mrep into owp->nd_mrep 1370 1.23 fvdl * - update the nd_eoff and nd_stable for owp 1371 1.23 fvdl * - put nfsd on owp's nd_coalesce list 1372 1.23 fvdl * NB: Must be called at splsoftclock(). 1373 1.23 fvdl */ 1374 1.23 fvdl void 1375 1.143 dsl nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd) 1376 1.23 fvdl { 1377 1.54 augustss int overlap; 1378 1.54 augustss struct mbuf *mp; 1379 1.70 yamt struct nfsrv_descript *m; 1380 1.23 fvdl 1381 1.132 yamt KASSERT(mutex_owned(&nfsd_lock)); 1382 1.132 yamt 1383 1.23 fvdl LIST_REMOVE(nfsd, nd_hash); 1384 1.23 fvdl LIST_REMOVE(nfsd, nd_tq); 1385 1.23 fvdl if (owp->nd_eoff < nfsd->nd_eoff) { 1386 1.23 fvdl overlap = owp->nd_eoff - nfsd->nd_off; 1387 1.23 fvdl if (overlap < 0) 1388 1.23 fvdl panic("nfsrv_coalesce: bad off"); 1389 1.23 fvdl if (overlap > 0) 1390 1.23 fvdl m_adj(nfsd->nd_mrep, overlap); 1391 1.23 fvdl mp = owp->nd_mrep; 1392 1.23 fvdl while (mp->m_next) 1393 1.23 fvdl mp = mp->m_next; 1394 1.23 fvdl mp->m_next = nfsd->nd_mrep; 1395 1.23 fvdl owp->nd_eoff = nfsd->nd_eoff; 1396 1.23 fvdl } else 1397 1.23 fvdl m_freem(nfsd->nd_mrep); 1398 1.23 fvdl nfsd->nd_mrep = NULL; 1399 1.23 fvdl if (nfsd->nd_stable == NFSV3WRITE_FILESYNC) 1400 1.23 fvdl owp->nd_stable = NFSV3WRITE_FILESYNC; 1401 1.23 fvdl else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC && 1402 1.23 fvdl owp->nd_stable == NFSV3WRITE_UNSTABLE) 1403 1.23 fvdl owp->nd_stable = NFSV3WRITE_DATASYNC; 1404 1.23 fvdl LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq); 1405 1.34 fvdl /* 1406 1.34 fvdl * nfsd might hold coalesce elements! Move them to owp. 1407 1.34 fvdl * Otherwise, requests may be lost and clients will be stuck. 1408 1.34 fvdl */ 1409 1.70 yamt while ((m = LIST_FIRST(&nfsd->nd_coalesce)) != NULL) { 1410 1.70 yamt LIST_REMOVE(m, nd_tq); 1411 1.70 yamt LIST_INSERT_HEAD(&owp->nd_coalesce, m, nd_tq); 1412 1.70 yamt } 1413 1.1 cgd } 1414 1.1 cgd 1415 1.1 cgd /* 1416 1.1 cgd * nfs create service 1417 1.15 mycroft * now does a truncate to 0 length via. setattr if it already exists 1418 1.1 cgd */ 1419 1.22 christos int 1420 1.143 dsl nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 1421 1.1 cgd { 1422 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1423 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 1424 1.126 christos char *dpos = nfsd->nd_dpos; 1425 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 1426 1.54 augustss struct nfs_fattr *fp; 1427 1.23 fvdl struct vattr va, dirfor, diraft; 1428 1.54 augustss struct nfsv2_sattr *sp; 1429 1.54 augustss u_int32_t *tl; 1430 1.1 cgd struct nameidata nd; 1431 1.126 christos char *cp; 1432 1.54 augustss int32_t t1; 1433 1.126 christos char *bpos; 1434 1.103 christos int error = 0, cache = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1; 1435 1.144 bouyer int rdev = 0, abort = 0; 1436 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0; 1437 1.1 cgd char *cp2; 1438 1.166 martin struct mbuf *mb, *mreq __unused; 1439 1.23 fvdl struct vnode *vp = NULL, *dirp = NULL; 1440 1.117 yamt nfsrvfh_t nsfh; 1441 1.23 fvdl u_quad_t frev, tempsize; 1442 1.23 fvdl u_char cverf[NFSX_V3CREATEVERF]; 1443 1.1 cgd 1444 1.15 mycroft nd.ni_cnd.cn_nameiop = 0; 1445 1.117 yamt nfsm_srvmtofh(&nsfh); 1446 1.23 fvdl nfsm_srvnamesiz(len); 1447 1.15 mycroft nd.ni_cnd.cn_cred = cred; 1448 1.15 mycroft nd.ni_cnd.cn_nameiop = CREATE; 1449 1.61 chs nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1450 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 1451 1.183 hannken &dirp, (v3 ? &dirfor_ret : NULL), &dirfor, 1452 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 1453 1.23 fvdl if (error) { 1454 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 1455 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1456 1.23 fvdl if (dirp) 1457 1.23 fvdl vrele(dirp); 1458 1.152 dholland if (nd.ni_pathbuf != NULL) { 1459 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1460 1.152 dholland nd.ni_pathbuf = NULL; 1461 1.152 dholland } 1462 1.23 fvdl return (0); 1463 1.23 fvdl } 1464 1.144 bouyer abort = 1; 1465 1.150 pooka vattr_null(&va); 1466 1.23 fvdl if (v3) { 1467 1.92 yamt va.va_mode = 0; 1468 1.23 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1469 1.23 fvdl how = fxdr_unsigned(int, *tl); 1470 1.23 fvdl switch (how) { 1471 1.23 fvdl case NFSV3CREATE_GUARDED: 1472 1.23 fvdl if (nd.ni_vp) { 1473 1.23 fvdl error = EEXIST; 1474 1.23 fvdl break; 1475 1.23 fvdl } 1476 1.176 mrg /* FALLTHROUGH */ 1477 1.23 fvdl case NFSV3CREATE_UNCHECKED: 1478 1.23 fvdl nfsm_srvsattr(&va); 1479 1.23 fvdl break; 1480 1.23 fvdl case NFSV3CREATE_EXCLUSIVE: 1481 1.126 christos nfsm_dissect(cp, void *, NFSX_V3CREATEVERF); 1482 1.44 perry memcpy(cverf, cp, NFSX_V3CREATEVERF); 1483 1.23 fvdl exclusive_flag = 1; 1484 1.23 fvdl break; 1485 1.23 fvdl }; 1486 1.23 fvdl va.va_type = VREG; 1487 1.23 fvdl } else { 1488 1.23 fvdl nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1489 1.23 fvdl va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 1490 1.23 fvdl if (va.va_type == VNON) 1491 1.23 fvdl va.va_type = VREG; 1492 1.23 fvdl va.va_mode = nfstov_mode(sp->sa_mode); 1493 1.23 fvdl switch (va.va_type) { 1494 1.23 fvdl case VREG: 1495 1.23 fvdl tsize = fxdr_unsigned(int32_t, sp->sa_size); 1496 1.23 fvdl if (tsize != -1) 1497 1.23 fvdl va.va_size = (u_quad_t)tsize; 1498 1.23 fvdl break; 1499 1.23 fvdl case VCHR: 1500 1.23 fvdl case VBLK: 1501 1.23 fvdl case VFIFO: 1502 1.23 fvdl rdev = fxdr_unsigned(int32_t, sp->sa_size); 1503 1.23 fvdl break; 1504 1.23 fvdl default: 1505 1.23 fvdl break; 1506 1.23 fvdl }; 1507 1.23 fvdl } 1508 1.23 fvdl 1509 1.1 cgd /* 1510 1.15 mycroft * Iff doesn't exist, create it 1511 1.15 mycroft * otherwise just truncate to 0 length 1512 1.1 cgd * should I set the mode too ?? 1513 1.1 cgd */ 1514 1.1 cgd if (nd.ni_vp == NULL) { 1515 1.18 mycroft if (va.va_type == VREG || va.va_type == VSOCK) { 1516 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 1517 1.23 fvdl error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1518 1.23 fvdl if (!error) { 1519 1.170 hannken vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); 1520 1.23 fvdl if (exclusive_flag) { 1521 1.23 fvdl exclusive_flag = 0; 1522 1.150 pooka vattr_null(&va); 1523 1.89 yamt /* 1524 1.89 yamt * XXX 1525 1.89 yamt * assuming NFSX_V3CREATEVERF 1526 1.89 yamt * == sizeof(nfstime3) 1527 1.89 yamt */ 1528 1.89 yamt fxdr_nfsv3time(cverf, &va.va_atime); 1529 1.131 pooka error = VOP_SETATTR(nd.ni_vp, &va, 1530 1.131 pooka cred); 1531 1.23 fvdl } 1532 1.23 fvdl } 1533 1.18 mycroft } else if (va.va_type == VCHR || va.va_type == VBLK || 1534 1.18 mycroft va.va_type == VFIFO) { 1535 1.18 mycroft if (va.va_type == VCHR && rdev == 0xffffffff) 1536 1.18 mycroft va.va_type = VFIFO; 1537 1.46 mrg if (va.va_type != VFIFO && 1538 1.136 elad (error = kauth_authorize_system(cred, 1539 1.136 elad KAUTH_SYSTEM_MKNOD, 0, NULL, NULL, NULL))) { 1540 1.15 mycroft VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1541 1.1 cgd vput(nd.ni_dvp); 1542 1.144 bouyer abort = 0; 1543 1.23 fvdl nfsm_reply(0); 1544 1.152 dholland if (nd.ni_pathbuf != NULL) { 1545 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1546 1.152 dholland nd.ni_pathbuf = NULL; 1547 1.152 dholland } 1548 1.23 fvdl return (error); 1549 1.1 cgd } else 1550 1.18 mycroft va.va_rdev = (dev_t)rdev; 1551 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 1552 1.22 christos error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, 1553 1.23 fvdl &va); 1554 1.170 hannken if (!error) { 1555 1.170 hannken vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); 1556 1.170 hannken } else { 1557 1.1 cgd nfsm_reply(0); 1558 1.1 cgd } 1559 1.1 cgd } else { 1560 1.15 mycroft VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1561 1.152 dholland if (nd.ni_pathbuf != NULL) { 1562 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1563 1.152 dholland nd.ni_pathbuf = NULL; 1564 1.152 dholland } 1565 1.1 cgd error = ENXIO; 1566 1.144 bouyer abort = 0; 1567 1.1 cgd } 1568 1.1 cgd vp = nd.ni_vp; 1569 1.1 cgd } else { 1570 1.133 yamt VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1571 1.152 dholland if (nd.ni_pathbuf != NULL) { 1572 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1573 1.152 dholland nd.ni_pathbuf = NULL; 1574 1.152 dholland } 1575 1.1 cgd vp = nd.ni_vp; 1576 1.144 bouyer abort = 0; 1577 1.50 mycroft if (!error && va.va_size != -1) { 1578 1.22 christos error = nfsrv_access(vp, VWRITE, cred, 1579 1.99 christos (nd.ni_cnd.cn_flags & RDONLY), lwp, 0); 1580 1.23 fvdl if (!error) { 1581 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 1582 1.23 fvdl tempsize = va.va_size; 1583 1.150 pooka vattr_null(&va); 1584 1.23 fvdl va.va_size = tempsize; 1585 1.131 pooka error = VOP_SETATTR(vp, &va, cred); 1586 1.15 mycroft } 1587 1.1 cgd } 1588 1.50 mycroft if (error) 1589 1.50 mycroft vput(vp); 1590 1.1 cgd } 1591 1.23 fvdl if (!error) { 1592 1.117 yamt error = nfsrv_composefh(vp, &nsfh, v3); 1593 1.23 fvdl if (!error) 1594 1.131 pooka error = VOP_GETATTR(vp, &va, cred); 1595 1.1 cgd vput(vp); 1596 1.1 cgd } 1597 1.169 hannken if (nd.ni_dvp == vp) 1598 1.169 hannken vrele(nd.ni_dvp); 1599 1.169 hannken else 1600 1.169 hannken vput(nd.ni_dvp); 1601 1.23 fvdl if (v3) { 1602 1.89 yamt if (exclusive_flag && !error) { 1603 1.89 yamt /* 1604 1.89 yamt * XXX assuming NFSX_V3CREATEVERF == sizeof(nfstime3) 1605 1.89 yamt */ 1606 1.89 yamt char oldverf[NFSX_V3CREATEVERF]; 1607 1.89 yamt 1608 1.89 yamt txdr_nfsv3time(&va.va_atime, oldverf); 1609 1.89 yamt if (memcmp(cverf, oldverf, NFSX_V3CREATEVERF)) 1610 1.89 yamt error = EEXIST; 1611 1.89 yamt } 1612 1.105 christos if (dirp) { 1613 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 1614 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 1615 1.161 hannken VOP_UNLOCK(dirp); 1616 1.105 christos } 1617 1.23 fvdl } 1618 1.120 chs if (dirp) { 1619 1.120 chs vrele(dirp); 1620 1.144 bouyer dirp = NULL; 1621 1.120 chs } 1622 1.152 dholland if (nd.ni_pathbuf != NULL) { 1623 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1624 1.152 dholland nd.ni_pathbuf = NULL; 1625 1.152 dholland } 1626 1.144 bouyer abort = 0; 1627 1.117 yamt nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3)); 1628 1.23 fvdl if (v3) { 1629 1.23 fvdl if (!error) { 1630 1.117 yamt nfsm_srvpostop_fh(&nsfh); 1631 1.23 fvdl nfsm_srvpostop_attr(0, &va); 1632 1.23 fvdl } 1633 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1634 1.23 fvdl } else { 1635 1.117 yamt nfsm_srvfhtom(&nsfh, v3); 1636 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 1637 1.23 fvdl nfsm_srvfillattr(&va, fp); 1638 1.23 fvdl } 1639 1.23 fvdl return (0); 1640 1.1 cgd nfsmout: 1641 1.23 fvdl if (dirp) 1642 1.23 fvdl vrele(dirp); 1643 1.144 bouyer if (abort) { 1644 1.144 bouyer VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1645 1.144 bouyer if (nd.ni_dvp == nd.ni_vp) 1646 1.144 bouyer vrele(nd.ni_dvp); 1647 1.144 bouyer else 1648 1.144 bouyer vput(nd.ni_dvp); 1649 1.144 bouyer if (nd.ni_vp) 1650 1.144 bouyer vput(nd.ni_vp); 1651 1.184 riastrad if (nd.ni_pathbuf != NULL) { 1652 1.184 riastrad pathbuf_destroy(nd.ni_pathbuf); 1653 1.184 riastrad nd.ni_pathbuf = NULL; 1654 1.184 riastrad } 1655 1.152 dholland } 1656 1.1 cgd return (error); 1657 1.23 fvdl } 1658 1.23 fvdl 1659 1.23 fvdl /* 1660 1.23 fvdl * nfs v3 mknod service 1661 1.23 fvdl */ 1662 1.23 fvdl int 1663 1.143 dsl nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 1664 1.23 fvdl { 1665 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1666 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 1667 1.126 christos char *dpos = nfsd->nd_dpos; 1668 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 1669 1.23 fvdl struct vattr va, dirfor, diraft; 1670 1.54 augustss u_int32_t *tl; 1671 1.23 fvdl struct nameidata nd; 1672 1.54 augustss int32_t t1; 1673 1.126 christos char *bpos; 1674 1.103 christos int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1; 1675 1.144 bouyer int abort = 0; 1676 1.23 fvdl u_int32_t major, minor; 1677 1.23 fvdl enum vtype vtyp; 1678 1.23 fvdl char *cp2; 1679 1.166 martin struct mbuf *mb, *mreq __unused; 1680 1.23 fvdl struct vnode *vp, *dirp = (struct vnode *)0; 1681 1.117 yamt nfsrvfh_t nsfh; 1682 1.23 fvdl u_quad_t frev; 1683 1.23 fvdl 1684 1.23 fvdl nd.ni_cnd.cn_nameiop = 0; 1685 1.117 yamt nfsm_srvmtofh(&nsfh); 1686 1.23 fvdl nfsm_srvnamesiz(len); 1687 1.23 fvdl nd.ni_cnd.cn_cred = cred; 1688 1.23 fvdl nd.ni_cnd.cn_nameiop = CREATE; 1689 1.61 chs nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1690 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 1691 1.183 hannken &dirp, &dirfor_ret, &dirfor, 1692 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 1693 1.23 fvdl if (error) { 1694 1.23 fvdl nfsm_reply(NFSX_WCCDATA(1)); 1695 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1696 1.23 fvdl if (dirp) 1697 1.23 fvdl vrele(dirp); 1698 1.152 dholland if (nd.ni_pathbuf != NULL) { 1699 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1700 1.152 dholland nd.ni_pathbuf = NULL; 1701 1.152 dholland } 1702 1.23 fvdl return (0); 1703 1.23 fvdl } 1704 1.144 bouyer abort = 1; 1705 1.23 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1706 1.23 fvdl vtyp = nfsv3tov_type(*tl); 1707 1.23 fvdl if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1708 1.23 fvdl error = NFSERR_BADTYPE; 1709 1.95 yamt goto abort; 1710 1.23 fvdl } 1711 1.150 pooka vattr_null(&va); 1712 1.92 yamt va.va_mode = 0; 1713 1.23 fvdl nfsm_srvsattr(&va); 1714 1.23 fvdl if (vtyp == VCHR || vtyp == VBLK) { 1715 1.95 yamt dev_t rdev; 1716 1.95 yamt 1717 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1718 1.23 fvdl major = fxdr_unsigned(u_int32_t, *tl++); 1719 1.23 fvdl minor = fxdr_unsigned(u_int32_t, *tl); 1720 1.95 yamt rdev = makedev(major, minor); 1721 1.95 yamt if (major(rdev) != major || minor(rdev) != minor) { 1722 1.95 yamt error = EINVAL; 1723 1.95 yamt goto abort; 1724 1.95 yamt } 1725 1.95 yamt va.va_rdev = rdev; 1726 1.23 fvdl } 1727 1.1 cgd 1728 1.23 fvdl /* 1729 1.23 fvdl * Iff doesn't exist, create it. 1730 1.23 fvdl */ 1731 1.23 fvdl if (nd.ni_vp) { 1732 1.23 fvdl error = EEXIST; 1733 1.95 yamt abort: 1734 1.23 fvdl VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1735 1.95 yamt if (nd.ni_vp) 1736 1.95 yamt vput(nd.ni_vp); 1737 1.152 dholland if (nd.ni_pathbuf != NULL) { 1738 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1739 1.152 dholland nd.ni_pathbuf = NULL; 1740 1.152 dholland } 1741 1.23 fvdl goto out; 1742 1.23 fvdl } 1743 1.23 fvdl va.va_type = vtyp; 1744 1.23 fvdl if (vtyp == VSOCK) { 1745 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 1746 1.23 fvdl error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1747 1.23 fvdl } else { 1748 1.46 mrg if (va.va_type != VFIFO && 1749 1.136 elad (error = kauth_authorize_system(cred, 1750 1.136 elad KAUTH_SYSTEM_MKNOD, 0, NULL, NULL, NULL))) { 1751 1.23 fvdl VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1752 1.23 fvdl vput(nd.ni_dvp); 1753 1.23 fvdl goto out; 1754 1.23 fvdl } 1755 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 1756 1.23 fvdl error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1757 1.23 fvdl if (error) 1758 1.23 fvdl goto out; 1759 1.23 fvdl } 1760 1.170 hannken if (!error) { 1761 1.170 hannken vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); 1762 1.170 hannken } 1763 1.1 cgd out: 1764 1.23 fvdl vp = nd.ni_vp; 1765 1.23 fvdl if (!error) { 1766 1.125 thorpej error = nfsrv_composefh(vp, &nsfh, true); 1767 1.23 fvdl if (!error) 1768 1.131 pooka error = VOP_GETATTR(vp, &va, cred); 1769 1.23 fvdl vput(vp); 1770 1.23 fvdl } 1771 1.169 hannken if (nd.ni_dvp == nd.ni_vp) 1772 1.169 hannken vrele(nd.ni_dvp); 1773 1.169 hannken else 1774 1.169 hannken vput(nd.ni_dvp); 1775 1.104 christos if (dirp) { 1776 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 1777 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 1778 1.161 hannken VOP_UNLOCK(dirp); 1779 1.104 christos vrele(dirp); 1780 1.144 bouyer dirp = NULL; 1781 1.104 christos } 1782 1.152 dholland if (nd.ni_pathbuf != NULL) { 1783 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1784 1.152 dholland nd.ni_pathbuf = NULL; 1785 1.152 dholland } 1786 1.144 bouyer abort = 0; 1787 1.125 thorpej nfsm_reply(NFSX_SRVFH(&nsfh, true) + NFSX_POSTOPATTR(1) + 1788 1.117 yamt NFSX_WCCDATA(1)); 1789 1.23 fvdl if (!error) { 1790 1.117 yamt nfsm_srvpostop_fh(&nsfh); 1791 1.23 fvdl nfsm_srvpostop_attr(0, &va); 1792 1.23 fvdl } 1793 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1794 1.23 fvdl return (0); 1795 1.23 fvdl nfsmout: 1796 1.144 bouyer if (abort) { 1797 1.144 bouyer VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1798 1.144 bouyer if (nd.ni_dvp == nd.ni_vp) 1799 1.144 bouyer vrele(nd.ni_dvp); 1800 1.144 bouyer else 1801 1.144 bouyer vput(nd.ni_dvp); 1802 1.144 bouyer if (nd.ni_vp) 1803 1.144 bouyer vput(nd.ni_vp); 1804 1.184 riastrad if (nd.ni_pathbuf != NULL) { 1805 1.184 riastrad pathbuf_destroy(nd.ni_pathbuf); 1806 1.184 riastrad nd.ni_pathbuf = NULL; 1807 1.184 riastrad } 1808 1.152 dholland } 1809 1.120 chs if (dirp) 1810 1.120 chs vrele(dirp); 1811 1.23 fvdl return (error); 1812 1.1 cgd } 1813 1.1 cgd 1814 1.1 cgd /* 1815 1.1 cgd * nfs remove service 1816 1.1 cgd */ 1817 1.22 christos int 1818 1.143 dsl nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 1819 1.1 cgd { 1820 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1821 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 1822 1.126 christos char *dpos = nfsd->nd_dpos; 1823 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 1824 1.1 cgd struct nameidata nd; 1825 1.54 augustss u_int32_t *tl; 1826 1.54 augustss int32_t t1; 1827 1.126 christos char *bpos; 1828 1.103 christos int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1; 1829 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 1830 1.1 cgd char *cp2; 1831 1.166 martin struct mbuf *mb, *mreq __unused; 1832 1.23 fvdl struct vnode *vp, *dirp; 1833 1.23 fvdl struct vattr dirfor, diraft; 1834 1.117 yamt nfsrvfh_t nsfh; 1835 1.15 mycroft u_quad_t frev; 1836 1.1 cgd 1837 1.23 fvdl #ifndef nolint 1838 1.23 fvdl vp = (struct vnode *)0; 1839 1.23 fvdl #endif 1840 1.117 yamt nfsm_srvmtofh(&nsfh); 1841 1.23 fvdl nfsm_srvnamesiz(len); 1842 1.15 mycroft nd.ni_cnd.cn_cred = cred; 1843 1.15 mycroft nd.ni_cnd.cn_nameiop = DELETE; 1844 1.15 mycroft nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1845 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 1846 1.183 hannken &dirp, (v3 ? &dirfor_ret : NULL), &dirfor, 1847 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 1848 1.23 fvdl if (!error) { 1849 1.23 fvdl vp = nd.ni_vp; 1850 1.137 yamt if (vp->v_type == VDIR) { 1851 1.137 yamt error = EPERM; 1852 1.23 fvdl goto out; 1853 1.137 yamt } 1854 1.23 fvdl /* 1855 1.23 fvdl * The root of a mounted filesystem cannot be deleted. 1856 1.23 fvdl */ 1857 1.130 ad if (vp->v_vflag & VV_ROOT) { 1858 1.23 fvdl error = EBUSY; 1859 1.23 fvdl } 1860 1.21 mycroft out: 1861 1.23 fvdl if (!error) { 1862 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 1863 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 1864 1.23 fvdl error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1865 1.173 riastrad vput(nd.ni_dvp); 1866 1.23 fvdl } else { 1867 1.23 fvdl VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1868 1.23 fvdl if (nd.ni_dvp == vp) 1869 1.23 fvdl vrele(nd.ni_dvp); 1870 1.23 fvdl else 1871 1.23 fvdl vput(nd.ni_dvp); 1872 1.23 fvdl vput(vp); 1873 1.23 fvdl } 1874 1.23 fvdl } 1875 1.152 dholland if (nd.ni_pathbuf != NULL) { 1876 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 1877 1.152 dholland nd.ni_pathbuf = NULL; 1878 1.152 dholland } 1879 1.120 chs if (dirp) { 1880 1.120 chs if (v3) { 1881 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 1882 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 1883 1.161 hannken VOP_UNLOCK(dirp); 1884 1.120 chs } 1885 1.23 fvdl vrele(dirp); 1886 1.23 fvdl } 1887 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 1888 1.23 fvdl if (v3) { 1889 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 1890 1.23 fvdl return (0); 1891 1.23 fvdl } 1892 1.1 cgd nfsm_srvdone; 1893 1.1 cgd } 1894 1.1 cgd 1895 1.1 cgd /* 1896 1.1 cgd * nfs rename service 1897 1.1 cgd */ 1898 1.22 christos int 1899 1.143 dsl nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 1900 1.1 cgd { 1901 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 1902 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 1903 1.126 christos char *dpos = nfsd->nd_dpos; 1904 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 1905 1.54 augustss u_int32_t *tl; 1906 1.54 augustss int32_t t1; 1907 1.126 christos char *bpos; 1908 1.103 christos int error = 0, cache = 0, fdirfor_ret = 1, fdiraft_ret = 1; 1909 1.68 yamt uint32_t len, len2; 1910 1.23 fvdl int tdirfor_ret = 1, tdiraft_ret = 1; 1911 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 1912 1.1 cgd char *cp2; 1913 1.166 martin struct mbuf *mb, *mreq __unused; 1914 1.1 cgd struct nameidata fromnd, tond; 1915 1.120 chs struct vnode *fvp, *tvp, *tdvp; 1916 1.120 chs struct vnode *fdirp = NULL, *tdirp = NULL; 1917 1.134 dholland struct mount *localfs = NULL; 1918 1.23 fvdl struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 1919 1.117 yamt nfsrvfh_t fnsfh, tnsfh; 1920 1.15 mycroft u_quad_t frev; 1921 1.15 mycroft uid_t saved_uid; 1922 1.1 cgd 1923 1.23 fvdl #ifndef nolint 1924 1.23 fvdl fvp = (struct vnode *)0; 1925 1.23 fvdl #endif 1926 1.15 mycroft fromnd.ni_cnd.cn_nameiop = 0; 1927 1.15 mycroft tond.ni_cnd.cn_nameiop = 0; 1928 1.117 yamt nfsm_srvmtofh(&fnsfh); 1929 1.23 fvdl nfsm_srvnamesiz(len); 1930 1.1 cgd /* 1931 1.15 mycroft * Remember our original uid so that we can reset cr_uid before 1932 1.15 mycroft * the second nfs_namei() call, in case it is remapped. 1933 1.1 cgd */ 1934 1.109 elad saved_uid = kauth_cred_geteuid(cred); 1935 1.15 mycroft fromnd.ni_cnd.cn_cred = cred; 1936 1.15 mycroft fromnd.ni_cnd.cn_nameiop = DELETE; 1937 1.172 riastrad fromnd.ni_cnd.cn_flags = LOCKPARENT; 1938 1.117 yamt error = nfs_namei(&fromnd, &fnsfh, len, slp, nam, &md, 1939 1.183 hannken &dpos, &fdirp, (v3 ? &fdirfor_ret : NULL), &fdirfor, 1940 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 1941 1.23 fvdl if (error) { 1942 1.164 chs fromnd.ni_cnd.cn_nameiop = 0; 1943 1.23 fvdl nfsm_reply(2 * NFSX_WCCDATA(v3)); 1944 1.23 fvdl nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1945 1.23 fvdl nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1946 1.23 fvdl if (fdirp) 1947 1.123 chs vrele(fdirp); 1948 1.160 dholland if (fromnd.ni_pathbuf != NULL) { 1949 1.160 dholland pathbuf_destroy(fromnd.ni_pathbuf); 1950 1.160 dholland } 1951 1.23 fvdl return (0); 1952 1.23 fvdl } 1953 1.177 hannken localfs = fromnd.ni_dvp->v_mount; 1954 1.177 hannken fstrans_start(localfs); 1955 1.123 chs if (fromnd.ni_dvp != fromnd.ni_vp) { 1956 1.151 hannken VOP_UNLOCK(fromnd.ni_dvp); 1957 1.123 chs } 1958 1.1 cgd fvp = fromnd.ni_vp; 1959 1.134 dholland 1960 1.134 dholland error = VFS_RENAMELOCK_ENTER(localfs); 1961 1.134 dholland if (error) { 1962 1.134 dholland VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1963 1.134 dholland vrele(fromnd.ni_dvp); 1964 1.134 dholland vrele(fvp); 1965 1.134 dholland goto out1; 1966 1.134 dholland } 1967 1.134 dholland 1968 1.134 dholland /* Copied, regrettably, from vfs_syscalls.c (q.v.) */ 1969 1.134 dholland vrele(fvp); 1970 1.138 dholland if ((fromnd.ni_cnd.cn_namelen == 1 && 1971 1.138 dholland fromnd.ni_cnd.cn_nameptr[0] == '.') || 1972 1.138 dholland (fromnd.ni_cnd.cn_namelen == 2 && 1973 1.138 dholland fromnd.ni_cnd.cn_nameptr[0] == '.' && 1974 1.138 dholland fromnd.ni_cnd.cn_nameptr[1] == '.')) { 1975 1.138 dholland error = EINVAL; 1976 1.138 dholland VFS_RENAMELOCK_EXIT(localfs); 1977 1.138 dholland VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1978 1.138 dholland vrele(fromnd.ni_dvp); 1979 1.138 dholland goto out1; 1980 1.138 dholland } 1981 1.134 dholland vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY); 1982 1.154 dholland error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd, 0); 1983 1.134 dholland if (error) { 1984 1.151 hannken VOP_UNLOCK(fromnd.ni_dvp); 1985 1.134 dholland VFS_RENAMELOCK_EXIT(localfs); 1986 1.134 dholland VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1987 1.134 dholland vrele(fromnd.ni_dvp); 1988 1.134 dholland goto out1; 1989 1.134 dholland } 1990 1.151 hannken VOP_UNLOCK(fromnd.ni_vp); 1991 1.134 dholland if (fromnd.ni_dvp != fromnd.ni_vp) 1992 1.151 hannken VOP_UNLOCK(fromnd.ni_dvp); 1993 1.134 dholland fvp = fromnd.ni_vp; 1994 1.134 dholland 1995 1.117 yamt nfsm_srvmtofh(&tnsfh); 1996 1.68 yamt if (v3) { 1997 1.68 yamt nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED); 1998 1.68 yamt len2 = fxdr_unsigned(uint32_t, *tl); 1999 1.68 yamt /* len2 will be checked by nfs_namei */ 2000 1.68 yamt } 2001 1.68 yamt else { 2002 1.68 yamt /* NFSv2 */ 2003 1.68 yamt nfsm_strsiz(len2, NFS_MAXNAMLEN); 2004 1.68 yamt } 2005 1.109 elad kauth_cred_seteuid(cred, saved_uid); 2006 1.15 mycroft tond.ni_cnd.cn_cred = cred; 2007 1.15 mycroft tond.ni_cnd.cn_nameiop = RENAME; 2008 1.172 riastrad tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE; 2009 1.117 yamt error = nfs_namei(&tond, &tnsfh, len2, slp, nam, &md, 2010 1.183 hannken &dpos, &tdirp, (v3 ? &tdirfor_ret : NULL), &tdirfor, 2011 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 2012 1.22 christos if (error) { 2013 1.134 dholland VFS_RENAMELOCK_EXIT(localfs); 2014 1.15 mycroft VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2015 1.1 cgd vrele(fromnd.ni_dvp); 2016 1.1 cgd vrele(fvp); 2017 1.1 cgd goto out1; 2018 1.1 cgd } 2019 1.1 cgd tdvp = tond.ni_dvp; 2020 1.1 cgd tvp = tond.ni_vp; 2021 1.1 cgd if (tvp != NULL) { 2022 1.1 cgd if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2023 1.23 fvdl if (v3) 2024 1.23 fvdl error = EEXIST; 2025 1.23 fvdl else 2026 1.23 fvdl error = EISDIR; 2027 1.1 cgd goto out; 2028 1.1 cgd } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2029 1.23 fvdl if (v3) 2030 1.23 fvdl error = EEXIST; 2031 1.23 fvdl else 2032 1.23 fvdl error = ENOTDIR; 2033 1.1 cgd goto out; 2034 1.1 cgd } 2035 1.15 mycroft if (tvp->v_type == VDIR && tvp->v_mountedhere) { 2036 1.23 fvdl if (v3) 2037 1.23 fvdl error = EXDEV; 2038 1.23 fvdl else 2039 1.23 fvdl error = ENOTEMPTY; 2040 1.15 mycroft goto out; 2041 1.15 mycroft } 2042 1.15 mycroft } 2043 1.15 mycroft if (fvp->v_type == VDIR && fvp->v_mountedhere) { 2044 1.23 fvdl if (v3) 2045 1.23 fvdl error = EXDEV; 2046 1.23 fvdl else 2047 1.23 fvdl error = ENOTEMPTY; 2048 1.15 mycroft goto out; 2049 1.1 cgd } 2050 1.1 cgd if (fvp->v_mount != tdvp->v_mount) { 2051 1.23 fvdl if (v3) 2052 1.23 fvdl error = EXDEV; 2053 1.23 fvdl else 2054 1.23 fvdl error = ENOTEMPTY; 2055 1.1 cgd goto out; 2056 1.1 cgd } 2057 1.45 thorpej if (fvp == tdvp) { 2058 1.23 fvdl if (v3) 2059 1.23 fvdl error = EINVAL; 2060 1.23 fvdl else 2061 1.23 fvdl error = ENOTEMPTY; 2062 1.45 thorpej } 2063 1.1 cgd /* 2064 1.1 cgd * If source is the same as the destination (that is the 2065 1.1 cgd * same vnode with the same name in the same directory), 2066 1.1 cgd * then there is nothing to do. 2067 1.1 cgd */ 2068 1.1 cgd if (fvp == tvp && fromnd.ni_dvp == tdvp && 2069 1.15 mycroft fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 2070 1.44 perry !memcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 2071 1.15 mycroft fromnd.ni_cnd.cn_namelen)) 2072 1.1 cgd error = -1; 2073 1.1 cgd out: 2074 1.1 cgd if (!error) { 2075 1.23 fvdl nqsrv_getl(fromnd.ni_dvp, ND_WRITE); 2076 1.23 fvdl nqsrv_getl(tdvp, ND_WRITE); 2077 1.30 fvdl if (tvp) { 2078 1.23 fvdl nqsrv_getl(tvp, ND_WRITE); 2079 1.30 fvdl } 2080 1.15 mycroft error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2081 1.15 mycroft tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2082 1.134 dholland VFS_RENAMELOCK_EXIT(localfs); 2083 1.1 cgd } else { 2084 1.15 mycroft VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2085 1.1 cgd if (tdvp == tvp) 2086 1.1 cgd vrele(tdvp); 2087 1.1 cgd else 2088 1.1 cgd vput(tdvp); 2089 1.1 cgd if (tvp) 2090 1.1 cgd vput(tvp); 2091 1.134 dholland VFS_RENAMELOCK_EXIT(localfs); 2092 1.15 mycroft VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2093 1.1 cgd vrele(fromnd.ni_dvp); 2094 1.1 cgd vrele(fvp); 2095 1.23 fvdl if (error == -1) 2096 1.23 fvdl error = 0; 2097 1.1 cgd } 2098 1.160 dholland if (tond.ni_pathbuf != NULL) { 2099 1.160 dholland pathbuf_destroy(tond.ni_pathbuf); 2100 1.160 dholland tond.ni_pathbuf = NULL; 2101 1.160 dholland } 2102 1.144 bouyer tond.ni_cnd.cn_nameiop = 0; 2103 1.1 cgd out1: 2104 1.23 fvdl if (fdirp) { 2105 1.120 chs if (v3) { 2106 1.161 hannken vn_lock(fdirp, LK_SHARED | LK_RETRY); 2107 1.131 pooka fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred); 2108 1.161 hannken VOP_UNLOCK(fdirp); 2109 1.120 chs } 2110 1.23 fvdl vrele(fdirp); 2111 1.144 bouyer fdirp = NULL; 2112 1.23 fvdl } 2113 1.23 fvdl if (tdirp) { 2114 1.120 chs if (v3) { 2115 1.161 hannken vn_lock(tdirp, LK_SHARED | LK_RETRY); 2116 1.131 pooka tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred); 2117 1.161 hannken VOP_UNLOCK(tdirp); 2118 1.120 chs } 2119 1.23 fvdl vrele(tdirp); 2120 1.144 bouyer tdirp = NULL; 2121 1.23 fvdl } 2122 1.152 dholland pathbuf_destroy(fromnd.ni_pathbuf); 2123 1.160 dholland fromnd.ni_pathbuf = NULL; 2124 1.144 bouyer fromnd.ni_cnd.cn_nameiop = 0; 2125 1.177 hannken fstrans_done(localfs); 2126 1.144 bouyer localfs = NULL; 2127 1.23 fvdl nfsm_reply(2 * NFSX_WCCDATA(v3)); 2128 1.23 fvdl if (v3) { 2129 1.23 fvdl nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 2130 1.23 fvdl nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 2131 1.23 fvdl } 2132 1.23 fvdl return (0); 2133 1.1 cgd 2134 1.1 cgd nfsmout: 2135 1.23 fvdl if (fdirp) 2136 1.23 fvdl vrele(fdirp); 2137 1.106 christos #ifdef notdef 2138 1.23 fvdl if (tdirp) 2139 1.23 fvdl vrele(tdirp); 2140 1.106 christos #endif 2141 1.23 fvdl if (tond.ni_cnd.cn_nameiop) { 2142 1.160 dholland if (tond.ni_pathbuf != NULL) { 2143 1.160 dholland pathbuf_destroy(tond.ni_pathbuf); 2144 1.160 dholland tond.ni_pathbuf = NULL; 2145 1.160 dholland } 2146 1.1 cgd } 2147 1.134 dholland if (localfs) { 2148 1.134 dholland VFS_RENAMELOCK_EXIT(localfs); 2149 1.177 hannken fstrans_done(localfs); 2150 1.134 dholland } 2151 1.23 fvdl if (fromnd.ni_cnd.cn_nameiop) { 2152 1.15 mycroft VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2153 1.160 dholland if (fromnd.ni_pathbuf != NULL) { 2154 1.160 dholland pathbuf_destroy(fromnd.ni_pathbuf); 2155 1.160 dholland fromnd.ni_pathbuf = NULL; 2156 1.160 dholland } 2157 1.1 cgd vrele(fromnd.ni_dvp); 2158 1.1 cgd vrele(fvp); 2159 1.1 cgd } 2160 1.1 cgd return (error); 2161 1.1 cgd } 2162 1.1 cgd 2163 1.1 cgd /* 2164 1.1 cgd * nfs link service 2165 1.1 cgd */ 2166 1.22 christos int 2167 1.143 dsl nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 2168 1.1 cgd { 2169 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2170 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 2171 1.126 christos char *dpos = nfsd->nd_dpos; 2172 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 2173 1.1 cgd struct nameidata nd; 2174 1.54 augustss u_int32_t *tl; 2175 1.54 augustss int32_t t1; 2176 1.126 christos char *bpos; 2177 1.103 christos int error = 0, rdonly, cache = 0, len, dirfor_ret = 1, diraft_ret = 1; 2178 1.23 fvdl int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3); 2179 1.1 cgd char *cp2; 2180 1.166 martin struct mbuf *mb, *mreq __unused; 2181 1.23 fvdl struct vnode *vp, *xp, *dirp = (struct vnode *)0; 2182 1.23 fvdl struct vattr dirfor, diraft, at; 2183 1.117 yamt nfsrvfh_t nsfh, dnsfh; 2184 1.15 mycroft u_quad_t frev; 2185 1.1 cgd 2186 1.117 yamt nfsm_srvmtofh(&nsfh); 2187 1.117 yamt nfsm_srvmtofh(&dnsfh); 2188 1.23 fvdl nfsm_srvnamesiz(len); 2189 1.125 thorpej error = nfsrv_fhtovp(&nsfh, false, &vp, cred, slp, nam, 2190 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 2191 1.23 fvdl if (error) { 2192 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2193 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2194 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2195 1.23 fvdl return (0); 2196 1.23 fvdl } 2197 1.137 yamt if (vp->v_type == VDIR) { 2198 1.137 yamt error = EPERM; 2199 1.23 fvdl goto out1; 2200 1.137 yamt } 2201 1.15 mycroft nd.ni_cnd.cn_cred = cred; 2202 1.15 mycroft nd.ni_cnd.cn_nameiop = CREATE; 2203 1.15 mycroft nd.ni_cnd.cn_flags = LOCKPARENT; 2204 1.117 yamt error = nfs_namei(&nd, &dnsfh, len, slp, nam, &md, &dpos, 2205 1.183 hannken &dirp, (v3 ? &dirfor_ret : NULL), &dirfor, 2206 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 2207 1.22 christos if (error) 2208 1.23 fvdl goto out1; 2209 1.23 fvdl xp = nd.ni_vp; 2210 1.23 fvdl if (xp != NULL) { 2211 1.23 fvdl error = EEXIST; 2212 1.1 cgd goto out; 2213 1.23 fvdl } 2214 1.23 fvdl xp = nd.ni_dvp; 2215 1.23 fvdl if (vp->v_mount != xp->v_mount) 2216 1.23 fvdl error = EXDEV; 2217 1.23 fvdl out: 2218 1.23 fvdl if (!error) { 2219 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 2220 1.23 fvdl nqsrv_getl(xp, ND_WRITE); 2221 1.23 fvdl error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 2222 1.171 riastrad if (nd.ni_dvp != nd.ni_vp) 2223 1.171 riastrad VOP_UNLOCK(nd.ni_dvp); 2224 1.171 riastrad vrele(nd.ni_dvp); 2225 1.23 fvdl } else { 2226 1.15 mycroft VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2227 1.1 cgd if (nd.ni_dvp == nd.ni_vp) 2228 1.1 cgd vrele(nd.ni_dvp); 2229 1.1 cgd else 2230 1.1 cgd vput(nd.ni_dvp); 2231 1.23 fvdl if (nd.ni_vp) 2232 1.23 fvdl vrele(nd.ni_vp); 2233 1.23 fvdl } 2234 1.23 fvdl out1: 2235 1.161 hannken if (v3) { 2236 1.161 hannken vn_lock(vp, LK_SHARED | LK_RETRY); 2237 1.131 pooka getret = VOP_GETATTR(vp, &at, cred); 2238 1.161 hannken VOP_UNLOCK(vp); 2239 1.161 hannken } 2240 1.23 fvdl if (dirp) { 2241 1.120 chs if (v3) { 2242 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 2243 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 2244 1.161 hannken VOP_UNLOCK(dirp); 2245 1.120 chs } 2246 1.23 fvdl vrele(dirp); 2247 1.1 cgd } 2248 1.1 cgd vrele(vp); 2249 1.160 dholland if (nd.ni_pathbuf != NULL) { 2250 1.160 dholland pathbuf_destroy(nd.ni_pathbuf); 2251 1.160 dholland nd.ni_pathbuf = NULL; 2252 1.160 dholland } 2253 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); 2254 1.23 fvdl if (v3) { 2255 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2256 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2257 1.23 fvdl return (0); 2258 1.23 fvdl } 2259 1.1 cgd nfsm_srvdone; 2260 1.1 cgd } 2261 1.1 cgd 2262 1.1 cgd /* 2263 1.1 cgd * nfs symbolic link service 2264 1.1 cgd */ 2265 1.22 christos int 2266 1.143 dsl nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 2267 1.1 cgd { 2268 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2269 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 2270 1.126 christos char *dpos = nfsd->nd_dpos; 2271 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 2272 1.23 fvdl struct vattr va, dirfor, diraft; 2273 1.1 cgd struct nameidata nd; 2274 1.54 augustss u_int32_t *tl; 2275 1.54 augustss int32_t t1; 2276 1.1 cgd struct nfsv2_sattr *sp; 2277 1.23 fvdl char *bpos, *pathcp = NULL, *cp2; 2278 1.1 cgd struct uio io; 2279 1.1 cgd struct iovec iv; 2280 1.144 bouyer int error = 0, cache = 0, dirfor_ret = 1, diraft_ret = 1, abort = 0; 2281 1.68 yamt uint32_t len, len2; 2282 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 2283 1.166 martin struct mbuf *mb, *mreq __unused; 2284 1.23 fvdl struct vnode *dirp = (struct vnode *)0; 2285 1.117 yamt nfsrvfh_t nsfh; 2286 1.15 mycroft u_quad_t frev; 2287 1.1 cgd 2288 1.23 fvdl nd.ni_cnd.cn_nameiop = 0; 2289 1.117 yamt nfsm_srvmtofh(&nsfh); 2290 1.23 fvdl nfsm_srvnamesiz(len); 2291 1.15 mycroft nd.ni_cnd.cn_cred = cred; 2292 1.15 mycroft nd.ni_cnd.cn_nameiop = CREATE; 2293 1.61 chs nd.ni_cnd.cn_flags = LOCKPARENT; 2294 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 2295 1.183 hannken &dirp, (v3 ? &dirfor_ret : NULL), &dirfor, 2296 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 2297 1.22 christos if (error) 2298 1.1 cgd goto out; 2299 1.144 bouyer abort = 1; 2300 1.150 pooka vattr_null(&va); 2301 1.97 jmmv va.va_type = VLNK; 2302 1.68 yamt if (v3) { 2303 1.92 yamt va.va_mode = 0; 2304 1.23 fvdl nfsm_srvsattr(&va); 2305 1.68 yamt nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED); 2306 1.68 yamt len2 = fxdr_unsigned(uint32_t, *tl); 2307 1.68 yamt if (len2 > PATH_MAX) { 2308 1.68 yamt /* XXX should check _PC_NO_TRUNC */ 2309 1.68 yamt error = ENAMETOOLONG; 2310 1.68 yamt goto abortop; 2311 1.68 yamt } 2312 1.68 yamt } 2313 1.68 yamt else { 2314 1.68 yamt /* NFSv2 */ 2315 1.68 yamt nfsm_strsiz(len2, NFS_MAXPATHLEN); 2316 1.68 yamt } 2317 1.56 thorpej pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK); 2318 1.1 cgd iv.iov_base = pathcp; 2319 1.1 cgd iv.iov_len = len2; 2320 1.1 cgd io.uio_resid = len2; 2321 1.1 cgd io.uio_offset = 0; 2322 1.1 cgd io.uio_iov = &iv; 2323 1.1 cgd io.uio_iovcnt = 1; 2324 1.1 cgd io.uio_rw = UIO_READ; 2325 1.101 yamt UIO_SETUP_SYSSPACE(&io); 2326 1.1 cgd nfsm_mtouio(&io, len2); 2327 1.23 fvdl if (!v3) { 2328 1.23 fvdl nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 2329 1.23 fvdl va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); 2330 1.23 fvdl } 2331 1.1 cgd *(pathcp + len2) = '\0'; 2332 1.1 cgd if (nd.ni_vp) { 2333 1.68 yamt error = EEXIST; 2334 1.68 yamt abortop: 2335 1.15 mycroft VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2336 1.1 cgd if (nd.ni_dvp == nd.ni_vp) 2337 1.1 cgd vrele(nd.ni_dvp); 2338 1.1 cgd else 2339 1.1 cgd vput(nd.ni_dvp); 2340 1.68 yamt if (nd.ni_vp) 2341 1.68 yamt vrele(nd.ni_vp); 2342 1.1 cgd goto out; 2343 1.1 cgd } 2344 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 2345 1.23 fvdl error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp); 2346 1.61 chs if (!error) { 2347 1.23 fvdl if (v3) { 2348 1.170 hannken vn_lock(nd.ni_vp, LK_SHARED | LK_RETRY); 2349 1.117 yamt error = nfsrv_composefh(nd.ni_vp, &nsfh, v3); 2350 1.60 assar if (!error) 2351 1.131 pooka error = VOP_GETATTR(nd.ni_vp, &va, cred); 2352 1.60 assar vput(nd.ni_vp); 2353 1.60 assar } else { 2354 1.170 hannken vrele(nd.ni_vp); 2355 1.60 assar } 2356 1.23 fvdl } 2357 1.169 hannken vput(nd.ni_dvp); 2358 1.1 cgd out: 2359 1.1 cgd if (pathcp) 2360 1.56 thorpej free(pathcp, M_TEMP); 2361 1.23 fvdl if (dirp) { 2362 1.120 chs if (v3) { 2363 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 2364 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 2365 1.161 hannken VOP_UNLOCK(dirp); 2366 1.120 chs } 2367 1.23 fvdl vrele(dirp); 2368 1.144 bouyer dirp = NULL; 2369 1.23 fvdl } 2370 1.160 dholland if (nd.ni_pathbuf != NULL) { 2371 1.160 dholland pathbuf_destroy(nd.ni_pathbuf); 2372 1.160 dholland nd.ni_pathbuf = NULL; 2373 1.160 dholland } 2374 1.144 bouyer abort = 0; 2375 1.117 yamt nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPATTR(v3) + 2376 1.117 yamt NFSX_WCCDATA(v3)); 2377 1.23 fvdl if (v3) { 2378 1.23 fvdl if (!error) { 2379 1.117 yamt nfsm_srvpostop_fh(&nsfh); 2380 1.23 fvdl nfsm_srvpostop_attr(0, &va); 2381 1.23 fvdl } 2382 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2383 1.23 fvdl } 2384 1.23 fvdl return (0); 2385 1.1 cgd nfsmout: 2386 1.144 bouyer if (abort) { 2387 1.144 bouyer VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2388 1.144 bouyer if (nd.ni_dvp == nd.ni_vp) 2389 1.144 bouyer vrele(nd.ni_dvp); 2390 1.144 bouyer else 2391 1.144 bouyer vput(nd.ni_dvp); 2392 1.144 bouyer if (nd.ni_vp) 2393 1.144 bouyer vrele(nd.ni_vp); 2394 1.160 dholland if (nd.ni_pathbuf != NULL) { 2395 1.160 dholland pathbuf_destroy(nd.ni_pathbuf); 2396 1.160 dholland nd.ni_pathbuf = NULL; 2397 1.160 dholland } 2398 1.144 bouyer } 2399 1.120 chs if (dirp) 2400 1.120 chs vrele(dirp); 2401 1.1 cgd if (pathcp) 2402 1.56 thorpej free(pathcp, M_TEMP); 2403 1.1 cgd return (error); 2404 1.1 cgd } 2405 1.1 cgd 2406 1.1 cgd /* 2407 1.1 cgd * nfs mkdir service 2408 1.1 cgd */ 2409 1.22 christos int 2410 1.143 dsl nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 2411 1.1 cgd { 2412 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2413 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 2414 1.126 christos char *dpos = nfsd->nd_dpos; 2415 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 2416 1.23 fvdl struct vattr va, dirfor, diraft; 2417 1.54 augustss struct nfs_fattr *fp; 2418 1.1 cgd struct nameidata nd; 2419 1.126 christos char *cp; 2420 1.54 augustss u_int32_t *tl; 2421 1.54 augustss int32_t t1; 2422 1.126 christos char *bpos; 2423 1.103 christos int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1; 2424 1.144 bouyer int abort = 0; 2425 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 2426 1.1 cgd char *cp2; 2427 1.166 martin struct mbuf *mb, *mreq __unused; 2428 1.23 fvdl struct vnode *vp, *dirp = (struct vnode *)0; 2429 1.117 yamt nfsrvfh_t nsfh; 2430 1.15 mycroft u_quad_t frev; 2431 1.1 cgd 2432 1.117 yamt nfsm_srvmtofh(&nsfh); 2433 1.23 fvdl nfsm_srvnamesiz(len); 2434 1.15 mycroft nd.ni_cnd.cn_cred = cred; 2435 1.15 mycroft nd.ni_cnd.cn_nameiop = CREATE; 2436 1.15 mycroft nd.ni_cnd.cn_flags = LOCKPARENT; 2437 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 2438 1.183 hannken &dirp, (v3 ? &dirfor_ret : NULL), &dirfor, 2439 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 2440 1.23 fvdl if (error) { 2441 1.152 dholland if (nd.ni_pathbuf != NULL) { 2442 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 2443 1.160 dholland nd.ni_pathbuf = NULL; 2444 1.152 dholland } 2445 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 2446 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2447 1.23 fvdl if (dirp) 2448 1.23 fvdl vrele(dirp); 2449 1.23 fvdl return (0); 2450 1.23 fvdl } 2451 1.144 bouyer abort = 1; 2452 1.150 pooka vattr_null(&va); 2453 1.23 fvdl if (v3) { 2454 1.92 yamt va.va_mode = 0; 2455 1.23 fvdl nfsm_srvsattr(&va); 2456 1.23 fvdl } else { 2457 1.23 fvdl nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2458 1.23 fvdl va.va_mode = nfstov_mode(*tl++); 2459 1.23 fvdl } 2460 1.18 mycroft va.va_type = VDIR; 2461 1.1 cgd vp = nd.ni_vp; 2462 1.1 cgd if (vp != NULL) { 2463 1.15 mycroft VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2464 1.1 cgd if (nd.ni_dvp == vp) 2465 1.1 cgd vrele(nd.ni_dvp); 2466 1.1 cgd else 2467 1.1 cgd vput(nd.ni_dvp); 2468 1.1 cgd vrele(vp); 2469 1.1 cgd error = EEXIST; 2470 1.23 fvdl goto out; 2471 1.1 cgd } 2472 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 2473 1.23 fvdl error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 2474 1.23 fvdl if (!error) { 2475 1.23 fvdl vp = nd.ni_vp; 2476 1.170 hannken vn_lock(vp, LK_SHARED | LK_RETRY); 2477 1.117 yamt error = nfsrv_composefh(vp, &nsfh, v3); 2478 1.23 fvdl if (!error) 2479 1.131 pooka error = VOP_GETATTR(vp, &va, cred); 2480 1.1 cgd vput(vp); 2481 1.1 cgd } 2482 1.169 hannken vput(nd.ni_dvp); 2483 1.23 fvdl out: 2484 1.23 fvdl if (dirp) { 2485 1.120 chs if (v3) { 2486 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 2487 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 2488 1.161 hannken VOP_UNLOCK(dirp); 2489 1.120 chs } 2490 1.23 fvdl vrele(dirp); 2491 1.144 bouyer dirp = NULL; 2492 1.23 fvdl } 2493 1.160 dholland if (nd.ni_pathbuf != NULL) { 2494 1.160 dholland pathbuf_destroy(nd.ni_pathbuf); 2495 1.160 dholland nd.ni_pathbuf = NULL; 2496 1.160 dholland } 2497 1.144 bouyer abort = 0; 2498 1.117 yamt nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPATTR(v3) + 2499 1.117 yamt NFSX_WCCDATA(v3)); 2500 1.23 fvdl if (v3) { 2501 1.23 fvdl if (!error) { 2502 1.117 yamt nfsm_srvpostop_fh(&nsfh); 2503 1.23 fvdl nfsm_srvpostop_attr(0, &va); 2504 1.23 fvdl } 2505 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2506 1.23 fvdl } else { 2507 1.117 yamt nfsm_srvfhtom(&nsfh, v3); 2508 1.23 fvdl nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR); 2509 1.23 fvdl nfsm_srvfillattr(&va, fp); 2510 1.23 fvdl } 2511 1.23 fvdl return (0); 2512 1.1 cgd nfsmout: 2513 1.144 bouyer if (abort) { 2514 1.144 bouyer VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2515 1.144 bouyer if (nd.ni_dvp == nd.ni_vp) 2516 1.144 bouyer vrele(nd.ni_dvp); 2517 1.144 bouyer else 2518 1.144 bouyer vput(nd.ni_dvp); 2519 1.144 bouyer if (nd.ni_vp) 2520 1.144 bouyer vrele(nd.ni_vp); 2521 1.160 dholland if (nd.ni_pathbuf != NULL) { 2522 1.160 dholland pathbuf_destroy(nd.ni_pathbuf); 2523 1.160 dholland nd.ni_pathbuf = NULL; 2524 1.160 dholland } 2525 1.144 bouyer } 2526 1.120 chs if (dirp) 2527 1.120 chs vrele(dirp); 2528 1.1 cgd return (error); 2529 1.1 cgd } 2530 1.1 cgd 2531 1.1 cgd /* 2532 1.1 cgd * nfs rmdir service 2533 1.1 cgd */ 2534 1.22 christos int 2535 1.143 dsl nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 2536 1.1 cgd { 2537 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2538 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 2539 1.126 christos char *dpos = nfsd->nd_dpos; 2540 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 2541 1.54 augustss u_int32_t *tl; 2542 1.54 augustss int32_t t1; 2543 1.126 christos char *bpos; 2544 1.103 christos int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1; 2545 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 2546 1.1 cgd char *cp2; 2547 1.166 martin struct mbuf *mb, *mreq __unused; 2548 1.23 fvdl struct vnode *vp, *dirp = (struct vnode *)0; 2549 1.23 fvdl struct vattr dirfor, diraft; 2550 1.117 yamt nfsrvfh_t nsfh; 2551 1.1 cgd struct nameidata nd; 2552 1.15 mycroft u_quad_t frev; 2553 1.1 cgd 2554 1.117 yamt nfsm_srvmtofh(&nsfh); 2555 1.23 fvdl nfsm_srvnamesiz(len); 2556 1.15 mycroft nd.ni_cnd.cn_cred = cred; 2557 1.15 mycroft nd.ni_cnd.cn_nameiop = DELETE; 2558 1.15 mycroft nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 2559 1.117 yamt error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos, 2560 1.183 hannken &dirp, (v3 ? &dirfor_ret : NULL), &dirfor, 2561 1.183 hannken lwp, (nfsd->nd_flag & ND_KERBAUTH), false); 2562 1.23 fvdl if (error) { 2563 1.152 dholland if (nd.ni_pathbuf != NULL) { 2564 1.152 dholland pathbuf_destroy(nd.ni_pathbuf); 2565 1.160 dholland nd.ni_pathbuf = NULL; 2566 1.152 dholland } 2567 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 2568 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2569 1.23 fvdl if (dirp) 2570 1.23 fvdl vrele(dirp); 2571 1.23 fvdl return (0); 2572 1.23 fvdl } 2573 1.1 cgd vp = nd.ni_vp; 2574 1.1 cgd if (vp->v_type != VDIR) { 2575 1.1 cgd error = ENOTDIR; 2576 1.1 cgd goto out; 2577 1.1 cgd } 2578 1.1 cgd /* 2579 1.1 cgd * No rmdir "." please. 2580 1.1 cgd */ 2581 1.1 cgd if (nd.ni_dvp == vp) { 2582 1.1 cgd error = EINVAL; 2583 1.1 cgd goto out; 2584 1.1 cgd } 2585 1.1 cgd /* 2586 1.1 cgd * The root of a mounted filesystem cannot be deleted. 2587 1.1 cgd */ 2588 1.130 ad if (vp->v_vflag & VV_ROOT) 2589 1.1 cgd error = EBUSY; 2590 1.1 cgd out: 2591 1.1 cgd if (!error) { 2592 1.23 fvdl nqsrv_getl(nd.ni_dvp, ND_WRITE); 2593 1.23 fvdl nqsrv_getl(vp, ND_WRITE); 2594 1.15 mycroft error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2595 1.173 riastrad vput(nd.ni_dvp); 2596 1.1 cgd } else { 2597 1.15 mycroft VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2598 1.1 cgd if (nd.ni_dvp == nd.ni_vp) 2599 1.1 cgd vrele(nd.ni_dvp); 2600 1.1 cgd else 2601 1.1 cgd vput(nd.ni_dvp); 2602 1.1 cgd vput(vp); 2603 1.1 cgd } 2604 1.160 dholland if (nd.ni_pathbuf != NULL) { 2605 1.160 dholland pathbuf_destroy(nd.ni_pathbuf); 2606 1.160 dholland nd.ni_pathbuf = NULL; 2607 1.160 dholland } 2608 1.23 fvdl if (dirp) { 2609 1.120 chs if (v3) { 2610 1.161 hannken vn_lock(dirp, LK_SHARED | LK_RETRY); 2611 1.131 pooka diraft_ret = VOP_GETATTR(dirp, &diraft, cred); 2612 1.161 hannken VOP_UNLOCK(dirp); 2613 1.120 chs } 2614 1.23 fvdl vrele(dirp); 2615 1.23 fvdl } 2616 1.23 fvdl nfsm_reply(NFSX_WCCDATA(v3)); 2617 1.23 fvdl if (v3) { 2618 1.23 fvdl nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); 2619 1.23 fvdl return (0); 2620 1.23 fvdl } 2621 1.1 cgd nfsm_srvdone; 2622 1.1 cgd } 2623 1.1 cgd 2624 1.1 cgd /* 2625 1.1 cgd * nfs readdir service 2626 1.1 cgd * - mallocs what it thinks is enough to read 2627 1.98 yamt * count rounded up to a multiple of NFS_SRVDIRBLKSIZ <= NFS_MAXREADDIR 2628 1.1 cgd * - calls VOP_READDIR() 2629 1.1 cgd * - loops around building the reply 2630 1.1 cgd * if the output generated exceeds count break out of loop 2631 1.1 cgd * The nfsm_clget macro is used here so that the reply will be packed 2632 1.1 cgd * tightly in mbuf clusters. 2633 1.1 cgd * - it only knows that it has encountered eof when the VOP_READDIR() 2634 1.1 cgd * reads nothing 2635 1.1 cgd * - as such one readdir rpc will return eof false although you are there 2636 1.1 cgd * and then the next will return eof 2637 1.11 ws * - it trims out records with d_fileno == 0 2638 1.1 cgd * this doesn't matter for Unix clients, but they might confuse clients 2639 1.1 cgd * for other os'. 2640 1.25 jtk * - it trims out records with d_type == DT_WHT 2641 1.25 jtk * these cannot be seen through NFS (unless we extend the protocol) 2642 1.1 cgd * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2643 1.1 cgd * than requested, but this may not apply to all filesystems. For 2644 1.1 cgd * example, client NFS does not { although it is never remote mounted 2645 1.1 cgd * anyhow } 2646 1.23 fvdl * The alternate call nfsrv_readdirplus() does lookups as well. 2647 1.1 cgd * PS: The NFS protocol spec. does not clarify what the "count" byte 2648 1.1 cgd * argument is a count of.. just name strings and file id's or the 2649 1.1 cgd * entire reply rpc or ... 2650 1.1 cgd * I tried just file name and id sizes and it confused the Sun client, 2651 1.1 cgd * so I am using the full rpc size now. The "paranoia.." comment refers 2652 1.1 cgd * to including the status longwords that are not a part of the dir. 2653 1.1 cgd * "entry" structures, but are in the rpc. 2654 1.1 cgd */ 2655 1.98 yamt 2656 1.98 yamt #define NFS_SRVDIRBLKSIZ 1024 2657 1.98 yamt 2658 1.15 mycroft struct flrep { 2659 1.23 fvdl nfsuint64 fl_off; 2660 1.23 fvdl u_int32_t fl_postopok; 2661 1.140 pooka struct nfs_fattr fl_fattr; /* XXX: must be of fattr3 size */ 2662 1.23 fvdl u_int32_t fl_fhok; 2663 1.23 fvdl u_int32_t fl_fhsize; 2664 1.140 pooka /* handle comes here, filled in dynamically */ 2665 1.15 mycroft }; 2666 1.15 mycroft 2667 1.22 christos int 2668 1.143 dsl nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 2669 1.1 cgd { 2670 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2671 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 2672 1.126 christos char *dpos = nfsd->nd_dpos; 2673 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 2674 1.54 augustss char *bp, *be; 2675 1.54 augustss struct mbuf *mp; 2676 1.54 augustss struct dirent *dp; 2677 1.126 christos char *cp; 2678 1.54 augustss u_int32_t *tl; 2679 1.54 augustss int32_t t1; 2680 1.126 christos char *bpos; 2681 1.166 martin struct mbuf *mb, *mreq __unused, *mp2; 2682 1.15 mycroft char *cpos, *cend, *cp2, *rbuf; 2683 1.1 cgd struct vnode *vp; 2684 1.23 fvdl struct vattr at; 2685 1.117 yamt nfsrvfh_t nsfh; 2686 1.1 cgd struct uio io; 2687 1.1 cgd struct iovec iv; 2688 1.23 fvdl int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2689 1.103 christos int siz, cnt, fullsiz, eofflag, rdonly, cache = 0, ncookies; 2690 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 2691 1.166 martin u_quad_t frev, off, toff; 2692 1.166 martin #ifdef NFS3_STRICTVERF 2693 1.166 martin u_quad_t verf; 2694 1.166 martin #endif 2695 1.38 fvdl off_t *cookies = NULL, *cookiep; 2696 1.38 fvdl nfsuint64 jar; 2697 1.15 mycroft 2698 1.117 yamt nfsm_srvmtofh(&nsfh); 2699 1.23 fvdl if (v3) { 2700 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2701 1.48 fair toff = fxdr_hyper(tl); 2702 1.23 fvdl tl += 2; 2703 1.166 martin #ifdef NFS3_STRICTVERF 2704 1.48 fair verf = fxdr_hyper(tl); 2705 1.166 martin #endif 2706 1.23 fvdl tl += 2; 2707 1.23 fvdl } else { 2708 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2709 1.23 fvdl toff = fxdr_unsigned(u_quad_t, *tl++); 2710 1.23 fvdl } 2711 1.23 fvdl off = toff; 2712 1.1 cgd cnt = fxdr_unsigned(int, *tl); 2713 1.98 yamt siz = ((cnt + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1)); 2714 1.23 fvdl xfer = NFS_SRVMAXDATA(nfsd); 2715 1.23 fvdl if (siz > xfer) 2716 1.23 fvdl siz = xfer; 2717 1.1 cgd fullsiz = siz; 2718 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 2719 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 2720 1.39 fvdl if (!error && vp->v_type != VDIR) { 2721 1.39 fvdl error = ENOTDIR; 2722 1.39 fvdl vput(vp); 2723 1.39 fvdl } 2724 1.23 fvdl if (error) { 2725 1.23 fvdl nfsm_reply(NFSX_UNSIGNED); 2726 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2727 1.23 fvdl return (0); 2728 1.23 fvdl } 2729 1.23 fvdl nqsrv_getl(vp, ND_READ); 2730 1.23 fvdl if (v3) { 2731 1.131 pooka error = getret = VOP_GETATTR(vp, &at, cred); 2732 1.23 fvdl #ifdef NFS3_STRICTVERF 2733 1.23 fvdl /* 2734 1.23 fvdl * XXX This check is too strict for Solaris 2.5 clients. 2735 1.23 fvdl */ 2736 1.23 fvdl if (!error && toff && verf != at.va_filerev) 2737 1.23 fvdl error = NFSERR_BAD_COOKIE; 2738 1.23 fvdl #endif 2739 1.23 fvdl } 2740 1.23 fvdl if (!error) 2741 1.99 christos error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0); 2742 1.22 christos if (error) { 2743 1.1 cgd vput(vp); 2744 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3)); 2745 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2746 1.23 fvdl return (0); 2747 1.1 cgd } 2748 1.151 hannken VOP_UNLOCK(vp); 2749 1.56 thorpej rbuf = malloc(siz, M_TEMP, M_WAITOK); 2750 1.1 cgd again: 2751 1.1 cgd iv.iov_base = rbuf; 2752 1.1 cgd iv.iov_len = fullsiz; 2753 1.1 cgd io.uio_iov = &iv; 2754 1.1 cgd io.uio_iovcnt = 1; 2755 1.15 mycroft io.uio_offset = (off_t)off; 2756 1.1 cgd io.uio_resid = fullsiz; 2757 1.1 cgd io.uio_rw = UIO_READ; 2758 1.101 yamt UIO_SETUP_SYSSPACE(&io); 2759 1.23 fvdl eofflag = 0; 2760 1.42 fvdl vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2761 1.23 fvdl 2762 1.42 fvdl error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies); 2763 1.23 fvdl 2764 1.15 mycroft off = (off_t)io.uio_offset; 2765 1.23 fvdl if (!cookies && !error) 2766 1.23 fvdl error = NFSERR_PERM; 2767 1.23 fvdl if (v3) { 2768 1.131 pooka getret = VOP_GETATTR(vp, &at, cred); 2769 1.23 fvdl if (!error) 2770 1.23 fvdl error = getret; 2771 1.23 fvdl } 2772 1.23 fvdl 2773 1.151 hannken VOP_UNLOCK(vp); 2774 1.1 cgd if (error) { 2775 1.1 cgd vrele(vp); 2776 1.126 christos free((void *)rbuf, M_TEMP); 2777 1.23 fvdl if (cookies) 2778 1.126 christos free((void *)cookies, M_TEMP); 2779 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3)); 2780 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2781 1.23 fvdl return (0); 2782 1.1 cgd } 2783 1.1 cgd if (io.uio_resid) { 2784 1.1 cgd siz -= io.uio_resid; 2785 1.1 cgd 2786 1.1 cgd /* 2787 1.1 cgd * If nothing read, return eof 2788 1.1 cgd * rpc reply 2789 1.1 cgd */ 2790 1.1 cgd if (siz == 0) { 2791 1.1 cgd vrele(vp); 2792 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + 2793 1.23 fvdl 2 * NFSX_UNSIGNED); 2794 1.23 fvdl if (v3) { 2795 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2796 1.23 fvdl nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2797 1.48 fair txdr_hyper(at.va_filerev, tl); 2798 1.23 fvdl tl += 2; 2799 1.23 fvdl } else 2800 1.23 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2801 1.1 cgd *tl++ = nfs_false; 2802 1.1 cgd *tl = nfs_true; 2803 1.126 christos free((void *)rbuf, M_TEMP); 2804 1.126 christos free((void *)cookies, M_TEMP); 2805 1.1 cgd return (0); 2806 1.1 cgd } 2807 1.1 cgd } 2808 1.1 cgd 2809 1.1 cgd /* 2810 1.1 cgd * Check for degenerate cases of nothing useful read. 2811 1.1 cgd * If so go try again 2812 1.1 cgd */ 2813 1.8 ws cpos = rbuf; 2814 1.1 cgd cend = rbuf + siz; 2815 1.23 fvdl dp = (struct dirent *)cpos; 2816 1.23 fvdl cookiep = cookies; 2817 1.23 fvdl 2818 1.28 fvdl while (cpos < cend && ncookies > 0 && 2819 1.28 fvdl (dp->d_fileno == 0 || dp->d_type == DT_WHT)) { 2820 1.23 fvdl cpos += dp->d_reclen; 2821 1.11 ws dp = (struct dirent *)cpos; 2822 1.23 fvdl cookiep++; 2823 1.23 fvdl ncookies--; 2824 1.1 cgd } 2825 1.23 fvdl if (cpos >= cend || ncookies == 0) { 2826 1.23 fvdl toff = off; 2827 1.1 cgd siz = fullsiz; 2828 1.115 christos free(cookies, M_TEMP); 2829 1.124 pooka cookies = NULL; 2830 1.1 cgd goto again; 2831 1.1 cgd } 2832 1.1 cgd 2833 1.23 fvdl len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 2834 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); 2835 1.23 fvdl if (v3) { 2836 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2837 1.23 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2838 1.48 fair txdr_hyper(at.va_filerev, tl); 2839 1.23 fvdl } 2840 1.15 mycroft mp = mp2 = mb; 2841 1.15 mycroft bp = bpos; 2842 1.15 mycroft be = bp + M_TRAILINGSPACE(mp); 2843 1.15 mycroft 2844 1.15 mycroft /* Loop through the records and build reply */ 2845 1.23 fvdl while (cpos < cend && ncookies > 0) { 2846 1.25 jtk if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { 2847 1.15 mycroft nlen = dp->d_namlen; 2848 1.15 mycroft rem = nfsm_rndup(nlen)-nlen; 2849 1.23 fvdl len += (4 * NFSX_UNSIGNED + nlen + rem); 2850 1.23 fvdl if (v3) 2851 1.23 fvdl len += 2 * NFSX_UNSIGNED; 2852 1.15 mycroft if (len > cnt) { 2853 1.15 mycroft eofflag = 0; 2854 1.15 mycroft break; 2855 1.15 mycroft } 2856 1.15 mycroft /* 2857 1.15 mycroft * Build the directory record xdr from 2858 1.15 mycroft * the dirent entry. 2859 1.15 mycroft */ 2860 1.15 mycroft nfsm_clget; 2861 1.15 mycroft *tl = nfs_true; 2862 1.15 mycroft bp += NFSX_UNSIGNED; 2863 1.23 fvdl if (v3) { 2864 1.23 fvdl nfsm_clget; 2865 1.96 yamt *tl = txdr_unsigned(dp->d_fileno >> 32); 2866 1.23 fvdl bp += NFSX_UNSIGNED; 2867 1.23 fvdl } 2868 1.15 mycroft nfsm_clget; 2869 1.15 mycroft *tl = txdr_unsigned(dp->d_fileno); 2870 1.15 mycroft bp += NFSX_UNSIGNED; 2871 1.15 mycroft nfsm_clget; 2872 1.15 mycroft *tl = txdr_unsigned(nlen); 2873 1.15 mycroft bp += NFSX_UNSIGNED; 2874 1.94 perry 2875 1.15 mycroft /* And loop around copying the name */ 2876 1.15 mycroft xfer = nlen; 2877 1.15 mycroft cp = dp->d_name; 2878 1.15 mycroft while (xfer > 0) { 2879 1.15 mycroft nfsm_clget; 2880 1.15 mycroft if ((bp+xfer) > be) 2881 1.15 mycroft tsiz = be-bp; 2882 1.15 mycroft else 2883 1.15 mycroft tsiz = xfer; 2884 1.44 perry memcpy(bp, cp, tsiz); 2885 1.15 mycroft bp += tsiz; 2886 1.15 mycroft xfer -= tsiz; 2887 1.15 mycroft if (xfer > 0) 2888 1.15 mycroft cp += tsiz; 2889 1.15 mycroft } 2890 1.23 fvdl /* And null pad to an int32_t boundary */ 2891 1.15 mycroft for (i = 0; i < rem; i++) 2892 1.15 mycroft *bp++ = '\0'; 2893 1.15 mycroft nfsm_clget; 2894 1.94 perry 2895 1.15 mycroft /* Finish off the record */ 2896 1.48 fair txdr_hyper(*cookiep, &jar); 2897 1.23 fvdl if (v3) { 2898 1.38 fvdl *tl = jar.nfsuquad[0]; 2899 1.23 fvdl bp += NFSX_UNSIGNED; 2900 1.23 fvdl nfsm_clget; 2901 1.23 fvdl } 2902 1.38 fvdl *tl = jar.nfsuquad[1]; 2903 1.15 mycroft bp += NFSX_UNSIGNED; 2904 1.15 mycroft } 2905 1.15 mycroft cpos += dp->d_reclen; 2906 1.15 mycroft dp = (struct dirent *)cpos; 2907 1.23 fvdl cookiep++; 2908 1.23 fvdl ncookies--; 2909 1.15 mycroft } 2910 1.1 cgd vrele(vp); 2911 1.15 mycroft nfsm_clget; 2912 1.15 mycroft *tl = nfs_false; 2913 1.15 mycroft bp += NFSX_UNSIGNED; 2914 1.15 mycroft nfsm_clget; 2915 1.15 mycroft if (eofflag) 2916 1.15 mycroft *tl = nfs_true; 2917 1.15 mycroft else 2918 1.15 mycroft *tl = nfs_false; 2919 1.15 mycroft bp += NFSX_UNSIGNED; 2920 1.15 mycroft if (mp != mb) { 2921 1.15 mycroft if (bp < be) 2922 1.126 christos mp->m_len = bp - mtod(mp, char *); 2923 1.15 mycroft } else 2924 1.15 mycroft mp->m_len += bp - bpos; 2925 1.126 christos free((void *)rbuf, M_TEMP); 2926 1.126 christos free((void *)cookies, M_TEMP); 2927 1.15 mycroft nfsm_srvdone; 2928 1.15 mycroft } 2929 1.15 mycroft 2930 1.22 christos int 2931 1.143 dsl nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 2932 1.15 mycroft { 2933 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 2934 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 2935 1.126 christos char *dpos = nfsd->nd_dpos; 2936 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 2937 1.54 augustss char *bp, *be; 2938 1.54 augustss struct mbuf *mp; 2939 1.54 augustss struct dirent *dp; 2940 1.126 christos char *cp; 2941 1.54 augustss u_int32_t *tl; 2942 1.54 augustss int32_t t1; 2943 1.126 christos char *bpos; 2944 1.166 martin struct mbuf *mb, *mreq __unused, *mp2; 2945 1.15 mycroft char *cpos, *cend, *cp2, *rbuf; 2946 1.15 mycroft struct vnode *vp, *nvp; 2947 1.15 mycroft struct flrep fl; 2948 1.117 yamt nfsrvfh_t nsfh; 2949 1.15 mycroft struct uio io; 2950 1.15 mycroft struct iovec iv; 2951 1.23 fvdl struct vattr va, at, *vap = &va; 2952 1.23 fvdl struct nfs_fattr *fp; 2953 1.23 fvdl int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; 2954 1.103 christos int siz, cnt, fullsiz, eofflag, rdonly, cache = 0, dirlen, ncookies; 2955 1.166 martin u_quad_t frev, off, toff; 2956 1.166 martin #ifdef NFS3_STRICTVERF 2957 1.166 martin u_quad_t verf; 2958 1.166 martin #endif 2959 1.38 fvdl off_t *cookies = NULL, *cookiep; 2960 1.15 mycroft 2961 1.117 yamt nfsm_srvmtofh(&nsfh); 2962 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2963 1.48 fair toff = fxdr_hyper(tl); 2964 1.23 fvdl tl += 2; 2965 1.166 martin #ifdef NFS3_STRICTVERF 2966 1.48 fair verf = fxdr_hyper(tl); 2967 1.166 martin #endif 2968 1.23 fvdl tl += 2; 2969 1.23 fvdl siz = fxdr_unsigned(int, *tl++); 2970 1.23 fvdl cnt = fxdr_unsigned(int, *tl); 2971 1.23 fvdl off = toff; 2972 1.98 yamt siz = ((siz + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1)); 2973 1.23 fvdl xfer = NFS_SRVMAXDATA(nfsd); 2974 1.23 fvdl if (siz > xfer) 2975 1.23 fvdl siz = xfer; 2976 1.15 mycroft fullsiz = siz; 2977 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 2978 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 2979 1.39 fvdl if (!error && vp->v_type != VDIR) { 2980 1.39 fvdl error = ENOTDIR; 2981 1.39 fvdl vput(vp); 2982 1.39 fvdl } 2983 1.23 fvdl if (error) { 2984 1.23 fvdl nfsm_reply(NFSX_UNSIGNED); 2985 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 2986 1.23 fvdl return (0); 2987 1.23 fvdl } 2988 1.131 pooka error = getret = VOP_GETATTR(vp, &at, cred); 2989 1.23 fvdl #ifdef NFS3_STRICTVERF 2990 1.23 fvdl /* 2991 1.23 fvdl * XXX This check is too strict for Solaris 2.5 clients. 2992 1.23 fvdl */ 2993 1.23 fvdl if (!error && toff && verf != at.va_filerev) 2994 1.23 fvdl error = NFSERR_BAD_COOKIE; 2995 1.23 fvdl #endif 2996 1.23 fvdl if (!error) { 2997 1.23 fvdl nqsrv_getl(vp, ND_READ); 2998 1.99 christos error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0); 2999 1.23 fvdl } 3000 1.22 christos if (error) { 3001 1.15 mycroft vput(vp); 3002 1.23 fvdl nfsm_reply(NFSX_V3POSTOPATTR); 3003 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3004 1.23 fvdl return (0); 3005 1.15 mycroft } 3006 1.151 hannken VOP_UNLOCK(vp); 3007 1.23 fvdl 3008 1.56 thorpej rbuf = malloc(siz, M_TEMP, M_WAITOK); 3009 1.15 mycroft again: 3010 1.15 mycroft iv.iov_base = rbuf; 3011 1.15 mycroft iv.iov_len = fullsiz; 3012 1.15 mycroft io.uio_iov = &iv; 3013 1.15 mycroft io.uio_iovcnt = 1; 3014 1.15 mycroft io.uio_offset = (off_t)off; 3015 1.15 mycroft io.uio_resid = fullsiz; 3016 1.15 mycroft io.uio_rw = UIO_READ; 3017 1.101 yamt UIO_SETUP_SYSSPACE(&io); 3018 1.23 fvdl eofflag = 0; 3019 1.23 fvdl 3020 1.42 fvdl vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 3021 1.42 fvdl 3022 1.42 fvdl error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies); 3023 1.23 fvdl 3024 1.23 fvdl off = (u_quad_t)io.uio_offset; 3025 1.131 pooka getret = VOP_GETATTR(vp, &at, cred); 3026 1.23 fvdl 3027 1.151 hannken VOP_UNLOCK(vp); 3028 1.36 fvdl 3029 1.36 fvdl /* 3030 1.36 fvdl * If the VGET operation doesn't work for this filesystem, 3031 1.36 fvdl * we can't support readdirplus. Returning NOTSUPP should 3032 1.36 fvdl * make clients fall back to plain readdir. 3033 1.36 fvdl * There's no need to check for VPTOFH as well, we wouldn't 3034 1.36 fvdl * even be here otherwise. 3035 1.36 fvdl */ 3036 1.36 fvdl if (!getret) { 3037 1.179 ad if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, 3038 1.179 ad LK_EXCLUSIVE, &nvp))) 3039 1.36 fvdl getret = (getret == EOPNOTSUPP) ? 3040 1.36 fvdl NFSERR_NOTSUPP : NFSERR_IO; 3041 1.36 fvdl else 3042 1.36 fvdl vput(nvp); 3043 1.36 fvdl } 3044 1.36 fvdl 3045 1.23 fvdl if (!cookies && !error) 3046 1.23 fvdl error = NFSERR_PERM; 3047 1.23 fvdl if (!error) 3048 1.23 fvdl error = getret; 3049 1.15 mycroft if (error) { 3050 1.15 mycroft vrele(vp); 3051 1.23 fvdl if (cookies) 3052 1.126 christos free((void *)cookies, M_TEMP); 3053 1.126 christos free((void *)rbuf, M_TEMP); 3054 1.23 fvdl nfsm_reply(NFSX_V3POSTOPATTR); 3055 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3056 1.23 fvdl return (0); 3057 1.15 mycroft } 3058 1.15 mycroft if (io.uio_resid) { 3059 1.15 mycroft siz -= io.uio_resid; 3060 1.15 mycroft 3061 1.15 mycroft /* 3062 1.15 mycroft * If nothing read, return eof 3063 1.15 mycroft * rpc reply 3064 1.15 mycroft */ 3065 1.15 mycroft if (siz == 0) { 3066 1.15 mycroft vrele(vp); 3067 1.23 fvdl nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 3068 1.23 fvdl 2 * NFSX_UNSIGNED); 3069 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3070 1.23 fvdl nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 3071 1.48 fair txdr_hyper(at.va_filerev, tl); 3072 1.23 fvdl tl += 2; 3073 1.15 mycroft *tl++ = nfs_false; 3074 1.15 mycroft *tl = nfs_true; 3075 1.126 christos free((void *)cookies, M_TEMP); 3076 1.126 christos free((void *)rbuf, M_TEMP); 3077 1.15 mycroft return (0); 3078 1.15 mycroft } 3079 1.15 mycroft } 3080 1.15 mycroft 3081 1.15 mycroft /* 3082 1.15 mycroft * Check for degenerate cases of nothing useful read. 3083 1.15 mycroft * If so go try again 3084 1.15 mycroft */ 3085 1.15 mycroft cpos = rbuf; 3086 1.15 mycroft cend = rbuf + siz; 3087 1.23 fvdl dp = (struct dirent *)cpos; 3088 1.23 fvdl cookiep = cookies; 3089 1.23 fvdl 3090 1.29 fvdl while (cpos < cend && ncookies > 0 && 3091 1.29 fvdl (dp->d_fileno == 0 || dp->d_type == DT_WHT)) { 3092 1.23 fvdl cpos += dp->d_reclen; 3093 1.15 mycroft dp = (struct dirent *)cpos; 3094 1.23 fvdl cookiep++; 3095 1.23 fvdl ncookies--; 3096 1.15 mycroft } 3097 1.23 fvdl if (cpos >= cend || ncookies == 0) { 3098 1.23 fvdl toff = off; 3099 1.15 mycroft siz = fullsiz; 3100 1.115 christos free(cookies, M_TEMP); 3101 1.124 pooka cookies = NULL; 3102 1.15 mycroft goto again; 3103 1.15 mycroft } 3104 1.15 mycroft 3105 1.23 fvdl dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; 3106 1.23 fvdl nfsm_reply(cnt); 3107 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3108 1.23 fvdl nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3109 1.48 fair txdr_hyper(at.va_filerev, tl); 3110 1.15 mycroft mp = mp2 = mb; 3111 1.15 mycroft bp = bpos; 3112 1.15 mycroft be = bp + M_TRAILINGSPACE(mp); 3113 1.1 cgd 3114 1.1 cgd /* Loop through the records and build reply */ 3115 1.23 fvdl while (cpos < cend && ncookies > 0) { 3116 1.25 jtk if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { 3117 1.117 yamt nfsrvfh_t nnsfh; 3118 1.117 yamt 3119 1.1 cgd nlen = dp->d_namlen; 3120 1.1 cgd rem = nfsm_rndup(nlen)-nlen; 3121 1.94 perry 3122 1.1 cgd /* 3123 1.15 mycroft * For readdir_and_lookup get the vnode using 3124 1.15 mycroft * the file number. 3125 1.1 cgd */ 3126 1.179 ad if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, 3127 1.179 ad &nvp)) 3128 1.15 mycroft goto invalid; 3129 1.125 thorpej if (nfsrv_composefh(nvp, &nnsfh, true)) { 3130 1.15 mycroft vput(nvp); 3131 1.15 mycroft goto invalid; 3132 1.15 mycroft } 3133 1.131 pooka if (VOP_GETATTR(nvp, vap, cred)) { 3134 1.15 mycroft vput(nvp); 3135 1.15 mycroft goto invalid; 3136 1.15 mycroft } 3137 1.15 mycroft vput(nvp); 3138 1.23 fvdl 3139 1.23 fvdl /* 3140 1.23 fvdl * If either the dircount or maxcount will be 3141 1.23 fvdl * exceeded, get out now. Both of these lengths 3142 1.23 fvdl * are calculated conservatively, including all 3143 1.23 fvdl * XDR overheads. 3144 1.23 fvdl */ 3145 1.52 fvdl len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH + 3146 1.23 fvdl NFSX_V3POSTOPATTR); 3147 1.23 fvdl dirlen += (6 * NFSX_UNSIGNED + nlen + rem); 3148 1.23 fvdl if (len > cnt || dirlen > fullsiz) { 3149 1.1 cgd eofflag = 0; 3150 1.1 cgd break; 3151 1.1 cgd } 3152 1.23 fvdl 3153 1.15 mycroft /* 3154 1.15 mycroft * Build the directory record xdr from 3155 1.15 mycroft * the dirent entry. 3156 1.15 mycroft */ 3157 1.23 fvdl fp = (struct nfs_fattr *)&fl.fl_fattr; 3158 1.23 fvdl nfsm_srvfillattr(vap, fp); 3159 1.23 fvdl fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 3160 1.23 fvdl fl.fl_fhok = nfs_true; 3161 1.23 fvdl fl.fl_postopok = nfs_true; 3162 1.48 fair txdr_hyper(*cookiep, fl.fl_off.nfsuquad); 3163 1.23 fvdl 3164 1.1 cgd nfsm_clget; 3165 1.1 cgd *tl = nfs_true; 3166 1.1 cgd bp += NFSX_UNSIGNED; 3167 1.23 fvdl nfsm_clget; 3168 1.96 yamt *tl = txdr_unsigned(dp->d_fileno >> 32); 3169 1.23 fvdl bp += NFSX_UNSIGNED; 3170 1.1 cgd nfsm_clget; 3171 1.11 ws *tl = txdr_unsigned(dp->d_fileno); 3172 1.1 cgd bp += NFSX_UNSIGNED; 3173 1.1 cgd nfsm_clget; 3174 1.1 cgd *tl = txdr_unsigned(nlen); 3175 1.1 cgd bp += NFSX_UNSIGNED; 3176 1.94 perry 3177 1.15 mycroft /* And loop around copying the name */ 3178 1.1 cgd xfer = nlen; 3179 1.1 cgd cp = dp->d_name; 3180 1.1 cgd while (xfer > 0) { 3181 1.1 cgd nfsm_clget; 3182 1.23 fvdl if ((bp + xfer) > be) 3183 1.23 fvdl tsiz = be - bp; 3184 1.1 cgd else 3185 1.1 cgd tsiz = xfer; 3186 1.44 perry memcpy(bp, cp, tsiz); 3187 1.1 cgd bp += tsiz; 3188 1.1 cgd xfer -= tsiz; 3189 1.1 cgd if (xfer > 0) 3190 1.1 cgd cp += tsiz; 3191 1.1 cgd } 3192 1.23 fvdl /* And null pad to an int32_t boundary */ 3193 1.1 cgd for (i = 0; i < rem; i++) 3194 1.1 cgd *bp++ = '\0'; 3195 1.94 perry 3196 1.23 fvdl /* 3197 1.23 fvdl * Now copy the flrep structure out. 3198 1.23 fvdl */ 3199 1.117 yamt xfer = sizeof(struct flrep); 3200 1.126 christos cp = (void *)&fl; 3201 1.23 fvdl while (xfer > 0) { 3202 1.23 fvdl nfsm_clget; 3203 1.23 fvdl if ((bp + xfer) > be) 3204 1.23 fvdl tsiz = be - bp; 3205 1.23 fvdl else 3206 1.23 fvdl tsiz = xfer; 3207 1.44 perry memcpy(bp, cp, tsiz); 3208 1.23 fvdl bp += tsiz; 3209 1.23 fvdl xfer -= tsiz; 3210 1.23 fvdl if (xfer > 0) 3211 1.23 fvdl cp += tsiz; 3212 1.23 fvdl } 3213 1.117 yamt 3214 1.117 yamt /* 3215 1.117 yamt * ... and filehandle. 3216 1.117 yamt */ 3217 1.117 yamt xfer = NFSRVFH_SIZE(&nnsfh); 3218 1.117 yamt cp = NFSRVFH_DATA(&nnsfh); 3219 1.117 yamt while (xfer > 0) { 3220 1.117 yamt nfsm_clget; 3221 1.117 yamt if ((bp + xfer) > be) 3222 1.117 yamt tsiz = be - bp; 3223 1.117 yamt else 3224 1.117 yamt tsiz = xfer; 3225 1.117 yamt memcpy(bp, cp, tsiz); 3226 1.117 yamt bp += tsiz; 3227 1.117 yamt xfer -= tsiz; 3228 1.117 yamt if (xfer > 0) 3229 1.117 yamt cp += tsiz; 3230 1.117 yamt } 3231 1.8 ws } 3232 1.15 mycroft invalid: 3233 1.1 cgd cpos += dp->d_reclen; 3234 1.11 ws dp = (struct dirent *)cpos; 3235 1.23 fvdl cookiep++; 3236 1.23 fvdl ncookies--; 3237 1.1 cgd } 3238 1.15 mycroft vrele(vp); 3239 1.1 cgd nfsm_clget; 3240 1.1 cgd *tl = nfs_false; 3241 1.1 cgd bp += NFSX_UNSIGNED; 3242 1.1 cgd nfsm_clget; 3243 1.1 cgd if (eofflag) 3244 1.1 cgd *tl = nfs_true; 3245 1.1 cgd else 3246 1.1 cgd *tl = nfs_false; 3247 1.1 cgd bp += NFSX_UNSIGNED; 3248 1.15 mycroft if (mp != mb) { 3249 1.15 mycroft if (bp < be) 3250 1.126 christos mp->m_len = bp - mtod(mp, char *); 3251 1.15 mycroft } else 3252 1.15 mycroft mp->m_len += bp - bpos; 3253 1.126 christos free((void *)cookies, M_TEMP); 3254 1.126 christos free((void *)rbuf, M_TEMP); 3255 1.23 fvdl nfsm_srvdone; 3256 1.23 fvdl } 3257 1.23 fvdl 3258 1.23 fvdl /* 3259 1.23 fvdl * nfs commit service 3260 1.23 fvdl */ 3261 1.23 fvdl int 3262 1.143 dsl nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 3263 1.23 fvdl { 3264 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3265 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 3266 1.126 christos char *dpos = nfsd->nd_dpos; 3267 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 3268 1.23 fvdl struct vattr bfor, aft; 3269 1.23 fvdl struct vnode *vp; 3270 1.117 yamt nfsrvfh_t nsfh; 3271 1.54 augustss u_int32_t *tl; 3272 1.54 augustss int32_t t1; 3273 1.126 christos char *bpos; 3274 1.103 christos int error = 0, rdonly, for_ret = 1, aft_ret = 1, cache = 0; 3275 1.93 yamt uint32_t cnt; 3276 1.23 fvdl char *cp2; 3277 1.166 martin struct mbuf *mb, *mreq __unused; 3278 1.65 bouyer u_quad_t frev, off, end; 3279 1.23 fvdl 3280 1.117 yamt nfsm_srvmtofh(&nsfh); 3281 1.23 fvdl nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3282 1.23 fvdl 3283 1.48 fair off = fxdr_hyper(tl); 3284 1.23 fvdl tl += 2; 3285 1.93 yamt cnt = fxdr_unsigned(uint32_t, *tl); 3286 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 3287 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 3288 1.23 fvdl if (error) { 3289 1.23 fvdl nfsm_reply(2 * NFSX_UNSIGNED); 3290 1.23 fvdl nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); 3291 1.23 fvdl return (0); 3292 1.23 fvdl } 3293 1.131 pooka for_ret = VOP_GETATTR(vp, &bfor, cred); 3294 1.65 bouyer end = (cnt > 0) ? off + cnt : vp->v_size; 3295 1.65 bouyer if (end < off || end > vp->v_size) 3296 1.65 bouyer end = vp->v_size; 3297 1.80 bouyer if (off < vp->v_size) 3298 1.131 pooka error = VOP_FSYNC(vp, cred, FSYNC_WAIT, off, end); 3299 1.80 bouyer /* else error == 0, from nfsrv_fhtovp() */ 3300 1.131 pooka aft_ret = VOP_GETATTR(vp, &aft, cred); 3301 1.23 fvdl vput(vp); 3302 1.23 fvdl nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); 3303 1.23 fvdl nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); 3304 1.23 fvdl if (!error) { 3305 1.23 fvdl nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF); 3306 1.178 thorpej struct timeval btv; 3307 1.178 thorpej getmicroboottime(&btv); 3308 1.178 thorpej *tl++ = txdr_unsigned(btv.tv_sec); 3309 1.178 thorpej *tl = txdr_unsigned(btv.tv_usec); 3310 1.82 hannken } else { 3311 1.23 fvdl return (0); 3312 1.82 hannken } 3313 1.1 cgd nfsm_srvdone; 3314 1.1 cgd } 3315 1.1 cgd 3316 1.1 cgd /* 3317 1.1 cgd * nfs statfs service 3318 1.1 cgd */ 3319 1.22 christos int 3320 1.143 dsl nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 3321 1.1 cgd { 3322 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3323 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 3324 1.126 christos char *dpos = nfsd->nd_dpos; 3325 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 3326 1.111 christos struct statvfs *sf = NULL; 3327 1.54 augustss struct nfs_statfs *sfp; 3328 1.54 augustss u_int32_t *tl; 3329 1.54 augustss int32_t t1; 3330 1.126 christos char *bpos; 3331 1.103 christos int error = 0, rdonly, cache = 0, getret = 1; 3332 1.23 fvdl int v3 = (nfsd->nd_flag & ND_NFSV3); 3333 1.1 cgd char *cp2; 3334 1.166 martin struct mbuf *mb, *mreq __unused; 3335 1.1 cgd struct vnode *vp; 3336 1.23 fvdl struct vattr at; 3337 1.117 yamt nfsrvfh_t nsfh; 3338 1.23 fvdl u_quad_t frev, tval; 3339 1.1 cgd 3340 1.117 yamt nfsm_srvmtofh(&nsfh); 3341 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 3342 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 3343 1.23 fvdl if (error) { 3344 1.23 fvdl nfsm_reply(NFSX_UNSIGNED); 3345 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3346 1.23 fvdl return (0); 3347 1.23 fvdl } 3348 1.111 christos sf = malloc(sizeof(*sf), M_TEMP, M_WAITOK); 3349 1.131 pooka error = VFS_STATVFS(vp->v_mount, sf); 3350 1.131 pooka getret = VOP_GETATTR(vp, &at, cred); 3351 1.1 cgd vput(vp); 3352 1.23 fvdl nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); 3353 1.23 fvdl if (v3) 3354 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3355 1.111 christos if (error) { 3356 1.111 christos free(sf, M_TEMP); 3357 1.23 fvdl return (0); 3358 1.111 christos } 3359 1.23 fvdl nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3)); 3360 1.23 fvdl if (v3) { 3361 1.88 christos tval = (u_quad_t)((quad_t)sf->f_blocks * (quad_t)sf->f_frsize); 3362 1.48 fair txdr_hyper(tval, &sfp->sf_tbytes); 3363 1.88 christos tval = (u_quad_t)((quad_t)sf->f_bfree * (quad_t)sf->f_frsize); 3364 1.48 fair txdr_hyper(tval, &sfp->sf_fbytes); 3365 1.88 christos tval = (u_quad_t)((quad_t)sf->f_bavail * (quad_t)sf->f_frsize); 3366 1.48 fair txdr_hyper(tval, &sfp->sf_abytes); 3367 1.47 mycroft tval = (u_quad_t)sf->f_files; 3368 1.48 fair txdr_hyper(tval, &sfp->sf_tfiles); 3369 1.47 mycroft tval = (u_quad_t)sf->f_ffree; 3370 1.48 fair txdr_hyper(tval, &sfp->sf_ffiles); 3371 1.48 fair txdr_hyper(tval, &sfp->sf_afiles); 3372 1.23 fvdl sfp->sf_invarsec = 0; 3373 1.23 fvdl } else { 3374 1.23 fvdl sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 3375 1.180 mlelstv sfp->sf_bsize = txdr_unsigned(NFS_V2CLAMP16(sf->f_frsize)); 3376 1.180 mlelstv sfp->sf_blocks = txdr_unsigned(NFS_V2CLAMP32(sf->f_blocks)); 3377 1.180 mlelstv sfp->sf_bfree = txdr_unsigned(NFS_V2CLAMP32(sf->f_bfree)); 3378 1.180 mlelstv sfp->sf_bavail = txdr_unsigned(NFS_V2CLAMP32(sf->f_bavail)); 3379 1.23 fvdl } 3380 1.111 christos nfsmout: 3381 1.111 christos if (sf) 3382 1.111 christos free(sf, M_TEMP); 3383 1.111 christos return error; 3384 1.23 fvdl } 3385 1.23 fvdl 3386 1.23 fvdl /* 3387 1.23 fvdl * nfs fsinfo service 3388 1.23 fvdl */ 3389 1.23 fvdl int 3390 1.143 dsl nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 3391 1.23 fvdl { 3392 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3393 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 3394 1.126 christos char *dpos = nfsd->nd_dpos; 3395 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 3396 1.54 augustss u_int32_t *tl; 3397 1.54 augustss struct nfsv3_fsinfo *sip; 3398 1.54 augustss int32_t t1; 3399 1.126 christos char *bpos; 3400 1.103 christos int error = 0, rdonly, cache = 0, getret = 1; 3401 1.69 yamt uint32_t maxdata; 3402 1.23 fvdl char *cp2; 3403 1.166 martin struct mbuf *mb, *mreq __unused; 3404 1.23 fvdl struct vnode *vp; 3405 1.23 fvdl struct vattr at; 3406 1.117 yamt nfsrvfh_t nsfh; 3407 1.37 fvdl u_quad_t frev, maxfsize; 3408 1.111 christos struct statvfs *sb; 3409 1.23 fvdl 3410 1.117 yamt nfsm_srvmtofh(&nsfh); 3411 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 3412 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 3413 1.23 fvdl if (error) { 3414 1.23 fvdl nfsm_reply(NFSX_UNSIGNED); 3415 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3416 1.23 fvdl return (0); 3417 1.15 mycroft } 3418 1.37 fvdl 3419 1.37 fvdl /* XXX Try to make a guess on the max file size. */ 3420 1.111 christos sb = malloc(sizeof(*sb), M_TEMP, M_WAITOK); 3421 1.131 pooka VFS_STATVFS(vp->v_mount, sb); 3422 1.111 christos maxfsize = (u_quad_t)0x80000000 * sb->f_frsize - 1; 3423 1.111 christos free(sb, M_TEMP); 3424 1.37 fvdl 3425 1.131 pooka getret = VOP_GETATTR(vp, &at, cred); 3426 1.23 fvdl vput(vp); 3427 1.23 fvdl nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); 3428 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3429 1.23 fvdl nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO); 3430 1.23 fvdl 3431 1.23 fvdl /* 3432 1.23 fvdl * XXX 3433 1.23 fvdl * There should be file system VFS OP(s) to get this information. 3434 1.23 fvdl * For now, assume ufs. 3435 1.23 fvdl */ 3436 1.23 fvdl if (slp->ns_so->so_type == SOCK_DGRAM) 3437 1.69 yamt maxdata = NFS_MAXDGRAMDATA; 3438 1.23 fvdl else 3439 1.69 yamt maxdata = NFS_MAXDATA; 3440 1.69 yamt sip->fs_rtmax = txdr_unsigned(maxdata); 3441 1.69 yamt sip->fs_rtpref = txdr_unsigned(maxdata); 3442 1.23 fvdl sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3443 1.69 yamt sip->fs_wtmax = txdr_unsigned(maxdata); 3444 1.69 yamt sip->fs_wtpref = txdr_unsigned(maxdata); 3445 1.23 fvdl sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3446 1.69 yamt sip->fs_dtpref = txdr_unsigned(maxdata); 3447 1.48 fair txdr_hyper(maxfsize, &sip->fs_maxfilesize); 3448 1.23 fvdl sip->fs_timedelta.nfsv3_sec = 0; 3449 1.23 fvdl sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3450 1.23 fvdl sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3451 1.23 fvdl NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3452 1.23 fvdl NFSV3FSINFO_CANSETTIME); 3453 1.23 fvdl nfsm_srvdone; 3454 1.23 fvdl } 3455 1.23 fvdl 3456 1.23 fvdl /* 3457 1.23 fvdl * nfs pathconf service 3458 1.23 fvdl */ 3459 1.23 fvdl int 3460 1.143 dsl nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq) 3461 1.23 fvdl { 3462 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md; 3463 1.23 fvdl struct mbuf *nam = nfsd->nd_nam; 3464 1.126 christos char *dpos = nfsd->nd_dpos; 3465 1.109 elad kauth_cred_t cred = nfsd->nd_cr; 3466 1.54 augustss u_int32_t *tl; 3467 1.54 augustss struct nfsv3_pathconf *pc; 3468 1.54 augustss int32_t t1; 3469 1.126 christos char *bpos; 3470 1.103 christos int error = 0, rdonly, cache = 0, getret = 1; 3471 1.24 cgd register_t linkmax, namemax, chownres, notrunc; 3472 1.23 fvdl char *cp2; 3473 1.166 martin struct mbuf *mb, *mreq __unused; 3474 1.23 fvdl struct vnode *vp; 3475 1.23 fvdl struct vattr at; 3476 1.117 yamt nfsrvfh_t nsfh; 3477 1.23 fvdl u_quad_t frev; 3478 1.23 fvdl 3479 1.117 yamt nfsm_srvmtofh(&nsfh); 3480 1.117 yamt error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam, 3481 1.125 thorpej &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false); 3482 1.23 fvdl if (error) { 3483 1.23 fvdl nfsm_reply(NFSX_UNSIGNED); 3484 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3485 1.23 fvdl return (0); 3486 1.23 fvdl } 3487 1.23 fvdl error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3488 1.23 fvdl if (!error) 3489 1.23 fvdl error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3490 1.23 fvdl if (!error) 3491 1.23 fvdl error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3492 1.23 fvdl if (!error) 3493 1.23 fvdl error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3494 1.131 pooka getret = VOP_GETATTR(vp, &at, cred); 3495 1.23 fvdl vput(vp); 3496 1.23 fvdl nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); 3497 1.23 fvdl nfsm_srvpostop_attr(getret, &at); 3498 1.23 fvdl if (error) 3499 1.23 fvdl return (0); 3500 1.23 fvdl nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 3501 1.23 fvdl 3502 1.23 fvdl pc->pc_linkmax = txdr_unsigned(linkmax); 3503 1.23 fvdl pc->pc_namemax = txdr_unsigned(namemax); 3504 1.23 fvdl pc->pc_notrunc = txdr_unsigned(notrunc); 3505 1.23 fvdl pc->pc_chownrestricted = txdr_unsigned(chownres); 3506 1.23 fvdl 3507 1.23 fvdl /* 3508 1.23 fvdl * These should probably be supported by VOP_PATHCONF(), but 3509 1.23 fvdl * until msdosfs is exportable (why would you want to?), the 3510 1.23 fvdl * Unix defaults should be ok. 3511 1.23 fvdl */ 3512 1.23 fvdl pc->pc_caseinsensitive = nfs_false; 3513 1.23 fvdl pc->pc_casepreserving = nfs_true; 3514 1.1 cgd nfsm_srvdone; 3515 1.1 cgd } 3516 1.1 cgd 3517 1.1 cgd /* 3518 1.1 cgd * Null operation, used by clients to ping server 3519 1.1 cgd */ 3520 1.1 cgd /* ARGSUSED */ 3521 1.22 christos int 3522 1.119 yamt nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3523 1.119 yamt struct lwp *lwp, struct mbuf **mrq) 3524 1.1 cgd { 3525 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep; 3526 1.126 christos char *bpos; 3527 1.23 fvdl int error = NFSERR_RETVOID, cache = 0; 3528 1.166 martin struct mbuf *mb, *mreq __unused; 3529 1.15 mycroft u_quad_t frev; 3530 1.1 cgd 3531 1.1 cgd nfsm_reply(0); 3532 1.144 bouyer nfsmout: 3533 1.23 fvdl return (0); 3534 1.1 cgd } 3535 1.1 cgd 3536 1.1 cgd /* 3537 1.1 cgd * No operation, used for obsolete procedures 3538 1.1 cgd */ 3539 1.1 cgd /* ARGSUSED */ 3540 1.22 christos int 3541 1.119 yamt nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3542 1.119 yamt struct lwp *lwp, struct mbuf **mrq) 3543 1.1 cgd { 3544 1.23 fvdl struct mbuf *mrep = nfsd->nd_mrep; 3545 1.126 christos char *bpos; 3546 1.22 christos int error, cache = 0; 3547 1.166 martin struct mbuf *mb, *mreq __unused; 3548 1.15 mycroft u_quad_t frev; 3549 1.1 cgd 3550 1.15 mycroft if (nfsd->nd_repstat) 3551 1.15 mycroft error = nfsd->nd_repstat; 3552 1.2 cgd else 3553 1.2 cgd error = EPROCUNAVAIL; 3554 1.1 cgd nfsm_reply(0); 3555 1.144 bouyer nfsmout: 3556 1.23 fvdl return (0); 3557 1.1 cgd } 3558 1.1 cgd 3559 1.1 cgd /* 3560 1.1 cgd * Perform access checking for vnodes obtained from file handles that would 3561 1.1 cgd * refer to files already opened by a Unix client. You cannot just use 3562 1.1 cgd * vn_writechk() and VOP_ACCESS() for two reasons. 3563 1.15 mycroft * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 3564 1.27 fvdl * 2 - The owner is to be given access irrespective of mode bits for some 3565 1.27 fvdl * operations, so that processes that chmod after opening a file don't 3566 1.27 fvdl * break. I don't like this because it opens a security hole, but since 3567 1.27 fvdl * the nfs server opens a security hole the size of a barn door anyhow, 3568 1.27 fvdl * what the heck. 3569 1.31 fvdl * 3570 1.31 fvdl * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() 3571 1.156 yamt * will return EPERM instead of EACCES. EPERM is always an error. 3572 1.1 cgd */ 3573 1.22 christos int 3574 1.143 dsl nfsrv_access(struct vnode *vp, int flags, kauth_cred_t cred, int rdonly, struct lwp *lwp, int override) 3575 1.1 cgd { 3576 1.1 cgd struct vattr vattr; 3577 1.1 cgd int error; 3578 1.1 cgd if (flags & VWRITE) { 3579 1.15 mycroft /* Just vn_writechk() changed to check rdonly */ 3580 1.1 cgd /* 3581 1.1 cgd * Disallow write attempts on read-only file systems; 3582 1.1 cgd * unless the file is a socket or a block or character 3583 1.1 cgd * device resident on the file system. 3584 1.1 cgd */ 3585 1.15 mycroft if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 3586 1.1 cgd switch (vp->v_type) { 3587 1.23 fvdl case VREG: 3588 1.23 fvdl case VDIR: 3589 1.23 fvdl case VLNK: 3590 1.1 cgd return (EROFS); 3591 1.23 fvdl default: 3592 1.22 christos break; 3593 1.1 cgd } 3594 1.1 cgd } 3595 1.59 chs 3596 1.1 cgd /* 3597 1.59 chs * If the vnode is in use as a process's text, 3598 1.59 chs * we can't allow writing. 3599 1.1 cgd */ 3600 1.130 ad if (vp->v_iflag & VI_TEXT) 3601 1.40 mrg return (ETXTBSY); 3602 1.1 cgd } 3603 1.131 pooka error = VOP_GETATTR(vp, &vattr, cred); 3604 1.23 fvdl if (error) 3605 1.1 cgd return (error); 3606 1.131 pooka error = VOP_ACCESS(vp, flags, cred); 3607 1.27 fvdl /* 3608 1.27 fvdl * Allow certain operations for the owner (reads and writes 3609 1.27 fvdl * on files that are already open). 3610 1.27 fvdl */ 3611 1.109 elad if (override && error == EACCES && kauth_cred_geteuid(cred) == vattr.va_uid) 3612 1.27 fvdl error = 0; 3613 1.27 fvdl return error; 3614 1.1 cgd } 3615