* [LTP] [PATCH] containers: added mountns/mountns05.c
@ 2014-10-30 15:07 Matus Marhefka
2014-10-30 16:01 ` Cyril Hrubis
2014-11-05 16:49 ` [LTP] [PATCH v2] " Matus Marhefka
0 siblings, 2 replies; 7+ messages in thread
From: Matus Marhefka @ 2014-10-30 15:07 UTC (permalink / raw)
To: ltp-list
Tests a slave-shared mount: slave-shared mount makes
a mountpoint both, shared and slave at the same time.
Signed-off-by: Matus Marhefka <mmarhefk@redhat.com>
---
runtest/containers | 1 +
testcases/kernel/containers/.gitignore | 1 +
testcases/kernel/containers/mountns/mountns05.c | 375 +++++++++++++++++++++
.../kernel/containers/mountns/mountns_helper.h | 4 +
4 files changed, 381 insertions(+)
create mode 100644 testcases/kernel/containers/mountns/mountns05.c
diff --git a/runtest/containers b/runtest/containers
index 6535628..54b9fd2 100644
--- a/runtest/containers
+++ b/runtest/containers
@@ -67,3 +67,4 @@ mountns01 mountns01
mountns02 mountns02
mountns03 mountns03
mountns04 mountns04
+mountns05 mountns05
diff --git a/testcases/kernel/containers/.gitignore b/testcases/kernel/containers/.gitignore
index 4a98373..386e211 100644
--- a/testcases/kernel/containers/.gitignore
+++ b/testcases/kernel/containers/.gitignore
@@ -3,3 +3,4 @@ mountns/mountns01
mountns/mountns02
mountns/mountns03
mountns/mountns04
+mountns/mountns05
diff --git a/testcases/kernel/containers/mountns/mountns05.c b/testcases/kernel/containers/mountns/mountns05.c
new file mode 100644
index 0000000..d1e61aa
--- /dev/null
+++ b/testcases/kernel/containers/mountns/mountns05.c
@@ -0,0 +1,375 @@
+/* Copyright (c) 2014 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ ***********************************************************************
+ * File: mountns05.c
+ *
+ * Tests a slave-shared mount: slave-shared mount makes a mountpoint both,
+ * shared and slave at the same time.
+ * Description (X is parent namespace, Y and Z are child namespaces):
+ * 1. Creates directories "A", "B" and files "A/A", "B/B"
+ * 2. Unshares mount namespace and makes it private (so mounts/umounts
+ * have no effect on a real system)
+ * 3. Bind mounts directory "A" to "A"
+ * 4. Makes directory "A" shared
+ * 5. Clones a new child process with CLONE_NEWNS flag (creates namespace Y)
+ * 6. The new child (namespace Y) makes "A" a slave mount (of mount in parent
+ * namespace X) and also makes "A" shared inside its (Y) namespace
+ * 7. The new child process (namespace Y) clones a new child with CLONE_NEWNS
+ * flag (creates namespace Z)
+ * 6. There are two test cases:
+ * 1)
+ * X: bind mounts "B" to "A"
+ * Y: must see "A/B"
+ * Z: must see "A/B"
+ * X: umounts "A"
+ * 2)
+ * Y: bind mounts "B" to "A"
+ * X: must see only "A/A" - slave cannot propagate up
+ * Z: must see "A/B" - NS Z shares "A" with NS Y
+ * Y: umounts "A"
+ * 3)
+ * Z: bind mounts "B" to "A"
+ * X: must see only "A/A" - slave cannot propagate up
+ * Y: must see "A/B" - NS Y shares "A" with NS Z
+ * Z: umounts "A"
+ ***********************************************************************/
+
+#define _GNU_SOURCE
+#include <sys/wait.h>
+#include <sys/mount.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/msg.h>
+#include "test.h"
+#include "usctest.h"
+#include "libclone.h"
+#include "safe_macros.h"
+#include "safe_file_ops.h"
+#include "mountns_helper.h"
+
+
+#define TC1_MSG "parent: shared mount propagation to slave mount shared between two children"
+#define TC2_MSG "child1: slave-shared mount inability to prapagate up to " \
+ "master and ability to propagate to shared mount with child2"
+#define TC3_MSG "child2: slave-shared mount inability to prapagate up to " \
+ "master and ability to propagate to shared mount with child1"
+
+#define TESTKEY 124426L
+#define TC1_OK 0x01
+#define TC2_OK 0x02
+#define TC3_OK 0x04
+#define ERRC 0x10
+
+#define REPORT_PARENT_ERROR(errmsg) \
+{ \
+ msgctl(id, IPC_RMID, NULL); \
+ tst_brkm(TBROK | TERRNO, cleanup, errmsg); \
+}
+
+#define REPORT_CHLD_ERROR(errmsg) \
+{ \
+ perror(errmsg); umount(DIRA); \
+ msgctl(id, IPC_RMID, NULL); \
+ wait(&status); return ERRC; \
+}
+
+char *TCID = "mountns05";
+int TST_TOTAL = 3;
+
+
+#if defined(MS_SHARED) && defined(MS_PRIVATE) \
+ && defined(MS_REC) && defined(MS_SLAVE)
+
+int child_func2(void *arg)
+{
+ int status;
+ int id, result = TC3_OK;
+ struct msgbuf m, r;
+ m.mtype = 3;
+
+ id = msgget(TESTKEY, 0644);
+ if (id == -1)
+ REPORT_CHLD_ERROR("msgget");
+
+ /* TC#1 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC1_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+ /* END OF TC#1 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ /* TC#2 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC2_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+ /* END OF TC#2 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ /* TC#3 */
+ /* bind mounts DIRB to DIRA */
+ if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1)
+ REPORT_CHLD_ERROR("mount");
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ umount(DIRA);
+ /* END OF TC#3 */
+
+ return result;
+}
+
+int child_func1(void *arg)
+{
+ int status, id, result = TC2_OK;
+ struct msgbuf m, r;
+ m.mtype = 2;
+
+ id = msgget(TESTKEY, 0644);
+ if (id == -1)
+ REPORT_CHLD_ERROR("msgget");
+
+ /* makes mount DIRA a slave mount (of DIRA in parent NS) */
+ if (mount("none", DIRA, "none", MS_SLAVE, NULL) == -1)
+ REPORT_CHLD_ERROR("mount");
+
+ /* makes mount DIRA a shared mount inside child NS */
+ if (mount("none", DIRA, "none", MS_SHARED, NULL) == -1)
+ REPORT_CHLD_ERROR("mount");
+
+ if (do_clone_tests(CLONE_NEWNS, child_func2, NULL, NULL, NULL) == -1)
+ REPORT_CHLD_ERROR("clone");
+
+ /* sync with parent*/
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+
+ /* TC#1 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC1_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+ /* END OF TC#1 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ /* TC#2 */
+ /* bind mounts DIRB to DIRA */
+ if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1)
+ REPORT_CHLD_ERROR("mount");
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ umount(DIRA);
+ /* END OF TC#2 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ /* TC#3 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1)
+ REPORT_CHLD_ERROR("msgrcv");
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC3_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_CHLD_ERROR("msgsnd");
+ /* END OF TC#3 */
+
+ wait(&status);
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) & ERRC)
+ return ERRC;
+ return (result & WEXITSTATUS(status));
+ } else {
+ return ERRC;
+ }
+}
+
+static void test(void)
+{
+ int status, id, result = TC1_OK;
+ struct msgbuf m, r, sync;
+ m.mtype = 1;
+ sync.mtype = 4;
+
+ /* unshares the mount ns */
+ if (unshare(CLONE_NEWNS) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup, "unshare failed");
+ /* makes sure parent mounts/umounts have no effect on a real system */
+ SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL);
+
+ /* bind mounts DIRA to itself */
+ SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL);
+
+ /* makes mount DIRA shared */
+ SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL);
+
+ id = msgget(TESTKEY, IPC_CREAT | 0644);
+ if (id == -1)
+ tst_brkm(TBROK | TERRNO, cleanup, "msgget");
+
+ if (do_clone_tests(CLONE_NEWNS, child_func1, NULL, NULL, NULL) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup, "clone");
+
+ /* sync with child1 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ REPORT_PARENT_ERROR("msgrcv");
+
+ /* TC#1 */
+ /* bind mounts DIRB to DIRA */
+ SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL);
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ REPORT_PARENT_ERROR("msgrcv");
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1)
+ REPORT_PARENT_ERROR("msgrcv");
+
+ SAFE_UMOUNT(cleanup, DIRA);
+ /* END OF TC#1 */
+
+ /* sync with children */
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+
+ /* TC#2 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ REPORT_PARENT_ERROR("msgrcv");
+
+ if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1))
+ result |= TC2_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+ /* END OF TC#2 */
+
+ /* sync with children */
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+
+ /* TC#3 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1)
+ REPORT_PARENT_ERROR("msgrcv");
+
+ if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1))
+ result |= TC3_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ REPORT_PARENT_ERROR("msgsnd");
+ /* END OF TC#3 */
+
+
+ SAFE_WAIT(cleanup, &status);
+ if (WIFEXITED(status)) {
+ result &= WEXITSTATUS(status);
+ if (result & ERRC)
+ tst_brkm(TBROK, cleanup, "error in child");
+ }
+ if (WIFSIGNALED(status)) {
+ tst_resm(TBROK, "child was killed with signal %s",
+ tst_strsig(WTERMSIG(status)));
+ return;
+ }
+
+ msgctl(id, IPC_RMID, NULL);
+ SAFE_UMOUNT(cleanup, DIRA);
+
+ if ((result & TC1_OK) == TC1_OK)
+ tst_resm(TPASS, TC1_MSG);
+ else
+ tst_resm(TFAIL, TC1_MSG);
+
+ if ((result & TC2_OK) == TC2_OK)
+ tst_resm(TPASS, TC2_MSG);
+ else
+ tst_resm(TFAIL, TC2_MSG);
+
+ if ((result & TC3_OK) == TC3_OK)
+ tst_resm(TPASS, TC3_MSG);
+ else
+ tst_resm(TFAIL, TC3_MSG);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *msg;
+ int lc;
+
+ msg = parse_opts(argc, argv, NULL, NULL);
+ if (msg != NULL)
+ tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+ setup();
+
+ for (lc = 0; TEST_LOOPING(lc); lc++)
+ test();
+
+ cleanup();
+ tst_exit();
+}
+
+#else
+int main(void)
+{
+ tst_brkm(TCONF, NULL, "needed mountflags are not defined");
+}
+#endif
diff --git a/testcases/kernel/containers/mountns/mountns_helper.h b/testcases/kernel/containers/mountns/mountns_helper.h
index d4a6a91..d82c837 100644
--- a/testcases/kernel/containers/mountns/mountns_helper.h
+++ b/testcases/kernel/containers/mountns/mountns_helper.h
@@ -47,6 +47,10 @@ static int check_newns(void)
static void cleanup(void)
{
+ int status;
+
+ wait(&status);
+ umount(DIRA);
umount(DIRA);
umount(DIRB);
tst_rmdir();
--
1.8.3.1
------------------------------------------------------------------------------
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH] containers: added mountns/mountns05.c
2014-10-30 15:07 [LTP] [PATCH] containers: added mountns/mountns05.c Matus Marhefka
@ 2014-10-30 16:01 ` Cyril Hrubis
2014-11-05 16:49 ` [LTP] [PATCH v2] " Matus Marhefka
1 sibling, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2014-10-30 16:01 UTC (permalink / raw)
To: Matus Marhefka; +Cc: ltp-list
Hi!
I do not like these macros.
> +#define REPORT_PARENT_ERROR(errmsg) \
> +{ \
> + msgctl(id, IPC_RMID, NULL); \
^
This should be removed from the test cleanup.
If you want to call the default cleanup defined in the header
you can define second cleanup function that does specific
cleanup and then calls the generic cleanup pass the right
function pointers to tst_brmk()
> + tst_brkm(TBROK | TERRNO, cleanup, errmsg); \
> +}
> +
> +#define REPORT_CHLD_ERROR(errmsg) \
> +{ \
> + perror(errmsg); umount(DIRA); \
> + msgctl(id, IPC_RMID, NULL); \
> + wait(&status); return ERRC; \
> +}
Can't we do the cleanup the kenel style?
i.e.
if (something_failed()) {
errmsg = "message";
goto err;
}
...
return result;
err:
perror(errmsg);
umout(DIRA);
msgclt(id, IPC_RMID, NULL);
wait(&status);
return ERRC;
...
> diff --git a/testcases/kernel/containers/mountns/mountns_helper.h b/testcases/kernel/containers/mountns/mountns_helper.h
> index d4a6a91..d82c837 100644
> --- a/testcases/kernel/containers/mountns/mountns_helper.h
> +++ b/testcases/kernel/containers/mountns/mountns_helper.h
> @@ -47,6 +47,10 @@ static int check_newns(void)
>
> static void cleanup(void)
> {
> + int status;
> +
> + wait(&status);
> + umount(DIRA);
> umount(DIRA);
> umount(DIRB);
> tst_rmdir();
This changes function called from several testcases, I guess that this
is missing cleanup being added there. Maybe it should deserve to be
pushed as a separate patch with description in commit message.
--
Cyril Hrubis
chrubis@suse.cz
------------------------------------------------------------------------------
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply [flat|nested] 7+ messages in thread
* [LTP] [PATCH v2] containers: added mountns/mountns05.c
2014-10-30 15:07 [LTP] [PATCH] containers: added mountns/mountns05.c Matus Marhefka
2014-10-30 16:01 ` Cyril Hrubis
@ 2014-11-05 16:49 ` Matus Marhefka
2014-12-02 16:42 ` Cyril Hrubis
1 sibling, 1 reply; 7+ messages in thread
From: Matus Marhefka @ 2014-11-05 16:49 UTC (permalink / raw)
To: ltp-list
Tests a slave-shared mount: slave-shared mount makes
a mountpoint both, shared and slave at the same time.
Signed-off-by: Matus Marhefka <mmarhefk@redhat.com>
---
runtest/containers | 1 +
testcases/kernel/containers/.gitignore | 1 +
testcases/kernel/containers/mountns/mountns05.c | 448 ++++++++++++++++++++++++
3 files changed, 450 insertions(+)
create mode 100644 testcases/kernel/containers/mountns/mountns05.c
diff --git a/runtest/containers b/runtest/containers
index 6535628..54b9fd2 100644
--- a/runtest/containers
+++ b/runtest/containers
@@ -67,3 +67,4 @@ mountns01 mountns01
mountns02 mountns02
mountns03 mountns03
mountns04 mountns04
+mountns05 mountns05
diff --git a/testcases/kernel/containers/.gitignore b/testcases/kernel/containers/.gitignore
index 4a98373..386e211 100644
--- a/testcases/kernel/containers/.gitignore
+++ b/testcases/kernel/containers/.gitignore
@@ -3,3 +3,4 @@ mountns/mountns01
mountns/mountns02
mountns/mountns03
mountns/mountns04
+mountns/mountns05
diff --git a/testcases/kernel/containers/mountns/mountns05.c b/testcases/kernel/containers/mountns/mountns05.c
new file mode 100644
index 0000000..a75f1bc
--- /dev/null
+++ b/testcases/kernel/containers/mountns/mountns05.c
@@ -0,0 +1,448 @@
+/* Copyright (c) 2014 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ ***********************************************************************
+ * File: mountns05.c
+ *
+ * Tests a slave-shared mount: slave-shared mount makes a mountpoint both,
+ * shared and slave at the same time.
+ * Description (X is parent namespace, Y and Z are child namespaces):
+ * 1. Creates directories "A", "B" and files "A/A", "B/B"
+ * 2. Unshares mount namespace and makes it private (so mounts/umounts
+ * have no effect on a real system)
+ * 3. Bind mounts directory "A" to "A"
+ * 4. Makes directory "A" shared
+ * 5. Clones a new child process with CLONE_NEWNS flag (creates namespace Y)
+ * 6. The new child (namespace Y) makes "A" a slave mount (of mount in parent
+ * namespace X) and also makes "A" shared inside its (Y) namespace
+ * 7. The new child process (namespace Y) clones a new child with CLONE_NEWNS
+ * flag (creates namespace Z)
+ * 6. There are three test cases:
+ * 1)
+ * X: bind mounts "B" to "A"
+ * Y: must see "A/B"
+ * Z: must see "A/B"
+ * X: umounts "A"
+ * 2)
+ * Y: bind mounts "B" to "A"
+ * X: must see only "A/A" - slave cannot propagate up
+ * Z: must see "A/B" - NS Z shares "A" with NS Y
+ * Y: umounts "A"
+ * 3)
+ * Z: bind mounts "B" to "A"
+ * X: must see only "A/A" - slave cannot propagate up
+ * Y: must see "A/B" - NS Y shares "A" with NS Z
+ * Z: umounts "A"
+ ***********************************************************************/
+
+#define _GNU_SOURCE
+#include <sys/wait.h>
+#include <sys/mount.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/msg.h>
+#include "test.h"
+#include "usctest.h"
+#include "libclone.h"
+#include "safe_macros.h"
+#include "safe_file_ops.h"
+#include "mountns_helper.h"
+
+
+#define TC1_MSG "parent: shared mount propagation to slave mount shared " \
+ " between two children"
+#define TC2_MSG "child1: slave-shared mount inability to prapagate up to " \
+ "master and ability to propagate to shared mount with child2"
+#define TC3_MSG "child2: slave-shared mount inability to prapagate up to " \
+ "master and ability to propagate to shared mount with child1"
+
+#define TESTKEY 124426L
+#define TC1_OK 0x01
+#define TC2_OK 0x02
+#define TC3_OK 0x04
+#define ERRC 0x10
+
+
+char *TCID = "mountns05";
+int TST_TOTAL = 3;
+int id;
+
+
+#if defined(MS_SHARED) && defined(MS_PRIVATE) \
+ && defined(MS_REC) && defined(MS_SLAVE)
+
+int child_func2(void *arg)
+{
+ int result = TC3_OK;
+ char *errmsg;
+ struct msgbuf m, r;
+
+ m.mtype = 3;
+
+ id = msgget(TESTKEY, 0644);
+ if (id == -1) {
+ errmsg = "msgget";
+ goto err;
+ }
+
+ /* TC#1 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC1_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+ /* END OF TC#1 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ /* TC#2 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC2_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+ /* END OF TC#2 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ /* TC#3 */
+ /* bind mounts DIRB to DIRA */
+ if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) {
+ errmsg = "mount";
+ goto err;
+ }
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ umount(DIRA);
+ /* END OF TC#3 */
+
+ return result;
+
+err:
+ perror(errmsg);
+ umount(DIRA);
+ msgctl(id, IPC_RMID, NULL);
+ return ERRC;
+}
+
+int child_func1(void *arg)
+{
+ int status, result = TC2_OK;
+ char *errmsg;
+ struct msgbuf m, r;
+
+ m.mtype = 2;
+
+ id = msgget(TESTKEY, 0644);
+ if (id == -1) {
+ errmsg = "msgget";
+ goto err;
+ }
+
+ /* makes mount DIRA a slave mount (of DIRA in parent NS) */
+ if (mount("none", DIRA, "none", MS_SLAVE, NULL) == -1) {
+ errmsg = "mount";
+ goto err;
+ }
+
+ /* makes mount DIRA a shared mount inside child NS */
+ if (mount("none", DIRA, "none", MS_SHARED, NULL) == -1) {
+ errmsg = "mount";
+ goto err;
+ }
+
+ if (do_clone_tests(CLONE_NEWNS, child_func2, NULL, NULL, NULL) == -1) {
+ errmsg = "clone";
+ goto err;
+ }
+
+ /* sync with parent*/
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+
+ /* TC#1 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC1_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+ /* END OF TC#1 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ /* TC#2 */
+ /* bind mounts DIRB to DIRA */
+ if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) {
+ errmsg = "mount";
+ goto err;
+ }
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+
+ if (msgrcv(id, &r, sizeof(r.mtext), 1, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ umount(DIRA);
+ /* END OF TC#2 */
+
+ /* sync with parent */
+ if (msgrcv(id, &r, sizeof(r.mtext), 4, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ /* TC#3 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1) {
+ errmsg = "msgrcv";
+ goto err;
+ }
+
+ if (access(DIRA"/B", F_OK) == 0)
+ result |= TC3_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1) {
+ errmsg = "msgsnd";
+ goto err;
+ }
+ /* END OF TC#3 */
+
+ wait(&status);
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) & ERRC)
+ return ERRC;
+ return (result & WEXITSTATUS(status));
+ } else {
+ return ERRC;
+ }
+
+err:
+ perror(errmsg);
+ umount(DIRA);
+ msgctl(id, IPC_RMID, NULL);
+ wait(&status);
+ return ERRC;
+}
+
+static void cleanup2(void)
+{
+ int status;
+
+ msgctl(id, IPC_RMID, NULL);
+ wait(&status);
+ umount(DIRA);
+ cleanup();
+}
+
+static void test(void)
+{
+ int status, result = TC1_OK;
+ struct msgbuf m, r, sync;
+
+ m.mtype = 1;
+ sync.mtype = 4;
+
+ /* unshares the mount ns */
+ if (unshare(CLONE_NEWNS) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup, "unshare failed");
+ /* makes sure parent mounts/umounts have no effect on a real system */
+ SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL);
+
+ /* bind mounts DIRA to itself */
+ SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL);
+
+ /* makes mount DIRA shared */
+ SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL);
+
+ id = msgget(TESTKEY, IPC_CREAT | 0644);
+ if (id == -1)
+ tst_brkm(TBROK | TERRNO, cleanup, "msgget");
+
+ if (do_clone_tests(CLONE_NEWNS, child_func1, NULL, NULL, NULL) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup, "clone");
+
+ /* sync with child1 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgrcv");
+
+ /* TC#1 */
+ /* bind mounts DIRB to DIRA */
+ SAFE_MOUNT(cleanup2, DIRB, DIRA, "none", MS_BIND, NULL);
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgrcv");
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgrcv");
+
+ SAFE_UMOUNT(cleanup2, DIRA);
+ /* END OF TC#1 */
+
+ /* sync with children */
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+
+ /* TC#2 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 2, 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgrcv");
+
+ if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1))
+ result |= TC2_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+ /* END OF TC#2 */
+
+ /* sync with children */
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+ if (msgsnd(id, &sync, sizeof(sync.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+
+ /* TC#3 */
+ if (msgrcv(id, &r, sizeof(r.mtext), 3, 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgrcv");
+
+ if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1))
+ result |= TC3_OK;
+
+ if (msgsnd(id, &m, sizeof(m.mtext), 0) == -1)
+ tst_brkm(TBROK | TERRNO, cleanup2, "msgsnd");
+ /* END OF TC#3 */
+
+
+ SAFE_WAIT(cleanup2, &status);
+ if (WIFEXITED(status)) {
+ result &= WEXITSTATUS(status);
+ if (result & ERRC)
+ tst_brkm(TBROK, cleanup2, "error in child");
+ }
+ if (WIFSIGNALED(status)) {
+ tst_resm(TBROK, "child was killed with signal %s",
+ tst_strsig(WTERMSIG(status)));
+ return;
+ }
+
+ msgctl(id, IPC_RMID, NULL);
+ SAFE_UMOUNT(cleanup, DIRA);
+
+ if ((result & TC1_OK) == TC1_OK)
+ tst_resm(TPASS, TC1_MSG);
+ else
+ tst_resm(TFAIL, TC1_MSG);
+
+ if ((result & TC2_OK) == TC2_OK)
+ tst_resm(TPASS, TC2_MSG);
+ else
+ tst_resm(TFAIL, TC2_MSG);
+
+ if ((result & TC3_OK) == TC3_OK)
+ tst_resm(TPASS, TC3_MSG);
+ else
+ tst_resm(TFAIL, TC3_MSG);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *msg;
+ int lc;
+
+ msg = parse_opts(argc, argv, NULL, NULL);
+ if (msg != NULL)
+ tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+ setup();
+
+ for (lc = 0; TEST_LOOPING(lc); lc++)
+ test();
+
+ cleanup();
+ tst_exit();
+}
+
+#else
+int main(void)
+{
+ tst_brkm(TCONF, NULL, "needed mountflags are not defined");
+}
+#endif
--
1.8.3.1
------------------------------------------------------------------------------
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2] containers: added mountns/mountns05.c
2014-11-05 16:49 ` [LTP] [PATCH v2] " Matus Marhefka
@ 2014-12-02 16:42 ` Cyril Hrubis
[not found] ` <1962544618.7994595.1417604885928.JavaMail.zimbra@redhat.com>
0 siblings, 1 reply; 7+ messages in thread
From: Cyril Hrubis @ 2014-12-02 16:42 UTC (permalink / raw)
To: Matus Marhefka; +Cc: ltp-list
Hi!
> Tests a slave-shared mount: slave-shared mount makes
> a mountpoint both, shared and slave at the same time.
Looking at the code I wonder why msg IPC was choosen for parent-child
synchronization over the checkpoint interface?
--
Cyril Hrubis
chrubis@suse.cz
------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2] containers: added mountns/mountns05.c
[not found] ` <1962544618.7994595.1417604885928.JavaMail.zimbra@redhat.com>
@ 2014-12-17 14:10 ` Cyril Hrubis
[not found] ` <5495D100.8000107@redhat.com>
[not found] ` <939621071.8375320.1423670135099.JavaMail.zimbra@redhat.com>
0 siblings, 2 replies; 7+ messages in thread
From: Cyril Hrubis @ 2014-12-17 14:10 UTC (permalink / raw)
To: Matus Marhefka; +Cc: ltp-list
Hi!
> I used msg IPC because this test needs to synchronize 3 processes (parent
> and 2 children) and in this case at least 6 named pipes would be needed.
> So instead 6 named pipes I used only one message queue where each process
> has its own message type.
There are a few things I do not like about this solution:
* There is a static IPC key compiled in the source
- we cannot run two instances of the test at once
- it may interfere with the rest of the system
* There are no timeouts, if something fails the parent may end up
waiting forever
* The code could be shorter, it takes more than three lines to just
send the notification.
I guess that one of the problems is that the child processes need to
signal each other, which is something that the checkpoint code wasn't
written for. I think that it would be better to adapth the library so
that it fits the needs that has emerged. Or write better one that fits
all needs.
Looking at the checkpoint code, we would need a two more functions
that could be used synchronize between child processes. What about:
tst_checkpoint_signal_sibling(const char *file, const int lineno,
struct tst_checkpoint *checkpoint);
tst_checkopint_sibling_wait(const char *file, const int lineno,
struct tst_checkpoint *checkpoint);
Internally we can just reuse the tst_checkpoint_child_wait() and
tst_checkpoint_signal_parent() code (move it to separate static
functions and add a parameter with the character to be send/received).
Would that solve the problem here or are there any other obstacles?
--
Cyril Hrubis
chrubis@suse.cz
------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2] containers: added mountns/mountns05.c
[not found] ` <5495D100.8000107@redhat.com>
@ 2015-01-05 12:38 ` Cyril Hrubis
0 siblings, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2015-01-05 12:38 UTC (permalink / raw)
To: Jiri Jaburek; +Cc: ltp-list
Hi!
> May I ask why there needs to be a distinction between "parent" and
> "child" embedded into the checkpoint implementation, going as far as
> checking 'p' or 'c' read from FIFO? Why does it matter?
> I guess it adds a little to "code safety", but also severely limits
> the use cases for checkpointing. Why not simply have a "regular" mutex
> lock, like ie. pthread mutexes?
The distinction is unfortunately mandated by the differencies between
the parent (main test process) and child (forked process).
The parent is expected to prepare the testing environment and also do a
cleanup and therefore uses the tst_* interface, passes the cleanup
function pointer to the calls etc. The parent also includes timeout
logic which ensures that the parent does not hang while waiting for
children to come up.
The child processes does only the some test related task and does not
use the tst_ interface, exit with plain exit(), etc. The letter that is
send around is different in order to enforce that the right function is
called, no more no less. What this avoids, for example, is calling
cleanup callback from the child process that is common mistake which
leads to ugly race conditions.
Note also that before commit 8c1e0b3afe4f1c4da32fe7d1b5fa9738aacacab4
any usage of tst_* interface in child processes was strongly
discouraged.
Maybe we can rethink the API a bit now...
> Going a bit further - wouldn't it be easier to simply let the test(s)
> use sysv ipc, with tstlib-created objects (IPC_PRIVATE), providing
> semi-safe macros for svipc(7) functions (permitting ie. EAGAIN)?
>
> (or even use sysv ipc for the mutex implementation, think semtimedop(2)
> instead of open_wronly_timed)
I've considered that.
There are a few downsides to this approach. Apart from these being
global system resources the reason why I've choosen fifos over these is
that they can be compiled out of kernel and there are minimal systems
out there run fine without them. And while I do not care much that
sysvipc tests are broken on such configuration I certainly do not want
to break rest of the testcases.
--
Cyril Hrubis
chrubis@suse.cz
------------------------------------------------------------------------------
Dive into the World of Parallel Programming! The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2] containers: added mountns/mountns05.c
[not found] ` <939621071.8375320.1423670135099.JavaMail.zimbra@redhat.com>
@ 2015-02-12 15:04 ` Cyril Hrubis
0 siblings, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2015-02-12 15:04 UTC (permalink / raw)
To: Matus Marhefka; +Cc: ltp-list
Hi!
> >There are a few things I do not like about this solution:
> >
> >* There is a static IPC key compiled in the source
> > - we cannot run two instances of the test at once
> > - it may interfere with the rest of the system
>
> Agree on that, I should rewrite it to use ftok() to get a key.
ftok() on a a path under tst_tmpdir() should be reasonably random, but
still it's a global resource...
> >
> >* There are no timeouts, if something fails the parent may end up
> > waiting forever
> >
>
> This shouldn't happen as whole code contains error checking. If something
> fails it also removes the message queue and according to the man page removing
> the message queue also does "awakening all waiting reader and writer processes
> (with an error return and errno set to EIDRM)".
Missed that. This should work fine in this case.
> >Internally we can just reuse the tst_checkpoint_child_wait() and
> >tst_checkpoint_signal_parent() code (move it to separate static
> >functions and add a parameter with the character to be send/received).
> >
> >Would that solve the problem here or are there any other obstacles?
> >
>
> In this case 3 pipes would have to be used anyway. The solution
> with only one sysv message queue seems just better at least for me
> plus it's just for this one specific test case.
I've sumarized my points in:
https://sourceforge.net/p/ltp/mailman/message/33204261/
The major point is to avoid sysv ipc in testcases that does not test
sysv ipc.
But we may be able to build something better than fifos with POSIX
shared memory (shm_open()) and futexes. I've looked into this recently.
The code would be quite easy to write as all we need is a page of shared
memory that would provide space for 128 futexes and implementing
timeouts is as easy as passing struct timespec to the FUTEX_WAIT
function.
So we will have one init function to create shared memory page and then
a pair of wait and wake functions with an offset to the page (selects
which futex to wait for).
The only scenario that would be a bit more complicated is the case where
code that waits is needed after exec(). For this case we need to open
and map the same shared memory segment, i.e. need to know the name to
pass to the shm_open() but we can pass it to the child as a parameter.
I will try to prototype the code and test it on older distributions
hopefully soon enough.
--
Cyril Hrubis
chrubis@suse.cz
------------------------------------------------------------------------------
Dive into the World of Parallel Programming. The Go Parallel Website,
sponsored by Intel and developed in partnership with Slashdot Media, is your
hub for all things parallel software development, from weekly thought
leadership blogs to news, videos, case studies, tutorials and more. Take a
look and join the conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-02-12 15:04 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-30 15:07 [LTP] [PATCH] containers: added mountns/mountns05.c Matus Marhefka
2014-10-30 16:01 ` Cyril Hrubis
2014-11-05 16:49 ` [LTP] [PATCH v2] " Matus Marhefka
2014-12-02 16:42 ` Cyril Hrubis
[not found] ` <1962544618.7994595.1417604885928.JavaMail.zimbra@redhat.com>
2014-12-17 14:10 ` Cyril Hrubis
[not found] ` <5495D100.8000107@redhat.com>
2015-01-05 12:38 ` Cyril Hrubis
[not found] ` <939621071.8375320.1423670135099.JavaMail.zimbra@redhat.com>
2015-02-12 15:04 ` Cyril Hrubis
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox