| /* |
| * |
| * 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 |
| * fcntl16.c |
| * |
| * DESCRIPTION |
| * Additional file locking test cases for checking proper notifictaion |
| * of processes on lock change |
| * |
| * ALGORITHM |
| * Various test cases are used to lock a file opened without mandatory |
| * locking, with madatory locking and mandatory locking with NOBLOCK. |
| * Checking that processes waiting on lock boundaries are notified |
| * properly when boundaries change |
| * |
| * USAGE |
| * fcntl16 |
| * |
| * HISTORY |
| * 07/2001 Ported by Wayne Boyer |
| * 04/2002 wjhuie sigset cleanups |
| * |
| * RESTRICTIONS |
| * None |
| */ |
| |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <errno.h> |
| #include "test.h" |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| |
| #include "tst_fs_type.h" |
| |
| #define SKIPVAL 0x0f00 |
| //#define SKIP SKIPVAL, 0, 0L, 0L, IGNORED |
| #define SKIP 0,0,0L,0L,0 |
| #if (SKIPVAL == F_RDLCK) || (SKIPVAL == F_WRLCK) |
| #error invalid SKIP, must not be F_RDLCK or F_WRLCK |
| #endif |
| |
| #define IGNORED 0 |
| #define NOBLOCK 2 /* immediate success */ |
| #define WILLBLOCK 3 /* blocks, succeeds, parent unlocks records */ |
| #define TIME_OUT 10 |
| int NO_NFS = 1; /* Test on NFS or not */ |
| |
| typedef struct { |
| struct flock parent_a; |
| struct flock parent_b; |
| struct flock child_a; |
| struct flock child_b; |
| struct flock parent_c; |
| struct flock parent_d; |
| } testcase; |
| |
| static testcase testcases[] = { |
| /* #1 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 1 to byte 5 */ |
| {F_RDLCK, 0, 0L, 5L, NOBLOCK}, |
| /* Child_b read lock on byte 6 to byte 10 */ |
| {F_RDLCK, 0, 6L, 5L, NOBLOCK}, |
| /* |
| * Parent_c read lock on entire file |
| */ |
| {F_RDLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #2 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 1 to byte 5 */ |
| {F_RDLCK, 0, 0L, 5L, WILLBLOCK}, |
| /* Child_b read lock on byte 6 to byte 10 */ |
| {F_RDLCK, 0, 6L, 5L, WILLBLOCK}, |
| /* |
| * Parent_c write lock on entire |
| * file |
| */ |
| {F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #3 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 2 to byte 4 */ |
| {F_RDLCK, 0, 2L, 3L, WILLBLOCK}, |
| /* Child_b read lock on byte 6 to byte 8 */ |
| {F_RDLCK, 0, 6L, 3L, WILLBLOCK}, |
| /* |
| * Parent_c read lock on byte 3 to |
| * byte 7 |
| */ |
| {F_RDLCK, 0, 3L, 5L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #4 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 2 to byte 4 */ |
| {F_RDLCK, 0, 2L, 3L, WILLBLOCK}, |
| /* Child_b read lock on byte 6 to byte 8 */ |
| {F_RDLCK, 0, 6L, 3L, NOBLOCK}, |
| /* |
| * Parent_c read lock on byte 5 to |
| * byte 9 |
| */ |
| {F_RDLCK, 0, 5L, 5L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #5 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 3 to byte 7 */ |
| {F_RDLCK, 0, 3L, 5L, NOBLOCK}, |
| /* Child_b read lock on byte 5 to byte 10 */ |
| {F_RDLCK, 0, 5L, 6L, WILLBLOCK}, |
| /* |
| * Parent_c read lock on byte 2 to |
| * byte 8 |
| */ |
| {F_RDLCK, 0, 2L, 7L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #6 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 2 to byte 4 */ |
| {F_RDLCK, 0, 2L, 3L, WILLBLOCK}, |
| /* Child_b write lock on byte 6 to byte 8 */ |
| {F_RDLCK, 0, 6L, 3L, NOBLOCK}, |
| /* Parent_c no lock on byte 3 to 9 */ |
| {F_UNLCK, 0, 3L, 7L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #7 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b read lock on byte 3 to byte 7 */ |
| {F_RDLCK, 0, 3L, 5L, IGNORED}, |
| /* Child_a read lock on byte 2 to byte 4 */ |
| {F_RDLCK, 0, 2L, 3L, NOBLOCK}, |
| /* Child_b read lock on byte 6 to byte 8 */ |
| {F_RDLCK, 0, 6L, 3L, NOBLOCK}, |
| /* |
| * Parent_c read lock on byte 1 to |
| * byte 9 |
| */ |
| {F_RDLCK, 0, 1L, 9L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| |
| /* #8 Parent_a making a write lock on byte 2 to byte 4 */ |
| {{F_WRLCK, 0, 2L, 3L, IGNORED}, |
| /* Parent_b write lock on byte 6 to byte 8 */ |
| {F_WRLCK, 0, 6L, 3L, IGNORED}, |
| /* Child_a read lock on byte 3 to byte 7 */ |
| {F_RDLCK, 0, 3L, 5L, NOBLOCK}, |
| /* Child_b skipped */ |
| {SKIP}, |
| /* |
| * Parent_c read lock on byte 1 to |
| * byte 5 |
| */ |
| {F_RDLCK, 0, 1L, 5L, IGNORED}, |
| /* |
| * Parent_d read lock on |
| * byte 5 to byte 9 |
| */ |
| {F_RDLCK, 0, 5L, 5L, |
| IGNORED},}, |
| |
| /* #9 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b read lock on byte 3 to byte 7 */ |
| {F_RDLCK, 0, 3L, 5L, IGNORED}, |
| /* Child_a read lock on byte 2 to byte 4 */ |
| {F_RDLCK, 0, 2L, 3L, NOBLOCK}, |
| /* Child_b read lock on byte 6 to byte 8 */ |
| {F_RDLCK, 0, 6L, 3L, NOBLOCK}, |
| /* |
| * Parent_c read lock on byte 1 to |
| * byte 3 |
| */ |
| {F_RDLCK, 0, 1L, 3L, IGNORED}, |
| /* |
| * Parent_d read lock on |
| * byte 7 to byte 9 |
| */ |
| {F_RDLCK, 0, 7L, 3L, |
| IGNORED},}, |
| |
| /* #10 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 2 to byte 4 */ |
| {F_RDLCK, 0, 2L, 3L, NOBLOCK}, |
| /* Child_b read lock on byte 6 to byte 8 */ |
| {F_RDLCK, 0, 6L, 3L, NOBLOCK}, |
| /* |
| * Parent_c read lock on byte 1 to |
| * byte 7 |
| */ |
| {F_RDLCK, 0, 1L, 7L, IGNORED}, |
| /* |
| * Parent_d read lock on |
| * byte 3 to byte 9 |
| */ |
| {F_RDLCK, 0, 3L, 7L, |
| IGNORED},}, |
| |
| /* #11 Parent_a making a write lock on entire file */ |
| {{F_WRLCK, 0, 0L, 0L, IGNORED}, |
| /* Parent_b skipped */ |
| {SKIP}, |
| /* Child_a read lock on byte 3 to byte 7 */ |
| {F_RDLCK, 0, 3L, 5L, NOBLOCK}, |
| /* Child_b read lock on byte 3 to byte 7 */ |
| {F_RDLCK, 0, 3L, 5L, NOBLOCK}, |
| /* |
| * Parent_c read lock on byte 3 to |
| * byte 7 |
| */ |
| {F_RDLCK, 0, 3L, 5L, IGNORED}, |
| /* Parent_d skipped */ |
| {SKIP},}, |
| }; |
| |
| static testcase *thiscase; |
| static struct flock *thislock; |
| static int parent; |
| static int child_flag1 = 0; |
| static int child_flag2 = 0; |
| static int parent_flag = 0; |
| static int alarm_flag = 0; |
| static int child_pid[2], flag[2]; |
| static int fd; |
| static int test; |
| static char tmpname[40]; |
| |
| #define FILEDATA "tenbytes!" |
| |
| extern void catch_int(int sig); /* signal catching subroutine */ |
| |
| char *TCID = "fcntl16"; |
| int TST_TOTAL = 1; |
| |
| #ifdef UCLINUX |
| static char *argv0; |
| #endif |
| |
| /* |
| * cleanup - performs all the ONE TIME cleanup for this test at completion or |
| * premature exit |
| */ |
| void cleanup(void) |
| { |
| tst_rmdir(); |
| |
| } |
| |
| void dochild(int kid) |
| { |
| /* child process */ |
| struct sigaction sact; |
| sact.sa_flags = 0; |
| sact.sa_handler = catch_int; |
| sigemptyset(&sact.sa_mask); |
| (void)sigaction(SIGUSR1, &sact, NULL); |
| |
| /* Lock should succeed after blocking and parent releases lock */ |
| if (kid) { |
| if ((kill(parent, SIGUSR2)) < 0) { |
| tst_resm(TFAIL, "Attempt to send signal to parent " |
| "failed"); |
| tst_resm(TFAIL, "Test case %d, child %d, errno = %d", |
| test + 1, kid, errno); |
| exit(1); |
| } |
| } else { |
| if ((kill(parent, SIGUSR1)) < 0) { |
| tst_resm(TFAIL, "Attempt to send signal to parent " |
| "failed"); |
| tst_resm(TFAIL, "Test case %d, child %d, errno = %d", |
| test + 1, kid, errno); |
| exit(1); |
| } |
| } |
| |
| if ((fcntl(fd, F_SETLKW, thislock)) < 0) { |
| if (errno == EINTR && parent_flag) { |
| /* |
| * signal received is waiting for lock to clear, |
| * this is expected if flag = WILLBLOCK |
| */ |
| exit(1); |
| } else { |
| tst_resm(TFAIL, "Attempt to set child BLOCKING lock " |
| "failed"); |
| tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, |
| errno); |
| exit(2); |
| } |
| } |
| exit(0); |
| } /* end of child process */ |
| |
| #ifdef UCLINUX |
| static int kid_uc; |
| |
| void dochild_uc(void) |
| { |
| dochild(kid_uc); |
| } |
| #endif |
| |
| void catch_alarm(int sig) |
| { |
| alarm_flag = 1; |
| } |
| |
| void catch_usr1(int sig) |
| { /* invoked on catching SIGUSR1 */ |
| /* |
| * Set flag to let parent know that child #1 is ready to have the |
| * lock removed |
| */ |
| child_flag1 = 1; |
| } |
| |
| void catch_usr2(int sig) |
| { /* invoked on catching SIGUSR2 */ |
| /* |
| * Set flag to let parent know that child #2 is ready to have the |
| * lock removed |
| */ |
| child_flag2 = 1; |
| } |
| |
| void catch_int(int sig) |
| { /* invoked on child catching SIGUSR1 */ |
| /* |
| * Set flag to interrupt fcntl call in child and force a controlled |
| * exit |
| */ |
| parent_flag = 1; |
| } |
| |
| void child_sig(int sig, int nkids) |
| { |
| int i; |
| |
| for (i = 0; i < nkids; i++) { |
| if (kill(child_pid[i], 0) == 0) { |
| if ((kill(child_pid[i], sig)) < 0) { |
| tst_resm(TFAIL, "Attempt to signal child %d, " |
| "failed", i + 1); |
| } |
| } |
| } |
| } |
| |
| /* |
| * setup - performs all ONE TIME steup for this test |
| */ |
| void setup(void) |
| { |
| struct sigaction sact; |
| |
| tst_sig(FORK, DEF_HANDLER, cleanup); |
| |
| umask(0); |
| |
| /* Pause if option was specified */ |
| TEST_PAUSE; |
| |
| parent = getpid(); |
| |
| tst_tmpdir(); |
| |
| /* On NFS or not */ |
| if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC) |
| NO_NFS = 0; |
| |
| /* set up temp filename */ |
| sprintf(tmpname, "fcntl4.%d", parent); |
| |
| /* |
| * Set up signal handling functions |
| */ |
| memset(&sact, 0, sizeof(sact)); |
| sact.sa_handler = catch_usr1; |
| sigemptyset(&sact.sa_mask); |
| sigaddset(&sact.sa_mask, SIGUSR1); |
| sigaction(SIGUSR1, &sact, NULL); |
| |
| memset(&sact, 0, sizeof(sact)); |
| sact.sa_handler = catch_usr2; |
| sigemptyset(&sact.sa_mask); |
| sigaddset(&sact.sa_mask, SIGUSR2); |
| sigaction(SIGUSR2, &sact, NULL); |
| |
| memset(&sact, 0, sizeof(sact)); |
| sact.sa_handler = catch_alarm; |
| sigemptyset(&sact.sa_mask); |
| sigaddset(&sact.sa_mask, SIGALRM); |
| sigaction(SIGALRM, &sact, NULL); |
| } |
| |
| int run_test(int file_flag, int file_mode, int start, int end) |
| { |
| int child_count; |
| int child; |
| int nexited; |
| int status, expect_stat; |
| int i, fail = 0; |
| |
| /* loop through all test cases */ |
| for (test = start; test < end; test++) { |
| /* open a temp file to lock */ |
| fd = open(tmpname, file_flag, file_mode); |
| if (fd < 0) { |
| tst_brkm(TBROK, cleanup, "open failed"); |
| } |
| |
| /* write some dummy data to the file */ |
| (void)write(fd, FILEDATA, 10); |
| |
| /* Initialize first parent lock structure */ |
| thiscase = &testcases[test]; |
| thislock = &thiscase->parent_a; |
| |
| /* set the initial parent lock on the file */ |
| if ((fcntl(fd, F_SETLK, thislock)) < 0) { |
| tst_resm(TFAIL, "First parent lock failed"); |
| tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, |
| errno); |
| close(fd); |
| unlink(tmpname); |
| return 1; |
| } |
| |
| /* Initialize second parent lock structure */ |
| thislock = &thiscase->parent_b; |
| |
| if ((thislock->l_type) != IGNORED) { /*SKIPVAL */ |
| /* set the second parent lock */ |
| if ((fcntl(fd, F_SETLK, thislock)) < 0) { |
| tst_resm(TFAIL, "Second parent lock failed"); |
| tst_resm(TFAIL, "Test case %d, errno = %d", |
| test + 1, errno); |
| close(fd); |
| unlink(tmpname); |
| return 1; |
| } |
| } |
| |
| /* Initialize first child lock structure */ |
| thislock = &thiscase->child_a; |
| |
| /* Initialize child counter and flags */ |
| alarm_flag = parent_flag = 0; |
| child_flag1 = child_flag2 = 0; |
| child_count = 0; |
| |
| /* spawn child processes */ |
| for (i = 0; i < 2; i++) { |
| if (thislock->l_type != IGNORED) { |
| if ((child = FORK_OR_VFORK()) == 0) { |
| #ifdef UCLINUX |
| if (self_exec(argv0, "ddddd", i, parent, |
| test, thislock, fd) < 0) { |
| perror("self_exec failed"); |
| return 1; |
| } |
| #else |
| dochild(i); |
| #endif |
| } |
| if (child < 0) { |
| perror("Fork failed"); |
| return 1; |
| } |
| child_count++; |
| child_pid[i] = child; |
| flag[i] = thislock->l_pid; |
| } |
| /* Initialize second child lock structure */ |
| thislock = &thiscase->child_b; |
| } |
| /* parent process */ |
| |
| /* |
| * Wait for children to signal they are ready. Set a timeout |
| * just in case they don't signal at all. |
| */ |
| alarm(TIME_OUT); |
| |
| while (!alarm_flag |
| && (child_flag1 + child_flag2 != child_count)) { |
| pause(); |
| } |
| |
| /* |
| * Turn off alarm and unmask signals |
| */ |
| alarm((unsigned)0); |
| |
| if (child_flag1 + child_flag2 != child_count) { |
| tst_resm(TFAIL, "Test case %d: kids didn't signal", |
| test + 1); |
| fail = 1; |
| } |
| child_flag1 = child_flag2 = alarm_flag = 0; |
| |
| thislock = &thiscase->parent_c; |
| |
| /* set the third parent lock on the file */ |
| if ((fcntl(fd, F_SETLK, thislock)) < 0) { |
| tst_resm(TFAIL, "Third parent lock failed"); |
| tst_resm(TFAIL, "Test case %d, errno = %d", |
| test + 1, errno); |
| close(fd); |
| unlink(tmpname); |
| return 1; |
| } |
| |
| /* Initialize fourth parent lock structure */ |
| thislock = &thiscase->parent_d; |
| |
| if ((thislock->l_type) != IGNORED) { /*SKIPVAL */ |
| /* set the fourth parent lock */ |
| if ((fcntl(fd, F_SETLK, thislock)) < 0) { |
| tst_resm(TINFO, "Fourth parent lock failed"); |
| tst_resm(TINFO, "Test case %d, errno = %d", |
| test + 1, errno); |
| close(fd); |
| unlink(tmpname); |
| return 1; |
| } |
| } |
| |
| /* |
| * Wait for children to exit, or for timeout to occur. |
| * Timeouts are expected for testcases where kids are |
| * 'WILLBLOCK', In that case, send kids a wakeup interrupt |
| * and wait again for them. If a second timeout occurs, then |
| * something is wrong. |
| */ |
| alarm_flag = nexited = 0; |
| while (nexited < child_count) { |
| alarm(TIME_OUT); |
| child = wait(&status); |
| alarm(0); |
| |
| if (child == -1) { |
| if (errno != EINTR || alarm_flag != 1) { |
| /* |
| * Some error other than a timeout, |
| * or else this is the second |
| * timeout. Both cases are errors. |
| */ |
| break; |
| } |
| |
| /* |
| * Expected timeout case. Signal kids then |
| * go back and wait again |
| */ |
| child_sig(SIGUSR1, child_count); |
| continue; |
| } |
| |
| for (i = 0; i < child_count; i++) |
| if (child == child_pid[i]) |
| break; |
| if (i == child_count) { |
| /* |
| * Ignore unexpected kid, it could be a |
| * leftover from a previous iteration that |
| * timed out. |
| */ |
| continue; |
| } |
| |
| /* Found the right kid, check his status */ |
| nexited++; |
| |
| expect_stat = (flag[i] == NOBLOCK) ? 0 : 1; |
| |
| if (!WIFEXITED(status) |
| || WEXITSTATUS(status) != expect_stat) { |
| /* got unexpected exit status from kid */ |
| tst_resm(TFAIL, "Test case %d: child %d %s " |
| "or got bad status (x%x)", test + 1, |
| i, (flag[i] == NOBLOCK) ? |
| "BLOCKED unexpectedly" : |
| "failed to BLOCK", status); |
| fail = 1; |
| } |
| } |
| |
| if (nexited != child_count) { |
| tst_resm(TFAIL, "Test case %d, caught %d expected %d " |
| "children", test + 1, nexited, child_count); |
| child_sig(SIGKILL, nexited); |
| fail = 1; |
| } |
| close(fd); |
| } |
| unlink(tmpname); |
| if (fail) { |
| return 1; |
| } else { |
| return 0; |
| } |
| return 0; |
| } |
| |
| int main(int ac, char **av) |
| { |
| |
| int lc; |
| const char *msg; |
| |
| if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { |
| tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
| } |
| #ifdef UCLINUX |
| maybe_run_child(dochild_uc, "ddddd", &kid_uc, &parent, &test, |
| &thislock, &fd); |
| argv0 = av[0]; |
| #endif |
| |
| setup(); /* global setup */ |
| |
| for (lc = 0; TEST_LOOPING(lc); lc++) { |
| /* reset tst_count in case we are looping */ |
| tst_count = 0; |
| |
| /* //block1: */ |
| /* |
| * Check file locks on an ordinary file without |
| * mandatory locking |
| */ |
| tst_resm(TINFO, "Entering block 1"); |
| if (run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 11)) { |
| tst_resm(TINFO, "Test case 1: without mandatory " |
| "locking FAILED"); |
| } else { |
| tst_resm(TINFO, "Test case 1: without manadatory " |
| "locking PASSED"); |
| } |
| tst_resm(TINFO, "Exiting block 1"); |
| |
| /* //block2: */ |
| /* |
| * Check the file locks on a file with mandatory record |
| * locking |
| */ |
| tst_resm(TINFO, "Entering block 2"); |
| if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC, S_ISGID | |
| S_IRUSR | S_IWUSR, 0, 11)) { |
| tst_resm(TINFO, "Test case 2: with mandatory record " |
| "locking FAILED"); |
| } else { |
| if (NO_NFS) |
| tst_resm(TINFO, "Test case 2: with mandatory" |
| " record locking PASSED"); |
| else |
| tst_resm(TCONF, "Test case 2: NFS does not" |
| " support mandatory locking"); |
| } |
| tst_resm(TINFO, "Exiting block 2"); |
| |
| /* //block3: */ |
| /* |
| * Check file locks on a file with mandatory record locking |
| * and no delay |
| */ |
| tst_resm(TINFO, "Entering block 3"); |
| if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC | O_NDELAY, |
| S_ISGID | S_IRUSR | S_IWUSR, 0, 11)) { |
| tst_resm(TINFO, "Test case 3: mandatory locking with " |
| "NODELAY FAILED"); |
| } else { |
| if (NO_NFS) |
| tst_resm(TINFO, "Test case 3: mandatory" |
| " locking with NODELAY PASSED"); |
| else |
| tst_resm(TCONF, "Test case 3: NFS does not" |
| " support mandatory locking"); |
| } |
| tst_resm(TINFO, "Exiting block 3"); |
| } |
| cleanup(); |
| tst_exit(); |
| } |