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;

Reply via email to