Revise loopback device handling to be parallelization safe.
Update engine tests were allocating loopback devices in a non-atomic fashion.
When they were run in parallel with other tests that were using loopback
devices, this could lead to two tests using the same device and failing.
This change follows jrbarnette's advice and allocates loopback devices
atomically using "losetup --show -f <file to bind>".
NOTE: integration_unittest.cc is not currently being built or run, and
so the change here has not been verified. I only discovered it wasn't being
built while making this change, and fixing/deleting it seemed out of scope
for the change.
BUG=chromium-os:24975
TEST=Ran unittests
Change-Id: Ica060c8add009cac134e22b46b4e87588d0246e0
Reviewed-on: https://gerrit.chromium.org/gerrit/15128
Reviewed-by: Richard Barnette <jrbarnette@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Don Garrett <dgarrett@chromium.org>
Commit-Ready: Don Garrett <dgarrett@chromium.org>
diff --git a/test_utils.h b/test_utils.h
index b5ac853..86ee030 100644
--- a/test_utils.h
+++ b/test_utils.h
@@ -36,7 +36,7 @@
// the first partition is marked bootable.
std::vector<char> GenerateSampleMbr();
-std::string GetUnusedLoopDevice();
+std::string BindToUnusedLoopDevice(const std::string &filename);
// Returns true iff a == b
bool ExpectVectorsEq(const std::vector<char>& a, const std::vector<char>& b);
@@ -111,10 +111,16 @@
void VerifyAllPaths(const std::string& parent,
std::set<std::string> expected_paths);
-class ScopedLoopbackDeviceReleaser {
+class ScopedLoopbackDeviceBinder {
public:
- explicit ScopedLoopbackDeviceReleaser(const std::string& dev) : dev_(dev) {}
- ~ScopedLoopbackDeviceReleaser() {
+ ScopedLoopbackDeviceBinder(const std::string& file, std::string* dev) {
+ dev_ = BindToUnusedLoopDevice(file);
+
+ if (dev)
+ *dev = dev_;
+ }
+
+ ~ScopedLoopbackDeviceBinder() {
for (int retry = 0; retry < 5; retry++) {
std::vector<std::string> args;
args.push_back("/sbin/losetup");
@@ -129,9 +135,12 @@
}
ADD_FAILURE();
}
+
+ const std::string &dev() { return dev_; }
+
private:
- const std::string dev_;
- DISALLOW_COPY_AND_ASSIGN(ScopedLoopbackDeviceReleaser);
+ std::string dev_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedLoopbackDeviceBinder);
};
class ScopedTempFile {
@@ -227,10 +236,10 @@
private:
// These objects must be destructed in the following order:
// ScopedFilesystemUnmounter (the file system must be unmounted first)
- // ScopedLoopbackDeviceReleaser (then the loop device can be deleted)
+ // ScopedLoopbackDeviceBinder (then the loop device can be deleted)
// ScopedDirRemover (then the mount point can be deleted)
scoped_ptr<ScopedDirRemover> dir_remover_;
- scoped_ptr<ScopedLoopbackDeviceReleaser> loop_releaser_;
+ scoped_ptr<ScopedLoopbackDeviceBinder> loop_binder_;
scoped_ptr<ScopedFilesystemUnmounter> unmounter_;
};