Autotools and pthreads

Today, I’ve been setting up autotools for a little project of mine because it started using too many cflags to type in all the time. I used autotools before but still had to look up a lot of things, this document was quite helpful. If you’re searching for a beginner friendly tutorial, look here.

However, my earlier autotools-using projects did not use pthreads, and autoscan apparently does not handle this case automatically. Well, how do I get autotools to set the right flags?

Searching the net for a while, I found that ACX_PTHREAD from the AC Autoconf Macro Archive should do the trick. Gentoo has an ebuild for this macro library (sys-devel/ac-archive), so installing it was no problem. I just needed to figure out how to let autotools find the macro from the library. Solution:

  1. Add the macro to configure.ac
  2. Use the acinclude tool

I added the following to configure.ac:

ACX_PTHREAD
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
CC="$PTHREAD_CC"

Afterwards, running

$ acinclude

created a file called acinclude.m4. This file will be used automatically by the normal autotools run, and that’s it. 🙂

Update 2013-07-10: On Ubuntu, the packet containing the ACX_PTHREAD macro is called autoconf-archive, running acinclude is not necessary. A normal autoreconf will do.

Instant minimal web server

Since quite some time I make sure to compile my system’s BusyBox with the included httpd to have a minimal web server available when I need it. A quick

$ busybox httpd -p 8080

is enough to offer the current directory via HTTP on port 8080. This post describes an alternative which has the advantage of being available on almost every Linux installation: Python comes with a built-in web server. Just go into the directory you want to use as the server’s root and run:

$ python -m SimpleHTTPServer 8080

If you don’t specify a port number, the server will use port 8000 (and fail if it can’t bind it). Directory listings are supported. In Python 3, the module is called http.server. Example:

$ python3 -m http.server 8113
Serving HTTP on 0.0.0.0 port 8113 ...
localhost - - [11/Jun/2010 19:53:26] "GET / HTTP/1.1" 200 -
localhost - - [11/Jun/2010 19:53:27] code 404, message File not found
localhost - - [11/Jun/2010 19:53:27] "GET /favicon.ico HTTP/1.1" 404 -
[some more transfers...]
^C
Keyboard interrupt received, exiting.

Quite useful when you just want to get some files from one computer to another, and the recipient needs only a browser (or any other HTTP client). However, BusyBox’s httpd is more configurable (just check busybox httpd --help), so I am going to keep it around.

Partitions on loop and network block devices

Some time ago I wanted to access a disk image for a virtual machine using a loop device, but I couldn’t access the partitions – /dev/loop0 pointed to the “disk”, no partitions available. Well, I learned that it is possible, and here’s how.

Let’s take a closer look at the nbd module:

# modinfo nbd
filename: /lib/modules/2.6.34/kernel/drivers/block/nbd.ko
license: GPL
description: Network Block Device
depends:
vermagic: 2.6.34 mod_unload
parm: nbds_max:number of network block devices to initialize (default: 16) (int)
parm: max_part:number of partitions per device (default: 0) (int)
parm: debugflags:flags for controlling debug output (int)

max_part really says it all. The loop module has a parameter of the same name. Just do:

# modprobe nbd max_part=8

Connect to the target device as usual, use fdisk (or another partitioning tool) on the NBD, and you’ll get a lot of devices named something like /dev/nbd0p1, /dev/nbd0p2 and so on. I tested a layout with two primary, one extended and two logical partitions. Excerpt from mount output after formatting and mounting three of them:

/dev/nbd0p1 on /mnt/p1 type ext2 (rw)
/dev/nbd0p5 on /mnt/p5 type ext4 (rw)
/dev/nbd0p6 on /mnt/p6 type btrfs (rw)

As you probably guessed, the only difference between partitions on an NBD and a loop device is how to set up the “disk”. Just load the right module with an appropriate value for max_part and have fun!

(I read about the parameter here and in the comments to this post.)

NBD over a slow connection

My previous experiments with NBD used small files and fast connections. Today, I tried a different scenario: both server and client used normal DSL connections.

Obviously, setting up the NBD was somewhat slower compared to my home network. What really surprised me was the time it took to create an ext4 filesystem on the 20GB network block device: slightly more than one hour. I used iotop to monitor the data throughput and found that mke2fs wrote about 115KB/s. Lesson learned: If you have the possibility, create the filesystem on the server and export the NBD ready to use.

