For HA clusters we attach RAID sets to two linux servers, which are
mounted
from one machine or the other. The device tells the kernel that it's
Type: Direct Access and not removable. If the kernel now mounts an
already
seen device again, it does not reread all file system information, but
uses
all buffered blocks from the cache. If the other box has modified the
data
meanwhile you got an inconsistent state.

To be able to enforce the invalidation of the caches I applied the
attached
patch (like D.  Gilbert). If you now say
        echo "scsi media-changed-device 9 1 2 3" >/proc/scsi/scsi
the file system information is reread from the device and all works
fine.

There is an other solution used from AMI to ensure consistency in
clustered configurations, but this solution also works without support
from
the device driver.

        Greetings,
-- 
J"org Lehrke                                 Tel +49 89 962284 44
Wizard Software Engineering GmbH             Fax +49 89 962284 39
Klenzestrasse 5, D-85737 Ismaning, Germany   PGP-KeyID: 682912C1
<A HREF="http://www.wizard.de/">`enabling the power of parallel
computing'/A>
--- linux/drivers/scsi/scsi.c.orig      Sat Dec  4 10:01:08 1999
+++ linux/drivers/scsi/scsi.c   Sat Dec  4 10:01:30 1999
@@ -2153,6 +2153,12 @@
 
 
 #ifdef CONFIG_PROC_FS
+typedef enum {
+    MEDIA_CHANGED_DEVICE,
+    ADD_SINGLE_DEVICE,
+    REMOVE_SINGLE_DEVICE
+} scsi_proc_cmd;
+
 int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
                    int hostno, int inout)
 {
@@ -2161,6 +2167,7 @@
     Scsi_Device *scd;
     struct Scsi_Host *HBA_ptr;
     char *p;
+    scsi_proc_cmd cmd;
     int   host, channel, id, lun;
     int          size, len = 0;
     off_t begin = 0;
@@ -2331,6 +2338,17 @@
 #endif /* CONFIG_SCSI_LOGGING */ /* } */
 
     /*
+     * Usage: echo "scsi media-changed-device 0 1 2 3" >/proc/scsi/scsi
+     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+     * Consider this feature BETA.
+     * While the device is not in use you can mark a media change
+     * and so enforce the invalidation of all buffer caches for this device.
+     */
+    if(!strncmp("media-changed-device", buffer + 5, 20)) {
+        cmd = MEDIA_CHANGED_DEVICE;
+        p = buffer + 26;
+    }
+    /*
      * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
      * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
      * Consider this feature BETA.
@@ -2341,53 +2359,10 @@
      * already connected device. It is perhaps not
      * guaranteed this device doesn't corrupt an ongoing data transfer.
      */
-    if(!strncmp("add-single-device", buffer + 5, 17)) {
+    else if(!strncmp("add-single-device", buffer + 5, 17)) {
+        cmd = ADD_SINGLE_DEVICE;
        p = buffer + 23;
-
-        host    = simple_strtoul(p, &p, 0);
-        channel = simple_strtoul(p+1, &p, 0);
-        id      = simple_strtoul(p+1, &p, 0);
-        lun     = simple_strtoul(p+1, &p, 0);
-
-       printk("scsi singledevice %d %d %d %d\n", host, channel,
-                       id, lun);
-
-        for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
-        {
-            if( HBA_ptr->host_no == host )
-            {
-                break;
-            }
-        }
-       if(!HBA_ptr)
-           return(-ENXIO);
-
-        for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
-        {
-            if((scd->channel == channel
-                && scd->id == id
-                && scd->lun == lun))
-            {
-                break;
-            }
-        }
-
-       if(scd)
-           return(-ENOSYS);  /* We do not yet support unplugging */
-
-       scan_scsis (HBA_ptr, 1, channel, id, lun);
-
-        /* FIXME (DB) This assumes that the queue_depth routines can be used
-           in this context as well, while they were all designed to be
-           called only once after the detect routine. (DB) */
-       /* ... but scan_scsis(,1,,,) needs the correct queue_length. So
-          select_queue_depths() has been moved inside scan_scsis() and
-          is only used in this context (ie scan_scsis(,1,,,) ). (dpg) */
-
-       return(length);
-
     }
-
     /*
      * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
      * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
@@ -2400,35 +2375,77 @@
      *
      */
     else if(!strncmp("remove-single-device", buffer + 5, 20)) {
+        cmd = REMOVE_SINGLE_DEVICE;
         p = buffer + 26;
+    }
+    else
+        return (-EINVAL);
 
-        host    = simple_strtoul(p, &p, 0);
-        channel = simple_strtoul(p+1, &p, 0);
-        id      = simple_strtoul(p+1, &p, 0);
-        lun     = simple_strtoul(p+1, &p, 0);
+    if( *p == '\0' )
+            return (-EINVAL);
+    host    = simple_strtoul(p, &p, 0);
+    if( *p == '\0' )
+            return (-EINVAL);
+    channel = simple_strtoul(p+1, &p, 0);
+    if( *p == '\0' )
+            return (-EINVAL);
+    id      = simple_strtoul(p+1, &p, 0);
+    if( *p == '\0' )
+            return (-EINVAL);
+    lun     = simple_strtoul(p+1, &p, 0);
 
+    printk("scsi singledevice %d %d %d %d\n", host, channel,
+           id, lun);
 
-        for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+    for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+    {
+        if( HBA_ptr->host_no == host )
         {
-            if( HBA_ptr->host_no == host )
-            {
-                break;
-            }
+            break;
         }
-       if(!HBA_ptr)
-           return(-ENODEV);
+    }
+    if(!HBA_ptr)
+        return(-ENODEV);
 
-        for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
-        {
+    for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
+    {
             if((scd->channel == channel
                 && scd->id == id
                 && scd->lun == lun))
             {
                 break;
             }
-        }
+    }
+     
+    switch (cmd) {
+    case MEDIA_CHANGED_DEVICE:
+        if(!scd)
+            return(-ENODEV);  /* there is no such device attached */
+
+        if(scd->access_count)
+            return(-EBUSY);
+
+        scd->changed = 1;
+        
+        break;
+
+    case ADD_SINGLE_DEVICE:
+       if(scd)
+           return(-ENOSYS);  /* We do not yet support unplugging */
 
-        if(scd == NULL)
+       scan_scsis (HBA_ptr, 1, channel, id, lun);
+
+        /* FIXME (DB) This assumes that the queue_depth routines can be used
+           in this context as well, while they were all designed to be
+           called only once after the detect routine. (DB) */
+       /* ... but scan_scsis(,1,,,) needs the correct queue_length. So
+          select_queue_depths() has been moved inside scan_scsis() and
+          is only used in this context (ie scan_scsis(,1,,,) ). (dpg) */
+        
+        break;
+        
+    case REMOVE_SINGLE_DEVICE:
+        if(!scd)
             return(-ENODEV);  /* there is no such device attached */
 
         if(scd->access_count)
@@ -2466,9 +2483,8 @@
         } else {
             return(-EBUSY);
         }
-        return(0);
     }
-    return(-EINVAL);
+    return(length);
 }
 #endif
 
--- linux/drivers/scsi/sd.c.orig        Sat Dec  4 10:01:08 1999
+++ linux/drivers/scsi/sd.c     Sat Dec  4 10:23:51 1999
@@ -153,8 +153,11 @@
 
     while (rscsi_disks[target].device->busy)
         barrier();
+    
+    /* Maybe the user whats us to invalidate all buffers */
+    check_disk_change(inode->i_rdev);
+
     if(rscsi_disks[target].device->removable) {
-       check_disk_change(inode->i_rdev);
 
        /*
         * If the drive is empty, just let the open fail.
@@ -1060,7 +1063,7 @@
 }
 
 static int check_scsidisk_media_change(kdev_t full_dev){
-    int retval;
+    int retval = 0;
     int target;
     struct inode inode;
     int flag = 0;
@@ -1073,7 +1076,13 @@
        return 0;
     }
 
-    if(!rscsi_disks[target].device->removable) return 0;
+    /* 
+     * We want to be able to enforce a invalidation of all
+     * buffer caches for a device even if it is a normal
+     * disk. Maybe we are using dual attached devices ;-)
+     *
+     * if(!rscsi_disks[target].device->removable) return 0;
+     */
 
     /*
      * If the device is offline, don't send any commands - just pretend as if
@@ -1097,7 +1106,8 @@
      * This also handles drives that auto spin down. eg iomega jaz 1GB
      * as this will spin up the drive.
      */
-    retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
+    if(rscsi_disks[target].device->removable)
+        retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
     
     if(retval){ /* Unable to test, unit probably not ready.  This usually
                 * means there is no disc in the drive.  Mark as changed,

Reply via email to