|
@@ -152,6 +152,87 @@ xfs_inobt_get_rec(
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Initialise a new set of inodes.
|
|
|
+ */
|
|
|
+STATIC void
|
|
|
+xfs_ialloc_inode_init(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ struct xfs_trans *tp,
|
|
|
+ xfs_agnumber_t agno,
|
|
|
+ xfs_agblock_t agbno,
|
|
|
+ xfs_agblock_t length,
|
|
|
+ unsigned int gen)
|
|
|
+{
|
|
|
+ struct xfs_buf *fbuf;
|
|
|
+ struct xfs_dinode *free;
|
|
|
+ int blks_per_cluster, nbufs, ninodes;
|
|
|
+ int version;
|
|
|
+ int i, j;
|
|
|
+ xfs_daddr_t d;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Loop over the new block(s), filling in the inodes.
|
|
|
+ * For small block sizes, manipulate the inodes in buffers
|
|
|
+ * which are multiples of the blocks size.
|
|
|
+ */
|
|
|
+ if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) {
|
|
|
+ blks_per_cluster = 1;
|
|
|
+ nbufs = length;
|
|
|
+ ninodes = mp->m_sb.sb_inopblock;
|
|
|
+ } else {
|
|
|
+ blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) /
|
|
|
+ mp->m_sb.sb_blocksize;
|
|
|
+ nbufs = length / blks_per_cluster;
|
|
|
+ ninodes = blks_per_cluster * mp->m_sb.sb_inopblock;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Figure out what version number to use in the inodes we create.
|
|
|
+ * If the superblock version has caught up to the one that supports
|
|
|
+ * the new inode format, then use the new inode version. Otherwise
|
|
|
+ * use the old version so that old kernels will continue to be
|
|
|
+ * able to use the file system.
|
|
|
+ */
|
|
|
+ if (xfs_sb_version_hasnlink(&mp->m_sb))
|
|
|
+ version = 2;
|
|
|
+ else
|
|
|
+ version = 1;
|
|
|
+
|
|
|
+ for (j = 0; j < nbufs; j++) {
|
|
|
+ /*
|
|
|
+ * Get the block.
|
|
|
+ */
|
|
|
+ d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster));
|
|
|
+ fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
|
|
|
+ mp->m_bsize * blks_per_cluster,
|
|
|
+ XFS_BUF_LOCK);
|
|
|
+ ASSERT(fbuf);
|
|
|
+ ASSERT(!XFS_BUF_GETERROR(fbuf));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Initialize all inodes in this buffer and then log them.
|
|
|
+ *
|
|
|
+ * XXX: It would be much better if we had just one transaction
|
|
|
+ * to log a whole cluster of inodes instead of all the
|
|
|
+ * individual transactions causing a lot of log traffic.
|
|
|
+ */
|
|
|
+ xfs_biozero(fbuf, 0, ninodes << mp->m_sb.sb_inodelog);
|
|
|
+ for (i = 0; i < ninodes; i++) {
|
|
|
+ int ioffset = i << mp->m_sb.sb_inodelog;
|
|
|
+ uint isize = sizeof(struct xfs_dinode);
|
|
|
+
|
|
|
+ free = xfs_make_iptr(mp, fbuf, i);
|
|
|
+ free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
|
|
|
+ free->di_version = version;
|
|
|
+ free->di_gen = cpu_to_be32(gen);
|
|
|
+ free->di_next_unlinked = cpu_to_be32(NULLAGINO);
|
|
|
+ xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1);
|
|
|
+ }
|
|
|
+ xfs_trans_inode_alloc_buf(tp, fbuf);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Allocate new inodes in the allocation group specified by agbp.
|
|
|
* Return 0 for success, else error code.
|
|
@@ -164,24 +245,15 @@ xfs_ialloc_ag_alloc(
|
|
|
{
|
|
|
xfs_agi_t *agi; /* allocation group header */
|
|
|
xfs_alloc_arg_t args; /* allocation argument structure */
|
|
|
- int blks_per_cluster; /* fs blocks per inode cluster */
|
|
|
xfs_btree_cur_t *cur; /* inode btree cursor */
|
|
|
- xfs_daddr_t d; /* disk addr of buffer */
|
|
|
xfs_agnumber_t agno;
|
|
|
int error;
|
|
|
- xfs_buf_t *fbuf; /* new free inodes' buffer */
|
|
|
- xfs_dinode_t *free; /* new free inode structure */
|
|
|
- int i; /* inode counter */
|
|
|
- int j; /* block counter */
|
|
|
- int nbufs; /* num bufs of new inodes */
|
|
|
+ int i;
|
|
|
xfs_agino_t newino; /* new first inode's number */
|
|
|
xfs_agino_t newlen; /* new number of inodes */
|
|
|
- int ninodes; /* num inodes per buf */
|
|
|
xfs_agino_t thisino; /* current inode number, for loop */
|
|
|
- int version; /* inode version number to use */
|
|
|
int isaligned = 0; /* inode allocation at stripe unit */
|
|
|
/* boundary */
|
|
|
- unsigned int gen;
|
|
|
|
|
|
args.tp = tp;
|
|
|
args.mp = tp->t_mountp;
|
|
@@ -202,12 +274,12 @@ xfs_ialloc_ag_alloc(
|
|
|
*/
|
|
|
agi = XFS_BUF_TO_AGI(agbp);
|
|
|
newino = be32_to_cpu(agi->agi_newino);
|
|
|
+ agno = be32_to_cpu(agi->agi_seqno);
|
|
|
args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
|
|
|
XFS_IALLOC_BLOCKS(args.mp);
|
|
|
if (likely(newino != NULLAGINO &&
|
|
|
(args.agbno < be32_to_cpu(agi->agi_length)))) {
|
|
|
- args.fsbno = XFS_AGB_TO_FSB(args.mp,
|
|
|
- be32_to_cpu(agi->agi_seqno), args.agbno);
|
|
|
+ args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
|
|
|
args.type = XFS_ALLOCTYPE_THIS_BNO;
|
|
|
args.mod = args.total = args.wasdel = args.isfl =
|
|
|
args.userdata = args.minalignslop = 0;
|
|
@@ -258,8 +330,7 @@ xfs_ialloc_ag_alloc(
|
|
|
* For now, just allocate blocks up front.
|
|
|
*/
|
|
|
args.agbno = be32_to_cpu(agi->agi_root);
|
|
|
- args.fsbno = XFS_AGB_TO_FSB(args.mp,
|
|
|
- be32_to_cpu(agi->agi_seqno), args.agbno);
|
|
|
+ args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
|
|
|
/*
|
|
|
* Allocate a fixed-size extent of inodes.
|
|
|
*/
|
|
@@ -282,8 +353,7 @@ xfs_ialloc_ag_alloc(
|
|
|
if (isaligned && args.fsbno == NULLFSBLOCK) {
|
|
|
args.type = XFS_ALLOCTYPE_NEAR_BNO;
|
|
|
args.agbno = be32_to_cpu(agi->agi_root);
|
|
|
- args.fsbno = XFS_AGB_TO_FSB(args.mp,
|
|
|
- be32_to_cpu(agi->agi_seqno), args.agbno);
|
|
|
+ args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno);
|
|
|
args.alignment = xfs_ialloc_cluster_alignment(&args);
|
|
|
if ((error = xfs_alloc_vextent(&args)))
|
|
|
return error;
|
|
@@ -294,85 +364,30 @@ xfs_ialloc_ag_alloc(
|
|
|
return 0;
|
|
|
}
|
|
|
ASSERT(args.len == args.minlen);
|
|
|
- /*
|
|
|
- * Convert the results.
|
|
|
- */
|
|
|
- newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0);
|
|
|
- /*
|
|
|
- * Loop over the new block(s), filling in the inodes.
|
|
|
- * For small block sizes, manipulate the inodes in buffers
|
|
|
- * which are multiples of the blocks size.
|
|
|
- */
|
|
|
- if (args.mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(args.mp)) {
|
|
|
- blks_per_cluster = 1;
|
|
|
- nbufs = (int)args.len;
|
|
|
- ninodes = args.mp->m_sb.sb_inopblock;
|
|
|
- } else {
|
|
|
- blks_per_cluster = XFS_INODE_CLUSTER_SIZE(args.mp) /
|
|
|
- args.mp->m_sb.sb_blocksize;
|
|
|
- nbufs = (int)args.len / blks_per_cluster;
|
|
|
- ninodes = blks_per_cluster * args.mp->m_sb.sb_inopblock;
|
|
|
- }
|
|
|
- /*
|
|
|
- * Figure out what version number to use in the inodes we create.
|
|
|
- * If the superblock version has caught up to the one that supports
|
|
|
- * the new inode format, then use the new inode version. Otherwise
|
|
|
- * use the old version so that old kernels will continue to be
|
|
|
- * able to use the file system.
|
|
|
- */
|
|
|
- if (xfs_sb_version_hasnlink(&args.mp->m_sb))
|
|
|
- version = 2;
|
|
|
- else
|
|
|
- version = 1;
|
|
|
|
|
|
/*
|
|
|
+ * Stamp and write the inode buffers.
|
|
|
+ *
|
|
|
* Seed the new inode cluster with a random generation number. This
|
|
|
* prevents short-term reuse of generation numbers if a chunk is
|
|
|
* freed and then immediately reallocated. We use random numbers
|
|
|
* rather than a linear progression to prevent the next generation
|
|
|
* number from being easily guessable.
|
|
|
*/
|
|
|
- gen = random32();
|
|
|
- for (j = 0; j < nbufs; j++) {
|
|
|
- /*
|
|
|
- * Get the block.
|
|
|
- */
|
|
|
- d = XFS_AGB_TO_DADDR(args.mp, be32_to_cpu(agi->agi_seqno),
|
|
|
- args.agbno + (j * blks_per_cluster));
|
|
|
- fbuf = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, d,
|
|
|
- args.mp->m_bsize * blks_per_cluster,
|
|
|
- XFS_BUF_LOCK);
|
|
|
- ASSERT(fbuf);
|
|
|
- ASSERT(!XFS_BUF_GETERROR(fbuf));
|
|
|
+ xfs_ialloc_inode_init(args.mp, tp, agno, args.agbno, args.len,
|
|
|
+ random32());
|
|
|
|
|
|
- /*
|
|
|
- * Initialize all inodes in this buffer and then log them.
|
|
|
- *
|
|
|
- * XXX: It would be much better if we had just one transaction to
|
|
|
- * log a whole cluster of inodes instead of all the individual
|
|
|
- * transactions causing a lot of log traffic.
|
|
|
- */
|
|
|
- xfs_biozero(fbuf, 0, ninodes << args.mp->m_sb.sb_inodelog);
|
|
|
- for (i = 0; i < ninodes; i++) {
|
|
|
- int ioffset = i << args.mp->m_sb.sb_inodelog;
|
|
|
- uint isize = sizeof(struct xfs_dinode);
|
|
|
-
|
|
|
- free = xfs_make_iptr(args.mp, fbuf, i);
|
|
|
- free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
|
|
|
- free->di_version = version;
|
|
|
- free->di_gen = cpu_to_be32(gen);
|
|
|
- free->di_next_unlinked = cpu_to_be32(NULLAGINO);
|
|
|
- xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1);
|
|
|
- }
|
|
|
- xfs_trans_inode_alloc_buf(tp, fbuf);
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Convert the results.
|
|
|
+ */
|
|
|
+ newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0);
|
|
|
be32_add_cpu(&agi->agi_count, newlen);
|
|
|
be32_add_cpu(&agi->agi_freecount, newlen);
|
|
|
- agno = be32_to_cpu(agi->agi_seqno);
|
|
|
down_read(&args.mp->m_peraglock);
|
|
|
args.mp->m_perag[agno].pagi_freecount += newlen;
|
|
|
up_read(&args.mp->m_peraglock);
|
|
|
agi->agi_newino = cpu_to_be32(newino);
|
|
|
+
|
|
|
/*
|
|
|
* Insert records describing the new inode chunk into the btree.
|
|
|
*/
|