347 lines
9.2 KiB
Diff
347 lines
9.2 KiB
Diff
From: Peter Osterlund <petero2@telia.com>
|
|
Subject: Re: [RFC][PATCH] Control pktcdvd with an auxiliary character device
|
|
To: linux-kernel@vger.kernel.org
|
|
Cc: Christoph Hellwig <hch@infradead.org>, Arnd Bergmann <arnd@arndb.de>,
|
|
Jens Axboe <axboe@suse.de>, Andrew Morton <akpm@osdl.org>
|
|
Date: Wed Jul 14 02:17:27 2004 +0200
|
|
|
|
Peter Osterlund <petero2@telia.com> writes:
|
|
|
|
> Peter Osterlund <petero2@telia.com> writes:
|
|
>
|
|
> > Christoph Hellwig <hch@infradead.org> writes:
|
|
> >
|
|
> > > On Sun, Jul 11, 2004 at 01:20:45AM +0200, Arnd Bergmann wrote:
|
|
> > > > These are actually incorrect definitions since the ioctl argument is
|
|
> > > > not a pointer to unsigned int but instead just an int. However, that's
|
|
> > > > too late to fix without breaking the existing tools.
|
|
> > >
|
|
> > > The tools need to change anyway to get away from the broken behaviour to
|
|
> > > issue in ioctl on the actual block device to bind it..
|
|
> >
|
|
> > OK, I'll create a patch that gets rid of the ioctl interface and uses
|
|
> > an auxiliary character device instead to control device bindings.
|
|
>
|
|
> Here is a patch for 2.6.7-mm7 that does that. The driver creates a
|
|
> misc character device and bind/unbind of the block devices are
|
|
> controlled by ioctl commands on the char device.
|
|
>
|
|
> This patch needs corresponding changes in the pktsetup user space
|
|
> program. I'll post a patch for pktsetup as a separate message.
|
|
|
|
And here is a patch for udftools-1.0.0b3 that updates the pktsetup
|
|
program to make it able to use the character device for block device
|
|
setup/teardown.
|
|
|
|
---
|
|
|
|
udftools-1.0.0b3-petero/pktsetup/pktsetup.c | 245 +++++++++++++++++++++++++++-
|
|
1 files changed, 238 insertions(+), 7 deletions(-)
|
|
|
|
diff -puN pktsetup/pktsetup.c~pktsetup-char-dev pktsetup/pktsetup.c
|
|
--- udftools-1.0.0b3/pktsetup/pktsetup.c~pktsetup-char-dev 2004-07-12 19:57:51.000000000 +0200
|
|
+++ udftools-1.0.0b3-petero/pktsetup/pktsetup.c 2004-07-14 00:34:02.471317888 +0200
|
|
@@ -1,5 +1,6 @@
|
|
/*
|
|
* Copyright (c) 1999,2000 Jens Axboe <axboe@suse.de>
|
|
+ * Copyright (c) 2004 Peter Osterlund <petero2@telia.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
@@ -19,6 +20,7 @@
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
+#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <bits/types.h>
|
|
@@ -33,8 +35,33 @@
|
|
#define PACKET_SETUP_DEV _IOW('X', 1, unsigned int)
|
|
#define PACKET_TEARDOWN_DEV _IOW('X', 2, unsigned int)
|
|
#endif
|
|
+#ifndef PACKET_CTRL_CMD
|
|
+#define PACKET_CTRL_CMD _IOWR('X', 1, struct pkt_ctrl_command)
|
|
+#endif
|
|
+
|
|
+#define MAJOR(dev) ((dev & 0xfff00) >> 8)
|
|
+#define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
|
|
+#define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
|
|
+
|
|
+#define MISC_MAJOR 10
|
|
+#define CTL_DIR "/dev/pktcdvd"
|
|
+#define CTL_DEV "control"
|
|
+
|
|
+#define PKT_CTRL_CMD_SETUP 0
|
|
+#define PKT_CTRL_CMD_TEARDOWN 1
|
|
+#define PKT_CTRL_CMD_STATUS 2
|
|
+
|
|
+struct pkt_ctrl_command {
|
|
+ __u32 command; /* in: Setup, teardown, status */
|
|
+ __u32 dev_index; /* in/out: Device index */
|
|
+ __u32 dev; /* in/out: Device nr for cdrw device */
|
|
+ __u32 pkt_dev; /* out: Device nr for packet device */
|
|
+ __u32 num_devices; /* out: Largest device index + 1 */
|
|
+ __u32 padding;
|
|
+};
|
|
+
|
|
|
|
-int init_cdrom(int fd)
|
|
+static int init_cdrom(int fd)
|
|
{
|
|
if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) < 0) {
|
|
perror("drive not ready\n");
|
|
@@ -54,7 +81,7 @@ int init_cdrom(int fd)
|
|
return 0;
|
|
}
|
|
|
|
-void setup_dev(char *pkt_device, char *device, int rem)
|
|
+static void setup_dev(char *pkt_device, char *device, int rem)
|
|
{
|
|
int pkt_fd, dev_fd, cmd;
|
|
|
|
@@ -88,29 +115,233 @@ void setup_dev(char *pkt_device, char *d
|
|
close(pkt_fd);
|
|
}
|
|
|
|
-int usage(void)
|
|
+static int usage(void)
|
|
{
|
|
- printf("pktsetup /dev/pktcdvd0 /dev/cdrom\tsetup device\n");
|
|
- printf("pktsetup -d /dev/pktcdvd0\t\ttear down device\n");
|
|
+ printf("For pktcdvd < 0.2.0:\n");
|
|
+ printf(" pktsetup /dev/pktcdvd0 /dev/cdrom setup device\n");
|
|
+ printf(" pktsetup -d /dev/pktcdvd0 tear down device\n");
|
|
+ printf("For pktcdvd >= 0.2.0:\n");
|
|
+ printf(" pktsetup dev_name /dev/cdrom setup device\n");
|
|
+ printf(" pktsetup -d dev_name tear down device\n");
|
|
+ printf(" pktsetup -d major:minor tear down device\n");
|
|
+ printf(" pktsetup -s show device mappings\n");
|
|
return 1;
|
|
}
|
|
|
|
+/*
|
|
+ * Find the minor device number for the pktcdvd control device.
|
|
+ */
|
|
+static int get_misc_minor(void)
|
|
+{
|
|
+ int minor;
|
|
+ char name[64];
|
|
+ FILE *f;
|
|
+
|
|
+ if ((f = fopen("/proc/misc", "r")) == NULL)
|
|
+ return -1;
|
|
+ while (fscanf(f, " %d %64s", &minor, name) == 2) {
|
|
+ if (strcmp(name, "pktcdvd") == 0) {
|
|
+ fclose(f);
|
|
+ return minor;
|
|
+ }
|
|
+ }
|
|
+ fclose(f);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static const char *pkt_dev_name(const char *dev)
|
|
+{
|
|
+ static char buf[128];
|
|
+ snprintf(buf, sizeof(buf), "%s/%s", CTL_DIR, dev);
|
|
+ return buf;
|
|
+}
|
|
+
|
|
+static void create_ctl_dev(void)
|
|
+{
|
|
+ int misc_minor;
|
|
+ struct stat stat_buf;
|
|
+ int dev;
|
|
+
|
|
+ if ((misc_minor = get_misc_minor()) < 0) {
|
|
+ system("/sbin/modprobe pktcdvd");
|
|
+ misc_minor = get_misc_minor();
|
|
+ }
|
|
+ if (misc_minor < 0) {
|
|
+ fprintf(stderr, "Can't find pktcdvd character device\n");
|
|
+ return;
|
|
+ }
|
|
+ dev = MKDEV(MISC_MAJOR, misc_minor);
|
|
+
|
|
+ if ((stat(pkt_dev_name(CTL_DEV), &stat_buf) >= 0) &&
|
|
+ S_ISCHR(stat_buf.st_mode) && (stat_buf.st_rdev == dev))
|
|
+ return; /* Already set up */
|
|
+
|
|
+ mkdir(CTL_DIR, 0755);
|
|
+ unlink(pkt_dev_name(CTL_DEV));
|
|
+ mknod(pkt_dev_name(CTL_DEV), S_IFCHR | 0644, dev);
|
|
+}
|
|
+
|
|
+static int remove_stale_dev_node(int ctl_fd, char *devname)
|
|
+{
|
|
+ struct stat stat_buf;
|
|
+ int i, dev;
|
|
+ struct pkt_ctrl_command c;
|
|
+
|
|
+ if (stat(pkt_dev_name(devname), &stat_buf) < 0)
|
|
+ return 0;
|
|
+ if (!S_ISBLK(stat_buf.st_mode))
|
|
+ return 1;
|
|
+ dev = stat_buf.st_rdev;
|
|
+ memset(&c, 0, sizeof(struct pkt_ctrl_command));
|
|
+ for (i = 0; ; i++) {
|
|
+ c.command = PKT_CTRL_CMD_STATUS;
|
|
+ c.dev_index = i;
|
|
+ if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
|
|
+ perror("ioctl");
|
|
+ return 1;
|
|
+ }
|
|
+ if (i >= c.num_devices)
|
|
+ break;
|
|
+ if (c.pkt_dev == dev)
|
|
+ return 1; /* busy */
|
|
+ }
|
|
+ unlink(pkt_dev_name(devname));
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void setup_dev_chardev(char *pkt_device, char *device, int rem)
|
|
+{
|
|
+ struct pkt_ctrl_command c;
|
|
+ struct stat stat_buf;
|
|
+ int ctl_fd, dev_fd;
|
|
+
|
|
+ memset(&c, 0, sizeof(struct pkt_ctrl_command));
|
|
+
|
|
+ create_ctl_dev();
|
|
+ if ((ctl_fd = open(pkt_dev_name(CTL_DEV), O_RDONLY)) < 0) {
|
|
+ perror("ctl open");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!rem) {
|
|
+ if ((dev_fd = open(device, O_RDONLY | O_NONBLOCK)) == -1) {
|
|
+ perror("open cd-rom");
|
|
+ goto out_close;
|
|
+ }
|
|
+ if (init_cdrom(dev_fd)) {
|
|
+ close(dev_fd);
|
|
+ goto out_close;
|
|
+ }
|
|
+ close(dev_fd);
|
|
+
|
|
+ if (stat(device, &stat_buf) < 0) {
|
|
+ perror("stat cd-rom");
|
|
+ goto out_close;
|
|
+ }
|
|
+ if (!S_ISBLK(stat_buf.st_mode)) {
|
|
+ fprintf(stderr, "Not a block device\n");
|
|
+ goto out_close;
|
|
+ }
|
|
+ c.command = PKT_CTRL_CMD_SETUP;
|
|
+ c.dev = stat_buf.st_rdev;
|
|
+
|
|
+ if (remove_stale_dev_node(ctl_fd, pkt_device) != 0) {
|
|
+ fprintf(stderr, "Device node '%s' already in use\n", pkt_device);
|
|
+ goto out_close;
|
|
+ }
|
|
+ if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
|
|
+ perror("ioctl");
|
|
+ goto out_close;
|
|
+ }
|
|
+ mknod(pkt_dev_name(pkt_device), S_IFBLK | 0640, c.pkt_dev);
|
|
+ } else {
|
|
+ int major, minor, remove_node;
|
|
+
|
|
+ if ((stat(pkt_dev_name(pkt_device), &stat_buf) >= 0) &&
|
|
+ S_ISBLK(stat_buf.st_mode)) {
|
|
+ major = MAJOR(stat_buf.st_rdev);
|
|
+ minor = MINOR(stat_buf.st_rdev);
|
|
+ remove_node = 1;
|
|
+ } else if (sscanf(pkt_device, "%d:%d", &major, &minor) == 2) {
|
|
+ remove_node = 0;
|
|
+ } else {
|
|
+ fprintf(stderr, "Can't find major/minor numbers\n");
|
|
+ goto out_close;
|
|
+ }
|
|
+
|
|
+ c.command = PKT_CTRL_CMD_TEARDOWN;
|
|
+ c.pkt_dev = MKDEV(major, minor);
|
|
+ if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
|
|
+ perror("ioctl");
|
|
+ goto out_close;
|
|
+ }
|
|
+ if (remove_node)
|
|
+ unlink(pkt_dev_name(pkt_device));
|
|
+ }
|
|
+
|
|
+out_close:
|
|
+ close(ctl_fd);
|
|
+}
|
|
+
|
|
+static void show_mappings(void)
|
|
+{
|
|
+ struct pkt_ctrl_command c;
|
|
+ int ctl_fd, i;
|
|
+
|
|
+ memset(&c, 0, sizeof(struct pkt_ctrl_command));
|
|
+
|
|
+ create_ctl_dev();
|
|
+ if ((ctl_fd = open(pkt_dev_name(CTL_DEV), O_RDONLY)) < 0) {
|
|
+ perror("ctl open");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; ; i++) {
|
|
+ c.command = PKT_CTRL_CMD_STATUS;
|
|
+ c.dev_index = i;
|
|
+ if (ioctl(ctl_fd, PACKET_CTRL_CMD, &c) < 0) {
|
|
+ perror("ioctl");
|
|
+ goto out_close;
|
|
+ }
|
|
+ if (i >= c.num_devices)
|
|
+ break;
|
|
+ if (c.dev) {
|
|
+ printf("%2d : %d:%d -> %d:%d\n",
|
|
+ i, MAJOR(c.pkt_dev), MINOR(c.pkt_dev),
|
|
+ MAJOR(c.dev), MINOR(c.dev));
|
|
+ }
|
|
+ }
|
|
+
|
|
+out_close:
|
|
+ close(ctl_fd);
|
|
+}
|
|
+
|
|
int main(int argc, char **argv)
|
|
{
|
|
int rem = 0, c;
|
|
+ char *pkt_device;
|
|
+ char *device;
|
|
|
|
if (argc == 1)
|
|
return usage();
|
|
|
|
- while ((c = getopt(argc, argv, "d")) != EOF) {
|
|
+ while ((c = getopt(argc, argv, "ds?")) != EOF) {
|
|
switch (c) {
|
|
case 'd':
|
|
rem = 1;
|
|
break;
|
|
+ case 's':
|
|
+ show_mappings();
|
|
+ return 0;
|
|
default:
|
|
return usage();
|
|
}
|
|
}
|
|
- setup_dev(argv[optind], argv[optind + 1], rem);
|
|
+ pkt_device = argv[optind];
|
|
+ device = argv[optind + 1];
|
|
+ if (strchr(pkt_device, '/'))
|
|
+ setup_dev(pkt_device, device, rem);
|
|
+ else
|
|
+ setup_dev_chardev(pkt_device, device, rem);
|
|
return 0;
|
|
}
|
|
_
|
|
|
|
--
|
|
Peter Osterlund - petero2@telia.com
|
|
http://w1.894.telia.com/~u89404340
|