kernel - NFS server cleanup and xid atomic ops
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 21 Aug 2010 21:26:12 +0000 (14:26 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 21 Aug 2010 21:26:12 +0000 (14:26 -0700)
* Use atomic_fetchadd_int() to allocate xid's in two places.

* NULL out rp fields and clear flags after freeing their pointers,
  for safety.

sys/vfs/nfs/krpc_subr.c
sys/vfs/nfs/nfs_srvcache.c
sys/vfs/nfs/nfsm_subs.c

index 838cbc9..0df0063 100644 (file)
@@ -201,7 +201,8 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func,
        struct timeval tv;
        struct sockbuf sio;
        int error, rcvflg, timo, secs, len;
-       static u_int32_t xid = ~0xFF;
+       static u_int32_t static_xid = ~0xFF;
+       u_int32_t xid;
        u_int16_t tport;
        u_int32_t saddr;
 
@@ -280,7 +281,9 @@ krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func,
        mhead->m_len = sizeof(*call);
        bzero((caddr_t)call, sizeof(*call));
        /* rpc_call part */
-       xid++;
+       do {
+               xid = atomic_fetchadd_int(&static_xid, 1);
+       } while (xid == 0);
        call->rp_xid = txdr_unsigned(xid);
        /* call->rp_direction = 0; */
        call->rp_rpcvers = txdr_unsigned(2);
index 00cd75b..355eedb 100644 (file)
@@ -176,7 +176,7 @@ loop:
                        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, 0, "nfsrc", 0);
+                               tsleep((caddr_t)rp, 0, "nfsrc", 0);
                                goto loop;
                        }
                        rp->rc_flag |= RC_LOCKED;
@@ -216,24 +216,29 @@ loop:
        nfsstats.srvcache_misses++;
        NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff));
        if (numnfsrvcache < desirednfsrvcache) {
-               rp = (struct nfsrvcache *)kmalloc((u_long)sizeof *rp,
-                   M_NFSD, M_WAITOK | M_ZERO);
+               rp = kmalloc((u_long)sizeof *rp, M_NFSD, M_WAITOK | M_ZERO);
                numnfsrvcache++;
                rp->rc_flag = RC_LOCKED;
        } else {
                rp = TAILQ_FIRST(&nfsrvlruhead);
                while ((rp->rc_flag & RC_LOCKED) != 0) {
                        rp->rc_flag |= RC_WANTED;
-                       (void) tsleep((caddr_t)rp, 0, "nfsrc", 0);
+                       tsleep((caddr_t)rp, 0, "nfsrc", 0);
                        rp = TAILQ_FIRST(&nfsrvlruhead);
                }
                rp->rc_flag |= RC_LOCKED;
                LIST_REMOVE(rp, rc_hash);
                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
-               if (rp->rc_flag & RC_REPMBUF)
+               if (rp->rc_flag & RC_REPMBUF) {
                        m_freem(rp->rc_reply);
-               if (rp->rc_flag & RC_NAM)
+                       rp->rc_reply = NULL;
+                       rp->rc_flag &= ~RC_REPMBUF;
+               }
+               if (rp->rc_flag & RC_NAM) {
                        FREE(rp->rc_nam, M_SONAME);
+                       rp->rc_nam = NULL;
+                       rp->rc_flag &= ~RC_NAM;
+               }
                rp->rc_flag &= (RC_LOCKED | RC_WANTED);
        }
        TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
@@ -279,7 +284,7 @@ loop:
                        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, 0, "nfsrc", 0);
+                               tsleep((caddr_t)rp, 0, "nfsrc", 0);
                                goto loop;
                        }
                        rp->rc_flag |= RC_LOCKED;
@@ -292,10 +297,12 @@ loop:
                                 */
                                if (rp->rc_flag & RC_REPMBUF) {
                                        m_freem(rp->rc_reply);
+                                       rp->rc_reply = NULL;
                                        rp->rc_flag &= ~RC_REPMBUF;
                                }
                        }
                        rp->rc_state = RC_DONE;
+
                        /*
                         * If we have a valid reply update status and save
                         * the reply for non-idempotent rpc's.
@@ -306,8 +313,13 @@ loop:
                                        rp->rc_status = nd->nd_repstat;
                                        rp->rc_flag |= RC_REPSTATUS;
                                } else {
-                                       rp->rc_reply = m_copym(repmbuf,
-                                               0, M_COPYALL, MB_WAIT);
+                                       if (rp->rc_flag & RC_REPMBUF) {
+                                               m_freem(rp->rc_reply);
+                                               rp->rc_reply = NULL;
+                                               rp->rc_flag &= ~RC_REPMBUF;
+                                       }
+                                       rp->rc_reply = m_copym(repmbuf, 0,
+                                                       M_COPYALL, MB_WAIT);
                                        rp->rc_flag |= RC_REPMBUF;
                                }
                        }
@@ -328,15 +340,26 @@ loop:
 void
 nfsrv_cleancache(void)
 {
-       struct nfsrvcache *rp, *nextrp;
+       struct nfsrvcache *rp;
 
-       TAILQ_FOREACH_MUTABLE(rp, &nfsrvlruhead, rc_lru, nextrp) {
+       while ((rp = TAILQ_FIRST(&nfsrvlruhead)) != NULL) {
+               if (rp->rc_flag & RC_LOCKED) {
+                       rp->rc_flag |= RC_WANTED;
+                       tsleep((caddr_t)rp, 0, "nfsrc", 0);
+                       continue;
+               }
                LIST_REMOVE(rp, rc_hash);
                TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
-               if (rp->rc_flag & RC_REPMBUF)
+               if (rp->rc_flag & RC_REPMBUF) {
                        m_freem(rp->rc_reply);
-               if (rp->rc_flag & RC_NAM)
+                       rp->rc_reply = NULL;
+                       rp->rc_flag &= ~RC_REPMBUF;
+               }
+               if (rp->rc_flag & RC_NAM) {
                        kfree(rp->rc_nam, M_SONAME);
+                       rp->rc_nam = NULL;
+                       rp->rc_flag &= ~RC_NAM;
+               }
                kfree(rp, M_NFSD);
        }
        numnfsrvcache = 0;
index 4c19e87..e38c6f4 100644 (file)
@@ -139,6 +139,7 @@ nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
        struct nfsm_info info;
        struct mbuf *mb2;
        u_int32_t *tl;
+       u_int32_t xid;
        int siz, grpsiz, authsiz, dsiz;
        int i;
 
@@ -163,13 +164,12 @@ nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
        /* Get a pretty random xid to start with */
        if (!nfs_xid)
                nfs_xid = krandom();
-       /*
-        * Skip zero xid if it should ever happen.
-        */
-       if (++nfs_xid == 0)
-               nfs_xid++;
 
-       *tl++ = *xidp = txdr_unsigned(nfs_xid);
+       do {
+               xid = atomic_fetchadd_int(&nfs_xid, 1);
+       } while (xid == 0);
+
+       *tl++ = *xidp = txdr_unsigned(xid);
        *tl++ = rpc_call;
        *tl++ = rpc_vers;
        *tl++ = txdr_unsigned(NFS_PROG);