diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 8ff667776b0c005281ea938f44d88cd4ef8a2c51..4b91e5a2797ee019c368230386ad967ef4bd3eea 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -57,6 +57,10 @@ static void zram_free_page(struct zram *zram, size_t index); static int zram_read_page(struct zram *zram, struct page *page, u32 index, struct bio *parent); +#ifdef CONFIG_ZRAM_PAGE_TRACE +struct anon_vma *folio_anon_vma(struct folio *folio); +#endif + #ifdef CONFIG_PREEMPT_RT static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) { @@ -1455,6 +1459,10 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) struct zcomp_strm *zstrm; unsigned long element = 0; enum zram_pageflags flags = 0; +#ifdef CONFIG_ZRAM_PAGE_TRACE + struct anon_vma *tmp; + struct folio *folio = page_folio(page); +#endif mem = kmap_atomic(page); if (page_same_filled(mem, &element)) { @@ -1558,8 +1566,39 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) if (flags) { zram_set_flag(zram, index, flags); +#ifdef CONFIG_ZRAM_PAGE_TRACE + if (flags == ZRAM_SAME){ + tmp = folio_anon_vma(folio); + if (tmp == NULL) { + unsigned long mapping; + struct address_space *addr_space; + + addr_space = page_mapping(page); + zram->table[index].mapping = (unsigned long)addr_space; + zram->table[index].pgoff = page_to_pgoff(page); + } else { + zram->table[index].mapping = (unsigned long)tmp | 1; + zram->table[index].pgoff = page_to_pgoff(page); + } + + } +#endif zram_set_element(zram, index, element); } else { +#ifdef CONFIG_ZRAM_PAGE_TRACE + tmp = folio_anon_vma(folio); + if (tmp == NULL) { + unsigned long mapping; + struct address_space *addr_space; + + addr_space = page_mapping(page); + zram->table[index].mapping = (unsigned long)addr_space; + zram->table[index].pgoff = page_to_pgoff(page); + } else { + zram->table[index].mapping = (unsigned long)tmp | 1; + zram->table[index].pgoff = page_to_pgoff(page); + } +#endif zram_set_handle(zram, index, handle); zram_set_obj_size(zram, index, comp_len); } @@ -1990,6 +2029,9 @@ static void zram_bio_write(struct zram *zram, struct bio *bio) bio_endio(bio); } +#ifdef CONFIG_ZRAM_PAGE_TRACE + int get_zram_major(void) {return zram_major;} +#endif /* * Handler function for all zram I/O requests. */ diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 4e0c7c6d481328d719527415551c83f3fe0614d2..f51ccab07cb155c27b03f53f2411d228771ee806 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -69,6 +69,10 @@ struct zram_table_entry { unsigned long element; }; unsigned long flags; +#ifdef CONFIG_ZRAM_PAGE_TRACE + unsigned long mapping; + unsigned long pgoff; +#endif #ifdef CONFIG_PREEMPT_RT spinlock_t lock; #endif diff --git a/mm/swapfile.c b/mm/swapfile.c index eada1351753e346502199b7a8ec7e7673d1a5056..4224e9667e79e08435c97459d283331c75c4a2ad 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -74,6 +74,11 @@ static const char Bad_file[] = "Bad swap file entry "; static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; static const char Unused_offset[] = "Unused swap offset entry "; +#ifdef CONFIG_ZRAM_PAGE_TRACE +extern int add_zram_attr(const char *name, void *pri_data); +extern int rm_zram_attr(void *pri_data); +extern int get_zram_major(void); +#endif /* * all active swap_info_structs @@ -2570,6 +2575,12 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) filp_close(victim, NULL); out: putname(pathname); +#ifdef CONFIG_ZRAM_PAGE_TRACE + if (!err && p->bdev->bd_disk->major > 0) { + if (p->bdev->bd_disk->major == get_zram_major()) + rm_zram_attr(p->bdev->bd_disk->private_data); + } +#endif return err; } @@ -3243,6 +3254,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) putname(name); if (inode) inode_unlock(inode); +#ifdef CONFIG_ZRAM_PAGE_TRACE + if (!error && p->bdev->bd_disk->major > 0) { + if (p->bdev->bd_disk->major == get_zram_major()) + add_zram_attr(p->bdev->bd_disk->disk_name, + p->bdev->bd_disk->private_data); + } +#endif if (!error) enable_swap_slots_cache(); return error; diff --git a/nos/extend_features/zram_page_trace/Kconfig b/nos/extend_features/zram_page_trace/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..41803269f096dfe569e1711d187acca15cf67a67 --- /dev/null +++ b/nos/extend_features/zram_page_trace/Kconfig @@ -0,0 +1,7 @@ +config ZRAM_PAGE_TRACE + bool "Tracing zero and nozero pages of zram" + depends on ZRAM=y && MEMCG=y && DEBUG_FS=y + default n + help + This option can provide infomation of zero and nozero pages + if we want to know about more of them. diff --git a/nos/extend_features/zram_page_trace/Makefile b/nos/extend_features/zram_page_trace/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3200288bf96ade7e4abb484591e77a62e5f4a919 --- /dev/null +++ b/nos/extend_features/zram_page_trace/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ZRAM_PAGE_TRACE) += zram_page_trace.o diff --git a/nos/extend_features/zram_page_trace/zram_page_trace.c b/nos/extend_features/zram_page_trace/zram_page_trace.c new file mode 100755 index 0000000000000000000000000000000000000000..77a3ce8266ba8bb134722613b0e454c6ed05e20c --- /dev/null +++ b/nos/extend_features/zram_page_trace/zram_page_trace.c @@ -0,0 +1,362 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../drivers/block/zram/zram_drv.h" + +struct zram_tracker { + struct list_head zlist; + struct zram *zram; + struct dentry *attr; +}; + +/*extern struct vm_area_struct *vma_interval_tree_iter_first(struct rb_root *root, + unsigned long start, unsigned long last); +extern struct vm_area_struct *vma_interval_tree_iter_next(struct vm_area_struct *node, + unsigned long start, unsigned long last); +*/ +static struct dentry *dzram; +static struct zram_tracker *ztrack_head; + +static int is_stack(struct vm_area_struct *vma) +{ + /* + * We make no effort to guess what a given thread considers to be + * its "stack". It's not even well-defined for programs written + * languages like Go. + */ + return vma->vm_start <= vma->vm_mm->start_stack && + vma->vm_end >= vma->vm_mm->start_stack; +} + + +static bool zram_test_flag(struct zram *zram, u32 index, + enum zram_pageflags flag) +{ + return zram->table[index].flags & BIT(flag); +} + +static unsigned long zram_get_element(struct zram *zram, u32 index) +{ + return zram->table[index].element; +} + +static void show_one_vma_info(struct seq_file *s, struct vm_area_struct *vma, unsigned long address) +{ + const char *name = NULL; + struct mm_struct *mm; + struct file *file = vma->vm_file; + struct task_struct *p; + + vm_flags_t flags = vma->vm_flags; + mm = vma->vm_mm; + p = mm->owner; + if (!p && !file) { + WARN_ON(1); + seq_printf(s, "BUG: can't find the owner of vma[%p]\n", vma); + return; + } + if (p) { + seq_printf(s, "task[%s:%d] addr[%08lx] %c%c%c%c ", + p->comm, p->tgid, address, + flags & VM_READ ? 'r' : '-', + flags & VM_WRITE ? 'w' : '-', + flags & VM_EXEC ? 'x' : '-', + flags & VM_MAYSHARE ? 's' : 'p'); + } else if (file) { + seq_printf(s, "addr[%08lx] %c%c%c%c ", address, + flags & VM_READ ? 'r' : '-', + flags & VM_WRITE ? 'w' : '-', + flags & VM_EXEC ? 'x' : '-', + flags & VM_MAYSHARE ? 's' : 'p'); + seq_pad(s, ' '); + seq_file_path(s, file, "\n"); + goto show; + } + if (vma->vm_ops && vma->vm_ops->name) { + name = vma->vm_ops->name(vma); + if (name) + goto show; + } + + if (!name) { + if (!mm) { + name = "[vdso]"; + goto show; + } + if (vma->vm_start <= mm->end_data && + vma->vm_end >= mm->start_data) { + name = "[data]"; + goto show; + } + if (vma->vm_start <= mm->brk && + vma->vm_end >= mm->start_brk) { + name = "[heap]"; + goto show; + } + if (is_stack(vma)) + name = "[stack]"; + } +show: + if (name) { + seq_pad(s, ' '); + seq_puts(s, name); + } + seq_putc(s, '\n'); +} + +static void show_anon_info(struct seq_file *s, struct anon_vma *anon_vma, pgoff_t pgoff) +{ + struct anon_vma_chain *avc; + unsigned long address = 0; + + if (!anon_vma) { + WARN(1, KERN_INFO "show_anon_info: anon_vma is NULL!\n"); + return; + } + + anon_vma_lock_read(anon_vma); + anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) { + struct vm_area_struct *vma = avc->vma; + if (!vma) { + WARN_ON(1); + continue; + } + address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); + show_one_vma_info(s, vma, address); + } + anon_vma_unlock_read(anon_vma); +} + +static void show_mapping_info(struct seq_file *s, struct address_space *mapping, pgoff_t pgoff) +{ + struct vm_area_struct *vma; + + if (!mapping) { + WARN(1, KERN_INFO "show_mapping_info: mapping is NULL\n"); + return; + } + + i_mmap_lock_read(mapping); + vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) { + unsigned long address; + + address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); + show_one_vma_info(s, vma, address); + } + i_mmap_unlock_read(mapping); +} + +static void zram_onepage_show(struct seq_file *s, struct zram *m, size_t index) +{ + struct zram *pzram = m; + struct address_space *mapping; + struct anon_vma * anon_vma; + + if (!(pzram->table[index].mapping)){ + return; + } + + if ((pzram->table[index].mapping & 1) == 0) { + mapping = (struct address_space *)pzram->table[index].mapping; + show_mapping_info(s, mapping, pzram->table[index].pgoff); + + } else { + anon_vma = (struct anon_vma *)(pzram->table[index].mapping - 1); + show_anon_info(s, anon_vma, pzram->table[index].pgoff); + } + return; +} + +static int zram_page_show(struct seq_file *s, void *v, bool active) +{ + u64 disksize; + size_t index, num_pages; + struct zram *pzram = s->private; + + if (!pzram) { + WARN_ON(1); + return -ENODEV; + } + disksize = pzram->disksize; + num_pages = disksize >> PAGE_SHIFT; + + if (pzram) + seq_printf(s, "%s: has %d pages\n", pzram->disk->disk_name, (int)num_pages); + for (index = 0; index < num_pages; index++) { + if (zram_test_flag(pzram, index, ZRAM_SAME) && zram_get_element(pzram, index) == 0) { + if (active) + continue; + zram_onepage_show(s, pzram, index); + } else { + if (!active) + continue; + zram_onepage_show(s, pzram, index); + } + } + + return 0; +} + +static int zram_zeropage_show(struct seq_file *s, void *v) +{ + return zram_page_show(s,v,false); +} +static int zram_nozeropage_show(struct seq_file *s, void *v) +{ + return zram_page_show(s,v,true); +} + +static int zram_zeropage_open(struct inode *inode, struct file *file) +{ + return single_open(file, zram_zeropage_show, inode->i_private); +} + +static int zram_nozeropage_open(struct inode *inode, struct file *file) +{ + return single_open(file, zram_nozeropage_show, inode->i_private); +} + +static ssize_t zram_zero_write(struct file *file, char const __user *buf, + size_t count, loff_t *ppos) +{ + pr_info("THIS FUNCTION IS RESERVED NOW\n"); + + return count; +} + +static const struct file_operations zram_zero_fops = { + .owner = THIS_MODULE, + .open = zram_zeropage_open, + .read = seq_read, + .write = zram_zero_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations zram_nozero_fops = { + .owner = THIS_MODULE, + .open = zram_nozeropage_open, + .read = seq_read, + .write = zram_zero_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init zram_track_init(void) +{ + dzram = debugfs_create_dir("zram_track", NULL); + if (!dzram) + return -ENODEV; + + ztrack_head = kmalloc(sizeof(*ztrack_head), GFP_KERNEL); + if (!ztrack_head){ + debugfs_remove_recursive(dzram); + return -ENOMEM; + } + + INIT_LIST_HEAD(&ztrack_head->zlist); + + return 0; +} + +int add_zram_attr(const char *name, void *pri_data) +{ + int ret = 0; + struct zram_tracker *ztrack; + struct dentry *ztrack_dir; + struct dentry *ztrack_zero; + struct dentry *ztrack_nozero; + + if (!dzram) { + pr_err(" zram_track not inited\n"); + return -ENODEV; + } + + ztrack_dir = debugfs_create_dir(name, dzram); + if (!ztrack_dir) { + pr_alert("Could not create %s\n", name); + return -ENODEV; + } + + ztrack_zero = debugfs_create_file("zeropage_trace", 0400, ztrack_dir, + pri_data, &zram_zero_fops); + if (!ztrack_zero) { + pr_alert("Could not create zeropage_trace\n"); + ret = -ENODEV; + goto fail; + } + + ztrack_nozero = debugfs_create_file("nozeropage_trace", 0400, ztrack_dir, + pri_data, &zram_nozero_fops); + if (!ztrack_nozero) { + pr_alert("Could not create nozeropage_trace\n"); + ret = -ENODEV; + goto fail; + } + + ztrack = kmalloc(sizeof(struct zram_tracker), GFP_KERNEL); + if (!ztrack) { + ret = -ENOMEM; + goto fail; + } + ztrack->attr = ztrack_dir; + ztrack->zram = (struct zram *)pri_data; + list_add(&ztrack->zlist, &ztrack_head->zlist); + return ret; + +fail: + debugfs_remove(ztrack_dir); + return ret; +} +EXPORT_SYMBOL(add_zram_attr); + +int rm_zram_attr(void *pri_data) +{ + struct zram_tracker *ztrack; + + list_for_each_entry(ztrack, &ztrack_head->zlist, zlist) { + if (pri_data == ztrack->zram) + break; + } + + if (&ztrack->zlist == &ztrack_head->zlist) { + pr_err(" rm_zram_attr fail: cannot find %p\n", pri_data); + return -ENODEV; + } + + if (ztrack->attr) { + list_del(&ztrack->zlist); + debugfs_remove(ztrack->attr); + kfree(ztrack); + } + + return 0; +} +EXPORT_SYMBOL(rm_zram_attr); + +static void __exit zram_track_exit(void) +{ + struct zram_tracker *ztrack, *tmp; + + + debugfs_remove_recursive(dzram); + list_for_each_entry_safe(ztrack, tmp, &ztrack_head->zlist, zlist) { + kfree(ztrack); + } + kfree(ztrack_head); +} + +module_init(zram_track_init); +module_exit(zram_track_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("CGEL"); +MODULE_DESCRIPTION("Debugfs module");