Jeff Epler's blog

1 March 2016, 2:56 UTC

Literal copying of GPL code into ZFS on Linux

Recently, Canonical has announced that they plan to ship zfsonlinux in compiled form from their "main" repository. They rely on advice from their lawyers that the compiled form of zfs.ko, the kernel loadable module implementing zfs, is not a derivative of the linux kernel. This is important, because if zfsonlinux is a derivative of both GPL code and CDDL code, the two licenses impose incompatible requirements on the compiled form of the software, and distribution is not possible. (This is in contrast to Debian's plan to ship zfs in source form only in their next release (and also in the somewhat ghettoized "contrib" section rather than "main"); this is considered safer by many because the GPL's restrictions on code in source format are less stringent than code in object code or executable format)

There are two main ways that zfsonlinux's zfs.ko could be a derivative work of linux: First, and the option that many commenters have concentrated on, is if the act of compiling zfs also includes copyrighted portions of linux in a way that activates the GPL's restrictions because the combined work is "a work based on [the Linux kernel]". However, there is a second way that zfsonlinux could be subject to the GPL and CDDL simultaneously: if source code licensed exclusively under the GPL has been copied into the zfsonlinux source tree.

In this article, I collect some samples of code from zfsonlinux and compare those samples to code committed earlier to linux. I present the samples using a customized word diff algorithm. To reproduce my results, you will need to manually find the associated refs in linux.git and zfsonlinux/zfs.git and use your own word-diff algorithm.

I don't know whether I've found the worst of the code copying; I found the two examples given below pretty quickly, imagined that I had found just the tip of the iceberg, and then decided to write this article before looking for more. But I haven't found any more that are as clear-cut as these two examples are in my mind, while also being over ten lines long. Beginner's luck? Or did I find the 50 copied lines out of 260,000 lines in a half hour and that's the whole story?

Because I cannot speak for the authors of the code committed to linux.git which appear to be duplicated in zfsonlinux, it is impossible for me to say whether they have some private arrangement with the code authors that permit the use of the code snippets under the CDDL. If not, it's a legal question whether the amount of code copied is relevant under copyright law. In this area, I imagine caution is best; after all, in the US, Google's copying of the 9-line "RangeCheck" function (out of how many million lines in the JRE?) has been determined not to be de minimis, though in a new trial Google will assert a fair use defense regarding that copying.

(note: some popular RSS readers do not show the color coding of insertions and deletions)

Snippet A: linux at commit 5f99f4e79abc64ed9d93a4b0158b21c64ff7f478
Snippet B: zfsonlinux at commit 0f37d0c8bed442dd0d2c1b1dddd68653fa6eec66
Common text

static inline bool dir_emit(struct dir_context *ctx,
                           const char *name, int namelen,
    uint64_t ino, unsigned type)
       return ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type) == 0;
static inline bool dir_emit_dot(struct file *file, struct dir_context *ctx)
       return ctx->actor(ctx->dirent, ".", 1, ctx->pos,
                         file->f_path.dentry->d_inode->i_ino, DT_DIR) == 0;
static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx)
       return ctx->actor(ctx->dirent, "..", 2, ctx->pos,
                         parent_ino(file->f_path.dentry), DT_DIR) == 0;
