[lc-checkins] CVS: linux/mm/comp_cache free.c,1.44,1.45 main.c,1.60,1.61 swapin.c,1.49,1.50 swapout.
Status: Beta
Brought to you by:
nitin_sf
From: Rodrigo S. de C. <rc...@us...> - 2002-07-31 12:31:08
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv23025/mm/comp_cache Modified Files: free.c main.c swapin.c swapout.c Log Message: Bug fixes o Fixed "kernel BUG at inode.c:518". That bug happened when, after truncating all the pages from an inode, there are still pending pages in that mapping. That scenario could occur if a certain fragment happens to waiting to lock its comp_page in order to be effectively freed. In this case, the fragment got removed from comp cache data structures, but not from the mapping data structures while waiting for its fragment->comp_page lock, so it was taken as being in the mapping (well, as a clean mapped page actually) in spite of having a zero counter. That was fixed by removing the fragment from the mapping structures too. o Fixed "oops in ext2_check_page()" bug. That bug could happen because a page, after being compressed in compress_clean_page(), could be removed from page cache (in shrink_cache()) even if it is not freeable (!is_page_cache_freeable()). So, ext2_check_page(), which assumes that the page wouldn't be removed since it has a reference on the page, accesses directly the page->mapping pointer and oopses, because that pointer is set to NULL after removing from page cache. The fix was very simple. We check, with the pagecache lock held, if the page is freeable after compressing it. In this case, it is not removed from page cache and is kept on the inactive list. Cleanup o Cleanup in lookup_comp_pages() o find_and_dirty_page() renamed to find_or_add_page() o __find_lock_page() does not read pages from comp cache if the page is not found in page cache. Index: free.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/free.c,v retrieving revision 1.44 retrieving revision 1.45 diff -C2 -r1.44 -r1.45 *** free.c 28 Jul 2002 15:47:04 -0000 1.44 --- free.c 31 Jul 2002 12:31:05 -0000 1.45 *************** *** 2,6 **** * linux/mm/comp_cache/free.c * ! * Time-stamp: <2002-07-28 10:21:04 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/free.c * ! * Time-stamp: <2002-07-29 10:04:24 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 72,79 **** } - /* remove from mapping->{clean,dirty}_comp_pages */ - list_del_init(&fragment->mapping_list); - fragment->mapping->nrpages--; - /* compressed fragments of swap cache are accounted in * swapper_space.nrpages, so we need to account them --- 72,75 ---- *************** *** 234,237 **** --- 230,239 ---- if (!fragment) BUG(); + + /* remove from mapping->{clean,dirty}_comp_pages */ + spin_lock(&pagecache_lock); + list_del_init(&fragment->mapping_list); + fragment->mapping->nrpages--; + spin_unlock(&pagecache_lock); remove_fragment_vswap(fragment); Index: main.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/main.c,v retrieving revision 1.60 retrieving revision 1.61 diff -C2 -r1.60 -r1.61 *** main.c 28 Jul 2002 15:47:04 -0000 1.60 --- main.c 31 Jul 2002 12:31:05 -0000 1.61 *************** *** 2,6 **** * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-07-28 10:04:28 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-07-29 09:31:05 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 74,78 **** } - comp_size = compress(current_compressed_page = page, buffer_compressed = (unsigned long *) &buffer_compressed1, &algorithm, state); comp_page = get_comp_cache_page(page, comp_size, &fragment, gfp_mask, priority); --- 74,77 ---- Index: swapin.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapin.c,v retrieving revision 1.49 retrieving revision 1.50 diff -C2 -r1.49 -r1.50 *** swapin.c 28 Jul 2002 20:48:32 -0000 1.49 --- swapin.c 31 Jul 2002 12:31:05 -0000 1.50 *************** *** 2,6 **** * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-28 17:34:57 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-30 12:21:21 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 141,146 **** #ifdef CONFIG_COMP_PAGE_CACHE - extern struct page * find_and_dirty_page(struct page * new_page, struct address_space *mapping, unsigned long offset, struct page **hash); - static void truncate_list_comp_pages(struct list_head * list, unsigned long start, unsigned partial) --- 141,144 ---- *************** *** 193,210 **** } /* caller must hold pagecache_lock */ void lookup_comp_pages(struct address_space * mapping) { ! struct page **hash; ! struct page * page; struct comp_cache_fragment * fragment; - spin_lock(&comp_cache_lock); - - if (list_empty(&mapping->dirty_comp_pages)) - goto out_unlock; - - spin_unlock(&pagecache_lock); /*** * This function may be called from the following code path: --- 191,203 ---- } + extern struct page * find_or_add_page(struct page * new_page, struct address_space *mapping, unsigned long offset); + /* caller must hold pagecache_lock */ void lookup_comp_pages(struct address_space * mapping) { ! struct page * page, * old_page; struct comp_cache_fragment * fragment; /*** * This function may be called from the following code path: *************** *** 229,235 **** * That's why the page must be allocated with GFP_NOFS mask. */ page = alloc_page(GFP_NOFS); if (!page) ! goto out_unlock; spin_lock(&pagecache_lock); --- 222,229 ---- * That's why the page must be allocated with GFP_NOFS mask. */ + spin_unlock(&pagecache_lock); page = alloc_page(GFP_NOFS); if (!page) ! return; spin_lock(&pagecache_lock); *************** *** 239,264 **** } fragment = list_entry(mapping->dirty_comp_pages.next, struct comp_cache_fragment, mapping_list); - hash = page_hash(mapping, fragment->index); - if (!CompFragmentTestandClearDirty(fragment)) - BUG(); - list_del(&fragment->mapping_list); ! list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); ! ! /* Checks if the page has been added to the page cache and add ! * this new page to the cache if the former condition is ! * false. Dirty the page in the page cache otherwise. */ ! if (find_and_dirty_page(page, mapping, fragment->index, hash)) ! goto out_release; ! get_fragment(fragment); spin_unlock(&comp_cache_lock); lock_page(fragment->comp_page->page); - decompress_fragment(fragment, page); - UnlockPage(fragment->comp_page->page); spin_lock(&comp_cache_lock); put_fragment(fragment); --- 233,262 ---- } + spin_lock(&comp_cache_lock); + fragment = list_entry(mapping->dirty_comp_pages.next, struct comp_cache_fragment, mapping_list); list_del(&fragment->mapping_list); ! list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); ! get_fragment(fragment); spin_unlock(&comp_cache_lock); + spin_unlock(&pagecache_lock); lock_page(fragment->comp_page->page); + /* Checks if the page has been added to the page cache in the + * meanwhile and dirty the page in this case. Otherwise, add + * the new page to the page cache. */ + old_page = find_or_add_page(page, mapping, fragment->index); + if (!old_page) { + decompress_fragment(fragment, page); + goto free_and_dirty; + } + page_cache_release(page); + page = old_page; + + free_and_dirty: + UnlockPage(fragment->comp_page->page); spin_lock(&comp_cache_lock); put_fragment(fragment); *************** *** 266,278 **** /* effectively free it */ drop_fragment(fragment); PageClearCompCache(page); ! __set_page_dirty(page); UnlockPage(page); - out_release: page_cache_release(page); - out_unlock: - spin_unlock(&comp_cache_lock); } #endif --- 264,274 ---- /* effectively free it */ drop_fragment(fragment); + spin_unlock(&comp_cache_lock); PageClearCompCache(page); ! __set_page_dirty(page); UnlockPage(page); out_release: page_cache_release(page); } #endif Index: swapout.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapout.c,v retrieving revision 1.66 retrieving revision 1.67 diff -C2 -r1.66 -r1.67 *** swapout.c 28 Jul 2002 15:47:04 -0000 1.66 --- swapout.c 31 Jul 2002 12:31:05 -0000 1.67 *************** *** 2,6 **** * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-28 11:33:53 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-29 17:18:46 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 427,430 **** --- 427,432 ---- } + /* that's going to be rechecked in shrink_cache() with + * pagecache lock held */ if (page_count(page) - !!page->buffers == 3) continue; *************** *** 460,464 **** check_references: ! /* 3 = shrink_cache() + page cache + us */ if (page_count(page) - !!page->buffers != 3) goto failed; --- 462,467 ---- check_references: ! /* 3 = shrink_cache() + page cache + us. That's going to be ! * rechecked in shrink_cache() with pagecache lock held */ if (page_count(page) - !!page->buffers != 3) goto failed; |