]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/xfs/xfs_dir2_readdir.c
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux...
[karo-tx-linux.git] / fs / xfs / xfs_dir2_readdir.c
index bf7a5cee7adc00d90f110913f4902ddaac9e5296..48e99afb9cb0ceff340e4842009d67d6c063d2f1 100644 (file)
@@ -76,26 +76,25 @@ const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
 
 STATIC int
 xfs_dir2_sf_getdents(
-       xfs_inode_t             *dp,            /* incore directory inode */
+       struct xfs_da_args      *args,
        struct dir_context      *ctx)
 {
        int                     i;              /* shortform entry number */
-       xfs_mount_t             *mp;            /* filesystem mount point */
+       struct xfs_inode        *dp = args->dp; /* incore directory inode */
        xfs_dir2_dataptr_t      off;            /* current entry's offset */
        xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
        xfs_dir2_dataptr_t      dot_offset;
        xfs_dir2_dataptr_t      dotdot_offset;
        xfs_ino_t               ino;
-
-       mp = dp->i_mount;
+       struct xfs_da_geometry  *geo = args->geo;
 
        ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
        /*
         * Give up if the directory is way too short.
         */
        if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(mp));
+               ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
                return XFS_ERROR(EIO);
        }
 
@@ -109,18 +108,18 @@ xfs_dir2_sf_getdents(
        /*
         * If the block number in the offset is out of range, we're done.
         */
-       if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
+       if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
                return 0;
 
        /*
         * Precalculate offsets for . and .. as we will always need them.
         *
         * XXX(hch): the second argument is sometimes 0 and sometimes
-        * mp->m_dirdatablk.
+        * geo->datablk
         */
-       dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+       dot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
                                                dp->d_ops->data_dot_offset);
