summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root@xa-s05.(none)>2005-08-24 08:21:42 +0200
committerroot <root@xa-s05.(none)>2005-08-24 08:21:42 +0200
commit6744ef227ac7be3498999527c2d2c61692911fbf (patch)
treecdb8606d4534186449ff12b49dfed577f3d90640
parenta9912e04bd4add6c1042ab361259c0f64cc32594 (diff)
downloadmultipath-tools-6744ef227ac7be3498999527c2d2c61692911fbf.tar.gz
multipath-tools-6744ef227ac7be3498999527c2d2c61692911fbf.tar.bz2
multipath-tools-6744ef227ac7be3498999527c2d2c61692911fbf.zip
[libcheckers] add the directio checker
Created by Hannes Reinecke, Suse, mainly for DASD devices.
-rw-r--r--libcheckers/Makefile2
-rw-r--r--libcheckers/checkers.h2
-rw-r--r--libcheckers/directio.c165
-rw-r--r--libcheckers/selector.c8
4 files changed, 176 insertions, 1 deletions
diff --git a/libcheckers/Makefile b/libcheckers/Makefile
index c737da1..b3e7231 100644
--- a/libcheckers/Makefile
+++ b/libcheckers/Makefile
@@ -6,7 +6,7 @@ BUILD = glibc
include ../Makefile.inc
-OBJS = readsector0.o tur.o selector.o emc_clariion.o hp_sw.o
+OBJS = readsector0.o tur.o selector.o directio.o emc_clariion.o hp_sw.o
all: $(BUILD)
diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h
index 363147f..92ecfe5 100644
--- a/libcheckers/checkers.h
+++ b/libcheckers/checkers.h
@@ -9,6 +9,7 @@ enum checkers {
CHECKER_UNDEF,
TUR,
READSECTOR0,
+ DIRECTIO,
EMC_CLARIION,
HP_SW
};
@@ -21,6 +22,7 @@ void *get_checker_addr (int);
int get_checker_name (char *, int);
int emc_clariion (int fd, char * msg, void ** ctxt);
+int directio (int fd, char * msg, void ** ctxt);
int readsector0 (int fd, char * msg, void ** ctxt);
int tur (int fd, char * msg, void ** ctxt);
int hp_sw (int fd, char * msg, void ** ctxt);
diff --git a/libcheckers/directio.c b/libcheckers/directio.c
new file mode 100644
index 0000000..6f52494
--- /dev/null
+++ b/libcheckers/directio.c
@@ -0,0 +1,165 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <errno.h>
+
+#include "path_state.h"
+#include "checkers.h"
+
+#define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
+#define MSG_DIRECTIO_UP "directio checker reports path is up"
+#define MSG_DIRECTIO_DOWN "directio checker reports path is down"
+
+struct readsector0_checker_context {
+ void * dummy;
+};
+
+static int
+direct_read (int fd, unsigned char * buff, int size)
+{
+ long flags;
+ int reset_flags = 0;
+ int res, retval;
+
+ flags = fcntl(fd,F_GETFL);
+
+ if (flags < 0) {
+ return PATH_UNCHECKED;
+ }
+
+ if (!(flags & O_DIRECT)) {
+ flags |= O_DIRECT;
+ if (fcntl(fd,F_SETFL,flags) < 0) {
+ return PATH_UNCHECKED;
+ }
+ reset_flags = 1;
+ }
+
+ while ( (res = read(fd,buff,size)) < 0 && errno == EINTR );
+ if (res < 0) {
+ if (errno == EINVAL) {
+ /* O_DIRECT is not available */
+ retval = PATH_UNCHECKED;
+ } else if (errno == ENOMEM) {
+ retval = PATH_UP;
+ } else {
+ retval = PATH_DOWN;
+ }
+ } else {
+ retval = PATH_UP;
+ }
+
+ if (reset_flags) {
+ flags &= ~O_DIRECT;
+ /* No point in checking for errors */
+ fcntl(fd,F_SETFL,flags);
+ }
+
+ return retval;
+}
+
+extern int
+directio (int fd, char *msg, void **context)
+{
+ unsigned char *buf, *ptr;
+ struct readsector0_checker_context * ctxt = NULL;
+ unsigned long pgsize, numsect;
+ int ret, blksize;
+
+ pgsize = getpagesize();
+
+ /*
+ * caller passed in a context : use its address
+ */
+ if (context)
+ ctxt = (struct readsector0_checker_context *) (*context);
+
+ /*
+ * passed in context is uninitialized or volatile context :
+ * initialize it
+ */
+ if (!ctxt) {
+ ctxt = malloc(sizeof(struct readsector0_checker_context));
+ memset(ctxt, 0, sizeof(struct readsector0_checker_context));
+
+ if (!ctxt) {
+ MSG("cannot allocate context");
+ return -1;
+ }
+ if (context)
+ *context = ctxt;
+ }
+ if (fd <= 0) {
+ MSG("no usable fd");
+ ret = -1;
+ goto out;
+ }
+
+ if (ioctl(fd, BLKGETSIZE, &numsect) < 0) {
+ MSG("cannot get number of sectors, set default");
+ numsect = 0;
+ }
+
+ if (ioctl(fd, BLKBSZGET, &blksize) < 0) {
+ MSG("cannot get blocksize, set default");
+ blksize = 512;
+ }
+
+ if (blksize > 4096) {
+ /*
+ * Sanity check for DASD; BSZGET is broken
+ */
+ blksize = 4096;
+ }
+
+ if (!blksize) {
+ /*
+ * Blocksize is 0, assume we can't write
+ * to this device.
+ */
+ MSG(MSG_DIRECTIO_DOWN);
+ ret = PATH_DOWN;
+ goto out;
+ }
+
+ buf = (unsigned char *)malloc(blksize + pgsize);
+ if (!buf){
+ goto out;
+ }
+ ptr = (unsigned char *)(((unsigned long)buf + pgsize - 1) &
+ (~(pgsize - 1)));
+ ret = direct_read(fd, ptr, blksize);
+
+ switch (ret)
+ {
+ case PATH_UNCHECKED:
+ MSG(MSG_DIRECTIO_UNKNOWN);
+ break;
+ case PATH_DOWN:
+ MSG(MSG_DIRECTIO_DOWN);
+ break;
+ case PATH_UP:
+ MSG(MSG_DIRECTIO_UP);
+ break;
+ default:
+ break;
+ }
+ free(buf);
+
+out:
+ /*
+ * caller told us he doesn't want to keep the context :
+ * free it
+ */
+ if (!context)
+ free(ctxt);
+
+ return ret;
+}
diff --git a/libcheckers/selector.c b/libcheckers/selector.c
index 306b198..43f88f0 100644
--- a/libcheckers/selector.c
+++ b/libcheckers/selector.c
@@ -10,6 +10,8 @@ get_checker_id (char * str)
return TUR;
if (0 == strncmp(str, "readsector0", 11))
return READSECTOR0;
+ if (0 == strncmp(str, "directio", 8))
+ return DIRECTIO;
if (0 == strncmp(str, "emc_clariion", 12))
return EMC_CLARIION;
if (0 == strncmp(str, "hp_sw", 5))
@@ -29,6 +31,9 @@ get_checker_addr (int id)
case READSECTOR0:
checker = &readsector0;
break;
+ case DIRECTIO:
+ checker = &directio;
+ break;
case EMC_CLARIION:
checker = &emc_clariion;
break;
@@ -54,6 +59,9 @@ get_checker_name (char * str, int id)
case READSECTOR0:
s = "readsector0";
break;
+ case DIRECTIO:
+ s = "directio";
+ break;
case EMC_CLARIION:
s = "emc_clariion";
break;