mm, swap: introduce SWP_SYNCHRONOUS_IO
[sfrench/cifs-2.6.git] / mm / swapfile.c
index bf91dc9e7a791d38b28ab84f10b57892fc0af9dc..cb08fa65819fc6502cfc6432a34239f88b23d7b9 100644 (file)
@@ -2869,6 +2869,7 @@ static struct swap_info_struct *alloc_swap_info(void)
        p->flags = SWP_USED;
        spin_unlock(&swap_lock);
        spin_lock_init(&p->lock);
+       spin_lock_init(&p->cont_lock);
 
        return p;
 }
@@ -3168,6 +3169,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        if (bdi_cap_stable_pages_required(inode_to_bdi(inode)))
                p->flags |= SWP_STABLE_WRITES;
 
+       if (bdi_cap_synchronous_io(inode_to_bdi(inode)))
+               p->flags |= SWP_SYNCHRONOUS_IO;
+
        if (p->bdev && blk_queue_nonrot(bdev_get_queue(p->bdev))) {
                int cpu;
                unsigned long ci, nr_cluster;
@@ -3545,6 +3549,7 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask)
        head = vmalloc_to_page(si->swap_map + offset);
        offset &= ~PAGE_MASK;
 
+       spin_lock(&si->cont_lock);
        /*
         * Page allocation does not initialize the page's lru field,
         * but it does always reset its private field.
@@ -3564,7 +3569,7 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask)
                 * a continuation page, free our allocation and use this one.
                 */
                if (!(count & COUNT_CONTINUED))
-                       goto out;
+                       goto out_unlock_cont;
 
                map = kmap_atomic(list_page) + offset;
                count = *map;
@@ -3575,11 +3580,13 @@ int add_swap_count_continuation(swp_entry_t entry, gfp_t gfp_mask)
                 * free our allocation and use this one.
                 */
                if ((count & ~COUNT_CONTINUED) != SWAP_CONT_MAX)
-                       goto out;
+                       goto out_unlock_cont;
        }
 
        list_add_tail(&page->lru, &head->lru);
        page = NULL;                    /* now it's attached, don't free it */
+out_unlock_cont:
+       spin_unlock(&si->cont_lock);
 out:
        unlock_cluster(ci);
        spin_unlock(&si->lock);
@@ -3604,6 +3611,7 @@ static bool swap_count_continued(struct swap_info_struct *si,
        struct page *head;
        struct page *page;
        unsigned char *map;
+       bool ret;
 
        head = vmalloc_to_page(si->swap_map + offset);
        if (page_private(head) != SWP_CONTINUED) {
@@ -3611,6 +3619,7 @@ static bool swap_count_continued(struct swap_info_struct *si,
                return false;           /* need to add count continuation */
        }
 
+       spin_lock(&si->cont_lock);
        offset &= ~PAGE_MASK;
        page = list_entry(head->lru.next, struct page, lru);
        map = kmap_atomic(page) + offset;
@@ -3631,8 +3640,10 @@ static bool swap_count_continued(struct swap_info_struct *si,
                if (*map == SWAP_CONT_MAX) {
                        kunmap_atomic(map);
                        page = list_entry(page->lru.next, struct page, lru);
-                       if (page == head)
-                               return false;   /* add count continuation */
+                       if (page == head) {
+                               ret = false;    /* add count continuation */
+                               goto out;
+                       }
                        map = kmap_atomic(page) + offset;
 init_map:              *map = 0;               /* we didn't zero the page */
                }
@@ -3645,7 +3656,7 @@ init_map:         *map = 0;               /* we didn't zero the page */
                        kunmap_atomic(map);
                        page = list_entry(page->lru.prev, struct page, lru);
                }
-               return true;                    /* incremented */
+               ret = true;                     /* incremented */
 
        } else {                                /* decrementing */
                /*
@@ -3671,8 +3682,11 @@ init_map:                *map = 0;               /* we didn't zero the page */
                        kunmap_atomic(map);
                        page = list_entry(page->lru.prev, struct page, lru);
                }
-               return count == COUNT_CONTINUED;
+               ret = count == COUNT_CONTINUED;
        }
+out:
+       spin_unlock(&si->cont_lock);
+       return ret;
 }
 
 /*