HAMMER - Fix panic when removing volume
authorMichael Neumann <mneumann@ntecs.de>
Sat, 12 Dec 2009 13:02:03 +0000 (14:02 +0100)
committerMichael Neumann <mneumann@ntecs.de>
Sat, 12 Dec 2009 13:02:03 +0000 (14:02 +0100)
* unload buffers before unloading volume

* fix missing call to hammer_rel_volume() which lead to
  kernel panic upon umount

sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_ondisk.c
sys/vfs/hammer/hammer_volume.c

index 1192b84..16ab273 100644 (file)
@@ -911,7 +911,7 @@ void        hammer_inode_waithard(hammer_mount_t hmp);
 int    hammer_unload_volume(hammer_volume_t volume, void *data __unused);
 int    hammer_adjust_volume_mode(hammer_volume_t volume, void *data __unused);
 
-int    hammer_unload_buffer(hammer_buffer_t buffer, void *data __unused);
+int    hammer_unload_buffer(hammer_buffer_t buffer, void *data);
 int    hammer_install_volume(hammer_mount_t hmp, const char *volname,
                        struct vnode *devvp);
 int    hammer_mountcheck_volumes(hammer_mount_t hmp);
index 0888a21..2a6a2c2 100644 (file)
@@ -815,11 +815,25 @@ hammer_load_buffer(hammer_buffer_t buffer, int isnew)
 
 /*
  * NOTE: Called from RB_SCAN, must return >= 0 for scan to continue.
- * This routine is only called during unmount.
+ * This routine is only called during unmount or when a volume is
+ * removed.
+ *
+ * If data != NULL, it specifies a volume whoose buffers should
+ * be unloaded.
  */
 int
-hammer_unload_buffer(hammer_buffer_t buffer, void *data __unused)
+hammer_unload_buffer(hammer_buffer_t buffer, void *data)
 {
+       struct hammer_volume *volume = (struct hammer_volume *) data;
+
+       if (volume != NULL && volume != buffer->io.volume) {
+               /*
+                * We are only interested in unloading buffers of volume,
+                * so skip it
+                */
+               return 0;
+       }
+
        /*
         * Clean up the persistent ref ioerror might have on the buffer
         * and acquire a ref (steal ioerror's if we can).
index 1b45f7a..8f9251a 100644 (file)
@@ -219,6 +219,7 @@ hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip,
                if (strcmp(volume->vol_name, ioc->device_name) == 0) {
                        break;
                }
+               hammer_rel_volume(volume, 0);
                volume = NULL;
        }
 
@@ -275,17 +276,24 @@ hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip,
        }
 
        hmp->volume_to_remove = -1;
-       hammer_rel_volume(volume, 1);
 
-       /* XXX: unload volume! */
-       /*error = hammer_unload_volume(volume, NULL);
+       hammer_rel_volume(volume, 0);
+
+       /*
+        * Unload buffers
+        */
+        RB_SCAN(hammer_buf_rb_tree, &hmp->rb_bufs_root, NULL,
+               hammer_unload_buffer, volume);
+
+       error = hammer_unload_volume(volume, NULL);
        if (error == -1) {
                kprintf("Failed to unload volume\n");
                hammer_unlock(&hmp->blkmap_lock);
                hammer_sync_unlock(trans);
                return (error);
-       }*/
+       }
 
+       volume = NULL;
        --hmp->nvolumes;
 
        /*
@@ -300,6 +308,7 @@ hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip,
                        error = 0;
                        continue;
                }
+
                KKASSERT(volume != NULL && error == 0);
                hammer_modify_volume_field(trans, volume, vol_count);
                volume->ondisk->vol_count = hmp->nvolumes;