Performance test

For this test, I copied three big files to the NBD. Copying was done using rsync with a subsequent call to sync to make sure that caching didn’t change the result. I used date +%s to create timestamps. Before I get to the results, these are the statistics form rsync’s --progress option:

110605205 100%   20.02MB/s   0:00:05 (xfer#1, to-check=2/3)
123533832 100%  127.37kB/s   0:15:47 (xfer#2, to-check=1/3)
 81317264 100%   22.38MB/s   0:00:03 (xfer#3, to-check=0/3)

The very high transfer speeds for the first and last files are a result of the filesystem cache. Rsync is done, and the data will migrate across the wire in the background. To find out when this was done I added the sync, and here are the results:

  • rsync start to finish: 1688 seconds
  • rsync finish to sync finish: 912 seconds
  • total: 2600 seconds

With a combined file size of 308063 KB that’s an average transfer speed of 118.5KB/s or 948Kb/s. According to the ISP, my connection should have an upstream speed of 1Mb/s. That’s a small overhead for SSH and NBD. 🙂

NBD through SSH

NBD is short for Linux’s “network block device”. On the client side, an NBD looks like any other block device, however, all data is stored on a server and reads and writes will be sent across the network. NBD does not offer any security beyond IP-whitelisting, which is why I want to send my data through an SSH tunnel.

Installation

Usually it will be best to install NBD from your distribution’s repository. The Gentoo package is called sys-block/nbd and will install both the client and server userland-tools, Ubuntu has separate packages called nbd-server and nbd-client. If you want to install manually, you can download the source via the NBD homepage. The server is a pure user space application, while the client application handles only connection/disconnection and hands over to the kernel for normal operation. If you compile your own kernel, make sure to activate NBD support on the client (set CONFIG_BLK_DEV_NBD to “m” or “y”).

Server setup

The storage space for the NBD can be an image file or any other block device (real partition, LVM logical volume or whatever). Once you have that, you’ll just need to start the server. The server does not need to run as root (unless you want to use a privileged port), read/write access to the storage is enough. Create a small image file for testing and start the server:

# dd if=/dev/zero bs=1M count=0 seek=80 of=/tmp/nbd-test.img
# nbd-server 127.0.0.1:10000 /tmp/nbd-test.img

The first argument tells the server which IP and port to bind to, the second which device to use. There are bunch of other options, like “-r” to export read-only. Just take a look at the man page. 😉 Binding to 127.0.0.1 will prevent anyone who can’t log in to the server from connecting to the NBD. The path to the storage file or device must be absolute.

Connecting to the NBD

The server is up, so the next step is to connect the client. If you haven’t already, load the NBD kernel module:

# modprobe nbd

Now we have to set up the SSH tunnel. My server in this example is called yukari:

# ssh -N -L 10001:127.0.0.1:10000 yukari

-L 10001:127.0.0.1:10000” is the key part: TCP connections to port 10001 on the local host will be forwarded to the remote host and sent to 127.0.0.1:10000. You could use “-L 10001:example.com:80” to access the example.com website through your tunnel. Fun fact: this works even if the tunnel is IPv4 and the endpoint IPv6, as long as the SSH gateway has IPv6 connectivity (or the other way around – just the TCP connection is forwarded, after all).

-N” tells SSH not to run any command on the server (like open a shell). Without -N you’ll get a shell as usual, and the tunnel will be gone as soon as you exit.

Let’s connect the NBD using the local tunnel endpoint:

# nbd-client localhost 10001 /dev/nbd0
Negotiation: ..size = 81920KB
bs=1024, sz=81920

/dev/nbd0 can be used like any other block device. Create a filesystem, mount it, put some data on it, unmount. If you worry about an attacker getting access to the storage: encrypt it. Once you’re done, disconnect the NBD:

# nbd-client -d /dev/nbd0
Disconnecting: que, disconnect, sock, done

Caveats

  • Never have two or more clients accessing the NBD read/write at the same time (exceptions apply for some cluster file systems).
  • Exporting the NBD to localhost only and accessing via SSH protects against attackers on the network, but not on the local machine. Users on the server will be able to read your data (unless it’s encrypted) and even overwrite it (unless your NBD is read-only).

Links

Design a site like this with WordPress.com
Get started