Update of /cvsroot/linuxcompressed/linux/mm
In directory sc8-pr-cvs1:/tmp/cvs-serv8451/mm
Modified Files:
swap_state.c swapfile.c
Log Message:
Some races still to be fixed, but we have fixed a bunch of them in
this set of changes, including one that would corrupt FSs when used
with preempt patch.
Bug fixes
o Fixed bug that might compress a page for the second time if it were
swapped in while being written using swap buffers. In this case, a new
swap cache page could be compressed and we are not sure the fragment
being written out had actually been freed. The fix is to make the swap
buffer get a reference on this swap cache page, releasing when the
swap buffer is freed.
o Fixed bug that could submit a read to the disk while the same block
is being written by a swap buffer. When writing out the swap buffer,
we get a reference on the fragment in order to avoid it to be
released, even if swapped in in the meanwhile.
o Removed extra spin_lock()/spin_unlock() on comp_cache_lock in
grow_comp_cache()
o Fixed race in compact_comp_cace() that we were triggering which
would corrupt fs or return wrong process data, likely to segfault. It
happened usually with preempt patch. When a fragment is relocated to
another comp page, we could preempt the process after the fragment is
removed from the previous comp page, but before being added to the
next comp page. If this happens, a read operation is submitted to the
disk, likely to read bogus data or, if vswap is used, to reach a
kernel BUG. In order to solve, we add the new fragment to the hash
table before the old one is removed. So, if the process is preempted
before removing the old fragment, we have a fragment with its
data. This fragment is locked until get to a sane state, but it surely
avoids a read operation to be done. We think it's SMP-safe too, since
if a reference to the old fragment is get after the new fragment is
added to the hash table, the old fragment isn't freed and we remove
the new fragment from the hash table. If the new fragment is
referenced, it's the same behaviour that happens when the process is
preempted.
o Added spin_lock/spin_unlock to clean page adaptability to provide
concurrency control.
o Fixed bug that would allow to set more than 50% of the memory size
as the maximum size of compressed cache. For example, booting with
"mem=16M compsize=12M" would work. Simple fix.
o Fixed bug that would duplicate a real swap entry (for compressed
swap) even if the swap entry failed to duplicate.
o Although unlikely, nothing prevents a swap entry to be freed while
being written out by a swap buffer. Now we, besides the reference on
the fragment, we hold a reference on the swap entry when writing out a
page.
Index: swap_state.c
===================================================================
RCS file: /cvsroot/linuxcompressed/linux/mm/swap_state.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -C2 -r1.41 -r1.42
*** swap_state.c 29 Nov 2002 21:23:02 -0000 1.41
--- swap_state.c 6 Dec 2002 19:29:21 -0000 1.42
***************
*** 215,218 ****
--- 215,219 ----
}
+ /* racy - have to fix */
if (readahead) {
found_page = find_get_page(&swapper_space, entry.val);
***************
*** 234,237 ****
--- 235,239 ----
err = add_to_swap_cache(new_page, entry);
if (!err) {
+ /* racy - have to fix */
if (!readahead) {
if (!read_comp_cache(&swapper_space, entry.val, new_page)) {
Index: swapfile.c
===================================================================
RCS file: /cvsroot/linuxcompressed/linux/mm/swapfile.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -C2 -r1.37 -r1.38
*** swapfile.c 29 Nov 2002 21:23:02 -0000 1.37
--- swapfile.c 6 Dec 2002 19:29:21 -0000 1.38
***************
*** 810,813 ****
--- 810,815 ----
atomic_inc(&init_mm.mm_users);
+ sync_all_swp_buffers();
+
/*
* Keep on scanning until all entries have gone. Usually,
***************
*** 1516,1527 ****
result = 1;
}
- }
#ifdef CONFIG_COMP_SWAP
! if (p->real_swap[offset]) {
! swp_entry_t real_entry;
! real_entry.val = p->real_swap[offset];
! real_swap_duplicate(real_entry, 1);
}
- #endif
swap_device_unlock(p);
out:
--- 1518,1529 ----
result = 1;
}
#ifdef CONFIG_COMP_SWAP
! if (p->real_swap[offset]) {
! swp_entry_t real_entry;
! real_entry.val = p->real_swap[offset];
! real_swap_duplicate(real_entry, 1);
! }
! #endif
}
swap_device_unlock(p);
out:
|