xfs: refactor xlog_recover_process_data()
authorDave Chinner <dchinner@redhat.com>
Sun, 28 Sep 2014 23:45:03 +0000 (09:45 +1000)
committerDave Chinner <david@fromorbit.com>
Sun, 28 Sep 2014 23:45:03 +0000 (09:45 +1000)
Clean up xlog_recover_process_data() structure in preparation for
fixing the allocation and freeing context of the transaction being
recovered.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Chinner <david@fromorbit.com>
fs/xfs/xfs_log_recover.c

index 1fd5787add9924d7ac726329f2ee88c13a90422d..8105b857197953f022e484b8423da6ed3244167a 100644 (file)
@@ -3535,12 +3535,124 @@ out:
 }
 
 STATIC int
-xlog_recover_unmount_trans(
-       struct xlog             *log)
+xlog_recovery_process_trans(
+       struct xlog             *log,
+       struct xlog_recover     *trans,
+       xfs_caddr_t             dp,
+       unsigned int            len,
+       unsigned int            flags,
+       int                     pass)
 {
-       /* Do nothing now */
-       xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
-       return 0;
+       int                     error = -EIO;
+
+       /* mask off ophdr transaction container flags */
+       flags &= ~XLOG_END_TRANS;
+       if (flags & XLOG_WAS_CONT_TRANS)
+               flags &= ~XLOG_CONTINUE_TRANS;
+
+       switch (flags) {
+       /* expected flag values */
+       case 0:
+       case XLOG_CONTINUE_TRANS:
+               error = xlog_recover_add_to_trans(log, trans, dp, len);
+               break;
+       case XLOG_WAS_CONT_TRANS:
+               error = xlog_recover_add_to_cont_trans(log, trans, dp, len);
+               break;
+       case XLOG_COMMIT_TRANS:
+               error = xlog_recover_commit_trans(log, trans, pass);
+               break;
+
+       /* unexpected flag values */
+       case XLOG_UNMOUNT_TRANS:
+               xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
+               error = 0; /* just skip trans */
+               break;
+       case XLOG_START_TRANS:
+               xfs_warn(log->l_mp, "%s: bad transaction", __func__);
+               ASSERT(0);
+               break;
+       default:
+               xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags);
+               ASSERT(0);
+               break;
+       }
+       return error;
+}
+
+STATIC struct xlog_recover *
+xlog_recover_ophdr_to_trans(
+       struct hlist_head       rhash[],
+       struct xlog_rec_header  *rhead,
+       struct xlog_op_header   *ohead)
+{
+       struct xlog_recover     *trans;
+       xlog_tid_t              tid;
+       struct hlist_head       *rhp;
+
+       tid = be32_to_cpu(ohead->oh_tid);
+       rhp = &rhash[XLOG_RHASH(tid)];
+       trans = xlog_recover_find_tid(rhp, tid);
+       if (trans)
+               return trans;
+
+       /*
+        * If this is a new transaction, the ophdr only contains the
+        * start record. In that case, the only processing we need to do
+        * on this opheader is allocate a new recovery container to hold
+        * the recovery ops that will follow.
+        */
+       if (ohead->oh_flags & XLOG_START_TRANS) {
+               ASSERT(be32_to_cpu(ohead->oh_len) == 0);
+               xlog_recover_new_tid(rhp, tid, be64_to_cpu(rhead->h_lsn));
+       }
+       return NULL;
+}
+
+STATIC int
+xlog_recover_process_ophdr(
+       struct xlog             *log,
+       struct hlist_head       rhash[],
+       struct xlog_rec_header  *rhead,
+       struct xlog_op_header   *ohead,
+       xfs_caddr_t             dp,
+       xfs_caddr_t             end,
+       int                     pass)
+{
+       struct xlog_recover     *trans;
+       int                     error;
+       unsigned int            len;
+
+       /* Do we understand who wrote this op? */
+       if (ohead->oh_clientid != XFS_TRANSACTION &&
+           ohead->oh_clientid != XFS_LOG) {
+               xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
+                       __func__, ohead->oh_clientid);
+               ASSERT(0);
+               return -EIO;
+       }
+
+       /*
+        * Check the ophdr contains all the data it is supposed to contain.
+        */
+       len = be32_to_cpu(ohead->oh_len);
+       if (dp + len > end) {
+               xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, len);
+               WARN_ON(1);
+               return -EIO;
+       }
+
+       trans = xlog_recover_ophdr_to_trans(rhash, rhead, ohead);
+       if (!trans) {
+               /* nothing to do, so skip over this ophdr */
+               return 0;
+       }
+
+       error = xlog_recovery_process_trans(log, trans, dp, len,
+                                           ohead->oh_flags, pass);
+       if (error)
+               xlog_recover_free_trans(trans);
+       return error;
 }
 
 /*
@@ -3560,86 +3672,30 @@ xlog_recover_process_data(
        xfs_caddr_t             dp,
        int                     pass)
 {
-       xfs_caddr_t             lp;
+       struct xlog_op_header   *ohead;
+       xfs_caddr_t             end;
        int                     num_logops;
-       xlog_op_header_t        *ohead;
-       xlog_recover_t          *trans;
-       xlog_tid_t              tid;
        int                     error;
-       unsigned long           hash;
-       uint                    flags;
 
-       lp = dp + be32_to_cpu(rhead->h_len);
+       end = dp + be32_to_cpu(rhead->h_len);
        num_logops = be32_to_cpu(rhead->h_num_logops);
 
        /* check the log format matches our own - else we can't recover */
        if (xlog_header_check_recover(log->l_mp, rhead))
                return -EIO;
 
