summaryrefslogtreecommitdiffstats
path: root/driver/kmem.c
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-17 22:47:51 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-17 22:47:51 +0200
commitad4a1e15877aff3da889c0c433475d3173a677e4 (patch)
tree541d61b531e71662f7c91d9b56393b80bd80ae47 /driver/kmem.c
parent2c52de4f914806c040f62d9fc3ee88081a7aa56b (diff)
downloadipecamera-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/kmem.c')
-rw-r--r--driver/kmem.c96
1 files changed, 65 insertions, 31 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;
}
/**