2001-11-17 15:45:06

by Roy S.C. Ho

[permalink] [raw]
Subject: Raw access to block devices

Dear all,

I would like to write a driver for a block device that
is better to be accessed directly without going
through the buffer cache. I read the source code raw.c
and learnt that linux does have raw I/O support.
However, it seems to me that the support only provides
a character device interface to users. Is there a
simple way to maintain the block device interface to
user programs / other parts of the kernel, while
bypassing the buffer cache system?

Since struct block_device_operations does not include
read or write operations, I have considered to
redirect the function pointers in filp->f_op to my own
routines when the device is opened. Is this an
appropriate solution?

Thank you very much. And please kindly correct me if I
am wrong.

Regards,
Roy Ho

__________________________________________________
Do You Yahoo!?
Find the one for you at Yahoo! Personals
http://personals.yahoo.com


2001-11-17 16:16:01

by Peter T. Breuer

[permalink] [raw]
Subject: Re: Raw access to block devices

"A month of sundays ago Roy S.C. Ho wrote:"
> I would like to write a driver for a block device that
> is better to be accessed directly without going
> through the buffer cache. I read the source code raw.c
> and learnt that linux does have raw I/O support.
> However, it seems to me that the support only provides
> a character device interface to users. Is there a

I think that's the control device. You can work out how to use it
by looking at the ioctls in raw.c. But, yes, sure, if you get some
"official" news on how to work it, let me know too and I'll use the
info like a shot!

> simple way to maintain the block device interface to
> user programs / other parts of the kernel, while
> bypassing the buffer cache system?

Peter

2001-11-18 08:15:54

by Roy S.C. Ho

[permalink] [raw]
Subject: Re: Raw access to block devices

Hi Peter, thanks for your help. I found that the
control device is only for GETBIND or SETBIND. It
seems that the binded devices still have to be char
devices. Is there a way to change this?
Your help is much appreciated. Thanks.

--- "Peter T. Breuer" <[email protected]> wrote:
> "A month of sundays ago Roy S.C. Ho wrote:"
> > I would like to write a driver for a block device
> that
> > is better to be accessed directly without going
> > through the buffer cache. I read the source code
> raw.c
> > and learnt that linux does have raw I/O support.
> > However, it seems to me that the support only
> provides
> > a character device interface to users. Is there a
>
> I think that's the control device. You can work out
> how to use it
> by looking at the ioctls in raw.c. But, yes, sure,
> if you get some
> "official" news on how to work it, let me know too
> and I'll use the
> info like a shot!
>
> > simple way to maintain the block device interface
> to
> > user programs / other parts of the kernel, while
> > bypassing the buffer cache system?
>
> Peter
> -


__________________________________________________
Do You Yahoo!?
Find the one for you at Yahoo! Personals
http://personals.yahoo.com

2001-11-18 08:40:06

by Peter T. Breuer

[permalink] [raw]
Subject: Re: Raw access to block devices

"A month of sundays ago Roy S.C. Ho wrote:"
> Hi Peter, thanks for your help. I found that the
> control device is only for GETBIND or SETBIND. It
> seems that the binded devices still have to be char
> devices. Is there a way to change this?
> Your help is much appreciated. Thanks.

I'm afraid I only ever read the code, then wrote a simple user space
tool to exercise the ioctls, but never got enough time to try it! But
my impression was that it aimed at controlling the vm system's
reactions to block-device memory buffers.

Here's the test code (rawsetup.c), entirely untested. Copyright me,
of course.


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include <linux/major.h>
#include <linux/raw.h>



char *raw_device;
char *blk_device;
int mode;
int fdctl;

static
int cmdline(int argc, char **argv) {
if (argc < 3)
return -EINVAL;

switch (argc) {
case 3:
mode = RAW_SET_BIND;
raw_device = argv[1];
blk_device = argv[2];
return 0;
case 2:
mode = RAW_GET_BIND;
raw_device = argv[1];
return 0;
}
return -EINVAL;
}

