aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Anderson <saa@android.com>2012-04-24 16:35:57 -0700
committerScott Anderson <saa@android.com>2012-04-26 12:05:50 -0700
commit613ee1f783d25f83aeb9b5ad25c3ceb3da49b163 (patch)
treebf2902d1a7cc273d4f151bbe1dbb037edea78d08
parentaf3e2eba53c86b352f49634dcffd23775b3de6be (diff)
downloadstressapptest-613ee1f783d25f83aeb9b5ad25c3ceb3da49b163.tar.gz
Work around O_DIRECT being invalid on Android
If a file is opened with O_DIRECT on Android, an EINVAL will be triggered. To try to accomplish the same effect as O_DIRECT, this change adds calls to flush the page cache at key points for the file and disk threads. These calls will sync and write a "1" to /proc/sys/vm/drop_caches if O_DIRECT caused an EINVAL, but will be a NOP otherwise. Change-Id: If0c7ca455384f9d60d4587127e96979a3c7f1169 Signed-off-by: Scott Anderson <saa@android.com>
-rw-r--r--src/os.cc42
-rw-r--r--src/os.h10
-rw-r--r--src/worker.cc28
3 files changed, 73 insertions, 7 deletions
diff --git a/src/os.cc b/src/os.cc
index 3434baa..8032cfc 100644
--- a/src/os.cc
+++ b/src/os.cc
@@ -77,6 +77,8 @@ OsLayer::OsLayer() {
has_clflush_ = false;
has_sse2_ = false;
+
+ use_flush_page_cache_ = false;
}
// OsLayer cleanup.
@@ -169,6 +171,46 @@ void OsLayer::GetFeatures() {
}
+// Enable FlushPageCache to be functional instead of a NOP.
+void OsLayer::ActivateFlushPageCache(void) {
+ logprintf(9, "Log: page cache will be flushed as needed\n");
+ use_flush_page_cache_ = true;
+}
+
+// Flush the page cache to ensure reads come from the disk.
+bool OsLayer::FlushPageCache(void) {
+ if (!use_flush_page_cache_)
+ return true;
+
+ // First, ask the kernel to write the cache to the disk.
+ sync();
+
+ // Second, ask the kernel to empty the cache by writing "1" to
+ // "/proc/sys/vm/drop_caches".
+ static const char *drop_caches_file = "/proc/sys/vm/drop_caches";
+ int dcfile = open(drop_caches_file, O_WRONLY);
+ if (dcfile < 0) {
+ int err = errno;
+ string errtxt = ErrorString(err);
+ logprintf(3, "Log: failed to open %s - err %d (%s)\n",
+ drop_caches_file, err, errtxt.c_str());
+ return false;
+ }
+
+ ssize_t bytes_written = write(dcfile, "1", 1);
+ close(dcfile);
+
+ if (bytes_written != 1) {
+ int err = errno;
+ string errtxt = ErrorString(err);
+ logprintf(3, "Log: failed to write %s - err %d (%s)\n",
+ drop_caches_file, err, errtxt.c_str());
+ return false;
+ }
+ return true;
+}
+
+
// We need to flush the cacheline here.
void OsLayer::Flush(void *vaddr) {
// Use the generic flush. This function is just so we can override
diff --git a/src/os.h b/src/os.h
index 28c8a2a..b043b61 100644
--- a/src/os.h
+++ b/src/os.h
@@ -101,6 +101,15 @@ class OsLayer {
// This will output a machine readable line regarding the error.
virtual bool ErrorReport(const char *part, const char *symptom, int count);
+ // Flushes page cache. Used to circumvent the page cache when doing disk
+ // I/O. This will be a NOP until ActivateFlushPageCache() is called, which
+ // is typically done when opening a file with O_DIRECT fails.
+ // Returns false on error, true on success or NOP.
+ // Subclasses may implement this in machine specific ways..
+ virtual bool FlushPageCache(void);
+ // Enable FlushPageCache() to actually do the flush instead of being a NOP.
+ virtual void ActivateFlushPageCache(void);
+
// Flushes cacheline. Used to distinguish read or write errors.
// Subclasses may implement this in machine specific ways..
// Takes a pointer, and flushed the cacheline containing that pointer.
@@ -260,6 +269,7 @@ class OsLayer {
int address_mode_; // Are we running 32 or 64 bit?
bool has_sse2_; // Do we have sse2 instructions?
bool has_clflush_; // Do we have clflush instructions?
+ bool use_flush_page_cache_; // Do we need to flush the page cache?
time_t time_initialized_; // Start time of test.
diff --git a/src/worker.cc b/src/worker.cc
index 2dae464..dcf4dcb 100644
--- a/src/worker.cc
+++ b/src/worker.cc
@@ -1600,15 +1600,21 @@ void FileThread::SetFile(const char *filename_init) {
// Open the file for access.
bool FileThread::OpenFile(int *pfile) {
- int fd = open(filename_.c_str(),
- O_RDWR | O_CREAT | O_SYNC | O_DIRECT,
- 0644);
+ bool no_O_DIRECT = false;
+ int flags = O_RDWR | O_CREAT | O_SYNC;
+ int fd = open(filename_.c_str(), flags | O_DIRECT, 0644);
+ if (O_DIRECT != 0 && fd < 0 && errno == EINVAL) {
+ no_O_DIRECT = true;
+ fd = open(filename_.c_str(), flags, 0644); // Try without O_DIRECT
+ }
if (fd < 0) {
logprintf(0, "Process Error: Failed to create file %s!!\n",
filename_.c_str());
pages_copied_ = 0;
return false;
}
+ if (no_O_DIRECT)
+ os_->ActivateFlushPageCache(); // Not using O_DIRECT fixed EINVAL
*pfile = fd;
return true;
}
@@ -1679,7 +1685,7 @@ bool FileThread::WritePages(int fd) {
if (!result)
return false;
}
- return true;
+ return os_->FlushPageCache(); // If O_DIRECT worked, this will be a NOP.
}
// Copy data from file into memory block.
@@ -2691,14 +2697,20 @@ bool DiskThread::SetParameters(int read_block_size,
// Open a device, return false on failure.
bool DiskThread::OpenDevice(int *pfile) {
- int fd = open(device_name_.c_str(),
- O_RDWR | O_SYNC | O_DIRECT | O_LARGEFILE,
- 0);
+ bool no_O_DIRECT = false;
+ int flags = O_RDWR | O_SYNC | O_LARGEFILE;
+ int fd = open(device_name_.c_str(), flags | O_DIRECT, 0);
+ if (O_DIRECT != 0 && fd < 0 && errno == EINVAL) {
+ no_O_DIRECT = true;
+ fd = open(device_name_.c_str(), flags, 0); // Try without O_DIRECT
+ }
if (fd < 0) {
logprintf(0, "Process Error: Failed to open device %s (thread %d)!!\n",
device_name_.c_str(), thread_num_);
return false;
}
+ if (no_O_DIRECT)
+ os_->ActivateFlushPageCache();
*pfile = fd;
return GetDiskSize(fd);
@@ -2858,6 +2870,8 @@ bool DiskThread::DoWork(int fd) {
in_flight_sectors_.push(block);
}
+ if (!os_->FlushPageCache()) // If O_DIRECT worked, this will be a NOP.
+ return false;
// Verify blocks on disk.
logprintf(20, "Log: Read phase for disk %s (thread %d).\n",