]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_srvcache.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_srvcache.c
index 9e7007ddb376ba6c9dbfb7ff2cb2e1560e6c2990..c15362dad4623bdb396c5c77d5575bf814ccb534 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  */
 #include <sys/param.h>
 #include <sys/vnode.h>
-#include <sys/mount.h>
+#include <sys/mount_internal.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
-#include <sys/mbuf.h>
+#include <sys/kpi_mbuf.h>
 #include <sys/malloc.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>     /* for dup_sockaddr */
+#include <libkern/OSAtomic.h>
 
 #include <netinet/in.h>
 #if ISO
@@ -96,8 +97,10 @@ LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
 TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
 u_long nfsrvhash;
 
-#define TRUE   1
-#define        FALSE   0
+lck_grp_t *nfsrv_reqcache_lck_grp;
+lck_grp_attr_t *nfsrv_reqcache_lck_grp_attr;
+lck_attr_t *nfsrv_reqcache_lck_attr;
+lck_mtx_t *nfsrv_reqcache_mutex;
 
 #define        NETFAMILY(rp) \
                (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
@@ -129,9 +132,6 @@ static int nonidempotent[NFS_NPROCS] = {
        FALSE,
        FALSE,
        FALSE,
-       FALSE,
-       FALSE,
-       FALSE,
 };
 
 /* True iff the rpc reply is an nfs status ONLY! */
@@ -162,6 +162,11 @@ static int nfsv2_repstat[NFS_NPROCS] = {
 void
 nfsrv_initcache()
 {
+       /* init nfs server request cache mutex */
+       nfsrv_reqcache_lck_grp_attr = lck_grp_attr_alloc_init();
+       nfsrv_reqcache_lck_grp = lck_grp_alloc_init("nfsrv_reqcache", nfsrv_reqcache_lck_grp_attr);
+       nfsrv_reqcache_lck_attr = lck_attr_alloc_init();
+       nfsrv_reqcache_mutex = lck_mtx_alloc_init(nfsrv_reqcache_lck_grp, nfsrv_reqcache_lck_attr);
 
        nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash);
        TAILQ_INIT(&nfsrvlruhead);
@@ -183,15 +188,15 @@ nfsrv_initcache()
  */
 int
 nfsrv_getcache(nd, slp, repp)
-       register struct nfsrv_descript *nd;
+       struct nfsrv_descript *nd;
        struct nfssvc_sock *slp;
-       struct mbuf **repp;
+       mbuf_t *repp;
 {
-       register struct nfsrvcache *rp;
-       struct mbuf *mb;
+       struct nfsrvcache *rp;
+       mbuf_t mb;
        struct sockaddr_in *saddr;
        caddr_t bpos;
-       int ret;
+       int ret, error;
 
        /*
         * Don't cache recent requests for reliable transport protocols.
@@ -199,12 +204,12 @@ nfsrv_getcache(nd, slp, repp)
         */
        if (!nd->nd_nam2)
                return (RC_DOIT);
+       lck_mtx_lock(nfsrv_reqcache_mutex);
 loop:
        for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
            rp = rp->rc_hash.le_next) {
            if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
                netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
-                       NFS_DPF(RC, ("H%03x", rp->rc_xid & 0xfff));
                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                                rp->rc_flag |= RC_WANTED;
                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
@@ -219,20 +224,23 @@ loop:
                        if (rp->rc_state == RC_UNUSED)
                                panic("nfsrv cache");
                        if (rp->rc_state == RC_INPROG) {
-                               nfsstats.srvcache_inproghits++;
+                               OSAddAtomic(1, (SInt32*)&nfsstats.srvcache_inproghits);
                                ret = RC_DROPIT;
                        } else if (rp->rc_flag & RC_REPSTATUS) {
-                               nfsstats.srvcache_nonidemdonehits++;
-                               nfs_rephead(0, nd, slp, rp->rc_status,
-                                  0, (u_quad_t *)0, repp, &mb, &bpos);
+                               OSAddAtomic(1, (SInt32*)&nfsstats.srvcache_nonidemdonehits);
+                               nfs_rephead(0, nd, slp, rp->rc_status, repp, &mb, &bpos);
                                ret = RC_REPLY;
                        } else if (rp->rc_flag & RC_REPMBUF) {
-                               nfsstats.srvcache_nonidemdonehits++;
-                               *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
-                                               M_WAIT);
-                               ret = RC_REPLY;
+                               OSAddAtomic(1, (SInt32*)&nfsstats.srvcache_nonidemdonehits);
+                               error = mbuf_copym(rp->rc_reply, 0, MBUF_COPYALL, MBUF_WAITOK, repp);
+                               if (error) {
+                                       printf("nfsrv cache: reply copym failed for nonidem request hit\n");
+                                       ret = RC_DROPIT;
+                               } else {
+                                       ret = RC_REPLY;
+                               }
                        } else {
-                               nfsstats.srvcache_idemdonehits++;
+                               OSAddAtomic(1, (SInt32*)&nfsstats.srvcache_idemdonehits);
                                rp->rc_state = RC_INPROG;
                                ret = RC_DOIT;
                        }
@@ -241,18 +249,31 @@ loop:
                                rp->rc_flag &= ~RC_WANTED;
                                wakeup((caddr_t)rp);
                        }
+                       lck_mtx_unlock(nfsrv_reqcache_mutex);
                        return (ret);
                }
        }
