@@ -2807,44 +2807,93 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
2807
2807
}
2808
2808
EXPORT_SYMBOL (kmem_cache_free );
2809
2809
2810
- /* Note that interrupts must be enabled when calling this function. */
2811
- void kmem_cache_free_bulk (struct kmem_cache * s , size_t size , void * * p )
2812
- {
2813
- struct kmem_cache_cpu * c ;
2810
+ struct detached_freelist {
2814
2811
struct page * page ;
2815
- int i ;
2812
+ void * tail ;
2813
+ void * freelist ;
2814
+ int cnt ;
2815
+ };
2816
2816
2817
- local_irq_disable ();
2818
- c = this_cpu_ptr (s -> cpu_slab );
2817
+ /*
2818
+ * This function progressively scans the array with free objects (with
2819
+ * a limited look ahead) and extract objects belonging to the same
2820
+ * page. It builds a detached freelist directly within the given
2821
+ * page/objects. This can happen without any need for
2822
+ * synchronization, because the objects are owned by running process.
2823
+ * The freelist is build up as a single linked list in the objects.
2824
+ * The idea is, that this detached freelist can then be bulk
2825
+ * transferred to the real freelist(s), but only requiring a single
2826
+ * synchronization primitive. Look ahead in the array is limited due
2827
+ * to performance reasons.
2828
+ */
2829
+ static int build_detached_freelist (struct kmem_cache * s , size_t size ,
2830
+ void * * p , struct detached_freelist * df )
2831
+ {
2832
+ size_t first_skipped_index = 0 ;
2833
+ int lookahead = 3 ;
2834
+ void * object ;
2819
2835
2820
- for ( i = 0 ; i < size ; i ++ ) {
2821
- void * object = p [ i ] ;
2836
+ /* Always re-init detached_freelist */
2837
+ df -> page = NULL ;
2822
2838
2823
- BUG_ON (!object );
2824
- /* kmem cache debug support */
2825
- s = cache_from_obj (s , object );
2826
- if (unlikely (!s ))
2827
- goto exit ;
2828
- slab_free_hook (s , object );
2839
+ do {
2840
+ object = p [-- size ];
2841
+ } while (!object && size );
2829
2842
2830
- page = virt_to_head_page (object );
2843
+ if (!object )
2844
+ return 0 ;
2831
2845
2832
- if (c -> page == page ) {
2833
- /* Fastpath: local CPU free */
2834
- set_freepointer (s , object , c -> freelist );
2835
- c -> freelist = object ;
2836
- } else {
2837
- c -> tid = next_tid (c -> tid );
2838
- local_irq_enable ();
2839
- /* Slowpath: overhead locked cmpxchg_double_slab */
2840
- __slab_free (s , page , object , object , 1 , _RET_IP_ );
2841
- local_irq_disable ();
2842
- c = this_cpu_ptr (s -> cpu_slab );
2846
+ /* Start new detached freelist */
2847
+ set_freepointer (s , object , NULL );
2848
+ df -> page = virt_to_head_page (object );
2849
+ df -> tail = object ;
2850
+ df -> freelist = object ;
2851
+ p [size ] = NULL ; /* mark object processed */
2852
+ df -> cnt = 1 ;
2853
+
2854
+ while (size ) {
2855
+ object = p [-- size ];
2856
+ if (!object )
2857
+ continue ; /* Skip processed objects */
2858
+
2859
+ /* df->page is always set at this point */
2860
+ if (df -> page == virt_to_head_page (object )) {
2861
+ /* Opportunity build freelist */
2862
+ set_freepointer (s , object , df -> freelist );
2863
+ df -> freelist = object ;
2864
+ df -> cnt ++ ;
2865
+ p [size ] = NULL ; /* mark object processed */
2866
+
2867
+ continue ;
2843
2868
}
2869
+
2870
+ /* Limit look ahead search */
2871
+ if (!-- lookahead )
2872
+ break ;
2873
+
2874
+ if (!first_skipped_index )
2875
+ first_skipped_index = size + 1 ;
2844
2876
}
2845
- exit :
2846
- c -> tid = next_tid (c -> tid );
2847
- local_irq_enable ();
2877
+
2878
+ return first_skipped_index ;
2879
+ }
2880
+
2881
+
2882
+ /* Note that interrupts must be enabled when calling this function. */
2883
+ void kmem_cache_free_bulk (struct kmem_cache * s , size_t size , void * * p )
2884
+ {
2885
+ if (WARN_ON (!size ))
2886
+ return ;
2887
+
2888
+ do {
2889
+ struct detached_freelist df ;
2890
+
2891
+ size = build_detached_freelist (s , size , p , & df );
2892
+ if (unlikely (!df .page ))
2893
+ continue ;
2894
+
2895
+ slab_free (s , df .page , df .freelist , df .tail , df .cnt , _RET_IP_ );
2896
+ } while (likely (size ));
2848
2897
}
2849
2898
EXPORT_SYMBOL (kmem_cache_free_bulk );
2850
2899
0 commit comments