[lc-checkins] CVS: linux/mm swap_state.c,1.41,1.42 swapfile.c,1.37,1.38
Status: Beta
Brought to you by:
nitin_sf
From: Rodrigo S. de C. <rc...@us...> - 2002-12-06 22:50:35
|
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: |