]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_attr_remote.c
xfs: don't rely on extent indices in xfs_bmap_collapse_extents
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr_remote.c
CommitLineData
9d6fabc0
DC
1/*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
59915981 3 * Copyright (c) 2013 Red Hat, Inc.
9d6fabc0
DC
4 * All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
9c799827 19#include "libxfs_priv.h"
b626fb59
DC
20#include "xfs_fs.h"
21#include "xfs_shared.h"
22#include "xfs_format.h"
23#include "xfs_log_format.h"
24#include "xfs_trans_resv.h"
25#include "xfs_bit.h"
26#include "xfs_mount.h"
f944d3d0 27#include "xfs_defer.h"
b626fb59
DC
28#include "xfs_da_format.h"
29#include "xfs_da_btree.h"
30#include "xfs_inode.h"
31#include "xfs_alloc.h"
32#include "xfs_trans.h"
33#include "xfs_bmap.h"
34#include "xfs_attr_leaf.h"
35#include "xfs_attr_remote.h"
36#include "xfs_trans_space.h"
37#include "xfs_trace.h"
38#include "xfs_cksum.h"
9d6fabc0
DC
39
40#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
41
59915981
DC
42/*
43 * Each contiguous block has a header, so it is not just a simple attribute
44 * length to FSB conversion.
45 */
f08bc2a9 46int
59915981
DC
47xfs_attr3_rmt_blocks(
48 struct xfs_mount *mp,
49 int attrlen)
50{
72e78b51
DC
51 if (xfs_sb_version_hascrc(&mp->m_sb)) {
52 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
53 return (attrlen + buflen - 1) / buflen;
54 }
55 return XFS_B_TO_FSB(mp, attrlen);
59915981
DC
56}
57
f08bc2a9
DC
58/*
59 * Checking of the remote attribute header is split into two parts. The verifier
60 * does CRC, location and bounds checking, the unpacking function checks the
61 * attribute parameters and owner.
62 */
63static bool
64xfs_attr3_rmt_hdr_ok(
f08bc2a9
DC
65 void *ptr,
66 xfs_ino_t ino,
67 uint32_t offset,
68 uint32_t size,
69 xfs_daddr_t bno)
70{
71 struct xfs_attr3_rmt_hdr *rmt = ptr;
72
73 if (bno != be64_to_cpu(rmt->rm_blkno))
74 return false;
75 if (offset != be32_to_cpu(rmt->rm_offset))
76 return false;
77 if (size != be32_to_cpu(rmt->rm_bytes))
78 return false;
79 if (ino != be64_to_cpu(rmt->rm_owner))
80 return false;
81
82 /* ok */
83 return true;
84}
85
59915981
DC
86static bool
87xfs_attr3_rmt_verify(
f08bc2a9
DC
88 struct xfs_mount *mp,
89 void *ptr,
90 int fsbsize,
91 xfs_daddr_t bno)
59915981 92{
f08bc2a9 93 struct xfs_attr3_rmt_hdr *rmt = ptr;
59915981
DC
94
95 if (!xfs_sb_version_hascrc(&mp->m_sb))
96 return false;
97 if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
98 return false;
9c4e12fb 99 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
59915981 100 return false;
f08bc2a9
DC
101 if (be64_to_cpu(rmt->rm_blkno) != bno)
102 return false;
103 if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
59915981
DC
104 return false;
105 if (be32_to_cpu(rmt->rm_offset) +
ec9d24e9 106 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
59915981
DC
107 return false;
108 if (rmt->rm_owner == 0)
109 return false;
110
111 return true;
112}
113
114static void
115xfs_attr3_rmt_read_verify(
116 struct xfs_buf *bp)
117{
118 struct xfs_mount *mp = bp->b_target->bt_mount;
f08bc2a9
DC
119 char *ptr;
120 int len;
f08bc2a9 121 xfs_daddr_t bno;
ff105f75 122 int blksize = mp->m_attr_geo->blksize;
59915981
DC
123
124 /* no verification of non-crc buffers */
125 if (!xfs_sb_version_hascrc(&mp->m_sb))
126 return;
127
f08bc2a9
DC
128 ptr = bp->b_addr;
129 bno = bp->b_bn;
130 len = BBTOB(bp->b_length);
ff105f75 131 ASSERT(len >= blksize);
f08bc2a9
DC
132
133 while (len > 0) {
ff105f75 134 if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
12b53197 135 xfs_buf_ioerror(bp, -EFSBADCRC);
f08bc2a9
DC
136 break;
137 }
ff105f75 138 if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
12b53197 139 xfs_buf_ioerror(bp, -EFSCORRUPTED);
f08bc2a9
DC
140 break;
141 }
ff105f75
DC
142 len -= blksize;
143 ptr += blksize;
144 bno += BTOBB(blksize);
f08bc2a9
DC
145 }
146
45922933
DC
147 if (bp->b_error)
148 xfs_verifier_error(bp);
149 else
f08bc2a9 150 ASSERT(len == 0);
59915981
DC
151}
152
153static void
154xfs_attr3_rmt_write_verify(
155 struct xfs_buf *bp)
156{
157 struct xfs_mount *mp = bp->b_target->bt_mount;
d9241d7e 158 int blksize = mp->m_attr_geo->blksize;
f08bc2a9
DC
159 char *ptr;
160 int len;
161 xfs_daddr_t bno;
59915981
DC
162
163 /* no verification of non-crc buffers */
164 if (!xfs_sb_version_hascrc(&mp->m_sb))
165 return;
166
f08bc2a9
DC
167 ptr = bp->b_addr;
168 bno = bp->b_bn;
169 len = BBTOB(bp->b_length);
ff105f75 170 ASSERT(len >= blksize);
f08bc2a9
DC
171
172 while (len > 0) {
d9241d7e
DC
173 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
174
ff105f75 175 if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
12b53197 176 xfs_buf_ioerror(bp, -EFSCORRUPTED);
45922933 177 xfs_verifier_error(bp);
f08bc2a9
DC
178 return;
179 }
59915981 180
d9241d7e
DC
181 /*
182 * Ensure we aren't writing bogus LSNs to disk. See
183 * xfs_attr3_rmt_hdr_set() for the explanation.
184 */
185 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
186 xfs_buf_ioerror(bp, -EFSCORRUPTED);
187 xfs_verifier_error(bp);
188 return;
f08bc2a9 189 }
ff105f75 190 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
f08bc2a9 191
ff105f75
DC
192 len -= blksize;
193 ptr += blksize;
194 bno += BTOBB(blksize);
59915981 195 }
f08bc2a9 196 ASSERT(len == 0);
59915981
DC
197}
198
199const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
a3fac935 200 .name = "xfs_attr3_rmt",
59915981
DC
201 .verify_read = xfs_attr3_rmt_read_verify,
202 .verify_write = xfs_attr3_rmt_write_verify,
203};
204
f08bc2a9 205STATIC int
59915981
DC
206xfs_attr3_rmt_hdr_set(
207 struct xfs_mount *mp,
f08bc2a9 208 void *ptr,
59915981
DC
209 xfs_ino_t ino,
210 uint32_t offset,
211 uint32_t size,
f08bc2a9 212 xfs_daddr_t bno)
59915981 213{
f08bc2a9 214 struct xfs_attr3_rmt_hdr *rmt = ptr;
59915981
DC
215
216 if (!xfs_sb_version_hascrc(&mp->m_sb))
217 return 0;
218
219 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
220 rmt->rm_offset = cpu_to_be32(offset);
221 rmt->rm_bytes = cpu_to_be32(size);
9c4e12fb 222 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
59915981 223 rmt->rm_owner = cpu_to_be64(ino);
f08bc2a9 224 rmt->rm_blkno = cpu_to_be64(bno);
59915981 225
d9241d7e
DC
226 /*
227 * Remote attribute blocks are written synchronously, so we don't
228 * have an LSN that we can stamp in them that makes any sense to log
229 * recovery. To ensure that log recovery handles overwrites of these
230 * blocks sanely (i.e. once they've been freed and reallocated as some
231 * other type of metadata) we need to ensure that the LSN has a value
232 * that tells log recovery to ignore the LSN and overwrite the buffer
233 * with whatever is in it's log. To do this, we use the magic
234 * NULLCOMMITLSN to indicate that the LSN is invalid.
235 */
236 rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
237
59915981
DC
238 return sizeof(struct xfs_attr3_rmt_hdr);
239}
240
241/*
f08bc2a9 242 * Helper functions to copy attribute data in and out of the one disk extents
59915981 243 */
f08bc2a9
DC
244STATIC int
245xfs_attr_rmtval_copyout(
246 struct xfs_mount *mp,
247 struct xfs_buf *bp,
248 xfs_ino_t ino,
249 int *offset,
250 int *valuelen,
4a492e72 251 uint8_t **dst)
59915981 252{
f08bc2a9
DC
253 char *src = bp->b_addr;
254 xfs_daddr_t bno = bp->b_bn;
255 int len = BBTOB(bp->b_length);
ff105f75 256 int blksize = mp->m_attr_geo->blksize;
59915981 257
ff105f75 258 ASSERT(len >= blksize);
59915981 259
f08bc2a9
DC
260 while (len > 0 && *valuelen > 0) {
261 int hdr_size = 0;
ff105f75 262 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
f08bc2a9
DC
263
264 byte_cnt = min(*valuelen, byte_cnt);
265
266 if (xfs_sb_version_hascrc(&mp->m_sb)) {
ff105f75 267 if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
f08bc2a9
DC
268 byte_cnt, bno)) {
269 xfs_alert(mp,
270"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
271 bno, *offset, byte_cnt, ino);
12b53197 272 return -EFSCORRUPTED;
f08bc2a9
DC
273 }
274 hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
275 }
276
277 memcpy(*dst, src + hdr_size, byte_cnt);
278
279 /* roll buffer forwards */
ff105f75
DC
280 len -= blksize;
281 src += blksize;
282 bno += BTOBB(blksize);
f08bc2a9
DC
283
284 /* roll attribute data forwards */
285 *valuelen -= byte_cnt;
286 *dst += byte_cnt;
287 *offset += byte_cnt;
288 }
289 return 0;
290}
291
292STATIC void
293xfs_attr_rmtval_copyin(
294 struct xfs_mount *mp,
295 struct xfs_buf *bp,
296 xfs_ino_t ino,
297 int *offset,
298 int *valuelen,
4a492e72 299 uint8_t **src)
f08bc2a9
DC
300{
301 char *dst = bp->b_addr;
302 xfs_daddr_t bno = bp->b_bn;
303 int len = BBTOB(bp->b_length);
ff105f75 304 int blksize = mp->m_attr_geo->blksize;
f08bc2a9 305
ff105f75 306 ASSERT(len >= blksize);
f08bc2a9
DC
307
308 while (len > 0 && *valuelen > 0) {
309 int hdr_size;
ff105f75 310 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
f08bc2a9
DC
311
312 byte_cnt = min(*valuelen, byte_cnt);
313 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
314 byte_cnt, bno);
315
316 memcpy(dst + hdr_size, *src, byte_cnt);
317
318 /*
319 * If this is the last block, zero the remainder of it.
320 * Check that we are actually the last block, too.
321 */
ff105f75 322 if (byte_cnt + hdr_size < blksize) {
f08bc2a9 323 ASSERT(*valuelen - byte_cnt == 0);
ff105f75 324 ASSERT(len == blksize);
f08bc2a9 325 memset(dst + hdr_size + byte_cnt, 0,
ff105f75 326 blksize - hdr_size - byte_cnt);
f08bc2a9
DC
327 }
328
329 /* roll buffer forwards */
ff105f75
DC
330 len -= blksize;
331 dst += blksize;
332 bno += BTOBB(blksize);
f08bc2a9
DC
333
334 /* roll attribute data forwards */
335 *valuelen -= byte_cnt;
336 *src += byte_cnt;
337 *offset += byte_cnt;
338 }
59915981
DC
339}
340
9d6fabc0
DC
341/*
342 * Read the value associated with an attribute from the out-of-line buffer
343 * that we stored it in.
344 */
345int
59915981
DC
346xfs_attr_rmtval_get(
347 struct xfs_da_args *args)
9d6fabc0 348{
59915981
DC
349 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE];
350 struct xfs_mount *mp = args->dp->i_mount;
351 struct xfs_buf *bp;
59915981 352 xfs_dablk_t lblkno = args->rmtblkno;
4a492e72 353 uint8_t *dst = args->value;
ff105f75 354 int valuelen;
59915981
DC
355 int nmap;
356 int error;
f08bc2a9 357 int blkcnt = args->rmtblkcnt;
59915981
DC
358 int i;
359 int offset = 0;
9d6fabc0
DC
360
361 trace_xfs_attr_rmtval_get(args);
362
363 ASSERT(!(args->flags & ATTR_KERNOVAL));
ff105f75 364 ASSERT(args->rmtvaluelen == args->valuelen);
9d6fabc0 365
ff105f75 366 valuelen = args->rmtvaluelen;
9d6fabc0
DC
367 while (valuelen > 0) {
368 nmap = ATTR_RMTVALUE_MAPSIZE;
369 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
72e78b51 370 blkcnt, map, &nmap,
9d6fabc0
DC
371 XFS_BMAPI_ATTRFORK);
372 if (error)
59915981 373 return error;
9d6fabc0
DC
374 ASSERT(nmap >= 1);
375
376 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
f08bc2a9
DC
377 xfs_daddr_t dblkno;
378 int dblkcnt;
59915981 379
9d6fabc0
DC
380 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
381 (map[i].br_startblock != HOLESTARTBLOCK));
382 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
f08bc2a9 383 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
b2d5ffd5
DW
384 error = xfs_trans_read_buf(mp, args->trans,
385 mp->m_ddev_targp,
f08bc2a9 386 dblkno, dblkcnt, 0, &bp,
59915981 387 &xfs_attr3_rmt_buf_ops);
9d6fabc0 388 if (error)
59915981
DC
389 return error;
390
f08bc2a9
DC
391 error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
392 &offset, &valuelen,
393 &dst);
b2d5ffd5 394 xfs_trans_brelse(args->trans, bp);
f08bc2a9
DC
395 if (error)
396 return error;
59915981 397
f08bc2a9 398 /* roll attribute extent map forwards */
9d6fabc0 399 lblkno += map[i].br_blockcount;
f08bc2a9 400 blkcnt -= map[i].br_blockcount;
9d6fabc0
DC
401 }
402 }
403 ASSERT(valuelen == 0);
59915981 404 return 0;
9d6fabc0
DC
405}
406
407/*
408 * Write the value associated with an attribute into the out-of-line buffer
409 * that we have defined for it.
410 */
411int
59915981
DC
412xfs_attr_rmtval_set(
413 struct xfs_da_args *args)
9d6fabc0 414{
59915981
DC
415 struct xfs_inode *dp = args->dp;
416 struct xfs_mount *mp = dp->i_mount;
417 struct xfs_bmbt_irec map;
59915981
DC
418 xfs_dablk_t lblkno;
419 xfs_fileoff_t lfileoff = 0;
4a492e72 420 uint8_t *src = args->value;
59915981
DC
421 int blkcnt;
422 int valuelen;
423 int nmap;
424 int error;
59915981 425 int offset = 0;
9d6fabc0
DC
426
427 trace_xfs_attr_rmtval_set(args);
428
9d6fabc0
DC
429 /*
430 * Find a "hole" in the attribute address space large enough for
59915981
DC
431 * us to drop the new attribute's value into. Because CRC enable
432 * attributes have headers, we can't just do a straight byte to FSB
f08bc2a9 433 * conversion and have to take the header space into account.
9d6fabc0 434 */
ff105f75 435 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
9d6fabc0
DC
436 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
437 XFS_ATTR_FORK);
59915981
DC
438 if (error)
439 return error;
440
9d6fabc0
DC
441 args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
442 args->rmtblkcnt = blkcnt;
443
444 /*
445 * Roll through the "value", allocating blocks on disk as required.
446 */
447 while (blkcnt > 0) {
448 /*
449 * Allocate a single extent, up to the size of the value.
92a57a69
DC
450 *
451 * Note that we have to consider this a data allocation as we
452 * write the remote attribute without logging the contents.
453 * Hence we must ensure that we aren't using blocks that are on
454 * the busy list so that we don't overwrite blocks which have
455 * recently been freed but their transactions are not yet
456 * committed to disk. If we overwrite the contents of a busy
457 * extent and then crash then the block may not contain the
458 * correct metadata after log recovery occurs.
9d6fabc0 459 */
f33cea1a 460 xfs_defer_init(args->dfops, args->firstblock);
9d6fabc0
DC
461 nmap = 1;
462 error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
92a57a69 463 blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock,
f33cea1a 464 args->total, &map, &nmap, args->dfops);
5c33baee
CH
465 if (error)
466 goto out_defer_cancel;
467 xfs_defer_ijoin(args->dfops, dp);
468 error = xfs_defer_finish(&args->trans, args->dfops);
469 if (error)
470 goto out_defer_cancel;
9d6fabc0 471
9d6fabc0
DC
472 ASSERT(nmap == 1);
473 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
474 (map.br_startblock != HOLESTARTBLOCK));
475 lblkno += map.br_blockcount;
476 blkcnt -= map.br_blockcount;
477
478 /*
479 * Start the next trans in the chain.
480 */
d67406c9 481 error = xfs_trans_roll_inode(&args->trans, dp);
9d6fabc0 482 if (error)
af43ca9f 483 return error;
9d6fabc0
DC
484 }
485
486 /*
487 * Roll through the "value", copying the attribute value to the
488 * already-allocated blocks. Blocks are written synchronously
489 * so that we can know they are all on disk before we turn off
490 * the INCOMPLETE flag.
491 */
492 lblkno = args->rmtblkno;
4da23ca6 493 blkcnt = args->rmtblkcnt;
ff105f75 494 valuelen = args->rmtvaluelen;
9d6fabc0 495 while (valuelen > 0) {
f08bc2a9
DC
496 struct xfs_buf *bp;
497 xfs_daddr_t dblkno;
498 int dblkcnt;
499
500 ASSERT(blkcnt > 0);
9d6fabc0 501
f33cea1a 502 xfs_defer_init(args->dfops, args->firstblock);
9d6fabc0
DC
503 nmap = 1;
504 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
4da23ca6 505 blkcnt, &map, &nmap,
9d6fabc0
DC
506 XFS_BMAPI_ATTRFORK);
507 if (error)
af43ca9f 508 return error;
9d6fabc0
DC
509 ASSERT(nmap == 1);
510 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
511 (map.br_startblock != HOLESTARTBLOCK));
512
513 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
4da23ca6 514 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
9d6fabc0 515
4da23ca6 516 bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
9d6fabc0 517 if (!bp)
12b53197 518 return -ENOMEM;
59915981
DC
519 bp->b_ops = &xfs_attr3_rmt_buf_ops;
520
f08bc2a9
DC
521 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
522 &valuelen, &src);
9d6fabc0
DC
523
524 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
525 xfs_buf_relse(bp);
526 if (error)
527 return error;
59915981 528
9d6fabc0 529
f08bc2a9 530 /* roll attribute extent map forwards */
9d6fabc0 531 lblkno += map.br_blockcount;
4da23ca6 532 blkcnt -= map.br_blockcount;
9d6fabc0
DC
533 }
534 ASSERT(valuelen == 0);
59915981 535 return 0;
5c33baee
CH
536out_defer_cancel:
537 xfs_defer_cancel(args->dfops);
538 args->trans = NULL;
539 return error;
9d6fabc0
DC
540}
541
542/*
543 * Remove the value associated with an attribute by deleting the
544 * out-of-line buffer that it is stored on.
545 */
546int
f08bc2a9
DC
547xfs_attr_rmtval_remove(
548 struct xfs_da_args *args)
9d6fabc0 549{
f08bc2a9
DC
550 struct xfs_mount *mp = args->dp->i_mount;
551 xfs_dablk_t lblkno;
552 int blkcnt;
553 int error;
554 int done;
9d6fabc0
DC
555
556 trace_xfs_attr_rmtval_remove(args);
557
9d6fabc0 558 /*
526f9be5 559 * Roll through the "value", invalidating the attribute value's blocks.
9d6fabc0
DC
560 */
561 lblkno = args->rmtblkno;
f08bc2a9
DC
562 blkcnt = args->rmtblkcnt;
563 while (blkcnt > 0) {
564 struct xfs_bmbt_irec map;
565 struct xfs_buf *bp;
566 xfs_daddr_t dblkno;
567 int dblkcnt;
568 int nmap;
526f9be5 569
9d6fabc0
DC
570 /*
571 * Try to remember where we decided to put the value.
572 */
573 nmap = 1;
574 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
526f9be5 575 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
9d6fabc0 576 if (error)
af43ca9f 577 return error;
9d6fabc0
DC
578 ASSERT(nmap == 1);
579 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
580 (map.br_startblock != HOLESTARTBLOCK));
581
582 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
526f9be5 583 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
9d6fabc0
DC
584
585 /*
586 * If the "remote" value is in the cache, remove it.
587 */
526f9be5 588 bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
9d6fabc0
DC
589 if (bp) {
590 xfs_buf_stale(bp);
591 xfs_buf_relse(bp);
592 bp = NULL;
593 }
594
9d6fabc0 595 lblkno += map.br_blockcount;
526f9be5 596 blkcnt -= map.br_blockcount;
9d6fabc0
DC
597 }
598
599 /*
600 * Keep de-allocating extents until the remote-value region is gone.
601 */
602 lblkno = args->rmtblkno;
f08bc2a9 603 blkcnt = args->rmtblkcnt;
9d6fabc0
DC
604 done = 0;
605 while (!done) {
f33cea1a 606 xfs_defer_init(args->dfops, args->firstblock);
9d6fabc0 607 error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
db9cba4e 608 XFS_BMAPI_ATTRFORK, 1, args->firstblock,
f33cea1a 609 args->dfops, &done);
5c33baee
CH
610 if (error)
611 goto out_defer_cancel;
612 xfs_defer_ijoin(args->dfops, args->dp);
613 error = xfs_defer_finish(&args->trans, args->dfops);
614 if (error)
615 goto out_defer_cancel;
9d6fabc0 616
9d6fabc0
DC
617 /*
618 * Close out trans and start the next one in the chain.
619 */
d67406c9 620 error = xfs_trans_roll_inode(&args->trans, args->dp);
9d6fabc0 621 if (error)
af43ca9f 622 return error;
9d6fabc0 623 }
af43ca9f 624 return 0;
5c33baee
CH
625out_defer_cancel:
626 xfs_defer_cancel(args->dfops);
627 args->trans = NULL;
628 return error;
9d6fabc0 629}