]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_attr_remote.c
xfsprogs: Release v6.7.0
[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"
b626fb59
DC
19#include "xfs_trans.h"
20#include "xfs_bmap.h"
43be641e
DW
21#include "xfs_attr.h"
22#include "xfs_attr_remote.h"
b626fb59 23#include "xfs_trace.h"
9d6fabc0
DC
24
25#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
26
a8bbb628
DW
27/*
28 * Remote Attribute Values
29 * =======================
30 *
31 * Remote extended attribute values are conceptually simple -- they're written
32 * to data blocks mapped by an inode's attribute fork, and they have an upper
33 * size limit of 64k. Setting a value does not involve the XFS log.
34 *
35 * However, on a v5 filesystem, maximally sized remote attr values require one
36 * block more than 64k worth of space to hold both the remote attribute value
37 * header (64 bytes). On a 4k block filesystem this results in a 68k buffer;
38 * on a 64k block filesystem, this would be a 128k buffer. Note that the log
39 * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
40 * Therefore, we /must/ ensure that remote attribute value buffers never touch
41 * the logging system and therefore never have a log item.
42 */
43
59915981
DC
44/*
45 * Each contiguous block has a header, so it is not just a simple attribute
46 * length to FSB conversion.
47 */
f08bc2a9 48int
59915981
DC
49xfs_attr3_rmt_blocks(
50 struct xfs_mount *mp,
51 int attrlen)
52{
b16a427a 53 if (xfs_has_crc(mp)) {
72e78b51
DC
54 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
55 return (attrlen + buflen - 1) / buflen;
56 }
57 return XFS_B_TO_FSB(mp, attrlen);
59915981
DC
58}
59
f08bc2a9
DC
60/*
61 * Checking of the remote attribute header is split into two parts. The verifier
62 * does CRC, location and bounds checking, the unpacking function checks the
63 * attribute parameters and owner.
64 */
bc01119d 65static xfs_failaddr_t
f08bc2a9 66xfs_attr3_rmt_hdr_ok(
f08bc2a9
DC
67 void *ptr,
68 xfs_ino_t ino,
69 uint32_t offset,
70 uint32_t size,
71 xfs_daddr_t bno)
72{
73 struct xfs_attr3_rmt_hdr *rmt = ptr;
74
75 if (bno != be64_to_cpu(rmt->rm_blkno))
bc01119d 76 return __this_address;
f08bc2a9 77 if (offset != be32_to_cpu(rmt->rm_offset))
bc01119d 78 return __this_address;
f08bc2a9 79 if (size != be32_to_cpu(rmt->rm_bytes))
bc01119d 80 return __this_address;
f08bc2a9 81 if (ino != be64_to_cpu(rmt->rm_owner))
bc01119d 82 return __this_address;
f08bc2a9
DC
83
84 /* ok */
bc01119d 85 return NULL;
f08bc2a9
DC
86}
87
bc01119d 88static xfs_failaddr_t
59915981 89xfs_attr3_rmt_verify(
f08bc2a9 90 struct xfs_mount *mp,
68dbe77f 91 struct xfs_buf *bp,
f08bc2a9
DC
92 void *ptr,
93 int fsbsize,
94 xfs_daddr_t bno)
59915981 95{
f08bc2a9 96 struct xfs_attr3_rmt_hdr *rmt = ptr;
59915981 97
68dbe77f 98 if (!xfs_verify_magic(bp, rmt->rm_magic))
bc01119d 99 return __this_address;
9c4e12fb 100 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
bc01119d 101 return __this_address;
f08bc2a9 102 if (be64_to_cpu(rmt->rm_blkno) != bno)
bc01119d 103 return __this_address;
f08bc2a9 104 if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
bc01119d 105 return __this_address;
59915981 106 if (be32_to_cpu(rmt->rm_offset) +
ec9d24e9 107 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
bc01119d 108 return __this_address;
59915981 109 if (rmt->rm_owner == 0)
bc01119d 110 return __this_address;
59915981 111
bc01119d 112 return NULL;
59915981
DC
113}
114
95d9582b
DW
115static int
116__xfs_attr3_rmt_read_verify(
117 struct xfs_buf *bp,
118 bool check_crc,
119 xfs_failaddr_t *failaddr)
59915981 120{
7861ef77 121 struct xfs_mount *mp = bp->b_mount;
f08bc2a9
DC
122 char *ptr;
123 int len;
f08bc2a9 124 xfs_daddr_t bno;
ff105f75 125 int blksize = mp->m_attr_geo->blksize;
59915981
DC
126
127 /* no verification of non-crc buffers */
b16a427a 128 if (!xfs_has_crc(mp))
95d9582b 129 return 0;
59915981 130
f08bc2a9 131 ptr = bp->b_addr;
f1208396 132 bno = xfs_buf_daddr(bp);
f08bc2a9 133 len = BBTOB(bp->b_length);
ff105f75 134 ASSERT(len >= blksize);
f08bc2a9
DC
135
136 while (len > 0) {
95d9582b
DW
137 if (check_crc &&
138 !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
139 *failaddr = __this_address;
140 return -EFSBADCRC;
f08bc2a9 141 }
68dbe77f 142 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
95d9582b
DW
143 if (*failaddr)
144 return -EFSCORRUPTED;
ff105f75
DC
145 len -= blksize;
146 ptr += blksize;
147 bno += BTOBB(blksize);
f08bc2a9
DC
148 }
149
95d9582b
DW
150 if (len != 0) {
151 *failaddr = __this_address;
152 return -EFSCORRUPTED;
153 }
154
155 return 0;
156}
157
158static void
159xfs_attr3_rmt_read_verify(
160 struct xfs_buf *bp)
161{
162 xfs_failaddr_t fa;
163 int error;
164
165 error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
166 if (error)
167 xfs_verifier_error(bp, error, fa);
168}
169
170static xfs_failaddr_t
171xfs_attr3_rmt_verify_struct(
172 struct xfs_buf *bp)
173{
174 xfs_failaddr_t fa;
175 int error;
176
177 error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
178 return error ? fa : NULL;
59915981
DC
179}
180
181static void
182xfs_attr3_rmt_write_verify(
183 struct xfs_buf *bp)
184{
7861ef77 185 struct xfs_mount *mp = bp->b_mount;
1e697959 186 xfs_failaddr_t fa;
d9241d7e 187 int blksize = mp->m_attr_geo->blksize;
f08bc2a9
DC
188 char *ptr;
189 int len;
190 xfs_daddr_t bno;
59915981
DC
191
192 /* no verification of non-crc buffers */
b16a427a 193 if (!xfs_has_crc(mp))
59915981
DC
194 return;
195
f08bc2a9 196 ptr = bp->b_addr;
f1208396 197 bno = xfs_buf_daddr(bp);
f08bc2a9 198 len = BBTOB(bp->b_length);
ff105f75 199 ASSERT(len >= blksize);
f08bc2a9
DC
200
201 while (len > 0) {
d9241d7e
DC
202 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
203
68dbe77f 204 fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
1e697959
DW
205 if (fa) {
206 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
f08bc2a9
DC
207 return;
208 }
59915981 209
d9241d7e
DC
210 /*
211 * Ensure we aren't writing bogus LSNs to disk. See
212 * xfs_attr3_rmt_hdr_set() for the explanation.
213 */
214 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
1e697959 215 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
d9241d7e 216 return;
f08bc2a9 217 }
ff105f75 218 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
f08bc2a9 219
ff105f75
DC
220 len -= blksize;
221 ptr += blksize;
222 bno += BTOBB(blksize);
59915981 223 }
7e6c95f1
DW
224
225 if (len != 0)
1e697959 226 xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
59915981
DC
227}
228
229const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
a3fac935 230 .name = "xfs_attr3_rmt",
68dbe77f 231 .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
59915981
DC
232 .verify_read = xfs_attr3_rmt_read_verify,
233 .verify_write = xfs_attr3_rmt_write_verify,
95d9582b 234 .verify_struct = xfs_attr3_rmt_verify_struct,
59915981
DC
235};
236
f08bc2a9 237STATIC int
59915981
DC
238xfs_attr3_rmt_hdr_set(
239 struct xfs_mount *mp,
f08bc2a9 240 void *ptr,
59915981
DC
241 xfs_ino_t ino,
242 uint32_t offset,
243 uint32_t size,
f08bc2a9 244 xfs_daddr_t bno)
59915981 245{
f08bc2a9 246 struct xfs_attr3_rmt_hdr *rmt = ptr;
59915981 247
b16a427a 248 if (!xfs_has_crc(mp))
59915981
DC
249 return 0;
250
251 rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
252 rmt->rm_offset = cpu_to_be32(offset);
253 rmt->rm_bytes = cpu_to_be32(size);
9c4e12fb 254 uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
59915981 255 rmt->rm_owner = cpu_to_be64(ino);
f08bc2a9 256 rmt->rm_blkno = cpu_to_be64(bno);
59915981 257
d9241d7e
DC
258 /*
259 * Remote attribute blocks are written synchronously, so we don't
260 * have an LSN that we can stamp in them that makes any sense to log
261 * recovery. To ensure that log recovery handles overwrites of these
262 * blocks sanely (i.e. once they've been freed and reallocated as some
263 * other type of metadata) we need to ensure that the LSN has a value
264 * that tells log recovery to ignore the LSN and overwrite the buffer
265 * with whatever is in it's log. To do this, we use the magic
266 * NULLCOMMITLSN to indicate that the LSN is invalid.
267 */
268 rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
269
59915981
DC
270 return sizeof(struct xfs_attr3_rmt_hdr);
271}
272
273/*
f08bc2a9 274 * Helper functions to copy attribute data in and out of the one disk extents
59915981 275 */
f08bc2a9
DC
276STATIC int
277xfs_attr_rmtval_copyout(
278 struct xfs_mount *mp,
279 struct xfs_buf *bp,
280 xfs_ino_t ino,
281 int *offset,
282 int *valuelen,
4a492e72 283 uint8_t **dst)
59915981 284{
f08bc2a9 285 char *src = bp->b_addr;
f1208396 286 xfs_daddr_t bno = xfs_buf_daddr(bp);
f08bc2a9 287 int len = BBTOB(bp->b_length);
ff105f75 288 int blksize = mp->m_attr_geo->blksize;
59915981 289
ff105f75 290 ASSERT(len >= blksize);
59915981 291
f08bc2a9
DC
292 while (len > 0 && *valuelen > 0) {
293 int hdr_size = 0;
ff105f75 294 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
f08bc2a9
DC
295
296 byte_cnt = min(*valuelen, byte_cnt);
297
b16a427a 298 if (xfs_has_crc(mp)) {
bc01119d 299 if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
f08bc2a9
DC
300 byte_cnt, bno)) {
301 xfs_alert(mp,
302"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
303 bno, *offset, byte_cnt, ino);
12b53197 304 return -EFSCORRUPTED;
f08bc2a9
DC
305 }
306 hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
307 }
308
309 memcpy(*dst, src + hdr_size, byte_cnt);
310
311 /* roll buffer forwards */
ff105f75
DC
312 len -= blksize;
313 src += blksize;
314 bno += BTOBB(blksize);
f08bc2a9
DC
315
316 /* roll attribute data forwards */
317 *valuelen -= byte_cnt;
318 *dst += byte_cnt;
319 *offset += byte_cnt;
320 }
321 return 0;
322}
323
324STATIC void
325xfs_attr_rmtval_copyin(
326 struct xfs_mount *mp,
327 struct xfs_buf *bp,
328 xfs_ino_t ino,
329 int *offset,
330 int *valuelen,
4a492e72 331 uint8_t **src)
f08bc2a9
DC
332{
333 char *dst = bp->b_addr;
f1208396 334 xfs_daddr_t bno = xfs_buf_daddr(bp);
f08bc2a9 335 int len = BBTOB(bp->b_length);
ff105f75 336 int blksize = mp->m_attr_geo->blksize;
f08bc2a9 337
ff105f75 338 ASSERT(len >= blksize);
f08bc2a9
DC
339
340 while (len > 0 && *valuelen > 0) {
341 int hdr_size;
ff105f75 342 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
f08bc2a9
DC
343
344 byte_cnt = min(*valuelen, byte_cnt);
345 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
346 byte_cnt, bno);
347
348 memcpy(dst + hdr_size, *src, byte_cnt);
349
350 /*
351 * If this is the last block, zero the remainder of it.
352 * Check that we are actually the last block, too.
353 */
ff105f75 354 if (byte_cnt + hdr_size < blksize) {
f08bc2a9 355 ASSERT(*valuelen - byte_cnt == 0);
ff105f75 356 ASSERT(len == blksize);
f08bc2a9 357 memset(dst + hdr_size + byte_cnt, 0,
ff105f75 358 blksize - hdr_size - byte_cnt);
f08bc2a9
DC
359 }
360
361 /* roll buffer forwards */
ff105f75
DC
362 len -= blksize;
363 dst += blksize;
364 bno += BTOBB(blksize);
f08bc2a9
DC
365
366 /* roll attribute data forwards */
367 *valuelen -= byte_cnt;
368 *src += byte_cnt;
369 *offset += byte_cnt;
370 }
59915981
DC
371}
372
9d6fabc0
DC
373/*
374 * Read the value associated with an attribute from the out-of-line buffer
375 * that we stored it in.
42a383ab
DC
376 *
377 * Returns 0 on successful retrieval, otherwise an error.
9d6fabc0
DC
378 */
379int
59915981
DC
380xfs_attr_rmtval_get(
381 struct xfs_da_args *args)
9d6fabc0 382{
59915981
DC
383 struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE];
384 struct xfs_mount *mp = args->dp->i_mount;
385 struct xfs_buf *bp;
59915981 386 xfs_dablk_t lblkno = args->rmtblkno;
4a492e72 387 uint8_t *dst = args->value;
ff105f75 388 int valuelen;
59915981
DC
389 int nmap;
390 int error;
f08bc2a9 391 int blkcnt = args->rmtblkcnt;
59915981
DC
392 int i;
393 int offset = 0;
9d6fabc0
DC
394
395 trace_xfs_attr_rmtval_get(args);
396
c1a80a3b 397 ASSERT(args->valuelen != 0);
ff105f75 398 ASSERT(args->rmtvaluelen == args->valuelen);
9d6fabc0 399
ff105f75 400 valuelen = args->rmtvaluelen;
9d6fabc0
DC
401 while (valuelen > 0) {
402 nmap = ATTR_RMTVALUE_MAPSIZE;
403 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
72e78b51 404 blkcnt, map, &nmap,
9d6fabc0
DC
405 XFS_BMAPI_ATTRFORK);
406 if (error)
59915981 407 return error;
9d6fabc0
DC
408 ASSERT(nmap >= 1);
409
410 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
f08bc2a9
DC
411 xfs_daddr_t dblkno;
412 int dblkcnt;
59915981 413
9d6fabc0
DC
414 ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
415 (map[i].br_startblock != HOLESTARTBLOCK));
416 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
f08bc2a9 417 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
31079e67
DW
418 error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
419 0, &bp, &xfs_attr3_rmt_buf_ops);
420 if (error)
421 return error;
59915981 422
f08bc2a9
DC
423 error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
424 &offset, &valuelen,
425 &dst);
a8bbb628 426 xfs_buf_relse(bp);
f08bc2a9
DC
427 if (error)
428 return error;
59915981 429
f08bc2a9 430 /* roll attribute extent map forwards */
9d6fabc0 431 lblkno += map[i].br_blockcount;
f08bc2a9 432 blkcnt -= map[i].br_blockcount;
9d6fabc0
DC
433 }
434 }
435 ASSERT(valuelen == 0);
59915981 436 return 0;
9d6fabc0
DC
437}
438
439/*
91986fc1 440 * Find a "hole" in the attribute address space large enough for us to drop the
d6d6237c 441 * new attributes value into
9d6fabc0 442 */
d6d6237c 443int
91986fc1 444xfs_attr_rmt_find_hole(
59915981 445 struct xfs_da_args *args)
9d6fabc0 446{
59915981
DC
447 struct xfs_inode *dp = args->dp;
448 struct xfs_mount *mp = dp->i_mount;
59915981 449 int error;
91986fc1
AC
450 int blkcnt;
451 xfs_fileoff_t lfileoff = 0;
9d6fabc0 452
9d6fabc0 453 /*
91986fc1
AC
454 * Because CRC enable attributes have headers, we can't just do a
455 * straight byte to FSB conversion and have to take the header space
456 * into account.
9d6fabc0 457 */
ff105f75 458 blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
9d6fabc0
DC
459 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
460 XFS_ATTR_FORK);
59915981
DC
461 if (error)
462 return error;
463
91986fc1 464 args->rmtblkno = (xfs_dablk_t)lfileoff;
9d6fabc0
DC
465 args->rmtblkcnt = blkcnt;
466
91986fc1
AC
467 return 0;
468}
9d6fabc0 469
d6d6237c 470int
91986fc1
AC
471xfs_attr_rmtval_set_value(
472 struct xfs_da_args *args)
473{
474 struct xfs_inode *dp = args->dp;
475 struct xfs_mount *mp = dp->i_mount;
476 struct xfs_bmbt_irec map;
477 xfs_dablk_t lblkno;
478 uint8_t *src = args->value;
479 int blkcnt;
480 int valuelen;
481 int nmap;
482 int error;
483 int offset = 0;
9d6fabc0
DC
484
485 /*
486 * Roll through the "value", copying the attribute value to the
487 * already-allocated blocks. Blocks are written synchronously
488 * so that we can know they are all on disk before we turn off
489 * the INCOMPLETE flag.
490 */
491 lblkno = args->rmtblkno;
4da23ca6 492 blkcnt = args->rmtblkcnt;
ff105f75 493 valuelen = args->rmtvaluelen;
9d6fabc0 494 while (valuelen > 0) {
f08bc2a9
DC
495 struct xfs_buf *bp;
496 xfs_daddr_t dblkno;
497 int dblkcnt;
498
499 ASSERT(blkcnt > 0);
9d6fabc0 500
9d6fabc0
DC
501 nmap = 1;
502 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
4da23ca6 503 blkcnt, &map, &nmap,
9d6fabc0
DC
504 XFS_BMAPI_ATTRFORK);
505 if (error)
af43ca9f 506 return error;
9d6fabc0
DC
507 ASSERT(nmap == 1);
508 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
509 (map.br_startblock != HOLESTARTBLOCK));
510
511 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
4da23ca6 512 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
9d6fabc0 513
58a8b31f
DW
514 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
515 if (error)
516 return error;
59915981
DC
517 bp->b_ops = &xfs_attr3_rmt_buf_ops;
518
f08bc2a9
DC
519 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
520 &valuelen, &src);
9d6fabc0
DC
521
522 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
523 xfs_buf_relse(bp);
524 if (error)
525 return error;
59915981 526
9d6fabc0 527
f08bc2a9 528 /* roll attribute extent map forwards */
9d6fabc0 529 lblkno += map.br_blockcount;
4da23ca6 530 blkcnt -= map.br_blockcount;
9d6fabc0
DC
531 }
532 ASSERT(valuelen == 0);
59915981 533 return 0;
9d6fabc0
DC
534}
535
5867837a
DW
536/* Mark stale any incore buffers for the remote value. */
537int
538xfs_attr_rmtval_stale(
539 struct xfs_inode *ip,
540 struct xfs_bmbt_irec *map,
541 xfs_buf_flags_t incore_flags)
542{
543 struct xfs_mount *mp = ip->i_mount;
544 struct xfs_buf *bp;
0b2f4162 545 int error;
5867837a
DW
546
547 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
548
549 if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
550 XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK))
551 return -EFSCORRUPTED;
552
0b2f4162 553 error = xfs_buf_incore(mp->m_ddev_targp,
5867837a 554 XFS_FSB_TO_DADDR(mp, map->br_startblock),
0b2f4162
DC
555 XFS_FSB_TO_BB(mp, map->br_blockcount),
556 incore_flags, &bp);
557 if (error) {
558 if (error == -ENOENT)
559 return 0;
560 return error;
5867837a
DW
561 }
562
0b2f4162
DC
563 xfs_buf_stale(bp);
564 xfs_buf_relse(bp);
5867837a
DW
565 return 0;
566}
567
d6d6237c
AH
568/*
569 * Find a hole for the attr and store it in the delayed attr context. This
570 * initializes the context to roll through allocating an attr extent for a
571 * delayed attr operation
572 */
573int
574xfs_attr_rmtval_find_space(
eff5933f 575 struct xfs_attr_intent *attr)
d6d6237c 576{
a951e052
AH
577 struct xfs_da_args *args = attr->xattri_da_args;
578 struct xfs_bmbt_irec *map = &attr->xattri_map;
d6d6237c
AH
579 int error;
580
a951e052
AH
581 attr->xattri_lblkno = 0;
582 attr->xattri_blkcnt = 0;
d6d6237c
AH
583 args->rmtblkcnt = 0;
584 args->rmtblkno = 0;
585 memset(map, 0, sizeof(struct xfs_bmbt_irec));
586
587 error = xfs_attr_rmt_find_hole(args);
588 if (error)
589 return error;
590
a951e052
AH
591 attr->xattri_blkcnt = args->rmtblkcnt;
592 attr->xattri_lblkno = args->rmtblkno;
d6d6237c
AH
593
594 return 0;
595}
596
597/*
598 * Write one block of the value associated with an attribute into the
599 * out-of-line buffer that we have defined for it. This is similar to a subset
600 * of xfs_attr_rmtval_set, but records the current block to the delayed attr
601 * context, and leaves transaction handling to the caller.
602 */
603int
604xfs_attr_rmtval_set_blk(
eff5933f 605 struct xfs_attr_intent *attr)
d6d6237c 606{
a951e052 607 struct xfs_da_args *args = attr->xattri_da_args;
d6d6237c 608 struct xfs_inode *dp = args->dp;
a951e052 609 struct xfs_bmbt_irec *map = &attr->xattri_map;
d6d6237c
AH
610 int nmap;
611 int error;
612
613 nmap = 1;
a951e052
AH
614 error = xfs_bmapi_write(args->trans, dp,
615 (xfs_fileoff_t)attr->xattri_lblkno,
616 attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,
d6d6237c
AH
617 map, &nmap);
618 if (error)
619 return error;
620
621 ASSERT(nmap == 1);
622 ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
623 (map->br_startblock != HOLESTARTBLOCK));
624
625 /* roll attribute extent map forwards */
a951e052
AH
626 attr->xattri_lblkno += map->br_blockcount;
627 attr->xattri_blkcnt -= map->br_blockcount;
d6d6237c
AH
628
629 return 0;
630}
631
9d6fabc0
DC
632/*
633 * Remove the value associated with an attribute by deleting the
634 * out-of-line buffer that it is stored on.
635 */
636int
5a2edbba 637xfs_attr_rmtval_invalidate(
f08bc2a9 638 struct xfs_da_args *args)
9d6fabc0 639{
f08bc2a9
DC
640 xfs_dablk_t lblkno;
641 int blkcnt;
642 int error;
9d6fabc0 643
9d6fabc0 644 /*
526f9be5 645 * Roll through the "value", invalidating the attribute value's blocks.
9d6fabc0
DC
646 */
647 lblkno = args->rmtblkno;
f08bc2a9
DC
648 blkcnt = args->rmtblkcnt;
649 while (blkcnt > 0) {
650 struct xfs_bmbt_irec map;
f08bc2a9 651 int nmap;
526f9be5 652
9d6fabc0
DC
653 /*
654 * Try to remember where we decided to put the value.
655 */
656 nmap = 1;
657 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
526f9be5 658 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
9d6fabc0 659 if (error)
af43ca9f 660 return error;
5867837a
DW
661 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
662 return -EFSCORRUPTED;
663 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
664 if (error)
665 return error;
9d6fabc0 666
9d6fabc0 667 lblkno += map.br_blockcount;
526f9be5 668 blkcnt -= map.br_blockcount;
9d6fabc0 669 }
5a2edbba
AC
670 return 0;
671}
9d6fabc0 672
978b6ada
AC
673/*
674 * Remove the value associated with an attribute by deleting the out-of-line
c749b4e1
AH
675 * buffer that it is stored on. Returns -EAGAIN for the caller to refresh the
676 * transaction and re-call the function. Callers should keep calling this
677 * routine until it returns something other than -EAGAIN.
978b6ada
AC
678 */
679int
4acc0d5d 680xfs_attr_rmtval_remove(
eff5933f 681 struct xfs_attr_intent *attr)
978b6ada 682{
a951e052 683 struct xfs_da_args *args = attr->xattri_da_args;
c749b4e1 684 int error, done;
978b6ada
AC
685
686 /*
687 * Unmap value blocks for this attr.
688 */
689 error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
690 args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
691 if (error)
692 return error;
693
c749b4e1
AH
694 /*
695 * We don't need an explicit state here to pick up where we left off. We
696 * can figure it out using the !done return code. The actual value of
697 * attr->xattri_dela_state may be some value reminiscent of the calling
698 * function, but it's value is irrelevant with in the context of this
699 * function. Once we are done here, the next state is set as needed by
700 * the parent
701 */
702 if (!done) {
a951e052
AH
703 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,
704 args->dp);
978b6ada 705 return -EAGAIN;
c749b4e1 706 }
978b6ada 707
c749b4e1
AH
708 args->rmtblkno = 0;
709 args->rmtblkcnt = 0;
710 return 0;
978b6ada 711}