X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..f427ee49d309d8fc33ebf3042c3a775f2f530ded:/bsd/nfs/nfs_lock.c?ds=inline diff --git a/bsd/nfs/nfs_lock.c b/bsd/nfs/nfs_lock.c index f76a9b6d0..4b0d19631 100644 --- a/bsd/nfs/nfs_lock.c +++ b/bsd/nfs/nfs_lock.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2002-2010 Apple Inc. All rights reserved. + * Copyright (c) 2002-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /*- @@ -55,17 +55,20 @@ * from BSDI nfs_lock.c,v 2.4 1998/12/14 23:49:56 jch Exp */ +#include +#if CONFIG_NFS_CLIENT + #include #include #include #include -#include /* for hz */ +#include /* for hz */ #include #include -#include /* for hz */ /* Must come after sys/malloc.h */ +#include /* for hz */ /* Must come after sys/malloc.h */ #include #include -#include /* for p_start */ +#include /* for p_start */ #include #include #include @@ -103,7 +106,7 @@ static uint64_t nfs_lockxid = 0; static LOCKD_MSG_QUEUE nfs_pendlockq; /* list of mounts that are (potentially) making lockd requests */ -TAILQ_HEAD(nfs_lockd_mount_list,nfsmount) nfs_lockd_mount_list; +TAILQ_HEAD(nfs_lockd_mount_list, nfsmount) nfs_lockd_mount_list; static lck_grp_t *nfs_lock_lck_grp; static lck_mtx_t *nfs_lock_mutex; @@ -155,18 +158,27 @@ nfs_lockd_mount_unregister(struct nfsmount *nmp) kern_return_t kr; lck_mtx_lock(nfs_lock_mutex); + if (nmp->nm_ldlink.tqe_next == NFSNOLIST) { + lck_mtx_unlock(nfs_lock_mutex); + return; + } + TAILQ_REMOVE(&nfs_lockd_mount_list, nmp, nm_ldlink); + nmp->nm_ldlink.tqe_next = NFSNOLIST; + nfs_lockd_mounts--; /* send a shutdown request if there are no more lockd mounts */ send_shutdown = ((nfs_lockd_mounts == 0) && nfs_lockd_request_sent); - if (send_shutdown) + if (send_shutdown) { nfs_lockd_request_sent = 0; + } lck_mtx_unlock(nfs_lock_mutex); - if (!send_shutdown) + if (!send_shutdown) { return; + } /* * Let lockd know that it is no longer needed for any NFS mounts @@ -174,14 +186,15 @@ nfs_lockd_mount_unregister(struct nfsmount *nmp) kr = host_get_lockd_port(host_priv_self(), &lockd_port); if ((kr != KERN_SUCCESS) || !IPC_PORT_VALID(lockd_port)) { printf("nfs_lockd_mount_change: shutdown couldn't get port, kr %d, port %s\n", - kr, (lockd_port == IPC_PORT_NULL) ? "NULL" : - (lockd_port == IPC_PORT_DEAD) ? "DEAD" : "VALID"); + kr, (lockd_port == IPC_PORT_NULL) ? "NULL" : + (lockd_port == IPC_PORT_DEAD) ? "DEAD" : "VALID"); return; } kr = lockd_shutdown(lockd_port); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { printf("nfs_lockd_mount_change: shutdown %d\n", kr); + } ipc_port_release_send(lockd_port); } @@ -240,10 +253,12 @@ nfs_lockdmsg_find_by_xid(uint64_t lockxid) LOCKD_MSG_REQUEST *mr; TAILQ_FOREACH(mr, &nfs_pendlockq, lmr_next) { - if (mr->lmr_msg.lm_xid == lockxid) + if (mr->lmr_msg.lm_xid == lockxid) { return mr; - if (mr->lmr_msg.lm_xid > lockxid) + } + if (mr->lmr_msg.lm_xid > lockxid) { return NULL; + } } return mr; } @@ -263,18 +278,24 @@ nfs_lockdmsg_find_by_xid(uint64_t lockxid) int nfs_lockdmsg_compare_to_answer(LOCKD_MSG_REQUEST *msgreq, struct lockd_ans *ansp) { - if (!(ansp->la_flags & LOCKD_ANS_LOCK_INFO)) + if (!(ansp->la_flags & LOCKD_ANS_LOCK_INFO)) { return 1; - if (msgreq->lmr_msg.lm_fl.l_pid != ansp->la_pid) + } + if (msgreq->lmr_msg.lm_fl.l_pid != ansp->la_pid) { return 1; - if (msgreq->lmr_msg.lm_fl.l_start != ansp->la_start) + } + if (msgreq->lmr_msg.lm_fl.l_start != ansp->la_start) { return 1; - if (msgreq->lmr_msg.lm_fl.l_len != ansp->la_len) + } + if (msgreq->lmr_msg.lm_fl.l_len != ansp->la_len) { return 1; - if (msgreq->lmr_msg.lm_fh_len != ansp->la_fh_len) + } + if (msgreq->lmr_msg.lm_fh_len != ansp->la_fh_len) { return 1; - if (bcmp(msgreq->lmr_msg.lm_fh, ansp->la_fh, ansp->la_fh_len)) + } + if (bcmp(msgreq->lmr_msg.lm_fh, ansp->la_fh, ansp->la_fh_len)) { return 1; + } return 0; } @@ -298,11 +319,13 @@ nfs_lockdmsg_find_by_answer(struct lockd_ans *ansp) { LOCKD_MSG_REQUEST *mr; - if (!(ansp->la_flags & LOCKD_ANS_LOCK_INFO)) + if (!(ansp->la_flags & LOCKD_ANS_LOCK_INFO)) { return NULL; + } TAILQ_FOREACH(mr, &nfs_pendlockq, lmr_next) { - if (!nfs_lockdmsg_compare_to_answer(mr, ansp)) + if (!nfs_lockdmsg_compare_to_answer(mr, ansp)) { break; + } } return mr; } @@ -332,10 +355,11 @@ nfs_lockxid_get(void) /* make sure we get a unique xid */ do { /* Skip zero xid if it should ever happen. */ - if (++nfs_lockxid == 0) + if (++nfs_lockxid == 0) { nfs_lockxid++; + } if (!(mr = TAILQ_LAST(&nfs_pendlockq, nfs_lock_msg_queue)) || - (mr->lmr_msg.lm_xid < nfs_lockxid)) { + (mr->lmr_msg.lm_xid < nfs_lockxid)) { /* fast path: empty queue or new largest xid */ break; } @@ -355,8 +379,9 @@ nfs_lockd_send_request(LOCKD_MSG *msg, int interruptable) mach_port_t lockd_port = IPC_PORT_NULL; kr = host_get_lockd_port(host_priv_self(), &lockd_port); - if (kr != KERN_SUCCESS || !IPC_PORT_VALID(lockd_port)) - return (ENOTSUP); + if (kr != KERN_SUCCESS || !IPC_PORT_VALID(lockd_port)) { + return ENOTSUP; + } do { /* In the kernel all mach messaging is interruptable */ @@ -375,26 +400,25 @@ nfs_lockd_send_request(LOCKD_MSG *msg, int interruptable) (uint32_t *)&msg->lm_cred, msg->lm_fh_len, msg->lm_fh); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { printf("lockd_request received %d!\n", kr); + } } while (!interruptable && kr == MACH_SEND_INTERRUPTED); } while (kr == MIG_SERVER_DIED && retries++ < MACH_MAX_TRIES); ipc_port_release_send(lockd_port); switch (kr) { - case MACH_SEND_INTERRUPTED: - return (EINTR); + case MACH_SEND_INTERRUPTED: + return EINTR; default: /* * Other MACH or MIG errors we will retry. Eventually - * we will call nfs_down and allow the user to disable + * we will call nfs_down and allow the user to disable * locking. */ - return (EAGAIN); + return EAGAIN; } - return (kr); } - /* * NFS advisory byte-level locks (client) @@ -412,23 +436,26 @@ nfs3_lockd_request( int interruptable, slpflag; struct nfsmount *nmp; struct timeval now; - int timeo, starttime, endtime, lastmsg, wentdown = 0; + int timeo, wentdown = 0; + long starttime, endtime, lastmsg; struct timespec ts; struct sockaddr *saddr; nmp = NFSTONMP(np); - if (!nmp || !nmp->nm_saddr) - return (ENXIO); + if (!nmp || !nmp->nm_saddr) { + return ENXIO; + } lck_mtx_lock(&nmp->nm_lock); saddr = nmp->nm_saddr; bcopy(saddr, &msg->lm_addr, min(sizeof msg->lm_addr, saddr->sa_len)); - if (nmp->nm_vers == NFS_VER3) + if (nmp->nm_vers == NFS_VER3) { msg->lm_flags |= LOCKD_MSG_NFSV3; -#if 0 /* not yet */ - if (nmp->nm_sotype != SOCK_DGRAM) + } + + if (nmp->nm_sotype != SOCK_DGRAM) { msg->lm_flags |= LOCKD_MSG_TCP; -#endif + } microuptime(&now); starttime = now.tv_sec; @@ -451,8 +478,9 @@ nfs3_lockd_request( lck_mtx_unlock(nfs_lock_mutex); error = nfs_lockd_send_request(msg, interruptable); lck_mtx_lock(nfs_lock_mutex); - if (error && error != EAGAIN) + if (error && error != EAGAIN) { break; + } /* * Always wait for an answer. Not waiting for unlocks could @@ -508,16 +536,18 @@ wait_for_granted: } break; } - if (error != EWOULDBLOCK) + if (error != EWOULDBLOCK) { break; + } /* check that we still have our mount... */ /* ...and that we still support locks */ /* ...and that there isn't a recovery pending */ nmp = NFSTONMP(np); if ((error2 = nfs_sigintr(nmp, NULL, NULL, 0))) { error = error2; - if (type == F_UNLCK) + if (type == F_UNLCK) { printf("nfs3_lockd_request: aborting unlock request, error %d\n", error); + } break; } lck_mtx_lock(&nmp->nm_lock); @@ -541,16 +571,18 @@ wait_for_granted: if ((error2 = nfs_sigintr(nmp, NULL, NULL, 0))) { error = error2; if (error2 != EINTR) { - if (type == F_UNLCK) + if (type == F_UNLCK) { printf("nfs3_lockd_request: aborting unlock request, error %d\n", error); + } break; } } /* ...and that we still support locks */ lck_mtx_lock(&nmp->nm_lock); if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) { - if (error == EWOULDBLOCK) + if (error == EWOULDBLOCK) { error = ENOTSUP; + } lck_mtx_unlock(&nmp->nm_lock); break; } @@ -603,10 +635,11 @@ wait_for_granted: ((lastmsg + nmp->nm_tprintf_delay) < now.tv_sec)) { lck_mtx_unlock(&nmp->nm_lock); lastmsg = now.tv_sec; - nfs_down(nmp, thd, 0, NFSSTA_LOCKTIMEO, "lockd not responding"); + nfs_down(nmp, thd, 0, NFSSTA_LOCKTIMEO, "lockd not responding", 1); wentdown = 1; - } else + } else { lck_mtx_unlock(&nmp->nm_lock); + } if (msgreq->lmr_errno == EINPROGRESS) { /* @@ -635,17 +668,19 @@ wait_for_granted: /* * We timed out, so we will resend the request. */ - if (!(flags & R_RECOVER)) + if (!(flags & R_RECOVER)) { timeo *= 2; - if (timeo > 30) + } + if (timeo > 30) { timeo = 30; + } /* resend request */ continue; } /* we got a reponse, so the server's lockd is OK */ nfs_up(NFSTONMP(np), thd, NFSSTA_LOCKTIMEO, - wentdown ? "lockd alive again" : NULL); + wentdown ? "lockd alive again" : NULL); wentdown = 0; if (msgreq->lmr_answered && (msg->lm_flags & LOCKD_MSG_DENIED_GRACE)) { @@ -675,8 +710,8 @@ wait_for_granted: * higher levels can resend the request. */ msg->lm_flags &= ~LOCKD_MSG_CANCEL; - nfs_lockdmsg_dequeue(msgreq); error = NFSERR_DENIED; + /* Will dequeue msgreq after the following break at the end of this routine */ break; } @@ -710,15 +745,16 @@ wait_for_granted: nmp->nm_state &= ~NFSSTA_LOCKTIMEO; lck_mtx_unlock(&nmp->nm_lock); printf("lockd returned ENOTSUP, disabling locks for nfs server: %s\n", - vfs_statfs(nmp->nm_mountp)->f_mntfromname); - return (error); + vfs_statfs(nmp->nm_mountp)->f_mntfromname); + return error; } if (!error) { /* record that NFS file locking has worked on this mount */ if (nmp) { lck_mtx_lock(&nmp->nm_lock); - if (!(nmp->nm_state & NFSSTA_LOCKSWORK)) + if (!(nmp->nm_state & NFSSTA_LOCKSWORK)) { nmp->nm_state |= NFSSTA_LOCKSWORK; + } lck_mtx_unlock(&nmp->nm_lock); } } @@ -729,7 +765,7 @@ wait_for_granted: lck_mtx_unlock(nfs_lock_mutex); - return (error); + return error; } /* @@ -752,24 +788,28 @@ nfs3_setlock_rpc( LOCKD_MSG *msg; nmp = NFSTONMP(np); - if (!nmp) - return (ENXIO); + if (nfs_mount_gone(nmp)) { + return ENXIO; + } if (!nlop->nlo_open_owner) { nfs_open_owner_ref(nofp->nof_owner); nlop->nlo_open_owner = nofp->nof_owner; } - if ((error = nfs_lock_owner_set_busy(nlop, thd))) - return (error); + if ((error = nfs_lock_owner_set_busy(nlop, thd))) { + return error; + } /* set up lock message request structure */ bzero(&msgreq, sizeof(msgreq)); msg = &msgreq.lmr_msg; msg->lm_version = LOCKD_MSG_VERSION; - if ((nflp->nfl_flags & NFS_FILE_LOCK_WAIT) && !reclaim) + if ((nflp->nfl_flags & NFS_FILE_LOCK_WAIT) && !reclaim) { msg->lm_flags |= LOCKD_MSG_BLOCK; - if (reclaim) + } + if (reclaim) { msg->lm_flags |= LOCKD_MSG_RECLAIM; + } msg->lm_fh_len = (nmp->nm_vers == NFS_VER2) ? NFSX_V2FH : np->n_fhsize; bcopy(np->n_fhp, msg->lm_fh, msg->lm_fh_len); cru2x(cred, &msg->lm_cred); @@ -783,7 +823,7 @@ nfs3_setlock_rpc( error = nfs3_lockd_request(np, 0, &msgreq, flags, thd); nfs_lock_owner_clear_busy(nlop); - return (error); + return error; } /* @@ -805,8 +845,9 @@ nfs3_unlock_rpc( LOCKD_MSG *msg; nmp = NFSTONMP(np); - if (!nmp) - return (ENXIO); + if (!nmp) { + return ENXIO; + } /* set up lock message request structure */ bzero(&msgreq, sizeof(msgreq)); @@ -822,7 +863,7 @@ nfs3_unlock_rpc( msg->lm_fl.l_type = F_UNLCK; msg->lm_fl.l_pid = nlop->nlo_pid; - return (nfs3_lockd_request(np, F_UNLCK, &msgreq, flags, thd)); + return nfs3_lockd_request(np, F_UNLCK, &msgreq, flags, thd); } /* @@ -843,8 +884,9 @@ nfs3_getlock_rpc( LOCKD_MSG *msg; nmp = NFSTONMP(np); - if (!nmp) - return (ENXIO); + if (nfs_mount_gone(nmp)) { + return ENXIO; + } /* set up lock message request structure */ bzero(&msgreq, sizeof(msgreq)); @@ -870,11 +912,12 @@ nfs3_getlock_rpc( fl->l_start = msg->lm_fl.l_start; fl->l_len = msg->lm_fl.l_len; fl->l_whence = SEEK_SET; - } else + } else { fl->l_type = F_UNLCK; + } } - return (error); + return error; } /* @@ -889,12 +932,14 @@ nfslockdans(proc_t p, struct lockd_ans *ansp) /* Let root make this call. */ error = proc_suser(p); - if (error) - return (error); + if (error) { + return error; + } /* the version should match, or we're out of sync */ - if (ansp->la_version != LOCKD_ANS_VERSION) - return (EINVAL); + if (ansp->la_version != LOCKD_ANS_VERSION) { + return EINVAL; + } lck_mtx_lock(nfs_lock_mutex); @@ -907,27 +952,30 @@ nfslockdans(proc_t p, struct lockd_ans *ansp) * If no message was found or it doesn't match the answer, * we look for the lockd message by the answer's lock info. */ - if (!msgreq || nfs_lockdmsg_compare_to_answer(msgreq, ansp)) + if (!msgreq || nfs_lockdmsg_compare_to_answer(msgreq, ansp)) { msgreq = nfs_lockdmsg_find_by_answer(ansp); + } /* * We need to make sure this request isn't being cancelled * If it is, we don't want to accept the granted message. */ - if (msgreq && (msgreq->lmr_msg.lm_flags & LOCKD_MSG_CANCEL)) + if (msgreq && (msgreq->lmr_msg.lm_flags & LOCKD_MSG_CANCEL)) { msgreq = NULL; + } } if (!msgreq) { lck_mtx_unlock(nfs_lock_mutex); - return (EPIPE); + return EPIPE; } msgreq->lmr_errno = ansp->la_errno; if ((msgreq->lmr_msg.lm_flags & LOCKD_MSG_TEST) && msgreq->lmr_errno == 0) { if (ansp->la_flags & LOCKD_ANS_LOCK_INFO) { - if (ansp->la_flags & LOCKD_ANS_LOCK_EXCL) + if (ansp->la_flags & LOCKD_ANS_LOCK_EXCL) { msgreq->lmr_msg.lm_fl.l_type = F_WRLCK; - else + } else { msgreq->lmr_msg.lm_fl.l_type = F_RDLCK; + } msgreq->lmr_msg.lm_fl.l_pid = ansp->la_pid; msgreq->lmr_msg.lm_fl.l_start = ansp->la_start; msgreq->lmr_msg.lm_fl.l_len = ansp->la_len; @@ -935,14 +983,15 @@ nfslockdans(proc_t p, struct lockd_ans *ansp) msgreq->lmr_msg.lm_fl.l_type = F_UNLCK; } } - if (ansp->la_flags & LOCKD_ANS_DENIED_GRACE) + if (ansp->la_flags & LOCKD_ANS_DENIED_GRACE) { msgreq->lmr_msg.lm_flags |= LOCKD_MSG_DENIED_GRACE; + } msgreq->lmr_answered = 1; lck_mtx_unlock(nfs_lock_mutex); wakeup(msgreq); - return (0); + return 0; } /* @@ -962,32 +1011,38 @@ nfslockdnotify(proc_t p, user_addr_t argp) /* Let root make this call. */ error = proc_suser(p); - if (error) - return (error); + if (error) { + return error; + } headsize = (char*)&ln.ln_addr[0] - (char*)&ln.ln_version; error = copyin(argp, &ln, headsize); - if (error) - return (error); - if (ln.ln_version != LOCKD_NOTIFY_VERSION) - return (EINVAL); - if ((ln.ln_addrcount < 1) || (ln.ln_addrcount > 128)) - return (EINVAL); + if (error) { + return error; + } + if (ln.ln_version != LOCKD_NOTIFY_VERSION) { + return EINVAL; + } + if ((ln.ln_addrcount < 1) || (ln.ln_addrcount > 128)) { + return EINVAL; + } argp += headsize; saddr = (struct sockaddr *)&ln.ln_addr[0]; lck_mtx_lock(nfs_lock_mutex); - for (i=0; i < ln.ln_addrcount; i++) { + for (i = 0; i < ln.ln_addrcount; i++) { error = copyin(argp, &ln.ln_addr[0], sizeof(ln.ln_addr[0])); - if (error) + if (error) { break; + } argp += sizeof(ln.ln_addr[0]); /* scan lockd mount list for match to this address */ TAILQ_FOREACH(nmp, &nfs_lockd_mount_list, nm_ldlink) { /* check if address matches this mount's server address */ - if (!nmp->nm_saddr || nfs_sockaddr_cmp(saddr, nmp->nm_saddr)) + if (!nmp->nm_saddr || nfs_sockaddr_cmp(saddr, nmp->nm_saddr)) { continue; + } /* We have a match! Mark it as needing recovery. */ lck_mtx_lock(&nmp->nm_lock); nfs_need_recover(nmp, 0); @@ -997,6 +1052,7 @@ nfslockdnotify(proc_t p, user_addr_t argp) lck_mtx_unlock(nfs_lock_mutex); - return (error); + return error; } +#endif /* CONFIG_NFS_CLIENT */