diff options
Diffstat (limited to 'fs/ntfs/runlist.c')
-rw-r--r-- | fs/ntfs/runlist.c | 68 |
1 files changed, 50 insertions, 18 deletions
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index 758855b0414e..3bb4a57d1fa9 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c | |||
@@ -35,7 +35,7 @@ static inline void ntfs_rl_mm(runlist_element *base, int dst, int src, | |||
35 | int size) | 35 | int size) |
36 | { | 36 | { |
37 | if (likely((dst != src) && (size > 0))) | 37 | if (likely((dst != src) && (size > 0))) |
38 | memmove(base + dst, base + src, size * sizeof (*base)); | 38 | memmove(base + dst, base + src, size * sizeof(*base)); |
39 | } | 39 | } |
40 | 40 | ||
41 | /** | 41 | /** |
@@ -95,6 +95,51 @@ static inline runlist_element *ntfs_rl_realloc(runlist_element *rl, | |||
95 | } | 95 | } |
96 | 96 | ||
97 | /** | 97 | /** |
98 | * ntfs_rl_realloc_nofail - Reallocate memory for runlists | ||
99 | * @rl: original runlist | ||
100 | * @old_size: number of runlist elements in the original runlist @rl | ||
101 | * @new_size: number of runlist elements we need space for | ||
102 | * | ||
103 | * As the runlists grow, more memory will be required. To prevent the | ||
104 | * kernel having to allocate and reallocate large numbers of small bits of | ||
105 | * memory, this function returns an entire page of memory. | ||
106 | * | ||
107 | * This function guarantees that the allocation will succeed. It will sleep | ||
108 | * for as long as it takes to complete the allocation. | ||
109 | * | ||
110 | * It is up to the caller to serialize access to the runlist @rl. | ||
111 | * | ||
112 | * N.B. If the new allocation doesn't require a different number of pages in | ||
113 | * memory, the function will return the original pointer. | ||
114 | * | ||
115 | * On success, return a pointer to the newly allocated, or recycled, memory. | ||
116 | * On error, return -errno. The following error codes are defined: | ||
117 | * -ENOMEM - Not enough memory to allocate runlist array. | ||
118 | * -EINVAL - Invalid parameters were passed in. | ||
119 | */ | ||
120 | static inline runlist_element *ntfs_rl_realloc_nofail(runlist_element *rl, | ||
121 | int old_size, int new_size) | ||
122 | { | ||
123 | runlist_element *new_rl; | ||
124 | |||
125 | old_size = PAGE_ALIGN(old_size * sizeof(*rl)); | ||
126 | new_size = PAGE_ALIGN(new_size * sizeof(*rl)); | ||
127 | if (old_size == new_size) | ||
128 | return rl; | ||
129 | |||
130 | new_rl = ntfs_malloc_nofs_nofail(new_size); | ||
131 | BUG_ON(!new_rl); | ||
132 | |||
133 | if (likely(rl != NULL)) { | ||
134 | if (unlikely(old_size > new_size)) | ||
135 | old_size = new_size; | ||
136 | memcpy(new_rl, rl, old_size); | ||
137 | ntfs_free(rl); | ||
138 | } | ||
139 | return new_rl; | ||
140 | } | ||
141 | |||
142 | /** | ||
98 | * ntfs_are_rl_mergeable - test if two runlists can be joined together | 143 | * ntfs_are_rl_mergeable - test if two runlists can be joined together |
99 | * @dst: original runlist | 144 | * @dst: original runlist |
100 | * @src: new runlist to test for mergeability with @dst | 145 | * @src: new runlist to test for mergeability with @dst |
@@ -621,11 +666,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, | |||
621 | if (drl[ds].lcn != LCN_RL_NOT_MAPPED) { | 666 | if (drl[ds].lcn != LCN_RL_NOT_MAPPED) { |
622 | /* Add an unmapped runlist element. */ | 667 | /* Add an unmapped runlist element. */ |
623 | if (!slots) { | 668 | if (!slots) { |
624 | /* FIXME/TODO: We need to have the | 669 | drl = ntfs_rl_realloc_nofail(drl, ds, |
625 | * extra memory already! (AIA) */ | 670 | ds + 2); |
626 | drl = ntfs_rl_realloc(drl, ds, ds + 2); | ||
627 | if (!drl) | ||
628 | goto critical_error; | ||
629 | slots = 2; | 671 | slots = 2; |
630 | } | 672 | } |
631 | ds++; | 673 | ds++; |
@@ -640,13 +682,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, | |||
640 | drl[ds].length = marker_vcn - drl[ds].vcn; | 682 | drl[ds].length = marker_vcn - drl[ds].vcn; |
641 | /* Finally add the ENOENT terminator. */ | 683 | /* Finally add the ENOENT terminator. */ |
642 | ds++; | 684 | ds++; |
643 | if (!slots) { | 685 | if (!slots) |
644 | /* FIXME/TODO: We need to have the extra | 686 | drl = ntfs_rl_realloc_nofail(drl, ds, ds + 1); |
645 | * memory already! (AIA) */ | ||
646 | drl = ntfs_rl_realloc(drl, ds, ds + 1); | ||
647 | if (!drl) | ||
648 | goto critical_error; | ||
649 | } | ||
650 | drl[ds].vcn = marker_vcn; | 687 | drl[ds].vcn = marker_vcn; |
651 | drl[ds].lcn = LCN_ENOENT; | 688 | drl[ds].lcn = LCN_ENOENT; |
652 | drl[ds].length = (s64)0; | 689 | drl[ds].length = (s64)0; |
@@ -659,11 +696,6 @@ finished: | |||
659 | ntfs_debug("Merged runlist:"); | 696 | ntfs_debug("Merged runlist:"); |
660 | ntfs_debug_dump_runlist(drl); | 697 | ntfs_debug_dump_runlist(drl); |
661 | return drl; | 698 | return drl; |
662 | |||
663 | critical_error: | ||
664 | /* Critical error! We cannot afford to fail here. */ | ||
665 | ntfs_error(NULL, "Critical error! Not enough memory."); | ||
666 | panic("NTFS: Cannot continue."); | ||
667 | } | 699 | } |
668 | 700 | ||
669 | /** | 701 | /** |