~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/btrfs/tests/extent-io-tests.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 2013 Fusion IO.  All rights reserved.
  4  */
  5 
  6 #include <linux/pagemap.h>
  7 #include <linux/pagevec.h>
  8 #include <linux/sched.h>
  9 #include <linux/slab.h>
 10 #include <linux/sizes.h>
 11 #include "btrfs-tests.h"
 12 #include "../ctree.h"
 13 #include "../extent_io.h"
 14 #include "../disk-io.h"
 15 #include "../btrfs_inode.h"
 16 
 17 #define PROCESS_UNLOCK          (1 << 0)
 18 #define PROCESS_RELEASE         (1 << 1)
 19 #define PROCESS_TEST_LOCKED     (1 << 2)
 20 
 21 static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
 22                                        unsigned long flags)
 23 {
 24         int ret;
 25         struct folio_batch fbatch;
 26         unsigned long index = start >> PAGE_SHIFT;
 27         unsigned long end_index = end >> PAGE_SHIFT;
 28         int i;
 29         int count = 0;
 30         int loops = 0;
 31 
 32         folio_batch_init(&fbatch);
 33 
 34         while (index <= end_index) {
 35                 ret = filemap_get_folios_contig(inode->i_mapping, &index,
 36                                 end_index, &fbatch);
 37                 for (i = 0; i < ret; i++) {
 38                         struct folio *folio = fbatch.folios[i];
 39 
 40                         if (flags & PROCESS_TEST_LOCKED &&
 41                             !folio_test_locked(folio))
 42                                 count++;
 43                         if (flags & PROCESS_UNLOCK && folio_test_locked(folio))
 44                                 folio_unlock(folio);
 45                         if (flags & PROCESS_RELEASE)
 46                                 folio_put(folio);
 47                 }
 48                 folio_batch_release(&fbatch);
 49                 cond_resched();
 50                 loops++;
 51                 if (loops > 100000) {
 52                         printk(KERN_ERR
 53                 "stuck in a loop, start %llu, end %llu, ret %d\n",
 54                                 start, end, ret);
 55                         break;
 56                 }
 57         }
 58 
 59         return count;
 60 }
 61 
 62 #define STATE_FLAG_STR_LEN                      256
 63 
 64 #define PRINT_ONE_FLAG(state, dest, cur, name)                          \
 65 ({                                                                      \
 66         if (state->state & EXTENT_##name)                               \
 67                 cur += scnprintf(dest + cur, STATE_FLAG_STR_LEN - cur,  \
 68                                  "%s" #name, cur == 0 ? "" : "|");      \
 69 })
 70 
 71 static void extent_flag_to_str(const struct extent_state *state, char *dest)
 72 {
 73         int cur = 0;
 74 
 75         dest[0] = 0;
 76         PRINT_ONE_FLAG(state, dest, cur, DIRTY);
 77         PRINT_ONE_FLAG(state, dest, cur, UPTODATE);
 78         PRINT_ONE_FLAG(state, dest, cur, LOCKED);
 79         PRINT_ONE_FLAG(state, dest, cur, NEW);
 80         PRINT_ONE_FLAG(state, dest, cur, DELALLOC);
 81         PRINT_ONE_FLAG(state, dest, cur, DEFRAG);
 82         PRINT_ONE_FLAG(state, dest, cur, BOUNDARY);
 83         PRINT_ONE_FLAG(state, dest, cur, NODATASUM);
 84         PRINT_ONE_FLAG(state, dest, cur, CLEAR_META_RESV);
 85         PRINT_ONE_FLAG(state, dest, cur, NEED_WAIT);
 86         PRINT_ONE_FLAG(state, dest, cur, NORESERVE);
 87         PRINT_ONE_FLAG(state, dest, cur, QGROUP_RESERVED);
 88         PRINT_ONE_FLAG(state, dest, cur, CLEAR_DATA_RESV);
 89 }
 90 
 91 static void dump_extent_io_tree(const struct extent_io_tree *tree)
 92 {
 93         struct rb_node *node;
 94         char flags_str[STATE_FLAG_STR_LEN];
 95 
 96         node = rb_first(&tree->state);
 97         test_msg("io tree content:");
 98         while (node) {
 99                 struct extent_state *state;
100 
101                 state = rb_entry(node, struct extent_state, rb_node);
102                 extent_flag_to_str(state, flags_str);
103                 test_msg("  start=%llu len=%llu flags=%s", state->start,
104                          state->end + 1 - state->start, flags_str);
105                 node = rb_next(node);
106         }
107 }
108 
109 static int test_find_delalloc(u32 sectorsize, u32 nodesize)
110 {
111         struct btrfs_fs_info *fs_info;
112         struct btrfs_root *root = NULL;
113         struct inode *inode = NULL;
114         struct extent_io_tree *tmp;
115         struct page *page;
116         struct page *locked_page = NULL;
117         unsigned long index = 0;
118         /* In this test we need at least 2 file extents at its maximum size */
119         u64 max_bytes = BTRFS_MAX_EXTENT_SIZE;
120         u64 total_dirty = 2 * max_bytes;
121         u64 start, end, test_start;
122         bool found;
123         int ret = -EINVAL;
124 
125         test_msg("running find delalloc tests");
126 
127         fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
128         if (!fs_info) {
129                 test_std_err(TEST_ALLOC_FS_INFO);
130                 return -ENOMEM;
131         }
132 
133         root = btrfs_alloc_dummy_root(fs_info);
134         if (IS_ERR(root)) {
135                 test_std_err(TEST_ALLOC_ROOT);
136                 ret = PTR_ERR(root);
137                 goto out;
138         }
139 
140         inode = btrfs_new_test_inode();
141         if (!inode) {
142                 test_std_err(TEST_ALLOC_INODE);
143                 ret = -ENOMEM;
144                 goto out;
145         }
146         tmp = &BTRFS_I(inode)->io_tree;
147         BTRFS_I(inode)->root = root;
148 
149         /*
150          * Passing NULL as we don't have fs_info but tracepoints are not used
151          * at this point
152          */
153         extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST);
154 
155         /*
156          * First go through and create and mark all of our pages dirty, we pin
157          * everything to make sure our pages don't get evicted and screw up our
158          * test.
159          */
160         for (index = 0; index < (total_dirty >> PAGE_SHIFT); index++) {
161                 page = find_or_create_page(inode->i_mapping, index, GFP_KERNEL);
162                 if (!page) {
163                         test_err("failed to allocate test page");
164                         ret = -ENOMEM;
165                         goto out;
166                 }
167                 SetPageDirty(page);
168                 if (index) {
169                         unlock_page(page);
170                 } else {
171                         get_page(page);
172                         locked_page = page;
173                 }
174         }
175 
176         /* Test this scenario
177          * |--- delalloc ---|
178          * |---  search  ---|
179          */
180         set_extent_bit(tmp, 0, sectorsize - 1, EXTENT_DELALLOC, NULL);
181         start = 0;
182         end = start + PAGE_SIZE - 1;
183         found = find_lock_delalloc_range(inode, locked_page, &start,
184                                          &end);
185         if (!found) {
186                 test_err("should have found at least one delalloc");
187                 goto out_bits;
188         }
189         if (start != 0 || end != (sectorsize - 1)) {
190                 test_err("expected start 0 end %u, got start %llu end %llu",
191                         sectorsize - 1, start, end);
192                 goto out_bits;
193         }
194         unlock_extent(tmp, start, end, NULL);
195         unlock_page(locked_page);
196         put_page(locked_page);
197 
198         /*
199          * Test this scenario
200          *
201          * |--- delalloc ---|
202          *           |--- search ---|
203          */
204         test_start = SZ_64M;
205         locked_page = find_lock_page(inode->i_mapping,
206                                      test_start >> PAGE_SHIFT);
207         if (!locked_page) {
208                 test_err("couldn't find the locked page");
209                 goto out_bits;
210         }
211         set_extent_bit(tmp, sectorsize, max_bytes - 1, EXTENT_DELALLOC, NULL);
212         start = test_start;
213         end = start + PAGE_SIZE - 1;
214         found = find_lock_delalloc_range(inode, locked_page, &start,
215                                          &end);
216         if (!found) {
217                 test_err("couldn't find delalloc in our range");
218                 goto out_bits;
219         }
220         if (start != test_start || end != max_bytes - 1) {
221                 test_err("expected start %llu end %llu, got start %llu, end %llu",
222                                 test_start, max_bytes - 1, start, end);
223                 goto out_bits;
224         }
225         if (process_page_range(inode, start, end,
226                                PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
227                 test_err("there were unlocked pages in the range");
228                 goto out_bits;
229         }
230         unlock_extent(tmp, start, end, NULL);
231         /* locked_page was unlocked above */
232         put_page(locked_page);
233 
234         /*
235          * Test this scenario
236          * |--- delalloc ---|
237          *                    |--- search ---|
238          */
239         test_start = max_bytes + sectorsize;
240         locked_page = find_lock_page(inode->i_mapping, test_start >>
241                                      PAGE_SHIFT);
242         if (!locked_page) {
243                 test_err("couldn't find the locked page");
244                 goto out_bits;
245         }
246         start = test_start;
247         end = start + PAGE_SIZE - 1;
248         found = find_lock_delalloc_range(inode, locked_page, &start,
249                                          &end);
250         if (found) {
251                 test_err("found range when we shouldn't have");
252                 goto out_bits;
253         }
254         if (end != test_start + PAGE_SIZE - 1) {
255                 test_err("did not return the proper end offset");
256                 goto out_bits;
257         }
258 
259         /*
260          * Test this scenario
261          * [------- delalloc -------|
262          * [max_bytes]|-- search--|
263          *
264          * We are re-using our test_start from above since it works out well.
265          */
266         set_extent_bit(tmp, max_bytes, total_dirty - 1, EXTENT_DELALLOC, NULL);
267         start = test_start;
268         end = start + PAGE_SIZE - 1;
269         found = find_lock_delalloc_range(inode, locked_page, &start,
270                                          &end);
271         if (!found) {
272                 test_err("didn't find our range");
273                 goto out_bits;
274         }
275         if (start != test_start || end != total_dirty - 1) {
276                 test_err("expected start %llu end %llu, got start %llu end %llu",
277                          test_start, total_dirty - 1, start, end);
278                 goto out_bits;
279         }
280         if (process_page_range(inode, start, end,
281                                PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
282                 test_err("pages in range were not all locked");
283                 goto out_bits;
284         }
285         unlock_extent(tmp, start, end, NULL);
286 
287         /*
288          * Now to test where we run into a page that is no longer dirty in the
289          * range we want to find.
290          */
291         page = find_get_page(inode->i_mapping,
292                              (max_bytes + SZ_1M) >> PAGE_SHIFT);
293         if (!page) {
294                 test_err("couldn't find our page");
295                 goto out_bits;
296         }
297         ClearPageDirty(page);
298         put_page(page);
299 
300         /* We unlocked it in the previous test */
301         lock_page(locked_page);
302         start = test_start;
303         end = start + PAGE_SIZE - 1;
304         /*
305          * Currently if we fail to find dirty pages in the delalloc range we
306          * will adjust max_bytes down to PAGE_SIZE and then re-search.  If
307          * this changes at any point in the future we will need to fix this
308          * tests expected behavior.
309          */
310         found = find_lock_delalloc_range(inode, locked_page, &start,
311                                          &end);
312         if (!found) {
313                 test_err("didn't find our range");
314                 goto out_bits;
315         }
316         if (start != test_start && end != test_start + PAGE_SIZE - 1) {
317                 test_err("expected start %llu end %llu, got start %llu end %llu",
318                          test_start, test_start + PAGE_SIZE - 1, start, end);
319                 goto out_bits;
320         }
321         if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED |
322                                PROCESS_UNLOCK)) {
323                 test_err("pages in range were not all locked");
324                 goto out_bits;
325         }
326         ret = 0;
327 out_bits:
328         if (ret)
329                 dump_extent_io_tree(tmp);
330         clear_extent_bits(tmp, 0, total_dirty - 1, (unsigned)-1);
331 out:
332         if (locked_page)
333                 put_page(locked_page);
334         process_page_range(inode, 0, total_dirty - 1,
335                            PROCESS_UNLOCK | PROCESS_RELEASE);
336         iput(inode);
337         btrfs_free_dummy_root(root);
338         btrfs_free_dummy_fs_info(fs_info);
339         return ret;
340 }
341 
342 static int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb)
343 {
344         unsigned long i;
345 
346         for (i = 0; i < eb->len * BITS_PER_BYTE; i++) {
347                 int bit, bit1;
348 
349                 bit = !!test_bit(i, bitmap);
350                 bit1 = !!extent_buffer_test_bit(eb, 0, i);
351                 if (bit1 != bit) {
352                         u8 has;
353                         u8 expect;
354 
355                         read_extent_buffer(eb, &has, i / BITS_PER_BYTE, 1);
356                         expect = bitmap_get_value8(bitmap, ALIGN(i, BITS_PER_BYTE));
357 
358                         test_err(
359                 "bits do not match, start byte 0 bit %lu, byte %lu has 0x%02x expect 0x%02x",
360                                  i, i / BITS_PER_BYTE, has, expect);
361                         return -EINVAL;
362                 }
363 
364                 bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE,
365                                                 i % BITS_PER_BYTE);
366                 if (bit1 != bit) {
367                         u8 has;
368                         u8 expect;
369 
370                         read_extent_buffer(eb, &has, i / BITS_PER_BYTE, 1);
371                         expect = bitmap_get_value8(bitmap, ALIGN(i, BITS_PER_BYTE));
372 
373                         test_err(
374                 "bits do not match, start byte %lu bit %lu, byte %lu has 0x%02x expect 0x%02x",
375                                  i / BITS_PER_BYTE, i % BITS_PER_BYTE,
376                                  i / BITS_PER_BYTE, has, expect);
377                         return -EINVAL;
378                 }
379         }
380         return 0;
381 }
382 
383 static int test_bitmap_set(const char *name, unsigned long *bitmap,
384                            struct extent_buffer *eb,
385                            unsigned long byte_start, unsigned long bit_start,
386                            unsigned long bit_len)
387 {
388         int ret;
389 
390         bitmap_set(bitmap, byte_start * BITS_PER_BYTE + bit_start, bit_len);
391         extent_buffer_bitmap_set(eb, byte_start, bit_start, bit_len);
392         ret = check_eb_bitmap(bitmap, eb);
393         if (ret < 0)
394                 test_err("%s test failed", name);
395         return ret;
396 }
397 
398 static int test_bitmap_clear(const char *name, unsigned long *bitmap,
399                              struct extent_buffer *eb,
400                              unsigned long byte_start, unsigned long bit_start,
401                              unsigned long bit_len)
402 {
403         int ret;
404 
405         bitmap_clear(bitmap, byte_start * BITS_PER_BYTE + bit_start, bit_len);
406         extent_buffer_bitmap_clear(eb, byte_start, bit_start, bit_len);
407         ret = check_eb_bitmap(bitmap, eb);
408         if (ret < 0)
409                 test_err("%s test failed", name);
410         return ret;
411 }
412 static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb)
413 {
414         unsigned long i, j;
415         unsigned long byte_len = eb->len;
416         u32 x;
417         int ret;
418 
419         ret = test_bitmap_clear("clear all run 1", bitmap, eb, 0, 0,
420                                 byte_len * BITS_PER_BYTE);
421         if (ret < 0)
422                 return ret;
423 
424         ret = test_bitmap_set("set all", bitmap, eb, 0, 0, byte_len * BITS_PER_BYTE);
425         if (ret < 0)
426                 return ret;
427 
428         ret = test_bitmap_clear("clear all run 2", bitmap, eb, 0, 0,
429                                 byte_len * BITS_PER_BYTE);
430         if (ret < 0)
431                 return ret;
432 
433         ret = test_bitmap_set("same byte set", bitmap, eb, 0, 2, 4);
434         if (ret < 0)
435                 return ret;
436 
437         ret = test_bitmap_clear("same byte partial clear", bitmap, eb, 0, 4, 1);
438         if (ret < 0)
439                 return ret;
440 
441         ret = test_bitmap_set("cross byte set", bitmap, eb, 2, 4, 8);
442         if (ret < 0)
443                 return ret;
444 
445         ret = test_bitmap_set("cross multi byte set", bitmap, eb, 4, 4, 24);
446         if (ret < 0)
447                 return ret;
448 
449         ret = test_bitmap_clear("cross byte clear", bitmap, eb, 2, 6, 4);
450         if (ret < 0)
451                 return ret;
452 
453         ret = test_bitmap_clear("cross multi byte clear", bitmap, eb, 4, 6, 20);
454         if (ret < 0)
455                 return ret;
456 
457         /* Straddling pages test */
458         if (byte_len > PAGE_SIZE) {
459                 ret = test_bitmap_set("cross page set", bitmap, eb,
460                                       PAGE_SIZE - sizeof(long) / 2, 0,
461                                       sizeof(long) * BITS_PER_BYTE);
462                 if (ret < 0)
463                         return ret;
464 
465                 ret = test_bitmap_set("cross page set all", bitmap, eb, 0, 0,
466                                       byte_len * BITS_PER_BYTE);
467                 if (ret < 0)
468                         return ret;
469 
470                 ret = test_bitmap_clear("cross page clear", bitmap, eb,
471                                         PAGE_SIZE - sizeof(long) / 2, 0,
472                                         sizeof(long) * BITS_PER_BYTE);
473                 if (ret < 0)
474                         return ret;
475         }
476 
477         /*
478          * Generate a wonky pseudo-random bit pattern for the sake of not using
479          * something repetitive that could miss some hypothetical off-by-n bug.
480          */
481         x = 0;
482         ret = test_bitmap_clear("clear all run 3", bitmap, eb, 0, 0,
483                                 byte_len * BITS_PER_BYTE);
484         if (ret < 0)
485                 return ret;
486 
487         for (i = 0; i < byte_len * BITS_PER_BYTE / 32; i++) {
488                 x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU;
489                 for (j = 0; j < 32; j++) {
490                         if (x & (1U << j)) {
491                                 bitmap_set(bitmap, i * 32 + j, 1);
492                                 extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1);
493                         }
494                 }
495         }
496 
497         ret = check_eb_bitmap(bitmap, eb);
498         if (ret) {
499                 test_err("random bit pattern failed");
500                 return ret;
501         }
502 
503         return 0;
504 }
505 
506 static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
507 {
508         struct btrfs_fs_info *fs_info;
509         unsigned long *bitmap = NULL;
510         struct extent_buffer *eb = NULL;
511         int ret;
512 
513         test_msg("running extent buffer bitmap tests");
514 
515         fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
516         if (!fs_info) {
517                 test_std_err(TEST_ALLOC_FS_INFO);
518                 return -ENOMEM;
519         }
520 
521         bitmap = kmalloc(nodesize, GFP_KERNEL);
522         if (!bitmap) {
523                 test_err("couldn't allocate test bitmap");
524                 ret = -ENOMEM;
525                 goto out;
526         }
527 
528         eb = __alloc_dummy_extent_buffer(fs_info, 0, nodesize);
529         if (!eb) {
530                 test_std_err(TEST_ALLOC_ROOT);
531                 ret = -ENOMEM;
532                 goto out;
533         }
534 
535         ret = __test_eb_bitmaps(bitmap, eb);
536         if (ret)
537                 goto out;
538 
539         free_extent_buffer(eb);
540 
541         /*
542          * Test again for case where the tree block is sectorsize aligned but
543          * not nodesize aligned.
544          */
545         eb = __alloc_dummy_extent_buffer(fs_info, sectorsize, nodesize);
546         if (!eb) {
547                 test_std_err(TEST_ALLOC_ROOT);
548                 ret = -ENOMEM;
549                 goto out;
550         }
551 
552         ret = __test_eb_bitmaps(bitmap, eb);
553 out:
554         free_extent_buffer(eb);
555         kfree(bitmap);
556         btrfs_free_dummy_fs_info(fs_info);
557         return ret;
558 }
559 
560 static int test_find_first_clear_extent_bit(void)
561 {
562         struct extent_io_tree tree;
563         u64 start, end;
564         int ret = -EINVAL;
565 
566         test_msg("running find_first_clear_extent_bit test");
567 
568         extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST);
569 
570         /* Test correct handling of empty tree */
571         find_first_clear_extent_bit(&tree, 0, &start, &end, CHUNK_TRIMMED);
572         if (start != 0 || end != -1) {
573                 test_err(
574         "error getting a range from completely empty tree: start %llu end %llu",
575                          start, end);
576                 goto out;
577         }
578         /*
579          * Set 1M-4M alloc/discard and 32M-64M thus leaving a hole between
580          * 4M-32M
581          */
582         set_extent_bit(&tree, SZ_1M, SZ_4M - 1,
583                        CHUNK_TRIMMED | CHUNK_ALLOCATED, NULL);
584 
585         find_first_clear_extent_bit(&tree, SZ_512K, &start, &end,
586                                     CHUNK_TRIMMED | CHUNK_ALLOCATED);
587 
588         if (start != 0 || end != SZ_1M - 1) {
589                 test_err("error finding beginning range: start %llu end %llu",
590                          start, end);
591                 goto out;
592         }
593 
594         /* Now add 32M-64M so that we have a hole between 4M-32M */
595         set_extent_bit(&tree, SZ_32M, SZ_64M - 1,
596                        CHUNK_TRIMMED | CHUNK_ALLOCATED, NULL);
597 
598         /*
599          * Request first hole starting at 12M, we should get 4M-32M
600          */
601         find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end,
602                                     CHUNK_TRIMMED | CHUNK_ALLOCATED);
603 
604         if (start != SZ_4M || end != SZ_32M - 1) {
605                 test_err("error finding trimmed range: start %llu end %llu",
606                          start, end);
607                 goto out;
608         }
609 
610         /*
611          * Search in the middle of allocated range, should get the next one
612          * available, which happens to be unallocated -> 4M-32M
613          */
614         find_first_clear_extent_bit(&tree, SZ_2M, &start, &end,
615                                     CHUNK_TRIMMED | CHUNK_ALLOCATED);
616 
617         if (start != SZ_4M || end != SZ_32M - 1) {
618                 test_err("error finding next unalloc range: start %llu end %llu",
619                          start, end);
620                 goto out;
621         }
622 
623         /*
624          * Set 64M-72M with CHUNK_ALLOC flag, then search for CHUNK_TRIMMED flag
625          * being unset in this range, we should get the entry in range 64M-72M
626          */
627         set_extent_bit(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED, NULL);
628         find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end,
629                                     CHUNK_TRIMMED);
630 
631         if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) {
632                 test_err("error finding exact range: start %llu end %llu",
633                          start, end);
634                 goto out;
635         }
636 
637         find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end,
638                                     CHUNK_TRIMMED);
639 
640         /*
641          * Search in the middle of set range whose immediate neighbour doesn't
642          * have the bits set so it must be returned
643          */
644         if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) {
645                 test_err("error finding next alloc range: start %llu end %llu",
646                          start, end);
647                 goto out;
648         }
649 
650         /*
651          * Search beyond any known range, shall return after last known range
652          * and end should be -1
653          */
654         find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED);
655         if (start != SZ_64M + SZ_8M || end != -1) {
656                 test_err(
657                 "error handling beyond end of range search: start %llu end %llu",
658                         start, end);
659                 goto out;
660         }
661 
662         ret = 0;
663 out:
664         if (ret)
665                 dump_extent_io_tree(&tree);
666         clear_extent_bits(&tree, 0, (u64)-1, CHUNK_TRIMMED | CHUNK_ALLOCATED);
667 
668         return ret;
669 }
670 
671 static void dump_eb_and_memory_contents(struct extent_buffer *eb, void *memory,
672                                         const char *test_name)
673 {
674         for (int i = 0; i < eb->len; i++) {
675                 struct page *page = folio_page(eb->folios[i >> PAGE_SHIFT], 0);
676                 void *addr = page_address(page) + offset_in_page(i);
677 
678                 if (memcmp(addr, memory + i, 1) != 0) {
679                         test_err("%s failed", test_name);
680                         test_err("eb and memory diffs at byte %u, eb has 0x%02x memory has 0x%02x",
681                                  i, *(u8 *)addr, *(u8 *)(memory + i));
682                         return;
683                 }
684         }
685 }
686 
687 static int verify_eb_and_memory(struct extent_buffer *eb, void *memory,
688                                 const char *test_name)
689 {
690         for (int i = 0; i < (eb->len >> PAGE_SHIFT); i++) {
691                 void *eb_addr = folio_address(eb->folios[i]);
692 
693                 if (memcmp(memory + (i << PAGE_SHIFT), eb_addr, PAGE_SIZE) != 0) {
694                         dump_eb_and_memory_contents(eb, memory, test_name);
695                         return -EUCLEAN;
696                 }
697         }
698         return 0;
699 }
700 
701 /*
702  * Init both memory and extent buffer contents to the same randomly generated
703  * contents.
704  */
705 static void init_eb_and_memory(struct extent_buffer *eb, void *memory)
706 {
707         get_random_bytes(memory, eb->len);
708         write_extent_buffer(eb, memory, 0, eb->len);
709 }
710 
711 static int test_eb_mem_ops(u32 sectorsize, u32 nodesize)
712 {
713         struct btrfs_fs_info *fs_info;
714         struct extent_buffer *eb = NULL;
715         void *memory = NULL;
716         int ret;
717 
718         test_msg("running extent buffer memory operation tests");
719 
720         fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
721         if (!fs_info) {
722                 test_std_err(TEST_ALLOC_FS_INFO);
723                 return -ENOMEM;
724         }
725 
726         memory = kvzalloc(nodesize, GFP_KERNEL);
727         if (!memory) {
728                 test_err("failed to allocate memory");
729                 ret = -ENOMEM;
730                 goto out;
731         }
732 
733         eb = __alloc_dummy_extent_buffer(fs_info, SZ_1M, nodesize);
734         if (!eb) {
735                 test_std_err(TEST_ALLOC_EXTENT_BUFFER);
736                 ret = -ENOMEM;
737                 goto out;
738         }
739 
740         init_eb_and_memory(eb, memory);
741         ret = verify_eb_and_memory(eb, memory, "full eb write");
742         if (ret < 0)
743                 goto out;
744 
745         memcpy(memory, memory + 16, 16);
746         memcpy_extent_buffer(eb, 0, 16, 16);
747         ret = verify_eb_and_memory(eb, memory, "same page non-overlapping memcpy 1");
748         if (ret < 0)
749                 goto out;
750 
751         memcpy(memory, memory + 2048, 16);
752         memcpy_extent_buffer(eb, 0, 2048, 16);
753         ret = verify_eb_and_memory(eb, memory, "same page non-overlapping memcpy 2");
754         if (ret < 0)
755                 goto out;
756         memcpy(memory, memory + 2048, 2048);
757         memcpy_extent_buffer(eb, 0, 2048, 2048);
758         ret = verify_eb_and_memory(eb, memory, "same page non-overlapping memcpy 3");
759         if (ret < 0)
760                 goto out;
761 
762         memmove(memory + 512, memory + 256, 512);
763         memmove_extent_buffer(eb, 512, 256, 512);
764         ret = verify_eb_and_memory(eb, memory, "same page overlapping memcpy 1");
765         if (ret < 0)
766                 goto out;
767 
768         memmove(memory + 2048, memory + 512, 2048);
769         memmove_extent_buffer(eb, 2048, 512, 2048);
770         ret = verify_eb_and_memory(eb, memory, "same page overlapping memcpy 2");
771         if (ret < 0)
772                 goto out;
773         memmove(memory + 512, memory + 2048, 2048);
774         memmove_extent_buffer(eb, 512, 2048, 2048);
775         ret = verify_eb_and_memory(eb, memory, "same page overlapping memcpy 3");
776         if (ret < 0)
777                 goto out;
778 
779         if (nodesize > PAGE_SIZE) {
780                 memcpy(memory, memory + 4096 - 128, 256);
781                 memcpy_extent_buffer(eb, 0, 4096 - 128, 256);
782                 ret = verify_eb_and_memory(eb, memory, "cross page non-overlapping memcpy 1");
783                 if (ret < 0)
784                         goto out;
785 
786                 memcpy(memory + 4096 - 128, memory + 4096 + 128, 256);
787                 memcpy_extent_buffer(eb, 4096 - 128, 4096 + 128, 256);
788                 ret = verify_eb_and_memory(eb, memory, "cross page non-overlapping memcpy 2");
789                 if (ret < 0)
790                         goto out;
791 
792                 memmove(memory + 4096 - 128, memory + 4096 - 64, 256);
793                 memmove_extent_buffer(eb, 4096 - 128, 4096 - 64, 256);
794                 ret = verify_eb_and_memory(eb, memory, "cross page overlapping memcpy 1");
795                 if (ret < 0)
796                         goto out;
797 
798                 memmove(memory + 4096 - 64, memory + 4096 - 128, 256);
799                 memmove_extent_buffer(eb, 4096 - 64, 4096 - 128, 256);
800                 ret = verify_eb_and_memory(eb, memory, "cross page overlapping memcpy 2");
801                 if (ret < 0)
802                         goto out;
803         }
804 out:
805         free_extent_buffer(eb);
806         kvfree(memory);
807         btrfs_free_dummy_fs_info(fs_info);
808         return ret;
809 }
810 
811 int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
812 {
813         int ret;
814 
815         test_msg("running extent I/O tests");
816 
817         ret = test_find_delalloc(sectorsize, nodesize);
818         if (ret)
819                 goto out;
820 
821         ret = test_find_first_clear_extent_bit();
822         if (ret)
823                 goto out;
824 
825         ret = test_eb_bitmaps(sectorsize, nodesize);
826         if (ret)
827                 goto out;
828 
829         ret = test_eb_mem_ops(sectorsize, nodesize);
830 out:
831         return ret;
832 }
833 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php