1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2012 Jilin Xpd <jilinxpd@gmail.com>
  14  * Copyright 2018 Nexenta Systems, Inc.
  15  */
  16 
  17 /*
  18  * After close file but before munmap it, test if we can still write into
  19  * mapped pages and the dirty pages are eventually synced to file,
  20  * the result should be that we can do it as long as we dont munmap it.
  21  * When userland attempts to close mapped file, smbfs will keep SMB FID
  22  * alive if there are mapped pages(not unmapped yet), so the otW will stay
  23  * open until last ref. to vnode goes away.
  24  * This program tests if smbfs works as we said.
  25  */
  26 
  27 #include <sys/mman.h>
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <fcntl.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <unistd.h>
  34 #include <string.h>
  35 #include <errno.h>
  36 
  37 int
  38 main(int argc, char **argv)
  39 {
  40         char *file_addr;
  41         char *p;
  42         size_t filesize;
  43         size_t blksize;
  44         int fid;
  45         int i;
  46         char *c = "?#*%&";
  47 
  48         if (argc != 2) {
  49                 fprintf(stderr, "\tusage:\n\tclose_wr <filename>\n");
  50                 return (1);
  51         }
  52 
  53         /* open test file */
  54         fid = open(argv[1], O_RDWR | O_CREAT | O_TRUNC,
  55             S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
  56         if (fid == -1) {
  57                 fprintf(stderr, "open %s error=%d\n", argv[1], errno);
  58                 return (1);
  59         }
  60 
  61         /* extend file */
  62         filesize = 64 * 1024;
  63         if (ftruncate(fid, filesize) == -1) {
  64                 fprintf(stderr, "ftrunc %s error=%d\n", argv[1], errno);
  65                 return (1);
  66         }
  67 
  68         /* map file */
  69         file_addr = mmap(NULL, filesize,
  70             PROT_READ | PROT_WRITE, MAP_SHARED, fid, 0);
  71         if (file_addr == MAP_FAILED) {
  72                 fprintf(stderr, "mmap %s error=%d\n", argv[1], errno);
  73                 return (1);
  74         }
  75 
  76         /* erase file */
  77         memset(file_addr, 0, filesize);
  78 
  79         /* close file here! */
  80         if (close(fid) == -1) {
  81                 fprintf(stderr, "close %s error=%d\n", argv[1], errno);
  82                 return (1);
  83         }
  84 
  85         /*
  86          * write somthing into mapped addr after close file,
  87          * it should be ok before munmap
  88          */
  89         blksize = filesize / 4;
  90         for (i = 0, p = file_addr; i < 4; i++, p += blksize) {
  91                 memset(p, c[i], blksize);
  92         }
  93 
  94         /* sync pages to file */
  95         if (msync(file_addr, filesize, MS_SYNC) == -1) {
  96                 fprintf(stderr, "msync %s error=%d\n", argv[1], errno);
  97                 return (1);
  98         }
  99 
 100         /* unmap file */
 101         if (munmap(file_addr, filesize) == -1) {
 102                 fprintf(stderr, "munmap %s error=%d\n", argv[1], errno);
 103                 return (1);
 104         }
 105 
 106         return (0);
 107 }