Add explicit configuring, starting, setup, started, and cancelled states. Serialize configuration and launch transitions with the builder mutex so configuration cannot change after task creation starts. Publish the eventual pid with release and acquire ordering. This state machine also provides the boundary for later one-shot claim and cancellation semantics. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Li Chen --- fs/pidfd_spawn.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/fs/pidfd_spawn.c b/fs/pidfd_spawn.c index 46207c8e8139f..99e3ef56ecfa3 100644 --- a/fs/pidfd_spawn.c +++ b/fs/pidfd_spawn.c @@ -22,6 +22,14 @@ #define PIDFD_SPAWN_MAX_CONFIG_KEY_SIZE 256 +enum pidfd_spawn_status { + PIDFD_SPAWN_CONFIGURING, + PIDFD_SPAWN_STARTING, + PIDFD_SPAWN_SETUP_DONE, + PIDFD_SPAWN_STARTED, + PIDFD_SPAWN_CANCELLED, +}; + struct pidfd_spawn_state { /* Serializes configuration and payload teardown. */ struct mutex lock; @@ -31,10 +39,45 @@ struct pidfd_spawn_state { const struct cred *creator_cred; struct pid_namespace *creator_pid_ns; char *staged_path; + enum pidfd_spawn_status status; }; +static struct pid * +pidfd_spawn_load_pid(const struct pidfd_spawn_state *state) +{ + /* Pair with the release publication in pidfd_spawn_publish_pid(). */ + return smp_load_acquire(&state->pid); +} + +static enum pidfd_spawn_status +pidfd_spawn_get_status(const struct pidfd_spawn_state *state) +{ + return READ_ONCE(state->status); +} + +static void pidfd_spawn_set_status(struct pidfd_spawn_state *state, + enum pidfd_spawn_status status) +{ + WRITE_ONCE(state->status, status); +} + static void pidfd_spawn_state_put(struct pidfd_spawn_state *state); +static int +pidfd_spawn_configuring_error(const struct pidfd_spawn_state *state) +{ + switch (pidfd_spawn_get_status(state)) { + case PIDFD_SPAWN_CONFIGURING: + return 0; + case PIDFD_SPAWN_CANCELLED: + if (!pidfd_spawn_load_pid(state)) + return -ECANCELED; + fallthrough; + default: + return -EBUSY; + } +} + static void pidfd_spawn_free_state(struct pidfd_spawn_state *state) { kfree(state->staged_path); @@ -73,7 +116,7 @@ static struct pid *pidfd_spawn_file_pid(void *data) struct pidfd_spawn_state *state = data; struct pid *pid; - pid = READ_ONCE(state->pid); + pid = pidfd_spawn_load_pid(state); return pid ? pid : ERR_PTR(-ESRCH); } @@ -136,6 +179,10 @@ static int pidfd_spawn_state_set_path(struct pidfd_spawn_state *state, return PTR_ERR(path); scoped_cond_guard(mutex_intr, return -EINTR, &state->lock) { + int ret = pidfd_spawn_configuring_error(state); + + if (ret) + return ret; if (!pidfd_spawn_same_creator(state)) return -EPERM; @@ -216,6 +263,7 @@ int pidfd_empty_open(unsigned int flags) state->creator_cred = get_current_cred(); state->creator_pid_ns = get_pid_ns(current->nsproxy->pid_ns_for_children); + pidfd_spawn_set_status(state, PIDFD_SPAWN_CONFIGURING); pidfile = pidfs_alloc_future_file("[pidfd_spawn]", state, &pidfd_spawn_future_ops, -- 2.52.0