Commit 4ae29b43 authored by David Chinner's avatar David Chinner Committed by Lachlan McIlroy

[XFS] Factor xfs_itobp() and xfs_inotobp().

The only difference between the functions is one passes an inode for the
lookup, the other passes an inode number. However, they don't do the same
validity checking or set all the same state on the buffer that is returned
yet they should.

Factor the functions into a common implementation.

SGI-PV: 970925
SGI-Modid: xfs-linux-melb:xfs-kern:30500a
Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarLachlan McIlroy <lachlan@sgi.com>
parent e9a56b7c
...@@ -125,6 +125,85 @@ xfs_inobp_check( ...@@ -125,6 +125,85 @@ xfs_inobp_check(
} }
#endif #endif
/*
* Find the buffer associated with the given inode map
* We do basic validation checks on the buffer once it has been
* retrieved from disk.
*/
STATIC int
xfs_imap_to_bp(
xfs_mount_t *mp,
xfs_trans_t *tp,
xfs_imap_t *imap,
xfs_buf_t **bpp,
uint buf_flags,
uint imap_flags)
{
int error;
int i;
int ni;
xfs_buf_t *bp;
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
(int)imap->im_len, XFS_BUF_LOCK, &bp);
if (error) {
cmn_err(CE_WARN, "xfs_imap_to_bp: xfs_trans_read_buf()returned "
"an error %d on %s. Returning error.",
error, mp->m_fsname);
return error;
}
/*
* Validate the magic number and version of every inode in the buffer
* (if DEBUG kernel) or the first inode in the buffer, otherwise.
*/
#ifdef DEBUG
ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog;
#else /* usual case */
ni = 1;
#endif
for (i = 0; i < ni; i++) {
int di_ok;
xfs_dinode_t *dip;
dip = (xfs_dinode_t *)xfs_buf_offset(bp,
(i << mp->m_sb.sb_inodelog));
di_ok = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
XFS_ERRTAG_ITOBP_INOTOBP,
XFS_RANDOM_ITOBP_INOTOBP))) {
if (imap_flags & XFS_IMAP_BULKSTAT) {
xfs_trans_brelse(tp, bp);
return XFS_ERROR(EINVAL);
}
XFS_CORRUPTION_ERROR("xfs_imap_to_bp",
XFS_ERRLEVEL_HIGH, mp, dip);
#ifdef DEBUG
cmn_err(CE_PANIC,
"Device %s - bad inode magic/vsn "
"daddr %lld #%d (magic=%x)",
XFS_BUFTARG_NAME(mp->m_ddev_targp),
(unsigned long long)imap->im_blkno, i,
be16_to_cpu(dip->di_core.di_magic));
#endif
xfs_trans_brelse(tp, bp);
return XFS_ERROR(EFSCORRUPTED);
}
}
xfs_inobp_check(mp, bp);
/*
* Mark the buffer as an inode buffer now that it looks good
*/
XFS_BUF_SET_VTYPE(bp, B_FS_INO);
*bpp = bp;
return 0;
}
/* /*
* This routine is called to map an inode number within a file * This routine is called to map an inode number within a file
* system to the buffer containing the on-disk version of the * system to the buffer containing the on-disk version of the
...@@ -147,72 +226,19 @@ xfs_inotobp( ...@@ -147,72 +226,19 @@ xfs_inotobp(
xfs_buf_t **bpp, xfs_buf_t **bpp,
int *offset) int *offset)
{ {
int di_ok;
xfs_imap_t imap; xfs_imap_t imap;
xfs_buf_t *bp; xfs_buf_t *bp;
int error; int error;
xfs_dinode_t *dip;
/*
* Call the space management code to find the location of the
* inode on disk.
*/
imap.im_blkno = 0; imap.im_blkno = 0;
error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP); error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP);
if (error != 0) { if (error)
cmn_err(CE_WARN,
"xfs_inotobp: xfs_imap() returned an "
"error %d on %s. Returning error.", error, mp->m_fsname);
return error; return error;
}
/*
* 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)) {
cmn_err(CE_WARN,
"xfs_inotobp: inode number (%llu + %d) maps to a block outside the bounds "
"of the file system %s. Returning EINVAL.",
(unsigned long long)imap.im_blkno,
imap.im_len, mp->m_fsname);
return XFS_ERROR(EINVAL);
}
/*
* Read in the buffer. If tp is NULL, xfs_trans_read_buf() will
* default to just a read_buf() call.
*/
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,
(int)imap.im_len, XFS_BUF_LOCK, &bp);
if (error) { error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, 0);
cmn_err(CE_WARN, if (error)
"xfs_inotobp: xfs_trans_read_buf() returned an "
"error %d on %s. Returning error.", error, mp->m_fsname);
return error; return error;
}
dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0);
di_ok =
be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP,
XFS_RANDOM_ITOBP_INOTOBP))) {
XFS_CORRUPTION_ERROR("xfs_inotobp", XFS_ERRLEVEL_LOW, mp, dip);
xfs_trans_brelse(tp, bp);
cmn_err(CE_WARN,
"xfs_inotobp: XFS_TEST_ERROR() returned an "
"error on %s. Returning EFSCORRUPTED.", mp->m_fsname);
return XFS_ERROR(EFSCORRUPTED);
}
xfs_inobp_check(mp, bp);
/*
* Set *dipp to point to the on-disk inode in the buffer.
*/
*dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
*bpp = bp; *bpp = bp;
*offset = imap.im_boffset; *offset = imap.im_boffset;
...@@ -253,40 +279,14 @@ xfs_itobp( ...@@ -253,40 +279,14 @@ xfs_itobp(
xfs_imap_t imap; xfs_imap_t imap;
xfs_buf_t *bp; xfs_buf_t *bp;
int error; int error;
int i;
int ni;
if (ip->i_blkno == (xfs_daddr_t)0) { if (ip->i_blkno == (xfs_daddr_t)0) {
/*
* Call the space management code to find the location of the
* inode on disk.
*/
imap.im_blkno = bno; imap.im_blkno = bno;
if ((error = xfs_imap(mp, tp, ip->i_ino, &imap, error = xfs_imap(mp, tp, ip->i_ino, &imap,
XFS_IMAP_LOOKUP | imap_flags))) XFS_IMAP_LOOKUP | imap_flags);
if (error)
return error; return error;
/*
* 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)) {
#ifdef DEBUG
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "
"(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));
#endif /* DEBUG */
return XFS_ERROR(EINVAL);
}
/* /*
* Fill in the fields in the inode that will be used to * Fill in the fields in the inode that will be used to
* map the inode to its buffer from now on. * map the inode to its buffer from now on.
...@@ -305,76 +305,10 @@ xfs_itobp( ...@@ -305,76 +305,10 @@ xfs_itobp(
} }
ASSERT(bno == 0 || bno == imap.im_blkno); ASSERT(bno == 0 || bno == imap.im_blkno);
/* error = xfs_imap_to_bp(mp, tp, &imap, &bp, XFS_BUF_LOCK, imap_flags);
* Read in the buffer. If tp is NULL, xfs_trans_read_buf() will if (error)
* default to just a read_buf() call.
*/
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno,
(int)imap.im_len, XFS_BUF_LOCK, &bp);
if (error) {
#ifdef DEBUG
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: "
"xfs_trans_read_buf() returned error %d, "
"imap.im_blkno 0x%llx, imap.im_len 0x%llx",
error, (unsigned long long) imap.im_blkno,
(unsigned long long) imap.im_len);
#endif /* DEBUG */
return error; return error;
}
/*
* Validate the magic number and version of every inode in the buffer
* (if DEBUG kernel) or the first inode in the buffer, otherwise.
* No validation is done here in userspace (xfs_repair).
*/
#if !defined(__KERNEL__)
ni = 0;
#elif defined(DEBUG)
ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog;
#else /* usual case */
ni = 1;
#endif
for (i = 0; i < ni; i++) {
int di_ok;
xfs_dinode_t *dip;
dip = (xfs_dinode_t *)xfs_buf_offset(bp,
(i << mp->m_sb.sb_inodelog));
di_ok = be16_to_cpu(dip->di_core.di_magic) == XFS_DINODE_MAGIC &&
XFS_DINODE_GOOD_VERSION(dip->di_core.di_version);
if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
XFS_ERRTAG_ITOBP_INOTOBP,
XFS_RANDOM_ITOBP_INOTOBP))) {
if (imap_flags & XFS_IMAP_BULKSTAT) {
xfs_trans_brelse(tp, bp);
return XFS_ERROR(EINVAL);
}
#ifdef DEBUG
cmn_err(CE_ALERT,
"Device %s - bad inode magic/vsn "
"daddr %lld #%d (magic=%x)",
XFS_BUFTARG_NAME(mp->m_ddev_targp),
(unsigned long long)imap.im_blkno, i,
be16_to_cpu(dip->di_core.di_magic));
#endif
XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH,
mp, dip);
xfs_trans_brelse(tp, bp);
return XFS_ERROR(EFSCORRUPTED);
}
}
xfs_inobp_check(mp, bp);
/*
* Mark the buffer as an inode buffer now that it looks good
*/
XFS_BUF_SET_VTYPE(bp, B_FS_INO);
/*
* Set *dipp to point to the on-disk inode in the buffer.
*/
*dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset);
*bpp = bp; *bpp = bp;
return 0; return 0;
...@@ -2678,14 +2612,31 @@ xfs_imap( ...@@ -2678,14 +2612,31 @@ xfs_imap(
fsbno = imap->im_blkno ? fsbno = imap->im_blkno ?
XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK; XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK;
error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags); error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags);
if (error != 0) { if (error)
return error; return error;
}
imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno); imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno);
imap->im_len = XFS_FSB_TO_BB(mp, len); imap->im_len = XFS_FSB_TO_BB(mp, len);
imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno); imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno);
imap->im_ioffset = (ushort)off; imap->im_ioffset = (ushort)off;
imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog); imap->im_boffset = (ushort)(off << 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 EINVAL;
}
return 0; return 0;
} }
......
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