--- disk-utils/Makefile.~1~ Mon Aug 30 22:34:13 1999 +++ disk-utils/Makefile Mon Aug 30 22:32:24 1999 @@ -16,13 +16,13 @@ SBIN= mkfs mkswap -USRBIN= fdformat setfdprm +USRBIN= fdformat setfdprm raw ETC= fdprm ifneq "$(CPU)" "sparc" # fsck and mkfs will compile, but there is no kernel support on sparc -MAN8:=$(MAN8) fsck.minix.8 mkfs.8 mkfs.minix.8 +MAN8:=$(MAN8) fsck.minix.8 mkfs.8 mkfs.minix.8 raw.8 SBIN:=$(SBIN) fsck.minix mkfs.minix endif --- disk-utils/raw.8.~1~ Mon Aug 30 22:35:02 1999 +++ disk-utils/raw.8 Mon Aug 30 23:00:21 1999 @@ -0,0 +1,87 @@ +.\" -*- nroff -*- +.TH RAW 8 "Aug 1999" "Version 0.1" +.SH NAME +raw \- bind a Linux raw character device +.SH SYNOPSIS +.B raw +.I /dev/raw +.PP +.B raw +.I /dev/raw /dev/ +.PP +.B raw +.B \-q +.I /dev/raw +.PP +.B raw +.B \-qa +.SH DESCRIPTION +.B raw +is used to bind a Linux raw character device to a block device. Any +block device may be used: at the time of binding, the device driver does +not even have to be accessible (it may be loaded on demand as a kernel +module later). +.PP +.B raw +is used in two modes: it either sets raw device bindings, or it queries +existing bindings. When setting a raw device, +.I /dev/raw +is the device name of an existing raw device node in the filesystem. +The block device to which it is to be bound can be specified either in +terms of its +.I major +and +.I minor +device numbers, or as a path name +.I /dev/ +to an existing block device file. +.PP +The bindings already in existance can be queried with the +.I \-q +option, with is used either with a raw device filename to query that one +device, or with the +.I \-a +option to query all bound raw devices. +.PP +Once bound to a block device, a raw device can be opened, read and +written, just like the block device it is bound to. However, the raw +device does not behave exactly like the block device. In particular, +access to the raw device bypasses the kernel's block buffer cache +entirely: all I/O is done directly to and from the address space of the +process performing the I/O. If the underlying block device driver can +support DMA, then no data copying at all is required to complete the +I/O. +.PP +Because raw I/O involves direct hardware access to a process's memory, a +few extra restrictions must be observed. All I/Os must be correctly +aligned in memory and on disk: they must start at a sector offset on +disk, they must be an exact number of sectors long, and the data buffer +in virtual memory must also be aligned to a multiple of the sector +size. The sector size is 512 bytes for most devices. +.SH OPTIONS +.TP +.B -q +Set query mode. +.B raw +will query an existing binding instead of setting a new one. +.TP +.B -a +With +.B -q +, specifies that all bound raw devices should be queried. +.TP +.B -h +provides a usage summary. +.SH BUGS +The Linux +.B dd +(1) command does not currently align its buffers correctly, and so +cannot be used on raw devices. +.PP +Raw I/O devices do not maintain cache coherency with the Linux block +device buffer cache. If you use raw I/O to overwrite data already in +the buffer cache, the buffer cache will no longer correspond to the +contents of the actual storage device underneath. This is deliberate, +but is regarded either a bug or a feature depending on who you ask! +.SH AUTHOR +Stephen Tweedie (sct@redhat.com) --- disk-utils/raw.c.~2~ Mon Aug 30 22:34:48 1999 +++ disk-utils/raw.c Mon Aug 30 22:36:18 1999 @@ -0,0 +1,217 @@ +/* + * raw.c: User mode tool to bind and query raw character devices. + * + * Stephen Tweedie, 1999 + * + * This file may be redistributed under the terms of the GNU General + * Public License, version 2. + * + * Copyright Red Hat Software, 1999 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +char * progname; +int do_query = 0; +int do_query_all = 0; + +int master_fd; +int raw_minor; + +void open_raw_ctl(void); +int query(int minor, int quiet); +int bind (int minor, int block_major, int block_minor); + + +static void usage(int err) +{ + fprintf(stderr, + "Usage:\n" + " %s /dev/rawN \n" + " %s /dev/rawN /dev/\n" + " %s -q /dev/rawN\n" + " %s -qa\n", + progname, progname, progname, progname); + exit(err); +} + + +int main(int argc, char *argv[]) +{ + char c; + char * raw_name; + char * block_name; + int err; + int block_major, block_minor; + int i; + + struct stat statbuf; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "ahq")) != EOF) { + switch (c) { + case 'a': + do_query_all = 1; + break; + case 'h': + usage(0); + case 'q': + do_query = 1; + break; + default: + usage(1); + } + } + + /* + * Check for, and open, the master raw device, /dev/raw + */ + + open_raw_ctl(); + + if (do_query_all) { + if (optind < argc) + usage(1); + for (i=1; i<255; i++) + query(i, 1); + exit(0); + } + + /* + * It's a bind or a single query. Either way we need a raw device. + */ + + if (optind >= argc) + usage(1); + raw_name = argv[optind++]; + + err = stat(raw_name, &statbuf); + if (err) { + fprintf (stderr, "Cannot locate raw device '%s' (%s)\n", + raw_name, strerror(errno)); + exit(2); + } + + if (!S_ISCHR(statbuf.st_mode)) { + fprintf (stderr, "raw device '%s' is not a character dev\n", + raw_name); + exit(2); + } + if (major(statbuf.st_rdev) != RAW_MAJOR) { + fprintf (stderr, "Device '%s' is not a raw dev\n", + raw_name); + exit(2); + } + + raw_minor = minor(statbuf.st_rdev); + + if (do_query) + return query(raw_minor, 0); + + /* + * It's not a query, so we still have some parsing to do. Have + * we been given a block device filename or a major/minor pair? + */ + + switch (argc - optind) { + case 1: + block_name = argv[optind]; + err = stat(block_name, &statbuf); + if (err) { + fprintf (stderr, + "Cannot locate block device '%s' (%s)\n", + block_name, strerror(errno)); + exit(2); + } + + if (!S_ISBLK(statbuf.st_mode)) { + fprintf (stderr, "Device '%s' is not a block dev\n", + block_name); + exit(2); + } + + block_major = major(statbuf.st_rdev); + block_minor = minor(statbuf.st_rdev); + break; + + case 2: + block_major = strtol(argv[optind], 0, 0); + block_minor = strtol(argv[optind+1], 0, 0); + break; + + default: + usage(1); + } + + return bind(raw_minor, block_major, block_minor); + return 0; + +} + + +void open_raw_ctl(void) +{ + master_fd = open("/dev/raw", O_RDWR, 0); + if (master_fd < 0) { + fprintf (stderr, + "Cannot open master raw device '/dev/raw' (%s)\n", + strerror(errno)); + exit(2); + } +} + +int query(int minor, int quiet) +{ + struct raw_config_request rq; + int err; + + rq.raw_minor = minor; + err = ioctl(master_fd, RAW_GETBIND, &rq); + if (err < 0) { + if (quiet && errno == ENODEV) + return 3; + fprintf (stderr, + "Error querying raw device (%s)\n", + strerror(errno)); + exit(3); + } + if (quiet && !rq.block_major && !rq.block_minor) + return 0; + printf ("/dev/raw%d: bound to major %d, minor %d\n", + minor, (int) rq.block_major, (int) rq.block_minor); + return 0; +} + +int bind(int minor, int block_major, int block_minor) +{ + struct raw_config_request rq; + int err; + + rq.raw_minor = minor; + rq.block_major = block_major; + rq.block_minor = block_minor; + err = ioctl(master_fd, RAW_SETBIND, &rq); + if (err < 0) { + fprintf (stderr, + "Error setting raw device (%s)\n", + strerror(errno)); + exit(3); + } + printf ("/dev/raw%d: bound to major %d, minor %d\n", + raw_minor, (int) rq.block_major, (int) rq.block_minor); + return 0; +} +