/* If unset, the snapshot device cannot be open. */
 extern atomic_t snapshot_device_available;
 
-/**
- *     The bitmap is used for tracing allocated swap pages
- *
- *     The entire bitmap consists of a number of bitmap_page
- *     structures linked with the help of the .next member.
- *     Thus each page can be allocated individually, so we only
- *     need to make 0-order memory allocations to create
- *     the bitmap.
- */
-
-#define BITMAP_PAGE_SIZE       (PAGE_SIZE - sizeof(void *))
-#define BITMAP_PAGE_CHUNKS     (BITMAP_PAGE_SIZE / sizeof(long))
-#define BITS_PER_CHUNK         (sizeof(long) * 8)
-#define BITMAP_PAGE_BITS       (BITMAP_PAGE_CHUNKS * BITS_PER_CHUNK)
-
-struct bitmap_page {
-       unsigned long           chunks[BITMAP_PAGE_CHUNKS];
-       struct bitmap_page      *next;
-};
-
-extern void free_bitmap(struct bitmap_page *bitmap);
-extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits);
-extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap);
-extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
+extern sector_t alloc_swapdev_block(int swap);
+extern void free_all_swap_pages(int swap);
+extern int swsusp_swap_in_use(void);
 
 extern int swsusp_check(void);
 extern int swsusp_shrink_memory(void);
 
 struct swap_map_handle {
        struct swap_map_page *cur;
        sector_t cur_swap;
-       struct bitmap_page *bitmap;
        unsigned int k;
 };
 
        if (handle->cur)
                free_page((unsigned long)handle->cur);
        handle->cur = NULL;
-       if (handle->bitmap)
-               free_bitmap(handle->bitmap);
-       handle->bitmap = NULL;
 }
 
 static int get_swap_writer(struct swap_map_handle *handle)
        handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
        if (!handle->cur)
                return -ENOMEM;
-       handle->bitmap = alloc_bitmap(count_swap_pages(root_swap, 0));
-       if (!handle->bitmap) {
-               release_swap_writer(handle);
-               return -ENOMEM;
-       }
-       handle->cur_swap = alloc_swapdev_block(root_swap, handle->bitmap);
+       handle->cur_swap = alloc_swapdev_block(root_swap);
        if (!handle->cur_swap) {
                release_swap_writer(handle);
                return -ENOSPC;
 
        if (!handle->cur)
                return -EINVAL;
-       offset = alloc_swapdev_block(root_swap, handle->bitmap);
+       offset = alloc_swapdev_block(root_swap);
        error = write_page(buf, offset, bio_chain);
        if (error)
                return error;
                error = wait_on_bio_chain(bio_chain);
                if (error)
                        goto out;
-               offset = alloc_swapdev_block(root_swap, handle->bitmap);
+               offset = alloc_swapdev_block(root_swap);
                if (!offset)
                        return -ENOSPC;
                handle->cur->next_swap = offset;
                }
        }
        if (error)
-               free_all_swap_pages(root_swap, handle.bitmap);
+               free_all_swap_pages(root_swap);
+
        release_swap_writer(&handle);
  out:
        swsusp_close();
 
 #include <linux/syscalls.h>
 #include <linux/highmem.h>
 #include <linux/time.h>
+#include <linux/rbtree.h>
 
 #include "power.h"
 
 /**
  *     The following functions are used for tracing the allocated
  *     swap pages, so that they can be freed in case of an error.
- *
- *     The functions operate on a linked bitmap structure defined
- *     in power.h
  */
 
-void free_bitmap(struct bitmap_page *bitmap)
-{
-       struct bitmap_page *bp;
+struct swsusp_extent {
+       struct rb_node node;
+       unsigned long start;
+       unsigned long end;
+};
 
-       while (bitmap) {
-               bp = bitmap->next;
-               free_page((unsigned long)bitmap);
-               bitmap = bp;
-       }
-}
+static struct rb_root swsusp_extents = RB_ROOT;
 
