diff options
author | root <root@xa-s05.(none)> | 2005-08-24 08:21:42 +0200 |
---|---|---|
committer | root <root@xa-s05.(none)> | 2005-08-24 08:21:42 +0200 |
commit | 6744ef227ac7be3498999527c2d2c61692911fbf (patch) | |
tree | cdb8606d4534186449ff12b49dfed577f3d90640 | |
parent | a9912e04bd4add6c1042ab361259c0f64cc32594 (diff) | |
download | multipath-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/Makefile | 2 | ||||
-rw-r--r-- | libcheckers/checkers.h | 2 | ||||
-rw-r--r-- | libcheckers/directio.c | 165 | ||||
-rw-r--r-- | libcheckers/selector.c | 8 |
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; |