14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #include "sfdchdr.h"
234887Schin
244887Schin /* Discipline to turn on direct IO capability.
254887Schin ** This currently only works for XFS on SGI's.
264887Schin **
274887Schin ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
284887Schin */
294887Schin
304887Schin #ifndef FDIRECT
314887Schin #undef F_FIOINFO
324887Schin #endif
334887Schin
344887Schin typedef struct _direct_s
354887Schin { Sfdisc_t disc; /* Sfio discipline */
364887Schin int cntl; /* file control flags */
374887Schin #ifdef F_DIOINFO
384887Schin struct dioattr dio; /* direct IO params */
394887Schin #endif
404887Schin } Direct_t;
414887Schin
424887Schin /* convert a pointer to an int */
434887Schin #define P2I(p) (Sfulong_t)((char*)(p) - (char*)0)
444887Schin
454887Schin #if __STD_C
diordwr(Sfio_t * f,Void_t * buf,size_t n,Direct_t * di,int type)464887Schin static ssize_t diordwr(Sfio_t* f, Void_t* buf, size_t n, Direct_t* di, int type)
474887Schin #else
484887Schin static ssize_t diordwr(f, buf, n, di, type)
494887Schin Sfio_t* f;
504887Schin Void_t* buf;
514887Schin size_t n;
524887Schin Direct_t* di;
534887Schin int type;
544887Schin #endif
554887Schin {
564887Schin size_t rw, done;
574887Schin ssize_t rv;
584887Schin
594887Schin done = 0; /* amount processed by direct IO */
608462SApril.Chin@Sun.COM rv = 0;
614887Schin
624887Schin #ifdef F_DIOINFO
634887Schin if((P2I(buf)%di->dio.d_mem) == 0 &&
644887Schin (f->here%di->dio.d_miniosz) == 0 && n >= di->dio.d_miniosz )
654887Schin { /* direct IO ok, make sure we're in the right mode */
664887Schin if(!(di->cntl & FDIRECT) )
674887Schin { di->cntl |= FDIRECT;
684887Schin (void)fcntl(f->file, F_SETFL, di->cntl);
694887Schin }
704887Schin
714887Schin for(rw = (n/di->dio.d_miniosz)*di->dio.d_miniosz;; )
724887Schin { size_t io;
734887Schin
744887Schin if((io = rw) > di->dio.d_maxiosz )
754887Schin io = di->dio.d_maxiosz;
764887Schin if(type == SF_READ)
774887Schin rv = read(f->file,buf,io);
784887Schin else rv = write(f->file,buf,io);
794887Schin
804887Schin if(rv > 0)
814887Schin { rw -= rv; done += rv;
824887Schin buf = (Void_t*)((char*)buf + rv);
834887Schin }
844887Schin
854887Schin if(rv < io || rw < di->dio.d_miniosz)
864887Schin break;
874887Schin }
884887Schin }
894887Schin
904887Schin if(done < n && (di->cntl & FDIRECT) )
914887Schin { /* turn off directIO for remaining IO operation */
924887Schin di->cntl &= ~FDIRECT;
934887Schin (void)fcntl(f->file, F_SETFL, di->cntl);
944887Schin }
954887Schin #endif /*F_DIOINFO*/
964887Schin
974887Schin if((rw = n-done) > 0 &&
984887Schin (rv = type == SF_READ ? read(f->file,buf,rw) : write(f->file,buf,rw)) > 0 )
994887Schin done += rv;
1004887Schin
1014887Schin return done ? done : rv;
1024887Schin }
1034887Schin
1044887Schin #if __STD_C
dioread(Sfio_t * f,Void_t * buf,size_t n,Sfdisc_t * disc)1054887Schin static ssize_t dioread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
1064887Schin #else
1074887Schin static ssize_t dioread(f, buf, n, disc)
1084887Schin Sfio_t* f;
1094887Schin Void_t* buf;
1104887Schin size_t n;
1114887Schin Sfdisc_t* disc;
1124887Schin #endif
1134887Schin {
1144887Schin return diordwr(f, buf, n, (Direct_t*)disc, SF_READ);
1154887Schin }
1164887Schin
1174887Schin #if __STD_C
diowrite(Sfio_t * f,const Void_t * buf,size_t n,Sfdisc_t * disc)1184887Schin static ssize_t diowrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
1194887Schin #else
1204887Schin static ssize_t diowrite(f, buf, n, disc)
1214887Schin Sfio_t* f;
1224887Schin Void_t* buf;
1234887Schin size_t n;
1244887Schin Sfdisc_t* disc;
1254887Schin #endif
1264887Schin {
1274887Schin return diordwr(f, (Void_t*)buf, n, (Direct_t*)disc, SF_WRITE);
1284887Schin }
1294887Schin
1304887Schin #if __STD_C
dioexcept(Sfio_t * f,int type,Void_t * data,Sfdisc_t * disc)1314887Schin static int dioexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
1324887Schin #else
1334887Schin static int dioexcept(f,type,data,disc)
1344887Schin Sfio_t* f;
1354887Schin int type;
1364887Schin Void_t* data;
1374887Schin Sfdisc_t* disc;
1384887Schin #endif
1394887Schin {
1404887Schin Direct_t* di = (Direct_t*)disc;
1414887Schin
1424887Schin if(type == SF_FINAL || type == SF_DPOP)
1434887Schin {
1444887Schin #ifdef F_DIOINFO
1454887Schin if(di->cntl&FDIRECT)
1464887Schin { di->cntl &= ~FDIRECT;
1474887Schin (void)fcntl(f->file,F_SETFL,di->cntl);
1484887Schin }
1494887Schin #endif
1504887Schin free(disc);
1514887Schin }
1524887Schin
1534887Schin return 0;
1544887Schin }
1554887Schin
1564887Schin #if __STD_C
sfdcdio(Sfio_t * f,size_t bufsize)1574887Schin int sfdcdio(Sfio_t* f, size_t bufsize)
1584887Schin #else
1594887Schin int sfdcdio(f, bufsize)
1604887Schin Sfio_t* f;
1614887Schin size_t bufsize;
1624887Schin #endif
1634887Schin {
1644887Schin #ifndef F_DIOINFO
1654887Schin return -1;
1664887Schin #else
1674887Schin int cntl;
1684887Schin struct dioattr dio;
1694887Schin Void_t* buf;
1704887Schin Direct_t* di;
1714887Schin
1724887Schin if(f->extent < 0 || (f->flags&SF_STRING))
1734887Schin return -1;
1744887Schin
1754887Schin if((cntl = fcntl(f->file,F_GETFL,0)) < 0)
1764887Schin return -1;
1774887Schin
1784887Schin if(!(cntl&FDIRECT) )
1794887Schin { cntl |= FDIRECT;
1804887Schin if(fcntl(f->file,F_SETFL,cntl) < 0)
1814887Schin return -1;
1824887Schin }
1834887Schin
1844887Schin if(fcntl(f->file,F_DIOINFO,&dio) < 0)
1854887Schin goto no_direct;
1864887Schin
1874887Schin if(bufsize > 0)
1884887Schin bufsize = (bufsize/dio.d_miniosz)*dio.d_miniosz;
1894887Schin if(bufsize <= 0)
1904887Schin bufsize = dio.d_miniosz*64;
1914887Schin if(bufsize > dio.d_maxiosz)
1924887Schin bufsize = dio.d_maxiosz;
1934887Schin
1944887Schin if(!(di = (Direct_t*)malloc(sizeof(Direct_t))) )
1954887Schin goto no_direct;
1964887Schin
1974887Schin if(!(buf = (Void_t*)memalign(dio.d_mem,bufsize)) )
1984887Schin { free(di);
1994887Schin goto no_direct;
2004887Schin }
2014887Schin
2024887Schin sfsetbuf(f,buf,bufsize);
2034887Schin if(sfsetbuf(f,buf,0) == buf)
2044887Schin sfset(f,SF_MALLOC,1);
2054887Schin else
2064887Schin { free(buf);
2074887Schin free(di);
2084887Schin goto no_direct;
2094887Schin }
2104887Schin
2114887Schin di->disc.readf = dioread;
2124887Schin di->disc.writef = diowrite;
2134887Schin di->disc.seekf = NIL(Sfseek_f);
2144887Schin di->disc.exceptf = dioexcept;
2154887Schin di->cntl = cntl;
2164887Schin di->dio = dio;
2174887Schin
2184887Schin if(sfdisc(f,(Sfdisc_t*)di) != (Sfdisc_t*)di)
2194887Schin { free(di);
2204887Schin no_direct:
2214887Schin cntl &= ~FDIRECT;
2224887Schin (void)fcntl(f->file,F_SETFL,cntl);
2234887Schin return -1;
2244887Schin }
2254887Schin
2264887Schin return 0;
2274887Schin
2284887Schin #endif /*F_DIOINFO*/
2294887Schin }
230