WelcomeWelcome | FAQFAQ | DownloadsDownloads | WikiWiki

Author Topic: Compiling blockdev as a standalone extension (or: how to "cheat" ioctl calls)  (Read 5588 times)

Offline qopit

  • Jr. Member
  • **
  • Posts: 81
I know that blockdev is in the util-linux-ng extension, but I would like to have a standalone blockdev similar to how there is a standalone cfdisk (which is also in util-linux-ng).

However - I can't find the source for blockdev, and even when I do find it, I'm not sure how to go about compiling such a wee application into an extension.  When I *do* find the blockdev code I'm pretty certain there will be no ./configure, make, make install setup.  I would certainly like to learn how to do this, though.  Any tips?  How was cfdisk done?  I can't find info on this type of extension in the wiki or forums.

Taking a different tack, I *have* found the implementation code for putting blockdev functionality into busybox:
http://git.busybox.net/busybox/tree/util-linux/blockdev.c

Looking into this it shows that blockdev is just a thin wrapper around calls to ioctl.  I'm not interested in remastering busybox, but am wondering if there is some other non-pretty way to get the appropriate ioctl calls done with an existing command/extension without the need for the blockdev wrapper.

So... I definitely would like to know how to make miniscule extensions like blockdev would be, but I am also definitely interested in any alternative hacksaw methods for making ioctl calls.  Any help appreciated!

For blockdev, my end objective is to put the equivalent of "blockdev --setra 4096 /dev/sda" into the boot process, which beefs up the read-ahead on sda from the kernel default of 256.

Offline curaga

  • Administrator
  • Hero Member
  • *****
  • Posts: 11044
1. Get util-linux extension
2. Copy binary out

Alternatively

1. Build busybox with only blockdev

;)

But if you only need that one ioctl, you could just code that in C. Would be a couple lines, and smaller than either of the blockdev binaries.
The only barriers that can stop you are the ones you create yourself.

Offline qopit

  • Jr. Member
  • **
  • Posts: 81
1. Get util-linux extension
2. Copy binary out

... the fact that that did not even occur to me is embarrassing.  :-[  I guess I was both assuming that util-linux was busybox-like in that functionality was all shoved into one file (clearly not), and distracted by trying to figure out how to do it myself.

With this extraction approach, I guess you would just pull the file out, drop it in /usr/local/sbin, and add it to .filetool.lst?

However - I'm still interested in how to make an extension out of something like this.  I found the latest blockdev source here:
http://util-linux.sourcearchive.com/documentation/2.19.1-5/blockdev_8c_source.html

But if you only need that one ioctl, you could just code that in C. Would be a couple lines, and smaller than either of the blockdev binaries.

blockdev in util-linux-ng is  only 10kB, but I'm definitely interested in trying to make the small file you mention, if only to get more comfortable with the process.  I'll fiddle with it.

Is there a general application/wrapper that allows ioctl calls from the cmdline?

Offline curaga

  • Administrator
  • Hero Member
  • *****
  • Posts: 11044
With this extraction approach, I guess you would just pull the file out, drop it in /usr/local/sbin, and add it to .filetool.lst?

Yes.

Quote
However - I'm still interested in how to make an extension out of something like this.  I found the latest blockdev source here:
http://util-linux.sourcearchive.com/documentation/2.19.1-5/blockdev_8c_source.html

You'd build util-linux as normal, and either skip make install & manually copy the binary, or make install, and remove everything else. Depending on the build config, you may be able to save time and just build the one binary.

Quote
blockdev in util-linux-ng is  only 10kB, but I'm definitely interested in trying to make the small file you mention, if only to get more comfortable with the process.  I'll fiddle with it.

Is there a general application/wrapper that allows ioctl calls from the cmdline?

None that I know of. ioctls differ a lot in what they can take as arguments.
The only barriers that can stop you are the ones you create yourself.

Offline qopit

  • Jr. Member
  • **
  • Posts: 81
For future reference, per curaga's suggestion, I wrote the following puny program that successfully does the equivalent of 'blockdev --setra [raval] [device]'.

http://static.inky.ws/syn/315

'gcc setra.c -o setra' and off you go.

End size is still 5k vs the util-linux-ng's blockdev size of 10k.  This is certainly due to all the needless messages, but it was worth the exercise, anyway.  As crazy as this sounds to me, it is actually the first time I've written my own standalone C application on a linux platform!?  I've just never had need to before.  The seal has been broken...

Code: [Select]
/* Filename: raset.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h> // for _IO macro

#define BLKRASET _IO(0x12, 98)
#define BLKRAGET _IO(0x12, 99)
#define O_RDONLY 0
#define MAX_MSG_LEN 80

int main(int argc, char **argv)
{
    int fd, ret;
    int raVal;
    char msg[MAX_MSG_LEN];
   
    if (argc != 3) {
        printf("Usage: raset [RAval] [device]\n");
        exit(1);
    }
    raVal = atoi(argv[1]);
    fd = open(argv[2], O_RDONLY, 0);
    if (fd < 0) {
        snprintf(msg, MAX_MSG_LEN, "open('%s')", argv[1]);
        perror(msg);
        exit(1);
    }
    ret = ioctl(fd, BLKRASET, raVal);
    if (ret == -1) {
        perror("ioctl");
    }
    else {
        printf("Read-ahead for '%s' successfully set to %d\n", argv[2], raVal);
    }
    return 0;
}


Offline qopit

  • Jr. Member
  • **
  • Posts: 81
End size is still 5k vs the util-linux-ng's blockdev size of 10k.  This is certainly due to all the needless messages, but it was worth the exercise, anyway.

I wasn't quite right.  I was curious what the bare size would be... stripping out all the fluff still has the output at 4.4k when compiled with gcc:

Code: [Select]
#include <sys/ioctl.h> // for _IO macro
#define BLKRASET _IO(0x12, 98)
#define BLKRAGET _IO(0x12, 99)
#define O_RDONLY 0
#define MAX_MSG_LEN 80

int main(int argc, char **argv)
{
    int fd, ret;
    int raVal; 
   
    raVal = atoi(argv[1]);
    fd = open(argv[2], O_RDONLY, 0);
    ret = ioctl(fd, BLKRASET, raVal);
    return ret * -1;
}

Offline curaga

  • Administrator
  • Hero Member
  • *****
  • Posts: 11044
I get a 1.9kb binary with your first one, and a 1.4kb one with your second one (gcc -Os -s, sstrip).

It's quite nice for a first attempt, I must say. :)


edit: In a flash of light, I recalled you can tune that parameter in sysfs, no need for ioctls. Heh ;)

echo 2048 > /sys/block/sda/queue/read_ahead_kb

The ioctl is in blocks, that is in kb's.
« Last Edit: September 01, 2011, 01:04:42 PM by curaga »
The only barriers that can stop you are the ones you create yourself.

Offline qopit

  • Jr. Member
  • **
  • Posts: 81
I get a 1.9kb binary with your first one, and a 1.4kb one with your second one (gcc -Os -s, sstrip).

Great!  It is always good to learn the tricks.  Thanks very much!

I find this progression interesting:

Code: [Select]
tc@box:~$ gcc raset.c -o raset; wc -c raset
5105 raset
tc@box:~$ gcc -Os raset.c -o raset; wc -c raset
5025 raset
tc@box:~$ gcc -Os -s raset.c -o raset; wc -c raset
3224 raset
tc@box:~$ strip raset; wc -c raset
3224 raset
tc@box:~$ strip -s raset; wc -c raset
3224 raset
tc@box:~$ sstrip raset; wc -c raset
1960 raset

'strip -s' is supposed to remove all symbols, yet sstrip makes a huge additional difference.  Does this only happen on small files?  ie: does sstrip only remove a few kB?  Looking at what sstrip is doing (although not understanding the ELF format) this seems plausible.

I thought about trying to one-up you on filesize, then came across this and decided I'd better not :) :
http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html

Quote
It's quite nice for a first attempt, I must say.

Thanks!

Quote
edit: In a flash of light, I recalled you can tune that parameter in sysfs, no need for ioctls. Heh ;)

echo 2048 > /sys/block/sda/queue/read_ahead_kb

Excellent - this is definitely the thinnest solution.  Not that the other stuff was a waste of time by an stretch!

Offline qopit

  • Jr. Member
  • **
  • Posts: 81
This is an old thread, but fwiw and for future reference hdparm -a can also be used to set device readahead, and hdparm is part of stock busybox.

Code: [Select]
hdparm -a4096  /dev/sda
is the same as:

Code: [Select]
echo 2048 > /sys/block/sda/queue/read_ahead_kb
which is the same as (although not in the stock tiny core):

Code: [Select]
blockdev --setra 4096 /dev/sda

Where blockdev and hdparm units are in 512-byte blocks, instead of kB,