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 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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>
| 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 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 224083 2011-07-16 08:05:41Z zack $");
| 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; 38 39extern int newnfs_numnfsd; 40extern struct nfsstats newnfsstats; 41extern int nfsrv_lease; 42extern struct timeval nfsboottime; 43extern u_int32_t newnfs_true, newnfs_false; 44NFSV4ROOTLOCKMUTEX; 45NFSSTATESPINLOCK; 46 47/* 48 * Hash lists for nfs V4. 49 * (Some would put them in the .h file, but I don't like declaring storage 50 * in a .h) 51 */ 52struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; 53struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE]; 54#endif /* !APPLEKEXT */ 55 56static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; 57static time_t nfsrvboottime; 58static int nfsrv_writedelegifpos = 1; 59static int nfsrv_returnoldstateid = 0, nfsrv_clients = 0; 60static int nfsrv_clienthighwater = NFSRV_CLIENTHIGHWATER; 61static int nfsrv_nogsscallback = 0; 62 63/* local functions */ 64static void nfsrv_dumpaclient(struct nfsclient *clp, 65 struct nfsd_dumpclients *dumpp); 66static void nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, 67 NFSPROC_T *p); 68static int nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, 69 NFSPROC_T *p); 70static void nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep, 71 NFSPROC_T *p); 72static void nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, 73 int cansleep, NFSPROC_T *p); 74static void nfsrv_freenfslock(struct nfslock *lop); 75static void nfsrv_freenfslockfile(struct nfslockfile *lfp); 76static void nfsrv_freedeleg(struct nfsstate *); 77static int nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, 78 u_int32_t flags, struct nfsstate **stpp); 79static void nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp, 80 struct nfsstate **stpp); 81static int nfsrv_getlockfh(vnode_t vp, u_short flags, 82 struct nfslockfile **new_lfpp, fhandle_t *nfhp, NFSPROC_T *p); 83static int nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp, 84 struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit); 85static void nfsrv_insertlock(struct nfslock *new_lop, 86 struct nfslock *insert_lop, struct nfsstate *stp, struct nfslockfile *lfp); 87static void nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp, 88 struct nfslock **other_lopp, struct nfslockfile *lfp); 89static int nfsrv_getipnumber(u_char *cp); 90static int nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags, 91 nfsv4stateid_t *stateidp, int specialid); 92static int nfsrv_checkgrace(u_int32_t flags); 93static int nfsrv_docallback(struct nfsclient *clp, int procnum, 94 nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp, 95 struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p); 96static u_int32_t nfsrv_nextclientindex(void); 97static u_int32_t nfsrv_nextstateindex(struct nfsclient *clp); 98static void nfsrv_markstable(struct nfsclient *clp); 99static int nfsrv_checkstable(struct nfsclient *clp); 100static int nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, struct 101 vnode *vp, NFSPROC_T *p); 102static int nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, 103 NFSPROC_T *p, vnode_t vp); 104static int nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp, 105 struct nfsclient *clp, int *haslockp, NFSPROC_T *p); 106static int nfsrv_notsamecredname(struct nfsrv_descript *nd, 107 struct nfsclient *clp); 108static time_t nfsrv_leaseexpiry(void); 109static void nfsrv_delaydelegtimeout(struct nfsstate *stp); 110static int nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid, 111 struct nfsstate *stp, struct nfsrvcache *op); 112static int nfsrv_nootherstate(struct nfsstate *stp); 113static int nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, 114 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p); 115static void nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, 116 uint64_t init_first, uint64_t init_end, NFSPROC_T *p); 117static int nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, 118 int oldflags, uint64_t first, uint64_t end, struct nfslockconflict *cfp, 119 NFSPROC_T *p); 120static void nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, 121 NFSPROC_T *p); 122static void nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, 123 uint64_t first, uint64_t end); 124static void nfsrv_locklf(struct nfslockfile *lfp); 125static void nfsrv_unlocklf(struct nfslockfile *lfp); 126 127/* 128 * Scan the client list for a match and either return the current one, 129 * create a new entry or return an error. 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;
| 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; 38 39extern int newnfs_numnfsd; 40extern struct nfsstats newnfsstats; 41extern int nfsrv_lease; 42extern struct timeval nfsboottime; 43extern u_int32_t newnfs_true, newnfs_false; 44NFSV4ROOTLOCKMUTEX; 45NFSSTATESPINLOCK; 46 47/* 48 * Hash lists for nfs V4. 49 * (Some would put them in the .h file, but I don't like declaring storage 50 * in a .h) 51 */ 52struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE]; 53struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE]; 54#endif /* !APPLEKEXT */ 55 56static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; 57static time_t nfsrvboottime; 58static int nfsrv_writedelegifpos = 1; 59static int nfsrv_returnoldstateid = 0, nfsrv_clients = 0; 60static int nfsrv_clienthighwater = NFSRV_CLIENTHIGHWATER; 61static int nfsrv_nogsscallback = 0; 62 63/* local functions */ 64static void nfsrv_dumpaclient(struct nfsclient *clp, 65 struct nfsd_dumpclients *dumpp); 66static void nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, 67 NFSPROC_T *p); 68static int nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, 69 NFSPROC_T *p); 70static void nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep, 71 NFSPROC_T *p); 72static void nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, 73 int cansleep, NFSPROC_T *p); 74static void nfsrv_freenfslock(struct nfslock *lop); 75static void nfsrv_freenfslockfile(struct nfslockfile *lfp); 76static void nfsrv_freedeleg(struct nfsstate *); 77static int nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, 78 u_int32_t flags, struct nfsstate **stpp); 79static void nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp, 80 struct nfsstate **stpp); 81static int nfsrv_getlockfh(vnode_t vp, u_short flags, 82 struct nfslockfile **new_lfpp, fhandle_t *nfhp, NFSPROC_T *p); 83static int nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp, 84 struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit); 85static void nfsrv_insertlock(struct nfslock *new_lop, 86 struct nfslock *insert_lop, struct nfsstate *stp, struct nfslockfile *lfp); 87static void nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp, 88 struct nfslock **other_lopp, struct nfslockfile *lfp); 89static int nfsrv_getipnumber(u_char *cp); 90static int nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags, 91 nfsv4stateid_t *stateidp, int specialid); 92static int nfsrv_checkgrace(u_int32_t flags); 93static int nfsrv_docallback(struct nfsclient *clp, int procnum, 94 nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp, 95 struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p); 96static u_int32_t nfsrv_nextclientindex(void); 97static u_int32_t nfsrv_nextstateindex(struct nfsclient *clp); 98static void nfsrv_markstable(struct nfsclient *clp); 99static int nfsrv_checkstable(struct nfsclient *clp); 100static int nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, struct 101 vnode *vp, NFSPROC_T *p); 102static int nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, 103 NFSPROC_T *p, vnode_t vp); 104static int nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp, 105 struct nfsclient *clp, int *haslockp, NFSPROC_T *p); 106static int nfsrv_notsamecredname(struct nfsrv_descript *nd, 107 struct nfsclient *clp); 108static time_t nfsrv_leaseexpiry(void); 109static void nfsrv_delaydelegtimeout(struct nfsstate *stp); 110static int nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid, 111 struct nfsstate *stp, struct nfsrvcache *op); 112static int nfsrv_nootherstate(struct nfsstate *stp); 113static int nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, 114 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p); 115static void nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, 116 uint64_t init_first, uint64_t init_end, NFSPROC_T *p); 117static int nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, 118 int oldflags, uint64_t first, uint64_t end, struct nfslockconflict *cfp, 119 NFSPROC_T *p); 120static void nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, 121 NFSPROC_T *p); 122static void nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, 123 uint64_t first, uint64_t end); 124static void nfsrv_locklf(struct nfslockfile *lfp); 125static void nfsrv_unlocklf(struct nfslockfile *lfp); 126 127/* 128 * Scan the client list for a match and either return the current one, 129 * create a new entry or return an error. 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;
| 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 */
| 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 return (NFSERR_RESOURCE);
| 147 if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { 148 error = NFSERR_RESOURCE; 149 goto out; 150 }
|
149 150 if (nfsrv_issuedelegs == 0 || 151 ((nd->nd_flag & ND_GSS) != 0 && nfsrv_nogsscallback != 0)) 152 /* 153 * Don't do callbacks when delegations are disabled or 154 * for AUTH_GSS unless enabled via nfsrv_nogsscallback. 155 * If establishing a callback connection is attempted 156 * when a firewall is blocking the callback path, the 157 * server may wait too long for the connect attempt to 158 * succeed during the Open. Some clients, such as Linux, 159 * may timeout and give up on the Open before the server 160 * replies. Also, since AUTH_GSS callbacks are not 161 * yet interoperability tested, they might cause the 162 * server to crap out, if they get past the Init call to 163 * the client. 164 */ 165 new_clp->lc_program = 0; 166 167 /* Lock out other nfsd threads */ 168 NFSLOCKV4ROOTMUTEX(); 169 nfsv4_relref(&nfsv4rootfs_lock); 170 do { 171 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 172 NFSV4ROOTLOCKMUTEXPTR, NULL); 173 } while (!igotlock); 174 NFSUNLOCKV4ROOTMUTEX(); 175 176 /* 177 * Search for a match in the client list. 178 */ 179 gotit = i = 0; 180 while (i < NFSCLIENTHASHSIZE && !gotit) { 181 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 182 if (new_clp->lc_idlen == clp->lc_idlen && 183 !NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) { 184 gotit = 1; 185 break; 186 } 187 } 188 i++; 189 } 190 if (!gotit || 191 (clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) { 192 /* 193 * Get rid of the old one. 194 */ 195 if (i != NFSCLIENTHASHSIZE) { 196 LIST_REMOVE(clp, lc_hash); 197 nfsrv_cleanclient(clp, p); 198 nfsrv_freedeleglist(&clp->lc_deleg); 199 nfsrv_freedeleglist(&clp->lc_olddeleg); 200 zapit = 1; 201 } 202 /* 203 * Add it after assigning a client id to it. 204 */ 205 new_clp->lc_flags |= LCL_NEEDSCONFIRM; 206 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 207 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 208 (u_int32_t)nfsrvboottime; 209 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 210 nfsrv_nextclientindex(); 211 new_clp->lc_stateindex = 0; 212 new_clp->lc_statemaxindex = 0; 213 new_clp->lc_cbref = 0; 214 new_clp->lc_expiry = nfsrv_leaseexpiry(); 215 LIST_INIT(&new_clp->lc_open); 216 LIST_INIT(&new_clp->lc_deleg); 217 LIST_INIT(&new_clp->lc_olddeleg); 218 for (i = 0; i < NFSSTATEHASHSIZE; i++) 219 LIST_INIT(&new_clp->lc_stateid[i]); 220 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 221 lc_hash); 222 newnfsstats.srvclients++; 223 nfsrv_openpluslock++; 224 nfsrv_clients++; 225 NFSLOCKV4ROOTMUTEX(); 226 nfsv4_unlock(&nfsv4rootfs_lock, 1); 227 NFSUNLOCKV4ROOTMUTEX(); 228 if (zapit) 229 nfsrv_zapclient(clp, p); 230 *new_clpp = NULL;
| 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 159 * server may wait too long for the connect attempt to 160 * succeed during the Open. Some clients, such as Linux, 161 * may timeout and give up on the Open before the server 162 * replies. Also, since AUTH_GSS callbacks are not 163 * yet interoperability tested, they might cause the 164 * server to crap out, if they get past the Init call to 165 * the client. 166 */ 167 new_clp->lc_program = 0; 168 169 /* Lock out other nfsd threads */ 170 NFSLOCKV4ROOTMUTEX(); 171 nfsv4_relref(&nfsv4rootfs_lock); 172 do { 173 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 174 NFSV4ROOTLOCKMUTEXPTR, NULL); 175 } while (!igotlock); 176 NFSUNLOCKV4ROOTMUTEX(); 177 178 /* 179 * Search for a match in the client list. 180 */ 181 gotit = i = 0; 182 while (i < NFSCLIENTHASHSIZE && !gotit) { 183 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 184 if (new_clp->lc_idlen == clp->lc_idlen && 185 !NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) { 186 gotit = 1; 187 break; 188 } 189 } 190 i++; 191 } 192 if (!gotit || 193 (clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) { 194 /* 195 * Get rid of the old one. 196 */ 197 if (i != NFSCLIENTHASHSIZE) { 198 LIST_REMOVE(clp, lc_hash); 199 nfsrv_cleanclient(clp, p); 200 nfsrv_freedeleglist(&clp->lc_deleg); 201 nfsrv_freedeleglist(&clp->lc_olddeleg); 202 zapit = 1; 203 } 204 /* 205 * Add it after assigning a client id to it. 206 */ 207 new_clp->lc_flags |= LCL_NEEDSCONFIRM; 208 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 209 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 210 (u_int32_t)nfsrvboottime; 211 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 212 nfsrv_nextclientindex(); 213 new_clp->lc_stateindex = 0; 214 new_clp->lc_statemaxindex = 0; 215 new_clp->lc_cbref = 0; 216 new_clp->lc_expiry = nfsrv_leaseexpiry(); 217 LIST_INIT(&new_clp->lc_open); 218 LIST_INIT(&new_clp->lc_deleg); 219 LIST_INIT(&new_clp->lc_olddeleg); 220 for (i = 0; i < NFSSTATEHASHSIZE; i++) 221 LIST_INIT(&new_clp->lc_stateid[i]); 222 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 223 lc_hash); 224 newnfsstats.srvclients++; 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;
|
231 return (0);
| 233 goto out;
|
232 } 233 234 /* 235 * Now, handle the cases where the id is already issued. 236 */ 237 if (nfsrv_notsamecredname(nd, clp)) { 238 /* 239 * Check to see if there is expired state that should go away. 240 */ 241 if (clp->lc_expiry < NFSD_MONOSEC && 242 (!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg))) { 243 nfsrv_cleanclient(clp, p); 244 nfsrv_freedeleglist(&clp->lc_deleg); 245 } 246 247 /* 248 * If there is outstanding state, then reply NFSERR_CLIDINUSE per 249 * RFC3530 Sec. 8.1.2 last para. 250 */ 251 if (!LIST_EMPTY(&clp->lc_deleg)) { 252 hasstate = 1; 253 } else if (LIST_EMPTY(&clp->lc_open)) { 254 hasstate = 0; 255 } else { 256 hasstate = 0; 257 /* Look for an Open on the OpenOwner */ 258 LIST_FOREACH(stp, &clp->lc_open, ls_list) { 259 if (!LIST_EMPTY(&stp->ls_open)) { 260 hasstate = 1; 261 break; 262 } 263 } 264 } 265 if (hasstate) { 266 /* 267 * If the uid doesn't match, return NFSERR_CLIDINUSE after 268 * filling out the correct ipaddr and portnum. 269 */ 270 sad = NFSSOCKADDR(new_clp->lc_req.nr_nam, struct sockaddr_in *); 271 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 272 sad->sin_addr.s_addr = rad->sin_addr.s_addr; 273 sad->sin_port = rad->sin_port; 274 NFSLOCKV4ROOTMUTEX(); 275 nfsv4_unlock(&nfsv4rootfs_lock, 1); 276 NFSUNLOCKV4ROOTMUTEX();
| 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. 242 */ 243 if (clp->lc_expiry < NFSD_MONOSEC && 244 (!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg))) { 245 nfsrv_cleanclient(clp, p); 246 nfsrv_freedeleglist(&clp->lc_deleg); 247 } 248 249 /* 250 * If there is outstanding state, then reply NFSERR_CLIDINUSE per 251 * RFC3530 Sec. 8.1.2 last para. 252 */ 253 if (!LIST_EMPTY(&clp->lc_deleg)) { 254 hasstate = 1; 255 } else if (LIST_EMPTY(&clp->lc_open)) { 256 hasstate = 0; 257 } else { 258 hasstate = 0; 259 /* Look for an Open on the OpenOwner */ 260 LIST_FOREACH(stp, &clp->lc_open, ls_list) { 261 if (!LIST_EMPTY(&stp->ls_open)) { 262 hasstate = 1; 263 break; 264 } 265 } 266 } 267 if (hasstate) { 268 /* 269 * If the uid doesn't match, return NFSERR_CLIDINUSE after 270 * filling out the correct ipaddr and portnum. 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();
|
277 return (NFSERR_CLIDINUSE);
| 279 error = NFSERR_CLIDINUSE; 280 goto out;
|
278 } 279 } 280 281 if (NFSBCMP(new_clp->lc_verf, clp->lc_verf, NFSX_VERF)) { 282 /* 283 * If the verifier has changed, the client has rebooted 284 * and a new client id is issued. The old state info 285 * can be thrown away once the SETCLIENTID_CONFIRM occurs. 286 */ 287 LIST_REMOVE(clp, lc_hash); 288 new_clp->lc_flags |= LCL_NEEDSCONFIRM; 289 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 290 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 291 nfsrvboottime; 292 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 293 nfsrv_nextclientindex(); 294 new_clp->lc_stateindex = 0; 295 new_clp->lc_statemaxindex = 0; 296 new_clp->lc_cbref = 0; 297 new_clp->lc_expiry = nfsrv_leaseexpiry(); 298 299 /* 300 * Save the state until confirmed. 301 */ 302 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list); 303 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list) 304 tstp->ls_clp = new_clp; 305 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list); 306 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list) 307 tstp->ls_clp = new_clp; 308 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, 309 ls_list); 310 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) 311 tstp->ls_clp = new_clp; 312 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 313 LIST_NEWHEAD(&new_clp->lc_stateid[i], 314 &clp->lc_stateid[i], ls_hash); 315 LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_list) 316 tstp->ls_clp = new_clp; 317 } 318 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 319 lc_hash); 320 newnfsstats.srvclients++; 321 nfsrv_openpluslock++; 322 nfsrv_clients++; 323 NFSLOCKV4ROOTMUTEX(); 324 nfsv4_unlock(&nfsv4rootfs_lock, 1); 325 NFSUNLOCKV4ROOTMUTEX(); 326 327 /* 328 * Must wait until any outstanding callback on the old clp 329 * completes. 330 */ 331 while (clp->lc_cbref) { 332 clp->lc_flags |= LCL_WAKEUPWANTED; 333 (void) tsleep((caddr_t)clp, PZERO - 1, 334 "nfsd clp", 10 * hz); 335 } 336 nfsrv_zapclient(clp, p); 337 *new_clpp = NULL;
| 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. 289 */ 290 LIST_REMOVE(clp, lc_hash); 291 new_clp->lc_flags |= LCL_NEEDSCONFIRM; 292 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 293 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 294 nfsrvboottime; 295 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 296 nfsrv_nextclientindex(); 297 new_clp->lc_stateindex = 0; 298 new_clp->lc_statemaxindex = 0; 299 new_clp->lc_cbref = 0; 300 new_clp->lc_expiry = nfsrv_leaseexpiry(); 301 302 /* 303 * Save the state until confirmed. 304 */ 305 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list); 306 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list) 307 tstp->ls_clp = new_clp; 308 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list); 309 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list) 310 tstp->ls_clp = new_clp; 311 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, 312 ls_list); 313 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) 314 tstp->ls_clp = new_clp; 315 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 316 LIST_NEWHEAD(&new_clp->lc_stateid[i], 317 &clp->lc_stateid[i], ls_hash); 318 LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_list) 319 tstp->ls_clp = new_clp; 320 } 321 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 322 lc_hash); 323 newnfsstats.srvclients++; 324 nfsrv_openpluslock++; 325 nfsrv_clients++; 326 NFSLOCKV4ROOTMUTEX(); 327 nfsv4_unlock(&nfsv4rootfs_lock, 1); 328 NFSUNLOCKV4ROOTMUTEX(); 329 330 /* 331 * Must wait until any outstanding callback on the old clp 332 * completes. 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;
|
338 return (0);
| 341 goto out;
|
339 } 340 /* 341 * id and verifier match, so update the net address info 342 * and get rid of any existing callback authentication 343 * handle, so a new one will be acquired. 344 */ 345 LIST_REMOVE(clp, lc_hash); 346 new_clp->lc_flags |= (LCL_NEEDSCONFIRM | LCL_DONTCLEAN); 347 new_clp->lc_expiry = nfsrv_leaseexpiry(); 348 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 349 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 350 clp->lc_clientid.lval[0]; 351 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 352 clp->lc_clientid.lval[1]; 353 new_clp->lc_delegtime = clp->lc_delegtime; 354 new_clp->lc_stateindex = clp->lc_stateindex; 355 new_clp->lc_statemaxindex = clp->lc_statemaxindex; 356 new_clp->lc_cbref = 0; 357 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list); 358 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list) 359 tstp->ls_clp = new_clp; 360 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list); 361 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list) 362 tstp->ls_clp = new_clp; 363 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list); 364 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) 365 tstp->ls_clp = new_clp; 366 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 367 LIST_NEWHEAD(&new_clp->lc_stateid[i], &clp->lc_stateid[i], 368 ls_hash); 369 LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_list) 370 tstp->ls_clp = new_clp; 371 } 372 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 373 lc_hash); 374 newnfsstats.srvclients++; 375 nfsrv_openpluslock++; 376 nfsrv_clients++; 377 NFSLOCKV4ROOTMUTEX(); 378 nfsv4_unlock(&nfsv4rootfs_lock, 1); 379 NFSUNLOCKV4ROOTMUTEX(); 380 381 /* 382 * Must wait until any outstanding callback on the old clp 383 * completes. 384 */ 385 while (clp->lc_cbref) { 386 clp->lc_flags |= LCL_WAKEUPWANTED; 387 (void) tsleep((caddr_t)clp, PZERO - 1, "nfsd clp", 10 * hz); 388 } 389 nfsrv_zapclient(clp, p); 390 *new_clpp = NULL;
| 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); 350 new_clp->lc_expiry = nfsrv_leaseexpiry(); 351 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index; 352 clientidp->lval[0] = new_clp->lc_clientid.lval[0] = 353 clp->lc_clientid.lval[0]; 354 clientidp->lval[1] = new_clp->lc_clientid.lval[1] = 355 clp->lc_clientid.lval[1]; 356 new_clp->lc_delegtime = clp->lc_delegtime; 357 new_clp->lc_stateindex = clp->lc_stateindex; 358 new_clp->lc_statemaxindex = clp->lc_statemaxindex; 359 new_clp->lc_cbref = 0; 360 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list); 361 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list) 362 tstp->ls_clp = new_clp; 363 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list); 364 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list) 365 tstp->ls_clp = new_clp; 366 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list); 367 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list) 368 tstp->ls_clp = new_clp; 369 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 370 LIST_NEWHEAD(&new_clp->lc_stateid[i], &clp->lc_stateid[i], 371 ls_hash); 372 LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_list) 373 tstp->ls_clp = new_clp; 374 } 375 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp, 376 lc_hash); 377 newnfsstats.srvclients++; 378 nfsrv_openpluslock++; 379 nfsrv_clients++; 380 NFSLOCKV4ROOTMUTEX(); 381 nfsv4_unlock(&nfsv4rootfs_lock, 1); 382 NFSUNLOCKV4ROOTMUTEX(); 383 384 /* 385 * Must wait until any outstanding callback on the old clp 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;
|
391 return (0);
| 394 395out: 396 NFSEXITCODE2(error, nd); 397 return (error);
|
392} 393 394/* 395 * Check to see if the client id exists and optionally confirm it. 396 */ 397APPLESTATIC int 398nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp, 399 nfsquad_t confirm, struct nfsrv_descript *nd, NFSPROC_T *p) 400{ 401 struct nfsclient *clp; 402 struct nfsstate *stp; 403 int i; 404 struct nfsclienthashhead *hp; 405 int error = 0, igotlock, doneok; 406 407 if (clpp) 408 *clpp = NULL;
| 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;
|
409 if (nfsrvboottime != clientid.lval[0]) 410 return (NFSERR_STALECLIENTID);
| 415 if (nfsrvboottime != clientid.lval[0]) { 416 error = NFSERR_STALECLIENTID; 417 goto out; 418 }
|
411 412 /* 413 * If called with opflags == CLOPS_RENEW, the State Lock is 414 * already held. Otherwise, we need to get either that or, 415 * for the case of Confirm, lock out the nfsd threads. 416 */ 417 if (opflags & CLOPS_CONFIRM) { 418 NFSLOCKV4ROOTMUTEX(); 419 nfsv4_relref(&nfsv4rootfs_lock); 420 do { 421 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 422 NFSV4ROOTLOCKMUTEXPTR, NULL); 423 } while (!igotlock); 424 NFSUNLOCKV4ROOTMUTEX(); 425 } else if (opflags != CLOPS_RENEW) { 426 NFSLOCKSTATE(); 427 } 428 429 hp = NFSCLIENTHASH(clientid); 430 LIST_FOREACH(clp, hp, lc_hash) { 431 if (clp->lc_clientid.lval[1] == clientid.lval[1]) 432 break; 433 } 434 if (clp == LIST_END(hp)) { 435 if (opflags & CLOPS_CONFIRM) 436 error = NFSERR_STALECLIENTID; 437 else 438 error = NFSERR_EXPIRED; 439 } else if (clp->lc_flags & LCL_ADMINREVOKED) { 440 /* 441 * If marked admin revoked, just return the error. 442 */ 443 error = NFSERR_ADMINREVOKED; 444 } 445 if (error) { 446 if (opflags & CLOPS_CONFIRM) { 447 NFSLOCKV4ROOTMUTEX(); 448 nfsv4_unlock(&nfsv4rootfs_lock, 1); 449 NFSUNLOCKV4ROOTMUTEX(); 450 } else if (opflags != CLOPS_RENEW) { 451 NFSUNLOCKSTATE(); 452 }
| 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(); 427 nfsv4_relref(&nfsv4rootfs_lock); 428 do { 429 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 430 NFSV4ROOTLOCKMUTEXPTR, NULL); 431 } while (!igotlock); 432 NFSUNLOCKV4ROOTMUTEX(); 433 } else if (opflags != CLOPS_RENEW) { 434 NFSLOCKSTATE(); 435 } 436 437 hp = NFSCLIENTHASH(clientid); 438 LIST_FOREACH(clp, hp, lc_hash) { 439 if (clp->lc_clientid.lval[1] == clientid.lval[1]) 440 break; 441 } 442 if (clp == LIST_END(hp)) { 443 if (opflags & CLOPS_CONFIRM) 444 error = NFSERR_STALECLIENTID; 445 else 446 error = NFSERR_EXPIRED; 447 } else if (clp->lc_flags & LCL_ADMINREVOKED) { 448 /* 449 * If marked admin revoked, just return the error. 450 */ 451 error = NFSERR_ADMINREVOKED; 452 } 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 }
|
453 return (error);
| 461 goto out;
|
454 } 455 456 /* 457 * Perform any operations specified by the opflags. 458 */ 459 if (opflags & CLOPS_CONFIRM) { 460 if (clp->lc_confirm.qval != confirm.qval) 461 error = NFSERR_STALECLIENTID; 462 else if (nfsrv_notsamecredname(nd, clp)) 463 error = NFSERR_CLIDINUSE; 464 465 if (!error) { 466 if ((clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_DONTCLEAN)) == 467 LCL_NEEDSCONFIRM) { 468 /* 469 * Hang onto the delegations (as old delegations) 470 * for an Open with CLAIM_DELEGATE_PREV unless in 471 * grace, but get rid of the rest of the state. 472 */ 473 nfsrv_cleanclient(clp, p); 474 nfsrv_freedeleglist(&clp->lc_olddeleg); 475 if (nfsrv_checkgrace(0)) { 476 /* In grace, so just delete delegations */ 477 nfsrv_freedeleglist(&clp->lc_deleg); 478 } else { 479 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) 480 stp->ls_flags |= NFSLCK_OLDDELEG; 481 clp->lc_delegtime = NFSD_MONOSEC + 482 nfsrv_lease + NFSRV_LEASEDELTA; 483 LIST_NEWHEAD(&clp->lc_olddeleg, &clp->lc_deleg, 484 ls_list); 485 } 486 } 487 clp->lc_flags &= ~(LCL_NEEDSCONFIRM | LCL_DONTCLEAN); 488 if (clp->lc_program) 489 clp->lc_flags |= LCL_NEEDSCBNULL; 490 } 491 } else if (clp->lc_flags & LCL_NEEDSCONFIRM) { 492 error = NFSERR_EXPIRED; 493 } 494 495 /* 496 * If called by the Renew Op, we must check the principal. 497 */ 498 if (!error && (opflags & CLOPS_RENEWOP)) { 499 if (nfsrv_notsamecredname(nd, clp)) { 500 doneok = 0; 501 for (i = 0; i < NFSSTATEHASHSIZE && doneok == 0; i++) { 502 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 503 if ((stp->ls_flags & NFSLCK_OPEN) && 504 stp->ls_uid == nd->nd_cred->cr_uid) { 505 doneok = 1; 506 break; 507 } 508 } 509 } 510 if (!doneok) 511 error = NFSERR_ACCES; 512 } 513 if (!error && (clp->lc_flags & LCL_CBDOWN)) 514 error = NFSERR_CBPATHDOWN; 515 } 516 if ((!error || error == NFSERR_CBPATHDOWN) && 517 (opflags & CLOPS_RENEW)) { 518 clp->lc_expiry = nfsrv_leaseexpiry(); 519 } 520 if (opflags & CLOPS_CONFIRM) { 521 NFSLOCKV4ROOTMUTEX(); 522 nfsv4_unlock(&nfsv4rootfs_lock, 1); 523 NFSUNLOCKV4ROOTMUTEX(); 524 } else if (opflags != CLOPS_RENEW) { 525 NFSUNLOCKSTATE(); 526 } 527 if (clpp) 528 *clpp = clp;
| 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; 470 else if (nfsrv_notsamecredname(nd, clp)) 471 error = NFSERR_CLIDINUSE; 472 473 if (!error) { 474 if ((clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_DONTCLEAN)) == 475 LCL_NEEDSCONFIRM) { 476 /* 477 * Hang onto the delegations (as old delegations) 478 * for an Open with CLAIM_DELEGATE_PREV unless in 479 * grace, but get rid of the rest of the state. 480 */ 481 nfsrv_cleanclient(clp, p); 482 nfsrv_freedeleglist(&clp->lc_olddeleg); 483 if (nfsrv_checkgrace(0)) { 484 /* In grace, so just delete delegations */ 485 nfsrv_freedeleglist(&clp->lc_deleg); 486 } else { 487 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) 488 stp->ls_flags |= NFSLCK_OLDDELEG; 489 clp->lc_delegtime = NFSD_MONOSEC + 490 nfsrv_lease + NFSRV_LEASEDELTA; 491 LIST_NEWHEAD(&clp->lc_olddeleg, &clp->lc_deleg, 492 ls_list); 493 } 494 } 495 clp->lc_flags &= ~(LCL_NEEDSCONFIRM | LCL_DONTCLEAN); 496 if (clp->lc_program) 497 clp->lc_flags |= LCL_NEEDSCBNULL; 498 } 499 } else if (clp->lc_flags & LCL_NEEDSCONFIRM) { 500 error = NFSERR_EXPIRED; 501 } 502 503 /* 504 * If called by the Renew Op, we must check the principal. 505 */ 506 if (!error && (opflags & CLOPS_RENEWOP)) { 507 if (nfsrv_notsamecredname(nd, clp)) { 508 doneok = 0; 509 for (i = 0; i < NFSSTATEHASHSIZE && doneok == 0; i++) { 510 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 511 if ((stp->ls_flags & NFSLCK_OPEN) && 512 stp->ls_uid == nd->nd_cred->cr_uid) { 513 doneok = 1; 514 break; 515 } 516 } 517 } 518 if (!doneok) 519 error = NFSERR_ACCES; 520 } 521 if (!error && (clp->lc_flags & LCL_CBDOWN)) 522 error = NFSERR_CBPATHDOWN; 523 } 524 if ((!error || error == NFSERR_CBPATHDOWN) && 525 (opflags & CLOPS_RENEW)) { 526 clp->lc_expiry = nfsrv_leaseexpiry(); 527 } 528 if (opflags & CLOPS_CONFIRM) { 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);
|
529 return (error); 530} 531 532/* 533 * Called from the new nfssvc syscall to admin revoke a clientid. 534 * Returns 0 for success, error otherwise. 535 */ 536APPLESTATIC int 537nfsrv_adminrevoke(struct nfsd_clid *revokep, NFSPROC_T *p) 538{ 539 struct nfsclient *clp = NULL;
| 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;
|
540 int i;
| 551 int i, error = 0;
|
541 int gotit, igotlock; 542 543 /* 544 * First, lock out the nfsd so that state won't change while the 545 * revocation record is being written to the stable storage restart 546 * file. 547 */ 548 NFSLOCKV4ROOTMUTEX(); 549 do { 550 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 551 NFSV4ROOTLOCKMUTEXPTR, NULL); 552 } while (!igotlock); 553 NFSUNLOCKV4ROOTMUTEX(); 554 555 /* 556 * Search for a match in the client list. 557 */ 558 gotit = i = 0; 559 while (i < NFSCLIENTHASHSIZE && !gotit) { 560 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 561 if (revokep->nclid_idlen == clp->lc_idlen && 562 !NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) { 563 gotit = 1; 564 break; 565 } 566 } 567 i++; 568 } 569 if (!gotit) { 570 NFSLOCKV4ROOTMUTEX(); 571 nfsv4_unlock(&nfsv4rootfs_lock, 0); 572 NFSUNLOCKV4ROOTMUTEX();
| 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(); 560 do { 561 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 562 NFSV4ROOTLOCKMUTEXPTR, NULL); 563 } while (!igotlock); 564 NFSUNLOCKV4ROOTMUTEX(); 565 566 /* 567 * Search for a match in the client list. 568 */ 569 gotit = i = 0; 570 while (i < NFSCLIENTHASHSIZE && !gotit) { 571 LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) { 572 if (revokep->nclid_idlen == clp->lc_idlen && 573 !NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) { 574 gotit = 1; 575 break; 576 } 577 } 578 i++; 579 } 580 if (!gotit) { 581 NFSLOCKV4ROOTMUTEX(); 582 nfsv4_unlock(&nfsv4rootfs_lock, 0); 583 NFSUNLOCKV4ROOTMUTEX();
|
573 return (EPERM);
| 584 error = EPERM; 585 goto out;
|
574 } 575 576 /* 577 * Now, write out the revocation record 578 */ 579 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 580 nfsrv_backupstable(); 581 582 /* 583 * and clear out the state, marking the clientid revoked. 584 */ 585 clp->lc_flags &= ~LCL_CALLBACKSON; 586 clp->lc_flags |= LCL_ADMINREVOKED; 587 nfsrv_cleanclient(clp, p); 588 nfsrv_freedeleglist(&clp->lc_deleg); 589 nfsrv_freedeleglist(&clp->lc_olddeleg); 590 NFSLOCKV4ROOTMUTEX(); 591 nfsv4_unlock(&nfsv4rootfs_lock, 0); 592 NFSUNLOCKV4ROOTMUTEX();
| 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();
|
593 return (0);
| 605 606out: 607 NFSEXITCODE(error); 608 return (error);
|
594} 595 596/* 597 * Dump out stats for all clients. Called from nfssvc(2), that is used 598 * newnfsstats. 599 */ 600APPLESTATIC void 601nfsrv_dumpclients(struct nfsd_dumpclients *dumpp, int maxcnt) 602{ 603 struct nfsclient *clp; 604 int i = 0, cnt = 0; 605 606 /* 607 * First, get a reference on the nfsv4rootfs_lock so that an 608 * exclusive lock cannot be acquired while dumping the clients. 609 */ 610 NFSLOCKV4ROOTMUTEX(); 611 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 612 NFSUNLOCKV4ROOTMUTEX(); 613 NFSLOCKSTATE(); 614 /* 615 * Rattle through the client lists until done. 616 */ 617 while (i < NFSCLIENTHASHSIZE && cnt < maxcnt) { 618 clp = LIST_FIRST(&nfsclienthash[i]); 619 while (clp != LIST_END(&nfsclienthash[i]) && cnt < maxcnt) { 620 nfsrv_dumpaclient(clp, &dumpp[cnt]); 621 cnt++; 622 clp = LIST_NEXT(clp, lc_hash); 623 } 624 i++; 625 } 626 if (cnt < maxcnt) 627 dumpp[cnt].ndcl_clid.nclid_idlen = 0; 628 NFSUNLOCKSTATE(); 629 NFSLOCKV4ROOTMUTEX(); 630 nfsv4_relref(&nfsv4rootfs_lock); 631 NFSUNLOCKV4ROOTMUTEX(); 632} 633 634/* 635 * Dump stats for a client. Must be called with the NFSSTATELOCK and spl'd. 636 */ 637static void 638nfsrv_dumpaclient(struct nfsclient *clp, struct nfsd_dumpclients *dumpp) 639{ 640 struct nfsstate *stp, *openstp, *lckownstp; 641 struct nfslock *lop; 642 struct sockaddr *sad; 643 struct sockaddr_in *rad; 644 struct sockaddr_in6 *rad6; 645 646 dumpp->ndcl_nopenowners = dumpp->ndcl_nlockowners = 0; 647 dumpp->ndcl_nopens = dumpp->ndcl_nlocks = 0; 648 dumpp->ndcl_ndelegs = dumpp->ndcl_nolddelegs = 0; 649 dumpp->ndcl_flags = clp->lc_flags; 650 dumpp->ndcl_clid.nclid_idlen = clp->lc_idlen; 651 NFSBCOPY(clp->lc_id, dumpp->ndcl_clid.nclid_id, clp->lc_idlen); 652 sad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr *); 653 dumpp->ndcl_addrfam = sad->sa_family; 654 if (sad->sa_family == AF_INET) { 655 rad = (struct sockaddr_in *)sad; 656 dumpp->ndcl_cbaddr.sin_addr = rad->sin_addr; 657 } else { 658 rad6 = (struct sockaddr_in6 *)sad; 659 dumpp->ndcl_cbaddr.sin6_addr = rad6->sin6_addr; 660 } 661 662 /* 663 * Now, scan the state lists and total up the opens and locks. 664 */ 665 LIST_FOREACH(stp, &clp->lc_open, ls_list) { 666 dumpp->ndcl_nopenowners++; 667 LIST_FOREACH(openstp, &stp->ls_open, ls_list) { 668 dumpp->ndcl_nopens++; 669 LIST_FOREACH(lckownstp, &openstp->ls_open, ls_list) { 670 dumpp->ndcl_nlockowners++; 671 LIST_FOREACH(lop, &lckownstp->ls_lock, lo_lckowner) { 672 dumpp->ndcl_nlocks++; 673 } 674 } 675 } 676 } 677 678 /* 679 * and the delegation lists. 680 */ 681 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) { 682 dumpp->ndcl_ndelegs++; 683 } 684 LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) { 685 dumpp->ndcl_nolddelegs++; 686 } 687} 688 689/* 690 * Dump out lock stats for a file. 691 */ 692APPLESTATIC void 693nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldumpp, int maxcnt, 694 NFSPROC_T *p) 695{ 696 struct nfsstate *stp; 697 struct nfslock *lop; 698 int cnt = 0; 699 struct nfslockfile *lfp; 700 struct sockaddr *sad; 701 struct sockaddr_in *rad; 702 struct sockaddr_in6 *rad6; 703 int ret; 704 fhandle_t nfh; 705 706 ret = nfsrv_getlockfh(vp, 0, NULL, &nfh, p); 707 /* 708 * First, get a reference on the nfsv4rootfs_lock so that an 709 * exclusive lock on it cannot be acquired while dumping the locks. 710 */ 711 NFSLOCKV4ROOTMUTEX(); 712 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 713 NFSUNLOCKV4ROOTMUTEX(); 714 NFSLOCKSTATE(); 715 if (!ret) 716 ret = nfsrv_getlockfile(0, NULL, &lfp, &nfh, 0); 717 if (ret) { 718 ldumpp[0].ndlck_clid.nclid_idlen = 0; 719 NFSUNLOCKSTATE(); 720 NFSLOCKV4ROOTMUTEX(); 721 nfsv4_relref(&nfsv4rootfs_lock); 722 NFSUNLOCKV4ROOTMUTEX(); 723 return; 724 } 725 726 /* 727 * For each open share on file, dump it out. 728 */ 729 stp = LIST_FIRST(&lfp->lf_open); 730 while (stp != LIST_END(&lfp->lf_open) && cnt < maxcnt) { 731 ldumpp[cnt].ndlck_flags = stp->ls_flags; 732 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 733 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 734 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 735 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 736 ldumpp[cnt].ndlck_owner.nclid_idlen = 737 stp->ls_openowner->ls_ownerlen; 738 NFSBCOPY(stp->ls_openowner->ls_owner, 739 ldumpp[cnt].ndlck_owner.nclid_id, 740 stp->ls_openowner->ls_ownerlen); 741 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 742 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 743 stp->ls_clp->lc_idlen); 744 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 745 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 746 if (sad->sa_family == AF_INET) { 747 rad = (struct sockaddr_in *)sad; 748 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 749 } else { 750 rad6 = (struct sockaddr_in6 *)sad; 751 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 752 } 753 stp = LIST_NEXT(stp, ls_file); 754 cnt++; 755 } 756 757 /* 758 * and all locks. 759 */ 760 lop = LIST_FIRST(&lfp->lf_lock); 761 while (lop != LIST_END(&lfp->lf_lock) && cnt < maxcnt) { 762 stp = lop->lo_stp; 763 ldumpp[cnt].ndlck_flags = lop->lo_flags; 764 ldumpp[cnt].ndlck_first = lop->lo_first; 765 ldumpp[cnt].ndlck_end = lop->lo_end; 766 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 767 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 768 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 769 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 770 ldumpp[cnt].ndlck_owner.nclid_idlen = stp->ls_ownerlen; 771 NFSBCOPY(stp->ls_owner, ldumpp[cnt].ndlck_owner.nclid_id, 772 stp->ls_ownerlen); 773 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 774 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 775 stp->ls_clp->lc_idlen); 776 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 777 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 778 if (sad->sa_family == AF_INET) { 779 rad = (struct sockaddr_in *)sad; 780 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 781 } else { 782 rad6 = (struct sockaddr_in6 *)sad; 783 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 784 } 785 lop = LIST_NEXT(lop, lo_lckfile); 786 cnt++; 787 } 788 789 /* 790 * and the delegations. 791 */ 792 stp = LIST_FIRST(&lfp->lf_deleg); 793 while (stp != LIST_END(&lfp->lf_deleg) && cnt < maxcnt) { 794 ldumpp[cnt].ndlck_flags = stp->ls_flags; 795 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 796 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 797 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 798 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 799 ldumpp[cnt].ndlck_owner.nclid_idlen = 0; 800 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 801 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 802 stp->ls_clp->lc_idlen); 803 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 804 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 805 if (sad->sa_family == AF_INET) { 806 rad = (struct sockaddr_in *)sad; 807 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 808 } else { 809 rad6 = (struct sockaddr_in6 *)sad; 810 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 811 } 812 stp = LIST_NEXT(stp, ls_file); 813 cnt++; 814 } 815 816 /* 817 * If list isn't full, mark end of list by setting the client name 818 * to zero length. 819 */ 820 if (cnt < maxcnt) 821 ldumpp[cnt].ndlck_clid.nclid_idlen = 0; 822 NFSUNLOCKSTATE(); 823 NFSLOCKV4ROOTMUTEX(); 824 nfsv4_relref(&nfsv4rootfs_lock); 825 NFSUNLOCKV4ROOTMUTEX(); 826} 827 828/* 829 * Server timer routine. It can scan any linked list, so long 830 * as it holds the spin/mutex lock and there is no exclusive lock on 831 * nfsv4rootfs_lock. 832 * (For OpenBSD, a kthread is ok. For FreeBSD, I think it is ok 833 * to do this from a callout, since the spin locks work. For 834 * Darwin, I'm not sure what will work correctly yet.) 835 * Should be called once per second. 836 */ 837APPLESTATIC void 838nfsrv_servertimer(void) 839{ 840 struct nfsclient *clp, *nclp; 841 struct nfsstate *stp, *nstp; 842 int got_ref, i; 843 844 /* 845 * Make sure nfsboottime is set. This is used by V3 as well 846 * as V4. Note that nfsboottime is not nfsrvboottime, which is 847 * only used by the V4 server for leases. 848 */ 849 if (nfsboottime.tv_sec == 0) 850 NFSSETBOOTTIME(nfsboottime); 851 852 /* 853 * If server hasn't started yet, just return. 854 */ 855 NFSLOCKSTATE(); 856 if (nfsrv_stablefirst.nsf_eograce == 0) { 857 NFSUNLOCKSTATE(); 858 return; 859 } 860 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) { 861 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) && 862 NFSD_MONOSEC > nfsrv_stablefirst.nsf_eograce) 863 nfsrv_stablefirst.nsf_flags |= 864 (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK); 865 NFSUNLOCKSTATE(); 866 return; 867 } 868 869 /* 870 * Try and get a reference count on the nfsv4rootfs_lock so that 871 * no nfsd thread can acquire an exclusive lock on it before this 872 * call is done. If it is already exclusively locked, just return. 873 */ 874 NFSLOCKV4ROOTMUTEX(); 875 got_ref = nfsv4_getref_nonblock(&nfsv4rootfs_lock); 876 NFSUNLOCKV4ROOTMUTEX(); 877 if (got_ref == 0) { 878 NFSUNLOCKSTATE(); 879 return; 880 } 881 882 /* 883 * For each client... 884 */ 885 for (i = 0; i < NFSCLIENTHASHSIZE; i++) { 886 clp = LIST_FIRST(&nfsclienthash[i]); 887 while (clp != LIST_END(&nfsclienthash[i])) { 888 nclp = LIST_NEXT(clp, lc_hash); 889 if (!(clp->lc_flags & LCL_EXPIREIT)) { 890 if (((clp->lc_expiry + NFSRV_STALELEASE) < NFSD_MONOSEC 891 && ((LIST_EMPTY(&clp->lc_deleg) 892 && LIST_EMPTY(&clp->lc_open)) || 893 nfsrv_clients > nfsrv_clienthighwater)) || 894 (clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC || 895 (clp->lc_expiry < NFSD_MONOSEC && 896 (nfsrv_openpluslock * 10 / 9) > NFSRV_V4STATELIMIT)) { 897 /* 898 * Lease has expired several nfsrv_lease times ago: 899 * PLUS 900 * - no state is associated with it 901 * OR 902 * - above high water mark for number of clients 903 * (nfsrv_clienthighwater should be large enough 904 * that this only occurs when clients fail to 905 * use the same nfs_client_id4.id. Maybe somewhat 906 * higher that the maximum number of clients that 907 * will mount this server?) 908 * OR 909 * Lease has expired a very long time ago 910 * OR 911 * Lease has expired PLUS the number of opens + locks 912 * has exceeded 90% of capacity 913 * 914 * --> Mark for expiry. The actual expiry will be done 915 * by an nfsd sometime soon. 916 */ 917 clp->lc_flags |= LCL_EXPIREIT; 918 nfsrv_stablefirst.nsf_flags |= 919 (NFSNSF_NEEDLOCK | NFSNSF_EXPIREDCLIENT); 920 } else { 921 /* 922 * If there are no opens, increment no open tick cnt 923 * If time exceeds NFSNOOPEN, mark it to be thrown away 924 * otherwise, if there is an open, reset no open time 925 * Hopefully, this will avoid excessive re-creation 926 * of open owners and subsequent open confirms. 927 */ 928 stp = LIST_FIRST(&clp->lc_open); 929 while (stp != LIST_END(&clp->lc_open)) { 930 nstp = LIST_NEXT(stp, ls_list); 931 if (LIST_EMPTY(&stp->ls_open)) { 932 stp->ls_noopens++; 933 if (stp->ls_noopens > NFSNOOPEN || 934 (nfsrv_openpluslock * 2) > 935 NFSRV_V4STATELIMIT) 936 nfsrv_stablefirst.nsf_flags |= 937 NFSNSF_NOOPENS; 938 } else { 939 stp->ls_noopens = 0; 940 } 941 stp = nstp; 942 } 943 } 944 } 945 clp = nclp; 946 } 947 } 948 NFSUNLOCKSTATE(); 949 NFSLOCKV4ROOTMUTEX(); 950 nfsv4_relref(&nfsv4rootfs_lock); 951 NFSUNLOCKV4ROOTMUTEX(); 952} 953 954/* 955 * The following set of functions free up the various data structures. 956 */ 957/* 958 * Clear out all open/lock state related to this nfsclient. 959 * Caller must hold an exclusive lock on nfsv4rootfs_lock, so that 960 * there are no other active nfsd threads. 961 */ 962APPLESTATIC void 963nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p) 964{ 965 struct nfsstate *stp, *nstp; 966 967 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) 968 nfsrv_freeopenowner(stp, 1, p); 969} 970 971/* 972 * Free a client that has been cleaned. It should also already have been 973 * removed from the lists. 974 * (Just to be safe w.r.t. newnfs_disconnect(), call this function when 975 * softclock interrupts are enabled.) 976 */ 977APPLESTATIC void 978nfsrv_zapclient(struct nfsclient *clp, NFSPROC_T *p) 979{ 980 981#ifdef notyet 982 if ((clp->lc_flags & (LCL_GSS | LCL_CALLBACKSON)) == 983 (LCL_GSS | LCL_CALLBACKSON) && 984 (clp->lc_hand.nfsh_flag & NFSG_COMPLETE) && 985 clp->lc_handlelen > 0) { 986 clp->lc_hand.nfsh_flag &= ~NFSG_COMPLETE; 987 clp->lc_hand.nfsh_flag |= NFSG_DESTROYED; 988 (void) nfsrv_docallback(clp, NFSV4PROC_CBNULL, 989 NULL, 0, NULL, NULL, NULL, p); 990 } 991#endif 992 newnfs_disconnect(&clp->lc_req); 993 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 994 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 995 free((caddr_t)clp, M_NFSDCLIENT); 996 NFSLOCKSTATE(); 997 newnfsstats.srvclients--; 998 nfsrv_openpluslock--; 999 nfsrv_clients--; 1000 NFSUNLOCKSTATE(); 1001} 1002 1003/* 1004 * Free a list of delegation state structures. 1005 * (This function will also free all nfslockfile structures that no 1006 * longer have associated state.) 1007 */ 1008APPLESTATIC void 1009nfsrv_freedeleglist(struct nfsstatehead *sthp) 1010{ 1011 struct nfsstate *stp, *nstp; 1012 1013 LIST_FOREACH_SAFE(stp, sthp, ls_list, nstp) { 1014 nfsrv_freedeleg(stp); 1015 } 1016 LIST_INIT(sthp); 1017} 1018 1019/* 1020 * Free up a delegation. 1021 */ 1022static void 1023nfsrv_freedeleg(struct nfsstate *stp) 1024{ 1025 struct nfslockfile *lfp; 1026 1027 LIST_REMOVE(stp, ls_hash); 1028 LIST_REMOVE(stp, ls_list); 1029 LIST_REMOVE(stp, ls_file); 1030 lfp = stp->ls_lfp; 1031 if (LIST_EMPTY(&lfp->lf_open) && 1032 LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_deleg) && 1033 LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && 1034 lfp->lf_usecount == 0 && 1035 nfsv4_testlock(&lfp->lf_locallock_lck) == 0) 1036 nfsrv_freenfslockfile(lfp); 1037 FREE((caddr_t)stp, M_NFSDSTATE); 1038 newnfsstats.srvdelegates--; 1039 nfsrv_openpluslock--; 1040 nfsrv_delegatecnt--; 1041} 1042 1043/* 1044 * This function frees an open owner and all associated opens. 1045 */ 1046static void 1047nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, NFSPROC_T *p) 1048{ 1049 struct nfsstate *nstp, *tstp; 1050 1051 LIST_REMOVE(stp, ls_list); 1052 /* 1053 * Now, free all associated opens. 1054 */ 1055 nstp = LIST_FIRST(&stp->ls_open); 1056 while (nstp != LIST_END(&stp->ls_open)) { 1057 tstp = nstp; 1058 nstp = LIST_NEXT(nstp, ls_list); 1059 (void) nfsrv_freeopen(tstp, NULL, cansleep, p); 1060 } 1061 if (stp->ls_op) 1062 nfsrvd_derefcache(stp->ls_op); 1063 FREE((caddr_t)stp, M_NFSDSTATE); 1064 newnfsstats.srvopenowners--; 1065 nfsrv_openpluslock--; 1066} 1067 1068/* 1069 * This function frees an open (nfsstate open structure) with all associated 1070 * lock_owners and locks. It also frees the nfslockfile structure iff there 1071 * are no other opens on the file. 1072 * Returns 1 if it free'd the nfslockfile, 0 otherwise. 1073 */ 1074static int 1075nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p) 1076{ 1077 struct nfsstate *nstp, *tstp; 1078 struct nfslockfile *lfp; 1079 int ret; 1080 1081 LIST_REMOVE(stp, ls_hash); 1082 LIST_REMOVE(stp, ls_list); 1083 LIST_REMOVE(stp, ls_file); 1084 1085 lfp = stp->ls_lfp; 1086 /* 1087 * Now, free all lockowners associated with this open. 1088 */ 1089 LIST_FOREACH_SAFE(tstp, &stp->ls_open, ls_list, nstp) 1090 nfsrv_freelockowner(tstp, vp, cansleep, p); 1091 1092 /* 1093 * The nfslockfile is freed here if there are no locks 1094 * associated with the open. 1095 * If there are locks associated with the open, the 1096 * nfslockfile structure can be freed via nfsrv_freelockowner(). 1097 * Acquire the state mutex to avoid races with calls to 1098 * nfsrv_getlockfile(). 1099 */ 1100 if (cansleep != 0) 1101 NFSLOCKSTATE(); 1102 if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) && 1103 LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) && 1104 LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && 1105 lfp->lf_usecount == 0 && 1106 (cansleep != 0 || nfsv4_testlock(&lfp->lf_locallock_lck) == 0)) { 1107 nfsrv_freenfslockfile(lfp); 1108 ret = 1; 1109 } else 1110 ret = 0; 1111 if (cansleep != 0) 1112 NFSUNLOCKSTATE(); 1113 FREE((caddr_t)stp, M_NFSDSTATE); 1114 newnfsstats.srvopens--; 1115 nfsrv_openpluslock--; 1116 return (ret); 1117} 1118 1119/* 1120 * Frees a lockowner and all associated locks. 1121 */ 1122static void 1123nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep, 1124 NFSPROC_T *p) 1125{ 1126 1127 LIST_REMOVE(stp, ls_hash); 1128 LIST_REMOVE(stp, ls_list); 1129 nfsrv_freeallnfslocks(stp, vp, cansleep, p); 1130 if (stp->ls_op) 1131 nfsrvd_derefcache(stp->ls_op); 1132 FREE((caddr_t)stp, M_NFSDSTATE); 1133 newnfsstats.srvlockowners--; 1134 nfsrv_openpluslock--; 1135} 1136 1137/* 1138 * Free all the nfs locks on a lockowner. 1139 */ 1140static void 1141nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep, 1142 NFSPROC_T *p) 1143{ 1144 struct nfslock *lop, *nlop; 1145 struct nfsrollback *rlp, *nrlp; 1146 struct nfslockfile *lfp = NULL; 1147 int gottvp = 0; 1148 vnode_t tvp = NULL; 1149 uint64_t first, end; 1150 1151 lop = LIST_FIRST(&stp->ls_lock); 1152 while (lop != LIST_END(&stp->ls_lock)) { 1153 nlop = LIST_NEXT(lop, lo_lckowner); 1154 /* 1155 * Since all locks should be for the same file, lfp should 1156 * not change. 1157 */ 1158 if (lfp == NULL) 1159 lfp = lop->lo_lfp; 1160 else if (lfp != lop->lo_lfp) 1161 panic("allnfslocks"); 1162 /* 1163 * If vp is NULL and cansleep != 0, a vnode must be acquired 1164 * from the file handle. This only occurs when called from 1165 * nfsrv_cleanclient(). 1166 */ 1167 if (gottvp == 0) { 1168 if (nfsrv_dolocallocks == 0) 1169 tvp = NULL; 1170 else if (vp == NULL && cansleep != 0) 1171 tvp = nfsvno_getvp(&lfp->lf_fh); 1172 else 1173 tvp = vp; 1174 gottvp = 1; 1175 } 1176 1177 if (tvp != NULL) { 1178 if (cansleep == 0) 1179 panic("allnfs2"); 1180 first = lop->lo_first; 1181 end = lop->lo_end; 1182 nfsrv_freenfslock(lop); 1183 nfsrv_localunlock(tvp, lfp, first, end, p); 1184 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, 1185 nrlp) 1186 free(rlp, M_NFSDROLLBACK); 1187 LIST_INIT(&lfp->lf_rollback); 1188 } else 1189 nfsrv_freenfslock(lop); 1190 lop = nlop; 1191 } 1192 if (vp == NULL && tvp != NULL) 1193 vput(tvp); 1194} 1195 1196/* 1197 * Free an nfslock structure. 1198 */ 1199static void 1200nfsrv_freenfslock(struct nfslock *lop) 1201{ 1202 1203 if (lop->lo_lckfile.le_prev != NULL) { 1204 LIST_REMOVE(lop, lo_lckfile); 1205 newnfsstats.srvlocks--; 1206 nfsrv_openpluslock--; 1207 } 1208 LIST_REMOVE(lop, lo_lckowner); 1209 FREE((caddr_t)lop, M_NFSDLOCK); 1210} 1211 1212/* 1213 * This function frees an nfslockfile structure. 1214 */ 1215static void 1216nfsrv_freenfslockfile(struct nfslockfile *lfp) 1217{ 1218 1219 LIST_REMOVE(lfp, lf_hash); 1220 FREE((caddr_t)lfp, M_NFSDLOCKFILE); 1221} 1222 1223/* 1224 * This function looks up an nfsstate structure via stateid. 1225 */ 1226static int 1227nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, __unused u_int32_t flags, 1228 struct nfsstate **stpp) 1229{ 1230 struct nfsstate *stp; 1231 struct nfsstatehead *hp;
| 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) 617{ 618 struct nfsclient *clp; 619 int i = 0, cnt = 0; 620 621 /* 622 * First, get a reference on the nfsv4rootfs_lock so that an 623 * exclusive lock cannot be acquired while dumping the clients. 624 */ 625 NFSLOCKV4ROOTMUTEX(); 626 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 627 NFSUNLOCKV4ROOTMUTEX(); 628 NFSLOCKSTATE(); 629 /* 630 * Rattle through the client lists until done. 631 */ 632 while (i < NFSCLIENTHASHSIZE && cnt < maxcnt) { 633 clp = LIST_FIRST(&nfsclienthash[i]); 634 while (clp != LIST_END(&nfsclienthash[i]) && cnt < maxcnt) { 635 nfsrv_dumpaclient(clp, &dumpp[cnt]); 636 cnt++; 637 clp = LIST_NEXT(clp, lc_hash); 638 } 639 i++; 640 } 641 if (cnt < maxcnt) 642 dumpp[cnt].ndcl_clid.nclid_idlen = 0; 643 NFSUNLOCKSTATE(); 644 NFSLOCKV4ROOTMUTEX(); 645 nfsv4_relref(&nfsv4rootfs_lock); 646 NFSUNLOCKV4ROOTMUTEX(); 647} 648 649/* 650 * Dump stats for a client. Must be called with the NFSSTATELOCK and spl'd. 651 */ 652static void 653nfsrv_dumpaclient(struct nfsclient *clp, struct nfsd_dumpclients *dumpp) 654{ 655 struct nfsstate *stp, *openstp, *lckownstp; 656 struct nfslock *lop; 657 struct sockaddr *sad; 658 struct sockaddr_in *rad; 659 struct sockaddr_in6 *rad6; 660 661 dumpp->ndcl_nopenowners = dumpp->ndcl_nlockowners = 0; 662 dumpp->ndcl_nopens = dumpp->ndcl_nlocks = 0; 663 dumpp->ndcl_ndelegs = dumpp->ndcl_nolddelegs = 0; 664 dumpp->ndcl_flags = clp->lc_flags; 665 dumpp->ndcl_clid.nclid_idlen = clp->lc_idlen; 666 NFSBCOPY(clp->lc_id, dumpp->ndcl_clid.nclid_id, clp->lc_idlen); 667 sad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr *); 668 dumpp->ndcl_addrfam = sad->sa_family; 669 if (sad->sa_family == AF_INET) { 670 rad = (struct sockaddr_in *)sad; 671 dumpp->ndcl_cbaddr.sin_addr = rad->sin_addr; 672 } else { 673 rad6 = (struct sockaddr_in6 *)sad; 674 dumpp->ndcl_cbaddr.sin6_addr = rad6->sin6_addr; 675 } 676 677 /* 678 * Now, scan the state lists and total up the opens and locks. 679 */ 680 LIST_FOREACH(stp, &clp->lc_open, ls_list) { 681 dumpp->ndcl_nopenowners++; 682 LIST_FOREACH(openstp, &stp->ls_open, ls_list) { 683 dumpp->ndcl_nopens++; 684 LIST_FOREACH(lckownstp, &openstp->ls_open, ls_list) { 685 dumpp->ndcl_nlockowners++; 686 LIST_FOREACH(lop, &lckownstp->ls_lock, lo_lckowner) { 687 dumpp->ndcl_nlocks++; 688 } 689 } 690 } 691 } 692 693 /* 694 * and the delegation lists. 695 */ 696 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) { 697 dumpp->ndcl_ndelegs++; 698 } 699 LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) { 700 dumpp->ndcl_nolddelegs++; 701 } 702} 703 704/* 705 * Dump out lock stats for a file. 706 */ 707APPLESTATIC void 708nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldumpp, int maxcnt, 709 NFSPROC_T *p) 710{ 711 struct nfsstate *stp; 712 struct nfslock *lop; 713 int cnt = 0; 714 struct nfslockfile *lfp; 715 struct sockaddr *sad; 716 struct sockaddr_in *rad; 717 struct sockaddr_in6 *rad6; 718 int ret; 719 fhandle_t nfh; 720 721 ret = nfsrv_getlockfh(vp, 0, NULL, &nfh, p); 722 /* 723 * First, get a reference on the nfsv4rootfs_lock so that an 724 * exclusive lock on it cannot be acquired while dumping the locks. 725 */ 726 NFSLOCKV4ROOTMUTEX(); 727 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 728 NFSUNLOCKV4ROOTMUTEX(); 729 NFSLOCKSTATE(); 730 if (!ret) 731 ret = nfsrv_getlockfile(0, NULL, &lfp, &nfh, 0); 732 if (ret) { 733 ldumpp[0].ndlck_clid.nclid_idlen = 0; 734 NFSUNLOCKSTATE(); 735 NFSLOCKV4ROOTMUTEX(); 736 nfsv4_relref(&nfsv4rootfs_lock); 737 NFSUNLOCKV4ROOTMUTEX(); 738 return; 739 } 740 741 /* 742 * For each open share on file, dump it out. 743 */ 744 stp = LIST_FIRST(&lfp->lf_open); 745 while (stp != LIST_END(&lfp->lf_open) && cnt < maxcnt) { 746 ldumpp[cnt].ndlck_flags = stp->ls_flags; 747 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 748 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 749 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 750 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 751 ldumpp[cnt].ndlck_owner.nclid_idlen = 752 stp->ls_openowner->ls_ownerlen; 753 NFSBCOPY(stp->ls_openowner->ls_owner, 754 ldumpp[cnt].ndlck_owner.nclid_id, 755 stp->ls_openowner->ls_ownerlen); 756 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 757 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 758 stp->ls_clp->lc_idlen); 759 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 760 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 761 if (sad->sa_family == AF_INET) { 762 rad = (struct sockaddr_in *)sad; 763 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 764 } else { 765 rad6 = (struct sockaddr_in6 *)sad; 766 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 767 } 768 stp = LIST_NEXT(stp, ls_file); 769 cnt++; 770 } 771 772 /* 773 * and all locks. 774 */ 775 lop = LIST_FIRST(&lfp->lf_lock); 776 while (lop != LIST_END(&lfp->lf_lock) && cnt < maxcnt) { 777 stp = lop->lo_stp; 778 ldumpp[cnt].ndlck_flags = lop->lo_flags; 779 ldumpp[cnt].ndlck_first = lop->lo_first; 780 ldumpp[cnt].ndlck_end = lop->lo_end; 781 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 782 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 783 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 784 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 785 ldumpp[cnt].ndlck_owner.nclid_idlen = stp->ls_ownerlen; 786 NFSBCOPY(stp->ls_owner, ldumpp[cnt].ndlck_owner.nclid_id, 787 stp->ls_ownerlen); 788 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 789 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 790 stp->ls_clp->lc_idlen); 791 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 792 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 793 if (sad->sa_family == AF_INET) { 794 rad = (struct sockaddr_in *)sad; 795 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 796 } else { 797 rad6 = (struct sockaddr_in6 *)sad; 798 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 799 } 800 lop = LIST_NEXT(lop, lo_lckfile); 801 cnt++; 802 } 803 804 /* 805 * and the delegations. 806 */ 807 stp = LIST_FIRST(&lfp->lf_deleg); 808 while (stp != LIST_END(&lfp->lf_deleg) && cnt < maxcnt) { 809 ldumpp[cnt].ndlck_flags = stp->ls_flags; 810 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid; 811 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0]; 812 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1]; 813 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2]; 814 ldumpp[cnt].ndlck_owner.nclid_idlen = 0; 815 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen; 816 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id, 817 stp->ls_clp->lc_idlen); 818 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *); 819 ldumpp[cnt].ndlck_addrfam = sad->sa_family; 820 if (sad->sa_family == AF_INET) { 821 rad = (struct sockaddr_in *)sad; 822 ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr; 823 } else { 824 rad6 = (struct sockaddr_in6 *)sad; 825 ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr; 826 } 827 stp = LIST_NEXT(stp, ls_file); 828 cnt++; 829 } 830 831 /* 832 * If list isn't full, mark end of list by setting the client name 833 * to zero length. 834 */ 835 if (cnt < maxcnt) 836 ldumpp[cnt].ndlck_clid.nclid_idlen = 0; 837 NFSUNLOCKSTATE(); 838 NFSLOCKV4ROOTMUTEX(); 839 nfsv4_relref(&nfsv4rootfs_lock); 840 NFSUNLOCKV4ROOTMUTEX(); 841} 842 843/* 844 * Server timer routine. It can scan any linked list, so long 845 * as it holds the spin/mutex lock and there is no exclusive lock on 846 * nfsv4rootfs_lock. 847 * (For OpenBSD, a kthread is ok. For FreeBSD, I think it is ok 848 * to do this from a callout, since the spin locks work. For 849 * Darwin, I'm not sure what will work correctly yet.) 850 * Should be called once per second. 851 */ 852APPLESTATIC void 853nfsrv_servertimer(void) 854{ 855 struct nfsclient *clp, *nclp; 856 struct nfsstate *stp, *nstp; 857 int got_ref, i; 858 859 /* 860 * Make sure nfsboottime is set. This is used by V3 as well 861 * as V4. Note that nfsboottime is not nfsrvboottime, which is 862 * only used by the V4 server for leases. 863 */ 864 if (nfsboottime.tv_sec == 0) 865 NFSSETBOOTTIME(nfsboottime); 866 867 /* 868 * If server hasn't started yet, just return. 869 */ 870 NFSLOCKSTATE(); 871 if (nfsrv_stablefirst.nsf_eograce == 0) { 872 NFSUNLOCKSTATE(); 873 return; 874 } 875 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) { 876 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) && 877 NFSD_MONOSEC > nfsrv_stablefirst.nsf_eograce) 878 nfsrv_stablefirst.nsf_flags |= 879 (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK); 880 NFSUNLOCKSTATE(); 881 return; 882 } 883 884 /* 885 * Try and get a reference count on the nfsv4rootfs_lock so that 886 * no nfsd thread can acquire an exclusive lock on it before this 887 * call is done. If it is already exclusively locked, just return. 888 */ 889 NFSLOCKV4ROOTMUTEX(); 890 got_ref = nfsv4_getref_nonblock(&nfsv4rootfs_lock); 891 NFSUNLOCKV4ROOTMUTEX(); 892 if (got_ref == 0) { 893 NFSUNLOCKSTATE(); 894 return; 895 } 896 897 /* 898 * For each client... 899 */ 900 for (i = 0; i < NFSCLIENTHASHSIZE; i++) { 901 clp = LIST_FIRST(&nfsclienthash[i]); 902 while (clp != LIST_END(&nfsclienthash[i])) { 903 nclp = LIST_NEXT(clp, lc_hash); 904 if (!(clp->lc_flags & LCL_EXPIREIT)) { 905 if (((clp->lc_expiry + NFSRV_STALELEASE) < NFSD_MONOSEC 906 && ((LIST_EMPTY(&clp->lc_deleg) 907 && LIST_EMPTY(&clp->lc_open)) || 908 nfsrv_clients > nfsrv_clienthighwater)) || 909 (clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC || 910 (clp->lc_expiry < NFSD_MONOSEC && 911 (nfsrv_openpluslock * 10 / 9) > NFSRV_V4STATELIMIT)) { 912 /* 913 * Lease has expired several nfsrv_lease times ago: 914 * PLUS 915 * - no state is associated with it 916 * OR 917 * - above high water mark for number of clients 918 * (nfsrv_clienthighwater should be large enough 919 * that this only occurs when clients fail to 920 * use the same nfs_client_id4.id. Maybe somewhat 921 * higher that the maximum number of clients that 922 * will mount this server?) 923 * OR 924 * Lease has expired a very long time ago 925 * OR 926 * Lease has expired PLUS the number of opens + locks 927 * has exceeded 90% of capacity 928 * 929 * --> Mark for expiry. The actual expiry will be done 930 * by an nfsd sometime soon. 931 */ 932 clp->lc_flags |= LCL_EXPIREIT; 933 nfsrv_stablefirst.nsf_flags |= 934 (NFSNSF_NEEDLOCK | NFSNSF_EXPIREDCLIENT); 935 } else { 936 /* 937 * If there are no opens, increment no open tick cnt 938 * If time exceeds NFSNOOPEN, mark it to be thrown away 939 * otherwise, if there is an open, reset no open time 940 * Hopefully, this will avoid excessive re-creation 941 * of open owners and subsequent open confirms. 942 */ 943 stp = LIST_FIRST(&clp->lc_open); 944 while (stp != LIST_END(&clp->lc_open)) { 945 nstp = LIST_NEXT(stp, ls_list); 946 if (LIST_EMPTY(&stp->ls_open)) { 947 stp->ls_noopens++; 948 if (stp->ls_noopens > NFSNOOPEN || 949 (nfsrv_openpluslock * 2) > 950 NFSRV_V4STATELIMIT) 951 nfsrv_stablefirst.nsf_flags |= 952 NFSNSF_NOOPENS; 953 } else { 954 stp->ls_noopens = 0; 955 } 956 stp = nstp; 957 } 958 } 959 } 960 clp = nclp; 961 } 962 } 963 NFSUNLOCKSTATE(); 964 NFSLOCKV4ROOTMUTEX(); 965 nfsv4_relref(&nfsv4rootfs_lock); 966 NFSUNLOCKV4ROOTMUTEX(); 967} 968 969/* 970 * The following set of functions free up the various data structures. 971 */ 972/* 973 * Clear out all open/lock state related to this nfsclient. 974 * Caller must hold an exclusive lock on nfsv4rootfs_lock, so that 975 * there are no other active nfsd threads. 976 */ 977APPLESTATIC void 978nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p) 979{ 980 struct nfsstate *stp, *nstp; 981 982 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) 983 nfsrv_freeopenowner(stp, 1, p); 984} 985 986/* 987 * Free a client that has been cleaned. It should also already have been 988 * removed from the lists. 989 * (Just to be safe w.r.t. newnfs_disconnect(), call this function when 990 * softclock interrupts are enabled.) 991 */ 992APPLESTATIC void 993nfsrv_zapclient(struct nfsclient *clp, NFSPROC_T *p) 994{ 995 996#ifdef notyet 997 if ((clp->lc_flags & (LCL_GSS | LCL_CALLBACKSON)) == 998 (LCL_GSS | LCL_CALLBACKSON) && 999 (clp->lc_hand.nfsh_flag & NFSG_COMPLETE) && 1000 clp->lc_handlelen > 0) { 1001 clp->lc_hand.nfsh_flag &= ~NFSG_COMPLETE; 1002 clp->lc_hand.nfsh_flag |= NFSG_DESTROYED; 1003 (void) nfsrv_docallback(clp, NFSV4PROC_CBNULL, 1004 NULL, 0, NULL, NULL, NULL, p); 1005 } 1006#endif 1007 newnfs_disconnect(&clp->lc_req); 1008 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 1009 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 1010 free((caddr_t)clp, M_NFSDCLIENT); 1011 NFSLOCKSTATE(); 1012 newnfsstats.srvclients--; 1013 nfsrv_openpluslock--; 1014 nfsrv_clients--; 1015 NFSUNLOCKSTATE(); 1016} 1017 1018/* 1019 * Free a list of delegation state structures. 1020 * (This function will also free all nfslockfile structures that no 1021 * longer have associated state.) 1022 */ 1023APPLESTATIC void 1024nfsrv_freedeleglist(struct nfsstatehead *sthp) 1025{ 1026 struct nfsstate *stp, *nstp; 1027 1028 LIST_FOREACH_SAFE(stp, sthp, ls_list, nstp) { 1029 nfsrv_freedeleg(stp); 1030 } 1031 LIST_INIT(sthp); 1032} 1033 1034/* 1035 * Free up a delegation. 1036 */ 1037static void 1038nfsrv_freedeleg(struct nfsstate *stp) 1039{ 1040 struct nfslockfile *lfp; 1041 1042 LIST_REMOVE(stp, ls_hash); 1043 LIST_REMOVE(stp, ls_list); 1044 LIST_REMOVE(stp, ls_file); 1045 lfp = stp->ls_lfp; 1046 if (LIST_EMPTY(&lfp->lf_open) && 1047 LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_deleg) && 1048 LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && 1049 lfp->lf_usecount == 0 && 1050 nfsv4_testlock(&lfp->lf_locallock_lck) == 0) 1051 nfsrv_freenfslockfile(lfp); 1052 FREE((caddr_t)stp, M_NFSDSTATE); 1053 newnfsstats.srvdelegates--; 1054 nfsrv_openpluslock--; 1055 nfsrv_delegatecnt--; 1056} 1057 1058/* 1059 * This function frees an open owner and all associated opens. 1060 */ 1061static void 1062nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, NFSPROC_T *p) 1063{ 1064 struct nfsstate *nstp, *tstp; 1065 1066 LIST_REMOVE(stp, ls_list); 1067 /* 1068 * Now, free all associated opens. 1069 */ 1070 nstp = LIST_FIRST(&stp->ls_open); 1071 while (nstp != LIST_END(&stp->ls_open)) { 1072 tstp = nstp; 1073 nstp = LIST_NEXT(nstp, ls_list); 1074 (void) nfsrv_freeopen(tstp, NULL, cansleep, p); 1075 } 1076 if (stp->ls_op) 1077 nfsrvd_derefcache(stp->ls_op); 1078 FREE((caddr_t)stp, M_NFSDSTATE); 1079 newnfsstats.srvopenowners--; 1080 nfsrv_openpluslock--; 1081} 1082 1083/* 1084 * This function frees an open (nfsstate open structure) with all associated 1085 * lock_owners and locks. It also frees the nfslockfile structure iff there 1086 * are no other opens on the file. 1087 * Returns 1 if it free'd the nfslockfile, 0 otherwise. 1088 */ 1089static int 1090nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p) 1091{ 1092 struct nfsstate *nstp, *tstp; 1093 struct nfslockfile *lfp; 1094 int ret; 1095 1096 LIST_REMOVE(stp, ls_hash); 1097 LIST_REMOVE(stp, ls_list); 1098 LIST_REMOVE(stp, ls_file); 1099 1100 lfp = stp->ls_lfp; 1101 /* 1102 * Now, free all lockowners associated with this open. 1103 */ 1104 LIST_FOREACH_SAFE(tstp, &stp->ls_open, ls_list, nstp) 1105 nfsrv_freelockowner(tstp, vp, cansleep, p); 1106 1107 /* 1108 * The nfslockfile is freed here if there are no locks 1109 * associated with the open. 1110 * If there are locks associated with the open, the 1111 * nfslockfile structure can be freed via nfsrv_freelockowner(). 1112 * Acquire the state mutex to avoid races with calls to 1113 * nfsrv_getlockfile(). 1114 */ 1115 if (cansleep != 0) 1116 NFSLOCKSTATE(); 1117 if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) && 1118 LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) && 1119 LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && 1120 lfp->lf_usecount == 0 && 1121 (cansleep != 0 || nfsv4_testlock(&lfp->lf_locallock_lck) == 0)) { 1122 nfsrv_freenfslockfile(lfp); 1123 ret = 1; 1124 } else 1125 ret = 0; 1126 if (cansleep != 0) 1127 NFSUNLOCKSTATE(); 1128 FREE((caddr_t)stp, M_NFSDSTATE); 1129 newnfsstats.srvopens--; 1130 nfsrv_openpluslock--; 1131 return (ret); 1132} 1133 1134/* 1135 * Frees a lockowner and all associated locks. 1136 */ 1137static void 1138nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep, 1139 NFSPROC_T *p) 1140{ 1141 1142 LIST_REMOVE(stp, ls_hash); 1143 LIST_REMOVE(stp, ls_list); 1144 nfsrv_freeallnfslocks(stp, vp, cansleep, p); 1145 if (stp->ls_op) 1146 nfsrvd_derefcache(stp->ls_op); 1147 FREE((caddr_t)stp, M_NFSDSTATE); 1148 newnfsstats.srvlockowners--; 1149 nfsrv_openpluslock--; 1150} 1151 1152/* 1153 * Free all the nfs locks on a lockowner. 1154 */ 1155static void 1156nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep, 1157 NFSPROC_T *p) 1158{ 1159 struct nfslock *lop, *nlop; 1160 struct nfsrollback *rlp, *nrlp; 1161 struct nfslockfile *lfp = NULL; 1162 int gottvp = 0; 1163 vnode_t tvp = NULL; 1164 uint64_t first, end; 1165 1166 lop = LIST_FIRST(&stp->ls_lock); 1167 while (lop != LIST_END(&stp->ls_lock)) { 1168 nlop = LIST_NEXT(lop, lo_lckowner); 1169 /* 1170 * Since all locks should be for the same file, lfp should 1171 * not change. 1172 */ 1173 if (lfp == NULL) 1174 lfp = lop->lo_lfp; 1175 else if (lfp != lop->lo_lfp) 1176 panic("allnfslocks"); 1177 /* 1178 * If vp is NULL and cansleep != 0, a vnode must be acquired 1179 * from the file handle. This only occurs when called from 1180 * nfsrv_cleanclient(). 1181 */ 1182 if (gottvp == 0) { 1183 if (nfsrv_dolocallocks == 0) 1184 tvp = NULL; 1185 else if (vp == NULL && cansleep != 0) 1186 tvp = nfsvno_getvp(&lfp->lf_fh); 1187 else 1188 tvp = vp; 1189 gottvp = 1; 1190 } 1191 1192 if (tvp != NULL) { 1193 if (cansleep == 0) 1194 panic("allnfs2"); 1195 first = lop->lo_first; 1196 end = lop->lo_end; 1197 nfsrv_freenfslock(lop); 1198 nfsrv_localunlock(tvp, lfp, first, end, p); 1199 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, 1200 nrlp) 1201 free(rlp, M_NFSDROLLBACK); 1202 LIST_INIT(&lfp->lf_rollback); 1203 } else 1204 nfsrv_freenfslock(lop); 1205 lop = nlop; 1206 } 1207 if (vp == NULL && tvp != NULL) 1208 vput(tvp); 1209} 1210 1211/* 1212 * Free an nfslock structure. 1213 */ 1214static void 1215nfsrv_freenfslock(struct nfslock *lop) 1216{ 1217 1218 if (lop->lo_lckfile.le_prev != NULL) { 1219 LIST_REMOVE(lop, lo_lckfile); 1220 newnfsstats.srvlocks--; 1221 nfsrv_openpluslock--; 1222 } 1223 LIST_REMOVE(lop, lo_lckowner); 1224 FREE((caddr_t)lop, M_NFSDLOCK); 1225} 1226 1227/* 1228 * This function frees an nfslockfile structure. 1229 */ 1230static void 1231nfsrv_freenfslockfile(struct nfslockfile *lfp) 1232{ 1233 1234 LIST_REMOVE(lfp, lf_hash); 1235 FREE((caddr_t)lfp, M_NFSDLOCKFILE); 1236} 1237 1238/* 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;
|
1232 1233 *stpp = NULL; 1234 hp = NFSSTATEHASH(clp, *stateidp); 1235 LIST_FOREACH(stp, hp, ls_hash) { 1236 if (!NFSBCMP(stp->ls_stateid.other, stateidp->other, 1237 NFSX_STATEIDOTHER)) 1238 break; 1239 } 1240 1241 /* 1242 * If no state id in list, return NFSERR_BADSTATEID. 1243 */
| 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 */
|
1244 if (stp == LIST_END(hp)) 1245 return (NFSERR_BADSTATEID);
| 1260 if (stp == LIST_END(hp)) { 1261 error = NFSERR_BADSTATEID; 1262 goto out; 1263 }
|
1246 *stpp = stp;
| 1264 *stpp = stp;
|
1247 return (0);
| 1265 1266out: 1267 NFSEXITCODE(error); 1268 return (error);
|
1248} 1249 1250/* 1251 * This function gets an nfsstate structure via owner string. 1252 */ 1253static void 1254nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp, 1255 struct nfsstate **stpp) 1256{ 1257 struct nfsstate *stp; 1258 1259 *stpp = NULL; 1260 LIST_FOREACH(stp, hp, ls_list) { 1261 if (new_stp->ls_ownerlen == stp->ls_ownerlen && 1262 !NFSBCMP(new_stp->ls_owner,stp->ls_owner,stp->ls_ownerlen)) { 1263 *stpp = stp; 1264 return; 1265 } 1266 } 1267} 1268 1269/* 1270 * Lock control function called to update lock status. 1271 * Returns 0 upon success, -1 if there is no lock and the flags indicate 1272 * that one isn't to be created and an NFSERR_xxx for other errors. 1273 * The structures new_stp and new_lop are passed in as pointers that should 1274 * be set to NULL if the structure is used and shouldn't be free'd. 1275 * For the NFSLCK_TEST and NFSLCK_CHECK cases, the structures are 1276 * never used and can safely be allocated on the stack. For all other 1277 * cases, *new_stpp and *new_lopp should be malloc'd before the call, 1278 * in case they are used. 1279 */ 1280APPLESTATIC int 1281nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp, 1282 struct nfslock **new_lopp, struct nfslockconflict *cfp, 1283 nfsquad_t clientid, nfsv4stateid_t *stateidp, 1284 __unused struct nfsexstuff *exp, 1285 struct nfsrv_descript *nd, NFSPROC_T *p) 1286{ 1287 struct nfslock *lop; 1288 struct nfsstate *new_stp = *new_stpp; 1289 struct nfslock *new_lop = *new_lopp; 1290 struct nfsstate *tstp, *mystp, *nstp; 1291 int specialid = 0; 1292 struct nfslockfile *lfp; 1293 struct nfslock *other_lop = NULL; 1294 struct nfsstate *stp, *lckstp = NULL; 1295 struct nfsclient *clp = NULL; 1296 u_int32_t bits; 1297 int error = 0, haslock = 0, ret, reterr; 1298 int getlckret, delegation = 0, filestruct_locked; 1299 fhandle_t nfh; 1300 uint64_t first, end; 1301 uint32_t lock_flags; 1302 1303 if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_SETATTR)) { 1304 /* 1305 * Note the special cases of "all 1s" or "all 0s" stateids and 1306 * let reads with all 1s go ahead. 1307 */ 1308 if (new_stp->ls_stateid.seqid == 0x0 && 1309 new_stp->ls_stateid.other[0] == 0x0 && 1310 new_stp->ls_stateid.other[1] == 0x0 && 1311 new_stp->ls_stateid.other[2] == 0x0) 1312 specialid = 1; 1313 else if (new_stp->ls_stateid.seqid == 0xffffffff && 1314 new_stp->ls_stateid.other[0] == 0xffffffff && 1315 new_stp->ls_stateid.other[1] == 0xffffffff && 1316 new_stp->ls_stateid.other[2] == 0xffffffff) 1317 specialid = 2; 1318 } 1319 1320 /* 1321 * Check for restart conditions (client and server). 1322 */ 1323 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 1324 &new_stp->ls_stateid, specialid); 1325 if (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) 1277{ 1278 struct nfsstate *stp; 1279 1280 *stpp = NULL; 1281 LIST_FOREACH(stp, hp, ls_list) { 1282 if (new_stp->ls_ownerlen == stp->ls_ownerlen && 1283 !NFSBCMP(new_stp->ls_owner,stp->ls_owner,stp->ls_ownerlen)) { 1284 *stpp = stp; 1285 return; 1286 } 1287 } 1288} 1289 1290/* 1291 * Lock control function called to update lock status. 1292 * Returns 0 upon success, -1 if there is no lock and the flags indicate 1293 * that one isn't to be created and an NFSERR_xxx for other errors. 1294 * The structures new_stp and new_lop are passed in as pointers that should 1295 * be set to NULL if the structure is used and shouldn't be free'd. 1296 * For the NFSLCK_TEST and NFSLCK_CHECK cases, the structures are 1297 * never used and can safely be allocated on the stack. For all other 1298 * cases, *new_stpp and *new_lopp should be malloc'd before the call, 1299 * in case they are used. 1300 */ 1301APPLESTATIC int 1302nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp, 1303 struct nfslock **new_lopp, struct nfslockconflict *cfp, 1304 nfsquad_t clientid, nfsv4stateid_t *stateidp, 1305 __unused struct nfsexstuff *exp, 1306 struct nfsrv_descript *nd, NFSPROC_T *p) 1307{ 1308 struct nfslock *lop; 1309 struct nfsstate *new_stp = *new_stpp; 1310 struct nfslock *new_lop = *new_lopp; 1311 struct nfsstate *tstp, *mystp, *nstp; 1312 int specialid = 0; 1313 struct nfslockfile *lfp; 1314 struct nfslock *other_lop = NULL; 1315 struct nfsstate *stp, *lckstp = NULL; 1316 struct nfsclient *clp = NULL; 1317 u_int32_t bits; 1318 int error = 0, haslock = 0, ret, reterr; 1319 int getlckret, delegation = 0, filestruct_locked; 1320 fhandle_t nfh; 1321 uint64_t first, end; 1322 uint32_t lock_flags; 1323 1324 if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_SETATTR)) { 1325 /* 1326 * Note the special cases of "all 1s" or "all 0s" stateids and 1327 * let reads with all 1s go ahead. 1328 */ 1329 if (new_stp->ls_stateid.seqid == 0x0 && 1330 new_stp->ls_stateid.other[0] == 0x0 && 1331 new_stp->ls_stateid.other[1] == 0x0 && 1332 new_stp->ls_stateid.other[2] == 0x0) 1333 specialid = 1; 1334 else if (new_stp->ls_stateid.seqid == 0xffffffff && 1335 new_stp->ls_stateid.other[0] == 0xffffffff && 1336 new_stp->ls_stateid.other[1] == 0xffffffff && 1337 new_stp->ls_stateid.other[2] == 0xffffffff) 1338 specialid = 2; 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)
|
1326 return (error);
| 1347 goto out;
|
1327 1328 /* 1329 * Check for state resource limit exceeded. 1330 */ 1331 if ((new_stp->ls_flags & NFSLCK_LOCK) &&
| 1348 1349 /* 1350 * Check for state resource limit exceeded. 1351 */ 1352 if ((new_stp->ls_flags & NFSLCK_LOCK) &&
|
1332 nfsrv_openpluslock > NFSRV_V4STATELIMIT) 1333 return (NFSERR_RESOURCE);
| 1353 nfsrv_openpluslock > NFSRV_V4STATELIMIT) { 1354 error = NFSERR_RESOURCE; 1355 goto out; 1356 }
|
1334 1335 /* 1336 * For the lock case, get another nfslock structure, 1337 * just in case we need it. 1338 * Malloc now, before we start sifting through the linked lists, 1339 * in case we have to wait for memory. 1340 */ 1341tryagain: 1342 if (new_stp->ls_flags & NFSLCK_LOCK) 1343 MALLOC(other_lop, struct nfslock *, sizeof (struct nfslock), 1344 M_NFSDLOCK, M_WAITOK); 1345 filestruct_locked = 0; 1346 reterr = 0; 1347 lfp = NULL; 1348 1349 /* 1350 * Get the lockfile structure for CFH now, so we can do a sanity 1351 * check against the stateid, before incrementing the seqid#, since 1352 * we want to return NFSERR_BADSTATEID on failure and the seqid# 1353 * shouldn't be incremented for this case. 1354 * If nfsrv_getlockfile() returns -1, it means "not found", which 1355 * will be handled later. 1356 * If we are doing Lock/LockU and local locking is enabled, sleep 1357 * lock the nfslockfile structure. 1358 */ 1359 getlckret = nfsrv_getlockfh(vp, new_stp->ls_flags, NULL, &nfh, p); 1360 NFSLOCKSTATE(); 1361 if (getlckret == 0) { 1362 if ((new_stp->ls_flags & (NFSLCK_LOCK | NFSLCK_UNLOCK)) != 0 && 1363 nfsrv_dolocallocks != 0 && nd->nd_repstat == 0) { 1364 getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL, 1365 &lfp, &nfh, 1); 1366 if (getlckret == 0) 1367 filestruct_locked = 1; 1368 } else 1369 getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL, 1370 &lfp, &nfh, 0); 1371 } 1372 if (getlckret != 0 && getlckret != -1) 1373 reterr = getlckret; 1374 1375 if (filestruct_locked != 0) { 1376 LIST_INIT(&lfp->lf_rollback); 1377 if ((new_stp->ls_flags & NFSLCK_LOCK)) { 1378 /* 1379 * For local locking, do the advisory locking now, so 1380 * that any conflict can be detected. A failure later 1381 * can be rolled back locally. If an error is returned, 1382 * struct nfslockfile has been unlocked and any local 1383 * locking rolled back. 1384 */ 1385 NFSUNLOCKSTATE(); 1386 reterr = nfsrv_locallock(vp, lfp, 1387 (new_lop->lo_flags & (NFSLCK_READ | NFSLCK_WRITE)), 1388 new_lop->lo_first, new_lop->lo_end, cfp, p); 1389 NFSLOCKSTATE(); 1390 } 1391 } 1392 1393 if (specialid == 0) { 1394 if (new_stp->ls_flags & NFSLCK_TEST) { 1395 /* 1396 * RFC 3530 does not list LockT as an op that renews a 1397 * lease, but the concensus seems to be that it is ok 1398 * for a server to do so. 1399 */ 1400 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 1401 (nfsquad_t)((u_quad_t)0), NULL, p); 1402 1403 /* 1404 * Since NFSERR_EXPIRED, NFSERR_ADMINREVOKED are not valid 1405 * error returns for LockT, just go ahead and test for a lock, 1406 * since there are no locks for this client, but other locks 1407 * can conflict. (ie. same client will always be false) 1408 */ 1409 if (error == NFSERR_EXPIRED || error == NFSERR_ADMINREVOKED) 1410 error = 0; 1411 lckstp = new_stp; 1412 } else { 1413 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 1414 (nfsquad_t)((u_quad_t)0), NULL, p); 1415 if (error == 0) 1416 /* 1417 * Look up the stateid 1418 */ 1419 error = nfsrv_getstate(clp, &new_stp->ls_stateid, 1420 new_stp->ls_flags, &stp); 1421 /* 1422 * do some sanity checks for an unconfirmed open or a 1423 * stateid that refers to the wrong file, for an open stateid 1424 */ 1425 if (error == 0 && (stp->ls_flags & NFSLCK_OPEN) && 1426 ((stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM) || 1427 (getlckret == 0 && stp->ls_lfp != lfp))) 1428 error = NFSERR_BADSTATEID; 1429 if (error == 0 && 1430 (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) && 1431 getlckret == 0 && stp->ls_lfp != lfp) 1432 error = NFSERR_BADSTATEID; 1433 1434 /* 1435 * If the lockowner stateid doesn't refer to the same file, 1436 * I believe that is considered ok, since some clients will 1437 * only create a single lockowner and use that for all locks 1438 * on all files. 1439 * For now, log it as a diagnostic, instead of considering it 1440 * a BadStateid. 1441 */ 1442 if (error == 0 && (stp->ls_flags & 1443 (NFSLCK_OPEN | NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) == 0 && 1444 getlckret == 0 && stp->ls_lfp != lfp) { 1445#ifdef DIAGNOSTIC 1446 printf("Got a lock statid for different file open\n"); 1447#endif 1448 /* 1449 error = NFSERR_BADSTATEID; 1450 */ 1451 } 1452 1453 if (error == 0) { 1454 if (new_stp->ls_flags & NFSLCK_OPENTOLOCK) { 1455 /* 1456 * If haslock set, we've already checked the seqid. 1457 */ 1458 if (!haslock) { 1459 if (stp->ls_flags & NFSLCK_OPEN) 1460 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 1461 stp->ls_openowner, new_stp->ls_op); 1462 else 1463 error = NFSERR_BADSTATEID; 1464 } 1465 if (!error) 1466 nfsrv_getowner(&stp->ls_open, new_stp, &lckstp); 1467 if (lckstp) 1468 /* 1469 * I believe this should be an error, but it 1470 * isn't obvious what NFSERR_xxx would be 1471 * appropriate, so I'll use NFSERR_INVAL for now. 1472 */ 1473 error = NFSERR_INVAL; 1474 else 1475 lckstp = new_stp; 1476 } else if (new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK)) { 1477 /* 1478 * If haslock set, ditto above. 1479 */ 1480 if (!haslock) { 1481 if (stp->ls_flags & NFSLCK_OPEN) 1482 error = NFSERR_BADSTATEID; 1483 else 1484 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 1485 stp, new_stp->ls_op); 1486 } 1487 lckstp = stp; 1488 } else { 1489 lckstp = stp; 1490 } 1491 } 1492 /* 1493 * If the seqid part of the stateid isn't the same, return 1494 * NFSERR_OLDSTATEID for cases other than I/O Ops. 1495 * For I/O Ops, only return NFSERR_OLDSTATEID if 1496 * nfsrv_returnoldstateid is set. (The concensus on the email 1497 * list was that most clients would prefer to not receive 1498 * NFSERR_OLDSTATEID for I/O Ops, but the RFC suggests that that 1499 * is what will happen, so I use the nfsrv_returnoldstateid to 1500 * allow for either server configuration.) 1501 */ 1502 if (!error && stp->ls_stateid.seqid!=new_stp->ls_stateid.seqid && 1503 (!(new_stp->ls_flags & NFSLCK_CHECK) || 1504 nfsrv_returnoldstateid)) 1505 error = NFSERR_OLDSTATEID; 1506 } 1507 } 1508 1509 /* 1510 * Now we can check for grace. 1511 */ 1512 if (!error) 1513 error = nfsrv_checkgrace(new_stp->ls_flags); 1514 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error && 1515 nfsrv_checkstable(clp)) 1516 error = NFSERR_NOGRACE; 1517 /* 1518 * If we successfully Reclaimed state, note that. 1519 */ 1520 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error) 1521 nfsrv_markstable(clp); 1522 1523 /* 1524 * At this point, either error == NFSERR_BADSTATEID or the 1525 * seqid# has been updated, so we can return any error. 1526 * If error == 0, there may be an error in: 1527 * nd_repstat - Set by the calling function. 1528 * reterr - Set above, if getting the nfslockfile structure 1529 * or acquiring the local lock failed. 1530 * (If both of these are set, nd_repstat should probably be 1531 * returned, since that error was detected before this 1532 * function call.) 1533 */ 1534 if (error != 0 || nd->nd_repstat != 0 || reterr != 0) { 1535 if (error == 0) { 1536 if (nd->nd_repstat != 0) 1537 error = nd->nd_repstat; 1538 else 1539 error = reterr; 1540 } 1541 if (filestruct_locked != 0) { 1542 /* Roll back local locks. */ 1543 NFSUNLOCKSTATE(); 1544 nfsrv_locallock_rollback(vp, lfp, p); 1545 NFSLOCKSTATE(); 1546 nfsrv_unlocklf(lfp); 1547 } 1548 NFSUNLOCKSTATE();
| 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: 1365 if (new_stp->ls_flags & NFSLCK_LOCK) 1366 MALLOC(other_lop, struct nfslock *, sizeof (struct nfslock), 1367 M_NFSDLOCK, M_WAITOK); 1368 filestruct_locked = 0; 1369 reterr = 0; 1370 lfp = NULL; 1371 1372 /* 1373 * Get the lockfile structure for CFH now, so we can do a sanity 1374 * check against the stateid, before incrementing the seqid#, since 1375 * we want to return NFSERR_BADSTATEID on failure and the seqid# 1376 * shouldn't be incremented for this case. 1377 * If nfsrv_getlockfile() returns -1, it means "not found", which 1378 * will be handled later. 1379 * If we are doing Lock/LockU and local locking is enabled, sleep 1380 * lock the nfslockfile structure. 1381 */ 1382 getlckret = nfsrv_getlockfh(vp, new_stp->ls_flags, NULL, &nfh, p); 1383 NFSLOCKSTATE(); 1384 if (getlckret == 0) { 1385 if ((new_stp->ls_flags & (NFSLCK_LOCK | NFSLCK_UNLOCK)) != 0 && 1386 nfsrv_dolocallocks != 0 && nd->nd_repstat == 0) { 1387 getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL, 1388 &lfp, &nfh, 1); 1389 if (getlckret == 0) 1390 filestruct_locked = 1; 1391 } else 1392 getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL, 1393 &lfp, &nfh, 0); 1394 } 1395 if (getlckret != 0 && getlckret != -1) 1396 reterr = getlckret; 1397 1398 if (filestruct_locked != 0) { 1399 LIST_INIT(&lfp->lf_rollback); 1400 if ((new_stp->ls_flags & NFSLCK_LOCK)) { 1401 /* 1402 * For local locking, do the advisory locking now, so 1403 * that any conflict can be detected. A failure later 1404 * can be rolled back locally. If an error is returned, 1405 * struct nfslockfile has been unlocked and any local 1406 * locking rolled back. 1407 */ 1408 NFSUNLOCKSTATE(); 1409 reterr = nfsrv_locallock(vp, lfp, 1410 (new_lop->lo_flags & (NFSLCK_READ | NFSLCK_WRITE)), 1411 new_lop->lo_first, new_lop->lo_end, cfp, p); 1412 NFSLOCKSTATE(); 1413 } 1414 } 1415 1416 if (specialid == 0) { 1417 if (new_stp->ls_flags & NFSLCK_TEST) { 1418 /* 1419 * RFC 3530 does not list LockT as an op that renews a 1420 * lease, but the concensus seems to be that it is ok 1421 * for a server to do so. 1422 */ 1423 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 1424 (nfsquad_t)((u_quad_t)0), NULL, p); 1425 1426 /* 1427 * Since NFSERR_EXPIRED, NFSERR_ADMINREVOKED are not valid 1428 * error returns for LockT, just go ahead and test for a lock, 1429 * since there are no locks for this client, but other locks 1430 * can conflict. (ie. same client will always be false) 1431 */ 1432 if (error == NFSERR_EXPIRED || error == NFSERR_ADMINREVOKED) 1433 error = 0; 1434 lckstp = new_stp; 1435 } else { 1436 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 1437 (nfsquad_t)((u_quad_t)0), NULL, p); 1438 if (error == 0) 1439 /* 1440 * Look up the stateid 1441 */ 1442 error = nfsrv_getstate(clp, &new_stp->ls_stateid, 1443 new_stp->ls_flags, &stp); 1444 /* 1445 * do some sanity checks for an unconfirmed open or a 1446 * stateid that refers to the wrong file, for an open stateid 1447 */ 1448 if (error == 0 && (stp->ls_flags & NFSLCK_OPEN) && 1449 ((stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM) || 1450 (getlckret == 0 && stp->ls_lfp != lfp))) 1451 error = NFSERR_BADSTATEID; 1452 if (error == 0 && 1453 (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) && 1454 getlckret == 0 && stp->ls_lfp != lfp) 1455 error = NFSERR_BADSTATEID; 1456 1457 /* 1458 * If the lockowner stateid doesn't refer to the same file, 1459 * I believe that is considered ok, since some clients will 1460 * only create a single lockowner and use that for all locks 1461 * on all files. 1462 * For now, log it as a diagnostic, instead of considering it 1463 * a BadStateid. 1464 */ 1465 if (error == 0 && (stp->ls_flags & 1466 (NFSLCK_OPEN | NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) == 0 && 1467 getlckret == 0 && stp->ls_lfp != lfp) { 1468#ifdef DIAGNOSTIC 1469 printf("Got a lock statid for different file open\n"); 1470#endif 1471 /* 1472 error = NFSERR_BADSTATEID; 1473 */ 1474 } 1475 1476 if (error == 0) { 1477 if (new_stp->ls_flags & NFSLCK_OPENTOLOCK) { 1478 /* 1479 * If haslock set, we've already checked the seqid. 1480 */ 1481 if (!haslock) { 1482 if (stp->ls_flags & NFSLCK_OPEN) 1483 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 1484 stp->ls_openowner, new_stp->ls_op); 1485 else 1486 error = NFSERR_BADSTATEID; 1487 } 1488 if (!error) 1489 nfsrv_getowner(&stp->ls_open, new_stp, &lckstp); 1490 if (lckstp) 1491 /* 1492 * I believe this should be an error, but it 1493 * isn't obvious what NFSERR_xxx would be 1494 * appropriate, so I'll use NFSERR_INVAL for now. 1495 */ 1496 error = NFSERR_INVAL; 1497 else 1498 lckstp = new_stp; 1499 } else if (new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK)) { 1500 /* 1501 * If haslock set, ditto above. 1502 */ 1503 if (!haslock) { 1504 if (stp->ls_flags & NFSLCK_OPEN) 1505 error = NFSERR_BADSTATEID; 1506 else 1507 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 1508 stp, new_stp->ls_op); 1509 } 1510 lckstp = stp; 1511 } else { 1512 lckstp = stp; 1513 } 1514 } 1515 /* 1516 * If the seqid part of the stateid isn't the same, return 1517 * NFSERR_OLDSTATEID for cases other than I/O Ops. 1518 * For I/O Ops, only return NFSERR_OLDSTATEID if 1519 * nfsrv_returnoldstateid is set. (The concensus on the email 1520 * list was that most clients would prefer to not receive 1521 * NFSERR_OLDSTATEID for I/O Ops, but the RFC suggests that that 1522 * is what will happen, so I use the nfsrv_returnoldstateid to 1523 * allow for either server configuration.) 1524 */ 1525 if (!error && stp->ls_stateid.seqid!=new_stp->ls_stateid.seqid && 1526 (!(new_stp->ls_flags & NFSLCK_CHECK) || 1527 nfsrv_returnoldstateid)) 1528 error = NFSERR_OLDSTATEID; 1529 } 1530 } 1531 1532 /* 1533 * Now we can check for grace. 1534 */ 1535 if (!error) 1536 error = nfsrv_checkgrace(new_stp->ls_flags); 1537 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error && 1538 nfsrv_checkstable(clp)) 1539 error = NFSERR_NOGRACE; 1540 /* 1541 * If we successfully Reclaimed state, note that. 1542 */ 1543 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error) 1544 nfsrv_markstable(clp); 1545 1546 /* 1547 * At this point, either error == NFSERR_BADSTATEID or the 1548 * seqid# has been updated, so we can return any error. 1549 * If error == 0, there may be an error in: 1550 * nd_repstat - Set by the calling function. 1551 * reterr - Set above, if getting the nfslockfile structure 1552 * or acquiring the local lock failed. 1553 * (If both of these are set, nd_repstat should probably be 1554 * returned, since that error was detected before this 1555 * function call.) 1556 */ 1557 if (error != 0 || nd->nd_repstat != 0 || reterr != 0) { 1558 if (error == 0) { 1559 if (nd->nd_repstat != 0) 1560 error = nd->nd_repstat; 1561 else 1562 error = reterr; 1563 } 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();
|
1549 if (other_lop) 1550 FREE((caddr_t)other_lop, M_NFSDLOCK); 1551 if (haslock) { 1552 NFSLOCKV4ROOTMUTEX(); 1553 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1554 NFSUNLOCKV4ROOTMUTEX(); 1555 } 1556 return (error);
| 1572 goto out;
|
1557 } 1558 1559 /* 1560 * Check the nfsrv_getlockfile return. 1561 * Returned -1 if no structure found. 1562 */ 1563 if (getlckret == -1) { 1564 error = NFSERR_EXPIRED; 1565 /* 1566 * Called from lockt, so no lock is OK. 1567 */ 1568 if (new_stp->ls_flags & NFSLCK_TEST) { 1569 error = 0; 1570 } else if (new_stp->ls_flags & 1571 (NFSLCK_CHECK | NFSLCK_SETATTR)) { 1572 /* 1573 * Called to check for a lock, OK if the stateid is all 1574 * 1s or all 0s, but there should be an nfsstate 1575 * otherwise. 1576 * (ie. If there is no open, I'll assume no share 1577 * deny bits.) 1578 */ 1579 if (specialid) 1580 error = 0; 1581 else 1582 error = NFSERR_BADSTATEID; 1583 } 1584 NFSUNLOCKSTATE();
| 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; 1581 /* 1582 * Called from lockt, so no lock is OK. 1583 */ 1584 if (new_stp->ls_flags & NFSLCK_TEST) { 1585 error = 0; 1586 } else if (new_stp->ls_flags & 1587 (NFSLCK_CHECK | NFSLCK_SETATTR)) { 1588 /* 1589 * Called to check for a lock, OK if the stateid is all 1590 * 1s or all 0s, but there should be an nfsstate 1591 * otherwise. 1592 * (ie. If there is no open, I'll assume no share 1593 * deny bits.) 1594 */ 1595 if (specialid) 1596 error = 0; 1597 else 1598 error = NFSERR_BADSTATEID; 1599 } 1600 NFSUNLOCKSTATE();
|
1585 if (haslock) { 1586 NFSLOCKV4ROOTMUTEX(); 1587 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1588 NFSUNLOCKV4ROOTMUTEX(); 1589 } 1590 /* 1591 * Called to lock or unlock, so the lock has gone away. 1592 */ 1593 return (error);
| 1601 goto out;
|
1594 } 1595 1596 /* 1597 * For NFSLCK_CHECK and NFSLCK_LOCK, test for a share conflict. 1598 * For NFSLCK_CHECK, allow a read if write access is granted, 1599 * but check for a deny. For NFSLCK_LOCK, require correct access, 1600 * which implies a conflicting deny can't exist. 1601 */ 1602 if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_LOCK)) { 1603 /* 1604 * Four kinds of state id: 1605 * - specialid (all 0s or all 1s), only for NFSLCK_CHECK 1606 * - stateid for an open 1607 * - stateid for a delegation 1608 * - stateid for a lock owner 1609 */ 1610 if (!specialid) { 1611 if (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) { 1612 delegation = 1; 1613 mystp = stp; 1614 nfsrv_delaydelegtimeout(stp); 1615 } else if (stp->ls_flags & NFSLCK_OPEN) { 1616 mystp = stp; 1617 } else { 1618 mystp = stp->ls_openstp; 1619 } 1620 /* 1621 * If locking or checking, require correct access 1622 * bit set. 1623 */ 1624 if (((new_stp->ls_flags & NFSLCK_LOCK) && 1625 !((new_lop->lo_flags >> NFSLCK_LOCKSHIFT) & 1626 mystp->ls_flags & NFSLCK_ACCESSBITS)) || 1627 ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_READACCESS)) == 1628 (NFSLCK_CHECK | NFSLCK_READACCESS) && 1629 !(mystp->ls_flags & NFSLCK_READACCESS)) || 1630 ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_WRITEACCESS)) == 1631 (NFSLCK_CHECK | NFSLCK_WRITEACCESS) && 1632 !(mystp->ls_flags & NFSLCK_WRITEACCESS))) { 1633 if (filestruct_locked != 0) { 1634 /* Roll back local locks. */ 1635 NFSUNLOCKSTATE(); 1636 nfsrv_locallock_rollback(vp, lfp, p); 1637 NFSLOCKSTATE(); 1638 nfsrv_unlocklf(lfp); 1639 } 1640 NFSUNLOCKSTATE();
| 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 */ 1610 if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_LOCK)) { 1611 /* 1612 * Four kinds of state id: 1613 * - specialid (all 0s or all 1s), only for NFSLCK_CHECK 1614 * - stateid for an open 1615 * - stateid for a delegation 1616 * - stateid for a lock owner 1617 */ 1618 if (!specialid) { 1619 if (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) { 1620 delegation = 1; 1621 mystp = stp; 1622 nfsrv_delaydelegtimeout(stp); 1623 } else if (stp->ls_flags & NFSLCK_OPEN) { 1624 mystp = stp; 1625 } else { 1626 mystp = stp->ls_openstp; 1627 } 1628 /* 1629 * If locking or checking, require correct access 1630 * bit set. 1631 */ 1632 if (((new_stp->ls_flags & NFSLCK_LOCK) && 1633 !((new_lop->lo_flags >> NFSLCK_LOCKSHIFT) & 1634 mystp->ls_flags & NFSLCK_ACCESSBITS)) || 1635 ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_READACCESS)) == 1636 (NFSLCK_CHECK | NFSLCK_READACCESS) && 1637 !(mystp->ls_flags & NFSLCK_READACCESS)) || 1638 ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_WRITEACCESS)) == 1639 (NFSLCK_CHECK | NFSLCK_WRITEACCESS) && 1640 !(mystp->ls_flags & NFSLCK_WRITEACCESS))) { 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();
|
1641 if (other_lop) 1642 FREE((caddr_t)other_lop, M_NFSDLOCK); 1643 if (haslock) { 1644 NFSLOCKV4ROOTMUTEX(); 1645 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1646 NFSUNLOCKV4ROOTMUTEX(); 1647 } 1648 return (NFSERR_OPENMODE);
| 1649 error = NFSERR_OPENMODE; 1650 goto out;
|
1649 } 1650 } else 1651 mystp = NULL; 1652 if ((new_stp->ls_flags & NFSLCK_CHECK) && !delegation) { 1653 /* 1654 * Check for a conflicting deny bit. 1655 */ 1656 LIST_FOREACH(tstp, &lfp->lf_open, ls_file) { 1657 if (tstp != mystp) { 1658 bits = tstp->ls_flags; 1659 bits >>= NFSLCK_SHIFT; 1660 if (new_stp->ls_flags & bits & NFSLCK_ACCESSBITS) { 1661 ret = nfsrv_clientconflict(tstp->ls_clp, &haslock, 1662 vp, p); 1663 if (ret == 1) { 1664 /* 1665 * nfsrv_clientconflict unlocks state 1666 * when it returns non-zero. 1667 */ 1668 lckstp = NULL; 1669 goto tryagain; 1670 } 1671 if (ret == 0) 1672 NFSUNLOCKSTATE();
| 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) { 1659 if (tstp != mystp) { 1660 bits = tstp->ls_flags; 1661 bits >>= NFSLCK_SHIFT; 1662 if (new_stp->ls_flags & bits & NFSLCK_ACCESSBITS) { 1663 ret = nfsrv_clientconflict(tstp->ls_clp, &haslock, 1664 vp, p); 1665 if (ret == 1) { 1666 /* 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();
|
1673 if (haslock) { 1674 NFSLOCKV4ROOTMUTEX(); 1675 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1676 NFSUNLOCKV4ROOTMUTEX(); 1677 }
| |
1678 if (ret == 2)
| 1675 if (ret == 2)
|
1679 return (NFSERR_PERM);
| 1676 error = NFSERR_PERM;
|
1680 else
| 1677 else
|
1681 return (NFSERR_OPENMODE);
| 1678 error = NFSERR_OPENMODE; 1679 goto out;
|
1682 } 1683 } 1684 } 1685 1686 /* We're outta here */ 1687 NFSUNLOCKSTATE();
| 1680 } 1681 } 1682 } 1683 1684 /* We're outta here */ 1685 NFSUNLOCKSTATE();
|
1688 if (haslock) { 1689 NFSLOCKV4ROOTMUTEX(); 1690 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1691 NFSUNLOCKV4ROOTMUTEX(); 1692 } 1693 return (0);
| 1686 goto out;
|
1694 } 1695 } 1696 1697 /* 1698 * For setattr, just get rid of all the Delegations for other clients. 1699 */ 1700 if (new_stp->ls_flags & NFSLCK_SETATTR) { 1701 ret = nfsrv_cleandeleg(vp, lfp, clp, &haslock, p); 1702 if (ret) { 1703 /* 1704 * nfsrv_cleandeleg() unlocks state when it 1705 * returns non-zero. 1706 */ 1707 if (ret == -1) { 1708 lckstp = NULL; 1709 goto tryagain; 1710 }
| 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 }
|
1711 return (ret);
| 1704 error = ret; 1705 goto out;
|
1712 } 1713 if (!(new_stp->ls_flags & NFSLCK_CHECK) || 1714 (LIST_EMPTY(&lfp->lf_open) && LIST_EMPTY(&lfp->lf_lock) && 1715 LIST_EMPTY(&lfp->lf_deleg))) { 1716 NFSUNLOCKSTATE();
| 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();
|
1717 if (haslock) { 1718 NFSLOCKV4ROOTMUTEX(); 1719 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1720 NFSUNLOCKV4ROOTMUTEX(); 1721 } 1722 return (0);
| 1711 goto out;
|
1723 } 1724 } 1725 1726 /* 1727 * Check for a conflicting delegation. If one is found, call 1728 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 1729 * been set yet, it will get the lock. Otherwise, it will recall 1730 * the delegation. Then, we try try again... 1731 * I currently believe the conflict algorithm to be: 1732 * For Lock Ops (Lock/LockT/LockU) 1733 * - there is a conflict iff a different client has a write delegation 1734 * For Reading (Read Op) 1735 * - there is a conflict iff a different client has a write delegation 1736 * (the specialids are always a different client) 1737 * For Writing (Write/Setattr of size) 1738 * - there is a conflict if a different client has any delegation 1739 * - there is a conflict if the same client has a read delegation 1740 * (I don't understand why this isn't allowed, but that seems to be 1741 * the current concensus?) 1742 */ 1743 tstp = LIST_FIRST(&lfp->lf_deleg); 1744 while (tstp != LIST_END(&lfp->lf_deleg)) { 1745 nstp = LIST_NEXT(tstp, ls_file); 1746 if ((((new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK|NFSLCK_TEST))|| 1747 ((new_stp->ls_flags & NFSLCK_CHECK) && 1748 (new_lop->lo_flags & NFSLCK_READ))) && 1749 clp != tstp->ls_clp && 1750 (tstp->ls_flags & NFSLCK_DELEGWRITE)) || 1751 ((new_stp->ls_flags & NFSLCK_CHECK) && 1752 (new_lop->lo_flags & NFSLCK_WRITE) && 1753 (clp != tstp->ls_clp || 1754 (tstp->ls_flags & NFSLCK_DELEGREAD)))) { 1755 if (filestruct_locked != 0) { 1756 /* Roll back local locks. */ 1757 NFSUNLOCKSTATE(); 1758 nfsrv_locallock_rollback(vp, lfp, p); 1759 NFSLOCKSTATE(); 1760 nfsrv_unlocklf(lfp); 1761 } 1762 ret = nfsrv_delegconflict(tstp, &haslock, p, vp); 1763 if (ret) { 1764 /* 1765 * nfsrv_delegconflict unlocks state when it 1766 * returns non-zero, which it always does. 1767 */ 1768 if (other_lop) { 1769 FREE((caddr_t)other_lop, M_NFSDLOCK); 1770 other_lop = NULL; 1771 } 1772 if (ret == -1) { 1773 lckstp = NULL; 1774 goto tryagain; 1775 }
| 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... 1720 * I currently believe the conflict algorithm to be: 1721 * For Lock Ops (Lock/LockT/LockU) 1722 * - there is a conflict iff a different client has a write delegation 1723 * For Reading (Read Op) 1724 * - there is a conflict iff a different client has a write delegation 1725 * (the specialids are always a different client) 1726 * For Writing (Write/Setattr of size) 1727 * - there is a conflict if a different client has any delegation 1728 * - there is a conflict if the same client has a read delegation 1729 * (I don't understand why this isn't allowed, but that seems to be 1730 * the current concensus?) 1731 */ 1732 tstp = LIST_FIRST(&lfp->lf_deleg); 1733 while (tstp != LIST_END(&lfp->lf_deleg)) { 1734 nstp = LIST_NEXT(tstp, ls_file); 1735 if ((((new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK|NFSLCK_TEST))|| 1736 ((new_stp->ls_flags & NFSLCK_CHECK) && 1737 (new_lop->lo_flags & NFSLCK_READ))) && 1738 clp != tstp->ls_clp && 1739 (tstp->ls_flags & NFSLCK_DELEGWRITE)) || 1740 ((new_stp->ls_flags & NFSLCK_CHECK) && 1741 (new_lop->lo_flags & NFSLCK_WRITE) && 1742 (clp != tstp->ls_clp || 1743 (tstp->ls_flags & NFSLCK_DELEGREAD)))) { 1744 if (filestruct_locked != 0) { 1745 /* Roll back local locks. */ 1746 NFSUNLOCKSTATE(); 1747 nfsrv_locallock_rollback(vp, lfp, p); 1748 NFSLOCKSTATE(); 1749 nfsrv_unlocklf(lfp); 1750 } 1751 ret = nfsrv_delegconflict(tstp, &haslock, p, vp); 1752 if (ret) { 1753 /* 1754 * nfsrv_delegconflict unlocks state when it 1755 * returns non-zero, which it always does. 1756 */ 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 }
|
1776 return (ret);
| 1765 error = ret; 1766 goto out;
|
1777 } 1778 /* Never gets here. */ 1779 } 1780 tstp = nstp; 1781 } 1782 1783 /* 1784 * Handle the unlock case by calling nfsrv_updatelock(). 1785 * (Should I have done some access checking above for unlock? For now, 1786 * just let it happen.) 1787 */ 1788 if (new_stp->ls_flags & NFSLCK_UNLOCK) { 1789 first = new_lop->lo_first; 1790 end = new_lop->lo_end; 1791 nfsrv_updatelock(stp, new_lopp, &other_lop, lfp); 1792 stateidp->seqid = ++(stp->ls_stateid.seqid); 1793 stateidp->other[0] = stp->ls_stateid.other[0]; 1794 stateidp->other[1] = stp->ls_stateid.other[1]; 1795 stateidp->other[2] = stp->ls_stateid.other[2]; 1796 if (filestruct_locked != 0) { 1797 NFSUNLOCKSTATE(); 1798 /* Update the local locks. */ 1799 nfsrv_localunlock(vp, lfp, first, end, p); 1800 NFSLOCKSTATE(); 1801 nfsrv_unlocklf(lfp); 1802 } 1803 NFSUNLOCKSTATE();
| 1767 } 1768 /* Never gets here. */ 1769 } 1770 tstp = nstp; 1771 } 1772 1773 /* 1774 * Handle the unlock case by calling nfsrv_updatelock(). 1775 * (Should I have done some access checking above for unlock? For now, 1776 * just let it happen.) 1777 */ 1778 if (new_stp->ls_flags & NFSLCK_UNLOCK) { 1779 first = new_lop->lo_first; 1780 end = new_lop->lo_end; 1781 nfsrv_updatelock(stp, new_lopp, &other_lop, lfp); 1782 stateidp->seqid = ++(stp->ls_stateid.seqid); 1783 stateidp->other[0] = stp->ls_stateid.other[0]; 1784 stateidp->other[1] = stp->ls_stateid.other[1]; 1785 stateidp->other[2] = stp->ls_stateid.other[2]; 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();
|
1804 if (haslock) { 1805 NFSLOCKV4ROOTMUTEX(); 1806 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1807 NFSUNLOCKV4ROOTMUTEX(); 1808 } 1809 return (0);
| 1794 goto out;
|
1810 } 1811 1812 /* 1813 * Search for a conflicting lock. A lock conflicts if: 1814 * - the lock range overlaps and 1815 * - at least one lock is a write lock and 1816 * - it is not owned by the same lock owner 1817 */ 1818 if (!delegation) { 1819 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { 1820 if (new_lop->lo_end > lop->lo_first && 1821 new_lop->lo_first < lop->lo_end && 1822 (new_lop->lo_flags == NFSLCK_WRITE || 1823 lop->lo_flags == NFSLCK_WRITE) && 1824 lckstp != lop->lo_stp && 1825 (clp != lop->lo_stp->ls_clp || 1826 lckstp->ls_ownerlen != lop->lo_stp->ls_ownerlen || 1827 NFSBCMP(lckstp->ls_owner, lop->lo_stp->ls_owner, 1828 lckstp->ls_ownerlen))) { 1829 if (other_lop) { 1830 FREE((caddr_t)other_lop, M_NFSDLOCK); 1831 other_lop = NULL; 1832 } 1833 ret = nfsrv_clientconflict(lop->lo_stp->ls_clp,&haslock,vp,p); 1834 if (ret == 1) { 1835 if (filestruct_locked != 0) { 1836 /* Roll back local locks. */ 1837 nfsrv_locallock_rollback(vp, lfp, p); 1838 NFSLOCKSTATE(); 1839 nfsrv_unlocklf(lfp); 1840 NFSUNLOCKSTATE(); 1841 } 1842 /* 1843 * nfsrv_clientconflict() unlocks state when it 1844 * returns non-zero. 1845 */ 1846 lckstp = NULL; 1847 goto tryagain; 1848 } 1849 /* 1850 * Found a conflicting lock, so record the conflict and 1851 * return the error. 1852 */ 1853 if (cfp != NULL && ret == 0) { 1854 cfp->cl_clientid.lval[0]=lop->lo_stp->ls_stateid.other[0]; 1855 cfp->cl_clientid.lval[1]=lop->lo_stp->ls_stateid.other[1]; 1856 cfp->cl_first = lop->lo_first; 1857 cfp->cl_end = lop->lo_end; 1858 cfp->cl_flags = lop->lo_flags; 1859 cfp->cl_ownerlen = lop->lo_stp->ls_ownerlen; 1860 NFSBCOPY(lop->lo_stp->ls_owner, cfp->cl_owner, 1861 cfp->cl_ownerlen); 1862 } 1863 if (ret == 2) 1864 error = NFSERR_PERM; 1865 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 1866 error = NFSERR_RECLAIMCONFLICT; 1867 else if (new_stp->ls_flags & NFSLCK_CHECK) 1868 error = NFSERR_LOCKED; 1869 else 1870 error = NFSERR_DENIED; 1871 if (filestruct_locked != 0 && ret == 0) { 1872 /* Roll back local locks. */ 1873 NFSUNLOCKSTATE(); 1874 nfsrv_locallock_rollback(vp, lfp, p); 1875 NFSLOCKSTATE(); 1876 nfsrv_unlocklf(lfp); 1877 } 1878 if (ret == 0) 1879 NFSUNLOCKSTATE();
| 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 */ 1803 if (!delegation) { 1804 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { 1805 if (new_lop->lo_end > lop->lo_first && 1806 new_lop->lo_first < lop->lo_end && 1807 (new_lop->lo_flags == NFSLCK_WRITE || 1808 lop->lo_flags == NFSLCK_WRITE) && 1809 lckstp != lop->lo_stp && 1810 (clp != lop->lo_stp->ls_clp || 1811 lckstp->ls_ownerlen != lop->lo_stp->ls_ownerlen || 1812 NFSBCMP(lckstp->ls_owner, lop->lo_stp->ls_owner, 1813 lckstp->ls_ownerlen))) { 1814 if (other_lop) { 1815 FREE((caddr_t)other_lop, M_NFSDLOCK); 1816 other_lop = NULL; 1817 } 1818 ret = nfsrv_clientconflict(lop->lo_stp->ls_clp,&haslock,vp,p); 1819 if (ret == 1) { 1820 if (filestruct_locked != 0) { 1821 /* Roll back local locks. */ 1822 nfsrv_locallock_rollback(vp, lfp, p); 1823 NFSLOCKSTATE(); 1824 nfsrv_unlocklf(lfp); 1825 NFSUNLOCKSTATE(); 1826 } 1827 /* 1828 * nfsrv_clientconflict() unlocks state when it 1829 * returns non-zero. 1830 */ 1831 lckstp = NULL; 1832 goto tryagain; 1833 } 1834 /* 1835 * Found a conflicting lock, so record the conflict and 1836 * return the error. 1837 */ 1838 if (cfp != NULL && ret == 0) { 1839 cfp->cl_clientid.lval[0]=lop->lo_stp->ls_stateid.other[0]; 1840 cfp->cl_clientid.lval[1]=lop->lo_stp->ls_stateid.other[1]; 1841 cfp->cl_first = lop->lo_first; 1842 cfp->cl_end = lop->lo_end; 1843 cfp->cl_flags = lop->lo_flags; 1844 cfp->cl_ownerlen = lop->lo_stp->ls_ownerlen; 1845 NFSBCOPY(lop->lo_stp->ls_owner, cfp->cl_owner, 1846 cfp->cl_ownerlen); 1847 } 1848 if (ret == 2) 1849 error = NFSERR_PERM; 1850 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 1851 error = NFSERR_RECLAIMCONFLICT; 1852 else if (new_stp->ls_flags & NFSLCK_CHECK) 1853 error = NFSERR_LOCKED; 1854 else 1855 error = NFSERR_DENIED; 1856 if (filestruct_locked != 0 && ret == 0) { 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();
|
1880 if (haslock) { 1881 NFSLOCKV4ROOTMUTEX(); 1882 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1883 NFSUNLOCKV4ROOTMUTEX(); 1884 } 1885 return (error);
| 1865 goto out;
|
1886 } 1887 } 1888 } 1889 1890 /* 1891 * We only get here if there was no lock that conflicted. 1892 */ 1893 if (new_stp->ls_flags & (NFSLCK_TEST | NFSLCK_CHECK)) { 1894 NFSUNLOCKSTATE();
| 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();
|
1895 if (haslock) { 1896 NFSLOCKV4ROOTMUTEX(); 1897 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1898 NFSUNLOCKV4ROOTMUTEX(); 1899 } 1900 return (0);
| 1875 goto out;
|
1901 } 1902 1903 /* 1904 * We only get here when we are creating or modifying a lock. 1905 * There are two variants: 1906 * - exist_lock_owner where lock_owner exists 1907 * - open_to_lock_owner with new lock_owner 1908 */ 1909 first = new_lop->lo_first; 1910 end = new_lop->lo_end; 1911 lock_flags = new_lop->lo_flags; 1912 if (!(new_stp->ls_flags & NFSLCK_OPENTOLOCK)) { 1913 nfsrv_updatelock(lckstp, new_lopp, &other_lop, lfp); 1914 stateidp->seqid = ++(lckstp->ls_stateid.seqid); 1915 stateidp->other[0] = lckstp->ls_stateid.other[0]; 1916 stateidp->other[1] = lckstp->ls_stateid.other[1]; 1917 stateidp->other[2] = lckstp->ls_stateid.other[2]; 1918 } else { 1919 /* 1920 * The new open_to_lock_owner case. 1921 * Link the new nfsstate into the lists. 1922 */ 1923 new_stp->ls_seq = new_stp->ls_opentolockseq; 1924 nfsrvd_refcache(new_stp->ls_op); 1925 stateidp->seqid = new_stp->ls_stateid.seqid = 1; 1926 stateidp->other[0] = new_stp->ls_stateid.other[0] = 1927 clp->lc_clientid.lval[0]; 1928 stateidp->other[1] = new_stp->ls_stateid.other[1] = 1929 clp->lc_clientid.lval[1]; 1930 stateidp->other[2] = new_stp->ls_stateid.other[2] = 1931 nfsrv_nextstateindex(clp); 1932 new_stp->ls_clp = clp; 1933 LIST_INIT(&new_stp->ls_lock); 1934 new_stp->ls_openstp = stp; 1935 new_stp->ls_lfp = lfp; 1936 nfsrv_insertlock(new_lop, (struct nfslock *)new_stp, new_stp, 1937 lfp); 1938 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_stp->ls_stateid), 1939 new_stp, ls_hash); 1940 LIST_INSERT_HEAD(&stp->ls_open, new_stp, ls_list); 1941 *new_lopp = NULL; 1942 *new_stpp = NULL; 1943 newnfsstats.srvlockowners++; 1944 nfsrv_openpluslock++; 1945 } 1946 if (filestruct_locked != 0) { 1947 NFSUNLOCKSTATE(); 1948 nfsrv_locallock_commit(lfp, lock_flags, first, end); 1949 NFSLOCKSTATE(); 1950 nfsrv_unlocklf(lfp); 1951 } 1952 NFSUNLOCKSTATE();
| 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 */ 1884 first = new_lop->lo_first; 1885 end = new_lop->lo_end; 1886 lock_flags = new_lop->lo_flags; 1887 if (!(new_stp->ls_flags & NFSLCK_OPENTOLOCK)) { 1888 nfsrv_updatelock(lckstp, new_lopp, &other_lop, lfp); 1889 stateidp->seqid = ++(lckstp->ls_stateid.seqid); 1890 stateidp->other[0] = lckstp->ls_stateid.other[0]; 1891 stateidp->other[1] = lckstp->ls_stateid.other[1]; 1892 stateidp->other[2] = lckstp->ls_stateid.other[2]; 1893 } else { 1894 /* 1895 * The new open_to_lock_owner case. 1896 * Link the new nfsstate into the lists. 1897 */ 1898 new_stp->ls_seq = new_stp->ls_opentolockseq; 1899 nfsrvd_refcache(new_stp->ls_op); 1900 stateidp->seqid = new_stp->ls_stateid.seqid = 1; 1901 stateidp->other[0] = new_stp->ls_stateid.other[0] = 1902 clp->lc_clientid.lval[0]; 1903 stateidp->other[1] = new_stp->ls_stateid.other[1] = 1904 clp->lc_clientid.lval[1]; 1905 stateidp->other[2] = new_stp->ls_stateid.other[2] = 1906 nfsrv_nextstateindex(clp); 1907 new_stp->ls_clp = clp; 1908 LIST_INIT(&new_stp->ls_lock); 1909 new_stp->ls_openstp = stp; 1910 new_stp->ls_lfp = lfp; 1911 nfsrv_insertlock(new_lop, (struct nfslock *)new_stp, new_stp, 1912 lfp); 1913 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_stp->ls_stateid), 1914 new_stp, ls_hash); 1915 LIST_INSERT_HEAD(&stp->ls_open, new_stp, ls_list); 1916 *new_lopp = NULL; 1917 *new_stpp = NULL; 1918 newnfsstats.srvlockowners++; 1919 nfsrv_openpluslock++; 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:
|
1953 if (haslock) { 1954 NFSLOCKV4ROOTMUTEX(); 1955 nfsv4_unlock(&nfsv4rootfs_lock, 1); 1956 NFSUNLOCKV4ROOTMUTEX(); 1957 } 1958 if (other_lop) 1959 FREE((caddr_t)other_lop, M_NFSDLOCK);
| 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);
|
1960 return (0);
| 1937 NFSEXITCODE2(error, nd); 1938 return (error);
|
1961} 1962 1963/* 1964 * Check for state errors for Open. 1965 * repstat is passed back out as an error if more critical errors 1966 * are not detected. 1967 */ 1968APPLESTATIC int 1969nfsrv_opencheck(nfsquad_t clientid, nfsv4stateid_t *stateidp, 1970 struct nfsstate *new_stp, vnode_t vp, struct nfsrv_descript *nd, 1971 NFSPROC_T *p, int repstat) 1972{ 1973 struct nfsstate *stp, *nstp; 1974 struct nfsclient *clp; 1975 struct nfsstate *ownerstp; 1976 struct nfslockfile *lfp, *new_lfp;
| 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;
|
1977 int error, haslock = 0, ret, readonly = 0, getfhret = 0;
| 1955 int error = 0, haslock = 0, ret, readonly = 0, getfhret = 0;
|
1978 1979 if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS) 1980 readonly = 1; 1981 /* 1982 * Check for restart conditions (client and server). 1983 */ 1984 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 1985 &new_stp->ls_stateid, 0); 1986 if (error)
| 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)
|
1987 return (error);
| 1965 goto out;
|
1988 1989 /* 1990 * Check for state resource limit exceeded. 1991 * Technically this should be SMP protected, but the worst 1992 * case error is "out by one or two" on the count when it 1993 * returns NFSERR_RESOURCE and the limit is just a rather 1994 * arbitrary high water mark, so no harm is done. 1995 */
| 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 */
|
1996 if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) 1997 return (NFSERR_RESOURCE);
| 1974 if (nfsrv_openpluslock > NFSRV_V4STATELIMIT) { 1975 error = NFSERR_RESOURCE; 1976 goto out; 1977 }
|
1998 1999tryagain: 2000 MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile), 2001 M_NFSDLOCKFILE, M_WAITOK); 2002 if (vp) 2003 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, &new_lfp, 2004 NULL, p); 2005 NFSLOCKSTATE(); 2006 /* 2007 * Get the nfsclient structure. 2008 */ 2009 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 2010 (nfsquad_t)((u_quad_t)0), NULL, p); 2011 2012 /* 2013 * Look up the open owner. See if it needs confirmation and 2014 * check the seq#, as required. 2015 */ 2016 if (!error) 2017 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp); 2018 2019 if (!error && ownerstp) { 2020 error = nfsrv_checkseqid(nd, new_stp->ls_seq, ownerstp, 2021 new_stp->ls_op); 2022 /* 2023 * If the OpenOwner hasn't been confirmed, assume the 2024 * old one was a replay and this one is ok. 2025 * See: RFC3530 Sec. 14.2.18. 2026 */ 2027 if (error == NFSERR_BADSEQID && 2028 (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM)) 2029 error = 0; 2030 } 2031 2032 /* 2033 * Check for grace. 2034 */ 2035 if (!error) 2036 error = nfsrv_checkgrace(new_stp->ls_flags); 2037 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error && 2038 nfsrv_checkstable(clp)) 2039 error = NFSERR_NOGRACE; 2040 2041 /* 2042 * If none of the above errors occurred, let repstat be 2043 * returned. 2044 */ 2045 if (repstat && !error) 2046 error = repstat; 2047 if (error) { 2048 NFSUNLOCKSTATE(); 2049 if (haslock) { 2050 NFSLOCKV4ROOTMUTEX(); 2051 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2052 NFSUNLOCKV4ROOTMUTEX(); 2053 } 2054 free((caddr_t)new_lfp, M_NFSDLOCKFILE);
| 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(); 1986 /* 1987 * Get the nfsclient structure. 1988 */ 1989 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 1990 (nfsquad_t)((u_quad_t)0), NULL, p); 1991 1992 /* 1993 * Look up the open owner. See if it needs confirmation and 1994 * check the seq#, as required. 1995 */ 1996 if (!error) 1997 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp); 1998 1999 if (!error && ownerstp) { 2000 error = nfsrv_checkseqid(nd, new_stp->ls_seq, ownerstp, 2001 new_stp->ls_op); 2002 /* 2003 * If the OpenOwner hasn't been confirmed, assume the 2004 * old one was a replay and this one is ok. 2005 * See: RFC3530 Sec. 14.2.18. 2006 */ 2007 if (error == NFSERR_BADSEQID && 2008 (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM)) 2009 error = 0; 2010 } 2011 2012 /* 2013 * Check for grace. 2014 */ 2015 if (!error) 2016 error = nfsrv_checkgrace(new_stp->ls_flags); 2017 if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error && 2018 nfsrv_checkstable(clp)) 2019 error = NFSERR_NOGRACE; 2020 2021 /* 2022 * If none of the above errors occurred, let repstat be 2023 * returned. 2024 */ 2025 if (repstat && !error) 2026 error = repstat; 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);
|
2055 return (error);
| 2035 goto out;
|
2056 } 2057 2058 /* 2059 * If vp == NULL, the file doesn't exist yet, so return ok. 2060 * (This always happens on the first pass, so haslock must be 0.) 2061 */ 2062 if (vp == NULL) { 2063 NFSUNLOCKSTATE(); 2064 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE);
| 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);
|
2065 return (0);
| 2045 goto out;
|
2066 } 2067 2068 /* 2069 * Get the structure for the underlying file. 2070 */ 2071 if (getfhret) 2072 error = getfhret; 2073 else 2074 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp, 2075 NULL, 0); 2076 if (new_lfp) 2077 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2078 if (error) { 2079 NFSUNLOCKSTATE(); 2080 if (haslock) { 2081 NFSLOCKV4ROOTMUTEX(); 2082 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2083 NFSUNLOCKV4ROOTMUTEX(); 2084 }
| 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 }
|
2085 return (error);
| 2065 goto out;
|
2086 } 2087 2088 /* 2089 * Search for a conflicting open/share. 2090 */ 2091 if (new_stp->ls_flags & NFSLCK_DELEGCUR) { 2092 /* 2093 * For Delegate_Cur, search for the matching Delegation, 2094 * which indicates no conflict. 2095 * An old delegation should have been recovered by the 2096 * client doing a Claim_DELEGATE_Prev, so I won't let 2097 * it match and return NFSERR_EXPIRED. Should I let it 2098 * match? 2099 */ 2100 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2101 if (!(stp->ls_flags & NFSLCK_OLDDELEG) && 2102 stateidp->seqid == stp->ls_stateid.seqid && 2103 !NFSBCMP(stateidp->other, stp->ls_stateid.other, 2104 NFSX_STATEIDOTHER)) 2105 break; 2106 } 2107 if (stp == LIST_END(&lfp->lf_deleg) || 2108 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) && 2109 (stp->ls_flags & NFSLCK_DELEGREAD))) { 2110 NFSUNLOCKSTATE(); 2111 if (haslock) { 2112 NFSLOCKV4ROOTMUTEX(); 2113 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2114 NFSUNLOCKV4ROOTMUTEX(); 2115 }
| 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, 2074 * which indicates no conflict. 2075 * An old delegation should have been recovered by the 2076 * client doing a Claim_DELEGATE_Prev, so I won't let 2077 * it match and return NFSERR_EXPIRED. Should I let it 2078 * match? 2079 */ 2080 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2081 if (!(stp->ls_flags & NFSLCK_OLDDELEG) && 2082 stateidp->seqid == stp->ls_stateid.seqid && 2083 !NFSBCMP(stateidp->other, stp->ls_stateid.other, 2084 NFSX_STATEIDOTHER)) 2085 break; 2086 } 2087 if (stp == LIST_END(&lfp->lf_deleg) || 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 }
|
2116 return (NFSERR_EXPIRED);
| 2096 error = NFSERR_EXPIRED; 2097 goto out;
|
2117 } 2118 } 2119 2120 /* 2121 * Check for access/deny bit conflicts. I check for the same 2122 * owner as well, in case the client didn't bother. 2123 */ 2124 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 2125 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR) && 2126 (((new_stp->ls_flags & NFSLCK_ACCESSBITS) & 2127 ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))|| 2128 ((stp->ls_flags & NFSLCK_ACCESSBITS) & 2129 ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS)))){ 2130 ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); 2131 if (ret == 1) { 2132 /* 2133 * nfsrv_clientconflict() unlocks 2134 * state when it returns non-zero. 2135 */ 2136 goto tryagain; 2137 } 2138 if (ret == 2) 2139 error = NFSERR_PERM; 2140 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2141 error = NFSERR_RECLAIMCONFLICT; 2142 else 2143 error = NFSERR_SHAREDENIED; 2144 if (ret == 0) 2145 NFSUNLOCKSTATE(); 2146 if (haslock) { 2147 NFSLOCKV4ROOTMUTEX(); 2148 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2149 NFSUNLOCKV4ROOTMUTEX(); 2150 }
| 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) { 2106 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR) && 2107 (((new_stp->ls_flags & NFSLCK_ACCESSBITS) & 2108 ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))|| 2109 ((stp->ls_flags & NFSLCK_ACCESSBITS) & 2110 ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS)))){ 2111 ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); 2112 if (ret == 1) { 2113 /* 2114 * nfsrv_clientconflict() unlocks 2115 * state when it returns non-zero. 2116 */ 2117 goto tryagain; 2118 } 2119 if (ret == 2) 2120 error = NFSERR_PERM; 2121 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2122 error = NFSERR_RECLAIMCONFLICT; 2123 else 2124 error = NFSERR_SHAREDENIED; 2125 if (ret == 0) 2126 NFSUNLOCKSTATE(); 2127 if (haslock) { 2128 NFSLOCKV4ROOTMUTEX(); 2129 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2130 NFSUNLOCKV4ROOTMUTEX(); 2131 }
|
2151 return (error);
| 2132 goto out;
|
2152 } 2153 } 2154 2155 /* 2156 * Check for a conflicting delegation. If one is found, call 2157 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 2158 * been set yet, it will get the lock. Otherwise, it will recall 2159 * the delegation. Then, we try try again... 2160 * (If NFSLCK_DELEGCUR is set, it has a delegation, so there 2161 * isn't a conflict.) 2162 * I currently believe the conflict algorithm to be: 2163 * For Open with Read Access and Deny None 2164 * - there is a conflict iff a different client has a write delegation 2165 * For Open with other Write Access or any Deny except None 2166 * - there is a conflict if a different client has any delegation 2167 * - there is a conflict if the same client has a read delegation 2168 * (The current concensus is that this last case should be 2169 * considered a conflict since the client with a read delegation 2170 * could have done an Open with ReadAccess and WriteDeny 2171 * locally and then not have checked for the WriteDeny.) 2172 * Don't check for a Reclaim, since that will be dealt with 2173 * by nfsrv_openctrl(). 2174 */ 2175 if (!(new_stp->ls_flags & 2176 (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR | NFSLCK_RECLAIM))) { 2177 stp = LIST_FIRST(&lfp->lf_deleg); 2178 while (stp != LIST_END(&lfp->lf_deleg)) { 2179 nstp = LIST_NEXT(stp, ls_file); 2180 if ((readonly && stp->ls_clp != clp && 2181 (stp->ls_flags & NFSLCK_DELEGWRITE)) || 2182 (!readonly && (stp->ls_clp != clp || 2183 (stp->ls_flags & NFSLCK_DELEGREAD)))) { 2184 ret = nfsrv_delegconflict(stp, &haslock, p, vp); 2185 if (ret) { 2186 /* 2187 * nfsrv_delegconflict() unlocks state 2188 * when it returns non-zero. 2189 */ 2190 if (ret == -1) 2191 goto tryagain;
| 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... 2141 * (If NFSLCK_DELEGCUR is set, it has a delegation, so there 2142 * isn't a conflict.) 2143 * I currently believe the conflict algorithm to be: 2144 * For Open with Read Access and Deny None 2145 * - there is a conflict iff a different client has a write delegation 2146 * For Open with other Write Access or any Deny except None 2147 * - there is a conflict if a different client has any delegation 2148 * - there is a conflict if the same client has a read delegation 2149 * (The current concensus is that this last case should be 2150 * considered a conflict since the client with a read delegation 2151 * could have done an Open with ReadAccess and WriteDeny 2152 * locally and then not have checked for the WriteDeny.) 2153 * Don't check for a Reclaim, since that will be dealt with 2154 * by nfsrv_openctrl(). 2155 */ 2156 if (!(new_stp->ls_flags & 2157 (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR | NFSLCK_RECLAIM))) { 2158 stp = LIST_FIRST(&lfp->lf_deleg); 2159 while (stp != LIST_END(&lfp->lf_deleg)) { 2160 nstp = LIST_NEXT(stp, ls_file); 2161 if ((readonly && stp->ls_clp != clp && 2162 (stp->ls_flags & NFSLCK_DELEGWRITE)) || 2163 (!readonly && (stp->ls_clp != clp || 2164 (stp->ls_flags & NFSLCK_DELEGREAD)))) { 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;
|
2192 return (ret);
| 2173 error = ret; 2174 goto out;
|
2193 } 2194 } 2195 stp = nstp; 2196 } 2197 } 2198 NFSUNLOCKSTATE(); 2199 if (haslock) { 2200 NFSLOCKV4ROOTMUTEX(); 2201 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2202 NFSUNLOCKV4ROOTMUTEX(); 2203 }
| 2175 } 2176 } 2177 stp = nstp; 2178 } 2179 } 2180 NFSUNLOCKSTATE(); 2181 if (haslock) { 2182 NFSLOCKV4ROOTMUTEX(); 2183 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2184 NFSUNLOCKV4ROOTMUTEX(); 2185 }
|
2204 return (0);
| 2186 2187out: 2188 NFSEXITCODE2(error, nd); 2189 return (error);
|
2205} 2206 2207/* 2208 * Open control function to create/update open state for an open. 2209 */ 2210APPLESTATIC int 2211nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp, 2212 struct nfsstate **new_stpp, nfsquad_t clientid, nfsv4stateid_t *stateidp, 2213 nfsv4stateid_t *delegstateidp, u_int32_t *rflagsp, struct nfsexstuff *exp, 2214 NFSPROC_T *p, u_quad_t filerev) 2215{ 2216 struct nfsstate *new_stp = *new_stpp; 2217 struct nfsstate *stp, *nstp; 2218 struct nfsstate *openstp = NULL, *new_open, *ownerstp, *new_deleg; 2219 struct nfslockfile *lfp, *new_lfp; 2220 struct nfsclient *clp;
| 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;
|
2221 int error, haslock = 0, ret, delegate = 1, writedeleg = 1;
| 2206 int error = 0, haslock = 0, ret, delegate = 1, writedeleg = 1;
|
2222 int readonly = 0, cbret = 1, getfhret = 0; 2223 2224 if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS) 2225 readonly = 1; 2226 /* 2227 * Check for restart conditions (client and server). 2228 * (Paranoia, should have been detected by nfsrv_opencheck().) 2229 * If an error does show up, return NFSERR_EXPIRED, since the 2230 * the seqid# has already been incremented. 2231 */ 2232 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 2233 &new_stp->ls_stateid, 0); 2234 if (error) { 2235 printf("Nfsd: openctrl unexpected restart err=%d\n", 2236 error);
| 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);
|
2237 return (NFSERR_EXPIRED);
| 2222 error = NFSERR_EXPIRED; 2223 goto out;
|
2238 } 2239 2240tryagain: 2241 MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile), 2242 M_NFSDLOCKFILE, M_WAITOK); 2243 MALLOC(new_open, struct nfsstate *, sizeof (struct nfsstate), 2244 M_NFSDSTATE, M_WAITOK); 2245 MALLOC(new_deleg, struct nfsstate *, sizeof (struct nfsstate), 2246 M_NFSDSTATE, M_WAITOK); 2247 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, &new_lfp, 2248 NULL, p); 2249 NFSLOCKSTATE(); 2250 /* 2251 * Get the client structure. Since the linked lists could be changed 2252 * by other nfsd processes if this process does a tsleep(), one of 2253 * two things must be done. 2254 * 1 - don't tsleep() 2255 * or 2256 * 2 - get the nfsv4_lock() { indicated by haslock == 1 } 2257 * before using the lists, since this lock stops the other 2258 * nfsd. This should only be used for rare cases, since it 2259 * essentially single threads the nfsd. 2260 * At this time, it is only done for cases where the stable 2261 * storage file must be written prior to completion of state 2262 * expiration. 2263 */ 2264 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 2265 (nfsquad_t)((u_quad_t)0), NULL, p); 2266 if (!error && (clp->lc_flags & LCL_NEEDSCBNULL) && 2267 clp->lc_program) { 2268 /* 2269 * This happens on the first open for a client 2270 * that supports callbacks. 2271 */ 2272 NFSUNLOCKSTATE(); 2273 /* 2274 * Although nfsrv_docallback() will sleep, clp won't 2275 * go away, since they are only removed when the 2276 * nfsv4_lock() has blocked the nfsd threads. The 2277 * fields in clp can change, but having multiple 2278 * threads do this Null callback RPC should be 2279 * harmless. 2280 */ 2281 cbret = nfsrv_docallback(clp, NFSV4PROC_CBNULL, 2282 NULL, 0, NULL, NULL, NULL, p); 2283 NFSLOCKSTATE(); 2284 clp->lc_flags &= ~LCL_NEEDSCBNULL; 2285 if (!cbret) 2286 clp->lc_flags |= LCL_CALLBACKSON; 2287 } 2288 2289 /* 2290 * Look up the open owner. See if it needs confirmation and 2291 * check the seq#, as required. 2292 */ 2293 if (!error) 2294 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp); 2295 2296 if (error) { 2297 NFSUNLOCKSTATE(); 2298 printf("Nfsd: openctrl unexpected state err=%d\n", 2299 error); 2300 free((caddr_t)new_lfp, M_NFSDLOCKFILE); 2301 free((caddr_t)new_open, M_NFSDSTATE); 2302 free((caddr_t)new_deleg, M_NFSDSTATE); 2303 if (haslock) { 2304 NFSLOCKV4ROOTMUTEX(); 2305 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2306 NFSUNLOCKV4ROOTMUTEX(); 2307 }
| 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), 2232 M_NFSDSTATE, M_WAITOK); 2233 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, &new_lfp, 2234 NULL, p); 2235 NFSLOCKSTATE(); 2236 /* 2237 * Get the client structure. Since the linked lists could be changed 2238 * by other nfsd processes if this process does a tsleep(), one of 2239 * two things must be done. 2240 * 1 - don't tsleep() 2241 * or 2242 * 2 - get the nfsv4_lock() { indicated by haslock == 1 } 2243 * before using the lists, since this lock stops the other 2244 * nfsd. This should only be used for rare cases, since it 2245 * essentially single threads the nfsd. 2246 * At this time, it is only done for cases where the stable 2247 * storage file must be written prior to completion of state 2248 * expiration. 2249 */ 2250 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 2251 (nfsquad_t)((u_quad_t)0), NULL, p); 2252 if (!error && (clp->lc_flags & LCL_NEEDSCBNULL) && 2253 clp->lc_program) { 2254 /* 2255 * This happens on the first open for a client 2256 * that supports callbacks. 2257 */ 2258 NFSUNLOCKSTATE(); 2259 /* 2260 * Although nfsrv_docallback() will sleep, clp won't 2261 * go away, since they are only removed when the 2262 * nfsv4_lock() has blocked the nfsd threads. The 2263 * fields in clp can change, but having multiple 2264 * threads do this Null callback RPC should be 2265 * harmless. 2266 */ 2267 cbret = nfsrv_docallback(clp, NFSV4PROC_CBNULL, 2268 NULL, 0, NULL, NULL, NULL, p); 2269 NFSLOCKSTATE(); 2270 clp->lc_flags &= ~LCL_NEEDSCBNULL; 2271 if (!cbret) 2272 clp->lc_flags |= LCL_CALLBACKSON; 2273 } 2274 2275 /* 2276 * Look up the open owner. See if it needs confirmation and 2277 * check the seq#, as required. 2278 */ 2279 if (!error) 2280 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp); 2281 2282 if (error) { 2283 NFSUNLOCKSTATE(); 2284 printf("Nfsd: openctrl unexpected state err=%d\n", 2285 error); 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 }
|
2308 return (NFSERR_EXPIRED);
| 2294 error = NFSERR_EXPIRED; 2295 goto out;
|
2309 } 2310 2311 if (new_stp->ls_flags & NFSLCK_RECLAIM) 2312 nfsrv_markstable(clp); 2313 2314 /* 2315 * Get the structure for the underlying file. 2316 */ 2317 if (getfhret) 2318 error = getfhret; 2319 else 2320 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp, 2321 NULL, 0); 2322 if (new_lfp) 2323 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2324 if (error) { 2325 NFSUNLOCKSTATE(); 2326 printf("Nfsd openctrl unexpected getlockfile err=%d\n", 2327 error); 2328 free((caddr_t)new_open, M_NFSDSTATE); 2329 free((caddr_t)new_deleg, M_NFSDSTATE); 2330 if (haslock) { 2331 NFSLOCKV4ROOTMUTEX(); 2332 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2333 NFSUNLOCKV4ROOTMUTEX(); 2334 }
| 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 */ 2304 if (getfhret) 2305 error = getfhret; 2306 else 2307 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp, 2308 NULL, 0); 2309 if (new_lfp) 2310 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE); 2311 if (error) { 2312 NFSUNLOCKSTATE(); 2313 printf("Nfsd openctrl unexpected getlockfile err=%d\n", 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 }
|
2335 return (error);
| 2322 goto out;
|
2336 } 2337 2338 /* 2339 * Search for a conflicting open/share. 2340 */ 2341 if (new_stp->ls_flags & NFSLCK_DELEGCUR) { 2342 /* 2343 * For Delegate_Cur, search for the matching Delegation, 2344 * which indicates no conflict. 2345 * An old delegation should have been recovered by the 2346 * client doing a Claim_DELEGATE_Prev, so I won't let 2347 * it match and return NFSERR_EXPIRED. Should I let it 2348 * match? 2349 */ 2350 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2351 if (!(stp->ls_flags & NFSLCK_OLDDELEG) && 2352 stateidp->seqid == stp->ls_stateid.seqid && 2353 !NFSBCMP(stateidp->other, stp->ls_stateid.other, 2354 NFSX_STATEIDOTHER)) 2355 break; 2356 } 2357 if (stp == LIST_END(&lfp->lf_deleg) || 2358 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) && 2359 (stp->ls_flags & NFSLCK_DELEGREAD))) { 2360 NFSUNLOCKSTATE(); 2361 printf("Nfsd openctrl unexpected expiry\n"); 2362 free((caddr_t)new_open, M_NFSDSTATE); 2363 free((caddr_t)new_deleg, M_NFSDSTATE); 2364 if (haslock) { 2365 NFSLOCKV4ROOTMUTEX(); 2366 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2367 NFSUNLOCKV4ROOTMUTEX(); 2368 }
| 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, 2331 * which indicates no conflict. 2332 * An old delegation should have been recovered by the 2333 * client doing a Claim_DELEGATE_Prev, so I won't let 2334 * it match and return NFSERR_EXPIRED. Should I let it 2335 * match? 2336 */ 2337 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2338 if (!(stp->ls_flags & NFSLCK_OLDDELEG) && 2339 stateidp->seqid == stp->ls_stateid.seqid && 2340 !NFSBCMP(stateidp->other, stp->ls_stateid.other, 2341 NFSX_STATEIDOTHER)) 2342 break; 2343 } 2344 if (stp == LIST_END(&lfp->lf_deleg) || 2345 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) && 2346 (stp->ls_flags & NFSLCK_DELEGREAD))) { 2347 NFSUNLOCKSTATE(); 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 }
|
2369 return (NFSERR_EXPIRED);
| 2356 error = NFSERR_EXPIRED; 2357 goto out;
|
2370 } 2371 2372 /* 2373 * Don't issue a Delegation, since one already exists and 2374 * delay delegation timeout, as required. 2375 */ 2376 delegate = 0; 2377 nfsrv_delaydelegtimeout(stp); 2378 } 2379 2380 /* 2381 * Check for access/deny bit conflicts. I also check for the 2382 * same owner, since the client might not have bothered to check. 2383 * Also, note an open for the same file and owner, if found, 2384 * which is all we do here for Delegate_Cur, since conflict 2385 * checking is already done. 2386 */ 2387 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 2388 if (ownerstp && stp->ls_openowner == ownerstp) 2389 openstp = stp; 2390 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR)) { 2391 /* 2392 * If another client has the file open, the only 2393 * delegation that can be issued is a Read delegation 2394 * and only if it is a Read open with Deny none. 2395 */ 2396 if (clp != stp->ls_clp) { 2397 if ((stp->ls_flags & NFSLCK_SHAREBITS) == 2398 NFSLCK_READACCESS) 2399 writedeleg = 0; 2400 else 2401 delegate = 0; 2402 } 2403 if(((new_stp->ls_flags & NFSLCK_ACCESSBITS) & 2404 ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))|| 2405 ((stp->ls_flags & NFSLCK_ACCESSBITS) & 2406 ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS))){ 2407 ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); 2408 if (ret == 1) { 2409 /* 2410 * nfsrv_clientconflict() unlocks state 2411 * when it returns non-zero. 2412 */ 2413 free((caddr_t)new_open, M_NFSDSTATE); 2414 free((caddr_t)new_deleg, M_NFSDSTATE); 2415 openstp = NULL; 2416 goto tryagain; 2417 } 2418 if (ret == 2) 2419 error = NFSERR_PERM; 2420 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2421 error = NFSERR_RECLAIMCONFLICT; 2422 else 2423 error = NFSERR_SHAREDENIED; 2424 if (ret == 0) 2425 NFSUNLOCKSTATE(); 2426 if (haslock) { 2427 NFSLOCKV4ROOTMUTEX(); 2428 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2429 NFSUNLOCKV4ROOTMUTEX(); 2430 } 2431 free((caddr_t)new_open, M_NFSDSTATE); 2432 free((caddr_t)new_deleg, M_NFSDSTATE); 2433 printf("nfsd openctrl unexpected client cnfl\n");
| 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); 2366 } 2367 2368 /* 2369 * Check for access/deny bit conflicts. I also check for the 2370 * same owner, since the client might not have bothered to check. 2371 * Also, note an open for the same file and owner, if found, 2372 * which is all we do here for Delegate_Cur, since conflict 2373 * checking is already done. 2374 */ 2375 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 2376 if (ownerstp && stp->ls_openowner == ownerstp) 2377 openstp = stp; 2378 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR)) { 2379 /* 2380 * If another client has the file open, the only 2381 * delegation that can be issued is a Read delegation 2382 * and only if it is a Read open with Deny none. 2383 */ 2384 if (clp != stp->ls_clp) { 2385 if ((stp->ls_flags & NFSLCK_SHAREBITS) == 2386 NFSLCK_READACCESS) 2387 writedeleg = 0; 2388 else 2389 delegate = 0; 2390 } 2391 if(((new_stp->ls_flags & NFSLCK_ACCESSBITS) & 2392 ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))|| 2393 ((stp->ls_flags & NFSLCK_ACCESSBITS) & 2394 ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS))){ 2395 ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); 2396 if (ret == 1) { 2397 /* 2398 * nfsrv_clientconflict() unlocks state 2399 * when it returns non-zero. 2400 */ 2401 free((caddr_t)new_open, M_NFSDSTATE); 2402 free((caddr_t)new_deleg, M_NFSDSTATE); 2403 openstp = NULL; 2404 goto tryagain; 2405 } 2406 if (ret == 2) 2407 error = NFSERR_PERM; 2408 else if (new_stp->ls_flags & NFSLCK_RECLAIM) 2409 error = NFSERR_RECLAIMCONFLICT; 2410 else 2411 error = NFSERR_SHAREDENIED; 2412 if (ret == 0) 2413 NFSUNLOCKSTATE(); 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");
|
2434 return (error);
| 2422 goto out;
|
2435 } 2436 } 2437 } 2438 2439 /* 2440 * Check for a conflicting delegation. If one is found, call 2441 * nfsrv_delegconflict() to handle it. If the v4root lock hasn't 2442 * been set yet, it will get the lock. Otherwise, it will recall 2443 * the delegation. Then, we try try again... 2444 * (If NFSLCK_DELEGCUR is set, it has a delegation, so there 2445 * isn't a conflict.) 2446 * I currently believe the conflict algorithm to be: 2447 * For Open with Read Access and Deny None 2448 * - there is a conflict iff a different client has a write delegation 2449 * For Open with other Write Access or any Deny except None 2450 * - there is a conflict if a different client has any delegation 2451 * - there is a conflict if the same client has a read delegation 2452 * (The current concensus is that this last case should be 2453 * considered a conflict since the client with a read delegation 2454 * could have done an Open with ReadAccess and WriteDeny 2455 * locally and then not have checked for the WriteDeny.) 2456 */ 2457 if (!(new_stp->ls_flags & (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR))) { 2458 stp = LIST_FIRST(&lfp->lf_deleg); 2459 while (stp != LIST_END(&lfp->lf_deleg)) { 2460 nstp = LIST_NEXT(stp, ls_file); 2461 if (stp->ls_clp != clp && (stp->ls_flags & NFSLCK_DELEGREAD)) 2462 writedeleg = 0; 2463 else 2464 delegate = 0; 2465 if ((readonly && stp->ls_clp != clp && 2466 (stp->ls_flags & NFSLCK_DELEGWRITE)) || 2467 (!readonly && (stp->ls_clp != clp || 2468 (stp->ls_flags & NFSLCK_DELEGREAD)))) { 2469 if (new_stp->ls_flags & NFSLCK_RECLAIM) { 2470 delegate = 2; 2471 } else { 2472 ret = nfsrv_delegconflict(stp, &haslock, p, vp); 2473 if (ret) { 2474 /* 2475 * nfsrv_delegconflict() unlocks state 2476 * when it returns non-zero. 2477 */ 2478 printf("Nfsd openctrl unexpected deleg cnfl\n"); 2479 free((caddr_t)new_open, M_NFSDSTATE); 2480 free((caddr_t)new_deleg, M_NFSDSTATE); 2481 if (ret == -1) { 2482 openstp = NULL; 2483 goto tryagain; 2484 }
| 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 2431 * the delegation. Then, we try try again... 2432 * (If NFSLCK_DELEGCUR is set, it has a delegation, so there 2433 * isn't a conflict.) 2434 * I currently believe the conflict algorithm to be: 2435 * For Open with Read Access and Deny None 2436 * - there is a conflict iff a different client has a write delegation 2437 * For Open with other Write Access or any Deny except None 2438 * - there is a conflict if a different client has any delegation 2439 * - there is a conflict if the same client has a read delegation 2440 * (The current concensus is that this last case should be 2441 * considered a conflict since the client with a read delegation 2442 * could have done an Open with ReadAccess and WriteDeny 2443 * locally and then not have checked for the WriteDeny.) 2444 */ 2445 if (!(new_stp->ls_flags & (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR))) { 2446 stp = LIST_FIRST(&lfp->lf_deleg); 2447 while (stp != LIST_END(&lfp->lf_deleg)) { 2448 nstp = LIST_NEXT(stp, ls_file); 2449 if (stp->ls_clp != clp && (stp->ls_flags & NFSLCK_DELEGREAD)) 2450 writedeleg = 0; 2451 else 2452 delegate = 0; 2453 if ((readonly && stp->ls_clp != clp && 2454 (stp->ls_flags & NFSLCK_DELEGWRITE)) || 2455 (!readonly && (stp->ls_clp != clp || 2456 (stp->ls_flags & NFSLCK_DELEGREAD)))) { 2457 if (new_stp->ls_flags & NFSLCK_RECLAIM) { 2458 delegate = 2; 2459 } else { 2460 ret = nfsrv_delegconflict(stp, &haslock, p, vp); 2461 if (ret) { 2462 /* 2463 * nfsrv_delegconflict() unlocks state 2464 * when it returns non-zero. 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 }
|
2485 return (ret);
| 2473 error = ret; 2474 goto out;
|
2486 } 2487 } 2488 } 2489 stp = nstp; 2490 } 2491 } 2492 2493 /* 2494 * We only get here if there was no open that conflicted. 2495 * If an open for the owner exists, or in the access/deny bits. 2496 * Otherwise it is a new open. If the open_owner hasn't been 2497 * confirmed, replace the open with the new one needing confirmation, 2498 * otherwise add the open. 2499 */ 2500 if (new_stp->ls_flags & NFSLCK_DELEGPREV) { 2501 /* 2502 * Handle NFSLCK_DELEGPREV by searching the old delegations for 2503 * a match. If found, just move the old delegation to the current 2504 * delegation list and issue open. If not found, return 2505 * NFSERR_EXPIRED. 2506 */ 2507 LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) { 2508 if (stp->ls_lfp == lfp) { 2509 /* Found it */ 2510 if (stp->ls_clp != clp) 2511 panic("olddeleg clp"); 2512 LIST_REMOVE(stp, ls_list); 2513 LIST_REMOVE(stp, ls_hash); 2514 stp->ls_flags &= ~NFSLCK_OLDDELEG; 2515 stp->ls_stateid.seqid = delegstateidp->seqid = 0; 2516 stp->ls_stateid.other[0] = delegstateidp->other[0] = 2517 clp->lc_clientid.lval[0]; 2518 stp->ls_stateid.other[1] = delegstateidp->other[1] = 2519 clp->lc_clientid.lval[1]; 2520 stp->ls_stateid.other[2] = delegstateidp->other[2] = 2521 nfsrv_nextstateindex(clp); 2522 stp->ls_compref = nd->nd_compref; 2523 LIST_INSERT_HEAD(&clp->lc_deleg, stp, ls_list); 2524 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2525 stp->ls_stateid), stp, ls_hash); 2526 if (stp->ls_flags & NFSLCK_DELEGWRITE) 2527 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2528 else 2529 *rflagsp |= NFSV4OPEN_READDELEGATE; 2530 clp->lc_delegtime = NFSD_MONOSEC + 2531 nfsrv_lease + NFSRV_LEASEDELTA; 2532 2533 /* 2534 * Now, do the associated open. 2535 */ 2536 new_open->ls_stateid.seqid = 0; 2537 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2538 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2539 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2540 new_open->ls_flags = (new_stp->ls_flags&NFSLCK_DENYBITS)| 2541 NFSLCK_OPEN; 2542 if (stp->ls_flags & NFSLCK_DELEGWRITE) 2543 new_open->ls_flags |= (NFSLCK_READACCESS | 2544 NFSLCK_WRITEACCESS); 2545 else 2546 new_open->ls_flags |= NFSLCK_READACCESS; 2547 new_open->ls_uid = new_stp->ls_uid; 2548 new_open->ls_lfp = lfp; 2549 new_open->ls_clp = clp; 2550 LIST_INIT(&new_open->ls_open); 2551 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2552 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2553 new_open, ls_hash); 2554 /* 2555 * and handle the open owner 2556 */ 2557 if (ownerstp) { 2558 new_open->ls_openowner = ownerstp; 2559 LIST_INSERT_HEAD(&ownerstp->ls_open,new_open,ls_list); 2560 } else { 2561 new_open->ls_openowner = new_stp; 2562 new_stp->ls_flags = 0; 2563 nfsrvd_refcache(new_stp->ls_op); 2564 new_stp->ls_noopens = 0; 2565 LIST_INIT(&new_stp->ls_open); 2566 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2567 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2568 *new_stpp = NULL; 2569 newnfsstats.srvopenowners++; 2570 nfsrv_openpluslock++; 2571 } 2572 openstp = new_open; 2573 new_open = NULL; 2574 newnfsstats.srvopens++; 2575 nfsrv_openpluslock++; 2576 break; 2577 } 2578 } 2579 if (stp == LIST_END(&clp->lc_olddeleg)) 2580 error = NFSERR_EXPIRED; 2581 } else if (new_stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) { 2582 /* 2583 * Scan to see that no delegation for this client and file 2584 * doesn't already exist. 2585 * There also shouldn't yet be an Open for this file and 2586 * openowner. 2587 */ 2588 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2589 if (stp->ls_clp == clp) 2590 break; 2591 } 2592 if (stp == LIST_END(&lfp->lf_deleg) && openstp == NULL) { 2593 /* 2594 * This is the Claim_Previous case with a delegation 2595 * type != Delegate_None. 2596 */ 2597 /* 2598 * First, add the delegation. (Although we must issue the 2599 * delegation, we can also ask for an immediate return.) 2600 */ 2601 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0; 2602 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] = 2603 clp->lc_clientid.lval[0]; 2604 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] = 2605 clp->lc_clientid.lval[1]; 2606 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] = 2607 nfsrv_nextstateindex(clp); 2608 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) { 2609 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2610 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2611 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2612 } else { 2613 new_deleg->ls_flags = (NFSLCK_DELEGREAD | 2614 NFSLCK_READACCESS); 2615 *rflagsp |= NFSV4OPEN_READDELEGATE; 2616 } 2617 new_deleg->ls_uid = new_stp->ls_uid; 2618 new_deleg->ls_lfp = lfp; 2619 new_deleg->ls_clp = clp; 2620 new_deleg->ls_filerev = filerev; 2621 new_deleg->ls_compref = nd->nd_compref; 2622 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2623 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2624 new_deleg->ls_stateid), new_deleg, ls_hash); 2625 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2626 new_deleg = NULL; 2627 if (delegate == 2 || nfsrv_issuedelegs == 0 || 2628 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != 2629 LCL_CALLBACKSON || 2630 NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) || 2631 !NFSVNO_DELEGOK(vp)) 2632 *rflagsp |= NFSV4OPEN_RECALL; 2633 newnfsstats.srvdelegates++; 2634 nfsrv_openpluslock++; 2635 nfsrv_delegatecnt++; 2636 2637 /* 2638 * Now, do the associated open. 2639 */ 2640 new_open->ls_stateid.seqid = 0; 2641 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2642 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2643 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2644 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_DENYBITS) | 2645 NFSLCK_OPEN; 2646 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) 2647 new_open->ls_flags |= (NFSLCK_READACCESS | 2648 NFSLCK_WRITEACCESS); 2649 else 2650 new_open->ls_flags |= NFSLCK_READACCESS; 2651 new_open->ls_uid = new_stp->ls_uid; 2652 new_open->ls_lfp = lfp; 2653 new_open->ls_clp = clp; 2654 LIST_INIT(&new_open->ls_open); 2655 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2656 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2657 new_open, ls_hash); 2658 /* 2659 * and handle the open owner 2660 */ 2661 if (ownerstp) { 2662 new_open->ls_openowner = ownerstp; 2663 LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list); 2664 } else { 2665 new_open->ls_openowner = new_stp; 2666 new_stp->ls_flags = 0; 2667 nfsrvd_refcache(new_stp->ls_op); 2668 new_stp->ls_noopens = 0; 2669 LIST_INIT(&new_stp->ls_open); 2670 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2671 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2672 *new_stpp = NULL; 2673 newnfsstats.srvopenowners++; 2674 nfsrv_openpluslock++; 2675 } 2676 openstp = new_open; 2677 new_open = NULL; 2678 newnfsstats.srvopens++; 2679 nfsrv_openpluslock++; 2680 } else { 2681 error = NFSERR_RECLAIMCONFLICT; 2682 } 2683 } else if (ownerstp) { 2684 if (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM) { 2685 /* Replace the open */ 2686 if (ownerstp->ls_op) 2687 nfsrvd_derefcache(ownerstp->ls_op); 2688 ownerstp->ls_op = new_stp->ls_op; 2689 nfsrvd_refcache(ownerstp->ls_op); 2690 ownerstp->ls_seq = new_stp->ls_seq; 2691 *rflagsp |= NFSV4OPEN_RESULTCONFIRM; 2692 stp = LIST_FIRST(&ownerstp->ls_open); 2693 stp->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) | 2694 NFSLCK_OPEN; 2695 stp->ls_stateid.seqid = 0; 2696 stp->ls_uid = new_stp->ls_uid; 2697 if (lfp != stp->ls_lfp) { 2698 LIST_REMOVE(stp, ls_file); 2699 LIST_INSERT_HEAD(&lfp->lf_open, stp, ls_file); 2700 stp->ls_lfp = lfp; 2701 } 2702 openstp = stp; 2703 } else if (openstp) { 2704 openstp->ls_flags |= (new_stp->ls_flags & NFSLCK_SHAREBITS); 2705 openstp->ls_stateid.seqid++; 2706 2707 /* 2708 * This is where we can choose to issue a delegation. 2709 */ 2710 if (delegate && nfsrv_issuedelegs && 2711 writedeleg && !NFSVNO_EXRDONLY(exp) && 2712 (nfsrv_writedelegifpos || !readonly) && 2713 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) == 2714 LCL_CALLBACKSON && 2715 !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) && 2716 NFSVNO_DELEGOK(vp)) { 2717 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0; 2718 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] 2719 = clp->lc_clientid.lval[0]; 2720 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] 2721 = clp->lc_clientid.lval[1]; 2722 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] 2723 = nfsrv_nextstateindex(clp); 2724 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2725 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2726 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2727 new_deleg->ls_uid = new_stp->ls_uid; 2728 new_deleg->ls_lfp = lfp; 2729 new_deleg->ls_clp = clp; 2730 new_deleg->ls_filerev = filerev; 2731 new_deleg->ls_compref = nd->nd_compref; 2732 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2733 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2734 new_deleg->ls_stateid), new_deleg, ls_hash); 2735 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2736 new_deleg = NULL; 2737 newnfsstats.srvdelegates++; 2738 nfsrv_openpluslock++; 2739 nfsrv_delegatecnt++; 2740 } 2741 } else { 2742 new_open->ls_stateid.seqid = 0; 2743 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2744 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2745 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2746 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS)| 2747 NFSLCK_OPEN; 2748 new_open->ls_uid = new_stp->ls_uid; 2749 new_open->ls_openowner = ownerstp; 2750 new_open->ls_lfp = lfp; 2751 new_open->ls_clp = clp; 2752 LIST_INIT(&new_open->ls_open); 2753 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2754 LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list); 2755 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2756 new_open, ls_hash); 2757 openstp = new_open; 2758 new_open = NULL; 2759 newnfsstats.srvopens++; 2760 nfsrv_openpluslock++; 2761 2762 /* 2763 * This is where we can choose to issue a delegation. 2764 */ 2765 if (delegate && nfsrv_issuedelegs && 2766 (writedeleg || readonly) && 2767 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) == 2768 LCL_CALLBACKSON && 2769 !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) && 2770 NFSVNO_DELEGOK(vp)) { 2771 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0; 2772 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] 2773 = clp->lc_clientid.lval[0]; 2774 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] 2775 = clp->lc_clientid.lval[1]; 2776 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] 2777 = nfsrv_nextstateindex(clp); 2778 if (writedeleg && !NFSVNO_EXRDONLY(exp) && 2779 (nfsrv_writedelegifpos || !readonly)) { 2780 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2781 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2782 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2783 } else { 2784 new_deleg->ls_flags = (NFSLCK_DELEGREAD | 2785 NFSLCK_READACCESS); 2786 *rflagsp |= NFSV4OPEN_READDELEGATE; 2787 } 2788 new_deleg->ls_uid = new_stp->ls_uid; 2789 new_deleg->ls_lfp = lfp; 2790 new_deleg->ls_clp = clp; 2791 new_deleg->ls_filerev = filerev; 2792 new_deleg->ls_compref = nd->nd_compref; 2793 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2794 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2795 new_deleg->ls_stateid), new_deleg, ls_hash); 2796 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2797 new_deleg = NULL; 2798 newnfsstats.srvdelegates++; 2799 nfsrv_openpluslock++; 2800 nfsrv_delegatecnt++; 2801 } 2802 } 2803 } else { 2804 /* 2805 * New owner case. Start the open_owner sequence with a 2806 * Needs confirmation (unless a reclaim) and hang the 2807 * new open off it. 2808 */ 2809 new_open->ls_stateid.seqid = 0; 2810 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2811 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2812 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2813 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) | 2814 NFSLCK_OPEN; 2815 new_open->ls_uid = new_stp->ls_uid; 2816 LIST_INIT(&new_open->ls_open); 2817 new_open->ls_openowner = new_stp; 2818 new_open->ls_lfp = lfp; 2819 new_open->ls_clp = clp; 2820 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2821 if (new_stp->ls_flags & NFSLCK_RECLAIM) { 2822 new_stp->ls_flags = 0; 2823 } else { 2824 *rflagsp |= NFSV4OPEN_RESULTCONFIRM; 2825 new_stp->ls_flags = NFSLCK_NEEDSCONFIRM; 2826 } 2827 nfsrvd_refcache(new_stp->ls_op); 2828 new_stp->ls_noopens = 0; 2829 LIST_INIT(&new_stp->ls_open); 2830 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2831 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2832 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2833 new_open, ls_hash); 2834 openstp = new_open; 2835 new_open = NULL; 2836 *new_stpp = NULL; 2837 newnfsstats.srvopens++; 2838 nfsrv_openpluslock++; 2839 newnfsstats.srvopenowners++; 2840 nfsrv_openpluslock++; 2841 } 2842 if (!error) { 2843 stateidp->seqid = openstp->ls_stateid.seqid; 2844 stateidp->other[0] = openstp->ls_stateid.other[0]; 2845 stateidp->other[1] = openstp->ls_stateid.other[1]; 2846 stateidp->other[2] = openstp->ls_stateid.other[2]; 2847 } 2848 NFSUNLOCKSTATE(); 2849 if (haslock) { 2850 NFSLOCKV4ROOTMUTEX(); 2851 nfsv4_unlock(&nfsv4rootfs_lock, 1); 2852 NFSUNLOCKV4ROOTMUTEX(); 2853 } 2854 if (new_open) 2855 FREE((caddr_t)new_open, M_NFSDSTATE); 2856 if (new_deleg) 2857 FREE((caddr_t)new_deleg, M_NFSDSTATE);
| 2475 } 2476 } 2477 } 2478 stp = nstp; 2479 } 2480 } 2481 2482 /* 2483 * We only get here if there was no open that conflicted. 2484 * If an open for the owner exists, or in the access/deny bits. 2485 * Otherwise it is a new open. If the open_owner hasn't been 2486 * confirmed, replace the open with the new one needing confirmation, 2487 * otherwise add the open. 2488 */ 2489 if (new_stp->ls_flags & NFSLCK_DELEGPREV) { 2490 /* 2491 * Handle NFSLCK_DELEGPREV by searching the old delegations for 2492 * a match. If found, just move the old delegation to the current 2493 * delegation list and issue open. If not found, return 2494 * NFSERR_EXPIRED. 2495 */ 2496 LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) { 2497 if (stp->ls_lfp == lfp) { 2498 /* Found it */ 2499 if (stp->ls_clp != clp) 2500 panic("olddeleg clp"); 2501 LIST_REMOVE(stp, ls_list); 2502 LIST_REMOVE(stp, ls_hash); 2503 stp->ls_flags &= ~NFSLCK_OLDDELEG; 2504 stp->ls_stateid.seqid = delegstateidp->seqid = 0; 2505 stp->ls_stateid.other[0] = delegstateidp->other[0] = 2506 clp->lc_clientid.lval[0]; 2507 stp->ls_stateid.other[1] = delegstateidp->other[1] = 2508 clp->lc_clientid.lval[1]; 2509 stp->ls_stateid.other[2] = delegstateidp->other[2] = 2510 nfsrv_nextstateindex(clp); 2511 stp->ls_compref = nd->nd_compref; 2512 LIST_INSERT_HEAD(&clp->lc_deleg, stp, ls_list); 2513 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2514 stp->ls_stateid), stp, ls_hash); 2515 if (stp->ls_flags & NFSLCK_DELEGWRITE) 2516 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2517 else 2518 *rflagsp |= NFSV4OPEN_READDELEGATE; 2519 clp->lc_delegtime = NFSD_MONOSEC + 2520 nfsrv_lease + NFSRV_LEASEDELTA; 2521 2522 /* 2523 * Now, do the associated open. 2524 */ 2525 new_open->ls_stateid.seqid = 0; 2526 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2527 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2528 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2529 new_open->ls_flags = (new_stp->ls_flags&NFSLCK_DENYBITS)| 2530 NFSLCK_OPEN; 2531 if (stp->ls_flags & NFSLCK_DELEGWRITE) 2532 new_open->ls_flags |= (NFSLCK_READACCESS | 2533 NFSLCK_WRITEACCESS); 2534 else 2535 new_open->ls_flags |= NFSLCK_READACCESS; 2536 new_open->ls_uid = new_stp->ls_uid; 2537 new_open->ls_lfp = lfp; 2538 new_open->ls_clp = clp; 2539 LIST_INIT(&new_open->ls_open); 2540 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2541 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2542 new_open, ls_hash); 2543 /* 2544 * and handle the open owner 2545 */ 2546 if (ownerstp) { 2547 new_open->ls_openowner = ownerstp; 2548 LIST_INSERT_HEAD(&ownerstp->ls_open,new_open,ls_list); 2549 } else { 2550 new_open->ls_openowner = new_stp; 2551 new_stp->ls_flags = 0; 2552 nfsrvd_refcache(new_stp->ls_op); 2553 new_stp->ls_noopens = 0; 2554 LIST_INIT(&new_stp->ls_open); 2555 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2556 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2557 *new_stpp = NULL; 2558 newnfsstats.srvopenowners++; 2559 nfsrv_openpluslock++; 2560 } 2561 openstp = new_open; 2562 new_open = NULL; 2563 newnfsstats.srvopens++; 2564 nfsrv_openpluslock++; 2565 break; 2566 } 2567 } 2568 if (stp == LIST_END(&clp->lc_olddeleg)) 2569 error = NFSERR_EXPIRED; 2570 } else if (new_stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) { 2571 /* 2572 * Scan to see that no delegation for this client and file 2573 * doesn't already exist. 2574 * There also shouldn't yet be an Open for this file and 2575 * openowner. 2576 */ 2577 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 2578 if (stp->ls_clp == clp) 2579 break; 2580 } 2581 if (stp == LIST_END(&lfp->lf_deleg) && openstp == NULL) { 2582 /* 2583 * This is the Claim_Previous case with a delegation 2584 * type != Delegate_None. 2585 */ 2586 /* 2587 * First, add the delegation. (Although we must issue the 2588 * delegation, we can also ask for an immediate return.) 2589 */ 2590 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0; 2591 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] = 2592 clp->lc_clientid.lval[0]; 2593 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] = 2594 clp->lc_clientid.lval[1]; 2595 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] = 2596 nfsrv_nextstateindex(clp); 2597 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) { 2598 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2599 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2600 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2601 } else { 2602 new_deleg->ls_flags = (NFSLCK_DELEGREAD | 2603 NFSLCK_READACCESS); 2604 *rflagsp |= NFSV4OPEN_READDELEGATE; 2605 } 2606 new_deleg->ls_uid = new_stp->ls_uid; 2607 new_deleg->ls_lfp = lfp; 2608 new_deleg->ls_clp = clp; 2609 new_deleg->ls_filerev = filerev; 2610 new_deleg->ls_compref = nd->nd_compref; 2611 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2612 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2613 new_deleg->ls_stateid), new_deleg, ls_hash); 2614 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2615 new_deleg = NULL; 2616 if (delegate == 2 || nfsrv_issuedelegs == 0 || 2617 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) != 2618 LCL_CALLBACKSON || 2619 NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) || 2620 !NFSVNO_DELEGOK(vp)) 2621 *rflagsp |= NFSV4OPEN_RECALL; 2622 newnfsstats.srvdelegates++; 2623 nfsrv_openpluslock++; 2624 nfsrv_delegatecnt++; 2625 2626 /* 2627 * Now, do the associated open. 2628 */ 2629 new_open->ls_stateid.seqid = 0; 2630 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2631 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2632 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2633 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_DENYBITS) | 2634 NFSLCK_OPEN; 2635 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) 2636 new_open->ls_flags |= (NFSLCK_READACCESS | 2637 NFSLCK_WRITEACCESS); 2638 else 2639 new_open->ls_flags |= NFSLCK_READACCESS; 2640 new_open->ls_uid = new_stp->ls_uid; 2641 new_open->ls_lfp = lfp; 2642 new_open->ls_clp = clp; 2643 LIST_INIT(&new_open->ls_open); 2644 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2645 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2646 new_open, ls_hash); 2647 /* 2648 * and handle the open owner 2649 */ 2650 if (ownerstp) { 2651 new_open->ls_openowner = ownerstp; 2652 LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list); 2653 } else { 2654 new_open->ls_openowner = new_stp; 2655 new_stp->ls_flags = 0; 2656 nfsrvd_refcache(new_stp->ls_op); 2657 new_stp->ls_noopens = 0; 2658 LIST_INIT(&new_stp->ls_open); 2659 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2660 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2661 *new_stpp = NULL; 2662 newnfsstats.srvopenowners++; 2663 nfsrv_openpluslock++; 2664 } 2665 openstp = new_open; 2666 new_open = NULL; 2667 newnfsstats.srvopens++; 2668 nfsrv_openpluslock++; 2669 } else { 2670 error = NFSERR_RECLAIMCONFLICT; 2671 } 2672 } else if (ownerstp) { 2673 if (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM) { 2674 /* Replace the open */ 2675 if (ownerstp->ls_op) 2676 nfsrvd_derefcache(ownerstp->ls_op); 2677 ownerstp->ls_op = new_stp->ls_op; 2678 nfsrvd_refcache(ownerstp->ls_op); 2679 ownerstp->ls_seq = new_stp->ls_seq; 2680 *rflagsp |= NFSV4OPEN_RESULTCONFIRM; 2681 stp = LIST_FIRST(&ownerstp->ls_open); 2682 stp->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) | 2683 NFSLCK_OPEN; 2684 stp->ls_stateid.seqid = 0; 2685 stp->ls_uid = new_stp->ls_uid; 2686 if (lfp != stp->ls_lfp) { 2687 LIST_REMOVE(stp, ls_file); 2688 LIST_INSERT_HEAD(&lfp->lf_open, stp, ls_file); 2689 stp->ls_lfp = lfp; 2690 } 2691 openstp = stp; 2692 } else if (openstp) { 2693 openstp->ls_flags |= (new_stp->ls_flags & NFSLCK_SHAREBITS); 2694 openstp->ls_stateid.seqid++; 2695 2696 /* 2697 * This is where we can choose to issue a delegation. 2698 */ 2699 if (delegate && nfsrv_issuedelegs && 2700 writedeleg && !NFSVNO_EXRDONLY(exp) && 2701 (nfsrv_writedelegifpos || !readonly) && 2702 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) == 2703 LCL_CALLBACKSON && 2704 !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) && 2705 NFSVNO_DELEGOK(vp)) { 2706 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0; 2707 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] 2708 = clp->lc_clientid.lval[0]; 2709 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] 2710 = clp->lc_clientid.lval[1]; 2711 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] 2712 = nfsrv_nextstateindex(clp); 2713 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2714 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2715 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2716 new_deleg->ls_uid = new_stp->ls_uid; 2717 new_deleg->ls_lfp = lfp; 2718 new_deleg->ls_clp = clp; 2719 new_deleg->ls_filerev = filerev; 2720 new_deleg->ls_compref = nd->nd_compref; 2721 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2722 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2723 new_deleg->ls_stateid), new_deleg, ls_hash); 2724 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2725 new_deleg = NULL; 2726 newnfsstats.srvdelegates++; 2727 nfsrv_openpluslock++; 2728 nfsrv_delegatecnt++; 2729 } 2730 } else { 2731 new_open->ls_stateid.seqid = 0; 2732 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2733 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2734 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2735 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS)| 2736 NFSLCK_OPEN; 2737 new_open->ls_uid = new_stp->ls_uid; 2738 new_open->ls_openowner = ownerstp; 2739 new_open->ls_lfp = lfp; 2740 new_open->ls_clp = clp; 2741 LIST_INIT(&new_open->ls_open); 2742 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2743 LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list); 2744 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2745 new_open, ls_hash); 2746 openstp = new_open; 2747 new_open = NULL; 2748 newnfsstats.srvopens++; 2749 nfsrv_openpluslock++; 2750 2751 /* 2752 * This is where we can choose to issue a delegation. 2753 */ 2754 if (delegate && nfsrv_issuedelegs && 2755 (writedeleg || readonly) && 2756 (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) == 2757 LCL_CALLBACKSON && 2758 !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) && 2759 NFSVNO_DELEGOK(vp)) { 2760 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 0; 2761 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] 2762 = clp->lc_clientid.lval[0]; 2763 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] 2764 = clp->lc_clientid.lval[1]; 2765 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] 2766 = nfsrv_nextstateindex(clp); 2767 if (writedeleg && !NFSVNO_EXRDONLY(exp) && 2768 (nfsrv_writedelegifpos || !readonly)) { 2769 new_deleg->ls_flags = (NFSLCK_DELEGWRITE | 2770 NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2771 *rflagsp |= NFSV4OPEN_WRITEDELEGATE; 2772 } else { 2773 new_deleg->ls_flags = (NFSLCK_DELEGREAD | 2774 NFSLCK_READACCESS); 2775 *rflagsp |= NFSV4OPEN_READDELEGATE; 2776 } 2777 new_deleg->ls_uid = new_stp->ls_uid; 2778 new_deleg->ls_lfp = lfp; 2779 new_deleg->ls_clp = clp; 2780 new_deleg->ls_filerev = filerev; 2781 new_deleg->ls_compref = nd->nd_compref; 2782 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file); 2783 LIST_INSERT_HEAD(NFSSTATEHASH(clp, 2784 new_deleg->ls_stateid), new_deleg, ls_hash); 2785 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list); 2786 new_deleg = NULL; 2787 newnfsstats.srvdelegates++; 2788 nfsrv_openpluslock++; 2789 nfsrv_delegatecnt++; 2790 } 2791 } 2792 } else { 2793 /* 2794 * New owner case. Start the open_owner sequence with a 2795 * Needs confirmation (unless a reclaim) and hang the 2796 * new open off it. 2797 */ 2798 new_open->ls_stateid.seqid = 0; 2799 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0]; 2800 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1]; 2801 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp); 2802 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) | 2803 NFSLCK_OPEN; 2804 new_open->ls_uid = new_stp->ls_uid; 2805 LIST_INIT(&new_open->ls_open); 2806 new_open->ls_openowner = new_stp; 2807 new_open->ls_lfp = lfp; 2808 new_open->ls_clp = clp; 2809 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file); 2810 if (new_stp->ls_flags & NFSLCK_RECLAIM) { 2811 new_stp->ls_flags = 0; 2812 } else { 2813 *rflagsp |= NFSV4OPEN_RESULTCONFIRM; 2814 new_stp->ls_flags = NFSLCK_NEEDSCONFIRM; 2815 } 2816 nfsrvd_refcache(new_stp->ls_op); 2817 new_stp->ls_noopens = 0; 2818 LIST_INIT(&new_stp->ls_open); 2819 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list); 2820 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list); 2821 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid), 2822 new_open, ls_hash); 2823 openstp = new_open; 2824 new_open = NULL; 2825 *new_stpp = NULL; 2826 newnfsstats.srvopens++; 2827 nfsrv_openpluslock++; 2828 newnfsstats.srvopenowners++; 2829 nfsrv_openpluslock++; 2830 } 2831 if (!error) { 2832 stateidp->seqid = openstp->ls_stateid.seqid; 2833 stateidp->other[0] = openstp->ls_stateid.other[0]; 2834 stateidp->other[1] = openstp->ls_stateid.other[1]; 2835 stateidp->other[2] = openstp->ls_stateid.other[2]; 2836 } 2837 NFSUNLOCKSTATE(); 2838 if (haslock) { 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);
|
2858 return (error); 2859} 2860 2861/* 2862 * Open update. Does the confirm, downgrade and close. 2863 */ 2864APPLESTATIC int 2865nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid, 2866 nfsv4stateid_t *stateidp, struct nfsrv_descript *nd, NFSPROC_T *p) 2867{ 2868 struct nfsstate *stp, *ownerstp; 2869 struct nfsclient *clp; 2870 struct nfslockfile *lfp; 2871 u_int32_t bits;
| 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;
|
2872 int error, gotstate = 0, len = 0;
| 2864 int error = 0, gotstate = 0, len = 0;
|
2873 u_char client[NFSV4_OPAQUELIMIT]; 2874 2875 /* 2876 * Check for restart conditions (client and server). 2877 */ 2878 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 2879 &new_stp->ls_stateid, 0); 2880 if (error)
| 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)
|
2881 return (error);
| 2873 goto out;
|
2882 2883 NFSLOCKSTATE(); 2884 /* 2885 * Get the open structure via clientid and stateid. 2886 */ 2887 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 2888 (nfsquad_t)((u_quad_t)0), NULL, p); 2889 if (!error) 2890 error = nfsrv_getstate(clp, &new_stp->ls_stateid, 2891 new_stp->ls_flags, &stp); 2892 2893 /* 2894 * Sanity check the open. 2895 */ 2896 if (!error && (!(stp->ls_flags & NFSLCK_OPEN) || 2897 (!(new_stp->ls_flags & NFSLCK_CONFIRM) && 2898 (stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) || 2899 ((new_stp->ls_flags & NFSLCK_CONFIRM) && 2900 (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM))))) 2901 error = NFSERR_BADSTATEID; 2902 2903 if (!error) 2904 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 2905 stp->ls_openowner, new_stp->ls_op); 2906 if (!error && stp->ls_stateid.seqid != new_stp->ls_stateid.seqid && 2907 !(new_stp->ls_flags & NFSLCK_CONFIRM)) 2908 error = NFSERR_OLDSTATEID; 2909 if (!error && vnode_vtype(vp) != VREG) { 2910 if (vnode_vtype(vp) == VDIR) 2911 error = NFSERR_ISDIR; 2912 else 2913 error = NFSERR_INVAL; 2914 } 2915 2916 if (error) { 2917 /* 2918 * If a client tries to confirm an Open with a bad 2919 * seqid# and there are no byte range locks or other Opens 2920 * on the openowner, just throw it away, so the next use of the 2921 * openowner will start a fresh seq#. 2922 */ 2923 if (error == NFSERR_BADSEQID && 2924 (new_stp->ls_flags & NFSLCK_CONFIRM) && 2925 nfsrv_nootherstate(stp)) 2926 nfsrv_freeopenowner(stp->ls_openowner, 0, p); 2927 NFSUNLOCKSTATE();
| 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) 2882 error = nfsrv_getstate(clp, &new_stp->ls_stateid, 2883 new_stp->ls_flags, &stp); 2884 2885 /* 2886 * Sanity check the open. 2887 */ 2888 if (!error && (!(stp->ls_flags & NFSLCK_OPEN) || 2889 (!(new_stp->ls_flags & NFSLCK_CONFIRM) && 2890 (stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) || 2891 ((new_stp->ls_flags & NFSLCK_CONFIRM) && 2892 (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM))))) 2893 error = NFSERR_BADSTATEID; 2894 2895 if (!error) 2896 error = nfsrv_checkseqid(nd, new_stp->ls_seq, 2897 stp->ls_openowner, new_stp->ls_op); 2898 if (!error && stp->ls_stateid.seqid != new_stp->ls_stateid.seqid && 2899 !(new_stp->ls_flags & NFSLCK_CONFIRM)) 2900 error = NFSERR_OLDSTATEID; 2901 if (!error && vnode_vtype(vp) != VREG) { 2902 if (vnode_vtype(vp) == VDIR) 2903 error = NFSERR_ISDIR; 2904 else 2905 error = NFSERR_INVAL; 2906 } 2907 2908 if (error) { 2909 /* 2910 * If a client tries to confirm an Open with a bad 2911 * seqid# and there are no byte range locks or other Opens 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();
|
2928 return (error);
| 2920 goto out;
|
2929 } 2930 2931 /* 2932 * Set the return stateid. 2933 */ 2934 stateidp->seqid = stp->ls_stateid.seqid + 1; 2935 stateidp->other[0] = stp->ls_stateid.other[0]; 2936 stateidp->other[1] = stp->ls_stateid.other[1]; 2937 stateidp->other[2] = stp->ls_stateid.other[2]; 2938 /* 2939 * Now, handle the three cases. 2940 */ 2941 if (new_stp->ls_flags & NFSLCK_CONFIRM) { 2942 /* 2943 * If the open doesn't need confirmation, it seems to me that 2944 * there is a client error, but I'll just log it and keep going? 2945 */ 2946 if (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) 2947 printf("Nfsv4d: stray open confirm\n"); 2948 stp->ls_openowner->ls_flags = 0; 2949 stp->ls_stateid.seqid++; 2950 if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) { 2951 clp->lc_flags |= LCL_STAMPEDSTABLE; 2952 len = clp->lc_idlen; 2953 NFSBCOPY(clp->lc_id, client, len); 2954 gotstate = 1; 2955 } 2956 NFSUNLOCKSTATE(); 2957 } else if (new_stp->ls_flags & NFSLCK_CLOSE) { 2958 ownerstp = stp->ls_openowner; 2959 lfp = stp->ls_lfp; 2960 if (nfsrv_dolocallocks != 0 && !LIST_EMPTY(&stp->ls_open)) { 2961 /* Get the lf lock */ 2962 nfsrv_locklf(lfp); 2963 NFSUNLOCKSTATE(); 2964 if (nfsrv_freeopen(stp, vp, 1, p) == 0) { 2965 NFSLOCKSTATE(); 2966 nfsrv_unlocklf(lfp); 2967 NFSUNLOCKSTATE(); 2968 } 2969 } else { 2970 (void) nfsrv_freeopen(stp, NULL, 0, p); 2971 NFSUNLOCKSTATE(); 2972 } 2973 } else { 2974 /* 2975 * Update the share bits, making sure that the new set are a 2976 * subset of the old ones. 2977 */ 2978 bits = (new_stp->ls_flags & NFSLCK_SHAREBITS); 2979 if (~(stp->ls_flags) & bits) { 2980 NFSUNLOCKSTATE();
| 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]; 2929 stateidp->other[2] = stp->ls_stateid.other[2]; 2930 /* 2931 * Now, handle the three cases. 2932 */ 2933 if (new_stp->ls_flags & NFSLCK_CONFIRM) { 2934 /* 2935 * If the open doesn't need confirmation, it seems to me that 2936 * there is a client error, but I'll just log it and keep going? 2937 */ 2938 if (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) 2939 printf("Nfsv4d: stray open confirm\n"); 2940 stp->ls_openowner->ls_flags = 0; 2941 stp->ls_stateid.seqid++; 2942 if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) { 2943 clp->lc_flags |= LCL_STAMPEDSTABLE; 2944 len = clp->lc_idlen; 2945 NFSBCOPY(clp->lc_id, client, len); 2946 gotstate = 1; 2947 } 2948 NFSUNLOCKSTATE(); 2949 } else if (new_stp->ls_flags & NFSLCK_CLOSE) { 2950 ownerstp = stp->ls_openowner; 2951 lfp = stp->ls_lfp; 2952 if (nfsrv_dolocallocks != 0 && !LIST_EMPTY(&stp->ls_open)) { 2953 /* Get the lf lock */ 2954 nfsrv_locklf(lfp); 2955 NFSUNLOCKSTATE(); 2956 if (nfsrv_freeopen(stp, vp, 1, p) == 0) { 2957 NFSLOCKSTATE(); 2958 nfsrv_unlocklf(lfp); 2959 NFSUNLOCKSTATE(); 2960 } 2961 } else { 2962 (void) nfsrv_freeopen(stp, NULL, 0, p); 2963 NFSUNLOCKSTATE(); 2964 } 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();
|
2981 return (NFSERR_INVAL);
| 2973 error = NFSERR_INVAL; 2974 goto out;
|
2982 } 2983 stp->ls_flags = (bits | NFSLCK_OPEN); 2984 stp->ls_stateid.seqid++; 2985 NFSUNLOCKSTATE(); 2986 } 2987 2988 /* 2989 * If the client just confirmed its first open, write a timestamp 2990 * to the stable storage file. 2991 */ 2992 if (gotstate != 0) { 2993 nfsrv_writestable(client, len, NFSNST_NEWSTATE, p); 2994 nfsrv_backupstable(); 2995 }
| 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);
|
2996 return (error); 2997} 2998 2999/* 3000 * Delegation update. Does the purge and return. 3001 */ 3002APPLESTATIC int 3003nfsrv_delegupdate(nfsquad_t clientid, nfsv4stateid_t *stateidp, 3004 vnode_t vp, int op, struct ucred *cred, NFSPROC_T *p) 3005{ 3006 struct nfsstate *stp; 3007 struct nfsclient *clp;
| 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;
|
3008 int error;
| 3004 int error = 0;
|
3009 fhandle_t fh; 3010 3011 /* 3012 * Do a sanity check against the file handle for DelegReturn. 3013 */ 3014 if (vp) { 3015 error = nfsvno_getfh(vp, &fh, p); 3016 if (error)
| 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)
|
3017 return (error);
| 3013 goto out;
|
3018 } 3019 /* 3020 * Check for restart conditions (client and server). 3021 */ 3022 if (op == NFSV4OP_DELEGRETURN) 3023 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGRETURN, 3024 stateidp, 0); 3025 else 3026 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGPURGE, 3027 stateidp, 0); 3028 3029 NFSLOCKSTATE(); 3030 /* 3031 * Get the open structure via clientid and stateid. 3032 */ 3033 if (!error) 3034 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 3035 (nfsquad_t)((u_quad_t)0), NULL, p); 3036 if (error) { 3037 if (error == NFSERR_CBPATHDOWN) 3038 error = 0; 3039 if (error == NFSERR_STALECLIENTID && op == NFSV4OP_DELEGRETURN) 3040 error = NFSERR_STALESTATEID; 3041 } 3042 if (!error && op == NFSV4OP_DELEGRETURN) { 3043 error = nfsrv_getstate(clp, stateidp, NFSLCK_DELEGRETURN, &stp); 3044 if (!error && stp->ls_stateid.seqid != stateidp->seqid) 3045 error = NFSERR_OLDSTATEID; 3046 } 3047 /* 3048 * NFSERR_EXPIRED means that the state has gone away, 3049 * so Delegations have been purged. Just return ok. 3050 */ 3051 if (error == NFSERR_EXPIRED && op == NFSV4OP_DELEGPURGE) { 3052 NFSUNLOCKSTATE();
| 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 3022 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGPURGE, 3023 stateidp, 0); 3024 3025 NFSLOCKSTATE(); 3026 /* 3027 * Get the open structure via clientid and stateid. 3028 */ 3029 if (!error) 3030 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 3031 (nfsquad_t)((u_quad_t)0), NULL, p); 3032 if (error) { 3033 if (error == NFSERR_CBPATHDOWN) 3034 error = 0; 3035 if (error == NFSERR_STALECLIENTID && op == NFSV4OP_DELEGRETURN) 3036 error = NFSERR_STALESTATEID; 3037 } 3038 if (!error && op == NFSV4OP_DELEGRETURN) { 3039 error = nfsrv_getstate(clp, stateidp, NFSLCK_DELEGRETURN, &stp); 3040 if (!error && stp->ls_stateid.seqid != stateidp->seqid) 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();
|
3053 return (0);
| 3049 error = 0; 3050 goto out;
|
3054 } 3055 if (error) { 3056 NFSUNLOCKSTATE();
| 3051 } 3052 if (error) { 3053 NFSUNLOCKSTATE();
|
3057 return (error);
| 3054 goto out;
|
3058 } 3059 3060 if (op == NFSV4OP_DELEGRETURN) { 3061 if (NFSBCMP((caddr_t)&fh, (caddr_t)&stp->ls_lfp->lf_fh, 3062 sizeof (fhandle_t))) { 3063 NFSUNLOCKSTATE();
| 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();
|
3064 return (NFSERR_BADSTATEID);
| 3061 error = NFSERR_BADSTATEID; 3062 goto out;
|
3065 } 3066 nfsrv_freedeleg(stp); 3067 } else { 3068 nfsrv_freedeleglist(&clp->lc_olddeleg); 3069 } 3070 NFSUNLOCKSTATE();
| 3063 } 3064 nfsrv_freedeleg(stp); 3065 } else { 3066 nfsrv_freedeleglist(&clp->lc_olddeleg); 3067 } 3068 NFSUNLOCKSTATE();
|
3071 return (0);
| 3069 error = 0; 3070 3071out: 3072 NFSEXITCODE(error); 3073 return (error);
|
3072} 3073 3074/* 3075 * Release lock owner. 3076 */ 3077APPLESTATIC int 3078nfsrv_releaselckown(struct nfsstate *new_stp, nfsquad_t clientid, 3079 NFSPROC_T *p) 3080{ 3081 struct nfsstate *stp, *nstp, *openstp, *ownstp; 3082 struct nfsclient *clp;
| 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;
|
3083 int error;
| 3085 int error = 0;
|
3084 3085 /* 3086 * Check for restart conditions (client and server). 3087 */ 3088 error = nfsrv_checkrestart(clientid, new_stp->ls_flags, 3089 &new_stp->ls_stateid, 0); 3090 if (error)
| 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)
|
3091 return (error);
| 3093 goto out;
|
3092 3093 NFSLOCKSTATE(); 3094 /* 3095 * Get the lock owner by name. 3096 */ 3097 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, 3098 (nfsquad_t)((u_quad_t)0), NULL, p); 3099 if (error) { 3100 NFSUNLOCKSTATE();
| 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();
|
3101 return (error);
| 3103 goto out;
|
3102 } 3103 LIST_FOREACH(ownstp, &clp->lc_open, ls_list) { 3104 LIST_FOREACH(openstp, &ownstp->ls_open, ls_list) { 3105 stp = LIST_FIRST(&openstp->ls_open); 3106 while (stp != LIST_END(&openstp->ls_open)) { 3107 nstp = LIST_NEXT(stp, ls_list); 3108 /* 3109 * If the owner matches, check for locks and 3110 * then free or return an error. 3111 */ 3112 if (stp->ls_ownerlen == new_stp->ls_ownerlen && 3113 !NFSBCMP(stp->ls_owner, new_stp->ls_owner, 3114 stp->ls_ownerlen)){ 3115 if (LIST_EMPTY(&stp->ls_lock)) { 3116 nfsrv_freelockowner(stp, NULL, 0, p); 3117 } else { 3118 NFSUNLOCKSTATE();
| 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();
|
3119 return (NFSERR_LOCKSHELD);
| 3121 error = NFSERR_LOCKSHELD; 3122 goto out;
|
3120 } 3121 } 3122 stp = nstp; 3123 } 3124 } 3125 } 3126 NFSUNLOCKSTATE();
| 3123 } 3124 } 3125 stp = nstp; 3126 } 3127 } 3128 } 3129 NFSUNLOCKSTATE();
|
3127 return (0);
| 3130 3131out: 3132 NFSEXITCODE(error); 3133 return (error);
|
3128} 3129 3130/* 3131 * Get the file handle for a lock structure. 3132 */ 3133static int 3134nfsrv_getlockfh(vnode_t vp, u_short flags, 3135 struct nfslockfile **new_lfpp, fhandle_t *nfhp, NFSPROC_T *p) 3136{ 3137 fhandle_t *fhp = NULL; 3138 struct nfslockfile *new_lfp; 3139 int error; 3140 3141 /* 3142 * For lock, use the new nfslock structure, otherwise just 3143 * a fhandle_t on the stack. 3144 */ 3145 if (flags & NFSLCK_OPEN) { 3146 new_lfp = *new_lfpp; 3147 fhp = &new_lfp->lf_fh; 3148 } else if (nfhp) { 3149 fhp = nfhp; 3150 } else { 3151 panic("nfsrv_getlockfh"); 3152 } 3153 error = nfsvno_getfh(vp, fhp, p);
| 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) 3142{ 3143 fhandle_t *fhp = NULL; 3144 struct nfslockfile *new_lfp; 3145 int error; 3146 3147 /* 3148 * For lock, use the new nfslock structure, otherwise just 3149 * a fhandle_t on the stack. 3150 */ 3151 if (flags & NFSLCK_OPEN) { 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);
|
3154 return (error); 3155} 3156 3157/* 3158 * Get an nfs lock structure. Allocate one, as required, and return a 3159 * pointer to it. 3160 * Returns an NFSERR_xxx upon failure or -1 to indicate no current lock. 3161 */ 3162static int 3163nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp, 3164 struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit) 3165{ 3166 struct nfslockfile *lfp; 3167 fhandle_t *fhp = NULL, *tfhp; 3168 struct nfslockhashhead *hp; 3169 struct nfslockfile *new_lfp = NULL; 3170 3171 /* 3172 * For lock, use the new nfslock structure, otherwise just 3173 * a fhandle_t on the stack. 3174 */ 3175 if (flags & NFSLCK_OPEN) { 3176 new_lfp = *new_lfpp; 3177 fhp = &new_lfp->lf_fh; 3178 } else if (nfhp) { 3179 fhp = nfhp; 3180 } else { 3181 panic("nfsrv_getlockfile"); 3182 } 3183 3184 hp = NFSLOCKHASH(fhp); 3185 LIST_FOREACH(lfp, hp, lf_hash) { 3186 tfhp = &lfp->lf_fh; 3187 if (NFSVNO_CMPFH(fhp, tfhp)) { 3188 if (lockit) 3189 nfsrv_locklf(lfp); 3190 *lfpp = lfp; 3191 return (0); 3192 } 3193 } 3194 if (!(flags & NFSLCK_OPEN)) 3195 return (-1); 3196 3197 /* 3198 * No match, so chain the new one into the list. 3199 */ 3200 LIST_INIT(&new_lfp->lf_open); 3201 LIST_INIT(&new_lfp->lf_lock); 3202 LIST_INIT(&new_lfp->lf_deleg); 3203 LIST_INIT(&new_lfp->lf_locallock); 3204 LIST_INIT(&new_lfp->lf_rollback); 3205 new_lfp->lf_locallock_lck.nfslock_usecnt = 0; 3206 new_lfp->lf_locallock_lck.nfslock_lock = 0; 3207 new_lfp->lf_usecount = 0; 3208 LIST_INSERT_HEAD(hp, new_lfp, lf_hash); 3209 *lfpp = new_lfp; 3210 *new_lfpp = NULL; 3211 return (0); 3212} 3213 3214/* 3215 * This function adds a nfslock lock structure to the list for the associated 3216 * nfsstate and nfslockfile structures. It will be inserted after the 3217 * entry pointed at by insert_lop. 3218 */ 3219static void 3220nfsrv_insertlock(struct nfslock *new_lop, struct nfslock *insert_lop, 3221 struct nfsstate *stp, struct nfslockfile *lfp) 3222{ 3223 struct nfslock *lop, *nlop; 3224 3225 new_lop->lo_stp = stp; 3226 new_lop->lo_lfp = lfp; 3227 3228 if (stp != NULL) { 3229 /* Insert in increasing lo_first order */ 3230 lop = LIST_FIRST(&lfp->lf_lock); 3231 if (lop == LIST_END(&lfp->lf_lock) || 3232 new_lop->lo_first <= lop->lo_first) { 3233 LIST_INSERT_HEAD(&lfp->lf_lock, new_lop, lo_lckfile); 3234 } else { 3235 nlop = LIST_NEXT(lop, lo_lckfile); 3236 while (nlop != LIST_END(&lfp->lf_lock) && 3237 nlop->lo_first < new_lop->lo_first) { 3238 lop = nlop; 3239 nlop = LIST_NEXT(lop, lo_lckfile); 3240 } 3241 LIST_INSERT_AFTER(lop, new_lop, lo_lckfile); 3242 } 3243 } else { 3244 new_lop->lo_lckfile.le_prev = NULL; /* list not used */ 3245 } 3246 3247 /* 3248 * Insert after insert_lop, which is overloaded as stp or lfp for 3249 * an empty list. 3250 */ 3251 if (stp == NULL && (struct nfslockfile *)insert_lop == lfp) 3252 LIST_INSERT_HEAD(&lfp->lf_locallock, new_lop, lo_lckowner); 3253 else if ((struct nfsstate *)insert_lop == stp) 3254 LIST_INSERT_HEAD(&stp->ls_lock, new_lop, lo_lckowner); 3255 else 3256 LIST_INSERT_AFTER(insert_lop, new_lop, lo_lckowner); 3257 if (stp != NULL) { 3258 newnfsstats.srvlocks++; 3259 nfsrv_openpluslock++; 3260 } 3261} 3262 3263/* 3264 * This function updates the locking for a lock owner and given file. It 3265 * maintains a list of lock ranges ordered on increasing file offset that 3266 * are NFSLCK_READ or NFSLCK_WRITE and non-overlapping (aka POSIX style). 3267 * It always adds new_lop to the list and sometimes uses the one pointed 3268 * at by other_lopp. 3269 */ 3270static void 3271nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp, 3272 struct nfslock **other_lopp, struct nfslockfile *lfp) 3273{ 3274 struct nfslock *new_lop = *new_lopp; 3275 struct nfslock *lop, *tlop, *ilop; 3276 struct nfslock *other_lop = *other_lopp; 3277 int unlock = 0, myfile = 0; 3278 u_int64_t tmp; 3279 3280 /* 3281 * Work down the list until the lock is merged. 3282 */ 3283 if (new_lop->lo_flags & NFSLCK_UNLOCK) 3284 unlock = 1; 3285 if (stp != NULL) { 3286 ilop = (struct nfslock *)stp; 3287 lop = LIST_FIRST(&stp->ls_lock); 3288 } else { 3289 ilop = (struct nfslock *)lfp; 3290 lop = LIST_FIRST(&lfp->lf_locallock); 3291 } 3292 while (lop != NULL) { 3293 /* 3294 * Only check locks for this file that aren't before the start of 3295 * new lock's range. 3296 */ 3297 if (lop->lo_lfp == lfp) { 3298 myfile = 1; 3299 if (lop->lo_end >= new_lop->lo_first) { 3300 if (new_lop->lo_end < lop->lo_first) { 3301 /* 3302 * If the new lock ends before the start of the 3303 * current lock's range, no merge, just insert 3304 * the new lock. 3305 */ 3306 break; 3307 } 3308 if (new_lop->lo_flags == lop->lo_flags || 3309 (new_lop->lo_first <= lop->lo_first && 3310 new_lop->lo_end >= lop->lo_end)) { 3311 /* 3312 * This lock can be absorbed by the new lock/unlock. 3313 * This happens when it covers the entire range 3314 * of the old lock or is contiguous 3315 * with the old lock and is of the same type or an 3316 * unlock. 3317 */ 3318 if (lop->lo_first < new_lop->lo_first) 3319 new_lop->lo_first = lop->lo_first; 3320 if (lop->lo_end > new_lop->lo_end) 3321 new_lop->lo_end = lop->lo_end; 3322 tlop = lop; 3323 lop = LIST_NEXT(lop, lo_lckowner); 3324 nfsrv_freenfslock(tlop); 3325 continue; 3326 } 3327 3328 /* 3329 * All these cases are for contiguous locks that are not the 3330 * same type, so they can't be merged. 3331 */ 3332 if (new_lop->lo_first <= lop->lo_first) { 3333 /* 3334 * This case is where the new lock overlaps with the 3335 * first part of the old lock. Move the start of the 3336 * old lock to just past the end of the new lock. The 3337 * new lock will be inserted in front of the old, since 3338 * ilop hasn't been updated. (We are done now.) 3339 */ 3340 lop->lo_first = new_lop->lo_end; 3341 break; 3342 } 3343 if (new_lop->lo_end >= lop->lo_end) { 3344 /* 3345 * This case is where the new lock overlaps with the 3346 * end of the old lock's range. Move the old lock's 3347 * end to just before the new lock's first and insert 3348 * the new lock after the old lock. 3349 * Might not be done yet, since the new lock could 3350 * overlap further locks with higher ranges. 3351 */ 3352 lop->lo_end = new_lop->lo_first; 3353 ilop = lop; 3354 lop = LIST_NEXT(lop, lo_lckowner); 3355 continue; 3356 } 3357 /* 3358 * The final case is where the new lock's range is in the 3359 * middle of the current lock's and splits the current lock 3360 * up. Use *other_lopp to handle the second part of the 3361 * split old lock range. (We are done now.) 3362 * For unlock, we use new_lop as other_lop and tmp, since 3363 * other_lop and new_lop are the same for this case. 3364 * We noted the unlock case above, so we don't need 3365 * new_lop->lo_flags any longer. 3366 */ 3367 tmp = new_lop->lo_first; 3368 if (other_lop == NULL) { 3369 if (!unlock) 3370 panic("nfsd srv update unlock"); 3371 other_lop = new_lop; 3372 *new_lopp = NULL; 3373 } 3374 other_lop->lo_first = new_lop->lo_end; 3375 other_lop->lo_end = lop->lo_end; 3376 other_lop->lo_flags = lop->lo_flags; 3377 other_lop->lo_stp = stp; 3378 other_lop->lo_lfp = lfp; 3379 lop->lo_end = tmp; 3380 nfsrv_insertlock(other_lop, lop, stp, lfp); 3381 *other_lopp = NULL; 3382 ilop = lop; 3383 break; 3384 } 3385 } 3386 ilop = lop; 3387 lop = LIST_NEXT(lop, lo_lckowner); 3388 if (myfile && (lop == NULL || lop->lo_lfp != lfp)) 3389 break; 3390 } 3391 3392 /* 3393 * Insert the new lock in the list at the appropriate place. 3394 */ 3395 if (!unlock) { 3396 nfsrv_insertlock(new_lop, ilop, stp, lfp); 3397 *new_lopp = NULL; 3398 } 3399} 3400 3401/* 3402 * This function handles sequencing of locks, etc. 3403 * It returns an error that indicates what the caller should do. 3404 */ 3405static int 3406nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid, 3407 struct nfsstate *stp, struct nfsrvcache *op) 3408{
| 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 */ 3169static int 3170nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp, 3171 struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit) 3172{ 3173 struct nfslockfile *lfp; 3174 fhandle_t *fhp = NULL, *tfhp; 3175 struct nfslockhashhead *hp; 3176 struct nfslockfile *new_lfp = NULL; 3177 3178 /* 3179 * For lock, use the new nfslock structure, otherwise just 3180 * a fhandle_t on the stack. 3181 */ 3182 if (flags & NFSLCK_OPEN) { 3183 new_lfp = *new_lfpp; 3184 fhp = &new_lfp->lf_fh; 3185 } else if (nfhp) { 3186 fhp = nfhp; 3187 } else { 3188 panic("nfsrv_getlockfile"); 3189 } 3190 3191 hp = NFSLOCKHASH(fhp); 3192 LIST_FOREACH(lfp, hp, lf_hash) { 3193 tfhp = &lfp->lf_fh; 3194 if (NFSVNO_CMPFH(fhp, tfhp)) { 3195 if (lockit) 3196 nfsrv_locklf(lfp); 3197 *lfpp = lfp; 3198 return (0); 3199 } 3200 } 3201 if (!(flags & NFSLCK_OPEN)) 3202 return (-1); 3203 3204 /* 3205 * No match, so chain the new one into the list. 3206 */ 3207 LIST_INIT(&new_lfp->lf_open); 3208 LIST_INIT(&new_lfp->lf_lock); 3209 LIST_INIT(&new_lfp->lf_deleg); 3210 LIST_INIT(&new_lfp->lf_locallock); 3211 LIST_INIT(&new_lfp->lf_rollback); 3212 new_lfp->lf_locallock_lck.nfslock_usecnt = 0; 3213 new_lfp->lf_locallock_lck.nfslock_lock = 0; 3214 new_lfp->lf_usecount = 0; 3215 LIST_INSERT_HEAD(hp, new_lfp, lf_hash); 3216 *lfpp = new_lfp; 3217 *new_lfpp = NULL; 3218 return (0); 3219} 3220 3221/* 3222 * This function adds a nfslock lock structure to the list for the associated 3223 * nfsstate and nfslockfile structures. It will be inserted after the 3224 * entry pointed at by insert_lop. 3225 */ 3226static void 3227nfsrv_insertlock(struct nfslock *new_lop, struct nfslock *insert_lop, 3228 struct nfsstate *stp, struct nfslockfile *lfp) 3229{ 3230 struct nfslock *lop, *nlop; 3231 3232 new_lop->lo_stp = stp; 3233 new_lop->lo_lfp = lfp; 3234 3235 if (stp != NULL) { 3236 /* Insert in increasing lo_first order */ 3237 lop = LIST_FIRST(&lfp->lf_lock); 3238 if (lop == LIST_END(&lfp->lf_lock) || 3239 new_lop->lo_first <= lop->lo_first) { 3240 LIST_INSERT_HEAD(&lfp->lf_lock, new_lop, lo_lckfile); 3241 } else { 3242 nlop = LIST_NEXT(lop, lo_lckfile); 3243 while (nlop != LIST_END(&lfp->lf_lock) && 3244 nlop->lo_first < new_lop->lo_first) { 3245 lop = nlop; 3246 nlop = LIST_NEXT(lop, lo_lckfile); 3247 } 3248 LIST_INSERT_AFTER(lop, new_lop, lo_lckfile); 3249 } 3250 } else { 3251 new_lop->lo_lckfile.le_prev = NULL; /* list not used */ 3252 } 3253 3254 /* 3255 * Insert after insert_lop, which is overloaded as stp or lfp for 3256 * an empty list. 3257 */ 3258 if (stp == NULL && (struct nfslockfile *)insert_lop == lfp) 3259 LIST_INSERT_HEAD(&lfp->lf_locallock, new_lop, lo_lckowner); 3260 else if ((struct nfsstate *)insert_lop == stp) 3261 LIST_INSERT_HEAD(&stp->ls_lock, new_lop, lo_lckowner); 3262 else 3263 LIST_INSERT_AFTER(insert_lop, new_lop, lo_lckowner); 3264 if (stp != NULL) { 3265 newnfsstats.srvlocks++; 3266 nfsrv_openpluslock++; 3267 } 3268} 3269 3270/* 3271 * This function updates the locking for a lock owner and given file. It 3272 * maintains a list of lock ranges ordered on increasing file offset that 3273 * are NFSLCK_READ or NFSLCK_WRITE and non-overlapping (aka POSIX style). 3274 * It always adds new_lop to the list and sometimes uses the one pointed 3275 * at by other_lopp. 3276 */ 3277static void 3278nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp, 3279 struct nfslock **other_lopp, struct nfslockfile *lfp) 3280{ 3281 struct nfslock *new_lop = *new_lopp; 3282 struct nfslock *lop, *tlop, *ilop; 3283 struct nfslock *other_lop = *other_lopp; 3284 int unlock = 0, myfile = 0; 3285 u_int64_t tmp; 3286 3287 /* 3288 * Work down the list until the lock is merged. 3289 */ 3290 if (new_lop->lo_flags & NFSLCK_UNLOCK) 3291 unlock = 1; 3292 if (stp != NULL) { 3293 ilop = (struct nfslock *)stp; 3294 lop = LIST_FIRST(&stp->ls_lock); 3295 } else { 3296 ilop = (struct nfslock *)lfp; 3297 lop = LIST_FIRST(&lfp->lf_locallock); 3298 } 3299 while (lop != NULL) { 3300 /* 3301 * Only check locks for this file that aren't before the start of 3302 * new lock's range. 3303 */ 3304 if (lop->lo_lfp == lfp) { 3305 myfile = 1; 3306 if (lop->lo_end >= new_lop->lo_first) { 3307 if (new_lop->lo_end < lop->lo_first) { 3308 /* 3309 * If the new lock ends before the start of the 3310 * current lock's range, no merge, just insert 3311 * the new lock. 3312 */ 3313 break; 3314 } 3315 if (new_lop->lo_flags == lop->lo_flags || 3316 (new_lop->lo_first <= lop->lo_first && 3317 new_lop->lo_end >= lop->lo_end)) { 3318 /* 3319 * This lock can be absorbed by the new lock/unlock. 3320 * This happens when it covers the entire range 3321 * of the old lock or is contiguous 3322 * with the old lock and is of the same type or an 3323 * unlock. 3324 */ 3325 if (lop->lo_first < new_lop->lo_first) 3326 new_lop->lo_first = lop->lo_first; 3327 if (lop->lo_end > new_lop->lo_end) 3328 new_lop->lo_end = lop->lo_end; 3329 tlop = lop; 3330 lop = LIST_NEXT(lop, lo_lckowner); 3331 nfsrv_freenfslock(tlop); 3332 continue; 3333 } 3334 3335 /* 3336 * All these cases are for contiguous locks that are not the 3337 * same type, so they can't be merged. 3338 */ 3339 if (new_lop->lo_first <= lop->lo_first) { 3340 /* 3341 * This case is where the new lock overlaps with the 3342 * first part of the old lock. Move the start of the 3343 * old lock to just past the end of the new lock. The 3344 * new lock will be inserted in front of the old, since 3345 * ilop hasn't been updated. (We are done now.) 3346 */ 3347 lop->lo_first = new_lop->lo_end; 3348 break; 3349 } 3350 if (new_lop->lo_end >= lop->lo_end) { 3351 /* 3352 * This case is where the new lock overlaps with the 3353 * end of the old lock's range. Move the old lock's 3354 * end to just before the new lock's first and insert 3355 * the new lock after the old lock. 3356 * Might not be done yet, since the new lock could 3357 * overlap further locks with higher ranges. 3358 */ 3359 lop->lo_end = new_lop->lo_first; 3360 ilop = lop; 3361 lop = LIST_NEXT(lop, lo_lckowner); 3362 continue; 3363 } 3364 /* 3365 * The final case is where the new lock's range is in the 3366 * middle of the current lock's and splits the current lock 3367 * up. Use *other_lopp to handle the second part of the 3368 * split old lock range. (We are done now.) 3369 * For unlock, we use new_lop as other_lop and tmp, since 3370 * other_lop and new_lop are the same for this case. 3371 * We noted the unlock case above, so we don't need 3372 * new_lop->lo_flags any longer. 3373 */ 3374 tmp = new_lop->lo_first; 3375 if (other_lop == NULL) { 3376 if (!unlock) 3377 panic("nfsd srv update unlock"); 3378 other_lop = new_lop; 3379 *new_lopp = NULL; 3380 } 3381 other_lop->lo_first = new_lop->lo_end; 3382 other_lop->lo_end = lop->lo_end; 3383 other_lop->lo_flags = lop->lo_flags; 3384 other_lop->lo_stp = stp; 3385 other_lop->lo_lfp = lfp; 3386 lop->lo_end = tmp; 3387 nfsrv_insertlock(other_lop, lop, stp, lfp); 3388 *other_lopp = NULL; 3389 ilop = lop; 3390 break; 3391 } 3392 } 3393 ilop = lop; 3394 lop = LIST_NEXT(lop, lo_lckowner); 3395 if (myfile && (lop == NULL || lop->lo_lfp != lfp)) 3396 break; 3397 } 3398 3399 /* 3400 * Insert the new lock in the list at the appropriate place. 3401 */ 3402 if (!unlock) { 3403 nfsrv_insertlock(new_lop, ilop, stp, lfp); 3404 *new_lopp = NULL; 3405 } 3406} 3407 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;
|
3409 3410 if (op != nd->nd_rp) 3411 panic("nfsrvstate checkseqid"); 3412 if (!(op->rc_flag & RC_INPROG)) 3413 panic("nfsrvstate not inprog"); 3414 if (stp->ls_op && stp->ls_op->rc_refcnt <= 0) { 3415 printf("refcnt=%d\n", stp->ls_op->rc_refcnt); 3416 panic("nfsrvstate op refcnt"); 3417 } 3418 if ((stp->ls_seq + 1) == seqid) { 3419 if (stp->ls_op) 3420 nfsrvd_derefcache(stp->ls_op); 3421 stp->ls_op = op; 3422 nfsrvd_refcache(op); 3423 stp->ls_seq = seqid;
| 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;
|
3424 return (0);
| 3432 goto out;
|
3425 } else if (stp->ls_seq == seqid && stp->ls_op && 3426 op->rc_xid == stp->ls_op->rc_xid && 3427 op->rc_refcnt == 0 && 3428 op->rc_reqlen == stp->ls_op->rc_reqlen && 3429 op->rc_cksum == stp->ls_op->rc_cksum) {
| 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) {
|
3430 if (stp->ls_op->rc_flag & RC_INPROG) 3431 return (NFSERR_DONTREPLY);
| 3438 if (stp->ls_op->rc_flag & RC_INPROG) { 3439 error = NFSERR_DONTREPLY; 3440 goto out; 3441 }
|
3432 nd->nd_rp = stp->ls_op; 3433 nd->nd_rp->rc_flag |= RC_INPROG; 3434 nfsrvd_delcache(op);
| 3442 nd->nd_rp = stp->ls_op; 3443 nd->nd_rp->rc_flag |= RC_INPROG; 3444 nfsrvd_delcache(op);
|
3435 return (NFSERR_REPLYFROMCACHE);
| 3445 error = NFSERR_REPLYFROMCACHE; 3446 goto out;
|
3436 }
| 3447 }
|
3437 return (NFSERR_BADSEQID);
| 3448 error = NFSERR_BADSEQID; 3449 3450out: 3451 NFSEXITCODE2(error, nd); 3452 return (error);
|
3438} 3439 3440/* 3441 * Get the client ip address for callbacks. If the strings can't be parsed, 3442 * just set lc_program to 0 to indicate no callbacks are possible. 3443 * (For cases where the address can't be parsed or is 0.0.0.0.0.0, set 3444 * the address to the client's transport address. This won't be used 3445 * for callbacks, but can be printed out by newnfsstats for info.) 3446 * Return error if the xdr can't be parsed, 0 otherwise. 3447 */ 3448APPLESTATIC int 3449nfsrv_getclientipaddr(struct nfsrv_descript *nd, struct nfsclient *clp) 3450{ 3451 u_int32_t *tl; 3452 u_char *cp, *cp2; 3453 int i, j; 3454 struct sockaddr_in *rad, *sad; 3455 u_char protocol[5], addr[24]; 3456 int error = 0, cantparse = 0; 3457 union { 3458 u_long ival; 3459 u_char cval[4]; 3460 } ip; 3461 union { 3462 u_short sval; 3463 u_char cval[2]; 3464 } port; 3465 3466 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3467 rad->sin_family = AF_INET; 3468 rad->sin_len = sizeof (struct sockaddr_in); 3469 rad->sin_addr.s_addr = 0; 3470 rad->sin_port = 0; 3471 clp->lc_req.nr_client = NULL; 3472 clp->lc_req.nr_lock = 0; 3473 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3474 i = fxdr_unsigned(int, *tl); 3475 if (i >= 3 && i <= 4) { 3476 error = nfsrv_mtostr(nd, protocol, i); 3477 if (error) 3478 goto nfsmout; 3479 if (!strcmp(protocol, "tcp")) { 3480 clp->lc_flags |= LCL_TCPCALLBACK; 3481 clp->lc_req.nr_sotype = SOCK_STREAM; 3482 clp->lc_req.nr_soproto = IPPROTO_TCP; 3483 } else if (!strcmp(protocol, "udp")) { 3484 clp->lc_req.nr_sotype = SOCK_DGRAM; 3485 clp->lc_req.nr_soproto = IPPROTO_UDP; 3486 } else { 3487 cantparse = 1; 3488 } 3489 } else { 3490 cantparse = 1; 3491 if (i > 0) { 3492 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3493 if (error) 3494 goto nfsmout; 3495 } 3496 } 3497 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3498 i = fxdr_unsigned(int, *tl); 3499 if (i < 0) { 3500 error = NFSERR_BADXDR; 3501 goto nfsmout; 3502 } else if (i == 0) { 3503 cantparse = 1; 3504 } else if (!cantparse && i <= 23 && i >= 11) { 3505 error = nfsrv_mtostr(nd, addr, i); 3506 if (error) 3507 goto nfsmout; 3508 3509 /* 3510 * Parse out the address fields. We expect 6 decimal numbers 3511 * separated by '.'s. 3512 */ 3513 cp = addr; 3514 i = 0; 3515 while (*cp && i < 6) { 3516 cp2 = cp; 3517 while (*cp2 && *cp2 != '.') 3518 cp2++; 3519 if (*cp2) 3520 *cp2++ = '\0'; 3521 else if (i != 5) { 3522 cantparse = 1; 3523 break; 3524 } 3525 j = nfsrv_getipnumber(cp); 3526 if (j >= 0) { 3527 if (i < 4) 3528 ip.cval[3 - i] = j; 3529 else 3530 port.cval[5 - i] = j; 3531 } else { 3532 cantparse = 1; 3533 break; 3534 } 3535 cp = cp2; 3536 i++; 3537 } 3538 if (!cantparse) { 3539 if (ip.ival != 0x0) { 3540 rad->sin_addr.s_addr = htonl(ip.ival); 3541 rad->sin_port = htons(port.sval); 3542 } else { 3543 cantparse = 1; 3544 } 3545 } 3546 } else { 3547 cantparse = 1; 3548 if (i > 0) { 3549 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3550 if (error) 3551 goto nfsmout; 3552 } 3553 } 3554 if (cantparse) { 3555 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 3556 rad->sin_addr.s_addr = sad->sin_addr.s_addr; 3557 rad->sin_port = 0x0; 3558 clp->lc_program = 0; 3559 } 3560nfsmout:
| 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.) 3461 * Return error if the xdr can't be parsed, 0 otherwise. 3462 */ 3463APPLESTATIC int 3464nfsrv_getclientipaddr(struct nfsrv_descript *nd, struct nfsclient *clp) 3465{ 3466 u_int32_t *tl; 3467 u_char *cp, *cp2; 3468 int i, j; 3469 struct sockaddr_in *rad, *sad; 3470 u_char protocol[5], addr[24]; 3471 int error = 0, cantparse = 0; 3472 union { 3473 u_long ival; 3474 u_char cval[4]; 3475 } ip; 3476 union { 3477 u_short sval; 3478 u_char cval[2]; 3479 } port; 3480 3481 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3482 rad->sin_family = AF_INET; 3483 rad->sin_len = sizeof (struct sockaddr_in); 3484 rad->sin_addr.s_addr = 0; 3485 rad->sin_port = 0; 3486 clp->lc_req.nr_client = NULL; 3487 clp->lc_req.nr_lock = 0; 3488 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3489 i = fxdr_unsigned(int, *tl); 3490 if (i >= 3 && i <= 4) { 3491 error = nfsrv_mtostr(nd, protocol, i); 3492 if (error) 3493 goto nfsmout; 3494 if (!strcmp(protocol, "tcp")) { 3495 clp->lc_flags |= LCL_TCPCALLBACK; 3496 clp->lc_req.nr_sotype = SOCK_STREAM; 3497 clp->lc_req.nr_soproto = IPPROTO_TCP; 3498 } else if (!strcmp(protocol, "udp")) { 3499 clp->lc_req.nr_sotype = SOCK_DGRAM; 3500 clp->lc_req.nr_soproto = IPPROTO_UDP; 3501 } else { 3502 cantparse = 1; 3503 } 3504 } else { 3505 cantparse = 1; 3506 if (i > 0) { 3507 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3508 if (error) 3509 goto nfsmout; 3510 } 3511 } 3512 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3513 i = fxdr_unsigned(int, *tl); 3514 if (i < 0) { 3515 error = NFSERR_BADXDR; 3516 goto nfsmout; 3517 } else if (i == 0) { 3518 cantparse = 1; 3519 } else if (!cantparse && i <= 23 && i >= 11) { 3520 error = nfsrv_mtostr(nd, addr, i); 3521 if (error) 3522 goto nfsmout; 3523 3524 /* 3525 * Parse out the address fields. We expect 6 decimal numbers 3526 * separated by '.'s. 3527 */ 3528 cp = addr; 3529 i = 0; 3530 while (*cp && i < 6) { 3531 cp2 = cp; 3532 while (*cp2 && *cp2 != '.') 3533 cp2++; 3534 if (*cp2) 3535 *cp2++ = '\0'; 3536 else if (i != 5) { 3537 cantparse = 1; 3538 break; 3539 } 3540 j = nfsrv_getipnumber(cp); 3541 if (j >= 0) { 3542 if (i < 4) 3543 ip.cval[3 - i] = j; 3544 else 3545 port.cval[5 - i] = j; 3546 } else { 3547 cantparse = 1; 3548 break; 3549 } 3550 cp = cp2; 3551 i++; 3552 } 3553 if (!cantparse) { 3554 if (ip.ival != 0x0) { 3555 rad->sin_addr.s_addr = htonl(ip.ival); 3556 rad->sin_port = htons(port.sval); 3557 } else { 3558 cantparse = 1; 3559 } 3560 } 3561 } else { 3562 cantparse = 1; 3563 if (i > 0) { 3564 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3565 if (error) 3566 goto nfsmout; 3567 } 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);
|
3561 return (error); 3562} 3563 3564/* 3565 * Turn a string of up to three decimal digits into a number. Return -1 upon 3566 * error. 3567 */ 3568static int 3569nfsrv_getipnumber(u_char *cp) 3570{ 3571 int i = 0, j = 0; 3572 3573 while (*cp) { 3574 if (j > 2 || *cp < '0' || *cp > '9') 3575 return (-1); 3576 i *= 10; 3577 i += (*cp - '0'); 3578 cp++; 3579 j++; 3580 } 3581 if (i < 256) 3582 return (i); 3583 return (-1); 3584} 3585 3586/* 3587 * This function checks for restart conditions. 3588 */ 3589static int 3590nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags, 3591 nfsv4stateid_t *stateidp, int specialid) 3592{
| 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 3585nfsrv_getipnumber(u_char *cp) 3586{ 3587 int i = 0, j = 0; 3588 3589 while (*cp) { 3590 if (j > 2 || *cp < '0' || *cp > '9') 3591 return (-1); 3592 i *= 10; 3593 i += (*cp - '0'); 3594 cp++; 3595 j++; 3596 } 3597 if (i < 256) 3598 return (i); 3599 return (-1); 3600} 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{
|
3593 int ret;
| 3609 int ret = 0;
|
3594 3595 /* 3596 * First check for a server restart. Open, LockT, ReleaseLockOwner 3597 * and DelegPurge have a clientid, the rest a stateid. 3598 */ 3599 if (flags & 3600 (NFSLCK_OPEN | NFSLCK_TEST | NFSLCK_RELEASE | NFSLCK_DELEGPURGE)) {
| 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)) {
|
3601 if (clientid.lval[0] != nfsrvboottime) 3602 return (NFSERR_STALECLIENTID);
| 3617 if (clientid.lval[0] != nfsrvboottime) { 3618 ret = NFSERR_STALECLIENTID; 3619 goto out; 3620 }
|
3603 } else if (stateidp->other[0] != nfsrvboottime &&
| 3621 } else if (stateidp->other[0] != nfsrvboottime &&
|
3604 specialid == 0) 3605 return (NFSERR_STALESTATEID);
| 3622 specialid == 0) { 3623 ret = NFSERR_STALESTATEID; 3624 goto out; 3625 }
|
3606 3607 /* 3608 * Read, Write, Setattr and LockT can return NFSERR_GRACE and do 3609 * not use a lock/open owner seqid#, so the check can be done now. 3610 * (The others will be checked, as required, later.) 3611 */ 3612 if (!(flags & (NFSLCK_CHECK | NFSLCK_TEST)))
| 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)))
|
3613 return (0);
| 3633 goto out;
|
3614 3615 NFSLOCKSTATE(); 3616 ret = nfsrv_checkgrace(flags); 3617 NFSUNLOCKSTATE();
| 3634 3635 NFSLOCKSTATE(); 3636 ret = nfsrv_checkgrace(flags); 3637 NFSUNLOCKSTATE();
|
| 3638 3639out: 3640 NFSEXITCODE(ret);
|
3618 return (ret); 3619} 3620 3621/* 3622 * Check for grace. 3623 */ 3624static int 3625nfsrv_checkgrace(u_int32_t flags) 3626{
| 3641 return (ret); 3642} 3643 3644/* 3645 * Check for grace. 3646 */ 3647static int 3648nfsrv_checkgrace(u_int32_t flags) 3649{
|
| 3650 int error = 0;
|
3627 3628 if (nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) {
| 3651 3652 if (nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) {
|
3629 if (flags & NFSLCK_RECLAIM) 3630 return (NFSERR_NOGRACE);
| 3653 if (flags & NFSLCK_RECLAIM) { 3654 error = NFSERR_NOGRACE; 3655 goto out; 3656 }
|
3631 } else {
| 3657 } else {
|
3632 if (!(flags & NFSLCK_RECLAIM)) 3633 return (NFSERR_GRACE);
| 3658 if (!(flags & NFSLCK_RECLAIM)) { 3659 error = NFSERR_GRACE; 3660 goto out; 3661 }
|
3634 3635 /* 3636 * If grace is almost over and we are still getting Reclaims, 3637 * extend grace a bit. 3638 */ 3639 if ((NFSD_MONOSEC + NFSRV_LEASEDELTA) > 3640 nfsrv_stablefirst.nsf_eograce) 3641 nfsrv_stablefirst.nsf_eograce = NFSD_MONOSEC + 3642 NFSRV_LEASEDELTA; 3643 }
| 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 }
|
3644 return (0);
| 3672 3673out: 3674 NFSEXITCODE(error); 3675 return (error);
|
3645} 3646 3647/* 3648 * Do a server callback. 3649 */ 3650static int 3651nfsrv_docallback(struct nfsclient *clp, int procnum, 3652 nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp, 3653 struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p) 3654{ 3655 mbuf_t m; 3656 u_int32_t *tl; 3657 struct nfsrv_descript nfsd, *nd = &nfsd; 3658 struct ucred *cred; 3659 int error = 0; 3660 u_int32_t callback; 3661 3662 cred = newnfs_getcred(); 3663 NFSLOCKSTATE(); /* mostly for lc_cbref++ */ 3664 if (clp->lc_flags & LCL_NEEDSCONFIRM) { 3665 NFSUNLOCKSTATE(); 3666 panic("docallb"); 3667 } 3668 clp->lc_cbref++; 3669 3670 /* 3671 * Fill the callback program# and version into the request 3672 * structure for newnfs_connect() to use. 3673 */ 3674 clp->lc_req.nr_prog = clp->lc_program; 3675 clp->lc_req.nr_vers = NFSV4_CBVERS; 3676 3677 /* 3678 * First, fill in some of the fields of nd and cr. 3679 */ 3680 nd->nd_flag = ND_NFSV4; 3681 if (clp->lc_flags & LCL_GSS) 3682 nd->nd_flag |= ND_KERBV; 3683 nd->nd_repstat = 0; 3684 cred->cr_uid = clp->lc_uid; 3685 cred->cr_gid = clp->lc_gid; 3686 callback = clp->lc_callback; 3687 NFSUNLOCKSTATE(); 3688 cred->cr_ngroups = 1; 3689 3690 /* 3691 * Get the first mbuf for the request. 3692 */ 3693 MGET(m, M_WAIT, MT_DATA); 3694 mbuf_setlen(m, 0); 3695 nd->nd_mreq = nd->nd_mb = m; 3696 nd->nd_bpos = NFSMTOD(m, caddr_t); 3697 3698 /* 3699 * and build the callback request. 3700 */ 3701 if (procnum == NFSV4OP_CBGETATTR) { 3702 nd->nd_procnum = NFSV4PROC_CBCOMPOUND; 3703 (void) nfsm_strtom(nd, "CB Getattr", 10); 3704 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 3705 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 3706 *tl++ = txdr_unsigned(callback); 3707 *tl++ = txdr_unsigned(1); 3708 *tl = txdr_unsigned(NFSV4OP_CBGETATTR); 3709 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); 3710 (void) nfsrv_putattrbit(nd, attrbitp); 3711 } else if (procnum == NFSV4OP_CBRECALL) { 3712 nd->nd_procnum = NFSV4PROC_CBCOMPOUND; 3713 (void) nfsm_strtom(nd, "CB Recall", 9); 3714 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 3715 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 3716 *tl++ = txdr_unsigned(callback); 3717 *tl++ = txdr_unsigned(1); 3718 *tl++ = txdr_unsigned(NFSV4OP_CBRECALL); 3719 *tl++ = txdr_unsigned(stateidp->seqid); 3720 NFSBCOPY((caddr_t)stateidp->other, (caddr_t)tl, 3721 NFSX_STATEIDOTHER); 3722 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3723 if (trunc) 3724 *tl = newnfs_true; 3725 else 3726 *tl = newnfs_false; 3727 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); 3728 } else { 3729 nd->nd_procnum = NFSV4PROC_CBNULL; 3730 } 3731 3732 /* 3733 * Call newnfs_connect(), as required, and then newnfs_request(). 3734 */ 3735 (void) newnfs_sndlock(&clp->lc_req.nr_lock); 3736 if (clp->lc_req.nr_client == NULL) { 3737 if (nd->nd_procnum == NFSV4PROC_CBNULL) 3738 error = newnfs_connect(NULL, &clp->lc_req, cred, 3739 NULL, 1); 3740 else 3741 error = newnfs_connect(NULL, &clp->lc_req, cred, 3742 NULL, 3); 3743 } 3744 newnfs_sndunlock(&clp->lc_req.nr_lock); 3745 if (!error) { 3746 error = newnfs_request(nd, NULL, clp, &clp->lc_req, NULL, 3747 NULL, cred, clp->lc_program, NFSV4_CBVERS, NULL, 1, NULL); 3748 } 3749 NFSFREECRED(cred); 3750 3751 /* 3752 * If error is set here, the Callback path isn't working 3753 * properly, so twiddle the appropriate LCL_ flags. 3754 * (nd_repstat != 0 indicates the Callback path is working, 3755 * but the callback failed on the client.) 3756 */ 3757 if (error) { 3758 /* 3759 * Mark the callback pathway down, which disabled issuing 3760 * of delegations and gets Renew to return NFSERR_CBPATHDOWN. 3761 */ 3762 NFSLOCKSTATE(); 3763 clp->lc_flags |= LCL_CBDOWN; 3764 NFSUNLOCKSTATE(); 3765 } else { 3766 /* 3767 * Callback worked. If the callback path was down, disable 3768 * callbacks, so no more delegations will be issued. (This 3769 * is done on the assumption that the callback pathway is 3770 * flakey.) 3771 */ 3772 NFSLOCKSTATE(); 3773 if (clp->lc_flags & LCL_CBDOWN) 3774 clp->lc_flags &= ~(LCL_CBDOWN | LCL_CALLBACKSON); 3775 NFSUNLOCKSTATE(); 3776 if (nd->nd_repstat) 3777 error = nd->nd_repstat; 3778 else if (procnum == NFSV4OP_CBGETATTR) 3779 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3780 NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 3781 p, NULL); 3782 mbuf_freem(nd->nd_mrep); 3783 } 3784 NFSLOCKSTATE(); 3785 clp->lc_cbref--; 3786 if ((clp->lc_flags & LCL_WAKEUPWANTED) && clp->lc_cbref == 0) { 3787 clp->lc_flags &= ~LCL_WAKEUPWANTED; 3788 NFSUNLOCKSTATE(); 3789 wakeup((caddr_t)clp); 3790 } else { 3791 NFSUNLOCKSTATE(); 3792 }
| 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, 3684 struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p) 3685{ 3686 mbuf_t m; 3687 u_int32_t *tl; 3688 struct nfsrv_descript nfsd, *nd = &nfsd; 3689 struct ucred *cred; 3690 int error = 0; 3691 u_int32_t callback; 3692 3693 cred = newnfs_getcred(); 3694 NFSLOCKSTATE(); /* mostly for lc_cbref++ */ 3695 if (clp->lc_flags & LCL_NEEDSCONFIRM) { 3696 NFSUNLOCKSTATE(); 3697 panic("docallb"); 3698 } 3699 clp->lc_cbref++; 3700 3701 /* 3702 * Fill the callback program# and version into the request 3703 * structure for newnfs_connect() to use. 3704 */ 3705 clp->lc_req.nr_prog = clp->lc_program; 3706 clp->lc_req.nr_vers = NFSV4_CBVERS; 3707 3708 /* 3709 * First, fill in some of the fields of nd and cr. 3710 */ 3711 nd->nd_flag = ND_NFSV4; 3712 if (clp->lc_flags & LCL_GSS) 3713 nd->nd_flag |= ND_KERBV; 3714 nd->nd_repstat = 0; 3715 cred->cr_uid = clp->lc_uid; 3716 cred->cr_gid = clp->lc_gid; 3717 callback = clp->lc_callback; 3718 NFSUNLOCKSTATE(); 3719 cred->cr_ngroups = 1; 3720 3721 /* 3722 * Get the first mbuf for the request. 3723 */ 3724 MGET(m, M_WAIT, MT_DATA); 3725 mbuf_setlen(m, 0); 3726 nd->nd_mreq = nd->nd_mb = m; 3727 nd->nd_bpos = NFSMTOD(m, caddr_t); 3728 3729 /* 3730 * and build the callback request. 3731 */ 3732 if (procnum == NFSV4OP_CBGETATTR) { 3733 nd->nd_procnum = NFSV4PROC_CBCOMPOUND; 3734 (void) nfsm_strtom(nd, "CB Getattr", 10); 3735 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 3736 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 3737 *tl++ = txdr_unsigned(callback); 3738 *tl++ = txdr_unsigned(1); 3739 *tl = txdr_unsigned(NFSV4OP_CBGETATTR); 3740 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); 3741 (void) nfsrv_putattrbit(nd, attrbitp); 3742 } else if (procnum == NFSV4OP_CBRECALL) { 3743 nd->nd_procnum = NFSV4PROC_CBCOMPOUND; 3744 (void) nfsm_strtom(nd, "CB Recall", 9); 3745 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 3746 *tl++ = txdr_unsigned(NFSV4_MINORVERSION); 3747 *tl++ = txdr_unsigned(callback); 3748 *tl++ = txdr_unsigned(1); 3749 *tl++ = txdr_unsigned(NFSV4OP_CBRECALL); 3750 *tl++ = txdr_unsigned(stateidp->seqid); 3751 NFSBCOPY((caddr_t)stateidp->other, (caddr_t)tl, 3752 NFSX_STATEIDOTHER); 3753 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3754 if (trunc) 3755 *tl = newnfs_true; 3756 else 3757 *tl = newnfs_false; 3758 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); 3759 } else { 3760 nd->nd_procnum = NFSV4PROC_CBNULL; 3761 } 3762 3763 /* 3764 * Call newnfs_connect(), as required, and then newnfs_request(). 3765 */ 3766 (void) newnfs_sndlock(&clp->lc_req.nr_lock); 3767 if (clp->lc_req.nr_client == NULL) { 3768 if (nd->nd_procnum == NFSV4PROC_CBNULL) 3769 error = newnfs_connect(NULL, &clp->lc_req, cred, 3770 NULL, 1); 3771 else 3772 error = newnfs_connect(NULL, &clp->lc_req, cred, 3773 NULL, 3); 3774 } 3775 newnfs_sndunlock(&clp->lc_req.nr_lock); 3776 if (!error) { 3777 error = newnfs_request(nd, NULL, clp, &clp->lc_req, NULL, 3778 NULL, cred, clp->lc_program, NFSV4_CBVERS, NULL, 1, NULL); 3779 } 3780 NFSFREECRED(cred); 3781 3782 /* 3783 * If error is set here, the Callback path isn't working 3784 * properly, so twiddle the appropriate LCL_ flags. 3785 * (nd_repstat != 0 indicates the Callback path is working, 3786 * but the callback failed on the client.) 3787 */ 3788 if (error) { 3789 /* 3790 * Mark the callback pathway down, which disabled issuing 3791 * of delegations and gets Renew to return NFSERR_CBPATHDOWN. 3792 */ 3793 NFSLOCKSTATE(); 3794 clp->lc_flags |= LCL_CBDOWN; 3795 NFSUNLOCKSTATE(); 3796 } else { 3797 /* 3798 * Callback worked. If the callback path was down, disable 3799 * callbacks, so no more delegations will be issued. (This 3800 * is done on the assumption that the callback pathway is 3801 * flakey.) 3802 */ 3803 NFSLOCKSTATE(); 3804 if (clp->lc_flags & LCL_CBDOWN) 3805 clp->lc_flags &= ~(LCL_CBDOWN | LCL_CALLBACKSON); 3806 NFSUNLOCKSTATE(); 3807 if (nd->nd_repstat) 3808 error = nd->nd_repstat; 3809 else if (procnum == NFSV4OP_CBGETATTR) 3810 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3811 NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, 3812 p, NULL); 3813 mbuf_freem(nd->nd_mrep); 3814 } 3815 NFSLOCKSTATE(); 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);
|
3793 return (error); 3794} 3795 3796/* 3797 * Return the next index# for a clientid. Mostly just increment and return 3798 * the next one, but... if the 32bit unsigned does actually wrap around, 3799 * it should be rebooted. 3800 * At an average rate of one new client per second, it will wrap around in 3801 * approximately 136 years. (I think the server will have been shut 3802 * down or rebooted before then.) 3803 */ 3804static u_int32_t 3805nfsrv_nextclientindex(void) 3806{ 3807 static u_int32_t client_index = 0; 3808 3809 client_index++; 3810 if (client_index != 0) 3811 return (client_index); 3812 3813 printf("%s: out of clientids\n", __func__); 3814 return (client_index); 3815} 3816 3817/* 3818 * Return the next index# for a stateid. Mostly just increment and return 3819 * the next one, but... if the 32bit unsigned does actually wrap around 3820 * (will a BSD server stay up that long?), find 3821 * new start and end values. 3822 */ 3823static u_int32_t 3824nfsrv_nextstateindex(struct nfsclient *clp) 3825{ 3826 struct nfsstate *stp; 3827 int i; 3828 u_int32_t canuse, min_index, max_index; 3829 3830 if (!(clp->lc_flags & LCL_INDEXNOTOK)) { 3831 clp->lc_stateindex++; 3832 if (clp->lc_stateindex != clp->lc_statemaxindex) 3833 return (clp->lc_stateindex); 3834 } 3835 3836 /* 3837 * Yuck, we've hit the end. 3838 * Look for a new min and max. 3839 */ 3840 min_index = 0; 3841 max_index = 0xffffffff; 3842 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 3843 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 3844 if (stp->ls_stateid.other[2] > 0x80000000) { 3845 if (stp->ls_stateid.other[2] < max_index) 3846 max_index = stp->ls_stateid.other[2]; 3847 } else { 3848 if (stp->ls_stateid.other[2] > min_index) 3849 min_index = stp->ls_stateid.other[2]; 3850 } 3851 } 3852 } 3853 3854 /* 3855 * Yikes, highly unlikely, but I'll handle it anyhow. 3856 */ 3857 if (min_index == 0x80000000 && max_index == 0x80000001) { 3858 canuse = 0; 3859 /* 3860 * Loop around until we find an unused entry. Return that 3861 * and set LCL_INDEXNOTOK, so the search will continue next time. 3862 * (This is one of those rare cases where a goto is the 3863 * cleanest way to code the loop.) 3864 */ 3865tryagain: 3866 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 3867 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 3868 if (stp->ls_stateid.other[2] == canuse) { 3869 canuse++; 3870 goto tryagain; 3871 } 3872 } 3873 } 3874 clp->lc_flags |= LCL_INDEXNOTOK; 3875 return (canuse); 3876 } 3877 3878 /* 3879 * Ok to start again from min + 1. 3880 */ 3881 clp->lc_stateindex = min_index + 1; 3882 clp->lc_statemaxindex = max_index; 3883 clp->lc_flags &= ~LCL_INDEXNOTOK; 3884 return (clp->lc_stateindex); 3885} 3886 3887/* 3888 * The following functions handle the stable storage file that deals with 3889 * the edge conditions described in RFC3530 Sec. 8.6.3. 3890 * The file is as follows: 3891 * - a single record at the beginning that has the lease time of the 3892 * previous server instance (before the last reboot) and the nfsrvboottime 3893 * values for the previous server boots. 3894 * These previous boot times are used to ensure that the current 3895 * nfsrvboottime does not, somehow, get set to a previous one. 3896 * (This is important so that Stale ClientIDs and StateIDs can 3897 * be recognized.) 3898 * The number of previous nfsvrboottime values preceeds the list. 3899 * - followed by some number of appended records with: 3900 * - client id string 3901 * - flag that indicates it is a record revoking state via lease 3902 * expiration or similar 3903 * OR has successfully acquired state. 3904 * These structures vary in length, with the client string at the end, up 3905 * to NFSV4_OPAQUELIMIT in size. 3906 * 3907 * At the end of the grace period, the file is truncated, the first 3908 * record is rewritten with updated information and any acquired state 3909 * records for successful reclaims of state are written. 3910 * 3911 * Subsequent records are appended when the first state is issued to 3912 * a client and when state is revoked for a client. 3913 * 3914 * When reading the file in, state issued records that come later in 3915 * the file override older ones, since the append log is in cronological order. 3916 * If, for some reason, the file can't be read, the grace period is 3917 * immediately terminated and all reclaims get NFSERR_NOGRACE. 3918 */ 3919 3920/* 3921 * Read in the stable storage file. Called by nfssvc() before the nfsd 3922 * processes start servicing requests. 3923 */ 3924APPLESTATIC void 3925nfsrv_setupstable(NFSPROC_T *p) 3926{ 3927 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 3928 struct nfsrv_stable *sp, *nsp; 3929 struct nfst_rec *tsp; 3930 int error, i, tryagain; 3931 off_t off = 0; 3932 int aresid, len; 3933 struct timeval curtime; 3934 3935 /* 3936 * If NFSNSF_UPDATEDONE is set, this is a restart of the nfsds without 3937 * a reboot, so state has not been lost. 3938 */ 3939 if (sf->nsf_flags & NFSNSF_UPDATEDONE) 3940 return; 3941 /* 3942 * Set Grace over just until the file reads successfully. 3943 */ 3944 NFSGETTIME(&curtime); 3945 nfsrvboottime = curtime.tv_sec; 3946 LIST_INIT(&sf->nsf_head); 3947 sf->nsf_flags = (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK); 3948 sf->nsf_eograce = NFSD_MONOSEC + NFSRV_LEASEDELTA; 3949 if (sf->nsf_fp == NULL) 3950 return; 3951 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 3952 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), off, UIO_SYSSPACE, 3953 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 3954 if (error || aresid || sf->nsf_numboots == 0 || 3955 sf->nsf_numboots > NFSNSF_MAXNUMBOOTS) 3956 return; 3957 3958 /* 3959 * Now, read in the boottimes. 3960 */ 3961 sf->nsf_bootvals = (time_t *)malloc((sf->nsf_numboots + 1) * 3962 sizeof (time_t), M_TEMP, M_WAITOK); 3963 off = sizeof (struct nfsf_rec); 3964 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 3965 (caddr_t)sf->nsf_bootvals, sf->nsf_numboots * sizeof (time_t), off, 3966 UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 3967 if (error || aresid) { 3968 free((caddr_t)sf->nsf_bootvals, M_TEMP); 3969 sf->nsf_bootvals = NULL; 3970 return; 3971 } 3972 3973 /* 3974 * Make sure this nfsrvboottime is different from all recorded 3975 * previous ones. 3976 */ 3977 do { 3978 tryagain = 0; 3979 for (i = 0; i < sf->nsf_numboots; i++) { 3980 if (nfsrvboottime == sf->nsf_bootvals[i]) { 3981 nfsrvboottime++; 3982 tryagain = 1; 3983 break; 3984 } 3985 } 3986 } while (tryagain); 3987 3988 sf->nsf_flags |= NFSNSF_OK; 3989 off += (sf->nsf_numboots * sizeof (time_t)); 3990 3991 /* 3992 * Read through the file, building a list of records for grace 3993 * checking. 3994 * Each record is between sizeof (struct nfst_rec) and 3995 * sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1 3996 * and is actually sizeof (struct nfst_rec) + nst_len - 1. 3997 */ 3998 tsp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) + 3999 NFSV4_OPAQUELIMIT - 1, M_TEMP, M_WAITOK); 4000 do { 4001 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 4002 (caddr_t)tsp, sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1, 4003 off, UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 4004 len = (sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1) - aresid; 4005 if (error || (len > 0 && (len < sizeof (struct nfst_rec) || 4006 len < (sizeof (struct nfst_rec) + tsp->len - 1)))) { 4007 /* 4008 * Yuck, the file has been corrupted, so just return 4009 * after clearing out any restart state, so the grace period 4010 * is over. 4011 */ 4012 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) { 4013 LIST_REMOVE(sp, nst_list); 4014 free((caddr_t)sp, M_TEMP); 4015 } 4016 free((caddr_t)tsp, M_TEMP); 4017 sf->nsf_flags &= ~NFSNSF_OK; 4018 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4019 sf->nsf_bootvals = NULL; 4020 return; 4021 } 4022 if (len > 0) { 4023 off += sizeof (struct nfst_rec) + tsp->len - 1; 4024 /* 4025 * Search the list for a matching client. 4026 */ 4027 LIST_FOREACH(sp, &sf->nsf_head, nst_list) { 4028 if (tsp->len == sp->nst_len && 4029 !NFSBCMP(tsp->client, sp->nst_client, tsp->len)) 4030 break; 4031 } 4032 if (sp == LIST_END(&sf->nsf_head)) { 4033 sp = (struct nfsrv_stable *)malloc(tsp->len + 4034 sizeof (struct nfsrv_stable) - 1, M_TEMP, 4035 M_WAITOK); 4036 NFSBCOPY((caddr_t)tsp, (caddr_t)&sp->nst_rec, 4037 sizeof (struct nfst_rec) + tsp->len - 1); 4038 LIST_INSERT_HEAD(&sf->nsf_head, sp, nst_list); 4039 } else { 4040 if (tsp->flag == NFSNST_REVOKE) 4041 sp->nst_flag |= NFSNST_REVOKE; 4042 else 4043 /* 4044 * A subsequent timestamp indicates the client 4045 * did a setclientid/confirm and any previous 4046 * revoke is no longer relevant. 4047 */ 4048 sp->nst_flag &= ~NFSNST_REVOKE; 4049 } 4050 } 4051 } while (len > 0); 4052 free((caddr_t)tsp, M_TEMP); 4053 sf->nsf_flags = NFSNSF_OK; 4054 sf->nsf_eograce = NFSD_MONOSEC + sf->nsf_lease + 4055 NFSRV_LEASEDELTA; 4056} 4057 4058/* 4059 * Update the stable storage file, now that the grace period is over. 4060 */ 4061APPLESTATIC void 4062nfsrv_updatestable(NFSPROC_T *p) 4063{ 4064 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4065 struct nfsrv_stable *sp, *nsp; 4066 int i; 4067 struct nfsvattr nva; 4068 vnode_t vp; 4069#if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000) 4070 mount_t mp = NULL; 4071#endif 4072 int error; 4073 4074 if (sf->nsf_fp == NULL || (sf->nsf_flags & NFSNSF_UPDATEDONE)) 4075 return; 4076 sf->nsf_flags |= NFSNSF_UPDATEDONE; 4077 /* 4078 * Ok, we need to rewrite the stable storage file. 4079 * - truncate to 0 length 4080 * - write the new first structure 4081 * - loop through the data structures, writing out any that 4082 * have timestamps older than the old boot 4083 */ 4084 if (sf->nsf_bootvals) { 4085 sf->nsf_numboots++; 4086 for (i = sf->nsf_numboots - 2; i >= 0; i--) 4087 sf->nsf_bootvals[i + 1] = sf->nsf_bootvals[i]; 4088 } else { 4089 sf->nsf_numboots = 1; 4090 sf->nsf_bootvals = (time_t *)malloc(sizeof (time_t), 4091 M_TEMP, M_WAITOK); 4092 } 4093 sf->nsf_bootvals[0] = nfsrvboottime; 4094 sf->nsf_lease = nfsrv_lease; 4095 NFSVNO_ATTRINIT(&nva); 4096 NFSVNO_SETATTRVAL(&nva, size, 0); 4097 vp = NFSFPVNODE(sf->nsf_fp); 4098 vn_start_write(vp, &mp, V_WAIT); 4099 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) { 4100 error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p, 4101 NULL); 4102 NFSVOPUNLOCK(vp, 0); 4103 } else 4104 error = EPERM; 4105 vn_finished_write(mp); 4106 if (!error) 4107 error = NFSD_RDWR(UIO_WRITE, vp, 4108 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), (off_t)0, 4109 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p); 4110 if (!error) 4111 error = NFSD_RDWR(UIO_WRITE, vp, 4112 (caddr_t)sf->nsf_bootvals, 4113 sf->nsf_numboots * sizeof (time_t), 4114 (off_t)(sizeof (struct nfsf_rec)), 4115 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p); 4116 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4117 sf->nsf_bootvals = NULL; 4118 if (error) { 4119 sf->nsf_flags &= ~NFSNSF_OK; 4120 printf("EEK! Can't write NfsV4 stable storage file\n"); 4121 return; 4122 } 4123 sf->nsf_flags |= NFSNSF_OK; 4124 4125 /* 4126 * Loop through the list and write out timestamp records for 4127 * any clients that successfully reclaimed state. 4128 */ 4129 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) { 4130 if (sp->nst_flag & NFSNST_GOTSTATE) { 4131 nfsrv_writestable(sp->nst_client, sp->nst_len, 4132 NFSNST_NEWSTATE, p); 4133 sp->nst_clp->lc_flags |= LCL_STAMPEDSTABLE; 4134 } 4135 LIST_REMOVE(sp, nst_list); 4136 free((caddr_t)sp, M_TEMP); 4137 } 4138 nfsrv_backupstable(); 4139} 4140 4141/* 4142 * Append a record to the stable storage file. 4143 */ 4144APPLESTATIC void 4145nfsrv_writestable(u_char *client, int len, int flag, NFSPROC_T *p) 4146{ 4147 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4148 struct nfst_rec *sp; 4149 int error; 4150 4151 if (!(sf->nsf_flags & NFSNSF_OK) || sf->nsf_fp == NULL) 4152 return; 4153 sp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) + 4154 len - 1, M_TEMP, M_WAITOK); 4155 sp->len = len; 4156 NFSBCOPY(client, sp->client, len); 4157 sp->flag = flag; 4158 error = NFSD_RDWR(UIO_WRITE, NFSFPVNODE(sf->nsf_fp), 4159 (caddr_t)sp, sizeof (struct nfst_rec) + len - 1, (off_t)0, 4160 UIO_SYSSPACE, (IO_SYNC | IO_APPEND), NFSFPCRED(sf->nsf_fp), NULL, p); 4161 free((caddr_t)sp, M_TEMP); 4162 if (error) { 4163 sf->nsf_flags &= ~NFSNSF_OK; 4164 printf("EEK! Can't write NfsV4 stable storage file\n"); 4165 } 4166} 4167 4168/* 4169 * This function is called during the grace period to mark a client 4170 * that successfully reclaimed state. 4171 */ 4172static void 4173nfsrv_markstable(struct nfsclient *clp) 4174{ 4175 struct nfsrv_stable *sp; 4176 4177 /* 4178 * First find the client structure. 4179 */ 4180 LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { 4181 if (sp->nst_len == clp->lc_idlen && 4182 !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) 4183 break; 4184 } 4185 if (sp == LIST_END(&nfsrv_stablefirst.nsf_head)) 4186 return; 4187 4188 /* 4189 * Now, just mark it and set the nfsclient back pointer. 4190 */ 4191 sp->nst_flag |= NFSNST_GOTSTATE; 4192 sp->nst_clp = clp; 4193} 4194 4195/* 4196 * This function is called for a reclaim, to see if it gets grace. 4197 * It returns 0 if a reclaim is allowed, 1 otherwise. 4198 */ 4199static int 4200nfsrv_checkstable(struct nfsclient *clp) 4201{ 4202 struct nfsrv_stable *sp; 4203 4204 /* 4205 * First, find the entry for the client. 4206 */ 4207 LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { 4208 if (sp->nst_len == clp->lc_idlen && 4209 !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) 4210 break; 4211 } 4212 4213 /* 4214 * If not in the list, state was revoked or no state was issued 4215 * since the previous reboot, a reclaim is denied. 4216 */ 4217 if (sp == LIST_END(&nfsrv_stablefirst.nsf_head) || 4218 (sp->nst_flag & NFSNST_REVOKE) || 4219 !(nfsrv_stablefirst.nsf_flags & NFSNSF_OK)) 4220 return (1); 4221 return (0); 4222} 4223 4224/* 4225 * Test for and try to clear out a conflicting client. This is called by 4226 * nfsrv_lockctrl() and nfsrv_openctrl() when conflicts with other clients 4227 * a found. 4228 * The trick here is that it can't revoke a conflicting client with an 4229 * expired lease unless it holds the v4root lock, so... 4230 * If no v4root lock, get the lock and return 1 to indicate "try again". 4231 * Return 0 to indicate the conflict can't be revoked and 1 to indicate 4232 * the revocation worked and the conflicting client is "bye, bye", so it 4233 * can be tried again. 4234 * Return 2 to indicate that the vnode is VI_DOOMED after NFSVOPLOCK(). 4235 * Unlocks State before a non-zero value is returned. 4236 */ 4237static int 4238nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, vnode_t vp, 4239 NFSPROC_T *p) 4240{ 4241 int gotlock, lktype; 4242 4243 /* 4244 * If lease hasn't expired, we can't fix it. 4245 */ 4246 if (clp->lc_expiry >= NFSD_MONOSEC || 4247 !(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) 4248 return (0); 4249 if (*haslockp == 0) { 4250 NFSUNLOCKSTATE(); 4251 lktype = NFSVOPISLOCKED(vp); 4252 NFSVOPUNLOCK(vp, 0); 4253 NFSLOCKV4ROOTMUTEX(); 4254 nfsv4_relref(&nfsv4rootfs_lock); 4255 do { 4256 gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 4257 NFSV4ROOTLOCKMUTEXPTR, NULL); 4258 } while (!gotlock); 4259 NFSUNLOCKV4ROOTMUTEX(); 4260 *haslockp = 1; 4261 NFSVOPLOCK(vp, lktype | LK_RETRY); 4262 if ((vp->v_iflag & VI_DOOMED) != 0) 4263 return (2); 4264 else 4265 return (1); 4266 } 4267 NFSUNLOCKSTATE(); 4268 4269 /* 4270 * Ok, we can expire the conflicting client. 4271 */ 4272 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 4273 nfsrv_backupstable(); 4274 nfsrv_cleanclient(clp, p); 4275 nfsrv_freedeleglist(&clp->lc_deleg); 4276 nfsrv_freedeleglist(&clp->lc_olddeleg); 4277 LIST_REMOVE(clp, lc_hash); 4278 nfsrv_zapclient(clp, p); 4279 return (1); 4280} 4281 4282/* 4283 * Resolve a delegation conflict. 4284 * Returns 0 to indicate the conflict was resolved without sleeping. 4285 * Return -1 to indicate that the caller should check for conflicts again. 4286 * Return > 0 for an error that should be returned, normally NFSERR_DELAY. 4287 * 4288 * Also, manipulate the nfsv4root_lock, as required. It isn't changed 4289 * for a return of 0, since there was no sleep and it could be required 4290 * later. It is released for a return of NFSERR_DELAY, since the caller 4291 * will return that error. It is released when a sleep was done waiting 4292 * for the delegation to be returned or expire (so that other nfsds can 4293 * handle ops). Then, it must be acquired for the write to stable storage. 4294 * (This function is somewhat similar to nfsrv_clientconflict(), but 4295 * the semantics differ in a couple of subtle ways. The return of 0 4296 * indicates the conflict was resolved without sleeping here, not 4297 * that the conflict can't be resolved and the handling of nfsv4root_lock 4298 * differs, as noted above.) 4299 * Unlocks State before returning a non-zero value. 4300 */ 4301static int 4302nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p, 4303 vnode_t vp) 4304{ 4305 struct nfsclient *clp = stp->ls_clp; 4306 int gotlock, error, lktype, retrycnt, zapped_clp; 4307 nfsv4stateid_t tstateid; 4308 fhandle_t tfh; 4309 4310 /* 4311 * If the conflict is with an old delegation... 4312 */ 4313 if (stp->ls_flags & NFSLCK_OLDDELEG) { 4314 /* 4315 * You can delete it, if it has expired. 4316 */ 4317 if (clp->lc_delegtime < NFSD_MONOSEC) { 4318 nfsrv_freedeleg(stp); 4319 NFSUNLOCKSTATE();
| 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 3834 * approximately 136 years. (I think the server will have been shut 3835 * down or rebooted before then.) 3836 */ 3837static u_int32_t 3838nfsrv_nextclientindex(void) 3839{ 3840 static u_int32_t client_index = 0; 3841 3842 client_index++; 3843 if (client_index != 0) 3844 return (client_index); 3845 3846 printf("%s: out of clientids\n", __func__); 3847 return (client_index); 3848} 3849 3850/* 3851 * Return the next index# for a stateid. Mostly just increment and return 3852 * the next one, but... if the 32bit unsigned does actually wrap around 3853 * (will a BSD server stay up that long?), find 3854 * new start and end values. 3855 */ 3856static u_int32_t 3857nfsrv_nextstateindex(struct nfsclient *clp) 3858{ 3859 struct nfsstate *stp; 3860 int i; 3861 u_int32_t canuse, min_index, max_index; 3862 3863 if (!(clp->lc_flags & LCL_INDEXNOTOK)) { 3864 clp->lc_stateindex++; 3865 if (clp->lc_stateindex != clp->lc_statemaxindex) 3866 return (clp->lc_stateindex); 3867 } 3868 3869 /* 3870 * Yuck, we've hit the end. 3871 * Look for a new min and max. 3872 */ 3873 min_index = 0; 3874 max_index = 0xffffffff; 3875 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 3876 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 3877 if (stp->ls_stateid.other[2] > 0x80000000) { 3878 if (stp->ls_stateid.other[2] < max_index) 3879 max_index = stp->ls_stateid.other[2]; 3880 } else { 3881 if (stp->ls_stateid.other[2] > min_index) 3882 min_index = stp->ls_stateid.other[2]; 3883 } 3884 } 3885 } 3886 3887 /* 3888 * Yikes, highly unlikely, but I'll handle it anyhow. 3889 */ 3890 if (min_index == 0x80000000 && max_index == 0x80000001) { 3891 canuse = 0; 3892 /* 3893 * Loop around until we find an unused entry. Return that 3894 * and set LCL_INDEXNOTOK, so the search will continue next time. 3895 * (This is one of those rare cases where a goto is the 3896 * cleanest way to code the loop.) 3897 */ 3898tryagain: 3899 for (i = 0; i < NFSSTATEHASHSIZE; i++) { 3900 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) { 3901 if (stp->ls_stateid.other[2] == canuse) { 3902 canuse++; 3903 goto tryagain; 3904 } 3905 } 3906 } 3907 clp->lc_flags |= LCL_INDEXNOTOK; 3908 return (canuse); 3909 } 3910 3911 /* 3912 * Ok to start again from min + 1. 3913 */ 3914 clp->lc_stateindex = min_index + 1; 3915 clp->lc_statemaxindex = max_index; 3916 clp->lc_flags &= ~LCL_INDEXNOTOK; 3917 return (clp->lc_stateindex); 3918} 3919 3920/* 3921 * The following functions handle the stable storage file that deals with 3922 * the edge conditions described in RFC3530 Sec. 8.6.3. 3923 * The file is as follows: 3924 * - a single record at the beginning that has the lease time of the 3925 * previous server instance (before the last reboot) and the nfsrvboottime 3926 * values for the previous server boots. 3927 * These previous boot times are used to ensure that the current 3928 * nfsrvboottime does not, somehow, get set to a previous one. 3929 * (This is important so that Stale ClientIDs and StateIDs can 3930 * be recognized.) 3931 * The number of previous nfsvrboottime values preceeds the list. 3932 * - followed by some number of appended records with: 3933 * - client id string 3934 * - flag that indicates it is a record revoking state via lease 3935 * expiration or similar 3936 * OR has successfully acquired state. 3937 * These structures vary in length, with the client string at the end, up 3938 * to NFSV4_OPAQUELIMIT in size. 3939 * 3940 * At the end of the grace period, the file is truncated, the first 3941 * record is rewritten with updated information and any acquired state 3942 * records for successful reclaims of state are written. 3943 * 3944 * Subsequent records are appended when the first state is issued to 3945 * a client and when state is revoked for a client. 3946 * 3947 * When reading the file in, state issued records that come later in 3948 * the file override older ones, since the append log is in cronological order. 3949 * If, for some reason, the file can't be read, the grace period is 3950 * immediately terminated and all reclaims get NFSERR_NOGRACE. 3951 */ 3952 3953/* 3954 * Read in the stable storage file. Called by nfssvc() before the nfsd 3955 * processes start servicing requests. 3956 */ 3957APPLESTATIC void 3958nfsrv_setupstable(NFSPROC_T *p) 3959{ 3960 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 3961 struct nfsrv_stable *sp, *nsp; 3962 struct nfst_rec *tsp; 3963 int error, i, tryagain; 3964 off_t off = 0; 3965 int aresid, len; 3966 struct timeval curtime; 3967 3968 /* 3969 * If NFSNSF_UPDATEDONE is set, this is a restart of the nfsds without 3970 * a reboot, so state has not been lost. 3971 */ 3972 if (sf->nsf_flags & NFSNSF_UPDATEDONE) 3973 return; 3974 /* 3975 * Set Grace over just until the file reads successfully. 3976 */ 3977 NFSGETTIME(&curtime); 3978 nfsrvboottime = curtime.tv_sec; 3979 LIST_INIT(&sf->nsf_head); 3980 sf->nsf_flags = (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK); 3981 sf->nsf_eograce = NFSD_MONOSEC + NFSRV_LEASEDELTA; 3982 if (sf->nsf_fp == NULL) 3983 return; 3984 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 3985 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), off, UIO_SYSSPACE, 3986 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 3987 if (error || aresid || sf->nsf_numboots == 0 || 3988 sf->nsf_numboots > NFSNSF_MAXNUMBOOTS) 3989 return; 3990 3991 /* 3992 * Now, read in the boottimes. 3993 */ 3994 sf->nsf_bootvals = (time_t *)malloc((sf->nsf_numboots + 1) * 3995 sizeof (time_t), M_TEMP, M_WAITOK); 3996 off = sizeof (struct nfsf_rec); 3997 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 3998 (caddr_t)sf->nsf_bootvals, sf->nsf_numboots * sizeof (time_t), off, 3999 UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 4000 if (error || aresid) { 4001 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4002 sf->nsf_bootvals = NULL; 4003 return; 4004 } 4005 4006 /* 4007 * Make sure this nfsrvboottime is different from all recorded 4008 * previous ones. 4009 */ 4010 do { 4011 tryagain = 0; 4012 for (i = 0; i < sf->nsf_numboots; i++) { 4013 if (nfsrvboottime == sf->nsf_bootvals[i]) { 4014 nfsrvboottime++; 4015 tryagain = 1; 4016 break; 4017 } 4018 } 4019 } while (tryagain); 4020 4021 sf->nsf_flags |= NFSNSF_OK; 4022 off += (sf->nsf_numboots * sizeof (time_t)); 4023 4024 /* 4025 * Read through the file, building a list of records for grace 4026 * checking. 4027 * Each record is between sizeof (struct nfst_rec) and 4028 * sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1 4029 * and is actually sizeof (struct nfst_rec) + nst_len - 1. 4030 */ 4031 tsp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) + 4032 NFSV4_OPAQUELIMIT - 1, M_TEMP, M_WAITOK); 4033 do { 4034 error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp), 4035 (caddr_t)tsp, sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1, 4036 off, UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p); 4037 len = (sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1) - aresid; 4038 if (error || (len > 0 && (len < sizeof (struct nfst_rec) || 4039 len < (sizeof (struct nfst_rec) + tsp->len - 1)))) { 4040 /* 4041 * Yuck, the file has been corrupted, so just return 4042 * after clearing out any restart state, so the grace period 4043 * is over. 4044 */ 4045 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) { 4046 LIST_REMOVE(sp, nst_list); 4047 free((caddr_t)sp, M_TEMP); 4048 } 4049 free((caddr_t)tsp, M_TEMP); 4050 sf->nsf_flags &= ~NFSNSF_OK; 4051 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4052 sf->nsf_bootvals = NULL; 4053 return; 4054 } 4055 if (len > 0) { 4056 off += sizeof (struct nfst_rec) + tsp->len - 1; 4057 /* 4058 * Search the list for a matching client. 4059 */ 4060 LIST_FOREACH(sp, &sf->nsf_head, nst_list) { 4061 if (tsp->len == sp->nst_len && 4062 !NFSBCMP(tsp->client, sp->nst_client, tsp->len)) 4063 break; 4064 } 4065 if (sp == LIST_END(&sf->nsf_head)) { 4066 sp = (struct nfsrv_stable *)malloc(tsp->len + 4067 sizeof (struct nfsrv_stable) - 1, M_TEMP, 4068 M_WAITOK); 4069 NFSBCOPY((caddr_t)tsp, (caddr_t)&sp->nst_rec, 4070 sizeof (struct nfst_rec) + tsp->len - 1); 4071 LIST_INSERT_HEAD(&sf->nsf_head, sp, nst_list); 4072 } else { 4073 if (tsp->flag == NFSNST_REVOKE) 4074 sp->nst_flag |= NFSNST_REVOKE; 4075 else 4076 /* 4077 * A subsequent timestamp indicates the client 4078 * did a setclientid/confirm and any previous 4079 * revoke is no longer relevant. 4080 */ 4081 sp->nst_flag &= ~NFSNST_REVOKE; 4082 } 4083 } 4084 } while (len > 0); 4085 free((caddr_t)tsp, M_TEMP); 4086 sf->nsf_flags = NFSNSF_OK; 4087 sf->nsf_eograce = NFSD_MONOSEC + sf->nsf_lease + 4088 NFSRV_LEASEDELTA; 4089} 4090 4091/* 4092 * Update the stable storage file, now that the grace period is over. 4093 */ 4094APPLESTATIC void 4095nfsrv_updatestable(NFSPROC_T *p) 4096{ 4097 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4098 struct nfsrv_stable *sp, *nsp; 4099 int i; 4100 struct nfsvattr nva; 4101 vnode_t vp; 4102#if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000) 4103 mount_t mp = NULL; 4104#endif 4105 int error; 4106 4107 if (sf->nsf_fp == NULL || (sf->nsf_flags & NFSNSF_UPDATEDONE)) 4108 return; 4109 sf->nsf_flags |= NFSNSF_UPDATEDONE; 4110 /* 4111 * Ok, we need to rewrite the stable storage file. 4112 * - truncate to 0 length 4113 * - write the new first structure 4114 * - loop through the data structures, writing out any that 4115 * have timestamps older than the old boot 4116 */ 4117 if (sf->nsf_bootvals) { 4118 sf->nsf_numboots++; 4119 for (i = sf->nsf_numboots - 2; i >= 0; i--) 4120 sf->nsf_bootvals[i + 1] = sf->nsf_bootvals[i]; 4121 } else { 4122 sf->nsf_numboots = 1; 4123 sf->nsf_bootvals = (time_t *)malloc(sizeof (time_t), 4124 M_TEMP, M_WAITOK); 4125 } 4126 sf->nsf_bootvals[0] = nfsrvboottime; 4127 sf->nsf_lease = nfsrv_lease; 4128 NFSVNO_ATTRINIT(&nva); 4129 NFSVNO_SETATTRVAL(&nva, size, 0); 4130 vp = NFSFPVNODE(sf->nsf_fp); 4131 vn_start_write(vp, &mp, V_WAIT); 4132 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) { 4133 error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p, 4134 NULL); 4135 NFSVOPUNLOCK(vp, 0); 4136 } else 4137 error = EPERM; 4138 vn_finished_write(mp); 4139 if (!error) 4140 error = NFSD_RDWR(UIO_WRITE, vp, 4141 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), (off_t)0, 4142 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p); 4143 if (!error) 4144 error = NFSD_RDWR(UIO_WRITE, vp, 4145 (caddr_t)sf->nsf_bootvals, 4146 sf->nsf_numboots * sizeof (time_t), 4147 (off_t)(sizeof (struct nfsf_rec)), 4148 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p); 4149 free((caddr_t)sf->nsf_bootvals, M_TEMP); 4150 sf->nsf_bootvals = NULL; 4151 if (error) { 4152 sf->nsf_flags &= ~NFSNSF_OK; 4153 printf("EEK! Can't write NfsV4 stable storage file\n"); 4154 return; 4155 } 4156 sf->nsf_flags |= NFSNSF_OK; 4157 4158 /* 4159 * Loop through the list and write out timestamp records for 4160 * any clients that successfully reclaimed state. 4161 */ 4162 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) { 4163 if (sp->nst_flag & NFSNST_GOTSTATE) { 4164 nfsrv_writestable(sp->nst_client, sp->nst_len, 4165 NFSNST_NEWSTATE, p); 4166 sp->nst_clp->lc_flags |= LCL_STAMPEDSTABLE; 4167 } 4168 LIST_REMOVE(sp, nst_list); 4169 free((caddr_t)sp, M_TEMP); 4170 } 4171 nfsrv_backupstable(); 4172} 4173 4174/* 4175 * Append a record to the stable storage file. 4176 */ 4177APPLESTATIC void 4178nfsrv_writestable(u_char *client, int len, int flag, NFSPROC_T *p) 4179{ 4180 struct nfsrv_stablefirst *sf = &nfsrv_stablefirst; 4181 struct nfst_rec *sp; 4182 int error; 4183 4184 if (!(sf->nsf_flags & NFSNSF_OK) || sf->nsf_fp == NULL) 4185 return; 4186 sp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) + 4187 len - 1, M_TEMP, M_WAITOK); 4188 sp->len = len; 4189 NFSBCOPY(client, sp->client, len); 4190 sp->flag = flag; 4191 error = NFSD_RDWR(UIO_WRITE, NFSFPVNODE(sf->nsf_fp), 4192 (caddr_t)sp, sizeof (struct nfst_rec) + len - 1, (off_t)0, 4193 UIO_SYSSPACE, (IO_SYNC | IO_APPEND), NFSFPCRED(sf->nsf_fp), NULL, p); 4194 free((caddr_t)sp, M_TEMP); 4195 if (error) { 4196 sf->nsf_flags &= ~NFSNSF_OK; 4197 printf("EEK! Can't write NfsV4 stable storage file\n"); 4198 } 4199} 4200 4201/* 4202 * This function is called during the grace period to mark a client 4203 * that successfully reclaimed state. 4204 */ 4205static void 4206nfsrv_markstable(struct nfsclient *clp) 4207{ 4208 struct nfsrv_stable *sp; 4209 4210 /* 4211 * First find the client structure. 4212 */ 4213 LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { 4214 if (sp->nst_len == clp->lc_idlen && 4215 !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) 4216 break; 4217 } 4218 if (sp == LIST_END(&nfsrv_stablefirst.nsf_head)) 4219 return; 4220 4221 /* 4222 * Now, just mark it and set the nfsclient back pointer. 4223 */ 4224 sp->nst_flag |= NFSNST_GOTSTATE; 4225 sp->nst_clp = clp; 4226} 4227 4228/* 4229 * This function is called for a reclaim, to see if it gets grace. 4230 * It returns 0 if a reclaim is allowed, 1 otherwise. 4231 */ 4232static int 4233nfsrv_checkstable(struct nfsclient *clp) 4234{ 4235 struct nfsrv_stable *sp; 4236 4237 /* 4238 * First, find the entry for the client. 4239 */ 4240 LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { 4241 if (sp->nst_len == clp->lc_idlen && 4242 !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) 4243 break; 4244 } 4245 4246 /* 4247 * If not in the list, state was revoked or no state was issued 4248 * since the previous reboot, a reclaim is denied. 4249 */ 4250 if (sp == LIST_END(&nfsrv_stablefirst.nsf_head) || 4251 (sp->nst_flag & NFSNST_REVOKE) || 4252 !(nfsrv_stablefirst.nsf_flags & NFSNSF_OK)) 4253 return (1); 4254 return (0); 4255} 4256 4257/* 4258 * Test for and try to clear out a conflicting client. This is called by 4259 * nfsrv_lockctrl() and nfsrv_openctrl() when conflicts with other clients 4260 * a found. 4261 * The trick here is that it can't revoke a conflicting client with an 4262 * expired lease unless it holds the v4root lock, so... 4263 * If no v4root lock, get the lock and return 1 to indicate "try again". 4264 * Return 0 to indicate the conflict can't be revoked and 1 to indicate 4265 * the revocation worked and the conflicting client is "bye, bye", so it 4266 * can be tried again. 4267 * Return 2 to indicate that the vnode is VI_DOOMED after NFSVOPLOCK(). 4268 * Unlocks State before a non-zero value is returned. 4269 */ 4270static int 4271nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, vnode_t vp, 4272 NFSPROC_T *p) 4273{ 4274 int gotlock, lktype; 4275 4276 /* 4277 * If lease hasn't expired, we can't fix it. 4278 */ 4279 if (clp->lc_expiry >= NFSD_MONOSEC || 4280 !(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) 4281 return (0); 4282 if (*haslockp == 0) { 4283 NFSUNLOCKSTATE(); 4284 lktype = NFSVOPISLOCKED(vp); 4285 NFSVOPUNLOCK(vp, 0); 4286 NFSLOCKV4ROOTMUTEX(); 4287 nfsv4_relref(&nfsv4rootfs_lock); 4288 do { 4289 gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 4290 NFSV4ROOTLOCKMUTEXPTR, NULL); 4291 } while (!gotlock); 4292 NFSUNLOCKV4ROOTMUTEX(); 4293 *haslockp = 1; 4294 NFSVOPLOCK(vp, lktype | LK_RETRY); 4295 if ((vp->v_iflag & VI_DOOMED) != 0) 4296 return (2); 4297 else 4298 return (1); 4299 } 4300 NFSUNLOCKSTATE(); 4301 4302 /* 4303 * Ok, we can expire the conflicting client. 4304 */ 4305 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 4306 nfsrv_backupstable(); 4307 nfsrv_cleanclient(clp, p); 4308 nfsrv_freedeleglist(&clp->lc_deleg); 4309 nfsrv_freedeleglist(&clp->lc_olddeleg); 4310 LIST_REMOVE(clp, lc_hash); 4311 nfsrv_zapclient(clp, p); 4312 return (1); 4313} 4314 4315/* 4316 * Resolve a delegation conflict. 4317 * Returns 0 to indicate the conflict was resolved without sleeping. 4318 * Return -1 to indicate that the caller should check for conflicts again. 4319 * Return > 0 for an error that should be returned, normally NFSERR_DELAY. 4320 * 4321 * Also, manipulate the nfsv4root_lock, as required. It isn't changed 4322 * for a return of 0, since there was no sleep and it could be required 4323 * later. It is released for a return of NFSERR_DELAY, since the caller 4324 * will return that error. It is released when a sleep was done waiting 4325 * for the delegation to be returned or expire (so that other nfsds can 4326 * handle ops). Then, it must be acquired for the write to stable storage. 4327 * (This function is somewhat similar to nfsrv_clientconflict(), but 4328 * the semantics differ in a couple of subtle ways. The return of 0 4329 * indicates the conflict was resolved without sleeping here, not 4330 * that the conflict can't be resolved and the handling of nfsv4root_lock 4331 * differs, as noted above.) 4332 * Unlocks State before returning a non-zero value. 4333 */ 4334static int 4335nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p, 4336 vnode_t vp) 4337{ 4338 struct nfsclient *clp = stp->ls_clp; 4339 int gotlock, error, lktype, retrycnt, zapped_clp; 4340 nfsv4stateid_t tstateid; 4341 fhandle_t tfh; 4342 4343 /* 4344 * If the conflict is with an old delegation... 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();
|
4320 return (-1);
| 4353 error = -1; 4354 goto out;
|
4321 } 4322 NFSUNLOCKSTATE(); 4323 /* 4324 * During this delay, the old delegation could expire or it 4325 * could be recovered by the client via an Open with 4326 * CLAIM_DELEGATE_PREV. 4327 * Release the nfsv4root_lock, if held. 4328 */ 4329 if (*haslockp) { 4330 *haslockp = 0; 4331 NFSLOCKV4ROOTMUTEX(); 4332 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4333 NFSUNLOCKV4ROOTMUTEX(); 4334 }
| 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 }
|
4335 return (NFSERR_DELAY);
| 4369 error = NFSERR_DELAY; 4370 goto out;
|
4336 } 4337 4338 /* 4339 * It's a current delegation, so: 4340 * - check to see if the delegation has expired 4341 * - if so, get the v4root lock and then expire it 4342 */ 4343 if (!(stp->ls_flags & NFSLCK_DELEGRECALL)) { 4344 /* 4345 * - do a recall callback, since not yet done 4346 * For now, never allow truncate to be set. To use 4347 * truncate safely, it must be guaranteed that the 4348 * Remove, Rename or Setattr with size of 0 will 4349 * succeed and that would require major changes to 4350 * the VFS/Vnode OPs. 4351 * Set the expiry time large enough so that it won't expire 4352 * until after the callback, then set it correctly, once 4353 * the callback is done. (The delegation will now time 4354 * out whether or not the Recall worked ok. The timeout 4355 * will be extended when ops are done on the delegation 4356 * stateid, up to the timelimit.) 4357 */ 4358 stp->ls_delegtime = NFSD_MONOSEC + (2 * nfsrv_lease) + 4359 NFSRV_LEASEDELTA; 4360 stp->ls_delegtimelimit = NFSD_MONOSEC + (6 * nfsrv_lease) + 4361 NFSRV_LEASEDELTA; 4362 stp->ls_flags |= NFSLCK_DELEGRECALL; 4363 4364 /* 4365 * Loop NFSRV_CBRETRYCNT times while the CBRecall replies 4366 * NFSERR_BADSTATEID or NFSERR_BADHANDLE. This is done 4367 * in order to try and avoid a race that could happen 4368 * when a CBRecall request passed the Open reply with 4369 * the delegation in it when transitting the network. 4370 * Since nfsrv_docallback will sleep, don't use stp after 4371 * the call. 4372 */ 4373 NFSBCOPY((caddr_t)&stp->ls_stateid, (caddr_t)&tstateid, 4374 sizeof (tstateid)); 4375 NFSBCOPY((caddr_t)&stp->ls_lfp->lf_fh, (caddr_t)&tfh, 4376 sizeof (tfh)); 4377 NFSUNLOCKSTATE(); 4378 if (*haslockp) { 4379 *haslockp = 0; 4380 NFSLOCKV4ROOTMUTEX(); 4381 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4382 NFSUNLOCKV4ROOTMUTEX(); 4383 } 4384 retrycnt = 0; 4385 do { 4386 error = nfsrv_docallback(clp, NFSV4OP_CBRECALL, 4387 &tstateid, 0, &tfh, NULL, NULL, p); 4388 retrycnt++; 4389 } while ((error == NFSERR_BADSTATEID || 4390 error == NFSERR_BADHANDLE) && retrycnt < NFSV4_CBRETRYCNT);
| 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)) { 4379 /* 4380 * - do a recall callback, since not yet done 4381 * For now, never allow truncate to be set. To use 4382 * truncate safely, it must be guaranteed that the 4383 * Remove, Rename or Setattr with size of 0 will 4384 * succeed and that would require major changes to 4385 * the VFS/Vnode OPs. 4386 * Set the expiry time large enough so that it won't expire 4387 * until after the callback, then set it correctly, once 4388 * the callback is done. (The delegation will now time 4389 * out whether or not the Recall worked ok. The timeout 4390 * will be extended when ops are done on the delegation 4391 * stateid, up to the timelimit.) 4392 */ 4393 stp->ls_delegtime = NFSD_MONOSEC + (2 * nfsrv_lease) + 4394 NFSRV_LEASEDELTA; 4395 stp->ls_delegtimelimit = NFSD_MONOSEC + (6 * nfsrv_lease) + 4396 NFSRV_LEASEDELTA; 4397 stp->ls_flags |= NFSLCK_DELEGRECALL; 4398 4399 /* 4400 * Loop NFSRV_CBRETRYCNT times while the CBRecall replies 4401 * NFSERR_BADSTATEID or NFSERR_BADHANDLE. This is done 4402 * in order to try and avoid a race that could happen 4403 * when a CBRecall request passed the Open reply with 4404 * the delegation in it when transitting the network. 4405 * Since nfsrv_docallback will sleep, don't use stp after 4406 * the call. 4407 */ 4408 NFSBCOPY((caddr_t)&stp->ls_stateid, (caddr_t)&tstateid, 4409 sizeof (tstateid)); 4410 NFSBCOPY((caddr_t)&stp->ls_lfp->lf_fh, (caddr_t)&tfh, 4411 sizeof (tfh)); 4412 NFSUNLOCKSTATE(); 4413 if (*haslockp) { 4414 *haslockp = 0; 4415 NFSLOCKV4ROOTMUTEX(); 4416 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4417 NFSUNLOCKV4ROOTMUTEX(); 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);
|
4391 return (NFSERR_DELAY);
| 4426 error = NFSERR_DELAY; 4427 goto out;
|
4392 } 4393 4394 if (clp->lc_expiry >= NFSD_MONOSEC && 4395 stp->ls_delegtime >= NFSD_MONOSEC) { 4396 NFSUNLOCKSTATE(); 4397 /* 4398 * A recall has been done, but it has not yet expired. 4399 * So, RETURN_DELAY. 4400 */ 4401 if (*haslockp) { 4402 *haslockp = 0; 4403 NFSLOCKV4ROOTMUTEX(); 4404 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4405 NFSUNLOCKV4ROOTMUTEX(); 4406 }
| 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 }
|
4407 return (NFSERR_DELAY);
| 4443 error = NFSERR_DELAY; 4444 goto out;
|
4408 } 4409 4410 /* 4411 * If we don't yet have the lock, just get it and then return, 4412 * since we need that before deleting expired state, such as 4413 * this delegation. 4414 * When getting the lock, unlock the vnode, so other nfsds that 4415 * are in progress, won't get stuck waiting for the vnode lock. 4416 */ 4417 if (*haslockp == 0) { 4418 NFSUNLOCKSTATE(); 4419 lktype = NFSVOPISLOCKED(vp); 4420 NFSVOPUNLOCK(vp, 0); 4421 NFSLOCKV4ROOTMUTEX(); 4422 nfsv4_relref(&nfsv4rootfs_lock); 4423 do { 4424 gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 4425 NFSV4ROOTLOCKMUTEXPTR, NULL); 4426 } while (!gotlock); 4427 NFSUNLOCKV4ROOTMUTEX(); 4428 *haslockp = 1; 4429 NFSVOPLOCK(vp, lktype | LK_RETRY); 4430 if ((vp->v_iflag & VI_DOOMED) != 0) { 4431 *haslockp = 0; 4432 NFSLOCKV4ROOTMUTEX(); 4433 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4434 NFSUNLOCKV4ROOTMUTEX();
| 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. 4453 */ 4454 if (*haslockp == 0) { 4455 NFSUNLOCKSTATE(); 4456 lktype = NFSVOPISLOCKED(vp); 4457 NFSVOPUNLOCK(vp, 0); 4458 NFSLOCKV4ROOTMUTEX(); 4459 nfsv4_relref(&nfsv4rootfs_lock); 4460 do { 4461 gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL, 4462 NFSV4ROOTLOCKMUTEXPTR, NULL); 4463 } while (!gotlock); 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();
|
4435 return (NFSERR_PERM);
| 4472 error = NFSERR_PERM; 4473 goto out;
|
4436 }
| 4474 }
|
4437 return (-1);
| 4475 error = -1; 4476 goto out;
|
4438 } 4439 4440 NFSUNLOCKSTATE(); 4441 /* 4442 * Ok, we can delete the expired delegation. 4443 * First, write the Revoke record to stable storage and then 4444 * clear out the conflict. 4445 * Since all other nfsd threads are now blocked, we can safely 4446 * sleep without the state changing. 4447 */ 4448 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 4449 nfsrv_backupstable(); 4450 if (clp->lc_expiry < NFSD_MONOSEC) { 4451 nfsrv_cleanclient(clp, p); 4452 nfsrv_freedeleglist(&clp->lc_deleg); 4453 nfsrv_freedeleglist(&clp->lc_olddeleg); 4454 LIST_REMOVE(clp, lc_hash); 4455 zapped_clp = 1; 4456 } else { 4457 nfsrv_freedeleg(stp); 4458 zapped_clp = 0; 4459 } 4460 if (zapped_clp) 4461 nfsrv_zapclient(clp, p);
| 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 4485 * sleep without the state changing. 4486 */ 4487 nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p); 4488 nfsrv_backupstable(); 4489 if (clp->lc_expiry < NFSD_MONOSEC) { 4490 nfsrv_cleanclient(clp, p); 4491 nfsrv_freedeleglist(&clp->lc_deleg); 4492 nfsrv_freedeleglist(&clp->lc_olddeleg); 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);
|
4462 return (-1);
| 4501 error = -1; 4502 4503out: 4504 NFSEXITCODE(error); 4505 return (error);
|
4463} 4464 4465/* 4466 * Check for a remove allowed, if remove is set to 1 and get rid of 4467 * delegations. 4468 */ 4469APPLESTATIC int 4470nfsrv_checkremove(vnode_t vp, int remove, NFSPROC_T *p) 4471{ 4472 struct nfsstate *stp; 4473 struct nfslockfile *lfp; 4474 int error, haslock = 0; 4475 fhandle_t nfh; 4476 4477 /* 4478 * First, get the lock file structure. 4479 * (A return of -1 means no associated state, so remove ok.) 4480 */ 4481 error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p); 4482tryagain: 4483 NFSLOCKSTATE(); 4484 if (!error) 4485 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0); 4486 if (error) { 4487 NFSUNLOCKSTATE(); 4488 if (haslock) { 4489 NFSLOCKV4ROOTMUTEX(); 4490 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4491 NFSUNLOCKV4ROOTMUTEX(); 4492 } 4493 if (error == -1)
| 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) 4514{ 4515 struct nfsstate *stp; 4516 struct nfslockfile *lfp; 4517 int error, haslock = 0; 4518 fhandle_t nfh; 4519 4520 /* 4521 * First, get the lock file structure. 4522 * (A return of -1 means no associated state, so remove ok.) 4523 */ 4524 error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p); 4525tryagain: 4526 NFSLOCKSTATE(); 4527 if (!error) 4528 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0); 4529 if (error) { 4530 NFSUNLOCKSTATE(); 4531 if (haslock) { 4532 NFSLOCKV4ROOTMUTEX(); 4533 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4534 NFSUNLOCKV4ROOTMUTEX(); 4535 } 4536 if (error == -1)
|
4494 return (0); 4495 return (error);
| 4537 error = 0; 4538 goto out;
|
4496 } 4497 4498 /* 4499 * Now, we must Recall any delegations. 4500 */ 4501 error = nfsrv_cleandeleg(vp, lfp, NULL, &haslock, p); 4502 if (error) { 4503 /* 4504 * nfsrv_cleandeleg() unlocks state for non-zero 4505 * return. 4506 */ 4507 if (error == -1) 4508 goto tryagain; 4509 if (haslock) { 4510 NFSLOCKV4ROOTMUTEX(); 4511 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4512 NFSUNLOCKV4ROOTMUTEX(); 4513 }
| 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 }
|
4514 return (error);
| 4557 goto out;
|
4515 } 4516 4517 /* 4518 * Now, look for a conflicting open share. 4519 */ 4520 if (remove) { 4521 LIST_FOREACH(stp, &lfp->lf_open, ls_file) { 4522 if (stp->ls_flags & NFSLCK_WRITEDENY) { 4523 error = NFSERR_FILEOPEN; 4524 break; 4525 } 4526 } 4527 } 4528 4529 NFSUNLOCKSTATE(); 4530 if (haslock) { 4531 NFSLOCKV4ROOTMUTEX(); 4532 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4533 NFSUNLOCKV4ROOTMUTEX(); 4534 }
| 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) { 4566 error = NFSERR_FILEOPEN; 4567 break; 4568 } 4569 } 4570 } 4571 4572 NFSUNLOCKSTATE(); 4573 if (haslock) { 4574 NFSLOCKV4ROOTMUTEX(); 4575 nfsv4_unlock(&nfsv4rootfs_lock, 1); 4576 NFSUNLOCKV4ROOTMUTEX(); 4577 }
|
| 4578 4579out: 4580 NFSEXITCODE(error);
|
4535 return (error); 4536} 4537 4538/* 4539 * Clear out all delegations for the file referred to by lfp. 4540 * May return NFSERR_DELAY, if there will be a delay waiting for 4541 * delegations to expire. 4542 * Returns -1 to indicate it slept while recalling a delegation. 4543 * This function has the side effect of deleting the nfslockfile structure, 4544 * if it no longer has associated state and didn't have to sleep. 4545 * Unlocks State before a non-zero value is returned. 4546 */ 4547static int 4548nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp, 4549 struct nfsclient *clp, int *haslockp, NFSPROC_T *p) 4550{ 4551 struct nfsstate *stp, *nstp;
| 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;
|
4552 int ret;
| 4598 int ret = 0;
|
4553 4554 stp = LIST_FIRST(&lfp->lf_deleg); 4555 while (stp != LIST_END(&lfp->lf_deleg)) { 4556 nstp = LIST_NEXT(stp, ls_file); 4557 if (stp->ls_clp != clp) { 4558 ret = nfsrv_delegconflict(stp, haslockp, p, vp); 4559 if (ret) { 4560 /* 4561 * nfsrv_delegconflict() unlocks state 4562 * when it returns non-zero. 4563 */
| 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 */
|
4564 return (ret);
| 4610 goto out;
|
4565 } 4566 } 4567 stp = nstp; 4568 }
| 4611 } 4612 } 4613 stp = nstp; 4614 }
|
4569 return (0);
| 4615out: 4616 NFSEXITCODE(ret); 4617 return (ret);
|
4570} 4571 4572/* 4573 * There are certain operations that, when being done outside of NFSv4, 4574 * require that any NFSv4 delegation for the file be recalled. 4575 * This function is to be called for those cases: 4576 * VOP_RENAME() - When a delegation is being recalled for any reason, 4577 * the client may have to do Opens against the server, using the file's 4578 * final component name. If the file has been renamed on the server, 4579 * that component name will be incorrect and the Open will fail. 4580 * VOP_REMOVE() - Theoretically, a client could Open a file after it has 4581 * been removed on the server, if there is a delegation issued to 4582 * that client for the file. I say "theoretically" since clients 4583 * normally do an Access Op before the Open and that Access Op will 4584 * fail with ESTALE. Note that NFSv2 and 3 don't even do Opens, so 4585 * they will detect the file's removal in the same manner. (There is 4586 * one case where RFC3530 allows a client to do an Open without first 4587 * doing an Access Op, which is passage of a check against the ACE 4588 * returned with a Write delegation, but current practice is to ignore 4589 * the ACE and always do an Access Op.) 4590 * Since the functions can only be called with an unlocked vnode, this 4591 * can't be done at this time. 4592 * VOP_ADVLOCK() - When a client holds a delegation, it can issue byte range 4593 * locks locally in the client, which are not visible to the server. To 4594 * deal with this, issuing of delegations for a vnode must be disabled 4595 * and all delegations for the vnode recalled. This is done via the 4596 * second function, using the VV_DISABLEDELEG vflag on the vnode. 4597 */ 4598APPLESTATIC void 4599nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p) 4600{ 4601 struct timespec mytime; 4602 int32_t starttime; 4603 int error; 4604 4605 /* 4606 * First, check to see if the server is currently running and it has 4607 * been called for a regular file when issuing delegations. 4608 */ 4609 if (newnfs_numnfsd == 0 || vp->v_type != VREG || 4610 nfsrv_issuedelegs == 0) 4611 return; 4612 4613 KASSERT((NFSVOPISLOCKED(vp) != LK_EXCLUSIVE), ("vp %p is locked", vp)); 4614 /* 4615 * First, get a reference on the nfsv4rootfs_lock so that an 4616 * exclusive lock cannot be acquired by another thread. 4617 */ 4618 NFSLOCKV4ROOTMUTEX(); 4619 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 4620 NFSUNLOCKV4ROOTMUTEX(); 4621 4622 /* 4623 * Now, call nfsrv_checkremove() in a loop while it returns 4624 * NFSERR_DELAY. Return upon any other error or when timed out. 4625 */ 4626 NFSGETNANOTIME(&mytime); 4627 starttime = (u_int32_t)mytime.tv_sec; 4628 do { 4629 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) { 4630 error = nfsrv_checkremove(vp, 0, p); 4631 NFSVOPUNLOCK(vp, 0); 4632 } else 4633 error = EPERM; 4634 if (error == NFSERR_DELAY) { 4635 NFSGETNANOTIME(&mytime); 4636 if (((u_int32_t)mytime.tv_sec - starttime) > 4637 NFS_REMOVETIMEO && 4638 ((u_int32_t)mytime.tv_sec - starttime) < 4639 100000) 4640 break; 4641 /* Sleep for a short period of time */ 4642 (void) nfs_catnap(PZERO, 0, "nfsremove"); 4643 } 4644 } while (error == NFSERR_DELAY); 4645 NFSLOCKV4ROOTMUTEX(); 4646 nfsv4_relref(&nfsv4rootfs_lock); 4647 NFSUNLOCKV4ROOTMUTEX(); 4648} 4649 4650APPLESTATIC void 4651nfsd_disabledelegation(vnode_t vp, NFSPROC_T *p) 4652{ 4653 4654#ifdef VV_DISABLEDELEG 4655 /* 4656 * First, flag issuance of delegations disabled. 4657 */ 4658 atomic_set_long(&vp->v_vflag, VV_DISABLEDELEG); 4659#endif 4660 4661 /* 4662 * Then call nfsd_recalldelegation() to get rid of all extant 4663 * delegations. 4664 */ 4665 nfsd_recalldelegation(vp, p); 4666} 4667 4668/* 4669 * Check for conflicting locks, etc. and then get rid of delegations. 4670 * (At one point I thought that I should get rid of delegations for any 4671 * Setattr, since it could potentially disallow the I/O op (read or write) 4672 * allowed by the delegation. However, Setattr Ops that aren't changing 4673 * the size get a stateid of all 0s, so you can't tell if it is a delegation 4674 * for the same client or a different one, so I decided to only get rid 4675 * of delegations for other clients when the size is being changed.) 4676 * In general, a Setattr can disable NFS I/O Ops that are outstanding, such 4677 * as Write backs, even if there is no delegation, so it really isn't any 4678 * different?) 4679 */ 4680APPLESTATIC int 4681nfsrv_checksetattr(vnode_t vp, struct nfsrv_descript *nd, 4682 nfsv4stateid_t *stateidp, struct nfsvattr *nvap, nfsattrbit_t *attrbitp, 4683 struct nfsexstuff *exp, NFSPROC_T *p) 4684{ 4685 struct nfsstate st, *stp = &st; 4686 struct nfslock lo, *lop = &lo; 4687 int error = 0; 4688 nfsquad_t clientid; 4689 4690 if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE)) { 4691 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 4692 lop->lo_first = nvap->na_size; 4693 } else { 4694 stp->ls_flags = 0; 4695 lop->lo_first = 0; 4696 } 4697 if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) || 4698 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) || 4699 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_MODE) || 4700 NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL)) 4701 stp->ls_flags |= NFSLCK_SETATTR; 4702 if (stp->ls_flags == 0)
| 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 4626 * final component name. If the file has been renamed on the server, 4627 * that component name will be incorrect and the Open will fail. 4628 * VOP_REMOVE() - Theoretically, a client could Open a file after it has 4629 * been removed on the server, if there is a delegation issued to 4630 * that client for the file. I say "theoretically" since clients 4631 * normally do an Access Op before the Open and that Access Op will 4632 * fail with ESTALE. Note that NFSv2 and 3 don't even do Opens, so 4633 * they will detect the file's removal in the same manner. (There is 4634 * one case where RFC3530 allows a client to do an Open without first 4635 * doing an Access Op, which is passage of a check against the ACE 4636 * returned with a Write delegation, but current practice is to ignore 4637 * the ACE and always do an Access Op.) 4638 * Since the functions can only be called with an unlocked vnode, this 4639 * can't be done at this time. 4640 * VOP_ADVLOCK() - When a client holds a delegation, it can issue byte range 4641 * locks locally in the client, which are not visible to the server. To 4642 * deal with this, issuing of delegations for a vnode must be disabled 4643 * and all delegations for the vnode recalled. This is done via the 4644 * second function, using the VV_DISABLEDELEG vflag on the vnode. 4645 */ 4646APPLESTATIC void 4647nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p) 4648{ 4649 struct timespec mytime; 4650 int32_t starttime; 4651 int error; 4652 4653 /* 4654 * First, check to see if the server is currently running and it has 4655 * been called for a regular file when issuing delegations. 4656 */ 4657 if (newnfs_numnfsd == 0 || vp->v_type != VREG || 4658 nfsrv_issuedelegs == 0) 4659 return; 4660 4661 KASSERT((NFSVOPISLOCKED(vp) != LK_EXCLUSIVE), ("vp %p is locked", vp)); 4662 /* 4663 * First, get a reference on the nfsv4rootfs_lock so that an 4664 * exclusive lock cannot be acquired by another thread. 4665 */ 4666 NFSLOCKV4ROOTMUTEX(); 4667 nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL); 4668 NFSUNLOCKV4ROOTMUTEX(); 4669 4670 /* 4671 * Now, call nfsrv_checkremove() in a loop while it returns 4672 * NFSERR_DELAY. Return upon any other error or when timed out. 4673 */ 4674 NFSGETNANOTIME(&mytime); 4675 starttime = (u_int32_t)mytime.tv_sec; 4676 do { 4677 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) { 4678 error = nfsrv_checkremove(vp, 0, p); 4679 NFSVOPUNLOCK(vp, 0); 4680 } else 4681 error = EPERM; 4682 if (error == NFSERR_DELAY) { 4683 NFSGETNANOTIME(&mytime); 4684 if (((u_int32_t)mytime.tv_sec - starttime) > 4685 NFS_REMOVETIMEO && 4686 ((u_int32_t)mytime.tv_sec - starttime) < 4687 100000) 4688 break; 4689 /* Sleep for a short period of time */ 4690 (void) nfs_catnap(PZERO, 0, "nfsremove"); 4691 } 4692 } while (error == NFSERR_DELAY); 4693 NFSLOCKV4ROOTMUTEX(); 4694 nfsv4_relref(&nfsv4rootfs_lock); 4695 NFSUNLOCKV4ROOTMUTEX(); 4696} 4697 4698APPLESTATIC void 4699nfsd_disabledelegation(vnode_t vp, NFSPROC_T *p) 4700{ 4701 4702#ifdef VV_DISABLEDELEG 4703 /* 4704 * First, flag issuance of delegations disabled. 4705 */ 4706 atomic_set_long(&vp->v_vflag, VV_DISABLEDELEG); 4707#endif 4708 4709 /* 4710 * Then call nfsd_recalldelegation() to get rid of all extant 4711 * delegations. 4712 */ 4713 nfsd_recalldelegation(vp, p); 4714} 4715 4716/* 4717 * Check for conflicting locks, etc. and then get rid of delegations. 4718 * (At one point I thought that I should get rid of delegations for any 4719 * Setattr, since it could potentially disallow the I/O op (read or write) 4720 * allowed by the delegation. However, Setattr Ops that aren't changing 4721 * the size get a stateid of all 0s, so you can't tell if it is a delegation 4722 * for the same client or a different one, so I decided to only get rid 4723 * of delegations for other clients when the size is being changed.) 4724 * In general, a Setattr can disable NFS I/O Ops that are outstanding, such 4725 * as Write backs, even if there is no delegation, so it really isn't any 4726 * different?) 4727 */ 4728APPLESTATIC int 4729nfsrv_checksetattr(vnode_t vp, struct nfsrv_descript *nd, 4730 nfsv4stateid_t *stateidp, struct nfsvattr *nvap, nfsattrbit_t *attrbitp, 4731 struct nfsexstuff *exp, NFSPROC_T *p) 4732{ 4733 struct nfsstate st, *stp = &st; 4734 struct nfslock lo, *lop = &lo; 4735 int error = 0; 4736 nfsquad_t clientid; 4737 4738 if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE)) { 4739 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 4740 lop->lo_first = nvap->na_size; 4741 } else { 4742 stp->ls_flags = 0; 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)
|
4703 return (0);
| 4751 goto out;
|
4704 lop->lo_end = NFS64BITSSET; 4705 lop->lo_flags = NFSLCK_WRITE; 4706 stp->ls_ownerlen = 0; 4707 stp->ls_op = NULL; 4708 stp->ls_uid = nd->nd_cred->cr_uid; 4709 stp->ls_stateid.seqid = stateidp->seqid; 4710 clientid.lval[0] = stp->ls_stateid.other[0] = stateidp->other[0]; 4711 clientid.lval[1] = stp->ls_stateid.other[1] = stateidp->other[1]; 4712 stp->ls_stateid.other[2] = stateidp->other[2]; 4713 error = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 4714 stateidp, exp, nd, p);
| 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);
|
4715 return (error); 4716} 4717 4718/* 4719 * Check for a write delegation and do a CBGETATTR if there is one, updating 4720 * the attributes, as required. 4721 * Should I return an error if I can't get the attributes? (For now, I'll 4722 * just return ok. 4723 */ 4724APPLESTATIC int 4725nfsrv_checkgetattr(struct nfsrv_descript *nd, vnode_t vp, 4726 struct nfsvattr *nvap, nfsattrbit_t *attrbitp, struct ucred *cred, 4727 NFSPROC_T *p) 4728{ 4729 struct nfsstate *stp; 4730 struct nfslockfile *lfp; 4731 struct nfsclient *clp; 4732 struct nfsvattr nva; 4733 fhandle_t nfh;
| 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;
|
4734 int error;
| 4785 int error = 0;
|
4735 nfsattrbit_t cbbits; 4736 u_quad_t delegfilerev; 4737 4738 NFSCBGETATTR_ATTRBIT(attrbitp, &cbbits); 4739 if (!NFSNONZERO_ATTRBIT(&cbbits))
| 4786 nfsattrbit_t cbbits; 4787 u_quad_t delegfilerev; 4788 4789 NFSCBGETATTR_ATTRBIT(attrbitp, &cbbits); 4790 if (!NFSNONZERO_ATTRBIT(&cbbits))
|
4740 return (0);
| 4791 goto out;
|
4741 4742 /* 4743 * Get the lock file structure. 4744 * (A return of -1 means no associated state, so return ok.) 4745 */ 4746 error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p); 4747 NFSLOCKSTATE(); 4748 if (!error) 4749 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0); 4750 if (error) { 4751 NFSUNLOCKSTATE(); 4752 if (error == -1)
| 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)
|
4753 return (0); 4754 return (error);
| 4804 error = 0; 4805 goto out;
|
4755 } 4756 4757 /* 4758 * Now, look for a write delegation. 4759 */ 4760 LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) { 4761 if (stp->ls_flags & NFSLCK_DELEGWRITE) 4762 break; 4763 } 4764 if (stp == LIST_END(&lfp->lf_deleg)) { 4765 NFSUNLOCKSTATE();
| 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();
|
4766 return (0);
| 4817 goto out;
|
4767 } 4768 clp = stp->ls_clp; 4769 delegfilerev = stp->ls_filerev; 4770 4771 /* 4772 * If the Write delegation was issued as a part of this Compound RPC 4773 * or if we have an Implied Clientid (used in a previous Op in this 4774 * compound) and it is the client the delegation was issued to, 4775 * just return ok. 4776 * I also assume that it is from the same client iff the network 4777 * host IP address is the same as the callback address. (Not 4778 * exactly correct by the RFC, but avoids a lot of Getattr 4779 * callbacks.) 4780 */ 4781 if (nd->nd_compref == stp->ls_compref || 4782 ((nd->nd_flag & ND_IMPLIEDCLID) && 4783 clp->lc_clientid.qval == nd->nd_clientid.qval) || 4784 nfsaddr2_match(clp->lc_req.nr_nam, nd->nd_nam)) { 4785 NFSUNLOCKSTATE();
| 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();
|
4786 return (0);
| 4837 goto out;
|
4787 } 4788 4789 /* 4790 * We are now done with the delegation state structure, 4791 * so the statelock can be released and we can now tsleep(). 4792 */ 4793 4794 /* 4795 * Now, we must do the CB Getattr callback, to see if Change or Size 4796 * has changed. 4797 */ 4798 if (clp->lc_expiry >= NFSD_MONOSEC) { 4799 NFSUNLOCKSTATE(); 4800 NFSVNO_ATTRINIT(&nva); 4801 nva.na_filerev = NFS64BITSSET; 4802 error = nfsrv_docallback(clp, NFSV4OP_CBGETATTR, NULL, 4803 0, &nfh, &nva, &cbbits, p); 4804 if (!error) { 4805 if ((nva.na_filerev != NFS64BITSSET && 4806 nva.na_filerev > delegfilerev) || 4807 (NFSVNO_ISSETSIZE(&nva) && 4808 nva.na_size != nvap->na_size)) { 4809 nfsvno_updfilerev(vp, nvap, cred, p); 4810 if (NFSVNO_ISSETSIZE(&nva)) 4811 nvap->na_size = nva.na_size; 4812 } 4813 } 4814 } else { 4815 NFSUNLOCKSTATE(); 4816 }
| 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 /* 4846 * Now, we must do the CB Getattr callback, to see if Change or Size 4847 * has changed. 4848 */ 4849 if (clp->lc_expiry >= NFSD_MONOSEC) { 4850 NFSUNLOCKSTATE(); 4851 NFSVNO_ATTRINIT(&nva); 4852 nva.na_filerev = NFS64BITSSET; 4853 error = nfsrv_docallback(clp, NFSV4OP_CBGETATTR, NULL, 4854 0, &nfh, &nva, &cbbits, p); 4855 if (!error) { 4856 if ((nva.na_filerev != NFS64BITSSET && 4857 nva.na_filerev > delegfilerev) || 4858 (NFSVNO_ISSETSIZE(&nva) && 4859 nva.na_size != nvap->na_size)) { 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 }
|
4817 return (0);
| 4868 error = 0; 4869 4870out: 4871 NFSEXITCODE2(error, nd); 4872 return (error);
|
4818} 4819 4820/* 4821 * This function looks for openowners that haven't had any opens for 4822 * a while and throws them away. Called by an nfsd when NFSNSF_NOOPENS 4823 * is set. 4824 */ 4825APPLESTATIC void 4826nfsrv_throwawayopens(NFSPROC_T *p) 4827{ 4828 struct nfsclient *clp, *nclp; 4829 struct nfsstate *stp, *nstp; 4830 int i; 4831 4832 NFSLOCKSTATE(); 4833 nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NOOPENS; 4834 /* 4835 * For each client... 4836 */ 4837 for (i = 0; i < NFSCLIENTHASHSIZE; i++) { 4838 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { 4839 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) { 4840 if (LIST_EMPTY(&stp->ls_open) && 4841 (stp->ls_noopens > NFSNOOPEN || 4842 (nfsrv_openpluslock * 2) > 4843 NFSRV_V4STATELIMIT)) 4844 nfsrv_freeopenowner(stp, 0, p); 4845 } 4846 } 4847 } 4848 NFSUNLOCKSTATE(); 4849} 4850 4851/* 4852 * This function checks to see if the credentials are the same. 4853 * Returns 1 for not same, 0 otherwise. 4854 */ 4855static int 4856nfsrv_notsamecredname(struct nfsrv_descript *nd, struct nfsclient *clp) 4857{ 4858 4859 if (nd->nd_flag & ND_GSS) { 4860 if (!(clp->lc_flags & LCL_GSS)) 4861 return (1); 4862 if (clp->lc_flags & LCL_NAME) { 4863 if (nd->nd_princlen != clp->lc_namelen || 4864 NFSBCMP(nd->nd_principal, clp->lc_name, 4865 clp->lc_namelen)) 4866 return (1); 4867 else 4868 return (0); 4869 } 4870 if (nd->nd_cred->cr_uid == clp->lc_uid) 4871 return (0); 4872 else 4873 return (1); 4874 } else if (clp->lc_flags & LCL_GSS) 4875 return (1); 4876 /* 4877 * For AUTH_SYS, allow the same uid or root. (This is underspecified 4878 * in RFC3530, which talks about principals, but doesn't say anything 4879 * about uids for AUTH_SYS.) 4880 */ 4881 if (nd->nd_cred->cr_uid == clp->lc_uid || nd->nd_cred->cr_uid == 0) 4882 return (0); 4883 else 4884 return (1); 4885} 4886 4887/* 4888 * Calculate the lease expiry time. 4889 */ 4890static time_t 4891nfsrv_leaseexpiry(void) 4892{ 4893 struct timeval curtime; 4894 4895 NFSGETTIME(&curtime); 4896 if (nfsrv_stablefirst.nsf_eograce > NFSD_MONOSEC) 4897 return (NFSD_MONOSEC + 2 * (nfsrv_lease + NFSRV_LEASEDELTA)); 4898 return (NFSD_MONOSEC + nfsrv_lease + NFSRV_LEASEDELTA); 4899} 4900 4901/* 4902 * Delay the delegation timeout as far as ls_delegtimelimit, as required. 4903 */ 4904static void 4905nfsrv_delaydelegtimeout(struct nfsstate *stp) 4906{ 4907 4908 if ((stp->ls_flags & NFSLCK_DELEGRECALL) == 0) 4909 return; 4910 4911 if ((stp->ls_delegtime + 15) > NFSD_MONOSEC && 4912 stp->ls_delegtime < stp->ls_delegtimelimit) { 4913 stp->ls_delegtime += nfsrv_lease; 4914 if (stp->ls_delegtime > stp->ls_delegtimelimit) 4915 stp->ls_delegtime = stp->ls_delegtimelimit; 4916 } 4917} 4918 4919/* 4920 * This function checks to see if there is any other state associated 4921 * with the openowner for this Open. 4922 * It returns 1 if there is no other state, 0 otherwise. 4923 */ 4924static int 4925nfsrv_nootherstate(struct nfsstate *stp) 4926{ 4927 struct nfsstate *tstp; 4928 4929 LIST_FOREACH(tstp, &stp->ls_openowner->ls_open, ls_list) { 4930 if (tstp != stp || !LIST_EMPTY(&tstp->ls_lock)) 4931 return (0); 4932 } 4933 return (1); 4934} 4935 4936/* 4937 * Create a list of lock deltas (changes to local byte range locking 4938 * that can be rolled back using the list) and apply the changes via 4939 * nfsvno_advlock(). Optionally, lock the list. It is expected that either 4940 * the rollback or update function will be called after this. 4941 * It returns an error (and rolls back, as required), if any nfsvno_advlock() 4942 * call fails. If it returns an error, it will unlock the list. 4943 */ 4944static int 4945nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, 4946 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p) 4947{ 4948 struct nfslock *lop, *nlop; 4949 int error = 0; 4950 4951 /* Loop through the list of locks. */ 4952 lop = LIST_FIRST(&lfp->lf_locallock); 4953 while (first < end && lop != NULL) { 4954 nlop = LIST_NEXT(lop, lo_lckowner); 4955 if (first >= lop->lo_end) { 4956 /* not there yet */ 4957 lop = nlop; 4958 } else if (first < lop->lo_first) { 4959 /* new one starts before entry in list */ 4960 if (end <= lop->lo_first) { 4961 /* no overlap between old and new */ 4962 error = nfsrv_dolocal(vp, lfp, flags, 4963 NFSLCK_UNLOCK, first, end, cfp, p); 4964 if (error != 0) 4965 break; 4966 first = end; 4967 } else { 4968 /* handle fragment overlapped with new one */ 4969 error = nfsrv_dolocal(vp, lfp, flags, 4970 NFSLCK_UNLOCK, first, lop->lo_first, cfp, 4971 p); 4972 if (error != 0) 4973 break; 4974 first = lop->lo_first; 4975 } 4976 } else { 4977 /* new one overlaps this entry in list */ 4978 if (end <= lop->lo_end) { 4979 /* overlaps all of new one */ 4980 error = nfsrv_dolocal(vp, lfp, flags, 4981 lop->lo_flags, first, end, cfp, p); 4982 if (error != 0) 4983 break; 4984 first = end; 4985 } else { 4986 /* handle fragment overlapped with new one */ 4987 error = nfsrv_dolocal(vp, lfp, flags, 4988 lop->lo_flags, first, lop->lo_end, cfp, p); 4989 if (error != 0) 4990 break; 4991 first = lop->lo_end; 4992 lop = nlop; 4993 } 4994 } 4995 } 4996 if (first < end && error == 0) 4997 /* handle fragment past end of list */ 4998 error = nfsrv_dolocal(vp, lfp, flags, NFSLCK_UNLOCK, first, 4999 end, cfp, p);
| 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 4881nfsrv_throwawayopens(NFSPROC_T *p) 4882{ 4883 struct nfsclient *clp, *nclp; 4884 struct nfsstate *stp, *nstp; 4885 int i; 4886 4887 NFSLOCKSTATE(); 4888 nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NOOPENS; 4889 /* 4890 * For each client... 4891 */ 4892 for (i = 0; i < NFSCLIENTHASHSIZE; i++) { 4893 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { 4894 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) { 4895 if (LIST_EMPTY(&stp->ls_open) && 4896 (stp->ls_noopens > NFSNOOPEN || 4897 (nfsrv_openpluslock * 2) > 4898 NFSRV_V4STATELIMIT)) 4899 nfsrv_freeopenowner(stp, 0, p); 4900 } 4901 } 4902 } 4903 NFSUNLOCKSTATE(); 4904} 4905 4906/* 4907 * This function checks to see if the credentials are the same. 4908 * Returns 1 for not same, 0 otherwise. 4909 */ 4910static int 4911nfsrv_notsamecredname(struct nfsrv_descript *nd, struct nfsclient *clp) 4912{ 4913 4914 if (nd->nd_flag & ND_GSS) { 4915 if (!(clp->lc_flags & LCL_GSS)) 4916 return (1); 4917 if (clp->lc_flags & LCL_NAME) { 4918 if (nd->nd_princlen != clp->lc_namelen || 4919 NFSBCMP(nd->nd_principal, clp->lc_name, 4920 clp->lc_namelen)) 4921 return (1); 4922 else 4923 return (0); 4924 } 4925 if (nd->nd_cred->cr_uid == clp->lc_uid) 4926 return (0); 4927 else 4928 return (1); 4929 } else if (clp->lc_flags & LCL_GSS) 4930 return (1); 4931 /* 4932 * For AUTH_SYS, allow the same uid or root. (This is underspecified 4933 * in RFC3530, which talks about principals, but doesn't say anything 4934 * about uids for AUTH_SYS.) 4935 */ 4936 if (nd->nd_cred->cr_uid == clp->lc_uid || nd->nd_cred->cr_uid == 0) 4937 return (0); 4938 else 4939 return (1); 4940} 4941 4942/* 4943 * Calculate the lease expiry time. 4944 */ 4945static time_t 4946nfsrv_leaseexpiry(void) 4947{ 4948 struct timeval curtime; 4949 4950 NFSGETTIME(&curtime); 4951 if (nfsrv_stablefirst.nsf_eograce > NFSD_MONOSEC) 4952 return (NFSD_MONOSEC + 2 * (nfsrv_lease + NFSRV_LEASEDELTA)); 4953 return (NFSD_MONOSEC + nfsrv_lease + NFSRV_LEASEDELTA); 4954} 4955 4956/* 4957 * Delay the delegation timeout as far as ls_delegtimelimit, as required. 4958 */ 4959static void 4960nfsrv_delaydelegtimeout(struct nfsstate *stp) 4961{ 4962 4963 if ((stp->ls_flags & NFSLCK_DELEGRECALL) == 0) 4964 return; 4965 4966 if ((stp->ls_delegtime + 15) > NFSD_MONOSEC && 4967 stp->ls_delegtime < stp->ls_delegtimelimit) { 4968 stp->ls_delegtime += nfsrv_lease; 4969 if (stp->ls_delegtime > stp->ls_delegtimelimit) 4970 stp->ls_delegtime = stp->ls_delegtimelimit; 4971 } 4972} 4973 4974/* 4975 * This function checks to see if there is any other state associated 4976 * with the openowner for this Open. 4977 * It returns 1 if there is no other state, 0 otherwise. 4978 */ 4979static int 4980nfsrv_nootherstate(struct nfsstate *stp) 4981{ 4982 struct nfsstate *tstp; 4983 4984 LIST_FOREACH(tstp, &stp->ls_openowner->ls_open, ls_list) { 4985 if (tstp != stp || !LIST_EMPTY(&tstp->ls_lock)) 4986 return (0); 4987 } 4988 return (1); 4989} 4990 4991/* 4992 * Create a list of lock deltas (changes to local byte range locking 4993 * that can be rolled back using the list) and apply the changes via 4994 * nfsvno_advlock(). Optionally, lock the list. It is expected that either 4995 * the rollback or update function will be called after this. 4996 * It returns an error (and rolls back, as required), if any nfsvno_advlock() 4997 * call fails. If it returns an error, it will unlock the list. 4998 */ 4999static int 5000nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, 5001 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p) 5002{ 5003 struct nfslock *lop, *nlop; 5004 int error = 0; 5005 5006 /* Loop through the list of locks. */ 5007 lop = LIST_FIRST(&lfp->lf_locallock); 5008 while (first < end && lop != NULL) { 5009 nlop = LIST_NEXT(lop, lo_lckowner); 5010 if (first >= lop->lo_end) { 5011 /* not there yet */ 5012 lop = nlop; 5013 } else if (first < lop->lo_first) { 5014 /* new one starts before entry in list */ 5015 if (end <= lop->lo_first) { 5016 /* no overlap between old and new */ 5017 error = nfsrv_dolocal(vp, lfp, flags, 5018 NFSLCK_UNLOCK, first, end, cfp, p); 5019 if (error != 0) 5020 break; 5021 first = end; 5022 } else { 5023 /* handle fragment overlapped with new one */ 5024 error = nfsrv_dolocal(vp, lfp, flags, 5025 NFSLCK_UNLOCK, first, lop->lo_first, cfp, 5026 p); 5027 if (error != 0) 5028 break; 5029 first = lop->lo_first; 5030 } 5031 } else { 5032 /* new one overlaps this entry in list */ 5033 if (end <= lop->lo_end) { 5034 /* overlaps all of new one */ 5035 error = nfsrv_dolocal(vp, lfp, flags, 5036 lop->lo_flags, first, end, cfp, p); 5037 if (error != 0) 5038 break; 5039 first = end; 5040 } else { 5041 /* handle fragment overlapped with new one */ 5042 error = nfsrv_dolocal(vp, lfp, flags, 5043 lop->lo_flags, first, lop->lo_end, cfp, p); 5044 if (error != 0) 5045 break; 5046 first = lop->lo_end; 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);
|
5000 return (error); 5001} 5002 5003/* 5004 * Local lock unlock. Unlock all byte ranges that are no longer locked 5005 * by NFSv4. To do this, unlock any subranges of first-->end that 5006 * do not overlap with the byte ranges of any lock in the lfp->lf_lock 5007 * list. This list has all locks for the file held by other 5008 * <clientid, lockowner> tuples. The list is ordered by increasing 5009 * lo_first value, but may have entries that overlap each other, for 5010 * the case of read locks. 5011 */ 5012static void 5013nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, uint64_t init_first, 5014 uint64_t init_end, NFSPROC_T *p) 5015{ 5016 struct nfslock *lop; 5017 uint64_t first, end, prevfirst; 5018 5019 first = init_first; 5020 end = init_end; 5021 while (first < init_end) { 5022 /* Loop through all nfs locks, adjusting first and end */ 5023 prevfirst = 0; 5024 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { 5025 KASSERT(prevfirst <= lop->lo_first, 5026 ("nfsv4 locks out of order")); 5027 KASSERT(lop->lo_first < lop->lo_end, 5028 ("nfsv4 bogus lock")); 5029 prevfirst = lop->lo_first; 5030 if (first >= lop->lo_first && 5031 first < lop->lo_end) 5032 /* 5033 * Overlaps with initial part, so trim 5034 * off that initial part by moving first past 5035 * it. 5036 */ 5037 first = lop->lo_end; 5038 else if (end > lop->lo_first && 5039 lop->lo_first > first) { 5040 /* 5041 * This lock defines the end of the 5042 * segment to unlock, so set end to the 5043 * start of it and break out of the loop. 5044 */ 5045 end = lop->lo_first; 5046 break; 5047 } 5048 if (first >= end) 5049 /* 5050 * There is no segment left to do, so 5051 * break out of this loop and then exit 5052 * the outer while() since first will be set 5053 * to end, which must equal init_end here. 5054 */ 5055 break; 5056 } 5057 if (first < end) { 5058 /* Unlock this segment */ 5059 (void) nfsrv_dolocal(vp, lfp, NFSLCK_UNLOCK, 5060 NFSLCK_READ, first, end, NULL, p); 5061 nfsrv_locallock_commit(lfp, NFSLCK_UNLOCK, 5062 first, end); 5063 } 5064 /* 5065 * Now move past this segment and look for any further 5066 * segment in the range, if there is one. 5067 */ 5068 first = end; 5069 end = init_end; 5070 } 5071} 5072 5073/* 5074 * Do the local lock operation and update the rollback list, as required. 5075 * Perform the rollback and return the error if nfsvno_advlock() fails. 5076 */ 5077static int 5078nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, int oldflags, 5079 uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p) 5080{ 5081 struct nfsrollback *rlp;
| 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 5065 * <clientid, lockowner> tuples. The list is ordered by increasing 5066 * lo_first value, but may have entries that overlap each other, for 5067 * the case of read locks. 5068 */ 5069static void 5070nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, uint64_t init_first, 5071 uint64_t init_end, NFSPROC_T *p) 5072{ 5073 struct nfslock *lop; 5074 uint64_t first, end, prevfirst; 5075 5076 first = init_first; 5077 end = init_end; 5078 while (first < init_end) { 5079 /* Loop through all nfs locks, adjusting first and end */ 5080 prevfirst = 0; 5081 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { 5082 KASSERT(prevfirst <= lop->lo_first, 5083 ("nfsv4 locks out of order")); 5084 KASSERT(lop->lo_first < lop->lo_end, 5085 ("nfsv4 bogus lock")); 5086 prevfirst = lop->lo_first; 5087 if (first >= lop->lo_first && 5088 first < lop->lo_end) 5089 /* 5090 * Overlaps with initial part, so trim 5091 * off that initial part by moving first past 5092 * it. 5093 */ 5094 first = lop->lo_end; 5095 else if (end > lop->lo_first && 5096 lop->lo_first > first) { 5097 /* 5098 * This lock defines the end of the 5099 * segment to unlock, so set end to the 5100 * start of it and break out of the loop. 5101 */ 5102 end = lop->lo_first; 5103 break; 5104 } 5105 if (first >= end) 5106 /* 5107 * There is no segment left to do, so 5108 * break out of this loop and then exit 5109 * the outer while() since first will be set 5110 * to end, which must equal init_end here. 5111 */ 5112 break; 5113 } 5114 if (first < end) { 5115 /* Unlock this segment */ 5116 (void) nfsrv_dolocal(vp, lfp, NFSLCK_UNLOCK, 5117 NFSLCK_READ, first, end, NULL, p); 5118 nfsrv_locallock_commit(lfp, NFSLCK_UNLOCK, 5119 first, end); 5120 } 5121 /* 5122 * Now move past this segment and look for any further 5123 * segment in the range, if there is one. 5124 */ 5125 first = end; 5126 end = init_end; 5127 } 5128} 5129 5130/* 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;
|
5082 int error, ltype, oldltype;
| 5139 int error = 0, ltype, oldltype;
|
5083 5084 if (flags & NFSLCK_WRITE) 5085 ltype = F_WRLCK; 5086 else if (flags & NFSLCK_READ) 5087 ltype = F_RDLCK; 5088 else 5089 ltype = F_UNLCK; 5090 if (oldflags & NFSLCK_WRITE) 5091 oldltype = F_WRLCK; 5092 else if (oldflags & NFSLCK_READ) 5093 oldltype = F_RDLCK; 5094 else 5095 oldltype = F_UNLCK; 5096 if (ltype == oldltype || (oldltype == F_WRLCK && ltype == F_RDLCK)) 5097 /* nothing to do */
| 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 */
|
5098 return (0);
| 5155 goto out;
|
5099 error = nfsvno_advlock(vp, ltype, first, end, p); 5100 if (error != 0) { 5101 if (cfp != NULL) { 5102 cfp->cl_clientid.lval[0] = 0; 5103 cfp->cl_clientid.lval[1] = 0; 5104 cfp->cl_first = 0; 5105 cfp->cl_end = NFS64BITSSET; 5106 cfp->cl_flags = NFSLCK_WRITE; 5107 cfp->cl_ownerlen = 5; 5108 NFSBCOPY("LOCAL", cfp->cl_owner, 5); 5109 } 5110 nfsrv_locallock_rollback(vp, lfp, p); 5111 } else if (ltype != F_UNLCK) { 5112 rlp = malloc(sizeof (struct nfsrollback), M_NFSDROLLBACK, 5113 M_WAITOK); 5114 rlp->rlck_first = first; 5115 rlp->rlck_end = end; 5116 rlp->rlck_type = oldltype; 5117 LIST_INSERT_HEAD(&lfp->lf_rollback, rlp, rlck_list); 5118 }
| 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; 5164 cfp->cl_ownerlen = 5; 5165 NFSBCOPY("LOCAL", cfp->cl_owner, 5); 5166 } 5167 nfsrv_locallock_rollback(vp, lfp, p); 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);
|
5119 return (error); 5120} 5121 5122/* 5123 * Roll back local lock changes and free up the rollback list. 5124 */ 5125static void 5126nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, NFSPROC_T *p) 5127{ 5128 struct nfsrollback *rlp, *nrlp; 5129 5130 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) { 5131 (void) nfsvno_advlock(vp, rlp->rlck_type, rlp->rlck_first, 5132 rlp->rlck_end, p); 5133 free(rlp, M_NFSDROLLBACK); 5134 } 5135 LIST_INIT(&lfp->lf_rollback); 5136} 5137 5138/* 5139 * Update local lock list and delete rollback list (ie now committed to the 5140 * local locks). Most of the work is done by the internal function. 5141 */ 5142static void 5143nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, uint64_t first, 5144 uint64_t end) 5145{ 5146 struct nfsrollback *rlp, *nrlp; 5147 struct nfslock *new_lop, *other_lop; 5148 5149 new_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, M_WAITOK); 5150 if (flags & (NFSLCK_READ | NFSLCK_WRITE)) 5151 other_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, 5152 M_WAITOK); 5153 else 5154 other_lop = NULL; 5155 new_lop->lo_flags = flags; 5156 new_lop->lo_first = first; 5157 new_lop->lo_end = end; 5158 nfsrv_updatelock(NULL, &new_lop, &other_lop, lfp); 5159 if (new_lop != NULL) 5160 free(new_lop, M_NFSDLOCK); 5161 if (other_lop != NULL) 5162 free(other_lop, M_NFSDLOCK); 5163 5164 /* and get rid of the rollback list */ 5165 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) 5166 free(rlp, M_NFSDROLLBACK); 5167 LIST_INIT(&lfp->lf_rollback); 5168} 5169 5170/* 5171 * Lock the struct nfslockfile for local lock updating. 5172 */ 5173static void 5174nfsrv_locklf(struct nfslockfile *lfp) 5175{ 5176 int gotlock; 5177 5178 /* lf_usecount ensures *lfp won't be free'd */ 5179 lfp->lf_usecount++; 5180 do { 5181 gotlock = nfsv4_lock(&lfp->lf_locallock_lck, 1, NULL, 5182 NFSSTATEMUTEXPTR, NULL); 5183 } while (gotlock == 0); 5184 lfp->lf_usecount--; 5185} 5186 5187/* 5188 * Unlock the struct nfslockfile after local lock updating. 5189 */ 5190static void 5191nfsrv_unlocklf(struct nfslockfile *lfp) 5192{ 5193 5194 nfsv4_unlock(&lfp->lf_locallock_lck, 0); 5195} 5196 5197/* 5198 * Clear out all state for the NFSv4 server. 5199 * Must be called by a thread that can sleep when no nfsds are running. 5200 */ 5201void 5202nfsrv_throwawayallstate(NFSPROC_T *p) 5203{ 5204 struct nfsclient *clp, *nclp; 5205 struct nfslockfile *lfp, *nlfp; 5206 int i; 5207 5208 /* 5209 * For each client, clean out the state and then free the structure. 5210 */ 5211 for (i = 0; i < NFSCLIENTHASHSIZE; i++) { 5212 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { 5213 nfsrv_cleanclient(clp, p); 5214 nfsrv_freedeleglist(&clp->lc_deleg); 5215 nfsrv_freedeleglist(&clp->lc_olddeleg); 5216 free(clp, M_NFSDCLIENT); 5217 } 5218 } 5219 5220 /* 5221 * Also, free up any remaining lock file structures. 5222 */ 5223 for (i = 0; i < NFSLOCKHASHSIZE; i++) { 5224 LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) { 5225 printf("nfsd unload: fnd a lock file struct\n"); 5226 nfsrv_freenfslockfile(lfp); 5227 } 5228 } 5229} 5230
| 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) 5187{ 5188 struct nfsrollback *rlp, *nrlp; 5189 5190 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) { 5191 (void) nfsvno_advlock(vp, rlp->rlck_type, rlp->rlck_first, 5192 rlp->rlck_end, p); 5193 free(rlp, M_NFSDROLLBACK); 5194 } 5195 LIST_INIT(&lfp->lf_rollback); 5196} 5197 5198/* 5199 * Update local lock list and delete rollback list (ie now committed to the 5200 * local locks). Most of the work is done by the internal function. 5201 */ 5202static void 5203nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, uint64_t first, 5204 uint64_t end) 5205{ 5206 struct nfsrollback *rlp, *nrlp; 5207 struct nfslock *new_lop, *other_lop; 5208 5209 new_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, M_WAITOK); 5210 if (flags & (NFSLCK_READ | NFSLCK_WRITE)) 5211 other_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, 5212 M_WAITOK); 5213 else 5214 other_lop = NULL; 5215 new_lop->lo_flags = flags; 5216 new_lop->lo_first = first; 5217 new_lop->lo_end = end; 5218 nfsrv_updatelock(NULL, &new_lop, &other_lop, lfp); 5219 if (new_lop != NULL) 5220 free(new_lop, M_NFSDLOCK); 5221 if (other_lop != NULL) 5222 free(other_lop, M_NFSDLOCK); 5223 5224 /* and get rid of the rollback list */ 5225 LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) 5226 free(rlp, M_NFSDROLLBACK); 5227 LIST_INIT(&lfp->lf_rollback); 5228} 5229 5230/* 5231 * Lock the struct nfslockfile for local lock updating. 5232 */ 5233static void 5234nfsrv_locklf(struct nfslockfile *lfp) 5235{ 5236 int gotlock; 5237 5238 /* lf_usecount ensures *lfp won't be free'd */ 5239 lfp->lf_usecount++; 5240 do { 5241 gotlock = nfsv4_lock(&lfp->lf_locallock_lck, 1, NULL, 5242 NFSSTATEMUTEXPTR, NULL); 5243 } while (gotlock == 0); 5244 lfp->lf_usecount--; 5245} 5246 5247/* 5248 * Unlock the struct nfslockfile after local lock updating. 5249 */ 5250static void 5251nfsrv_unlocklf(struct nfslockfile *lfp) 5252{ 5253 5254 nfsv4_unlock(&lfp->lf_locallock_lck, 0); 5255} 5256 5257/* 5258 * Clear out all state for the NFSv4 server. 5259 * Must be called by a thread that can sleep when no nfsds are running. 5260 */ 5261void 5262nfsrv_throwawayallstate(NFSPROC_T *p) 5263{ 5264 struct nfsclient *clp, *nclp; 5265 struct nfslockfile *lfp, *nlfp; 5266 int i; 5267 5268 /* 5269 * For each client, clean out the state and then free the structure. 5270 */ 5271 for (i = 0; i < NFSCLIENTHASHSIZE; i++) { 5272 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) { 5273 nfsrv_cleanclient(clp, p); 5274 nfsrv_freedeleglist(&clp->lc_deleg); 5275 nfsrv_freedeleglist(&clp->lc_olddeleg); 5276 free(clp, M_NFSDCLIENT); 5277 } 5278 } 5279 5280 /* 5281 * Also, free up any remaining lock file structures. 5282 */ 5283 for (i = 0; i < NFSLOCKHASHSIZE; i++) { 5284 LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) { 5285 printf("nfsd unload: fnd a lock file struct\n"); 5286 nfsrv_freenfslockfile(lfp); 5287 } 5288 } 5289} 5290
|