diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 6e078fe650..50437d69ae 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -1854,8 +1854,9 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v } const auto file = std::as_const(all_files).find(file_path); + const u64 pos = fileSet->fileOffset; - if (file == all_files.cend() || file->second.size() <= fileSet->fileOffset) + if (file == all_files.cend() || file->second.size() <= pos) { cellSaveData.error("Failed to open file %s%s (size=%d, fileOffset=%d)", dir_path, file_path, file == all_files.cend() ? -1 : file->second.size(), fileSet->fileOffset); savedata_result = CELL_SAVEDATA_ERROR_FAILURE; @@ -1863,8 +1864,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v } // Read from memory file to vm - file->second.seek(fileSet->fileOffset); - const u64 rr = lv2_file::op_read(file->second, fileSet->fileBuf, fileSet->fileSize); + const u64 rr = lv2_file::op_read(file->second, fileSet->fileBuf, fileSet->fileSize, pos); fileGet->excSize = ::narrow(rr); break; } diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index aebb611852..4e1817493b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -16,6 +16,7 @@ #include #include +#include LOG_CHANNEL(sys_fs); @@ -371,7 +372,7 @@ lv2_fs_object::lv2_fs_object(utils::serial& ar, bool) { } -u64 lv2_file::op_read(const fs::file& file, vm::ptr buf, u64 size) +u64 lv2_file::op_read(const fs::file& file, vm::ptr buf, u64 size, u64 opt_pos) { // Copy data from intermediate buffer (avoid passing vm pointer to a native API) std::vector local_buf(std::min(size, 65536)); @@ -381,7 +382,7 @@ u64 lv2_file::op_read(const fs::file& file, vm::ptr buf, u64 size) while (result < size) { const u64 block = std::min(size - result, local_buf.size()); - const u64 nread = file.read(+local_buf.data(), block); + const u64 nread = (opt_pos == umax ? file.read(local_buf.data(), block) : file.read_at(opt_pos + result, local_buf.data(), block)); std::memcpy(static_cast(buf.get_ptr()) + result, local_buf.data(), nread); result += nread; @@ -1930,7 +1931,19 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 sys_fs.error("%s type: Writing %u bytes to FD=%d (path=%s)", file->type, arg->size, file->name.data()); } - std::lock_guard lock(file->mp->mutex); + std::unique_lock wlock(file->mp->mutex, std::defer_lock); + std::shared_lock rlock(file->mp->mutex, std::defer_lock); + + if (op == 0x8000000b) + { + // Writer lock + wlock.lock(); + } + else + { + // Reader lock (not needing exclusivity in this special case because the state should not change) + rlock.lock(); + } if (!file->file) { @@ -1947,14 +1960,23 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 return CELL_EBUSY; } - const u64 old_pos = file->file.pos(); - file->file.seek(arg->offset); + u64 old_pos = umax; + const u64 op_pos = arg->offset; + + if (op == 0x8000000b) + { + old_pos = file->file.pos(); + file->file.seek(op_pos); + } arg->out_size = op == 0x8000000a - ? file->op_read(arg->buf, arg->size) + ? file->op_read(arg->buf, arg->size, op_pos) : file->op_write(arg->buf, arg->size); - ensure(old_pos == file->file.seek(old_pos)); + if (op == 0x8000000b) + { + ensure(old_pos == file->file.seek(old_pos)); + } // TODO: EDATA corruption detection diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 79ee4636bd..4c926f5aa9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -157,7 +157,7 @@ struct lv2_fs_mount_point const bs_t flags{}; lv2_fs_mount_point* const next = nullptr; - mutable std::recursive_mutex mutex; + mutable shared_mutex mutex; }; extern lv2_fs_mount_point g_mp_sys_dev_hdd0; @@ -340,11 +340,11 @@ struct lv2_file final : lv2_fs_object static open_result_t open(std::string_view vpath, s32 flags, s32 mode, const void* arg = {}, u64 size = 0); // File reading with intermediate buffer - static u64 op_read(const fs::file& file, vm::ptr buf, u64 size); + static u64 op_read(const fs::file& file, vm::ptr buf, u64 size, u64 opt_pos = umax); - u64 op_read(vm::ptr buf, u64 size) const + u64 op_read(vm::ptr buf, u64 size, u64 opt_pos = umax) const { - return op_read(file, buf, size); + return op_read(file, buf, size, opt_pos); } // File writing with intermediate buffer