Home | History | Annotate | Line # | Download | only in libukfs
ukfs.c revision 1.1
      1 /*	$NetBSD: ukfs.c,v 1.1 2008/07/29 13:17:41 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Finnish Cultural Foundation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * This library enables access to files systems directly without
     33  * involving system calls.
     34  */
     35 
     36 #ifdef __linux__
     37 #define _XOPEN_SOURCE 500
     38 #define _BSD_SOURCE
     39 #define _FILE_OFFSET_BITS 64
     40 #endif
     41 
     42 #include <sys/stat.h>
     43 
     44 #include <assert.h>
     45 #include <err.h>
     46 #include <errno.h>
     47 #include <pthread.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 #include <stdint.h>
     53 
     54 #include <rump/ukfs.h>
     55 
     56 #include <rump/rump.h>
     57 #include <rump/rump_syscalls.h>
     58 
     59 #define UKFS_MODE_DEFAULT 0555
     60 
     61 struct ukfs {
     62 	struct mount *ukfs_mp;
     63 	struct vnode *ukfs_rvp;
     64 
     65 	pthread_spinlock_t ukfs_spin;
     66 	pid_t ukfs_nextpid;
     67 	struct vnode *ukfs_cdir;
     68 };
     69 
     70 struct mount *
     71 ukfs_getmp(struct ukfs *ukfs)
     72 {
     73 
     74 	return ukfs->ukfs_mp;
     75 }
     76 
     77 struct vnode *
     78 ukfs_getrvp(struct ukfs *ukfs)
     79 {
     80 	struct vnode *rvp;
     81 
     82 	rvp = ukfs->ukfs_rvp;
     83 	rump_vp_incref(rvp);
     84 
     85 	return rvp;
     86 }
     87 
     88 static pid_t
     89 nextpid(struct ukfs *ukfs)
     90 {
     91 	pid_t npid;
     92 
     93 	pthread_spin_lock(&ukfs->ukfs_spin);
     94 	npid = ukfs->ukfs_nextpid++;
     95 	pthread_spin_unlock(&ukfs->ukfs_spin);
     96 
     97 	return npid;
     98 }
     99 
    100 static void
    101 precall(struct ukfs *ukfs)
    102 {
    103 	struct vnode *rvp, *cvp;
    104 
    105 	rump_setup_curlwp(nextpid(ukfs), 1, 1);
    106 	rvp = ukfs_getrvp(ukfs);
    107 	pthread_spin_lock(&ukfs->ukfs_spin);
    108 	cvp = ukfs->ukfs_cdir;
    109 	pthread_spin_unlock(&ukfs->ukfs_spin);
    110 	rump_rcvp_set(rvp, cvp); /* takes refs */
    111 	rump_vp_rele(rvp);
    112 }
    113 
    114 static void
    115 postcall(struct ukfs *ukfs)
    116 {
    117 	struct vnode *rvp;
    118 
    119 	rvp = ukfs_getrvp(ukfs);
    120 	rump_rcvp_set(NULL, rvp);
    121 	rump_vp_rele(rvp);
    122 	rump_clear_curlwp();
    123 }
    124 
    125 int
    126 ukfs_init()
    127 {
    128 
    129 	rump_init();
    130 
    131 	return 0;
    132 }
    133 
    134 struct ukfs *
    135 ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
    136 	int mntflags, void *arg, size_t alen)
    137 {
    138 	struct ukfs *fs = NULL;
    139 	struct vfsops *vfsops;
    140 	struct mount *mp;
    141 	int rv = 0;
    142 
    143 	vfsops = rump_vfs_getopsbyname(vfsname);
    144 	if (vfsops == NULL) {
    145 		rv = ENOENT;
    146 		goto out;
    147 	}
    148 
    149 	mp = rump_mnt_init(vfsops, mntflags);
    150 
    151 	fs = malloc(sizeof(struct ukfs));
    152 	if (fs == NULL) {
    153 		rv = ENOMEM;
    154 		goto out;
    155 	}
    156 	memset(fs, 0, sizeof(struct ukfs));
    157 	pthread_spin_init(&fs->ukfs_spin, PTHREAD_PROCESS_SHARED);
    158 
    159 	rump_fakeblk_register(devpath);
    160 	rv = rump_mnt_mount(mp, mountpath, arg, &alen);
    161 	rump_fakeblk_deregister(devpath);
    162 	if (rv) {
    163 		warnx("VFS_MOUNT %d", rv);
    164 		goto out;
    165 	}
    166 	fs->ukfs_mp = mp;
    167 
    168 	rv = rump_vfs_root(fs->ukfs_mp, &fs->ukfs_rvp, 0);
    169 	fs->ukfs_cdir = ukfs_getrvp(fs);
    170 
    171  out:
    172 	if (rv) {
    173 		if (fs && fs->ukfs_mp)
    174 			rump_mnt_destroy(fs->ukfs_mp);
    175 		if (fs)
    176 			free(fs);
    177 		errno = rv;
    178 		fs = NULL;
    179 	}
    180 
    181 	return fs;
    182 }
    183 
    184 void
    185 ukfs_release(struct ukfs *fs, int flags)
    186 {
    187 	int rv;
    188 
    189 	if ((flags & UKFS_RELFLAG_NOUNMOUNT) == 0) {
    190 		rump_vp_rele(fs->ukfs_cdir);
    191 		rv = rump_vfs_sync(fs->ukfs_mp, 1, NULL);
    192 		rump_vp_recycle_nokidding(ukfs_getrvp(fs));
    193 		rv |= rump_vfs_unmount(fs->ukfs_mp, 0);
    194 		assert(rv == 0);
    195 	}
    196 
    197 	rump_vfs_syncwait(fs->ukfs_mp);
    198 	rump_mnt_destroy(fs->ukfs_mp);
    199 
    200 	pthread_spin_destroy(&fs->ukfs_spin);
    201 	free(fs);
    202 }
    203 
    204 /* don't need vn_lock(), since we don't have VXLOCK */
    205 #define VLE(a) rump_vp_lock_exclusive(a)
    206 #define VLS(a) rump_vp_lock_shared(a)
    207 #define VUL(a) rump_vp_unlock(a)
    208 #define AUL(a) assert(rump_vp_islocked(a) == 0)
    209 
    210 #define STDCALL(ukfs, thecall)						\
    211 	int rv = 0;							\
    212 									\
    213 	precall(ukfs);							\
    214 	thecall;							\
    215 	postcall(ukfs);							\
    216 	if (rv) {							\
    217 		errno = rv;						\
    218 		return -1;						\
    219 	}								\
    220 	return 0;
    221 
    222 int
    223 ukfs_getdents(struct ukfs *ukfs, const char *dirname, off_t *off,
    224 	uint8_t *buf, size_t bufsize)
    225 {
    226 	struct uio *uio;
    227 	struct vnode *vp;
    228 	size_t resid;
    229 	int rv, eofflag;
    230 
    231 	precall(ukfs);
    232 	rv = rump_namei(RUMP_NAMEI_LOOKUP, RUMP_NAMEI_LOCKLEAF, dirname,
    233 	    NULL, &vp, NULL);
    234 	postcall(ukfs);
    235 	if (rv)
    236 		goto out;
    237 
    238 	uio = rump_uio_setup(buf, bufsize, *off, RUMPUIO_READ);
    239 	rv = RUMP_VOP_READDIR(vp, uio, NULL, &eofflag, NULL, NULL);
    240 	VUL(vp);
    241 	*off = rump_uio_getoff(uio);
    242 	resid = rump_uio_free(uio);
    243 	rump_vp_rele(vp);
    244 
    245  out:
    246 	if (rv) {
    247 		errno = rv;
    248 		return -1;
    249 	}
    250 
    251 	/* LINTED: not totally correct return type, but follows syscall */
    252 	return bufsize - resid;
    253 }
    254 
    255 ssize_t
    256 ukfs_read(struct ukfs *ukfs, const char *filename, off_t off,
    257 	uint8_t *buf, size_t bufsize)
    258 {
    259 	int fd, rv = 0, dummy;
    260 	ssize_t xfer = -1; /* XXXgcc */
    261 
    262 	precall(ukfs);
    263 	fd = rump_sys_open(filename, RUMP_O_RDONLY, 0, &rv);
    264 	if (rv)
    265 		goto out;
    266 
    267 	xfer = rump_sys_pread(fd, buf, bufsize, 0, off, &rv);
    268 	rump_sys_close(fd, &dummy);
    269 
    270  out:
    271 	postcall(ukfs);
    272 	if (rv) {
    273 		errno = rv;
    274 		return -1;
    275 	}
    276 	return xfer;
    277 }
    278 
    279 ssize_t
    280 ukfs_write(struct ukfs *ukfs, const char *filename, off_t off,
    281 	uint8_t *buf, size_t bufsize)
    282 {
    283 	int fd, rv = 0, dummy;
    284 	ssize_t xfer = -1; /* XXXgcc */
    285 
    286 	precall(ukfs);
    287 	fd = rump_sys_open(filename, RUMP_O_WRONLY, 0, &rv);
    288 	if (rv)
    289 		goto out;
    290 
    291 	/* write and commit */
    292 	xfer = rump_sys_pwrite(fd, buf, bufsize, 0, off, &rv);
    293 	if (rv == 0)
    294 		rump_sys_fsync(fd, &dummy);
    295 
    296 	rump_sys_close(fd, &dummy);
    297 
    298  out:
    299 	postcall(ukfs);
    300 	if (rv) {
    301 		errno = rv;
    302 		return -1;
    303 	}
    304 	return xfer;
    305 }
    306 
    307 int
    308 ukfs_create(struct ukfs *ukfs, const char *filename, mode_t mode)
    309 {
    310 	int rv, fd, dummy;
    311 
    312 	precall(ukfs);
    313 	fd = rump_sys_open(filename, RUMP_O_WRONLY | RUMP_O_CREAT, mode, &rv);
    314 	rump_sys_close(fd, &dummy);
    315 
    316 	postcall(ukfs);
    317 	if (rv) {
    318 		errno = rv;
    319 		return -1;
    320 	}
    321 	return 0;
    322 }
    323 
    324 int
    325 ukfs_mknod(struct ukfs *ukfs, const char *path, mode_t mode, dev_t dev)
    326 {
    327 
    328 	STDCALL(ukfs, rump_sys_mknod(path, mode, dev, &rv));
    329 }
    330 
    331 int
    332 ukfs_mkfifo(struct ukfs *ukfs, const char *path, mode_t mode)
    333 {
    334 
    335 	STDCALL(ukfs, rump_sys_mkfifo(path, mode, &rv));
    336 }
    337 
    338 int
    339 ukfs_mkdir(struct ukfs *ukfs, const char *filename, mode_t mode)
    340 {
    341 
    342 	STDCALL(ukfs, rump_sys_mkdir(filename, mode, &rv));
    343 }
    344 
    345 int
    346 ukfs_remove(struct ukfs *ukfs, const char *filename)
    347 {
    348 
    349 	STDCALL(ukfs, rump_sys_unlink(filename, &rv));
    350 }
    351 
    352 int
    353 ukfs_rmdir(struct ukfs *ukfs, const char *filename)
    354 {
    355 
    356 	STDCALL(ukfs, rump_sys_rmdir(filename, &rv));
    357 }
    358 
    359 int
    360 ukfs_link(struct ukfs *ukfs, const char *filename, const char *f_create)
    361 {
    362 
    363 	STDCALL(ukfs, rump_sys_link(filename, f_create, &rv));
    364 }
    365 
    366 int
    367 ukfs_symlink(struct ukfs *ukfs, const char *filename, const char *linkname)
    368 {
    369 
    370 	STDCALL(ukfs, rump_sys_symlink(filename, linkname, &rv));
    371 }
    372 
    373 ssize_t
    374 ukfs_readlink(struct ukfs *ukfs, const char *filename,
    375 	char *linkbuf, size_t buflen)
    376 {
    377 	ssize_t rv;
    378 	int myerr = 0;
    379 
    380 	precall(ukfs);
    381 	rv = rump_sys_readlink(filename, linkbuf, buflen, &myerr);
    382 	postcall(ukfs);
    383 	if (myerr) {
    384 		errno = rv;
    385 		return -1;
    386 	}
    387 	return rv;
    388 }
    389 
    390 int
    391 ukfs_rename(struct ukfs *ukfs, const char *from, const char *to)
    392 {
    393 
    394 	STDCALL(ukfs, rump_sys_rename(from, to, &rv));
    395 }
    396 
    397 int
    398 ukfs_chdir(struct ukfs *ukfs, const char *path)
    399 {
    400 	struct vnode *newvp, *oldvp;
    401 	int rv;
    402 
    403 	precall(ukfs);
    404 	rump_sys_chdir(path, &rv);
    405 	if (rv)
    406 		goto out;
    407 
    408 	newvp = rump_cdir_get();
    409 	pthread_spin_lock(&ukfs->ukfs_spin);
    410 	oldvp = ukfs->ukfs_cdir;
    411 	ukfs->ukfs_cdir = newvp;
    412 	pthread_spin_unlock(&ukfs->ukfs_spin);
    413 	if (oldvp)
    414 		rump_vp_rele(oldvp);
    415 
    416  out:
    417 	postcall(ukfs);
    418 	if (rv) {
    419 		errno = rv;
    420 		return -1;
    421 	}
    422 	return 0;
    423 }
    424 
    425 int
    426 ukfs_stat(struct ukfs *ukfs, const char *filename, struct stat *file_stat)
    427 {
    428 
    429 	STDCALL(ukfs, rump_sys___stat30(filename, file_stat, &rv));
    430 }
    431 
    432 int
    433 ukfs_lstat(struct ukfs *ukfs, const char *filename, struct stat *file_stat)
    434 {
    435 
    436 	STDCALL(ukfs, rump_sys___lstat30(filename, file_stat, &rv));
    437 }
    438 
    439 int
    440 ukfs_chmod(struct ukfs *ukfs, const char *filename, mode_t mode)
    441 {
    442 
    443 	STDCALL(ukfs, rump_sys_chmod(filename, mode, &rv));
    444 }
    445 
    446 int
    447 ukfs_lchmod(struct ukfs *ukfs, const char *filename, mode_t mode)
    448 {
    449 
    450 	STDCALL(ukfs, rump_sys_lchmod(filename, mode, &rv));
    451 }
    452 
    453 int
    454 ukfs_chown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid)
    455 {
    456 
    457 	STDCALL(ukfs, rump_sys_chown(filename, uid, gid, &rv));
    458 }
    459 
    460 int
    461 ukfs_lchown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid)
    462 {
    463 
    464 	STDCALL(ukfs, rump_sys_lchown(filename, uid, gid, &rv));
    465 }
    466 
    467 int
    468 ukfs_chflags(struct ukfs *ukfs, const char *filename, u_long flags)
    469 {
    470 
    471 	STDCALL(ukfs, rump_sys_chflags(filename, flags, &rv));
    472 }
    473 
    474 int
    475 ukfs_lchflags(struct ukfs *ukfs, const char *filename, u_long flags)
    476 {
    477 
    478 	STDCALL(ukfs, rump_sys_lchflags(filename, flags, &rv));
    479 }
    480 
    481 int
    482 ukfs_utimes(struct ukfs *ukfs, const char *filename, const struct timeval *tptr)
    483 {
    484 
    485 	STDCALL(ukfs, rump_sys_utimes(filename, tptr, &rv));
    486 }
    487 
    488 int
    489 ukfs_lutimes(struct ukfs *ukfs, const char *filename,
    490 	      const struct timeval *tptr)
    491 {
    492 
    493 	STDCALL(ukfs, rump_sys_lutimes(filename, tptr, &rv));
    494 }
    495 
    496 int
    497 ukfs_util_builddirs(struct ukfs *ukfs, const char *pathname, mode_t mode)
    498 {
    499 	char *f1, *f2;
    500 	int rv;
    501 	mode_t mask;
    502 	bool end;
    503 
    504 	/*ukfs_umask((mask = ukfs_umask(0)));*/
    505 	umask((mask = umask(0)));
    506 
    507 	f1 = f2 = strdup(pathname);
    508 	if (f1 == NULL) {
    509 		errno = ENOMEM;
    510 		return -1;
    511 	}
    512 
    513 	end = false;
    514 	for (;;) {
    515 		/* find next component */
    516 		f2 += strspn(f2, "/");
    517 		f2 += strcspn(f2, "/");
    518 		if (*f2 == '\0')
    519 			end = true;
    520 		else
    521 			*f2 = '\0';
    522 
    523 		rv = ukfs_mkdir(ukfs, f1, mode & ~mask);
    524 		if (errno == EEXIST)
    525 			rv = 0;
    526 
    527 		if (rv == -1 || *f2 != '\0' || end)
    528 			break;
    529 
    530 		*f2 = '/';
    531 	}
    532 
    533 	free(f1);
    534 
    535 	return rv;
    536 }
    537