Blog

Getting Ready for Linux 2.6-test1

Linus released 2.6.0-test1 this week, which means the 2.5 development series has finally put on a tie and is pretending to be suitable for polite company. It is still a test kernel. I would not install it on the machine that pays the bills, but I do want to know what will break before 2.6 becomes ordinary.

The obvious approach is to keep the current 2.4 kernel installed, add 2.6 beside it, and make the boot loader offer both. Do not replace the known-good entry. This sounds insultingly basic until the new kernel cannot find its root filesystem and the old entry is the difference between five minutes and a rescue disk.

My first checklist is mostly userspace:

module-init-tools
recent modutils-compatible configuration
procps that understands the newer /proc output
filesystem tools matching every filesystem in use
working boot loader configuration

The module change is the one most likely to surprise people. Linux 2.6 uses a new module format and the module-init-tools programs. They can coexist with the old tools, so one installation can boot both 2.4 and 2.6. Check this before rebooting, not while staring at an emergency shell.

I also build the drivers needed to reach the root filesystem directly into the kernel for the first attempt. That means the disk controller, root filesystem, and anything else between the kernel and /sbin/init. An initial ramdisk is useful, but removing it from the first experiment makes failures much easier to understand.

The device model has changed substantially. A mounted sysfs, normally at /sys, exposes devices and drivers in a structured tree. Old scripts that scrape /proc or assume particular module names deserve suspicion. Sound users should note that ALSA is now in the kernel tree; OSS compatibility exists, but that does not make every mixer setup identical.

Finally, save the exact .config and the complete build output. make oldconfig is a convenient starting point, not proof that old choices still mean the same thing. Read every new question that affects storage, filesystems, networking, or the console.

The kernel has many attractive improvements: preemption, the O(1) scheduler, better threading support, and a much saner device model. None of them will comfort you if the machine does not boot. My plan is boring: test hardware, test userspace, test rollback, then become adventurous. Adventure is much nicer with a working fallback kernel.

What Safari Means for KHTML

I have spent enough time explaining that Konqueror is not merely a file manager with a web page bolted onto it. Now Apple has provided a rather convincing demonstration for me: Safari uses KHTML and KJS as the basis of its rendering engine.

The obvious reaction is pride. A small, portable engine built by the KDE project was good enough to become the foundation of Apple’s browser. That says more about the quality of the code than a dozen benchmark charts could.

The practical implication is more interesting. Web authors who previously tested only Internet Explorer and Mozilla now have a commercial reason to care about KHTML behaviour. Fixing a standards bug in KHTML can improve two browsers, and work done by Apple can potentially flow back to Konqueror under the LGPL.

“Potentially” is doing some work there. Apple’s first published changes arrived as large patches against old snapshots, which are not pleasant to merge. Source availability is not the same thing as easy collaboration. A patch the size of a small moon is technically useful, but it does not make the maintainer’s afternoon better.

Still, this is a very good problem to have. KHTML now has another serious user, more testing, and engineers being paid to improve it. KDE should be friendly but firm about working in manageable changes. If both sides manage that, Konqueror users may benefit every time Safari improves, and the web gets another standards-minded engine instead of another collection of browser-specific tricks.

Keeping Work Out of a Network Interrupt

I put packet bookkeeping into a network device’s interrupt handler because the information was conveniently available there. Under load, the machine reminded me that convenience inside interrupt context is borrowed at unreasonable interest.

The interrupt handler should acknowledge the device, collect enough status to know what happened, move completed descriptors along, and arrange deferred processing where appropriate. It cannot sleep, and time spent there delays other interrupt work. Long parsing, allocation loops, or diagnostic printing are especially poor guests.

Linux 2.4 offers deferred mechanisms including tasklets and the network receive path’s softirq processing. A driver can prepare received skbs and pass them to netif_rx(), allowing the protocol stack to process packets outside the hard interrupt handler. For driver-specific deferred work, I put the tasklet in the device’s private state:

struct sample_dev {
        struct tasklet_struct rx_tasklet;
        /* rings, locks, and device state */
};

static void sample_tasklet(unsigned long data)
{
        struct sample_dev *dev = (struct sample_dev *)data;

        service_completed_packets(dev);
}

static void sample_init_tasklet(struct sample_dev *dev)
{
        tasklet_init(&dev->rx_tasklet, sample_tasklet,
                     (unsigned long)dev);
}

sample_init_tasklet() runs after dev is allocated and before the interrupt can schedule dev->rx_tasklet. Teardown disables that interrupt source, calls tasklet_kill(&dev->rx_tasklet), and only then frees dev. The callback therefore never receives the null value that a static DECLARE_TASKLET(..., 0) would have supplied.

Shared rings and status fields need protection across the interrupt, deferred function, transmit entry point, and process-context control operations. I use spinlocks where the data can be touched in interrupt context and choose the interrupt-disabling variant when the same processor could otherwise interrupt a lock holder. I keep the protected section short and never call a function that can sleep while holding it.

There is a balance. Deferring every tiny operation adds overhead and can complicate ordering, while doing everything in the handler harms latency. I measure under sustained receive and transmit load, watch dropped packets, and check that another device’s interrupts are not starved.

