Commit ec790197 authored by Muktesh Khole's avatar Muktesh Khole Committed by Vikram Narayanan

added memory reclaim feature

parent 32ecf3ff
...@@ -23,15 +23,10 @@ int lcd_init_cspace(struct cspace *cspace) { ...@@ -23,15 +23,10 @@ int lcd_init_cspace(struct cspace *cspace) {
return -ENOMEM; return -ENOMEM;
}; };
cspace->cdt_root_cache = KMEM_CACHE(cdt_root_node, 0);
if(!cspace->cdt_root_cache){
printk(KERN_ERR "lcd_cap Failed to allocate cdt_root slab\n");
return -ENOMEM;
};
cspace->cnode_table = kmem_cache_alloc(cspace->cnode_table_cache, 0); cspace->cnode_table = kmem_cache_alloc(cspace->cnode_table_cache, 0);
for (i = 0; i < MAX_SLOTS_PER_TABLE; i++) for (i = 0; i < MAX_SLOTS_PER_TABLE; i++)
{ {
spin_lock_init(&(cspace->cnode_table->cnode[i].lock));
cspace->cnode_table->cnode[i].type = LCD_CAP_TYPE_FREE; cspace->cnode_table->cnode[i].type = LCD_CAP_TYPE_FREE;
cspace->cnode_table->table_level = 0; cspace->cnode_table->table_level = 0;
} }
...@@ -108,7 +103,6 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap, ...@@ -108,7 +103,6 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap,
{ {
unsigned long flags, flags_cnode_lock; unsigned long flags, flags_cnode_lock;
struct cnode *cnode; struct cnode *cnode;
struct cdt_root_node *cdt_node;
spin_lock_irqsave(&cspace->lock, flags); spin_lock_irqsave(&cspace->lock, flags);
if (cspace->state != ALLOCATION_VALID) if (cspace->state != ALLOCATION_VALID)
...@@ -125,7 +119,6 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap, ...@@ -125,7 +119,6 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap,
cnode->object = object; cnode->object = object;
spin_lock_irqsave(&cnode->lock, flags_cnode_lock); spin_lock_irqsave(&cnode->lock, flags_cnode_lock);
cdt_node = kmem_cache_alloc(cspace->cdt_root_cache, 0);
spin_unlock_irqrestore(&cspace->lock, flags); spin_unlock_irqrestore(&cspace->lock, flags);
cnode->cap = cap; cnode->cap = cap;
...@@ -135,13 +128,9 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap, ...@@ -135,13 +128,9 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap,
cnode->prev = NULL; cnode->prev = NULL;
cnode->child = NULL; cnode->child = NULL;
cnode->type = type; cnode->type = type;
cnode->cdt_root = cdt_node; cnode->cdt_root = get_cdt_root();
cnode->cdt_root->state = ALLOCATION_VALID;
cnode->cdt_root->node_count = 0;
spin_lock_init(&(cnode->cdt_root->lock));
cnode->cdt_root->cnode = cnode; cnode->cdt_root->cnode = cnode;
cnode->cdt_root->node_count = 1; cnode->cdt_root->node_count = 1;
cnode->cdt_root->state = ALLOCATION_VALID;
//lcd_cnode_release(cnode); //lcd_cnode_release(cnode);
spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock); spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock);
...@@ -193,19 +182,10 @@ void lcd_cap_delete(struct cspace *cspace, capability_t cap) { ...@@ -193,19 +182,10 @@ void lcd_cap_delete(struct cspace *cspace, capability_t cap) {
spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock); spin_unlock_irqrestore(&cnode->lock, flags_cnode_lock);
if (done) { if (done) {
lcd_free_cap(&(cspace->cap_cache), cap);
if (last_node) { if (last_node) {
// at this point we are not holding any locks free_cdt_root(cdt_node);
// so its ok to request for cspace lock
spin_lock_irqsave(&cspace->lock, flags);
if (cspace->state != ALLOCATION_VALID) {
spin_unlock_irqrestore(&cspace->lock, flags);
return;
}
cdt_node->state = ALLOCATION_REMOVED;
kmem_cache_free(cspace->cdt_root_cache, cdt_node);
spin_unlock_irqrestore(&(cspace->lock), flags);
} }
lcd_free_cap(&(cspace->cap_cache), cap);
} else { } else {
// someone is using CDT root // someone is using CDT root
// wait for him to finish // wait for him to finish
...@@ -414,19 +394,10 @@ int lcd_cap_revoke(struct cspace *cspace, capability_t cap) { ...@@ -414,19 +394,10 @@ int lcd_cap_revoke(struct cspace *cspace, capability_t cap) {
if (done) { if (done) {
lcd_free_cap(&(cspace->cap_cache), cap);
if (last_node) { if (last_node) {
// at this point we are not holding any locks free_cdt_root(cdt_node);
// so its ok to request for cspace lock
spin_lock_irqsave(&cspace->lock, flags);
if (cspace->state != ALLOCATION_VALID) {
spin_unlock_irqrestore(&cspace->lock, flags);
return 0;
}
cdt_node->state = ALLOCATION_REMOVED;
kmem_cache_free(cspace->cdt_root_cache, cdt_node);
spin_unlock_irqrestore(&(cspace->lock), flags);
} }
lcd_free_cap(&(cspace->cap_cache), cap);
} else { } else {
// someone is using CDT root // someone is using CDT root
// wait for him to finish // wait for him to finish
...@@ -438,6 +409,23 @@ int lcd_cap_revoke(struct cspace *cspace, capability_t cap) { ...@@ -438,6 +409,23 @@ int lcd_cap_revoke(struct cspace *cspace, capability_t cap) {
}; };
EXPORT_SYMBOL(lcd_cap_revoke); EXPORT_SYMBOL(lcd_cap_revoke);
int lcd_cap_destroy_cspace(struct cspace *cspace) {
int res;
unsigned long flags;
spin_lock_irqsave(&cspace->lock, flags);
if (cspace->state != ALLOCATION_VALID)
{
spin_unlock_irqrestore(&cspace->lock, flags);
return -EIDRM;
}
cspace->state = ALLOCATION_MARKED_FOR_DELETE;
spin_unlock_irqrestore(&cspace->lock, flags);
res = _lcd_delete_table(cspace, cspace->cnode_table);
return res;
};
EXPORT_SYMBOL(lcd_cap_destroy_cspace);
int lcd_cnode_insert(struct cspace *cspace, capability_t cap, struct cnode *cnode) { int lcd_cnode_insert(struct cspace *cspace, capability_t cap, struct cnode *cnode) {
/* XXX: not clear */ /* XXX: not clear */
return 0; return 0;
...@@ -547,4 +535,60 @@ bool _lcd_delete_node (struct cnode *cnode){ ...@@ -547,4 +535,60 @@ bool _lcd_delete_node (struct cnode *cnode){
last_node = true; last_node = true;
} }
return last_node; return last_node;
} }
\ No newline at end of file
int _lcd_delete_table(struct cspace *cspace, struct cnode_table *table) {
unsigned long flags;
capability_t index = MAX_CAP_SLOTS;
struct cnode *cnode;
struct cdt_root_node *cdt_node;
bool last_node = false;
if (table == NULL || table->cnode[index].type == LCD_CAP_TYPE_FREE) {
return -EINVAL;
}
while (index < MAX_SLOTS_PER_TABLE) {
_lcd_delete_table(cspace, table->cnode[index].object);
// traversal through cnode_table happens only after locking cspace and checking if cspace is valid.
// we have already marked cspace as invalid so insert, revoke and delete cannot reach here.
table->cnode[index].type = LCD_CAP_TYPE_FREE;
index++;
}
index = 0;
while (index < MAX_CAP_SLOTS) {
spin_lock_irqsave(&(table->cnode[index].lock), flags);
if (table->cnode[index].type == LCD_CAP_TYPE_FREE) {
index++;
spin_unlock_irqrestore(&(table->cnode[index].lock), flags);
continue;
}
cnode = &(table->cnode[index]);
if (spin_trylock(&(cnode->cdt_root->lock))) {
cdt_node = cnode->cdt_root;
last_node = _lcd_delete_node(cnode);
if (last_node) {
cdt_node->state = ALLOCATION_MARKED_FOR_DELETE;
}
cnode->cdt_root = NULL;
spin_unlock(&(cdt_node->lock));
spin_unlock_irqrestore(&(cnode->lock), flags);
lcd_free_cap(&(cspace->cap_cache), cnode->cap);
index++;
} else {
spin_unlock_irqrestore(&(table->cnode[index].lock), flags);
msleep(1);
}
if (last_node) {
free_cdt_root(cdt_node);
last_node = false;
}
}
// no locks are being held till here
spin_lock_irqsave(&cspace->lock, flags);
kmem_cache_free(cspace->cnode_table_cache, table);
spin_unlock_irqrestore(&cspace->lock, flags);
return 0;
}
\ No newline at end of file
...@@ -8,12 +8,29 @@ ...@@ -8,12 +8,29 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <lcd/cap.h>
#include "test.h" #include "test.h"
struct cdt_cache_t {
spinlock_t lock;
struct kmem_cache *cdt_root_cache;
};
struct cdt_cache_t cdt_cache;
int __init api_init(void) int __init api_init(void)
{ {
bool res = true; bool res = true;
printk(KERN_ERR "lcd cspace entering module"); printk(KERN_ERR "lcd_cap entering module");
spin_lock_init(&(cdt_cache.lock));
cdt_cache.cdt_root_cache = KMEM_CACHE(cdt_root_node, 0);
if(!cdt_cache.cdt_root_cache){
printk(KERN_ERR "lcd_cap Failed to initialize cdt_root_node allocator\n");
return -ENOMEM;
};
res = begintests(); res = begintests();
if (res == false) { if (res == false) {
printk(KERN_ERR "tests failed"); printk(KERN_ERR "tests failed");
...@@ -29,6 +46,27 @@ void __exit api_exit(void) ...@@ -29,6 +46,27 @@ void __exit api_exit(void)
return; return;
} }
struct cdt_root_node * get_cdt_root(void) {
unsigned long flags;
struct cdt_root_node *cdt_node;
spin_lock_irqsave(&cdt_cache.lock, flags);
cdt_node = kmem_cache_alloc(cdt_cache.cdt_root_cache, 0);
cdt_node->state = ALLOCATION_VALID;
spin_lock_init(&(cdt_node->lock));
cdt_node->node_count = 0;
spin_unlock_irqrestore(&cdt_cache.lock, flags);
return cdt_node;
}
void free_cdt_root(struct cdt_root_node *cdt_node) {
unsigned long flags;
spin_lock_irqsave(&cdt_cache.lock, flags);
cdt_node->state = ALLOCATION_REMOVED;
cdt_node->node_count = 0;
kmem_cache_free(cdt_cache.cdt_root_cache, cdt_node);
spin_unlock_irqrestore(&cdt_cache.lock, flags);
}
module_init(api_init); module_init(api_init);
module_exit(api_exit); module_exit(api_exit);
...@@ -36,6 +36,15 @@ bool begintests(void) { ...@@ -36,6 +36,15 @@ bool begintests(void) {
} else { } else {
printk(KERN_INFO "lcd_cap_test test_revoke() Succeeded\n"); printk(KERN_INFO "lcd_cap_test test_revoke() Succeeded\n");
} }
res = test_cspace_destroy();
if (res == TEST_FAILED) {
printk(KERN_ERR "lcd_cap_test test_cspace_destroy() failed\n");
return false;
} else {
printk(KERN_INFO "lcd_cap_test test_cspace_destroy() Succeeded\n");
}
return true; return true;
} }
...@@ -123,7 +132,7 @@ void test_delete(void) { ...@@ -123,7 +132,7 @@ void test_delete(void) {
test_cap_grant_count2 = 0; test_cap_grant_count2 = 0;
} }
bool test_revoke() { bool test_revoke(void) {
// this inherently tests delete functionality // this inherently tests delete functionality
int i = 0; int i = 0;
int res; int res;
...@@ -141,4 +150,18 @@ bool test_revoke() { ...@@ -141,4 +150,18 @@ bool test_revoke() {
test_cap_grant_count = 0; test_cap_grant_count = 0;
test_cap_grant_count2 = 0; test_cap_grant_count2 = 0;
return ret; return ret;
}
bool test_cspace_destroy(void) {
bool res = false;
int ret = -1;
res = test_insert();
if (res) {
printk(KERN_INFO "lcd_cap_test insert succeeded");
ret = lcd_cap_destroy_cspace(&test_cspace);
} else {
printk(KERN_ERR "lcd_cap_test insert failed");
}
return ret == 0;
} }
\ No newline at end of file
...@@ -4,9 +4,10 @@ extern int lcd_init_cspace(struct cspace *cspace); ...@@ -4,9 +4,10 @@ extern int lcd_init_cspace(struct cspace *cspace);
extern int lcd_cap_insert(struct cspace *cspace, capability_t cap, extern int lcd_cap_insert(struct cspace *cspace, capability_t cap,
void *object, enum lcd_cap_type type); void *object, enum lcd_cap_type type);
extern void lcd_cap_delete(struct cspace *cspace, capability_t cap); extern void lcd_cap_delete(struct cspace *cspace, capability_t cap);
extern int lcd_cap_destroy_cspace(struct cspace *cspace);
bool test_insert(void); bool test_insert(void);
bool test_grant(void); bool test_grant(void);
void test_delete(void); void test_delete(void);
bool test_revoke(void); bool test_revoke(void);
bool test_cspace_destroy(void);
bool begintests(void); bool begintests(void);
\ No newline at end of file
...@@ -22,9 +22,13 @@ ...@@ -22,9 +22,13 @@
// should always be 2^CAP_IDENTIFIER_BITS + 2^TABLE_IDENTIFIER_BITS // should always be 2^CAP_IDENTIFIER_BITS + 2^TABLE_IDENTIFIER_BITS
#define MAX_SLOTS_PER_TABLE 6 #define MAX_SLOTS_PER_TABLE 6
struct cdt_root_node;
struct cnode; struct cnode;
struct cspace; struct cspace;
extern struct cdt_root_node * get_cdt_root(void);
extern void free_cdt_root(struct cdt_root_node *cdt_node);
enum lcd_cap_type enum lcd_cap_type
{ {
LCD_CAP_TYPE_INVALID, LCD_CAP_TYPE_INVALID,
...@@ -59,7 +63,6 @@ struct cnode { ...@@ -59,7 +63,6 @@ struct cnode {
struct cnode_table { struct cnode_table {
struct cnode cnode[MAX_SLOTS_PER_TABLE]; struct cnode cnode[MAX_SLOTS_PER_TABLE];
uint8_t table_Id;
uint8_t table_level; uint8_t table_level;
}; };
...@@ -67,13 +70,13 @@ struct cspace { ...@@ -67,13 +70,13 @@ struct cspace {
spinlock_t lock; spinlock_t lock;
enum allocation_state state; enum allocation_state state;
struct cnode_table *cnode_table; struct cnode_table *cnode_table;
struct kmem_cache *cdt_root_cache;
struct kmem_cache *cnode_table_cache; struct kmem_cache *cnode_table_cache;
struct cap_cache cap_cache; struct cap_cache cap_cache;
}; };
bool _get_level_bits(int table_level, capability_t cap, capability_t *levelId); bool _get_level_bits(int table_level, capability_t cap, capability_t *levelId);
bool _lcd_delete_node (struct cnode *cnode); bool _lcd_delete_node (struct cnode *cnode);
int _lcd_delete_table(struct cspace *cspace, struct cnode_table *table);
int lcd_cap_init_cspace(struct cspace *cspace); int lcd_cap_init_cspace(struct cspace *cspace);
struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap, bool alloc); struct cnode *lcd_cnode_lookup(struct cspace *cspace, capability_t cap, bool alloc);
...@@ -82,4 +85,5 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap, ...@@ -82,4 +85,5 @@ int lcd_cap_insert(struct cspace *cspace, capability_t cap,
void lcd_cap_delete(struct cspace *cspace, capability_t cap); void lcd_cap_delete(struct cspace *cspace, capability_t cap);
int lcd_cap_grant(struct cspace *cspacesrc, capability_t capsrc, struct cspace *cspacedst, capability_t capdst); int lcd_cap_grant(struct cspace *cspacesrc, capability_t capsrc, struct cspace *cspacedst, capability_t capdst);
int lcd_cap_revoke(struct cspace *cspace, capability_t cap); int lcd_cap_revoke(struct cspace *cspace, capability_t cap);
int lcd_cap_destroy_cspace(struct cspace *cspace);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment