Re: [PATCH] ACPICA: Revert "ACPICA: Remove obsolete acpi_os_validate_address interface"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thursday 02 July 2009 08:27:25 Lin Ming wrote:
> On Thu, 2009-07-02 at 10:03 +0800, Len Brown wrote: 
> > I can't apply a patch that adds a known memory leak,
> > even if it removes a conflict between drivers.
> > 
> > The reason is that there is a workaround for the driver conflict,
> > but no workaround for the memory leak.
> 
> Here is a prototype simple patch, please review to see if it is the
> right way to go.
> 
> 1) add a new field "count" to struct acpi_res_list.
> 
>    When inserting, if the region(addr, len) is already in the resource 
>    list, we just increase "count", otherwise, the region is inserted 
>    with count=1.
> 
>    When deleting, the "count" is decreased, if it's decreased to 0,
>    the region is deleted from the resource list.
> 
>    With "count", the region with same address and length can only be 
>    inserted to the resource list once, so prevent potential memory leak.
Is the counting really needed?
An OpRegion inside a method should get deleted when the function is exited
and acpi_os_invalidate_address will get called.

I like it. Thanks for looking into that!

   Thomas
> 
> 2) add a new function acpi_os_invalidate_address, which is called when 
>    region is deleted. 
> 
> 
> diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
> index bc17103..96e26e7 100644
> --- a/drivers/acpi/acpica/utdelete.c
> +++ b/drivers/acpi/acpica/utdelete.c
> @@ -215,6 +215,12 @@ static void acpi_ut_delete_internal_obj(union 
acpi_operand_object *object)
>  		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
>  				  "***** Region %p\n", object));
>  
> +		/* Invalidate the region address/length via the host OS */
> +
> +		acpi_os_invalidate_address(object->region.space_id,
> +					  object->region.address,
> +					  (acpi_size) object->region.length);
> +
>  		second_desc = acpi_ns_get_secondary_object(object);
>  		if (second_desc) {
>  			/*
> diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
> index 7167071..620a65a 100644
> --- a/drivers/acpi/osl.c
> +++ b/drivers/acpi/osl.c
> @@ -88,6 +88,7 @@ struct acpi_res_list {
>  	char name[5];   /* only can have a length of 4 chars, make use of this
>  			   one instead of res->name, no need to kalloc then */
>  	struct list_head resource_list;
> +	int count;
>  };
>  
>  static LIST_HEAD(resource_list_head);
> @@ -1333,6 +1334,88 @@ acpi_os_validate_interface (char *interface)
>  	return AE_SUPPORT;
>  }
>  
> +static inline int acpi_res_list_add(struct acpi_res_list *res)
> +{
> +	struct acpi_res_list *res_list_elem;
> +
> +	list_for_each_entry(res_list_elem, &resource_list_head,
> +			    resource_list) {
> +
> +		if (res->resource_type == res_list_elem->resource_type &&
> +		    res->start == res_list_elem->start &&
> +		    res->end == res_list_elem->end) {
> +
> +			/*
> +			 * The Region(addr,len) already exist in the list,
> +			 * just increase the count
> +			 */
> +
> +			res_list_elem->count++;
> +			return 0;
> +		}
> +	}
> +
> +	res->count = 1;
> +	list_add(&res->resource_list, &resource_list_head);
> +	return 1;
> +}
> +
> +static inline void acpi_res_list_del(struct acpi_res_list *res)
> +{
> +	struct acpi_res_list *res_list_elem;
> +
> +	list_for_each_entry(res_list_elem, &resource_list_head,
> +			    resource_list) {
> +
> +		if (res->resource_type == res_list_elem->resource_type &&
> +		    res->start == res_list_elem->start &&
> +		    res->end == res_list_elem->end) {
> +
> +			/*
> +			 * If the res count is decreased to 0, remove and free it
> +			 */
> +
> +			if (--res_list_elem->count == 0) {
> +				list_del(&res_list_elem->resource_list);
> +				kfree(res_list_elem);
> +			}
> +			return;
> +		}
> +	}
> +}
> +
> +acpi_status
> +acpi_os_invalidate_address(
> +    u8                   space_id,
> +    acpi_physical_address   address,
> +    acpi_size               length)
> +{
> +	struct acpi_res_list res;
> +
> +	switch (space_id) {
> +	case ACPI_ADR_SPACE_SYSTEM_IO:
> +	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
> +		/* Only interference checks against SystemIO and SytemMemory
> +		   are needed */
> +		res.start = address;
> +		res.end = address + length - 1;
> +		res.resource_type = space_id;
> +		spin_lock(&acpi_res_lock);
> +		acpi_res_list_del(&res);
> +		spin_unlock(&acpi_res_lock);
> +		break;
> +	case ACPI_ADR_SPACE_PCI_CONFIG:
> +	case ACPI_ADR_SPACE_EC:
> +	case ACPI_ADR_SPACE_SMBUS:
> +	case ACPI_ADR_SPACE_CMOS:
> +	case ACPI_ADR_SPACE_PCI_BAR_TARGET:
> +	case ACPI_ADR_SPACE_DATA_TABLE:
> +	case ACPI_ADR_SPACE_FIXED_HARDWARE:
> +		break;
> +	}
> +	return AE_OK;
> +}
> +
>  
/******************************************************************************
>   *
>   * FUNCTION:    acpi_os_validate_address
> @@ -1357,6 +1440,7 @@ acpi_os_validate_address (
>      char *name)
>  {
>  	struct acpi_res_list *res;
> +	int added;
>  	if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
>  		return AE_OK;
>  
> @@ -1374,14 +1458,17 @@ acpi_os_validate_address (
>  		res->end = address + length - 1;
>  		res->resource_type = space_id;
>  		spin_lock(&acpi_res_lock);
> -		list_add(&res->resource_list, &resource_list_head);
> +		added = acpi_res_list_add(res);
>  		spin_unlock(&acpi_res_lock);
> -		pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
> -			 "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
> +		pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, "
> +			 "name: %s\n", added ? "Added" : "Already exist",
> +			 (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
>  			 ? "SystemIO" : "System Memory",
>  			 (unsigned long long)res->start,
>  			 (unsigned long long)res->end,
>  			 res->name);
> +		if (!added)
> +			kfree(res);
>  		break;
>  	case ACPI_ADR_SPACE_PCI_CONFIG:
>  	case ACPI_ADR_SPACE_EC:
> diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
> index ab0b85c..14d40bf 100644
> --- a/include/acpi/acpiosxf.h
> +++ b/include/acpi/acpiosxf.h
> @@ -246,6 +246,10 @@ acpi_status
>  acpi_os_validate_address(u8 space_id, acpi_physical_address address,
>  			 acpi_size length, char *name);
>  
> +acpi_status
> +acpi_os_invalidate_address(u8 space_id, acpi_physical_address address,
> +			 acpi_size length);
> +
>  u64 acpi_os_get_timer(void);
>  
>  acpi_status acpi_os_signal(u32 function, void *info);
> 
> 
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux