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#include "xfs_sb.h"
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 struct xfs_buf **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 struct xfs_buf **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 struct xfs_buf *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 struct xfs_buf **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 struct xfs_buf **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 maxlen = min(mp->m_sb.sb_rextents, i + maxlen) - i;
252
253
254
255
256
257 error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat);
258 if (error) {
259 return error;
260 }
261 if (stat) {
262
263
264
265 error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp,
266 rsb);
267 if (error) {
268 return error;
269 }
270 *len = maxlen;
271 *rtblock = i;
272 return 0;
273 }
274
275
276
277
278
279
280 if (minlen < maxlen) {
281 xfs_rtblock_t thislen;
282
283 thislen = next - i;
284 if (thislen >= minlen && thislen > bestlen) {
285 besti = i;
286 bestlen = thislen;
287 }
288 }
289
290
291
292 if (next < end) {
293 error = xfs_rtfind_forw(mp, tp, next, end, &i);
294 if (error) {
295 return error;
296 }
297 } else
298 break;
299 }
300
301
302
303 if (minlen < maxlen && besti != -1) {
304 xfs_extlen_t p;
305
306
307
308
309 if (prod > 1) {
310 div_u64_rem(bestlen, prod, &p);
311 if (p)
312 bestlen -= p;
313 }
314
315
316
317
318 error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb);
319 if (error) {
320 return error;
321 }
322 *len = bestlen;
323 *rtblock = besti;
324 return 0;
325 }
326
327
328
329 *nextp = next;
330 *rtblock = NULLRTBLOCK;
331 return 0;
332}
333
334
335
336
337
338
339
340STATIC int
341xfs_rtallocate_extent_exact(
342 xfs_mount_t *mp,
343 xfs_trans_t *tp,
344 xfs_rtblock_t bno,
345 xfs_extlen_t minlen,
346 xfs_extlen_t maxlen,
347 xfs_extlen_t *len,
348 struct xfs_buf **rbpp,
349 xfs_fsblock_t *rsb,
350 xfs_extlen_t prod,
351 xfs_rtblock_t *rtblock)
352{
353 int error;
354 xfs_extlen_t i;
355 int isfree;
356 xfs_rtblock_t next;
357
358 ASSERT(minlen % prod == 0 && maxlen % prod == 0);
359
360
361
362 error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree);
363 if (error) {
364 return error;
365 }
366 if (isfree) {
367
368
369
370 error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
371 if (error) {
372 return error;
373 }
374 *len = maxlen;
375 *rtblock = bno;
376 return 0;
377 }
378
379
380
381 maxlen = next - bno;
382 if (maxlen < minlen) {
383
384
385
386 *rtblock = NULLRTBLOCK;
387 return 0;
388 }
389
390
391
392 if (prod > 1 && (i = maxlen % prod)) {
393 maxlen -= i;
394 if (maxlen < minlen) {
395
396
397
398 *rtblock = NULLRTBLOCK;
399 return 0;
400 }
401 }
402
403
404
405 error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
406 if (error) {
407 return error;
408 }
409 *len = maxlen;
410 *rtblock = bno;
411 return 0;
412}
413
414
415
416
417
418
419STATIC int
420xfs_rtallocate_extent_near(
421 xfs_mount_t *mp,
422 xfs_trans_t *tp,
423 xfs_rtblock_t bno,
424 xfs_extlen_t minlen,
425 xfs_extlen_t maxlen,
426 xfs_extlen_t *len,
427 struct xfs_buf **rbpp,
428 xfs_fsblock_t *rsb,
429 xfs_extlen_t prod,
430 xfs_rtblock_t *rtblock)
431{
432 int any;
433 xfs_rtblock_t bbno;
434 int error;
435 int i;
436 int j;
437 int log2len;
438 xfs_rtblock_t n;
439 xfs_rtblock_t r;
440
441 ASSERT(minlen % prod == 0 && maxlen % prod == 0);
442
443
444
445
446 if (bno >= mp->m_sb.sb_rextents)
447 bno = mp->m_sb.sb_rextents - 1;
448
449
450 maxlen = min(mp->m_sb.sb_rextents, bno + maxlen) - bno;
451 if (maxlen < minlen) {
452 *rtblock = NULLRTBLOCK;
453 return 0;
454 }
455
456
457
458
459 error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len,
460 rbpp, rsb, prod, &r);
461 if (error) {
462 return error;
463 }
464
465
466
467 if (r != NULLRTBLOCK) {
468 *rtblock = r;
469 return 0;
470 }
471 bbno = XFS_BITTOBLOCK(mp, bno);
472 i = 0;
473 ASSERT(minlen != 0);
474 log2len = xfs_highbit32(minlen);
475
476
477
478 for (;;) {
479
480
481
482
483 error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1,
484 bbno + i, rbpp, rsb, &any);
485 if (error) {
486 return error;
487 }
488
489
490
491
492 if (any) {
493
494
495
496 if (i >= 0) {
497
498
499
500
501 error = xfs_rtallocate_extent_block(mp, tp,
502 bbno + i, minlen, maxlen, len, &n, rbpp,
503 rsb, prod, &r);
504 if (error) {
505 return error;
506 }
507
508
509
510 if (r != NULLRTBLOCK) {
511 *rtblock = r;
512 return 0;
513 }
514 }
515
516
517
518 else {
519
520
521
522
523
524
525 for (j = -1; j > i; j--) {
526
527
528
529
530 error = xfs_rtany_summary(mp, tp,
531 log2len, mp->m_rsumlevels - 1,
532 bbno + j, rbpp, rsb, &any);
533 if (error) {
534 return error;
535 }
536
537
538
539
540
541
542
543
544 if (any)
545 continue;
546 error = xfs_rtallocate_extent_block(mp,
547 tp, bbno + j, minlen, maxlen,
548 len, &n, rbpp, rsb, prod, &r);
549 if (error) {
550 return error;
551 }
552
553
554
555 if (r != NULLRTBLOCK) {
556 *rtblock = r;
557 return 0;
558 }
559 }
560
561
562
563
564
565
566
567
568 error = xfs_rtallocate_extent_block(mp, tp,
569 bbno + i, minlen, maxlen, len, &n, rbpp,
570 rsb, prod, &r);
571 if (error) {
572 return error;
573 }
574
575
576
577 if (r != NULLRTBLOCK) {
578 *rtblock = r;
579 return 0;
580 }
581 }
582 }
583
584
585
586
587 if (i > 0 && (int)bbno - i >= 0)
588 i = -i;
589
590
591
592
593 else if (i > 0 && (int)bbno + i < mp->m_sb.sb_rbmblocks - 1)
594 i++;
595
596
597
598
599 else if (i <= 0 && (int)bbno - i < mp->m_sb.sb_rbmblocks - 1)
600 i = 1 - i;
601
602
603
604
605 else if (i <= 0 && (int)bbno + i > 0)
606 i--;
607
608
609
610 else
611 break;
612 }
613 *rtblock = NULLRTBLOCK;
614 return 0;
615}
616
617
618
619
620
621
622STATIC int
623xfs_rtallocate_extent_size(
624 xfs_mount_t *mp,
625 xfs_trans_t *tp,
626 xfs_extlen_t minlen,
627 xfs_extlen_t maxlen,
628 xfs_extlen_t *len,
629 struct xfs_buf **rbpp,
630 xfs_fsblock_t *rsb,
631 xfs_extlen_t prod,
632 xfs_rtblock_t *rtblock)
633{
634 int error;
635 int i;
636 int l;
637 xfs_rtblock_t n;
638 xfs_rtblock_t r;
639 xfs_suminfo_t sum;
640
641 ASSERT(minlen % prod == 0 && maxlen % prod == 0);
642 ASSERT(maxlen != 0);
643
644
645
646
647
648
649
650
651 for (l = xfs_highbit32(maxlen); l < mp->m_rsumlevels; l++) {
652
653
654
655 for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
656
657
658
659 error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
660 &sum);
661 if (error) {
662 return error;
663 }
664
665
666
667 if (!sum)
668 continue;
669
670
671
672 error = xfs_rtallocate_extent_block(mp, tp, i, maxlen,
673 maxlen, len, &n, rbpp, rsb, prod, &r);
674 if (error) {
675 return error;
676 }
677
678
679
680 if (r != NULLRTBLOCK) {
681 *rtblock = r;
682 return 0;
683 }
684
685
686
687
688
689 if (XFS_BITTOBLOCK(mp, n) > i + 1)
690 i = XFS_BITTOBLOCK(mp, n) - 1;
691 }
692 }
693
694
695
696
697 if (minlen > --maxlen) {
698 *rtblock = NULLRTBLOCK;
699 return 0;
700 }
701 ASSERT(minlen != 0);
702 ASSERT(maxlen != 0);
703
704
705
706
707
708
709 for (l = xfs_highbit32(maxlen); l >= xfs_highbit32(minlen); l--) {
710
711
712
713
714 for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
715
716
717
718 error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
719 &sum);
720 if (error) {
721 return error;
722 }
723
724
725
726 if (!sum)
727 continue;
728
729
730
731
732
733 error = xfs_rtallocate_extent_block(mp, tp, i,
734 XFS_RTMAX(minlen, 1 << l),
735 XFS_RTMIN(maxlen, (1 << (l + 1)) - 1),
736 len, &n, rbpp, rsb, prod, &r);
737 if (error) {
738 return error;
739 }
740
741
742
743 if (r != NULLRTBLOCK) {
744 *rtblock = r;
745 return 0;
746 }
747
748
749
750
751
752 if (XFS_BITTOBLOCK(mp, n) > i + 1)
753 i = XFS_BITTOBLOCK(mp, n) - 1;
754 }
755 }
756
757
758
759 *rtblock = NULLRTBLOCK;
760 return 0;
761}
762
763
764
765
766STATIC int
767xfs_growfs_rt_alloc(
768 struct xfs_mount *mp,
769 xfs_extlen_t oblocks,
770 xfs_extlen_t nblocks,
771 struct xfs_inode *ip)
772{
773 xfs_fileoff_t bno;
774 struct xfs_buf *bp;
775 xfs_daddr_t d;
776 int error;
777 xfs_fsblock_t fsbno;
778 struct xfs_bmbt_irec map;
779 int nmap;
780 int resblks;
781 enum xfs_blft buf_type;
782 struct xfs_trans *tp;
783
784 if (ip == mp->m_rsumip)
785 buf_type = XFS_BLFT_RTSUMMARY_BUF;
786 else
787 buf_type = XFS_BLFT_RTBITMAP_BUF;
788
789
790
791
792 while (oblocks < nblocks) {
793 resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
794
795
796
797 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtalloc, resblks,
798 0, 0, &tp);
799 if (error)
800 return error;
801
802
803
804 xfs_ilock(ip, XFS_ILOCK_EXCL);
805 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
806
807 error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
808 XFS_IEXT_ADD_NOSPLIT_CNT);
809 if (error)
810 goto out_trans_cancel;
811
812
813
814
815 nmap = 1;
816 error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks,
817 XFS_BMAPI_METADATA, 0, &map, &nmap);
818 if (!error && nmap < 1)
819 error = -ENOSPC;
820 if (error)
821 goto out_trans_cancel;
822
823
824
825 error = xfs_trans_commit(tp);
826 if (error)
827 return error;
828
829
830
831
832 for (bno = map.br_startoff, fsbno = map.br_startblock;
833 bno < map.br_startoff + map.br_blockcount;
834 bno++, fsbno++) {
835
836
837
838 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero,
839 0, 0, 0, &tp);
840 if (error)
841 return error;
842
843
844
845 xfs_ilock(ip, XFS_ILOCK_EXCL);
846 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
847
848
849
850 d = XFS_FSB_TO_DADDR(mp, fsbno);
851 error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
852 mp->m_bsize, 0, &bp);
853 if (error)
854 goto out_trans_cancel;
855
856 xfs_trans_buf_set_type(tp, bp, buf_type);
857 bp->b_ops = &xfs_rtbuf_ops;
858 memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
859 xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
860
861
862
863 error = xfs_trans_commit(tp);
864 if (error)
865 return error;
866 }
867
868
869
870 oblocks = map.br_startoff + map.br_blockcount;
871 }
872
873 return 0;
874
875out_trans_cancel:
876 xfs_trans_cancel(tp);
877 return error;
878}
879
880static void
881xfs_alloc_rsum_cache(
882 xfs_mount_t *mp,
883 xfs_extlen_t rbmblocks)
884{
885
886
887
888
889
890 mp->m_rsum_cache = kvzalloc(rbmblocks, GFP_KERNEL);
891 if (!mp->m_rsum_cache)
892 xfs_warn(mp, "could not allocate realtime summary cache");
893}
894
895
896
897
898
899
900
901
902int
903xfs_growfs_rt(
904 xfs_mount_t *mp,
905 xfs_growfs_rt_t *in)
906{
907 xfs_rtblock_t bmbno;
908 struct xfs_buf *bp;
909 int error;
910 xfs_mount_t *nmp;
911 xfs_rfsblock_t nrblocks;
912 xfs_extlen_t nrbmblocks;
913 xfs_rtblock_t nrextents;
914 uint8_t nrextslog;
915 xfs_extlen_t nrsumblocks;
916 uint nrsumlevels;
917 uint nrsumsize;
918 xfs_sb_t *nsbp;
919 xfs_extlen_t rbmblocks;
920 xfs_extlen_t rsumblocks;
921 xfs_sb_t *sbp;
922 xfs_fsblock_t sumbno;
923 uint8_t *rsum_cache;
924
925 sbp = &mp->m_sb;
926
927 if (!capable(CAP_SYS_ADMIN))
928 return -EPERM;
929
930
931 if (!XFS_IS_REALTIME_MOUNT(mp))
932 return -EINVAL;
933
934
935
936
937 if (!mp->m_rbmip || !mp->m_rsumip)
938 return -EINVAL;
939
940
941 if (in->newblocks <= sbp->sb_rblocks)
942 return -EINVAL;
943
944
945 if (sbp->sb_rblocks > 0 && in->extsize != sbp->sb_rextsize)
946 return -EINVAL;
947
948
949 if (XFS_FSB_TO_B(mp, in->extsize) > XFS_MAX_RTEXTSIZE ||
950 XFS_FSB_TO_B(mp, in->extsize) < XFS_MIN_RTEXTSIZE)
951 return -EINVAL;
952
953
954 if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp))
955 return -EOPNOTSUPP;
956
957 nrblocks = in->newblocks;
958 error = xfs_sb_validate_fsb_count(sbp, nrblocks);
959 if (error)
960 return error;
961
962
963
964 error = xfs_buf_read_uncached(mp->m_rtdev_targp,
965 XFS_FSB_TO_BB(mp, nrblocks - 1),
966 XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
967 if (error)
968 return error;
969 xfs_buf_relse(bp);
970
971
972
973
974 nrextents = nrblocks;
975 do_div(nrextents, in->extsize);
976 nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
977 nrextslog = xfs_highbit32(nrextents);
978 nrsumlevels = nrextslog + 1;
979 nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
980 nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
981 nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
982
983
984
985
986
987 if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))
988 return -EINVAL;
989
990
991
992
993 rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_disk_size);
994 rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_disk_size);
995
996
997
998 error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_rbmip);
999 if (error)
1000 return error;
1001 error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip);
1002 if (error)
1003 return error;
1004
1005 rsum_cache = mp->m_rsum_cache;
1006 if (nrbmblocks != sbp->sb_rbmblocks)
1007 xfs_alloc_rsum_cache(mp, nrbmblocks);
1008
1009
1010
1011
1012 nmp = kmem_alloc(sizeof(*nmp), 0);
1013
1014
1015
1016
1017
1018
1019 for (bmbno = sbp->sb_rbmblocks -
1020 ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
1021 bmbno < nrbmblocks;
1022 bmbno++) {
1023 struct xfs_trans *tp;
1024 xfs_rfsblock_t nrblocks_step;
1025
1026 *nmp = *mp;
1027 nsbp = &nmp->m_sb;
1028
1029
1030
1031 nsbp->sb_rextsize = in->extsize;
1032 nsbp->sb_rbmblocks = bmbno + 1;
1033 nrblocks_step = (bmbno + 1) * NBBY * nsbp->sb_blocksize *
1034 nsbp->sb_rextsize;
1035 nsbp->sb_rblocks = min(nrblocks, nrblocks_step);
1036 nsbp->sb_rextents = nsbp->sb_rblocks;
1037 do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
1038 ASSERT(nsbp->sb_rextents != 0);
1039 nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
1040 nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
1041 nrsumsize =
1042 (uint)sizeof(xfs_suminfo_t) * nrsumlevels *
1043 nsbp->sb_rbmblocks;
1044 nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
1045 nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
1046
1047
1048
1049 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtfree, 0, 0, 0,
1050 &tp);
1051 if (error)
1052 break;
1053
1054
1055
1056 xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP);
1057 xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
1058
1059
1060
1061
1062
1063 mp->m_rbmip->i_disk_size =
1064 nsbp->sb_rbmblocks * nsbp->sb_blocksize;
1065 i_size_write(VFS_I(mp->m_rbmip), mp->m_rbmip->i_disk_size);
1066 xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
1067
1068
1069
1070 xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM);
1071 xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
1072
1073
1074
1075
1076
1077 mp->m_rsumip->i_disk_size = nmp->m_rsumsize;
1078 i_size_write(VFS_I(mp->m_rsumip), mp->m_rsumip->i_disk_size);
1079 xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE);
1080
1081
1082
1083
1084 if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks ||
1085 mp->m_rsumlevels != nmp->m_rsumlevels) {
1086 error = xfs_rtcopy_summary(mp, nmp, tp);
1087 if (error)
1088 goto error_cancel;
1089 }
1090
1091
1092
1093 if (nsbp->sb_rextsize != sbp->sb_rextsize)
1094 xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE,
1095 nsbp->sb_rextsize - sbp->sb_rextsize);
1096 if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks)
1097 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS,
1098 nsbp->sb_rbmblocks - sbp->sb_rbmblocks);
1099 if (nsbp->sb_rblocks != sbp->sb_rblocks)
1100 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS,
1101 nsbp->sb_rblocks - sbp->sb_rblocks);
1102 if (nsbp->sb_rextents != sbp->sb_rextents)
1103 xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS,
1104 nsbp->sb_rextents - sbp->sb_rextents);
1105 if (nsbp->sb_rextslog != sbp->sb_rextslog)
1106 xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,
1107 nsbp->sb_rextslog - sbp->sb_rextslog);
1108
1109
1110
1111 bp = NULL;
1112 error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
1113 nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
1114 if (error) {
1115error_cancel:
1116 xfs_trans_cancel(tp);
1117 break;
1118 }
1119
1120
1121
1122 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
1123 nsbp->sb_rextents - sbp->sb_rextents);
1124
1125
1126
1127 mp->m_rsumlevels = nrsumlevels;
1128 mp->m_rsumsize = nrsumsize;
1129
1130 error = xfs_trans_commit(tp);
1131 if (error)
1132 break;
1133
1134
1135 mp->m_features |= XFS_FEAT_REALTIME;
1136 }
1137 if (error)
1138 goto out_free;
1139
1140
1141 error = xfs_update_secondary_sbs(mp);
1142
1143out_free:
1144
1145
1146
1147 kmem_free(nmp);
1148
1149
1150
1151
1152
1153
1154 if (rsum_cache != mp->m_rsum_cache) {
1155 if (error) {
1156 kmem_free(mp->m_rsum_cache);
1157 mp->m_rsum_cache = rsum_cache;
1158 } else {
1159 kmem_free(rsum_cache);
1160 }
1161 }
1162
1163 return error;
1164}
1165
1166
1167
1168
1169
1170
1171int
1172xfs_rtallocate_extent(
1173 xfs_trans_t *tp,
1174 xfs_rtblock_t bno,
1175 xfs_extlen_t minlen,
1176 xfs_extlen_t maxlen,
1177 xfs_extlen_t *len,
1178 int wasdel,
1179 xfs_extlen_t prod,
1180 xfs_rtblock_t *rtblock)
1181{
1182 xfs_mount_t *mp = tp->t_mountp;
1183 int error;
1184 xfs_rtblock_t r;
1185 xfs_fsblock_t sb;
1186 struct xfs_buf *sumbp;
1187
1188 ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
1189 ASSERT(minlen > 0 && minlen <= maxlen);
1190
1191
1192
1193
1194 if (prod > 1) {
1195 xfs_extlen_t i;
1196
1197 if ((i = maxlen % prod))
1198 maxlen -= i;
1199 if ((i = minlen % prod))
1200 minlen += prod - i;
1201 if (maxlen < minlen) {
1202 *rtblock = NULLRTBLOCK;
1203 return 0;
1204 }
1205 }
1206
1207retry:
1208 sumbp = NULL;
1209 if (bno == 0) {
1210 error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,
1211 &sumbp, &sb, prod, &r);
1212 } else {
1213 error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,
1214 len, &sumbp, &sb, prod, &r);
1215 }
1216
1217 if (error)
1218 return error;
1219
1220
1221
1222
1223 if (r != NULLRTBLOCK) {
1224 long slen = (long)*len;
1225
1226 ASSERT(*len >= minlen && *len <= maxlen);
1227 if (wasdel)
1228 xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen);
1229 else
1230 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen);
1231 } else if (prod > 1) {
1232 prod = 1;
1233 goto retry;
1234 }
1235
1236 *rtblock = r;
1237 return 0;
1238}
1239
1240
1241
1242
1243int
1244xfs_rtmount_init(
1245 struct xfs_mount *mp)
1246{
1247 struct xfs_buf *bp;
1248 struct xfs_sb *sbp;
1249 xfs_daddr_t d;
1250 int error;
1251
1252 sbp = &mp->m_sb;
1253 if (sbp->sb_rblocks == 0)
1254 return 0;
1255 if (mp->m_rtdev_targp == NULL) {
1256 xfs_warn(mp,
1257 "Filesystem has a realtime volume, use rtdev=device option");
1258 return -ENODEV;
1259 }
1260 mp->m_rsumlevels = sbp->sb_rextslog + 1;
1261 mp->m_rsumsize =
1262 (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels *
1263 sbp->sb_rbmblocks;
1264 mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize);
1265 mp->m_rbmip = mp->m_rsumip = NULL;
1266
1267
1268
1269 d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
1270 if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) {
1271 xfs_warn(mp, "realtime mount -- %llu != %llu",
1272 (unsigned long long) XFS_BB_TO_FSB(mp, d),
1273 (unsigned long long) mp->m_sb.sb_rblocks);
1274 return -EFBIG;
1275 }
1276 error = xfs_buf_read_uncached(mp->m_rtdev_targp,
1277 d - XFS_FSB_TO_BB(mp, 1),
1278 XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
1279 if (error) {
1280 xfs_warn(mp, "realtime device size check failed");
1281 return error;
1282 }
1283 xfs_buf_relse(bp);
1284 return 0;
1285}
1286
1287
1288
1289
1290
1291int
1292xfs_rtmount_inodes(
1293 xfs_mount_t *mp)
1294{
1295 int error;
1296 xfs_sb_t *sbp;
1297
1298 sbp = &mp->m_sb;
1299 error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);
1300 if (error)
1301 return error;
1302 ASSERT(mp->m_rbmip != NULL);
1303
1304 error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);
1305 if (error) {
1306 xfs_irele(mp->m_rbmip);
1307 return error;
1308 }
1309 ASSERT(mp->m_rsumip != NULL);
1310 xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
1311 return 0;
1312}
1313
1314void
1315xfs_rtunmount_inodes(
1316 struct xfs_mount *mp)
1317{
1318 kmem_free(mp->m_rsum_cache);
1319 if (mp->m_rbmip)
1320 xfs_irele(mp->m_rbmip);
1321 if (mp->m_rsumip)
1322 xfs_irele(mp->m_rsumip);
1323}
1324
1325
1326
1327
1328
1329
1330
1331
1332int
1333xfs_rtpick_extent(
1334 xfs_mount_t *mp,
1335 xfs_trans_t *tp,
1336 xfs_extlen_t len,
1337 xfs_rtblock_t *pick)
1338{
1339 xfs_rtblock_t b;
1340 int log2;
1341 uint64_t resid;
1342 uint64_t seq;
1343 uint64_t *seqp;
1344
1345 ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
1346
1347 seqp = (uint64_t *)&VFS_I(mp->m_rbmip)->i_atime;
1348 if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
1349 mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
1350 *seqp = 0;
1351 }
1352 seq = *seqp;
1353 if ((log2 = xfs_highbit64(seq)) == -1)
1354 b = 0;
1355 else {
1356 resid = seq - (1ULL << log2);
1357 b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >>
1358 (log2 + 1);
1359 if (b >= mp->m_sb.sb_rextents)
1360 div64_u64_rem(b, mp->m_sb.sb_rextents, &b);
1361 if (b + len > mp->m_sb.sb_rextents)
1362 b = mp->m_sb.sb_rextents - len;
1363 }
1364 *seqp = seq + 1;
1365 xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
1366 *pick = b;
1367 return 0;
1368}
1369