# Copyright (C) 2011 Red Hat, Inc. All rights reserved. # This file is part of LVM2. # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU Lesser General Public License v.2.1. # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Author(s): # Jonathan Brassow # # Copy this file to ~/.gdbinit or /.gdbinit printf "\n\n" printf "Loading commands:\n" printf " - dm_list_size \n" printf " - pv_dev_name \n" printf " - first_seg \n" printf " - lv_status \n" printf " - lv_status_r \n" printf " - lv_is_mirrored \n" printf " - seg_item \n" printf " - seg_status \n" printf " - segs_using_this_lv \n" printf " - seg_pvs \n" printf " - \n" printf "Use 'help ' for more info\n" printf "\n\n" printf "Popular breakpoints:\n" printf "break _alloc_image_components\n" printf "run --repair --use-policies vg/lv\n" printf "\n\n" set follow-fork-mode child # Conventions: # foo : function named 'foo' available to user # __foo : an internal function # # External functions should have a corresponding 'document' # section. Internal functions should have leading comments define dm_list_size set $_DLS_list_head = (struct dm_list *)$arg0 set $_DLS_list = $_DLS_list_head->n set $_DLS_size = 0 while (($_DLS_list != $_DLS_list_head) && ($_DLS_size < 100)) set $_DLS_list = $_DLS_list->n set $_DLS_size++ end printf "%d list items\n", $_DLS_size end document dm_list_size Returns the number of elements in the dm_list Usage: dm_list_size end define pv_dev_name set $_PDN_pv = (struct physical_volume *)$arg0 set $_PDN_dev = $_PDN_pv->dev set $_PDN_strl = (struct str_list *)$_PDN_dev->aliases.n printf "%s\n", $_PDN_strl->str end document pv_dev_name Print the name of the PV for the given PV pointer Usage: pv_dev_name end define seg_pvs set $_SP_list_head = (struct dm_list *)$arg0 set $_SP_list = $_SP_list_head->n while (($_SP_list != $_SP_list_head) && ($_SP_size < 100)) set $_SP_spv = (struct seg_pvs *)$_SP_list printf "* Can't print PV list\n" set $_SP_list = $_SP_list->n end printf "%d list items\n", $_SP_size end document seg_pvs Print the elements of a seg_pvs list Usage: seg_pvs end # # __first_seg define __first_seg set $arg0 = 0x0 set $_FS_lv = (struct logical_volume *)$arg1 if ($_FS_lv->segments.n != &$_FS_lv->segments) set $arg0 = (struct lv_segment *)$_FS_lv->segments.n end end define first_seg set $_seg = 0 set $_lv=(struct logical_volume *)$arg0 __first_seg $_seg $_lv if ($_seg) p $_seg else printf "No segments (list empty)\n" end end document first_seg Returns the pointer to the first segment of an LV Usage: first_seg WARNING: If the list pointer in 'struct lv_segment' moves, this function will be wrong. end # # __seg_type define __seg_type set $arg0 = 0x0 set $_ST_seg = (struct lv_segment *)$arg1 set $_ST_index= $arg2 set $_ST_area = $_ST_seg->areas[$_ST_index] set $_ST_type = $_ST_area.type set $arg0 = $_ST_type end # # __seg_item define __seg_item set $arg0 = 0x0 set $_SI_seg = (struct lv_segment *)$arg1 set $_SI_index= $arg2 if ($_SI_index < $_SI_seg->area_count) set $_SI_area = $_SI_seg->areas[$_SI_index] set $_SI_type = $_SI_area.type if ($_SI_type == AREA_PV) set $arg0 = $_SI_area.u.pv.pvseg->pv else if ($_SI_type == AREA_LV) set $arg0 = $_SI_area.u.lv.lv end end end end # # __seg_metaitem define __seg_metaitem set $arg0 = 0x0 set $_SMI_seg = (struct lv_segment *)$arg1 set $_SMI_index= $arg2 if (($_SMI_index < $_SMI_seg->area_count) && $_SMI_seg->meta_areas) set $_SMI_area = $_SMI_seg->meta_areas[$_SMI_index] set $_SMI_type = $_SMI_area.type if ($_SMI_type == AREA_PV) set $arg0 = $_SMI_area.u.pv.pvseg->pv else if ($_SMI_type == AREA_LV) set $arg0 = $_SMI_area.u.lv.lv end end end end define seg_item set $_item = 0x0 __seg_item $_item $arg0 $arg1 if ($_item) p $_item else printf "AREA_UNASSIGNED or invalid\n" end end define seg_metaitem set $_metaitem = 0x0 __seg_metaitem $_metaitem $arg0 $arg1 if ($_metaitem) p $_metaitem else printf "AREA_UNASSIGNED or invalid\n" end end document seg_item Returns the pointer to the LV or PV for the indexed area of a segment Usage: seg_item Example - Getting to the sub-lv of a mirror: (gdb) p lv->name $1 = 0x712548 "lv" (gdb) first_seg lv $2 = (struct lv_segment *) 0x7128b8 (gdb) seg_item $2 0 $3 = (struct logical_volume *) 0x712688 (gdb) p $3->name $4 = 0x712770 "lv_mimage_0" end define __status set $_s_status = $arg0->status # Constants defined in metadata-exported.h # if ($_s_status & RAID) if ($_s_status & 0x0000000100000000LU) set $_s_status = $_s_status & ~0x0000000100000000LU printf " RAID" end # if ($_s_status & RAID_META) if ($_s_status & 0x0000000200000000LU) set $_s_status = $_s_status & ~0x0000000200000000LU printf " RAID_META" end # if ($_s_status & RAID_IMAGE) if ($_s_status & 0x0000000400000000LU) set $_s_status = $_s_status & ~0x0000000400000000LU printf " RAID_IMAGE" end # if ($_s_status & MIRRORED) if ($_s_status & 0x00008000U) set $_s_status = $_s_status & ~0x00008000U printf " MIRRORED" end # if ($_s_status & MIRROR_LOG) if ($_s_status & 0x00020000U) set $_s_status = $_s_status & ~0x00020000U printf " MIRROR_LOG" end # if ($_s_status & MIRROR_IMAGE) if ($_s_status & 0x00040000U) set $_s_status = $_s_status & ~0x00040000U printf " MIRROR_IMAGE" end # if ($_s_status & VISIBLE_LV) if ($_s_status & 0x00000040U) printf " VISIBLE_LV" set $_s_status = $_s_status & ~0x00000040U else printf " *HIDDEN_LV*" end # if ($_s_status & FIXED_MINOR) if ($_s_status & 0x00000080U) set $_s_status = $_s_status & ~0x00000080U printf " FIXED_MINOR" end # if ($_s_status & LVM_READ) if ($_s_status & 0x00000100U) set $_s_status = $_s_status & ~0x00000100U printf " LVM_READ" end # if ($_s_status & LVM_WRITE) if ($_s_status & 0x00000200U) set $_s_status = $_s_status & ~0x00000200U printf " LVM_WRITE" end # if ($_s_status & SNAPSHOT) if ($_s_status & 0x00001000U) set $_s_status = $_s_status & ~0x00001000U printf " SNAPSHOT" end # if ($_s_status & PVMOVE) if ($_s_status & 0x00002000U) set $_s_status = $_s_status & ~0x00002000U printf " PVMOVE" end # if ($_s_status & LOCKED) if ($_s_status & 0x00004000U) set $_s_status = $_s_status & ~0x00004000U printf " LOCKED" end # if ($_s_status & LV_NOTSYNCED) if ($_s_status & 0x00080000U) set $_s_status = $_s_status & ~0x00080000U printf " LV_NOTSYNCED" end # if ($_s_status & CONVERTING) if ($_s_status & 0x00400000U) set $_s_status = $_s_status & ~0x00400000U printf " CONVERTING" end # if ($_s_status & LV_REBUILD) if ($_s_status & 0x100000U) set $_s_status = $_s_status & ~0x100000U printf " LV_REBUILD" end # if ($_s_status & PARTIAL_LV) if ($_s_status & 0x1000000U) set $_s_status = $_s_status & ~0x1000000U printf " PARTIAL_LV" end # if ($_s_status & MERGING) if ($_s_status & 0x10000000U) set $_s_status = $_s_status & ~0x10000000U printf " MERGING" end # if ($_s_status & LV_WRITEMOSTLY) if ($_s_status & 0x10000000000U) set $_s_status = $_s_status & ~0x10000000000U printf " LV_WRITEMOSTLY" end if ($_s_status) printf " 0x%x", $_s_status end end # # __print_indent [No marks] define __print_indent set $_PI_indent = $arg0 set $_PI_lead_mark = 0 while ($_PI_indent) if ($_PI_indent == 1) if ($argc > 1) if ($_PI_lead_mark) printf " " else printf "| " end else printf "|-----> " end else printf "| " set $_PI_lead_mark = 1 end set $_PI_indent-- end end define lv_status # Use __lv because we don't want to overwrite higher functions set $__lv = (struct logical_volume *)$arg0 if ($argc == 2) __print_indent $arg1 end printf "%s->status:", $__lv->name __status $__lv printf "\n" end document lv_status Display the flags that are set on an LV. Usage: lv_status end define seg_status set $_seg=(struct lv_segment *)$arg0 if ($argc == 2) __print_indent $arg1 1 end printf "[ (%s) seg->status:", $_seg->lv->name __status $_seg printf " ]\n" end document seg_status Display the flags that are set on an lv_segment. Usage: seg_status <(struct lv_segment *)> end # # get_only_segment_using_this_lv define __get_only_segment_using_this_lv set $arg0 = 0x0 set $_lv=(struct logical_volume *)$arg1 set $_seg_list_head = &$_lv->segs_using_this_lv set $_s = $_lv->segs_using_this_lv.n set $_i = 0 while (($_s != $_seg_list_head) && ($_i < 100)) set $_seg_list = (struct seg_list *)$_s set $_seg = (struct lv_segment *)$_seg_list->seg set $_i++ set $_s = $_s->n end if ($_i > 1) printf "More than %s using %s\n", ($_i > 99) ? "100 segments" : "one segment", $_lv->name end if ($_i == 1) set $arg0 = $_seg end end define segs_using_this_lv set $_lv=(struct logical_volume *)$arg0 set $_seg_list_head = &$_lv->segs_using_this_lv set $_s = $_lv->segs_using_this_lv.n set $_i = 0 if ($_s != $_seg_list_head) printf "Segments using %s\n", $_lv->name else printf "No segments using %s\n", $_lv->name end while ($_s != $_seg_list_head) set $_seg_list = (struct seg_list *)$_s set $_seg = (struct lv_segment *)$_seg_list->seg printf " %d) seg: %p", $_i, $_seg if ($_seg->lv < 0x200) printf " [BAD LV POINTER FROM THIS SEG]\n" else printf " [seg found in %s]\n", $_seg->lv->name end set $_i++ set $_s = $_s->n end end document segs_using_this_lv Display the segments (and their associated LV) using an LV Usage: segs_using_this_lv Example: (gdb) lv_is_mirrored lv lv is mirrored ('core' log) (gdb) segs_using_this_lv lv No segments using lv (gdb) first_seg lv $1 = (struct lv_segment *) 0x92d360 (gdb) seg_item $1 0 $2 = (struct logical_volume *) 0x928f58 (gdb) segs_using_this_lv $2 Segments using lv_mimage_0 0) seg: 0x92d360 [seg found in lv] end # # __next_area_index define __next_area_index set $arg0 = 0x0 set $_seg = (struct lv_segment *)$arg1 set $_item = 0x0 set $_i = 0 __seg_item $_item $_seg $_i while ($_item && ($_item != $arg2)) set $_i++ __seg_item $_item $_seg $_i end # $_i points to current, now get next (if there) set $_i++ __seg_item $_item $_seg $_i if ($_item) set $arg0 = $_i end end # # __lv_status_r # Descend tree, printing LV and seg status as we go. This # performs a depth first approach (but can't come up) # # or # # __lv_status_r # Try continuing decent of tree by first shifting to the # next 'area' in the seg ($arg1). If no more areas, then # try going to the next segment. define __lv_status_r if ($argc == 1) set $_lv=(struct logical_volume *)$arg0 set $_seg_list_head = &$_lv->segments set $_s = $_lv->segments.n set $_area_index = 0 # printf "\n" lv_status $_lv $indent else set $_seg = (struct lv_segment *)$arg1 __next_area_index $_area_index $_seg $arg0 # Don't fuck this up. We need the next two lines here. set $_lv=(struct logical_volume *)$_seg->lv set $_seg_list_head = &$_lv->segments set $_s = (struct dm_list *)$_seg if (!$_area_index) set $_s = $_s->n end end if ($_s == $_seg_list_head) if ($argc == 1) __print_indent $indent 1 printf "[ No segments for %s ]\n", $_lv->name end __get_only_segment_using_this_lv $_seg $_lv if ($_seg && $indent) set $indent-- __lv_status_r $_lv $_seg end else set $_seg = (struct lv_segment *)$_s set $_type = 0x0 if (!$_area_index) seg_status $_seg $indent end __seg_type $_type $_seg $_area_index if ($_type == AREA_LV) set $indent++ __seg_metaitem $_lv $_seg $_area_index if ($_lv) set $rindent = $indent set $rseg = $_seg set $rarea_index = $_area_index set $rlv = $_lv __lv_status_r $_lv set $indent = $rindent set $_seg = $rseg set $_area_index = $rarea_index set $_lv = $rlv end __seg_item $_lv $_seg $_area_index __lv_status_r $_lv else if ($_seg->log_lv) set $indent++ set $_log_seg = 0x0 __first_seg $_log_seg $_seg->log_lv lv_status $_seg->log_lv $indent seg_status $_log_seg $indent set $indent-- end __get_only_segment_using_this_lv $_seg $_lv if ($_seg) set $indent-- __lv_status_r $_lv $_seg end end end end define lv_status_r set $indent = 0 __lv_status_r $arg0 end document lv_status_r Display the status flags of an LV and its sub_lvs. Usage: lv_status_r This function is useful for checking that all the LVs that compose a logical volume have the correct flags set (and also their associated lv_segments) end define lv_is_mirrored set $_lv=(struct logical_volume *)$arg0 set $_fs=(struct lv_segment *)$_lv->segments.n set $_log_lv=(struct logical_volume *)$_fs->log_lv # if ($_lv->status & MIRRORED) if ($_lv->status & 0x00008000U) printf "%s is mirrored (", $_lv->name if ($_log_lv) if ($_log_lv->status & 0x00008000U) printf "'mirrored' log)\n" else printf "'disk' log)\n" end else printf "'core' log)\n" end else printf "%s is not mirrored\n", $_lv->name end end document lv_is_mirrored Report whether the given LV is mirrored (and its log type). Usage: lv_is_mirrored end