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