Hi
On 05/07/07 21:48, Peter Tribble wrote:
[cut]
So there is a small chance that back in sfmmu_shadow_hcleanup we could
still see the hblk_cnt and hblk_hmecnt non-zero, which is the comment
you have highlighted. In that case we do not remove the block from
the hash chain, and proceed on to the next chunk of addresses.
When we unwind back to the sfmmu_tteload_find_hmeblk it could
find this same block again and cause us to descend through the
whole process again. This won't happen indefinitely since
sooner or later the pageunload will be unpinned and will
decrement the counters allowing us to free the block.
That's how it should work. If you are spinning in that
stack at and below sfmmu_tteload_find_hmeblk then chances
are that some mismanagement of the hmecnt/vcnt has happened.
This may be verified through some post-mortem crash
analysis.
I have some crash dumps - what should I be looking for?
I'd look at the hash bucket that we appear to be spinning on. Dig
out the calling arguments to sfmmu_shadow_hcleanup:
384 static void sfmmu_shadow_hcleanup(sfmmu_t *, struct hme_blk *,
385 struct hmehash_bucket *);
There you have a pointer to the bucket as the last arg - much easier
than trying to find it by computing the hash yourself.
858 struct hmehash_bucket {
859 kmutex_t hmehash_mutex;
860 uint64_t hmeh_nextpa; /* physical address for hash
list */
861 struct hme_blk *hmeblkp;
862 uint_t hmeh_listlock;
863 };
Now walk the list of hmeblks off that bucket. Assuming <addr> is the *hmeblkp
from
the bucket you dump above:
<addr>::list struct hme_blk hblk_next | ::print -t struct hme_blk
741 struct hme_blk {
742 uint64_t hblk_nextpa; /* physical address for hash
list */
743
744 hmeblk_tag hblk_tag; /* tag used to obtain an hmeblk
match */
745
746 struct hme_blk *hblk_next; /* on free list or on hash list
*/
747 /* protected by hash lock */
748
749 struct hme_blk *hblk_shadow; /* pts to shadow hblk */
750 /* protected by hash lock */
751 uint_t hblk_span; /* span of memory hmeblk maps */
752
753 struct hme_blk_misc hblk_misc;
754
755 union {
756 struct {
757 ushort_t hblk_hmecount; /* hment on mlists
counter */
758 ushort_t hblk_validcnt; /* valid tte reference
count */
759 } hblk_counts;
760 uint_t hblk_shadow_mask;
761 } hblk_un;
762
763 #ifdef HBLK_TRACE
764 kmutex_t hblk_audit_lock; /* lock to protect
index */
765 uint_t hblk_audit_index; /* index into
audit_cache */
766 struct hblk_lockcnt_audit
hblk_audit_cache[HBLK_AUDIT_CACHE_SIZE];
767 #endif /* HBLK_AUDIT */
768
769 struct sf_hment hblk_hme[1]; /* hment array */
770 };
Note that the hblk_hme array has 1 entry as suggested above only for large-page
mappings.
For 8K mappings it is actually an array of 8 sf_hment, and that is the common
case of
course. You can recognise the size of the mappings in this hblk from the
hblk_misc
member: ttesize there will be 0 (TTE_8K, see pte.h> for 8K mappings.
Actually the sf_hments themselves may not be all that interesting. The first
thing
I'd be looking at is the hblk_hmecount and hblk_validcnt in each hblk. We
expect
a value from 0 to 8, anything else would be a bug and would likely make as
loop on an unload.
Gavin
_______________________________________________
opensolaris-code mailing list
[email protected]
http://mail.opensolaris.org/mailman/listinfo/opensolaris-code