static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx)
       if (ctx->pos == 0) {
               if (!dir_emit_dot(file, ctx))
                       return false;
               ctx->pos = 1;
       if (ctx->pos == 1) {
               if (!dir_emit_dotdot(file, ctx))
                       return false;
               ctx->pos = 2;
       return true;

Snippet A: linux at c3c532061e46156e8aab1268f38d66cfb63aeb2d
Snippet B: zfsonlinux at 5547c2f1bf49802835fd6c52f15115ba344a2a8b
Common text

static inline int bdi_setup_and_register(struct backing_dev_info *bdi, char *name,
                           unsigned int cap)
        char tmp[32];
        int errerror;

        bdi->name = name;
        bdi->capabilities = cap;
        errerror = bdi_init(bdi);
        if (errerror)
                return err;(error);

        sprintf(tmp, "%.28s%s", name, "-%d");
        errerror = bdi_register(bdi, NULL, tmp, atomic_long_inc_return(&bdi_seqzfs_bdi_seq));
        if (errerror) {
                return err;(error);

        return 0;(error);


1 September 2015, 14:39 UTC

DragonBoard™ 410c with rt-preempt failure

I was excited to obtain a DragonBoard, an affordable 64-bit ARM single-board computer, but unfortunately it hasn't lived up to my hopes.

First of all, it shipped with one terrible problem, making it useless for headless development: The onboard wireless doesn't receive multicast traffic, including ARP requests! And their kernel doesn't provide many modular drivers, so adding any old USB wireless dongle doesn't work until you rebuild the kernel. As of this writing, there is no useful workaround.

And that's when I hit the second show-stopper problem. I planned to build kernels for this thing anyway, because the goal is to run LinuxCNC on it with rt-preempt realtime. So I stuck in a large capacity micro-sd card, obtained the kernel source, built it, and rebooted with my new kernel.

(incidentally, testing kernels is a PITA. You have two choices: one, flash the one and only boot area with your new and untested kernel and hope for the best; two, tether to a PC (losing USB keyboard and mouse on the dragonboard!) and use fastboot every time you boot. ugh)

.. but the new kernel just didn't work. It scrolled kernel messages, but got stuck partway through booting. dmesg implicated the wireless card. This one at least has a workaround: cherry-pick a certain commit from their kernel git. As I understand it, this bug is triggered by using the compiler on the dragonboard, and not encountered with the linaro cross-compiler running on a traditional x86 desktop.

Anyway, having found out about this I was briefly celebratory. I booted with my own kernel and had a working USB dongle. Unfortunately, that celebration was short-lived. The USB dongle hasn't been terribly reliable either, particularly under high CPU load.

I soldiered on and patched the linaro 4.0 kernel with the 4.0-rt5 patchset. There were a few minor conflicts which I believe I resolved correctly. Unfortunately, the LinuxCNC latency-test readily encounters latencies above 15ms (15000us). LinuxCNC really would like sub-100us max latencies.

I briefly enabled tracers, and have traces that seem to implicate a variety of subsystems: networking, usb, and video *all* figure. More experienced developers than I will have to be the ones to sort out RT on 64-bit ARM.


4 March 2015, 19:45 UTC

Hide non-linux titles in humble bundle sales

Like many people over the age of 30, I remember when the Humble Bundle consistently offered Linux versions of almost everything in their bundles.

Those days are long gone, and now it's necessary to scrub over the "DRM FREE!" button of every title to find out whether it's on Linux.

But with this userscript (tested only on firefox with greasemonkey), titles that are not available on Linux are automatically greyed out and need trouble you no more.

If you're like me, and the number of times you boot a Windows machine to play video games is way under twice a year, remember to vote with your wallet: before checking out, open "choose where your money goes" and "developers", then slide the slider for all non-linux titles right down to zero.


24 June 2014, 12:35 UTC

Better pasting for irssi in X

While it's otherwise an excellent irc client, I've been frustrated by pasting in irssi. There are two main problems:

read more…

15 May 2014, 16:28 UTC

Samsung ARM Chromebook: the portable I've always wanted

As you might remember, I got a chromebook back in January. A few months later, I just want to say: this is the portable I've always wanted.

read more…

24 February 2014, 13:10 UTC

How do you check a signature on a PGP/Mime message

…I'll answer in Python. First, put your whole message in a file in unix "mbox" format (this will be the problem if you use some brain-dead GUI mailer!), then in Python extract the signature and the signed message, and finally invoke gpg:

import email
import os
import sys

with open(sys.argv[1]) as mfile: message = email.message_from_file(mfile)

if message.get_content_type() != "multipart/signed":
    raise SystemExit, "message not signed"

# Really, you'd want safe temporary filenames, and you'd want to clean them up
with open("msg", "wb") as msg: msg.write(message.get_payload(0).as_string())
with open("sig", "wb") as sig: sig.write(message.get_payload(1).get_payload())

# Delegate the real business to gpg
os.execvp("gpg", ["gpg", "--verify", "sig", "msg"])


31 January 2014, 18:05 UTC

Mosh automatic cleanup of dead sessions

I love mosh, using it to connect to a long-lived screen session from multiple computers (laptop, chromebook, $DAY_JOB, and phone).

One problem with it is that a mosh-server process that has no living client will linger for a very long time (forever?). This can happen for various reasons, such as letting a device's battery run down.

With some brainstorming help from the participants from #mosh, I came up with a way to automatically kill old mosh-server processes that probably represented defunct clients without killing ones that may represent working clients.

For a long time, my basic setup has been to run a command equivalent to: mosh myserver -- bin/cs where cs is a script which sets some environment variables and ends with exec screen, so I already had an excellent location to put cleanup code.

I also felt that the cleanup rule I wanted was: kill all mosh-server processes started from the same client. $SSH_CLIENT was suggested for this, but it's not useful since my portable devices naturally connect from different networks with different IP addresses (that's the point of mosh after all!) So I jumped to the conclusion that I needed a unique identifier. Why not involve a UUID?

As soon as I realized I needed to pass the UUID on the commandline or environment of cs, I realized that meant it would show up in the mosh-server commandline. So that led to the following snippet: ($i is already identified as being the UUID= argument):

    ps h --sort start_time -o pid,command -C mosh-server |
        grep "$i" |
        head --lines=-1 |
        awk '{print $1}' |
        xargs --no-run-if-empty -n 1 --verbose kill

That seems to work! One final wrinkle, though: In mosh irssi connectbot, there's no way to specify the mosh commandline directly. Hoever, there is "Requested mosh server". I created a wrapper script reading:

exec mosh-server "$@" -- bin/cs UUID=...
and used that script (with full path, in my case) as the configuration value.

Now I shouldn't have to worry about mosh-server processes piling up on my main linux box anymore.


25 January 2014, 16:17 UTC

Ctrl-digit to switch to tab on Linux Firefox

Since I switch between Linux Firefox, Windows Firefox, and Chrome, it would be nice if I could access tabs with the same shortcut everywhere. The path of least resistance turns out to be to make Linux Firefox understand Ctrl-<digit> for tab switching. So here's my first Firefox extension, which seems to do the trick:

Files currently attached to this page:


(tested on Iceweasel 26.0)


24 January 2014, 17:06 UTC

Got A Chromebook

23 January 2014, 22:18 UTC

pnacl vs Debian Jessie

21 December 2013, 3:53 UTC

First few weeks on Digital Ocean

13 December 2013, 23:26 UTC

Benchmarking ungeli on real data

6 December 2013, 19:31 UTC

Changing hosting providers

2 December 2013, 19:30 UTC

mailpie moves to github

All older entries
Website Copyright © 2004-2017 Jeff Epler