diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 55 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap.c | 259 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_rmap.h | 24 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_error.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_rmap_item.c | 57 | ||||
-rw-r--r-- | fs/xfs/xfs_trans.h | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_rmap.c | 13 |
8 files changed, 400 insertions, 16 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index c4b89218c7eb..b060bca93402 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -2179,6 +2179,11 @@ xfs_bmap_add_extent_delay_real( | |||
2179 | ASSERT(0); | 2179 | ASSERT(0); |
2180 | } | 2180 | } |
2181 | 2181 | ||
2182 | /* add reverse mapping */ | ||
2183 | error = xfs_rmap_map_extent(mp, bma->dfops, bma->ip, whichfork, new); | ||
2184 | if (error) | ||
2185 | goto done; | ||
2186 | |||
2182 | /* convert to a btree if necessary */ | 2187 | /* convert to a btree if necessary */ |
2183 | if (xfs_bmap_needs_btree(bma->ip, whichfork)) { | 2188 | if (xfs_bmap_needs_btree(bma->ip, whichfork)) { |
2184 | int tmp_logflags; /* partial log flag return val */ | 2189 | int tmp_logflags; /* partial log flag return val */ |
@@ -2715,6 +2720,11 @@ xfs_bmap_add_extent_unwritten_real( | |||
2715 | ASSERT(0); | 2720 | ASSERT(0); |
2716 | } | 2721 | } |
2717 | 2722 | ||
2723 | /* update reverse mappings */ | ||
2724 | error = xfs_rmap_convert_extent(mp, dfops, ip, XFS_DATA_FORK, new); | ||
2725 | if (error) | ||
2726 | goto done; | ||
2727 | |||
2718 | /* convert to a btree if necessary */ | 2728 | /* convert to a btree if necessary */ |
2719 | if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) { | 2729 | if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) { |
2720 | int tmp_logflags; /* partial log flag return val */ | 2730 | int tmp_logflags; /* partial log flag return val */ |
@@ -3107,6 +3117,11 @@ xfs_bmap_add_extent_hole_real( | |||
3107 | break; | 3117 | break; |
3108 | } | 3118 | } |
3109 | 3119 | ||
3120 | /* add reverse mapping */ | ||
3121 | error = xfs_rmap_map_extent(mp, bma->dfops, bma->ip, whichfork, new); | ||
3122 | if (error) | ||
3123 | goto done; | ||
3124 | |||
3110 | /* convert to a btree if necessary */ | 3125 | /* convert to a btree if necessary */ |
3111 | if (xfs_bmap_needs_btree(bma->ip, whichfork)) { | 3126 | if (xfs_bmap_needs_btree(bma->ip, whichfork)) { |
3112 | int tmp_logflags; /* partial log flag return val */ | 3127 | int tmp_logflags; /* partial log flag return val */ |
@@ -5034,6 +5049,14 @@ xfs_bmap_del_extent( | |||
5034 | ++*idx; | 5049 | ++*idx; |
5035 | break; | 5050 | break; |
5036 | } | 5051 | } |
5052 | |||
5053 | /* remove reverse mapping */ | ||
5054 | if (!delay) { | ||
5055 | error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, del); | ||
5056 | if (error) | ||
5057 | goto done; | ||
5058 | } | ||
5059 | |||
5037 | /* | 5060 | /* |
5038 | * If we need to, add to list of extents to delete. | 5061 | * If we need to, add to list of extents to delete. |
5039 | */ | 5062 | */ |
@@ -5573,7 +5596,8 @@ xfs_bmse_shift_one( | |||
5573 | struct xfs_bmbt_rec_host *gotp, | 5596 | struct xfs_bmbt_rec_host *gotp, |
5574 | struct xfs_btree_cur *cur, | 5597 | struct xfs_btree_cur *cur, |
5575 | int *logflags, | 5598 | int *logflags, |
5576 | enum shift_direction direction) | 5599 | enum shift_direction direction, |
5600 | struct xfs_defer_ops *dfops) | ||
5577 | { | 5601 | { |
5578 | struct xfs_ifork *ifp; | 5602 | struct xfs_ifork *ifp; |
5579 | struct xfs_mount *mp; | 5603 | struct xfs_mount *mp; |
@@ -5621,9 +5645,13 @@ xfs_bmse_shift_one( | |||
5621 | /* check whether to merge the extent or shift it down */ | 5645 | /* check whether to merge the extent or shift it down */ |
5622 | if (xfs_bmse_can_merge(&adj_irec, &got, | 5646 | if (xfs_bmse_can_merge(&adj_irec, &got, |
5623 | offset_shift_fsb)) { | 5647 | offset_shift_fsb)) { |
5624 | return xfs_bmse_merge(ip, whichfork, offset_shift_fsb, | 5648 | error = xfs_bmse_merge(ip, whichfork, offset_shift_fsb, |
5625 | *current_ext, gotp, adj_irecp, | 5649 | *current_ext, gotp, adj_irecp, |
5626 | cur, logflags); | 5650 | cur, logflags); |
5651 | if (error) | ||
5652 | return error; | ||
5653 | adj_irec = got; | ||
5654 | goto update_rmap; | ||
5627 | } | 5655 | } |
5628 | } else { | 5656 | } else { |
5629 | startoff = got.br_startoff + offset_shift_fsb; | 5657 | startoff = got.br_startoff + offset_shift_fsb; |
@@ -5660,9 +5688,10 @@ update_current_ext: | |||
5660 | (*current_ext)--; | 5688 | (*current_ext)--; |
5661 | xfs_bmbt_set_startoff(gotp, startoff); | 5689 | xfs_bmbt_set_startoff(gotp, startoff); |
5662 | *logflags |= XFS_ILOG_CORE; | 5690 | *logflags |= XFS_ILOG_CORE; |
5691 | adj_irec = got; | ||
5663 | if (!cur) { | 5692 | if (!cur) { |
5664 | *logflags |= XFS_ILOG_DEXT; | 5693 | *logflags |= XFS_ILOG_DEXT; |
5665 | return 0; | 5694 | goto update_rmap; |
5666 | } | 5695 | } |
5667 | 5696 | ||
5668 | error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, | 5697 | error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, |
@@ -5672,8 +5701,18 @@ update_current_ext: | |||
5672 | XFS_WANT_CORRUPTED_RETURN(mp, i == 1); | 5701 | XFS_WANT_CORRUPTED_RETURN(mp, i == 1); |
5673 | 5702 | ||
5674 | got.br_startoff = startoff; | 5703 | got.br_startoff = startoff; |
5675 | return xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, | 5704 | error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, |
5676 | got.br_blockcount, got.br_state); | 5705 | got.br_blockcount, got.br_state); |
5706 | if (error) | ||
5707 | return error; | ||
5708 | |||
5709 | update_rmap: | ||
5710 | /* update reverse mapping */ | ||
5711 | error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, &adj_irec); | ||
5712 | if (error) | ||
5713 | return error; | ||
5714 | adj_irec.br_startoff = startoff; | ||
5715 | return xfs_rmap_map_extent(mp, dfops, ip, whichfork, &adj_irec); | ||
5677 | } | 5716 | } |
5678 | 5717 | ||
5679 | /* | 5718 | /* |
@@ -5801,7 +5840,7 @@ xfs_bmap_shift_extents( | |||
5801 | while (nexts++ < num_exts) { | 5840 | while (nexts++ < num_exts) { |
5802 | error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb, | 5841 | error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb, |
5803 | ¤t_ext, gotp, cur, &logflags, | 5842 | ¤t_ext, gotp, cur, &logflags, |
5804 | direction); | 5843 | direction, dfops); |
5805 | if (error) | 5844 | if (error) |
5806 | goto del_cursor; | 5845 | goto del_cursor; |
5807 | /* | 5846 | /* |
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index e8ce97fd0608..73d05407d663 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include "xfs_trace.h" | 36 | #include "xfs_trace.h" |
37 | #include "xfs_error.h" | 37 | #include "xfs_error.h" |
38 | #include "xfs_extent_busy.h" | 38 | #include "xfs_extent_busy.h" |
39 | #include "xfs_bmap.h" | ||
40 | #include "xfs_inode.h" | ||
39 | 41 | ||
40 | /* | 42 | /* |
41 | * Lookup the first record less than or equal to [bno, len, owner, offset] | 43 | * Lookup the first record less than or equal to [bno, len, owner, offset] |
@@ -1138,3 +1140,260 @@ xfs_rmap_query_range( | |||
1138 | return xfs_btree_query_range(cur, &low_brec, &high_brec, | 1140 | return xfs_btree_query_range(cur, &low_brec, &high_brec, |
1139 | xfs_rmap_query_range_helper, &query); | 1141 | xfs_rmap_query_range_helper, &query); |
1140 | } | 1142 | } |
1143 | |||
1144 | /* Clean up after calling xfs_rmap_finish_one. */ | ||
1145 | void | ||
1146 | xfs_rmap_finish_one_cleanup( | ||
1147 | struct xfs_trans *tp, | ||
1148 | struct xfs_btree_cur *rcur, | ||
1149 | int error) | ||
1150 | { | ||
1151 | struct xfs_buf *agbp; | ||
1152 | |||
1153 | if (rcur == NULL) | ||
1154 | return; | ||
1155 | agbp = rcur->bc_private.a.agbp; | ||
1156 | xfs_btree_del_cursor(rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); | ||
1157 | if (error) | ||
1158 | xfs_trans_brelse(tp, agbp); | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1162 | * Process one of the deferred rmap operations. We pass back the | ||
1163 | * btree cursor to maintain our lock on the rmapbt between calls. | ||
1164 | * This saves time and eliminates a buffer deadlock between the | ||
1165 | * superblock and the AGF because we'll always grab them in the same | ||
1166 | * order. | ||
1167 | */ | ||
1168 | int | ||
1169 | xfs_rmap_finish_one( | ||
1170 | struct xfs_trans *tp, | ||
1171 | enum xfs_rmap_intent_type type, | ||
1172 | __uint64_t owner, | ||
1173 | int whichfork, | ||
1174 | xfs_fileoff_t startoff, | ||
1175 | xfs_fsblock_t startblock, | ||
1176 | xfs_filblks_t blockcount, | ||
1177 | xfs_exntst_t state, | ||
1178 | struct xfs_btree_cur **pcur) | ||
1179 | { | ||
1180 | struct xfs_mount *mp = tp->t_mountp; | ||
1181 | struct xfs_btree_cur *rcur; | ||
1182 | struct xfs_buf *agbp = NULL; | ||
1183 | int error = 0; | ||
1184 | xfs_agnumber_t agno; | ||
1185 | struct xfs_owner_info oinfo; | ||
1186 | xfs_agblock_t bno; | ||
1187 | bool unwritten; | ||
1188 | |||
1189 | agno = XFS_FSB_TO_AGNO(mp, startblock); | ||
1190 | ASSERT(agno != NULLAGNUMBER); | ||
1191 | bno = XFS_FSB_TO_AGBNO(mp, startblock); | ||
1192 | |||
1193 | trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork, | ||
1194 | startoff, blockcount, state); | ||
1195 | |||
1196 | if (XFS_TEST_ERROR(false, mp, | ||
1197 | XFS_ERRTAG_RMAP_FINISH_ONE, | ||
1198 | XFS_RANDOM_RMAP_FINISH_ONE)) | ||
1199 | return -EIO; | ||
1200 | |||
1201 | /* | ||
1202 | * If we haven't gotten a cursor or the cursor AG doesn't match | ||
1203 | * the startblock, get one now. | ||
1204 | */ | ||
1205 | rcur = *pcur; | ||
1206 | if (rcur != NULL && rcur->bc_private.a.agno != agno) { | ||
1207 | xfs_rmap_finish_one_cleanup(tp, rcur, 0); | ||
1208 | rcur = NULL; | ||
1209 | *pcur = NULL; | ||
1210 | } | ||
1211 | if (rcur == NULL) { | ||
1212 | /* | ||
1213 | * Refresh the freelist before we start changing the | ||
1214 | * rmapbt, because a shape change could cause us to | ||
1215 | * allocate blocks. | ||
1216 | */ | ||
1217 | error = xfs_free_extent_fix_freelist(tp, agno, &agbp); | ||
1218 | if (error) | ||
1219 | return error; | ||
1220 | if (!agbp) | ||
1221 | return -EFSCORRUPTED; | ||
1222 | |||
1223 | rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); | ||
1224 | if (!rcur) { | ||
1225 | error = -ENOMEM; | ||
1226 | goto out_cur; | ||
1227 | } | ||
1228 | } | ||
1229 | *pcur = rcur; | ||
1230 | |||
1231 | xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff); | ||
1232 | unwritten = state == XFS_EXT_UNWRITTEN; | ||
1233 | bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock); | ||
1234 | |||
1235 | switch (type) { | ||
1236 | case XFS_RMAP_ALLOC: | ||
1237 | case XFS_RMAP_MAP: | ||
1238 | error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo); | ||
1239 | break; | ||
1240 | case XFS_RMAP_FREE: | ||
1241 | case XFS_RMAP_UNMAP: | ||
1242 | error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten, | ||
1243 | &oinfo); | ||
1244 | break; | ||
1245 | case XFS_RMAP_CONVERT: | ||
1246 | error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten, | ||
1247 | &oinfo); | ||
1248 | break; | ||
1249 | default: | ||
1250 | ASSERT(0); | ||
1251 | error = -EFSCORRUPTED; | ||
1252 | } | ||
1253 | return error; | ||
1254 | |||
1255 | out_cur: | ||
1256 | xfs_trans_brelse(tp, agbp); | ||
1257 | |||
1258 | return error; | ||
1259 | } | ||
1260 | |||
1261 | /* | ||
1262 | * Don't defer an rmap if we aren't an rmap filesystem. | ||
1263 | */ | ||
1264 | static bool | ||
1265 | xfs_rmap_update_is_needed( | ||
1266 | struct xfs_mount *mp) | ||
1267 | { | ||
1268 | return xfs_sb_version_hasrmapbt(&mp->m_sb); | ||
1269 | } | ||
1270 | |||
1271 | /* | ||
1272 | * Record a rmap intent; the list is kept sorted first by AG and then by | ||
1273 | * increasing age. | ||
1274 | */ | ||
1275 | static int | ||
1276 | __xfs_rmap_add( | ||
1277 | struct xfs_mount *mp, | ||
1278 | struct xfs_defer_ops *dfops, | ||
1279 | enum xfs_rmap_intent_type type, | ||
1280 | __uint64_t owner, | ||
1281 | int whichfork, | ||
1282 | struct xfs_bmbt_irec *bmap) | ||
1283 | { | ||
1284 | struct xfs_rmap_intent *ri; | ||
1285 | |||
1286 | trace_xfs_rmap_defer(mp, XFS_FSB_TO_AGNO(mp, bmap->br_startblock), | ||
1287 | type, | ||
1288 | XFS_FSB_TO_AGBNO(mp, bmap->br_startblock), | ||
1289 | owner, whichfork, | ||
1290 | bmap->br_startoff, | ||
1291 | bmap->br_blockcount, | ||
1292 | bmap->br_state); | ||
1293 | |||
1294 | ri = kmem_alloc(sizeof(struct xfs_rmap_intent), KM_SLEEP | KM_NOFS); | ||
1295 | INIT_LIST_HEAD(&ri->ri_list); | ||
1296 | ri->ri_type = type; | ||
1297 | ri->ri_owner = owner; | ||
1298 | ri->ri_whichfork = whichfork; | ||
1299 | ri->ri_bmap = *bmap; | ||
1300 | |||
1301 | xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list); | ||
1302 | return 0; | ||
1303 | } | ||
1304 | |||
1305 | /* Map an extent into a file. */ | ||
1306 | int | ||
1307 | xfs_rmap_map_extent( | ||
1308 | struct xfs_mount *mp, | ||
1309 | struct xfs_defer_ops *dfops, | ||
1310 | struct xfs_inode *ip, | ||
1311 | int whichfork, | ||
1312 | struct xfs_bmbt_irec *PREV) | ||
1313 | { | ||
1314 | if (!xfs_rmap_update_is_needed(mp)) | ||
1315 | return 0; | ||
1316 | |||
1317 | return __xfs_rmap_add(mp, dfops, XFS_RMAP_MAP, ip->i_ino, | ||
1318 | whichfork, PREV); | ||
1319 | } | ||
1320 | |||
1321 | /* Unmap an extent out of a file. */ | ||
1322 | int | ||
1323 | xfs_rmap_unmap_extent( | ||
1324 | struct xfs_mount *mp, | ||
1325 | struct xfs_defer_ops *dfops, | ||
1326 | struct xfs_inode *ip, | ||
1327 | int whichfork, | ||
1328 | struct xfs_bmbt_irec *PREV) | ||
1329 | { | ||
1330 | if (!xfs_rmap_update_is_needed(mp)) | ||
1331 | return 0; | ||
1332 | |||
1333 | return __xfs_rmap_add(mp, dfops, XFS_RMAP_UNMAP, ip->i_ino, | ||
1334 | whichfork, PREV); | ||
1335 | } | ||
1336 | |||
1337 | /* Convert a data fork extent from unwritten to real or vice versa. */ | ||
1338 | int | ||
1339 | xfs_rmap_convert_extent( | ||
1340 | struct xfs_mount *mp, | ||
1341 | struct xfs_defer_ops *dfops, | ||
1342 | struct xfs_inode *ip, | ||
1343 | int whichfork, | ||
1344 | struct xfs_bmbt_irec *PREV) | ||
1345 | { | ||
1346 | if (!xfs_rmap_update_is_needed(mp)) | ||
1347 | return 0; | ||
1348 | |||
1349 | return __xfs_rmap_add(mp, dfops, XFS_RMAP_CONVERT, ip->i_ino, | ||
1350 | whichfork, PREV); | ||
1351 | } | ||
1352 | |||
1353 | /* Schedule the creation of an rmap for non-file data. */ | ||
1354 | int | ||
1355 | xfs_rmap_alloc_extent( | ||
1356 | struct xfs_mount *mp, | ||
1357 | struct xfs_defer_ops *dfops, | ||
1358 | xfs_agnumber_t agno, | ||
1359 | xfs_agblock_t bno, | ||
1360 | xfs_extlen_t len, | ||
1361 | __uint64_t owner) | ||
1362 | { | ||
1363 | struct xfs_bmbt_irec bmap; | ||
1364 | |||
1365 | if (!xfs_rmap_update_is_needed(mp)) | ||
1366 | return 0; | ||
1367 | |||
1368 | bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno); | ||
1369 | bmap.br_blockcount = len; | ||
1370 | bmap.br_startoff = 0; | ||
1371 | bmap.br_state = XFS_EXT_NORM; | ||
1372 | |||
1373 | return __xfs_rmap_add(mp, dfops, XFS_RMAP_ALLOC, owner, | ||
1374 | XFS_DATA_FORK, &bmap); | ||
1375 | } | ||
1376 | |||
1377 | /* Schedule the deletion of an rmap for non-file data. */ | ||
1378 | int | ||
1379 | xfs_rmap_free_extent( | ||
1380 | struct xfs_mount *mp, | ||
1381 | struct xfs_defer_ops *dfops, | ||
1382 | xfs_agnumber_t agno, | ||
1383 | xfs_agblock_t bno, | ||
1384 | xfs_extlen_t len, | ||
1385 | __uint64_t owner) | ||
1386 | { | ||
1387 | struct xfs_bmbt_irec bmap; | ||
1388 | |||
1389 | if (!xfs_rmap_update_is_needed(mp)) | ||
1390 | return 0; | ||
1391 | |||
1392 | bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno); | ||
1393 | bmap.br_blockcount = len; | ||
1394 | bmap.br_startoff = 0; | ||
1395 | bmap.br_state = XFS_EXT_NORM; | ||
1396 | |||
1397 | return __xfs_rmap_add(mp, dfops, XFS_RMAP_FREE, owner, | ||
1398 | XFS_DATA_FORK, &bmap); | ||
1399 | } | ||
diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h index c4b1133e2ff9..71cf99a4acba 100644 --- a/fs/xfs/libxfs/xfs_rmap.h +++ b/fs/xfs/libxfs/xfs_rmap.h | |||
@@ -182,4 +182,28 @@ struct xfs_rmap_intent { | |||
182 | struct xfs_bmbt_irec ri_bmap; | 182 | struct xfs_bmbt_irec ri_bmap; |
183 | }; | 183 | }; |
184 | 184 | ||
185 | /* functions for updating the rmapbt based on bmbt map/unmap operations */ | ||
186 | int xfs_rmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, | ||
187 | struct xfs_inode *ip, int whichfork, | ||
188 | struct xfs_bmbt_irec *imap); | ||
189 | int xfs_rmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, | ||
190 | struct xfs_inode *ip, int whichfork, | ||
191 | struct xfs_bmbt_irec *imap); | ||
192 | int xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, | ||
193 | struct xfs_inode *ip, int whichfork, | ||
194 | struct xfs_bmbt_irec *imap); | ||
195 | int xfs_rmap_alloc_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, | ||
196 | xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, | ||
197 | __uint64_t owner); | ||
198 | int xfs_rmap_free_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, | ||
199 | xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, | ||
200 | __uint64_t owner); | ||
201 | |||
202 | void xfs_rmap_finish_one_cleanup(struct xfs_trans *tp, | ||
203 | struct xfs_btree_cur *rcur, int error); | ||
204 | int xfs_rmap_finish_one(struct xfs_trans *tp, enum xfs_rmap_intent_type type, | ||
205 | __uint64_t owner, int whichfork, xfs_fileoff_t startoff, | ||
206 | xfs_fsblock_t startblock, xfs_filblks_t blockcount, | ||
207 | xfs_exntst_t state, struct xfs_btree_cur **pcur); | ||
208 | |||
185 | #endif /* __XFS_RMAP_H__ */ | 209 | #endif /* __XFS_RMAP_H__ */ |
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 3bbe46bdbc6e..a819d7baa346 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "xfs_trace.h" | 41 | #include "xfs_trace.h" |
42 | #include "xfs_icache.h" | 42 | #include "xfs_icache.h" |
43 | #include "xfs_log.h" | 43 | #include "xfs_log.h" |
44 | #include "xfs_rmap_btree.h" | ||
44 | 45 | ||
45 | /* Kernel only BMAP related definitions and functions */ | 46 | /* Kernel only BMAP related definitions and functions */ |
46 | 47 | ||
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index da6f951435c9..3d224702fbc0 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h | |||
@@ -91,7 +91,8 @@ extern void xfs_verifier_error(struct xfs_buf *bp); | |||
91 | #define XFS_ERRTAG_DIOWRITE_IOERR 20 | 91 | #define XFS_ERRTAG_DIOWRITE_IOERR 20 |
92 | #define XFS_ERRTAG_BMAPIFORMAT 21 | 92 | #define XFS_ERRTAG_BMAPIFORMAT 21 |
93 | #define XFS_ERRTAG_FREE_EXTENT 22 | 93 | #define XFS_ERRTAG_FREE_EXTENT 22 |
94 | #define XFS_ERRTAG_MAX 23 | 94 | #define XFS_ERRTAG_RMAP_FINISH_ONE 23 |
95 | #define XFS_ERRTAG_MAX 24 | ||
95 | 96 | ||
96 | /* | 97 | /* |
97 | * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. | 98 | * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. |
@@ -119,6 +120,7 @@ extern void xfs_verifier_error(struct xfs_buf *bp); | |||
119 | #define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) | 120 | #define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) |
120 | #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT | 121 | #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT |
121 | #define XFS_RANDOM_FREE_EXTENT 1 | 122 | #define XFS_RANDOM_FREE_EXTENT 1 |
123 | #define XFS_RANDOM_RMAP_FINISH_ONE 1 | ||
122 | 124 | ||
123 | #ifdef DEBUG | 125 | #ifdef DEBUG |
124 | extern int xfs_error_test_active; | 126 | extern int xfs_error_test_active; |
diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c index fecd1e4d688d..6d6cc3b8d44f 100644 --- a/fs/xfs/xfs_rmap_item.c +++ b/fs/xfs/xfs_rmap_item.c | |||
@@ -24,11 +24,13 @@ | |||
24 | #include "xfs_trans_resv.h" | 24 | #include "xfs_trans_resv.h" |
25 | #include "xfs_bit.h" | 25 | #include "xfs_bit.h" |
26 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
27 | #include "xfs_defer.h" | ||
27 | #include "xfs_trans.h" | 28 | #include "xfs_trans.h" |
28 | #include "xfs_trans_priv.h" | 29 | #include "xfs_trans_priv.h" |
29 | #include "xfs_buf_item.h" | 30 | #include "xfs_buf_item.h" |
30 | #include "xfs_rmap_item.h" | 31 | #include "xfs_rmap_item.h" |
31 | #include "xfs_log.h" | 32 | #include "xfs_log.h" |
33 | #include "xfs_rmap.h" | ||
32 | 34 | ||
33 | 35 | ||
34 | kmem_zone_t *xfs_rui_zone; | 36 | kmem_zone_t *xfs_rui_zone; |
@@ -473,6 +475,12 @@ xfs_rui_recover( | |||
473 | struct xfs_map_extent *rmap; | 475 | struct xfs_map_extent *rmap; |
474 | xfs_fsblock_t startblock_fsb; | 476 | xfs_fsblock_t startblock_fsb; |
475 | bool op_ok; | 477 | bool op_ok; |
478 | struct xfs_rud_log_item *rudp; | ||
479 | enum xfs_rmap_intent_type type; | ||
480 | int whichfork; | ||
481 | xfs_exntst_t state; | ||
482 | struct xfs_trans *tp; | ||
483 | struct xfs_btree_cur *rcur = NULL; | ||
476 | 484 | ||
477 | ASSERT(!test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags)); | 485 | ASSERT(!test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags)); |
478 | 486 | ||
@@ -512,8 +520,53 @@ xfs_rui_recover( | |||
512 | } | 520 | } |
513 | } | 521 | } |
514 | 522 | ||
515 | /* XXX: do nothing for now */ | 523 | error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); |
524 | if (error) | ||
525 | return error; | ||
526 | rudp = xfs_trans_get_rud(tp, ruip, ruip->rui_format.rui_nextents); | ||
527 | |||
528 | for (i = 0; i < ruip->rui_format.rui_nextents; i++) { | ||
529 | rmap = &(ruip->rui_format.rui_extents[i]); | ||
530 | state = (rmap->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ? | ||
531 | XFS_EXT_UNWRITTEN : XFS_EXT_NORM; | ||
532 | whichfork = (rmap->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ? | ||
533 | XFS_ATTR_FORK : XFS_DATA_FORK; | ||
534 | switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { | ||
535 | case XFS_RMAP_EXTENT_MAP: | ||
536 | type = XFS_RMAP_MAP; | ||
537 | break; | ||
538 | case XFS_RMAP_EXTENT_UNMAP: | ||
539 | type = XFS_RMAP_UNMAP; | ||
540 | break; | ||
541 | case XFS_RMAP_EXTENT_CONVERT: | ||
542 | type = XFS_RMAP_CONVERT; | ||
543 | break; | ||
544 | case XFS_RMAP_EXTENT_ALLOC: | ||
545 | type = XFS_RMAP_ALLOC; | ||
546 | break; | ||
547 | case XFS_RMAP_EXTENT_FREE: | ||
548 | type = XFS_RMAP_FREE; | ||
549 | break; | ||
550 | default: | ||
551 | error = -EFSCORRUPTED; | ||
552 | goto abort_error; | ||
553 | } | ||
554 | error = xfs_trans_log_finish_rmap_update(tp, rudp, type, | ||
555 | rmap->me_owner, whichfork, | ||
556 | rmap->me_startoff, rmap->me_startblock, | ||
557 | rmap->me_len, state, &rcur); | ||
558 | if (error) | ||
559 | goto abort_error; | ||
560 | |||
561 | } | ||
562 | |||
563 | xfs_rmap_finish_one_cleanup(tp, rcur, error); | ||
516 | set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags); | 564 | set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags); |
517 | xfs_rui_release(ruip); | 565 | error = xfs_trans_commit(tp); |
566 | return error; | ||
567 | |||
568 | abort_error: | ||
569 | xfs_rmap_finish_one_cleanup(tp, rcur, error); | ||
570 | xfs_trans_cancel(tp); | ||
518 | return error; | 571 | return error; |
519 | } | 572 | } |
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 07f4550825f6..bb4b84f9347e 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h | |||
@@ -35,6 +35,7 @@ struct xfs_dquot_acct; | |||
35 | struct xfs_busy_extent; | 35 | struct xfs_busy_extent; |
36 | struct xfs_rud_log_item; | 36 | struct xfs_rud_log_item; |
37 | struct xfs_rui_log_item; | 37 | struct xfs_rui_log_item; |
38 | struct xfs_btree_cur; | ||
38 | 39 | ||
39 | typedef struct xfs_log_item { | 40 | typedef struct xfs_log_item { |
40 | struct list_head li_ail; /* AIL pointers */ | 41 | struct list_head li_ail; /* AIL pointers */ |
@@ -245,6 +246,6 @@ int xfs_trans_log_finish_rmap_update(struct xfs_trans *tp, | |||
245 | struct xfs_rud_log_item *rudp, enum xfs_rmap_intent_type type, | 246 | struct xfs_rud_log_item *rudp, enum xfs_rmap_intent_type type, |
246 | __uint64_t owner, int whichfork, xfs_fileoff_t startoff, | 247 | __uint64_t owner, int whichfork, xfs_fileoff_t startoff, |
247 | xfs_fsblock_t startblock, xfs_filblks_t blockcount, | 248 | xfs_fsblock_t startblock, xfs_filblks_t blockcount, |
248 | xfs_exntst_t state); | 249 | xfs_exntst_t state, struct xfs_btree_cur **pcur); |
249 | 250 | ||
250 | #endif /* __XFS_TRANS_H__ */ | 251 | #endif /* __XFS_TRANS_H__ */ |
diff --git a/fs/xfs/xfs_trans_rmap.c b/fs/xfs/xfs_trans_rmap.c index baab99077f77..83414764e1ab 100644 --- a/fs/xfs/xfs_trans_rmap.c +++ b/fs/xfs/xfs_trans_rmap.c | |||
@@ -171,14 +171,15 @@ xfs_trans_log_finish_rmap_update( | |||
171 | xfs_fileoff_t startoff, | 171 | xfs_fileoff_t startoff, |
172 | xfs_fsblock_t startblock, | 172 | xfs_fsblock_t startblock, |
173 | xfs_filblks_t blockcount, | 173 | xfs_filblks_t blockcount, |
174 | xfs_exntst_t state) | 174 | xfs_exntst_t state, |
175 | struct xfs_btree_cur **pcur) | ||
175 | { | 176 | { |
176 | uint next_extent; | 177 | uint next_extent; |
177 | struct xfs_map_extent *rmap; | 178 | struct xfs_map_extent *rmap; |
178 | int error; | 179 | int error; |
179 | 180 | ||
180 | /* XXX: actually finish the rmap update here */ | 181 | error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff, |
181 | error = -EFSCORRUPTED; | 182 | startblock, blockcount, state, pcur); |
182 | 183 | ||
183 | /* | 184 | /* |
184 | * Mark the transaction dirty, even on error. This ensures the | 185 | * Mark the transaction dirty, even on error. This ensures the |
@@ -276,7 +277,8 @@ xfs_rmap_update_finish_item( | |||
276 | rmap->ri_bmap.br_startoff, | 277 | rmap->ri_bmap.br_startoff, |
277 | rmap->ri_bmap.br_startblock, | 278 | rmap->ri_bmap.br_startblock, |
278 | rmap->ri_bmap.br_blockcount, | 279 | rmap->ri_bmap.br_blockcount, |
279 | rmap->ri_bmap.br_state); | 280 | rmap->ri_bmap.br_state, |
281 | (struct xfs_btree_cur **)state); | ||
280 | kmem_free(rmap); | 282 | kmem_free(rmap); |
281 | return error; | 283 | return error; |
282 | } | 284 | } |
@@ -288,6 +290,9 @@ xfs_rmap_update_finish_cleanup( | |||
288 | void *state, | 290 | void *state, |
289 | int error) | 291 | int error) |
290 | { | 292 | { |
293 | struct xfs_btree_cur *rcur = state; | ||
294 | |||
295 | xfs_rmap_finish_one_cleanup(tp, rcur, error); | ||
291 | } | 296 | } |
292 | 297 | ||
293 | /* Abort all pending RUIs. */ | 298 | /* Abort all pending RUIs. */ |