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