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