1/*- 2 * Copyright (c) 2009 Rick Macklem, University of Guelph 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 12 unchanged lines hidden (view full) --- 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28#include <sys/cdefs.h> |
29__FBSDID("$FreeBSD: head/sys/fs/nfsserver/nfs_nfsdstate.c 224086 2011-07-16 08:51:09Z zack $"); |
30 31#ifndef APPLEKEXT 32#include <fs/nfs/nfsport.h> 33 34struct nfsrv_stablefirst nfsrv_stablefirst; 35int nfsrv_issuedelegs = 0; 36int nfsrv_dolocallocks = 0; 37struct nfsv4lock nfsv4rootfs_lock; --- 92 unchanged lines hidden (view full) --- 130 * If returning a non-error, the clp structure must either be linked into 131 * the client list or free'd. 132 */ 133APPLESTATIC int 134nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, 135 nfsquad_t *clientidp, nfsquad_t *confirmp, NFSPROC_T *p) 136{ 137 struct nfsclient *clp = NULL, *new_clp = *new_clpp; |
138 int i, error = 0; |
139 struct nfsstate *stp, *tstp; 140 struct sockaddr_in *sad, *rad; 141 int zapit = 0, gotit, hasstate = 0, igotlock; 142 static u_int64_t confirm_index = 0; 143 144 /* 145 * Check for state resource limit exceeded. 146 */ |
147 if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { 148 error = NFSERR_RESOURCE; 149 goto out; 150 } |
151 152 if (nfsrv_issuedelegs == 0 || 153 ((nd->nd_flag & ND_GSS) != 0 && nfsrv_nogsscallback != 0)) 154 /* 155 * Don't do callbacks when delegations are disabled or 156 * for AUTH_GSS unless enabled via nfsrv_nogsscallback. 157 * If establishing a callback connection is attempted 158 * when a firewall is blocking the callback path, the --- 66 unchanged lines hidden (view full) --- 225 nfsrv_openpluslock++; 226 nfsrv_clients++; 227 NFSLOCKV4ROOTMUTEX(); 228 nfsv4_unlock(&nfsv4rootfs_lock, 1); 229 NFSUNLOCKV4ROOTMUTEX(); 230 if (zapit) 231 nfsrv_zapclient(clp, p); 232 *new_clpp = NULL; |
233 goto out; |
234 } 235 236 /* 237 * Now, handle the cases where the id is already issued. 238 */ 239 if (nfsrv_notsamecredname(nd, clp)) { 240 /* 241 * Check to see if there is expired state that should go away. --- 29 unchanged lines hidden (view full) --- 271 */ 272 sad = NFSSOCKADDR(new_clp->lc_req.nr_nam, struct sockaddr_in *); 273 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 274 sad->sin_addr.s_addr = rad->sin_addr.s_addr; 275 sad->sin_port = rad->sin_port; 276 NFSLOCKV4ROOTMUTEX(); 277 nfsv4_unlock(&nfsv4rootfs_lock, 1); 278 NFSUNLOCKV4ROOTMUTEX(); |
279 error = NFSERR_CLIDINUSE; 280 goto out; |
281 } 282 } 283 284 if (NFSBCMP(new_clp->lc_verf, clp->lc_verf, NFSX_VERF)) { 285 /* 286 * If the verifier has changed, the client has rebooted 287 * and a new client id is issued. The old state info 288 * can be thrown away once the SETCLIENTID_CONFIRM occurs. --- 44 unchanged lines hidden (view full) --- 333 */ 334 while (clp->lc_cbref) { 335 clp->lc_flags |= LCL_WAKEUPWANTED; 336 (void) tsleep((caddr_t)clp, PZERO - 1, 337 "nfsd clp", 10 * hz); 338 } 339 nfsrv_zapclient(clp, p); 340 *new_clpp = NULL; |
341 goto out; |
342 } 343 /* 344 * id and verifier match, so update the net address info 345 * and get rid of any existing callback authentication 346 * handle, so a new one will be acquired. 347 */ 348 LIST_REMOVE(clp, lc_hash); 349 new_clp->lc_flags |= (LCL_NEEDSCONFIRM | LCL_DONTCLEAN); --- 36 unchanged lines hidden (view full) --- 386 * completes. 387 */ 388 while (clp->lc_cbref) { 389 clp->lc_flags |= LCL_WAKEUPWANTED; 390 (void) tsleep((caddr_t)clp, PZERO - 1, "nfsd clp", 10 * hz); 391 } 392 nfsrv_zapclient(clp, p); 393 *new_clpp = NULL; |
394 395out: 396 NFSEXITCODE2(error, nd); 397 return (error); |
398} 399 400/* 401 * Check to see if the client id exists and optionally confirm it. 402 */ 403APPLESTATIC int 404nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp, 405 nfsquad_t confirm, struct nfsrv_descript *nd, NFSPROC_T *p) 406{ 407 struct nfsclient *clp; 408 struct nfsstate *stp; 409 int i; 410 struct nfsclienthashhead *hp; 411 int error = 0, igotlock, doneok; 412 413 if (clpp) 414 *clpp = NULL; |
415 if (nfsrvboottime != clientid.lval[0]) { 416 error = NFSERR_STALECLIENTID; 417 goto out; 418 } |
419 420 /* 421 * If called with opflags == CLOPS_RENEW, the State Lock is 422 * already held. Otherwise, we need to get either that or, 423 * for the case of Confirm, lock out the nfsd threads. 424 */ 425 if (opflags & CLOPS_CONFIRM) { 426 NFSLOCKV4ROOTMUTEX(); --- 26 unchanged lines hidden (view full) --- 453 if (error) { 454 if (opflags & CLOPS_CONFIRM) { 455 NFSLOCKV4ROOTMUTEX(); 456 nfsv4_unlock(&nfsv4rootfs_lock, 1); 457 NFSUNLOCKV4ROOTMUTEX(); 458 } else if (opflags != CLOPS_RENEW) { 459 NFSUNLOCKSTATE(); 460 } |
461 goto out; |
462 } 463 464 /* 465 * Perform any operations specified by the opflags. 466 */ 467 if (opflags & CLOPS_CONFIRM) { 468 if (clp->lc_confirm.qval != confirm.qval) 469 error = NFSERR_STALECLIENTID; --- 59 unchanged lines hidden (view full) --- 529 NFSLOCKV4ROOTMUTEX(); 530 nfsv4_unlock(&nfsv4rootfs_lock, 1); 531 NFSUNLOCKV4ROOTMUTEX(); 532 } else if (opflags != CLOPS_RENEW) { 533 NFSUNLOCKSTATE(); 534 } 535 if (clpp) 536 *clpp = clp; |
537 538out: 539 NFSEXITCODE2(error, nd); |
540 return (error); 541} 542 543/* 544 * Called from the new nfssvc syscall to admin revoke a clientid. 545 * Returns 0 for success, error otherwise. 546 */ 547APPLESTATIC int 548nfsrv_adminrevoke(struct nfsd_clid *revokep, NFSPROC_T *p) 549{ 550 struct nfsclient *clp = NULL; |
551 int i, error = 0; |
552 int gotit, igotlock; 553 554 /* 555 * First, lock out the nfsd so that state won't change while the 556 * revocation record is being written to the stable storage restart 557 * file. 558 */ 559 NFSLOCKV4ROOTMUTEX(); --- 16 unchanged lines hidden (view full) --- 576 } 577 } 578 i++; 579 } 580 if (!gotit) { 581 NFSLOCKV4ROOTMUTEX(); 582 nfsv4_unlock(&nfsv4rootfs_lock, 0); 583 NFSUNLOCKV4ROOTMUTEX(); |
584 error = EPERM; 585 goto out; |
586 } 587 588 /* 589 * Now, write out the revocation record 590 */ 591 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 592 nfsrv_backupstable(); 593 594 /* 595 * and clear out the state, marking the clientid revoked. 596 */ 597 clp->lc_flags &= ~LCL_CALLBACKSON; 598 clp->lc_flags |= LCL_ADMINREVOKED; 599 nfsrv_cleanclient(clp, p); 600 nfsrv_freedeleglist(&clp->lc_deleg); 601 nfsrv_freedeleglist(&clp->lc_olddeleg); 602 NFSLOCKV4ROOTMUTEX(); 603 nfsv4_unlock(&nfsv4rootfs_lock, 0); 604 NFSUNLOCKV4ROOTMUTEX(); |
605 606out: 607 NFSEXITCODE(error); 608 return (error); |
609} 610 611/* 612 * Dump out stats for all clients. Called from nfssvc(2), that is used 613 * newnfsstats. 614 */ 615APPLESTATIC void 616nfsrv_dumpclients(struct nfsd_dumpclients *dumpp, int maxcnt) --- 622 unchanged lines hidden (view full) --- 1239 * This function looks up an nfsstate structure via stateid. 1240 */ 1241static int 1242nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, __unused u_int32_t flags, 1243 struct nfsstate **stpp) 1244{ 1245 struct nfsstate *stp; 1246 struct nfsstatehead *hp; |
1247 int error = 0; |
1248 1249 *stpp = NULL; 1250 hp = NFSSTATEHASH(clp, *stateidp); 1251 LIST_FOREACH(stp, hp, ls_hash) { 1252 if (!NFSBCMP(stp->ls_stateid.other, stateidp->other, 1253 NFSX_STATEIDOTHER)) 1254 break; 1255 } 1256 1257 /* 1258 * If no state id in list, return NFSERR_BADSTATEID. 1259 */ |
1260 if (stp == LIST_END(hp)) { 1261 error = NFSERR_BADSTATEID; 1262 goto out; 1263 } |
1264 *stpp = stp; |
1265 1266out: 1267 NFSEXITCODE(error); 1268 return (error); |
1269} 1270 1271/* 1272 * This function gets an nfsstate structure via owner string. 1273 */ 1274static void 1275nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp, 1276 struct nfsstate **stpp) --- 62 unchanged lines hidden (view full) --- 1339 } 1340 1341 /* 1342 * Check for restart conditions (client and server). 1343 */ 1344 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 1345 &new_stp->ls_stateid, specialid); 1346 if (error) |
1347 goto out; |
1348 1349 /* 1350 * Check for state resource limit exceeded. 1351 */ 1352 if ((new_stp->ls_flags & NFSLCK_LOCK) && |
1353 nfsrv_openpluslock > NFSRV_V4STATELIMIT) { 1354 error = NFSERR_RESOURCE; 1355 goto out; 1356 } |
1357 1358 /* 1359 * For the lock case, get another nfslock structure, 1360 * just in case we need it. 1361 * Malloc now, before we start sifting through the linked lists, 1362 * in case we have to wait for memory. 1363 */ 1364tryagain: --- 199 unchanged lines hidden (view full) --- 1564 if (filestruct_locked != 0) { 1565 /* Roll back local locks. */ 1566 NFSUNLOCKSTATE(); 1567 nfsrv_locallock_rollback(vp, lfp, p); 1568 NFSLOCKSTATE(); 1569 nfsrv_unlocklf(lfp); 1570 } 1571 NFSUNLOCKSTATE(); |
1572 goto out; |
1573 } 1574 1575 /* 1576 * Check the nfsrv_getlockfile return. 1577 * Returned -1 if no structure found. 1578 */ 1579 if (getlckret == -1) { 1580 error = NFSERR_EXPIRED; --- 12 unchanged lines hidden (view full) --- 1593 * deny bits.) 1594 */ 1595 if (specialid) 1596 error = 0; 1597 else 1598 error = NFSERR_BADSTATEID; 1599 } 1600 NFSUNLOCKSTATE(); |
1601 goto out; |
1602 } 1603 1604 /* 1605 * For NFSLCK_CHECK and NFSLCK_LOCK, test for a share conflict. 1606 * For NFSLCK_CHECK, allow a read if write access is granted, 1607 * but check for a deny. For NFSLCK_LOCK, require correct access, 1608 * which implies a conflicting deny can't exist. 1609 */ --- 31 unchanged lines hidden (view full) --- 1641 if (filestruct_locked != 0) { 1642 /* Roll back local locks. */ 1643 NFSUNLOCKSTATE(); 1644 nfsrv_locallock_rollback(vp, lfp, p); 1645 NFSLOCKSTATE(); 1646 nfsrv_unlocklf(lfp); 1647 } 1648 NFSUNLOCKSTATE(); |
1649 error = NFSERR_OPENMODE; 1650 goto out; |
1651 } 1652 } else 1653 mystp = NULL; 1654 if ((new_stp->ls_flags & NFSLCK_CHECK) && !delegation) { 1655 /* 1656 * Check for a conflicting deny bit. 1657 */ 1658 LIST_FOREACH(tstp, &lfp->lf_open, ls_file) { --- 8 unchanged lines hidden (view full) --- 1667 * nfsrv_clientconflict unlocks state 1668 * when it returns non-zero. 1669 */ 1670 lckstp = NULL; 1671 goto tryagain; 1672 } 1673 if (ret == 0) 1674 NFSUNLOCKSTATE(); |
1675 if (ret == 2) |
1676 error = NFSERR_PERM; |
1677 else |
1678 error = NFSERR_OPENMODE; 1679 goto out; |
1680 } 1681 } 1682 } 1683 1684 /* We're outta here */ 1685 NFSUNLOCKSTATE(); |
1686 goto out; |
1687 } 1688 } 1689 1690 /* 1691 * For setattr, just get rid of all the Delegations for other clients. 1692 */ 1693 if (new_stp->ls_flags & NFSLCK_SETATTR) { 1694 ret = nfsrv_cleandeleg(vp, lfp, clp, &haslock, p); 1695 if (ret) { 1696 /* 1697 * nfsrv_cleandeleg() unlocks state when it 1698 * returns non-zero. 1699 */ 1700 if (ret == -1) { 1701 lckstp = NULL; 1702 goto tryagain; 1703 } |
1704 error = ret; 1705 goto out; |
1706 } 1707 if (!(new_stp->ls_flags & NFSLCK_CHECK) || 1708 (LIST_EMPTY(&lfp->lf_open) && LIST_EMPTY(&lfp->lf_lock) && 1709 LIST_EMPTY(&lfp->lf_deleg))) { 1710 NFSUNLOCKSTATE(); |
1711 goto out; |
1712 } 1713 } 1714 1715 /* 1716 * Check for a conflicting delegation. If one is found, call 1717 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 1718 * been set yet, it will get the lock. Otherwise, it will recall 1719 * the delegation. Then, we try try again... --- 37 unchanged lines hidden (view full) --- 1757 if (other_lop) { 1758 FREE((caddr_t)other_lop, M_NFSDLOCK); 1759 other_lop = NULL; 1760 } 1761 if (ret == -1) { 1762 lckstp = NULL; 1763 goto tryagain; 1764 } |
1765 error = ret; 1766 goto out; |
1767 } 1768 /* Never gets here. */ 1769 } 1770 tstp = nstp; 1771 } 1772 1773 /* 1774 * Handle the unlock case by calling nfsrv_updatelock(). --- 11 unchanged lines hidden (view full) --- 1786 if (filestruct_locked != 0) { 1787 NFSUNLOCKSTATE(); 1788 /* Update the local locks. */ 1789 nfsrv_localunlock(vp, lfp, first, end, p); 1790 NFSLOCKSTATE(); 1791 nfsrv_unlocklf(lfp); 1792 } 1793 NFSUNLOCKSTATE(); |
1794 goto out; |
1795 } 1796 1797 /* 1798 * Search for a conflicting lock. A lock conflicts if: 1799 * - the lock range overlaps and 1800 * - at least one lock is a write lock and 1801 * - it is not owned by the same lock owner 1802 */ --- 54 unchanged lines hidden (view full) --- 1857 /* Roll back local locks. */ 1858 NFSUNLOCKSTATE(); 1859 nfsrv_locallock_rollback(vp, lfp, p); 1860 NFSLOCKSTATE(); 1861 nfsrv_unlocklf(lfp); 1862 } 1863 if (ret == 0) 1864 NFSUNLOCKSTATE(); |
1865 goto out; |
1866 } 1867 } 1868 } 1869 1870 /* 1871 * We only get here if there was no lock that conflicted. 1872 */ 1873 if (new_stp->ls_flags & (NFSLCK_TEST | NFSLCK_CHECK)) { 1874 NFSUNLOCKSTATE(); |
1875 goto out; |
1876 } 1877 1878 /* 1879 * We only get here when we are creating or modifying a lock. 1880 * There are two variants: 1881 * - exist_lock_owner where lock_owner exists 1882 * - open_to_lock_owner with new lock_owner 1883 */ --- 36 unchanged lines hidden (view full) --- 1920 } 1921 if (filestruct_locked != 0) { 1922 NFSUNLOCKSTATE(); 1923 nfsrv_locallock_commit(lfp, lock_flags, first, end); 1924 NFSLOCKSTATE(); 1925 nfsrv_unlocklf(lfp); 1926 } 1927 NFSUNLOCKSTATE(); |
1928 1929out: |
1930 if (haslock) { 1931 NFSLOCKV4ROOTMUTEX(); 1932 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1933 NFSUNLOCKV4ROOTMUTEX(); 1934 } 1935 if (other_lop) 1936 FREE((caddr_t)other_lop, M_NFSDLOCK); |
1937 NFSEXITCODE2(error, nd); 1938 return (error); |
1939} 1940 1941/* 1942 * Check for state errors for Open. 1943 * repstat is passed back out as an error if more critical errors 1944 * are not detected. 1945 */ 1946APPLESTATIC int 1947nfsrv_opencheck(nfsquad_t clientid, nfsv4stateid_t *stateidp, 1948 struct nfsstate *new_stp, vnode_t vp, struct nfsrv_descript *nd, 1949 NFSPROC_T *p, int repstat) 1950{ 1951 struct nfsstate *stp, *nstp; 1952 struct nfsclient *clp; 1953 struct nfsstate *ownerstp; 1954 struct nfslockfile *lfp, *new_lfp; |
1955 int error = 0, haslock = 0, ret, readonly = 0, getfhret = 0; |
1956 1957 if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS) 1958 readonly = 1; 1959 /* 1960 * Check for restart conditions (client and server). 1961 */ 1962 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 1963 &new_stp->ls_stateid, 0); 1964 if (error) |
1965 goto out; |
1966 1967 /* 1968 * Check for state resource limit exceeded. 1969 * Technically this should be SMP protected, but the worst 1970 * case error is "out by one or two" on the count when it 1971 * returns NFSERR_RESOURCE and the limit is just a rather 1972 * arbitrary high water mark, so no harm is done. 1973 */ |
1974 if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { 1975 error = NFSERR_RESOURCE; 1976 goto out; 1977 } |
1978 1979tryagain: 1980 MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile), 1981 M_NFSDLOCKFILE, M_WAITOK); 1982 if (vp) 1983 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, &new_lfp, 1984 NULL, p); 1985 NFSLOCKSTATE(); --- 41 unchanged lines hidden (view full) --- 2027 if (error) { 2028 NFSUNLOCKSTATE(); 2029 if (haslock) { 2030 NFSLOCKV4ROOTMUTEX(); 2031 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2032 NFSUNLOCKV4ROOTMUTEX(); 2033 } 2034 free((caddr_t)new_lfp, M_NFSDLOCKFILE); |
2035 goto out; |
2036 } 2037 2038 /* 2039 * If vp == NULL, the file doesn't exist yet, so return ok. 2040 * (This always happens on the first pass, so haslock must be 0.) 2041 */ 2042 if (vp == NULL) { 2043 NFSUNLOCKSTATE(); 2044 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); |
2045 goto out; |
2046 } 2047 2048 /* 2049 * Get the structure for the underlying file. 2050 */ 2051 if (getfhret) 2052 error = getfhret; 2053 else 2054 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp, 2055 NULL, 0); 2056 if (new_lfp) 2057 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2058 if (error) { 2059 NFSUNLOCKSTATE(); 2060 if (haslock) { 2061 NFSLOCKV4ROOTMUTEX(); 2062 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2063 NFSUNLOCKV4ROOTMUTEX(); 2064 } |
2065 goto out; |
2066 } 2067 2068 /* 2069 * Search for a conflicting open/share. 2070 */ 2071 if (new_stp->ls_flags & NFSLCK_DELEGCUR) { 2072 /* 2073 * For Delegate_Cur, search for the matching Delegation, --- 14 unchanged lines hidden (view full) --- 2088 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) && 2089 (stp->ls_flags & NFSLCK_DELEGREAD))) { 2090 NFSUNLOCKSTATE(); 2091 if (haslock) { 2092 NFSLOCKV4ROOTMUTEX(); 2093 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2094 NFSUNLOCKV4ROOTMUTEX(); 2095 } |
2096 error = NFSERR_EXPIRED; 2097 goto out; |
2098 } 2099 } 2100 2101 /* 2102 * Check for access/deny bit conflicts. I check for the same 2103 * owner as well, in case the client didn't bother. 2104 */ 2105 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { --- 18 unchanged lines hidden (view full) --- 2124 error = NFSERR_SHAREDENIED; 2125 if (ret == 0) 2126 NFSUNLOCKSTATE(); 2127 if (haslock) { 2128 NFSLOCKV4ROOTMUTEX(); 2129 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2130 NFSUNLOCKV4ROOTMUTEX(); 2131 } |
2132 goto out; |
2133 } 2134 } 2135 2136 /* 2137 * Check for a conflicting delegation. If one is found, call 2138 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 2139 * been set yet, it will get the lock. Otherwise, it will recall 2140 * the delegation. Then, we try try again... --- 24 unchanged lines hidden (view full) --- 2165 ret = nfsrv_delegconflict(stp, &haslock, p, vp); 2166 if (ret) { 2167 /* 2168 * nfsrv_delegconflict() unlocks state 2169 * when it returns non-zero. 2170 */ 2171 if (ret == -1) 2172 goto tryagain; |
2173 error = ret; 2174 goto out; |
2175 } 2176 } 2177 stp = nstp; 2178 } 2179 } 2180 NFSUNLOCKSTATE(); 2181 if (haslock) { 2182 NFSLOCKV4ROOTMUTEX(); 2183 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2184 NFSUNLOCKV4ROOTMUTEX(); 2185 } |
2186 2187out: 2188 NFSEXITCODE2(error, nd); 2189 return (error); |
2190} 2191 2192/* 2193 * Open control function to create/update open state for an open. 2194 */ 2195APPLESTATIC int 2196nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp, 2197 struct nfsstate **new_stpp, nfsquad_t clientid, nfsv4stateid_t *stateidp, 2198 nfsv4stateid_t *delegstateidp, u_int32_t *rflagsp, struct nfsexstuff *exp, 2199 NFSPROC_T *p, u_quad_t filerev) 2200{ 2201 struct nfsstate *new_stp = *new_stpp; 2202 struct nfsstate *stp, *nstp; 2203 struct nfsstate *openstp = NULL, *new_open, *ownerstp, *new_deleg; 2204 struct nfslockfile *lfp, *new_lfp; 2205 struct nfsclient *clp; |
2206 int error = 0, haslock = 0, ret, delegate = 1, writedeleg = 1; |
2207 int readonly = 0, cbret = 1, getfhret = 0; 2208 2209 if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS) 2210 readonly = 1; 2211 /* 2212 * Check for restart conditions (client and server). 2213 * (Paranoia, should have been detected by nfsrv_opencheck().) 2214 * If an error does show up, return NFSERR_EXPIRED, since the 2215 * the seqid# has already been incremented. 2216 */ 2217 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 2218 &new_stp->ls_stateid, 0); 2219 if (error) { 2220 printf("Nfsd: openctrl unexpected restart err=%d\n", 2221 error); |
2222 error = NFSERR_EXPIRED; 2223 goto out; |
2224 } 2225 2226tryagain: 2227 MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile), 2228 M_NFSDLOCKFILE, M_WAITOK); 2229 MALLOC(new_open, struct nfsstate *, sizeof (struct nfsstate), 2230 M_NFSDSTATE, M_WAITOK); 2231 MALLOC(new_deleg, struct nfsstate *, sizeof (struct nfsstate), --- 54 unchanged lines hidden (view full) --- 2286 free((caddr_t)new_lfp, M_NFSDLOCKFILE); 2287 free((caddr_t)new_open, M_NFSDSTATE); 2288 free((caddr_t)new_deleg, M_NFSDSTATE); 2289 if (haslock) { 2290 NFSLOCKV4ROOTMUTEX(); 2291 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2292 NFSUNLOCKV4ROOTMUTEX(); 2293 } |
2294 error = NFSERR_EXPIRED; 2295 goto out; |
2296 } 2297 2298 if (new_stp->ls_flags & NFSLCK_RECLAIM) 2299 nfsrv_markstable(clp); 2300 2301 /* 2302 * Get the structure for the underlying file. 2303 */ --- 10 unchanged lines hidden (view full) --- 2314 error); 2315 free((caddr_t)new_open, M_NFSDSTATE); 2316 free((caddr_t)new_deleg, M_NFSDSTATE); 2317 if (haslock) { 2318 NFSLOCKV4ROOTMUTEX(); 2319 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2320 NFSUNLOCKV4ROOTMUTEX(); 2321 } |
2322 goto out; |
2323 } 2324 2325 /* 2326 * Search for a conflicting open/share. 2327 */ 2328 if (new_stp->ls_flags & NFSLCK_DELEGCUR) { 2329 /* 2330 * For Delegate_Cur, search for the matching Delegation, --- 17 unchanged lines hidden (view full) --- 2348 printf("Nfsd openctrl unexpected expiry\n"); 2349 free((caddr_t)new_open, M_NFSDSTATE); 2350 free((caddr_t)new_deleg, M_NFSDSTATE); 2351 if (haslock) { 2352 NFSLOCKV4ROOTMUTEX(); 2353 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2354 NFSUNLOCKV4ROOTMUTEX(); 2355 } |
2356 error = NFSERR_EXPIRED; 2357 goto out; |
2358 } 2359 2360 /* 2361 * Don't issue a Delegation, since one already exists and 2362 * delay delegation timeout, as required. 2363 */ 2364 delegate = 0; 2365 nfsrv_delaydelegtimeout(stp); --- 48 unchanged lines hidden (view full) --- 2414 if (haslock) { 2415 NFSLOCKV4ROOTMUTEX(); 2416 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2417 NFSUNLOCKV4ROOTMUTEX(); 2418 } 2419 free((caddr_t)new_open, M_NFSDSTATE); 2420 free((caddr_t)new_deleg, M_NFSDSTATE); 2421 printf("nfsd openctrl unexpected client cnfl\n"); |
2422 goto out; |
2423 } 2424 } 2425 } 2426 2427 /* 2428 * Check for a conflicting delegation. If one is found, call 2429 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 2430 * been set yet, it will get the lock. Otherwise, it will recall --- 34 unchanged lines hidden (view full) --- 2465 */ 2466 printf("Nfsd openctrl unexpected deleg cnfl\n"); 2467 free((caddr_t)new_open, M_NFSDSTATE); 2468 free((caddr_t)new_deleg, M_NFSDSTATE); 2469 if (ret == -1) { 2470 openstp = NULL; 2471 goto tryagain; 2472 } |
2473 error = ret; 2474 goto out; |
2475 } 2476 } 2477 } 2478 stp = nstp; 2479 } 2480 } 2481 2482 /* --- 356 unchanged lines hidden (view full) --- 2839 NFSLOCKV4ROOTMUTEX(); 2840 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2841 NFSUNLOCKV4ROOTMUTEX(); 2842 } 2843 if (new_open) 2844 FREE((caddr_t)new_open, M_NFSDSTATE); 2845 if (new_deleg) 2846 FREE((caddr_t)new_deleg, M_NFSDSTATE); |
2847 2848out: 2849 NFSEXITCODE2(error, nd); |
2850 return (error); 2851} 2852 2853/* 2854 * Open update. Does the confirm, downgrade and close. 2855 */ 2856APPLESTATIC int 2857nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid, 2858 nfsv4stateid_t *stateidp, struct nfsrv_descript *nd, NFSPROC_T *p) 2859{ 2860 struct nfsstate *stp, *ownerstp; 2861 struct nfsclient *clp; 2862 struct nfslockfile *lfp; 2863 u_int32_t bits; |
2864 int error = 0, gotstate = 0, len = 0; |
2865 u_char client[NFSV4_OPAQUELIMIT]; 2866 2867 /* 2868 * Check for restart conditions (client and server). 2869 */ 2870 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 2871 &new_stp->ls_stateid, 0); 2872 if (error) |
2873 goto out; |
2874 2875 NFSLOCKSTATE(); 2876 /* 2877 * Get the open structure via clientid and stateid. 2878 */ 2879 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 2880 (nfsquad_t)((u_quad_t)0), NULL, p); 2881 if (!error) --- 30 unchanged lines hidden (view full) --- 2912 * on the openowner, just throw it away, so the next use of the 2913 * openowner will start a fresh seq#. 2914 */ 2915 if (error == NFSERR_BADSEQID && 2916 (new_stp->ls_flags & NFSLCK_CONFIRM) && 2917 nfsrv_nootherstate(stp)) 2918 nfsrv_freeopenowner(stp->ls_openowner, 0, p); 2919 NFSUNLOCKSTATE(); |
2920 goto out; |
2921 } 2922 2923 /* 2924 * Set the return stateid. 2925 */ 2926 stateidp->seqid = stp->ls_stateid.seqid + 1; 2927 stateidp->other[0] = stp->ls_stateid.other[0]; 2928 stateidp->other[1] = stp->ls_stateid.other[1]; --- 36 unchanged lines hidden (view full) --- 2965 } else { 2966 /* 2967 * Update the share bits, making sure that the new set are a 2968 * subset of the old ones. 2969 */ 2970 bits = (new_stp->ls_flags & NFSLCK_SHAREBITS); 2971 if (~(stp->ls_flags) & bits) { 2972 NFSUNLOCKSTATE(); |
2973 error = NFSERR_INVAL; 2974 goto out; |
2975 } 2976 stp->ls_flags = (bits | NFSLCK_OPEN); 2977 stp->ls_stateid.seqid++; 2978 NFSUNLOCKSTATE(); 2979 } 2980 2981 /* 2982 * If the client just confirmed its first open, write a timestamp 2983 * to the stable storage file. 2984 */ 2985 if (gotstate != 0) { 2986 nfsrv_writestable(client, len, NFSNST_NEWSTATE, p); 2987 nfsrv_backupstable(); 2988 } |
2989 2990out: 2991 NFSEXITCODE2(error, nd); |
2992 return (error); 2993} 2994 2995/* 2996 * Delegation update. Does the purge and return. 2997 */ 2998APPLESTATIC int 2999nfsrv_delegupdate(nfsquad_t clientid, nfsv4stateid_t *stateidp, 3000 vnode_t vp, int op, struct ucred *cred, NFSPROC_T *p) 3001{ 3002 struct nfsstate *stp; 3003 struct nfsclient *clp; |
3004 int error = 0; |
3005 fhandle_t fh; 3006 3007 /* 3008 * Do a sanity check against the file handle for DelegReturn. 3009 */ 3010 if (vp) { 3011 error = nfsvno_getfh(vp, &fh, p); 3012 if (error) |
3013 goto out; |
3014 } 3015 /* 3016 * Check for restart conditions (client and server). 3017 */ 3018 if (op == NFSV4OP_DELEGRETURN) 3019 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGRETURN, 3020 stateidp, 0); 3021 else --- 19 unchanged lines hidden (view full) --- 3041 error = NFSERR_OLDSTATEID; 3042 } 3043 /* 3044 * NFSERR_EXPIRED means that the state has gone away, 3045 * so Delegations have been purged. Just return ok. 3046 */ 3047 if (error == NFSERR_EXPIRED && op == NFSV4OP_DELEGPURGE) { 3048 NFSUNLOCKSTATE(); |
3049 error = 0; 3050 goto out; |
3051 } 3052 if (error) { 3053 NFSUNLOCKSTATE(); |
3054 goto out; |
3055 } 3056 3057 if (op == NFSV4OP_DELEGRETURN) { 3058 if (NFSBCMP((caddr_t)&fh, (caddr_t)&stp->ls_lfp->lf_fh, 3059 sizeof (fhandle_t))) { 3060 NFSUNLOCKSTATE(); |
3061 error = NFSERR_BADSTATEID; 3062 goto out; |
3063 } 3064 nfsrv_freedeleg(stp); 3065 } else { 3066 nfsrv_freedeleglist(&clp->lc_olddeleg); 3067 } 3068 NFSUNLOCKSTATE(); |
3069 error = 0; 3070 3071out: 3072 NFSEXITCODE(error); 3073 return (error); |
3074} 3075 3076/* 3077 * Release lock owner. 3078 */ 3079APPLESTATIC int 3080nfsrv_releaselckown(struct nfsstate *new_stp, nfsquad_t clientid, 3081 NFSPROC_T *p) 3082{ 3083 struct nfsstate *stp, *nstp, *openstp, *ownstp; 3084 struct nfsclient *clp; |
3085 int error = 0; |
3086 3087 /* 3088 * Check for restart conditions (client and server). 3089 */ 3090 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 3091 &new_stp->ls_stateid, 0); 3092 if (error) |
3093 goto out; |
3094 3095 NFSLOCKSTATE(); 3096 /* 3097 * Get the lock owner by name. 3098 */ 3099 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 3100 (nfsquad_t)((u_quad_t)0), NULL, p); 3101 if (error) { 3102 NFSUNLOCKSTATE(); |
3103 goto out; |
3104 } 3105 LIST_FOREACH(ownstp, &clp->lc_open, ls_list) { 3106 LIST_FOREACH(openstp, &ownstp->ls_open, ls_list) { 3107 stp = LIST_FIRST(&openstp->ls_open); 3108 while (stp != LIST_END(&openstp->ls_open)) { 3109 nstp = LIST_NEXT(stp, ls_list); 3110 /* 3111 * If the owner matches, check for locks and 3112 * then free or return an error. 3113 */ 3114 if (stp->ls_ownerlen == new_stp->ls_ownerlen && 3115 !NFSBCMP(stp->ls_owner, new_stp->ls_owner, 3116 stp->ls_ownerlen)){ 3117 if (LIST_EMPTY(&stp->ls_lock)) { 3118 nfsrv_freelockowner(stp, NULL, 0, p); 3119 } else { 3120 NFSUNLOCKSTATE(); |
3121 error = NFSERR_LOCKSHELD; 3122 goto out; |
3123 } 3124 } 3125 stp = nstp; 3126 } 3127 } 3128 } 3129 NFSUNLOCKSTATE(); |
3130 3131out: 3132 NFSEXITCODE(error); 3133 return (error); |
3134} 3135 3136/* 3137 * Get the file handle for a lock structure. 3138 */ 3139static int 3140nfsrv_getlockfh(vnode_t vp, u_short flags, 3141 struct nfslockfile **new_lfpp, fhandle_t *nfhp, NFSPROC_T *p) --- 10 unchanged lines hidden (view full) --- 3152 new_lfp = *new_lfpp; 3153 fhp = &new_lfp->lf_fh; 3154 } else if (nfhp) { 3155 fhp = nfhp; 3156 } else { 3157 panic("nfsrv_getlockfh"); 3158 } 3159 error = nfsvno_getfh(vp, fhp, p); |
3160 NFSEXITCODE(error); |
3161 return (error); 3162} 3163 3164/* 3165 * Get an nfs lock structure. Allocate one, as required, and return a 3166 * pointer to it. 3167 * Returns an NFSERR_xxx upon failure or -1 to indicate no current lock. 3168 */ --- 239 unchanged lines hidden (view full) --- 3408/* 3409 * This function handles sequencing of locks, etc. 3410 * It returns an error that indicates what the caller should do. 3411 */ 3412static int 3413nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid, 3414 struct nfsstate *stp, struct nfsrvcache *op) 3415{ |
3416 int error = 0; |
3417 3418 if (op != nd->nd_rp) 3419 panic("nfsrvstate checkseqid"); 3420 if (!(op->rc_flag & RC_INPROG)) 3421 panic("nfsrvstate not inprog"); 3422 if (stp->ls_op && stp->ls_op->rc_refcnt <= 0) { 3423 printf("refcnt=%d\n", stp->ls_op->rc_refcnt); 3424 panic("nfsrvstate op refcnt"); 3425 } 3426 if ((stp->ls_seq + 1) == seqid) { 3427 if (stp->ls_op) 3428 nfsrvd_derefcache(stp->ls_op); 3429 stp->ls_op = op; 3430 nfsrvd_refcache(op); 3431 stp->ls_seq = seqid; |
3432 goto out; |
3433 } else if (stp->ls_seq == seqid && stp->ls_op && 3434 op->rc_xid == stp->ls_op->rc_xid && 3435 op->rc_refcnt == 0 && 3436 op->rc_reqlen == stp->ls_op->rc_reqlen && 3437 op->rc_cksum == stp->ls_op->rc_cksum) { |
3438 if (stp->ls_op->rc_flag & RC_INPROG) { 3439 error = NFSERR_DONTREPLY; 3440 goto out; 3441 } |
3442 nd->nd_rp = stp->ls_op; 3443 nd->nd_rp->rc_flag |= RC_INPROG; 3444 nfsrvd_delcache(op); |
3445 error = NFSERR_REPLYFROMCACHE; 3446 goto out; |
3447 } |
3448 error = NFSERR_BADSEQID; 3449 3450out: 3451 NFSEXITCODE2(error, nd); 3452 return (error); |
3453} 3454 3455/* 3456 * Get the client ip address for callbacks. If the strings can't be parsed, 3457 * just set lc_program to 0 to indicate no callbacks are possible. 3458 * (For cases where the address can't be parsed or is 0.0.0.0.0.0, set 3459 * the address to the client's transport address. This won't be used 3460 * for callbacks, but can be printed out by newnfsstats for info.) --- 107 unchanged lines hidden (view full) --- 3568 } 3569 if (cantparse) { 3570 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 3571 rad->sin_addr.s_addr = sad->sin_addr.s_addr; 3572 rad->sin_port = 0x0; 3573 clp->lc_program = 0; 3574 } 3575nfsmout: |
3576 NFSEXITCODE2(error, nd); |
3577 return (error); 3578} 3579 3580/* 3581 * Turn a string of up to three decimal digits into a number. Return -1 upon 3582 * error. 3583 */ 3584static int --- 16 unchanged lines hidden (view full) --- 3601 3602/* 3603 * This function checks for restart conditions. 3604 */ 3605static int 3606nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags, 3607 nfsv4stateid_t *stateidp, int specialid) 3608{ |
3609 int ret = 0; |
3610 3611 /* 3612 * First check for a server restart. Open, LockT, ReleaseLockOwner 3613 * and DelegPurge have a clientid, the rest a stateid. 3614 */ 3615 if (flags & 3616 (NFSLCK_OPEN | NFSLCK_TEST | NFSLCK_RELEASE | NFSLCK_DELEGPURGE)) { |
3617 if (clientid.lval[0] != nfsrvboottime) { 3618 ret = NFSERR_STALECLIENTID; 3619 goto out; 3620 } |
3621 } else if (stateidp->other[0] != nfsrvboottime && |
3622 specialid == 0) { 3623 ret = NFSERR_STALESTATEID; 3624 goto out; 3625 } |
3626 3627 /* 3628 * Read, Write, Setattr and LockT can return NFSERR_GRACE and do 3629 * not use a lock/open owner seqid#, so the check can be done now. 3630 * (The others will be checked, as required, later.) 3631 */ 3632 if (!(flags & (NFSLCK_CHECK | NFSLCK_TEST))) |
3633 goto out; |
3634 3635 NFSLOCKSTATE(); 3636 ret = nfsrv_checkgrace(flags); 3637 NFSUNLOCKSTATE(); |
3638 3639out: 3640 NFSEXITCODE(ret); |
3641 return (ret); 3642} 3643 3644/* 3645 * Check for grace. 3646 */ 3647static int 3648nfsrv_checkgrace(u_int32_t flags) 3649{ |
3650 int error = 0; |
3651 3652 if (nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) { |
3653 if (flags & NFSLCK_RECLAIM) { 3654 error = NFSERR_NOGRACE; 3655 goto out; 3656 } |
3657 } else { |
3658 if (!(flags & NFSLCK_RECLAIM)) { 3659 error = NFSERR_GRACE; 3660 goto out; 3661 } |
3662 3663 /* 3664 * If grace is almost over and we are still getting Reclaims, 3665 * extend grace a bit. 3666 */ 3667 if ((NFSD_MONOSEC + NFSRV_LEASEDELTA) > 3668 nfsrv_stablefirst.nsf_eograce) 3669 nfsrv_stablefirst.nsf_eograce = NFSD_MONOSEC + 3670 NFSRV_LEASEDELTA; 3671 } |
3672 3673out: 3674 NFSEXITCODE(error); 3675 return (error); |
3676} 3677 3678/* 3679 * Do a server callback. 3680 */ 3681static int 3682nfsrv_docallback(struct nfsclient *clp, int procnum, 3683 nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp, --- 132 unchanged lines hidden (view full) --- 3816 clp->lc_cbref--; 3817 if ((clp->lc_flags & LCL_WAKEUPWANTED) && clp->lc_cbref == 0) { 3818 clp->lc_flags &= ~LCL_WAKEUPWANTED; 3819 NFSUNLOCKSTATE(); 3820 wakeup((caddr_t)clp); 3821 } else { 3822 NFSUNLOCKSTATE(); 3823 } |
3824 3825 NFSEXITCODE(error); |
3826 return (error); 3827} 3828 3829/* 3830 * Return the next index# for a clientid. Mostly just increment and return 3831 * the next one, but... if the 32bit unsigned does actually wrap around, 3832 * it should be rebooted. 3833 * At an average rate of one new client per second, it will wrap around in --- 511 unchanged lines hidden (view full) --- 4345 */ 4346 if (stp->ls_flags & NFSLCK_OLDDELEG) { 4347 /* 4348 * You can delete it, if it has expired. 4349 */ 4350 if (clp->lc_delegtime < NFSD_MONOSEC) { 4351 nfsrv_freedeleg(stp); 4352 NFSUNLOCKSTATE(); |
4353 error = -1; 4354 goto out; |
4355 } 4356 NFSUNLOCKSTATE(); 4357 /* 4358 * During this delay, the old delegation could expire or it 4359 * could be recovered by the client via an Open with 4360 * CLAIM_DELEGATE_PREV. 4361 * Release the nfsv4root_lock, if held. 4362 */ 4363 if (*haslockp) { 4364 *haslockp = 0; 4365 NFSLOCKV4ROOTMUTEX(); 4366 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4367 NFSUNLOCKV4ROOTMUTEX(); 4368 } |
4369 error = NFSERR_DELAY; 4370 goto out; |
4371 } 4372 4373 /* 4374 * It's a current delegation, so: 4375 * - check to see if the delegation has expired 4376 * - if so, get the v4root lock and then expire it 4377 */ 4378 if (!(stp->ls_flags & NFSLCK_DELEGRECALL)) { --- 39 unchanged lines hidden (view full) --- 4418 } 4419 retrycnt = 0; 4420 do { 4421 error = nfsrv_docallback(clp, NFSV4OP_CBRECALL, 4422 &tstateid, 0, &tfh, NULL, NULL, p); 4423 retrycnt++; 4424 } while ((error == NFSERR_BADSTATEID || 4425 error == NFSERR_BADHANDLE) && retrycnt < NFSV4_CBRETRYCNT); |
4426 error = NFSERR_DELAY; 4427 goto out; |
4428 } 4429 4430 if (clp->lc_expiry >= NFSD_MONOSEC && 4431 stp->ls_delegtime >= NFSD_MONOSEC) { 4432 NFSUNLOCKSTATE(); 4433 /* 4434 * A recall has been done, but it has not yet expired. 4435 * So, RETURN_DELAY. 4436 */ 4437 if (*haslockp) { 4438 *haslockp = 0; 4439 NFSLOCKV4ROOTMUTEX(); 4440 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4441 NFSUNLOCKV4ROOTMUTEX(); 4442 } |
4443 error = NFSERR_DELAY; 4444 goto out; |
4445 } 4446 4447 /* 4448 * If we don't yet have the lock, just get it and then return, 4449 * since we need that before deleting expired state, such as 4450 * this delegation. 4451 * When getting the lock, unlock the vnode, so other nfsds that 4452 * are in progress, won't get stuck waiting for the vnode lock. --- 11 unchanged lines hidden (view full) --- 4464 NFSUNLOCKV4ROOTMUTEX(); 4465 *haslockp = 1; 4466 NFSVOPLOCK(vp, lktype | LK_RETRY); 4467 if ((vp->v_iflag & VI_DOOMED) != 0) { 4468 *haslockp = 0; 4469 NFSLOCKV4ROOTMUTEX(); 4470 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4471 NFSUNLOCKV4ROOTMUTEX(); |
4472 error = NFSERR_PERM; 4473 goto out; |
4474 } |
4475 error = -1; 4476 goto out; |
4477 } 4478 4479 NFSUNLOCKSTATE(); 4480 /* 4481 * Ok, we can delete the expired delegation. 4482 * First, write the Revoke record to stable storage and then 4483 * clear out the conflict. 4484 * Since all other nfsd threads are now blocked, we can safely --- 8 unchanged lines hidden (view full) --- 4493 LIST_REMOVE(clp, lc_hash); 4494 zapped_clp = 1; 4495 } else { 4496 nfsrv_freedeleg(stp); 4497 zapped_clp = 0; 4498 } 4499 if (zapped_clp) 4500 nfsrv_zapclient(clp, p); |
4501 error = -1; 4502 4503out: 4504 NFSEXITCODE(error); 4505 return (error); |
4506} 4507 4508/* 4509 * Check for a remove allowed, if remove is set to 1 and get rid of 4510 * delegations. 4511 */ 4512APPLESTATIC int 4513nfsrv_checkremove(vnode_t vp, int remove, NFSPROC_T *p) --- 15 unchanged lines hidden (view full) --- 4529 if (error) { 4530 NFSUNLOCKSTATE(); 4531 if (haslock) { 4532 NFSLOCKV4ROOTMUTEX(); 4533 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4534 NFSUNLOCKV4ROOTMUTEX(); 4535 } 4536 if (error == -1) |
4537 error = 0; 4538 goto out; |
4539 } 4540 4541 /* 4542 * Now, we must Recall any delegations. 4543 */ 4544 error = nfsrv_cleandeleg(vp, lfp, NULL, &haslock, p); 4545 if (error) { 4546 /* 4547 * nfsrv_cleandeleg() unlocks state for non-zero 4548 * return. 4549 */ 4550 if (error == -1) 4551 goto tryagain; 4552 if (haslock) { 4553 NFSLOCKV4ROOTMUTEX(); 4554 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4555 NFSUNLOCKV4ROOTMUTEX(); 4556 } |
4557 goto out; |
4558 } 4559 4560 /* 4561 * Now, look for a conflicting open share. 4562 */ 4563 if (remove) { 4564 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 4565 if (stp->ls_flags & NFSLCK_WRITEDENY) { --- 4 unchanged lines hidden (view full) --- 4570 } 4571 4572 NFSUNLOCKSTATE(); 4573 if (haslock) { 4574 NFSLOCKV4ROOTMUTEX(); 4575 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4576 NFSUNLOCKV4ROOTMUTEX(); 4577 } |
4578 4579out: 4580 NFSEXITCODE(error); |
4581 return (error); 4582} 4583 4584/* 4585 * Clear out all delegations for the file referred to by lfp. 4586 * May return NFSERR_DELAY, if there will be a delay waiting for 4587 * delegations to expire. 4588 * Returns -1 to indicate it slept while recalling a delegation. 4589 * This function has the side effect of deleting the nfslockfile structure, 4590 * if it no longer has associated state and didn't have to sleep. 4591 * Unlocks State before a non-zero value is returned. 4592 */ 4593static int 4594nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp, 4595 struct nfsclient *clp, int *haslockp, NFSPROC_T *p) 4596{ 4597 struct nfsstate *stp, *nstp; |
4598 int ret = 0; |
4599 4600 stp = LIST_FIRST(&lfp->lf_deleg); 4601 while (stp != LIST_END(&lfp->lf_deleg)) { 4602 nstp = LIST_NEXT(stp, ls_file); 4603 if (stp->ls_clp != clp) { 4604 ret = nfsrv_delegconflict(stp, haslockp, p, vp); 4605 if (ret) { 4606 /* 4607 * nfsrv_delegconflict() unlocks state 4608 * when it returns non-zero. 4609 */ |
4610 goto out; |
4611 } 4612 } 4613 stp = nstp; 4614 } |
4615out: 4616 NFSEXITCODE(ret); 4617 return (ret); |
4618} 4619 4620/* 4621 * There are certain operations that, when being done outside of NFSv4, 4622 * require that any NFSv4 delegation for the file be recalled. 4623 * This function is to be called for those cases: 4624 * VOP_RENAME() - When a delegation is being recalled for any reason, 4625 * the client may have to do Opens against the server, using the file's --- 117 unchanged lines hidden (view full) --- 4743 lop->lo_first = 0; 4744 } 4745 if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) || 4746 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) || 4747 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_MODE) || 4748 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL)) 4749 stp->ls_flags |= NFSLCK_SETATTR; 4750 if (stp->ls_flags == 0) |
4751 goto out; |
4752 lop->lo_end = NFS64BITSSET; 4753 lop->lo_flags = NFSLCK_WRITE; 4754 stp->ls_ownerlen = 0; 4755 stp->ls_op = NULL; 4756 stp->ls_uid = nd->nd_cred->cr_uid; 4757 stp->ls_stateid.seqid = stateidp->seqid; 4758 clientid.lval[0] = stp->ls_stateid.other[0] = stateidp->other[0]; 4759 clientid.lval[1] = stp->ls_stateid.other[1] = stateidp->other[1]; 4760 stp->ls_stateid.other[2] = stateidp->other[2]; 4761 error = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 4762 stateidp, exp, nd, p); |
4763 4764out: 4765 NFSEXITCODE2(error, nd); |
4766 return (error); 4767} 4768 4769/* 4770 * Check for a write delegation and do a CBGETATTR if there is one, updating 4771 * the attributes, as required. 4772 * Should I return an error if I can't get the attributes? (For now, I'll 4773 * just return ok. 4774 */ 4775APPLESTATIC int 4776nfsrv_checkgetattr(struct nfsrv_descript *nd, vnode_t vp, 4777 struct nfsvattr *nvap, nfsattrbit_t *attrbitp, struct ucred *cred, 4778 NFSPROC_T *p) 4779{ 4780 struct nfsstate *stp; 4781 struct nfslockfile *lfp; 4782 struct nfsclient *clp; 4783 struct nfsvattr nva; 4784 fhandle_t nfh; |
4785 int error = 0; |
4786 nfsattrbit_t cbbits; 4787 u_quad_t delegfilerev; 4788 4789 NFSCBGETATTR_ATTRBIT(attrbitp, &cbbits); 4790 if (!NFSNONZERO_ATTRBIT(&cbbits)) |
4791 goto out; |
4792 4793 /* 4794 * Get the lock file structure. 4795 * (A return of -1 means no associated state, so return ok.) 4796 */ 4797 error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p); 4798 NFSLOCKSTATE(); 4799 if (!error) 4800 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0); 4801 if (error) { 4802 NFSUNLOCKSTATE(); 4803 if (error == -1) |
4804 error = 0; 4805 goto out; |
4806 } 4807 4808 /* 4809 * Now, look for a write delegation. 4810 */ 4811 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 4812 if (stp->ls_flags & NFSLCK_DELEGWRITE) 4813 break; 4814 } 4815 if (stp == LIST_END(&lfp->lf_deleg)) { 4816 NFSUNLOCKSTATE(); |
4817 goto out; |
4818 } 4819 clp = stp->ls_clp; 4820 delegfilerev = stp->ls_filerev; 4821 4822 /* 4823 * If the Write delegation was issued as a part of this Compound RPC 4824 * or if we have an Implied Clientid (used in a previous Op in this 4825 * compound) and it is the client the delegation was issued to, 4826 * just return ok. 4827 * I also assume that it is from the same client iff the network 4828 * host IP address is the same as the callback address. (Not 4829 * exactly correct by the RFC, but avoids a lot of Getattr 4830 * callbacks.) 4831 */ 4832 if (nd->nd_compref == stp->ls_compref || 4833 ((nd->nd_flag & ND_IMPLIEDCLID) && 4834 clp->lc_clientid.qval == nd->nd_clientid.qval) || 4835 nfsaddr2_match(clp->lc_req.nr_nam, nd->nd_nam)) { 4836 NFSUNLOCKSTATE(); |
4837 goto out; |
4838 } 4839 4840 /* 4841 * We are now done with the delegation state structure, 4842 * so the statelock can be released and we can now tsleep(). 4843 */ 4844 4845 /* --- 14 unchanged lines hidden (view full) --- 4860 nfsvno_updfilerev(vp, nvap, cred, p); 4861 if (NFSVNO_ISSETSIZE(&nva)) 4862 nvap->na_size = nva.na_size; 4863 } 4864 } 4865 } else { 4866 NFSUNLOCKSTATE(); 4867 } |
4868 error = 0; 4869 4870out: 4871 NFSEXITCODE2(error, nd); 4872 return (error); |
4873} 4874 4875/* 4876 * This function looks for openowners that haven't had any opens for 4877 * a while and throws them away. Called by an nfsd when NFSNSF_NOOPENS 4878 * is set. 4879 */ 4880APPLESTATIC void --- 166 unchanged lines hidden (view full) --- 5047 lop = nlop; 5048 } 5049 } 5050 } 5051 if (first < end && error == 0) 5052 /* handle fragment past end of list */ 5053 error = nfsrv_dolocal(vp, lfp, flags, NFSLCK_UNLOCK, first, 5054 end, cfp, p); |
5055 5056 NFSEXITCODE(error); |
5057 return (error); 5058} 5059 5060/* 5061 * Local lock unlock. Unlock all byte ranges that are no longer locked 5062 * by NFSv4. To do this, unlock any subranges of first-->end that 5063 * do not overlap with the byte ranges of any lock in the lfp->lf_lock 5064 * list. This list has all locks for the file held by other --- 66 unchanged lines hidden (view full) --- 5131 * Do the local lock operation and update the rollback list, as required. 5132 * Perform the rollback and return the error if nfsvno_advlock() fails. 5133 */ 5134static int 5135nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, int oldflags, 5136 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p) 5137{ 5138 struct nfsrollback *rlp; |
5139 int error = 0, ltype, oldltype; |
5140 5141 if (flags & NFSLCK_WRITE) 5142 ltype = F_WRLCK; 5143 else if (flags & NFSLCK_READ) 5144 ltype = F_RDLCK; 5145 else 5146 ltype = F_UNLCK; 5147 if (oldflags & NFSLCK_WRITE) 5148 oldltype = F_WRLCK; 5149 else if (oldflags & NFSLCK_READ) 5150 oldltype = F_RDLCK; 5151 else 5152 oldltype = F_UNLCK; 5153 if (ltype == oldltype || (oldltype == F_WRLCK && ltype == F_RDLCK)) 5154 /* nothing to do */ |
5155 goto out; |
5156 error = nfsvno_advlock(vp, ltype, first, end, p); 5157 if (error != 0) { 5158 if (cfp != NULL) { 5159 cfp->cl_clientid.lval[0] = 0; 5160 cfp->cl_clientid.lval[1] = 0; 5161 cfp->cl_first = 0; 5162 cfp->cl_end = NFS64BITSSET; 5163 cfp->cl_flags = NFSLCK_WRITE; --- 4 unchanged lines hidden (view full) --- 5168 } else if (ltype != F_UNLCK) { 5169 rlp = malloc(sizeof (struct nfsrollback), M_NFSDROLLBACK, 5170 M_WAITOK); 5171 rlp->rlck_first = first; 5172 rlp->rlck_end = end; 5173 rlp->rlck_type = oldltype; 5174 LIST_INSERT_HEAD(&lfp->lf_rollback, rlp, rlck_list); 5175 } |
5176 5177out: 5178 NFSEXITCODE(error); |
5179 return (error); 5180} 5181 5182/* 5183 * Roll back local lock changes and free up the rollback list. 5184 */ 5185static void 5186nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, NFSPROC_T *p) --- 104 unchanged lines hidden --- |