GNU Linux-libre 6.9-gnu
[releases.git] / fs / xfs / libxfs / xfs_attr_remote.c
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 xfs_attr3_rmt_blocks(
52         struct xfs_mount *mp,
53         int             attrlen)
54 {
55         if (xfs_has_crc(mp)) {
56                 int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
57                 return (attrlen + buflen - 1) / buflen;
58         }
59         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 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         struct xfs_attr3_rmt_hdr *rmt = ptr;
76
77         if (bno != be64_to_cpu(rmt->rm_blkno))
78                 return __this_address;
79         if (offset != be32_to_cpu(rmt->rm_offset))
80                 return __this_address;
81         if (size != be32_to_cpu(rmt->rm_bytes))
82                 return __this_address;
83         if (ino != be64_to_cpu(rmt->rm_owner))
84                 return __this_address;
85
86         /* ok */
87         return NULL;
88 }
89
90 static xfs_failaddr_t
91 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         struct xfs_attr3_rmt_hdr *rmt = ptr;
99
100         if (!xfs_verify_magic(bp, rmt->rm_magic))
101                 return __this_address;
102         if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
103                 return __this_address;
104         if (be64_to_cpu(rmt->rm_blkno) != bno)
105                 return __this_address;
106         if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
107                 return __this_address;
108         if (be32_to_cpu(rmt->rm_offset) +
109                                 be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
110                 return __this_address;
111         if (rmt->rm_owner == 0)
112                 return __this_address;
113
114         return NULL;
115 }
116
117 static int
118 __xfs_attr3_rmt_read_verify(
119         struct xfs_buf  *bp,
120         bool            check_crc,
121         xfs_failaddr_t  *failaddr)
122 {
123         struct xfs_mount *mp = bp->b_mount;
124         char            *ptr;
125         int             len;
126         xfs_daddr_t     bno;
127         int             blksize = mp->m_attr_geo->blksize;
128
129         /* no verification of non-crc buffers */
130         if (!xfs_has_crc(mp))
131                 return 0;
132
133         ptr = bp->b_addr;
134         bno = xfs_buf_daddr(bp);
135         len = BBTOB(bp->b_length);
136         ASSERT(len >= blksize);
137
138         while (len > 0) {
139                 if (check_crc &&
140                     !xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
141                         *failaddr = __this_address;
142                         return -EFSBADCRC;
143                 }
144                 *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
145                 if (*failaddr)
146                         return -EFSCORRUPTED;
147                 len -= blksize;
148                 ptr += blksize;
149                 bno += BTOBB(blksize);
150         }
151
152         if (len != 0) {
153                 *failaddr = __this_address;
154                 return -EFSCORRUPTED;
155         }
156
157         return 0;
158 }
159
160 static void
161 xfs_attr3_rmt_read_verify(
162         struct xfs_buf  *bp)
163 {
164         xfs_failaddr_t  fa;
165         int             error;
166
167         error = __xfs_attr3_rmt_read_verify(bp, true, &fa);
168         if (error)
169                 xfs_verifier_error(bp, error, fa);
170 }
171
172 static xfs_failaddr_t
173 xfs_attr3_rmt_verify_struct(
174         struct xfs_buf  *bp)
175 {
176         xfs_failaddr_t  fa;
177         int             error;
178
179         error = __xfs_attr3_rmt_read_verify(bp, false, &fa);
180         return error ? fa : NULL;
181 }
182
183 static void
184 xfs_attr3_rmt_write_verify(
185         struct xfs_buf  *bp)
186 {
187         struct xfs_mount *mp = bp->b_mount;
188         xfs_failaddr_t  fa;
189         int             blksize = mp->m_attr_geo->blksize;
190         char            *ptr;
191         int             len;
192         xfs_daddr_t     bno;
193
194         /* no verification of non-crc buffers */
195         if (!xfs_has_crc(mp))
196                 return;
197
198         ptr = bp->b_addr;
199         bno = xfs_buf_daddr(bp);
200         len = BBTOB(bp->b_length);
201         ASSERT(len >= blksize);
202
203         while (len > 0) {
204                 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
205
206                 fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
207                 if (fa) {
208                         xfs_verifier_error(bp, -EFSCORRUPTED, fa);
209                         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                 if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) {
217                         xfs_verifier_error(bp, -EFSCORRUPTED, __this_address);
218                         return;
219                 }
220                 xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
221
222                 len -= blksize;
223                 ptr += blksize;
224                 bno += BTOBB(blksize);
225         }
226
227         if (len != 0)
228                 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 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         struct xfs_attr3_rmt_hdr *rmt = ptr;
249
250         if (!xfs_has_crc(mp))
251                 return 0;
252
253         rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC);
254         rmt->rm_offset = cpu_to_be32(offset);
255         rmt->rm_bytes = cpu_to_be32(size);
256         uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid);
257         rmt->rm_owner = cpu_to_be64(ino);
258         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         rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN);
271
272         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 xfs_attr_rmtval_copyout(
280         struct xfs_mount        *mp,
281         struct xfs_buf          *bp,
282         struct xfs_inode        *dp,
283         int                     *offset,
284         int                     *valuelen,
285         uint8_t                 **dst)
286 {
287         char                    *src = bp->b_addr;
288         xfs_ino_t               ino = dp->i_ino;
289         xfs_daddr_t             bno = xfs_buf_daddr(bp);
290         int                     len = BBTOB(bp->b_length);
291         int                     blksize = mp->m_attr_geo->blksize;
292
293         ASSERT(len >= blksize);
294
295         while (len > 0 && *valuelen > 0) {
296                 int hdr_size = 0;
297                 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
298
299                 byte_cnt = min(*valuelen, byte_cnt);
300
301                 if (xfs_has_crc(mp)) {
302                         if (xfs_attr3_rmt_hdr_ok(src, ino, *offset,
303                                                   byte_cnt, bno)) {
304                                 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, ino);
307                                 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
308                                 return -EFSCORRUPTED;
309                         }
310                         hdr_size = sizeof(struct xfs_attr3_rmt_hdr);
311                 }
312
313                 memcpy(*dst, src + hdr_size, byte_cnt);
314
315                 /* roll buffer forwards */
316                 len -= blksize;
317                 src += blksize;
318                 bno += BTOBB(blksize);
319
320                 /* roll attribute data forwards */
321                 *valuelen -= byte_cnt;
322                 *dst += byte_cnt;
323                 *offset += byte_cnt;
324         }
325         return 0;
326 }
327
328 STATIC void
329 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         char            *dst = bp->b_addr;
338         xfs_daddr_t     bno = xfs_buf_daddr(bp);
339         int             len = BBTOB(bp->b_length);
340         int             blksize = mp->m_attr_geo->blksize;
341
342         ASSERT(len >= blksize);
343
344         while (len > 0 && *valuelen > 0) {
345                 int hdr_size;
346                 int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
347
348                 byte_cnt = min(*valuelen, byte_cnt);
349                 hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
350                                                  byte_cnt, bno);
351
352                 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                 if (byte_cnt + hdr_size < blksize) {
359                         ASSERT(*valuelen - byte_cnt == 0);
360                         ASSERT(len == blksize);
361                         memset(dst + hdr_size + byte_cnt, 0,
362                                         blksize - hdr_size - byte_cnt);
363                 }
364
365                 /* roll buffer forwards */
366                 len -= blksize;
367                 dst += blksize;
368                 bno += BTOBB(blksize);
369
370                 /* roll attribute data forwards */
371                 *valuelen -= byte_cnt;
372                 *src += byte_cnt;
373                 *offset += byte_cnt;
374         }
375 }
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 xfs_attr_rmtval_get(
385         struct xfs_da_args      *args)
386 {
387         struct xfs_bmbt_irec    map[ATTR_RMTVALUE_MAPSIZE];
388         struct xfs_mount        *mp = args->dp->i_mount;
389         struct xfs_buf          *bp;
390         xfs_dablk_t             lblkno = args->rmtblkno;
391         uint8_t                 *dst = args->value;
392         int                     valuelen;
393         int                     nmap;
394         int                     error;
395         int                     blkcnt = args->rmtblkcnt;
396         int                     i;
397         int                     offset = 0;
398
399         trace_xfs_attr_rmtval_get(args);
400
401         ASSERT(args->valuelen != 0);
402         ASSERT(args->rmtvaluelen == args->valuelen);
403
404         valuelen = args->rmtvaluelen;
405         while (valuelen > 0) {
406                 nmap = ATTR_RMTVALUE_MAPSIZE;
407                 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
408                                        blkcnt, map, &nmap,
409                                        XFS_BMAPI_ATTRFORK);
410                 if (error)
411                         return error;
412                 ASSERT(nmap >= 1);
413
414                 for (i = 0; (i < nmap) && (valuelen > 0); i++) {
415                         xfs_daddr_t     dblkno;
416                         int             dblkcnt;
417
418                         ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) &&
419                                (map[i].br_startblock != HOLESTARTBLOCK));
420                         dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
421                         dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
422                         error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
423                                         0, &bp, &xfs_attr3_rmt_buf_ops);
424                         if (xfs_metadata_is_sick(error))
425                                 xfs_dirattr_mark_sick(args->dp, XFS_ATTR_FORK);
426                         if (error)
427                                 return error;
428
429                         error = xfs_attr_rmtval_copyout(mp, bp, args->dp,
430                                                         &offset, &valuelen,
431                                                         &dst);
432                         xfs_buf_relse(bp);
433                         if (error)
434                                 return error;
435
436                         /* roll attribute extent map forwards */
437                         lblkno += map[i].br_blockcount;
438                         blkcnt -= map[i].br_blockcount;
439                 }
440         }
441         ASSERT(valuelen == 0);
442         return 0;
443 }
444
445 /*
446  * Find a "hole" in the attribute address space large enough for us to drop the
447  * new attributes value into
448  */
449 int
450 xfs_attr_rmt_find_hole(
451         struct xfs_da_args      *args)
452 {
453         struct xfs_inode        *dp = args->dp;
454         struct xfs_mount        *mp = dp->i_mount;
455         int                     error;
456         int                     blkcnt;
457         xfs_fileoff_t           lfileoff = 0;
458
459         /*
460          * Because CRC enable attributes have headers, we can't just do a
461          * straight byte to FSB conversion and have to take the header space
462          * into account.
463          */
464         blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
465         error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
466                                                    XFS_ATTR_FORK);
467         if (error)
468                 return error;
469
470         args->rmtblkno = (xfs_dablk_t)lfileoff;
471         args->rmtblkcnt = blkcnt;
472
473         return 0;
474 }
475
476 int
477 xfs_attr_rmtval_set_value(
478         struct xfs_da_args      *args)
479 {
480         struct xfs_inode        *dp = args->dp;
481         struct xfs_mount        *mp = dp->i_mount;
482         struct xfs_bmbt_irec    map;
483         xfs_dablk_t             lblkno;
484         uint8_t                 *src = args->value;
485         int                     blkcnt;
486         int                     valuelen;
487         int                     nmap;
488         int                     error;
489         int                     offset = 0;
490
491         /*
492          * Roll through the "value", copying the attribute value to the
493          * already-allocated blocks.  Blocks are written synchronously
494          * so that we can know they are all on disk before we turn off
495          * the INCOMPLETE flag.
496          */
497         lblkno = args->rmtblkno;
498         blkcnt = args->rmtblkcnt;
499         valuelen = args->rmtvaluelen;
500         while (valuelen > 0) {
501                 struct xfs_buf  *bp;
502                 xfs_daddr_t     dblkno;
503                 int             dblkcnt;
504
505                 ASSERT(blkcnt > 0);
506
507                 nmap = 1;
508                 error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
509                                        blkcnt, &map, &nmap,
510                                        XFS_BMAPI_ATTRFORK);
511                 if (error)
512                         return error;
513                 ASSERT(nmap == 1);
514                 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
515                        (map.br_startblock != HOLESTARTBLOCK));
516
517                 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
518                 dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
519
520                 error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
521                 if (error)
522                         return error;
523                 bp->b_ops = &xfs_attr3_rmt_buf_ops;
524
525                 xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
526                                        &valuelen, &src);
527
528                 error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
529                 xfs_buf_relse(bp);
530                 if (error)
531                         return error;
532
533
534                 /* roll attribute extent map forwards */
535                 lblkno += map.br_blockcount;
536                 blkcnt -= map.br_blockcount;
537         }
538         ASSERT(valuelen == 0);
539         return 0;
540 }
541
542 /* Mark stale any incore buffers for the remote value. */
543 int
544 xfs_attr_rmtval_stale(
545         struct xfs_inode        *ip,
546         struct xfs_bmbt_irec    *map,
547         xfs_buf_flags_t         incore_flags)
548 {
549         struct xfs_mount        *mp = ip->i_mount;
550         struct xfs_buf          *bp;
551         int                     error;
552
553         xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
554
555         if (XFS_IS_CORRUPT(mp, map->br_startblock == DELAYSTARTBLOCK) ||
556             XFS_IS_CORRUPT(mp, map->br_startblock == HOLESTARTBLOCK)) {
557                 xfs_bmap_mark_sick(ip, XFS_ATTR_FORK);
558                 return -EFSCORRUPTED;
559         }
560
561         error = xfs_buf_incore(mp->m_ddev_targp,
562                         XFS_FSB_TO_DADDR(mp, map->br_startblock),
563                         XFS_FSB_TO_BB(mp, map->br_blockcount),
564                         incore_flags, &bp);
565         if (error) {
566                 if (error == -ENOENT)
567                         return 0;
568                 return error;
569         }
570
571         xfs_buf_stale(bp);
572         xfs_buf_relse(bp);
573         return 0;
574 }
575
576 /*
577  * Find a hole for the attr and store it in the delayed attr context.  This
578  * initializes the context to roll through allocating an attr extent for a
579  * delayed attr operation
580  */
581 int
582 xfs_attr_rmtval_find_space(
583         struct xfs_attr_intent          *attr)
584 {
585         struct xfs_da_args              *args = attr->xattri_da_args;
586         struct xfs_bmbt_irec            *map = &attr->xattri_map;
587         int                             error;
588
589         attr->xattri_lblkno = 0;
590         attr->xattri_blkcnt = 0;
591         args->rmtblkcnt = 0;
592         args->rmtblkno = 0;
593         memset(map, 0, sizeof(struct xfs_bmbt_irec));
594
595         error = xfs_attr_rmt_find_hole(args);
596         if (error)
597                 return error;
598
599         attr->xattri_blkcnt = args->rmtblkcnt;
600         attr->xattri_lblkno = args->rmtblkno;
601
602         return 0;
603 }
604
605 /*
606  * Write one block of the value associated with an attribute into the
607  * out-of-line buffer that we have defined for it. This is similar to a subset
608  * of xfs_attr_rmtval_set, but records the current block to the delayed attr
609  * context, and leaves transaction handling to the caller.
610  */
611 int
612 xfs_attr_rmtval_set_blk(
613         struct xfs_attr_intent          *attr)
614 {
615         struct xfs_da_args              *args = attr->xattri_da_args;
616         struct xfs_inode                *dp = args->dp;
617         struct xfs_bmbt_irec            *map = &attr->xattri_map;
618         int nmap;
619         int error;
620
621         nmap = 1;
622         error = xfs_bmapi_write(args->trans, dp,
623                         (xfs_fileoff_t)attr->xattri_lblkno,
624                         attr->xattri_blkcnt, XFS_BMAPI_ATTRFORK, args->total,
625                         map, &nmap);
626         if (error)
627                 return error;
628
629         ASSERT(nmap == 1);
630         ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
631                (map->br_startblock != HOLESTARTBLOCK));
632
633         /* roll attribute extent map forwards */
634         attr->xattri_lblkno += map->br_blockcount;
635         attr->xattri_blkcnt -= map->br_blockcount;
636
637         return 0;
638 }
639
640 /*
641  * Remove the value associated with an attribute by deleting the
642  * out-of-line buffer that it is stored on.
643  */
644 int
645 xfs_attr_rmtval_invalidate(
646         struct xfs_da_args      *args)
647 {
648         xfs_dablk_t             lblkno;
649         int                     blkcnt;
650         int                     error;
651
652         /*
653          * Roll through the "value", invalidating the attribute value's blocks.
654          */
655         lblkno = args->rmtblkno;
656         blkcnt = args->rmtblkcnt;
657         while (blkcnt > 0) {
658                 struct xfs_bmbt_irec    map;
659                 int                     nmap;
660
661                 /*
662                  * Try to remember where we decided to put the value.
663                  */
664                 nmap = 1;
665                 error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno,
666                                        blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
667                 if (error)
668                         return error;
669                 if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1)) {
670                         xfs_bmap_mark_sick(args->dp, XFS_ATTR_FORK);
671                         return -EFSCORRUPTED;
672                 }
673                 error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
674                 if (error)
675                         return error;
676
677                 lblkno += map.br_blockcount;
678                 blkcnt -= map.br_blockcount;
679         }
680         return 0;
681 }
682
683 /*
684  * Remove the value associated with an attribute by deleting the out-of-line
685  * buffer that it is stored on. Returns -EAGAIN for the caller to refresh the
686  * transaction and re-call the function.  Callers should keep calling this
687  * routine until it returns something other than -EAGAIN.
688  */
689 int
690 xfs_attr_rmtval_remove(
691         struct xfs_attr_intent          *attr)
692 {
693         struct xfs_da_args              *args = attr->xattri_da_args;
694         int                             error, done;
695
696         /*
697          * Unmap value blocks for this attr.
698          */
699         error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
700                             args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
701         if (error)
702                 return error;
703
704         /*
705          * We don't need an explicit state here to pick up where we left off. We
706          * can figure it out using the !done return code. The actual value of
707          * attr->xattri_dela_state may be some value reminiscent of the calling
708          * function, but it's value is irrelevant with in the context of this
709          * function. Once we are done here, the next state is set as needed by
710          * the parent
711          */
712         if (!done) {
713                 trace_xfs_attr_rmtval_remove_return(attr->xattri_dela_state,
714                                                     args->dp);
715                 return -EAGAIN;
716         }
717
718         args->rmtblkno = 0;
719         args->rmtblkcnt = 0;
720         return 0;
721 }