Interrupt acknowledgement order is device-specific and worth documenting beside the handler. A level-triggered interrupt that remains asserted can immediately enter again; acknowledging too early on other hardware may lose status that has not been copied. I read the device manual rather than deriving this order from whichever experiment happened not to hang.

Shutdown receives the same scrutiny. The driver disables the device’s interrupt source, prevents new deferred work, frees the IRQ with the required synchronization, and only then releases rings and private data. Otherwise a late tasklet can faithfully process memory that has already acquired a new purpose.

I want the hard interrupt path to be visibly bounded. One caveat: printk can completely distort timing here. A hundred helpful messages per second soon become the performance problem, a promotion few debug statements deserve.

Merging KParts Actions Without Duplicates

I embedded a part and ended up with two Edit menus, three separators, and no obvious place to put Find. Every individual action worked. Their diplomacy was lacking.

KParts uses XMLGUI to merge the shell’s actions with the active part’s actions. The shell supplies a main XML resource, the part supplies its own, and named menu locations and merge points tell the GUI factory where contributions belong. The names, not their visual positions, form the contract.

A part can declare an action and place it into a standard menu:

<!DOCTYPE kpartgui>
<kpartgui name="note_part" version="1">
  <MenuBar>
    <Menu name="edit"><text>Edit</text>
      <Action name="note_find"/>
    </Menu>
  </MenuBar>
</kpartgui>

The C++ action collection must use the same action name:

KAction *find = new KAction(i18n("Find"), "find", CTRL + Key_F,
                            this, SLOT(slotFind()),
                            actionCollection(), "note_find");

If the XML name and action-collection name differ, the merge cannot place the action. If the part invents a menu name that the shell does not recognize, it may create a second menu instead of contributing to the first. I now compare the shell and part resource files side by side before touching C++.

Activation matters too. A shell hosting several parts should add the active client’s GUI and remove or replace it when focus moves. Leaving an old client registered explains actions that continue targeting a document no longer visible. I test by switching parts repeatedly, not just by opening one and closing the program.

Versioning the XML resource helps installed updates replace cached expectations, but it does not excuse stale files in the wrong prefix. When changes appear to be ignored, I inspect the paths reported by kde-config, remove obsolete application-owned resources, and rebuild the service cache if appropriate.

Action state remains the part’s responsibility. When a read-only document becomes active, its Cut action should be disabled before the GUI is merged, and selection changes should update it afterward. The shell should not infer document capabilities from menu names. It hosts the action; the part knows whether invoking it makes sense.

For debugging, I temporarily give each contribution an unmistakable label and watch the terminal for XMLGUI warnings. Once placement is correct, I restore the proper translated text. This is faster than deciding which of two identical separators came from which file.

I prefer a small part resource that contributes document-specific actions while the shell owns window actions such as New Window and Quit. The caveat is that the boundary requires discipline: an action should live where its state and target live. Otherwise XMLGUI can merge the menu perfectly and still dispatch Find to yesterday’s document, which is technically impressive but not helpful.

Building a Tiny KIO Slave

I had an application talking to a small read-only service and was about to put the protocol code directly into its file dialog path. A KIO slave turned out to be a cleaner experiment: teach KDE one URL scheme, then let Konqueror and any KIO-aware application use it.

The slave is a separate process driven through KIO’s protocol. A class derived from KIO::SlaveBase implements operations such as get, stat, or listDir, depending on what the scheme supports. For a tiny read-only resource, get is enough to prove the mechanism:

void NoteProtocol::get(const KURL &url)
{
    QByteArray bytes = loadNote(url.path());

    mimeType("text/plain");
    totalSize(bytes.size());
    data(bytes);
    data(QByteArray());
    finished();
}

Real code must report failures with error() rather than returning silently. It should also send data in useful chunks for large objects instead of reading everything into memory as this demonstration does. The empty data block marks the end of data before finished() completes the operation.

KIO discovers the slave through an installed protocol description and service information. Those files state the scheme, executable, supported operations, and whether the protocol works with files, directories, reading, or writing. If Konqueror says the protocol is unknown, I check installation paths and run kbuildsycoca before blaming the C++.

The process boundary is the interesting part. The client starts a KIO job. KIO selects and communicates with the slave, and the slave translates operations into the remote or special resource’s rules. A failure in the protocol handler need not take the client application down with it, and authentication or progress can use KDE’s common machinery.

I am careful not to claim operations the protocol cannot honor. Advertising rename for an immutable service only moves the error from an absent menu item to an annoyed user. stat results must also be consistent with get; applications rely on metadata for decisions before fetching.

I test the scheme directly in Konqueror and with a tiny KIO client, including a missing object, an empty object, and a path containing escaped characters. URL decoding must happen at the protocol boundary exactly once. Decoding twice turns a perfectly legal percent sign into an accidental instruction.

My preference is a KIO slave when a resource genuinely behaves like a hierarchy of files or directories and should be available across KDE. For one private command, DCOP or an application-specific class is smaller. Giving every service a URL is attractive, but some services are verbs wearing a hat.