linux/fs/xfs/xfs_ialloc_btree.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2001,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_bit.h"
  22#include "xfs_log.h"
  23#include "xfs_trans.h"
  24#include "xfs_sb.h"
  25#include "xfs_ag.h"
  26#include "xfs_mount.h"
  27#include "xfs_bmap_btree.h"
  28#include "xfs_alloc_btree.h"
  29#include "xfs_ialloc_btree.h"
  30#include "xfs_dinode.h"
  31#include "xfs_inode.h"
  32#include "xfs_btree.h"
  33#include "xfs_ialloc.h"
  34#include "xfs_alloc.h"
  35#include "xfs_error.h"
  36
  37
  38STATIC int
  39xfs_inobt_get_minrecs(
  40        struct xfs_btree_cur    *cur,
  41        int                     level)
  42{
  43        return cur->bc_mp->m_inobt_mnr[level != 0];
  44}
  45
  46STATIC struct xfs_btree_cur *
  47xfs_inobt_dup_cursor(
  48        struct xfs_btree_cur    *cur)
  49{
  50        return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
  51                        cur->bc_private.a.agbp, cur->bc_private.a.agno);
  52}
  53
  54STATIC void
  55xfs_inobt_set_root(
  56        struct xfs_btree_cur    *cur,
  57        union xfs_btree_ptr     *nptr,
  58        int                     inc)    /* level change */
  59{
  60        struct xfs_buf          *agbp = cur->bc_private.a.agbp;
  61        struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
  62
  63        agi->agi_root = nptr->s;
  64        be32_add_cpu(&agi->agi_level, inc);
  65        xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
  66}
  67
  68STATIC int
  69xfs_inobt_alloc_block(
  70        struct xfs_btree_cur    *cur,
  71        union xfs_btree_ptr     *start,
  72        union xfs_btree_ptr     *new,
  73        int                     length,
  74        int                     *stat)
  75{
  76        xfs_alloc_arg_t         args;           /* block allocation args */
  77        int                     error;          /* error return value */
  78        xfs_agblock_t           sbno = be32_to_cpu(start->s);
  79
  80        XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
  81
  82        memset(&args, 0, sizeof(args));
  83        args.tp = cur->bc_tp;
  84        args.mp = cur->bc_mp;
  85        args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno);
  86        args.minlen = 1;
  87        args.maxlen = 1;
  88        args.prod = 1;
  89        args.type = XFS_ALLOCTYPE_NEAR_BNO;
  90
  91        error = xfs_alloc_vextent(&args);
  92        if (error) {
  93                XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
  94                return error;
  95        }
  96        if (args.fsbno == NULLFSBLOCK) {
  97                XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
  98                *stat = 0;
  99                return 0;
 100        }
 101        ASSERT(args.len == 1);
 102        XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
 103
 104        new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno));
 105        *stat = 1;
 106        return 0;
 107}
 108
 109STATIC int
 110xfs_inobt_free_block(
 111        struct xfs_btree_cur    *cur,
 112        struct xfs_buf          *bp)
 113{
 114        xfs_fsblock_t           fsbno;
 115        int                     error;
 116
 117        fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp));
 118        error = xfs_free_extent(cur->bc_tp, fsbno, 1);
 119        if (error)
 120                return error;
 121
 122        xfs_trans_binval(cur->bc_tp, bp);
 123        return error;
 124}
 125
 126STATIC int
 127xfs_inobt_get_maxrecs(
 128        struct xfs_btree_cur    *cur,
 129        int                     level)
 130{
 131        return cur->bc_mp->m_inobt_mxr[level != 0];
 132}
 133
 134STATIC void
 135xfs_inobt_init_key_from_rec(
 136        union xfs_btree_key     *key,
 137        union xfs_btree_rec     *rec)
 138{
 139        key->inobt.ir_startino = rec->inobt.ir_startino;
 140}
 141
 142STATIC void
 143xfs_inobt_init_rec_from_key(
 144        union xfs_btree_key     *key,
 145        union xfs_btree_rec     *rec)
 146{
 147        rec->inobt.ir_startino = key->inobt.ir_startino;
 148}
 149
 150STATIC void
 151xfs_inobt_init_rec_from_cur(
 152        struct xfs_btree_cur    *cur,
 153        union xfs_btree_rec     *rec)
 154{
 155        rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
 156        rec->inobt.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
 157        rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
 158}
 159
 160/*
 161 * initial value of ptr for lookup
 162 */
 163STATIC void
 164xfs_inobt_init_ptr_from_cur(
 165        struct xfs_btree_cur    *cur,
 166        union xfs_btree_ptr     *ptr)
 167{
 168        struct xfs_agi          *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
 169
 170        ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
 171
 172        ptr->s = agi->agi_root;
 173}
 174
 175STATIC __int64_t
 176xfs_inobt_key_diff(
 177        struct xfs_btree_cur    *cur,
 178        union xfs_btree_key     *key)
 179{
 180        return (__int64_t)be32_to_cpu(key->inobt.ir_startino) -
 181                          cur->bc_rec.i.ir_startino;
 182}
 183
 184#ifdef DEBUG
 185STATIC int
 186xfs_inobt_keys_inorder(
 187        struct xfs_btree_cur    *cur,
 188        union xfs_btree_key     *k1,
 189        union xfs_btree_key     *k2)
 190{
 191        return be32_to_cpu(k1->inobt.ir_startino) <
 192                be32_to_cpu(k2->inobt.ir_startino);
 193}
 194
 195STATIC int
 196xfs_inobt_recs_inorder(
 197        struct xfs_btree_cur    *cur,
 198        union xfs_btree_rec     *r1,
 199        union xfs_btree_rec     *r2)
 200{
 201        return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <=
 202                be32_to_cpu(r2->inobt.ir_startino);
 203}
 204#endif  /* DEBUG */
 205
 206static const struct xfs_btree_ops xfs_inobt_ops = {
 207        .rec_len                = sizeof(xfs_inobt_rec_t),
 208        .key_len                = sizeof(xfs_inobt_key_t),
 209
 210        .dup_cursor             = xfs_inobt_dup_cursor,
 211        .set_root               = xfs_inobt_set_root,
 212        .alloc_block            = xfs_inobt_alloc_block,
 213        .free_block             = xfs_inobt_free_block,
 214        .get_minrecs            = xfs_inobt_get_minrecs,
 215        .get_maxrecs            = xfs_inobt_get_maxrecs,
 216        .init_key_from_rec      = xfs_inobt_init_key_from_rec,
 217        .init_rec_from_key      = xfs_inobt_init_rec_from_key,
 218        .init_rec_from_cur      = xfs_inobt_init_rec_from_cur,
 219        .init_ptr_from_cur      = xfs_inobt_init_ptr_from_cur,
 220        .key_diff               = xfs_inobt_key_diff,
 221#ifdef DEBUG
 222        .keys_inorder           = xfs_inobt_keys_inorder,
 223        .recs_inorder           = xfs_inobt_recs_inorder,
 224#endif
 225};
 226
 227/*
 228 * Allocate a new inode btree cursor.
 229 */
 230struct xfs_btree_cur *                          /* new inode btree cursor */
 231xfs_inobt_init_cursor(
 232        struct xfs_mount        *mp,            /* file system mount point */
 233        struct xfs_trans        *tp,            /* transaction pointer */
 234        struct xfs_buf          *agbp,          /* buffer for agi structure */
 235        xfs_agnumber_t          agno)           /* allocation group number */
 236{
 237        struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
 238        struct xfs_btree_cur    *cur;
 239
 240        cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
 241
 242        cur->bc_tp = tp;
 243        cur->bc_mp = mp;
 244        cur->bc_nlevels = be32_to_cpu(agi->agi_level);
 245        cur->bc_btnum = XFS_BTNUM_INO;
 246        cur->bc_blocklog = mp->m_sb.sb_blocklog;
 247
 248        cur->bc_ops = &xfs_inobt_ops;
 249
 250        cur->bc_private.a.agbp = agbp;
 251        cur->bc_private.a.agno = agno;
 252
 253        return cur;
 254}
 255
 256/*
 257 * Calculate number of records in an inobt btree block.
 258 */
 259int
 260xfs_inobt_maxrecs(
 261        struct xfs_mount        *mp,
 262        int                     blocklen,
 263        int                     leaf)
 264{
 265        blocklen -= XFS_INOBT_BLOCK_LEN(mp);
 266
 267        if (leaf)
 268                return blocklen / sizeof(xfs_inobt_rec_t);
 269        return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t));
 270}
 271