fault-injection-developer Mailing List for Fault Injection Test Harness (Page 9)
Status: Alpha
Brought to you by:
rustyl
You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
(13) |
Sep
(2) |
Oct
(49) |
Nov
(69) |
Dec
(70) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(64) |
Feb
(41) |
Mar
(25) |
Apr
(18) |
May
(5) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(3) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(1) |
Nov
|
Dec
|
2009 |
Jan
(1) |
Feb
(2) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(1) |
Nov
(1) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(2) |
2016 |
Jan
(2) |
Feb
(5) |
Mar
(2) |
Apr
(1) |
May
(1) |
Jun
(1) |
Jul
(2) |
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
2017 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(4) |
Nov
|
Dec
|
From: Rusty L. <ru...@li...> - 2002-12-17 16:27:10
|
MessageWow! Well, we have to start somewhere. I suspected this just = from my systems response time while hacking on a patched box. It will be very = interesting to see how these numbers improve after a critical eye is taken to pf. --rusty ----- Original Message -----=20 From: Gao, Kevin=20 To: 'fau...@so...' ; Zhuang, Louis ; = Wang, Stanley=20 Sent: Monday, December 16, 2002 11:05 PM Subject: [Fault-injection-developer] Overhead summary. According to the results of performance testing. We can get some important conlusion. Compare 2.5.51 with our FITH with pure kernel(2.5.51) The over head is as follow: Mmap Latency about 17.8% Prot Fault about 63.5% Page Fault about 50% |
From: Gao, K. <kev...@in...> - 2002-12-17 07:07:37
|
According to the results of performance testing. We can get some important conlusion. Compare 2.5.51 with our FITH with pure kernel(2.5.51) The over head is as follow: Mmap Latency about 17.8% Prot Fault about 63.5% Page Fault about 50% |
From: Zhuang, L. <lou...@in...> - 2002-12-17 03:29:37
|
> According to what should be done in execute_trigger, > I don't think that include it inline will reduce much overhead. > Also, if there is any fault that should be injected, we don't really > care the system's performance; if there isn't, we could found other > way to reduce the overhead (using global flag?). This is a good idea to minimize overhead when there are no triggers. |
From: Zhuang, L. <lou...@in...> - 2002-12-17 03:18:05
|
> It seems to me that something more then just > mucking up a chunk of data could be implemented > by an interceptor. Doesn't this seem like an > artificial limitation? I think fi_core should know these things more then mucking. In my meaning, fi_core should know all these things such as 'cancel IO write', 'corrupt IO access' etc. and tell interceptor what they should do. if interceptor can not understand this hint or do this hits, it can ignore it w/ a warning. we should not assign interceptor too many responsibilities... * Interceptors should only intercept somthing wanted by others, report this intercepting event and do mucking what they can underderstand and can also do. * fi_core should assign triggers to interceptors, recieve intecepting events from interceptors, computing logic to determine what should do and tell interceptor do it. Interceptors should not compute logic because they *only* have information about trigger... fi_core should delegate mucking to interceptors beacuse it do not know hardware details. > Also, wouldn't you want your trigger executed > with as little overhead as possible if your Yes, I want. But I perfer to minimize overhead as little as possible when no triggers. When there are triggers, there are two more overheads, one is judging if the pagefault is caused by FITH, the other is processing the trigger if pagefault is caused by trigger. The first overhead can be optimized by searching algorithm. Then second overhead is *unavoidable*. the overhead is as much as what we do in FI. Less we do, Less overhead is... > interceptor is getting triggered very often > (like in a page fault handler.) It seems like it > would be a good idea to include the trigger execution > inline instead of making yet another function call. In our view, we'll update the limited computing logic code with code segment. So I do not think inline computing logic code is very helpful. |
From: Wang, S. <sta...@in...> - 2002-12-17 03:03:26
|
> > > I agree that the core is the proper location for putting > > > common (i.e. 'core') functionality that is exported for > > > other code to use. > > > > > > This doesn't explain why you want execute_trigger inside > > > the core. I would argue that each interceptor does not > > > want to execute a trigger in exactly the same way. > > As you see, execute_trigger handles an intercepted event, > > and look up the wp table to decide how to injection fault. It > > will be need by all the other interceptor, IO/PCI config etc. > > Why not we move it into fi_core.c and share it among all > > interceptors. > > > > -Stan > > > > > > > > Could you further explain your position? > > > > > > > When the pf interceptor executes a trigger all it > really does is: > 1. apply some filter criteria contained in the > trigger to decide if anything should be done > 2. If something should be done then apply some > operations on the data passed to the handler > 3. store the manipulated data back where it was > read from > > It seems to me that something more then just > mucking up a chunk of data could be implemented > by an interceptor. Doesn't this seem like an > artificial limitation? > > Also, wouldn't you want your trigger executed > with as little overhead as possible if your > interceptor is getting triggered very often > (like in a page fault handler.) It seems like it > would be a good idea to include the trigger execution > inline instead of making yet another function call. According to what should be done in execute_trigger, I don't think that include it inline will reduce much overhead. Also, if there is any fault that should be injected, we don't really care the system's performance; if there isn't, we could found other way to reduce the overhead (using global flag?). How do you think about it :) -Stan > > -rusty > |
From: Wang, S. <sta...@in...> - 2002-12-17 02:56:28
|
Hi, folks According to Kevin's test results, we could found the kernel with fi has a serious performance depress on page fault relatived operation. How about use hash table instead array to store the WP? -Stan -----Original Message----- From: Gao, Kevin [mailto:kev...@in...] Sent: 2002?12?17? 9:10 To: 'fau...@so...' Subject: [Fault-injection-developer] Result of lmbench L M B E N C H 2 . 0 S U M M A R Y ------------------------------------ Basic system parameters ---------------------------------------------------- Host OS Description Mhz --------- ------------- ----------------------- ---- 51-fi Linux 2.5.51 i686-pc-linux-gnu 932 51-pure Linux 2.5.51 i686-pc-linux-gnu 932 Processor, Processes - times in microseconds - smaller is better ---------------------------------------------------------------- Host OS Mhz null null open selct sig sig fork exec sh call I/O stat clos TCP inst hndl proc proc proc --------- ------------- ---- ---- ---- ---- ---- ----- ---- ---- ---- ---- ---- 51-fi Linux 2.5.51 932 0.37 0.72 23.2 24.5 31.5 1.09 4.44 231. 1078 5299 51-pure Linux 2.5.51 932 0.37 0.70 23.0 24.4 31.8 1.07 4.64 216. 1013 5069 Context switching - times in microseconds - smaller is better ------------------------------------------------------------- Host OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw --------- ------------- ----- ------ ------ ------ ------ ------- ------- 51-fi Linux 2.5.51 1.180 7.8700 17.2 6.1600 98.0 14.4 103.8 51-pure Linux 2.5.51 1.190 7.5300 16.9 5.9600 95.6 16.8 103.1 *Local* Communication latencies in microseconds - smaller is better ------------------------------------------------------------------- Host OS 2p/0K Pipe AF UDP RPC/ TCP RPC/ TCP ctxsw UNIX UDP TCP conn --------- ------------- ----- ----- ---- ----- ----- ----- ----- ---- 51-fi Linux 2.5.51 1.180 6.949 15.3 27.4 49.4 86.5 91.9 133. 51-pure Linux 2.5.51 1.190 34.0 14.9 26.3 49.9 66.8 108.6 110. File & VM system latencies in microseconds - smaller is better -------------------------------------------------------------- Host OS 0K File 10K File Mmap Prot Page Create Delete Create Delete Latency Fault Fault --------- ------------- ------ ------ ------ ------ ------- ----- ----- 51-fi Linux 2.5.51 90.7 45.6 217.9 74.9 2492.0 1.519 3.00000 51-pure Linux 2.5.51 90.7 45.5 216.4 75.1 1995.0 0.966 2.00000 *Local* Communication bandwidths in MB/s - bigger is better ----------------------------------------------------------- Host OS Pipe AF TCP File Mmap Bcopy Bcopy Mem Mem UNIX reread reread (libc) (hand) read write --------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- ----- 51-fi Linux 2.5.51 369. 165. 44.6 446.2 557.5 242.2 175.7 557. 236.4 51-pure Linux 2.5.51 394. 164. 40.6 448.0 549.6 241.4 174.2 557. 235.7 Memory latencies in nanoseconds - smaller is better (WARNING - may not be correct, check graphs) --------------------------------------------------- Host OS Mhz L1 $ L2 $ Main mem Guesses --------- ------------- ---- ----- ------ -------- ------- 51-fi Linux 2.5.51 932 3.220 7.5140 100.8 51-pure Linux 2.5.51 932 3.220 7.5150 100.9 |
From: Lynch, R. <rus...@in...> - 2002-12-17 01:34:24
|
> > I agree that the core is the proper location for putting > > common (i.e. 'core') functionality that is exported for > > other code to use. > > > > This doesn't explain why you want execute_trigger inside > > the core. I would argue that each interceptor does not > > want to execute a trigger in exactly the same way. > As you see, execute_trigger handles an intercepted event, > and look up the wp table to decide how to injection fault. It > will be need by all the other interceptor, IO/PCI config etc. > Why not we move it into fi_core.c and share it among all > interceptors. > > -Stan > > > > > Could you further explain your position? > > > When the pf interceptor executes a trigger all it really does is: 1. apply some filter criteria contained in the trigger to decide if anything should be done 2. If something should be done then apply some operations on the data passed to the handler 3. store the manipulated data back where it was read from It seems to me that something more then just mucking up a chunk of data could be implemented by an interceptor. Doesn't this seem like an artificial limitation? Also, wouldn't you want your trigger executed with as little overhead as possible if your interceptor is getting triggered very often (like in a page fault handler.) It seems like it would be a good idea to include the trigger execution inline instead of making yet another function call. -rusty |
From: Gao, K. <kev...@in...> - 2002-12-17 01:12:09
|
L M B E N C H 2 . 0 S U M M A R Y ------------------------------------ Basic system parameters ---------------------------------------------------- Host OS Description Mhz --------- ------------- ----------------------- ---- 51-fi Linux 2.5.51 i686-pc-linux-gnu 932 51-pure Linux 2.5.51 i686-pc-linux-gnu 932 Processor, Processes - times in microseconds - smaller is better ---------------------------------------------------------------- Host OS Mhz null null open selct sig sig fork exec sh call I/O stat clos TCP inst hndl proc proc proc --------- ------------- ---- ---- ---- ---- ---- ----- ---- ---- ---- ---- ---- 51-fi Linux 2.5.51 932 0.37 0.72 23.2 24.5 31.5 1.09 4.44 231. 1078 5299 51-pure Linux 2.5.51 932 0.37 0.70 23.0 24.4 31.8 1.07 4.64 216. 1013 5069 Context switching - times in microseconds - smaller is better ------------------------------------------------------------- Host OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw --------- ------------- ----- ------ ------ ------ ------ ------- ------- 51-fi Linux 2.5.51 1.180 7.8700 17.2 6.1600 98.0 14.4 103.8 51-pure Linux 2.5.51 1.190 7.5300 16.9 5.9600 95.6 16.8 103.1 *Local* Communication latencies in microseconds - smaller is better ------------------------------------------------------------------- Host OS 2p/0K Pipe AF UDP RPC/ TCP RPC/ TCP ctxsw UNIX UDP TCP conn --------- ------------- ----- ----- ---- ----- ----- ----- ----- ---- 51-fi Linux 2.5.51 1.180 6.949 15.3 27.4 49.4 86.5 91.9 133. 51-pure Linux 2.5.51 1.190 34.0 14.9 26.3 49.9 66.8 108.6 110. File & VM system latencies in microseconds - smaller is better -------------------------------------------------------------- Host OS 0K File 10K File Mmap Prot Page Create Delete Create Delete Latency Fault Fault --------- ------------- ------ ------ ------ ------ ------- ----- ----- 51-fi Linux 2.5.51 90.7 45.6 217.9 74.9 2492.0 1.519 3.00000 51-pure Linux 2.5.51 90.7 45.5 216.4 75.1 1995.0 0.966 2.00000 *Local* Communication bandwidths in MB/s - bigger is better ----------------------------------------------------------- Host OS Pipe AF TCP File Mmap Bcopy Bcopy Mem Mem UNIX reread reread (libc) (hand) read write --------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- ----- 51-fi Linux 2.5.51 369. 165. 44.6 446.2 557.5 242.2 175.7 557. 236.4 51-pure Linux 2.5.51 394. 164. 40.6 448.0 549.6 241.4 174.2 557. 235.7 Memory latencies in nanoseconds - smaller is better (WARNING - may not be correct, check graphs) --------------------------------------------------- Host OS Mhz L1 $ L2 $ Main mem Guesses --------- ------------- ---- ----- ------ -------- ------- 51-fi Linux 2.5.51 932 3.220 7.5140 100.8 51-pure Linux 2.5.51 932 3.220 7.5150 100.9 |
From: Wang, S. <sta...@in...> - 2002-12-17 00:42:24
|
Please see my comment :) > -----Original Message----- > From: Lynch, Rusty [mailto:rus...@in...] > Sent: 2002=E5=B9=B412=E6=9C=8817=E6=97=A5 1:22 > To: Zhuang, Louis; 'Rusty Lynch';=20 > fau...@so... > Subject: RE: [Fault-injection-developer] RE: [PATCH]Rewrite=20 > of fi_core.c u sing sysfs >=20 >=20 > > Louis said: > > I've some concerns, so fight me. :) > > * Sysfs is wonderful but backporting to kernel 2.4. Should we=20 > > never plan to > > use FITH in 2.4? >=20 > I think that by the time fith is ready for a stable kernel, > the kernel will be 2.6 which will contain sysfs. If for=20 > some reason somebody has an interest in backporting fi to > 2.4, then they will have to backport sysfs. >=20 > Everyday more and more components are moving in this > direction so I am confident somebody will backport sysfs. >=20 > > * fi_core should include not only sysfs code, but also some=20 > > general logic > > code. These logic functions are common among several=20 > > interceptors. So I'd > > like to move 'execute_trigger' code move trigger back to=20 > > fith_core.c and add > > 'corrupt' callback in 'struct trigger'=20 >=20 > I agree that the core is the proper location for putting > common (i.e. 'core') functionality that is exported for=20 > other code to use. >=20 > This doesn't explain why you want execute_trigger inside > the core. I would argue that each interceptor does not > want to execute a trigger in exactly the same way. =20 As you see, execute_trigger handles an intercepted event, and look up the wp table to decide how to injection fault. It will be need by all the other interceptor, IO/PCI config etc.=20 Why not we move it into fi_core.c and share it among all interceptors. -Stan >=20 > Could you further explain your position? >=20 > -rusty >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility=20 > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Lynch, R. <rus...@in...> - 2002-12-16 17:33:37
|
> Louis said: > I've some concerns, so fight me. :) > * Sysfs is wonderful but backporting to kernel 2.4. Should we > never plan to > use FITH in 2.4? I think that by the time fith is ready for a stable kernel, the kernel will be 2.6 which will contain sysfs. If for some reason somebody has an interest in backporting fi to 2.4, then they will have to backport sysfs. Everyday more and more components are moving in this direction so I am confident somebody will backport sysfs. > * fi_core should include not only sysfs code, but also some > general logic > code. These logic functions are common among several > interceptors. So I'd > like to move 'execute_trigger' code move trigger back to > fith_core.c and add > 'corrupt' callback in 'struct trigger' I agree that the core is the proper location for putting common (i.e. 'core') functionality that is exported for other code to use. This doesn't explain why you want execute_trigger inside the core. I would argue that each interceptor does not want to execute a trigger in exactly the same way. Could you further explain your position? -rusty |
From: Gao, K. <kev...@in...> - 2002-12-16 09:30:59
|
L M B E N C H 3 . 0 S U M M A R Y ------------------------------------ (Alpha software, do not distribute) Basic system parameters ---------------------------------------------------------------------------- -- Host OS Description Mhz tlb cache mem scal pages line par load bytes --------- ------------- ----------------------- ---- ----- ----- ------ ---- linux51-f Linux 2.5.51 i686-pc-linux-gnu 932 32 32 2.5200 1 linux51-p Linux 2.5.51 i686-pc-linux-gnu 932 32 32 2.6300 1 Processor, Processes - times in microseconds - smaller is better ---------------------------------------------------------------------------- -- Host OS Mhz null null open slct sig sig fork exec sh call I/O stat clos TCP inst hndl proc proc proc --------- ------------- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- linux51-f Linux 2.5.51 932 0.37 0.70 22.9 24.4 29.1 1.05 4.46 300. 1320 5533 linux51-p Linux 2.5.51 932 0.37 0.67 23.0 24.3 28.1 1.06 4.69 267. 1274 5293 Basic integer operations - times in nanoseconds - smaller is better ------------------------------------------------------------------- Host OS intgr intgr intgr intgr intgr bit add mul div mod --------- ------------- ------ ------ ------ ------ ------ linux51-f Linux 2.5.51 1.0700 1.0800 4.2900 41.9 45.1 linux51-p Linux 2.5.51 1.0700 1.0800 4.2900 41.9 45.1 Basic float operations - times in nanoseconds - smaller is better ----------------------------------------------------------------- Host OS float float float float add mul div bogo --------- ------------- ------ ------ ------ ------ linux51-f Linux 2.5.51 3.2200 5.3700 25.2 8.6300 linux51-p Linux 2.5.51 3.2200 5.3700 25.2 8.6300 Basic double operations - times in nanoseconds - smaller is better ------------------------------------------------------------------ Host OS double double double double add mul div bogo --------- ------------- ------ ------ ------ ------ linux51-f Linux 2.5.51 3.2200 5.3700 25.2 9.7100 linux51-p Linux 2.5.51 3.2200 5.3700 25.2 9.6900 Context switching - times in microseconds - smaller is better ------------------------------------------------------------------------- Host OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw ctxsw --------- ------------- ------ ------ ------ ------ ------ ------- ------- linux51-f Linux 2.5.51 0.9000 2.9300 2.3600 5.9600 80.1 12.5 99.5 linux51-p Linux 2.5.51 0.8200 2.8200 1.6000 5.3300 69.1 13.8 97.2 *Local* Communication latencies in microseconds - smaller is better --------------------------------------------------------------------- Host OS 2p/0K Pipe AF UDP RPC/ TCP RPC/ TCP ctxsw UNIX UDP TCP conn --------- ------------- ----- ----- ---- ----- ----- ----- ----- ---- linux51-f Linux 2.5.51 0.900 6.906 15.1 42.4 53.3 81.1 91.5 112. linux51-p Linux 2.5.51 0.820 6.888 15.4 26.7 61.3 80.4 108.3 133. File & VM system latencies in microseconds - smaller is better ---------------------------------------------------------------------------- --- Host OS 0K File 10K File Mmap Prot Page 100fd Create Delete Create Delete Latency Fault Fault selct --------- ------------- ------ ------ ------ ------ ------- ----- ------- ----- linux51-f Linux 2.5.51 90.9 45.6 278.4 77.3 2262.0 1.461 3.25490 20.0 linux51-p Linux 2.5.51 91.5 46.4 231.1 77.9 1731.0 0.944 2.62660 20.0 *Local* Communication bandwidths in MB/s - bigger is better ---------------------------------------------------------------------------- - Host OS Pipe AF TCP File Mmap Bcopy Bcopy Mem Mem UNIX reread reread (libc) (hand) read write --------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- ----- linux51-f Linux 2.5.51 490. 165. 37.5 449.5 557.6 250.1 205.1 557. 242.8 linux51-p Linux 2.5.51 529. 93.1 38.4 446.5 557.6 251.2 201.1 557. 240.0 Memory latencies in nanoseconds - smaller is better (WARNING - may not be correct, check graphs) ------------------------------------------------------------------ Host OS Mhz L1 $ L2 $ Main mem Guesses --------- ------------- --- ---- ---- -------- ------- linux51-f Linux 2.5.51 932 3.2200 7.5320 102.3 linux51-p Linux 2.5.51 932 3.2200 7.5210 102.1 make[1]: Leaving directory `/root/lmbench-3.0-a2/results' |
From: Zhuang, L. <lou...@in...> - 2002-12-16 09:06:43
|
I've some concerns, so fight me. :) * Sysfs is wonderful but backporting to kernel 2.4. Should we never plan to use FITH in 2.4? * fi_core should include not only sysfs code, but also some general logic code. These logic functions are common among several interceptors. So I'd like to move 'execute_trigger' code move trigger back to fith_core.c and add 'corrupt' callback in 'struct trigger' -----Original Message----- From: Rusty Lynch [mailto:ru...@st...] Sent: Monday, December 16, 2002 2:38 PM To: fau...@so... Subject: [Fault-injection-developer] [PATCH]Rewrite of fi_core.c using sysfs As I mentioned in a previous email, I was hacking around with some alternative approaches to the core functionality for fault injection, and ended up making a complete rewrite of fi_core.c. This was actually my second attempt, since the first avenue I went down ended turning more complicated then I believe fault injection warrants. The code is still pretty preliminary, but I wanted to get it out for review before I gave up for the night, and since the second half of tomorrow will be taken up with the opening of the new Star Trek flick... then maybe somebody will have a chance to run with this idea. Why I felt we needed an overhaul of fi_core.c --------------------------------------------- 1. When I read through fi_core.c, I notice that there are a lot of assumptions about what a given interceptor is doing (specifically the mmio interceptor in arch/i386/fi/pf/*). We already have volunteers to implement other interceptors that are described in the high level design documentation, but until we get better model for plugging new interceptors into the core fault injection functionality then life will get very complicated. 2. Anytime I look at a block of kernel code I ask 'is there some way this can be done in user space?'. The high level design papers describe a model where faults (or triggers) are grouped into fault sets. I have no problem with that type of design, but since a given trigger has no need to know about sibling triggers, then this should be information kept in user space. The below implementation implements triggers that expose everything there is to know about themselves to user space via sysfs. With this kind of information user space can keep track of what triggers are associated with what fault set. 3. Ever since I discovered the elegance of the new kobject model for dealing with data in the kernel, I have tried to utilize that model where ever possible. I moved the core functionality to use this model instead of using the fixed size block of data that existed before. I feel this makes the code easier to read, very easy to expose data to user space via sysfs, and allows us to piggy back on one of the most utilized subsystems in the kernel. We no longer have the need for exposing an ioctl interface since all interaction happens via sysfs. Here is an example: when I boot a system with fault injection enabled and mount sysfs on /sysfs/, then I can see ==> # NOTE: All of this is without the aid of a tool. The existing # ficl tool could be tweaked to expose the same interface # to the user (i.e. the manual is still correct), but be # implemented by reading/write to files in sysfs $ tree /sysfs/fault_injection /sysfs/fault_injection/ |-- debug |-- enabled |-- interceptors | `-- pf_interceptor `-- triggers `-- ctl From this I can see that I have one interceptor named pf_interceptor and not triggers inserted. If I want to enable extra debugging information the I ==> $ cat "1" > /sysfs/fault_injection/debug By default fault injection is disabled at startup. I can enable it by ==> $ cat "1" > /sysfs/fault_injection/enabled Adding and removing triggers happens by writing commands to triggers/ctl. To add a trigger ==> # documentation about what each field is for is documented in the code $echo "add test1 MMIO 1 1 1 1 10 1 1 1 1 1 1 1" > \ /sysfs/fault_injection/triggers/ctl I could then see the trigger represented in sysfs by ==> $ tree /sysfs/fault_injection /sysfs/fault_injection/ |-- debug |-- enabled |-- interceptors | `-- pf_interceptor `-- triggers |-- ctl `-- test1 |-- bitmask |-- count |-- hertz |-- max |-- min |-- opcode |-- operand |-- protection |-- registered |-- skip |-- stop |-- type `-- wp And then inspect what ever I wanted, like ==> $ cat /sysfs/fault_injection/triggers/test1/type MMIO To remove the trigger ==> $ echo "del test1" > /sysfs/fault_injection/triggers/ctl Hopefully you get the idea. The possibilities are endless. New model for plugging interceptors into fault injection -------------------------------------------------------- When an interceptor is initialized, it registers with the fi_core.c by: creating an interceptor object which is a kobject, and then passing that object to fi_core.c by calling ==> int fi_register_interceptor(struct interceptor *); One of the fields in a trigger indicates what type of interceptor it is designed for. When a trigger is registered for a INTERCEPTOR_TYPE_MMIO type of interceptor, the trigger will arm itself with all appropriate interceptors by calling the 'arm' callback inside the interceptor object. This is same idea as fi_core.c calling fi_pf_register(), but doesn't require fi_core.c to know about the pf implementation of a mmio interceptor ahead of time. When a trigger is removed, fi_core.c calls the 'disarm' callback also contained in the interceptor object passed to fi_core.c during registration. The code has still got some major holes, but it compiles and fundamental operations can be done via cat and echo on the command line. Since this is a complete rewrite of fi_core.c, I am sending the entire file for browsing, and then also sending a diff against the bk tree. These files can also be found at http//fault-injection.sf.net/rustyl/ --rustyl /*************************************************************************** *** * Fault Injection Core Functionality * Copyright (C) Intel Crop. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **************************************************************************** ** * * This is a rewrite of code originally submitted by * Louis Zhuang <lou...@in...>. I have moved the code from * a ioctl based control using proc to expose information about * fault injection data that was contained in fixed sized tables, * to an extendable kobject based implementation that uses sysfs * for all user space access. * --rustyl * * Contributors: * Louis Zhuang <lou...@in...> * Stanley Wang <sta...@in...> * Rusty Lynch <ru...@li...> */ #include <linux/module.h> #include <linux/init.h> #include <linux/kprobes.h> #include <linux/slab.h> #include <linux/kobject.h> #define PREFIX_NAME "FI" #include <linux/fi/fi.h> #include <linux/fi.h> #ifdef CONFIG_FI_DEBUG #define dbg(format, arg...) \ do { \ if(fi_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ __FUNCTION__, ## arg); \ } while(0) #else #define dbg(format, art...) #endif #define err(format, arg...) \ printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ## arg) #define info(format, arg...) \ printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ## arg) #define warn(format, arg...) \ printk(KERN_WARNING "%s: " format "\n", __FUNCTION__ , ## arg) static DECLARE_MUTEX(fi_sem); static struct subsystem fi_subsys; static struct subsystem trigger_subsys; static struct subsystem interceptor_subsys; static int is_initialized = 0; int fault_injection_enabled = 0; static int fi_debug = 1; int fi_register_interceptor(struct interceptor *); struct trigger_attribute { struct attribute attr; ssize_t (*show)(struct trigger *,char *,size_t,loff_t); }; static struct trigger_attribute trigger_attr_wp; static struct trigger_attribute trigger_attr_bitmask; static struct trigger_attribute trigger_attr_min; static struct trigger_attribute trigger_attr_max; static struct trigger_attribute trigger_attr_skip; static struct trigger_attribute trigger_attr_stop; static struct trigger_attribute trigger_attr_protection; static struct trigger_attribute trigger_attr_hertz; static struct trigger_attribute trigger_attr_registered; static struct trigger_attribute trigger_attr_opcode; static struct trigger_attribute trigger_attr_operand; static struct trigger_attribute trigger_attr_count; static struct trigger_attribute trigger_attr_type; static inline void create_trigger_files(struct trigger *t) { sysfs_create_file(&t->kobj, &trigger_attr_wp.attr); sysfs_create_file(&t->kobj, &trigger_attr_bitmask.attr); sysfs_create_file(&t->kobj, &trigger_attr_min.attr); sysfs_create_file(&t->kobj, &trigger_attr_max.attr); sysfs_create_file(&t->kobj, &trigger_attr_skip.attr); sysfs_create_file(&t->kobj, &trigger_attr_stop.attr); sysfs_create_file(&t->kobj, &trigger_attr_protection.attr); sysfs_create_file(&t->kobj, &trigger_attr_hertz.attr); sysfs_create_file(&t->kobj, &trigger_attr_registered.attr); sysfs_create_file(&t->kobj, &trigger_attr_opcode.attr); sysfs_create_file(&t->kobj, &trigger_attr_operand.attr); sysfs_create_file(&t->kobj, &trigger_attr_count.attr); sysfs_create_file(&t->kobj, &trigger_attr_type.attr); } static inline void remove_trigger_files(struct trigger *t) { sysfs_remove_file(&t->kobj, &trigger_attr_wp.attr); sysfs_remove_file(&t->kobj, &trigger_attr_bitmask.attr); sysfs_remove_file(&t->kobj, &trigger_attr_min.attr); sysfs_remove_file(&t->kobj, &trigger_attr_max.attr); sysfs_remove_file(&t->kobj, &trigger_attr_skip.attr); sysfs_remove_file(&t->kobj, &trigger_attr_stop.attr); sysfs_remove_file(&t->kobj, &trigger_attr_protection.attr); sysfs_remove_file(&t->kobj, &trigger_attr_hertz.attr); sysfs_remove_file(&t->kobj, &trigger_attr_registered.attr); sysfs_remove_file(&t->kobj, &trigger_attr_opcode.attr); sysfs_remove_file(&t->kobj, &trigger_attr_operand.attr); sysfs_remove_file(&t->kobj, &trigger_attr_count.attr); sysfs_remove_file(&t->kobj, &trigger_attr_type.attr); } static inline ssize_t add_trigger(struct trigger *t) { struct list_head * entry; struct interceptor * i; struct trigger *n; n = kmalloc(sizeof(struct trigger),GFP_KERNEL); if (!n) return -ENOMEM; memset(n,0,sizeof(struct trigger)); kobject_init(&n->kobj); strncpy(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN); n->kobj.subsys = &trigger_subsys; n->wp.addr = t->wp.addr; n->wp.type = t->wp.type; n->bitmask = t->bitmask; n->min = t->min; n->max = t->max; n->skip = t->skip; n->stop = t->stop; n->protection = t->protection; n->hertz = t->hertz; n->registered = t->registered; n->opcode = t->opcode; n->operand = t->operand; n->type = t->type; atomic_set(&n->count, 0); if (kobject_register(&n->kobj)) { err("Unable to register kobject"); return -EINVAL; } create_trigger_files(n); list_for_each(entry,&interceptor_subsys.list) { i = to_interceptor(entry); if (i->type == n->type) { (i->arm)(n); } } return 0; } static inline ssize_t del_trigger(struct trigger *t) { struct list_head * entry; struct trigger * n; list_for_each(entry,&trigger_subsys.list) { n = to_trigger(entry); if (!strncmp(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN)) { dbg("comparing %s to %s", n->kobj.name, t->kobj.name); remove_trigger_files(n); kobject_unregister(&n->kobj); return 0; } } err("trigger %s does not exist", t->kobj.name); return -EINVAL; } /* * =========================================================== * <>-- Toplevel Containing Subsystem (fi_subsys) --<> * ----------------------------------------------------------- */ static ssize_t fi_enabled_show(struct subsystem * s, char * page, size_t count, loff_t off) { return off ? 0 : snprintf(page,count,"%i\n",fault_injection_enabled); } static ssize_t fi_enabled_store(struct subsystem * s, const char * page, size_t count, loff_t off) { int tmp = 0; int num; int ret = 0; int error = 0; down(&fi_sem); if (off) goto Done; num = sscanf(page,"%i",&tmp); if (!num) { error = -EINVAL; goto Done; } if (tmp) { fault_injection_enabled = 1; } else { fault_injection_enabled = 0; } ret = error ? error : count; Done: up(&fi_sem); return ret; } static ssize_t fi_debug_show(struct subsystem * s, char * page, size_t count, loff_t off) { return off ? 0 : snprintf(page,count,"%i\n",fi_debug); } static ssize_t fi_debug_store(struct subsystem * s, const char * page, size_t count, loff_t off) { int tmp = 0; int num; int ret = 0; int error = 0; down(&fi_sem); if (off) goto Done; num = sscanf(page,"%i",&tmp); if (!num) { error = -EINVAL; goto Done; } if (tmp) { fi_debug = 1; } else { fi_debug = 0; } ret = error ? error : count; Done: up(&fi_sem); return ret; } static struct subsystem fi_subsys = { .kobj = { .name = "fault_injection" }, }; static struct subsys_attribute fi_subsys_attr_enabled = { .attr = { .name = "enabled", .mode = 0644 }, .show = fi_enabled_show, .store = fi_enabled_store, }; static struct subsys_attribute fi_subsys_attr_debug = { .attr = { .name = "debug", .mode = 0644 }, .show = fi_debug_show, .store = fi_debug_store, }; /* * =============================================================== * <>-- Interceptor Containing Subsystem (interceptor_subsys) --<> * --------------------------------------------------------------- */ static struct subsystem interceptor_subsys = { .kobj = { .name = "interceptors" }, .parent = &fi_subsys, }; /* * =========================================================== * <>-- Trigger Subsystem (trigger_subsys) --<> * ----------------------------------------------------------- */ static ssize_t trigger_attr_show(struct kobject * kobj, struct attribute * attr, char * page, size_t count, loff_t off) { struct trigger * n = container_of(kobj,struct trigger,kobj); struct trigger_attribute * trigger_attr = container_of(attr,struct trigger_attribute,attr); dbg("about to call show function for %s", trigger_attr->attr.name); return trigger_attr->show ? trigger_attr->show(n,page,count,off) : 0; } static ssize_t trigger_wp_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("wp.addr = %#lx, wp.type = %#x", p->wp.addr, p->wp.type); return off ? 0 : snprintf(page,count,"%#lx %#x\n", p->wp.addr,p->wp.type); } static struct trigger_attribute trigger_attr_wp = { .attr = { .name = "wp", .mode = S_IRUGO }, .show = trigger_wp_read, }; static ssize_t trigger_bitmask_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("bitmask = %#x", p->bitmask); return off ? 0 : snprintf(page,count,"%#x\n",p->bitmask); } static struct trigger_attribute trigger_attr_bitmask = { .attr = { .name = "bitmask", .mode = S_IRUGO }, .show = trigger_bitmask_read, }; static ssize_t trigger_min_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("min = %i", p->min); return off ? 0 : snprintf(page,count,"%i\n",p->min); } static struct trigger_attribute trigger_attr_min = { .attr = { .name = "min", .mode = S_IRUGO }, .show = trigger_min_read, }; static ssize_t trigger_max_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("max = %i", p->max); return off ? 0 : snprintf(page,count,"%i\n",p->max); } static struct trigger_attribute trigger_attr_max = { .attr = { .name = "max", .mode = S_IRUGO }, .show = trigger_max_read, }; static ssize_t trigger_skip_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("skip = %i", p->skip); return off ? 0 : snprintf(page,count,"%i\n",p->skip); } static struct trigger_attribute trigger_attr_skip = { .attr = { .name = "skip", .mode = S_IRUGO }, .show = trigger_skip_read, }; static ssize_t trigger_stop_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("stop = %i", p->stop); return off ? 0 : snprintf(page,count,"%i\n",p->stop); } static struct trigger_attribute trigger_attr_stop = { .attr = { .name = "stop", .mode = S_IRUGO }, .show = trigger_stop_read, }; static ssize_t trigger_protection_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("protection = %i", p->protection); return off ? 0 : snprintf(page,count,"%i\n",p->protection); } static struct trigger_attribute trigger_attr_protection = { .attr = { .name = "protection", .mode = S_IRUGO }, .show = trigger_protection_read, }; static ssize_t trigger_hertz_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("hertz = %i", p->hertz); return off ? 0 : snprintf(page,count,"%i\n",p->hertz); } static struct trigger_attribute trigger_attr_hertz = { .attr = { .name = "hertz", .mode = S_IRUGO }, .show = trigger_hertz_read, }; static ssize_t trigger_registered_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("registered = %i", p->registered); return off ? 0 : snprintf(page,count,"%i\n",p->registered); } static struct trigger_attribute trigger_attr_registered = { .attr = { .name = "registered", .mode = S_IRUGO }, .show = trigger_registered_read, }; static ssize_t trigger_count_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("count = %i", atomic_read(&p->count)); return off ? 0 : snprintf(page,count,"%i\n",atomic_read(&p->count)); } static struct trigger_attribute trigger_attr_count = { .attr = { .name = "count", .mode = S_IRUGO }, .show = trigger_count_read, }; static ssize_t trigger_type_read(struct trigger * p, char * page, size_t count, loff_t off) { int rv; dbg("type = %i", p->type); if (off) return 0; switch (p->type) { case INTERCEPTOR_TYPE_MMIO: rv = snprintf(page,count,"MMIO\n"); break; default: rv = snprintf(page,count,"UNKNOWN\n"); } return rv; } static struct trigger_attribute trigger_attr_type = { .attr = { .name = "type", .mode = S_IRUGO }, .show = trigger_type_read, }; static ssize_t trigger_opcode_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("opcode = %i", p->opcode); return off ? 0 : snprintf(page,count,"%i\n",p->opcode); } static struct trigger_attribute trigger_attr_opcode = { .attr = { .name = "opcode", .mode = S_IRUGO }, .show = trigger_opcode_read, }; static ssize_t trigger_operand_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("operand = %i", p->operand); return off ? 0 : snprintf(page,count,"%i\n",p->operand); } static struct trigger_attribute trigger_attr_operand = { .attr = { .name = "operand", .mode = S_IRUGO }, .show = trigger_operand_read, }; static ssize_t trigger_ctl_show(struct subsystem * s, char * page, size_t count, loff_t off) { return 0; } static ssize_t trigger_ctl_store(struct subsystem * s, const char * page, size_t count, loff_t off) { char ctl[16]; char type[16]; int num; int error; int ret = 0; struct trigger tmp; if (off) return 0; /* 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 */ /* ctl nm tp wa wb bm mn mx sk st pt hz rg oc oa */ num = sscanf(page,"%15s %s %s %lx %x %x %i %i %i %i %i %i %i %i %i", ctl, /* 3 */ tmp.kobj.name, /* 4 */ type, /* 5 */ &tmp.wp.addr, /* 6 */ &tmp.wp.type, /* 7 */ &tmp.bitmask, /* 8 */ &tmp.min, /* 9 */ &tmp.max, /* 10 */ &tmp.skip, /* 11 */ &tmp.stop, /* 12 */ &tmp.protection, /* 13 */ &tmp.hertz, /* 14 */ &tmp.registered, /* 15 */ (int *)&tmp.opcode, /* 16 */ &tmp.operand); /* 17 */ if (!num) { err("Invalid command format, translated no commands"); error = -EINVAL; goto Done; } dbg("type = '%s'", type); if (!strncmp(type, "MMIO", 4)) tmp.type = INTERCEPTOR_TYPE_MMIO; else tmp.type = INTERCEPTOR_TYPE_UNKNOWN; if (!strcmp(ctl,"add") && num == 15) error = add_trigger(&tmp); else if (!strcmp(ctl,"del") && num == 2) error = del_trigger(&tmp); else { err("Invalid command format: %s, %i tokens found",ctl,num); error = -EINVAL; } ret = error ? error : count; Done: return ret; } static struct subsys_attribute trigger_subsys_attr_ctl = { .attr = { .name = "ctl", .mode = 0644 }, .show = trigger_ctl_show, .store = trigger_ctl_store, }; static struct sysfs_ops trigger_sysfs_ops = { .show = trigger_attr_show, }; static struct subsystem trigger_subsys = { .kobj = { .name = "triggers" }, .sysfs_ops = &trigger_sysfs_ops, .parent = &fi_subsys, }; static int __init fi_init(void){ down(&fi_sem); if (is_initialized) { dbg("alreading initialized... exiting"); goto Done; } dbg("initializing fault injection core"); subsystem_register(&fi_subsys); subsys_create_file(&fi_subsys,&fi_subsys_attr_debug); subsys_create_file(&fi_subsys,&fi_subsys_attr_enabled); subsystem_register(&interceptor_subsys); subsystem_register(&trigger_subsys); subsys_create_file(&trigger_subsys,&trigger_subsys_attr_ctl); is_initialized++; Done: up(&fi_sem); return 0; }; int fi_register_interceptor(struct interceptor *i) { /* * If an interceptor is able to initialize * before we are then do our own initialization * before going on */ if (!is_initialized) fi_init(); dbg("registering interceptor %s", i->kobj.name); i->kobj.subsys = &interceptor_subsys; kobject_init(&i->kobj); return kobject_register(&i->kobj); } /* Is there a better way to get my init code to execute on startup? */ module_init(fi_init); EXPORT_SYMBOL_GPL(fault_injection_enabled); EXPORT_SYMBOL_GPL(fi_register_interceptor); MODULE_PARM(fi_debug, "i"); MODULE_PARM_DESC(fi_debug, "Debugging mode enabled or not"); # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.879 -> 1.880 # arch/i386/kernel/fi/pf/pf.c 1.6 -> 1.7 # kernel/Makefile 1.25 -> 1.26 # kernel/fi_core.c 1.6 -> 1.7 # (new) -> 1.1 include/linux/fi.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/15 ru...@st... 1.880 # This changeset includes a complete rewrite of fi_core.c, a new # header file infavor of the include/linux/fi/ going away, and a new # model for interfacing between interceptors and the core fault injection # routines. # # -------------------------------------------- # diff -Nru a/arch/i386/kernel/fi/pf/pf.c b/arch/i386/kernel/fi/pf/pf.c --- a/arch/i386/kernel/fi/pf/pf.c Sun Dec 15 21:33:50 2002 +++ b/arch/i386/kernel/fi/pf/pf.c Sun Dec 15 21:33:50 2002 @@ -51,6 +51,7 @@ #include <asm/pgalloc.h> #include <asm/io.h> #include <asm/tlbflush.h> +#include <linux/random.h> #include <asm/fi.h> @@ -58,6 +59,7 @@ #include <linux/fi/fi.h> #include <linux/fi/fi_interface.h> #include <linux/fi/fi_internal.h> +#include <linux/fi.h> #include "fi_pf.h" @@ -67,14 +69,105 @@ static struct{ int page_index; struct watchpoint wp; - int id; - struct intercept_hook * hook; + struct trigger * trigger; }wp_tb[MAX_WP] = { [0 ... MAX_WP-1] = { wp: {0,0}, - id: -1, - hook: NULL } + trigger: NULL } }; +/** + * This is a KEY data structure. When interceptor triggers DM + * and then DM call iAction method. iAction remembers this corrupted data. + * Then DM returns to Interceptor and Interceptor returns corrupted data + * to intercepted access. + */ +struct fi_corrupt{ + __u32 corrupted_data; +}; + +static inline void execute_trigger(struct trigger *t, __u32 val, + int len, int type, void *data) +{ + int tmp = 0; + + if (!t) { + PERROR("Unable to execute null trigger\n"); + goto exit; + } + + get_random_bytes(&tmp, sizeof(tmp)); + if (t->hertz==0) {t->hertz=1;};//divid is not 0! + if (tmp >= 0xFFFFFFFF/t->hertz){ + PDEBUG("rnd=%d, HERZ=%d\n", tmp, t->hertz); + goto exit; + } + + tmp = val & (~t->bitmask); + if (t->min>tmp || tmp>=t->max){ + PDEBUG("min=%d, max=%d, val=%d\n", t->min, t->max, val); + if(!(t->min==0 && t->max==0)) + goto exit; + } + + // Increase count only when passing all conditions + atomic_inc(&t->count); + + if (t->skip >= atomic_read(&t->count)){ + PDEBUG("count=%d, skip=%d\n", atomic_read(&t->count), t->skip); + goto exit; + } + + if ( t->stop!=0 && (t->stop < (atomic_read(&t->count)-t->skip)) ) { + PDEBUG("count=%d, stop=%d\n", atomic_read(&t->count), t->stop); + goto exit; + } + + PDEBUG("count=%d, skip=%d, min=%d, max=%d, val=%d\n", + atomic_read(&t->count), t->skip, t->min, t->max, val); + tmp = val; + switch (t->opcode){ + case FI_NOTHING: + goto exit_for; + case FI_SET: + tmp = t->operand; + break; + case FI_AND: + tmp &= t->operand; + break; + case FI_OR: + tmp |= t->operand; + break; + case FI_NOT: + tmp = ~tmp; + break; + case FI_XOR: + tmp ^= t->operand; + break; + case FI_NAND: + tmp = ~(tmp & t->operand); + break; + case FI_NOR: + tmp = ~(tmp | t->operand); + break; + case FI_ADD: + tmp = tmp + t->operand; + break; + case FI_SUB: + tmp = tmp - t->operand; + break; + default: + PERROR("Not recognized opcode%d\n", t->opcode); + break; + } + + exit_for: + val = (val & (t->protection)) | (tmp & (~t->protection)); + + exit: + ((struct fi_corrupt *)data)->corrupted_data = val; + return; +} + static void fi_do_flush_tlb_ipi(void* addr) { __flush_tlb_one(addr); }; @@ -85,7 +178,8 @@ __flush_tlb_one(addr); }; -int fi_pf_register(struct watchpoint wp, int id, struct intercept_hook *hook){ +int fi_pf_register(struct watchpoint wp, struct trigger *trigger) +{ unsigned long flags; int wi=0; //watchpoint index int ri=0; //region index @@ -93,8 +187,8 @@ unsigned long addr; /* Make sure that wp is vaild */ - if ( hook==NULL ) { - PERROR("Reason: %s\n", "/* There are no callback */"); + if ( trigger==NULL ) { + PERROR("Reason: %s\n", "/* There are no trigger */"); return -EFI_INVALID; } if ( wp.type& (~FI_WPTYPE_ALL_MASK) ) { @@ -113,9 +207,10 @@ /* Make sure there are no the same wp or id */ for (wi=0; wi<MAX_WP; wi++) { - if (wp_tb[wi].hook==NULL) continue; - if ((id==wp_tb[wi].id) || (addr==wp_tb[wi].wp.addr)) { - PERROR("Reason: %s\n", "/* there are same wp or id */"); + if (wp_tb[wi].trigger==NULL) continue; + if ((trigger==wp_tb[wi].trigger) || (addr==wp_tb[wi].wp.addr)){ + PERROR("Reason: %s\n", + "/* there are same wp or trigger */"); rv = -EFI_REGISTERED; goto err; } @@ -129,7 +224,7 @@ /* find empty item in wp_tb */ for (wi=0; wi<MAX_WP; wi++){ - if (wp_tb[wi].hook==NULL){ + if (wp_tb[wi].trigger==NULL){ break; } } @@ -142,12 +237,8 @@ /* register this wp into wp_tb*/ wp_tb[wi].wp.addr = addr; wp_tb[wi].wp.type = wp.type; - wp_tb[wi].id = id; - wp_tb[wi].hook = hook; + wp_tb[wi].trigger = trigger; - PDEBUG("register WP: index=%d, addr=0X%#lx, type=0x%x, id=%d, hook=0x%p\n", - wi, wp_tb[wi].wp.addr, wp_tb[wi].wp.type, - wp_tb[wi].id, wp_tb[wi].hook); err: pf_unlock_region_irqrestore(flags); fi_flush_tlb_all((unsigned long)addr); @@ -155,7 +246,7 @@ }; -int fi_pf_unregister(int id) { +int fi_pf_unregister(struct trigger *t) { unsigned long flags; int wi=0; int ri=0; @@ -165,7 +256,7 @@ /* find the id */ for (wi=0; wi<MAX_WP; wi++) { - if (wp_tb[wi].hook!=NULL && wp_tb[wi].id == id) { + if (wp_tb[wi].trigger == t) { break; } } @@ -183,8 +274,7 @@ wp_tb[wi].wp.addr = 0; wp_tb[wi].wp.type = 0; - wp_tb[wi].id = -1; - wp_tb[wi].hook = 0; + wp_tb[wi].trigger = 0; err: pf_unlock_region_irqrestore(flags); @@ -192,16 +282,6 @@ }; -/** - * This is a KEY data structure. When interceptor triggers DM - * and then DM call iAction method. iAction remembers this corrupted data. - * Then DM returns to Interceptor and Interceptor returns corrupted data - * to intercepted access. - */ -struct fi_corrupt{ - __u32 corrupted_data; -}; - int fi_pf_corrupt(int id, __u32 dirty, void *data){ ((struct fi_corrupt *)data)->corrupted_data = dirty; return 0; @@ -212,7 +292,7 @@ int i=0; for (i=0; i<MAX_WP; i++) { - if (wp_tb[i].hook == NULL) continue; + if (wp_tb[i].trigger == NULL) continue; if (addr == (unsigned long)wp_tb[i].wp.addr) { break; } @@ -235,12 +315,16 @@ static unsigned long crpt_mask[] = { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF}; +extern int fault_injection_enabled; int fi_page_fault(struct pt_regs * regs, unsigned long address) { unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int i; int ins_len, crpt_len; - + + if (!fault_injection_enabled) + return 0; + pf_lock_region(); //lock it! if (pf_find_region(address)<0) { if (pf_is_removed_regions(address)) { @@ -287,9 +371,8 @@ WP_LEN(wp_tb[i].wp):ins_len; crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; - (wp_tb[i].hook->trigger)( wp_tb[i].id, crpt.corrupted_data, - crpt_len, 0, &crpt); - + execute_trigger(wp_tb[i].trigger, crpt.corrupted_data, + crpt_len, 0, &crpt); set_ins_reg_val(pf_reason[cpu].eip, regs, (crpt.corrupted_data&crpt_mask[crpt_len-1]) | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); @@ -305,10 +388,10 @@ crpt_len = (WP_LEN(wp_tb[i].wp)<ins_len)? WP_LEN(wp_tb[i].wp):ins_len; - crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; - (wp_tb[i].hook->trigger)( wp_tb[i].id, crpt.corrupted_data, - crpt_len, 0, &crpt); - + crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; + execute_trigger(wp_tb[i].trigger, crpt.corrupted_data, + crpt_len, 0, &crpt); + set_ins_imm_val(pf_reason[cpu].eip, (crpt.corrupted_data&crpt_mask[crpt_len-1]) | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); @@ -346,6 +429,9 @@ unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int ins_len, crpt_len; + + if (!fault_injection_enabled) + return 0; /* * DProbes make do_debug disallow irq. So we are safty from irq now. @@ -383,9 +469,9 @@ crpt_len = (WP_LEN(wp_tb[pf_reason[cpu].index].wp)<ins_len)? WP_LEN(wp_tb[pf_reason[cpu].index].wp):ins_len; crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; - (wp_tb[pf_reason[cpu].index].hook->trigger)( - wp_tb[pf_reason[cpu].index].id, crpt.corrupted_data, - crpt_len, 0, &crpt); + //(wp_tb[pf_reason[cpu].index].hook->trigger)( + //wp_tb[pf_reason[cpu].index].id, crpt.corrupted_data, + //crpt_len, 0, &crpt); set_ins_reg_val(pf_reason[cpu].eip, regs, (crpt.corrupted_data&crpt_mask[crpt_len-1]) @@ -417,11 +503,35 @@ return 0; }; +static void pf_arm(struct trigger *t) +{ + PDEBUG("arming %s trigger\n", t->kobj.name); + fi_pf_register(t->wp, t); +} + +static void pf_disarm(struct trigger *t) +{ + PDEBUG("disarming %s trigger\n", t->kobj.name); +} + +static struct interceptor pf_interceptor = { + .kobj = {.name = "pf_interceptor"}, + .type = INTERCEPTOR_TYPE_MMIO, + .arm = &pf_arm, + .disarm = &pf_disarm +}; + +extern int fi_register_interceptor(struct interceptor *); +static int __init pf_init(void) +{ + return fi_register_interceptor(&pf_interceptor); +} EXPORT_SYMBOL_NOVERS(fi_pf_register); EXPORT_SYMBOL_NOVERS(fi_pf_unregister); EXPORT_SYMBOL_NOVERS(fi_pf_corrupt); +module_init(pf_init); MODULE_AUTHOR("Louis Zhuang"); MODULE_DESCRIPTION("Pagefault interceptor component for FI"); diff -Nru a/include/linux/fi.h b/include/linux/fi.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/fi.h Sun Dec 15 21:33:50 2002 @@ -0,0 +1,56 @@ +#ifndef _FAULT_INJECTION_H +#define _FAULT_INJECTION_H +#if defined(__KERNEL__) + +#include <linux/kobject.h> +#include <linux/fi/fi.h> + +#define to_trigger(entry) container_of(entry,struct trigger,kobj.entry); +#define to_interceptor(entry)container_of(entry,struct interceptor,kobj.entry); + +typedef enum +{ + TRIGGER_OPCODE_NOTHING=0, + TRIGGER_OPCODE_SET=1, + TRIGGER_OPCODE_AND=2, + TRIGGER_OPCODE_OR=3, + TRIGGER_OPCODE_NOT=4, + TRIGGER_OPCODE_XOR=5, + TRIGGER_OPCODE_NAND=6, + TRIGGER_OPCODE_NOR=7, + TRIGGER_OPCODE_ADD=8, + TRIGGER_OPCODE_SUB=9, +} trigger_opcode_t; + +typedef enum +{ + INTERCEPTOR_TYPE_UNKNOWN=0, + INTERCEPTOR_TYPE_MMIO=1 +} interceptor_type_t; + +struct trigger { + struct watchpoint wp; + __u32 bitmask; + int min; + int max; + int skip; + int stop; + int protection; + int hertz; + int registered; + trigger_opcode_t opcode; + int operand; + atomic_t count; + interceptor_type_t type; + struct kobject kobj; +}; + +struct interceptor { + interceptor_type_t type; + void (*arm) (struct trigger *); + void (*disarm) (struct trigger *); + struct kobject kobj; +}; + +#endif /* __KERNEL__ */ +#endif /* _FAULT_INJECTION_H */ diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Sun Dec 15 21:33:50 2002 +++ b/kernel/Makefile Sun Dec 15 21:33:50 2002 @@ -4,7 +4,7 @@ export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ printk.o platform.o suspend.o dma.o module.o cpufreq.o \ - profile.o rcupdate.o intermodule.o kprobes.o + profile.o rcupdate.o intermodule.o kprobes.o fi_core.o obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ exit.o itimer.o time.o softirq.o resource.o \ diff -Nru a/kernel/fi_core.c b/kernel/fi_core.c --- a/kernel/fi_core.c Sun Dec 15 21:33:50 2002 +++ b/kernel/fi_core.c Sun Dec 15 21:33:50 2002 @@ -1,5 +1,6 @@ + /*************************************************************************** *** - * Fault Injection Test harness (FI) + * Fault Injection Core Functionality * Copyright (C) Intel Crop. * * This program is free software; you can redistribute it and/or @@ -17,508 +18,577 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **************************************************************************** ** + * + * This is a rewrite of code originally submitted by + * Louis Zhuang <lou...@in...>. I have moved the code from + * a ioctl based control using proc to expose information about + * fault injection data that was contained in fixed sized tables, + * to an extendable kobject based implementation that uses sysfs + * for all user space access. + * --rustyl + * + * Contributors: + * Louis Zhuang <lou...@in...> + * Stanley Wang <sta...@in...> + * Rusty Lynch <ru...@li...> */ -/* $Id: dm_core.c,v 1.3 2002/11/14 07:11:37 brlock Exp $ - * Copyright by Intel Crop., 2002 - * Louis Zhuang (lou...@in...) - */ -/** - * @file dm_core.c - */ - -#include <linux/config.h> -#include <linux/version.h> - -#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/version.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/atomic.h> -#include <asm/debugreg.h> -#include <asm/desc.h> -#include <linux/ioport.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <linux/sched.h> -#include <asm/system.h> -#include <linux/vmalloc.h> -#include <linux/proc_fs.h> -#include <linux/random.h> -#include <linux/highmem.h> #include <linux/kprobes.h> +#include <linux/slab.h> +#include <linux/kobject.h> #define PREFIX_NAME "FI" #include <linux/fi/fi.h> -#include <linux/fi/fi_internal.h> -#include <linux/fi/fi_interface.h> +#include <linux/fi.h> -#define MAX_MOD 16 +#ifdef CONFIG_FI_DEBUG +#define dbg(format, arg...) \ + do { \ + if(fi_debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + __FUNCTION__, ## arg); \ + } while(0) +#else +#define dbg(format, art...) +#endif +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format "\n", __FUNCTION__ , ## arg) + +static DECLARE_MUTEX(fi_sem); + +static struct subsystem fi_subsys; +static struct subsystem trigger_subsys; +static struct subsystem interceptor_subsys; + +static int is_initialized = 0; +int fault_injection_enabled = 0; +static int fi_debug = 1; + +int fi_register_interceptor(struct interceptor *); + +struct trigger_attribute { + struct attribute attr; + ssize_t (*show)(struct trigger *,char *,size_t,loff_t); +}; + +static struct trigger_attribute trigger_attr_wp; +static struct trigger_attribute trigger_attr_bitmask; +static struct trigger_attribute trigger_attr_min; +static struct trigger_attribute trigger_attr_max; +static struct trigger_attribute trigger_attr_skip; +static struct trigger_attribute trigger_attr_stop; +static struct trigger_attribute trigger_attr_protection; +static struct trigger_attribute trigger_attr_hertz; +static struct trigger_attribute trigger_attr_registered; +static struct trigger_attribute trigger_attr_opcode; +static struct trigger_attribute trigger_attr_operand; +static struct trigger_attribute trigger_attr_count; +static struct trigger_attribute trigger_attr_type; + +static inline void create_trigger_files(struct trigger *t) +{ + sysfs_create_file(&t->kobj, &trigger_attr_wp.attr); + sysfs_create_file(&t->kobj, &trigger_attr_bitmask.attr); + sysfs_create_file(&t->kobj, &trigger_attr_min.attr); + sysfs_create_file(&t->kobj, &trigger_attr_max.attr); + sysfs_create_file(&t->kobj, &trigger_attr_skip.attr); + sysfs_create_file(&t->kobj, &trigger_attr_stop.attr); + sysfs_create_file(&t->kobj, &trigger_attr_protection.attr); + sysfs_create_file(&t->kobj, &trigger_attr_hertz.attr); + sysfs_create_file(&t->kobj, &trigger_attr_registered.attr); + sysfs_create_file(&t->kobj, &trigger_attr_opcode.attr); + sysfs_create_file(&t->kobj, &trigger_attr_operand.attr); + sysfs_create_file(&t->kobj, &trigger_attr_count.attr); + sysfs_create_file(&t->kobj, &trigger_attr_type.attr); +} -#define MODULE_NAME "fi_dm" -#define MODULE_VERSION "0.1" +static inline void remove_trigger_files(struct trigger *t) +{ + sysfs_remove_file(&t->kobj, &trigger_attr_wp.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_bitmask.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_min.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_max.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_skip.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_stop.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_protection.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_hertz.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_registered.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_opcode.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_operand.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_count.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_type.attr); +} -static int insert_faultset(struct fi_faultset *fs); -static int remove_faultset(int index); -static int enable_faultset(int index); -static int disable_faultset(int index); - - -static struct fi_faultset fs_tb[MAX_FAULTSET]; - -extern int fi_pf_register(struct watchpoint wp, int id, struct intercept_hook *hook); -extern int fi_pf_unregister(int id); -extern int fi_pf_corrupt(int id, __u32 dirty, void *data); - - -void dm_trigger(int id, __u32 val, int len, int type, void *data){ - int fs_num= FI_FS_NUM(id); - int tri_num=FI_TRI_NUM(id); - int tmp=0, i=0; - struct fi_trigger *tri = NULL; - __u32 old = val; - - PDEBUG("entry, id=%#x, val=%#x, len=%d, type=%d, data=%p\n", - id, val, len, type, data); - if (fs_num>=MAX_FAULTSET || fs_num<0 - || tri_num>=MAX_TRIGGER_PER_FAULTSET || tri_num<0){ - PERROR(":error id number %d\n", id); - goto exit; - } - - tri = &fs_tb[fs_num].trigger_tb[tri_num]; - - if (!tri->registered){ - PERROR("Should not trigger an unregistered wp %d!?\n", id); - } - - - get_random_bytes(&tmp, sizeof(tmp)); - if (tri->hertz==0) {tri->hertz=1;};//divid is not 0! - if (tmp >= 0xFFFFFFFF/tri->hertz){ - PDEBUG("rnd=%d, HERZ=%d\n", tmp, tri->hertz); - goto exit; - } - - tmp = val & (~tri->bitmask); - if (tri->min>tmp || tmp>=tri->max){ - PDEBUG("min=%d, max=%d, val=%d\n", tri->min, tri->max, val); - if(!(tri->min==0 && tri->max==0)) - goto exit; - } - - // Increase count only when passing all conditions - atomic_inc(&tri->count); - - if (tri->skip >= atomic_read(&tri->count)){ - PDEBUG("count=%d, skip=%d\n", atomic_read(&tri->count), tri->skip); - goto exit; - } - - if ( tri->stop!=0 && (tri->stop < (atomic_read(&tri->count)-tri->skip)) ) { - PDEBUG("count=%d, stop=%d\n", atomic_read(&tri->count), tri->stop); - goto exit; - } - - PDEBUG("count=%d, skip=%d, min=%d, max=%d, val=%d\n", - atomic_read(&tri->count), tri->skip, tri->min, tri->max, val); - tmp = val; - for (i=0; i<MAX_OP_PER_TRIGGER; i++) { - switch (tri->ops[i].opcode){ - case FI_NOTHING: - goto exit_for; - case FI_SET: - tmp = tri->ops[i].operand; - break; - case FI_AND: - tmp &= tri->ops[i].operand; - break; - case FI_OR: - tmp |= tri->ops[i].operand; - break; - case FI_NOT: - tmp = ~tmp; - break; - case FI_XOR: - tmp ^= tri->ops[i].operand; - break; - case FI_NAND: - tmp = ~(tmp & tri->ops[i].operand); - break; - case FI_NOR: - tmp = ~(tmp | tri->ops[i].operand); - break; - case FI_ADD: - tmp = tmp + tri->ops[i].operand; - break; - case FI_SUB: - tmp = tmp - tri->ops[i].operand; - break; - default: - PERROR("Not recognized opcode%d\n", tri->ops[i].opcode); - break; +static inline ssize_t add_trigger(struct trigger *t) +{ + struct list_head * entry; + struct interceptor * i; + struct trigger *n; + + n = kmalloc(sizeof(struct trigger),GFP_KERNEL); + if (!n) + return -ENOMEM; + memset(n,0,sizeof(struct trigger)); + + kobject_init(&n->kobj); + strncpy(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN); + n->kobj.subsys = &trigger_subsys; + n->wp.addr = t->wp.addr; + n->wp.type = t->wp.type; + n->bitmask = t->bitmask; + n->min = t->min; + n->max = t->max; + n->skip = t->skip; + n->stop = t->stop; + n->protection = t->protection; + n->hertz = t->hertz; + n->registered = t->registered; + n->opcode = t->opcode; + n->operand = t->operand; + n->type = t->type; + atomic_set(&n->count, 0); + + if (kobject_register(&n->kobj)) { + err("Unable to register kobject"); + return -EINVAL; + } + + create_trigger_files(n); + + list_for_each(entry,&interceptor_subsys.list) { + i = to_interceptor(entry); + if (i->type == n->type) { + (i->arm)(n); } } - exit_for: - val = (val & (tri->protection)) | (tmp & (~tri->protection)); + + return 0; +} - exit: +static inline ssize_t del_trigger(struct trigger *t) +{ + struct list_head * entry; + struct trigger * n; + + list_for_each(entry,&trigger_subsys.list) { + n = to_trigger(entry); + if (!strncmp(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN)) { + dbg("comparing %s to %s", n->kobj.name, t->kobj.name); + remove_trigger_files(n); + kobject_unregister(&n->kobj); + return 0; + } + } - PINFO("id=%#x, val=%#x, old=%#x, len=%d, type=%d, data=%p\n", - id, val, old, len, type, data); - fi_pf_corrupt(id, val, data); - return; + err("trigger %s does not exist", t->kobj.name); + return -EINVAL; } -static struct intercept_hook intcpt_hook[1] = { - { - trigger: dm_trigger - } -}; - +/* + * =========================================================== + * <>-- Toplevel Containing Subsystem (fi_subsys) --<> + * ----------------------------------------------------------- + */ -/*manipulate fault set*/ -static int insert_faultset(struct fi_faultset *fs){ - int rv=0; - int i=0; +static ssize_t fi_enabled_show(struct subsystem * s, char * page, + size_t count, loff_t off) +{ + return off ? 0 : snprintf(page,count,"%i\n",fault_injection_enabled); +} - for (i=0; i<MAX_FAULTSET; i++) { - if (fs_tb[i].stat == NOUSED) break; +static ssize_t fi_enabled_store(struct subsystem * s, const char * page, + size_t count, loff_t off) +{ + int tmp = 0; + int num; + int ret = 0; + int error = 0; + + down(&fi_sem); + if (off) + goto Done; + + num = sscanf(page,"%i",&tmp); + if (!num) { + error = -EINVAL; + goto Done; } - if (i < MAX_FAULTSET) { - int rv1; - copy_from_user(&fs_tb[i], fs, sizeof(fs_tb[i])); - fs_tb[i].stat = DISABLED; - rv = i; - PINFO("insert #%d fs\n", i); - rv1 = enable_faultset(i); - if(rv1<0) { - PERROR("can not enable faultset# %d\n", i); - } - }else{ - rv = -ENOSPC; + + if (tmp) { + fault_injection_enabled = 1; + } else { + fault_injection_enabled = 0; } - return rv; -} -static int remove_faultset(int index){ - int rv=0; + ret = error ? error : count; + Done: + up(&fi_sem); + return ret; +} - if (index<0 || index>=MAX_FAULTSET || fs_tb[index].stat == NOUSED) { - rv = -EPERM; - goto exit1; - } - - if (index>=0 && index<MAX_FAULTSET && fs_tb[index].stat == ENABLED) { - disable_faultset(index); - } - - if (index<0 || index>=MAX_FAULTSET || fs_tb[index].stat == ENABLED) { - PERROR("can not remove #%d fs when it is enabled\n", index); - rv = -EPERM; - }else{ - fs_tb[index].stat = NOUSED; - } - PINFO("remove #%d fs\n", index); - exit1: - return rv; +static ssize_t fi_debug_show(struct subsystem * s, char * page, + size_t count, loff_t off) +{ + return off ? 0 : snprintf(page,count,"%i\n",fi_debug); } -static int enable_faultset(int index){ - int rv=0; - int i=0; - int id_high; - struct fi_faultset *fs; - - PDEBUG("trying to enable faultset# %d\n", index); - - if (index<0 || index>= MAX_FAULTSET || fs_tb[index].stat != DISABLED) { - rv = -EINVAL; - goto exit; - } - - id_high = index<<16; - fs = &fs_tb[index]; - /*register all wp into interceptor component*/ - for (i=0; i<MAX_TRIGGER_PER_FAULTSET && (fs->trigger_tb[i].wp.addr); i++){ - PDEBUG("register WP, id=%d, hook=%p\n", id_high+i, intcpt_hook); - atomic_set(&fs->trigger_tb[i].count, 0); - fs->trigger_tb[i].registered = 1; - rv = fi_pf_register(fs->trigger_tb[i].wp, id_high+i, intcpt_hook); +static ssize_t fi_debug_store(struct subsystem * s, const char * page, + size_t count, loff_t off) +{ + int tmp = 0; + int num; + int ret = 0; + int error = 0; + + down(&fi_sem); + if (off) + goto Done; + + num = sscanf(page,"%i",&tmp); + if (!num) { + error = -EINVAL; + goto Done; + } - if (rv<0) { - fs->trigger_tb[i].registered = 0; - PERROR("can not register WP, id = %d\n", id_high+i); - continue; //goto exit;//XXX: I should remove registered trigger - } - fs->stat = ENABLED; + if (tmp) { + fi_debug = 1; + } else { + fi_debug = 0; } - if (fs->stat == DISABLED) { - PERROR("none of trigger can be active, enable faultset failed!\n"); - goto exit; - } - PINFO("enable #%d fs\n", index); - rv = 0; - exit: - return rv; -} -static int disable_faultset(int index){ - int rv=0; - int i=0; - int id_high=0; - struct fi_faultset *fs; - - PDEBUG("trying to disable faultset# %d\n", index); - if(index<0 || index>MAX_FAULTSET || fs_tb[index].stat!=ENABLED) { - rv=-EINVAL; - goto exit; - } - - id_high=index<<16; - fs = &fs_tb[index]; - - for (i=0; i<MAX_TRIGGER_PER_FAULTSET && (fs->trigger_tb[i].wp.addr); i++){ - rv = fi_pf_unregister(id_high+i); - if (rv>=0) { - fs->trigger_tb[i].registered = 0; - }else{ - PERROR("can not unregister wp, id=%d\n", id_high+i); - } - } - fs->stat = DISABLED; - PINFO("disable #%d fs\n", index); - rv = 0; - exit: - return rv; + ret = error ? error : count; + Done: + up(&fi_sem); + return ret; } -/*END OF fault set functions*/ +static struct subsystem fi_subsys = { + .kobj = { .name = "fault_injection" }, +}; -static int fi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg){ - int rv=0; - int i=0; - - switch (cmd){ - default: - rv = -ENOTTY; - break; - case FIIOC_INSERT: - rv = insert_faultset((struct fi_faultset *)arg); - break; - case FIIOC_REMOVE: - get_user(i, (int *)arg); - rv = remove_faultset(i); - break; - case FIIOC_ENABLE: - get_user(i, (int *)arg); - rv = enable_faultset(i); - break; - case FIIOC_DISABLE: - get_user(i, (int *)arg); - rv = disable_faultset(i); - break; - }; - return rv; +static struct subsys_attribute fi_subsys_attr_enabled = { + .attr = { .name = "enabled", .mode = 0644 }, + .show = fi_enabled_show, + .store = fi_enabled_store, }; -static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED; -static int counter=0; +static struct subsys_attribute fi_subsys_attr_debug = { + .attr = { .name = "debug", .mode = 0644 }, + .show = fi_debug_show, + .store = fi_debug_store, +}; -static int fi_open(struct inode *inode, struct file *file){ - int rv=0; - - spin_lock(&counter_lock); - if (counter) { - rv = -1; - goto out; - } - counter++; - MOD_INC_USE_COUNT; - out: - spin_unlock(&counter_lock); - return rv; -} +/* + * =============================================================== + * <>-- Interceptor Containing Subsystem (interceptor_subsys) --<> + * --------------------------------------------------------------- + */ + +static struct subsystem interceptor_subsys = { + .kobj = { .name = "interceptors" }, + .parent = &fi_subsys, +}; +/* + * =========================================================== + * <>-- Trigger Subsystem (trigger_subsys) --<> + * ----------------------------------------------------------- + */ -static int fi_release(struct inode *inode, struct file *file){ - spin_lock(&counter_lock); - counter--; - MOD_DEC_USE_COUNT; - spin_unlock(&counter_lock); - return 0; +static ssize_t trigger_attr_show(struct kobject * kobj, + struct attribute * attr, + char * page, size_t count, + loff_t off) +{ + struct trigger * n = container_of(kobj,struct trigger,kobj); + struct trigger_attribute * trigger_attr = + container_of(attr,struct trigger_attribute,attr); + + dbg("about to call show function for %s", trigger_attr->attr.name); + return trigger_attr->show ? trigger_attr->show(n,page,count,off) : 0; } -static in... [truncated message content] |
From: Rusty L. <ru...@st...> - 2002-12-16 07:04:07
|
As I mentioned in a previous email, I was hacking around with some alternative approaches to the core functionality for fault injection, and ended up making a complete rewrite of fi_core.c. This was actually my second attempt, since the first avenue I went down ended turning more complicated then I believe fault injection warrants. The code is still pretty preliminary, but I wanted to get it out for review before I gave up for the night, and since the second half of tomorrow will be taken up with the opening of the new Star Trek flick... then maybe somebody will have a chance to run with this idea. Why I felt we needed an overhaul of fi_core.c --------------------------------------------- 1. When I read through fi_core.c, I notice that there are a lot of assumptions about what a given interceptor is doing (specifically the mmio interceptor in arch/i386/fi/pf/*). We already have volunteers to implement other interceptors that are described in the high level design documentation, but until we get better model for plugging new interceptors into the core fault injection functionality then life will get very complicated. 2. Anytime I look at a block of kernel code I ask 'is there some way this can be done in user space?'. The high level design papers describe a model where faults (or triggers) are grouped into fault sets. I have no problem with that type of design, but since a given trigger has no need to know about sibling triggers, then this should be information kept in user space. The below implementation implements triggers that expose everything there is to know about themselves to user space via sysfs. With this kind of information user space can keep track of what triggers are associated with what fault set. 3. Ever since I discovered the elegance of the new kobject model for dealing with data in the kernel, I have tried to utilize that model where ever possible. I moved the core functionality to use this model instead of using the fixed size block of data that existed before. I feel this makes the code easier to read, very easy to expose data to user space via sysfs, and allows us to piggy back on one of the most utilized subsystems in the kernel. We no longer have the need for exposing an ioctl interface since all interaction happens via sysfs. Here is an example: when I boot a system with fault injection enabled and mount sysfs on /sysfs/, then I can see ==> # NOTE: All of this is without the aid of a tool. The existing # ficl tool could be tweaked to expose the same interface # to the user (i.e. the manual is still correct), but be # implemented by reading/write to files in sysfs $ tree /sysfs/fault_injection /sysfs/fault_injection/ |-- debug |-- enabled |-- interceptors | `-- pf_interceptor `-- triggers `-- ctl From this I can see that I have one interceptor named pf_interceptor and not triggers inserted. If I want to enable extra debugging information the I ==> $ cat "1" > /sysfs/fault_injection/debug By default fault injection is disabled at startup. I can enable it by ==> $ cat "1" > /sysfs/fault_injection/enabled Adding and removing triggers happens by writing commands to triggers/ctl. To add a trigger ==> # documentation about what each field is for is documented in the code $echo "add test1 MMIO 1 1 1 1 10 1 1 1 1 1 1 1" > \ /sysfs/fault_injection/triggers/ctl I could then see the trigger represented in sysfs by ==> $ tree /sysfs/fault_injection /sysfs/fault_injection/ |-- debug |-- enabled |-- interceptors | `-- pf_interceptor `-- triggers |-- ctl `-- test1 |-- bitmask |-- count |-- hertz |-- max |-- min |-- opcode |-- operand |-- protection |-- registered |-- skip |-- stop |-- type `-- wp And then inspect what ever I wanted, like ==> $ cat /sysfs/fault_injection/triggers/test1/type MMIO To remove the trigger ==> $ echo "del test1" > /sysfs/fault_injection/triggers/ctl Hopefully you get the idea. The possibilities are endless. New model for plugging interceptors into fault injection -------------------------------------------------------- When an interceptor is initialized, it registers with the fi_core.c by: creating an interceptor object which is a kobject, and then passing that object to fi_core.c by calling ==> int fi_register_interceptor(struct interceptor *); One of the fields in a trigger indicates what type of interceptor it is designed for. When a trigger is registered for a INTERCEPTOR_TYPE_MMIO type of interceptor, the trigger will arm itself with all appropriate interceptors by calling the 'arm' callback inside the interceptor object. This is same idea as fi_core.c calling fi_pf_register(), but doesn't require fi_core.c to know about the pf implementation of a mmio interceptor ahead of time. When a trigger is removed, fi_core.c calls the 'disarm' callback also contained in the interceptor object passed to fi_core.c during registration. The code has still got some major holes, but it compiles and fundamental operations can be done via cat and echo on the command line. Since this is a complete rewrite of fi_core.c, I am sending the entire file for browsing, and then also sending a diff against the bk tree. These files can also be found at http//fault-injection.sf.net/rustyl/ --rustyl /****************************************************************************** * Fault Injection Core Functionality * Copyright (C) Intel Crop. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************** * * This is a rewrite of code originally submitted by * Louis Zhuang <lou...@in...>. I have moved the code from * a ioctl based control using proc to expose information about * fault injection data that was contained in fixed sized tables, * to an extendable kobject based implementation that uses sysfs * for all user space access. * --rustyl * * Contributors: * Louis Zhuang <lou...@in...> * Stanley Wang <sta...@in...> * Rusty Lynch <ru...@li...> */ #include <linux/module.h> #include <linux/init.h> #include <linux/kprobes.h> #include <linux/slab.h> #include <linux/kobject.h> #define PREFIX_NAME "FI" #include <linux/fi/fi.h> #include <linux/fi.h> #ifdef CONFIG_FI_DEBUG #define dbg(format, arg...) \ do { \ if(fi_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ __FUNCTION__, ## arg); \ } while(0) #else #define dbg(format, art...) #endif #define err(format, arg...) \ printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ## arg) #define info(format, arg...) \ printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ## arg) #define warn(format, arg...) \ printk(KERN_WARNING "%s: " format "\n", __FUNCTION__ , ## arg) static DECLARE_MUTEX(fi_sem); static struct subsystem fi_subsys; static struct subsystem trigger_subsys; static struct subsystem interceptor_subsys; static int is_initialized = 0; int fault_injection_enabled = 0; static int fi_debug = 1; int fi_register_interceptor(struct interceptor *); struct trigger_attribute { struct attribute attr; ssize_t (*show)(struct trigger *,char *,size_t,loff_t); }; static struct trigger_attribute trigger_attr_wp; static struct trigger_attribute trigger_attr_bitmask; static struct trigger_attribute trigger_attr_min; static struct trigger_attribute trigger_attr_max; static struct trigger_attribute trigger_attr_skip; static struct trigger_attribute trigger_attr_stop; static struct trigger_attribute trigger_attr_protection; static struct trigger_attribute trigger_attr_hertz; static struct trigger_attribute trigger_attr_registered; static struct trigger_attribute trigger_attr_opcode; static struct trigger_attribute trigger_attr_operand; static struct trigger_attribute trigger_attr_count; static struct trigger_attribute trigger_attr_type; static inline void create_trigger_files(struct trigger *t) { sysfs_create_file(&t->kobj, &trigger_attr_wp.attr); sysfs_create_file(&t->kobj, &trigger_attr_bitmask.attr); sysfs_create_file(&t->kobj, &trigger_attr_min.attr); sysfs_create_file(&t->kobj, &trigger_attr_max.attr); sysfs_create_file(&t->kobj, &trigger_attr_skip.attr); sysfs_create_file(&t->kobj, &trigger_attr_stop.attr); sysfs_create_file(&t->kobj, &trigger_attr_protection.attr); sysfs_create_file(&t->kobj, &trigger_attr_hertz.attr); sysfs_create_file(&t->kobj, &trigger_attr_registered.attr); sysfs_create_file(&t->kobj, &trigger_attr_opcode.attr); sysfs_create_file(&t->kobj, &trigger_attr_operand.attr); sysfs_create_file(&t->kobj, &trigger_attr_count.attr); sysfs_create_file(&t->kobj, &trigger_attr_type.attr); } static inline void remove_trigger_files(struct trigger *t) { sysfs_remove_file(&t->kobj, &trigger_attr_wp.attr); sysfs_remove_file(&t->kobj, &trigger_attr_bitmask.attr); sysfs_remove_file(&t->kobj, &trigger_attr_min.attr); sysfs_remove_file(&t->kobj, &trigger_attr_max.attr); sysfs_remove_file(&t->kobj, &trigger_attr_skip.attr); sysfs_remove_file(&t->kobj, &trigger_attr_stop.attr); sysfs_remove_file(&t->kobj, &trigger_attr_protection.attr); sysfs_remove_file(&t->kobj, &trigger_attr_hertz.attr); sysfs_remove_file(&t->kobj, &trigger_attr_registered.attr); sysfs_remove_file(&t->kobj, &trigger_attr_opcode.attr); sysfs_remove_file(&t->kobj, &trigger_attr_operand.attr); sysfs_remove_file(&t->kobj, &trigger_attr_count.attr); sysfs_remove_file(&t->kobj, &trigger_attr_type.attr); } static inline ssize_t add_trigger(struct trigger *t) { struct list_head * entry; struct interceptor * i; struct trigger *n; n = kmalloc(sizeof(struct trigger),GFP_KERNEL); if (!n) return -ENOMEM; memset(n,0,sizeof(struct trigger)); kobject_init(&n->kobj); strncpy(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN); n->kobj.subsys = &trigger_subsys; n->wp.addr = t->wp.addr; n->wp.type = t->wp.type; n->bitmask = t->bitmask; n->min = t->min; n->max = t->max; n->skip = t->skip; n->stop = t->stop; n->protection = t->protection; n->hertz = t->hertz; n->registered = t->registered; n->opcode = t->opcode; n->operand = t->operand; n->type = t->type; atomic_set(&n->count, 0); if (kobject_register(&n->kobj)) { err("Unable to register kobject"); return -EINVAL; } create_trigger_files(n); list_for_each(entry,&interceptor_subsys.list) { i = to_interceptor(entry); if (i->type == n->type) { (i->arm)(n); } } return 0; } static inline ssize_t del_trigger(struct trigger *t) { struct list_head * entry; struct trigger * n; list_for_each(entry,&trigger_subsys.list) { n = to_trigger(entry); if (!strncmp(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN)) { dbg("comparing %s to %s", n->kobj.name, t->kobj.name); remove_trigger_files(n); kobject_unregister(&n->kobj); return 0; } } err("trigger %s does not exist", t->kobj.name); return -EINVAL; } /* * =========================================================== * <>-- Toplevel Containing Subsystem (fi_subsys) --<> * ----------------------------------------------------------- */ static ssize_t fi_enabled_show(struct subsystem * s, char * page, size_t count, loff_t off) { return off ? 0 : snprintf(page,count,"%i\n",fault_injection_enabled); } static ssize_t fi_enabled_store(struct subsystem * s, const char * page, size_t count, loff_t off) { int tmp = 0; int num; int ret = 0; int error = 0; down(&fi_sem); if (off) goto Done; num = sscanf(page,"%i",&tmp); if (!num) { error = -EINVAL; goto Done; } if (tmp) { fault_injection_enabled = 1; } else { fault_injection_enabled = 0; } ret = error ? error : count; Done: up(&fi_sem); return ret; } static ssize_t fi_debug_show(struct subsystem * s, char * page, size_t count, loff_t off) { return off ? 0 : snprintf(page,count,"%i\n",fi_debug); } static ssize_t fi_debug_store(struct subsystem * s, const char * page, size_t count, loff_t off) { int tmp = 0; int num; int ret = 0; int error = 0; down(&fi_sem); if (off) goto Done; num = sscanf(page,"%i",&tmp); if (!num) { error = -EINVAL; goto Done; } if (tmp) { fi_debug = 1; } else { fi_debug = 0; } ret = error ? error : count; Done: up(&fi_sem); return ret; } static struct subsystem fi_subsys = { .kobj = { .name = "fault_injection" }, }; static struct subsys_attribute fi_subsys_attr_enabled = { .attr = { .name = "enabled", .mode = 0644 }, .show = fi_enabled_show, .store = fi_enabled_store, }; static struct subsys_attribute fi_subsys_attr_debug = { .attr = { .name = "debug", .mode = 0644 }, .show = fi_debug_show, .store = fi_debug_store, }; /* * =============================================================== * <>-- Interceptor Containing Subsystem (interceptor_subsys) --<> * --------------------------------------------------------------- */ static struct subsystem interceptor_subsys = { .kobj = { .name = "interceptors" }, .parent = &fi_subsys, }; /* * =========================================================== * <>-- Trigger Subsystem (trigger_subsys) --<> * ----------------------------------------------------------- */ static ssize_t trigger_attr_show(struct kobject * kobj, struct attribute * attr, char * page, size_t count, loff_t off) { struct trigger * n = container_of(kobj,struct trigger,kobj); struct trigger_attribute * trigger_attr = container_of(attr,struct trigger_attribute,attr); dbg("about to call show function for %s", trigger_attr->attr.name); return trigger_attr->show ? trigger_attr->show(n,page,count,off) : 0; } static ssize_t trigger_wp_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("wp.addr = %#lx, wp.type = %#x", p->wp.addr, p->wp.type); return off ? 0 : snprintf(page,count,"%#lx %#x\n", p->wp.addr,p->wp.type); } static struct trigger_attribute trigger_attr_wp = { .attr = { .name = "wp", .mode = S_IRUGO }, .show = trigger_wp_read, }; static ssize_t trigger_bitmask_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("bitmask = %#x", p->bitmask); return off ? 0 : snprintf(page,count,"%#x\n",p->bitmask); } static struct trigger_attribute trigger_attr_bitmask = { .attr = { .name = "bitmask", .mode = S_IRUGO }, .show = trigger_bitmask_read, }; static ssize_t trigger_min_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("min = %i", p->min); return off ? 0 : snprintf(page,count,"%i\n",p->min); } static struct trigger_attribute trigger_attr_min = { .attr = { .name = "min", .mode = S_IRUGO }, .show = trigger_min_read, }; static ssize_t trigger_max_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("max = %i", p->max); return off ? 0 : snprintf(page,count,"%i\n",p->max); } static struct trigger_attribute trigger_attr_max = { .attr = { .name = "max", .mode = S_IRUGO }, .show = trigger_max_read, }; static ssize_t trigger_skip_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("skip = %i", p->skip); return off ? 0 : snprintf(page,count,"%i\n",p->skip); } static struct trigger_attribute trigger_attr_skip = { .attr = { .name = "skip", .mode = S_IRUGO }, .show = trigger_skip_read, }; static ssize_t trigger_stop_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("stop = %i", p->stop); return off ? 0 : snprintf(page,count,"%i\n",p->stop); } static struct trigger_attribute trigger_attr_stop = { .attr = { .name = "stop", .mode = S_IRUGO }, .show = trigger_stop_read, }; static ssize_t trigger_protection_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("protection = %i", p->protection); return off ? 0 : snprintf(page,count,"%i\n",p->protection); } static struct trigger_attribute trigger_attr_protection = { .attr = { .name = "protection", .mode = S_IRUGO }, .show = trigger_protection_read, }; static ssize_t trigger_hertz_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("hertz = %i", p->hertz); return off ? 0 : snprintf(page,count,"%i\n",p->hertz); } static struct trigger_attribute trigger_attr_hertz = { .attr = { .name = "hertz", .mode = S_IRUGO }, .show = trigger_hertz_read, }; static ssize_t trigger_registered_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("registered = %i", p->registered); return off ? 0 : snprintf(page,count,"%i\n",p->registered); } static struct trigger_attribute trigger_attr_registered = { .attr = { .name = "registered", .mode = S_IRUGO }, .show = trigger_registered_read, }; static ssize_t trigger_count_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("count = %i", atomic_read(&p->count)); return off ? 0 : snprintf(page,count,"%i\n",atomic_read(&p->count)); } static struct trigger_attribute trigger_attr_count = { .attr = { .name = "count", .mode = S_IRUGO }, .show = trigger_count_read, }; static ssize_t trigger_type_read(struct trigger * p, char * page, size_t count, loff_t off) { int rv; dbg("type = %i", p->type); if (off) return 0; switch (p->type) { case INTERCEPTOR_TYPE_MMIO: rv = snprintf(page,count,"MMIO\n"); break; default: rv = snprintf(page,count,"UNKNOWN\n"); } return rv; } static struct trigger_attribute trigger_attr_type = { .attr = { .name = "type", .mode = S_IRUGO }, .show = trigger_type_read, }; static ssize_t trigger_opcode_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("opcode = %i", p->opcode); return off ? 0 : snprintf(page,count,"%i\n",p->opcode); } static struct trigger_attribute trigger_attr_opcode = { .attr = { .name = "opcode", .mode = S_IRUGO }, .show = trigger_opcode_read, }; static ssize_t trigger_operand_read(struct trigger * p, char * page, size_t count, loff_t off) { dbg("operand = %i", p->operand); return off ? 0 : snprintf(page,count,"%i\n",p->operand); } static struct trigger_attribute trigger_attr_operand = { .attr = { .name = "operand", .mode = S_IRUGO }, .show = trigger_operand_read, }; static ssize_t trigger_ctl_show(struct subsystem * s, char * page, size_t count, loff_t off) { return 0; } static ssize_t trigger_ctl_store(struct subsystem * s, const char * page, size_t count, loff_t off) { char ctl[16]; char type[16]; int num; int error; int ret = 0; struct trigger tmp; if (off) return 0; /* 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 */ /* ctl nm tp wa wb bm mn mx sk st pt hz rg oc oa */ num = sscanf(page,"%15s %s %s %lx %x %x %i %i %i %i %i %i %i %i %i", ctl, /* 3 */ tmp.kobj.name, /* 4 */ type, /* 5 */ &tmp.wp.addr, /* 6 */ &tmp.wp.type, /* 7 */ &tmp.bitmask, /* 8 */ &tmp.min, /* 9 */ &tmp.max, /* 10 */ &tmp.skip, /* 11 */ &tmp.stop, /* 12 */ &tmp.protection, /* 13 */ &tmp.hertz, /* 14 */ &tmp.registered, /* 15 */ (int *)&tmp.opcode, /* 16 */ &tmp.operand); /* 17 */ if (!num) { err("Invalid command format, translated no commands"); error = -EINVAL; goto Done; } dbg("type = '%s'", type); if (!strncmp(type, "MMIO", 4)) tmp.type = INTERCEPTOR_TYPE_MMIO; else tmp.type = INTERCEPTOR_TYPE_UNKNOWN; if (!strcmp(ctl,"add") && num == 15) error = add_trigger(&tmp); else if (!strcmp(ctl,"del") && num == 2) error = del_trigger(&tmp); else { err("Invalid command format: %s, %i tokens found",ctl,num); error = -EINVAL; } ret = error ? error : count; Done: return ret; } static struct subsys_attribute trigger_subsys_attr_ctl = { .attr = { .name = "ctl", .mode = 0644 }, .show = trigger_ctl_show, .store = trigger_ctl_store, }; static struct sysfs_ops trigger_sysfs_ops = { .show = trigger_attr_show, }; static struct subsystem trigger_subsys = { .kobj = { .name = "triggers" }, .sysfs_ops = &trigger_sysfs_ops, .parent = &fi_subsys, }; static int __init fi_init(void){ down(&fi_sem); if (is_initialized) { dbg("alreading initialized... exiting"); goto Done; } dbg("initializing fault injection core"); subsystem_register(&fi_subsys); subsys_create_file(&fi_subsys,&fi_subsys_attr_debug); subsys_create_file(&fi_subsys,&fi_subsys_attr_enabled); subsystem_register(&interceptor_subsys); subsystem_register(&trigger_subsys); subsys_create_file(&trigger_subsys,&trigger_subsys_attr_ctl); is_initialized++; Done: up(&fi_sem); return 0; }; int fi_register_interceptor(struct interceptor *i) { /* * If an interceptor is able to initialize * before we are then do our own initialization * before going on */ if (!is_initialized) fi_init(); dbg("registering interceptor %s", i->kobj.name); i->kobj.subsys = &interceptor_subsys; kobject_init(&i->kobj); return kobject_register(&i->kobj); } /* Is there a better way to get my init code to execute on startup? */ module_init(fi_init); EXPORT_SYMBOL_GPL(fault_injection_enabled); EXPORT_SYMBOL_GPL(fi_register_interceptor); MODULE_PARM(fi_debug, "i"); MODULE_PARM_DESC(fi_debug, "Debugging mode enabled or not"); # This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.879 -> 1.880 # arch/i386/kernel/fi/pf/pf.c 1.6 -> 1.7 # kernel/Makefile 1.25 -> 1.26 # kernel/fi_core.c 1.6 -> 1.7 # (new) -> 1.1 include/linux/fi.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/12/15 ru...@st... 1.880 # This changeset includes a complete rewrite of fi_core.c, a new # header file infavor of the include/linux/fi/ going away, and a new # model for interfacing between interceptors and the core fault injection # routines. # # -------------------------------------------- # diff -Nru a/arch/i386/kernel/fi/pf/pf.c b/arch/i386/kernel/fi/pf/pf.c --- a/arch/i386/kernel/fi/pf/pf.c Sun Dec 15 21:33:50 2002 +++ b/arch/i386/kernel/fi/pf/pf.c Sun Dec 15 21:33:50 2002 @@ -51,6 +51,7 @@ #include <asm/pgalloc.h> #include <asm/io.h> #include <asm/tlbflush.h> +#include <linux/random.h> #include <asm/fi.h> @@ -58,6 +59,7 @@ #include <linux/fi/fi.h> #include <linux/fi/fi_interface.h> #include <linux/fi/fi_internal.h> +#include <linux/fi.h> #include "fi_pf.h" @@ -67,14 +69,105 @@ static struct{ int page_index; struct watchpoint wp; - int id; - struct intercept_hook * hook; + struct trigger * trigger; }wp_tb[MAX_WP] = { [0 ... MAX_WP-1] = { wp: {0,0}, - id: -1, - hook: NULL } + trigger: NULL } }; +/** + * This is a KEY data structure. When interceptor triggers DM + * and then DM call iAction method. iAction remembers this corrupted data. + * Then DM returns to Interceptor and Interceptor returns corrupted data + * to intercepted access. + */ +struct fi_corrupt{ + __u32 corrupted_data; +}; + +static inline void execute_trigger(struct trigger *t, __u32 val, + int len, int type, void *data) +{ + int tmp = 0; + + if (!t) { + PERROR("Unable to execute null trigger\n"); + goto exit; + } + + get_random_bytes(&tmp, sizeof(tmp)); + if (t->hertz==0) {t->hertz=1;};//divid is not 0! + if (tmp >= 0xFFFFFFFF/t->hertz){ + PDEBUG("rnd=%d, HERZ=%d\n", tmp, t->hertz); + goto exit; + } + + tmp = val & (~t->bitmask); + if (t->min>tmp || tmp>=t->max){ + PDEBUG("min=%d, max=%d, val=%d\n", t->min, t->max, val); + if(!(t->min==0 && t->max==0)) + goto exit; + } + + // Increase count only when passing all conditions + atomic_inc(&t->count); + + if (t->skip >= atomic_read(&t->count)){ + PDEBUG("count=%d, skip=%d\n", atomic_read(&t->count), t->skip); + goto exit; + } + + if ( t->stop!=0 && (t->stop < (atomic_read(&t->count)-t->skip)) ) { + PDEBUG("count=%d, stop=%d\n", atomic_read(&t->count), t->stop); + goto exit; + } + + PDEBUG("count=%d, skip=%d, min=%d, max=%d, val=%d\n", + atomic_read(&t->count), t->skip, t->min, t->max, val); + tmp = val; + switch (t->opcode){ + case FI_NOTHING: + goto exit_for; + case FI_SET: + tmp = t->operand; + break; + case FI_AND: + tmp &= t->operand; + break; + case FI_OR: + tmp |= t->operand; + break; + case FI_NOT: + tmp = ~tmp; + break; + case FI_XOR: + tmp ^= t->operand; + break; + case FI_NAND: + tmp = ~(tmp & t->operand); + break; + case FI_NOR: + tmp = ~(tmp | t->operand); + break; + case FI_ADD: + tmp = tmp + t->operand; + break; + case FI_SUB: + tmp = tmp - t->operand; + break; + default: + PERROR("Not recognized opcode%d\n", t->opcode); + break; + } + + exit_for: + val = (val & (t->protection)) | (tmp & (~t->protection)); + + exit: + ((struct fi_corrupt *)data)->corrupted_data = val; + return; +} + static void fi_do_flush_tlb_ipi(void* addr) { __flush_tlb_one(addr); }; @@ -85,7 +178,8 @@ __flush_tlb_one(addr); }; -int fi_pf_register(struct watchpoint wp, int id, struct intercept_hook *hook){ +int fi_pf_register(struct watchpoint wp, struct trigger *trigger) +{ unsigned long flags; int wi=0; //watchpoint index int ri=0; //region index @@ -93,8 +187,8 @@ unsigned long addr; /* Make sure that wp is vaild */ - if ( hook==NULL ) { - PERROR("Reason: %s\n", "/* There are no callback */"); + if ( trigger==NULL ) { + PERROR("Reason: %s\n", "/* There are no trigger */"); return -EFI_INVALID; } if ( wp.type& (~FI_WPTYPE_ALL_MASK) ) { @@ -113,9 +207,10 @@ /* Make sure there are no the same wp or id */ for (wi=0; wi<MAX_WP; wi++) { - if (wp_tb[wi].hook==NULL) continue; - if ((id==wp_tb[wi].id) || (addr==wp_tb[wi].wp.addr)) { - PERROR("Reason: %s\n", "/* there are same wp or id */"); + if (wp_tb[wi].trigger==NULL) continue; + if ((trigger==wp_tb[wi].trigger) || (addr==wp_tb[wi].wp.addr)){ + PERROR("Reason: %s\n", + "/* there are same wp or trigger */"); rv = -EFI_REGISTERED; goto err; } @@ -129,7 +224,7 @@ /* find empty item in wp_tb */ for (wi=0; wi<MAX_WP; wi++){ - if (wp_tb[wi].hook==NULL){ + if (wp_tb[wi].trigger==NULL){ break; } } @@ -142,12 +237,8 @@ /* register this wp into wp_tb*/ wp_tb[wi].wp.addr = addr; wp_tb[wi].wp.type = wp.type; - wp_tb[wi].id = id; - wp_tb[wi].hook = hook; + wp_tb[wi].trigger = trigger; - PDEBUG("register WP: index=%d, addr=0X%#lx, type=0x%x, id=%d, hook=0x%p\n", - wi, wp_tb[wi].wp.addr, wp_tb[wi].wp.type, - wp_tb[wi].id, wp_tb[wi].hook); err: pf_unlock_region_irqrestore(flags); fi_flush_tlb_all((unsigned long)addr); @@ -155,7 +246,7 @@ }; -int fi_pf_unregister(int id) { +int fi_pf_unregister(struct trigger *t) { unsigned long flags; int wi=0; int ri=0; @@ -165,7 +256,7 @@ /* find the id */ for (wi=0; wi<MAX_WP; wi++) { - if (wp_tb[wi].hook!=NULL && wp_tb[wi].id == id) { + if (wp_tb[wi].trigger == t) { break; } } @@ -183,8 +274,7 @@ wp_tb[wi].wp.addr = 0; wp_tb[wi].wp.type = 0; - wp_tb[wi].id = -1; - wp_tb[wi].hook = 0; + wp_tb[wi].trigger = 0; err: pf_unlock_region_irqrestore(flags); @@ -192,16 +282,6 @@ }; -/** - * This is a KEY data structure. When interceptor triggers DM - * and then DM call iAction method. iAction remembers this corrupted data. - * Then DM returns to Interceptor and Interceptor returns corrupted data - * to intercepted access. - */ -struct fi_corrupt{ - __u32 corrupted_data; -}; - int fi_pf_corrupt(int id, __u32 dirty, void *data){ ((struct fi_corrupt *)data)->corrupted_data = dirty; return 0; @@ -212,7 +292,7 @@ int i=0; for (i=0; i<MAX_WP; i++) { - if (wp_tb[i].hook == NULL) continue; + if (wp_tb[i].trigger == NULL) continue; if (addr == (unsigned long)wp_tb[i].wp.addr) { break; } @@ -235,12 +315,16 @@ static unsigned long crpt_mask[] = { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF}; +extern int fault_injection_enabled; int fi_page_fault(struct pt_regs * regs, unsigned long address) { unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int i; int ins_len, crpt_len; - + + if (!fault_injection_enabled) + return 0; + pf_lock_region(); //lock it! if (pf_find_region(address)<0) { if (pf_is_removed_regions(address)) { @@ -287,9 +371,8 @@ WP_LEN(wp_tb[i].wp):ins_len; crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; - (wp_tb[i].hook->trigger)( wp_tb[i].id, crpt.corrupted_data, - crpt_len, 0, &crpt); - + execute_trigger(wp_tb[i].trigger, crpt.corrupted_data, + crpt_len, 0, &crpt); set_ins_reg_val(pf_reason[cpu].eip, regs, (crpt.corrupted_data&crpt_mask[crpt_len-1]) | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); @@ -305,10 +388,10 @@ crpt_len = (WP_LEN(wp_tb[i].wp)<ins_len)? WP_LEN(wp_tb[i].wp):ins_len; - crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; - (wp_tb[i].hook->trigger)( wp_tb[i].id, crpt.corrupted_data, - crpt_len, 0, &crpt); - + crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; + execute_trigger(wp_tb[i].trigger, crpt.corrupted_data, + crpt_len, 0, &crpt); + set_ins_imm_val(pf_reason[cpu].eip, (crpt.corrupted_data&crpt_mask[crpt_len-1]) | (pf_reason[cpu].val&(~crpt_mask[crpt_len-1]))); @@ -346,6 +429,9 @@ unsigned long cpu = smp_processor_id(); struct fi_corrupt crpt; int ins_len, crpt_len; + + if (!fault_injection_enabled) + return 0; /* * DProbes make do_debug disallow irq. So we are safty from irq now. @@ -383,9 +469,9 @@ crpt_len = (WP_LEN(wp_tb[pf_reason[cpu].index].wp)<ins_len)? WP_LEN(wp_tb[pf_reason[cpu].index].wp):ins_len; crpt.corrupted_data = pf_reason[cpu].val & crpt_mask[crpt_len-1]; - (wp_tb[pf_reason[cpu].index].hook->trigger)( - wp_tb[pf_reason[cpu].index].id, crpt.corrupted_data, - crpt_len, 0, &crpt); + //(wp_tb[pf_reason[cpu].index].hook->trigger)( + //wp_tb[pf_reason[cpu].index].id, crpt.corrupted_data, + //crpt_len, 0, &crpt); set_ins_reg_val(pf_reason[cpu].eip, regs, (crpt.corrupted_data&crpt_mask[crpt_len-1]) @@ -417,11 +503,35 @@ return 0; }; +static void pf_arm(struct trigger *t) +{ + PDEBUG("arming %s trigger\n", t->kobj.name); + fi_pf_register(t->wp, t); +} + +static void pf_disarm(struct trigger *t) +{ + PDEBUG("disarming %s trigger\n", t->kobj.name); +} + +static struct interceptor pf_interceptor = { + .kobj = {.name = "pf_interceptor"}, + .type = INTERCEPTOR_TYPE_MMIO, + .arm = &pf_arm, + .disarm = &pf_disarm +}; + +extern int fi_register_interceptor(struct interceptor *); +static int __init pf_init(void) +{ + return fi_register_interceptor(&pf_interceptor); +} EXPORT_SYMBOL_NOVERS(fi_pf_register); EXPORT_SYMBOL_NOVERS(fi_pf_unregister); EXPORT_SYMBOL_NOVERS(fi_pf_corrupt); +module_init(pf_init); MODULE_AUTHOR("Louis Zhuang"); MODULE_DESCRIPTION("Pagefault interceptor component for FI"); diff -Nru a/include/linux/fi.h b/include/linux/fi.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/fi.h Sun Dec 15 21:33:50 2002 @@ -0,0 +1,56 @@ +#ifndef _FAULT_INJECTION_H +#define _FAULT_INJECTION_H +#if defined(__KERNEL__) + +#include <linux/kobject.h> +#include <linux/fi/fi.h> + +#define to_trigger(entry) container_of(entry,struct trigger,kobj.entry); +#define to_interceptor(entry)container_of(entry,struct interceptor,kobj.entry); + +typedef enum +{ + TRIGGER_OPCODE_NOTHING=0, + TRIGGER_OPCODE_SET=1, + TRIGGER_OPCODE_AND=2, + TRIGGER_OPCODE_OR=3, + TRIGGER_OPCODE_NOT=4, + TRIGGER_OPCODE_XOR=5, + TRIGGER_OPCODE_NAND=6, + TRIGGER_OPCODE_NOR=7, + TRIGGER_OPCODE_ADD=8, + TRIGGER_OPCODE_SUB=9, +} trigger_opcode_t; + +typedef enum +{ + INTERCEPTOR_TYPE_UNKNOWN=0, + INTERCEPTOR_TYPE_MMIO=1 +} interceptor_type_t; + +struct trigger { + struct watchpoint wp; + __u32 bitmask; + int min; + int max; + int skip; + int stop; + int protection; + int hertz; + int registered; + trigger_opcode_t opcode; + int operand; + atomic_t count; + interceptor_type_t type; + struct kobject kobj; +}; + +struct interceptor { + interceptor_type_t type; + void (*arm) (struct trigger *); + void (*disarm) (struct trigger *); + struct kobject kobj; +}; + +#endif /* __KERNEL__ */ +#endif /* _FAULT_INJECTION_H */ diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Sun Dec 15 21:33:50 2002 +++ b/kernel/Makefile Sun Dec 15 21:33:50 2002 @@ -4,7 +4,7 @@ export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ printk.o platform.o suspend.o dma.o module.o cpufreq.o \ - profile.o rcupdate.o intermodule.o kprobes.o + profile.o rcupdate.o intermodule.o kprobes.o fi_core.o obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ exit.o itimer.o time.o softirq.o resource.o \ diff -Nru a/kernel/fi_core.c b/kernel/fi_core.c --- a/kernel/fi_core.c Sun Dec 15 21:33:50 2002 +++ b/kernel/fi_core.c Sun Dec 15 21:33:50 2002 @@ -1,5 +1,6 @@ + /****************************************************************************** - * Fault Injection Test harness (FI) + * Fault Injection Core Functionality * Copyright (C) Intel Crop. * * This program is free software; you can redistribute it and/or @@ -17,508 +18,577 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************** + * + * This is a rewrite of code originally submitted by + * Louis Zhuang <lou...@in...>. I have moved the code from + * a ioctl based control using proc to expose information about + * fault injection data that was contained in fixed sized tables, + * to an extendable kobject based implementation that uses sysfs + * for all user space access. + * --rustyl + * + * Contributors: + * Louis Zhuang <lou...@in...> + * Stanley Wang <sta...@in...> + * Rusty Lynch <ru...@li...> */ -/* $Id: dm_core.c,v 1.3 2002/11/14 07:11:37 brlock Exp $ - * Copyright by Intel Crop., 2002 - * Louis Zhuang (lou...@in...) - */ -/** - * @file dm_core.c - */ - -#include <linux/config.h> -#include <linux/version.h> - -#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/version.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/atomic.h> -#include <asm/debugreg.h> -#include <asm/desc.h> -#include <linux/ioport.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <linux/sched.h> -#include <asm/system.h> -#include <linux/vmalloc.h> -#include <linux/proc_fs.h> -#include <linux/random.h> -#include <linux/highmem.h> #include <linux/kprobes.h> +#include <linux/slab.h> +#include <linux/kobject.h> #define PREFIX_NAME "FI" #include <linux/fi/fi.h> -#include <linux/fi/fi_internal.h> -#include <linux/fi/fi_interface.h> +#include <linux/fi.h> -#define MAX_MOD 16 +#ifdef CONFIG_FI_DEBUG +#define dbg(format, arg...) \ + do { \ + if(fi_debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + __FUNCTION__, ## arg); \ + } while(0) +#else +#define dbg(format, art...) +#endif +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format "\n", __FUNCTION__ , ## arg) + +static DECLARE_MUTEX(fi_sem); + +static struct subsystem fi_subsys; +static struct subsystem trigger_subsys; +static struct subsystem interceptor_subsys; + +static int is_initialized = 0; +int fault_injection_enabled = 0; +static int fi_debug = 1; + +int fi_register_interceptor(struct interceptor *); + +struct trigger_attribute { + struct attribute attr; + ssize_t (*show)(struct trigger *,char *,size_t,loff_t); +}; + +static struct trigger_attribute trigger_attr_wp; +static struct trigger_attribute trigger_attr_bitmask; +static struct trigger_attribute trigger_attr_min; +static struct trigger_attribute trigger_attr_max; +static struct trigger_attribute trigger_attr_skip; +static struct trigger_attribute trigger_attr_stop; +static struct trigger_attribute trigger_attr_protection; +static struct trigger_attribute trigger_attr_hertz; +static struct trigger_attribute trigger_attr_registered; +static struct trigger_attribute trigger_attr_opcode; +static struct trigger_attribute trigger_attr_operand; +static struct trigger_attribute trigger_attr_count; +static struct trigger_attribute trigger_attr_type; + +static inline void create_trigger_files(struct trigger *t) +{ + sysfs_create_file(&t->kobj, &trigger_attr_wp.attr); + sysfs_create_file(&t->kobj, &trigger_attr_bitmask.attr); + sysfs_create_file(&t->kobj, &trigger_attr_min.attr); + sysfs_create_file(&t->kobj, &trigger_attr_max.attr); + sysfs_create_file(&t->kobj, &trigger_attr_skip.attr); + sysfs_create_file(&t->kobj, &trigger_attr_stop.attr); + sysfs_create_file(&t->kobj, &trigger_attr_protection.attr); + sysfs_create_file(&t->kobj, &trigger_attr_hertz.attr); + sysfs_create_file(&t->kobj, &trigger_attr_registered.attr); + sysfs_create_file(&t->kobj, &trigger_attr_opcode.attr); + sysfs_create_file(&t->kobj, &trigger_attr_operand.attr); + sysfs_create_file(&t->kobj, &trigger_attr_count.attr); + sysfs_create_file(&t->kobj, &trigger_attr_type.attr); +} -#define MODULE_NAME "fi_dm" -#define MODULE_VERSION "0.1" +static inline void remove_trigger_files(struct trigger *t) +{ + sysfs_remove_file(&t->kobj, &trigger_attr_wp.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_bitmask.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_min.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_max.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_skip.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_stop.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_protection.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_hertz.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_registered.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_opcode.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_operand.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_count.attr); + sysfs_remove_file(&t->kobj, &trigger_attr_type.attr); +} -static int insert_faultset(struct fi_faultset *fs); -static int remove_faultset(int index); -static int enable_faultset(int index); -static int disable_faultset(int index); - - -static struct fi_faultset fs_tb[MAX_FAULTSET]; - -extern int fi_pf_register(struct watchpoint wp, int id, struct intercept_hook *hook); -extern int fi_pf_unregister(int id); -extern int fi_pf_corrupt(int id, __u32 dirty, void *data); - - -void dm_trigger(int id, __u32 val, int len, int type, void *data){ - int fs_num= FI_FS_NUM(id); - int tri_num=FI_TRI_NUM(id); - int tmp=0, i=0; - struct fi_trigger *tri = NULL; - __u32 old = val; - - PDEBUG("entry, id=%#x, val=%#x, len=%d, type=%d, data=%p\n", - id, val, len, type, data); - if (fs_num>=MAX_FAULTSET || fs_num<0 - || tri_num>=MAX_TRIGGER_PER_FAULTSET || tri_num<0){ - PERROR(":error id number %d\n", id); - goto exit; - } - - tri = &fs_tb[fs_num].trigger_tb[tri_num]; - - if (!tri->registered){ - PERROR("Should not trigger an unregistered wp %d!?\n", id); - } - - - get_random_bytes(&tmp, sizeof(tmp)); - if (tri->hertz==0) {tri->hertz=1;};//divid is not 0! - if (tmp >= 0xFFFFFFFF/tri->hertz){ - PDEBUG("rnd=%d, HERZ=%d\n", tmp, tri->hertz); - goto exit; - } - - tmp = val & (~tri->bitmask); - if (tri->min>tmp || tmp>=tri->max){ - PDEBUG("min=%d, max=%d, val=%d\n", tri->min, tri->max, val); - if(!(tri->min==0 && tri->max==0)) - goto exit; - } - - // Increase count only when passing all conditions - atomic_inc(&tri->count); - - if (tri->skip >= atomic_read(&tri->count)){ - PDEBUG("count=%d, skip=%d\n", atomic_read(&tri->count), tri->skip); - goto exit; - } - - if ( tri->stop!=0 && (tri->stop < (atomic_read(&tri->count)-tri->skip)) ) { - PDEBUG("count=%d, stop=%d\n", atomic_read(&tri->count), tri->stop); - goto exit; - } - - PDEBUG("count=%d, skip=%d, min=%d, max=%d, val=%d\n", - atomic_read(&tri->count), tri->skip, tri->min, tri->max, val); - tmp = val; - for (i=0; i<MAX_OP_PER_TRIGGER; i++) { - switch (tri->ops[i].opcode){ - case FI_NOTHING: - goto exit_for; - case FI_SET: - tmp = tri->ops[i].operand; - break; - case FI_AND: - tmp &= tri->ops[i].operand; - break; - case FI_OR: - tmp |= tri->ops[i].operand; - break; - case FI_NOT: - tmp = ~tmp; - break; - case FI_XOR: - tmp ^= tri->ops[i].operand; - break; - case FI_NAND: - tmp = ~(tmp & tri->ops[i].operand); - break; - case FI_NOR: - tmp = ~(tmp | tri->ops[i].operand); - break; - case FI_ADD: - tmp = tmp + tri->ops[i].operand; - break; - case FI_SUB: - tmp = tmp - tri->ops[i].operand; - break; - default: - PERROR("Not recognized opcode%d\n", tri->ops[i].opcode); - break; +static inline ssize_t add_trigger(struct trigger *t) +{ + struct list_head * entry; + struct interceptor * i; + struct trigger *n; + + n = kmalloc(sizeof(struct trigger),GFP_KERNEL); + if (!n) + return -ENOMEM; + memset(n,0,sizeof(struct trigger)); + + kobject_init(&n->kobj); + strncpy(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN); + n->kobj.subsys = &trigger_subsys; + n->wp.addr = t->wp.addr; + n->wp.type = t->wp.type; + n->bitmask = t->bitmask; + n->min = t->min; + n->max = t->max; + n->skip = t->skip; + n->stop = t->stop; + n->protection = t->protection; + n->hertz = t->hertz; + n->registered = t->registered; + n->opcode = t->opcode; + n->operand = t->operand; + n->type = t->type; + atomic_set(&n->count, 0); + + if (kobject_register(&n->kobj)) { + err("Unable to register kobject"); + return -EINVAL; + } + + create_trigger_files(n); + + list_for_each(entry,&interceptor_subsys.list) { + i = to_interceptor(entry); + if (i->type == n->type) { + (i->arm)(n); } } - exit_for: - val = (val & (tri->protection)) | (tmp & (~tri->protection)); + + return 0; +} - exit: +static inline ssize_t del_trigger(struct trigger *t) +{ + struct list_head * entry; + struct trigger * n; + + list_for_each(entry,&trigger_subsys.list) { + n = to_trigger(entry); + if (!strncmp(n->kobj.name, t->kobj.name, KOBJ_NAME_LEN)) { + dbg("comparing %s to %s", n->kobj.name, t->kobj.name); + remove_trigger_files(n); + kobject_unregister(&n->kobj); + return 0; + } + } - PINFO("id=%#x, val=%#x, old=%#x, len=%d, type=%d, data=%p\n", - id, val, old, len, type, data); - fi_pf_corrupt(id, val, data); - return; + err("trigger %s does not exist", t->kobj.name); + return -EINVAL; } -static struct intercept_hook intcpt_hook[1] = { - { - trigger: dm_trigger - } -}; - +/* + * =========================================================== + * <>-- Toplevel Containing Subsystem (fi_subsys) --<> + * ----------------------------------------------------------- + */ -/*manipulate fault set*/ -static int insert_faultset(struct fi_faultset *fs){ - int rv=0; - int i=0; +static ssize_t fi_enabled_show(struct subsystem * s, char * page, + size_t count, loff_t off) +{ + return off ? 0 : snprintf(page,count,"%i\n",fault_injection_enabled); +} - for (i=0; i<MAX_FAULTSET; i++) { - if (fs_tb[i].stat == NOUSED) break; +static ssize_t fi_enabled_store(struct subsystem * s, const char * page, + size_t count, loff_t off) +{ + int tmp = 0; + int num; + int ret = 0; + int error = 0; + + down(&fi_sem); + if (off) + goto Done; + + num = sscanf(page,"%i",&tmp); + if (!num) { + error = -EINVAL; + goto Done; } - if (i < MAX_FAULTSET) { - int rv1; - copy_from_user(&fs_tb[i], fs, sizeof(fs_tb[i])); - fs_tb[i].stat = DISABLED; - rv = i; - PINFO("insert #%d fs\n", i); - rv1 = enable_faultset(i); - if(rv1<0) { - PERROR("can not enable faultset# %d\n", i); - } - }else{ - rv = -ENOSPC; + + if (tmp) { + fault_injection_enabled = 1; + } else { + fault_injection_enabled = 0; } - return rv; -} -static int remove_faultset(int index){ - int rv=0; + ret = error ? error : count; + Done: + up(&fi_sem); + return ret; +} - if (index<0 || index>=MAX_FAULTSET || fs_tb[index].stat == NOUSED) { - rv = -EPERM; - goto exit1; - } - - if (index>=0 && index<MAX_FAULTSET && fs_tb[index].stat == ENABLED) { - disable_faultset(index); - } - - if (index<0 || index>=MAX_FAULTSET || fs_tb[index].stat == ENABLED) { - PERROR("can not remove #%d fs when it is enabled\n", index); - rv = -EPERM; - }else{ - fs_tb[index].stat = NOUSED; - } - PINFO("remove #%d fs\n", index); - exit1: - return rv; +static ssize_t fi_debug_show(struct subsystem * s, char * page, + size_t count, loff_t off) +{ + return off ? 0 : snprintf(page,count,"%i\n",fi_debug); } -static int enable_faultset(int index){ - int rv=0; - int i=0; - int id_high; - struct fi_faultset *fs; - - PDEBUG("trying to enable faultset# %d\n", index); - - if (index<0 || index>= MAX_FAULTSET || fs_tb[index].stat != DISABLED) { - rv = -EINVAL; - goto exit; - } - - id_high = index<<16; - fs = &fs_tb[index]; - /*register all wp into interceptor component*/ - for (i=0; i<MAX_TRIGGER_PER_FAULTSET && (fs->trigger_tb[i].wp.addr); i++){ - PDEBUG("register WP, id=%d, hook=%p\n", id_high+i, intcpt_hook); - atomic_set(&fs->trigger_tb[i].count, 0); - fs->trigger_tb[i].registered = 1; - rv = fi_pf_register(fs->trigger_tb[i].wp, id_high+i, intcpt_hook); +static ssize_t fi_debug_store(struct subsystem * s, const char * page, + size_t count, loff_t off) +{ + int tmp = 0; + int num; + int ret = 0; + int error = 0; + + down(&fi_sem); + if (off) + goto Done; + + num = sscanf(page,"%i",&tmp); + if (!num) { + error = -EINVAL; + goto Done; + } - if (rv<0) { - fs->trigger_tb[i].registered = 0; - PERROR("can not register WP, id = %d\n", id_high+i); - continue; //goto exit;//XXX: I should remove registered trigger - } - fs->stat = ENABLED; + if (tmp) { + fi_debug = 1; + } else { + fi_debug = 0; } - if (fs->stat == DISABLED) { - PERROR("none of trigger can be active, enable faultset failed!\n"); - goto exit; - } - PINFO("enable #%d fs\n", index); - rv = 0; - exit: - return rv; -} -static int disable_faultset(int index){ - int rv=0; - int i=0; - int id_high=0; - struct fi_faultset *fs; - - PDEBUG("trying to disable faultset# %d\n", index); - if(index<0 || index>MAX_FAULTSET || fs_tb[index].stat!=ENABLED) { - rv=-EINVAL; - goto exit; - } - - id_high=index<<16; - fs = &fs_tb[index]; - - for (i=0; i<MAX_TRIGGER_PER_FAULTSET && (fs->trigger_tb[i].wp.addr); i++){ - rv = fi_pf_unregister(id_high+i); - if (rv>=0) { - fs->trigger_tb[i].registered = 0; - }else{ - PERROR("can not unregister wp, id=%d\n", id_high+i); - } - } - fs->stat = DISABLED; - PINFO("disable #%d fs\n", index); - rv = 0; - exit: - return rv; + ret = error ? error : count; + Done: + up(&fi_sem); + return ret; } -/*END OF fault set functions*/ +static struct subsystem fi_subsys = { + .kobj = { .name = "fault_injection" }, +}; -static int fi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg){ - int rv=0; - int i=0; - - switch (cmd){ - default: - rv = -ENOTTY; - break; - case FIIOC_INSERT: - rv = insert_faultset((struct fi_faultset *)arg); - break; - case FIIOC_REMOVE: - get_user(i, (int *)arg); - rv = remove_faultset(i); - break; - case FIIOC_ENABLE: - get_user(i, (int *)arg); - rv = enable_faultset(i); - break; - case FIIOC_DISABLE: - get_user(i, (int *)arg); - rv = disable_faultset(i); - break; - }; - return rv; +static struct subsys_attribute fi_subsys_attr_enabled = { + .attr = { .name = "enabled", .mode = 0644 }, + .show = fi_enabled_show, + .store = fi_enabled_store, }; -static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED; -static int counter=0; +static struct subsys_attribute fi_subsys_attr_debug = { + .attr = { .name = "debug", .mode = 0644 }, + .show = fi_debug_show, + .store = fi_debug_store, +}; -static int fi_open(struct inode *inode, struct file *file){ - int rv=0; - - spin_lock(&counter_lock); - if (counter) { - rv = -1; - goto out; - } - counter++; - MOD_INC_USE_COUNT; - out: - spin_unlock(&counter_lock); - return rv; -} +/* + * =============================================================== + * <>-- Interceptor Containing Subsystem (interceptor_subsys) --<> + * --------------------------------------------------------------- + */ + +static struct subsystem interceptor_subsys = { + .kobj = { .name = "interceptors" }, + .parent = &fi_subsys, +}; +/* + * =========================================================== + * <>-- Trigger Subsystem (trigger_subsys) --<> + * ----------------------------------------------------------- + */ -static int fi_release(struct inode *inode, struct file *file){ - spin_lock(&counter_lock); - counter--; - MOD_DEC_USE_COUNT; - spin_unlock(&counter_lock); - return 0; +static ssize_t trigger_attr_show(struct kobject * kobj, + struct attribute * attr, + char * page, size_t count, + loff_t off) +{ + struct trigger * n = container_of(kobj,struct trigger,kobj); + struct trigger_attribute * trigger_attr = + container_of(attr,struct trigger_attribute,attr); + + dbg("about to call show function for %s", trigger_attr->attr.name); + return trigger_attr->show ? trigger_attr->show(n,page,count,off) : 0; } -static int dump_faultset(struct fi_faultset *fs, char *buf){ - int i=0, n=0; - int rv=0; - static char *op_name[]={ - "NOTHING", "SET", "AND", "OR", "NOT", "XOR", "NAND", "NOR", "ADD", "SUB", - }; - - if (fs->stat == NOUSED){ - n += sprintf(buf+n, "This faultset is not used!\n"); - goto exit1; - } - - n += sprintf( buf+n, "This will dump fault set information, stat=%d\n", - fs->stat); - n += sprintf( buf+n, "The faultset is %s\n", - (fs->stat==ENABLED)? "ENABLED" : - ((fs->stat==DISABLED)? "DISABLED": - "UNKNOWN!")); - for(i=0; i<MAX_TRIGGER_PER_FAULTSET; i++){ - int j=0; - struct fi_trigger *tri; - - tri = &fs->trigger_tb[i]; - if (tri->wp.addr==0) break; - n += sprintf(buf+n, "watchpoint #%d phy_addr=%#lx, type=%#x, len=%d\n", - i, tri->wp.addr, tri->wp.type, access_len(tri->wp.type)); - n += sprintf(buf+n, "bitmask=%#x, min=%#x, max=%#x, skip=%d, " - "stop=%d, protection=%#x, Hertz=%#x\n", - tri->bitmask, tri->min, tri->max, tri->skip, - tri->stop, tri->protection, tri->hertz); - - n += sprintf(buf+n, "ops list\n"); - for(j=0; j<MAX_OP_PER_TRIGGER; j++){ - if (tri->ops[j].opcode==FI_NOTHING) break; - n += sprintf(buf+n, "opcode=%s, operand=%#x\n", - op_name[tri->ops[j].opcode], tri->ops[j].operand); - } - - if (is_MMIO(tri->wp.type)) { - n += sprintf(buf+n, "watchpoint status:%s\n", - (tri->registered==1) ? - "ENABLED" : "DISABLED"); - } else { - n += sprintf(buf+n, "watchpoint status:%s\n", - (tri->registered==1) ? "ENABLED" : "DISABLED"); - } +static ssize_t trigger_wp_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("wp.addr = %#lx, wp.type = %#x", p->wp.addr, p->wp.type); + return off ? 0 : snprintf(page,count,"%#lx %#x\n", + p->wp.addr,p->wp.type); +} +static struct trigger_attribute trigger_attr_wp = { + .attr = { .name = "wp", .mode = S_IRUGO }, + .show = trigger_wp_read, +}; - n += sprintf(buf+n, "-----------------\n"); - } - - exit1: - n += sprintf(buf+n, "\n"); - rv = n; - return rv; +static ssize_t trigger_bitmask_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("bitmask = %#x", p->bitmask); + return off ? 0 : snprintf(page,count,"%#x\n",p->bitmask); } +static struct trigger_attribute trigger_attr_bitmask = { + .attr = { .name = "bitmask", .mode = S_IRUGO }, + .show = trigger_bitmask_read, +}; -static int fi_proc_read( char* page, char **start, off_t off, int count, int *eof, void *data){ - return dump_faultset((struct fi_faultset *)data, page); +static ssize_t trigger_min_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("min = %i", p->min); + return off ? 0 : snprintf(page,count,"%i\n",p->min); +} +static struct trigger_attribute trigger_attr_min = { + .attr = { .name = "min", .mode = S_IRUGO }, + .show = trigger_min_read, }; -static int fi_proc_write( struct file *file, const char *buffer, unsigned long count, void *data){ - return 0;//dummy now :-) +static ssize_t trigger_max_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("max = %i", p->max); + return off ? 0 : snprintf(page,count,"%i\n",p->max); +} +static struct trigger_attribute trigger_attr_max = { + .attr = { .name = "max", .mode = S_IRUGO }, + .show = trigger_max_read, }; -static struct file_operations fi_fops[1]={ - { - owner: THIS_MODULE, - ioctl: fi_ioctl, - open: fi_open, - release: fi_release - } +static ssize_t trigger_skip_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("skip = %i", p->skip); + return off ? 0 : snprintf(page,count,"%i\n",p->skip); +} +static struct trigger_attribute trigger_attr_skip = { + .attr = { .name = "skip", .mode = S_IRUGO }, + .show = trigger_skip_read, }; +static ssize_t trigger_stop_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("stop = %i", p->stop); + return off ? 0 : snprintf(page,count,"%i\n",p->stop); +} +static struct trigger_attribute trigger_attr_stop = { + .attr = { .name = "stop", .mode = S_IRUGO }, + .show = trigger_stop_read, +}; -static struct proc_dir_entry *root_entry; -static struct proc_dir_entry *fs_entry; -static int fi_major = FI_MAJOR; +static ssize_t trigger_protection_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("protection = %i", p->protection); + return off ? 0 : snprintf(page,count,"%i\n",p->protection); +} +static struct trigger_attribute trigger_attr_protection = { + .attr = { .name = "protection", .mode = S_IRUGO }, + .show = trigger_protection_read, +}; -static int __init fi_dm_init(void){ - int i=0 ; - int rv=0; - - PDEBUG("FI version: %s\n", FI_VERSION); +static ssize_t trigger_hertz_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("hertz = %i", p->hertz); + return off ? 0 : snprintf(page,count,"%i\n",p->hertz); +} +static struct trigger_attribute trigger_attr_hertz = { + .attr = { .name = "hertz", .mode = S_IRUGO }, + .show = trigger_hertz_read, +}; - /*Setup proc file*/ - root_entry = proc_mkdir(MODULE_NAME, NULL); - if (!root_entry){ - PERROR("can not register proc %s\n", MODULE_NAME); - rv = -ENOMEM; - goto exit1; - } - root_entry->owner=THIS_MODULE; - - for (i=0; i<MAX_FAULTSET; i++){ - char name[20]; - - sprintf(name, "fs%d", i); - fs_entry = create_proc_entry(name, 0644, root_entry); - if (!fs_entry){ - PERROR("can not register proc %s\n", name); - rv = -ENOMEM; - goto exit2; - } - fs_entry->owner = THIS_MODULE; - fs_entry->read_proc = fi_proc_read; - fs_entry->write_proc= fi_proc_write; - fs_entry->data = &fs_tb[i]; - } - - rv = register_chrdev(fi_major, MODULE_NAME, fi_fops); - if (rv<0){ - PERROR("can not register device, major=%d\n", fi_major); - goto exit3; - } - if (fi_major==0) fi_major = rv;/*dynamic alloc major number*/ - PDEBUG("Setup IOCTL as char device, major=%d\n", fi_major); - - /*clear fs_tb */ - memset(fs_tb, 0, sizeof(fs_tb)); - EXPORT_NO_SYMBOLS; - return 0; +static ssize_t trigger_registered_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("registered = %i", p->registered); + return off ? 0 : snprintf(page,count,"%i\n",p->registered); +} +static struct trigger_attribute trigger_attr_registered = { + .attr = { .name = "registered", .mode = S_IRUGO }, + .show = trigger_registered_read, +}; - exit3: - - i=MAX_FAULTSET;/* error happen above 2, you must clear ALL entries*/ - exit2: - i--; - for (;i>=0;i--){ - char name[20]; +static ssize_t trigger_count_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("count = %i", atomic_read(&p->count)); + return off ? 0 : snprintf(page,count,"%i\n",atomic_read(&p->count)); +} +static struct trigger_attribute trigger_attr_count = { + .attr = { .name = "count", .mode = S_IRUGO }, + .show = trigger_count_read, +}; - sprintf(name, "fs%d", i); - remove_proc_entry(name, root_entry); +static ssize_t trigger_type_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + int rv; + + dbg("type = %i", p->type); + if (off) + return 0; + + switch (p->type) { + case INTERCEPTOR_TYPE_MMIO: + rv = snprintf(page,count,"MMIO\n"); + break; + default: + rv = snprintf(page,count,"UNKNOWN\n"); } - remove_proc_entry(MODULE_NAME, NULL); - exit1: + return rv; +} +static struct trigger_attribute trigger_attr_type = { + .attr = { .name = "type", .mode = S_IRUGO }, + .show = trigger_type_read, }; +static ssize_t trigger_opcode_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("opcode = %i", p->opcode); + return off ? 0 : snprintf(page,count,"%i\n",p->opcode); +} +static struct trigger_attribute trigger_attr_opcode = { + .attr = { .name = "opcode", .mode = S_IRUGO }, + .show = trigger_opcode_read, +}; -static void __exit fi_dm_cleanup(void){ - int i=0; +static ssize_t trigger_operand_read(struct trigger * p, char * page, + size_t count, loff_t off) +{ + dbg("operand = %i", p->operand); + return off ? 0 : snprintf(page,count,"%i\n",p->operand); +} +static struct trigger_attribute trigger_attr_operand = { + .attr = { .name = "operand", .mode = S_IRUGO }, + .show = trigger_operand_read, +}; - unregister_chrdev(fi_major, MODULE_NAME); - - /*unregister proc files*/ - remove_proc_entry("globalcounter", root_entry); - for (i=MAX_FAULTSET-1;i>=0;i--){ - char name[20]; - - sprintf(name, "fs%d", i); - remove_proc_entry(name, root_entry); +static ssize_t trigger_ctl_show(struct subsystem * s, char * page, + size_t count, loff_t off) +{ + return 0; +} +static ssize_t trigger_ctl_store(struct subsystem * s, const char * page, + size_t count, loff_t off) +{ + char ctl[16]; + char type[16]; + int num; + int error; + int ret = 0; + struct trigger tmp; + + if (off) + return 0; + + /* 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 */ + /* ctl nm tp wa wb bm mn mx sk st pt hz rg oc oa */ + num = sscanf(page,"%15s %s %s %lx %x %x %i %i %i %i %i %i %i %i %i", + ctl, /* 3 */ + tmp.kobj.name, /* 4 */ + type, /* 5 */ + &tmp.wp.addr, /* 6 */ + &tmp.wp.type, /* 7 */ + &tmp.bitmask, /* 8 */ + &tmp.min, /* 9 */ + &tmp.max, /* 10 */ + &tmp.skip, /* 11 */ + &tmp.stop, /* 12 */ + &tmp.protection, /* 13 */ + &tmp.hertz, /* 14 */ + &tmp.registered, /* 15 */ + (int *)&tmp.opcode, /* 16 */ + &tmp.operand); /* 17 */ + if (!num) { + err("Invalid command format, translated no commands"); + error = -EINVAL; + goto Done; } - remove_proc_entry(MODULE_NAME, NULL); + + dbg("type = '%s'", type); + if (!strncmp(type, "MMIO", 4)) + tmp.type = INTERCEPTOR_TYPE_MMIO; + else + tmp.type = INTERCE... [truncated message content] |
From: Rusty L. <ru...@li...> - 2002-12-16 05:06:11
|
excellent. If we can start getting regular results posted then we can get a clue as to what kind of overhead we are causing. Seems like something that could be automated if you have the hardware available. --rusty ----- Original Message ----- From: "Wang, Stanley" <sta...@in...> To: "Lynch, Rusty" <rus...@in...>; "Zhuang, Louis" <louis.zhuang= @intel.com>; "Gao, Kevin" <kev...@in...>; "'Rusty Lynch'" <ru...@li...>; <fau...@li...ur= ceforge.net> Sent: Sunday, December 15, 2002 8:56 PM Subject: RE: [Fault-injection-developer] Need for benchmarking > We've download "lmbench". And it may help us :) > > Stan > > > -----Original Message----- > > From: Lynch, Rusty [mailto:rus...@in...] > > Sent: 2002=C4=EA12=D4=C216=C8=D5 11:54 > > To: Zhuang, Louis; Gao, Kevin; 'Rusty Lynch'; > > fau...@li... > > Subject: RE: [Fault-injection-developer] Need for benchmarking > > > > > > Does LTP contain a benchmarking tool? We could definitely > > run it to make sure we didn't accidentally break something > > else in the kernel. > > > > BTW, do not overlook using STP on OSDL as a testing tool. > > It's easy to use and there are a bunch of machines waiting > > to be utilized. > > > > -rusty > > > > > -----Original Message----- > > > From: Zhuang, Louis [mailto:lou...@in...] > > > Sent: Sunday, December 15, 2002 4:45 PM > > > To: Gao, Kevin; 'Rusty Lynch'; > > > fau...@li... > > > Subject: RE: [Fault-injection-developer] Need for benchmarking > > > > > > > > > Maybe we can use LTP to test performance. > > > > > > -----Original Message----- > > > From: Gao, Kevin [mailto:kev...@in...] > > > Sent: Monday, December 16, 2002 8:31 AM > > > To: 'Rusty Lynch'; fau...@li... > > > Subject: RE: [Fault-injection-developer] Need for benchmarking > > > > > > We can do some tiny program to test the time of MMIO read, > > > write operation in such situation: > > > > > > common kernel. > > > Kernel with our FITH, but no faultset. > > > Kernel with our FITH, but the address of faultset is not > > > associate with the > > > operation. > > > Kernel with our FITH, corresponding faultset but no action. > > > Kernel with our FITH, and injection corresponding fault into > > > the operation. > > > > > > Any other ideas? > > > > > > Kevin > > > > > > > > > -----Original Message----- > > > From: Rusty Lynch [mailto:ru...@li...] > > > Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 > > > To: fau...@li... > > > Subject: [Fault-injection-developer] Need for benchmarking > > > > > > > > > We could use some standardized benchmarking to > > > periodically run on our code base to get a feel for how > > > much overhead our changes are adding. > > > > > > For example our current code adds a hook to the > > > page fault handler. It would be really easy to thrash > > > the kernel with even the smallest of tweaks to that > > > code. > > > > > > Any idea's? Kevin, have planned on putting something > > > together? > > > > > > -rustyl > > > > > > > > > ------------------------------------------------------- > > > This sf.net email is sponsored by: > > > With Great Power, Comes Great Responsibility > > > Learn to use your power at OSDN's High Performance Computing Channe= l > > > http://hpc.devchannel.org/ > > > _______________________________________________ > > > Fault-injection-developer mailing list > > > Fau...@li... > > > > > https://lists.sourceforge.net/lists/listinfo/fault-injection-develope= r > > > > > > > > > ------------------------------------------------------- > > > This sf.net email is sponsored by: > > > With Great Power, Comes Great Responsibility > > > Learn to use your power at OSDN's High Performance Computing Channe= l > > > http://hpc.devchannel.org/ > > > _______________________________________________ > > > Fault-injection-developer mailing list > > > Fau...@li... > > > > > https://lists.sourceforge.net/lists/listinfo/fault-injection-develope= r > > > > > > > > > ------------------------------------------------------- > > > This sf.net email is sponsored by: > > > With Great Power, Comes Great Responsibility > > > Learn to use your power at OSDN's High Performance Computing Channe= l > > > http://hpc.devchannel.org/ > > > _______________________________________________ > > > Fault-injection-developer mailing list > > > Fau...@li... > > > > > https://lists.sourceforge.net/lists/listinfo/fault-injection-develope= r > > > > > > > > > ------------------------------------------------------- > > This sf.net email is sponsored by: > > With Great Power, Comes Great Responsibility > > Learn to use your power at OSDN's High Performance Computing Channel > > http://hpc.devchannel.org/ > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > > https://lists.sourceforge.net/lists/listinfo/fault-injection-develope= r > > > > > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Wang, S. <sta...@in...> - 2002-12-16 04:58:35
|
We've download "lmbench". And it may help us :) Stan > -----Original Message----- > From: Lynch, Rusty [mailto:rus...@in...] > Sent: 2002=C4=EA12=D4=C216=C8=D5 11:54 > To: Zhuang, Louis; Gao, Kevin; 'Rusty Lynch'; > fau...@li... > Subject: RE: [Fault-injection-developer] Need for benchmarking >=20 >=20 > Does LTP contain a benchmarking tool? We could definitely=20 > run it to make sure we didn't accidentally break something=20 > else in the kernel. >=20 > BTW, do not overlook using STP on OSDL as a testing tool. > It's easy to use and there are a bunch of machines waiting > to be utilized. >=20 > -rusty >=20 > > -----Original Message----- > > From: Zhuang, Louis [mailto:lou...@in...] > > Sent: Sunday, December 15, 2002 4:45 PM > > To: Gao, Kevin; 'Rusty Lynch';=20 > > fau...@li... > > Subject: RE: [Fault-injection-developer] Need for benchmarking > >=20 > >=20 > > Maybe we can use LTP to test performance. > >=20 > > -----Original Message----- > > From: Gao, Kevin [mailto:kev...@in...] > > Sent: Monday, December 16, 2002 8:31 AM > > To: 'Rusty Lynch'; fau...@li... > > Subject: RE: [Fault-injection-developer] Need for benchmarking > >=20 > > We can do some tiny program to test the time of MMIO read, > > write operation in such situation: > >=20 > > common kernel. > > Kernel with our FITH, but no faultset. > > Kernel with our FITH, but the address of faultset is not=20 > > associate with the > > operation. > > Kernel with our FITH, corresponding faultset but no action. > > Kernel with our FITH, and injection corresponding fault into=20 > > the operation. > >=20 > > Any other ideas? > >=20 > > Kevin > >=20 > >=20 > > -----Original Message----- > > From: Rusty Lynch [mailto:ru...@li...] > > Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 > > To: fau...@li... > > Subject: [Fault-injection-developer] Need for benchmarking > >=20 > >=20 > > We could use some standardized benchmarking to > > periodically run on our code base to get a feel for how > > much overhead our changes are adding. > >=20 > > For example our current code adds a hook to the > > page fault handler. It would be really easy to thrash > > the kernel with even the smallest of tweaks to that > > code. > >=20 > > Any idea's? Kevin, have planned on putting something > > together? > >=20 > > -rustyl > >=20 > >=20 > > ------------------------------------------------------- > > This sf.net email is sponsored by: > > With Great Power, Comes Great Responsibility > > Learn to use your power at OSDN's High Performance Computing = Channel > > http://hpc.devchannel.org/ > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > >=20 > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > >=20 > >=20 > > ------------------------------------------------------- > > This sf.net email is sponsored by: > > With Great Power, Comes Great Responsibility > > Learn to use your power at OSDN's High Performance Computing = Channel > > http://hpc.devchannel.org/ > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > >=20 > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > >=20 > >=20 > > ------------------------------------------------------- > > This sf.net email is sponsored by: > > With Great Power, Comes Great Responsibility=20 > > Learn to use your power at OSDN's High Performance Computing = Channel > > http://hpc.devchannel.org/ > > _______________________________________________ > > Fault-injection-developer mailing list > > Fau...@li... > >=20 > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > >=20 >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility=20 > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Lynch, R. <rus...@in...> - 2002-12-16 03:54:09
|
Does LTP contain a benchmarking tool? We could definitely=20 run it to make sure we didn't accidentally break something=20 else in the kernel. BTW, do not overlook using STP on OSDL as a testing tool. It's easy to use and there are a bunch of machines waiting to be utilized. -rusty > -----Original Message----- > From: Zhuang, Louis [mailto:lou...@in...] > Sent: Sunday, December 15, 2002 4:45 PM > To: Gao, Kevin; 'Rusty Lynch';=20 > fau...@li... > Subject: RE: [Fault-injection-developer] Need for benchmarking >=20 >=20 > Maybe we can use LTP to test performance. >=20 > -----Original Message----- > From: Gao, Kevin [mailto:kev...@in...] > Sent: Monday, December 16, 2002 8:31 AM > To: 'Rusty Lynch'; fau...@li... > Subject: RE: [Fault-injection-developer] Need for benchmarking >=20 > We can do some tiny program to test the time of MMIO read, > write operation in such situation: >=20 > common kernel. > Kernel with our FITH, but no faultset. > Kernel with our FITH, but the address of faultset is not=20 > associate with the > operation. > Kernel with our FITH, corresponding faultset but no action. > Kernel with our FITH, and injection corresponding fault into=20 > the operation. >=20 > Any other ideas? >=20 > Kevin >=20 >=20 > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 > To: fau...@li... > Subject: [Fault-injection-developer] Need for benchmarking >=20 >=20 > We could use some standardized benchmarking to > periodically run on our code base to get a feel for how > much overhead our changes are adding. >=20 > For example our current code adds a hook to the > page fault handler. It would be really easy to thrash > the kernel with even the smallest of tweaks to that > code. >=20 > Any idea's? Kevin, have planned on putting something > together? >=20 > -rustyl >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility=20 > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Lynch, R. <rus...@in...> - 2002-12-16 03:51:18
|
There have been people posting benchmarking results on LKML. I haven't = looked into the results or which tool they are using to generate the results, but I am guessing that they would do the job. The iterations you listed sound fine. -rustyl > -----Original Message----- > From: Gao, Kevin [mailto:kev...@in...] > Sent: Sunday, December 15, 2002 4:31 PM > To: 'Rusty Lynch'; fau...@li... > Subject: RE: [Fault-injection-developer] Need for benchmarking >=20 >=20 > We can do some tiny program to test the time of MMIO read, > write operation in such situation: >=20 > common kernel. > Kernel with our FITH, but no faultset. > Kernel with our FITH, but the address of faultset is not=20 > associate with the > operation. > Kernel with our FITH, corresponding faultset but no action. > Kernel with our FITH, and injection corresponding fault into=20 > the operation. >=20 > Any other ideas? >=20 > Kevin >=20 >=20 > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...]=20 > Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 > To: fau...@li... > Subject: [Fault-injection-developer] Need for benchmarking >=20 >=20 > We could use some standardized benchmarking to=20 > periodically run on our code base to get a feel for how > much overhead our changes are adding. >=20 > For example our current code adds a hook to the > page fault handler. It would be really easy to thrash > the kernel with even the smallest of tweaks to that > code. >=20 > Any idea's? Kevin, have planned on putting something > together? >=20 > -rustyl=20 >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility=20 > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility=20 > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Rusty L. <ru...@li...> - 2002-12-16 03:25:03
|
I have been hacking around with a rewrite of fi_core that uses kobjects for managing data (instead of the existing tables), and sysfs for control (instead of iocts). It also changes how an interceptor registers with core fault injection. I'm in the process of fixing up pf.c to work with the new implementation. This is just a heads up. I will be posting a patch in a couple of hours, and then then start making an argument for the directional move. BTW, there is no longer an IRC server on developer.osdl.org (which for you Intel folk is the one the proxy points too). I am using irc.ozona.org (which is the one the web page points to.) -rusty |
From:
<kan...@jp...> - 2002-12-16 02:57:40
|
On Sun, 15 Dec 2002 18:54:38 -0800 fau...@li... wrote: > Fault-injection-developer -- confirmation of subscription -- request > 406082 > > We have received a request from 192.51.44.10 for subscription of your > email address, <kan...@jp...>, to the > fau...@li... mailing list. To > confirm the request, please send a message to > fau...@li..., and either: > > - maintain the subject line as is (the reply's additional "Re:" is > ok), > > - or include the following line - and only the following line - in the > message body: > > confirm 406082 > > (Simply sending a 'reply' to this message should work from most email > interfaces, since that usually leaves the subject line in the right > form.) > > If you do not wish to subscribe to this list, please simply disregard > this message. Send questions to > fau...@li.... -- 金重 憲治 富士通株式会社 BCCシステム推進室 BCCプロジェクト推進部 Tel : 055-924-7241 (内線7551-5726) Mail: kan...@jp..., kan...@so... |
From: Zhuang, L. <lou...@in...> - 2002-12-16 02:41:20
|
I've check fith-tool into repository. You can download it from http://fault-injection.bkbits.net/fith-tool/ -----Original Message----- From: Wang, Stanley [mailto:sta...@in...] Sent: Monday, December 16, 2002 8:30 AM To: 'Rusty Lynch'; fau...@li... Subject: RE: [Fault-injection-developer] Who is working on what Hi, Rusty I'm interested in implementing IRQ and IO/MMIO interceptor. Could add my name in your task list :) Thanks, Stan > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: 2002=E5=B9=B412=E6=9C=8814=E6=97=A5 0:16 > To: fau...@li... > Subject: [Fault-injection-developer] Who is working on what > > > Anybody can work on any part of the code base they > want, but as more people join the effort we really need > some place to document who is working on what and > probably who owns what sections. > > So far I know: > * GOTO Yasunori (welcome aboard!) would like to > work on either a a PCI configuration interceptor or a > code segment caller > * Louis have been volunteering to publish snapshots > > ... there is a lot more going on. How about people > respond to this email and I will compile a list to either > post on the website or periodically send to this list > (since it will be a very dynamic list) > > Note: I once had a discussion with Alan Robertson > about how he running the Linux-HA project, and he > had practical view of what his role in the project was. > Basically he was responsible for doing all the work > that needed to be done, but wasn't all that fun (and > therefore nobody volunteered to do the work) > > -rustyl > > > > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer > ------------------------------------------------------- This sf.net email is sponsored by: With Great Power, Comes Great Responsibility Learn to use your power at OSDN's High Performance Computing Channel http://hpc.devchannel.org/ _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Gao, K. <kev...@in...> - 2002-12-16 00:54:26
|
Yes, great idea! -----Original Message----- From: Zhuang, Louis=20 Sent: 2002=C4=EA12=D4=C216=C8=D5 8:45 To: Gao, Kevin; 'Rusty Lynch'; fau...@li... Subject: RE: [Fault-injection-developer] Need for benchmarking Maybe we can use LTP to test performance. -----Original Message----- From: Gao, Kevin [mailto:kev...@in...] Sent: Monday, December 16, 2002 8:31 AM To: 'Rusty Lynch'; fau...@li... Subject: RE: [Fault-injection-developer] Need for benchmarking We can do some tiny program to test the time of MMIO read, write operation in such situation: common kernel. Kernel with our FITH, but no faultset. Kernel with our FITH, but the address of faultset is not associate with = the operation. Kernel with our FITH, corresponding faultset but no action. Kernel with our FITH, and injection corresponding fault into the = operation. Any other ideas? Kevin -----Original Message----- From: Rusty Lynch [mailto:ru...@li...] Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 To: fau...@li... Subject: [Fault-injection-developer] Need for benchmarking We could use some standardized benchmarking to periodically run on our code base to get a feel for how much overhead our changes are adding. For example our current code adds a hook to the page fault handler. It would be really easy to thrash the kernel with even the smallest of tweaks to that code. Any idea's? Kevin, have planned on putting something together? -rustyl ------------------------------------------------------- This sf.net email is sponsored by: With Great Power, Comes Great Responsibility Learn to use your power at OSDN's High Performance Computing Channel http://hpc.devchannel.org/ _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer ------------------------------------------------------- This sf.net email is sponsored by: With Great Power, Comes Great Responsibility Learn to use your power at OSDN's High Performance Computing Channel http://hpc.devchannel.org/ _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Zhuang, L. <lou...@in...> - 2002-12-16 00:47:37
|
Maybe we can use LTP to test performance. -----Original Message----- From: Gao, Kevin [mailto:kev...@in...] Sent: Monday, December 16, 2002 8:31 AM To: 'Rusty Lynch'; fau...@li... Subject: RE: [Fault-injection-developer] Need for benchmarking We can do some tiny program to test the time of MMIO read, write operation in such situation: common kernel. Kernel with our FITH, but no faultset. Kernel with our FITH, but the address of faultset is not associate with = the operation. Kernel with our FITH, corresponding faultset but no action. Kernel with our FITH, and injection corresponding fault into the = operation. Any other ideas? Kevin -----Original Message----- From: Rusty Lynch [mailto:ru...@li...] Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 To: fau...@li... Subject: [Fault-injection-developer] Need for benchmarking We could use some standardized benchmarking to periodically run on our code base to get a feel for how much overhead our changes are adding. For example our current code adds a hook to the page fault handler. It would be really easy to thrash the kernel with even the smallest of tweaks to that code. Any idea's? Kevin, have planned on putting something together? -rustyl ------------------------------------------------------- This sf.net email is sponsored by: With Great Power, Comes Great Responsibility Learn to use your power at OSDN's High Performance Computing Channel http://hpc.devchannel.org/ _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer ------------------------------------------------------- This sf.net email is sponsored by: With Great Power, Comes Great Responsibility Learn to use your power at OSDN's High Performance Computing Channel http://hpc.devchannel.org/ _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Gao, K. <kev...@in...> - 2002-12-16 00:33:10
|
We can do some tiny program to test the time of MMIO read, write operation in such situation: common kernel. Kernel with our FITH, but no faultset. Kernel with our FITH, but the address of faultset is not associate with = the operation. Kernel with our FITH, corresponding faultset but no action. Kernel with our FITH, and injection corresponding fault into the = operation. Any other ideas? Kevin -----Original Message----- From: Rusty Lynch [mailto:ru...@li...]=20 Sent: 2002=C4=EA12=D4=C214=C8=D5 0:36 To: fau...@li... Subject: [Fault-injection-developer] Need for benchmarking We could use some standardized benchmarking to=20 periodically run on our code base to get a feel for how much overhead our changes are adding. For example our current code adds a hook to the page fault handler. It would be really easy to thrash the kernel with even the smallest of tweaks to that code. Any idea's? Kevin, have planned on putting something together? -rustyl=20 ------------------------------------------------------- This sf.net email is sponsored by: With Great Power, Comes Great Responsibility=20 Learn to use your power at OSDN's High Performance Computing Channel http://hpc.devchannel.org/ _______________________________________________ Fault-injection-developer mailing list Fau...@li... https://lists.sourceforge.net/lists/listinfo/fault-injection-developer |
From: Wang, S. <sta...@in...> - 2002-12-16 00:32:44
|
Hi, Rusty I'm interested in implementing IRQ and IO/MMIO interceptor.=20 Could add my name in your task list :) Thanks, Stan > -----Original Message----- > From: Rusty Lynch [mailto:ru...@li...] > Sent: 2002=E5=B9=B412=E6=9C=8814=E6=97=A5 0:16 > To: fau...@li... > Subject: [Fault-injection-developer] Who is working on what >=20 >=20 > Anybody can work on any part of the code base they=20 > want, but as more people join the effort we really need=20 > some place to document who is working on what and=20 > probably who owns what sections. >=20 > So far I know: > * GOTO Yasunori (welcome aboard!) would like to=20 > work on either a a PCI configuration interceptor or a=20 > code segment caller > * Louis have been volunteering to publish snapshots >=20 > ... there is a lot more going on. How about people=20 > respond to this email and I will compile a list to either=20 > post on the website or periodically send to this list=20 > (since it will be a very dynamic list) >=20 > Note: I once had a discussion with Alan Robertson > about how he running the Linux-HA project, and he > had practical view of what his role in the project was. > Basically he was responsible for doing all the work > that needed to be done, but wasn't all that fun (and > therefore nobody volunteered to do the work) >=20 > -rustyl=20 >=20 >=20 >=20 > ------------------------------------------------------- > This sf.net email is sponsored by: > With Great Power, Comes Great Responsibility=20 > Learn to use your power at OSDN's High Performance Computing Channel > http://hpc.devchannel.org/ > _______________________________________________ > Fault-injection-developer mailing list > Fau...@li... > = https://lists.sourceforge.net/lists/listinfo/fault-injection-developer >=20 |
From: Rusty L. <ru...@li...> - 2002-12-13 16:36:13
|
We could use some standardized benchmarking to periodically run on our code base to get a feel for how much overhead our changes are adding. For example our current code adds a hook to the page fault handler. It would be really easy to thrash the kernel with even the smallest of tweaks to that code. Any idea's? Kevin, have planned on putting something together? -rustyl |