Re: [PATCH v15] semctl01: fix SEM_STAT failures under parallel LTP runs

Andrea Cervesato via ltp <[email protected]> Tue, 04 Aug 2026 13:03:19 +0000
Newsgroups gmane.linux.ltp
Message-ID <[email protected]>
Hi Stephan,

> diff --git a/include/tse_newipc.h b/include/tse_newipc.h
> index 1d3bbd129..175a60234 100644
> --- a/include/tse_newipc.h
> +++ b/include/tse_newipc.h
> @@ -49,4 +49,24 @@ void *probe_free_addr(const char *file, const int lineno);
>  #define PROBE_FREE_ADDR() \
>  	probe_free_addr(__FILE__, __LINE__)
>  
> +/**
> + * get_ipc_idx_from_id() - Find the kernel index of an IPC resource by id.
> + *
> + * @id: The msqid/semid/shmid to look for.
> + * @max_idx: Highest kernel index to search, from IPC_INFO/SEM_INFO/SHM_INFO.
> + * @stat_fn: Per-family *_STAT wrapper called as stat_fn(idx, buf) for
> + *           each idx in [0, max_idx]; must return the id at idx, or -1
> + *           on error, without aborting the test.
> + * @buf: Buffer passed through to @stat_fn.
> + *
> + * SysV *_STAT commands (MSG_STAT/SEM_STAT/SHM_STAT) take a kernel array
> + * index rather than the id returned by *get(), and that index is not
> + * guaranteed to match the id when other IPC users are active. This walks
> + * the live indices to find the one that currently maps to @id.
> + *
> + * Return: The kernel index mapping to @id, or -1 if none was found.
> + */
> +int get_ipc_idx_from_id(int id, int max_idx,
> +			int (*stat_fn)(int idx, void *buf), void *buf);
> +
>  #endif /* tse_newipc.h */
> diff --git a/libs/newipc/tse_newipc.c b/libs/newipc/tse_newipc.c
> index f7edda6b5..aee286a31 100644
> --- a/libs/newipc/tse_newipc.c
> +++ b/libs/newipc/tse_newipc.c
> @@ -86,3 +86,16 @@ void *probe_free_addr(const char *file, const int lineno)
>  
>  	return addr;
>  }
> +
> +int get_ipc_idx_from_id(int id, int max_idx,
> +			int (*stat_fn)(int idx, void *buf), void *buf)
> +{
> +	int i;
> +
> +	for (i = 0; i <= max_idx; i++) {
> +		if (stat_fn(i, buf) == id)
> +			return i;
> +	}
> +
> +	return -1;
> +}

can we add patch 1/2 for this..

