linux/fs/xfs/xfs_dir2_data.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include "xfs.h"
  19#include "xfs_fs.h"
  20#include "xfs_types.h"
  21#include "xfs_log.h"
  22#include "xfs_trans.h"
  23#include "xfs_sb.h"
  24#include "xfs_ag.h"
  25#include "xfs_mount.h"
  26#include "xfs_da_btree.h"
  27#include "xfs_bmap_btree.h"
  28#include "xfs_dinode.h"
  29#include "xfs_inode.h"
  30#include "xfs_dir2_format.h"
  31#include "xfs_dir2_priv.h"
  32#include "xfs_error.h"
  33
  34STATIC xfs_dir2_data_free_t *
  35xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup);
  36
  37/*
  38 * Check the consistency of the data block.
  39 * The input can also be a block-format directory.
  40 * Return 0 is the buffer is good, otherwise an error.
  41 */
  42int
  43__xfs_dir2_data_check(
  44        struct xfs_inode        *dp,            /* incore inode pointer */
  45        struct xfs_buf          *bp)            /* data block's buffer */
  46{
  47        xfs_dir2_dataptr_t      addr;           /* addr for leaf lookup */
  48        xfs_dir2_data_free_t    *bf;            /* bestfree table */
  49        xfs_dir2_block_tail_t   *btp=NULL;      /* block tail */
  50        int                     count;          /* count of entries found */
  51        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
  52        xfs_dir2_data_entry_t   *dep;           /* data entry */
  53        xfs_dir2_data_free_t    *dfp;           /* bestfree entry */
  54        xfs_dir2_data_unused_t  *dup;           /* unused entry */
  55        char                    *endp;          /* end of useful data */
  56        int                     freeseen;       /* mask of bestfrees seen */
  57        xfs_dahash_t            hash;           /* hash of current name */
  58        int                     i;              /* leaf index */
  59        int                     lastfree;       /* last entry was unused */
  60        xfs_dir2_leaf_entry_t   *lep=NULL;      /* block leaf entries */
  61        xfs_mount_t             *mp;            /* filesystem mount point */
  62        char                    *p;             /* current data position */
  63        int                     stale;          /* count of stale leaves */
  64        struct xfs_name         name;
  65
  66        mp = bp->b_target->bt_mount;
  67        hdr = bp->b_addr;
  68        bf = hdr->bestfree;
  69        p = (char *)(hdr + 1);
  70
  71        switch (hdr->magic) {
  72        case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
  73                btp = xfs_dir2_block_tail_p(mp, hdr);
  74                lep = xfs_dir2_block_leaf_p(btp);
  75                endp = (char *)lep;
  76                break;
  77        case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
  78                endp = (char *)hdr + mp->m_dirblksize;
  79                break;
  80        default:
  81                XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp);
  82                return EFSCORRUPTED;
  83        }
  84
  85        count = lastfree = freeseen = 0;
  86        /*
  87         * Account for zero bestfree entries.
  88         */
  89        if (!bf[0].length) {
  90                XFS_WANT_CORRUPTED_RETURN(!bf[0].offset);
  91                freeseen |= 1 << 0;
  92        }
  93        if (!bf[1].length) {
  94                XFS_WANT_CORRUPTED_RETURN(!bf[1].offset);
  95                freeseen |= 1 << 1;
  96        }
  97        if (!bf[2].length) {
  98                XFS_WANT_CORRUPTED_RETURN(!bf[2].offset);
  99                freeseen |= 1 << 2;
 100        }
 101
 102        XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[0].length) >=
 103                                                be16_to_cpu(bf[1].length));
 104        XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[1].length) >=
 105                                                be16_to_cpu(bf[2].length));
 106        /*
 107         * Loop over the data/unused entries.
 108         */
 109        while (p < endp) {
 110                dup = (xfs_dir2_data_unused_t *)p;
 111                /*
 112                 * If it's unused, look for the space in the bestfree table.
 113                 * If we find it, account for that, else make sure it
 114                 * doesn't need to be there.
 115                 */
 116                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 117                        XFS_WANT_CORRUPTED_RETURN(lastfree == 0);
 118                        XFS_WANT_CORRUPTED_RETURN(
 119                                be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
 120                                               (char *)dup - (char *)hdr);
 121                        dfp = xfs_dir2_data_freefind(hdr, dup);
 122                        if (dfp) {
 123                                i = (int)(dfp - bf);
 124                                XFS_WANT_CORRUPTED_RETURN(
 125                                        (freeseen & (1 << i)) == 0);
 126                                freeseen |= 1 << i;
 127                        } else {
 128                                XFS_WANT_CORRUPTED_RETURN(
 129                                        be16_to_cpu(dup->length) <=
 130                                                be16_to_cpu(bf[2].length));
 131                        }
 132                        p += be16_to_cpu(dup->length);
 133                        lastfree = 1;
 134                        continue;
 135                }
 136                /*
 137                 * It's a real entry.  Validate the fields.
 138                 * If this is a block directory then make sure it's
 139                 * in the leaf section of the block.
 140                 * The linear search is crude but this is DEBUG code.
 141                 */
 142                dep = (xfs_dir2_data_entry_t *)p;
 143                XFS_WANT_CORRUPTED_RETURN(dep->namelen != 0);
 144                XFS_WANT_CORRUPTED_RETURN(
 145                        !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
 146                XFS_WANT_CORRUPTED_RETURN(
 147                        be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
 148                                               (char *)dep - (char *)hdr);
 149                count++;
 150                lastfree = 0;
 151                if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
 152                        addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
 153                                (xfs_dir2_data_aoff_t)
 154                                ((char *)dep - (char *)hdr));
 155                        name.name = dep->name;
 156                        name.len = dep->namelen;
 157                        hash = mp->m_dirnameops->hashname(&name);
 158                        for (i = 0; i < be32_to_cpu(btp->count); i++) {
 159                                if (be32_to_cpu(lep[i].address) == addr &&
 160                                    be32_to_cpu(lep[i].hashval) == hash)
 161                                        break;
 162                        }
 163                        XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
 164                }
 165                p += xfs_dir2_data_entsize(dep->namelen);
 166        }
 167        /*
 168         * Need to have seen all the entries and all the bestfree slots.
 169         */
 170        XFS_WANT_CORRUPTED_RETURN(freeseen == 7);
 171        if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
 172                for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
 173                        if (lep[i].address ==
 174                            cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
 175                                stale++;
 176                        if (i > 0)
 177                                XFS_WANT_CORRUPTED_RETURN(
 178                                        be32_to_cpu(lep[i].hashval) >=
 179                                                be32_to_cpu(lep[i - 1].hashval));
 180                }
 181                XFS_WANT_CORRUPTED_RETURN(count ==
 182                        be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
 183                XFS_WANT_CORRUPTED_RETURN(stale == be32_to_cpu(btp->stale));
 184        }
 185        return 0;
 186}
 187
 188static void
 189xfs_dir2_data_verify(
 190        struct xfs_buf          *bp)
 191{
 192        struct xfs_mount        *mp = bp->b_target->bt_mount;
 193        struct xfs_dir2_data_hdr *hdr = bp->b_addr;
 194        int                     block_ok = 0;
 195
 196        block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC);
 197        block_ok = block_ok && __xfs_dir2_data_check(NULL, bp) == 0;
 198
 199        if (!block_ok) {
 200                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
 201                xfs_buf_ioerror(bp, EFSCORRUPTED);
 202        }
 203}
 204
 205/*
 206 * Readahead of the first block of the directory when it is opened is completely
 207 * oblivious to the format of the directory. Hence we can either get a block
 208 * format buffer or a data format buffer on readahead.
 209 */
 210static void
 211xfs_dir2_data_reada_verify(
 212        struct xfs_buf          *bp)
 213{
 214        struct xfs_mount        *mp = bp->b_target->bt_mount;
 215        struct xfs_dir2_data_hdr *hdr = bp->b_addr;
 216
 217        switch (hdr->magic) {
 218        case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
 219                bp->b_ops = &xfs_dir2_block_buf_ops;
 220                bp->b_ops->verify_read(bp);
 221                return;
 222        case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
 223                xfs_dir2_data_verify(bp);
 224                return;
 225        default:
 226                XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
 227                xfs_buf_ioerror(bp, EFSCORRUPTED);
 228                break;
 229        }
 230}
 231
 232static void
 233xfs_dir2_data_read_verify(
 234        struct xfs_buf  *bp)
 235{
 236        xfs_dir2_data_verify(bp);
 237}
 238
 239static void
 240xfs_dir2_data_write_verify(
 241        struct xfs_buf  *bp)
 242{
 243        xfs_dir2_data_verify(bp);
 244}
 245
 246const struct xfs_buf_ops xfs_dir2_data_buf_ops = {
 247        .verify_read = xfs_dir2_data_read_verify,
 248        .verify_write = xfs_dir2_data_write_verify,
 249};
 250
 251static const struct xfs_buf_ops xfs_dir2_data_reada_buf_ops = {
 252        .verify_read = xfs_dir2_data_reada_verify,
 253        .verify_write = xfs_dir2_data_write_verify,
 254};
 255
 256
 257int
 258xfs_dir2_data_read(
 259        struct xfs_trans        *tp,
 260        struct xfs_inode        *dp,
 261        xfs_dablk_t             bno,
 262        xfs_daddr_t             mapped_bno,
 263        struct xfs_buf          **bpp)
 264{
 265        return xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
 266                                XFS_DATA_FORK, &xfs_dir2_data_buf_ops);
 267}
 268
 269int
 270xfs_dir2_data_readahead(
 271        struct xfs_trans        *tp,
 272        struct xfs_inode        *dp,
 273        xfs_dablk_t             bno,
 274        xfs_daddr_t             mapped_bno)
 275{
 276        return xfs_da_reada_buf(tp, dp, bno, mapped_bno,
 277                                XFS_DATA_FORK, &xfs_dir2_data_reada_buf_ops);
 278}
 279
 280/*
 281 * Given a data block and an unused entry from that block,
 282 * return the bestfree entry if any that corresponds to it.
 283 */
 284STATIC xfs_dir2_data_free_t *
 285xfs_dir2_data_freefind(
 286        xfs_dir2_data_hdr_t     *hdr,           /* data block */
 287        xfs_dir2_data_unused_t  *dup)           /* data unused entry */
 288{
 289        xfs_dir2_data_free_t    *dfp;           /* bestfree entry */
 290        xfs_dir2_data_aoff_t    off;            /* offset value needed */
 291#if defined(DEBUG) && defined(__KERNEL__)
 292        int                     matched;        /* matched the value */
 293        int                     seenzero;       /* saw a 0 bestfree entry */
 294#endif
 295
 296        off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
 297#if defined(DEBUG) && defined(__KERNEL__)
 298        /*
 299         * Validate some consistency in the bestfree table.
 300         * Check order, non-overlapping entries, and if we find the
 301         * one we're looking for it has to be exact.
 302         */
 303        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 304               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 305        for (dfp = &hdr->bestfree[0], seenzero = matched = 0;
 306             dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT];
 307             dfp++) {
 308                if (!dfp->offset) {
 309                        ASSERT(!dfp->length);
 310                        seenzero = 1;
 311                        continue;
 312                }
 313                ASSERT(seenzero == 0);
 314                if (be16_to_cpu(dfp->offset) == off) {
 315                        matched = 1;
 316                        ASSERT(dfp->length == dup->length);
 317                } else if (off < be16_to_cpu(dfp->offset))
 318                        ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset));
 319                else
 320                        ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
 321                ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
 322                if (dfp > &hdr->bestfree[0])
 323                        ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
 324        }
 325#endif
 326        /*
 327         * If this is smaller than the smallest bestfree entry,
 328         * it can't be there since they're sorted.
 329         */
 330        if (be16_to_cpu(dup->length) <
 331            be16_to_cpu(hdr->bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length))
 332                return NULL;
 333        /*
 334         * Look at the three bestfree entries for our guy.
 335         */
 336        for (dfp = &hdr->bestfree[0];
 337             dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT];
 338             dfp++) {
 339                if (!dfp->offset)
 340                        return NULL;
 341                if (be16_to_cpu(dfp->offset) == off)
 342                        return dfp;
 343        }
 344        /*
 345         * Didn't find it.  This only happens if there are duplicate lengths.
 346         */
 347        return NULL;
 348}
 349
 350/*
 351 * Insert an unused-space entry into the bestfree table.
 352 */
 353xfs_dir2_data_free_t *                          /* entry inserted */
 354xfs_dir2_data_freeinsert(
 355        xfs_dir2_data_hdr_t     *hdr,           /* data block pointer */
 356        xfs_dir2_data_unused_t  *dup,           /* unused space */
 357        int                     *loghead)       /* log the data header (out) */
 358{
 359        xfs_dir2_data_free_t    *dfp;           /* bestfree table pointer */
 360        xfs_dir2_data_free_t    new;            /* new bestfree entry */
 361
 362#ifdef __KERNEL__
 363        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 364               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 365#endif
 366        dfp = hdr->bestfree;
 367        new.length = dup->length;
 368        new.offset = cpu_to_be16((char *)dup - (char *)hdr);
 369
 370        /*
 371         * Insert at position 0, 1, or 2; or not at all.
 372         */
 373        if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
 374                dfp[2] = dfp[1];
 375                dfp[1] = dfp[0];
 376                dfp[0] = new;
 377                *loghead = 1;
 378                return &dfp[0];
 379        }
 380        if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
 381                dfp[2] = dfp[1];
 382                dfp[1] = new;
 383                *loghead = 1;
 384                return &dfp[1];
 385        }
 386        if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
 387                dfp[2] = new;
 388                *loghead = 1;
 389                return &dfp[2];
 390        }
 391        return NULL;
 392}
 393
 394/*
 395 * Remove a bestfree entry from the table.
 396 */
 397STATIC void
 398xfs_dir2_data_freeremove(
 399        xfs_dir2_data_hdr_t     *hdr,           /* data block header */
 400        xfs_dir2_data_free_t    *dfp,           /* bestfree entry pointer */
 401        int                     *loghead)       /* out: log data header */
 402{
 403#ifdef __KERNEL__
 404        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 405               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 406#endif
 407        /*
 408         * It's the first entry, slide the next 2 up.
 409         */
 410        if (dfp == &hdr->bestfree[0]) {
 411                hdr->bestfree[0] = hdr->bestfree[1];
 412                hdr->bestfree[1] = hdr->bestfree[2];
 413        }
 414        /*
 415         * It's the second entry, slide the 3rd entry up.
 416         */
 417        else if (dfp == &hdr->bestfree[1])
 418                hdr->bestfree[1] = hdr->bestfree[2];
 419        /*
 420         * Must be the last entry.
 421         */
 422        else
 423                ASSERT(dfp == &hdr->bestfree[2]);
 424        /*
 425         * Clear the 3rd entry, must be zero now.
 426         */
 427        hdr->bestfree[2].length = 0;
 428        hdr->bestfree[2].offset = 0;
 429        *loghead = 1;
 430}
 431
 432/*
 433 * Given a data block, reconstruct its bestfree map.
 434 */
 435void
 436xfs_dir2_data_freescan(
 437        xfs_mount_t             *mp,            /* filesystem mount point */
 438        xfs_dir2_data_hdr_t     *hdr,           /* data block header */
 439        int                     *loghead)       /* out: log data header */
 440{
 441        xfs_dir2_block_tail_t   *btp;           /* block tail */
 442        xfs_dir2_data_entry_t   *dep;           /* active data entry */
 443        xfs_dir2_data_unused_t  *dup;           /* unused data entry */
 444        char                    *endp;          /* end of block's data */
 445        char                    *p;             /* current entry pointer */
 446
 447#ifdef __KERNEL__
 448        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 449               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 450#endif
 451        /*
 452         * Start by clearing the table.
 453         */
 454        memset(hdr->bestfree, 0, sizeof(hdr->bestfree));
 455        *loghead = 1;
 456        /*
 457         * Set up pointers.
 458         */
 459        p = (char *)(hdr + 1);
 460        if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
 461                btp = xfs_dir2_block_tail_p(mp, hdr);
 462                endp = (char *)xfs_dir2_block_leaf_p(btp);
 463        } else
 464                endp = (char *)hdr + mp->m_dirblksize;
 465        /*
 466         * Loop over the block's entries.
 467         */
 468        while (p < endp) {
 469                dup = (xfs_dir2_data_unused_t *)p;
 470                /*
 471                 * If it's a free entry, insert it.
 472                 */
 473                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 474                        ASSERT((char *)dup - (char *)hdr ==
 475                               be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
 476                        xfs_dir2_data_freeinsert(hdr, dup, loghead);
 477                        p += be16_to_cpu(dup->length);
 478                }
 479                /*
 480                 * For active entries, check their tags and skip them.
 481                 */
 482                else {
 483                        dep = (xfs_dir2_data_entry_t *)p;
 484                        ASSERT((char *)dep - (char *)hdr ==
 485                               be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
 486                        p += xfs_dir2_data_entsize(dep->namelen);
 487                }
 488        }
 489}
 490
 491/*
 492 * Initialize a data block at the given block number in the directory.
 493 * Give back the buffer for the created block.
 494 */
 495int                                             /* error */
 496xfs_dir2_data_init(
 497        xfs_da_args_t           *args,          /* directory operation args */
 498        xfs_dir2_db_t           blkno,          /* logical dir block number */
 499        struct xfs_buf          **bpp)          /* output block buffer */
 500{
 501        struct xfs_buf          *bp;            /* block buffer */
 502        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
 503        xfs_inode_t             *dp;            /* incore directory inode */
 504        xfs_dir2_data_unused_t  *dup;           /* unused entry pointer */
 505        int                     error;          /* error return value */
 506        int                     i;              /* bestfree index */
 507        xfs_mount_t             *mp;            /* filesystem mount point */
 508        xfs_trans_t             *tp;            /* transaction pointer */
 509        int                     t;              /* temp */
 510
 511        dp = args->dp;
 512        mp = dp->i_mount;
 513        tp = args->trans;
 514        /*
 515         * Get the buffer set up for the block.
 516         */
 517        error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
 518                XFS_DATA_FORK);
 519        if (error)
 520                return error;
 521        bp->b_ops = &xfs_dir2_data_buf_ops;
 522
 523        /*
 524         * Initialize the header.
 525         */
 526        hdr = bp->b_addr;
 527        hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
 528        hdr->bestfree[0].offset = cpu_to_be16(sizeof(*hdr));
 529        for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
 530                hdr->bestfree[i].length = 0;
 531                hdr->bestfree[i].offset = 0;
 532        }
 533
 534        /*
 535         * Set up an unused entry for the block's body.
 536         */
 537        dup = (xfs_dir2_data_unused_t *)(hdr + 1);
 538        dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 539
 540        t = mp->m_dirblksize - (uint)sizeof(*hdr);
 541        hdr->bestfree[0].length = cpu_to_be16(t);
 542        dup->length = cpu_to_be16(t);
 543        *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
 544        /*
 545         * Log it and return it.
 546         */
 547        xfs_dir2_data_log_header(tp, bp);
 548        xfs_dir2_data_log_unused(tp, bp, dup);
 549        *bpp = bp;
 550        return 0;
 551}
 552
 553/*
 554 * Log an active data entry from the block.
 555 */
 556void
 557xfs_dir2_data_log_entry(
 558        struct xfs_trans        *tp,
 559        struct xfs_buf          *bp,
 560        xfs_dir2_data_entry_t   *dep)           /* data entry pointer */
 561{
 562        xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
 563
 564        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 565               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 566
 567        xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
 568                (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
 569                       (char *)hdr - 1));
 570}
 571
 572/*
 573 * Log a data block header.
 574 */
 575void
 576xfs_dir2_data_log_header(
 577        struct xfs_trans        *tp,
 578        struct xfs_buf          *bp)
 579{
 580        xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
 581
 582        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 583               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 584
 585        xfs_trans_log_buf(tp, bp, 0, sizeof(*hdr) - 1);
 586}
 587
 588/*
 589 * Log a data unused entry.
 590 */
 591void
 592xfs_dir2_data_log_unused(
 593        struct xfs_trans        *tp,
 594        struct xfs_buf          *bp,
 595        xfs_dir2_data_unused_t  *dup)           /* data unused pointer */
 596{
 597        xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
 598
 599        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 600               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 601
 602        /*
 603         * Log the first part of the unused entry.
 604         */
 605        xfs_trans_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
 606                (uint)((char *)&dup->length + sizeof(dup->length) -
 607                       1 - (char *)hdr));
 608        /*
 609         * Log the end (tag) of the unused entry.
 610         */
 611        xfs_trans_log_buf(tp, bp,
 612                (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
 613                (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
 614                       sizeof(xfs_dir2_data_off_t) - 1));
 615}
 616
 617/*
 618 * Make a byte range in the data block unused.
 619 * Its current contents are unimportant.
 620 */
 621void
 622xfs_dir2_data_make_free(
 623        struct xfs_trans        *tp,
 624        struct xfs_buf          *bp,
 625        xfs_dir2_data_aoff_t    offset,         /* starting byte offset */
 626        xfs_dir2_data_aoff_t    len,            /* length in bytes */
 627        int                     *needlogp,      /* out: log header */
 628        int                     *needscanp)     /* out: regen bestfree */
 629{
 630        xfs_dir2_data_hdr_t     *hdr;           /* data block pointer */
 631        xfs_dir2_data_free_t    *dfp;           /* bestfree pointer */
 632        char                    *endptr;        /* end of data area */
 633        xfs_mount_t             *mp;            /* filesystem mount point */
 634        int                     needscan;       /* need to regen bestfree */
 635        xfs_dir2_data_unused_t  *newdup;        /* new unused entry */
 636        xfs_dir2_data_unused_t  *postdup;       /* unused entry after us */
 637        xfs_dir2_data_unused_t  *prevdup;       /* unused entry before us */
 638
 639        mp = tp->t_mountp;
 640        hdr = bp->b_addr;
 641
 642        /*
 643         * Figure out where the end of the data area is.
 644         */
 645        if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC))
 646                endptr = (char *)hdr + mp->m_dirblksize;
 647        else {
 648                xfs_dir2_block_tail_t   *btp;   /* block tail */
 649
 650                ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 651                btp = xfs_dir2_block_tail_p(mp, hdr);
 652                endptr = (char *)xfs_dir2_block_leaf_p(btp);
 653        }
 654        /*
 655         * If this isn't the start of the block, then back up to
 656         * the previous entry and see if it's free.
 657         */
 658        if (offset > sizeof(*hdr)) {
 659                __be16                  *tagp;  /* tag just before us */
 660
 661                tagp = (__be16 *)((char *)hdr + offset) - 1;
 662                prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
 663                if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
 664                        prevdup = NULL;
 665        } else
 666                prevdup = NULL;
 667        /*
 668         * If this isn't the end of the block, see if the entry after
 669         * us is free.
 670         */
 671        if ((char *)hdr + offset + len < endptr) {
 672                postdup =
 673                        (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
 674                if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
 675                        postdup = NULL;
 676        } else
 677                postdup = NULL;
 678        ASSERT(*needscanp == 0);
 679        needscan = 0;
 680        /*
 681         * Previous and following entries are both free,
 682         * merge everything into a single free entry.
 683         */
 684        if (prevdup && postdup) {
 685                xfs_dir2_data_free_t    *dfp2;  /* another bestfree pointer */
 686
 687                /*
 688                 * See if prevdup and/or postdup are in bestfree table.
 689                 */
 690                dfp = xfs_dir2_data_freefind(hdr, prevdup);
 691                dfp2 = xfs_dir2_data_freefind(hdr, postdup);
 692                /*
 693                 * We need a rescan unless there are exactly 2 free entries
 694                 * namely our two.  Then we know what's happening, otherwise
 695                 * since the third bestfree is there, there might be more
 696                 * entries.
 697                 */
 698                needscan = (hdr->bestfree[2].length != 0);
 699                /*
 700                 * Fix up the new big freespace.
 701                 */
 702                be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length));
 703                *xfs_dir2_data_unused_tag_p(prevdup) =
 704                        cpu_to_be16((char *)prevdup - (char *)hdr);
 705                xfs_dir2_data_log_unused(tp, bp, prevdup);
 706                if (!needscan) {
 707                        /*
 708                         * Has to be the case that entries 0 and 1 are
 709                         * dfp and dfp2 (don't know which is which), and
 710                         * entry 2 is empty.
 711                         * Remove entry 1 first then entry 0.
 712                         */
 713                        ASSERT(dfp && dfp2);
 714                        if (dfp == &hdr->bestfree[1]) {
 715                                dfp = &hdr->bestfree[0];
 716                                ASSERT(dfp2 == dfp);
 717                                dfp2 = &hdr->bestfree[1];
 718                        }
 719                        xfs_dir2_data_freeremove(hdr, dfp2, needlogp);
 720                        xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 721                        /*
 722                         * Now insert the new entry.
 723                         */
 724                        dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
 725                        ASSERT(dfp == &hdr->bestfree[0]);
 726                        ASSERT(dfp->length == prevdup->length);
 727                        ASSERT(!dfp[1].length);
 728                        ASSERT(!dfp[2].length);
 729                }
 730        }
 731        /*
 732         * The entry before us is free, merge with it.
 733         */
 734        else if (prevdup) {
 735                dfp = xfs_dir2_data_freefind(hdr, prevdup);
 736                be16_add_cpu(&prevdup->length, len);
 737                *xfs_dir2_data_unused_tag_p(prevdup) =
 738                        cpu_to_be16((char *)prevdup - (char *)hdr);
 739                xfs_dir2_data_log_unused(tp, bp, prevdup);
 740                /*
 741                 * If the previous entry was in the table, the new entry
 742                 * is longer, so it will be in the table too.  Remove
 743                 * the old one and add the new one.
 744                 */
 745                if (dfp) {
 746                        xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 747                        xfs_dir2_data_freeinsert(hdr, prevdup, needlogp);
 748                }
 749                /*
 750                 * Otherwise we need a scan if the new entry is big enough.
 751                 */
 752                else {
 753                        needscan = be16_to_cpu(prevdup->length) >
 754                                   be16_to_cpu(hdr->bestfree[2].length);
 755                }
 756        }
 757        /*
 758         * The following entry is free, merge with it.
 759         */
 760        else if (postdup) {
 761                dfp = xfs_dir2_data_freefind(hdr, postdup);
 762                newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
 763                newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 764                newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
 765                *xfs_dir2_data_unused_tag_p(newdup) =
 766                        cpu_to_be16((char *)newdup - (char *)hdr);
 767                xfs_dir2_data_log_unused(tp, bp, newdup);
 768                /*
 769                 * If the following entry was in the table, the new entry
 770                 * is longer, so it will be in the table too.  Remove
 771                 * the old one and add the new one.
 772                 */
 773                if (dfp) {
 774                        xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 775                        xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
 776                }
 777                /*
 778                 * Otherwise we need a scan if the new entry is big enough.
 779                 */
 780                else {
 781                        needscan = be16_to_cpu(newdup->length) >
 782                                   be16_to_cpu(hdr->bestfree[2].length);
 783                }
 784        }
 785        /*
 786         * Neither neighbor is free.  Make a new entry.
 787         */
 788        else {
 789                newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
 790                newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 791                newdup->length = cpu_to_be16(len);
 792                *xfs_dir2_data_unused_tag_p(newdup) =
 793                        cpu_to_be16((char *)newdup - (char *)hdr);
 794                xfs_dir2_data_log_unused(tp, bp, newdup);
 795                xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
 796        }
 797        *needscanp = needscan;
 798}
 799
 800/*
 801 * Take a byte range out of an existing unused space and make it un-free.
 802 */
 803void
 804xfs_dir2_data_use_free(
 805        struct xfs_trans        *tp,
 806        struct xfs_buf          *bp,
 807        xfs_dir2_data_unused_t  *dup,           /* unused entry */
 808        xfs_dir2_data_aoff_t    offset,         /* starting offset to use */
 809        xfs_dir2_data_aoff_t    len,            /* length to use */
 810        int                     *needlogp,      /* out: need to log header */
 811        int                     *needscanp)     /* out: need regen bestfree */
 812{
 813        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
 814        xfs_dir2_data_free_t    *dfp;           /* bestfree pointer */
 815        int                     matchback;      /* matches end of freespace */
 816        int                     matchfront;     /* matches start of freespace */
 817        int                     needscan;       /* need to regen bestfree */
 818        xfs_dir2_data_unused_t  *newdup;        /* new unused entry */
 819        xfs_dir2_data_unused_t  *newdup2;       /* another new unused entry */
 820        int                     oldlen;         /* old unused entry's length */
 821
 822        hdr = bp->b_addr;
 823        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
 824               hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC));
 825        ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
 826        ASSERT(offset >= (char *)dup - (char *)hdr);
 827        ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
 828        ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
 829        /*
 830         * Look up the entry in the bestfree table.
 831         */
 832        dfp = xfs_dir2_data_freefind(hdr, dup);
 833        oldlen = be16_to_cpu(dup->length);
 834        ASSERT(dfp || oldlen <= be16_to_cpu(hdr->bestfree[2].length));
 835        /*
 836         * Check for alignment with front and back of the entry.
 837         */
 838        matchfront = (char *)dup - (char *)hdr == offset;
 839        matchback = (char *)dup + oldlen - (char *)hdr == offset + len;
 840        ASSERT(*needscanp == 0);
 841        needscan = 0;
 842        /*
 843         * If we matched it exactly we just need to get rid of it from
 844         * the bestfree table.
 845         */
 846        if (matchfront && matchback) {
 847                if (dfp) {
 848                        needscan = (hdr->bestfree[2].offset != 0);
 849                        if (!needscan)
 850                                xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 851                }
 852        }
 853        /*
 854         * We match the first part of the entry.
 855         * Make a new entry with the remaining freespace.
 856         */
 857        else if (matchfront) {
 858                newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
 859                newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 860                newdup->length = cpu_to_be16(oldlen - len);
 861                *xfs_dir2_data_unused_tag_p(newdup) =
 862                        cpu_to_be16((char *)newdup - (char *)hdr);
 863                xfs_dir2_data_log_unused(tp, bp, newdup);
 864                /*
 865                 * If it was in the table, remove it and add the new one.
 866                 */
 867                if (dfp) {
 868                        xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 869                        dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
 870                        ASSERT(dfp != NULL);
 871                        ASSERT(dfp->length == newdup->length);
 872                        ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
 873                        /*
 874                         * If we got inserted at the last slot,
 875                         * that means we don't know if there was a better
 876                         * choice for the last slot, or not.  Rescan.
 877                         */
 878                        needscan = dfp == &hdr->bestfree[2];
 879                }
 880        }
 881        /*
 882         * We match the last part of the entry.
 883         * Trim the allocated space off the tail of the entry.
 884         */
 885        else if (matchback) {
 886                newdup = dup;
 887                newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
 888                *xfs_dir2_data_unused_tag_p(newdup) =
 889                        cpu_to_be16((char *)newdup - (char *)hdr);
 890                xfs_dir2_data_log_unused(tp, bp, newdup);
 891                /*
 892                 * If it was in the table, remove it and add the new one.
 893                 */
 894                if (dfp) {
 895                        xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 896                        dfp = xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
 897                        ASSERT(dfp != NULL);
 898                        ASSERT(dfp->length == newdup->length);
 899                        ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
 900                        /*
 901                         * If we got inserted at the last slot,
 902                         * that means we don't know if there was a better
 903                         * choice for the last slot, or not.  Rescan.
 904                         */
 905                        needscan = dfp == &hdr->bestfree[2];
 906                }
 907        }
 908        /*
 909         * Poking out the middle of an entry.
 910         * Make two new entries.
 911         */
 912        else {
 913                newdup = dup;
 914                newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
 915                *xfs_dir2_data_unused_tag_p(newdup) =
 916                        cpu_to_be16((char *)newdup - (char *)hdr);
 917                xfs_dir2_data_log_unused(tp, bp, newdup);
 918                newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
 919                newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
 920                newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
 921                *xfs_dir2_data_unused_tag_p(newdup2) =
 922                        cpu_to_be16((char *)newdup2 - (char *)hdr);
 923                xfs_dir2_data_log_unused(tp, bp, newdup2);
 924                /*
 925                 * If the old entry was in the table, we need to scan
 926                 * if the 3rd entry was valid, since these entries
 927                 * are smaller than the old one.
 928                 * If we don't need to scan that means there were 1 or 2
 929                 * entries in the table, and removing the old and adding
 930                 * the 2 new will work.
 931                 */
 932                if (dfp) {
 933                        needscan = (hdr->bestfree[2].length != 0);
 934                        if (!needscan) {
 935                                xfs_dir2_data_freeremove(hdr, dfp, needlogp);
 936                                xfs_dir2_data_freeinsert(hdr, newdup, needlogp);
 937                                xfs_dir2_data_freeinsert(hdr, newdup2,
 938                                                         needlogp);
 939                        }
 940                }
 941        }
 942        *needscanp = needscan;
 943}
 944
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.