kernel - Fix excessive mbuf use in nfs_realign()
[dragonfly.git] / sys / vfs / nfs / nfs_socket.c
index 294f627..c241c3c 100644 (file)
@@ -1240,7 +1240,7 @@ nfs_request_try(struct nfsreq *rep)
         * action possible is for r_mrep to be set (once we enqueue it).
         */
        if (rep->r_flags == 0xdeadc0de) {
-               print_backtrace();
+               print_backtrace(-1);
                panic("flags nbad\n");
        }
        KKASSERT((rep->r_flags & (R_LOCKED | R_ONREQQ)) == 0);
@@ -2153,49 +2153,48 @@ nfs_rcvunlock(struct nfsmount *nmp)
 }
 
 /*
- *     nfs_realign:
+ * nfs_realign:
  *
- *     Check for badly aligned mbuf data and realign by copying the unaligned
- *     portion of the data into a new mbuf chain and freeing the portions
- *     of the old chain that were replaced.
+ * Check for badly aligned mbuf data and realign by copying the unaligned
+ * portion of the data into a new mbuf chain and freeing the portions
+ * of the old chain that were replaced.
  *
- *     We cannot simply realign the data within the existing mbuf chain
- *     because the underlying buffers may contain other rpc commands and
- *     we cannot afford to overwrite them.
+ * We cannot simply realign the data within the existing mbuf chain
+ * because the underlying buffers may contain other rpc commands and
+ * we cannot afford to overwrite them.
  *
- *     We would prefer to avoid this situation entirely.  The situation does
- *     not occur with NFS/UDP and is supposed to only occassionally occur
- *     with TCP.  Use vfs.nfs.realign_count and realign_test to check this.
+ * We would prefer to avoid this situation entirely.  The situation does
+ * not occur with NFS/UDP and is supposed to only occassionally occur
+ * with TCP.  Use vfs.nfs.realign_count and realign_test to check this.
+ *
+ * NOTE!  MB_DONTWAIT cannot be used here.  The mbufs must be acquired
+ *       because the rpc request OR reply cannot be thrown away.  TCP NFS
+ *       mounts do not retry their RPCs unless the TCP connection itself
+ *       is dropped so throwing away a RPC will basically cause the NFS
+ *       operation to lockup indefinitely.
  */
 static void
 nfs_realign(struct mbuf **pm, int hsiz)
 {
        struct mbuf *m;
        struct mbuf *n = NULL;
-       int off = 0;
 
+       /*
+        * Check for misalignemnt
+        */
        ++nfs_realign_test;
-
        while ((m = *pm) != NULL) {
-               if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) {
-                       n = m_getl(m->m_len, MB_WAIT, MT_DATA, 0, NULL);
-                       n->m_len = 0;
+               if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3))
                        break;
-               }
                pm = &m->m_next;
        }
 
        /*
-        * If n is non-NULL, loop on m copying data, then replace the
-        * portion of the chain that had to be realigned.
+        * If misalignment found make a completely new copy.
         */
-       if (n != NULL) {
+       if (m) {
                ++nfs_realign_count;
-               while (m) {
-                       m_copyback(n, off, m->m_len, mtod(m, caddr_t));
-                       off += m->m_len;
-                       m = m->m_next;
-               }
+               n = m_dup_data(m, MB_WAIT);
                m_freem(*pm);
                *pm = n;
        }