1 /*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 /* 38 * These functions support the macros and help fiddle mbuf chains for 39 * the nfs op functions. They do things like create the rpc header and 40 * copy data between mbuf chains and uio lists. 41 */ 42 #ifndef APPLEKEXT 43 #include <fs/nfs/nfsport.h> 44 45 extern struct nfsstats newnfsstats; 46 extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS]; 47 extern int ncl_mbuf_mlen; 48 extern enum vtype newnv2tov_type[8]; 49 extern enum vtype nv34tov_type[8]; 50 NFSCLSTATEMUTEX; 51 #endif /* !APPLEKEXT */ 52 53 static nfsuint64 nfs_nullcookie = {{ 0, 0 }}; 54 static struct { 55 int op; 56 int opcnt; 57 const u_char *tag; 58 int taglen; 59 } nfsv4_opmap[NFS_NPROCS] = { 60 { 0, 1, "Null", 4 }, 61 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 62 { NFSV4OP_SETATTR, 2, "Setattr", 7, }, 63 { NFSV4OP_LOOKUP, 3, "Lookup", 6, }, 64 { NFSV4OP_ACCESS, 2, "Access", 6, }, 65 { NFSV4OP_READLINK, 2, "Readlink", 8, }, 66 { NFSV4OP_READ, 1, "Read", 4, }, 67 { NFSV4OP_WRITE, 2, "Write", 5, }, 68 { NFSV4OP_OPEN, 3, "Open", 4, }, 69 { NFSV4OP_CREATE, 3, "Create", 6, }, 70 { NFSV4OP_CREATE, 1, "Create", 6, }, 71 { NFSV4OP_CREATE, 3, "Create", 6, }, 72 { NFSV4OP_REMOVE, 1, "Remove", 6, }, 73 { NFSV4OP_REMOVE, 1, "Remove", 6, }, 74 { NFSV4OP_SAVEFH, 5, "Rename", 6, }, 75 { NFSV4OP_SAVEFH, 4, "Link", 4, }, 76 { NFSV4OP_READDIR, 2, "Readdir", 7, }, 77 { NFSV4OP_READDIR, 2, "Readdir", 7, }, 78 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 79 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 80 { NFSV4OP_GETATTR, 1, "Getattr", 7, }, 81 { NFSV4OP_COMMIT, 2, "Commit", 6, }, 82 { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, }, 83 { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, }, 84 { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, }, 85 { NFSV4OP_LOCK, 1, "Lock", 4, }, 86 { NFSV4OP_LOCKU, 1, "LockU", 5, }, 87 { NFSV4OP_OPEN, 2, "Open", 4, }, 88 { NFSV4OP_CLOSE, 1, "Close", 5, }, 89 { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, }, 90 { NFSV4OP_LOCKT, 1, "LockT", 5, }, 91 { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, }, 92 { NFSV4OP_RENEW, 1, "Renew", 5, }, 93 { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, }, 94 { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, }, 95 { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, }, 96 { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, }, 97 { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, }, 98 { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, }, 99 { NFSV4OP_GETATTR, 1, "Getacl", 6, }, 100 { NFSV4OP_SETATTR, 1, "Setacl", 6, }, 101 }; 102 103 104 /* 105 * NFS RPCS that have large request message size. 106 */ 107 static int nfs_bigrequest[NFS_NPROCS] = { 108 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110 }; 111 112 /* 113 * Start building a request. Mostly just put the first file handle in 114 * place. 115 */ 116 APPLESTATIC void 117 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp, 118 u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp) 119 { 120 struct mbuf *mb; 121 u_int32_t *tl; 122 int opcnt; 123 nfsattrbit_t attrbits; 124 125 /* 126 * First, fill in some of the fields of nd. 127 */ 128 if (NFSHASNFSV4(nmp)) 129 nd->nd_flag = ND_NFSV4 | ND_NFSCL; 130 else if (NFSHASNFSV3(nmp)) 131 nd->nd_flag = ND_NFSV3 | ND_NFSCL; 132 else 133 nd->nd_flag = ND_NFSV2 | ND_NFSCL; 134 nd->nd_procnum = procnum; 135 nd->nd_repstat = 0; 136 137 /* 138 * Get the first mbuf for the request. 139 */ 140 if (nfs_bigrequest[procnum]) 141 NFSMCLGET(mb, M_WAIT); 142 else 143 NFSMGET(mb); 144 mbuf_setlen(mb, 0); 145 nd->nd_mreq = nd->nd_mb = mb; 146 nd->nd_bpos = NFSMTOD(mb, caddr_t); 147 148 /* 149 * And fill the first file handle into the request. 150 */ 151 if (nd->nd_flag & ND_NFSV4) { 152 opcnt = nfsv4_opmap[procnum].opcnt + 153 nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh; 154 /* 155 * What should the tag really be? 156 */ 157 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag, 158 nfsv4_opmap[procnum].taglen); 159 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 160 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 161 if (opcntpp != NULL) 162 *opcntpp = tl; 163 *tl++ = txdr_unsigned(opcnt); 164 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) { 165 *tl = txdr_unsigned(NFSV4OP_PUTFH); 166 (void) nfsm_fhtom(nd, nfhp, fhlen, 0); 167 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh==2){ 168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 169 *tl = txdr_unsigned(NFSV4OP_GETATTR); 170 NFSWCCATTR_ATTRBIT(&attrbits); 171 (void) nfsrv_putattrbit(nd, &attrbits); 172 nd->nd_flag |= ND_V4WCCATTR; 173 } 174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 175 } 176 *tl = txdr_unsigned(nfsv4_opmap[procnum].op); 177 } else { 178 (void) nfsm_fhtom(nd, nfhp, fhlen, 0); 179 } 180 NFSINCRGLOBAL(newnfsstats.rpccnt[procnum]); 181 } 182 183 #ifndef APPLE 184 /* 185 * copies a uio scatter/gather list to an mbuf chain. 186 * NOTE: can ony handle iovcnt == 1 187 */ 188 APPLESTATIC void 189 nfsm_uiombuf(struct nfsrv_descript *nd, struct uio *uiop, int siz) 190 { 191 char *uiocp; 192 struct mbuf *mp, *mp2; 193 int xfer, left, mlen; 194 int uiosiz, clflg, rem; 195 char *cp, *tcp; 196 197 KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1")); 198 199 if (siz > ncl_mbuf_mlen) /* or should it >= MCLBYTES ?? */ 200 clflg = 1; 201 else 202 clflg = 0; 203 rem = NFSM_RNDUP(siz) - siz; 204 mp = mp2 = nd->nd_mb; 205 while (siz > 0) { 206 left = uiop->uio_iov->iov_len; 207 uiocp = uiop->uio_iov->iov_base; 208 if (left > siz) 209 left = siz; 210 uiosiz = left; 211 while (left > 0) { 212 mlen = M_TRAILINGSPACE(mp); 213 if (mlen == 0) { 214 if (clflg) 215 NFSMCLGET(mp, M_WAIT); 216 else 217 NFSMGET(mp); 218 mbuf_setlen(mp, 0); 219 mbuf_setnext(mp2, mp); 220 mp2 = mp; 221 mlen = M_TRAILINGSPACE(mp); 222 } 223 xfer = (left > mlen) ? mlen : left; 224 #ifdef notdef 225 /* Not Yet.. */ 226 if (uiop->uio_iov->iov_op != NULL) 227 (*(uiop->uio_iov->iov_op)) 228 (uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp), 229 xfer); 230 else 231 #endif 232 if (uiop->uio_segflg == UIO_SYSSPACE) 233 NFSBCOPY(uiocp, NFSMTOD(mp, caddr_t) + mbuf_len(mp), 234 xfer); 235 else 236 copyin(CAST_USER_ADDR_T(uiocp), NFSMTOD(mp, caddr_t) 237 + mbuf_len(mp), xfer); 238 mbuf_setlen(mp, mbuf_len(mp) + xfer); 239 left -= xfer; 240 uiocp += xfer; 241 uiop->uio_offset += xfer; 242 uiop->uio_resid -= xfer; 243 } 244 tcp = (char *)uiop->uio_iov->iov_base; 245 tcp += uiosiz; 246 uiop->uio_iov->iov_base = (void *)tcp; 247 uiop->uio_iov->iov_len -= uiosiz; 248 siz -= uiosiz; 249 } 250 if (rem > 0) { 251 if (rem > M_TRAILINGSPACE(mp)) { 252 NFSMGET(mp); 253 mbuf_setlen(mp, 0); 254 mbuf_setnext(mp2, mp); 255 } 256 cp = NFSMTOD(mp, caddr_t) + mbuf_len(mp); 257 for (left = 0; left < rem; left++) 258 *cp++ = '\0'; 259 mbuf_setlen(mp, mbuf_len(mp) + rem); 260 nd->nd_bpos = cp; 261 } else 262 nd->nd_bpos = NFSMTOD(mp, caddr_t) + mbuf_len(mp); 263 nd->nd_mb = mp; 264 } 265 #endif /* !APPLE */ 266 267 /* 268 * Load vnode attributes from the xdr file attributes. 269 * Returns EBADRPC if they can't be parsed, 0 otherwise. 270 */ 271 APPLESTATIC int 272 nfsm_loadattr(struct nfsrv_descript *nd, struct nfsvattr *nap) 273 { 274 struct nfs_fattr *fp; 275 int error = 0; 276 277 if (nd->nd_flag & ND_NFSV4) { 278 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, 279 NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL); 280 } else if (nd->nd_flag & ND_NFSV3) { 281 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V3FATTR); 282 nap->na_type = nfsv34tov_type(fp->fa_type); 283 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode); 284 nap->na_rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 285 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 286 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 287 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid); 288 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid); 289 nap->na_size = fxdr_hyper(&fp->fa3_size); 290 nap->na_blocksize = NFS_FABLKSIZE; 291 nap->na_bytes = fxdr_hyper(&fp->fa3_used); 292 nap->na_fileid = fxdr_hyper(&fp->fa3_fileid); 293 fxdr_nfsv3time(&fp->fa3_atime, &nap->na_atime); 294 fxdr_nfsv3time(&fp->fa3_ctime, &nap->na_ctime); 295 fxdr_nfsv3time(&fp->fa3_mtime, &nap->na_mtime); 296 nap->na_flags = 0; 297 nap->na_filerev = 0; 298 } else { 299 NFSM_DISSECT(fp, struct nfs_fattr *, NFSX_V2FATTR); 300 nap->na_type = nfsv2tov_type(fp->fa_type); 301 nap->na_mode = fxdr_unsigned(u_short, fp->fa_mode); 302 if (nap->na_type == VNON || nap->na_type == VREG) 303 nap->na_type = IFTOVT(nap->na_mode); 304 nap->na_rdev = fxdr_unsigned(dev_t, fp->fa2_rdev); 305 306 /* 307 * Really ugly NFSv2 kludge. 308 */ 309 if (nap->na_type == VCHR && nap->na_rdev == ((dev_t)-1)) 310 nap->na_type = VFIFO; 311 nap->na_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 312 nap->na_uid = fxdr_unsigned(uid_t, fp->fa_uid); 313 nap->na_gid = fxdr_unsigned(gid_t, fp->fa_gid); 314 nap->na_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 315 nap->na_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 316 nap->na_bytes = 317 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) * 318 NFS_FABLKSIZE; 319 nap->na_fileid = fxdr_unsigned(uint64_t, fp->fa2_fileid); 320 fxdr_nfsv2time(&fp->fa2_atime, &nap->na_atime); 321 fxdr_nfsv2time(&fp->fa2_mtime, &nap->na_mtime); 322 nap->na_flags = 0; 323 nap->na_ctime.tv_sec = fxdr_unsigned(u_int32_t, 324 fp->fa2_ctime.nfsv2_sec); 325 nap->na_ctime.tv_nsec = 0; 326 nap->na_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 327 nap->na_filerev = 0; 328 } 329 nfsmout: 330 return (error); 331 } 332 333 /* 334 * This function finds the directory cookie that corresponds to the 335 * logical byte offset given. 336 */ 337 APPLESTATIC nfsuint64 * 338 nfscl_getcookie(struct nfsnode *np, off_t off, int add) 339 { 340 struct nfsdmap *dp, *dp2; 341 int pos; 342 343 pos = off / NFS_DIRBLKSIZ; 344 if (pos == 0) { 345 KASSERT(!add, ("nfs getcookie add at 0")); 346 return (&nfs_nullcookie); 347 } 348 pos--; 349 dp = LIST_FIRST(&np->n_cookies); 350 if (!dp) { 351 if (add) { 352 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 353 M_NFSDIROFF, M_WAITOK); 354 dp->ndm_eocookie = 0; 355 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 356 } else 357 return (NULL); 358 } 359 while (pos >= NFSNUMCOOKIES) { 360 pos -= NFSNUMCOOKIES; 361 if (LIST_NEXT(dp, ndm_list) != NULL) { 362 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 363 pos >= dp->ndm_eocookie) 364 return (NULL); 365 dp = LIST_NEXT(dp, ndm_list); 366 } else if (add) { 367 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 368 M_NFSDIROFF, M_WAITOK); 369 dp2->ndm_eocookie = 0; 370 LIST_INSERT_AFTER(dp, dp2, ndm_list); 371 dp = dp2; 372 } else 373 return (NULL); 374 } 375 if (pos >= dp->ndm_eocookie) { 376 if (add) 377 dp->ndm_eocookie = pos + 1; 378 else 379 return (NULL); 380 } 381 return (&dp->ndm_cookies[pos]); 382 } 383 384 /* 385 * Gets a file handle out of an nfs reply sent to the client and returns 386 * the file handle and the file's attributes. 387 * For V4, it assumes that Getfh and Getattr Op's results are here. 388 */ 389 APPLESTATIC int 390 nfscl_mtofh(struct nfsrv_descript *nd, struct nfsfh **nfhpp, 391 struct nfsvattr *nap, int *attrflagp) 392 { 393 u_int32_t *tl; 394 int error = 0, flag = 1; 395 396 *nfhpp = NULL; 397 *attrflagp = 0; 398 /* 399 * First get the file handle and vnode. 400 */ 401 if (nd->nd_flag & ND_NFSV3) { 402 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 403 flag = fxdr_unsigned(int, *tl); 404 } else if (nd->nd_flag & ND_NFSV4) { 405 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 406 } 407 if (flag) { 408 error = nfsm_getfh(nd, nfhpp); 409 if (error) 410 return (error); 411 } 412 413 /* 414 * Now, get the attributes. 415 */ 416 if (nd->nd_flag & ND_NFSV4) { 417 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 418 } else if (nd->nd_flag & ND_NFSV3) { 419 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 420 if (flag) { 421 flag = fxdr_unsigned(int, *tl); 422 } else if (fxdr_unsigned(int, *tl)) { 423 error = nfsm_advance(nd, NFSX_V3FATTR, -1); 424 if (error) 425 return (error); 426 } 427 } 428 if (flag) { 429 error = nfsm_loadattr(nd, nap); 430 if (!error) 431 *attrflagp = 1; 432 } 433 nfsmout: 434 return (error); 435 } 436 437 /* 438 * Put a state Id in the mbuf list. 439 */ 440 APPLESTATIC void 441 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag) 442 { 443 nfsv4stateid_t *st; 444 445 NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID); 446 if (flag == NFSSTATEID_PUTALLZERO) { 447 st->seqid = 0; 448 st->other[0] = 0; 449 st->other[1] = 0; 450 st->other[2] = 0; 451 } else if (flag == NFSSTATEID_PUTALLONE) { 452 st->seqid = 0xffffffff; 453 st->other[0] = 0xffffffff; 454 st->other[1] = 0xffffffff; 455 st->other[2] = 0xffffffff; 456 } else { 457 st->seqid = stateidp->seqid; 458 st->other[0] = stateidp->other[0]; 459 st->other[1] = stateidp->other[1]; 460 st->other[2] = stateidp->other[2]; 461 } 462 } 463 464 /* 465 * Initialize the owner/delegation sleep lock. 466 */ 467 APPLESTATIC void 468 nfscl_lockinit(struct nfsv4lock *lckp) 469 { 470 471 lckp->nfslock_usecnt = 0; 472 lckp->nfslock_lock = 0; 473 } 474 475 /* 476 * Get an exclusive lock. (Not needed for OpenBSD4, since there is only one 477 * thread for each posix process in the kernel.) 478 */ 479 APPLESTATIC void 480 nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex) 481 { 482 int igotlock; 483 484 do { 485 igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL); 486 } while (!igotlock); 487 } 488 489 /* 490 * Release an exclusive lock. 491 */ 492 APPLESTATIC void 493 nfscl_lockunlock(struct nfsv4lock *lckp) 494 { 495 496 nfsv4_unlock(lckp, 0); 497 } 498 499 /* 500 * Called to derefernce a lock on a stateid (delegation or open owner). 501 */ 502 APPLESTATIC void 503 nfscl_lockderef(struct nfsv4lock *lckp) 504 { 505 506 NFSLOCKCLSTATE(); 507 lckp->nfslock_usecnt--; 508 if (lckp->nfslock_usecnt == 0 && (lckp->nfslock_lock & NFSV4LOCK_WANTED)) { 509 lckp->nfslock_lock &= ~NFSV4LOCK_WANTED; 510 wakeup((caddr_t)lckp); 511 } 512 NFSUNLOCKCLSTATE(); 513 } 514 515