linux/fs/xfs/xfs_dir2_readdir.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
   3 * Copyright (c) 2013 Red Hat, Inc.
   4 * All Rights Reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it would be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write the Free Software Foundation,
  17 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18 */
  19#include "xfs.h"
  20#include "xfs_fs.h"
  21#include "xfs_format.h"
  22#include "xfs_log_format.h"
  23#include "xfs_trans_resv.h"
  24#include "xfs_bit.h"
  25#include "xfs_mount.h"
  26#include "xfs_da_format.h"
  27#include "xfs_da_btree.h"
  28#include "xfs_inode.h"
  29#include "xfs_dir2.h"
  30#include "xfs_dir2_priv.h"
  31#include "xfs_error.h"
  32#include "xfs_trace.h"
  33#include "xfs_bmap.h"
  34#include "xfs_trans.h"
  35
  36/*
  37 * Directory file type support functions
  38 */
  39static unsigned char xfs_dir3_filetype_table[] = {
  40        DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK,
  41        DT_FIFO, DT_SOCK, DT_LNK, DT_WHT,
  42};
  43
  44static unsigned char
  45xfs_dir3_get_dtype(
  46        struct xfs_mount        *mp,
  47        uint8_t                 filetype)
  48{
  49        if (!xfs_sb_version_hasftype(&mp->m_sb))
  50                return DT_UNKNOWN;
  51
  52        if (filetype >= XFS_DIR3_FT_MAX)
  53                return DT_UNKNOWN;
  54
  55        return xfs_dir3_filetype_table[filetype];
  56}
  57
  58STATIC int
  59xfs_dir2_sf_getdents(
  60        struct xfs_da_args      *args,
  61        struct dir_context      *ctx)
  62{
  63        int                     i;              /* shortform entry number */
  64        struct xfs_inode        *dp = args->dp; /* incore directory inode */
  65        xfs_dir2_dataptr_t      off;            /* current entry's offset */
  66        xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
  67        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
  68        xfs_dir2_dataptr_t      dot_offset;
  69        xfs_dir2_dataptr_t      dotdot_offset;
  70        xfs_ino_t               ino;
  71        struct xfs_da_geometry  *geo = args->geo;
  72
  73        ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
  74        ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
  75        ASSERT(dp->i_df.if_u1.if_data != NULL);
  76
  77        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
  78
  79        /*
  80         * If the block number in the offset is out of range, we're done.
  81         */
  82        if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
  83                return 0;
  84
  85        /*
  86         * Precalculate offsets for . and .. as we will always need them.
  87         *
  88         * XXX(hch): the second argument is sometimes 0 and sometimes
  89         * geo->datablk
  90         */
  91        dot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
  92                                                dp->d_ops->data_dot_offset);
  93        dotdot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
  94                                                dp->d_ops->data_dotdot_offset);
  95
  96        /*
  97         * Put . entry unless we're starting past it.
  98         */
  99        if (ctx->pos <= dot_offset) {
 100                ctx->pos = dot_offset & 0x7fffffff;
 101                if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR))
 102                        return 0;
 103        }
 104
 105        /*
 106         * Put .. entry unless we're starting past it.
 107         */
 108        if (ctx->pos <= dotdot_offset) {
 109                ino = dp->d_ops->sf_get_parent_ino(sfp);
 110                ctx->pos = dotdot_offset & 0x7fffffff;
 111                if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
 112                        return 0;
 113        }
 114
 115        /*
 116         * Loop while there are more entries and put'ing works.
 117         */
 118        sfep = xfs_dir2_sf_firstentry(sfp);
 119        for (i = 0; i < sfp->count; i++) {
 120                uint8_t filetype;
 121
 122                off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
 123                                xfs_dir2_sf_get_offset(sfep));
 124
 125                if (ctx->pos > off) {
 126                        sfep = dp->d_ops->sf_nextentry(sfp, sfep);
 127                        continue;
 128                }
 129
 130                ino = dp->d_ops->sf_get_ino(sfp, sfep);
 131                filetype = dp->d_ops->sf_get_ftype(sfep);
 132                ctx->pos = off & 0x7fffffff;
 133                if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
 134                            xfs_dir3_get_dtype(dp->i_mount, filetype)))
 135                        return 0;
 136                sfep = dp->d_ops->sf_nextentry(sfp, sfep);
 137        }
 138
 139        ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
 140                                                                0x7fffffff;
 141        return 0;
 142}
 143
 144/*
 145 * Readdir for block directories.
 146 */
 147STATIC int
 148xfs_dir2_block_getdents(
 149        struct xfs_da_args      *args,
 150        struct dir_context      *ctx)
 151{
 152        struct xfs_inode        *dp = args->dp; /* incore directory inode */
 153        xfs_dir2_data_hdr_t     *hdr;           /* block header */
 154        struct xfs_buf          *bp;            /* buffer for block */
 155        xfs_dir2_block_tail_t   *btp;           /* block tail */
 156        xfs_dir2_data_entry_t   *dep;           /* block data entry */
 157        xfs_dir2_data_unused_t  *dup;           /* block unused entry */
 158        char                    *endptr;        /* end of the data entries */
 159        int                     error;          /* error return value */
 160        char                    *ptr;           /* current data entry */
 161        int                     wantoff;        /* starting block offset */
 162        xfs_off_t               cook;
 163        struct xfs_da_geometry  *geo = args->geo;
 164        int                     lock_mode;
 165
 166        /*
 167         * If the block number in the offset is out of range, we're done.
 168         */
 169        if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
 170                return 0;
 171
 172        lock_mode = xfs_ilock_data_map_shared(dp);
 173        error = xfs_dir3_block_read(args->trans, dp, &bp);
 174        xfs_iunlock(dp, lock_mode);
 175        if (error)
 176                return error;
 177
 178        /*
 179         * Extract the byte offset we start at from the seek pointer.
 180         * We'll skip entries before this.
 181         */
 182        wantoff = xfs_dir2_dataptr_to_off(geo, ctx->pos);
 183        hdr = bp->b_addr;
 184        xfs_dir3_data_check(dp, bp);
 185        /*
 186         * Set up values for the loop.
 187         */
 188        btp = xfs_dir2_block_tail_p(geo, hdr);
 189        ptr = (char *)dp->d_ops->data_entry_p(hdr);
 190        endptr = (char *)xfs_dir2_block_leaf_p(btp);
 191
 192        /*
 193         * Loop over the data portion of the block.
 194         * Each object is a real entry (dep) or an unused one (dup).
 195         */
 196        while (ptr < endptr) {
 197                uint8_t filetype;
 198
 199                dup = (xfs_dir2_data_unused_t *)ptr;
 200                /*
 201                 * Unused, skip it.
 202                 */
 203                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 204                        ptr += be16_to_cpu(dup->length);
 205                        continue;
 206                }
 207
 208                dep = (xfs_dir2_data_entry_t *)ptr;
 209
 210                /*
 211                 * Bump pointer for the next iteration.
 212                 */
 213                ptr += dp->d_ops->data_entsize(dep->namelen);
 214                /*
 215                 * The entry is before the desired starting point, skip it.
 216                 */
 217                if ((char *)dep - (char *)hdr < wantoff)
 218                        continue;
 219
 220                cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
 221                                            (char *)dep - (char *)hdr);
 222
 223                ctx->pos = cook & 0x7fffffff;
 224                filetype = dp->d_ops->data_get_ftype(dep);
 225                /*
 226                 * If it didn't fit, set the final offset to here & return.
 227                 */
 228                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
 229                            be64_to_cpu(dep->inumber),
 230                            xfs_dir3_get_dtype(dp->i_mount, filetype))) {
 231                        xfs_trans_brelse(args->trans, bp);
 232                        return 0;
 233                }
 234        }
 235
 236        /*
 237         * Reached the end of the block.
 238         * Set the offset to a non-existent block 1 and return.
 239         */
 240        ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
 241                                                                0x7fffffff;
 242        xfs_trans_brelse(args->trans, bp);
 243        return 0;
 244}
 245
 246/*
 247 * Read a directory block and initiate readahead for blocks beyond that.
 248 * We maintain a sliding readahead window of the remaining space in the
 249 * buffer rounded up to the nearest block.
 250 */
 251STATIC int
 252xfs_dir2_leaf_readbuf(
 253        struct xfs_da_args      *args,
 254        size_t                  bufsize,
 255        xfs_dir2_off_t          *cur_off,
 256        xfs_dablk_t             *ra_blk,
 257        struct xfs_buf          **bpp)
 258{
 259        struct xfs_inode        *dp = args->dp;
 260        struct xfs_buf          *bp = NULL;
 261        struct xfs_da_geometry  *geo = args->geo;
 262        struct xfs_ifork        *ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
 263        struct xfs_bmbt_irec    map;
 264        struct blk_plug         plug;
 265        xfs_dir2_off_t          new_off;
 266        xfs_dablk_t             next_ra;
 267        xfs_dablk_t             map_off;
 268        xfs_dablk_t             last_da;
 269        xfs_extnum_t            idx;
 270        int                     ra_want;
 271        int                     error = 0;
 272
 273        if (!(ifp->if_flags & XFS_IFEXTENTS)) {
 274                error = xfs_iread_extents(args->trans, dp, XFS_DATA_FORK);
 275                if (error)
 276                        goto out;
 277        }
 278
 279        /*
 280         * Look for mapped directory blocks at or above the current offset.
 281         * Truncate down to the nearest directory block to start the scanning
 282         * operation.
 283         */
 284        last_da = xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET);
 285        map_off = xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, *cur_off));
 286        if (!xfs_iext_lookup_extent(dp, ifp, map_off, &idx, &map))
 287                goto out;
 288        if (map.br_startoff >= last_da)
 289                goto out;
 290        xfs_trim_extent(&map, map_off, last_da - map_off);
 291
 292        /* Read the directory block of that first mapping. */
 293        new_off = xfs_dir2_da_to_byte(geo, map.br_startoff);
 294        if (new_off > *cur_off)
 295                *cur_off = new_off;
 296        error = xfs_dir3_data_read(args->trans, dp, map.br_startoff, -1, &bp);
 297        if (error)
 298                goto out;
 299
 300        /*
 301         * Start readahead for the next bufsize's worth of dir data blocks.
 302         * We may have already issued readahead for some of that range;
 303         * ra_blk tracks the last block we tried to read(ahead).
 304         */
 305        ra_want = howmany(bufsize + geo->blksize, (1 << geo->fsblog));
 306        if (*ra_blk >= last_da)
 307                goto out;
 308        else if (*ra_blk == 0)
 309                *ra_blk = map.br_startoff;
 310        next_ra = map.br_startoff + geo->fsbcount;
 311        if (next_ra >= last_da)
 312                goto out_no_ra;
 313        if (map.br_blockcount < geo->fsbcount &&
 314            !xfs_iext_get_extent(ifp, ++idx, &map))
 315                goto out_no_ra;
 316        if (map.br_startoff >= last_da)
 317                goto out_no_ra;
 318        xfs_trim_extent(&map, next_ra, last_da - next_ra);
 319
 320        /* Start ra for each dir (not fs) block that has a mapping. */
 321        blk_start_plug(&plug);
 322        while (ra_want > 0) {
 323                next_ra = roundup((xfs_dablk_t)map.br_startoff, geo->fsbcount);
 324                while (ra_want > 0 &&
 325                       next_ra < map.br_startoff + map.br_blockcount) {
 326                        if (next_ra >= last_da) {
 327                                *ra_blk = last_da;
 328                                break;
 329                        }
 330                        if (next_ra > *ra_blk) {
 331                                xfs_dir3_data_readahead(dp, next_ra, -2);
 332                                *ra_blk = next_ra;
 333                        }
 334                        ra_want -= geo->fsbcount;
 335                        next_ra += geo->fsbcount;
 336                }
 337                if (!xfs_iext_get_extent(ifp, ++idx, &map)) {
 338                        *ra_blk = last_da;
 339                        break;
 340                }
 341        }
 342        blk_finish_plug(&plug);
 343
 344out:
 345        *bpp = bp;
 346        return error;
 347out_no_ra:
 348        *ra_blk = last_da;
 349        goto out;
 350}
 351
 352/*
 353 * Getdents (readdir) for leaf and node directories.
 354 * This reads the data blocks only, so is the same for both forms.
 355 */
 356STATIC int
 357xfs_dir2_leaf_getdents(
 358        struct xfs_da_args      *args,
 359        struct dir_context      *ctx,
 360        size_t                  bufsize)
 361{
 362        struct xfs_inode        *dp = args->dp;
 363        struct xfs_buf          *bp = NULL;     /* data block buffer */
 364        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
 365        xfs_dir2_data_entry_t   *dep;           /* data entry */
 366        xfs_dir2_data_unused_t  *dup;           /* unused entry */
 367        char                    *ptr = NULL;    /* pointer to current data */
 368        struct xfs_da_geometry  *geo = args->geo;
 369        xfs_dablk_t             rablk = 0;      /* current readahead block */
 370        xfs_dir2_off_t          curoff;         /* current overall offset */
 371        int                     length;         /* temporary length value */
 372        int                     byteoff;        /* offset in current block */
 373        int                     lock_mode;
 374        int                     error = 0;      /* error return value */
 375
 376        /*
 377         * If the offset is at or past the largest allowed value,
 378         * give up right away.
 379         */
 380        if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
 381                return 0;
 382
 383        /*
 384         * Inside the loop we keep the main offset value as a byte offset
 385         * in the directory file.
 386         */
 387        curoff = xfs_dir2_dataptr_to_byte(ctx->pos);
 388
 389        /*
 390         * Loop over directory entries until we reach the end offset.
 391         * Get more blocks and readahead as necessary.
 392         */
 393        while (curoff < XFS_DIR2_LEAF_OFFSET) {
 394                uint8_t filetype;
 395
 396                /*
 397                 * If we have no buffer, or we're off the end of the
 398                 * current buffer, need to get another one.
 399                 */
 400                if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) {
 401                        if (bp) {
 402                                xfs_trans_brelse(args->trans, bp);
 403                                bp = NULL;
 404                        }
 405
 406                        lock_mode = xfs_ilock_data_map_shared(dp);
 407                        error = xfs_dir2_leaf_readbuf(args, bufsize, &curoff,
 408                                        &rablk, &bp);
 409                        xfs_iunlock(dp, lock_mode);
 410                        if (error || !bp)
 411                                break;
 412
 413                        hdr = bp->b_addr;
 414                        xfs_dir3_data_check(dp, bp);
 415                        /*
 416                         * Find our position in the block.
 417                         */
 418                        ptr = (char *)dp->d_ops->data_entry_p(hdr);
 419                        byteoff = xfs_dir2_byte_to_off(geo, curoff);
 420                        /*
 421                         * Skip past the header.
 422                         */
 423                        if (byteoff == 0)
 424                                curoff += dp->d_ops->data_entry_offset;
 425                        /*
 426                         * Skip past entries until we reach our offset.
 427                         */
 428                        else {
 429                                while ((char *)ptr - (char *)hdr < byteoff) {
 430                                        dup = (xfs_dir2_data_unused_t *)ptr;
 431
 432                                        if (be16_to_cpu(dup->freetag)
 433                                                  == XFS_DIR2_DATA_FREE_TAG) {
 434
 435                                                length = be16_to_cpu(dup->length);
 436                                                ptr += length;
 437                                                continue;
 438                                        }
 439                                        dep = (xfs_dir2_data_entry_t *)ptr;
 440                                        length =
 441                                           dp->d_ops->data_entsize(dep->namelen);
 442                                        ptr += length;
 443                                }
 444                                /*
 445                                 * Now set our real offset.
 446                                 */
 447                                curoff =
 448                                        xfs_dir2_db_off_to_byte(geo,
 449                                            xfs_dir2_byte_to_db(geo, curoff),
 450                                            (char *)ptr - (char *)hdr);
 451                                if (ptr >= (char *)hdr + geo->blksize) {
 452                                        continue;
 453                                }
 454                        }
 455                }
 456                /*
 457                 * We have a pointer to an entry.
 458                 * Is it a live one?
 459                 */
 460                dup = (xfs_dir2_data_unused_t *)ptr;
 461                /*
 462                 * No, it's unused, skip over it.
 463                 */
 464                if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
 465                        length = be16_to_cpu(dup->length);
 466                        ptr += length;
 467                        curoff += length;
 468                        continue;
 469                }
 470
 471                dep = (xfs_dir2_data_entry_t *)ptr;
 472                length = dp->d_ops->data_entsize(dep->namelen);
 473                filetype = dp->d_ops->data_get_ftype(dep);
 474
 475                ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
 476                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
 477                            be64_to_cpu(dep->inumber),
 478                            xfs_dir3_get_dtype(dp->i_mount, filetype)))
 479                        break;
 480
 481                /*
 482                 * Advance to next entry in the block.
 483                 */
 484                ptr += length;
 485                curoff += length;
 486                /* bufsize may have just been a guess; don't go negative */
 487                bufsize = bufsize > length ? bufsize - length : 0;
 488        }
 489
 490        /*
 491         * All done.  Set output offset value to current offset.
 492         */
 493        if (curoff > xfs_dir2_dataptr_to_byte(XFS_DIR2_MAX_DATAPTR))
 494                ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
 495        else
 496                ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
 497        if (bp)
 498                xfs_trans_brelse(args->trans, bp);
 499        return error;
 500}
 501
 502/*
 503 * Read a directory.
 504 *
 505 * If supplied, the transaction collects locked dir buffers to avoid
 506 * nested buffer deadlocks.  This function does not dirty the
 507 * transaction.  The caller should ensure that the inode is locked
 508 * before calling this function.
 509 */
 510int
 511xfs_readdir(
 512        struct xfs_trans        *tp,
 513        struct xfs_inode        *dp,
 514        struct dir_context      *ctx,
 515        size_t                  bufsize)
 516{
 517        struct xfs_da_args      args = { NULL };
 518        int                     rval;
 519        int                     v;
 520
 521        trace_xfs_readdir(dp);
 522
 523        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 524                return -EIO;
 525
 526        ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 527        XFS_STATS_INC(dp->i_mount, xs_dir_getdents);
 528
 529        args.dp = dp;
 530        args.geo = dp->i_mount->m_dir_geo;
 531        args.trans = tp;
 532
 533        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 534                rval = xfs_dir2_sf_getdents(&args, ctx);
 535        else if ((rval = xfs_dir2_isblock(&args, &v)))
 536                ;
 537        else if (v)
 538                rval = xfs_dir2_block_getdents(&args, ctx);
 539        else
 540                rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize);
 541
 542        return rval;
 543}
 544