[dm-devel] multipath-tools/libcheckers directio.c
bmarzins at sourceware.org
bmarzins at sourceware.org
Thu Jul 26 19:27:15 UTC 2007
CVSROOT: /cvs/dm
Module name: multipath-tools
Branch: RHEL4_FC5
Changes by: bmarzins at sourceware.org 2007-07-26 19:27:14
Modified files:
libcheckers : directio.c
Log message:
Fix for #235081. Now using async directio callout.
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/multipath-tools/libcheckers/directio.c.diff?cvsroot=dm&only_with_tag=RHEL4_FC5&r1=1.2&r2=1.2.2.1
--- multipath-tools/libcheckers/directio.c 2005/11/16 20:24:57 1.2
+++ multipath-tools/libcheckers/directio.c 2007/07/26 19:27:13 1.2.2.1
@@ -12,90 +12,149 @@
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <errno.h>
+#include <linux/kdev_t.h>
+#include <asm/unistd.h>
+#include "libaio.h"
#include "path_state.h"
#include "checkers.h"
+#include "../libmultipath/debug.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;
+struct directio_context {
+ int running;
+ int blksize;
+ unsigned char * buf;
+ unsigned char * ptr;
+ io_context_t ioctx;
+ struct iocb io;
};
static int
-direct_read (int fd, unsigned char * buff, int size)
+check_state(int fd, struct directio_context *ct)
{
long flags;
int reset_flags = 0;
- int res, retval;
+ struct timespec timeout = { .tv_sec = 2 };
+ struct io_event event;
+ struct stat sb;
+ int rc = PATH_UNCHECKED;
+ long r;
- flags = fcntl(fd,F_GETFL);
-
- if (flags < 0) {
- return PATH_UNCHECKED;
- }
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ goto out;
if (!(flags & O_DIRECT)) {
flags |= O_DIRECT;
- if (fcntl(fd,F_SETFL,flags) < 0) {
- return PATH_UNCHECKED;
- }
+ if (fcntl(fd, F_SETFL, flags) < 0)
+ goto out;
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;
+ if (fstat(fd, &sb) == 0) {
+ condlog(4, "directio: called for %x", (unsigned) sb.st_rdev);
+ }
+
+ if (!ct->running) {
+ struct iocb *ios[1] = { &ct->io };
+
+ condlog(3, "directio: starting new request");
+ memset(&ct->io, 0, sizeof(struct iocb));
+ io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
+ if (syscall(__NR_io_submit, ct->ioctx, 1, ios) != 1) {
+ condlog(3, "directio: io_submit error %i", errno);
+ rc = PATH_UNCHECKED;
+ goto out;
}
+ }
+ ct->running = 1;
+
+ r = syscall(__NR_io_getevents, ct->ioctx, 1L, 1L, &event, &timeout);
+ if (r < 1L) {
+ condlog(3, "directio: timeout r=%li errno=%i", r, errno);
+ rc = PATH_DOWN;
} else {
- retval = PATH_UP;
+ condlog(3, "directio: io finished %lu/%lu", event.res,
+ event.res2);
+ ct->running = 0;
+ rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
}
-
+
+out:
if (reset_flags) {
flags &= ~O_DIRECT;
/* No point in checking for errors */
- fcntl(fd,F_SETFL,flags);
+ fcntl(fd, F_SETFL, flags);
}
+ return rc;
+}
- return retval;
+void
+cleanup_context (struct directio_context *ctxt)
+{
+ if (ctxt->buf)
+ free(ctxt->buf);
+ syscall(__NR_io_destroy, ctxt->ioctx);
+ free(ctxt);
}
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();
+ struct directio_context * ctxt = NULL;
+ int ret;
/*
* caller passed in a context : use its address
*/
if (context)
- ctxt = (struct readsector0_checker_context *) (*context);
+ ctxt = (struct directio_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));
-
+ unsigned long pgsize = getpagesize();
+
+ ctxt = malloc(sizeof(struct directio_context));
if (!ctxt) {
- MSG("cannot allocate context");
- return -1;
+ condlog(0, "cannot allocate context");
+ goto fail;
+ }
+ memset(ctxt, 0, sizeof(struct directio_context));
+ if (syscall(__NR_io_setup, 1, &ctxt->ioctx) != 0) {
+ condlog(0, "io_setup failed");
+ goto fail;
+ }
+ if (ioctl(fd, BLKBSZGET, &ctxt->blksize) < 0) {
+ condlog(3, "cannot get blocksize, set default");
+ ctxt->blksize = 512;
}
+ if (ctxt->blksize > 4096) {
+ /*
+ * Sanity check for DASD; BSZGET is broken
+ */
+ ctxt->blksize = 4096;
+ }
+ if (!ctxt->blksize){
+ condlog(3, "blocksize is zero? Assuming path down\n");
+ MSG(MSG_DIRECTIO_DOWN);
+ ret = PATH_DOWN;
+ goto out;
+ }
+ ctxt->buf = (unsigned char *)malloc(ctxt->blksize + pgsize);
+ if (!ctxt->buf){
+ condlog(0, "cannot allocate context buffer\n");
+ goto fail;
+ }
+
+ ctxt->ptr = (unsigned char *) (((unsigned long)ctxt->buf + pgsize - 1) & (~(pgsize - 1)));
+
if (context)
*context = ctxt;
}
@@ -104,41 +163,7 @@
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);
+ ret = check_state(fd, ctxt);
switch (ret)
{
@@ -154,7 +179,6 @@
default:
break;
}
- free(buf);
out:
/*
@@ -162,7 +186,13 @@
* free it
*/
if (!context)
- free(ctxt);
+ cleanup_context(ctxt);
return ret;
+fail:
+ if (context)
+ *context = NULL;
+ if (ctxt)
+ cleanup_context(ctxt);
+ return -1;
}
More information about the dm-devel
mailing list