diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 3 | ||||
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/debugobjects.c | 54 | ||||
-rw-r--r-- | lib/dynamic_queue_limits.c | 133 | ||||
-rw-r--r-- | lib/reciprocal_div.c | 2 | ||||
-rw-r--r-- | lib/vsprintf.c | 19 |
6 files changed, 209 insertions, 4 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 32f3e5ae2be5..63b5782732ed 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -244,6 +244,9 @@ config CPU_RMAP | |||
244 | bool | 244 | bool |
245 | depends on SMP | 245 | depends on SMP |
246 | 246 | ||
247 | config DQL | ||
248 | bool | ||
249 | |||
247 | # | 250 | # |
248 | # Netlink attribute parsing support is select'ed if needed | 251 | # Netlink attribute parsing support is select'ed if needed |
249 | # | 252 | # |
diff --git a/lib/Makefile b/lib/Makefile index 6f195ff6a1a1..c0ffaaff6534 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -115,6 +115,8 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o | |||
115 | 115 | ||
116 | obj-$(CONFIG_CORDIC) += cordic.o | 116 | obj-$(CONFIG_CORDIC) += cordic.o |
117 | 117 | ||
118 | obj-$(CONFIG_DQL) += dynamic_queue_limits.o | ||
119 | |||
118 | hostprogs-y := gen_crc32table | 120 | hostprogs-y := gen_crc32table |
119 | clean-files := crc32table.h | 121 | clean-files := crc32table.h |
120 | 122 | ||
diff --git a/lib/debugobjects.c b/lib/debugobjects.c index a78b7c6e042c..77cb245f8e7b 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c | |||
@@ -268,12 +268,16 @@ static void debug_print_object(struct debug_obj *obj, char *msg) | |||
268 | * Try to repair the damage, so we have a better chance to get useful | 268 | * Try to repair the damage, so we have a better chance to get useful |
269 | * debug output. | 269 | * debug output. |
270 | */ | 270 | */ |
271 | static void | 271 | static int |
272 | debug_object_fixup(int (*fixup)(void *addr, enum debug_obj_state state), | 272 | debug_object_fixup(int (*fixup)(void *addr, enum debug_obj_state state), |
273 | void * addr, enum debug_obj_state state) | 273 | void * addr, enum debug_obj_state state) |
274 | { | 274 | { |
275 | int fixed = 0; | ||
276 | |||
275 | if (fixup) | 277 | if (fixup) |
276 | debug_objects_fixups += fixup(addr, state); | 278 | fixed = fixup(addr, state); |
279 | debug_objects_fixups += fixed; | ||
280 | return fixed; | ||
277 | } | 281 | } |
278 | 282 | ||
279 | static void debug_object_is_on_stack(void *addr, int onstack) | 283 | static void debug_object_is_on_stack(void *addr, int onstack) |
@@ -386,6 +390,9 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr) | |||
386 | struct debug_bucket *db; | 390 | struct debug_bucket *db; |
387 | struct debug_obj *obj; | 391 | struct debug_obj *obj; |
388 | unsigned long flags; | 392 | unsigned long flags; |
393 | struct debug_obj o = { .object = addr, | ||
394 | .state = ODEBUG_STATE_NOTAVAILABLE, | ||
395 | .descr = descr }; | ||
389 | 396 | ||
390 | if (!debug_objects_enabled) | 397 | if (!debug_objects_enabled) |
391 | return; | 398 | return; |
@@ -425,8 +432,9 @@ void debug_object_activate(void *addr, struct debug_obj_descr *descr) | |||
425 | * let the type specific code decide whether this is | 432 | * let the type specific code decide whether this is |
426 | * true or not. | 433 | * true or not. |
427 | */ | 434 | */ |
428 | debug_object_fixup(descr->fixup_activate, addr, | 435 | if (debug_object_fixup(descr->fixup_activate, addr, |
429 | ODEBUG_STATE_NOTAVAILABLE); | 436 | ODEBUG_STATE_NOTAVAILABLE)) |
437 | debug_print_object(&o, "activate"); | ||
430 | } | 438 | } |
431 | 439 | ||
432 | /** | 440 | /** |
@@ -563,6 +571,44 @@ out_unlock: | |||
563 | } | 571 | } |
564 | 572 | ||
565 | /** | 573 | /** |
574 | * debug_object_assert_init - debug checks when object should be init-ed | ||
575 | * @addr: address of the object | ||
576 | * @descr: pointer to an object specific debug description structure | ||
577 | */ | ||
578 | void debug_object_assert_init(void *addr, struct debug_obj_descr *descr) | ||
579 | { | ||
580 | struct debug_bucket *db; | ||
581 | struct debug_obj *obj; | ||
582 | unsigned long flags; | ||
583 | |||
584 | if (!debug_objects_enabled) | ||
585 | return; | ||
586 | |||
587 | db = get_bucket((unsigned long) addr); | ||
588 | |||
589 | raw_spin_lock_irqsave(&db->lock, flags); | ||
590 | |||
591 | obj = lookup_object(addr, db); | ||
592 | if (!obj) { | ||
593 | struct debug_obj o = { .object = addr, | ||
594 | .state = ODEBUG_STATE_NOTAVAILABLE, | ||
595 | .descr = descr }; | ||
596 | |||
597 | raw_spin_unlock_irqrestore(&db->lock, flags); | ||
598 | /* | ||
599 | * Maybe the object is static. Let the type specific | ||
600 | * code decide what to do. | ||
601 | */ | ||
602 | if (debug_object_fixup(descr->fixup_assert_init, addr, | ||
603 | ODEBUG_STATE_NOTAVAILABLE)) | ||
604 | debug_print_object(&o, "assert_init"); | ||
605 | return; | ||
606 | } | ||
607 | |||
608 | raw_spin_unlock_irqrestore(&db->lock, flags); | ||
609 | } | ||
610 | |||
611 | /** | ||
566 | * debug_object_active_state - debug checks object usage state machine | 612 | * debug_object_active_state - debug checks object usage state machine |
567 | * @addr: address of the object | 613 | * @addr: address of the object |
568 | * @descr: pointer to an object specific debug description structure | 614 | * @descr: pointer to an object specific debug description structure |
diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c new file mode 100644 index 000000000000..3d1bdcdd7db4 --- /dev/null +++ b/lib/dynamic_queue_limits.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * Dynamic byte queue limits. See include/linux/dynamic_queue_limits.h | ||
3 | * | ||
4 | * Copyright (c) 2011, Tom Herbert <therbert@google.com> | ||
5 | */ | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/types.h> | ||
8 | #include <linux/ctype.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/dynamic_queue_limits.h> | ||
11 | |||
12 | #define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0) | ||
13 | |||
14 | /* Records completed count and recalculates the queue limit */ | ||
15 | void dql_completed(struct dql *dql, unsigned int count) | ||
16 | { | ||
17 | unsigned int inprogress, prev_inprogress, limit; | ||
18 | unsigned int ovlimit, all_prev_completed, completed; | ||
19 | |||
20 | /* Can't complete more than what's in queue */ | ||
21 | BUG_ON(count > dql->num_queued - dql->num_completed); | ||
22 | |||
23 | completed = dql->num_completed + count; | ||
24 | limit = dql->limit; | ||
25 | ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit); | ||
26 | inprogress = dql->num_queued - completed; | ||
27 | prev_inprogress = dql->prev_num_queued - dql->num_completed; | ||
28 | all_prev_completed = POSDIFF(completed, dql->prev_num_queued); | ||
29 | |||
30 | if ((ovlimit && !inprogress) || | ||
31 | (dql->prev_ovlimit && all_prev_completed)) { | ||
32 | /* | ||
33 | * Queue considered starved if: | ||
34 | * - The queue was over-limit in the last interval, | ||
35 | * and there is no more data in the queue. | ||
36 | * OR | ||
37 | * - The queue was over-limit in the previous interval and | ||
38 | * when enqueuing it was possible that all queued data | ||
39 | * had been consumed. This covers the case when queue | ||
40 | * may have becomes starved between completion processing | ||
41 | * running and next time enqueue was scheduled. | ||
42 | * | ||
43 | * When queue is starved increase the limit by the amount | ||
44 | * of bytes both sent and completed in the last interval, | ||
45 | * plus any previous over-limit. | ||
46 | */ | ||
47 | limit += POSDIFF(completed, dql->prev_num_queued) + | ||
48 | dql->prev_ovlimit; | ||
49 | dql->slack_start_time = jiffies; | ||
50 | dql->lowest_slack = UINT_MAX; | ||
51 | } else if (inprogress && prev_inprogress && !all_prev_completed) { | ||
52 | /* | ||
53 | * Queue was not starved, check if the limit can be decreased. | ||
54 | * A decrease is only considered if the queue has been busy in | ||
55 | * the whole interval (the check above). | ||
56 | * | ||
57 | * If there is slack, the amount of execess data queued above | ||
58 | * the the amount needed to prevent starvation, the queue limit | ||
59 | * can be decreased. To avoid hysteresis we consider the | ||
60 | * minimum amount of slack found over several iterations of the | ||
61 | * completion routine. | ||
62 | */ | ||
63 | unsigned int slack, slack_last_objs; | ||
64 | |||
65 | /* | ||
66 | * Slack is the maximum of | ||
67 | * - The queue limit plus previous over-limit minus twice | ||
68 | * the number of objects completed. Note that two times | ||
69 | * number of completed bytes is a basis for an upper bound | ||
70 | * of the limit. | ||
71 | * - Portion of objects in the last queuing operation that | ||
72 | * was not part of non-zero previous over-limit. That is | ||
73 | * "round down" by non-overlimit portion of the last | ||
74 | * queueing operation. | ||
75 | */ | ||
76 | slack = POSDIFF(limit + dql->prev_ovlimit, | ||
77 | 2 * (completed - dql->num_completed)); | ||
78 | slack_last_objs = dql->prev_ovlimit ? | ||
79 | POSDIFF(dql->prev_last_obj_cnt, dql->prev_ovlimit) : 0; | ||
80 | |||
81 | slack = max(slack, slack_last_objs); | ||
82 | |||
83 | if (slack < dql->lowest_slack) | ||
84 | dql->lowest_slack = slack; | ||
85 | |||
86 | if (time_after(jiffies, | ||
87 | dql->slack_start_time + dql->slack_hold_time)) { | ||
88 | limit = POSDIFF(limit, dql->lowest_slack); | ||
89 | dql->slack_start_time = jiffies; | ||
90 | dql->lowest_slack = UINT_MAX; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* Enforce bounds on limit */ | ||
95 | limit = clamp(limit, dql->min_limit, dql->max_limit); | ||
96 | |||
97 | if (limit != dql->limit) { | ||
98 | dql->limit = limit; | ||
99 | ovlimit = 0; | ||
100 | } | ||
101 | |||
102 | dql->adj_limit = limit + completed; | ||
103 | dql->prev_ovlimit = ovlimit; | ||
104 | dql->prev_last_obj_cnt = dql->last_obj_cnt; | ||
105 | dql->num_completed = completed; | ||
106 | dql->prev_num_queued = dql->num_queued; | ||
107 | } | ||
108 | EXPORT_SYMBOL(dql_completed); | ||
109 | |||
110 | void dql_reset(struct dql *dql) | ||
111 | { | ||
112 | /* Reset all dynamic values */ | ||
113 | dql->limit = 0; | ||
114 | dql->num_queued = 0; | ||
115 | dql->num_completed = 0; | ||
116 | dql->last_obj_cnt = 0; | ||
117 | dql->prev_num_queued = 0; | ||
118 | dql->prev_last_obj_cnt = 0; | ||
119 | dql->prev_ovlimit = 0; | ||
120 | dql->lowest_slack = UINT_MAX; | ||
121 | dql->slack_start_time = jiffies; | ||
122 | } | ||
123 | EXPORT_SYMBOL(dql_reset); | ||
124 | |||
125 | int dql_init(struct dql *dql, unsigned hold_time) | ||
126 | { | ||
127 | dql->max_limit = DQL_MAX_LIMIT; | ||
128 | dql->min_limit = 0; | ||
129 | dql->slack_hold_time = hold_time; | ||
130 | dql_reset(dql); | ||
131 | return 0; | ||
132 | } | ||
133 | EXPORT_SYMBOL(dql_init); | ||
diff --git a/lib/reciprocal_div.c b/lib/reciprocal_div.c index 6a3bd48fa2a0..75510e94f7d0 100644 --- a/lib/reciprocal_div.c +++ b/lib/reciprocal_div.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <asm/div64.h> | 1 | #include <asm/div64.h> |
2 | #include <linux/reciprocal_div.h> | 2 | #include <linux/reciprocal_div.h> |
3 | #include <linux/export.h> | ||
3 | 4 | ||
4 | u32 reciprocal_value(u32 k) | 5 | u32 reciprocal_value(u32 k) |
5 | { | 6 | { |
@@ -7,3 +8,4 @@ u32 reciprocal_value(u32 k) | |||
7 | do_div(val, k); | 8 | do_div(val, k); |
8 | return (u32)val; | 9 | return (u32)val; |
9 | } | 10 | } |
11 | EXPORT_SYMBOL(reciprocal_value); | ||
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 993599e66e5a..8e75003d62f6 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -777,6 +777,18 @@ char *uuid_string(char *buf, char *end, const u8 *addr, | |||
777 | return string(buf, end, uuid, spec); | 777 | return string(buf, end, uuid, spec); |
778 | } | 778 | } |
779 | 779 | ||
780 | static | ||
781 | char *netdev_feature_string(char *buf, char *end, const u8 *addr, | ||
782 | struct printf_spec spec) | ||
783 | { | ||
784 | spec.flags |= SPECIAL | SMALL | ZEROPAD; | ||
785 | if (spec.field_width == -1) | ||
786 | spec.field_width = 2 + 2 * sizeof(netdev_features_t); | ||
787 | spec.base = 16; | ||
788 | |||
789 | return number(buf, end, *(const netdev_features_t *)addr, spec); | ||
790 | } | ||
791 | |||
780 | int kptr_restrict __read_mostly; | 792 | int kptr_restrict __read_mostly; |
781 | 793 | ||
782 | /* | 794 | /* |
@@ -824,6 +836,7 @@ int kptr_restrict __read_mostly; | |||
824 | * Do not use this feature without some mechanism to verify the | 836 | * Do not use this feature without some mechanism to verify the |
825 | * correctness of the format string and va_list arguments. | 837 | * correctness of the format string and va_list arguments. |
826 | * - 'K' For a kernel pointer that should be hidden from unprivileged users | 838 | * - 'K' For a kernel pointer that should be hidden from unprivileged users |
839 | * - 'NF' For a netdev_features_t | ||
827 | * | 840 | * |
828 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 | 841 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 |
829 | * function pointers are really function descriptors, which contain a | 842 | * function pointers are really function descriptors, which contain a |
@@ -896,6 +909,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
896 | has_capability_noaudit(current, CAP_SYSLOG)))) | 909 | has_capability_noaudit(current, CAP_SYSLOG)))) |
897 | ptr = NULL; | 910 | ptr = NULL; |
898 | break; | 911 | break; |
912 | case 'N': | ||
913 | switch (fmt[1]) { | ||
914 | case 'F': | ||
915 | return netdev_feature_string(buf, end, ptr, spec); | ||
916 | } | ||
917 | break; | ||
899 | } | 918 | } |
900 | spec.flags |= SMALL; | 919 | spec.flags |= SMALL; |
901 | if (spec.field_width == -1) { | 920 | if (spec.field_width == -1) { |