]> Pileus Git - ~andy/linux/blobdiff - fs/xfs/xfs_dir2_data.c
Merge tag 'drm-intel-fixes-2014-03-17' of git://anongit.freedesktop.org/drm-intel...
[~andy/linux] / fs / xfs / xfs_dir2_data.c
index 00006b3db054364364a34159d70b2b01d89bcd3a..70acff4ee1739860a4ed8a311aa8ff2f2b33aafe 100644 (file)
@@ -65,22 +65,15 @@ __xfs_dir3_data_check(
        const struct xfs_dir_ops *ops;
 
        mp = bp->b_target->bt_mount;
-       hdr = bp->b_addr;
-       bf = xfs_dir3_data_bestfree_p(hdr);
-       p = (char *)xfs_dir3_data_entry_p(hdr);
 
        /*
-        * We can be passed a null dp here from a verifier, so manually
-        * configure the ops here in that case.
+        * We can be passed a null dp here from a verifier, so we need to go the
+        * hard way to get them.
         */
-       if (dp)
-               ops = dp->d_ops;
-       else if (xfs_sb_version_hascrc(&mp->m_sb))
-               ops = &xfs_dir3_ops;
-       else if (xfs_sb_version_hasftype(&mp->m_sb))
-               ops = &xfs_dir2_ftype_ops;
-       else
-               ops = &xfs_dir2_ops;
+       ops = xfs_dir_get_ops(mp, dp);
+
+       hdr = bp->b_addr;
+       p = (char *)ops->data_entry_p(hdr);
 
        switch (hdr->magic) {
        case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
@@ -88,6 +81,16 @@ __xfs_dir3_data_check(
                btp = xfs_dir2_block_tail_p(mp, hdr);
                lep = xfs_dir2_block_leaf_p(btp);
                endp = (char *)lep;
+
+               /*
+                * The number of leaf entries is limited by the size of the
+                * block and the amount of space used by the data entries.
+                * We don't know how much space is used by the data entries yet,
+                * so just ensure that the count falls somewhere inside the
+                * block right now.
+                */
+               XFS_WANT_CORRUPTED_RETURN(be32_to_cpu(btp->count) <
+                       ((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry));
                break;
        case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
        case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
@@ -98,10 +101,11 @@ __xfs_dir3_data_check(
                return EFSCORRUPTED;
        }
 
-       count = lastfree = freeseen = 0;
        /*
         * Account for zero bestfree entries.
         */
+       bf = ops->data_bestfree_p(hdr);
+       count = lastfree = freeseen = 0;
        if (!bf[0].length) {
                XFS_WANT_CORRUPTED_RETURN(!bf[0].offset);
                freeseen |= 1 << 0;
@@ -134,7 +138,7 @@ __xfs_dir3_data_check(
                        XFS_WANT_CORRUPTED_RETURN(
                                be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
                                               (char *)dup - (char *)hdr);
-                       dfp = xfs_dir2_data_freefind(hdr, dup);
+                       dfp = xfs_dir2_data_freefind(hdr, bf, dup);
                        if (dfp) {
                                i = (int)(dfp - bf);
                                XFS_WANT_CORRUPTED_RETURN(
@@ -340,19 +344,18 @@ xfs_dir3_data_readahead(
  */
 xfs_dir2_data_free_t *
 xfs_dir2_data_freefind(
-       xfs_dir2_data_hdr_t     *hdr,           /* data block */
-       xfs_dir2_data_unused_t  *dup)           /* data unused entry */
+       struct xfs_dir2_data_hdr *hdr,          /* data block header */
+       struct xfs_dir2_data_free *bf,          /* bestfree table pointer */
+       struct xfs_dir2_data_unused *dup)       /* unused space */
 {
        xfs_dir2_data_free_t    *dfp;           /* bestfree entry */
        xfs_dir2_data_aoff_t    off;            /* offset value needed */
-       struct xfs_dir2_data_free *bf;
 #ifdef DEBUG
        int                     matched;        /* matched the value */
        int                     seenzero;       /* saw a 0 bestfree entry */
 #endif
 
        off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
-       bf = xfs_dir3_data_bestfree_p(hdr);
 
 #ifdef DEBUG
        /*
@@ -412,11 +415,11 @@ xfs_dir2_data_freefind(
  */
 xfs_dir2_data_free_t *                         /* entry inserted */
 xfs_dir2_data_freeinsert(
-       xfs_dir2_data_hdr_t     *hdr,           /* data block pointer */
-       xfs_dir2_data_unused_t  *dup,           /* unused space */
+       struct xfs_dir2_data_hdr *hdr,          /* data block pointer */
+       struct xfs_dir2_data_free *dfp,         /* bestfree table pointer */
+       struct xfs_dir2_data_unused *dup,       /* unused space */
        int                     *loghead)       /* log the data header (out) */
 {
-       xfs_dir2_data_free_t    *dfp;           /* bestfree table pointer */
        xfs_dir2_data_free_t    new;            /* new bestfree entry */
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
@@ -424,7 +427,6 @@ xfs_dir2_data_freeinsert(
               hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
 
-       dfp = xfs_dir3_data_bestfree_p(hdr);
        new.length = dup->length;
        new.offset = cpu_to_be16((char *)dup - (char *)hdr);
 
@@ -457,11 +459,11 @@ xfs_dir2_data_freeinsert(
  */
 STATIC void
 xfs_dir2_data_freeremove(
-       xfs_dir2_data_hdr_t     *hdr,           /* data block header */
-       xfs_dir2_data_free_t    *dfp,           /* bestfree entry pointer */
+       struct xfs_dir2_data_hdr *hdr,          /* data block header */
+       struct xfs_dir2_data_free *bf,          /* bestfree table pointer */
+       struct xfs_dir2_data_free *dfp,         /* bestfree entry pointer */
        int                     *loghead)       /* out: log data header */
 {
-       struct xfs_dir2_data_free *bf;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
@@ -471,7 +473,6 @@ xfs_dir2_data_freeremove(
        /*
         * It's the first entry, slide the next 2 up.
         */
-       bf = xfs_dir3_data_bestfree_p(hdr);
        if (dfp == &bf[0]) {
                bf[0] = bf[1];
                bf[1] = bf[2];
@@ -518,13 +519,13 @@ xfs_dir2_data_freescan(
        /*
         * Start by clearing the table.
         */
-       bf = xfs_dir3_data_bestfree_p(hdr);
+       bf = dp->d_ops->data_bestfree_p(hdr);
        memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT);
        *loghead = 1;
        /*
         * Set up pointers.
         */
-       p = (char *)xfs_dir3_data_entry_p(hdr);
+       p = (char *)dp->d_ops->data_entry_p(hdr);
        if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
            hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
                btp = xfs_dir2_block_tail_p(dp->i_mount, hdr);
@@ -542,7 +543,7 @@ xfs_dir2_data_freescan(
                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
                        ASSERT((char *)dup - (char *)hdr ==
                               be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
-                       xfs_dir2_data_freeinsert(hdr, dup, loghead);
+                       xfs_dir2_data_freeinsert(hdr, bf, dup, loghead);
                        p += be16_to_cpu(dup->length);
                }
                /*
@@ -607,8 +608,8 @@ xfs_dir3_data_init(
        } else
                hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
 
-       bf = xfs_dir3_data_bestfree_p(hdr);
-       bf[0].offset = cpu_to_be16(xfs_dir3_data_entry_offset(hdr));
+       bf = dp->d_ops->data_bestfree_p(hdr);
+       bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset);
        for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
                bf[i].length = 0;
                bf[i].offset = 0;
@@ -617,17 +618,17 @@ xfs_dir3_data_init(
        /*
         * Set up an unused entry for the block's body.
         */
-       dup = xfs_dir3_data_unused_p(hdr);
+       dup = dp->d_ops->data_unused_p(hdr);
        dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 
-       t = mp->m_dirblksize - (uint)xfs_dir3_data_entry_offset(hdr);
+       t = mp->m_dirblksize - (uint)dp->d_ops->data_entry_offset;
        bf[0].length = cpu_to_be16(t);
        dup->length = cpu_to_be16(t);
        *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
        /*
         * Log it and return it.
         */
-       xfs_dir2_data_log_header(tp, bp);
+       xfs_dir2_data_log_header(tp, dp, bp);
        xfs_dir2_data_log_unused(tp, bp, dup);
        *bpp = bp;
        return 0;
@@ -661,16 +662,19 @@ xfs_dir2_data_log_entry(
 void
 xfs_dir2_data_log_header(
        struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
        struct xfs_buf          *bp)
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
+#ifdef DEBUG
+       struct xfs_dir2_data_hdr *hdr = bp->b_addr;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
+#endif
 
-       xfs_trans_log_buf(tp, bp, 0, xfs_dir3_data_entry_offset(hdr) - 1);
+       xfs_trans_log_buf(tp, bp, 0, dp->d_ops->data_entry_offset - 1);
 }
 
 /*
@@ -711,6 +715,7 @@ xfs_dir2_data_log_unused(
 void
 xfs_dir2_data_make_free(
        struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
        struct xfs_buf          *bp,
        xfs_dir2_data_aoff_t    offset,         /* starting byte offset */
        xfs_dir2_data_aoff_t    len,            /* length in bytes */
@@ -748,7 +753,7 @@ xfs_dir2_data_make_free(
         * If this isn't the start of the block, then back up to
         * the previous entry and see if it's free.
         */
-       if (offset > xfs_dir3_data_entry_offset(hdr)) {
+       if (offset > dp->d_ops->data_entry_offset) {
                __be16                  *tagp;  /* tag just before us */
 
                tagp = (__be16 *)((char *)hdr + offset) - 1;
@@ -774,15 +779,15 @@ xfs_dir2_data_make_free(
         * Previous and following entries are both free,
         * merge everything into a single free entry.
         */
-       bf = xfs_dir3_data_bestfree_p(hdr);
+       bf = dp->d_ops->data_bestfree_p(hdr);
        if (prevdup && postdup) {
                xfs_dir2_data_free_t    *dfp2;  /* another bestfree pointer */
 
                /*
                 * See if prevdup and/or postdup are in bestfree table.
                 */
-               dfp = xfs_dir2_data_freefind(hdr, prevdup);
-               dfp2 = xfs_dir2_data_freefind(hdr, postdup);
+               dfp = xfs_dir2_data_freefind(hdr, bf, prevdup);
+               dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup);
                /*
                 * We need a rescan unless there are exactly 2 free entries
                 * namely our two.  Then we know what's happening, otherwise
@@ -810,12 +815,13 @@ xfs_dir2_data_make_free(
                                ASSERT(dfp2 == dfp);
                                dfp2 = &bf[1];
                        }
-                       xfs_dir2_data_freeremove(hdr, dfp2, needlogp);
-                       xfs_dir2_data_freeremove(hdr, dfp, needlogp);
+                       xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp);
+                       xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
                        /*
                         * Now insert the new entry.
                         */
-                       dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
+                       dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup,
+                                                      needlogp);
                        ASSERT(dfp == &bf[0]);
                        ASSERT(dfp->length == prevdup->length);
                        ASSERT(!dfp[1].length);
@@ -826,7 +832,7 @@ xfs_dir2_data_make_free(
         * The entry before us is free, merge with it.
         */
        else if (prevdup) {
-               dfp = xfs_dir2_data_freefind(hdr, prevdup);
+               dfp = xfs_dir2_data_freefind(hdr, bf, prevdup);
                be16_add_cpu(&prevdup->length, len);
                *xfs_dir2_data_unused_tag_p(prevdup) =
                        cpu_to_be16((char *)prevdup - (char *)hdr);
@@ -837,8 +843,8 @@ xfs_dir2_data_make_free(
                 * the old one and add the new one.
                 */
                if (dfp) {
-                       xfs_dir2_data_freeremove(hdr, dfp, needlogp);
-                       xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
+                       xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
+                       xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp);
                }
                /*
                 * Otherwise we need a scan if the new entry is big enough.
@@ -852,7 +858,7 @@ xfs_dir2_data_make_free(
         * The following entry is free, merge with it.
         */
        else if (postdup) {
-               dfp = xfs_dir2_data_freefind(hdr, postdup);
+               dfp = xfs_dir2_data_freefind(hdr, bf, postdup);
                newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
                newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
                newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
@@ -865,8 +871,8 @@ xfs_dir2_data_make_free(
                 * the old one and add the new one.
                 */
                if (dfp) {
-                       xfs_dir2_data_freeremove(hdr, dfp, needlogp);
-                       xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
+                       xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
+                       xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
                }
                /*
                 * Otherwise we need a scan if the new entry is big enough.
@@ -886,7 +892,7 @@ xfs_dir2_data_make_free(
                *xfs_dir2_data_unused_tag_p(newdup) =
                        cpu_to_be16((char *)newdup - (char *)hdr);
                xfs_dir2_data_log_unused(tp, bp, newdup);
-               xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
+               xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
        }
        *needscanp = needscan;
 }
@@ -897,6 +903,7 @@ xfs_dir2_data_make_free(
 void
 xfs_dir2_data_use_free(
        struct xfs_trans        *tp,
+       struct xfs_inode        *dp,
        struct xfs_buf          *bp,
        xfs_dir2_data_unused_t  *dup,           /* unused entry */
        xfs_dir2_data_aoff_t    offset,         /* starting offset to use */
@@ -926,9 +933,9 @@ xfs_dir2_data_use_free(
        /*
         * Look up the entry in the bestfree table.
         */
-       dfp = xfs_dir2_data_freefind(hdr, dup);
        oldlen = be16_to_cpu(dup->length);
-       bf = xfs_dir3_data_bestfree_p(hdr);
+       bf = dp->d_ops->data_bestfree_p(hdr);
+       dfp = xfs_dir2_data_freefind(hdr, bf, dup);
        ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
        /*
         * Check for alignment with front and back of the entry.
@@ -945,7 +952,8 @@ xfs_dir2_data_use_free(
                if (dfp) {
                        needscan = (bf[2].offset != 0);
                        if (!needscan)
-                               xfs_dir2_data_freeremove(hdr, dfp, needlogp);
+                               xfs_dir2_data_freeremove(hdr, bf, dfp,
+                                                        needlogp);
                }
        }
        /*
@@ -963,8 +971,9 @@ xfs_dir2_data_use_free(
                 * If it was in the table, remove it and add the new one.
                 */
                if (dfp) {
-                       xfs_dir2_data_freeremove(hdr, dfp, needlogp);
-                       dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
+                       xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
+                       dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
+                                                      needlogp);
                        ASSERT(dfp != NULL);
                        ASSERT(dfp->length == newdup->length);
                        ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
@@ -990,8 +999,9 @@ xfs_dir2_data_use_free(
                 * If it was in the table, remove it and add the new one.
                 */
                if (dfp) {
-                       xfs_dir2_data_freeremove(hdr, dfp, needlogp);
-                       dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
+                       xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
+                       dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
+                                                      needlogp);
                        ASSERT(dfp != NULL);
                        ASSERT(dfp->length == newdup->length);
                        ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
@@ -1030,9 +1040,11 @@ xfs_dir2_data_use_free(
                if (dfp) {
                        needscan = (bf[2].length != 0);
                        if (!needscan) {
-                               xfs_dir2_data_freeremove(hdr, dfp, needlogp);
-                               xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
-                               xfs_dir2_data_freeinsert(hdr, newdup2,
+                               xfs_dir2_data_freeremove(hdr, bf, dfp,
+                                                        needlogp);
+                               xfs_dir2_data_freeinsert(hdr, bf, newdup,
+                                                        needlogp);
+                               xfs_dir2_data_freeinsert(hdr, bf, newdup2,
                                                         needlogp);
                        }
                }