aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:48 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2016-10-05 19:26:29 -0400
commitceeb9c832eeca5c1c2efc54a38f67283ccb60288 (patch)
tree9758e097e4b7ffcbca52b5689acc5588e83db920
parent0e07c039bac5f6ce7e3bc512ab9efb4aaa76da94 (diff)
xfs: use interval query for rmap alloc operations on shared files
When it's possible for reverse mappings to overlap (data fork extents of files on reflink filesystems), use the interval query function to find the left neighbor of an extent we're trying to add; and be careful to use the lookup functions to update the neighbors and/or add new extents. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/libxfs/xfs_rmap.c514
-rw-r--r--fs/xfs/libxfs/xfs_rmap.h7
-rw-r--r--fs/xfs/xfs_rmap_item.c6
-rw-r--r--fs/xfs/xfs_trace.h5
4 files changed, 530 insertions, 2 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 1c40b851a21d..bb5e2f840370 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -148,6 +148,37 @@ done:
148 return error; 148 return error;
149} 149}
150 150
151STATIC int
152xfs_rmap_delete(
153 struct xfs_btree_cur *rcur,
154 xfs_agblock_t agbno,
155 xfs_extlen_t len,
156 uint64_t owner,
157 uint64_t offset,
158 unsigned int flags)
159{
160 int i;
161 int error;
162
163 trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_private.a.agno, agbno,
164 len, owner, offset, flags);
165
166 error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
167 if (error)
168 goto done;
169 XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
170
171 error = xfs_btree_delete(rcur, &i);
172 if (error)
173 goto done;
174 XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
175done:
176 if (error)
177 trace_xfs_rmap_delete_error(rcur->bc_mp,
178 rcur->bc_private.a.agno, error, _RET_IP_);
179 return error;
180}
181
151static int 182static int
152xfs_rmap_btrec_to_irec( 183xfs_rmap_btrec_to_irec(
153 union xfs_btree_rec *rec, 184 union xfs_btree_rec *rec,
@@ -180,6 +211,160 @@ xfs_rmap_get_rec(
180 return xfs_rmap_btrec_to_irec(rec, irec); 211 return xfs_rmap_btrec_to_irec(rec, irec);
181} 212}
182 213
214struct xfs_find_left_neighbor_info {
215 struct xfs_rmap_irec high;
216 struct xfs_rmap_irec *irec;
217 int *stat;
218};
219
220/* For each rmap given, figure out if it matches the key we want. */
221STATIC int
222xfs_rmap_find_left_neighbor_helper(
223 struct xfs_btree_cur *cur,
224 struct xfs_rmap_irec *rec,
225 void *priv)
226{
227 struct xfs_find_left_neighbor_info *info = priv;
228
229 trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
230 cur->bc_private.a.agno, rec->rm_startblock,
231 rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
232 rec->rm_flags);
233
234 if (rec->rm_owner != info->high.rm_owner)
235 return XFS_BTREE_QUERY_RANGE_CONTINUE;
236 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
237 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
238 rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset)
239 return XFS_BTREE_QUERY_RANGE_CONTINUE;
240
241 *info->irec = *rec;
242 *info->stat = 1;
243 return XFS_BTREE_QUERY_RANGE_ABORT;
244}
245
246/*
247 * Find the record to the left of the given extent, being careful only to
248 * return a match with the same owner and adjacent physical and logical
249 * block ranges.
250 */
251int
252xfs_rmap_find_left_neighbor(
253 struct xfs_btree_cur *cur,
254 xfs_agblock_t bno,
255 uint64_t owner,
256 uint64_t offset,
257 unsigned int flags,
258 struct xfs_rmap_irec *irec,
259 int *stat)
260{
261 struct xfs_find_left_neighbor_info info;
262 int error;
263
264 *stat = 0;
265 if (bno == 0)
266 return 0;
267 info.high.rm_startblock = bno - 1;
268 info.high.rm_owner = owner;
269 if (!XFS_RMAP_NON_INODE_OWNER(owner) &&
270 !(flags & XFS_RMAP_BMBT_BLOCK)) {
271 if (offset == 0)
272 return 0;
273 info.high.rm_offset = offset - 1;
274 } else
275 info.high.rm_offset = 0;
276 info.high.rm_flags = flags;
277 info.high.rm_blockcount = 0;
278 info.irec = irec;
279 info.stat = stat;
280
281 trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
282 cur->bc_private.a.agno, bno, 0, owner, offset, flags);
283
284 error = xfs_rmap_query_range(cur, &info.high, &info.high,
285 xfs_rmap_find_left_neighbor_helper, &info);
286 if (error == XFS_BTREE_QUERY_RANGE_ABORT)
287 error = 0;
288 if (*stat)
289 trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
290 cur->bc_private.a.agno, irec->rm_startblock,
291 irec->rm_blockcount, irec->rm_owner,
292 irec->rm_offset, irec->rm_flags);
293 return error;
294}
295
296/* For each rmap given, figure out if it matches the key we want. */
297STATIC int
298xfs_rmap_lookup_le_range_helper(
299 struct xfs_btree_cur *cur,
300 struct xfs_rmap_irec *rec,
301 void *priv)
302{
303 struct xfs_find_left_neighbor_info *info = priv;
304
305 trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
306 cur->bc_private.a.agno, rec->rm_startblock,
307 rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
308 rec->rm_flags);
309
310 if (rec->rm_owner != info->high.rm_owner)
311 return XFS_BTREE_QUERY_RANGE_CONTINUE;
312 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) &&
313 !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) &&
314 (rec->rm_offset > info->high.rm_offset ||
315 rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset))
316 return XFS_BTREE_QUERY_RANGE_CONTINUE;
317
318 *info->irec = *rec;
319 *info->stat = 1;
320 return XFS_BTREE_QUERY_RANGE_ABORT;
321}
322
323/*
324 * Find the record to the left of the given extent, being careful only to
325 * return a match with the same owner and overlapping physical and logical
326 * block ranges. This is the overlapping-interval version of
327 * xfs_rmap_lookup_le.
328 */
329int
330xfs_rmap_lookup_le_range(
331 struct xfs_btree_cur *cur,
332 xfs_agblock_t bno,
333 uint64_t owner,
334 uint64_t offset,
335 unsigned int flags,
336 struct xfs_rmap_irec *irec,
337 int *stat)
338{
339 struct xfs_find_left_neighbor_info info;
340 int error;
341
342 info.high.rm_startblock = bno;
343 info.high.rm_owner = owner;
344 if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK))
345 info.high.rm_offset = offset;
346 else
347 info.high.rm_offset = 0;
348 info.high.rm_flags = flags;
349 info.high.rm_blockcount = 0;
350 *stat = 0;
351 info.irec = irec;
352 info.stat = stat;
353
354 trace_xfs_rmap_lookup_le_range(cur->bc_mp,
355 cur->bc_private.a.agno, bno, 0, owner, offset, flags);
356 error = xfs_rmap_query_range(cur, &info.high, &info.high,
357 xfs_rmap_lookup_le_range_helper, &info);
358 if (error == XFS_BTREE_QUERY_RANGE_ABORT)
359 error = 0;
360 if (*stat)
361 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
362 cur->bc_private.a.agno, irec->rm_startblock,
363 irec->rm_blockcount, irec->rm_owner,
364 irec->rm_offset, irec->rm_flags);
365 return error;
366}
367
183/* 368/*
184 * Find the extent in the rmap btree and remove it. 369 * Find the extent in the rmap btree and remove it.
185 * 370 *
@@ -1098,6 +1283,321 @@ done:
1098#undef RIGHT 1283#undef RIGHT
1099#undef PREV 1284#undef PREV
1100 1285
1286/*
1287 * Find an extent in the rmap btree and unmap it. For rmap extent types that
1288 * can overlap (data fork rmaps on reflink filesystems) we must be careful
1289 * that the prev/next records in the btree might belong to another owner.
1290 * Therefore we must use delete+insert to alter any of the key fields.
1291 *
1292 * For every other situation there can only be one owner for a given extent,
1293 * so we can call the regular _free function.
1294 */
1295STATIC int
1296xfs_rmap_unmap_shared(
1297 struct xfs_btree_cur *cur,
1298 xfs_agblock_t bno,
1299 xfs_extlen_t len,
1300 bool unwritten,
1301 struct xfs_owner_info *oinfo)
1302{
1303 struct xfs_mount *mp = cur->bc_mp;
1304 struct xfs_rmap_irec ltrec;
1305 uint64_t ltoff;
1306 int error = 0;
1307 int i;
1308 uint64_t owner;
1309 uint64_t offset;
1310 unsigned int flags;
1311
1312 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1313 if (unwritten)
1314 flags |= XFS_RMAP_UNWRITTEN;
1315 trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
1316 unwritten, oinfo);
1317
1318 /*
1319 * We should always have a left record because there's a static record
1320 * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
1321 * will not ever be removed from the tree.
1322 */
1323 error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags,
1324 &ltrec, &i);
1325 if (error)
1326 goto out_error;
1327 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
1328 ltoff = ltrec.rm_offset;
1329
1330 /* Make sure the extent we found covers the entire freeing range. */
1331 XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
1332 ltrec.rm_startblock + ltrec.rm_blockcount >=
1333 bno + len, out_error);
1334
1335 /* Make sure the owner matches what we expect to find in the tree. */
1336 XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner, out_error);
1337
1338 /* Make sure the unwritten flag matches. */
1339 XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
1340 (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
1341
1342 /* Check the offset. */
1343 XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_offset <= offset, out_error);
1344 XFS_WANT_CORRUPTED_GOTO(mp, offset <= ltoff + ltrec.rm_blockcount,
1345 out_error);
1346
1347 if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
1348 /* Exact match, simply remove the record from rmap tree. */
1349 error = xfs_rmap_delete(cur, ltrec.rm_startblock,
1350 ltrec.rm_blockcount, ltrec.rm_owner,
1351 ltrec.rm_offset, ltrec.rm_flags);
1352 if (error)
1353 goto out_error;
1354 } else if (ltrec.rm_startblock == bno) {
1355 /*
1356 * Overlap left hand side of extent: move the start, trim the
1357 * length and update the current record.
1358 *
1359 * ltbno ltlen
1360 * Orig: |oooooooooooooooooooo|
1361 * Freeing: |fffffffff|
1362 * Result: |rrrrrrrrrr|
1363 * bno len
1364 */
1365
1366 /* Delete prev rmap. */
1367 error = xfs_rmap_delete(cur, ltrec.rm_startblock,
1368 ltrec.rm_blockcount, ltrec.rm_owner,
1369 ltrec.rm_offset, ltrec.rm_flags);
1370 if (error)
1371 goto out_error;
1372
1373 /* Add an rmap at the new offset. */
1374 ltrec.rm_startblock += len;
1375 ltrec.rm_blockcount -= len;
1376 ltrec.rm_offset += len;
1377 error = xfs_rmap_insert(cur, ltrec.rm_startblock,
1378 ltrec.rm_blockcount, ltrec.rm_owner,
1379 ltrec.rm_offset, ltrec.rm_flags);
1380 if (error)
1381 goto out_error;
1382 } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
1383 /*
1384 * Overlap right hand side of extent: trim the length and
1385 * update the current record.
1386 *
1387 * ltbno ltlen
1388 * Orig: |oooooooooooooooooooo|
1389 * Freeing: |fffffffff|
1390 * Result: |rrrrrrrrrr|
1391 * bno len
1392 */
1393 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
1394 ltrec.rm_blockcount, ltrec.rm_owner,
1395 ltrec.rm_offset, ltrec.rm_flags, &i);
1396 if (error)
1397 goto out_error;
1398 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
1399 ltrec.rm_blockcount -= len;
1400 error = xfs_rmap_update(cur, &ltrec);
1401 if (error)
1402 goto out_error;
1403 } else {
1404 /*
1405 * Overlap middle of extent: trim the length of the existing
1406 * record to the length of the new left-extent size, increment
1407 * the insertion position so we can insert a new record
1408 * containing the remaining right-extent space.
1409 *
1410 * ltbno ltlen
1411 * Orig: |oooooooooooooooooooo|
1412 * Freeing: |fffffffff|
1413 * Result: |rrrrr| |rrrr|
1414 * bno len
1415 */
1416 xfs_extlen_t orig_len = ltrec.rm_blockcount;
1417
1418 /* Shrink the left side of the rmap */
1419 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
1420 ltrec.rm_blockcount, ltrec.rm_owner,
1421 ltrec.rm_offset, ltrec.rm_flags, &i);
1422 if (error)
1423 goto out_error;
1424 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
1425 ltrec.rm_blockcount = bno - ltrec.rm_startblock;
1426 error = xfs_rmap_update(cur, &ltrec);
1427 if (error)
1428 goto out_error;
1429
1430 /* Add an rmap at the new offset */
1431 error = xfs_rmap_insert(cur, bno + len,
1432 orig_len - len - ltrec.rm_blockcount,
1433 ltrec.rm_owner, offset + len,
1434 ltrec.rm_flags);
1435 if (error)
1436 goto out_error;
1437 }
1438
1439 trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
1440 unwritten, oinfo);
1441out_error:
1442 if (error)
1443 trace_xfs_rmap_unmap_error(cur->bc_mp,
1444 cur->bc_private.a.agno, error, _RET_IP_);
1445 return error;
1446}
1447
1448/*
1449 * Find an extent in the rmap btree and map it. For rmap extent types that
1450 * can overlap (data fork rmaps on reflink filesystems) we must be careful
1451 * that the prev/next records in the btree might belong to another owner.
1452 * Therefore we must use delete+insert to alter any of the key fields.
1453 *
1454 * For every other situation there can only be one owner for a given extent,
1455 * so we can call the regular _alloc function.
1456 */
1457STATIC int
1458xfs_rmap_map_shared(
1459 struct xfs_btree_cur *cur,
1460 xfs_agblock_t bno,
1461 xfs_extlen_t len,
1462 bool unwritten,
1463 struct xfs_owner_info *oinfo)
1464{
1465 struct xfs_mount *mp = cur->bc_mp;
1466 struct xfs_rmap_irec ltrec;
1467 struct xfs_rmap_irec gtrec;
1468 int have_gt;
1469 int have_lt;
1470 int error = 0;
1471 int i;
1472 uint64_t owner;
1473 uint64_t offset;
1474 unsigned int flags = 0;
1475
1476 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
1477 if (unwritten)
1478 flags |= XFS_RMAP_UNWRITTEN;
1479 trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
1480 unwritten, oinfo);
1481
1482 /* Is there a left record that abuts our range? */
1483 error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags,
1484 &ltrec, &have_lt);
1485 if (error)
1486 goto out_error;
1487 if (have_lt &&
1488 !xfs_rmap_is_mergeable(&ltrec, owner, flags))
1489 have_lt = 0;
1490
1491 /* Is there a right record that abuts our range? */
1492 error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len,
1493 flags, &have_gt);
1494 if (error)
1495 goto out_error;
1496 if (have_gt) {
1497 error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
1498 if (error)
1499 goto out_error;
1500 XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
1501 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
1502 cur->bc_private.a.agno, gtrec.rm_startblock,
1503 gtrec.rm_blockcount, gtrec.rm_owner,
1504 gtrec.rm_offset, gtrec.rm_flags);
1505
1506 if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
1507 have_gt = 0;
1508 }
1509
1510 if (have_lt &&
1511 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
1512 ltrec.rm_offset + ltrec.rm_blockcount == offset) {
1513 /*
1514 * Left edge contiguous, merge into left record.
1515 *
1516 * ltbno ltlen
1517 * orig: |ooooooooo|
1518 * adding: |aaaaaaaaa|
1519 * result: |rrrrrrrrrrrrrrrrrrr|
1520 * bno len
1521 */
1522 ltrec.rm_blockcount += len;
1523 if (have_gt &&
1524 bno + len == gtrec.rm_startblock &&
1525 offset + len == gtrec.rm_offset) {
1526 /*
1527 * Right edge also contiguous, delete right record
1528 * and merge into left record.
1529 *
1530 * ltbno ltlen gtbno gtlen
1531 * orig: |ooooooooo| |ooooooooo|
1532 * adding: |aaaaaaaaa|
1533 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
1534 */
1535 ltrec.rm_blockcount += gtrec.rm_blockcount;
1536 error = xfs_rmap_delete(cur, gtrec.rm_startblock,
1537 gtrec.rm_blockcount, gtrec.rm_owner,
1538 gtrec.rm_offset, gtrec.rm_flags);
1539 if (error)
1540 goto out_error;
1541 }
1542
1543 /* Point the cursor back to the left record and update. */
1544 error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock,
1545 ltrec.rm_blockcount, ltrec.rm_owner,
1546 ltrec.rm_offset, ltrec.rm_flags, &i);
1547 if (error)
1548 goto out_error;
1549 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
1550
1551 error = xfs_rmap_update(cur, &ltrec);
1552 if (error)
1553 goto out_error;
1554 } else if (have_gt &&
1555 bno + len == gtrec.rm_startblock &&
1556 offset + len == gtrec.rm_offset) {
1557 /*
1558 * Right edge contiguous, merge into right record.
1559 *
1560 * gtbno gtlen
1561 * Orig: |ooooooooo|
1562 * adding: |aaaaaaaaa|
1563 * Result: |rrrrrrrrrrrrrrrrrrr|
1564 * bno len
1565 */
1566 /* Delete the old record. */
1567 error = xfs_rmap_delete(cur, gtrec.rm_startblock,
1568 gtrec.rm_blockcount, gtrec.rm_owner,
1569 gtrec.rm_offset, gtrec.rm_flags);
1570 if (error)
1571 goto out_error;
1572
1573 /* Move the start and re-add it. */
1574 gtrec.rm_startblock = bno;
1575 gtrec.rm_blockcount += len;
1576 gtrec.rm_offset = offset;
1577 error = xfs_rmap_insert(cur, gtrec.rm_startblock,
1578 gtrec.rm_blockcount, gtrec.rm_owner,
1579 gtrec.rm_offset, gtrec.rm_flags);
1580 if (error)
1581 goto out_error;
1582 } else {
1583 /*
1584 * No contiguous edge with identical owner, insert
1585 * new record at current cursor position.
1586 */
1587 error = xfs_rmap_insert(cur, bno, len, owner, offset, flags);
1588 if (error)
1589 goto out_error;
1590 }
1591
1592 trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
1593 unwritten, oinfo);
1594out_error:
1595 if (error)
1596 trace_xfs_rmap_map_error(cur->bc_mp,
1597 cur->bc_private.a.agno, error, _RET_IP_);
1598 return error;
1599}
1600
1101struct xfs_rmap_query_range_info { 1601struct xfs_rmap_query_range_info {
1102 xfs_rmap_query_range_fn fn; 1602 xfs_rmap_query_range_fn fn;
1103 void *priv; 1603 void *priv;
@@ -1237,11 +1737,19 @@ xfs_rmap_finish_one(
1237 case XFS_RMAP_MAP: 1737 case XFS_RMAP_MAP:
1238 error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo); 1738 error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo);
1239 break; 1739 break;
1740 case XFS_RMAP_MAP_SHARED:
1741 error = xfs_rmap_map_shared(rcur, bno, blockcount, unwritten,
1742 &oinfo);
1743 break;
1240 case XFS_RMAP_FREE: 1744 case XFS_RMAP_FREE:
1241 case XFS_RMAP_UNMAP: 1745 case XFS_RMAP_UNMAP:
1242 error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten, 1746 error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten,
1243 &oinfo); 1747 &oinfo);
1244 break; 1748 break;
1749 case XFS_RMAP_UNMAP_SHARED:
1750 error = xfs_rmap_unmap_shared(rcur, bno, blockcount, unwritten,
1751 &oinfo);
1752 break;
1245 case XFS_RMAP_CONVERT: 1753 case XFS_RMAP_CONVERT:
1246 error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten, 1754 error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten,
1247 &oinfo); 1755 &oinfo);
@@ -1315,7 +1823,8 @@ xfs_rmap_map_extent(
1315 if (!xfs_rmap_update_is_needed(mp, whichfork)) 1823 if (!xfs_rmap_update_is_needed(mp, whichfork))
1316 return 0; 1824 return 0;
1317 1825
1318 return __xfs_rmap_add(mp, dfops, XFS_RMAP_MAP, ip->i_ino, 1826 return __xfs_rmap_add(mp, dfops, xfs_is_reflink_inode(ip) ?
1827 XFS_RMAP_MAP_SHARED : XFS_RMAP_MAP, ip->i_ino,
1319 whichfork, PREV); 1828 whichfork, PREV);
1320} 1829}
1321 1830
@@ -1331,7 +1840,8 @@ xfs_rmap_unmap_extent(
1331 if (!xfs_rmap_update_is_needed(mp, whichfork)) 1840 if (!xfs_rmap_update_is_needed(mp, whichfork))
1332 return 0; 1841 return 0;
1333 1842
1334 return __xfs_rmap_add(mp, dfops, XFS_RMAP_UNMAP, ip->i_ino, 1843 return __xfs_rmap_add(mp, dfops, xfs_is_reflink_inode(ip) ?
1844 XFS_RMAP_UNMAP_SHARED : XFS_RMAP_UNMAP, ip->i_ino,
1335 whichfork, PREV); 1845 whichfork, PREV);
1336} 1846}
1337 1847
diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
index 71cf99a4acba..789930599339 100644
--- a/fs/xfs/libxfs/xfs_rmap.h
+++ b/fs/xfs/libxfs/xfs_rmap.h
@@ -206,4 +206,11 @@ int xfs_rmap_finish_one(struct xfs_trans *tp, enum xfs_rmap_intent_type type,
206 xfs_fsblock_t startblock, xfs_filblks_t blockcount, 206 xfs_fsblock_t startblock, xfs_filblks_t blockcount,
207 xfs_exntst_t state, struct xfs_btree_cur **pcur); 207 xfs_exntst_t state, struct xfs_btree_cur **pcur);
208 208
209int xfs_rmap_find_left_neighbor(struct xfs_btree_cur *cur, xfs_agblock_t bno,
210 uint64_t owner, uint64_t offset, unsigned int flags,
211 struct xfs_rmap_irec *irec, int *stat);
212int xfs_rmap_lookup_le_range(struct xfs_btree_cur *cur, xfs_agblock_t bno,
213 uint64_t owner, uint64_t offset, unsigned int flags,
214 struct xfs_rmap_irec *irec, int *stat);
215
209#endif /* __XFS_RMAP_H__ */ 216#endif /* __XFS_RMAP_H__ */
diff --git a/fs/xfs/xfs_rmap_item.c b/fs/xfs/xfs_rmap_item.c
index 19d817e3e1d9..3b8742e48815 100644
--- a/fs/xfs/xfs_rmap_item.c
+++ b/fs/xfs/xfs_rmap_item.c
@@ -484,9 +484,15 @@ xfs_rui_recover(
484 case XFS_RMAP_EXTENT_MAP: 484 case XFS_RMAP_EXTENT_MAP:
485 type = XFS_RMAP_MAP; 485 type = XFS_RMAP_MAP;
486 break; 486 break;
487 case XFS_RMAP_EXTENT_MAP_SHARED:
488 type = XFS_RMAP_MAP_SHARED;
489 break;
487 case XFS_RMAP_EXTENT_UNMAP: 490 case XFS_RMAP_EXTENT_UNMAP:
488 type = XFS_RMAP_UNMAP; 491 type = XFS_RMAP_UNMAP;
489 break; 492 break;
493 case XFS_RMAP_EXTENT_UNMAP_SHARED:
494 type = XFS_RMAP_UNMAP_SHARED;
495 break;
490 case XFS_RMAP_EXTENT_CONVERT: 496 case XFS_RMAP_EXTENT_CONVERT:
491 type = XFS_RMAP_CONVERT; 497 type = XFS_RMAP_CONVERT;
492 break; 498 break;
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 263dab10c982..75bf18bc275b 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -2588,6 +2588,11 @@ DEFINE_RMAPBT_EVENT(xfs_rmap_delete);
2588DEFINE_AG_ERROR_EVENT(xfs_rmap_insert_error); 2588DEFINE_AG_ERROR_EVENT(xfs_rmap_insert_error);
2589DEFINE_AG_ERROR_EVENT(xfs_rmap_delete_error); 2589DEFINE_AG_ERROR_EVENT(xfs_rmap_delete_error);
2590DEFINE_AG_ERROR_EVENT(xfs_rmap_update_error); 2590DEFINE_AG_ERROR_EVENT(xfs_rmap_update_error);
2591
2592DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_candidate);
2593DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_query);
2594DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_candidate);
2595DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range);
2591DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result); 2596DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result);
2592DEFINE_RMAPBT_EVENT(xfs_rmap_find_right_neighbor_result); 2597DEFINE_RMAPBT_EVENT(xfs_rmap_find_right_neighbor_result);
2593DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_result); 2598DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_result);