diff options
Diffstat (limited to 'mm/slab.c')
-rw-r--r-- | mm/slab.c | 88 |
1 files changed, 84 insertions, 4 deletions
@@ -107,6 +107,7 @@ | |||
107 | #include <linux/nodemask.h> | 107 | #include <linux/nodemask.h> |
108 | #include <linux/mempolicy.h> | 108 | #include <linux/mempolicy.h> |
109 | #include <linux/mutex.h> | 109 | #include <linux/mutex.h> |
110 | #include <linux/fault-inject.h> | ||
110 | #include <linux/rtmutex.h> | 111 | #include <linux/rtmutex.h> |
111 | 112 | ||
112 | #include <asm/cacheflush.h> | 113 | #include <asm/cacheflush.h> |
@@ -945,7 +946,8 @@ static void __devinit start_cpu_timer(int cpu) | |||
945 | if (keventd_up() && reap_work->work.func == NULL) { | 946 | if (keventd_up() && reap_work->work.func == NULL) { |
946 | init_reap_node(cpu); | 947 | init_reap_node(cpu); |
947 | INIT_DELAYED_WORK(reap_work, cache_reap); | 948 | INIT_DELAYED_WORK(reap_work, cache_reap); |
948 | schedule_delayed_work_on(cpu, reap_work, HZ + 3 * cpu); | 949 | schedule_delayed_work_on(cpu, reap_work, |
950 | __round_jiffies_relative(HZ, cpu)); | ||
949 | } | 951 | } |
950 | } | 952 | } |
951 | 953 | ||
@@ -3088,12 +3090,89 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep, | |||
3088 | #define cache_alloc_debugcheck_after(a,b,objp,d) (objp) | 3090 | #define cache_alloc_debugcheck_after(a,b,objp,d) (objp) |
3089 | #endif | 3091 | #endif |
3090 | 3092 | ||
3093 | #ifdef CONFIG_FAILSLAB | ||
3094 | |||
3095 | static struct failslab_attr { | ||
3096 | |||
3097 | struct fault_attr attr; | ||
3098 | |||
3099 | u32 ignore_gfp_wait; | ||
3100 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
3101 | struct dentry *ignore_gfp_wait_file; | ||
3102 | #endif | ||
3103 | |||
3104 | } failslab = { | ||
3105 | .attr = FAULT_ATTR_INITIALIZER, | ||
3106 | .ignore_gfp_wait = 1, | ||
3107 | }; | ||
3108 | |||
3109 | static int __init setup_failslab(char *str) | ||
3110 | { | ||
3111 | return setup_fault_attr(&failslab.attr, str); | ||
3112 | } | ||
3113 | __setup("failslab=", setup_failslab); | ||
3114 | |||
3115 | static int should_failslab(struct kmem_cache *cachep, gfp_t flags) | ||
3116 | { | ||
3117 | if (cachep == &cache_cache) | ||
3118 | return 0; | ||
3119 | if (flags & __GFP_NOFAIL) | ||
3120 | return 0; | ||
3121 | if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT)) | ||
3122 | return 0; | ||
3123 | |||
3124 | return should_fail(&failslab.attr, obj_size(cachep)); | ||
3125 | } | ||
3126 | |||
3127 | #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||
3128 | |||
3129 | static int __init failslab_debugfs(void) | ||
3130 | { | ||
3131 | mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; | ||
3132 | struct dentry *dir; | ||
3133 | int err; | ||
3134 | |||
3135 | err = init_fault_attr_dentries(&failslab.attr, "failslab"); | ||
3136 | if (err) | ||
3137 | return err; | ||
3138 | dir = failslab.attr.dentries.dir; | ||
3139 | |||
3140 | failslab.ignore_gfp_wait_file = | ||
3141 | debugfs_create_bool("ignore-gfp-wait", mode, dir, | ||
3142 | &failslab.ignore_gfp_wait); | ||
3143 | |||
3144 | if (!failslab.ignore_gfp_wait_file) { | ||
3145 | err = -ENOMEM; | ||
3146 | debugfs_remove(failslab.ignore_gfp_wait_file); | ||
3147 | cleanup_fault_attr_dentries(&failslab.attr); | ||
3148 | } | ||
3149 | |||
3150 | return err; | ||
3151 | } | ||
3152 | |||
3153 | late_initcall(failslab_debugfs); | ||
3154 | |||
3155 | #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||
3156 | |||
3157 | #else /* CONFIG_FAILSLAB */ | ||
3158 | |||
3159 | static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags) | ||
3160 | { | ||
3161 | return 0; | ||
3162 | } | ||
3163 | |||
3164 | #endif /* CONFIG_FAILSLAB */ | ||
3165 | |||
3091 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) | 3166 | static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags) |
3092 | { | 3167 | { |
3093 | void *objp; | 3168 | void *objp; |
3094 | struct array_cache *ac; | 3169 | struct array_cache *ac; |
3095 | 3170 | ||
3096 | check_irq_off(); | 3171 | check_irq_off(); |
3172 | |||
3173 | if (should_failslab(cachep, flags)) | ||
3174 | return NULL; | ||
3175 | |||
3097 | ac = cpu_cache_get(cachep); | 3176 | ac = cpu_cache_get(cachep); |
3098 | if (likely(ac->avail)) { | 3177 | if (likely(ac->avail)) { |
3099 | STATS_INC_ALLOCHIT(cachep); | 3178 | STATS_INC_ALLOCHIT(cachep); |
@@ -3182,7 +3261,7 @@ retry: | |||
3182 | for (z = zonelist->zones; *z && !obj; z++) { | 3261 | for (z = zonelist->zones; *z && !obj; z++) { |
3183 | nid = zone_to_nid(*z); | 3262 | nid = zone_to_nid(*z); |
3184 | 3263 | ||
3185 | if (cpuset_zone_allowed(*z, flags) && | 3264 | if (cpuset_zone_allowed(*z, flags | __GFP_HARDWALL) && |
3186 | cache->nodelists[nid] && | 3265 | cache->nodelists[nid] && |
3187 | cache->nodelists[nid]->free_objects) | 3266 | cache->nodelists[nid]->free_objects) |
3188 | obj = ____cache_alloc_node(cache, | 3267 | obj = ____cache_alloc_node(cache, |
@@ -3928,7 +4007,7 @@ static void cache_reap(struct work_struct *unused) | |||
3928 | if (!mutex_trylock(&cache_chain_mutex)) { | 4007 | if (!mutex_trylock(&cache_chain_mutex)) { |
3929 | /* Give up. Setup the next iteration. */ | 4008 | /* Give up. Setup the next iteration. */ |
3930 | schedule_delayed_work(&__get_cpu_var(reap_work), | 4009 | schedule_delayed_work(&__get_cpu_var(reap_work), |
3931 | REAPTIMEOUT_CPUC); | 4010 | round_jiffies_relative(REAPTIMEOUT_CPUC)); |
3932 | return; | 4011 | return; |
3933 | } | 4012 | } |
3934 | 4013 | ||
@@ -3974,7 +4053,8 @@ next: | |||
3974 | next_reap_node(); | 4053 | next_reap_node(); |
3975 | refresh_cpu_vm_stats(smp_processor_id()); | 4054 | refresh_cpu_vm_stats(smp_processor_id()); |
3976 | /* Set up the next iteration */ | 4055 | /* Set up the next iteration */ |
3977 | schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC); | 4056 | schedule_delayed_work(&__get_cpu_var(reap_work), |
4057 | round_jiffies_relative(REAPTIMEOUT_CPUC)); | ||
3978 | } | 4058 | } |
3979 | 4059 | ||
3980 | #ifdef CONFIG_PROC_FS | 4060 | #ifdef CONFIG_PROC_FS |