/* * hello-1.c - The simplest kernel module. */ #include /* Needed by all modules */ #include /* Needed for KERN_INFO */ #include #ifdef DBG_MEMORY_LEAK #include atomic_t _malloc_cnt = ATOMIC_INIT(0); atomic_t _malloc_size = ATOMIC_INIT(0); #endif /* DBG_MEMORY_LEAK */ void* _rtw_malloc(u32 sz) { void *pbuf = NULL; pbuf = kmalloc(sz, /*GFP_KERNEL*/GFP_ATOMIC); #ifdef DBG_MEMORY_LEAK if (pbuf != NULL) { atomic_inc(&_malloc_cnt); atomic_add(sz, &_malloc_size); } #endif return pbuf; } void _rtw_mfree(const void *pbuf, u32 sz) { if (pbuf) { kfree(pbuf); #ifdef DBG_MEMORY_LEAK atomic_dec(&_malloc_cnt); atomic_sub(sz, &_malloc_size); #endif } } void* _rtw_zmalloc(u32 sz) { void *pbuf = _rtw_malloc(sz); if (pbuf != NULL) { memset(pbuf, 0, sz); } return pbuf; } #define rtw_malloc(sz) _rtw_malloc((sz)) #define rtw_zmalloc(sz) _rtw_zmalloc((sz)) #define rtw_mfree(pbuf, sz) _rtw_mfree((pbuf), (sz)) struct prealloc_node { struct list_head entry; int type; int size; void *buf; }; struct list_head alloc_list; struct list_head free_list; spinlock_t lock; void *rtw_find_prealloc(int type, size_t size) { struct list_head *phead, *plist; struct prealloc_node *node; unsigned long flags; void *pbuf = NULL; spin_lock_irqsave(&lock, flags); phead = &free_list; plist = phead->next; while (plist != phead) { node = list_entry(plist, struct prealloc_node, entry); plist = plist->next; if (node->type == type) { // deletes entry from free_list list_del(&node->entry); // add a new entry to alloc_list list_add_tail(&node->entry, &alloc_list); pbuf = node->buf; break; } } spin_unlock_irqrestore(&lock, flags); return pbuf; } void *rtw_pre_malloc(int type, size_t size) { struct prealloc_node *node; void *pbuf; unsigned long flags; pbuf = rtw_find_prealloc(type, size); if (pbuf) return pbuf; node = rtw_zmalloc(sizeof(struct prealloc_node)); if (NULL == node) return NULL; node->buf = rtw_zmalloc(size); if (NULL == node->buf) { rtw_mfree(node, sizeof(struct prealloc_node)); return NULL; } node->type = type; node->size = size; // add a new entry to alloc_list spin_lock_irqsave(&lock, flags); list_add_tail(&node->entry, &alloc_list); spin_unlock_irqrestore(&lock, flags); return node->buf; } EXPORT_SYMBOL(rtw_pre_malloc); void rtw_pre_free(const void *p) { struct list_head *phead, *plist; struct prealloc_node *node; unsigned long flags; spin_lock_irqsave(&lock, flags); phead = &alloc_list; plist = phead->next; while (plist != phead) { node = list_entry(plist, struct prealloc_node, entry); plist = plist->next; if (node->buf == p) { // deletes entry from alloc_list list_del(&node->entry); // add a new entry to free_list list_add_tail(&node->entry, &free_list); goto out; } } printk("[%s] invalid address.\n", __func__); out: spin_unlock_irqrestore(&lock, flags); } EXPORT_SYMBOL(rtw_pre_free); void rtw_init(void) { INIT_LIST_HEAD(&alloc_list); INIT_LIST_HEAD(&free_list); spin_lock_init(&lock); } void rtw_free(void) { struct list_head *phead, *plist; struct prealloc_node *node; unsigned long flags; spin_lock_irqsave(&lock, flags); phead = &free_list; plist = phead->next; while (plist != phead) { node = list_entry(plist, struct prealloc_node, entry); plist = plist->next; rtw_mfree(node->buf, node->size); rtw_mfree(node, sizeof(struct prealloc_node)); } phead = &alloc_list; plist = phead->next; while (plist != phead) { node = list_entry(plist, struct prealloc_node, entry); plist = plist->next; printk("WARNING!! prealloc memory is not freed(type %d size %d).\n", node->type, node->size); rtw_mfree(node->buf, node->size); rtw_mfree(node, sizeof(struct prealloc_node)); } spin_unlock_irqrestore(&lock, flags); } int init_module(void) { printk(KERN_INFO "Hello world 1.\n"); rtw_init(); /* * A non 0 return means init_module failed; module can't be loaded. */ return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye world 1.\n"); rtw_free(); }