diff options
author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-07-17 22:47:51 +0200 |
---|---|---|
committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-07-17 22:47:51 +0200 |
commit | ad4a1e15877aff3da889c0c433475d3173a677e4 (patch) | |
tree | 541d61b531e71662f7c91d9b56393b80bd80ae47 /driver | |
parent | 2c52de4f914806c040f62d9fc3ee88081a7aa56b (diff) | |
download | ipecamera-ad4a1e15877aff3da889c0c433475d3173a677e4.tar.gz ipecamera-ad4a1e15877aff3da889c0c433475d3173a677e4.tar.bz2 ipecamera-ad4a1e15877aff3da889c0c433475d3173a677e4.tar.xz ipecamera-ad4a1e15877aff3da889c0c433475d3173a677e4.zip |
Support forceful clean-up of kernel memory
Diffstat (limited to 'driver')
-rw-r--r-- | driver/kmem.c | 96 | ||||
-rw-r--r-- | driver/pciDriver.h | 3 |
2 files changed, 67 insertions, 32 deletions
diff --git a/driver/kmem.c b/driver/kmem.c index 90ae5ba..31fc685 100644 --- a/driver/kmem.c +++ b/driver/kmem.c @@ -152,56 +152,90 @@ kmem_alloc_entry_fail: return -ENOMEM; } -/** - * - * Called via sysfs, frees kernel memory and the corresponding management structure - * - */ -int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle ) -{ - pcidriver_kmem_entry_t *kmem_entry; - - /* Find the associated kmem_entry for this buffer */ - if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL) - return -EINVAL; /* kmem_handle is not valid */ - -// if (kmem_entry->id == 0) -// mod_info("1: %i %x %lx %lx\n", kmem_entry->id, kmem_handle->flags, kmem_entry->refs, kmem_entry->mode); - - if (kmem_entry->mode&KMEM_MODE_COUNT) +static int pcidriver_kmem_free_check(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle, pcidriver_kmem_entry_t *kmem_entry) { + if ((kmem_handle->flags & KMEM_FLAG_FORCE) == 0) { + if (kmem_entry->mode&KMEM_MODE_COUNT) kmem_entry->mode -= 1; - if (kmem_handle->flags&KMEM_FLAG_HW) + if (kmem_handle->flags&KMEM_FLAG_HW) kmem_entry->refs &= ~KMEM_REF_HW; - if (kmem_handle->flags&KMEM_FLAG_PERSISTENT) + if (kmem_handle->flags&KMEM_FLAG_PERSISTENT) kmem_entry->mode &= ~KMEM_MODE_PERSISTENT; - -// if (kmem_entry->id == 0) -// mod_info("2: %i %x %lx %lx\n", kmem_entry->id, kmem_handle->flags, kmem_entry->refs, kmem_entry->mode); - if (kmem_handle->flags&KMEM_FLAG_REUSE) + if (kmem_handle->flags&KMEM_FLAG_REUSE) return 0; - if (kmem_entry->refs) { + if (kmem_entry->refs) { mod_info("can't free referenced kmem_entry\n"); kmem_entry->mode += 1; return -EBUSY; - } + } - if (kmem_entry->mode & KMEM_MODE_PERSISTENT) { + if (kmem_entry->mode & KMEM_MODE_PERSISTENT) { mod_info("can't free persistent kmem_entry\n"); return -EBUSY; - } + } - if (((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)==0)&&(kmem_entry->mode&KMEM_MODE_COUNT)) + if (((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)==0)&&(kmem_entry->mode&KMEM_MODE_COUNT)&&((kmem_handle->flags&KMEM_FLAG_EXCLUSIVE)==0)) return 0; + } + return 1; +} + +static int pcidriver_kmem_free_use(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle) +{ + int err; + int failed = 0; + struct list_head *ptr, *next; + pcidriver_kmem_entry_t *kmem_entry; + + /* iterate safely over the entries and delete them */ + list_for_each_safe(ptr, next, &(privdata->kmem_list)) { + kmem_entry = list_entry(ptr, pcidriver_kmem_entry_t, list); + if (kmem_entry->use == kmem_handle->use) { + err = pcidriver_kmem_free_check(privdata, kmem_handle, kmem_entry); + if (err > 0) + pcidriver_kmem_free_entry(privdata, kmem_entry); /* spin lock inside! */ + else + failed = 1; + } + } + + if (failed) { + mod_info("Some kmem_entries for use %lx are still referenced\n", kmem_handle->use); + return -EBUSY; + } + + return 0; +} + +/** + * + * Called via sysfs, frees kernel memory and the corresponding management structure + * + */ +int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle ) +{ + int err; + pcidriver_kmem_entry_t *kmem_entry; + + if (kmem_handle->flags&KMEM_FLAG_MASS) { + kmem_handle->flags &= ~KMEM_FLAG_MASS; + return pcidriver_kmem_free_use(privdata, kmem_handle); + } + + /* Find the associated kmem_entry for this buffer */ + if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL) + return -EINVAL; /* kmem_handle is not valid */ + + err = pcidriver_kmem_free_check(privdata, kmem_handle, kmem_entry); -// if (kmem_entry->id == 0) -// mod_info("cleaned %i\n", kmem_entry->id); + if (err > 0) + return pcidriver_kmem_free_entry(privdata, kmem_entry); - return pcidriver_kmem_free_entry(privdata, kmem_entry); + return err; } /** diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 9aa580f..fc92b11 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -104,13 +104,14 @@ #define KMEM_FLAG_EXCLUSIVE 2 /**< Allow only a single application accessing a specified use & item */ #define KMEM_FLAG_PERSISTENT 4 /**< Sets persistent mode */ #define KMEM_FLAG_HW 8 /**< The buffer may be accessed by hardware, the hardware access will not occur any more if passed to _free function */ +#define KMEM_FLAG_FORCE 16 /**< Force memory cleanup even if references are present */ +#define KMEM_FLAG_MASS 32 /**< Apply to all buffers of selected use */ #define KMEM_FLAG_REUSED 1 /**< Indicates if buffer with specified use & item was already allocated and reused */ #define KMEM_FLAG_REUSED_PERSISTENT 4 /**< Indicates that reused buffer was persistent before the call */ #define KMEM_FLAG_REUSED_HW 8 /**< Indicates that reused buffer had a HW reference before the call */ - /* Types */ typedef struct { unsigned long type; |