Home | History | Annotate | Line # | Download | only in librumpuser
rumpuser_file.c revision 1.2
      1 /*	$NetBSD: rumpuser_file.c,v 1.2 2014/08/24 14:37:31 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007-2010 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 /* NOTE this code will move to a new driver in the next hypercall revision */
     29 
     30 #include "rumpuser_port.h"
     31 
     32 #if !defined(lint)
     33 __RCSID("$NetBSD: rumpuser_file.c,v 1.2 2014/08/24 14:37:31 pooka Exp $");
     34 #endif /* !lint */
     35 
     36 #include <sys/ioctl.h>
     37 #include <sys/mman.h>
     38 #include <sys/uio.h>
     39 #include <sys/stat.h>
     40 #include <sys/time.h>
     41 #include <sys/types.h>
     42 
     43 #ifdef __NetBSD__
     44 #include <sys/disk.h>
     45 #include <sys/disklabel.h>
     46 #include <sys/dkio.h>
     47 #endif
     48 
     49 #if defined(__NetBSD__) || defined(__FreeBSD__) || \
     50     defined(__DragonFly__) || defined(__APPLE__)
     51 #define	__BSD__
     52 #endif
     53 
     54 #if defined(__BSD__)
     55 #include <sys/sysctl.h>
     56 #endif
     57 
     58 #include <assert.h>
     59 #include <errno.h>
     60 #include <fcntl.h>
     61 #include <netdb.h>
     62 #include <stdarg.h>
     63 #include <stdint.h>
     64 #include <stdio.h>
     65 #include <stdlib.h>
     66 #include <string.h>
     67 #include <unistd.h>
     68 
     69 #include <rump/rumpuser.h>
     70 
     71 #include "rumpuser_int.h"
     72 
     73 int
     74 rumpuser_getfileinfo(const char *path, uint64_t *sizep, int *ftp)
     75 {
     76 	struct stat sb;
     77 	uint64_t size = 0;
     78 	int needsdev = 0, rv = 0, ft = 0;
     79 	int fd = -1;
     80 
     81 	if (stat(path, &sb) == -1) {
     82 		rv = errno;
     83 		goto out;
     84 	}
     85 
     86 	switch (sb.st_mode & S_IFMT) {
     87 	case S_IFDIR:
     88 		ft = RUMPUSER_FT_DIR;
     89 		break;
     90 	case S_IFREG:
     91 		ft = RUMPUSER_FT_REG;
     92 		break;
     93 	case S_IFBLK:
     94 		ft = RUMPUSER_FT_BLK;
     95 		needsdev = 1;
     96 		break;
     97 	case S_IFCHR:
     98 		ft = RUMPUSER_FT_CHR;
     99 		needsdev = 1;
    100 		break;
    101 	default:
    102 		ft = RUMPUSER_FT_OTHER;
    103 		break;
    104 	}
    105 
    106 	if (!needsdev) {
    107 		size = sb.st_size;
    108 	} else if (sizep) {
    109 		/*
    110 		 * Welcome to the jungle.  Of course querying the kernel
    111 		 * for a device partition size is supposed to be far from
    112 		 * trivial.  On NetBSD we use ioctl.  On $other platform
    113 		 * we have a problem.  We try "the lseek trick" and just
    114 		 * fail if that fails.  Platform specific code can later
    115 		 * be written here if appropriate.
    116 		 *
    117 		 * On NetBSD we hope and pray that for block devices nobody
    118 		 * else is holding them open, because otherwise the kernel
    119 		 * will not permit us to open it.  Thankfully, this is
    120 		 * usually called only in bootstrap and then we can
    121 		 * forget about it.
    122 		 */
    123 #ifndef __NetBSD__
    124 		off_t off;
    125 
    126 		fd = open(path, O_RDONLY);
    127 		if (fd == -1) {
    128 			rv = errno;
    129 			goto out;
    130 		}
    131 
    132 		off = lseek(fd, 0, SEEK_END);
    133 		if (off != 0) {
    134 			size = off;
    135 			goto out;
    136 		}
    137 		fprintf(stderr, "error: device size query not implemented on "
    138 		    "this platform\n");
    139 		rv = EOPNOTSUPP;
    140 		goto out;
    141 #else
    142 		struct disklabel lab;
    143 		struct partition *parta;
    144 		struct dkwedge_info dkw;
    145 
    146 		fd = open(path, O_RDONLY);
    147 		if (fd == -1) {
    148 			rv = errno;
    149 			goto out;
    150 		}
    151 
    152 		if (ioctl(fd, DIOCGDINFO, &lab) == 0) {
    153 			parta = &lab.d_partitions[DISKPART(sb.st_rdev)];
    154 			size = (uint64_t)lab.d_secsize * parta->p_size;
    155 			goto out;
    156 		}
    157 
    158 		if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) {
    159 			/*
    160 			 * XXX: should use DIOCGDISKINFO to query
    161 			 * sector size, but that requires proplib,
    162 			 * so just don't bother for now.  it's nice
    163 			 * that something as difficult as figuring out
    164 			 * a partition's size has been made so easy.
    165 			 */
    166 			size = dkw.dkw_size << DEV_BSHIFT;
    167 			goto out;
    168 		}
    169 
    170 		rv = errno;
    171 #endif /* __NetBSD__ */
    172 	}
    173 
    174  out:
    175 	if (rv == 0 && sizep)
    176 		*sizep = size;
    177 	if (rv == 0 && ftp)
    178 		*ftp = ft;
    179 	if (fd != -1)
    180 		close(fd);
    181 
    182 	ET(rv);
    183 }
    184 
    185 int
    186 rumpuser_open(const char *path, int ruflags, int *fdp)
    187 {
    188 	int fd, flags, rv;
    189 
    190 	switch (ruflags & RUMPUSER_OPEN_ACCMODE) {
    191 	case RUMPUSER_OPEN_RDONLY:
    192 		flags = O_RDONLY;
    193 		break;
    194 	case RUMPUSER_OPEN_WRONLY:
    195 		flags = O_WRONLY;
    196 		break;
    197 	case RUMPUSER_OPEN_RDWR:
    198 		flags = O_RDWR;
    199 		break;
    200 	default:
    201 		rv = EINVAL;
    202 		goto out;
    203 	}
    204 
    205 #define TESTSET(_ru_, _h_) if (ruflags & _ru_) flags |= _h_;
    206 	TESTSET(RUMPUSER_OPEN_CREATE, O_CREAT);
    207 	TESTSET(RUMPUSER_OPEN_EXCL, O_EXCL);
    208 #undef TESTSET
    209 
    210 	KLOCK_WRAP(fd = open(path, flags, 0644));
    211 	if (fd == -1) {
    212 		rv = errno;
    213 	} else {
    214 		*fdp = fd;
    215 		rv = 0;
    216 	}
    217 
    218  out:
    219 	ET(rv);
    220 }
    221 
    222 int
    223 rumpuser_close(int fd)
    224 {
    225 	int nlocks;
    226 
    227 	rumpkern_unsched(&nlocks, NULL);
    228 	fsync(fd);
    229 	close(fd);
    230 	rumpkern_sched(nlocks, NULL);
    231 
    232 	ET(0);
    233 }
    234 
    235 /*
    236  * Assume "struct rumpuser_iovec" and "struct iovec" are the same.
    237  * If you encounter POSIX platforms where they aren't, add some
    238  * translation for iovlen > 1.
    239  */
    240 int
    241 rumpuser_iovread(int fd, struct rumpuser_iovec *ruiov, size_t iovlen,
    242 	int64_t roff, size_t *retp)
    243 {
    244 	struct iovec *iov = (struct iovec *)ruiov;
    245 	off_t off = (off_t)roff;
    246 	ssize_t nn;
    247 	int rv;
    248 
    249 	if (off == RUMPUSER_IOV_NOSEEK) {
    250 		KLOCK_WRAP(nn = readv(fd, iov, iovlen));
    251 	} else {
    252 		int nlocks;
    253 
    254 		rumpkern_unsched(&nlocks, NULL);
    255 		if (lseek(fd, off, SEEK_SET) == off) {
    256 			nn = readv(fd, iov, iovlen);
    257 		} else {
    258 			nn = -1;
    259 		}
    260 		rumpkern_sched(nlocks, NULL);
    261 	}
    262 
    263 	if (nn == -1) {
    264 		rv = errno;
    265 	} else {
    266 		*retp = (size_t)nn;
    267 		rv = 0;
    268 	}
    269 
    270 	ET(rv);
    271 }
    272 
    273 int
    274 rumpuser_iovwrite(int fd, const struct rumpuser_iovec *ruiov, size_t iovlen,
    275 	int64_t roff, size_t *retp)
    276 {
    277 	const struct iovec *iov = (const struct iovec *)ruiov;
    278 	off_t off = (off_t)roff;
    279 	ssize_t nn;
    280 	int rv;
    281 
    282 	if (off == RUMPUSER_IOV_NOSEEK) {
    283 		KLOCK_WRAP(nn = writev(fd, iov, iovlen));
    284 	} else {
    285 		int nlocks;
    286 
    287 		rumpkern_unsched(&nlocks, NULL);
    288 		if (lseek(fd, off, SEEK_SET) == off) {
    289 			nn = writev(fd, iov, iovlen);
    290 		} else {
    291 			nn = -1;
    292 		}
    293 		rumpkern_sched(nlocks, NULL);
    294 	}
    295 
    296 	if (nn == -1) {
    297 		rv = errno;
    298 	} else {
    299 		*retp = (size_t)nn;
    300 		rv = 0;
    301 	}
    302 
    303 	ET(rv);
    304 }
    305 
    306 int
    307 rumpuser_syncfd(int fd, int flags, uint64_t start, uint64_t len)
    308 {
    309 	int rv = 0;
    310 
    311 	/*
    312 	 * For now, assume fd is regular file and does not care
    313 	 * about read syncing
    314 	 */
    315 	if ((flags & RUMPUSER_SYNCFD_BOTH) == 0) {
    316 		rv = EINVAL;
    317 		goto out;
    318 	}
    319 	if ((flags & RUMPUSER_SYNCFD_WRITE) == 0) {
    320 		rv = 0;
    321 		goto out;
    322 	}
    323 
    324 #ifdef __NetBSD__
    325 	{
    326 	int fsflags = FDATASYNC;
    327 
    328 	if (fsflags & RUMPUSER_SYNCFD_SYNC)
    329 		fsflags |= FDISKSYNC;
    330 	if (fsync_range(fd, fsflags, start, len) == -1)
    331 		rv = errno;
    332 	}
    333 #else
    334 	/* el-simplo */
    335 	if (fsync(fd) == -1)
    336 		rv = errno;
    337 #endif
    338 
    339  out:
    340 	ET(rv);
    341 }
    342