xfs
[Top] [All Lists]

[PATCH 13/13] xfs: add CRC checks for quota blocks

To: xfs@xxxxxxxxxxx
Subject: [PATCH 13/13] xfs: add CRC checks for quota blocks
From: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Date: Tue, 10 Feb 2009 15:22:54 -0500
References: <20090210202241.546501000@xxxxxxxxxxxxxxxxxxxxxx>
User-agent: quilt/0.47-1
Use the reserved space in struct xfs_dqblk to store a UUID and a crc
for the quota blocks.

I'm pondering if we should just move the crc check into xfs_qm_dqcheck
where all the other validity checks are located.


Signed-off-by: Christoph Hellwig <hch@xxxxxx>

Index: xfs/fs/xfs/xfs_quota.h
===================================================================
--- xfs.orig/fs/xfs/xfs_quota.h 2009-02-09 08:47:34.234069111 +0100
+++ xfs/fs/xfs/xfs_quota.h      2009-02-10 20:15:36.874947481 +0100
@@ -77,7 +77,13 @@ typedef struct       xfs_disk_dquot {
  */
 typedef struct xfs_dqblk {
        xfs_disk_dquot_t  dd_diskdq;    /* portion that lives incore as well */
-       char              dd_fill[32];  /* filling for posterity */
+       char              dd_fill[12];  /* filling for posterity */
+
+       /*
+        * These two are only present one filesystems with the CRC bits set.
+        */
+       __be32            dd_crc;       /* checksum */
+       uuid_t            dd_uuid;      /* location information */
 } xfs_dqblk_t;
 
 /*
Index: xfs/fs/xfs/quota/xfs_dquot.c
===================================================================
--- xfs.orig/fs/xfs/quota/xfs_dquot.c   2009-02-10 19:55:01.982070089 +0100
+++ xfs/fs/xfs/quota/xfs_dquot.c        2009-02-10 20:23:25.618944664 +0100
@@ -48,6 +48,7 @@
 #include "xfs_trans_space.h"
 #include "xfs_trans_priv.h"
 #include "xfs_qm.h"
+#include "xfs_cksum.h"
 
 
 /*
@@ -368,6 +369,40 @@ xfs_qm_adjust_dqtimers(
        }
 }
 
+STATIC void
+xfs_dquot_calc_crc(
+       struct xfs_buf          *bp)
+{
+       struct xfs_dqblk        *d = (struct xfs_dqblk *)XFS_BUF_PTR(bp);
+       int                     i;
+
+       for (i = 0; i < XFS_QM_DQPERBLK(bp->b_mount); i++, d++) {
+               xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk),
+                                offsetof(struct xfs_dqblk, dd_crc));
+       }
+}
+
+STATIC int
+xfs_dquot_verify_crc(
+       struct xfs_mount        *mp,
+       struct xfs_buf          *bp)
+{
+       struct xfs_dqblk        *d = (struct xfs_dqblk *)XFS_BUF_PTR(bp);
+       int                     i;
+
+       for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++) {
+               if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
+                                offsetof(struct xfs_dqblk, dd_crc))) {
+//                 !uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_uuid) ||
+                       XFS_CORRUPTION_ERROR("xfs_qm_dqtobp crc",
+                                       XFS_ERRLEVEL_LOW, mp, d);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+       }
+
+       return 0;
+}
+
 /*
  * initialize a buffer full of dquots and log the whole thing
  */
@@ -476,6 +511,10 @@ xfs_qm_dqalloc(
                               0);
        if (!bp || (error = XFS_BUF_GETERROR(bp)))
                goto error1;
+
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               xfs_buf_set_io_callback(bp, xfs_dquot_calc_crc);
+
        /*
         * Make a chunk of dquots out of this buffer and log
         * the entire thing.
@@ -539,6 +578,7 @@ xfs_qm_dqtobp(
        xfs_inode_t     *quotip;
        xfs_mount_t     *mp;
        xfs_disk_dquot_t *ddq;
+       struct xfs_dqblk *d;
        xfs_dqid_t      id;
        boolean_t       newdquot;
        xfs_trans_t     *tp = (tpp ? *tpp : NULL);
@@ -622,6 +662,22 @@ xfs_qm_dqtobp(
                }
                if (error || !bp)
                        return XFS_ERROR(error);
+
+               /*
+                * Validate the CRC of the AGF block only if the block is clean 
(i.e.
+                * it just came from disk).
+                */
+               if (xfs_sb_version_hascrc(&mp->m_sb) &&
+                   !(XFS_BUF_ISWRITE(bp) || XFS_BUF_ISDELAYWRITE(bp))) {
+                       error = xfs_dquot_verify_crc(mp, bp);
+                       if (error) {
+                               xfs_trans_brelse(tp, bp);
+                               return error;
+                       }
+
+                       xfs_buf_set_io_callback(bp, xfs_dquot_calc_crc);
+               }
+
        }
        ASSERT(XFS_BUF_ISBUSY(bp));
        ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
@@ -629,7 +685,8 @@ xfs_qm_dqtobp(
        /*
         * calculate the location of the dquot inside the buffer.
         */
-       ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+       d = (struct xfs_dqblk *)(XFS_BUF_PTR(bp) + dqp->q_bufoffset);
+       ddq = &d->dd_diskdq;
 
        /*
         * A simple sanity check in case we got a corrupted dquot...
Index: xfs/fs/xfs/quota/xfs_qm.c
===================================================================
--- xfs.orig/fs/xfs/quota/xfs_qm.c      2009-02-10 19:55:02.006069507 +0100
+++ xfs/fs/xfs/quota/xfs_qm.c   2009-02-10 19:58:48.005974236 +0100
@@ -1430,6 +1430,10 @@ xfs_qm_dqiter_bufs(
                if (error)
                        break;
 
+               /*
+                * XXX(hch): need to figure out if it makes sense to validate
+                *           the CRC here.
+                */
                xfs_qm_reset_dqcounts(mp, bp, firstid, type);
                xfs_bdwrite(mp, bp);
                /*

<Prev in Thread] Current Thread [Next in Thread>