> diff --git a/testcases/kernel/syscalls/semctl/Makefile b/testcases/kernel/syscalls/semctl/Makefile
> index 0e7223998..1f1ec9c81 100644
> --- a/testcases/kernel/syscalls/semctl/Makefile
> +++ b/testcases/kernel/syscalls/semctl/Makefile
> @@ -8,6 +8,6 @@ LTPLIBS = ipc newipc
>  include $(top_srcdir)/include/mk/testcases.mk
>  
>  semctl06: LTPLDLIBS = -lltpipc
> -semctl02 semctl03 semctl04 semctl05 semctl07 semctl08 semctl09: LTPLDLIBS = -lltpnewipc
> +semctl01 semctl02 semctl03 semctl04 semctl05 semctl07 semctl08 semctl09: LTPLDLIBS = -lltpnewipc
>  
>  include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syscalls/semctl/semctl01.c b/testcases/kernel/syscalls/semctl/semctl01.c
> index 5bd675ab6..398cb3028 100644
> --- a/testcases/kernel/syscalls/semctl/semctl01.c
> +++ b/testcases/kernel/syscalls/semctl/semctl01.c
> @@ -210,13 +210,16 @@ static void func_rmid(void)
>  
>  static void func_iinfo(int hidx)
>  {
> -	if (hidx >= 0) {
> -		sem_index = hidx;
> -		tst_res(TPASS, "the highest index is correct");
> -	} else {
> -		sem_index = 0;
> -		tst_res(TFAIL, "the highest index is incorrect");
> -	}
> +	/*
> +	 * Return value is the highest used index. Our set is alive, so the
> +	 * highest used index must be at least our index.
> +	 */
> +	if (hidx >= sem_index)
> +		tst_res(TPASS, "IPC_INFO highest index %d >= our index %d",
> +			hidx, sem_index);
> +	else
> +		tst_res(TFAIL, "IPC_INFO highest index %d < our index %d",
> +			hidx, sem_index);
>  }
>  
>  static void func_sinfo(void)
> @@ -227,12 +230,54 @@ static void func_sinfo(void)
>  		tst_res(TPASS, "number of semaphore sets is correct");
>  }
>  
> -static void func_sstat(int semidx)
> +/*
> + * SEM_STAT fills buf the same way IPC_STAT does. sem_nsems and
> + * sem_perm.mode (set via IPC_SET earlier) verify SEM_STAT's own data,
> + * not just the id already used to find sem_index.
> + */
> +static void func_sstat(int semid)
>  {
> -	if (semidx >= 0)
> -		tst_res(TPASS, "id of the semaphore set is correct");
> +	if (semid != sem_id) {
> +		tst_res(TFAIL, "expected sem_id %d, got %d", sem_id, semid);
> +		return;
> +	}
> +
> +	if (buf.sem_nsems == PSEMS && buf.sem_perm.mode == (SEM_RA | NEWMODE))
> +		tst_res(TPASS, "id and semaphore STAT info are correct (id=%d)",
> +			sem_id);
>  	else
> -		tst_res(TFAIL, "id of the semaphore set is incorrect");
> +		tst_res(TFAIL, "nsems=%d (expected %d), mode=%o (expected %o)",
> +			(int)buf.sem_nsems, PSEMS,
> +			buf.sem_perm.mode, (SEM_RA | NEWMODE));
> +}
> +
> +/*
> + * SAFE_SEMCTL() would abort the test on per-index failures.
> + */
> +static int sem_stat(int idx, void *buf)
> +{
> +	union semun arg;
> +
> +	arg.buf = buf;
> +	return semctl(idx, 0, SEM_STAT, arg);
> +}
> +
> +/*
> + * SEM_STAT takes an index into the kernel's internal array, not a semid.
> + * Return the index that maps to this test's set.
> + */
> +static int get_sem_idx_from_id(int id)
> +{
> +	struct seminfo info;
> +	struct semid_ds dummy_ds;
> +	union semun arg;
> +	int max_idx;
> +
> +	arg.__buf = &info;
> +	/* SEM_INFO ignores semid; but SAFE_SEMCTL requires an lvalue */
> +	max_idx = SAFE_SEMCTL(id, 0, SEM_INFO, arg);
> +
> +	return get_ipc_idx_from_id(id, max_idx, sem_stat, &dummy_ds);
>  }
>  
>  static struct tcases {
> @@ -263,8 +308,15 @@ static void verify_semctl(unsigned int n)
>  	struct tcases *tc = &tests[n];
>  	int rval;
>  
> -	if (sem_id == -1)
> +	if (sem_id == -1) {
>  		sem_id = SAFE_SEMGET(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
> +		sem_index = get_sem_idx_from_id(sem_id);
> +		if (sem_index < 0)
> +			tst_brk(TBROK,
> +				"Failed to get sem_id %d to idx mapping", sem_id);
> +		tst_res(TINFO, "sem_id=%d maps to kernel index=%d",
> +			sem_id, sem_index);
> +	}
>  	if (tc->func_setup) {
>  		switch (tc->cmd) {
>  		case GETNCNT:
> diff --git a/testcases/kernel/syscalls/shmctl/shmctl01.c b/testcases/kernel/syscalls/shmctl/shmctl01.c
> index 05aea58cc..bfc11fa39 100644
> --- a/testcases/kernel/syscalls/shmctl/shmctl01.c
> +++ b/testcases/kernel/syscalls/shmctl/shmctl01.c
> @@ -224,20 +224,20 @@ static void dummy_sighandler(int sig)
>  	(void)sig;
>  }
>  
> +static int shm_stat(int idx, void *buf)
> +{
> +	return shmctl(idx, SHM_STAT, buf);
> +}
> +
>  static int get_shm_idx_from_id(int shm_id)
>  {
>  	struct shm_info dummy;
>  	struct shmid_ds dummy_ds;
> -	int max_idx, i;
> +	int max_idx;
>  
>  	max_idx = SAFE_SHMCTL(shm_id, SHM_INFO, (void *)&dummy);
>  
> -	for (i = 0; i <= max_idx; i++) {
> -		if (shmctl(i, SHM_STAT, &dummy_ds) == shm_id)
> -			return i;
> -	}
> -
> -	return -1;
> +	return get_ipc_idx_from_id(shm_id, max_idx, shm_stat, &dummy_ds);
>  }
>  
>  static void setup(void)
> -- 
> 2.55.0
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

And patch 2/2 for this?

--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato-IBi9RG/[email protected]

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp