Implement a lock-free way to lookup modules when unwind stack.
The idea is use a SLIST to store all the necessary information regarding to
the modules. In unwind context, the information can be accessed without lock.
Differential D4244
Implement a lock-free way to lookup modules when unwind stack. howard0su_gmail.com on Nov 22 2015, 1:09 AM. Authored by Tags None Referenced Files
Details
Implement a lock-free way to lookup modules when unwind stack. The idea is use a SLIST to store all the necessary information regarding to
Diff Detail
Event Timeline
Comment Actions Declare type for malloc(9) Comment Actions I agreed with Andrew's comments but once they're addressed this should be good to go in. Always a good idea to add markj@ to these reviews, as I just did. Also, what hardware was this tested on? Comment Actions I only tested in my BBB. I have a sh script to keep load/unload several ko files. in another window, i run a dtrace script with a profile-100 probe to print out stack. I don't have access to a SMB ARM box (although I have a JETSON but not able to load BSD to it yet.) Comment Actions Most of my observations about the code itself are style nits, but generally this solution seems heavyweight. The problem, as I understand it, is that we're currently calling linker_file_foreach from the stack action handler, which is of course unsafe since this may occur in arbitrary contexts. Similar problems have been solved elsewhere by introducing unlocked variants of linker functions. These are the linker_*_ddb() functions, which are misnamed since they're called from places other than DDB (e.g., witness(4)). It might be that we just want to add a linker_file_foreach_unlocked() or so and use that instead. This is unsafe since a KLD may be unloaded as we're iterating over the linker file list, but the approach here is racy in the same way, isn't it?
Comment Actions This patch also try to improve performance in ARM unwind. As you can read from the code, every *frame* unwind needs to get access to _idx_start/end. So lookup symbol table of each module adds lots of CPU time to do so. There are two approaches, 1 is what you can see in this change. 2 is stored idx_start/idx_end in linker_file structure. I finally choose 1 due to the concern adding MD code into kernel linker. I will change to unload_try from unload. I didn't think about that. Since this function is not only used in DDB, but also in dtrace. it needs to be production env ready. To complete grantee safe, we may need a spinlock to protected between unwind and unload_try? Thoughts? Comment Actions Seems like a reasonable smoke test to me. Please make the requested changes and commit. Comment Actions Hm, I see. I'll take a closer look at that. (I know nothing about stack unwinding on ARM.)
Something like that. At the moment, the code isn't SMP-safe since the unwinder may access an element of your module list as it's being freed by another thread. The problem with using a spin mutex (or any kind of lock) here is that you may get recursion if you do something like lockstat:::spin-acquire {stack();}. I don't really see a good solution for this problem other than to completely prohibit KLD unloads while DTrace probes are enabled. We already do that selectively: see the nenabled field in struct linker_file. Comment Actions ustack() of dtrace implemention is still missing in ARM due to similar unwind problem. And it is even worse in userland. we cannot get unwinding table (reliable, trustful or even impossible if binary doesn't contain it) as kernel did. I am looking at some alternative solution like http://www.mcternan.me.uk/ArmStackUnwinding/. Just FYI not relate to this change.
You are absolute right. Since this will be called from probe context, we should never use any mutex even spinmutex. I will look at nenabled further. Comment Actions Tonight's testing didn't go very well. I hit a crash. [ thread pid 970 tid 100074 ] /* Load the registers */ for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { if (mask & 1) { 3c4: e3120001 tst r2, #1 ; 0x1 state->registers[reg] = *vsp++; 3cc: e4976004 ldr r6, [r7], #4 state->update_mask |= 1 << reg; /* If we have updated SP kep its value */ if (reg == SP) 3d0: e3550009 cmp r5, #9 ; 0x9 Which is not necessary related to this change. But I will take a look further.
|