]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - mm/shmem.c
tmpfs: make shmem_unuse more preemptible
[net-next-2.6.git] / mm / shmem.c
index c919ed578f0a2909b1d149bb3ed4793a9ec6845b..2e03d6031c244dbc213514bfb95cb862d4583975 100644 (file)
@@ -193,7 +193,7 @@ static struct backing_dev_info shmem_backing_dev_info  __read_mostly = {
 };
 
 static LIST_HEAD(shmem_swaplist);
-static DEFINE_SPINLOCK(shmem_swaplist_lock);
+static DEFINE_MUTEX(shmem_swaplist_mutex);
 
 static void shmem_free_blocks(struct inode *inode, long pages)
 {
@@ -796,9 +796,9 @@ static void shmem_delete_inode(struct inode *inode)
                inode->i_size = 0;
                shmem_truncate(inode);
                if (!list_empty(&info->swaplist)) {
-                       spin_lock(&shmem_swaplist_lock);
+                       mutex_lock(&shmem_swaplist_mutex);
                        list_del_init(&info->swaplist);
-                       spin_unlock(&shmem_swaplist_lock);
+                       mutex_unlock(&shmem_swaplist_mutex);
                }
        }
        BUG_ON(inode->i_blocks);
@@ -851,6 +851,14 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
        for (idx = SHMEM_NR_DIRECT; idx < limit; idx += ENTRIES_PER_PAGE, dir++) {
                if (unlikely(idx == stage)) {
                        shmem_dir_unmap(dir-1);
+                       if (cond_resched_lock(&info->lock)) {
+                               /* check it has not been truncated */
+                               if (limit > info->next_index) {
+                                       limit = info->next_index;
+                                       if (idx >= limit)
+                                               goto lost2;
+                               }
+                       }
                        dir = shmem_dir_map(info->i_indirect) +
                            ENTRIES_PER_PAGE/2 + idx/ENTRIES_PER_PAGEPAGE;
                        while (!*dir) {
@@ -924,7 +932,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
        struct shmem_inode_info *info;
        int found = 0;
 
-       spin_lock(&shmem_swaplist_lock);
+       mutex_lock(&shmem_swaplist_mutex);
        list_for_each_safe(p, next, &shmem_swaplist) {
                info = list_entry(p, struct shmem_inode_info, swaplist);
                if (!info->swapped)
@@ -935,8 +943,9 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
                        found = 1;
                        break;
                }
+               cond_resched();
        }
-       spin_unlock(&shmem_swaplist_lock);
+       mutex_unlock(&shmem_swaplist_mutex);
        return found;
 }
 
@@ -996,10 +1005,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
                shmem_swp_unmap(entry);
                spin_unlock(&info->lock);
                if (list_empty(&info->swaplist)) {
-                       spin_lock(&shmem_swaplist_lock);
+                       mutex_lock(&shmem_swaplist_mutex);
                        /* move instead of add in case we're racing */
                        list_move_tail(&info->swaplist, &shmem_swaplist);
-                       spin_unlock(&shmem_swaplist_lock);
+                       mutex_unlock(&shmem_swaplist_mutex);
                }
                swap_duplicate(swap);
                BUG_ON(page_mapped(page));