Hi,

I think softraid is leaking vnodes.  When taking a device offline with
bioctl -O /dev/sd0a sd2, then wiping the disk with dd (including the
disklabel), I cannot change sd0's disklabel as it would say "open part-
ition would change/shrink".  This is because on assembly (and rebuild)
the device is VOP_OPEN()d, but never closed.

With this diff, whenever a disk goes offline (I/O error or bioctl -O),
we actively close the vnode.  One thing I wonder is, this still works
when the backing device has already detached (USB drive being pulled).

Opinions?

Patrick

diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index dcc4db16864..e43594e48b6 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -4354,6 +4354,18 @@ die:
        sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state;
        sd->sd_set_vol_state(sd);
 
+       if (new_state == BIOC_SDOFFLINE) {
+               sd->sd_vol.sv_chunks[c]->src_dev_mm = NODEV;
+               if (sd->sd_vol.sv_chunks[c]->src_vn) {
+                       vn_lock(sd->sd_vol.sv_chunks[c]->src_vn,
+                           LK_EXCLUSIVE | LK_RETRY, curproc);
+                       VOP_CLOSE(sd->sd_vol.sv_chunks[c]->src_vn,
+                           FREAD | FWRITE, NOCRED, curproc);
+                       vput(sd->sd_vol.sv_chunks[c]->src_vn);
+                       sd->sd_vol.sv_chunks[c]->src_vn = NULL;
+               }
+       }
+
        sd->sd_must_flush = 1;
        task_add(systq, &sd->sd_meta_save_task);
 done:
diff --git a/sys/dev/softraid_raid1.c b/sys/dev/softraid_raid1.c
index 055b8868dfa..5106054129c 100644
--- a/sys/dev/softraid_raid1.c
+++ b/sys/dev/softraid_raid1.c
@@ -28,6 +28,8 @@
 #include <sys/rwlock.h>
 #include <sys/queue.h>
 #include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/sensors.h>
 #include <sys/stat.h>
@@ -184,6 +186,18 @@ die:
        sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state;
        sd->sd_set_vol_state(sd);
 
+       if (new_state == BIOC_SDOFFLINE) {
+               sd->sd_vol.sv_chunks[c]->src_dev_mm = NODEV;
+               if (sd->sd_vol.sv_chunks[c]->src_vn) {
+                       vn_lock(sd->sd_vol.sv_chunks[c]->src_vn,
+                           LK_EXCLUSIVE | LK_RETRY, curproc);
+                       VOP_CLOSE(sd->sd_vol.sv_chunks[c]->src_vn,
+                           FREAD | FWRITE, NOCRED, curproc);
+                       vput(sd->sd_vol.sv_chunks[c]->src_vn);
+                       sd->sd_vol.sv_chunks[c]->src_vn = NULL;
+               }
+       }
+
        sd->sd_must_flush = 1;
        task_add(systq, &sd->sd_meta_save_task);
 done:
diff --git a/sys/dev/softraid_raid5.c b/sys/dev/softraid_raid5.c
index a3425842808..d2c36fe577d 100644
--- a/sys/dev/softraid_raid5.c
+++ b/sys/dev/softraid_raid5.c
@@ -30,6 +30,8 @@
 #include <sys/rwlock.h>
 #include <sys/queue.h>
 #include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/sensors.h>
 #include <sys/stat.h>
@@ -212,6 +214,18 @@ die:
        sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state;
        sd->sd_set_vol_state(sd);
 
+       if (new_state == BIOC_SDOFFLINE) {
+               sd->sd_vol.sv_chunks[c]->src_dev_mm = NODEV;
+               if (sd->sd_vol.sv_chunks[c]->src_vn) {
+                       vn_lock(sd->sd_vol.sv_chunks[c]->src_vn,
+                           LK_EXCLUSIVE | LK_RETRY, curproc);
+                       VOP_CLOSE(sd->sd_vol.sv_chunks[c]->src_vn,
+                           FREAD | FWRITE, NOCRED, curproc);
+                       vput(sd->sd_vol.sv_chunks[c]->src_vn);
+                       sd->sd_vol.sv_chunks[c]->src_vn = NULL;
+               }
+       }
+
        sd->sd_must_flush = 1;
        task_add(systq, &sd->sd_meta_save_task);
 done:
diff --git a/sys/dev/softraid_raid6.c b/sys/dev/softraid_raid6.c
index 14eb9f98369..aee93eae6f5 100644
--- a/sys/dev/softraid_raid6.c
+++ b/sys/dev/softraid_raid6.c
@@ -29,6 +29,8 @@
 #include <sys/rwlock.h>
 #include <sys/queue.h>
 #include <sys/fcntl.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/sensors.h>
 #include <sys/stat.h>
@@ -230,6 +232,18 @@ die:
        sd->sd_vol.sv_chunks[c]->src_meta.scm_status = new_state;
        sd->sd_set_vol_state(sd);
 
+       if (new_state == BIOC_SDOFFLINE) {
+               sd->sd_vol.sv_chunks[c]->src_dev_mm = NODEV;
+               if (sd->sd_vol.sv_chunks[c]->src_vn) {
+                       vn_lock(sd->sd_vol.sv_chunks[c]->src_vn,
+                           LK_EXCLUSIVE | LK_RETRY, curproc);
+                       VOP_CLOSE(sd->sd_vol.sv_chunks[c]->src_vn,
+                           FREAD | FWRITE, NOCRED, curproc);
+                       vput(sd->sd_vol.sv_chunks[c]->src_vn);
+                       sd->sd_vol.sv_chunks[c]->src_vn = NULL;
+               }
+       }
+
        sd->sd_must_flush = 1;
        task_add(systq, &sd->sd_meta_save_task);
 done:

Reply via email to