static
void usage(void) {
fprintf(stderr,"usage: rawsetup <raw_device> <blk_device>\n");
fprintf(stderr," : rawsetup <raw_device>\n");
}

int setup() {

int err;
struct stat statbuf;

fdctl = open("/dev/raw",O_RDWR);
if (fdctl < 0) {
perror("rawsetup error on open of /dev/raw");
return fdctl;
}
err = fstat(fdctl, &statbuf);
if (err < 0) {
perror("rawsetup error on stat of /dev/raw");
return err;
}
if (!S_ISCHAR(statbuf.st_rdev)) {
fprintf(stderr,"/dev/raw is not a character device\n");
return -ENODEV;
}
if (MAJOR(statbuf.st_rdev) != RAW_MAJOR) {
fprintf(stderr,"/dev/raw is not a RAW minor character device\n");
return -ENODEV;
}
if (MINOR(statbuf.st_rdev) != 0) {
fprintf(stderr,"/dev/raw is not the RAW control device\n");
return -ENODEV;
}
return 0;
}

int get() {
struct raw_config_request rq;
/* int raw_minor;
__u64 block_major;
__u64 block_minor;
*/
int err;
struct stat statbuf;

err = stat(raw_device, &statbuf);
if (err < 0) {
perror("rawsetup error on stat of raw device");
return err;
}
if (!S_ISCHAR(statbuf.st_rdev)) {
fprintf(stderr,"%s is not a character device\n", raw_device);
return -ENODEV;
}
if (MAJOR(statbuf.st_rdev) != RAW_MAJOR) {
fprintf(stderr,"%s is not a RAW device\n", raw_device);
return -ENODEV;
}
rq.raw_minor = MINOR(statbuf.st_rdev);
if (rq.raw_minor <= 0) {
fprintf(stderr,"%s is not a RAW minor device\n", raw_device);
return -ENODEV;
}

err = ioctl(fdctl,RAW_GETBIND,&rq) ;
if (err < 0) {
perror("rawsetup error on GETBIND ioctl to /dev/raw");
return err;
}
printf("raw device %s is bound to block device %h:%h\n",
rq.raw_major, rq.raw_minor);
return 0;
}

int bind() {

struct raw_config_request rq;
/* int raw_minor;
__u64 block_major;
__u64 block_minor;
*/
int err;
struct stat statbuf;

err = stat(raw_device, &statbuf);
if (err < 0) {
perror("rawsetup error on stat of raw device");
return err;
}
if (!S_ISCHAR(statbuf.st_rdev)) {
fprintf(stderr,"%s is not a character device\n", raw_device);
return -ENODEV;
}
if (MAJOR(statbuf.st_rdev) != RAW_MAJOR) {
fprintf(stderr,"%s is not a RAW device\n", raw_device);
return -ENODEV;
}
rq.raw_minor = MINOR(statbuf.st_rdev);
if (rq.raw_minor <= 0) {
fprintf(stderr,"%s is not a RAW minor device\n", raw_device);
return -ENODEV;
}

err = stat(blk_device, &statbuf);
if (err < 0) {
perror("rawsetup error on stat of block device");
return err;
}
if (!S_ISBLK(statbuf.st_rdev)) {
fprintf(stderr,"%s is not a block device\n");
return -ENODEV;
}
rq.block_major = MAJOR(statbuf.st_rdev);
rq.block_minor = MINOR(statbuf.st_rdev);

err = ioctl(fdctl,RAW_SETBIND,&rq) ;
if (err < 0) {
perror("rawsetup error on SETBIND ioctl to /dev/raw");
return err;
}
return 0;
}

int main(int argc, char **argv) {

if (cmdline(argc,argv) < 0) {
usage();
return 1;
}
if (setup() < 0) {
return 2;
}
switch(mode) {
case RAW_SET_BIND: return bind();
case RAW_GET_BIND: return get();
default: usage(); return 3;
}
return 0;
}

// (C) Peter T, Breuer 2001, [email protected]