Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 200781
b: refs/heads/master
c: 7124fe0
h: refs/heads/master
i:
  200779: 0c004ac
v: v3
  • Loading branch information
Dave Chinner authored and Dave Chinner committed Jun 24, 2010
1 parent feeb3a8 commit a600de6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 44 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7dce11dbac54fce777eea0f5fb25b2694ccd7900
refs/heads/master: 7124fe0a5b619d65b739477b3b55a20bf805b06d
121 changes: 78 additions & 43 deletions trunk/fs/xfs/xfs_ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,63 @@ xfs_difree(
return error;
}

STATIC int
xfs_imap_lookup(
struct xfs_mount *mp,
struct xfs_trans *tp,
xfs_agnumber_t agno,
xfs_agino_t agino,
xfs_agblock_t agbno,
xfs_agblock_t *chunk_agbno,
xfs_agblock_t *offset_agbno,
int flags)
{
struct xfs_inobt_rec_incore rec;
struct xfs_btree_cur *cur;
struct xfs_buf *agbp;
xfs_agino_t startino;
int error;
int i;

error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_ialloc_read_agi() returned "
"error %d, agno %d",
error, agno);
return error;
}

/*
* derive and lookup the exact inode record for the given agino. If the
* record cannot be found, then it's an invalid inode number and we
* should abort.
*/
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
startino = agino & ~(XFS_IALLOC_INODES(mp) - 1);
error = xfs_inobt_lookup(cur, startino, XFS_LOOKUP_EQ, &i);
if (!error) {
if (i)
error = xfs_inobt_get_rec(cur, &rec, &i);
if (!error && i == 0)
error = EINVAL;
}

xfs_trans_brelse(tp, agbp);
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
if (error)
return error;

/* for untrusted inodes check it is allocated first */
if ((flags & XFS_IGET_BULKSTAT) &&
(rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino)))
return EINVAL;

*chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino);
*offset_agbno = agbno - *chunk_agbno;
return 0;
}

/*
* Return the location of the inode in imap, for mapping it into a buffer.
*/
Expand Down Expand Up @@ -1263,6 +1320,23 @@ xfs_imap(
return XFS_ERROR(EINVAL);
}

blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;

/*
* For bulkstat and handle lookups, we have an untrusted inode number
* that we have to verify is valid. We cannot do this just by reading
* the inode buffer as it may have been unlinked and removed leaving
* inodes in stale state on disk. Hence we have to do a btree lookup
* in all cases where an untrusted inode number is passed.
*/
if (flags & XFS_IGET_BULKSTAT) {
error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
&chunk_agbno, &offset_agbno, flags);
if (error)
return error;
goto out_map;
}

/*
* If the inode cluster size is the same as the blocksize or
* smaller we get to the buffer by simple arithmetics.
Expand All @@ -1277,10 +1351,8 @@ xfs_imap(
return 0;
}

blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;

/*
* If we get a block number passed from bulkstat we can use it to
* If we get a block number passed we can use it to
* find the buffer easily.
*/
if (imap->im_blkno) {
Expand All @@ -1304,50 +1376,13 @@ xfs_imap(
offset_agbno = agbno & mp->m_inoalign_mask;
chunk_agbno = agbno - offset_agbno;
} else {
xfs_btree_cur_t *cur; /* inode btree cursor */
xfs_inobt_rec_incore_t chunk_rec;
xfs_buf_t *agbp; /* agi buffer */
int i; /* temp state */

error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_ialloc_read_agi() returned "
"error %d, agno %d",
error, agno);
return error;
}

cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_inobt_lookup() failed");
goto error0;
}

error = xfs_inobt_get_rec(cur, &chunk_rec, &i);
if (error) {
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
"xfs_inobt_get_rec() failed");
goto error0;
}
if (i == 0) {
#ifdef DEBUG
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);
error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
&chunk_agbno, &offset_agbno, flags);
if (error)
return error;
chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_rec.ir_startino);
offset_agbno = agbno - chunk_agbno;
}

out_map:
ASSERT(agbno >= chunk_agbno);
cluster_agbno = chunk_agbno +
((offset_agbno / blks_per_cluster) * blks_per_cluster);
Expand Down

0 comments on commit a600de6

Please sign in to comment.