# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
"""
SUMMARY
-------
Display XFS internal data structures
::
xfs <command> [arguments ...]
COMMANDS
--------
::
xfs list
xfs show <superblock>
xfs dump-ail <superblock>
xfs dump-buft <buftarg>
"""
import argparse
from crash.commands import Command, ArgumentParser
from crash.commands import CommandLineError, CommandError
from crash.types.list import list_for_each_entry, list_empty
from crash.subsystem.filesystem import for_each_super_block, get_super_block
from crash.subsystem.filesystem import super_flags
from crash.subsystem.filesystem.xfs import xfs_mount
from crash.subsystem.filesystem.xfs import xfs_for_each_ail_log_item
from crash.subsystem.filesystem.xfs import xfs_log_item_typed
from crash.subsystem.filesystem.xfs import xfs_format_xfsbuf
from crash.subsystem.filesystem.xfs import XFS_LI_TYPES
from crash.subsystem.filesystem.xfs import XFS_LI_EFI
from crash.subsystem.filesystem.xfs import XFS_LI_INODE
from crash.subsystem.filesystem.xfs import XFS_LI_BUF, XFS_LI_DQUOT
from crash.subsystem.filesystem.xfs import XFS_LI_QUOTAOFF, XFS_BLI_FLAGS
from crash.subsystem.filesystem.xfs import XFS_DQ_FLAGS
from crash.subsystem.filesystem.xfs import xfs_mount_flags, xfs_mount_uuid
from crash.subsystem.filesystem.xfs import xfs_mount_version
from crash.util import decode_flags, struct_has_member
from crash.util.symbols import Types
import gdb
types = Types(['struct xfs_buf *'])
[docs]class XFSCommand(Command):
"""display XFS internal data structures"""
def __init__(self, name: str) -> None:
parser = ArgumentParser(prog=name)
subparsers = parser.add_subparsers(help="sub-command help")
show_parser = subparsers.add_parser('show', help='show help')
show_parser.set_defaults(subcommand=self.show_xfs)
show_parser.add_argument('addr')
list_parser = subparsers.add_parser('list', help='list help')
list_parser.set_defaults(subcommand=self.list_xfs)
ail_parser = subparsers.add_parser('dump-ail', help='ail help')
ail_parser.set_defaults(subcommand=self.dump_ail)
ail_parser.add_argument('addr')
buft_parser = subparsers.add_parser('dump-buft', help='buft help')
buft_parser.set_defaults(subcommand=self.dump_buftargs)
buft_parser.add_argument('addr')
Command.__init__(self, name, parser)
# pylint: disable=unused-argument
[docs] def list_xfs(self, args: argparse.Namespace) -> None:
count = 0
print_header = True
for sb in for_each_super_block():
if sb['s_type']['name'].string() == "xfs":
mp = xfs_mount(sb)
u = xfs_mount_uuid(mp)
if print_header:
print_header = False
print("SUPER BLOCK\t\t\tDEVICE\t\tUUID")
print("{}\t{}\t{}".format(sb.address, sb['s_id'].string(), u))
count += 1
if count == 0:
print("No xfs file systems are mounted.")
[docs] def show_xfs(self, args: argparse.Namespace) -> None:
try:
sb = get_super_block(args.addr)
except gdb.NotAvailableError as e:
raise CommandError(str(e))
mp = xfs_mount(sb)
print("Device: {}".format(sb['s_id'].string()))
print("UUID: {}".format(xfs_mount_uuid(mp)))
print("VFS superblock flags: {}".format(super_flags(sb)))
print("Flags: {}".format(xfs_mount_flags(mp)))
print("Version: {}".format(xfs_mount_version(mp)))
if list_empty(mp['m_ail']['xa_ail']):
print("AIL is empty")
else:
print("AIL has items queued")
[docs] def dump_ail(self, args: argparse.Namespace) -> None:
try:
sb = get_super_block(args.addr)
except gdb.NotAvailableError as e:
raise CommandError(str(e))
mp = xfs_mount(sb)
ail = mp['m_ail']
itemno = 0
print("AIL @ {:x}".format(int(ail)))
print("target={} last_pushed_lsn={} log_flush="
.format(int(ail['xa_target']), int(ail['xa_last_pushed_lsn'])),
end='')
# This was added in Linux v3.2 (670ce93fef93b)
if struct_has_member(ail, 'xa_log_flush'):
print("{}".format(int(ail['xa_log_flush'])))
else:
print("[N/A]")
for bitem in xfs_for_each_ail_log_item(mp):
li_type = int(bitem['li_type'])
lsn = int(bitem['li_lsn'])
item = xfs_log_item_typed(bitem)
print("{}: item={:x} lsn={} {} "
.format(itemno, int(bitem.address), lsn,
XFS_LI_TYPES[li_type][7:]), end='')
if li_type == XFS_LI_BUF:
buf = item['bli_buf']
flags = decode_flags(item['bli_flags'], XFS_BLI_FLAGS)
print(" buf@{:x} bli_flags={}" .format(int(buf), flags))
print(" {}".format(xfs_format_xfsbuf(buf)))
elif li_type == XFS_LI_INODE:
ili_flags = int(item['ili_lock_flags'])
xfs_inode = item['ili_inode']
print("inode@{:x} i_ino={} ili_lock_flags={:x} "
.format(int(xfs_inode['i_vnode'].address),
int(xfs_inode['i_ino']), ili_flags))
elif li_type == XFS_LI_EFI:
efi = item['efi_format']
print("efi@{:x} size={}, nextents={}, id={:x}"
.format(int(item.address), int(efi['efi_size']),
int(efi['efi_nextents']), int(efi['efi_id'])))
elif li_type == XFS_LI_EFI:
efd = item['efd_format']
print("efd@{:x} size={}, nextents={}, id={:x}"
.format(int(item.address), int(efd['efd_size']),
int(efd['efd_nextents']), int(efd['efd_id'])))
elif li_type == XFS_LI_DQUOT:
dquot = item['qli_dquot']
flags = decode_flags(dquot['dq_flags'], XFS_DQ_FLAGS)
print("dquot@{:x} flags={}".format(int(dquot), flags))
elif li_type == XFS_LI_QUOTAOFF:
qoff = item['qql_format']
print("qoff@{:x} type={} size={} flags={}"
.format(int(qoff), int(qoff['qf_type']),
int(qoff['qf_size']), int(qoff['qf_flags'])))
else:
print("item@{:x}".format(int(item.address)))
itemno += 1
[docs] @classmethod
def dump_buftarg(cls, targ: gdb.Value) -> None:
for buf in list_for_each_entry(targ['bt_delwrite_queue'],
types.xfs_buf_p_type.target(),
'b_list'):
print("{:x} {}".format(int(buf.address), xfs_format_xfsbuf(buf)))
[docs] @classmethod
def dump_buftargs(cls, args: argparse.Namespace) -> None:
try:
sb = get_super_block(args.addr)
except gdb.NotAvailableError as e:
raise CommandError(str(e))
mp = xfs_mount(sb)
ddev = mp['m_ddev_targp']
ldev = mp['m_logdev_targp']
print("Data device queue @ {:x}:".format(int(ddev)))
cls.dump_buftarg(ddev)
if int(ddev) != int(ldev):
print("Log device queue:")
cls.dump_buftarg(ldev)
[docs] def execute(self, args: argparse.Namespace) -> None:
if hasattr(args, 'subcommand'):
args.subcommand(args)
else:
raise CommandLineError("no command specified")
XFSCommand("xfs")