|
@@ -40,6 +40,7 @@
|
|
|
#include "xfs_rtalloc.h"
|
|
|
#include "xfs_error.h"
|
|
|
#include "xfs_bmap.h"
|
|
|
+#include "xfs_imap.h"
|
|
|
|
|
|
|
|
|
/*
|
|
@@ -1196,36 +1197,28 @@ error0:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Return the location of the inode in bno/off, for mapping it into a buffer.
|
|
|
+ * Return the location of the inode in imap, for mapping it into a buffer.
|
|
|
*/
|
|
|
-/*ARGSUSED*/
|
|
|
int
|
|
|
-xfs_dilocate(
|
|
|
- xfs_mount_t *mp, /* file system mount structure */
|
|
|
- xfs_trans_t *tp, /* transaction pointer */
|
|
|
+xfs_imap(
|
|
|
+ xfs_mount_t *mp, /* file system mount structure */
|
|
|
+ xfs_trans_t *tp, /* transaction pointer */
|
|
|
xfs_ino_t ino, /* inode to locate */
|
|
|
- xfs_fsblock_t *bno, /* output: block containing inode */
|
|
|
- int *len, /* output: num blocks in inode cluster */
|
|
|
- int *off, /* output: index in block of inode */
|
|
|
- uint flags) /* flags concerning inode lookup */
|
|
|
+ struct xfs_imap *imap, /* location map structure */
|
|
|
+ uint flags) /* flags for inode btree lookup */
|
|
|
{
|
|
|
xfs_agblock_t agbno; /* block number of inode in the alloc group */
|
|
|
- xfs_buf_t *agbp; /* agi buffer */
|
|
|
xfs_agino_t agino; /* inode number within alloc group */
|
|
|
xfs_agnumber_t agno; /* allocation group number */
|
|
|
int blks_per_cluster; /* num blocks per inode cluster */
|
|
|
xfs_agblock_t chunk_agbno; /* first block in inode chunk */
|
|
|
- xfs_agino_t chunk_agino; /* first agino in inode chunk */
|
|
|
- __int32_t chunk_cnt; /* count of free inodes in chunk */
|
|
|
- xfs_inofree_t chunk_free; /* mask of free inodes in chunk */
|
|
|
xfs_agblock_t cluster_agbno; /* first block in inode cluster */
|
|
|
- xfs_btree_cur_t *cur; /* inode btree cursor */
|
|
|
int error; /* error code */
|
|
|
- int i; /* temp state */
|
|
|
int offset; /* index of inode in its buffer */
|
|
|
int offset_agbno; /* blks from chunk start to inode */
|
|
|
|
|
|
ASSERT(ino != NULLFSINO);
|
|
|
+
|
|
|
/*
|
|
|
* Split up the inode number into its parts.
|
|
|
*/
|
|
@@ -1240,20 +1233,20 @@ xfs_dilocate(
|
|
|
return XFS_ERROR(EINVAL);
|
|
|
if (agno >= mp->m_sb.sb_agcount) {
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
- "xfs_dilocate: agno (%d) >= "
|
|
|
+ "xfs_imap: agno (%d) >= "
|
|
|
"mp->m_sb.sb_agcount (%d)",
|
|
|
agno, mp->m_sb.sb_agcount);
|
|
|
}
|
|
|
if (agbno >= mp->m_sb.sb_agblocks) {
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
- "xfs_dilocate: agbno (0x%llx) >= "
|
|
|
+ "xfs_imap: agbno (0x%llx) >= "
|
|
|
"mp->m_sb.sb_agblocks (0x%lx)",
|
|
|
(unsigned long long) agbno,
|
|
|
(unsigned long) mp->m_sb.sb_agblocks);
|
|
|
}
|
|
|
if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
|
|
|
xfs_fs_cmn_err(CE_ALERT, mp,
|
|
|
- "xfs_dilocate: ino (0x%llx) != "
|
|
|
+ "xfs_imap: ino (0x%llx) != "
|
|
|
"XFS_AGINO_TO_INO(mp, agno, agino) "
|
|
|
"(0x%llx)",
|
|
|
ino, XFS_AGINO_TO_INO(mp, agno, agino));
|
|
@@ -1262,63 +1255,89 @@ xfs_dilocate(
|
|
|
#endif /* DEBUG */
|
|
|
return XFS_ERROR(EINVAL);
|
|
|
}
|
|
|
- if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp))) {
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the inode cluster size is the same as the blocksize or
|
|
|
+ * smaller we get to the buffer by simple arithmetics.
|
|
|
+ */
|
|
|
+ if (XFS_INODE_CLUSTER_SIZE(mp) <= mp->m_sb.sb_blocksize) {
|
|
|
offset = XFS_INO_TO_OFFSET(mp, ino);
|
|
|
ASSERT(offset < mp->m_sb.sb_inopblock);
|
|
|
- *bno = XFS_AGB_TO_FSB(mp, agno, agbno);
|
|
|
- *off = offset;
|
|
|
- *len = 1;
|
|
|
+
|
|
|
+ imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
|
|
|
+ imap->im_len = XFS_FSB_TO_BB(mp, 1);
|
|
|
+ imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
|
|
|
- if (*bno != NULLFSBLOCK) {
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we get a block number passed from bulkstat we can use it to
|
|
|
+ * find the buffer easily.
|
|
|
+ */
|
|
|
+ if (imap->im_blkno) {
|
|
|
offset = XFS_INO_TO_OFFSET(mp, ino);
|
|
|
ASSERT(offset < mp->m_sb.sb_inopblock);
|
|
|
- cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno);
|
|
|
- *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
|
|
|
- offset;
|
|
|
- *len = blks_per_cluster;
|
|
|
+
|
|
|
+ cluster_agbno = XFS_DADDR_TO_AGBNO(mp, imap->im_blkno);
|
|
|
+ offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock;
|
|
|
+
|
|
|
+ imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
|
|
|
+ imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the inode chunks are aligned then use simple maths to
|
|
|
+ * find the location. Otherwise we have to do a btree
|
|
|
+ * lookup to find the location.
|
|
|
+ */
|
|
|
if (mp->m_inoalign_mask) {
|
|
|
offset_agbno = agbno & mp->m_inoalign_mask;
|
|
|
chunk_agbno = agbno - offset_agbno;
|
|
|
} else {
|
|
|
+ xfs_btree_cur_t *cur; /* inode btree cursor */
|
|
|
+ xfs_agino_t chunk_agino; /* first agino in inode chunk */
|
|
|
+ __int32_t chunk_cnt; /* count of free inodes in chunk */
|
|
|
+ xfs_inofree_t chunk_free; /* mask of free inodes in chunk */
|
|
|
+ xfs_buf_t *agbp; /* agi buffer */
|
|
|
+ int i; /* temp state */
|
|
|
+
|
|
|
down_read(&mp->m_peraglock);
|
|
|
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
|
|
|
up_read(&mp->m_peraglock);
|
|
|
if (error) {
|
|
|
-#ifdef DEBUG
|
|
|
- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
|
|
|
+ xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
|
|
"xfs_ialloc_read_agi() returned "
|
|
|
"error %d, agno %d",
|
|
|
error, agno);
|
|
|
-#endif /* DEBUG */
|
|
|
return error;
|
|
|
}
|
|
|
+
|
|
|
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
|
|
|
- if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) {
|
|
|
-#ifdef DEBUG
|
|
|
- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
|
|
|
+ error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i);
|
|
|
+ if (error) {
|
|
|
+ xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
|
|
"xfs_inobt_lookup_le() failed");
|
|
|
-#endif /* DEBUG */
|
|
|
goto error0;
|
|
|
}
|
|
|
- if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt,
|
|
|
- &chunk_free, &i))) {
|
|
|
-#ifdef DEBUG
|
|
|
- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
|
|
|
+
|
|
|
+ error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt,
|
|
|
+ &chunk_free, &i);
|
|
|
+ if (error) {
|
|
|
+ xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
|
|
"xfs_inobt_get_rec() failed");
|
|
|
-#endif /* DEBUG */
|
|
|
goto error0;
|
|
|
}
|
|
|
if (i == 0) {
|
|
|
#ifdef DEBUG
|
|
|
- xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
|
|
|
+ xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
|
|
"xfs_inobt_get_rec() failed");
|
|
|
#endif /* DEBUG */
|
|
|
error = XFS_ERROR(EINVAL);
|
|
|
}
|
|
|
+ error0:
|
|
|
xfs_trans_brelse(tp, agbp);
|
|
|
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
|
|
|
if (error)
|
|
@@ -1326,19 +1345,35 @@ xfs_dilocate(
|
|
|
chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino);
|
|
|
offset_agbno = agbno - chunk_agbno;
|
|
|
}
|
|
|
+
|
|
|
ASSERT(agbno >= chunk_agbno);
|
|
|
cluster_agbno = chunk_agbno +
|
|
|
((offset_agbno / blks_per_cluster) * blks_per_cluster);
|
|
|
offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
|
|
|
XFS_INO_TO_OFFSET(mp, ino);
|
|
|
- *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno);
|
|
|
- *off = offset;
|
|
|
- *len = blks_per_cluster;
|
|
|
+
|
|
|
+ imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
|
|
|
+ imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
|
|
|
+ imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the inode number maps to a block outside the bounds
|
|
|
+ * of the file system then return NULL rather than calling
|
|
|
+ * read_buf and panicing when we get an error from the
|
|
|
+ * driver.
|
|
|
+ */
|
|
|
+ if ((imap->im_blkno + imap->im_len) >
|
|
|
+ XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
|
|
|
+ xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
|
|
|
+ "(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > "
|
|
|
+ " XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)",
|
|
|
+ (unsigned long long) imap->im_blkno,
|
|
|
+ (unsigned long long) imap->im_len,
|
|
|
+ XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
|
|
|
+ return XFS_ERROR(EINVAL);
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
-error0:
|
|
|
- xfs_trans_brelse(tp, agbp);
|
|
|
- xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
|
|
|
- return error;
|
|
|
}
|
|
|
|
|
|
/*
|