aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-08-02 21:44:21 -0400
committerDave Chinner <david@fromorbit.com>2016-08-02 21:44:21 -0400
commit0a1b0b3855cf74bb11243076b00178a0f1a0320e (patch)
tree947b7c576176915441e5fb7a07dd654bce3014d9
parentaa966d84aa487c4cb7f6fade1a35ca961652a395 (diff)
xfs: add an extent to the rmap btree
Originally-From: Dave Chinner <dchinner@redhat.com> Now all the btree, free space and transaction infrastructure is in place, we can finally add the code to insert reverse mappings to the rmap btree. Freeing will be done in a separate patch, so just the addition operation can be focussed on here. [darrick: handle owner offsets when adding rmaps] [dchinner: remove remaining debug printk statements] [darrick: move unwritten bit to rm_offset] Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/libxfs/xfs_rmap.c226
-rw-r--r--fs/xfs/xfs_trace.h2
2 files changed, 223 insertions, 5 deletions
diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 6638bc725b23..1c0e2a8943a4 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -31,6 +31,7 @@
31#include "xfs_trans.h" 31#include "xfs_trans.h"
32#include "xfs_alloc.h" 32#include "xfs_alloc.h"
33#include "xfs_rmap.h" 33#include "xfs_rmap.h"
34#include "xfs_rmap_btree.h"
34#include "xfs_trans_space.h" 35#include "xfs_trans_space.h"
35#include "xfs_trace.h" 36#include "xfs_trace.h"
36#include "xfs_error.h" 37#include "xfs_error.h"
@@ -158,6 +159,218 @@ out_error:
158 return error; 159 return error;
159} 160}
160 161
162/*
163 * A mergeable rmap must have the same owner and the same values for
164 * the unwritten, attr_fork, and bmbt flags. The startblock and
165 * offset are checked separately.
166 */
167static bool
168xfs_rmap_is_mergeable(
169 struct xfs_rmap_irec *irec,
170 uint64_t owner,
171 unsigned int flags)
172{
173 if (irec->rm_owner == XFS_RMAP_OWN_NULL)
174 return false;
175 if (irec->rm_owner != owner)
176 return false;
177 if ((flags & XFS_RMAP_UNWRITTEN) ^
178 (irec->rm_flags & XFS_RMAP_UNWRITTEN))
179 return false;
180 if ((flags & XFS_RMAP_ATTR_FORK) ^
181 (irec->rm_flags & XFS_RMAP_ATTR_FORK))
182 return false;
183 if ((flags & XFS_RMAP_BMBT_BLOCK) ^
184 (irec->rm_flags & XFS_RMAP_BMBT_BLOCK))
185 return false;
186 return true;
187}
188
189/*
190 * When we allocate a new block, the first thing we do is add a reference to
191 * the extent in the rmap btree. This takes the form of a [agbno, length,
192 * owner, offset] record. Flags are encoded in the high bits of the offset
193 * field.
194 */
195STATIC int
196xfs_rmap_map(
197 struct xfs_btree_cur *cur,
198 xfs_agblock_t bno,
199 xfs_extlen_t len,
200 bool unwritten,
201 struct xfs_owner_info *oinfo)
202{
203 struct xfs_mount *mp = cur->bc_mp;
204 struct xfs_rmap_irec ltrec;
205 struct xfs_rmap_irec gtrec;
206 int have_gt;
207 int have_lt;
208 int error = 0;
209 int i;
210 uint64_t owner;
211 uint64_t offset;
212 unsigned int flags = 0;
213 bool ignore_off;
214
215 xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
216 ASSERT(owner != 0);
217 ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) ||
218 (flags & XFS_RMAP_BMBT_BLOCK);
219 if (unwritten)
220 flags |= XFS_RMAP_UNWRITTEN;
221 trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len,
222 unwritten, oinfo);
223
224 /*
225 * For the initial lookup, look for an exact match or the left-adjacent
226 * record for our insertion point. This will also give us the record for
227 * start block contiguity tests.
228 */
229 error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags,
230 &have_lt);
231 if (error)
232 goto out_error;
233 XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
234
235 error = xfs_rmap_get_rec(cur, &ltrec, &have_lt);
236 if (error)
237 goto out_error;
238 XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error);
239 trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
240 cur->bc_private.a.agno, ltrec.rm_startblock,
241 ltrec.rm_blockcount, ltrec.rm_owner,
242 ltrec.rm_offset, ltrec.rm_flags);
243
244 if (!xfs_rmap_is_mergeable(&ltrec, owner, flags))
245 have_lt = 0;
246
247 XFS_WANT_CORRUPTED_GOTO(mp,
248 have_lt == 0 ||
249 ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error);
250
251 /*
252 * Increment the cursor to see if we have a right-adjacent record to our
253 * insertion point. This will give us the record for end block
254 * contiguity tests.
255 */
256 error = xfs_btree_increment(cur, 0, &have_gt);
257 if (error)
258 goto out_error;
259 if (have_gt) {
260 error = xfs_rmap_get_rec(cur, &gtrec, &have_gt);
261 if (error)
262 goto out_error;
263 XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error);
264 XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock,
265 out_error);
266 trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
267 cur->bc_private.a.agno, gtrec.rm_startblock,
268 gtrec.rm_blockcount, gtrec.rm_owner,
269 gtrec.rm_offset, gtrec.rm_flags);
270 if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
271 have_gt = 0;
272 }
273
274 /*
275 * Note: cursor currently points one record to the right of ltrec, even
276 * if there is no record in the tree to the right.
277 */
278 if (have_lt &&
279 ltrec.rm_startblock + ltrec.rm_blockcount == bno &&
280 (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) {
281 /*
282 * left edge contiguous, merge into left record.
283 *
284 * ltbno ltlen
285 * orig: |ooooooooo|
286 * adding: |aaaaaaaaa|
287 * result: |rrrrrrrrrrrrrrrrrrr|
288 * bno len
289 */
290 ltrec.rm_blockcount += len;
291 if (have_gt &&
292 bno + len == gtrec.rm_startblock &&
293 (ignore_off || offset + len == gtrec.rm_offset) &&
294 (unsigned long)ltrec.rm_blockcount + len +
295 gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) {
296 /*
297 * right edge also contiguous, delete right record
298 * and merge into left record.
299 *
300 * ltbno ltlen gtbno gtlen
301 * orig: |ooooooooo| |ooooooooo|
302 * adding: |aaaaaaaaa|
303 * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
304 */
305 ltrec.rm_blockcount += gtrec.rm_blockcount;
306 trace_xfs_rmap_delete(mp, cur->bc_private.a.agno,
307 gtrec.rm_startblock,
308 gtrec.rm_blockcount,
309 gtrec.rm_owner,
310 gtrec.rm_offset,
311 gtrec.rm_flags);
312 error = xfs_btree_delete(cur, &i);
313 if (error)
314 goto out_error;
315 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
316 }
317
318 /* point the cursor back to the left record and update */
319 error = xfs_btree_decrement(cur, 0, &have_gt);
320 if (error)
321 goto out_error;
322 error = xfs_rmap_update(cur, &ltrec);
323 if (error)
324 goto out_error;
325 } else if (have_gt &&
326 bno + len == gtrec.rm_startblock &&
327 (ignore_off || offset + len == gtrec.rm_offset)) {
328 /*
329 * right edge contiguous, merge into right record.
330 *
331 * gtbno gtlen
332 * Orig: |ooooooooo|
333 * adding: |aaaaaaaaa|
334 * Result: |rrrrrrrrrrrrrrrrrrr|
335 * bno len
336 */
337 gtrec.rm_startblock = bno;
338 gtrec.rm_blockcount += len;
339 if (!ignore_off)
340 gtrec.rm_offset = offset;
341 error = xfs_rmap_update(cur, &gtrec);
342 if (error)
343 goto out_error;
344 } else {
345 /*
346 * no contiguous edge with identical owner, insert
347 * new record at current cursor position.
348 */
349 cur->bc_rec.r.rm_startblock = bno;
350 cur->bc_rec.r.rm_blockcount = len;
351 cur->bc_rec.r.rm_owner = owner;
352 cur->bc_rec.r.rm_offset = offset;
353 cur->bc_rec.r.rm_flags = flags;
354 trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len,
355 owner, offset, flags);
356 error = xfs_btree_insert(cur, &i);
357 if (error)
358 goto out_error;
359 XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
360 }
361
362 trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len,
363 unwritten, oinfo);
364out_error:
365 if (error)
366 trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno,
367 error, _RET_IP_);
368 return error;
369}
370
371/*
372 * Add a reference to an extent in the rmap btree.
373 */
161int 374int
162xfs_rmap_alloc( 375xfs_rmap_alloc(
163 struct xfs_trans *tp, 376 struct xfs_trans *tp,
@@ -168,19 +381,22 @@ xfs_rmap_alloc(
168 struct xfs_owner_info *oinfo) 381 struct xfs_owner_info *oinfo)
169{ 382{
170 struct xfs_mount *mp = tp->t_mountp; 383 struct xfs_mount *mp = tp->t_mountp;
171 int error = 0; 384 struct xfs_btree_cur *cur;
385 int error;
172 386
173 if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) 387 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
174 return 0; 388 return 0;
175 389
176 trace_xfs_rmap_map(mp, agno, bno, len, false, oinfo); 390 cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);
177 if (1) 391 error = xfs_rmap_map(cur, bno, len, false, oinfo);
392 if (error)
178 goto out_error; 393 goto out_error;
179 trace_xfs_rmap_map_done(mp, agno, bno, len, false, oinfo); 394
395 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
180 return 0; 396 return 0;
181 397
182out_error: 398out_error:
183 trace_xfs_rmap_map_error(mp, agno, error, _RET_IP_); 399 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
184 return error; 400 return error;
185} 401}
186 402
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 7498c7780d99..e099eda75b68 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -2551,6 +2551,8 @@ DEFINE_RMAPBT_EVENT(xfs_rmap_delete);
2551DEFINE_AG_ERROR_EVENT(xfs_rmap_insert_error); 2551DEFINE_AG_ERROR_EVENT(xfs_rmap_insert_error);
2552DEFINE_AG_ERROR_EVENT(xfs_rmap_delete_error); 2552DEFINE_AG_ERROR_EVENT(xfs_rmap_delete_error);
2553DEFINE_AG_ERROR_EVENT(xfs_rmap_update_error); 2553DEFINE_AG_ERROR_EVENT(xfs_rmap_update_error);
2554DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result);
2555DEFINE_RMAPBT_EVENT(xfs_rmap_find_right_neighbor_result);
2554 2556
2555#endif /* _TRACE_XFS_H */ 2557#endif /* _TRACE_XFS_H */
2556 2558