patch-2.4.11-dontuse linux/mm/shmem.c

Next file: linux/mm/swap_state.c
Previous file: linux/mm/page_alloc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.10/linux/mm/shmem.c linux/mm/shmem.c
@@ -245,6 +245,14 @@
 	index = page->index;
 	inode = mapping->host;
 	info = &inode->u.shmem_i;
+getswap:
+	swap = get_swap_page();
+	if (!swap.val) {
+		activate_page(page);
+		SetPageDirty(page);
+		error = -ENOMEM;
+		goto out;
+	}
 
 	spin_lock(&info->lock);
 	entry = shmem_swp_entry(info, index);
@@ -257,32 +265,27 @@
 	/* Remove it from the page cache */
 	lru_cache_del(page);
 	remove_inode_page(page);
+	page_cache_release(page);
 
-	swap_list_lock();
-	swap = get_swap_page();
-
-	if (!swap.val) {
-		swap_list_unlock();
-		/* Add it back to the page cache */
+	/* Add it to the swap cache */
+	if (add_to_swap_cache(page, swap) != 0) {
+		/*
+		 * Raced with "speculative" read_swap_cache_async.
+		 * Add page back to page cache, unref swap, try again.
+		 */
 		add_to_page_cache_locked(page, mapping, index);
-		activate_page(page);
-		SetPageDirty(page);
-		error = -ENOMEM;
-		goto out;
+		spin_unlock(&info->lock);
+		swap_free(swap);
+		goto getswap;
 	}
 
-	/* Add it to the swap cache */
-	add_to_swap_cache(page, swap);
-	swap_list_unlock();
-
-	set_page_dirty(page);
-	info->swapped++;
 	*entry = swap;
+	info->swapped++;
+	spin_unlock(&info->lock);
+	set_page_dirty(page);
 	error = 0;
 out:
-	spin_unlock(&info->lock);
 	UnlockPage(page);
-	page_cache_release(page);
 	return error;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)