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