1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * Copyright (c) 2013 by Delphix. All rights reserved. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <pthread.h> 36 #include <string.h> 37 #include <stdio.h> 38 #include <unistd.h> 39 #include <stdlib.h> 40 #include <errno.h> 41 42 /* 43 * The size of the output file, "go.out", should be 80*8192*2 = 1310720 44 * 45 * $ cd /tmp; go; ls -l go.out 46 * done. 47 * -rwxr-xr-x 1 jdm staff 1310720 Apr 13 19:45 go.out 48 * $ cd /zfs; go; ls -l go.out 49 * done. 50 * -rwxr-xr-x 1 jdm staff 663552 Apr 13 19:45 go.out 51 * 52 * The file on zfs is short as it does not appear that zfs is making the 53 * implicit seek to EOF and the actual write atomic. From the SUSv3 54 * interface spec, behavior is undefined if concurrent writes are performed 55 * from multi-processes to a single file. So I don't know if this is a 56 * standards violation, but I cannot find any such disclaimers in our 57 * man pages. This issue came up at a customer site in another context, and 58 * the suggestion was to open the file with O_APPEND, but that wouldn't 59 * help with zfs(see 4977529). Also see bug# 5031301. 60 */ 61 62 static int outfd = 0; 63 64 static void * 65 go(void *data) 66 { 67 int ret, i = 0, n = *(int *)data; 68 char buf[8192] = {0}; 69 (void) memset(buf, n, sizeof (buf)); 70 71 for (i = 0; i < 80; i++) { 72 ret = write(outfd, buf, sizeof (buf)); 73 if (ret != sizeof (buf)) 74 perror("write"); 75 } 76 return (NULL); 77 } 78 79 static void 80 usage(void) 81 { 82 (void) fprintf(stderr, 83 "usage: zfs_threadsappend <file name>\n"); 84 exit(1); 85 } 86 87 int 88 main(int argc, char **argv) 89 { 90 pthread_t tid; 91 int ret = 0; 92 long ncpus = 0; 93 int i; 94 95 if (argc != 2) { 96 usage(); 97 } 98 99 ncpus = sysconf(_SC_NPROCESSORS_ONLN); 100 if (ncpus < 0) { 101 (void) fprintf(stderr, 102 "Invalid return from sysconf(_SC_NPROCESSORS_ONLN)" 103 " : errno (decimal)=%d\n", errno); 104 exit(1); 105 } 106 if (ncpus < 2) { 107 (void) fprintf(stderr, 108 "Must execute this binary on a multi-processor system\n"); 109 exit(1); 110 } 111 112 outfd = open(argv[optind++], O_RDWR|O_CREAT|O_APPEND|O_TRUNC, 0777); 113 if (outfd == -1) { 114 (void) fprintf(stderr, 115 "zfs_threadsappend: " 116 "open(%s, O_RDWR|O_CREAT|O_APPEND|O_TRUNC, 0777)" 117 " failed\n", argv[optind]); 118 perror("open"); 119 exit(1); 120 } 121 122 for (i = 0; i < 2; i++) { 123 ret = pthread_create(&tid, NULL, go, (void *)&i); 124 if (ret != 0) { 125 (void) fprintf(stderr, 126 "zfs_threadsappend: thr_create(#%d) " 127 "failed error=%d\n", i+1, ret); 128 exit(1); 129 } 130 } 131 132 while (pthread_join(tid, NULL) == 0) 133 continue; 134 135 return (0); 136 } 137