linuxcompressed-checkins Mailing List for Linux Compressed Cache (Page 4)
Status: Beta
Brought to you by:
nitin_sf
You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(2) |
Nov
|
Dec
(31) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(28) |
Feb
(50) |
Mar
(29) |
Apr
(6) |
May
(33) |
Jun
(36) |
Jul
(60) |
Aug
(7) |
Sep
(12) |
Oct
|
Nov
(13) |
Dec
(3) |
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(9) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2006 |
Jan
(13) |
Feb
(4) |
Mar
(4) |
Apr
(1) |
May
|
Jun
(22) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Rodrigo S. de C. <rc...@us...> - 2002-09-10 16:44:01
|
Update of /cvsroot/linuxcompressed/linux/Documentation In directory usw-pr-cvs1:/tmp/cvs-serv17835/Documentation Modified Files: Configure.help Log Message: New features o Adaptivity: the greatest feature of the changeset is the adaptivity implementation. Now compressed cache resizes by itself and it seems to be picking the a size pretty close to the best size noticed in our tests. The police can be described as follow. Instead of having an LRU queue, we have now two queues: active and inactive, like the LRU queues in vanilla. The active list has the pages that would be in memory if the compressed cache is not used and the inactive list is the gain from using the compressed cache. If there are many accesses to the active list, we first block growing (by demand) and later shrink the compressed cache, and if we have many accesses to the inactive list, we let the cache grow if needed. The active list size is computed based on the effective compression ratio (number of fragments/number of memory pages). When shrinking the cache, we try to free a compressed cache by moving its fragments to other places. If unable to free a page that way, we free a fragment at the end of inactive list. o Compressed swap: now all swap cache pages are swapped out in compressed format. A bit in swap_map array is used to know if the entry is compressed or not. The compressed size is stored in the entry on the disk. There is almost no cost to store the pages in compressed format, that's why it is the default configuration for compressed cache. o Compacted swap: besides swapping out the pages in compressed format, we may decrease the number of writeouts by writing many fragments to the same disk block. Since it has a memory cost to store some metadata, it is an option to be enabled by user. It uses two arrays, real_swap (unsigned long array) and real_swap_map (unsigned short array). All the metadata about the fragments in the disk block are stored on the block, like offset, size, index. o Clean fragments not decompressed when they would be used to write some data. We don't decompress a clean fragment when grabbing a page cache page in __grab_cache_page() any longer. We would decompress a fragment, but it's data wouldn't be used (that's why this __grab_cache_page() creates a page if not found in page cache). Dirty fragments will be decompressed, but that's a rare situation in page cache since most data are written via buffers. Bug fixes o Larger compressed cache page support would not support pages larger than 2*PAGE_SIZE (8K). Reason: wrong computation of comp page size, very simple to fix. o In /proc/comp_cache_hist, we were showing the number of fragments in a comp page, no matter if those fragments were freed. It has been fixed to not show the freed fragments. o Writing out every dirty page with buffers. That was a conceptual bug, since all the swapped in pages would have bugs, and if they got dirty, they would not be added to compressed cache as dirty, they would be written out first and only then added to swap cache as a clean page. Now we try to free the buffers and if we are unable to do that, we write it out. With this bug, the page was added to compressed cache, but we were forcing many writes. Other: o Removed support to change algorithms online. That was a not very used option and would introduce a space cost to pages swapped out in compressed format, so it was removed. It also saved some memory space, since we allocate only the data structure used by the selected algorithm. Recall that the algorithm can be set through the compalg= kernel parameter. o All entries in /proc/sys/vm/comp_cache removed. Since compression algorithms cannot be changed nor compressed cache size, so it's useless to have a directory in /proc/sys. Compressed cache size can still be checked in /proc/meminfo. o Info for compression algorithm is shown even if no page has been compressed. o There are many code blocks with "#if 0" that are/were being tested. Cleanups: o Code to add the fragment into a comp page fragment list was split to a new function. o decompress() function removed. Index: Configure.help =================================================================== RCS file: /cvsroot/linuxcompressed/linux/Documentation/Configure.help,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -r1.10 -r1.11 *** Configure.help 28 Jul 2002 15:58:23 -0000 1.10 --- Configure.help 10 Sep 2002 16:42:54 -0000 1.11 *************** *** 413,422 **** 8KiB instead of the regular 4KiB. ! Note that with double pages, all the values showed in compressed ! initialization info (in boot process) and in ! /proc/sys/vm/comp_cache/{actual_size,size} entries are in functions ! of those pages and not in function of memory pages. If unsure, say Y here. Normal floppy disk support --- 413,429 ---- 8KiB instead of the regular 4KiB. ! The size of the compressed cache page is listed in the output of ! /proc/comp_cache_stat. If unsure, say Y here. + + Compressed Swap + CONFIG_COMP_SWAP + + Compressed cache swaps out its fragments (i.e, compressed memory + pages) in compressed format. If you also want it to swap out them + clustered to the disk, in order to reduce the writeout traffic, say + Y here. Note that this option adds some data structures that will + cost some memory, so if you don't have much, you'd better say N. Normal floppy disk support |
From: Rodrigo S. de C. <rc...@us...> - 2002-09-10 16:43:54
|
Update of /cvsroot/linuxcompressed/linux/mm In directory usw-pr-cvs1:/tmp/cvs-serv17835/mm Modified Files: filemap.c memory.c page_alloc.c shmem.c swap_state.c swapfile.c Added Files: page_io.c Log Message: New features o Adaptivity: the greatest feature of the changeset is the adaptivity implementation. Now compressed cache resizes by itself and it seems to be picking the a size pretty close to the best size noticed in our tests. The police can be described as follow. Instead of having an LRU queue, we have now two queues: active and inactive, like the LRU queues in vanilla. The active list has the pages that would be in memory if the compressed cache is not used and the inactive list is the gain from using the compressed cache. If there are many accesses to the active list, we first block growing (by demand) and later shrink the compressed cache, and if we have many accesses to the inactive list, we let the cache grow if needed. The active list size is computed based on the effective compression ratio (number of fragments/number of memory pages). When shrinking the cache, we try to free a compressed cache by moving its fragments to other places. If unable to free a page that way, we free a fragment at the end of inactive list. o Compressed swap: now all swap cache pages are swapped out in compressed format. A bit in swap_map array is used to know if the entry is compressed or not. The compressed size is stored in the entry on the disk. There is almost no cost to store the pages in compressed format, that's why it is the default configuration for compressed cache. o Compacted swap: besides swapping out the pages in compressed format, we may decrease the number of writeouts by writing many fragments to the same disk block. Since it has a memory cost to store some metadata, it is an option to be enabled by user. It uses two arrays, real_swap (unsigned long array) and real_swap_map (unsigned short array). All the metadata about the fragments in the disk block are stored on the block, like offset, size, index. o Clean fragments not decompressed when they would be used to write some data. We don't decompress a clean fragment when grabbing a page cache page in __grab_cache_page() any longer. We would decompress a fragment, but it's data wouldn't be used (that's why this __grab_cache_page() creates a page if not found in page cache). Dirty fragments will be decompressed, but that's a rare situation in page cache since most data are written via buffers. Bug fixes o Larger compressed cache page support would not support pages larger than 2*PAGE_SIZE (8K). Reason: wrong computation of comp page size, very simple to fix. o In /proc/comp_cache_hist, we were showing the number of fragments in a comp page, no matter if those fragments were freed. It has been fixed to not show the freed fragments. o Writing out every dirty page with buffers. That was a conceptual bug, since all the swapped in pages would have bugs, and if they got dirty, they would not be added to compressed cache as dirty, they would be written out first and only then added to swap cache as a clean page. Now we try to free the buffers and if we are unable to do that, we write it out. With this bug, the page was added to compressed cache, but we were forcing many writes. Other: o Removed support to change algorithms online. That was a not very used option and would introduce a space cost to pages swapped out in compressed format, so it was removed. It also saved some memory space, since we allocate only the data structure used by the selected algorithm. Recall that the algorithm can be set through the compalg= kernel parameter. o All entries in /proc/sys/vm/comp_cache removed. Since compression algorithms cannot be changed nor compressed cache size, so it's useless to have a directory in /proc/sys. Compressed cache size can still be checked in /proc/meminfo. o Info for compression algorithm is shown even if no page has been compressed. o There are many code blocks with "#if 0" that are/were being tested. Cleanups: o Code to add the fragment into a comp page fragment list was split to a new function. o decompress() function removed. Index: filemap.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/filemap.c,v retrieving revision 1.39 retrieving revision 1.40 diff -C2 -r1.39 -r1.40 *** filemap.c 1 Aug 2002 14:52:25 -0000 1.39 --- filemap.c 10 Sep 2002 16:43:12 -0000 1.40 *************** *** 2907,2911 **** #endif err = filler(data, page); - if (err < 0) { page_cache_release(page); --- 2907,2910 ---- *************** *** 2978,2982 **** *cached_page = NULL; #ifdef CONFIG_COMP_PAGE_CACHE ! read_comp_cache(mapping, index, page); #endif } --- 2977,2981 ---- *cached_page = NULL; #ifdef CONFIG_COMP_PAGE_CACHE ! read_dirty_comp_cache(mapping, index, page); #endif } Index: memory.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/memory.c,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -r1.35 -r1.36 *** memory.c 18 Jul 2002 13:32:50 -0000 1.35 --- memory.c 10 Sep 2002 16:43:12 -0000 1.36 *************** *** 1177,1181 **** /* The page isn't present yet, go ahead with the fault. */ ! swap_free(entry); if (vm_swap_full()) --- 1177,1182 ---- /* The page isn't present yet, go ahead with the fault. */ ! if (PageCompressed(page)) ! decompress_swap_cache_page(page); swap_free(entry); if (vm_swap_full()) Index: page_alloc.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/page_alloc.c,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -r1.23 -r1.24 *** page_alloc.c 16 Jul 2002 18:41:55 -0000 1.23 --- page_alloc.c 10 Sep 2002 16:43:14 -0000 1.24 *************** *** 98,102 **** if (PageActive(page)) BUG(); ! page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty) | (1<<PG_comp_cache)); if (current->flags & PF_FREE_PAGES) --- 98,102 ---- if (PageActive(page)) BUG(); ! page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty) | (1<<PG_comp_cache) | (1<<PG_compressed)); if (current->flags & PF_FREE_PAGES) Index: shmem.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/shmem.c,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -r1.21 -r1.22 *** shmem.c 5 Jul 2002 15:21:50 -0000 1.21 --- shmem.c 10 Sep 2002 16:43:16 -0000 1.22 *************** *** 386,389 **** --- 386,391 ---- return 0; found: + if (PageCompressed(page)) + decompress_swap_cache_page(page); delete_from_swap_cache(page); add_to_page_cache(page, info->inode->i_mapping, offset + idx); *************** *** 558,561 **** --- 560,565 ---- swap_free(*entry); *entry = (swp_entry_t) {0}; + if (PageCompressed(page)) + decompress_swap_cache_page(page); delete_from_swap_cache(page); flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1)); Index: swap_state.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/swap_state.c,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -r1.38 -r1.39 *** swap_state.c 28 Jul 2002 15:47:04 -0000 1.38 --- swap_state.c 10 Sep 2002 16:43:16 -0000 1.39 *************** *** 242,246 **** if (vswap_address(entry)) BUG(); ! rw_swap_page(READ, new_page); return new_page; --- 242,247 ---- if (vswap_address(entry)) BUG(); ! if (get_swap_compressed(entry)) ! PageSetCompressed(new_page); rw_swap_page(READ, new_page); return new_page; Index: swapfile.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/swapfile.c,v retrieving revision 1.34 retrieving revision 1.35 diff -C2 -r1.34 -r1.35 *** swapfile.c 18 Jul 2002 21:31:08 -0000 1.34 --- swapfile.c 10 Sep 2002 16:43:17 -0000 1.35 *************** *** 206,209 **** --- 206,424 ---- } + #ifdef CONFIG_COMP_SWAP + void + real_swap_free(swp_entry_t entry, int count) + { + struct swap_info_struct * p; + unsigned long type, offset = SWP_OFFSET(entry); + + type = SWP_TYPE(entry); + p = type + swap_info; + + if (!p->real_swap_map[offset]) + BUG(); + + if (p->real_swap_map[offset] < COMP_SWAP_MAP_MAX) { + p->real_swap_map[offset] -= count; + if (!p->real_swap_map[offset]) { + if (offset < p->real_lowest_bit) + p->real_lowest_bit = offset; + if (offset > p->real_highest_bit) + p->real_highest_bit = offset; + } + } + } + + void + real_swap_duplicate(swp_entry_t entry, int count) + { + struct swap_info_struct * p; + unsigned long offset, type; + + type = SWP_TYPE(entry); + p = type + swap_info; + offset = SWP_OFFSET(entry); + + if (!p->real_swap_map[offset]) + BUG(); + if (count >= COMP_SWAP_MAP_MAX) + BUG(); + + if (p->real_swap_map[offset] < COMP_SWAP_MAP_MAX - count) + p->real_swap_map[offset] += count; + else if (p->real_swap_map[offset] <= COMP_SWAP_MAP_MAX) + p->real_swap_map[offset] = COMP_SWAP_MAP_MAX; + } + + swp_entry_t + get_real_swap_page(swp_entry_t entry) + { + unsigned long offset, real_offset; + struct swap_info_struct * p; + swp_entry_t real_entry; + + offset = SWP_OFFSET(entry); + + p = swap_info_get(entry); + + if (!p) + BUG(); + + if (p->real_cluster_nr) { + while (p->real_cluster_next <= p->real_highest_bit) { + real_offset = p->real_cluster_next++; + if (p->real_swap_map[real_offset]) + continue; + p->real_cluster_nr--; + goto got_page; + } + } + p->real_cluster_nr = SWAPFILE_CLUSTER; + + /* try to find an empty (even not aligned) cluster. */ + real_offset = p->real_lowest_bit; + check_next_cluster: + if (real_offset+SWAPFILE_CLUSTER-1 <= p->real_highest_bit) + { + int nr; + for (nr = real_offset; nr < real_offset+SWAPFILE_CLUSTER; nr++) + if (p->real_swap_map[nr]) + { + real_offset = nr+1; + goto check_next_cluster; + } + /* We found a completly empty cluster, so start + * using it. + */ + goto got_page; + } + /* No luck, so now go finegrined as usual. -Andrea */ + for (real_offset = p->real_lowest_bit; real_offset <= p->real_highest_bit ; real_offset++) { + if (p->real_swap_map[real_offset]) + continue; + p->real_lowest_bit = real_offset+1; + got_page: + if (real_offset == p->real_lowest_bit) + p->real_lowest_bit++; + if (real_offset == p->real_highest_bit) + p->real_highest_bit--; + if (p->real_lowest_bit > p->real_highest_bit) { + p->real_lowest_bit = p->max; + p->real_highest_bit = 0; + } + real_entry.val = p->real_swap[offset]; + if (real_entry.val) + real_swap_free(real_entry, swap_map_count(p->swap_map[offset])); + real_entry = SWP_ENTRY(SWP_TYPE(entry), real_offset); + p->real_swap[offset] = real_entry.val; + p->real_swap_map[real_offset] = swap_map_count(p->swap_map[offset]); + p->real_cluster_next = real_offset+1; + swap_info_put(p); + return real_entry; + } + p->real_lowest_bit = p->max; + p->real_highest_bit = 0; + swap_info_put(p); + real_entry.val = 0; + return real_entry; + } + + swp_entry_t + get_map(swp_entry_t entry) + { + struct swap_info_struct * p; + unsigned long offset; + swp_entry_t real_entry; + + p = swap_info_get(entry); + + if (!p) + BUG(); + + offset = SWP_OFFSET(entry); + if (offset >= p->max) + BUG(); + real_entry.val = p->real_swap[offset]; + + if (!real_entry.val) + BUG(); + swap_info_put(p); + + return real_entry; + } + + void + map_swap(swp_entry_t entry, swp_entry_t real_entry) + { + struct swap_info_struct * p; + unsigned long offset; + swp_entry_t old_entry; + + p = swap_info_get(entry); + + if (!p) + BUG(); + + offset = SWP_OFFSET(entry); + if (offset >= p->max) + BUG(); + old_entry.val = p->real_swap[offset]; + if (old_entry.val) + real_swap_free(old_entry, swap_map_count(p->swap_map[offset])); + + p->real_swap[offset] = real_entry.val; + + real_swap_duplicate(real_entry, swap_map_count(p->swap_map[offset])); + swap_info_put(p); + } + #endif + + #ifdef CONFIG_COMP_CACHE + void + set_swap_compressed(swp_entry_t entry, int compressed) + { + struct swap_info_struct * p; + unsigned long offset; + + p = swap_info_get(entry); + + if (!p) + BUG(); + + offset = SWP_OFFSET(entry); + if (offset >= p->max) + BUG(); + if (compressed) + p->swap_map[offset] |= SWAP_MAP_COMP_BIT; + else + p->swap_map[offset] &= SWAP_MAP_COMP_BIT_MASK; + + swap_info_put(p); + } + + int + get_swap_compressed(swp_entry_t entry) + { + struct swap_info_struct * p; + unsigned long offset; + int ret = 0; + + p = swap_info_get(entry); + + if (!p) + BUG(); + + offset = SWP_OFFSET(entry); + if (offset >= p->max) + BUG(); + if (p->swap_map[offset] & SWAP_MAP_COMP_BIT) + ret = 1; + swap_info_put(p); + + return ret; + } + + #endif + static int swap_entry_free(struct swap_info_struct *p, unsigned long offset) { *************** *** 215,221 **** count = p->swap_map[offset]; ! if (count < SWAP_MAP_MAX) { count--; ! if (!count) { entry = SWP_ENTRY(p - swap_info, offset); invalidate_comp_cache(&swapper_space, entry.val); --- 430,447 ---- count = p->swap_map[offset]; ! if (swap_map_count(count) < SWAP_MAP_MAX) { count--; ! #ifdef CONFIG_COMP_SWAP ! if (p->real_swap[offset]) { ! swp_entry_t real_entry; ! real_entry.val = p->real_swap[offset]; ! real_swap_free(real_entry, 1); ! } ! #endif ! if (!swap_map_count(count)) { ! #ifdef CONFIG_COMP_SWAP ! if (p->real_swap[offset]) ! p->real_swap[offset] = 0; ! #endif entry = SWP_ENTRY(p - swap_info, offset); invalidate_comp_cache(&swapper_space, entry.val); *************** *** 225,234 **** p->highest_bit = offset; nr_swap_pages++; ! count = p->swap_map[offset]; ! count--; } ! p->swap_map[offset] = count; } ! return count; } --- 451,459 ---- p->highest_bit = offset; nr_swap_pages++; ! count = 0; } ! p->swap_map[offset] = count; } ! return swap_map_count(count); } *************** *** 268,272 **** goto check_exclusive; } ! if (p->swap_map[SWP_OFFSET(entry)] == 1) exclusive = 1; check_exclusive: --- 493,497 ---- goto check_exclusive; } ! if (swap_map_count(p->swap_map[SWP_OFFSET(entry)]) == 1) exclusive = 1; check_exclusive: *************** *** 345,349 **** goto check_exclusive; } ! if (p->swap_map[SWP_OFFSET(entry)] == 1) exclusive = 1; check_exclusive: --- 570,574 ---- goto check_exclusive; } ! if (swap_map_count(p->swap_map[SWP_OFFSET(entry)]) == 1) exclusive = 1; check_exclusive: *************** *** 353,356 **** --- 578,583 ---- if (page_count(page) - !!page->buffers == 2) { __delete_from_swap_cache(page); + if (PageCompressed(page)) + decompress_swap_cache_page(page); SetPageDirty(page); retval = 1; *************** *** 542,546 **** i = 1; } ! count = si->swap_map[i]; if (count && count != SWAP_MAP_BAD) break; --- 769,773 ---- i = 1; } ! count = swap_map_count(si->swap_map[i]); if (count && count != SWAP_MAP_BAD) break; *************** *** 643,647 **** * to search, but use it as a reminder to search shmem. */ ! swcount = *swap_map; if (swcount > 1) { flush_page_to_ram(page); --- 870,874 ---- * to search, but use it as a reminder to search shmem. */ ! swcount = swap_map_count(*swap_map); if (swcount > 1) { flush_page_to_ram(page); *************** *** 651,656 **** unuse_process(start_mm, entry, page); } ! if (*swap_map > 1) { ! int set_start_mm = (*swap_map >= swcount); struct list_head *p = &start_mm->mmlist; struct mm_struct *new_start_mm = start_mm; --- 878,883 ---- unuse_process(start_mm, entry, page); } ! if (swap_map_count(*swap_map) > 1) { ! int set_start_mm = (swap_map_count(*swap_map) >= swcount); struct list_head *p = &start_mm->mmlist; struct mm_struct *new_start_mm = start_mm; *************** *** 658,665 **** spin_lock(&mmlist_lock); ! while (*swap_map > 1 && (p = p->next) != &start_mm->mmlist) { mm = list_entry(p, struct mm_struct, mmlist); ! swcount = *swap_map; if (mm == &init_mm) { set_start_mm = 1; --- 885,892 ---- spin_lock(&mmlist_lock); ! while (swap_map_count(*swap_map) > 1 && (p = p->next) != &start_mm->mmlist) { mm = list_entry(p, struct mm_struct, mmlist); ! swcount = swap_map_count(*swap_map); if (mm == &init_mm) { set_start_mm = 1; *************** *** 667,671 **** } else unuse_process(mm, entry, page); ! if (set_start_mm && *swap_map < swcount) { new_start_mm = mm; set_start_mm = 0; --- 894,898 ---- } else unuse_process(mm, entry, page); ! if (set_start_mm && swap_map_count(*swap_map) < swcount) { new_start_mm = mm; set_start_mm = 0; *************** *** 691,699 **** * report them; but do report if we reset SWAP_MAP_MAX. */ ! if (*swap_map == SWAP_MAP_MAX) { swap_list_lock(); swap_device_lock(si); nr_swap_pages++; ! *swap_map = 1; swap_device_unlock(si); swap_list_unlock(); --- 918,926 ---- * report them; but do report if we reset SWAP_MAP_MAX. */ ! if (swap_map_count(*swap_map) == SWAP_MAP_MAX) { swap_list_lock(); swap_device_lock(si); nr_swap_pages++; ! *swap_map = 1 | (*swap_map & SWAP_MAP_COMP_BIT); swap_device_unlock(si); swap_list_unlock(); *************** *** 715,719 **** * Note shmem_unuse already deleted its from swap cache. */ ! swcount = *swap_map; if ((swcount > 0) != PageSwapCache(page)) BUG(); --- 942,946 ---- * Note shmem_unuse already deleted its from swap cache. */ ! swcount = swap_map_count(*swap_map); if ((swcount > 0) != PageSwapCache(page)) BUG(); *************** *** 722,725 **** --- 949,954 ---- lock_page(page); } + if (PageCompressed(page)) + decompress_swap_cache_page(page); if (PageSwapCache(page)) delete_from_swap_cache(page); *************** *** 758,761 **** --- 987,994 ---- int i, type, prev; int err; + #ifdef CONFIG_COMP_SWAP + unsigned long * real_swap; + unsigned short * real_swap_map; + #endif if (!capable(CAP_SYS_ADMIN)) *************** *** 830,837 **** --- 1063,1080 ---- swap_map = p->swap_map; p->swap_map = NULL; + #ifdef CONFIG_COMP_SWAP + real_swap = p->real_swap; + p->real_swap = NULL; + real_swap_map = p->real_swap_map; + p->real_swap_map = NULL; + #endif p->flags = 0; swap_device_unlock(p); swap_list_unlock(); vfree(swap_map); + #ifdef CONFIG_COMP_SWAP + vfree(real_swap); + vfree(real_swap_map); + #endif err = 0; *************** *** 867,871 **** usedswap = 0; for (j = 0; j < ptr->max; ++j) ! switch (ptr->swap_map[j]) { case SWAP_MAP_BAD: case 0: --- 1110,1114 ---- usedswap = 0; for (j = 0; j < ptr->max; ++j) ! switch (swap_map_count(ptr->swap_map[j])) { case SWAP_MAP_BAD: case 0: *************** *** 915,918 **** --- 1158,1165 ---- struct block_device *bdev = NULL; unsigned short *swap_map; + #ifdef CONFIG_COMP_SWAP + unsigned long * real_swap; + unsigned short * real_swap_map; + #endif if (!capable(CAP_SYS_ADMIN)) *************** *** 939,942 **** --- 1186,1196 ---- p->highest_bit = 0; p->cluster_nr = 0; + #ifdef CONFIG_COMP_SWAP + p->real_swap = NULL; + p->real_swap_map = NULL; + p->real_lowest_bit = 0; + p->real_highest_bit = 0; + p->real_cluster_nr = 0; + #endif p->sdev_lock = SPIN_LOCK_UNLOCKED; p->next = -1; *************** *** 1039,1042 **** --- 1293,1308 ---- goto bad_swap; } + #ifdef CONFIG_COMP_SWAP + p->real_lowest_bit = p->lowest_bit; + p->real_highest_bit = p->highest_bit; + + p->real_swap = vmalloc(maxpages * sizeof(long)); + p->real_swap_map = vmalloc(maxpages * sizeof(short)); + if (!p->real_swap || !p->real_swap_map) { + error = -ENOMEM; + goto bad_swap; + } + memset(p->real_swap, 0, maxpages * sizeof(long)); + #endif for (i = 1 ; i < maxpages ; i++) { if (test_bit(i,(char *) swap_header)) *************** *** 1045,1048 **** --- 1311,1322 ---- p->swap_map[i] = SWAP_MAP_BAD; } + #ifdef CONFIG_COMP_SWAP + for (i = 1 ; i < maxpages ; i++) { + if (test_bit(i,(char *) swap_header)) + p->real_swap_map[i] = 0; + else + p->real_swap_map[i] = COMP_SWAP_MAP_BAD; + } + #endif break; *************** *** 1076,1085 **** error = 0; memset(p->swap_map, 0, maxpages * sizeof(short)); for (i=0; i<swap_header->info.nr_badpages; i++) { int page = swap_header->info.badpages[i]; if (page <= 0 || page >= swap_header->info.last_page) error = -EINVAL; ! else p->swap_map[page] = SWAP_MAP_BAD; } nr_good_pages = swap_header->info.last_page - --- 1350,1376 ---- error = 0; memset(p->swap_map, 0, maxpages * sizeof(short)); + #ifdef CONFIG_COMP_SWAP + p->real_lowest_bit = p->lowest_bit; + p->real_highest_bit = p->highest_bit; + + p->real_swap = vmalloc(maxpages * sizeof(long)); + p->real_swap_map = vmalloc(maxpages * sizeof(short)); + if (!p->real_swap || !p->real_swap_map) { + error = -ENOMEM; + goto bad_swap; + } + memset(p->real_swap, 0, maxpages * sizeof(long)); + memset(p->real_swap_map, 0, maxpages * sizeof(short)); + #endif for (i=0; i<swap_header->info.nr_badpages; i++) { int page = swap_header->info.badpages[i]; if (page <= 0 || page >= swap_header->info.last_page) error = -EINVAL; ! else { p->swap_map[page] = SWAP_MAP_BAD; + #ifdef CONFIG_COMP_SWAP + p->real_swap_map[page] = COMP_SWAP_MAP_BAD; + #endif + } } nr_good_pages = swap_header->info.last_page - *************** *** 1102,1105 **** --- 1393,1399 ---- } p->swap_map[0] = SWAP_MAP_BAD; + #ifdef CONFIG_COMP_SWAP + p->real_swap_map[0] = COMP_SWAP_MAP_BAD; + #endif swap_list_lock(); swap_device_lock(p); *************** *** 1136,1139 **** --- 1430,1437 ---- swap_list_lock(); swap_map = p->swap_map; + #ifdef CONFIG_COMP_SWAP + real_swap = p->real_swap; + real_swap_map = p->real_swap_map; + #endif nd.mnt = p->swap_vfsmnt; nd.dentry = p->swap_file; *************** *** 1148,1151 **** --- 1446,1455 ---- if (swap_map) vfree(swap_map); + #ifdef CONFIG_COMP_SWAP + if (real_swap) + vfree(real_swap); + if (real_swap_map) + vfree(real_swap_map); + #endif path_release(&nd); out: *************** *** 1167,1171 **** continue; for (j = 0; j < swap_info[i].max; ++j) { ! switch (swap_info[i].swap_map[j]) { case 0: case SWAP_MAP_BAD: --- 1471,1475 ---- continue; for (j = 0; j < swap_info[i].max; ++j) { ! switch (swap_map_count(swap_info[i].swap_map[j])) { case 0: case SWAP_MAP_BAD: *************** *** 1194,1198 **** if (vswap_address(entry)) ! goto virtual_swap; type = SWP_TYPE(entry); if (type >= nr_swapfiles) --- 1498,1502 ---- if (vswap_address(entry)) ! return virtual_swap_duplicate(entry); type = SWP_TYPE(entry); if (type >= nr_swapfiles) *************** *** 1203,1216 **** swap_device_lock(p); if (offset < p->max && p->swap_map[offset]) { ! if (p->swap_map[offset] < SWAP_MAP_MAX - 1) { p->swap_map[offset]++; result = 1; ! } else if (p->swap_map[offset] <= SWAP_MAP_MAX) { if (swap_overflow++ < 5) printk(KERN_WARNING "swap_dup: swap entry overflow\n"); ! p->swap_map[offset] = SWAP_MAP_MAX; result = 1; } } swap_device_unlock(p); out: --- 1507,1527 ---- swap_device_lock(p); if (offset < p->max && p->swap_map[offset]) { ! if (swap_map_count(p->swap_map[offset]) < SWAP_MAP_MAX - 1) { p->swap_map[offset]++; result = 1; ! } else if (swap_map_count(p->swap_map[offset]) <= SWAP_MAP_MAX) { if (swap_overflow++ < 5) printk(KERN_WARNING "swap_dup: swap entry overflow\n"); ! p->swap_map[offset] = SWAP_MAP_MAX | (p->swap_map[offset] & SWAP_MAP_COMP_BIT); 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: *************** *** 1220,1226 **** printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val); goto out; - - virtual_swap: - return virtual_swap_duplicate(entry); } --- 1531,1534 ---- *************** *** 1250,1254 **** if (!p->swap_map[offset]) goto bad_unused; ! retval = p->swap_map[offset]; out: return retval; --- 1558,1562 ---- if (!p->swap_map[offset]) goto bad_unused; ! retval = swap_map_count(p->swap_map[offset]); out: return retval; *************** *** 1291,1295 **** --- 1599,1607 ---- return; } + #ifdef CONFIG_COMP_SWAP + if (p->real_swap_map && !p->real_swap_map[*offset]) { + #else if (p->swap_map && !p->swap_map[*offset]) { + #endif printk(KERN_ERR "rw_swap_page: %s%08lx\n", Unused_offset, entry.val); return; *************** *** 1335,1339 **** if (!swapdev->swap_map[toff]) break; ! if (swapdev->swap_map[toff] == SWAP_MAP_BAD) break; toff++; --- 1647,1651 ---- if (!swapdev->swap_map[toff]) break; ! if (swap_map_count(swapdev->swap_map[toff]) == SWAP_MAP_BAD) break; toff++; *************** *** 1343,1344 **** --- 1655,1657 ---- return ret; } + |
From: Rodrigo S. de C. <rc...@us...> - 2002-09-10 16:43:41
|
Update of /cvsroot/linuxcompressed/linux/include/linux In directory usw-pr-cvs1:/tmp/cvs-serv17835/include/linux Modified Files: comp_cache.h mm.h swap.h Log Message: New features o Adaptivity: the greatest feature of the changeset is the adaptivity implementation. Now compressed cache resizes by itself and it seems to be picking the a size pretty close to the best size noticed in our tests. The police can be described as follow. Instead of having an LRU queue, we have now two queues: active and inactive, like the LRU queues in vanilla. The active list has the pages that would be in memory if the compressed cache is not used and the inactive list is the gain from using the compressed cache. If there are many accesses to the active list, we first block growing (by demand) and later shrink the compressed cache, and if we have many accesses to the inactive list, we let the cache grow if needed. The active list size is computed based on the effective compression ratio (number of fragments/number of memory pages). When shrinking the cache, we try to free a compressed cache by moving its fragments to other places. If unable to free a page that way, we free a fragment at the end of inactive list. o Compressed swap: now all swap cache pages are swapped out in compressed format. A bit in swap_map array is used to know if the entry is compressed or not. The compressed size is stored in the entry on the disk. There is almost no cost to store the pages in compressed format, that's why it is the default configuration for compressed cache. o Compacted swap: besides swapping out the pages in compressed format, we may decrease the number of writeouts by writing many fragments to the same disk block. Since it has a memory cost to store some metadata, it is an option to be enabled by user. It uses two arrays, real_swap (unsigned long array) and real_swap_map (unsigned short array). All the metadata about the fragments in the disk block are stored on the block, like offset, size, index. o Clean fragments not decompressed when they would be used to write some data. We don't decompress a clean fragment when grabbing a page cache page in __grab_cache_page() any longer. We would decompress a fragment, but it's data wouldn't be used (that's why this __grab_cache_page() creates a page if not found in page cache). Dirty fragments will be decompressed, but that's a rare situation in page cache since most data are written via buffers. Bug fixes o Larger compressed cache page support would not support pages larger than 2*PAGE_SIZE (8K). Reason: wrong computation of comp page size, very simple to fix. o In /proc/comp_cache_hist, we were showing the number of fragments in a comp page, no matter if those fragments were freed. It has been fixed to not show the freed fragments. o Writing out every dirty page with buffers. That was a conceptual bug, since all the swapped in pages would have bugs, and if they got dirty, they would not be added to compressed cache as dirty, they would be written out first and only then added to swap cache as a clean page. Now we try to free the buffers and if we are unable to do that, we write it out. With this bug, the page was added to compressed cache, but we were forcing many writes. Other: o Removed support to change algorithms online. That was a not very used option and would introduce a space cost to pages swapped out in compressed format, so it was removed. It also saved some memory space, since we allocate only the data structure used by the selected algorithm. Recall that the algorithm can be set through the compalg= kernel parameter. o All entries in /proc/sys/vm/comp_cache removed. Since compression algorithms cannot be changed nor compressed cache size, so it's useless to have a directory in /proc/sys. Compressed cache size can still be checked in /proc/meminfo. o Info for compression algorithm is shown even if no page has been compressed. o There are many code blocks with "#if 0" that are/were being tested. Cleanups: o Code to add the fragment into a comp page fragment list was split to a new function. o decompress() function removed. Index: comp_cache.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/comp_cache.h,v retrieving revision 1.100 retrieving revision 1.101 diff -C2 -r1.100 -r1.101 *** comp_cache.h 7 Aug 2002 18:30:58 -0000 1.100 --- comp_cache.h 10 Sep 2002 16:43:03 -0000 1.101 *************** *** 2,6 **** * linux/mm/comp_cache.h * ! * Time-stamp: <2002-08-07 10:51:24 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache.h * ! * Time-stamp: <2002-09-06 19:25:59 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 17,20 **** --- 17,21 ---- #include <linux/compiler.h> #include <linux/list.h> + #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/fs.h> *************** *** 30,40 **** #include <linux/minilzo.h> ! #define COMP_CACHE_VERSION "0.24pre3" /* maximum compressed size of a page */ #define MAX_COMPRESSED_SIZE 4500 ! extern unsigned long num_comp_pages, num_fragments, num_swapper_fragments, new_num_comp_pages, zone_num_comp_pages; ! extern unsigned long min_num_comp_pages, max_num_comp_pages, max_used_num_comp_pages; struct pte_list { --- 31,42 ---- #include <linux/minilzo.h> ! #define COMP_CACHE_VERSION "0.24pre4" /* maximum compressed size of a page */ #define MAX_COMPRESSED_SIZE 4500 ! extern unsigned long num_comp_pages, num_fragments, num_active_fragments, num_swapper_fragments, num_clean_fragments, zone_num_comp_pages; ! extern unsigned long new_num_comp_pages, min_num_comp_pages, max_num_comp_pages, max_used_num_comp_pages; ! extern kmem_cache_t * fragment_cachep; struct pte_list { *************** *** 114,119 **** --- 116,125 ---- #ifdef CONFIG_COMP_CACHE extern unsigned long failed_comp_page_allocs; + extern int growing_lock; + int grow_on_demand(void); int shrink_on_demand(struct comp_cache_page *); + void compact_comp_cache(void); + void balance_lru_queues(void); #else static inline int grow_on_demand(void) { return 0; } *************** *** 124,154 **** extern struct list_head swp_free_buffer_head; ! /* -- Fragment Flags */ ! /* CF_WKdm/CF_WK4x4/CF_LZO: defines the algorithm the fragment has ! * been compressed (if it's been compressed) */ ! #define CF_WKdm 0 ! #define CF_WK4x4 1 ! #define CF_LZO 2 /* CF_Dirty: is the fragment dirty? */ ! #define CF_Dirty 3 ! #define CF_ToBeFreed 4 ! ! #define CompFragmentWKdm(fragment) test_bit(CF_WKdm, &(fragment)->flags) ! #define CompFragmentSetWKdm(fragment) set_bit(CF_WKdm, &(fragment)->flags) ! #define CompFragmentTestandSetWKdm(fragment) test_and_set_bit(CF_WKdm, &(fragment)->flags) ! #define CompFragmentClearWKdm(fragment) clear_bit(CF_WKdm, &(fragment)->flags) ! ! #define CompFragmentWK4x4(fragment) test_bit(CF_WK4x4, &(fragment)->flags) ! #define CompFragmentSetWK4x4(fragment) set_bit(CF_WK4x4, &(fragment)->flags) ! #define CompFragmentTestandSetWK4x4(fragment) test_and_set_bit(CF_WK4x4, &(fragment)->flags) ! #define CompFragmentClearWK4x4(fragment) clear_bit(CF_WK4x4, &(fragment)->flags) ! ! #define CompFragmentLZO(fragment) test_bit(CF_LZO, &(fragment)->flags) ! #define CompFragmentSetLZO(fragment) set_bit(CF_LZO, &(fragment)->flags) ! #define CompFragmentTestandSetLZO(fragment) test_and_set_bit(CF_LZO, &(fragment)->flags) ! #define CompFragmentClearLZO(fragment) clear_bit(CF_LZO, &(fragment)->flags) #define CompFragmentDirty(fragment) test_bit(CF_Dirty, &(fragment)->flags) --- 130,142 ---- extern struct list_head swp_free_buffer_head; ! int writeout_fragments(unsigned int, int, int); ! /* -- Fragment Flags */ /* CF_Dirty: is the fragment dirty? */ ! #define CF_Dirty 0 ! #define CF_ToBeFreed 1 ! #define CF_Active 2 #define CompFragmentDirty(fragment) test_bit(CF_Dirty, &(fragment)->flags) *************** *** 159,164 **** --- 147,159 ---- #define CompFragmentToBeFreed(fragment) test_bit(CF_ToBeFreed, &(fragment)->flags) + #define CompFragmentSetToBeFreed(fragment) set_bit(CF_ToBeFreed, &(fragment)->flags) #define CompFragmentTestandSetToBeFreed(fragment) test_and_set_bit(CF_ToBeFreed, &(fragment)->flags) + #define CompFragmentActive(fragment) test_bit(CF_Active, &(fragment)->flags) + #define CompFragmentSetActive(fragment) set_bit(CF_Active, &(fragment)->flags) + #define CompFragmentTestandSetActive(fragment) test_and_set_bit(CF_Active, &(fragment)->flags) + #define CompFragmentTestandClearActive(fragment) test_and_clear_bit(CF_Active, &(fragment)->flags) + #define CompFragmentClearActive(fragment) clear_bit(CF_Active, &(fragment)->flags) + /* general */ #define get_fragment(f) do { \ *************** *** 221,225 **** /* LZO */ lzo_byte * wrkmem; ! unsigned short compressed_size; }; --- 216,223 ---- /* LZO */ lzo_byte * wrkmem; ! unsigned short compressed_size; ! ! /* Compressed Swap */ ! struct page * decompress_buffer; }; *************** *** 236,252 **** /* proc.c */ #ifdef CONFIG_COMP_CACHE ! void set_fragment_algorithm(struct comp_cache_fragment *, unsigned short); ! void decompress(struct comp_cache_fragment *, struct page *, int); ! int compress(struct page *, void *, unsigned short *); void __init comp_cache_algorithms_init(void); #endif /* swapin.c */ #ifdef CONFIG_COMP_CACHE extern int FASTCALL(flush_comp_cache(struct page *)); ! int read_comp_cache(struct address_space *, unsigned long, struct page *); int invalidate_comp_cache(struct address_space *, unsigned long); void invalidate_comp_pages(struct address_space *); --- 234,266 ---- /* proc.c */ #ifdef CONFIG_COMP_CACHE ! void decompress_fragment_to_page(struct comp_cache_fragment *, struct page *); ! void decompress_swap_cache_page(struct page *); ! int compress(struct page *, void *, int); void __init comp_cache_algorithms_init(void); + extern int clean_page_compress_lock; + #endif + + #ifdef CONFIG_COMP_SWAP + void get_comp_data(struct page *, unsigned short *, unsigned short *); + #else + static inline void + get_comp_data(struct page * page, unsigned short * size, unsigned short * offset) + { + *size = *((unsigned short *) page_address(page)); + *offset = sizeof(unsigned short); + } #endif + /* swapin.c */ #ifdef CONFIG_COMP_CACHE extern int FASTCALL(flush_comp_cache(struct page *)); ! #define read_comp_cache(mapping, index, page) __read_comp_cache(mapping, index, page, CLEAN_PAGE) ! #define read_dirty_comp_cache(mapping, index, page) __read_comp_cache(mapping, index, page, DIRTY_PAGE) ! ! int __read_comp_cache(struct address_space *, unsigned long, struct page *, int); int invalidate_comp_cache(struct address_space *, unsigned long); void invalidate_comp_pages(struct address_space *); *************** *** 278,288 **** #define DIRTY_PAGE 1 ! #define COMP_PAGE_SIZE ((comp_page_order + 1) * PAGE_SIZE) #define comp_cache_used_space ((num_comp_pages * COMP_PAGE_SIZE) - comp_cache_free_space) ! #define page_to_comp_page(n) ((n) >> comp_page_order) ! #define comp_page_to_page(n) ((n) << comp_page_order) - extern int comp_page_order; extern unsigned long comp_cache_free_space; extern spinlock_t comp_cache_lock; --- 292,307 ---- #define DIRTY_PAGE 1 ! #ifdef CONFIG_COMP_DOUBLE_PAGE ! #define COMP_PAGE_ORDER 1 ! #else ! #define COMP_PAGE_ORDER 0 ! #endif ! ! #define COMP_PAGE_SIZE (PAGE_SIZE << COMP_PAGE_ORDER) #define comp_cache_used_space ((num_comp_pages * COMP_PAGE_SIZE) - comp_cache_free_space) ! #define page_to_comp_page(n) ((n) >> COMP_PAGE_ORDER) ! #define comp_page_to_page(n) ((n) << COMP_PAGE_ORDER) extern unsigned long comp_cache_free_space; extern spinlock_t comp_cache_lock; *************** *** 344,347 **** --- 363,367 ---- int virtual_swap_free(unsigned long); swp_entry_t get_virtual_swap_page(void); + void add_fragment_vswap(struct comp_cache_fragment *); int comp_cache_available_space(void); *************** *** 433,436 **** --- 453,458 ---- inline void set_comp_page(struct comp_cache_page *, struct page *); inline void check_all_fragments(struct comp_cache_page *); + void add_to_comp_page_list(struct comp_cache_page *, struct comp_cache_fragment *); + extern struct comp_cache_fragment ** fragment_hash; *************** *** 486,493 **** struct comp_cache_fragment ** create_fragment_hash(unsigned long *, unsigned int *, unsigned int *); ! extern struct list_head lru_queue; ! inline void add_fragment_to_lru_queue(struct comp_cache_fragment *); ! inline void add_fragment_to_lru_queue_tail(struct comp_cache_fragment *); inline void remove_fragment_from_lru_queue(struct comp_cache_fragment *); --- 508,517 ---- struct comp_cache_fragment ** create_fragment_hash(unsigned long *, unsigned int *, unsigned int *); ! extern struct list_head active_lru_queue, inactive_lru_queue; ! inline void add_fragment_to_active_lru_queue(struct comp_cache_fragment *); ! inline void add_fragment_to_active_lru_queue_tail(struct comp_cache_fragment *); ! inline void add_fragment_to_inactive_lru_queue(struct comp_cache_fragment *); ! inline void add_fragment_to_inactive_lru_queue_tail(struct comp_cache_fragment *); inline void remove_fragment_from_lru_queue(struct comp_cache_fragment *); *************** *** 505,513 **** /* proc.c */ - void print_comp_cache_stats(unsigned short, char *, int *); int comp_cache_stat_read_proc(char *, char **, off_t, int, int *, void *); int comp_cache_hist_read_proc(char *, char **, off_t, int, int *, void *); int comp_cache_frag_read_proc(char *, char **, off_t, int, int *, void *); - int get_fragment_algorithm(struct comp_cache_fragment *); --- 529,535 ---- Index: mm.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/mm.h,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -r1.17 -r1.18 *** mm.h 16 Jul 2002 18:41:55 -0000 1.17 --- mm.h 10 Sep 2002 16:43:04 -0000 1.18 *************** *** 287,292 **** #define PG_launder 15 /* written out by VM pressure.. */ #define PG_comp_cache 16 /* page with a fragment in compressed cache */ ! #define PG_mapped_comp_cache 17 /* page from page cache that is also mapped in ! * the compressed cache */ /* Make it prettier to test the above... */ --- 287,291 ---- #define PG_launder 15 /* written out by VM pressure.. */ #define PG_comp_cache 16 /* page with a fragment in compressed cache */ ! #define PG_compressed 17 /* swapped in page with compressed data */ /* Make it prettier to test the above... */ *************** *** 332,337 **** --- 331,338 ---- #ifdef CONFIG_COMP_CACHE #define PageCompCache(page) test_bit(PG_comp_cache, &(page)->flags) + #define PageCompressed(page) test_bit(PG_compressed, &(page)->flags) #else #define PageCompCache(page) 0 + #define PageCompressed(page) 0 #endif *************** *** 340,343 **** --- 341,349 ---- #define PageTestandSetCompCache(page) test_and_set_bit(PG_comp_cache, &(page)->flags) #define PageTestandClearCompCache(page) test_and_clear_bit(PG_comp_cache, &(page)->flags) + + #define PageSetCompressed(page) set_bit(PG_compressed, &(page)->flags) + #define PageClearCompressed(page) clear_bit(PG_compressed, &(page)->flags) + #define PageTestandSetCompressed(page) test_and_set_bit(PG_compressed, &(page)->flags) + #define PageTestandClearCompressed(page) test_and_clear_bit(PG_compressed, &(page)->flags) #define PageActive(page) test_bit(PG_active, &(page)->flags) Index: swap.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/swap.h,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -r1.15 -r1.16 *** swap.h 1 Jul 2002 17:37:29 -0000 1.15 --- swap.h 10 Sep 2002 16:43:04 -0000 1.16 *************** *** 66,71 **** --- 66,86 ---- #define SWAP_CLUSTER_MAX 32 + #ifdef CONFIG_COMP_CACHE + #define SWAP_MAP_MAX 0x3fff + #define SWAP_MAP_BAD 0x4000 + #define SWAP_MAP_COMP_BIT 0x8000 + #define SWAP_MAP_COMP_BIT_MASK 0x7fff + #define swap_map_count(swap) (swap & 0x7fff) + #else #define SWAP_MAP_MAX 0x7fff #define SWAP_MAP_BAD 0x8000 + #define SWAP_MAP_COMP 0x0000 + #define swap_map_count(swap) (swap) + #endif + + #ifdef CONFIG_COMP_SWAP + #define COMP_SWAP_MAP_MAX 0x7fff + #define COMP_SWAP_MAP_BAD 0x8000 + #endif /* *************** *** 83,86 **** --- 98,109 ---- unsigned int cluster_next; unsigned int cluster_nr; + #ifdef CONFIG_COMP_SWAP + unsigned long * real_swap; + unsigned short * real_swap_map; + unsigned int real_lowest_bit; + unsigned int real_highest_bit; + unsigned int real_cluster_next; + unsigned int real_cluster_nr; + #endif int prio; /* swap priority */ int pages; *************** *** 168,171 **** --- 191,208 ---- asmlinkage long sys_swapoff(const char *); asmlinkage long sys_swapon(const char *, int); + + #ifdef CONFIG_COMP_SWAP + swp_entry_t get_real_swap_page(swp_entry_t); + swp_entry_t get_map(swp_entry_t); + + void map_swap(swp_entry_t, swp_entry_t); + #endif + + #ifdef CONFIG_COMP_CACHE + void set_swap_compressed(swp_entry_t, int); + int get_swap_compressed(swp_entry_t); + #else + static inline int get_swap_compressed(swp_entry_t entry) { return 0; } + #endif extern spinlock_t pagemap_lru_lock; |
From: Rodrigo S. de C. <rc...@us...> - 2002-09-10 16:43:34
|
Update of /cvsroot/linuxcompressed/linux/fs/proc In directory usw-pr-cvs1:/tmp/cvs-serv17835/fs/proc Modified Files: proc_misc.c Log Message: New features o Adaptivity: the greatest feature of the changeset is the adaptivity implementation. Now compressed cache resizes by itself and it seems to be picking the a size pretty close to the best size noticed in our tests. The police can be described as follow. Instead of having an LRU queue, we have now two queues: active and inactive, like the LRU queues in vanilla. The active list has the pages that would be in memory if the compressed cache is not used and the inactive list is the gain from using the compressed cache. If there are many accesses to the active list, we first block growing (by demand) and later shrink the compressed cache, and if we have many accesses to the inactive list, we let the cache grow if needed. The active list size is computed based on the effective compression ratio (number of fragments/number of memory pages). When shrinking the cache, we try to free a compressed cache by moving its fragments to other places. If unable to free a page that way, we free a fragment at the end of inactive list. o Compressed swap: now all swap cache pages are swapped out in compressed format. A bit in swap_map array is used to know if the entry is compressed or not. The compressed size is stored in the entry on the disk. There is almost no cost to store the pages in compressed format, that's why it is the default configuration for compressed cache. o Compacted swap: besides swapping out the pages in compressed format, we may decrease the number of writeouts by writing many fragments to the same disk block. Since it has a memory cost to store some metadata, it is an option to be enabled by user. It uses two arrays, real_swap (unsigned long array) and real_swap_map (unsigned short array). All the metadata about the fragments in the disk block are stored on the block, like offset, size, index. o Clean fragments not decompressed when they would be used to write some data. We don't decompress a clean fragment when grabbing a page cache page in __grab_cache_page() any longer. We would decompress a fragment, but it's data wouldn't be used (that's why this __grab_cache_page() creates a page if not found in page cache). Dirty fragments will be decompressed, but that's a rare situation in page cache since most data are written via buffers. Bug fixes o Larger compressed cache page support would not support pages larger than 2*PAGE_SIZE (8K). Reason: wrong computation of comp page size, very simple to fix. o In /proc/comp_cache_hist, we were showing the number of fragments in a comp page, no matter if those fragments were freed. It has been fixed to not show the freed fragments. o Writing out every dirty page with buffers. That was a conceptual bug, since all the swapped in pages would have bugs, and if they got dirty, they would not be added to compressed cache as dirty, they would be written out first and only then added to swap cache as a clean page. Now we try to free the buffers and if we are unable to do that, we write it out. With this bug, the page was added to compressed cache, but we were forcing many writes. Other: o Removed support to change algorithms online. That was a not very used option and would introduce a space cost to pages swapped out in compressed format, so it was removed. It also saved some memory space, since we allocate only the data structure used by the selected algorithm. Recall that the algorithm can be set through the compalg= kernel parameter. o All entries in /proc/sys/vm/comp_cache removed. Since compression algorithms cannot be changed nor compressed cache size, so it's useless to have a directory in /proc/sys. Compressed cache size can still be checked in /proc/meminfo. o Info for compression algorithm is shown even if no page has been compressed. o There are many code blocks with "#if 0" that are/were being tested. Cleanups: o Code to add the fragment into a comp page fragment list was split to a new function. o decompress() function removed. Index: proc_misc.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/fs/proc/proc_misc.c,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -r1.7 -r1.8 *** proc_misc.c 28 Jul 2002 15:47:04 -0000 1.7 --- proc_misc.c 10 Sep 2002 16:43:00 -0000 1.8 *************** *** 183,187 **** #ifdef CONFIG_COMP_CACHE K(pg_size + num_swapper_fragments - swapper_space.nrpages), ! K(num_comp_pages << comp_page_order), comp_cache_used_space/1024, K(swapper_space.nrpages - num_swapper_fragments), --- 183,187 ---- #ifdef CONFIG_COMP_CACHE K(pg_size + num_swapper_fragments - swapper_space.nrpages), ! K(num_comp_pages << COMP_PAGE_ORDER), comp_cache_used_space/1024, K(swapper_space.nrpages - num_swapper_fragments), |
From: Rodrigo S. de C. <rc...@us...> - 2002-09-10 16:43:32
|
Update of /cvsroot/linuxcompressed/linux/arch/i386 In directory usw-pr-cvs1:/tmp/cvs-serv17835/arch/i386 Modified Files: config.in Log Message: New features o Adaptivity: the greatest feature of the changeset is the adaptivity implementation. Now compressed cache resizes by itself and it seems to be picking the a size pretty close to the best size noticed in our tests. The police can be described as follow. Instead of having an LRU queue, we have now two queues: active and inactive, like the LRU queues in vanilla. The active list has the pages that would be in memory if the compressed cache is not used and the inactive list is the gain from using the compressed cache. If there are many accesses to the active list, we first block growing (by demand) and later shrink the compressed cache, and if we have many accesses to the inactive list, we let the cache grow if needed. The active list size is computed based on the effective compression ratio (number of fragments/number of memory pages). When shrinking the cache, we try to free a compressed cache by moving its fragments to other places. If unable to free a page that way, we free a fragment at the end of inactive list. o Compressed swap: now all swap cache pages are swapped out in compressed format. A bit in swap_map array is used to know if the entry is compressed or not. The compressed size is stored in the entry on the disk. There is almost no cost to store the pages in compressed format, that's why it is the default configuration for compressed cache. o Compacted swap: besides swapping out the pages in compressed format, we may decrease the number of writeouts by writing many fragments to the same disk block. Since it has a memory cost to store some metadata, it is an option to be enabled by user. It uses two arrays, real_swap (unsigned long array) and real_swap_map (unsigned short array). All the metadata about the fragments in the disk block are stored on the block, like offset, size, index. o Clean fragments not decompressed when they would be used to write some data. We don't decompress a clean fragment when grabbing a page cache page in __grab_cache_page() any longer. We would decompress a fragment, but it's data wouldn't be used (that's why this __grab_cache_page() creates a page if not found in page cache). Dirty fragments will be decompressed, but that's a rare situation in page cache since most data are written via buffers. Bug fixes o Larger compressed cache page support would not support pages larger than 2*PAGE_SIZE (8K). Reason: wrong computation of comp page size, very simple to fix. o In /proc/comp_cache_hist, we were showing the number of fragments in a comp page, no matter if those fragments were freed. It has been fixed to not show the freed fragments. o Writing out every dirty page with buffers. That was a conceptual bug, since all the swapped in pages would have bugs, and if they got dirty, they would not be added to compressed cache as dirty, they would be written out first and only then added to swap cache as a clean page. Now we try to free the buffers and if we are unable to do that, we write it out. With this bug, the page was added to compressed cache, but we were forcing many writes. Other: o Removed support to change algorithms online. That was a not very used option and would introduce a space cost to pages swapped out in compressed format, so it was removed. It also saved some memory space, since we allocate only the data structure used by the selected algorithm. Recall that the algorithm can be set through the compalg= kernel parameter. o All entries in /proc/sys/vm/comp_cache removed. Since compression algorithms cannot be changed nor compressed cache size, so it's useless to have a directory in /proc/sys. Compressed cache size can still be checked in /proc/meminfo. o Info for compression algorithm is shown even if no page has been compressed. o There are many code blocks with "#if 0" that are/were being tested. Cleanups: o Code to add the fragment into a comp page fragment list was split to a new function. o decompress() function removed. Index: config.in =================================================================== RCS file: /cvsroot/linuxcompressed/linux/arch/i386/config.in,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -r1.22 -r1.23 *** config.in 28 Jul 2002 15:47:03 -0000 1.22 --- config.in 10 Sep 2002 16:42:58 -0000 1.23 *************** *** 212,215 **** --- 212,216 ---- bool ' Support for Page Cache compression' CONFIG_COMP_PAGE_CACHE bool ' Double Page Size' CONFIG_COMP_DOUBLE_PAGE + bool ' Compressed Swap' CONFIG_COMP_SWAP fi fi |
From: Rodrigo S. de C. <rc...@us...> - 2002-09-10 16:43:16
|
Update of /cvsroot/linuxcompressed/linux/kernel In directory usw-pr-cvs1:/tmp/cvs-serv17835/kernel Removed Files: sysctl.c Log Message: New features o Adaptivity: the greatest feature of the changeset is the adaptivity implementation. Now compressed cache resizes by itself and it seems to be picking the a size pretty close to the best size noticed in our tests. The police can be described as follow. Instead of having an LRU queue, we have now two queues: active and inactive, like the LRU queues in vanilla. The active list has the pages that would be in memory if the compressed cache is not used and the inactive list is the gain from using the compressed cache. If there are many accesses to the active list, we first block growing (by demand) and later shrink the compressed cache, and if we have many accesses to the inactive list, we let the cache grow if needed. The active list size is computed based on the effective compression ratio (number of fragments/number of memory pages). When shrinking the cache, we try to free a compressed cache by moving its fragments to other places. If unable to free a page that way, we free a fragment at the end of inactive list. o Compressed swap: now all swap cache pages are swapped out in compressed format. A bit in swap_map array is used to know if the entry is compressed or not. The compressed size is stored in the entry on the disk. There is almost no cost to store the pages in compressed format, that's why it is the default configuration for compressed cache. o Compacted swap: besides swapping out the pages in compressed format, we may decrease the number of writeouts by writing many fragments to the same disk block. Since it has a memory cost to store some metadata, it is an option to be enabled by user. It uses two arrays, real_swap (unsigned long array) and real_swap_map (unsigned short array). All the metadata about the fragments in the disk block are stored on the block, like offset, size, index. o Clean fragments not decompressed when they would be used to write some data. We don't decompress a clean fragment when grabbing a page cache page in __grab_cache_page() any longer. We would decompress a fragment, but it's data wouldn't be used (that's why this __grab_cache_page() creates a page if not found in page cache). Dirty fragments will be decompressed, but that's a rare situation in page cache since most data are written via buffers. Bug fixes o Larger compressed cache page support would not support pages larger than 2*PAGE_SIZE (8K). Reason: wrong computation of comp page size, very simple to fix. o In /proc/comp_cache_hist, we were showing the number of fragments in a comp page, no matter if those fragments were freed. It has been fixed to not show the freed fragments. o Writing out every dirty page with buffers. That was a conceptual bug, since all the swapped in pages would have bugs, and if they got dirty, they would not be added to compressed cache as dirty, they would be written out first and only then added to swap cache as a clean page. Now we try to free the buffers and if we are unable to do that, we write it out. With this bug, the page was added to compressed cache, but we were forcing many writes. Other: o Removed support to change algorithms online. That was a not very used option and would introduce a space cost to pages swapped out in compressed format, so it was removed. It also saved some memory space, since we allocate only the data structure used by the selected algorithm. Recall that the algorithm can be set through the compalg= kernel parameter. o All entries in /proc/sys/vm/comp_cache removed. Since compression algorithms cannot be changed nor compressed cache size, so it's useless to have a directory in /proc/sys. Compressed cache size can still be checked in /proc/meminfo. o Info for compression algorithm is shown even if no page has been compressed. o There are many code blocks with "#if 0" that are/were being tested. Cleanups: o Code to add the fragment into a comp page fragment list was split to a new function. o decompress() function removed. --- sysctl.c DELETED --- |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-13 14:15:22
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv30160/mm/comp_cache Modified Files: proc.c Log Message: Other o Added the ratio of decompressed/read/written pages to the number of compressed pages Index: proc.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/proc.c,v retrieving revision 1.24 retrieving revision 1.25 diff -C2 -r1.24 -r1.25 *** proc.c 7 Aug 2002 18:30:58 -0000 1.24 --- proc.c 13 Aug 2002 14:15:20 -0000 1.25 *************** *** 2,6 **** * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-08-07 14:43:55 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-08-12 19:19:39 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 290,300 **** #define current_msg ((algorithm == &compression_algorithms[current_algorithm])?"*":"") ! #define proportion(part, total) (total?(int) ((part * 100)/(total)):0) void print_comp_cache_stats(unsigned short alg_idx, char * page, int * length) { ! unsigned int compression_ratio_swap, compression_ratio_page, compression_ratio_total; ! unsigned long total_comp_pages, total_sum_comp_pages; struct comp_alg * algorithm = &compression_algorithms[alg_idx]; struct stats_summary * stats = &algorithm->stats; --- 290,301 ---- #define current_msg ((algorithm == &compression_algorithms[current_algorithm])?"*":"") ! #define proportion(part, total) (total?((unsigned int) ((part * 100)/(total))):0) void print_comp_cache_stats(unsigned short alg_idx, char * page, int * length) { ! unsigned int compression_ratio_swap, compression_ratio_page, compression_ratio_total; ! unsigned long long total_sum_comp_pages; ! unsigned long total_comp_pages; struct comp_alg * algorithm = &compression_algorithms[alg_idx]; struct stats_summary * stats = &algorithm->stats; *************** *** 324,334 **** *length += sprintf(page + *length, " algorithm %s%s\n" ! " - compressed pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - decompressed pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - read pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - written pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - compression ratio: %8d%% (S: %3d%% P: %3d%%)\n", algorithm->name, current_msg, ! stats->comp_swap + stats->comp_page, proportion(stats->comp_swap, total_comp_pages), proportion(stats->comp_page, total_comp_pages), --- 325,335 ---- *length += sprintf(page + *length, " algorithm %s%s\n" ! " - (C) compressed pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - (D) decompressed pages: %8lu (S: %3d%% P: %3d%%) D/C %3u%%\n" ! " - (R) read pages: %8lu (S: %3d%% P: %3d%%) R/C: %3u%%\n" ! " - (W) written pages: %8lu (S: %3d%% P: %3d%%) W/C: %3u%% \n" ! " compression ratio: %8u%% (S: %3u%% P: %3u%%)\n", algorithm->name, current_msg, ! total_comp_pages, proportion(stats->comp_swap, total_comp_pages), proportion(stats->comp_page, total_comp_pages), *************** *** 336,345 **** --- 337,349 ---- proportion(stats->decomp_swap, stats->decomp_swap + stats->decomp_page), proportion(stats->decomp_page, stats->decomp_swap + stats->decomp_page), + (unsigned int) (((stats->decomp_swap + stats->decomp_page) * 100)/total_comp_pages), stats->read_swap + stats->read_page, proportion(stats->read_swap, stats->read_swap + stats->read_page), proportion(stats->read_page, stats->read_swap + stats->read_page), + (unsigned int) (((stats->read_swap + stats->read_page) * 100)/total_comp_pages), stats->written_swap + stats->written_page, proportion(stats->written_swap, stats->written_swap + stats->written_page), proportion(stats->written_page, stats->written_swap + stats->written_page), + (unsigned int) (((stats->written_swap + stats->written_page) * 100)/total_comp_pages), compression_ratio_total, compression_ratio_swap, *************** *** 455,462 **** "compressed cache - statistics\n" " general\n" #ifdef CONFIG_COMP_PAGE_CACHE ! " - swap (S) and page (P) cache support\n" #else ! " - swap (S) cache support only\n" #endif " - maximum used size: %6lu KiB\n" --- 459,468 ---- "compressed cache - statistics\n" " general\n" + " - (S) swap cache support enabled\n" + #ifdef CONFIG_COMP_PAGE_CACHE ! " - (P) page cache support enabled\n" #else ! " - (P) page cache support disabled\n" #endif " - maximum used size: %6lu KiB\n" |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-07 18:31:02
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv28260/mm/comp_cache Modified Files: adaptivity.c free.c main.c proc.c swapin.c swapout.c Log Message: Feature o New comp_cache_stat output, including some configurations (like if there is support for page cache, the comp page size, failed allocations). There is also data separated for page and swap cache. Bug fixes o A deadlock happens when compiling the linux kernel on a host kernel with compressed cache. It usually happens when used make -j 2/4, but also happens with make -j 1. From the stack traces, a process hangs waiting for a swap buffer page in comp_cache_free_locked() and all the other processes hang trying to lock the fragment->comp_page which is locked waiting for the swap buffer. This deadlock might happen if the swap buffer gets unlocked when the fragment is waiting for it, but it is locked again before the wait_on_page() function enters the CPU. In this case, if the swap buffer is also trying to write out a fragment in the very same comp page as the former fragment, it will sleep to lock the comp page which could only get unlocked when this swap buffer got unlocked (what will not happen). The fix was to remove the wait_on_page() to not wait for the swap buffer. Actually, it was removed because it fixes the deadlock, but the most important reason is that it was not needed. It had been put there trying to fix a race which it didn't fix (the goal was to avoid to read a page that is being written from a swap buffer). o Once, compiling the linux kernel on a host kernel with compressed cache, we hit a bug from a error happened when decompressing a fragment (in the case, the error was -4 in LZO). After compressing a page to a static buffer in compress_page(), if it happened that this buffer got used, we compressed it again, without making sure that the compressed size was the same. So, we could have a fragment set to a wrong compressed size and copy the wrong number of bytes from the buffer to the page. Now we check if the size is the same, freeing the fragment and getting a new one if the differ. o After a failed writepage(), the swap buffer would not set the fragment->swp_buffer to NULL, so it might end having its fragment field nulled in the future, possibly when set to a fragment that is being written. If that happens, the fragment would not be freed and never freed by the writeout code, since it had been removed from the LRU queue. The fix was just set swp_buffer->fragment->swp_buffer to NULL. o There is a potential bug in refill_swp_buffer() that can free a swap buffer pages that has buffers. A "goto" to give up on that page and add it back to the used list has been wrongly deleted. It has been added back. Cleanups o Cleanups in the stats code and structures. Index: adaptivity.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/adaptivity.c,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -r1.38 -r1.39 *** adaptivity.c 28 Jul 2002 15:47:04 -0000 1.38 --- adaptivity.c 7 Aug 2002 18:30:58 -0000 1.39 *************** *** 2,6 **** * linux/mm/comp_cache/adaptivity.c * ! * Time-stamp: <2002-07-26 17:22:32 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/adaptivity.c * ! * Time-stamp: <2002-08-03 12:12:40 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 17,20 **** --- 17,21 ---- extern kmem_cache_t * comp_cachep; static int fragment_failed_alloc = 0, vswap_failed_alloc = 0; + unsigned long failed_comp_page_allocs = 0; /* semaphore used to avoid two concurrent instances of *************** *** 641,646 **** /* couldn't allocate the page */ ! if (!page) goto out_unlock; if (!init_comp_page(&comp_page, page)) { --- 642,649 ---- /* couldn't allocate the page */ ! if (!page) { ! failed_comp_page_allocs++; goto out_unlock; + } if (!init_comp_page(&comp_page, page)) { *************** *** 652,655 **** --- 655,660 ---- comp_cache_free_space += COMP_PAGE_SIZE; num_comp_pages++; + if (num_comp_pages > max_used_num_comp_pages) + max_used_num_comp_pages = num_comp_pages; #if 0 printk("grow real %lu\n", num_comp_pages); Index: free.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/free.c,v retrieving revision 1.45 retrieving revision 1.46 diff -C2 -r1.45 -r1.46 *** free.c 31 Jul 2002 12:31:05 -0000 1.45 --- free.c 7 Aug 2002 18:30:58 -0000 1.46 *************** *** 2,6 **** * linux/mm/comp_cache/free.c * ! * Time-stamp: <2002-07-29 10:04:24 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/free.c * ! * Time-stamp: <2002-08-07 12:50:00 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 66,74 **** * non-null swp_buffer. Let's warn the swap buffer that this * page has been already removed by setting its fragment field ! * to NULL and also let's wait for the IO to finish. */ ! if (fragment->swp_buffer) { fragment->swp_buffer->fragment = NULL; - wait_on_page(fragment->swp_buffer->page); - } /* compressed fragments of swap cache are accounted in --- 66,72 ---- * non-null swp_buffer. Let's warn the swap buffer that this * page has been already removed by setting its fragment field ! * to NULL. */ ! if (fragment->swp_buffer) fragment->swp_buffer->fragment = NULL; /* compressed fragments of swap cache are accounted in Index: main.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/main.c,v retrieving revision 1.62 retrieving revision 1.63 diff -C2 -r1.62 -r1.63 *** main.c 1 Aug 2002 14:52:25 -0000 1.62 --- main.c 7 Aug 2002 18:30:58 -0000 1.63 *************** *** 2,6 **** * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-08-01 10:19:51 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-08-07 15:17:28 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 29,32 **** --- 29,33 ---- unsigned long max_num_comp_pages = 0; unsigned long min_num_comp_pages = 0; + unsigned long max_used_num_comp_pages = 0; /* stores the last number of compressed pages that has been used to *************** *** 77,81 **** } ! 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); --- 78,83 ---- } ! try_again: ! comp_size = compress(current_compressed_page = page, buffer_compressed = (unsigned long *) &buffer_compressed1, &algorithm); comp_page = get_comp_cache_page(page, comp_size, &fragment, gfp_mask, priority); *************** *** 110,115 **** copy_page: if (compressed(fragment)) { ! if (current_compressed_page != page) ! compress(page, buffer_compressed = (unsigned long *) &buffer_compressed2, &algorithm, state); memcpy(page_address(comp_page->page) + fragment->offset, buffer_compressed , fragment->compressed_size); } else --- 112,123 ---- copy_page: if (compressed(fragment)) { ! if (current_compressed_page != page) { ! comp_size = compress(page, buffer_compressed = (unsigned long *) &buffer_compressed2, &algorithm); ! if (comp_size != fragment->compressed_size) { ! UnlockPage(comp_page->page); ! drop_fragment(fragment); ! goto try_again; ! } ! } memcpy(page_address(comp_page->page) + fragment->offset, buffer_compressed , fragment->compressed_size); } else *************** *** 211,221 **** int i; ! min_num_comp_pages = page_to_comp_page(48); if (!max_num_comp_pages || max_num_comp_pages < min_num_comp_pages || max_num_comp_pages > num_physpages * 0.5) max_num_comp_pages = page_to_comp_page((unsigned long) (num_physpages * 0.5)); - if (!init_num_comp_pages || init_num_comp_pages < min_num_comp_pages || init_num_comp_pages > max_num_comp_pages) - init_num_comp_pages = min_num_comp_pages; new_num_comp_pages = num_comp_pages = init_num_comp_pages; --- 219,227 ---- int i; ! max_used_num_comp_pages = init_num_comp_pages = min_num_comp_pages = page_to_comp_page(48); if (!max_num_comp_pages || max_num_comp_pages < min_num_comp_pages || max_num_comp_pages > num_physpages * 0.5) max_num_comp_pages = page_to_comp_page((unsigned long) (num_physpages * 0.5)); new_num_comp_pages = num_comp_pages = init_num_comp_pages; Index: proc.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/proc.c,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -r1.23 -r1.24 *** proc.c 1 Aug 2002 14:52:25 -0000 1.23 --- proc.c 7 Aug 2002 18:30:58 -0000 1.24 *************** *** 2,6 **** * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-08-01 09:03:16 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-08-07 14:43:55 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 27,31 **** extern unsigned long new_num_comp_pages, max_num_comp_pages, min_num_comp_pages; ! static struct comp_alg compression_algorithms[NUM_ALGORITHMS]; static int algorithm_min = WKDM_IDX; static int algorithm_max = LZO_IDX; --- 27,55 ---- extern unsigned long new_num_comp_pages, max_num_comp_pages, min_num_comp_pages; ! struct stats_summary { ! /* swap cache */ ! unsigned long long comp_size_sum_swap; ! unsigned long comp_swap; ! unsigned long decomp_swap; ! unsigned long read_swap; ! unsigned long written_swap; ! ! ! /* page cache */ ! unsigned long long comp_size_sum_page; ! unsigned long comp_page; ! unsigned long decomp_page; ! unsigned long read_page; ! unsigned long written_page; ! ! }; ! ! static struct comp_alg { ! char name[6]; ! compress_function_t * comp; ! decompress_function_t * decomp; ! struct stats_summary stats; ! } compression_algorithms[NUM_ALGORITHMS]; ! static int algorithm_min = WKDM_IDX; static int algorithm_max = LZO_IDX; *************** *** 49,158 **** }; ! static inline void ! comp_cache_update_page_stats(struct page * page, int state) { ! #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(page)) ! compression_algorithms[current_algorithm].stats.comp_page++; ! else ! #endif ! compression_algorithms[current_algorithm].stats.comp_swap++; ! if (state == DIRTY_PAGE) ! compression_algorithms[current_algorithm].stats.comp_dirty++; ! else ! compression_algorithms[current_algorithm].stats.comp_clean++; } ! static void ! comp_cache_update_comp_stats(struct stats_page * comp_page_stats, struct page * page, int state) { ! struct comp_alg * algorithm = &compression_algorithms[current_algorithm]; ! struct stats_summary * stats = &(algorithm->stats); ! ! /* update compressed size statistics */ ! if (!comp_page_stats->comp_size) BUG(); ! ! if (comp_page_stats->comp_size < stats->comp_size_min) ! stats->comp_size_min = comp_page_stats->comp_size; ! ! if (comp_page_stats->comp_size > stats->comp_size_max) ! stats->comp_size_max = comp_page_stats->comp_size; ! ! stats->comp_size_sum += comp_page_stats->comp_size; ! ! /* update comp cycles statistics */ ! if (comp_page_stats->comp_cycles < stats->comp_cycles_min) ! stats->comp_cycles_min = comp_page_stats->comp_cycles; ! ! if (comp_page_stats->comp_cycles > stats->comp_cycles_max) ! stats->comp_cycles_max = comp_page_stats->comp_cycles; ! ! stats->comp_cycles_sum += comp_page_stats->comp_cycles; ! ! comp_cache_update_page_stats(page, state); } ! static void ! comp_cache_update_decomp_stats(unsigned short alg_idx, struct stats_page * comp_page_stats, struct comp_cache_fragment * fragment) { ! struct comp_alg * algorithm = &compression_algorithms[alg_idx]; ! struct stats_summary * stats = &(algorithm->stats); ! ! /* update decomp cycles statistics */ ! if (comp_page_stats->decomp_cycles < stats->decomp_cycles_min) ! stats->decomp_cycles_min = comp_page_stats->decomp_cycles; ! ! if (comp_page_stats->decomp_cycles > stats->decomp_cycles_max) ! stats->decomp_cycles_max = comp_page_stats->decomp_cycles; ! ! stats->decomp_cycles_sum += comp_page_stats->decomp_cycles; #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(fragment)) ! compression_algorithms[current_algorithm].stats.decomp_page++; ! else #endif ! compression_algorithms[current_algorithm].stats.decomp_swap++; } ! void ! comp_cache_update_writeout_stats(struct comp_cache_fragment * fragment) { #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(fragment)) ! compression_algorithms[current_algorithm].stats.page_out++; ! else #endif ! compression_algorithms[current_algorithm].stats.swap_out++; } ! void ! comp_cache_update_faultin_stats(struct comp_cache_fragment * fragment) { #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(fragment)) ! compression_algorithms[current_algorithm].stats.faultin_page++; ! else #endif ! compression_algorithms[current_algorithm].stats.faultin_swap++; } ! ! void ! set_fragment_algorithm(struct comp_cache_fragment * fragment, unsigned short algorithm) { ! switch (algorithm) { ! case WKDM_IDX: ! CompFragmentSetWKdm(fragment); ! break; ! case WK4X4_IDX: ! CompFragmentSetWK4x4(fragment); ! break; ! case LZO_IDX: ! CompFragmentSetLZO(fragment); ! break; ! default: BUG(); } } --- 73,168 ---- }; ! int ! get_fragment_algorithm(struct comp_cache_fragment * fragment) { ! if (CompFragmentWKdm(fragment)) ! return WKDM_IDX; ! if (CompFragmentWK4x4(fragment)) ! return WK4X4_IDX; ! if (CompFragmentLZO(fragment)) ! return LZO_IDX; ! BUG(); ! return -1; } ! void ! set_fragment_algorithm(struct comp_cache_fragment * fragment, unsigned short algorithm) { ! switch (algorithm) { ! case WKDM_IDX: ! CompFragmentSetWKdm(fragment); ! break; ! case WK4X4_IDX: ! CompFragmentSetWK4x4(fragment); ! break; ! case LZO_IDX: ! CompFragmentSetLZO(fragment); ! break; ! default: BUG(); ! } } ! inline void ! comp_cache_update_read_stats(unsigned short algorithm, struct comp_cache_fragment * fragment) { ! struct stats_summary * stats = &(compression_algorithms[algorithm].stats); #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(fragment)) { ! stats->read_page++; ! return; ! } #endif ! stats->read_swap++; } ! inline void ! comp_cache_update_written_stats(unsigned short algorithm, struct comp_cache_fragment * fragment) { + struct stats_summary * stats = &(compression_algorithms[algorithm].stats); + #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(fragment)) { ! stats->written_page++; ! return; ! } #endif ! stats->written_swap++; } ! static inline void ! comp_cache_update_decomp_stats(unsigned short algorithm, struct comp_cache_fragment * fragment) { + struct stats_summary * stats = &(compression_algorithms[algorithm].stats); + #ifdef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(fragment)) { ! stats->decomp_page++; ! return; ! } #endif ! stats->decomp_swap++; } ! ! static inline void ! comp_cache_update_comp_stats(unsigned int comp_size, struct page * page) { ! struct stats_summary * stats = &(compression_algorithms[current_algorithm].stats); ! ! /* update compressed size statistics */ ! if (!comp_size) BUG(); + + #ifdef CONFIG_COMP_PAGE_CACHE + if (!PageSwapCache(page)) { + stats->comp_page++; + stats->comp_size_sum_page += comp_size; + return; } + #endif + + stats->comp_swap++; + stats->comp_size_sum_swap += comp_size; } *************** *** 186,192 **** int ! compress(struct page * page, void * to, unsigned short * algorithm, int state) { ! struct stats_page comp_page_stats; void * from = page_address(page); --- 196,202 ---- int ! compress(struct page * page, void * to, unsigned short * algorithm) { ! unsigned int comp_size; void * from = page_address(page); *************** *** 202,239 **** spin_lock(&comp_data_lock); ! START_ZEN_TIME(comp_page_stats.myTimer); ! comp_page_stats.comp_size = compression_algorithms[current_algorithm].comp(from, to, PAGE_SIZE/4, &comp_data); ! STOP_ZEN_TIME(comp_page_stats.myTimer, comp_page_stats.comp_cycles); spin_unlock(&comp_data_lock); ! comp_cache_update_comp_stats(&comp_page_stats, page, state); *algorithm = current_algorithm; ! if (comp_page_stats.comp_size > PAGE_SIZE) ! comp_page_stats.comp_size = PAGE_SIZE; ! return (comp_page_stats.comp_size); } void ! decompress(struct comp_cache_fragment * fragment, struct page * page) { - struct stats_page comp_page_stats; - unsigned int algorithm = WKDM_IDX; void * from = page_address(fragment->comp_page->page) + fragment->offset; void * to = page_address(page); - if (CompFragmentWK4x4(fragment)) - algorithm = WK4X4_IDX; - else if (CompFragmentLZO(fragment)) { - algorithm = LZO_IDX; - comp_data.compressed_size = fragment->compressed_size; - } - spin_lock(&comp_data_lock); ! START_ZEN_TIME(comp_page_stats.myTimer); compression_algorithms[algorithm].decomp(from, to, PAGE_SIZE/4, &comp_data); - STOP_ZEN_TIME(comp_page_stats.myTimer, comp_page_stats.decomp_cycles); spin_unlock(&comp_data_lock); ! comp_cache_update_decomp_stats(algorithm, &comp_page_stats, fragment); } --- 212,237 ---- spin_lock(&comp_data_lock); ! comp_size = compression_algorithms[current_algorithm].comp(from, to, PAGE_SIZE/4, &comp_data); spin_unlock(&comp_data_lock); ! comp_cache_update_comp_stats(comp_size, page); *algorithm = current_algorithm; ! if (comp_size > PAGE_SIZE) ! comp_size = PAGE_SIZE; ! return comp_size; } void ! decompress(struct comp_cache_fragment * fragment, struct page * page, int algorithm) { void * from = page_address(fragment->comp_page->page) + fragment->offset; void * to = page_address(page); spin_lock(&comp_data_lock); ! comp_data.compressed_size = fragment->compressed_size; compression_algorithms[algorithm].decomp(from, to, PAGE_SIZE/4, &comp_data); spin_unlock(&comp_data_lock); ! comp_cache_update_decomp_stats(algorithm, fragment); } *************** *** 258,267 **** /* stats for algorithms */ ! for (i = 0; i < NUM_ALGORITHMS; i++) { memset((void *) &compression_algorithms[i], 0, sizeof(struct stats_summary)); - compression_algorithms[i].stats.comp_size_min = INF; - compression_algorithms[i].stats.comp_cycles_min = INF; - compression_algorithms[i].stats.decomp_cycles_min = INF; - } /* compression algorithms */ --- 256,261 ---- /* stats for algorithms */ ! for (i = 0; i < NUM_ALGORITHMS; i++) memset((void *) &compression_algorithms[i], 0, sizeof(struct stats_summary)); /* compression algorithms */ *************** *** 296,380 **** #define current_msg ((algorithm == &compression_algorithms[current_algorithm])?"*":"") void print_comp_cache_stats(unsigned short alg_idx, char * page, int * length) { ! unsigned int compression_ratio, discard_ratio; ! unsigned int mean_size, mean_comp_cycles, mean_decomp_cycles; ! unsigned long total_comp_pages, total_wout_pages, total_decomp_pages, total_faultin_pages; ! struct comp_alg * algorithm = &compression_algorithms[alg_idx]; struct stats_summary * stats = &algorithm->stats; ! total_comp_pages = stats->comp_swap + stats->comp_page; ! total_decomp_pages = stats->decomp_swap + stats->decomp_page; ! total_wout_pages = stats->swap_out + stats->page_out; ! total_faultin_pages = stats->faultin_swap + stats->faultin_page; ! if (!total_comp_pages) return; - - *length += sprintf(page + *length, "compressed cache - statistics\n"); - *length += sprintf(page + *length, "algorithm %s%s\n", algorithm->name, current_msg); ! *length += sprintf(page + *length, ! "Compressed Pages: %8lu\n" ! " Swap Cache: %8lu\n" ! " Page Cache: %8lu\n" ! " Dirty: %8lu\n" ! " Clean: %8lu\n" ! "Decompressed Pages: %8lu\n" ! " Swap Cache: %8lu\n" ! " Page Cache: %8lu\n" ! "Written Out: %8lu\n" ! " Swap Cache: %8lu\n" ! " Page Cache: %8lu\n" ! "Faulted In: %8lu\n" ! " Swap Cache: %8lu\n" ! " Page Cache: %8lu\n", ! total_comp_pages, ! stats->comp_swap, ! stats->comp_page, ! stats->comp_dirty, ! stats->comp_clean, ! total_decomp_pages, ! stats->decomp_swap, ! stats->decomp_page, ! total_wout_pages, ! stats->swap_out, ! stats->page_out, ! total_faultin_pages, ! stats->faultin_swap, ! stats->faultin_page); ! ! mean_size = big_division(stats->comp_size_sum, total_comp_pages); ! mean_comp_cycles = big_division(stats->comp_cycles_sum, total_comp_pages); ! mean_decomp_cycles = big_division(stats->decomp_cycles_sum, total_comp_pages); ! compression_ratio = ((big_division(stats->comp_size_sum, total_comp_pages)*100)/PAGE_SIZE); ! discard_ratio = (int) ((stats->discarded_pages * 100)/total_comp_pages); ! ! *length += sprintf(page + *length, ! "Compression\n" ! " MinSize: %8d\n" ! " MaxSize: %8u\n" ! " AvgSize: %8u\n" ! " Ratio: %8d%%\n" ! " MinCycles: %8lu\n" ! " MaxCycles: %8lu\n" ! " AvgCycles: %8u\n" ! "Decompression\n" ! " MinCycles: %8lu\n" ! " MaxCycles: %8lu\n" ! " AvgCycles: %8u\n", ! stats->comp_size_min, ! stats->comp_size_max, ! mean_size, ! compression_ratio, ! stats->comp_cycles_min, ! stats->comp_cycles_max, ! mean_comp_cycles, ! stats->decomp_cycles_min, ! stats->decomp_cycles_max, ! mean_decomp_cycles); } --- 290,348 ---- #define current_msg ((algorithm == &compression_algorithms[current_algorithm])?"*":"") + #define proportion(part, total) (total?(int) ((part * 100)/(total)):0) void print_comp_cache_stats(unsigned short alg_idx, char * page, int * length) { ! unsigned int compression_ratio_swap, compression_ratio_page, compression_ratio_total; ! unsigned long total_comp_pages, total_sum_comp_pages; struct comp_alg * algorithm = &compression_algorithms[alg_idx]; struct stats_summary * stats = &algorithm->stats; ! /* swap cache */ ! total_comp_pages = stats->comp_swap; ! total_sum_comp_pages = stats->comp_size_sum_swap; ! ! compression_ratio_swap = 0; ! if (stats->comp_swap) ! compression_ratio_swap = ((big_division(stats->comp_size_sum_swap, stats->comp_swap)*100)/PAGE_SIZE); ! ! /* page cache */ ! total_comp_pages += stats->comp_page; ! total_sum_comp_pages += stats->comp_size_sum_page; ! ! compression_ratio_page = 0; ! if (stats->comp_page) ! compression_ratio_page = ((big_division(stats->comp_size_sum_page, stats->comp_page)*100)/PAGE_SIZE); ! ! /* total */ if (!total_comp_pages) return; ! compression_ratio_total = ((big_division(total_sum_comp_pages, total_comp_pages)*100)/PAGE_SIZE); ! ! *length += sprintf(page + *length, ! " algorithm %s%s\n" ! " - compressed pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - decompressed pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - read pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - written pages: %8lu (S: %3d%% P: %3d%%)\n" ! " - compression ratio: %8d%% (S: %3d%% P: %3d%%)\n", ! algorithm->name, current_msg, ! stats->comp_swap + stats->comp_page, ! proportion(stats->comp_swap, total_comp_pages), ! proportion(stats->comp_page, total_comp_pages), ! stats->decomp_swap + stats->decomp_page, ! proportion(stats->decomp_swap, stats->decomp_swap + stats->decomp_page), ! proportion(stats->decomp_page, stats->decomp_swap + stats->decomp_page), ! stats->read_swap + stats->read_page, ! proportion(stats->read_swap, stats->read_swap + stats->read_page), ! proportion(stats->read_page, stats->read_swap + stats->read_page), ! stats->written_swap + stats->written_page, ! proportion(stats->written_swap, stats->written_swap + stats->written_page), ! proportion(stats->written_page, stats->written_swap + stats->written_page), ! compression_ratio_total, ! compression_ratio_swap, ! compression_ratio_page); } *************** *** 484,487 **** --- 452,470 ---- int length = 0, i; + length += sprintf(page + length, + "compressed cache - statistics\n" + " general\n" + #ifdef CONFIG_COMP_PAGE_CACHE + " - swap (S) and page (P) cache support\n" + #else + " - swap (S) cache support only\n" + #endif + " - maximum used size: %6lu KiB\n" + " - comp page size: %6lu KiB\n" + " - failed allocations: %6lu\n", + max_used_num_comp_pages << (comp_page_order + PAGE_SHIFT - 10), + PAGE_SIZE >> (10 - comp_page_order), + failed_comp_page_allocs); + for (i = 0; i < NUM_ALGORITHMS; i++) print_comp_cache_stats(i, page, &length); Index: swapin.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapin.c,v retrieving revision 1.52 retrieving revision 1.53 diff -C2 -r1.52 -r1.53 *** swapin.c 1 Aug 2002 15:35:46 -0000 1.52 --- swapin.c 7 Aug 2002 18:30:58 -0000 1.53 *************** *** 2,6 **** * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-08-01 12:32:01 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-08-07 10:46:04 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 69,76 **** } ! void decompress_fragment(struct comp_cache_fragment * fragment, struct page * page) { struct comp_cache_page * comp_page; if (!fragment) --- 69,77 ---- } ! unsigned short decompress_fragment(struct comp_cache_fragment * fragment, struct page * page) { struct comp_cache_page * comp_page; + int algorithm = get_fragment_algorithm(fragment); if (!fragment) *************** *** 87,97 **** if (compressed(fragment)) ! decompress(fragment, page); else memcpy(page_address(page), page_address(comp_page->page) + fragment->offset, PAGE_SIZE); ! SetPageUptodate(page); } /* caller may hold pagecache_lock (__find_lock_page()) */ int --- 88,101 ---- if (compressed(fragment)) ! decompress(fragment, page, algorithm); else memcpy(page_address(page), page_address(comp_page->page) + fragment->offset, PAGE_SIZE); ! SetPageUptodate(page); ! return algorithm; } + extern inline void comp_cache_update_read_stats(unsigned short, struct comp_cache_fragment *); + /* caller may hold pagecache_lock (__find_lock_page()) */ int *************** *** 99,102 **** --- 103,107 ---- { struct comp_cache_fragment * fragment; + unsigned short algorithm; int err; *************** *** 124,131 **** lock_page(fragment->comp_page->page); ! decompress_fragment(fragment, page); spin_lock(&comp_cache_lock); - comp_cache_update_faultin_stats(fragment); if (CompFragmentTestandClearDirty(fragment)) --- 129,136 ---- lock_page(fragment->comp_page->page); ! algorithm = decompress_fragment(fragment, page); ! comp_cache_update_read_stats(algorithm, fragment); spin_lock(&comp_cache_lock); if (CompFragmentTestandClearDirty(fragment)) Index: swapout.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapout.c,v retrieving revision 1.69 retrieving revision 1.70 diff -C2 -r1.69 -r1.70 *** swapout.c 1 Aug 2002 14:52:25 -0000 1.69 --- swapout.c 7 Aug 2002 18:30:58 -0000 1.70 *************** *** 2,6 **** * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-08-01 09:00:35 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-08-07 11:04:43 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 47,51 **** if (TryLockPage(buffer_page)) { if (!wait) ! goto add_to_dirty; spin_unlock(&swap_buffer_lock); lock_page(buffer_page); --- 47,51 ---- if (TryLockPage(buffer_page)) { if (!wait) ! goto add_to_used; spin_unlock(&swap_buffer_lock); lock_page(buffer_page); *************** *** 61,64 **** --- 61,65 ---- UnlockPage(buffer_page); spin_lock(&swap_buffer_lock); + goto add_to_used; } spin_lock(&swap_buffer_lock); *************** *** 71,75 **** --- 72,78 ---- * free the fragment and should simply backout. */ if (PageDirty(buffer_page)) { + spin_lock(&comp_cache_lock); if (fragment) { + fragment->swp_buffer = NULL; spin_lock(&pagecache_lock); list_del(&fragment->mapping_list); *************** *** 80,83 **** --- 83,87 ---- } ClearPageDirty(buffer_page); + spin_unlock(&comp_cache_lock); goto add_to_free; } *************** *** 96,100 **** list_add_tail(swp_buffer_lh, &swp_free_buffer_head); return 1; ! add_to_dirty: list_add(swp_buffer_lh, &swp_used_buffer_head); } --- 100,104 ---- list_add_tail(swp_buffer_lh, &swp_free_buffer_head); return 1; ! add_to_used: list_add(swp_buffer_lh, &swp_used_buffer_head); } *************** *** 179,183 **** } ! extern void decompress_fragment(struct comp_cache_fragment *, struct page *); static struct swp_buffer * --- 183,188 ---- } ! extern unsigned short decompress_fragment(struct comp_cache_fragment *, struct page *); ! extern inline void comp_cache_update_written_stats(unsigned short, struct comp_cache_fragment *); static struct swp_buffer * *************** *** 185,188 **** --- 190,194 ---- struct page * buffer_page; struct swp_buffer * swp_buffer; + unsigned short algorithm; swp_buffer = find_free_swp_buffer(fragment, gfp_mask); *************** *** 196,201 **** lock_page(fragment->comp_page->page); ! decompress_fragment(fragment, buffer_page); UnlockPage(fragment->comp_page->page); buffer_page->flags &= (1 << PG_locked); --- 202,208 ---- lock_page(fragment->comp_page->page); ! algorithm = decompress_fragment(fragment, buffer_page); UnlockPage(fragment->comp_page->page); + comp_cache_update_written_stats(algorithm, fragment); buffer_page->flags &= (1 << PG_locked); *************** *** 293,298 **** } - comp_cache_update_writeout_stats(fragment); - if (nrpages) continue; --- 300,303 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-07 18:31:02
|
Update of /cvsroot/linuxcompressed/linux/include/linux In directory usw-pr-cvs1:/tmp/cvs-serv28260/include/linux Modified Files: comp_cache.h Log Message: Feature o New comp_cache_stat output, including some configurations (like if there is support for page cache, the comp page size, failed allocations). There is also data separated for page and swap cache. Bug fixes o A deadlock happens when compiling the linux kernel on a host kernel with compressed cache. It usually happens when used make -j 2/4, but also happens with make -j 1. From the stack traces, a process hangs waiting for a swap buffer page in comp_cache_free_locked() and all the other processes hang trying to lock the fragment->comp_page which is locked waiting for the swap buffer. This deadlock might happen if the swap buffer gets unlocked when the fragment is waiting for it, but it is locked again before the wait_on_page() function enters the CPU. In this case, if the swap buffer is also trying to write out a fragment in the very same comp page as the former fragment, it will sleep to lock the comp page which could only get unlocked when this swap buffer got unlocked (what will not happen). The fix was to remove the wait_on_page() to not wait for the swap buffer. Actually, it was removed because it fixes the deadlock, but the most important reason is that it was not needed. It had been put there trying to fix a race which it didn't fix (the goal was to avoid to read a page that is being written from a swap buffer). o Once, compiling the linux kernel on a host kernel with compressed cache, we hit a bug from a error happened when decompressing a fragment (in the case, the error was -4 in LZO). After compressing a page to a static buffer in compress_page(), if it happened that this buffer got used, we compressed it again, without making sure that the compressed size was the same. So, we could have a fragment set to a wrong compressed size and copy the wrong number of bytes from the buffer to the page. Now we check if the size is the same, freeing the fragment and getting a new one if the differ. o After a failed writepage(), the swap buffer would not set the fragment->swp_buffer to NULL, so it might end having its fragment field nulled in the future, possibly when set to a fragment that is being written. If that happens, the fragment would not be freed and never freed by the writeout code, since it had been removed from the LRU queue. The fix was just set swp_buffer->fragment->swp_buffer to NULL. o There is a potential bug in refill_swp_buffer() that can free a swap buffer pages that has buffers. A "goto" to give up on that page and add it back to the used list has been wrongly deleted. It has been added back. Cleanups o Cleanups in the stats code and structures. Index: comp_cache.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/comp_cache.h,v retrieving revision 1.99 retrieving revision 1.100 diff -C2 -r1.99 -r1.100 *** comp_cache.h 1 Aug 2002 14:52:25 -0000 1.99 --- comp_cache.h 7 Aug 2002 18:30:58 -0000 1.100 *************** *** 2,6 **** * linux/mm/comp_cache.h * ! * Time-stamp: <2002-08-01 09:49:34 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache.h * ! * Time-stamp: <2002-08-07 10:51:24 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 35,39 **** #define MAX_COMPRESSED_SIZE 4500 ! extern unsigned long num_comp_pages, num_fragments, num_swapper_fragments, new_num_comp_pages, min_num_comp_pages, max_num_comp_pages, zone_num_comp_pages; struct pte_list { --- 35,40 ---- #define MAX_COMPRESSED_SIZE 4500 ! extern unsigned long num_comp_pages, num_fragments, num_swapper_fragments, new_num_comp_pages, zone_num_comp_pages; ! extern unsigned long min_num_comp_pages, max_num_comp_pages, max_used_num_comp_pages; struct pte_list { *************** *** 112,115 **** --- 113,117 ---- /* adaptivity.c */ #ifdef CONFIG_COMP_CACHE + extern unsigned long failed_comp_page_allocs; int grow_on_demand(void); int shrink_on_demand(struct comp_cache_page *); *************** *** 211,253 **** #define DISCARD_MARK 0.80 - typedef struct { - union { - volatile unsigned long long int timerValue; - struct { - volatile unsigned long int timerValueLow; - volatile unsigned long int timerValueHigh; - } separated; - } startTime; - - union { - volatile unsigned long long int timerValue; - struct { - volatile unsigned long int timerValueLow; - volatile unsigned long int timerValueHigh; - } separated; - } stopTime; - } zenTimerType; - - struct stats_summary { - unsigned long long comp_size_sum; - unsigned int comp_size_max, comp_size_min; - unsigned long long comp_cycles_sum, decomp_cycles_sum; - unsigned long comp_cycles_max, comp_cycles_min; - unsigned long decomp_cycles_max, decomp_cycles_min; - unsigned long comp_swap, decomp_swap; - unsigned long comp_page, decomp_page; - unsigned long comp_dirty, comp_clean; - unsigned long swap_out, page_out; - unsigned long faultin_swap, faultin_page; - unsigned long discarded_pages; - }; - - struct stats_page { - unsigned int comp_size; /* compressed size of a page */ - unsigned long comp_cycles; /* cycles taken for compression */ - unsigned long decomp_cycles; /* cycles taken for decompression */ - zenTimerType myTimer; /* used to calculate the cycles */ - }; - struct comp_alg_data { /* WKdm and WK4x4 */ --- 213,216 ---- *************** *** 271,306 **** struct comp_alg_data * data); - struct comp_alg { - char name[6]; - compress_function_t * comp; - decompress_function_t * decomp; - struct stats_summary stats; - }; - - #define START_ZEN_TIME(userTimer) { \ - userTimer.startTime.timerValue = 0; \ - userTimer.stopTime.timerValue = 0; \ - asm volatile ("rdtsc; movl %%edx, %0; movl %%eax, %1" \ - : "=r" (userTimer.startTime.separated.timerValueHigh), \ - "=r" (userTimer.startTime.separated.timerValueLow) \ - : \ - : "%edx", "%eax"); } - - #define STOP_ZEN_TIME(userTimer,totalTime) { \ - asm volatile ("rdtsc; movl %%edx, %0; movl %%eax, %1" \ - : "=r" (userTimer.stopTime.separated.timerValueHigh), \ - "=r" (userTimer.stopTime.separated.timerValueLow) \ - : \ - : "%edx", "%eax"); \ - totalTime = userTimer.stopTime.timerValue - userTimer.startTime.timerValue; } - /* proc.c */ #ifdef CONFIG_COMP_CACHE - void comp_cache_update_page_comp_stats(struct page *); - void comp_cache_update_writeout_stats(struct comp_cache_fragment *); - void comp_cache_update_faultin_stats(struct comp_cache_fragment *); void set_fragment_algorithm(struct comp_cache_fragment *, unsigned short); ! void decompress(struct comp_cache_fragment *, struct page *); ! int compress(struct page *, void *, unsigned short *, int); void __init comp_cache_algorithms_init(void); --- 234,242 ---- struct comp_alg_data * data); /* proc.c */ #ifdef CONFIG_COMP_CACHE void set_fragment_algorithm(struct comp_cache_fragment *, unsigned short); ! void decompress(struct comp_cache_fragment *, struct page *, int); ! int compress(struct page *, void *, unsigned short *); void __init comp_cache_algorithms_init(void); *************** *** 573,576 **** --- 509,514 ---- int comp_cache_hist_read_proc(char *, char **, off_t, int, int *, void *); int comp_cache_frag_read_proc(char *, char **, off_t, int, int *, void *); + int get_fragment_algorithm(struct comp_cache_fragment *); + #endif /* _LINUX_COMP_CACHE_H */ |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-01 16:08:40
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv26639/mm/comp_cache Modified Files: swapin.c Log Message: Bug fix o Remove bogus BUG() in flush_comp_cache() Index: swapin.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapin.c,v retrieving revision 1.51 retrieving revision 1.52 diff -C2 -r1.51 -r1.52 *** swapin.c 1 Aug 2002 14:52:25 -0000 1.51 --- swapin.c 1 Aug 2002 15:35:46 -0000 1.52 *************** *** 2,6 **** * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-08-01 10:06:03 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-08-01 12:32:01 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 58,63 **** list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); ! if (PageDirty(page)) ! BUG(); __set_page_dirty(page); } --- 58,62 ---- list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); ! /* it may be already dirty if called from set_page_dirty() */ __set_page_dirty(page); } |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-01 14:52:29
|
Update of /cvsroot/linuxcompressed/linux/include/linux In directory usw-pr-cvs1:/tmp/cvs-serv6713/include/linux Modified Files: comp_cache.h Log Message: Bug fixes o We were only accounting writeout statistics if the writepage() returned one, but returning zero doesn't mean it has not been written tough (swap_writepage() always returns zero). So, it ended up that we didn't account any writeout page because most writepage() functions return zero. Now we account every written page, no matter the return value. o Fixed CompCache bit assignment, so now we don't have to search compressed cache for every page that gets compressed. Given that, a PageCompCache(page) does not mean it has a fragment in compressed cache, but a !PageCompCache(page) surely doesn't have a fragment. That improves performance. Cleanups o Don't printk initial compressed cache size, only the maximum size o comp_data defined as static in proc.c Index: comp_cache.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/comp_cache.h,v retrieving revision 1.98 retrieving revision 1.99 diff -C2 -r1.98 -r1.99 *** comp_cache.h 31 Jul 2002 12:31:05 -0000 1.98 --- comp_cache.h 1 Aug 2002 14:52:25 -0000 1.99 *************** *** 2,6 **** * linux/mm/comp_cache.h * ! * Time-stamp: <2002-07-29 09:43:00 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache.h * ! * Time-stamp: <2002-08-01 09:49:34 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 30,34 **** #include <linux/minilzo.h> ! #define COMP_CACHE_VERSION "0.24pre2" /* maximum compressed size of a page */ --- 30,34 ---- #include <linux/minilzo.h> ! #define COMP_CACHE_VERSION "0.24pre3" /* maximum compressed size of a page */ *************** *** 108,127 **** ((struct swp_buffer *) kmem_cache_alloc(comp_cachep, SLAB_ATOMIC)) - #define get_fragment(f) do { \ - if (atomic_read(&(f)->count) == 0) \ - BUG(); \ - atomic_inc(&(f)->count); \ - } while(0); - - #define drop_fragment(f) do { \ - if (!CompFragmentTestandSetToBeFreed(f)) \ - put_fragment(f); \ - } while(0); - - #define put_fragment(f) __comp_cache_free(f) - #define put_fragment_testzero(f) atomic_dec_and_test(&(f)->count) - #define fragment_count(f) atomic_read(&(f)->count) - #define set_fragment_count(f,v) atomic_set(&(f)->count, v) - extern int shmem_page(struct page * page); --- 108,111 ---- *************** *** 175,178 **** --- 159,185 ---- #define CompFragmentTestandSetToBeFreed(fragment) test_and_set_bit(CF_ToBeFreed, &(fragment)->flags) + /* general */ + #define get_fragment(f) do { \ + if (atomic_read(&(f)->count) == 0) \ + BUG(); \ + atomic_inc(&(f)->count); \ + } while(0); + + #define put_fragment(f) __comp_cache_free(f) + #define put_fragment_testzero(f) atomic_dec_and_test(&(f)->count) + #define fragment_count(f) atomic_read(&(f)->count) + #define set_fragment_count(f,v) atomic_set(&(f)->count, v) + + extern int __comp_cache_free(struct comp_cache_fragment *); + + static inline int + drop_fragment(struct comp_cache_fragment * fragment) + { + int err = 0; + if (!CompFragmentTestandSetToBeFreed(fragment)) + err = put_fragment(fragment); + return err; + } + #define INF 0xffffffff *************** *** 436,441 **** /* free.c */ - int __comp_cache_free(struct comp_cache_fragment *); - #ifdef CONFIG_COMP_CACHE --- 443,446 ---- *************** *** 443,446 **** --- 448,452 ---- int comp_cache_use_address(swp_entry_t); + int __comp_cache_free(struct comp_cache_fragment *); /* from Riel's rmap patch */ |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-01 14:52:29
|
Update of /cvsroot/linuxcompressed/linux/mm In directory usw-pr-cvs1:/tmp/cvs-serv6713/mm Modified Files: filemap.c Log Message: Bug fixes o We were only accounting writeout statistics if the writepage() returned one, but returning zero doesn't mean it has not been written tough (swap_writepage() always returns zero). So, it ended up that we didn't account any writeout page because most writepage() functions return zero. Now we account every written page, no matter the return value. o Fixed CompCache bit assignment, so now we don't have to search compressed cache for every page that gets compressed. Given that, a PageCompCache(page) does not mean it has a fragment in compressed cache, but a !PageCompCache(page) surely doesn't have a fragment. That improves performance. Cleanups o Don't printk initial compressed cache size, only the maximum size o comp_data defined as static in proc.c Index: filemap.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/filemap.c,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -r1.38 -r1.39 *** filemap.c 31 Jul 2002 20:48:59 -0000 1.38 --- filemap.c 1 Aug 2002 14:52:25 -0000 1.39 *************** *** 163,168 **** mark_inode_dirty_pages(mapping->host); #ifdef CONFIG_COMP_CACHE ! if (PageTestandClearCompCache(page)) ! invalidate_comp_cache(mapping, page->index); #endif } --- 163,167 ---- mark_inode_dirty_pages(mapping->host); #ifdef CONFIG_COMP_CACHE ! flush_comp_cache(page); #endif } |
From: Rodrigo S. de C. <rc...@us...> - 2002-08-01 14:52:29
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv6713/mm/comp_cache Modified Files: main.c proc.c swapin.c swapout.c Log Message: Bug fixes o We were only accounting writeout statistics if the writepage() returned one, but returning zero doesn't mean it has not been written tough (swap_writepage() always returns zero). So, it ended up that we didn't account any writeout page because most writepage() functions return zero. Now we account every written page, no matter the return value. o Fixed CompCache bit assignment, so now we don't have to search compressed cache for every page that gets compressed. Given that, a PageCompCache(page) does not mean it has a fragment in compressed cache, but a !PageCompCache(page) surely doesn't have a fragment. That improves performance. Cleanups o Don't printk initial compressed cache size, only the maximum size o comp_data defined as static in proc.c Index: main.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/main.c,v retrieving revision 1.61 retrieving revision 1.62 diff -C2 -r1.61 -r1.62 *** main.c 31 Jul 2002 12:31:05 -0000 1.61 --- main.c 1 Aug 2002 14:52:25 -0000 1.62 *************** *** 2,6 **** * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-07-29 09:31:05 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-08-01 10:19:51 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 68,75 **** if (!PageLocked(page)) BUG(); ! if (!find_comp_page(page->mapping, page->index, &fragment)) { ! if (!CompFragmentToBeFreed(fragment)) ! BUG(); ! return 0; } --- 68,78 ---- if (!PageLocked(page)) BUG(); ! if (PageCompCache(page)) { ! if (!find_comp_page(page->mapping, page->index, &fragment)) { ! if (!CompFragmentToBeFreed(fragment)) ! BUG(); ! return 0; ! } ! PageClearCompCache(page); } *************** *** 218,226 **** printk("Compressed Cache: %s\n", COMP_CACHE_VERSION); ! printk("Compressed Cache: initial size\n" ! "Compressed Cache: %lu pages = %luKiB\n" ! "Compressed Cache: maximum size\n" "Compressed Cache: %lu pages = %luKiB\n", - init_num_comp_pages, (init_num_comp_pages * COMP_PAGE_SIZE)/1024, max_num_comp_pages, (max_num_comp_pages * COMP_PAGE_SIZE)/1024); --- 221,226 ---- printk("Compressed Cache: %s\n", COMP_CACHE_VERSION); ! printk("Compressed Cache: maximum size\n" "Compressed Cache: %lu pages = %luKiB\n", max_num_comp_pages, (max_num_comp_pages * COMP_PAGE_SIZE)/1024); Index: proc.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/proc.c,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -r1.22 -r1.23 *** proc.c 28 Jul 2002 15:47:04 -0000 1.22 --- proc.c 1 Aug 2002 14:52:25 -0000 1.23 *************** *** 2,6 **** * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-07-28 12:01:51 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-08-01 09:03:16 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 32,36 **** static int current_algorithm = 0; ! struct comp_alg_data comp_data; static spinlock_t comp_data_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; --- 32,36 ---- static int current_algorithm = 0; ! static struct comp_alg_data comp_data; static spinlock_t comp_data_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; Index: swapin.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapin.c,v retrieving revision 1.50 retrieving revision 1.51 diff -C2 -r1.50 -r1.51 *** swapin.c 31 Jul 2002 12:31:05 -0000 1.50 --- swapin.c 1 Aug 2002 14:52:25 -0000 1.51 *************** *** 2,6 **** * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-30 12:21:21 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-08-01 10:06:03 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 42,46 **** spin_lock(&comp_cache_lock); ! if (likely(!PageTestandClearCompCache(page))) goto out_unlock; --- 42,46 ---- spin_lock(&comp_cache_lock); ! if (likely(!PageCompCache(page))) goto out_unlock; *************** *** 49,55 **** * cache entry, what may happen in do_swap_page() */ err = find_comp_page(page->mapping?:&swapper_space, page->index, &fragment); ! ! if (err) goto out_unlock; if (CompFragmentTestandClearDirty(fragment)) { --- 49,56 ---- * cache entry, what may happen in do_swap_page() */ err = find_comp_page(page->mapping?:&swapper_space, page->index, &fragment); ! if (err) { ! PageClearCompCache(page); goto out_unlock; + } if (CompFragmentTestandClearDirty(fragment)) { *************** *** 61,66 **** __set_page_dirty(page); } ! drop_fragment(fragment); ! out_unlock: spin_unlock(&comp_cache_lock); --- 62,68 ---- __set_page_dirty(page); } ! ! if (drop_fragment(fragment)) ! PageClearCompCache(page); out_unlock: spin_unlock(&comp_cache_lock); *************** *** 134,138 **** put_fragment(fragment); ! drop_fragment(fragment); out_unlock: spin_unlock(&comp_cache_lock); --- 136,141 ---- put_fragment(fragment); ! if (!drop_fragment(fragment)) ! PageSetCompCache(page); out_unlock: spin_unlock(&comp_cache_lock); *************** *** 263,270 **** /* effectively free it */ ! drop_fragment(fragment); spin_unlock(&comp_cache_lock); - - PageClearCompCache(page); __set_page_dirty(page); UnlockPage(page); --- 266,272 ---- /* effectively free it */ ! if (drop_fragment(fragment)) ! PageClearCompCache(page); spin_unlock(&comp_cache_lock); __set_page_dirty(page); UnlockPage(page); Index: swapout.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapout.c,v retrieving revision 1.68 retrieving revision 1.69 diff -C2 -r1.68 -r1.69 *** swapout.c 31 Jul 2002 20:48:59 -0000 1.68 --- swapout.c 1 Aug 2002 14:52:25 -0000 1.69 *************** *** 2,6 **** * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-31 16:07:44 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-08-01 09:00:35 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 293,300 **** } ! /* account only those fragments that have been ! * sucessfully written */ ! if (ret) ! comp_cache_update_writeout_stats(fragment); if (nrpages) --- 293,297 ---- } ! comp_cache_update_writeout_stats(fragment); if (nrpages) |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-31 20:49:05
|
Update of /cvsroot/linuxcompressed/linux/mm In directory usw-pr-cvs1:/tmp/cvs-serv28826/mm Modified Files: filemap.c Log Message: Bug fixes: o Compilation error in filemap.c o Clear dirty bit when a swap buffer page fails to be written. Otherwise, once a swap buffer page fails to be written, never again it would free its fragment. Index: filemap.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/filemap.c,v retrieving revision 1.37 retrieving revision 1.38 diff -C2 -r1.37 -r1.38 *** filemap.c 31 Jul 2002 12:31:05 -0000 1.37 --- filemap.c 31 Jul 2002 20:48:59 -0000 1.38 *************** *** 1011,1015 **** { struct page *page = NULL; ! struct page **hash = page_hash(mapping, fragment->index); /* --- 1011,1015 ---- { struct page *page = NULL; ! struct page **hash = page_hash(mapping, offset); /* |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-31 20:49:05
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv28826/mm/comp_cache Modified Files: swapout.c Log Message: Bug fixes: o Compilation error in filemap.c o Clear dirty bit when a swap buffer page fails to be written. Otherwise, once a swap buffer page fails to be written, never again it would free its fragment. Index: swapout.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapout.c,v retrieving revision 1.67 retrieving revision 1.68 diff -C2 -r1.67 -r1.68 *** swapout.c 31 Jul 2002 12:31:05 -0000 1.67 --- swapout.c 31 Jul 2002 20:48:59 -0000 1.68 *************** *** 2,6 **** * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-29 17:18:46 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-31 16:07:44 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 79,82 **** --- 79,83 ---- CompFragmentSetDirty(fragment); } + ClearPageDirty(buffer_page); goto add_to_free; } |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-31 12:31:09
|
Update of /cvsroot/linuxcompressed/linux/mm In directory usw-pr-cvs1:/tmp/cvs-serv23025/mm Modified Files: filemap.c vmscan.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: filemap.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/filemap.c,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -r1.36 -r1.37 *** filemap.c 28 Jul 2002 20:48:32 -0000 1.36 --- filemap.c 31 Jul 2002 12:31:05 -0000 1.37 *************** *** 882,958 **** } - #ifdef CONFIG_COMP_CACHE - /* - * Change the swap cache page index in the page cache data structure, - * specifically the hash queue. It's used by shrink_vswap() when * - * compacting the vswap entries. - */ - void change_index_hash_queue(struct page * page, unsigned long new_index) { - struct buffer_head * buffers; - struct page ** p; - - if (!PageLocked(page)) - BUG(); - - spin_lock(&pagecache_lock); - - /* hack to avoid problems in the function to - * add pages to the hash queue, since it does - * not like pages with buffers */ - buffers = page->buffers; - page->buffers = NULL; - - remove_page_from_hash_queue(page); - page->index = new_index; - p = page_hash(page->mapping, new_index); - add_page_to_hash_queue(page, p); - - page->buffers = buffers; - - spin_unlock(&pagecache_lock); - } - - /* - * The same function as below, but doesn't invalidate the comp cache - */ - void __set_page_dirty(struct page *page) - { - if (!test_and_set_bit(PG_dirty, &page->flags)) { - struct address_space *mapping = page->mapping; - - if (mapping) { - spin_lock(&pagecache_lock); - list_del(&page->list); - list_add(&page->list, &mapping->dirty_pages); - spin_unlock(&pagecache_lock); - - if (mapping->host) - mark_inode_dirty_pages(mapping->host); - } - } - } - - /* caller (lookup_comp_page()) holds the pagecache_lock */ - int find_and_dirty_page(struct page * new_page, struct address_space *mapping, unsigned long offset, struct page **hash) - { - struct page *page = NULL; - - /* - * We scan the hash list read-only. Addition to and removal from - * the hash-list needs a held write-lock. - */ - page = __find_page_nolock(mapping, offset, *hash); - if (page) { - spin_unlock(&pagecache_lock); - __set_page_dirty(page); - return 1; - } - __add_to_page_cache(new_page, mapping, offset, hash); - spin_unlock(&pagecache_lock); - lru_cache_add(new_page); - return 0; - } - #endif - /* * a rather lightweight function, finding and getting a reference to a --- 882,885 ---- *************** *** 1029,1091 **** } /* ! * Same as the above, but lock the page too, verifying that ! * it's still valid once we own it. */ ! struct page * __find_lock_page (struct address_space *mapping, ! unsigned long offset, struct page **hash) ! { ! struct page *page, * cached_page = NULL; - goto repeat; - - repeat: spin_lock(&pagecache_lock); ! page = __find_lock_page_helper(mapping, offset, *hash); spin_unlock(&pagecache_lock); ! #ifdef CONFIG_COMP_PAGE_CACHE ! if (page) ! goto out; ! if (in_comp_cache(mapping, offset)) { ! if (!cached_page) { ! cached_page = page_cache_alloc(mapping); ! goto repeat; ! } ! LockPage(cached_page); ! ! spin_lock(&pagecache_lock); ! /* the page has been added to page cache after we ! * released the pagecache_lock spinlock */ ! if (__find_page_nolock(mapping, offset, *hash)) { spin_unlock(&pagecache_lock); - goto repeat; - } ! /* there are no page in page cache, and we hold the ! * pagecache_lock, so we can decompress the ! * fragment. In the case the fragment has been removed ! * from the compressed cache between in_comp_cache() ! * above and this read_comp_cache(), we won't have ! * problems since we hold pagecache_lock */ ! if (read_comp_cache(mapping, offset, cached_page)) { ! UnlockPage(cached_page); ! spin_unlock(&pagecache_lock); ! goto out; } ! ! page = cached_page; ! cached_page = NULL; ! __add_to_page_cache(page, mapping, offset, hash); spin_unlock(&pagecache_lock); ! lru_cache_add(page); } ! out: #endif - if (cached_page) - page_cache_release(cached_page); return page; } --- 956,1048 ---- } + #ifdef CONFIG_COMP_CACHE /* ! * Change the swap cache page index in the page cache data structure, ! * specifically the hash queue. It's used by shrink_vswap() when * ! * compacting the vswap entries. */ ! void change_index_hash_queue(struct page * page, unsigned long new_index) { ! struct buffer_head * buffers; ! struct page ** p; ! ! if (!PageLocked(page)) ! BUG(); spin_lock(&pagecache_lock); ! ! /* hack to avoid problems in the function to ! * add pages to the hash queue, since it does ! * not like pages with buffers */ ! buffers = page->buffers; ! page->buffers = NULL; ! ! remove_page_from_hash_queue(page); ! page->index = new_index; ! p = page_hash(page->mapping, new_index); ! add_page_to_hash_queue(page, p); ! ! page->buffers = buffers; ! spin_unlock(&pagecache_lock); ! } ! /* ! * The same function as below, but doesn't invalidate the comp cache ! */ ! void __set_page_dirty(struct page *page) ! { ! if (!test_and_set_bit(PG_dirty, &page->flags)) { ! struct address_space *mapping = page->mapping; ! if (mapping) { ! spin_lock(&pagecache_lock); ! list_del(&page->list); ! list_add(&page->list, &mapping->dirty_pages); spin_unlock(&pagecache_lock); ! if (mapping->host) ! mark_inode_dirty_pages(mapping->host); } ! } ! } ! struct page * ! find_or_add_page(struct page * new_page, struct address_space *mapping, unsigned long offset) ! { ! struct page *page = NULL; ! struct page **hash = page_hash(mapping, fragment->index); ! ! /* ! * We scan the hash list read-only. Addition to and removal from ! * the hash-list needs a held write-lock. ! */ ! spin_lock(&pagecache_lock); ! page = __find_lock_page_helper(mapping, offset, *hash); ! if (page) { spin_unlock(&pagecache_lock); ! return page; } ! __add_to_page_cache(new_page, mapping, offset, hash); ! spin_unlock(&pagecache_lock); ! lru_cache_add(new_page); ! return NULL; ! } #endif + /* + * Same as the above, but lock the page too, verifying that + * it's still valid once we own it. + */ + struct page * __find_lock_page (struct address_space *mapping, + unsigned long offset, struct page **hash) + { + struct page *page; + + goto repeat; + + repeat: + spin_lock(&pagecache_lock); + page = __find_lock_page_helper(mapping, offset, *hash); + spin_unlock(&pagecache_lock); return page; } *************** *** 2952,2956 **** err = filler(data, page); - if (err < 0) { page_cache_release(page); --- 2909,2912 ---- *************** *** 3022,3025 **** --- 2978,2984 ---- goto repeat; *cached_page = NULL; + #ifdef CONFIG_COMP_PAGE_CACHE + read_comp_cache(mapping, index, page); + #endif } #ifdef CONFIG_COMP_PAGE_CACHE Index: vmscan.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/vmscan.c,v retrieving revision 1.42 retrieving revision 1.43 diff -C2 -r1.42 -r1.43 *** vmscan.c 28 Jul 2002 15:47:04 -0000 1.42 --- vmscan.c 31 Jul 2002 12:31:05 -0000 1.43 *************** *** 536,539 **** --- 536,544 ---- spin_lock(&pagecache_lock); + if (!is_page_cache_freeable(page)) { + spin_unlock(&pagecache_lock); + UnlockPage(page); + continue; + } } #endif |
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; |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-31 12:31:08
|
Update of /cvsroot/linuxcompressed/linux/include/linux In directory usw-pr-cvs1:/tmp/cvs-serv23025/include/linux Modified Files: comp_cache.h 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: comp_cache.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/comp_cache.h,v retrieving revision 1.97 retrieving revision 1.98 diff -C2 -r1.97 -r1.98 *** comp_cache.h 28 Jul 2002 15:47:04 -0000 1.97 --- comp_cache.h 31 Jul 2002 12:31:05 -0000 1.98 *************** *** 2,6 **** * linux/mm/comp_cache.h * ! * Time-stamp: <2002-07-28 10:08:41 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache.h * ! * Time-stamp: <2002-07-29 09:43:00 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 63,68 **** unsigned short offset; - /* index != 0 && compressed_size == 0 => page stored uncompressed */ - /* index == 0 && compressed_size != 0 => compressed_size = free_space */ unsigned short compressed_size; unsigned long flags; --- 63,66 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 20:48:36
|
Update of /cvsroot/linuxcompressed/linux/mm In directory usw-pr-cvs1:/tmp/cvs-serv5964/mm Modified Files: filemap.c Log Message: Bug fix: o Fixed potential deadlock in find_and_dirty()/lookup_comp_pages() which wouldn't unlock a spin_lock (pagecache_lock). Index: filemap.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/filemap.c,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -r1.35 -r1.36 *** filemap.c 28 Jul 2002 15:47:04 -0000 1.35 --- filemap.c 28 Jul 2002 20:48:32 -0000 1.36 *************** *** 944,947 **** --- 944,948 ---- page = __find_page_nolock(mapping, offset, *hash); if (page) { + spin_unlock(&pagecache_lock); __set_page_dirty(page); return 1; *************** *** 950,954 **** spin_unlock(&pagecache_lock); lru_cache_add(new_page); - spin_lock(&pagecache_lock); return 0; } --- 951,954 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 20:48:36
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv5964/mm/comp_cache Modified Files: swapin.c Log Message: Bug fix: o Fixed potential deadlock in find_and_dirty()/lookup_comp_pages() which wouldn't unlock a spin_lock (pagecache_lock). Index: swapin.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapin.c,v retrieving revision 1.48 retrieving revision 1.49 diff -C2 -r1.48 -r1.49 *** swapin.c 28 Jul 2002 15:47:04 -0000 1.48 --- swapin.c 28 Jul 2002 20:48:32 -0000 1.49 *************** *** 2,6 **** * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-27 18:55:37 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-28 17:34:57 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 255,259 **** get_fragment(fragment); - spin_unlock(&pagecache_lock); spin_unlock(&comp_cache_lock); --- 255,258 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 15:58:27
|
Update of /cvsroot/linuxcompressed/linux/Documentation In directory usw-pr-cvs1:/tmp/cvs-serv29058/Documentation Modified Files: Configure.help Log Message: Other o Update Configure.help documentation Index: Configure.help =================================================================== RCS file: /cvsroot/linuxcompressed/linux/Documentation/Configure.help,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -r1.9 -r1.10 *** Configure.help 16 Jul 2002 18:41:54 -0000 1.9 --- Configure.help 28 Jul 2002 15:58:23 -0000 1.10 *************** *** 386,393 **** system performance. ! Initial number of pages reserved for compressed cache is set by the ! kernel parameter "compsize=N", where N is a memory size like the input accepted by "mem=" parameter. For example "compsize=48M" sets ! the initial compressed cache size to 48 megabytes. If unsure, say N here. --- 386,394 ---- system performance. ! The maximum number of pages reserved for compressed cache is set by ! the kernel parameter "compsize=N", where N is a memory size like the input accepted by "mem=" parameter. For example "compsize=48M" sets ! the maximum compressed cache size to 48 megabytes. It resizes by ! itself as much as it is actually needed (ie, resizes on demand). If unsure, say N here. *************** *** 402,427 **** If unsure, say N here. - - Resize Compressed Cache On Demand - CONFIG_COMP_DEMAND_RESIZE - - Select this option in case you want compressed cache to start with a - minimum number of pages and resize on demand. It means that - compressed cache will grow uo to its maximum size while the system - is under memory pressure and will only start swapping out when it - reaches that size. As soon as the reserved pages for compressed - cache are no longer used, they are freed to the system, decreasing - compressed cache size. - - The maximum size is defined by the very same kernel parameter - "compsize=N", where N is a memory size like the input accepted by - "mem=" parameter. For example "compsize=48M" will set the maximum - compressed cache size to 48 megabytes. - - In the case this option is enabled, the user cannot any longer - change compressed cache size via sysctl entry - (/proc/sys/vm/comp_cache/size). - - If unsure, say Y here. Double Page Size --- 403,406 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 15:47:08
|
Update of /cvsroot/linuxcompressed/linux/mm/comp_cache In directory usw-pr-cvs1:/tmp/cvs-serv26313/mm/comp_cache Modified Files: WK4x4.c WKdm.c adaptivity.c aux.c free.c main.c proc.c swapin.c swapout.c vswap.c Log Message: Features o First page cache support for preempted kernels is implemented. o Fragments have a "count" field that stores the number of references to the fragment, so we don't have to worry about it getting freed in the middle of an operation. That tries to fix a highly potential source of bugs. Bug fixes o Fix memory accountancy for double page sizes. Meminfo was broken for 8K pages. o truncate_list_comp_pages() could try to truncate fragments that were in locked_comp_pages list, which is bogus. Only swap buffers list are on this list, and are listed there only for wait_comp_pages(). o when writing out fragments, we didn't pay attention to the return value, so we may end up freeing a fragment (when refilling swap buffer) even if the writepage failed. In particular, ramfs, ramdisk and other memory file systems always fail to write out its pages. Now we check if the swap buffer page has been set dirty (the writepage() usually does that after failing to write a page), moving back the fragment to the dirty list (and of course not freeing the fragment). o fixed bug that would corrupt the swap buffer list. A bug in the variable that returned the error code could return error even if a fragment was found afterall, so the caller function would backout the writeout operation, leaving the swap buffer locked on the used list, and it wouldn't never get unlocked. o account writeout stats only for pages that have been actually submitted to IO operation. o fixed bug that would deadlock a system with comp_cache that has page cache support. The lookup_comp_pages() function may be called from the following code path: __sync_one() -> filemap_fdatasync(). This code path tries to sync an inode (and keeps it locked while it is syncing). However, that very inode can be also in the clear path (clear_inode() function, called in the exit process path) which will lock the super block and then wait for inode if it is locked (what happens with an inode syncing). Since the allocation path may write pages, which may need to lock the same super block, it will deadlock, because the super block is locked by the exit path explained above. So, we end up not being able to allocate the page (in order to finish this function and unlock the inode) _and_ the super block won't be unlocked since the inode doesn't get unlocked either. The fix was to allocate pages with GFP_NOFS mask. Cleanups o Some functions were renamed. o Compression algorithms (removed unnecessary data structures that were allocated, made some structures to be allocated statically in the algorithms, some data statically allocated are now kmalloc()) o Removed /proc/sys/vm/comp_cache/actual_size, it doesn't make sense with resizing on demand. Others o Compressed cache only resizes on demand. Index: WK4x4.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/WK4x4.c,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** WK4x4.c 19 Jun 2002 12:18:44 -0000 1.3 --- WK4x4.c 28 Jul 2002 15:47:04 -0000 1.4 *************** *** 258,268 **** WK_word* destinationBuffer, unsigned int words, ! void *page) { ! DictionaryElement *dictionary = ((struct comp_alg_data *)page)->dictionary; ! unsigned int *hashTable = ((struct comp_alg_data *)page)->hashLookupTable_WK4x4; ! ! /*DictionaryElement dictionary[DICTIONARY_SIZE]; ! unsigned int hashTable [] = HASH_LOOKUP_TABLE_CONTENTS_WK4x4;*/ int wordIndex; unsigned int remainingBits = BITS_PER_WORD; --- 258,265 ---- WK_word* destinationBuffer, unsigned int words, ! struct comp_alg_data * data) { ! DictionaryElement dictionary[DICTIONARY_SIZE]; ! unsigned int hashTable [] = HASH_LOOKUP_TABLE_CONTENTS_WK4x4; int wordIndex; unsigned int remainingBits = BITS_PER_WORD; *************** *** 273,278 **** PRELOAD_DICTIONARY; - //printk("WK4x4\n"); - /* Loop through each word in the source page. */ for (wordIndex = 0; wordIndex < words; wordIndex++) { --- 270,273 ---- *************** *** 418,422 **** WK_word* destinationBuffer, unsigned int words, ! void * page) { /* The dictionary array is divided into sets. Each entry in the dictionary array is really an entry in one of the dictionary's --- 413,418 ---- WK_word* destinationBuffer, unsigned int words, ! struct comp_alg_data * data) ! { /* The dictionary array is divided into sets. Each entry in the dictionary array is really an entry in one of the dictionary's *************** *** 426,433 **** which that set begins in the dictionary array. */ ! /*DictionaryElement dictionary[DICTIONARY_SIZE]; ! unsigned int hashTable [] = HASH_LOOKUP_TABLE_CONTENTS_WK4x4;*/ ! DictionaryElement *dictionary = ((struct comp_alg_data *)page)->dictionary; ! unsigned int *hashTable = ((struct comp_alg_data *)page)->hashLookupTable_WK4x4; unsigned int initialIndexTable [] = INITIAL_INDEX_TABLE_CONTENTS; --- 422,427 ---- which that set begins in the dictionary array. */ ! DictionaryElement dictionary[DICTIONARY_SIZE]; ! unsigned int hashTable [] = HASH_LOOKUP_TABLE_CONTENTS_WK4x4; unsigned int initialIndexTable [] = INITIAL_INDEX_TABLE_CONTENTS; Index: WKdm.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/WKdm.c,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** WKdm.c 19 Jun 2002 12:18:44 -0000 1.3 --- WKdm.c 28 Jul 2002 15:47:04 -0000 1.4 *************** *** 40,43 **** --- 40,44 ---- /* Included files */ + #include <linux/slab.h> #include <linux/comp_cache.h> #include <linux/WKcommon.h> *************** *** 383,392 **** WK_word* dest_buf, unsigned int num_input_words, ! void *page) { ! /* DictionaryElement dictionary[DICTIONARY_SIZE]; ! char hashLookupTable [] = HASH_LOOKUP_TABLE_CONTENTS; */ ! DictionaryElement *dictionary = ((struct comp_alg_data *)page)->dictionary; ! char *hashLookupTable = ((struct comp_alg_data *)page)->hashLookupTable_WKdm; /* arrays that hold output data in intermediate form during modeling */ --- 384,391 ---- WK_word* dest_buf, unsigned int num_input_words, ! struct comp_alg_data * data) { ! DictionaryElement dictionary[DICTIONARY_SIZE]; ! char hashLookupTable [] = HASH_LOOKUP_TABLE_CONTENTS_WKDM; /* arrays that hold output data in intermediate form during modeling */ *************** *** 396,406 **** * pages larger than 4KB */ ! ! /* WK_word tempTagsArray[300]; tags for everything */ ! /* WK_word tempQPosArray[300]; queue positions for matches */ ! /* WK_word tempLowBitsArray[1200]; low bits for partial matches */ ! WK_word *tempTagsArray = ((struct comp_alg_data *)page)->tempTagsArray; ! WK_word *tempQPosArray = ((struct comp_alg_data *)page)->tempQPosArray; ! WK_word *tempLowBitsArray = ((struct comp_alg_data *)page)->tempLowBitsArray; /* boundary_tmp will be used for keeping track of what's where in --- 395,401 ---- * pages larger than 4KB */ ! WK_word * tempTagsArray = data->tempTagsArray; ! WK_word * tempQPosArray = data->tempQPosArray; ! WK_word * tempLowBitsArray = data->tempLowBitsArray; /* boundary_tmp will be used for keeping track of what's where in *************** *** 423,429 **** PRELOAD_DICTIONARY; ! ! //printk("WKDM\n"); ! next_full_patt = dest_buf + TAGS_AREA_OFFSET + (num_input_words / 16); --- 418,422 ---- PRELOAD_DICTIONARY; ! next_full_patt = dest_buf + TAGS_AREA_OFFSET + (num_input_words / 16); *************** *** 621,625 **** } - return ((char *) boundary_tmp - (char *) dest_buf); --- 614,617 ---- *************** *** 638,648 **** WK_word* dest_buf, unsigned int words, ! void *page) { ! ! /*DictionaryElement dictionary[DICTIONARY_SIZE]; ! unsigned int hashLookupTable [] = HASH_LOOKUP_TABLE_CONTENTS_WKDM;*/ ! DictionaryElement *dictionary = ((struct comp_alg_data *)page)->dictionary; ! char *hashLookupTable = ((struct comp_alg_data *)page)->hashLookupTable_WKdm; /* arrays that hold output data in intermediate form during modeling */ --- 630,638 ---- WK_word* dest_buf, unsigned int words, ! struct comp_alg_data * data) ! { + DictionaryElement dictionary[DICTIONARY_SIZE]; + unsigned int hashLookupTable [] = HASH_LOOKUP_TABLE_CONTENTS_WKDM; /* arrays that hold output data in intermediate form during modeling */ *************** *** 652,664 **** * pages larger than 4KB */ ! //WK_word tempTagsArray[300]; /* tags for everything */ ! //WK_word tempQPosArray[300]; /* queue positions for matches */ ! //WK_word tempLowBitsArray[1200]; /* low bits for partial matches */ ! WK_word *tempTagsArray = ((struct comp_alg_data *)page)->tempTagsArray; ! WK_word *tempQPosArray = ((struct comp_alg_data *)page)->tempQPosArray; ! WK_word *tempLowBitsArray = ((struct comp_alg_data *)page)->tempLowBitsArray; PRELOAD_DICTIONARY; #ifdef WK_DEBUG --- 642,658 ---- * pages larger than 4KB */ ! WK_word * tempTagsArray = data->tempTagsArray; ! WK_word * tempQPosArray = data->tempQPosArray; ! WK_word * tempLowBitsArray = data->tempLowBitsArray; PRELOAD_DICTIONARY; + + if (!tempTagsArray) + BUG(); + if (!tempQPosArray) + BUG(); + if (!tempLowBitsArray) + BUG(); #ifdef WK_DEBUG Index: adaptivity.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/adaptivity.c,v retrieving revision 1.37 retrieving revision 1.38 diff -C2 -r1.37 -r1.38 *** adaptivity.c 18 Jul 2002 21:31:08 -0000 1.37 --- adaptivity.c 28 Jul 2002 15:47:04 -0000 1.38 *************** *** 2,6 **** * linux/mm/comp_cache/adaptivity.c * ! * Time-stamp: <2002-07-18 15:44:59 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/adaptivity.c * ! * Time-stamp: <2002-07-26 17:22:32 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 501,505 **** * caller must hold comp_cache_lock lock */ ! int shrink_comp_cache(struct comp_cache_page * comp_page, int check_further) { --- 501,505 ---- * caller must hold comp_cache_lock lock */ ! static int shrink_comp_cache(struct comp_cache_page * comp_page, int check_further) { *************** *** 578,582 **** } - #ifdef CONFIG_COMP_DEMAND_RESIZE /*** * shrink_on_demand(comp_page) - called by comp_cache_free(), it will --- 578,581 ---- *************** *** 606,610 **** return 0; } - #endif #define comp_cache_needs_to_grow() (new_num_comp_pages > num_comp_pages) --- 605,608 ---- *************** *** 630,634 **** } ! int grow_comp_cache(int nrpages) { --- 628,632 ---- } ! static int grow_comp_cache(int nrpages) { *************** *** 677,681 **** } - #ifdef CONFIG_COMP_DEMAND_RESIZE /*** * grow_on_demand(void) - called by get_comp_cache_page() when it --- 675,678 ---- *************** *** 703,707 **** return 0; } - #endif void __init --- 700,703 ---- Index: aux.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/aux.c,v retrieving revision 1.41 retrieving revision 1.42 diff -C2 -r1.41 -r1.42 *** aux.c 18 Jul 2002 21:31:08 -0000 1.41 --- aux.c 28 Jul 2002 15:47:04 -0000 1.42 *************** *** 2,6 **** * linux/mm/comp_cache/aux.c * ! * Time-stamp: <2002-07-18 14:14:42 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/aux.c * ! * Time-stamp: <2002-07-28 11:55:38 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 268,272 **** fragment = list_entry(fragment_lh, struct comp_cache_fragment, list); ! if (CompFragmentFreed(fragment)) fragmented_space += fragment->compressed_size; } --- 268,272 ---- fragment = list_entry(fragment_lh, struct comp_cache_fragment, list); ! if (fragment_freed(fragment)) fragmented_space += fragment->compressed_size; } *************** *** 427,431 **** } ! /* adapted version of __find_page_nolock:filemap.c */ int FASTCALL(find_comp_page(struct address_space *, unsigned long, struct comp_cache_fragment **)); int find_comp_page(struct address_space * mapping, unsigned long offset, struct comp_cache_fragment ** fragment) --- 427,432 ---- } ! /* adapted version of __find_page_nolock:filemap.c ! * caller must hold comp_cache_hold */ int FASTCALL(find_comp_page(struct address_space *, unsigned long, struct comp_cache_fragment **)); int find_comp_page(struct address_space * mapping, unsigned long offset, struct comp_cache_fragment ** fragment) *************** *** 465,469 **** { struct comp_cache_fragment * fragment; ! return !find_comp_page(mapping, offset, &fragment); } --- 466,475 ---- { struct comp_cache_fragment * fragment; ! int ret; ! ! spin_lock(&comp_cache_lock); ! ret = !find_comp_page(mapping, offset, &fragment); ! spin_unlock(&comp_cache_lock); ! return ret; } Index: free.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/free.c,v retrieving revision 1.43 retrieving revision 1.44 diff -C2 -r1.43 -r1.44 *** free.c 18 Jul 2002 21:31:08 -0000 1.43 --- free.c 28 Jul 2002 15:47:04 -0000 1.44 *************** *** 2,6 **** * linux/mm/comp_cache/free.c * ! * Time-stamp: <2002-07-18 16:20:01 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/free.c * ! * Time-stamp: <2002-07-28 10:21:04 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 35,46 **** return; ! if (CompFragmentFreed(right_fragment)) { fragment_to_free->compressed_size += right_fragment->compressed_size; list_del(&(right_fragment->list)); ! ! if (!CompFragmentTestandClearIO(right_fragment)) ! kmem_cache_free(fragment_cachep, (right_fragment)); ! ! } } --- 35,42 ---- return; ! if (fragment_freed(right_fragment)) { fragment_to_free->compressed_size += right_fragment->compressed_size; list_del(&(right_fragment->list)); ! kmem_cache_free(fragment_cachep, (right_fragment)); } } *************** *** 52,63 **** return; ! if (CompFragmentFreed(left_fragment)) { fragment_to_free->offset = left_fragment->offset; fragment_to_free->compressed_size += left_fragment->compressed_size; list_del(&(left_fragment->list)); ! ! if (!CompFragmentTestandClearIO(left_fragment)) ! kmem_cache_free(fragment_cachep, (left_fragment)); } } --- 48,57 ---- return; ! if (fragment_freed(left_fragment)) { fragment_to_free->offset = left_fragment->offset; fragment_to_free->compressed_size += left_fragment->compressed_size; list_del(&(left_fragment->list)); ! kmem_cache_free(fragment_cachep, (left_fragment)); } } *************** *** 66,79 **** remove_fragment_from_comp_cache(struct comp_cache_fragment * fragment) { ! remove_fragment_vswap(fragment); ! remove_fragment_from_hash_table(fragment); ! remove_fragment_from_lru_queue(fragment); list_del_init(&fragment->mapping_list); fragment->mapping->nrpages--; if (PageSwapCache(fragment)) num_swapper_fragments--; num_fragments--; comp_cache_free_space += fragment->compressed_size; ! fragment->comp_page->total_free_space += fragment->compressed_size; } --- 60,96 ---- remove_fragment_from_comp_cache(struct comp_cache_fragment * fragment) { ! if (!fragment->mapping) ! BUG(); ! ! /* fragments that have already been submitted to IO have a ! * non-null swp_buffer. Let's warn the swap buffer that this ! * page has been already removed by setting its fragment field ! * to NULL and also let's wait for the IO to finish. */ ! if (fragment->swp_buffer) { ! fragment->swp_buffer->fragment = NULL; ! wait_on_page(fragment->swp_buffer->page); ! } ! ! /* 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 + * separately to display sane values in /proc/meminfo */ if (PageSwapCache(fragment)) num_swapper_fragments--; num_fragments--; + + /* total free space in compressed cache */ comp_cache_free_space += fragment->compressed_size; ! ! /* used to know a fragment with zero count is actually freed ! * or waiting to be freed (like when sleeping to lock its page ! * in comp_cache_free()) */ ! fragment->mapping = NULL; ! ! /* debug */ ! fragment->index = 0; } *************** *** 91,99 **** fragment = list_entry(fragment_lh, struct comp_cache_fragment, list); ! if (CompFragmentFreed(fragment)) { list_del(&(fragment->list)); comp_page->free_space += fragment->compressed_size; ! if (!CompFragmentTestandClearIO(fragment)) ! kmem_cache_free(fragment_cachep, (fragment)); continue; } --- 108,115 ---- fragment = list_entry(fragment_lh, struct comp_cache_fragment, list); ! if (fragment_freed(fragment)) { list_del(&(fragment->list)); comp_page->free_space += fragment->compressed_size; ! kmem_cache_free(fragment_cachep, (fragment)); continue; } *************** *** 140,144 **** /* caller must hold comp_cache_lock lock */ ! void comp_cache_free_locked(struct comp_cache_fragment * fragment) { --- 156,160 ---- /* caller must hold comp_cache_lock lock */ ! static void comp_cache_free_locked(struct comp_cache_fragment * fragment) { *************** *** 166,169 **** --- 182,189 ---- remove_fragment_from_comp_cache(fragment); + fragment->comp_page->total_free_space += fragment->compressed_size; + + if (fragment->mapping) + BUG(); /* simple case - no free space *************** *** 188,198 **** } - /* we have used fragment(s) between the free space and the one we want to free */ - if (CompFragmentTestandSetFreed(fragment)) - BUG(); - - /* debug only */ - fragment->mapping = NULL; - merge_right_neighbour(fragment, next_fragment); merge_left_neighbour(fragment, previous_fragment); --- 208,211 ---- *************** *** 209,218 **** comp_page->free_space += fragment->compressed_size; ! /* is this fragment waiting for swap out? let's not free it ! * now, but let's tell swap out path that it does not need IO ! * anymore because it has been freed (maybe due to swapin) */ ! if (!CompFragmentTestandClearIO(fragment)) ! kmem_cache_free(fragment_cachep, (fragment)); ! out: add_comp_page_to_hash_table(comp_page); --- 222,226 ---- comp_page->free_space += fragment->compressed_size; ! kmem_cache_free(fragment_cachep, (fragment)); out: add_comp_page_to_hash_table(comp_page); *************** *** 220,250 **** /* caller must hold comp_cache_lock lock */ ! void comp_cache_free(struct comp_cache_fragment * fragment) { struct comp_cache_page * comp_page; - struct page * page; - int locked = 0; if (!fragment) BUG(); comp_page = fragment->comp_page; - if (comp_page->page) { - locked = !TryLockPage(comp_page->page); - page = comp_page->page; - } comp_cache_free_locked(fragment); ! /* steal the page if we need to shrink the cache. The ! * page will be unlocked in shrink_comp_cache() ! * function */ ! if (locked) { ! #ifdef CONFIG_COMP_DEMAND_RESIZE ! shrink_on_demand(comp_page); ! #else ! shrink_comp_cache(comp_page, 1); ! #endif ! } } --- 228,266 ---- /* caller must hold comp_cache_lock lock */ ! static void comp_cache_free(struct comp_cache_fragment * fragment) { struct comp_cache_page * comp_page; if (!fragment) BUG(); + remove_fragment_vswap(fragment); + remove_fragment_from_hash_table(fragment); + remove_fragment_from_lru_queue(fragment); comp_page = fragment->comp_page; + spin_unlock(&comp_cache_lock); + lock_page(comp_page->page); + spin_lock(&comp_cache_lock); + comp_cache_free_locked(fragment); ! /* steal the page if we need to shrink the cache. The page ! * will be unlocked in shrink_comp_cache() (even if shrinking ! * on demand, shrink_on_demand() will call it anyway) */ ! shrink_on_demand(comp_page); ! } ! ! /* caller must hold comp_cache_lock lock */ ! int ! __comp_cache_free(struct comp_cache_fragment * fragment) { ! int zero; ! ! if (!fragment_count(fragment)) ! BUG(); ! ! if ((zero = put_fragment_testzero(fragment))) ! comp_cache_free(fragment); ! return zero; } *************** *** 316,321 **** --- 332,339 ---- goto backout; + spin_lock(&comp_cache_lock); remove_fragment_vswap(fragment); remove_fragment_from_hash_table(fragment); + spin_unlock(&comp_cache_lock); /* remove all those ptes from vswap struct */ *************** *** 357,363 **** --- 375,383 ---- fragment->index = entry.val; + spin_lock(&comp_cache_lock); add_fragment_to_lru_queue(fragment); add_fragment_to_hash_table(fragment); UnlockPage(fragment->comp_page->page); + spin_unlock(&comp_cache_lock); out_unlock: spin_unlock(&virtual_swap_list); Index: main.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/main.c,v retrieving revision 1.59 retrieving revision 1.60 diff -C2 -r1.59 -r1.60 *** main.c 18 Jul 2002 21:31:08 -0000 1.59 --- main.c 28 Jul 2002 15:47:04 -0000 1.60 *************** *** 2,6 **** * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-07-18 13:19:51 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/main.c * ! * Time-stamp: <2002-07-28 10:04:28 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 51,112 **** spinlock_t comp_cache_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; ! inline void ! compress_dirty_page(struct page * page, int (*writepage)(struct page *), unsigned int gfp_mask, int priority) ! { ! int write, ret; ! ! write = !!page->buffers; ! #ifdef CONFIG_COMP_PAGE_CACHE ! write |= shmem_page(page); ! #else ! write |= !PageSwapCache(page); ! #endif ! if (write) { ! /* if gfp_mask does not allow us to write out the ! * page, unlock the page and set all the bits back */ ! if (!(gfp_mask & __GFP_FS)) { ! UnlockPage(page); ! goto set_bits_back; ! } ! writepage(page); ! return; ! } ! ! if (page->buffers) ! BUG(); ! ! spin_lock(&comp_cache_lock); ! ret = compress_page(page, 1, gfp_mask, priority); ! spin_unlock(&comp_cache_lock); ! ! /* failed to compress the dirty page? set the bits back */ ! if (ret) ! return; ! set_bits_back: ! SetPageDirty(page); ! ClearPageLaunder(page); ! } ! ! inline int ! compress_clean_page(struct page * page, unsigned int gfp_mask, int priority) ! { ! int ret; ! ! if (page->buffers) ! BUG(); ! ! #ifndef CONFIG_COMP_PAGE_CACHE ! if (!PageSwapCache(page)) ! return 1; ! #endif ! spin_lock(&comp_cache_lock); ! ret = compress_page(page, 0, gfp_mask, priority); ! spin_unlock(&comp_cache_lock); ! ! return ret; ! } ! ! int ! compress_page(struct page * page, int dirty, unsigned int gfp_mask, int priority) { struct comp_cache_page * comp_page; --- 51,56 ---- spinlock_t comp_cache_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; ! static int ! compress_page(struct page * page, int state, unsigned int gfp_mask, int priority) { struct comp_cache_page * comp_page; *************** *** 124,134 **** if (!PageLocked(page)) BUG(); ! if (PageTestandClearCompCache(page)) { ! if (!dirty) BUG(); ! __invalidate_comp_cache(page->mapping, page->index); } ! comp_size = compress(current_compressed_page = page, buffer_compressed = (unsigned long *) &buffer_compressed1, &algorithm, dirty); comp_page = get_comp_cache_page(page, comp_size, &fragment, gfp_mask, priority); --- 68,79 ---- if (!PageLocked(page)) BUG(); ! if (!find_comp_page(page->mapping, page->index, &fragment)) { ! if (!CompFragmentToBeFreed(fragment)) BUG(); ! return 0; } + ! 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); *************** *** 148,152 **** /* fix mapping stuff */ page->mapping->nrpages++; ! if (!dirty) { list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); goto copy_page; --- 93,97 ---- /* fix mapping stuff */ page->mapping->nrpages++; ! if (state != DIRTY_PAGE) { list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); goto copy_page; *************** *** 164,168 **** if (compressed(fragment)) { if (current_compressed_page != page) ! compress(page, buffer_compressed = (unsigned long *) &buffer_compressed2, &algorithm, dirty); memcpy(page_address(comp_page->page) + fragment->offset, buffer_compressed , fragment->compressed_size); } else --- 109,113 ---- if (compressed(fragment)) { if (current_compressed_page != page) ! compress(page, buffer_compressed = (unsigned long *) &buffer_compressed2, &algorithm, state); memcpy(page_address(comp_page->page) + fragment->offset, buffer_compressed , fragment->compressed_size); } else *************** *** 175,178 **** --- 120,181 ---- } + int + compress_dirty_page(struct page * page, int (*writepage)(struct page *), unsigned int gfp_mask, int priority) + { + int write, ret = 0; + + write = !!page->buffers; + #ifdef CONFIG_COMP_PAGE_CACHE + write |= shmem_page(page); + #else + write |= !PageSwapCache(page); + #endif + if (write) { + /* if gfp_mask does not allow us to write out the + * page, unlock the page and set all the bits back */ + if (!(gfp_mask & __GFP_FS)) + goto set_bits_back; + writepage(page); + return 0; + } + + if (page->buffers) + BUG(); + + spin_lock(&comp_cache_lock); + ret = compress_page(page, DIRTY_PAGE, gfp_mask, priority); + spin_unlock(&comp_cache_lock); + + /* failed to compress the dirty page? set the bits back */ + if (!ret) { + set_bits_back: + spin_lock(&pagemap_lru_lock); + SetPageDirty(page); + ClearPageLaunder(page); + UnlockPage(page); + spin_unlock(&pagemap_lru_lock); + } + return ret; + } + + int + compress_clean_page(struct page * page, unsigned int gfp_mask, int priority) + { + int ret; + + if (page->buffers) + BUG(); + + #ifndef CONFIG_COMP_PAGE_CACHE + if (!PageSwapCache(page)) + return 1; + #endif + spin_lock(&comp_cache_lock); + ret = compress_page(page, CLEAN_PAGE, gfp_mask, priority); + spin_unlock(&comp_cache_lock); + + return ret; + } + extern void __init comp_cache_hash_init(void); extern void __init comp_cache_swp_buffer_init(void); *************** *** 206,214 **** int i; - #ifdef CONFIG_COMP_DEMAND_RESIZE min_num_comp_pages = page_to_comp_page(48); - #else - min_num_comp_pages = page_to_comp_page((unsigned long) (num_physpages * 0.05)); - #endif if (!max_num_comp_pages || max_num_comp_pages < min_num_comp_pages || max_num_comp_pages > num_physpages * 0.5) --- 209,213 ---- *************** *** 264,272 **** nr_pages = memparse(str, &endp) >> (PAGE_SHIFT + comp_page_order); - #ifdef CONFIG_COMP_DEMAND_RESIZE max_num_comp_pages = nr_pages; - #else - init_num_comp_pages = nr_pages; - #endif return 1; } --- 263,267 ---- Index: proc.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/proc.c,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -r1.21 -r1.22 *** proc.c 16 Jul 2002 21:58:08 -0000 1.21 --- proc.c 28 Jul 2002 15:47:04 -0000 1.22 *************** *** 2,6 **** * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-07-16 16:32:43 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/proc.c * ! * Time-stamp: <2002-07-28 12:01:51 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 32,76 **** static int current_algorithm = 0; ! /* data used for compression */ ! static struct comp_alg_data comp_data; ! static WK_word compresseddata[1200]; ! static WK_word decompresseddata[1200]; ! static WK_word compressedtempTagsArray[300]; ! static WK_word compressedtempQPosArray[300]; ! static WK_word compressedtempLowBitsArray[1200]; ! ! static char compressedhashLookupTable_WKdm [] = HASH_LOOKUP_TABLE_CONTENTS_WKDM; ! static unsigned int compressedhashLookupTable_WK4x4 [] = HASH_LOOKUP_TABLE_CONTENTS_WK4x4; ! static DictionaryElement compresseddictionary[DICTIONARY_SIZE]; ! ! lzo_byte * wrkmem; enum { CC_SIZE=1, ! CC_ACTUAL_SIZE=2, ! CC_ALGORITHM=3 }; ctl_table comp_cache_table[] = { ! {CC_SIZE, "size", &new_num_comp_pages, sizeof(int), ! #ifdef CONFIG_COMP_DEMAND_RESIZE ! 0444, ! #else ! 0644, ! #endif ! NULL, ! &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_num_comp_pages, ! &max_num_comp_pages}, ! {CC_ACTUAL_SIZE, "actual_size", &num_comp_pages, sizeof(int), 0444, NULL, &proc_dointvec}, {CC_ALGORITHM, "algorithm", ¤t_algorithm, sizeof(int), 0644, NULL, ! &proc_dointvec_minmax, &sysctl_intvec, NULL, &algorithm_min, ! &algorithm_max}, {0} }; ! inline void ! comp_cache_update_page_stats(struct page * page, int dirty) { #ifdef CONFIG_COMP_PAGE_CACHE --- 32,54 ---- static int current_algorithm = 0; ! struct comp_alg_data comp_data; ! static spinlock_t comp_data_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; enum { CC_SIZE=1, ! CC_ALGORITHM=2 }; ctl_table comp_cache_table[] = { ! {CC_SIZE, "size", &num_comp_pages, sizeof(int), 0444, NULL, &proc_dointvec}, {CC_ALGORITHM, "algorithm", ¤t_algorithm, sizeof(int), 0644, NULL, ! &proc_dointvec_minmax, &sysctl_intvec, NULL, &algorithm_min, &algorithm_max}, {0} }; ! static inline void ! comp_cache_update_page_stats(struct page * page, int state) { #ifdef CONFIG_COMP_PAGE_CACHE *************** *** 80,84 **** #endif compression_algorithms[current_algorithm].stats.comp_swap++; ! if (dirty) compression_algorithms[current_algorithm].stats.comp_dirty++; else --- 58,62 ---- #endif compression_algorithms[current_algorithm].stats.comp_swap++; ! if (state == DIRTY_PAGE) compression_algorithms[current_algorithm].stats.comp_dirty++; else *************** *** 87,91 **** static void ! comp_cache_update_comp_stats(struct stats_page * comp_page_stats, struct page * page, int dirty) { struct comp_alg * algorithm = &compression_algorithms[current_algorithm]; --- 65,69 ---- static void ! comp_cache_update_comp_stats(struct stats_page * comp_page_stats, struct page * page, int state) { struct comp_alg * algorithm = &compression_algorithms[current_algorithm]; *************** *** 113,117 **** stats->comp_cycles_sum += comp_page_stats->comp_cycles; ! comp_cache_update_page_stats(page, dirty); } --- 91,95 ---- stats->comp_cycles_sum += comp_page_stats->comp_cycles; ! comp_cache_update_page_stats(page, state); } *************** *** 180,189 **** static unsigned int ! lzo_wrapper_compress(unsigned long * from, unsigned long * to, unsigned int words, void * page) { int error; lzo_uint out_len; ! error = lzo1x_1_compress((lzo_byte *) from, words * sizeof(unsigned long), (lzo_byte *) to, &out_len, wrkmem); if (error != LZO_E_OK) --- 158,167 ---- static unsigned int ! lzo_wrapper_compress(unsigned long * from, unsigned long * to, unsigned int words, struct comp_alg_data * data) { int error; lzo_uint out_len; ! error = lzo1x_1_compress((lzo_byte *) from, words * sizeof(unsigned long), (lzo_byte *) to, &out_len, data->wrkmem); if (error != LZO_E_OK) *************** *** 194,203 **** static void ! lzo_wrapper_decompress(unsigned long * from, unsigned long * to, unsigned int words, void * page) { ! int error; lzo_uint new_len; ! error = lzo1x_decompress((lzo_byte *) from, ((struct comp_alg_data *) page)->compressed_size, (lzo_byte *) to, &new_len, NULL); if (error != LZO_E_OK || new_len != PAGE_SIZE) { --- 172,181 ---- static void ! lzo_wrapper_decompress(unsigned long * from, unsigned long * to, unsigned int words, struct comp_alg_data * data) { ! int error; lzo_uint new_len; ! error = lzo1x_decompress((lzo_byte *) from, data->compressed_size, (lzo_byte *) to, &new_len, NULL); if (error != LZO_E_OK || new_len != PAGE_SIZE) { *************** *** 208,212 **** int ! compress(struct page * page, void * to, unsigned short * algorithm, int dirty) { struct stats_page comp_page_stats; --- 186,190 ---- int ! compress(struct page * page, void * to, unsigned short * algorithm, int state) { struct stats_page comp_page_stats; *************** *** 222,230 **** } #endif ! START_ZEN_TIME(comp_page_stats.myTimer); ! comp_page_stats.comp_size = compression_algorithms[current_algorithm].comp(from, to, PAGE_SIZE/4, (void *)(&comp_data)); ! STOP_ZEN_TIME(comp_page_stats.myTimer, comp_page_stats.comp_cycles); ! comp_cache_update_comp_stats(&comp_page_stats, page, dirty); *algorithm = current_algorithm; --- 200,210 ---- } #endif ! ! spin_lock(&comp_data_lock); START_ZEN_TIME(comp_page_stats.myTimer); ! comp_page_stats.comp_size = compression_algorithms[current_algorithm].comp(from, to, PAGE_SIZE/4, &comp_data); ! STOP_ZEN_TIME(comp_page_stats.myTimer, comp_page_stats.comp_cycles); ! spin_unlock(&comp_data_lock); ! comp_cache_update_comp_stats(&comp_page_stats, page, state); *algorithm = current_algorithm; *************** *** 249,256 **** comp_data.compressed_size = fragment->compressed_size; } ! START_ZEN_TIME(comp_page_stats.myTimer); ! compression_algorithms[algorithm].decomp(from, to, PAGE_SIZE/4, (void *)(&comp_data)); STOP_ZEN_TIME(comp_page_stats.myTimer, comp_page_stats.decomp_cycles); comp_cache_update_decomp_stats(algorithm, &comp_page_stats, fragment); } --- 229,238 ---- comp_data.compressed_size = fragment->compressed_size; } ! ! spin_lock(&comp_data_lock); START_ZEN_TIME(comp_page_stats.myTimer); ! compression_algorithms[algorithm].decomp(from, to, PAGE_SIZE/4, &comp_data); STOP_ZEN_TIME(comp_page_stats.myTimer, comp_page_stats.decomp_cycles); + spin_unlock(&comp_data_lock); comp_cache_update_decomp_stats(algorithm, &comp_page_stats, fragment); } *************** *** 261,275 **** { int i; - - /* initialize our data for the `test' compressed_page */ - comp_data.compressed_data = compresseddata; - comp_data.decompressed_data = decompresseddata; - comp_data.hashLookupTable_WKdm = compressedhashLookupTable_WKdm; - comp_data.hashLookupTable_WK4x4 = compressedhashLookupTable_WK4x4; - comp_data.dictionary = compresseddictionary; - comp_data.tempTagsArray = compressedtempTagsArray; - comp_data.tempQPosArray = compressedtempQPosArray; - comp_data.tempLowBitsArray = compressedtempLowBitsArray; for (i = 0; i < NUM_ALGORITHMS; i++) { memset((void *) &compression_algorithms[i], 0, sizeof(struct stats_summary)); --- 243,261 ---- { int i; + /* data structures for WKdm and WK4x4 */ + comp_data.tempTagsArray = kmalloc(300 * sizeof(WK_word), GFP_ATOMIC); + comp_data.tempQPosArray = kmalloc(300 * sizeof(WK_word), GFP_ATOMIC); + comp_data.tempLowBitsArray = kmalloc(1200 * sizeof(WK_word), GFP_ATOMIC); + + if (!comp_data.tempTagsArray || !comp_data.tempQPosArray || !comp_data.tempLowBitsArray) + panic("comp_cache_algorithms_init(): cannot allocate structures for WKdm/WK4x4"); + + /* data structure (dictionary) for LZO */ + comp_data.wrkmem = (lzo_byte *) kmalloc(LZO1X_1_MEM_COMPRESS, GFP_ATOMIC); + if (!comp_data.wrkmem) + panic("comp_cache_algorithms_init(): cannot allocate dictionary for LZO"); + + /* stats for algorithms */ for (i = 0; i < NUM_ALGORITHMS; i++) { memset((void *) &compression_algorithms[i], 0, sizeof(struct stats_summary)); *************** *** 278,282 **** compression_algorithms[i].stats.decomp_cycles_min = INF; } ! strcpy(compression_algorithms[WKDM_IDX].name, "WKdm"); compression_algorithms[WKDM_IDX].comp = WKdm_compress; --- 264,269 ---- compression_algorithms[i].stats.decomp_cycles_min = INF; } ! ! /* compression algorithms */ strcpy(compression_algorithms[WKDM_IDX].name, "WKdm"); compression_algorithms[WKDM_IDX].comp = WKdm_compress; *************** *** 291,298 **** compression_algorithms[LZO_IDX].decomp = lzo_wrapper_decompress; - wrkmem = (lzo_byte *) kmalloc(LZO1X_1_MEM_COMPRESS, GFP_ATOMIC); - if (!wrkmem) - panic("comp_cache_algorithms_init(): cannot allocate wrkmem (for LZO)"); - if (!current_algorithm || current_algorithm < algorithm_min || current_algorithm > algorithm_max) current_algorithm = WKDM_IDX; --- 278,281 ---- *************** *** 420,423 **** --- 403,408 ---- memset((void *) num_fragments, 0, HIST_COUNT * sizeof(unsigned long)); + spin_lock(&comp_cache_lock); + total1 = free_space_count(0, num_fragments); length += sprintf(page + length, *************** *** 439,443 **** HIST_PRINTK); } ! vfree(num_fragments); out: --- 424,429 ---- HIST_PRINTK); } ! ! spin_unlock(&comp_cache_lock); vfree(num_fragments); out: *************** *** 469,474 **** for (i = FRAG_INTERVAL * 2; i < COMP_PAGE_SIZE; i += FRAG_INTERVAL) length += sprintf(page + length, " -%d", i); ! length += sprintf(page + length, " -%d\n", (int)COMP_PAGE_SIZE); for (i = 1; i < free_space_hash_size; i += 2) { memset((void *) frag_space, 0, (COMP_PAGE_SIZE/FRAG_INTERVAL + 1) * sizeof(unsigned long)); --- 455,462 ---- for (i = FRAG_INTERVAL * 2; i < COMP_PAGE_SIZE; i += FRAG_INTERVAL) length += sprintf(page + length, " -%d", i); ! length += sprintf(page + length, " %d\n", (int)COMP_PAGE_SIZE); + spin_lock(&comp_cache_lock); + for (i = 1; i < free_space_hash_size; i += 2) { memset((void *) frag_space, 0, (COMP_PAGE_SIZE/FRAG_INTERVAL + 1) * sizeof(unsigned long)); *************** *** 479,486 **** length += sprintf(page + length, ! "%4d - %4d: %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", (i-1)*free_space_interval+1, (i+1)*free_space_interval<COMP_PAGE_SIZE?(i+1)*free_space_interval:(int)COMP_PAGE_SIZE, total1 + total2, FRAG_PRINTK); } vfree(frag_space); --- 467,476 ---- length += sprintf(page + length, ! "%4d - %4d: %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", (i-1)*free_space_interval+1, (i+1)*free_space_interval<COMP_PAGE_SIZE?(i+1)*free_space_interval:(int)COMP_PAGE_SIZE, total1 + total2, FRAG_PRINTK); } + + spin_unlock(&comp_cache_lock); vfree(frag_space); Index: swapin.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapin.c,v retrieving revision 1.47 retrieving revision 1.48 diff -C2 -r1.47 -r1.48 *** swapin.c 18 Jul 2002 21:31:08 -0000 1.47 --- swapin.c 28 Jul 2002 15:47:04 -0000 1.48 *************** *** 2,6 **** * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-18 17:59:01 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache/swapin.c * ! * Time-stamp: <2002-07-27 18:55:37 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 19,39 **** int - __invalidate_comp_cache(struct address_space * mapping, unsigned long offset) - { - struct comp_cache_fragment * fragment; - int err = find_comp_page(mapping, offset, &fragment); - - if (!err) - comp_cache_free(fragment); - return err; - } - - int invalidate_comp_cache(struct address_space * mapping, unsigned long offset) { int err; spin_lock(&comp_cache_lock); ! err = __invalidate_comp_cache(mapping, offset); spin_unlock(&comp_cache_lock); return err; --- 19,31 ---- int invalidate_comp_cache(struct address_space * mapping, unsigned long offset) { + struct comp_cache_fragment * fragment; int err; spin_lock(&comp_cache_lock); ! err = find_comp_page(mapping, offset, &fragment); ! if (!err) ! drop_fragment(fragment); spin_unlock(&comp_cache_lock); return err; *************** *** 69,73 **** __set_page_dirty(page); } ! comp_cache_free(fragment); out_unlock: --- 61,65 ---- __set_page_dirty(page); } ! drop_fragment(fragment); out_unlock: *************** *** 83,86 **** --- 75,80 ---- if (!fragment) BUG(); + if (!fragment_count(fragment)) + BUG(); comp_page = fragment->comp_page; if (!comp_page->page) *************** *** 96,103 **** memcpy(page_address(page), page_address(comp_page->page) + fragment->offset, PAGE_SIZE); - PageSetCompCache(page); SetPageUptodate(page); } int read_comp_cache(struct address_space *mapping, unsigned long offset, struct page * page) --- 90,97 ---- memcpy(page_address(page), page_address(comp_page->page) + fragment->offset, PAGE_SIZE); SetPageUptodate(page); } + /* caller may hold pagecache_lock (__find_lock_page()) */ int read_comp_cache(struct address_space *mapping, unsigned long offset, struct page * page) *************** *** 106,109 **** --- 100,106 ---- int err; + if (!PageLocked(page)) + BUG(); + spin_lock(&comp_cache_lock); err = find_comp_page(mapping, offset, &fragment); *************** *** 114,144 **** goto out_unlock; ! if (!PageLocked(page)) ! BUG(); ! if (TryLockPage(fragment->comp_page->page)) BUG(); ! /* move the fragment to the back of the lru list */ remove_fragment_from_lru_queue(fragment); add_fragment_to_lru_queue(fragment); decompress_fragment(fragment, page); ! /* update fault in stats */ comp_cache_update_faultin_stats(fragment); - #ifdef CONFIG_COMP_DEMAND_RESIZE - PageClearCompCache(page); - if (CompFragmentTestandClearDirty(fragment)) __set_page_dirty(page); UnlockPage(fragment->comp_page->page); ! comp_cache_free(fragment); ! #else ! UnlockPage(fragment->comp_page->page); ! #endif ! ! UnlockPage(page); out_unlock: spin_unlock(&comp_cache_lock); --- 111,138 ---- goto out_unlock; ! if (!fragment_count(fragment)) BUG(); + + get_fragment(fragment); ! /* move the fragment to the back of the lru list */ remove_fragment_from_lru_queue(fragment); add_fragment_to_lru_queue(fragment); + + spin_unlock(&comp_cache_lock); + lock_page(fragment->comp_page->page); decompress_fragment(fragment, page); ! spin_lock(&comp_cache_lock); comp_cache_update_faultin_stats(fragment); if (CompFragmentTestandClearDirty(fragment)) __set_page_dirty(page); UnlockPage(fragment->comp_page->page); ! put_fragment(fragment); ! ! drop_fragment(fragment); out_unlock: spin_unlock(&comp_cache_lock); *************** *** 146,150 **** } ! extern struct page * find_and_dirty_page(struct address_space *mapping, unsigned long offset, struct page **hash); static void --- 140,145 ---- } ! #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 *************** *** 160,164 **** if ((fragment->index >= start) || (partial && (fragment->index + 1) == start)) ! comp_cache_free(fragment); } --- 155,159 ---- if ((fragment->index >= start) || (partial && (fragment->index + 1) == start)) ! drop_fragment(fragment); } *************** *** 166,169 **** --- 161,165 ---- } + /* caller must hold pagecache_lock */ void truncate_comp_pages(struct address_space * mapping, unsigned long start, unsigned partial) *************** *** 171,177 **** truncate_list_comp_pages(&mapping->clean_comp_pages, start, partial); truncate_list_comp_pages(&mapping->dirty_comp_pages, start, partial); - truncate_list_comp_pages(&mapping->locked_comp_pages, start, partial); } void invalidate_comp_pages(struct address_space * mapping) --- 167,173 ---- truncate_list_comp_pages(&mapping->clean_comp_pages, start, partial); truncate_list_comp_pages(&mapping->dirty_comp_pages, start, partial); } + /* caller must hold pagecache_lock */ void invalidate_comp_pages(struct address_space * mapping) *************** *** 180,185 **** } void ! wait_all_comp_pages(struct address_space * mapping) { struct page * page; --- 176,182 ---- } + /* caller must hold pagecache_lock */ void ! wait_comp_pages(struct address_space * mapping) { struct page * page; *************** *** 190,199 **** list_del_init(&page->list); wait_on_page(page); } } void ! lookup_all_comp_pages(struct address_space * mapping) { struct page **hash; --- 187,199 ---- list_del_init(&page->list); + spin_unlock(&pagecache_lock); wait_on_page(page); + spin_lock(&pagecache_lock); } } + /* caller must hold pagecache_lock */ void ! lookup_comp_pages(struct address_space * mapping) { struct page **hash; *************** *** 206,215 **** goto out_unlock; ! page = page_cache_alloc(mapping); if (!page) goto out_unlock; ! if (list_empty(&mapping->dirty_comp_pages)) goto out_release; fragment = list_entry(mapping->dirty_comp_pages.next, struct comp_cache_fragment, mapping_list); --- 206,241 ---- goto out_unlock; ! spin_unlock(&pagecache_lock); ! /*** ! * This function may be called from the following code path: ! * ! * __sync_one() -> filemap_fdatasync() ! * ! * This code path tries to sync an inode (and keeps it locked ! * while it is syncing). However, that inode can be also in ! * the clear path (clear_inode() function, called in the exit ! * process path) which will lock the super block and then wait ! * for the inode, if locked (what happens when syncing it like ! * here). ! * ! * Since the allocation path may write pages, which may need ! * to lock the same super block, it will deadlock, because the ! * super block is locked by the exit path explained above. So, ! * we end up not being able to allocate the page (in order to ! * finish this function and unlock the inode) _and_ the super ! * block won't be unlocked since the inode doesn't get ! * unlocked either. ! * ! * 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); ! if (list_empty(&mapping->dirty_comp_pages)) { ! spin_unlock(&pagecache_lock); goto out_release; + } fragment = list_entry(mapping->dirty_comp_pages.next, struct comp_cache_fragment, mapping_list); *************** *** 221,237 **** list_del(&fragment->mapping_list); list_add(&fragment->mapping_list, &fragment->mapping->clean_comp_pages); ! ! if (add_to_page_cache_unique(page, mapping, fragment->index, hash)) { ! if (!find_and_dirty_page(mapping, fragment->index, hash)) ! BUG(); goto out_release; - } ! if (TryLockPage(fragment->comp_page->page)) ! BUG(); decompress_fragment(fragment, page); UnlockPage(fragment->comp_page->page); ! comp_cache_free(fragment); PageClearCompCache(page); --- 247,270 ---- 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(&pagecache_lock); ! 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); ! ! /* effectively free it */ ! drop_fragment(fragment); PageClearCompCache(page); *************** *** 244,247 **** --- 277,281 ---- spin_unlock(&comp_cache_lock); } + #endif /* Index: swapout.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/comp_cache/swapout.c,v retrieving revision 1.65 retrieving revision 1.66 diff -C2 -r1.65 -r1.66 *** swapout.c 18 Jul 2002 11:54:48 -0000 1.65 --- swapout.c 28 Jul 2002 15:47:04 -0000 1.66 *************** *** 2,6 **** * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-17 18:48:02 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * /mm/comp_cache/swapout.c * ! * Time-stamp: <2002-07-28 11:33:53 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 23,26 **** --- 23,30 ---- struct list_head swp_free_buffer_head, swp_used_buffer_head; + static spinlock_t swap_buffer_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; + + #define SWP_BUFFER_PRIORITY 6 + static int refill_swp_buffer(unsigned int gfp_mask, int priority) *************** *** 39,102 **** swp_buffer = list_entry(swp_buffer_lh, struct swp_buffer, list); buffer_page = swp_buffer->page; - fragment = swp_buffer->fragment; - list_del(swp_buffer_lh); - list_add(swp_buffer_lh, &swp_used_buffer_head); if (TryLockPage(buffer_page)) { if (!wait) ! continue; ! list_del_init(swp_buffer_lh); lock_page(buffer_page); } ! /* its fragment was added to locked_pages list below, ! * right before being returned to the caller, so let's ! * remove it now from any mapping->*_pages list */ ! list_del(&buffer_page->list); if (buffer_page->buffers) { ! list_del_init(swp_buffer_lh); if (!try_to_free_buffers(buffer_page, gfp_mask)) { - list_add(swp_buffer_lh, &swp_used_buffer_head); - - list_add(&buffer_page->list, &fragment->mapping->locked_comp_pages); UnlockPage(buffer_page); ! continue; } } ! /*** ! * Has the fragment we are swapping out been already ! * freed? Given that we were on IO process, ! * comp_cache_free() didn't free the fragment struct, ! * so let's do it now. ! */ ! if (!CompFragmentTestandClearIO(fragment)) { ! kmem_cache_free(fragment_cachep, (fragment)); ! goto out; } ! /*** ! * In the case it is waiting for merge in ! * comp_cache_free(), we don't have to free it. To be ! * clearer, it has been freed, except its data ! * structure, what will be freed when merged in ! * comp_cache_free() ! */ ! if (CompFragmentFreed(fragment)) ! goto out; ! ! /* it's not swapped out, so let' free it */ ! comp_cache_free(fragment); ! ! out: ! swp_buffer->fragment = NULL; ! ! list_del(swp_buffer_lh); ! list_add_tail(swp_buffer_lh, &swp_free_buffer_head); ! UnlockPage(buffer_page); return 1; } --- 43,100 ---- swp_buffer = list_entry(swp_buffer_lh, struct swp_buffer, list); buffer_page = swp_buffer->page; list_del(swp_buffer_lh); if (TryLockPage(buffer_page)) { if (!wait) ! goto add_to_dirty; ! spin_unlock(&swap_buffer_lock); lock_page(buffer_page); + spin_lock(&swap_buffer_lock); } ! /* remove from buffer_page->mapping->locked_comp_pages */ ! list_del_init(&buffer_page->list); if (buffer_page->buffers) { ! spin_unlock(&swap_buffer_lock); if (!try_to_free_buffers(buffer_page, gfp_mask)) { UnlockPage(buffer_page); ! spin_lock(&swap_buffer_lock); } + spin_lock(&swap_buffer_lock); } ! fragment = swp_buffer->fragment; ! ! /* A swap buffer page that has been set to dirty means ! * that the writepage() function failed, so we cannot ! * free the fragment and should simply backout. */ ! if (PageDirty(buffer_page)) { ! if (fragment) { ! spin_lock(&pagecache_lock); ! list_del(&fragment->mapping_list); ! list_add(&fragment->mapping_list, &fragment->mapping->dirty_comp_pages); ! spin_unlock(&pagecache_lock); ! ! CompFragmentSetDirty(fragment); ! } ! goto add_to_free; } ! /* A clean swap buffer page means that the writepage() ! * didn't failed, so we can go on freeing the fragment ! * (if still needed). */ ! spin_lock(&comp_cache_lock); ! if (fragment) { ! fragment->swp_buffer = NULL; ! drop_fragment(fragment); ! } ! spin_unlock(&comp_cache_lock); ! add_to_free: UnlockPage(buffer_page); + list_add_tail(swp_buffer_lh, &swp_free_buffer_head); return 1; + add_to_dirty: + list_add(swp_buffer_lh, &swp_used_buffer_head); } *************** *** 108,112 **** --- 106,112 ---- if (unlikely(current->need_resched)) { __set_current_state(TASK_RUNNING); + spin_unlock(&swap_buffer_lock); schedule(); + spin_lock(&swap_buffer_lock); } goto try_again; *************** *** 123,141 **** * If there's a free buffer page, it will lock the page and * return. Otherwise we may sleep to get the lock. - * */ ! static int ! find_free_swp_buffer(struct comp_cache_fragment * fragment, unsigned int gfp_mask, struct swp_buffer ** swp_buffer_out) { struct page * buffer_page; struct list_head * swp_buffer_lh; ! struct swp_buffer * swp_buffer; ! int priority = 6, error = 0; if (!fragment) BUG(); ! CompFragmentSetIO(fragment); ! if (!list_empty(&swp_free_buffer_head)) goto get_free_buffer; --- 123,140 ---- * If there's a free buffer page, it will lock the page and * return. Otherwise we may sleep to get the lock. */ ! static struct swp_buffer * ! find_free_swp_buffer(struct comp_cache_fragment * fragment, unsigned int gfp_mask) { struct page * buffer_page; struct list_head * swp_buffer_lh; ! struct swp_buffer * swp_buffer = NULL; ! int priority = SWP_BUFFER_PRIORITY; if (!fragment) BUG(); ! spin_lock(&swap_buffer_lock); ! if (!list_empty(&swp_free_buffer_head)) goto get_free_buffer; *************** *** 144,165 **** refill_swp_buffer(gfp_mask, priority--); - error = -ENOENT; - /* Failed to get a free swap buffer. Probably gfp_mask does * not allow buffer sync in refill_swp_buffer() function. */ ! if (list_empty(&swp_free_buffer_head)) { ! error = -ENOMEM; ! goto failed; ! } ! ! /* Fragment totally freed. Free its struct to avoid leakage. */ ! if (!CompFragmentIO(fragment)) { ! kmem_cache_free(fragment_cachep, (fragment)); ! goto failed; ! } ! ! /* Fragment partially freed (to be merged). Nothing to do. */ ! if (CompFragmentFreed(fragment)) ! goto failed; get_free_buffer: --- 143,150 ---- refill_swp_buffer(gfp_mask, priority--); /* Failed to get a free swap buffer. Probably gfp_mask does * not allow buffer sync in refill_swp_buffer() function. */ ! if (list_empty(&swp_free_buffer_head)) ! goto out_unlock; get_free_buffer: *************** *** 172,206 **** list_del(swp_buffer_lh); - list_add(swp_buffer_lh, &swp_used_buffer_head); swp_buffer->fragment = fragment; buffer_page->index = fragment->index; buffer_page->mapping = fragment->mapping; list_add(&buffer_page->list, &fragment->mapping->locked_comp_pages); ! (*swp_buffer_out) = swp_buffer; ! out: ! return error; ! ! failed: ! CompFragmentClearIO(fragment); ! goto out; } extern void decompress_fragment(struct comp_cache_fragment *, struct page *); ! static int ! decompress_to_swp_buffer(struct comp_cache_fragment * fragment, unsigned int gfp_mask, struct swp_buffer ** swp_buffer_out) { struct page * buffer_page; struct swp_buffer * swp_buffer; - int error; - - if (fragment->comp_page->page->buffers) - BUG(); ! error = find_free_swp_buffer(fragment, gfp_mask, &swp_buffer); ! if (error) ! goto out; buffer_page = swp_buffer->page; --- 157,191 ---- list_del(swp_buffer_lh); + spin_lock(&comp_cache_lock); swp_buffer->fragment = fragment; + fragment->swp_buffer = swp_buffer; buffer_page->index = fragment->index; buffer_page->mapping = fragment->mapping; + spin_unlock(&comp_cache_lock); + spin_lock(&pagecache_lock); + if (!fragment->mapping) + BUG(); list_add(&buffer_page->list, &fragment->mapping->locked_comp_pages); ! spin_unlock(&pagecache_lock); ! ! list_add(swp_buffer_lh, &swp_used_buffer_head); ! out_unlock: ! spin_unlock(&swap_buffer_lock); ! return swp_buffer; } extern void decompress_fragment(struct comp_cache_fragment *, struct page *); ! static struct swp_buffer * ! decompress_to_swp_buffer(struct comp_cache_fragment * fragment, unsigned int gfp_mask) { struct page * buffer_page; struct swp_buffer * swp_buffer; ! swp_buffer = find_free_swp_buffer(fragment, gfp_mask); ! if (!swp_buffer) ! return NULL; buffer_page = swp_buffer->page; *************** *** 208,221 **** if (!buffer_page) BUG(); - if (TryLockPage(fragment->comp_page->page)) - BUG(); decompress_fragment(fragment, buffer_page); - buffer_page->flags &= (1 << PG_locked); - UnlockPage(fragment->comp_page->page); ! (*swp_buffer_out) = swp_buffer; ! out: ! return error; } --- 193,203 ---- if (!buffer_page) BUG(); + lock_page(fragment->comp_page->page); decompress_fragment(fragment, buffer_page); UnlockPage(fragment->comp_page->page); ! ! buffer_page->flags &= (1 << PG_locked); ! return swp_buffer; } *************** *** 228,240 **** int (*writepage)(struct page *); struct list_head * fragment_lh; ! int maxscan, nrpages, swap_cache_page, error; struct comp_cache_fragment * fragment; struct swp_buffer * swp_buffer; - struct page * page; swp_entry_t entry; nrpages = SWAP_CLUSTER_MAX; maxscan = max((int) (num_fragments/priority), (int) (nrpages * 1.5)); ! while (!list_empty(&lru_queue) && maxscan--) { if (unlikely(current->need_resched)) { --- 210,223 ---- int (*writepage)(struct page *); struct list_head * fragment_lh; ! int ret, maxscan, nrpages, swap_cache_page; struct comp_cache_fragment * fragment; struct swp_buffer * swp_buffer; swp_entry_t entry; nrpages = SWAP_CLUSTER_MAX; maxscan = max((int) (num_fragments/priority), (int) (nrpages * 1.5)); ! ! ret = 0; ! while (!list_empty(&lru_queue) && maxscan--) { if (unlikely(current->need_resched)) { *************** *** 246,251 **** fragment = list_entry(fragment_lh = lru_queue.prev, struct comp_cache_fragment, lru_queue); - - page = fragment->comp_page->page; /* move it to the back of the list */ --- 229,232 ---- *************** *** 253,265 **** list_add(fragment_lh, &lru_queue); - /* page locked */ - if (TryLockPage(page)) - continue; - /* clean page, let's free it */ if (!CompFragmentDirty(fragment)) { ! comp_cache_free_locked(fragment); ! UnlockPage(page); ! if (--nrpages) continue; --- 234,240 ---- list_add(fragment_lh, &lru_queue); /* clean page, let's free it */ if (!CompFragmentDirty(fragment)) { ! drop_fragment(fragment); if (--nrpages) continue; *************** *** 268,275 **** /* we can't perform IO, so we can't go on */ ! if (!(gfp_mask & __GFP_FS)) { ! UnlockPage(page); continue; - } if ((swap_cache_page = PageSwapCache(fragment))) { --- 243,248 ---- /* we can't perform IO, so we can't go on */ ! if (!(gfp_mask & __GFP_FS)) continue; if ((swap_cache_page = PageSwapCache(fragment))) { *************** *** 283,325 **** remove_fragment_from_lru_queue(fragment); - list_del(&... [truncated message content] |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 15:47:08
|
Update of /cvsroot/linuxcompressed/linux/include/linux In directory usw-pr-cvs1:/tmp/cvs-serv26313/include/linux Modified Files: WK4x4.h WKdm.h comp_cache.h Log Message: Features o First page cache support for preempted kernels is implemented. o Fragments have a "count" field that stores the number of references to the fragment, so we don't have to worry about it getting freed in the middle of an operation. That tries to fix a highly potential source of bugs. Bug fixes o Fix memory accountancy for double page sizes. Meminfo was broken for 8K pages. o truncate_list_comp_pages() could try to truncate fragments that were in locked_comp_pages list, which is bogus. Only swap buffers list are on this list, and are listed there only for wait_comp_pages(). o when writing out fragments, we didn't pay attention to the return value, so we may end up freeing a fragment (when refilling swap buffer) even if the writepage failed. In particular, ramfs, ramdisk and other memory file systems always fail to write out its pages. Now we check if the swap buffer page has been set dirty (the writepage() usually does that after failing to write a page), moving back the fragment to the dirty list (and of course not freeing the fragment). o fixed bug that would corrupt the swap buffer list. A bug in the variable that returned the error code could return error even if a fragment was found afterall, so the caller function would backout the writeout operation, leaving the swap buffer locked on the used list, and it wouldn't never get unlocked. o account writeout stats only for pages that have been actually submitted to IO operation. o fixed bug that would deadlock a system with comp_cache that has page cache support. The lookup_comp_pages() function may be called from the following code path: __sync_one() -> filemap_fdatasync(). This code path tries to sync an inode (and keeps it locked while it is syncing). However, that very inode can be also in the clear path (clear_inode() function, called in the exit process path) which will lock the super block and then wait for inode if it is locked (what happens with an inode syncing). Since the allocation path may write pages, which may need to lock the same super block, it will deadlock, because the super block is locked by the exit path explained above. So, we end up not being able to allocate the page (in order to finish this function and unlock the inode) _and_ the super block won't be unlocked since the inode doesn't get unlocked either. The fix was to allocate pages with GFP_NOFS mask. Cleanups o Some functions were renamed. o Compression algorithms (removed unnecessary data structures that were allocated, made some structures to be allocated statically in the algorithms, some data statically allocated are now kmalloc()) o Removed /proc/sys/vm/comp_cache/actual_size, it doesn't make sense with resizing on demand. Others o Compressed cache only resizes on demand. Index: WK4x4.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/WK4x4.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -r1.1.1.1 -r1.2 *** WK4x4.h 15 Apr 2001 22:27:56 -0000 1.1.1.1 --- WK4x4.h 28 Jul 2002 15:47:04 -0000 1.2 *************** *** 326,330 **** WK_word* destinationBuffer, unsigned int words, ! void *page); /* Given a pointer to a source buffer (sourceBuffer) of compressed --- 326,330 ---- WK_word* destinationBuffer, unsigned int words, ! struct comp_alg_data * data); /* Given a pointer to a source buffer (sourceBuffer) of compressed *************** *** 336,340 **** WK_word* destinationPage, unsigned int words, ! void * page); /* Given a pointer to a source buffer (sourceBuffer) of uncompressed --- 336,340 ---- WK_word* destinationPage, unsigned int words, ! struct comp_alg_data * data); /* Given a pointer to a source buffer (sourceBuffer) of uncompressed Index: WKdm.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/WKdm.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -r1.1.1.1 -r1.2 *** WKdm.h 15 Apr 2001 22:27:56 -0000 1.1.1.1 --- WKdm.h 28 Jul 2002 15:47:04 -0000 1.2 *************** *** 52,56 **** WK_word* destinationBuffer, unsigned int words, ! void * page); /* Given a pointer to a source buffer (sourceBuffer) of compressed --- 52,56 ---- WK_word* destinationBuffer, unsigned int words, ! struct comp_alg_data * data); /* Given a pointer to a source buffer (sourceBuffer) of compressed *************** *** 63,67 **** WK_word* destinationPage, unsigned int words, ! void * page); /* Given a pointer to a source buffer (sourceBuffer) of uncompressed --- 63,67 ---- WK_word* destinationPage, unsigned int words, ! struct comp_alg_data * data); /* Given a pointer to a source buffer (sourceBuffer) of uncompressed Index: comp_cache.h =================================================================== RCS file: /cvsroot/linuxcompressed/linux/include/linux/comp_cache.h,v retrieving revision 1.96 retrieving revision 1.97 diff -C2 -r1.96 -r1.97 *** comp_cache.h 18 Jul 2002 21:31:08 -0000 1.96 --- comp_cache.h 28 Jul 2002 15:47:04 -0000 1.97 *************** *** 2,6 **** * linux/mm/comp_cache.h * ! * Time-stamp: <2002-07-18 15:45:44 rcastro> * * Linux Virtual Memory Compressed Cache --- 2,6 ---- * linux/mm/comp_cache.h * ! * Time-stamp: <2002-07-28 10:08:41 rcastro> * * Linux Virtual Memory Compressed Cache *************** *** 28,33 **** #include <linux/shmem_fs.h> #include <linux/WKcommon.h> ! #define COMP_CACHE_VERSION "0.24pre1" /* maximum compressed size of a page */ --- 28,34 ---- #include <linux/shmem_fs.h> #include <linux/WKcommon.h> + #include <linux/minilzo.h> ! #define COMP_CACHE_VERSION "0.24pre2" /* maximum compressed size of a page */ *************** *** 51,57 **** struct list_head mapping_list; unsigned long index; ! struct address_space *mapping; /* offset in the compressed cache we are stored in */ unsigned short offset; --- 52,63 ---- struct list_head mapping_list; + /* usage count */ + atomic_t count; + unsigned long index; ! struct address_space * mapping; + struct swp_buffer * swp_buffer; + /* offset in the compressed cache we are stored in */ unsigned short offset; *************** *** 104,120 **** ((struct swp_buffer *) kmem_cache_alloc(comp_cachep, SLAB_ATOMIC)) extern int shmem_page(struct page * page); /* adaptivity.c */ #ifdef CONFIG_COMP_CACHE - int shrink_comp_cache(struct comp_cache_page *, int); - int grow_comp_cache(int); - void adapt_comp_cache(void); - #else - static inline int shrink_comp_cache(struct comp_cache_page * comp_page, int check_further) { return 0; } - static inline void grow_comp_cache(int nrpages) { } - #endif - - #ifdef CONFIG_COMP_DEMAND_RESIZE int grow_on_demand(void); int shrink_on_demand(struct comp_cache_page *); --- 110,133 ---- ((struct swp_buffer *) kmem_cache_alloc(comp_cachep, SLAB_ATOMIC)) + #define get_fragment(f) do { \ + if (atomic_read(&(f)->count) == 0) \ + BUG(); \ + atomic_inc(&(f)->count); \ + } while(0); + + #define drop_fragment(f) do { \ + if (!CompFragmentTestandSetToBeFreed(f)) \ + put_fragment(f); \ + } while(0); + + #define put_fragment(f) __comp_cache_free(f) + #define put_fragment_testzero(f) atomic_dec_and_test(&(f)->count) + #define fragment_count(f) atomic_read(&(f)->count) + #define set_fragment_count(f,v) atomic_set(&(f)->count, v) + extern int shmem_page(struct page * page); /* adaptivity.c */ #ifdef CONFIG_COMP_CACHE int grow_on_demand(void); int shrink_on_demand(struct comp_cache_page *); *************** *** 129,165 **** /* -- Fragment Flags */ - /* CF_Freed: when a fragment is going to be submitted to IO, there's a - * special case where one must tell swap buffer functions that the - * fragment was partially freed, so it does not need IO any longer - * (but the struct cannot be freed). In this case, we use Freed - * flag */ - #define CF_Freed 0 - - /* CF_IO: used to coordinate the swap buffer functions and - comp_cache_free() when freeing the fragment. If CF_IO is set and a - fragment happens to be freed, its structure will not be freed there, - only in find_free_swp_buffer(). */ - #define CF_IO 1 - /* CF_WKdm/CF_WK4x4/CF_LZO: defines the algorithm the fragment has * been compressed (if it's been compressed) */ ! #define CF_WKdm 2 ! #define CF_WK4x4 3 ! #define CF_LZO 4 /* CF_Dirty: is the fragment dirty? */ ! #define CF_Dirty 5 ! #define CompFragmentFreed(fragment) test_bit(CF_Freed, &(fragment)->flags) ! #define CompFragmentSetFreed(fragment) set_bit(CF_Freed, &(fragment)->flags) ! #define CompFragmentTestandSetFreed(fragment) test_and_set_bit(CF_Freed, &(fragment)->flags) ! #define CompFragmentTestandClearFreed(fragment) test_and_clear_bit(CF_Freed, &(fragment)->flags) ! #define CompFragmentClearFreed(fragment) clear_bit(CF_Freed, &(fragment)->flags) ! ! #define CompFragmentIO(fragment) test_bit(CF_IO, &(fragment)->flags) ! #define CompFragmentSetIO(fragment) set_bit(CF_IO, &(fragment)->flags) ! #define CompFragmentTestandSetIO(fragment) test_and_set_bit(CF_IO, &(fragment)->flags) ! #define CompFragmentTestandClearIO(fragment) test_and_clear_bit(CF_IO, &(fragment)->flags) ! #define CompFragmentClearIO(fragment) clear_bit(CF_IO, &(fragment)->flags) #define CompFragmentWKdm(fragment) test_bit(CF_WKdm, &(fragment)->flags) --- 142,155 ---- /* -- Fragment Flags */ /* CF_WKdm/CF_WK4x4/CF_LZO: defines the algorithm the fragment has * been compressed (if it's been compressed) */ ! #define CF_WKdm 0 ! #define CF_WK4x4 1 ! #define CF_LZO 2 /* CF_Dirty: is the fragment dirty? */ ! #define CF_Dirty 3 ! #define CF_ToBeFreed 4 #define CompFragmentWKdm(fragment) test_bit(CF_WKdm, &(fragment)->flags) *************** *** 184,187 **** --- 174,180 ---- #define CompFragmentClearDirty(fragment) clear_bit(CF_Dirty, &(fragment)->flags) + #define CompFragmentToBeFreed(fragment) test_bit(CF_ToBeFreed, &(fragment)->flags) + #define CompFragmentTestandSetToBeFreed(fragment) test_and_set_bit(CF_ToBeFreed, &(fragment)->flags) + #define INF 0xffffffff *************** *** 192,205 **** struct list_head list; ! struct page * page; /* page for IO */ ! struct comp_cache_fragment * fragment; /* pointer to the fragment we are doing IO */ }; - #define DEBUG_CHECK_COUNT \ - if ((page_count(page) - !!page->buffers) != 2) { \ - printk("page_count %d page->buffers: %d\n", page_count(page), !!page->buffers); \ - BUG(); \ - } - #define NUM_MEAN_PAGES 100 --- 185,192 ---- struct list_head list; ! struct page * page; /* page for IO */ ! struct comp_cache_fragment * fragment; /* pointer to the fragment we are doing IO */ }; #define NUM_MEAN_PAGES 100 *************** *** 219,232 **** #define DISCARD_MARK 0.80 - typedef unsigned int (compress_function_t)(unsigned long* source, - unsigned long* destination, - unsigned int words, - void *page); - - typedef void (decompress_function_t)(unsigned long* source, - unsigned long* destination, - unsigned int words, - void *page); - typedef struct { union { --- 206,209 ---- *************** *** 268,290 **** }; - struct comp_alg { - char name[6]; - compress_function_t * comp; - decompress_function_t * decomp; - struct stats_summary stats; - }; - struct comp_alg_data { ! WK_word *compressed_data; ! WK_word *decompressed_data; ! ! WK_word *dictionary; ! char *hashLookupTable_WKdm; ! unsigned int *hashLookupTable_WK4x4; WK_word *tempTagsArray; WK_word *tempQPosArray; WK_word *tempLowBitsArray; ! unsigned short compressed_size; }; --- 245,274 ---- }; struct comp_alg_data { ! /* WKdm and WK4x4 */ WK_word *tempTagsArray; WK_word *tempQPosArray; WK_word *tempLowBitsArray; ! /* LZO */ ! lzo_byte * wrkmem; ! unsigned short compressed_size; ! }; ! ! typedef unsigned int (compress_function_t)(unsigned long* source, ! unsigned long* destination, ! unsigned int words, ! struct comp_alg_data * data); ! ! typedef void (decompress_function_t)(unsigned long* source, ! unsigned long* destination, ! unsigned int words, ! struct comp_alg_data * data); ! ! struct comp_alg { ! char name[6]; ! compress_function_t * comp; ! decompress_function_t * decomp; ! struct stats_summary stats; }; *************** *** 324,333 **** int read_comp_cache(struct address_space *, unsigned long, struct page *); - int __invalidate_comp_cache(struct address_space *, unsigned long); int invalidate_comp_cache(struct address_space *, unsigned long); void invalidate_comp_pages(struct address_space *); void truncate_comp_pages(struct address_space *, unsigned long, unsigned); ! void wait_all_comp_pages(struct address_space *); ! void lookup_all_comp_pages(struct address_space *); #define there_are_dirty_comp_pages(mapping) (!list_empty(&(mapping)->dirty_comp_pages)) #define there_are_locked_comp_pages(mapping) (!list_empty(&(mapping)->locked_comp_pages)) --- 308,316 ---- int read_comp_cache(struct address_space *, unsigned long, struct page *); int invalidate_comp_cache(struct address_space *, unsigned long); void invalidate_comp_pages(struct address_space *); void truncate_comp_pages(struct address_space *, unsigned long, unsigned); ! void wait_comp_pages(struct address_space *); ! void lookup_comp_pages(struct address_space *); #define there_are_dirty_comp_pages(mapping) (!list_empty(&(mapping)->dirty_comp_pages)) #define there_are_locked_comp_pages(mapping) (!list_empty(&(mapping)->locked_comp_pages)) *************** *** 338,343 **** static inline void invalidate_comp_pages(struct address_space * mapping) { }; static inline void truncate_comp_pages(struct address_space * mapping, unsigned long start, unsigned partial) { }; ! static inline void wait_all_comp_pages(struct address_space * mapping) { }; ! static inline void lookup_all_comp_pages(struct address_space * mapping) { }; #define there_are_dirty_comp_pages(mapping) 0 #define there_are_locked_comp_pages(mapping) 0 --- 321,326 ---- static inline void invalidate_comp_pages(struct address_space * mapping) { }; static inline void truncate_comp_pages(struct address_space * mapping, unsigned long start, unsigned partial) { }; ! static inline void wait_comp_pages(struct address_space * mapping) { }; ! static inline void lookup_comp_pages(struct address_space * mapping) { }; #define there_are_dirty_comp_pages(mapping) 0 #define there_are_locked_comp_pages(mapping) 0 *************** *** 346,357 **** /* main.c */ #ifdef CONFIG_COMP_CACHE - int compress_page(struct page *, int, unsigned int, int); void comp_cache_init(void); inline int init_comp_page(struct comp_cache_page **,struct page *); ! inline void compress_dirty_page(struct page *, int (*writepage)(struct page *), unsigned int, int); ! inline int compress_clean_page(struct page *, unsigned int, int); #define COMP_PAGE_SIZE ((comp_page_order + 1) * PAGE_SIZE) ! #define comp_cache_used_space ((num_comp_pages * PAGE_SIZE) - comp_cache_free_space) #define page_to_comp_page(n) ((n) >> comp_page_order) --- 329,342 ---- /* main.c */ #ifdef CONFIG_COMP_CACHE void comp_cache_init(void); inline int init_comp_page(struct comp_cache_page **,struct page *); ! int compress_dirty_page(struct page *, int (*writepage)(struct page *), unsigned int, int); ! int compress_clean_page(struct page *, unsigned int, int); ! ! #define CLEAN_PAGE 0 ! #define DIRTY_PAGE 1 #define COMP_PAGE_SIZE ((comp_page_order + 1) * PAGE_SIZE) ! #define comp_cache_used_space ((num_comp_pages * COMP_PAGE_SIZE) - comp_cache_free_space) #define page_to_comp_page(n) ((n) >> comp_page_order) *************** *** 363,367 **** #else static inline void comp_cache_init(void) {}; ! static inline int compress_dirty_page(struct page * page, int (*writepage)(struct page *), unsigned int gfp_mask, int priority) { return writepage(page); } static inline int compress_clean_page(struct page * page, unsigned int gfp_mask, int priority) { return 1; } #endif --- 348,352 ---- #else static inline void comp_cache_init(void) {}; ! static inline int compress_dirty_page(struct page * page, int (*writepage)(struct page *), unsigned int gfp_mask, int priority) { writepage(page); return 0; } static inline int compress_clean_page(struct page * page, unsigned int gfp_mask, int priority) { return 1; } #endif *************** *** 453,460 **** /* free.c */ ! void comp_cache_free_locked(struct comp_cache_fragment *); ! void comp_cache_free(struct comp_cache_fragment *); #ifdef CONFIG_COMP_CACHE int comp_cache_use_address(swp_entry_t); --- 438,447 ---- /* free.c */ ! int __comp_cache_free(struct comp_cache_fragment *); #ifdef CONFIG_COMP_CACHE + + #define fragment_freed(fragment) (!fragment_count(fragment) && !fragment->mapping) + int comp_cache_use_address(swp_entry_t); *************** *** 582,586 **** int comp_cache_hist_read_proc(char *, char **, off_t, int, int *, void *); int comp_cache_frag_read_proc(char *, char **, off_t, int, int *, void *); - inline void comp_cache_update_page_stats(struct page *, int); #endif /* _LINUX_COMP_CACHE_H */ --- 569,572 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 15:47:07
|
Update of /cvsroot/linuxcompressed/linux/arch/i386 In directory usw-pr-cvs1:/tmp/cvs-serv26313/arch/i386 Modified Files: config.in Log Message: Features o First page cache support for preempted kernels is implemented. o Fragments have a "count" field that stores the number of references to the fragment, so we don't have to worry about it getting freed in the middle of an operation. That tries to fix a highly potential source of bugs. Bug fixes o Fix memory accountancy for double page sizes. Meminfo was broken for 8K pages. o truncate_list_comp_pages() could try to truncate fragments that were in locked_comp_pages list, which is bogus. Only swap buffers list are on this list, and are listed there only for wait_comp_pages(). o when writing out fragments, we didn't pay attention to the return value, so we may end up freeing a fragment (when refilling swap buffer) even if the writepage failed. In particular, ramfs, ramdisk and other memory file systems always fail to write out its pages. Now we check if the swap buffer page has been set dirty (the writepage() usually does that after failing to write a page), moving back the fragment to the dirty list (and of course not freeing the fragment). o fixed bug that would corrupt the swap buffer list. A bug in the variable that returned the error code could return error even if a fragment was found afterall, so the caller function would backout the writeout operation, leaving the swap buffer locked on the used list, and it wouldn't never get unlocked. o account writeout stats only for pages that have been actually submitted to IO operation. o fixed bug that would deadlock a system with comp_cache that has page cache support. The lookup_comp_pages() function may be called from the following code path: __sync_one() -> filemap_fdatasync(). This code path tries to sync an inode (and keeps it locked while it is syncing). However, that very inode can be also in the clear path (clear_inode() function, called in the exit process path) which will lock the super block and then wait for inode if it is locked (what happens with an inode syncing). Since the allocation path may write pages, which may need to lock the same super block, it will deadlock, because the super block is locked by the exit path explained above. So, we end up not being able to allocate the page (in order to finish this function and unlock the inode) _and_ the super block won't be unlocked since the inode doesn't get unlocked either. The fix was to allocate pages with GFP_NOFS mask. Cleanups o Some functions were renamed. o Compression algorithms (removed unnecessary data structures that were allocated, made some structures to be allocated statically in the algorithms, some data statically allocated are now kmalloc()) o Removed /proc/sys/vm/comp_cache/actual_size, it doesn't make sense with resizing on demand. Others o Compressed cache only resizes on demand. Index: config.in =================================================================== RCS file: /cvsroot/linuxcompressed/linux/arch/i386/config.in,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -r1.21 -r1.22 *** config.in 16 Jul 2002 18:41:54 -0000 1.21 --- config.in 28 Jul 2002 15:47:03 -0000 1.22 *************** *** 211,215 **** if [ "$CONFIG_COMP_CACHE" = "y" ]; then bool ' Support for Page Cache compression' CONFIG_COMP_PAGE_CACHE - bool ' Resize Compressed Cache On Demand' CONFIG_COMP_DEMAND_RESIZE bool ' Double Page Size' CONFIG_COMP_DOUBLE_PAGE fi --- 211,214 ---- |
From: Rodrigo S. de C. <rc...@us...> - 2002-07-28 15:47:07
|
Update of /cvsroot/linuxcompressed/linux/mm In directory usw-pr-cvs1:/tmp/cvs-serv26313/mm Modified Files: filemap.c swap_state.c vmscan.c Log Message: Features o First page cache support for preempted kernels is implemented. o Fragments have a "count" field that stores the number of references to the fragment, so we don't have to worry about it getting freed in the middle of an operation. That tries to fix a highly potential source of bugs. Bug fixes o Fix memory accountancy for double page sizes. Meminfo was broken for 8K pages. o truncate_list_comp_pages() could try to truncate fragments that were in locked_comp_pages list, which is bogus. Only swap buffers list are on this list, and are listed there only for wait_comp_pages(). o when writing out fragments, we didn't pay attention to the return value, so we may end up freeing a fragment (when refilling swap buffer) even if the writepage failed. In particular, ramfs, ramdisk and other memory file systems always fail to write out its pages. Now we check if the swap buffer page has been set dirty (the writepage() usually does that after failing to write a page), moving back the fragment to the dirty list (and of course not freeing the fragment). o fixed bug that would corrupt the swap buffer list. A bug in the variable that returned the error code could return error even if a fragment was found afterall, so the caller function would backout the writeout operation, leaving the swap buffer locked on the used list, and it wouldn't never get unlocked. o account writeout stats only for pages that have been actually submitted to IO operation. o fixed bug that would deadlock a system with comp_cache that has page cache support. The lookup_comp_pages() function may be called from the following code path: __sync_one() -> filemap_fdatasync(). This code path tries to sync an inode (and keeps it locked while it is syncing). However, that very inode can be also in the clear path (clear_inode() function, called in the exit process path) which will lock the super block and then wait for inode if it is locked (what happens with an inode syncing). Since the allocation path may write pages, which may need to lock the same super block, it will deadlock, because the super block is locked by the exit path explained above. So, we end up not being able to allocate the page (in order to finish this function and unlock the inode) _and_ the super block won't be unlocked since the inode doesn't get unlocked either. The fix was to allocate pages with GFP_NOFS mask. Cleanups o Some functions were renamed. o Compression algorithms (removed unnecessary data structures that were allocated, made some structures to be allocated statically in the algorithms, some data statically allocated are now kmalloc()) o Removed /proc/sys/vm/comp_cache/actual_size, it doesn't make sense with resizing on demand. Others o Compressed cache only resizes on demand. Index: filemap.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/filemap.c,v retrieving revision 1.34 retrieving revision 1.35 diff -C2 -r1.34 -r1.35 *** filemap.c 16 Jul 2002 18:41:55 -0000 1.34 --- filemap.c 28 Jul 2002 15:47:04 -0000 1.35 *************** *** 183,190 **** struct page * page; - #ifdef CONFIG_COMP_PAGE_CACHE - invalidate_comp_pages(inode->i_mapping); - #endif - head = &inode->i_mapping->clean_pages; --- 183,186 ---- *************** *** 193,196 **** --- 189,196 ---- curr = head->next; + #ifdef CONFIG_COMP_PAGE_CACHE + invalidate_comp_pages(inode->i_mapping); + #endif + while (curr != head) { page = list_entry(curr, struct page, list); *************** *** 341,350 **** unlocked |= truncate_list_pages(&mapping->locked_pages, start, &partial); } while (unlocked); - /* Traversed all three lists without dropping the lock */ - spin_unlock(&pagecache_lock); - #ifdef CONFIG_COMP_PAGE_CACHE truncate_comp_pages(mapping, start, partial); #endif } --- 341,349 ---- unlocked |= truncate_list_pages(&mapping->locked_pages, start, &partial); } while (unlocked); #ifdef CONFIG_COMP_PAGE_CACHE truncate_comp_pages(mapping, start, partial); #endif + /* Traversed all three lists without dropping the lock */ + spin_unlock(&pagecache_lock); } *************** *** 449,457 **** unlocked |= invalidate_list_pages2(&mapping->locked_pages); } while (unlocked); - spin_unlock(&pagecache_lock); #ifdef CONFIG_COMP_PAGE_CACHE if (there_are_dirty_comp_pages(mapping)) { ! lookup_all_comp_pages(mapping); goto try_again; } --- 448,455 ---- unlocked |= invalidate_list_pages2(&mapping->locked_pages); } while (unlocked); #ifdef CONFIG_COMP_PAGE_CACHE if (there_are_dirty_comp_pages(mapping)) { ! lookup_comp_pages(mapping); goto try_again; } *************** *** 459,462 **** --- 457,461 ---- truncate_comp_pages(mapping, 0, 0); #endif + spin_unlock(&pagecache_lock); } *************** *** 609,619 **** spin_lock(&pagecache_lock); } - spin_unlock(&pagecache_lock); #ifdef CONFIG_COMP_PAGE_CACHE if (there_are_dirty_comp_pages(mapping)) { ! lookup_all_comp_pages(mapping); goto try_again; } #endif return ret; } --- 608,618 ---- spin_lock(&pagecache_lock); } #ifdef CONFIG_COMP_PAGE_CACHE if (there_are_dirty_comp_pages(mapping)) { ! lookup_comp_pages(mapping); goto try_again; } #endif + spin_unlock(&pagecache_lock); return ret; } *************** *** 630,640 **** int ret = 0; #ifdef CONFIG_COMP_PAGE_CACHE try_again: ! wait_all_comp_pages(mapping); #endif - spin_lock(&pagecache_lock); - while (!list_empty(&mapping->locked_pages)) { struct page *page = list_entry(mapping->locked_pages.next, struct page, list); --- 629,639 ---- int ret = 0; + spin_lock(&pagecache_lock); + #ifdef CONFIG_COMP_PAGE_CACHE try_again: ! wait_comp_pages(mapping); #endif while (!list_empty(&mapping->locked_pages)) { struct page *page = list_entry(mapping->locked_pages.next, struct page, list); *************** *** 656,664 **** spin_lock(&pagecache_lock); } - spin_unlock(&pagecache_lock); #ifdef CONFIG_COMP_PAGE_CACHE if (there_are_locked_comp_pages(mapping)) goto try_again; #endif return ret; } --- 655,663 ---- spin_lock(&pagecache_lock); } #ifdef CONFIG_COMP_PAGE_CACHE if (there_are_locked_comp_pages(mapping)) goto try_again; #endif + spin_unlock(&pagecache_lock); return ret; } *************** *** 758,762 **** if (readahead) { ! struct page * tmp_page = __find_page_nolock(mapping, offset, *hash); if (!tmp_page && in_comp_cache(mapping, offset)) { page_cache_release(page); --- 757,765 ---- if (readahead) { ! struct page * tmp_page; ! spin_lock(&pagecache_lock); ! tmp_page = __find_page_nolock(mapping, offset, *hash); ! spin_unlock(&pagecache_lock); ! if (!tmp_page && in_comp_cache(mapping, offset)) { page_cache_release(page); *************** *** 768,774 **** int error = 0; #ifdef CONFIG_COMP_PAGE_CACHE ! if (readahead || read_comp_cache(mapping, offset, page)) #endif ! error = mapping->a_ops->readpage(file, page); page_cache_release(page); return error; --- 771,783 ---- int error = 0; #ifdef CONFIG_COMP_PAGE_CACHE ! if (!readahead) { ! if (!read_comp_cache(mapping, offset, page)) { ! UnlockPage(page); ! page_cache_release(page); ! return error; ! } ! } #endif ! error = mapping->a_ops->readpage(file, page); page_cache_release(page); return error; *************** *** 886,889 **** --- 895,900 ---- BUG(); + spin_lock(&pagecache_lock); + /* hack to avoid problems in the function to * add pages to the hash queue, since it does *************** *** 898,901 **** --- 909,914 ---- page->buffers = buffers; + + spin_unlock(&pagecache_lock); } *************** *** 920,938 **** } ! struct page * find_and_dirty_page(struct address_space *mapping, ! unsigned long offset, struct page **hash) { ! struct page *page; ! /* ! * We scan the hash list read-only. Addition to and removal from ! * the hash-list needs a held write-lock. ! */ ! spin_lock(&pagecache_lock); ! page = __find_page_nolock(mapping, offset, *hash); ! if (page) ! __set_page_dirty(page); ! spin_unlock(&pagecache_lock); ! return page; } #endif --- 933,955 ---- } ! /* caller (lookup_comp_page()) holds the pagecache_lock */ ! int find_and_dirty_page(struct page * new_page, struct address_space *mapping, unsigned long offset, struct page **hash) { ! struct page *page = NULL; ! /* ! * We scan the hash list read-only. Addition to and removal from ! * the hash-list needs a held write-lock. ! */ ! page = __find_page_nolock(mapping, offset, *hash); ! if (page) { ! __set_page_dirty(page); ! return 1; ! } ! __add_to_page_cache(new_page, mapping, offset, hash); ! spin_unlock(&pagecache_lock); ! lru_cache_add(new_page); ! spin_lock(&pagecache_lock); ! return 0; } #endif *************** *** 1026,1053 **** spin_lock(&pagecache_lock); page = __find_lock_page_helper(mapping, offset, *hash); #ifdef CONFIG_COMP_PAGE_CACHE ! if (!page && in_comp_cache(mapping, offset)) { if (!cached_page) { - spin_unlock(&pagecache_lock); cached_page = page_cache_alloc(mapping); goto repeat; } ! if (add_to_page_cache_unique(cached_page, mapping, offset, hash)) ! goto out; if (read_comp_cache(mapping, offset, cached_page)) { - __lru_cache_del(cached_page); - __remove_inode_page(cached_page); UnlockPage(cached_page); ! page_cache_release(cached_page); goto out; } ! ! if (TryLockPage(cached_page)) ! BUG(); ! page = cached_page; cached_page = NULL; } out: --- 1043,1085 ---- spin_lock(&pagecache_lock); page = __find_lock_page_helper(mapping, offset, *hash); + spin_unlock(&pagecache_lock); #ifdef CONFIG_COMP_PAGE_CACHE ! if (page) ! goto out; ! if (in_comp_cache(mapping, offset)) { if (!cached_page) { cached_page = page_cache_alloc(mapping); goto repeat; } ! LockPage(cached_page); ! ! spin_lock(&pagecache_lock); + /* the page has been added to page cache after we + * released the pagecache_lock spinlock */ + if (__find_page_nolock(mapping, offset, *hash)) { + spin_unlock(&pagecache_lock); + goto repeat; + } + + /* there are no page in page cache, and we hold the + * pagecache_lock, so we can decompress the + * fragment. In the case the fragment has been removed + * from the compressed cache between in_comp_cache() + * above and this read_comp_cache(), we won't have + * problems since we hold pagecache_lock */ if (read_comp_cache(mapping, offset, cached_page)) { UnlockPage(cached_page); ! spin_unlock(&pagecache_lock); goto out; } ! page = cached_page; cached_page = NULL; + + __add_to_page_cache(page, mapping, offset, hash); + spin_unlock(&pagecache_lock); + lru_cache_add(page); } out: *************** *** 1056,1060 **** page_cache_release(cached_page); - spin_unlock(&pagecache_lock); return page; } --- 1088,1091 ---- *************** *** 1085,1090 **** lru_cache_add(page); #ifdef CONFIG_COMP_PAGE_CACHE ! if (!read_comp_cache(mapping, index, page) && TryLockPage(page)) ! BUG(); #endif } --- 1116,1120 ---- lru_cache_add(page); #ifdef CONFIG_COMP_PAGE_CACHE ! read_comp_cache(mapping, index, page); #endif } *************** *** 1618,1623 **** #ifdef CONFIG_COMP_PAGE_CACHE ! if (!read_comp_cache(mapping, index, page)) goto page_ok; #endif goto readpage; --- 1648,1655 ---- #ifdef CONFIG_COMP_PAGE_CACHE ! if (!read_comp_cache(mapping, index, page)) { ! UnlockPage(page); goto page_ok; + } #endif goto readpage; *************** *** 2913,2919 **** #ifdef CONFIG_COMP_PAGE_CACHE ! if (read_comp_cache(mapping, index, page)) #endif ! err = filler(data, page); --- 2945,2954 ---- #ifdef CONFIG_COMP_PAGE_CACHE ! if (!read_comp_cache(mapping, index, page)) { ! UnlockPage(page); ! goto out; ! } #endif ! err = filler(data, page); *************** *** 2926,2931 **** page_cache_release(cached_page); #ifdef CONFIG_COMP_PAGE_CACHE ! if (page) ! flush_comp_cache(page); #endif return page; --- 2961,2966 ---- page_cache_release(cached_page); #ifdef CONFIG_COMP_PAGE_CACHE ! out: ! flush_comp_cache(page); #endif return page; Index: swap_state.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/swap_state.c,v retrieving revision 1.37 retrieving revision 1.38 diff -C2 -r1.37 -r1.38 *** swap_state.c 16 Jul 2002 18:41:55 -0000 1.37 --- swap_state.c 28 Jul 2002 15:47:04 -0000 1.38 *************** *** 234,242 **** err = add_to_swap_cache(new_page, entry); if (!err) { ! if (readahead || read_comp_cache(&swapper_space, entry.val, new_page)) { ! if (vswap_address(entry)) ! BUG(); ! rw_swap_page(READ, new_page); } return new_page; } --- 234,247 ---- err = add_to_swap_cache(new_page, entry); if (!err) { ! if (!readahead) { ! if (!read_comp_cache(&swapper_space, entry.val, new_page)) { ! UnlockPage(new_page); ! return new_page; ! } } + if (vswap_address(entry)) + BUG(); + + rw_swap_page(READ, new_page); return new_page; } Index: vmscan.c =================================================================== RCS file: /cvsroot/linuxcompressed/linux/mm/vmscan.c,v retrieving revision 1.41 retrieving revision 1.42 diff -C2 -r1.41 -r1.42 *** vmscan.c 16 Jul 2002 18:41:55 -0000 1.41 --- vmscan.c 28 Jul 2002 15:47:04 -0000 1.42 *************** *** 416,419 **** --- 416,420 ---- #endif { + int compressed; ClearPageDirty(page); SetPageLaunder(page); *************** *** 421,425 **** spin_unlock(&pagemap_lru_lock); ! compress_dirty_page(page, writepage, gfp_mask, priority); page_cache_release(page); --- 422,426 ---- spin_unlock(&pagemap_lru_lock); ! compressed = compress_dirty_page(page, writepage, gfp_mask, priority); page_cache_release(page); *************** *** 427,431 **** spin_lock(&pagemap_lru_lock); ! if (!PageCompCache(page)) continue; } --- 428,432 ---- spin_lock(&pagemap_lru_lock); ! if (!compressed) continue; } *************** *** 521,524 **** --- 522,526 ---- page_cache_get(page); + spin_unlock(&pagecache_lock); spin_unlock(&pagemap_lru_lock); *************** *** 528,533 **** spin_lock(&pagemap_lru_lock); ! if (!compressed) continue; } #endif --- 530,539 ---- spin_lock(&pagemap_lru_lock); ! if (!compressed) { ! UnlockPage(page); continue; + } + + spin_lock(&pagecache_lock); } #endif *************** *** 629,638 **** do { nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages); ! if (nr_pages <= 0) { ! #if defined(CONFIG_COMP_CACHE) && !defined(CONFIG_COMP_DEMAND_RESIZE) ! grow_comp_cache(SWAP_CLUSTER_MAX/2); ! #endif return 1; - } } while (--priority); --- 635,640 ---- do { nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages); ! if (nr_pages <= 0) return 1; } while (--priority); |