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