xref: /freebsd/tools/test/stress2/misc/nullfs33.sh (revision 9c6ed9a88d3afb8bc9aba7cf852cc36e03bcd34c)
1*9c6ed9a8SPeter Holm#!/bin/sh
2*9c6ed9a8SPeter Holm
3*9c6ed9a8SPeter Holm# Bug 275570 - self-referential nullfs mount over tmpfs in combination with MNT_UPDATE results in a hang
4*9c6ed9a8SPeter Holm
5*9c6ed9a8SPeter Holm# Test scenario mounts:
6*9c6ed9a8SPeter Holm# tmpfs on /mnt (tmpfs, local, noexec, read-only)
7*9c6ed9a8SPeter Holm# .setup-done on /mnt/.setup-done (nullfs, local)
8*9c6ed9a8SPeter Holm
9*9c6ed9a8SPeter Holm# Hang seen on a GENERIC kernel only
10*9c6ed9a8SPeter Holm# UID  PID PPID C PRI NI   VSZ  RSS MWCHAN STAT TT     TIME COMMAND
11*9c6ed9a8SPeter Holm#   0 4429 4417 4  59  0 14192 2832 vlp2   D+    0  0:00.06 ./nullfs33
12*9c6ed9a8SPeter Holm# https://people.freebsd.org/~pho/stress/log/log0663.txt
13*9c6ed9a8SPeter Holm
14*9c6ed9a8SPeter Holm
15*9c6ed9a8SPeter Holm. ../default.cfg
16*9c6ed9a8SPeter Holmset -u
17*9c6ed9a8SPeter Holmprog=$(basename "$0" .sh)
18*9c6ed9a8SPeter Holm
19*9c6ed9a8SPeter Holmcat > /tmp/$prog.c <<EOF
20*9c6ed9a8SPeter Holm#include <assert.h>
21*9c6ed9a8SPeter Holm#include <err.h>
22*9c6ed9a8SPeter Holm#include <errno.h>
23*9c6ed9a8SPeter Holm#include <stdlib.h>
24*9c6ed9a8SPeter Holm#include <stdio.h>
25*9c6ed9a8SPeter Holm#include <string.h>
26*9c6ed9a8SPeter Holm#include <unistd.h>
27*9c6ed9a8SPeter Holm#include <sys/_iovec.h>
28*9c6ed9a8SPeter Holm#include <sys/file.h>
29*9c6ed9a8SPeter Holm#include <sys/mount.h>
30*9c6ed9a8SPeter Holm
31*9c6ed9a8SPeter Holmstatic void xmount(const char* fstype, const char* from, const char* to, int flags) {
32*9c6ed9a8SPeter Holm
33*9c6ed9a8SPeter Holm  char errmsg[255];
34*9c6ed9a8SPeter Holm  errmsg[0] = '\0';
35*9c6ed9a8SPeter Holm
36*9c6ed9a8SPeter Holm  int capacity = 8;
37*9c6ed9a8SPeter Holm
38*9c6ed9a8SPeter Holm  struct iovec* iov = malloc(sizeof(struct iovec) * capacity);
39*9c6ed9a8SPeter Holm
40*9c6ed9a8SPeter Holm  iov[0].iov_base = "fstype";
41*9c6ed9a8SPeter Holm  iov[0].iov_len  = sizeof("fstype");
42*9c6ed9a8SPeter Holm  iov[1].iov_base = __DECONST(char*, fstype);
43*9c6ed9a8SPeter Holm  iov[1].iov_len  = strlen(fstype) + 1;
44*9c6ed9a8SPeter Holm
45*9c6ed9a8SPeter Holm  iov[2].iov_base = "fspath";
46*9c6ed9a8SPeter Holm  iov[2].iov_len  = sizeof("fspath");
47*9c6ed9a8SPeter Holm  iov[3].iov_base = __DECONST(char*, to);
48*9c6ed9a8SPeter Holm  iov[3].iov_len  = strlen(to) + 1;
49*9c6ed9a8SPeter Holm
50*9c6ed9a8SPeter Holm  iov[4].iov_base = "from";
51*9c6ed9a8SPeter Holm  iov[4].iov_len  = sizeof("from");
52*9c6ed9a8SPeter Holm  iov[5].iov_base = __DECONST(char*, from);
53*9c6ed9a8SPeter Holm  iov[5].iov_len  = strlen(from) + 1;
54*9c6ed9a8SPeter Holm
55*9c6ed9a8SPeter Holm  iov[6].iov_base = "errmsg";
56*9c6ed9a8SPeter Holm  iov[6].iov_len  = sizeof("errmsg");
57*9c6ed9a8SPeter Holm  iov[7].iov_base = errmsg;
58*9c6ed9a8SPeter Holm  iov[7].iov_len  = sizeof(errmsg);
59*9c6ed9a8SPeter Holm
60*9c6ed9a8SPeter Holm  int len = 8;
61*9c6ed9a8SPeter Holm
62*9c6ed9a8SPeter Holm  if (flags & MNT_NOCOVER) {
63*9c6ed9a8SPeter Holm
64*9c6ed9a8SPeter Holm    assert(len + 2 <= capacity);
65*9c6ed9a8SPeter Holm
66*9c6ed9a8SPeter Holm    iov[len].iov_base = "nocover";
67*9c6ed9a8SPeter Holm    iov[len].iov_len  = sizeof("nocover");
68*9c6ed9a8SPeter Holm    len++;
69*9c6ed9a8SPeter Holm
70*9c6ed9a8SPeter Holm    iov[len].iov_base = NULL;
71*9c6ed9a8SPeter Holm    iov[len].iov_len  = 0;
72*9c6ed9a8SPeter Holm    len++;
73*9c6ed9a8SPeter Holm  }
74*9c6ed9a8SPeter Holm
75*9c6ed9a8SPeter Holm  assert(len == capacity);
76*9c6ed9a8SPeter Holm
77*9c6ed9a8SPeter Holm  if (nmount(iov, len, (int)flags) == -1) {
78*9c6ed9a8SPeter Holm    err(EXIT_FAILURE, "nmount %s -> %s: %s", from, to, errmsg);
79*9c6ed9a8SPeter Holm  }
80*9c6ed9a8SPeter Holm
81*9c6ed9a8SPeter Holm  free(iov);
82*9c6ed9a8SPeter Holm}
83*9c6ed9a8SPeter Holm
84*9c6ed9a8SPeter Holmstatic void xchdir(const char* path) {
85*9c6ed9a8SPeter Holm  if (chdir(path) == -1) {
86*9c6ed9a8SPeter Holm    err(EXIT_FAILURE, "chdir(\"%s\")", path);
87*9c6ed9a8SPeter Holm  }
88*9c6ed9a8SPeter Holm}
89*9c6ed9a8SPeter Holm
90*9c6ed9a8SPeter Holmstatic void xcreat(char* path, int mode) {
91*9c6ed9a8SPeter Holm  int fd = open(path, O_CREAT | O_WRONLY, mode);
92*9c6ed9a8SPeter Holm  if (fd == -1) {
93*9c6ed9a8SPeter Holm    err(EXIT_FAILURE, "can't create %s", path);
94*9c6ed9a8SPeter Holm  }
95*9c6ed9a8SPeter Holm  close(fd);
96*9c6ed9a8SPeter Holm}
97*9c6ed9a8SPeter Holm
98*9c6ed9a8SPeter Holm//#define ROOT_DIR "/mnt"
99*9c6ed9a8SPeter Holm#define ROOT_DIR "$mntpoint"
100*9c6ed9a8SPeter Holm
101*9c6ed9a8SPeter Holmint main(int argc __unused, char* argv[] __unused) {
102*9c6ed9a8SPeter Holm
103*9c6ed9a8SPeter Holm  xchdir(ROOT_DIR);
104*9c6ed9a8SPeter Holm
105*9c6ed9a8SPeter Holm  xmount("tmpfs", "tmpfs", ".", MNT_NOEXEC);
106*9c6ed9a8SPeter Holm
107*9c6ed9a8SPeter Holm  xcreat(".setup-done", 0444);
108*9c6ed9a8SPeter Holm  xmount("nullfs", ".setup-done", ".setup-done", 0);
109*9c6ed9a8SPeter Holm
110*9c6ed9a8SPeter Holm  xmount("tmpfs", "tmpfs", ".", MNT_RDONLY | MNT_NOEXEC | MNT_UPDATE);
111*9c6ed9a8SPeter Holm
112*9c6ed9a8SPeter Holm  unmount(ROOT_DIR "/.setup-done", MNT_FORCE);
113*9c6ed9a8SPeter Holm  unmount(ROOT_DIR, MNT_FORCE);
114*9c6ed9a8SPeter Holm
115*9c6ed9a8SPeter Holm  return 0;
116*9c6ed9a8SPeter Holm}
117*9c6ed9a8SPeter HolmEOF
118*9c6ed9a8SPeter Holmcc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
119*9c6ed9a8SPeter Holm
120*9c6ed9a8SPeter Holmcd /tmp
121*9c6ed9a8SPeter Holmstart=`date +%s`
122*9c6ed9a8SPeter Holmwhile [ $((`date +%s` - start)) -lt 60 ]; do
123*9c6ed9a8SPeter Holm	./$prog || break
124*9c6ed9a8SPeter Holmdone
125*9c6ed9a8SPeter Holmcd -
126*9c6ed9a8SPeter Holm
127*9c6ed9a8SPeter Holmmount | grep -q "on $mntpoint " && umount $mntpoint
128*9c6ed9a8SPeter Holmrm -f /tmp/$prog /tmp/$prog.c
129*9c6ed9a8SPeter Holmexit 0
130