diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 10 | ||||
-rw-r--r-- | lib/Kconfig.debug | 19 | ||||
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/debugobjects.c | 20 | ||||
-rw-r--r-- | lib/dynamic_debug.c | 2 | ||||
-rw-r--r-- | lib/earlycpio.c | 27 | ||||
-rw-r--r-- | lib/kobject.c | 22 | ||||
-rw-r--r-- | lib/lockref.c | 128 | ||||
-rw-r--r-- | lib/lz4/lz4_compress.c | 4 | ||||
-rw-r--r-- | lib/lz4/lz4_decompress.c | 6 | ||||
-rw-r--r-- | lib/lz4/lz4hc_compress.c | 4 |
11 files changed, 213 insertions, 30 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 71d9f81f6eed..65561716c16c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -48,6 +48,16 @@ config STMP_DEVICE | |||
48 | config PERCPU_RWSEM | 48 | config PERCPU_RWSEM |
49 | boolean | 49 | boolean |
50 | 50 | ||
51 | config ARCH_USE_CMPXCHG_LOCKREF | ||
52 | bool | ||
53 | |||
54 | config CMPXCHG_LOCKREF | ||
55 | def_bool y if ARCH_USE_CMPXCHG_LOCKREF | ||
56 | depends on SMP | ||
57 | depends on !GENERIC_LOCKBREAK | ||
58 | depends on !DEBUG_SPINLOCK | ||
59 | depends on !DEBUG_LOCK_ALLOC | ||
60 | |||
51 | config CRC_CCITT | 61 | config CRC_CCITT |
52 | tristate "CRC-CCITT functions" | 62 | tristate "CRC-CCITT functions" |
53 | help | 63 | help |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 1501aa553221..444e1c12fea9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -981,6 +981,25 @@ config DEBUG_KOBJECT | |||
981 | If you say Y here, some extra kobject debugging messages will be sent | 981 | If you say Y here, some extra kobject debugging messages will be sent |
982 | to the syslog. | 982 | to the syslog. |
983 | 983 | ||
984 | config DEBUG_KOBJECT_RELEASE | ||
985 | bool "kobject release debugging" | ||
986 | depends on DEBUG_KERNEL | ||
987 | help | ||
988 | kobjects are reference counted objects. This means that their | ||
989 | last reference count put is not predictable, and the kobject can | ||
990 | live on past the point at which a driver decides to drop it's | ||
991 | initial reference to the kobject gained on allocation. An | ||
992 | example of this would be a struct device which has just been | ||
993 | unregistered. | ||
994 | |||
995 | However, some buggy drivers assume that after such an operation, | ||
996 | the memory backing the kobject can be immediately freed. This | ||
997 | goes completely against the principles of a refcounted object. | ||
998 | |||
999 | If you say Y here, the kernel will delay the release of kobjects | ||
1000 | on the last reference count to improve the visibility of this | ||
1001 | kind of kobject release bug. | ||
1002 | |||
984 | config HAVE_DEBUG_BUGVERBOSE | 1003 | config HAVE_DEBUG_BUGVERBOSE |
985 | bool | 1004 | bool |
986 | 1005 | ||
diff --git a/lib/Makefile b/lib/Makefile index 7baccfd8a4e9..f2cb3082697c 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -20,6 +20,7 @@ lib-$(CONFIG_MMU) += ioremap.o | |||
20 | lib-$(CONFIG_SMP) += cpumask.o | 20 | lib-$(CONFIG_SMP) += cpumask.o |
21 | 21 | ||
22 | lib-y += kobject.o klist.o | 22 | lib-y += kobject.o klist.o |
23 | obj-y += lockref.o | ||
23 | 24 | ||
24 | obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ | 25 | obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ |
25 | bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ | 26 | bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ |
diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 37061ede8b81..bf2c8b1043d8 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c | |||
@@ -381,19 +381,21 @@ void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) | |||
381 | * debug_object_activate - debug checks when an object is activated | 381 | * debug_object_activate - debug checks when an object is activated |
382 | * @addr: address of the object | 382 | * @addr: address of the object |
383 | * @descr: pointer to an object specific debug description structure | 383 | * @descr: pointer to an object specific debug description structure |
384 | * Returns 0 for success, -EINVAL for check failed. | ||
384 | */ | 385 | */ |
385 | void debug_object_activate(void *addr, struct debug_obj_descr *descr) | 386 | int debug_object_activate(void *addr, struct debug_obj_descr *descr) |
386 | { | 387 | { |
387 | enum debug_obj_state state; | 388 | enum debug_obj_state state; |
388 | struct debug_bucket *db; | 389 | struct debug_bucket *db; |
389 | struct debug_obj *obj; | 390 | struct debug_obj *obj; |
390 | unsigned long flags; | 391 | unsigned long flags; |
392 | int ret; | ||
391 | struct debug_obj o = { .object = addr, | 393 | struct debug_obj o = { .object = addr, |
392 | .state = ODEBUG_STATE_NOTAVAILABLE, | 394 | .state = ODEBUG_STATE_NOTAVAILABLE, |
393 | .descr = descr }; | 395 | .descr = descr }; |
394 | 396 | ||
395 | if (!debug_objects_enabled) | 397 | if (!debug_objects_enabled) |
396 | return; | 398 | return 0; |
397 | 399 | ||
398 | db = get_bucket((unsigned long) addr); | 400 | db = get_bucket((unsigned long) addr); |
399 | 401 | ||
@@ -405,23 +407,26 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr) | |||
405 | case ODEBUG_STATE_INIT: | 407 | case ODEBUG_STATE_INIT: |
406 | case ODEBUG_STATE_INACTIVE: | 408 | case ODEBUG_STATE_INACTIVE: |
407 | obj->state = ODEBUG_STATE_ACTIVE; | 409 | obj->state = ODEBUG_STATE_ACTIVE; |
410 | ret = 0; | ||
408 | break; | 411 | break; |
409 | 412 | ||
410 | case ODEBUG_STATE_ACTIVE: | 413 | case ODEBUG_STATE_ACTIVE: |
411 | debug_print_object(obj, "activate"); | 414 | debug_print_object(obj, "activate"); |
412 | state = obj->state; | 415 | state = obj->state; |
413 | raw_spin_unlock_irqrestore(&db->lock, flags); | 416 | raw_spin_unlock_irqrestore(&db->lock, flags); |
414 | debug_object_fixup(descr->fixup_activate, addr, state); | 417 | ret = debug_object_fixup(descr->fixup_activate, addr, state); |
415 | return; | 418 | return ret ? -EINVAL : 0; |
416 | 419 | ||
417 | case ODEBUG_STATE_DESTROYED: | 420 | case ODEBUG_STATE_DESTROYED: |
418 | debug_print_object(obj, "activate"); | 421 | debug_print_object(obj, "activate"); |
422 | ret = -EINVAL; | ||
419 | break; | 423 | break; |
420 | default: | 424 | default: |
425 | ret = 0; | ||
421 | break; | 426 | break; |
422 | } | 427 | } |
423 | raw_spin_unlock_irqrestore(&db->lock, flags); | 428 | raw_spin_unlock_irqrestore(&db->lock, flags); |
424 | return; | 429 | return ret; |
425 | } | 430 | } |
426 | 431 | ||
427 | raw_spin_unlock_irqrestore(&db->lock, flags); | 432 | raw_spin_unlock_irqrestore(&db->lock, flags); |
@@ -431,8 +436,11 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr) | |||
431 | * true or not. | 436 | * true or not. |
432 | */ | 437 | */ |
433 | if (debug_object_fixup(descr->fixup_activate, addr, | 438 | if (debug_object_fixup(descr->fixup_activate, addr, |
434 | ODEBUG_STATE_NOTAVAILABLE)) | 439 | ODEBUG_STATE_NOTAVAILABLE)) { |
435 | debug_print_object(&o, "activate"); | 440 | debug_print_object(&o, "activate"); |
441 | return -EINVAL; | ||
442 | } | ||
443 | return 0; | ||
436 | } | 444 | } |
437 | 445 | ||
438 | /** | 446 | /** |
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c index 99fec3ae405a..c37aeacd7651 100644 --- a/lib/dynamic_debug.c +++ b/lib/dynamic_debug.c | |||
@@ -309,7 +309,7 @@ static int ddebug_parse_query(char *words[], int nwords, | |||
309 | struct ddebug_query *query, const char *modname) | 309 | struct ddebug_query *query, const char *modname) |
310 | { | 310 | { |
311 | unsigned int i; | 311 | unsigned int i; |
312 | int rc; | 312 | int rc = 0; |
313 | 313 | ||
314 | /* check we have an even number of words */ | 314 | /* check we have an even number of words */ |
315 | if (nwords % 2 != 0) { | 315 | if (nwords % 2 != 0) { |
diff --git a/lib/earlycpio.c b/lib/earlycpio.c index 7aa7ce250c94..3eb3e4722b8e 100644 --- a/lib/earlycpio.c +++ b/lib/earlycpio.c | |||
@@ -49,22 +49,23 @@ enum cpio_fields { | |||
49 | 49 | ||
50 | /** | 50 | /** |
51 | * cpio_data find_cpio_data - Search for files in an uncompressed cpio | 51 | * cpio_data find_cpio_data - Search for files in an uncompressed cpio |
52 | * @path: The directory to search for, including a slash at the end | 52 | * @path: The directory to search for, including a slash at the end |
53 | * @data: Pointer to the the cpio archive or a header inside | 53 | * @data: Pointer to the the cpio archive or a header inside |
54 | * @len: Remaining length of the cpio based on data pointer | 54 | * @len: Remaining length of the cpio based on data pointer |
55 | * @offset: When a matching file is found, this is the offset to the | 55 | * @nextoff: When a matching file is found, this is the offset from the |
56 | * beginning of the cpio. It can be used to iterate through | 56 | * beginning of the cpio to the beginning of the next file, not the |
57 | * the cpio to find all files inside of a directory path | 57 | * matching file itself. It can be used to iterate through the cpio |
58 | * to find all files inside of a directory path. | ||
58 | * | 59 | * |
59 | * @return: struct cpio_data containing the address, length and | 60 | * @return: struct cpio_data containing the address, length and |
60 | * filename (with the directory path cut off) of the found file. | 61 | * filename (with the directory path cut off) of the found file. |
61 | * If you search for a filename and not for files in a directory, | 62 | * If you search for a filename and not for files in a directory, |
62 | * pass the absolute path of the filename in the cpio and make sure | 63 | * pass the absolute path of the filename in the cpio and make sure |
63 | * the match returned an empty filename string. | 64 | * the match returned an empty filename string. |
64 | */ | 65 | */ |
65 | 66 | ||
66 | struct cpio_data find_cpio_data(const char *path, void *data, | 67 | struct cpio_data find_cpio_data(const char *path, void *data, |
67 | size_t len, long *offset) | 68 | size_t len, long *nextoff) |
68 | { | 69 | { |
69 | const size_t cpio_header_len = 8*C_NFIELDS - 2; | 70 | const size_t cpio_header_len = 8*C_NFIELDS - 2; |
70 | struct cpio_data cd = { NULL, 0, "" }; | 71 | struct cpio_data cd = { NULL, 0, "" }; |
@@ -124,7 +125,7 @@ struct cpio_data find_cpio_data(const char *path, void *data, | |||
124 | if ((ch[C_MODE] & 0170000) == 0100000 && | 125 | if ((ch[C_MODE] & 0170000) == 0100000 && |
125 | ch[C_NAMESIZE] >= mypathsize && | 126 | ch[C_NAMESIZE] >= mypathsize && |
126 | !memcmp(p, path, mypathsize)) { | 127 | !memcmp(p, path, mypathsize)) { |
127 | *offset = (long)nptr - (long)data; | 128 | *nextoff = (long)nptr - (long)data; |
128 | if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { | 129 | if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { |
129 | pr_warn( | 130 | pr_warn( |
130 | "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", | 131 | "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", |
diff --git a/lib/kobject.c b/lib/kobject.c index 4a1f33d43548..1d46c151a4ae 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -545,8 +545,8 @@ static void kobject_cleanup(struct kobject *kobj) | |||
545 | struct kobj_type *t = get_ktype(kobj); | 545 | struct kobj_type *t = get_ktype(kobj); |
546 | const char *name = kobj->name; | 546 | const char *name = kobj->name; |
547 | 547 | ||
548 | pr_debug("kobject: '%s' (%p): %s\n", | 548 | pr_debug("kobject: '%s' (%p): %s, parent %p\n", |
549 | kobject_name(kobj), kobj, __func__); | 549 | kobject_name(kobj), kobj, __func__, kobj->parent); |
550 | 550 | ||
551 | if (t && !t->release) | 551 | if (t && !t->release) |
552 | pr_debug("kobject: '%s' (%p): does not have a release() " | 552 | pr_debug("kobject: '%s' (%p): does not have a release() " |
@@ -580,9 +580,25 @@ static void kobject_cleanup(struct kobject *kobj) | |||
580 | } | 580 | } |
581 | } | 581 | } |
582 | 582 | ||
583 | #ifdef CONFIG_DEBUG_KOBJECT_RELEASE | ||
584 | static void kobject_delayed_cleanup(struct work_struct *work) | ||
585 | { | ||
586 | kobject_cleanup(container_of(to_delayed_work(work), | ||
587 | struct kobject, release)); | ||
588 | } | ||
589 | #endif | ||
590 | |||
583 | static void kobject_release(struct kref *kref) | 591 | static void kobject_release(struct kref *kref) |
584 | { | 592 | { |
585 | kobject_cleanup(container_of(kref, struct kobject, kref)); | 593 | struct kobject *kobj = container_of(kref, struct kobject, kref); |
594 | #ifdef CONFIG_DEBUG_KOBJECT_RELEASE | ||
595 | pr_debug("kobject: '%s' (%p): %s, parent %p (delayed)\n", | ||
596 | kobject_name(kobj), kobj, __func__, kobj->parent); | ||
597 | INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup); | ||
598 | schedule_delayed_work(&kobj->release, HZ); | ||
599 | #else | ||
600 | kobject_cleanup(kobj); | ||
601 | #endif | ||
586 | } | 602 | } |
587 | 603 | ||
588 | /** | 604 | /** |
diff --git a/lib/lockref.c b/lib/lockref.c new file mode 100644 index 000000000000..9d76f404ce9a --- /dev/null +++ b/lib/lockref.c | |||
@@ -0,0 +1,128 @@ | |||
1 | #include <linux/export.h> | ||
2 | #include <linux/lockref.h> | ||
3 | |||
4 | #ifdef CONFIG_CMPXCHG_LOCKREF | ||
5 | |||
6 | /* | ||
7 | * Note that the "cmpxchg()" reloads the "old" value for the | ||
8 | * failure case. | ||
9 | */ | ||
10 | #define CMPXCHG_LOOP(CODE, SUCCESS) do { \ | ||
11 | struct lockref old; \ | ||
12 | BUILD_BUG_ON(sizeof(old) != 8); \ | ||
13 | old.lock_count = ACCESS_ONCE(lockref->lock_count); \ | ||
14 | while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) { \ | ||
15 | struct lockref new = old, prev = old; \ | ||
16 | CODE \ | ||
17 | old.lock_count = cmpxchg(&lockref->lock_count, \ | ||
18 | old.lock_count, new.lock_count); \ | ||
19 | if (likely(old.lock_count == prev.lock_count)) { \ | ||
20 | SUCCESS; \ | ||
21 | } \ | ||
22 | cpu_relax(); \ | ||
23 | } \ | ||
24 | } while (0) | ||
25 | |||
26 | #else | ||
27 | |||
28 | #define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0) | ||
29 | |||
30 | #endif | ||
31 | |||
32 | /** | ||
33 | * lockref_get - Increments reference count unconditionally | ||
34 | * @lockcnt: pointer to lockref structure | ||
35 | * | ||
36 | * This operation is only valid if you already hold a reference | ||
37 | * to the object, so you know the count cannot be zero. | ||
38 | */ | ||
39 | void lockref_get(struct lockref *lockref) | ||
40 | { | ||
41 | CMPXCHG_LOOP( | ||
42 | new.count++; | ||
43 | , | ||
44 | return; | ||
45 | ); | ||
46 | |||
47 | spin_lock(&lockref->lock); | ||
48 | lockref->count++; | ||
49 | spin_unlock(&lockref->lock); | ||
50 | } | ||
51 | EXPORT_SYMBOL(lockref_get); | ||
52 | |||
53 | /** | ||
54 | * lockref_get_not_zero - Increments count unless the count is 0 | ||
55 | * @lockcnt: pointer to lockref structure | ||
56 | * Return: 1 if count updated successfully or 0 if count was zero | ||
57 | */ | ||
58 | int lockref_get_not_zero(struct lockref *lockref) | ||
59 | { | ||
60 | int retval; | ||
61 | |||
62 | CMPXCHG_LOOP( | ||
63 | new.count++; | ||
64 | if (!old.count) | ||
65 | return 0; | ||
66 | , | ||
67 | return 1; | ||
68 | ); | ||
69 | |||
70 | spin_lock(&lockref->lock); | ||
71 | retval = 0; | ||
72 | if (lockref->count) { | ||
73 | lockref->count++; | ||
74 | retval = 1; | ||
75 | } | ||
76 | spin_unlock(&lockref->lock); | ||
77 | return retval; | ||
78 | } | ||
79 | EXPORT_SYMBOL(lockref_get_not_zero); | ||
80 | |||
81 | /** | ||
82 | * lockref_get_or_lock - Increments count unless the count is 0 | ||
83 | * @lockcnt: pointer to lockref structure | ||
84 | * Return: 1 if count updated successfully or 0 if count was zero | ||
85 | * and we got the lock instead. | ||
86 | */ | ||
87 | int lockref_get_or_lock(struct lockref *lockref) | ||
88 | { | ||
89 | CMPXCHG_LOOP( | ||
90 | new.count++; | ||
91 | if (!old.count) | ||
92 | break; | ||
93 | , | ||
94 | return 1; | ||
95 | ); | ||
96 | |||
97 | spin_lock(&lockref->lock); | ||
98 | if (!lockref->count) | ||
99 | return 0; | ||
100 | lockref->count++; | ||
101 | spin_unlock(&lockref->lock); | ||
102 | return 1; | ||
103 | } | ||
104 | EXPORT_SYMBOL(lockref_get_or_lock); | ||
105 | |||
106 | /** | ||
107 | * lockref_put_or_lock - decrements count unless count <= 1 before decrement | ||
108 | * @lockcnt: pointer to lockref structure | ||
109 | * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken | ||
110 | */ | ||
111 | int lockref_put_or_lock(struct lockref *lockref) | ||
112 | { | ||
113 | CMPXCHG_LOOP( | ||
114 | new.count--; | ||
115 | if (old.count <= 1) | ||
116 | break; | ||
117 | , | ||
118 | return 1; | ||
119 | ); | ||
120 | |||
121 | spin_lock(&lockref->lock); | ||
122 | if (lockref->count <= 1) | ||
123 | return 0; | ||
124 | lockref->count--; | ||
125 | spin_unlock(&lockref->lock); | ||
126 | return 1; | ||
127 | } | ||
128 | EXPORT_SYMBOL(lockref_put_or_lock); | ||
diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c index fd94058bd7f9..28321d8f75ef 100644 --- a/lib/lz4/lz4_compress.c +++ b/lib/lz4/lz4_compress.c | |||
@@ -437,7 +437,7 @@ int lz4_compress(const unsigned char *src, size_t src_len, | |||
437 | exit: | 437 | exit: |
438 | return ret; | 438 | return ret; |
439 | } | 439 | } |
440 | EXPORT_SYMBOL_GPL(lz4_compress); | 440 | EXPORT_SYMBOL(lz4_compress); |
441 | 441 | ||
442 | MODULE_LICENSE("GPL"); | 442 | MODULE_LICENSE("Dual BSD/GPL"); |
443 | MODULE_DESCRIPTION("LZ4 compressor"); | 443 | MODULE_DESCRIPTION("LZ4 compressor"); |
diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c index d3414eae73a1..411be80ddb46 100644 --- a/lib/lz4/lz4_decompress.c +++ b/lib/lz4/lz4_decompress.c | |||
@@ -299,7 +299,7 @@ exit_0: | |||
299 | return ret; | 299 | return ret; |
300 | } | 300 | } |
301 | #ifndef STATIC | 301 | #ifndef STATIC |
302 | EXPORT_SYMBOL_GPL(lz4_decompress); | 302 | EXPORT_SYMBOL(lz4_decompress); |
303 | #endif | 303 | #endif |
304 | 304 | ||
305 | int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, | 305 | int lz4_decompress_unknownoutputsize(const char *src, size_t src_len, |
@@ -319,8 +319,8 @@ exit_0: | |||
319 | return ret; | 319 | return ret; |
320 | } | 320 | } |
321 | #ifndef STATIC | 321 | #ifndef STATIC |
322 | EXPORT_SYMBOL_GPL(lz4_decompress_unknownoutputsize); | 322 | EXPORT_SYMBOL(lz4_decompress_unknownoutputsize); |
323 | 323 | ||
324 | MODULE_LICENSE("GPL"); | 324 | MODULE_LICENSE("Dual BSD/GPL"); |
325 | MODULE_DESCRIPTION("LZ4 Decompressor"); | 325 | MODULE_DESCRIPTION("LZ4 Decompressor"); |
326 | #endif | 326 | #endif |
diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c index eb1a74f5e368..f344f76b6559 100644 --- a/lib/lz4/lz4hc_compress.c +++ b/lib/lz4/lz4hc_compress.c | |||
@@ -533,7 +533,7 @@ int lz4hc_compress(const unsigned char *src, size_t src_len, | |||
533 | exit: | 533 | exit: |
534 | return ret; | 534 | return ret; |
535 | } | 535 | } |
536 | EXPORT_SYMBOL_GPL(lz4hc_compress); | 536 | EXPORT_SYMBOL(lz4hc_compress); |
537 | 537 | ||
538 | MODULE_LICENSE("GPL"); | 538 | MODULE_LICENSE("Dual BSD/GPL"); |
539 | MODULE_DESCRIPTION("LZ4HC compressor"); | 539 | MODULE_DESCRIPTION("LZ4HC compressor"); |