Skip to content
Snippets Groups Projects
Commit 32c4833f authored by Patrick Daly's avatar Patrick Daly
Browse files

lrdp: rbtree: Support error recovery during tree iteration

In some cases it may be possible to detect whether an rbtree is corrupted.
Skip over any corrupted nodes, and their children, while iterating.
Additionally, log a message whenever a bad entry is detected. This behavior
may be enabled by the client by setting the 'logger' and 'debug' properties
for a particular instance of an RbTree.

Modify the --print-ionbuffer parser to use the new RbTree implementation.

Change-Id: I2ed2364b5e7d42ee009a0a49876feb82ab0fa78c
parent 0686897d
No related branches found
No related tags found
No related merge requests found
""" """
Copyright (c) 2016, The Linux Foundation. All rights reserved. Copyright (c) 2016, 2018 The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
...@@ -28,6 +28,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -28,6 +28,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
""" """
from parser_util import register_parser, RamParser from parser_util import register_parser, RamParser
from rb_tree import RbTree
import logging
import os
RB_PARENT_COLOR_MASK = 0xFFFFFFFFFFFFFFFC RB_PARENT_COLOR_MASK = 0xFFFFFFFFFFFFFFFC
grand_total = 0 grand_total = 0
...@@ -112,13 +115,12 @@ def parse_heap(self, ramdump, heap_addr, ion_info): ...@@ -112,13 +115,12 @@ def parse_heap(self, ramdump, heap_addr, ion_info):
ion_dev = ramdump.read_structure_field( ion_dev = ramdump.read_structure_field(
ion_heap, 'struct ion_heap', 'dev') ion_heap, 'struct ion_heap', 'dev')
ion_dev_rb_root = ramdump.read_structure_field( clients_rb_root = ion_dev + ramdump.field_offset('struct ion_device', 'clients')
ion_dev, 'struct ion_device', 'clients')
if ionheap_total_allocated != 0: if ionheap_total_allocated != 0:
nr_clients = show_ion_dev_client( nr_clients = show_ion_dev_client(
self, ramdump, self, ramdump,
ion_dev_rb_root, clients_rb_root,
ionheap_id, ion_info) ionheap_id, ion_info)
str = "\n \nTotal number of clients: {0:1}" str = "\n \nTotal number of clients: {0:1}"
...@@ -142,11 +144,9 @@ def parse_heap(self, ramdump, heap_addr, ion_info): ...@@ -142,11 +144,9 @@ def parse_heap(self, ramdump, heap_addr, ion_info):
def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info): def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
orphan_buffer_size = 0 orphan_buffer_size = 0
total_buffer_size = 0 total_buffer_size = 0
ion_dev_buffer_rb_root = ramdump.read_structure_field(
ion_dev, 'struct ion_device', 'buffers')
rb_node = parser( rbtree = RbTree(ramdump, ion_dev + ramdump.field_offset('struct ion_device', 'buffers'),
self, 1, ramdump, ion_dev_buffer_rb_root, ion_info) logger = self.logger, debug = True)
ion_buffer_rb_node_offset = ramdump.field_offset( ion_buffer_rb_node_offset = ramdump.field_offset(
'struct ion_buffer', 'node') 'struct ion_buffer', 'node')
...@@ -156,7 +156,7 @@ def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info): ...@@ -156,7 +156,7 @@ def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
'struct ion_buffer', 'ref') 'struct ion_buffer', 'ref')
str = "\n buffer: 0x{0:x}, Buffer size: {1} KB " str = "\n buffer: 0x{0:x}, Buffer size: {1} KB "
str = str + "comm: {2} PID: {3} kmap count: {4} ref_count : {5}" str = str + "comm: {2} PID: {3} kmap count: {4} ref_count : {5}"
while rb_node != 0: for rb_node in rbtree:
ion_buffer = rb_node - ion_buffer_rb_node_offset ion_buffer = rb_node - ion_buffer_rb_node_offset
ion_buffer_ref_add = ion_buffer + ion_buffer_ref_offset ion_buffer_ref_add = ion_buffer + ion_buffer_ref_offset
ion_buffer_heap = ramdump.read_structure_field( ion_buffer_heap = ramdump.read_structure_field(
...@@ -188,19 +188,20 @@ def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info): ...@@ -188,19 +188,20 @@ def parse_orphan_buffers(self, ramdump, ion_dev, heap_id, ion_info):
ion_buffer_kmap_count, ion_buffer_kmap_count,
ref_counter)) ref_counter))
orphan_buffer_size = orphan_buffer_size + ion_buffer_size orphan_buffer_size = orphan_buffer_size + ion_buffer_size
rb_node = parser(self, 2, ramdump, rb_node, ion_info)
return orphan_buffer_size, total_buffer_size return orphan_buffer_size, total_buffer_size
def show_ion_dev_client( def show_ion_dev_client(
self, self,
ramdump, ramdump,
ion_dev_rb_root, rb_root,
ionheap_id, ion_info): ionheap_id, ion_info):
global ion_heap_buffers global ion_heap_buffers
nr_clients = 0 nr_clients = 0
client_name = 0 client_name = 0
rb_node = parser(self, 1, ramdump, ion_dev_rb_root, ion_info)
rbtree = RbTree(ramdump, rb_root, logger = self.logger, debug = True)
ion_client_node_offset = ramdump.field_offset( ion_client_node_offset = ramdump.field_offset(
'struct ion_client', 'node') 'struct ion_client', 'node')
task_comm_offset = ramdump.field_offset( task_comm_offset = ramdump.field_offset(
...@@ -208,8 +209,8 @@ def show_ion_dev_client( ...@@ -208,8 +209,8 @@ def show_ion_dev_client(
tempstr = "\n\n CLIENT: (struct ion_client *)0x{0:x} , " tempstr = "\n\n CLIENT: (struct ion_client *)0x{0:x} , "
str = tempstr + "task : {1} / ion_client : {2} / PID: {3} / Size : {4} KB" str = tempstr + "task : {1} / ion_client : {2} / PID: {3} / Size : {4} KB"
str1 = tempstr + "ion_client : {1} / PID: {2} / Size : {3} KB" str1 = tempstr + "ion_client : {1} / PID: {2} / Size : {3} KB"
if rb_node != 0: if True:
while rb_node != 0: for rb_node in rbtree:
ion_client = rb_node - ion_client_node_offset ion_client = rb_node - ion_client_node_offset
heap_size = traverse_ion_heap_buffer( heap_size = traverse_ion_heap_buffer(
self, self,
...@@ -244,7 +245,6 @@ def show_ion_dev_client( ...@@ -244,7 +245,6 @@ def show_ion_dev_client(
client_PID, bytes_to_KB(heap_size))) client_PID, bytes_to_KB(heap_size)))
for heap_buffer in ion_heap_buffers: for heap_buffer in ion_heap_buffers:
ion_info.write(heap_buffer) ion_info.write(heap_buffer)
rb_node = parser(self, 2, ramdump, rb_node, ion_info)
return nr_clients return nr_clients
...@@ -256,9 +256,11 @@ def traverse_ion_heap_buffer(self, ramdump, ion_client, ionheap_id, ion_info): ...@@ -256,9 +256,11 @@ def traverse_ion_heap_buffer(self, ramdump, ion_client, ionheap_id, ion_info):
ion_buffer_heap_size = 0 ion_buffer_heap_size = 0
ion_heap_buffers = [] ion_heap_buffers = []
str = "\n (+) ion_buffer: 0x{0:x} size: {1:0} KB Handle Count: {2:0}" str = "\n (+) ion_buffer: 0x{0:x} size: {1:0} KB Handle Count: {2:0}"
ion_handle_rb_node = parser(
self, 1, ramdump, ion_handle_root_address, ion_info) rbtree = RbTree(ramdump, ion_handle_root_address,
while ion_handle_rb_node != 0: logger=self.logger, debug = True)
for ion_handle_rb_node in rbtree:
ion_handle = ion_handle_rb_node - self.ion_handle_node_offset ion_handle = ion_handle_rb_node - self.ion_handle_node_offset
ion_buffer = ramdump.read_structure_field( ion_buffer = ramdump.read_structure_field(
ion_handle, 'struct ion_handle', 'buffer') ion_handle, 'struct ion_handle', 'buffer')
...@@ -278,8 +280,6 @@ def traverse_ion_heap_buffer(self, ramdump, ion_client, ionheap_id, ion_info): ...@@ -278,8 +280,6 @@ def traverse_ion_heap_buffer(self, ramdump, ion_client, ionheap_id, ion_info):
bytes_to_KB(ion_buffer_size), bytes_to_KB(ion_buffer_size),
ion_buffer_handlecount) ion_buffer_handlecount)
ion_heap_buffers.append(temp) ion_heap_buffers.append(temp)
ion_handle_rb_node = parser(
self, 2, ramdump, ion_handle_rb_node, ion_info)
return ion_buffer_heap_size return ion_buffer_heap_size
...@@ -368,4 +368,10 @@ class DumpIonBuffer(RamParser): ...@@ -368,4 +368,10 @@ class DumpIonBuffer(RamParser):
{1}'.format(self.ramdump.kernel_version[0], {1}'.format(self.ramdump.kernel_version[0],
self.ramdump.kernel_version[1])) self.ramdump.kernel_version[1]))
return return
self.logger = logging.getLogger(__name__)
path = os.path.join(self.ramdump.outdir, 'print-ionbuffer.stderr')
self.logger.addHandler(logging.FileHandler(path, mode='w'))
self.logger.setLevel(logging.INFO)
self.logger.info("Starting --print-ionbuffer")
do_dump_ionbuff_info(self, self.ramdump, ion_info) do_dump_ionbuff_info(self, self.ramdump, ion_info)
# Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. # Copyright (c) 2012-2014, 2018 The Linux Foundation. All rights reserved.
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 and # it under the terms of the GNU General Public License version 2 and
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
from print_out import print_out_str
import pdb
""" """
struct rb_node struct rb_node
{ {
...@@ -20,6 +23,137 @@ struct rb_node ...@@ -20,6 +23,137 @@ struct rb_node
} __attribute__((aligned(sizeof(long)))); } __attribute__((aligned(sizeof(long))));
""" """
class RbTree(object):
def __init__(self, ramdump, root,
logger = None, debug = False):
self.rd = ramdump
self.rb_root = root
if not logger:
self.logger = logging.getLogger(__name__)
else:
self.logger = logger
self.debug = debug
def __rb_parent(self, node):
parent_color = self.rd.read_structure_field(
node, 'struct rb_node', '__rb_parent_color')
if parent_color is None:
pdb.set_trace()
self.logger.error("struct rb_node@0x{:x}: Memory access failed".format(node))
return 0x0
return parent_color & ~3
def __rb_left(self, node):
child = self.rd.read_structure_field(node, 'struct rb_node', 'rb_left')
if child is None:
pdb.set_trace()
self.logger.error("struct rb_node@0x{:x}: Memory access failed".format(node))
return 0x0
return child
def __rb_right(self, node):
child = self.rd.read_structure_field(node, 'struct rb_node', 'rb_right')
if child is None:
pdb.set_trace()
self.logger.error("struct rb_node@0x{:x}: Memory access failed".format(node))
return 0x0
return child
def validate(self, parent, child):
if not self.debug:
return True
if not parent or not child:
return True
_parent = self.__rb_parent(child)
if parent != _parent:
self.logger.error(
"Bad rb_tree child->parent pointer:\n"+
"Parent: 0x{:x}\n".format(parent)+
"Child: 0x{:x}\n".format(child))
return False
right = self.__rb_right(parent)
left = self.__rb_left(parent)
if (child != left and child != right):
self.logger.error(
"Bad rb_tree parent->child pointer:\n"+
"Parent: 0x{:x}\n".format(parent)+
"Child: 0x{:x}\n".format(child))
return False
return True
def rb_parent(self, node):
parent = self.__rb_parent(node)
if self.validate(parent, node):
return parent
def rb_left(self, node):
child = self.__rb_left(node)
if self.validate(node, child):
return child
def rb_right(self, node):
child = self.__rb_right(node)
if self.validate(node, child):
return child
def rb_first(self, node):
if not node:
return 0x0
while node:
prev = node
node = self.rb_left(node)
return prev
def rb_next(self, node):
if not node:
return 0x0
right = self.rb_right(node)
if right:
return self.rb_first(right)
while True:
parent = self.rb_parent(node)
if not parent:
return 0x0
right = self.rb_right(parent)
if node != right:
return parent
node = parent
def __iter__(self):
return self.RbTreeIter(self)
class RbTreeIter(object):
def __init__(self, rbtree):
#pdb.set_trace()
self.rbtree = rbtree
node = rbtree.rd.read_structure_field(
rbtree.rb_root, 'struct rb_root', 'rb_node')
self.cur = rbtree.rb_first(node)
def next(self):
if not self.cur:
raise StopIteration
self.cur = self.rbtree.rb_next(self.cur)
if not self.cur:
raise StopIteration
return self.cur
class RbTreeWalker(object): class RbTreeWalker(object):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment