1
2
3
4
5
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_bit.h"
13#include "xfs_mount.h"
14#include "xfs_inode.h"
15#include "xfs_bmap.h"
16#include "xfs_bmap_btree.h"
17#include "xfs_trans.h"
18#include "xfs_trans_space.h"
19#include "xfs_icache.h"
20#include "xfs_rtalloc.h"
21
22
23
24
25
26
27
28
29static int
30xfs_rtget_summary(
31 xfs_mount_t *mp,
32 xfs_trans_t *tp,
33 int log,
34 xfs_rtblock_t bbno,
35 xfs_buf_t **rbpp,
36 xfs_fsblock_t *rsb,
37 xfs_suminfo_t *sum)
38{
39 return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
40}
41
42
43
44
45
46STATIC int
47xfs_rtany_summary(
48 xfs_mount_t *mp,
49 xfs_trans_t *tp,
50 int low,
51 int high,
52 xfs_rtblock_t bbno,
53 xfs_buf_t **rbpp,
54 xfs_fsblock_t *rsb,
55 int *stat)
56{
57 int error;
58 int log;
59 xfs_suminfo_t sum;
60
61
62 if (mp->m_rsum_cache && low < mp->m_rsum_cache[bbno])
63 low = mp->m_rsum_cache[bbno];
64
65
66
67
68 for (log = low; log <= high; log++) {
69
70
71
72 error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum);
73 if (error) {
74 return error;
75 }
76
77
78
79 if (sum) {
80 *stat = 1;
81 goto out;
82 }
83 }
84
85
86
87 *stat = 0;
88out:
89
90 if (mp->m_rsum_cache && log > mp->m_rsum_cache[bbno])
91 mp->m_rsum_cache[bbno] = log;
92 return 0;
93}
94
95
96
97
98
99
100STATIC int
101xfs_rtcopy_summary(
102 xfs_mount_t *omp,
103 xfs_mount_t *nmp,
104 xfs_trans_t *tp)
105{
106 xfs_rtblock_t bbno;
107 xfs_buf_t *bp;
108 int error;
109 int log;
110 xfs_suminfo_t sum;
111 xfs_fsblock_t sumbno;
112
113 bp = NULL;
114 for (log = omp->m_rsumlevels - 1; log >= 0; log--) {
115 for (bbno = omp->m_sb.sb_rbmblocks - 1;
116 (xfs_srtblock_t)bbno >= 0;
117 bbno--) {
118 error = xfs_rtget_summary(omp, tp, log, bbno, &bp,
119 &sumbno, &sum);
120 if (error)
121 return error;
122 if (sum == 0)
123 continue;
124 error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum,
125 &bp, &sumbno);
126 if (error)
127 return error;
128 error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum,
129 &bp, &sumbno);
130 if (error)
131 return error;
132 ASSERT(sum > 0);
133 }
134 }
135 return 0;
136}
137
138
139
140
141STATIC int
142xfs_rtallocate_range(
143 xfs_mount_t *mp,
144 xfs_trans_t *tp,
145 xfs_rtblock_t start,
146 xfs_extlen_t len,
147 xfs_buf_t **rbpp,
148 xfs_fsblock_t *rsb)
149{
150 xfs_rtblock_t end;
151 int error;
152 xfs_rtblock_t postblock = 0;
153 xfs_rtblock_t preblock = 0;
154
155 end = start + len - 1;
156
157
158
159
160
161 error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
162 if (error) {
163 return error;
164 }
165
166
167
168 error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
169 &postblock);
170 if (error) {
171 return error;
172 }
173
174
175
176
177 error = xfs_rtmodify_summary(mp, tp,
178 XFS_RTBLOCKLOG(postblock + 1 - preblock),
179 XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
180 if (error) {
181 return error;
182 }
183
184
185
186
187 if (preblock < start) {
188 error = xfs_rtmodify_summary(mp, tp,
189 XFS_RTBLOCKLOG(start - preblock),
190 XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
191 if (error) {
192 return error;
193 }
194 }
195
196
197
198
199 if (postblock > end) {
200 error = xfs_rtmodify_summary(mp, tp,
201 XFS_RTBLOCKLOG(postblock - end),
202 XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb);
203 if (error) {
204 return error;
205 }
206 }
207
208
209
210 error = xfs_rtmodify_range(mp, tp, start, len, 0);
211 return error;
212}
213
214
215
216
217
218
219
220STATIC int
221xfs_rtallocate_extent_block(
222 xfs_mount_t *mp,
223 xfs_trans_t *tp,
224 xfs_rtblock_t bbno,
225 xfs_extlen_t minlen,
226 xfs_extlen_t maxlen,
227 xfs_extlen_t *len,
228 xfs_rtblock_t *nextp,
229 xfs_buf_t **rbpp,
230 xfs_fsblock_t *rsb,
231 xfs_extlen_t prod,
232 xfs_rtblock_t *rtblock)
233{
234 xfs_rtblock_t besti;
235 xfs_rtblock_t bestlen;
236 xfs_rtblock_t end;
237 int error;
238 xfs_rtblock_t i;
239 xfs_rtblock_t next;
240 int stat;
241
242
243
244
245
246 for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0,
247 end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1;
248 i <= end;
249 i++) {
250
251
252
253
254 error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat);
255 if (error) {
256 return error;
257 }
258 if (stat) {
259
260
261
262 error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp,
263 rsb);
264 if (error) {
265 return error;
266 }
267 *len = maxlen;
268 *rtblock = i;
269 return 0;
270 }
271
272
273
274
275
276
277 if (minlen < maxlen) {
278 xfs_rtblock_t thislen;
279
280 thislen = next - i;
281 if (thislen >= minlen && thislen > bestlen) {
282 besti = i;
283 bestlen = thislen;
284 }
285 }
286
287
288
289 if (next < end) {
290 error = xfs_rtfind_forw(mp, tp, next, end, &i);
291 if (error) {
292 return error;
293 }
294 } else
295 break;
296 }
297
298
299
300 if (minlen < maxlen && besti != -1) {
301 xfs_extlen_t p;
302
303
304
305
306 if (prod > 1) {
307 div_u64_rem(bestlen, prod, &p);
308 if (p)
309 bestlen -= p;
310 }
311
312
313
314
315 error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb);
316 if (error) {
317 return error;
318 }
319 *len = bestlen;
320 *rtblock = besti;
321 return 0;
322 }
323
324
325
326 *nextp = next;
327 *rtblock = NULLRTBLOCK;
328 return 0;
329}
330
331
332
333
334
335
336
337STATIC int
338xfs_rtallocate_extent_exact(
339 xfs_mount_t *mp,
340 xfs_trans_t *tp,
341 xfs_rtblock_t bno,
342 xfs_extlen_t minlen,
343 xfs_extlen_t maxlen,
344 xfs_extlen_t *len,
345 xfs_buf_t **rbpp,
346 xfs_fsblock_t *rsb,
347 xfs_extlen_t prod,
348 xfs_rtblock_t *rtblock)
349{
350 int error;
351 xfs_extlen_t i;
352 int isfree;
353 xfs_rtblock_t next;
354
355 ASSERT(minlen % prod == 0 && maxlen % prod == 0);
356
357
358
359 error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree);
360 if (error) {
361 return error;
362 }
363 if (isfree) {
364
365
366
367 error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
368 if (error) {
369 return error;
370 }
371 *len = maxlen;
372 *rtblock = bno;
373 return 0;
374 }
375
376
377
378 maxlen = next - bno;
379 if (maxlen < minlen) {
380
381
382
383 *rtblock = NULLRTBLOCK;
384 return 0;
385 }
386
387
388
389 if (prod > 1 && (i = maxlen % prod)) {
390 maxlen -= i;
391 if (maxlen < minlen) {
392
393
394
395 *rtblock = NULLRTBLOCK;
396 return 0;
397 }
398 }
399
400
401
402 error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
403 if (error) {
404 return error;
405 }
406 *len = maxlen;
407 *rtblock = bno;
408 return 0;
409}
410
411
412
413
414
415
416STATIC int
417xfs_rtallocate_extent_near(
418 xfs_mount_t *mp,
419 xfs_trans_t *tp,
420 xfs_rtblock_t bno,
421 xfs_extlen_t minlen,
422 xfs_extlen_t maxlen,
423 xfs_extlen_t *len,
424 xfs_buf_t **rbpp,
425 xfs_fsblock_t *rsb,
426 xfs_extlen_t prod,
427 xfs_rtblock_t *rtblock)
428{
429 int any;
430 xfs_rtblock_t bbno;
431 int error;
432 int i;
433 int j;
434 int log2len;
435 xfs_rtblock_t n;
436 xfs_rtblock_t r;
437
438 ASSERT(minlen % prod == 0 && maxlen % prod == 0);
439
440
441
442
443 if (bno >= mp->m_sb.sb_rextents)
444 bno = mp->m_sb.sb_rextents - 1;
445
446
447
448 error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len,
449 rbpp, rsb, prod, &r);
450 if (error) {
451 return error;
452 }
453
454
455
456 if (r != NULLRTBLOCK) {
457 *rtblock = r;
458 return 0;
459 }
460 bbno = XFS_BITTOBLOCK(mp, bno);
461 i = 0;
462 ASSERT(minlen != 0);
463 log2len = xfs_highbit32(minlen);
464
465
466
467 for (;;) {
468
469
470
471
472 error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1,
473 bbno + i, rbpp, rsb, &any);
474 if (error) {
475 return error;
476 }
477
478
479
480
481 if (any) {
482
483
484
485 if (i >= 0) {
486
487
488
489
490 error = xfs_rtallocate_extent_block(mp, tp,
491 bbno + i, minlen, maxlen, len, &n, rbpp,
492 rsb, prod, &r);
493 if (error) {
494 return error;
495 }
496
497
498
499 if (r != NULLRTBLOCK) {
500 *rtblock = r;
501 return 0;
502 }
503 }
504
505
506
507 else {
508
509
510
511
512
513
514 for (j = -1; j > i; j--) {
515
516
517
518
519 error = xfs_rtany_summary(mp, tp,
520 log2len, mp->m_rsumlevels - 1,
521 bbno + j, rbpp, rsb, &any);
522 if (error) {
523 return error;
524 }
525
526
527
528
529
530
531
532
533 if (any)
534 continue;
535 error = xfs_rtallocate_extent_block(mp,
536 tp, bbno + j, minlen, maxlen,
537 len, &n, rbpp, rsb, prod, &r);
538 if (error) {
539 return error;
540 }
541
542
543
544 if (r != NULLRTBLOCK) {
545 *rtblock = r;
546 return 0;
547 }
548 }
549
550
551
552
553
554
555
556
557 error = xfs_rtallocate_extent_block(mp, tp,
558 bbno + i, minlen, maxlen, len, &n, rbpp,
559 rsb, prod, &r);
560 if (error) {
561 return error;
562 }
563
564
565
566 if (r != NULLRTBLOCK) {
567 *rtblock = r;
568 return 0;
569 }
570 }
571 }
572
573
574
575
576 if (i > 0 && (int)bbno - i >= 0)
577 i = -i;
578
579
580
581
582 else if (i > 0 && (int)bbno + i < mp->m_sb.sb_rbmblocks - 1)
583 i++;
584
585
586
587
588 else if (i <= 0 && (int)bbno - i < mp->m_sb.sb_rbmblocks - 1)
589 i = 1 - i;
590
591
592
593
594 else if (i <= 0 && (int)bbno + i > 0)
595 i--;
596
597
598
599 else
600 break;
601 }
602 *rtblock = NULLRTBLOCK;
603 return 0;
604}
605
606
607
608
609
610
611STATIC int
612xfs_rtallocate_extent_size(
613 xfs_mount_t *mp,
614 xfs_trans_t *tp,
615 xfs_extlen_t minlen,
616 xfs_extlen_t maxlen,
617 xfs_extlen_t *len,
618 xfs_buf_t **rbpp,
619 xfs_fsblock_t *rsb,
620 xfs_extlen_t prod,
621 xfs_rtblock_t *rtblock)
622{
623 int error;
624 int i;
625 int l;
626 xfs_rtblock_t n;
627 xfs_rtblock_t r;
628 xfs_suminfo_t sum;
629
630 ASSERT(minlen % prod == 0 && maxlen % prod == 0);
631 ASSERT(maxlen != 0);
632
633
634
635
636
637
638
639
640 for (l = xfs_highbit32(maxlen); l < mp->m_rsumlevels; l++) {
641
642
643
644 for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
645
646
647
648 error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
649 &sum);
650 if (error) {
651 return error;
652 }
653
654
655
656 if (!sum)
657 continue;
658
659
660
661 error = xfs_rtallocate_extent_block(mp, tp, i, maxlen,
662 maxlen, len, &n, rbpp, rsb, prod, &r);
663 if (error) {
664 return error;
665 }
666
667
668
669 if (r != NULLRTBLOCK) {
670 *rtblock = r;
671 return 0;
672 }
673
674
675
676
677
678 if (XFS_BITTOBLOCK(mp, n) > i + 1)
679 i = XFS_BITTOBLOCK(mp, n) - 1;
680 }
681 }
682
683
684
685
686 if (minlen > --maxlen) {
687 *rtblock = NULLRTBLOCK;
688 return 0;
689 }
690 ASSERT(minlen != 0);
691 ASSERT(maxlen != 0);
692
693
694
695
696
697
698 for (l = xfs_highbit32(maxlen); l >= xfs_highbit32(minlen); l--) {
699
700
701
702
703 for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
704
705
706
707 error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
708 &sum);
709 if (error) {
710 return error;
711 }
712
713
714
715 if (!sum)
716 continue;
717
718
719
720
721
722 error = xfs_rtallocate_extent_block(mp, tp, i,
723 XFS_RTMAX(minlen, 1 << l),
724 XFS_RTMIN(maxlen, (1 << (l + 1)) - 1),
725 len, &n, rbpp, rsb, prod, &r);
726 if (error) {
727 return error;
728 }
729
730
731
732 if (r != NULLRTBLOCK) {
733 *rtblock = r;
734 return 0;
735 }
736
737
738
739
740
741 if (XFS_BITTOBLOCK(mp, n) > i + 1)
742 i = XFS_BITTOBLOCK(mp, n) - 1;
743 }
744 }
745
746
747
748 *rtblock = NULLRTBLOCK;
749 return 0;
750}
751
752
753
754
755STATIC int
756xfs_growfs_rt_alloc(
757 struct xfs_mount *mp,
758 xfs_extlen_t oblocks,
759 xfs_extlen_t nblocks,
760 struct xfs_inode *ip)
761{
762 xfs_fileoff_t bno;
763 struct xfs_buf *bp;
764 xfs_daddr_t d;
765 int error;
766 xfs_fsblock_t fsbno;
767 struct xfs_bmbt_irec map;
768 int nmap;
769 int resblks;
770 struct xfs_trans *tp;
771
772
773
774
775 while (oblocks < nblocks) {
776 resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
777
778
779
780 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtalloc, resblks,
781 0, 0, &tp);
782 if (error)
783 return error;
784
785
786
787 xfs_ilock(ip, XFS_ILOCK_EXCL);
788 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
789
790
791
792
793 nmap = 1;
794 error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks,
795 XFS_BMAPI_METADATA, 0, &map, &nmap);
796 if (!error && nmap < 1)
797 error = -ENOSPC;
798 if (error)
799 goto out_trans_cancel;
800
801
802
803 error = xfs_trans_commit(tp);
804 if (error)
805 return error;
806
807
808
809
810 for (bno = map.br_startoff, fsbno = map.br_startblock;
811 bno < map.br_startoff + map.br_blockcount;
812 bno++, fsbno++) {
813
814
815
816 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero,
817 0, 0, 0, &tp);
818 if (error)
819 return error;
820
821
822
823 xfs_ilock(ip, XFS_ILOCK_EXCL);
824 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
825
826
827
828 d = XFS_FSB_TO_DADDR(mp, fsbno);
829 bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
830 mp->m_bsize, 0);
831 if (bp == NULL) {
832 error = -EIO;
833 goto out_trans_cancel;
834 }
835 memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
836 xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
837
838
839
840 error = xfs_trans_commit(tp);
841 if (error)
842 return error;
843 }
844
845
846
847 oblocks = map.br_startoff + map.br_blockcount;
848 }
849
850 return 0;
851
852out_trans_cancel:
853 xfs_trans_cancel(tp);
854 return error;
855}
856
857static void
858xfs_alloc_rsum_cache(
859 xfs_mount_t *mp,
860 xfs_extlen_t rbmblocks)
861{
862
863
864
865
866
867 mp->m_rsum_cache = kmem_zalloc_large(rbmblocks, 0);
868 if (!mp->m_rsum_cache)
869 xfs_warn(mp, "could not allocate realtime summary cache");
870}
871
872
873
874
875
876
877
878
879int
880xfs_growfs_rt(
881 xfs_mount_t *mp,
882 xfs_growfs_rt_t *in)
883{
884 xfs_rtblock_t bmbno;
885 xfs_buf_t *bp;
886 int error;
887 xfs_mount_t *nmp;
888 xfs_rfsblock_t nrblocks;
889 xfs_extlen_t nrbmblocks;
890 xfs_rtblock_t nrextents;
891 uint8_t nrextslog;
892 xfs_extlen_t nrsumblocks;
893 uint nrsumlevels;
894 uint nrsumsize;
895 xfs_sb_t *nsbp;
896 xfs_extlen_t rbmblocks;
897 xfs_extlen_t rsumblocks;
898 xfs_sb_t *sbp;
899 xfs_fsblock_t sumbno;
900 uint8_t *rsum_cache;
901
902 sbp = &mp->m_sb;
903
904
905
906 if (!capable(CAP_SYS_ADMIN))
907 return -EPERM;
908 if (mp->m_rtdev_targp == NULL || mp->m_rbmip == NULL ||
909 (nrblocks = in->newblocks) <= sbp->sb_rblocks ||
910 (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
911 return -EINVAL;
912 if ((error = xfs_sb_validate_fsb_count(sbp, nrblocks)))
913 return error;
914
915
916
917 error = xfs_buf_read_uncached(mp->m_rtdev_targp,
918 XFS_FSB_TO_BB(mp, nrblocks - 1),
919 XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
920 if (error)
921 return error;
922 xfs_buf_relse(bp);
923
924
925
926
927 nrextents = nrblocks;
928 do_div(nrextents, in->extsize);
929 nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
930 nrextslog = xfs_highbit32(nrextents);
931 nrsumlevels = nrextslog + 1;
932 nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
933 nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
934 nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
935
936
937
938
939
940 if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))
941 return -EINVAL;
942
943
944
945
946 rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_d.di_size);
947 rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_d.di_size);
948
949
950
951 error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_rbmip);
952 if (error)
953 return error;
954 error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip);
955 if (error)
956 return error;
957
958 rsum_cache = mp->m_rsum_cache;
959 if (nrbmblocks != sbp->sb_rbmblocks)
960 xfs_alloc_rsum_cache(mp, nrbmblocks);
961
962
963
964
965 nmp = kmem_alloc(sizeof(*nmp), 0);
966
967
968
969
970
971
972 for (bmbno = sbp->sb_rbmblocks -
973 ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
974 bmbno < nrbmblocks;
975 bmbno++) {
976 xfs_trans_t *tp;
977
978 *nmp = *mp;
979 nsbp = &nmp->m_sb;
980
981
982
983 nsbp->sb_rextsize = in->extsize;
984 nsbp->sb_rbmblocks = bmbno + 1;
985 nsbp->sb_rblocks =
986 XFS_RTMIN(nrblocks,
987 nsbp->sb_rbmblocks * NBBY *
988 nsbp->sb_blocksize * nsbp->sb_rextsize);
989 nsbp->sb_rextents = nsbp->sb_rblocks;
990 do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
991 ASSERT(nsbp->sb_rextents != 0);
992 nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
993 nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
994 nrsumsize =
995 (uint)sizeof(xfs_suminfo_t) * nrsumlevels *
996 nsbp->sb_rbmblocks;
997 nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
998 nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
999
1000
1001
1002 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtfree, 0, 0, 0,
1003 &tp);
1004 if (error)
1005 break;
1006
1007
1008
1009 xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
1010 xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
1011
1012
1013
1014 mp->m_rbmip->i_d.di_size =
1015 nsbp->sb_rbmblocks * nsbp->sb_blocksize;
1016 xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
1017
1018
1019
1020 xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL);
1021 xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
1022
1023
1024
1025 mp->m_rsumip->i_d.di_size = nmp->m_rsumsize;
1026 xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE);
1027
1028
1029
1030
1031 if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks ||
1032 mp->m_rsumlevels != nmp->m_rsumlevels) {
1033 error = xfs_rtcopy_summary(mp, nmp, tp);
1034 if (error)
1035 goto error_cancel;
1036 }
1037
1038
1039
1040 if (nsbp->sb_rextsize != sbp->sb_rextsize)
1041 xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE,
1042 nsbp->sb_rextsize - sbp->sb_rextsize);
1043 if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks)
1044 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS,
1045 nsbp->sb_rbmblocks - sbp->sb_rbmblocks);
1046 if (nsbp->sb_rblocks != sbp->sb_rblocks)
1047 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS,
1048 nsbp->sb_rblocks - sbp->sb_rblocks);
1049 if (nsbp->sb_rextents != sbp->sb_rextents)
1050 xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS,
1051 nsbp->sb_rextents - sbp->sb_rextents);
1052 if (nsbp->sb_rextslog != sbp->sb_rextslog)
1053 xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,
1054 nsbp->sb_rextslog - sbp->sb_rextslog);
1055
1056
1057
1058 bp = NULL;
1059 error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
1060 nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
1061 if (error) {
1062error_cancel:
1063 xfs_trans_cancel(tp);
1064 break;
1065 }
1066
1067
1068
1069 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
1070 nsbp->sb_rextents - sbp->sb_rextents);
1071
1072
1073
1074 mp->m_rsumlevels = nrsumlevels;
1075 mp->m_rsumsize = nrsumsize;
1076
1077 error = xfs_trans_commit(tp);
1078 if (error)
1079 break;
1080 }
1081
1082
1083
1084
1085 kmem_free(nmp);
1086
1087
1088
1089
1090
1091
1092 if (rsum_cache != mp->m_rsum_cache) {
1093 if (error) {
1094 kmem_free(mp->m_rsum_cache);
1095 mp->m_rsum_cache = rsum_cache;
1096 } else {
1097 kmem_free(rsum_cache);
1098 }
1099 }
1100
1101 return error;
1102}
1103
1104
1105
1106
1107
1108
1109int
1110xfs_rtallocate_extent(
1111 xfs_trans_t *tp,
1112 xfs_rtblock_t bno,
1113 xfs_extlen_t minlen,
1114 xfs_extlen_t maxlen,
1115 xfs_extlen_t *len,
1116 int wasdel,
1117 xfs_extlen_t prod,
1118 xfs_rtblock_t *rtblock)
1119{
1120 xfs_mount_t *mp = tp->t_mountp;
1121 int error;
1122 xfs_rtblock_t r;
1123 xfs_fsblock_t sb;
1124 xfs_buf_t *sumbp;
1125
1126 ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
1127 ASSERT(minlen > 0 && minlen <= maxlen);
1128
1129
1130
1131
1132 if (prod > 1) {
1133 xfs_extlen_t i;
1134
1135 if ((i = maxlen % prod))
1136 maxlen -= i;
1137 if ((i = minlen % prod))
1138 minlen += prod - i;
1139 if (maxlen < minlen) {
1140 *rtblock = NULLRTBLOCK;
1141 return 0;
1142 }
1143 }
1144
1145retry:
1146 sumbp = NULL;
1147 if (bno == 0) {
1148 error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,
1149 &sumbp, &sb, prod, &r);
1150 } else {
1151 error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,
1152 len, &sumbp, &sb, prod, &r);
1153 }
1154
1155 if (error)
1156 return error;
1157
1158
1159
1160
1161 if (r != NULLRTBLOCK) {
1162 long slen = (long)*len;
1163
1164 ASSERT(*len >= minlen && *len <= maxlen);
1165 if (wasdel)
1166 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen);
1167 else
1168 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen);
1169 } else if (prod > 1) {
1170 prod = 1;
1171 goto retry;
1172 }
1173
1174 *rtblock = r;
1175 return 0;
1176}
1177
1178
1179
1180
1181int
1182xfs_rtmount_init(
1183 struct xfs_mount *mp)
1184{
1185 struct xfs_buf *bp;
1186 struct xfs_sb *sbp;
1187 xfs_daddr_t d;
1188 int error;
1189
1190 sbp = &mp->m_sb;
1191 if (sbp->sb_rblocks == 0)
1192 return 0;
1193 if (mp->m_rtdev_targp == NULL) {
1194 xfs_warn(mp,
1195 "Filesystem has a realtime volume, use rtdev=device option");
1196 return -ENODEV;
1197 }
1198 mp->m_rsumlevels = sbp->sb_rextslog + 1;
1199 mp->m_rsumsize =
1200 (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels *
1201 sbp->sb_rbmblocks;
1202 mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize);
1203 mp->m_rbmip = mp->m_rsumip = NULL;
1204
1205
1206
1207 d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
1208 if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) {
1209 xfs_warn(mp, "realtime mount -- %llu != %llu",
1210 (unsigned long long) XFS_BB_TO_FSB(mp, d),
1211 (unsigned long long) mp->m_sb.sb_rblocks);
1212 return -EFBIG;
1213 }
1214 error = xfs_buf_read_uncached(mp->m_rtdev_targp,
1215 d - XFS_FSB_TO_BB(mp, 1),
1216 XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
1217 if (error) {
1218 xfs_warn(mp, "realtime device size check failed");
1219 return error;
1220 }
1221 xfs_buf_relse(bp);
1222 return 0;
1223}
1224
1225
1226
1227
1228
1229int
1230xfs_rtmount_inodes(
1231 xfs_mount_t *mp)
1232{
1233 int error;
1234 xfs_sb_t *sbp;
1235
1236 sbp = &mp->m_sb;
1237 error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);
1238 if (error)
1239 return error;
1240 ASSERT(mp->m_rbmip != NULL);
1241
1242 error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);
1243 if (error) {
1244 xfs_irele(mp->m_rbmip);
1245 return error;
1246 }
1247 ASSERT(mp->m_rsumip != NULL);
1248 xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
1249 return 0;
1250}
1251
1252void
1253xfs_rtunmount_inodes(
1254 struct xfs_mount *mp)
1255{
1256 kmem_free(mp->m_rsum_cache);
1257 if (mp->m_rbmip)
1258 xfs_irele(mp->m_rbmip);
1259 if (mp->m_rsumip)
1260 xfs_irele(mp->m_rsumip);
1261}
1262
1263
1264
1265
1266
1267
1268
1269
1270int
1271xfs_rtpick_extent(
1272 xfs_mount_t *mp,
1273 xfs_trans_t *tp,
1274 xfs_extlen_t len,
1275 xfs_rtblock_t *pick)
1276{
1277 xfs_rtblock_t b;
1278 int log2;
1279 uint64_t resid;
1280 uint64_t seq;
1281 uint64_t *seqp;
1282
1283 ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
1284
1285 seqp = (uint64_t *)&VFS_I(mp->m_rbmip)->i_atime;
1286 if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) {
1287 mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM;
1288 *seqp = 0;
1289 }
1290 seq = *seqp;
1291 if ((log2 = xfs_highbit64(seq)) == -1)
1292 b = 0;
1293 else {
1294 resid = seq - (1ULL << log2);
1295 b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >>
1296 (log2 + 1);
1297 if (b >= mp->m_sb.sb_rextents)
1298 div64_u64_rem(b, mp->m_sb.sb_rextents, &b);
1299 if (b + len > mp->m_sb.sb_rextents)
1300 b = mp->m_sb.sb_rextents - len;
1301 }
1302 *seqp = seq + 1;
1303 xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
1304 *pick = b;
1305 return 0;
1306}
1307