Lustre Debugging Procedures

The procedures below may be useful to administrators or developers debugging a Lustre™ file system.

Lustre Messages and Logging
keep first

Understanding the Lustre debug messaging format
Lustre debug messages are divided into several subsystems and types related to the Lustre module that generates the message. Each Lustre message is tagged with:
 * Subsystem in which it originated (mdc, mds, osc, ost, obdclass, obdfilter, llite, ptlrpc, portals, lnd, ldlm, or lov)
 * Message type (see below)
 * Location in the source code

Listed below are the types of debug messages used in Lustre.
 * trace: Entry/Exit markers
 * dlmtrace: Locking related information.
 * inode
 * super
 * ext2: Anything from ext2_debug.
 * malloc: Print malloc or free information.
 * cache: Cache related information.
 * info: General information.
 * ioctl: IOCTL related information.
 * blocks: Ext2 block allocation information.
 * net: Networking.
 * warning
 * buffs
 * other
 * dentry
 * portals: Entry/ Exit markers.
 * page: Bulk page handling.
 * error: Error messages.
 * emerg
 * rpctrace: For distributed debugging.
 * ha: Information related to failover and recovery.

Note: For a current list of subsystems and debug message types, see lnet/include/libcfs/libcfs.h How current is this list

The CDEBUG and CERROR macros are used in Lustre to print the debug or error messages. The CDEBUG macro uses portals_debug_msg (portals/linux/oslib/debug.c) to print the message.

The message format is shown below with an example:

Using the Lustre debug daemon
The debug_daemon allows users to control the Lustre kernel debug daemon to dump the debug_kernel buffer to a user-specified file. This functionality is built using a kernel thread on top of debug_kernel. debug_kernel, another sub-command of lctl, continues to work in parallel with the debug_daemon command.

Debug_daemon is highly dependent on the filesystem write speed. If the Lustre file system is under heavy system load, the filesystem write operation may not be fast enough to flush out all of the debug_buffer and continue to CDEBUG to the debug_buffer. Debug_daemon is to put DEBUG MARKER: Trace buffer full into the debug_buffer, indicating that debug_buffer is overlapping itself before debug_daemon flushes data to a file.

The user can use lctl control to start or stop the Lustre daemon from dumping the debug_buffer to a file. Users can also temporarily pause daemon from dumping the file. It can be controlled using the debug_daemon sub-command to lctl.

Debug daemon commands

 * debug_daemon start [{file} {megabytes}] - Initiates the debug_daemon to start dumping debug_buffer into a file. The file can be a system default file,as shown in /proc/sys/lnet/debug_path.

The default patch path? after Lustre boots up is /tmp/lustre-log-$HOSTNAME.

Users can specify a new file name for debug_daemon to output debug_buffer. The new file name will show up in /proc/sys/lnet/debug_path.

megabytes is the limitation of the file size in megabytes.

The daemon will wrap around and dump data to the beginning of the file when the output file size exceeds the user-specified file size limit. To decode the dumped file to ASCII run:


 * debug_daemon stop - Completely shuts down the debug_daemon operation and flushes the file output. Otherwise, debug_daemon is shut down as part of Lustre file system shutdown process. Users can restart debug_daemon by using start command after each issued stop command.

Below is an example using the debug_daemon to dump debug logs to a 10MB file:


 * 1) ~/utils/lctl

To start the daemon dumping debug_buffer into a 40 MB /tmp/dump file, enter: lctl > debug_daemon start /trace/log 40

To completely shut down the daemon, enter: lctl > debug_daemon stop

To start yet another daemon with an unlimited file size, enter: lctl > debug_daemon start /tmp/unlimited

The following line is added to end of each output file: *** End of debug_daemon trace log ***

Controlling the Kernel Debug Log
The amount of information printed to the kernel debug logs can be controlled by masks in /proc/sys/lnet/subsystem_debug and /proc/sys/lnet/debug. The subsystem_debug mask is for controlling the subsystems (e.g. obdfilter, net, portals, OSC, etc) and the debug mask is for controlling the debug types that would be written out to the log (e.g. info, error, trace, alloc, etc).

The different options are listed in lnet/include/libcfs/libcfs.h.
 * sysctl -w lnet.debug=0 - Turns off Lustre debugging completely
 * sysctl -w lnet.debug=-1 - Enables full debugging
 * sysctl -w lnet.debug=net - Turns on logging of messages related to network communications.
 * sysctl -w lnet.debug=+net - Turns on logging of messages related to network communications, in addition to existing debug flags.
 * sysctl -w lnet.debug=-net - Turns off logging of messages related to network communications, leaving debug flags alone.

The lctl Tool
Debug messages useful for troubleshooting are sprinkled throughout the Lustre source code. As described earlier, we have sub-divided the debug messages into a number of sub-systems and types. This allows us to filter and show only the messages we are interested in.

The lctl tool is very useful to enable this filtering and manipulate the logs to extract the useful information from them. The lctl command can be used directly from the command-line to execute a single command, or it can be used interactively to execute multiple commands in a single invocation.

In this section, we describe the lctl commands which can be used effectively to obtain the required information from the logs. More detailed help on lctl can be found in the lctl reference section in the Lustre manual.

Note that the debug messages displayed with lctl are also subject to the kernel debug masks above! In other words, the filters are additive.

lctl debug_list 
 * Listing all the sub-systems/types. Use the following command to obtain a list of all the types and sub-systems:


 * Filtering. As mentioned before, the whole key to debugging such a system is limiting the debug log to what is really important. The filter command is the primary means of doing this:

lctl filter  ''


 * When lctl filters, it removes those lines from the displayed output only--this does not affect the contents of the debug log in the kernel's memory. As a result, you can print the log many times with different filtering levels without worrying about losing data.

lctl show 
 * Enabling the required debug messages. In order to show debug messages belonging to certain type or sub-system, use the show command as shown below:


 * Displaying the Log. Once you've setup your filters, debug_kernel pulls the data from the kernel logs, filters it appropriately, and displays or saves it as per the options specified in the command below: lctl debug_kernel [output filename] If the debugging is being done on User Mode Linux (UML), it might be useful to save the logs on the host machine so that they can be used at any later time too.

lctl debug_file  [output filename]
 * Filter a log on disk. If you already have a debug log saved to disk (probably from a crash), debug_file will process that:


 * Marking the Log. During the course of a debug session you may want to add markers or breaks to the log for many reasons: lctl mark [marker text] The marker text defaults to the current date and time. Three lines similar to these will be inserted into the debug log:


 * DEBUG MARKER: Tue Mar 5 16:06:44 EST 2002
 * DEBUG MARKER: Tue Mar 5 16:06:44 EST 2002


 * Clearing the Log. When you're ready to completely flush the kernel debug buffer, run the command:


 * lctl clear

A sample run of lctl is shown below: bash-2.04# ./lctl lctl > debug_kernel /tmp/lustre_logs/log_all Debug log: 324 lines, 324 kept, 0 dropped. lctl > filter trace Disabling output of type "trace" lctl > debug_kernel /tmp/lustre_logs/log_notrace Debug log: 324 lines, 282 kept, 42 dropped. lctl > show trace Enabling output of type "trace" lctl > filter portals Disabling output from subsystem "portals" lctl > debug_kernel /tmp/lustre_logs/log_noportals Debug log: 324 lines, 258 kept, 66 dropped.

Use of strace for Troubleshooting
strace is a system call trace utility made available by the operating system. It can be used to trace a system call, intercept all the systems calls made by a process, and record the system call name, arguments, and return values. This tool is useful when trying to troubleshoot a failed system call.

The strace can be invoked for a system call as shown below:

$strace  

A system call might sometimes fork child processes, we need to use the -f option in such case to trace the child processes also:

$strace -f  

We can redirect the strace output to a file that maybe examined at a later time:

$strace -o   

We can use the -ff option along with -o to cause the trace output to be saved in filename.pid, where pid is the process id of the process being traced.

Use -ttt to timestamp all lines in the strace output, so they can be correlated to operations in the lustre kernel debug log.

If the debugging is done in User mode Linux, it's a good idea to save the traces on the host machine by using the command shown below; here we assume that the hostfs is mounted on /r:

$strace -o /r/tmp/vi.strace

Looking at Disk Content
In Lustre, the information about objects that make a file is stored in the extended attributes of the file inode. This will contain a list of all the object ids and their locations (that is, which OST device stores them). Lustre has a tool called the lfs that can be used to obtain this information for a given file name via the getstripe subcommand. A corresponding lfs setstripe command can be used to specify the striping attributes of a new file or directory.

The lfs getstripe utility is written in C; it takes a Lustre filename as input and lists all the objects that form a part of this file. So, to obtain this information for the file /mnt/lustre/frog in Lustre filesystem, we would do:

The  debugfs tool is provided by the e2fsprogs package; it can be used for interactive debugging of an ext3/ldiskfs filesystem. It can either be used just to check the status, or it can be used to modify some information in the filesystem, maybe to correct the filesystem state. In Lustre, all the objects that belong to a file are stored in an underlying ldiskfs filesystem on the OST's. The filesystem uses the object id's as the file names. So, once the object id's are known, debugfs can be used to obtain the attributes of all the objects from the different OST's. A sample run for the /mnt/lustre/frog file used in the example above is shown here:

More help on debugfs can be obtained from the man pages.

Finding the lustre UUID of an OST
To find the Lustre UUID of an obdfilter disk (in the event, perhaps, you mix up the cables on your OST devices or the SCSI bus numbering suddenly changes and your SCSI devices get new names), use debugfs to get the last_rcvd file debugfs -R "dump last_rcvd /tmp/last_rcvf"

Tcpdump
Obsolete? Lustre provides a modified version of tcpdump that can be used to decode the complete Lustre message packet. [NOTE: It is currently out-of-date and unusable] The tool has more developed support to read packets from clients to OSTs; the functionality to decode the packets between clients and MDSs is not well developed yet.

Printing to /var/log/messages
To dump debug messages to the console set the corresponding debug mask in the printk flag: sysctl -w lnet.printk=-1

This slows down the system dramatically. It is also possible to selectively enable or disable this for particular flags: sysctl -w lnet.printk=+vfstrace sysctl -w lnet.printk=-vfstrace

In newer versions of Lustre (1.4.12, 1.6.5) it is even possible to disable warning, error, and console messages, though it is strongly recommended to have something like lctl debug_daemon running to capture this data to a local filesystem for debugging purposes.

Tracing Lock Traffic
We have built a special debug type category for tracing lock traffic:

NOTES Put at end - used only in extreme cases when we are helping them trace a bad problem but useful for admin to know.