Commit d7744d2b authored by Max Kellermann's avatar Max Kellermann

command/storage: check if storage is already mounted

Mounting one storage URI twice on different mount points can lead to conflicts with the database cache file, and it doesn't make a lot of sense. But most importantly, our udisks storage plugin will unmount the disk from the kernel VFS, and if two exist, they will compete with each others. We could (and should) fix this in the udisks storage plugin, but for now, this workaround is good enough (and useful).
parent 33ee35ab
...@@ -203,6 +203,11 @@ handle_mount(Client &client, Request args, Response &r) ...@@ -203,6 +203,11 @@ handle_mount(Client &client, Request args, Response &r)
return CommandResult::ERROR; return CommandResult::ERROR;
} }
if (composite.IsMounted(remote_uri)) {
r.Error(ACK_ERROR_ARG, "This storage is already mounted");
return CommandResult::ERROR;
}
auto &event_loop = instance.io_thread.GetEventLoop(); auto &event_loop = instance.io_thread.GetEventLoop();
auto storage = CreateStorageURI(event_loop, remote_uri); auto storage = CreateStorageURI(event_loop, remote_uri);
if (storage == nullptr) { if (storage == nullptr) {
......
...@@ -121,6 +121,15 @@ public: ...@@ -121,6 +121,15 @@ public:
VisitMounts(uri, root, t); VisitMounts(uri, root, t);
} }
/**
* Is a storage with the given URI already mounted?
*/
gcc_pure gcc_nonnull_all
bool IsMounted(const char *storage_uri) const noexcept {
const std::lock_guard<Mutex> protect(mutex);
return IsMounted(root, storage_uri);
}
void Mount(const char *uri, std::unique_ptr<Storage> storage); void Mount(const char *uri, std::unique_ptr<Storage> storage);
bool Unmount(const char *uri); bool Unmount(const char *uri);
...@@ -155,6 +164,22 @@ private: ...@@ -155,6 +164,22 @@ private:
} }
} }
gcc_pure gcc_nonnull_all
static bool IsMounted(const Directory &directory,
const char *storage_uri) noexcept {
if (directory.storage) {
const auto uri = directory.storage->MapUTF8("");
if (uri == storage_uri)
return true;
}
for (const auto &i : directory.children)
if (IsMounted(i.second, storage_uri))
return true;
return false;
}
/** /**
* Follow the given URI path, and find the outermost directory * Follow the given URI path, and find the outermost directory
* which is a #Storage mount point. If there are no mounts, * which is a #Storage mount point. If there are no mounts,
......
...@@ -112,6 +112,11 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance) ...@@ -112,6 +112,11 @@ storage_state_restore(const char *line, TextFile &file, Instance &instance)
return true; return true;
} }
if (composite_storage.IsMounted(url.c_str())) {
LogError(storage_domain, "This storage is already mounted");
return true;
}
auto &event_loop = instance.io_thread.GetEventLoop(); auto &event_loop = instance.io_thread.GetEventLoop();
auto storage = CreateStorageURI(event_loop, url.c_str()); auto storage = CreateStorageURI(event_loop, url.c_str());
if (storage == nullptr) { if (storage == nullptr) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment