The md ioctls expect their extra arguments to be unsigned longs
(explicitly converted to kdev_t), while raidtools-0.50beta2 provides
ints and dev_ts. As these arguments are covered by an ellipsis in the
C prototype, no conversion is done by the compiler. Usually it works
out O.K. on little-endian machines. Sun Sparcs are big-endian.
Trying to add /dev/sdc1 to /dev/md0 fails with the following syslog
message:
md_add(): zero device size, huh, bailing out.
The strace log ended with:
...
stat("/dev/sdc1", {st_mode=S_IFBLK|0660, st_rdev=makedev(8, 33), ...}) = 0
ioctl(5, REGISTER_DEV, 0) = -1 EINVAL (Invalid argument)
write(2, "/dev/sdc1: Invalid argument\n", 28) = 28
exit(0) = ?
The relevant source fragment in raidadd.c is:
if (stat (dev, &s))
{
...
}
...
if (ioctl (fd, REGISTER_DEV, s.st_rdev)) {
...
perror (dev);
...
}
The device /dev/sdc1 is stat()ed for its device number (8/33), which
is sent as the ioctl()'s third argument (type dev_t). In the kernel
(`drivers/block/md.c', md_ioctl()) the extra argument is read as were
it a long, silently padded with (hopefully) zero bytes. With big-end
numbers, this shifts the original short toward the long's MSBs. The
subequent conversion to a kdev_t is done by examining the long's LSBs,
where the zeros happen to be. So the kernel believes that I am trying
to add the 0/0 device to /dev/md0, and rightly rejects my request.
Also, gcc had gripes about redefining __NR__llseek, an really bad
thing to do, espesially as <asm/unistd.h> defines it to 236, not 140.
After adding the patch below, raidtools compiled and ran with no
trouble.
I am running Linux 2.2.0-pre8smp, by the way.
/Sverker
======================
diff -u orig/raidtools-0.50/raid_io.c raidtools-0.50/raid_io.c
--- orig/raidtools-0.50/raid_io.c Thu Jul 23 23:32:25 1998
+++ raidtools-0.50/raid_io.c Wed Jan 27 00:07:26 1999
@@ -78,7 +78,13 @@
}
#undef F
+#if !defined(__NR__llseek)
+/*
+ * Architecture-specific syscall number. Use the one in
+ * <asm/unistd.h> instead.
+ */
#define __NR__llseek 140
+#endif
static int _llseek (unsigned int, unsigned long,
unsigned long, long long *, unsigned int);
@@ -284,7 +290,7 @@
fprintf(stderr, "couldn't open device %s -- %s\n", cfg->
device_name[i], strerror(errno));
return 1;
}
- if (ioctl(fd, BLKGETSIZE, &nr_blocks) == -1) {
+ if (ioctl(fd, BLKGETSIZE, (unsigned long)&nr_blocks) == -1) {
fprintf(stderr, "couldn't get device size for %s -- %s\n
", cfg->device_name[i], strerror(errno));
close(fd);
return 1;
diff -u orig/raidtools-0.50/raidadd.c raidtools-0.50/raidadd.c
--- orig/raidtools-0.50/raidadd.c Thu Jul 23 23:32:26 1998
+++ raidtools-0.50/raidadd.c Wed Jan 27 05:30:57 1999
@@ -89,7 +89,7 @@
save_errno=EPERM; /* used in case of valid return */
}
- if (ioctl (fd, REGISTER_DEV, s.st_rdev)) {
+ if (ioctl (fd, REGISTER_DEV, (unsigned long)s.st_rdev)) {
save_errno = errno;
perror (dev);
errno=save_errno;
@@ -101,7 +101,7 @@
static int do_mdstart (int fd, char *dev, int pers)
{
- if (ioctl (fd, START_MD, pers)) {
+ if (ioctl (fd, START_MD, (unsigned long)pers)) {
save_errno=errno;
perror (dev);
errno=save_errno;
@@ -112,7 +112,7 @@
static int do_mdstop (int fd, char *dev)
{
- if (ioctl (fd, STOP_MD, 0)) {
+ if (ioctl (fd, STOP_MD, 0UL)) {
save_errno=errno;
perror (dev);
errno=save_errno;