aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-03-23 13:06:52 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-03-23 21:05:07 -0400
commit30b0984d9117dd14c895265886d34335856b712b (patch)
treec83233ce6ee62c7675651091c584b8d40bf2d27e
parent6915ef35c0350e87a104cb4c4ab2121c81ca7a34 (diff)
xfs: refactor bmap record validation
Refactor the bmap validator into a more complete helper that looks for extents that run off the end of the device, overflow into the next AG, or have invalid flag states. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c46
-rw-r--r--fs/xfs/libxfs/xfs_bmap.h3
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.h14
-rw-r--r--fs/xfs/libxfs/xfs_inode_fork.c12
4 files changed, 54 insertions, 21 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index daae00ed30c5..91214f21563c 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -1261,11 +1261,15 @@ xfs_iread_extents(
1261 */ 1261 */
1262 frp = XFS_BMBT_REC_ADDR(mp, block, 1); 1262 frp = XFS_BMBT_REC_ADDR(mp, block, 1);
1263 for (j = 0; j < num_recs; j++, frp++, i++) { 1263 for (j = 0; j < num_recs; j++, frp++, i++) {
1264 xfs_failaddr_t fa;
1265
1264 xfs_bmbt_disk_get_all(frp, &new); 1266 xfs_bmbt_disk_get_all(frp, &new);
1265 if (!xfs_bmbt_validate_extent(mp, whichfork, &new)) { 1267 fa = xfs_bmap_validate_extent(ip, whichfork, &new);
1266 XFS_ERROR_REPORT("xfs_bmap_read_extents(2)", 1268 if (fa) {
1267 XFS_ERRLEVEL_LOW, mp);
1268 error = -EFSCORRUPTED; 1269 error = -EFSCORRUPTED;
1270 xfs_inode_verifier_error(ip, error,
1271 "xfs_iread_extents(2)",
1272 frp, sizeof(*frp), fa);
1269 goto out_brelse; 1273 goto out_brelse;
1270 } 1274 }
1271 xfs_iext_insert(ip, &icur, &new, state); 1275 xfs_iext_insert(ip, &icur, &new, state);
@@ -6154,3 +6158,39 @@ xfs_bmap_finish_one(
6154 6158
6155 return error; 6159 return error;
6156} 6160}
6161
6162/* Check that an inode's extent does not have invalid flags or bad ranges. */
6163xfs_failaddr_t
6164xfs_bmap_validate_extent(
6165 struct xfs_inode *ip,
6166 int whichfork,
6167 struct xfs_bmbt_irec *irec)
6168{
6169 struct xfs_mount *mp = ip->i_mount;
6170 xfs_fsblock_t endfsb;
6171 bool isrt;
6172
6173 isrt = XFS_IS_REALTIME_INODE(ip);
6174 endfsb = irec->br_startblock + irec->br_blockcount - 1;
6175 if (isrt) {
6176 if (!xfs_verify_rtbno(mp, irec->br_startblock))
6177 return __this_address;
6178 if (!xfs_verify_rtbno(mp, endfsb))
6179 return __this_address;
6180 } else {
6181 if (!xfs_verify_fsbno(mp, irec->br_startblock))
6182 return __this_address;
6183 if (!xfs_verify_fsbno(mp, endfsb))
6184 return __this_address;
6185 if (XFS_FSB_TO_AGNO(mp, irec->br_startblock) !=
6186 XFS_FSB_TO_AGNO(mp, endfsb))
6187 return __this_address;
6188 }
6189 if (irec->br_state != XFS_EXT_NORM) {
6190 if (whichfork != XFS_DATA_FORK)
6191 return __this_address;
6192 if (!xfs_sb_version_hasextflgbit(&mp->m_sb))
6193 return __this_address;
6194 }
6195 return NULL;
6196}
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index e36d75799cd5..f3be6416260b 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -274,4 +274,7 @@ static inline int xfs_bmap_fork_to_state(int whichfork)
274 } 274 }
275} 275}
276 276
277xfs_failaddr_t xfs_bmap_validate_extent(struct xfs_inode *ip, int whichfork,
278 struct xfs_bmbt_irec *irec);
279
277#endif /* __XFS_BMAP_H__ */ 280#endif /* __XFS_BMAP_H__ */
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h
index 135b8c56d23e..e4505746ccaa 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.h
+++ b/fs/xfs/libxfs/xfs_bmap_btree.h
@@ -118,18 +118,4 @@ extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
118extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, 118extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
119 struct xfs_trans *, struct xfs_inode *, int); 119 struct xfs_trans *, struct xfs_inode *, int);
120 120
121/*
122 * Check that the extent does not contain an invalid unwritten extent flag.
123 */
124static inline bool xfs_bmbt_validate_extent(struct xfs_mount *mp, int whichfork,
125 struct xfs_bmbt_irec *irec)
126{
127 if (irec->br_state == XFS_EXT_NORM)
128 return true;
129 if (whichfork == XFS_DATA_FORK &&
130 xfs_sb_version_hasextflgbit(&mp->m_sb))
131 return true;
132 return false;
133}
134
135#endif /* __XFS_BMAP_BTREE_H__ */ 121#endif /* __XFS_BMAP_BTREE_H__ */
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 866d2861c625..613fba22ae4e 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -245,10 +245,14 @@ xfs_iformat_extents(
245 245
246 xfs_iext_first(ifp, &icur); 246 xfs_iext_first(ifp, &icur);
247 for (i = 0; i < nex; i++, dp++) { 247 for (i = 0; i < nex; i++, dp++) {
248 xfs_failaddr_t fa;
249
248 xfs_bmbt_disk_get_all(dp, &new); 250 xfs_bmbt_disk_get_all(dp, &new);
249 if (!xfs_bmbt_validate_extent(mp, whichfork, &new)) { 251 fa = xfs_bmap_validate_extent(ip, whichfork, &new);
250 XFS_ERROR_REPORT("xfs_iformat_extents(2)", 252 if (fa) {
251 XFS_ERRLEVEL_LOW, mp); 253 xfs_inode_verifier_error(ip, -EFSCORRUPTED,
254 "xfs_iformat_extents(2)",
255 dp, sizeof(*dp), fa);
252 return -EFSCORRUPTED; 256 return -EFSCORRUPTED;
253 } 257 }
254 258
@@ -595,7 +599,7 @@ xfs_iextents_copy(
595 for_each_xfs_iext(ifp, &icur, &rec) { 599 for_each_xfs_iext(ifp, &icur, &rec) {
596 if (isnullstartblock(rec.br_startblock)) 600 if (isnullstartblock(rec.br_startblock))
597 continue; 601 continue;
598 ASSERT(xfs_bmbt_validate_extent(ip->i_mount, whichfork, &rec)); 602 ASSERT(xfs_bmap_validate_extent(ip, whichfork, &rec) == NULL);
599 xfs_bmbt_disk_set_all(dp, &rec); 603 xfs_bmbt_disk_set_all(dp, &rec);
600 trace_xfs_write_extent(ip, &icur, state, _RET_IP_); 604 trace_xfs_write_extent(ip, &icur, state, _RET_IP_);
601 copied += sizeof(struct xfs_bmbt_rec); 605 copied += sizeof(struct xfs_bmbt_rec);