diff options
Diffstat (limited to 'testcases/kernel')
269 files changed, 4189 insertions, 19331 deletions
diff --git a/testcases/kernel/containers/pidns/pidns05.c b/testcases/kernel/containers/pidns/pidns05.c index 0e7739aaa..7843fe7a9 100644 --- a/testcases/kernel/containers/pidns/pidns05.c +++ b/testcases/kernel/containers/pidns/pidns05.c @@ -24,7 +24,7 @@ static struct tst_clone_args clone_args = { }; static pid_t pid_max; -static void child_func(int *level) +static void child_func(const int level) { pid_t cpid, ppid; @@ -34,15 +34,13 @@ static void child_func(int *level) TST_EXP_EQ_LI(cpid, 1); TST_EXP_EQ_LI(ppid, 0); - if (*level >= MAX_DEPTH) { + if (level >= MAX_DEPTH - 1) { TST_CHECKPOINT_WAKE(0); return; } - (*level)++; - if (!SAFE_CLONE(&clone_args)) { - child_func(level); + child_func(level + 1); return; } @@ -81,14 +79,13 @@ static void setup(void) static void run(void) { int i, status, children; - int level = 0; pid_t pids_new[MAX_DEPTH]; pid_t pids[MAX_DEPTH]; pid_t pid; pid = SAFE_CLONE(&clone_args); if (!pid) { - child_func(&level); + child_func(0); return; } diff --git a/testcases/kernel/controllers/cpuset/cpuset_funcs.sh b/testcases/kernel/controllers/cpuset/cpuset_funcs.sh index 0cfa0c17e..567178e3f 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_funcs.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_funcs.sh @@ -165,8 +165,7 @@ setup() mount -t cgroup -o cpuset cpuset "$CPUSET" 2> /dev/null if [ $? -ne 0 ]; then cleanup - tst_brkm TFAIL "Could not mount cgroup filesystem with"\ - " cpuset on $CPUSET..Exiting test" + tst_brkm TCONF "Could not mount cgroup filesystem with cpuset on $CPUSET" fi CHILDREN_VALUE="`cat $CLONE_CHILDREN`" diff --git a/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh b/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh index a5757309f..bedc48110 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh @@ -190,21 +190,27 @@ do_test() ROD_SILENT mkdir ${root_cpuset_dir}/testdir # Creat an exclusive cpuset. - echo 1 > ${root_cpuset_dir}/testdir/${cpu_exclusive} - [ $? -ne 0 ] && tst_brk TFAIL "'echo 1 > ${root_cpuset_dir}/testdir/${cpu_exclusive}' failed" + if ! echo 1 > ${root_cpuset_dir}/testdir/${cpu_exclusive}; then + tst_res TFAIL "'echo 1 > ${root_cpuset_dir}/testdir/${cpu_exclusive}' failed" + return + fi cpu_exclusive_tmp=$(cat ${root_cpuset_dir}/testdir/${cpu_exclusive}) if [ "${cpu_exclusive_tmp}" != "1" ]; then - tst_brk TFAIL "${cpu_exclusive} is '${cpu_exclusive_tmp}', expected '1'" + tst_res TFAIL "${cpu_exclusive} is '${cpu_exclusive_tmp}', expected '1'" + return fi # This may trigger the kernel crash - echo 0 > ${root_cpuset_dir}/testdir/${cpus} - [ $? -ne 0 ] && tst_brk TFAIL "'echo 0 > ${root_cpuset_dir}/testdir/${cpus}' failed" + if ! echo 0 > ${root_cpuset_dir}/testdir/${cpus}; then + tst_res TFAIL "'echo 0 > ${root_cpuset_dir}/testdir/${cpus}' failed" + return + fi cpus_value=$(cat ${root_cpuset_dir}/testdir/${cpus}) if [ "${cpus_value}" != "0" ]; then - tst_brk TFAIL "${cpus} is '${cpus_value}', expected '0'" + tst_res TFAIL "${cpus} is '${cpus_value}', expected '0'" + return fi tst_res TPASS "Bug is not reproducible" diff --git a/testcases/kernel/controllers/freezer/vfork.c b/testcases/kernel/controllers/freezer/vfork.c index 0b25e90c2..9f4359bf8 100644 --- a/testcases/kernel/controllers/freezer/vfork.c +++ b/testcases/kernel/controllers/freezer/vfork.c @@ -29,6 +29,7 @@ * until vfork returns. This can delay delivery of signals to the parent * process, even delay or stop system suspend. */ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -39,9 +40,8 @@ #include <sys/types.h> #include <sys/wait.h> #include <sys/socket.h> +#include <sys/ptrace.h> #include "test.h" -#include "config.h" -#include "../../syscalls/ptrace/ptrace.h" #define str_expand(s) str(s) #define str(s) #s diff --git a/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh b/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh index 9bcc01258..3b7311422 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh @@ -33,8 +33,8 @@ test_subgroup() fi echo $MEMCG_PROCESS_PID > tasks - signal_memcg_process $MEM_TO_ALLOC - check_mem_stat "rss" $MEM_TO_ALLOC + signal_memcg_process $MIN_CHARGED + check_mem_stat "rss" $MIN_CHARGED $MEM_TO_ALLOC cd subgroup echo $MEMCG_PROCESS_PID > tasks @@ -66,5 +66,6 @@ test3() # Allocate memory bigger than per-cpu kernel memory MEM_TO_ALLOC=$((PAGESIZES * 2)) +MIN_CHARGED=$((2 * (PAGESIZES - 1))) tst_run diff --git a/testcases/kernel/controllers/memcg/memcontrol02.c b/testcases/kernel/controllers/memcg/memcontrol02.c index 1656176b6..0d93abd9e 100644 --- a/testcases/kernel/controllers/memcg/memcontrol02.c +++ b/testcases/kernel/controllers/memcg/memcontrol02.c @@ -134,7 +134,7 @@ static struct tst_test test = { .tcnt = 2, .test = test_memcg_current, .mount_device = 1, - .dev_min_size = 256, + .dev_min_size = 300, .mntpoint = TMPDIR, .all_filesystems = 1, .forks_child = 1, diff --git a/testcases/kernel/controllers/memcg/memcontrol03.c b/testcases/kernel/controllers/memcg/memcontrol03.c index bc726f395..9c6c808e0 100644 --- a/testcases/kernel/controllers/memcg/memcontrol03.c +++ b/testcases/kernel/controllers/memcg/memcontrol03.c @@ -239,7 +239,6 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = test_memcg_min, .mount_device = 1, - .dev_min_size = 256, .mntpoint = TMPDIR, .all_filesystems = 1, .skip_filesystems = (const char *const[]){ diff --git a/testcases/kernel/controllers/memcg/memcontrol04.c b/testcases/kernel/controllers/memcg/memcontrol04.c index c963a1cd8..32a0b9fd4 100644 --- a/testcases/kernel/controllers/memcg/memcontrol04.c +++ b/testcases/kernel/controllers/memcg/memcontrol04.c @@ -232,7 +232,6 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = test_memcg_low, .mount_device = 1, - .dev_min_size = 256, .mntpoint = TMPDIR, .all_filesystems = 1, .skip_filesystems = (const char *const[]){ diff --git a/testcases/kernel/controllers/memcg/memcontrol_common.h b/testcases/kernel/controllers/memcg/memcontrol_common.h index adb6fafb3..a3bd243f5 100644 --- a/testcases/kernel/controllers/memcg/memcontrol_common.h +++ b/testcases/kernel/controllers/memcg/memcontrol_common.h @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +#ifndef MEMCONTROL_COMMON_H__ +#define MEMCONTROL_COMMON_H__ + #include <stdlib.h> #include <stdio.h> @@ -45,3 +48,5 @@ static inline void alloc_anon(const size_t size) free(buf); } + +#endif /* MEMCONTROL_COMMON_H__ */ diff --git a/testcases/kernel/controllers/memcg/regression/memcg_test_3.c b/testcases/kernel/controllers/memcg/regression/memcg_test_3.c index f29c2bea5..31b1b5a83 100644 --- a/testcases/kernel/controllers/memcg/regression/memcg_test_3.c +++ b/testcases/kernel/controllers/memcg/regression/memcg_test_3.c @@ -21,6 +21,7 @@ static volatile int sigcounter; static struct tst_cg_group *test_cg; +static pid_t ppid; static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) { @@ -29,8 +30,8 @@ static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) static void do_child(void) { - while (1) - SAFE_KILL(getppid(), SIGUSR1); + while (getppid() == ppid) + SAFE_KILL(ppid, SIGUSR1); exit(0); } @@ -40,6 +41,7 @@ static void do_test(void) pid_t cpid; SAFE_SIGNAL(SIGUSR1, sighandler); + ppid = getpid(); cpid = SAFE_FORK(); if (cpid == 0) diff --git a/testcases/kernel/crypto/crypto_user01.c b/testcases/kernel/crypto/crypto_user01.c index 47bf9f0d2..6f6036aed 100644 --- a/testcases/kernel/crypto/crypto_user01.c +++ b/testcases/kernel/crypto/crypto_user01.c @@ -17,7 +17,6 @@ #include "tst_test.h" #include "tst_crypto.h" -#include "tst_netlink.h" /* * include after <sys/socket.h> (via tst_test.h), to work around dependency bug @@ -25,11 +24,11 @@ */ #include <linux/rtnetlink.h> -static struct tst_crypto_session ses = TST_CRYPTO_SESSION_INIT; +static struct tst_netlink_context *ctx; static void setup(void) { - tst_crypto_open(&ses); + ctx = NETLINK_CREATE_CONTEXT(NETLINK_CRYPTO); } static void do_check_for_leaks(const char *name, const char *value, size_t vlen) @@ -131,25 +130,20 @@ static void validate_one_alg(const struct nlmsghdr *nh) } } -static void validate_alg_list(const void *buf, size_t remaining) +static void validate_alg_list(const struct tst_netlink_message *msg) { - const struct nlmsghdr *nh; - - for (nh = buf; NLMSG_OK(nh, remaining); - nh = NLMSG_NEXT(nh, remaining)) { - if (nh->nlmsg_seq != ses.seq_num) { - tst_brk(TBROK, - "Message out of sequence; type=0%hx, seq_num=%u (not %u)", - nh->nlmsg_type, nh->nlmsg_seq, ses.seq_num); - } - if (nh->nlmsg_type == NLMSG_DONE) + for (; msg->header; msg++) { + if (msg->header->nlmsg_type == NLMSG_DONE) return; - if (nh->nlmsg_type != CRYPTO_MSG_GETALG) { + + if (msg->header->nlmsg_type != CRYPTO_MSG_GETALG) { tst_brk(TBROK, "Unexpected message type; type=0x%hx, seq_num=%u", - nh->nlmsg_type, nh->nlmsg_seq); + msg->header->nlmsg_type, + msg->header->nlmsg_seq); } - validate_one_alg(nh); + + validate_one_alg(msg->header); } } @@ -157,35 +151,23 @@ static void run(void) { struct crypto_user_alg payload = { 0 }; struct nlmsghdr nh = { - .nlmsg_len = sizeof(payload), .nlmsg_type = CRYPTO_MSG_GETALG, .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, - .nlmsg_seq = ++(ses.seq_num), - .nlmsg_pid = 0, }; - /* - * Due to an apparent kernel bug, this API cannot be used incrementally, - * so we just use a large recvmsg() buffer. This is good enough since - * we don't necessarily have to check every algorithm for this test to - * be effective... - */ - const size_t bufsize = 1048576; - void *buf = SAFE_MALLOC(bufsize); - size_t res; - - SAFE_NETLINK_SEND(ses.fd, &nh, &payload); - - res = SAFE_NETLINK_RECV(ses.fd, buf, bufsize); - - validate_alg_list(buf, res); - - free(buf); + struct tst_netlink_message *msg; + + NETLINK_ADD_MESSAGE(ctx, &nh, &payload, sizeof(payload)); + NETLINK_SEND(ctx); + NETLINK_WAIT(ctx); + msg = NETLINK_RECV(ctx); + validate_alg_list(msg); + NETLINK_FREE_MESSAGE(msg); tst_res(TPASS, "No information leaks found"); } static void cleanup(void) { - tst_crypto_close(&ses); + NETLINK_DESTROY_CONTEXT(ctx); } static struct tst_test test = { diff --git a/testcases/kernel/crypto/crypto_user02.c b/testcases/kernel/crypto/crypto_user02.c index afaff5d18..89cbb9bc5 100644 --- a/testcases/kernel/crypto/crypto_user02.c +++ b/testcases/kernel/crypto/crypto_user02.c @@ -52,7 +52,7 @@ static const char * const ALGORITHM_CANDIDATES[] = { }; static const char* algorithm = NULL; -static struct tst_crypto_session ses = TST_CRYPTO_SESSION_INIT; +static struct tst_netlink_context *ctx; static void setup(void) @@ -60,7 +60,8 @@ static void setup(void) int rc; unsigned i; struct crypto_user_alg alg; - tst_crypto_open(&ses); + + ctx = NETLINK_CREATE_CONTEXT(NETLINK_CRYPTO); /* find an algorithm, that is not in use */ for (i = 0; i < ARRAY_SIZE(ALGORITHM_CANDIDATES); ++i) { @@ -68,12 +69,12 @@ static void setup(void) strcpy(alg.cru_driver_name, ALGORITHM_CANDIDATES[i]); /* try to add it, to see if it is valid */ - rc = tst_crypto_add_alg(&ses, &alg); + rc = tst_crypto_add_alg(ctx, &alg); if (rc != 0) continue; /* it also has to be deletable */ - rc = tst_crypto_del_alg(&ses, &alg); + rc = tst_crypto_del_alg(ctx, &alg, 1000); if (rc == 0) { algorithm = ALGORITHM_CANDIDATES[i]; break; @@ -103,9 +104,9 @@ static void run(void) if (pid == 0) { /* Child process: execute CRYPTO_MSG_NEWALG. */ - tst_crypto_open(&ses); + ctx = NETLINK_CREATE_CONTEXT(NETLINK_CRYPTO); for (;;) { - TEST(tst_crypto_add_alg(&ses, &alg)); + TEST(tst_crypto_add_alg(ctx, &alg)); if (TST_RET && TST_RET != -EEXIST) tst_brk(TBROK | TRERRNO, "unexpected error from tst_crypto_add_alg()"); @@ -123,7 +124,7 @@ static void run(void) SAFE_WAIT(&status); if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) tst_brk(TBROK, "child %s", tst_strstatus(status)); - TEST(tst_crypto_del_alg(&ses, &alg)); + TEST(tst_crypto_del_alg(ctx, &alg, 1000)); if (TST_RET && TST_RET != -ENOENT) tst_brk(TBROK | TRERRNO, "unexpected error from tst_crypto_del_alg()"); @@ -134,7 +135,7 @@ static void run(void) static void cleanup(void) { - tst_crypto_close(&ses); + NETLINK_DESTROY_CONTEXT(ctx); } static struct tst_test test = { diff --git a/testcases/kernel/crypto/pcrypt_aead01.c b/testcases/kernel/crypto/pcrypt_aead01.c index 3b4f5d8d1..3979f317a 100644 --- a/testcases/kernel/crypto/pcrypt_aead01.c +++ b/testcases/kernel/crypto/pcrypt_aead01.c @@ -26,11 +26,11 @@ #define ATTEMPTS 10000 -static struct tst_crypto_session ses = TST_CRYPTO_SESSION_INIT; +static struct tst_netlink_context *ctx; void setup(void) { - tst_crypto_open(&ses); + ctx = NETLINK_CREATE_CONTEXT(NETLINK_CRYPTO); } void run(void) @@ -43,7 +43,7 @@ void run(void) }; for (i = 0; i < ATTEMPTS; ++i) { - TEST(tst_crypto_add_alg(&ses, &a)); + TEST(tst_crypto_add_alg(ctx, &a)); if (TST_RET && TST_RET == -ENOENT) { tst_brk(TCONF | TRERRNO, "pcrypt, hmac, sha256, cbc or aes not supported"); @@ -51,7 +51,7 @@ void run(void) if (TST_RET && TST_RET != -EEXIST) tst_brk(TBROK | TRERRNO, "add_alg"); - TEST(tst_crypto_del_alg(&ses, &a)); + TEST(tst_crypto_del_alg(ctx, &a, 1000)); if (TST_RET) tst_brk(TBROK | TRERRNO, "del_alg"); @@ -67,7 +67,7 @@ void run(void) void cleanup(void) { - tst_crypto_close(&ses); + NETLINK_DESTROY_CONTEXT(ctx); } static struct tst_test test = { diff --git a/testcases/kernel/device-drivers/zram/zram01.sh b/testcases/kernel/device-drivers/zram/zram01.sh index 6bc305f2c..0c100b706 100755 --- a/testcases/kernel/device-drivers/zram/zram01.sh +++ b/testcases/kernel/device-drivers/zram/zram01.sh @@ -82,7 +82,9 @@ zram_makefs() mkfs.$fs /dev/zram$i > err.log 2>&1 if [ $? -ne 0 ]; then cat err.log - tst_brk TFAIL "failed to make $fs on /dev/zram$i" + tst_res TFAIL "Failed to make $fs on /dev/zram$i" + tst_brk TBROK "Can't continue with mounting the FS" + return fi i=$(($i + 1)) diff --git a/testcases/kernel/device-drivers/zram/zram03.c b/testcases/kernel/device-drivers/zram/zram03.c index 98eb61e1c..1df3325ec 100644 --- a/testcases/kernel/device-drivers/zram/zram03.c +++ b/testcases/kernel/device-drivers/zram/zram03.c @@ -89,7 +89,7 @@ static void verify_device(void) SAFE_CLOSE(fd); } -static void reset(void) +static void reset_zram(void) { char reset_path[200]; @@ -163,7 +163,7 @@ static void run(void) dump_info(); verify_device(); - reset(); + reset_zram(); dump_info(); } @@ -181,7 +181,7 @@ static void setup(void) tst_res(TINFO, "zram module already loaded, kernel supports zram-control interface"); SAFE_FILE_SCANF(HOT_ADD_PATH, "%d", &dev_num); - hot_add_flag =1; + hot_add_flag = 1; goto fill_path; } diff --git a/testcases/kernel/device-drivers/zram/zram_lib.sh b/testcases/kernel/device-drivers/zram/zram_lib.sh index e94d7db11..e94f9244d 100755 --- a/testcases/kernel/device-drivers/zram/zram_lib.sh +++ b/testcases/kernel/device-drivers/zram/zram_lib.sh @@ -108,12 +108,16 @@ zram_max_streams() for max_s in $zram_max_streams; do local sys_path="/sys/block/zram${i}/max_comp_streams" - echo $max_s > $sys_path || \ - tst_brk TFAIL "failed to set '$max_s' to $sys_path" + if ! echo $max_s > $sys_path; then + tst_res TFAIL "failed to set '$max_s' to $sys_path" + return + fi local max_streams=$(cat $sys_path) - [ "$max_s" -ne "$max_streams" ] && \ - tst_brk TFAIL "can't set max_streams '$max_s', get $max_stream" + if [ "$max_s" -ne "$max_streams" ]; then + tst_res TFAIL "can't set max_streams '$max_s', get $max_stream" + return + fi i=$(($i + 1)) tst_res TINFO "$sys_path = '$max_streams'" @@ -140,8 +144,10 @@ zram_compress_alg() for i in $(seq $dev_start $dev_end); do for alg in $algs; do local sys_path="/sys/block/zram${i}/comp_algorithm" - echo "$alg" > $sys_path || \ - tst_brk TFAIL "can't set '$alg' to $sys_path" + if ! echo "$alg" > $sys_path; then + tst_res TFAIL "can't set '$alg' to $sys_path" + return + fi tst_res TINFO "$sys_path = '$alg'" done done @@ -157,8 +163,10 @@ zram_set_disksizes() tst_res TINFO "set disk size to zram device(s)" for ds in $zram_sizes; do local sys_path="/sys/block/zram${i}/disksize" - echo "$ds" > $sys_path || \ - tst_brk TFAIL "can't set '$ds' to $sys_path" + if ! echo "$ds" > $sys_path; then + tst_res TFAIL "can't set '$ds' to $sys_path" + return + fi i=$(($i + 1)) tst_res TINFO "$sys_path = '$ds'" @@ -183,8 +191,10 @@ zram_set_memlimit() for ds in $zram_mem_limits; do local sys_path="/sys/block/zram${i}/mem_limit" - echo "$ds" > $sys_path || \ - tst_brk TFAIL "can't set '$ds' to $sys_path" + if ! echo "$ds" > $sys_path; then + tst_res TFAIL "can't set '$ds' to $sys_path" + return + fi i=$(($i + 1)) tst_res TINFO "$sys_path = '$ds'" diff --git a/testcases/kernel/fs/doio/growfiles.c b/testcases/kernel/fs/doio/growfiles.c index eb58ce0cd..7bf51fb9c 100644 --- a/testcases/kernel/fs/doio/growfiles.c +++ b/testcases/kernel/fs/doio/growfiles.c @@ -328,7 +328,7 @@ int Open_flags[] = { #define USECS_PER_SEC 1000000 /* microseconds per second */ /* - * Define marcos used when dealing with file locks. + * Define macros used when dealing with file locks. */ #define LKLVL0 1 /* file lock around write/read/trunc */ #define LKLVL1 2 /* file lock after open to before close */ diff --git a/testcases/kernel/fs/doio/rwtest b/testcases/kernel/fs/doio/rwtest index 6725e1426..3fbdf7f96 100644 --- a/testcases/kernel/fs/doio/rwtest +++ b/testcases/kernel/fs/doio/rwtest @@ -327,13 +327,6 @@ do then blks=${szblks[$n]} else - # If df is a symlink (to busybox) then do not pass the $dir and $dfOpts - # parameters because they don't work as expected - if test -h $(which df) - then - dir=""; dfOpts=""; - fi - blks=$(df $dfOpts $dir | (while read fs blks used avail cap mountpoint do diff --git a/testcases/kernel/fs/fs_fill/fs_fill.c b/testcases/kernel/fs/fs_fill/fs_fill.c index 2ecd8e2ad..3b4ee1ae9 100644 --- a/testcases/kernel/fs/fs_fill/fs_fill.c +++ b/testcases/kernel/fs/fs_fill/fs_fill.c @@ -121,8 +121,9 @@ static void cleanup(void) } static struct tst_test test = { - .max_runtime = 60, + .max_runtime = 300, .needs_root = 1, + .dev_min_size = 1024, .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, diff --git a/testcases/kernel/fs/fsx-linux/Makefile b/testcases/kernel/fs/fsx-linux/Makefile index 956486b8a..5d04d81bc 100644 --- a/testcases/kernel/fs/fsx-linux/Makefile +++ b/testcases/kernel/fs/fsx-linux/Makefile @@ -22,13 +22,11 @@ top_srcdir ?= ../../../.. -include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/testcases.mk CPPFLAGS += -DNO_XFS -I$(abs_srcdir) \ -D_LARGEFILE64_SOURCE -D_GNU_SOURCE WCFLAGS += -w -INSTALL_TARGETS := fsxtest* - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/fs/fsx-linux/fsx-linux.c b/testcases/kernel/fs/fsx-linux/fsx-linux.c index 64c27a0f5..ba1e21bbc 100644 --- a/testcases/kernel/fs/fsx-linux/fsx-linux.c +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c @@ -1,1353 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 1991, NeXT Computer, Inc. All Rights Reserverd. - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * File: fsx.c * Author: Avadis Tevanian, Jr. * - * File system exerciser. - * - * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com - * - * Various features from Joe Sokol, Pat Dirks, and Clark Warner. - * - * Small changes to work under Linux -- davej@suse.de - * - * Sundry porting patches from Guy Harris 12/2001 - * $FreeBSD: src/tools/regression/fsx/fsx.c,v 1.1 2001/12/20 04:15:57 jkh Exp $ + * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved. + * Conrad Minshall <conrad@mac.com> + * Dave Jones <davej@suse.de> + * Zach Brown <zab@clusterfs.com> + * Joe Sokol, Pat Dirks, Clark Warner, Guy Harris * - * Add multi-file testing feature -- Zach Brown <zab@clusterfs.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -#include <sys/types.h> -#include <sys/stat.h> -#if defined(_UWIN) || defined(__linux__) -#include <sys/param.h> -#include <limits.h> -#include <time.h> -#include <string.h> -#include <sys/time.h> -#endif -#include <fcntl.h> -#include <sys/mman.h> -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif -#include <limits.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <stdarg.h> -#include <errno.h> - -/* - * A log entry is an operation and a bunch of arguments. +/*\ + * [Description] + * + * This is a complete rewrite of the old fsx-linux tool, created by + * NeXT Computer, Inc. and Apple Computer, Inc. between 1991 and 2001, + * then adapted for LTP. Test is actually a file system exerciser: we bring a + * file and randomly write operations like read/write/map read/map write and + * truncate, according with input parameters. Then we check if all of them + * have been completed. */ -struct log_entry { - int operation; - struct timeval tv; - int args[3]; +#include <stdlib.h> +#include "tst_test.h" + +#define FNAME "ltp-file.bin" + +enum { + OP_READ = 0, + OP_WRITE, + OP_TRUNCATE, + OP_MAPREAD, + OP_MAPWRITE, + /* keep counter here */ + OP_TOTAL, }; -#define LOGSIZE 1000 +static char *str_file_max_size; +static char *str_op_max_size; +static char *str_op_nums; +static char *str_op_write_align; +static char *str_op_read_align; +static char *str_op_trunc_align; + +static int file_desc; +static long long file_max_size = 256 * 1024; +static long long op_max_size = 64 * 1024; +static long long file_size; +static int op_write_align = 1; +static int op_read_align = 1; +static int op_trunc_align = 1; +static int op_nums = 1000; +static int page_size; + +static char *file_buff; +static char *temp_buff; + +struct file_pos_t { + long long offset; + long long size; +}; -struct log_entry oplog[LOGSIZE]; /* the log */ -int logptr = 0; /* current position in log */ -int logcount = 0; /* total ops */ +static void op_align_pages(struct file_pos_t *pos) +{ + long long pg_offset; -/* - * Define operations - */ + pg_offset = pos->offset % page_size; -#define OP_READ 1 -#define OP_WRITE 2 -#define OP_TRUNCATE 3 -#define OP_CLOSEOPEN 4 -#define OP_MAPREAD 5 -#define OP_MAPWRITE 6 -#define OP_SKIPPED 7 - -int page_size; -int page_mask; - -char *original_buf; /* a pointer to the original data */ -char *good_buf; /* a pointer to the correct data */ -char *temp_buf; /* a pointer to the current data */ -char *fname; /* name of our test file */ -char logfile[1024]; /* name of our log file */ -char goodfile[1024]; /* name of our test file */ - -off_t file_size = 0; -off_t biggest = 0; -char state[256]; -unsigned long testcalls = 0; /* calls to function "test" */ - -unsigned long simulatedopcount = 0; /* -b flag */ -int closeprob = 0; /* -c flag */ -int debug = 0; /* -d flag */ -unsigned long debugstart = 0; /* -D flag */ -unsigned long maxfilelen = 256 * 1024; /* -l flag */ -int sizechecks = 1; /* -n flag disables them */ -int maxoplen = 64 * 1024; /* -o flag */ -int quiet = 0; /* -q flag */ -unsigned long progressinterval = 0; /* -p flag */ -int readbdy = 1; /* -r flag */ -int style = 0; /* -s flag */ -int truncbdy = 1; /* -t flag */ -int writebdy = 1; /* -w flag */ -long monitorstart = -1; /* -m flag */ -long monitorend = -1; /* -m flag */ -int lite = 0; /* -L flag */ -long numops = -1; /* -N flag */ -int randomoplen = 1; /* -O flag disables it */ -int seed = 1; /* -S flag */ -int mapped_writes = 1; /* -W flag disables */ -int mapped_reads = 1; /* -R flag disables it */ -int fsxgoodfd = 0; -FILE *fsxlogf = NULL; -int badoff = -1; - -void vwarnc(int code,const char *fmt, va_list ap) -{ - fprintf(stderr, "fsx: "); - if (fmt != NULL) { - vfprintf(stderr, fmt, ap); - fprintf(stderr, ": "); - } - fprintf(stderr, "%s\n", strerror(code)); + pos->offset -= pg_offset; + pos->size += pg_offset; } -void warn(const char *fmt, ...) +static void op_file_position( + const long long fsize, + const int align, + struct file_pos_t *pos) { - va_list ap; - va_start(ap, fmt); - vwarnc(errno, fmt, ap); - va_end(ap); -} + long long diff; -void - __attribute__ ((format(printf, 1, 2))) - prt(char *fmt, ...) -{ - va_list args; + pos->offset = random() % fsize; + pos->size = random() % (fsize - pos->offset); - va_start(args, fmt); - vfprintf(stdout, fmt, args); - va_end(args); + diff = pos->offset % align; - if (fsxlogf) { - va_start(args, fmt); - vfprintf(fsxlogf, fmt, args); - va_end(args); + if (diff) { + pos->offset -= diff; + pos->size += diff; } -} -void prterr(char *prefix) -{ - prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno)); + if (!pos->size) + pos->size = 1; } -void log4(int operation, int arg0, int arg1, int arg2, struct timeval *tv) +static void update_file_size(struct file_pos_t const *pos) { - struct log_entry *le; - - le = &oplog[logptr]; - le->tv = *tv; - le->operation = operation; - le->args[0] = arg0; - le->args[1] = arg1; - le->args[2] = arg2; - logptr++; - logcount++; - if (logptr >= LOGSIZE) - logptr = 0; + if (pos->offset + pos->size > file_size) { + file_size = pos->offset + pos->size; + tst_res(TDEBUG, "File size changed: %llu", file_size); + } } -void logdump(void) +static int memory_compare( + const char *a, + const char *b, + const long long offset, + const long long size) { - int i, count, down; - struct log_entry *lp; - - prt("LOG DUMP (%d total operations):\n", logcount); - if (logcount < LOGSIZE) { - i = 0; - count = logcount; - } else { - i = logptr; - count = LOGSIZE; - } - for (; count > 0; count--) { - int opnum; + int diff; - opnum = i + 1 + (logcount / LOGSIZE) * LOGSIZE; - lp = &oplog[i]; - prt("%d: %lu.%06lu ", opnum, lp->tv.tv_sec, lp->tv.tv_usec); - - switch (lp->operation) { - case OP_MAPREAD: - prt("MAPREAD 0x%x thru 0x%x (0x%x bytes)", - lp->args[0], lp->args[0] + lp->args[1] - 1, - lp->args[1]); - if (badoff >= lp->args[0] && badoff < - lp->args[0] + lp->args[1]) - prt("\t***RRRR***"); - break; - case OP_MAPWRITE: - prt("MAPWRITE 0x%x thru 0x%x (0x%x bytes)", - lp->args[0], lp->args[0] + lp->args[1] - 1, - lp->args[1]); - if (badoff >= lp->args[0] && badoff < - lp->args[0] + lp->args[1]) - prt("\t******WWWW"); - break; - case OP_READ: - prt("READ 0x%x thru 0x%x (0x%x bytes)", - lp->args[0], lp->args[0] + lp->args[1] - 1, - lp->args[1]); - if (badoff >= lp->args[0] && - badoff < lp->args[0] + lp->args[1]) - prt("\t***RRRR***"); - break; - case OP_WRITE: - prt("WRITE 0x%x thru 0x%x (0x%x bytes)", - lp->args[0], lp->args[0] + lp->args[1] - 1, - lp->args[1]); - if (lp->args[0] > lp->args[2]) - prt(" HOLE"); - else if (lp->args[0] + lp->args[1] > lp->args[2]) - prt(" EXTEND"); - if ((badoff >= lp->args[0] || badoff >= lp->args[2]) && - badoff < lp->args[0] + lp->args[1]) - prt("\t***WWWW"); - break; - case OP_TRUNCATE: - down = lp->args[0] < lp->args[1]; - prt("TRUNCATE %s\tfrom 0x%x to 0x%x", - down ? "DOWN" : "UP", lp->args[1], lp->args[0]); - if (badoff >= lp->args[!down] && - badoff < lp->args[! !down]) - prt("\t******WWWW"); - break; - case OP_CLOSEOPEN: - prt("CLOSE/OPEN"); + for (long long i = 0; i < size; i++) { + diff = a[i] - b[i]; + if (diff) { + tst_res(TDEBUG, "File memory differs at offset=%llu ('%c' != '%c')", + offset + i, a[i], b[i]); break; - case OP_SKIPPED: - prt("SKIPPED (no operation)"); - break; - default: - prt("BOGUS LOG ENTRY (operation code = %d)!", - lp->operation); } - prt("\n"); - i++; - if (i == LOGSIZE) - i = 0; } + + return diff; } -void save_buffer(char *buffer, off_t bufferlength, int fd) +static int op_read(void) { - off_t ret; - ssize_t byteswritten; - - if (fd <= 0 || bufferlength == 0) - return; - - if (bufferlength > INT_MAX) { - prt("fsx flaw: overflow in save_buffer\n"); - exit(67); - } - if (lite) { - off_t size_by_seek = lseek(fd, (off_t) 0, SEEK_END); - if (size_by_seek == (off_t) - 1) - prterr("save_buffer: lseek eof"); - else if (bufferlength > size_by_seek) { - warn("save_buffer: .fsxgood file too short... will " - "save 0x%llx bytes instead of 0x%llx\n", - (unsigned long long)size_by_seek, - (unsigned long long)bufferlength); - bufferlength = size_by_seek; - } + if (!file_size) { + tst_res(TINFO, "Skipping zero size read"); + return 0; } - ret = lseek(fd, (off_t) 0, SEEK_SET); - if (ret == (off_t) - 1) - prterr("save_buffer: lseek 0"); - - byteswritten = write(fd, buffer, (size_t) bufferlength); - if (byteswritten != bufferlength) { - if (byteswritten == -1) - prterr("save_buffer write"); - else - warn("save_buffer: short write, 0x%x bytes instead " - "of 0x%llx\n", - (unsigned)byteswritten, - (unsigned long long)bufferlength); - } -} + struct file_pos_t pos; -void report_failure(int status) -{ - logdump(); - - if (fsxgoodfd) { - if (good_buf) { - save_buffer(good_buf, file_size, fsxgoodfd); - prt("Correct content saved for comparison\n"); - prt("(maybe hexdump \"%s\" vs \"%s\")\n", - fname, goodfile); - } - close(fsxgoodfd); - } - exit(status); -} + op_file_position(file_size, op_read_align, &pos); -#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \ - *(((unsigned char *)(cp)) + 1))) + tst_res(TDEBUG, "Reading at offset=%llu, size=%llu", + pos.offset, pos.size); -void check_buffers(unsigned offset, unsigned size) -{ - unsigned char c, t; - unsigned i = 0; - unsigned n = 0; - unsigned op = 0; - unsigned bad = 0; - - if (memcmp(good_buf + offset, temp_buf, size) != 0) { - prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n", - offset, size); - prt("OFFSET\tGOOD\tBAD\tRANGE\n"); - while (size > 0) { - c = good_buf[offset]; - t = temp_buf[i]; - if (c != t) { - if (n == 0) { - bad = short_at(&temp_buf[i]); - prt("%#07x\t%#06x\t%#06x", offset, - short_at(&good_buf[offset]), bad); - op = temp_buf[offset & 1 ? i + 1 : i]; - } - n++; - badoff = offset; - } - offset++; - i++; - size--; - } - if (n) { - prt("\t%#7x\n", n); - if (bad) - prt("operation# (mod 256) for the bad data " - "may be %u\n", ((unsigned)op & 0xff)); - else - prt("operation# (mod 256) for the bad data " - "unknown, check HOLE and EXTEND ops\n"); - } else - prt("????????????????\n"); - report_failure(110); - } -} + memset(temp_buff, 0, file_max_size); -struct test_file { - char *path; - int fd; -} *test_files = NULL; + SAFE_LSEEK(file_desc, (off_t)pos.offset, SEEK_SET); + SAFE_READ(0, file_desc, temp_buff, pos.size); -int num_test_files = 0; -enum fd_iteration_policy { - FD_SINGLE, - FD_ROTATE, - FD_RANDOM, -}; -int fd_policy = FD_RANDOM; -int fd_last = 0; + int ret = memory_compare( + file_buff + pos.offset, + temp_buff, + pos.offset, + pos.size); -struct test_file *get_tf(void) -{ - unsigned index = 0; - - switch (fd_policy) { - case FD_ROTATE: - index = fd_last++; - break; - case FD_RANDOM: - index = random(); - break; - case FD_SINGLE: - index = 0; - break; - default: - prt("unknown policy"); - exit(1); - break; - } - return &test_files[index % num_test_files]; + if (ret) + return -1; + + return 1; } -void assign_fd_policy(char *policy) +static int op_write(void) { - if (!strcmp(policy, "random")) - fd_policy = FD_RANDOM; - else if (!strcmp(policy, "rotate")) - fd_policy = FD_ROTATE; - else { - prt("unknown -I policy: '%s'\n", policy); - exit(1); + if (file_size >= file_max_size) { + tst_res(TINFO, "Skipping max size write"); + return 0; } -} -int get_fd(void) -{ - struct test_file *tf = get_tf(); - return tf->fd; -} + struct file_pos_t pos; + char data; -void open_test_files(char **argv, int argc) -{ - struct test_file *tf; - int i; + op_file_position(file_max_size, op_write_align, &pos); - num_test_files = argc; - if (num_test_files == 1) - fd_policy = FD_SINGLE; + for (long long i = 0; i < pos.size; i++) { + data = random() % 10 + 'a'; - test_files = calloc(num_test_files, sizeof(*test_files)); - if (test_files == NULL) { - prterr("reallocating space for test files"); - exit(1); + file_buff[pos.offset + i] = data; + temp_buff[i] = data; } - for (i = 0, tf = test_files; i < num_test_files; i++, tf++) { + tst_res(TDEBUG, "Writing at offset=%llu, size=%llu", + pos.offset, pos.size); - tf->path = argv[i]; - tf->fd = open(tf->path, O_RDWR | (lite ? 0 : O_CREAT | O_TRUNC), - 0666); - if (tf->fd < 0) { - prterr(tf->path); - exit(91); - } - } + SAFE_LSEEK(file_desc, (off_t)pos.offset, SEEK_SET); + SAFE_WRITE(SAFE_WRITE_ALL, file_desc, temp_buff, pos.size); - if (quiet || fd_policy == FD_SINGLE) - return; + update_file_size(&pos); - for (i = 0, tf = test_files; i < num_test_files; i++, tf++) - prt("fd %d: %s\n", i, tf->path); + return 1; } -void close_test_files(void) +static int op_truncate(void) { - int i; - struct test_file *tf; + struct file_pos_t pos; - for (i = 0, tf = test_files; i < num_test_files; i++, tf++) { - if (close(tf->fd)) { - prterr("close"); - report_failure(99); - } - } -} + op_file_position(file_max_size, op_trunc_align, &pos); + file_size = pos.offset + pos.size; -void check_size(void) -{ - struct stat statbuf; - off_t size_by_seek; - int fd = get_fd(); + tst_res(TDEBUG, "Truncating to %llu", file_size); - if (fstat(fd, &statbuf)) { - prterr("check_size: fstat"); - statbuf.st_size = -1; - } - size_by_seek = lseek(fd, (off_t) 0, SEEK_END); - if (file_size != statbuf.st_size || file_size != size_by_seek) { - prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n", - (unsigned long long)file_size, - (unsigned long long)statbuf.st_size, - (unsigned long long)size_by_seek); - report_failure(120); - } -} + SAFE_FTRUNCATE(file_desc, file_size); + memset(file_buff + file_size, 0, file_max_size - file_size); -void check_trunc_hack(void) -{ - struct stat statbuf; - int fd = get_fd(); - - ftruncate(fd, (off_t) 0); - ftruncate(fd, (off_t) 100000); - if (fstat(fd, &statbuf)) { - prterr("trunc_hack: fstat"); - statbuf.st_size = -1; - } - if (statbuf.st_size != (off_t) 100000) { - prt("no extend on truncate! not posix!\n"); - exit(130); - } - ftruncate(fd, 0); + return 1; } -static char *tf_buf = NULL; -static int max_tf_len = 0; - -void alloc_tf_buf(void) +static int op_map_read(void) { - char dummy = '\0'; - int highest = num_test_files - 1; - int len; - - len = snprintf(&dummy, 0, "%u ", highest); - if (len < 1) { - prterr("finding max tf_buf"); - exit(1); - } - len++; - tf_buf = malloc(len); - if (tf_buf == NULL) { - prterr("allocating tf_buf"); - exit(1); + if (!file_size) { + tst_res(TINFO, "Skipping zero size read"); + return 0; } - max_tf_len = snprintf(tf_buf, len, "%u ", highest); - if (max_tf_len < 1) { - prterr("fiding max_tv_len\n"); - exit(1); - } - if (max_tf_len != len - 1) { - warn("snprintf() gave %d instead of %d?\n", - max_tf_len, len - 1); - exit(1); - } -} -char *fill_tf_buf(struct test_file *tf) -{ - if (tf_buf == NULL) - alloc_tf_buf(); + struct file_pos_t pos; + char *addr; - sprintf(tf_buf, "%lu ", (unsigned long)(tf - test_files)); - return tf_buf; -} + op_file_position(file_size, op_read_align, &pos); + op_align_pages(&pos); -void -output_line(struct test_file *tf, int op, unsigned offset, - unsigned size, struct timeval *tv) -{ - char *tf_num = ""; - - char *ops[] = { - [OP_READ] = "read", - [OP_WRITE] = "write", - [OP_TRUNCATE] = "trunc from", - [OP_MAPREAD] = "mapread", - [OP_MAPWRITE] = "mapwrite", - }; - - /* W. */ - if (!(!quiet && ((progressinterval && - testcalls % progressinterval == 0) || - (debug && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))))) - return; - - if (fd_policy != FD_SINGLE) - tf_num = fill_tf_buf(tf); - - prt("%06lu %lu.%06lu %.*s%-10s %#08x %s %#08x\t(0x%x bytes)\n", - testcalls, tv->tv_sec, tv->tv_usec, max_tf_len, - tf_num, ops[op], - offset, op == OP_TRUNCATE ? " to " : "thru", - offset + size - 1, size); -} + tst_res(TDEBUG, "Map reading at offset=%llu, size=%llu", + pos.offset, pos.size); -void doread(unsigned offset, unsigned size) -{ - struct timeval t; - off_t ret; - unsigned iret; - struct test_file *tf = get_tf(); - int fd = tf->fd; - - offset -= offset % readbdy; - gettimeofday(&t, NULL); - if (size == 0) { - if (!quiet && testcalls > simulatedopcount) - prt("skipping zero size read\n"); - log4(OP_SKIPPED, OP_READ, offset, size, &t); - return; - } - if (size + offset > file_size) { - if (!quiet && testcalls > simulatedopcount) - prt("skipping seek/read past end of file\n"); - log4(OP_SKIPPED, OP_READ, offset, size, &t); - return; - } + addr = SAFE_MMAP( + 0, pos.size, + PROT_READ, + MAP_FILE | MAP_SHARED, + file_desc, + (off_t)pos.offset); - log4(OP_READ, offset, size, 0, &t); + memcpy(file_buff + pos.offset, addr, pos.size); - if (testcalls <= simulatedopcount) - return; + int ret = memory_compare( + addr, + file_buff + pos.offset, + pos.offset, + pos.size); - output_line(tf, OP_READ, offset, size, &t); + SAFE_MUNMAP(addr, pos.size); + if (ret) + return -1; - ret = lseek(fd, (off_t) offset, SEEK_SET); - if (ret == (off_t) - 1) { - prterr("doread: lseek"); - report_failure(140); - } - iret = read(fd, temp_buf, size); - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu read done\n", t.tv_sec, t.tv_usec); - } - if (iret != size) { - if (iret == -1) - prterr("doread: read"); - else - prt("short read: 0x%x bytes instead of 0x%x\n", - iret, size); - report_failure(141); - } - check_buffers(offset, size); + return 1; } -void domapread(unsigned offset, unsigned size) +static int op_map_write(void) { - struct timeval t; - unsigned pg_offset; - unsigned map_size; - char *p; - struct test_file *tf = get_tf(); - int fd = tf->fd; - - offset -= offset % readbdy; - gettimeofday(&t, NULL); - if (size == 0) { - if (!quiet && testcalls > simulatedopcount) - prt("skipping zero size read\n"); - log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t); - return; - } - if (size + offset > file_size) { - if (!quiet && testcalls > simulatedopcount) - prt("skipping seek/read past end of file\n"); - log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t); - return; + if (file_size >= file_max_size) { + tst_res(TINFO, "Skipping max size write"); + return 0; } - log4(OP_MAPREAD, offset, size, 0, &t); + struct file_pos_t pos; + char *addr; - if (testcalls <= simulatedopcount) - return; + op_file_position(file_max_size, op_write_align, &pos); + op_align_pages(&pos); - output_line(tf, OP_MAPREAD, offset, size, &t); + if (file_size < pos.offset + pos.size) + SAFE_FTRUNCATE(file_desc, pos.offset + pos.size); - pg_offset = offset & page_mask; - map_size = pg_offset + size; + tst_res(TDEBUG, "Map writing at offset=%llu, size=%llu", + pos.offset, pos.size); - if ((p = mmap(0, map_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, - (off_t) (offset - pg_offset))) == MAP_FAILED) { - prterr("domapread: mmap"); - report_failure(190); - } - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu mmap done\n", t.tv_sec, t.tv_usec); - } - memcpy(temp_buf, p + pg_offset, size); - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu memcpy done\n", t.tv_sec, t.tv_usec); - } - if (munmap(p, map_size) != 0) { - prterr("domapread: munmap"); - report_failure(191); - } - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu munmap done\n", t.tv_sec, t.tv_usec); - } + for (long long i = 0; i < pos.size; i++) + file_buff[pos.offset + i] = random() % 10 + 'l'; - check_buffers(offset, size); -} + addr = SAFE_MMAP( + 0, pos.size, + PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, + file_desc, + (off_t)pos.offset); -void gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size) -{ - while (size--) { - good_buf[offset] = testcalls % 256; - if (offset % 2) - good_buf[offset] += original_buf[offset]; - offset++; - } -} + memcpy(addr, file_buff + pos.offset, pos.size); + SAFE_MSYNC(addr, pos.size, MS_SYNC); + SAFE_MUNMAP(addr, pos.size); + update_file_size(&pos); -void dowrite(unsigned offset, unsigned size) -{ - struct timeval t; - off_t ret; - unsigned iret; - struct test_file *tf = get_tf(); - int fd = tf->fd; - - offset -= offset % writebdy; - gettimeofday(&t, NULL); - if (size == 0) { - if (!quiet && testcalls > simulatedopcount) - prt("skipping zero size write\n"); - log4(OP_SKIPPED, OP_WRITE, offset, size, &t); - return; - } - - log4(OP_WRITE, offset, size, file_size, &t); - - gendata(original_buf, good_buf, offset, size); - if (file_size < offset + size) { - if (file_size < offset) - memset(good_buf + file_size, '\0', offset - file_size); - file_size = offset + size; - if (lite) { - warn("Lite file size bug in fsx!"); - report_failure(149); - } - } - - if (testcalls <= simulatedopcount) - return; - - output_line(tf, OP_WRITE, offset, size, &t); - - ret = lseek(fd, (off_t) offset, SEEK_SET); - if (ret == (off_t) - 1) { - prterr("dowrite: lseek"); - report_failure(150); - } - iret = write(fd, good_buf + offset, size); - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu write done\n", t.tv_sec, t.tv_usec); - } - if (iret != size) { - if (iret == -1) - prterr("dowrite: write"); - else - prt("short write: 0x%x bytes instead of 0x%x\n", - iret, size); - report_failure(151); - } + return 1; } -void domapwrite(unsigned offset, unsigned size) +static void run(void) { - struct timeval t; - unsigned pg_offset; - unsigned map_size; - off_t cur_filesize; - char *p; - struct test_file *tf = get_tf(); - int fd = tf->fd; - - offset -= offset % writebdy; - gettimeofday(&t, NULL); - if (size == 0) { - if (!quiet && testcalls > simulatedopcount) - prt("skipping zero size write\n"); - log4(OP_SKIPPED, OP_MAPWRITE, offset, size, &t); - return; - } - cur_filesize = file_size; - - log4(OP_MAPWRITE, offset, size, 0, &t); - - gendata(original_buf, good_buf, offset, size); - if (file_size < offset + size) { - if (file_size < offset) - memset(good_buf + file_size, '\0', offset - file_size); - file_size = offset + size; - if (lite) { - warn("Lite file size bug in fsx!"); - report_failure(200); - } - } + int op; + int ret; + int counter = 0; - if (testcalls <= simulatedopcount) - return; + file_size = 0; - output_line(tf, OP_MAPWRITE, offset, size, &t); + memset(file_buff, 0, file_max_size); + memset(temp_buff, 0, file_max_size); - if (file_size > cur_filesize) { - if (ftruncate(fd, file_size) == -1) { - prterr("domapwrite: ftruncate"); - exit(201); - } - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 - || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu truncate done\n", t.tv_sec, - t.tv_usec); - } - } - pg_offset = offset & page_mask; - map_size = pg_offset + size; - - if ((p = - mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, - fd, (off_t) (offset - pg_offset))) == MAP_FAILED) { - prterr("domapwrite: mmap"); - report_failure(202); - } - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu mmap done\n", t.tv_sec, t.tv_usec); - } - memcpy(p + pg_offset, good_buf + offset, size); - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu memcpy done\n", t.tv_sec, t.tv_usec); - } - if (msync(p, map_size, 0) != 0) { - prterr("domapwrite: msync"); - report_failure(203); - } - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu msync done\n", t.tv_sec, t.tv_usec); - } - if (munmap(p, map_size) != 0) { - prterr("domapwrite: munmap"); - report_failure(204); - } - if (!quiet && (debug > 1 && - (monitorstart == -1 || - (offset + size > monitorstart && - (monitorend == -1 || offset <= monitorend))))) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu munmap done\n", t.tv_sec, t.tv_usec); - } -} + SAFE_FTRUNCATE(file_desc, 0); -void dotruncate(unsigned size) -{ - struct timeval t; - int oldsize = file_size; - struct test_file *tf = get_tf(); - int fd = tf->fd; - - size -= size % truncbdy; - gettimeofday(&t, NULL); - if (size > biggest) { - biggest = size; - if (!quiet && testcalls > simulatedopcount) - prt("truncating to largest ever: 0x%x\n", size); - } + while (counter < op_nums) { + op = random() % OP_TOTAL; - log4(OP_TRUNCATE, size, (unsigned)file_size, 0, &t); - - if (size > file_size) - memset(good_buf + file_size, '\0', size - file_size); - file_size = size; - - if (testcalls <= simulatedopcount) - return; + switch (op) { + case OP_WRITE: + ret = op_write(); + break; + case OP_MAPREAD: + ret = op_map_read(); + break; + case OP_MAPWRITE: + ret = op_map_write(); + break; + case OP_TRUNCATE: + ret = op_truncate(); + break; + case OP_READ: + default: + ret = op_read(); + break; + }; - output_line(tf, OP_TRUNCATE, oldsize, size, &t); + if (ret == -1) + break; - if (ftruncate(fd, (off_t) size) == -1) { - prt("ftruncate1: %x\n", size); - prterr("dotruncate: ftruncate"); - report_failure(160); - } - if (!quiet && debug > 1) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu trunc done\n", t.tv_sec, t.tv_usec); + counter += ret; } + + if (counter != op_nums) + tst_brk(TFAIL, "Some file operations failed"); + else + tst_res(TPASS, "All file operations succeed"); } -void writefileimage(void) +static void setup(void) { - ssize_t iret; - int fd = get_fd(); + if (tst_parse_filesize(str_file_max_size, &file_max_size, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid file size '%s'", str_file_max_size); - if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) { - prterr("writefileimage: lseek"); - report_failure(171); - } - iret = write(fd, good_buf, file_size); - if ((off_t) iret != file_size) { - if (iret == -1) - prterr("writefileimage: write"); - else - prt("short write: 0x%lx bytes instead of 0x%llx\n", - (unsigned long)iret, (unsigned long long)file_size); - report_failure(172); - } - if (lite ? 0 : ftruncate(fd, file_size) == -1) { - prt("ftruncate2: %llx\n", (unsigned long long)file_size); - prterr("writefileimage: ftruncate"); - report_failure(173); - } -} + if (tst_parse_filesize(str_op_max_size, &op_max_size, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid maximum size for single operation '%s'", str_op_max_size); -void docloseopen(void) -{ - struct timeval t; - struct test_file *tf = get_tf(); + if (tst_parse_int(str_op_nums, &op_nums, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of operations '%s'", str_op_nums); - if (testcalls <= simulatedopcount) - return; + if (tst_parse_int(str_op_write_align, &op_write_align, 1, INT_MAX)) + tst_brk(TBROK, "Invalid memory write alignment factor '%s'", str_op_write_align); - gettimeofday(&t, NULL); - log4(OP_CLOSEOPEN, file_size, (unsigned)file_size, 0, &t); + if (tst_parse_int(str_op_read_align, &op_read_align, 1, INT_MAX)) + tst_brk(TBROK, "Invalid memory read alignment factor '%s'", str_op_read_align); - if (debug) - prt("%06lu %lu.%06lu close/open\n", testcalls, t.tv_sec, - t.tv_usec); - if (close(tf->fd)) { - prterr("docloseopen: close"); - report_failure(180); - } - if (!quiet && debug > 1) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu close done\n", t.tv_sec, t.tv_usec); - } - tf->fd = open(tf->path, O_RDWR, 0); - if (tf->fd < 0) { - prterr("docloseopen: open"); - report_failure(181); - } - if (!quiet && debug > 1) { - gettimeofday(&t, NULL); - prt(" %lu.%06lu open done\n", t.tv_sec, t.tv_usec); - } -} + if (tst_parse_int(str_op_trunc_align, &op_trunc_align, 1, INT_MAX)) + tst_brk(TBROK, "Invalid memory truncate alignment factor '%s'", str_op_trunc_align); -void test(void) -{ - unsigned long offset; - unsigned long size = maxoplen; - unsigned long rv = random(); - unsigned long op = rv % (3 + !lite + mapped_writes); - - /* turn off the map read if necessary */ - - if (op == 2 && !mapped_reads) - op = 0; - - if (simulatedopcount > 0 && testcalls == simulatedopcount) - writefileimage(); - - testcalls++; - - if (debugstart > 0 && testcalls >= debugstart) - debug = 1; - - if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0) - prt("%lu...\n", testcalls); - - /* - * READ: op = 0 - * WRITE: op = 1 - * MAPREAD: op = 2 - * TRUNCATE: op = 3 - * MAPWRITE: op = 3 or 4 - */ - if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */ - dotruncate(random() % maxfilelen); - else { - if (randomoplen) - size = random() % (maxoplen + 1); - if (lite ? 0 : op == 3) - dotruncate(size); - else { - offset = random(); - if (op == 1 || op == (lite ? 3 : 4)) { - offset %= maxfilelen; - if (offset + size > maxfilelen) - size = maxfilelen - offset; - if (op != 1) - domapwrite(offset, size); - else - dowrite(offset, size); - } else { - if (file_size) - offset %= file_size; - else - offset = 0; - if (offset + size > file_size) - size = file_size - offset; - if (op != 0) - domapread(offset, size); - else - doread(offset, size); - } - } - } - if (sizechecks && testcalls > simulatedopcount) - check_size(); - if (closeprob && (rv >> 3) < (1 << 28) / closeprob) - docloseopen(); -} + page_size = (int)sysconf(_SC_PAGESIZE); -void cleanup(int sig) -{ - if (sig) - prt("signal %d\n", sig); - prt("testcalls = %lu\n", testcalls); - exit(sig); -} + srandom(time(NULL)); -void usage(void) -{ - fprintf(stdout, "usage: %s", - "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m " - "start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t " - "truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] " - "[ -I random|rotate ] fname [additional paths to fname..]\n" - " -b opnum: beginning operation number (default 1)\n" - " -c P: 1 in P chance of file close+open at each op (default infinity)\n" - " -d: debug output for all operations [-d -d = more debugging]\n" - " -l flen: the upper bound on file size (default 262144)\n" - " -m start:end: monitor (print debug) specified byte range (default 0:infinity)\n" - " -n: no verifications of file size\n" - " -o oplen: the upper bound on operation size (default 65536)\n" - " -p progressinterval: debug output at specified operation interval\n" - " -q: quieter operation\n" - " -r readbdy: 4096 would make reads page aligned (default 1)\n" - " -s style: 1 gives smaller truncates (default 0)\n" - " -t truncbdy: 4096 would make truncates page aligned (default 1)\n" - " -w writebdy: 4096 would make writes page aligned (default 1)\n" - " -D startingop: debug output starting at specified operation\n" - " -L: fsxLite - no file creations & no file size changes\n" - " -N numops: total # operations to do (default infinity)\n" - " -O: use oplen (see -o flag) for every op (default random)\n" - " -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n" - " -S seed: for random # generator (default 1) 0 gets timestamp\n" - " -W: mapped write operations DISabled\n" - " -R: read() system calls only (mapped reads disabled)\n" - " -I: When multiple paths to the file are given each operation uses\n" - " a different path. Iterate through them in order with 'rotate'\n" - " or chose then at 'random'. (defaults to random)\n" - " fname: this filename is REQUIRED (no default)\n"); - exit(90); -} + file_desc = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0666); -int getnum(char *s, char **e) -{ - int ret = -1; - - *e = NULL; - ret = strtol(s, e, 0); - if (*e) - switch (**e) { - case 'b': - case 'B': - ret *= 512; - *e = *e + 1; - break; - case 'k': - case 'K': - ret *= 1024; - *e = *e + 1; - break; - case 'm': - case 'M': - ret *= 1024 * 1024; - *e = *e + 1; - break; - case 'w': - case 'W': - ret *= 4; - *e = *e + 1; - break; - } - return (ret); + file_buff = SAFE_MALLOC(file_max_size); + temp_buff = SAFE_MALLOC(file_max_size); } -int main(int argc, char **argv) +static void cleanup(void) { - int i, style, ch; - char *endp; - int dirpath = 0; - - goodfile[0] = 0; - logfile[0] = 0; - - page_size = getpagesize(); - page_mask = page_size - 1; - - setvbuf(stdout, NULL, _IOLBF, 0); /* line buffered stdout */ - - while ((ch = getopt(argc, argv, - "b:c:dl:m:no:p:qr:s:t:w:D:I:LN:OP:RS:W")) - != EOF) - switch (ch) { - case 'b': - simulatedopcount = getnum(optarg, &endp); - if (!quiet) - fprintf(stdout, "Will begin at operation" - "%ld\n", simulatedopcount); - if (simulatedopcount == 0) - usage(); - simulatedopcount -= 1; - break; - case 'c': - closeprob = getnum(optarg, &endp); - if (!quiet) - fprintf(stdout, - "Chance of close/open is 1 in %d\n", - closeprob); - if (closeprob <= 0) - usage(); - break; - case 'd': - debug++; - break; - case 'l': - maxfilelen = getnum(optarg, &endp); - if (maxfilelen <= 0) - usage(); - break; - case 'm': - monitorstart = getnum(optarg, &endp); - if (monitorstart < 0) - usage(); - if (!endp || *endp++ != ':') - usage(); - monitorend = getnum(endp, &endp); - if (monitorend < 0) - usage(); - if (monitorend == 0) - monitorend = -1; /* aka infinity */ - debug = 1; - case 'n': - sizechecks = 0; - break; - case 'o': - maxoplen = getnum(optarg, &endp); - if (maxoplen <= 0) - usage(); - break; - case 'p': - progressinterval = getnum(optarg, &endp); - if (progressinterval < 0) - usage(); - break; - case 'q': - quiet = 1; - break; - case 'r': - readbdy = getnum(optarg, &endp); - if (readbdy <= 0) - usage(); - break; - case 's': - style = getnum(optarg, &endp); - if (style < 0 || style > 1) - usage(); - break; - case 't': - truncbdy = getnum(optarg, &endp); - if (truncbdy <= 0) - usage(); - break; - case 'w': - writebdy = getnum(optarg, &endp); - if (writebdy <= 0) - usage(); - break; - case 'D': - debugstart = getnum(optarg, &endp); - if (debugstart < 1) - usage(); - break; - case 'I': - assign_fd_policy(optarg); - break; - case 'L': - lite = 1; - break; - case 'N': - numops = getnum(optarg, &endp); - if (numops < 0) - usage(); - break; - case 'O': - randomoplen = 0; - break; - case 'P': - strncpy(goodfile, optarg, sizeof(goodfile)); - strcat(goodfile, "/"); - strncpy(logfile, optarg, sizeof(logfile)); - strcat(logfile, "/"); - dirpath = 1; - break; - case 'R': - mapped_reads = 0; - break; - case 'S': - seed = getnum(optarg, &endp); - if (seed == 0) - seed = time(0) % 10000; - if (!quiet) - fprintf(stdout, "Seed set to %d\n", seed); - if (seed < 0) - usage(); - break; - case 'W': - mapped_writes = 0; - if (!quiet) - fprintf(stdout, "mapped writes DISABLED\n"); - break; + if (file_buff) + free(file_buff); - default: - usage(); + if (temp_buff) + free(temp_buff); - } - argc -= optind; - argv += optind; - if (argc < 1) - usage(); - fname = argv[0]; - - signal(SIGHUP, cleanup); - signal(SIGINT, cleanup); - signal(SIGPIPE, cleanup); - signal(SIGALRM, cleanup); - signal(SIGTERM, cleanup); - signal(SIGXCPU, cleanup); - signal(SIGXFSZ, cleanup); - signal(SIGVTALRM, cleanup); - signal(SIGUSR1, cleanup); - signal(SIGUSR2, cleanup); - - initstate(seed, state, 256); - setstate(state); - - open_test_files(argv, argc); - - strncat(goodfile, dirpath ? basename(fname) : fname, 256); - strcat(goodfile, ".fsxgood"); - fsxgoodfd = open(goodfile, O_RDWR | O_CREAT | O_TRUNC, 0666); - if (fsxgoodfd < 0) { - prterr(goodfile); - exit(92); - } - strncat(logfile, dirpath ? basename(fname) : fname, 256); - strcat(logfile, ".fsxlog"); - fsxlogf = fopen(logfile, "w"); - if (fsxlogf == NULL) { - prterr(logfile); - exit(93); - } - if (lite) { - off_t ret; - int fd = get_fd(); - file_size = maxfilelen = lseek(fd, (off_t) 0, SEEK_END); - if (file_size == (off_t) - 1) { - prterr(fname); - warn("main: lseek eof"); - exit(94); - } - ret = lseek(fd, (off_t) 0, SEEK_SET); - if (ret == (off_t) - 1) { - prterr(fname); - warn("main: lseek 0"); - exit(95); - } - } - original_buf = malloc(maxfilelen); - if (original_buf == NULL) - exit(96); - for (i = 0; i < maxfilelen; i++) - original_buf[i] = random() % 256; - - good_buf = malloc(maxfilelen); - if (good_buf == NULL) - exit(97); - memset(good_buf, '\0', maxfilelen); - - temp_buf = malloc(maxoplen); - if (temp_buf == NULL) - exit(99); - memset(temp_buf, '\0', maxoplen); - - if (lite) { /* zero entire existing file */ - ssize_t written; - int fd = get_fd(); - - written = write(fd, good_buf, (size_t) maxfilelen); - if (written != maxfilelen) { - if (written == -1) { - prterr(fname); - warn("main: error on write"); - } else - warn("main: short write, 0x%x bytes instead " - "of 0x%x\n", - (unsigned)written, maxfilelen); - exit(98); - } - } else - check_trunc_hack(); - - while (numops == -1 || numops--) - test(); - - close_test_files(); - prt("All operations completed A-OK!\n"); - - if (tf_buf) - free(tf_buf); - - free(original_buf); - free(good_buf); - free(temp_buf); - - return 0; + if (file_desc) + SAFE_CLOSE(file_desc); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .max_runtime = 1800, + .options = (struct tst_option[]) { + { "l:", &str_file_max_size, "Maximum size in MB of the test file(s) (default 262144)" }, + { "o:", &str_op_max_size, "Maximum size for single operation (default 65536)" }, + { "N:", &str_op_nums, "Total # operations to do (default 1000)" }, + { "w:", &str_op_write_align, "Write memory page alignment (default 1)" }, + { "r:", &str_op_read_align, "Read memory page alignment (default 1)" }, + { "t:", &str_op_trunc_align, "Truncate memory page alignment (default 1)" }, + {}, + }, +}; diff --git a/testcases/kernel/fs/fsx-linux/fsxtest b/testcases/kernel/fs/fsx-linux/fsxtest deleted file mode 100755 index 61835437d..000000000 --- a/testcases/kernel/fs/fsx-linux/fsxtest +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. -# Copyright (c) International Business Machines Corp., 2001 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# -# -# Proper error checking and result reporting still needed -# -# usage: fsxtest $1 $2 $3 -# $1 scratch device to use for testing -# $2 optional file system type -# $3 number of operations to perform - -#Uncomment line below for debugging -#set -x -if [ $2 = "jfs" ]; then - mkfs -t $2 -q $1 -else - mkfs -t $2 $1 -fi -mkdir /testmount -mount -t $2 $1 /testmount -touch /testmount/testfile -fsx-linux -N $3 /testmount/testfile -RESULT=$? -# report the results -if [ $RESULT -eq "0" ]; then - echo "PASS: fsxtest $1 $2 $3" -else - echo "FAIL: fsxtest $1 $2 $3" -fi -umount /testmount -rm -rf /testmount -fsck -a -t $2 $1 # report the results -exit $RESULT diff --git a/testcases/kernel/fs/fsx-linux/fsxtest02 b/testcases/kernel/fs/fsx-linux/fsxtest02 deleted file mode 100755 index fe014abdd..000000000 --- a/testcases/kernel/fs/fsx-linux/fsxtest02 +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. -# Copyright (c) International Business Machines Corp., 2001 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# -# -# Proper error checking and result reporting still needed -# -# usage: fsxtest02 $1 -# $1 number of operations to perform - -#Uncomment line below for debugging -#set -x - -TCbin=${TCbin:-`pwd`} -TCtmp=${TCtmp:-/tmp/fsxtest2.$$} - -mkdir -p $TCtmp 2>/dev/null -touch $TCtmp/testfile -$TCbin/fsx-linux -N $1 $TCtmp/testfile -RESULT=$? -# report the results -if [ $RESULT -eq "0" ]; then - echo "PASS: fsxtest02 $1 $2 $3" -else - echo "FAIL: fsxtest02 $1 $2 $3" -fi -rm -rf $TCtmp -exit $RESULT diff --git a/testcases/kernel/fs/iso9660/isofs.sh b/testcases/kernel/fs/iso9660/isofs.sh index dfa4ac73d..d1a362d97 100755 --- a/testcases/kernel/fs/iso9660/isofs.sh +++ b/testcases/kernel/fs/iso9660/isofs.sh @@ -1,7 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2003 -# Copyright (c) Linux Test Project, 2016-2021 +# Copyright (c) Linux Test Project, 2016-2024 # Written by Prakash Narayana (prakashn@us.ibm.com) # and Michael Reed (mreed10@us.ibm.com) # @@ -11,23 +11,12 @@ TST_NEEDS_CMDS="mount umount" TST_NEEDS_TMPDIR=1 -TST_SETUP=setup TST_TESTFUNC=do_test +TST_CNT=3 MAX_DEPTH=3 MAX_DIRS=4 -setup() -{ - if tst_cmd_available mkisofs; then - MKISOFS_CMD="mkisofs" - elif tst_cmd_available genisoimage; then - MKISOFS_CMD="genisoimage" - else - tst_brk TCONF "please install mkisofs or genisoimage" - fi -} - gen_fs_tree() { local cur_path="$1" @@ -50,10 +39,33 @@ do_test() local make_file_sys_dir="$PWD/files" local mkisofs_opt mount_opt + case $1 in + 1) MKISOFS_CMD="mkisofs" + HFSOPT="-hfs -D" + GREPOPT="mkisofs";; + 2) MKISOFS_CMD="genisoimage" + HFSOPT="-hfsplus -D -hfs -D" + GREPOPT="genisoimage";; + 3) MKISOFS_CMD="xorrisofs" + HFSOPT="-hfsplus -D" + GREPOPT="xorriso";; + esac + + if ! tst_cmd_available $MKISOFS_CMD; then + tst_res TCONF "Missing '$MKISOFS_CMD'" + return + fi + + if ! $MKISOFS_CMD 2>&1 | head -n 2 | grep -q "$GREPOPT"; then + tst_res TCONF "'$MKISOFS_CMD' is a symlink to another tool" + return + fi + + tst_res TINFO "Testing $MKISOFS_CMD" + mkdir -p -m 777 $mnt_point mkdir -p $make_file_sys_dir - # Generated directories and files mkdir -p $make_file_sys_dir gen_fs_tree "$make_file_sys_dir" 1 @@ -62,15 +74,16 @@ do_test() for mkisofs_opt in \ " " \ "-J" \ - "-hfs -D" \ + "$HFSOPT" \ " -R " \ "-R -J" \ "-f -l -D -J -allow-leading-dots -R" \ - "-allow-lowercase -allow-multidot -iso-level 3 -f -l -D -J -allow-leading-dots -R" + "-allow-lowercase -allow-multidot -iso-level 3 -f -l -D -J \ + -allow-leading-dots -R" do rm -f isofs.iso - EXPECT_PASS $MKISOFS_CMD -o isofs.iso -quiet $mkisofs_opt $make_file_sys_dir 2\> /dev/null \ - || continue + EXPECT_PASS $MKISOFS_CMD -o isofs.iso -quiet $mkisofs_opt \ + $make_file_sys_dir 2\> /dev/null || continue for mount_opt in \ "loop" \ diff --git a/testcases/kernel/fs/mongo/README b/testcases/kernel/fs/mongo/README deleted file mode 100644 index a134305b6..000000000 --- a/testcases/kernel/fs/mongo/README +++ /dev/null @@ -1,37 +0,0 @@ - - MONGO.PL BENCHMARK. - -To run mongo benchmark please use the next : - -# run_mongo <device> <processes> - -Where : -<device> - test device -<processes> - number of processes - -The benchmark will be performed on given device with -reiserfs and ext2. Then results will be compared. - -The results directory : ./results -The comparision *.html and *.txt files in ./results/html - -Warning : All info will be erased on device. - ------------------------------------------------------- - -Mongo.pl description : - - mongo.pl <filesystem> <device> <test_dir> <log> <processes> - - for example : - mongo.pl reiserfs /dev/hda5 /testfs log 1 - -Be careful : - /dev/hda5 - test device and all info on it will be erased. - It should be at least 500 Mb in size. - - /testfs - mount-point directory - - log - name prefix for results file. - - diff --git a/testcases/kernel/fs/mongo/map5.c b/testcases/kernel/fs/mongo/map5.c deleted file mode 100644 index 7cd700e98..000000000 --- a/testcases/kernel/fs/mongo/map5.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README - */ - -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <linux/fs.h> -#include <errno.h> - -int main(int argc, char **argv) -{ - int fd; - int block; - int first_block; - int last_block; - int totals_block; - int fragments; - int i; - int n; - - for (n = 1; n < argc; n++) { - if (argc < 2) { - printf - ("Used to see file maps \nUsage: %s filename1 [[..[filename2]...filename(N-1)] filenameN]\n", - argv[0]); - return 0; - } - fd = open(argv[n], O_RDONLY); - if (fd == -1) { - perror("open failed"); - continue; - } - // printf ("file %s occupies blocks: \n", argv[1]); - // printf ("START\tEND\tCOUNT\n"); - i = 0; - block = 0; - first_block = 0; - last_block = 0; - fragments = 0; - totals_block = 0; - - while (ioctl(fd, FIBMAP, &block) == 0) { - if (first_block == 0) { - last_block = block - 1; - first_block = block; - } - if (block != last_block + 1) { - // printf ("%d\t%d\t%d\n",first_block,last_block,last_block-first_block+1); - totals_block += last_block - first_block + 1; - fragments++; - first_block = block; - last_block = block; - } else { - last_block++; - } - - if (!block) { - //printf ("Fragments: %d\tBlocks: %d\n",fragments,totals_block); - //printf ("%d:%d\t",fragments,totals_block); - //if (fragments == 1) printf(".",totals_block); - //else printf("%d_",fragments,totals_block); - printf("%d\n", fragments); - break; - } - - i++; - block = i; - } - if (errno) { - perror("FIBMAP failed"); - } - close(fd); - // printf ("\n"); - } - return 0; -} diff --git a/testcases/kernel/fs/mongo/mongo.pl b/testcases/kernel/fs/mongo/mongo.pl deleted file mode 100755 index 5d47d8746..000000000 --- a/testcases/kernel/fs/mongo/mongo.pl +++ /dev/null @@ -1,511 +0,0 @@ -#!/usr/bin/perl -# -# Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README -# - -# -# Mongo.pl is reiserfs benchmark. -# -# To run please use run_mongo script or : -# -# # ./mongo.pl reiserfs /dev/xxxx /testfs log1 5 -# or -# # ./mongo.pl ext2 /dev/xxxx /testfs log2 5 -# -# 5 - number of processes, you can set any number here -# -# Test will format partition /dev/xxxx by 'mkreiserfs' or 'mke2fs' -# mount it and run given number of processes during each phase : -# Create, Copy, Symlinks, Read, Stats, Rename and Delete. -# -# Also, the program calc fragmentations after Create and Copy phases: -# Fragm = number_of_fragments / number_of_files -# (Current version use the files more than 16KB to calc Fragm.) -# -# You can find the same results in files : log, log.tbl, log_table -# -# log - raw results -# log.tbl - results for compare program -# log_table - results in table form -# - -$EXTENDED_STATISTICS = 1; - - -use POSIX; -use File::stat; - -sub print_usage { - - print "\nUsage: mongo.pl <filesystem> <device>"; - print " <mount_point> <log> <processes>\n"; - - print "<filesystem> - the name of filesystem [reiserfs|ext2]\n"; - print "<device> - the device for benchmark (e.g. /dev/hda9)\n"; - print "<mount_point> - mount-point for the filesystem"; - print " (e.g. /mnt/testfs)\n"; - print "<log> - the name prefix for benchmark results\n"; - print "<processes> - the number of benchmark processes\n"; - - print "\nexamples:\n"; - print "mongo.pl reiserfs /dev/hda9 /testfs reiserfs_results 1\n"; - print "mongo.pl ext2 /dev/hda9 /testfs ext2_results 1\n"; - - print "\nThe results will be put in ./results directory\n"; -} - - -#------- Subroutines declaration -------- -sub make_fsys; -sub mongo_x_process; -sub mongo_launcher; -sub set_params; - -#------- main() ------------------------- - -if ( $#{ARGV} != 4 ) { - print_usage; - exit(0); - } - -#-------------------------------------------- -# Set working directories -#-------------------------------------------- -$TOPDIR = "$ENV{PWD}"; - -$RESDIR = "${TOPDIR}/results"; -$HTMLDIR = "${RESDIR}/html"; - -$FILESYSTEM = $ARGV[0]; -$DEVICE = $ARGV[1]; -$TESTDIR = $ARGV[2]; -$PROCESSES = $ARGV[4]; - -$LOGFILE = "${RESDIR}/${ARGV[3]}"; -$LOGFILE2 = "${LOGFILE}_table"; -$LOGFILE3 = "${LOGFILE}.tbl"; - -$TMPFILE = "${RESDIR}/mongo_tmp"; -$nproc = $PROCESSES; -$READIT = "${TOPDIR}/mongo_read"; -$SLINKS = "${TOPDIR}/mongo_slinks"; - -#-------- reiser_fract_tree parameters---------------- -$x1mb = 1024 * 1024; -$x2mb = 2 * $x1mb; -$x3mb = 3 * $x1mb; - -$x5mb = 5 * $x1mb; -$x50mb = 50 * $x1mb; -$x100mb = 100 * $x1mb; - -# Total amount of bytes in all files on test partition -#----------------------------------------------------- - -$small_bytes = $x50mb; -$medium_bytes = $x100mb; -$big_bytes = $x100mb; -$large_bytes = $x100mb; - -# Median size of files in bytes for first tree to create -#------------------------------------------------------- -$small_size = 100; -$medium_size = 1000; -$big_size = 10000; -$large_size = 100000; - -# Keep the largest file to one fifth (100 million bytes) -# of the total tree size. -#------------------------------------------------------- -$max_file_size = 100000000; - -# Yuri Shevchuk says that 0 is the median size -# in real life, so I believe him. -#---------------------------------------------- -$median_dir_nr_files = 0; - -# This should be larger, change once done testing. -#------------------------------------------------- -$bytes_to_consume = 10000000; - -$median_file_size = 100; -$max_file_size = 1000000; - -$median_dir_nr_files = 100; -$max_directory_nr_files = 10000; - -$median_dir_branching = 0; -$max_dir_branching = 1; - -# This should be varying, someday.... -#------------------------------------ -$write_buffer_size = 4096; - -@numb_of_bytes = ($small_bytes, $medium_bytes, $big_bytes, $large_bytes); -@size_of_files = ($small_size, $medium_size, $big_size, $large_size); - -$reiser_fract_tree_rep_counter = 3; - -$total_params = $#{numb_of_bytes}; - -#... Make directories for results -#-------------------------------- -unless (-e $RESDIR) { - print "Creating dir: ${RESDIR} \n"; - system("mkdir $RESDIR"); -} - -unless ( -e $HTMLDIR ) { - print "Creating dir: ${HTMLDIR} \n"; - system("mkdir $HTMLDIR"); -} - -#... Compile *.c files if it is necessary -#---------------------------------------- -sub compile -{ - my $file = shift @_; - my $opt = shift @_ if @_ ; - my $cfile = $file . ".c"; - die "source file \"${cfile}\" does not exist" unless (-e "$cfile"); - if ( -e "$file" && (stat("$file")->mtime >= stat("$cfile")->mtime)) { - print "$file is up to date ...\n"; - } else { - print "Compiling ${cfile} ...\n"; - system ("gcc $cfile -o $file $opt"); - } -} - -compile("reiser_fract_tree", "-lm"); -compile("mongo_slinks"); -compile("mongo_read"); -compile("map5"); -compile("summ"); -compile("mongo_compare"); - -#... Check the command string parameters -#--------------------------------------- -unless ( ($FILESYSTEM eq "reiserfs") or ($FILESYSTEM eq "ext2") ) { - print "mongo.pl: not valid filesystem name: ${FILESYSTEM} \n"; - print "Usage: mongo.pl <filesystem> <device> <mount_point> <log> <repeat>\n"; - exit(0); -} - -unless ( -b $DEVICE ) { - print "mongo.pl: not valid device: ${DEVICE} \n"; - print "Usage: mongo.pl <filesystem> <device> <mount_point> <log> <repeat>\n"; - exit(0); -} - - -#------- Subroutines -------------------------------------- -#---------------------------------------------------------- -sub get_blocks_usage ($) { - my ($mp) = @_; - my $df = `df -k $mp | tail -n 1`; - chomp $df; - my @items = split / +/, $df; - return $items[2]; -} - -sub make_fsys { - - system ("umount $TESTDIR") ; - - if ( $FILESYSTEM eq "reiserfs" ) { - system("echo y | mkreiserfs $DEVICE") ; - system("mount -t reiserfs $DEVICE $TESTDIR") ; - } - - if ( $FILESYSTEM eq "ext2" ) { - system("mke2fs $DEVICE") ; - system("mount $DEVICE $TESTDIR") ; - } -} - - -#------------------------------------------------------------------ -# Mongo Launcher -#------------------------------------------------------------------ -sub mongo_launcher { - - my ($phase_num, $phase_name, $cmd, $dir1, $dir2, $flag, $processes) = @_ ; - - - print "$phase_num.$phase_name files of median size $median_file_size bytes ($p processes)...\n"; - print LOG "********* Phase $phase_num: $phase_name files of median size $median_file_size bytes ($p processes) *********\n"; - $i=0; - $total=0; - -# eliminate the rep counter and the while - while ( $i < $reiser_fract_tree_rep_counter ) { - print "$phase_name : "; - print LOG "$phase_name : "; - $com = ""; - $pp=$processes; - - $j=0; - while ($pp > 0) { - $pp--; - -# the fact that this if statement was necessary indicated you -# attempted excessive generalization and abstraction where it was not -# natural to the task that makes the code harder to understand. put -# every command on one line to execute. I like it when I can read a -# one line command and see what that phase of the test does instead of -# looking in many places throughout the code. - - if ($phase_num == 1) { - $com .= "$cmd $dir1-$i-$j $flag"; - } - elsif ($phase_num == 2) { - $com .= "$cmd $dir1-$i-$j $dir2-$i-$j"; - } - elsif ($phase_num == 3) { - $com .= "$cmd $dir1-$i-$j "."-type f | while read X; do echo \$X \$X.lnk ; done | $TOPDIR/mongo_slinks "; - } - elsif ($phase_num == 4) { - $com .= "$cmd"; - } - elsif ($phase_num == 5) { - $com .= "$cmd"; - } - elsif ($phase_num == 6) { - $com .= "$cmd $dir1-$i-$j -type f | perl -e 'while (<>) { chomp; rename (\$_, \"\$_.r\"); };'"; - #$com .= " & $cmd $dir2-$i-$j "."-type d -exec mv {} {}.r ';'"; - } - elsif ($phase_num == 7) { - if ($processes > 1) { - $com .= "$cmd $dir1-$i-$j & $cmd $dir2-$i-$j"; - } - else { - $com .= "$cmd $dir1-$i-$j ; $cmd $dir2-$i-$j"; - } - } - $com .= " & "; - $j++; - } - - $com .= " wait"; - #print $com, "\n"; - - @t=`(time -p $com) 2>&1`; - - @tt = split ' ', $t[0]; - $res = $tt[1]; - unless ( $res =~ /\s*\d+/) { - print @t , "\n"; - print LOG @t, "\n"; - } else { - print LOG "$res sec.\n"; - print "$res sec.\n"; - } - - $total += $res; - $i++; - } - - print "total $phase_name time: $total sec.\n"; - print LOG "total $phase_name time: $total sec.\n"; - - $ares[$phase_num]=$total; # ser array of results - - if ($EXTENDED_STATISTICS) { - if( $phase_num < 3) { - $used = get_blocks_usage($TESTDIR) - $used0; - if ($phase_num == 1) { - $used1=$used; - }elsif($phase_num == 2){ - $used2=$used; - } - print "Used disk space (df) : $used KB\n"; - print LOG "Used disk space (df) : $used KB\n"; - - open (FIND_PIPE, "find $TESTDIR|") || die "cannnot open pipe from \"find\": $!\n"; - $dirs = 0; - $files = 0; - $files16 = 0; - - while(<FIND_PIPE>) { - chomp; - $st = lstat ($_); - if (S_ISDIR($st->mode)) { - $dirs ++; - } elsif (S_ISREG($st->mode)) { - $files ++; - $files16 ++ if ($st->size > 16384); - } - } - - close (FIND_PIPE); - - print "Total dirs: $dirs\n"; - print "Total files: $files\n"; - print LOG "Total dirs: $dirs\n"; - print LOG "Total files: $files\n"; - - #$f=$frag; - $f16 = $files16; - $fr16 =`find $TESTDIR -type f -size +16k | xargs $TOPDIR/map5 | $TOPDIR/summ | tail -n 1 2>&1`; - @ff16= split ' ', $f16; - @ffr16= split ' ', $fr16; - $files16 = $ff16[0]; - $frag = $ffr16[0]; - $procent = $frag / $files16; - print "Total fragments : $frag \n"; - print LOG "Total fragments : $frag \n"; - - printf "Fragments / files :%.3f\n", $procent; - printf LOG "Fragments / files :%.3f\n", $procent; - $frag_res[$phase_num]=$procent; # ser array of results - } - } - - system("sync"); - print "\n"; - print LOG "\n"; - -} - -# and what is an x process? - -#------------------------------------------------------------------ -# MONGO_X_PROCESS ( x is number of processes to run ) -#------------------------------------------------------------------ -sub mongo_x_process { - - my ($processes) = @_ ; - $p = $processes; - - make_fsys; # make and mount the file system - $used0 = get_blocks_usage($TESTDIR); - - open LOG, ">>$LOGFILE" or die "Can not open log file $LOGFILE\n"; - open LOG2, ">>$LOGFILE2" or die "Can not open log file $LOGFILE2\n"; - open LOG3, ">>$LOGFILE3" or die "Can not open log file $LOGFILE2\n"; - - print LOG "FILESYSTEM=$FILESYSTEM \n"; - - print "\n"; - if($p == 1) { - print "mongo_single_process, the_set_of_param.N=$par_set_n of $total_params \n"; - print LOG "mongo_single_process, the_set_of_paramN=$par_set_n of $total_params \n"; - } elsif ($p > 1) { - print "mongo_multi_process ($p processes), the_set_of_param.N=$par_set_n of $total_params \n"; - print LOG "mongo_multi_process ($p processes), the_set_of_paramN=$par_set_n of $total_params \n"; - } - - print "Results in file : $LOGFILE \n"; - print "\n"; - - $dir1 = "$TESTDIR/testdir1"; - $dir2 = "$TESTDIR/testdir2"; - $flag = 0; - - $cmd_1 = "$TOPDIR/reiser_fract_tree $bytes_to_consume $median_file_size $max_file_size $median_dir_nr_files $max_directory_nr_files $median_dir_branching $max_dir_branching $write_buffer_size"; - $cmd_2 = "cp -r"; - $cmd_3 = "find"; - $cmd_4 = "find $TESTDIR -type f | xargs $TOPDIR/mongo_read"; - $cmd_5 = "find $TESTDIR -type f > /dev/null"; # it should be enough for stat all files. -zam - $cmd_6 = "find"; #" $TESTDIR -type f -exec mv {} {}.r ';'"; - $cmd_7 = "rm -r"; - - system("sync"); - $frag = 0; - mongo_launcher ( 1, "Create", $cmd_1, $dir1, $dir2, $flag, $p); # phase 1 - mongo_launcher ( 2, "Copy ", $cmd_2, $dir1, $dir2, $flag, $p); # phase 2 - mongo_launcher ( 3, "Slinks", $cmd_3, $dir1, $dir2, $flag, $p); # phase 3 - mongo_launcher ( 4, "Read ", $cmd_4, $dir1, $dir2, $flag, $p); # phase 4 - mongo_launcher ( 5, "Stats ", $cmd_5, $dir1, $dir2, $flag, $p); # phase 5 - mongo_launcher ( 6, "Rename", $cmd_6, $dir1, $dir2, $flag, $p); # phase 6 - mongo_launcher ( 7, "Delete", $cmd_7, $dir1, $dir2, $flag, $p); # phase 7 - - print LOG2 "\n"; - if ($processes > 1) { - print LOG2 "MONGO_MULTI_PROCESS ($processes processes) BENCHMARK RESULTS (time in sec.)\n"; - }else { - print LOG2 "MONGO_SINGLE_PROCESS BENCHMARK RESULTS (time in sec.)\n"; - } - print LOG2 " FILESYSTEM=$FILESYSTEM\n"; - print LOG2 " parameters: files=$files, base_size=$median_file_size bytes, dirs=$dirs\n"; - print LOG2 "--------------------------------------------------------------\n"; - print LOG2 "Create\tCopy\tSlink\tRead\tStats\tRename\tDelete\n"; - print LOG2 " time \ttime\ttime\ttime\ttime \t time \t time\n"; - print LOG2 "--------------------------------------------------------------\n"; - print LOG2 "$ares[1]\t$ares[2]\t$ares[3]\t$ares[4]\t$ares[5]\t$ares[6]\t$ares[7]\n"; - print LOG2 "--------------------------------------------------------------\n"; - print LOG2 "The size of files tree : \n"; - print LOG2 " after create = $used1 kb\n"; - print LOG2 " after copy = $used2 kb\n"; - print LOG2 "\n"; - - - print LOG3 "\n"; - if ($processes > 1) { - print LOG3 "MONGO_MULTI_PROCESS ($processes) \n"; - }else { - print LOG3 "MONGO_SINGLE_PROCESS \n"; - } - print LOG3 "parameters: \n"; - print LOG3 "files=$files \n"; - print LOG3 "base_size=$median_file_size bytes \n"; - print LOG3 "dirs=$dirs \n"; - print LOG3 "\n"; - - print LOG3 "FSYS=$FILESYSTEM \n"; - print LOG3 "(time in sec.) \n"; - print LOG3 "Create : $ares[1]\n"; - print LOG3 "Fragm. : $frag_res[1]\n"; - print LOG3 "df : $used1\n\n"; - print LOG3 "Copy : $ares[2] \n"; - print LOG3 "Fragm. : $frag_res[2]\n"; - print LOG3 "df : $used2\n\n"; - print LOG3 "Slinks : $ares[3]\n"; - print LOG3 "Read : $ares[4]\n"; - print LOG3 "Stats : $ares[5]\n"; - print LOG3 "Rename : $ares[6] \n"; - print LOG3 "Delete : $ares[7]\n"; - - print LOG3 "\n"; - - - if($processes > 1) { - print LOG "******* The end of mongo_multi_process *******"; - }else { - print LOG "******* The end of mongo_single_process *******"; - } -} - -#--------------------------------------------------- -# Set parameters -#--------------------------------------------------- -sub set_params { - my ($n) = @_ ; - - $bytes_to_consume = $numb_of_bytes[$n]; - $median_file_size = $size_of_files[$n]; - - #$max_file_size = 1000000; - - #$median_dir_nr_files = 100; - #$max_directory_nr_files = 10000; - - #$median_dir_branching = 0; - #$max_dir_branching = 1; - -} - -#---------------------------------------------------------- -# TEST START -#---------------------------------------------------------- - - $par_set_n = 0; - foreach $fsize (@size_of_files) { - set_params ($par_set_n); - mongo_x_process( $nproc ); # run n processes - $par_set_n++; - } - system("umount $TESTDIR"); - exit; - - diff --git a/testcases/kernel/fs/mongo/mongo_compare.c b/testcases/kernel/fs/mongo/mongo_compare.c deleted file mode 100644 index 6dba95347..000000000 --- a/testcases/kernel/fs/mongo/mongo_compare.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README - */ - -#include <stdio.h> -#include <ctype.h> -#include <string.h> - -char time_str1[50]; -char time_str2[50]; -char name_str1[50]; -char tmp_str[20][100]; - -char out1[256]; -char out2[256]; - -FILE *f1; -FILE *f2; -FILE *f3; -FILE *f4; - -void write_html_head(FILE * fp); -void write_html_end(FILE * fp); - -char head_str[] = "\n \ -<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">\n \ -<html>\n \ -<head>\n \ - <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n \ - <meta name=\"GENERATOR\" content=\"Mozilla/4.5 [en] (X11; I; Linux 2.2.7 i586) [Netscape]\">\n \ -</head>\n \ -<body>\n \ -"; -/* -<tt></tt> \n \ -<table BORDER NOSAVE >\n \ -<tr BGCOLOR=\"#CCFFFF\" NOSAVE>\n \ -<td NOSAVE> \n \ -"; -*/ - -char end_str[] = "\n \ -</table> \n \ -<tt></tt> \n \ -</body> \n \ -</html> \n \ -"; - -main(int argc, char **argv) -{ - float n1, n2, ratio; - char *p, *p1, *p2; - char line0[100]; - char line1[100]; - char line2[100]; - char line3[100]; - char out_line[100]; - char html_line[500]; - int i, k; - - if (argc < 3) { - printf("\nUsage: mongo_compare file1 file2 res_file\n\n"); - printf - ("\t<file1> should contain reiserfs or ext2 results of mogo benchmark\n"); - printf - ("\t<file2> should contain reiserfs or ext2 results of mogo benchmark\n"); - printf("\tMongo results will be compared\n"); - printf - ("\t<res_file.txt> will be contain results in the text form\n"); - printf - ("\t<res_file.html> will be contain results in the html form\n"); - exit(0); - } - - strcpy(out1, argv[3]); - strcat(out1, ".txt"); - - strcpy(out2, argv[3]); - strcat(out2, ".html"); - - if ((f1 = fopen(argv[1], "r")) == NULL) { - fprintf(stderr, "%s: can't open %s\n", argv[0], argv[1]); - return 1; - } - - if ((f2 = fopen(argv[2], "r")) == NULL) { - fprintf(stderr, "%s: can't open %s\n", argv[0], argv[2]); - return 1; - } - - if ((f3 = fopen(out1, "wr")) == NULL) { - fprintf(stderr, "%s: can't open %s\n", argv[0], out1); - return 1; - } - - if ((f4 = fopen(out2, "wr")) == NULL) { - fprintf(stderr, "%s: can't open %s\n", argv[0], out2); - return 1; - } - - write_html_head(f4); - i = 0; - while (fgets(line1, 100, f1)) { - fgets(line2, 100, f2); - - if (p = strstr(line1, "\n")) - *(p + 1) = 0; - if (p = strstr(line2, "\n")) - *(p + 1) = 0; - - strcpy(line3, line1); - line3[strlen(line3) - 1] = 0; - - while (strlen(line3) < 40) { - strcat(line3, " "); - } - - if (strstr(line3, "MONGO_")) { - fprintf(f4, "</table>\n<table BORDER NOSAVE >\n"); - fprintf(f4, "<tr BGCOLOR=\"#CCFFFF\" NOSAVE>"); - fprintf(f4, "<td NOSAVE>\n"); - i = 0; - } - if (i < 20) - strcpy(tmp_str[i], line2); - - if (strstr(line3, "FSYS=")) { - fprintf(f4, "</td><td>\n"); - for (k = 0; k < i; k++) { - fprintf(f4, "<tt>%s</tt><br>\n", tmp_str[k]); - } - fprintf(f4, - "</td>\n <tr BGCOLOR=\"#CCFFFF\" NOSAVE><td COLSPAN=\"2\"><tt><B> %s %s </B></tt>\n", - line3, line2); - i = 20; - } else if (NULL == strstr(line3, " :")) { - - if (strstr(line3, "(time")) - fprintf(f4, - "<br><tt><center>%s</center></tt>\n", - line3); - else { - k = 0; - p = line3; - while (*p++ != 0) { - if (*p != ' ' && *p != '\n') - k++; - } - if (k > 0) { - fprintf(f4, "<tt>%s</tt><br>\n", line3); - if (i < 20) - i++; - } - } - } - - else if (strstr(line3, "Create")) - fprintf(f4, "</td>\n"); - - line2[strlen(line2) - 1] = 0; - while (strlen(line2) < 40) { - strcat(line2, " "); - } - - strcat(line3, line2); - - strcpy(out_line, line3); - strcat(out_line, "\n"); - name_str1[0] = 0; - - if (p1 = strstr(line1, " :")) { - strcpy(time_str1, p1 + 2); - strncpy(name_str1, line1, p1 - line1); - - if (p2 = strstr(line2, " :")) { - strcpy(time_str2, p2 + 2); - - time_str1[strlen(time_str1) - 1] = 0; - time_str2[strlen(time_str2) - 1] = 0; - - sscanf(time_str1, "%f", &n1); - sscanf(time_str2, "%f", &n2); - - ratio = n1 / n2; - sprintf(out_line, "%s : %6.2f / %6.2f = %.2f\n", - name_str1, n1, n2, ratio); - - fprintf(f4, - "<tr><td><tt> %s   </tt></td> <td><div align=right><tt> %6.2f / %6.2f = %.2f   </tt></div></td></tr>\n", - name_str1, n1, n2, ratio); - - } - } - - fprintf(f3, "%s", out_line); - line1[0] = 0; - line2[0] = 0; - line3[0] = 0; - out_line[0] = 0; - } - - write_html_end(f4); - - fclose(f1); - fclose(f2); - - fclose(f3); - fclose(f4); - - fflush(f3); - fflush(f4); -} - -/*******************************************/ -void write_html_head(FILE * fp) -{ - fprintf(fp, "%s", head_str); -} - -/*******************************************/ -void write_html_end(FILE * fp) -{ - fprintf(fp, "%s", end_str); -} diff --git a/testcases/kernel/fs/mongo/mongo_read.c b/testcases/kernel/fs/mongo/mongo_read.c deleted file mode 100644 index 927b92a13..000000000 --- a/testcases/kernel/fs/mongo/mongo_read.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README - */ - -/* - * MONGO READ - simple possible program to read a number of given files - * suitable for benchmarking FS read performance - */ - -#include <stdio.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> - -int main(int argc, char **argv) -{ - int fd, rd, i; - char *buf; - int bufsize = 4096; - - if (argc < 2) { - printf("\nUsage: %s filename [,filename2 [,...] ] ]\n\n", - argv[0]); - return 0; - } - - buf = malloc(bufsize); - if (buf == 0) { - printf("Malloc failed on %d\n", bufsize); - return 0; - } - - /* Read all given files */ - for (i = 1; i < argc; i++) { - - /* open the file */ - fd = open(argv[i], O_RDONLY); - if (fd == -1) { - printf("Open failed (%s)\n", strerror(errno)); - return 0; - } - - /* read the file */ - while ((rd = read(fd, buf, bufsize)) == bufsize) ; - if (rd == -1) { - printf("Read failed (%s)\n", strerror(errno)); - return 0; - } - close(fd); - } - - free(buf); - return 0; -} diff --git a/testcases/kernel/fs/mongo/mongo_slinks.c b/testcases/kernel/fs/mongo/mongo_slinks.c deleted file mode 100644 index 6bd1e2b69..000000000 --- a/testcases/kernel/fs/mongo/mongo_slinks.c +++ /dev/null @@ -1,98 +0,0 @@ -// -// A simple symlink test -// - -#define _GNU_SOURCE - -#include <sys/stat.h> -#include <unistd.h> -#include <stdlib.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> - -// -// Creates symlink [new-path] to [old-path], checks it, -// returnes 0 - if everything looks fine and -// 1 - otherwise. -// mongo_slinks reads arguments from stdin. - -int main(int argc, char *argv[]) -{ - char *old_path; - char *new_path; - - struct stat statbuf; - - int num; - char *buffer = NULL; - char *line_buffer = NULL; - size_t line_buffer_size = 0; - int size = 1; - - if ((buffer = malloc(size + 1)) == NULL) { - perror("checklink: malloc failed"); - return 1; - } - - while (getline(&line_buffer, &line_buffer_size, stdin) != -1) { - - old_path = strtok(line_buffer, "\t "); - new_path = strtok(NULL, "\t\n "); - - if (!old_path || !new_path) /* empty lines at the end of file */ - break; - - // Create symlink - if (symlink(old_path, new_path) != 0) { - perror("checklink : symlink failed "); - return 1; - } - // stat data of symlink itself - if (lstat(new_path, &statbuf) == -1) { - perror("checklink: lstat failed"); - return 1; - } - - if (!(S_ISLNK(statbuf.st_mode))) { - printf("checklink : file %s is not a symbol link\n", - new_path); - return 1; - } - // Test readlink - // - // Increase size of buffer to readlink untile whole symlink body will be read. - // Check readlink result on every iteration. - - while (1) { - memset(buffer, 0, size + 1); - num = readlink(new_path, buffer, size); - if (num < 1 || num > size) { - perror("checklink: readlink failed"); - free(buffer); - return 1; - } - // Make sure that readlink did not break things - if (buffer[num] != 0) { - printf - ("checklink : readlink corrupts memory\n"); - free(buffer); - return 1; - } - // Whole expected symlink body is read - if (num < size) - break; - - // Only part of symlink body was read. So we make a bigger buffer - // and call `readlink' again. - size *= 2; - if ((buffer = realloc(buffer, size + 1)) == NULL) { - perror("checklink: realloc failed"); - return 1; - } - } - } - free(buffer); - free(line_buffer); - return 0; -} diff --git a/testcases/kernel/fs/mongo/reiser_fract_tree.c b/testcases/kernel/fs/mongo/reiser_fract_tree.c deleted file mode 100644 index af2fa46a7..000000000 --- a/testcases/kernel/fs/mongo/reiser_fract_tree.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> -#include <sys/types.h> -#include <unistd.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -char tdir[256]; -char path[256]; -long stats = 0; - -void print_usage() -{ - printf(" -This program creates files in a tree of random depth and branching. Files vary -in size randomly according to a distribution function which seems to model real -file systems. This distribution function has a median size of median_file_size -(Median file size is hypothesized to be proportional to the average per file -space wastage. Notice how that implies that with a more efficient file system -file size usage patterns will in the long term move to a lower median file -size), and a maximum size of max_file_size. Directories vary in size according -to the same distribution function but with separate parameters to control median -and maximum size for the number of files within them, and the number of -subdirectories within them. This program prunes some empty subdirectories in a -way that causes parents of leaf directories to branch less than -median_dir_branching. - - To avoid having one large file distort the results such that you have -to benchmark many times set max_file_size to not more than -bytes_to_consume/10. If maximum/median is a small integer, then -randomness is very poor. This is a bug, Nikita, please find some -clever way to fix it. If it is 0, then the program crashes.... - -For isolating performance consequences of design variations on -particular file or directory size ranges, try setting their median size and -max_size to both equal the max size of the file size range you want -to test. - -To avoid having one large file distort the results set max_file_size to -not more than bytes_to_consume/10. Using a distribution function for -the sizes of writes would be a natural next step in developing this program.\n\n"); - - printf - ("Usage: reiser_fract_tree bytes_to_consume median_file_size max_file_size median_dir_nr_files max_directory_nr_files median_dir_branching max_dir_branching write_buffer_size /testfs_mount_point print_stats_flag\n\n"); -} - -/* #define DEBUG */ - -char *write_buffer; /* buffer from which we write */ -int write_buffer_size = 0; /* gets reset to an argv */ -static int already_whined = 0; /* keep out of disk space errors from being - endless by tracking whether we already - printed the message */ -long bytes_to_consume = 0; /* create files until their total number of - bytes exceeds this number, but not by more - than 1/10th */ -long byte_total = 0; /* bytes created so far */ - -/* statistics on sizes of files we attempted to create */ -int fsz_0_100 = 0; -int fsz_100_1k = 0; -int fsz_1k_10k = 0; -int fsz_10k_100k = 0; -int fsz_100k_1m = 0; -int fsz_1m_10m = 0; -int fsz_10m_larger = 0; - -void chngdir(char *name) -{ - int i; - - if (name[0] == '.' && name[1] == '.') { - for (i = strlen(path); i > 0; i--) { - if (path[i] == '/') { - path[i] = 0; - break; - } - } - } else { - strcat(path, "/"); - strcat(path, name); - } -} - -/* this is the core statistical distribution function, and it is used for file - sizes, directory sizes, etc. */ -int determine_size(double median_size, - double max_size /* The maximal value of size */ ) -{ - /* when x is half of its random range (max_size/median_size), result is - median_size */ - int nr_random, granularity_reducer; - double size, double_nr_random; - - /* it is a feature for us that this repeats identically every time it is run, - as otherwise meaningless variances would affect our results and require us - to use a higher number of benchmarks to achieve low noise results. */ - nr_random = rand(); - median_size++; /* avoids divide by zero errors */ - - /* this code does poorly when max_size is not a lot more than median size, - and that needs fixing */ - - /* THE NEXT 2 LINES ARE THE HEART OF THE PROGRAM */ - - /* keep x below the value that when multiplied by median size on the next - line will equal max_size */ - /* the granularity_reducer is to handle the case where max_size is near - median_size, since '%' can only take ints, we need this complicated what - of handling that for small values of max_size/median_size by making - large ints out of small ints temporarily. */ - if (max_size / median_size < 1024) - granularity_reducer = 1024 * 1024; - else - granularity_reducer = 1; - nr_random = - nr_random % - ((int) - (granularity_reducer * - (((double)max_size) / ((double)median_size)))); - double_nr_random = ((double)nr_random) / (granularity_reducer); - size = - median_size * (1 / - (1 - - (double_nr_random) / (((double)max_size) / - ((double)median_size))) - 1); - return ((int)size); -} - -/* generate a unique filename */ -void get_name_by_number(long this_files_number, char *str) -{ - sprintf(str, "%lu", this_files_number); -} - -/* make a file of a specified size */ -void make_file(int size) -{ - char string[128] = { 0 }; - char *str = string; - char fname[256]; - int fd = 0; - int error; - static long this_files_number = 1; - - /* collect statistics about the size of files created, or more precisely, the - size of files that we will attempt to create. */ - if (size <= 100) - fsz_0_100++; - else if (size <= 1000) - fsz_100_1k++; - else if (size <= 10 * 1000) - fsz_1k_10k++; - else if (size <= 100 * 1000) - fsz_10k_100k++; - else if (size <= 1000 * 1000) - fsz_100k_1m++; - else if (size <= 10 * 1000 * 1000) - fsz_1m_10m++; - else - fsz_10m_larger++; - - /* construct a name for the file */ - get_name_by_number(this_files_number++, str); - strcpy(fname, path); - strcat(fname, "/"); - strcat(fname, str); - - /* open the file, and deal with the various errors that can occur */ - - if ((fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0777)) == -1) { - if (errno == ENOSPC) { - if (!already_whined) { - printf - ("reiser-2021A: out of disk (or inodes) space, will keep trying\n"); - already_whined = 1; /* we continue other file creation in out of - space conditions */ - } - return; - } - /* it is sometimes useful to be able to run this program more than once - inside the same directory, and that means skipping over filenames that - already exist. Thus we ignore EEXIST, and pay attention to all - else. */ - if (errno == EEXIST) { /* just skip existing file */ - return; - } - perror("open"); - exit(errno); - } - /* write to the file until it is the right size, handling the various error - conditions appropriately */ - - while (size > 0) { - size -= (error = - write(fd, write_buffer, - (size < - write_buffer_size - - 1) ? size : (write_buffer_size - 1))); - if (error == -1) { - if (errno == ENOSPC) { - if (!already_whined) { - printf - ("reiser-2022: out of disk space, will keep trying\n"); - already_whined = 1; - } - close(fd); - return; - } - perror("write() failed"); - exit(errno); - } - } - - /* close the file */ - if (close(fd)) { - perror("close() failed"); - exit(errno); - } -} - -/* print the statistics on how many files were created of what size */ - -void print_stats() -{ - if (!stats) - return; - - printf("\n"); - printf("File stats: Units are decimal (1k = 1000)\n"); - printf("files 0-100 : %i\n", fsz_0_100); - printf("files 100-1K : %i\n", fsz_100_1k); - printf("files 1K-10K : %i\n", fsz_1k_10k); - printf("files 10K-100K : %i\n", fsz_10k_100k); - printf("files 100K-1M : %i\n", fsz_100k_1m); - printf("files 1M-10M : %i\n", fsz_1m_10m); - printf("files 10M-larger : %i\n", fsz_10m_larger); - printf("total bytes written : %lu\n", byte_total); - -} - -/* predict the number of files that will be created before max_bytes total - length of files is reached */ -long determine_nr_of_files(int median_file_size, double max_file_size, - long bytes_to_consume) -{ - long nr_of_files = 0, byte_total = 0; - - /* the next line is not necessary as 1 is the default, it is just cautious - coding */ - srand(1); - while (byte_total < bytes_to_consume) { - byte_total += determine_size(median_file_size, max_file_size); - nr_of_files++; - } - /* reset the random number generator so that when we determine_size() of the - files later they will be created with the same "random" sequence used in - this calculation */ - srand(1); -#ifdef DEBUG - printf("number of files is %d\n", (int)nr_of_files); -#endif /* DEBUG */ - fflush(NULL); - return nr_of_files; -} - -/* fill the current working directory with nr_files_this_directory number of - files*/ - -void fill_this_directory(long nr_files_this_directory, long median_file_size, - long maximum_size) -{ - long size; - -#ifdef DEBUG - printf("filling with %lu files, ", nr_files_this_directory); -#endif - while (nr_files_this_directory--) { - size = determine_size(median_file_size, maximum_size); - byte_total += size; - make_file(size); - } -} - -/* this will unfortunately handle out of disk space by forever trying */ -/* What we should do in out of space situaltion ? I think we must skip this - directory and continue files/dirs creation process. Error value (!= 0) - indicates that we can't go to this directory. -zam */ -int make_directory(char *dirname) -{ - static long this_directory_number = 0; - - strcpy(tdir, path); - strcat(tdir, "/"); - strcat(tdir, dirname); - - if (mkdir(tdir, 0755) == -1) { - if (errno == ENOSPC) { - if (!already_whined) { - printf("reiser-2021: out of disk space, "); - already_whined = 1; - } - return errno; - } - /* it is sometimes useful to be able to run this program more than once - inside the same directory, and that means skipping over filenames that - already exist. Thus we ignore EEXIST, and pay attention to all else. */ - if (errno != EEXIST) { - perror("mkdir"); - exit(errno); - } - } - sprintf(dirname, "d%lu", this_directory_number++); - strcpy(tdir, path); - strcat(tdir, "/"); - strcat(tdir, dirname); - - return 0; -} - -/* assumes we are already chdir'd into a directory that the subtree is rooted - at. Fills the directory with files and subdirectories, cd's into those - subdirectories, and recurses upon itself */ - -void do_subtree( - /* the start and end of the portion of the directory sizes - array which corresponds to the sizes of the directories - composing this subtree */ - /* sizes_end minus sizes_start is equal to the number of - directories in this subtree */ - long *sizes_start, long *sizes_end, - long median_file_size, long maximum_file_size, - long median_dir_branching, long max_dir_branching) -{ - long *p; - long *sub_start; - long *sub_end; - int index_subdirectory_to_add_directory_to; - long *dirs_in_subtrees; - char *subtree_name; - long *sizes_index = sizes_start; - char subtree_name_array[128]; - long this_directory_branching; - static long this_directorys_number; - - subtree_name = subtree_name_array; - /* fill this directory with its number of files */ - fill_this_directory(*sizes_index, median_file_size, maximum_file_size); - sizes_index++; - /* ok, now randomly assign directories (and their number of files) among the - subdirectories that will be created if at least one directory is assigned - to it */ - - /* this will cause the random number sequence to not match the one used in - determine_nr_files() I need to accumulate my values in an array - beforehand. I'll code that later. */ - /* worry about whether 0 or 1 is a problem value */ - this_directory_branching = - determine_size(median_dir_branching, max_dir_branching) + 1; - - /* create an array holding the number of directories assigned to each - potential subdirectory */ - dirs_in_subtrees = calloc(this_directory_branching, sizeof(long)); - while (sizes_index <= sizes_end) { - index_subdirectory_to_add_directory_to = - (rand() % this_directory_branching); - (* - (dirs_in_subtrees + index_subdirectory_to_add_directory_to))++; - sizes_index++; - } - /* the +1 is for the fill_directory() we did above */ - sizes_index = sizes_start + 1; - - /* go through each potential subdirectory, and if at least one directory has - been assigned to it, create it and recurse */ - for (p = dirs_in_subtrees; - p < (dirs_in_subtrees + this_directory_branching); p++) { - if (*p) { - int nocd; - sprintf(subtree_name, "d%lu", this_directorys_number++); - nocd = make_directory(subtree_name); - /* if make_dir.. may fails (in out of space situation), we continue - creation process in same dir */ - if (!nocd) - chngdir(subtree_name); - sub_start = sizes_index; - /* the minus one is because *p is the number of elements and arrays start at 0 */ - sub_end = (sizes_index + (*p - 1)); - -#ifdef DEBUG - /* comment this back in if the array logic has you going cross-eyed */ - /* printf ("sizes_start is %p, sizes_index is %p, sizes_index+p is %p, sizes_end is %p\n", sizes_start, sub_start, sub_end, sizes_end); */ -#endif - do_subtree(sub_start, sub_end, median_file_size, - maximum_file_size, median_dir_branching, - max_dir_branching); - if (!nocd) - chngdir(".."); - } - sizes_index += *p; - } -} - -/* We have already determined that nr_files can fit in bytes_to_consume space. - Fill the sizes array with the number of files to be in each directory, and - then call do_subtree to fill the tree with files and directories. */ - -void make_fractal_tree(long median_file_size, long maximum_file_size, - long median_dir_nr_files, long max_dir_nr_files, - long median_dir_branching, long max_dir_branching, - long nr_files) -{ - long *sizes_start; - long *sizes_end; - long *sizes_index; - long remaining_files = nr_files; - - /* collect together array of directory sizes for whole filesystem. This - cannot easily be done recursively without distorting the directory sizes - and making deeper directories smaller. Send me the code if you - disagree.:-) */ - /* we almost certainly don't need this much space, but so what.... */ - sizes_index = sizes_start = malloc(nr_files * sizeof(long)); - for (; remaining_files > 0;) { - *sizes_index = - determine_size(median_dir_nr_files, max_dir_nr_files); - // we alloc space for nr_files, so we should avoid - // number of files in directory = 0 -grev. - if (*sizes_index == 0) - *sizes_index = 1; - *sizes_index = - (*sizes_index < - remaining_files) ? *sizes_index : remaining_files; - -#ifdef DEBUG - printf("*sizes_index == %lu, ", *sizes_index); -#endif - remaining_files -= *sizes_index; - sizes_index++; - } - /* don't decrement below sizes_start if nr_files is 0 */ - sizes_end = (sizes_index-- > sizes_start) ? sizes_index : sizes_start; - - sizes_index = sizes_start; - srand(1); - do_subtree(sizes_start, sizes_end, median_file_size, maximum_file_size, - median_dir_branching, max_dir_branching); - -} - -int main(int argc, char *argv[]) -{ - /* initialized from argv[] */ - long median_file_size, - median_dir_branching, - median_dir_nr_files, - max_dir_nr_files, max_dir_branching, max_file_size; - long nr_of_files = 0; /* files to be created */ - - if (argc != 11) { - print_usage(); - exit(1); - } - - write_buffer_size = atoi(argv[8]); - write_buffer = malloc(write_buffer_size); - memset(write_buffer, 'a', write_buffer_size); - - /* the number of bytes that we desire this tree to consume. It will actually - consume more, because the last file will overshoot by a random amount, and - because the directories and metadata will consume space. */ - bytes_to_consume = atol(argv[1]); - max_file_size = atol(argv[3]); - median_file_size = atol(argv[2]); - /* Figure out how many random files will fit into bytes_to_consume bytes. We - depend on resetting rand() to get the same result later. */ - nr_of_files = - determine_nr_of_files(median_file_size, max_file_size, - bytes_to_consume); - - strcpy(path, argv[9]); - mkdir(path, 0755); - stats = atol(argv[10]); - median_dir_branching = atol(argv[6]); - max_dir_branching = atol(argv[7]); - median_dir_nr_files = atol(argv[4]); - max_dir_nr_files = atol(argv[5]); - make_fractal_tree(median_file_size, max_file_size, median_dir_nr_files, - max_dir_nr_files, median_dir_branching, - max_dir_branching, nr_of_files); - print_stats(); - if (stats) - printf("\nreiser_fract_tree finished\n"); - - return 0; -} diff --git a/testcases/kernel/fs/mongo/run_mongo b/testcases/kernel/fs/mongo/run_mongo deleted file mode 100755 index e22e2b9a8..000000000 --- a/testcases/kernel/fs/mongo/run_mongo +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README -# -if [ $# -lt 2 ] -then - echo - echo "Usage : run_mogo <device> <processes>" - echo - echo "Example :" - echo "# run_mogo /dev/hdx1 2" - echo - exit -fi - -DEVICE=$1 -NPROC=$2 - -y="Yes" -echo "WARNING : All data will be erased on device=$DEVICE " -echo "Run ? (Yes | no)" -read x - -if [ -z $x ] -then - exit -fi - -if ! [ $x = $y ] -then - exit -fi - -./mongo.pl reiserfs $DEVICE /testfs reiserfs $NPROC -./mongo.pl ext2 $DEVICE /testfs ext2 $NPROC -./mongo_compare ./results/ext2.tbl ./results/reiserfs.tbl ./results/html/ext2_vs_reiserfs diff --git a/testcases/kernel/fs/mongo/summ.c b/testcases/kernel/fs/mongo/summ.c deleted file mode 100644 index c5712a4e3..000000000 --- a/testcases/kernel/fs/mongo/summ.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README - */ - -#include <stdio.h> -#include <stdlib.h> -char str[100]; - -int main(int argc, char **argv) -{ - char c, *p; - int sum = 0, n = 0; - - p = str; - while ((c = getchar()) != EOF) { - if (c != '\n') { - *p++ = c; - } else { - *p = '\0'; - n = atol(str); - sum += n; - printf("%i\n", sum); - p = str; - *p = '\0'; - } - } -} diff --git a/testcases/kernel/fs/mongo/test.sh b/testcases/kernel/fs/mongo/test.sh deleted file mode 100755 index 5ec4e3139..000000000 --- a/testcases/kernel/fs/mongo/test.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/sh -#To exectute this you need mongo filesystem utility. -#Run this inside the mongo directory. -#mongo utility can be found in www.namesys.com/benchmarks/mongo-xxx.tgz -#Description-this script tests the mongo utility which actulally give the time ie cpu time -#Real time etc on reiserfile system and jfs filesystem. -#created by prakash.banu@wipro.com -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# - -LOG_DIR=$PWD -TEST_DIR=testdir - - - #should be root to execute this script . - if [ $(id -ru) -ne 0 ]; then - echo "This script must be run as root" - exit - fi - #set the PATH variable if its not done . -export PATH=$PATH:/sbin -lsmod |grep reiserfs - - if [ $? -ne 0 ]; then - echo "inserting reiserfs and its dependencies" - fi -modprobe reiserfs - if [ $? -ne 0 ]; then - echo "check wheather reiserfs is been compiled in the kernel" - fi - -lsmod |grep loop - if [ $? -ne 0 ]; then - echo "inserting loopback device module" - fi -modprobe loop - if [ $? -ne 0 ]; then - echo "check wheather loopback device option is been compiled in the kernel" - fi - - #run the mongo test on reiserfs file system type -reiserfs() -{ -cat > fs.sh <<EOF -echo "performing mongo on reiserfs" -dd if=/dev/zero of=reiserfs bs=8k count=10240 > /dev/null 2>&1 -losetup /dev/loop0 reiserfs -mkdir -p $TEST_DIR -./mongo.pl LOG=/tmp/logfile1 file_size=10000 bytes=100000 fstype=reiserfs dev=/dev/loop0 dir=$TEST_DIR RUN log=$LOG_DIR/reiserlog > /dev/null 2>&1 - -echo "RESULTS LOGGED IN $LOG_DIR/reiserlog" -export PATH=$PATH:/sbin -losetup -d /dev/loop0 - -EOF -} - - -#To run on jfs file system type -JFS() -{ -cat >> fs.sh <<EOF -echo "performing mongo on jfs file system" -mkdir -p $TEST_DIR -dd if=/dev/zero of=jfs bs=8k count=10240 > /dev/null 2>&1 -losetup /dev/loop0 jfs -./mongo.pl LOG=/tmp/logfile1 file_size=10000 bytes=100000 fstype=jfs dev=/dev/loop0 dir=$TEST_DIR RUN log=$LOG_DIR/jfslog - -echo "RESULTS LOGGED IN $LOG_DIR/jfslog" -export PATH=$PATH:/sbin -losetup -d /dev/loop0 -echo "rm -rf ./fs.sh" >> ./fs.sh 2>&1 -EOF -} - - -echo -ne "TEST ON REISERFS?[y/N]:" -read ker - -case $ker in -y|Y) reiserfs -esac - -echo -ne "TEST ON JFS[y/N]: " -read ker - -case $ker in -y|Y) JFS -esac - -echo "THIS MAY TAKE SOME MINUTES" -sh fs.sh - -#performing cleanup -#losetup -d /dev/loop0 -rm -rf $TEST_DIR diff --git a/testcases/kernel/fs/quota_remount/quota_remount_test01.sh b/testcases/kernel/fs/quota_remount/quota_remount_test01.sh index 25d9f8fcc..7e20b3608 100755 --- a/testcases/kernel/fs/quota_remount/quota_remount_test01.sh +++ b/testcases/kernel/fs/quota_remount/quota_remount_test01.sh @@ -67,7 +67,8 @@ do_test() newblocks=$(get_blocks) if [ $blocks -eq $newblocks ]; then - tst_brk TFAIL "usage did not change after remount" + tst_res TFAIL "usage did not change after remount" + return fi tst_res TPASS "quota on remount passed" diff --git a/testcases/kernel/fs/scsi/ltpfs/Ltpfs.h b/testcases/kernel/fs/scsi/ltpfs/Ltpfs.h deleted file mode 100644 index 24a85c95c..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/Ltpfs.h +++ /dev/null @@ -1,71 +0,0 @@ - -#define FS_LTP_TEST_COMPONENT 0x00020999 -#define FS_LTP_TEST_CLASS "ltp_test" -#define FS_LTP_TEST_HID "FS0999" -#define FS_LTP_TEST_DRIVER_NAME "FS LTP Test Driver" -#define FS_LTP_TEST_DEVICE_NAME "LTP Test" -#define FS_LTP_TEST_FILE_STATE "state" -#define FS_LTP_TEST_NOTIFY_STATUS 0x80 -#define FS_LTP_TEST_STATUS_OFFLINE 0x00 -#define FS_LTP_TEST_STATUS_ONLINE 0x01 -#define FS_LTP_TEST_STATUS_UNKNOWN 0xFF -#define _COMPONENT FS_LTP_TEST_COMPONENT -#define FS_TLP_TEST_MODULE_NAME ("fs_ltp_test") -#define FS_NS_SYSTEM_BUS "_SB_" -#define FS_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS" -#define FS_BATTERY_FORMAT_BST "NNNN" - - -#define FS_TYPE_ANY 0x00 -#define FS_TYPE_INTEGER 0x01 /* Byte/Word/Dword/Zero/One/Ones */ -#define FS_TYPE_STRING 0x02 -#define FS_TYPE_BUFFER 0x03 -#define FS_TYPE_PACKAGE 0x04 /* byte_const, multiple data_term/Constant/super_name */ -#define FS_TYPE_FIELD_UNIT 0x05 -#define FS_TYPE_DEVICE 0x06 /* Name, multiple Node */ -#define FS_TYPE_EVENT 0x07 -#define FS_TYPE_METHOD 0x08 /* Name, byte_const, multiple Code */ -#define FS_TYPE_MUTEX 0x09 -#define FS_TYPE_REGION 0x0A -#define FS_TYPE_POWER 0x0B /* Name,byte_const,word_const,multi Node */ -#define FS_TYPE_PROCESSOR 0x0C /* Name,byte_const,Dword_const,byte_const,multi nm_o */ -#define FS_TYPE_THERMAL 0x0D /* Name, multiple Node */ -#define FS_TYPE_BUFFER_FIELD 0x0E -#define FS_TYPE_DDB_HANDLE 0x0F -#define FS_TYPE_DEBUG_OBJECT 0x10 - -#define FS_TYPE_EXTERNAL_MAX 0x10 -#define LTPMAJOR 256 - -/* Use 'k' as magic number */ -#define LTPFS_IOC_MAGIC 'k' -#define TOMINOR(x) ((x & 3) | ((x & 4) << 5)) - - -#define DEV_PATH "/dev" -#define LTP_FS_DIR_NAME "" -#define LTP_FS_DEV_NAME "LTPFS" -#define LTP_FS_DEV_NODE_PATH DEV_PATH "/" -#define LTP_FS_DEVICE_NAME DEV_PATH "/" LTP_FS_DEV_NAME -#define MINOR_SHIFT_BITS 3 -#define MAX_PARTITIONS 8 /* partition 0 + 7 more possible due to 3 bit partition number field */ -#define MAX_NUM_DISKS 3 /* number of real devices */ - -#define MPDEV_FLAG_CLEAR 0 -#define MPDEV_FLAG_SET 1 - -typedef struct _ltpdev_cmd { - u_int32_t cmd; // input - 0==recover, 1==fail - u_int32_t status; // ouput - 0==success -} ltpdev_cmd_t; - -typedef enum ltpdev_ioctl_cmds_s { - /* version commands */ - LTP_AIO_IOCTL_NUMBER = 0x5500, - LTP_BIO_IOCTL_NUMBER = 0x5501 -} ltpdev_ioctl_cmds_t; - -// define the ioctl cmds -#define LTPAIODEV_CMD _IOR( LTPMAJOR, LTP_AIO_IOCTL_NUMBER, ltpdev_cmd_t **) -#define LTPBIODEV_CMD _IOR( LTPMAJOR, LTP_BIO_IOCTL_NUMBER, ltpdev_cmd_t **) - diff --git a/testcases/kernel/fs/scsi/ltpfs/LtpfsCmds.c b/testcases/kernel/fs/scsi/ltpfs/LtpfsCmds.c deleted file mode 100644 index 0b561702e..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/LtpfsCmds.c +++ /dev/null @@ -1,315 +0,0 @@ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/fs.h> -#include <linux/ioctl.h> -#include <linux/pm.h> -#include <linux/genhd.h> -#include <linux/bio.h> -#include <linux/mm.h> -#include <linux/swap.h> -#include <linux/bio.h> -#include <linux/blk.h> -#include <linux/slab.h> -#include <linux/mempool.h> -#include <linux/workqueue.h> -#include <linux/namei.h> -#include <linux/mount.h> -#include <linux/quotaops.h> -#include <linux/pagemap.h> -#include <linux/dnotify.h> -#include <linux/smp_lock.h> -#include <linux/personality.h> -#include <linux/security.h> -#include <linux/buffer_head.h> -#include <asm/namei.h> -#include <asm/uaccess.h> - -#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) -#define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) -#define TEST_MEM_SIZE 4096 -#define FALSE 0 -#include "Ltpfs.h" - -static int ltpdev_open(struct inode *inode, struct file *pfile); -static int ltpdev_release(struct inode *inode, struct file *pfile); -static int ltpdev_ioctl(struct inode *pinode, struct file *pfile, - unsigned int cmd, unsigned long arg); -static int do_buffer_c_tests(void); - -static struct block_device_operations blkops = { -open: ltpdev_open, -release:ltpdev_release, -ioctl: ltpdev_ioctl, -}; - -int ltp_fs_major = LTPMAJOR; -int test_iteration = 0; - -static char genhd_flags = 0; -static struct gendisk *gd_ptr; -static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; - -MODULE_AUTHOR("Martin Ridgeway <mridge@us.ibm.com>"); -MODULE_DESCRIPTION(FS_LTP_TEST_DRIVER_NAME); -MODULE_LICENSE("GPL"); - -/* - * Device operations for the virtual FS devices - */ - -static struct pm_dev *ltp_pm_dev = NULL; -struct block_device *ltplookup_bdev(const char *path); -int path_lookup(const char *name, unsigned int flags, struct nameidata *nd); -//static int __emul_lookup_dentry(const char *name, struct nameidata *nd); -void path_release(struct nameidata *nd); - -static int ltpdev_open(struct inode *pinode, struct file *pfile) -{ - printk(KERN_ALERT "ltpdev_open \n"); - return 0; -} - -static int ltpdev_release(struct inode *pinode, struct file *pfile) -{ - - printk(KERN_ALERT "ltpdev_release \n"); - return 0; -} - -static int ltpdev_ioctl(struct inode *pinode, struct file *pfile, - unsigned int cmd, unsigned long arg) -{ - - struct bio *my_bio = NULL; - struct bio *my_bio_copy = NULL; - request_queue_t *q = NULL; - struct block_device *bdev = NULL; - unsigned long uaddr; - - unsigned int bytes_done = 100; - - int error = 0; - int rc = 0; - - /*****************************************************************************/ - - printk(KERN_ALERT "ltpdev_ioctl fs tests\n"); - - switch (cmd) { - - case LTPAIODEV_CMD: - printk(KERN_ALERT "Running AIO FS tests \n"); - printk(KERN_ALERT "AIO FS tests complete\n"); - break; - - case LTPBIODEV_CMD: - - printk(KERN_ALERT "Running BIO FS tests \n"); - - my_bio = bio_alloc(GFP_KERNEL, 0); - if (!my_bio) { - printk(KERN_ALERT - "Error getting kernel slab memory !!\n"); - } else { - printk(KERN_ALERT "kernel slab memory alloc OK\n"); - } - - bio_endio(my_bio, bytes_done, error); - - printk(KERN_ALERT "Return from bio_endio = %d \n", error); - - my_bio_copy = bio_clone(my_bio, GFP_ATOMIC); - - if (!my_bio_copy) { - printk(KERN_ALERT - "Error getting kernel bio clone !!\n"); - } else { - printk(KERN_ALERT "kernel bio clone OK\n"); - } - - my_bio_copy = bio_clone(my_bio, GFP_NOIO); - - if (!my_bio_copy) { - printk(KERN_ALERT - "Error getting kernel bio clone !!\n"); - } else { - printk(KERN_ALERT "kernel bio clone OK\n"); - } - -// q = bdev_get_queue(my_bio->bi_bdev); - -// rc = bio_phys_segments(q, my_bio); - -// rc = bio_hw_segments(q, my_bio); - - bdev = lookup_bdev(LTP_FS_DEVICE_NAME); - - printk(KERN_ALERT "return from bdev size %d\n", - bdev->bd_block_size); - - printk(KERN_ALERT "Return from phys_segments = %d \n", rc); - -// Don't use this API, causes system to hang and corrupts FS -// bio_put(my_bio); - - (char *)uaddr = kmalloc(TEST_MEM_SIZE, GFP_KERNEL); - - my_bio_copy = bio_map_user(bdev, uaddr, TEST_MEM_SIZE, FALSE); - - printk(KERN_ALERT "Return from bio_map_user %p\n", my_bio_copy); - - do_buffer_c_tests(); - - printk(KERN_ALERT "BIO FS tests complete\n"); - - break; - } - - return 0; -} - -static int ltp_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - return 0; -} - -int init_module(void) -{ - int result; - - printk(KERN_ALERT "ltpdev_init_module \n"); - - ltp_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, ltp_pm_callback); - - result = register_blkdev(ltp_fs_major, LTP_FS_DEV_NAME); - - printk(KERN_ALERT "LTP FS: register_blkdev result=%d major %d\n", - result, ltp_fs_major); - - if (result < 0) { - printk(KERN_ALERT "LTP FS: can't get major %d\n", ltp_fs_major); - return result; - } - - gd_ptr = kmalloc(sizeof(struct gendisk *), GFP_KERNEL); - - if (!gd_ptr) { - printk(KERN_ALERT "ERROR getting memory !!!\n"); - return 0; - } - - gd_ptr = alloc_disk(1); - - printk(KERN_ALERT "gd_ptr after alloc = %p \n", gd_ptr); - - gd_ptr->major = ltp_fs_major; - gd_ptr->first_minor = 0; - gd_ptr->fops = &blkops; - gd_ptr->driverfs_dev = NULL; - gd_ptr->capacity = MAX_NUM_DISKS; - gd_ptr->flags = genhd_flags; - - sprintf(gd_ptr->disk_name, LTP_FS_DEV_NAME); - - add_disk(gd_ptr); - - return 0; -} - -void cleanup_module(void) -{ - - printk(KERN_ALERT "Exiting module and cleaning up \n"); - - pm_unregister(ltp_pm_dev); - - put_disk(gd_ptr); - - del_gendisk(gd_ptr); - - unregister_blkdev(ltp_fs_major, LTP_FS_DEV_NAME); - -} - -static int do_buffer_c_tests() -{ - int line_no = 0; - - printk(KERN_ALERT "Starting buffer.c coverage tests... \n"); - - __buffer_error("Test file", line_no); - - printk(KERN_ALERT "buffer.c coverage tests complete...\n"); - - return 0; -} - -/** - * lookup_bdev - lookup a struct block_device by name - * - * @path: special file representing the block device - * - * Get a reference to the blockdevice at @path in the current - * namespace if possible and return it. Return ERR_PTR(error) - * otherwise. - */ -struct block_device *lookup_bdev(const char *path) -{ - struct block_device *bdev; - struct inode *inode; - struct nameidata nd; - int error; - - if (!path || !*path) - return ERR_PTR(-EINVAL); - - error = path_lookup(path, LOOKUP_FOLLOW, &nd); - if (error) - return ERR_PTR(error); - - inode = nd.dentry->d_inode; - error = -ENOTBLK; - if (!S_ISBLK(inode->i_mode)) - goto fail; - error = -EACCES; - if (nd.mnt->mnt_flags & MNT_NODEV) - goto fail; - error = bd_acquire(inode); - if (error) - goto fail; - bdev = inode->i_bdev; - -out: - path_release(&nd); - return bdev; -fail: - bdev = ERR_PTR(error); - goto out; -} - -int bd_acquire(struct inode *inode) -{ - struct block_device *bdev; - spin_lock(&bdev_lock); - if (inode->i_bdev) { - atomic_inc(&inode->i_bdev->bd_count); - spin_unlock(&bdev_lock); - return 0; - } - spin_unlock(&bdev_lock); - bdev = bdget(kdev_t_to_nr(inode->i_rdev)); - if (!bdev) - return -ENOMEM; - spin_lock(&bdev_lock); - if (!inode->i_bdev) { - inode->i_bdev = bdev; - inode->i_mapping = bdev->bd_inode->i_mapping; - list_add(&inode->i_devices, &bdev->bd_inodes); - } else if (inode->i_bdev != bdev) - BUG(); - spin_unlock(&bdev_lock); - return 0; -} diff --git a/testcases/kernel/fs/scsi/ltpfs/Makefile b/testcases/kernel/fs/scsi/ltpfs/Makefile deleted file mode 100644 index 5f4030661..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Makefile for GCOV profiling kernel module -# - -#KERNELDIR := ../linux-2.5.73 -CFLAGS := $(CFLAGS) -Wall -g - -ifneq ($(KERNELRELEASE),) - -obj-m := LtpfsCmds.o -obj-p := ltpfstest -else -KDIR := /lib/modules/$(shell uname -r)/build -PWD := $(shell pwd) - -default: - $(MAKE) -C $(KDIR) M=$(PWD) modules - ${CC} $(CFLAGS) -o ltpfstest -lm main.c -# $(MAKE) -C $(KERNELDIR) M=$(PWD) modules -endif - -clean: - rm -f LtpfsCmds.o - rm -f LtpfsCmds.ko - rm -f LtpfsCmds.bb - rm -f LtpfsCmds.bbg - rm -f LtpfsCmds.mod.c - rm -f LtpfsCmds.mod.o - rm -f .*.mod* - rm -f .*.cmd diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part1 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part1 deleted file mode 100644 index 65086d536..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part1 +++ /dev/null @@ -1,4 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the EXT2 & NFS filesystems -bfs101 ltpfstest /test/growfiles/ext2 -bfs102 ltpfstest /test/growfiles/nfs diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part2 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part2 deleted file mode 100644 index 86514908e..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part2 +++ /dev/null @@ -1,3 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the XFS filesystems -bfs201 ltpfstest /test/growfiles/xfs diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part3 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part3 deleted file mode 100644 index 4f2ee5f21..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part3 +++ /dev/null @@ -1,3 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the MSDOS filesystems -bfs101 ltpfstest /test/growfiles/msdos diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part4 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part4 deleted file mode 100644 index 84519512c..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part4 +++ /dev/null @@ -1,3 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the Reiser filesystems -bfs401 ltpfstest /test/growfiles/reiser diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part5 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part5 deleted file mode 100644 index c3fa4d7aa..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part5 +++ /dev/null @@ -1,3 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the Minix filesystems -bfs501 ltpfstest /test/growfiles/minix diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part6 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part6 deleted file mode 100644 index 0d600fe8e..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part6 +++ /dev/null @@ -1,3 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the EXT3 filesystems -bfs601 ltpfstest /test/growfiles/ext3 diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part7 b/testcases/kernel/fs/scsi/ltpfs/ltpfs.part7 deleted file mode 100644 index c9904d6be..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfs.part7 +++ /dev/null @@ -1,3 +0,0 @@ -#DESCRIPTION:filesystem tests -# Check the JFS filesystems -bfs701 ltpfstest /test/growfiles/jfs diff --git a/testcases/kernel/fs/scsi/ltpfs/ltpfsio.sh b/testcases/kernel/fs/scsi/ltpfs/ltpfsio.sh deleted file mode 100755 index ed3d8e2ab..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/ltpfsio.sh +++ /dev/null @@ -1,154 +0,0 @@ --#!/bin/sh -# This script should be run prior to running executing the filesystem tests. -# valid devices need to be passed for the test to work correctly -# 10/06/03 mridge@us.ibm.com added instance and time command line options -# -# - -cd `dirname $0` -export LTPROOT=${PWD} -echo $LTPROOT | grep testscripts > /dev/null 2>&1 -if [ $? -eq 0 ]; then - cd .. - export LTPROOT=${PWD} -fi - -export TMPBASE="/tmp" - - -usage() -{ - cat <<-END >&2 - usage: ${0##*/} [ -a part1 ] [ -n nfsmount ] - defaults: - part1=$part1 - nfsmount=$nfsmount - ltproot=$TPROOT - tmpdir=$TMPBASE - - example: ${0##*/} -a hdc1 -b hdc2 -c hdc3 -d hdc4 -n mytesthost:/testmountdir - - - This test will ONLY run on a 2.5.66 or higher kernel system. - - - These operations are destructive so do NOT point the tests to partitions where the data shouldn't be overwritten. - Once these tests are started all data in the partitions you point to will be destroyed. - - END -exit -} - -while getopts :a:n:v: arg -do case $arg in - a) part1=$OPTARG;; - n) nfsmount=$OPTARG;; - v) verb=$OPTARG;; - - \?) echo "************** Help Info: ********************" - usage;; - esac -done - -if [ ! -n "$part1" ]; then - echo "Missing 1st partition. You must pass 4 partitions for testing" - usage; - exit -fi - -if [ ! -n "$nfsmount" ]; then - echo "Missing NFS partition. You must pass an NFS mount point for testing" - usage; - exit -fi - -export PATH="${PATH}:${LTPROOT}/testcases/bin" - - -mkdir /test >/dev/null 2>&1 -mkdir /test/growfiles >/dev/null 2>&1 -mkdir /test/growfiles/ext2 >/dev/null 2>&1 -mkdir /test/growfiles/msdos >/dev/null 2>&1 -mkdir /test/growfiles/reiser >/dev/null 2>&1 -mkdir /test/growfiles/minix >/dev/null 2>&1 -mkdir /test/growfiles/xfs >/dev/null 2>&1 -mkdir /test/growfiles/nfs >/dev/null 2>&1 -mkdir /test/growfiles/jfs >/dev/null 2>&1 -mkdir /test/growfiles/ext3 >/dev/null 2>&1 - - -mkfs -V -t ext2 /dev/$part1 - - -mount -v -t nfs $nfsmount /test/growfiles/nfs -mount -v /dev/$part1 /test/growfiles/ext2 - - -echo "************ Running tests " -sort -R ${LTPROOT}/runtest/ltpfs.part1 -o ${TMPBASE}/ltpfs.part1 - -${LTPROOT}/pan/pan -e -S -a ltpfspart1 -n ltpfspart1 -l lvmlogfile -f ${TMPBASE}/ltpfs.part1 & - -wait $! - -umount -v -t nfs $nfsmount -umount -v /dev/$part1 -mkfs.xfs -f /dev/$part1 -mount -v /dev/$part1 /test/growfiles/xfs - - -sort -R ${LTPROOT}/runtest/ltpfs.part2 -o ${TMPBASE}/ltpfs.part2 - -${LTPROOT}/pan/pan -e -S -a ltpfspart2 -n ltpfspart2 -l lvmlogfile -f ${TMPBASE}/ltpfs.part2 & - -wait $! - -mkfs -V -t msdos /dev/$part1 -umount -v /dev/$part1 -mount -v /dev/$part1 /test/growfiles/msdos - -sort -R ${LTPROOT}/runtest/ltpfs.part3 -o ${TMPBASE}/ltpfs.part3 - -${LTPROOT}/pan/pan -e -S -a ltpfspart3 -n ltpfspart3 -l lvmlogfile -f ${TMPBASE}/ltpfs.part3 & - -wait $! - -umount -v /dev/$part1 -mkreiserfs /dev/$part1 <yesenter.txt -mount -v /dev/$part1 /test/growfiles/reiser - -sort -R ${LTPROOT}/runtest/ltpfs.part4 -o ${TMPBASE}/ltpfs.part4 - -${LTPROOT}/pan/pan -e -S -a ltpfspart4 -n ltpfspart4 -l lvmlogfile -f ${TMPBASE}/ltpfs.part4 & - -wait $! - -umount -v /dev/$part1 -mkfs -V -t minix /dev/$part1 -mount -v /dev/$part1 /test/growfiles/minix - -sort -R ${LTPROOT}/runtest/ltpfs.part5 -o ${TMPBASE}/ltpfs.part5 - -${LTPROOT}/pan/pan -e -S -a ltpfspart5 -n ltpfspart5 -l lvmlogfile -f ${TMPBASE}/ltpfs.part5 & - -wait $! - -umount -v /dev/$part1 -mkfs -V -t ext3 /dev/$part1 -mount -v /dev/$part1 /test/growfiles/ext3 - -sort -R ${LTPROOT}/runtest/ltpfs.part6 -o ${TMPBASE}/ltpfs.part6 - -${LTPROOT}/pan/pan -e -S -a ltpfspart6 -n ltpfspart6 -l lvmlogfile -f ${TMPBASE}/ltpfs.part6 & - -wait $! - -umount -v /dev/$part1 -mkfs -V -t jfs /dev/$part1 <yesenter.txt -mount -v -t jfs /dev/$part1 /test/growfiles/jfs - -sort -R ${LTPROOT}/runtest/ltpfs.part7 -o ${TMPBASE}/ltpfs.part7 - -${LTPROOT}/pan/pan -e -S -a ltpfspart7 -n ltpfspart7 -l lvmlogfile -f ${TMPBASE}/ltpfs.part7 & - -wait $! - - diff --git a/testcases/kernel/fs/scsi/ltpfs/main.c b/testcases/kernel/fs/scsi/ltpfs/main.c deleted file mode 100644 index 90a5531ac..000000000 --- a/testcases/kernel/fs/scsi/ltpfs/main.c +++ /dev/null @@ -1,647 +0,0 @@ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> -#include <math.h> -#include <time.h> -#include <ftw.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <linux/kd.h> -#include <linux/errno.h> - -#include "Ltpfs.h" - -#define M_2PI (M_PI*2) -#define MAXN 4096 -#define MAXFSIZE 1024 * 192 -#define FILE_CREATE_COUNT 256 -#define FAIL 0 -#define SUCCESS 1 -#define MAXNUM 5000 -#define BUFFSIZE 8192 -#define AVEFSIZE (MAXFSIZE/2) -#define POOLDISKSPACE (AVEFSIZE*128) -#define MAXERROR 1024 -#define FILES_ONLY 0x01 -#define ALL 0x00 - -// Globals - -char wbuf[MAXFSIZE]; -int startc = 0; -int showchar[] = { 124, 47, 45, 92, 124, 47, 45, 92 }; - -int nullFileHandle; -static int openlog[2] = { 0, 0 }; - -int cFileCount, dFileCount, errorCount; -static int disk_space_pool = 0; -char rootPath[BUFFSIZE]; - -int LTP_fs_open_block_device(void); -int do_fs_thump_tests(char *path); -int do_create_file_test(char *path); -int makedir(char *dir1); -int changedir(char *dir); -int do_random_access_test(int maxNum); -int do_random_create_delete(int maxNum); -int create_file(char *filename); -int delete_file(char *filename); -int gen_random_file_size(int min, int max); -int open_read_close(char *fname); -int create_or_delete(char *fname); -int do_tree_cleanup(char *path, int flag); -int cleanup_files(char *file, struct stat *statBuff, int flag); -int cleanup_dirs(char *file, struct stat *statBuff, int flag); - -int ltp_block_dev_handle = 0; /* handle to LTP Test block device */ -int ltp_fileHandle = 0; -char *fileBuf; - -int main(int argc, char **argv) -{ - - ltpdev_cmd_t cmd = { 0, 0 }; - int rc, i, tmpHandle; - struct stat statBuf; - - printf("[%s] - Running test program\n", argv[0]); - - rc = LTP_fs_open_block_device(); - - if (!rc) { - - ltp_block_dev_handle = open(LTP_FS_DEVICE_NAME, O_RDWR); - - if (ltp_block_dev_handle < 0) { - printf - ("ERROR: Open of device %s failed %d errno = %d\n", - LTP_FS_DEVICE_NAME, ltp_block_dev_handle, errno); - } else { - rc = ioctl(ltp_block_dev_handle, LTPAIODEV_CMD, &cmd); - - printf("return from AIO ioctl %d \n", rc); - - rc = ioctl(ltp_block_dev_handle, LTPBIODEV_CMD, &cmd); - - printf("return from BIO ioctl %d \n", rc); - } - - } else { - printf("ERROR: Create/open block device failed\n"); - } - - ltp_fileHandle = - open("/tmp/testfile", O_CREAT | O_RDWR | O_SYNC | FASYNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - if (ltp_fileHandle > 0) { - - tmpHandle = open("/usr/include/ctype.h", O_RDONLY); - - if (tmpHandle > 0) { - - rc = fstat(tmpHandle, &statBuf); - - if (!rc) { - fileBuf = malloc(statBuf.st_size); - - if (fileBuf) { - - read(tmpHandle, fileBuf, - statBuf.st_size); - close(tmpHandle); - write(ltp_fileHandle, fileBuf, - statBuf.st_size); - - for (i = 0; i < 100; i++) { - read(ltp_fileHandle, fileBuf, - statBuf.st_size * i); - write(ltp_fileHandle, fileBuf, - statBuf.st_size * i); - } - } - - } - - } else { - printf("ERROR: Create/open file failed\n"); - } - } - - printf("*** Starting FileSystem thump tests....****\n"); - printf("*** Please be patient, this may take a little while... ***\n"); - - for (i = 1; i < argc; i++) { - printf("Running test %d of %d on FileSystem %s \n", i, argc - 1, - argv[i]); - if (strcmp(argv[i], "|") != 0) { - strcpy(rootPath, argv[i]); - rc = do_fs_thump_tests(argv[i]); - if (rc != 0 && rc != ENOSPC) { - printf - ("ERROR: Failed on FileSystem %s with errno %d \n", - argv[i], rc); - } - } else { - printf("Test Program complete..\n"); - break; - } - - } - - printf("Test Program complete..\n"); - - return 0; -} - -int do_fs_thump_tests(char *path) -{ - int rc = 0; - - printf("Changing to directory %s \n", path); - - changedir(path); - - cFileCount = 0; - dFileCount = 0; - - rc |= do_create_file_test(path); - rc |= do_random_access_test(MAXNUM); - rc |= do_tree_cleanup(path, FILES_ONLY); - rc |= do_random_create_delete(MAXNUM); - rc |= do_tree_cleanup(path, ALL); - - return rc; - -} - -int do_tree_cleanup(char *path, int flag) -{ - - if (flag == FILES_ONLY) { - printf("Cleaning up test files...\n"); - ftw(path, (void *)cleanup_files, MAXNUM); - } else { - printf("Cleaning up everything in the test directory...\n"); - ftw(path, (void *)cleanup_files, MAXNUM); - ftw(path, (void *)cleanup_dirs, MAXNUM); - } - - return 0; -} - -int cleanup_files(char *file, struct stat *statBuff, int flag) -{ - int rc = 0; - - if (flag == FTW_F) { - if (unlink(file)) { - printf("ERROR:%d removing file %s\n", errno, file); - } - } - - return rc; -} - -int cleanup_dirs(char *file, struct stat *statBuff, int flag) -{ - int rc = 0; - - //printf("%s:Cleaning up directory %s \n", __FUNCTION__, file); - - if (strcmp(rootPath, file) == 0) { - return 0; - } - - if (flag == FTW_F) { - if (unlink(file)) { - printf("ERROR:%d removing file %s\n", errno, file); - } - } else if (flag == FTW_D) { - changedir(file); - ftw(file, (void *)cleanup_dirs, MAXNUM); - rmdir(file); - - } else { - printf("No idea what we found here\n"); - } - - return rc; -} - -int do_create_file_test(char *path) -{ - int i = 0; - int j = 0; - int k = 0; - int l = 0; - int rc = 0; - - char dir1[MAXN]; - char dir2[MAXN]; - char dir3[MAXN]; - char filename[MAXN]; - - time_t t; - - int maxfiles = 0xFFFFFF; - - time(&t); - - srandom((unsigned int)getpid() ^ - (((unsigned int)t << 16) | (unsigned int)t >> 16)); - - printf("Creating files...\n"); - - for (i = 0; i < FILE_CREATE_COUNT; i++) { - - sprintf(dir1, "%2.2x", i); - - makedir(dir1); - - changedir(dir1); - - for (j = 0; j < FILE_CREATE_COUNT; j++) { - - sprintf(dir2, "%2.2x", j); - - makedir(dir2); - - changedir(dir2); - - for (k = 0; k < FILE_CREATE_COUNT; k++) { - - sprintf(dir3, "%2.2x", k); - makedir(dir3); - changedir(dir3); - - for (l = 0; l < FILE_CREATE_COUNT; l++) { - sprintf(filename, "%s%s%s%2.2x", dir1, - dir2, dir3, l); - rc = create_file(filename); - if (rc != 0 || maxfiles < dFileCount++) { - if (rc != ENOSPC) { - printf - ("ERROR: failed error:%d creating all the test files ! \n", - errno); - printf - ("ERROR2: rc:%d -- dFileCount:%d \n", - rc, dFileCount); - } - goto end; - } - } - changedir("../"); - } - changedir("../"); - } - changedir("../"); - } -end: - fprintf(stderr, "\nTotal create files: %d\n", cFileCount); - printf("Done\n"); - return rc; -} - -int makedir(char *dir1) -{ - if (mkdir(dir1, S_IRWXU) < 0) { - perror(dir1); - return (errno); - } - return 0; -} - -int changedir(char *dir) -{ - if (chdir(dir) < 0) { - perror(dir); - return (errno); - } - - return 0; -} - -int create_file(char *filename) -{ - int fileHandle; - int randomsize; - - if ((fileHandle = creat(filename, S_IRWXU)) < 0) { - - fprintf(stderr, "\nERROR line %d: Total create files: %d\n", - __LINE__, cFileCount); - perror(filename); - return (errno); - } - - if ((randomsize = gen_random_file_size(0, MAXFSIZE)) < 0) { - randomsize = MAXFSIZE; - } - if (write(fileHandle, wbuf, randomsize) < 0) { - - fprintf(stderr, "\nERROR:%d line%d: Total create files: %d\n", - errno, __LINE__, cFileCount); - close(fileHandle); - - perror(filename); - return (errno); - } - - cFileCount++; - close(fileHandle); - return 0; -} - -int delete_file(char *filename) -{ - struct stat buf; - int st; - - st = stat(filename, &buf); - - if (st < 0) { - errorCount++; - printf("ERROR line %d: Getting file stats %s \n", __LINE__, - filename); - return (-1); - } - - disk_space_pool += buf.st_size; - - if (unlink(filename) < 0) { - errorCount++; - printf("ERROR line %d: Removing file %s \n", __LINE__, - filename); - return (-1); - } - - dFileCount++; - return 0; -} - -int LTP_fs_open_block_device() -{ - dev_t devt; - struct stat statbuf; - int rc = 0; - - if (ltp_block_dev_handle == 0) { - - /* check for the /dev/LTPFSTest subdir, and create if it does not exist. - * - * If devfs is running and mounted on /dev, these checks will all pass, - * so a new node will not be created. - */ - devt = makedev(LTPMAJOR, 0); - - rc = stat(LTP_FS_DEV_NODE_PATH, &statbuf); - - if (rc) { - if (errno == ENOENT) { - /* dev node does not exist. */ - rc = mkdir(LTP_FS_DEV_NODE_PATH, - (S_IFDIR | S_IRWXU | S_IRGRP | - S_IXGRP | S_IROTH | S_IXOTH)); - } else { - printf - ("ERROR: Problem with LTP FS dev directory. Error code from stat() is %d\n\n", - errno); - } - - } else { - if (!(statbuf.st_mode & S_IFDIR)) { - rc = unlink(LTP_FS_DEV_NODE_PATH); - if (!rc) { - rc = mkdir(LTP_FS_DEV_NODE_PATH, - (S_IFDIR | S_IRWXU | S_IRGRP - | S_IXGRP | S_IROTH | - S_IXOTH)); - } - } - } - - /* - * Check for the /dev/ltp-fs/block_device node, and create if it does not - * exist. - */ - rc = stat(LTP_FS_DEVICE_NAME, &statbuf); - if (rc) { - if (errno == ENOENT) { - /* dev node does not exist */ - rc = mknod(LTP_FS_DEVICE_NAME, - (S_IFBLK | S_IRUSR | S_IWUSR | - S_IRGRP | S_IWGRP), devt); - } else { - printf - ("ERROR:Problem with LTP FS block device node directory. Error code form stat() is %d\n\n", - errno); - } - - } else { - /* - * /dev/ltp-fs/block_device exists. Check to make sure it is for a - * block device and that it has the right major and minor. - */ - if ((!(statbuf.st_mode & S_IFBLK)) || - (statbuf.st_rdev != devt)) { - - /* Recreate the dev node. */ - rc = unlink(LTP_FS_DEVICE_NAME); - if (!rc) { - rc = mknod(LTP_FS_DEVICE_NAME, - (S_IFBLK | S_IRUSR | S_IWUSR - | S_IRGRP | S_IWGRP), devt); - } - } - } - - } - - return rc; -} - -int gen_random_file_size(int min, int max) -{ - double u1, u2, z; - int i; - int ave; - int range; - int ZZ; - if (min >= max) { - return (-1); - } - range = max - min; - ave = range / 2; - for (i = 0; i < 10; i++) { - u1 = ((double)(random() % 1000000)) / 1000000; - u2 = ((double)(random() % 1000000)) / 1000000; - z = sqrt(-2.0 * log(u1)) * cos(M_2PI * u2); - ZZ = min + (ave + (z * (ave / 4))); - if (ZZ >= min && ZZ < max) { - return (ZZ); - } - } - return (-1); -} - -int do_random_access_test(int maxNum) -{ - int r; - char fname[1024]; - time_t t; - int i; - - printf("Running random access test...\n"); - changedir(rootPath); - - if (maxNum < 1 || maxNum > MAXNUM) { - printf("out of size %d\n", maxNum); - return 1; - } - - time(&t); - srandom((unsigned int)getpid() ^ - (((unsigned int)t << 16) | (unsigned int)t >> 16)); - - if ((nullFileHandle = open("/dev/null", O_WRONLY)) < 0) { - perror("/dev/null"); - return (errno); - } - - /* 00/00/00/00 */ - for (i = 0; i < maxNum; i++) { - - r = random() % maxNum; - - sprintf(fname, "00/%2.2x/%2.2x/00%2.2x%2.2x%2.2x", - ((r >> 16) & 0xFF), - ((r >> 8) & 0xFF), - ((r >> 16) & 0xFF), ((r >> 8) & 0xFF), (r & 0xFF)); - - open_read_close(fname); - } - close(nullFileHandle); - printf("Success:\t%d\nFail:\t%d\n", openlog[SUCCESS], openlog[FAIL]); - return 0; -} - -int open_read_close(char *fname) -{ - int fileHandle, fileHandle2; - char buffer[BUFFSIZE]; - int c; - - if ((fileHandle = open(fname, O_RDONLY | O_SYNC | O_ASYNC)) < 0) { - openlog[FAIL]++; - printf("ERROR:opening file %s failed %d \n", fname, errno); - return (errno); - } - - if ((fileHandle2 = open(fname, O_RDONLY | O_SYNC | O_ASYNC)) < 0) { - openlog[FAIL]++; - printf("ERROR:2nd opening file %s failed %d \n", fname, errno); - return (errno); - } - - openlog[SUCCESS]++; - - while ((c = read(fileHandle, buffer, BUFFSIZE)) > 0) { - if (write(nullFileHandle, buffer, c) < 0) { - perror("/dev/null"); - printf("Opened\t %d\nUnopend:\t%d\n", openlog[SUCCESS], - openlog[FAIL]); - close(fileHandle2); - close(fileHandle); - return (errno); - } - if ((c = read(fileHandle2, buffer, BUFFSIZE)) > 0) { - if (write(nullFileHandle, buffer, c) < 0) { - perror("/dev/null"); - printf("Opened\t %d\nUnopend:\t%d\n", - openlog[SUCCESS], openlog[FAIL]); - close(fileHandle2); - close(fileHandle); - return (errno); - } - } - } - - if (c < 0) { - perror(fname); - printf("Opened\t %d\nUnopend:\t%d\n", openlog[SUCCESS], - openlog[FAIL]); - return (errno); - } - - close(fileHandle2); - close(fileHandle); - return 0; -} - -int create_or_delete(char *fname) -{ - int r, rc; - - r = (random() & 1); - - /* create */ - if ((create_file(fname) == 0)) { - rc = delete_file(fname); - } else { - printf("Error: %d creating random file \n", errno); - } - - if ((errorCount > dFileCount || errorCount > cFileCount) - && (errorCount > MAXERROR)) { - fprintf(stderr, "Too many errors -- Aborting test\n"); - fprintf(stderr, "Total create files: %d\n", cFileCount); - fprintf(stderr, "Total delete files: %d\n", dFileCount); - fprintf(stderr, "Total error : %d\n", errorCount); - return (MAXERROR); - } - - return 0; -} - -int do_random_create_delete(int maxNum) -{ - int r, rc = 0; - char fname[1024]; - time_t t; - int i; - - printf("Running random create/delete test...\n"); - - if (maxNum < 1 || maxNum > MAXNUM) { - printf("MAX out of size %d\n", maxNum); - return (maxNum); - } - - time(&t); - srandom((unsigned int)getpid() ^ - (((unsigned int)t << 16) | (unsigned int)t >> 16)); - - /* 00/00/00/00 */ - for (i = 0; i < maxNum && rc != MAXERROR; i++) { - r = random() % maxNum; - sprintf(fname, "00/%2.2x/%2.2x/00%2.2x%2.2x%2.2x", - ((r >> 16) & 0xFF), - ((r >> 8) & 0xFF), - ((r >> 16) & 0xFF), ((r >> 8) & 0xFF), (r & 0xFF)); - - rc = create_or_delete(fname); - } - - fprintf(stderr, "Total create files: %d\n", cFileCount); - fprintf(stderr, "Total delete files: %d\n", dFileCount); - fprintf(stderr, "Total error : %d\n", errorCount); - return (rc); -} diff --git a/testcases/kernel/fs/scsi/ltpscsi/Makefile b/testcases/kernel/fs/scsi/ltpscsi/Makefile deleted file mode 100644 index e404ce074..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -SHELL = /bin/sh - -EXECS = scsimain - -LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 - -CFLAGS = -g -O2 -Wall -D_REENTRANT $(LARGE_FILE_FLAGS) -# CFLAGS = -g -O2 -Wall -D_REENTRANT -DSG_KERNEL_INCLUDES $(LARGE_FILE_FLAGS) -# CFLAGS = -g -O2 -Wall -pedantic -D_REENTRANT $(LARGE_FILE_FLAGS) - -LDFLAGS = - -all: $(EXECS) - -depend dep: - @set -e; for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ - done > .depend - -clean: - /bin/rm -f *.o $(EXECS) core .depend - -scsimain: scsimain.o sg_err.o llseek.o - $(LD) -o $@ $(LDFLAGS) $^ -lpthread - -install: $(EXECS) - install -d $(INSTDIR) - @set -e; for name in $^; \ - do install -s -o root -g root -m 755 $$name $(INSTDIR); \ - done - install -d $(MANDIR)/$(MAN_PREF) - @set -e; for mp in $(MAN_PGS); \ - do install -o root -g root -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ - gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ - done - -uninstall: - dists="$(EXECS)"; \ - @set -e; for name in $$dists; do \ - rm -f $(INSTDIR)/$$name; \ - done - @set -e; for mp in $(MAN_PGS); do \ - rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ - done - -ifeq (.depend,$(wildcard .depend)) -include .depend -endif diff --git a/testcases/kernel/fs/scsi/ltpscsi/llseek.c b/testcases/kernel/fs/scsi/ltpscsi/llseek.c deleted file mode 100644 index 25b77620c..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/llseek.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * llseek.c -- stub calling the llseek system call - * - * Copyright (C) 1994 Remy Card. This file may be redistributed - * under the terms of the GNU Public License. - * - * This file is borrowed from the util-linux-2.10q tarball's implementation - * of fdisk. It allows seeks to 64 bit offsets, if supported. - * Changed "ext2_" prefix to "llse". - */ - -#include <sys/types.h> - -#include <errno.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <linux/unistd.h> /* for __NR_llseek */ - -#if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long llse_loff_t; -#else -typedef long llse_loff_t; -#endif - -extern llse_loff_t llse_llseek(unsigned int, llse_loff_t, unsigned int); - -#ifdef __linux__ - -#if defined(__alpha__) || defined(__ia64__) - -#ifdef __NR_lseek -static off_t my_lseek(int fd, off_t off, int whence) -{ - return syscall(__NR_lseek, fd, off, whence); -} -#else /* undefined __NR_lseek */ -static off_t my_lseek(int fd, off_t off, int whence) -{ - errno = ENOSYS; - return -1; -} -#endif /* __NR_lseek */ - -#define my_llseek my_lseek - -#else /* !__alpha__ && !__ia64__ */ - -static int _llseek(unsigned int, unsigned long, - unsigned long, llse_loff_t *, unsigned int); - -#ifndef __NR_llseek -/* no __NR_llseek on compilation machine - might give it explicitly */ -static int _llseek(unsigned int fd, unsigned long oh, - unsigned long ol, llse_loff_t * result, unsigned int origin) -{ - errno = ENOSYS; - return -1; -} -#else -static int _llseek(unsigned int fd, unsigned long oh, - unsigned long ol, llse_loff_t * result, unsigned int origin) -{ - return syscall(__NR_llseek, fd, oh, ol, result, origin); -} -#endif - -static llse_loff_t my_llseek(unsigned int fd, llse_loff_t offset, - unsigned int origin) -{ - llse_loff_t result; - int retval; - - retval = _llseek(fd, ((unsigned long long)offset) >> 32, - ((unsigned long long)offset) & 0xffffffff, - &result, origin); - return (retval == -1 ? (llse_loff_t) retval : result); -} - -#endif /* __alpha__ */ - -llse_loff_t llse_llseek(unsigned int fd, llse_loff_t offset, - unsigned int origin) -{ - llse_loff_t result; - static int do_compat = 0; - - if (!do_compat) { - result = my_llseek(fd, offset, origin); - if (!(result == -1 && errno == ENOSYS)) - return result; - - /* - * Just in case this code runs on top of an old kernel - * which does not support the llseek system call - */ - do_compat = 1; - /* - * Now try ordinary lseek. - */ - } - - if ((sizeof(off_t) >= sizeof(llse_loff_t)) || - (offset < ((llse_loff_t) 1 << ((sizeof(off_t) * 8) - 1)))) - return lseek(fd, (off_t) offset, origin); - - errno = EINVAL; - return -1; -} - -#else /* !linux */ - -llse_loff_t llse_llseek(unsigned int fd, llse_loff_t offset, - unsigned int origin) -{ - if ((sizeof(off_t) < sizeof(llse_loff_t)) && - (offset >= ((llse_loff_t) 1 << ((sizeof(off_t) * 8) - 1)))) { - errno = EINVAL; - return -1; - } - return lseek(fd, (off_t) offset, origin); -} - -#endif /* linux */ diff --git a/testcases/kernel/fs/scsi/ltpscsi/llseek.h b/testcases/kernel/fs/scsi/ltpscsi/llseek.h deleted file mode 100644 index cdf6fceae..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/llseek.h +++ /dev/null @@ -1,10 +0,0 @@ - -#if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long llse_loff_t; -#else -typedef long llse_loff_t; -#endif - -extern llse_loff_t llse_llseek(unsigned int fd, - llse_loff_t offset, - unsigned int origin); diff --git a/testcases/kernel/fs/scsi/ltpscsi/ltpfsscsi.sh b/testcases/kernel/fs/scsi/ltpscsi/ltpfsscsi.sh deleted file mode 100755 index 29648d9e7..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/ltpfsscsi.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/sh -# This script should be run to execute the filesystem tests on SCSI vitual devices. -# 10/21/03 mridge@us.ibm.com Initial creation of testcases -# -# - -cd `dirname $0` -export LTPROOT=${PWD} -echo $LTPROOT | grep testscripts > /dev/null 2>&1 -if [ $? -eq 0 ]; then - cd .. - export LTPROOT=${PWD} -fi - -export TMPBASE="/tmp" - - -usage() -{ - cat <<-END >&2 - usage: ${0##*/} [ -a part1 ] [ -b part2 ] [ -k Kernel Path - fully qualified kernel path ] - defaults: - - There are no defaults, all items MUST be passed - - example: ${0##*/} -a sda -b sdb -k /usr/src/linux - - - These tests must be run after ssi_debug has been configured and built as a module so it can be loaded with - the correct parameters. - - - These operations are destructive so do NOT point the tests to partitions where the data shouldn't be overwritten. - Once these tests are started all data in the partitions you point to will be destroyed. - - END -exit -} - -while getopts :a:b:c:k: arg -do case $arg in - a) part1=$OPTARG;; - b) part2=$OPTARG;; - c) part3=$OPTARG;; - k) kernpath=$OPTARG;; - - \?) echo "************** Help Info: ********************" - usage;; - esac -done - -if [ ! -n "$part1" ]; then - echo "Missing 1st partition. You must pass 2 partitions for testing" - usage; - exit -fi - -if [ ! -n "$part2" ]; then - echo "Missing 2nd partition. You must pass 2 partitions for testing" - usage; - exit -fi - -if [ ! -n "$part3" ]; then - echo "Missing 3rd partition. You must pass 3 partitions for testing" - usage; - exit -fi - -if [ ! -n "$kernpath" ]; then - echo "Missing kernel path. You must pass kernel path for testing" - usage; - exit -fi - -export PATH="${PATH}:${LTPROOT}/testcases/bin" - - -mkdir /test >/dev/null 2>&1 -mkdir /test/growfiles >/dev/null 2>&1 -mkdir /test/growfiles/scsi >/dev/null 2>&1 -mkdir /test/growfiles/scsi/ext2 >/dev/null 2>&1 -mkdir /test/growfiles/scsi/ext3 >/dev/null 2>&1 -mkdir /test/growfiles/scsi/reiser >/dev/null 2>&1 - - -mkfs -V -t ext2 /dev/$part1 <yesenter.txt -mkfs -V -t ext3 /dev/$part2 <yesenter.txt -mkreiserfs -f /dev/$part3 <yesenter.txt - - -mount -v -t ext2 /dev/$part1 /test/growfiles/scsi/ext2 -mount -v -t ext3 /dev/$part2 /test/growfiles/scsi/ext3 -mount -v /dev/$part3 /test/growfiles/scsi/reiser - -cd $kernpath/drivers/scsi -modprobe scsi_debug max_luns=2 num_tgts=7 add_host=10 -cd ${LTPROOT} - -echo "************ Running tests " -sort -R ${LTPROOT}/runtest/scsi.part1 -o ${TMPBASE}/scsi.part1 - -${LTPROOT}/pan/pan -e -S -a scsipart1 -n scsipart1 -l scsilogfile -f ${TMPBASE}/scsi.part1 & - -wait $! - -umount -v /dev/$part1 -umount -v /dev/$part2 -umount -v /dev/$part3 -rmmod scsi_debug - - - diff --git a/testcases/kernel/fs/scsi/ltpscsi/scsimain.c b/testcases/kernel/fs/scsi/ltpscsi/scsimain.c deleted file mode 100644 index ce23ae1e7..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/scsimain.c +++ /dev/null @@ -1,7651 +0,0 @@ -/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") - device driver. -* Copyright (C) 1999 - 2002 D. Gilbert -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. - - This program scans the "sg" device space (ie actual + simulated SCSI - generic devices). - Options: -w open writable (new driver opens readable unless -i) - -n numeric scan: scan /dev/sg0,1,2, .... - -a alpha scan: scan /dev/sga,b,c, .... - -i do SCSI inquiry on device (implies -w) - -x extra information output - - By default this program will look for /dev/sg0 first (i.e. numeric scan) - - Note: This program is written to work under both the original and - the new sg driver. - - Version 1.00 20031022 - - F. Jansen - modification to extend beyond 26 sg devices. - M. Ridgeway - Roll code together for SCSI testing with one command line - -6 byte INQUIRY command: -[0x12][ |lu][pg cde][res ][al len][cntrl ] -*/ - -#define _GNU_SOURCE -#include <unistd.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <dirent.h> -#include <limits.h> -#include <time.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <signal.h> -#include <ctype.h> -#include <pthread.h> -#include <sys/sysmacros.h> -#include <sys/time.h> -#include <sys/mman.h> -#include <linux/major.h> -#include "sg_include.h" -#include "sg_err.h" -#include "llseek.h" - -#define ME "scsimain: " - -#define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */ -//static char * version_str = "0.21 20030513"; - -#define BPI (signed)(sizeof(int)) -#define READWRITE_BASE_NUM 0x12345678 -#define DEF_BLOCK_SIZE 512 -#define DEF_NUM_THREADS 16 -#define MAX_NUM_THREADS SG_MAX_QUEUE -#define DEF_BLOCKS_PER_TRANSFER 128 -#define DEF_SCSI_CDBSZ 10 -#define MAX_SCSI_CDBSZ 16 -#define TUR_CMD_LEN 6 -#define DEVNAME_SZ 256 -#define MAX_HOLES 4 - -#define OFF sizeof(struct sg_header) -#define INQ_REPLY_LEN 96 /* logic assumes >= sizeof(inqCmdBlk) */ -#define INQUIRY_CMDLEN 6 -#define INQUIRY_CMD 0x12 -#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */ -#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ -#define REASON_SZ 128 - -#define SENSE_BUFF_SZ 64 -#define RCAP_REPLY_LEN 8 -#define LOG_SENSE_CMD 0x4d -#define LOG_SENSE_CMDLEN 10 -#define MX_ALLOC_LEN (1024 * 17) -#define D_ROOT_SZ 512 -#define STR_SZ 1024 -#define INOUTF_SZ 512 -#define EBUFF_SZ 512 -#define MDEV_NAME_SZ 256 - -#define PG_CODE_ALL 0x00 - -#define TRUE 1 -#define FALSE 0 -#define MAX_DEVICES 50 - -#define NAME_LEN_MAX 256 -#define LEVELS 4 - -#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */ -#define INQ_ALLOC_LEN 255 - -#ifndef SCSI_IOCTL_GET_PCI -#define SCSI_IOCTL_GET_PCI 0x5387 -#endif - -#define READ_CAP_REPLY_LEN 8 - -#ifndef RAW_MAJOR -#define RAW_MAJOR 255 /*unlikey value */ -#endif - -#define FT_OTHER 1 /* filetype is probably normal */ -#define FT_SG 2 /* filetype is sg char device or supports - SG_IO ioctl */ -#define FT_RAW 4 /* filetype is raw char device */ -#define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */ -#define FT_ST 16 /* filetype is st char device (tape) */ -#define FT_BLOCK 32 /* filetype is block device */ - -#define DEV_NULL_MINOR_NUM 3 - -#ifdef SG_GET_RESERVED_SIZE -#define OPEN_FLAG O_RDONLY -#else -#define OPEN_FLAG O_RDWR -#endif - -#ifndef SG_MAX_SENSE -#define SG_MAX_SENSE 16 -#endif - -#define TEST_START 0 -#define TEST_BREAK 1 -#define TEST_STOP 2 -#define MAX_SG_DEVS 128 -#define MAX_SD_DEVS 128 -#define MAX_SR_DEVS 128 -#define MAX_ST_DEVS 128 -#define MAX_OSST_DEVS 128 -#define MAX_ERRORS 5 - -#define LIN_DEV_TYPE_UNKNOWN 0 -#define LIN_DEV_TYPE_SD 1 -#define LIN_DEV_TYPE_SR 2 -#define LIN_DEV_TYPE_ST 3 -#define LIN_DEV_TYPE_SCD 4 -#define LIN_DEV_TYPE_OSST 5 - -#define MODE_SENSE6_CMD 0x1a -#define MODE_SENSE6_CMDLEN 6 -#define MODE_SENSE10_CMD 0x5a -#define MODE_SENSE10_CMDLEN 10 -#define INQUIRY_CMD 0x12 -#define INQUIRY_CMDLEN 6 -#define MODE_ALLOC_LEN (1024 * 4) - -#define MODE_CODE_ALL 0x3f - -#define RB_MODE_DESC 3 -#define RB_MODE_DATA 2 -#define RB_DESC_LEN 4 -#define RB_MB_TO_READ 200 -#define RB_OPCODE 0x3C -#define RB_CMD_LEN 10 - -/* #define SG_DEBUG */ - -#ifndef SG_FLAG_MMAP_IO -#define SG_FLAG_MMAP_IO 4 -#endif -#ifndef SG_SCSI_RESET -#define SG_SCSI_RESET 0x2284 -#endif - -#ifndef SG_SCSI_RESET_NOTHING -#define SG_SCSI_RESET_NOTHING 0 -#define SG_SCSI_RESET_DEVICE 1 -#define SG_SCSI_RESET_BUS 2 -#define SG_SCSI_RESET_HOST 3 -#endif -#define LONG_TIMEOUT 2400000 /* 2,400,000 millisecs == 40 minutes */ - -#define SEND_DIAGNOSTIC_CMD 0x1d -#define SEND_DIAGNOSTIC_CMDLEN 6 -#define RECEIVE_DIAGNOSTIC_CMD 0x1c -#define RECEIVE_DIAGNOSTIC_CMDLEN 6 - -#define START_STOP 0x1b -#define SYNCHRONIZE_CACHE 0x35 - -#define DEF_START_TIMEOUT 120000 /* 120,000 millisecs == 2 minutes */ - -#define DEVICE_RESET 0 -#define HOST_RESET 1 -#define BUS_RESET 2 -#define SG_HSZ sizeof(struct sg_header) -#define OFFSET_HEADER (SG_HSZ - (2 * sizeof(int))) -#define SIZEOF_BUFFER (256*1024) -#define SIZEOF_BUFFER1 (16*1024) -#define MAXPARM 32 - -#define SETUP_MODE_PAGE(NPAGE, NPARAM) \ - status = get_mode_page(NPAGE, page_code); \ - if (status) { printf("\n"); return status; } \ - bdlen = buffer[11]; \ - pagestart = buffer + 12 + bdlen; - -typedef struct request_collection { /* one instance visible to all threads */ - int infd; - int skip; - int in_type; - int in_scsi_type; - int in_blk; /* -\ next block address to read */ - int in_count; /* | blocks remaining for next read */ - int in_done_count; /* | count of completed in blocks */ - int in_partial; /* | */ - int in_stop; /* | */ - pthread_mutex_t in_mutex; /* -/ */ - int outfd; - int seek; - int out_type; - int out_scsi_type; - int out_blk; /* -\ next block address to write */ - int out_count; /* | blocks remaining for next write */ - int out_done_count; /* | count of completed out blocks */ - int out_partial; /* | */ - int out_stop; /* | */ - pthread_mutex_t out_mutex; /* | */ - pthread_cond_t out_sync_cv; /* -/ hold writes until "in order" */ - int bs; - int bpt; - int fua_mode; - int dio; - int dio_incomplete; /* -\ */ - int sum_of_resids; /* | */ - pthread_mutex_t aux_mutex; /* -/ (also serializes some printf()s */ - int coe; - int cdbsz; - int debug; -} Rq_coll; - -typedef struct request_element { /* one instance per worker thread */ - int infd; - int outfd; - int wr; - int blk; - int num_blks; - unsigned char *buffp; - unsigned char *alloc_bp; - sg_io_hdr_t io_hdr; - unsigned char cmd[MAX_SCSI_CDBSZ]; - unsigned char sb[SENSE_BUFF_LEN]; - int bs; - int fua_mode; - int dio; - int dio_incomplete; - int resid; - int in_scsi_type; - int out_scsi_type; - int cdbsz; - int debug; -} Rq_elem; - -typedef struct my_map_info { - int active; - int lin_dev_type; - int oth_dev_num; - struct sg_scsi_id sg_dat; - char vendor[8]; - char product[16]; - char revision[4]; -} my_map_info_t; - -typedef struct sg_map { - int bus; - int channel; - int target_id; - int lun; - char *dev_name; -} Sg_map; - -typedef struct my_scsi_idlun { -/* why can't userland see this structure ??? */ - int dev_id; - int host_unique_id; -} My_scsi_idlun; - -struct page_code_desc { - int page_code; - const char *desc; -}; - -static const char *pg_control_str_arr[] = { - "current", - "changeable", - "default", - "saved" -}; - -char *devices[] = - { "/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd", "/dev/sde", "/dev/sdf", - "/dev/sdg", "/dev/sdh", "/dev/sdi", "/dev/sdj", "/dev/sdk", "/dev/sdl", - "/dev/sdm", "/dev/sdn", "/dev/sdo", "/dev/sdp", "/dev/sdq", "/dev/sdr", - "/dev/sds", "/dev/sdt", "/dev/sdu", "/dev/sdv", "/dev/sdw", "/dev/sdx", - "/dev/sdy", "/dev/sdz", "/dev/sdaa", "/dev/sdab", "/dev/sdac", - "/dev/sdad", - "/dev/scd0", "/dev/scd1", "/dev/scd2", "/dev/scd3", "/dev/scd4", - "/dev/scd5", - "/dev/scd6", "/dev/scd7", "/dev/scd8", "/dev/scd9", "/dev/scd10", - "/dev/scd11", - "/dev/sr0", "/dev/sr1", "/dev/sr2", "/dev/sr3", "/dev/sr4", "/dev/sr5", - "/dev/sr6", "/dev/sr7", "/dev/sr8", "/dev/sr9", "/dev/sr10", - "/dev/sr11", - "/dev/nst0", "/dev/nst1", "/dev/nst2", "/dev/nst3", "/dev/nst4", - "/dev/nst5", - "/dev/nosst0", "/dev/nosst1", "/dev/nosst2", "/dev/nosst3", - "/dev/nosst4" -}; - -static char *page_names[] = { - NULL, - "Read-Write Error Recovery", - "Disconnect-Reconnect", - "Format Device", - "Rigid Disk Geometry", - /* "Flexible Disk" */ NULL, - NULL, - "Verify Error Recovery", - "Caching", - "Peripheral Device", - "Control Mode", - /* "Medium Types Supported" */ NULL, - "Notch and Partition", - /* "CD-ROM" */ NULL, - /* "CD-ROM Audio Control" */ NULL, - NULL, - /* "Medium Partition (1)" */ NULL, - /* "Medium Partition (2)" */ NULL, - /* "Medium Partition (3)" */ NULL, - /* "Medium Partition (4)" */ NULL -}; - -#define MAX_PAGENO (sizeof(page_names)/sizeof(char *)) - -/* Following 2 macros from D.R. Butenhof's POSIX threads book: - ISBN 0-201-63392-2 . [Highly recommended book.] */ -#define err_exit(code,text) do { \ - fprintf(stderr, "%s at \"%s\":%d: %s\n", \ - text, __FILE__, __LINE__, strerror(code)); \ - exit(1); \ - } while (0) - -static Sg_map sg_map_arr[(sizeof(devices) / sizeof(char *)) + 1]; - -static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 12, 12, 10, 10 -}; -const unsigned char rbCmdBlk[10] = { READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static const char *level_arr[LEVELS] = { "host", "bus", "target", "lun" }; - -static const char *proc_allow_dio = "/proc/scsi/sg/allow_dio"; -static const char *devfs_id = "/dev/.devfsd"; -static my_map_info_t map_arr[MAX_SG_DEVS]; -static char ebuff[EBUFF_SZ]; -static int glob_fd; -static char defectformat = 0x4; -static sigset_t signal_set; -static pthread_t sig_listen_thread_id; - -static int do_ide = 0; -static int do_inq = 1; -static int do_leaf = 1; -static int do_extra = 1; -static int do_quiet = 0; -static int checked_sg = 1; -static int sum_of_resids = 0; - -static int dd_count = -1; -static int in_full = 0; -static int in_partial = 0; -static int out_full = 0; -static int out_partial = 0; -static int do_coe = 0; -int base = READWRITE_BASE_NUM; -unsigned char *cmpbuf = 0; -static unsigned char buff_a[SIZEOF_BUFFER + SG_HSZ + 12]; -static unsigned char *buffer = buff_a + OFFSET_HEADER; - -typedef struct my_sg_scsi_id { - int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */ - int channel; - int scsi_id; /* scsi id of target device */ - int lun; - int scsi_type; /* TYPE_... defined in scsi/scsi.h */ - short h_cmd_per_lun; /* host (adapter) maximum commands per lun */ - short d_queue_depth; /* device (or adapter) maximum queue length */ - int unused1; /* probably find a good use, set 0 for now */ - int unused2; /* ditto */ -} My_sg_scsi_id; - -// Prototypes -int do_scsi_sgp_read_write(char *device); -int do_scsi_sgm_read_write(char *device); -void sg_in_operation(Rq_coll * clp, Rq_elem * rep); -void sg_out_operation(Rq_coll * clp, Rq_elem * rep); -int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks); -void normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks); -int sg_start_io(Rq_elem * rep); -int sg_finish_io(int wr, Rq_elem * rep, pthread_mutex_t * a_mutp); -int run_sg_scan_tests(void); -int show_scsi_logs(char *device); -int validate_device(char *device); -int show_devfs_devices(void); -void usage(void); -int do_scsi_device_read_write(char *device); -int do_scsi_inquiry(char *device, int hex_flag); -int show_scsi_maps(void); -int show_scsi_modes(char *device); -int do_scsi_read_buffer(char *device); -int show_scsi_read_capacity(char *device); -int do_scsi_reset_devices(char *device, int reset_opts); -int do_scsi_send_diagnostics(char *device); -int do_scsi_start_stop(char *device, int startstop); -int do_scsi_read_write_buffer(char *device); -int do_scsi_test_unit_ready(char *device); -int show_scsi_info(char *device); -void print_msg(int msg_num, const char *msg); -static void scan_dev_type(const char *leadin, int max_dev, int do_numeric, - int lin_dev_type, int last_sg_ind); - -#ifdef SG_IO -int sg3_inq(int sg_fd, unsigned char *inqBuff, int do_extra); -#endif - -static unsigned char inqCmdBlk[INQUIRY_CMDLEN] = - { 0x12, 0, 0, 0, INQ_REPLY_LEN, 0 }; - -void print_msg(int msg_num, const char *msg) -{ - switch (msg_num) { - case TEST_START: - printf - ("\n****************** Starting Tests ***************************\n"); - break; - case TEST_STOP: - printf - ("\n****************** Tests Complete ***************************\n"); - break; - case TEST_BREAK: - printf("\n------------------ %s Test ------------------\n\n", - msg); - break; - } -} - -int main(int argc, char *argv[]) -{ - int rc = 0; - - if (argc < 2) { - printf("\n\nERROR:No device passed to test\n\n"); - usage(); - return 1; - } - - rc = validate_device(argv[1]); - if (rc == 0) { - - print_msg(TEST_START, NULL); - - rc = run_sg_scan_tests(); - if (rc != 0) { - printf("ERROR: run_sg_scan_tests failed %d\n", rc); - } - - rc = show_scsi_logs(argv[1]); - if (rc != 0) { - printf("ERROR: show_scsi_logs failed %d\n", rc); - } - - rc = show_devfs_devices(); - if (rc != 0) { - printf("ERROR: show_devfs_devices failed %d\n", rc); - } - - rc = do_scsi_device_read_write(argv[1]); - if (rc != 0) { - printf("ERROR: do_scsi_devices_read_write failed %d\n", - rc); - } - - rc = do_scsi_inquiry(argv[1], TRUE); - if (rc != 0) { - printf("ERROR: do_scsi_inquiry HEX failed %d\n", rc); - } else { - rc = do_scsi_inquiry(argv[1], FALSE); - if (rc != 0) { - printf("ERROR: do_scsi_inquiry PCI failed %d\n", - rc); - } - } - - rc = show_scsi_maps(); - if (rc != 0) { - printf("ERROR: show_scsi_maps failed %d\n", rc); - } - - rc = show_scsi_modes(argv[1]); - if (rc != 0) { - printf("ERROR: show_scsi_modes failed %d\n", rc); - } - - rc = do_scsi_read_buffer(argv[1]); - if (rc != 0 && rc != 1) { - printf("ERROR: do_scsi_read_buffer failed %d\n", rc); - } - - rc = show_scsi_read_capacity(argv[1]); - if (rc != 0) { - printf("ERROR: show_scsi_read_capacity failed %d\n", - rc); - } - - rc |= do_scsi_reset_devices(argv[1], DEVICE_RESET); - rc |= do_scsi_reset_devices(argv[1], BUS_RESET); - rc |= do_scsi_reset_devices(argv[1], HOST_RESET); - if (rc != 0) { - printf("ERROR: do_scsi_reset_devices failed %d\n", rc); - } - - rc = do_scsi_send_diagnostics(argv[1]); - if (rc != 0) { - printf("ERROR: do_scsi_send_diagnostics failed %d\n", - rc); - } - - rc |= do_scsi_start_stop(argv[1], FALSE); - rc |= do_scsi_start_stop(argv[1], TRUE); - if (rc != 0) { - printf("ERROR: do_scsi_start_top failed %d\n", rc); - } - - rc = do_scsi_read_write_buffer(argv[1]); - if (rc != 0 && rc != 1) { - printf("ERROR: do_scsi_read_write_buffer failed %d\n", - rc); - } - - rc = do_scsi_test_unit_ready(argv[1]); - if (rc != 0) { - printf("ERROR: do_scsi_test_unit_ready failed %d\n", - rc); - } - - rc = show_scsi_info(argv[1]); - if (rc != 0) { - printf("ERROR: show_scsi_info failed %d\n", rc); - } - - rc = do_scsi_sgp_read_write(argv[1]); - if (rc != 0) { - printf("ERROR: do_scsi_sgp_read_write failed %d\n", rc); - } - - rc = do_scsi_sgm_read_write(argv[1]); - if (rc != 0) { - printf("ERROR: do_scsi_sgm_read_write failed %d\n", rc); - } - - print_msg(TEST_STOP, NULL); - } else { - printf("\nERROR: Invalid device passed to test\n\n\n"); - usage(); - - } - - return 0; -} - -int validate_device(char *device) -{ - int rc = 0; - int i, found = FALSE; - char device_string[25]; - - for (i = 0; i < MAX_DEVICES && !found; i++) { - sprintf(device_string, "/dev/sg%d", i); - //printf("checking %s \n", device_string); - if (strcmp(device, device_string) == 0) { - found = TRUE; - } - } - - return rc; -} - -void usage() -{ - printf("Usage: 'sg_scan [-a] [-n] [-w] [-i] [-x]'\n"); - printf(" where: -a do alpha scan (ie sga, sgb, sgc)\n"); - printf(" -n do numeric scan (ie sg0, sg1...) [default]\n"); - printf(" -w force open with read/write flag\n"); - printf(" -i do SCSI INQUIRY, output results\n"); - printf(" -x extra information output about queuing\n\n\n"); -} - -void make_dev_name(char *fname, const char *leadin, int k, int do_numeric) -{ - char buff[64]; - int big, little; - - strcpy(fname, leadin ? leadin : "/dev/sg"); - if (do_numeric) { - sprintf(buff, "%d", k); - strcat(fname, buff); - } else { - if (k < 26) { - buff[0] = 'a' + (char)k; - buff[1] = '\0'; - strcat(fname, buff); - } else if (k <= 255) { /* assumes sequence goes x,y,z,aa,ab,ac etc */ - big = k / 26; - little = k - (26 * big); - big = big - 1; - - buff[0] = 'a' + (char)big; - buff[1] = 'a' + (char)little; - buff[2] = '\0'; - strcat(fname, buff); - } else - strcat(fname, "xxxx"); - } -} - -int run_sg_scan_tests() -{ - int sg_fd, res, k, f; - unsigned char inqBuff[OFF + INQ_REPLY_LEN]; - int inqInLen = OFF + sizeof(inqCmdBlk); - int inqOutLen = OFF + INQ_REPLY_LEN; - unsigned char *buffp = inqBuff + OFF; - struct sg_header *isghp = (struct sg_header *)inqBuff; - int do_numeric = NUMERIC_SCAN_DEF; - int do_inquiry = 0; - int do_extra = 1; - int writeable = 0; - int num_errors = 0; - int num_silent = 0; - int eacces_err = 0; - char fname[64]; - My_scsi_idlun my_idlun; - int host_no; - int flags; - int emul; - - print_msg(TEST_BREAK, __FUNCTION__); - - flags = writeable ? O_RDWR : OPEN_FLAG; - - do_numeric = 1; - writeable = O_RDONLY; - do_inquiry = 1; - do_extra = 1; - - for (k = 0, res = 0; (k < 1000) && (num_errors < MAX_ERRORS); - ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, ME "Error closing %s ", - fname); - perror(ME "close error"); - return 1; - } - make_dev_name(fname, NULL, k, do_numeric); - - sg_fd = open(fname, flags | O_NONBLOCK); - if (sg_fd < 0) { - if (EBUSY == errno) { - printf - ("%s: device busy (O_EXCL lock), skipping\n", - fname); - continue; - } else if ((ENODEV == errno) || (ENOENT == errno) || - (ENXIO == errno)) { - ++num_errors; - ++num_silent; - continue; - } else { - if (EACCES == errno) - eacces_err = 1; - snprintf(ebuff, EBUFF_SZ, - ME "Error opening %s ", fname); - perror(ebuff); - ++num_errors; - continue; - } - } - res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "device %s failed on scsi ioctl, skip", - fname); - perror(ebuff); - ++num_errors; - continue; - } - res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, ME "device %s failed on scsi " - "ioctl(2), skip", fname); - perror(ebuff); - ++num_errors; - continue; - } -#ifdef SG_EMULATED_HOST - res = ioctl(sg_fd, SG_EMULATED_HOST, &emul); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "device %s failed on sg ioctl(3), skip", - fname); - perror(ebuff); - ++num_errors; - continue; - } -#else - emul = 0; -#endif - printf("%s: scsi%d channel=%d id=%d lun=%d", fname, host_no, - (my_idlun.dev_id >> 16) & 0xff, my_idlun.dev_id & 0xff, - (my_idlun.dev_id >> 8) & 0xff); - if (emul) - printf(" [em]"); -#if 0 - printf(", huid=%d", my_idlun.host_unique_id); -#endif -#ifdef SG_GET_RESERVED_SIZE - { - My_sg_scsi_id m_id; /* compatible with sg_scsi_id_t in sg.h */ - - res = ioctl(sg_fd, SG_GET_SCSI_ID, &m_id); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "device %s ioctls(4), skip", fname); - perror(ebuff); - ++num_errors; - continue; - } - printf(" type=%d", m_id.scsi_type); - if (do_extra) - printf(" cmd_per_lun=%hd queue_depth=%hd\n", - m_id.h_cmd_per_lun, m_id.d_queue_depth); - else - printf("\n"); - } -#else - printf("\n"); -#endif - if (!do_inquiry) - continue; - -#ifdef SG_IO - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &f) >= 0) && (f >= 30000)) { - res = sg3_inq(sg_fd, inqBuff, do_extra); - continue; - } -#endif - memset(isghp, 0, sizeof(struct sg_header)); - isghp->reply_len = inqOutLen; - memcpy(inqBuff + OFF, inqCmdBlk, INQUIRY_CMDLEN); - - if (O_RDWR == (flags & O_ACCMODE)) { /* turn on blocking */ - f = fcntl(sg_fd, F_GETFL); - fcntl(sg_fd, F_SETFL, f & (~O_NONBLOCK)); - } else { - close(sg_fd); - sg_fd = open(fname, O_RDWR); - } - - res = write(sg_fd, inqBuff, inqInLen); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, ME "device %s writing, skip", - fname); - perror(ebuff); - ++num_errors; - continue; - } - res = read(sg_fd, inqBuff, inqOutLen); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, ME "device %s reading, skip", - fname); - perror(ebuff); - ++num_errors; - continue; - } -#ifdef SG_GET_RESERVED_SIZE - if (!sg_chk_n_print("Error from Inquiry", isghp->target_status, - isghp->host_status, isghp->driver_status, - isghp->sense_buffer, SG_MAX_SENSE)) - continue; -#else - if ((isghp->result != 0) || (0 != isghp->sense_buffer[0])) { - printf("Error from Inquiry: result=%d\n", - isghp->result); - if (0 != isghp->sense_buffer[0]) - sg_print_sense("Error from Inquiry", - isghp->sense_buffer, - SG_MAX_SENSE); - continue; - } -#endif - f = (int)*(buffp + 7); - printf(" %.8s %.16s %.4s ", buffp + 8, buffp + 16, - buffp + 32); - printf("[wide=%d sync=%d cmdq=%d sftre=%d pq=0x%x]\n", - ! !(f & 0x20), ! !(f & 0x10), ! !(f & 2), ! !(f & 1), - (*buffp & 0xe0) >> 5); - } - if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors)) { - printf("Stopping because there are too many error\n"); - if (eacces_err) - printf(" root access may be required\n"); - } - return 0; -} - -#ifdef SG_IO -int sg3_inq(int sg_fd, unsigned char *inqBuff, int do_extra) -{ - sg_io_hdr_t io_hdr; - unsigned char sense_buffer[32]; - int ok; - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(inqCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_buffer); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = INQ_REPLY_LEN; - io_hdr.dxferp = inqBuff; - io_hdr.cmdp = inqCmdBlk; - io_hdr.sbp = sense_buffer; - io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror(ME "Inquiry SG_IO ioctl error"); - return 1; - } - - /* now for the error processing */ - ok = 0; - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - ok = 1; - break; - default: /* won't bother decoding other categories */ - sg_chk_n_print3("INQUIRY command error", &io_hdr); - break; - } - - if (ok) { /* output result if it is available */ - char *p = (char *)inqBuff; - int f = (int)*(p + 7); - printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); - printf("[wide=%d sync=%d cmdq=%d sftre=%d pq=0x%x] ", - ! !(f & 0x20), ! !(f & 0x10), ! !(f & 2), ! !(f & 1), - (*p & 0xe0) >> 5); - if (do_extra) - printf("dur=%ums\n", io_hdr.duration); - else - printf("\n"); - } - return 0; -} -#endif - -static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code, - int paramp, void *resp, int mx_resp_len, int noisy) -{ - int res; - unsigned char logsCmdBlk[LOG_SENSE_CMDLEN] = - { LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - logsCmdBlk[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0)); - logsCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); - logsCmdBlk[5] = (unsigned char)((paramp >> 8) & 0xff); - logsCmdBlk[6] = (unsigned char)(paramp & 0xff); - if (mx_resp_len > 0xffff) { - printf(ME "mx_resp_len too big\n"); - return -1; - } - logsCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); - logsCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(logsCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = logsCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (log sense) error"); - return -1; - } -#if 0 - printf("SG_IO ioctl: status=%d, info=%d, sb_len_wr=%d\n", - io_hdr.status, io_hdr.info, io_hdr.sb_len_wr); -#endif - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, ME "ppc=%d, sp=%d, " - "pc=%d, page_code=%x, paramp=%x\n ", ppc, - sp, pc, pg_code, paramp); - sg_chk_n_print3(ebuff, &io_hdr); - } - return -1; - } -} - -static void dStrHex(const char *str, int len, int no_ascii) -{ - const char *p = str; - unsigned char c; - char buff[82]; - int a = 0; - const int bpstart = 5; - const int cpstart = 60; - int cpos = cpstart; - int bpos = bpstart; - int i, k; - - if (len <= 0) - return; - memset(buff, ' ', 80); - buff[80] = '\0'; - k = sprintf(buff + 1, "%.2x", a); - buff[k + 1] = ' '; - if (bpos >= ((bpstart + (9 * 3)))) - bpos++; - - for (i = 0; i < len; i++) { - c = *p++; - bpos += 3; - if (bpos == (bpstart + (9 * 3))) - bpos++; - sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); - buff[bpos + 2] = ' '; - if (no_ascii) - buff[cpos++] = ' '; - else { - if ((c < ' ') || (c >= 0x7f)) - c = '.'; - buff[cpos++] = c; - } - if (cpos > (cpstart + 15)) { - printf("%s\n", buff); - bpos = bpstart; - cpos = cpstart; - a += 16; - memset(buff, ' ', 80); - k = sprintf(buff + 1, "%.2x", a); - buff[k + 1] = ' '; - } - } - if (cpos > cpstart) { - printf("%s\n", buff); - } -} - -static void show_page_name(int page_no) -{ - switch (page_no) { - case 0x0: - printf(" 0x00 Supported log pages\n"); - break; - case 0x1: - printf(" 0x01 Buffer over-run/under-run\n"); - break; - case 0x2: - printf(" 0x02 Error counters (write)\n"); - break; - case 0x3: - printf(" 0x03 Error counters (read)\n"); - break; - case 0x4: - printf(" 0x04 Error counters (read reverse)\n"); - break; - case 0x5: - printf(" 0x05 Error counters (verify)\n"); - break; - case 0x6: - printf(" 0x06 Non-medium errors\n"); - break; - case 0x7: - printf(" 0x07 Last n error events\n"); - break; - case 0x8: - printf(" 0x08 Format status (sbc2)\n"); - break; - case 0xb: - printf(" 0x0b Last n deferred errors of " - "asynchronous events\n"); - break; - case 0xc: - printf(" 0x0c Sequential Access (ssc-2)\n"); - break; - case 0xd: - printf(" 0x0d Temperature\n"); - break; - case 0xe: - printf(" 0x0e Start-stop cycle counter\n"); - break; - case 0xf: - printf(" 0x0f Application client\n"); - break; - case 0x10: - printf(" 0x10 Self-test results\n"); - break; - case 0x18: - printf(" 0x18 Protocol specific port\n"); - break; - case 0x2e: - printf(" 0x2e Tape alerts (ssc-2)\n"); - break; - case 0x2f: - printf(" 0x2f Informational exceptions (SMART)\n"); - break; - default: - printf(" 0x%.2x\n", page_no); - break; - } -} - -static void show_buffer_under_overrun_page(unsigned char *resp, int len) -{ - int k, j, num, pl, count_basis, cause; - unsigned char *ucp; - unsigned char *xp; - unsigned long long ull; - - printf("Buffer over-run/under-run page\n"); - num = len - 4; - ucp = &resp[0] + 4; - while (num > 3) { - pl = ucp[3] + 4; - count_basis = (ucp[1] >> 5) & 0x7; - printf(" Count basis: "); - switch (count_basis) { - case 0: - printf("undefined"); - break; - case 1: - printf("per command"); - break; - case 2: - printf("per failed reconnect"); - break; - case 3: - printf("per unit of time"); - break; - default: - printf("reserved [0x%x]", count_basis); - break; - } - cause = (ucp[1] >> 1) & 0xf; - printf(", Cause: "); - switch (cause) { - case 0: - printf("bus busy"); - break; - case 1: - printf("transfer rate too slow"); - break; - default: - printf("reserved [0x%x]", cause); - break; - } - printf(", Type: "); - if (ucp[1] & 1) - printf("over-run"); - else - printf("under-run"); - printf(", count"); - k = pl - 4; - xp = ucp + 4; - if (k > sizeof(ull)) { - xp += (k - sizeof(ull)); - k = sizeof(ull); - } - ull = 0; - for (j = 0; j < k; ++j) { - if (j > 0) - ull <<= 8; - ull |= xp[j]; - } - printf(" = %llu\n", ull); - num -= pl; - ucp += pl; - } -} - -static void show_error_counter_page(unsigned char *resp, int len) -{ - int k, j, num, pl, pc; - unsigned char *ucp; - unsigned char *xp; - unsigned long long ull; - - switch (resp[0]) { - case 2: - printf("Write error counter page\n"); - break; - case 3: - printf("Read error counter page\n"); - break; - case 4: - printf("Read Reverse error counter page\n"); - break; - case 5: - printf("Verify error counter page\n"); - break; - default: - printf("expecting error counter page, got page=0x%x\n", - resp[0]); - return; - } - num = len - 4; - ucp = &resp[0] + 4; - while (num > 3) { - pc = (ucp[0] << 8) | ucp[1]; - pl = ucp[3] + 4; - switch (pc) { - case 0: - printf(" Errors corrected without substantion delay"); - break; - case 1: - printf(" Errors corrected with possible delays"); - break; - case 2: - printf(" Total operations"); - break; - case 3: - printf(" Total errors corrected"); - break; - case 4: - printf(" Total times correction algorithm processed"); - break; - case 5: - printf(" Total bytes processed"); - break; - case 6: - printf(" Total uncorrected errors"); - break; - default: - printf(" Reserved or vendor specific [0x%x]", pc); - break; - } - k = pl - 4; - xp = ucp + 4; - if (k > sizeof(ull)) { - xp += (k - sizeof(ull)); - k = sizeof(ull); - } - ull = 0; - for (j = 0; j < k; ++j) { - if (j > 0) - ull <<= 8; - ull |= xp[j]; - } - printf(" = %llu\n", ull); - num -= pl; - ucp += pl; - } -} - -static void show_non_medium_error_page(unsigned char *resp, int len) -{ - int k, j, num, pl, pc; - unsigned char *ucp; - unsigned char *xp; - unsigned long long ull; - - printf("Non-medium error page\n"); - num = len - 4; - ucp = &resp[0] + 4; - while (num > 3) { - pc = (ucp[0] << 8) | ucp[1]; - pl = ucp[3] + 4; - switch (pc) { - case 0: - printf(" Non-medium error count"); - break; - default: - if (pc <= 0x7fff) - printf(" Reserved [0x%x]", pc); - else - printf(" Vendor specific [0x%x]", pc); - break; - } - k = pl - 4; - xp = ucp + 4; - if (k > sizeof(ull)) { - xp += (k - sizeof(ull)); - k = sizeof(ull); - } - ull = 0; - for (j = 0; j < k; ++j) { - if (j > 0) - ull <<= 8; - ull |= xp[j]; - } - printf(" = %llu\n", ull); - num -= pl; - ucp += pl; - } -} - -const char *self_test_code[] = { - "default", "background short", "background extended", "reserved", - "aborted background", "foreground short", "foreground extended", - "reserved" -}; - -const char *self_test_result[] = { - "completed without error", - "aborted by SEND DIAGNOSTIC", - "aborted other than by SEND DIAGNOSTIC", - "unknown error, unable to complete", - "self test completed with failure in test segment (which one unkown)", - "first segment in self test failed", - "second segment in self test failed", - "another segment in self test failed", - "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", - "reserved", - "self test in progress" -}; - -static void show_self_test_page(unsigned char *resp, int len) -{ - int k, num, n, res; - unsigned char *ucp; - unsigned long long ull; - - num = len - 4; - if (num < 0x190) { - printf("badly formed self-test results page\n"); - return; - } - printf("Self-test results page\n"); - for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20) { - n = (ucp[6] << 8) | ucp[7]; - if ((0 == n) && (0 == ucp[4])) - break; - printf(" Parameter code=%d, accumulated power-on hours=%d\n", - (ucp[0] << 8) | ucp[1], n); - printf(" self test code: %s [%d]\n", - self_test_code[(ucp[4] >> 5) & 0x7], - (ucp[4] >> 5) & 0x7); - res = ucp[4] & 0xf; - printf(" self test result: %s [%d]\n", - self_test_result[res], res); - if (ucp[5]) - printf(" self-test number=%d\n", (int)ucp[5]); - ull = ucp[8]; - ull <<= 8; - ull |= ucp[9]; - ull <<= 8; - ull |= ucp[10]; - ull <<= 8; - ull |= ucp[11]; - ull <<= 8; - ull |= ucp[12]; - ull <<= 8; - ull |= ucp[13]; - ull <<= 8; - ull |= ucp[14]; - ull <<= 8; - ull |= ucp[14]; - ull <<= 8; - ull |= ucp[15]; - if ((0xffffffffffffffffULL != ull) && (res > 0) && (res < 0xf)) - printf(" address of first error=0x%llx\n", ull); - if (ucp[16] & 0xf) - printf(" sense key=0x%x, asc=0x%x, asq=0x%x\n", - ucp[16] & 0xf, ucp[17], ucp[18]); - } -} - -static void show_Temperature_page(unsigned char *resp, int len, int hdr) -{ - int k, num, extra, pc; - unsigned char *ucp; - - num = len - 4; - ucp = &resp[0] + 4; - if (num < 4) { - printf("badly formed Temperature log page\n"); - return; - } - if (hdr) - printf("Temperature log page\n"); - for (k = num; k > 0; k -= extra, ucp += extra) { - if (k < 3) { - printf("short Temperature log page\n"); - return; - } - extra = ucp[3] + 4; - pc = ((ucp[0] << 8) & 0xff) + ucp[1]; - if (0 == pc) { - if (extra > 5) { - if (ucp[5] < 0xff) - printf(" Current temperature= %d C\n", - ucp[5]); - else - printf - (" Current temperature=<not available>\n"); - } - } else if (1 == pc) { - if (extra > 5) { - if (ucp[5] < 0xff) - printf - (" Reference temperature= %d C\n", - ucp[5]); - else - printf - (" Reference temperature=<not available>\n"); - } - - } else { - printf(" parameter code=0x%x, contents in hex:\n", pc); - dStrHex((const char *)ucp, extra, 1); - } - } -} - -static void show_IE_page(unsigned char *resp, int len, int full) -{ - int k, num, extra, pc; - unsigned char *ucp; - - num = len - 4; - ucp = &resp[0] + 4; - if (num < 4) { - printf("badly formed Informational Exceptions log page\n"); - return; - } - if (full) - printf("Informational Exceptions log page\n"); - for (k = num; k > 0; k -= extra, ucp += extra) { - if (k < 3) { - printf("short Informational Exceptions log page\n"); - return; - } - extra = ucp[3] + 4; - pc = ((ucp[0] << 8) & 0xff) + ucp[1]; - if (0 == pc) { - if (extra > 5) { - if (full) - printf(" IE asc=0x%x, ascq=0x%x", - ucp[4], ucp[5]); - if (extra > 6) { - if (full) - printf(","); - if (ucp[6] < 0xff) - printf - (" Current temperature=%d C", - ucp[6]); - else - printf - (" Current temperature=<not available>"); - } - printf("\n"); - } - } else if (full) { - printf(" parameter code=0x%x, contents in hex:\n", pc); - dStrHex((const char *)ucp, extra, 1); - } - } -} - -static void show_ascii_page(unsigned char *resp, int len) -{ - int k, n, num; - - if (len < 0) { - printf("response has bad length\n"); - return; - } - num = len - 4; - switch (resp[0]) { - case 0: - printf("Supported pages:\n"); - for (k = 0; k < num; ++k) - show_page_name((int)resp[4 + k]); - break; - case 0x1: - show_buffer_under_overrun_page(resp, len); - break; - case 0x2: - case 0x3: - case 0x4: - case 0x5: - show_error_counter_page(resp, len); - break; - case 0x6: - show_non_medium_error_page(resp, len); - break; - case 0xd: - show_Temperature_page(resp, len, 1); - break; - case 0xe: - if (len < 40) { - printf("badly formed start-stop cycle counter page\n"); - break; - } - printf("Start-stop cycle counter page\n"); - printf(" Date of manufacture, year: %.4s, week: %.2s\n", - &resp[8], &resp[12]); - printf(" Accounting date, year: %.4s, week: %.2s\n", - &resp[18], &resp[22]); - n = (resp[28] << 24) | (resp[29] << 16) | (resp[30] << 8) | - resp[31]; - printf(" Specified cycle count over device lifetime=%d\n", n); - n = (resp[36] << 24) | (resp[37] << 16) | (resp[38] << 8) | - resp[39]; - printf(" Accumulated start-stop cycles=%d\n", n); - break; - case 0x10: - show_self_test_page(resp, len); - break; - case 0x2f: - show_IE_page(resp, len, 1); - break; - default: - printf("No ascii information for page=0x%x, here is hex:\n", - resp[0]); - dStrHex((const char *)resp, len, 1); - break; - } -} - -static int fetchTemperature(int sg_fd, int do_hex, unsigned char *resp, - int max_len) -{ - int res = 0; - - if (0 == do_logs(sg_fd, 0, 0, 1, 0xd, 0, resp, max_len, 0)) - show_Temperature_page(resp, (resp[2] << 8) + resp[3] + 4, 0); - else if (0 == do_logs(sg_fd, 0, 0, 1, 0x2f, 0, resp, max_len, 0)) - show_IE_page(resp, (resp[2] << 8) + resp[3] + 4, 0); - else { - printf - ("Unable to find temperature in either log page (temperature " - "or IE)\n"); - res = 1; - } - close(sg_fd); - return res; -} - -int show_scsi_logs(char *device) -{ - int sg_fd, k, pg_len; - char *file_name = 0; - unsigned char rsp_buff[MX_ALLOC_LEN]; - int pg_code = 0; - int pc = 1; /* N.B. some disks only give data for current cumulative */ - int paramp = 0; - int do_list = 0; - int do_ppc = 0; - int do_sp = 0; - int do_hex = 0; - int do_all = 1; - int do_temp = 0; - int oflags = O_RDWR | O_NONBLOCK; - - file_name = device; - print_msg(TEST_BREAK, __FUNCTION__); - - if ((sg_fd = open(file_name, oflags)) < 0) { - snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", - file_name); - perror(ebuff); - return 1; - } - /* Just to be safe, check we have a new sg device by trying an ioctl */ - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { - printf(ME "%s doesn't seem to be a version 3 sg device\n", - file_name); - close(sg_fd); - return 1; - } - if (do_list || do_all) - pg_code = PG_CODE_ALL; - pg_len = 0; - if (1 == do_temp) - return fetchTemperature(sg_fd, do_hex, rsp_buff, MX_ALLOC_LEN); - - if (0 == do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, paramp, - rsp_buff, MX_ALLOC_LEN, 1)) { - pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; - if ((pg_len + 4) > MX_ALLOC_LEN) { - printf - ("Only fetched %d bytes of response, truncate output\n", - MX_ALLOC_LEN); - pg_len = MX_ALLOC_LEN - 4; - } - if (do_hex) { - printf("Returned log page code=0x%x, page len=0x%x\n", - rsp_buff[0], pg_len); - dStrHex((const char *)rsp_buff, pg_len + 4, 1); - } else - show_ascii_page(rsp_buff, pg_len + 4); - } - if (do_all && (pg_len > 1)) { - int my_len = pg_len - 1; - unsigned char parr[256]; - - memcpy(parr, rsp_buff + 5, my_len); - for (k = 0; k < my_len; ++k) { - printf("\n"); - pg_code = parr[k]; - if (0 == - do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, paramp, - rsp_buff, MX_ALLOC_LEN, 1)) { - pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; - if ((pg_len + 4) > MX_ALLOC_LEN) { - printf - ("Only fetched %d bytes of response, truncate " - "output\n", MX_ALLOC_LEN); - pg_len = MX_ALLOC_LEN - 4; - } - if (do_hex) { - printf - ("Returned log page code=0x%x, page len=0x%x\n", - rsp_buff[0], pg_len); - dStrHex((const char *)rsp_buff, - pg_len + 4, 1); - } else - show_ascii_page(rsp_buff, pg_len + 4); - } - } - } - close(sg_fd); - return 0; -} - -static int do_inquiry(int sg_fd, void *resp, int mx_resp_len) -{ - int res; - unsigned char inqCmdBlk[INQUIRY_CMDLEN] = - { INQUIRY_CMD, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - inqCmdBlk[4] = (unsigned char)mx_resp_len; - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(inqCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_TO_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = inqCmdBlk; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (inquiry) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - sg_chk_n_print3("Failed INQUIRY", &io_hdr); - return -1; - } -} - -void leaf_dir(const char *lf, unsigned int *larr) -{ - char name[NAME_LEN_MAX * 2]; - int res; - - if (do_quiet) { - printf("%u\t%u\t%u\t%u\n", larr[0], larr[1], larr[2], larr[3]); - return; - } - printf("%u\t%u\t%u\t%u\t%s\n", larr[0], larr[1], larr[2], larr[3], lf); - if (do_leaf) { - struct dirent *de_entry; - struct dirent *de_result; - DIR *sdir; - int outpos; - - if (NULL == (sdir = opendir(lf))) { - fprintf(stderr, "leaf_dir: opendir of %s: failed\n", - lf); - return; - } - de_entry = malloc(sizeof(struct dirent) + NAME_LEN_MAX); - if (NULL == de_entry) - return; - res = 0; - printf("\t"); - outpos = 8; - while (1) { - res = readdir_r(sdir, de_entry, &de_result); - if (0 != res) { - fprintf(stderr, - "leaf_dir: readdir_r of %s: %s\n", lf, - strerror(res)); - res = -2; - break; - } - if (de_result == NULL) - break; - strncpy(name, de_entry->d_name, NAME_LEN_MAX * 2); - if ((0 == strcmp("..", name)) - || (0 == strcmp(".", name))) - continue; - if (do_extra) { - struct stat st; - char devname[NAME_LEN_MAX * 2]; - - strncpy(devname, lf, NAME_LEN_MAX * 2); - strcat(devname, "/"); - strcat(devname, name); - if (stat(devname, &st) < 0) - return; - if (S_ISCHR(st.st_mode)) { - strcat(name, "(c "); - sprintf(name + strlen(name), "%d %d)", - major(st.st_rdev), - minor(st.st_rdev)); - } else if (S_ISBLK(st.st_mode)) { - strcat(name, "(b "); - sprintf(name + strlen(name), "%d %d)", - major(st.st_rdev), - minor(st.st_rdev)); - } - } - res = strlen(name); - if ((outpos + res + 2) > 80) { - printf("\n\t"); - outpos = 8; - } - printf("%s ", name); - outpos += res + 2; - } - printf("\n"); - } - if (do_inq) { - int sg_fd; - char buff[64]; - - memset(buff, 0, sizeof(buff)); - strncpy(name, lf, NAME_LEN_MAX * 2); - strcat(name, "/generic"); - if ((sg_fd = open(name, O_RDONLY)) < 0) { - if (!checked_sg) { - checked_sg = 1; - if ((sg_fd = open("/dev/sg0", O_RDONLY)) >= 0) - close(sg_fd); /* try and get sg module loaded */ - sg_fd = open(name, O_RDONLY); - } - if (sg_fd < 0) { - printf("Unable to open sg device: %s, %s\n", - name, strerror(errno)); - return; - } - } - if (0 != do_inquiry(sg_fd, buff, 64)) - return; - close(sg_fd); - dStrHex(buff, 64, 0); - } -} - -/* Return 0 -> ok, -1 -> opendir() error, -2 -> readdir_r error, - -3 -> malloc error */ -int hbtl_scan(const char *path, int level, unsigned int *larr) -{ - struct dirent *de_entry; - struct dirent *de_result; - char new_path[NAME_LEN_MAX * 2]; - DIR *sdir; - int res; - size_t level_slen; - - level_slen = strlen(level_arr[level]); - if (NULL == (sdir = opendir(path))) { - fprintf(stderr, "hbtl_scan: opendir of %s: failed\n", path); - return -1; - } - de_entry = malloc(sizeof(struct dirent) + NAME_LEN_MAX); - if (NULL == de_entry) - return -3; - res = 0; - while (1) { - res = readdir_r(sdir, de_entry, &de_result); - if (0 != res) { - fprintf(stderr, "hbtl_scan: readdir_r of %s: %s\n", - path, strerror(res)); - res = -2; - break; - } - if (de_result == NULL) - break; - if (0 == - strncmp(level_arr[level], de_entry->d_name, level_slen)) { - if (1 != - sscanf(de_entry->d_name + level_slen, "%u", - larr + level)) - larr[level] = UINT_MAX; - strncpy(new_path, path, NAME_LEN_MAX * 2); - strcat(new_path, "/"); - strcat(new_path, de_entry->d_name); - if ((level + 1) < LEVELS) { - res = hbtl_scan(new_path, level + 1, larr); - if (res < 0) - break; - } else - leaf_dir(new_path, larr); - } - } - free(de_entry); - closedir(sdir); - return res; -} - -int show_devfs_devices() -{ - int res; - char ds_root[D_ROOT_SZ]; - char di_root[D_ROOT_SZ]; - unsigned int larr[LEVELS]; - struct stat st; - - print_msg(TEST_BREAK, __FUNCTION__); - strncpy(ds_root, "/dev", D_ROOT_SZ); - - strncpy(di_root, ds_root, D_ROOT_SZ); - - strcat(di_root, "/.devfsd"); - - if (stat(di_root, &st) < 0) { - printf("Didn't find %s so perhaps devfs is not present," - " attempting to continue ...\n", di_root); - } - - strncpy(di_root, ds_root, D_ROOT_SZ); - strcat(ds_root, "/scsi"); - strcat(di_root, "/ide"); - - if (!do_ide) - printf("SCSI scan:\n"); - - res = hbtl_scan(ds_root, 0, larr); - - if (res < 0) - printf("main: scsi hbtl_scan res=%d\n", res); - - do_ide = TRUE; - do_inq = 0; /* won't try SCSI INQUIRY on IDE devices */ - - if (do_ide) { - printf("\nIDE scan:\n"); - res = hbtl_scan(di_root, 0, larr); - - if (res < 0) - printf("main: ide hbtl_scan res=%d\n", res); - } - return 0; -} - -static void install_handler(int sig_num, void (*sig_handler) (int sig)) -{ - struct sigaction sigact; - sigaction(sig_num, NULL, &sigact); - if (sigact.sa_handler != SIG_IGN) { - sigact.sa_handler = sig_handler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(sig_num, &sigact, NULL); - } -} - -void print_stats() -{ - if (0 != dd_count) - fprintf(stderr, " remaining block count=%d\n", dd_count); - fprintf(stderr, "%d+%d records in\n", in_full - in_partial, in_partial); - fprintf(stderr, "%d+%d records out\n", out_full - out_partial, - out_partial); -} - -static void interrupt_handler(int sig) -{ - struct sigaction sigact; - - sigact.sa_handler = SIG_DFL; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(sig, &sigact, NULL); - fprintf(stderr, "Interrupted by signal,"); - print_stats(); - kill(getpid(), sig); -} - -static void siginfo_handler(int sig) -{ - fprintf(stderr, "Progress report, continuing ...\n"); - print_stats(); -} - -int dd_filetype(const char *filename) -{ - struct stat st; - size_t len = strlen(filename); - - if ((1 == len) && ('.' == filename[0])) - return FT_DEV_NULL; - if (stat(filename, &st) < 0) - return FT_OTHER; - if (S_ISCHR(st.st_mode)) { - if ((MEM_MAJOR == major(st.st_rdev)) && - (DEV_NULL_MINOR_NUM == minor(st.st_rdev))) - return FT_DEV_NULL; - if (RAW_MAJOR == major(st.st_rdev)) - return FT_RAW; - if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) - return FT_SG; - if (SCSI_TAPE_MAJOR == major(st.st_rdev)) - return FT_ST; - } else if (S_ISBLK(st.st_mode)) - return FT_BLOCK; - return FT_OTHER; -} - -int read_capacity(int sg_fd, int *num_sect, int *sect_sz) -{ - int res; - unsigned char rcCmdBlk[10] = - { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char rcBuff[READ_CAP_REPLY_LEN]; - unsigned char sense_b[64]; - sg_io_hdr_t io_hdr; - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(rcCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = sizeof(rcBuff); - io_hdr.dxferp = rcBuff; - io_hdr.cmdp = rcCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("read_capacity (SG_IO) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - if (SG_ERR_CAT_MEDIA_CHANGED == res) - return 2; /* probably have another go ... */ - else if (SG_ERR_CAT_CLEAN != res) { - sg_chk_n_print3("read capacity", &io_hdr); - return -1; - } - *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) | - (rcBuff[2] << 8) | rcBuff[3]); - *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | - (rcBuff[6] << 8) | rcBuff[7]; - return 0; -} - -/* Return of 0 -> success, -1 -> failure, 2 -> try again */ -int sync_cache(int sg_fd) -{ - int res; - unsigned char scCmdBlk[10] = { SYNCHRONIZE_CACHE, 0, 0, 0, 0, 0, 0, - 0, 0, 0 - }; - unsigned char sense_b[64]; - sg_io_hdr_t io_hdr; - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(scCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_NONE; - io_hdr.dxfer_len = 0; - io_hdr.dxferp = NULL; - io_hdr.cmdp = scCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("synchronize_cache (SG_IO) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - if (SG_ERR_CAT_MEDIA_CHANGED == res) - return 2; /* probably have another go ... */ - else if (SG_ERR_CAT_CLEAN != res) { - sg_chk_n_print3("synchronize cache", &io_hdr); - return -1; - } - return 0; -} - -int sg_build_scsi_cdb(unsigned char *cdbp, int cdb_sz, unsigned int blocks, - unsigned int start_block, int write_true, int fua, - int dpo) -{ - int rd_opcode[] = { 0x8, 0x28, 0xa8, 0x88 }; - int wr_opcode[] = { 0xa, 0x2a, 0xaa, 0x8a }; - int sz_ind; - - memset(cdbp, 0, cdb_sz); - if (dpo) - cdbp[1] |= 0x10; - if (fua) - cdbp[1] |= 0x8; - switch (cdb_sz) { - case 6: - sz_ind = 0; - cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : - rd_opcode[sz_ind]); - cdbp[1] = (unsigned char)((start_block >> 16) & 0x1f); - cdbp[2] = (unsigned char)((start_block >> 8) & 0xff); - cdbp[3] = (unsigned char)(start_block & 0xff); - cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks; - if (blocks > 256) { - fprintf(stderr, - ME "for 6 byte commands, maximum number of " - "blocks is 256\n"); - return 1; - } - if ((start_block + blocks - 1) & (~0x1fffff)) { - fprintf(stderr, - ME "for 6 byte commands, can't address blocks" - " beyond %d\n", 0x1fffff); - return 1; - } - if (dpo || fua) { - fprintf(stderr, - ME "for 6 byte commands, neither dpo nor fua" - " bits supported\n"); - return 1; - } - break; - case 10: - sz_ind = 1; - cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : - rd_opcode[sz_ind]); - cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); - cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); - cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); - cdbp[5] = (unsigned char)(start_block & 0xff); - cdbp[7] = (unsigned char)((blocks >> 8) & 0xff); - cdbp[8] = (unsigned char)(blocks & 0xff); - if (blocks & (~0xffff)) { - fprintf(stderr, - ME "for 10 byte commands, maximum number of " - "blocks is %d\n", 0xffff); - return 1; - } - break; - case 12: - sz_ind = 2; - cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : - rd_opcode[sz_ind]); - cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); - cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); - cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); - cdbp[5] = (unsigned char)(start_block & 0xff); - cdbp[6] = (unsigned char)((blocks >> 24) & 0xff); - cdbp[7] = (unsigned char)((blocks >> 16) & 0xff); - cdbp[8] = (unsigned char)((blocks >> 8) & 0xff); - cdbp[9] = (unsigned char)(blocks & 0xff); - break; - case 16: - sz_ind = 3; - cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : - rd_opcode[sz_ind]); - /* can't cope with block number > 32 bits (yet) */ - cdbp[6] = (unsigned char)((start_block >> 24) & 0xff); - cdbp[7] = (unsigned char)((start_block >> 16) & 0xff); - cdbp[8] = (unsigned char)((start_block >> 8) & 0xff); - cdbp[9] = (unsigned char)(start_block & 0xff); - cdbp[10] = (unsigned char)((blocks >> 24) & 0xff); - cdbp[11] = (unsigned char)((blocks >> 16) & 0xff); - cdbp[12] = (unsigned char)((blocks >> 8) & 0xff); - cdbp[13] = (unsigned char)(blocks & 0xff); - break; - default: - fprintf(stderr, - ME "expected cdb size of 6, 10, 12, or 16 but got" - "=%d\n", cdb_sz); - return 1; - } - return 0; -} - -/* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM), - 2 -> try again */ -int sg_read(int sg_fd, unsigned char *buff, int blocks, int from_block, - int bs, int cdbsz, int fua, int *diop) -{ - unsigned char rdCmd[MAX_SCSI_CDBSZ]; - unsigned char senseBuff[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, 0)) { - fprintf(stderr, - ME "bad rd cdb build, from_block=%d, blocks=%d\n", - from_block, blocks); - return -1; - } - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = cdbsz; - io_hdr.cmdp = rdCmd; - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = bs * blocks; - io_hdr.dxferp = buff; - io_hdr.mx_sb_len = SENSE_BUFF_LEN; - io_hdr.sbp = senseBuff; - io_hdr.timeout = DEF_TIMEOUT; - io_hdr.pack_id = from_block; - if (diop && *diop) - io_hdr.flags |= SG_FLAG_DIRECT_IO; - - if (ioctl(sg_fd, SG_IO, &io_hdr)) { - if (ENOMEM == errno) - return 1; - perror("reading (SG_IO) on sg device, error"); - return -1; - } - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - fprintf(stderr, - "Recovered error while reading block=%d, num=%d\n", - from_block, blocks); - break; - case SG_ERR_CAT_MEDIA_CHANGED: - return 2; - default: - sg_chk_n_print3("reading", &io_hdr); - if (do_coe) { - memset(buff, 0, bs * blocks); - fprintf(stderr, ">> unable to read at blk=%d for " - "%d bytes, use zeros\n", from_block, - bs * blocks); - return 0; /* fudge success */ - } else - return -1; - } - if (diop && *diop && - ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) - *diop = 0; /* flag that dio not done (completely) */ - sum_of_resids += io_hdr.resid; -#if SG_DEBUG - fprintf(stderr, "duration=%u ms\n", io_hdr.duration); -#endif - return 0; -} - -/* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM), - 2 -> try again */ -int sg_write(int sg_fd, unsigned char *buff, int blocks, int to_block, - int bs, int cdbsz, int fua, int *diop) -{ - unsigned char wrCmd[MAX_SCSI_CDBSZ]; - unsigned char senseBuff[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, 0)) { - fprintf(stderr, ME "bad wr cdb build, to_block=%d, blocks=%d\n", - to_block, blocks); - return -1; - } - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = cdbsz; - io_hdr.cmdp = wrCmd; - io_hdr.dxfer_direction = SG_DXFER_TO_DEV; - io_hdr.dxfer_len = bs * blocks; - io_hdr.dxferp = buff; - io_hdr.mx_sb_len = SENSE_BUFF_LEN; - io_hdr.sbp = senseBuff; - io_hdr.timeout = DEF_TIMEOUT; - io_hdr.pack_id = to_block; - if (diop && *diop) - io_hdr.flags |= SG_FLAG_DIRECT_IO; - - if (ioctl(sg_fd, SG_IO, &io_hdr)) { - if (ENOMEM == errno) - return 1; - perror("writing (SG_IO) on sg device, error"); - return -1; - } - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - fprintf(stderr, - "Recovered error while writing block=%d, num=%d\n", - to_block, blocks); - break; - case SG_ERR_CAT_MEDIA_CHANGED: - return 2; - default: - sg_chk_n_print3("writing", &io_hdr); - if (do_coe) { - fprintf(stderr, ">> ignored errors for out blk=%d for " - "%d bytes\n", to_block, bs * blocks); - return 0; /* fudge success */ - } else - return -1; - } - if (diop && *diop && - ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) - *diop = 0; /* flag that dio not done (completely) */ - return 0; -} - -int get_num(char *buf) -{ - int res, num; - char c; - - res = sscanf(buf, "%d%c", &num, &c); - if (0 == res) - return -1; - else if (1 == res) - return num; - else { - switch (c) { - case 'c': - case 'C': - return num; - case 'b': - case 'B': - return num * 512; - case 'k': - return num * 1024; - case 'K': - return num * 1000; - case 'm': - return num * 1024 * 1024; - case 'M': - return num * 1000000; - case 'g': - return num * 1024 * 1024 * 1024; - case 'G': - return num * 1000000000; - default: - fprintf(stderr, "unrecognized multiplier\n"); - return -1; - } - } -} - -int do_scsi_device_read_write(char *device) -{ - int skip = 0; - int seek = 0; - int bs = 0; - int ibs = 0; - int obs = 0; - int bpt = DEF_BLOCKS_PER_TRANSFER; - char inf[INOUTF_SZ]; - int in_type = FT_OTHER; - char outf[INOUTF_SZ]; - int out_type = FT_OTHER; - int dio = 0; - int dio_incomplete = 0; - int do_time = 1; - int do_odir = 1; - int scsi_cdbsz = DEF_SCSI_CDBSZ; - int fua_mode = 0; - int do_sync = 1; - int do_blk_sgio = 1; - int do_append = 1; - int res, t, buf_sz, dio_tmp; - int infd, outfd, blocks; - unsigned char *wrkBuff; - unsigned char *wrkPos; - int in_num_sect = 0; - int out_num_sect = 0; - int in_sect_sz, out_sect_sz; - char ebuff[EBUFF_SZ]; - int blocks_per; - int req_count; - struct timeval start_tm, end_tm; - - print_msg(TEST_BREAK, __FUNCTION__); - strcpy(inf, "/dev/zero"); - strcpy(outf, device); - - if (bs <= 0) { - bs = DEF_BLOCK_SIZE; - fprintf(stderr, - "Assume default 'bs' (block size) of %d bytes\n", bs); - } - if ((ibs && (ibs != bs)) || (obs && (obs != bs))) { - fprintf(stderr, - "If 'ibs' or 'obs' given must be same as 'bs'\n"); - usage(); - return 1; - } - if ((skip < 0) || (seek < 0)) { - fprintf(stderr, "skip and seek cannot be negative\n"); - return 1; - } - if ((do_append > 0) && (seek > 0)) { - fprintf(stderr, "Can't use both append and seek switches\n"); - return 1; - } -#ifdef SG_DEBUG - fprintf(stderr, ME "if=%s skip=%d of=%s seek=%d count=%d\n", - inf, skip, outf, seek, dd_count); -#endif - install_handler(SIGINT, interrupt_handler); - install_handler(SIGQUIT, interrupt_handler); - install_handler(SIGPIPE, interrupt_handler); - install_handler(SIGUSR1, siginfo_handler); - - infd = STDIN_FILENO; - outfd = STDOUT_FILENO; - if (inf[0] && ('-' != inf[0])) { - in_type = dd_filetype(inf); - - if ((FT_BLOCK & in_type) && do_blk_sgio) - in_type |= FT_SG; - - if (FT_ST == in_type) { - fprintf(stderr, - ME "unable to use scsi tape device %s\n", inf); - return 1; - } else if (FT_SG & in_type) { - if ((infd = open(inf, O_RDWR)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for sg reading", - inf); - perror(ebuff); - return 1; - } - t = bs * bpt; - res = ioctl(infd, SG_SET_RESERVED_SIZE, &t); - if (res < 0) - perror(ME "SG_SET_RESERVED_SIZE error"); - res = ioctl(infd, SG_GET_VERSION_NUM, &t); - if ((res < 0) || (t < 30000)) { - if (FT_BLOCK & in_type) - fprintf(stderr, - ME - "SG_IO unsupported on this block" - " device\n"); - else - fprintf(stderr, - ME - "sg driver prior to 3.x.y\n"); - return 1; - } - } else { - if (do_odir && (FT_BLOCK == in_type)) - infd = open(inf, O_RDONLY | O_DIRECT); - else - infd = open(inf, O_RDONLY); - if (infd < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for reading", - inf); - perror(ebuff); - return 1; - } else if (skip > 0) { - llse_loff_t offset = skip; - - offset *= bs; /* could exceed 32 bits here! */ - if (llse_llseek(infd, offset, SEEK_SET) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "couldn't skip to required position on %s", - inf); - perror(ebuff); - return 1; - } - } - } - } - - if (outf[0] && ('-' != outf[0])) { - out_type = dd_filetype(outf); - - if ((FT_BLOCK & out_type) && do_blk_sgio) - out_type |= FT_SG; - - if (FT_ST == out_type) { - fprintf(stderr, - ME "unable to use scsi tape device %s\n", outf); - return 1; - } else if (FT_SG & out_type) { - if ((outfd = open(outf, O_RDWR)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for sg writing", - outf); - perror(ebuff); - return 1; - } - t = bs * bpt; - res = ioctl(outfd, SG_SET_RESERVED_SIZE, &t); - if (res < 0) - perror(ME "SG_SET_RESERVED_SIZE error"); - res = ioctl(outfd, SG_GET_VERSION_NUM, &t); - if ((res < 0) || (t < 30000)) { - fprintf(stderr, - ME "sg driver prior to 3.x.y\n"); - return 1; - } - } else if (FT_DEV_NULL & out_type) - outfd = -1; /* don't bother opening */ - else { - if (FT_RAW != out_type) { - int flags = O_WRONLY | O_CREAT; - - if (do_odir && (FT_BLOCK == out_type)) - flags |= O_DIRECT; - else if (do_append) - flags |= O_APPEND; - if ((outfd = open(outf, flags, 0666)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "could not open %s for writing", - outf); - perror(ebuff); - return 1; - } - } else { - if ((outfd = open(outf, O_WRONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "could not open %s for raw writing", - outf); - perror(ebuff); - return 1; - } - } - if (seek > 0) { - llse_loff_t offset = seek; - - offset *= bs; /* could exceed 32 bits here! */ - if (llse_llseek(outfd, offset, SEEK_SET) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "couldn't seek to required position on %s", - outf); - perror(ebuff); - return 1; - } - } - } - } - if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { - fprintf(stderr, - "Can't have both 'if' as stdin _and_ 'of' as stdout\n"); - return 1; - } - - if (dd_count < 0) { - if (FT_SG & in_type) { - res = read_capacity(infd, &in_num_sect, &in_sect_sz); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(in), continuing\n"); - res = - read_capacity(infd, &in_num_sect, - &in_sect_sz); - } - if (0 != res) { - fprintf(stderr, - "Unable to read capacity on %s\n", inf); - in_num_sect = -1; - } else { - if (in_num_sect > skip) - in_num_sect -= skip; - } - } - if (FT_SG & out_type) { - res = read_capacity(outfd, &out_num_sect, &out_sect_sz); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(out), continuing\n"); - res = - read_capacity(outfd, &out_num_sect, - &out_sect_sz); - } - if (0 != res) { - fprintf(stderr, - "Unable to read capacity on %s\n", - outf); - out_num_sect = -1; - } else { - if (out_num_sect > seek) - out_num_sect -= seek; - } - } -#ifdef SG_DEBUG - fprintf(stderr, - "Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n", - dd_count, in_num_sect, out_num_sect); -#endif - if (in_num_sect > 0) { - if (out_num_sect > 0) - dd_count = - (in_num_sect > - out_num_sect) ? out_num_sect : in_num_sect; - else - dd_count = in_num_sect; - } else - dd_count = out_num_sect; - } - if (dd_count < 0) { - fprintf(stderr, "Couldn't calculate count, please give one\n"); - return 1; - } - - if (dio || do_odir || (FT_RAW == in_type) || (FT_RAW == out_type)) { - size_t psz = getpagesize(); - wrkBuff = malloc(bs * bpt + psz); - if (0 == wrkBuff) { - fprintf(stderr, "Not enough user memory for raw\n"); - return 1; - } - wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) & - (~(psz - 1))); - } else { - wrkBuff = malloc(bs * bpt); - if (0 == wrkBuff) { - fprintf(stderr, "Not enough user memory\n"); - return 1; - } - wrkPos = wrkBuff; - } - - blocks_per = bpt; -#ifdef SG_DEBUG - fprintf(stderr, "Start of loop, count=%d, blocks_per=%d\n", - dd_count, blocks_per); -#endif - if (do_time) { - start_tm.tv_sec = 0; - start_tm.tv_usec = 0; - gettimeofday(&start_tm, NULL); - } - req_count = dd_count; - - while (dd_count > 0) { - blocks = (dd_count > blocks_per) ? blocks_per : dd_count; - if (FT_SG & in_type) { - int fua = fua_mode & 2; - - dio_tmp = dio; - res = - sg_read(infd, wrkPos, blocks, skip, bs, scsi_cdbsz, - fua, &dio_tmp); - if (1 == res) { /* ENOMEM, find what's available+try that */ - if (ioctl(infd, SG_GET_RESERVED_SIZE, &buf_sz) < - 0) { - perror("RESERVED_SIZE ioctls failed"); - break; - } - blocks_per = (buf_sz + bs - 1) / bs; - blocks = blocks_per; - fprintf(stderr, - "Reducing read to %d blocks per loop\n", - blocks_per); - res = - sg_read(infd, wrkPos, blocks, skip, bs, - scsi_cdbsz, fua, &dio_tmp); - } else if (2 == res) { - fprintf(stderr, - "Unit attention, media changed, continuing (r)\n"); - res = - sg_read(infd, wrkPos, blocks, skip, bs, - scsi_cdbsz, fua, &dio_tmp); - } - if (0 != res) { - fprintf(stderr, "sg_read failed, skip=%d\n", - skip); - break; - } else { - in_full += blocks; - if (dio && (0 == dio_tmp)) - dio_incomplete++; - } - } else { - while (((res = read(infd, wrkPos, blocks * bs)) < 0) && - (EINTR == errno)) ; - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "reading, skip=%d ", skip); - perror(ebuff); - break; - } else if (res < blocks * bs) { - dd_count = 0; - blocks = res / bs; - if ((res % bs) > 0) { - blocks++; - in_partial++; - } - } - in_full += blocks; - } - - if (FT_SG & out_type) { - int fua = fua_mode & 1; - - dio_tmp = dio; - res = - sg_write(outfd, wrkPos, blocks, seek, bs, - scsi_cdbsz, fua, &dio_tmp); - if (1 == res) { /* ENOMEM, find what's available+try that */ - if (ioctl(outfd, SG_GET_RESERVED_SIZE, &buf_sz) - < 0) { - perror("RESERVED_SIZE ioctls failed"); - break; - } - blocks_per = (buf_sz + bs - 1) / bs; - blocks = blocks_per; - fprintf(stderr, - "Reducing write to %d blocks per loop\n", - blocks); - res = - sg_write(outfd, wrkPos, blocks, seek, bs, - scsi_cdbsz, fua, &dio_tmp); - } else if (2 == res) { - fprintf(stderr, - "Unit attention, media changed, continuing (w)\n"); - res = - sg_write(outfd, wrkPos, blocks, seek, bs, - scsi_cdbsz, fua, &dio_tmp); - } else if (0 != res) { - fprintf(stderr, "sg_write failed, seek=%d\n", - seek); - break; - } else { - out_full += blocks; - if (dio && (0 == dio_tmp)) - dio_incomplete++; - } - } else if (FT_DEV_NULL & out_type) - out_full += blocks; /* act as if written out without error */ - else { - while (((res = write(outfd, wrkPos, blocks * bs)) < 0) - && (EINTR == errno)) ; - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "writing, seek=%d ", seek); - perror(ebuff); - break; - } else if (res < blocks * bs) { - fprintf(stderr, - "output file probably full, seek=%d ", - seek); - blocks = res / bs; - out_full += blocks; - if ((res % bs) > 0) - out_partial++; - break; - } else - out_full += blocks; - } - if (dd_count > 0) - dd_count -= blocks; - skip += blocks; - seek += blocks; - } - if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { - struct timeval res_tm; - double a, b; - - gettimeofday(&end_tm, NULL); - res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; - res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; - if (res_tm.tv_usec < 0) { - --res_tm.tv_sec; - res_tm.tv_usec += 1000000; - } - a = res_tm.tv_sec; - a += (0.000001 * res_tm.tv_usec); - b = (double)bs *(req_count - dd_count); - printf("time to transfer data was %d.%06d secs", - (int)res_tm.tv_sec, (int)res_tm.tv_usec); - if ((a > 0.00001) && (b > 511)) - printf(", %.2f MB/sec\n", b / (a * 1000000.0)); - else - printf("\n"); - } - if (do_sync) { - if (FT_SG & out_type) { - fprintf(stderr, ">> Synchronizing cache on %s\n", outf); - res = sync_cache(outfd); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(in), continuing\n"); - res = sync_cache(outfd); - } - if (0 != res) - fprintf(stderr, - "Unable to synchronize cache\n"); - } - } - free(wrkBuff); - if (STDIN_FILENO != infd) - close(infd); - if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type)) - close(outfd); - res = 0; - if (0 != dd_count) { - fprintf(stderr, "Some error occurred,"); - res = 2; - } - print_stats(); - if (dio_incomplete) { - int fd; - char c; - - fprintf(stderr, - ">> Direct IO requested but incomplete %d times\n", - dio_incomplete); - if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { - if (1 == read(fd, &c, 1)) { - if ('0' == c) - fprintf(stderr, - ">>> %s set to '0' but should be set " - "to '1' for direct IO\n", - proc_allow_dio); - } - close(fd); - } - } - if (sum_of_resids) - fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", - sum_of_resids); - return res; -} - -/* Returns 0 when successful, else -1 */ -static int do_scsi_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op, - void *resp, int mx_resp_len, int noisy) -{ - int res; - unsigned char inqCmdBlk[INQUIRY_CMDLEN] = - { INQUIRY_CMD, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - if (cmddt) - inqCmdBlk[1] |= 2; - if (evpd) - inqCmdBlk[1] |= 1; - inqCmdBlk[2] = (unsigned char)pg_op; - inqCmdBlk[4] = (unsigned char)mx_resp_len; - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(inqCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = inqCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (inquiry) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, "Inquiry error, CmdDt=%d, " - "EVPD=%d, page_opcode=%x ", cmddt, evpd, - pg_op); - sg_chk_n_print3(ebuff, &io_hdr); - } - return -1; - } -} - -int do_scsi_inquiry(char *device, int hex_flag) -{ - int sg_fd, k, j, num, len, act_len; - int support_num; - char *file_name = 0; - char buff[MX_ALLOC_LEN + 1]; - unsigned char rsp_buff[MX_ALLOC_LEN + 1]; - unsigned int num_opcode = 0; - int do_evpd = 0; - int do_cmddt = 0; - int do_cmdlst = 0; - int do_hex = 0; - int do_raw = 0; - int do_pci = 0; - int do_36 = 0; - int oflags = O_RDONLY | O_NONBLOCK; - int ansi_version = 0; - int ret = 0; - - file_name = device; - - if (hex_flag) { - do_hex = TRUE; - print_msg(TEST_BREAK, __FUNCTION__); - } else { - do_pci = TRUE; - } - - if (do_pci) - oflags = O_RDWR | O_NONBLOCK; - if ((sg_fd = open(file_name, oflags)) < 0) { - snprintf(ebuff, EBUFF_SZ, "sg_inq: error opening file: %s", - file_name); - perror(ebuff); - return 1; - } - /* Just to be safe, check we have a new sg device by trying an ioctl */ - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { - fprintf(stderr, - "sg_inq: %s doesn't seem to be a version 3 sg device\n", - file_name); - close(sg_fd); - return 1; - } - memset(rsp_buff, 0, MX_ALLOC_LEN + 1); - - if (!(do_cmddt || do_evpd)) { - if (!do_raw) - printf("standard INQUIRY:\n"); - if (num_opcode > 0) - printf - (" <<given opcode or page_code is being ignored>>\n"); - - if (0 == do_scsi_inq(sg_fd, 0, 0, 0, rsp_buff, 36, 1)) { - len = rsp_buff[4] + 5; - ansi_version = rsp_buff[2] & 0x7; - if ((len > 36) && (len < 256) && (!do_36)) { - if (do_scsi_inq - (sg_fd, 0, 0, 0, rsp_buff, len, 1)) { - fprintf(stderr, - "second INQUIRY (%d byte) failed\n", - len); - return 1; - } - if (len != (rsp_buff[4] + 5)) { - fprintf(stderr, - "strange, twin INQUIRYs yield different " - "'additional length'\n"); - ret = 2; - } - } - if (do_36) { - act_len = len; - len = 36; - } else - act_len = len; - if (do_hex) - dStrHex((const char *)rsp_buff, len, 0); - else { - printf - (" PQual=%d, Device type=%d, RMB=%d, ANSI version=%d, ", - (rsp_buff[0] & 0xe0) >> 5, - rsp_buff[0] & 0x1f, - ! !(rsp_buff[1] & 0x80), ansi_version); - printf("[full version=0x%02x]\n", - (unsigned int)rsp_buff[2]); - printf - (" AERC=%d, TrmTsk=%d, NormACA=%d, HiSUP=%d, " - "Resp data format=%d, SCCS=%d\n", - ! !(rsp_buff[3] & 0x80), - ! !(rsp_buff[3] & 0x40), - ! !(rsp_buff[3] & 0x20), - ! !(rsp_buff[3] & 0x10), - rsp_buff[3] & 0x0f, - ! !(rsp_buff[5] & 0x80)); - printf - (" BQue=%d, EncServ=%d, MultiP=%d, MChngr=%d, " - "ACKREQQ=%d, ", ! !(rsp_buff[6] & 0x80), - ! !(rsp_buff[6] & 0x40), - ! !(rsp_buff[6] & 0x10), - ! !(rsp_buff[6] & 0x08), - ! !(rsp_buff[6] & 0x04)); - printf("Addr16=%d\n RelAdr=%d, ", - ! !(rsp_buff[6] & 0x01), - ! !(rsp_buff[7] & 0x80)); - printf - ("WBus16=%d, Sync=%d, Linked=%d, TranDis=%d, ", - ! !(rsp_buff[7] & 0x20), - ! !(rsp_buff[7] & 0x10), - ! !(rsp_buff[7] & 0x08), - ! !(rsp_buff[7] & 0x04)); - printf("CmdQue=%d\n", ! !(rsp_buff[7] & 0x02)); - if (len > 56) - printf - (" Clocking=0x%x, QAS=%d, IUS=%d\n", - (rsp_buff[56] & 0x0c) >> 2, - ! !(rsp_buff[56] & 0x2), - ! !(rsp_buff[56] & 0x1)); - if (act_len == len) - printf(" length=%d (0x%x)", len, - len); - else - printf - (" length=%d (0x%x), but only read 36 bytes", - len, len); - if ((ansi_version >= 2) && (len < 36)) - printf - (" [for SCSI>=2, len>=36 is expected]\n"); - else - printf("\n"); - - if (len <= 8) - printf - (" Inquiry response length=%d\n, no vendor, " - "product or revision data\n", len); - else { - if (len < 36) - rsp_buff[len] = '\0'; - memcpy(buff, &rsp_buff[8], 8); - buff[8] = '\0'; - printf(" Vendor identification: %s\n", - buff); - if (len <= 16) - printf - (" Product identification: <none>\n"); - else { - memcpy(buff, &rsp_buff[16], 16); - buff[16] = '\0'; - printf - (" Product identification: %s\n", - buff); - } - if (len <= 32) - printf - (" Product revision level: <none>\n"); - else { - memcpy(buff, &rsp_buff[32], 4); - buff[4] = '\0'; - printf - (" Product revision level: %s\n", - buff); - } - } - } - if (!do_raw && - (0 == - do_scsi_inq(sg_fd, 0, 1, 0x80, rsp_buff, - MX_ALLOC_LEN, 0))) { - len = rsp_buff[3]; - if (len > 0) { - memcpy(buff, rsp_buff + 4, len); - buff[len] = '\0'; - printf(" Product serial number: %s\n", - buff); - } - } - } else { - printf("36 byte INQUIRY failed\n"); - return 1; - } - } else if (do_cmddt) { - int reserved_cmddt; - char op_name[128]; - - if (do_cmdlst) { - printf("Supported command list:\n"); - for (k = 0; k < 256; ++k) { - if (0 == - do_scsi_inq(sg_fd, 1, 0, k, rsp_buff, - MX_ALLOC_LEN, 1)) { - support_num = rsp_buff[1] & 7; - reserved_cmddt = rsp_buff[4]; - if ((3 == support_num) - || (5 == support_num)) { - num = rsp_buff[5]; - for (j = 0; j < num; ++j) - printf(" %.2x", - (int)rsp_buff[6 + - j]); - if (5 == support_num) - printf - (" [vendor specific manner (5)]"); - sg_get_command_name((unsigned - char)k, - sizeof - (op_name) - - 1, op_name); - op_name[sizeof(op_name) - 1] = - '\0'; - printf(" %s\n", op_name); - } else if ((4 == support_num) - || (6 == support_num)) - printf - (" opcode=0x%.2x vendor specific (%d)\n", - k, support_num); - else if ((0 == support_num) - && (reserved_cmddt > 0)) { - printf - (" opcode=0x%.2x ignored cmddt bit, " - "given standard INQUIRY response, stop\n", - k); - break; - } - } else { - fprintf(stderr, - "CmdDt INQUIRY on opcode=0x%.2x: failed\n", - k); - break; - } - } - } else { - if (!do_raw) { - printf("CmdDt INQUIRY, opcode=0x%.2x: [", - num_opcode); - sg_get_command_name((unsigned char)num_opcode, - sizeof(op_name) - 1, - op_name); - op_name[sizeof(op_name) - 1] = '\0'; - printf("%s]\n", op_name); - } - if (0 == do_scsi_inq(sg_fd, 1, 0, num_opcode, rsp_buff, - MX_ALLOC_LEN, 1)) { - len = rsp_buff[5] + 6; - reserved_cmddt = rsp_buff[4]; - if (do_hex) - dStrHex((const char *)rsp_buff, len, 0); - else { - const char *desc_p; - int prnt_cmd = 0; - - support_num = rsp_buff[1] & 7; - num = rsp_buff[5]; - switch (support_num) { - case 0: - if (0 == reserved_cmddt) - desc_p = - "no data available"; - else - desc_p = - "ignored cmddt bit, standard INQUIRY " - "response"; - break; - case 1: - desc_p = "not supported"; - break; - case 2: - desc_p = "reserved (2)"; - break; - case 3: - desc_p = - "supported as per standard"; - prnt_cmd = 1; - break; - case 4: - desc_p = "vendor specific (4)"; - break; - case 5: - desc_p = - "supported in vendor specific way"; - prnt_cmd = 1; - break; - case 6: - desc_p = "vendor specific (6)"; - break; - case 7: - desc_p = "reserved (7)"; - break; - default: - desc_p = "impossible value > 7"; - break; - } - if (prnt_cmd) { - printf(" Support field: %s [", - desc_p); - for (j = 0; j < num; ++j) - printf(" %.2x", - (int)rsp_buff[6 + - j]); - printf(" ]\n"); - } else - printf(" Support field: %s\n", - desc_p); - } - } else { - fprintf(stderr, - "CmdDt INQUIRY on opcode=0x%.2x: failed\n", - num_opcode); - return 1; - } - - } - } else if (do_evpd) { - if (!do_raw) - printf("EVPD INQUIRY, page code=0x%.2x:\n", num_opcode); - if (0 == - do_scsi_inq(sg_fd, 0, 1, num_opcode, rsp_buff, MX_ALLOC_LEN, - 1)) { - len = rsp_buff[3] + 4; - if (num_opcode != rsp_buff[1]) - printf - ("non evpd respone; probably a STANDARD INQUIRY " - "response\n"); - else { - if (!do_hex) - printf(" Only hex output supported\n"); - dStrHex((const char *)rsp_buff, len, 0); - } - } else { - fprintf(stderr, - "EVPD INQUIRY, page code=0x%.2x: failed\n", - num_opcode); - return 1; - } - } - - if (do_pci) { - unsigned char slot_name[16]; - - printf("\n"); - memset(slot_name, '\0', sizeof(slot_name)); - if (ioctl(sg_fd, SCSI_IOCTL_GET_PCI, slot_name) < 0) { - if (EINVAL == errno) - printf - ("ioctl(SCSI_IOCTL_GET_PCI) not supported by this " - "kernel\n"); - else if (ENXIO == errno) - printf - ("associated adapter not a PCI device?\n"); - else - perror("ioctl(SCSI_IOCTL_GET_PCI) failed"); - } else - printf("PCI:slot_name: %s\n", slot_name); - } - - close(sg_fd); - return ret; -} - -int show_scsi_maps() -{ - int sg_fd, res, k; - int do_numeric = NUMERIC_SCAN_DEF; - int do_all_s = 1; - int do_sd = 0; - int do_st = 0; - int do_osst = 0; - int do_sr = 0; - int do_scd = 0; - int do_extra = 1; - int do_inquiry = 0; - char fname[64]; - int num_errors = 0; - int num_silent = 0; - int eacces_err = 0; - int last_sg_ind = -1; - struct stat stat_buf; - - print_msg(TEST_BREAK, __FUNCTION__); - - if (stat(devfs_id, &stat_buf) == 0) - printf("# Note: the devfs pseudo file system is present\n"); - - for (k = 0, res = 0; (k < MAX_SG_DEVS) && (num_errors < MAX_ERRORS); - ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, "Error closing %s ", fname); - perror("sg_map: close error"); - return 1; - } - make_dev_name(fname, "/dev/sg", k, do_numeric); - - sg_fd = open(fname, O_RDONLY | O_NONBLOCK); - if (sg_fd < 0) { - if (EBUSY == errno) { - map_arr[k].active = -2; - continue; - } else if ((ENODEV == errno) || (ENOENT == errno) || - (ENXIO == errno)) { - ++num_errors; - ++num_silent; - map_arr[k].active = -1; - continue; - } else { - if (EACCES == errno) - eacces_err = 1; - snprintf(ebuff, EBUFF_SZ, "Error opening %s ", - fname); - perror(ebuff); - ++num_errors; - continue; - } - } - res = ioctl(sg_fd, SG_GET_SCSI_ID, &map_arr[k].sg_dat); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - "device %s failed on sg ioctl, skip", fname); - perror(ebuff); - ++num_errors; - continue; - } - if (do_inquiry) { - char buff[36]; - - if (0 == - do_scsi_inq(sg_fd, 0, 0, 0, buff, sizeof(buff), - 1)) { - memcpy(map_arr[k].vendor, &buff[8], 8); - memcpy(map_arr[k].product, &buff[16], 16); - memcpy(map_arr[k].revision, &buff[32], 4); - } - } - map_arr[k].active = 1; - map_arr[k].oth_dev_num = -1; - last_sg_ind = k; - } - if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors)) { - printf("Stopping because there are too many error\n"); - if (eacces_err) - printf(" root access may be required\n"); - return 1; - } - if (last_sg_ind < 0) { - printf("Stopping because no sg devices found\n"); - } - - if (do_all_s || do_sd) - scan_dev_type("/dev/sd", MAX_SD_DEVS, 0, LIN_DEV_TYPE_SD, - last_sg_ind); - if (do_all_s || do_sr) - scan_dev_type("/dev/sr", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SR, - last_sg_ind); - if (do_all_s || do_scd) - scan_dev_type("/dev/scd", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SCD, - last_sg_ind); - if (do_all_s || do_st) - scan_dev_type("/dev/st", MAX_ST_DEVS, 1, LIN_DEV_TYPE_ST, - last_sg_ind); - if (do_all_s || do_osst) - scan_dev_type("/dev/osst", MAX_OSST_DEVS, 1, LIN_DEV_TYPE_OSST, - last_sg_ind); - - for (k = 0; k <= last_sg_ind; ++k) { - make_dev_name(fname, "/dev/sg", k, do_numeric); - printf("%s", fname); - switch (map_arr[k].active) { - case -2: - printf(do_extra ? " -2 -2 -2 -2 -2" : " busy"); - break; - case -1: - printf(do_extra ? " -1 -1 -1 -1 -1" : - " not present"); - break; - case 0: - printf(do_extra ? " -3 -3 -3 -3 -3" : - " some error\n"); - break; - case 1: - if (do_extra) - printf(" %d %d %d %d %d", - map_arr[k].sg_dat.host_no, - map_arr[k].sg_dat.channel, - map_arr[k].sg_dat.scsi_id, - map_arr[k].sg_dat.lun, - map_arr[k].sg_dat.scsi_type); - switch (map_arr[k].lin_dev_type) { - case LIN_DEV_TYPE_SD: - make_dev_name(fname, "/dev/sd", - map_arr[k].oth_dev_num, 0); - printf(" %s", fname); - break; - case LIN_DEV_TYPE_ST: - make_dev_name(fname, "/dev/st", - map_arr[k].oth_dev_num, 1); - printf(" %s", fname); - break; - case LIN_DEV_TYPE_OSST: - make_dev_name(fname, "/dev/osst", - map_arr[k].oth_dev_num, 1); - printf(" %s", fname); - break; - case LIN_DEV_TYPE_SR: - make_dev_name(fname, "/dev/sr", - map_arr[k].oth_dev_num, 1); - printf(" %s", fname); - break; - case LIN_DEV_TYPE_SCD: - make_dev_name(fname, "/dev/scd", - map_arr[k].oth_dev_num, 1); - printf(" %s", fname); - break; - default: - break; - } - if (do_inquiry) - printf(" %.8s %.16s %.4s", map_arr[k].vendor, - map_arr[k].product, map_arr[k].revision); - break; - default: - printf(" bad logic\n"); - break; - } - printf("\n"); - } - return 0; -} - -static int find_dev_in_sg_arr(My_scsi_idlun * my_idlun, int host_no, - int last_sg_ind) -{ - int k; - struct sg_scsi_id *sidp; - - for (k = 0; k <= last_sg_ind; ++k) { - sidp = &(map_arr[k].sg_dat); - if ((host_no == sidp->host_no) && - ((my_idlun->dev_id & 0xff) == sidp->scsi_id) && - (((my_idlun->dev_id >> 8) & 0xff) == sidp->lun) && - (((my_idlun->dev_id >> 16) & 0xff) == sidp->channel)) - return k; - } - return -1; -} - -static void scan_dev_type(const char *leadin, int max_dev, int do_numeric, - int lin_dev_type, int last_sg_ind) -{ - int k, res, ind, sg_fd = 0; - int num_errors = 0; - int num_silent = 0; - int host_no = -1; - int nonMappedDevicesPresent = FALSE; - My_scsi_idlun my_idlun; - char fname[64]; - - for (k = 0, res = 0; (k < max_dev) && (num_errors < MAX_ERRORS); - ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { - -/* ignore close() errors */ -#if 0 - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, "Error closing %s ", fname); - perror("sg_map: close error"); -#ifndef IGN_CLOSE_ERR - return; -#else - ++num_errors; - sg_fd = 0; -#endif - } -#endif - make_dev_name(fname, leadin, k, do_numeric); -#ifdef DEBUG - printf("Trying %s: ", fname); -#endif - - sg_fd = open(fname, O_RDONLY | O_NONBLOCK); - if (sg_fd < 0) { -#ifdef DEBUG - printf("ERROR %i\n", errno); -#endif - if (EBUSY == errno) { - printf("Device %s is busy\n", fname); - ++num_errors; - continue; - } else if ((ENODEV == errno) || (ENOENT == errno) || - (ENXIO == errno)) { - ++num_errors; - ++num_silent; - continue; - } else { - snprintf(ebuff, EBUFF_SZ, "Error opening %s ", - fname); - perror(ebuff); - ++num_errors; - continue; - } - } - - res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - "device %s failed on scsi ioctl(idlun), skip", - fname); - perror(ebuff); - ++num_errors; -#ifdef DEBUG - printf("Couldn't get IDLUN!\n"); -#endif - continue; - } - res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no); - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - "device %s failed on scsi ioctl(bus_number), skip", - fname); - perror(ebuff); - ++num_errors; -#ifdef DEBUG - printf("Couldn't get BUS!\n"); -#endif - continue; - } -#ifdef DEBUG - printf("%i(%x) %i %i %i %i\n", host_no, my_idlun.host_unique_id, - (my_idlun.dev_id >> 24) & 0xff, - (my_idlun.dev_id >> 16) & 0xff, - (my_idlun.dev_id >> 8) & 0xff, my_idlun.dev_id & 0xff); -#endif - ind = find_dev_in_sg_arr(&my_idlun, host_no, last_sg_ind); - if (ind >= 0) { - map_arr[ind].oth_dev_num = k; - map_arr[ind].lin_dev_type = lin_dev_type; - } else if (ind != -1) { - printf - ("Strange, could not find device %s mapped to sg device error %d??\n", - fname, ind); - } else { - nonMappedDevicesPresent = TRUE; - } - } - if (nonMappedDevicesPresent) { - printf("Unmapped Devices found...\n\n"); - } -} - -/* Returns 0 when successful, else -1 */ -static int do_simple_inq(int sg_fd, void *resp, int mx_resp_len, int noisy) -{ - int res; - unsigned char inqCmdBlk[INQUIRY_CMDLEN] = - { INQUIRY_CMD, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - inqCmdBlk[4] = (unsigned char)mx_resp_len; - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(inqCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = inqCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (inquiry) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, "Inquiry error "); - sg_chk_n_print3(ebuff, &io_hdr); - } - return -1; - } -} - -static int do_modes(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code, - void *resp, int mx_resp_len, int noisy, int mode6) -{ - int res; - unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] = - { MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0); - modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); - modesCmdBlk[3] = (unsigned char)(sub_pg_code & 0xff); - if (mx_resp_len > (mode6 ? 0xff : 0xffff)) { - printf(ME "mx_resp_len too big\n"); - return -1; - } - if (mode6) { - modesCmdBlk[0] = MODE_SENSE6_CMD; - modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); - } else { - modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); - modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); - } - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - memset(sense_b, 0, sizeof(sense_b)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = mode6 ? MODE_SENSE6_CMDLEN : MODE_SENSE10_CMDLEN; - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = modesCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (mode sense) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, "Mode sense error, dbd=%d " - "pc=%d page_code=%x sub_page_code=%x\n ", - dbd, pc, pg_code, sub_pg_code); - sg_chk_n_print3(ebuff, &io_hdr); - } - if ((0x70 == (0x7f & sense_b[0])) && (0x20 == sense_b[12]) && - (0x0 == sense_b[13])) { - if (mode6) - fprintf(stderr, - ">>>>>> drop '-6' switch and try again with " - "a 10 byte MODE SENSE\n"); - else - fprintf(stderr, - ">>>>>> add '-6' switch and try again with " - "a 6 byte MODE SENSE\n"); - } - return -1; - } -} - -const char *scsi_ptype_strs[] = { - "disk", - "tape", - "printer", - "processor", - "write once optical disk", - "cd/dvd", - "scanner", - "optical memory device", - "medium changer", - "communications", - "graphics", - "graphics", - "storage array controller", - "enclosure services device", - "simplified direct access device", - "optical card reader/writer device", -}; - -const char *get_ptype_str(int scsi_ptype) -{ - int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]); - - return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : ""; -} - -static struct page_code_desc pc_desc_all[] = { - {0x0, "Unit Attention condition [vendor: page format not required]"}, - {0x2, "Disconnect-Reconnect"}, - {0xa, "Control"}, - {0x15, "Extended"}, - {0x16, "Extended device-type specific"}, - {0x18, "Protocol specific LUN"}, - {0x19, "Protocol specific port"}, - {0x1a, "Power condition"}, - {0x1c, "Informational exceptions control"}, - {0x3f, "[yields all supported pages]"}, -}; - -static struct page_code_desc pc_desc_disk[] = { - {0x1, "Read-Write error recovery"}, - {0x3, "Format"}, - {0x4, "Rigid disk geometry"}, - {0x5, "Flexible geometry"}, - {0x7, "Verify error recovery"}, - {0x8, "Caching"}, - {0x9, "Peripheral device (spc-2 ?)"}, - {0xb, "Medium types supported"}, - {0xc, "Notch and partition"}, - {0xd, "Power condition (obsolete)"}, - {0x10, "XOR control"}, -}; - -static struct page_code_desc pc_desc_tape[] = { - {0xf, "Data Compression"}, - {0x10, "Device config"}, - {0x11, "Medium Partition [1]"}, - {0x12, "Medium Partition [2]"}, - {0x13, "Medium Partition [3]"}, - {0x14, "Medium Partition [4]"}, - {0x1c, "Informational exceptions control (tape version)"}, -}; - -static struct page_code_desc pc_desc_cddvd[] = { - {0x1, "Read-Write error recovery"}, - {0x3, "MRW"}, - {0x5, "Write parameters"}, - {0xd, "CD device parameters (obsolete)"}, - {0xe, "CD audio"}, - {0x1a, "Power condition"}, - {0x1c, "Fault/failure reporting control"}, - {0x1d, "Timeout and protect"}, - {0x2a, "MM capabilities and mechanical status (obsolete)"}, -}; - -static struct page_code_desc pc_desc_smc[] = { - {0x1d, "Element address assignment"}, - {0x1e, "Transport geometry parameters"}, - {0x1f, "Device capabilities"}, -}; - -static struct page_code_desc pc_desc_scc[] = { - {0x1b, "LUN mapping"}, -}; - -static struct page_code_desc pc_desc_ses[] = { - {0x14, "Enclosure services management"}, -}; - -struct page_code_desc *find_mode_page_table(int scsi_ptype, int *size) -{ - switch (scsi_ptype) { - case 0: /* disk (direct access) type devices */ - case 4: - case 7: - case 0xe: - *size = sizeof(pc_desc_disk) / sizeof(pc_desc_disk[0]); - return &pc_desc_disk[0]; - case 1: /* tape devices */ - case 2: - *size = sizeof(pc_desc_tape) / sizeof(pc_desc_tape[0]); - return &pc_desc_tape[0]; - case 5: /* cd/dvd devices */ - *size = sizeof(pc_desc_cddvd) / sizeof(pc_desc_cddvd[0]); - return &pc_desc_cddvd[0]; - case 8: /* medium changer devices */ - *size = sizeof(pc_desc_smc) / sizeof(pc_desc_smc[0]); - return &pc_desc_smc[0]; - case 0xc: /* storage array devices */ - *size = sizeof(pc_desc_scc) / sizeof(pc_desc_scc[0]); - return &pc_desc_scc[0]; - case 0xd: /* enclosure services devices */ - *size = sizeof(pc_desc_ses) / sizeof(pc_desc_ses[0]); - return &pc_desc_ses[0]; - } - *size = 0; - return NULL; -} - -const char *find_page_code_desc(int page_num, int scsi_ptype) -{ - int k; - int num; - const struct page_code_desc *pcdp; - - pcdp = find_mode_page_table(scsi_ptype, &num); - if (pcdp) { - for (k = 0; k < num; ++k, ++pcdp) { - if (page_num == pcdp->page_code) - return pcdp->desc; - else if (page_num < pcdp->page_code) - break; - } - } - pcdp = &pc_desc_all[0]; - num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]); - for (k = 0; k < num; ++k, ++pcdp) { - if (page_num == pcdp->page_code) - return pcdp->desc; - else if (page_num < pcdp->page_code) - break; - } - return NULL; -} - -static void list_page_codes(int scsi_ptype) -{ - int k; - int num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]); - const struct page_code_desc *pcdp = &pc_desc_all[0]; - int num_ptype; - const struct page_code_desc *pcd_ptypep; - - pcd_ptypep = find_mode_page_table(scsi_ptype, &num_ptype); - printf("Page_Code Description\n"); - for (k = 0; k < 0x3f; ++k) { - if (pcd_ptypep && (num_ptype > 0)) { - if (k == pcd_ptypep->page_code) { - printf(" 0x%02x %s\n", - pcd_ptypep->page_code, pcd_ptypep->desc); - ++pcd_ptypep; - --num_ptype; - continue; - } else if (k > pcd_ptypep->page_code) { - pcd_ptypep++; - --num_ptype; - } - } - if (pcdp && (num > 0)) { - if (k == pcdp->page_code) { - printf(" 0x%02x %s\n", pcdp->page_code, - pcdp->desc); - ++pcdp; - --num; - continue; - } else if (k > pcdp->page_code) { - pcdp++; - --num; - } - } - } -} - -int show_scsi_modes(char *device) -{ - int sg_fd, k, num, len, md_len, bd_len, longlba, page_num; - char *file_name = 0; - char ebuff[EBUFF_SZ]; - const char *descp; - unsigned char rsp_buff[MODE_ALLOC_LEN]; - int rsp_buff_size = MODE_ALLOC_LEN; - int pg_code = 0; - int sub_pg_code = 0; - int pc = 0; - int do_all = 1; - int do_dbd = 0; - int do_hex = 0; - int do_mode6 = 0; /* Use MODE SENSE(6) instead of MODE SENSE(10) */ - int oflags = O_RDONLY | O_NONBLOCK; - struct sg_scsi_id a_sid; - int scsi_ptype, density_code_off; - unsigned char *ucp; - unsigned char uc; - - print_msg(TEST_BREAK, __FUNCTION__); - - file_name = device; - - list_page_codes(0); - - /* The 6 bytes command only allows up to 255 bytes of response data */ - if (do_mode6) - rsp_buff_size = 255; - - if ((sg_fd = open(file_name, oflags)) < 0) { - snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", - file_name); - perror(ebuff); - return 1; - } - /* Just to be safe, check we have a new sg device by trying an ioctl */ - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { - printf(ME "%s doesn't seem to be a version 3 sg device\n", - file_name); - close(sg_fd); - return 1; - } - if (ioctl(sg_fd, SG_GET_SCSI_ID, &a_sid) < 0) { - unsigned char inqBuff[36]; - - if (do_simple_inq(sg_fd, inqBuff, sizeof(inqBuff), 1)) { - printf(ME "%s doesn't respond to a SCSI INQUIRY\n", - file_name); - close(sg_fd); - return 1; - } - scsi_ptype = inqBuff[0] & 0x1f; /* fetch peripheral device type */ - } else - scsi_ptype = a_sid.scsi_type; - printf(" SCSI peripheral type: %s [0x%x] (from INQUIRY)\n", - get_ptype_str(scsi_ptype), scsi_ptype); - - if (do_all) - pg_code = MODE_CODE_ALL; - - if (0 == do_modes(sg_fd, do_dbd, pc, pg_code, sub_pg_code, - rsp_buff, rsp_buff_size, 1, do_mode6)) { - int medium_type, specific, headerlen; - - printf("Mode parameter header from %s byte MODE SENSE:\n", - (do_mode6 ? "6" : "10")); - if (do_mode6) { - headerlen = 4; - if (do_hex) - dStrHex((const char *)rsp_buff, headerlen, 1); - md_len = rsp_buff[0] + 1; - bd_len = rsp_buff[3]; - medium_type = rsp_buff[1]; - specific = rsp_buff[2]; - longlba = 0; /* what is this field? */ - } else { - headerlen = 8; - md_len = (rsp_buff[0] << 8) + rsp_buff[1] + 2; - bd_len = (rsp_buff[6] << 8) + rsp_buff[7]; - medium_type = rsp_buff[2]; - specific = rsp_buff[3]; - longlba = rsp_buff[4] & 1; - } - if (do_hex) - dStrHex((const char *)rsp_buff, headerlen, 1); - printf(" Mode data length=%d, medium type=0x%.2x, specific" - " param=0x%.2x, longlba=%d\n", md_len, medium_type, - specific, longlba); - if (md_len > rsp_buff_size) { - printf - ("Only fetched %d bytes of response, truncate output\n", - rsp_buff_size); - md_len = rsp_buff_size; - if (bd_len + headerlen > rsp_buff_size) - bd_len = rsp_buff_size - headerlen; - } - printf(" Block descriptor length=%d\n", bd_len); - if (bd_len > 0) { - len = 8; - density_code_off = 0; - num = bd_len; - if (longlba) { - printf("> longlba block descriptors:\n"); - len = 16; - density_code_off = 8; - } else if (0 == scsi_ptype) { - printf - ("> Direct access device block descriptors:\n"); - density_code_off = 4; - } else - printf - ("> General mode parameter block descriptors:\n"); - - ucp = rsp_buff + headerlen; - while (num > 0) { - printf(" Density code=0x%x\n", - *(ucp + density_code_off)); - dStrHex((const char *)ucp, len, 1); - ucp += len; - num -= len; - } - printf("\n"); - } - ucp = rsp_buff + bd_len + headerlen; /* start of mode page(s) */ - md_len -= bd_len + headerlen; /* length of mode page(s) */ - while (md_len > 0) { /* got mode page(s) */ - uc = *ucp; - page_num = ucp[0] & 0x3f; - if (do_hex) - descp = NULL; - else { - descp = - find_page_code_desc(page_num, scsi_ptype); - if (NULL == descp) - snprintf(ebuff, EBUFF_SZ, - "vendor[0x%x]", page_num); - } - if (uc & 0x40) { - len = (ucp[2] << 8) + ucp[3] + 4; - if (do_hex) - printf - (">> page_code=0x%x, subpage_code=0x%x, " - "page_control=%d\n", page_num, - ucp[1], pc); - else - printf - (">> page_code: %s, subpage_code=0x%x, " - "page_control: %s\n", - (descp ? descp : ebuff), ucp[1], - pg_control_str_arr[pc]); - } else { - len = ucp[1] + 2; - if (do_hex) - printf - (">> page_code=0x%x, page_control=%d\n", - page_num, pc); - else - printf - (">> page_code: %s, page_control: %s\n", - (descp ? descp : ebuff), - pg_control_str_arr[pc]); - } - dStrHex((const char *)ucp, len, 1); - ucp += len; - md_len -= len; - } - } - - close(sg_fd); - return 0; -} - -int do_scsi_read_buffer(char *device) -{ - int sg_fd, res; - unsigned int k, num; - unsigned char rbCmdBlk[RB_CMD_LEN]; - unsigned char *rbBuff = NULL; - void *rawp = NULL; - unsigned char sense_buffer[32]; - int buf_capacity = 0; - int do_quick = 0; - int do_dio = 0; - int do_mmap = 1; - int do_time = 0; - int buf_size = 0; - unsigned int total_size_mb = RB_MB_TO_READ; - char *file_name = 0; - size_t psz = getpagesize(); - int dio_incomplete = 0; - sg_io_hdr_t io_hdr; - struct timeval start_tm, end_tm; -#ifdef SG_DEBUG - int clear = 1; -#endif - - print_msg(TEST_BREAK, __FUNCTION__); - - file_name = device; - - sg_fd = open(file_name, O_RDONLY); - if (sg_fd < 0) { - perror(ME "open error"); - return 1; - } - /* Don't worry, being very careful not to write to a none-sg file ... */ - res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k); - if ((res < 0) || (k < 30000)) { - printf(ME "not a sg device, or driver prior to 3.x\n"); - return 1; - } - if (do_mmap) { - do_dio = 0; - do_quick = 0; - } - if (NULL == (rawp = malloc(512))) { - printf(ME "out of memory (query)\n"); - return 1; - } - rbBuff = rawp; - - memset(rbCmdBlk, 0, RB_CMD_LEN); - rbCmdBlk[0] = RB_OPCODE; - rbCmdBlk[1] = RB_MODE_DESC; - rbCmdBlk[8] = RB_DESC_LEN; - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(rbCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_buffer); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = RB_DESC_LEN; - io_hdr.dxferp = rbBuff; - io_hdr.cmdp = rbCmdBlk; - io_hdr.sbp = sense_buffer; - io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ - /* do normal IO to find RB size (not dio or mmap-ed at this stage) */ - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror(ME "SG_IO READ BUFFER descriptor error"); - if (rawp) - free(rawp); - return 1; - } - - /* now for the error processing */ - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - printf - ("Recovered error on READ BUFFER descriptor, continuing\n"); - break; - default: /* won't bother decoding other categories */ - sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr); - if (rawp) - free(rawp); - return 1; - } - - buf_capacity = ((rbBuff[1] << 16) | (rbBuff[2] << 8) | rbBuff[3]); - printf("READ BUFFER reports: buffer capacity=%d, offset boundary=%d\n", - buf_capacity, (int)rbBuff[0]); - - if (0 == buf_size) - buf_size = buf_capacity; - else if (buf_size > buf_capacity) { - printf - ("Requested buffer size=%d exceeds reported capacity=%d\n", - buf_size, buf_capacity); - if (rawp) - free(rawp); - return 1; - } - if (rawp) { - free(rawp); - rawp = NULL; - } - - if (!do_dio) { - k = buf_size; - if (do_mmap && (0 != (k % psz))) - k = ((k / psz) + 1) * psz; /* round up to page size */ - res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, &k); - if (res < 0) - perror(ME "SG_SET_RESERVED_SIZE error"); - } - - if (do_mmap) { - rbBuff = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, sg_fd, 0); - if (MAP_FAILED == rbBuff) { - if (ENOMEM == errno) - printf(ME "mmap() out of memory, try a smaller " - "buffer size than %d KB\n", - buf_size / 1024); - else - perror(ME "error using mmap()"); - return 1; - } - } else { /* non mmap-ed IO */ - rawp = malloc(buf_size + (do_dio ? psz : 0)); - if (NULL == rawp) { - printf(ME "out of memory (data)\n"); - return 1; - } - if (do_dio) /* align to page boundary */ - rbBuff = - (unsigned char *)(((unsigned long)rawp + psz - 1) & - (~(psz - 1))); - else - rbBuff = rawp; - } - - num = (total_size_mb * 1024U * 1024U) / (unsigned int)buf_size; - if (do_time) { - start_tm.tv_sec = 0; - start_tm.tv_usec = 0; - gettimeofday(&start_tm, NULL); - } - /* main data reading loop */ - for (k = 0; k < num; ++k) { - memset(rbCmdBlk, 0, RB_CMD_LEN); - rbCmdBlk[0] = RB_OPCODE; - rbCmdBlk[1] = RB_MODE_DATA; - rbCmdBlk[6] = 0xff & (buf_size >> 16); - rbCmdBlk[7] = 0xff & (buf_size >> 8); - rbCmdBlk[8] = 0xff & buf_size; -#ifdef SG_DEBUG - memset(rbBuff, 0, buf_size); -#endif - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(rbCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_buffer); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = buf_size; - if (!do_mmap) - io_hdr.dxferp = rbBuff; - io_hdr.cmdp = rbCmdBlk; - io_hdr.sbp = sense_buffer; - io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ - io_hdr.pack_id = k; - if (do_mmap) - io_hdr.flags |= SG_FLAG_MMAP_IO; - else if (do_dio) - io_hdr.flags |= SG_FLAG_DIRECT_IO; - else if (do_quick) - io_hdr.flags |= SG_FLAG_NO_DXFER; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - if (ENOMEM == errno) - printf(ME - "SG_IO data; out of memory, try a smaller " - "buffer size than %d KB\n", - buf_size / 1024); - else - perror(ME "SG_IO READ BUFFER data error"); - if (rawp) - free(rawp); - return 1; - } - - /* now for the error processing */ - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - printf - ("Recovered error on READ BUFFER data, continuing\n"); - break; - default: /* won't bother decoding other categories */ - sg_chk_n_print3("READ BUFFER data error", &io_hdr); - if (rawp) - free(rawp); - return 1; - } - if (do_dio && - ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != - SG_INFO_DIRECT_IO)) - dio_incomplete = 1; /* flag that dio not done (completely) */ - -#ifdef SG_DEBUG - if (clear) { - for (j = 0; j < buf_size; ++j) { - if (rbBuff[j] != 0) { - clear = 0; - break; - } - } - } -#endif - } - if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { - struct timeval res_tm; - double a, b; - - gettimeofday(&end_tm, NULL); - res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; - res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; - if (res_tm.tv_usec < 0) { - --res_tm.tv_sec; - res_tm.tv_usec += 1000000; - } - a = res_tm.tv_sec; - a += (0.000001 * res_tm.tv_usec); - b = (double)buf_size *num; - printf("time to read data from buffer was %d.%06d secs", - (int)res_tm.tv_sec, (int)res_tm.tv_usec); - if ((a > 0.00001) && (b > 511)) - printf(", %.2f MB/sec\n", b / (a * 1000000.0)); - else - printf("\n"); - } - if (dio_incomplete) - printf(">> direct IO requested but not done\n"); - printf - ("Read %u MBytes (actual %u MB, %u bytes), buffer size=%d KBytes\n", - total_size_mb, (num * buf_size) / 1048576, num * buf_size, - buf_size / 1024); - - if (rawp) - free(rawp); - res = close(sg_fd); - if (res < 0) { - perror(ME "close error"); - return 0; - } -#ifdef SG_DEBUG - if (clear) - printf("read buffer always zero\n"); - else - printf("read buffer non-zero\n"); -#endif - return 0; -} - -/* Performs a 10 byte READ CAPACITY command and fetches response. There is - * evidently a 16 byte READ CAPACITY command coming. - * Return of 0 -> success, -1 -> failure */ -int do_readcap_10(int sg_fd, int pmi, unsigned int lba, - unsigned int *last_sect, unsigned int *sect_sz) -{ - int res; - unsigned char rcCmdBlk[10] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char rcBuff[RCAP_REPLY_LEN]; - unsigned char sense_b[SENSE_BUFF_SZ]; - sg_io_hdr_t io_hdr; - - if (pmi) { /* lbs only valid when pmi set */ - rcCmdBlk[8] |= 1; - rcCmdBlk[2] = (lba >> 24) & 0xff; - rcCmdBlk[3] = (lba >> 16) & 0xff; - rcCmdBlk[4] = (lba >> 8) & 0xff; - rcCmdBlk[5] = lba & 0xff; - } - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(rcCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = sizeof(rcBuff); - io_hdr.dxferp = rcBuff; - io_hdr.cmdp = rcCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = 60000; - - while (1) { - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("read_capacity (SG_IO) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - if (SG_ERR_CAT_MEDIA_CHANGED == res) - continue; - else if (SG_ERR_CAT_CLEAN != res) { - sg_chk_n_print3("READ CAPACITY command error", &io_hdr); - return -1; - } else - break; - } - *last_sect = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | - (rcBuff[2] << 8) | rcBuff[3]); - *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | - (rcBuff[6] << 8) | rcBuff[7]; - return 0; -} - -int show_scsi_read_capacity(char *device) -{ - int sg_fd, k, res; - unsigned int lba = 0; - int pmi = 1; - unsigned int last_blk_addr, block_size; - char ebuff[EBUFF_SZ]; - const char *file_name = 0; - - print_msg(TEST_BREAK, __FUNCTION__); - - file_name = device; - - if ((0 == pmi) && (lba > 0)) { - fprintf(stderr, - ME "lba can only be non-zero when pmi is set\n"); - usage(); - return 1; - } - if ((sg_fd = open(file_name, O_RDONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", - file_name); - perror(ebuff); - return 1; - } - /* Just to be safe, check we have a new sg device by trying an ioctl */ - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { - printf(ME "%s doesn't seem to be a version 3 sg device\n", - file_name); - close(sg_fd); - return 1; - } - res = do_readcap_10(sg_fd, pmi, lba, &last_blk_addr, &block_size); - - if (0 == res) { - printf("Read Capacity results:\n"); - if (pmi) - printf(" PMI mode: given lba=0x%x, last block before " - "delay=0x%x\n", lba, last_blk_addr); - else - printf - (" Last block address=%u (0x%x), Number of blocks=%u\n", - last_blk_addr, last_blk_addr, last_blk_addr + 1); - printf(" Block size = %u bytes\n", block_size); - } - close(sg_fd); - return 0; -} - -int do_scsi_reset_devices(char *device, int reset_opt) -{ - int sg_fd, res, k; - int do_device_reset = 0; - int do_bus_reset = 0; - int do_host_reset = 0; - char *file_name = 0; - - switch (reset_opt) { - case DEVICE_RESET: - print_msg(TEST_BREAK, __FUNCTION__); - do_device_reset = 1; - break; - case HOST_RESET: - do_host_reset = 1; - break; - case BUS_RESET: - do_bus_reset = 1; - break; - } - - file_name = device; - - sg_fd = open(file_name, O_RDWR | O_NONBLOCK); - if (sg_fd < 0) { - perror("sg_reset: open error"); - return 1; - } - - k = SG_SCSI_RESET_NOTHING; - if (do_device_reset) { - printf("sg_reset: starting device reset\n"); - k = SG_SCSI_RESET_DEVICE; - } else if (do_bus_reset) { - printf("sg_reset: starting bus reset\n"); - k = SG_SCSI_RESET_BUS; - } else if (do_host_reset) { - printf("sg_reset: starting host reset\n"); - k = SG_SCSI_RESET_HOST; - } - - res = ioctl(sg_fd, SG_SCSI_RESET, &k); - if (res < 0) { - if (EBUSY == errno) - printf("sg_reset: BUSY, may be resetting now\n"); - else if (EIO == errno) - printf - ("sg_reset: requested type of reset may not be available\n"); - else if (EACCES == errno) - printf("sg_reset: reset requires CAP_SYS_ADMIN (root) " - "permission\n"); - else if (EINVAL == errno) - printf("sg_reset: SG_SCSI_RESET not supported\n"); - else if (EIO == errno) - printf("sg_reset: scsi_reset_provider() call failed\n"); - else - perror("sg_reset: SG_SCSI_RESET failed"); - return 1; - } - if (SG_SCSI_RESET_NOTHING == k) - printf("sg_reset: did nothing, device is normal mode\n"); - else if (SG_SCSI_RESET_DEVICE == k) - printf("sg_reset: completed device reset\n"); - else if (SG_SCSI_RESET_BUS == k) - printf("sg_reset: completed bus reset\n"); - else if (SG_SCSI_RESET_HOST == k) - printf("sg_reset: completed host reset\n"); - - if (close(sg_fd) < 0) { - perror("sg_reset: close error"); - return 1; - } - return 0; -} - -static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit, - int devofl_bit, int unitofl_bit, void *outgoing_pg, - int outgoing_len, int noisy) -{ - int res; - unsigned char senddiagCmdBlk[SEND_DIAGNOSTIC_CMDLEN] = - { SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - senddiagCmdBlk[1] = (unsigned char)((sf_code << 5) | (pf_bit << 4) | - (sf_bit << 2) | (devofl_bit << 1) | - unitofl_bit); - senddiagCmdBlk[3] = (unsigned char)((outgoing_len >> 8) & 0xff); - senddiagCmdBlk[4] = (unsigned char)(outgoing_len & 0xff); - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = SEND_DIAGNOSTIC_CMDLEN; - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = outgoing_len ? SG_DXFER_TO_DEV : SG_DXFER_NONE; - io_hdr.dxfer_len = outgoing_len; - io_hdr.dxferp = outgoing_pg; - io_hdr.cmdp = senddiagCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = LONG_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (send diagnostic) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, - "Send diagnostic error, sf_code=0x%x, " - "pf_bit=%d, sf_bit=%d ", sf_code, pf_bit, - sf_bit); - sg_chk_n_print3(ebuff, &io_hdr); - } - return -1; - } -} - -static int do_rcvdiag(int sg_fd, int pcv, int pg_code, void *resp, - int mx_resp_len, int noisy) -{ - int res; - unsigned char rcvdiagCmdBlk[RECEIVE_DIAGNOSTIC_CMDLEN] = - { RECEIVE_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - - rcvdiagCmdBlk[1] = (unsigned char)(pcv ? 0x1 : 0); - rcvdiagCmdBlk[2] = (unsigned char)(pg_code); - rcvdiagCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff); - rcvdiagCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = RECEIVE_DIAGNOSTIC_CMDLEN; - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = rcvdiagCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (receive diagnostic) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, - "Receive diagnostic error, pcv=%d, " - "page_code=%x ", pcv, pg_code); - sg_chk_n_print3(ebuff, &io_hdr); - } - return -1; - } -} - -/* Get last extended self-test time from mode page 0xa (for '-e' option) */ -static int do_modes_0a(int sg_fd, void *resp, int mx_resp_len, int noisy, - int mode6) -{ - int res; - unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] = - { MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char sense_b[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - int dbd = 1; - int pc = 0; - int pg_code = 0xa; - - modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0); - modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); - if (mx_resp_len > (mode6 ? 0xff : 0xffff)) { - printf(ME "mx_resp_len too big\n"); - return -1; - } - if (mode6) { - modesCmdBlk[0] = MODE_SENSE6_CMD; - modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); - } else { - modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); - modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); - } - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = mode6 ? MODE_SENSE6_CMDLEN : MODE_SENSE10_CMDLEN; - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = mx_resp_len; - io_hdr.dxferp = resp; - io_hdr.cmdp = modesCmdBlk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_TIMEOUT; - - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("SG_IO (mode sense) error"); - return -1; - } - res = sg_err_category3(&io_hdr); - switch (res) { - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - return 0; - default: - if (noisy) { - char ebuff[EBUFF_SZ]; - snprintf(ebuff, EBUFF_SZ, "Mode sense error, dbd=%d, " - "pc=%d, page_code=%x ", dbd, pc, pg_code); - sg_chk_n_print3(ebuff, &io_hdr); - } - return -1; - } -} - -int do_scsi_send_diagnostics(char *device) -{ - int sg_fd, k, num, rsp_len; - char *file_name = 0; - unsigned char rsp_buff[MODE_ALLOC_LEN]; - int rsp_buff_size = MODE_ALLOC_LEN; - int self_test_code = 6; - int do_pf = 0; - int do_doff = 0; - int do_def_test = 0; - int do_uoff = 0; - int oflags = O_RDWR; - - print_msg(TEST_BREAK, __FUNCTION__); - - file_name = device; - - if ((sg_fd = open(file_name, oflags)) < 0) { - snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", - file_name); - perror(ebuff); - return 1; - } - /* Just to be safe, check we have a new sg device by trying an ioctl */ - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { - printf(ME "%s doesn't seem to be a version 3 sg device\n", - file_name); - close(sg_fd); - return 1; - } - - if (0 == do_modes_0a(sg_fd, rsp_buff, 32, 1, 0)) { - /* Assume mode sense(10) response without block descriptors */ - num = (rsp_buff[0] << 8) + rsp_buff[1] - 6; - if (num >= 0xc) { - int secs; - - secs = (rsp_buff[18] << 8) + rsp_buff[19]; - printf - ("Previous extended self-test duration=%d seconds " - "(%.2f minutes)\n", secs, secs / 60.0); - } else - printf("Extended self-test duration not available\n"); - } else - printf("Extended self-test duration (mode page 0xa) failed\n"); - - memset(rsp_buff, 0, sizeof(rsp_buff)); - if (0 == do_senddiag(sg_fd, 0, do_pf, 0, 0, 0, rsp_buff, 4, 1)) { - if (0 == do_rcvdiag(sg_fd, 0, 0, rsp_buff, rsp_buff_size, 1)) { - printf("Supported diagnostic pages response:\n"); - rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4; - for (k = 0; k < (rsp_len - 4); ++k) - printf(" %s\n", - find_page_code_desc(rsp_buff[k + 4], 0)); - } - } - - if (0 == do_senddiag(sg_fd, self_test_code, do_pf, do_def_test, - do_doff, do_uoff, NULL, 0, 1)) { - if ((5 == self_test_code) || (6 == self_test_code)) - printf("Foreground self test returned GOOD status\n"); - else if (do_def_test && (!do_doff) && (!do_uoff)) - printf("Default self test returned GOOD status\n"); - } - close(sg_fd); - return 0; -} - -static void do_start_stop(int fd, int start, int immed, int loej, - int power_conditions) -{ - unsigned char cmdblk[6] = { - START_STOP, /* Command */ - 0, /* Resvd/Immed */ - 0, /* Reserved */ - 0, /* Reserved */ - 0, /* PowCond/Resvd/LoEj/Start */ - 0 - }; /* Reserved/Flag/Link */ - unsigned char sense_b[32]; - sg_io_hdr_t io_hdr; - int k, res, debug = 1; - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - cmdblk[1] = immed & 1; - cmdblk[4] = ((power_conditions & 0xf) << 4) | - ((loej & 1) << 1) | (start & 1); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(cmdblk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_NONE; - io_hdr.dxfer_len = 0; - io_hdr.dxferp = NULL; - io_hdr.cmdp = cmdblk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_START_TIMEOUT; - - if (debug) { - printf(" Start/Stop command:"); - for (k = 0; k < 6; ++k) - printf(" %02x", cmdblk[k]); - printf("\n"); - } - - if (ioctl(fd, SG_IO, &io_hdr) < 0) { - perror("start_stop (SG_IO) error"); - return; - } - res = sg_err_category3(&io_hdr); - if (SG_ERR_CAT_MEDIA_CHANGED == res) { - fprintf(stderr, "media change report, try start_stop again\n"); - if (ioctl(fd, SG_IO, &io_hdr) < 0) { - perror("start_stop (SG_IO) error"); - return; - } - } - if (SG_ERR_CAT_CLEAN != res) { - sg_chk_n_print3("start_stop", &io_hdr); - return; - } - if (debug) - fprintf(stderr, "start_stop [%s] successful\n", - start ? "start" : "stop"); -} - -static void do_sync_cache(int fd) -{ - unsigned char cmdblk[10] = { - SYNCHRONIZE_CACHE, /* Command */ - 0, /* Immed (2) */ - 0, 0, 0, 0, /* LBA */ - 0, /* Reserved */ - 0, 0, /* No of blocks */ - 0 - }; /* Reserved/Flag/Link */ - unsigned char sense_b[32]; - sg_io_hdr_t io_hdr; - int res, debug = 1; - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(cmdblk); - io_hdr.mx_sb_len = sizeof(sense_b); - io_hdr.dxfer_direction = SG_DXFER_NONE; - io_hdr.dxfer_len = 0; - io_hdr.dxferp = NULL; - io_hdr.cmdp = cmdblk; - io_hdr.sbp = sense_b; - io_hdr.timeout = DEF_START_TIMEOUT; - - if (ioctl(fd, SG_IO, &io_hdr) < 0) { - perror("sync_cache (SG_IO) error"); - return; - } - res = sg_err_category3(&io_hdr); - if (SG_ERR_CAT_MEDIA_CHANGED == res) { - fprintf(stderr, "media change report, try sync_cache again\n"); - if (ioctl(fd, SG_IO, &io_hdr) < 0) { - perror("sync_cache (SG_IO) error"); - return; - } - } - if (SG_ERR_CAT_CLEAN != res) { - sg_chk_n_print3("sync_cache", &io_hdr); - return; - } - if (debug) - fprintf(stderr, "synchronize cache successful\n"); -} - -int do_scsi_start_stop(char *device, int startstop) -{ - int synccache = 1; - char *file_name = 0; - int fd; - int immed = 1; - int loej = 0; - int power_conds = 0; - - print_msg(TEST_BREAK, __FUNCTION__); - - file_name = device; - - fd = open(file_name, O_RDWR | O_NONBLOCK); - if (fd < 0) { - fprintf(stderr, "Error trying to open %s\n", file_name); - perror(""); - usage(); - return 2; - } - if (ioctl(fd, SG_GET_TIMEOUT, 0) < 0) { - fprintf(stderr, "Given file not block or SCSI " - "generic device\n"); - close(fd); - return 3; - } - - if (synccache) - do_sync_cache(fd); - - if (power_conds > 0) - do_start_stop(fd, 0, immed, 0, power_conds); - else if (startstop != -1) - do_start_stop(fd, startstop, immed, loej, 0); - - close(fd); - return 0; -} - -int find_out_about_buffer(int sg_fd, int *buf_capacity, char *file_name) -{ - int res, buf_granul = 255; - unsigned char *rbBuff = malloc(OFF + sizeof(rbCmdBlk) + 512); - struct sg_header *rsghp = (struct sg_header *)rbBuff; - int rbInLen = OFF + RB_DESC_LEN; - int rbOutLen = OFF + sizeof(rbCmdBlk); - unsigned char *buffp = rbBuff + OFF; - rsghp->pack_len = 0; /* don't care */ - rsghp->pack_id = 0; - rsghp->reply_len = rbInLen; - rsghp->twelve_byte = 0; - rsghp->result = 0; -#ifndef SG_GET_RESERVED_SIZE - rsghp->sense_buffer[0] = 0; -#endif - memcpy(rbBuff + OFF, rbCmdBlk, sizeof(rbCmdBlk)); - rbBuff[OFF + 1] = RB_MODE_DESC; - rbBuff[OFF + 8] = RB_DESC_LEN; - - res = write(sg_fd, rbBuff, rbOutLen); - if (res < 0) { - perror("sg_test_rwbuf: write (desc) error"); - if (rbBuff) - free(rbBuff); - return 1; - } - if (res < rbOutLen) { - printf("sg_test_rwbuf: wrote less (desc), ask=%d, got=%d\n", - rbOutLen, res); - if (rbBuff) - free(rbBuff); - return 1; - } - - memset(rbBuff + OFF, 0, RB_DESC_LEN); - res = read(sg_fd, rbBuff, rbInLen); - if (res < 0) { - perror("sg_test_rwbuf: read (desc) error"); - if (rbBuff) - free(rbBuff); - return 1; - } - if (res < rbInLen) { - printf("sg_test_rwbuf: read less (desc), ask=%d, got=%d\n", - rbInLen, res); - if (rbBuff) - free(rbBuff); - return 1; - } -#ifdef SG_GET_RESERVED_SIZE - if (!sg_chk_n_print("sg_test_rwbuf: desc", rsghp->target_status, - rsghp->host_status, rsghp->driver_status, - rsghp->sense_buffer, SG_MAX_SENSE)) { - printf - ("sg_test_rwbuf: perhaps %s doesn't support READ BUFFER\n", - file_name); - if (rbBuff) - free(rbBuff); - return 1; - } -#else - if ((rsghp->result != 0) || (0 != rsghp->sense_buffer[0])) { - printf("sg_test_rwbuf: read(desc) result=%d\n", rsghp->result); - if (0 != rsghp->sense_buffer[0]) - sg_print_sense("sg_test_rwbuf: desc", - rsghp->sense_buffer, SG_MAX_SENSE); - printf - ("sg_test_rwbuf: perhaps %s doesn't support READ BUFFER\n", - file_name); - if (rbBuff) - free(rbBuff); - return 1; - } -#endif - *(buf_capacity) = ((buffp[1] << 16) | (buffp[2] << 8) | buffp[3]); - buf_granul = (unsigned char)buffp[0]; - - printf("READ BUFFER reports: %02x %02x %02x %02x %02x %02x %02x %02x\n", - buffp[0], buffp[1], buffp[2], buffp[3], - buffp[4], buffp[5], buffp[6], buffp[7]); - - printf("READ BUFFER reports: buffer capacity=%d, offset boundary=%d\n", - *(buf_capacity), buf_granul); -#ifdef SG_DEF_RESERVED_SIZE - res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, buf_capacity); - if (res < 0) - perror("sg_test_rwbuf: SG_SET_RESERVED_SIZE error"); -#endif - return 0; -} - -int mymemcmp(unsigned char *bf1, unsigned char *bf2, int len) -{ - int df; - for (df = 0; df < len; df++) - if (bf1[df] != bf2[df]) - return df; - return 0; -} - -int do_checksum(int *buf, int len, int quiet) -{ - int sum = base; - int i; - int rln = len; - for (i = 0; i < len / BPI; i++) - sum += buf[i]; - while (rln % BPI) - sum += ((char *)buf)[--rln]; - if (sum != READWRITE_BASE_NUM) { - if (!quiet) - printf("sg_test_rwbuf: Checksum error (sz=%i): %08x\n", - len, sum); - if (cmpbuf && !quiet) { - int diff = mymemcmp(cmpbuf, (unsigned char *)buf, len); - printf("Differ at pos %i/%i:\n", diff, len); - for (i = 0; i < 24 && i + diff < len; i++) - printf(" %02x", cmpbuf[i + diff]); - printf("\n"); - for (i = 0; i < 24 && i + diff < len; i++) - printf(" %02x", - ((unsigned char *)buf)[i + diff]); - printf("\n"); - } - return 2; - } else - return 0; -} - -void do_fill_buffer(int *buf, int len) -{ - int sum; - int i; - int rln = len; - srand(time(0)); -retry: - if (len >= BPI) - base = READWRITE_BASE_NUM + rand(); - else - base = READWRITE_BASE_NUM + (char)rand(); - sum = base; - for (i = 0; i < len / BPI - 1; i++) { - /* we rely on rand() giving full range of int */ - buf[i] = rand(); - sum += buf[i]; - } - while (rln % BPI) { - ((char *)buf)[--rln] = rand(); - sum += ((char *)buf)[rln]; - } - if (len >= BPI) - buf[len / BPI - 1] = READWRITE_BASE_NUM - sum; - else - ((char *)buf)[0] = READWRITE_BASE_NUM + ((char *)buf)[0] - sum; - if (do_checksum(buf, len, 1)) { - if (len < BPI) - goto retry; - printf("sg_test_rwbuf: Memory corruption?\n"); - exit(1); - } - if (cmpbuf) - memcpy(cmpbuf, (char *)buf, len); -} - -int read_buffer(int sg_fd, unsigned size) -{ - int res; - unsigned char *rbBuff = malloc(OFF + sizeof(rbCmdBlk) + size); - struct sg_header *rsghp = (struct sg_header *)rbBuff; - - int rbInLen = OFF + size; - int rbOutLen = OFF + sizeof(rbCmdBlk); - memset(rbBuff, 0, OFF + sizeof(rbCmdBlk) + size); - rsghp->pack_len = 0; /* don't care */ - rsghp->reply_len = rbInLen; - rsghp->twelve_byte = 0; - rsghp->result = 0; - memcpy(rbBuff + OFF, rbCmdBlk, sizeof(rbCmdBlk)); - rbBuff[OFF + 1] = RB_MODE_DATA; - rbBuff[OFF + 6] = 0xff & ((size) >> 16); - rbBuff[OFF + 7] = 0xff & ((size) >> 8); - rbBuff[OFF + 8] = 0xff & (size); - - rsghp->pack_id = 2; - res = write(sg_fd, rbBuff, rbOutLen); - if (res < 0) { - perror("sg_test_rwbuf: write (data) error"); - if (rbBuff) - free(rbBuff); - return 1; - } - if (res < rbOutLen) { - printf("sg_test_rwbuf: wrote less (data), ask=%d, got=%d\n", - rbOutLen, res); - if (rbBuff) - free(rbBuff); - return 1; - } - - res = read(sg_fd, rbBuff, rbInLen); - if (res < 0) { - perror("sg_test_rwbuf: read (data) error"); - if (rbBuff) - free(rbBuff); - return 1; - } - if (res < rbInLen) { - printf("sg_test_rwbuf: read less (data), ask=%d, got=%d\n", - rbInLen, res); - if (rbBuff) - free(rbBuff); - return 1; - } - res = do_checksum((int *)(rbBuff + OFF), size, 0); - if (rbBuff) - free(rbBuff); - return res; -} - -int write_buffer(int sg_fd, unsigned size) -{ - int res; - unsigned char *rbBuff = malloc(OFF + sizeof(rbCmdBlk) + size); - struct sg_header *rsghp = (struct sg_header *)rbBuff; - //unsigned char * buffp = rbBuff + OFF; - - int rbInLen = OFF; - int rbOutLen = OFF + sizeof(rbCmdBlk) + size; - - do_fill_buffer((int *)(rbBuff + OFF + sizeof(rbCmdBlk)), size); - rsghp->pack_len = 0; /* don't care */ - rsghp->reply_len = rbInLen; - rsghp->twelve_byte = 0; - rsghp->result = 0; - memcpy(rbBuff + OFF, rbCmdBlk, sizeof(rbCmdBlk)); - rbBuff[OFF + 0] = WRITE_BUFFER; - rbBuff[OFF + 1] = RB_MODE_DATA; - rbBuff[OFF + 6] = 0xff & ((size) >> 16); - rbBuff[OFF + 7] = 0xff & ((size) >> 8); - rbBuff[OFF + 8] = 0xff & (size); - - rsghp->pack_id = 1; - res = write(sg_fd, rbBuff, rbOutLen); - if (res < 0) { - perror("sg_test_rwbuf: write (data) error"); - if (rbBuff) - free(rbBuff); - return 1; - } - if (res < rbOutLen) { - printf("sg_test_rwbuf: wrote less (data), ask=%d, got=%d\n", - rbOutLen, res); - if (rbBuff) - free(rbBuff); - return 1; - } - - res = read(sg_fd, rbBuff, rbInLen); - if (res < 0) { - perror("sg_test_rwbuf: read (status) error"); - if (rbBuff) - free(rbBuff); - return 1; - } - if (rbBuff) - free(rbBuff); - return 0; -} - -int do_scsi_read_write_buffer(char *device) -{ - int sg_fd; - int res, buf_capacity; - char *file_name = device; - struct stat a_st; - int block_dev = 0; - - print_msg(TEST_BREAK, __FUNCTION__); - - sg_fd = open(file_name, O_RDWR); - if (sg_fd < 0) { - perror("sg_test_rwbuf: open error"); - return 1; - } - if (fstat(sg_fd, &a_st) < 0) { - fprintf(stderr, "could do fstat() on fd ??\n"); - close(sg_fd); - return 1; - } - if (S_ISBLK(a_st.st_mode)) - block_dev = 1; - /* Don't worry, being very careful not to write to a none-sg file ... */ - if (block_dev || (ioctl(sg_fd, SG_GET_TIMEOUT, 0) < 0)) { - /* perror("ioctl on generic device, error"); */ - printf("sg_test_rwbuf: not a sg device, or wrong driver\n"); - return 1; - } - if (find_out_about_buffer(sg_fd, &buf_capacity, file_name)) - return 1; - - cmpbuf = malloc(buf_capacity); - if (write_buffer(sg_fd, buf_capacity)) - return 3; - res = read_buffer(sg_fd, buf_capacity); - if (res) - return (res + 4); - - res = close(sg_fd); - if (res < 0) { - perror("sg_test_rwbuf: close error"); - return 6; - } - printf("Success\n"); - return 0; -} - -int do_scsi_test_unit_ready(char *device) -{ - int sg_fd, k; - unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 }; - sg_io_hdr_t io_hdr; - char *file_name = device; - char ebuff[EBUFF_SZ]; - unsigned char sense_buffer[32]; - int num_turs = 10240; - int num_errs = 0; - int do_time = 1; - struct timeval start_tm, end_tm; - - print_msg(TEST_BREAK, __FUNCTION__); - - if ((sg_fd = open(file_name, O_RDONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, - "sg_turs: error opening file: %s", file_name); - perror(ebuff); - return 1; - } - /* Just to be safe, check we have a new sg driver by trying an ioctl */ - if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { - printf - ("sg_turs: %s isn't an sg device (or the sg driver is old)\n", - file_name); - close(sg_fd); - return 1; - } - /* Prepare TEST UNIT READY command */ - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(turCmdBlk); - io_hdr.mx_sb_len = sizeof(sense_buffer); - io_hdr.dxfer_direction = SG_DXFER_NONE; - io_hdr.cmdp = turCmdBlk; - io_hdr.sbp = sense_buffer; - io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ - if (do_time) { - start_tm.tv_sec = 0; - start_tm.tv_usec = 0; - gettimeofday(&start_tm, NULL); - } - for (k = 0; k < num_turs; ++k) { - io_hdr.pack_id = k; - if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { - perror("sg_turs: Test Unit Ready SG_IO ioctl error"); - close(sg_fd); - return 1; - } - if (io_hdr.info & SG_INFO_OK_MASK) { - ++num_errs; - if (1 == num_turs) { /* then print out the error message */ - if (SG_ERR_CAT_CLEAN != - sg_err_category3(&io_hdr)) - sg_chk_n_print3("tur", &io_hdr); - } - } - } - if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { - struct timeval res_tm; - double a, b; - - gettimeofday(&end_tm, NULL); - res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; - res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; - if (res_tm.tv_usec < 0) { - --res_tm.tv_sec; - res_tm.tv_usec += 1000000; - } - a = res_tm.tv_sec; - a += (0.000001 * res_tm.tv_usec); - b = (double)num_turs; - printf("time to perform commands was %d.%06d secs", - (int)res_tm.tv_sec, (int)res_tm.tv_usec); - if (a > 0.00001) - printf("; %.2f operations/sec\n", b / a); - else - printf("\n"); - } - - printf("Completed %d Test Unit Ready commands with %d errors\n", - num_turs, num_errs); - close(sg_fd); - return 0; -} - -/* Returns 0 -> ok, 1 -> err, 2 -> recovered error */ -static int do_sg_io(int sg_fd, unsigned char *buff) -{ -/* N.B. Assuming buff contains pointer 'buffer' or 'buffer1' */ - struct sg_header *sghp = (struct sg_header *)(buff - OFF); - int res; - - sghp->pack_len = 0; - sghp->reply_len = SG_HSZ + *(((int *)buff) + 1); - sghp->pack_id = 0; - sghp->twelve_byte = 0; - sghp->other_flags = 0; -#ifndef SG_GET_RESERVED_SIZE - sghp->sense_buffer[0] = 0; -#endif -#if 0 - sg_print_command(buff + 8); - printf(" write_len=%d, read_len=%d\n", - SG_HSZ + sg_get_command_size(buff[8]) + *((int *)buff), - sghp->reply_len); -#endif - res = write(sg_fd, (const void *)sghp, - SG_HSZ + sg_get_command_size(buff[8]) + *((int *)buff)); - if (res < 0) { -#ifdef SG_IO_DEBUG - perror("write to sg failed"); -#endif - return 1; - } - res = read(sg_fd, (void *)sghp, sghp->reply_len); - if (res < 0) { -#ifdef SG_IO_DEBUG - perror("read from sg failed"); -#endif - return 1; - } -#ifdef SG_GET_RESERVED_SIZE - res = sg_err_category(sghp->target_status, sghp->host_status, - sghp->driver_status, sghp->sense_buffer, - SG_MAX_SENSE); - switch (res) { - case SG_ERR_CAT_CLEAN: - return 0; - case SG_ERR_CAT_RECOVERED: - return 2; - default: -#ifdef SG_IO_DEBUG - sg_chk_n_print("read from sg", sghp->target_status, - sghp->host_status, sghp->driver_status, - sghp->sense_buffer, SG_MAX_SENSE); -#endif - return 1; - } -#else - if (0 != sghp->sense_buffer[0]) { -#ifdef SG_IO_DEBUG - int k; - printf("read from sg, sense buffer (in hex):\n "); - for (k = 0; k < 16; ++k) - printf("%02x ", (int)sghp->sense_buffer[k]); - printf("\n"); -#endif - return 1; - } else if (0 != sghp->result) { -#ifdef SG_IO_DEBUG - printf("read from sg, bad result=%d\n", sghp->result); -#endif - return 1; - } else - return 0; -#endif -} - -static char *get_page_name(int pageno) -{ - if ((pageno <= 0) || (pageno >= MAX_PAGENO) || (!page_names[pageno])) - return "Mode"; - return page_names[pageno]; -} - -static int getnbyte(unsigned char *pnt, int nbyte) -{ - unsigned int result; - int i; - result = 0; - for (i = 0; i < nbyte; i++) - result = (result << 8) | (pnt[i] & 0xff); - return result; -} - -static void bitfield(unsigned char *pageaddr, char *text, int mask, int shift) -{ - printf("%-35s%d\n", text, (*pageaddr >> shift) & mask); -} - -static void notbitfield(unsigned char *pageaddr, char *text, int mask, - int shift) -{ - printf("%-35s%d\n", text, !((*pageaddr >> shift) & mask)); -} - -static void intfield(unsigned char *pageaddr, int nbytes, char *text) -{ - printf("%-35s%d\n", text, getnbyte(pageaddr, nbytes)); -} - -static void hexfield(unsigned char *pageaddr, int nbytes, char *text) -{ - printf("%-35s0x%x\n", text, getnbyte(pageaddr, nbytes)); -} - -static void hexdatafield(unsigned char *pageaddr, int nbytes, char *text) -{ - printf("%-35s0x", text); - while (nbytes-- > 0) - printf("%02x", *pageaddr++); - putchar('\n'); -} - -static int get_mode_page(int page, int page_code) -{ - int status, quiet; - unsigned char *cmd; - - memset(buffer, 0, SIZEOF_BUFFER); - - quiet = page_code & ~3; - page_code &= 3; - - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = 0xff; /* length of output data */ - - cmd = (unsigned char *)(((int *)buffer) + 2); - - cmd[0] = MODE_SENSE; /* MODE SENSE (6) */ - cmd[1] = 0x00; /* lun = 0, inhibitting BD makes this fail - for me */ - cmd[2] = (page_code << 6) | page; - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = (unsigned char)0xff; /* allocation length */ - cmd[5] = 0x00; /* control */ - - status = do_sg_io(glob_fd, buffer); - if (status && (!quiet)) - fprintf(stdout, ">>> Unable to read %s Page %02xh\n", - get_page_name(page), page); - //dump (buffer+2, 46); - return status; -} - -/* Same as above, but this time with MODE_SENSE_10 */ -static int get_mode_page10(int page, int page_code) -{ - int status, quiet; - unsigned char *cmd; - - memset(buffer, 0, SIZEOF_BUFFER); - - quiet = page_code & ~3; - page_code &= 3; - - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = 0xffff; /* length of output buffer */ - - cmd = (unsigned char *)(((int *)buffer) + 2); - - cmd[0] = MODE_SENSE_10; /* MODE SENSE (10) */ - cmd[1] = 0x00; /* lun = 0, inhibitting BD makes this fail - for me */ - cmd[2] = (page_code << 6) | page; - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0x00; /* (reserved) */ - cmd[5] = 0x00; /* (reserved) */ - cmd[6] = 0x00; /* (reserved) */ - cmd[7] = 0xff; /* allocation length hi */ - cmd[8] = 0xff; /* allocation length lo */ - cmd[9] = 0x00; /* control */ - - status = do_sg_io(glob_fd, buffer); - if (status && (!quiet)) - fprintf(stdout, - ">>> Unable to read %s Page %02xh with MODESENSE(10)\n", - get_page_name(page), page); - return status; -} - -/* Contents should point to the mode parameter header that we obtained - in a prior read operation. This way we do not have to work out the - format of the beast */ - -static int read_geometry(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(4, 9); - - printf("Data from Rigid Disk Drive Geometry Page\n"); - printf("----------------------------------------\n"); - intfield(pagestart + 2, 3, "Number of cylinders"); - intfield(pagestart + 5, 1, "Number of heads"); - intfield(pagestart + 6, 3, "Starting write precomp"); - intfield(pagestart + 9, 3, "Starting reduced current"); - intfield(pagestart + 12, 2, "Drive step rate"); - intfield(pagestart + 14, 3, "Landing Zone Cylinder"); - bitfield(pagestart + 17, "RPL", 3, 0); - intfield(pagestart + 18, 1, "Rotational Offset"); - intfield(pagestart + 20, 2, "Rotational Rate"); - printf("\n"); - return 0; - -} - -static int read_disconnect_reconnect_data(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(2, 7); - - printf("Data from Disconnect-Reconnect Page\n"); - printf("-----------------------------------\n"); - intfield(pagestart + 2, 1, "Buffer full ratio"); - intfield(pagestart + 3, 1, "Buffer empty ratio"); - intfield(pagestart + 4, 2, "Bus Inactivity Limit"); - intfield(pagestart + 6, 2, "Disconnect Time Limit"); - intfield(pagestart + 8, 2, "Connect Time Limit"); - intfield(pagestart + 10, 2, "Maximum Burst Size"); - hexfield(pagestart + 12, 1, "DTDC"); - printf("\n"); - return 0; - -} - -static int read_control_page(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(10, 9); - - printf("Data from Control Page\n"); - printf("----------------------\n"); - bitfield(pagestart + 2, "RLEC", 1, 0); - bitfield(pagestart + 3, "QErr", 1, 1); - bitfield(pagestart + 3, "DQue", 1, 0); - bitfield(pagestart + 4, "EECA", 1, 7); - bitfield(pagestart + 4, "RAENP", 1, 2); - bitfield(pagestart + 4, "UUAENP", 1, 1); - bitfield(pagestart + 4, "EAENP", 1, 0); - bitfield(pagestart + 3, "Queue Algorithm Modifier", 0xf, 4); - intfield(pagestart + 6, 2, "Ready AEN Holdoff Period"); - printf("\n"); - return 0; - -} - -static int error_recovery_page(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(1, 14); - printf("Data from Error Recovery Page\n"); - printf("-----------------------------\n"); - bitfield(pagestart + 2, "AWRE", 1, 7); - bitfield(pagestart + 2, "ARRE", 1, 6); - bitfield(pagestart + 2, "TB", 1, 5); - bitfield(pagestart + 2, "RC", 1, 4); - bitfield(pagestart + 2, "EER", 1, 3); - bitfield(pagestart + 2, "PER", 1, 2); - bitfield(pagestart + 2, "DTE", 1, 1); - bitfield(pagestart + 2, "DCR", 1, 0); - intfield(pagestart + 3, 1, "Read Retry Count"); - intfield(pagestart + 4, 1, "Correction Span"); - intfield(pagestart + 5, 1, "Head Offset Count"); - intfield(pagestart + 6, 1, "Data Strobe Offset Count"); - intfield(pagestart + 8, 1, "Write Retry Count"); - intfield(pagestart + 10, 2, "Recovery Time Limit"); - printf("\n"); - return 0; -} - -static int notch_parameters_page(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(0xc, 7); - - printf("Data from Notch Parameters Page\n"); - printf("-------------------------------\n"); - bitfield(pagestart + 2, "Notched Drive", 1, 7); - bitfield(pagestart + 2, "Logical or Physical Notch", 1, 6); - intfield(pagestart + 4, 2, "Max # of notches"); - intfield(pagestart + 6, 2, "Active Notch"); - if (pagestart[2] & 0x40) { - intfield(pagestart + 8, 4, "Starting Boundary"); - intfield(pagestart + 12, 4, "Ending Boundary"); - } else { /* Hex is more meaningful for physical notches */ - hexfield(pagestart + 8, 4, "Starting Boundary"); - hexfield(pagestart + 12, 4, "Ending Boundary"); - } - - printf("0x%8.8x%8.8x", getnbyte(pagestart + 16, 4), - getnbyte(pagestart + 20, 4)); - - printf("\n"); - return 0; -} - -static char *formatname(int format) -{ - switch (format) { - case 0x0: - return "logical blocks"; - case 0x4: - return "bytes from index [Cyl:Head:Off]\n" - "Offset -1 marks whole track as bad.\n"; - case 0x5: - return "physical blocks [Cyl:Head:Sect]\n" - "Sector -1 marks whole track as bad.\n"; - } - return "Weird, unknown format"; -} - -static int read_defect_list(int page_code) -{ - int status = 0, i, len, reallen, table, k; - unsigned char *cmd, *df = 0; - int trunc; - - printf("Data from Defect Lists\n" "----------------------\n"); - for (table = 0; table < 2; table++) { - memset(buffer, 0, SIZEOF_BUFFER); - trunc = 0; - - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = 4; /* length of output buffer */ - - cmd = (unsigned char *)(((int *)buffer) + 2); - - cmd[0] = 0x37; /* READ DEFECT DATA */ - cmd[1] = 0x00; /* lun=0 */ - cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0x00; /* (reserved) */ - cmd[5] = 0x00; /* (reserved) */ - cmd[6] = 0x00; /* (reserved) */ - cmd[7] = 0x00; /* Alloc len */ - cmd[8] = 0x04; /* Alloc len */ - cmd[9] = 0x00; /* control */ - - i = do_sg_io(glob_fd, buffer); - if (2 == i) - i = 0; /* Recovered error, probably returned a different - format */ - if (i) { - fprintf(stdout, ">>> Unable to read %s defect data.\n", - (table ? "grown" : "manufacturer")); - status |= i; - continue; - } - len = (buffer[10] << 8) | buffer[11]; - reallen = len; - if (len > 0) { - if (len >= 0xfff8) { - len = SIZEOF_BUFFER - 8; - k = len + 8; /* length of defect list */ - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = k; /* length of output buffer */ - ((struct sg_header *)buffer)->twelve_byte = 1; - cmd[0] = 0xB7; /* READ DEFECT DATA */ - cmd[1] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */ - cmd[2] = 0x00; /* (reserved) */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0x00; /* (reserved) */ - cmd[5] = 0x00; /* (reserved) */ - cmd[6] = 0x00; /* Alloc len */ - cmd[7] = (k >> 16); /* Alloc len */ - cmd[8] = (k >> 8); /* Alloc len */ - cmd[9] = (k & 0xff); /* Alloc len */ - cmd[10] = 0x00; /* reserved */ - cmd[11] = 0x00; /* control */ - i = do_sg_io(glob_fd, buffer); - if (i == 2) - i = 0; - if (i) - goto trytenbyte; - reallen = - (buffer[12] << 24 | buffer[13] << 16 | - buffer[14] << 8 | buffer[15]); - len = reallen; - if (len > SIZEOF_BUFFER - 8) { - len = SIZEOF_BUFFER - 8; - trunc = 1; - } - df = (unsigned char *)(buffer + 16); - } else { -trytenbyte: - if (len > 0xfff8) { - len = 0xfff8; - trunc = 1; - } - k = len + 4; /* length of defect list */ - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = k; /* length of output buffer */ - cmd[0] = 0x37; /* READ DEFECT DATA */ - cmd[1] = 0x00; /* lun=0 */ - cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0x00; /* (reserved) */ - cmd[5] = 0x00; /* (reserved) */ - cmd[6] = 0x00; /* (reserved) */ - cmd[7] = (k >> 8); /* Alloc len */ - cmd[8] = (k & 0xff); /* Alloc len */ - cmd[9] = 0x00; /* control */ - i = do_sg_io(glob_fd, buffer); - df = (unsigned char *)(buffer + 12); - } - } - if (2 == i) - i = 0; /* Recovered error, probably returned a different - format */ - if (i) { - fprintf(stdout, ">>> Unable to read %s defect data.\n", - (table ? "grown" : "manufacturer")); - status |= i; - continue; - } else { - if (table && !status) - printf("\n"); - printf("%d entries (%d bytes) in %s table.\n" - "Format (%x) is: %s\n", - reallen / ((buffer[9] & 7) ? 8 : 4), reallen, - (table ? "grown" : "manufacturer"), - buffer[9] & 7, formatname(buffer[9] & 7)); - i = 0; - if ((buffer[9] & 7) == 4) { - while (len > 0) { - snprintf((char *)buffer, 40, - "%6d:%3u:%8d", getnbyte(df, 3), - df[3], getnbyte(df + 4, 4)); - printf("%19s", (char *)buffer); - len -= 8; - df += 8; - i++; - if (i >= 4) { - printf("\n"); - i = 0; - } else - printf("|"); - } - } else if ((buffer[9] & 7) == 5) { - while (len > 0) { - snprintf((char *)buffer, 40, - "%6d:%2u:%5d", getnbyte(df, 3), - df[3], getnbyte(df + 4, 4)); - printf("%15s", (char *)buffer); - len -= 8; - df += 8; - i++; - if (i >= 5) { - printf("\n"); - i = 0; - } else - printf("|"); - } - } else { - while (len > 0) { - printf("%10d", getnbyte(df, 4)); - len -= 4; - df += 4; - i++; - if (i >= 7) { - printf("\n"); - i = 0; - } else - printf("|"); - } - } - if (i) - printf("\n"); - } - if (trunc) - printf("[truncated]\n"); - } - printf("\n"); - return status; -} - -static int read_cache(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(8, 9); - - printf("Data from Caching Page\n"); - printf("----------------------\n"); - bitfield(pagestart + 2, "Write Cache", 1, 2); - notbitfield(pagestart + 2, "Read Cache", 1, 0); - bitfield(pagestart + 2, "Prefetch units", 1, 1); - bitfield(pagestart + 3, "Demand Read Retention Priority", 0xf, 4); - bitfield(pagestart + 3, "Demand Write Retention Priority", 0xf, 0); - intfield(pagestart + 4, 2, "Disable Pre-fetch Transfer Length"); - intfield(pagestart + 6, 2, "Minimum Pre-fetch"); - intfield(pagestart + 8, 2, "Maximum Pre-fetch"); - intfield(pagestart + 10, 2, "Maximum Pre-fetch Ceiling"); - printf("\n"); - return 0; -} - -static int read_format_info(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(3, 13); - - printf("Data from Format Device Page\n"); - printf("----------------------------\n"); - bitfield(pagestart + 20, "Removable Medium", 1, 5); - bitfield(pagestart + 20, "Supports Hard Sectoring", 1, 6); - bitfield(pagestart + 20, "Supports Soft Sectoring", 1, 7); - bitfield(pagestart + 20, "Addresses assigned by surface", 1, 4); - intfield(pagestart + 2, 2, "Tracks per Zone"); - intfield(pagestart + 4, 2, "Alternate sectors per zone"); - intfield(pagestart + 6, 2, "Alternate tracks per zone"); - intfield(pagestart + 8, 2, "Alternate tracks per lun"); - intfield(pagestart + 10, 2, "Sectors per track"); - intfield(pagestart + 12, 2, "Bytes per sector"); - intfield(pagestart + 14, 2, "Interleave"); - intfield(pagestart + 16, 2, "Track skew factor"); - intfield(pagestart + 18, 2, "Cylinder skew factor"); - printf("\n"); - return 0; - -} - -static int verify_error_recovery(int page_code) -{ - int status; - int bdlen; - unsigned char *pagestart; - - SETUP_MODE_PAGE(7, 7); - - printf("Data from Verify Error Recovery Page\n"); - printf("------------------------------------\n"); - bitfield(pagestart + 2, "EER", 1, 3); - bitfield(pagestart + 2, "PER", 1, 2); - bitfield(pagestart + 2, "DTE", 1, 1); - bitfield(pagestart + 2, "DCR", 1, 0); - intfield(pagestart + 3, 1, "Verify Retry Count"); - intfield(pagestart + 4, 1, "Verify Correction Span (bits)"); - intfield(pagestart + 10, 2, "Verify Recovery Time Limit (ms)"); - - printf("\n"); - return 0; -} - -static int peripheral_device_page(int page_code) -{ - static char *idents[] = { - "X3.131: Small Computer System Interface", - "X3.91M-1987: Storage Module Interface", - "X3.170: Enhanced Small Device Interface", - "X3.130-1986; X3T9.3/87-002: IPI-2", - "X3.132-1987; X3.147-1988: IPI-3" - }; - int status; - int bdlen; - unsigned ident; - unsigned char *pagestart; - char *name; - - SETUP_MODE_PAGE(9, 2); - - printf("Data from Peripheral Device Page\n"); - printf("--------------------------------\n"); - - ident = getnbyte(pagestart + 2, 2); - if (ident < (sizeof(idents) / sizeof(char *))) - name = idents[ident]; - else if (ident < 0x8000) - name = "Reserved"; - else - name = "Vendor Specific"; - - bdlen = pagestart[1] - 6; - if (bdlen < 0) - bdlen = 0; - else - SETUP_MODE_PAGE(9, 2); - - hexfield(pagestart + 2, 2, "Interface Identifier"); - for (ident = 0; ident < 35; ident++) - putchar(' '); - puts(name); - - hexdatafield(pagestart + 8, bdlen, "Vendor Specific Data"); - - printf("\n"); - return 0; -} - -/* end */ - -static int do_user_page(int page_code, int page_no) -{ - int status; - int bdlen; - int i; - //unsigned ident; - unsigned char *pagestart; - char *name; - - SETUP_MODE_PAGE(page_no, 0); - //printf ("Page 0x%02x len: %i\n", page_code, pagestart[1]); - - name = "Vendor specific"; - for (i = 2; i < pagestart[1] + 2; i++) { - char nm[8]; - snprintf(nm, 8, "%02x", i); - hexdatafield(pagestart + i, 1, nm); - } - - printf("\n"); - puts(name); - return 0; -} - -/* end */ - -static int do_scsi_info_inquiry(int page_code) -{ - int status, i, x_interface = 0; - unsigned char *cmd; - unsigned char *pagestart; - unsigned char tmp; - - for (i = 0; i < 1024; i++) { - buffer[i] = 0; - } - - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = 36; /* length of output buffer */ - - cmd = (unsigned char *)(((int *)buffer) + 2); - - cmd[0] = 0x12; /* INQUIRY */ - cmd[1] = 0x00; /* lun=0, evpd=0 */ - cmd[2] = 0x00; /* page code = 0 */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0x24; /* allocation length */ - cmd[5] = 0x00; /* control */ - - status = do_sg_io(glob_fd, buffer); - if (status) { - printf("Error doing INQUIRY (1)"); - return status; - } - - pagestart = buffer + 8; - - printf("Inquiry command\n"); - printf("---------------\n"); - bitfield(pagestart + 7, "Relative Address", 1, 7); - bitfield(pagestart + 7, "Wide bus 32", 1, 6); - bitfield(pagestart + 7, "Wide bus 16", 1, 5); - bitfield(pagestart + 7, "Synchronous neg.", 1, 4); - bitfield(pagestart + 7, "Linked Commands", 1, 3); - bitfield(pagestart + 7, "Command Queueing", 1, 1); - bitfield(pagestart + 7, "SftRe", 1, 0); - bitfield(pagestart + 0, "Device Type", 0x1f, 0); - bitfield(pagestart + 0, "Peripheral Qualifier", 0x7, 5); - bitfield(pagestart + 1, "Removable?", 1, 7); - bitfield(pagestart + 1, "Device Type Modifier", 0x7f, 0); - bitfield(pagestart + 2, "ISO Version", 3, 6); - bitfield(pagestart + 2, "ECMA Version", 7, 3); - bitfield(pagestart + 2, "ANSI Version", 7, 0); - bitfield(pagestart + 3, "AENC", 1, 7); - bitfield(pagestart + 3, "TrmIOP", 1, 6); - bitfield(pagestart + 3, "Response Data Format", 0xf, 0); - tmp = pagestart[16]; - pagestart[16] = 0; - printf("%s%s\n", (!x_interface ? "Vendor: " : ""), - pagestart + 8); - pagestart[16] = tmp; - - tmp = pagestart[32]; - pagestart[32] = 0; - printf("%s%s\n", (!x_interface ? "Product: " : ""), - pagestart + 16); - pagestart[32] = tmp; - - printf("%s%s\n", (!x_interface ? "Revision level: " : ""), - pagestart + 32); - - printf("\n"); - return status; - -} - -static int do_serial_number(int page_code) -{ - int status, i, pagelen; - unsigned char *cmd; - unsigned char *pagestart; - - for (i = 0; i < 1024; i++) { - buffer[i] = 0; - } - - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = 4; /* length of output buffer */ - - cmd = (unsigned char *)(((int *)buffer) + 2); - - cmd[0] = 0x12; /* INQUIRY */ - cmd[1] = 0x01; /* lun=0, evpd=1 */ - cmd[2] = 0x80; /* page code = 0x80, serial number */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = 0x04; /* allocation length */ - cmd[5] = 0x00; /* control */ - - status = do_sg_io(glob_fd, buffer); - if (status) { - printf("Error doing INQUIRY (evpd=1, serial number)\n"); - return status; - } - - pagestart = buffer + 8; - - pagelen = 4 + pagestart[3]; - *((int *)buffer) = 0; /* length of input data */ - *(((int *)buffer) + 1) = pagelen; /* length of output buffer */ - - cmd[0] = 0x12; /* INQUIRY */ - cmd[1] = 0x01; /* lun=0, evpd=1 */ - cmd[2] = 0x80; /* page code = 0x80, serial number */ - cmd[3] = 0x00; /* (reserved) */ - cmd[4] = (unsigned char)pagelen; /* allocation length */ - cmd[5] = 0x00; /* control */ - - status = do_sg_io(glob_fd, buffer); - if (status) { - printf("Error doing INQUIRY (evpd=1, serial number, len)\n"); - return status; - } - - printf("Serial Number '"); - for (i = 0; i < pagestart[3]; i++) - printf("%c", pagestart[4 + i]); - printf("'\n"); - printf("\n"); - - return status; -} - -/* Print out a list of the known devices on the system */ -static void show_devices() -{ - int k, j, fd, err, bus; - My_scsi_idlun m_idlun; - char name[MDEV_NAME_SZ]; - char ebuff[EBUFF_SZ]; - int do_numeric = 1; - int max_holes = MAX_HOLES; - - for (k = 0, j = 0; k < sizeof(devices) / sizeof(char *); k++) { - fd = open(devices[k], O_RDONLY | O_NONBLOCK); - if (fd < 0) - continue; - err = - ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &(sg_map_arr[j].bus)); - if (err < 0) { - snprintf(ebuff, EBUFF_SZ, - "SCSI(1) ioctl on %s failed", devices[k]); - perror(ebuff); - close(fd); - continue; - } - err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun); - if (err < 0) { - snprintf(ebuff, EBUFF_SZ, - "SCSI(2) ioctl on %s failed", devices[k]); - perror(ebuff); - close(fd); - continue; - } - sg_map_arr[j].channel = (m_idlun.dev_id >> 16) & 0xff; - sg_map_arr[j].lun = (m_idlun.dev_id >> 8) & 0xff; - sg_map_arr[j].target_id = m_idlun.dev_id & 0xff; - sg_map_arr[j].dev_name = devices[k]; - - printf("[scsi%d ch=%d id=%d lun=%d %s] ", sg_map_arr[j].bus, - sg_map_arr[j].channel, sg_map_arr[j].target_id, - sg_map_arr[j].lun, sg_map_arr[j].dev_name); - - ++j; - printf("%s ", devices[k]); - close(fd); - }; - printf("\n"); - for (k = 0; k < MAX_SG_DEVS; k++) { - make_dev_name(name, NULL, k, do_numeric); - fd = open(name, O_RDWR | O_NONBLOCK); - if (fd < 0) { - if ((ENOENT == errno) && (0 == k)) { - do_numeric = 0; - make_dev_name(name, NULL, k, do_numeric); - fd = open(name, O_RDWR | O_NONBLOCK); - } - if (fd < 0) { - if (EBUSY == errno) - continue; /* step over if O_EXCL already on it */ - else { -#if 0 - snprintf(ebuff, EBUFF_SZ, - "open on %s failed (%d)", name, - errno); - perror(ebuff); -#endif - if (max_holes-- > 0) - continue; - else - break; - } - } - } - max_holes = MAX_HOLES; - err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus); - if (err < 0) { - snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed", - name); - perror(ebuff); - close(fd); - continue; - } - err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun); - if (err < 0) { - snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed", - name); - perror(ebuff); - close(fd); - continue; - } - - printf("[scsi%d ch=%d id=%d lun=%d %s]", bus, - (m_idlun.dev_id >> 16) & 0xff, m_idlun.dev_id & 0xff, - (m_idlun.dev_id >> 8) & 0xff, name); - - for (j = 0; sg_map_arr[j].dev_name; ++j) { - if ((bus == sg_map_arr[j].bus) && - ((m_idlun.dev_id & 0xff) == sg_map_arr[j].target_id) - && (((m_idlun.dev_id >> 16) & 0xff) == - sg_map_arr[j].channel) - && (((m_idlun.dev_id >> 8) & 0xff) == - sg_map_arr[j].lun)) { - printf("%s [=%s scsi%d ch=%d id=%d lun=%d]\n", - name, sg_map_arr[j].dev_name, bus, - ((m_idlun.dev_id >> 16) & 0xff), - m_idlun.dev_id & 0xff, - ((m_idlun.dev_id >> 8) & 0xff)); - break; - } - } - if (NULL == sg_map_arr[j].dev_name) - printf("%s [scsi%d ch=%d id=%d lun=%d]\n", name, bus, - ((m_idlun.dev_id >> 16) & 0xff), - m_idlun.dev_id & 0xff, - ((m_idlun.dev_id >> 8) & 0xff)); - close(fd); - } - printf("\n"); -} - -static int show_pages(int page_code) -{ - int offset; - int length; - int i; - unsigned long long pages_sup = 0; - unsigned long long pages_mask = 0; - - if (!get_mode_page10(0x3f, page_code | 0x10)) { - length = 9 + getnbyte(buffer + 8, 2); - offset = 16 + getnbyte(buffer + 14, 2); - } else if (!get_mode_page(0x3f, page_code | 0x10)) { - length = 9 + buffer[8]; - offset = 12 + buffer[11]; - } else { /* Assume SCSI-1 and fake settings to report NO pages */ - offset = 10; - length = 0; - } - - /* Get mask of pages supported by prog: */ - for (i = 0; i < MAX_PAGENO; i++) - if (page_names[i]) - pages_mask |= (1LL << i); - - /* Get pages listed in mode_pages */ - while (offset < length) { - pages_sup |= (1LL << (buffer[offset] & 0x3f)); - offset += 2 + buffer[offset + 1]; - } - - /* Mask out pages unsupported by this binary */ - pages_sup &= pages_mask; - - /* Notch page supported? */ - if (pages_sup & (1LL << 12)) { - if (get_mode_page(12, 0)) - return 2; - offset = 12 + buffer[11]; - } else { /* Fake empty notch page */ - memset(buffer, 0, SIZEOF_BUFFER); - offset = 0; - } - - pages_mask = getnbyte(buffer + offset + 16, 4); - pages_mask <<= 32; - pages_mask += getnbyte(buffer + offset + 20, 4); - - puts("Mode Pages supported by this binary and target:"); - puts("-----------------------------------------------"); - for (i = 0; i < MAX_PAGENO; i++) - if (pages_sup & (1LL << i)) - printf("%02xh: %s Page%s\n", i, get_page_name(i), - (pages_mask & (1LL << i)) ? " (notched)" : ""); - if (pages_sup & (1LL << 12)) { - printf("\nCurrent notch is %d.\n", - getnbyte(buffer + offset + 6, 2)); - } - if (!pages_sup) - puts("No mode pages supported (SCSI-1?)."); - - return 0; -} - -static int open_sg_dev(char *devname) -{ - int fd, err, bus, bbus, k; - My_scsi_idlun m_idlun, mm_idlun; - int do_numeric = 1; - char name[DEVNAME_SZ]; - struct stat a_st; - int block_dev = 0; - - strncpy(name, devname, DEVNAME_SZ); - name[DEVNAME_SZ - 1] = '\0'; - fd = open(name, O_RDONLY); - if (fd < 0) - return fd; - if (fstat(fd, &a_st) < 0) { - fprintf(stderr, "could do fstat() on fd ??\n"); - close(fd); - return -9999; - } - if (S_ISBLK(a_st.st_mode)) - block_dev = 1; - if (block_dev || (ioctl(fd, SG_GET_TIMEOUT, 0) < 0)) { - err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus); - if (err < 0) { - perror("A SCSI device name is required\n"); - close(fd); - return -9999; - } - err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun); - if (err < 0) { - perror("A SCSI device name is required\n"); - close(fd); - return -9999; - } - close(fd); - - for (k = 0; k < MAX_SG_DEVS; k++) { - make_dev_name(name, NULL, k, do_numeric); - fd = open(name, O_RDWR | O_NONBLOCK); - if (fd < 0) { - if ((ENOENT == errno) && (0 == k)) { - do_numeric = 0; - make_dev_name(name, NULL, k, - do_numeric); - fd = open(name, O_RDWR | O_NONBLOCK); - } - if (fd < 0) { - if (EBUSY == errno) - continue; /* step over if O_EXCL already on it */ - else - break; - } - } - err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bbus); - if (err < 0) { - perror("sg ioctl failed"); - close(fd); - fd = -9999; - } - err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &mm_idlun); - if (err < 0) { - perror("sg ioctl failed"); - close(fd); - fd = -9999; - } - if ((bus == bbus) && - ((m_idlun.dev_id & 0xff) == - (mm_idlun.dev_id & 0xff)) - && (((m_idlun.dev_id >> 8) & 0xff) == - ((mm_idlun.dev_id >> 8) & 0xff)) - && (((m_idlun.dev_id >> 16) & 0xff) == - ((mm_idlun.dev_id >> 16) & 0xff))) - break; - else { - close(fd); - fd = -9999; - } - } - } - if (fd >= 0) { -#ifdef SG_GET_RESERVED_SIZE - int size; - - if (ioctl(fd, SG_GET_RESERVED_SIZE, &size) < 0) { - fprintf(stderr, - "Compiled with new driver, running on old!!\n"); - close(fd); - return -9999; - } -#endif - close(fd); - return open(name, O_RDWR); - } else - return fd; -} - -int show_scsi_info(char *device) -{ - int page_code = 0; - int status = 0; - - print_msg(TEST_BREAK, __FUNCTION__); - - show_devices(); - - glob_fd = open_sg_dev(device); - if (glob_fd < 0) { - if (-9999 == glob_fd) - fprintf(stderr, - "Couldn't find sg device corresponding to %s\n", - device); - else { - perror("sginfo(open)"); - fprintf(stderr, - "file=%s, or no corresponding sg device found\n", - device); - fprintf(stderr, "Is sg driver loaded?\n"); - } - return 1; - } - - status |= do_scsi_info_inquiry(page_code); - - status |= do_serial_number(page_code); - - status |= read_geometry(page_code); - - status |= read_cache(page_code); - - status |= read_format_info(page_code); - - status |= error_recovery_page(page_code); - - status |= read_control_page(page_code); - - status |= read_disconnect_reconnect_data(page_code); - - status |= read_defect_list(page_code); - - status |= notch_parameters_page(page_code); - - status |= verify_error_recovery(page_code); - - status |= peripheral_device_page(page_code); - - status |= do_user_page(page_code, 0); - - status |= show_pages(page_code); - - return status; -} - -/* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM), - 2 -> try again */ -int sg_read2(int sg_fd, unsigned char *buff, int blocks, int from_block, - int bs, int cdbsz, int fua, int do_mmap) -{ - unsigned char rdCmd[MAX_SCSI_CDBSZ]; - unsigned char senseBuff[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - int res; - - if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, 0)) { - fprintf(stderr, - ME "bad rd cdb build, from_block=%d, blocks=%d\n", - from_block, blocks); - return -1; - } - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = cdbsz; - io_hdr.cmdp = rdCmd; - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = bs * blocks; - if (!do_mmap) - io_hdr.dxferp = buff; - io_hdr.mx_sb_len = SENSE_BUFF_LEN; - io_hdr.sbp = senseBuff; - io_hdr.timeout = DEF_TIMEOUT; - io_hdr.pack_id = from_block; - if (do_mmap) - io_hdr.flags |= SG_FLAG_MMAP_IO; - - while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && - (EINTR == errno)) ; - if (res < 0) { - if (ENOMEM == errno) - return 1; - perror("reading (wr) on sg device, error"); - return -1; - } - - while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && - (EINTR == errno)) ; - if (res < 0) { - perror("reading (rd) on sg device, error"); - return -1; - } - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - fprintf(stderr, - "Recovered error while reading block=%d, num=%d\n", - from_block, blocks); - break; - case SG_ERR_CAT_MEDIA_CHANGED: - return 2; - default: - sg_chk_n_print3("reading", &io_hdr); - return -1; - } - sum_of_resids += io_hdr.resid; -#if SG_DEBUG - fprintf(stderr, "duration=%u ms\n", io_hdr.duration); -#endif - return 0; -} - -/* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM), - 2 -> try again */ -int sg_write2(int sg_fd, unsigned char *buff, int blocks, int to_block, - int bs, int cdbsz, int fua, int do_mmap, int *diop) -{ - unsigned char wrCmd[MAX_SCSI_CDBSZ]; - unsigned char senseBuff[SENSE_BUFF_LEN]; - sg_io_hdr_t io_hdr; - int res; - - if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, 0)) { - fprintf(stderr, ME "bad wr cdb build, to_block=%d, blocks=%d\n", - to_block, blocks); - return -1; - } - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = cdbsz; - io_hdr.cmdp = wrCmd; - io_hdr.dxfer_direction = SG_DXFER_TO_DEV; - io_hdr.dxfer_len = bs * blocks; - if (!do_mmap) - io_hdr.dxferp = buff; - io_hdr.mx_sb_len = SENSE_BUFF_LEN; - io_hdr.sbp = senseBuff; - io_hdr.timeout = DEF_TIMEOUT; - io_hdr.pack_id = to_block; - if (do_mmap) - io_hdr.flags |= SG_FLAG_MMAP_IO; - if (diop && *diop) - io_hdr.flags |= SG_FLAG_DIRECT_IO; - - while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && - (EINTR == errno)) ; - if (res < 0) { - if (ENOMEM == errno) - return 1; - perror("writing (wr) on sg device, error"); - return -1; - } - - while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && - (EINTR == errno)) ; - if (res < 0) { - perror("writing (rd) on sg device, error"); - return -1; - } - switch (sg_err_category3(&io_hdr)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - fprintf(stderr, - "Recovered error while writing block=%d, num=%d\n", - to_block, blocks); - break; - case SG_ERR_CAT_MEDIA_CHANGED: - return 2; - default: - sg_chk_n_print3("writing", &io_hdr); - return -1; - } - if (diop && *diop && - ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) - *diop = 0; /* flag that dio not done (completely) */ - return 0; -} - -int do_scsi_sgm_read_write(char *device) -{ - int skip = 0; - int seek = 0; - int bs = 0; - int bpt = DEF_BLOCKS_PER_TRANSFER; - char inf[INOUTF_SZ]; - int in_type = FT_OTHER; - char outf[INOUTF_SZ]; - int out_type = FT_OTHER; - int res, t; - int infd, outfd, blocks; - unsigned char *wrkPos; - unsigned char *wrkBuff = NULL; - unsigned char *wrkMmap = NULL; - int in_num_sect = 0; - int in_res_sz = 0; - int out_num_sect = 0; - int out_res_sz = 0; - int do_time = 1; - int scsi_cdbsz = DEF_SCSI_CDBSZ; - int do_sync = 1; - int do_dio = 0; - int num_dio_not_done = 0; - int fua_mode = 0; - int in_sect_sz, out_sect_sz; - char ebuff[EBUFF_SZ]; - int blocks_per; - int req_count; - size_t psz = getpagesize(); - struct timeval start_tm, end_tm; - - print_msg(TEST_BREAK, __FUNCTION__); - - strcpy(inf, "/dev/zero"); - strcpy(outf, device); - - install_handler(SIGINT, interrupt_handler); - install_handler(SIGQUIT, interrupt_handler); - install_handler(SIGPIPE, interrupt_handler); - install_handler(SIGUSR1, siginfo_handler); - - infd = STDIN_FILENO; - outfd = STDOUT_FILENO; - - in_type = dd_filetype(inf); - - if (FT_ST == in_type) { - fprintf(stderr, ME "unable to use scsi tape device %s\n", inf); - return 1; - } else if (FT_SG == in_type) { - if ((infd = open(inf, O_RDWR)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for sg reading", inf); - perror(ebuff); - return 1; - } - res = ioctl(infd, SG_GET_VERSION_NUM, &t); - if ((res < 0) || (t < 30122)) { - fprintf(stderr, ME "sg driver prior to 3.1.22\n"); - return 1; - } - in_res_sz = bs * bpt; - if (0 != (in_res_sz % psz)) /* round up to next page */ - in_res_sz = ((in_res_sz / psz) + 1) * psz; - if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) < 0) { - perror(ME "SG_GET_RESERVED_SIZE error"); - return 1; - } - if (in_res_sz > t) { - if (ioctl(infd, SG_SET_RESERVED_SIZE, &in_res_sz) < 0) { - perror(ME "SG_SET_RESERVED_SIZE error"); - return 1; - } - } - wrkMmap = mmap(NULL, in_res_sz, PROT_READ | PROT_WRITE, - MAP_SHARED, infd, 0); - if (MAP_FAILED == wrkMmap) { - snprintf(ebuff, EBUFF_SZ, - ME "error using mmap() on file: %s", inf); - perror(ebuff); - return 1; - } - } else { - if ((infd = open(inf, O_RDONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for reading", inf); - perror(ebuff); - return 1; - } else if (skip > 0) { - llse_loff_t offset = skip; - - offset *= bs; /* could exceed 32 bits here! */ - if (llse_llseek(infd, offset, SEEK_SET) < 0) { - snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " - "required position on %s", inf); - perror(ebuff); - return 1; - } - } - } - - if (outf[0] && ('-' != outf[0])) { - out_type = dd_filetype(outf); - - if (FT_ST == out_type) { - fprintf(stderr, - ME "unable to use scsi tape device %s\n", outf); - return 1; - } else if (FT_SG == out_type) { - if ((outfd = open(outf, O_RDWR)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for " - "sg writing", outf); - perror(ebuff); - return 1; - } - res = ioctl(outfd, SG_GET_VERSION_NUM, &t); - if ((res < 0) || (t < 30122)) { - fprintf(stderr, - ME "sg driver prior to 3.1.22\n"); - return 1; - } - if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) { - perror(ME "SG_GET_RESERVED_SIZE error"); - return 1; - } - out_res_sz = bs * bpt; - if (out_res_sz > t) { - if (ioctl - (outfd, SG_SET_RESERVED_SIZE, - &out_res_sz) < 0) { - perror(ME "SG_SET_RESERVED_SIZE error"); - return 1; - } - } - if (NULL == wrkMmap) { - wrkMmap = - mmap(NULL, out_res_sz, - PROT_READ | PROT_WRITE, MAP_SHARED, - outfd, 0); - if (MAP_FAILED == wrkMmap) { - snprintf(ebuff, EBUFF_SZ, - ME - "error using mmap() on file: %s", - outf); - perror(ebuff); - return 1; - } - } - } else if (FT_DEV_NULL == out_type) - outfd = -1; /* don't bother opening */ - else { - if (FT_RAW != out_type) { - if ((outfd = - open(outf, O_WRONLY | O_CREAT, - 0666)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "could not open %s for writing", - outf); - perror(ebuff); - return 1; - } - } else { - if ((outfd = open(outf, O_WRONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s " - "for raw writing", outf); - perror(ebuff); - return 1; - } - } - if (seek > 0) { - llse_loff_t offset = seek; - - offset *= bs; /* could exceed 32 bits here! */ - if (llse_llseek(outfd, offset, SEEK_SET) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "couldn't seek to " - "required position on %s", - outf); - perror(ebuff); - return 1; - } - } - } - } - if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { - fprintf(stderr, - "Can't have both 'if' as stdin _and_ 'of' as stdout\n"); - return 1; - } -#if 0 - if ((FT_OTHER == in_type) && (FT_OTHER == out_type)) { - fprintf(stderr, "Both 'if' and 'of' can't be ordinary files\n"); - return 1; - } -#endif - if (dd_count < 0) { - if (FT_SG == in_type) { - res = read_capacity(infd, &in_num_sect, &in_sect_sz); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(in), continuing\n"); - res = - read_capacity(infd, &in_num_sect, - &in_sect_sz); - } - if (0 != res) { - fprintf(stderr, - "Unable to read capacity on %s\n", inf); - in_num_sect = -1; - } else { -#if 0 - if (0 == in_sect_sz) - in_sect_sz = bs; - else if (in_sect_sz > bs) - in_num_sect *= (in_sect_sz / bs); - else if (in_sect_sz < bs) - in_num_sect /= (bs / in_sect_sz); -#endif - if (in_num_sect > skip) - in_num_sect -= skip; - } - } - if (FT_SG == out_type) { - res = read_capacity(outfd, &out_num_sect, &out_sect_sz); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(out), continuing\n"); - res = - read_capacity(outfd, &out_num_sect, - &out_sect_sz); - } - if (0 != res) { - fprintf(stderr, - "Unable to read capacity on %s\n", - outf); - out_num_sect = -1; - } else { - if (out_num_sect > seek) - out_num_sect -= seek; - } - } -#ifdef SG_DEBUG - fprintf(stderr, - "Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n", - dd_count, in_num_sect, out_num_sect); -#endif - if (in_num_sect > 0) { - if (out_num_sect > 0) - dd_count = - (in_num_sect > - out_num_sect) ? out_num_sect : in_num_sect; - else - dd_count = in_num_sect; - } else - dd_count = out_num_sect; - } - if (dd_count < 0) { - fprintf(stderr, "Couldn't calculate count, please give one\n"); - return 1; - } - if (do_dio && (FT_SG != in_type)) { - do_dio = 0; - fprintf(stderr, - ">>> dio only performed on 'of' side when 'if' is" - " an sg device\n"); - } - if (do_dio) { - int fd; - char c; - - if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { - if (1 == read(fd, &c, 1)) { - if ('0' == c) - fprintf(stderr, - ">>> %s set to '0' but should be set " - "to '1' for direct IO\n", - proc_allow_dio); - } - close(fd); - } - } - - if (wrkMmap) - wrkPos = wrkMmap; - else { - if ((FT_RAW == in_type) || (FT_RAW == out_type)) { - wrkBuff = malloc(bs * bpt + psz); - if (0 == wrkBuff) { - fprintf(stderr, - "Not enough user memory for raw\n"); - return 1; - } - wrkPos = - (unsigned char *)(((unsigned long)wrkBuff + psz - 1) - & (~(psz - 1))); - } else { - wrkBuff = malloc(bs * bpt); - if (0 == wrkBuff) { - fprintf(stderr, "Not enough user memory\n"); - return 1; - } - wrkPos = wrkBuff; - } - } - - blocks_per = bpt; -#ifdef SG_DEBUG - fprintf(stderr, "Start of loop, count=%d, blocks_per=%d\n", - dd_count, blocks_per); -#endif - if (do_time) { - start_tm.tv_sec = 0; - start_tm.tv_usec = 0; - gettimeofday(&start_tm, NULL); - } - req_count = dd_count; - - while (dd_count > 0) { - blocks = (dd_count > blocks_per) ? blocks_per : dd_count; - if (FT_SG == in_type) { - int fua = fua_mode & 2; - - res = - sg_read2(infd, wrkPos, blocks, skip, bs, scsi_cdbsz, - fua, 1); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed, continuing (r)\n"); - res = - sg_read2(infd, wrkPos, blocks, skip, bs, - scsi_cdbsz, fua, 1); - } - if (0 != res) { - fprintf(stderr, "sg_read2 failed, skip=%d\n", - skip); - break; - } else - in_full += blocks; - } else { - while (((res = read(infd, wrkPos, blocks * bs)) < 0) && - (EINTR == errno)) ; - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "reading, skip=%d ", skip); - perror(ebuff); - break; - } else if (res < blocks * bs) { - dd_count = 0; - blocks = res / bs; - if ((res % bs) > 0) { - blocks++; - in_partial++; - } - } - in_full += blocks; - } - - if (FT_SG == out_type) { - int do_mmap = (FT_SG == in_type) ? 0 : 1; - int fua = fua_mode & 1; - int dio_res = do_dio; - - res = - sg_write2(outfd, wrkPos, blocks, seek, bs, - scsi_cdbsz, fua, do_mmap, &dio_res); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed, continuing (w)\n"); - res = - sg_write2(outfd, wrkPos, blocks, seek, bs, - scsi_cdbsz, fua, do_mmap, - &dio_res); - } else if (0 != res) { - fprintf(stderr, "sg_write2 failed, seek=%d\n", - seek); - break; - } else { - out_full += blocks; - if (do_dio && (0 == dio_res)) - num_dio_not_done++; - } - } else if (FT_DEV_NULL == out_type) - out_full += blocks; /* act as if written out without error */ - else { - while (((res = write(outfd, wrkPos, blocks * bs)) < 0) - && (EINTR == errno)) ; - if (res < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "writing, seek=%d ", seek); - perror(ebuff); - break; - } else if (res < blocks * bs) { - fprintf(stderr, - "output file probably full, seek=%d ", - seek); - blocks = res / bs; - out_full += blocks; - if ((res % bs) > 0) - out_partial++; - break; - } else - out_full += blocks; - } - if (dd_count > 0) - dd_count -= blocks; - skip += blocks; - seek += blocks; - } - if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { - struct timeval res_tm; - double a, b; - - gettimeofday(&end_tm, NULL); - res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; - res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; - if (res_tm.tv_usec < 0) { - --res_tm.tv_sec; - res_tm.tv_usec += 1000000; - } - a = res_tm.tv_sec; - a += (0.000001 * res_tm.tv_usec); - b = (double)bs *(req_count - dd_count); - printf("time to transfer data was %d.%06d secs", - (int)res_tm.tv_sec, (int)res_tm.tv_usec); - if ((a > 0.00001) && (b > 511)) - printf(", %.2f MB/sec\n", b / (a * 1000000.0)); - else - printf("\n"); - } - if (do_sync) { - if (FT_SG == out_type) { - fprintf(stderr, ">> Synchronizing cache on %s\n", outf); - res = sync_cache(outfd); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(in), continuing\n"); - res = sync_cache(outfd); - } - if (0 != res) - fprintf(stderr, - "Unable to synchronize cache\n"); - } - } - - if (wrkBuff) - free(wrkBuff); - if (STDIN_FILENO != infd) - close(infd); - if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type)) - close(outfd); - res = 0; - if (0 != dd_count) { - fprintf(stderr, "Some error occurred,"); - res = 2; - } - print_stats(); - if (sum_of_resids) - fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", - sum_of_resids); - if (num_dio_not_done) - fprintf(stderr, ">> dio requested but _not done %d times\n", - num_dio_not_done); - return res; -} - -static void guarded_stop_in(Rq_coll * clp) -{ - pthread_mutex_lock(&clp->in_mutex); - clp->in_stop = 1; - pthread_mutex_unlock(&clp->in_mutex); -} - -static void guarded_stop_out(Rq_coll * clp) -{ - pthread_mutex_lock(&clp->out_mutex); - clp->out_stop = 1; - pthread_mutex_unlock(&clp->out_mutex); -} - -static void guarded_stop_both(Rq_coll * clp) -{ - guarded_stop_in(clp); - guarded_stop_out(clp); -} - -void *sig_listen_thread(void *v_clp) -{ - Rq_coll *clp = (Rq_coll *) v_clp; - int sig_number; - - while (1) { - sigwait(&signal_set, &sig_number); - if (SIGINT == sig_number) { - fprintf(stderr, ME "interrupted by SIGINT\n"); - guarded_stop_both(clp); - pthread_cond_broadcast(&clp->out_sync_cv); - } - } - return NULL; -} - -void cleanup_in(void *v_clp) -{ - Rq_coll *clp = (Rq_coll *) v_clp; - - fprintf(stderr, "thread cancelled while in mutex held\n"); - clp->in_stop = 1; - pthread_mutex_unlock(&clp->in_mutex); - guarded_stop_out(clp); - pthread_cond_broadcast(&clp->out_sync_cv); -} - -void cleanup_out(void *v_clp) -{ - Rq_coll *clp = (Rq_coll *) v_clp; - - fprintf(stderr, "thread cancelled while out mutex held\n"); - clp->out_stop = 1; - pthread_mutex_unlock(&clp->out_mutex); - guarded_stop_in(clp); - pthread_cond_broadcast(&clp->out_sync_cv); -} - -void *read_write_thread(void *v_clp) -{ - Rq_coll *clp = (Rq_coll *) v_clp; - Rq_elem rel; - Rq_elem *rep = &rel; - size_t psz = 0; - int sz = clp->bpt * clp->bs; - int stop_after_write = 0; - int seek_skip = clp->seek - clp->skip; - int blocks, status; - - memset(rep, 0, sizeof(Rq_elem)); - psz = getpagesize(); - if (NULL == (rep->alloc_bp = malloc(sz + psz))) - err_exit(ENOMEM, "out of memory creating user buffers\n"); - rep->buffp = - (unsigned char *)(((unsigned long)rep->alloc_bp + psz - 1) & - (~(psz - 1))); - /* Follow clp members are constant during lifetime of thread */ - rep->bs = clp->bs; - rep->fua_mode = clp->fua_mode; - rep->dio = clp->dio; - rep->infd = clp->infd; - rep->outfd = clp->outfd; - rep->debug = clp->debug; - rep->in_scsi_type = clp->in_scsi_type; - rep->out_scsi_type = clp->out_scsi_type; - rep->cdbsz = clp->cdbsz; - - while (1) { - status = pthread_mutex_lock(&clp->in_mutex); - if (0 != status) - err_exit(status, "lock in_mutex"); - if (clp->in_stop || (clp->in_count <= 0)) { - /* no more to do, exit loop then thread */ - status = pthread_mutex_unlock(&clp->in_mutex); - if (0 != status) - err_exit(status, "unlock in_mutex"); - break; - } - blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count; - rep->wr = 0; - rep->blk = clp->in_blk; - rep->num_blks = blocks; - clp->in_blk += blocks; - clp->in_count -= blocks; - - pthread_cleanup_push(cleanup_in, (void *)clp); - if (FT_SG == clp->in_type) - sg_in_operation(clp, rep); /* lets go of in_mutex mid operation */ - else { - stop_after_write = - normal_in_operation(clp, rep, blocks); - status = pthread_mutex_unlock(&clp->in_mutex); - if (0 != status) - err_exit(status, "unlock in_mutex"); - } - pthread_cleanup_pop(0); - - status = pthread_mutex_lock(&clp->out_mutex); - if (0 != status) - err_exit(status, "lock out_mutex"); - if (FT_DEV_NULL != clp->out_type) { - while ((!clp->out_stop) && - ((rep->blk + seek_skip) != clp->out_blk)) { - /* if write would be out of sequence then wait */ - pthread_cleanup_push(cleanup_out, (void *)clp); - status = - pthread_cond_wait(&clp->out_sync_cv, - &clp->out_mutex); - if (0 != status) - err_exit(status, "cond out_sync_cv"); - pthread_cleanup_pop(0); - } - } - - if (clp->out_stop || (clp->out_count <= 0)) { - if (!clp->out_stop) - clp->out_stop = 1; - status = pthread_mutex_unlock(&clp->out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - break; - } - if (stop_after_write) - clp->out_stop = 1; - rep->wr = 1; - rep->blk = clp->out_blk; - /* rep->num_blks = blocks; */ - clp->out_blk += blocks; - clp->out_count -= blocks; - - pthread_cleanup_push(cleanup_out, (void *)clp); - if (FT_SG == clp->out_type) - sg_out_operation(clp, rep); /* releases out_mutex mid operation */ - else if (FT_DEV_NULL == clp->out_type) { - /* skip actual write operation */ - clp->out_done_count -= blocks; - status = pthread_mutex_unlock(&clp->out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - } else { - normal_out_operation(clp, rep, blocks); - status = pthread_mutex_unlock(&clp->out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - } - pthread_cleanup_pop(0); - - if (stop_after_write) - break; - pthread_cond_broadcast(&clp->out_sync_cv); - } /* end of while loop */ - if (rep->alloc_bp) - free(rep->alloc_bp); - status = pthread_mutex_lock(&clp->in_mutex); - if (0 != status) - err_exit(status, "lock in_mutex"); - if (!clp->in_stop) - clp->in_stop = 1; /* flag other workers to stop */ - status = pthread_mutex_unlock(&clp->in_mutex); - if (0 != status) - err_exit(status, "unlock in_mutex"); - pthread_cond_broadcast(&clp->out_sync_cv); - return stop_after_write ? NULL : v_clp; -} - -int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks) -{ - int res; - int stop_after_write = 0; - - /* enters holding in_mutex */ - while (((res = read(clp->infd, rep->buffp, - blocks * clp->bs)) < 0) && (EINTR == errno)) ; - if (res < 0) { - if (clp->coe) { - memset(rep->buffp, 0, rep->num_blks * rep->bs); - fprintf(stderr, - ">> substituted zeros for in blk=%d for " - "%d bytes, %s\n", rep->blk, - rep->num_blks * rep->bs, strerror(errno)); - res = rep->num_blks * clp->bs; - } else { - fprintf(stderr, "error in normal read, %s\n", - strerror(errno)); - clp->in_stop = 1; - guarded_stop_out(clp); - return 1; - } - } - if (res < blocks * clp->bs) { - int o_blocks = blocks; - stop_after_write = 1; - blocks = res / clp->bs; - if ((res % clp->bs) > 0) { - blocks++; - clp->in_partial++; - } - /* Reverse out + re-apply blocks on clp */ - clp->in_blk -= o_blocks; - clp->in_count += o_blocks; - rep->num_blks = blocks; - clp->in_blk += blocks; - clp->in_count -= blocks; - } - clp->in_done_count -= blocks; - return stop_after_write; -} - -void normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks) -{ - int res; - - /* enters holding out_mutex */ - while (((res = write(clp->outfd, rep->buffp, - rep->num_blks * clp->bs)) < 0) - && (EINTR == errno)) ; - if (res < 0) { - if (clp->coe) { - fprintf(stderr, ">> ignored error for out blk=%d for " - "%d bytes, %s\n", rep->blk, - rep->num_blks * rep->bs, strerror(errno)); - res = rep->num_blks * clp->bs; - } else { - fprintf(stderr, "error normal write, %s\n", - strerror(errno)); - guarded_stop_in(clp); - clp->out_stop = 1; - return; - } - } - if (res < blocks * clp->bs) { - blocks = res / clp->bs; - if ((res % clp->bs) > 0) { - blocks++; - clp->out_partial++; - } - rep->num_blks = blocks; - } - clp->out_done_count -= blocks; -} - -void sg_in_operation(Rq_coll * clp, Rq_elem * rep) -{ - int res; - int status; - - /* enters holding in_mutex */ - while (1) { - res = sg_start_io(rep); - if (1 == res) - err_exit(ENOMEM, "sg starting in command"); - else if (res < 0) { - fprintf(stderr, ME "inputting to sg failed, blk=%d\n", - rep->blk); - status = pthread_mutex_unlock(&clp->in_mutex); - if (0 != status) - err_exit(status, "unlock in_mutex"); - guarded_stop_both(clp); - return; - } - /* Now release in mutex to let other reads run in parallel */ - status = pthread_mutex_unlock(&clp->in_mutex); - if (0 != status) - err_exit(status, "unlock in_mutex"); - - res = sg_finish_io(rep->wr, rep, &clp->aux_mutex); - if (res < 0) { - if (clp->coe) { - memset(rep->buffp, 0, rep->num_blks * rep->bs); - fprintf(stderr, - ">> substituted zeros for in blk=%d for " - "%d bytes\n", rep->blk, - rep->num_blks * rep->bs); - } else { - fprintf(stderr, - "error finishing sg in command\n"); - guarded_stop_both(clp); - return; - } - } - if (res <= 0) { /* looks good, going to return */ - if (rep->dio_incomplete || rep->resid) { - status = pthread_mutex_lock(&clp->aux_mutex); - if (0 != status) - err_exit(status, "lock aux_mutex"); - clp->dio_incomplete += rep->dio_incomplete; - clp->sum_of_resids += rep->resid; - status = pthread_mutex_unlock(&clp->aux_mutex); - if (0 != status) - err_exit(status, "unlock aux_mutex"); - } - status = pthread_mutex_lock(&clp->in_mutex); - if (0 != status) - err_exit(status, "lock in_mutex"); - clp->in_done_count -= rep->num_blks; - status = pthread_mutex_unlock(&clp->in_mutex); - if (0 != status) - err_exit(status, "unlock in_mutex"); - return; - } - /* else assume 1 == res so try again with same addr, count info */ - /* now re-acquire read mutex for balance */ - /* N.B. This re-read could now be out of read sequence */ - status = pthread_mutex_lock(&clp->in_mutex); - if (0 != status) - err_exit(status, "lock in_mutex"); - } -} - -void sg_out_operation(Rq_coll * clp, Rq_elem * rep) -{ - int res; - int status; - - /* enters holding out_mutex */ - while (1) { - res = sg_start_io(rep); - if (1 == res) - err_exit(ENOMEM, "sg starting out command"); - else if (res < 0) { - fprintf(stderr, - ME "outputting from sg failed, blk=%d\n", - rep->blk); - status = pthread_mutex_unlock(&clp->out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - guarded_stop_both(clp); - return; - } - /* Now release in mutex to let other reads run in parallel */ - status = pthread_mutex_unlock(&clp->out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - - res = sg_finish_io(rep->wr, rep, &clp->aux_mutex); - if (res < 0) { - if (clp->coe) - fprintf(stderr, - ">> ignored error for out blk=%d for " - "%d bytes\n", rep->blk, - rep->num_blks * rep->bs); - else { - fprintf(stderr, - "error finishing sg out command\n"); - guarded_stop_both(clp); - return; - } - } - if (res <= 0) { - if (rep->dio_incomplete || rep->resid) { - status = pthread_mutex_lock(&clp->aux_mutex); - if (0 != status) - err_exit(status, "lock aux_mutex"); - clp->dio_incomplete += rep->dio_incomplete; - clp->sum_of_resids += rep->resid; - status = pthread_mutex_unlock(&clp->aux_mutex); - if (0 != status) - err_exit(status, "unlock aux_mutex"); - } - status = pthread_mutex_lock(&clp->out_mutex); - if (0 != status) - err_exit(status, "lock out_mutex"); - clp->out_done_count -= rep->num_blks; - status = pthread_mutex_unlock(&clp->out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - return; - } - /* else assume 1 == res so try again with same addr, count info */ - /* now re-acquire out mutex for balance */ - /* N.B. This re-write could now be out of write sequence */ - status = pthread_mutex_lock(&clp->out_mutex); - if (0 != status) - err_exit(status, "lock out_mutex"); - } -} - -int sg_start_io(Rq_elem * rep) -{ - sg_io_hdr_t *hp = &rep->io_hdr; - int fua = rep->wr ? (rep->fua_mode & 1) : (rep->fua_mode & 2); - int res; - - if (sg_build_scsi_cdb(rep->cmd, rep->cdbsz, rep->num_blks, rep->blk, - rep->wr, fua, 0)) { - fprintf(stderr, ME "bad cdb build, start_blk=%d, blocks=%d\n", - rep->blk, rep->num_blks); - return -1; - } - memset(hp, 0, sizeof(sg_io_hdr_t)); - hp->interface_id = 'S'; - hp->cmd_len = rep->cdbsz; - hp->cmdp = rep->cmd; - hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; - hp->dxfer_len = rep->bs * rep->num_blks; - hp->dxferp = rep->buffp; - hp->mx_sb_len = sizeof(rep->sb); - hp->sbp = rep->sb; - hp->timeout = DEF_TIMEOUT; - hp->usr_ptr = rep; - hp->pack_id = rep->blk; - if (rep->dio) - hp->flags |= SG_FLAG_DIRECT_IO; - if (rep->debug > 8) { - fprintf(stderr, "sg_start_io: SCSI %s, blk=%d num_blks=%d\n", - rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks); - sg_print_command(hp->cmdp); - fprintf(stderr, "dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n", - hp->dxfer_direction, hp->dxfer_len, hp->dxferp, - hp->cmd_len); - } - - while (((res = write(rep->wr ? rep->outfd : rep->infd, hp, - sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ; - if (res < 0) { - if (ENOMEM == errno) - return 1; - perror("starting io on sg device, error"); - return -1; - } - return 0; -} - -/* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */ -int sg_finish_io(int wr, Rq_elem * rep, pthread_mutex_t * a_mutp) -{ - int res, status; - sg_io_hdr_t io_hdr; - sg_io_hdr_t *hp; -#if 0 - static int testing = 0; /* thread dubious! */ -#endif - - memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); - /* FORCE_PACK_ID active set only read packet with matching pack_id */ - io_hdr.interface_id = 'S'; - io_hdr.dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; - io_hdr.pack_id = rep->blk; - - while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr, - sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ; - if (res < 0) { - perror("finishing io on sg device, error"); - return -1; - } - if (rep != (Rq_elem *) io_hdr.usr_ptr) - err_exit(0, - "sg_finish_io: bad usr_ptr, request-response mismatch\n"); - memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t)); - hp = &rep->io_hdr; - - switch (sg_err_category3(hp)) { - case SG_ERR_CAT_CLEAN: - break; - case SG_ERR_CAT_RECOVERED: - fprintf(stderr, "Recovered error on block=%d, num=%d\n", - rep->blk, rep->num_blks); - break; - case SG_ERR_CAT_MEDIA_CHANGED: - return 1; - default: - { - char ebuff[EBUFF_SZ]; - - snprintf(ebuff, EBUFF_SZ, - "%s blk=%d", rep->wr ? "writing" : "reading", - rep->blk); - status = pthread_mutex_lock(a_mutp); - if (0 != status) - err_exit(status, "lock aux_mutex"); - sg_chk_n_print3(ebuff, hp); - status = pthread_mutex_unlock(a_mutp); - if (0 != status) - err_exit(status, "unlock aux_mutex"); - return -1; - } - } -#if 0 - if (0 == (++testing % 100)) - return -1; -#endif - if (rep->dio && - ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) - rep->dio_incomplete = 1; /* count dios done as indirect IO */ - else - rep->dio_incomplete = 0; - rep->resid = hp->resid; - if (rep->debug > 8) - fprintf(stderr, "sg_finish_io: completed %s\n", - wr ? "WRITE" : "READ"); - return 0; -} - -int sg_prepare(int fd, int bs, int bpt, int *scsi_typep) -{ - int res, t; - - res = ioctl(fd, SG_GET_VERSION_NUM, &t); - if ((res < 0) || (t < 30000)) { - fprintf(stderr, ME "sg driver prior to 3.x.y\n"); - return 1; - } - res = 0; - t = bs * bpt; - res = ioctl(fd, SG_SET_RESERVED_SIZE, &t); - if (res < 0) - perror(ME "SG_SET_RESERVED_SIZE error"); - t = 1; - res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t); - if (res < 0) - perror(ME "SG_SET_FORCE_PACK_ID error"); - if (scsi_typep) { - struct sg_scsi_id info; - - res = ioctl(fd, SG_GET_SCSI_ID, &info); - if (res < 0) - perror(ME "SG_SET_SCSI_ID error"); - *scsi_typep = info.scsi_type; - } - return 0; -} - -int do_scsi_sgp_read_write(char *device) -{ - int skip = 0; - int seek = 0; - int count = -1; - char inf[INOUTF_SZ]; - char outf[INOUTF_SZ]; - int res, k; - int in_num_sect = 0; - int out_num_sect = 0; - int num_threads = DEF_NUM_THREADS; - pthread_t threads[MAX_NUM_THREADS]; - int do_time = 1; - int do_sync = 1; - int in_sect_sz, out_sect_sz, status, infull, outfull; - void *vp; - char ebuff[EBUFF_SZ]; - struct timeval start_tm, end_tm; - Rq_coll rcoll; - - print_msg(TEST_BREAK, __FUNCTION__); - - memset(&rcoll, 0, sizeof(Rq_coll)); - rcoll.bpt = DEF_BLOCKS_PER_TRANSFER; - rcoll.in_type = FT_OTHER; - rcoll.out_type = FT_OTHER; - rcoll.cdbsz = DEF_SCSI_CDBSZ; - - strcpy(inf, "/dev/zero"); - strcpy(outf, device); - - if (rcoll.bs <= 0) { - rcoll.bs = DEF_BLOCK_SIZE; - fprintf(stderr, - "Assume default 'bs' (block size) of %d bytes\n", - rcoll.bs); - } - - if (rcoll.debug) - fprintf(stderr, ME "if=%s skip=%d of=%s seek=%d count=%d\n", - inf, skip, outf, seek, count); - - rcoll.infd = STDIN_FILENO; - rcoll.outfd = STDOUT_FILENO; - if (inf[0] && ('-' != inf[0])) { - rcoll.in_type = dd_filetype(inf); - - if (FT_ST == rcoll.in_type) { - fprintf(stderr, - ME "unable to use scsi tape device %s\n", inf); - return 1; - } else if (FT_SG == rcoll.in_type) { - if ((rcoll.infd = open(inf, O_RDWR)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for sg reading", - inf); - perror(ebuff); - return 1; - } - if (sg_prepare(rcoll.infd, rcoll.bs, rcoll.bpt, - &rcoll.in_scsi_type)) - return 1; - } else { - if ((rcoll.infd = open(inf, O_RDONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for reading", - inf); - perror(ebuff); - return 1; - } else if (skip > 0) { - llse_loff_t offset = skip; - - offset *= rcoll.bs; /* could exceed 32 here! */ - if (llse_llseek(rcoll.infd, offset, SEEK_SET) < - 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "couldn't skip to required position on %s", - inf); - perror(ebuff); - return 1; - } - } - } - } - if (outf[0] && ('-' != outf[0])) { - rcoll.out_type = dd_filetype(outf); - - if (FT_ST == rcoll.out_type) { - fprintf(stderr, - ME "unable to use scsi tape device %s\n", outf); - return 1; - } else if (FT_SG == rcoll.out_type) { - if ((rcoll.outfd = open(outf, O_RDWR)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME "could not open %s for sg writing", - outf); - perror(ebuff); - return 1; - } - - if (sg_prepare(rcoll.outfd, rcoll.bs, rcoll.bpt, - &rcoll.out_scsi_type)) - return 1; - } else if (FT_DEV_NULL == rcoll.out_type) - rcoll.outfd = -1; /* don't bother opening */ - else { - if (FT_RAW != rcoll.out_type) { - if ((rcoll.outfd = - open(outf, O_WRONLY | O_CREAT, - 0666)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "could not open %s for writing", - outf); - perror(ebuff); - return 1; - } - } else { - if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "could not open %s for raw writing", - outf); - perror(ebuff); - return 1; - } - } - if (seek > 0) { - llse_loff_t offset = seek; - - offset *= rcoll.bs; /* could exceed 32 bits here! */ - if (llse_llseek(rcoll.outfd, offset, SEEK_SET) < - 0) { - snprintf(ebuff, EBUFF_SZ, - ME - "couldn't seek to required position on %s", - outf); - perror(ebuff); - return 1; - } - } - } - } - if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) { - fprintf(stderr, - "Disallow both if and of to be stdin and stdout"); - return 1; - } - if (count < 0) { - if (FT_SG == rcoll.in_type) { - res = - read_capacity(rcoll.infd, &in_num_sect, - &in_sect_sz); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(in), continuing\n"); - res = - read_capacity(rcoll.infd, &in_num_sect, - &in_sect_sz); - } - if (0 != res) { - fprintf(stderr, - "Unable to read capacity on %s\n", inf); - in_num_sect = -1; - } else { - if (in_num_sect > skip) - in_num_sect -= skip; - } - } - if (FT_SG == rcoll.out_type) { - res = - read_capacity(rcoll.outfd, &out_num_sect, - &out_sect_sz); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(out), continuing\n"); - res = - read_capacity(rcoll.outfd, &out_num_sect, - &out_sect_sz); - } - if (0 != res) { - fprintf(stderr, - "Unable to read capacity on %s\n", - outf); - out_num_sect = -1; - } else { - if (out_num_sect > seek) - out_num_sect -= seek; - } - } - if (in_num_sect > 0) { - if (out_num_sect > 0) - count = - (in_num_sect > - out_num_sect) ? out_num_sect : in_num_sect; - else - count = in_num_sect; - } else - count = out_num_sect; - } - if (rcoll.debug > 1) - fprintf(stderr, "Start of loop, count=%d, in_num_sect=%d, " - "out_num_sect=%d\n", count, in_num_sect, out_num_sect); - if (count < 0) { - fprintf(stderr, "Couldn't calculate count, please give one\n"); - return 1; - } - - rcoll.in_count = count; - rcoll.in_done_count = count; - rcoll.skip = skip; - rcoll.in_blk = skip; - rcoll.out_count = count; - rcoll.out_done_count = count; - rcoll.seek = seek; - rcoll.out_blk = seek; - status = pthread_mutex_init(&rcoll.in_mutex, NULL); - if (0 != status) - err_exit(status, "init in_mutex"); - status = pthread_mutex_init(&rcoll.out_mutex, NULL); - if (0 != status) - err_exit(status, "init out_mutex"); - status = pthread_mutex_init(&rcoll.aux_mutex, NULL); - if (0 != status) - err_exit(status, "init aux_mutex"); - status = pthread_cond_init(&rcoll.out_sync_cv, NULL); - if (0 != status) - err_exit(status, "init out_sync_cv"); - - sigemptyset(&signal_set); - sigaddset(&signal_set, SIGINT); - status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL); - if (0 != status) - err_exit(status, "pthread_sigmask"); - status = pthread_create(&sig_listen_thread_id, NULL, - sig_listen_thread, (void *)&rcoll); - if (0 != status) - err_exit(status, "pthread_create, sig..."); - - if (do_time) { - start_tm.tv_sec = 0; - start_tm.tv_usec = 0; - gettimeofday(&start_tm, NULL); - } - -/* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */ - if ((rcoll.out_done_count > 0) && (num_threads > 0)) { - /* Run 1 work thread to shake down infant retryable stuff */ - status = pthread_mutex_lock(&rcoll.out_mutex); - if (0 != status) - err_exit(status, "lock out_mutex"); - status = pthread_create(&threads[0], NULL, read_write_thread, - (void *)&rcoll); - if (0 != status) - err_exit(status, "pthread_create"); - if (rcoll.debug) - fprintf(stderr, "Starting worker thread k=0\n"); - - /* wait for any broadcast */ - pthread_cleanup_push(cleanup_out, (void *)&rcoll); - status = - pthread_cond_wait(&rcoll.out_sync_cv, &rcoll.out_mutex); - if (0 != status) - err_exit(status, "cond out_sync_cv"); - pthread_cleanup_pop(0); - status = pthread_mutex_unlock(&rcoll.out_mutex); - if (0 != status) - err_exit(status, "unlock out_mutex"); - - /* now start the rest of the threads */ - for (k = 1; k < num_threads; ++k) { - status = - pthread_create(&threads[k], NULL, read_write_thread, - (void *)&rcoll); - if (0 != status) - err_exit(status, "pthread_create"); - if (rcoll.debug) - fprintf(stderr, "Starting worker thread k=%d\n", - k); - } - - /* now wait for worker threads to finish */ - for (k = 0; k < num_threads; ++k) { - status = pthread_join(threads[k], &vp); - if (0 != status) - err_exit(status, "pthread_join"); - if (rcoll.debug) - fprintf(stderr, - "Worker thread k=%d terminated\n", k); - } - } - - if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { - struct timeval res_tm; - double a, b; - - gettimeofday(&end_tm, NULL); - res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; - res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; - if (res_tm.tv_usec < 0) { - --res_tm.tv_sec; - res_tm.tv_usec += 1000000; - } - a = res_tm.tv_sec; - a += (0.000001 * res_tm.tv_usec); - b = (double)rcoll.bs * (count - rcoll.out_done_count); - printf("time to transfer data was %d.%06d secs", - (int)res_tm.tv_sec, (int)res_tm.tv_usec); - if ((a > 0.00001) && (b > 511)) - printf(", %.2f MB/sec\n", b / (a * 1000000.0)); - else - printf("\n"); - } - if (do_sync) { - if (FT_SG == rcoll.out_type) { - fprintf(stderr, ">> Synchronizing cache on %s\n", outf); - res = sync_cache(rcoll.outfd); - if (2 == res) { - fprintf(stderr, - "Unit attention, media changed(in), continuing\n"); - res = sync_cache(rcoll.outfd); - } - if (0 != res) - fprintf(stderr, - "Unable to synchronize cache\n"); - } - } - - status = pthread_cancel(sig_listen_thread_id); - if (0 != status) - err_exit(status, "pthread_cancel"); - if (STDIN_FILENO != rcoll.infd) - close(rcoll.infd); - if ((STDOUT_FILENO != rcoll.outfd) && (FT_DEV_NULL != rcoll.out_type)) - close(rcoll.outfd); - res = 0; - if (0 != rcoll.out_count) { - fprintf(stderr, - ">>>> Some error occurred, remaining blocks=%d\n", - rcoll.out_count); - res = 2; - } - infull = count - rcoll.in_done_count - rcoll.in_partial; - fprintf(stderr, "%d+%d records in\n", infull, rcoll.in_partial); - outfull = count - rcoll.out_done_count - rcoll.out_partial; - fprintf(stderr, "%d+%d records out\n", outfull, rcoll.out_partial); - if (rcoll.dio_incomplete) { - int fd; - char c; - - fprintf(stderr, - ">> Direct IO requested but incomplete %d times\n", - rcoll.dio_incomplete); - if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { - if (1 == read(fd, &c, 1)) { - if ('0' == c) - fprintf(stderr, - ">>> %s set to '0' but should be set " - "to '1' for direct IO\n", - proc_allow_dio); - } - close(fd); - } - } - if (rcoll.sum_of_resids) - fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", - rcoll.sum_of_resids); - return res; -} diff --git a/testcases/kernel/fs/scsi/ltpscsi/sg_err.c b/testcases/kernel/fs/scsi/ltpscsi/sg_err.c deleted file mode 100644 index 08eba2cf3..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/sg_err.c +++ /dev/null @@ -1,1379 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "sg_include.h" -#include "sg_err.h" - -/* This file is a huge cut, paste and hack from linux/drivers/scsi/constant.c -* which I guess was written by: -* Copyright (C) 1993, 1994, 1995 Eric Youngdale - -* The rest of this is: -* Copyright (C) 1999 - 2003 D. Gilbert -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2, or (at your option) -* any later version. -* -* ASCII values for a number of symbolic constants, printing functions, etc. -* -* Some of the tables have been updated for SCSI 2. -* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002) -* -* Version 0.89 (20030313) -* sense key specific field (bytes 15-17) decoding [Trent Piepho] -*/ - -#define OUTP stderr - -static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, - 16, 12, 10, 10 -}; - -#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] - -static const char unknown[] = "UNKNOWN"; - -static const char *group_0_commands[] = { -/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", -/* 04-07 */ "Format Unit", "Read Block Limits", unknown, - "Reasssign Blocks", -/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, - unknown, -/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", - "Inquiry", -/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", -/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", -/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", -/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, -}; - -static const char *group_1_commands[] = { -/* 20-23 */ unknown, unknown, unknown, "Read Format capacities", -/* 24-28 */ "Set window", "Read Capacity", - unknown, unknown, "Read (10)", -/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", - "Read updated block", -/* 2e-31 */ "Write Verify", "Verify", "Search High", "Search Equal", -/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", -/* 35-37 */ "Synchronize Cache", "Lock/Unlock Cache", - "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", - "Read Buffer", -/* 3d-3f */ "Update Block", "Read Long", "Write Long", -}; - -static const char *group_2_commands[] = { -/* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", - "Play audio (10)", "Get configuration", "Play audio msf", - "Play audio track/index", -/* 49-4f */ "Play track relative (10)", "Get event status notification", - "Pause/resume", "Log Select", "Log Sense", "Stop play/scan", - unknown, -/* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", - "Xdread, Read track info", - "Reserve track", "Send OPC onfo", "Mode Select (10)", -/* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", - "Read master cue", - "Mode Sense (10)", "Close track/session", -/* 5c-5f */ "Read buffer capacity", "Send cue sheet", - "Persistent reserve in", - "Persistent reserve out", -}; - -/* The following are 16 byte commands in group 4 */ -static const char *group_4_commands[] = { -/* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", - "Extended copy", - "Receive copy results", -/* 85-89 */ "Memory Export In (16)", "Access control in", - "Access control out", - "Read (16)", "Memory Export Out (16)", -/* 8a-8f */ "Write (16)", unknown, "Read attributes", - "Write attributes", - "Write and verify (16)", "Verify (16)", -/* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)", - "Lock/unlock cache (16)", "Write same (16)", unknown, -/* 95-99 */ unknown, unknown, unknown, unknown, unknown, -/* 9a-9f */ unknown, unknown, unknown, unknown, "Service action in", - "Service action out", -}; - -/* The following are 12 byte commands in group 5 */ -static const char *group_5_commands[] = { -/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance (in)", - "Maintenance (out)", "Move medium/play audio(12)", -/* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)", - "Play track relative(12)", -/* aa-ae */ "Write(12)", unknown, "Erase(12), Get Performance", - "Read DVD structure", "Write and verify(12)", -/* af-b1 */ "Verify(12)", "Search data high(12)", - "Search data equal(12)", -/* b2-b4 */ "Search data low(12)", "Set limits(12)", - "Read element status attached", -/* b5-b6 */ "Request volume element address", - "Send volume tag, set streaming", -/* b7-b9 */ "Read defect data(12)", "Read element status", - "Read CD msf", -/* ba-bc */ "Redundancy group (in), Scan", - "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd", -/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd", - "Volume set (out), Send DVD structure", -}; - -#define group(opcode) (((opcode) >> 5) & 7) - -#define RESERVED_GROUP 0 -#define VENDOR_GROUP 1 - -static const char **commands[] = { - group_0_commands, group_1_commands, group_2_commands, - (const char **)RESERVED_GROUP, group_4_commands, - group_5_commands, (const char **)VENDOR_GROUP, - (const char **)VENDOR_GROUP -}; - -static const char reserved[] = "RESERVED"; -static const char vendor[] = "VENDOR SPECIFIC"; - -static void print_opcode(int opcode) -{ - const char **table = commands[group(opcode)]; - - switch ((unsigned long)table) { - case RESERVED_GROUP: - fprintf(OUTP, "%s(0x%02x)", reserved, opcode); - break; - case VENDOR_GROUP: - fprintf(OUTP, "%s(0x%02x)", vendor, opcode); - break; - default: - fprintf(OUTP, "%s", table[opcode & 0x1f]); - break; - } -} - -void sg_print_command(const unsigned char *command) -{ - int k, s; - print_opcode(command[0]); - fprintf(OUTP, " ["); - for (k = 0, s = COMMAND_SIZE(command[0]); k < s; ++k) - fprintf(OUTP, "%02x ", command[k]); - fprintf(OUTP, "]\n"); -} - -void sg_print_status(int masked_status) -{ - int scsi_status = (masked_status << 1) & 0x7e; - - sg_print_scsi_status(scsi_status); -} - -void sg_print_scsi_status(int scsi_status) -{ - const char *ccp; - - scsi_status &= 0x7e; /* sanitize as much as possible */ - switch (scsi_status) { - case 0: - ccp = "Good"; - break; - case 0x2: - ccp = "Check Condition"; - break; - case 0x4: - ccp = "Condition Met"; - break; - case 0x8: - ccp = "Busy"; - break; - case 0x10: - ccp = "Intermediate"; - break; - case 0x14: - ccp = "Intermediate-Condition Met"; - break; - case 0x18: - ccp = "Reservation Conflict"; - break; - case 0x22: - ccp = "Command Terminated (obsolete)"; - break; - case 0x28: - ccp = "Task set Full"; - break; - case 0x30: - ccp = "ACA Active"; - break; - case 0x40: - ccp = "Task Aborted"; - break; - default: - ccp = "Unknown status"; - break; - } - fprintf(OUTP, "%s ", ccp); -} - -/* In brackets is the related SCSI document (see www.t10.org) with the */ -/* peripheral device type after the colon */ -/* No programmatic use is made of these flags currently */ -#define D 0x0001 /* DIRECT ACCESS DEVICE (disk) [SBC-2: 0] */ -#define T 0x0002 /* SEQUENTIAL ACCESS DEVICE (tape) [SSC: 1] */ -#define L 0x0004 /* PRINTER DEVICE [SSC: 2] */ -#define P 0x0008 /* PROCESSOR DEVICE [SPC-2: 3] */ -#define W 0x0010 /* WRITE ONCE READ MULTIPLE DEVICE [SBC-2: 4] */ -#define R 0x0020 /* CD/DVD DEVICE [MMC-2: 5] */ -#define S 0x0040 /* SCANNER DEVICE [SCSI-2 (obsolete): 6] */ -#define O 0x0080 /* OPTICAL MEMORY DEVICE [SBC-2: 7] */ -#define M 0x0100 /* MEDIA CHANGER DEVICE [SMC-2: 8] */ -#define C 0x0200 /* COMMUNICATION DEVICE [SCSI-2 (obsolete): 9] */ -#define A 0x0400 /* ARRAY STORAGE [SCC-2: 12] */ -#define E 0x0800 /* ENCLOSURE SERVICES DEVICE [SES: 13] */ -#define B 0x1000 /* SIMPLIFIED DIRECT ACCESS DEVICE [RBC: 14] */ -#define K 0x2000 /* OPTICAL CARD READER/WRITER DEVICE [OCRW: 15] */ - -#define SC_ALL_DEVS ( D|T|L|P|W|R|S|O|M|C|A|E|B|K ) - -/* oft used strings are encoded using ASCII codes 0x1 to 0x1f . */ -/* This is to save space. This encoding should be UTF-8 and */ -/* UTF-16 friendly. */ -#define SC_AUDIO_PLAY_OPERATION "\x1" -#define SC_LOGICAL_UNIT "\x2" -#define SC_NOT_READY "\x3" -#define SC_OPERATION "\x4" -#define SC_IN_PROGRESS "\x5" -#define SC_HARDWARE_IF "\x6" -#define SC_CONTROLLER_IF "\x7" -#define SC_DATA_CHANNEL_IF "\x8" -#define SC_SERVO_IF "\x9" -#define SC_SPINDLE_IF "\xa" -#define SC_FIRMWARE_IF "\xb" -#define SC_RECOVERED_DATA "\xc" -#define SC_ERROR_RATE_TOO_HIGH "\xd" -#define SC_TIMES_TOO_HIGH "\xe" - -struct error_info { - unsigned char code1, code2; - unsigned short int devices; - const char *text; -}; - -struct error_info2 { - unsigned char code1, code2_min, code2_max; - unsigned short int devices; - const char *text; -}; - -static struct error_info2 additional2[] = { - {0x40, 0x00, 0x7f, D, "Ram failure (%x)"}, - {0x40, 0x80, 0xff, D | T | L | P | W | R | S | O | M | C, - "Diagnostic failure on component (%x)"}, - {0x41, 0x00, 0xff, D, "Data path failure (%x)"}, - {0x42, 0x00, 0xff, D, "Power-on or self-test failure (%x)"}, - {0, 0, 0, 0, NULL} -}; - -static struct error_info additional[] = { - {0x00, 0x00, SC_ALL_DEVS, "No additional sense information"}, - {0x00, 0x01, T, "Filemark detected"}, - {0x00, 0x02, T | S, "End-of-partition/medium detected"}, - {0x00, 0x03, T, "Setmark detected"}, - {0x00, 0x04, T | S, "Beginning-of-partition/medium detected"}, - {0x00, 0x05, T | L | S, "End-of-data detected"}, - {0x00, 0x06, SC_ALL_DEVS, "I/O process terminated"}, - {0x00, 0x11, R, SC_AUDIO_PLAY_OPERATION SC_IN_PROGRESS}, - {0x00, 0x12, R, SC_AUDIO_PLAY_OPERATION "paused"}, - {0x00, 0x13, R, SC_AUDIO_PLAY_OPERATION "successfully completed"}, - {0x00, 0x14, R, SC_AUDIO_PLAY_OPERATION "stopped due to error"}, - {0x00, 0x15, R, "No current audio status to return"}, - {0x00, 0x16, SC_ALL_DEVS, SC_OPERATION SC_IN_PROGRESS}, - {0x00, 0x17, D | T | L | W | R | S | O | M | A | E | B | K, - "Cleaning requested"}, - {0x00, 0x18, T, "Erase" SC_OPERATION SC_IN_PROGRESS}, - {0x00, 0x19, T, "Locate" SC_OPERATION SC_IN_PROGRESS}, - {0x00, 0x1a, T, "Rewind" SC_OPERATION SC_IN_PROGRESS}, - {0x00, 0x1b, T, "Set capacity" SC_OPERATION SC_IN_PROGRESS}, - {0x00, 0x1c, T, "Verify" SC_OPERATION SC_IN_PROGRESS}, - {0x01, 0x00, D | W | O | B | K, "No index/sector signal"}, - {0x02, 0x00, D | W | R | O | M | B | K, "No seek complete"}, - {0x03, 0x00, D | T | L | W | S | O | B | K, - "Peripheral device write fault"}, - {0x03, 0x01, T, "No write current"}, - {0x03, 0x02, T, "Excessive write errors"}, - {0x04, 0x00, SC_ALL_DEVS, - SC_LOGICAL_UNIT SC_NOT_READY "cause not reportable"}, - {0x04, 0x01, SC_ALL_DEVS, - SC_LOGICAL_UNIT "is" SC_IN_PROGRESS "of becoming ready"}, - {0x04, 0x02, SC_ALL_DEVS, - SC_LOGICAL_UNIT SC_NOT_READY "initializing cmd. required"}, - {0x04, 0x03, SC_ALL_DEVS, - SC_LOGICAL_UNIT SC_NOT_READY "manual intervention required"}, - {0x04, 0x04, D | T | L | R | O | B, - SC_LOGICAL_UNIT SC_NOT_READY "format" SC_IN_PROGRESS}, - {0x04, 0x05, D | T | W | O | M | C | A | B | K, - SC_LOGICAL_UNIT SC_NOT_READY "rebuild" SC_IN_PROGRESS}, - {0x04, 0x06, D | T | W | O | M | C | A | B | K, - SC_LOGICAL_UNIT SC_NOT_READY "recalculation" SC_IN_PROGRESS}, - {0x04, 0x07, SC_ALL_DEVS, - SC_LOGICAL_UNIT SC_NOT_READY SC_OPERATION SC_IN_PROGRESS}, - {0x04, 0x08, R, - SC_LOGICAL_UNIT SC_NOT_READY "long write" SC_IN_PROGRESS}, - {0x04, 0x09, SC_ALL_DEVS, - SC_LOGICAL_UNIT SC_NOT_READY "self-test" SC_IN_PROGRESS}, - {0x04, 0x0a, SC_ALL_DEVS, - SC_LOGICAL_UNIT "not accessible, asymmetric access state transition"}, - {0x04, 0x0b, SC_ALL_DEVS, - SC_LOGICAL_UNIT "not accessible, target port in standby state"}, - {0x04, 0x0c, SC_ALL_DEVS, - SC_LOGICAL_UNIT "not accessible, target port in unavailable state"}, - {0x04, 0x10, SC_ALL_DEVS, - SC_LOGICAL_UNIT SC_NOT_READY "auxiliary memory not accessible"}, - {0x05, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K, - SC_LOGICAL_UNIT "does not respond to selection"}, - {0x06, 0x00, D | W | R | O | M | B | K, "No reference position found"}, - {0x07, 0x00, D | T | L | W | R | S | O | M | B | K, - "Multiple peripheral devices selected"}, - {0x08, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K, - SC_LOGICAL_UNIT "communication failure"}, - {0x08, 0x01, D | T | L | W | R | S | O | M | C | A | E | B | K, - SC_LOGICAL_UNIT "communication time-out"}, - {0x08, 0x02, D | T | L | W | R | S | O | M | C | A | E | B | K, - SC_LOGICAL_UNIT "communication parity error"}, - {0x08, 0x03, D | T | R | O | M | B | K, - SC_LOGICAL_UNIT "communication CRC error (Ultra-DMA/32)"}, - {0x08, 0x04, D | T | L | P | W | R | S | O | C | K, - "Unreachable copy target"}, - {0x09, 0x00, D | T | W | R | O | B, "Track following error"}, - {0x09, 0x01, W | R | O | K, "Tracking servo failure"}, - {0x09, 0x02, W | R | O | K, "Focus servo failure"}, - {0x09, 0x03, W | R | O, "Spindle servo failure"}, - {0x09, 0x04, D | T | W | R | O | B, "Head select fault"}, - {0x0A, 0x00, SC_ALL_DEVS, "Error log overflow"}, - {0x0B, 0x00, SC_ALL_DEVS, "Warning"}, - {0x0B, 0x01, SC_ALL_DEVS, "Warning - specified temperature exceeded"}, - {0x0B, 0x02, SC_ALL_DEVS, "Warning - enclosure degraded"}, - {0x0C, 0x00, T | R | S, "Write error"}, - {0x0C, 0x01, K, "Write error - recovered with auto reallocation"}, - {0x0C, 0x02, D | W | O | B | K, - "Write error - auto reallocation failed"}, - {0x0C, 0x03, D | W | O | B | K, "Write error - recommend reassignment"}, - {0x0C, 0x04, D | T | W | O | B, "Compression check miscompare error"}, - {0x0C, 0x05, D | T | W | O | B, - "Data expansion occurred during compression"}, - {0x0C, 0x06, D | T | W | O | B, "Block not compressible"}, - {0x0C, 0x07, R, "Write error - recovery needed"}, - {0x0C, 0x08, R, "Write error - recovery failed"}, - {0x0C, 0x09, R, "Write error - loss of streaming"}, - {0x0C, 0x0A, R, "Write error - padding blocks added"}, - {0x0C, 0x0B, D | T | W | R | O | M | B, "Auxiliary memory write error"}, - {0x0C, 0x0C, SC_ALL_DEVS, "Write error - unexpected unsolicited data"}, - {0x0C, 0x0D, SC_ALL_DEVS, "Write error - not enough unsolicited data"}, - {0x0D, 0x00, D | T | L | P | W | R | S | O | C | A | K, - "Error detected by third party temporary initiator"}, - {0x0D, 0x01, D | T | L | P | W | R | S | O | C | A | K, - "Third party device failure"}, - {0x0D, 0x02, D | T | L | P | W | R | S | O | C | A | K, - "Copy target device not reachable"}, - {0x0D, 0x03, D | T | L | P | W | R | S | O | C | A | K, - "Incorrect copy target device"}, - {0x0D, 0x04, D | T | L | P | W | R | S | O | C | A | K, - "Copy target device underrun"}, - {0x0D, 0x05, D | T | L | P | W | R | S | O | C | A | K, - "Copy target device overrun"}, - {0x10, 0x00, D | W | O | B | K, "Id CRC or ECC error"}, - {0x11, 0x00, D | T | W | R | S | O | B | K, "Unrecovered read error"}, - {0x11, 0x01, D | T | W | R | S | O | B | K, "Read retries exhausted"}, - {0x11, 0x02, D | T | W | R | S | O | B | K, - "Error too long to correct"}, - {0x11, 0x03, D | T | W | S | O | B | K, "Multiple read errors"}, - {0x11, 0x04, D | W | O | B | K, - "Unrecovered read error - auto reallocate failed"}, - {0x11, 0x05, W | R | O | B, "L-EC uncorrectable error"}, - {0x11, 0x06, W | R | O | B, "CIRC unrecovered error"}, - {0x11, 0x07, W | O | B, "Data re-synchronization error"}, - {0x11, 0x08, T, "Incomplete block read"}, - {0x11, 0x09, T, "No gap found"}, - {0x11, 0x0A, D | T | O | B | K, "Miscorrected error"}, - {0x11, 0x0B, D | W | O | B | K, - "Unrecovered read error - recommend reassignment"}, - {0x11, 0x0C, D | W | O | B | K, - "Unrecovered read error - recommend rewrite the data"}, - {0x11, 0x0D, D | T | W | R | O | B, "De-compression CRC error"}, - {0x11, 0x0E, D | T | W | R | O | B, - "Cannot decompress using declared algorithm"}, - {0x11, 0x0F, R, "Error reading UPC/EAN number"}, - {0x11, 0x10, R, "Error reading ISRC number"}, - {0x11, 0x11, R, "Read error - loss of streaming"}, - {0x11, 0x12, D | T | W | R | O | M | B, "Auxiliary memory read error"}, - {0x11, 0x13, SC_ALL_DEVS, "Read error - failed retransmission request"}, - {0x12, 0x00, D | W | O | B | K, "Address mark not found for id field"}, - {0x13, 0x00, D | W | O | B | K, - "Address mark not found for data field"}, - {0x14, 0x00, D | T | L | W | R | S | O | B | K, - "Recorded entity not found"}, - {0x14, 0x01, D | T | W | R | O | B | K, "Record not found"}, - {0x14, 0x02, T, "Filemark or setmark not found"}, - {0x14, 0x03, T, "End-of-data not found"}, - {0x14, 0x04, T, "Block sequence error"}, - {0x14, 0x05, D | T | W | O | B | K, - "Record not found - recommend reassignment"}, - {0x14, 0x06, D | T | W | O | B | K, - "Record not found - data auto-reallocated"}, - {0x14, 0x07, T, "Locate" SC_OPERATION " failure"}, - {0x15, 0x00, D | T | L | W | R | S | O | M | B | K, - "Random positioning error"}, - {0x15, 0x01, D | T | L | W | R | S | O | M | B | K, - "Mechanical positioning error"}, - {0x15, 0x02, D | T | W | R | O | B | K, - "Positioning error detected by read of medium"}, - {0x16, 0x00, D | W | O | B | K, "Data synchronization mark error"}, - {0x16, 0x01, D | W | O | B | K, "Data sync error - data rewritten"}, - {0x16, 0x02, D | W | O | B | K, "Data sync error - recommend rewrite"}, - {0x16, 0x03, D | W | O | B | K, - "Data sync error - data auto-reallocated"}, - {0x16, 0x04, D | W | O | B | K, - "Data sync error - recommend reassignment"}, - {0x17, 0x00, D | T | W | R | S | O | B | K, - SC_RECOVERED_DATA "with no error correction applied"}, - {0x17, 0x01, D | T | W | R | S | O | B | K, - SC_RECOVERED_DATA "with retries"}, - {0x17, 0x02, D | T | W | R | O | B | K, - SC_RECOVERED_DATA "with positive head offset"}, - {0x17, 0x03, D | T | W | R | O | B | K, - SC_RECOVERED_DATA "with negative head offset"}, - {0x17, 0x04, W | R | O | B, - SC_RECOVERED_DATA "with retries and/or circ applied"}, - {0x17, 0x05, D | W | R | O | B | K, - SC_RECOVERED_DATA "using previous sector id"}, - {0x17, 0x06, D | W | O | B | K, - SC_RECOVERED_DATA "without ecc - data auto-reallocated"}, - {0x17, 0x07, D | W | R | O | B | K, - SC_RECOVERED_DATA "without ecc - recommend reassignment"}, - {0x17, 0x08, D | W | R | O | B | K, - SC_RECOVERED_DATA "without ecc - recommend rewrite"}, - {0x17, 0x09, D | W | R | O | B | K, - SC_RECOVERED_DATA "without ecc - data rewritten"}, - {0x18, 0x00, D | T | W | R | O | B | K, - SC_RECOVERED_DATA "with error correction applied"}, - {0x18, 0x01, D | W | R | O | B | K, - SC_RECOVERED_DATA "with error corr. & retries applied"}, - {0x18, 0x02, D | W | R | O | B | K, - SC_RECOVERED_DATA "- data auto-reallocated"}, - {0x18, 0x03, R, SC_RECOVERED_DATA "with CIRC"}, - {0x18, 0x04, R, SC_RECOVERED_DATA "with L-EC"}, - {0x18, 0x05, D | W | R | O | B | K, - SC_RECOVERED_DATA "- recommend reassignment"}, - {0x18, 0x06, D | W | R | O | B | K, - SC_RECOVERED_DATA "- recommend rewrite"}, - {0x18, 0x07, D | W | O | B | K, - SC_RECOVERED_DATA "with ecc - data rewritten"}, - {0x18, 0x08, R, SC_RECOVERED_DATA "with linking"}, - {0x19, 0x00, D | O | K, "Defect list error"}, - {0x19, 0x01, D | O | K, "Defect list not available"}, - {0x19, 0x02, D | O | K, "Defect list error in primary list"}, - {0x19, 0x03, D | O | K, "Defect list error in grown list"}, - {0x1A, 0x00, SC_ALL_DEVS, "Parameter list length error"}, - {0x1B, 0x00, SC_ALL_DEVS, "Synchronous data transfer error"}, - {0x1C, 0x00, D | O | B | K, "Defect list not found"}, - {0x1C, 0x01, D | O | B | K, "Primary defect list not found"}, - {0x1C, 0x02, D | O | B | K, "Grown defect list not found"}, - {0x1D, 0x00, D | T | W | R | O | B | K, - "Miscompare during verify" SC_OPERATION}, - {0x1E, 0x00, D | W | O | B | K, "Recovered id with ecc correction"}, - {0x1F, 0x00, D | O | K, "Partial defect list transfer"}, - {0x20, 0x00, SC_ALL_DEVS, "Invalid command" SC_OPERATION " code"}, - {0x20, 0x01, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - initiator pending-enrolled"}, - {0x20, 0x02, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - no access rights"}, - {0x20, 0x03, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - no mgmt id key"}, - {0x20, 0x04, T, "Illegal command while in write capable state"}, - {0x20, 0x05, T, "Obsolete"}, - {0x20, 0x06, T, "Illegal command while in explicit address mode"}, - {0x20, 0x07, T, "Illegal command while in implicit address mode"}, - {0x20, 0x08, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - enrollment conflict"}, - {0x20, 0x09, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - invalid LU identifier"}, - {0x20, 0x0A, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - invalid proxy token"}, - {0x20, 0x0B, D | T | P | W | R | O | M | A | E | B | K, - "Access denied - ACL LUN conflict"}, - {0x21, 0x00, D | T | W | R | O | M | B | K, - "Logical block address out of range"}, - {0x21, 0x01, D | T | W | R | O | M | B | K, "Invalid element address"}, - {0x21, 0x02, R, "Invalid address for write"}, - {0x22, 0x00, D, "Illegal function (use 20 00,24 00,or 26 00)"}, - {0x24, 0x00, SC_ALL_DEVS, "Invalid field in cdb"}, - {0x24, 0x01, SC_ALL_DEVS, "CDB decryption error"}, - {0x25, 0x00, SC_ALL_DEVS, SC_LOGICAL_UNIT "not supported"}, - {0x26, 0x00, SC_ALL_DEVS, "Invalid field in parameter list"}, - {0x26, 0x01, SC_ALL_DEVS, "Parameter not supported"}, - {0x26, 0x02, SC_ALL_DEVS, "Parameter value invalid"}, - {0x26, 0x03, D | T | L | P | W | R | S | O | M | C | A | E | K, - "Threshold parameters not supported"}, - {0x26, 0x04, SC_ALL_DEVS, "Invalid release of persistent reservation"}, - {0x26, 0x05, D | T | L | P | W | R | S | O | M | C | A | B | K, - "Data decryption error"}, - {0x26, 0x06, D | T | L | P | W | R | S | O | C | K, - "Too many target descriptors"}, - {0x26, 0x07, D | T | L | P | W | R | S | O | C | K, - "Unsupported target descriptor type code"}, - {0x26, 0x08, D | T | L | P | W | R | S | O | C | K, - "Too many segment descriptors"}, - {0x26, 0x09, D | T | L | P | W | R | S | O | C | K, - "Unsupported segment descriptor type code"}, - {0x26, 0x0A, D | T | L | P | W | R | S | O | C | K, - "Unexpected inexact segment"}, - {0x26, 0x0B, D | T | L | P | W | R | S | O | C | K, - "Inline data length exceeded"}, - {0x26, 0x0C, D | T | L | P | W | R | S | O | C | K, - "Invalid" SC_OPERATION " for copy source or destination"}, - {0x26, 0x0D, D | T | L | P | W | R | S | O | C | K, - "Copy segment granularity violation"}, - {0x27, 0x00, D | T | W | R | O | B | K, "Write protected"}, - {0x27, 0x01, D | T | W | R | O | B | K, "Hardware write protected"}, - {0x27, 0x02, D | T | W | R | O | B | K, - SC_LOGICAL_UNIT "software write protected"}, - {0x27, 0x03, T | R, "Associated write protect"}, - {0x27, 0x04, T | R, "Persistent write protect"}, - {0x27, 0x05, T | R, "Permanent write protect"}, - {0x27, 0x06, R, "Conditional write protect"}, - {0x28, 0x00, SC_ALL_DEVS, - "Not ready to ready change, medium may have changed"}, - {0x28, 0x01, D | T | W | R | O | M | B, - "Import or export element accessed"}, - {0x29, 0x00, SC_ALL_DEVS, - "Power on,reset,or bus device reset occurred"}, - {0x29, 0x01, SC_ALL_DEVS, "Power on occurred"}, - {0x29, 0x02, SC_ALL_DEVS, "Scsi bus reset occurred"}, - {0x29, 0x03, SC_ALL_DEVS, "Bus device reset function occurred"}, - {0x29, 0x04, SC_ALL_DEVS, "Device internal reset"}, - {0x29, 0x05, SC_ALL_DEVS, "Transceiver mode changed to single-ended"}, - {0x29, 0x06, SC_ALL_DEVS, "Transceiver mode changed to lvd"}, - {0x29, 0x07, SC_ALL_DEVS, "I_T nexus loss occurred"}, - {0x2A, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K, - "Parameters changed"}, - {0x2A, 0x01, D | T | L | W | R | S | O | M | C | A | E | B | K, - "Mode parameters changed"}, - {0x2A, 0x02, D | T | L | W | R | S | O | M | C | A | E | K, - "Log parameters changed"}, - {0x2A, 0x03, D | T | L | P | W | R | S | O | M | C | A | E | K, - "Reservations preempted"}, - {0x2A, 0x04, D | T | L | P | W | R | S | O | M | C | A | E, - "Reservations released"}, - {0x2A, 0x05, D | T | L | P | W | R | S | O | M | C | A | E, - "Registrations preempted"}, - {0x2A, 0x06, SC_ALL_DEVS, "Asymmetric access state changed"}, - {0x2A, 0x07, SC_ALL_DEVS, - "Implicit asymmetric access state transition failed"}, - {0x2B, 0x00, D | T | L | P | W | R | S | O | C | K, - "Copy cannot execute since host cannot disconnect"}, - {0x2C, 0x00, SC_ALL_DEVS, "Command sequence error"}, - {0x2C, 0x01, S, "Too many windows specified"}, - {0x2C, 0x02, S, "Invalid combination of windows specified"}, - {0x2C, 0x03, R, "Current program area is not empty"}, - {0x2C, 0x04, R, "Current program area is empty"}, - {0x2C, 0x05, B, "Illegal power condition request"}, - {0x2C, 0x06, R, "Persistent prevent conflict"}, - {0x2C, 0x07, SC_ALL_DEVS, "Previous busy status"}, - {0x2C, 0x08, SC_ALL_DEVS, "Previous task set full status"}, - {0x2C, 0x09, D | T | L | P | W | R | S | O | M | E | B | K, - "Previous reservation conflict status"}, - {0x2D, 0x00, T, "Overwrite error on update in place"}, - {0x2F, 0x00, SC_ALL_DEVS, "Commands cleared by another initiator"}, - {0x30, 0x00, D | T | W | R | O | M | B | K, - "Incompatible medium installed"}, - {0x30, 0x01, D | T | W | R | O | B | K, - "Cannot read medium - unknown format"}, - {0x30, 0x02, D | T | W | R | O | B | K, - "Cannot read medium - incompatible format"}, - {0x30, 0x03, D | T | R | K, "Cleaning cartridge installed"}, - {0x30, 0x04, D | T | W | R | O | B | K, - "Cannot write medium - unknown format"}, - {0x30, 0x05, D | T | W | R | O | B | K, - "Cannot write medium - incompatible format"}, - {0x30, 0x06, D | T | W | R | O | B, - "Cannot format medium - incompatible medium"}, - {0x30, 0x07, D | T | L | W | R | S | O | M | A | E | B | K, - "Cleaning failure"}, - {0x30, 0x08, R, "Cannot write - application code mismatch"}, - {0x30, 0x09, R, "Current session not fixated for append"}, - {0x30, 0x10, R, "Medium not formatted"}, /* should ascq be 0xa ?? */ - {0x31, 0x00, D | T | W | R | O | B | K, "Medium format corrupted"}, - {0x31, 0x01, D | L | R | O | B, "Format command failed"}, - {0x31, 0x02, R, "Zoned formatting failed due to spare linking"}, - {0x32, 0x00, D | W | O | B | K, "No defect spare location available"}, - {0x32, 0x01, D | W | O | B | K, "Defect list update failure"}, - {0x33, 0x00, T, "Tape length error"}, - {0x34, 0x00, SC_ALL_DEVS, "Enclosure failure"}, - {0x35, 0x00, SC_ALL_DEVS, "Enclosure services failure"}, - {0x35, 0x01, SC_ALL_DEVS, "Unsupported enclosure function"}, - {0x35, 0x02, SC_ALL_DEVS, "Enclosure services unavailable"}, - {0x35, 0x03, SC_ALL_DEVS, "Enclosure services transfer failure"}, - {0x35, 0x04, SC_ALL_DEVS, "Enclosure services transfer refused"}, - {0x36, 0x00, L, "Ribbon,ink,or toner failure"}, - {0x37, 0x00, D | T | L | W | R | S | O | M | C | A | E | B | K, - "Rounded parameter"}, - {0x38, 0x00, B, "Event status notification"}, - {0x38, 0x02, B, "Esn - power management class event"}, - {0x38, 0x04, B, "Esn - media class event"}, - {0x38, 0x06, B, "Esn - device busy class event"}, - {0x39, 0x00, D | T | L | W | R | S | O | M | C | A | E | K, - "Saving parameters not supported"}, - {0x3A, 0x00, D | T | L | W | R | S | O | M | B | K, - "Medium not present"}, - {0x3A, 0x01, D | T | W | R | O | M | B | K, - "Medium not present - tray closed"}, - {0x3A, 0x02, D | T | W | R | O | M | B | K, - "Medium not present - tray open"}, - {0x3A, 0x03, D | T | W | R | O | M | B, - "Medium not present - loadable"}, - {0x3A, 0x04, D | T | W | R | O | M | B, - "Medium not present - medium auxiliary memory accessible"}, - {0x3B, 0x00, T | L, "Sequential positioning error"}, - {0x3B, 0x01, T, "Tape position error at beginning-of-medium"}, - {0x3B, 0x02, T, "Tape position error at end-of-medium"}, - {0x3B, 0x03, L, "Tape or electronic vertical forms unit " SC_NOT_READY}, - {0x3B, 0x04, L, "Slew failure"}, - {0x3B, 0x05, L, "Paper jam"}, - {0x3B, 0x06, L, "Failed to sense top-of-form"}, - {0x3B, 0x07, L, "Failed to sense bottom-of-form"}, - {0x3B, 0x08, T, "Reposition error"}, - {0x3B, 0x09, S, "Read past end of medium"}, - {0x3B, 0x0A, S, "Read past beginning of medium"}, - {0x3B, 0x0B, S, "Position past end of medium"}, - {0x3B, 0x0C, T | S, "Position past beginning of medium"}, - {0x3B, 0x0D, D | T | W | R | O | M | B | K, - "Medium destination element full"}, - {0x3B, 0x0E, D | T | W | R | O | M | B | K, - "Medium source element empty"}, - {0x3B, 0x0F, R, "End of medium reached"}, - {0x3B, 0x11, D | T | W | R | O | M | B | K, - "Medium magazine not accessible"}, - {0x3B, 0x12, D | T | W | R | O | M | B | K, "Medium magazine removed"}, - {0x3B, 0x13, D | T | W | R | O | M | B | K, "Medium magazine inserted"}, - {0x3B, 0x14, D | T | W | R | O | M | B | K, "Medium magazine locked"}, - {0x3B, 0x15, D | T | W | R | O | M | B | K, "Medium magazine unlocked"}, - {0x3B, 0x16, R, "Mechanical positioning or changer error"}, - {0x3D, 0x00, D | T | L | P | W | R | S | O | M | C | A | E | K, - "Invalid bits in identify message"}, - {0x3E, 0x00, SC_ALL_DEVS, - SC_LOGICAL_UNIT "has not self-configured yet"}, - {0x3E, 0x01, SC_ALL_DEVS, SC_LOGICAL_UNIT "failure"}, - {0x3E, 0x02, SC_ALL_DEVS, "Timeout on logical unit"}, - {0x3E, 0x03, SC_ALL_DEVS, SC_LOGICAL_UNIT "failed self-test"}, - {0x3E, 0x04, SC_ALL_DEVS, - SC_LOGICAL_UNIT "unable to update self-test log"}, - {0x3F, 0x00, SC_ALL_DEVS, "Target operating conditions have changed"}, - {0x3F, 0x01, SC_ALL_DEVS, "Microcode has been changed"}, - {0x3F, 0x02, D | T | L | P | W | R | S | O | M | C | B | K, - "Changed operating definition"}, - {0x3F, 0x03, SC_ALL_DEVS, "Inquiry data has changed"}, - {0x3F, 0x04, D | T | W | R | O | M | C | A | E | B | K, - "Component device attached"}, - {0x3F, 0x05, D | T | W | R | O | M | C | A | E | B | K, - "Device identifier changed"}, - {0x3F, 0x06, D | T | W | R | O | M | C | A | E | B, - "Redundancy group created or modified"}, - {0x3F, 0x07, D | T | W | R | O | M | C | A | E | B, - "Redundancy group deleted"}, - {0x3F, 0x08, D | T | W | R | O | M | C | A | E | B, - "Spare created or modified"}, - {0x3F, 0x09, D | T | W | R | O | M | C | A | E | B, "Spare deleted"}, - {0x3F, 0x0A, D | T | W | R | O | M | C | A | E | B | K, - "Volume set created or modified"}, - {0x3F, 0x0B, D | T | W | R | O | M | C | A | E | B | K, - "Volume set deleted"}, - {0x3F, 0x0C, D | T | W | R | O | M | C | A | E | B | K, - "Volume set deassigned"}, - {0x3F, 0x0D, D | T | W | R | O | M | C | A | E | B | K, - "Volume set reassigned"}, - {0x3F, 0x0E, D | T | L | P | W | R | S | O | M | C | A | E, - "Reported luns data has changed"}, - {0x3F, 0x10, D | T | W | R | O | M | B, "Medium loadable"}, - {0x3F, 0x11, D | T | W | R | O | M | B, - "Medium auxiliary memory accessible"}, - {0x40, 0x00, D, "Ram failure (should use 40 nn)"}, - /* - * FIXME(eric) - need a way to represent wildcards here. - */ - {0x40, 0x00, SC_ALL_DEVS, - "Diagnostic failure on component nn (80h-ffh)"}, - {0x41, 0x00, D, "Data path failure (should use 40 nn)"}, - {0x42, 0x00, D, "Power-on or self-test failure (should use 40 nn)"}, - {0x43, 0x00, SC_ALL_DEVS, "Message error"}, - {0x44, 0x00, SC_ALL_DEVS, "Internal target failure"}, - {0x45, 0x00, SC_ALL_DEVS, "Select or reselect failure"}, - {0x46, 0x00, D | T | L | P | W | R | S | O | M | C | B | K, - "Unsuccessful soft reset"}, - {0x47, 0x00, SC_ALL_DEVS, "Scsi parity error"}, - {0x47, 0x01, SC_ALL_DEVS, "Data phase CRC error detected"}, - {0x47, 0x02, SC_ALL_DEVS, - "Scsi parity error detected during st data phase"}, - {0x47, 0x03, SC_ALL_DEVS, "Information unit CRC error detected"}, - {0x47, 0x04, SC_ALL_DEVS, - "Asynchronous information protection error detected"}, - {0x47, 0x05, SC_ALL_DEVS, "Protocol service CRC error"}, - {0x48, 0x00, SC_ALL_DEVS, "Initiator detected error message received"}, - {0x49, 0x00, SC_ALL_DEVS, "Invalid message error"}, - {0x4A, 0x00, SC_ALL_DEVS, "Command phase error"}, - {0x4B, 0x00, SC_ALL_DEVS, "Data phase error"}, - {0x4C, 0x00, SC_ALL_DEVS, SC_LOGICAL_UNIT "failed self-configuration"}, - /* - * FIXME(eric) - need a way to represent wildcards here. - */ - {0x4D, 0x00, SC_ALL_DEVS, - "Tagged overlapped commands (nn = queue tag)"}, - {0x4E, 0x00, SC_ALL_DEVS, "Overlapped commands attempted"}, - {0x50, 0x00, T, "Write append error"}, - {0x50, 0x01, T, "Write append position error"}, - {0x50, 0x02, T, "Position error related to timing"}, - {0x51, 0x00, T | R | O, "Erase failure"}, - {0x52, 0x00, T, "Cartridge fault"}, - {0x53, 0x00, D | T | L | W | R | S | O | M | B | K, - "Media load or eject failed"}, - {0x53, 0x01, T, "Unload tape failure"}, - {0x53, 0x02, D | T | W | R | O | M | B | K, "Medium removal prevented"}, - {0x54, 0x00, P, "Scsi to host system interface failure"}, - {0x55, 0x00, P, "System resource failure"}, - {0x55, 0x01, D | O | B | K, "System buffer full"}, - {0x55, 0x02, D | T | L | P | W | R | S | O | M | A | E | K, - "Insufficient reservation resources"}, - {0x55, 0x03, D | T | L | P | W | R | S | O | M | C | A | E, - "Insufficient resources"}, - {0x55, 0x04, D | T | L | P | W | R | S | O | M | A | E, - "Insufficient registration resources"}, - {0x55, 0x05, D | T | P | W | R | O | M | A | E | B | K, - "Insufficient access control resources"}, - {0x55, 0x06, D | T | W | R | O | M | B, - "Auxiliary memory out of space"}, - {0x57, 0x00, R, "Unable to recover table-of-contents"}, - {0x58, 0x00, O, "Generation does not exist"}, - {0x59, 0x00, O, "Updated block read"}, - {0x5A, 0x00, D | T | L | P | W | R | S | O | M | B | K, - "Operator request or state change input"}, - {0x5A, 0x01, D | T | W | R | O | M | B | K, - "Operator medium removal request"}, - {0x5A, 0x02, D | T | W | R | O | A | B | K, - "Operator selected write protect"}, - {0x5A, 0x03, D | T | W | R | O | A | B | K, - "Operator selected write permit"}, - {0x5B, 0x00, D | T | L | P | W | R | S | O | M | K, "Log exception"}, - {0x5B, 0x01, D | T | L | P | W | R | S | O | M | K, - "Threshold condition met"}, - {0x5B, 0x02, D | T | L | P | W | R | S | O | M | K, - "Log counter at maximum"}, - {0x5B, 0x03, D | T | L | P | W | R | S | O | M | K, - "Log list codes exhausted"}, - {0x5C, 0x00, D | O, "Rpl status change"}, - {0x5C, 0x01, D | O, "Spindles synchronized"}, - {0x5C, 0x02, D | O, "Spindles not synchronized"}, - {0x5D, 0x00, SC_ALL_DEVS, "Failure prediction threshold exceeded"}, - {0x5D, 0x01, R | B, "Media failure prediction threshold exceeded"}, - {0x5D, 0x02, R, - SC_LOGICAL_UNIT "failure prediction threshold exceeded"}, - {0x5D, 0x03, R, "spare area exhaustion prediction threshold exceeded"}, - /* large series of "impending failure" messages */ - {0x5D, 0x10, D | B, SC_HARDWARE_IF "general hard drive failure"}, - {0x5D, 0x11, D | B, SC_HARDWARE_IF "drive" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x12, D | B, SC_HARDWARE_IF "data" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x13, D | B, SC_HARDWARE_IF "seek" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x14, D | B, SC_HARDWARE_IF "too many block reassigns"}, - {0x5D, 0x15, D | B, SC_HARDWARE_IF "access" SC_TIMES_TOO_HIGH}, - {0x5D, 0x16, D | B, SC_HARDWARE_IF "start unit" SC_TIMES_TOO_HIGH}, - {0x5D, 0x17, D | B, SC_HARDWARE_IF "channel parametrics"}, - {0x5D, 0x18, D | B, SC_HARDWARE_IF "controller detected"}, - {0x5D, 0x19, D | B, SC_HARDWARE_IF "throughput performance"}, - {0x5D, 0x1A, D | B, SC_HARDWARE_IF "seek time performance"}, - {0x5D, 0x1B, D | B, SC_HARDWARE_IF "spin-up retry count"}, - {0x5D, 0x1C, D | B, SC_HARDWARE_IF "drive calibration retry count"}, - {0x5D, 0x20, D | B, SC_CONTROLLER_IF "general hard drive failure"}, - {0x5D, 0x21, D | B, SC_CONTROLLER_IF "drive" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x22, D | B, SC_CONTROLLER_IF "data" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x23, D | B, SC_CONTROLLER_IF "seek" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x24, D | B, SC_CONTROLLER_IF "too many block reassigns"}, - {0x5D, 0x25, D | B, SC_CONTROLLER_IF "access" SC_TIMES_TOO_HIGH}, - {0x5D, 0x26, D | B, SC_CONTROLLER_IF "start unit" SC_TIMES_TOO_HIGH}, - {0x5D, 0x27, D | B, SC_CONTROLLER_IF "channel parametrics"}, - {0x5D, 0x28, D | B, SC_CONTROLLER_IF "controller detected"}, - {0x5D, 0x29, D | B, SC_CONTROLLER_IF "throughput performance"}, - {0x5D, 0x2A, D | B, SC_CONTROLLER_IF "seek time performance"}, - {0x5D, 0x2B, D | B, SC_CONTROLLER_IF "spin-up retry count"}, - {0x5D, 0x2C, D | B, SC_CONTROLLER_IF "drive calibration retry count"}, - {0x5D, 0x30, D | B, SC_DATA_CHANNEL_IF "general hard drive failure"}, - {0x5D, 0x31, D | B, SC_DATA_CHANNEL_IF "drive" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x32, D | B, SC_DATA_CHANNEL_IF "data" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x33, D | B, SC_DATA_CHANNEL_IF "seek" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x34, D | B, SC_DATA_CHANNEL_IF "too many block reassigns"}, - {0x5D, 0x35, D | B, SC_DATA_CHANNEL_IF "access" SC_TIMES_TOO_HIGH}, - {0x5D, 0x36, D | B, SC_DATA_CHANNEL_IF "start unit" SC_TIMES_TOO_HIGH}, - {0x5D, 0x37, D | B, SC_DATA_CHANNEL_IF "channel parametrics"}, - {0x5D, 0x38, D | B, SC_DATA_CHANNEL_IF "controller detected"}, - {0x5D, 0x39, D | B, SC_DATA_CHANNEL_IF "throughput performance"}, - {0x5D, 0x3A, D | B, SC_DATA_CHANNEL_IF "seek time performance"}, - {0x5D, 0x3B, D | B, SC_DATA_CHANNEL_IF "spin-up retry count"}, - {0x5D, 0x3C, D | B, SC_DATA_CHANNEL_IF "drive calibration retry count"}, - {0x5D, 0x40, D | B, SC_SERVO_IF "general hard drive failure"}, - {0x5D, 0x41, D | B, SC_SERVO_IF "drive" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x42, D | B, SC_SERVO_IF "data" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x43, D | B, SC_SERVO_IF "seek" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x44, D | B, SC_SERVO_IF "too many block reassigns"}, - {0x5D, 0x45, D | B, SC_SERVO_IF "access" SC_TIMES_TOO_HIGH}, - {0x5D, 0x46, D | B, SC_SERVO_IF "start unit" SC_TIMES_TOO_HIGH}, - {0x5D, 0x47, D | B, SC_SERVO_IF "channel parametrics"}, - {0x5D, 0x48, D | B, SC_SERVO_IF "controller detected"}, - {0x5D, 0x49, D | B, SC_SERVO_IF "throughput performance"}, - {0x5D, 0x4A, D | B, SC_SERVO_IF "seek time performance"}, - {0x5D, 0x4B, D | B, SC_SERVO_IF "spin-up retry count"}, - {0x5D, 0x4C, D | B, SC_SERVO_IF "drive calibration retry count"}, - {0x5D, 0x50, D | B, SC_SPINDLE_IF "general hard drive failure"}, - {0x5D, 0x51, D | B, SC_SPINDLE_IF "drive" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x52, D | B, SC_SPINDLE_IF "data" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x53, D | B, SC_SPINDLE_IF "seek" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x54, D | B, SC_SPINDLE_IF "too many block reassigns"}, - {0x5D, 0x55, D | B, SC_SPINDLE_IF "access" SC_TIMES_TOO_HIGH}, - {0x5D, 0x56, D | B, SC_SPINDLE_IF "start unit" SC_TIMES_TOO_HIGH}, - {0x5D, 0x57, D | B, SC_SPINDLE_IF "channel parametrics"}, - {0x5D, 0x58, D | B, SC_SPINDLE_IF "controller detected"}, - {0x5D, 0x59, D | B, SC_SPINDLE_IF "throughput performance"}, - {0x5D, 0x5A, D | B, SC_SPINDLE_IF "seek time performance"}, - {0x5D, 0x5B, D | B, SC_SPINDLE_IF "spin-up retry count"}, - {0x5D, 0x5C, D | B, SC_SPINDLE_IF "drive calibration retry count"}, - {0x5D, 0x60, D | B, SC_FIRMWARE_IF "general hard drive failure"}, - {0x5D, 0x61, D | B, SC_FIRMWARE_IF "drive" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x62, D | B, SC_FIRMWARE_IF "data" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x63, D | B, SC_FIRMWARE_IF "seek" SC_ERROR_RATE_TOO_HIGH}, - {0x5D, 0x64, D | B, SC_FIRMWARE_IF "too many block reassigns"}, - {0x5D, 0x65, D | B, SC_FIRMWARE_IF "access" SC_TIMES_TOO_HIGH}, - {0x5D, 0x66, D | B, SC_FIRMWARE_IF "start unit" SC_TIMES_TOO_HIGH}, - {0x5D, 0x67, D | B, SC_FIRMWARE_IF "channel parametrics"}, - {0x5D, 0x68, D | B, SC_FIRMWARE_IF "controller detected"}, - {0x5D, 0x69, D | B, SC_FIRMWARE_IF "throughput performance"}, - {0x5D, 0x6A, D | B, SC_FIRMWARE_IF "seek time performance"}, - {0x5D, 0x6B, D | B, SC_FIRMWARE_IF "spin-up retry count"}, - {0x5D, 0x6C, D | B, SC_FIRMWARE_IF "drive calibration retry count"}, - {0x5D, 0xFF, SC_ALL_DEVS, - "Failure prediction threshold exceeded (false)"}, - {0x5E, 0x00, D | T | L | P | W | R | S | O | C | A | K, - "Low power condition on"}, - {0x5E, 0x01, D | T | L | P | W | R | S | O | C | A | K, - "Idle condition activated by timer"}, - {0x5E, 0x02, D | T | L | P | W | R | S | O | C | A | K, - "Standby condition activated by timer"}, - {0x5E, 0x03, D | T | L | P | W | R | S | O | C | A | K, - "Idle condition activated by command"}, - {0x5E, 0x04, D | T | L | P | W | R | S | O | C | A | K, - "Standby condition activated by command"}, - {0x5E, 0x41, B, "Power state change to active"}, - {0x5E, 0x42, B, "Power state change to idle"}, - {0x5E, 0x43, B, "Power state change to standby"}, - {0x5E, 0x45, B, "Power state change to sleep"}, - {0x5E, 0x47, B | K, "Power state change to device control"}, - {0x60, 0x00, S, "Lamp failure"}, - {0x61, 0x00, S, "Video acquisition error"}, - {0x61, 0x01, S, "Unable to acquire video"}, - {0x61, 0x02, S, "Out of focus"}, - {0x62, 0x00, S, "Scan head positioning error"}, - {0x63, 0x00, R, "End of user area encountered on this track"}, - {0x63, 0x01, R, "Packet does not fit in available space"}, - {0x64, 0x00, R, "Illegal mode for this track"}, - {0x64, 0x01, R, "Invalid packet size"}, - {0x65, 0x00, SC_ALL_DEVS, "Voltage fault"}, - {0x66, 0x00, S, "Automatic document feeder cover up"}, - {0x66, 0x01, S, "Automatic document feeder lift up"}, - {0x66, 0x02, S, "Document jam in automatic document feeder"}, - {0x66, 0x03, S, "Document miss feed automatic in document feeder"}, - {0x67, 0x00, A, "Configuration failure"}, - {0x67, 0x01, A, "Configuration of incapable logical units failed"}, - {0x67, 0x02, A, "Add logical unit failed"}, - {0x67, 0x03, A, "Modification of logical unit failed"}, - {0x67, 0x04, A, "Exchange of logical unit failed"}, - {0x67, 0x05, A, "Remove of logical unit failed"}, - {0x67, 0x06, A, "Attachment of logical unit failed"}, - {0x67, 0x07, A, "Creation of logical unit failed"}, - {0x67, 0x08, A, "Assign failure occurred"}, - {0x67, 0x09, A, "Multiply assigned logical unit"}, - {0x67, 0x0A, SC_ALL_DEVS, "Set target port groups command failed"}, - {0x68, 0x00, A, SC_LOGICAL_UNIT "not configured"}, - {0x69, 0x00, A, "Data loss on logical unit"}, - {0x69, 0x01, A, "Multiple logical unit failures"}, - {0x69, 0x02, A, "Parity/data mismatch"}, - {0x6A, 0x00, A, "Informational,refer to log"}, - {0x6B, 0x00, A, "State change has occurred"}, - {0x6B, 0x01, A, "Redundancy level got better"}, - {0x6B, 0x02, A, "Redundancy level got worse"}, - {0x6C, 0x00, A, "Rebuild failure occurred"}, - {0x6D, 0x00, A, "Recalculate failure occurred"}, - {0x6E, 0x00, A, "Command to logical unit failed"}, - {0x6F, 0x00, R, - "Copy protection key exchange failure - authentication failure"}, - {0x6F, 0x01, R, - "Copy protection key exchange failure - key not present"}, - {0x6F, 0x02, R, - "Copy protection key exchange failure - key not established"}, - {0x6F, 0x03, R, "Read of scrambled sector without authentication"}, - {0x6F, 0x04, R, - "Media region code is mismatched to logical unit region"}, - {0x6F, 0x05, R, - "Drive region must be permanent/region reset count error"}, - /* - * FIXME(eric) - need a way to represent wildcards here. - */ - {0x70, 0x00, T, "Decompression exception short algorithm id of nn"}, - {0x71, 0x00, T, "Decompression exception long algorithm id"}, - {0x72, 0x00, R, "Session fixation error"}, - {0x72, 0x01, R, "Session fixation error writing lead-in"}, - {0x72, 0x02, R, "Session fixation error writing lead-out"}, - {0x72, 0x03, R, "Session fixation error - incomplete track in session"}, - {0x72, 0x04, R, "Empty or partially written reserved track"}, - {0x72, 0x05, R, "No more track reservations allowed"}, - {0x73, 0x00, R, "Cd control error"}, - {0x73, 0x01, R, "Power calibration area almost full"}, - {0x73, 0x02, R, "Power calibration area is full"}, - {0x73, 0x03, R, "Power calibration area error"}, - {0x73, 0x04, R, "Program memory area update failure"}, - {0x73, 0x05, R, "Program memory area is full"}, - {0x73, 0x06, R, "RMA/PMA is full"}, - {0, 0, 0, NULL} -}; - -static const char *sc_oft_used[0x1f] = { - "umulig", /* index 0x0 should be impossible */ - "Audio play operation ", - "Logical unit ", - "not ready, ", - " operation", - " in progress ", - "Hardware impending failure ", - "Controller impending failure ", - "Data channel impending failure ", /* index 0x8 */ - "Servo impending failure ", - "Spindle impending failure ", - "Firmware impending failure ", - "Recovered data ", - " error rate too high", - " times too high", -}; - -static const char *snstext[] = { - "No Sense", /* There is no sense information */ - "Recovered Error", /* The last command completed successfully - but used error correction */ - "Not Ready", /* The addressed target is not ready */ - "Medium Error", /* Data error detected on the medium */ - "Hardware Error", /* Controller or device failure */ - "Illegal Request", - "Unit Attention", /* Removable medium was changed, or - the target has been reset */ - "Data Protect", /* Access to the data is blocked */ - "Blank Check", /* Reached unexpected written or unwritten - region of the medium */ - "Key=9", /* Vendor specific */ - "Copy Aborted", /* COPY or COMPARE was aborted */ - "Aborted Command", /* The target aborted the command */ - "Equal", /* SEARCH DATA found data equal (obsolete) */ - "Volume Overflow", /* Medium full with still data to be written */ - "Miscompare", /* Source data and data on the medium - do not agree */ - "Key=15" /* Reserved */ -}; - -static -void sg_print_asc_ascq(unsigned char asc, unsigned char ascq) -{ - int k, j; - char obuff[256]; - const char *ccp; - const char *oup; - char c; - int found = 0; - - for (k = 0; additional[k].text; k++) { - if (additional[k].code1 == asc && additional[k].code2 == ascq) { - found = 1; - ccp = additional[k].text; - for (j = 0; *ccp && (j < sizeof(obuff)); ++ccp) { - c = *ccp; - if ((c < 0x20) && (c > 0)) { - oup = sc_oft_used[(int)c]; - if (oup) { - strcpy(obuff + j, oup); - j += strlen(oup); - } else { - strcpy(obuff + j, "???"); - j += 3; - } - } else - obuff[j++] = c; - } - if (j < sizeof(obuff)) - obuff[j] = '\0'; - else - obuff[sizeof(obuff) - 1] = '\0'; - fprintf(OUTP, "Additional sense: %s\n", obuff); - } - } - if (found) - return; - - for (k = 0; additional2[k].text; k++) { - if ((additional2[k].code1 == asc) && - (ascq >= additional2[k].code2_min) && - (ascq <= additional2[k].code2_max)) { - found = 1; - fprintf(OUTP, "Additional sense: "); - fprintf(OUTP, additional2[k].text, ascq); - fprintf(OUTP, "\n"); - } - } - if (!found) - fprintf(OUTP, "ASC=%2x ASCQ=%2x\n", asc, ascq); -} - -/* Print sense information */ -void sg_print_sense(const char *leadin, const unsigned char *sense_buffer, - int sb_len) -{ - int k, s; - int sense_key, sense_class, valid, code; - int descriptor_format = 0; - const char *error = NULL; - - if (sb_len < 1) { - fprintf(OUTP, "sense buffer empty\n"); - return; - } - sense_class = (sense_buffer[0] >> 4) & 0x07; - code = sense_buffer[0] & 0xf; - valid = sense_buffer[0] & 0x80; - if (leadin) - fprintf(OUTP, "%s: ", leadin); - - if (sense_class == 7) { /* extended sense data */ - s = sense_buffer[7] + 8; - if (s > sb_len) { - fprintf(OUTP, - "Sense buffer too small (at %d bytes), %d bytes " - "truncated\n", sb_len, s - sb_len); - s = sb_len; - } - - switch (code) { - case 0x0: - error = "Current"; /* error concerns current command */ - break; - case 0x1: - error = "Deferred"; /* error concerns some earlier command */ - /* e.g., an earlier write to disk cache succeeded, but - now the disk discovers that it cannot write the data */ - break; - case 0x2: - descriptor_format = 1; - error = "Descriptor current"; - /* new descriptor sense format */ - break; - case 0x3: - descriptor_format = 1; - error = "Descriptor deferred"; - /* new descriptor sense format (deferred report) */ - break; - default: - error = "Invalid"; - } - sense_key = sense_buffer[descriptor_format ? 1 : 2] & 0xf; - fprintf(OUTP, "%s, Sense key: %s\n", error, snstext[sense_key]); - - if (descriptor_format) - sg_print_asc_ascq(sense_buffer[2], sense_buffer[3]); - else { - if (!valid) - fprintf(OUTP, "[valid=0] "); - fprintf(OUTP, "Info fld=0x%x, ", - (int)((sense_buffer[3] << 24) | - (sense_buffer[4] << 16) | (sense_buffer[5] - << 8) | - sense_buffer[6])); - - if (sense_buffer[2] & 0x80) - fprintf(OUTP, "FMK "); /* current command has read a filemark */ - if (sense_buffer[2] & 0x40) - fprintf(OUTP, "EOM "); /* end-of-medium condition exists */ - if (sense_buffer[2] & 0x20) - fprintf(OUTP, "ILI "); /* incorrect block length requested */ - - if (s > 13) { - if (sense_buffer[12] || sense_buffer[13]) - sg_print_asc_ascq(sense_buffer[12], - sense_buffer[13]); - } - if (sense_key == 5 && s >= 18 - && (sense_buffer[15] & 0x80)) { - fprintf(OUTP, - "Sense Key Specific: Error in %s byte %d", - (sense_buffer[15] & 0x40) ? "Command" : - "Data", - (sense_buffer[16] << 8) | - sense_buffer[17]); - if (sense_buffer[15] & 0x08) { - fprintf(OUTP, " bit %d\n", - sense_buffer[15] & 0x07); - } else { - fprintf(OUTP, "\n"); - } - } - } - - } else { /* non-extended sense data */ - - /* - * Standard says: - * sense_buffer[0] & 0200 : address valid - * sense_buffer[0] & 0177 : vendor-specific error code - * sense_buffer[1] & 0340 : vendor-specific - * sense_buffer[1..3] : 21-bit logical block address - */ - - if (sb_len < 4) { - fprintf(OUTP, - "sense buffer too short (4 byte minimum)\n"); - return; - } - if (leadin) - fprintf(OUTP, "%s: ", leadin); - if (sense_buffer[0] < 15) - fprintf(OUTP, - "old sense: key %s\n", - snstext[sense_buffer[0] & 0x0f]); - else - fprintf(OUTP, "sns = %2x %2x\n", sense_buffer[0], - sense_buffer[2]); - - fprintf(OUTP, "Non-extended sense class %d code 0x%0x ", - sense_class, code); - s = 4; - } - - fprintf(OUTP, "Raw sense data (in hex):\n "); - for (k = 0; k < s; ++k) { - if ((k > 0) && (0 == (k % 24))) - fprintf(OUTP, "\n "); - fprintf(OUTP, "%02x ", sense_buffer[k]); - } - fprintf(OUTP, "\n"); -} - -static const char *hostbyte_table[] = { - "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", - "DID_BAD_TARGET", - "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", - "DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL -}; - -void sg_print_host_status(int host_status) -{ - static int maxcode = 0; - int i; - - if (!maxcode) { - for (i = 0; hostbyte_table[i]; i++) ; - maxcode = i - 1; - } - fprintf(OUTP, "Host_status=0x%02x", host_status); - if (host_status > maxcode) { - fprintf(OUTP, "is invalid "); - return; - } - fprintf(OUTP, "(%s) ", hostbyte_table[host_status]); -} - -static const char *driverbyte_table[] = { - "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", - "DRIVER_ERROR", - "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", NULL -}; - -static const char *driversuggest_table[] = { "SUGGEST_OK", - "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", - unknown, unknown, unknown, "SUGGEST_SENSE", NULL -}; - -void sg_print_driver_status(int driver_status) -{ - static int driver_max = 0, suggest_max = 0; - int i; - int dr = driver_status & SG_ERR_DRIVER_MASK; - int su = (driver_status & SG_ERR_SUGGEST_MASK) >> 4; - - if (!driver_max) { - for (i = 0; driverbyte_table[i]; i++) ; - driver_max = i; - for (i = 0; driversuggest_table[i]; i++) ; - suggest_max = i; - } - fprintf(OUTP, "Driver_status=0x%02x", driver_status); - fprintf(OUTP, " (%s,%s) ", - dr < driver_max ? driverbyte_table[dr] : "invalid", - su < suggest_max ? driversuggest_table[su] : "invalid"); -} - -static int sg_sense_print(const char *leadin, int scsi_status, - int host_status, int driver_status, - const unsigned char *sense_buffer, int sb_len) -{ - int done_leadin = 0; - int done_sense = 0; - - scsi_status &= 0x7e; /*sanity */ - if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status)) - return 1; /* No problems */ - if (0 != scsi_status) { - if (leadin) - fprintf(OUTP, "%s: ", leadin); - done_leadin = 1; - fprintf(OUTP, "scsi status: "); - sg_print_scsi_status(scsi_status); - fprintf(OUTP, "\n"); - if (sense_buffer && ((scsi_status == SCSI_CHECK_CONDITION) || - (scsi_status == - SCSI_COMMAND_TERMINATED))) { - sg_print_sense(0, sense_buffer, sb_len); - done_sense = 1; - } - } - if (0 != host_status) { - if (leadin && (!done_leadin)) - fprintf(OUTP, "%s: ", leadin); - if (done_leadin) - fprintf(OUTP, "plus...: "); - else - done_leadin = 1; - sg_print_host_status(host_status); - fprintf(OUTP, "\n"); - } - if (0 != driver_status) { - if (leadin && (!done_leadin)) - fprintf(OUTP, "%s: ", leadin); - if (done_leadin) - fprintf(OUTP, "plus...: "); - else - done_leadin = 1; - sg_print_driver_status(driver_status); - fprintf(OUTP, "\n"); - if (sense_buffer && (!done_sense) && - (SG_ERR_DRIVER_SENSE == (0xf & driver_status))) - sg_print_sense(0, sense_buffer, sb_len); - } - return 0; -} - -#ifdef SG_IO -int sg_chk_n_print3(const char *leadin, struct sg_io_hdr *hp) -{ - return sg_sense_print(leadin, hp->status, hp->host_status, - hp->driver_status, hp->sbp, hp->sb_len_wr); -} -#endif - -int sg_chk_n_print(const char *leadin, int masked_status, - int host_status, int driver_status, - const unsigned char *sense_buffer, int sb_len) -{ - int scsi_status = (masked_status << 1) & 0x7e; - - return sg_sense_print(leadin, scsi_status, host_status, driver_status, - sense_buffer, sb_len); -} - -#ifdef SG_IO -int sg_err_category3(struct sg_io_hdr *hp) -{ - return sg_err_category_new(hp->status, hp->host_status, - hp->driver_status, hp->sbp, hp->sb_len_wr); -} -#endif - -int sg_err_category(int masked_status, int host_status, - int driver_status, const unsigned char *sense_buffer, - int sb_len) -{ - int scsi_status = (masked_status << 1) & 0x7e; - - return sg_err_category_new(scsi_status, host_status, driver_status, - sense_buffer, sb_len); -} - -int sg_err_category_new(int scsi_status, int host_status, int driver_status, - const unsigned char *sense_buffer, int sb_len) -{ - scsi_status &= 0x7e; - if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status)) - return SG_ERR_CAT_CLEAN; - if ((SCSI_CHECK_CONDITION == scsi_status) || - (SCSI_COMMAND_TERMINATED == scsi_status) || - (SG_ERR_DRIVER_SENSE == (0xf & driver_status))) { - if (sense_buffer && (sb_len > 2)) { - int sense_key; - unsigned char asc; - - if (sense_buffer[0] & 0x2) { - sense_key = sense_buffer[1] & 0xf; - asc = sense_buffer[2]; - } else { - sense_key = sense_buffer[2] & 0xf; - asc = (sb_len > 12) ? sense_buffer[12] : 0; - } - - if (RECOVERED_ERROR == sense_key) - return SG_ERR_CAT_RECOVERED; - else if (UNIT_ATTENTION == sense_key) { - if (0x28 == asc) - return SG_ERR_CAT_MEDIA_CHANGED; - if (0x29 == asc) - return SG_ERR_CAT_RESET; - } - } - return SG_ERR_CAT_SENSE; - } - if (0 != host_status) { - if ((SG_ERR_DID_NO_CONNECT == host_status) || - (SG_ERR_DID_BUS_BUSY == host_status) || - (SG_ERR_DID_TIME_OUT == host_status)) - return SG_ERR_CAT_TIMEOUT; - } - if (0 != driver_status) { - if (SG_ERR_DRIVER_TIMEOUT == driver_status) - return SG_ERR_CAT_TIMEOUT; - } - return SG_ERR_CAT_OTHER; -} - -int sg_get_command_size(unsigned char opcode) -{ - return COMMAND_SIZE(opcode); -} - -void sg_get_command_name(unsigned char opcode, int buff_len, char *buff) -{ - const char **table = commands[group(opcode)]; - - if ((NULL == buff) || (buff_len < 1)) - return; - - switch ((unsigned long)table) { - case RESERVED_GROUP: - strncpy(buff, reserved, buff_len); - break; - case VENDOR_GROUP: - strncpy(buff, vendor, buff_len); - break; - default: - strncpy(buff, table[opcode & 0x1f], buff_len); - break; - } -} diff --git a/testcases/kernel/fs/scsi/ltpscsi/sg_err.h b/testcases/kernel/fs/scsi/ltpscsi/sg_err.h deleted file mode 100644 index 735f8a940..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/sg_err.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef SG_ERR_H -#define SG_ERR_H - -/* Feel free to copy and modify this GPL-ed code into your applications. */ - -/* Version 0.89 (20030313) -*/ - - -/* Some of the following error/status codes are exchanged between the - various layers of the SCSI sub-system in Linux and should never - reach the user. They are placed here for completeness. What appears - here is copied from drivers/scsi/scsi.h which is not visible in - the user space. */ - -#ifndef SCSI_CHECK_CONDITION -/* Following are the "true" SCSI status codes. Linux has traditionally - used a 1 bit right and masked version of these. So now CHECK_CONDITION - and friends (in <scsi/scsi.h>) are deprecated. */ -#define SCSI_CHECK_CONDITION 0x2 -#define SCSI_CONDITION_MET 0x4 -#define SCSI_BUSY 0x8 -#define SCSI_IMMEDIATE 0x10 -#define SCSI_IMMEDIATE_CONDITION_MET 0x14 -#define SCSI_RESERVATION_CONFLICT 0x18 -#define SCSI_COMMAND_TERMINATED 0x22 -#define SCSI_TASK_SET_FULL 0x28 -#define SCSI_ACA_ACTIVE 0x30 -#define SCSI_TASK_ABORTED 0x40 -#endif - -/* The following are 'host_status' codes */ -#ifndef DID_OK -#define DID_OK 0x00 -#endif -#ifndef DID_NO_CONNECT -#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ -#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ -#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ -#define DID_BAD_TARGET 0x04 /* Bad target (id?) */ -#define DID_ABORT 0x05 /* Told to abort for some other reason */ -#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */ -#define DID_ERROR 0x07 /* Internal error */ -#define DID_RESET 0x08 /* Reset by somebody */ -#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */ -#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */ -#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */ -#endif - -/* These defines are to isolate applictaions from kernel define changes */ -#define SG_ERR_DID_OK DID_OK -#define SG_ERR_DID_NO_CONNECT DID_NO_CONNECT -#define SG_ERR_DID_BUS_BUSY DID_BUS_BUSY -#define SG_ERR_DID_TIME_OUT DID_TIME_OUT -#define SG_ERR_DID_BAD_TARGET DID_BAD_TARGET -#define SG_ERR_DID_ABORT DID_ABORT -#define SG_ERR_DID_PARITY DID_PARITY -#define SG_ERR_DID_ERROR DID_ERROR -#define SG_ERR_DID_RESET DID_RESET -#define SG_ERR_DID_BAD_INTR DID_BAD_INTR -#define SG_ERR_DID_PASSTHROUGH DID_PASSTHROUGH -#define SG_ERR_DID_SOFT_ERROR DID_SOFT_ERROR - -/* The following are 'driver_status' codes */ -#ifndef DRIVER_OK -#define DRIVER_OK 0x00 -#endif -#ifndef DRIVER_BUSY -#define DRIVER_BUSY 0x01 -#define DRIVER_SOFT 0x02 -#define DRIVER_MEDIA 0x03 -#define DRIVER_ERROR 0x04 -#define DRIVER_INVALID 0x05 -#define DRIVER_TIMEOUT 0x06 -#define DRIVER_HARD 0x07 -#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ - -/* Following "suggests" are "or-ed" with one of previous 8 entries */ -#define SUGGEST_RETRY 0x10 -#define SUGGEST_ABORT 0x20 -#define SUGGEST_REMAP 0x30 -#define SUGGEST_DIE 0x40 -#define SUGGEST_SENSE 0x80 -#define SUGGEST_IS_OK 0xff -#endif -#ifndef DRIVER_MASK -#define DRIVER_MASK 0x0f -#endif -#ifndef SUGGEST_MASK -#define SUGGEST_MASK 0xf0 -#endif - -/* These defines are to isolate applictaions from kernel define changes */ -#define SG_ERR_DRIVER_OK DRIVER_OK -#define SG_ERR_DRIVER_BUSY DRIVER_BUSY -#define SG_ERR_DRIVER_SOFT DRIVER_SOFT -#define SG_ERR_DRIVER_MEDIA DRIVER_MEDIA -#define SG_ERR_DRIVER_ERROR DRIVER_ERROR -#define SG_ERR_DRIVER_INVALID DRIVER_INVALID -#define SG_ERR_DRIVER_TIMEOUT DRIVER_TIMEOUT -#define SG_ERR_DRIVER_HARD DRIVER_HARD -#define SG_ERR_DRIVER_SENSE DRIVER_SENSE -#define SG_ERR_SUGGEST_RETRY SUGGEST_RETRY -#define SG_ERR_SUGGEST_ABORT SUGGEST_ABORT -#define SG_ERR_SUGGEST_REMAP SUGGEST_REMAP -#define SG_ERR_SUGGEST_DIE SUGGEST_DIE -#define SG_ERR_SUGGEST_SENSE SUGGEST_SENSE -#define SG_ERR_SUGGEST_IS_OK SUGGEST_IS_OK -#define SG_ERR_DRIVER_MASK DRIVER_MASK -#define SG_ERR_SUGGEST_MASK SUGGEST_MASK - - - -/* The following "print" functions send ACSII to stdout */ -extern void sg_print_command(const unsigned char * command); -extern void sg_print_sense(const char * leadin, - const unsigned char * sense_buffer, int sb_len); -extern void sg_print_status(int masked_status); -extern void sg_print_scsi_status(int scsi_status); -extern void sg_print_host_status(int host_status); -extern void sg_print_driver_status(int driver_status); - -/* sg_chk_n_print() returns 1 quietly if there are no errors/warnings - else it prints to standard output and returns 0. */ -extern int sg_chk_n_print(const char * leadin, int masked_status, - int host_status, int driver_status, - const unsigned char * sense_buffer, int sb_len); - -/* The following function declaration is for the sg version 3 driver. - Only version 3 sg_err.c defines it. */ -struct sg_io_hdr; -extern int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp); - - -/* The following "category" function returns one of the following */ -#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ -#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ -#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ -#define SG_ERR_CAT_TIMEOUT 3 -#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ -#define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */ -#define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */ - -extern int sg_err_category(int masked_status, int host_status, - int driver_status, const unsigned char * sense_buffer, - int sb_len); - -extern int sg_err_category_new(int scsi_status, int host_status, - int driver_status, const unsigned char * sense_buffer, - int sb_len); - -/* The following function declaration is for the sg version 3 driver. - Only version 3 sg_err.c defines it. */ -extern int sg_err_category3(struct sg_io_hdr * hp); - -/* Returns length of SCSI command given the opcode (first byte) */ -extern int sg_get_command_size(unsigned char opcode); - -extern void sg_get_command_name(unsigned char opcode, int buff_len, - char * buff); - -#endif diff --git a/testcases/kernel/fs/scsi/ltpscsi/sg_include.h b/testcases/kernel/fs/scsi/ltpscsi/sg_include.h deleted file mode 100644 index 5baca3cc8..000000000 --- a/testcases/kernel/fs/scsi/ltpscsi/sg_include.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifdef SG_KERNEL_INCLUDES - #include "/usr/src/linux/include/scsi/sg.h" - #include "/usr/src/linux/include/scsi/scsi.h" -#else - #ifdef SG_TRICK_GNU_INCLUDES - #include <linux/../scsi/sg.h> - #include <linux/../scsi/scsi.h> - #else - #include <scsi/sg.h> - #include <scsi/scsi.h> - #endif -#endif - -/* - Getting the correct include files for the sg interface can be an ordeal. - In a perfect world, one would just write: - #include <scsi/sg.h> - #include <scsi/scsi.h> - This would include the files found in the /usr/include/scsi directory. - Those files are maintained with the GNU library which may or may not - agree with the kernel and version of sg driver that is running. Any - many cases this will not matter. However in some it might, for example - glibc 2.1's include files match the sg driver found in the lk 2.2 - series. Hence if glibc 2.1 is used with lk 2.4 then the additional - sg v3 interface will not be visible. - If this is a problem then defining SG_KERNEL_INCLUDES will access the - kernel supplied header files (assuming they are in the normal place). - The GNU library maintainers and various kernel people don't like - this approach (but it does work). - The technique selected by defining SG_TRICK_GNU_INCLUDES worked (and - was used) prior to glibc 2.2 . Prior to that version /usr/include/linux - was a symbolic link to /usr/src/linux/include/linux . - - There are other approaches if this include "mixup" causes pain. These - would involve include files being copied or symbolic links being - introduced. - - Sorry about the inconvenience. Typically neither SG_KERNEL_INCLUDES - nor SG_TRICK_GNU_INCLUDES is defined. - - dpg 20010415 -*/ diff --git a/testcases/kernel/input/input_helper.c b/testcases/kernel/input/input_helper.c index 09530fb4d..c929de6ba 100644 --- a/testcases/kernel/input/input_helper.c +++ b/testcases/kernel/input/input_helper.c @@ -25,6 +25,7 @@ #include "test.h" #include "safe_macros.h" #include "input_helper.h" +#include "lapi/uinput.h" #define VIRTUAL_DEVICE "virtual-device-ltp" @@ -185,6 +186,29 @@ void send_rel_move(int fd, int x, int y) send_event(fd, EV_SYN, 0, 0); } +static void check_ui_get_sysname_ioctl(int fd) +{ + char sys_name[256]; + char dev_name[256]; + char *path; + + SAFE_IOCTL(NULL, fd, UI_GET_SYSNAME(sizeof(sys_name)), sys_name, NULL); + SAFE_ASPRINTF(NULL, &path, "/sys/devices/virtual/input/%s/name", sys_name); + + if (FILE_SCANF(path, "%s", dev_name)) { + tst_resm(TFAIL|TERRNO, "Failed to read '%s'", path); + free(path); + return; + } + + if (!strcmp(VIRTUAL_DEVICE, dev_name)) + tst_resm(TPASS, "ioctl UI_GET_SYSNAME returned correct name"); + else + tst_resm(TFAIL, "ioctl UI_GET_SYSNAME returned wrong name"); + + free(path); +} + void create_device(int fd) { int nb; @@ -202,8 +226,10 @@ void create_device(int fd) SAFE_IOCTL(NULL, fd, UI_DEV_CREATE, NULL); for (nb = 100; nb > 0; nb--) { - if (check_device()) + if (check_device()) { + check_ui_get_sysname_ioctl(fd); return; + } usleep(10000); } diff --git a/testcases/kernel/io/direct_io/diotest4.c b/testcases/kernel/io/direct_io/diotest4.c index 45c677b5b..ad00fa3e0 100644 --- a/testcases/kernel/io/direct_io/diotest4.c +++ b/testcases/kernel/io/direct_io/diotest4.c @@ -270,6 +270,7 @@ int main(int argc, char *argv[]) case TST_NFS_MAGIC: case TST_BTRFS_MAGIC: case TST_FUSE_MAGIC: + case TST_TMPFS_MAGIC: tst_resm(TCONF, "%s supports odd count IO", tst_fs_type_name(fs_type)); break; @@ -443,6 +444,7 @@ int main(int argc, char *argv[]) case TST_NFS_MAGIC: case TST_BTRFS_MAGIC: case TST_FUSE_MAGIC: + case TST_TMPFS_MAGIC: tst_resm(TCONF, "%s supports non-aligned buffer", tst_fs_type_name(fs_type)); break; diff --git a/testcases/kernel/irq/irqbalance01.c b/testcases/kernel/irq/irqbalance01.c index a3d29aec2..96bbec6a8 100644 --- a/testcases/kernel/irq/irqbalance01.c +++ b/testcases/kernel/irq/irqbalance01.c @@ -93,7 +93,7 @@ static void collect_irq_info(void) char path[PATH_MAX]; size_t row, col, len; long acc; - unsigned int cpu_total, bit; + unsigned int cpu_total, bit, row_parsed; nr_cpus = 0; nr_irqs = 0; @@ -136,7 +136,7 @@ static void collect_irq_info(void) c = first_row; acc = -1; - row = col = 0; + row = col = row_parsed = 0; /* Parse columns containing IRQ counts and IRQ IDs into acc. Ignore * everything else. */ @@ -154,7 +154,9 @@ static void collect_irq_info(void) if (acc != -1) tst_brk(TBROK, "Unexpected EOL"); col = 0; - row++; + if (row_parsed) + row++; + row_parsed = 0; break; case '0' ... '9': if (acc == -1) @@ -168,6 +170,7 @@ static void collect_irq_info(void) tst_brk(TBROK, "Unexpected ':'"); irq_ids[row] = acc; acc = -1; + row_parsed = 1; break; default: acc = -1; diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore index 7258489ed..c96fe8bfc 100644 --- a/testcases/kernel/mem/.gitignore +++ b/testcases/kernel/mem/.gitignore @@ -53,6 +53,7 @@ /ksm/ksm04 /ksm/ksm05 /ksm/ksm06 +/ksm/ksm07 /mem/mem02 /mmapstress/mmap-corruption01 /mmapstress/mmapstress01 diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c index 79bea8e8b..5032e05ec 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c @@ -1,24 +1,28 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015-2017 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2018-2023 * - * DESCRIPTION + * Authors: + * Herton R. Krzesinski <herton@redhat.com> + * Li Wang <liwang@redhat.com> + */ + +/*\ + * [Description] * - * There is a race condition if we map a same file on different processes. - * Region tracking is protected by mmap_sem and hugetlb_instantiation_mutex. - * When we do mmap, we don't grab a hugetlb_instantiation_mutex, but only - * mmap_sem (exclusively). This doesn't prevent other tasks from modifying - * the region structure, so it can be modified by two processes concurrently. + * There is a race condition if we map a same file on different processes. + * Region tracking is protected by mmap_sem and hugetlb_instantiation_mutex. + * When we do mmap, we don't grab a hugetlb_instantiation_mutex, but only + * mmap_sem (exclusively). This doesn't prevent other tasks from modifying + * the region structure, so it can be modified by two processes concurrently. * - * This bug was fixed on stable kernel by commits: - * f522c3ac00a4(mm, hugetlb: change variable name reservations to resv) - * 9119a41e9091(mm, hugetlb: unify region structure handling) - * 7b24d8616be3(mm, hugetlb: fix race in region tracking) - * 1406ec9ba6c6(mm, hugetlb: improve, cleanup resv_map parameters) + * This bug was fixed on stable kernel by commits: * - * AUTHOR: - * Herton R. Krzesinski <herton@redhat.com> - * Li Wang <liwang@redhat.com> + * f522c3ac00a4 (mm, hugetlb: change variable name reservations to resv) + * 9119a41e9091 (mm, hugetlb: unify region structure handling) + * 7b24d8616be3 (mm, hugetlb: fix race in region tracking) + * 1406ec9ba6c6 (mm, hugetlb: improve, cleanup resv_map parameters) */ #define _GNU_SOURCE @@ -73,8 +77,7 @@ static void do_mmap(unsigned int j LTP_ATTRIBUTE_UNUSED) if (addr == MAP_FAILED) { if (errno == ENOMEM) { - tst_brk(TCONF, - "Cannot allocate hugepage, memory too fragmented?"); + tst_brk(TCONF, "Cannot allocate hugepage, memory too fragmented?"); } tst_brk(TBROK | TERRNO, "Cannot allocate hugepage"); @@ -86,8 +89,7 @@ static void do_mmap(unsigned int j LTP_ATTRIBUTE_UNUSED) TEST(pthread_create(&tid[i], NULL, thr, &mmap_sz[i])); if (TST_RET) - tst_brk(TBROK | TRERRNO, - "pthread_create failed"); + tst_brk(TBROK | TRERRNO, "pthread_create failed"); new_addr = mmap(addr, (sz - 1) * hpage_size, PROT_READ | PROT_WRITE, @@ -103,14 +105,13 @@ static void do_mmap(unsigned int j LTP_ATTRIBUTE_UNUSED) for (i = 0; i < ARSZ; ++i) { TEST(pthread_join(tid[i], NULL)); if (TST_RET) - tst_brk(TBROK | TRERRNO, - "pthread_join failed"); + tst_brk(TBROK | TRERRNO, "pthread_join failed"); } if (munmap(addr, sz * hpage_size) == -1) tst_brk(TFAIL | TERRNO, "huge munmap failed"); - tst_res(TPASS, "No regression found."); + tst_res(TPASS, "No regression found"); } static struct tst_test test = { diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c index f8c36640d..42b80064e 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c @@ -21,6 +21,7 @@ #include <limits.h> #include <sys/param.h> #include <sys/types.h> +#include <lapi/mmap.h> #include "hugetlb.h" @@ -62,15 +63,15 @@ static void run_test(void) memset(p, 0, hpage_size); /* Test just below 4GB to check for off-by-one errors */ - lowaddr = FOURGB - page_size; - q = mmap((void *)lowaddr, page_size, PROT_READ|PROT_WRITE, + lowaddr = FOURGB - MMAP_GRANULARITY; + q = mmap((void *)lowaddr, MMAP_GRANULARITY, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); if (q == MAP_FAILED) { - below_start = FOURGB - page_size; + below_start = FOURGB - MMAP_GRANULARITY; above_end = FOURGB; if (range_is_mapped(below_start, above_end) == 1) { - tst_res(TINFO|TERRNO, "region (4G-page)-4G is not free & " + tst_res(TINFO|TERRNO, "region (4G-MMAP_GRANULARITY)-4G is not free & " "mmap() failed expected"); tst_res(TPASS, "Successful but inconclusive"); } else diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c index 6bc367f96..e6b6bda76 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c @@ -14,6 +14,7 @@ #include "hugetlb.h" #define MNTPOINT "hugetlbfs/" +#define FLAGS_DESC(x) .flags = x, .flags_str = #x static int fd = -1; static unsigned long hpage_size; @@ -22,10 +23,10 @@ static struct tcase { int flags; char *flags_str; } tcases[] = { - {MAP_PRIVATE, "MAP_PRIVATE"}, - {MAP_SHARED, "MAP_SHARED"}, - {MAP_PRIVATE | MAP_LOCKED, "MAP_PRIVATE | MAP_LOCKED"}, - {MAP_SHARED | MAP_LOCKED, "MAP_SHARED | MAP_LOCKED"}, + { FLAGS_DESC(MAP_PRIVATE) }, + { FLAGS_DESC(MAP_SHARED) }, + { FLAGS_DESC(MAP_PRIVATE | MAP_LOCKED) }, + { FLAGS_DESC(MAP_SHARED | MAP_LOCKED) }, }; static void run_test(unsigned int i) diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c index a8e332ebd..7abfda92d 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c @@ -36,9 +36,7 @@ static void do_work(int thread, size_t size, int fd) for (i = 0; i < size; i++) memcpy((char *)addr+i, &pattern, 1); - if (msync(addr, size, MS_SYNC)) - tst_brk(TBROK | TERRNO, "Thread %d (pid %d): msync() failed", - thread, getpid()); + SAFE_MSYNC(addr, size, MS_SYNC); for (i = 0; i < size; i++) { if (addr[i] != pattern) { diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c index 4c1cff325..d755161c9 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: LGPL-2.1-or-later /* * Copyright (C) 2005-2006 IBM Corporation. + * Copyright (c) Linux Test Project, 2023 * Author: David Gibson & Adam Litke */ @@ -11,11 +12,13 @@ * perform read/write operation. It checks if the operation results in * expected behaviour as per the protection. */ + #include <setjmp.h> #include "hugetlb.h" #define MNTPOINT "hugetlbfs/" #define RANDOM_CONSTANT 0x1234ABCD +#define FLAGS_DESC(x) x, #x static int fd = -1; static sigjmp_buf sig_escape; @@ -32,23 +35,12 @@ static struct tcase { int prot2; char *prot2_str; } tcases[] = { - {"R->RW", 1, PROT_READ, "PROT_READ", - 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, - - {"RW->R", 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE", - 1, PROT_READ, "PROT_READ"}, - - {"R->RW 1/2", 2, PROT_READ, "PROT_READ", - 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, - - {"RW->R 1/2", 2, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE", - 1, PROT_READ, "PROT_READ"}, - - {"NONE->R", 1, PROT_NONE, "PROT_NONE", - 1, PROT_READ, "PROT_READ"}, - - {"NONE->RW", 1, PROT_NONE, "PROT_NONE", - 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, + {"R->RW", 1, FLAGS_DESC(PROT_READ), 1, FLAGS_DESC(PROT_READ|PROT_WRITE)}, + {"RW->R", 1, FLAGS_DESC(PROT_READ | PROT_WRITE), 1, FLAGS_DESC(PROT_READ)}, + {"R->RW 1/2", 2, FLAGS_DESC(PROT_READ), 1, FLAGS_DESC(PROT_READ | PROT_WRITE)}, + {"RW->R 1/2", 2, FLAGS_DESC(PROT_READ | PROT_WRITE), 1, FLAGS_DESC(PROT_READ)}, + {"NONE->R", 1, FLAGS_DESC(PROT_NONE), 1, FLAGS_DESC(PROT_READ)}, + {"NONE->RW", 1, FLAGS_DESC(PROT_NONE), 1, FLAGS_DESC(PROT_READ | PROT_WRITE)}, }; static void sig_handler(int signum, siginfo_t *si, void *uc) diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c index 158a03010..431dc1bbf 100644 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c @@ -30,7 +30,7 @@ static int init_slice_boundary(int fd) unsigned long slice_size; void *p, *heap; int i; -#if defined(__LP64__) && !defined(__aarch64__) +#if defined(__LP64__) && !defined(__aarch64__) && !defined(__loongarch__) /* powerpc: 1TB slices starting at 1 TB */ slice_boundary = 0x10000000000; slice_size = 0x10000000000; diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c index a68b0da75..04325ce10 100644 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c @@ -1,35 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2004 - * Copyright (c) Linux Test Project, 2004-2020 + * Copyright (c) Linux Test Project, 2004-2023 + * Original author: Wayne Boyer, modified by Robbie Williamson */ -/* - * DESCRIPTION - * hugeshmctl01 - test the IPC_STAT, IPC_SET and IPC_RMID commands as - * they are used with shmctl() - * - * ALGORITHM - * loop if that option was specified - * create a large shared memory segment with read and write permission - * set up any test case specific conditions - * call shmctl() using the TEST macro - * check the return code - * if failure, issue a FAIL message. - * otherwise, - * if doing functionality testing - * call the correct test function - * if the conditions are correct, - * issue a PASS message - * otherwise - * issue a FAIL message - * otherwise - * issue a PASS message - * call cleanup +/*\ + * [Description] * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * 04/2004 - Updated by Robbie Williamson + * Test the IPC_STAT, IPC_SET and IPC_RMID commands used by shmctl(). */ #include <limits.h> @@ -71,9 +50,11 @@ static void test_hugeshmctl(unsigned int i) * permissions. Do this here instead of in setup() * so that looping (-i) will work correctly. */ - if (i == 0) + if (i == 0) { shm_id_1 = shmget(shmkey, shm_size, SHM_HUGETLB | IPC_CREAT | IPC_EXCL | SHM_RW); + } + if (shm_id_1 == -1) tst_brk(TBROK | TERRNO, "shmget #main"); diff --git a/testcases/kernel/mem/ksm/ksm01.c b/testcases/kernel/mem/ksm/ksm01.c index bcd095865..e2d3d9e00 100644 --- a/testcases/kernel/mem/ksm/ksm01.c +++ b/testcases/kernel/mem/ksm/ksm01.c @@ -86,6 +86,8 @@ static struct tst_test test = { TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, {"/sys/kernel/mm/ksm/merge_across_nodes", "1", TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/smart_scan", "0", + TST_SR_SKIP_MISSING | TST_SR_TBROK_RO}, {} }, .needs_kconfigs = (const char *const[]){ diff --git a/testcases/kernel/mem/ksm/ksm02.c b/testcases/kernel/mem/ksm/ksm02.c index bce639dce..3707de95d 100644 --- a/testcases/kernel/mem/ksm/ksm02.c +++ b/testcases/kernel/mem/ksm/ksm02.c @@ -107,6 +107,8 @@ static struct tst_test test = { TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, {"/sys/kernel/mm/ksm/merge_across_nodes", "1", TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/smart_scan", "0", + TST_SR_SKIP_MISSING | TST_SR_TBROK_RO}, {} }, .needs_kconfigs = (const char *const[]){ diff --git a/testcases/kernel/mem/ksm/ksm03.c b/testcases/kernel/mem/ksm/ksm03.c index 4a733269f..cff74700d 100644 --- a/testcases/kernel/mem/ksm/ksm03.c +++ b/testcases/kernel/mem/ksm/ksm03.c @@ -89,6 +89,8 @@ static struct tst_test test = { TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, {"/sys/kernel/mm/ksm/merge_across_nodes", "1", TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/smart_scan", "0", + TST_SR_SKIP_MISSING | TST_SR_TBROK_RO}, {} }, .needs_kconfigs = (const char *const[]){ diff --git a/testcases/kernel/mem/ksm/ksm04.c b/testcases/kernel/mem/ksm/ksm04.c index 4f1f2f721..f558b23be 100644 --- a/testcases/kernel/mem/ksm/ksm04.c +++ b/testcases/kernel/mem/ksm/ksm04.c @@ -1,34 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2010-2017 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * Kernel Samepage Merging (KSM) for Memory Resource Controller and NUMA - * - * Basic tests were to start several programs with same and different - * memory contents and ensure only to merge the ones with the same - * contents. When changed the content of one of merged pages in a - * process and to the mode "unmerging", it should discard all merged - * pages there. Also tested it is possible to disable KSM. There are - * also command-line options to specify the memory allocation size, and - * number of processes have same memory contents so it is possible to - * test more advanced things like KSM + OOM etc. + */ + +/*\ + * [Description] * * Prerequisites: * - * 1) ksm and ksmtuned daemons need to be disabled. Otherwise, it could - * distrub the testing as they also change some ksm tunables depends - * on current workloads. + * ksm and ksmtuned daemons need to be disabled. Otherwise, it could + * distrub the testing as they also change some ksm tunables depends + * on current workloads. + * + * [Algorithm] * - * The test steps are: * - Check ksm feature and backup current run setting. * - Change run setting to 1 - merging. * - 3 memory allocation programs have the memory contents that 2 of @@ -109,6 +94,8 @@ static struct tst_test test = { TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, {"/sys/kernel/mm/ksm/merge_across_nodes", "1", TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/smart_scan", "0", + TST_SR_SKIP_MISSING | TST_SR_TBROK_RO}, {} }, .needs_kconfigs = (const char *const[]){ diff --git a/testcases/kernel/mem/ksm/ksm05.c b/testcases/kernel/mem/ksm/ksm05.c index 1f58c8325..1d9d9699a 100644 --- a/testcases/kernel/mem/ksm/ksm05.c +++ b/testcases/kernel/mem/ksm/ksm05.c @@ -43,7 +43,6 @@ #ifdef HAVE_DECL_MADV_MERGEABLE -static int ksm_run_orig = -1; static void sighandler(int sig); static void test_ksm(void) @@ -89,6 +88,8 @@ static struct tst_test test = { .test_all = test_ksm, .save_restore = (const struct tst_path_val[]) { {"/sys/kernel/mm/ksm/run", "1", TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/smart_scan", "0", + TST_SR_SKIP_MISSING | TST_SR_TBROK_RO}, {} }, .needs_kconfigs = (const char *const[]){ diff --git a/testcases/kernel/mem/ksm/ksm06.c b/testcases/kernel/mem/ksm/ksm06.c index 0b159e5c7..80fdf1e47 100644 --- a/testcases/kernel/mem/ksm/ksm06.c +++ b/testcases/kernel/mem/ksm/ksm06.c @@ -142,6 +142,8 @@ static struct tst_test test = { {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, {"/sys/kernel/mm/ksm/merge_across_nodes", NULL, TST_SR_TCONF}, + {"/sys/kernel/mm/ksm/smart_scan", "0", + TST_SR_SKIP_MISSING | TST_SR_TBROK_RO}, {} }, .needs_kconfigs = (const char *const[]){ diff --git a/testcases/kernel/mem/ksm/ksm07.c b/testcases/kernel/mem/ksm/ksm07.c new file mode 100644 index 000000000..619bd7b55 --- /dev/null +++ b/testcases/kernel/mem/ksm/ksm07.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Red Hat, Inc. + */ +/*\ + * [Description] + * + * Kernel Samepage Merging (KSM) for smart scan feature + * + * Test allocates a page and fills it with 'a' characters. It captures the + * pages_skipped counter, waits for a few iterations and captures the + * pages_skipped counter again. The expectation is that over 50% of the page + * scans are skipped. (There is only one page that has KSM enabled and it gets + * scanned during each iteration and it cannot be de-duplicated.) + * + * Smart scan feature was added in kernel v6.7. + * + * [Prerequisites] + * + * ksm and ksmtuned daemons need to be disabled. Otherwise, it could + * distrub the testing as they also change some ksm tunables depends + * on current workloads. + */ + +#include <sys/wait.h> +#include "mem.h" + +/* This test allocates one page, fills the page with a's, captures the + * full_scan and pages_skipped counters. Then it makes sure at least 3 + * full scans have been performed and measures the above counters again. + * The expectation is that at least 50% of the pages are skipped. + * + * To wait for at least 3 scans it uses the wait_ksmd_full_scan() function. In + * reality, it will be a lot more scans as the wait_ksmd_full_scan() function + * sleeps for one second. + */ +static void verify_ksm(void) +{ + int full_scans_begin; + int full_scans_end; + int pages_skipped_begin; + int pages_skipped_end; + int diff_pages; + int diff_scans; + unsigned long page_size; + char *memory; + + /* Apply for the space for memory. */ + page_size = sysconf(_SC_PAGE_SIZE); + memory = SAFE_MALLOC(page_size); + memory = SAFE_MMAP(NULL, page_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +#ifdef HAVE_DECL_MADV_MERGEABLE + if (madvise(memory, page_size, MADV_MERGEABLE) == -1) + tst_brk(TBROK|TERRNO, "madvise"); +#endif + memset(memory, 'a', page_size); + + tst_res(TINFO, "KSM merging"); + + if (access(PATH_KSM "max_page_sharing", F_OK) == 0) + SAFE_FILE_PRINTF(PATH_KSM "run", "2"); + + /* Set defalut ksm scan values. */ + SAFE_FILE_PRINTF(PATH_KSM "run", "1"); + SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", 100l); + SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0"); + + /* Measure pages skipped aka "smart scan". */ + SAFE_FILE_SCANF(PATH_KSM "full_scans", "%d", &full_scans_begin); + SAFE_FILE_SCANF(PATH_KSM "pages_skipped", "%d", &pages_skipped_begin); + wait_ksmd_full_scan(); + + tst_res(TINFO, "stop KSM"); + SAFE_FILE_PRINTF(PATH_KSM "run", "0"); + + SAFE_FILE_SCANF(PATH_KSM "full_scans", "%d", &full_scans_end); + SAFE_FILE_SCANF(PATH_KSM "pages_skipped", "%d", &pages_skipped_end); + diff_pages = pages_skipped_end - pages_skipped_begin; + diff_scans = full_scans_end - full_scans_begin; + + if (diff_pages < diff_scans * 50 / 100) { + tst_res(TINFO, "number of pages %d", diff_pages); + tst_res(TINFO, "number of scans %d", diff_scans); + tst_res(TFAIL, "not enough pages have been skipped by smart_scan"); + } else { + tst_res(TPASS, "smart_scan skipped more than 50%% of the pages"); + } + +#ifdef HAVE_DECL_MADV_MERGEABLE + if (madvise(memory, page_size, MADV_UNMERGEABLE) == -1) + tst_brk(TBROK|TERRNO, "madvise"); +#endif +} + +static struct tst_test test = { + .needs_root = 1, + .options = (struct tst_option[]) { + {} + }, + .save_restore = (const struct tst_path_val[]) { + {PATH_KSM "pages_skipped", NULL, TST_SR_TCONF}, + {PATH_KSM "run", NULL, TST_SR_TCONF}, + {PATH_KSM "sleep_millisecs", NULL, TST_SR_TCONF}, + {PATH_KSM "smart_scan", "1", + TST_SR_SKIP_MISSING | TST_SR_TCONF}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + NULL + }, + .test_all = verify_ksm, +}; diff --git a/testcases/kernel/mem/ksm/ksm_common.h b/testcases/kernel/mem/ksm/ksm_common.h index a582891c6..489d34ae0 100644 --- a/testcases/kernel/mem/ksm/ksm_common.h +++ b/testcases/kernel/mem/ksm/ksm_common.h @@ -1,32 +1,36 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ - /* - * Parse the ksm0* test options in funcion parse_ksm_options(). - */ +/* + * Parse the ksm0* test options in funcion parse_ksm_options(). + */ + +#ifndef KSM_COMMON_H__ +#define KSM_COMMON_H__ #include "tst_test.h" #define DEFAULT_MEMSIZE 128 -int size = DEFAULT_MEMSIZE, num = 3, unit = 1; -char *opt_sizestr, *opt_numstr, *opt_unitstr; +static int size = DEFAULT_MEMSIZE, num = 3, unit = 1; +static char *opt_sizestr, *opt_numstr, *opt_unitstr; static inline void parse_ksm_options(char *str_size, int *size, char *str_num, int *num, char *str_unit, int *unit) { - if(tst_parse_int(str_size, size, 1, INT_MAX)) + if (tst_parse_int(str_size, size, 1, INT_MAX)) tst_brk(TBROK, "Invalid size '%s'", str_size); - if(tst_parse_int(str_num, num, 3, INT_MAX)) + if (tst_parse_int(str_num, num, 3, INT_MAX)) tst_brk(TBROK, "Invalid num '%s'", str_num); - if(tst_parse_int(str_unit, unit, 1, *size)) + if (tst_parse_int(str_unit, unit, 1, *size)) tst_brk(TBROK, "Invalid unit '%s'", str_unit); + if (*size % *unit != 0) - tst_brk(TBROK, - "the remainder of division of size by unit is " - "not zero."); + tst_brk(TBROK, "the remainder of division of size by unit is not zero."); } + +#endif /* KSM_COMMON_H__ */ diff --git a/testcases/kernel/mem/mmapstress/mmapstress01.c b/testcases/kernel/mem/mmapstress/mmapstress01.c index 6209c1bc3..9189f113e 100644 --- a/testcases/kernel/mem/mmapstress/mmapstress01.c +++ b/testcases/kernel/mem/mmapstress/mmapstress01.c @@ -187,13 +187,13 @@ static void child_mapper(char *file, unsigned int procno, unsigned int nprocs) *(paddr + i) = (procno + pattern) & 0xff; } } + if (do_sync) { randpage = lrand48() % mappages; paddr = maddr + (randpage * pagesize); /* page address */ - if (msync(paddr, (mappages - randpage) * pagesize, - MS_SYNC) == -1) - tst_brk(TBROK | TERRNO, "msync failed"); + SAFE_MSYNC(paddr, (mappages - randpage) * pagesize, MS_SYNC); } + SAFE_MUNMAP(maddr, mapsize); exit(0); } diff --git a/testcases/kernel/mem/oom/oom01.c b/testcases/kernel/mem/oom/oom01.c index b13699898..903785f93 100644 --- a/testcases/kernel/mem/oom/oom01.c +++ b/testcases/kernel/mem/oom/oom01.c @@ -1,23 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Out Of Memory (OOM) - * - * The program is designed to cope with unpredictable like amount and - * system physical memory, swap size and other VMM technology like KSM, - * memcg, memory hotplug and so on which may affect the OOM - * behaviours. It simply increase the memory consumption 3G each time - * until all the available memory is consumed and OOM is triggered. - * * Copyright (C) 2010-2017 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2011-2023 + */ +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * Out Of Memory (OOM) test */ #include <sys/types.h> @@ -27,15 +16,10 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include "lapi/abisize.h" #include "mem.h" static void verify_oom(void) { -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif - /* we expect mmap to fail before OOM is hit */ set_sys_tune("overcommit_memory", 2, 1); oom(NORMAL, 0, ENOMEM, 0); @@ -54,6 +38,7 @@ static struct tst_test test = { .forks_child = 1, .max_runtime = TST_UNLIMITED_RUNTIME, .test_all = verify_oom, + .skip_in_compat = 1, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, {} diff --git a/testcases/kernel/mem/oom/oom02.c b/testcases/kernel/mem/oom/oom02.c index 8d565d12a..087d61abe 100644 --- a/testcases/kernel/mem/oom/oom02.c +++ b/testcases/kernel/mem/oom/oom02.c @@ -1,23 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Out Of Memory (OOM) for mempolicy - need NUMA system support - * - * The program is designed to cope with unpredictable like amount and - * system physical memory, swap size and other VMM technology like KSM, - * memcg, memory hotplug and so on which may affect the OOM - * behaviours. It simply increase the memory consumption 3G each time - * until all the available memory is consumed and OOM is triggered. - * * Copyright (C) 2010-2017 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2011-2023 + */ +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * Out Of Memory (OOM) test for mempolicy - need NUMA system support */ #include "config.h" @@ -30,7 +19,6 @@ #include <numa.h> #endif -#include "lapi/abisize.h" #include "numa_helper.h" #include "mem.h" @@ -38,10 +26,6 @@ static void verify_oom(void) { -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif - tst_res(TINFO, "OOM on MPOL_BIND mempolicy..."); testoom(MPOL_BIND, 0, ENOMEM, 1); @@ -61,9 +45,10 @@ static void setup(void) static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .max_runtime = TST_UNLIMITED_RUNTIME, + .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, .test_all = verify_oom, + .skip_in_compat = 1, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, {} diff --git a/testcases/kernel/mem/oom/oom03.c b/testcases/kernel/mem/oom/oom03.c index 778055d03..1041a6a1d 100644 --- a/testcases/kernel/mem/oom/oom03.c +++ b/testcases/kernel/mem/oom/oom03.c @@ -1,23 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Out Of Memory (OOM) for Memory Resource Controller - * - * The program is designed to cope with unpredictable like amount and - * system physical memory, swap size and other VMM technology like KSM, - * memcg, memory hotplug and so on which may affect the OOM - * behaviours. It simply increase the memory consumption 3G each time - * until all the available memory is consumed and OOM is triggered. - * * Copyright (C) 2010-2017 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2011-2023 + */ +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * Out Of Memory (OOM) test for Memory Resource Controller */ #include "config.h" @@ -30,7 +19,6 @@ #include <numa.h> #endif -#include "lapi/abisize.h" #include "numa_helper.h" #include "mem.h" @@ -38,9 +26,6 @@ static void verify_oom(void) { -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif testoom(0, 0, ENOMEM, 1); if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) { @@ -90,6 +75,7 @@ static struct tst_test test = { .setup = setup, .test_all = verify_oom, .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, + .skip_in_compat = 1, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, {} diff --git a/testcases/kernel/mem/oom/oom04.c b/testcases/kernel/mem/oom/oom04.c index d27d9d9e7..3f0bcf7e2 100644 --- a/testcases/kernel/mem/oom/oom04.c +++ b/testcases/kernel/mem/oom/oom04.c @@ -1,23 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Out Of Memory (OOM) for CPUSET - * - * The program is designed to cope with unpredictable like amount and - * system physical memory, swap size and other VMM technology like KSM, - * memcg, memory hotplug and so on which may affect the OOM - * behaviours. It simply increase the memory consumption 3G each time - * until all the available memory is consumed and OOM is triggered. - * * Copyright (C) 2010-2017 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2011-2023 + */ +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * Out Of Memory (OOM) test for CPUSET */ #include "config.h" @@ -30,7 +19,6 @@ #include <numa.h> #endif -#include "lapi/abisize.h" #include "numa_helper.h" #include "mem.h" @@ -38,9 +26,6 @@ static void verify_oom(void) { -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif tst_res(TINFO, "OOM on CPUSET..."); testoom(0, 0, ENOMEM, 1); @@ -86,6 +71,7 @@ static struct tst_test test = { .setup = setup, .test_all = verify_oom, .needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL }, + .skip_in_compat = 1, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, {} diff --git a/testcases/kernel/mem/oom/oom05.c b/testcases/kernel/mem/oom/oom05.c index eb1a64267..74f0f78b3 100644 --- a/testcases/kernel/mem/oom/oom05.c +++ b/testcases/kernel/mem/oom/oom05.c @@ -1,23 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Out Of Memory (OOM) for MEMCG and CPUSET - * - * The program is designed to cope with unpredictable like amount and - * system physical memory, swap size and other VMM technology like KSM, - * memcg, memory hotplug and so on which may affect the OOM - * behaviours. It simply increase the memory consumption 3G each time - * until all the available memory is consumed and OOM is triggered. - * * Copyright (C) 2013-2017 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2014-2023 + */ +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. + * Out Of Memory (OOM) test for MEMCG and CPUSET */ #include "config.h" @@ -30,7 +19,6 @@ #include <numa.h> #endif -#include "lapi/abisize.h" #include "numa_helper.h" #include "mem.h" @@ -38,10 +26,6 @@ static void verify_oom(void) { -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif - tst_res(TINFO, "OOM on CPUSET & MEMCG..."); testoom(0, 0, ENOMEM, 1); @@ -110,6 +94,7 @@ static struct tst_test test = { .needs_cgroup_ctrls = (const char *const []){ "memory", "cpuset", NULL }, + .skip_in_compat = 1, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, {} diff --git a/testcases/kernel/mem/swapping/swapping01.c b/testcases/kernel/mem/swapping/swapping01.c index fc225e4a6..a0030a75f 100644 --- a/testcases/kernel/mem/swapping/swapping01.c +++ b/testcases/kernel/mem/swapping/swapping01.c @@ -41,7 +41,6 @@ #include <string.h> #include <unistd.h> #include "tst_safe_stdio.h" -#include "lapi/abisize.h" #include "mem.h" /* allow swapping 1 * phy_mem in maximum */ @@ -62,9 +61,6 @@ static unsigned int start_runtime; static void test_swapping(void) { -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif FILE *file; char line[PATH_MAX]; @@ -83,7 +79,9 @@ static void test_swapping(void) switch (pid = SAFE_FORK()) { case 0: + TST_PRINT_MEMINFO(); do_alloc(0); + TST_PRINT_MEMINFO(); do_alloc(1); exit(0); default: @@ -111,15 +109,19 @@ static void do_alloc(int allow_raise) if (allow_raise == 1) tst_res(TINFO, "available physical memory: %ld MB", mem_available_init / 1024); + mem_count = mem_available_init + mem_over; + if (allow_raise == 1) tst_res(TINFO, "try to allocate: %ld MB", mem_count / 1024); s = SAFE_MALLOC(mem_count * 1024); memset(s, 1, mem_count * 1024); + if ((allow_raise == 1) && (raise(SIGSTOP) == -1)) { tst_res(TINFO, "memory allocated: %ld MB", mem_count / 1024); tst_brk(TBROK | TERRNO, "kill"); } + free(s); } @@ -138,6 +140,7 @@ static void check_swapping(void) swap_free_now = SAFE_READ_MEMINFO("SwapFree:"); sleep(1); long diff = labs(swap_free_now - SAFE_READ_MEMINFO("SwapFree:")); + if (diff < 10) break; @@ -146,9 +149,10 @@ static void check_swapping(void) swapped = SAFE_READ_PROC_STATUS(pid, "VmSwap:"); if (swapped > mem_over_max) { + TST_PRINT_MEMINFO(); kill(pid, SIGCONT); - tst_brk(TFAIL, "heavy swapping detected: " - "%ld MB swapped.", swapped / 1024); + tst_brk(TFAIL, "heavy swapping detected: %ld MB swapped", + swapped / 1024); } tst_res(TPASS, "no heavy swapping detected, %ld MB swapped.", @@ -164,6 +168,7 @@ static struct tst_test test = { .min_mem_avail = 10, .max_runtime = 600, .test_all = test_swapping, + .skip_in_compat = 1, .needs_kconfigs = (const char *[]) { "CONFIG_SWAP=y", NULL diff --git a/testcases/kernel/mem/tunable/overcommit_memory.c b/testcases/kernel/mem/tunable/overcommit_memory.c index ffb7a6d9d..d055dd18f 100644 --- a/testcases/kernel/mem/tunable/overcommit_memory.c +++ b/testcases/kernel/mem/tunable/overcommit_memory.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2012-2020 Linux Test Project + * Copyright (c) 2012-2023 Linux Test Project * Copyright (c) 2012-2017 Red Hat, Inc. * * There are two tunables overcommit_memory and overcommit_ratio under @@ -62,7 +62,6 @@ #include <stdio.h> #include <stdlib.h> #include <limits.h> -#include "lapi/abisize.h" #include "mem.h" #define DEFAULT_OVER_RATIO 50L @@ -124,10 +123,6 @@ static void setup(void) static void overcommit_memory_test(void) { - -#ifdef TST_ABI32 - tst_brk(TCONF, "test is not designed for 32-bit system."); -#endif /* start to test overcommit_memory=2 */ set_sys_tune("overcommit_memory", 2, 1); @@ -256,6 +251,7 @@ static struct tst_test test = { }, .setup = setup, .test_all = overcommit_memory_test, + .skip_in_compat = 1, .save_restore = (const struct tst_path_val[]) { {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, {"/proc/sys/vm/overcommit_ratio", NULL, TST_SR_TBROK}, diff --git a/testcases/kernel/mem/vma/vma05.sh b/testcases/kernel/mem/vma/vma05.sh index c9e4becdb..e1ef1014e 100755 --- a/testcases/kernel/mem/vma/vma05.sh +++ b/testcases/kernel/mem/vma/vma05.sh @@ -25,11 +25,13 @@ TST_NEEDS_CMDS="gdb" CORE_LIMIT=$(ulimit -c) CORE_PATTERN=$(cat /proc/sys/kernel/core_pattern) +CORE_USES_PID=$(cat /proc/sys/kernel/core_uses_pid) setup() { ulimit -c unlimited echo "core" > /proc/sys/kernel/core_pattern + echo 0 > /proc/sys/kernel/core_uses_pid unset DEBUGINFOD_URLS } @@ -37,6 +39,7 @@ cleanup() { ulimit -c "$CORE_LIMIT" echo "$CORE_PATTERN" > /proc/sys/kernel/core_pattern + echo $CORE_USES_PID > /proc/sys/kernel/core_uses_pid } vma_report_check() @@ -54,6 +57,8 @@ vma_report_check() rm -rf core* { vma05_vdso; } > /dev/null 2>&1 + [ -f core ] || tst_brk TBROK "missing core file" + TRACE=$(gdb -silent -ex="thread apply all backtrace" -ex="quit"\ vma05_vdso ./core* 2> /dev/null) if echo "$TRACE" | grep -qF "??"; then diff --git a/testcases/kernel/pty/pty04.c b/testcases/kernel/pty/pty04.c index 8c7b1bf92..204703253 100644 --- a/testcases/kernel/pty/pty04.c +++ b/testcases/kernel/pty/pty04.c @@ -93,6 +93,19 @@ static struct ldisc_info ldiscs[] = { static int ptmx = -1, pts = -1, sk = -1, mtu, no_check; +static void setup(void) +{ + int fd = SAFE_OPEN("/dev/ptmx", O_RDWR); + + TEST(ioctl(fd, TIOCVHANGUP)); + SAFE_CLOSE(fd); + + if (TST_RET && TST_ERR == ENOTTY) + tst_brk(TCONF | TTERRNO, "ioctl(TIOCVHANGUP) not supported"); + else if (TST_RET) + tst_brk(TBROK | TTERRNO, "ioctl(TIOCVHANGUP) failed"); +} + static int set_ldisc(int tty, const struct ldisc_info *ldisc) { TEST(ioctl(tty, TIOCSETD, &ldisc->n)); @@ -467,6 +480,7 @@ static void cleanup(void) } static struct tst_test test = { + .setup = setup, .test = do_test, .cleanup = cleanup, .tcnt = 2, diff --git a/testcases/kernel/sched/sysctl/.gitignore b/testcases/kernel/sched/sysctl/.gitignore new file mode 100644 index 000000000..29b859b81 --- /dev/null +++ b/testcases/kernel/sched/sysctl/.gitignore @@ -0,0 +1 @@ +proc_sched_rt01 diff --git a/testcases/kernel/syscalls/getdtablesize/Makefile b/testcases/kernel/sched/sysctl/Makefile index 044619fb8..18896b6f2 100644 --- a/testcases/kernel/syscalls/getdtablesize/Makefile +++ b/testcases/kernel/sched/sysctl/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) International Business Machines Corp., 2001 top_srcdir ?= ../../../.. diff --git a/testcases/kernel/sched/sysctl/proc_sched_rt01.c b/testcases/kernel/sched/sysctl/proc_sched_rt01.c new file mode 100644 index 000000000..7c1aaccd9 --- /dev/null +++ b/testcases/kernel/sched/sysctl/proc_sched_rt01.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Cyril Hrubis <chrubis@suse.cz> + */ + +/*\ + * [Description] + * + * Sanity tests for the /proc/sys/kernel/sched_r* files. + * + * - The sched_rt_period_us range is 1 to INT_MAX + * try invalid values and check for EINVAL + * + * - The sched_rt_runtime_us range is -1 to INT_MAX + * try invalid values and check for EINVAL + * + * - The sched_rt_runtime_us must be less or equal to sched_rt_period_us + * + * - Reset sched_rr_timeslice_ms to default value by writing -1 and check that + * we get the default value on next read. + * + * This is a regression test for a commits: + * + * - c1fc6484e1fb ("sched/rt: sysctl_sched_rr_timeslice show default timeslice after reset") + * - 079be8fc6309 ("sched/rt: Disallow writing invalid values to sched_rt_period_us") + */ + +#include <stdio.h> +#include "tst_test.h" + +#define RT_PERIOD_US "/proc/sys/kernel/sched_rt_period_us" +#define RT_RUNTIME_US "/proc/sys/kernel/sched_rt_runtime_us" +#define RR_TIMESLICE_MS "/proc/sys/kernel/sched_rr_timeslice_ms" + +static int period_fd; +static int runtime_fd; + +static void rr_timeslice_ms_reset(void) +{ + long timeslice_ms; + + SAFE_FILE_PRINTF(RR_TIMESLICE_MS, "-1"); + SAFE_FILE_SCANF(RR_TIMESLICE_MS, "%li", ×lice_ms); + + TST_EXP_EXPR(timeslice_ms > 0, + "timeslice_ms > 0 after reset to default"); +} + +static void rt_period_us_einval(void) +{ + TST_EXP_FAIL(write(period_fd, "0", 2), EINVAL, + "echo 0 > "RT_PERIOD_US); + TST_EXP_FAIL(write(period_fd, "-1", 2), EINVAL, + "echo -1 > "RT_PERIOD_US); +} + +static void rt_runtime_us_einval(void) +{ + TST_EXP_FAIL(write(runtime_fd, "-2", 2), EINVAL, + "echo -2 > "RT_RUNTIME_US); +} + +static void rt_runtime_us_le_period_us(void) +{ + int period_us; + char buf[32]; + + SAFE_FILE_SCANF(RT_PERIOD_US, "%i", &period_us); + + sprintf(buf, "%i", period_us+1); + + TST_EXP_FAIL(write(runtime_fd, buf, strlen(buf)), EINVAL, + "echo rt_period_us+1 > "RT_RUNTIME_US); +} + +static void verify_sched_proc(void) +{ + rr_timeslice_ms_reset(); + rt_period_us_einval(); + rt_runtime_us_einval(); + rt_runtime_us_le_period_us(); +} + +static void setup(void) +{ + period_fd = open(RT_PERIOD_US, O_RDWR); + runtime_fd = open(RT_RUNTIME_US, O_RDWR); +} + +static void cleanup(void) +{ + if (period_fd > 0) + SAFE_CLOSE(period_fd); + + if (runtime_fd > 0) + SAFE_CLOSE(runtime_fd); +} + +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_sched_proc, + .tags = (struct tst_tag []) { + {"linux-git", "c1fc6484e1fb"}, + {"linux-git", "079be8fc6309"}, + {} + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_SYSCTL", + NULL + }, +}; diff --git a/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh b/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh index b675a20a1..2a28562e6 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh @@ -159,7 +159,8 @@ get_pcr10_aggregate() $cmd > hash.txt 2>&1 ret=$? elif [ $ret -ne 0 -a "$MISSING_EVMCTL" = 1 ]; then - tst_brk TFAIL "evmctl failed $msg" + tst_res TFAIL "evmctl failed $msg" + return fi [ $ret -ne 0 ] && tst_res TWARN "evmctl failed, trying to continue $msg" diff --git a/testcases/kernel/syscalls/accept/.gitignore b/testcases/kernel/syscalls/accept/.gitignore index 5b1462699..f81d4bec9 100644 --- a/testcases/kernel/syscalls/accept/.gitignore +++ b/testcases/kernel/syscalls/accept/.gitignore @@ -1,2 +1,3 @@ /accept01 /accept02 +/accept03 diff --git a/testcases/kernel/syscalls/accept/accept01.c b/testcases/kernel/syscalls/accept/accept01.c index 85af0f8af..e5db1dfec 100644 --- a/testcases/kernel/syscalls/accept/accept01.c +++ b/testcases/kernel/syscalls/accept/accept01.c @@ -26,7 +26,6 @@ struct sockaddr_in sin0, sin1, fsin1; int invalid_socketfd = 400; /* anything that is not an open file */ -int devnull_fd; int socket_fd; int udp_fd; @@ -46,10 +45,6 @@ static struct test_case { "bad file descriptor" }, { - PF_INET, SOCK_STREAM, 0, &devnull_fd, (struct sockaddr *)&fsin1, - sizeof(fsin1), ENOTSOCK, "fd is not socket" - }, - { PF_INET, SOCK_STREAM, 0, &socket_fd, (struct sockaddr *)3, sizeof(fsin1), EINVAL, "invalid socket buffer" }, @@ -73,8 +68,6 @@ static void test_setup(void) sin0.sin_port = 0; sin0.sin_addr.s_addr = INADDR_ANY; - devnull_fd = SAFE_OPEN("/dev/null", O_WRONLY); - socket_fd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); SAFE_BIND(socket_fd, (struct sockaddr *)&sin0, sizeof(sin0)); @@ -88,7 +81,6 @@ static void test_setup(void) static void test_cleanup(void) { - SAFE_CLOSE(devnull_fd); SAFE_CLOSE(socket_fd); SAFE_CLOSE(udp_fd); } diff --git a/testcases/kernel/syscalls/accept/accept03.c b/testcases/kernel/syscalls/accept/accept03.c new file mode 100644 index 000000000..b85ec0d9b --- /dev/null +++ b/testcases/kernel/syscalls/accept/accept03.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2023-2024 Cyril Hrubis <chrubis@suse.cz> + */ + +/*\ + * [Description] + * + * Verify that accept() returns ENOTSOCK or EBADF for non-socket file + * descriptors. The EBADF is returned in the case that the file descriptor has + * not a file associated with it, which is for example in the case of O_PATH + * opened file. + */ + +#include <sys/socket.h> +#include <netinet/in.h> + +#include "tst_test.h" + +void check_accept(struct tst_fd *fd) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = 0, + .sin_addr = {.s_addr = INADDR_ANY}, + }; + + socklen_t size = sizeof(addr); + + int exp_errno = ENOTSOCK; + + switch (fd->type) { + case TST_FD_UNIX_SOCK: + case TST_FD_INET_SOCK: + return; + /* + * With these two we fail even before we get to the do_accept() because + * the fd does not have a struct file associated. + */ + case TST_FD_OPEN_TREE: + case TST_FD_PATH: + exp_errno = EBADF; + default: + break; + } + + TST_EXP_FAIL2(accept(fd->fd, (void*)&addr, &size), + exp_errno, "accept() on %s", tst_fd_desc(fd)); +} + +static void verify_accept(void) +{ + TST_FD_FOREACH(fd) + check_accept(&fd); +} + +static struct tst_test test = { + .test_all = verify_accept, +}; diff --git a/testcases/kernel/syscalls/acct/acct01.c b/testcases/kernel/syscalls/acct/acct01.c index 52c4d41da..a05ed2ea9 100644 --- a/testcases/kernel/syscalls/acct/acct01.c +++ b/testcases/kernel/syscalls/acct/acct01.c @@ -1,14 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) Linux Test Project, 2003-2023 + * 12/03/2002 Port to LTP robbiew@us.ibm.com + * 06/30/2001 Port to Linux nsharoff@us.ibm.com */ -/* 12/03/2002 Port to LTP robbiew@us.ibm.com */ -/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ - /*\ - * [DOCUMENTATION] + * [Description] + * * Verify that acct() returns proper errno on failure. */ diff --git a/testcases/kernel/syscalls/acct/acct02.c b/testcases/kernel/syscalls/acct/acct02.c index b8eb1aad4..d3f3d9d04 100644 --- a/testcases/kernel/syscalls/acct/acct02.c +++ b/testcases/kernel/syscalls/acct/acct02.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) SUSE LLC, 2019 - * Author: Christian Amann <camann@suse.com> + * Copyright (c) SUSE LLC, 2019 + * Copyright (c) Linux Test Project, 2019-2023 + * Author: Christian Amann <camann@suse.com> */ /*\ - * [DOCUMENTATION] + * [Description] * * This tests if the kernel writes correct data to the * process accounting file. @@ -19,8 +20,8 @@ * file, the contents get parsed until the correct entry is found, or EOF * is reached. * - * This is also accidental regression test for: - * 4d9570158b626 kernel/acct.c: fix the acct->needcheck check in check_free_space() + * This is also regression test for commit: + * 4d9570158b62 ("kernel/acct.c: fix the acct->needcheck check in check_free_space()") */ #include <sys/stat.h> @@ -55,10 +56,7 @@ static union acct_union { static int acct_version_is_3(void) { - struct tst_kconfig_var kconfig = { - .id = ACCT_V3, - .id_len = sizeof(ACCT_V3)-1, - }; + struct tst_kconfig_var kconfig = TST_KCONFIG_INIT(ACCT_V3); tst_kconfig_read(&kconfig, 1); diff --git a/testcases/kernel/syscalls/acct/acct02_helper.c b/testcases/kernel/syscalls/acct/acct02_helper.c index 66017cb9b..0f55a6ae6 100644 --- a/testcases/kernel/syscalls/acct/acct02_helper.c +++ b/testcases/kernel/syscalls/acct/acct02_helper.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) SUSE LLC, 2019 - * Author: Christian Amann <camann@suse.com> + * Copyright (c) SUSE LLC, 2019 + * Author: Christian Amann <camann@suse.com> */ /* * Dummy program used in acct02 diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex03.c b/testcases/kernel/syscalls/adjtimex/adjtimex03.c index 7056973cc..9d34235e4 100644 --- a/testcases/kernel/syscalls/adjtimex/adjtimex03.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex03.c @@ -23,7 +23,7 @@ * To test that, Pass struct timex buffer filled with zero with * some INVALID mode to the system call adjtimex. Passing an invalid * parameters will not call do_adjtimex() and before that, it shall throw - * an error(On error test shall not break). Therefore, none of the parameters + * an error (on error test shall not break). Therefore, none of the parameters * will get initialized. * * On reading the last attribute tai of the struct, if the attribute is non- diff --git a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h index 7577ab24d..63ebf5295 100644 --- a/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h +++ b/testcases/kernel/syscalls/clock_adjtime/clock_adjtime.h @@ -251,4 +251,5 @@ TIMEX_GET_SET_FIELD_TYPE(uint, uint); TIMEX_GET_SET_FIELD_TYPE(long, long long); #undef TIMEX_GET_SET_FIELD_TYPE -#endif + +#endif /* CLOCK_ADJTIME_H__ */ diff --git a/testcases/kernel/syscalls/dup/dup06.c b/testcases/kernel/syscalls/dup/dup06.c index e3f8070bf..cd4cb3513 100644 --- a/testcases/kernel/syscalls/dup/dup06.c +++ b/testcases/kernel/syscalls/dup/dup06.c @@ -1,41 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2002 - * ported from SPIE, section2/iosuite/dup1.c, by Airong Zhang - * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2002 + * Ported from SPIE, section2/iosuite/dup1.c, by Airong Zhang + * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2003-2024 */ -/* - WHAT: Does dup return -1 on the 21st file? - HOW: Create up to _NFILE (20) files and check for -1 return on the - next attempt - Should check NOFILE as well as _NFILE. 19-Jun-84 Dale. -*/ +/*\ + * [Description] + * + * Test for dup(2) syscall with max open file descriptors. + */ -#include <stdio.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/param.h> -#include "test.h" +#include <stdlib.h> +#include "tst_test.h" -char *TCID = "dup06"; -int TST_TOTAL = 1; +static int *pfildes; +static int minfd, maxfd, freefds; +static char pfilname[40]; static int cnt_free_fds(int maxfd) { @@ -45,70 +27,53 @@ static int cnt_free_fds(int maxfd) if (fcntl(maxfd, F_GETFD) == -1 && errno == EBADF) freefds++; - return (freefds); + return freefds; } -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void setup(void) { - int *fildes, i; - int min; - int freefds; - int lc; - const char *pfilname = "dup06"; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - min = getdtablesize(); - freefds = cnt_free_fds(min); - fildes = malloc((min + 5) * sizeof(int)); - - for (i = 0; i < min + 5; i++) - fildes[i] = 0; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - unlink(pfilname); - - if ((fildes[0] = creat(pfilname, 0666)) == -1) { - tst_resm(TFAIL, "Cannot open first file"); - } else { - for (i = 1; i < min + 5; i++) { - if ((fildes[i] = dup(fildes[i - 1])) == -1) - break; - } - if (i < freefds) { - tst_resm(TFAIL, "Not enough files duped"); - } else if (i > freefds) { - tst_resm(TFAIL, "Too many files duped"); - } else { - tst_resm(TPASS, "Test passed."); - } - } - - unlink(pfilname); - - for (i = 0; i < min + 5; i++) { - if (fildes[i] != 0 && fildes[i] != -1) - close(fildes[i]); - - fildes[i] = 0; - } - } - - cleanup(); - tst_exit(); + minfd = getdtablesize(); /* get number of files allowed open */ + maxfd = minfd + 5; + freefds = cnt_free_fds(minfd); + pfildes = SAFE_MALLOC(maxfd * sizeof(int)); + memset(pfildes, -1, maxfd * sizeof(int)); + sprintf(pfilname, "./dup06.%d\n", getpid()); } -static void setup(void) +static void cleanup(void) { - tst_tmpdir(); + if (pfildes != NULL) + free(pfildes); } -static void cleanup(void) +static void run(void) { - tst_rmdir(); + int i; + + pfildes[0] = SAFE_CREAT(pfilname, 0666); + for (i = 1; i < maxfd; i++) { + pfildes[i] = dup(pfildes[i - 1]); + if (pfildes[i] == -1) + break; + } + if (i < freefds) + tst_res(TFAIL, "Not enough files duped"); + else if (i > freefds) + tst_res(TFAIL, "Too many files duped"); + else + tst_res(TPASS, "Test passed"); + + SAFE_UNLINK(pfilname); + + for (i = 0; i < maxfd; i++) { + if (pfildes[i] != 0 && pfildes[i] != -1) + SAFE_CLOSE(pfildes[i]); + } } + +static struct tst_test test = { + .needs_tmpdir = 1, + .test_all = run, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/dup/dup07.c b/testcases/kernel/syscalls/dup/dup07.c index a100f5d58..688ee1989 100644 --- a/testcases/kernel/syscalls/dup/dup07.c +++ b/testcases/kernel/syscalls/dup/dup07.c @@ -1,142 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2002 - * ported from SPIE, section2/iosuite/dup3.c, by Airong Zhang - * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2002 + * Ported from SPIE, section2/iosuite/dup3.c, by Airong Zhang + * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2006-2024 */ -/* - WHAT: Is the access mode the same for both file descriptors? - 0: read only? - 1: write only? - 2: read/write? - HOW: Creat a file with each access mode; dup each file descriptor; - stat each file descriptor and compare mode of each pair -*/ - -#include <stdio.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "test.h" +/*\ + * [Description] + * + * Verify that the file descriptor created by dup(2) syscall has the same + * access mode as the old one. + */ -char *TCID = "dup07"; -int TST_TOTAL = 3; +#include "tst_test.h" static const char *testfile = "dup07"; -static void setup(void); -static void cleanup(void); +static struct tcase { + char *mode_desc; + int mode; +} tcases[] = { + {"read only", 0444}, + {"write only", 0222}, + {"read/write", 0666}, +}; -int main(int ac, char **av) +static void run(unsigned int n) { - struct stat retbuf; - struct stat dupbuf; - int rdoret, wroret, rdwret; - int duprdo, dupwro, duprdwr; - - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - if ((rdoret = creat(testfile, 0444)) == -1) { - tst_resm(TFAIL, "Unable to creat file '%s'", testfile); - } else { - if ((duprdo = dup(rdoret)) == -1) { - tst_resm(TFAIL, "Unable to dup '%s'", testfile); - } else { - fstat(rdoret, &retbuf); - fstat(duprdo, &dupbuf); - if (retbuf.st_mode != dupbuf.st_mode) { - tst_resm(TFAIL, - "rdonly and dup do not match"); - } else { - tst_resm(TPASS, - "Passed in read mode."); - } - close(duprdo); - } - close(rdoret); - } - - unlink(testfile); - - if ((wroret = creat(testfile, 0222)) == -1) { - tst_resm(TFAIL, "Unable to creat file '%s'", testfile); - } else { - if ((dupwro = dup(wroret)) == -1) { - tst_resm(TFAIL, "Unable to dup '%s'", testfile); - } else { - fstat(wroret, &retbuf); - fstat(dupwro, &dupbuf); - if (retbuf.st_mode != dupbuf.st_mode) { - tst_resm(TFAIL, - "wronly and dup do not match"); - } else { - tst_resm(TPASS, - "Passed in write mode."); - } - close(dupwro); - } - close(wroret); - - } - - unlink(testfile); - - if ((rdwret = creat(testfile, 0666)) == -1) { - tst_resm(TFAIL, "Unable to creat file '%s'", testfile); - } else { - if ((duprdwr = dup(rdwret)) == -1) { - tst_resm(TFAIL, "Unable to dup '%s'", testfile); - } else { - fstat(rdwret, &retbuf); - fstat(duprdwr, &dupbuf); - if (retbuf.st_mode != dupbuf.st_mode) { - tst_resm(TFAIL, - "rdwr and dup do not match"); - } else { - tst_resm(TPASS, - "Passed in read/write mode."); - } - close(duprdwr); - } - close(rdwret); - } - - unlink(testfile); + int oldfd, dupfd; + struct stat oldbuf, dupbuf; + struct tcase *tc = &tcases[n]; + + oldfd = SAFE_CREAT(testfile, tc->mode); + dupfd = TST_EXP_FD_SILENT(dup(oldfd), "dup() %s file", tc->mode_desc); + if (TST_PASS) { + SAFE_FSTAT(oldfd, &oldbuf); + SAFE_FSTAT(dupfd, &dupbuf); + + if (oldbuf.st_mode != dupbuf.st_mode) + tst_res(TFAIL, "%s and dup do not match", tc->mode_desc); + else + tst_res(TPASS, "Passed in %s mode", tc->mode_desc); + + SAFE_CLOSE(dupfd); } - cleanup(); - tst_exit(); + SAFE_CLOSE(oldfd); + SAFE_UNLINK(testfile); } -static void setup(void) -{ - tst_tmpdir(); -} - -static void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .needs_tmpdir = 1, + .test = run, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2.h b/testcases/kernel/syscalls/eventfd2/eventfd2.h index 5350820b8..2333d1e53 100644 --- a/testcases/kernel/syscalls/eventfd2/eventfd2.h +++ b/testcases/kernel/syscalls/eventfd2/eventfd2.h @@ -3,6 +3,9 @@ * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ +#ifndef EVENTFD2_H__ +#define EVENTFD2_H__ + #include "tst_test.h" #include "lapi/syscalls.h" @@ -16,3 +19,5 @@ static inline int eventfd2(unsigned int count, unsigned int flags) return ret; } + +#endif /* EVENTFD2_H__ */ diff --git a/testcases/kernel/syscalls/execve/execve04.c b/testcases/kernel/syscalls/execve/execve04.c index 18e883ab3..3bac642e5 100644 --- a/testcases/kernel/syscalls/execve/execve04.c +++ b/testcases/kernel/syscalls/execve/execve04.c @@ -8,7 +8,9 @@ * 04/2008 Roy Lee <roylee@andestech.com> */ -/* +/*\ + * [Description] + * * Attempt to execve(2) a file which is being opened by another process for * writing fails with ETXTBSY. */ diff --git a/testcases/kernel/syscalls/execve/execve05.c b/testcases/kernel/syscalls/execve/execve05.c index 87565d994..d87d7446d 100644 --- a/testcases/kernel/syscalls/execve/execve05.c +++ b/testcases/kernel/syscalls/execve/execve05.c @@ -1,32 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2018 Linux Test Project + * Copyright (c) 2001-2023 Linux Test Project * Copyright (c) International Business Machines Corp., 2001 - * + * Copyright (c) 2008 Renaud Lottiaux <Renaud.Lottiaux@kerlabs.com> * Ported to LTP: Wayne Boyer - * 21/04/2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com) */ -/* - * NAME - * execve05.c - * - * DESCRIPTION - * This testcase tests the basic functionality of the execve(2) system - * call. +/*\ + * [Description] * - * ALGORITHM - * This tests the functionality of the execve(2) system call by spawning - * a few children, each of which would execute "execve_child" simultaneously, - * and finally the parent ensures that they terminated correctly. - * - * USAGE - * execve05 -i 5 -n 20 + * This tests the functionality of the execve(2) system call by spawning + * a few children, each of which would execute "execve_child" simultaneously, + * and finally the parent ensures that they terminated correctly. */ -#ifndef _GNU_SOURCE #define _GNU_SOURCE -#endif + #include <stdio.h> #include <stdlib.h> #include <errno.h> diff --git a/testcases/kernel/syscalls/exit_group/Makefile b/testcases/kernel/syscalls/exit_group/Makefile index 1273a4e9c..adbac3c51 100644 --- a/testcases/kernel/syscalls/exit_group/Makefile +++ b/testcases/kernel/syscalls/exit_group/Makefile @@ -3,6 +3,8 @@ top_srcdir ?= ../../../.. +exit_group01: CFLAGS+=-pthread + include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/exit_group/exit_group01.c b/testcases/kernel/syscalls/exit_group/exit_group01.c index 5bf5b0218..6407a20e8 100644 --- a/testcases/kernel/syscalls/exit_group/exit_group01.c +++ b/testcases/kernel/syscalls/exit_group/exit_group01.c @@ -1,68 +1,127 @@ -/****************************************************************************** - * Copyright (c) Crackerjack Project., 2007 * - * Ported to LTP by Manas Kumar Nayak <maknayak@in.ibm.com> * - * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz> * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * 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, write to the Free Software Foundation, * - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * * - ******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Ported to LTP by Manas Kumar Nayak <maknayak@in.ibm.com> + * Copyright (c) 2015 Linux Test Project + * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ -#include <stdio.h> -#include <errno.h> -#include <linux/unistd.h> -#include <sys/wait.h> +/*\ + * [Description] + * + * This test checks if exit_group() correctly ends a spawned child and all its + * running threads. + */ -#include "test.h" -#include "safe_macros.h" +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include "tst_test.h" #include "lapi/syscalls.h" +#include "tst_safe_pthread.h" + +static int cpu_count; -char *TCID = "exit_group01"; -int testno; -int TST_TOTAL = 1; +static struct worker_data { + pid_t tid; + int counter; +} *workers_data; -static void verify_exit_group(void) +static void *worker(void *arg) { - pid_t cpid, w; - int status; + struct worker_data *data; - cpid = fork(); - if (cpid == -1) - tst_brkm(TFAIL | TERRNO, NULL, "fork failed"); + data = (struct worker_data *)arg; + data->tid = tst_gettid(); - if (cpid == 0) { - TEST(tst_syscall(__NR_exit_group, 4)); - } else { - w = SAFE_WAIT(NULL, &status); - - if (WIFEXITED(status) && (WEXITSTATUS(status) == 4)) { - tst_resm(TPASS, "exit_group() succeeded"); - } else { - tst_resm(TFAIL | TERRNO, - "exit_group() failed (wait status = %d)", w); + while (1) { + tst_atomic_inc(&data->counter); + sched_yield(); + } + + return arg; +} + +static void spawn_threads(void) +{ + pthread_t threads[cpu_count]; + + for (int i = 0; i < cpu_count; i++) + SAFE_PTHREAD_CREATE(&threads[i], NULL, worker, (void *)(workers_data + i)); +} + +static void check_counters(void) +{ + struct worker_data data_copy[cpu_count]; + + memset(data_copy, 0, sizeof(struct worker_data) * cpu_count); + memcpy(data_copy, workers_data, sizeof(struct worker_data) * cpu_count); + + tst_res(TINFO, "Checking if threads are still running"); + usleep(100000); + + struct worker_data *old_data; + struct worker_data *new_data; + + for (int i = 0; i < cpu_count; i++) { + old_data = data_copy + i; + new_data = workers_data + i; + + if (old_data->counter != new_data->counter) { + tst_res(TFAIL, "Counter value has changed for thread[%d]", i); + return; } } + + tst_res(TINFO, "Threads counters value didn't change"); } -int main(int ac, char **av) +static void run(void) { - int lc; + pid_t pid; + int status; + + pid = SAFE_FORK(); + if (!pid) { + spawn_threads(); + + TEST(tst_syscall(__NR_exit_group, 4)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "exit_group() error"); + + return; + } - tst_parse_opts(ac, av, NULL, NULL); + SAFE_WAITPID(pid, &status, 0); - for (lc = 0; TEST_LOOPING(lc); lc++) - verify_exit_group(); + TST_EXP_EXPR(WIFEXITED(status) && WEXITSTATUS(status) == 4, + "exit_group() succeeded"); - tst_exit(); + check_counters(); } + +static void setup(void) +{ + cpu_count = MAX(2, tst_ncpus()); + + workers_data = SAFE_MMAP( + NULL, + sizeof(struct worker_data) * cpu_count, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, + -1, 0); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(workers_data, sizeof(struct worker_data) * cpu_count); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/fallocate/fallocate06.c b/testcases/kernel/syscalls/fallocate/fallocate06.c index 124fb7eae..24f98e271 100644 --- a/testcases/kernel/syscalls/fallocate/fallocate06.c +++ b/testcases/kernel/syscalls/fallocate/fallocate06.c @@ -260,6 +260,8 @@ static struct tst_test test = { .test = run, .tcnt = ARRAY_SIZE(testcase_list), .needs_root = 1, + .dev_min_size = 1024, + .max_runtime = 120, .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h index 75a081dc9..e0d178bcc 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify.h +++ b/testcases/kernel/syscalls/fanotify/fanotify.h @@ -68,19 +68,14 @@ static inline int safe_fanotify_mark(const char *file, const int lineno, #ifdef HAVE_NAME_TO_HANDLE_AT -#ifndef MAX_HANDLE_SZ -#define MAX_HANDLE_SZ 128 -#endif - -#ifndef AT_HANDLE_FID -#define AT_HANDLE_FID 0x200 -#endif - /* * Helper function used to obtain fsid and file_handle for a given path. * Used by test files correlated to FAN_REPORT_FID functionality. + * + * Returns 0 if normal NFS file handles are supported. + * Returns AT_HANDLE_FID, if only non-decodeable file handles are supported. */ -static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, +static inline int fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, struct file_handle *handle) { int mount_id; @@ -93,6 +88,11 @@ static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) { if (errno == EOPNOTSUPP) { + /* Try to request non-decodeable fid instead */ + if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, + AT_HANDLE_FID) == 0) + return AT_HANDLE_FID; + tst_brk(TCONF, "filesystem %s does not support file handles", tst_device->fs_type); @@ -100,30 +100,30 @@ static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, tst_brk(TBROK | TERRNO, "name_to_handle_at(AT_FDCWD, %s, ...) failed", path); } + return 0; } -#ifndef FILEID_INVALID -#define FILEID_INVALID 0xff -#endif - struct fanotify_fid_t { __kernel_fsid_t fsid; struct file_handle handle; char buf[MAX_HANDLE_SZ]; }; -static inline void fanotify_save_fid(const char *path, +static inline int fanotify_save_fid(const char *path, struct fanotify_fid_t *fid) { int *fh = (int *)(fid->handle.f_handle); + int ret; fh[0] = fh[1] = fh[2] = 0; fid->handle.handle_bytes = MAX_HANDLE_SZ; - fanotify_get_fid(path, &fid->fsid, &fid->handle); + ret = fanotify_get_fid(path, &fid->fsid, &fid->handle); tst_res(TINFO, "fid(%s) = %x.%x.%x.%x.%x...", path, fid->fsid.val[0], fid->fsid.val[1], fh[0], fh[1], fh[2]); + + return ret; } #endif /* HAVE_NAME_TO_HANDLE_AT */ @@ -133,13 +133,14 @@ static inline void fanotify_save_fid(const char *path, #define INIT_FANOTIFY_MARK_TYPE(t) \ { FAN_MARK_ ## t, "FAN_MARK_" #t } -static inline void require_fanotify_access_permissions_supported_by_kernel(void) +static inline void require_fanotify_access_permissions_supported_on_fs( + const char *fname) { int fd; fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY); - if (fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, ".") < 0) { + if (fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, fname) < 0) { if (errno == EINVAL) { tst_brk(TCONF | TERRNO, "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not configured in kernel?"); @@ -152,21 +153,42 @@ static inline void require_fanotify_access_permissions_supported_by_kernel(void) SAFE_CLOSE(fd); } -static inline int fanotify_events_supported_by_kernel(uint64_t mask, - unsigned int init_flags, - unsigned int mark_flags) +/* + * @return 0: fanotify flags supported both in kernel and on tested filesystem + * @return -1: @init_flags not supported in kernel + * @return -2: @mark_flags not supported on tested filesystem (tested if @fname is not NULL) + * @return -3: @mark_flags not supported on overlayfs (tested if @fname == OVL_MNT) + */ +static inline int fanotify_flags_supported_on_fs(unsigned int init_flags, + unsigned int mark_flags, + uint64_t event_flags, + const char *fname) { int fd; int rval = 0; - fd = SAFE_FANOTIFY_INIT(init_flags, O_RDONLY); + fd = fanotify_init(init_flags, O_RDONLY); - if (fanotify_mark(fd, FAN_MARK_ADD | mark_flags, mask, AT_FDCWD, ".") < 0) { - if (errno == EINVAL) { - rval = -1; - } else { + if (fd < 0) { + if (errno == ENOSYS) + tst_brk(TCONF, "fanotify not configured in kernel"); + if (errno != EINVAL) + tst_brk(TBROK | TERRNO, + "fanotify_init(%x, O_RDONLY) failed", + init_flags); + return -1; + } + + if (fname && fanotify_mark(fd, FAN_MARK_ADD | mark_flags, event_flags, AT_FDCWD, fname) < 0) { + if (errno == ENODEV || errno == EOPNOTSUPP || errno == EXDEV) { + rval = strcmp(fname, OVL_MNT) ? -2 : -3; + } else if (errno != EINVAL) { tst_brk(TBROK | TERRNO, - "fanotify_mark (%d, FAN_MARK_ADD, ..., AT_FDCWD, \".\") failed", fd); + "fanotify_mark (%d, FAN_MARK_ADD | %x, %llx, AT_FDCWD, %s) failed", + fd, mark_flags, (unsigned long long)event_flags, + fname); + } else { + rval = -1; } } @@ -175,95 +197,85 @@ static inline int fanotify_events_supported_by_kernel(uint64_t mask, return rval; } -/* - * @return 0: fanotify supported both in kernel and on tested filesystem - * @return -1: @flags not supported in kernel - * @return -2: @flags not supported on tested filesystem (tested if @fname is not NULL) - */ static inline int fanotify_init_flags_supported_on_fs(unsigned int flags, const char *fname) { - int fd; - int rval = 0; - - fd = fanotify_init(flags, O_RDONLY); + return fanotify_flags_supported_on_fs(flags, FAN_MARK_INODE, FAN_ACCESS, fname); +} - if (fd < 0) { - if (errno == ENOSYS) - tst_brk(TCONF, "fanotify not configured in kernel"); +static inline int fanotify_mark_supported_on_fs(uint64_t flag, const char *fname) +{ + return fanotify_flags_supported_on_fs(FAN_CLASS_NOTIF, flag, FAN_ACCESS, fname); +} - if (errno == EINVAL) - return -1; +#define TST_FANOTIFY_INIT_KNOWN_FLAGS \ + (FAN_REPORT_DFID_NAME_TARGET | FAN_REPORT_TID | FAN_REPORT_PIDFD | \ + FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | FAN_CLASS_PRE_CONTENT) - tst_brk(TBROK | TERRNO, "fanotify_init() failed"); +/* + * Check support of given init flags one by one and return those which are + * supported. + */ +static inline unsigned int fanotify_get_supported_init_flags(unsigned int flags, + const char *fname) +{ + unsigned int i, flg, arg, ret = 0; + static const struct { unsigned int flag, deps; } deplist[] = { + {FAN_REPORT_NAME, FAN_REPORT_DIR_FID}, + {FAN_REPORT_TARGET_FID, FAN_REPORT_DFID_NAME_FID}, + {0, 0} + }; + + if (flags & ~TST_FANOTIFY_INIT_KNOWN_FLAGS) { + tst_brk(TBROK, "fanotify_init() feature check called with unknown flags %x, please update flag dependency table if needed", + flags & ~TST_FANOTIFY_INIT_KNOWN_FLAGS); } - if (fname && fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS, AT_FDCWD, fname) < 0) { - if (errno == ENODEV || errno == EOPNOTSUPP || errno == EXDEV) { - rval = -2; - } else { - tst_brk(TBROK | TERRNO, - "fanotify_mark (%d, FAN_MARK_ADD, ..., AT_FDCWD, %s) failed", - fd, fname); - } - } + for (flg = 1; flg; flg <<= 1) { + if (!(flags & flg)) + continue; - SAFE_CLOSE(fd); + arg = flg; - return rval; -} + for (i = 0; deplist[i].flag; i++) { + if (deplist[i].flag == flg) { + arg |= deplist[i].deps; + break; + } + } -static inline int fanotify_init_flags_supported_by_kernel(unsigned int flags) -{ - return fanotify_init_flags_supported_on_fs(flags, NULL); + if (!fanotify_init_flags_supported_on_fs(arg, fname)) + ret |= flg; + } + + return ret; } typedef void (*tst_res_func_t)(const char *file, const int lineno, int ttype, const char *fmt, ...); -static inline void fanotify_init_flags_err_msg(const char *flags_str, +static inline void fanotify_flags_err_msg(const char *flags_str, const char *file, const int lineno, tst_res_func_t res_func, int fail) { if (fail == -1) res_func(file, lineno, TCONF, "%s not supported in kernel?", flags_str); - if (fail == -2) + if (fail == -2 || fail == -3) res_func(file, lineno, TCONF, - "%s not supported on %s filesystem", - flags_str, tst_device->fs_type); + "%s not supported on %s%s filesystem", + flags_str, fail == -3 ? "overlayfs over " : "", + tst_device->fs_type); } #define FANOTIFY_INIT_FLAGS_ERR_MSG(flags, fail) \ - fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_res_, (fail)) + fanotify_flags_err_msg(#flags, __FILE__, __LINE__, tst_res_, (fail)) + +#define FANOTIFY_MARK_FLAGS_ERR_MSG(mark, fail) \ + fanotify_flags_err_msg((mark)->name, __FILE__, __LINE__, tst_res_, (fail)) #define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(flags, fname) \ - fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \ + fanotify_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \ fanotify_init_flags_supported_on_fs(flags, fname)) -#define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(flags) \ - fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \ - fanotify_init_flags_supported_by_kernel(flags)) - -static inline int fanotify_mark_supported_by_kernel(uint64_t flag) -{ - int fd; - int rval = 0; - - fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY); - - if (fanotify_mark(fd, FAN_MARK_ADD | flag, FAN_ACCESS, AT_FDCWD, ".") < 0) { - if (errno == EINVAL) { - rval = -1; - } else { - tst_brk(TBROK | TERRNO, - "fanotify_mark (%d, FAN_MARK_ADD, ..., FAN_ACCESS, AT_FDCWD, \".\") failed", fd); - } - } - - SAFE_CLOSE(fd); - - return rval; -} - static inline int fanotify_handle_supported_by_kernel(int flag) { /* @@ -277,21 +289,21 @@ static inline int fanotify_handle_supported_by_kernel(int flag) return 0; } -#define REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type) \ - fanotify_init_flags_err_msg(#mark_type, __FILE__, __LINE__, tst_brk_, \ - fanotify_mark_supported_by_kernel(mark_type)) +#define REQUIRE_MARK_TYPE_SUPPORTED_ON_FS(mark_type, fname) \ + fanotify_flags_err_msg(#mark_type, __FILE__, __LINE__, tst_brk_, \ + fanotify_mark_supported_on_fs(mark_type, fname)) #define REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(handle_type) \ - fanotify_init_flags_err_msg(#handle_type, __FILE__, __LINE__, tst_brk_, \ - fanotify_handle_supported_by_kernel(handle_type)) + fanotify_flags_err_msg(#handle_type, __FILE__, __LINE__, tst_brk_, \ + fanotify_handle_supported_by_kernel(handle_type)) #define REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(init_flags, mark_type, mask, fname) do { \ if (mark_type) \ - REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type); \ + REQUIRE_MARK_TYPE_SUPPORTED_ON_FS(mark_type, fname); \ if (init_flags) \ REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(init_flags, fname); \ - fanotify_init_flags_err_msg(#mask, __FILE__, __LINE__, tst_brk_, \ - fanotify_events_supported_by_kernel(mask, init_flags, mark_type)); \ + fanotify_flags_err_msg(#mask, __FILE__, __LINE__, tst_brk_, \ + fanotify_flags_supported_on_fs(init_flags, mark_type, mask, fname)); \ } while (0) static inline struct fanotify_event_info_header *get_event_info( diff --git a/testcases/kernel/syscalls/fanotify/fanotify01.c b/testcases/kernel/syscalls/fanotify/fanotify01.c index 3538335c9..e4398f236 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify01.c +++ b/testcases/kernel/syscalls/fanotify/fanotify01.c @@ -76,6 +76,7 @@ static char fname[BUF_SIZE]; static char buf[BUF_SIZE]; static int fd_notify; static int fan_report_fid_unsupported; +static int mount_mark_fid_unsupported; static int filesystem_mark_unsupported; static unsigned long long event_set[EVENT_MAX]; @@ -88,16 +89,22 @@ static void test_fanotify(unsigned int n) struct fanotify_mark_type *mark = &tc->mark; int fd, ret, len, i = 0, test_num = 0; int tst_count = 0; + int report_fid = (tc->init_flags & FAN_REPORT_FID); tst_res(TINFO, "Test #%d: %s", n, tc->tname); - if (fan_report_fid_unsupported && (tc->init_flags & FAN_REPORT_FID)) { + if (fan_report_fid_unsupported && report_fid) { FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_FID, fan_report_fid_unsupported); return; } if (filesystem_mark_unsupported && mark->flag == FAN_MARK_FILESYSTEM) { - tst_res(TCONF, "FAN_MARK_FILESYSTEM not supported in kernel?"); + FANOTIFY_MARK_FLAGS_ERR_MSG(mark, filesystem_mark_unsupported); + return; + } + + if (mount_mark_fid_unsupported && report_fid && mark->flag != FAN_MARK_INODE) { + FANOTIFY_MARK_FLAGS_ERR_MSG(mark, mount_mark_fid_unsupported); return; } @@ -341,7 +348,10 @@ static void setup(void) SAFE_FILE_PRINTF(fname, "1"); fan_report_fid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_FID, fname); - filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); + filesystem_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_FILESYSTEM, fname); + mount_mark_fid_unsupported = fanotify_flags_supported_on_fs(FAN_REPORT_FID, + FAN_MARK_MOUNT, + FAN_OPEN, fname); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/fanotify/fanotify03.c b/testcases/kernel/syscalls/fanotify/fanotify03.c index 0bd61587a..028da742c 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify03.c +++ b/testcases/kernel/syscalls/fanotify/fanotify03.c @@ -320,14 +320,14 @@ static void test_fanotify(unsigned int n) static void setup(void) { - require_fanotify_access_permissions_supported_by_kernel(); - - filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); - exec_events_unsupported = fanotify_events_supported_by_kernel(FAN_OPEN_EXEC_PERM, - FAN_CLASS_CONTENT, 0); sprintf(fname, MOUNT_PATH"/fname_%d", getpid()); SAFE_FILE_PRINTF(fname, "1"); + require_fanotify_access_permissions_supported_on_fs(fname); + filesystem_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_FILESYSTEM, fname); + exec_events_unsupported = fanotify_flags_supported_on_fs(FAN_CLASS_CONTENT, + 0, FAN_OPEN_EXEC_PERM, fname); + SAFE_CP(TEST_APP, FILE_EXEC_PATH); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify07.c b/testcases/kernel/syscalls/fanotify/fanotify07.c index 396c8490e..34aa810c7 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify07.c +++ b/testcases/kernel/syscalls/fanotify/fanotify07.c @@ -189,10 +189,9 @@ static void test_fanotify(void) static void setup(void) { - require_fanotify_access_permissions_supported_by_kernel(); - sprintf(fname, "fname_%d", getpid()); SAFE_FILE_PRINTF(fname, "%s", fname); + require_fanotify_access_permissions_supported_on_fs(fname); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/fanotify/fanotify09.c b/testcases/kernel/syscalls/fanotify/fanotify09.c index 3f2db4709..f61c4e45a 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify09.c +++ b/testcases/kernel/syscalls/fanotify/fanotify09.c @@ -480,9 +480,11 @@ static void test_fanotify(unsigned int n) static void setup(void) { - fan_report_dfid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME, - MOUNT_PATH); - ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV); + fan_report_dfid_unsupported = fanotify_flags_supported_on_fs(FAN_REPORT_DFID_NAME, + FAN_MARK_MOUNT, + FAN_OPEN, MOUNT_PATH); + ignore_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_IGNORE_SURV, + MOUNT_PATH); SAFE_MKDIR(MOUNT_NAME, 0755); SAFE_MOUNT(MOUNT_PATH, MOUNT_NAME, "none", MS_BIND, NULL); diff --git a/testcases/kernel/syscalls/fanotify/fanotify10.c b/testcases/kernel/syscalls/fanotify/fanotify10.c index d0e9194e7..6c89ca1d0 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify10.c +++ b/testcases/kernel/syscalls/fanotify/fanotify10.c @@ -874,13 +874,17 @@ static void setup(void) { int i; - exec_events_unsupported = fanotify_events_supported_by_kernel(FAN_OPEN_EXEC, - FAN_CLASS_CONTENT, 0); - filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); - evictable_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_EVICTABLE); - ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV); - fan_report_dfid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME, - MOUNT_PATH); + exec_events_unsupported = fanotify_flags_supported_on_fs(FAN_CLASS_CONTENT, + 0, FAN_OPEN_EXEC, MOUNT_PATH); + filesystem_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_FILESYSTEM, + MOUNT_PATH); + evictable_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_EVICTABLE, + MOUNT_PATH); + ignore_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_IGNORE_SURV, + MOUNT_PATH); + fan_report_dfid_unsupported = fanotify_flags_supported_on_fs(FAN_REPORT_DFID_NAME, + FAN_MARK_MOUNT, + FAN_OPEN, MOUNT_PATH); if (fan_report_dfid_unsupported) { FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_DFID_NAME, fan_report_dfid_unsupported); /* Limit tests to legacy priority classes */ diff --git a/testcases/kernel/syscalls/fanotify/fanotify11.c b/testcases/kernel/syscalls/fanotify/fanotify11.c index 03583d84b..ce46913b1 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify11.c +++ b/testcases/kernel/syscalls/fanotify/fanotify11.c @@ -94,7 +94,7 @@ static void test01(unsigned int i) static void setup(void) { - fan_report_tid_unsupported = fanotify_init_flags_supported_by_kernel(FAN_REPORT_TID); + fan_report_tid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_TID, "."); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/fanotify/fanotify12.c b/testcases/kernel/syscalls/fanotify/fanotify12.c index 7f8e97b17..42ba08800 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify12.c +++ b/testcases/kernel/syscalls/fanotify/fanotify12.c @@ -222,11 +222,10 @@ cleanup: static void do_setup(void) { - exec_events_unsupported = fanotify_events_supported_by_kernel(FAN_OPEN_EXEC, - FAN_CLASS_NOTIF, 0); - sprintf(fname, "fname_%d", getpid()); SAFE_FILE_PRINTF(fname, "1"); + exec_events_unsupported = fanotify_flags_supported_on_fs(FAN_CLASS_NOTIF, + 0, FAN_OPEN_EXEC, fname); } static void do_cleanup(void) diff --git a/testcases/kernel/syscalls/fanotify/fanotify13.c b/testcases/kernel/syscalls/fanotify/fanotify13.c index a25a360fd..6086a81fc 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify13.c +++ b/testcases/kernel/syscalls/fanotify/fanotify13.c @@ -91,8 +91,10 @@ static struct test_case_t { static int ovl_mounted; static int bind_mounted; +static int ovl_bind_mounted; static int nofid_fd; static int fanotify_fd; +static int at_handle_fid; static int filesystem_mark_unsupported; static char events_buf[BUF_SIZE]; static struct event_t event_set[EVENT_MAX]; @@ -113,8 +115,10 @@ static void get_object_stats(void) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(objects); i++) - fanotify_save_fid(objects[i].path, &objects[i].fid); + for (i = 0; i < ARRAY_SIZE(objects); i++) { + at_handle_fid |= + fanotify_save_fid(objects[i].path, &objects[i].fid); + } } static int setup_marks(unsigned int fd, struct test_case_t *tc) @@ -154,8 +158,8 @@ static void do_test(unsigned int number) return; } - if (filesystem_mark_unsupported && mark->flag & FAN_MARK_FILESYSTEM) { - tst_res(TCONF, "FAN_MARK_FILESYSTEM not supported in kernel?"); + if (filesystem_mark_unsupported && mark->flag != FAN_MARK_INODE) { + FANOTIFY_MARK_FLAGS_ERR_MSG(mark, filesystem_mark_unsupported); return; } @@ -168,10 +172,10 @@ static void do_test(unsigned int number) if (setup_marks(fanotify_fd, tc) != 0) goto out; - /* Variant #1: watching upper fs - open files on overlayfs */ - if (tst_variant == 1) { + /* Watching base fs - open files on overlayfs */ + if (tst_variant && !ovl_bind_mounted) { if (mark->flag & FAN_MARK_MOUNT) { - tst_res(TCONF, "overlayfs upper fs cannot be watched with mount mark"); + tst_res(TCONF, "overlayfs base fs cannot be watched with mount mark"); goto out; } SAFE_MOUNT(OVL_MNT, MOUNT_PATH, "none", MS_BIND, NULL); @@ -191,7 +195,7 @@ static void do_test(unsigned int number) SAFE_CLOSE(fds[i]); } - if (tst_variant == 1) + if (tst_variant && !ovl_bind_mounted) SAFE_UMOUNT(MOUNT_PATH); /* Read events from event queue */ @@ -286,19 +290,27 @@ static void do_setup(void) /* * Bind mount to either base fs or to overlayfs over base fs: * Variant #0: watch base fs - open files on base fs - * Variant #1: watch upper fs - open files on overlayfs + * Variant #1: watch lower fs - open lower files on overlayfs + * Variant #2: watch upper fs - open upper files on overlayfs + * Variant #3: watch overlayfs - open lower files on overlayfs + * Variant #4: watch overlayfs - open upper files on overlayfs * - * Variant #1 tests a bug whose fix bc2473c90fca ("ovl: enable fsnotify + * Variants 1,2 test a bug whose fix bc2473c90fca ("ovl: enable fsnotify * events on underlying real files") in kernel 6.5 is not likely to be * backported to older kernels. * To avoid waiting for events that won't arrive when testing old kernels, - * require that kernel supports encoding fid with new flag AT_HADNLE_FID, + * require that kernel supports encoding fid with new flag AT_HANDLE_FID, * also merged to 6.5 and not likely to be backported to older kernels. + * Variants 3,4 test overlayfs watch with FAN_REPORT_FID, which also + * requires kernel with support for AT_HANDLE_FID. */ if (tst_variant) { REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(AT_HANDLE_FID); ovl_mounted = TST_MOUNT_OVERLAY(); - mnt = OVL_UPPER; + if (!ovl_mounted) + return; + + mnt = tst_variant & 1 ? OVL_LOWER : OVL_UPPER; } else { mnt = OVL_BASE_MNTPOINT; @@ -308,13 +320,21 @@ static void do_setup(void) SAFE_MOUNT(mnt, MOUNT_PATH, "none", MS_BIND, NULL); bind_mounted = 1; - filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); - nofid_fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY); - /* Create file and directory objects for testing */ + /* Create file and directory objects for testing on base fs */ create_objects(); + if (tst_variant > 2) { + /* Setup watches on overlayfs */ + SAFE_MOUNT(OVL_MNT, MOUNT_PATH, "none", MS_BIND, NULL); + ovl_bind_mounted = 1; + } + + filesystem_mark_unsupported = + fanotify_flags_supported_on_fs(FAN_REPORT_FID, FAN_MARK_FILESYSTEM, FAN_OPEN, + ovl_bind_mounted ? OVL_MNT : MOUNT_PATH); + /* * Create a mark on first inode without FAN_REPORT_FID, to test * uninitialized connector->fsid cache. This mark remains for all test @@ -329,9 +349,12 @@ static void do_setup(void) static void do_cleanup(void) { - SAFE_CLOSE(nofid_fd); + if (nofid_fd > 0) + SAFE_CLOSE(nofid_fd); if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (ovl_bind_mounted) + SAFE_UMOUNT(MOUNT_PATH); if (bind_mounted) { SAFE_UMOUNT(MOUNT_PATH); SAFE_RMDIR(MOUNT_PATH); @@ -343,7 +366,7 @@ static void do_cleanup(void) static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(test_cases), - .test_variants = 2, + .test_variants = 5, .setup = do_setup, .cleanup = do_cleanup, .needs_root = 1, diff --git a/testcases/kernel/syscalls/fanotify/fanotify14.c b/testcases/kernel/syscalls/fanotify/fanotify14.c index 4596511f0..0b0da89ca 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify14.c +++ b/testcases/kernel/syscalls/fanotify/fanotify14.c @@ -45,8 +45,9 @@ static int pipes[2] = {-1, -1}; static int fanotify_fd; -static int fan_report_target_fid_unsupported; static int ignore_mark_unsupported; +static int filesystem_mark_unsupported; +static unsigned int supported_init_flags; struct test_case_flags_t { unsigned long long flags; @@ -246,9 +247,8 @@ static void do_test(unsigned int number) tst_res(TINFO, "Test case %d: fanotify_init(%s, O_RDONLY)", number, tc->init.desc); - if (fan_report_target_fid_unsupported && tc->init.flags & FAN_REPORT_TARGET_FID) { - FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID, - fan_report_target_fid_unsupported); + if (tc->init.flags & ~supported_init_flags) { + tst_res(TCONF, "Unsupported init flags"); return; } @@ -300,7 +300,7 @@ static void do_test(unsigned int number) "Adding an inode mark on directory did not fail with " "ENOTDIR error as on non-dir inode"); - if (!(tc->mark.flags & FAN_MARK_ONLYDIR)) { + if (!(tc->mark.flags & FAN_MARK_ONLYDIR) && !filesystem_mark_unsupported) { SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD | tc->mark.flags | FAN_MARK_FILESYSTEM, tc->mask.flags, AT_FDCWD, FILE1); @@ -317,12 +317,18 @@ out: static void do_setup(void) { + unsigned int all_init_flags = FAN_REPORT_DFID_NAME_TARGET | + FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | FAN_CLASS_PRE_CONTENT; + /* Require FAN_REPORT_FID support for all tests to simplify per test case requirements */ REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, MNTPOINT); + supported_init_flags = fanotify_get_supported_init_flags(all_init_flags, MNTPOINT); - fan_report_target_fid_unsupported = - fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MNTPOINT); - ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV); + ignore_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_IGNORE_SURV, + MNTPOINT); + filesystem_mark_unsupported = + fanotify_flags_supported_on_fs(FAN_REPORT_FID, FAN_MARK_FILESYSTEM, FAN_OPEN, + MNTPOINT); /* Create temporary test file to place marks on */ SAFE_FILE_PRINTF(FILE1, "0"); diff --git a/testcases/kernel/syscalls/fanotify/fanotify15.c b/testcases/kernel/syscalls/fanotify/fanotify15.c index 6109d32cd..bacf05049 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify15.c +++ b/testcases/kernel/syscalls/fanotify/fanotify15.c @@ -52,6 +52,7 @@ struct event_t { }; static int fanotify_fd; +static int filesystem_mark_unsupported; static char events_buf[EVENT_BUF_LEN]; static struct event_t event_set[EVENT_MAX]; @@ -85,6 +86,11 @@ static void do_test(unsigned int number) tst_res(TINFO, "Test #%d: %s", number, tc->tname); + if (filesystem_mark_unsupported && mark->flag != FAN_MARK_INODE) { + FANOTIFY_MARK_FLAGS_ERR_MSG(mark, filesystem_mark_unsupported); + return; + } + SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD | mark->flag, tc->mask | FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_MODIFY | FAN_ONDIR, @@ -274,6 +280,10 @@ static void do_setup(void) { SAFE_MKDIR(TEST_DIR, 0755); REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, TEST_DIR); + filesystem_mark_unsupported = + fanotify_flags_supported_on_fs(FAN_REPORT_FID, FAN_MARK_FILESYSTEM, FAN_OPEN, + MOUNT_POINT); + fanotify_fd = SAFE_FANOTIFY_INIT(FAN_REPORT_FID, O_RDONLY); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify16.c b/testcases/kernel/syscalls/fanotify/fanotify16.c index d45270a9a..6ab360984 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify16.c +++ b/testcases/kernel/syscalls/fanotify/fanotify16.c @@ -70,6 +70,7 @@ static char event_buf[EVENT_BUF_LEN]; #define TEMP_DIR MOUNT_PATH "/temp_dir" static int fan_report_target_fid_unsupported; +static int filesystem_mark_unsupported; static int rename_events_unsupported; static struct test_case_t { @@ -281,6 +282,16 @@ static void do_test(unsigned int number) return; } + if (filesystem_mark_unsupported) { + if (sub_mark && sub_mark->flag != FAN_MARK_INODE) + mark = sub_mark; + + if (mark->flag != FAN_MARK_INODE) { + FANOTIFY_MARK_FLAGS_ERR_MSG(mark, filesystem_mark_unsupported); + return; + } + } + fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0); /* @@ -328,7 +339,15 @@ static void do_test(unsigned int number) tst_count++; /* Generate modify events "on child" */ - fd = SAFE_CREAT(fname1, 0755); + + /* + * Split SAFE_CREAT() into explicit SAFE_MKNOD() and SAFE_OPEN(), + * because with atomic open (e.g. fuse), SAFE_CREAT() generates + * FAN_OPEN before FAN_CREATE and it is inconsistent with the order + * of events expectated from other filesystems. + */ + SAFE_MKNOD(fname1, S_IFREG | 0644, 0); + fd = SAFE_OPEN(fname1, O_WRONLY); /* Save the file fid */ fanotify_save_fid(fname1, &file_fid); @@ -765,8 +784,12 @@ static void setup(void) REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH); fan_report_target_fid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MOUNT_PATH); + filesystem_mark_unsupported = + fanotify_flags_supported_on_fs(FAN_REPORT_FID, FAN_MARK_FILESYSTEM, FAN_OPEN, + MOUNT_PATH); rename_events_unsupported = - fanotify_events_supported_by_kernel(FAN_RENAME, FAN_REPORT_DFID_NAME, 0); + fanotify_flags_supported_on_fs(FAN_REPORT_DFID_NAME, 0, + FAN_RENAME, MOUNT_PATH); SAFE_MKDIR(TEMP_DIR, 0755); sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1); diff --git a/testcases/kernel/syscalls/fanotify/fanotify20.c b/testcases/kernel/syscalls/fanotify/fanotify20.c index 71310fb86..1d249ac9c 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify20.c +++ b/testcases/kernel/syscalls/fanotify/fanotify20.c @@ -50,7 +50,8 @@ static void do_setup(void) * An explicit check for FAN_REPORT_PIDFD is performed early on in the * test initialization as it's a prerequisite for all test cases. */ - REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(FAN_REPORT_PIDFD); + REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_PIDFD, + MOUNT_PATH); } static void do_test(unsigned int i) diff --git a/testcases/kernel/syscalls/fanotify/fanotify21.c b/testcases/kernel/syscalls/fanotify/fanotify21.c index 2b7202b8a..90a797fce 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify21.c +++ b/testcases/kernel/syscalls/fanotify/fanotify21.c @@ -119,7 +119,8 @@ static void do_setup(void) * on in the test initialization as it's a prerequisite for * all test cases. */ - REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(FAN_REPORT_PIDFD); + REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_PIDFD, + TEST_FILE); fanotify_fd = SAFE_FANOTIFY_INIT(FAN_REPORT_PIDFD, O_RDONLY); SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, diff --git a/testcases/kernel/syscalls/fanotify/fanotify23.c b/testcases/kernel/syscalls/fanotify/fanotify23.c index fb812c51e..5a03503e9 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify23.c +++ b/testcases/kernel/syscalls/fanotify/fanotify23.c @@ -230,7 +230,7 @@ static void setup(void) { SAFE_TOUCH(TEST_FILE, 0666, NULL); - REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(FAN_MARK_EVICTABLE); + REQUIRE_MARK_TYPE_SUPPORTED_ON_FS(FAN_MARK_EVICTABLE, "."); REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(FAN_CLASS_NOTIF|FAN_REPORT_FID, FAN_MARK_FILESYSTEM, FAN_ATTRIB, "."); diff --git a/testcases/kernel/syscalls/fchmodat/.gitignore b/testcases/kernel/syscalls/fchmodat/.gitignore index a9508bc5a..09d5c47d5 100644 --- a/testcases/kernel/syscalls/fchmodat/.gitignore +++ b/testcases/kernel/syscalls/fchmodat/.gitignore @@ -1 +1,2 @@ /fchmodat01 +/fchmodat02 diff --git a/testcases/kernel/syscalls/fchmodat/fchmodat01.c b/testcases/kernel/syscalls/fchmodat/fchmodat01.c index 3deff0ebe..bf3812738 100644 --- a/testcases/kernel/syscalls/fchmodat/fchmodat01.c +++ b/testcases/kernel/syscalls/fchmodat/fchmodat01.c @@ -1,99 +1,82 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2006 - * + * Copyright (c) Linux Test Project, 2003-2023 * 08/28/2006 AUTHOR: Yi Yang <yyangcdl@cn.ibm.com> */ /*\ * [Description] * - * This test case will verify basic function of fchmodat. + * Check the basic functionality of the fchmodat() system call. + * + * - fchmodat() passes if dir_fd is file descriptor to the directory + * where the file is located and pathname is relative path of the file. + * - fchmodat() passes if pathname is absolute, then dirfd is ignored. + * - fchmodat() passes if dir_fd is AT_FDCWD and pathname is interpreted + * relative to the current working directory of the calling process. */ -#define _GNU_SOURCE - -#include <unistd.h> -#include <string.h> #include <stdlib.h> #include <stdio.h> #include "tst_test.h" -#include "lapi/syscalls.h" -#ifndef AT_FDCWD -#define AT_FDCWD -100 -#endif +#define TESTDIR "fchmodatdir" +#define TESTFILE "fchmodatfile" +#define FILEPATH "fchmodatdir/fchmodatfile" -static char pathname[256]; -static char testfile[256]; -static char testfile2[256]; -static char testfile3[256]; +static int dir_fd, file_fd; +static int atcwd_fd = AT_FDCWD; +static char *abs_path; +static char *test_file; +static char *file_path; static struct tcase { - int exp_errno; - char *exp_errval; + int *fd; + char **filenames; + char **full_path; } tcases[] = { - { 0, NULL}, - { 0, NULL}, - { ENOTDIR, "ENOTDIR"}, - { EBADF, "EBADF"}, - { 0, NULL}, - { 0, NULL}, + {&dir_fd, &test_file, &file_path}, + {&file_fd, &abs_path, &abs_path}, + {&atcwd_fd, &file_path, &file_path}, }; -static int fds[ARRAY_SIZE(tcases)]; -static char *filenames[ARRAY_SIZE(tcases)]; static void verify_fchmodat(unsigned int i) { struct tcase *tc = &tcases[i]; + struct stat st; - if (tc->exp_errno == 0) - TST_EXP_PASS(tst_syscall(__NR_fchmodat, fds[i], filenames[i], 0600), - "fchmodat() returned the expected errno %d: %s", - TST_ERR, strerror(TST_ERR)); + TST_EXP_PASS(fchmodat(*tc->fd, *tc->filenames, 0600, 0), + "fchmodat(%d, %s, 0600, 0)", + *tc->fd, *tc->filenames); + + SAFE_LSTAT(*tc->full_path, &st); + + if ((st.st_mode & ~S_IFREG) == 0600) + tst_res(TPASS, "File permission changed correctly"); else - TST_EXP_FAIL(tst_syscall(__NR_fchmodat, fds[i], filenames[i], 0600), - tc->exp_errno, - "fchmodat() returned the expected errno %d: %s", - TST_ERR, strerror(TST_ERR)); + tst_res(TFAIL, "File permission not changed correctly"); } static void setup(void) { - /* Initialize test dir and file names */ - char *abs_path = tst_get_tmpdir(); - int p = getpid(); - - sprintf(pathname, "fchmodattestdir%d", p); - sprintf(testfile, "fchmodattest%d.txt", p); - sprintf(testfile2, "%s/fchmodattest%d.txt", abs_path, p); - sprintf(testfile3, "fchmodattestdir%d/fchmodattest%d.txt", p, p); + char *tmpdir_path = tst_get_tmpdir(); - free(abs_path); + abs_path = tst_aprintf("%s/%s", tmpdir_path, FILEPATH); + free(tmpdir_path); - SAFE_MKDIR(pathname, 0700); - - fds[0] = SAFE_OPEN(pathname, O_DIRECTORY); - fds[1] = fds[4] = fds[0]; - - SAFE_FILE_PRINTF(testfile, "%s", testfile); - SAFE_FILE_PRINTF(testfile2, "%s", testfile2); - - fds[2] = SAFE_OPEN(testfile3, O_CREAT | O_RDWR, 0600); - fds[3] = 100; - fds[5] = AT_FDCWD; - - filenames[0] = filenames[2] = filenames[3] = filenames[4] = testfile; - filenames[1] = testfile2; - filenames[5] = testfile3; + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); } static void cleanup(void) { - if (fds[0] > 0) - close(fds[0]); - if (fds[2] > 0) - close(fds[2]); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); } static struct tst_test test = { @@ -101,5 +84,10 @@ static struct tst_test test = { .test = verify_fchmodat, .setup = setup, .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&file_path, .str = FILEPATH}, + {}, + }, .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/fchmodat/fchmodat02.c b/testcases/kernel/syscalls/fchmodat/fchmodat02.c new file mode 100644 index 000000000..117865a8f --- /dev/null +++ b/testcases/kernel/syscalls/fchmodat/fchmodat02.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang <yyangcdl@cn.ibm.com> + */ + +/*\ + * [Description] + * + * Tests basic error handling of the fchmodat() syscall. + * + * - fchmodat() fails with ENOTDIR if dir_fd is file descriptor + * to the file and pathname is relative path of the file. + * - fchmodat() fails with EBADF if dir_fd is invalid. + * - fchmodat() fails with EFAULT if pathname points outside + * the accessible address space. + * - fchmodat() fails with ENAMETOOLONG if path is too long. + * - fchmodat() fails with ENOENT if pathname does not exist. + * - fchmodat() fails with EINVAL if flag is invalid. + */ + +#include <stdlib.h> +#include <stdio.h> +#include "tst_test.h" + +#define TESTFILE "fchmodatfile" + +static int file_fd; +static int bad_fd = -1; +static char path[PATH_MAX + 2]; +static char *long_path = path; +static int fd_atcwd = AT_FDCWD; +static char *bad_path; +static char *test_path; +static char *empty_path; + +static struct tcase { + int *fd; + char **filenames; + int flag; + int exp_errno; + const char *desc; +} tcases[] = { + {&file_fd, &test_path, 0, ENOTDIR, "fd pointing to file"}, + {&bad_fd, &test_path, 0, EBADF, "invalid fd"}, + {&file_fd, &bad_path, 0, EFAULT, "invalid address"}, + {&file_fd, &long_path, 0, ENAMETOOLONG, "pathname too long"}, + {&file_fd, &empty_path, 0, ENOENT, "path is empty"}, + {&fd_atcwd, &test_path, -1, EINVAL, "invalid flag"}, +}; + +static void verify_fchmodat(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_FAIL(fchmodat(*tc->fd, *tc->filenames, 0600, tc->flag), + tc->exp_errno, "fchmodat() with %s", tc->desc); +} + +static void setup(void) +{ + file_fd = SAFE_OPEN(TESTFILE, O_CREAT | O_RDWR, 0600); + + bad_path = tst_get_bad_addr(NULL); + + memset(path, 'a', PATH_MAX + 2); +} + +static void cleanup(void) +{ + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_fchmodat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&test_path, .str = TESTFILE}, + {&empty_path, .str = ""}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/fchownat/fchownat.h b/testcases/kernel/syscalls/fchownat/fchownat.h deleted file mode 100644 index 927cf929a..000000000 --- a/testcases/kernel/syscalls/fchownat/fchownat.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014 Fujitsu Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef FCHOWNAT_H -#define FCHOWNAT_H - -#include <sys/types.h> -#include "config.h" -#include "lapi/syscalls.h" - - -#if !defined(HAVE_FCHOWNAT) -static inline int fchownat(int dirfd, const char *filename, uid_t owner, - gid_t group, int flags) -{ - return tst_syscall(__NR_fchownat, dirfd, filename, owner, group, flags); -} -#endif - - -#endif /* FCHOWNAT_H */ diff --git a/testcases/kernel/syscalls/fchownat/fchownat01.c b/testcases/kernel/syscalls/fchownat/fchownat01.c index 3b29f1e75..7771c111a 100644 --- a/testcases/kernel/syscalls/fchownat/fchownat01.c +++ b/testcases/kernel/syscalls/fchownat/fchownat01.c @@ -34,7 +34,6 @@ #include "test.h" #include "safe_macros.h" -#include "fchownat.h" #include "lapi/fcntl.h" #define TESTFILE "testfile" diff --git a/testcases/kernel/syscalls/fchownat/fchownat02.c b/testcases/kernel/syscalls/fchownat/fchownat02.c index c39b0a919..6dd1e024e 100644 --- a/testcases/kernel/syscalls/fchownat/fchownat02.c +++ b/testcases/kernel/syscalls/fchownat/fchownat02.c @@ -31,7 +31,6 @@ #include <signal.h> #include "test.h" #include "safe_macros.h" -#include "fchownat.h" #include "lapi/fcntl.h" #define TESTFILE "testfile" diff --git a/testcases/kernel/syscalls/fcntl/Makefile b/testcases/kernel/syscalls/fcntl/Makefile index df663a50a..aac774111 100644 --- a/testcases/kernel/syscalls/fcntl/Makefile +++ b/testcases/kernel/syscalls/fcntl/Makefile @@ -17,6 +17,6 @@ include $(abs_srcdir)/../utils/newer_64.mk %_64: CPPFLAGS += -D_FILE_OFFSET_BITS=64 -CPPFLAGS += -D_GNU_SOURCE +CPPFLAGS += -D_GNU_SOURCE -D_LARGEFILE64_SOURCE include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/fork/.gitignore b/testcases/kernel/syscalls/fork/.gitignore index b817e9c05..acab5f768 100644 --- a/testcases/kernel/syscalls/fork/.gitignore +++ b/testcases/kernel/syscalls/fork/.gitignore @@ -2,12 +2,10 @@ /fork03 /fork04 /fork05 -/fork06 /fork07 /fork08 /fork09 /fork10 -/fork11 -/fork12 /fork13 /fork14 +/fork_procs diff --git a/testcases/kernel/syscalls/fork/fork04.c b/testcases/kernel/syscalls/fork/fork04.c index 5e5e42c4e..1a515987e 100644 --- a/testcases/kernel/syscalls/fork/fork04.c +++ b/testcases/kernel/syscalls/fork/fork04.c @@ -1,328 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2001-2023 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + *[Description] * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - * - * OS Test - Silicon Graphics, Inc. - * TEST IDENTIFIER : fork04 - * TEST TITLE : Child inheritance of Environment Variables after fork() - * PARENT DOCUMENT : frktds01 - * TEST CASE TOTAL : 3 - * WALL CLOCK TIME : 1 - * CPU TYPES : ALL - * AUTHOR : Kathy Olmsted - * CO-PILOT : Steve Shaw - * DATE STARTED : 06/17/92 - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * Test these environment variables correctly inherited by child: - * 1. TERM - * 2. NoTSetzWq - * 3. TESTPROG - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * DETAILED DESCRIPTION - * - * Setup: - * Setup signal handling. - * Make and change to a temporary directory. - * Pause for SIGUSR1 if option specified. - * Add TESTPROG variable to the environment - * - * Test: - * Loop if the proper options are given. - * fork() - * Check return code, if system call failed (return=-1) - * Log the errno - * CHILD: - * open a temp file - * Determine environment values and write to file - * close file containing test values. - * exit. - * PARENT: - * Wait for child to exit. - * Verify exit status - * Open file containing test values. - * For each test case: - * Read the value from the file. - * Determine and report PASS/FAIL result. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * Remove the temporary directory and exit. + * This test verifies that parent process shares environ variables with the + * child and that child doesn't change parent's environ variables. */ #include <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <sys/param.h> -#include <signal.h> -#include <errno.h> -#include "test.h" -#include "safe_macros.h" - -char *TCID = "fork04"; - -#define KIDEXIT 42 -#define MAX_LINE_LENGTH 256 -#define OUTPUT_FILE "env.out" -#define ENV_NOT_SET "getenv() does not find variable set" +#include "tst_test.h" -/* list of environment variables to test */ -char *environ_list[] = { "TERM", "NoTSetzWq", "TESTPROG" }; +#define ENV_KEY "LTP_FORK04" +#define ENV_VAL0 "PASS" +#define ENV_VAL1 "FAIL" -#define NUMBER_OF_ENVIRON (sizeof(environ_list)/sizeof(char *)) -int TST_TOTAL = NUMBER_OF_ENVIRON; - -static void cleanup(void) +static void run_child(void) { - tst_rmdir(); -} + const char *val; -static void setup(void) -{ + val = getenv(ENV_KEY); + if (!val) + tst_brk(TBROK, "Can't find %s environ variable", ENV_KEY); - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; - tst_tmpdir(); + TST_EXP_EXPR(strcmp(ENV_VAL0, val) == 0, + "%s environ variable has been inherited by the child", + ENV_KEY) - /* add a variable to the environment */ - putenv("TESTPROG=FRKTCS04"); -} + tst_res(TINFO, "Unset %s environ variable inside child", ENV_KEY); -static void child_environment(void) -{ - - int fildes; - int index; - char msg[MAX_LINE_LENGTH]; - char *var; + if (unsetenv(ENV_KEY) == -1) + tst_brk(TBROK, "Can't unset %s environ variable", ENV_KEY); - fildes = creat(OUTPUT_FILE, 0700); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - for (index = 0; index < (int)NUMBER_OF_ENVIRON; index++) { - memset(msg, 0, MAX_LINE_LENGTH); + tst_res(TINFO, "Set %s=%s environ variable inside child", ENV_KEY, ENV_VAL1); - var = getenv(environ_list[index]); - if (var == NULL) - (void)sprintf(msg, "%s:%s", environ_list[index], - ENV_NOT_SET); - else - (void)sprintf(msg, "%s:%s", environ_list[index], var); - /* includes extra null chars */ - write(fildes, msg, sizeof(msg)); - } + SAFE_SETENV(ENV_KEY, ENV_VAL1, 0); - close(fildes); + TST_CHECKPOINT_WAKE(0); } -/* - * Compare parent env string to child's string. - * Each string is in the format: <env var>:<value> - */ -static int cmp_env_strings(char *pstring, char *cstring) +static void run(void) { - char *penv, *cenv, *pvalue, *cvalue; + const char *val; - /* - * Break pstring into env and value - */ - penv = pstring; - pvalue = strchr(pstring, ':'); - if (pvalue == NULL) { - tst_resm(TBROK, - "internal error - parent's env string not in correct format:'%s'", - pstring); - return -1; - } else { - *pvalue = '\0'; - pvalue++; - if (*pvalue == '\0') { - tst_resm(TBROK, - "internal error - missing parent's env value"); - return -1; - } - } + tst_res(TINFO, + "Set %s=%s environ variable inside parent", + ENV_KEY, ENV_VAL0); - /* - * Break cstring into env and value - */ - cenv = cstring; - cvalue = strchr(cstring, ':'); - if (cvalue == NULL) { - tst_resm(TBROK, - "internal error - parent's env string not in correct format:'%s'", - cstring); - return -1; - } else { - *cvalue = '\0'; - cvalue++; - if (*cvalue == '\0') { - tst_resm(TBROK, - "internal error - missing child's env value"); - return -1; - } - } + SAFE_SETENV(ENV_KEY, ENV_VAL0, 0); - if (strcmp(penv, cenv) != 0) { - tst_resm(TBROK, "internal error - parent(%s) != child (%s) env", - penv, cenv); - return -1; - } + tst_res(TINFO, "Spawning child"); - if (strcmp(pvalue, cvalue) != 0) { - tst_resm(TFAIL, - "Env var %s changed after fork(), parent's %s, child's %s", - penv, pvalue, cvalue); - } else { - tst_resm(TPASS, "Env var %s unchanged after fork(): %s", - penv, cvalue); + if (!SAFE_FORK()) { + run_child(); + exit(0); } - return 0; - -} - -/*************************************************************** - * parent_environment - the parent side of the environment tests - * determine values for the variables - * read the values determined by the child - * compare values - ***************************************************************/ -void parent_environment(void) -{ - - int fildes; - char tmp_line[MAX_LINE_LENGTH]; - char parent_value[MAX_LINE_LENGTH]; - unsigned int index; - int ret; - char *var; - - fildes = SAFE_OPEN(cleanup, OUTPUT_FILE, O_RDWR); - for (index = 0; index < NUMBER_OF_ENVIRON; index++) { - ret = read(fildes, tmp_line, MAX_LINE_LENGTH); - if (ret == 0) { - tst_resm(TBROK, - "fork() test. parent_environment: failed to read from file with %d (%s)", - errno, strerror(errno)); - } else { - var = getenv(environ_list[index]); - if (var == NULL) - sprintf(parent_value, "%s:%s", - environ_list[index], ENV_NOT_SET); - else - sprintf(parent_value, "%s:%s", - environ_list[index], var); + TST_CHECKPOINT_WAIT(0); - cmp_env_strings(parent_value, tmp_line); - - } + val = getenv(ENV_KEY); + if (!val) { + tst_res(TFAIL, + "%s environ variable has been unset inside parent", + ENV_KEY); + } else { + TST_EXP_EXPR(strcmp(ENV_VAL0, val) == 0, + "%s environ variable is still present inside parent", + ENV_KEY) } - close(fildes); -} - -int main(int ac, char **av) -{ - int lc; - int kid_status; - int wait_status; - int fails; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - fails = 0; - - TEST(fork()); - - if (TEST_RETURN == -1) { - /* fork failed */ - tst_brkm(TFAIL, cleanup, - "fork() failed with %d (%s)", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else if (TEST_RETURN == 0) { - /* child */ - /* determine environment variables */ - child_environment(); - /* exit with known value */ - exit(KIDEXIT); - } else { - /* parent of successful fork */ - /* wait for the child to complete */ - wait_status = waitpid(TEST_RETURN, &kid_status, 0); - /* validate the child exit status */ - if (wait_status == TEST_RETURN) { - if (kid_status != KIDEXIT << 8) { - tst_brkm(TBROK, cleanup, - "fork(): Incorrect child status returned on wait(): %d", - kid_status); - fails++; - } - } else { - tst_brkm(TBROK, cleanup, - "fork(): wait() for child status failed with %d errno: %d : %s", - wait_status, errno, - strerror(errno)); - fails++; - } - - if (fails == 0) { - /* verification tests */ - parent_environment(); - } - } - + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + val = getenv(ENV_KEY); + if (!val) + tst_res(TFAIL, + "%s environ variable has been unset inside parent", + ENV_KEY); + else { + TST_EXP_EXPR(strcmp(ENV_VAL0, val) == 0, + "%s environ variable didn't change inside parent", + ENV_KEY) } - - cleanup(); - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/fork/fork06.c b/testcases/kernel/syscalls/fork/fork06.c deleted file mode 100644 index 3bc11b14b..000000000 --- a/testcases/kernel/syscalls/fork/fork06.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * NAME - * fork06.c - * - * DESCRIPTION - * Test that a process can fork children a large number of - * times in succession - * - * ALGORITHM - * Attempt to fork a child that exits immediately - * Repeat it many times(1000), counting the number of successes and - * failures - * - * USAGE - * fork06 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None - */ - -#include <sys/types.h> -#include <sys/wait.h> -#include <stdio.h> -#include "test.h" - -char *TCID = "fork06"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); - -#define NUMFORKS 1000 - -int main(int ac, char **av) -{ - int i, pid, status, childpid, succeed, fail; - - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - succeed = 0; - fail = 0; - - for (i = 0; i < NUMFORKS; i++) { - pid = fork(); - if (pid == -1) { - fail++; - continue; - } - - if (pid == 0) - _exit(0); - - childpid = wait(&status); - if (pid != childpid) - tst_resm(TFAIL, "pid from wait %d", childpid); - succeed++; - } - - tst_resm(TINFO, "tries %d", i); - tst_resm(TINFO, "successes %d", succeed); - tst_resm(TINFO, "failures %d", fail); - - if ((wait(&status)) == -1) - tst_resm(TINFO, "There were no children to wait for"); - else - tst_resm(TINFO, "There were children left"); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; -} - -static void cleanup(void) -{ -} diff --git a/testcases/kernel/syscalls/fork/fork10.c b/testcases/kernel/syscalls/fork/fork10.c index 815eee1f6..790e7b386 100644 --- a/testcases/kernel/syscalls/fork/fork10.c +++ b/testcases/kernel/syscalls/fork/fork10.c @@ -1,159 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * - * NAME - * fork10.c - * - * DESCRIPTION - * Check inheritance of file descriptor by children, they - * should all be refering to the same file. + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] * - * ALGORITHM - * Child reads several chars and exits. - * Parent forks another child, have the child and parent attempt to use - * that location + * This test verifies inheritance of file descriptors from parent to child + * process. We open a file from parent, then we check if file offset changes + * accordingly with file descriptor usage. * - * USAGE - * fork10 + * [Algorithm] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Test steps are the following: + * - create a file made in three parts -> | aa..a | bb..b | cc..c | + * - from parent, open the file + * - from child, move file offset after the first part + * - from parent, read second part and check if it's | bb..b | + * - from child, read third part and check if it's | cc..c | * - * RESTRICTIONS - * None + * Test passes if we were able to read the correct file parts from parent and + * child. */ -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdio.h> -#include <errno.h> -#include "test.h" -#include "safe_macros.h" - -char *TCID = "fork10"; -int TST_TOTAL = 1; +#include <stdlib.h> +#include "tst_test.h" -static void setup(void); -static void cleanup(void); +#define FILENAME "file.txt" +#define DATASIZE 1024 -static char pidbuf[10]; -static char fnamebuf[40]; +static int fd = -1; -int main(int ac, char **av) +static void run(void) { - int status, pid, fildes; - char parchar[2]; - char chilchar[2]; - - int lc; - - fildes = -1; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - fildes = SAFE_CREAT(cleanup, fnamebuf, 0600); - write(fildes, "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 27); - close(fildes); - - fildes = SAFE_OPEN(cleanup, fnamebuf, 0); - - pid = fork(); - if (pid == -1) - tst_brkm(TBROK, cleanup, "fork() #1 failed"); - - if (pid == 0) { /* child */ - tst_resm(TINFO, "fork child A"); - if (lseek(fildes, 10L, 0) == -1L) { - tst_resm(TFAIL, "bad lseek by child"); - exit(1); - } - exit(0); - } else { /* parent */ - wait(&status); - - /* parent starts second child */ - pid = fork(); - if (pid == -1) - tst_brkm(TBROK, cleanup, "fork() #2 failed"); - - if (pid == 0) { /* child */ - if (read(fildes, chilchar, 1) <= 0) { - tst_resm(TFAIL, "Child can't read " - "file"); - exit(1); - } else { - if (chilchar[0] != 'K') { - chilchar[1] = '\n'; - exit(1); - } else { - exit(0); - } - } - } else { /* parent */ - (void)wait(&status); - if (status >> 8 != 0) { - tst_resm(TFAIL, "Bad return from " - "second child"); - continue; - } - /* parent reads */ - if (read(fildes, parchar, 1) <= 0) { - tst_resm(TFAIL, "Parent cannot read " - "file"); - continue; - } else { - write(fildes, parchar, 1); - if (parchar[0] != 'L') { - parchar[1] = '\n'; - tst_resm(TFAIL, "Test failed"); - continue; - } - } - } - } - tst_resm(TPASS, "test 1 PASSED"); + int status; + char buff[DATASIZE]; + char data[DATASIZE]; + + fd = SAFE_OPEN(FILENAME, 0); + + if (!SAFE_FORK()) { + SAFE_LSEEK(fd, DATASIZE, SEEK_SET); + exit(0); + } + + SAFE_WAIT(&status); + + memset(buff, 'b', DATASIZE); + SAFE_READ(1, fd, data, DATASIZE); + + TST_EXP_EXPR(strncmp(buff, data, DATASIZE) == 0, + "read first part of data from parent process"); + + if (!SAFE_FORK()) { + memset(buff, 'c', DATASIZE); + SAFE_READ(1, fd, data, DATASIZE); + + TST_EXP_EXPR(strncmp(buff, data, DATASIZE) == 0, + "read second part of data from child process"); + + exit(0); } - close(fildes); - cleanup(); - tst_exit(); + SAFE_CLOSE(fd); } static void setup(void) { - tst_sig(FORK, DEF_HANDLER, cleanup); - umask(0); - TEST_PAUSE; - tst_tmpdir(); - - strcpy(fnamebuf, "fork10."); - sprintf(pidbuf, "%d", getpid()); - strcat(fnamebuf, pidbuf); + char buff[DATASIZE]; + + fd = SAFE_CREAT(FILENAME, 0600); + + memset(buff, 'a', DATASIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buff, DATASIZE); + + memset(buff, 'b', DATASIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buff, DATASIZE); + + memset(buff, 'c', DATASIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buff, DATASIZE); + + SAFE_CLOSE(fd); } static void cleanup(void) { - tst_rmdir(); + if (fd >= 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .forks_child = 1, + .needs_tmpdir = 1, + .test_all = run, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/fork/fork11.c b/testcases/kernel/syscalls/fork/fork11.c deleted file mode 100644 index 6afda3a33..000000000 --- a/testcases/kernel/syscalls/fork/fork11.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * - * NAME - * fork11.c - * - * DESCRIPTION - * Test that parent gets a pid from each child when doing wait - * - * ALGORITHM - * Fork NUMFORKS children that do nothing. - * - * USAGE - * fork11 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None - */ - -#include <sys/types.h> -#include <sys/wait.h> -#include <stdio.h> -#include <errno.h> -#include "test.h" - -char *TCID = "fork11"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); - -#define NUMFORKS 100 - -int main(int ac, char **av) -{ - int i, pid, cpid, status; - int fail = 0; - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < NUMFORKS; i++) { - pid = fork(); - if (pid == 0) - exit(0); - - if (pid > 0) { /* parent */ - cpid = wait(&status); - if (cpid != pid) - fail++; - } else { - fail++; - break; - } - } - if (fail) - tst_resm(TFAIL, "fork failed %d times", fail); - else - tst_resm(TPASS, "fork test passed, %d processes", i); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; -} - -static void cleanup(void) -{ -} diff --git a/testcases/kernel/syscalls/fork/fork12.c b/testcases/kernel/syscalls/fork/fork12.c deleted file mode 100644 index 1c55c0c30..000000000 --- a/testcases/kernel/syscalls/fork/fork12.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * - * NAME - * fork12.c - * - * DESCRIPTION - * Check that all children inherit parent's file descriptor - * - * ALGORITHM - * Parent forks processes until -1 is returned.$ - * - * USAGE - * fork12 - * ** CAUTION ** Can hang your machine, esp prior to 2.4.19 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * 07/2002 Split from fork07 as a test case to exhaust available pids. - * - * RESTRICTIONS - * Should be run as root to avoid resource limits.$ - * Should not be run with other test programs because it tries to - * use all available pids. - */ - -#include <stdio.h> -#include <sys/wait.h> -#include <errno.h> -#include <string.h> -#include "test.h" -#include "safe_macros.h" - -char *TCID = "fork12"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); -static void fork12_sigs(int signum); - -int main(int ac, char **av) -{ - int forks, pid1, fork_errno, waitstatus; - int ret, status; - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - tst_resm(TINFO, "Forking as many kids as possible"); - forks = 0; - while ((pid1 = fork()) != -1) { - if (pid1 == 0) { /* child */ - /* - * Taunt the OOM killer so that it doesn't - * kill system processes - */ - SAFE_FILE_PRINTF(NULL, - "/proc/self/oom_score_adj", "500"); - pause(); - exit(0); - } - forks++; - ret = SAFE_WAITPID(cleanup, -1, &status, WNOHANG); - if (ret > 0) { - /* a child may be killed by OOM killer */ - if (WTERMSIG(status) == SIGKILL) - break; - tst_brkm(TBROK, cleanup, - "child exit with error code %d or signal %d", - WEXITSTATUS(status), WTERMSIG(status)); - } - } - fork_errno = errno; - - /* parent */ - tst_resm(TINFO, "Number of processes forked is %d", forks); - tst_resm(TPASS, "fork() eventually failed with %d: %s", - fork_errno, strerror(fork_errno)); - /* collect our kids */ - /* - * Introducing a sleep(3) to make sure all children are - * at pause() when SIGQUIT is sent to them - */ - sleep(3); - kill(0, SIGQUIT); - while (wait(&waitstatus) > 0) ; - - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(FORK, fork12_sigs, cleanup); - TEST_PAUSE; -} - -static void cleanup(void) -{ - int waitstatus; - - /* collect our kids */ - kill(0, SIGQUIT); - while (wait(&waitstatus) > 0) ; -} - -static void fork12_sigs(int signum) -{ - if (signum == SIGQUIT) { - /* Children will continue, parent will ignore */ - } else { - tst_brkm(TBROK, cleanup, - "Unexpected signal %d received.", signum); - } -} diff --git a/testcases/kernel/syscalls/fork/fork_procs.c b/testcases/kernel/syscalls/fork/fork_procs.c new file mode 100644 index 000000000..c35bb480c --- /dev/null +++ b/testcases/kernel/syscalls/fork/fork_procs.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + *[Description] + * + * This test spawns multiple processes using fork() and it checks if wait() + * returns the right PID once they end up. + */ + +#include <stdlib.h> +#include "tst_test.h" + +static char *str_numforks; +static int numforks = 1000; + +static void run(void) +{ + pid_t pid; + int status; + int counter = 0; + + tst_res(TINFO, "Forking %d processes", numforks); + + for (int i = 0; i < numforks; i++) { + pid = SAFE_FORK(); + if (!pid) + exit(0); + + if (SAFE_WAIT(&status) == pid) + counter++; + } + + TST_EXP_EXPR(numforks == counter, + "%d processes ended successfully", + counter); +} + +static void setup(void) +{ + if (tst_parse_int(str_numforks, &numforks, 1, INT_MAX)) + tst_brk(TBROK, "wrong number of forks '%s'", str_numforks); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .forks_child = 1, + .options = (struct tst_option[]) { + { "n:", &str_numforks, "Number of processes to spawn" }, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c b/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c index d799e477f..b65b27bdf 100644 --- a/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c +++ b/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c @@ -140,7 +140,7 @@ static void verify_fsetxattr(unsigned int i) { /* some tests might require existing keys for each iteration */ if (tc[i].keyneeded) { - SAFE_FSETXATTR(fd, tc[i].key, tc[i].value, tc[i].size, + SAFE_FSETXATTR(fd, tc[i].key, *tc[i].value, tc[i].size, XATTR_CREATE); } diff --git a/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c b/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c index 0336c964a..39265af36 100644 --- a/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c +++ b/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c @@ -1,27 +1,33 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2018 Linaro Limited. All rights reserved. + * Copyright (c) Linux Test Project, 2018-2023 * Author: Rafael David Tinoco <rafael.tinoco@linaro.org> */ +/*\ + * [Description] + * + * Verify basic fsetxattr(2) syscall functionality: + * + * - Set attribute to a regular file, fsetxattr(2) should succeed. + * - Set attribute to a directory, fsetxattr(2) should succeed. + * - Set attribute to a symlink which points to the regular file, + * fsetxattr(2) should return -1 and set errno to EEXIST. + * - Set attribute to a FIFO, fsetxattr(2) should return -1 and set + * errno to EPERM. + * - Set attribute to a char special file, fsetxattr(2) should + * return -1 and set errno to EPERM. + * - Set attribute to a block special file, fsetxattr(2) should + * return -1 and set errno to EPERM. + * - Set attribute to a UNIX domain socket, fsetxattr(2) should + * return -1 and set errno to EPERM. + */ + /* * In the user.* namespace, only regular files and directories can * have extended attributes. Otherwise fsetxattr(2) will return -1 * and set errno to EPERM. - * - * There are 7 test cases: - * 1. Set attribute to a regular file, fsetxattr(2) should succeed - * 2. Set attribute to a directory, fsetxattr(2) should succeed - * 3. Set attribute to a symlink which points to the regular file, - * fsetxattr(2) should return -1 and set errno to EEXIST - * 4. Set attribute to a FIFO, fsetxattr(2) should return -1 and set - * errno to EPERM - * 5. Set attribute to a char special file, fsetxattr(2) should - * return -1 and set errno to EPERM - * 6. Set attribute to a block special file, fsetxattr(2) should - * return -1 and set errno to EPERM - * 7. Set attribute to a UNIX domain socket, fsetxattr(2) should - * return -1 and set errno to EPERM */ #include "config.h" diff --git a/testcases/kernel/syscalls/getcwd/getcwd01.c b/testcases/kernel/syscalls/getcwd/getcwd01.c index 65d827873..218bf4ef2 100644 --- a/testcases/kernel/syscalls/getcwd/getcwd01.c +++ b/testcases/kernel/syscalls/getcwd/getcwd01.c @@ -14,17 +14,17 @@ * * Expected Result: * 1) getcwd(2) should return NULL and set errno to EFAULT. - * 2) getcwd(2) should return NULL and set errno to ENOMEM. - * 3) getcwd(2) should return NULL and set errno to EINVAL. + * 2) getcwd(2) should return NULL and set errno to EFAULT. + * 3) getcwd(2) should return NULL and set errno to ERANGE. * 4) getcwd(2) should return NULL and set errno to ERANGE. * 5) getcwd(2) should return NULL and set errno to ERANGE. - * */ #include <errno.h> #include <unistd.h> #include <limits.h> #include "tst_test.h" +#include "lapi/syscalls.h" static char buffer[5]; @@ -34,32 +34,18 @@ static struct t_case { int exp_err; } tcases[] = { {(void *)-1, PATH_MAX, EFAULT}, - {NULL, (size_t)-1, ENOMEM}, - {buffer, 0, EINVAL}, + {NULL, (size_t)-1, EFAULT}, + {buffer, 0, ERANGE}, {buffer, 1, ERANGE}, {NULL, 1, ERANGE} }; + static void verify_getcwd(unsigned int n) { struct t_case *tc = &tcases[n]; - char *res; - - errno = 0; - res = getcwd(tc->buf, tc->size); - TST_ERR = errno; - if (res) { - tst_res(TFAIL, "getcwd() succeeded unexpectedly"); - return; - } - - if (TST_ERR != tc->exp_err) { - tst_res(TFAIL | TTERRNO, "getcwd() failed unexpectedly, expected %s", - tst_strerrno(tc->exp_err)); - return; - } - tst_res(TPASS | TTERRNO, "getcwd() failed as expected"); + TST_EXP_FAIL2(tst_syscall(__NR_getcwd, tc->buf, tc->size), tc->exp_err); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/getcwd/getcwd02.c b/testcases/kernel/syscalls/getcwd/getcwd02.c index cb111a698..e3df22ceb 100644 --- a/testcases/kernel/syscalls/getcwd/getcwd02.c +++ b/testcases/kernel/syscalls/getcwd/getcwd02.c @@ -3,12 +3,14 @@ * Copyright (c) International Business Machines Corp., 2001 */ -/* - * DESCRIPTION +/*\ + * [Description] + * * Testcase to check the basic functionality of the getcwd(2) system call. - * 1) getcwd(2) works fine if buf and size are valid. - * 2) getcwd(2) works fine if buf points to NULL and size is set to 0. - * 3) getcwd(2) works fine if buf points to NULL and size is greater than strlen(path). + * + * 1. getcwd(2) works fine if buf and size are valid. + * 2. getcwd(2) works fine if buf points to NULL and size is set to 0. + * 3. getcwd(2) works fine if buf points to NULL and size is greater than strlen(path). */ #include <errno.h> diff --git a/testcases/kernel/syscalls/getcwd/getcwd03.c b/testcases/kernel/syscalls/getcwd/getcwd03.c index 97f4f3a33..9e3828a93 100644 --- a/testcases/kernel/syscalls/getcwd/getcwd03.c +++ b/testcases/kernel/syscalls/getcwd/getcwd03.c @@ -3,18 +3,20 @@ * Copyright (c) International Business Machines Corp., 2001 */ -/* - * DESCRIPTION +/*\ + * [Description] + * * Testcase to check the basic functionality of the getcwd(2) * system call on a symbolic link. * - * ALGORITHM - * 1) create a directory, and create a symbolic link to it at the + * [Algorithm] + * + * 1. create a directory, and create a symbolic link to it at the * same directory level. - * 2) get the working directory of a directory, and its pathname. - * 3) get the working directory of a symbolic link, and its pathname, + * 2. get the working directory of a directory, and its pathname. + * 3. get the working directory of a symbolic link, and its pathname, * and its readlink info. - * 4) compare the working directories and link information. + * 4. compare the working directories and link information. */ #define _GNU_SOURCE 1 diff --git a/testcases/kernel/syscalls/getdtablesize/.gitignore b/testcases/kernel/syscalls/getdtablesize/.gitignore deleted file mode 100644 index 67a71b5e2..000000000 --- a/testcases/kernel/syscalls/getdtablesize/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/getdtablesize01 diff --git a/testcases/kernel/syscalls/getdtablesize/getdtablesize01.c b/testcases/kernel/syscalls/getdtablesize/getdtablesize01.c deleted file mode 100644 index d25cac261..000000000 --- a/testcases/kernel/syscalls/getdtablesize/getdtablesize01.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2005 - * Copyright (c) Wipro Technologies Ltd, 2005. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ -/********************************************************** - * - * TEST IDENTIFIER : getdtablesize01 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Basic tests for getdtablesize01(2) - * - * TEST CASE TOTAL : 1 - * - * AUTHOR : Prashant P Yendigeri - * <prashant.yendigeri@wipro.com> - * Robbie Williamson - * <robbiew@us.ibm.com> - * - * DESCRIPTION - * This is a Phase I test for the getdtablesize01(2) system call. - * It is intended to provide a limited exposure of the system call. - * - **********************************************************/ - -#include <stdio.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/time.h> -#include <sys/resource.h> -#include <unistd.h> -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "getdtablesize01"; -int TST_TOTAL = 1; - -int main(void) -{ - int table_size, fd = 0, count = 0; - int max_val_opfiles; - struct rlimit rlp; - - setup(); - table_size = getdtablesize(); - getrlimit(RLIMIT_NOFILE, &rlp); - max_val_opfiles = (rlim_t) rlp.rlim_cur; - - tst_resm(TINFO, - "Maximum number of files a process can have opened is %d", - table_size); - tst_resm(TINFO, - "Checking with the value returned by getrlimit...RLIMIT_NOFILE"); - - if (table_size == max_val_opfiles) - tst_resm(TPASS, "got correct dtablesize, value is %d", - max_val_opfiles); - else { - tst_resm(TFAIL, "got incorrect table size, value is %d", - max_val_opfiles); - cleanup(); - } - - tst_resm(TINFO, - "Checking Max num of files that can be opened by a process.Should be: RLIMIT_NOFILE - 1"); - for (;;) { - fd = open("/etc/hosts", O_RDONLY); - - if (fd == -1) - break; - count = fd; - -#ifdef DEBUG - printf("Opened file num %d\n", fd); -#endif - } - -//Now the max files opened should be RLIMIT_NOFILE - 1 , why ? read getdtablesize man page - - if (count > 0) - close(count); - if (count == (max_val_opfiles - 1)) - tst_resm(TPASS, "%d = %d", count, (max_val_opfiles - 1)); - else if (fd < 0 && errno == ENFILE) - tst_brkm(TCONF, cleanup, "Reached maximum number of open files for the system"); - else - tst_resm(TFAIL, "%d != %d", count, (max_val_opfiles - 1)); - - cleanup(); - tst_exit(); -} - -void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -void cleanup(void) -{ -} diff --git a/testcases/kernel/syscalls/getegid/getegid01.c b/testcases/kernel/syscalls/getegid/getegid01.c index 271fbb6b6..46cdc680b 100644 --- a/testcases/kernel/syscalls/getegid/getegid01.c +++ b/testcases/kernel/syscalls/getegid/getegid01.c @@ -1,87 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * William Roske, Dave Fenner + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner +/*\ + * [Description] + * + * This test checks if getegid() returns the effective group id. */ -#include <sys/types.h> -#include <errno.h> -#include <string.h> -#include <signal.h> - -#include "test.h" -#include "compat_16.h" - -static void setup(); -static void cleanup(); +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(getegid01); -int TST_TOTAL = 1; - -int main(int ac, char **av) +static void run(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(GETEGID(cleanup)); + gid_t gid, st_egid; - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "getegid failed"); - continue; /* next loop for MTKERNEL */ - } + SAFE_FILE_LINES_SCANF("/proc/self/status", "Gid: %*d %d", &st_egid); + gid = getegid(); - tst_resm(TPASS, "getegid returned %ld", TEST_RETURN); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + if (GID_SIZE_CHECK(st_egid)) + TST_EXP_EQ_LI(gid, st_egid); + else + tst_res(TPASS, "getegid() passed"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/getegid/getegid02.c b/testcases/kernel/syscalls/getegid/getegid02.c index 60f09501e..2f64bd869 100644 --- a/testcases/kernel/syscalls/getegid/getegid02.c +++ b/testcases/kernel/syscalls/getegid/getegid02.c @@ -1,90 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 - * Ported by Wayne Boyer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * William Roske, Dave Fenner + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * Testcase to check the basic functionality of getegid(). +/*\ + * [Description] * - * For functionality test the return value from getegid() is compared to passwd - * entry. + * This test checks if getegid() returns the same effective group given by + * passwd entry via getpwuid(). */ #include <pwd.h> -#include <errno.h> - -#include "test.h" -#include "compat_16.h" -static void cleanup(void); -static void setup(void); +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(getegid02); -int TST_TOTAL = 1; - -int main(int ac, char **av) +static void run(void) { - int lc; uid_t euid; + gid_t egid; struct passwd *pwent; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(GETEGID(cleanup)); + UID16_CHECK((euid = geteuid()), "geteuid"); - if (TEST_RETURN < 0) { - tst_brkm(TBROK, cleanup, "This should never happen"); - } + pwent = getpwuid(euid); + if (!pwent) + tst_brk(TBROK | TERRNO, "getpwuid() error"); - euid = geteuid(); - pwent = getpwuid(euid); + GID16_CHECK((egid = getegid()), "getegid"); - if (pwent == NULL) - tst_brkm(TBROK, cleanup, "geteuid() returned " - "unexpected value %d", euid); - - GID16_CHECK(pwent->pw_gid, getegid, cleanup); - - if (pwent->pw_gid != TEST_RETURN) { - tst_resm(TFAIL, "getegid() return value" - " %ld unexpected - expected %d", - TEST_RETURN, pwent->pw_gid); - } else { - tst_resm(TPASS, - "effective group id %ld " - "is correct", TEST_RETURN); - } - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_EQ_LI(pwent->pw_gid, egid); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/getgroups/Makefile b/testcases/kernel/syscalls/getgroups/Makefile index b2bb1e005..a319acf85 100644 --- a/testcases/kernel/syscalls/getgroups/Makefile +++ b/testcases/kernel/syscalls/getgroups/Makefile @@ -3,6 +3,9 @@ top_srcdir ?= ../../../.. +# Remove after rewriting all tests to the new API. +USE_LEGACY_COMPAT_16_H := 1 + include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../utils/compat_16.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/getgroups/getgroups01.c b/testcases/kernel/syscalls/getgroups/getgroups01.c index cfddeb408..c253e487f 100644 --- a/testcases/kernel/syscalls/getgroups/getgroups01.c +++ b/testcases/kernel/syscalls/getgroups/getgroups01.c @@ -54,6 +54,11 @@ #include <sys/types.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" static void setup(void); diff --git a/testcases/kernel/syscalls/getgroups/getgroups03.c b/testcases/kernel/syscalls/getgroups/getgroups03.c index 5ba20ef82..fc94f0b8e 100644 --- a/testcases/kernel/syscalls/getgroups/getgroups03.c +++ b/testcases/kernel/syscalls/getgroups/getgroups03.c @@ -40,6 +40,11 @@ #include <pwd.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" #define TESTUSER "root" diff --git a/testcases/kernel/syscalls/getpid/getpid01.c b/testcases/kernel/syscalls/getpid/getpid01.c index ec18b67d5..495002037 100644 --- a/testcases/kernel/syscalls/getpid/getpid01.c +++ b/testcases/kernel/syscalls/getpid/getpid01.c @@ -6,26 +6,31 @@ /*\ * [Description] * - * Verify that getpid() system call returns process ID in range 2 ... PID_MAX + * Verify that getpid() system call returns process ID in range <2, PID_MAX>. */ #include <stdlib.h> #include "tst_test.h" +static pid_t pid_max; + +static void setup(void) +{ + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max); +} + static void verify_getpid(void) { - pid_t pid_max, pid; + pid_t pid; int i; - SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max); - for (i = 0; i < 100; i++) { pid = SAFE_FORK(); if (pid == 0) { pid = getpid(); /* pid should not be 1 or out of maximum */ - if (1 < pid && pid <= pid_max) + if (pid > 1 && pid <= pid_max) tst_res(TPASS, "getpid() returns %d", pid); else tst_res(TFAIL, @@ -38,6 +43,7 @@ static void verify_getpid(void) } static struct tst_test test = { + .setup = setup, .forks_child = 1, .test_all = verify_getpid, }; diff --git a/testcases/kernel/syscalls/getppid/getppid01.c b/testcases/kernel/syscalls/getppid/getppid01.c index f37948dd4..57efe1c1f 100644 --- a/testcases/kernel/syscalls/getppid/getppid01.c +++ b/testcases/kernel/syscalls/getppid/getppid01.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2006-2023 */ /*\ @@ -12,11 +13,16 @@ #include <errno.h> #include "tst_test.h" -static void verify_getppid(void) -{ - pid_t ppid, pid_max; +static pid_t pid_max; +static void setup(void) +{ SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max); +} + +static void verify_getppid(void) +{ + pid_t ppid; ppid = getppid(); if (ppid > pid_max) @@ -26,5 +32,6 @@ static void verify_getppid(void) } static struct tst_test test = { + .setup = setup, .test_all = verify_getppid, }; diff --git a/testcases/kernel/syscalls/getresgid/Makefile b/testcases/kernel/syscalls/getresgid/Makefile index b2bb1e005..a319acf85 100644 --- a/testcases/kernel/syscalls/getresgid/Makefile +++ b/testcases/kernel/syscalls/getresgid/Makefile @@ -3,6 +3,9 @@ top_srcdir ?= ../../../.. +# Remove after rewriting all tests to the new API. +USE_LEGACY_COMPAT_16_H := 1 + include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../utils/compat_16.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/getresgid/getresgid01.c b/testcases/kernel/syscalls/getresgid/getresgid01.c index b5fb804ee..8000200e1 100644 --- a/testcases/kernel/syscalls/getresgid/getresgid01.c +++ b/testcases/kernel/syscalls/getresgid/getresgid01.c @@ -73,6 +73,11 @@ #include <signal.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" char *TCID = "getresgid01"; diff --git a/testcases/kernel/syscalls/getresgid/getresgid02.c b/testcases/kernel/syscalls/getresgid/getresgid02.c index 8bddf9824..ca4502aac 100644 --- a/testcases/kernel/syscalls/getresgid/getresgid02.c +++ b/testcases/kernel/syscalls/getresgid/getresgid02.c @@ -75,6 +75,11 @@ #include <pwd.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" #define LTPUSER "nobody" diff --git a/testcases/kernel/syscalls/getresgid/getresgid03.c b/testcases/kernel/syscalls/getresgid/getresgid03.c index 0785359e0..1d7bcabd2 100644 --- a/testcases/kernel/syscalls/getresgid/getresgid03.c +++ b/testcases/kernel/syscalls/getresgid/getresgid03.c @@ -77,6 +77,11 @@ #include <pwd.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" char *TCID = "getresgid03"; diff --git a/testcases/kernel/syscalls/getresuid/Makefile b/testcases/kernel/syscalls/getresuid/Makefile index b2bb1e005..a319acf85 100644 --- a/testcases/kernel/syscalls/getresuid/Makefile +++ b/testcases/kernel/syscalls/getresuid/Makefile @@ -3,6 +3,9 @@ top_srcdir ?= ../../../.. +# Remove after rewriting all tests to the new API. +USE_LEGACY_COMPAT_16_H := 1 + include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../utils/compat_16.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/getresuid/getresuid01.c b/testcases/kernel/syscalls/getresuid/getresuid01.c index 07fed9c13..a04918d6f 100644 --- a/testcases/kernel/syscalls/getresuid/getresuid01.c +++ b/testcases/kernel/syscalls/getresuid/getresuid01.c @@ -72,6 +72,11 @@ #include <signal.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" char *TCID = "getresuid01"; diff --git a/testcases/kernel/syscalls/getresuid/getresuid02.c b/testcases/kernel/syscalls/getresuid/getresuid02.c index 23f7944dd..77896a8a3 100644 --- a/testcases/kernel/syscalls/getresuid/getresuid02.c +++ b/testcases/kernel/syscalls/getresuid/getresuid02.c @@ -75,6 +75,11 @@ #include <pwd.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" #define LTPUSER "nobody" diff --git a/testcases/kernel/syscalls/getresuid/getresuid03.c b/testcases/kernel/syscalls/getresuid/getresuid03.c index bf117038b..34e40c45d 100644 --- a/testcases/kernel/syscalls/getresuid/getresuid03.c +++ b/testcases/kernel/syscalls/getresuid/getresuid03.c @@ -76,6 +76,11 @@ #include <pwd.h> #include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" char *TCID = "getresuid03"; diff --git a/testcases/kernel/syscalls/getrlimit/getrlimit02.c b/testcases/kernel/syscalls/getrlimit/getrlimit02.c index 9b68ce20b..9f5b2bf9c 100644 --- a/testcases/kernel/syscalls/getrlimit/getrlimit02.c +++ b/testcases/kernel/syscalls/getrlimit/getrlimit02.c @@ -7,12 +7,13 @@ /*\ * [Description] * - * Test for checking error conditions for getrlimit(2) - * 1) getrlimit(2) returns -1 and sets errno to EFAULT if an invalid - * address is given for address parameter. - * 2) getrlimit(2) returns -1 and sets errno to EINVAL if an invalid - * resource type (RLIM_NLIMITS is a out of range resource type) is - * passed. + * Test for checking error conditions for getrlimit(2): + * + * 1. getrlimit(2) returns -1 and sets errno to EFAULT if an invalid + * address is given for address parameter. + * 2. getrlimit(2) returns -1 and sets errno to EINVAL if an invalid + * resource type (RLIM_NLIMITS is a out of range resource type) is + * passed. */ #include <sys/resource.h> diff --git a/testcases/kernel/syscalls/getsockopt/getsockopt02.c b/testcases/kernel/syscalls/getsockopt/getsockopt02.c index 47aef32af..d24e9b693 100644 --- a/testcases/kernel/syscalls/getsockopt/getsockopt02.c +++ b/testcases/kernel/syscalls/getsockopt/getsockopt02.c @@ -3,9 +3,10 @@ * Copyright (C) 2017 Red Hat, Inc. */ -/* - * Test description: Test retrieving of peer credentials (SO_PEERCRED) +/*\ + * [Description] * + * Test getsockopt(2) for retrieving peer credentials (SO_PEERCRED). */ #define _GNU_SOURCE @@ -53,6 +54,7 @@ static void test_function(void) tst_res(TFAIL | TERRNO, "Error with accepting connection"); goto clean; } + if (getsockopt(accepted, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) < 0) { tst_res(TFAIL | TERRNO, "Error while getting socket option"); @@ -67,6 +69,7 @@ static void test_function(void) clean: if (accepted >= 0) SAFE_CLOSE(accepted); + TST_CHECKPOINT_WAKE(0); } @@ -74,6 +77,7 @@ static void cleanup(void) { if (accepted >= 0) SAFE_CLOSE(accepted); + if (socket_fd >= 0) SAFE_CLOSE(socket_fd); } diff --git a/testcases/kernel/syscalls/gettid/.gitignore b/testcases/kernel/syscalls/gettid/.gitignore index 78dce3499..9014f7c3a 100644 --- a/testcases/kernel/syscalls/gettid/.gitignore +++ b/testcases/kernel/syscalls/gettid/.gitignore @@ -1 +1,2 @@ /gettid01 +/gettid02 diff --git a/testcases/kernel/syscalls/gettid/Makefile b/testcases/kernel/syscalls/gettid/Makefile index 4e9982f76..5345eb0f5 100644 --- a/testcases/kernel/syscalls/gettid/Makefile +++ b/testcases/kernel/syscalls/gettid/Makefile @@ -10,7 +10,9 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk ifeq ($(ANDROID), 1) -FILTER_OUT_MAKE_TARGETS += gettid01 +FILTER_OUT_MAKE_TARGETS += gettid01 gettid02 endif +gettid02: LDLIBS += -lpthread + include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/gettid/gettid01.c b/testcases/kernel/syscalls/gettid/gettid01.c index 7e5b6b175..22ba15016 100644 --- a/testcases/kernel/syscalls/gettid/gettid01.c +++ b/testcases/kernel/syscalls/gettid/gettid01.c @@ -1,96 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Crackerjack Project - * * Copyright (C) 2007-2008, Hitachi, Ltd. - * Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, - * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, - * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $Id: gettid01.c,v 1.5 2009/10/26 14:55:47 subrata_modak Exp $ + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ +/*\ + * [Description] * + * This test checks if parent pid is equal to tid in single-threaded + * application. */ -/* Porting from Crackerjack to LTP is done - by Masatake YAMATO <yamato@redhat.com> */ - -#include <sys/types.h> -#include <linux/unistd.h> -#include <errno.h> - -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "gettid01"; - -int TST_TOTAL = 1; - -pid_t my_gettid(void) -{ - return (pid_t) syscall(__NR_gettid); -} - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* - * The following loop checks looping state if -c option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { +#include "tst_test.h" +#include "lapi/syscalls.h" - tst_count = 0; - - TEST(my_gettid()); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "gettid() Failed, errno=%d: %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, "gettid() returned %ld", - TEST_RETURN); - } - } - - cleanup(); - tst_exit(); -} - -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { + long pid, tid; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + SAFE_FILE_LINES_SCANF("/proc/self/status", "Pid: %ld", &pid); + SAFE_FILE_LINES_SCANF("/proc/self/status", "Tgid: %ld", &tid); - TEST_PAUSE; + if (pid != tid) + tst_brk(TBROK, "Test function has been moved inside a thread?"); + TST_EXP_EQ_LI(tst_syscall(__NR_gettid), tst_syscall(__NR_getpid)); + TST_EXP_EQ_LI(tst_syscall(__NR_gettid), pid); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/gettid/gettid02.c b/testcases/kernel/syscalls/gettid/gettid02.c new file mode 100644 index 000000000..ef44761c4 --- /dev/null +++ b/testcases/kernel/syscalls/gettid/gettid02.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ +/*\ + * [Description] + * + * This test spawns multiple threads, then check for each one of them if the + * parent ID is different AND if the thread ID is different from all the other + * spwaned threads. + */ + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "tst_safe_pthread.h" + +#define THREADS_NUM 10 + +static volatile pid_t tids[THREADS_NUM]; + +static void *threaded(void *arg) +{ + int i = *(int *)arg; + pid_t pid, tid; + + pid = tst_syscall(__NR_getpid); + tid = tst_syscall(__NR_gettid); + + TST_EXP_EXPR(pid != tid, + "parent ID (%d) differs from thread[%d] ID (%d)", + pid, i, tid); + tids[i] = tid; + return NULL; +} + +static void run(void) +{ + pthread_t thread[THREADS_NUM]; + int args[THREADS_NUM]; + int error = 0; + + for (int i = 0; i < THREADS_NUM; i++) { + args[i] = i; + SAFE_PTHREAD_CREATE(&thread[i], NULL, threaded, &args[i]); + } + for (int i = 0; i < THREADS_NUM; i++) + SAFE_PTHREAD_JOIN(thread[i], NULL); + + for (int i = 0; i < THREADS_NUM; i++) { + for (int j = i + 1; j < THREADS_NUM; j++) { + if (tids[i] == tids[j]) { + tst_res(TINFO, "thread[%d] and thread[%d] have the same ID %d", i, j, tids[i]); + error = 1; + } + } + } + + if (error) + tst_res(TFAIL, "Some threads have the same TID"); + else + tst_res(TPASS, "All threads have a different TID"); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c b/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c index f9acb9665..887a36688 100644 --- a/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c +++ b/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c @@ -1,107 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2001-2023 */ -/* - * NAME - * gettimeofday01.c - * - * DESCRIPTION - * Testcase to check that gettimeofday(2) sets errno to EFAULT. - * - * ALGORITHM - * Call gettimeofday() with an invalid buffer, and expect EFAULT to be - * set in errno. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Test for gettimeofday error. * - * RESTRICTIONS - * NONE + * - EFAULT: tv pointed outside the accessible address space + * - EFAULT: tz pointed outside the accessible address space + * - EFAULT: both tv and tz pointed outside the accessible address space */ -#include <sys/time.h> -#include <errno.h> -#include "test.h" -#include <unistd.h> +#include "tst_test.h" #include "lapi/syscalls.h" -char *TCID = "gettimeofday01"; -int TST_TOTAL = 1; +static struct timeval tv1; -#if !defined UCLINUX +static struct tcase { + void *tv; + void *tz; +} tcases[] = { + /* timezone structure is obsolete, tz should be treated as null */ + {(void *)-1, NULL}, + {&tv1, (void *)-1}, + {(void *)-1, (void *)-1}, +}; -void cleanup(void); -void setup(void); - -int main(int ac, char **av) +static void verify_gettimeofday(unsigned int n) { - int lc; - int ret; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(tst_syscall(__NR_gettimeofday, (void *)-1, (void *)-1)); - - /* gettimeofday returns an int, so we need to turn the long - * TEST_RETURN into an int to test with */ - ret = TEST_RETURN; - if (ret != -1) { - tst_resm(TFAIL, - "call succeeded unexpectedly (got back %i, wanted -1)", - ret); - continue; - } + struct tcase *tc = &tcases[n]; - if (TEST_ERRNO == EFAULT) - tst_resm(TPASS, - "gettimeofday(2) set the errno EFAULT correctly"); - else - tst_resm(TFAIL, - "gettimeofday(2) didn't set errno to EFAULT, errno=%i (%s)", - errno, strerror(errno)); - } - - cleanup(); - tst_exit(); -} - -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -void cleanup(void) -{ -} -#else - -int main(void) -{ - tst_brkm(TCONF, "gettimeofday EFAULT check disabled on uClinux"); + TST_EXP_FAIL(tst_syscall(__NR_gettimeofday, tc->tv, tc->tz), EFAULT); } -#endif +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = verify_gettimeofday, +}; diff --git a/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c b/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c index 7c462cc29..84bf1f773 100644 --- a/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c +++ b/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c @@ -4,13 +4,13 @@ * Copyright (C) 2017 Cyril Hrubis <chrubis@suse.cz> */ -/* - * DESCRIPTION - * Check if gettimeofday is monotonous +/*\ + * [Description] + * + * Check if gettimeofday() is monotonous during 10s: * - * ALGORITHM - * Call gettimeofday() to get a t1 (fist value) - * call it again to get t2, see if t2 < t1, set t2 = t1, repeat for 10 sec + * - Call gettimeofday() to get a t1 (fist value) + * - Call it again to get t2, see if t2 < t1, set t2 = t1, repeat for 10 sec */ #include <stdint.h> diff --git a/testcases/kernel/syscalls/getxattr/getxattr02.c b/testcases/kernel/syscalls/getxattr/getxattr02.c index a42057d0a..5a84d876c 100644 --- a/testcases/kernel/syscalls/getxattr/getxattr02.c +++ b/testcases/kernel/syscalls/getxattr/getxattr02.c @@ -1,64 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2011 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * Copyright (C) 2011 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2012-2022 + * Copyright (c) 2023 Marius Kittler <mkittler@suse.de> */ -/* +/*\ + * [Description] + * * In the user.* namespace, only regular files and directories can * have extended attributes. Otherwise getxattr(2) will return -1 * and set errno to ENODATA. * * There are 4 test cases: - * 1. Get attribute from a FIFO, setxattr(2) should return -1 and + * + * - Get attribute from a FIFO, setxattr(2) should return -1 and * set errno to ENODATA - * 2. Get attribute from a char special file, setxattr(2) should + * - Get attribute from a char special file, setxattr(2) should * return -1 and set errno to ENODATA - * 3. Get attribute from a block special file, setxattr(2) should + * - Get attribute from a block special file, setxattr(2) should * return -1 and set errno to ENODATA - * 4. Get attribute from a UNIX domain socket, setxattr(2) should + * - Get attribute from a UNIX domain socket, setxattr(2) should * return -1 and set errno to ENODATA */ -#include "config.h" #include <sys/types.h> -#include <sys/stat.h> #include <sys/sysmacros.h> -#include <sys/wait.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <signal.h> +#include <sys/xattr.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#ifdef HAVE_SYS_XATTR_H -# include <sys/xattr.h> -#endif -#include "test.h" -#include "safe_macros.h" -char *TCID = "getxattr02"; +#include "tst_res_flags.h" +#include "tst_test.h" +#include "tst_test_macros.h" -#ifdef HAVE_SYS_XATTR_H +#define MNTPOINT "mntpoint" +#define FNAME MNTPOINT"/getxattr02" #define XATTR_TEST_KEY "user.testkey" #define FIFO "getxattr02fifo" @@ -66,94 +43,78 @@ char *TCID = "getxattr02"; #define BLK "getxattr02blk" #define SOCK "getxattr02sock" -static void setup(void); -static void cleanup(void); - -static char *tc[] = { - FIFO, /* case 00, get attr from fifo */ - CHR, /* case 01, get attr from char special */ - BLK, /* case 02, get attr from block special */ - SOCK, /* case 03, get attr from UNIX domain socket */ +static struct test_case { + const char *desc; + char *fname; + int mode; +} tcases[] = { + { + .desc = "get attr from fifo", + .fname = FNAME FIFO, + .mode = S_IFIFO, + }, + { + .desc = "get attr from char special", + .fname = FNAME CHR, + .mode = S_IFCHR, + }, + { + .desc = "get attr from block special", + .fname = FNAME BLK, + .mode = S_IFBLK, + }, + { + .desc = "get attr from UNIX domain socket", + .fname = FNAME SOCK, + .mode = S_IFSOCK, + }, }; -int TST_TOTAL = sizeof(tc) / sizeof(tc[0]); - -int main(int argc, char *argv[]) +static void run(unsigned int i) { - int lc; - int i; - int exp_eno; char buf[BUFSIZ]; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - exp_eno = ENODATA; - - for (i = 0; i < TST_TOTAL; i++) { - TEST(getxattr(tc[0], XATTR_TEST_KEY, buf, BUFSIZ)); - - if (TEST_RETURN == -1 && TEST_ERRNO == exp_eno) - tst_resm(TPASS | TTERRNO, "expected behavior"); - else - tst_resm(TFAIL | TTERRNO, "unexpected behavior" - " - expected errno %d - Got", exp_eno); - } - } - - cleanup(); - tst_exit(); + struct test_case *tc = &tcases[i]; + dev_t dev = tc->mode == S_IFCHR ? makedev(1, 3) : 0u; + + if (mknod(tc->fname, tc->mode | 0777, dev) < 0) + tst_brk(TBROK | TERRNO, "create %s (mode %i) failed (%s)", + tc->fname, tc->mode, tc->desc); + + TEST(getxattr(tc->fname, XATTR_TEST_KEY, buf, BUFSIZ)); + if (TST_RET == -1 && TST_ERR == ENODATA) + tst_res(TPASS | TTERRNO, "%s: expected return value", + tc->desc); + else + tst_res(TFAIL | TTERRNO, + "%s: unexpected return value - expected errno %d - got", + tc->desc, ENODATA); + + unlink(tc->fname); } static void setup(void) { - int fd; - dev_t dev; - - tst_require_root(); - - tst_tmpdir(); - - /* Test for xattr support */ - fd = SAFE_CREAT(cleanup, "testfile", 0644); - close(fd); - if (setxattr("testfile", "user.test", "test", 4, XATTR_CREATE) == -1) - if (errno == ENOTSUP) - tst_brkm(TCONF, cleanup, "No xattr support in fs or " - "mount without user_xattr option"); - unlink("testfile"); - - /* Create test files */ - if (mknod(FIFO, S_IFIFO | 0777, 0) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "Create FIFO(%s) failed", - FIFO); - - dev = makedev(1, 3); - if (mknod(CHR, S_IFCHR | 0777, dev) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "Create char special(%s)" - " failed", CHR); - - if (mknod(BLK, S_IFBLK | 0777, 0) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "Create block special(%s)" - " failed", BLK); - - if (mknod(SOCK, S_IFSOCK | 0777, 0) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "Create socket(%s) failed", - SOCK); - - TEST_PAUSE; + /* assert xattr support in the current filesystem */ + SAFE_TOUCH(FNAME, 0644, NULL); + TEST(setxattr(FNAME, "user.test", "test", 4, XATTR_CREATE)); + if (TST_ERR == ENOTSUP) + tst_brk(TCONF, + "No xattr support in fs or mount without user_xattr option"); + else if (TST_RET != 0) + tst_brk(TBROK | TTERRNO, "setxattr failed"); } -static void cleanup(void) -{ - tst_rmdir(); -} -#else /* HAVE_SYS_XATTR_H */ -int main(int argc, char *argv[]) -{ - tst_brkm(TCONF, NULL, "<sys/xattr.h> does not exist."); -} -#endif +static struct tst_test test = { + .all_filesystems = 1, + .needs_root = 1, + .mntpoint = MNTPOINT, + .mount_device = 1, + .skip_filesystems = (const char *const []) { + "ramfs", + "nfs", + NULL + }, + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/getxattr/getxattr03.c b/testcases/kernel/syscalls/getxattr/getxattr03.c index b6ea14287..1fe4ba48f 100644 --- a/testcases/kernel/syscalls/getxattr/getxattr03.c +++ b/testcases/kernel/syscalls/getxattr/getxattr03.c @@ -1,117 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2012 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (c) 2023 Marius Kittler <mkittler@suse.de> */ -/* - * An empty buffer of size zero can be passed into getxattr(2) to return - * the current size of the named extended attribute. +/*\ + * [Description] + * + * An empty buffer of size zero can be passed into getxattr(2) to + * return the current size of the named extended attribute. */ #include "config.h" -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#ifdef HAVE_SYS_XATTR_H -# include <sys/xattr.h> -#endif -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" -char *TCID = "getxattr03"; +#include <sys/xattr.h> +#include "tst_safe_macros.h" -#ifdef HAVE_SYS_XATTR_H +#define MNTPOINT "mntpoint" +#define FNAME MNTPOINT"/getxattr03testfile" #define XATTR_TEST_KEY "user.testkey" #define XATTR_TEST_VALUE "test value" #define XATTR_TEST_VALUE_SIZE (sizeof(XATTR_TEST_VALUE) - 1) -#define TESTFILE "getxattr03testfile" -static void setup(void); -static void cleanup(void); - -int TST_TOTAL = 1; - -int main(int argc, char *argv[]) +static void run(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(getxattr(TESTFILE, XATTR_TEST_KEY, NULL, 0)); - - if (TEST_RETURN == XATTR_TEST_VALUE_SIZE) - tst_resm(TPASS, "getxattr(2) returned correct value"); - else - tst_resm(TFAIL | TTERRNO, "getxattr(2) failed"); - } - - cleanup(); - tst_exit(); + TST_EXP_VAL(getxattr(FNAME, XATTR_TEST_KEY, NULL, 0), + XATTR_TEST_VALUE_SIZE); } static void setup(void) { - int fd; - - tst_require_root(); - - tst_tmpdir(); - - /* Test for xattr support and set attr value */ - fd = SAFE_CREAT(cleanup, TESTFILE, 0644); - close(fd); - - if (setxattr(TESTFILE, XATTR_TEST_KEY, XATTR_TEST_VALUE, - XATTR_TEST_VALUE_SIZE, XATTR_CREATE) == -1) { - if (errno == ENOTSUP) - tst_brkm(TCONF, cleanup, "No xattr support in fs or " - "fs mounted without user_xattr option"); - else - tst_brkm(TBROK | TERRNO, cleanup, "setxattr %s failed", - TESTFILE); - } - - TEST_PAUSE; + SAFE_TOUCH(FNAME, 0644, NULL); + SAFE_SETXATTR(FNAME, XATTR_TEST_KEY, XATTR_TEST_VALUE, + XATTR_TEST_VALUE_SIZE, XATTR_CREATE); } -static void cleanup(void) -{ - tst_rmdir(); -} -#else /* HAVE_SYS_XATTR_H */ -int main(int argc, char *argv[]) -{ - tst_brkm(TCONF, NULL, "<sys/xattr.h> does not exist."); -} -#endif +static struct tst_test test = { + .all_filesystems = 1, + .needs_root = 1, + .mntpoint = MNTPOINT, + .mount_device = 1, + .skip_filesystems = (const char *const []) { + "exfat", + "tmpfs", + "ramfs", + "nfs", + "vfat", + NULL + }, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/ioctl/ioctl02.c b/testcases/kernel/syscalls/ioctl/ioctl02.c index b4d4a3594..aab80b251 100644 --- a/testcases/kernel/syscalls/ioctl/ioctl02.c +++ b/testcases/kernel/syscalls/ioctl/ioctl02.c @@ -1,468 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 - * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2020 Petr Vorel <pvorel@suse.cz> + * Copyright (c) 2023 Marius Kittler <mkittler@suse.de> */ -/* - * NAME - * ioctl02.c - * - * DESCRIPTION - * Testcase to test the TCGETA, and TCSETA ioctl implementations for - * the tty driver +/*\ + * [Description] * - * ALGORITHM - * In this test, the parent and child open the parentty and the childtty - * respectively. After opening the childtty the child flushes the stream - * and sends a SIGUSR1 to the parent (thereby asking it to continue its - * testing). The parent, which was waiting for this signal to arrive, now - * starts the testing. It issues a TCGETA ioctl to get all the tty - * parameters. It then changes them to known values by issuing a TCSETA - * ioctl. Then the parent issues a TCGETA ioctl again and compares the - * received values with what it had set earlier. The test fails if TCGETA - * or TCSETA fails, or if the received values don't match those that were - * set. The parent does all the testing, the requirement of the child - * process is to moniter the testing done by the parent, and hence the - * child just waits for the parent. + * Test TCGETA/TCGETS and TCSETA/TCSETS ioctl implementations for tty driver. * - * USAGE: <for command-line> - * ioctl02 -D /dev/tty[0-9] [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * test must be run with the -D option - * test may have to be run as root depending on the tty permissions + * In this test, the parent and child open the parentty and the childtty + * respectively. After opening the childtty the child flushes the stream + * and wakes the parent (thereby asking it to continue its testing). The + * parent, then starts the testing. It issues a TCGETA/TCGETS ioctl to + * get all the tty parameters. It then changes them to known values by + * issuing a TCSETA/TCSETS ioctl. Then the parent issues a TCSETA/TCGETS + * ioctl again and compares the received values with what it had set + * earlier. The test fails if TCGETA/TCGETS or TCSETA/TCSETS fails, or if + * the received values don't match those that were set. The parent does + * all the testing, the requirement of the child process is to moniter + * the testing done by the parent, and hence the child just waits for the + * parent. */ #include <stdio.h> -#include <fcntl.h> -#include <signal.h> -#include <errno.h> -#include <sys/wait.h> -#include <sys/types.h> -#include <sys/stat.h> +#include <stdlib.h> #include <termios.h> -#include "test.h" -#include "safe_macros.h" -#include "lapi/ioctl.h" -#define CNUL 0 - -char *TCID = "ioctl02"; -int TST_TOTAL = 1; +#include "lapi/ioctl.h" +#include "tst_test.h" -static struct termio termio, save_io; +static struct termio termio, termio_exp; +static struct termios termios, termios_exp, termios_bak; static char *parenttty, *childtty; -static int parentfd, childfd; +static int parentfd = -1; static int parentpid, childpid; -static volatile int sigterm, sigusr1, sigusr2; -static int closed = 1; - -static int do_child_setup(void); -static int do_parent_setup(void); -static int run_ptest(void); -static int run_ctest(void); -static int chk_tty_parms(); + +static void do_child(void); +static void prepare_termio(void); +static void run_ptest(void); +static void chk_tty_parms_termio(void); +static void chk_tty_parms_termios(void); static void setup(void); static void cleanup(void); -static void help(void); -static void do_child(void); -void do_child_uclinux(void); -static void sigterm_handler(void); -static int Devflag; -static char *devname; - -static option_t options[] = { - {"D:", &Devflag, &devname}, - {NULL, NULL, NULL} +static char *device; + +static struct variant { + const char *name; + void *termio, *termio_exp, *termio_bak; + size_t termio_size; + void (*check)(void); + int tcget, tcset; +} variants[] = { + { + .name = "termio", + .termio = &termio, + .termio_exp = &termio_exp, + .termio_size = sizeof(termio), + .check = &chk_tty_parms_termio, + .tcget = TCGETA, + .tcset = TCSETA, + }, + { + .name = "termios", + .termio = &termios, + .termio_exp = &termios_exp, + .termio_size = sizeof(termios), + .check = &chk_tty_parms_termios, + .tcget = TCGETS, + .tcset = TCSETS, + }, }; -int main(int ac, char **av) +static void verify_ioctl(void) { - int lc; - int rval; - - tst_parse_opts(ac, av, options, &help); - -#ifdef UCLINUX - maybe_run_child(&do_child_uclinux, "dS", &parentpid, &childtty); -#endif - - if (!Devflag) - tst_brkm(TBROK, NULL, "You must specify a tty device with " - "the -D option."); - - tst_require_root(); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - parenttty = devname; - childtty = devname; - - parentpid = getpid(); - - childpid = FORK_OR_VFORK(); - if (childpid < 0) - tst_brkm(TBROK, cleanup, "fork failed"); - - if (childpid == 0) { /* child */ -#ifdef UCLINUX - if (self_exec(av[0], "dS", parentpid, childtty) < 0) - tst_brkm(TBROK, cleanup, "self_exec failed"); -#else - do_child(); -#endif - } - - while (!sigusr1) - sleep(1); - - sigusr1 = 0; - - parentfd = do_parent_setup(); - if (parentfd < 0) { - kill(childpid, SIGTERM); - waitpid(childpid, NULL, 0); - cleanup(); - } - - /* run the parent test */ - rval = run_ptest(); - if (rval == -1) { - /* - * Parent cannot set/get ioctl parameters. - * SIGTERM the child and cleanup. - */ - kill(childpid, SIGTERM); - waitpid(childpid, NULL, 0); - cleanup(); - } - - if (rval != 0) - tst_resm(TFAIL, "TCGETA/TCSETA tests FAILED with " - "%d %s", rval, rval > 1 ? "errors" : "error"); - else - tst_resm(TPASS, "TCGETA/TCSETA tests SUCCEEDED"); - - /* FIXME: check return codes. */ - (void)kill(childpid, SIGTERM); - (void)waitpid(childpid, NULL, 0); - - /* - * Clean up things from the parent by restoring the - * tty device information that was saved in setup() - * and closing the tty file descriptor. - */ - if (ioctl(parentfd, TCSETA, &save_io) == -1) - tst_resm(TINFO, "ioctl restore failed in main"); - SAFE_CLOSE(cleanup, parentfd); - - closed = 1; - } - cleanup(); + tst_res(TINFO, "Testing %s variant", variants[tst_variant].name); - tst_exit(); -} + parenttty = device; + childtty = device; -static void do_child(void) -{ - childfd = do_child_setup(); - if (childfd < 0) - _exit(1); - run_ctest(); - _exit(0); -} + parentpid = getpid(); + childpid = SAFE_FORK(); + if (!childpid) { + do_child(); + exit(EXIT_SUCCESS); + } -void do_child_uclinux(void) -{ - struct sigaction act; + TST_CHECKPOINT_WAIT(0); + + parentfd = SAFE_OPEN(parenttty, O_RDWR, 0777); + SAFE_IOCTL(parentfd, TCFLSH, TCIOFLUSH); - /* Set up the signal handlers again */ - act.sa_handler = (void *)sigterm_handler; - act.sa_flags = 0; - sigemptyset(&act.sa_mask); - (void)sigaction(SIGTERM, &act, 0); + run_ptest(); - /* Run the normal child */ - do_child(); + TST_CHECKPOINT_WAKE(0); + SAFE_CLOSE(parentfd); } -/* - * run_ptest() - setup the various termio structure values and issue - * the TCSETA ioctl call with the TEST macro. - */ -static int run_ptest(void) +static void prepare_termio(void) { - int i, rval; - /* Use "old" line discipline */ - termio.c_line = 0; + termios_exp.c_line = termio_exp.c_line = 0; /* Set control modes */ - termio.c_cflag = B50 | CS7 | CREAD | PARENB | PARODD | CLOCAL; + termios_exp.c_cflag = termio_exp.c_cflag = B50 | CS7 | CREAD | PARENB | PARODD | CLOCAL; /* Set control chars. */ - for (i = 0; i < NCC; i++) { - if (i == VEOL2) - continue; - termio.c_cc[i] = CSTART; - } + for (int i = 0; i < NCC; i++) + termio_exp.c_cc[i] = CSTART; + for (int i = 0; i < VEOL2; i++) + termios_exp.c_cc[i] = CSTART; /* Set local modes. */ - termio.c_lflag = + termios_exp.c_lflag = termio_exp.c_lflag = ((unsigned short)(ISIG | ICANON | XCASE | ECHO | ECHOE | NOFLSH)); /* Set input modes. */ - termio.c_iflag = + termios_exp.c_iflag = termio_exp.c_iflag = BRKINT | IGNPAR | INPCK | ISTRIP | ICRNL | IUCLC | IXON | IXANY | IXOFF; /* Set output modes. */ - termio.c_oflag = OPOST | OLCUC | ONLCR | ONOCR; - - TEST(ioctl(parentfd, TCSETA, &termio)); - - if (TEST_RETURN < 0) { - tst_resm(TFAIL, "ioctl TCSETA failed : " - "errno = %d", TEST_ERRNO); - return -1; - } - - /* Get termio and see if all parameters actually got set */ - rval = ioctl(parentfd, TCGETA, &termio); - if (rval < 0) { - tst_resm(TFAIL, "ioctl TCGETA failed. Ending test."); - return -1; - } - - return chk_tty_parms(); + termios_exp.c_oflag = termio_exp.c_oflag = OPOST | OLCUC | ONLCR | ONOCR; } -static int run_ctest(void) +/* + * run_ptest() - setup the various termio/termios structure values and issue + * the TCSETA/TCSETS ioctl call with the TEST macro. + */ +static void run_ptest(void) { - /* - * Wait till the parent has finished testing. - */ - while (!sigterm) - sleep(1); + struct variant *v = &variants[tst_variant]; - sigterm = 0; + /* Init termio/termios structures used to check if all params got set */ + memset(v->termio, 0, v->termio_size); - tst_resm(TINFO, "child: Got SIGTERM from parent."); + SAFE_IOCTL(parentfd, v->tcset, v->termio_exp); - if (close(childfd) == -1) - tst_resm(TINFO, "close() in run_ctest() failed"); - return 0; + /* Get termio and see if all parameters actually got set */ + SAFE_IOCTL(parentfd, v->tcget, v->termio); + v->check(); } -static int chk_tty_parms(void) +static int cmp_attr(unsigned long long exp, unsigned long long act, const char *attr) { - int i, flag = 0; - - if (termio.c_line != 0) { - tst_resm(TINFO, "line discipline has incorrect value %o", - termio.c_line); - flag++; - } - /* - * The following Code Sniffet is disabled to check the value of c_cflag - * as it seems that due to some changes from 2.6.24 onwards, this - * setting is not done properly for either of (B50|CS7|CREAD|PARENB| - * PARODD|CLOCAL|(CREAD|HUPCL|CLOCAL). - * However, it has been observed that other flags are properly set. - */ -#if 0 - if (termio.c_cflag != (B50 | CS7 | CREAD | PARENB | PARODD | CLOCAL)) { - tst_resm(TINFO, "cflag has incorrect value. %o", - termio.c_cflag); - flag++; - } -#endif - - for (i = 0; i < NCC; i++) { - if (i == VEOL2) { - if (termio.c_cc[VEOL2] == CNUL) { - continue; - } else { - tst_resm(TINFO, "control char %d has " - "incorrect value %d %d", i, - termio.c_cc[i], CNUL); - flag++; - continue; - } - } - - if (termio.c_cc[i] != CSTART) { - tst_resm(TINFO, "control char %d has incorrect " - "value %d.", i, termio.c_cc[i]); - flag++; - } - } + if (act == exp) + return 0; + tst_res(TFAIL, "%s has incorrect value %llu, expected %llu", + attr, act, exp); + return 1; +} - if (! - (termio.c_lflag - && (ISIG | ICANON | XCASE | ECHO | ECHOE | NOFLSH))) { - tst_resm(TINFO, "lflag has incorrect value. %o", - termio.c_lflag); - flag++; - } +static int cmp_c_cc(unsigned char *exp_c_cc, unsigned char *act_c_cc, int ncc) +{ + int i, fails = 0; + char what[32]; - if (! - (termio.c_iflag - && (BRKINT | IGNPAR | INPCK | ISTRIP | ICRNL | IUCLC | IXON | IXANY - | IXOFF))) { - tst_resm(TINFO, "iflag has incorrect value. %o", - termio.c_iflag); - flag++; + for (i = 0; i < ncc; ++i) { + sprintf(what, "control char %d", i); + fails += cmp_attr(exp_c_cc[i], act_c_cc[i], what); } + return fails; +} - if (!(termio.c_oflag && (OPOST | OLCUC | ONLCR | ONOCR))) { - tst_resm(TINFO, "oflag has incorrect value. %o", - termio.c_oflag); - flag++; - } +#define CMP_ATTR(term_exp, term, attr, flag) \ +({ \ + flag += cmp_attr((term_exp).attr, (term).attr, #attr); \ + flag; \ +}) - if (!flag) - tst_resm(TINFO, "termio values are set as expected"); +#define CMP_C_CC(term_exp, term, flag) \ +({ \ + flag += cmp_c_cc(term_exp.c_cc, term.c_cc, sizeof(term.c_cc)); \ + flag; \ +}) - return flag; -} - -static int do_parent_setup(void) +static void chk_tty_parms_termio(void) { - int pfd; - - pfd = SAFE_OPEN(cleanup, parenttty, O_RDWR, 0777); + int flag = 0; - /* unset the closed flag */ - closed = 0; + flag = CMP_ATTR(termio_exp, termio, c_line, flag); + flag = CMP_C_CC(termio_exp, termio, flag); + flag = CMP_ATTR(termio_exp, termio, c_lflag, flag); + flag = CMP_ATTR(termio_exp, termio, c_iflag, flag); + flag = CMP_ATTR(termio_exp, termio, c_oflag, flag); - /* flush tty queues to remove old output */ - SAFE_IOCTL(cleanup, pfd, TCFLSH, 2); - return pfd; + if (!flag) + tst_res(TPASS, "TCGETA/TCSETA tests"); } -static int do_child_setup(void) +static void chk_tty_parms_termios(void) { - int cfd; - - cfd = open(childtty, O_RDWR, 0777); - if (cfd < 0) { - tst_resm(TINFO, "Could not open %s in do_child_setup(), errno " - "= %d", childtty, errno); - /* signal the parent so we don't hang the test */ - kill(parentpid, SIGUSR1); - return -1; - } + int flag = 0; - /* flush tty queues to remove old output */ - if (ioctl(cfd, TCFLSH, 2) < 0) { - tst_resm(TINFO, "ioctl TCFLSH failed. : errno = %d", errno); - /* signal the parent so we don't hang the test */ - kill(parentpid, SIGUSR1); - return -1; - } + flag = CMP_ATTR(termios_exp, termios, c_line, flag); + flag = CMP_C_CC(termios_exp, termios, flag); + flag = CMP_ATTR(termios_exp, termios, c_lflag, flag); + flag = CMP_ATTR(termios_exp, termios, c_iflag, flag); + flag = CMP_ATTR(termios_exp, termios, c_oflag, flag); - /* tell the parent that we're done */ - kill(parentpid, SIGUSR1); - - return cfd; + if (!flag) + tst_res(TPASS, "TCGETS/TCSETS tests"); } -/* - * Define the signals handlers here. - */ -static void sigterm_handler(void) +static void do_child(void) { - sigterm = 1; -} + int cfd = SAFE_OPEN(childtty, O_RDWR, 0777); -static void sigusr1_handler(void) -{ - sigusr1 = 1; -} + SAFE_IOCTL(cfd, TCFLSH, TCIOFLUSH); -static void sigusr2_handler(void) -{ - sigusr2 = 1; -} + /* tell the parent that we're done */ + TST_CHECKPOINT_WAKE(0); -static void help(void) -{ - printf(" -D <tty device> : for example, /dev/tty[0-9]\n"); + TST_CHECKPOINT_WAIT(0); + tst_res(TINFO, "child: parent has finished testing"); + SAFE_CLOSE(cfd); } static void setup(void) { - int fd; - struct sigaction act; + if (!device) + tst_brk(TBROK, "You must specify a tty device with -d option"); - /* XXX: TERRNO required all over the place */ - fd = SAFE_OPEN(NULL, devname, O_RDWR, 0777); + int fd = SAFE_OPEN(device, O_RDWR, 0777); - /* Save the current device information - to be restored in cleanup() */ - SAFE_IOCTL(cleanup, fd, TCGETA, &save_io); + SAFE_IOCTL(fd, TCGETS, &termios_bak); + SAFE_CLOSE(fd); - /* Close the device */ - SAFE_CLOSE(cleanup, fd); - - /* Set up the signal handlers */ - act.sa_handler = (void *)sigterm_handler; - act.sa_flags = 0; - sigemptyset(&act.sa_mask); - (void)sigaction(SIGTERM, &act, 0); - - act.sa_handler = (void *)sigusr1_handler; - act.sa_flags = 0; - (void)sigaction(SIGUSR1, &act, 0); - - act.sa_handler = (void *)sigusr2_handler; - act.sa_flags = 0; - (void)sigaction(SIGUSR2, &act, 0); - - act.sa_handler = SIG_IGN; - act.sa_flags = 0; - (void)sigaction(SIGTTOU, &act, 0); - - sigterm = sigusr1 = sigusr2 = 0; - - TEST_PAUSE; + prepare_termio(); } static void cleanup(void) { - if (!closed) { - if (ioctl(parentfd, TCSETA, &save_io) == -1) - tst_resm(TINFO, "ioctl restore failed in cleanup()"); - if (close(parentfd) == -1) - tst_resm(TINFO, "close() failed in cleanup()"); + if (parentfd >= 0) { + SAFE_IOCTL(parentfd, TCSETS, &termios_bak); + SAFE_CLOSE(parentfd); } } + +static struct tst_test test = { + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_ioctl, + .test_variants = 2, + .options = (struct tst_option[]) { + {"d:", &device, "Tty device. For example, /dev/tty[0-9]"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop06.c b/testcases/kernel/syscalls/ioctl/ioctl_loop06.c index 6d009af6a..64800b4ee 100644 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop06.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop06.c @@ -109,8 +109,9 @@ static void setup(void) unalign_value = pg_size - 1; dev_fd = SAFE_OPEN(dev_path, O_RDWR); + ret = ioctl(dev_fd, LOOP_SET_BLOCK_SIZE, 512); - if (ioctl(dev_fd, LOOP_SET_BLOCK_SIZE, 512) && errno == EINVAL) + if (ret && (errno == EINVAL || errno == ENOTTY)) tst_brk(TCONF, "LOOP_SET_BLOCK_SIZE is not supported"); file_fd = SAFE_OPEN("test.img", O_RDWR); diff --git a/testcases/kernel/syscalls/ioctl/test_ioctl b/testcases/kernel/syscalls/ioctl/test_ioctl index 43836a229..8549e5608 100755 --- a/testcases/kernel/syscalls/ioctl/test_ioctl +++ b/testcases/kernel/syscalls/ioctl/test_ioctl @@ -45,7 +45,7 @@ case "$device_no" in continue fi tst_resm TINFO "Testing ioctl02 with $tttype" - ioctl02 -D $tttype + ioctl02 -d $tttype RC=$? if [ $RC -eq 0 ] then diff --git a/testcases/kernel/syscalls/ipc/msgctl/msgctl06.c b/testcases/kernel/syscalls/ipc/msgctl/msgctl06.c index 6f5476383..c1264b71e 100644 --- a/testcases/kernel/syscalls/ipc/msgctl/msgctl06.c +++ b/testcases/kernel/syscalls/ipc/msgctl/msgctl06.c @@ -139,12 +139,16 @@ static void verify_msgctl(unsigned int n) static void setup(void) { struct msqid_ds temp_buf; + struct buf { + long type; + char text[5]; + } msgbuf = {MSGTYPE, "abcd"}; ltpuser = SAFE_GETPWNAM("nobody"); nobody_uid = ltpuser->pw_uid; root_uid = 0; msg_id = SAFE_MSGGET(IPC_PRIVATE, IPC_CREAT | MSG_RW); - SAFE_MSGSND(msg_id, "abcd", 4, 0); + SAFE_MSGSND(msg_id, &msgbuf, sizeof(msgbuf.text), 0); TEST(msgctl(msg_id, MSG_STAT_ANY, &temp_buf)); if (TST_RET == -1) { diff --git a/testcases/kernel/syscalls/ipc/shmget/shmget02.c b/testcases/kernel/syscalls/ipc/shmget/shmget02.c index 8168803a5..10b8c9292 100644 --- a/testcases/kernel/syscalls/ipc/shmget/shmget02.c +++ b/testcases/kernel/syscalls/ipc/shmget/shmget02.c @@ -37,8 +37,6 @@ #include "libnewipc.h" #include "lapi/shm.h" -#define CONFIG_HUGETLBFS "CONFIG_HUGETLBFS" - static int shm_id = -1; static key_t shmkey, shmkey1; static struct passwd *pw; @@ -66,10 +64,7 @@ static struct tcase { static int get_hugetlb_exp_error(void) { long tmp; - struct tst_kconfig_var kconfig = { - .id = CONFIG_HUGETLBFS, - .id_len = sizeof(CONFIG_HUGETLBFS)-1, - }; + struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_HUGETLBFS"); tst_kconfig_read(&kconfig, 1); diff --git a/testcases/kernel/syscalls/keyctl/keyctl01.c b/testcases/kernel/syscalls/keyctl/keyctl01.c index 55e069c68..674094eec 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl01.c +++ b/testcases/kernel/syscalls/keyctl/keyctl01.c @@ -2,14 +2,17 @@ /* * Copyright (c) Crackerjack Project., 2007 * Copyright (c) 2017 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2009-2024 + * Ported by Manas Kumar Nayak maknayak@in.ibm.com> + * Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> */ -/* - * Description: This tests the keyctl() syscall - * Manipulate the kernel's key management facility +/*\ + * [Description] * - * Ported by Manas Kumar Nayak maknayak@in.ibm.com> - * Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * Tests the keyctl(2) syscall. + * + * Manipulate the kernel's key management facility. */ #include <errno.h> diff --git a/testcases/kernel/syscalls/keyctl/keyctl02.c b/testcases/kernel/syscalls/keyctl/keyctl02.c index 35cc2838d..fd3f86bbc 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl02.c +++ b/testcases/kernel/syscalls/keyctl/keyctl02.c @@ -1,11 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Fujitsu Ltd. - * Ported: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2017-2024 + * Ported: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> */ -/* - * This is a regression test for the race between keyctl_read() and +/*\ + * [Description] + * + * Regression test for the race between keyctl_read() and * keyctl_revoke(), if the revoke happens between keyctl_read() * checking the validity of a key and the key's semaphore being taken, * then the key type read method will see a revoked key. @@ -14,13 +17,8 @@ * assumes in its read method that there will always be a payload * in a non-revoked key and doesn't check for a NULL pointer. * - * This test can crash the buggy kernel, and the bug was fixed in: - * - * commit b4a1b4f5047e4f54e194681125c74c0aa64d637d - * Author: David Howells <dhowells@redhat.com> - * Date: Fri Dec 18 01:34:26 2015 +0000 - * - * KEYS: Fix race between read and revoke + * Bug was fixed in commit + * b4a1b4f5047e ("KEYS: Fix race between read and revoke") */ #include <errno.h> @@ -29,6 +27,7 @@ #include "tst_safe_pthread.h" #include "tst_test.h" +#include "tst_kconfig.h" #include "lapi/keyctl.h" #define LOOPS 20000 @@ -36,6 +35,7 @@ #define PATH_KEY_COUNT_QUOTA "/proc/sys/kernel/keys/root_maxkeys" static int orig_maxkeys; +static int realtime_kernel; static void *do_read(void *arg) { @@ -86,6 +86,15 @@ static void do_test(void) tst_res(TINFO, "Runtime exhausted, exiting after %d loops", i); break; } + + /* + * Realtime kernel has deferred post-join thread cleanup which + * may result in exhaustion of cgroup thread limit. Add delay + * to limit the maximum number of stale threads to 4000 + * even with CONFIG_HZ=100. + */ + if (realtime_kernel) + usleep(100); } /* @@ -126,8 +135,19 @@ static void do_test(void) static void setup(void) { + unsigned int i; + struct tst_kconfig_var rt_kconfigs[] = { + TST_KCONFIG_INIT("CONFIG_PREEMPT_RT"), + TST_KCONFIG_INIT("CONFIG_PREEMPT_RT_FULL") + }; + SAFE_FILE_SCANF(PATH_KEY_COUNT_QUOTA, "%d", &orig_maxkeys); SAFE_FILE_PRINTF(PATH_KEY_COUNT_QUOTA, "%d", orig_maxkeys + LOOPS + 1); + + tst_kconfig_read(rt_kconfigs, ARRAY_SIZE(rt_kconfigs)); + + for (i = 0; i < ARRAY_SIZE(rt_kconfigs); i++) + realtime_kernel |= rt_kconfigs[i].choice == 'y'; } static void cleanup(void) diff --git a/testcases/kernel/syscalls/keyctl/keyctl03.c b/testcases/kernel/syscalls/keyctl/keyctl03.c index 9d7b9a0b5..563ee96a9 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl03.c +++ b/testcases/kernel/syscalls/keyctl/keyctl03.c @@ -1,19 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Fujitsu Ltd. - * Ported: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2017-2024 + * Ported: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> */ -/* - * This regression test can crash the buggy kernel, - * and the bug was fixed in: - * - * commit f05819df10d7b09f6d1eb6f8534a8f68e5a4fe61 - * Author: David Howells <dhowells@redhat.com> - * Date: Thu Oct 15 17:21:37 2015 +0100 +/*\ + * [Description] * - * KEYS: Fix crash when attempt to garbage collect - * an uninstantiated keyring + * Regression test for commit + * f05819df10d7 ("KEYS: Fix crash when attempt to garbage collect an uninstantiated keyring") */ #include <errno.h> diff --git a/testcases/kernel/syscalls/keyctl/keyctl04.c b/testcases/kernel/syscalls/keyctl/keyctl04.c index 1fed23ca6..50c9244de 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl04.c +++ b/testcases/kernel/syscalls/keyctl/keyctl04.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Google, Inc. + * Copyright (c) Linux Test Project, 2017-2024 */ -/* +/*\ + * [Description] + * * Regression test for commit c9f838d104fe ("KEYS: fix * keyctl_set_reqkey_keyring() to not leak thread keyrings"), a.k.a. * CVE-2017-7472. This bug could be used to exhaust kernel memory, though it diff --git a/testcases/kernel/syscalls/keyctl/keyctl05.c b/testcases/kernel/syscalls/keyctl/keyctl05.c index 7d7c076c0..0ad106774 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl05.c +++ b/testcases/kernel/syscalls/keyctl/keyctl05.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Google, Inc. + * Copyright (c) Linux Test Project, 2017-2024 */ -/* +/*\ + * [Description] + * * Regression test for commit 63a0b0509e70 ("KEYS: fix freeing uninitialized * memory in key_update()"). Try to reproduce the crash in two different ways: * @@ -31,6 +34,8 @@ #include "tst_test.h" #include "lapi/keyctl.h" +#define MODULE "dns_resolver" + /* * A valid payload for the "asymmetric" key type. This is an x509 certificate * in DER format, generated using: @@ -190,6 +195,9 @@ static void test_update_setperm_race(void) static void setup(void) { + /* There is no way to trigger automatic dns_resolver module loading. */ + tst_cmd((const char*[]){"modprobe", MODULE, NULL}, NULL, NULL, 0); + fips_enabled = tst_fips_enabled(); } @@ -198,8 +206,12 @@ static void do_test(unsigned int i) /* * We need to pass check in dns_resolver_preparse(), * give it dummy server list request. + * From v6.8-rc1 commit acc657692aed438e9931438f8c923b2b107aebf9: + * the incoming data for add_key() sysdall should be not less than 6 + * bytes, because struct dns_server_list_v1_header is 6 bytes. + * The minimum payload will be tested here for boundary testing. */ - static char dns_res_payload[] = { 0x00, 0x00, 0x01, 0xff, 0x00 }; + static char dns_res_payload[] = { 0x00, 0x00, 0x01, 0xff, 0x00, 0x00 }; switch (i) { case 0: @@ -207,7 +219,7 @@ static void do_test(unsigned int i) x509_cert, sizeof(x509_cert)); break; case 1: - test_update_nonupdatable("dns_resolver", dns_res_payload, + test_update_nonupdatable(MODULE, dns_res_payload, sizeof(dns_res_payload)); break; case 2: @@ -217,12 +229,14 @@ static void do_test(unsigned int i) } static struct tst_test test = { + .needs_root = 1, .tcnt = 3, .setup = setup, .test = do_test, .forks_child = 1, .tags = (const struct tst_tag[]) { {"linux-git", "63a0b0509e70"}, + {"linux-git", "acc657692aed"}, {} } }; diff --git a/testcases/kernel/syscalls/keyctl/keyctl06.c b/testcases/kernel/syscalls/keyctl/keyctl06.c index f76a85ff2..4564601d1 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl06.c +++ b/testcases/kernel/syscalls/keyctl/keyctl06.c @@ -1,19 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Google, Inc. + * Copyright (c) Linux Test Project, 2017-2024 */ -/* - * Regression test for: +/*\ + * [Description] * - * commit e645016abc80 ("KEYS: fix writing past end of user-supplied buffer - * in keyring_read()"). + * Regression test for commit: * - * as well as its follow-on fix: + * e645016abc80 ("KEYS: fix writing past end of user-supplied buffer in keyring_read()") * - * commit 3239b6f29bdf ("KEYS: return full count in keyring_read() if - * buffer is too small") + * as well as its follow-on fix: * + * commit 3239b6f29bdf ("KEYS: return full count in keyring_read() if buffer is too small") */ #include <errno.h> diff --git a/testcases/kernel/syscalls/keyctl/keyctl07.c b/testcases/kernel/syscalls/keyctl/keyctl07.c index d9e20db5f..8b10ee803 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl07.c +++ b/testcases/kernel/syscalls/keyctl/keyctl07.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Google, Inc. + * Copyright (c) Linux Test Project, 2018-2024 */ -/* +/*\ + * [Description] + * * Regression test for commit 37863c43b2c6 ("KEYS: prevent KEYCTL_READ on * negative key"). This is CVE-2017-12192. */ diff --git a/testcases/kernel/syscalls/keyctl/keyctl08.c b/testcases/kernel/syscalls/keyctl/keyctl08.c index be4b23b14..30e077c50 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl08.c +++ b/testcases/kernel/syscalls/keyctl/keyctl08.c @@ -1,10 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com> + * Copyright (c) Linux Test Project, 2019-2024 */ -/* Check for CVE-2016-9604; that keys beginning with "." are disallowed. + +/*\ + * [Description] + * + * Test for CVE-2016-9604, checks that keys beginning with "." are disallowed. * - * See commit ee8f844e3c5a73b999edf733df1c529d6503ec2f + * See commit + * ee8f844e3c5a ("KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings") */ #include <errno.h> diff --git a/testcases/kernel/syscalls/keyctl/keyctl09.c b/testcases/kernel/syscalls/keyctl/keyctl09.c index cfd5f7e5f..1f24f804a 100644 --- a/testcases/kernel/syscalls/keyctl/keyctl09.c +++ b/testcases/kernel/syscalls/keyctl/keyctl09.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2022 Google, Inc. + * Copyright (c) Linux Test Project, 2023 */ /*\ diff --git a/testcases/kernel/syscalls/lchown/Makefile b/testcases/kernel/syscalls/lchown/Makefile index 305fee281..7c76afea5 100644 --- a/testcases/kernel/syscalls/lchown/Makefile +++ b/testcases/kernel/syscalls/lchown/Makefile @@ -3,6 +3,9 @@ top_srcdir ?= ../../../.. +# Remove after rewriting all tests to the new API. +USE_LEGACY_COMPAT_16_H := 1 + include $(top_srcdir)/include/mk/testcases.mk SRCS := $(sort $(wildcard $(abs_srcdir)/lchown*.c)) diff --git a/testcases/kernel/syscalls/lchown/lchown01.c b/testcases/kernel/syscalls/lchown/lchown01.c index 4e6076e1f..aaa0ef403 100644 --- a/testcases/kernel/syscalls/lchown/lchown01.c +++ b/testcases/kernel/syscalls/lchown/lchown01.c @@ -41,6 +41,11 @@ #include "test.h" #include "safe_macros.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" #define FILE_MODE (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) diff --git a/testcases/kernel/syscalls/lchown/lchown02.c b/testcases/kernel/syscalls/lchown/lchown02.c index 97966f6be..c0932fb7a 100644 --- a/testcases/kernel/syscalls/lchown/lchown02.c +++ b/testcases/kernel/syscalls/lchown/lchown02.c @@ -58,6 +58,11 @@ #include "test.h" #include "safe_macros.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" #define TEST_USER "nobody" diff --git a/testcases/kernel/syscalls/lchown/lchown03.c b/testcases/kernel/syscalls/lchown/lchown03.c index c26f54c21..ecb6ed64d 100644 --- a/testcases/kernel/syscalls/lchown/lchown03.c +++ b/testcases/kernel/syscalls/lchown/lchown03.c @@ -39,6 +39,11 @@ #include "test.h" #include "safe_macros.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting all tests to the new API. + */ #include "compat_16.h" #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ diff --git a/testcases/kernel/syscalls/link/.gitignore b/testcases/kernel/syscalls/link/.gitignore index e5d7f1bbc..b2b9db632 100644 --- a/testcases/kernel/syscalls/link/.gitignore +++ b/testcases/kernel/syscalls/link/.gitignore @@ -1,5 +1,4 @@ /link02 -/link03 /link04 /link05 /link08 diff --git a/testcases/kernel/syscalls/link/link03.c b/testcases/kernel/syscalls/link/link03.c deleted file mode 100644 index 1f45240ae..000000000 --- a/testcases/kernel/syscalls/link/link03.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : Richard Logan - * CO-PILOT : William Roske - * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - */ - - /* - * Tests that link(2) succeds with creating n links. - */ - -#include <sys/types.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void help(void); -static void cleanup(void); - -char *TCID = "link03"; -int TST_TOTAL = 2; - -#define BASENAME "lkfile" - -static char fname[255]; -static int nlinks = 0; -static char *links_arg; - -option_t options[] = { - {"N:", NULL, &links_arg}, - {NULL, NULL, NULL} -}; - -int main(int ac, char **av) -{ - int lc; - struct stat buf; - int i, links; - char lname[255]; - - tst_parse_opts(ac, av, options, &help); - - if (links_arg) { - nlinks = atoi(links_arg); - - if (nlinks == 0) { - tst_brkm(TBROK, NULL, - "nlinks is not a positive number"); - } - - if (nlinks > 1000) { - tst_resm(TINFO, - "nlinks > 1000 - may get errno:%d (EMLINK)", - EMLINK); - } - } - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - if (nlinks) - links = nlinks; - else - links = (lc % 90) + 10; - - /* Create links - 1 hardlinks so that the st_nlink == links */ - for (i = 1; i < links; i++) { - sprintf(lname, "%s%d", fname, i); - TEST(link(fname, lname)); - - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "link(%s, %s) Failed", fname, lname); - } - } - - SAFE_STAT(cleanup, fname, &buf); - - if (buf.st_nlink != (nlink_t)links) { - tst_resm(TFAIL, "Wrong number of links for " - "'%s' have %i, should be %i", - fname, (int)buf.st_nlink, links); - goto unlink; - } - - for (i = 1; i < links; i++) { - sprintf(lname, "%s%d", fname, i); - SAFE_STAT(cleanup, lname, &buf); - if (buf.st_nlink != (nlink_t)links) { - tst_resm(TFAIL, - "Wrong number of links for " - "'%s' have %i, should be %i", - lname, (int)buf.st_nlink, links); - goto unlink; - } - } - - tst_resm(TPASS, "link() passed and linkcounts=%d match", links); - -unlink: - for (i = 1; i < links; i++) { - sprintf(lname, "%s%d", fname, i); - SAFE_UNLINK(cleanup, lname); - } - } - - cleanup(); - tst_exit(); -} - -static void help(void) -{ - printf(" -N #links : create #links hard links every iteration\n"); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - sprintf(fname, "%s_%d", BASENAME, getpid()); - SAFE_TOUCH(cleanup, fname, 0700, NULL); -} - -static void cleanup(void) -{ - tst_rmdir(); -} diff --git a/testcases/kernel/syscalls/link/link05.c b/testcases/kernel/syscalls/link/link05.c index 95787ec24..dfef3d458 100644 --- a/testcases/kernel/syscalls/link/link05.c +++ b/testcases/kernel/syscalls/link/link05.c @@ -1,13 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : Richard Logan - * CO-PILOT : William Roske + * Authors: Richard Logan, William Roske * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2001-2023 */ -/* - * Test if link(2) fails with EMLINK. +/*\ + * [Description] + * + * Tests that link(2) succeeds with creating 1000 links. */ #include <stdio.h> @@ -41,10 +43,8 @@ static void verify_link(void) (fbuf.st_nlink != lbuf.st_nlink)) { tst_res(TFAIL, - "link(%s, %s[1-%d]) ret %ld for %d " - "files, stat values do not match %d %d", - fname, fname, nlinks, - TST_RET, nlinks, + "link(%s, %s[1-%d]) ret %ld for %d files, stat values do not match %d %d", + fname, fname, nlinks, TST_RET, nlinks, (int)fbuf.st_nlink, (int)lbuf.st_nlink); break; } @@ -52,10 +52,8 @@ static void verify_link(void) if (cnt >= nlinks) { tst_res(TPASS, - "link(%s, %s[1-%d]) ret %ld for %d files, " - "stat linkcounts match %d", - fname, fname, nlinks, TST_RET, - nlinks, (int)fbuf.st_nlink); + "link(%s, %s[1-%d]) ret %ld for %d files, stat linkcounts match %d", + fname, fname, nlinks, TST_RET, nlinks, (int)fbuf.st_nlink); } for (cnt = 1; cnt < nlinks; cnt++) { @@ -71,7 +69,7 @@ static void setup(void) } static struct tst_test test = { - .test_all = verify_link, - .setup = setup, - .needs_tmpdir = 1, + .test_all = verify_link, + .setup = setup, + .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/link/link08.c b/testcases/kernel/syscalls/link/link08.c index d3e33d077..92d507489 100644 --- a/testcases/kernel/syscalls/link/link08.c +++ b/testcases/kernel/syscalls/link/link08.c @@ -1,23 +1,26 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2014-2023 * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com> */ -/* - * Test Description: - * Verify that, - * 1. link() fails with -1 return value and sets errno to EPERM - * if oldpath is a directory. - * 2. link() fails with -1 return value and sets errno to EXDEV - * if oldpath and newpath are not on the same mounted file system( Linux - * permits a file system to be mounted at multiple points, but link() - * does not work across different mount points, even if the same - * file system is mounted on both. ). - * 3. link() fails with -1 return value and sets errno to EROFS - * if the file is on a read-only file system. - * 4. link() fails with -1 return value and sets errno to ELOOP - * if too many symbolic links were encountered in resolving path. + +/*\ + * [Description] + * + * Verify that: + * + * - link() fails with EPERM if the old path is a directory. + * - link() fails with EXDEV if the old path and the new path + * are not on the same mounted file system(Linux permits + * a file system to be mounted at multiple points, but link() + * does not work across different mount points, even if the same + * file system is mounted on both). + * - link() fails with EROFS if the file is on a read-only file system. + * - link() fails with ELOOP if too many symbolic links were encountered + * in resolving path. */ + #include <errno.h> #include "tst_test.h" diff --git a/testcases/kernel/syscalls/mkdirat/mkdirat01.c b/testcases/kernel/syscalls/mkdirat/mkdirat01.c index a323ed5b3..ca536bdab 100644 --- a/testcases/kernel/syscalls/mkdirat/mkdirat01.c +++ b/testcases/kernel/syscalls/mkdirat/mkdirat01.c @@ -35,7 +35,6 @@ #include <string.h> #include <signal.h> #include "test.h" -#include "lapi/mkdirat.h" #include "safe_macros.h" static void setup(void); diff --git a/testcases/kernel/syscalls/mkdirat/mkdirat02.c b/testcases/kernel/syscalls/mkdirat/mkdirat02.c index ebc0ed16b..2bd8fe9c0 100644 --- a/testcases/kernel/syscalls/mkdirat/mkdirat02.c +++ b/testcases/kernel/syscalls/mkdirat/mkdirat02.c @@ -11,7 +11,6 @@ #define _GNU_SOURCE #include "tst_test.h" -#include "lapi/mkdirat.h" #define MNT_POINT "mntpoint" #define TEST_DIR "mntpoint/test_dir" diff --git a/testcases/kernel/syscalls/mknodat/mknodat.h b/testcases/kernel/syscalls/mknodat/mknodat.h deleted file mode 100644 index 8f3a1f007..000000000 --- a/testcases/kernel/syscalls/mknodat/mknodat.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2007 - * Copyright (c) 2014 Fujitsu Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef MKNODAT_H -#define MKNODAT_H - -#include <sys/types.h> -#include "config.h" -#include "lapi/syscalls.h" - -#if !defined(HAVE_MKNODAT) -int mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) -{ - return tst_syscall(__NR_mknodat, dirfd, filename, mode, dev); -} -#endif - -#endif /* MKNODAT_H */ diff --git a/testcases/kernel/syscalls/mknodat/mknodat01.c b/testcases/kernel/syscalls/mknodat/mknodat01.c index 6500ca362..3be0a4f87 100644 --- a/testcases/kernel/syscalls/mknodat/mknodat01.c +++ b/testcases/kernel/syscalls/mknodat/mknodat01.c @@ -35,7 +35,6 @@ #include "test.h" #include "safe_macros.h" #include "lapi/fcntl.h" -#include "mknodat.h" #define PATHNAME "mknodattestdir" diff --git a/testcases/kernel/syscalls/mknodat/mknodat02.c b/testcases/kernel/syscalls/mknodat/mknodat02.c index eda247fda..fdac5db15 100644 --- a/testcases/kernel/syscalls/mknodat/mknodat02.c +++ b/testcases/kernel/syscalls/mknodat/mknodat02.c @@ -37,7 +37,7 @@ #include "test.h" #include "safe_macros.h" #include "lapi/fcntl.h" -#include "mknodat.h" +#include "lapi/syscalls.h" static void setup(void); static void cleanup(void); diff --git a/testcases/kernel/syscalls/mmap/mmap04.c b/testcases/kernel/syscalls/mmap/mmap04.c index 43f7b7525..fa85deed1 100644 --- a/testcases/kernel/syscalls/mmap/mmap04.c +++ b/testcases/kernel/syscalls/mmap/mmap04.c @@ -1,185 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> */ -/* - * Test Description: - * Call mmap() to map a file creating a mapped region with read/exec access - * under the following conditions - - * - The prot parameter is set to PROT_READ|PROT_EXEC - * - The file descriptor is open for read - * - The file being mapped has read and execute permission bit set. - * - The minimum file permissions should be 0555. - * - * The call should succeed to map the file creating mapped memory with the - * required attributes. - * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * and the mapped region should contain the contents of the mapped file. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, after a successful mmap() call, permission bits of the new + * mapping in /proc/pid/maps file matches the prot and flags arguments in + * mmap() call. */ +#include <inttypes.h> +#include "tst_test.h" #include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include "test.h" - -#define TEMPFILE "mmapfile" - -char *TCID = "mmap04"; -int TST_TOTAL = 1; - -static size_t page_sz; -static char *addr; -static char *dummy; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static char *addr1; +static char *addr2; + +static struct tcase { + int prot; + int flags; + char *exp_perms; +} tcases[] = { + {PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, "---p"}, + {PROT_NONE, MAP_ANONYMOUS | MAP_SHARED, "---s"}, + {PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, "r--p"}, + {PROT_READ, MAP_ANONYMOUS | MAP_SHARED, "r--s"}, + {PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, "-w-p"}, + {PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, "-w-s"}, + {PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, "rw-p"}, + {PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, "rw-s"}, + {PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, "r-xp"}, + {PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, "r-xs"}, + {PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, "-wxp"}, + {PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, "-wxs"}, + {PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, "rwxp"}, + {PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_SHARED, "rwxs"} +}; + +static void run(unsigned int i) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read and execute access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ | PROT_EXEC, - MAP_FILE | MAP_SHARED, fildes, 0); - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); - continue; - } - - /* - * Read the file contents into the dummy - * variable. - */ - if (read(fildes, dummy, page_sz) < 0) { - tst_brkm(TFAIL, cleanup, "reading %s failed", - TEMPFILE); - } - - /* - * Check whether the mapped memory region - * has the file contents. - */ - if (memcmp(dummy, addr, page_sz)) { - tst_resm(TFAIL, - "mapped memory region contains invalid " - "data"); - } else { - tst_resm(TPASS, - "Functionality of mmap() successful"); - } - - /* Clean up things in case we are looping. */ - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TFAIL, cleanup, "munmapping failed"); - } + struct tcase *tc = &tcases[i]; + char perms[8]; + char fmt[1024]; + unsigned int pagesize; + int flag; + + pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + + /* To avoid new mapping getting merged with existing mappings, we first + * create a 2-page mapping with the different permissions, and then remap + * the 2nd page with the perms being tested. + */ + flag = (tc->flags & MAP_PRIVATE) ? MAP_SHARED : MAP_PRIVATE; + addr1 = SAFE_MMAP(NULL, pagesize * 2, PROT_NONE, MAP_ANONYMOUS | flag, -1, 0); + + addr2 = SAFE_MMAP(addr1 + pagesize, pagesize, tc->prot, tc->flags | MAP_FIXED, -1, 0); + + sprintf(fmt, "%" PRIxPTR "-%%*x %%s", (uintptr_t)addr2); + SAFE_FILE_LINES_SCANF("/proc/self/maps", fmt, perms); + + if (!strcmp(perms, tc->exp_perms)) { + tst_res(TPASS, "mapping permissions in /proc matched: %s", perms); + } else { + tst_res(TFAIL, "mapping permissions in /proc mismatched, expected: %s, found: %s", + tc->exp_perms, perms); } - cleanup(); - tst_exit(); + SAFE_MUNMAP(addr1, pagesize * 2); } -static void setup(void) -{ - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - page_sz = getpagesize(); - - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (ssize_t)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Make sure proper permissions set on file */ - if (fchmod(fildes, 0555) < 0) { - tst_brkm(TFAIL, cleanup, "fchmod of %s failed", TEMPFILE); - } - - /* Close the temporary file opened for write */ - if (close(fildes) < 0) { - tst_brkm(TFAIL, cleanup, "closing %s failed", TEMPFILE); - } - - /* Allocate and initialize dummy string of system page size bytes */ - if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); - } - - /* Open the temporary file again for reading */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL, cleanup, - "opening %s read-only failed", TEMPFILE); - } -} - -static void cleanup(void) -{ - close(fildes); - free(dummy); - tst_rmdir(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/mmap/mmap15.c b/testcases/kernel/syscalls/mmap/mmap15.c index 443a37eb8..71c18a10a 100644 --- a/testcases/kernel/syscalls/mmap/mmap15.c +++ b/testcases/kernel/syscalls/mmap/mmap15.c @@ -1,113 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2004 - * Written by Robbie Williamson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Written by Robbie Williamson + * Copyright (c) 2023 SUSE LLC Avinesh Kumar <avinesh.kumar@suse.com> + * Copyright (c) Linux Test Project, 2014-2023 */ -/* - * Test Description: Test that a normal page cannot be mapped into a high - * memory region. +/*\ + * [Description] + * + * Verify that, a normal page cannot be mapped into a high memory region, + * and mmap() call fails with either ENOMEM or EINVAL errno. */ -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include "test.h" -#include "safe_macros.h" -#include "lapi/abisize.h" - -char *TCID = "mmap15"; -int TST_TOTAL = 1; +#include "tst_test.h" #ifdef __ia64__ -# define HIGH_ADDR (void *)(0xa000000000000000UL) +# define HIGH_ADDR ((void *)(0xa000000000000000UL)) #else -# define HIGH_ADDR (void *)(-page_size) +# define HIGH_ADDR ((void *)(-page_size)) #endif -static long page_size; +#define TEMPFILE "mmapfile" -static void setup(void); -static void cleanup(void); +static long page_size; +static int fd; -int main(int ac, char **av) +static void run(void) { - int lc, fd; - void *addr; - -#ifdef TST_ABI32 - tst_brkm(TCONF, NULL, "This test is only for 64bit"); -#endif + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); - tst_parse_opts(ac, av, NULL, NULL); + TESTPTR(mmap(HIGH_ADDR, page_size, PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0)); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - fd = SAFE_OPEN(cleanup, "testfile", O_RDWR | O_CREAT, 0666); - - /* Attempt to mmap into highmem addr, should get ENOMEM */ - addr = mmap(HIGH_ADDR, page_size, PROT_READ, - MAP_SHARED | MAP_FIXED, fd, 0); - if (addr != MAP_FAILED) { - tst_resm(TFAIL, "mmap into high region " - "succeeded unexpectedly"); - munmap(addr, page_size); - close(fd); - continue; - } - - if (errno != ENOMEM && errno != EINVAL) { - tst_resm(TFAIL | TERRNO, "mmap into high region " - "failed unexpectedly"); - } else { - tst_resm(TPASS | TERRNO, "mmap into high region " - "failed as expected"); - } - - SAFE_CLOSE(cleanup, fd); + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() into high mem region succeeded unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, page_size); + return; } - cleanup(); - tst_exit(); + if (TST_ERR == ENOMEM || TST_ERR == EINVAL) + tst_res(TPASS | TERRNO, "mmap() failed with expected errno"); + else + tst_res(TFAIL | TERRNO, "mmap() failed with unexpected errno"); + + SAFE_CLOSE(fd); } static void setup(void) { - tst_require_root(); - - tst_tmpdir(); - page_size = getpagesize(); - - TEST_PAUSE; } static void cleanup(void) { - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .skip_in_compat = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mount/mount04.c b/testcases/kernel/syscalls/mount/mount04.c index 5969fbacb..5eb5ee11b 100644 --- a/testcases/kernel/syscalls/mount/mount04.c +++ b/testcases/kernel/syscalls/mount/mount04.c @@ -1,119 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * DESCRIPTION - * Verify that mount(2) returns -1 and sets errno to EPERM if the user - * is not the super-user. + * Verify that mount(2) returns -1 and sets errno to EPERM if the user + * is not root. */ -#include <errno.h> -#include <sys/mount.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> +#include "tst_test.h" #include <pwd.h> -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); - -char *TCID = "mount04"; - -#define DIR_MODE S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP - -static char *mntpoint = "mntpoint"; -static const char *fs_type; -static const char *device; - -int TST_TOTAL = 1; - -static void verify_mount(void) -{ - - TEST(mount(device, mntpoint, fs_type, 0, NULL)); - - if (TEST_RETURN == -1) { - if (TEST_ERRNO == EPERM) - tst_resm(TPASS | TTERRNO, "mount() failed expectedly"); - else - tst_resm(TFAIL | TTERRNO, - "mount() was expected to fail with EPERM"); - return; - } +#include <sys/mount.h> - if (TEST_RETURN == 0) { - tst_resm(TFAIL, "mount() succeeded unexpectedly"); - if (tst_umount(mntpoint)) - tst_brkm(TBROK, cleanup, "umount() failed"); - return; - } +#define MNTPOINT "mntpoint" - tst_resm(TFAIL | TTERRNO, "mount() returned %li", TEST_RETURN); -} - -int main(int ac, char **av) +static void cleanup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - verify_mount(); - } - - cleanup(); - tst_exit(); + if (tst_is_mounted(MNTPOINT)) + SAFE_UMOUNT(MNTPOINT); } -static void setup(void) +static void run(void) { - char nobody_uid[] = "nobody"; struct passwd *ltpuser; - tst_sig(FORK, DEF_HANDLER, cleanup); - - tst_require_root(); - - tst_tmpdir(); + ltpuser = SAFE_GETPWNAM("nobody"); + SAFE_SETEUID(ltpuser->pw_uid); - fs_type = tst_dev_fs_type(); - device = tst_acquire_device(cleanup); + TST_EXP_FAIL( + mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL), + EPERM, + "mount() failed expectedly for normal user" + ); - if (!device) - tst_brkm(TCONF, cleanup, "Failed to obtain block device"); - - tst_mkfs(cleanup, device, fs_type, NULL, NULL); - - ltpuser = SAFE_GETPWNAM(cleanup, nobody_uid); - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - SAFE_MKDIR(cleanup, mntpoint, DIR_MODE); - - TEST_PAUSE; + if (tst_is_mounted(MNTPOINT)) + SAFE_UMOUNT(MNTPOINT); } -static void cleanup(void) -{ - if (seteuid(0)) - tst_resm(TWARN | TERRNO, "seteuid(0) failed"); - - if (device) - tst_release_device(device); - - tst_rmdir(); -} +static struct tst_test test = { + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT, +}; diff --git a/testcases/kernel/syscalls/mount/mount05.c b/testcases/kernel/syscalls/mount/mount05.c index ca26f9738..616eeee79 100644 --- a/testcases/kernel/syscalls/mount/mount05.c +++ b/testcases/kernel/syscalls/mount/mount05.c @@ -1,131 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2013 Fujitsu Ltd. - * Author: DAN LI <li.dan@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * Copyright (c) 2013 Fujitsu Ltd. Dan Li <li.dan@cn.fujitsu.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * DESCRIPTION - * Test for feature MS_BIND of mount. - * "Perform a bind mount, making a file or a directory subtree visible - * at another point within a file system." +/*\ + * [Description] + * + * Test for feature MS_BIND of mount, which performs a bind mount, making a file + * or a directory subtree visible at another point within a file system. */ -#include <errno.h> +#include "tst_test.h" #include <sys/mount.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> - -#include "test.h" -#include "safe_macros.h" - -static void help(void); -static void setup(void); -static void cleanup(void); -char *TCID = "mount05"; -int TST_TOTAL = 1; +#define MNTPOINT1 "mntpoint1" +#define TESTFILE1 MNTPOINT1 "/testfile" +#define TESTDIR1 MNTPOINT1 "/testdir" -#define DIR_MODE (S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP) +#define MNTPOINT2 "mntpoint2" +#define TESTFILE2 MNTPOINT2 "/testfile" +#define TESTDIR2 MNTPOINT2 "/testdir" -static int dflag; -static char *fstype = "ext2"; -static char *device; -static const char file_src[] = "mnt_src/tstfile"; -static const char file_des[] = "mnt_des/tstfile"; -static const char mntpoint_src[] = "mnt_src"; -static const char mntpoint_des[] = "mnt_des"; - -static option_t options[] = { - {"T:", NULL, &fstype}, - {"D:", &dflag, &device}, - {NULL, NULL, NULL}, -}; - -int main(int argc, char *argv[]) +static void setup(void) { - int lc; - - tst_parse_opts(argc, argv, options, &help); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; + SAFE_MOUNT(tst_device->dev, MNTPOINT1, tst_device->fs_type, 0, NULL); - TEST(mount(mntpoint_src, mntpoint_des, fstype, MS_BIND, NULL)); + tst_res(TINFO, "Creating file in '%s'", TESTFILE1); - if (TEST_RETURN != 0) { - tst_resm(TFAIL | TTERRNO, "mount(2) failed"); - } else { - - if (open(file_des, O_CREAT | O_EXCL, S_IRWXU) == -1 && - errno == EEXIST) - tst_resm(TPASS, "bind mount is ok"); - else - tst_resm(TFAIL, "file %s is not available", - file_des); - - TEST(tst_umount(mntpoint_des)); - if (TEST_RETURN != 0) - tst_brkm(TBROK | TTERRNO, cleanup, - "umount(2) failed"); - } - } - - cleanup(); - tst_exit(); + SAFE_FILE_PRINTF(TESTFILE1, "LTP TEST FILE"); + SAFE_MKDIR(TESTDIR1, 0750); } -void setup(void) +static void cleanup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - SAFE_MKDIR(cleanup, mntpoint_src, DIR_MODE); - SAFE_MKDIR(cleanup, mntpoint_des, DIR_MODE); - - if (dflag) { - tst_mkfs(NULL, device, fstype, NULL, NULL); + if (tst_is_mounted(MNTPOINT1)) + SAFE_UMOUNT(MNTPOINT1); - SAFE_MOUNT(cleanup, device, mntpoint_src, fstype, 0, NULL); - } - - SAFE_FILE_PRINTF(cleanup, file_src, "TEST FILE"); - - TEST_PAUSE; + if (tst_is_mounted(MNTPOINT2)) + SAFE_UMOUNT(MNTPOINT2); } -void cleanup(void) +static void run(void) { - if (dflag) - if (tst_umount(mntpoint_src) != 0) - tst_brkm(TBROK | TTERRNO, NULL, "umount(2) failed"); + SAFE_MKDIR(MNTPOINT2, 0750); + SAFE_MOUNT(MNTPOINT1, MNTPOINT2, tst_device->fs_type, MS_BIND, NULL); - tst_rmdir(); -} + TST_EXP_PASS(access(TESTFILE2, F_OK), "Accessing to '%s'", TESTFILE2); + TST_EXP_PASS(access(TESTDIR2, F_OK), "Accessing to '%s'", TESTDIR2); -void help(void) -{ - printf("-T type : specifies the type of filesystem to be mounted. " - "Default ext2.\n"); - printf("-D device : device used for mounting.\n"); + if (tst_is_mounted(MNTPOINT2)) + SAFE_UMOUNT(MNTPOINT2); + + SAFE_RMDIR(MNTPOINT2); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT1, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){ + "exfat", + "vfat", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/mount/mount06.c b/testcases/kernel/syscalls/mount/mount06.c index 857f5f905..2376deab3 100644 --- a/testcases/kernel/syscalls/mount/mount06.c +++ b/testcases/kernel/syscalls/mount/mount06.c @@ -1,34 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2013 Fujitsu Ltd. - * Author: DAN LI <li.dan@cn.fujitsu.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * Copyright (c) 2013 Fujitsu Ltd. Dan Li <li.dan@cn.fujitsu.com> + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ -/* - * DESCRIPTION - * Test for feature MS_MOVE of mount(2). - * "Move an existing mount point to the new location." +/*\ + * [Description] + * + * Test for feature MS_MOVE of mount, which moves an existing mount point to + * a new location. */ -#include <errno.h> +#include "tst_test.h" +#include <stdio.h> #include <sys/mount.h> -#include <unistd.h> -#include <fcntl.h> - -#include "test.h" -#include "safe_macros.h" #ifndef MS_MOVE #define MS_MOVE 8192 @@ -38,126 +23,86 @@ #define MS_PRIVATE (1 << 18) #endif -#define MNTPOINT_SRC "mnt_src" -#define MNTPOINT_DES "mnt_des" -#define LINELENGTH 256 -#define DIR_MODE (S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP) - -static int ismount(char *mntpoint); -static void setup(void); -static void cleanup(void); +#define MNTPOINT_SRC "mntpoint1" +#define MNTPOINT_DST "mntpoint2" -char *TCID = "mount06"; -int TST_TOTAL = 1; - -static const char *fs_type; -static const char *device; -static char path_name[PATH_MAX]; +static char *tmppath; static char mntpoint_src[PATH_MAX]; -static char mntpoint_des[PATH_MAX]; -static int mount_flag; +static char mntpoint_dst[PATH_MAX]; +static char tstfiles_src[PATH_MAX]; +static char tstfiles_dst[PATH_MAX]; -int main(int argc, char *argv[]) +static void setup(void) { - int lc; + tmppath = tst_get_tmpdir(); - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - SAFE_MOUNT(cleanup, device, mntpoint_src, fs_type, 0, NULL); - - TEST(mount(mntpoint_src, mntpoint_des, fs_type, MS_MOVE, NULL)); - - if (TEST_RETURN != 0) { - tst_resm(TFAIL | TTERRNO, "mount(2) failed"); - } else { - - if (!ismount(mntpoint_src) && ismount(mntpoint_des)) - tst_resm(TPASS, "move mount is ok"); - else - tst_resm(TFAIL, "move mount does not work"); + /* + * Turn current dir into a private mount point being a parent + * mount which is required by move mount. + */ + SAFE_MOUNT(tmppath, tmppath, "none", MS_BIND, NULL); + SAFE_MOUNT("none", tmppath, "none", MS_PRIVATE, NULL); - TEST(tst_umount(mntpoint_des)); - if (TEST_RETURN != 0) - tst_brkm(TBROK | TTERRNO, cleanup, - "umount(2) failed"); - } - } + snprintf(mntpoint_src, PATH_MAX, "%s/%s", tmppath, MNTPOINT_SRC); + snprintf(mntpoint_dst, PATH_MAX, "%s/%s", tmppath, MNTPOINT_DST); - cleanup(); - tst_exit(); -} + snprintf(tstfiles_src, PATH_MAX, "%s/%s/testfile", tmppath, MNTPOINT_SRC); + snprintf(tstfiles_dst, PATH_MAX, "%s/%s/testfile", tmppath, MNTPOINT_DST); -int ismount(char *mntpoint) -{ - int ret = 0; - FILE *file; - char line[LINELENGTH]; - - file = fopen("/proc/mounts", "r"); - if (file == NULL) - tst_brkm(TFAIL | TERRNO, NULL, "Open /proc/mounts failed"); - - while (fgets(line, LINELENGTH, file) != NULL) { - if (strstr(line, mntpoint) != NULL) { - ret = 1; - break; - } - } - fclose(file); - return ret; + SAFE_MKDIR(mntpoint_dst, 0750); } -static void setup(void) +static void cleanup(void) { - tst_require_root(); + if (tst_is_mounted(mntpoint_src)) + SAFE_UMOUNT(mntpoint_src); - tst_sig(NOFORK, DEF_HANDLER, cleanup); + if (tst_is_mounted(mntpoint_dst)) + SAFE_UMOUNT(mntpoint_dst); - tst_tmpdir(); + if (tst_is_mounted(tmppath)) + SAFE_UMOUNT(tmppath); - fs_type = tst_dev_fs_type(); - device = tst_acquire_device(cleanup); - - if (!device) - tst_brkm(TCONF, cleanup, "Failed to obtain block device"); - - tst_mkfs(cleanup, device, fs_type, NULL, NULL); - - if (getcwd(path_name, sizeof(path_name)) == NULL) - tst_brkm(TBROK, cleanup, "getcwd failed"); + SAFE_RMDIR(mntpoint_dst); +} - /* - * Turn current dir into a private mount point being a parent - * mount which is required by move mount. - */ - SAFE_MOUNT(cleanup, path_name, path_name, "none", MS_BIND, NULL); +static void run(void) +{ + SAFE_MOUNT(tst_device->dev, mntpoint_src, tst_device->fs_type, 0, NULL); + SAFE_FILE_PRINTF(tstfiles_src, "LTP TEST FILE"); - mount_flag = 1; + SAFE_MOUNT(mntpoint_src, mntpoint_dst, tst_device->fs_type, MS_MOVE, NULL); - SAFE_MOUNT(cleanup, "none", path_name, "none", MS_PRIVATE, NULL); + TST_EXP_FAIL( + access(tstfiles_src, F_OK), + ENOENT, + "File %s doesn't exist", + tstfiles_src); - snprintf(mntpoint_src, PATH_MAX, "%s/%s", path_name, MNTPOINT_SRC); - snprintf(mntpoint_des, PATH_MAX, "%s/%s", path_name, MNTPOINT_DES); + TST_EXP_PASS( + access(tstfiles_dst, F_OK), + "File %s exists :", + tstfiles_dst); - SAFE_MKDIR(cleanup, mntpoint_src, DIR_MODE); - SAFE_MKDIR(cleanup, mntpoint_des, DIR_MODE); + if (tst_is_mounted(mntpoint_src)) + SAFE_UMOUNT(mntpoint_src); - TEST_PAUSE; + if (tst_is_mounted(mntpoint_dst)) + SAFE_UMOUNT(mntpoint_dst); } -static void cleanup(void) -{ - if (mount_flag && tst_umount(path_name) != 0) - tst_resm(TWARN | TERRNO, "umount(2) %s failed", path_name); - - if (device) - tst_release_device(device); - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT_SRC, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){ + "exfat", + "vfat", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/mremap/mremap06.c b/testcases/kernel/syscalls/mremap/mremap06.c index a19262750..3bbaf441a 100644 --- a/testcases/kernel/syscalls/mremap/mremap06.c +++ b/testcases/kernel/syscalls/mremap/mremap06.c @@ -18,15 +18,16 @@ #include <stdio.h> #include <fcntl.h> #include <sys/mman.h> +#include <lapi/mmap.h> #include "tst_test.h" #include "tst_safe_macros.h" -#define NUM_PAGES 3 +#define NUM_GRANULARITYS 3 static int fd; static char *buf, *buf2; -static int page_size, mmap_size, mremap_size; +static int mmap_size, mremap_size; static struct tcase { size_t incompatible; @@ -37,11 +38,11 @@ static struct tcase { }, { .incompatible = 3, - .desc = "third page's mapping incompatible", + .desc = "third MMAP_GRANULARITY's mapping incompatible", }, { .incompatible = 1, - .desc = "first page's mapping incompatible", + .desc = "first MMAP_GRANULARITY's mapping incompatible", }, }; @@ -51,7 +52,7 @@ static int check_pages(void) char val; for (i = 0; i < (int)ARRAY_SIZE(tcases); i++) { - val = buf[i * page_size]; + val = buf[i * MMAP_GRANULARITY]; if (val != 0x30 + i) { tst_res(TFAIL, "page %d wrong value %d (0x%x)", i, val - 0x30, val); fail = 1; @@ -70,19 +71,20 @@ static void do_test(unsigned int n) buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - buf2 = mremap(buf + page_size, page_size, page_size, + buf2 = mremap(buf + MMAP_GRANULARITY, MMAP_GRANULARITY, MMAP_GRANULARITY, MREMAP_MAYMOVE|MREMAP_FIXED, buf + mremap_size); if (buf2 == MAP_FAILED) tst_brk(TBROK, "mremap() failed"); if (tc->incompatible) { - ret = mprotect(buf + (tc->incompatible-1)*page_size, page_size, PROT_READ); + ret = mprotect(buf + (tc->incompatible-1)*MMAP_GRANULARITY, + MMAP_GRANULARITY, PROT_READ); if (ret == -1) tst_brk(TBROK, "mprotect() failed"); } - buf2 = mremap(buf + mremap_size, page_size, page_size, - MREMAP_MAYMOVE|MREMAP_FIXED, buf + page_size); + buf2 = mremap(buf + mremap_size, MMAP_GRANULARITY, MMAP_GRANULARITY, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + MMAP_GRANULARITY); if (buf2 == MAP_FAILED) tst_brk(TBROK, "mremap() failed"); @@ -96,9 +98,8 @@ static void setup(void) { int ret, i; - page_size = getpagesize(); - mmap_size = (NUM_PAGES+1) * page_size; - mremap_size = NUM_PAGES * page_size; + mmap_size = (NUM_GRANULARITYS+1) * MMAP_GRANULARITY; + mremap_size = NUM_GRANULARITYS * MMAP_GRANULARITY; fd = SAFE_OPEN("testfile", O_CREAT | O_RDWR | O_TRUNC, 0600); @@ -109,7 +110,7 @@ static void setup(void) buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); for (i = 0; i < (int)ARRAY_SIZE(tcases)+1; i++) - buf[i*page_size] = 0x30 + i; + buf[i*MMAP_GRANULARITY] = 0x30 + i; /* clear the page tables */ SAFE_MUNMAP(buf, mmap_size); diff --git a/testcases/kernel/syscalls/open/open11.c b/testcases/kernel/syscalls/open/open11.c index 3c3c11b84..3431efc2c 100644 --- a/testcases/kernel/syscalls/open/open11.c +++ b/testcases/kernel/syscalls/open/open11.c @@ -1,28 +1,34 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2013 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2013-2022 + */ + +/*\ + * [Description] * * Basic tests for open(2) and make sure open(2) works and handles error * conditions correctly. * * There are 28 test cases: + * * 1. Open regular file O_RDONLY * 2. Open regular file O_WRONLY * 3. Open regular file O_RDWR * 4. Open regular file O_RDWR | O_SYNC * 5. Open regular file O_RDWR | O_TRUNC - * 6. Open dir O_RDONLY - * 7. Open dir O_RDWR, expect EISDIR + * 6. Open directory O_RDONLY + * 7. Open directory O_RDWR, expect EISDIR * 8. Open regular file O_DIRECTORY, expect ENOTDIR * 9. Open hard link file O_RDONLY * 10. Open hard link file O_WRONLY * 11. Open hard link file O_RDWR - * 12. Open sym link file O_RDONLY - * 13. Open sym link file O_WRONLY - * 14. Open sym link file O_RDWR - * 15. Open sym link dir O_RDONLY - * 16. Open sym link dir O_WRONLY, expect EISDIR - * 17. Open sym link dir O_RDWR, expect EISDIR + * 12. Open symlink file O_RDONLY + * 13. Open symlink file O_WRONLY + * 14. Open symlink file O_RDWR + * 15. Open symlink directory O_RDONLY + * 16. Open symlink directory O_WRONLY, expect EISDIR + * 17. Open symlink directory O_RDWR, expect EISDIR * 18. Open device special file O_RDONLY * 19. Open device special file O_WRONLY * 20. Open device special file O_RDWR @@ -30,8 +36,8 @@ * 22. Open link file O_RDONLY | O_CREAT * 23. Open symlink file O_RDONLY | O_CREAT * 24. Open regular file O_RDONLY | O_CREAT - * 25. Open symlink dir O_RDONLY | O_CREAT, expect EISDIR - * 26. Open dir O_RDONLY | O_CREAT, expect EISDIR + * 25. Open symlink directory O_RDONLY | O_CREAT, expect EISDIR + * 26. Open directory O_RDONLY | O_CREAT, expect EISDIR * 27. Open regular file O_RDONLY | O_TRUNC, behaviour is undefined but should * not oops or hang * 28. Open regular file(non-empty) O_RDONLY | O_TRUNC, behaviour is undefined @@ -54,7 +60,7 @@ #define T_LINK_REG "t_link_reg" /* hard link to T_REG */ #define T_NEW_REG "t_new_reg" /* new regular file to be created */ #define T_SYMLINK_REG "t_symlink_reg" /* symlink to T_REG */ -#define T_DIR "t_dir" /* test dir */ +#define T_DIR "t_dir" /* test directory */ #define T_SYMLINK_DIR "t_symlink_dir" /* symlink to T_DIR */ #define T_DEV MNTPOINT"/t_dev" /* test device special file */ @@ -68,205 +74,191 @@ static struct test_case { int err; } tc[] = { /* Test open(2) regular file */ - { /* open regular file O_RDONLY */ - .desc = "Open regular file O_RDONLY", + { + .desc = "open regular file O_RDONLY", .path = T_REG_EMPTY, .flags = O_RDONLY, .mode = 0644, - .err = 0, }, - { /* open regular file O_WRONLY */ - .desc = "Open regular file O_WRONLY", + { + .desc = "open regular file O_WRONLY", .path = T_REG_EMPTY, .flags = O_WRONLY, .mode = 0644, - .err = 0, }, - { /* open regular file O_RDWR */ - .desc = "Open regular file O_RDWR", + { + .desc = "open regular file O_RDWR", .path = T_REG_EMPTY, .flags = O_RDWR, .mode = 0644, - .err = 0, }, - { /* open regular file O_RDWR | O_SYNC*/ - .desc = "Open regular file O_RDWR | O_SYNC", + { + .desc = "open regular file O_RDWR | O_SYNC", .path = T_REG_EMPTY, .flags = O_RDWR | O_SYNC, .mode = 0644, - .err = 0, }, - { /* open regular file O_RDWR | O_TRUNC */ - .desc = "Open regular file O_RDWR | O_TRUNC", + { + .desc = "open regular file O_RDWR | O_TRUNC", .path = T_REG_EMPTY, .flags = O_RDWR | O_TRUNC, .mode = 0644, - .err = 0, }, + /* Test open(2) directory */ - { /* open dir O_RDONLY */ - .desc = "Open dir O_RDONLY", + { + .desc = "open directory O_RDONLY", .path = T_DIR, .flags = O_RDONLY, .mode = 0755, - .err = 0, }, - { /* open dir O_RDWR */ - .desc = "Open dir O_RDWR, expect EISDIR", + { + .desc = "open directory O_RDWR", .path = T_DIR, .flags = O_RDWR, .mode = 0755, .err = EISDIR, }, - { /* open regular file O_DIRECTORY */ - .desc = "Open regular file O_DIRECTORY, expect ENOTDIR", + { + .desc = "open regular file O_DIRECTORY", .path = T_REG_EMPTY, .flags = O_RDONLY | O_DIRECTORY, .mode = 0644, .err = ENOTDIR, }, /* Test open(2) hard link */ - { /* open hard link file O_RDONLY */ - .desc = "Open hard link file O_RDONLY", + { + .desc = "open hard link file O_RDONLY", .path = T_LINK_REG, .flags = O_RDONLY, .mode = 0644, - .err = 0, }, - { /* open hard link file O_WRONLY */ - .desc = "Open hard link file O_WRONLY", + { + .desc = "open hard link file O_WRONLY", .path = T_LINK_REG, .flags = O_WRONLY, .mode = 0644, - .err = 0, }, - { /* open hard link file O_RDWR */ - .desc = "Open hard link file O_RDWR", + { + .desc = "open hard link file O_RDWR", .path = T_LINK_REG, .flags = O_RDWR, .mode = 0644, - .err = 0, }, - /* Test open(2) sym link */ - { /* open sym link file O_RDONLY */ - .desc = "Open sym link file O_RDONLY", + + /* Test open(2) symlink */ + { + .desc = "open symlink file O_RDONLY", .path = T_SYMLINK_REG, .flags = O_RDONLY, .mode = 0644, - .err = 0, }, - { /* open sym link file O_WRONLY */ - .desc = "Open sym link file O_WRONLY", + { + .desc = "open symlink file O_WRONLY", .path = T_SYMLINK_REG, .flags = O_WRONLY, .mode = 0644, - .err = 0, }, - { /* open sym link file O_RDWR */ - .desc = "Open sym link file O_RDWR", + { + .desc = "open symlink file O_RDWR", .path = T_SYMLINK_REG, .flags = O_RDWR, .mode = 0644, - .err = 0, }, - { /* open sym link dir O_RDONLY */ - .desc = "Open sym link dir O_RDONLY", + { + .desc = "open symlink directory O_RDONLY", .path = T_SYMLINK_DIR, .flags = O_RDONLY, .mode = 0644, - .err = 0, }, - { /* open sym link dir O_WRONLY */ - .desc = "Open sym link dir O_WRONLY, expect EISDIR", + { + .desc = "open symlink directory O_WRONLY", .path = T_SYMLINK_DIR, .flags = O_WRONLY, .mode = 0644, .err = EISDIR, }, - { /* open sym link dir O_RDWR */ - .desc = "Open sym link dir O_RDWR, expect EISDIR", + { + .desc = "open symlink directory O_RDWR", .path = T_SYMLINK_DIR, .flags = O_RDWR, .mode = 0644, .err = EISDIR, }, - /* * Test open(2) device special */ - { /* open device special file O_RDONLY */ - .desc = "Open device special file O_RDONLY", + + /* Test open(2) device special */ + { + .desc = "open device special file O_RDONLY", .path = T_DEV, .flags = O_RDONLY, .mode = 0644, - .err = 0, }, - { /* open device special file O_WRONLY */ - .desc = "Open device special file O_WRONLY", + { + .desc = "open device special file O_WRONLY", .path = T_DEV, .flags = O_WRONLY, .mode = 0644, - .err = 0, }, - { /* open device special file O_RDWR */ - .desc = "Open device special file O_RDWR", + { + .desc = "open device special file O_RDWR", .path = T_DEV, .flags = O_RDWR, .mode = 0644, - .err = 0, }, - /* * Test open(2) non-existing file */ - { /* open non-existing regular file in existing dir */ - .desc = "Open non-existing regular file in existing dir", + + /* Test open(2) non-existing file */ + { + .desc = "open non-existing regular file in existing dir", .path = T_DIR"/"T_NEW_REG, .flags = O_RDWR | O_CREAT, .mode = 0644, - .err = 0, }, + /* test open(2) with O_CREAT */ - { /* open hard link file O_RDONLY | O_CREAT */ - .desc = "Open link file O_RDONLY | O_CREAT", + { + .desc = "open link file O_RDONLY | O_CREAT", .path = T_LINK_REG, .flags = O_RDONLY | O_CREAT, .mode = 0644, - .err = 0, }, - { /* open sym link file O_RDONLY | O_CREAT */ - .desc = "Open symlink file O_RDONLY | O_CREAT", + { + .desc = "open symlink file O_RDONLY | O_CREAT", .path = T_SYMLINK_REG, .flags = O_RDONLY | O_CREAT, .mode = 0644, - .err = 0, }, - { /* open regular file O_RDONLY | O_CREAT */ - .desc = "Open regular file O_RDONLY | O_CREAT", + { + .desc = "open regular file O_RDONLY | O_CREAT", .path = T_REG_EMPTY, .flags = O_RDONLY | O_CREAT, .mode = 0644, - .err = 0, }, - { /* open symlink dir O_RDONLY | O_CREAT */ - .desc = "Open symlink dir O_RDONLY | O_CREAT, expect EISDIR", + { + .desc = "open symlink directory O_RDONLY | O_CREAT", .path = T_SYMLINK_DIR, .flags = O_RDONLY | O_CREAT, .mode = 0644, .err = EISDIR, }, - { /* open dir O_RDONLY | O_CREAT */ - .desc = "Open dir O_RDONLY | O_CREAT, expect EISDIR", + { + .desc = "open directory O_RDONLY | O_CREAT", .path = T_DIR, .flags = O_RDONLY | O_CREAT, .mode = 0644, .err = EISDIR, }, + /* Other random open(2) tests */ - { /* open regular file O_RDONLY | O_TRUNC */ - .desc = "Open regular file O_RDONLY | O_TRUNC, " + { + .desc = "open regular file O_RDONLY | O_TRUNC, " "behaviour is undefined but should not oops or hang", .path = T_REG_EMPTY, .flags = O_RDONLY | O_TRUNC, .mode = 0644, .err = -1, }, - { /* open regular(non-empty) file O_RDONLY | O_TRUNC */ - .desc = "Open regular file(non-empty) O_RDONLY | O_TRUNC, " + { + .desc = "open regular file(non-empty) O_RDONLY | O_TRUNC, " "behaviour is undefined but should not oops or hang", .path = T_REG, .flags = O_RDONLY | O_TRUNC, diff --git a/testcases/kernel/syscalls/pathconf/.gitignore b/testcases/kernel/syscalls/pathconf/.gitignore index 31abe8a28..82e38b253 100644 --- a/testcases/kernel/syscalls/pathconf/.gitignore +++ b/testcases/kernel/syscalls/pathconf/.gitignore @@ -1 +1,2 @@ /pathconf01 +/pathconf02 diff --git a/testcases/kernel/syscalls/pathconf/pathconf01.c b/testcases/kernel/syscalls/pathconf/pathconf01.c index 362bae94f..66b8d1fc1 100644 --- a/testcases/kernel/syscalls/pathconf/pathconf01.c +++ b/testcases/kernel/syscalls/pathconf/pathconf01.c @@ -1,237 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Copyright (c) Linux Test Project, 2000-2023 + * Authors: William Roske, Dave Fenner */ -/* $Id: pathconf01.c,v 1.5 2009/11/02 13:57:17 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : pathconf01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for pathconf(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 6 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) pathconf(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - * - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the pathconf(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * pathconf(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -void setup(); -void cleanup(); -void help(); - -struct pathconf_args { - char *define_tag; - int value; -} args[] = { - { - "_PC_LINK_MAX", _PC_LINK_MAX}, { - "_PC_NAME_MAX", _PC_NAME_MAX}, { - "_PC_PATH_MAX", _PC_PATH_MAX}, { - "_PC_PIPE_BUF", _PC_PIPE_BUF}, { - "_PC_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED}, { - "_PC_NO_TRUNC", _PC_NO_TRUNC}, { - NULL, 0} -}; - -char *TCID = "pathconf01"; -int TST_TOTAL = ARRAY_SIZE(args); +/*\ + * [Description] + * + * Check the basic functionality of the pathconf(2) system call. + */ -int i; +#include <stdlib.h> +#include "tst_test.h" +#define NAME_DESC(x) .value = x, .name = #x -int lflag; -char *path; +static char *path; -option_t options[] = { - {"l:", &lflag, &path}, /* -l <path to test> */ - {NULL, NULL, NULL} +static struct tcase { + int value; + char *name; +} tcases[] = { + {NAME_DESC(_PC_LINK_MAX)}, + {NAME_DESC(_PC_MAX_CANON)}, + {NAME_DESC(_PC_MAX_INPUT)}, + {NAME_DESC(_PC_NAME_MAX)}, + {NAME_DESC(_PC_PATH_MAX)}, + {NAME_DESC(_PC_PIPE_BUF)}, + {NAME_DESC(_PC_CHOWN_RESTRICTED)}, + {NAME_DESC(_PC_NO_TRUNC)}, + {NAME_DESC(_PC_VDISABLE)}, + {NAME_DESC(_PC_SYNC_IO)}, + {NAME_DESC(_PC_ASYNC_IO)}, + {NAME_DESC(_PC_PRIO_IO)}, + {NAME_DESC(_PC_FILESIZEBITS)}, + {NAME_DESC(_PC_REC_INCR_XFER_SIZE)}, + {NAME_DESC(_PC_REC_MAX_XFER_SIZE)}, + {NAME_DESC(_PC_REC_MIN_XFER_SIZE)}, + {NAME_DESC(_PC_REC_XFER_ALIGN)}, }; -int main(int ac, char **av) +static void verify_pathconf(unsigned int i) { - int lc; + struct tcase *tc = &tcases[i]; - tst_parse_opts(ac, av, options, &help); + path = tst_get_tmpdir(); - if (!lflag) { - tst_tmpdir(); - path = tst_get_tmpdir(); - } - /*************************************************************** - * perform global setup for test - ***************************************************************/ - setup(); + TEST(pathconf(path, tc->value)); - /*************************************************************** - * check looping state if -c option given - ***************************************************************/ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - errno = -4; - - /* - * Call pathconf(2) - */ - TEST(pathconf(path, args[i].value)); - - /* - * A test case can only fail if -1 is returned and the errno - * was set. If the errno remains unchanged, the - * system call did not fail. - */ - if (TEST_RETURN == -1 && errno != -4) { - tst_resm(TFAIL, - "pathconf(%s, %s) Failed, errno=%d : %s", - path, args[i].define_tag, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "pathconf(%s, %s) returned %ld", - path, args[i].define_tag, - TEST_RETURN); - } - } - } - - /*************************************************************** - * cleanup and exit - ***************************************************************/ - cleanup(); - - tst_exit(); + if (TST_RET == -1 && errno != 0) + tst_res(TFAIL, "pathconf Failed, errno = %d", TST_ERR); + else + tst_res(TPASS, "pathconf(%s, %s)", path, tc->name); } -/*************************************************************** - * setup() - performs all ONE TIME setup for this test. - ***************************************************************/ -void setup(void) +static void cleanup(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -/*************************************************************** - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - ***************************************************************/ -void cleanup(void) -{ - if (!lflag) { - tst_rmdir(); - free(path); - } + free(path); } -/*************************************************************** - * help - ***************************************************************/ -void help(void) -{ - printf(" -l path a path to test with pathconf(2) (def: /tmp)\n"); -} +static struct tst_test test = { + .needs_tmpdir = 1, + .test = verify_pathconf, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/pathconf/pathconf02.c b/testcases/kernel/syscalls/pathconf/pathconf02.c new file mode 100644 index 000000000..3fb2cdbe8 --- /dev/null +++ b/testcases/kernel/syscalls/pathconf/pathconf02.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> + */ + +/*\ + * [Description] + * + * Verify that, + * + * - pathconf() fails with ENOTDIR if a component used as a directory + * in path is not in fact a directory. + * - pathconf() fails with ENOENT if path is an empty string. + * - pathconf() fails with ENAMETOOLONG if path is too long. + * - pathconf() fails with EINVA if name is invalid. + * - pathconf() fails with EACCES if search permission is denied for + * one of the directories in the path prefix of path. + * - pathconf() fails with ELOOP if too many symbolic links were + * encountered while resolving path. + */ + +#define FILEPATH "testfile/testfile_1" +#define TESTELOOP "test_eloop1" +#define PATH_LEN (PATH_MAX + 2) + +#include <stdlib.h> +#include <pwd.h> +#include "tst_test.h" + +static char *fpath; +static char *emptypath; +static char path[PATH_LEN]; +static char *long_path = path; +static char *abs_path; +static char *testeloop; +static struct passwd *user; + +static struct tcase { + char **path; + int name; + int exp_errno; + char *desc; +} tcases[] = { + {&fpath, 0, ENOTDIR, "path prefix is not a directory"}, + {&emptypath, 0, ENOENT, "path is an empty string"}, + {&long_path, 0, ENAMETOOLONG, "path is too long"}, + {&abs_path, -1, EINVAL, "name is invalid"}, + {&abs_path, 0, EACCES, "without full permissions of the path prefix"}, + {&testeloop, 0, ELOOP, "too many symbolic links"}, +}; + +static void verify_fpathconf(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(user->pw_uid); + + TST_EXP_FAIL(pathconf(*tc->path, tc->name), tc->exp_errno, + "pathconf() fail with %s", tc->desc); + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(0); +} + +static void setup(void) +{ + user = SAFE_GETPWNAM("nobody"); + + SAFE_TOUCH("testfile", 0777, NULL); + + char *tmpdir = tst_get_tmpdir(); + + abs_path = tst_aprintf("%s/%s", tmpdir, FILEPATH); + + SAFE_CHMOD(tmpdir, 0); + free(tmpdir); + + memset(path, 'a', PATH_LEN); + + SAFE_SYMLINK("test_eloop1", "test_eloop2"); + SAFE_SYMLINK("test_eloop2", "test_eloop1"); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = verify_fpathconf, + .setup = setup, + .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&fpath, .str = FILEPATH}, + {&emptypath, .str = ""}, + {&testeloop, .str = TESTELOOP}, + {}, + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/pipe/.gitignore b/testcases/kernel/syscalls/pipe/.gitignore index 774d73205..581a68b78 100644 --- a/testcases/kernel/syscalls/pipe/.gitignore +++ b/testcases/kernel/syscalls/pipe/.gitignore @@ -12,3 +12,4 @@ /pipe12 /pipe13 /pipe14 +/pipe15 diff --git a/testcases/kernel/syscalls/pipe/pipe15.c b/testcases/kernel/syscalls/pipe/pipe15.c new file mode 100644 index 000000000..c85ad1820 --- /dev/null +++ b/testcases/kernel/syscalls/pipe/pipe15.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC Marius Kittler <mkittler@suse.de> + */ + +/*\ + * [Description] + * + * This is a regression test for hangup on pipe operations. See + * https://www.spinics.net/lists/linux-api/msg49762.html for + * additional context. It tests that pipe operations do not block + * indefinitely when going to the soft limit on the total size of + * all pipes created by a single user. + */ + +#define _GNU_SOURCE +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include "tst_safe_macros.h" + +static int pipe_count; +static int *pipes; +static char *buffer; + +static void run(void) +{ + const int *const pipe = pipes + 2 * (pipe_count - 1); + const int buffer_size = SAFE_FCNTL(pipe[1], F_GETPIPE_SZ); + + tst_res(TINFO, "Soft-limited buffer size: %d bytes", buffer_size); + SAFE_WRITE(1, pipe[1], buffer, buffer_size); + SAFE_READ(1, pipe[0], buffer, buffer_size - 1); + SAFE_WRITE(1, pipe[1], buffer, 1); + tst_res(TPASS, "Pipe operation did not block"); + + SAFE_READ(1, pipe[0], buffer, 2); +} + +static void setup(void) +{ + int pipe[2]; + int page_size = getpagesize(), soft_limit; + struct rlimit nfd; + + SAFE_PIPE(pipe); + const int buffer_size = SAFE_FCNTL(pipe[1], F_GETPIPE_SZ); + SAFE_CLOSE(pipe[0]); + SAFE_CLOSE(pipe[1]); + + SAFE_FILE_SCANF("/proc/sys/fs/pipe-user-pages-soft", "%i", &soft_limit); + pipe_count = soft_limit * page_size / buffer_size; + + tst_res(TINFO, "Soft limit for pipes: %i pages", soft_limit); + tst_res(TINFO, "Buffer size: %d byte", buffer_size); + tst_res(TINFO, "Creating %i pipes", pipe_count); + + SAFE_GETRLIMIT(RLIMIT_NOFILE, &nfd); + if (nfd.rlim_max < (unsigned long)pipe_count) + tst_brk(TCONF, "NOFILE limit max too low: %lu < %i", nfd.rlim_max, pipe_count); + if (nfd.rlim_cur < nfd.rlim_max) { + nfd.rlim_cur = nfd.rlim_max; + SAFE_SETRLIMIT(RLIMIT_NOFILE, &nfd); + } + + buffer = SAFE_MALLOC(buffer_size); + pipes = SAFE_MALLOC(pipe_count * 2 * sizeof(int)); + for (int i = 0; i < pipe_count; ++i) + SAFE_PIPE(pipes + i * 2); + +} + +static void cleanup(void) +{ + for (int i = 0; i < pipe_count * 2; i++) + if (pipes[i] > 0) + SAFE_CLOSE(pipes[i]); + if (pipes) + free(pipes); + if (buffer) + free(buffer); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup, + .tags = (const struct tst_tag[]){ + {"linux-git", "46c4c9d1beb7"}, + }, +}; diff --git a/testcases/kernel/syscalls/preadv/preadv.h b/testcases/kernel/syscalls/preadv/preadv.h index 73466a9aa..c715715b1 100644 --- a/testcases/kernel/syscalls/preadv/preadv.h +++ b/testcases/kernel/syscalls/preadv/preadv.h @@ -1,18 +1,9 @@ -/* -* Copyright (c) 2015 Fujitsu Ltd. -* Author: Xiao Yang <yangx.jy@cn.fujitsu.com> -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of version 2 of the GNU General Public License as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it would be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* -* You should have received a copy of the GNU General Public License -* alone with this program. -*/ +/* SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (c) 2015 Fujitsu Ltd. + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2016-2023 + */ #ifndef PREADV_H #define PREADV_H diff --git a/testcases/kernel/syscalls/preadv/preadv01.c b/testcases/kernel/syscalls/preadv/preadv01.c index 62f9296f2..871b3ab42 100644 --- a/testcases/kernel/syscalls/preadv/preadv01.c +++ b/testcases/kernel/syscalls/preadv/preadv01.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) 2015 Fujitsu Ltd. -* Author: Xiao Yang <yangx.jy@cn.fujitsu.com> -*/ - -/* -* Test Name: preadv01 -* -* Test Description: -* Testcase to check the basic functionality of the preadv(2). -* Preadv(2) should succeed to read the expected content of data -* and after reading the file, the file offset is not changed. -*/ + * Copyright (c) 2015 Fujitsu Ltd. + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2016-2023 + */ + +/*\ + * [Description] + * + * Testcase to check the basic functionality of the preadv(2). + * + * Preadv(2) should succeed to read the expected content of data + * and after reading the file, the file offset is not changed. + */ #define _GNU_SOURCE @@ -38,7 +39,7 @@ static struct tcase { {1, CHUNK*3/2, CHUNK/2, 'b'} }; -void verify_preadv(unsigned int n) +static void verify_preadv(unsigned int n) { int i; char *vec; @@ -81,7 +82,7 @@ void verify_preadv(unsigned int n) "with content '%c' expectedly", tc->size, tc->content); } -void setup(void) +static void setup(void) { char buf[CHUNK]; @@ -94,7 +95,7 @@ void setup(void) SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); } -void cleanup(void) +static void cleanup(void) { if (fd > 0) SAFE_CLOSE(fd); diff --git a/testcases/kernel/syscalls/preadv/preadv02.c b/testcases/kernel/syscalls/preadv/preadv02.c index 500059e42..9977a4f48 100644 --- a/testcases/kernel/syscalls/preadv/preadv02.c +++ b/testcases/kernel/syscalls/preadv/preadv02.c @@ -1,32 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) 2015-2016 Fujitsu Ltd. -* Author: Xiao Yang <yangx.jy@cn.fujitsu.com> -*/ - -/* -* Test Name: preadv02 -* -* Description: -* 1) preadv(2) fails if iov_len is invalid. -* 2) preadv(2) fails if the vector count iovcnt is less than zero. -* 3) preadv(2) fails if offset is negative. -* 4) preadv(2) fails when attempts to read into a invalid address. -* 5) preadv(2) fails if file descriptor is invalid. -* 6) preadv(2) fails if file descriptor is not open for reading. -* 7) preadv(2) fails when fd refers to a directory. -* 8) preadv(2) fails if fd is associated with a pipe. -* -* Expected Result: -* 1) preadv(2) should return -1 and set errno to EINVAL. -* 2) preadv(2) should return -1 and set errno to EINVAL. -* 3) preadv(2) should return -1 and set errno to EINVAL. -* 4) preadv(2) should return -1 and set errno to EFAULT. -* 5) preadv(2) should return -1 and set errno to EBADF. -* 6) preadv(2) should return -1 and set errno to EBADF. -* 7) preadv(2) should return -1 and set errno to EISDIR. -* 8) preadv(2) should return -1 and set errno to ESPIPE. -*/ + * Copyright (c) 2015-2016 Fujitsu Ltd. + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2017-2023 + */ + +/*\ + * [Description] + * + * - EINVAL when iov_len is invalid. + * - EINVAL when the vector count iovcnt is less than zero. + * - EINVAL when offset is negative. + * - EFAULT when attempts to read into a invalid address. + * - EBADF when file descriptor is invalid. + * - EBADF when file descriptor is not open for reading. + * - EISDIR when fd refers to a directory. + * - ESPIPE when fd is associated with a pipe. + */ #define _GNU_SOURCE diff --git a/testcases/kernel/syscalls/preadv/preadv03.c b/testcases/kernel/syscalls/preadv/preadv03.c index d4595dda6..558d85050 100644 --- a/testcases/kernel/syscalls/preadv/preadv03.c +++ b/testcases/kernel/syscalls/preadv/preadv03.c @@ -2,12 +2,15 @@ /* * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2019-2023 */ -/* - * Description: +/*\ + * [Description] + * * Check the basic functionality of the preadv(2) for the file * opened with O_DIRECT in all filesystem. + * * preadv(2) should succeed to read the expected content of data * and after reading the file, the file offset is not changed. */ diff --git a/testcases/kernel/syscalls/ptrace/.gitignore b/testcases/kernel/syscalls/ptrace/.gitignore index 01cbc6072..1ee6117e9 100644 --- a/testcases/kernel/syscalls/ptrace/.gitignore +++ b/testcases/kernel/syscalls/ptrace/.gitignore @@ -3,6 +3,7 @@ /ptrace03 /ptrace04 /ptrace05 +/ptrace06 /ptrace07 /ptrace08 /ptrace09 diff --git a/testcases/kernel/syscalls/ptrace/Makefile b/testcases/kernel/syscalls/ptrace/Makefile index 9ee7b8374..d7eca6837 100644 --- a/testcases/kernel/syscalls/ptrace/Makefile +++ b/testcases/kernel/syscalls/ptrace/Makefile @@ -1,34 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2002-2023 # Copyright (c) International Business Machines Corp., 2001 top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -# - ptrace06 is a broken test ; it hangs the target consistently, chewing up -# CPU. See: `Issue 3 - ptrace06 hung for 7 hours' -- -# http://sourceforge.net/mailarchive/forum.php?thread_name=364299f40910062300s65c43c93w9cccdfe8835c2334%40mail.gmail.com&forum_name=ltp-list -# - simple_tracer is a utility that Mike Frysinger added that shouldn't be -# compiled by default: -# -# gcc -g -O2 -g -O2 -fno-strict-aliasing -pipe -Wall -# -I//scratch/ltp-install6/include -I../../../../include -# -L//scratch/ltp-install6/lib simple_tracer.c -laio -lltp -o -# simple_tracer -# In file included from simple_tracer.c:25: -# syscalls.h:6:23: error: _syscalls.h: No such file or directory -# make[4]: *** [simple_tracer] Error 1 -# make[4]: Leaving directory -# `/scratch/ltp-dev2/ltp/testcases/kernel/syscalls/ptrace' -# make[3]: *** [all] Error 2 -# make[3]: Leaving directory `/scratch/ltp-dev2/ltp/testcases/kernel/syscalls' -# make[2]: *** [all] Error 2 -# make[2]: Leaving directory `/scratch/ltp-dev2/ltp/testcases/kernel' -# make[1]: *** [all] Error 2 -# make[1]: Leaving directory `/scratch/ltp-dev2/ltp/testcases' -# make: *** [testcases-all] Error 2 -# - -FILTER_OUT_MAKE_TARGETS := ptrace06 simple_tracer - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ptrace/make_syscall_list.sh b/testcases/kernel/syscalls/ptrace/make_syscall_list.sh deleted file mode 100755 index e5d6d2765..000000000 --- a/testcases/kernel/syscalls/ptrace/make_syscall_list.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -- $( \ - printf '#include <sys/syscall.h>' | \ - ${CC:-gcc} -E -dD - | \ - awk '$2 ~ /^SYS_/ { sub(/SYS_/,"",$2); print $2; }' -) -printf 'P(%s)\n' "$@" diff --git a/testcases/kernel/syscalls/ptrace/ptrace.h b/testcases/kernel/syscalls/ptrace/ptrace.h deleted file mode 100644 index 4a43f01ef..000000000 --- a/testcases/kernel/syscalls/ptrace/ptrace.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ptrace is a fickle beast and each arch sucks in a different way - */ - -#ifndef __LTP_PTRACE_H__ -#define __LTP_PTRACE_H__ - -#ifdef HAVE_SYS_PTRACE_H -# include <sys/ptrace.h> -#endif -#ifdef HAVE_SYS_REG_H -# include <sys/reg.h> -#endif -#ifdef __ia64__ /* what a pos */ -# define ia64_fpreg FU_ia64_fpreg -# define pt_all_user_regs FU_pt_all_user_regs -#endif -#ifdef HAVE_ASM_PTRACE_H -# include <asm/ptrace.h> -#endif -#ifdef HAVE_LINUX_PTRACE_H -# ifndef HAVE_STRUCT_PTRACE_PEEKSIGINFO_ARGS -# include <linux/ptrace.h> -# endif -#endif -#undef FU_ia64_fpreg -#undef FU_pt_all_user_regs - -#if defined(HAVE_STRUCT_PT_REGS) -typedef struct pt_regs ptrace_regs; -#elif defined(HAVE_STRUCT_USER_REGS_STRUCT) -typedef struct user_regs_struct ptrace_regs; -#endif - -#endif diff --git a/testcases/kernel/syscalls/ptrace/ptrace01.c b/testcases/kernel/syscalls/ptrace/ptrace01.c index 9071bbaba..53ddfb393 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace01.c +++ b/testcases/kernel/syscalls/ptrace/ptrace01.c @@ -26,8 +26,7 @@ #include <errno.h> #include <signal.h> #include <sys/wait.h> -#include <config.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "tst_test.h" static struct tcase { diff --git a/testcases/kernel/syscalls/ptrace/ptrace02.c b/testcases/kernel/syscalls/ptrace/ptrace02.c index e330f459e..a48ef58a5 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace02.c +++ b/testcases/kernel/syscalls/ptrace/ptrace02.c @@ -11,9 +11,8 @@ #include <signal.h> #include <sys/wait.h> #include <pwd.h> -#include <config.h> #include <stdlib.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "tst_test.h" uid_t uid; diff --git a/testcases/kernel/syscalls/ptrace/ptrace03.c b/testcases/kernel/syscalls/ptrace/ptrace03.c index b2b3fb49d..42ac3e7cf 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace03.c +++ b/testcases/kernel/syscalls/ptrace/ptrace03.c @@ -14,9 +14,8 @@ #include <signal.h> #include <sys/wait.h> #include <pwd.h> -#include <config.h> #include <stdlib.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "tst_test.h" static pid_t unused_pid; diff --git a/testcases/kernel/syscalls/ptrace/ptrace04.c b/testcases/kernel/syscalls/ptrace/ptrace04.c index af35fb3a2..8f1b5c6cc 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace04.c +++ b/testcases/kernel/syscalls/ptrace/ptrace04.c @@ -13,9 +13,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> - -#include <config.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "test.h" #include "spawn_ptrace_child.h" @@ -49,7 +47,7 @@ int TST_TOTAL = 2; void compare_registers(unsigned char poison) { -#ifdef HAVE_STRUCT_PTRACE_REGS +#if defined(HAVE_STRUCT_PTRACE_REGS) && defined(PTRACE_GETREGS) ptrace_regs _pt_regs; size_t i; long ret; diff --git a/testcases/kernel/syscalls/ptrace/ptrace05.c b/testcases/kernel/syscalls/ptrace/ptrace05.c index 54cfa4d7b..541018393 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace05.c +++ b/testcases/kernel/syscalls/ptrace/ptrace05.c @@ -33,9 +33,7 @@ #include <stdio.h> #include <string.h> #include <unistd.h> - -#include <config.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "test.h" #include "lapi/signal.h" diff --git a/testcases/kernel/syscalls/ptrace/ptrace06.c b/testcases/kernel/syscalls/ptrace/ptrace06.c index c0cb3b9bd..a1db3bab8 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace06.c +++ b/testcases/kernel/syscalls/ptrace/ptrace06.c @@ -16,13 +16,10 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> - -#include <config.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "test.h" #include "spawn_ptrace_child.h" -#include "config.h" /* this should be sizeof(struct user), but that info is only found * in the kernel asm/user.h which is not exported to userspace. diff --git a/testcases/kernel/syscalls/ptrace/ptrace07.c b/testcases/kernel/syscalls/ptrace/ptrace07.c index 362cee543..a78243671 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace07.c +++ b/testcases/kernel/syscalls/ptrace/ptrace07.c @@ -35,9 +35,8 @@ #include <stdlib.h> #include <sys/uio.h> #include <sys/wait.h> +#include <sys/ptrace.h> -#include "config.h" -#include "ptrace.h" #include "tst_safe_macros.h" #include "lapi/cpuid.h" diff --git a/testcases/kernel/syscalls/ptrace/ptrace11.c b/testcases/kernel/syscalls/ptrace/ptrace11.c index c54441671..90154852f 100644 --- a/testcases/kernel/syscalls/ptrace/ptrace11.c +++ b/testcases/kernel/syscalls/ptrace/ptrace11.c @@ -16,9 +16,8 @@ #include <signal.h> #include <sys/wait.h> #include <pwd.h> -#include <config.h> #include <stdlib.h> -#include "ptrace.h" +#include <sys/ptrace.h> #include "tst_test.h" static void verify_ptrace(void) diff --git a/testcases/kernel/syscalls/ptrace/simple_tracer.c b/testcases/kernel/syscalls/ptrace/simple_tracer.c deleted file mode 100644 index ae1af7c2f..000000000 --- a/testcases/kernel/syscalls/ptrace/simple_tracer.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * simple example ptrace() code to help build basis for other tests - * - * Copyright (c) 2009 Analog Devices Inc. - * - * Licensed under the GPL-2 or later - */ - -#define _GNU_SOURCE - -#include <config.h> - -#include <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/ptrace.h> -#include <sys/syscall.h> -#include "ptrace.h" - -#include "test.h" -#include "spawn_ptrace_child.h" - -#include "syscalls.h" - -char *TCID = "simple_tracer"; -int TST_TOTAL = 0; - -#define _decode(name, val) \ -({ \ - if (sizeof(long) == 4) \ - printf(name ":%08lx ", val); \ - else if (sizeof(long) == 8) \ - printf(name ":%016lx ", val); \ - else \ - printf(name ":%lx ", val); \ - val; \ -}) -#define decode(reg) _decode(#reg, pt->reg) -#define decode_user(name, offset) \ - _decode(name, vptrace(PTRACE_PEEKUSER, pid, offset, NULL)); -#define decode_sysnum(nr) printf("%s ", get_sysnum(nr)) -static void decode_regs(struct pt_regs *pt) -{ -#if defined(__bfin__) - long nr = decode_user("orig_p0", PT_ORIG_P0); - decode(p0); - decode(r0); - decode(r1); - decode(r2); - decode(r3); - decode(r4); - decode(r5); - decode_sysnum(nr); - puts(""); -#elif defined(__i386__) - long nr = decode_user("orig_eax", 4 * ORIG_EAX); - decode(eax); - decode(ebx); - decode(ecx); - decode(edx); - decode(esi); - decode(edi); - decode(ebp); - decode_sysnum(nr); - puts(""); -#elif defined(__x86_64__) - long nr = decode_user("orig_rax", 8 * ORIG_RAX); - decode(rax); - decode(rbx); - decode(rcx); - decode(rdx); - decode(rsi); - decode(rdi); - decode(rbp); - decode_sysnum(nr); - puts(""); -#elif defined(__sparc__) -#define G1 u_regs[0] -#define G2 u_regs[1] -#define G3 u_regs[2] -#define G4 u_regs[3] -#define G5 u_regs[4] -#define G6 u_regs[5] -#define G7 u_regs[6] -#define O0 u_regs[7] -#define O1 u_regs[8] -#define O2 u_regs[9] -#define O3 u_regs[10] -#define O4 u_regs[11] -#define O5 u_regs[12] -#define O6 u_regs[13] -#define O7 u_regs[14] - decode(G1); - decode(G2); - decode(G3); - decode(G4); - decode(G5); - decode(G6); - decode(G7); - decode(O0); - decode(O1); - decode(O2); - decode(O3); - decode(O4); - decode(O5); - decode(O6); - decode(O7); - decode_sysnum(pt->G1); - puts(""); -#else -#warning "no idea how to decode your arch" - puts("no idea how to decode your arch"); -#endif -} - -int main(int argc, char *argv[]) -{ - struct pt_regs pt_regs; - long ret; - int status; - - make_a_baby(argc, argv); - - while (1) { - ret = vptrace(PTRACE_GETREGS, pid, NULL, &pt_regs); - if (ret) - break; - decode_regs(&pt_regs); - - ret = vptrace(PTRACE_SYSCALL, pid, NULL, NULL); - if (ret) - break; - - if (waitpid(pid, &status, 0) == -1) - break; - } - - /* hopefully this worked */ - vptrace(PTRACE_KILL, pid, NULL, NULL); - - tst_exit(); -} diff --git a/testcases/kernel/syscalls/ptrace/syscalls.h b/testcases/kernel/syscalls/ptrace/syscalls.h deleted file mode 100644 index 2d9c5ceb6..000000000 --- a/testcases/kernel/syscalls/ptrace/syscalls.h +++ /dev/null @@ -1,17 +0,0 @@ -const struct sysnums { - long nr; - const char *snr; -} sysnums[] = { -#define P(NR) { .nr = SYS_##NR, .snr = #NR, }, -#include "_syscalls.h" -#undef P -}; - -const char *get_sysnum(long nr) -{ - int i; - for (i = 0; i < ARRAY_SIZE(sysnums); ++i) - if (sysnums[i].nr == nr) - break; - return i == ARRAY_SIZE(sysnums) ? "???" : sysnums[i].snr; -} diff --git a/testcases/kernel/syscalls/pwritev/pwritev.h b/testcases/kernel/syscalls/pwritev/pwritev.h index 833160ddb..e657dc7e6 100644 --- a/testcases/kernel/syscalls/pwritev/pwritev.h +++ b/testcases/kernel/syscalls/pwritev/pwritev.h @@ -1,18 +1,9 @@ -/* -* Copyright (c) 2015 Fujitsu Ltd. -* Author: Xiao Yang <yangx.jy@cn.fujitsu.com> -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of version 2 of the GNU General Public License as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it would be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -* -* You should have received a copy of the GNU General Public License -* alone with this program. -*/ +/* SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (c) 2015 Fujitsu Ltd. + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2016-2023 + */ #ifndef PWRITEV_H #define PWRITEV_H diff --git a/testcases/kernel/syscalls/pwritev/pwritev01.c b/testcases/kernel/syscalls/pwritev/pwritev01.c index 66358f7c4..f5fce81f2 100644 --- a/testcases/kernel/syscalls/pwritev/pwritev01.c +++ b/testcases/kernel/syscalls/pwritev/pwritev01.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) 2015 Fujitsu Ltd. -* Author: Xiao Yang <yangx.jy@cn.fujitsu.com> -*/ - -/* -* Test Name: pwritev01 -* -* Test Description: -* Testcase to check the basic functionality of the pwritev(2). -* pwritev(2) should succeed to write the expected content of data -* and after writing the file, the file offset is not changed. -*/ + * Copyright (c) 2015 Fujitsu Ltd. + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2016-2023 + */ + +/*\ + * [Description] + * + * Testcase to check the basic functionality of the pwritev(2). + * + * pwritev(2) should succeed to write the expected content of data + * and after writing the file, the file offset is not changed. + */ #define _GNU_SOURCE #include <string.h> diff --git a/testcases/kernel/syscalls/pwritev/pwritev02.c b/testcases/kernel/syscalls/pwritev/pwritev02.c index 0881b7566..59a286847 100644 --- a/testcases/kernel/syscalls/pwritev/pwritev02.c +++ b/testcases/kernel/syscalls/pwritev/pwritev02.c @@ -1,30 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) 2015-2016 Fujitsu Ltd. -* Author: Xiao Yang <yangx.jy@cn.fujitsu.com> -*/ - -/* -* Test Name: pwritev02 -* -* Description: -* 1) pwritev(2) fails if iov_len is invalid. -* 2) pwritev(2) fails if the vector count iovcnt is less than zero. -* 3) pwritev(2) fails if offset is negative. -* 4) pwritev(2) fails when attempts to write from a invalid address -* 5) pwritev(2) fails if file descriptor is invalid. -* 6) pwritev(2) fails if file descriptor is not open for writing. -* 7) pwritev(2) fails if fd is associated with a pipe. -* -* Expected Result: -* 1) pwritev(2) should return -1 and set errno to EINVAL. -* 2) pwritev(2) should return -1 and set errno to EINVAL. -* 3) pwritev(2) should return -1 and set errno to EINVAL. -* 4) pwritev(2) should return -1 and set errno to EFAULT. -* 5) pwritev(2) should return -1 and set errno to EBADF. -* 6) pwritev(2) should return -1 and set errno to EBADF. -* 7) pwritev(2) should return -1 and set errno to ESPIPE. -*/ + * Copyright (c) 2015-2016 Fujitsu Ltd. + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2017-2023 + */ + +/*\ + * [Description] + * + * - EINVAL when iov_len is invalid. + * - EINVAL when the vector count iovcnt is less than zero. + * - EINVAL when offset is negative. + * - EFAULT when attempts to write from a invalid address + * - EBADF when file descriptor is invalid. + * - EBADF when file descriptor is not open for writing. + * - ESPIPE when fd is associated with a pipe. + */ #define _GNU_SOURCE diff --git a/testcases/kernel/syscalls/pwritev/pwritev03.c b/testcases/kernel/syscalls/pwritev/pwritev03.c index 8b91de336..1bf9d5731 100644 --- a/testcases/kernel/syscalls/pwritev/pwritev03.c +++ b/testcases/kernel/syscalls/pwritev/pwritev03.c @@ -2,12 +2,15 @@ /* * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. * Author: Xiao Yang <yangx.jy@cn.fujitsu.com> + * Copyright (c) Linux Test Project, 2019-2023 */ -/* - * Description: +/*\ + * [Description] + * * Check the basic functionality of the pwritev(2) for the file * opened with O_DIRECT in all filesystem. + * * pwritev(2) should succeed to write the expected content of data * and after writing the file, the file offset is not changed. */ @@ -90,7 +93,7 @@ static void verify_direct_pwritev(unsigned int n) static void setup(void) { int dev_fd, ret; - + dev_fd = SAFE_OPEN(tst_device->dev, O_RDWR); SAFE_IOCTL(dev_fd, BLKSSZGET, &ret); SAFE_CLOSE(dev_fd); diff --git a/testcases/kernel/syscalls/readahead/readahead01.c b/testcases/kernel/syscalls/readahead/readahead01.c index bdef7945d..a1f313605 100644 --- a/testcases/kernel/syscalls/readahead/readahead01.c +++ b/testcases/kernel/syscalls/readahead/readahead01.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012 Linux Test Project, Inc. + * Copyright (C) 2023-2024 Cyril Hrubis <chrubis@suse.cz> */ /*\ @@ -30,43 +31,45 @@ static void test_bad_fd(void) { - char tempname[PATH_MAX] = "readahead01_XXXXXX"; - int fd; + int fd[2]; + + TST_EXP_FAIL(readahead(-1, 0, getpagesize()), EBADF, + "readahead() with fd = -1"); - tst_res(TINFO, "%s -1", __func__); - TST_EXP_FAIL(readahead(-1, 0, getpagesize()), EBADF); + SAFE_PIPE(fd); + SAFE_CLOSE(fd[0]); + SAFE_CLOSE(fd[1]); - tst_res(TINFO, "%s O_WRONLY", __func__); - fd = mkstemp(tempname); - if (fd == -1) - tst_res(TFAIL | TERRNO, "mkstemp failed"); - SAFE_CLOSE(fd); - fd = SAFE_OPEN(tempname, O_WRONLY); - TST_EXP_FAIL(readahead(fd, 0, getpagesize()), EBADF); - SAFE_CLOSE(fd); - unlink(tempname); + TST_EXP_FAIL(readahead(fd[0], 0, getpagesize()), EBADF, + "readahead() with invalid fd"); } -static void test_invalid_fd(void) +static void test_invalid_fd(struct tst_fd *fd) { - int fd[2]; - tst_res(TINFO, "%s pipe", __func__); - SAFE_PIPE(fd); - TST_EXP_FAIL(readahead(fd[0], 0, getpagesize()), EINVAL); - SAFE_CLOSE(fd[0]); - SAFE_CLOSE(fd[1]); + switch (fd->type) { + /* These succeed */ + case TST_FD_FILE: + case TST_FD_MEMFD: + case TST_FD_MEMFD_SECRET: + case TST_FD_PROC_MAPS: + return; + default: + break; + } - tst_res(TINFO, "%s socket", __func__); - fd[0] = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); - TST_EXP_FAIL(readahead(fd[0], 0, getpagesize()), EINVAL); - SAFE_CLOSE(fd[0]); + int exp_errnos[] = {EBADF, EINVAL, ESPIPE}; + + TST_EXP_FAIL_ARR(readahead(fd->fd, 0, getpagesize()), exp_errnos, + "readahead() on %s", tst_fd_desc(fd)); } static void test_readahead(void) { test_bad_fd(); - test_invalid_fd(); + + TST_FD_FOREACH(fd) + test_invalid_fd(&fd); } static void setup(void) diff --git a/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c b/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c index 09143a2d0..8a401fe0a 100644 --- a/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c +++ b/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c @@ -85,6 +85,7 @@ #include <sys/ioctl.h> #include <sys/syscall.h> #include <linux/unistd.h> +#include <lapi/mmap.h> #include "test.h" /*LTP Specific Include File */ @@ -92,6 +93,7 @@ #define WINDOW_START 0x48000000 static int page_sz; +static int granula; size_t page_words; size_t cache_pages; size_t cache_sz; @@ -140,10 +142,10 @@ static void test_nonlinear(int fd) char *data = NULL; int i, j, repeat = 2; - for (i = 0; i < (int)cache_pages; i++) { + for (i = 0; i < (int)cache_pages; i += granula) { char *page = cache_contents + i * page_sz; - for (j = 0; j < (int)page_words; j++) + for (j = 0; j < (int)page_words * granula; j++) page[j] = i; } @@ -164,24 +166,24 @@ static void test_nonlinear(int fd) } again: - for (i = 0; i < (int)window_pages; i += 2) { + for (i = 0; i < (int)window_pages; i += 2 * granula) { char *page = data + i * page_sz; - if (remap_file_pages(page, page_sz * 2, 0, - (window_pages - i - 2), 0) == -1) { + if (remap_file_pages(page, 2 * MMAP_GRANULARITY, 0, + (window_pages - i - 2 * granula), 0) == -1) { tst_resm(TFAIL | TERRNO, "remap_file_pages error for page=%p, " - "page_sz=%d, window_pages=%zu", - page, (page_sz * 2), (window_pages - i - 2)); + "remap_sz=%d, window_pages=%zu", + page, 2 * MMAP_GRANULARITY, (window_pages - i - 2 * granula)); cleanup(data); } } - for (i = 0; i < (int)window_pages; i++) { + for (i = 0, j = 0; i < (int)window_pages; i += granula, j++) { /* * Double-check the correctness of the mapping: */ - if (i & 1) { + if (j & 1) { if (data[i * page_sz] != ((int)window_pages) - i) { tst_resm(TFAIL, "hm, mapped incorrect data, " @@ -191,12 +193,12 @@ again: cleanup(data); } } else { - if (data[i * page_sz] != ((int)window_pages) - i - 2) { + if (data[i * page_sz] != ((int)window_pages) - i - 2 * granula) { tst_resm(TFAIL, "hm, mapped incorrect data, " - "data[%d]=%d, (window_pages-%d-2)=%zu", + "data[%d]=%d, (window_pages-%d-2 * min_pages)=%zu", (i * page_sz), data[i * page_sz], i, - (window_pages - i - 2)); + (window_pages - i - 2 * granula)); cleanup(data); } } @@ -223,13 +225,15 @@ void setup(void) page_words = page_sz; + granula = MMAP_GRANULARITY / page_sz; + /* Set the cache size */ - cache_pages = 1024; + cache_pages = 1024 * granula; cache_sz = cache_pages * page_sz; cache_contents = malloc(cache_sz * sizeof(char)); /* Set the window size */ - window_pages = 16; + window_pages = 16 * granula; window_sz = window_pages * page_sz; sprintf(fname, "/dev/shm/cache_%d", getpid()); diff --git a/testcases/kernel/syscalls/rename/rename10.c b/testcases/kernel/syscalls/rename/rename10.c index 444f65366..5b5f79073 100644 --- a/testcases/kernel/syscalls/rename/rename10.c +++ b/testcases/kernel/syscalls/rename/rename10.c @@ -18,7 +18,13 @@ #define MNT_POINT "mntpoint" #define TEMP_FILE "tmpfile" -static char long_path[NAME_MAX + 1] = {[0 ... NAME_MAX] = 'a'}; +/* Path longer than PATH_MAX: fails the syscall right away (getname() fails) */ +static char long_path[PATH_MAX + 1] = {[0 ... PATH_MAX] = 'a'}; +/* + * Path fitting in PATH_MAX, but with an excessively long file name: rejected + * by the underlying filesystem + */ +static char long_name[PATH_MAX] = {[0 ... PATH_MAX - 2] = 'a', [PATH_MAX - 1] = '\0'}; static void setup(void) { @@ -30,6 +36,8 @@ static void run(void) { TST_EXP_FAIL(rename(TEMP_FILE, long_path), ENAMETOOLONG); + TST_EXP_FAIL(rename(TEMP_FILE, long_name), + ENAMETOOLONG); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/renameat/renameat01.c b/testcases/kernel/syscalls/renameat/renameat01.c index 3de103563..c318a7971 100644 --- a/testcases/kernel/syscalls/renameat/renameat01.c +++ b/testcases/kernel/syscalls/renameat/renameat01.c @@ -50,7 +50,6 @@ #include "test.h" #include "safe_macros.h" #include "lapi/fcntl.h" -#include "lapi/renameat.h" #define MNTPOINT "mntpoint" #define TESTDIR "testdir" diff --git a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c index 597de4665..40ff6e988 100644 --- a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c +++ b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c @@ -2,13 +2,17 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com> + */ +/*\ + * [Description] * * Gets round-robin time quantum by calling sched_rr_get_interval() and * checks that the value is sane. * - * It is also a regression test for kernel - * commit 975e155ed873 ("sched/rt: Show the 'sched_rr_timeslice' SCHED_RR - * timeslice tuning knob in milliseconds"). + * It is also a regression test for: + * + * - 975e155ed873 (sched/rt: Show the 'sched_rr_timeslice' SCHED_RR timeslice tuning knob in milliseconds) + * - c7fcb99877f9 ( sched/rt: Fix sysctl_sched_rr_timeslice intial value) */ #include "time64_variants.h" diff --git a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval02.c b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval02.c index 15e4a3053..a61e2969b 100644 --- a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval02.c +++ b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval02.c @@ -2,6 +2,9 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com> + */ +/*\ + * [Description] * * Verify that for a process with scheduling policy SCHED_FIFO, * sched_rr_get_interval() writes zero into timespec structure diff --git a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval03.c b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval03.c index f5a88f084..731c50082 100644 --- a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval03.c +++ b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval03.c @@ -2,14 +2,20 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com> + */ +/*\ + * [Description] + * + * Verify that: + * + * - sched_rr_get_interval() fails with errno set to EINVAL for an + * invalid pid + * + * - sched_rr_get_interval() fails with errno set to ESRCH if the + * process with specified pid does not exists * - * Verify that - * 1) sched_rr_get_interval() fails with errno set to EINVAL for an - * invalid pid - * 2) sched_rr_get_interval() fails with errno set to ESRCH if the - * process with specified pid does not exists - * 3) sched_rr_get_interval() fails with errno set to EFAULT if the - * address specified as &tp is invalid + * - sched_rr_get_interval() fails with errno set to EFAULT if the + * address specified as &tp is invalid */ #include "time64_variants.h" diff --git a/testcases/kernel/syscalls/sched_setparam/sched_setparam03.c b/testcases/kernel/syscalls/sched_setparam/sched_setparam03.c index 759b790b6..ffa92a3bf 100644 --- a/testcases/kernel/syscalls/sched_setparam/sched_setparam03.c +++ b/testcases/kernel/syscalls/sched_setparam/sched_setparam03.c @@ -49,7 +49,7 @@ void setup(void) tst_res(TINFO, "Testing %s variant", tv->desc); if (tv->sched_setscheduler(0, SCHED_FIFO, &p)) - tst_brk(TBROK | TERRNO, "sched_setcheduler(0, SCHED_FIFO, 1)"); + tst_brk(TBROK | TERRNO, "sched_setscheduler(0, SCHED_FIFO, 1)"); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/sched_setparam/sched_setparam04.c b/testcases/kernel/syscalls/sched_setparam/sched_setparam04.c index dbcb3c55c..26477e455 100644 --- a/testcases/kernel/syscalls/sched_setparam/sched_setparam04.c +++ b/testcases/kernel/syscalls/sched_setparam/sched_setparam04.c @@ -2,22 +2,23 @@ /* * Copyright (c) 2021, BELLSOFT. All rights reserved. * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * AUTHOR: Saji Kumar.V.R <saji.kumar@wipro.com> + * Author: Saji Kumar.V.R <saji.kumar@wipro.com> */ /*\ * [Description] * * Verify that: + * * 1. sched_setparam(2) returns -1 and sets errno to ESRCH if the - * process with specified pid could not be found + * process with specified pid could not be found. * 2. sched_setparam(2) returns -1 and sets errno to EINVAL if - * the parameter pid is an invalid value (-1) + * the parameter pid is an invalid value (-1). * 3. sched_setparam(2) returns -1 and sets errno to EINVAL if the - * parameter p is an invalid address + * parameter p is an invalid address. * 4. sched_setparam(2) returns -1 sets errno to EINVAL if the * value for p.sched_priority is other than 0 for scheduling - * policy, SCHED_OTHER + * policy, SCHED_OTHER. */ #include "tst_test.h" diff --git a/testcases/kernel/syscalls/sched_setscheduler/.gitignore b/testcases/kernel/syscalls/sched_setscheduler/.gitignore index aa8ad9695..1b8860d2c 100644 --- a/testcases/kernel/syscalls/sched_setscheduler/.gitignore +++ b/testcases/kernel/syscalls/sched_setscheduler/.gitignore @@ -1,3 +1,4 @@ /sched_setscheduler01 /sched_setscheduler02 /sched_setscheduler03 +/sched_setscheduler04 diff --git a/testcases/kernel/syscalls/sched_setscheduler/sched_setscheduler04.c b/testcases/kernel/syscalls/sched_setscheduler/sched_setscheduler04.c new file mode 100644 index 000000000..828d1ec09 --- /dev/null +++ b/testcases/kernel/syscalls/sched_setscheduler/sched_setscheduler04.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Federico Bonfiglio <federico.bonfiglio@protonmail.ch> + */ + +/* + * [Description] + * + * Testcases that test if sched_setscheduler with flag + * SCHED_RESET_ON_FORK restores children policy to + * SCHED_NORMAL. + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <sched.h> +#include <linux/sched.h> + +#include "tst_test.h" +#include "tst_sched.h" + +struct test_case_t { + int policy; + char *desc; +}; + +static struct test_case_t cases[] = { + { + .policy = SCHED_FIFO, + .desc = "SCHED_FIFO" + }, + { + .policy = SCHED_RR, + .desc = "SCHED_RR" + } +}; + +static void test_reset_on_fork(unsigned int i) +{ + struct sched_variant *tv = &sched_variants[tst_variant]; + struct test_case_t *tc = &cases[i]; + + tst_res(TINFO, "Testing %s variant %s policy", tv->desc, tc->desc); + + struct sched_param param = { .sched_priority = 10 }; + + tv->sched_setscheduler(getpid(), tc->policy | SCHED_RESET_ON_FORK, ¶m); + + pid_t pid = SAFE_FORK(); + + if (pid) { + if (sched_getscheduler(pid) == SCHED_NORMAL) + tst_res(TPASS, "Policy reset to SCHED_NORMAL"); + else + tst_res(TFAIL, "Policy NOT reset to SCHED_NORMAL"); + + sched_getparam(pid, ¶m); + + /* kernel will return sched_priority 0 if task is not RT Policy */ + if (param.sched_priority == 0) + tst_res(TPASS, "Priority set to 0"); + else + tst_res(TFAIL, "Priority not set to 0"); + } +} + +static struct tst_test test = { + .forks_child = 1, + .caps = (struct tst_cap[]) { + TST_CAP(TST_CAP_REQ, CAP_SYS_NICE), + {} + }, + .test_variants = ARRAY_SIZE(sched_variants), + .tcnt = ARRAY_SIZE(cases), + .test = test_reset_on_fork, +}; diff --git a/testcases/kernel/syscalls/sendfile/sendfile09.c b/testcases/kernel/syscalls/sendfile/sendfile09.c index 4a2d2083f..6cb3cd593 100644 --- a/testcases/kernel/syscalls/sendfile/sendfile09.c +++ b/testcases/kernel/syscalls/sendfile/sendfile09.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2014 + * Copyright (c) Linux Test Project, 2013-2023 */ /*\ @@ -20,11 +21,7 @@ #include <inttypes.h> #include <sys/sendfile.h> - #include "tst_test.h" -#include "lapi/abisize.h" - -#ifndef TST_ABI32 #define ONE_GB (INT64_C(1) << 30) #define IN_FILE "in_file" @@ -97,12 +94,9 @@ static struct tst_test test = { .test = run, .tcnt = ARRAY_SIZE(tc), .max_runtime = 120, + .skip_in_compat = 1, .tags = (const struct tst_tag[]) { {"linux-git", "5d73320a96fcc"}, {} } }; - -#else -TST_TEST_TCONF("This test is only for 64bit"); -#endif diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg.h b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h index 65d5b680f..69ed80d44 100644 --- a/testcases/kernel/syscalls/sendmmsg/sendmmsg.h +++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg.h @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef SENDMMSG_H__ +#define SENDMMSG_H__ + #include <netinet/ip.h> #include <stdio.h> #include <stdlib.h> @@ -25,3 +28,5 @@ static struct time64_variants variants[] = { { .recvmmsg = sys_recvmmsg64, .sendmmsg = sys_sendmmsg, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, #endif }; + +#endif /* SENDMMSG_H__ */ diff --git a/testcases/kernel/syscalls/setgroups/.gitignore b/testcases/kernel/syscalls/setgroups/.gitignore index 9de928241..0649a3425 100644 --- a/testcases/kernel/syscalls/setgroups/.gitignore +++ b/testcases/kernel/syscalls/setgroups/.gitignore @@ -4,3 +4,5 @@ /setgroups02_16 /setgroups03 /setgroups03_16 +/setgroups04 +/setgroups04_16 diff --git a/testcases/kernel/syscalls/setgroups/Makefile b/testcases/kernel/syscalls/setgroups/Makefile index b2bb1e005..41160978e 100644 --- a/testcases/kernel/syscalls/setgroups/Makefile +++ b/testcases/kernel/syscalls/setgroups/Makefile @@ -3,6 +3,9 @@ top_srcdir ?= ../../../.. +# Remove after rewriting setgroups04.c to the new API. +USE_LEGACY_COMPAT_16_H := 1 + include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../utils/compat_16.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/setgroups/setgroups04.c b/testcases/kernel/syscalls/setgroups/setgroups04.c new file mode 100644 index 000000000..93a064cda --- /dev/null +++ b/testcases/kernel/syscalls/setgroups/setgroups04.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) Bull S.A. 2001 + * Copyright (c) International Business Machines Corp., 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Test Name: setgroups04 + * + * Test Description: + * Verify that, setgroups() fails with -1 and sets errno to EFAULT if the list has an invalid address. + * + * Expected Result: + * setgroups() should fail with return value -1 and set expected errno. + * + * Algorithm: + * Setup: + * Setup signal handling. + * Pause for SIGUSR1 if option specified. + * + * Test: + * Loop if the proper options are given. + * Execute system call + * Check return code, if system call failed (return=-1) + * if errno set == expected errno + * Issue sys call fails with expected return value and errno. + * Otherwise, + * Issue sys call fails with unexpected errno. + * Otherwise, + * Issue sys call returns unexpected value. + * + * Cleanup: + * Print errno log and/or timing stats if options given + * + * Usage: <for command-line> + * setgroups04 [-c n] [-e] [-i n] [-I x] [-P x] [-t] + * where, -c n : Run n copies concurrently. + * -f : Turn off functionality Testing. + * -i n : Execute test n times. + * -I x : Execute test for x seconds. + * -P x : Pause for x seconds between iterations. + * -t : Turn on syscall timing. + * + * HISTORY + * 05/2002 Ported by André Merlier + * + * RESTRICTIONS: + * none. + * + */ +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> + +#include "test.h" + +/* + * Don't forget to remove USE_LEGACY_COMPAT_16_H from Makefile after + * rewriting this test to the new API. + */ +#include "compat_16.h" + +TCID_DEFINE(setgroups04); +int TST_TOTAL = 1; + +GID_T groups_list[NGROUPS]; + +void setup(); /* setup function for the test */ +void cleanup(); /* cleanup function for the test */ + +#if !defined(UCLINUX) + +int main(int ac, char **av) +{ + int lc; + int gidsetsize; /* total no. of groups */ + char *test_desc; /* test specific error message */ + + tst_parse_opts(ac, av, NULL, NULL); + + /* Perform setup for test */ + setup(); + + for (lc = 0; TEST_LOOPING(lc); lc++) { + + tst_count = 0; + + gidsetsize = NGROUPS; + test_desc = "EFAULT"; + + /* + * Call setgroups() to test condition + * verify that it fails with -1 return value and + * sets appropriate errno. + */ + TEST(SETGROUPS(cleanup, gidsetsize, sbrk(0))); + + if (TEST_RETURN != -1) { + tst_resm(TFAIL, "setgroups() returned %ld, " + "expected -1, errno=%d", TEST_RETURN, + EFAULT); + } else { + + if (TEST_ERRNO == EFAULT) { + tst_resm(TPASS, + "setgroups() fails with expected " + "error EFAULT errno:%d", TEST_ERRNO); + } else { + tst_resm(TFAIL, "setgroups() fails, %s, " + "errno=%d, expected errno=%d", + test_desc, TEST_ERRNO, EFAULT); + } + } + + } + + cleanup(); + tst_exit(); + +} + +#else + +int main(void) +{ + tst_resm(TINFO, "test is not available on uClinux"); + tst_exit(); +} + +#endif /* if !defined(UCLINUX) */ + +/* + * setup() + */ +void setup(void) +{ + tst_require_root(); + + tst_sig(NOFORK, DEF_HANDLER, cleanup); + + TEST_PAUSE; + +} + +/* + * cleanup() + */ +void cleanup(void) +{ + +} diff --git a/testcases/kernel/syscalls/setsockopt/.gitignore b/testcases/kernel/syscalls/setsockopt/.gitignore index fd3235bb3..5c05290a5 100644 --- a/testcases/kernel/syscalls/setsockopt/.gitignore +++ b/testcases/kernel/syscalls/setsockopt/.gitignore @@ -7,3 +7,4 @@ /setsockopt07 /setsockopt08 /setsockopt09 +/setsockopt10 diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt10.c b/testcases/kernel/syscalls/setsockopt/setsockopt10.c new file mode 100644 index 000000000..4e7e44938 --- /dev/null +++ b/testcases/kernel/syscalls/setsockopt/setsockopt10.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Richard Palethorpe <rpalethorpe@suse.com> + */ +/*\ + * [Description] + * + * Reproducer for CVE-2023-0461 which is an exploitable use-after-free + * in a TLS socket. In fact it is exploitable in any User Level + * Protocol (ULP) which does not clone its context when accepting a + * connection. + * + * Because it does not clone the context, the child socket which is + * created on accept has a pointer to the listening socket's + * context. When the child is closed the parent's context is freed + * while it still has a reference to it. + * + * TLS can only be added to a socket which is connected. Not listening + * or disconnected, and a connected socket can not be set to + * listening. So we have to connect the socket, add TLS, then + * disconnect, then set it to listening. + * + * To my knowledge, setting a socket from open to disconnected + * requires a trick; we have to "connect" to an unspecified + * address. This could explain why the bug was not found earlier. + * + * The accepted fix was to disallow listening on sockets with a ULP + * set which does not have a clone function. + * + * The test uses two processes, first the child acts as a server so + * that the parent can create the TLS socket. Then the child connects + * to the parent's TLS socket. + * + * When we try to listen on the parent, the current kernel should + * return EINVAL. However if clone is implemented then this could + * become a valid operation. It is also quite easy to crash the kernel + * if we set some TLS options before doing a double free. + * + * commit 2c02d41d71f90a5168391b6a5f2954112ba2307c + * Author: Paolo Abeni <pabeni@redhat.com> + * Date: Tue Jan 3 12:19:17 2023 +0100 + * + * net/ulp: prevent ULP without clone op from entering the LISTEN status + */ + +#include "sched.h" +#include "tst_test.h" + +#ifdef HAVE_LINUX_TLS_H + +#include <linux/tls.h> +#include <netinet/in.h> + +#include "lapi/sched.h" +#include "lapi/socket.h" +#include "lapi/tcp.h" +#include "tst_checkpoint.h" +#include "tst_net.h" +#include "tst_safe_net.h" +#include "tst_taint.h" + +static struct tls12_crypto_info_aes_gcm_128 opts = { + .info = { + .version = TLS_1_2_VERSION, + .cipher_type = TLS_CIPHER_AES_GCM_128, + }, + .iv = { 'i', 'v' }, + .key = { 'k', 'e', 'y' }, + .salt = { 's', 'a', 'l', 't' }, + .rec_seq = { 'r', 'e', 'c', 's' }, +}; + +static struct sockaddr_in tcp0_addr, tcp1_addr; +static const struct sockaddr unspec_addr = { + .sa_family = AF_UNSPEC +}; + +static int tcp0_sk, tcp1_sk, tcp2_sk, tcp3_sk; + +static void setup(void) +{ + tst_init_sockaddr_inet(&tcp0_addr, "127.0.0.1", 0x7c90); + tst_init_sockaddr_inet(&tcp1_addr, "127.0.0.1", 0x7c91); +} + +static void cleanup(void) +{ + if (tcp0_sk > 0) + SAFE_CLOSE(tcp0_sk); + if (tcp1_sk > 0) + SAFE_CLOSE(tcp1_sk); + if (tcp2_sk > 0) + SAFE_CLOSE(tcp2_sk); + if (tcp3_sk > 0) + SAFE_CLOSE(tcp3_sk); +} + +static void child(void) +{ + tst_res(TINFO, "child: Listen for tcp1 connection"); + tcp0_sk = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + SAFE_BIND(tcp0_sk, (struct sockaddr *)&tcp0_addr, sizeof(tcp0_addr)); + SAFE_LISTEN(tcp0_sk, 1); + TST_CHECKPOINT_WAKE(0); + + tcp3_sk = SAFE_ACCEPT(tcp0_sk, NULL, 0); + TST_CHECKPOINT_WAIT(1); + SAFE_CLOSE(tcp3_sk); + SAFE_CLOSE(tcp0_sk); + + tcp3_sk = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + TST_CHECKPOINT_WAIT(2); + + tst_res(TINFO, "child: connect for tcp2 connection"); + TEST(connect(tcp3_sk, (struct sockaddr *)&tcp1_addr, sizeof(tcp1_addr))); + + if (TST_RET == -1) { + tst_res(TINFO | TTERRNO, "child: could not connect to tcp1"); + return; + } + + TST_CHECKPOINT_WAIT(3); +} + +static void run(void) +{ + const pid_t child_pid = SAFE_FORK(); + + if (child_pid == 0) { + child(); + return; + } + + tcp1_sk = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "parent: Connect for tcp0 connection"); + SAFE_CONNECT(tcp1_sk, (struct sockaddr *)&tcp0_addr, sizeof(tcp0_addr)); + TEST(setsockopt(tcp1_sk, SOL_TCP, TCP_ULP, "tls", 3)); + + if (TST_RET == -1 && TST_ERR == ENOENT) + tst_brk(TCONF | TTERRNO, "parent: setsockopt failed: The TLS module is probably not loaded"); + else if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "parent: setsockopt failed"); + + SAFE_SETSOCKOPT(tcp1_sk, SOL_TLS, TLS_TX, &opts, sizeof(opts)); + TST_CHECKPOINT_WAKE(1); + + tst_res(TINFO, "parent: Disconnect by setting unspec address"); + SAFE_CONNECT(tcp1_sk, &unspec_addr, sizeof(unspec_addr)); + SAFE_BIND(tcp1_sk, (struct sockaddr *)&tcp1_addr, sizeof(tcp1_addr)); + + TEST(listen(tcp1_sk, 1)); + + if (TST_RET == -1) { + if (TST_ERR == EINVAL) + tst_res(TPASS | TTERRNO, "parent: Can't listen on disconnected TLS socket"); + else + tst_res(TCONF | TTERRNO, "parent: Can't listen on disconnected TLS socket, but the errno is not EINVAL as expected"); + + TST_CHECKPOINT_WAKE(2); + tst_reap_children(); + return; + } + + tst_res(TINFO, "parent: Can listen on disconnected TLS socket"); + TST_CHECKPOINT_WAKE(2); + + tcp2_sk = SAFE_ACCEPT(tcp1_sk, NULL, 0); + SAFE_CLOSE(tcp2_sk); + + tst_res(TINFO, "parent: Attempting double free, because we set cipher options this should result in an crash"); + tst_flush(); + SAFE_CLOSE(tcp1_sk); + + TST_CHECKPOINT_WAKE(3); + tst_reap_children(); + sched_yield(); + + tst_res(TCONF, "parent: We're still here, maybe the kernel can clone the TLS-ULP context now?"); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_TLS", + NULL + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "2c02d41d71f90"}, + {"CVE", "2023-0461"}, + {} + } +}; + +#else + +TST_TEST_TCONF("linux/tls.h missing, we assume your system is too old"); + +#endif diff --git a/testcases/kernel/syscalls/setuid/Makefile b/testcases/kernel/syscalls/setuid/Makefile index 1fdd7bd76..88d6385d9 100644 --- a/testcases/kernel/syscalls/setuid/Makefile +++ b/testcases/kernel/syscalls/setuid/Makefile @@ -4,8 +4,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -#for compat_16.mk uses the compat_16_tst.h -COMPAT_TST_16_H := 1 - include $(abs_srcdir)/../utils/compat_16.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/setxattr/setxattr01.c b/testcases/kernel/syscalls/setxattr/setxattr01.c index 8cd2821d0..31f41369a 100644 --- a/testcases/kernel/syscalls/setxattr/setxattr01.c +++ b/testcases/kernel/syscalls/setxattr/setxattr01.c @@ -137,7 +137,7 @@ static void verify_setxattr(unsigned int i) { /* some tests might require existing keys for each iteration */ if (tc[i].keyneeded) { - SAFE_SETXATTR(FNAME, tc[i].key, tc[i].value, tc[i].size, + SAFE_SETXATTR(FNAME, tc[i].key, *tc[i].value, tc[i].size, XATTR_CREATE); } diff --git a/testcases/kernel/syscalls/sighold/sighold02.c b/testcases/kernel/syscalls/sighold/sighold02.c index 1cfb7688b..2807bf67e 100644 --- a/testcases/kernel/syscalls/sighold/sighold02.c +++ b/testcases/kernel/syscalls/sighold/sighold02.c @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : Bob Clark - * CO-PILOT : Barrie Kletscher - * DATE STARTED : 9/26/86 + * Authors: Bob Clark, Barrie Kletscher * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz> * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> */ @@ -12,8 +10,9 @@ * [Description] * * This test checks following conditions: - * 1. sighold action to turn off the receipt of all signals was done without error. - * 2. After signals were held, and sent, no signals were trapped. + * + * 1. sighold action to turn off the receipt of all signals was done without error. + * 2. After signals were held, and sent, no signals were trapped. */ #define _XOPEN_SOURCE 600 diff --git a/testcases/kernel/syscalls/splice/.gitignore b/testcases/kernel/syscalls/splice/.gitignore index a3e502f00..88a8dff78 100644 --- a/testcases/kernel/syscalls/splice/.gitignore +++ b/testcases/kernel/syscalls/splice/.gitignore @@ -3,3 +3,5 @@ /splice03 /splice04 /splice05 +/splice06 +/splice07 diff --git a/testcases/kernel/syscalls/splice/splice06.c b/testcases/kernel/syscalls/splice/splice06.c new file mode 100644 index 000000000..0cb5dec29 --- /dev/null +++ b/testcases/kernel/syscalls/splice/splice06.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC <wegao@suse.com> + */ + +/*\ + * [Description] + * + * This test is cover splice() on proc files. + * + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <sys/types.h> +#include <fcntl.h> +#include <ctype.h> + +#include "tst_test.h" +#include "lapi/splice.h" + +#define BUF_SIZE 100 +#define PIPE_MAX_INIT_SIZE 65536 +#define DOMAIN_INIT_NAME "LTP_INIT" +#define DOMAIN_TEST_NAME "LTP_TEST" +#define INTEGER_PROCFILE "/proc/sys/fs/pipe-max-size" +#define STRING_PROCFILE "/proc/sys/kernel/domainname" +static int pipe_max_test_size; + +static void format_str(char *str) +{ + int i; + + for (i = 0; i < BUF_SIZE ; i++) { + if (!isdigit(str[i])) { + str[i] = '\0'; + break; + } + } + if (i == BUF_SIZE) + tst_brk(TBROK, "can not find nonnumeric character from input string"); +} + +static int splice_read_num(const char *file) +{ + int pipes[2]; + int fd_in; + int ret; + int num; + char buf[BUF_SIZE]; + + memset(buf, '\0', sizeof(buf)); + fd_in = SAFE_OPEN(file, O_RDONLY); + SAFE_PIPE(pipes); + + ret = splice(fd_in, NULL, pipes[1], NULL, BUF_SIZE - 1, 0); + if (ret < 0) + tst_brk(TBROK | TERRNO, "splice(fd_in, pipe) failed"); + + SAFE_READ(0, pipes[0], buf, BUF_SIZE); + + /* Search for the first nonnumeric character and replace it with \0 */ + format_str(buf); + + if (tst_parse_int(buf, &num, 0, INT_MAX)) + tst_brk(TBROK, "Invalid buffer num %s", buf); + + SAFE_CLOSE(fd_in); + SAFE_CLOSE(pipes[0]); + SAFE_CLOSE(pipes[1]); + + return num; +} + +static char *splice_read_str(const char *file, char *dest) +{ + int pipes[2]; + int fd_in; + int ret; + + fd_in = SAFE_OPEN(file, O_RDONLY); + SAFE_PIPE(pipes); + + ret = splice(fd_in, NULL, pipes[1], NULL, BUF_SIZE, 0); + if (ret < 0) + tst_brk(TBROK | TERRNO, "splice(fd_in, pipe) failed"); + + SAFE_READ(0, pipes[0], dest, BUF_SIZE); + + SAFE_CLOSE(fd_in); + SAFE_CLOSE(pipes[0]); + SAFE_CLOSE(pipes[1]); + + return dest; +} + + +static void splice_write_num(const char *file, int num) +{ + int pipes[2]; + int fd_out; + int ret; + char buf[BUF_SIZE]; + + memset(buf, '\0', sizeof(buf)); + + fd_out = SAFE_OPEN(file, O_WRONLY, 0777); + SAFE_PIPE(pipes); + sprintf(buf, "%d", num); + + SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], buf, strlen(buf)); + + ret = splice(pipes[0], NULL, fd_out, NULL, BUF_SIZE, 0); + if (ret < 0) + tst_brk(TBROK | TERRNO, "splice write failed"); + + SAFE_CLOSE(fd_out); + SAFE_CLOSE(pipes[0]); + SAFE_CLOSE(pipes[1]); +} + +static void splice_write_str(const char *file, char *dest) +{ + int pipes[2]; + int fd_out; + int ret; + + fd_out = SAFE_OPEN(file, O_WRONLY, 0777); + SAFE_PIPE(pipes); + + SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], dest, strlen(dest)); + + ret = splice(pipes[0], NULL, fd_out, NULL, BUF_SIZE, 0); + if (ret < 0) + tst_brk(TBROK | TERRNO, "splice write failed"); + + SAFE_CLOSE(fd_out); + SAFE_CLOSE(pipes[0]); + SAFE_CLOSE(pipes[1]); +} + +static void file_write_num(const char *file, int num) +{ + SAFE_FILE_PRINTF(file, "%d", num); +} + +static void file_write_str(const char *file, char *dest) +{ + SAFE_FILE_PRINTF(file, "%s", dest); +} + +static int file_read_num(const char *file) +{ + int num; + + SAFE_FILE_SCANF(file, "%d", &num); + + return num; +} + +static char *file_read_str(const char *file, char *dest) +{ + SAFE_FILE_SCANF(file, "%s", dest); + return dest; +} + +static void splice_test(void) +{ + + char buf_file[BUF_SIZE]; + char buf_splice[BUF_SIZE]; + + if (file_read_num(INTEGER_PROCFILE) == splice_read_num(INTEGER_PROCFILE)) + tst_res(TPASS, "Read num through splice correctly"); + else + tst_brk(TBROK | TERRNO, "Read num through splice failed"); + + splice_write_num(INTEGER_PROCFILE, pipe_max_test_size); + + if (file_read_num(INTEGER_PROCFILE) == pipe_max_test_size) + tst_res(TPASS, "Write num through splice correctly"); + else + tst_brk(TBROK | TERRNO, "Write num through splice failed"); + + memset(buf_file, '\0', sizeof(buf_file)); + memset(buf_splice, '\0', sizeof(buf_splice)); + + file_read_str(STRING_PROCFILE, buf_file); + splice_read_str(STRING_PROCFILE, buf_splice); + + if (!strncmp(buf_file, buf_splice, strlen(buf_file))) + tst_res(TPASS, "Read string through splice correctly"); + else + tst_brk(TBROK | TERRNO, "Read string through splice failed"); + + memset(buf_file, '\0', sizeof(buf_file)); + + splice_write_str(STRING_PROCFILE, DOMAIN_TEST_NAME); + file_read_str(STRING_PROCFILE, buf_file); + + if (!strncmp(buf_file, DOMAIN_TEST_NAME, strlen(buf_file))) + tst_res(TPASS, "Write string through splice correctly"); + else + tst_brk(TBROK | TERRNO, "Write string through splice failed"); +} + +static void setup(void) +{ + pipe_max_test_size = getpagesize(); + file_write_str(STRING_PROCFILE, DOMAIN_INIT_NAME); + file_write_num(STRING_PROCFILE, PIPE_MAX_INIT_SIZE); +} + +static struct tst_test test = { + .min_kver = "5.11", + .setup = setup, + .test_all = splice_test, + .needs_tmpdir = 1, + .save_restore = (const struct tst_path_val[]) { + {INTEGER_PROCFILE, NULL, TST_SR_TCONF}, + {STRING_PROCFILE, NULL, TST_SR_TCONF}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/splice/splice07.c b/testcases/kernel/syscalls/splice/splice07.c new file mode 100644 index 000000000..9c23e0aac --- /dev/null +++ b/testcases/kernel/syscalls/splice/splice07.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2023-2024 Cyril Hrubis <chrubis@suse.cz> + */ + +/*\ + * [Description] + * + * Iterate over all kinds of file descriptors and feed splice() with all possible + * combinations where at least one file descriptor is invalid. We do expect the + * syscall to fail either with EINVAL or EBADF. + */ + +#define _GNU_SOURCE + +#include <sys/socket.h> +#include <netinet/in.h> + +#include "tst_test.h" + +static void check_splice(struct tst_fd *fd_in, struct tst_fd *fd_out) +{ + /* These combinations just hang since the pipe is empty */ + if (fd_in->type == TST_FD_PIPE_READ) { + switch (fd_out->type) { + case TST_FD_FILE: + case TST_FD_PIPE_WRITE: + case TST_FD_UNIX_SOCK: + case TST_FD_INET_SOCK: + case TST_FD_MEMFD: + return; + default: + break; + } + } + + if (fd_out->type == TST_FD_PIPE_WRITE) { + switch (fd_in->type) { + /* While these combinations succeeed */ + case TST_FD_DEV_ZERO: + case TST_FD_FILE: + case TST_FD_PROC_MAPS: + case TST_FD_MEMFD: + return; + /* And this complains about socket not being connected */ + case TST_FD_INET_SOCK: + return; + default: + break; + } + } + + const int exp_errnos[] = {EBADF, EINVAL}; + + TST_EXP_FAIL2_ARR(splice(fd_in->fd, NULL, fd_out->fd, NULL, 1, 0), + exp_errnos, "splice() on %s -> %s", + tst_fd_desc(fd_in), tst_fd_desc(fd_out)); +} + +static void verify_splice(void) +{ + TST_FD_FOREACH(fd_in) { + tst_res(TINFO, "%s -> ...", tst_fd_desc(&fd_in)); + TST_FD_FOREACH(fd_out) + check_splice(&fd_in, &fd_out); + } +} + +static struct tst_test test = { + .test_all = verify_splice, +}; diff --git a/testcases/kernel/syscalls/swapon/swapon01.c b/testcases/kernel/syscalls/swapon/swapon01.c index c334ae246..e59fb20a1 100644 --- a/testcases/kernel/syscalls/swapon/swapon01.c +++ b/testcases/kernel/syscalls/swapon/swapon01.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2024 */ /*\ @@ -16,30 +17,26 @@ #include "lapi/syscalls.h" #include "libswap.h" +#define SWAP_FILE "swapfile01" + static void verify_swapon(void) { - TEST(tst_syscall(__NR_swapon, "./swapfile01", 0)); + TST_EXP_PASS(tst_syscall(__NR_swapon, SWAP_FILE, 0)); - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "Failed to turn on swapfile"); - } else { - tst_res(TPASS, "Succeeded to turn on swapfile"); - /*we need to turn this swap file off for -i option */ - if (tst_syscall(__NR_swapoff, "./swapfile01") != 0) { - tst_brk(TBROK | TERRNO, "Failed to turn off swapfile," - " system reboot after execution of LTP " - "test suite is recommended."); - } + if (TST_PASS && tst_syscall(__NR_swapoff, SWAP_FILE) != 0) { + tst_brk(TBROK | TERRNO, + "Failed to turn off swapfile, system reboot recommended"); } } static void setup(void) { - is_swap_supported("./tstswap"); - make_swapfile("swapfile01", 0); + is_swap_supported(SWAP_FILE); + make_swapfile(SWAP_FILE, 0); } static struct tst_test test = { + .needs_root = 1, .needs_tmpdir = 1, .test_all = verify_swapon, .setup = setup diff --git a/testcases/kernel/syscalls/swapon/swapon02.c b/testcases/kernel/syscalls/swapon/swapon02.c index d34c17a80..fceea77be 100644 --- a/testcases/kernel/syscalls/swapon/swapon02.c +++ b/testcases/kernel/syscalls/swapon/swapon02.c @@ -1,56 +1,39 @@ // SPDX-License-Identifier: GPL-2.0-or-later - /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) Linux Test Project, 2002-2023 */ /*\ * [Description] * * This test case checks whether swapon(2) system call returns - * 1. ENOENT when the path does not exist - * 2. EINVAL when the path exists but is invalid - * 3. EPERM when user is not a superuser - * 4. EBUSY when the specified path is already being used as a swap area + * - ENOENT when the path does not exist + * - EINVAL when the path exists but is invalid + * - EPERM when user is not a superuser + * - EBUSY when the specified path is already being used as a swap area */ -#include <errno.h> #include <pwd.h> #include "tst_test.h" #include "lapi/syscalls.h" #include "libswap.h" -static void setup01(void); -static void cleanup01(void); - static uid_t nobody_uid; static int do_swapoff; static struct tcase { char *err_desc; int exp_errno; - char *exp_errval; char *path; - void (*setup)(void); - void (*cleanup)(void); } tcases[] = { - {"Path does not exist", ENOENT, "ENOENT", "./doesnotexist", NULL, NULL}, - {"Invalid path", EINVAL, "EINVAL", "./notswap", NULL, NULL}, - {"Permission denied", EPERM, "EPERM", "./swapfile01", setup01, cleanup01}, - {"File already used", EBUSY, "EBUSY", "./alreadyused", NULL, NULL}, + {"Path does not exist", ENOENT, "./doesnotexist"}, + {"Invalid path", EINVAL, "./notswap"}, + {"Permission denied", EPERM, "./swapfile01"}, + {"File already used", EBUSY, "./alreadyused"}, }; -static void setup01(void) -{ - SAFE_SETEUID(nobody_uid); -} - -static void cleanup01(void) -{ - SAFE_SETEUID(0); -} - static void setup(void) { struct passwd *nobody; @@ -70,7 +53,7 @@ static void setup(void) do_swapoff = 1; } -void cleanup(void) +static void cleanup(void) { if (do_swapoff && tst_syscall(__NR_swapoff, "alreadyused")) tst_res(TWARN | TERRNO, "swapoff(alreadyused) failed"); @@ -79,24 +62,19 @@ void cleanup(void) static void verify_swapon(unsigned int i) { struct tcase *tc = tcases + i; - if (tc->setup) - tc->setup(); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(nobody_uid); - TEST(tst_syscall(__NR_swapon, tc->path, 0)); + TST_EXP_FAIL(tst_syscall(__NR_swapon, tc->path, 0), tc->exp_errno, + "swapon(2) fail with %s", tc->err_desc); - if (tc->cleanup) - tc->cleanup(); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(0); - if (TST_RET == -1 && TST_ERR == tc->exp_errno) { - tst_res(TPASS, "swapon(2) expected failure;" - " Got errno - %s : %s", - tc->exp_errval, tc->err_desc); - return; + if (TST_RET != -1) { + tst_res(TFAIL, "swapon(2) failed unexpectedly, expected: %s", + tst_strerrno(tc->exp_errno)); } - - tst_res(TFAIL, "swapon(2) failed to produce expected error:" - " %d, errno: %s and got %d.", tc->exp_errno, - tc->exp_errval, TST_ERR); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/swapon/swaponoff.h b/testcases/kernel/syscalls/swapon/swaponoff.h index e3eae3fe3..900761bda 100644 --- a/testcases/kernel/syscalls/swapon/swaponoff.h +++ b/testcases/kernel/syscalls/swapon/swaponoff.h @@ -2,17 +2,7 @@ #ifndef __SWAP_ON_OFF_H_ #define __SWAP_ON_OFF_H_ -/* - * Read swapon(2) / swapoff(2) for a full history lesson behind the value of - * MAX_SWAPFILES. - */ #include <linux/version.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) #define MAX_SWAPFILES 30 -#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 10) -#define MAX_SWAPFILES 32 -#else -#define MAX_SWAPFILES 8 -#endif #endif diff --git a/testcases/kernel/syscalls/symlink/.gitignore b/testcases/kernel/syscalls/symlink/.gitignore index d1497e680..6ea587ff3 100644 --- a/testcases/kernel/syscalls/symlink/.gitignore +++ b/testcases/kernel/syscalls/symlink/.gitignore @@ -2,4 +2,3 @@ /symlink02 /symlink03 /symlink04 -/symlink05 diff --git a/testcases/kernel/syscalls/symlink/symlink02.c b/testcases/kernel/syscalls/symlink/symlink02.c index c18db2b37..d2226501e 100644 --- a/testcases/kernel/syscalls/symlink/symlink02.c +++ b/testcases/kernel/syscalls/symlink/symlink02.c @@ -1,208 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Copyright (c) Linux Test Project, 2001-2023 + * Author: William Roske */ -/* $Id: symlink02.c,v 1.6 2009/08/28 14:17:14 vapier Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : symlink02 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for symlink(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) symlink(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the symlink(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * symlink(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include "test.h" -#include "safe_macros.h" - -void setup(); -void cleanup(); +/*\ + * [Description] + * + * Check the basic functionality of the symlink() system call. + */ -char *TCID = "symlink02"; -int TST_TOTAL = 1; +#include "tst_test.h" -char fname[255], symlnk[255]; -int fd; +static char *fname, *symlnk; -int main(int ac, char **av) +static void verify_symlink(void) { - int lc; - - /*************************************************************** - * parse standard options - ***************************************************************/ - tst_parse_opts(ac, av, NULL, NULL); - - /*************************************************************** - * perform global setup for test - ***************************************************************/ - setup(); - - /*************************************************************** - * check looping state if -c option given - ***************************************************************/ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call symlink(2) - */ - TEST(symlink(fname, symlnk)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "symlink(%s, %s) Failed, errno=%d : %s", - fname, symlnk, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - SAFE_UNLINK(cleanup, symlnk); - } - } - - /*************************************************************** - * cleanup and exit - ***************************************************************/ - cleanup(); - tst_exit(); + TST_EXP_POSITIVE(symlink(fname, symlnk), "symlink(%s, %s)", + fname, symlnk); + if (TST_RET == -1) + tst_res(TFAIL, "symlink(%s, %s) Failed", fname, symlnk); + else + SAFE_UNLINK(symlnk); } -/*************************************************************** - * setup() - performs all ONE TIME setup for this test. - ***************************************************************/ -void setup(void) +static void setup(void) { + fname = tst_aprintf("tfile_%d", getpid()); - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - sprintf(fname, "tfile_%d", getpid()); - if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) { - tst_brkm(TBROK, cleanup, - "open(%s, O_RDWR|O_CREAT,0700) Failed, errno=%d : %s", - fname, errno, strerror(errno)); - } - - if (close(fd) == -1) { - tst_resm(TWARN, "close(%s) Failed, errno=%d : %s", - fname, errno, strerror(errno)); - } - sprintf(symlnk, "st_%d", getpid()); + symlnk = tst_aprintf("st_%d", getpid()); } -/*************************************************************** - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - ***************************************************************/ -void cleanup(void) -{ - - tst_rmdir(); - -} +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .test_all = verify_symlink, +}; diff --git a/testcases/kernel/syscalls/symlink/symlink04.c b/testcases/kernel/syscalls/symlink/symlink04.c index 2190b3b1b..c43a03a26 100644 --- a/testcases/kernel/syscalls/symlink/symlink04.c +++ b/testcases/kernel/syscalls/symlink/symlink04.c @@ -1,193 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2001-2023 + * Author: John George */ -/* - * Test Name : symlink04 - * - * Test Description : - * Verify that, symlink will succeed to creat a symbolic link of an existing - * object name path. - * - * Expected Result: - * symlink() should return value 0 on success and symbolic link of an - * existing object should be created. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: <for command-line> - * symlink04 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions: - * None. +/*\ + * [Description] * + * Check that a symbolic link may point to an existing file or + * to a nonexistent one. */ +#include <stdlib.h> #include <stdio.h> -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" -#define TESTFILE "testfile" -#define SYMFILE "slink_file" -#define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH +#define TESTFILE "testfile" +#define NONFILE "noexistfile" +#define SYMFILE "slink_file" -char *TCID = "symlink04"; -int TST_TOTAL = 1; +static char *testfile; +static char *nonfile; -void setup(); -void cleanup(); +static struct tcase { + char **srcfile; +} tcases[] = { + {&testfile}, + {&nonfile}, +}; -int main(int ac, char **av) +static void setup(void) { - struct stat stat_buf; /* stat structure buffer */ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call symlink(2) to create a symlink of - * testfile. - */ - TEST(symlink(TESTFILE, SYMFILE)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "symlink(%s, %s) Failed, errno=%d : %s", - TESTFILE, SYMFILE, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - /* - * Get the symlink file status information - * using lstat(2). - */ - if (lstat(SYMFILE, &stat_buf) < 0) { - tst_brkm(TFAIL, cleanup, "lstat(2) of " - "%s failed, error:%d", SYMFILE, - errno); - } - - /* Check if the st_mode contains a link */ - if (!S_ISLNK(stat_buf.st_mode)) { - tst_resm(TFAIL, - "symlink of %s doesn't exist", - TESTFILE); - } else { - tst_resm(TPASS, "symlink(%s, %s) " - "functionality successful", - TESTFILE, SYMFILE); - } - } - - /* Unlink the symlink file for next loop */ - SAFE_UNLINK(cleanup, SYMFILE); - tst_count++; /* incr TEST_LOOP counter */ - } - - cleanup(); - tst_exit(); - + SAFE_TOUCH(TESTFILE, 0644, NULL); } -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and change directory to it. - * Create a test file under temporary directory and close it - */ -void setup(void) +static void verify_symlink(unsigned int i) { - int fd; /* file handle for testfile */ + struct tcase *tc = &tcases[i]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + struct stat stat_buf; - /* Pause if that option was specified - * TEST_PAUSE contains the code to fork the test with the -i option. - * You want to make sure you do this before you create your temporary - * directory. - */ - TEST_PAUSE; + TST_EXP_PASS(symlink(*tc->srcfile, SYMFILE)); - tst_tmpdir(); + SAFE_LSTAT(SYMFILE, &stat_buf); - /* creat/open a testfile */ - if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) { - tst_brkm(TBROK, cleanup, - "open(%s, O_RDWR|O_CREAT, %#o) Failed, errno=%d : %s", - TESTFILE, FILE_MODE, errno, strerror(errno)); - } + if (!S_ISLNK(stat_buf.st_mode)) + tst_res(TFAIL, "symlink of %s doesn't exist", *tc->srcfile); - /* Close the temporary file created above */ - if (close(fd) == -1) { - tst_resm(TBROK, "close(%s) Failed, errno=%d : %s", - TESTFILE, errno, strerror(errno)); - } + SAFE_UNLINK(SYMFILE); } -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Remove the test directory and testfile created in the setup. - */ -void cleanup(void) -{ - - tst_rmdir(); - -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .test = verify_symlink, + .bufs = (struct tst_buffers []) { + {&testfile, .str = TESTFILE}, + {&nonfile, .str = NONFILE}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/symlink/symlink05.c b/testcases/kernel/syscalls/symlink/symlink05.c deleted file mode 100644 index 83b151f5d..000000000 --- a/testcases/kernel/syscalls/symlink/symlink05.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * Test Name : symlink05 - * - * Test Description : - * Verify that, symlink will succeed to creat a symbolic link of an - * non-existing object name path. - * - * Expected Result: - * symlink() should return value 0 on success and symlink of an - * non-existing object should be created. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: <for command-line> - * symlink05 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions: - * This test should be run by 'non-super-user' only. - * - */ - -#include <stdio.h> -#include <sys/types.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> - -#include "test.h" -#include "safe_macros.h" - -#define TESTFILE "testfile" -#define SYMFILE "slink_file" - -char *TCID = "symlink05"; -int TST_TOTAL = 1; - -void setup(); -void cleanup(); - -int main(int ac, char **av) -{ - struct stat stat_buf; /* stat structure buffer */ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call symlink(2) to create a symlink of - * an non-existing testfile. - */ - TEST(symlink(TESTFILE, SYMFILE)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "symlink(%s, %s) Failed, errno=%d : %s", - TESTFILE, SYMFILE, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - /* - * Get the symlink file status information - * using lstat(2). - */ - if (lstat(SYMFILE, &stat_buf) < 0) { - tst_brkm(TFAIL, cleanup, "lstat(2) of " - "%s failed, error:%d", - SYMFILE, errno); - } - - /* Check if the st_mode contains a link */ - if (!S_ISLNK(stat_buf.st_mode)) { - tst_resm(TFAIL, - "symlink of %s doesn't exist", - TESTFILE); - } else { - tst_resm(TPASS, "symlink(%s, %s) " - "functionality successful", - TESTFILE, SYMFILE); - } - } - - /* Unlink the symlink file for next loop */ - SAFE_UNLINK(cleanup, SYMFILE); - tst_count++; /* incr TEST_LOOP counter */ - } - - cleanup(); - tst_exit(); - -} - -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and change directory to it. - */ -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - /* Pause if that option was specified - * TEST_PAUSE contains the code to fork the test with the -i option. - * You want to make sure you do this before you create your temporary - * directory. - */ - TEST_PAUSE; - - tst_tmpdir(); - -} - -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Remove the temporary directory created in the setup. - */ -void cleanup(void) -{ - - tst_rmdir(); - -} diff --git a/testcases/kernel/syscalls/timerfd/.gitignore b/testcases/kernel/syscalls/timerfd/.gitignore index ef388685d..ca6cbb1f4 100644 --- a/testcases/kernel/syscalls/timerfd/.gitignore +++ b/testcases/kernel/syscalls/timerfd/.gitignore @@ -1,6 +1,5 @@ /timerfd01 /timerfd02 -/timerfd03 /timerfd04 /timerfd_create01 /timerfd_gettime01 diff --git a/testcases/kernel/syscalls/timerfd/timerfd02.c b/testcases/kernel/syscalls/timerfd/timerfd02.c index 936cdbc53..3dabfb5c0 100644 --- a/testcases/kernel/syscalls/timerfd/timerfd02.c +++ b/testcases/kernel/syscalls/timerfd/timerfd02.c @@ -1,174 +1,51 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper <drepper@redhat.com> */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* 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, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: timerfd02.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=11fcb6c14676023d0bd437841f5dcd670e7990a0 */ -/* says: */ -/* The timerfd_create syscall already has a flags parameter. It just is */ -/* unused so far. This patch changes this by introducing the TFD_CLOEXEC */ -/* flag to set the close-on-exec flag for the returned file descriptor. A new */ -/* name TFD_CLOEXEC is introduced which in this implementation must have the */ -/* same value as O_CLOEXEC. */ -/* The following test must be adjusted for architectures other than x86 and */ -/* x86-64 and in case the syscall numbers changed. */ -/* */ -/* Usage: <for command-line> */ -/* timerfd02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: timerfd02 */ -/* */ -/* Author: Ulrich Drepper <drepper@redhat.com> */ -/* */ -/* History: Created - Jan 08 2009 - Ulrich Drepper <drepper@redhat.com> */ -/* Ported to LTP */ -/* - Jan 08 2009 - Subrata <subrata@linux.vnet.ibm.com> */ -/******************************************************************************/ - -#include <stdio.h> -#include <time.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -#include "test.h" +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper <drepper@redhat.com> + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> + */ +/*\ + * [Description] + * + * This test verifies that: + * - TFD_CLOEXEC sets the close-on-exec file status flag on the new open file + * - TFD_NONBLOCK sets the O_NONBLOCK file status flag on the new open file + */ + +#include "tst_test.h" +#include "tst_safe_timerfd.h" #include "lapi/fcntl.h" #include "lapi/syscalls.h" -#define TFD_CLOEXEC O_CLOEXEC +static int fdesc; -char *TCID = "timerfd02"; -int testno; -int TST_TOTAL = 1; +static struct test_case_t { + int flags; + int check; + int expected; +} tcases[] = { + { 0, F_GETFD, 0 }, + { TFD_CLOEXEC, F_GETFD, FD_CLOEXEC }, + { TFD_NONBLOCK, F_GETFL, O_NONBLOCK } +}; -/* Extern Global Functions */ -/******************************************************************************/ -/* */ -/* Function: cleanup */ -/* */ -/* Description: Performs all one time clean up for this test on successful */ -/* completion, premature exit or failure. Closes all temporary */ -/* files, removes all temporary directories exits the test with */ -/* appropriate return code by calling tst_exit() function. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits calling tst_exit(). Non '0' return code. */ -/* On success - Exits calling tst_exit(). With '0' return code. */ -/* */ -/******************************************************************************/ -void cleanup(void) +static void run(unsigned int i) { + struct test_case_t *tcase = &tcases[i]; - tst_rmdir(); - + TST_EXP_FD(fdesc = SAFE_TIMERFD_CREATE(CLOCK_REALTIME, tcase->flags)); + TST_EXP_EQ_LI(SAFE_FCNTL(fdesc, tcase->check) & tcase->expected, tcase->expected); + SAFE_CLOSE(fdesc); } -/* Local Functions */ -/******************************************************************************/ -/* */ -/* Function: setup */ -/* */ -/* Description: Performs all one time setup for this test. This function is */ -/* typically used to capture signals, create temporary dirs */ -/* and temporary files that may be used in the course of this */ -/* test. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits by calling cleanup(). */ -/* On success - returns 0. */ -/* */ -/******************************************************************************/ -void setup(void) +static void cleanup(void) { - /* Capture signals if any */ - /* Create temporary directories */ - TEST_PAUSE; - tst_tmpdir(); + if (fcntl(fdesc, F_GETFD) != -1) + SAFE_CLOSE(fdesc); } -int main(int argc, char *argv[]) -{ - int fd, coe; - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - fd = tst_syscall(__NR_timerfd_create, - CLOCK_REALTIME, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, - "timerfd_create(0) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (coe & FD_CLOEXEC) { - tst_brkm(TFAIL, - cleanup, - "timerfd_create(0) set close-on-exec flag"); - } - close(fd); - - fd = tst_syscall(__NR_timerfd_create, CLOCK_REALTIME, - TFD_CLOEXEC); - if (fd == -1) { - tst_brkm(TFAIL, - cleanup, - "timerfd_create(TFD_CLOEXEC) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((coe & FD_CLOEXEC) == 0) { - tst_brkm(TFAIL, - cleanup, - "timerfd_create(TFD_CLOEXEC) set close-on-exec flag"); - } - close(fd); - tst_resm(TPASS, "timerfd_create(TFD_CLOEXEC) Passed"); - cleanup(); - } - } - tst_exit(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/timerfd/timerfd03.c b/testcases/kernel/syscalls/timerfd/timerfd03.c deleted file mode 100644 index 89dec325f..000000000 --- a/testcases/kernel/syscalls/timerfd/timerfd03.c +++ /dev/null @@ -1,170 +0,0 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper <drepper@redhat.com> */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* 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, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: timerfd03.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=6b1ef0e60d42f2fdaec26baee8327eb156347b4f */ -/* which says: */ -/* This patch adds support for the TFD_NONBLOCK flag to timerfd_create. The */ -/* additional changes needed are minimal. The following test must be adjusted */ -/* for architectures other than x86 and x86-64 and in case the syscall numbers*/ -/* changed. */ -/* */ -/* Usage: <for command-line> */ -/* timerfd03 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: timerfd03 */ -/* */ -/* Author: Ulrich Drepper <drepper@redhat.com> */ -/* */ -/* History: Created - Jan 13 2009 - Ulrich Drepper <drepper@redhat.com> */ -/* Ported to LTP */ -/* - Jan 13 2009 - Subrata <subrata@linux.vnet.ibm.com> */ -/******************************************************************************/ -#include <stdio.h> -#include <time.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <errno.h> - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define TFD_NONBLOCK O_NONBLOCK - -char *TCID = "timerfd03"; -int testno; -int TST_TOTAL = 1; - -/* Extern Global Functions */ -/******************************************************************************/ -/* */ -/* Function: cleanup */ -/* */ -/* Description: Performs all one time clean up for this test on successful */ -/* completion, premature exit or failure. Closes all temporary */ -/* files, removes all temporary directories exits the test with */ -/* appropriate return code by calling tst_exit() function. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits calling tst_exit(). Non '0' return code. */ -/* On success - Exits calling tst_exit(). With '0' return code. */ -/* */ -/******************************************************************************/ -void cleanup(void) -{ - - tst_rmdir(); - -} - -/* Local Functions */ -/******************************************************************************/ -/* */ -/* Function: setup */ -/* */ -/* Description: Performs all one time setup for this test. This function is */ -/* typically used to capture signals, create temporary dirs */ -/* and temporary files that may be used in the course of this */ -/* test. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits by calling cleanup(). */ -/* On success - returns 0. */ -/* */ -/******************************************************************************/ -void setup(void) -{ - /* Capture signals if any */ - /* Create temporary directories */ - TEST_PAUSE; - tst_tmpdir(); -} - -int main(int argc, char *argv[]) -{ - int fd, fl; - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - fd = tst_syscall(__NR_timerfd_create, - CLOCK_REALTIME, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, - "timerfd_create(0) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (fl & O_NONBLOCK) { - tst_brkm(TFAIL, - cleanup, - "timerfd_create(0) set non-blocking mode"); - } - close(fd); - - fd = tst_syscall(__NR_timerfd_create, CLOCK_REALTIME, - TFD_NONBLOCK); - if (fd == -1) { - tst_brkm(TFAIL, - cleanup, - "timerfd_create(TFD_NONBLOCK) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((fl & O_NONBLOCK) == 0) { - tst_brkm(TFAIL, - cleanup, - "timerfd_create(TFD_NONBLOCK) set non-blocking mode"); - } - close(fd); - tst_resm(TPASS, "timerfd_create(TFD_NONBLOCK) PASSED"); - cleanup(); - } - } - tst_exit(); -} diff --git a/testcases/kernel/syscalls/umount/umount01.c b/testcases/kernel/syscalls/umount/umount01.c index d05296dce..264c8f7d7 100644 --- a/testcases/kernel/syscalls/umount/umount01.c +++ b/testcases/kernel/syscalls/umount/umount01.c @@ -2,12 +2,15 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Author: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> + * Copyright (c) Linux Test Project, 2002-2023 + */ + +/*\ + * [Description] * - * Phase I test for the umount(2) system call. - * It is intended to provide a limited exposure of the system call. + * Check the basic functionality of the umount(2) system call. */ -#include <errno.h> #include <sys/mount.h> #include "tst_test.h" @@ -23,7 +26,7 @@ static void verify_umount(void) mount_flag = 1; } - TEST(umount(MNTPOINT)); + TST_EXP_PASS(umount(MNTPOINT)); if (TST_RET != 0 && TST_ERR == EBUSY) { tst_res(TINFO, "umount() Failed with EBUSY " @@ -31,12 +34,6 @@ static void verify_umount(void) "is probing newly mounted dirs"); } - if (TST_RET != 0) { - tst_res(TFAIL | TTERRNO, "umount() Failed"); - return; - } - - tst_res(TPASS, "umount() Passed"); mount_flag = 0; } diff --git a/testcases/kernel/syscalls/umount/umount02.c b/testcases/kernel/syscalls/umount/umount02.c index 34a38c998..acc35e8a4 100644 --- a/testcases/kernel/syscalls/umount/umount02.c +++ b/testcases/kernel/syscalls/umount/umount02.c @@ -2,20 +2,24 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2002-2023 * Author: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> + */ + +/*\ + * [Description] * * Check for basic errors returned by umount(2) system call. * * Verify that umount(2) returns -1 and sets errno to - * 1) EBUSY if it cannot be umounted, because dir is still busy. - * 2) EFAULT if specialfile or device file points to invalid address space. - * 3) ENOENT if pathname was empty or has a nonexistent component. - * 4) EINVAL if specialfile or device is invalid or not a mount point. - * 5) ENAMETOOLONG if pathname was longer than MAXPATHLEN. + * + * 1. EBUSY if it cannot be umounted, because dir is still busy. + * 2. EFAULT if specialfile or device file points to invalid address space. + * 3. ENOENT if pathname was empty or has a nonexistent component. + * 4. EINVAL if specialfile or device is invalid or not a mount point. + * 5. ENAMETOOLONG if pathname was longer than MAXPATHLEN. */ -#include <errno.h> -#include <string.h> #include <sys/mount.h> #include "tst_test.h" @@ -41,21 +45,7 @@ static void verify_umount(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(umount(tc->mntpoint)); - - if (TST_RET != -1) { - tst_res(TFAIL, "umount() succeeds unexpectedly"); - return; - } - - if (tc->exp_errno != TST_ERR) { - tst_res(TFAIL | TTERRNO, "umount() should fail with %s", - tst_strerrno(tc->exp_errno)); - return; - } - - tst_res(TPASS | TTERRNO, "umount() fails as expected: %s", - tc->err_desc); + TST_EXP_FAIL(umount(tc->mntpoint), tc->exp_errno); } static void setup(void) diff --git a/testcases/kernel/syscalls/umount/umount03.c b/testcases/kernel/syscalls/umount/umount03.c index 1cef06fa1..3260312f7 100644 --- a/testcases/kernel/syscalls/umount/umount03.c +++ b/testcases/kernel/syscalls/umount/umount03.c @@ -1,17 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) Linux Test Project, 2002-2023 * Author: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com> + */ + +/*\ + * [Description] * - * Verify that umount(2) returns -1 and sets errno to EPERM if the user + * Verify that umount(2) returns -1 and sets errno to EPERM if the user * is not the super-user. */ -#include <errno.h> #include <pwd.h> #include <sys/mount.h> -#include <sys/types.h> -#include <unistd.h> #include "tst_test.h" #define MNTPOINT "mntpoint" @@ -20,19 +22,7 @@ static int mount_flag; static void verify_umount(void) { - TEST(umount(MNTPOINT)); - - if (TST_RET != -1) { - tst_res(TFAIL, "umount() succeeds unexpectedly"); - return; - } - - if (TST_ERR != EPERM) { - tst_res(TFAIL | TTERRNO, "umount() should fail with EPERM"); - return; - } - - tst_res(TPASS | TTERRNO, "umount() fails as expected"); + TST_EXP_FAIL(umount(MNTPOINT), EPERM); } static void setup(void) diff --git a/testcases/kernel/syscalls/utils/compat_16.mk b/testcases/kernel/syscalls/utils/compat_16.mk index e81a00c40..71a8cc56f 100644 --- a/testcases/kernel/syscalls/utils/compat_16.mk +++ b/testcases/kernel/syscalls/utils/compat_16.mk @@ -60,7 +60,7 @@ MAKE_TARGETS += $(addsuffix _16,$(MAKE_TARGETS)) # (no .h file, no TST_USE_NEWER64_SYSCALL def). DEF_16 := TST_USE_COMPAT16_SYSCALL -ifneq ($(COMPAT_TST_16_H),1) +ifeq ($(USE_LEGACY_COMPAT_16_H),1) COMPAT_16_H := $(abs_srcdir)/../utils/compat_16.h else COMPAT_16_H := $(abs_srcdir)/../utils/compat_tst_16.h diff --git a/testcases/kernel/syscalls/wait4/wait402.c b/testcases/kernel/syscalls/wait4/wait402.c index 39b170253..36fba7378 100644 --- a/testcases/kernel/syscalls/wait4/wait402.c +++ b/testcases/kernel/syscalls/wait4/wait402.c @@ -1,101 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * Copyright (c) 2012 Cyril Hrubis <chrubis@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2012 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2001-2015 + * Copyright (c) 2023 Ioannis Bonatakis <ybonatakis@suse.com> */ - /* - * wait402 - check for ECHILD errno when using an illegal pid value - */ - -#include "test.h" +/*\ + * [Description] + * + * Check for ECHILD errno when call wait4(2) with an invalid pid value. + */ -#include <errno.h> -#define _USE_BSD -#include <sys/types.h> -#include <sys/resource.h> +#include "tst_test.h" #include <sys/wait.h> -#include <stdlib.h> -#include <string.h> - -char *TCID = "wait402"; -int TST_TOTAL = 1; - -static void cleanup(void); -static void setup(void); - -static long get_pid_max(void) -{ - long pid_max; - - SAFE_FILE_SCANF(NULL, "/proc/sys/kernel/pid_max", "%ld", &pid_max); - return pid_max; -} +static pid_t pid_max; -int main(int ac, char **av) +static void run(void) { - int lc; - pid_t epid = get_pid_max() + 1; - - int status = 1; + int status; struct rusage rusage; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(wait4(epid, &status, 0, &rusage)); - - if (TEST_RETURN == 0) { - tst_brkm(TFAIL, cleanup, - "call failed to produce expected error - errno = %d - %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } - - switch (TEST_ERRNO) { - case ECHILD: - tst_resm(TPASS, - "received expected failure - errno = %d - %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_brkm(TFAIL, cleanup, - "call failed to produce expected " - "error - errno = %d - %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } - } - - cleanup(); - tst_exit(); + TST_EXP_FAIL2(wait4(pid_max + 1, &status, 0, &rusage), ECHILD); } static void setup(void) { - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .setup = setup, +}; diff --git a/testcases/kernel/syscalls/writev/writev07.c b/testcases/kernel/syscalls/writev/writev07.c index b725f08db..3dda1caa4 100644 --- a/testcases/kernel/syscalls/writev/writev07.c +++ b/testcases/kernel/syscalls/writev/writev07.c @@ -4,20 +4,26 @@ * Copyright (c) Linux Test Project, 2016 */ -/* - * Test Description: - * Verify writev() behaviour with partially valid iovec list. - * Kernel <4.8 used to shorten write up to first bad invalid - * iovec. Starting with 4.8, a writev with short data (under - * page size) is likely to get shorten to 0 bytes and return - * EFAULT. +/*\ + * [Description] + * + * Verify writev() behaviour with partially valid iovec list. + * Kernel <4.8 used to shorten write up to first bad invalid + * iovec. Starting with 4.8, a writev with short data (under + * page size) is likely to get shorten to 0 bytes and return + * EFAULT. + * + * This test doesn't make assumptions how much will write get + * shortened. It only tests that file content/offset after + * syscall corresponds to return value of writev(). * - * This test doesn't make assumptions how much will write get - * shortened. It only tests that file content/offset after - * syscall corresponds to return value of writev(). + * See: [RFC] writev() semantics with invalid iovec in the middle + * https://marc.info/?l=linux-kernel&m=147388891614289&w=2. * - * See: [RFC] writev() semantics with invalid iovec in the middle - * https://marc.info/?l=linux-kernel&m=147388891614289&w=2 + * This is also regression test for kernel commits: + * + * * 20c64ec83a9f ("iomap: fix a regression for partial write errors") + * * 3ac974796e5d ("iomap: fix short copy in iomap_write_iter()") */ #include <errno.h> @@ -138,4 +144,9 @@ static struct tst_test test = { .needs_tmpdir = 1, .setup = setup, .test_all = test_writev, + .tags = (const struct tst_tag[]) { + {"linux-git", "20c64ec83a9f"}, + {"linux-git", "3ac974796e5d"}, + {}, + } }; diff --git a/testcases/kernel/uevents/uevent01.c b/testcases/kernel/uevents/uevent01.c index 5c65556c9..a1f994150 100644 --- a/testcases/kernel/uevents/uevent01.c +++ b/testcases/kernel/uevents/uevent01.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2019-2023 */ -/* +/*\ + * [Description] * Very simple uevent netlink socket test. * * We fork a child that listens for a kernel events while parents attaches and diff --git a/testcases/kernel/uevents/uevent02.c b/testcases/kernel/uevents/uevent02.c index 4355cd8db..daa1b4f12 100644 --- a/testcases/kernel/uevents/uevent02.c +++ b/testcases/kernel/uevents/uevent02.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2019-2023 */ -/* +/*\ + * [Description] + * * Very simple uevent netlink socket test. * * We fork a child that listens for a kernel events while parents creates and @@ -24,7 +27,6 @@ #include "uevent.h" #define TUN_PATH "/dev/net/tun" -#define CONFIG_RPS "CONFIG_RPS" #define MAX_UEVENTS 7 static struct uevent_desc add = { @@ -127,10 +129,7 @@ static void verify_uevent(void) static void setup(void) { - struct tst_kconfig_var kconfig = { - .id = CONFIG_RPS, - .id_len = sizeof(CONFIG_RPS) - 1, - }; + struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_RPS"); int i = 0; tst_kconfig_read(&kconfig, 1); diff --git a/testcases/kernel/uevents/uevent03.c b/testcases/kernel/uevents/uevent03.c index ed15fea93..5b3dd701f 100644 --- a/testcases/kernel/uevents/uevent03.c +++ b/testcases/kernel/uevents/uevent03.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2019 Cyril Hrubis <chrubis@suse.cz> + * Copyright (c) Linux Test Project, 2019-2023 */ -/* +/*\ + * [Description] * Very simple uevent netlink socket test. * * We fork a child that listens for a kernel events while parents creates and |