diff options
author | bbudge@chromium.org <bbudge@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-28 17:54:27 +0000 |
---|---|---|
committer | bbudge@chromium.org <bbudge@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-28 17:54:27 +0000 |
commit | 7a90b856e3b08d2386750640d938d27773c08a94 (patch) | |
tree | aac5f475aba781ad4b5653f6543e1f0d81437dfd /content/browser/renderer_host | |
parent | 012a53cdbf8550a781776acf17953e4010df3be8 (diff) | |
download | chromium_src-7a90b856e3b08d2386750640d938d27773c08a94.zip chromium_src-7a90b856e3b08d2386750640d938d27773c08a94.tar.gz chromium_src-7a90b856e3b08d2386750640d938d27773c08a94.tar.bz2 |
Do PPB_FileIO Write on the plugin side.
This eliminates IPC for FileIO.Write, instead using the plugin's file descriptor.
Performs the file op on the plugin's thread if blocking, otherwise on the file
thread.
FileIOResources know their maximum written offset after they are opened.
They can thus calculate whether a Write or SetLength operation will extend
this max offset. If so, they call FileSystemResource::RequestQuota. This can
return synchronously or asynchronously, and either returns the requested
amount or 0 in case it can't be satisfied.
FileSystemResource will request a quota reservation from the host, queuing
up unsatisfied requests. The quota reservation will be at least 1MB with this
CL. The main point of a quota reservation is to reduce the number of times
we query the quota system.
Both the FileSystemResource and the host maintain a collection of open files
that are subject to quota. These are kept in sync. Maps that take PP_Resource
to resource or host are used to ensure good performance and make it easier
to keep the resource and host collections synced.
SetLength uses the plugin side machinery to request quota. When its request
is granted, it calls over to the host side as before. This is because of OS X
sandbox restrictions.
For trusted plugins, I assume that this plugin / host checking is sufficient. In
particular, SetLength is performed in the browser process without checking
the length against quota restrictions. We're essentially assuming trusted
plugins don't cheat.
For untrusted plugins, this approach isn't sufficient. NaClMessageScanner
audits the FIleSystem and FileIO message traffic to maintain a parallel
accounting of quota reservation and current file sizes. In addition, we wrap
the native file handle in a NaClDescQuota for files that need quota checking.
This NaClDescQuota uses NaClMessageScanner information to determine
whether or not to allow a Write. We must check at the descriptor level since
the untrusted plugin may bypass our proxy code and use the file handle
directly to Write. We must also fail any attempt to call ftruncate directly.
BUG=194304
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=242659
Review URL: https://codereview.chromium.org/100703004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242691 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host')
5 files changed, 107 insertions, 316 deletions
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/content/browser/renderer_host/pepper/pepper_file_io_host.cc index 1118c58..6fe68de 100644 --- a/content/browser/renderer_host/pepper/pepper_file_io_host.cc +++ b/content/browser/renderer_host/pepper/pepper_file_io_host.cc @@ -41,13 +41,6 @@ using ppapi::PPTimeToTime; namespace { -int32_t ErrorOrByteNumber(int32_t pp_error, int32_t byte_number) { - // On the plugin side, some callbacks expect a parameter that means different - // things depending on whether it is negative or not. We translate for those - // callbacks here. - return pp_error == PP_OK ? byte_number : pp_error; -} - PepperFileIOHost::UIThreadStuff GetUIThreadStuffForInternalFileSystems(int render_process_id) { PepperFileIOHost::UIThreadStuff stuff; @@ -79,6 +72,10 @@ bool GetPluginAllowedToCallRequestOSFileHandle(int render_process_id, host->GetBrowserContext(), document_url); } +bool FileOpenForWrite(int32_t open_flags) { + return (open_flags & (PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_APPEND)) != 0; +} + } // namespace PepperFileIOHost::PepperFileIOHost(BrowserPpapiHostImpl* host, @@ -104,7 +101,9 @@ PepperFileIOHost::PepperFileIOHost(BrowserPpapiHostImpl* host, } PepperFileIOHost::~PepperFileIOHost() { - OnHostMsgClose(NULL); + // FileIOResource will normally send a close message, but the plugin may have + // crashed. + OnHostMsgClose(NULL, max_written_offset_); } int32_t PepperFileIOHost::OnResourceMessageReceived( @@ -115,14 +114,12 @@ int32_t PepperFileIOHost::OnResourceMessageReceived( OnHostMsgOpen) PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Touch, OnHostMsgTouch) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Write, - OnHostMsgWrite) PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_SetLength, OnHostMsgSetLength) PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Flush, OnHostMsgFlush) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_Close, - OnHostMsgClose) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FileIO_Close, + OnHostMsgClose) PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FileIO_RequestOSFileHandle, OnHostMsgRequestOSFileHandle) IPC_END_MESSAGE_MAP() @@ -209,13 +206,13 @@ void PepperFileIOHost::GotUIThreadStuffForInternalFileSystems( if (resolved_render_process_id_ == base::kNullProcessId || !file_system_context_.get()) { reply_context.params.set_result(PP_ERROR_FAILED); - host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply()); + SendOpenErrorReply(reply_context); return; } if (!file_system_context_->GetFileSystemBackend(file_system_url_.type())) { reply_context.params.set_result(PP_ERROR_FAILED); - host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply()); + SendOpenErrorReply(reply_context); return; } @@ -237,8 +234,8 @@ void PepperFileIOHost::DidOpenInternalFile( if (result == base::PLATFORM_FILE_OK) { on_close_callback_ = on_close_callback; - check_quota_ = file_system_host_ && file_system_host_->ChecksQuota(); - if (check_quota_) { + if (FileOpenForWrite(open_flags_) && file_system_host_->ChecksQuota()) { + check_quota_ = true; file_system_host_->OpenQuotaFile( this, file_system_url_.path(), @@ -293,55 +290,6 @@ int32_t PepperFileIOHost::OnHostMsgTouch( return PP_OK_COMPLETIONPENDING; } -int32_t PepperFileIOHost::OnHostMsgWrite( - ppapi::host::HostMessageContext* context, - int64_t offset, - const std::string& buffer) { - int32_t rv = state_manager_.CheckOperationState( - FileIOStateManager::OPERATION_WRITE, true); - if (rv != PP_OK) - return rv; - if (offset < 0) - return PP_ERROR_BADARGUMENT; - - if (check_quota_) { - int64_t actual_offset = - (open_flags_ & PP_FILEOPENFLAG_APPEND) ? max_written_offset_ : offset; - - uint64_t max_offset = actual_offset + buffer.size(); - if (max_offset > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) - return PP_ERROR_FAILED; // max_offset overflows. - int64_t amount = static_cast<int64_t>(max_offset) - max_written_offset_; - - // Quota request amounts are restricted to 32 bits so we can use atomics - // when we move this code to the plugin side of the proxy. - if (amount > std::numeric_limits<int32_t>::max()) - return PP_ERROR_NOQUOTA; - - if (amount > 0) { - int32_t result = file_system_host_->RequestQuota( - static_cast<int32_t>(amount), - base::Bind(&PepperFileIOHost::GotWriteQuota, - weak_factory_.GetWeakPtr(), - context->MakeReplyMessageContext(), - offset, buffer)); - if (result == PP_OK_COMPLETIONPENDING) { - state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); - return result; - } - // RequestQuota returns either PP_OK_COMPLETIONPENDING or the requested - // quota amount. - DCHECK(result > 0); - } - } - - if (!CallWrite(context->MakeReplyMessageContext(), offset, buffer)) - return PP_ERROR_FAILED; - - state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_WRITE); - return PP_OK_COMPLETIONPENDING; -} - int32_t PepperFileIOHost::OnHostMsgSetLength( ppapi::host::HostMessageContext* context, int64_t length) { @@ -352,32 +300,16 @@ int32_t PepperFileIOHost::OnHostMsgSetLength( if (length < 0) return PP_ERROR_BADARGUMENT; - if (check_quota_) { - int64_t amount = length - max_written_offset_; - // Quota request amounts are restricted to 32 bits so we can use atomics - // when we move this code to the plugin side of the proxy. - if (amount > std::numeric_limits<int32_t>::max()) - return PP_ERROR_NOQUOTA; - - if (amount > 0) { - int32_t result = file_system_host_->RequestQuota( - static_cast<int32_t>(amount), - base::Bind(&PepperFileIOHost::GotSetLengthQuota, - weak_factory_.GetWeakPtr(), - context->MakeReplyMessageContext(), - length)); - if (result == PP_OK_COMPLETIONPENDING) { - state_manager_.SetPendingOperation( - FileIOStateManager::OPERATION_EXCLUSIVE); - return result; - } - // RequestQuota returns either PP_OK_COMPLETIONPENDING or the requested - // quota amount. - DCHECK(result > 0); - } - } + // Quota checks are performed on the plugin side, in order to use the same + // quota reservation and request system as Write. - if (!CallSetLength(context->MakeReplyMessageContext(), length)) + if (!base::FileUtilProxy::Truncate( + file_message_loop_, + file_, + length, + base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, + weak_factory_.GetWeakPtr(), + context->MakeReplyMessageContext()))) return PP_ERROR_FAILED; state_manager_.SetPendingOperation(FileIOStateManager::OPERATION_EXCLUSIVE); @@ -404,9 +336,10 @@ int32_t PepperFileIOHost::OnHostMsgFlush( } int32_t PepperFileIOHost::OnHostMsgClose( - ppapi::host::HostMessageContext* context) { + ppapi::host::HostMessageContext* context, + int64_t max_written_offset) { if (check_quota_) { - file_system_host_->CloseQuotaFile(this); + file_system_host_->CloseQuotaFile(this, max_written_offset); check_quota_ = false; } @@ -426,75 +359,12 @@ void PepperFileIOHost::DidOpenQuotaFile( base::PlatformFile file, int64_t max_written_offset) { max_written_offset_ = max_written_offset; - DCHECK_LE(0, max_written_offset_); ExecutePlatformOpenFileCallback( reply_context, base::PLATFORM_FILE_OK, base::PassPlatformFile(&file), true); } -void PepperFileIOHost::GotWriteQuota( - ppapi::host::ReplyMessageContext reply_context, - int64_t offset, - const std::string& buffer, - int32_t granted) { - if (granted == 0) { - reply_context.params.set_result(PP_ERROR_NOQUOTA); - } else if (!CallWrite(reply_context, offset, buffer)) { - reply_context.params.set_result(PP_ERROR_FAILED); - } else { - max_written_offset_ += granted; - return; - } - // Return the error result set above. - host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply()); - state_manager_.SetOperationFinished(); -} - -void PepperFileIOHost::GotSetLengthQuota( - ppapi::host::ReplyMessageContext reply_context, - int64_t length, - int32_t granted) { - if (granted == 0) { - reply_context.params.set_result(PP_ERROR_NOQUOTA); - } else if (!CallSetLength(reply_context, length)) { - reply_context.params.set_result(PP_ERROR_FAILED); - } else { - max_written_offset_ += granted; - return; - } - // Return the error result set above. - host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply()); - state_manager_.SetOperationFinished(); -} - -bool PepperFileIOHost::CallWrite( - ppapi::host::ReplyMessageContext reply_context, - int64_t offset, - const std::string& buffer) { - return base::FileUtilProxy::Write( - file_message_loop_, - file_, - offset, - buffer.c_str(), - buffer.size(), - base::Bind(&PepperFileIOHost::ExecutePlatformWriteCallback, - weak_factory_.GetWeakPtr(), - reply_context)); -} - -bool PepperFileIOHost::CallSetLength( - ppapi::host::ReplyMessageContext reply_context, - int64_t length) { - return base::FileUtilProxy::Truncate( - file_message_loop_, - file_, - length, - base::Bind(&PepperFileIOHost::ExecutePlatformGeneralCallback, - weak_factory_.GetWeakPtr(), - reply_context)); -} - void PepperFileIOHost::DidCloseFile(base::PlatformFileError error) { // Silently ignore if we fail to close the file. if (!on_close_callback_.is_null()) { @@ -553,39 +423,31 @@ void PepperFileIOHost::ExecutePlatformOpenFileCallback( base::PassPlatformFile file, bool unused_created) { int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code); - if (pp_error == PP_OK) - state_manager_.SetOpenSucceed(); - DCHECK(file_ == base::kInvalidPlatformFileValue); file_ = file.ReleaseValue(); - if (file_ != base::kInvalidPlatformFileValue) { - int32_t flags_to_send = open_flags_; - if (!host()->permissions().HasPermission(ppapi::PERMISSION_DEV)) { - // IMPORTANT: Clear PP_FILEOPENFLAG_WRITE and PP_FILEOPENFLAG_APPEND so - // the plugin can't write and so bypass our quota checks. - flags_to_send = - open_flags_ & ~(PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_APPEND); - } - if (!AddFileToReplyContext(flags_to_send, &reply_context)) - pp_error = PP_ERROR_FAILED; + if (file_ != base::kInvalidPlatformFileValue && + !AddFileToReplyContext(open_flags_, &reply_context)) + pp_error = PP_ERROR_FAILED; + + PP_Resource quota_file_system = 0; + if (pp_error == PP_OK) { + state_manager_.SetOpenSucceed(); + // A non-zero resource id signals the plugin side to check quota. + if (check_quota_) + quota_file_system = file_system_host_->pp_resource(); } + reply_context.params.set_result(pp_error); - host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply()); + host()->SendReply(reply_context, + PpapiPluginMsg_FileIO_OpenReply(quota_file_system, + max_written_offset_)); state_manager_.SetOperationFinished(); } -void PepperFileIOHost::ExecutePlatformWriteCallback( - ppapi::host::ReplyMessageContext reply_context, - base::PlatformFileError error_code, - int bytes_written) { - // On the plugin side, the callback expects a parameter with different meaning - // depends on whether is negative or not. It is the result here. We translate - // for the callback. - int32_t pp_error = ppapi::PlatformFileErrorToPepperError(error_code); - reply_context.params.set_result(ErrorOrByteNumber(pp_error, bytes_written)); - host()->SendReply(reply_context, PpapiPluginMsg_FileIO_GeneralReply()); - state_manager_.SetOperationFinished(); +void PepperFileIOHost::SendOpenErrorReply( + ppapi::host::ReplyMessageContext reply_context) { + host()->SendReply(reply_context, PpapiPluginMsg_FileIO_OpenReply(0, 0)); } bool PepperFileIOHost::AddFileToReplyContext( @@ -602,8 +464,11 @@ bool PepperFileIOHost::AddFileToReplyContext( file_, plugin_process_id, false); if (transit_file == IPC::InvalidPlatformFileForTransit()) return false; + ppapi::proxy::SerializedHandle file_handle; - file_handle.set_file_handle(transit_file, open_flags, 0 /* file_io */); + // A non-zero resource id signals NaClIPCAdapter to create a NaClQuotaDesc. + PP_Resource quota_file_io = check_quota_ ? pp_resource() : 0; + file_handle.set_file_handle(transit_file, open_flags, quota_file_io); reply_context->params.AppendHandle(file_handle); return true; } diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.h b/content/browser/renderer_host/pepper/pepper_file_io_host.h index 9394e6c..4fa4bc2 100644 --- a/content/browser/renderer_host/pepper/pepper_file_io_host.h +++ b/content/browser/renderer_host/pepper/pepper_file_io_host.h @@ -41,12 +41,6 @@ class PepperFileIOHost : public ppapi::host::ResourceHost, const IPC::Message& msg, ppapi::host::HostMessageContext* context) OVERRIDE; - // Direct access for PepperFileSystemBrowserHost. - int64_t max_written_offset() const { return max_written_offset_; } - void set_max_written_offset(int64_t max_written_offset) { - max_written_offset_ = max_written_offset; - } - struct UIThreadStuff { UIThreadStuff(); ~UIThreadStuff(); @@ -60,12 +54,10 @@ class PepperFileIOHost : public ppapi::host::ResourceHost, int32_t OnHostMsgTouch(ppapi::host::HostMessageContext* context, PP_Time last_access_time, PP_Time last_modified_time); - int32_t OnHostMsgWrite(ppapi::host::HostMessageContext* context, - int64_t offset, - const std::string& buffer); int32_t OnHostMsgSetLength(ppapi::host::HostMessageContext* context, int64_t length); - int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context); + int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context, + int64_t max_written_offset); int32_t OnHostMsgFlush(ppapi::host::HostMessageContext* context); int32_t OnHostMsgRequestOSFileHandle( ppapi::host::HostMessageContext* context); @@ -86,10 +78,6 @@ class PepperFileIOHost : public ppapi::host::ResourceHost, base::PlatformFileError error_code, base::PassPlatformFile file, bool unused_created); - void ExecutePlatformWriteCallback( - ppapi::host::ReplyMessageContext reply_context, - base::PlatformFileError error_code, - int bytes_written); void GotUIThreadStuffForInternalFileSystems( ppapi::host::ReplyMessageContext reply_context, @@ -109,21 +97,13 @@ class PepperFileIOHost : public ppapi::host::ResourceHost, void DidOpenQuotaFile(ppapi::host::ReplyMessageContext reply_context, base::PlatformFile file, int64_t max_written_offset); - void GotWriteQuota(ppapi::host::ReplyMessageContext reply_context, - int64_t offset, - const std::string& buffer, - int32_t granted); - void GotSetLengthQuota(ppapi::host::ReplyMessageContext reply_context, - int64_t length, - int32_t granted); - bool CallWrite(ppapi::host::ReplyMessageContext reply_context, - int64_t offset, - const std::string& buffer); bool CallSetLength(ppapi::host::ReplyMessageContext reply_context, int64_t length); void DidCloseFile(base::PlatformFileError error); + void SendOpenErrorReply(ppapi::host::ReplyMessageContext reply_context); + // Adds file_ to |reply_context| with the specified |open_flags|. bool AddFileToReplyContext( int32_t open_flags, diff --git a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc index 9161ad7..2bc0042 100644 --- a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc +++ b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.cc @@ -48,16 +48,6 @@ GetFileSystemContextFromRenderId(int render_process_id) { } // namespace -PepperFileSystemBrowserHost::QuotaRequest::QuotaRequest( - int32_t amount_arg, - const RequestQuotaCallback& callback_arg) - : amount(amount_arg), - callback(callback_arg) { -} - -PepperFileSystemBrowserHost::QuotaRequest::~QuotaRequest() { -} - PepperFileSystemBrowserHost::PepperFileSystemBrowserHost(BrowserPpapiHost* host, PP_Instance instance, PP_Resource resource, @@ -110,6 +100,9 @@ int32_t PepperFileSystemBrowserHost::OnResourceMessageReceived( PPAPI_DISPATCH_HOST_RESOURCE_CALL( PpapiHostMsg_FileSystem_InitIsolatedFileSystem, OnHostMsgInitIsolatedFileSystem) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_FileSystem_ReserveQuota, + OnHostMsgReserveQuota) IPC_END_MESSAGE_MAP() return PP_ERROR_FAILED; } @@ -140,12 +133,11 @@ void PepperFileSystemBrowserHost::OpenQuotaFile( } void PepperFileSystemBrowserHost::CloseQuotaFile( - PepperFileIOHost* file_io_host) { + PepperFileIOHost* file_io_host, + int64_t max_written_offset) { int32_t id = file_io_host->pp_resource(); - int64_t max_written_offset = 0; FileMap::iterator it = files_.find(id); if (it != files_.end()) { - max_written_offset = file_io_host->max_written_offset(); files_.erase(it); } else { NOTREACHED(); @@ -160,25 +152,6 @@ void PepperFileSystemBrowserHost::CloseQuotaFile( max_written_offset)); } -int32_t PepperFileSystemBrowserHost::RequestQuota( - int32_t amount, - const RequestQuotaCallback& callback) { - DCHECK(amount >= 0); - if (!reserving_quota_ && reserved_quota_ >= amount) { - reserved_quota_ -= amount; - return amount; - } - - // Queue up a pending quota request. - pending_quota_requests_.push(QuotaRequest(amount, callback)); - - // Reserve more quota if we haven't already. - if (!reserving_quota_) - ReserveQuota(amount); - - return PP_OK_COMPLETIONPENDING; -} - int32_t PepperFileSystemBrowserHost::OnHostMsgOpen( ppapi::host::HostMessageContext* context, int64_t /* unused */) { @@ -381,6 +354,33 @@ int32_t PepperFileSystemBrowserHost::OnHostMsgInitIsolatedFileSystem( return PP_OK_COMPLETIONPENDING; } +int32_t PepperFileSystemBrowserHost::OnHostMsgReserveQuota( + ppapi::host::HostMessageContext* context, + int64_t amount, + const std::map<int32_t, int64_t>& max_written_offsets) { + DCHECK(ChecksQuota()); + DCHECK(amount > 0); + + if (reserving_quota_) + return PP_ERROR_INPROGRESS; + reserving_quota_ = true; + + int64_t reservation_amount = std::max<int64_t>(kMinimumQuotaReservationSize, + amount); + file_system_context_->default_file_task_runner()->PostTask( + FROM_HERE, + base::Bind(&QuotaReservation::ReserveQuota, + quota_reservation_, + reservation_amount, + max_written_offsets, + base::Bind(&PepperFileSystemBrowserHost::GotReservedQuota, + weak_factory_.GetWeakPtr(), + context->MakeReplyMessageContext()))); + + + return PP_OK_COMPLETIONPENDING; +} + void PepperFileSystemBrowserHost::SendReplyForFileSystem( ppapi::host::ReplyMessageContext reply_context, int32_t pp_error) { @@ -413,7 +413,7 @@ bool PepperFileSystemBrowserHost::ShouldCreateQuotaReservation() const { if (!ppapi::FileSystemTypeHasQuota(type_)) return false; - // For file system types with quota, ome origins have unlimited storage. + // For file system types with quota, some origins have unlimited storage. quota::QuotaManagerProxy* quota_manager_proxy = file_system_context_->quota_manager_proxy(); CHECK(quota_manager_proxy); @@ -447,67 +447,18 @@ void PepperFileSystemBrowserHost::GotQuotaReservation( callback.Run(); } -void PepperFileSystemBrowserHost::ReserveQuota(int32_t amount) { - DCHECK(!reserving_quota_); - reserving_quota_ = true; - - // Get the max_written_offset for each open file. - QuotaReservation::OffsetMap max_written_offsets; - for (FileMap::iterator it = files_.begin(); it != files_.end(); ++ it) { - max_written_offsets.insert( - std::make_pair(it->first, it->second->max_written_offset())); - } - - int64_t reservation_amount = std::max<int64_t>(kMinimumQuotaReservationSize, - amount); - file_system_context_->default_file_task_runner()->PostTask( - FROM_HERE, - base::Bind(&QuotaReservation::ReserveQuota, - quota_reservation_, - reservation_amount, - max_written_offsets, - base::Bind(&PepperFileSystemBrowserHost::GotReservedQuota, - weak_factory_.GetWeakPtr()))); -} - void PepperFileSystemBrowserHost::GotReservedQuota( + ppapi::host::ReplyMessageContext reply_context, int64_t amount, const QuotaReservation::OffsetMap& max_written_offsets) { DCHECK(reserving_quota_); reserving_quota_ = false; reserved_quota_ = amount; - // Update open files with their new base sizes. This won't write over any - // updates since the files are waiting for quota and can't write. - for (FileMap::iterator it = files_.begin(); it != files_.end(); ++ it) { - QuotaReservation::OffsetMap::const_iterator offset_it = - max_written_offsets.find(it->first); - if (offset_it != max_written_offsets.end()) - it->second->set_max_written_offset(offset_it->second); - else - NOTREACHED(); - } - - DCHECK(!pending_quota_requests_.empty()); - // If we can't grant the first request after refreshing reserved_quota_, then - // fail all pending quota requests to avoid an infinite refresh/fail loop. - bool fail_all = reserved_quota_ < pending_quota_requests_.front().amount; - while (!pending_quota_requests_.empty()) { - QuotaRequest& request = pending_quota_requests_.front(); - if (fail_all) { - request.callback.Run(0); - pending_quota_requests_.pop(); - } else if (reserved_quota_ >= request.amount) { - reserved_quota_ -= request.amount; - request.callback.Run(request.amount); - pending_quota_requests_.pop(); - } else { - // Refresh the quota reservation for the first pending request that we - // can't satisfy. - ReserveQuota(request.amount); - break; - } - } + reply_context.params.set_result(PP_OK); + host()->SendReply( + reply_context, + PpapiPluginMsg_FileSystem_ReserveQuotaReply(amount, max_written_offsets)); } std::string PepperFileSystemBrowserHost::GetPluginMimeType() const { diff --git a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h index bd47a43..6a90fae 100644 --- a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h +++ b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h @@ -72,26 +72,12 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost const OpenQuotaFileCallback& callback); // Closes the file. This must be called after OpenQuotaFile and before the // PepperFileIOHost is destroyed. - void CloseQuotaFile(PepperFileIOHost* file_io_host); - // Requests the given amount of quota. Returns the amount requested or - // PP_OK_COMPLETIONPENDING, in which case the amount granted is returned in - // the callback. Requests can't partially succeed so the amount granted is - // either 0 or the amount of the request. Requesting an amount of 0 will - // return immediately with a 0 result. - typedef base::Callback<void(int32_t)> RequestQuotaCallback; - int32_t RequestQuota(int32_t amount, - const RequestQuotaCallback& callback); + void CloseQuotaFile(PepperFileIOHost* file_io_host, + int64_t max_written_offset); + private: friend class PepperFileSystemBrowserHostTest; - struct QuotaRequest { - QuotaRequest(int32_t amount, const RequestQuotaCallback& callback); - ~QuotaRequest(); - - int32_t amount; - RequestQuotaCallback callback; - }; - void OpenExistingFileSystem( const base::Closure& callback, scoped_refptr<fileapi::FileSystemContext> file_system_context); @@ -118,12 +104,17 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost const std::string& fsid, base::PlatformFileError error); - int32_t OnHostMsgOpen(ppapi::host::HostMessageContext* context, - int64_t expected_size); + int32_t OnHostMsgOpen( + ppapi::host::HostMessageContext* context, + int64_t expected_size); int32_t OnHostMsgInitIsolatedFileSystem( ppapi::host::HostMessageContext* context, const std::string& fsid, PP_IsolatedFileSystemType_Private type); + int32_t OnHostMsgReserveQuota( + ppapi::host::HostMessageContext* context, + int64_t amount, + const std::map<int32_t, int64_t>& max_written_offsets); void SendReplyForFileSystem( ppapi::host::ReplyMessageContext reply_context, @@ -142,9 +133,14 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost const base::Closure& callback, scoped_refptr<QuotaReservation> quota_reservation); - void ReserveQuota(int32_t amount); - void GotReservedQuota(int64_t amount, - const QuotaReservation::OffsetMap& max_written_offsets); + void GotReservedQuota( + ppapi::host::ReplyMessageContext reply_context, + int64_t amount, + const std::map<int32_t, int64_t>& max_written_offsets); + void DidOpenQuotaFile( + PP_Resource file_io_resource, + const OpenQuotaFileCallback& callback, + int64_t max_written_offset); std::string GetPluginMimeType() const; @@ -167,7 +163,6 @@ class CONTENT_EXPORT PepperFileSystemBrowserHost // destroyed. typedef std::map<int32_t, PepperFileIOHost*> FileMap; FileMap files_; - std::queue<QuotaRequest> pending_quota_requests_; int64_t reserved_quota_; bool reserving_quota_; // Access only on the FileSystemContext's default_file_task_runner(). diff --git a/content/browser/renderer_host/pepper/quota_reservation.cc b/content/browser/renderer_host/pepper/quota_reservation.cc index a512f10..d928f23 100644 --- a/content/browser/renderer_host/pepper/quota_reservation.cc +++ b/content/browser/renderer_host/pepper/quota_reservation.cc @@ -78,7 +78,7 @@ void QuotaReservation::ReserveQuota( int64_t amount, const OffsetMap& max_written_offsets, const ReserveQuotaCallback& callback) { - for (FileMap::iterator it = files_.begin(); it != files_.end(); ++ it) { + for (FileMap::iterator it = files_.begin(); it != files_.end(); ++it) { OffsetMap::const_iterator offset_it = max_written_offsets.find(it->first); if (offset_it != max_written_offsets.end()) it->second->UpdateMaxWrittenOffset(offset_it->second); |