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;  | 
