xref: /haiku/src/system/kernel/fs/vfs_request_io.cpp (revision e1ca73e1f1c7736a786e4a1dd152542ba9c07449)
1ec598fe4SIngo Weinhold /*
2ec598fe4SIngo Weinhold  * Copyright 2008, 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 
1766394896SIngo Weinhold // #pragma mark - AsyncIOCallback
1866394896SIngo Weinhold 
1966394896SIngo Weinhold 
2066394896SIngo Weinhold AsyncIOCallback::~AsyncIOCallback()
2166394896SIngo Weinhold {
2266394896SIngo Weinhold }
2366394896SIngo Weinhold 
2466394896SIngo Weinhold 
2566394896SIngo Weinhold void
2666394896SIngo Weinhold AsyncIOCallback::operator delete(void* address, size_t size)
2766394896SIngo Weinhold {
2866394896SIngo Weinhold 	io_request_free(address);
2966394896SIngo Weinhold }
3066394896SIngo Weinhold 
3166394896SIngo Weinhold 
3266394896SIngo Weinhold /* static */ status_t
3366394896SIngo Weinhold AsyncIOCallback::IORequestCallback(void* data, io_request* request,
3466394896SIngo Weinhold 	status_t status, bool partialTransfer, size_t transferEndOffset)
3566394896SIngo Weinhold {
3666394896SIngo Weinhold 	((AsyncIOCallback*)data)->IOFinished(status, partialTransfer,
3766394896SIngo Weinhold 		transferEndOffset);
3866394896SIngo Weinhold 	return B_OK;
3966394896SIngo Weinhold }
4066394896SIngo Weinhold 
4166394896SIngo Weinhold 
4266394896SIngo Weinhold // #pragma mark - StackableAsyncIOCallback
4366394896SIngo Weinhold 
4466394896SIngo Weinhold 
4566394896SIngo Weinhold StackableAsyncIOCallback::StackableAsyncIOCallback(AsyncIOCallback* next)
4666394896SIngo Weinhold 	:
4766394896SIngo Weinhold 	fNextCallback(next)
4866394896SIngo Weinhold {
4966394896SIngo Weinhold }
5066394896SIngo Weinhold 
5166394896SIngo Weinhold 
5266394896SIngo Weinhold // #pragma mark -
5366394896SIngo Weinhold 
5466394896SIngo Weinhold 
55ec598fe4SIngo Weinhold struct iterative_io_cookie {
56ec598fe4SIngo Weinhold 	struct vnode*					vnode;
57ec598fe4SIngo Weinhold 	file_descriptor*				descriptor;
58ec598fe4SIngo Weinhold 	iterative_io_get_vecs			get_vecs;
59ec598fe4SIngo Weinhold 	iterative_io_finished			finished;
60ec598fe4SIngo Weinhold 	void*							cookie;
61ec598fe4SIngo Weinhold 	off_t							request_offset;
62ec598fe4SIngo Weinhold 	io_request_finished_callback	next_finished_callback;
63ec598fe4SIngo Weinhold 	void*							next_finished_cookie;
6441417412SIngo Weinhold 
6541417412SIngo Weinhold 	void operator delete(void* address, size_t size)
6641417412SIngo Weinhold 		{ io_request_free(address); }
67ec598fe4SIngo Weinhold };
68ec598fe4SIngo Weinhold 
69ec598fe4SIngo Weinhold 
70ec598fe4SIngo Weinhold class DoIO {
71ec598fe4SIngo Weinhold public:
72ec598fe4SIngo Weinhold 	DoIO(bool write, bool isPhysical)
73ec598fe4SIngo Weinhold 		:
74ec598fe4SIngo Weinhold 		fWrite(write),
75ec598fe4SIngo Weinhold 		fIsPhysical(isPhysical)
76ec598fe4SIngo Weinhold 	{
77ec598fe4SIngo Weinhold 	}
78ec598fe4SIngo Weinhold 
79ec598fe4SIngo Weinhold 	virtual	~DoIO()
80ec598fe4SIngo Weinhold 	{
81ec598fe4SIngo Weinhold 	}
82ec598fe4SIngo Weinhold 
837f12cc54SIngo Weinhold 	status_t IO(off_t offset, void* _buffer, size_t* _length)
84ec598fe4SIngo Weinhold 	{
85ec598fe4SIngo Weinhold 		if (!fIsPhysical)
867f12cc54SIngo Weinhold 			return InternalIO(offset, _buffer, _length);
87ec598fe4SIngo Weinhold 
88ec598fe4SIngo Weinhold 		// buffer points to physical address -- map pages
89ec598fe4SIngo Weinhold 		addr_t buffer = (addr_t)_buffer;
907f12cc54SIngo Weinhold 		size_t length = *_length;
91ec598fe4SIngo Weinhold 
92ec598fe4SIngo Weinhold 		while (length > 0) {
93ec598fe4SIngo Weinhold 			addr_t pageOffset = buffer % B_PAGE_SIZE;
94ec598fe4SIngo Weinhold 			addr_t virtualAddress;
95ec598fe4SIngo Weinhold 			status_t error = vm_get_physical_page(buffer - pageOffset,
96ec598fe4SIngo Weinhold 				&virtualAddress, 0);
97ec598fe4SIngo Weinhold 			if (error != B_OK)
98ec598fe4SIngo Weinhold 				return error;
99ec598fe4SIngo Weinhold 
100ec598fe4SIngo Weinhold 			size_t toTransfer = min_c(length, B_PAGE_SIZE - pageOffset);
1017f12cc54SIngo Weinhold 			size_t transferred = toTransfer;
102ec598fe4SIngo Weinhold 			error = InternalIO(offset, (void*)(virtualAddress + pageOffset),
1037f12cc54SIngo Weinhold 				&transferred);
104ec598fe4SIngo Weinhold 
105ec598fe4SIngo Weinhold 			vm_put_physical_page(virtualAddress);
106ec598fe4SIngo Weinhold 
107ec598fe4SIngo Weinhold 			if (error != B_OK)
108ec598fe4SIngo Weinhold 				return error;
109ec598fe4SIngo Weinhold 
1107f12cc54SIngo Weinhold 			offset += transferred;
1117f12cc54SIngo Weinhold 			buffer += transferred;
1127f12cc54SIngo Weinhold 			length -= transferred;
1137f12cc54SIngo Weinhold 
1147f12cc54SIngo Weinhold 			if (transferred != toTransfer)
1157f12cc54SIngo Weinhold 				break;
116ec598fe4SIngo Weinhold 		}
117ec598fe4SIngo Weinhold 
1187f12cc54SIngo Weinhold 		*_length -= length;
119ec598fe4SIngo Weinhold 		return B_OK;
120ec598fe4SIngo Weinhold 	}
121ec598fe4SIngo Weinhold 
122ec598fe4SIngo Weinhold protected:
1237f12cc54SIngo Weinhold 	virtual status_t InternalIO(off_t offset, void* buffer, size_t* length) = 0;
124ec598fe4SIngo Weinhold 
125ec598fe4SIngo Weinhold protected:
126ec598fe4SIngo Weinhold 	bool	fWrite;
127ec598fe4SIngo Weinhold 	bool	fIsPhysical;
128ec598fe4SIngo Weinhold };
129ec598fe4SIngo Weinhold 
130ec598fe4SIngo Weinhold 
131ec598fe4SIngo Weinhold class CallbackIO : public DoIO {
132ec598fe4SIngo Weinhold public:
133ec598fe4SIngo Weinhold 	CallbackIO(bool write, bool isPhysical,
134ec598fe4SIngo Weinhold 			status_t (*doIO)(void* cookie, off_t offset, void* buffer,
1357f12cc54SIngo Weinhold 				size_t* length),
136ec598fe4SIngo Weinhold 			void* cookie)
137ec598fe4SIngo Weinhold 		:
138ec598fe4SIngo Weinhold 		DoIO(write, isPhysical),
139ec598fe4SIngo Weinhold 		fDoIO(doIO),
140ec598fe4SIngo Weinhold 		fCookie(cookie)
141ec598fe4SIngo Weinhold 	{
142ec598fe4SIngo Weinhold 	}
143ec598fe4SIngo Weinhold 
144ec598fe4SIngo Weinhold protected:
1457f12cc54SIngo Weinhold 	virtual status_t InternalIO(off_t offset, void* buffer, size_t* length)
146ec598fe4SIngo Weinhold 	{
147ec598fe4SIngo Weinhold 		return fDoIO(fCookie, offset, buffer, length);
148ec598fe4SIngo Weinhold 	}
149ec598fe4SIngo Weinhold 
150ec598fe4SIngo Weinhold private:
1517f12cc54SIngo Weinhold 	status_t (*fDoIO)(void*, off_t, void*, size_t*);
152ec598fe4SIngo Weinhold 	void*		fCookie;
153ec598fe4SIngo Weinhold };
154ec598fe4SIngo Weinhold 
155ec598fe4SIngo Weinhold 
156ec598fe4SIngo Weinhold class VnodeIO : public DoIO {
157ec598fe4SIngo Weinhold public:
158ec598fe4SIngo Weinhold 	VnodeIO(bool write, bool isPhysical, struct vnode* vnode, void* cookie)
159ec598fe4SIngo Weinhold 		:
160ec598fe4SIngo Weinhold 		DoIO(write, isPhysical),
161ec598fe4SIngo Weinhold 		fVnode(vnode),
162ec598fe4SIngo Weinhold 		fCookie(cookie)
163ec598fe4SIngo Weinhold 	{
164ec598fe4SIngo Weinhold 	}
165ec598fe4SIngo Weinhold 
166ec598fe4SIngo Weinhold protected:
1677f12cc54SIngo Weinhold 	virtual status_t InternalIO(off_t offset, void* buffer, size_t* length)
168ec598fe4SIngo Weinhold 	{
1697a253cf5SAxel Dörfler 		iovec vec;
1707a253cf5SAxel Dörfler 		vec.iov_base = buffer;
1717a253cf5SAxel Dörfler 		vec.iov_len = *length;
172ec598fe4SIngo Weinhold 
1737a253cf5SAxel Dörfler 		if (fWrite) {
1747a253cf5SAxel Dörfler 			return FS_CALL(fVnode, write_pages, fCookie, offset, &vec, 1,
1757a253cf5SAxel Dörfler 				length);
1767a253cf5SAxel Dörfler 		}
1777a253cf5SAxel Dörfler 
1787a253cf5SAxel Dörfler 		return FS_CALL(fVnode, read_pages, fCookie, offset, &vec, 1, length);
179ec598fe4SIngo Weinhold 	}
180ec598fe4SIngo Weinhold 
181ec598fe4SIngo Weinhold private:
182ec598fe4SIngo Weinhold 	struct vnode*	fVnode;
183ec598fe4SIngo Weinhold 	void*			fCookie;
184ec598fe4SIngo Weinhold };
185ec598fe4SIngo Weinhold 
186ec598fe4SIngo Weinhold 
187ec598fe4SIngo Weinhold static status_t
1887f12cc54SIngo Weinhold do_iterative_fd_io_iterate(void* _cookie, io_request* request,
1897f12cc54SIngo Weinhold 	bool* _partialTransfer)
190ec598fe4SIngo Weinhold {
1917f12cc54SIngo Weinhold 	TRACE_RIO("[%ld] do_iterative_fd_io_iterate(request: %p)\n",
1927f12cc54SIngo Weinhold 		find_thread(NULL), request);
1937f12cc54SIngo Weinhold 
194ec598fe4SIngo Weinhold 	static const int32 kMaxSubRequests = 8;
195ec598fe4SIngo Weinhold 
196ec598fe4SIngo Weinhold 	iterative_io_cookie* cookie = (iterative_io_cookie*)_cookie;
197ec598fe4SIngo Weinhold 
198ec598fe4SIngo Weinhold 	request->DeleteSubRequests();
199ec598fe4SIngo Weinhold 
200ec598fe4SIngo Weinhold 	off_t requestOffset = cookie->request_offset;
201ec598fe4SIngo Weinhold 	size_t requestLength = request->Length()
202ec598fe4SIngo Weinhold 		- (requestOffset - request->Offset());
203ec598fe4SIngo Weinhold 
204ec598fe4SIngo Weinhold 	// get the next file vecs
205ec598fe4SIngo Weinhold 	file_io_vec vecs[kMaxSubRequests];
206ec598fe4SIngo Weinhold 	uint32 vecCount = kMaxSubRequests;
207ec598fe4SIngo Weinhold 	status_t error = cookie->get_vecs(cookie->cookie, request, requestOffset,
208ec598fe4SIngo Weinhold 		requestLength, vecs, &vecCount);
209*e1ca73e1SAxel Dörfler 	if (error != B_OK && error != B_BUFFER_OVERFLOW)
210ec598fe4SIngo Weinhold 		return error;
2117f12cc54SIngo Weinhold 	if (vecCount == 0) {
2127f12cc54SIngo Weinhold 		*_partialTransfer = true;
2137f12cc54SIngo Weinhold 		return B_OK;
2147f12cc54SIngo Weinhold 	}
2157f12cc54SIngo Weinhold 	TRACE_RIO("[%ld]  got %lu file vecs\n", find_thread(NULL), vecCount);
216ec598fe4SIngo Weinhold 
217ec598fe4SIngo Weinhold 	// create subrequests for the file vecs we've got
218ec598fe4SIngo Weinhold 	int32 subRequestCount = 0;
219ec598fe4SIngo Weinhold 	for (uint32 i = 0; i < vecCount && subRequestCount < kMaxSubRequests; i++) {
220ec598fe4SIngo Weinhold 		off_t vecOffset = vecs[i].offset;
2217f12cc54SIngo Weinhold 		off_t vecLength = min_c(vecs[i].length, requestLength);
2227f12cc54SIngo Weinhold 		TRACE_RIO("[%ld]    vec %lu offset: %lld, length: %lld\n",
2237f12cc54SIngo Weinhold 			find_thread(NULL), i, vecOffset, vecLength);
224ec598fe4SIngo Weinhold 
225ec598fe4SIngo Weinhold 		while (vecLength > 0 && subRequestCount < kMaxSubRequests) {
2267f12cc54SIngo Weinhold 			TRACE_RIO("[%ld]    creating subrequest: offset: %lld, length: "
2277f12cc54SIngo Weinhold 				"%lld\n", find_thread(NULL), vecOffset, vecLength);
228ec598fe4SIngo Weinhold 			IORequest* subRequest;
229ec598fe4SIngo Weinhold 			error = request->CreateSubRequest(requestOffset, vecOffset,
230ec598fe4SIngo Weinhold 				vecLength, subRequest);
231ec598fe4SIngo Weinhold 			if (error != B_OK)
232ec598fe4SIngo Weinhold 				break;
233ec598fe4SIngo Weinhold 
234ec598fe4SIngo Weinhold 			subRequestCount++;
235ec598fe4SIngo Weinhold 
236ec598fe4SIngo Weinhold 			size_t lengthProcessed = subRequest->Length();
237ec598fe4SIngo Weinhold 			vecOffset += lengthProcessed;
238ec598fe4SIngo Weinhold 			vecLength -= lengthProcessed;
239ec598fe4SIngo Weinhold 			requestOffset += lengthProcessed;
240ec598fe4SIngo Weinhold 			requestLength -= lengthProcessed;
241ec598fe4SIngo Weinhold 		}
242ec598fe4SIngo Weinhold 	}
243ec598fe4SIngo Weinhold 
244ec598fe4SIngo Weinhold 	// Only if we couldn't create any subrequests, we fail.
245ec598fe4SIngo Weinhold 	if (error != B_OK && subRequestCount == 0)
246ec598fe4SIngo Weinhold 		return error;
247ec598fe4SIngo Weinhold 
248ec598fe4SIngo Weinhold 	request->Advance(requestOffset - cookie->request_offset);
249ec598fe4SIngo Weinhold 	cookie->request_offset = requestOffset;
250ec598fe4SIngo Weinhold 
251ec598fe4SIngo Weinhold 	// Schedule the subrequests.
2527f12cc54SIngo Weinhold 	IORequest* nextSubRequest = request->FirstSubRequest();
2537f12cc54SIngo Weinhold 	while (nextSubRequest != NULL) {
2547f12cc54SIngo Weinhold 		IORequest* subRequest = nextSubRequest;
2557f12cc54SIngo Weinhold 		nextSubRequest = request->NextSubRequest(subRequest);
2567f12cc54SIngo Weinhold 
257ec598fe4SIngo Weinhold 		if (error == B_OK) {
2587f12cc54SIngo Weinhold 			TRACE_RIO("[%ld]  scheduling subrequest: %p\n", find_thread(NULL),
2597f12cc54SIngo Weinhold 				subRequest);
2605054db18SIngo Weinhold 			error = vfs_vnode_io(cookie->vnode, cookie->descriptor->cookie,
261ec598fe4SIngo Weinhold 				subRequest);
262ec598fe4SIngo Weinhold 		} else {
263ec598fe4SIngo Weinhold 			// Once scheduling a subrequest failed, we cancel all subsequent
264ec598fe4SIngo Weinhold 			// subrequests.
265ec598fe4SIngo Weinhold 			subRequest->SetStatusAndNotify(B_CANCELED);
266ec598fe4SIngo Weinhold 		}
267ec598fe4SIngo Weinhold 	}
268ec598fe4SIngo Weinhold 
269ec598fe4SIngo Weinhold 	// TODO: Cancel the subrequests that were scheduled successfully.
270ec598fe4SIngo Weinhold 
271ec598fe4SIngo Weinhold 	return B_OK;
272ec598fe4SIngo Weinhold }
273ec598fe4SIngo Weinhold 
274ec598fe4SIngo Weinhold 
275ec598fe4SIngo Weinhold static status_t
2767f12cc54SIngo Weinhold do_iterative_fd_io_finish(void* _cookie, io_request* request, status_t status,
2777f12cc54SIngo Weinhold 	bool partialTransfer, size_t transferEndOffset)
278ec598fe4SIngo Weinhold {
279ec598fe4SIngo Weinhold 	iterative_io_cookie* cookie = (iterative_io_cookie*)_cookie;
280ec598fe4SIngo Weinhold 
2817f12cc54SIngo Weinhold 	if (cookie->finished != NULL) {
2827f12cc54SIngo Weinhold 		cookie->finished(cookie->cookie, request, status, partialTransfer,
2837f12cc54SIngo Weinhold 			transferEndOffset);
2847f12cc54SIngo Weinhold 	}
285ec598fe4SIngo Weinhold 
286ec598fe4SIngo Weinhold 	put_fd(cookie->descriptor);
287ec598fe4SIngo Weinhold 
288ec598fe4SIngo Weinhold 	if (cookie->next_finished_callback != NULL) {
289ec598fe4SIngo Weinhold 		cookie->next_finished_callback(cookie->next_finished_cookie, request,
2907f12cc54SIngo Weinhold 			status, partialTransfer, transferEndOffset);
291ec598fe4SIngo Weinhold 	}
292ec598fe4SIngo Weinhold 
293ec598fe4SIngo Weinhold 	delete cookie;
294ec598fe4SIngo Weinhold 
295ec598fe4SIngo Weinhold 	return B_OK;
296ec598fe4SIngo Weinhold }
297ec598fe4SIngo Weinhold 
298ec598fe4SIngo Weinhold 
299ec598fe4SIngo Weinhold static status_t
300ec598fe4SIngo Weinhold do_synchronous_iterative_vnode_io(struct vnode* vnode, void* openCookie,
301ec598fe4SIngo Weinhold 	io_request* request, iterative_io_get_vecs getVecs,
302ec598fe4SIngo Weinhold 	iterative_io_finished finished, void* cookie)
303ec598fe4SIngo Weinhold {
304ec598fe4SIngo Weinhold 	IOBuffer* buffer = request->Buffer();
305ec598fe4SIngo Weinhold 	VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, openCookie);
306ec598fe4SIngo Weinhold 
307ec598fe4SIngo Weinhold 	iovec* vecs = buffer->Vecs();
308ec598fe4SIngo Weinhold 	int32 vecCount = buffer->VecCount();
309ec598fe4SIngo Weinhold 	off_t offset = request->Offset();
310ec598fe4SIngo Weinhold 	size_t length = request->Length();
311ec598fe4SIngo Weinhold 
312ec598fe4SIngo Weinhold 	status_t error = B_OK;
313ec598fe4SIngo Weinhold 
314ec598fe4SIngo Weinhold 	for (int32 i = 0; error == B_OK && length > 0 && i < vecCount; i++) {
315ec598fe4SIngo Weinhold 		uint8* vecBase = (uint8*)vecs[i].iov_base;
3167f12cc54SIngo Weinhold 		size_t vecLength = min_c(vecs[i].iov_len, length);
317ec598fe4SIngo Weinhold 
318ec598fe4SIngo Weinhold 		while (error == B_OK && vecLength > 0) {
319ec598fe4SIngo Weinhold 			file_io_vec fileVecs[8];
320ec598fe4SIngo Weinhold 			uint32 fileVecCount = 8;
321ec598fe4SIngo Weinhold 			error = getVecs(cookie, request, offset, vecLength, fileVecs,
322ec598fe4SIngo Weinhold 				&fileVecCount);
3237f12cc54SIngo Weinhold 			if (error != B_OK || fileVecCount == 0)
324ec598fe4SIngo Weinhold 				break;
325ec598fe4SIngo Weinhold 
326ec598fe4SIngo Weinhold 			for (uint32 k = 0; k < fileVecCount; k++) {
327ec598fe4SIngo Weinhold 				const file_io_vec& fileVec = fileVecs[i];
3287f12cc54SIngo Weinhold 				size_t toTransfer = min_c(fileVec.length, length);
3297f12cc54SIngo Weinhold 				size_t transferred = toTransfer;
3307f12cc54SIngo Weinhold 				error = io.IO(fileVec.offset, vecBase, &transferred);
331ec598fe4SIngo Weinhold 				if (error != B_OK)
332ec598fe4SIngo Weinhold 					break;
333ec598fe4SIngo Weinhold 
3347f12cc54SIngo Weinhold 				offset += transferred;
3357f12cc54SIngo Weinhold 				length -= transferred;
3367f12cc54SIngo Weinhold 				vecBase += transferred;
3377f12cc54SIngo Weinhold 				vecLength -= transferred;
3387f12cc54SIngo Weinhold 
3397f12cc54SIngo Weinhold 				if (transferred != toTransfer)
3407f12cc54SIngo Weinhold 					break;
341ec598fe4SIngo Weinhold 			}
342ec598fe4SIngo Weinhold 		}
343ec598fe4SIngo Weinhold 	}
344ec598fe4SIngo Weinhold 
3457f12cc54SIngo Weinhold 	bool partial = length > 0;
3467f12cc54SIngo Weinhold 	size_t bytesTransferred = request->Length() - length;
3477f12cc54SIngo Weinhold 	request->SetTransferredBytes(partial, bytesTransferred);
3487f12cc54SIngo Weinhold 	finished(cookie, request, error, partial, bytesTransferred);
349ec598fe4SIngo Weinhold 	request->SetStatusAndNotify(error);
350ec598fe4SIngo Weinhold 	return error;
351ec598fe4SIngo Weinhold }
352ec598fe4SIngo Weinhold 
353ec598fe4SIngo Weinhold 
354ec598fe4SIngo Weinhold static status_t
355ec598fe4SIngo Weinhold synchronous_io(io_request* request, DoIO& io)
356ec598fe4SIngo Weinhold {
3577f12cc54SIngo Weinhold 	TRACE_RIO("[%ld] synchronous_io(request: %p (offset: %lld, length: %lu))\n",
3587f12cc54SIngo Weinhold 		find_thread(NULL), request, request->Offset(), request->Length());
3597f12cc54SIngo Weinhold 
360ec598fe4SIngo Weinhold 	IOBuffer* buffer = request->Buffer();
361ec598fe4SIngo Weinhold 
362ec598fe4SIngo Weinhold 	iovec* vecs = buffer->Vecs();
363ec598fe4SIngo Weinhold 	int32 vecCount = buffer->VecCount();
364ec598fe4SIngo Weinhold 	off_t offset = request->Offset();
365ec598fe4SIngo Weinhold 	size_t length = request->Length();
366ec598fe4SIngo Weinhold 
367ec598fe4SIngo Weinhold 	for (int32 i = 0; length > 0 && i < vecCount; i++) {
368ec598fe4SIngo Weinhold 		void* vecBase = vecs[i].iov_base;
3697f12cc54SIngo Weinhold 		size_t vecLength = min_c(vecs[i].iov_len, length);
370ec598fe4SIngo Weinhold 
3717f12cc54SIngo Weinhold 		TRACE_RIO("[%ld]   I/O: offset: %lld, vecBase: %p, length: %lu\n",
3727f12cc54SIngo Weinhold 			find_thread(NULL), offset, vecBase, vecLength);
3737f12cc54SIngo Weinhold 
3747f12cc54SIngo Weinhold 		size_t transferred = vecLength;
3757f12cc54SIngo Weinhold 		status_t error = io.IO(offset, vecBase, &transferred);
376ec598fe4SIngo Weinhold 		if (error != B_OK) {
3777f12cc54SIngo Weinhold 			TRACE_RIO("[%ld]   I/O failed: %#lx\n", find_thread(NULL), error);
378ec598fe4SIngo Weinhold 			request->SetStatusAndNotify(error);
379ec598fe4SIngo Weinhold 			return error;
380ec598fe4SIngo Weinhold 		}
381ec598fe4SIngo Weinhold 
3827f12cc54SIngo Weinhold 		offset += transferred;
3837f12cc54SIngo Weinhold 		length -= transferred;
3847f12cc54SIngo Weinhold 
3855054db18SIngo Weinhold 		if (transferred != vecLength)
3867f12cc54SIngo Weinhold 			break;
387ec598fe4SIngo Weinhold 	}
388ec598fe4SIngo Weinhold 
3897f12cc54SIngo Weinhold 	TRACE_RIO("[%ld] synchronous_io() succeeded\n", find_thread(NULL));
3907f12cc54SIngo Weinhold 
3917f12cc54SIngo Weinhold 	request->SetTransferredBytes(length > 0, request->Length() - length);
392ec598fe4SIngo Weinhold 	request->SetStatusAndNotify(B_OK);
393ec598fe4SIngo Weinhold 	return B_OK;
394ec598fe4SIngo Weinhold }
395ec598fe4SIngo Weinhold 
396ec598fe4SIngo Weinhold 
397ec598fe4SIngo Weinhold // #pragma mark - kernel private API
398ec598fe4SIngo Weinhold 
399ec598fe4SIngo Weinhold 
400cfae07b6SIngo Weinhold status_t
401cfae07b6SIngo Weinhold vfs_vnode_io(struct vnode* vnode, void* cookie, io_request* request)
402cfae07b6SIngo Weinhold {
403cfae07b6SIngo Weinhold 	if (!HAS_FS_CALL(vnode, io)) {
404cfae07b6SIngo Weinhold 		// no io() call -- fall back to synchronous I/O
405cfae07b6SIngo Weinhold 		IOBuffer* buffer = request->Buffer();
406cfae07b6SIngo Weinhold 		VnodeIO io(request->IsWrite(), buffer->IsPhysical(), vnode, cookie);
407cfae07b6SIngo Weinhold 		return synchronous_io(request, io);
408cfae07b6SIngo Weinhold 	}
409cfae07b6SIngo Weinhold 
410cfae07b6SIngo Weinhold 	return FS_CALL(vnode, io, cookie, request);
411cfae07b6SIngo Weinhold }
412cfae07b6SIngo Weinhold 
413cfae07b6SIngo Weinhold 
414cfae07b6SIngo Weinhold status_t
415ec598fe4SIngo Weinhold vfs_synchronous_io(io_request* request,
4167f12cc54SIngo Weinhold 	status_t (*doIO)(void* cookie, off_t offset, void* buffer, size_t* length),
417ec598fe4SIngo Weinhold 	void* cookie)
418ec598fe4SIngo Weinhold {
419ec598fe4SIngo Weinhold 	IOBuffer* buffer = request->Buffer();
420ec598fe4SIngo Weinhold 	CallbackIO io(request->IsWrite(), buffer->IsPhysical(), doIO, cookie);
421ec598fe4SIngo Weinhold 
422ec598fe4SIngo Weinhold 	return synchronous_io(request, io);
423ec598fe4SIngo Weinhold }
424ec598fe4SIngo Weinhold 
425ec598fe4SIngo Weinhold 
42666394896SIngo Weinhold status_t
42766394896SIngo Weinhold vfs_asynchronous_write_pages(struct vnode* vnode, void* cookie, off_t pos,
42866394896SIngo Weinhold 	const iovec* vecs, size_t count, size_t numBytes, uint32 flags,
42966394896SIngo Weinhold 	AsyncIOCallback* callback)
43066394896SIngo Weinhold {
43166394896SIngo Weinhold 	IORequest* request = IORequest::Create((flags & B_VIP_IO_REQUEST) != 0);
43266394896SIngo Weinhold 	if (request == NULL) {
43366394896SIngo Weinhold 		callback->IOFinished(B_NO_MEMORY, true, 0);
43466394896SIngo Weinhold 		return B_NO_MEMORY;
43566394896SIngo Weinhold 	}
43666394896SIngo Weinhold 
43766394896SIngo Weinhold 	status_t status = request->Init(pos, vecs, count, numBytes, true,
43866394896SIngo Weinhold 		flags | B_DELETE_IO_REQUEST);
43966394896SIngo Weinhold 	if (status != B_OK) {
44066394896SIngo Weinhold 		delete request;
44166394896SIngo Weinhold 		callback->IOFinished(status, true, 0);
44266394896SIngo Weinhold 		return status;
44366394896SIngo Weinhold 	}
44466394896SIngo Weinhold 
44566394896SIngo Weinhold 	request->SetFinishedCallback(&AsyncIOCallback::IORequestCallback,
44666394896SIngo Weinhold 		callback);
44766394896SIngo Weinhold 
44866394896SIngo Weinhold 	return vfs_vnode_io(vnode, cookie, request);
44966394896SIngo Weinhold }
45066394896SIngo Weinhold 
45166394896SIngo Weinhold 
452ec598fe4SIngo Weinhold // #pragma mark - public API
453ec598fe4SIngo Weinhold 
454ec598fe4SIngo Weinhold 
455cfae07b6SIngo Weinhold status_t
456ec598fe4SIngo Weinhold do_fd_io(int fd, io_request* request)
457ec598fe4SIngo Weinhold {
458ec598fe4SIngo Weinhold 	struct vnode* vnode;
459ec598fe4SIngo Weinhold 	file_descriptor* descriptor = get_fd_and_vnode(fd, &vnode, true);
460ec598fe4SIngo Weinhold 	if (descriptor == NULL) {
461ec598fe4SIngo Weinhold 		request->SetStatusAndNotify(B_FILE_ERROR);
462ec598fe4SIngo Weinhold 		return B_FILE_ERROR;
463ec598fe4SIngo Weinhold 	}
464ec598fe4SIngo Weinhold 
465ec598fe4SIngo Weinhold 	CObjectDeleter<file_descriptor> descriptorPutter(descriptor, put_fd);
466ec598fe4SIngo Weinhold 
467cfae07b6SIngo Weinhold 	return vfs_vnode_io(vnode, descriptor->cookie, request);
468ec598fe4SIngo Weinhold }
469ec598fe4SIngo Weinhold 
470ec598fe4SIngo Weinhold 
471cfae07b6SIngo Weinhold status_t
472ec598fe4SIngo Weinhold do_iterative_fd_io(int fd, io_request* request, iterative_io_get_vecs getVecs,
473ec598fe4SIngo Weinhold 	iterative_io_finished finished, void* cookie)
474ec598fe4SIngo Weinhold {
4757f12cc54SIngo Weinhold 	TRACE_RIO("[%ld] do_iterative_fd_io(fd: %d, request: %p (offset: %lld, "
4767f12cc54SIngo Weinhold 		"length: %ld))\n", find_thread(NULL), fd, request, request->Offset(),
4777f12cc54SIngo Weinhold 		request->Length());
4787f12cc54SIngo Weinhold 
479ec598fe4SIngo Weinhold 	struct vnode* vnode;
480ec598fe4SIngo Weinhold 	file_descriptor* descriptor = get_fd_and_vnode(fd, &vnode, true);
481ec598fe4SIngo Weinhold 	if (descriptor == NULL) {
4827f12cc54SIngo Weinhold 		finished(cookie, request, B_FILE_ERROR, true, 0);
483ec598fe4SIngo Weinhold 		request->SetStatusAndNotify(B_FILE_ERROR);
484ec598fe4SIngo Weinhold 		return B_FILE_ERROR;
485ec598fe4SIngo Weinhold 	}
486ec598fe4SIngo Weinhold 
487ec598fe4SIngo Weinhold 	CObjectDeleter<file_descriptor> descriptorPutter(descriptor, put_fd);
488ec598fe4SIngo Weinhold 
489ec598fe4SIngo Weinhold 	if (!HAS_FS_CALL(vnode, io)) {
490ec598fe4SIngo Weinhold 		// no io() call -- fall back to synchronous I/O
491ec598fe4SIngo Weinhold 		return do_synchronous_iterative_vnode_io(vnode, descriptor->cookie,
492ec598fe4SIngo Weinhold 			request, getVecs, finished, cookie);
493ec598fe4SIngo Weinhold 	}
494ec598fe4SIngo Weinhold 
495ec598fe4SIngo Weinhold 	iterative_io_cookie* iterationCookie
49641417412SIngo Weinhold 		= (request->Flags() & B_VIP_IO_REQUEST) != 0
49741417412SIngo Weinhold 			? new(vip_io_alloc) iterative_io_cookie
49841417412SIngo Weinhold 			: new(std::nothrow) iterative_io_cookie;
499ec598fe4SIngo Weinhold 	if (iterationCookie == NULL) {
500ec598fe4SIngo Weinhold 		// no memory -- fall back to synchronous I/O
501ec598fe4SIngo Weinhold 		return do_synchronous_iterative_vnode_io(vnode, descriptor->cookie,
502ec598fe4SIngo Weinhold 			request, getVecs, finished, cookie);
503ec598fe4SIngo Weinhold 	}
504ec598fe4SIngo Weinhold 
505ec598fe4SIngo Weinhold 	iterationCookie->vnode = vnode;
506ec598fe4SIngo Weinhold 	iterationCookie->descriptor = descriptor;
507ec598fe4SIngo Weinhold 	iterationCookie->get_vecs = getVecs;
508ec598fe4SIngo Weinhold 	iterationCookie->finished = finished;
509ec598fe4SIngo Weinhold 	iterationCookie->cookie = cookie;
510ec598fe4SIngo Weinhold 	iterationCookie->request_offset = request->Offset();
511ec598fe4SIngo Weinhold 	iterationCookie->next_finished_callback = request->FinishedCallback(
512ec598fe4SIngo Weinhold 		&iterationCookie->next_finished_cookie);
513ec598fe4SIngo Weinhold 
514ec598fe4SIngo Weinhold 	request->SetFinishedCallback(&do_iterative_fd_io_finish, iterationCookie);
515ec598fe4SIngo Weinhold 	request->SetIterationCallback(&do_iterative_fd_io_iterate, iterationCookie);
516ec598fe4SIngo Weinhold 
517be87a493SIngo Weinhold 	descriptorPutter.Detach();
518be87a493SIngo Weinhold 		// From now on the descriptor is put by our finish callback.
519be87a493SIngo Weinhold 
5207f12cc54SIngo Weinhold 	bool partialTransfer = false;
5217f12cc54SIngo Weinhold 	status_t error = do_iterative_fd_io_iterate(iterationCookie, request,
5227f12cc54SIngo Weinhold 		&partialTransfer);
5237f12cc54SIngo Weinhold 	if (error != B_OK || partialTransfer) {
5247f12cc54SIngo Weinhold 		if (partialTransfer) {
5257f12cc54SIngo Weinhold 			request->SetTransferredBytes(partialTransfer,
5267f12cc54SIngo Weinhold 				request->TransferredBytes());
5277f12cc54SIngo Weinhold 		}
5287f12cc54SIngo Weinhold 
529ec598fe4SIngo Weinhold 		request->SetStatusAndNotify(error);
530ec598fe4SIngo Weinhold 		return error;
531ec598fe4SIngo Weinhold 	}
532ec598fe4SIngo Weinhold 
533ec598fe4SIngo Weinhold 	return B_OK;
534ec598fe4SIngo Weinhold }
535