-       nfsstats.srvcache_misses++;
-       NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff));
+       OSAddAtomic(1, (SInt32*)&nfsstats.srvcache_misses);
        if (numnfsrvcache < desirednfsrvcache) {
+               /* try to allocate a new entry */
                MALLOC(rp, struct nfsrvcache *, sizeof *rp, M_NFSD, M_WAITOK);
-               bzero((char *)rp, sizeof *rp);
-               numnfsrvcache++;
-               rp->rc_flag = RC_LOCKED;
+               if (rp) {
+                       bzero((char *)rp, sizeof *rp);
+                       numnfsrvcache++;
+                       rp->rc_flag = RC_LOCKED;
+               }
        } else {
+               rp = NULL;
+       }
+       if (!rp) {
+               /* try to reuse the least recently used entry */
                rp = nfsrvlruhead.tqh_first;
+               if (!rp) {
+                       /* no entry to reuse? */
+                       /* OK, we just won't be able to cache this request */
+                       lck_mtx_unlock(nfsrv_reqcache_mutex);
+                       return (RC_DOIT);
+               }
                while ((rp->rc_flag & RC_LOCKED) != 0) {
                        rp->rc_flag |= RC_WANTED;
                        (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
@@ -262,15 +283,15 @@ loop:
                LIST_REMOVE(rp, rc_hash);
                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
                if (rp->rc_flag & RC_REPMBUF)
-                       m_freem(rp->rc_reply);
+                       mbuf_freem(rp->rc_reply);
                if (rp->rc_flag & RC_NAM)
-                       MFREE(rp->rc_nam, mb);
+                       mbuf_freem(rp->rc_nam);
                rp->rc_flag &= (RC_LOCKED | RC_WANTED);
        }
        TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
        rp->rc_state = RC_INPROG;
        rp->rc_xid = nd->nd_retxid;
-       saddr = mtod(nd->nd_nam, struct sockaddr_in *);
+       saddr = mbuf_data(nd->nd_nam);
        switch (saddr->sin_family) {
        case AF_INET:
                rp->rc_flag |= RC_INETADDR;
@@ -278,8 +299,11 @@ loop:
                break;
        case AF_ISO:
        default:
-               rp->rc_flag |= RC_NAM;
-               rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT);
+               error = mbuf_copym(nd->nd_nam, 0, MBUF_COPYALL, MBUF_WAITOK, &rp->rc_nam);
+               if (error)
+                       printf("nfsrv cache: nam copym failed\n");
+               else
+                       rp->rc_flag |= RC_NAM;
                break;
        };
        rp->rc_proc = nd->nd_procnum;
@@ -289,6 +313,7 @@ loop:
                rp->rc_flag &= ~RC_WANTED;
                wakeup((caddr_t)rp);
        }
+       lck_mtx_unlock(nfsrv_reqcache_mutex);
        return (RC_DOIT);
 }
 
@@ -297,20 +322,21 @@ loop:
  */
 void
 nfsrv_updatecache(nd, repvalid, repmbuf)
-       register struct nfsrv_descript *nd;
+       struct nfsrv_descript *nd;
        int repvalid;
-       struct mbuf *repmbuf;
+       mbuf_t repmbuf;
 {
-       register struct nfsrvcache *rp;
+       struct nfsrvcache *rp;
+       int error;
 
        if (!nd->nd_nam2)
                return;
+       lck_mtx_lock(nfsrv_reqcache_mutex);
 loop:
        for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
            rp = rp->rc_hash.le_next) {
            if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
                netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
-                       NFS_DPF(RC, ("U%03x", rp->rc_xid & 0xfff));
                        if ((rp->rc_flag & RC_LOCKED) != 0) {
                                rp->rc_flag |= RC_WANTED;
                                (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
@@ -328,9 +354,9 @@ loop:
                                        rp->rc_status = nd->nd_repstat;
                                        rp->rc_flag |= RC_REPSTATUS;
                                } else {
-                                       rp->rc_reply = m_copym(repmbuf,
-                                               0, M_COPYALL, M_WAIT);
-                                       rp->rc_flag |= RC_REPMBUF;
+                                       error = mbuf_copym(repmbuf, 0, MBUF_COPYALL, MBUF_WAITOK, &rp->rc_reply);
+                                       if (!error)
+                                               rp->rc_flag |= RC_REPMBUF;
                                }
                        }
                        rp->rc_flag &= ~RC_LOCKED;
@@ -338,10 +364,11 @@ loop:
                                rp->rc_flag &= ~RC_WANTED;
                                wakeup((caddr_t)rp);
                        }
+                       lck_mtx_unlock(nfsrv_reqcache_mutex);
                        return;
                }
        }
-       NFS_DPF(RC, ("L%03x", nd->nd_retxid & 0xfff));
+       lck_mtx_unlock(nfsrv_reqcache_mutex);
 }
 
 /*
@@ -350,8 +377,9 @@ loop:
 void
 nfsrv_cleancache()
 {
-       register struct nfsrvcache *rp, *nextrp;
+       struct nfsrvcache *rp, *nextrp;
 
+       lck_mtx_lock(nfsrv_reqcache_mutex);
        for (rp = nfsrvlruhead.tqh_first; rp != 0; rp = nextrp) {
                nextrp = rp->rc_lru.tqe_next;
                LIST_REMOVE(rp, rc_hash);
@@ -359,6 +387,7 @@ nfsrv_cleancache()
                _FREE(rp, M_NFSD);
        }
        numnfsrvcache = 0;
+       lck_mtx_unlock(nfsrv_reqcache_mutex);
 }
 
 #endif /* NFS_NOSERVER */