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: