hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/xfs/libxfs/xfs_attr_remote.c
....@@ -16,21 +16,31 @@
1616 #include "xfs_da_format.h"
1717 #include "xfs_da_btree.h"
1818 #include "xfs_inode.h"
19
-#include "xfs_alloc.h"
2019 #include "xfs_trans.h"
21
-#include "xfs_inode_item.h"
2220 #include "xfs_bmap.h"
23
-#include "xfs_bmap_util.h"
2421 #include "xfs_attr.h"
25
-#include "xfs_attr_leaf.h"
2622 #include "xfs_attr_remote.h"
27
-#include "xfs_trans_space.h"
2823 #include "xfs_trace.h"
29
-#include "xfs_cksum.h"
30
-#include "xfs_buf_item.h"
3124 #include "xfs_error.h"
3225
3326 #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
27
+
28
+/*
29
+ * Remote Attribute Values
30
+ * =======================
31
+ *
32
+ * Remote extended attribute values are conceptually simple -- they're written
33
+ * to data blocks mapped by an inode's attribute fork, and they have an upper
34
+ * size limit of 64k. Setting a value does not involve the XFS log.
35
+ *
36
+ * However, on a v5 filesystem, maximally sized remote attr values require one
37
+ * block more than 64k worth of space to hold both the remote attribute value
38
+ * header (64 bytes). On a 4k block filesystem this results in a 68k buffer;
39
+ * on a 64k block filesystem, this would be a 128k buffer. Note that the log
40
+ * format can only handle a dirty buffer of XFS_MAX_BLOCKSIZE length (64k).
41
+ * Therefore, we /must/ ensure that remote attribute value buffers never touch
42
+ * the logging system and therefore never have a log item.
43
+ */
3444
3545 /*
3646 * Each contiguous block has a header, so it is not just a simple attribute
....@@ -79,15 +89,14 @@
7989 static xfs_failaddr_t
8090 xfs_attr3_rmt_verify(
8191 struct xfs_mount *mp,
92
+ struct xfs_buf *bp,
8293 void *ptr,
8394 int fsbsize,
8495 xfs_daddr_t bno)
8596 {
8697 struct xfs_attr3_rmt_hdr *rmt = ptr;
8798
88
- if (!xfs_sb_version_hascrc(&mp->m_sb))
89
- return __this_address;
90
- if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC))
99
+ if (!xfs_verify_magic(bp, rmt->rm_magic))
91100 return __this_address;
92101 if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid))
93102 return __this_address;
....@@ -110,7 +119,7 @@
110119 bool check_crc,
111120 xfs_failaddr_t *failaddr)
112121 {
113
- struct xfs_mount *mp = bp->b_target->bt_mount;
122
+ struct xfs_mount *mp = bp->b_mount;
114123 char *ptr;
115124 int len;
116125 xfs_daddr_t bno;
....@@ -131,7 +140,7 @@
131140 *failaddr = __this_address;
132141 return -EFSBADCRC;
133142 }
134
- *failaddr = xfs_attr3_rmt_verify(mp, ptr, blksize, bno);
143
+ *failaddr = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
135144 if (*failaddr)
136145 return -EFSCORRUPTED;
137146 len -= blksize;
....@@ -174,7 +183,7 @@
174183 xfs_attr3_rmt_write_verify(
175184 struct xfs_buf *bp)
176185 {
177
- struct xfs_mount *mp = bp->b_target->bt_mount;
186
+ struct xfs_mount *mp = bp->b_mount;
178187 xfs_failaddr_t fa;
179188 int blksize = mp->m_attr_geo->blksize;
180189 char *ptr;
....@@ -193,7 +202,7 @@
193202 while (len > 0) {
194203 struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr;
195204
196
- fa = xfs_attr3_rmt_verify(mp, ptr, blksize, bno);
205
+ fa = xfs_attr3_rmt_verify(mp, bp, ptr, blksize, bno);
197206 if (fa) {
198207 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
199208 return;
....@@ -220,6 +229,7 @@
220229
221230 const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = {
222231 .name = "xfs_attr3_rmt",
232
+ .magic = { 0, cpu_to_be32(XFS_ATTR3_RMT_MAGIC) },
223233 .verify_read = xfs_attr3_rmt_read_verify,
224234 .verify_write = xfs_attr3_rmt_write_verify,
225235 .verify_struct = xfs_attr3_rmt_verify_struct,
....@@ -364,6 +374,8 @@
364374 /*
365375 * Read the value associated with an attribute from the out-of-line buffer
366376 * that we stored it in.
377
+ *
378
+ * Returns 0 on successful retrieval, otherwise an error.
367379 */
368380 int
369381 xfs_attr_rmtval_get(
....@@ -383,7 +395,7 @@
383395
384396 trace_xfs_attr_rmtval_get(args);
385397
386
- ASSERT(!(args->flags & ATTR_KERNOVAL));
398
+ ASSERT(args->valuelen != 0);
387399 ASSERT(args->rmtvaluelen == args->valuelen);
388400
389401 valuelen = args->rmtvaluelen;
....@@ -404,17 +416,15 @@
404416 (map[i].br_startblock != HOLESTARTBLOCK));
405417 dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
406418 dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
407
- error = xfs_trans_read_buf(mp, args->trans,
408
- mp->m_ddev_targp,
409
- dblkno, dblkcnt, 0, &bp,
410
- &xfs_attr3_rmt_buf_ops);
419
+ error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt,
420
+ 0, &bp, &xfs_attr3_rmt_buf_ops);
411421 if (error)
412422 return error;
413423
414424 error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
415425 &offset, &valuelen,
416426 &dst);
417
- xfs_trans_brelse(args->trans, bp);
427
+ xfs_buf_relse(bp);
418428 if (error)
419429 return error;
420430
....@@ -428,6 +438,130 @@
428438 }
429439
430440 /*
441
+ * Find a "hole" in the attribute address space large enough for us to drop the
442
+ * new attribute's value into
443
+ */
444
+STATIC int
445
+xfs_attr_rmt_find_hole(
446
+ struct xfs_da_args *args)
447
+{
448
+ struct xfs_inode *dp = args->dp;
449
+ struct xfs_mount *mp = dp->i_mount;
450
+ int error;
451
+ int blkcnt;
452
+ xfs_fileoff_t lfileoff = 0;
453
+
454
+ /*
455
+ * Because CRC enable attributes have headers, we can't just do a
456
+ * straight byte to FSB conversion and have to take the header space
457
+ * into account.
458
+ */
459
+ blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
460
+ error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
461
+ XFS_ATTR_FORK);
462
+ if (error)
463
+ return error;
464
+
465
+ args->rmtblkno = (xfs_dablk_t)lfileoff;
466
+ args->rmtblkcnt = blkcnt;
467
+
468
+ return 0;
469
+}
470
+
471
+STATIC int
472
+xfs_attr_rmtval_set_value(
473
+ struct xfs_da_args *args)
474
+{
475
+ struct xfs_inode *dp = args->dp;
476
+ struct xfs_mount *mp = dp->i_mount;
477
+ struct xfs_bmbt_irec map;
478
+ xfs_dablk_t lblkno;
479
+ uint8_t *src = args->value;
480
+ int blkcnt;
481
+ int valuelen;
482
+ int nmap;
483
+ int error;
484
+ int offset = 0;
485
+
486
+ /*
487
+ * Roll through the "value", copying the attribute value to the
488
+ * already-allocated blocks. Blocks are written synchronously
489
+ * so that we can know they are all on disk before we turn off
490
+ * the INCOMPLETE flag.
491
+ */
492
+ lblkno = args->rmtblkno;
493
+ blkcnt = args->rmtblkcnt;
494
+ valuelen = args->rmtvaluelen;
495
+ while (valuelen > 0) {
496
+ struct xfs_buf *bp;
497
+ xfs_daddr_t dblkno;
498
+ int dblkcnt;
499
+
500
+ ASSERT(blkcnt > 0);
501
+
502
+ nmap = 1;
503
+ error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
504
+ blkcnt, &map, &nmap,
505
+ XFS_BMAPI_ATTRFORK);
506
+ if (error)
507
+ return error;
508
+ ASSERT(nmap == 1);
509
+ ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
510
+ (map.br_startblock != HOLESTARTBLOCK));
511
+
512
+ dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
513
+ dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
514
+
515
+ error = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, &bp);
516
+ if (error)
517
+ return error;
518
+ bp->b_ops = &xfs_attr3_rmt_buf_ops;
519
+
520
+ xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
521
+ &valuelen, &src);
522
+
523
+ error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
524
+ xfs_buf_relse(bp);
525
+ if (error)
526
+ return error;
527
+
528
+
529
+ /* roll attribute extent map forwards */
530
+ lblkno += map.br_blockcount;
531
+ blkcnt -= map.br_blockcount;
532
+ }
533
+ ASSERT(valuelen == 0);
534
+ return 0;
535
+}
536
+
537
+/* Mark stale any incore buffers for the remote value. */
538
+int
539
+xfs_attr_rmtval_stale(
540
+ struct xfs_inode *ip,
541
+ struct xfs_bmbt_irec *map,
542
+ xfs_buf_flags_t incore_flags)
543
+{
544
+ struct xfs_mount *mp = ip->i_mount;
545
+ struct xfs_buf *bp;
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
+
553
+ bp = xfs_buf_incore(mp->m_ddev_targp,
554
+ XFS_FSB_TO_DADDR(mp, map->br_startblock),
555
+ XFS_FSB_TO_BB(mp, map->br_blockcount), incore_flags);
556
+ if (bp) {
557
+ xfs_buf_stale(bp);
558
+ xfs_buf_relse(bp);
559
+ }
560
+
561
+ return 0;
562
+}
563
+
564
+/*
431565 * Write the value associated with an attribute into the out-of-line buffer
432566 * that we have defined for it.
433567 */
....@@ -436,34 +570,20 @@
436570 struct xfs_da_args *args)
437571 {
438572 struct xfs_inode *dp = args->dp;
439
- struct xfs_mount *mp = dp->i_mount;
440573 struct xfs_bmbt_irec map;
441574 xfs_dablk_t lblkno;
442
- xfs_fileoff_t lfileoff = 0;
443
- uint8_t *src = args->value;
444575 int blkcnt;
445
- int valuelen;
446576 int nmap;
447577 int error;
448
- int offset = 0;
449578
450579 trace_xfs_attr_rmtval_set(args);
451580
452
- /*
453
- * Find a "hole" in the attribute address space large enough for
454
- * us to drop the new attribute's value into. Because CRC enable
455
- * attributes have headers, we can't just do a straight byte to FSB
456
- * conversion and have to take the header space into account.
457
- */
458
- blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
459
- error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
460
- XFS_ATTR_FORK);
581
+ error = xfs_attr_rmt_find_hole(args);
461582 if (error)
462583 return error;
463584
464
- args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
465
- args->rmtblkcnt = blkcnt;
466
-
585
+ blkcnt = args->rmtblkcnt;
586
+ lblkno = (xfs_dablk_t)args->rmtblkno;
467587 /*
468588 * Roll through the "value", allocating blocks on disk as required.
469589 */
....@@ -504,55 +624,7 @@
504624 return error;
505625 }
506626
507
- /*
508
- * Roll through the "value", copying the attribute value to the
509
- * already-allocated blocks. Blocks are written synchronously
510
- * so that we can know they are all on disk before we turn off
511
- * the INCOMPLETE flag.
512
- */
513
- lblkno = args->rmtblkno;
514
- blkcnt = args->rmtblkcnt;
515
- valuelen = args->rmtvaluelen;
516
- while (valuelen > 0) {
517
- struct xfs_buf *bp;
518
- xfs_daddr_t dblkno;
519
- int dblkcnt;
520
-
521
- ASSERT(blkcnt > 0);
522
-
523
- nmap = 1;
524
- error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno,
525
- blkcnt, &map, &nmap,
526
- XFS_BMAPI_ATTRFORK);
527
- if (error)
528
- return error;
529
- ASSERT(nmap == 1);
530
- ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
531
- (map.br_startblock != HOLESTARTBLOCK));
532
-
533
- dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
534
- dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
535
-
536
- bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0);
537
- if (!bp)
538
- return -ENOMEM;
539
- bp->b_ops = &xfs_attr3_rmt_buf_ops;
540
-
541
- xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset,
542
- &valuelen, &src);
543
-
544
- error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
545
- xfs_buf_relse(bp);
546
- if (error)
547
- return error;
548
-
549
-
550
- /* roll attribute extent map forwards */
551
- lblkno += map.br_blockcount;
552
- blkcnt -= map.br_blockcount;
553
- }
554
- ASSERT(valuelen == 0);
555
- return 0;
627
+ return xfs_attr_rmtval_set_value(args);
556628 }
557629
558630 /*
....@@ -560,16 +632,12 @@
560632 * out-of-line buffer that it is stored on.
561633 */
562634 int
563
-xfs_attr_rmtval_remove(
635
+xfs_attr_rmtval_invalidate(
564636 struct xfs_da_args *args)
565637 {
566
- struct xfs_mount *mp = args->dp->i_mount;
567638 xfs_dablk_t lblkno;
568639 int blkcnt;
569640 int error;
570
- int done;
571
-
572
- trace_xfs_attr_rmtval_remove(args);
573641
574642 /*
575643 * Roll through the "value", invalidating the attribute value's blocks.
....@@ -578,9 +646,6 @@
578646 blkcnt = args->rmtblkcnt;
579647 while (blkcnt > 0) {
580648 struct xfs_bmbt_irec map;
581
- struct xfs_buf *bp;
582
- xfs_daddr_t dblkno;
583
- int dblkcnt;
584649 int nmap;
585650
586651 /*
....@@ -591,41 +656,38 @@
591656 blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK);
592657 if (error)
593658 return error;
594
- ASSERT(nmap == 1);
595
- ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
596
- (map.br_startblock != HOLESTARTBLOCK));
597
-
598
- dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
599
- dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
600
-
601
- /*
602
- * If the "remote" value is in the cache, remove it.
603
- */
604
- bp = xfs_buf_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK);
605
- if (bp) {
606
- xfs_buf_stale(bp);
607
- xfs_buf_relse(bp);
608
- bp = NULL;
609
- }
659
+ if (XFS_IS_CORRUPT(args->dp->i_mount, nmap != 1))
660
+ return -EFSCORRUPTED;
661
+ error = xfs_attr_rmtval_stale(args->dp, &map, XBF_TRYLOCK);
662
+ if (error)
663
+ return error;
610664
611665 lblkno += map.br_blockcount;
612666 blkcnt -= map.br_blockcount;
613667 }
668
+ return 0;
669
+}
670
+
671
+/*
672
+ * Remove the value associated with an attribute by deleting the
673
+ * out-of-line buffer that it is stored on.
674
+ */
675
+int
676
+xfs_attr_rmtval_remove(
677
+ struct xfs_da_args *args)
678
+{
679
+ int error;
680
+ int retval;
681
+
682
+ trace_xfs_attr_rmtval_remove(args);
614683
615684 /*
616685 * Keep de-allocating extents until the remote-value region is gone.
617686 */
618
- lblkno = args->rmtblkno;
619
- blkcnt = args->rmtblkcnt;
620
- done = 0;
621
- while (!done) {
622
- error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
623
- XFS_BMAPI_ATTRFORK, 1, &done);
624
- if (error)
625
- return error;
626
- error = xfs_defer_finish(&args->trans);
627
- if (error)
628
- return error;
687
+ do {
688
+ retval = __xfs_attr_rmtval_remove(args);
689
+ if (retval && retval != -EAGAIN)
690
+ return retval;
629691
630692 /*
631693 * Close out trans and start the next one in the chain.
....@@ -633,6 +695,36 @@
633695 error = xfs_trans_roll_inode(&args->trans, args->dp);
634696 if (error)
635697 return error;
636
- }
698
+ } while (retval == -EAGAIN);
699
+
637700 return 0;
638701 }
702
+
703
+/*
704
+ * Remove the value associated with an attribute by deleting the out-of-line
705
+ * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
706
+ * transaction and re-call the function
707
+ */
708
+int
709
+__xfs_attr_rmtval_remove(
710
+ struct xfs_da_args *args)
711
+{
712
+ int error, done;
713
+
714
+ /*
715
+ * Unmap value blocks for this attr.
716
+ */
717
+ error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
718
+ args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
719
+ if (error)
720
+ return error;
721
+
722
+ error = xfs_defer_finish(&args->trans);
723
+ if (error)
724
+ return error;
725
+
726
+ if (!done)
727
+ return -EAGAIN;
728
+
729
+ return error;
730
+}