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