xfs_rmap.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /*
  2. * Copyright (c) 2014 Red Hat, Inc.
  3. * All Rights Reserved.
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it would be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write the Free Software Foundation,
  16. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "xfs.h"
  19. #include "xfs_fs.h"
  20. #include "xfs_shared.h"
  21. #include "xfs_format.h"
  22. #include "xfs_log_format.h"
  23. #include "xfs_trans_resv.h"
  24. #include "xfs_bit.h"
  25. #include "xfs_sb.h"
  26. #include "xfs_mount.h"
  27. #include "xfs_defer.h"
  28. #include "xfs_da_format.h"
  29. #include "xfs_da_btree.h"
  30. #include "xfs_btree.h"
  31. #include "xfs_trans.h"
  32. #include "xfs_alloc.h"
  33. #include "xfs_rmap.h"
  34. #include "xfs_rmap_btree.h"
  35. #include "xfs_trans_space.h"
  36. #include "xfs_trace.h"
  37. #include "xfs_error.h"
  38. #include "xfs_extent_busy.h"
  39. /*
  40. * Lookup the first record less than or equal to [bno, len, owner, offset]
  41. * in the btree given by cur.
  42. */
  43. int
  44. xfs_rmap_lookup_le(
  45. struct xfs_btree_cur *cur,
  46. xfs_agblock_t bno,
  47. xfs_extlen_t len,
  48. uint64_t owner,
  49. uint64_t offset,
  50. unsigned int flags,
  51. int *stat)
  52. {
  53. cur->bc_rec.r.rm_startblock = bno;
  54. cur->bc_rec.r.rm_blockcount = len;
  55. cur->bc_rec.r.rm_owner = owner;
  56. cur->bc_rec.r.rm_offset = offset;
  57. cur->bc_rec.r.rm_flags = flags;
  58. return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat);
  59. }
  60. /*
  61. * Lookup the record exactly matching [bno, len, owner, offset]
  62. * in the btree given by cur.
  63. */
  64. int
  65. xfs_rmap_lookup_eq(
  66. struct xfs_btree_cur *cur,
  67. xfs_agblock_t bno,
  68. xfs_extlen_t len,
  69. uint64_t owner,
  70. uint64_t offset,
  71. unsigned int flags,
  72. int *stat)
  73. {
  74. cur->bc_rec.r.rm_startblock = bno;
  75. cur->bc_rec.r.rm_blockcount = len;
  76. cur->bc_rec.r.rm_owner = owner;
  77. cur->bc_rec.r.rm_offset = offset;
  78. cur->bc_rec.r.rm_flags = flags;
  79. return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat);
  80. }
  81. /*
  82. * Update the record referred to by cur to the value given
  83. * by [bno, len, owner, offset].
  84. * This either works (return 0) or gets an EFSCORRUPTED error.
  85. */
  86. STATIC int
  87. xfs_rmap_update(
  88. struct xfs_btree_cur *cur,
  89. struct xfs_rmap_irec *irec)
  90. {
  91. union xfs_btree_rec rec;
  92. int error;
  93. trace_xfs_rmap_update(cur->bc_mp, cur->bc_private.a.agno,
  94. irec->rm_startblock, irec->rm_blockcount,
  95. irec->rm_owner, irec->rm_offset, irec->rm_flags);
  96. rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock);
  97. rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount);
  98. rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner);
  99. rec.rmap.rm_offset = cpu_to_be64(
  100. xfs_rmap_irec_offset_pack(irec));
  101. error = xfs_btree_update(cur, &rec);
  102. if (error)
  103. trace_xfs_rmap_update_error(cur->bc_mp,
  104. cur->bc_private.a.agno, error, _RET_IP_);
  105. return error;
  106. }
  107. int
  108. xfs_rmap_insert(
  109. struct xfs_btree_cur *rcur,
  110. xfs_agblock_t agbno,
  111. xfs_extlen_t len,
  112. uint64_t owner,
  113. uint64_t offset,
  114. unsigned int flags)
  115. {
  116. int i;
  117. int error;
  118. trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, agbno,
  119. len, owner, offset, flags);
  120. error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
  121. if (error)
  122. goto done;
  123. XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 0, done);
  124. rcur->bc_rec.r.rm_startblock = agbno;
  125. rcur->bc_rec.r.rm_blockcount = len;
  126. rcur->bc_rec.r.rm_owner = owner;
  127. rcur->bc_rec.r.rm_offset = offset;
  128. rcur->bc_rec.r.rm_flags = flags;
  129. error = xfs_btree_insert(rcur, &i);
  130. if (error)
  131. goto done;
  132. XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done);
  133. done:
  134. if (error)
  135. trace_xfs_rmap_insert_error(rcur->bc_mp,
  136. rcur->bc_private.a.agno, error, _RET_IP_);
  137. return error;
  138. }
  139. static int
  140. xfs_rmap_btrec_to_irec(
  141. union xfs_btree_rec *rec,
  142. struct xfs_rmap_irec *irec)
  143. {
  144. irec->rm_flags = 0;
  145. irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock);
  146. irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount);
  147. irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner);
  148. return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset),
  149. irec);
  150. }
  151. /*
  152. * Get the data from the pointed-to record.
  153. */
  154. int
  155. xfs_rmap_get_rec(
  156. struct xfs_btree_cur *cur,
  157. struct xfs_rmap_irec *irec,
  158. int *stat)
  159. {
  160. union xfs_btree_rec *rec;
  161. int error;
  162. error = xfs_btree_get_rec(cur, &rec, stat);
  163. if (error || !*stat)
  164. return error;
  165. return xfs_rmap_btrec_to_irec(rec, irec);
  166. }
  167. /*
  168. * Find the extent in the rmap btree and remove it.
  169. *
  170. * The record we find should always be an exact match for the extent that we're
  171. * looking for, since we insert them into the btree without modification.
  172. *
  173. * Special Case #1: when growing the filesystem, we "free" an extent when
  174. * growing the last AG. This extent is new space and so it is not tracked as
  175. * used space in the btree. The growfs code will pass in an owner of
  176. * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this
  177. * extent. We verify that - the extent lookup result in a record that does not
  178. * overlap.
  179. *
  180. * Special Case #2: EFIs do not record the owner of the extent, so when
  181. * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap
  182. * btree to ignore the owner (i.e. wildcard match) so we don't trigger
  183. * corruption checks during log recovery.
  184. */
  185. STATIC int
  186. xfs_rmap_unmap(
  187. struct xfs_btree_cur *cur,
  188. xfs_agblock_t bno,
  189. xfs_extlen_t len,
  190. bool unwritten,
  191. struct xfs_owner_info *oinfo)
  192. {
  193. struct xfs_mount *mp = cur->bc_mp;
  194. struct xfs_rmap_irec ltrec;
  195. uint64_t ltoff;
  196. int error = 0;
  197. int i;
  198. uint64_t owner;
  199. uint64_t offset;
  200. unsigned int flags;
  201. bool ignore_off;
  202. xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
  203. ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
  204. (flags & XFS_RMAP_BMBT_BLOCK);
  205. if (unwritten)
  206. flags |= XFS_RMAP_UNWRITTEN;
  207. trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len,
  208. unwritten, oinfo);
  209. /*
  210. * We should always have a left record because there's a static record
  211. * for the AG headers at rm_startblock == 0 created by mkfs/growfs that
  212. * will not ever be removed from the tree.
  213. */
  214. error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i);
  215. if (error)
  216. goto out_error;
  217. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
  218. error = xfs_rmap_get_rec(cur, &ltrec, &i);
  219. if (error)
  220. goto out_error;
  221. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
  222. trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
  223. cur->bc_private.a.agno, ltrec.rm_startblock,
  224. ltrec.rm_blockcount, ltrec.rm_owner,
  225. ltrec.rm_offset, ltrec.rm_flags);
  226. ltoff = ltrec.rm_offset;
  227. /*
  228. * For growfs, the incoming extent must be beyond the left record we
  229. * just found as it is new space and won't be used by anyone. This is
  230. * just a corruption check as we don't actually do anything with this
  231. * extent. Note that we need to use >= instead of > because it might
  232. * be the case that the "left" extent goes all the way to EOFS.
  233. */
  234. if (owner == XFS_RMAP_OWN_NULL) {
  235. XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock +
  236. ltrec.rm_blockcount, out_error);
  237. goto out_done;
  238. }
  239. /* Make sure the unwritten flag matches. */
  240. XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) ==
  241. (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error);
  242. /* Make sure the extent we found covers the entire freeing range. */
  243. XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
  244. ltrec.rm_startblock + ltrec.rm_blockcount >=
  245. bno + len, out_error);
  246. /* Make sure the owner matches what we expect to find in the tree. */
  247. XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner ||
  248. XFS_RMAP_NON_INODE_OWNER(owner), out_error);
  249. /* Check the offset, if necessary. */
  250. if (!XFS_RMAP_NON_INODE_OWNER(owner)) {
  251. if (flags & XFS_RMAP_BMBT_BLOCK) {
  252. XFS_WANT_CORRUPTED_GOTO(mp,
  253. ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK,
  254. out_error);
  255. } else {
  256. XFS_WANT_CORRUPTED_GOTO(mp,
  257. ltrec.rm_offset <= offset, out_error);
  258. XFS_WANT_CORRUPTED_GOTO(mp,
  259. ltoff + ltrec.rm_blockcount >= offset + len,
  260. out_error);
  261. }
  262. }
  263. if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
  264. /* exact match, simply remove the record from rmap tree */
  265. trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
  266. ltrec.rm_startblock, ltrec.rm_blockcount,
  267. ltrec.rm_owner, ltrec.rm_offset,
  268. ltrec.rm_flags);
  269. error = xfs_btree_delete(cur, &i);
  270. if (error)
  271. goto out_error;
  272. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
  273. } else if (ltrec.rm_startblock == bno) {
  274. /*
  275. * overlap left hand side of extent: move the start, trim the
  276. * length and update the current record.
  277. *
  278. * ltbno ltlen
  279. * Orig: |oooooooooooooooooooo|
  280. * Freeing: |fffffffff|
  281. * Result: |rrrrrrrrrr|
  282. * bno len
  283. */
  284. ltrec.rm_startblock += len;
  285. ltrec.rm_blockcount -= len;
  286. if (!ignore_off)
  287. ltrec.rm_offset += len;
  288. error = xfs_rmap_update(cur, &ltrec);
  289. if (error)
  290. goto out_error;
  291. } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) {
  292. /*
  293. * overlap right hand side of extent: trim the length and update
  294. * the current record.
  295. *
  296. * ltbno ltlen
  297. * Orig: |oooooooooooooooooooo|
  298. * Freeing: |fffffffff|
  299. * Result: |rrrrrrrrrr|
  300. * bno len
  301. */
  302. ltrec.rm_blockcount -= len;
  303. error = xfs_rmap_update(cur, &ltrec);
  304. if (error)
  305. goto out_error;
  306. } else {
  307. /*
  308. * overlap middle of extent: trim the length of the existing
  309. * record to the length of the new left-extent size, increment
  310. * the insertion position so we can insert a new record
  311. * containing the remaining right-extent space.
  312. *
  313. * ltbno ltlen
  314. * Orig: |oooooooooooooooooooo|
  315. * Freeing: |fffffffff|
  316. * Result: |rrrrr| |rrrr|
  317. * bno len
  318. */
  319. xfs_extlen_t orig_len = ltrec.rm_blockcount;
  320. ltrec.rm_blockcount = bno - ltrec.rm_startblock;
  321. error = xfs_rmap_update(cur, &ltrec);
  322. if (error)
  323. goto out_error;
  324. error = xfs_btree_increment(cur, 0, &i);
  325. if (error)
  326. goto out_error;
  327. cur->bc_rec.r.rm_startblock = bno + len;
  328. cur->bc_rec.r.rm_blockcount = orig_len - len -
  329. ltrec.rm_blockcount;
  330. cur->bc_rec.r.rm_owner = ltrec.rm_owner;
  331. if (ignore_off)
  332. cur->bc_rec.r.rm_offset = 0;
  333. else
  334. cur->bc_rec.r.rm_offset = offset + len;
  335. cur->bc_rec.r.rm_flags = flags;
  336. trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
  337. cur->bc_rec.r.rm_startblock,
  338. cur->bc_rec.r.rm_blockcount,
  339. cur->bc_rec.r.rm_owner,
  340. cur->bc_rec.r.rm_offset,
  341. cur->bc_rec.r.rm_flags);
  342. error = xfs_btree_insert(cur, &i);
  343. if (error)
  344. goto out_error;
  345. }
  346. out_done:
  347. trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len,
  348. unwritten, oinfo);
  349. out_error:
  350. if (error)
  351. trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno,
  352. error, _RET_IP_);
  353. return error;
  354. }
  355. /*
  356. * Remove a reference to an extent in the rmap btree.
  357. */
  358. int
  359. xfs_rmap_free(
  360. struct xfs_trans *tp,
  361. struct xfs_buf *agbp,
  362. xfs_agnumber_t agno,
  363. xfs_agblock_t bno,
  364. xfs_extlen_t len,
  365. struct xfs_owner_info *oinfo)
  366. {
  367. struct xfs_mount *mp = tp->t_mountp;
  368. struct xfs_btree_cur *cur;
  369. int error;
  370. if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
  371. return 0;
  372. cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
  373. error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
  374. if (error)
  375. goto out_error;
  376. xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
  377. return 0;
  378. out_error:
  379. xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
  380. return error;
  381. }
  382. /*
  383. * A mergeable rmap must have the same owner and the same values for
  384. * the unwritten, attr_fork, and bmbt flags. The startblock and
  385. * offset are checked separately.
  386. */
  387. static bool
  388. xfs_rmap_is_mergeable(
  389. struct xfs_rmap_irec *irec,
  390. uint64_t owner,
  391. unsigned int flags)
  392. {
  393. if (irec->rm_owner == XFS_RMAP_OWN_NULL)
  394. return false;
  395. if (irec->rm_owner != owner)
  396. return false;
  397. if ((flags & XFS_RMAP_UNWRITTEN) ^
  398. (irec->rm_flags & XFS_RMAP_UNWRITTEN))
  399. return false;
  400. if ((flags & XFS_RMAP_ATTR_FORK) ^
  401. (irec->rm_flags & XFS_RMAP_ATTR_FORK))
  402. return false;
  403. if ((flags & XFS_RMAP_BMBT_BLOCK) ^
  404. (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
  405. return false;
  406. return true;
  407. }
  408. /*
  409. * When we allocate a new block, the first thing we do is add a reference to
  410. * the extent in the rmap btree. This takes the form of a [agbno, length,
  411. * owner, offset] record. Flags are encoded in the high bits of the offset
  412. * field.
  413. */
  414. STATIC int
  415. xfs_rmap_map(
  416. struct xfs_btree_cur *cur,
  417. xfs_agblock_t bno,
  418. xfs_extlen_t len,
  419. bool unwritten,
  420. struct xfs_owner_info *oinfo)
  421. {
  422. struct xfs_mount *mp = cur->bc_mp;
  423. struct xfs_rmap_irec ltrec;
  424. struct xfs_rmap_irec gtrec;
  425. int have_gt;
  426. int have_lt;
  427. int error = 0;
  428. int i;
  429. uint64_t owner;
  430. uint64_t offset;
  431. unsigned int flags = 0;
  432. bool ignore_off;
  433. xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
  434. ASSERT(owner != 0);
  435. ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
  436. (flags & XFS_RMAP_BMBT_BLOCK);
  437. if (unwritten)
  438. flags |= XFS_RMAP_UNWRITTEN;
  439. trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
  440. unwritten, oinfo);
  441. /*
  442. * For the initial lookup, look for an exact match or the left-adjacent
  443. * record for our insertion point. This will also give us the record for
  444. * start block contiguity tests.
  445. */
  446. error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
  447. &have_lt);
  448. if (error)
  449. goto out_error;
  450. XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
  451. error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
  452. if (error)
  453. goto out_error;
  454. XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
  455. trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
  456. cur->bc_private.a.agno, ltrec.rm_startblock,
  457. ltrec.rm_blockcount, ltrec.rm_owner,
  458. ltrec.rm_offset, ltrec.rm_flags);
  459. if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
  460. have_lt = 0;
  461. XFS_WANT_CORRUPTED_GOTO(mp,
  462. have_lt == 0 ||
  463. ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error);
  464. /*
  465. * Increment the cursor to see if we have a right-adjacent record to our
  466. * insertion point. This will give us the record for end block
  467. * contiguity tests.
  468. */
  469. error = xfs_btree_increment(cur, 0, &have_gt);
  470. if (error)
  471. goto out_error;
  472. if (have_gt) {
  473. error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
  474. if (error)
  475. goto out_error;
  476. XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
  477. XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock,
  478. out_error);
  479. trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
  480. cur->bc_private.a.agno, gtrec.rm_startblock,
  481. gtrec.rm_blockcount, gtrec.rm_owner,
  482. gtrec.rm_offset, gtrec.rm_flags);
  483. if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
  484. have_gt = 0;
  485. }
  486. /*
  487. * Note: cursor currently points one record to the right of ltrec, even
  488. * if there is no record in the tree to the right.
  489. */
  490. if (have_lt &&
  491. ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
  492. (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
  493. /*
  494. * left edge contiguous, merge into left record.
  495. *
  496. * ltbno ltlen
  497. * orig: |ooooooooo|
  498. * adding: |aaaaaaaaa|
  499. * result: |rrrrrrrrrrrrrrrrrrr|
  500. * bno len
  501. */
  502. ltrec.rm_blockcount += len;
  503. if (have_gt &&
  504. bno + len == gtrec.rm_startblock &&
  505. (ignore_off || offset + len == gtrec.rm_offset) &&
  506. (unsigned long)ltrec.rm_blockcount + len +
  507. gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
  508. /*
  509. * right edge also contiguous, delete right record
  510. * and merge into left record.
  511. *
  512. * ltbno ltlen gtbno gtlen
  513. * orig: |ooooooooo| |ooooooooo|
  514. * adding: |aaaaaaaaa|
  515. * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
  516. */
  517. ltrec.rm_blockcount += gtrec.rm_blockcount;
  518. trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
  519. gtrec.rm_startblock,
  520. gtrec.rm_blockcount,
  521. gtrec.rm_owner,
  522. gtrec.rm_offset,
  523. gtrec.rm_flags);
  524. error = xfs_btree_delete(cur, &i);
  525. if (error)
  526. goto out_error;
  527. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
  528. }
  529. /* point the cursor back to the left record and update */
  530. error = xfs_btree_decrement(cur, 0, &have_gt);
  531. if (error)
  532. goto out_error;
  533. error = xfs_rmap_update(cur, &ltrec);
  534. if (error)
  535. goto out_error;
  536. } else if (have_gt &&
  537. bno + len == gtrec.rm_startblock &&
  538. (ignore_off || offset + len == gtrec.rm_offset)) {
  539. /*
  540. * right edge contiguous, merge into right record.
  541. *
  542. * gtbno gtlen
  543. * Orig: |ooooooooo|
  544. * adding: |aaaaaaaaa|
  545. * Result: |rrrrrrrrrrrrrrrrrrr|
  546. * bno len
  547. */
  548. gtrec.rm_startblock = bno;
  549. gtrec.rm_blockcount += len;
  550. if (!ignore_off)
  551. gtrec.rm_offset = offset;
  552. error = xfs_rmap_update(cur, &gtrec);
  553. if (error)
  554. goto out_error;
  555. } else {
  556. /*
  557. * no contiguous edge with identical owner, insert
  558. * new record at current cursor position.
  559. */
  560. cur->bc_rec.r.rm_startblock = bno;
  561. cur->bc_rec.r.rm_blockcount = len;
  562. cur->bc_rec.r.rm_owner = owner;
  563. cur->bc_rec.r.rm_offset = offset;
  564. cur->bc_rec.r.rm_flags = flags;
  565. trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
  566. owner, offset, flags);
  567. error = xfs_btree_insert(cur, &i);
  568. if (error)
  569. goto out_error;
  570. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
  571. }
  572. trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
  573. unwritten, oinfo);
  574. out_error:
  575. if (error)
  576. trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno,
  577. error, _RET_IP_);
  578. return error;
  579. }
  580. /*
  581. * Add a reference to an extent in the rmap btree.
  582. */
  583. int
  584. xfs_rmap_alloc(
  585. struct xfs_trans *tp,
  586. struct xfs_buf *agbp,
  587. xfs_agnumber_t agno,
  588. xfs_agblock_t bno,
  589. xfs_extlen_t len,
  590. struct xfs_owner_info *oinfo)
  591. {
  592. struct xfs_mount *mp = tp->t_mountp;
  593. struct xfs_btree_cur *cur;
  594. int error;
  595. if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
  596. return 0;
  597. cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
  598. error = xfs_rmap_map(cur, bno, len, false, oinfo);
  599. if (error)
  600. goto out_error;
  601. xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
  602. return 0;
  603. out_error:
  604. xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
  605. return error;
  606. }
  607. #define RMAP_LEFT_CONTIG (1 << 0)
  608. #define RMAP_RIGHT_CONTIG (1 << 1)
  609. #define RMAP_LEFT_FILLING (1 << 2)
  610. #define RMAP_RIGHT_FILLING (1 << 3)
  611. #define RMAP_LEFT_VALID (1 << 6)
  612. #define RMAP_RIGHT_VALID (1 << 7)
  613. #define LEFT r[0]
  614. #define RIGHT r[1]
  615. #define PREV r[2]
  616. #define NEW r[3]
  617. /*
  618. * Convert an unwritten extent to a real extent or vice versa.
  619. * Does not handle overlapping extents.
  620. */
  621. STATIC int
  622. xfs_rmap_convert(
  623. struct xfs_btree_cur *cur,
  624. xfs_agblock_t bno,
  625. xfs_extlen_t len,
  626. bool unwritten,
  627. struct xfs_owner_info *oinfo)
  628. {
  629. struct xfs_mount *mp = cur->bc_mp;
  630. struct xfs_rmap_irec r[4]; /* neighbor extent entries */
  631. /* left is 0, right is 1, prev is 2 */
  632. /* new is 3 */
  633. uint64_t owner;
  634. uint64_t offset;
  635. uint64_t new_endoff;
  636. unsigned int oldext;
  637. unsigned int newext;
  638. unsigned int flags = 0;
  639. int i;
  640. int state = 0;
  641. int error;
  642. xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
  643. ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) ||
  644. (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
  645. oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
  646. new_endoff = offset + len;
  647. trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len,
  648. unwritten, oinfo);
  649. /*
  650. * For the initial lookup, look for an exact match or the left-adjacent
  651. * record for our insertion point. This will also give us the record for
  652. * start block contiguity tests.
  653. */
  654. error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
  655. if (error)
  656. goto done;
  657. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  658. error = xfs_rmap_get_rec(cur, &PREV, &i);
  659. if (error)
  660. goto done;
  661. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  662. trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
  663. cur->bc_private.a.agno, PREV.rm_startblock,
  664. PREV.rm_blockcount, PREV.rm_owner,
  665. PREV.rm_offset, PREV.rm_flags);
  666. ASSERT(PREV.rm_offset <= offset);
  667. ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff);
  668. ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext);
  669. newext = ~oldext & XFS_RMAP_UNWRITTEN;
  670. /*
  671. * Set flags determining what part of the previous oldext allocation
  672. * extent is being replaced by a newext allocation.
  673. */
  674. if (PREV.rm_offset == offset)
  675. state |= RMAP_LEFT_FILLING;
  676. if (PREV.rm_offset + PREV.rm_blockcount == new_endoff)
  677. state |= RMAP_RIGHT_FILLING;
  678. /*
  679. * Decrement the cursor to see if we have a left-adjacent record to our
  680. * insertion point. This will give us the record for end block
  681. * contiguity tests.
  682. */
  683. error = xfs_btree_decrement(cur, 0, &i);
  684. if (error)
  685. goto done;
  686. if (i) {
  687. state |= RMAP_LEFT_VALID;
  688. error = xfs_rmap_get_rec(cur, &LEFT, &i);
  689. if (error)
  690. goto done;
  691. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  692. XFS_WANT_CORRUPTED_GOTO(mp,
  693. LEFT.rm_startblock + LEFT.rm_blockcount <= bno,
  694. done);
  695. trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
  696. cur->bc_private.a.agno, LEFT.rm_startblock,
  697. LEFT.rm_blockcount, LEFT.rm_owner,
  698. LEFT.rm_offset, LEFT.rm_flags);
  699. if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
  700. LEFT.rm_offset + LEFT.rm_blockcount == offset &&
  701. xfs_rmap_is_mergeable(&LEFT, owner, newext))
  702. state |= RMAP_LEFT_CONTIG;
  703. }
  704. /*
  705. * Increment the cursor to see if we have a right-adjacent record to our
  706. * insertion point. This will give us the record for end block
  707. * contiguity tests.
  708. */
  709. error = xfs_btree_increment(cur, 0, &i);
  710. if (error)
  711. goto done;
  712. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  713. error = xfs_btree_increment(cur, 0, &i);
  714. if (error)
  715. goto done;
  716. if (i) {
  717. state |= RMAP_RIGHT_VALID;
  718. error = xfs_rmap_get_rec(cur, &RIGHT, &i);
  719. if (error)
  720. goto done;
  721. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  722. XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock,
  723. done);
  724. trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
  725. cur->bc_private.a.agno, RIGHT.rm_startblock,
  726. RIGHT.rm_blockcount, RIGHT.rm_owner,
  727. RIGHT.rm_offset, RIGHT.rm_flags);
  728. if (bno + len == RIGHT.rm_startblock &&
  729. offset + len == RIGHT.rm_offset &&
  730. xfs_rmap_is_mergeable(&RIGHT, owner, newext))
  731. state |= RMAP_RIGHT_CONTIG;
  732. }
  733. /* check that left + prev + right is not too long */
  734. if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
  735. RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) ==
  736. (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
  737. RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) &&
  738. (unsigned long)LEFT.rm_blockcount + len +
  739. RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
  740. state &= ~RMAP_RIGHT_CONTIG;
  741. trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state,
  742. _RET_IP_);
  743. /* reset the cursor back to PREV */
  744. error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i);
  745. if (error)
  746. goto done;
  747. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  748. /*
  749. * Switch out based on the FILLING and CONTIG state bits.
  750. */
  751. switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
  752. RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) {
  753. case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG |
  754. RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
  755. /*
  756. * Setting all of a previous oldext extent to newext.
  757. * The left and right neighbors are both contiguous with new.
  758. */
  759. error = xfs_btree_increment(cur, 0, &i);
  760. if (error)
  761. goto done;
  762. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  763. trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
  764. RIGHT.rm_startblock, RIGHT.rm_blockcount,
  765. RIGHT.rm_owner, RIGHT.rm_offset,
  766. RIGHT.rm_flags);
  767. error = xfs_btree_delete(cur, &i);
  768. if (error)
  769. goto done;
  770. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  771. error = xfs_btree_decrement(cur, 0, &i);
  772. if (error)
  773. goto done;
  774. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  775. trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
  776. PREV.rm_startblock, PREV.rm_blockcount,
  777. PREV.rm_owner, PREV.rm_offset,
  778. PREV.rm_flags);
  779. error = xfs_btree_delete(cur, &i);
  780. if (error)
  781. goto done;
  782. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  783. error = xfs_btree_decrement(cur, 0, &i);
  784. if (error)
  785. goto done;
  786. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  787. NEW = LEFT;
  788. NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount;
  789. error = xfs_rmap_update(cur, &NEW);
  790. if (error)
  791. goto done;
  792. break;
  793. case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
  794. /*
  795. * Setting all of a previous oldext extent to newext.
  796. * The left neighbor is contiguous, the right is not.
  797. */
  798. trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
  799. PREV.rm_startblock, PREV.rm_blockcount,
  800. PREV.rm_owner, PREV.rm_offset,
  801. PREV.rm_flags);
  802. error = xfs_btree_delete(cur, &i);
  803. if (error)
  804. goto done;
  805. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  806. error = xfs_btree_decrement(cur, 0, &i);
  807. if (error)
  808. goto done;
  809. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  810. NEW = LEFT;
  811. NEW.rm_blockcount += PREV.rm_blockcount;
  812. error = xfs_rmap_update(cur, &NEW);
  813. if (error)
  814. goto done;
  815. break;
  816. case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
  817. /*
  818. * Setting all of a previous oldext extent to newext.
  819. * The right neighbor is contiguous, the left is not.
  820. */
  821. error = xfs_btree_increment(cur, 0, &i);
  822. if (error)
  823. goto done;
  824. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  825. trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
  826. RIGHT.rm_startblock, RIGHT.rm_blockcount,
  827. RIGHT.rm_owner, RIGHT.rm_offset,
  828. RIGHT.rm_flags);
  829. error = xfs_btree_delete(cur, &i);
  830. if (error)
  831. goto done;
  832. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  833. error = xfs_btree_decrement(cur, 0, &i);
  834. if (error)
  835. goto done;
  836. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  837. NEW = PREV;
  838. NEW.rm_blockcount = len + RIGHT.rm_blockcount;
  839. NEW.rm_flags = newext;
  840. error = xfs_rmap_update(cur, &NEW);
  841. if (error)
  842. goto done;
  843. break;
  844. case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING:
  845. /*
  846. * Setting all of a previous oldext extent to newext.
  847. * Neither the left nor right neighbors are contiguous with
  848. * the new one.
  849. */
  850. NEW = PREV;
  851. NEW.rm_flags = newext;
  852. error = xfs_rmap_update(cur, &NEW);
  853. if (error)
  854. goto done;
  855. break;
  856. case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG:
  857. /*
  858. * Setting the first part of a previous oldext extent to newext.
  859. * The left neighbor is contiguous.
  860. */
  861. NEW = PREV;
  862. NEW.rm_offset += len;
  863. NEW.rm_startblock += len;
  864. NEW.rm_blockcount -= len;
  865. error = xfs_rmap_update(cur, &NEW);
  866. if (error)
  867. goto done;
  868. error = xfs_btree_decrement(cur, 0, &i);
  869. if (error)
  870. goto done;
  871. NEW = LEFT;
  872. NEW.rm_blockcount += len;
  873. error = xfs_rmap_update(cur, &NEW);
  874. if (error)
  875. goto done;
  876. break;
  877. case RMAP_LEFT_FILLING:
  878. /*
  879. * Setting the first part of a previous oldext extent to newext.
  880. * The left neighbor is not contiguous.
  881. */
  882. NEW = PREV;
  883. NEW.rm_startblock += len;
  884. NEW.rm_offset += len;
  885. NEW.rm_blockcount -= len;
  886. error = xfs_rmap_update(cur, &NEW);
  887. if (error)
  888. goto done;
  889. NEW.rm_startblock = bno;
  890. NEW.rm_owner = owner;
  891. NEW.rm_offset = offset;
  892. NEW.rm_blockcount = len;
  893. NEW.rm_flags = newext;
  894. cur->bc_rec.r = NEW;
  895. trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
  896. len, owner, offset, newext);
  897. error = xfs_btree_insert(cur, &i);
  898. if (error)
  899. goto done;
  900. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  901. break;
  902. case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG:
  903. /*
  904. * Setting the last part of a previous oldext extent to newext.
  905. * The right neighbor is contiguous with the new allocation.
  906. */
  907. NEW = PREV;
  908. NEW.rm_blockcount -= len;
  909. error = xfs_rmap_update(cur, &NEW);
  910. if (error)
  911. goto done;
  912. error = xfs_btree_increment(cur, 0, &i);
  913. if (error)
  914. goto done;
  915. NEW = RIGHT;
  916. NEW.rm_offset = offset;
  917. NEW.rm_startblock = bno;
  918. NEW.rm_blockcount += len;
  919. error = xfs_rmap_update(cur, &NEW);
  920. if (error)
  921. goto done;
  922. break;
  923. case RMAP_RIGHT_FILLING:
  924. /*
  925. * Setting the last part of a previous oldext extent to newext.
  926. * The right neighbor is not contiguous.
  927. */
  928. NEW = PREV;
  929. NEW.rm_blockcount -= len;
  930. error = xfs_rmap_update(cur, &NEW);
  931. if (error)
  932. goto done;
  933. error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
  934. oldext, &i);
  935. if (error)
  936. goto done;
  937. XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
  938. NEW.rm_startblock = bno;
  939. NEW.rm_owner = owner;
  940. NEW.rm_offset = offset;
  941. NEW.rm_blockcount = len;
  942. NEW.rm_flags = newext;
  943. cur->bc_rec.r = NEW;
  944. trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno,
  945. len, owner, offset, newext);
  946. error = xfs_btree_insert(cur, &i);
  947. if (error)
  948. goto done;
  949. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  950. break;
  951. case 0:
  952. /*
  953. * Setting the middle part of a previous oldext extent to
  954. * newext. Contiguity is impossible here.
  955. * One extent becomes three extents.
  956. */
  957. /* new right extent - oldext */
  958. NEW.rm_startblock = bno + len;
  959. NEW.rm_owner = owner;
  960. NEW.rm_offset = new_endoff;
  961. NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount -
  962. new_endoff;
  963. NEW.rm_flags = PREV.rm_flags;
  964. error = xfs_rmap_update(cur, &NEW);
  965. if (error)
  966. goto done;
  967. /* new left extent - oldext */
  968. NEW = PREV;
  969. NEW.rm_blockcount = offset - PREV.rm_offset;
  970. cur->bc_rec.r = NEW;
  971. trace_xfs_rmap_insert(mp, cur->bc_private.a.agno,
  972. NEW.rm_startblock, NEW.rm_blockcount,
  973. NEW.rm_owner, NEW.rm_offset,
  974. NEW.rm_flags);
  975. error = xfs_btree_insert(cur, &i);
  976. if (error)
  977. goto done;
  978. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  979. /*
  980. * Reset the cursor to the position of the new extent
  981. * we are about to insert as we can't trust it after
  982. * the previous insert.
  983. */
  984. error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset,
  985. oldext, &i);
  986. if (error)
  987. goto done;
  988. XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done);
  989. /* new middle extent - newext */
  990. cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
  991. cur->bc_rec.r.rm_flags |= newext;
  992. trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
  993. owner, offset, newext);
  994. error = xfs_btree_insert(cur, &i);
  995. if (error)
  996. goto done;
  997. XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done);
  998. break;
  999. case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
  1000. case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
  1001. case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG:
  1002. case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG:
  1003. case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG:
  1004. case RMAP_LEFT_CONTIG:
  1005. case RMAP_RIGHT_CONTIG:
  1006. /*
  1007. * These cases are all impossible.
  1008. */
  1009. ASSERT(0);
  1010. }
  1011. trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len,
  1012. unwritten, oinfo);
  1013. done:
  1014. if (error)
  1015. trace_xfs_rmap_convert_error(cur->bc_mp,
  1016. cur->bc_private.a.agno, error, _RET_IP_);
  1017. return error;
  1018. }
  1019. #undef NEW
  1020. #undef LEFT
  1021. #undef RIGHT
  1022. #undef PREV
  1023. struct xfs_rmap_query_range_info {
  1024. xfs_rmap_query_range_fn fn;
  1025. void *priv;
  1026. };
  1027. /* Format btree record and pass to our callback. */
  1028. STATIC int
  1029. xfs_rmap_query_range_helper(
  1030. struct xfs_btree_cur *cur,
  1031. union xfs_btree_rec *rec,
  1032. void *priv)
  1033. {
  1034. struct xfs_rmap_query_range_info *query = priv;
  1035. struct xfs_rmap_irec irec;
  1036. int error;
  1037. error = xfs_rmap_btrec_to_irec(rec, &irec);
  1038. if (error)
  1039. return error;
  1040. return query->fn(cur, &irec, query->priv);
  1041. }
  1042. /* Find all rmaps between two keys. */
  1043. int
  1044. xfs_rmap_query_range(
  1045. struct xfs_btree_cur *cur,
  1046. struct xfs_rmap_irec *low_rec,
  1047. struct xfs_rmap_irec *high_rec,
  1048. xfs_rmap_query_range_fn fn,
  1049. void *priv)
  1050. {
  1051. union xfs_btree_irec low_brec;
  1052. union xfs_btree_irec high_brec;
  1053. struct xfs_rmap_query_range_info query;
  1054. low_brec.r = *low_rec;
  1055. high_brec.r = *high_rec;
  1056. query.priv = priv;
  1057. query.fn = fn;
  1058. return xfs_btree_query_range(cur, &low_brec, &high_brec,
  1059. xfs_rmap_query_range_helper, &query);
  1060. }