aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_ialloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_ialloc.c')
-rw-r--r--fs/xfs/xfs_ialloc.c146
1 files changed, 82 insertions, 64 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index 9d884c127bb9..abf80ae1e95b 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -24,14 +24,10 @@
24#include "xfs_trans.h" 24#include "xfs_trans.h"
25#include "xfs_sb.h" 25#include "xfs_sb.h"
26#include "xfs_ag.h" 26#include "xfs_ag.h"
27#include "xfs_dir2.h"
28#include "xfs_dmapi.h"
29#include "xfs_mount.h" 27#include "xfs_mount.h"
30#include "xfs_bmap_btree.h" 28#include "xfs_bmap_btree.h"
31#include "xfs_alloc_btree.h" 29#include "xfs_alloc_btree.h"
32#include "xfs_ialloc_btree.h" 30#include "xfs_ialloc_btree.h"
33#include "xfs_dir2_sf.h"
34#include "xfs_attr_sf.h"
35#include "xfs_dinode.h" 31#include "xfs_dinode.h"
36#include "xfs_inode.h" 32#include "xfs_inode.h"
37#include "xfs_btree.h" 33#include "xfs_btree.h"
@@ -1203,6 +1199,63 @@ error0:
1203 return error; 1199 return error;
1204} 1200}
1205 1201
1202STATIC int
1203xfs_imap_lookup(
1204 struct xfs_mount *mp,
1205 struct xfs_trans *tp,
1206 xfs_agnumber_t agno,
1207 xfs_agino_t agino,
1208 xfs_agblock_t agbno,
1209 xfs_agblock_t *chunk_agbno,
1210 xfs_agblock_t *offset_agbno,
1211 int flags)
1212{
1213 struct xfs_inobt_rec_incore rec;
1214 struct xfs_btree_cur *cur;
1215 struct xfs_buf *agbp;
1216 xfs_agino_t startino;
1217 int error;
1218 int i;
1219
1220 error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
1221 if (error) {
1222 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1223 "xfs_ialloc_read_agi() returned "
1224 "error %d, agno %d",
1225 error, agno);
1226 return error;
1227 }
1228
1229 /*
1230 * derive and lookup the exact inode record for the given agino. If the
1231 * record cannot be found, then it's an invalid inode number and we
1232 * should abort.
1233 */
1234 cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
1235 startino = agino & ~(XFS_IALLOC_INODES(mp) - 1);
1236 error = xfs_inobt_lookup(cur, startino, XFS_LOOKUP_EQ, &i);
1237 if (!error) {
1238 if (i)
1239 error = xfs_inobt_get_rec(cur, &rec, &i);
1240 if (!error && i == 0)
1241 error = EINVAL;
1242 }
1243
1244 xfs_trans_brelse(tp, agbp);
1245 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
1246 if (error)
1247 return error;
1248
1249 /* for untrusted inodes check it is allocated first */
1250 if ((flags & XFS_IGET_UNTRUSTED) &&
1251 (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino)))
1252 return EINVAL;
1253
1254 *chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino);
1255 *offset_agbno = agbno - *chunk_agbno;
1256 return 0;
1257}
1258
1206/* 1259/*
1207 * Return the location of the inode in imap, for mapping it into a buffer. 1260 * Return the location of the inode in imap, for mapping it into a buffer.
1208 */ 1261 */
@@ -1235,8 +1288,11 @@ xfs_imap(
1235 if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || 1288 if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
1236 ino != XFS_AGINO_TO_INO(mp, agno, agino)) { 1289 ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
1237#ifdef DEBUG 1290#ifdef DEBUG
1238 /* no diagnostics for bulkstat, ino comes from userspace */ 1291 /*
1239 if (flags & XFS_IGET_BULKSTAT) 1292 * Don't output diagnostic information for untrusted inodes
1293 * as they can be invalid without implying corruption.
1294 */
1295 if (flags & XFS_IGET_UNTRUSTED)
1240 return XFS_ERROR(EINVAL); 1296 return XFS_ERROR(EINVAL);
1241 if (agno >= mp->m_sb.sb_agcount) { 1297 if (agno >= mp->m_sb.sb_agcount) {
1242 xfs_fs_cmn_err(CE_ALERT, mp, 1298 xfs_fs_cmn_err(CE_ALERT, mp,
@@ -1263,6 +1319,23 @@ xfs_imap(
1263 return XFS_ERROR(EINVAL); 1319 return XFS_ERROR(EINVAL);
1264 } 1320 }
1265 1321
1322 blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
1323
1324 /*
1325 * For bulkstat and handle lookups, we have an untrusted inode number
1326 * that we have to verify is valid. We cannot do this just by reading
1327 * the inode buffer as it may have been unlinked and removed leaving
1328 * inodes in stale state on disk. Hence we have to do a btree lookup
1329 * in all cases where an untrusted inode number is passed.
1330 */
1331 if (flags & XFS_IGET_UNTRUSTED) {
1332 error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
1333 &chunk_agbno, &offset_agbno, flags);
1334 if (error)
1335 return error;
1336 goto out_map;
1337 }
1338
1266 /* 1339 /*
1267 * If the inode cluster size is the same as the blocksize or 1340 * If the inode cluster size is the same as the blocksize or
1268 * smaller we get to the buffer by simple arithmetics. 1341 * smaller we get to the buffer by simple arithmetics.
@@ -1277,24 +1350,6 @@ xfs_imap(
1277 return 0; 1350 return 0;
1278 } 1351 }
1279 1352
1280 blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
1281
1282 /*
1283 * If we get a block number passed from bulkstat we can use it to
1284 * find the buffer easily.
1285 */
1286 if (imap->im_blkno) {
1287 offset = XFS_INO_TO_OFFSET(mp, ino);
1288 ASSERT(offset < mp->m_sb.sb_inopblock);
1289
1290 cluster_agbno = xfs_daddr_to_agbno(mp, imap->im_blkno);
1291 offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock;
1292
1293 imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
1294 imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
1295 return 0;
1296 }
1297
1298 /* 1353 /*
1299 * If the inode chunks are aligned then use simple maths to 1354 * If the inode chunks are aligned then use simple maths to
1300 * find the location. Otherwise we have to do a btree 1355 * find the location. Otherwise we have to do a btree
@@ -1304,50 +1359,13 @@ xfs_imap(
1304 offset_agbno = agbno & mp->m_inoalign_mask; 1359 offset_agbno = agbno & mp->m_inoalign_mask;
1305 chunk_agbno = agbno - offset_agbno; 1360 chunk_agbno = agbno - offset_agbno;
1306 } else { 1361 } else {
1307 xfs_btree_cur_t *cur; /* inode btree cursor */ 1362 error = xfs_imap_lookup(mp, tp, agno, agino, agbno,
1308 xfs_inobt_rec_incore_t chunk_rec; 1363 &chunk_agbno, &offset_agbno, flags);
1309 xfs_buf_t *agbp; /* agi buffer */
1310 int i; /* temp state */
1311
1312 error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
1313 if (error) {
1314 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1315 "xfs_ialloc_read_agi() returned "
1316 "error %d, agno %d",
1317 error, agno);
1318 return error;
1319 }
1320
1321 cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
1322 error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
1323 if (error) {
1324 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1325 "xfs_inobt_lookup() failed");
1326 goto error0;
1327 }
1328
1329 error = xfs_inobt_get_rec(cur, &chunk_rec, &i);
1330 if (error) {
1331 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1332 "xfs_inobt_get_rec() failed");
1333 goto error0;
1334 }
1335 if (i == 0) {
1336#ifdef DEBUG
1337 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1338 "xfs_inobt_get_rec() failed");
1339#endif /* DEBUG */
1340 error = XFS_ERROR(EINVAL);
1341 }
1342 error0:
1343 xfs_trans_brelse(tp, agbp);
1344 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
1345 if (error) 1364 if (error)
1346 return error; 1365 return error;
1347 chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_rec.ir_startino);
1348 offset_agbno = agbno - chunk_agbno;
1349 } 1366 }
1350 1367
1368out_map:
1351 ASSERT(agbno >= chunk_agbno); 1369 ASSERT(agbno >= chunk_agbno);
1352 cluster_agbno = chunk_agbno + 1370 cluster_agbno = chunk_agbno +
1353 ((offset_agbno / blks_per_cluster) * blks_per_cluster); 1371 ((offset_agbno / blks_per_cluster) * blks_per_cluster);