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 Thu, 2009-07-02 at 18:12 +0800, Thomas Renninger wrote:
> 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 was considering maybe some strange BIOS defines a region in a method
with the same address and length of the global region, as below

OperationRegion (reg1, SystemMemory, 0xFED11000, 0xFF)

Method(m000)
{
    OperationRegion (xxxx, SystemMemory, 0xFED11000, 0xFF)
    ....
}

Although, this is a really seldom case, 
but with the counting it would be more safe.

Lin Ming

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