aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-08-10 20:55:57 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-08-14 11:17:02 -0400
commit1fc25f51d7c18e07e8cf935cbdd4603adfc7b3ad (patch)
tree504a881c0fe9c4eaba3f114855245f6d46b11a99 /fs/xfs
parent00d22a1c367d03f469f8e1e924b062b09b0545e8 (diff)
xfs: sanity check ag header values in xrep_calc_ag_resblks
Check the values we read in from the AG headers when calculating the block reservations for a repair transaction. If they're obviously wrong, substitute worst case assumptions (rather than ENOSPC on a bogus reservation request). Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Allison Henderson <allison.henderson@oracle.com> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/scrub/repair.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 17cf48564390..9f08dd9bf1d5 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -195,8 +195,8 @@ xrep_calc_ag_resblks(
195 struct xfs_scrub_metadata *sm = sc->sm; 195 struct xfs_scrub_metadata *sm = sc->sm;
196 struct xfs_perag *pag; 196 struct xfs_perag *pag;
197 struct xfs_buf *bp; 197 struct xfs_buf *bp;
198 xfs_agino_t icount = 0; 198 xfs_agino_t icount = NULLAGINO;
199 xfs_extlen_t aglen = 0; 199 xfs_extlen_t aglen = NULLAGBLOCK;
200 xfs_extlen_t usedlen; 200 xfs_extlen_t usedlen;
201 xfs_extlen_t freelen; 201 xfs_extlen_t freelen;
202 xfs_extlen_t bnobt_sz; 202 xfs_extlen_t bnobt_sz;
@@ -208,20 +208,14 @@ xrep_calc_ag_resblks(
208 if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) 208 if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
209 return 0; 209 return 0;
210 210
211 /* Use in-core counters if possible. */
212 pag = xfs_perag_get(mp, sm->sm_agno); 211 pag = xfs_perag_get(mp, sm->sm_agno);
213 if (pag->pagi_init) 212 if (pag->pagi_init) {
213 /* Use in-core icount if possible. */
214 icount = pag->pagi_count; 214 icount = pag->pagi_count;
215 215 } else {
216 /* 216 /* Try to get the actual counters from disk. */
217 * Otherwise try to get the actual counters from disk; if not, make
218 * some worst case assumptions.
219 */
220 if (icount == 0) {
221 error = xfs_ialloc_read_agi(mp, NULL, sm->sm_agno, &bp); 217 error = xfs_ialloc_read_agi(mp, NULL, sm->sm_agno, &bp);
222 if (error) { 218 if (!error) {
223 icount = mp->m_sb.sb_agblocks / mp->m_sb.sb_inopblock;
224 } else {
225 icount = pag->pagi_count; 219 icount = pag->pagi_count;
226 xfs_buf_relse(bp); 220 xfs_buf_relse(bp);
227 } 221 }
@@ -229,18 +223,32 @@ xrep_calc_ag_resblks(
229 223
230 /* Now grab the block counters from the AGF. */ 224 /* Now grab the block counters from the AGF. */
231 error = xfs_alloc_read_agf(mp, NULL, sm->sm_agno, 0, &bp); 225 error = xfs_alloc_read_agf(mp, NULL, sm->sm_agno, 0, &bp);
232 if (error) { 226 if (!error) {
233 aglen = mp->m_sb.sb_agblocks;
234 freelen = aglen;
235 usedlen = aglen;
236 } else {
237 aglen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_length); 227 aglen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_length);
238 freelen = pag->pagf_freeblks; 228 freelen = be32_to_cpu(XFS_BUF_TO_AGF(bp)->agf_freeblks);
239 usedlen = aglen - freelen; 229 usedlen = aglen - freelen;
240 xfs_buf_relse(bp); 230 xfs_buf_relse(bp);
241 } 231 }
242 xfs_perag_put(pag); 232 xfs_perag_put(pag);
243 233
234 /* If the icount is impossible, make some worst-case assumptions. */
235 if (icount == NULLAGINO ||
236 !xfs_verify_agino(mp, sm->sm_agno, icount)) {
237 xfs_agino_t first, last;
238
239 xfs_agino_range(mp, sm->sm_agno, &first, &last);
240 icount = last - first + 1;
241 }
242
243 /* If the block counts are impossible, make worst-case assumptions. */
244 if (aglen == NULLAGBLOCK ||
245 aglen != xfs_ag_block_count(mp, sm->sm_agno) ||
246 freelen >= aglen) {
247 aglen = xfs_ag_block_count(mp, sm->sm_agno);
248 freelen = aglen;
249 usedlen = aglen;
250 }
251
244 trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen, 252 trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen,
245 freelen, usedlen); 253 freelen, usedlen);
246 254