Prevent detach and cache invalidation reuse races

This commit is contained in:
Roman Tarasov committed 2026-08-25 15:21:21 +03:00
1 parent 06576fabe3
commit 01ea403b88
5 files changed
+210 -131

No files matched your search

+5 -4
View File
@@ -43,16 +43,17 @@ bool mark_image_cache_detach_requested(const char *path, uint64_t generation,
int unit_id,
attach_backend_t backend);
// Claim one detach attempt and return a stable snapshot of its record.
bool claim_image_cache_detach(const char *path, int unit_id,
attach_backend_t backend,
bool claim_image_cache_detach(const char *path, uint64_t generation,
int unit_id, attach_backend_t backend,
image_cache_entry_t *entry_out);
// Publish the result of a claimed detach attempt and release its claim.
bool finish_image_cache_detach_attempt(
const char *path, uint64_t generation, int unit_id,
attach_backend_t backend,
const attached_unit_detach_state_t *detach_state);
// Invalidate the same generation of a cached image mount entry.
bool invalidate_image_cache_entry(int index, uint64_t generation);
// Invalidate only when the slot still owns the complete expected attachment.
bool invalidate_image_cache_entry(int index,
const image_cache_entry_t *expected);
// Resolve a device mapping from the in-memory mount cache.
bool resolve_device_from_mount_cache(const char *mount_point,
attach_backend_t *backend_out,
+2 -2
View File
@@ -19,8 +19,8 @@ bool resolve_device_from_mount(const char *mount_point,
bool is_active_image_mount_point(const char *path);
// Wait until /dev/lvd2 is no longer mounted during startup.
bool wait_for_lvd_release(void);
// Detach a previously attached MD or LVD unit. A non-NULL state makes an
// accepted asynchronous detach idempotent across later cleanup attempts.
// Detach a previously attached MD or LVD unit. State and node identity are
// required so an accepted asynchronous detach remains bound to one device.
bool detach_attached_unit(attach_backend_t backend, int unit_id,
attached_unit_detach_state_t *state);
// Wait for an accepted detach to remove its node, or detect unit reuse.
+77 -50
View File
@@ -22,6 +22,43 @@ static bool unmount_completed(unmount_result_t result) {
result.directory_removed;
}
static bool invalidate_matching_image_cache_entry(
int index, const image_cache_entry_t *expected) {
image_cache_entry_t current;
if (!expected || !get_image_cache_entry(index, &current) ||
current.generation != expected->generation ||
strcmp(current.path, expected->path) != 0 ||
strcmp(current.mount_point, expected->mount_point) != 0 ||
current.unit_id != expected->unit_id ||
current.backend != expected->backend ||
(expected->detach_state.node_identity_valid &&
(!current.detach_state.node_identity_valid ||
current.detach_state.node_device != expected->detach_state.node_device ||
current.detach_state.node_inode != expected->detach_state.node_inode ||
current.detach_state.node_rdev != expected->detach_state.node_rdev))) {
errno = ESTALE;
return false;
}
return invalidate_image_cache_entry(index, &current);
}
static void rollback_unpublished_attached_unit(attach_backend_t backend,
int unit_id,
const char *devname) {
attached_unit_detach_state_t detach_state = {0};
bool detached = detach_attached_unit(backend, unit_id, &detach_state);
if (!detached && !detach_state.node_identity_valid &&
wait_for_dev_node_state(devname, true)) {
detached = detach_attached_unit(backend, unit_id, &detach_state);
}
if (!detached && detach_state.requested)
detached = wait_for_attached_unit_release(backend, unit_id, &detach_state);
if (!detached) {
log_debug(" [IMG][%s] unpublished unit rollback pending: unit=%d error=%s",
attach_backend_name(backend), unit_id, strerror(errno));
}
}
static bool image_fs_type_is_pfs(image_fs_type_t fs_type) {
return fs_type == IMAGE_FS_PFS || fs_type == IMAGE_FS_PFSC_CONTAINER;
}
@@ -798,9 +835,9 @@ static attach_backend_t select_image_backend(const runtime_config_t *cfg,
}
static bool attach_image_device(
const char *file_path, const char *mount_point, image_fs_type_t fs_type,
bool mount_read_only, off_t file_size, attach_backend_t attach_backend,
int *unit_id_out, char *devname_out, size_t devname_size,
const char *file_path, image_fs_type_t fs_type, bool mount_read_only,
off_t file_size, attach_backend_t attach_backend, int *unit_id_out,
char *devname_out, size_t devname_size,
const image_mount_profile_t *profile, uint16_t lvd_image_type,
uint64_t generation) {
bool attached = false;
@@ -827,14 +864,9 @@ static bool attach_image_device(
attach_backend)) {
log_debug(" [IMG][%s] failed to publish attached unit: unit=%d source=%s",
attach_backend_name(attach_backend), *unit_id_out, file_path);
if (cache_image_mount(file_path, mount_point, *unit_id_out,
attach_backend)) {
(void)release_runtime_image_mount(file_path);
} else {
attached_unit_detach_state_t detach_state;
memset(&detach_state, 0, sizeof(detach_state));
(void)detach_attached_unit(attach_backend, *unit_id_out, &detach_state);
}
(void)cancel_image_attachment(file_path, generation);
rollback_unpublished_attached_unit(attach_backend, *unit_id_out,
devname_out);
errno = EIO;
return false;
}
@@ -1074,7 +1106,7 @@ static bool try_exfat_lvd_type_fallback(
.nested_backing_cache = false,
};
if (!attach_image_device(
file_path, mount_point, IMAGE_FS_EXFAT, mount_read_only, file_size,
file_path, IMAGE_FS_EXFAT, mount_read_only, file_size,
ATTACH_BACKEND_LVD, unit_id_out, devname_out, devname_size,
&fallback_profile, LVD_ATTACH_IMAGE_TYPE_SINGLE, generation)) {
return false;
@@ -1228,8 +1260,8 @@ bool mount_image(const char *file_path, image_fs_type_t fs_type) {
memset(devname, 0, sizeof(devname));
bool attached =
attach_image_device(
file_path, mount_point, fs_type, mount_read_only, st.st_size,
attach_backend, &unit_id, devname, sizeof(devname), &profile,
file_path, fs_type, mount_read_only, st.st_size, attach_backend,
&unit_id, devname, sizeof(devname), &profile,
get_lvd_image_type(file_path, fs_type, profile.legacy),
attachment_generation);
int attach_errno = errno;
@@ -1320,7 +1352,7 @@ static bool unmount_child_image_mounts_for_container(
: unmount_runtime_image(cached_entry.path, cached_entry.unit_id,
cached_entry.backend);
if (unmount_completed(result)) {
(void)invalidate_image_cache_entry(k, cached_entry.generation);
(void)invalidate_matching_image_cache_entry(k, &cached_entry);
continue;
}
@@ -1335,26 +1367,18 @@ static bool unmount_child_image_mounts_for_container(
}
static bool detach_cached_image_device(const char *file_path,
uint64_t generation,
attach_backend_t backend, int unit_id) {
image_cache_entry_t cached_entry;
bool cached_device = claim_image_cache_detach(
file_path, unit_id, backend, &cached_entry);
if (!cached_device && errno == EINPROGRESS)
if (!claim_image_cache_detach(file_path, generation, unit_id, backend,
&cached_entry))
return false;
attached_unit_detach_state_t detach_state;
memset(&detach_state, 0, sizeof(detach_state));
bool detach_was_requested = false;
if (cached_device) {
detach_state = cached_entry.detach_state;
detach_was_requested = detach_state.requested;
}
attached_unit_detach_state_t detach_state = cached_entry.detach_state;
bool detach_was_requested = detach_state.requested;
bool detached = detach_attached_unit(
backend, unit_id, cached_device ? &detach_state : NULL);
bool detached = detach_attached_unit(backend, unit_id, &detach_state);
int detach_errno = errno;
if (!cached_device)
return detached;
if (!finish_image_cache_detach_attempt(
file_path, cached_entry.generation, unit_id, backend,
@@ -1402,6 +1426,7 @@ static unmount_result_t unmount_image_impl(const char *file_path, int unit_id,
build_image_mount_point_for_fs(file_path, fs_type, mount_point);
int resolved_unit = unit_id;
attach_backend_t resolved_backend = backend;
uint64_t tracked_generation = 0;
if (resolved_unit < 0 || resolved_backend == ATTACH_BACKEND_NONE) {
if (!resolve_device_from_mount(mount_point, &resolved_backend,
@@ -1412,9 +1437,11 @@ static unmount_result_t unmount_image_impl(const char *file_path, int unit_id,
}
image_cache_entry_t tracked_entry;
if (find_image_cache_entry(file_path, &tracked_entry, NULL) &&
bool has_tracked_device =
find_image_cache_entry(file_path, &tracked_entry, NULL) &&
tracked_entry.backend != ATTACH_BACKEND_NONE &&
tracked_entry.unit_id >= 0) {
tracked_entry.unit_id >= 0;
if (has_tracked_device) {
if (tracked_entry.unit_id != resolved_unit ||
tracked_entry.backend != resolved_backend) {
result.error = ESTALE;
@@ -1429,10 +1456,19 @@ static unmount_result_t unmount_image_impl(const char *file_path, int unit_id,
if (!mark_image_cache_detach_requested(
tracked_entry.path, tracked_entry.generation,
tracked_entry.unit_id, tracked_entry.backend)) {
result.error = ESTALE;
result.error = errno != 0 ? errno : ESTALE;
log_debug(" [IMG][%s] unmount deferred before detach reservation: "
"source=%s unit=%d error=%s",
attach_backend_name(tracked_entry.backend), tracked_entry.path,
tracked_entry.unit_id, strerror(result.error));
errno = result.error;
return result;
}
tracked_generation = tracked_entry.generation;
} else if (resolved_backend != ATTACH_BACKEND_NONE && resolved_unit >= 0) {
result.error = ESTALE;
errno = result.error;
return result;
}
log_debug(" [IMG][%s] unmount start: source=%s mount=%s unit=%d",
@@ -1482,7 +1518,7 @@ static unmount_result_t unmount_image_impl(const char *file_path, int unit_id,
result.device_released = true;
if (resolved_backend != ATTACH_BACKEND_NONE && resolved_unit >= 0) {
result.device_released = detach_cached_image_device(
file_path, resolved_backend, resolved_unit);
file_path, tracked_generation, resolved_backend, resolved_unit);
if (!result.device_released)
result.error = errno != 0 ? errno : EIO;
}
@@ -1530,16 +1566,11 @@ static bool release_runtime_image_attachment(const char *file_path,
}
if (entry.backend == ATTACH_BACKEND_NONE || entry.unit_id < 0)
return cancel_image_attachment(file_path, generation);
if (!mark_image_cache_detach_requested(
entry.path, generation, entry.unit_id, entry.backend)) {
errno = ESTALE;
return false;
}
unmount_result_t result =
unmount_runtime_image(entry.path, entry.unit_id, entry.backend);
if (!unmount_completed(result))
return false;
(void)invalidate_image_cache_entry(index, generation);
(void)invalidate_matching_image_cache_entry(index, &entry);
return true;
}
@@ -1554,15 +1585,11 @@ bool release_runtime_image_mount(const char *file_path) {
}
if (entry.backend == ATTACH_BACKEND_NONE || entry.unit_id < 0)
return true;
if (!mark_image_cache_detach_requested(
entry.path, entry.generation, entry.unit_id, entry.backend)) {
return false;
}
unmount_result_t result =
unmount_runtime_image(entry.path, entry.unit_id, entry.backend);
if (!unmount_completed(result))
return false;
(void)invalidate_image_cache_entry(index, entry.generation);
(void)invalidate_matching_image_cache_entry(index, &entry);
return true;
}
@@ -1585,7 +1612,7 @@ bool release_runtime_image_mounts(void) {
unmount_result_t result =
unmount_runtime_image(entry.path, entry.unit_id, entry.backend);
if (unmount_completed(result)) {
(void)invalidate_image_cache_entry(k, entry.generation);
(void)invalidate_matching_image_cache_entry(k, &entry);
progress = true;
} else {
any_remaining = true;
@@ -1608,7 +1635,7 @@ static bool service_pending_image_detach(
unmount_result_t result =
unmount_runtime_image(entry->path, entry->unit_id, entry->backend);
if (unmount_completed(result))
(void)invalidate_image_cache_entry(cache_index, entry->generation);
(void)invalidate_matching_image_cache_entry(cache_index, entry);
return true;
}
@@ -1655,7 +1682,7 @@ void cleanup_stale_image_mounts(void) {
unmount_image(cached_entry.path, cached_entry.unit_id,
cached_entry.backend);
if (unmount_completed(result))
(void)invalidate_image_cache_entry(k, cached_entry.generation);
(void)invalidate_matching_image_cache_entry(k, &cached_entry);
continue;
}
@@ -1714,7 +1741,7 @@ void cleanup_stale_image_mounts_for_root(const char *root) {
unmount_image(cached_entry.path, cached_entry.unit_id,
cached_entry.backend);
if (unmount_completed(result))
(void)invalidate_image_cache_entry(k, cached_entry.generation);
(void)invalidate_matching_image_cache_entry(k, &cached_entry);
continue;
}
@@ -1764,7 +1791,7 @@ bool unmount_usb_image_mounts_for_suspend(void) {
if (unmount_completed(result)) {
log_debug(" [IMG][%s] USB suspend unmounted: %s",
attach_backend_name(cached_entry.backend), cached_entry.path);
(void)invalidate_image_cache_entry(k, cached_entry.generation);
(void)invalidate_matching_image_cache_entry(k, &cached_entry);
continue;
}
@@ -1868,7 +1895,7 @@ bool shutdown_image_mounts(void) {
unmount_result_t result = unmount_runtime_image(
cached_entry.path, cached_entry.unit_id, cached_entry.backend);
if (unmount_completed(result)) {
(void)invalidate_image_cache_entry(k, cached_entry.generation);
(void)invalidate_matching_image_cache_entry(k, &cached_entry);
progress = true;
continue;
}
+89 -28
View File
@@ -31,20 +31,25 @@ static uint64_t next_cache_generation(void) {
return g_image_cache_generation;
}
static bool attach_backend_is_valid(attach_backend_t backend) {
return backend == ATTACH_BACKEND_MD || backend == ATTACH_BACKEND_LVD;
}
static bool device_identity_matches(
const attached_unit_detach_state_t *left,
const attached_unit_detach_state_t *right) {
if (!left->node_identity_valid || !right->node_identity_valid)
return true;
return false;
return left->node_device == right->node_device &&
left->node_inode == right->node_inode &&
left->node_rdev == right->node_rdev;
}
static void capture_attached_unit_identity(struct ImageCache *entry) {
memset(&entry->detach_state, 0, sizeof(entry->detach_state));
if (entry->backend == ATTACH_BACKEND_NONE || entry->unit_id < 0)
return;
static bool refresh_attached_unit_identity(struct ImageCache *entry) {
if (!attach_backend_is_valid(entry->backend) || entry->unit_id < 0)
return false;
if (entry->detach_state.node_identity_valid)
return true;
const char *prefix =
entry->backend == ATTACH_BACKEND_MD ? "/dev/md" : "/dev/lvd";
@@ -53,12 +58,18 @@ static void capture_attached_unit_identity(struct ImageCache *entry) {
struct stat st;
if (stat(devname, &st) != 0)
return;
return false;
entry->detach_state.node_identity_valid = true;
entry->detach_state.node_device = (uint64_t)st.st_dev;
entry->detach_state.node_inode = (uint64_t)st.st_ino;
entry->detach_state.node_rdev = (uint64_t)st.st_rdev;
return true;
}
static void reset_attached_unit_identity(struct ImageCache *entry) {
memset(&entry->detach_state, 0, sizeof(entry->detach_state));
(void)refresh_attached_unit_identity(entry);
}
static void copy_cache_entry(int index, image_cache_entry_t *entry_out) {
@@ -285,7 +296,8 @@ bool cancel_image_attachment(const char *path, uint64_t generation) {
bool publish_image_attachment(const char *path, uint64_t generation,
int unit_id, attach_backend_t backend) {
if (!path || generation == 0 || unit_id < 0 ||
backend == ATTACH_BACKEND_NONE) {
!attach_backend_is_valid(backend)) {
errno = EINVAL;
return false;
}
@@ -302,15 +314,18 @@ bool publish_image_attachment(const char *path, uint64_t generation,
struct ImageCache *entry = &g_image_cache[index];
entry->unit_id = unit_id;
entry->backend = backend;
capture_attached_unit_identity(entry);
(void)refresh_attached_unit_identity(entry);
pthread_mutex_unlock(&g_image_cache_mutex);
return true;
}
bool complete_image_attachment(const char *path, uint64_t generation,
int unit_id, attach_backend_t backend) {
if (!path || generation == 0)
if (!path || generation == 0 || unit_id < 0 ||
!attach_backend_is_valid(backend)) {
errno = EINVAL;
return false;
}
pthread_mutex_lock(&g_image_cache_mutex);
int index = find_source_path_index(path);
@@ -323,13 +338,19 @@ bool complete_image_attachment(const char *path, uint64_t generation,
}
g_image_cache[index].state = ATTACHED_DEVICE_MOUNTED;
capture_attached_unit_identity(&g_image_cache[index]);
(void)refresh_attached_unit_identity(&g_image_cache[index]);
pthread_mutex_unlock(&g_image_cache_mutex);
return true;
}
bool cache_image_mount(const char *path, const char *mount_point, int unit_id,
attach_backend_t backend) {
if (!path || !mount_point || unit_id < 0 ||
!attach_backend_is_valid(backend)) {
errno = EINVAL;
return false;
}
pthread_mutex_lock(&g_image_cache_mutex);
int entry_index = upsert_image_source_mapping(path, mount_point);
if (entry_index < 0) {
@@ -343,7 +364,7 @@ bool cache_image_mount(const char *path, const char *mount_point, int unit_id,
entry->backend = backend;
entry->state = ATTACHED_DEVICE_MOUNTED;
entry->detach_attempt_active = false;
capture_attached_unit_identity(entry);
reset_attached_unit_identity(entry);
pthread_mutex_unlock(&g_image_cache_mutex);
return true;
}
@@ -381,47 +402,62 @@ bool find_image_cache_entry(const char *path, image_cache_entry_t *entry_out,
bool mark_image_cache_detach_requested(const char *path, uint64_t generation,
int unit_id,
attach_backend_t backend) {
if (!path || generation == 0)
if (!path || generation == 0 || unit_id < 0 ||
!attach_backend_is_valid(backend)) {
errno = EINVAL;
return false;
}
pthread_mutex_lock(&g_image_cache_mutex);
struct ImageCache *entry = find_attachment_record(
path, generation, unit_id, backend);
if (!entry) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = ESTALE;
return false;
}
entry->state = ATTACHED_DEVICE_DETACH_REQUESTED;
if (!refresh_attached_unit_identity(entry)) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = EAGAIN;
return false;
}
entry->state = ATTACHED_DEVICE_DETACH_REQUESTED;
pthread_mutex_unlock(&g_image_cache_mutex);
return true;
}
bool claim_image_cache_detach(const char *path, int unit_id,
attach_backend_t backend,
bool claim_image_cache_detach(const char *path, uint64_t generation,
int unit_id, attach_backend_t backend,
image_cache_entry_t *entry_out) {
if (!path || !entry_out) {
if (!path || generation == 0 || unit_id < 0 ||
!attach_backend_is_valid(backend) || !entry_out) {
errno = EINVAL;
return false;
}
pthread_mutex_lock(&g_image_cache_mutex);
int index = find_source_path_index(path);
if (index < 0 || g_image_cache[index].unit_id != unit_id ||
g_image_cache[index].backend != backend) {
struct ImageCache *entry =
find_attachment_record(path, generation, unit_id, backend);
if (!entry) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = ENOENT;
errno = ESTALE;
return false;
}
if (g_image_cache[index].detach_attempt_active) {
if (entry->detach_attempt_active) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = EINPROGRESS;
return false;
}
if (!refresh_attached_unit_identity(entry)) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = EAGAIN;
return false;
}
g_image_cache[index].state = ATTACHED_DEVICE_DETACH_REQUESTED;
g_image_cache[index].detach_attempt_active = true;
copy_cache_entry(index, entry_out);
entry->state = ATTACHED_DEVICE_DETACH_REQUESTED;
entry->detach_attempt_active = true;
copy_cache_entry((int)(entry - g_image_cache), entry_out);
pthread_mutex_unlock(&g_image_cache_mutex);
return true;
}
@@ -430,8 +466,12 @@ bool finish_image_cache_detach_attempt(
const char *path, uint64_t generation, int unit_id,
attach_backend_t backend,
const attached_unit_detach_state_t *detach_state) {
if (!path || !detach_state)
if (!path || generation == 0 || unit_id < 0 ||
!attach_backend_is_valid(backend) || !detach_state ||
!detach_state->node_identity_valid) {
errno = EINVAL;
return false;
}
pthread_mutex_lock(&g_image_cache_mutex);
struct ImageCache *entry = find_attachment_record(
@@ -439,6 +479,7 @@ bool finish_image_cache_detach_attempt(
if (!entry || !entry->detach_attempt_active ||
!device_identity_matches(&entry->detach_state, detach_state)) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = ESTALE;
return false;
}
@@ -449,12 +490,32 @@ bool finish_image_cache_detach_attempt(
return true;
}
bool invalidate_image_cache_entry(int index, uint64_t generation) {
bool invalidate_image_cache_entry(int index,
const image_cache_entry_t *expected) {
if (!expected) {
errno = EINVAL;
return false;
}
pthread_mutex_lock(&g_image_cache_mutex);
if (index < 0 || index >= MAX_IMAGE_MOUNTS ||
!g_image_cache[index].valid ||
g_image_cache[index].generation != generation) {
!g_image_cache[index].valid) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = ESTALE;
return false;
}
const struct ImageCache *entry = &g_image_cache[index];
if (entry->generation != expected->generation ||
strcmp(entry->path, expected->path) != 0 ||
strcmp(entry->mount_point, expected->mount_point) != 0 ||
entry->unit_id != expected->unit_id ||
entry->backend != expected->backend ||
entry->state != expected->state || entry->detach_attempt_active ||
entry->detach_state.requested != expected->detach_state.requested ||
!device_identity_matches(&entry->detach_state,
&expected->detach_state)) {
pthread_mutex_unlock(&g_image_cache_mutex);
errno = ESTALE;
return false;
}
g_image_cache[index].state = ATTACHED_DEVICE_RELEASED;
+37 -47
View File
@@ -212,6 +212,11 @@ static bool device_node_is_mounted(const char *devname,
static bool detach_target_is_released_or_reused(
attach_backend_t backend, int unit_id, const char *devname,
const attached_unit_detach_state_t *state) {
if (!state || !state->node_identity_valid) {
errno = EAGAIN;
return false;
}
struct stat st;
if (stat(devname, &st) != 0) {
if (errno != ENOENT && errno != ENOTDIR)
@@ -221,10 +226,9 @@ static bool detach_target_is_released_or_reused(
return true;
}
if (state && state->node_identity_valid &&
(state->node_device != (uint64_t)st.st_dev ||
state->node_inode != (uint64_t)st.st_ino ||
state->node_rdev != (uint64_t)st.st_rdev)) {
if (state->node_device != (uint64_t)st.st_dev ||
state->node_inode != (uint64_t)st.st_ino ||
state->node_rdev != (uint64_t)st.st_rdev) {
log_debug(" [IMG][%s] detach target released: unit=%d node identity "
"changed",
attach_backend_name(backend), unit_id);
@@ -252,43 +256,39 @@ static attached_unit_detach_prepare_t prepare_attached_unit_detach(
const attached_unit_detach_state_t *state, char devname[64],
attached_unit_detach_state_t *request_state) {
build_attached_unit_devname(backend, unit_id, devname);
*request_state = *state;
if (!request_state->node_identity_valid &&
!read_device_node_identity(devname, request_state)) {
log_debug(" [IMG][%s] detach deferred without device identity: unit=%d",
attach_backend_name(backend), unit_id);
errno = EAGAIN;
return ATTACHED_UNIT_DETACH_PENDING;
}
// A freshly attached unit may not have published its device node yet. An
// absent node is only proof of release after the node identity was observed
// or a detach request was accepted.
bool release_can_be_observed =
!state || state->requested || state->node_identity_valid;
if (release_can_be_observed &&
detach_target_is_released_or_reused(backend, unit_id, devname, state)) {
if (detach_target_is_released_or_reused(backend, unit_id, devname,
request_state)) {
return ATTACHED_UNIT_DETACH_COMPLETE;
}
if (!release_can_be_observed) {
struct stat st;
char mount_point[MNAMELEN];
if (stat(devname, &st) == 0 &&
device_node_is_mounted(devname, mount_point)) {
log_debug(" [IMG][%s] detach target released: unit=%d reused at %s",
attach_backend_name(backend), unit_id, mount_point);
return ATTACHED_UNIT_DETACH_COMPLETE;
}
}
if (state && state->requested) {
if (request_state->requested) {
errno = EINPROGRESS;
return ATTACHED_UNIT_DETACH_PENDING;
}
if (state)
*request_state = *state;
else
memset(request_state, 0, sizeof(*request_state));
if (!request_state->node_identity_valid)
(void)read_device_node_identity(devname, request_state);
return ATTACHED_UNIT_DETACH_REQUEST;
}
bool wait_for_attached_unit_release(
attach_backend_t backend, int unit_id,
const attached_unit_detach_state_t *state) {
if (!state || !state->node_identity_valid) {
errno = EAGAIN;
return false;
}
char devname[64];
build_attached_unit_devname(backend, unit_id, devname);
if (wait_for_dev_node_state(devname, false))
@@ -303,17 +303,12 @@ bool wait_for_attached_unit_release(
}
static bool finish_accepted_detach(
attach_backend_t backend, int unit_id,
attached_unit_detach_state_t *state,
attached_unit_detach_state_t *request_state) {
request_state->requested = true;
if (state) {
*state = *request_state;
errno = EINPROGRESS;
return false;
}
return wait_for_attached_unit_release(backend, unit_id, request_state);
*state = *request_state;
errno = EINPROGRESS;
return false;
}
static bool finish_failed_detach(attach_backend_t backend, int unit_id,
@@ -322,7 +317,7 @@ static bool finish_failed_detach(attach_backend_t backend, int unit_id,
int detach_errno) {
// Before a detach request is accepted, an unobserved node may still belong
// to the freshly attached unit. Keep it queued when the ioctl itself fails.
if (state && state->node_identity_valid &&
if (state->node_identity_valid &&
detach_target_is_released_or_reused(backend, unit_id, devname, state)) {
return true;
}
@@ -332,9 +327,6 @@ static bool finish_failed_detach(attach_backend_t backend, int unit_id,
static bool detach_lvd_unit(int unit_id,
attached_unit_detach_state_t *state) {
if (unit_id < 0)
return true;
char devname[64];
attached_unit_detach_state_t request_state;
attached_unit_detach_prepare_t prepare = prepare_attached_unit_detach(
@@ -367,15 +359,11 @@ static bool detach_lvd_unit(int unit_id,
}
close(fd);
return finish_accepted_detach(ATTACH_BACKEND_LVD, unit_id, state,
&request_state);
return finish_accepted_detach(state, &request_state);
}
static bool detach_md_unit(int unit_id,
attached_unit_detach_state_t *state) {
if (unit_id < 0)
return true;
char devname[64];
attached_unit_detach_state_t request_state;
attached_unit_detach_prepare_t prepare = prepare_attached_unit_detach(
@@ -409,15 +397,17 @@ static bool detach_md_unit(int unit_id,
}
close(fd);
return finish_accepted_detach(ATTACH_BACKEND_MD, unit_id, state,
&request_state);
return finish_accepted_detach(state, &request_state);
}
bool detach_attached_unit(attach_backend_t backend, int unit_id,
attached_unit_detach_state_t *state) {
if (!state || unit_id < 0 ||
(backend != ATTACH_BACKEND_MD && backend != ATTACH_BACKEND_LVD)) {
errno = EINVAL;
return false;
}
if (backend == ATTACH_BACKEND_MD)
return detach_md_unit(unit_id, state);
else if (backend == ATTACH_BACKEND_LVD)
return detach_lvd_unit(unit_id, state);
return true;
return detach_lvd_unit(unit_id, state);
}