Eric Schrock's Blog

Category: OpenSolaris

A while ago, for my own amusement, I went through the Solaris source base and searched for the source files with the most lines. For some unknown reason this popped in my head yesterday so I decided to try it again. Here are the top 10 longest files in OpenSolaris:

Length Source File
29944 usr/src/uts/common/io/scsi/targets/sd.c
25920 [closed]
25429 usr/src/uts/common/inet/tcp/tcp.c
22789 [closed]
16954 [closed]
16339 [closed]
15667 usr/src/uts/common/fs/nfs4_vnops.c
14550 usr/src/uts/sfmmu/vm/hat_sfmmu.c
13931 usr/src/uts/common/dtrace/dtrace.c
13027 usr/src/uts/sun4u/starfire/io/idn_proto.c

You can see some of the largest files are still closed source. Note that the length of the file doesn’t necessarily indicate anything about the quality of the code, it’s more just idle curiosity. Knowing the quality of online journalism these days, I’m sure this will get turned into “Solaris source reveals completely unmaintable code” …

After looking at this, I decided a much more interesting question was “which source files are the most commented?” To answer this question, I ran evey source file through a script I found that counts the number of commented lines in each file. I filtered out those files that were less than 500 lines long, and ran the results through another script to calculate the percentage of lines that were commented. Lines which have a comment along with source are considered a commented line, so some of the ratios were quite high. I filtered out those files which were mostly tables (like uwidth.c), as these comments didn’t really count. I also ignored header files, because they tend to be far more commented that the implementation itself. In the end I had the following list:

Percentage File
62.9% usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.c
58.7% usr/src/cmd/sgs/libld/amd64/amd64unwind.c
58.4% usr/src/lib/libtecla/common/expand.c
56.7% usr/src/cmd/lvm/metassist/common/volume_nvpair.c
56.6% usr/src/lib/libtecla/common/cplfile.c
55.6% usr/src/lib/libc/port/gen/mon.c
55.4% usr/src/lib/libadm/common/devreserv.c
55.1% usr/src/lib/libtecla/common/getline.c
54.5% [closed]
54.3% usr/src/uts/common/io/ib/ibtl/ibtl_mem.c

Now, when I write code I tend to hover in the 20-30% comments range (my best of those in the gate is gfs.c, which with Dave’s help is 44% comments). Some of the above are rather over-commented (especially snmp_sub.c, which likes to repeat comments above and within functions).

I found this little experiment interesting, but please don’t base any conclusions on these results. They are for entertainment purposes only.

Technorati Tag:

Since Bryan solved my last puzzle a little too quickly, this post will serve as a followup puzzle that may or may not be easier. All I know is that Bryan is ineligible this time around 😉

Once again, the rules are simple. The solution must be a single line dcmd that produces precise output without any additional steps or post processing. For this puzzle, you’re actually allowed two commands: one for your dcmd, and another for ‘::run’. For this puzzle, we’ll be using the following test program:

#include 
int
main(int argc, char **argv)
{
int i;
srand(time(NULL));
for (i = 0; i < 100; i++)
write(rand() % 10, NULL, 0);
return (0);
}

The puzzle itself demonstrates how conditional breakpoints can be implemented on top of existing functionality:

Stop the test program on entry to the write() system call only when the file descriptor number is 7

I thought this one would be harder than the last, but now I’m not so sure, especially once you absorb some of the finer points from the last post.

Technorati Tag:

On a lighter note, I’d thought I post an “MDB puzzle” for the truly masochistic out there. I was going to post two, but the second one was just way too hard, and I was having a hard time finding a good test case in userland. You can check out how we hope to make this better over at the MDB community. Unfortunately I don’t have anything cool to give away, other than my blessing as a truly elite MDB hacker. Of course, if you get this one right I might just have to post the second one I had in mind…

The rules are simple. You can only use a single line command in ‘mdb -k’. You cannot use shell escapes (!). Your answer must be precise, without requiring post-processing through some other utility. Leaders of the MDB community and their relatives are ineligible, though other Sun employees are welcome to try. And now, the puzzle:

Print out the current working directory of every process with an effective user id of 0.

Should be simple, right? Well, make sure you go home and study your MDB pipelines, because you’ll need some clever tricks to get this one just right…

Technorati Tags:

On opening day, I chose to post an entry on adding
a system call
to OpenSolaris. Considering the feedback, I thought I’d
continue with brief “How-To add to OpenSolaris” documents for a while.
There’s a lot to choose from here, so I’ll just pick them off as quick as I can.
Todays topic as adding a new kernel module to OpenSolaris.

For the sake of discussion, we will be adding a new module that does nothing
apart from print a message on load and unload. It will be architecture-neutral,
and be distributed as part of a separate package (to give you a taste of our
packaging system). We’ll continue my narcissistic
tradition and name this the “schrock” module.

1. Adding source

To begin, you must put your source somewhere in the tree. It must be put
somewhere under usr/src/uts/common,
but exactly where depends on the type of module. Just about the only real rule
is that filesystems go in the “fs” directory, but other than that there are no
real rules. The bulk of the modules live in the “io” directory, since the
majority of modules are drivers of some kind. For now, we’ll put ‘schrock.c’ in
the “io” directory:

#include <sys/modctl.h>
#include <sys/cmn_err.h>
static struct modldrv modldrv = {
&mod_miscops,
"schrock module %I%",
NULL
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modldrv, NULL
};
int
_init(void)
{
cmn_err(CE_WARN, "OpenSolaris has arrived");
return (mod_install(&modlinkage));
}
int
_fini(void)
{
cmn_err(CE_WARN, "OpenSolaris has left the building");
return (mod_remove(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}

The code is pretty simple, and is basically the minimum needed to add
a module to the system. You notice we use ‘mod_miscops’ in our modldrv.
If we were adding a device driver or filesystem, we would be using a
different set of linkage structures.

2. Creating Makefiles

We must add two Makefiles to get this building:

usr/src/uts/intel/schrock/Makefile
usr/src/uts/sparc/schrock/Makefile

With contents similar to the following:

UTSBASE = ../..
MODULE          = schrock
OBJECTS         = $(SCHROCK_OBJS:%=$(OBJS_DIR)/%)
LINTS           = $(SCHROCK_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE      = $(ROOT_MISC_DIR)/$(MODULE)
include $(UTSBASE)/intel/Makefile.intel
ALL_TARGET      = $(BINARY)
LINT_TARGET     = $(MODULE).lint
INSTALL_TARGET  = $(BINARY) $(ROOTMODULE)
CFLAGS          += $(CCVERBOSE)
.KEEP_STATE:
def:            $(DEF_DEPS)
all:            $(ALL_DEPS)
clean:          $(CLEAN_DEPS)
clobber:        $(CLOBBER_DEPS)
lint:           $(LINT_DEPS)
modlintlib:     $(MODLINTLIB_DEPS)
clean.lint:     $(CLEAN_LINT_DEPS)
install:        $(INSTALL_DEPS)
include $(UTSBASE)/intel/Makefile.targ

3. Modifying existing Makefiles

There are two remaining Makefile chores before we can continue. First, we have
to add the set of files to usr/src/uts/common/Makefile.files:

KMDB_OBJS += kdrv.o
SCHROCK_OBJS += schrock.o
BGE_OBJS += bge_main.o bge_chip.o bge_kstats.o bge_log.o bge_ndd.o \
bge_atomic.o bge_mii.o bge_send.o bge_recv.o

If you had created a subdirectory for your module instead of placing it in
“io”, you would also have to add a set of rules to usr/src/uts/common/Makefile.rules.
If you need to do this, make sure you get both the object targets and the
lint targets, or you’ll get build failures if you try to run lint.

You’ll also need to modify the usr/src/uts/intel/Makefile.intel
file, as well as the corresponding SPARC version:

MISC_KMODS      += usba usba10
MISC_KMODS      += zmod
MISC_KMODS      += schrock
#
#       Software Cryptographic Providers (/kernel/crypto):
#

4. Creating a package

As mentioned previously, we want this module to live in its own package. We
start by creating usr/src/pkgdefs/SUNWschrock and adding it to the list
of COMMON_SUBDIRS in usr/src/pkgdefs/Makefile:

SUNWsasnm \
SUNWsbp2 \
        SUNWschrock \
SUNWscpr  \
SUNWscpu  \

Next, we have to add a skeleton package system. Since we’re only adding a
miscellaneous module and not a full blown driver, we only need a simple
skeleton. First, there’s the Makefile:

include ../Makefile.com
.KEEP_STATE:
all: $(FILES)
install: all pkg
include ../Makefile.targ

A ‘pkgimfo.tmpl’ file:

PKG=SUNWschrock
NAME="Sample kernel module"
ARCH="ISA"
VERSION="ONVERS,REV=0.0.0"
SUNW_PRODNAME="SunOS"
SUNW_PRODVERS="RELEASE/VERSION"
SUNW_PKGVERS="1.0"
SUNW_PKGTYPE="root"
MAXINST="1000"
CATEGORY="system"
VENDOR="Sun Microsystems, Inc."
DESC="Sample kernel module"
CLASSES="none"
HOTLINE="Please contact your local service provider"
EMAIL=""
BASEDIR=/
SUNW_PKG_ALLZONES="true"
SUNW_PKG_HOLLOW="true"

And ‘prototype_com’, ‘prototype_i386’, and ‘prototype_sparc’ (elided) files:

# prototype_i386
!include prototype_com
d none kernel/misc/amd64 755 root sys
f none kernel/misc/amd64/schrock 755 root sys
# prototype_com
i pkginfo
d none kernel 755 root sys
d none kernel/misc 755 root sys
f none kernel/misc/schrock 755 root sys

5. Putting it all together

If we pkgadd our package, or BFU to the resulting archives, we can see our
module in action:

halcyon# modload /kernel/misc/schrock
Jun 19 12:43:35 halcyon schrock: WARNING: OpenSolaris has arrived
halcyon# modunload -i 197
Jun 19 12:43:50 halcyon schrock: WARNING: OpenSolaris has left the building

This process is common to all kernel modules (though packaging is simpler for
those combined in SUNWckr, for example). Things get a little more complicated
and a little more specific when you begin to talk about drivers or filesystems
in particular. I’ll try to create some simple howtos for those as
well.

Technorati Tag:

Just a heads up that we’ve formed a new OpenSolaris Observability community. There’s not much there night now, but I encourage to head over and check out what OpenSolaris has to offer. Or come to the discussion forum and gripe about what features we’re still missing. Topics covered include process, system, hardware, and post mortem observability. We’ll be adding much more content as soon as we can.

Technorati Tag:

So talking to Ben last night convinced me I needed to finish up the GDB to MDB reference that I started last month. So here’s part two.

GDB MDB Description

Program Stack

backtrace n ::stack
$C
Display stack backtrace for the current thread
thread::findstack
-v
Display a stack for a given thread. In the kernel, thread
is the address of the kthread_t. In userland, it's the thread
identifier.
info ... - Display information about the current frame. MDB doesn't support
the debugging data necessary to maintain the frame abstraction.

Execution Control

continue
c
:c Continue target.
stepi
si
::step
]
Step to the next machine instruction. MDB does not support
stepping by source lines.
nexti
ni
::step
over
[
Step over the next machine instruction, skipping any function
calls.
finish ::step
out
Continue until returning from the current frame.
jump *address address&gtreg Jump to the given location. In MDB, reg depends on your
platform. For SPARC it's 'pc', for i386 its 'eip', and for amd64 it's
'rip'.

Display

print expr addr::print
expr
Print the given expression. In GDB you can specify variable
names as well as addresses. For MDB, you give a particular address and then
specify the type to display (which can include dereferencing of members,
etc).
print /f addr/f Print data in a precise format. See ::formats for a
list of MDB formats.
disassem addr addr::dis Dissasemble text at the given address, or the current PC if no
address is specified

This is just a primer. Both programs support a wide variety of additional
options. Running 'mdb -k', you can quickly see just how many commands are out
there:

> ::dcmds ! wc -l
385
> ::walkers ! wc -l
436

One helpful trick is ::dcmds ! grep thing, which searches the
description of each command. Good luck, and join the discussion over at the
OpenSolaris MDB
community
if you have any questions or tips of your own.

Technorati tag:
Technorati tag:
Technorati tag:

Recent Posts

April 21, 2013
February 28, 2013
August 14, 2012
July 28, 2012

Archives