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