diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/bust_spinlocks.c | 3 | ||||
| -rw-r--r-- | lib/dma-debug.c | 45 | ||||
| -rw-r--r-- | lib/kobject.c | 9 | 
3 files changed, 40 insertions, 17 deletions
diff --git a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c index 9681d54b95d..f8e0e536739 100644 --- a/lib/bust_spinlocks.c +++ b/lib/bust_spinlocks.c @@ -8,6 +8,7 @@   */  #include <linux/kernel.h> +#include <linux/printk.h>  #include <linux/spinlock.h>  #include <linux/tty.h>  #include <linux/wait.h> @@ -28,5 +29,3 @@ void __attribute__((weak)) bust_spinlocks(int yes)  			wake_up_klogd();  	}  } - - diff --git a/lib/dma-debug.c b/lib/dma-debug.c index 5e396accd3d..d87a17a819d 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -862,17 +862,21 @@ static void check_unmap(struct dma_debug_entry *ref)  	entry = bucket_find_exact(bucket, ref);  	if (!entry) { +		/* must drop lock before calling dma_mapping_error */ +		put_hash_bucket(bucket, &flags); +  		if (dma_mapping_error(ref->dev, ref->dev_addr)) {  			err_printk(ref->dev, NULL, -				   "DMA-API: device driver tries " -				   "to free an invalid DMA memory address\n"); -			return; +				   "DMA-API: device driver tries to free an " +				   "invalid DMA memory address\n"); +		} else { +			err_printk(ref->dev, NULL, +				   "DMA-API: device driver tries to free DMA " +				   "memory it has not allocated [device " +				   "address=0x%016llx] [size=%llu bytes]\n", +				   ref->dev_addr, ref->size);  		} -		err_printk(ref->dev, NULL, "DMA-API: device driver tries " -			   "to free DMA memory it has not allocated " -			   "[device address=0x%016llx] [size=%llu bytes]\n", -			   ref->dev_addr, ref->size); -		goto out; +		return;  	}  	if (ref->size != entry->size) { @@ -936,7 +940,6 @@ static void check_unmap(struct dma_debug_entry *ref)  	hash_bucket_del(entry);  	dma_entry_free(entry); -out:  	put_hash_bucket(bucket, &flags);  } @@ -1082,13 +1085,27 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)  	ref.dev = dev;  	ref.dev_addr = dma_addr;  	bucket = get_hash_bucket(&ref, &flags); -	entry = bucket_find_exact(bucket, &ref); -	if (!entry) -		goto out; +	list_for_each_entry(entry, &bucket->list, list) { +		if (!exact_match(&ref, entry)) +			continue; + +		/* +		 * The same physical address can be mapped multiple +		 * times. Without a hardware IOMMU this results in the +		 * same device addresses being put into the dma-debug +		 * hash multiple times too. This can result in false +		 * positives being reported. Therefore we implement a +		 * best-fit algorithm here which updates the first entry +		 * from the hash which fits the reference value and is +		 * not currently listed as being checked. +		 */ +		if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { +			entry->map_err_type = MAP_ERR_CHECKED; +			break; +		} +	} -	entry->map_err_type = MAP_ERR_CHECKED; -out:  	put_hash_bucket(bucket, &flags);  }  EXPORT_SYMBOL(debug_dma_mapping_error); diff --git a/lib/kobject.c b/lib/kobject.c index e07ee1fcd6f..a65486613d7 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -529,6 +529,13 @@ struct kobject *kobject_get(struct kobject *kobj)  	return kobj;  } +static struct kobject *kobject_get_unless_zero(struct kobject *kobj) +{ +	if (!kref_get_unless_zero(&kobj->kref)) +		kobj = NULL; +	return kobj; +} +  /*   * kobject_cleanup - free kobject resources.   * @kobj: object to cleanup @@ -751,7 +758,7 @@ struct kobject *kset_find_obj(struct kset *kset, const char *name)  	list_for_each_entry(k, &kset->list, entry) {  		if (kobject_name(k) && !strcmp(kobject_name(k), name)) { -			ret = kobject_get(k); +			ret = kobject_get_unless_zero(k);  			break;  		}  	}  |