Commit b7676929 authored by Dave Chinner's avatar Dave Chinner

Merge branch 'xfs-free-inode-btree' into for-next

parents 232c2f5c 53801fd9
...@@ -160,30 +160,38 @@ typedef struct xfs_agi { ...@@ -160,30 +160,38 @@ typedef struct xfs_agi {
* still being referenced. * still being referenced.
*/ */
__be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
/*
* This marks the end of logging region 1 and start of logging region 2.
*/
uuid_t agi_uuid; /* uuid of filesystem */ uuid_t agi_uuid; /* uuid of filesystem */
__be32 agi_crc; /* crc of agi sector */ __be32 agi_crc; /* crc of agi sector */
__be32 agi_pad32; __be32 agi_pad32;
__be64 agi_lsn; /* last write sequence */ __be64 agi_lsn; /* last write sequence */
__be32 agi_free_root; /* root of the free inode btree */
__be32 agi_free_level;/* levels in free inode btree */
/* structure must be padded to 64 bit alignment */ /* structure must be padded to 64 bit alignment */
} xfs_agi_t; } xfs_agi_t;
#define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc) #define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc)
#define XFS_AGI_MAGICNUM 0x00000001 #define XFS_AGI_MAGICNUM (1 << 0)
#define XFS_AGI_VERSIONNUM 0x00000002 #define XFS_AGI_VERSIONNUM (1 << 1)
#define XFS_AGI_SEQNO 0x00000004 #define XFS_AGI_SEQNO (1 << 2)
#define XFS_AGI_LENGTH 0x00000008 #define XFS_AGI_LENGTH (1 << 3)
#define XFS_AGI_COUNT 0x00000010 #define XFS_AGI_COUNT (1 << 4)
#define XFS_AGI_ROOT 0x00000020 #define XFS_AGI_ROOT (1 << 5)
#define XFS_AGI_LEVEL 0x00000040 #define XFS_AGI_LEVEL (1 << 6)
#define XFS_AGI_FREECOUNT 0x00000080 #define XFS_AGI_FREECOUNT (1 << 7)
#define XFS_AGI_NEWINO 0x00000100 #define XFS_AGI_NEWINO (1 << 8)
#define XFS_AGI_DIRINO 0x00000200 #define XFS_AGI_DIRINO (1 << 9)
#define XFS_AGI_UNLINKED 0x00000400 #define XFS_AGI_UNLINKED (1 << 10)
#define XFS_AGI_NUM_BITS 11 #define XFS_AGI_NUM_BITS_R1 11 /* end of the 1st agi logging region */
#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1) #define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1)
#define XFS_AGI_FREE_ROOT (1 << 11)
#define XFS_AGI_FREE_LEVEL (1 << 12)
#define XFS_AGI_NUM_BITS_R2 13
/* disk block (xfs_daddr_t) in the AG */ /* disk block (xfs_daddr_t) in the AG */
#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log)) #define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))
......
...@@ -43,9 +43,10 @@ kmem_zone_t *xfs_btree_cur_zone; ...@@ -43,9 +43,10 @@ kmem_zone_t *xfs_btree_cur_zone;
* Btree magic numbers. * Btree magic numbers.
*/ */
static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = { static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
{ XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC }, { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
XFS_FIBT_MAGIC },
{ XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC } XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC }
}; };
#define xfs_btree_magic(cur) \ #define xfs_btree_magic(cur) \
xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum] xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
...@@ -1115,6 +1116,7 @@ xfs_btree_set_refs( ...@@ -1115,6 +1116,7 @@ xfs_btree_set_refs(
xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF); xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF);
break; break;
case XFS_BTNUM_INO: case XFS_BTNUM_INO:
case XFS_BTNUM_FINO:
xfs_buf_set_ref(bp, XFS_INO_BTREE_REF); xfs_buf_set_ref(bp, XFS_INO_BTREE_REF);
break; break;
case XFS_BTNUM_BMAP: case XFS_BTNUM_BMAP:
......
...@@ -62,6 +62,7 @@ union xfs_btree_rec { ...@@ -62,6 +62,7 @@ union xfs_btree_rec {
#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) #define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi)
#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) #define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi)
#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) #define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi)
#define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi)
/* /*
* For logging record fields. * For logging record fields.
...@@ -92,6 +93,7 @@ do { \ ...@@ -92,6 +93,7 @@ do { \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \ case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \
case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \ } \
} while (0) } while (0)
...@@ -105,6 +107,7 @@ do { \ ...@@ -105,6 +107,7 @@ do { \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \ case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \ } \
} while (0) } while (0)
......
...@@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t; ...@@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t;
*/ */
#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ #define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */
#define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */ #define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */
#define XFS_FIBT_MAGIC 0x46494254 /* 'FIBT' */
#define XFS_FIBT_CRC_MAGIC 0x46494233 /* 'FIB3' */
typedef __uint64_t xfs_inofree_t; typedef __uint64_t xfs_inofree_t;
#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) #define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t))
...@@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t; ...@@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t;
* block numbers in the AG. * block numbers in the AG.
*/ */
#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) #define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1))
#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) #define XFS_FIBT_BLOCK(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
/*
* The first data block of an AG depends on whether the filesystem was formatted
* with the finobt feature. If so, account for the finobt reserved root btree
* block.
*/
#define XFS_PREALLOC_BLOCKS(mp) \
(xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
XFS_FIBT_BLOCK(mp) + 1 : \
XFS_IBT_BLOCK(mp) + 1)
......
...@@ -238,6 +238,7 @@ typedef struct xfs_fsop_resblks { ...@@ -238,6 +238,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ #define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */ #define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */
#define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */ #define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */
#define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */
/* /*
* Minimum and maximum sizes need for growth checks. * Minimum and maximum sizes need for growth checks.
......
...@@ -104,7 +104,9 @@ xfs_fs_geometry( ...@@ -104,7 +104,9 @@ xfs_fs_geometry(
(xfs_sb_version_hascrc(&mp->m_sb) ? (xfs_sb_version_hascrc(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_V5SB : 0) | XFS_FSOP_GEOM_FLAGS_V5SB : 0) |
(xfs_sb_version_hasftype(&mp->m_sb) ? (xfs_sb_version_hasftype(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_FTYPE : 0); XFS_FSOP_GEOM_FLAGS_FTYPE : 0) |
(xfs_sb_version_hasfinobt(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_FINOBT : 0);
geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ? geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
mp->m_sb.sb_logsectsize : BBSIZE; mp->m_sb.sb_logsectsize : BBSIZE;
geo->rtsectsize = mp->m_sb.sb_blocksize; geo->rtsectsize = mp->m_sb.sb_blocksize;
...@@ -316,6 +318,10 @@ xfs_growfs_data_private( ...@@ -316,6 +318,10 @@ xfs_growfs_data_private(
agi->agi_dirino = cpu_to_be32(NULLAGINO); agi->agi_dirino = cpu_to_be32(NULLAGINO);
if (xfs_sb_version_hascrc(&mp->m_sb)) if (xfs_sb_version_hascrc(&mp->m_sb))
uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid); uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
agi->agi_free_level = cpu_to_be32(1);
}
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
...@@ -407,6 +413,34 @@ xfs_growfs_data_private( ...@@ -407,6 +413,34 @@ xfs_growfs_data_private(
xfs_buf_relse(bp); xfs_buf_relse(bp);
if (error) if (error)
goto error0; goto error0;
/*
* FINO btree root block
*/
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
bp = xfs_growfs_get_hdr_buf(mp,
XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
BTOBB(mp->m_sb.sb_blocksize), 0,
&xfs_inobt_buf_ops);
if (!bp) {
error = ENOMEM;
goto error0;
}
if (xfs_sb_version_hascrc(&mp->m_sb))
xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC,
0, 0, agno,
XFS_BTREE_CRC_BLOCKS);
else
xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0,
0, agno, 0);
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
if (error)
goto error0;
}
} }
xfs_trans_agblocks_delta(tp, nfree); xfs_trans_agblocks_delta(tp, nfree);
/* /*
......
This diff is collapsed.
...@@ -49,7 +49,8 @@ xfs_inobt_dup_cursor( ...@@ -49,7 +49,8 @@ xfs_inobt_dup_cursor(
struct xfs_btree_cur *cur) struct xfs_btree_cur *cur)
{ {
return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_private.a.agbp, cur->bc_private.a.agno); cur->bc_private.a.agbp, cur->bc_private.a.agno,
cur->bc_btnum);
} }
STATIC void STATIC void
...@@ -66,6 +67,21 @@ xfs_inobt_set_root( ...@@ -66,6 +67,21 @@ xfs_inobt_set_root(
xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
} }
STATIC void
xfs_finobt_set_root(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *nptr,
int inc) /* level change */
{
struct xfs_buf *agbp = cur->bc_private.a.agbp;
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
agi->agi_free_root = nptr->s;
be32_add_cpu(&agi->agi_free_level, inc);
xfs_ialloc_log_agi(cur->bc_tp, agbp,
XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL);
}
STATIC int STATIC int
xfs_inobt_alloc_block( xfs_inobt_alloc_block(
struct xfs_btree_cur *cur, struct xfs_btree_cur *cur,
...@@ -172,6 +188,17 @@ xfs_inobt_init_ptr_from_cur( ...@@ -172,6 +188,17 @@ xfs_inobt_init_ptr_from_cur(
ptr->s = agi->agi_root; ptr->s = agi->agi_root;
} }
STATIC void
xfs_finobt_init_ptr_from_cur(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *ptr)
{
struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
ptr->s = agi->agi_free_root;
}
STATIC __int64_t STATIC __int64_t
xfs_inobt_key_diff( xfs_inobt_key_diff(
struct xfs_btree_cur *cur, struct xfs_btree_cur *cur,
...@@ -202,6 +229,7 @@ xfs_inobt_verify( ...@@ -202,6 +229,7 @@ xfs_inobt_verify(
*/ */
switch (block->bb_magic) { switch (block->bb_magic) {
case cpu_to_be32(XFS_IBT_CRC_MAGIC): case cpu_to_be32(XFS_IBT_CRC_MAGIC):
case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
if (!xfs_sb_version_hascrc(&mp->m_sb)) if (!xfs_sb_version_hascrc(&mp->m_sb))
return false; return false;
if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid)) if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
...@@ -213,6 +241,7 @@ xfs_inobt_verify( ...@@ -213,6 +241,7 @@ xfs_inobt_verify(
return false; return false;
/* fall through */ /* fall through */
case cpu_to_be32(XFS_IBT_MAGIC): case cpu_to_be32(XFS_IBT_MAGIC):
case cpu_to_be32(XFS_FIBT_MAGIC):
break; break;
default: default:
return 0; return 0;
...@@ -316,6 +345,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = { ...@@ -316,6 +345,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
#endif #endif
}; };
static const struct xfs_btree_ops xfs_finobt_ops = {
.rec_len = sizeof(xfs_inobt_rec_t),
.key_len = sizeof(xfs_inobt_key_t),
.dup_cursor = xfs_inobt_dup_cursor,
.set_root = xfs_finobt_set_root,
.alloc_block = xfs_inobt_alloc_block,
.free_block = xfs_inobt_free_block,
.get_minrecs = xfs_inobt_get_minrecs,
.get_maxrecs = xfs_inobt_get_maxrecs,
.init_key_from_rec = xfs_inobt_init_key_from_rec,
.init_rec_from_key = xfs_inobt_init_rec_from_key,
.init_rec_from_cur = xfs_inobt_init_rec_from_cur,
.init_ptr_from_cur = xfs_finobt_init_ptr_from_cur,
.key_diff = xfs_inobt_key_diff,
.buf_ops = &xfs_inobt_buf_ops,
#if defined(DEBUG) || defined(XFS_WARN)
.keys_inorder = xfs_inobt_keys_inorder,
.recs_inorder = xfs_inobt_recs_inorder,
#endif
};
/* /*
* Allocate a new inode btree cursor. * Allocate a new inode btree cursor.
*/ */
...@@ -324,7 +375,8 @@ xfs_inobt_init_cursor( ...@@ -324,7 +375,8 @@ xfs_inobt_init_cursor(
struct xfs_mount *mp, /* file system mount point */ struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */ struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer for agi structure */ struct xfs_buf *agbp, /* buffer for agi structure */
xfs_agnumber_t agno) /* allocation group number */ xfs_agnumber_t agno, /* allocation group number */
xfs_btnum_t btnum) /* ialloc or free ino btree */
{ {
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
...@@ -333,11 +385,17 @@ xfs_inobt_init_cursor( ...@@ -333,11 +385,17 @@ xfs_inobt_init_cursor(
cur->bc_tp = tp; cur->bc_tp = tp;
cur->bc_mp = mp; cur->bc_mp = mp;
cur->bc_nlevels = be32_to_cpu(agi->agi_level); cur->bc_btnum = btnum;
cur->bc_btnum = XFS_BTNUM_INO; if (btnum == XFS_BTNUM_INO) {
cur->bc_nlevels = be32_to_cpu(agi->agi_level);
cur->bc_ops = &xfs_inobt_ops;
} else {
cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
cur->bc_ops = &xfs_finobt_ops;
}
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ops = &xfs_inobt_ops;
if (xfs_sb_version_hascrc(&mp->m_sb)) if (xfs_sb_version_hascrc(&mp->m_sb))
cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
......
...@@ -58,7 +58,8 @@ struct xfs_mount; ...@@ -58,7 +58,8 @@ struct xfs_mount;
((index) - 1) * sizeof(xfs_inobt_ptr_t))) ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t); struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
xfs_btnum_t);
extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int); extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
#endif /* __XFS_IALLOC_BTREE_H__ */ #endif /* __XFS_IALLOC_BTREE_H__ */
...@@ -1811,9 +1811,33 @@ xfs_inactive_ifree( ...@@ -1811,9 +1811,33 @@ xfs_inactive_ifree(
int error; int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
/*
* The ifree transaction might need to allocate blocks for record
* insertion to the finobt. We don't want to fail here at ENOSPC, so
* allow ifree to dip into the reserved block pool if necessary.
*
* Freeing large sets of inodes generally means freeing inode chunks,
* directory and file data blocks, so this should be relatively safe.
* Only under severe circumstances should it be possible to free enough
* inodes to exhaust the reserve block pool via finobt expansion while
* at the same time not creating free space in the filesystem.
*
* Send a warning if the reservation does happen to fail, as the inode
* now remains allocated and sits on the unlinked list until the fs is
* repaired.
*/
tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
XFS_IFREE_SPACE_RES(mp), 0);
if (error) { if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp)); if (error == ENOSPC) {
xfs_warn_ratelimited(mp,
"Failed to remove inode(s) from unlinked list. "
"Please free space, unmount and run xfs_repair.");
} else {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
}
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
return error; return error;
} }
......
...@@ -270,7 +270,8 @@ xfs_bulkstat( ...@@ -270,7 +270,8 @@ xfs_bulkstat(
/* /*
* Allocate and initialize a btree cursor for ialloc btree. * Allocate and initialize a btree cursor for ialloc btree.
*/ */
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno); cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
XFS_BTNUM_INO);
irbp = irbuf; irbp = irbuf;
irbufend = irbuf + nirbuf; irbufend = irbuf + nirbuf;
end_of_ag = 0; end_of_ag = 0;
...@@ -621,7 +622,8 @@ xfs_inumbers( ...@@ -621,7 +622,8 @@ xfs_inumbers(
agino = 0; agino = 0;
continue; continue;
} }
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno); cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
XFS_BTNUM_INO);
error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
&tmp); &tmp);
if (error) { if (error) {
......
...@@ -2138,7 +2138,9 @@ xlog_recover_validate_buf_type( ...@@ -2138,7 +2138,9 @@ xlog_recover_validate_buf_type(
bp->b_ops = &xfs_allocbt_buf_ops; bp->b_ops = &xfs_allocbt_buf_ops;
break; break;
case XFS_IBT_CRC_MAGIC: case XFS_IBT_CRC_MAGIC:
case XFS_FIBT_CRC_MAGIC:
case XFS_IBT_MAGIC: case XFS_IBT_MAGIC:
case XFS_FIBT_MAGIC:
bp->b_ops = &xfs_inobt_buf_ops; bp->b_ops = &xfs_inobt_buf_ops;
break; break;
case XFS_BMAP_CRC_MAGIC: case XFS_BMAP_CRC_MAGIC:
......
...@@ -587,7 +587,9 @@ xfs_sb_has_compat_feature( ...@@ -587,7 +587,9 @@ xfs_sb_has_compat_feature(
return (sbp->sb_features_compat & feature) != 0; return (sbp->sb_features_compat & feature) != 0;
} }
#define XFS_SB_FEAT_RO_COMPAT_ALL 0 #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
#define XFS_SB_FEAT_RO_COMPAT_ALL \
(XFS_SB_FEAT_RO_COMPAT_FINOBT)
#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
static inline bool static inline bool
xfs_sb_has_ro_compat_feature( xfs_sb_has_ro_compat_feature(
...@@ -641,6 +643,12 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp) ...@@ -641,6 +643,12 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp)
(sbp->sb_features2 & XFS_SB_VERSION2_FTYPE)); (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE));
} }
static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT);
}
/* /*
* end of superblock version macros * end of superblock version macros
*/ */
......
...@@ -59,6 +59,7 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v) ...@@ -59,6 +59,7 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v)
{ "abtc2", XFSSTAT_END_ABTC_V2 }, { "abtc2", XFSSTAT_END_ABTC_V2 },
{ "bmbt2", XFSSTAT_END_BMBT_V2 }, { "bmbt2", XFSSTAT_END_BMBT_V2 },
{ "ibt2", XFSSTAT_END_IBT_V2 }, { "ibt2", XFSSTAT_END_IBT_V2 },
{ "fibt2", XFSSTAT_END_FIBT_V2 },
/* we print both series of quota information together */ /* we print both series of quota information together */
{ "qm", XFSSTAT_END_QM }, { "qm", XFSSTAT_END_QM },
}; };
......
...@@ -183,7 +183,23 @@ struct xfsstats { ...@@ -183,7 +183,23 @@ struct xfsstats {
__uint32_t xs_ibt_2_alloc; __uint32_t xs_ibt_2_alloc;
__uint32_t xs_ibt_2_free; __uint32_t xs_ibt_2_free;
__uint32_t xs_ibt_2_moves; __uint32_t xs_ibt_2_moves;
#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_IBT_V2+6) #define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2+15)
__uint32_t xs_fibt_2_lookup;
__uint32_t xs_fibt_2_compare;
__uint32_t xs_fibt_2_insrec;
__uint32_t xs_fibt_2_delrec;
__uint32_t xs_fibt_2_newroot;
__uint32_t xs_fibt_2_killroot;
__uint32_t xs_fibt_2_increment;
__uint32_t xs_fibt_2_decrement;
__uint32_t xs_fibt_2_lshift;
__uint32_t xs_fibt_2_rshift;
__uint32_t xs_fibt_2_split;
__uint32_t xs_fibt_2_join;
__uint32_t xs_fibt_2_alloc;
__uint32_t xs_fibt_2_free;
__uint32_t xs_fibt_2_moves;
#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_FIBT_V2+6)
__uint32_t xs_qm_dqreclaims; __uint32_t xs_qm_dqreclaims;
__uint32_t xs_qm_dqreclaim_misses; __uint32_t xs_qm_dqreclaim_misses;
__uint32_t xs_qm_dquot_dups; __uint32_t xs_qm_dquot_dups;
......
...@@ -105,6 +105,47 @@ xfs_calc_inode_res( ...@@ -105,6 +105,47 @@ xfs_calc_inode_res(
2 * XFS_BMBT_BLOCK_LEN(mp)); 2 * XFS_BMBT_BLOCK_LEN(mp));
} }
/*
* The free inode btree is a conditional feature and the log reservation
* requirements differ slightly from that of the traditional inode allocation
* btree. The finobt tracks records for inode chunks with at least one free
* inode. A record can be removed from the tree for an inode allocation
* or free and thus the finobt reservation is unconditional across:
*
* - inode allocation
* - inode free
* - inode chunk allocation
*
* The 'modify' param indicates to include the record modification scenario. The
* 'alloc' param indicates to include the reservation for free space btree
* modifications on behalf of finobt modifications. This is required only for
* transactions that do not already account for free space btree modifications.
*
* the free inode btree: max depth * block size
* the allocation btrees: 2 trees * (max depth - 1) * block size
* the free inode btree entry: block size
*/
STATIC uint
xfs_calc_finobt_res(
struct xfs_mount *mp,
int alloc,
int modify)
{
uint res;
if (!xfs_sb_version_hasfinobt(&mp->m_sb))
return 0;
res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
if (alloc)
res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1));
if (modify)
res += (uint)XFS_FSB_TO_B(mp, 1);
return res;
}
/* /*
* Various log reservation values. * Various log reservation values.
* *
...@@ -302,6 +343,7 @@ xfs_calc_remove_reservation( ...@@ -302,6 +343,7 @@ xfs_calc_remove_reservation(
* the superblock for the nlink flag: sector size * the superblock for the nlink flag: sector size
* the directory btree: (max depth + v2) * dir block size * the directory btree: (max depth + v2) * dir block size
* the directory inode's bmap btree: (max depth + v2) * block size * the directory inode's bmap btree: (max depth + v2) * block size
* the finobt (record modification and allocation btrees)
*/ */
STATIC uint STATIC uint
xfs_calc_create_resv_modify( xfs_calc_create_resv_modify(
...@@ -310,7 +352,8 @@ xfs_calc_create_resv_modify( ...@@ -310,7 +352,8 @@ xfs_calc_create_resv_modify(
return xfs_calc_inode_res(mp, 2) + return xfs_calc_inode_res(mp, 2) +
xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
(uint)XFS_FSB_TO_B(mp, 1) + (uint)XFS_FSB_TO_B(mp, 1) +
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 1, 1);
} }
/* /*
...@@ -348,6 +391,7 @@ __xfs_calc_create_reservation( ...@@ -348,6 +391,7 @@ __xfs_calc_create_reservation(
* the superblock for the nlink flag: sector size * the superblock for the nlink flag: sector size
* the inode btree: max depth * blocksize * the inode btree: max depth * blocksize
* the allocation btrees: 2 trees * (max depth - 1) * block size * the allocation btrees: 2 trees * (max depth - 1) * block size
* the finobt (record insertion)
*/ */
STATIC uint STATIC uint
xfs_calc_icreate_resv_alloc( xfs_calc_icreate_resv_alloc(
...@@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc( ...@@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc(
mp->m_sb.sb_sectsize + mp->m_sb.sb_sectsize +
xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1)); XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 0, 0);
} }
STATIC uint STATIC uint
...@@ -425,6 +470,7 @@ xfs_calc_symlink_reservation( ...@@ -425,6 +470,7 @@ xfs_calc_symlink_reservation(
* the on disk inode before ours in the agi hash list: inode cluster size * the on disk inode before ours in the agi hash list: inode cluster size
* the inode btree: max depth * blocksize * the inode btree: max depth * blocksize
* the allocation btrees: 2 trees * (max depth - 1) * block size * the allocation btrees: 2 trees * (max depth - 1) * block size
* the finobt (record insertion, removal or modification)
*/ */
STATIC uint STATIC uint
xfs_calc_ifree_reservation( xfs_calc_ifree_reservation(
...@@ -439,7 +485,8 @@ xfs_calc_ifree_reservation( ...@@ -439,7 +485,8 @@ xfs_calc_ifree_reservation(
xfs_calc_buf_res(2 + mp->m_ialloc_blks + xfs_calc_buf_res(2 + mp->m_ialloc_blks +
mp->m_in_maxlevels, 0) + mp->m_in_maxlevels, 0) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1)); XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 0, 1);
} }
/* /*
......
...@@ -47,7 +47,9 @@ ...@@ -47,7 +47,9 @@
#define XFS_DIRREMOVE_SPACE_RES(mp) \ #define XFS_DIRREMOVE_SPACE_RES(mp) \
XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
#define XFS_IALLOC_SPACE_RES(mp) \ #define XFS_IALLOC_SPACE_RES(mp) \
((mp)->m_ialloc_blks + (mp)->m_in_maxlevels - 1) ((mp)->m_ialloc_blks + \
(xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
((mp)->m_in_maxlevels - 1)))
/* /*
* Space reservation values for various transactions. * Space reservation values for various transactions.
...@@ -82,5 +84,8 @@ ...@@ -82,5 +84,8 @@
(XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ #define XFS_SYMLINK_SPACE_RES(mp,nl,b) \
(XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
#define XFS_IFREE_SPACE_RES(mp) \
(xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
#endif /* __XFS_TRANS_SPACE_H__ */ #endif /* __XFS_TRANS_SPACE_H__ */
...@@ -134,7 +134,7 @@ typedef enum { ...@@ -134,7 +134,7 @@ typedef enum {
typedef enum { typedef enum {
XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
XFS_BTNUM_MAX XFS_BTNUM_FINOi, XFS_BTNUM_MAX
} xfs_btnum_t; } xfs_btnum_t;
struct xfs_name { struct xfs_name {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment