diff options
Diffstat (limited to 'usr/src/test')
6 files changed, 322 insertions, 2 deletions
diff --git a/usr/src/test/zfs-tests/cmd/watch_dir/Makefile b/usr/src/test/zfs-tests/cmd/watch_dir/Makefile new file mode 100644 index 0000000000..517dff64af --- /dev/null +++ b/usr/src/test/zfs-tests/cmd/watch_dir/Makefile @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Joyent, Inc. +# + +PROG = watch_dir + +include $(SRC)/cmd/Makefile.cmd +include ../Makefile.subdirs diff --git a/usr/src/test/zfs-tests/cmd/watch_dir/watch_dir.c b/usr/src/test/zfs-tests/cmd/watch_dir/watch_dir.c new file mode 100644 index 0000000000..f6d8445162 --- /dev/null +++ b/usr/src/test/zfs-tests/cmd/watch_dir/watch_dir.c @@ -0,0 +1,151 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Joyent, Inc. + */ + +/* + * This program watches a directory with portfs or inotify, exiting when the + * directory is removed. It is useful in tests that ensure that watching a + * directory does not prevent it from being used as a mount point. + */ +#include <limits.h> +#include <port.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/inotify.h> +#include <unistd.h> + +void +fail_usage(void) +{ + (void) fprintf(stderr, "Usage: watch <portfs|inotify> directory\n"); + exit(1); +} + +#define MAX_PES 8 + +void +watch_port(const char *path) +{ + int port; + struct file_obj fobj = {0}; + + if ((port = port_create()) < 0) { + perror("port_create"); + exit(1); + } + + fobj.fo_name = (char *)path; + for (;;) { + timespec_t ts = {300, 0}; + port_event_t pe; + + if (port_associate(port, PORT_SOURCE_FILE, (uintptr_t)&fobj, + 0, (char *)path) != 0) { + perror("port_associate"); + exit(1); + } + + if (port_get(port, &pe, &ts) != 0) { + perror("port_get"); + exit(1); + } + + if (pe.portev_events & FILE_DELETE) { + (void) printf("DELETE\t%s\n", path); + exit(0); + } + if (pe.portev_events & MOUNTEDOVER) { + (void) printf("MOUNTEDOVER\t%s\n", path); + } + } +} + +void +watch_inotify(const char *path) +{ + int in, wd; + struct inotify_event ev; + + if ((in = inotify_init()) < 0) { + perror("inotify_init"); + exit(1); + } + if ((wd = inotify_add_watch(in, path, IN_DELETE_SELF)) == -1) { + perror("inotify_add_watch"); + exit(1); + } + + for (;;) { + ssize_t cnt; + char evpath[PATH_MAX]; + + cnt = read(in, &ev, sizeof (ev)); + if (cnt != sizeof (ev)) { + (void) fprintf(stderr, + "read: expected %ld bytes got %ld\n", + sizeof (ev), cnt); + exit(1); + } + if (ev.len != 0) { + if (ev.len > sizeof (evpath)) { + (void) fprintf(stderr, "read: oversize " + "path (%u bytes)\n", ev.len); + exit(1); + } + cnt = read(in, evpath, ev.len); + if (cnt != ev.len) { + (void) fprintf(stderr, "read: expected %ld " + "bytes for path, got %ld\n", ev.len, cnt); + exit(1); + } + evpath[ev.len - 1] = '\0'; + } else { + evpath[0] = '\0'; + } + if (ev.mask & IN_DELETE_SELF) { + /* + * IN_DELETE_SELF events don't appear to include + * the path in the event. + */ + (void) printf("DELETE_SELF\n"); + exit(0); + } else { + (void) printf("EVENT_%08x\t%s\n", ev.mask, evpath); + } + + } +} + +int +main(int argc, char **argv) +{ + const char *watcher, *path; + + if (argc != 3) { + fail_usage(); + } + watcher = argv[1]; + path = argv[2]; + + if (strcmp(watcher, "portfs") == 0) { + watch_port(path); + } else if (strcmp(watcher, "inotify") == 0) { + watch_inotify(path); + } else { + fail_usage(); + } + + return (0); +} diff --git a/usr/src/test/zfs-tests/include/commands.cfg b/usr/src/test/zfs-tests/include/commands.cfg index f9b0bdf7ac..0ad892e2b2 100644 --- a/usr/src/test/zfs-tests/include/commands.cfg +++ b/usr/src/test/zfs-tests/include/commands.cfg @@ -196,4 +196,5 @@ export ZFSTEST_FILES='chg_usr_exec randwritecomp readmmap rename_dir - rm_lnkcnt_zero_file' + rm_lnkcnt_zero_file + watch_dir' diff --git a/usr/src/test/zfs-tests/runfiles/smartos.run b/usr/src/test/zfs-tests/runfiles/smartos.run index 47059b0b52..18e819a301 100644 --- a/usr/src/test/zfs-tests/runfiles/smartos.run +++ b/usr/src/test/zfs-tests/runfiles/smartos.run @@ -130,7 +130,8 @@ tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_pos', 'zfs_mount_007_pos', 'zfs_mount_008_pos', 'zfs_mount_009_neg', 'zfs_mount_010_neg', 'zfs_mount_011_neg', 'zfs_mount_012_neg', 'zfs_mount_all_001_pos', 'zfs_mount_all_fail', 'zfs_mount_all_mountpoints', - 'zfs_mount_encrypted'] + 'zfs_mount_encrypted', 'zfs_mount_watched_inotify', + 'zfs_mount_watched_portfs' ] [/opt/zfs-tests/tests/functional/cli_root/zfs_program] tests = ['zfs_program_json'] diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_watched_inotify.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_watched_inotify.ksh new file mode 100644 index 0000000000..0f181621e8 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_watched_inotify.ksh @@ -0,0 +1,74 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright 2020 Joyent, Inc. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# 'zfs mount' should not get EBUSY due to inotify(5) watching a directory +# +# STRATEGY: +# 1. Create a directory +# 2. Start watching the directory with inotify(5). +# 3. Create a filesystem +# 4. Mount the filesystem at the directory created in step 1 +# 5. Destroy the filesystem +# 6. Remove the directory +# 7. Verify the watcher saw the directory removal +# + +verify_runnable "both" + +function cleanup +{ + datasetexists $TESTPOOL/$TESTFS1 && \ + log_must zfs destroy -f $TESTPOOL/$TESTFS1 + log_must rm -rf "$TESTDIR/mntpt" "$TESTDIR/watch_dir.log" +} + +log_onexit cleanup + +log_assert "'zfs mount' should not get EBUSY due to inotify(5) watching a directory" + +# 1. Create a directory. +log_must mkdir -p "$TESTDIR/mntpt" + +# 2. Start watching the directory with inotify(5). +watch_dir inotify $TESTDIR/mntpt > $TESTDIR/watch_dir.log & + +# 3. Create a filesystem +log_must zfs create $TESTPOOL/$TESTFS1 + +# 4. Mount the file system at the directory created in step 1 +log_must zfs set mountpoint=$TESTDIR/mntpt $TESTPOOL/$TESTFS1 + +# 5. Destroy the filesystem +log_must zfs destroy $TESTPOOL/$TESTFS1 + +# 6. Remove the directory. The corresponding inotify event will cause the +# watcher to exit. +log_must rmdir $TESTDIR/mntpt + +# 7. Verify the watcher saw the directory removal. This ensures that the watcher +# was watching the directory we are interested in. +wait +log_must grep -q DELETE_SELF $TESTDIR/watch_dir.log + +log_pass "'zfs mount' should not get EBUSY due to inotify(5) watching a directory" diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_watched_portfs.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_watched_portfs.ksh new file mode 100644 index 0000000000..3135203973 --- /dev/null +++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_watched_portfs.ksh @@ -0,0 +1,74 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# CDDL HEADER END +# + +# +# Copyright 2020 Joyent, Inc. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# 'zfs mount' should not get EBUSY due to portfs watching a directory +# +# STRATEGY: +# 1. Create a directory +# 2. Start watching the directory with port_associate +# 3. Create a filesystem +# 4. Mount the filesystem at the directory created in step 1 +# 5. Destroy the filesystem +# 6. Remove the directory +# 7. Verify the watcher saw the directory removal +# + +verify_runnable "both" + +function cleanup +{ + datasetexists $TESTPOOL/$TESTFS1 && \ + log_must zfs destroy -f $TESTPOOL/$TESTFS1 + log_must rm -rf "$TESTDIR/mntpt" "$TESTDIR/watch_dir.log" +} + +log_onexit cleanup + +log_assert "'zfs mount' should not get EBUSY due to portfs watching a directory" + +# 1. Create a directory. +log_must mkdir -p "$TESTDIR/mntpt" + +# 2. Start watching the directory with port_associate +watch_dir portfs $TESTDIR/mntpt > $TESTDIR/watch_dir.log & + +# 3. Create a filesystem +log_must zfs create $TESTPOOL/$TESTFS1 + +# 4. Mount the file system at the directory created in step 1 +log_must zfs set mountpoint=$TESTDIR/mntpt $TESTPOOL/$TESTFS1 + +# 5. Destroy the filesystem +log_must zfs destroy $TESTPOOL/$TESTFS1 + +# 6. Remove the directory. The corresponding portfs event will cause the +# watcher to exit. +log_must rmdir $TESTDIR/mntpt + +# 7. Verify the watcher saw the directory removal. This ensures that the watcher +# was watching the directory we are interested in. +wait +log_must grep -q DELETE.$TESTDIR/mntpt $TESTDIR/watch_dir.log + +log_pass "'zfs mount' should not get EBUSY due to portfs watching a directory" |