1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or https://opensource.org/licenses/CDDL-1.0. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2012 by Delphix. All rights reserved. 29 */ 30 31 /* 32 * -------------------------------------------------------------------- 33 * The purpose of this test is to see if the bug reported (#4723351) for 34 * UFS exists when using a ZFS file system. 35 * -------------------------------------------------------------------- 36 * 37 */ 38 #define _REENTRANT 1 39 #include <stdio.h> 40 #include <fcntl.h> 41 #include <pthread.h> 42 #include <string.h> 43 #include <errno.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 49 static char *filebase; 50 51 static int 52 pickidx(void) 53 { 54 return (random() % 1000); 55 } 56 57 static void * 58 mover(void *a) 59 { 60 (void) a; 61 char buf[256]; 62 int idx, len, ret; 63 64 len = strlen(filebase) + 5; 65 66 for (;;) { 67 idx = pickidx(); 68 (void) snprintf(buf, len, "%s.%03d", filebase, idx); 69 ret = rename(filebase, buf); 70 if (ret < 0 && errno != ENOENT) 71 (void) perror("renaming file"); 72 } 73 74 return (NULL); 75 } 76 77 static void * 78 cleaner(void *a) 79 { 80 (void) a; 81 char buf[256]; 82 int idx, len, ret; 83 84 len = strlen(filebase) + 5; 85 86 for (;;) { 87 idx = pickidx(); 88 (void) snprintf(buf, len, "%s.%03d", filebase, idx); 89 ret = remove(buf); 90 if (ret < 0 && errno != ENOENT) 91 (void) perror("removing file"); 92 } 93 94 return (NULL); 95 } 96 97 static void * 98 writer(void *a) 99 { 100 int *fd = (int *)a; 101 int ret; 102 103 for (;;) { 104 if (*fd != -1) 105 (void) close (*fd); 106 107 *fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644); 108 if (*fd == -1) { 109 perror("fail to open test file, refreshing it"); 110 continue; 111 } 112 113 ret = write(*fd, "test\n", 5); 114 if (ret != 5) 115 perror("writing file"); 116 } 117 118 return (NULL); 119 } 120 121 int 122 main(int argc, char **argv) 123 { 124 int fd; 125 pthread_t tid; 126 127 if (argc == 1) { 128 (void) printf("Usage: %s <filebase>\n", argv[0]); 129 exit(-1); 130 } 131 132 filebase = argv[1]; 133 fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644); 134 if (fd < 0) { 135 perror("creating test file"); 136 exit(-1); 137 } 138 139 (void) pthread_setconcurrency(4); /* 3 threads + main */ 140 (void) pthread_create(&tid, NULL, mover, NULL); 141 (void) pthread_create(&tid, NULL, cleaner, NULL); 142 (void) pthread_create(&tid, NULL, writer, (void *) &fd); 143 144 for (;;) { 145 int ret; 146 struct stat st; 147 148 ret = stat(filebase, &st); 149 if (ret == 0 && (st.st_nlink > 2 || st.st_nlink < 1)) { 150 (void) printf("st.st_nlink = %d, exiting\n", \ 151 (int)st.st_nlink); 152 exit(0); 153 } 154 (void) sleep(1); 155 } 156 157 return (0); 158 } 159