xref: /titanic_50/usr/src/lib/libast/common/disc/sfdcdio.c (revision bbfe764ef179c2f606b093b6ec6bb149cde0e31b)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfdchdr.h"
23 
24 /*	Discipline to turn on direct IO capability.
25 **	This currently only works for XFS on SGI's.
26 **
27 **	Written by Kiem-Phong Vo, kpv@research.att.com, 03/18/1998.
28 */
29 
30 #ifndef FDIRECT
31 #undef F_FIOINFO
32 #endif
33 
34 typedef struct _direct_s
35 {	Sfdisc_t	disc;	/* Sfio discipline	*/
36 	int		cntl;	/* file control flags	*/
37 #ifdef F_DIOINFO
38 	struct dioattr	dio;	/* direct IO params	*/
39 #endif
40 } Direct_t;
41 
42 /* convert a pointer to an int */
43 #define P2I(p)	(Sfulong_t)((char*)(p) - (char*)0)
44 
45 #if __STD_C
46 static ssize_t diordwr(Sfio_t* f, Void_t* buf, size_t n, Direct_t* di, int type)
47 #else
48 static ssize_t diordwr(f, buf, n, di, type)
49 Sfio_t*		f;
50 Void_t*		buf;
51 size_t		n;
52 Direct_t*	di;
53 int		type;
54 #endif
55 {
56 	size_t	rw, done;
57 	ssize_t	rv;
58 
59 	done = 0;	/* amount processed by direct IO */
60 
61 #ifdef F_DIOINFO
62 	if((P2I(buf)%di->dio.d_mem) == 0 &&
63 	   (f->here%di->dio.d_miniosz) == 0 && n >= di->dio.d_miniosz )
64 	{	/* direct IO ok, make sure we're in the right mode */
65 		if(!(di->cntl & FDIRECT) )
66 		{	di->cntl |= FDIRECT;
67 			(void)fcntl(f->file, F_SETFL, di->cntl);
68 		}
69 
70 		for(rw = (n/di->dio.d_miniosz)*di->dio.d_miniosz;; )
71 		{	size_t	io;
72 
73 			if((io = rw) > di->dio.d_maxiosz )
74 				io = di->dio.d_maxiosz;
75 			if(type == SF_READ)
76 				rv = read(f->file,buf,io);
77 			else	rv = write(f->file,buf,io);
78 
79 			if(rv > 0)
80 			{	rw -= rv; done += rv;
81 				buf = (Void_t*)((char*)buf + rv);
82 			}
83 
84 			if(rv < io || rw < di->dio.d_miniosz)
85 				break;
86 		}
87 	}
88 
89 	if(done < n && (di->cntl & FDIRECT) )
90 	{	/* turn off directIO for remaining IO operation */
91 		di->cntl &= ~FDIRECT;
92 		(void)fcntl(f->file, F_SETFL, di->cntl);
93 	}
94 #endif /*F_DIOINFO*/
95 
96 	if((rw = n-done) > 0 &&
97 	   (rv = type == SF_READ ? read(f->file,buf,rw) : write(f->file,buf,rw)) > 0 )
98 		done += rv;
99 
100 	return done ? done : rv;
101 }
102 
103 #if __STD_C
104 static ssize_t dioread(Sfio_t* f, Void_t* buf, size_t n, Sfdisc_t* disc)
105 #else
106 static ssize_t dioread(f, buf, n, disc)
107 Sfio_t*		f;
108 Void_t*		buf;
109 size_t		n;
110 Sfdisc_t*	disc;
111 #endif
112 {
113 	return diordwr(f, buf, n, (Direct_t*)disc, SF_READ);
114 }
115 
116 #if __STD_C
117 static ssize_t diowrite(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
118 #else
119 static ssize_t diowrite(f, buf, n, disc)
120 Sfio_t*		f;
121 Void_t*		buf;
122 size_t		n;
123 Sfdisc_t*	disc;
124 #endif
125 {
126 	return diordwr(f, (Void_t*)buf, n, (Direct_t*)disc, SF_WRITE);
127 }
128 
129 #if __STD_C
130 static int dioexcept(Sfio_t* f, int type, Void_t* data, Sfdisc_t* disc)
131 #else
132 static int dioexcept(f,type,data,disc)
133 Sfio_t*		f;
134 int		type;
135 Void_t*		data;
136 Sfdisc_t*	disc;
137 #endif
138 {
139 	Direct_t*	di = (Direct_t*)disc;
140 
141 	if(type == SF_FINAL || type == SF_DPOP)
142 	{
143 #ifdef F_DIOINFO
144 		if(di->cntl&FDIRECT)
145 		{	di->cntl &= ~FDIRECT;
146 			(void)fcntl(f->file,F_SETFL,di->cntl);
147 		}
148 #endif
149 		free(disc);
150 	}
151 
152 	return 0;
153 }
154 
155 #if __STD_C
156 int sfdcdio(Sfio_t* f, size_t bufsize)
157 #else
158 int sfdcdio(f, bufsize)
159 Sfio_t*	f;
160 size_t	bufsize;
161 #endif
162 {
163 #ifndef F_DIOINFO
164 	return -1;
165 #else
166 	int		cntl;
167 	struct dioattr	dio;
168 	Void_t*		buf;
169 	Direct_t*	di;
170 
171 	if(f->extent < 0 || (f->flags&SF_STRING))
172 		return -1;
173 
174 	if((cntl = fcntl(f->file,F_GETFL,0)) < 0)
175 		return -1;
176 
177 	if(!(cntl&FDIRECT) )
178 	{	cntl |= FDIRECT;
179 		if(fcntl(f->file,F_SETFL,cntl) < 0)
180 			return -1;
181 	}
182 
183 	if(fcntl(f->file,F_DIOINFO,&dio) < 0)
184 		goto no_direct;
185 
186 	if(bufsize > 0)
187 		bufsize = (bufsize/dio.d_miniosz)*dio.d_miniosz;
188 	if(bufsize <= 0)
189 		bufsize = dio.d_miniosz*64;
190 	if(bufsize > dio.d_maxiosz)
191 		bufsize = dio.d_maxiosz;
192 
193 	if(!(di = (Direct_t*)malloc(sizeof(Direct_t))) )
194 		goto no_direct;
195 
196 	if(!(buf = (Void_t*)memalign(dio.d_mem,bufsize)) )
197 	{	free(di);
198 		goto no_direct;
199 	}
200 
201 	sfsetbuf(f,buf,bufsize);
202 	if(sfsetbuf(f,buf,0) == buf)
203 		sfset(f,SF_MALLOC,1);
204 	else
205 	{	free(buf);
206 		free(di);
207 		goto no_direct;
208 	}
209 
210 	di->disc.readf = dioread;
211 	di->disc.writef = diowrite;
212 	di->disc.seekf = NIL(Sfseek_f);
213 	di->disc.exceptf = dioexcept;
214 	di->cntl = cntl;
215 	di->dio = dio;
216 
217 	if(sfdisc(f,(Sfdisc_t*)di) != (Sfdisc_t*)di)
218 	{	free(di);
219 	no_direct:
220 		cntl &= ~FDIRECT;
221 		(void)fcntl(f->file,F_SETFL,cntl);
222 		return -1;
223 	}
224 
225 	return 0;
226 
227 #endif /*F_DIOINFO*/
228 }
229