xref: /haiku/src/system/kernel/fs/vfs_request_io.cpp (revision 5c56d775a9ef7f4dc3508b3ea4f2377324b6a575)
1ec598fe4SIngo Weinhold /*
2deee8524SIngo Weinhold  * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3ec598fe4SIngo Weinhold  * Distributed under the terms of the MIT License.
4ec598fe4SIngo Weinhold  */
5ec598fe4SIngo Weinhold 
6ec598fe4SIngo Weinhold // included by vfs.cpp
7ec598fe4SIngo Weinhold 
87f12cc54SIngo Weinhold 
97f12cc54SIngo Weinhold //#define TRACE_VFS_REQUEST_IO
107f12cc54SIngo Weinhold #ifdef TRACE_VFS_REQUEST_IO
117f12cc54SIngo Weinhold #	define TRACE_RIO(x...) dprintf(x)
127f12cc54SIngo Weinhold #else
137f12cc54SIngo Weinhold #	define TRACE_RIO(x...) do {} while (false)
147f12cc54SIngo Weinhold #endif
15ec598fe4SIngo Weinhold 
16ec598fe4SIngo Weinhold 
17deee8524SIngo Weinhold #include <heap.h>
18cdccd323SX512 #include <AutoDeleterDrivers.h>
19deee8524SIngo Weinhold 
20deee8524SIngo Weinhold 
2166394896SIngo Weinhold // #pragma mark - AsyncIOCallback
2266394896SIngo Weinhold 
2366394896SIngo Weinhold 
~AsyncIOCallback()2466394896SIngo Weinhold AsyncIOCallback::~AsyncIOCallback()
2566394896SIngo Weinhold {
2666394896SIngo Weinhold }
2766394896SIngo Weinhold 
2866394896SIngo Weinhold 
293ecbb342SAugustin Cavalier /* static */ void
IORequestCallback(void * data,io_request * request,status_t status,bool partialTransfer,generic_size_t bytesTransferred)3066394896SIngo Weinhold AsyncIOCallback::IORequestCallback(void* data, io_request* request,
313ecbb342SAugustin Cavalier 	status_t status, bool partialTransfer, generic_size_t bytesTransferred)
3266394896SIngo Weinhold {
3366394896SIngo Weinhold 	((AsyncIOCallback*)data)->IOFinished(status, partialTransfer,
343ecbb342SAugustin Cavalier 		bytesTransferred);
3566394896SIngo Weinhold }
3666394896SIngo Weinhold 
3766394896SIngo Weinhold 
3866394896SIngo Weinhold // #pragma mark - StackableAsyncIOCallback
3966394896SIngo Weinhold 
4066394896SIngo Weinhold 
StackableAsyncIOCallback(AsyncIOCallback * next)4166394896SIngo Weinhold StackableAsyncIOCallback::StackableAsyncIOCallback(AsyncIOCallback* next)
4266394896SIngo Weinhold 	:
4366394896SIngo Weinhold 	fNextCallback(next)
4466394896SIngo Weinhold {
4566394896SIngo Weinhold }
4666394896SIngo Weinhold 
4766394896SIngo Weinhold 
4866394896SIngo Weinhold // #pragma mark -
4966394896SIngo Weinhold 
5066394896SIngo Weinhold 
51ec598fe4SIngo Weinhold struct iterative_io_cookie {
52ec598fe4SIngo Weinhold 	struct vnode*					vnode;
53ec598fe4SIngo Weinhold 	file_descriptor*				descriptor;
54ec598fe4SIngo Weinhold 	iterative_io_get_vecs			get_vecs;
55ec598fe4SIngo Weinhold 	iterative_io_finished			finished;
56ec598fe4SIngo Weinhold 	void*							cookie;
57ec598fe4SIngo Weinhold 	off_t							request_offset;
58ec598fe4SIngo Weinhold 	io_request_finished_callback	next_finished_callback;
59ec598fe4SIngo Weinhold 	void*							next_finished_cookie;
60ec598fe4SIngo Weinhold };
61ec598fe4SIngo Weinhold 
62ec598fe4SIngo Weinhold 
63ec598fe4SIngo Weinhold class DoIO {
64ec598fe4SIngo Weinhold public:
DoIO(bool write)6530372751SMichael Lotz 	DoIO(bool write)
66ec598fe4SIngo Weinhold 		:
6730372751SMichael Lotz 		fWrite(write)
68ec598fe4SIngo Weinhold 	{
69ec598fe4SIngo Weinhold 	}
70ec598fe4SIngo Weinhold 
~DoIO()71ec598fe4SIngo Weinhold 	virtual	~DoIO()
72ec598fe4SIngo Weinhold 	{
73ec598fe4SIngo Weinhold 	}
74ec598fe4SIngo Weinhold 
7530372751SMichael Lotz 	virtual status_t IO(off_t offset, void* buffer, size_t* length) = 0;
76ec598fe4SIngo Weinhold 
77ec598fe4SIngo Weinhold protected:
78ec598fe4SIngo Weinhold 	bool	fWrite;
79ec598fe4SIngo Weinhold };
80ec598fe4SIngo Weinhold 
81ec598fe4SIngo Weinhold 
82ec598fe4SIngo Weinhold class CallbackIO : public DoIO {
83ec598fe4SIngo Weinhold public:
CallbackIO(bool write,status_t (* doIO)(void * cookie,off_t offset,void * buffer,size_t * length),void * cookie)8430372751SMichael Lotz 	CallbackIO(bool write,
85ec598fe4SIngo Weinhold 			status_t (*doIO)(void* cookie, off_t offset, void* buffer,
867f12cc54SIngo Weinhold 				size_t* length),
87ec598fe4SIngo Weinhold 			void* cookie)
88ec598fe4SIngo Weinhold 		:
8930372751SMichael Lotz 		DoIO(write),
90ec598fe4SIngo Weinhold 		fDoIO(doIO),
91ec598fe4SIngo Weinhold 		fCookie(cookie)
92ec598fe4SIngo Weinhold 	{
93ec598fe4SIngo Weinhold 	}
94ec598fe4SIngo Weinhold 
IO(off_t offset,void * buffer,size_t * length)9530372751SMichael Lotz 	virtual status_t IO(off_t offset, void* buffer, size_t* length)
96ec598fe4SIngo Weinhold 	{
97ec598fe4SIngo Weinhold 		return fDoIO(fCookie, offset, buffer, length);
98ec598fe4SIngo Weinhold 	}
99ec598fe4SIngo Weinhold 
100ec598fe4SIngo Weinhold private:
1017f12cc54SIngo Weinhold 	status_t (*fDoIO)(void*, off_t, void*, size_t*);
102ec598fe4SIngo Weinhold 	void*		fCookie;
103ec598fe4SIngo Weinhold };
104ec598fe4SIngo Weinhold 
105ec598fe4SIngo Weinhold 
106ec598fe4SIngo Weinhold class VnodeIO : public DoIO {
107ec598fe4SIngo Weinhold public:
VnodeIO(bool write,struct vnode * vnode,void * cookie)108891a50b2SBruno G. Albuquerque 	VnodeIO(bool write, struct vnode* vnode, void* cookie)
109ec598fe4SIngo Weinhold 		:
11030372751SMichael Lotz 		DoIO(write),
111ec598fe4SIngo Weinhold 		fVnode(vnode),
112ec598fe4SIngo Weinhold 		fCookie(cookie)
113ec598fe4SIngo Weinhold 	{
114ec598fe4SIngo Weinhold 	}
115ec598fe4SIngo Weinhold 
IO(off_t offset,void * buffer,size_t * length)11630372751SMichael Lotz 	virtual status_t IO(off_t offset, void* buffer, size_t* length)
117ec598fe4SIngo Weinhold 	{
1187a253cf5SAxel Dörfler 		iovec vec;
1197a253cf5SAxel Dörfler 		vec.iov_base = buffer;
1207a253cf5SAxel Dörfler 		vec.iov_len = *length;
121ec598fe4SIngo Weinhold 
1227a253cf5SAxel Dörfler 		if (fWrite) {
1237a253cf5SAxel Dörfler 			return FS_CALL(fVnode, write_pages, fCookie, offset, &vec, 1,
1247a253cf5SAxel Dörfler 				length);
1257a253cf5SAxel Dörfler 		}
1267a253cf5SAxel Dörfler 
1277a253cf5SAxel Dörfler 		return FS_CALL(fVnode, read_pages, fCookie, offset, &vec, 1, length);
128ec598fe4SIngo Weinhold 	}
129ec598fe4SIngo Weinhold 
130ec598fe4SIngo Weinhold private:
131ec598fe4SIngo Weinhold 	struct vnode*	fVnode;
132ec598fe4SIngo Weinhold 	void*			fCookie;
133ec598fe4SIngo Weinhold };
134ec598fe4SIngo Weinhold 
135ec598fe4SIngo Weinhold 
136ec598fe4SIngo Weinhold static status_t
do_iterative_fd_io_iterate(void * _cookie,io_request * request,bool * _partialTransfer)1377f12cc54SIngo Weinhold do_iterative_fd_io_iterate(void* _cookie, io_request* request,
1387f12cc54SIngo Weinhold 	bool* _partialTransfer)
139ec598fe4SIngo Weinhold {
1407f12cc54SIngo Weinhold 	TRACE_RIO("[%ld] do_iterative_fd_io_iterate(request: %p)\n",
1417f12cc54SIngo Weinhold 		find_thread(NULL), request);
1427f12cc54SIngo Weinhold 
1434be4fc6bSAlex Smith 	static const size_t kMaxSubRequests = 8;
144ec598fe4SIngo Weinhold 
145ec598fe4SIngo Weinhold 	iterative_io_cookie* cookie = (iterative_io_cookie*)_cookie;
146ec598fe4SIngo Weinhold 
147ec598fe4SIngo Weinhold 	request->DeleteSubRequests();
148ec598fe4SIngo Weinhold 
149ec598fe4SIngo Weinhold 	off_t requestOffset = cookie->request_offset;
150ec598fe4SIngo Weinhold 	size_t requestLength = request->Length()
151ec598fe4SIngo Weinhold 		- (requestOffset - request->Offset());
152ec598fe4SIngo Weinhold 
153ec598fe4SIngo Weinhold 	// get the next file vecs
154ec598fe4SIngo Weinhold 	file_io_vec vecs[kMaxSubRequests];
1554be4fc6bSAlex Smith 	size_t vecCount = kMaxSubRequests;
156ec598fe4SIngo Weinhold 	status_t error = cookie->get_vecs(cookie->cookie, request, requestOffset,
157ec598fe4SIngo Weinhold 		requestLength, vecs, &vecCount);
158e1ca73e1SAxel Dörfler 	if (error != B_OK && error != B_BUFFER_OVERFLOW)
159ec598fe4SIngo Weinhold 		return error;
1607f12cc54SIngo Weinhold 	if (vecCount == 0) {
1617f12cc54SIngo Weinhold 		*_partialTransfer = true;
1627f12cc54SIngo Weinhold 		return B_OK;
1637f12cc54SIngo Weinhold 	}
1644be4fc6bSAlex Smith 	TRACE_RIO("[%ld]  got %zu file vecs\n", find_thread(NULL), vecCount);
165ec598fe4SIngo Weinhold 
166e36ad522SFrançois Revol 	// Reset the error code for the loop below
167e36ad522SFrançois Revol 	error = B_OK;
168e36ad522SFrançois Revol 
169ec598fe4SIngo Weinhold 	// create subrequests for the file vecs we've got
1704be4fc6bSAlex Smith 	size_t subRequestCount = 0;
171e36ad522SFrançois Revol 	for (size_t i = 0;
172e36ad522SFrançois Revol 		i < vecCount && subRequestCount < kMaxSubRequests && error == B_OK;
173e36ad522SFrançois Revol 		i++) {
174ec598fe4SIngo Weinhold 		off_t vecOffset = vecs[i].offset;
175311e1487SJérôme Duval 		off_t vecLength = min_c(vecs[i].length, (off_t)requestLength);
1767f12cc54SIngo Weinhold 		TRACE_RIO("[%ld]    vec %lu offset: %lld, length: %lld\n",
1777f12cc54SIngo Weinhold 			find_thread(NULL), i, vecOffset, vecLength);
178ec598fe4SIngo Weinhold 
17924d0e21fSIngo Weinhold 		// Special offset -1 means that this is part of sparse file that is
18024d0e21fSIngo Weinhold 		// zero. We fill it in right here.
18124d0e21fSIngo Weinhold 		if (vecOffset == -1) {
18224d0e21fSIngo Weinhold 			if (request->IsWrite()) {
18324d0e21fSIngo Weinhold 				panic("do_iterative_fd_io_iterate(): write to sparse file "
18424d0e21fSIngo Weinhold 					"vector");
18524d0e21fSIngo Weinhold 				error = B_BAD_VALUE;
18624d0e21fSIngo Weinhold 				break;
18724d0e21fSIngo Weinhold 			}
18824d0e21fSIngo Weinhold 
18924d0e21fSIngo Weinhold 			error = request->ClearData(requestOffset, vecLength);
19024d0e21fSIngo Weinhold 			if (error != B_OK)
19124d0e21fSIngo Weinhold 				break;
19224d0e21fSIngo Weinhold 
19324d0e21fSIngo Weinhold 			requestOffset += vecLength;
19424d0e21fSIngo Weinhold 			requestLength -= vecLength;
19524d0e21fSIngo Weinhold 			continue;
19624d0e21fSIngo Weinhold 		}
19724d0e21fSIngo Weinhold 
198ec598fe4SIngo Weinhold 		while (vecLength > 0 && subRequestCount < kMaxSubRequests) {
1997f12cc54SIngo Weinhold 			TRACE_RIO("[%ld]    creating subrequest: offset: %lld, length: "
2007f12cc54SIngo Weinhold 				"%lld\n", find_thread(NULL), vecOffset, vecLength);
201ec598fe4SIngo Weinhold 			IORequest* subRequest;
202ec598fe4SIngo Weinhold 			error = request->CreateSubRequest(requestOffset, vecOffset,
203ec598fe4SIngo Weinhold 				vecLength, subRequest);
204ec598fe4SIngo Weinhold 			if (error != B_OK)
205ec598fe4SIngo Weinhold 				break;
206ec598fe4SIngo Weinhold 
207ec598fe4SIngo Weinhold 			subRequestCount++;
208ec598fe4SIngo Weinhold 
209ec598fe4SIngo Weinhold 			size_t lengthProcessed = subRequest->Length();
210ec598fe4SIngo Weinhold 			vecOffset += lengthProcessed;
211ec598fe4SIngo Weinhold 			vecLength -= lengthProcessed;
212ec598fe4SIngo Weinhold 			requestOffset += lengthProcessed;
213ec598fe4SIngo Weinhold 			requestLength -= lengthProcessed;
214ec598fe4SIngo Weinhold 		}
215ec598fe4SIngo Weinhold 	}
216ec598fe4SIngo Weinhold 
217ec598fe4SIngo Weinhold 	// Only if we couldn't create any subrequests, we fail.
218ec598fe4SIngo Weinhold 	if (error != B_OK && subRequestCount == 0)
219ec598fe4SIngo Weinhold 		return error;
220ec598fe4SIngo Weinhold 
221230153f1SMichael Lotz 	// Reset the error code for the loop below
222230153f1SMichael Lotz 	error = B_OK;
223230153f1SMichael Lotz 
224ec598fe4SIngo Weinhold 	request->Advance(requestOffset - cookie->request_offset);
225ec598fe4SIngo Weinhold 	cookie->request_offset = requestOffset;
226ec598fe4SIngo Weinhold 
22724d0e21fSIngo Weinhold 	// If we don't have any sub requests at this point, that means all that
22824d0e21fSIngo Weinhold 	// remained were zeroed sparse file vectors. So the request is done now.
22924d0e21fSIngo Weinhold 	if (subRequestCount == 0) {
23024d0e21fSIngo Weinhold 		ASSERT(request->RemainingBytes() == 0);
23124d0e21fSIngo Weinhold 		request->SetStatusAndNotify(B_OK);
23224d0e21fSIngo Weinhold 		return B_OK;
23324d0e21fSIngo Weinhold 	}
23424d0e21fSIngo Weinhold 
235ec598fe4SIngo Weinhold 	// Schedule the subrequests.
2367f12cc54SIngo Weinhold 	IORequest* nextSubRequest = request->FirstSubRequest();
2377f12cc54SIngo Weinhold 	while (nextSubRequest != NULL) {
2387f12cc54SIngo Weinhold 		IORequest* subRequest = nextSubRequest;
2397f12cc54SIngo Weinhold 		nextSubRequest = request->NextSubRequest(subRequest);
2407f12cc54SIngo Weinhold 
241ec598fe4SIngo Weinhold 		if (error == B_OK) {
2427f12cc54SIngo Weinhold 			TRACE_RIO("[%ld]  scheduling subrequest: %p\n", find_thread(NULL),
2437f12cc54SIngo Weinhold 				subRequest);
2445054db18SIngo Weinhold 			error = vfs_vnode_io(cookie->vnode, cookie->descriptor->cookie,
245ec598fe4SIngo Weinhold 				subRequest);
246ec598fe4SIngo Weinhold 		} else {
247ec598fe4SIngo Weinhold 			// Once scheduling a subrequest failed, we cancel all subsequent
248ec598fe4SIngo Weinhold 			// subrequests.
249ec598fe4SIngo Weinhold 			subRequest->SetStatusAndNotify(B_CANCELED);
250ec598fe4SIngo Weinhold 		}
251ec598fe4SIngo Weinhold 	}
252ec598fe4SIngo Weinhold 
253ec598fe4SIngo Weinhold 	// TODO: Cancel the subrequests that were scheduled successfully.
254ec598fe4SIngo Weinhold 
255ec598fe4SIngo Weinhold 	return B_OK;
256ec598fe4SIngo Weinhold }
257ec598fe4SIngo Weinhold 
258ec598fe4SIngo Weinhold 
2593ecbb342SAugustin Cavalier static void
do_iterative_fd_io_finish(void * _cookie,io_request * request,status_t status,bool partialTransfer,generic_size_t bytesTransferred)2607f12cc54SIngo Weinhold do_iterative_fd_io_finish(void* _cookie, io_request* request, status_t status,
2613ecbb342SAugustin Cavalier 	bool partialTransfer, generic_size_t bytesTransferred)
262ec598fe4SIngo Weinhold {
263ec598fe4SIngo Weinhold 	iterative_io_cookie* cookie = (iterative_io_cookie*)_cookie;
264ec598fe4SIngo Weinhold 
2657f12cc54SIngo Weinhold 	if (cookie->finished != NULL) {
2667f12cc54SIngo Weinhold 		cookie->finished(cookie->cookie, request, status, partialTransfer,
2673ecbb342SAugustin Cavalier 			bytesTransferred);
2687f12cc54SIngo Weinhold 	}
269ec598fe4SIngo Weinhold 
270ec598fe4SIngo Weinhold 	put_fd(cookie->descriptor);
271ec598fe4SIngo Weinhold 
272ec598fe4SIngo Weinhold 	if (cookie->next_finished_callback != NULL) {
273ec598fe4SIngo Weinhold 		cookie->next_finished_callback(cookie->next_finished_cookie, request,
2743ecbb342SAugustin Cavalier 			status, partialTransfer, bytesTransferred);
275ec598fe4SIngo Weinhold 	}
276ec598fe4SIngo Weinhold 
277ec598fe4SIngo Weinhold 	delete cookie;
278ec598fe4SIngo Weinhold }
279ec598fe4SIngo Weinhold 
280ec598fe4SIngo Weinhold 
281ec598fe4SIngo Weinhold static status_t
do_synchronous_iterative_vnode_io(struct vnode * vnode,void * openCookie,io_request * request,iterative_io_get_vecs getVecs,iterative_io_finished finished,void * cookie)282ec598fe4SIngo Weinhold do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
283ec598fe4SIngo Weinhold 	io_request* request, iterative_io_get_vecs getVecs,
284ec598fe4SIngo Weinhold 	iterative_io_finished finished, void* cookie)
285ec598fe4SIngo Weinhold {
286ec598fe4SIngo Weinhold 	IOBuffer* buffer = request->Buffer();
28730372751SMichael Lotz 	VnodeIO io(request->IsWrite(), vnode, openCookie);
288ec598fe4SIngo Weinhold 
28930372751SMichael Lotz 	iovec vector;
29030372751SMichael Lotz 	void* virtualVecCookie = NULL;
291ec598fe4SIngo Weinhold 	off_t offset = request->Offset();
292435c43f5SIngo Weinhold 	generic_size_t length = request->Length();
293ec598fe4SIngo Weinhold 
294ec598fe4SIngo Weinhold 	status_t error = B_OK;
295*5c56d775SAugustin Cavalier 	bool partial = false;
296ec598fe4SIngo Weinhold 
297*5c56d775SAugustin Cavalier 	for (; error == B_OK && length > 0 && !partial
29830372751SMichael Lotz 			&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
29930372751SMichael Lotz 		uint8* vecBase = (uint8*)vector.iov_base;
300435c43f5SIngo Weinhold 		generic_size_t vecLength = min_c(vector.iov_len, length);
301ec598fe4SIngo Weinhold 
302ec598fe4SIngo Weinhold 		while (error == B_OK && vecLength > 0) {
303ec598fe4SIngo Weinhold 			file_io_vec fileVecs[8];
3044be4fc6bSAlex Smith 			size_t fileVecCount = 8;
305e829154fSAugustin Cavalier 			if (getVecs != NULL) {
306ec598fe4SIngo Weinhold 				error = getVecs(cookie, request, offset, vecLength, fileVecs,
307ec598fe4SIngo Weinhold 					&fileVecCount);
308e829154fSAugustin Cavalier 			} else {
309e829154fSAugustin Cavalier 				fileVecs[0].offset = offset;
310e829154fSAugustin Cavalier 				fileVecs[0].length = vecLength;
311e829154fSAugustin Cavalier 				fileVecCount = 1;
312e829154fSAugustin Cavalier 			}
313*5c56d775SAugustin Cavalier 			if (error != B_OK)
314ec598fe4SIngo Weinhold 				break;
315*5c56d775SAugustin Cavalier 			if (fileVecCount == 0) {
316*5c56d775SAugustin Cavalier 				partial = true;
317*5c56d775SAugustin Cavalier 				break;
318*5c56d775SAugustin Cavalier 			}
319ec598fe4SIngo Weinhold 
3204be4fc6bSAlex Smith 			for (size_t i = 0; i < fileVecCount; i++) {
321ec598fe4SIngo Weinhold 				const file_io_vec& fileVec = fileVecs[i];
3221d578e15SIngo Weinhold 				size_t toTransfer = min_c(fileVec.length, (off_t)length);
3237f12cc54SIngo Weinhold 				size_t transferred = toTransfer;
3247f12cc54SIngo Weinhold 				error = io.IO(fileVec.offset, vecBase, &transferred);
325ec598fe4SIngo Weinhold 				if (error != B_OK)
326ec598fe4SIngo Weinhold 					break;
327ec598fe4SIngo Weinhold 
3287f12cc54SIngo Weinhold 				offset += transferred;
3297f12cc54SIngo Weinhold 				length -= transferred;
3307f12cc54SIngo Weinhold 				vecBase += transferred;
3317f12cc54SIngo Weinhold 				vecLength -= transferred;
3327f12cc54SIngo Weinhold 
333*5c56d775SAugustin Cavalier 				if (transferred != toTransfer) {
334*5c56d775SAugustin Cavalier 					partial = true;
3357f12cc54SIngo Weinhold 					break;
336ec598fe4SIngo Weinhold 				}
337ec598fe4SIngo Weinhold 			}
338ec598fe4SIngo Weinhold 		}
339*5c56d775SAugustin Cavalier 	}
340ec598fe4SIngo Weinhold 
34130372751SMichael Lotz 	buffer->FreeVirtualVecCookie(virtualVecCookie);
34230372751SMichael Lotz 
343*5c56d775SAugustin Cavalier 	partial = (partial || length > 0);
3447f12cc54SIngo Weinhold 	size_t bytesTransferred = request->Length() - length;
3457f12cc54SIngo Weinhold 	request->SetTransferredBytes(partial, bytesTransferred);
346e829154fSAugustin Cavalier 	if (finished != NULL)
3477f12cc54SIngo Weinhold 		finished(cookie, request, error, partial, bytesTransferred);
348ec598fe4SIngo Weinhold 	request->SetStatusAndNotify(error);
349ec598fe4SIngo Weinhold 	return error;
350ec598fe4SIngo Weinhold }
351ec598fe4SIngo Weinhold 
352ec598fe4SIngo Weinhold 
353ec598fe4SIngo Weinhold static status_t
synchronous_io(io_request * request,DoIO & io)354ec598fe4SIngo Weinhold synchronous_io(io_request* request, DoIO& io)
355ec598fe4SIngo Weinhold {
356935c5e82SIngo Weinhold 	TRACE_RIO("[%" B_PRId32 "] synchronous_io(request: %p (offset: %" B_PRIdOFF
357935c5e82SIngo Weinhold 		", length: %" B_PRIuGENADDR "))\n", find_thread(NULL), request,
358935c5e82SIngo Weinhold 		request->Offset(), request->Length());
3597f12cc54SIngo Weinhold 
360ec598fe4SIngo Weinhold 	IOBuffer* buffer = request->Buffer();
361ec598fe4SIngo Weinhold 
36230372751SMichael Lotz 	iovec vector;
36330372751SMichael Lotz 	void* virtualVecCookie = NULL;
364ec598fe4SIngo Weinhold 	off_t offset = request->Offset();
365435c43f5SIngo Weinhold 	generic_size_t length = request->Length();
366ec598fe4SIngo Weinhold 
36730372751SMichael Lotz 	for (; length > 0
36830372751SMichael Lotz 			&& buffer->GetNextVirtualVec(virtualVecCookie, vector) == B_OK;) {
369435c43f5SIngo Weinhold 		void* vecBase = (void*)(addr_t)vector.iov_base;
37030372751SMichael Lotz 		size_t vecLength = min_c(vector.iov_len, length);
371ec598fe4SIngo Weinhold 
3727f12cc54SIngo Weinhold 		TRACE_RIO("[%ld]   I/O: offset: %lld, vecBase: %p, length: %lu\n",
3737f12cc54SIngo Weinhold 			find_thread(NULL), offset, vecBase, vecLength);
3747f12cc54SIngo Weinhold 
3751d578e15SIngo Weinhold 		size_t transferred = vecLength;
3767f12cc54SIngo Weinhold 		status_t error = io.IO(offset, vecBase, &transferred);
377ec598fe4SIngo Weinhold 		if (error != B_OK) {
3787f12cc54SIngo Weinhold 			TRACE_RIO("[%ld]   I/O failed: %#lx\n", find_thread(NULL), error);
37930372751SMichael Lotz 			buffer->FreeVirtualVecCookie(virtualVecCookie);
380ec598fe4SIngo Weinhold 			request->SetStatusAndNotify(error);
381ec598fe4SIngo Weinhold 			return error;
382ec598fe4SIngo Weinhold 		}
383ec598fe4SIngo Weinhold 
3847f12cc54SIngo Weinhold 		offset += transferred;
3857f12cc54SIngo Weinhold 		length -= transferred;
3867f12cc54SIngo Weinhold 
3875054db18SIngo Weinhold 		if (transferred != vecLength)
3887f12cc54SIngo Weinhold 			break;
389ec598fe4SIngo Weinhold 	}
390ec598fe4SIngo Weinhold 
3917f12cc54SIngo Weinhold 	TRACE_RIO("[%ld] synchronous_io() succeeded\n", find_thread(NULL));
3927f12cc54SIngo Weinhold 
39330372751SMichael Lotz 	buffer->FreeVirtualVecCookie(virtualVecCookie);
3947f12cc54SIngo Weinhold 	request->SetTransferredBytes(length > 0, request->Length() - length);
395ec598fe4SIngo Weinhold 	request->SetStatusAndNotify(B_OK);
396ec598fe4SIngo Weinhold 	return B_OK;
397ec598fe4SIngo Weinhold }
398ec598fe4SIngo Weinhold 
399ec598fe4SIngo Weinhold 
400ec598fe4SIngo Weinhold // #pragma mark - kernel private API
401ec598fe4SIngo Weinhold 
402ec598fe4SIngo Weinhold 
403cfae07b6SIngo Weinhold status_t
vfs_vnode_io(struct vnode * vnode,void * cookie,io_request * request)404cfae07b6SIngo Weinhold vfs_vnode_io(struct vnode* vnode, void* cookie, io_request* request)
405cfae07b6SIngo Weinhold {
40600405f22SMichael Lotz 	status_t result = B_ERROR;
40700405f22SMichael Lotz 	if (!HAS_FS_CALL(vnode, io)
40800405f22SMichael Lotz 		|| (result = FS_CALL(vnode, io, cookie, request)) == B_UNSUPPORTED) {
409cfae07b6SIngo Weinhold 		// no io() call -- fall back to synchronous I/O
41030372751SMichael Lotz 		VnodeIO io(request->IsWrite(), vnode, cookie);
411cfae07b6SIngo Weinhold 		return synchronous_io(request, io);
412cfae07b6SIngo Weinhold 	}
413cfae07b6SIngo Weinhold 
41400405f22SMichael Lotz 	return result;
415cfae07b6SIngo Weinhold }
416cfae07b6SIngo Weinhold 
417cfae07b6SIngo Weinhold 
418cfae07b6SIngo Weinhold status_t
vfs_synchronous_io(io_request * request,status_t (* doIO)(void * cookie,off_t offset,void * buffer,size_t * length),void * cookie)419ec598fe4SIngo Weinhold vfs_synchronous_io(io_request* request,
4207f12cc54SIngo Weinhold 	status_t (*doIO)(void* cookie, off_t offset, void* buffer, size_t* length),
421ec598fe4SIngo Weinhold 	void* cookie)
422ec598fe4SIngo Weinhold {
42330372751SMichael Lotz 	CallbackIO io(request->IsWrite(), doIO, cookie);
424ec598fe4SIngo Weinhold 	return synchronous_io(request, io);
425ec598fe4SIngo Weinhold }
426ec598fe4SIngo Weinhold 
427ec598fe4SIngo Weinhold 
42866394896SIngo Weinhold status_t
vfs_asynchronous_read_pages(struct vnode * vnode,void * cookie,off_t pos,const generic_io_vec * vecs,size_t count,generic_size_t numBytes,uint32 flags,AsyncIOCallback * callback)429eb2bd0e8SStephan Aßmus vfs_asynchronous_read_pages(struct vnode* vnode, void* cookie, off_t pos,
4301d578e15SIngo Weinhold 	const generic_io_vec* vecs, size_t count, generic_size_t numBytes,
4311d578e15SIngo Weinhold 	uint32 flags, AsyncIOCallback* callback)
432eb2bd0e8SStephan Aßmus {
433eb2bd0e8SStephan Aßmus 	IORequest* request = IORequest::Create((flags & B_VIP_IO_REQUEST) != 0);
434eb2bd0e8SStephan Aßmus 	if (request == NULL) {
435eb2bd0e8SStephan Aßmus 		callback->IOFinished(B_NO_MEMORY, true, 0);
436eb2bd0e8SStephan Aßmus 		return B_NO_MEMORY;
437eb2bd0e8SStephan Aßmus 	}
438eb2bd0e8SStephan Aßmus 
439eb2bd0e8SStephan Aßmus 	status_t status = request->Init(pos, vecs, count, numBytes, false,
440eb2bd0e8SStephan Aßmus 		flags | B_DELETE_IO_REQUEST);
441eb2bd0e8SStephan Aßmus 	if (status != B_OK) {
442eb2bd0e8SStephan Aßmus 		delete request;
443eb2bd0e8SStephan Aßmus 		callback->IOFinished(status, true, 0);
444eb2bd0e8SStephan Aßmus 		return status;
445eb2bd0e8SStephan Aßmus 	}
446eb2bd0e8SStephan Aßmus 
447eb2bd0e8SStephan Aßmus 	request->SetFinishedCallback(&AsyncIOCallback::IORequestCallback,
448eb2bd0e8SStephan Aßmus 		callback);
449eb2bd0e8SStephan Aßmus 
450eb2bd0e8SStephan Aßmus 	return vfs_vnode_io(vnode, cookie, request);
451eb2bd0e8SStephan Aßmus }
452eb2bd0e8SStephan Aßmus 
453eb2bd0e8SStephan Aßmus 
454eb2bd0e8SStephan Aßmus status_t
vfs_asynchronous_write_pages(struct vnode * vnode,void * cookie,off_t pos,const generic_io_vec * vecs,size_t count,generic_size_t numBytes,uint32 flags,AsyncIOCallback * callback)45566394896SIngo Weinhold vfs_asynchronous_write_pages(struct vnode* vnode, void* cookie, off_t pos,
4561d578e15SIngo Weinhold 	const generic_io_vec* vecs, size_t count, generic_size_t numBytes,
4571d578e15SIngo Weinhold 	uint32 flags, AsyncIOCallback* callback)
45866394896SIngo Weinhold {
45966394896SIngo Weinhold 	IORequest* request = IORequest::Create((flags & B_VIP_IO_REQUEST) != 0);
46066394896SIngo Weinhold 	if (request == NULL) {
46166394896SIngo Weinhold 		callback->IOFinished(B_NO_MEMORY, true, 0);
46266394896SIngo Weinhold 		return B_NO_MEMORY;
46366394896SIngo Weinhold 	}
46466394896SIngo Weinhold 
46566394896SIngo Weinhold 	status_t status = request->Init(pos, vecs, count, numBytes, true,
46666394896SIngo Weinhold 		flags | B_DELETE_IO_REQUEST);
46766394896SIngo Weinhold 	if (status != B_OK) {
46866394896SIngo Weinhold 		delete request;
46966394896SIngo Weinhold 		callback->IOFinished(status, true, 0);
47066394896SIngo Weinhold 		return status;
47166394896SIngo Weinhold 	}
47266394896SIngo Weinhold 
47366394896SIngo Weinhold 	request->SetFinishedCallback(&AsyncIOCallback::IORequestCallback,
47466394896SIngo Weinhold 		callback);
47566394896SIngo Weinhold 
47666394896SIngo Weinhold 	return vfs_vnode_io(vnode, cookie, request);
47766394896SIngo Weinhold }
47866394896SIngo Weinhold 
47966394896SIngo Weinhold 
480ec598fe4SIngo Weinhold // #pragma mark - public API
481ec598fe4SIngo Weinhold 
482ec598fe4SIngo Weinhold 
483cfae07b6SIngo Weinhold status_t
do_fd_io(int fd,io_request * request)484ec598fe4SIngo Weinhold do_fd_io(int fd, io_request* request)
485ec598fe4SIngo Weinhold {
486e829154fSAugustin Cavalier 	return do_iterative_fd_io(fd, request, NULL, NULL, NULL);
487ec598fe4SIngo Weinhold }
488ec598fe4SIngo Weinhold 
489ec598fe4SIngo Weinhold 
490cfae07b6SIngo Weinhold status_t
do_iterative_fd_io(int fd,io_request * request,iterative_io_get_vecs getVecs,iterative_io_finished finished,void * cookie)491ec598fe4SIngo Weinhold do_iterative_fd_io(int fd, io_request* request, iterative_io_get_vecs getVecs,
492ec598fe4SIngo Weinhold 	iterative_io_finished finished, void* cookie)
493ec598fe4SIngo Weinhold {
494935c5e82SIngo Weinhold 	TRACE_RIO("[%" B_PRId32 "] do_iterative_fd_io(fd: %d, request: %p "
495935c5e82SIngo Weinhold 		"(offset: %" B_PRIdOFF ", length: %" B_PRIuGENADDR "))\n",
496935c5e82SIngo Weinhold 		find_thread(NULL), fd, request, request->Offset(), request->Length());
4977f12cc54SIngo Weinhold 
498ec598fe4SIngo Weinhold 	struct vnode* vnode;
499ec598fe4SIngo Weinhold 	file_descriptor* descriptor = get_fd_and_vnode(fd, &vnode, true);
500ec598fe4SIngo Weinhold 	if (descriptor == NULL) {
501e829154fSAugustin Cavalier 		if (finished != NULL)
5027f12cc54SIngo Weinhold 			finished(cookie, request, B_FILE_ERROR, true, 0);
503ec598fe4SIngo Weinhold 		request->SetStatusAndNotify(B_FILE_ERROR);
504ec598fe4SIngo Weinhold 		return B_FILE_ERROR;
505ec598fe4SIngo Weinhold 	}
506ec598fe4SIngo Weinhold 
507fa766875SAugustin Cavalier 	FileDescriptorPutter descriptorPutter(descriptor);
508ec598fe4SIngo Weinhold 
509ec598fe4SIngo Weinhold 	if (!HAS_FS_CALL(vnode, io)) {
510ec598fe4SIngo Weinhold 		// no io() call -- fall back to synchronous I/O
511ec598fe4SIngo Weinhold 		return do_synchronous_iterative_vnode_io(vnode, descriptor->cookie,
512ec598fe4SIngo Weinhold 			request, getVecs, finished, cookie);
513ec598fe4SIngo Weinhold 	}
514ec598fe4SIngo Weinhold 
515ec598fe4SIngo Weinhold 	iterative_io_cookie* iterationCookie
51641417412SIngo Weinhold 		= (request->Flags() & B_VIP_IO_REQUEST) != 0
517deee8524SIngo Weinhold 			? new(malloc_flags(HEAP_PRIORITY_VIP)) iterative_io_cookie
51841417412SIngo Weinhold 			: new(std::nothrow) iterative_io_cookie;
519ec598fe4SIngo Weinhold 	if (iterationCookie == NULL) {
520ec598fe4SIngo Weinhold 		// no memory -- fall back to synchronous I/O
521ec598fe4SIngo Weinhold 		return do_synchronous_iterative_vnode_io(vnode, descriptor->cookie,
522ec598fe4SIngo Weinhold 			request, getVecs, finished, cookie);
523ec598fe4SIngo Weinhold 	}
524ec598fe4SIngo Weinhold 
525ec598fe4SIngo Weinhold 	iterationCookie->vnode = vnode;
526ec598fe4SIngo Weinhold 	iterationCookie->descriptor = descriptor;
527ec598fe4SIngo Weinhold 	iterationCookie->get_vecs = getVecs;
528ec598fe4SIngo Weinhold 	iterationCookie->finished = finished;
529ec598fe4SIngo Weinhold 	iterationCookie->cookie = cookie;
530ec598fe4SIngo Weinhold 	iterationCookie->request_offset = request->Offset();
531ec598fe4SIngo Weinhold 	iterationCookie->next_finished_callback = request->FinishedCallback(
532ec598fe4SIngo Weinhold 		&iterationCookie->next_finished_cookie);
533ec598fe4SIngo Weinhold 
534ec598fe4SIngo Weinhold 	request->SetFinishedCallback(&do_iterative_fd_io_finish, iterationCookie);
535e829154fSAugustin Cavalier 	if (getVecs != NULL)
536ec598fe4SIngo Weinhold 		request->SetIterationCallback(&do_iterative_fd_io_iterate, iterationCookie);
537ec598fe4SIngo Weinhold 
538be87a493SIngo Weinhold 	descriptorPutter.Detach();
539be87a493SIngo Weinhold 		// From now on the descriptor is put by our finish callback.
540be87a493SIngo Weinhold 
541e829154fSAugustin Cavalier 	if (getVecs != NULL) {
5427f12cc54SIngo Weinhold 		bool partialTransfer = false;
5437f12cc54SIngo Weinhold 		status_t error = do_iterative_fd_io_iterate(iterationCookie, request,
5447f12cc54SIngo Weinhold 			&partialTransfer);
5457f12cc54SIngo Weinhold 		if (error != B_OK || partialTransfer) {
5467f12cc54SIngo Weinhold 			if (partialTransfer) {
5477f12cc54SIngo Weinhold 				request->SetTransferredBytes(partialTransfer,
5487f12cc54SIngo Weinhold 					request->TransferredBytes());
5497f12cc54SIngo Weinhold 			}
5507f12cc54SIngo Weinhold 
551ec598fe4SIngo Weinhold 			request->SetStatusAndNotify(error);
552ec598fe4SIngo Weinhold 			return error;
553ec598fe4SIngo Weinhold 		}
554e829154fSAugustin Cavalier 	} else {
555e829154fSAugustin Cavalier 		return vfs_vnode_io(vnode, descriptor->cookie, request);
556e829154fSAugustin Cavalier 	}
557ec598fe4SIngo Weinhold 
558ec598fe4SIngo Weinhold 	return B_OK;
559ec598fe4SIngo Weinhold }
560