diff options
Diffstat (limited to 'fs/xfs/xfs_ialloc.c')
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 129 |
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*/ | ||
1202 | int | 1202 | int |
1203 | xfs_dilocate( | 1203 | xfs_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; |
1338 | error0: | ||
1339 | xfs_trans_brelse(tp, agbp); | ||
1340 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | ||
1341 | return error; | ||
1342 | } | 1377 | } |
1343 | 1378 | ||
1344 | /* | 1379 | /* |