* use advisory file locks to avoid multiple mounts on the same device
(multiple rdonly mounts are still allowed) * shuffle some assignments to avoid leaking resources in error branches
This commit is contained in:
parent
220377354c
commit
f455f7ee91
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: ukfs.c,v 1.10 2008/10/07 23:16:59 pooka Exp $ */
|
/* $NetBSD: ukfs.c,v 1.11 2008/11/07 00:18:33 pooka Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007, 2008 Antti Kantee. All Rights Reserved.
|
* Copyright (c) 2007, 2008 Antti Kantee. All Rights Reserved.
|
||||||
|
@ -50,6 +50,7 @@
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -71,6 +72,7 @@ struct ukfs {
|
||||||
pthread_spinlock_t ukfs_spin;
|
pthread_spinlock_t ukfs_spin;
|
||||||
pid_t ukfs_nextpid;
|
pid_t ukfs_nextpid;
|
||||||
struct vnode *ukfs_cdir;
|
struct vnode *ukfs_cdir;
|
||||||
|
int ukfs_devfd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mount *
|
struct mount *
|
||||||
|
@ -156,8 +158,8 @@ ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
|
||||||
{
|
{
|
||||||
struct ukfs *fs = NULL;
|
struct ukfs *fs = NULL;
|
||||||
struct vfsops *vfsops;
|
struct vfsops *vfsops;
|
||||||
struct mount *mp;
|
struct mount *mp = NULL;
|
||||||
int rv = 0;
|
int rv = 0, devfd = -1, rdonly;
|
||||||
|
|
||||||
vfsops = rump_vfs_getopsbyname(vfsname);
|
vfsops = rump_vfs_getopsbyname(vfsname);
|
||||||
if (vfsops == NULL) {
|
if (vfsops == NULL) {
|
||||||
|
@ -165,7 +167,31 @@ ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp = rump_mnt_init(vfsops, mntflags);
|
/*
|
||||||
|
* Try open and lock the device. if we can't open it, assume
|
||||||
|
* it's a file system which doesn't use a real device and let
|
||||||
|
* it slide. The mount will fail anyway if the fs requires a
|
||||||
|
* device.
|
||||||
|
*
|
||||||
|
* XXX: strictly speaking this is not 100% correct, as virtual
|
||||||
|
* file systems can use a device path which does exist and can
|
||||||
|
* be opened. E.g. tmpfs should be mountable multiple times
|
||||||
|
* with "device" path "/swap", but now isn't. But I think the
|
||||||
|
* chances are so low that it's currently acceptable to let
|
||||||
|
* this one slip.
|
||||||
|
*/
|
||||||
|
rdonly = mntflags & MNT_RDONLY;
|
||||||
|
devfd = open(devpath, rdonly ? O_RDONLY : O_RDWR);
|
||||||
|
if (devfd != -1) {
|
||||||
|
if (flock(devfd, LOCK_NB | (rdonly ? LOCK_SH:LOCK_EX)) == -1) {
|
||||||
|
warnx("ukfs_mount: cannot get %s lock on device",
|
||||||
|
rdonly ? "shared" : "exclusive");
|
||||||
|
close(devfd);
|
||||||
|
devfd = -1;
|
||||||
|
rv = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fs = malloc(sizeof(struct ukfs));
|
fs = malloc(sizeof(struct ukfs));
|
||||||
if (fs == NULL) {
|
if (fs == NULL) {
|
||||||
|
@ -173,7 +199,7 @@ ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
memset(fs, 0, sizeof(struct ukfs));
|
memset(fs, 0, sizeof(struct ukfs));
|
||||||
pthread_spin_init(&fs->ukfs_spin, PTHREAD_PROCESS_SHARED);
|
mp = rump_mnt_init(vfsops, mntflags);
|
||||||
|
|
||||||
rump_fakeblk_register(devpath);
|
rump_fakeblk_register(devpath);
|
||||||
rv = rump_mnt_mount(mp, mountpath, arg, &alen);
|
rv = rump_mnt_mount(mp, mountpath, arg, &alen);
|
||||||
|
@ -181,19 +207,29 @@ ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath,
|
||||||
if (rv) {
|
if (rv) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
fs->ukfs_mp = mp;
|
rv = rump_vfs_root(mp, &fs->ukfs_rvp, 0);
|
||||||
|
if (rv) {
|
||||||
rv = rump_vfs_root(fs->ukfs_mp, &fs->ukfs_rvp, 0);
|
goto out;
|
||||||
|
}
|
||||||
fs->ukfs_cdir = ukfs_getrvp(fs);
|
fs->ukfs_cdir = ukfs_getrvp(fs);
|
||||||
|
|
||||||
|
fs->ukfs_mp = mp;
|
||||||
|
pthread_spin_init(&fs->ukfs_spin, PTHREAD_PROCESS_SHARED);
|
||||||
|
fs->ukfs_devfd = devfd;
|
||||||
|
assert(rv == 0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (rv) {
|
if (rv) {
|
||||||
if (fs && fs->ukfs_mp)
|
if (mp)
|
||||||
rump_mnt_destroy(fs->ukfs_mp);
|
rump_mnt_destroy(mp);
|
||||||
if (fs)
|
if (fs)
|
||||||
free(fs);
|
free(fs);
|
||||||
errno = rv;
|
errno = rv;
|
||||||
fs = NULL;
|
fs = NULL;
|
||||||
|
if (devfd != -1) {
|
||||||
|
flock(devfd, LOCK_UN);
|
||||||
|
close(devfd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs;
|
return fs;
|
||||||
|
@ -220,6 +256,8 @@ ukfs_release(struct ukfs *fs, int flags)
|
||||||
rump_mnt_destroy(fs->ukfs_mp);
|
rump_mnt_destroy(fs->ukfs_mp);
|
||||||
|
|
||||||
pthread_spin_destroy(&fs->ukfs_spin);
|
pthread_spin_destroy(&fs->ukfs_spin);
|
||||||
|
if (fs->ukfs_devfd != -1)
|
||||||
|
flock(fs->ukfs_devfd, LOCK_UN);
|
||||||
free(fs);
|
free(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue