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.c129
1 files changed, 82 insertions, 47 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index 0ce56d6a4922..348ac30174c5 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -40,6 +40,7 @@
40#include "xfs_rtalloc.h" 40#include "xfs_rtalloc.h"
41#include "xfs_error.h" 41#include "xfs_error.h"
42#include "xfs_bmap.h" 42#include "xfs_bmap.h"
43#include "xfs_imap.h"
43 44
44 45
45/* 46/*
@@ -1196,36 +1197,28 @@ error0:
1196} 1197}
1197 1198
1198/* 1199/*
1199 * Return the location of the inode in bno/off, for mapping it into a buffer. 1200 * Return the location of the inode in imap, for mapping it into a buffer.
1200 */ 1201 */
1201/*ARGSUSED*/
1202int 1202int
1203xfs_dilocate( 1203xfs_imap(
1204 xfs_mount_t *mp, /* file system mount structure */ 1204 xfs_mount_t *mp, /* file system mount structure */
1205 xfs_trans_t *tp, /* transaction pointer */ 1205 xfs_trans_t *tp, /* transaction pointer */
1206 xfs_ino_t ino, /* inode to locate */ 1206 xfs_ino_t ino, /* inode to locate */
1207 xfs_fsblock_t *bno, /* output: block containing inode */ 1207 struct xfs_imap *imap, /* location map structure */
1208 int *len, /* output: num blocks in inode cluster */ 1208 uint flags) /* flags for inode btree lookup */
1209 int *off, /* output: index in block of inode */
1210 uint flags) /* flags concerning inode lookup */
1211{ 1209{
1212 xfs_agblock_t agbno; /* block number of inode in the alloc group */ 1210 xfs_agblock_t agbno; /* block number of inode in the alloc group */
1213 xfs_buf_t *agbp; /* agi buffer */
1214 xfs_agino_t agino; /* inode number within alloc group */ 1211 xfs_agino_t agino; /* inode number within alloc group */
1215 xfs_agnumber_t agno; /* allocation group number */ 1212 xfs_agnumber_t agno; /* allocation group number */
1216 int blks_per_cluster; /* num blocks per inode cluster */ 1213 int blks_per_cluster; /* num blocks per inode cluster */
1217 xfs_agblock_t chunk_agbno; /* first block in inode chunk */ 1214 xfs_agblock_t chunk_agbno; /* first block in inode chunk */
1218 xfs_agino_t chunk_agino; /* first agino in inode chunk */
1219 __int32_t chunk_cnt; /* count of free inodes in chunk */
1220 xfs_inofree_t chunk_free; /* mask of free inodes in chunk */
1221 xfs_agblock_t cluster_agbno; /* first block in inode cluster */ 1215 xfs_agblock_t cluster_agbno; /* first block in inode cluster */
1222 xfs_btree_cur_t *cur; /* inode btree cursor */
1223 int error; /* error code */ 1216 int error; /* error code */
1224 int i; /* temp state */
1225 int offset; /* index of inode in its buffer */ 1217 int offset; /* index of inode in its buffer */
1226 int offset_agbno; /* blks from chunk start to inode */ 1218 int offset_agbno; /* blks from chunk start to inode */
1227 1219
1228 ASSERT(ino != NULLFSINO); 1220 ASSERT(ino != NULLFSINO);
1221
1229 /* 1222 /*
1230 * Split up the inode number into its parts. 1223 * Split up the inode number into its parts.
1231 */ 1224 */
@@ -1240,20 +1233,20 @@ xfs_dilocate(
1240 return XFS_ERROR(EINVAL); 1233 return XFS_ERROR(EINVAL);
1241 if (agno >= mp->m_sb.sb_agcount) { 1234 if (agno >= mp->m_sb.sb_agcount) {
1242 xfs_fs_cmn_err(CE_ALERT, mp, 1235 xfs_fs_cmn_err(CE_ALERT, mp,
1243 "xfs_dilocate: agno (%d) >= " 1236 "xfs_imap: agno (%d) >= "
1244 "mp->m_sb.sb_agcount (%d)", 1237 "mp->m_sb.sb_agcount (%d)",
1245 agno, mp->m_sb.sb_agcount); 1238 agno, mp->m_sb.sb_agcount);
1246 } 1239 }
1247 if (agbno >= mp->m_sb.sb_agblocks) { 1240 if (agbno >= mp->m_sb.sb_agblocks) {
1248 xfs_fs_cmn_err(CE_ALERT, mp, 1241 xfs_fs_cmn_err(CE_ALERT, mp,
1249 "xfs_dilocate: agbno (0x%llx) >= " 1242 "xfs_imap: agbno (0x%llx) >= "
1250 "mp->m_sb.sb_agblocks (0x%lx)", 1243 "mp->m_sb.sb_agblocks (0x%lx)",
1251 (unsigned long long) agbno, 1244 (unsigned long long) agbno,
1252 (unsigned long) mp->m_sb.sb_agblocks); 1245 (unsigned long) mp->m_sb.sb_agblocks);
1253 } 1246 }
1254 if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { 1247 if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
1255 xfs_fs_cmn_err(CE_ALERT, mp, 1248 xfs_fs_cmn_err(CE_ALERT, mp,
1256 "xfs_dilocate: ino (0x%llx) != " 1249 "xfs_imap: ino (0x%llx) != "
1257 "XFS_AGINO_TO_INO(mp, agno, agino) " 1250 "XFS_AGINO_TO_INO(mp, agno, agino) "
1258 "(0x%llx)", 1251 "(0x%llx)",
1259 ino, XFS_AGINO_TO_INO(mp, agno, agino)); 1252 ino, XFS_AGINO_TO_INO(mp, agno, agino));
@@ -1262,63 +1255,89 @@ xfs_dilocate(
1262#endif /* DEBUG */ 1255#endif /* DEBUG */
1263 return XFS_ERROR(EINVAL); 1256 return XFS_ERROR(EINVAL);
1264 } 1257 }
1265 if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp))) { 1258
1259 /*
1260 * If the inode cluster size is the same as the blocksize or
1261 * smaller we get to the buffer by simple arithmetics.
1262 */
1263 if (XFS_INODE_CLUSTER_SIZE(mp) <= mp->m_sb.sb_blocksize) {
1266 offset = XFS_INO_TO_OFFSET(mp, ino); 1264 offset = XFS_INO_TO_OFFSET(mp, ino);
1267 ASSERT(offset < mp->m_sb.sb_inopblock); 1265 ASSERT(offset < mp->m_sb.sb_inopblock);
1268 *bno = XFS_AGB_TO_FSB(mp, agno, agbno); 1266
1269 *off = offset; 1267 imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno);
1270 *len = 1; 1268 imap->im_len = XFS_FSB_TO_BB(mp, 1);
1269 imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
1271 return 0; 1270 return 0;
1272 } 1271 }
1272
1273 blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; 1273 blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog;
1274 if (*bno != NULLFSBLOCK) { 1274
1275 /*
1276 * If we get a block number passed from bulkstat we can use it to
1277 * find the buffer easily.
1278 */
1279 if (imap->im_blkno) {
1275 offset = XFS_INO_TO_OFFSET(mp, ino); 1280 offset = XFS_INO_TO_OFFSET(mp, ino);
1276 ASSERT(offset < mp->m_sb.sb_inopblock); 1281 ASSERT(offset < mp->m_sb.sb_inopblock);
1277 cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno); 1282
1278 *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + 1283 cluster_agbno = XFS_DADDR_TO_AGBNO(mp, imap->im_blkno);
1279 offset; 1284 offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock;
1280 *len = blks_per_cluster; 1285
1286 imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
1287 imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
1281 return 0; 1288 return 0;
1282 } 1289 }
1290
1291 /*
1292 * If the inode chunks are aligned then use simple maths to
1293 * find the location. Otherwise we have to do a btree
1294 * lookup to find the location.
1295 */
1283 if (mp->m_inoalign_mask) { 1296 if (mp->m_inoalign_mask) {
1284 offset_agbno = agbno & mp->m_inoalign_mask; 1297 offset_agbno = agbno & mp->m_inoalign_mask;
1285 chunk_agbno = agbno - offset_agbno; 1298 chunk_agbno = agbno - offset_agbno;
1286 } else { 1299 } else {
1300 xfs_btree_cur_t *cur; /* inode btree cursor */
1301 xfs_agino_t chunk_agino; /* first agino in inode chunk */
1302 __int32_t chunk_cnt; /* count of free inodes in chunk */
1303 xfs_inofree_t chunk_free; /* mask of free inodes in chunk */
1304 xfs_buf_t *agbp; /* agi buffer */
1305 int i; /* temp state */
1306
1287 down_read(&mp->m_peraglock); 1307 down_read(&mp->m_peraglock);
1288 error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); 1308 error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
1289 up_read(&mp->m_peraglock); 1309 up_read(&mp->m_peraglock);
1290 if (error) { 1310 if (error) {
1291#ifdef DEBUG 1311 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1292 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
1293 "xfs_ialloc_read_agi() returned " 1312 "xfs_ialloc_read_agi() returned "
1294 "error %d, agno %d", 1313 "error %d, agno %d",
1295 error, agno); 1314 error, agno);
1296#endif /* DEBUG */
1297 return error; 1315 return error;
1298 } 1316 }
1317
1299 cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); 1318 cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
1300 if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { 1319 error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i);
1301#ifdef DEBUG 1320 if (error) {
1302 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " 1321 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1303 "xfs_inobt_lookup_le() failed"); 1322 "xfs_inobt_lookup_le() failed");
1304#endif /* DEBUG */
1305 goto error0; 1323 goto error0;
1306 } 1324 }
1307 if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, 1325
1308 &chunk_free, &i))) { 1326 error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt,
1309#ifdef DEBUG 1327 &chunk_free, &i);
1310 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " 1328 if (error) {
1329 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1311 "xfs_inobt_get_rec() failed"); 1330 "xfs_inobt_get_rec() failed");
1312#endif /* DEBUG */
1313 goto error0; 1331 goto error0;
1314 } 1332 }
1315 if (i == 0) { 1333 if (i == 0) {
1316#ifdef DEBUG 1334#ifdef DEBUG
1317 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: " 1335 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1318 "xfs_inobt_get_rec() failed"); 1336 "xfs_inobt_get_rec() failed");
1319#endif /* DEBUG */ 1337#endif /* DEBUG */
1320 error = XFS_ERROR(EINVAL); 1338 error = XFS_ERROR(EINVAL);
1321 } 1339 }
1340 error0:
1322 xfs_trans_brelse(tp, agbp); 1341 xfs_trans_brelse(tp, agbp);
1323 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); 1342 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
1324 if (error) 1343 if (error)
@@ -1326,19 +1345,35 @@ xfs_dilocate(
1326 chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); 1345 chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino);
1327 offset_agbno = agbno - chunk_agbno; 1346 offset_agbno = agbno - chunk_agbno;
1328 } 1347 }
1348
1329 ASSERT(agbno >= chunk_agbno); 1349 ASSERT(agbno >= chunk_agbno);
1330 cluster_agbno = chunk_agbno + 1350 cluster_agbno = chunk_agbno +
1331 ((offset_agbno / blks_per_cluster) * blks_per_cluster); 1351 ((offset_agbno / blks_per_cluster) * blks_per_cluster);
1332 offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + 1352 offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
1333 XFS_INO_TO_OFFSET(mp, ino); 1353 XFS_INO_TO_OFFSET(mp, ino);
1334 *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno); 1354
1335 *off = offset; 1355 imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno);
1336 *len = blks_per_cluster; 1356 imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster);
1357 imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog);
1358
1359 /*
1360 * If the inode number maps to a block outside the bounds
1361 * of the file system then return NULL rather than calling
1362 * read_buf and panicing when we get an error from the
1363 * driver.
1364 */
1365 if ((imap->im_blkno + imap->im_len) >
1366 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {
1367 xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: "
1368 "(imap->im_blkno (0x%llx) + imap->im_len (0x%llx)) > "
1369 " XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) (0x%llx)",
1370 (unsigned long long) imap->im_blkno,
1371 (unsigned long long) imap->im_len,
1372 XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
1373 return XFS_ERROR(EINVAL);
1374 }
1375
1337 return 0; 1376 return 0;
1338error0:
1339 xfs_trans_brelse(tp, agbp);
1340 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
1341 return error;
1342} 1377}
1343 1378
1344/* 1379/*