da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1985-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* http://www.opensource.org/licenses/cpl1.0.txt *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Glenn Fowler <gsf@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Phong Vo <kpv@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "sfdchdr.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* Discipline to turn on direct IO capability.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** This currently only works for XFS on SGI's.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin**
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef FDIRECT
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef F_FIOINFO
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct _direct_s
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{ Sfdisc_t disc; /* Sfio discipline */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int cntl; /* file control flags */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef F_DIOINFO
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct dioattr dio; /* direct IO params */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin} Direct_t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* convert a pointer to an int */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define P2I(p) (Sfulong_t)((char*)(p) - (char*)0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t diordwr(Sfio_t* f, Void_t* buf, size_t n, Direct_t* di, int type)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t diordwr(f, buf, n, di, type)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfio_t* f;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinsize_t n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinDirect_t* di;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint type;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t rw, done;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ssize_t rv;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin done = 0; /* amount processed by direct IO */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin rv = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef F_DIOINFO
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((P2I(buf)%di->dio.d_mem) == 0 &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (f->here%di->dio.d_miniosz) == 0 && n >= di->dio.d_miniosz )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* direct IO ok, make sure we're in the right mode */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(di->cntl & FDIRECT) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { di->cntl |= FDIRECT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void)fcntl(f->file, F_SETFL, di->cntl);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for(rw = (n/di->dio.d_miniosz)*di->dio.d_miniosz;; )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { size_t io;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((io = rw) > di->dio.d_maxiosz )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin io = di->dio.d_maxiosz;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(type == SF_READ)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rv = read(f->file,buf,io);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else rv = write(f->file,buf,io);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(rv > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { rw -= rv; done += rv;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin buf = (Void_t*)((char*)buf + rv);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(rv < io || rw < di->dio.d_miniosz)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(done < n && (di->cntl & FDIRECT) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* turn off directIO for remaining IO operation */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->cntl &= ~FDIRECT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void)fcntl(f->file, F_SETFL, di->cntl);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /*F_DIOINFO*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((rw = n-done) > 0 &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (rv = type == SF_READ ? read(f->file,buf,rw) : write(f->file,buf,rw)) > 0 )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin done += rv;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return done ? done : rv;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t dioread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t dioread(f, buf, n, disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfio_t* f;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinsize_t n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfdisc_t* disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return diordwr(f, buf, n, (Direct_t*)disc, SF_READ);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t diowrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t diowrite(f, buf, n, disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfio_t* f;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinsize_t n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfdisc_t* disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return diordwr(f, (Void_t*)buf, n, (Direct_t*)disc, SF_WRITE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int dioexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int dioexcept(f,type,data,disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfio_t* f;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint type;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* data;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfdisc_t* disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Direct_t* di = (Direct_t*)disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(type == SF_FINAL || type == SF_DPOP)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef F_DIOINFO
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(di->cntl&FDIRECT)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { di->cntl &= ~FDIRECT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void)fcntl(f->file,F_SETFL,di->cntl);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(disc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint sfdcdio(Sfio_t* f, size_t bufsize)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint sfdcdio(f, bufsize)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinSfio_t* f;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinsize_t bufsize;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef F_DIOINFO
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int cntl;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct dioattr dio;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Void_t* buf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Direct_t* di;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(f->extent < 0 || (f->flags&SF_STRING))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((cntl = fcntl(f->file,F_GETFL,0)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(cntl&FDIRECT) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { cntl |= FDIRECT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fcntl(f->file,F_SETFL,cntl) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fcntl(f->file,F_DIOINFO,&dio) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto no_direct;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(bufsize > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bufsize = (bufsize/dio.d_miniosz)*dio.d_miniosz;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(bufsize <= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bufsize = dio.d_miniosz*64;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(bufsize > dio.d_maxiosz)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin bufsize = dio.d_maxiosz;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(di = (Direct_t*)malloc(sizeof(Direct_t))) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto no_direct;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(buf = (Void_t*)memalign(dio.d_mem,bufsize)) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { free(di);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto no_direct;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfsetbuf(f,buf,bufsize);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sfsetbuf(f,buf,0) == buf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfset(f,SF_MALLOC,1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { free(buf);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(di);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto no_direct;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->disc.readf = dioread;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->disc.writef = diowrite;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->disc.seekf = NIL(Sfseek_f);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->disc.exceptf = dioexcept;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->cntl = cntl;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di->dio = dio;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sfdisc(f,(Sfdisc_t*)di) != (Sfdisc_t*)di)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { free(di);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin no_direct:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cntl &= ~FDIRECT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void)fcntl(f->file,F_SETFL,cntl);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /*F_DIOINFO*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}