-       dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+       dotdot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
                                                dp->d_ops->data_dotdot_offset);
 
        /*
@@ -149,7 +148,7 @@ xfs_dir2_sf_getdents(
        for (i = 0; i < sfp->count; i++) {
                __uint8_t filetype;
 
-               off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+               off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
                                xfs_dir2_sf_get_offset(sfep));
 
                if (ctx->pos > off) {
@@ -161,13 +160,13 @@ xfs_dir2_sf_getdents(
                filetype = dp->d_ops->sf_get_ftype(sfep);
                ctx->pos = off & 0x7fffffff;
                if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
-                           xfs_dir3_get_dtype(mp, filetype)))
+                           xfs_dir3_get_dtype(dp->i_mount, filetype)))
                        return 0;
                sfep = dp->d_ops->sf_nextentry(sfp, sfep);
        }
 
-       ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
-                       0x7fffffff;
+       ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
+                                                               0x7fffffff;
        return 0;
 }
 
@@ -176,9 +175,10 @@ xfs_dir2_sf_getdents(
  */
 STATIC int
 xfs_dir2_block_getdents(
-       xfs_inode_t             *dp,            /* incore inode */
+       struct xfs_da_args      *args,
        struct dir_context      *ctx)
 {
+       struct xfs_inode        *dp = args->dp; /* incore directory inode */
        xfs_dir2_data_hdr_t     *hdr;           /* block header */
        struct xfs_buf          *bp;            /* buffer for block */
        xfs_dir2_block_tail_t   *btp;           /* block tail */
@@ -186,16 +186,15 @@ xfs_dir2_block_getdents(
        xfs_dir2_data_unused_t  *dup;           /* block unused entry */
        char                    *endptr;        /* end of the data entries */
        int                     error;          /* error return value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
        char                    *ptr;           /* current data entry */
        int                     wantoff;        /* starting block offset */
        xfs_off_t               cook;
+       struct xfs_da_geometry  *geo = args->geo;
 
-       mp = dp->i_mount;
        /*
         * If the block number in the offset is out of range, we're done.
         */
-       if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
+       if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
                return 0;
 
        error = xfs_dir3_block_read(NULL, dp, &bp);
@@ -206,13 +205,13 @@ xfs_dir2_block_getdents(
         * Extract the byte offset we start at from the seek pointer.
         * We'll skip entries before this.
         */
-       wantoff = xfs_dir2_dataptr_to_off(mp, ctx->pos);
+       wantoff = xfs_dir2_dataptr_to_off(geo, ctx->pos);
        hdr = bp->b_addr;
        xfs_dir3_data_check(dp, bp);
        /*
         * Set up values for the loop.
         */
-       btp = xfs_dir2_block_tail_p(mp, hdr);
+       btp = xfs_dir2_block_tail_p(geo, hdr);
        ptr = (char *)dp->d_ops->data_entry_p(hdr);
        endptr = (char *)xfs_dir2_block_leaf_p(btp);
 
@@ -244,7 +243,7 @@ xfs_dir2_block_getdents(
                if ((char *)dep - (char *)hdr < wantoff)
                        continue;
 
-               cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+               cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
                                            (char *)dep - (char *)hdr);
 
                ctx->pos = cook & 0x7fffffff;
@@ -254,7 +253,7 @@ xfs_dir2_block_getdents(
                 */
                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
                            be64_to_cpu(dep->inumber),
-                           xfs_dir3_get_dtype(mp, filetype))) {
+                           xfs_dir3_get_dtype(dp->i_mount, filetype))) {
                        xfs_trans_brelse(NULL, bp);
                        return 0;
                }
@@ -264,8 +263,8 @@ xfs_dir2_block_getdents(
         * Reached the end of the block.
         * Set the offset to a non-existent block 1 and return.
         */
-       ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
-                       0x7fffffff;
+       ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
+                                                               0x7fffffff;
        xfs_trans_brelse(NULL, bp);
        return 0;
 }
@@ -286,13 +285,13 @@ struct xfs_dir2_leaf_map_info {
 
 STATIC int
 xfs_dir2_leaf_readbuf(
-       struct xfs_inode        *dp,
+       struct xfs_da_args      *args,
        size_t                  bufsize,
        struct xfs_dir2_leaf_map_info *mip,
        xfs_dir2_off_t          *curoff,
        struct xfs_buf          **bpp)
 {
-       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_inode        *dp = args->dp;
        struct xfs_buf          *bp = *bpp;
        struct xfs_bmbt_irec    *map = mip->map;
        struct blk_plug         plug;
@@ -300,6 +299,7 @@ xfs_dir2_leaf_readbuf(
        int                     length;
        int                     i;
        int                     j;
+       struct xfs_da_geometry  *geo = args->geo;
 
        /*
         * If we have a buffer, we need to release it and
@@ -309,12 +309,12 @@ xfs_dir2_leaf_readbuf(
        if (bp) {
                xfs_trans_brelse(NULL, bp);
                bp = NULL;
-               mip->map_blocks -= mp->m_dirblkfsbs;
+               mip->map_blocks -= geo->fsbcount;
                /*
                 * Loop to get rid of the extents for the
                 * directory block.
                 */
-               for (i = mp->m_dirblkfsbs; i > 0; ) {
+               for (i = geo->fsbcount; i > 0; ) {
                        j = min_t(int, map->br_blockcount, i);
                        map->br_blockcount -= j;
                        map->br_startblock += j;
@@ -333,8 +333,7 @@ xfs_dir2_leaf_readbuf(
        /*
         * Recalculate the readahead blocks wanted.
         */
-       mip->ra_want = howmany(bufsize + mp->m_dirblksize,
-                              mp->m_sb.sb_blocksize) - 1;
+       mip->ra_want = howmany(bufsize + geo->blksize, (1 << geo->fsblog)) - 1;
        ASSERT(mip->ra_want >= 0);
 
        /*
@@ -342,14 +341,14 @@ xfs_dir2_leaf_readbuf(
         * run out of data blocks, get some more mappings.
         */
        if (1 + mip->ra_want > mip->map_blocks &&
-           mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
+           mip->map_off < xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET)) {
                /*
                 * Get more bmaps, fill in after the ones
                 * we already have in the table.
                 */
                mip->nmap = mip->map_size - mip->map_valid;
                error = xfs_bmapi_read(dp, mip->map_off,
-                               xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
+                               xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET) -
                                                                mip->map_off,
                                &map[mip->map_valid], &mip->nmap, 0);
 
@@ -370,7 +369,7 @@ xfs_dir2_leaf_readbuf(
                        i = mip->map_valid + mip->nmap - 1;
                        mip->map_off = map[i].br_startoff + map[i].br_blockcount;
                } else
-                       mip->map_off = xfs_dir2_byte_to_da(mp,
+                       mip->map_off = xfs_dir2_byte_to_da(geo,
                                                        XFS_DIR2_LEAF_OFFSET);
 
                /*
@@ -396,18 +395,18 @@ xfs_dir2_leaf_readbuf(
         * No valid mappings, so no more data blocks.
         */
        if (!mip->map_valid) {
-               *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
+               *curoff = xfs_dir2_da_to_byte(geo, mip->map_off);
                goto out;
        }
 
        /*
         * Read the directory block starting at the first mapping.
         */
-       mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
+       mip->curdb = xfs_dir2_da_to_db(geo, map->br_startoff);
        error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
-                       map->br_blockcount >= mp->m_dirblkfsbs ?
-                           XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
-
+                       map->br_blockcount >= geo->fsbcount ?
+                           XFS_FSB_TO_DADDR(dp->i_mount, map->br_startblock) :
+                           -1, &bp);
        /*
         * Should just skip over the data block instead of giving up.
         */
@@ -419,7 +418,7 @@ xfs_dir2_leaf_readbuf(
         * was previously ra.
         */
        if (mip->ra_current)
-               mip->ra_current -= mp->m_dirblkfsbs;
+               mip->ra_current -= geo->fsbcount;
 
        /*
         * Do we need more readahead?
@@ -427,16 +426,16 @@ xfs_dir2_leaf_readbuf(
        blk_start_plug(&plug);
        for (mip->ra_index = mip->ra_offset = i = 0;
             mip->ra_want > mip->ra_current && i < mip->map_blocks;
-            i += mp->m_dirblkfsbs) {
+            i += geo->fsbcount) {
                ASSERT(mip->ra_index < mip->map_valid);
                /*
                 * Read-ahead a contiguous directory block.
                 */
                if (i > mip->ra_current &&
-                   map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
+                   map[mip->ra_index].br_blockcount >= geo->fsbcount) {
                        xfs_dir3_data_readahead(dp,
                                map[mip->ra_index].br_startoff + mip->ra_offset,
-                               XFS_FSB_TO_DADDR(mp,
+                               XFS_FSB_TO_DADDR(dp->i_mount,
                                        map[mip->ra_index].br_startblock +
                                                        mip->ra_offset));
                        mip->ra_current = i;
@@ -456,12 +455,12 @@ xfs_dir2_leaf_readbuf(
                /*
                 * Advance offset through the mapping table.
                 */
-               for (j = 0; j < mp->m_dirblkfsbs; j += length ) {
+               for (j = 0; j < geo->fsbcount; j += length ) {
                        /*
                         * The rest of this extent but not more than a dir
                         * block.
                         */
-                       length = min_t(int, mp->m_dirblkfsbs,
+                       length = min_t(int, geo->fsbcount,
                                        map[mip->ra_index].br_blockcount -
                                                        mip->ra_offset);
                        mip->ra_offset += length;
@@ -488,22 +487,23 @@ out:
  */
 STATIC int
 xfs_dir2_leaf_getdents(
-       xfs_inode_t             *dp,            /* incore directory inode */
+       struct xfs_da_args      *args,
        struct dir_context      *ctx,
        size_t                  bufsize)
 {
+       struct xfs_inode        *dp = args->dp;
        struct xfs_buf          *bp = NULL;     /* data block buffer */
        xfs_dir2_data_hdr_t     *hdr;           /* data block header */
        xfs_dir2_data_entry_t   *dep;           /* data entry */
        xfs_dir2_data_unused_t  *dup;           /* unused entry */
        int                     error = 0;      /* error return value */
        int                     length;         /* temporary length value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
        int                     byteoff;        /* offset in current block */
        xfs_dir2_off_t          curoff;         /* current overall offset */
        xfs_dir2_off_t          newoff;         /* new curoff after new blk */
        char                    *ptr = NULL;    /* pointer to current data */
        struct xfs_dir2_leaf_map_info *map_info;
+       struct xfs_da_geometry  *geo = args->geo;
 
        /*
         * If the offset is at or past the largest allowed value,
@@ -512,15 +512,12 @@ xfs_dir2_leaf_getdents(
        if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
                return 0;
 
-       mp = dp->i_mount;
-
        /*
         * Set up to bmap a number of blocks based on the caller's
         * buffer size, the directory block size, and the filesystem
         * block size.
         */
-       length = howmany(bufsize + mp->m_dirblksize,
-                                    mp->m_sb.sb_blocksize);
+       length = howmany(bufsize + geo->blksize, (1 << geo->fsblog));
        map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
                                (length * sizeof(struct xfs_bmbt_irec)),
                               KM_SLEEP | KM_NOFS);
@@ -536,8 +533,8 @@ xfs_dir2_leaf_getdents(
         * Force this conversion through db so we truncate the offset
         * down to get the start of the data block.
         */
-       map_info->map_off = xfs_dir2_db_to_da(mp,
-                                             xfs_dir2_byte_to_db(mp, curoff));
+       map_info->map_off = xfs_dir2_db_to_da(geo,
+                                             xfs_dir2_byte_to_db(geo, curoff));
 
        /*
         * Loop over directory entries until we reach the end offset.
@@ -550,9 +547,9 @@ xfs_dir2_leaf_getdents(
                 * If we have no buffer, or we're off the end of the
                 * current buffer, need to get another one.
                 */
-               if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
+               if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) {
 
-                       error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
+                       error = xfs_dir2_leaf_readbuf(args, bufsize, map_info,
                                                      &curoff, &bp);
                        if (error || !map_info->map_valid)
                                break;
@@ -560,7 +557,8 @@ xfs_dir2_leaf_getdents(
                        /*
                         * Having done a read, we need to set a new offset.
                         */
-                       newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
+                       newoff = xfs_dir2_db_off_to_byte(geo,
+                                                        map_info->curdb, 0);
                        /*
                         * Start of the current block.
                         */
@@ -570,7 +568,7 @@ xfs_dir2_leaf_getdents(
                         * Make sure we're in the right block.
                         */
                        else if (curoff > newoff)
-                               ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
+                               ASSERT(xfs_dir2_byte_to_db(geo, curoff) ==
                                       map_info->curdb);
                        hdr = bp->b_addr;
                        xfs_dir3_data_check(dp, bp);
@@ -578,7 +576,7 @@ xfs_dir2_leaf_getdents(
                         * Find our position in the block.
                         */
                        ptr = (char *)dp->d_ops->data_entry_p(hdr);
-                       byteoff = xfs_dir2_byte_to_off(mp, curoff);
+                       byteoff = xfs_dir2_byte_to_off(geo, curoff);
                        /*
                         * Skip past the header.
                         */
@@ -607,10 +605,10 @@ xfs_dir2_leaf_getdents(
                                 * Now set our real offset.
                                 */
                                curoff =
-                                       xfs_dir2_db_off_to_byte(mp,
-                                           xfs_dir2_byte_to_db(mp, curoff),
+                                       xfs_dir2_db_off_to_byte(geo,
+                                           xfs_dir2_byte_to_db(geo, curoff),
                                            (char *)ptr - (char *)hdr);
-                               if (ptr >= (char *)hdr + mp->m_dirblksize) {
+                               if (ptr >= (char *)hdr + geo->blksize) {
                                        continue;
                                }
                        }
@@ -637,7 +635,7 @@ xfs_dir2_leaf_getdents(
                ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
                if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
                            be64_to_cpu(dep->inumber),
-                           xfs_dir3_get_dtype(mp, filetype)))
+                           xfs_dir3_get_dtype(dp->i_mount, filetype)))
                        break;
 
                /*
@@ -667,13 +665,14 @@ xfs_dir2_leaf_getdents(
  */
 int
 xfs_readdir(
-       xfs_inode_t     *dp,
-       struct dir_context *ctx,
-       size_t          bufsize)
+       struct xfs_inode        *dp,
+       struct dir_context      *ctx,
+       size_t                  bufsize)
 {
-       int             rval;           /* return value */
-       int             v;              /* type-checking value */
-       uint            lock_mode;
+       struct xfs_da_args      args = { NULL };
+       int                     rval;
+       int                     v;
+       uint                    lock_mode;
 
        trace_xfs_readdir(dp);
 
@@ -683,15 +682,18 @@ xfs_readdir(
        ASSERT(S_ISDIR(dp->i_d.di_mode));
        XFS_STATS_INC(xs_dir_getdents);
 
+       args.dp = dp;
+       args.geo = dp->i_mount->m_dir_geo;
+
        lock_mode = xfs_ilock_data_map_shared(dp);
        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
-               rval = xfs_dir2_sf_getdents(dp, ctx);
-       else if ((rval = xfs_dir2_isblock(dp, &v)))
+               rval = xfs_dir2_sf_getdents(&args, ctx);
+       else if ((rval = xfs_dir2_isblock(&args, &v)))
                ;
        else if (v)
-               rval = xfs_dir2_block_getdents(dp, ctx);
+               rval = xfs_dir2_block_getdents(&args, ctx);
        else
-               rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize);
+               rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize);
        xfs_iunlock(dp, lock_mode);
 
        return rval;