-       while ((dp < lp) && num_logops) {
-               ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
-               ohead = (xlog_op_header_t *)dp;
-               dp += sizeof(xlog_op_header_t);
-               if (ohead->oh_clientid != XFS_TRANSACTION &&
-                   ohead->oh_clientid != XFS_LOG) {
-                       xfs_warn(log->l_mp, "%s: bad clientid 0x%x",
-                                       __func__, ohead->oh_clientid);
-                       ASSERT(0);
-                       return -EIO;
-               }
-               tid = be32_to_cpu(ohead->oh_tid);
-               hash = XLOG_RHASH(tid);
-               trans = xlog_recover_find_tid(&rhash[hash], tid);
-               if (trans == NULL) {               /* not found; add new tid */
-                       if (ohead->oh_flags & XLOG_START_TRANS)
-                               xlog_recover_new_tid(&rhash[hash], tid,
-                                       be64_to_cpu(rhead->h_lsn));
-               } else {
-                       if (dp + be32_to_cpu(ohead->oh_len) > lp) {
-                               xfs_warn(log->l_mp, "%s: bad length 0x%x",
-                                       __func__, be32_to_cpu(ohead->oh_len));
-                               WARN_ON(1);
-                               return -EIO;
-                       }
-                       flags = ohead->oh_flags & ~XLOG_END_TRANS;
-                       if (flags & XLOG_WAS_CONT_TRANS)
-                               flags &= ~XLOG_CONTINUE_TRANS;
-                       switch (flags) {
-                       case XLOG_COMMIT_TRANS:
-                               error = xlog_recover_commit_trans(log,
-                                                               trans, pass);
-                               break;
-                       case XLOG_UNMOUNT_TRANS:
-                               error = xlog_recover_unmount_trans(log);
-                               break;
-                       case XLOG_WAS_CONT_TRANS:
-                               error = xlog_recover_add_to_cont_trans(log,
-                                               trans, dp,
-                                               be32_to_cpu(ohead->oh_len));
-                               break;
-                       case XLOG_START_TRANS:
-                               xfs_warn(log->l_mp, "%s: bad transaction",
-                                       __func__);
-                               ASSERT(0);
-                               error = -EIO;
-                               break;
-                       case 0:
-                       case XLOG_CONTINUE_TRANS:
-                               error = xlog_recover_add_to_trans(log, trans,
-                                               dp, be32_to_cpu(ohead->oh_len));
-                               break;
-                       default:
-                               xfs_warn(log->l_mp, "%s: bad flag 0x%x",
-                                       __func__, flags);
-                               ASSERT(0);
-                               error = -EIO;
-                               break;
-                       }
-                       if (error) {
-                               xlog_recover_free_trans(trans);
-                               return error;
-                       }
-               }
+       while ((dp < end) && num_logops) {
+
+               ohead = (struct xlog_op_header *)dp;
+               dp += sizeof(*ohead);
+               ASSERT(dp <= end);
+
+               /* errors will abort recovery */
+               error = xlog_recover_process_ophdr(log, rhash, rhead, ohead,
+                                                   dp, end, pass);
+               if (error)
+                       return error;
+
                dp += be32_to_cpu(ohead->oh_len);
                num_logops--;
        }