-struct bitmap_page *alloc_bitmap(unsigned int nr_bits)
+static int swsusp_extents_insert(unsigned long swap_offset)
 {
-       struct bitmap_page *bitmap, *bp;
-       unsigned int n;
-
-       if (!nr_bits)
-               return NULL;
-
-       bitmap = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL);
-       bp = bitmap;
-       for (n = BITMAP_PAGE_BITS; n < nr_bits; n += BITMAP_PAGE_BITS) {
-               bp->next = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL);
-               bp = bp->next;
-               if (!bp) {
-                       free_bitmap(bitmap);
-                       return NULL;
+       struct rb_node **new = &(swsusp_extents.rb_node);
+       struct rb_node *parent = NULL;
+       struct swsusp_extent *ext;
+
+       /* Figure out where to put the new node */
+       while (*new) {
+               ext = container_of(*new, struct swsusp_extent, node);
+               parent = *new;
+               if (swap_offset < ext->start) {
+                       /* Try to merge */
+                       if (swap_offset == ext->start - 1) {
+                               ext->start--;
+                               return 0;
+                       }
+                       new = &((*new)->rb_left);
+               } else if (swap_offset > ext->end) {
+                       /* Try to merge */
+                       if (swap_offset == ext->end + 1) {
+                               ext->end++;
+                               return 0;
+                       }
+                       new = &((*new)->rb_right);
+               } else {
+                       /* It already is in the tree */
+                       return -EINVAL;
                }
        }
-       return bitmap;
-}
-
-static int bitmap_set(struct bitmap_page *bitmap, unsigned long bit)
-{
-       unsigned int n;
-
-       n = BITMAP_PAGE_BITS;
-       while (bitmap && n <= bit) {
-               n += BITMAP_PAGE_BITS;
-               bitmap = bitmap->next;
-       }
-       if (!bitmap)
-               return -EINVAL;
-       n -= BITMAP_PAGE_BITS;
-       bit -= n;
-       n = 0;
-       while (bit >= BITS_PER_CHUNK) {
-               bit -= BITS_PER_CHUNK;
-               n++;
-       }
-       bitmap->chunks[n] |= (1UL << bit);
+       /* Add the new node and rebalance the tree. */
+       ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
+       if (!ext)
+               return -ENOMEM;
+
+       ext->start = swap_offset;
+       ext->end = swap_offset;
+       rb_link_node(&ext->node, parent, new);
+       rb_insert_color(&ext->node, &swsusp_extents);
        return 0;
 }
 
-sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap)
+/**
+ *     alloc_swapdev_block - allocate a swap page and register that it has
+ *     been allocated, so that it can be freed in case of an error.
+ */
+
+sector_t alloc_swapdev_block(int swap)
 {
        unsigned long offset;
 
        offset = swp_offset(get_swap_page_of_type(swap));
        if (offset) {
-               if (bitmap_set(bitmap, offset))
+               if (swsusp_extents_insert(offset))
                        swap_free(swp_entry(swap, offset));
                else
                        return swapdev_block(swap, offset);
        return 0;
 }
 
-void free_all_swap_pages(int swap, struct bitmap_page *bitmap)
+/**
+ *     free_all_swap_pages - free swap pages allocated for saving image data.
+ *     It also frees the extents used to register which swap entres had been
+ *     allocated.
+ */
+
+void free_all_swap_pages(int swap)
 {
-       unsigned int bit, n;
-       unsigned long test;
-
-       bit = 0;
-       while (bitmap) {
-               for (n = 0; n < BITMAP_PAGE_CHUNKS; n++)
-                       for (test = 1UL; test; test <<= 1) {
-                               if (bitmap->chunks[n] & test)
-                                       swap_free(swp_entry(swap, bit));
-                               bit++;
-                       }
-               bitmap = bitmap->next;
+       struct rb_node *node;
+
+       while ((node = swsusp_extents.rb_node)) {
+               struct swsusp_extent *ext;
+               unsigned long offset;
+
+               ext = container_of(node, struct swsusp_extent, node);
+               rb_erase(node, &swsusp_extents);
+               for (offset = ext->start; offset <= ext->end; offset++)
+                       swap_free(swp_entry(swap, offset));
+
+               kfree(ext);
        }
 }
 
+int swsusp_swap_in_use(void)
+{
+       return (swsusp_extents.rb_node != NULL);
+}
+
 /**
  *     swsusp_show_speed - print the time elapsed between two events represented by
  *     @start and @stop
 
 static struct snapshot_data {
        struct snapshot_handle handle;
        int swap;
-       struct bitmap_page *bitmap;
        int mode;
        char frozen;
        char ready;
                data->swap = -1;
                data->mode = O_WRONLY;
        }
-       data->bitmap = NULL;
        data->frozen = 0;
        data->ready = 0;
        data->platform_suspend = 0;
        swsusp_free();
        free_basic_memory_bitmaps();
        data = filp->private_data;
-       free_all_swap_pages(data->swap, data->bitmap);
-       free_bitmap(data->bitmap);
+       free_all_swap_pages(data->swap);
        if (data->frozen) {
                mutex_lock(&pm_mutex);
                thaw_processes();
                        error = -ENODEV;
                        break;
                }
-               if (!data->bitmap) {
-                       data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0));
-                       if (!data->bitmap) {
-                               error = -ENOMEM;
-                               break;
-                       }
-               }
-               offset = alloc_swapdev_block(data->swap, data->bitmap);
+               offset = alloc_swapdev_block(data->swap);
                if (offset) {
                        offset <<= PAGE_SHIFT;
                        error = put_user(offset, (sector_t __user *)arg);
                        error = -ENODEV;
                        break;
                }
-               free_all_swap_pages(data->swap, data->bitmap);
-               free_bitmap(data->bitmap);
-               data->bitmap = NULL;
+               free_all_swap_pages(data->swap);
                break;
 
        case SNAPSHOT_SET_SWAP_FILE:
-               if (!data->bitmap) {
+               if (!swsusp_swap_in_use()) {
                        /*
                         * User space encodes device types as two-byte values,
                         * so we need to recode them
                break;
 
        case SNAPSHOT_SET_SWAP_AREA:
-               if (data->bitmap) {
+               if (swsusp_swap_in_use()) {
                        error = -EPERM;
                } else {
                        struct resume_swap_area swap_area;