[linux-mm-cc] Re: [lc-devel] Chunk list issues
Anderson Briglia
briglia.anderson at gmail.com
Tue Jun 27 17:11:02 EDT 2006
Hi Gupta and others,
I have a doubt related to chunk operations:
- I guess you will use the virtual swap as the compressed cache for
anon pages, right? If yes, how will you swapin/swapout chunks? If a
single chunk points to a portion of a physical page, and the
swapin/swapout operations handle entire pages of data.
Best regards,
Anderson Briglia
On 6/27/06, Nitin Gupta <nitingupta.mail at gmail.com> wrote:
> Hi Mauricio,
>
> I am currently implementing compression structure in compress-test module (see
> CompressedCaching/Code). This can then be transfered to ccache git tree.
>
> Also, I've made some changes to chunk_head and chunk structs which further
> compact them by few bytes. I will update Wiki page soon.
>
> I think your code will be useful too. Thanks.
>
> Cheers,
> Nitin Gupta
>
>
> Mauricio Lin wrote:
> > In order to make the development of chunk list operations easier to
> > debug, I have created a module that helps gradually to put more chunk
> > list operation an test it.
> >
> > add_page_to_chunk_list() function is created to call the
> > compress_function() to compress a page and add the related chunk in a
> > chunk list (related and master chunk list). The remaining space of the
> > page after the compression is inserted in the free chunk list.
> > Currently add_page_to_chunk_list() allows just one chunk points to one
> > page, i.e. one chunk for one page. The next idea is to improve the
> > add_page_to_chunk_list() in order to allow many chunks (related chunk)
> > points to a page that stores many compressed pages.
> >
> > The current /proc/chunk_list entry accepts a number as input:
> >
> > # echo 2 > /proc/chunk_list
> >
> > This number is the number of times that new pages will be allocated,
> > compressed and added in the chunk lists using the
> > add_page_to_chunk_list().
> >
> > It shows as output something like:
> >
> > # cat /proc/chunk_list
> >
> > Master chunk list: 3278794752 (792) 3278795544 (3304) 3250196480 (788)
> > 3250197268 (3308) 3250565120 (792) 3250565912 (3304) 3250429952 (788)
> > 3250430740 (3308)
> > Related Chunk list: 3278794752 (792) 3250565120 (792)
> > Related Chunk list: 3250196480 (788) 3250429952 (788)
> > Free list: 3278795544 (3304) 3250197268 (3308) 3250565912 (3304)
> > 3250430740 (3308)
> >
> > The large number is the chunk->start_addr value and the short number
> > inside the brackets is the chunk->size value. It prints the element of
> > each chunk list as "chunk->start_addr (chunk->size)".
> >
> > The current module is presented as follows.
> >
> > #include <linux/module.h>
> > #include <linux/kernel.h>
> > #include <linux/init.h>
> > #include <linux/proc_fs.h>
> > #include <linux/sched.h>
> > #include <asm/uaccess.h>
> >
> > #include <linux/ccache.h>
> >
> > #define MODULE_NAME "chunk_list"
> >
> > static struct proc_dir_entry *chunk_list_file;
> >
> > struct chunk init_chunk = {
> > .start_addr = NULL,
> > .size = 0,
> > .next = NULL,
> > .chunks = LIST_HEAD_INIT(init_chunk.chunks)
> > };
> >
> >
> > // Some related chunk lists
> > struct chunk_head *chk_head_a = NULL;
> >
> > struct chunk_head *chk_head_b = NULL;
> >
> > struct chunk_head *chk_head_free = NULL;
> >
> > // Some macros for chunk list operation
> > #define next_chunk(chk) list_entry((chk)->chunks.next, struct chunk,
> > chunks)
> >
> > #define prev_chunk(chk) list_entry((chk)->chunks.prev, struct chunk,
> > chunks)
> >
> > #define for_each_chunk(chk) \
> > for (chk = &init_chunk ; (chk = next_chunk(chk)) != &init_chunk ; )
> >
> > #define for_each_related_chunk(chk, chk_head) \
> > for (chk = chk_head->chunk_list; chk != NULL; chk = chk->next)
> >
> > /*
> > * Add a chunk in the master chunk list
> > */
> > static inline void add_chunk_to_list(struct chunk *chk)
> > {
> > list_add_tail(&chk->chunks, &init_chunk.chunks);
> > }
> >
> > /*
> > * Delete a chunk from the master chunk list
> > */
> > static inline void del_chunk_from_list(struct chunk *chk)
> > {
> > list_del(&chk->chunks);
> > }
> >
> > /*
> > * Add a chunk in the related chunk list
> > */
> > static inline void add_related_chunk_to_list(struct chunk_head *chk_head,
> > struct chunk *new_chk)
> > {
> > struct chunk *chk = NULL;
> >
> > if (chk_head->chunk_list) {
> > chk = chk_head->chunk_list;
> > while (chk->next)
> > chk = chk->next;
> > chk->next = new_chk;
> > }
> > else
> > chk_head->chunk_list=new_chk;
> >
> > new_chk->next = NULL;
> >
> > // Add to master chunk list as well
> > add_chunk_to_list(new_chk);
> > }
> >
> > /*
> > * Delete all related chunks from the list
> > */
> > static inline void del_all_related_chunks_from_list(struct chunk_head
> > *chk_head)
> > {
> > struct chunk *chk = NULL;
> >
> > while (chk_head->chunk_list) {
> > chk = chk_head->chunk_list;
> > chk_head->chunk_list = chk->next;
> >
> > // Delete from master chunk list
> > del_chunk_from_list(chk);
> >
> > // Free the chunk
> > kfree(chk);
> > }
> > }
> >
> > /*
> > * Add a chunk in the free chunk list
> > */
> > static inline void add_chunk_to_free_list(void *start_addr,
> > unsigned short size)
> > {
> > struct chunk *chk = NULL;
> > chk = (struct chunk *)kmalloc(sizeof(struct chunk),
> > GFP_KERNEL);
> > chk->start_addr = start_addr + size;
> > chk->size = PAGE_SIZE - size;
> > add_related_chunk_to_list(chk_head_free, chk);
> > }
> >
> > /*
> > * Add a page in the chunk list (NOT FINISHED YET)
> > */
> > static inline void add_page_to_chunk_list(struct chunk_head *chk_head,
> > struct page *page)
> > {
> > struct page *comp_page = NULL;
> > struct chunk *chk = NULL;
> >
> > // compress the page
> > comp_page = compress_function(page);
> >
> > if (comp_page) {
> > // create the chunk
> > chk = (struct chunk *)kmalloc(sizeof(struct chunk),
> > GFP_KERNEL);
> > chk->start_addr = page_address(comp_page);
> > chk->size = comp_page->comp_size;
> >
> > // add to list
> > add_related_chunk_to_list(chk_head, chk);
> >
> > // add the remaining space in the free chunk list
> > if (chk->size < PAGE_SIZE)
> > add_chunk_to_free_list(chk->start_addr, chk->size);
> >
> > }
> > }
> >
> >
> > static int read_chunk_list(char *page, char **start,
> > off_t off, int count,
> > int *eof, void *data)
> > {
> > int len = 0;
> > struct chunk *chk;
> > char *output;
> > char *item;
> >
> > output = kmalloc(100, GFP_KERNEL);
> > item = kmalloc(6, GFP_KERNEL);
> > strcpy(output, "Master chunk list: ");
> > if (!list_empty(&init_chunk.chunks)) {
> >
> > for_each_chunk(chk) {
> > sprintf(item, "%lu (%d) ", (unsigned long)(chk->start_addr),
> > chk->size);
> > strcat(output, item);
> > }
> >
> > strcat(output, "\n Related Chunk list: ");
> > for_each_related_chunk(chk, chk_head_a) {
> > sprintf(item, "%lu (%d) ", (unsigned long)(chk->start_addr),
> > chk->size);
> > strcat(output, item);
> > }
> >
> > strcat(output, "\n Related Chunk list: ");
> > for_each_related_chunk(chk, chk_head_b) {
> > sprintf(item, "%lu (%d) ", (unsigned long)(chk->start_addr),
> > chk->size);
> > strcat(output, item);
> > }
> >
> > strcat(output, "\n Free list: ");
> > for_each_related_chunk(chk, chk_head_free) {
> > sprintf(item, "%lu (%d) ", (unsigned long)(chk->start_addr),
> > chk->size);
> > strcat(output, item);
> > }
> > strcat(output, "\n");
> > len = sprintf(page, output);
> > kfree(output);
> > kfree(item);
> > }
> > else {
> > len = sprintf(page, "\n");
> > }
> >
> > return len;
> > }
> >
> > static int write_chunk_list(struct file *file,
> > const char *buffer,
> > unsigned long count,
> > void *data)
> > {
> > char *input;
> > int i;
> > struct page *page;
> > unsigned int nr;
> >
> > input = kmalloc(count, GFP_KERNEL);
> >
> > if (!input)
> > return -ENOMEM;
> > if(copy_from_user(input, buffer, count)) {
> > kfree(input);
> > return -EFAULT;
> > }
> >
> > nr = simple_strtoul(input, NULL, 10);
> >
> > //del_all_related_chunks_from_list(chk_head_a);
> >
> > for (i=0; i<nr; i++) {
> > page = alloc_page(GFP_KERNEL);
> > memset(page_address(page), 1, PAGE_SIZE/2);
> > memset(page_address(page) + PAGE_SIZE/2, 4, PAGE_SIZE/2);
> > add_page_to_chunk_list(chk_head_a, page);
> >
> > page = alloc_page(GFP_KERNEL);
> > memset(page_address(page), 1, PAGE_SIZE);
> > add_page_to_chunk_list(chk_head_b, page);
> > }
> >
> > kfree(input);
> > return count;
> > }
> >
> > static int __init init_chunk_list(void)
> > {
> > int flag = 0;
> > chunk_list_file = create_proc_entry("chunk_list", S_IRUGO | S_IWUSR,
> > NULL);
> > chunk_list_file->read_proc = read_chunk_list;
> > chunk_list_file->write_proc = write_chunk_list;
> > chunk_list_file->owner = THIS_MODULE;
> >
> > chk_head_a = (struct chunk_head *)kmalloc(sizeof(struct chunk_head),
> > GFP_KERNEL);
> > chk_head_a->chunk_list = NULL;
> >
> > chk_head_b = (struct chunk_head *)kmalloc(sizeof(struct chunk_head),
> > GFP_KERNEL);
> > chk_head_b->chunk_list = NULL;
> >
> > chk_head_free = (struct chunk_head *)kmalloc(sizeof(struct chunk_head),
> > GFP_KERNEL);
> > chk_head_free->chunk_list = NULL;
> >
> > printk(KERN_DEBUG "%s included\n", MODULE_NAME);
> > return flag;
> > }
> >
> > static void __exit cleanup_chunk_list(void)
> > {
> > del_all_related_chunks_from_list(chk_head_a);
> > del_all_related_chunks_from_list(chk_head_b);
> > del_all_related_chunks_from_list(chk_head_free);
> > kfree(chk_head_a);
> > kfree(chk_head_b);
> > kfree(chk_head_free);
> > remove_proc_entry("chunk_list", NULL);
> > printk(KERN_DEBUG "%s removed\n", MODULE_NAME);
> > }
> >
> > module_init(init_chunk_list);
> > module_exit(cleanup_chunk_list);
> > MODULE_LICENSE("GPL");
> >
> > BR,
> >
> > Mauricio Lin.
> >
>
>
> Using Tomcat but need to do more? Need to support web services, security?
> Get stuff done quickly with pre-integrated technology to make your job easier
> Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
> http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
> _______________________________________________
> linuxcompressed-devel mailing list
> linuxcompressed-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linuxcompressed-devel
>
More information about the linux-mm-cc
mailing list