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 http://www.opensolaris.org/os/licensing.
  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) 2013 by Delphix. All rights reserved.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/stat.h>
  33 #include <fcntl.h>
  34 #include <thread.h>
  35 #include <string.h>
  36 #include <stdio.h>
  37 #include <unistd.h>
  38 #include <stdlib.h>
  39 #include <errno.h>
  40 
  41 /*
  42  * The size of the output file, "go.out", should be 80*8192*2 = 1310720
  43  *
  44  * $ cd /tmp; go; ls -l go.out
  45  * done.
  46  * -rwxr-xr-x   1 jdm   staff   1310720 Apr 13 19:45 go.out
  47  * $ cd /zfs; go; ls -l go.out
  48  * done.
  49  * -rwxr-xr-x   1 jdm   staff   663552 Apr 13 19:45 go.out
  50  *
  51  * The file on zfs is short as it does not appear that zfs is making the
  52  * implicit seek to EOF and the actual write atomic. From the SUSv3
  53  * interface spec, behavior is undefined if concurrent writes are performed
  54  * from multi-processes to a single file. So I don't know if this is a
  55  * standards violation, but I cannot find any such disclaimers in our
  56  * man pages. This issue came up at a customer site in another context, and
  57  * the suggestion was to open the file with O_APPEND, but that wouldn't
  58  * help with zfs(see 4977529). Also see bug# 5031301.
  59  */
  60 
  61 static int outfd = 0;
  62 
  63 static void *
  64 go(void *data)
  65 {
  66         int i = 0, n = *(int *)data;
  67         char buf[8192] = {0};
  68         (void) memset(buf, n, sizeof (buf));
  69 
  70         for (i = 0; i < 80; i++) {
  71                 (void) write(outfd, buf, sizeof (buf));
  72         }
  73         return (NULL);
  74 }
  75 
  76 static void
  77 usage()
  78 {
  79         (void) fprintf(stderr,
  80             "usage: zfs_threadsappend <file name>\n");
  81         exit(1);
  82 }
  83 
  84 int
  85 main(int argc, char **argv)
  86 {
  87         int     ret = 0;
  88         long    ncpus = 0;
  89         int     i;
  90 
  91         if (argc != 2) {
  92                 usage();
  93         }
  94 
  95         ncpus = sysconf(_SC_NPROCESSORS_ONLN);
  96         if (ncpus < 0) {
  97                 (void) fprintf(stderr,
  98                     "Invalid return from sysconf(_SC_NPROCESSORS_ONLN)"
  99                     " : errno (decimal)=%d\n", errno);
 100                 exit(1);
 101         }
 102         if (ncpus < 2) {
 103                 (void) fprintf(stderr,
 104                     "Must execute this binary on a multi-processor system\n");
 105                 exit(1);
 106         }
 107 
 108         outfd = open(argv[optind++], O_RDWR|O_CREAT|O_APPEND|O_TRUNC, 0777);
 109         if (outfd == -1) {
 110                 (void) fprintf(stderr,
 111                     "zfs_threadsappend: "
 112                     "open(%s, O_RDWR|O_CREAT|O_APPEND|O_TRUNC, 0777)"
 113                     " failed\n", argv[optind]);
 114                 perror("open");
 115                 exit(1);
 116         }
 117 
 118         for (i = 0; i < 2; i++) {
 119                 ret = thr_create(NULL, 0, go, (void *)&i, 0, NULL);
 120                 if (ret != 0) {
 121                         (void) fprintf(stderr,
 122                             "zfs_threadsappend: thr_create(#%d) "
 123                             "failed error=%d\n", i+1, ret);
 124                         exit(1);
 125                 }
 126         }
 127 
 128         while (thr_join(0, NULL, NULL) == 0)
 129                 continue;
 130 
 131         return (0);
 132 }