Messages in this thread Patch in this message | | | Date | Thu, 25 Feb 1999 20:29:19 +0100 (CET) | From | Andrea Arcangeli <> | Subject | [patch] kmem_cache_destroy (modules will be happy) |
| |
I implemented kmem_cache_destroy() in the slab. This will allow a module to create its slab cache at insmod time and to destroy it _completly_ at rmmod time.
I also did a little cleanup of the code related to the new slab API.
Here the patch against 2.2.2:
Index: include/linux/slab.h =================================================================== RCS file: /var/cvs/linux/include/linux/slab.h,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 slab.h --- slab.h 1999/01/18 01:33:10 1.1.2.1 +++ linux/include/linux/slab.h 1999/02/25 17:04:25 @@ -51,6 +51,7 @@ extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(void *, kmem_cache_t *, unsigned long), void (*)(void *, kmem_cache_t *, unsigned long)); +extern int kmem_cache_destroy(kmem_cache_t *); extern int kmem_cache_shrink(kmem_cache_t *); extern void *kmem_cache_alloc(kmem_cache_t *, int); extern void kmem_cache_free(kmem_cache_t *, void *); Index: kernel/ksyms.c =================================================================== RCS file: /var/cvs/linux/kernel/ksyms.c,v retrieving revision 1.1.2.11 diff -u -r1.1.2.11 ksyms.c --- ksyms.c 1999/02/20 15:57:41 1.1.2.11 +++ linux/kernel/ksyms.c 1999/02/25 16:02:39 @@ -92,6 +92,7 @@ EXPORT_SYMBOL(__free_page); EXPORT_SYMBOL(kmem_find_general_cachep); EXPORT_SYMBOL(kmem_cache_create); +EXPORT_SYMBOL(kmem_cache_destroy); EXPORT_SYMBOL(kmem_cache_shrink); EXPORT_SYMBOL(kmem_cache_alloc); EXPORT_SYMBOL(kmem_cache_free); Index: mm//slab.c =================================================================== RCS file: /var/cvs/linux/mm/slab.c,v retrieving revision 1.1.2.1 diff -u -r1.1.2.1 slab.c --- slab.c 1999/01/18 01:32:53 1.1.2.1 +++ linux/mm/slab.c 1999/02/25 18:23:31 @@ -3,6 +3,8 @@ * Written by Mark Hemment, 1996/97. * (markhe@nextd.demon.co.uk) * + * kmem_cache_destroy() + some cleanup - 1999 Andrea Arcangeli + * * 11 April '97. Started multi-threading - markhe * The global cache-chain is protected by the semaphore 'cache_chain_sem'. * The sem is only needed when accessing/extending the cache-chain, which @@ -979,6 +981,59 @@ return cachep; } +/* + * This check if the kmem_cache_t pointer is chained in the cache_cache + * list. -arca + */ +static int is_chained_kmem_cache(kmem_cache_t * cachep) +{ + kmem_cache_t * searchp; + int ret = 0; + + /* Find the cache in the chain of caches. */ + down(&cache_chain_sem); + for (searchp = &cache_cache; searchp->c_nextp != &cache_cache; + searchp = searchp->c_nextp) + { + if (searchp->c_nextp != cachep) + continue; + + /* Accessing clock_searchp is safe - we hold the mutex. */ + if (cachep == clock_searchp) + clock_searchp = cachep->c_nextp; + ret = 1; + break; + } + up(&cache_chain_sem); + + return ret; +} + +/* returns 0 if every slab is been freed -arca */ +static int __kmem_cache_shrink(kmem_cache_t *cachep) +{ + kmem_slab_t *slabp; + int ret; + + spin_lock_irq(&cachep->c_spinlock); + + /* If the cache is growing, stop shrinking. */ + while (!cachep->c_growing) { + slabp = cachep->c_lastp; + if (slabp->s_inuse || slabp == kmem_slab_end(cachep)) + break; + kmem_slab_unlink(slabp); + spin_unlock_irq(&cachep->c_spinlock); + kmem_slab_destroy(cachep, slabp); + spin_lock_irq(&cachep->c_spinlock); + } + ret = 1; + if (cachep->c_lastp == kmem_slab_end(cachep)) + ret = 0; /* Cache is empty. */ + spin_unlock_irq(&cachep->c_spinlock); + return ret; +} + /* Shrink a cache. Releases as many slabs as possible for a cache. * It is expected this function will be called by a module when it is * unloaded. The cache is _not_ removed, this creates too many problems and @@ -990,10 +1045,6 @@ int kmem_cache_shrink(kmem_cache_t *cachep) { - kmem_cache_t *searchp; - kmem_slab_t *slabp; - int ret; - if (!cachep) { printk(KERN_ERR "kmem_shrink: NULL ptr\n"); return 2; @@ -1003,43 +1054,77 @@ return 2; } + if (!is_chained_kmem_cache(cachep)) + { + printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", + cachep); + return 2; + } + + return __kmem_cache_shrink(cachep); +} + +/* + * Remove a kmem_cache_t object from the slab cache. When returns 0 it + * completed succesfully. -arca + */ +int kmem_cache_destroy(kmem_cache_t * cachep) +{ + kmem_cache_t * prev; + int ret; + + if (!cachep) { + printk(KERN_ERR "kmem_destroy: NULL ptr\n"); + return 1; + } + if (in_interrupt()) { + printk(KERN_ERR "kmem_destroy: Called during int - %s\n", + cachep->c_name); + return 1; + } + + ret = 0; /* Find the cache in the chain of caches. */ - down(&cache_chain_sem); /* Semaphore is needed. */ - searchp = &cache_cache; - for (;searchp->c_nextp != &cache_cache; searchp = searchp->c_nextp) { - if (searchp->c_nextp != cachep) + down(&cache_chain_sem); + for (prev = &cache_cache; prev->c_nextp != &cache_cache; + prev = prev->c_nextp) + { + if (prev->c_nextp != cachep) continue; /* Accessing clock_searchp is safe - we hold the mutex. */ if (cachep == clock_searchp) clock_searchp = cachep->c_nextp; - goto found; + + /* remove the cachep from the cache_cache list. -arca */ + prev->c_nextp = cachep->c_nextp; + + ret = 1; + break; } up(&cache_chain_sem); - printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", cachep); - return 2; -found: - /* Release the semaphore before getting the cache-lock. This could - * mean multiple engines are shrinking the cache, but so what. - */ - up(&cache_chain_sem); - spin_lock_irq(&cachep->c_spinlock); - /* If the cache is growing, stop shrinking. */ - while (!cachep->c_growing) { - slabp = cachep->c_lastp; - if (slabp->s_inuse || slabp == kmem_slab_end(cachep)) - break; - kmem_slab_unlink(slabp); - spin_unlock_irq(&cachep->c_spinlock); - kmem_slab_destroy(cachep, slabp); - spin_lock_irq(&cachep->c_spinlock); + if (!ret) + { + printk(KERN_ERR "kmem_destroy: Invalid cache addr %p\n", + cachep); + return 1; } - ret = 1; - if (cachep->c_lastp == kmem_slab_end(cachep)) - ret--; /* Cache is empty. */ - spin_unlock_irq(&cachep->c_spinlock); - return ret; + + if (__kmem_cache_shrink(cachep)) + { + printk(KERN_ERR "kmem_destroy: Can't free all objects %p\n", + cachep); + down(&cache_chain_sem); + cachep->c_nextp = cache_cache.c_nextp; + cache_cache.c_nextp = cachep; + up(&cache_chain_sem); + return 1; + } + + kmem_cache_free(&cache_cache, cachep); + + return 0; } /* Get the memory for a slab management obj. */
And here a kernel module I developed to test the new API. This new kernel module simply alloc an array of slab cache headers, and for each of them alloc tons of slab object. Then initialize the slab object to a known value and check that the value it's unchanged before deallocing the object.
I tried for example to alloc 60Mbyte of RAM distributed between 20 slab headers and everything get released fine when the module got released from the kernel.
Here the slab-test module I written today:
begin 644 slab-test-0.tar.gz M'XL(`!B@U38``^T8:W?:R-5?T:^X<=QS!$$\#:SM.&=E+-MT,7`DJ-?=]FAE M,3+C"(F.1GC=GO2W]\Y((+#)XX.S>]KJYB31S-SW<X;(=^XT3B)>W?MN`(>U M3JL%>P#0:1]N_9]"#:#=;K>:C5JMU@&HU]N-QAZTOI]*&<01=QC`GA-,&7$^ MC_>U\_]2B-;Q7W]5W%>64:_5VH>'GXU_Z[#=2>-?[W00$>J'M7IS#VJOK,=. M^#^/?[6D0`E@'?QCZ-,@_@TLW(`Q;A`F$;KAXHG1^QD'M5N$^M'1$8`N70(Z M<YW@GO@4$27N>$8C6+#PGCESP$^/$0)1Z/%'AY$3>`IC0`I@9$HCSNA=S`E0 M#NCA:LA@'DZI]R09X68<3`D#/B.`FLPC"#VYN!Q,X)($A#D^C.([G[JHMTN" MB("#LL5.-"-3N$L8"9(+H865:@$7(7)V.`V#$R`4SQDL"8MP#8V5D)1C&<+$ M!ZK#A?(,PH4@+*+&3^`[/*.M?,X%F:53H('D/@L7:-0,>:*9C]3WX8Y`'!$O M]LN2!V+#36]\-9R,01_<PHUNFOI@?'N"V'P6XBE9DH07G2]\BJS1-.8$_`DM MD"RN#;-[A33Z6:_?&]^B(7#1&P\,RX*+H0DZC'1SW.M.^KH)HXDY&EI&!<`B M0C$B.7S!T9X,%OIR2KA#_6AM_"T&.$(%_2G,G"7!0+N$+E$]!UQ,HZ_'4')Q M_#"XEZ8B=N;-$Z`>!"$OPR.CF#@\?!E=29]%N`R]P*V4H76$&8V>(C#R'1?C M:L6"0[-9*\-9&'&!>:WC-&K4ZW6MWA2C:&+I*[.>I[M,8HR9&P;<<45DE]0! M,D=?`$;U?=(Q?B3:G`;3BAO./ZP]=-";'N!'55'>TL#UXRF!][ZHNRIF?^R3 MRNS#KI,TRZ)=QQ\)"XB_ZT34]J[]Y=SQ_=`51\KU\'S2-VQ,AVLU8+;KN#/T MSS[=+YX\/Q/L5D<*#3BL\.$4&K63U99`2W<4;+$<H[L,*5:D$V#(5?%=5/ZE M%!8,"3ZJ^R_:#FBPKQ32&;'_+?WG;\$&P6`X-D#\<PR]R\'0-&2:G$VL6R", M8>IB%M(@0J^^03JTY=.VGD)_6W3$3-6/<S)/3+4YE$H@UZ+BGDZ4@C`;]R39 MYAY%^PL9)KHD];L:T7^2T%.WN18Q/58.1:4*&;^7E,@^19?.WB9$KA'A:B:Y M#)CFWR0S)<U$;Y)^2:CR=DH\&I""U=?/[-[YSP65EE+,=P]%=(3H&2I%4VI8 MQ_!^38RK=^^*2@&]7$BC@&45<7!G.)W1K9PAT?YZ3.VCFM*]#\*]&_[]A?X= M$3?L<S%%.%&1P98)9:02`,(TJ>[535?O7AFVWL=\*</Z?##I]\ORWZ(4ZH'Z M9DL>JBWU7J?R"^GPIRGF6!FHY%"X#[%I8?^VQ6`4.Y_PK_3,0^*9A\0SPEI< M2,<D$K*0_+)R\3-SDP39TF]E:J%P>3&R?S+,@9&8DMBRBZ<0F$C<9924@3:M MS2K#0\+PI6G2MD+I,XK3TD-J/U;?6E37-/2Q<0[&7PSS=GS5&UPF%:H4W)@Q M$G#M@\@1T7#&NO63W1N,#=.<C,:]L[XA:@:5%%W4YG1.4!FU7BM=_54P6*MV M_(VYF*78[K@71//'SD4DSC?%\,M.WV"8XN[VW1OIO.)6B!Z9F)A+QX^)N&3( M^@SO'HC+LV`I25)+R.*V$5SAG6?Y`SNU30*7>F:#P13+DX5/VSR*Q<T"\7!$ MXKC$5$F1909O50ER?BON?MZZEZ"HY3/E!&*REVDH\V0EZ,(T=N31IV1NT8!R M.YFW68]/QY/DDHT`N62$QRR`NF#P1U_;7PVR]]^U\Q&;MT]>7\97WG]X`6LG M[[]&I]EIM_#]ASOY^^]W@;?B+GH,J^"7EU"OR#_BCO5#M794;=:@T3QN=HYK MAY`X`8S?%G"@*,DH*9P6JG'$JA%SJ_)BJ5S;P[,_6[B?_:00*@I.C6.\6Z`@ MT+IPH*:#"*S)V7G/M$Y_73Q.?X6D'B-%<7WB!$B@L3EH'I0J(93^#94I69!@ M"I52Q?.=^TA4<G*I73.LFH)!10CZWRG3[P99_5<VHI4X][5D?*W^6ZWV^O>? MPY;X_:]5;^7U_[L`]<@_0-5NL#I!NQ$_4KA<PZ<V#_G3@D2@#1M8?N&<<LW# MUS?1%B'.3O$Z.[=MZWIDVZ`MZ`)KV@M"#>E)<,]G&L,+F(N;<ZQ63N,Y<L2% MX]/[0//#<!&=-M;K!SS>7'MQX(IGN]P[[XXFI^T?VOB5O$.3#YSH5F\XL$!; MU?]V#ZJFV]4=;^?R@7@-4&QA:A3?X1OC0,7'^=PIEH_QJ'O1UR^M(FX:/X]- MW<[6R9>]429%!.6BUS<L.SF;C.SQT#['VRN\.X7-]H=-BWIY/\HAAQQRR"&' 7''+((8<<<L@AAQS^`/@/^U)`6P`H```` ` end Andrea Arcangeli
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |