Btrfs: use linux/sizes.h to represent constants
[deliverable/linux.git] / fs / btrfs / tests / extent-io-tests.c
1 /*
2 * Copyright (C) 2013 Fusion IO. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
17 */
18
19 #include <linux/pagemap.h>
20 #include <linux/sched.h>
21 #include <linux/sizes.h>
22 #include "btrfs-tests.h"
23 #include "../extent_io.h"
24
25 #define PROCESS_UNLOCK (1 << 0)
26 #define PROCESS_RELEASE (1 << 1)
27 #define PROCESS_TEST_LOCKED (1 << 2)
28
29 static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
30 unsigned long flags)
31 {
32 int ret;
33 struct page *pages[16];
34 unsigned long index = start >> PAGE_CACHE_SHIFT;
35 unsigned long end_index = end >> PAGE_CACHE_SHIFT;
36 unsigned long nr_pages = end_index - index + 1;
37 int i;
38 int count = 0;
39 int loops = 0;
40
41 while (nr_pages > 0) {
42 ret = find_get_pages_contig(inode->i_mapping, index,
43 min_t(unsigned long, nr_pages,
44 ARRAY_SIZE(pages)), pages);
45 for (i = 0; i < ret; i++) {
46 if (flags & PROCESS_TEST_LOCKED &&
47 !PageLocked(pages[i]))
48 count++;
49 if (flags & PROCESS_UNLOCK && PageLocked(pages[i]))
50 unlock_page(pages[i]);
51 page_cache_release(pages[i]);
52 if (flags & PROCESS_RELEASE)
53 page_cache_release(pages[i]);
54 }
55 nr_pages -= ret;
56 index += ret;
57 cond_resched();
58 loops++;
59 if (loops > 100000) {
60 printk(KERN_ERR "stuck in a loop, start %Lu, end %Lu, nr_pages %lu, ret %d\n", start, end, nr_pages, ret);
61 break;
62 }
63 }
64 return count;
65 }
66
67 static int test_find_delalloc(void)
68 {
69 struct inode *inode;
70 struct extent_io_tree tmp;
71 struct page *page;
72 struct page *locked_page = NULL;
73 unsigned long index = 0;
74 u64 total_dirty = SZ_256M;
75 u64 max_bytes = SZ_128M;
76 u64 start, end, test_start;
77 u64 found;
78 int ret = -EINVAL;
79
80 inode = btrfs_new_test_inode();
81 if (!inode) {
82 test_msg("Failed to allocate test inode\n");
83 return -ENOMEM;
84 }
85
86 extent_io_tree_init(&tmp, &inode->i_data);
87
88 /*
89 * First go through and create and mark all of our pages dirty, we pin
90 * everything to make sure our pages don't get evicted and screw up our
91 * test.
92 */
93 for (index = 0; index < (total_dirty >> PAGE_CACHE_SHIFT); index++) {
94 page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
95 if (!page) {
96 test_msg("Failed to allocate test page\n");
97 ret = -ENOMEM;
98 goto out;
99 }
100 SetPageDirty(page);
101 if (index) {
102 unlock_page(page);
103 } else {
104 page_cache_get(page);
105 locked_page = page;
106 }
107 }
108
109 /* Test this scenario
110 * |--- delalloc ---|
111 * |--- search ---|
112 */
113 set_extent_delalloc(&tmp, 0, 4095, NULL, GFP_NOFS);
114 start = 0;
115 end = 0;
116 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
117 &end, max_bytes);
118 if (!found) {
119 test_msg("Should have found at least one delalloc\n");
120 goto out_bits;
121 }
122 if (start != 0 || end != 4095) {
123 test_msg("Expected start 0 end 4095, got start %Lu end %Lu\n",
124 start, end);
125 goto out_bits;
126 }
127 unlock_extent(&tmp, start, end);
128 unlock_page(locked_page);
129 page_cache_release(locked_page);
130
131 /*
132 * Test this scenario
133 *
134 * |--- delalloc ---|
135 * |--- search ---|
136 */
137 test_start = SZ_64M;
138 locked_page = find_lock_page(inode->i_mapping,
139 test_start >> PAGE_CACHE_SHIFT);
140 if (!locked_page) {
141 test_msg("Couldn't find the locked page\n");
142 goto out_bits;
143 }
144 set_extent_delalloc(&tmp, 4096, max_bytes - 1, NULL, GFP_NOFS);
145 start = test_start;
146 end = 0;
147 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
148 &end, max_bytes);
149 if (!found) {
150 test_msg("Couldn't find delalloc in our range\n");
151 goto out_bits;
152 }
153 if (start != test_start || end != max_bytes - 1) {
154 test_msg("Expected start %Lu end %Lu, got start %Lu, end "
155 "%Lu\n", test_start, max_bytes - 1, start, end);
156 goto out_bits;
157 }
158 if (process_page_range(inode, start, end,
159 PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
160 test_msg("There were unlocked pages in the range\n");
161 goto out_bits;
162 }
163 unlock_extent(&tmp, start, end);
164 /* locked_page was unlocked above */
165 page_cache_release(locked_page);
166
167 /*
168 * Test this scenario
169 * |--- delalloc ---|
170 * |--- search ---|
171 */
172 test_start = max_bytes + 4096;
173 locked_page = find_lock_page(inode->i_mapping, test_start >>
174 PAGE_CACHE_SHIFT);
175 if (!locked_page) {
176 test_msg("Could'nt find the locked page\n");
177 goto out_bits;
178 }
179 start = test_start;
180 end = 0;
181 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
182 &end, max_bytes);
183 if (found) {
184 test_msg("Found range when we shouldn't have\n");
185 goto out_bits;
186 }
187 if (end != (u64)-1) {
188 test_msg("Did not return the proper end offset\n");
189 goto out_bits;
190 }
191
192 /*
193 * Test this scenario
194 * [------- delalloc -------|
195 * [max_bytes]|-- search--|
196 *
197 * We are re-using our test_start from above since it works out well.
198 */
199 set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, NULL, GFP_NOFS);
200 start = test_start;
201 end = 0;
202 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
203 &end, max_bytes);
204 if (!found) {
205 test_msg("Didn't find our range\n");
206 goto out_bits;
207 }
208 if (start != test_start || end != total_dirty - 1) {
209 test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
210 test_start, total_dirty - 1, start, end);
211 goto out_bits;
212 }
213 if (process_page_range(inode, start, end,
214 PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
215 test_msg("Pages in range were not all locked\n");
216 goto out_bits;
217 }
218 unlock_extent(&tmp, start, end);
219
220 /*
221 * Now to test where we run into a page that is no longer dirty in the
222 * range we want to find.
223 */
224 page = find_get_page(inode->i_mapping,
225 (max_bytes + SZ_1M) >> PAGE_CACHE_SHIFT);
226 if (!page) {
227 test_msg("Couldn't find our page\n");
228 goto out_bits;
229 }
230 ClearPageDirty(page);
231 page_cache_release(page);
232
233 /* We unlocked it in the previous test */
234 lock_page(locked_page);
235 start = test_start;
236 end = 0;
237 /*
238 * Currently if we fail to find dirty pages in the delalloc range we
239 * will adjust max_bytes down to PAGE_CACHE_SIZE and then re-search. If
240 * this changes at any point in the future we will need to fix this
241 * tests expected behavior.
242 */
243 found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
244 &end, max_bytes);
245 if (!found) {
246 test_msg("Didn't find our range\n");
247 goto out_bits;
248 }
249 if (start != test_start && end != test_start + PAGE_CACHE_SIZE - 1) {
250 test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
251 test_start, test_start + PAGE_CACHE_SIZE - 1, start,
252 end);
253 goto out_bits;
254 }
255 if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED |
256 PROCESS_UNLOCK)) {
257 test_msg("Pages in range were not all locked\n");
258 goto out_bits;
259 }
260 ret = 0;
261 out_bits:
262 clear_extent_bits(&tmp, 0, total_dirty - 1, (unsigned)-1, GFP_NOFS);
263 out:
264 if (locked_page)
265 page_cache_release(locked_page);
266 process_page_range(inode, 0, total_dirty - 1,
267 PROCESS_UNLOCK | PROCESS_RELEASE);
268 iput(inode);
269 return ret;
270 }
271
272 int btrfs_test_extent_io(void)
273 {
274 test_msg("Running find delalloc tests\n");
275 return test_find_delalloc();
276 }
This page took 0.036778 seconds and 6 git commands to generate.