Patch to allow gmirror to set priority of a disk
Mel Flynn
mel.flynn+fbsd.fs at mailing.thruhere.net
Wed Sep 2 22:17:15 UTC 2009
Hi,
I've created a patch that allows gmirror to set the priority of a disk. I've
needed this feature so I can signal which disk is the "master" on the next
reboot and also because insertion of a 3rd disk comes with the same priority
as the master disk.
Some background about the first issue: I've got one system that gets READ_DMA
errors and then dumps the disk out of the mirror. I believe it is NOT related
to disk errors, but rather to IDE/Motherboard bandwidth (SMART doesn't show
any errors and the READ_DMA errors are scattered amongst LBA blocks, no
WRITE_DMA errors ever, never got SATA disks to work on this mobo and last but
not least it only happens when IO is high, like daily backup with dump -C
20M).
Which disk gets thrown out, is random and the last time that happened I
rebooted since I needed a new kernel anyway and the wrong disk was consider
master. This is a side-effect of me having to do several:
gmirror forget gm0
gmirror insert gm0 adX
during an uptime sequence. As a result, both disks have the same priority.
Unfortunately, due to geographic relocation, I no longer have physical access
to the machine, so I have only compile tested this patch, but I wanted to get
some feedback about it:
- Have I made some mistakes that would trash my mirror? ;)
- Is there any desire to have this feature other then my own?
- Any style issues?
--
Mel
-------------- next part --------------
Index: sbin/geom/class/mirror/geom_mirror.c
===================================================================
--- sbin/geom/class/mirror/geom_mirror.c (revision 196761)
+++ sbin/geom/class/mirror/geom_mirror.c (working copy)
@@ -27,6 +27,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/limits.h> /* UCHAR_MAX */
#include <sys/param.h>
#include <errno.h>
#include <paths.h>
@@ -54,6 +55,7 @@
static void mirror_clear(struct gctl_req *req);
static void mirror_dump(struct gctl_req *req);
static void mirror_label(struct gctl_req *req);
+static void mirror_setprio(struct gctl_req *req);
struct g_command class_commands[] = {
{ "activate", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS, NULL,
@@ -111,6 +113,9 @@
{ "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, NULL,
"[-v] name prov ..."
},
+ { "setprio", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS, NULL,
+ "[-v] name prov priority"
+ },
{ "stop", G_FLAG_VERBOSE, NULL,
{
{ 'f', "force", NULL, G_TYPE_BOOL },
@@ -144,6 +149,8 @@
mirror_dump(req);
else if (strcmp(name, "activate") == 0)
mirror_activate(req);
+ else if (strcmp(name, "setprio") == 0)
+ mirror_setprio(req);
else
gctl_error(req, "Unknown command: %s.", name);
}
@@ -375,3 +382,64 @@
printf("Provider %s activated.\n", path);
}
}
+
+static void
+mirror_setprio(struct gctl_req *req)
+{
+ struct g_mirror_metadata md, tmpmd;
+ const char *name, *prov;
+ intmax_t prio;
+ uint8_t oldprio;
+ int error, nargs;
+
+ nargs = gctl_get_int(req, "nargs");
+ if (nargs < 3) {
+ gctl_error(req, "Too few arguments.");
+ return;
+ }
+
+ name = gctl_get_ascii(req, "arg0");
+ prov = gctl_get_ascii(req, "arg1");
+ prio = gctl_get_intmax(req, "arg2");
+ if ( prio < 0 || prio > UCHAR_MAX ) {
+ fprintf(stderr,
+ "Priority has to be between 0 and %u", UCHAR_MAX);
+ gctl_error(req, "Failed.");
+ return;
+ }
+ error = g_metadata_read(prov, (u_char *)&tmpmd, sizeof(tmpmd),
+ G_MIRROR_MAGIC);
+ if (error != 0) {
+ fprintf(stderr, "Can't read metadata from %s: %s.\n",
+ name, strerror(error));
+ gctl_error(req, "Failed.");
+ return;
+ }
+ if (mirror_metadata_decode((u_char *)&tmpmd, &md) != 0) {
+ fprintf(stderr,
+ "MD5 hash mismatch for provider %s: %s, aborting\n",
+ prov, strerror(error));
+ gctl_error(req, "Failed.");
+ return;
+ }
+ if (strcmp(md.md_name, name) != 0) {
+ fprintf(stderr,
+ "Provider %s is not the mirror %s component.\n",
+ prov, name);
+ gctl_error(req, "Failed.");
+ return;
+ }
+ oldprio = md.md_priority;
+ md.md_priority = (uint8_t)prio;
+ mirror_metadata_encode(&md, (u_char *)&tmpmd);
+ error = g_metadata_store(prov, (u_char *)&tmpmd, sizeof(tmpmd));
+ if (error != 0) {
+ fprintf(stderr, "Cannot write metadata from %s: %s.\n",
+ prov, strerror(error));
+ gctl_error(req, "Failed.");
+ return;
+ }
+ if (verbose)
+ printf("Provider %s priority %u => %u", prov, oldprio,
+ md.md_priority);
+}
More information about the freebsd-fs
mailing list