Skip to content

Commit 1a03d3f

Browse files
Sebastian Andrzej SiewiorKAGA-KOKO
authored andcommitted
fork: Move task stack accounting to do_exit()
There is no need to perform the stack accounting of the outgoing task in its final schedule() invocation which happens with preemption disabled. The task is leaving, the resources will be freed and the accounting can happen in do_exit() before the actual schedule invocation which frees the stack memory. Move the accounting of the stack memory from release_task_stack() to exit_task_stack_account() which then can be invoked from do_exit(). Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Andy Lutomirski <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent f1c1a9e commit 1a03d3f

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

include/linux/sched/task_stack.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ static inline void *try_get_task_stack(struct task_struct *tsk)
7979
static inline void put_task_stack(struct task_struct *tsk) {}
8080
#endif
8181

82+
void exit_task_stack_account(struct task_struct *tsk);
83+
8284
#define task_stack_end_corrupted(task) \
8385
(*(end_of_stack(task)) != STACK_END_MAGIC)
8486

kernel/exit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ void __noreturn do_exit(long code)
845845
put_page(tsk->task_frag.page);
846846

847847
validate_creds_for_do_exit(tsk);
848+
exit_task_stack_account(tsk);
848849

849850
check_stack_usage();
850851
preempt_disable();

kernel/fork.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,8 @@ static int free_vm_stack_cache(unsigned int cpu)
211211
return 0;
212212
}
213213

214-
static int memcg_charge_kernel_stack(struct task_struct *tsk)
214+
static int memcg_charge_kernel_stack(struct vm_struct *vm)
215215
{
216-
struct vm_struct *vm = task_stack_vm_area(tsk);
217216
int i;
218217
int ret;
219218

@@ -239,6 +238,7 @@ static int memcg_charge_kernel_stack(struct task_struct *tsk)
239238

240239
static int alloc_thread_stack_node(struct task_struct *tsk, int node)
241240
{
241+
struct vm_struct *vm;
242242
void *stack;
243243
int i;
244244

@@ -256,7 +256,7 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
256256
/* Clear stale pointers from reused stack. */
257257
memset(s->addr, 0, THREAD_SIZE);
258258

259-
if (memcg_charge_kernel_stack(tsk)) {
259+
if (memcg_charge_kernel_stack(s)) {
260260
vfree(s->addr);
261261
return -ENOMEM;
262262
}
@@ -279,7 +279,8 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
279279
if (!stack)
280280
return -ENOMEM;
281281

282-
if (memcg_charge_kernel_stack(tsk)) {
282+
vm = find_vm_area(stack);
283+
if (memcg_charge_kernel_stack(vm)) {
283284
vfree(stack);
284285
return -ENOMEM;
285286
}
@@ -288,19 +289,15 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
288289
* free_thread_stack() can be called in interrupt context,
289290
* so cache the vm_struct.
290291
*/
291-
tsk->stack_vm_area = find_vm_area(stack);
292+
tsk->stack_vm_area = vm;
292293
tsk->stack = stack;
293294
return 0;
294295
}
295296

296297
static void free_thread_stack(struct task_struct *tsk)
297298
{
298-
struct vm_struct *vm = task_stack_vm_area(tsk);
299299
int i;
300300

301-
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++)
302-
memcg_kmem_uncharge_page(vm->pages[i], 0);
303-
304301
for (i = 0; i < NR_CACHED_STACKS; i++) {
305302
if (this_cpu_cmpxchg(cached_stacks[i], NULL,
306303
tsk->stack_vm_area) != NULL)
@@ -454,12 +451,25 @@ static void account_kernel_stack(struct task_struct *tsk, int account)
454451
}
455452
}
456453

454+
void exit_task_stack_account(struct task_struct *tsk)
455+
{
456+
account_kernel_stack(tsk, -1);
457+
458+
if (IS_ENABLED(CONFIG_VMAP_STACK)) {
459+
struct vm_struct *vm;
460+
int i;
461+
462+
vm = task_stack_vm_area(tsk);
463+
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++)
464+
memcg_kmem_uncharge_page(vm->pages[i], 0);
465+
}
466+
}
467+
457468
static void release_task_stack(struct task_struct *tsk)
458469
{
459470
if (WARN_ON(READ_ONCE(tsk->__state) != TASK_DEAD))
460471
return; /* Better to leak the stack than to free prematurely */
461472

462-
account_kernel_stack(tsk, -1);
463473
free_thread_stack(tsk);
464474
}
465475

@@ -918,6 +928,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
918928
#ifdef CONFIG_THREAD_INFO_IN_TASK
919929
refcount_set(&tsk->stack_refcount, 1);
920930
#endif
931+
account_kernel_stack(tsk, 1);
921932

922933
err = scs_prepare(tsk, node);
923934
if (err)
@@ -961,8 +972,6 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
961972
tsk->wake_q.next = NULL;
962973
tsk->worker_private = NULL;
963974

964-
account_kernel_stack(tsk, 1);
965-
966975
kcov_task_init(tsk);
967976
kmap_local_fork(tsk);
968977

@@ -981,6 +990,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
981990
return tsk;
982991

983992
free_stack:
993+
exit_task_stack_account(tsk);
984994
free_thread_stack(tsk);
985995
free_tsk:
986996
free_task_struct(tsk);
@@ -2459,6 +2469,7 @@ static __latent_entropy struct task_struct *copy_process(
24592469
exit_creds(p);
24602470
bad_fork_free:
24612471
WRITE_ONCE(p->__state, TASK_DEAD);
2472+
exit_task_stack_account(p);
24622473
put_task_stack(p);
24632474
delayed_free_task(p);
24642475
fork_out:

0 commit comments

Comments
 (0)