[LTP] [PATCH v2 05/10] Rewrite semtest_2ns.c using new LTP API
Cyril Hrubis
chrubis@suse.cz
Thu Mar 10 17:37:13 CET 2022
Hi!
> +/*\
> + * [Description]
> + *
> + * Test SysV IPC semaphore usage between namespaces.
> + *
> + * [Algorithm]
> + *
> + * Create 2 'containers'
> + * In container1 create semaphore with a specific key
> + * In container2 try to access the semaphore created in container1
> + *
> + * Test is PASS if flag = none and the semaphore is accessible in container2 or
> + * if flag = unshare/clone and the semaphore is not accessible in container2.
> + * If semaphore is not accessible in container2, creates new semaphore with the
> + * same key to double check isloation in IPCNS.
> + *
> + * Test is FAIL if flag = none and the semaphore is not accessible, if
> + * flag = unshare/clone and semaphore is accessible in container2 or if the new
> + * semaphore creation Fails.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/wait.h>
> +#include <sys/msg.h>
> +#include <sys/types.h>
> #include <sys/sem.h>
> -#include <libclone.h>
> -#include "test.h"
> -#include "ipcns_helper.h"
> -
> -#define MY_KEY 124326L
> -#define UNSHARESTR "unshare"
> -#define CLONESTR "clone"
> -#define NONESTR "none"
> -
> -char *TCID = "semtest_2ns";
> -int TST_TOTAL = 1;
> -int p1[2];
> -int p2[2];
> +#include "tst_safe_sysv_ipc.h"
> +#include "tst_test.h"
> +#include "common.h"
> +
> +#define MY_KEY 124326L
> +
> +static char *str_op = "clone";
> +static int use_clone;
> +
> static struct sembuf semop_lock[2] = {
> /* sem_num, sem_op, flag */
> - {0, 0, 0}, /* wait for sem#0 to become 0 */
> - {0, 1, SEM_UNDO} /* then increment sem#0 by 1 */
> + { 0, 0, 0 }, /* wait for sem#0 to become 0 */
> + { 0, 1, SEM_UNDO } /* then increment sem#0 by 1 */
> };
>
> static struct sembuf semop_unlock[1] = {
> /* sem_num, sem_op, flag */
> - {0, -1, (IPC_NOWAIT | SEM_UNDO)} /* decrement sem#0 by 1 (sets it to 0) */
> + { 0, -1, (IPC_NOWAIT | SEM_UNDO) } /* decrement sem#0 by 1 (sets it to 0) */
> };
>
> /*
> * sem_lock() - Locks the semaphore for crit-sec updation, and unlocks it later
> */
> -void sem_lock(int id)
> +static void sem_lock(int id)
> {
> - /* Checking the semlock and simulating as if the crit-sec is updated */
> - if (semop(id, &semop_lock[0], 2) < 0) {
> - perror("sem lock error");
> - tst_brkm(TBROK, NULL, "semop failed");
> - }
> - tst_resm(TINFO, "Sem1: File locked, Critical section is updated...");
> + SAFE_SEMOP(id, &semop_lock[0], 2);
> +
> + tst_res(TINFO, "semaphore1: File locked, Critical section is updated...");
> +
> sleep(2);
> - if (semop(id, &semop_unlock[0], 1) < 0) {
> - perror("sem unlock error");
> - tst_brkm(TBROK, NULL, "semop failed");
> - }
> +
> + SAFE_SEMOP(id, &semop_unlock[0], 1);
> }
>
> /*
> * check_sem1 - does not read -- it writes to check_sem2() when it's done.
> */
> -int check_sem1(void *vtest)
> +static int check_sem1(LTP_ATTRIBUTE_UNUSED void *vtest)
> {
> - int id1;
> -
> - (void) vtest;
> -
> - close(p1[0]);
> - /* 1. Create (or fetch if existing) the binary semaphore */
> - id1 = semget(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666);
> - if (id1 == -1) {
> - perror("Semaphore create");
> - if (errno != EEXIST) {
> - perror("semget failure");
> - tst_brkm(TBROK, NULL, "semget failure");
> - }
> - id1 = semget(MY_KEY, 1, 0);
> - if (id1 == -1) {
> - perror("Semaphore create");
> - tst_brkm(TBROK, NULL, "semget failure");
> - }
> + TEST(semget(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666));
> + if (TST_RET < 0) {
> + tst_res(TINFO, "semget failure. Checking existing semaphore");
> +
> + if (TST_ERR != EEXIST)
> + tst_brk(TBROK | TRERRNO, "Semaphore creation failed");
> +
> + SAFE_SEMGET(MY_KEY, 1, 0);
> }
>
> - write(p1[1], "go", 3);
> - tst_resm(TINFO, "Cont1: Able to create semaphore");
> - tst_exit();
> + tst_res(TINFO, "container1: Able to create semaphore");
> +
> + return 0;
> }
>
> /*
> * check_sem2() reads from check_sem1() and writes to main() when it's done.
> */
> -
> -int check_sem2(void *vtest)
> +static int check_sem2(LTP_ATTRIBUTE_UNUSED void *vtest)
> {
> - char buf[3];
> - int id2;
> -
> - (void) vtest;
> + int id;
>
> - close(p1[1]);
> - close(p2[0]);
> - read(p1[0], buf, 3);
> + id = semget(MY_KEY, 1, 0);
> + if (id >= 0) {
> + sem_lock(id);
I wonder why we even call the sem_lock() here, it does not add any
value to the test and only slows it down for two seconds for no reason
in the case of -m none.
Looking at the code the whole test looks strange and does not make much
sense.
Looking at the check_sem1() I guess that it's supposed to create a
semaphore in one namespace, while the check_sem2() is trying to check if
that leaks into the second namespace. But without the checkpoint
synchronization the order is not guaranteed at all.
I guess that this should really be rewritten so that:
* check_sem1() creates the semaphore, then calls CHECKPOINT_WAKE()
* check_sem2() does CHEKPOINT_WAIT() then check if the semaphore does
exists
That is the very basic test we should do.
On the top of that we can make the check_sem1() to also lock the
semaphore between the call to wake the other process. And the other
process check_sem2() can attempt to lock it as well with IPC_NOWAIT. If
that fails the reference to the semaphore somehow leaked even if the
namespaces are isolated.
--
Cyril Hrubis
chrubis@suse.cz
More information about the ltp
mailing list