42
42
#include "xfs_icache.h"
43
43
#include "xfs_log.h"
44
44
#include "xfs_rmap_btree.h"
45
+ #include "xfs_iomap.h"
46
+ #include "xfs_reflink.h"
47
+ #include "xfs_refcount.h"
45
48
46
49
/* Kernel only BMAP related definitions and functions */
47
50
@@ -389,11 +392,13 @@ xfs_bmap_count_blocks(
389
392
STATIC int
390
393
xfs_getbmapx_fix_eof_hole (
391
394
xfs_inode_t * ip , /* xfs incore inode pointer */
395
+ int whichfork ,
392
396
struct getbmapx * out , /* output structure */
393
397
int prealloced , /* this is a file with
394
398
* preallocated data space */
395
399
__int64_t end , /* last block requested */
396
- xfs_fsblock_t startblock )
400
+ xfs_fsblock_t startblock ,
401
+ bool moretocome )
397
402
{
398
403
__int64_t fixlen ;
399
404
xfs_mount_t * mp ; /* file system mount point */
@@ -418,15 +423,91 @@ xfs_getbmapx_fix_eof_hole(
418
423
else
419
424
out -> bmv_block = xfs_fsb_to_db (ip , startblock );
420
425
fileblock = XFS_BB_TO_FSB (ip -> i_mount , out -> bmv_offset );
421
- ifp = XFS_IFORK_PTR (ip , XFS_DATA_FORK );
422
- if (xfs_iext_bno_to_ext (ifp , fileblock , & lastx ) &&
426
+ ifp = XFS_IFORK_PTR (ip , whichfork );
427
+ if (!moretocome &&
428
+ xfs_iext_bno_to_ext (ifp , fileblock , & lastx ) &&
423
429
(lastx == (ifp -> if_bytes / (uint )sizeof (xfs_bmbt_rec_t ))- 1 ))
424
430
out -> bmv_oflags |= BMV_OF_LAST ;
425
431
}
426
432
427
433
return 1 ;
428
434
}
429
435
436
+ /* Adjust the reported bmap around shared/unshared extent transitions. */
437
+ STATIC int
438
+ xfs_getbmap_adjust_shared (
439
+ struct xfs_inode * ip ,
440
+ int whichfork ,
441
+ struct xfs_bmbt_irec * map ,
442
+ struct getbmapx * out ,
443
+ struct xfs_bmbt_irec * next_map )
444
+ {
445
+ struct xfs_mount * mp = ip -> i_mount ;
446
+ xfs_agnumber_t agno ;
447
+ xfs_agblock_t agbno ;
448
+ xfs_agblock_t ebno ;
449
+ xfs_extlen_t elen ;
450
+ xfs_extlen_t nlen ;
451
+ int error ;
452
+
453
+ next_map -> br_startblock = NULLFSBLOCK ;
454
+ next_map -> br_startoff = NULLFILEOFF ;
455
+ next_map -> br_blockcount = 0 ;
456
+
457
+ /* Only written data blocks can be shared. */
458
+ if (!xfs_is_reflink_inode (ip ) || whichfork != XFS_DATA_FORK ||
459
+ map -> br_startblock == DELAYSTARTBLOCK ||
460
+ map -> br_startblock == HOLESTARTBLOCK ||
461
+ ISUNWRITTEN (map ))
462
+ return 0 ;
463
+
464
+ agno = XFS_FSB_TO_AGNO (mp , map -> br_startblock );
465
+ agbno = XFS_FSB_TO_AGBNO (mp , map -> br_startblock );
466
+ error = xfs_reflink_find_shared (mp , agno , agbno , map -> br_blockcount ,
467
+ & ebno , & elen , true);
468
+ if (error )
469
+ return error ;
470
+
471
+ if (ebno == NULLAGBLOCK ) {
472
+ /* No shared blocks at all. */
473
+ return 0 ;
474
+ } else if (agbno == ebno ) {
475
+ /*
476
+ * Shared extent at (agbno, elen). Shrink the reported
477
+ * extent length and prepare to move the start of map[i]
478
+ * to agbno+elen, with the aim of (re)formatting the new
479
+ * map[i] the next time through the inner loop.
480
+ */
481
+ out -> bmv_length = XFS_FSB_TO_BB (mp , elen );
482
+ out -> bmv_oflags |= BMV_OF_SHARED ;
483
+ if (elen != map -> br_blockcount ) {
484
+ * next_map = * map ;
485
+ next_map -> br_startblock += elen ;
486
+ next_map -> br_startoff += elen ;
487
+ next_map -> br_blockcount -= elen ;
488
+ }
489
+ map -> br_blockcount -= elen ;
490
+ } else {
491
+ /*
492
+ * There's an unshared extent (agbno, ebno - agbno)
493
+ * followed by shared extent at (ebno, elen). Shrink
494
+ * the reported extent length to cover only the unshared
495
+ * extent and prepare to move up the start of map[i] to
496
+ * ebno, with the aim of (re)formatting the new map[i]
497
+ * the next time through the inner loop.
498
+ */
499
+ * next_map = * map ;
500
+ nlen = ebno - agbno ;
501
+ out -> bmv_length = XFS_FSB_TO_BB (mp , nlen );
502
+ next_map -> br_startblock += nlen ;
503
+ next_map -> br_startoff += nlen ;
504
+ next_map -> br_blockcount -= nlen ;
505
+ map -> br_blockcount -= nlen ;
506
+ }
507
+
508
+ return 0 ;
509
+ }
510
+
430
511
/*
431
512
* Get inode's extents as described in bmv, and format for output.
432
513
* Calls formatter to fill the user's buffer until all extents
@@ -459,12 +540,28 @@ xfs_getbmap(
459
540
int iflags ; /* interface flags */
460
541
int bmapi_flags ; /* flags for xfs_bmapi */
461
542
int cur_ext = 0 ;
543
+ struct xfs_bmbt_irec inject_map ;
462
544
463
545
mp = ip -> i_mount ;
464
546
iflags = bmv -> bmv_iflags ;
465
- whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK ;
466
547
467
- if (whichfork == XFS_ATTR_FORK ) {
548
+ #ifndef DEBUG
549
+ /* Only allow CoW fork queries if we're debugging. */
550
+ if (iflags & BMV_IF_COWFORK )
551
+ return - EINVAL ;
552
+ #endif
553
+ if ((iflags & BMV_IF_ATTRFORK ) && (iflags & BMV_IF_COWFORK ))
554
+ return - EINVAL ;
555
+
556
+ if (iflags & BMV_IF_ATTRFORK )
557
+ whichfork = XFS_ATTR_FORK ;
558
+ else if (iflags & BMV_IF_COWFORK )
559
+ whichfork = XFS_COW_FORK ;
560
+ else
561
+ whichfork = XFS_DATA_FORK ;
562
+
563
+ switch (whichfork ) {
564
+ case XFS_ATTR_FORK :
468
565
if (XFS_IFORK_Q (ip )) {
469
566
if (ip -> i_d .di_aformat != XFS_DINODE_FMT_EXTENTS &&
470
567
ip -> i_d .di_aformat != XFS_DINODE_FMT_BTREE &&
@@ -480,7 +577,15 @@ xfs_getbmap(
480
577
481
578
prealloced = 0 ;
482
579
fixlen = 1LL << 32 ;
483
- } else {
580
+ break ;
581
+ case XFS_COW_FORK :
582
+ if (ip -> i_cformat != XFS_DINODE_FMT_EXTENTS )
583
+ return - EINVAL ;
584
+
585
+ prealloced = 0 ;
586
+ fixlen = XFS_ISIZE (ip );
587
+ break ;
588
+ default :
484
589
if (ip -> i_d .di_format != XFS_DINODE_FMT_EXTENTS &&
485
590
ip -> i_d .di_format != XFS_DINODE_FMT_BTREE &&
486
591
ip -> i_d .di_format != XFS_DINODE_FMT_LOCAL )
@@ -494,6 +599,7 @@ xfs_getbmap(
494
599
prealloced = 0 ;
495
600
fixlen = XFS_ISIZE (ip );
496
601
}
602
+ break ;
497
603
}
498
604
499
605
if (bmv -> bmv_length == -1 ) {
@@ -520,7 +626,8 @@ xfs_getbmap(
520
626
return - ENOMEM ;
521
627
522
628
xfs_ilock (ip , XFS_IOLOCK_SHARED );
523
- if (whichfork == XFS_DATA_FORK ) {
629
+ switch (whichfork ) {
630
+ case XFS_DATA_FORK :
524
631
if (!(iflags & BMV_IF_DELALLOC ) &&
525
632
(ip -> i_delayed_blks || XFS_ISIZE (ip ) > ip -> i_d .di_size )) {
526
633
error = filemap_write_and_wait (VFS_I (ip )-> i_mapping );
@@ -538,8 +645,14 @@ xfs_getbmap(
538
645
}
539
646
540
647
lock = xfs_ilock_data_map_shared (ip );
541
- } else {
648
+ break ;
649
+ case XFS_COW_FORK :
650
+ lock = XFS_ILOCK_SHARED ;
651
+ xfs_ilock (ip , lock );
652
+ break ;
653
+ case XFS_ATTR_FORK :
542
654
lock = xfs_ilock_attr_map_shared (ip );
655
+ break ;
543
656
}
544
657
545
658
/*
@@ -581,7 +694,8 @@ xfs_getbmap(
581
694
goto out_free_map ;
582
695
ASSERT (nmap <= subnex );
583
696
584
- for (i = 0 ; i < nmap && nexleft && bmv -> bmv_length ; i ++ ) {
697
+ for (i = 0 ; i < nmap && nexleft && bmv -> bmv_length &&
698
+ cur_ext < bmv -> bmv_count ; i ++ ) {
585
699
out [cur_ext ].bmv_oflags = 0 ;
586
700
if (map [i ].br_state == XFS_EXT_UNWRITTEN )
587
701
out [cur_ext ].bmv_oflags |= BMV_OF_PREALLOC ;
@@ -614,9 +728,16 @@ xfs_getbmap(
614
728
goto out_free_map ;
615
729
}
616
730
617
- if (!xfs_getbmapx_fix_eof_hole (ip , & out [cur_ext ],
618
- prealloced , bmvend ,
619
- map [i ].br_startblock ))
731
+ /* Is this a shared block? */
732
+ error = xfs_getbmap_adjust_shared (ip , whichfork ,
733
+ & map [i ], & out [cur_ext ], & inject_map );
734
+ if (error )
735
+ goto out_free_map ;
736
+
737
+ if (!xfs_getbmapx_fix_eof_hole (ip , whichfork ,
738
+ & out [cur_ext ], prealloced , bmvend ,
739
+ map [i ].br_startblock ,
740
+ inject_map .br_startblock != NULLFSBLOCK ))
620
741
goto out_free_map ;
621
742
622
743
bmv -> bmv_offset =
@@ -636,11 +757,16 @@ xfs_getbmap(
636
757
continue ;
637
758
}
638
759
639
- nexleft -- ;
760
+ if (inject_map .br_startblock != NULLFSBLOCK ) {
761
+ map [i ] = inject_map ;
762
+ i -- ;
763
+ } else
764
+ nexleft -- ;
640
765
bmv -> bmv_entries ++ ;
641
766
cur_ext ++ ;
642
767
}
643
- } while (nmap && nexleft && bmv -> bmv_length );
768
+ } while (nmap && nexleft && bmv -> bmv_length &&
769
+ cur_ext < bmv -> bmv_count );
644
770
645
771
out_free_map :
646
772
kmem_free (map );
0 commit comments