mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
vfs: advisory locking + flock syscall
This commit is contained in:
@@ -93,6 +93,7 @@ extern syscall_sigpending
|
|||||||
extern syscall_killthread
|
extern syscall_killthread
|
||||||
extern syscall_shutdown
|
extern syscall_shutdown
|
||||||
extern syscall_nice
|
extern syscall_nice
|
||||||
|
extern syscall_flock
|
||||||
syscalltab:
|
syscalltab:
|
||||||
dq syscall_print
|
dq syscall_print
|
||||||
dq syscall_mmap
|
dq syscall_mmap
|
||||||
@@ -188,7 +189,8 @@ dq syscall_sigpending
|
|||||||
dq syscall_killthread
|
dq syscall_killthread
|
||||||
dq syscall_shutdown
|
dq syscall_shutdown
|
||||||
dq syscall_nice
|
dq syscall_nice
|
||||||
syscallcount equ 94
|
dq syscall_flock
|
||||||
|
syscallcount equ 95
|
||||||
section .text
|
section .text
|
||||||
global arch_syscall_entry
|
global arch_syscall_entry
|
||||||
; on entry:
|
; on entry:
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#ifdef SYSCALL_LOGGING
|
#ifdef SYSCALL_LOGGING
|
||||||
|
|
||||||
#define SYSCALL_COUNT 94
|
#define SYSCALL_COUNT 95
|
||||||
#define LOGSTR(x) arch_e9_puts(x)
|
#define LOGSTR(x) arch_e9_puts(x)
|
||||||
|
|
||||||
static char *name[] = {
|
static char *name[] = {
|
||||||
@@ -102,7 +102,8 @@ static char *name[] = {
|
|||||||
"sigpending",
|
"sigpending",
|
||||||
"killthread",
|
"killthread",
|
||||||
"shutdown",
|
"shutdown",
|
||||||
"nice"
|
"nice",
|
||||||
|
"flock"
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *args[] = {
|
static char *args[] = {
|
||||||
@@ -199,7 +200,8 @@ static char *args[] = {
|
|||||||
"sigset %p", // sigpending
|
"sigset %p", // sigpending
|
||||||
"pid %d tid %d signal %d", // killthread
|
"pid %d tid %d signal %d", // killthread
|
||||||
"how %d", // shutdown
|
"how %d", // shutdown
|
||||||
"off %d" // nice
|
"off %d", // nice
|
||||||
|
"fd %d op %d" // flock
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -443,6 +443,14 @@ static int devfs_unlock(vnode_t *vnode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int devfs_advlock(vnode_t *node, int op, advlock_t *advlock) {
|
||||||
|
devnode_t *devnode = (devnode_t *)node;
|
||||||
|
if (devnode->master)
|
||||||
|
devnode = devnode->master;
|
||||||
|
|
||||||
|
return vfs_advlock((vnode_t *)devnode, op, advlock);
|
||||||
|
}
|
||||||
|
|
||||||
static int devfs_enodev() {
|
static int devfs_enodev() {
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
@@ -479,6 +487,7 @@ static vops_t vnops = {
|
|||||||
.putpage = devfs_putpage,
|
.putpage = devfs_putpage,
|
||||||
.getpage = devfs_getpage,
|
.getpage = devfs_getpage,
|
||||||
.sync = devfs_sync,
|
.sync = devfs_sync,
|
||||||
|
.advlock = devfs_advlock,
|
||||||
.lock = devfs_lock,
|
.lock = devfs_lock,
|
||||||
.unlock = devfs_unlock
|
.unlock = devfs_unlock
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1823,6 +1823,10 @@ static int ext2_unlock(vnode_t *vnode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ext2_advlock(vnode_t *node, int op, advlock_t *advlock) {
|
||||||
|
return vfs_advlock(node, op, advlock);
|
||||||
|
}
|
||||||
|
|
||||||
static int ext2_inactive(vnode_t *vnode) {
|
static int ext2_inactive(vnode_t *vnode) {
|
||||||
ext2node_t *node = (ext2node_t *)vnode;
|
ext2node_t *node = (ext2node_t *)vnode;
|
||||||
ext2fs_t *fs = (ext2fs_t *)vnode->vfs;
|
ext2fs_t *fs = (ext2fs_t *)vnode->vfs;
|
||||||
@@ -2010,6 +2014,7 @@ static vops_t vnops = {
|
|||||||
.getpage = ext2_getpage,
|
.getpage = ext2_getpage,
|
||||||
.putpage = ext2_putpage,
|
.putpage = ext2_putpage,
|
||||||
.sync = ext2_sync,
|
.sync = ext2_sync,
|
||||||
|
.advlock = ext2_advlock,
|
||||||
.lock = ext2_lock,
|
.lock = ext2_lock,
|
||||||
.unlock = ext2_unlock
|
.unlock = ext2_unlock
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ static bool ctor(scache_t *cache, void *obj) {
|
|||||||
file->offset = 0;
|
file->offset = 0;
|
||||||
file->flags = 0;
|
file->flags = 0;
|
||||||
file->mode = 0;
|
file->mode = 0;
|
||||||
|
file->advlock = NULL;
|
||||||
file->refcount = 1;
|
file->refcount = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -39,12 +40,18 @@ static void cleanfile(file_t *file) {
|
|||||||
VOP_RELEASE(file->vnode);
|
VOP_RELEASE(file->vnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
file->vnode = NULL;
|
|
||||||
file->refcount = 1;
|
file->refcount = 1;
|
||||||
file->offset = 0;
|
file->offset = 0;
|
||||||
file->flags = 0;
|
file->flags = 0;
|
||||||
file->mode = 0;
|
file->mode = 0;
|
||||||
MUTEX_INIT(&file->mutex);
|
MUTEX_INIT(&file->mutex);
|
||||||
|
if (file->advlock) {
|
||||||
|
// try unlocking it if applicable
|
||||||
|
VOP_ADVLOCK(file->vnode, ADVLOCK_UNLOCK, file->advlock);
|
||||||
|
ADVLOCK_UNREF(file->advlock);
|
||||||
|
file->advlock = NULL;
|
||||||
|
}
|
||||||
|
file->vnode = NULL;
|
||||||
slab_free(filecache, file);
|
slab_free(filecache, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -364,6 +364,10 @@ static int pipefs_unlock(vnode_t *vnode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pipefs_advlock(vnode_t *node, int op, advlock_t *advlock) {
|
||||||
|
return vfs_advlock(node, op, advlock);
|
||||||
|
}
|
||||||
|
|
||||||
static int pipefs_enodev() {
|
static int pipefs_enodev() {
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
@@ -392,6 +396,7 @@ static vops_t vnops = {
|
|||||||
.putpage = pipefs_enodev,
|
.putpage = pipefs_enodev,
|
||||||
.getpage = pipefs_enodev,
|
.getpage = pipefs_enodev,
|
||||||
.sync = pipefs_enodev,
|
.sync = pipefs_enodev,
|
||||||
|
.advlock = pipefs_advlock,
|
||||||
.lock = pipefs_lock,
|
.lock = pipefs_lock,
|
||||||
.unlock = pipefs_unlock
|
.unlock = pipefs_unlock
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -229,6 +229,10 @@ static int sockfs_unlock(vnode_t *) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sockfs_advlock(vnode_t *node, int op, advlock_t *advlock) {
|
||||||
|
return vfs_advlock(node, op, advlock);
|
||||||
|
}
|
||||||
|
|
||||||
static int sockfs_enodev() {
|
static int sockfs_enodev() {
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
@@ -258,6 +262,7 @@ static vops_t vnops = {
|
|||||||
.putpage = sockfs_enodev,
|
.putpage = sockfs_enodev,
|
||||||
.getpage = sockfs_enodev,
|
.getpage = sockfs_enodev,
|
||||||
.sync = sockfs_enodev,
|
.sync = sockfs_enodev,
|
||||||
|
.advlock = sockfs_advlock,
|
||||||
.lock = sockfs_lock,
|
.lock = sockfs_lock,
|
||||||
.unlock = sockfs_unlock
|
.unlock = sockfs_unlock
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -503,6 +503,10 @@ static int tmpfs_sync(vnode_t *node) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tmpfs_advlock(vnode_t *node, int op, advlock_t *advlock) {
|
||||||
|
return vfs_advlock(node, op, advlock);
|
||||||
|
}
|
||||||
|
|
||||||
static int tmpfs_lock(vnode_t *node) {
|
static int tmpfs_lock(vnode_t *node) {
|
||||||
MUTEX_ACQUIRE(&node->lock);
|
MUTEX_ACQUIRE(&node->lock);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -542,6 +546,7 @@ static vops_t vnops = {
|
|||||||
.getpage = tmpfs_getpage,
|
.getpage = tmpfs_getpage,
|
||||||
.putpage = tmpfs_putpage,
|
.putpage = tmpfs_putpage,
|
||||||
.sync = tmpfs_sync,
|
.sync = tmpfs_sync,
|
||||||
|
.advlock = tmpfs_advlock,
|
||||||
.lock = tmpfs_lock,
|
.lock = tmpfs_lock,
|
||||||
.unlock = tmpfs_unlock
|
.unlock = tmpfs_unlock
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <kernel/pipefs.h>
|
#include <kernel/pipefs.h>
|
||||||
#include <kernel/auth.h>
|
#include <kernel/auth.h>
|
||||||
#include <kernel/init.h>
|
#include <kernel/init.h>
|
||||||
|
#include <kernel/slab.h>
|
||||||
|
|
||||||
#define PATHNAME_MAX 512
|
#define PATHNAME_MAX 512
|
||||||
#define MAXLINKDEPTH 64
|
#define MAXLINKDEPTH 64
|
||||||
@@ -21,6 +22,7 @@ vnode_t *vfsroot;
|
|||||||
|
|
||||||
static mutex_t listlock;
|
static mutex_t listlock;
|
||||||
static vfs_t *vfslist;
|
static vfs_t *vfslist;
|
||||||
|
static scache_t *advlock_cache;
|
||||||
|
|
||||||
static cred_t *getcred() {
|
static cred_t *getcred() {
|
||||||
if (current_thread() == NULL || current_thread()->proc == NULL)
|
if (current_thread() == NULL || current_thread()->proc == NULL)
|
||||||
@@ -50,6 +52,15 @@ static vops_t vnops = {
|
|||||||
.unlock = noop
|
.unlock = noop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool advlock_ctor(scache_t *cache, void *_obj) {
|
||||||
|
advlock_t *obj = _obj;
|
||||||
|
obj->type = ADVLOCK_UNLOCK;
|
||||||
|
obj->shared_count = 0;
|
||||||
|
obj->refcount = 1;
|
||||||
|
EVENT_INITHEADER(&obj->unlock_event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void vfs_init() {
|
void vfs_init() {
|
||||||
__assert(hashtable_init(&fstable, 20) == 0);
|
__assert(hashtable_init(&fstable, 20) == 0);
|
||||||
vfsroot = alloc(sizeof(vnode_t));
|
vfsroot = alloc(sizeof(vnode_t));
|
||||||
@@ -58,10 +69,21 @@ void vfs_init() {
|
|||||||
vfsroot->type = V_TYPE_DIR;
|
vfsroot->type = V_TYPE_DIR;
|
||||||
vfsroot->refcount = 1;
|
vfsroot->refcount = 1;
|
||||||
vfsroot->ops = &vnops;
|
vfsroot->ops = &vnops;
|
||||||
|
advlock_cache = slab_newcache(sizeof(advlock_t), 0, advlock_ctor, NULL);
|
||||||
|
__assert(advlock_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_ROUTINE_DEFINE(vfs, INIT_ROUTINE_FLAGS_NONE, vfs_init, bsp_early);
|
INIT_ROUTINE_DEFINE(vfs, INIT_ROUTINE_FLAGS_NONE, vfs_init, bsp_early);
|
||||||
|
|
||||||
|
advlock_t *advlock_allocate(void) {
|
||||||
|
return slab_allocate(advlock_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
void advlock_free(advlock_t *advlock) {
|
||||||
|
advlock->refcount = 1;
|
||||||
|
slab_free(advlock_cache, advlock);
|
||||||
|
}
|
||||||
|
|
||||||
int vfs_register(vfsops_t *ops, char *name) {
|
int vfs_register(vfsops_t *ops, char *name) {
|
||||||
return hashtable_set(&fstable, ops, name, strlen(name), true);
|
return hashtable_set(&fstable, ops, name, strlen(name), true);
|
||||||
}
|
}
|
||||||
@@ -166,6 +188,140 @@ int vfs_close(vnode_t *node, int flags) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void adv_unlock(vnode_t *vnode, int op, advlock_t *lock) {
|
||||||
|
MUTEX_ACQUIRE(&vnode->adv_mutex);
|
||||||
|
|
||||||
|
switch (lock->type) {
|
||||||
|
// is this lock not attached anywhere?
|
||||||
|
case ADVLOCK_UNLOCK:
|
||||||
|
goto leave;
|
||||||
|
case ADVLOCK_EXCLUSIVE:
|
||||||
|
__assert(vnode->advlock == lock);
|
||||||
|
|
||||||
|
EVENT_SIGNAL(&lock->unlock_event);
|
||||||
|
ADVLOCK_UNREF(lock);
|
||||||
|
vnode->advlock = NULL;
|
||||||
|
|
||||||
|
lock->type = ADVLOCK_UNLOCK;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ADVLOCK_SHARED:
|
||||||
|
__assert(vnode->advlock && vnode->advlock->type == ADVLOCK_SHARED);
|
||||||
|
lock->type = ADVLOCK_UNLOCK;
|
||||||
|
|
||||||
|
if (--vnode->advlock->shared_count == 0) {
|
||||||
|
// we do not change the type as this will be destroyed
|
||||||
|
// (shared locks allocate an extra advlock)
|
||||||
|
EVENT_SIGNAL(&vnode->advlock->unlock_event);
|
||||||
|
ADVLOCK_UNREF(vnode->advlock);
|
||||||
|
vnode->advlock = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
MUTEX_RELEASE(&vnode->adv_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adv_lock(vnode_t *vnode, int op, advlock_t *lock, bool non_blocking) {
|
||||||
|
retry:
|
||||||
|
MUTEX_ACQUIRE(&vnode->adv_mutex);
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
// do we have to convert the lock?
|
||||||
|
if ((lock->type == ADVLOCK_EXCLUSIVE && op == ADVLOCK_SHARED) ||
|
||||||
|
(lock->type == ADVLOCK_SHARED && op == ADVLOCK_EXCLUSIVE)) {
|
||||||
|
error = EDEADLK;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
// have we already taken it?
|
||||||
|
if (lock->type == op) {
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((op == ADVLOCK_EXCLUSIVE && vnode->advlock && vnode->advlock != lock) ||
|
||||||
|
(op == ADVLOCK_SHARED && vnode->advlock && vnode->advlock->type == ADVLOCK_EXCLUSIVE)
|
||||||
|
) {
|
||||||
|
// can't take lock, sleep
|
||||||
|
if (non_blocking) {
|
||||||
|
error = EWOULDBLOCK;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
advlock_t *sleeping_on = vnode->advlock;
|
||||||
|
ADVLOCK_REF(sleeping_on);
|
||||||
|
|
||||||
|
eventlistener_t listener;
|
||||||
|
EVENT_INITLISTENER(&listener);
|
||||||
|
EVENT_ATTACH(&listener, &sleeping_on->unlock_event);
|
||||||
|
|
||||||
|
MUTEX_RELEASE(&vnode->adv_mutex);
|
||||||
|
|
||||||
|
error = EVENT_WAIT(&listener, 0);
|
||||||
|
EVENT_DETACHALL(&listener);
|
||||||
|
|
||||||
|
ADVLOCK_UNREF(sleeping_on);
|
||||||
|
|
||||||
|
// interrupted by a signal?
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can take the lock!
|
||||||
|
lock->type = op;
|
||||||
|
|
||||||
|
if (vnode->advlock == NULL) {
|
||||||
|
// unlocked advlock
|
||||||
|
if (op == ADVLOCK_SHARED) {
|
||||||
|
// shared locks allocate a dummy one
|
||||||
|
vnode->advlock = advlock_allocate();
|
||||||
|
if (vnode->advlock == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// exclusive lock
|
||||||
|
vnode->advlock = lock;
|
||||||
|
ADVLOCK_REF(vnode->advlock);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// shared lock on shared advlock
|
||||||
|
++vnode->advlock->shared_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
MUTEX_RELEASE(&vnode->adv_mutex);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected to be called from inside filesystem specific code
|
||||||
|
// adv_mutex is expected to be unlocked
|
||||||
|
// returns 0 if successful lock, EWOULDBLOCK if unsucessful and non-blocking
|
||||||
|
// a ADVLOCK_UNLOCK operation decreases the shared count or releases an exclusive lock if applicable, waking all waiters in case of a successful unlock
|
||||||
|
// a ADVLOCK_SHARED operation takes an unlocked lock or increments the shared count of a shared one
|
||||||
|
// a ADVLOCK_EXCLUSIVE operation either places the lock or sleeps waiting to do so
|
||||||
|
int vfs_advlock(vnode_t *node, int op, advlock_t *lock) {
|
||||||
|
int error = 0;
|
||||||
|
int non_blocking = op & ADVLOCK_NON_BLOCKING;
|
||||||
|
op &= ~ADVLOCK_NON_BLOCKING;
|
||||||
|
|
||||||
|
if (op == ADVLOCK_UNLOCK) {
|
||||||
|
adv_unlock(node, op, lock);
|
||||||
|
} else {
|
||||||
|
retry:
|
||||||
|
error = adv_lock(node, op, lock, non_blocking);
|
||||||
|
if (error == EDEADLK) {
|
||||||
|
// EDEADLK is a way of adv_lock signaling that the lock should be converted, and thus must be unlocked and then relocked non-atomically
|
||||||
|
adv_unlock(node, ADVLOCK_UNLOCK, lock);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
// if node is not NULL, then a reference is kept and the newnode is returned in node
|
// if node is not NULL, then a reference is kept and the newnode is returned in node
|
||||||
// ref is expected to be unlocked.
|
// ref is expected to be unlocked.
|
||||||
// the new node is returned locked
|
// the new node is returned locked
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <kernel/vfs.h>
|
#include <kernel/vfs.h>
|
||||||
#include <mutex.h>
|
#include <mutex.h>
|
||||||
#include <kernel/scheduler.h>
|
#include <kernel/scheduler.h>
|
||||||
|
#include <kernel/event.h>
|
||||||
|
|
||||||
typedef struct file_t {
|
typedef struct file_t {
|
||||||
vnode_t *vnode;
|
vnode_t *vnode;
|
||||||
@@ -12,6 +13,7 @@ typedef struct file_t {
|
|||||||
mode_t mode;
|
mode_t mode;
|
||||||
uintmax_t offset;
|
uintmax_t offset;
|
||||||
int flags;
|
int flags;
|
||||||
|
advlock_t *advlock;
|
||||||
} file_t;
|
} file_t;
|
||||||
|
|
||||||
typedef struct fd_t {
|
typedef struct fd_t {
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ typedef struct polldata {
|
|||||||
} polldata_t;
|
} polldata_t;
|
||||||
|
|
||||||
#define POLL_INITHEADER(x) \
|
#define POLL_INITHEADER(x) \
|
||||||
SPINLOCK_INIT((x)->lock);
|
SPINLOCK_INIT((x)->lock); \
|
||||||
|
(x)->data = NULL;
|
||||||
|
|
||||||
int poll_initdesc(polldesc_t *, size_t size);
|
int poll_initdesc(polldesc_t *, size_t size);
|
||||||
void poll_add(pollheader_t *, polldata_t *, int events);
|
void poll_add(pollheader_t *, polldata_t *, int events);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <kernel/cred.h>
|
#include <kernel/cred.h>
|
||||||
|
#include <kernel/event.h>
|
||||||
|
|
||||||
#define V_ATTR_MODE 1
|
#define V_ATTR_MODE 1
|
||||||
#define V_ATTR_UID 2
|
#define V_ATTR_UID 2
|
||||||
@@ -71,6 +72,21 @@ typedef struct vfs_t {
|
|||||||
int flags;
|
int flags;
|
||||||
} vfs_t;
|
} vfs_t;
|
||||||
|
|
||||||
|
#define ADVLOCK_SHARED 1
|
||||||
|
#define ADVLOCK_EXCLUSIVE 2
|
||||||
|
#define ADVLOCK_NON_BLOCKING 4
|
||||||
|
#define ADVLOCK_UNLOCK 8
|
||||||
|
|
||||||
|
typedef struct advlock_t {
|
||||||
|
int type;
|
||||||
|
int refcount;
|
||||||
|
int shared_count;
|
||||||
|
eventheader_t unlock_event;
|
||||||
|
} advlock_t;
|
||||||
|
|
||||||
|
#define ADVLOCK_REF(x) __atomic_fetch_add(&(x)->refcount, 1, __ATOMIC_SEQ_CST);
|
||||||
|
#define ADVLOCK_UNREF(x) if (__atomic_sub_fetch(&(x)->refcount, 1, __ATOMIC_SEQ_CST) == 0) advlock_free(x);
|
||||||
|
|
||||||
#define V_FLAGS_ROOT 1
|
#define V_FLAGS_ROOT 1
|
||||||
|
|
||||||
#define V_TYPE_REGULAR 0
|
#define V_TYPE_REGULAR 0
|
||||||
@@ -105,6 +121,9 @@ typedef struct vnode_t {
|
|||||||
|
|
||||||
mutex_t pages_mutex;
|
mutex_t pages_mutex;
|
||||||
struct page_t *pages;
|
struct page_t *pages;
|
||||||
|
|
||||||
|
mutex_t adv_mutex;
|
||||||
|
advlock_t *advlock;
|
||||||
} vnode_t;
|
} vnode_t;
|
||||||
|
|
||||||
typedef struct vfsops_t {
|
typedef struct vfsops_t {
|
||||||
@@ -143,6 +162,7 @@ typedef struct vops_t {
|
|||||||
int (*getpage)(vnode_t *node, uintmax_t offset, struct page_t *page);
|
int (*getpage)(vnode_t *node, uintmax_t offset, struct page_t *page);
|
||||||
int (*putpage)(vnode_t *node, uintmax_t offset, struct page_t *page);
|
int (*putpage)(vnode_t *node, uintmax_t offset, struct page_t *page);
|
||||||
int (*sync)(vnode_t *node);
|
int (*sync)(vnode_t *node);
|
||||||
|
int (*advlock)(vnode_t *node, int op, advlock_t *advlock);
|
||||||
int (*lock)(vnode_t *node);
|
int (*lock)(vnode_t *node);
|
||||||
int (*unlock)(vnode_t *node);
|
int (*unlock)(vnode_t *node);
|
||||||
} vops_t;
|
} vops_t;
|
||||||
@@ -164,6 +184,8 @@ typedef struct vops_t {
|
|||||||
MUTEX_INIT(&(vn)->lock); \
|
MUTEX_INIT(&(vn)->lock); \
|
||||||
MUTEX_INIT(&(vn)->size_lock); \
|
MUTEX_INIT(&(vn)->size_lock); \
|
||||||
MUTEX_INIT(&(vn)->pages_mutex); \
|
MUTEX_INIT(&(vn)->pages_mutex); \
|
||||||
|
MUTEX_INIT(&(vn)->adv_mutex); \
|
||||||
|
(vn)->advlock = NULL; \
|
||||||
(vn)->refcount = 1; \
|
(vn)->refcount = 1; \
|
||||||
(vn)->flags = f; \
|
(vn)->flags = f; \
|
||||||
(vn)->type = t; \
|
(vn)->type = t; \
|
||||||
@@ -201,6 +223,7 @@ typedef struct vops_t {
|
|||||||
#define VOP_GETPAGE(v, o, p) (v)->ops->getpage(v, o, p)
|
#define VOP_GETPAGE(v, o, p) (v)->ops->getpage(v, o, p)
|
||||||
#define VOP_PUTPAGE(v, o, p) (v)->ops->putpage(v, o, p)
|
#define VOP_PUTPAGE(v, o, p) (v)->ops->putpage(v, o, p)
|
||||||
#define VOP_SYNC(v) (v)->ops->sync(v)
|
#define VOP_SYNC(v) (v)->ops->sync(v)
|
||||||
|
#define VOP_ADVLOCK(v, o, a) (v)->ops->advlock(v, o, a)
|
||||||
#define VOP_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST)
|
#define VOP_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST)
|
||||||
#define VOP_RELEASE(v) {\
|
#define VOP_RELEASE(v) {\
|
||||||
if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\
|
if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\
|
||||||
@@ -211,6 +234,9 @@ typedef struct vops_t {
|
|||||||
|
|
||||||
extern vnode_t *vfsroot;
|
extern vnode_t *vfsroot;
|
||||||
|
|
||||||
|
advlock_t *advlock_allocate(void);
|
||||||
|
void advlock_free(advlock_t *advlock);
|
||||||
|
|
||||||
void vfs_init();
|
void vfs_init();
|
||||||
int vfs_mount(vnode_t *backing, vnode_t *pathref, char *path, char *name, void *data);
|
int vfs_mount(vnode_t *backing, vnode_t *pathref, char *path, char *name, void *data);
|
||||||
int vfs_register(vfsops_t *vfsops, char *name);
|
int vfs_register(vfsops_t *vfsops, char *name);
|
||||||
@@ -226,6 +252,7 @@ int vfs_link(vnode_t *destref, char *destpath, vnode_t *linkref, char *linkpath,
|
|||||||
int vfs_rename(vnode_t *srcref, char *srcpath, vnode_t *dstref, char *dstpath, int flags);
|
int vfs_rename(vnode_t *srcref, char *srcpath, vnode_t *dstref, char *dstpath, int flags);
|
||||||
int vfs_unlink(vnode_t *ref, char *path);
|
int vfs_unlink(vnode_t *ref, char *path);
|
||||||
int vfs_pollstub(vnode_t *node, struct polldata *, int events);
|
int vfs_pollstub(vnode_t *node, struct polldata *, int events);
|
||||||
|
int vfs_advlock(vnode_t *node, int op, advlock_t *lock);
|
||||||
void vfs_inactive(vnode_t *node);
|
void vfs_inactive(vnode_t *node);
|
||||||
|
|
||||||
#define VFS_LOOKUP_PARENT 0x20000000
|
#define VFS_LOOKUP_PARENT 0x20000000
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#include <kernel/syscalls.h>
|
||||||
|
#include <kernel/file.h>
|
||||||
|
#include <kernel/vfs.h>
|
||||||
|
|
||||||
|
syscallret_t syscall_flock(context_t *, int fd, int op_flag) {
|
||||||
|
syscallret_t ret = {
|
||||||
|
.ret = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
int op = op_flag &= ~ADVLOCK_NON_BLOCKING;
|
||||||
|
switch (op) {
|
||||||
|
case ADVLOCK_UNLOCK:
|
||||||
|
case ADVLOCK_SHARED:
|
||||||
|
case ADVLOCK_EXCLUSIVE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret.errno = EINVAL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_t *file = fd_get(fd);
|
||||||
|
if (file == NULL) {
|
||||||
|
ret.errno = EBADF;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUTEX_ACQUIRE(&file->mutex);
|
||||||
|
|
||||||
|
advlock_t *advlock = file->advlock;
|
||||||
|
if (advlock)
|
||||||
|
ADVLOCK_REF(advlock);
|
||||||
|
|
||||||
|
if (op == ADVLOCK_UNLOCK && advlock == NULL) {
|
||||||
|
// trying to unlock a lock which does not exist, just leave
|
||||||
|
ret.errno = 0;
|
||||||
|
ret.ret = 0;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op != ADVLOCK_UNLOCK && advlock == NULL) {
|
||||||
|
// locking and the lock does not exist yet, allocate it
|
||||||
|
advlock = advlock_allocate();
|
||||||
|
if (advlock == NULL) {
|
||||||
|
ret.errno = ENOMEM;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->advlock = advlock;
|
||||||
|
advlock->refcount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
vnode_t *vn = file->vnode;
|
||||||
|
VOP_HOLD(vn);
|
||||||
|
|
||||||
|
// release the file so that it can be closed etc in case we block
|
||||||
|
MUTEX_RELEASE(&file->mutex);
|
||||||
|
fd_release(file);
|
||||||
|
|
||||||
|
ret.errno = VOP_ADVLOCK(vn, op_flag, advlock);
|
||||||
|
ret.ret = ret.errno ? -1 : 0;
|
||||||
|
|
||||||
|
VOP_RELEASE(vn);
|
||||||
|
ADVLOCK_UNREF(advlock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (advlock)
|
||||||
|
ADVLOCK_UNREF(advlock);
|
||||||
|
MUTEX_RELEASE(&file->mutex);
|
||||||
|
fd_release(file);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -84,7 +84,7 @@ index d5ba7b2..a86353f 100644
|
|||||||
long error = syscall(SYSCALL_ARCHCTL, &ret, func, (uint64_t)arg);
|
long error = syscall(SYSCALL_ARCHCTL, &ret, func, (uint64_t)arg);
|
||||||
if(error)
|
if(error)
|
||||||
diff --git mlibc-clean/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp
|
diff --git mlibc-clean/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp
|
||||||
index bb85dba..a541845 100644
|
index bb85dba..5e9e21a 100644
|
||||||
--- mlibc-clean/sysdeps/astral/generic/generic.cpp
|
--- mlibc-clean/sysdeps/astral/generic/generic.cpp
|
||||||
+++ mlibc-workdir/sysdeps/astral/generic/generic.cpp
|
+++ mlibc-workdir/sysdeps/astral/generic/generic.cpp
|
||||||
@@ -31,6 +31,12 @@ namespace mlibc {
|
@@ -31,6 +31,12 @@ namespace mlibc {
|
||||||
@@ -100,10 +100,15 @@ index bb85dba..a541845 100644
|
|||||||
int sys_getsockopt(int fd, int layer, int number,
|
int sys_getsockopt(int fd, int layer, int number,
|
||||||
void *__restrict buffer, socklen_t *__restrict size) {
|
void *__restrict buffer, socklen_t *__restrict size) {
|
||||||
(void)size;
|
(void)size;
|
||||||
@@ -40,6 +46,18 @@ namespace mlibc {
|
@@ -40,6 +46,23 @@ namespace mlibc {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ int sys_flock(int fd, int options) {
|
||||||
|
+ long r;
|
||||||
|
+ return syscall(SYSCALL_FLOCK, &r, fd, options);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ int sys_nice(int nice, int *ret) {
|
+ int sys_nice(int nice, int *ret) {
|
||||||
+ long r = -1;
|
+ long r = -1;
|
||||||
+ long e = syscall(SYSCALL_NICE, &r, nice);
|
+ long e = syscall(SYSCALL_NICE, &r, nice);
|
||||||
@@ -119,7 +124,7 @@ index bb85dba..a541845 100644
|
|||||||
int sys_tgkill(int pid, int tid, int sig) {
|
int sys_tgkill(int pid, int tid, int sig) {
|
||||||
long ret;
|
long ret;
|
||||||
return syscall(SYSCALL_KILLTHREAD, &ret, pid, tid, sig);
|
return syscall(SYSCALL_KILLTHREAD, &ret, pid, tid, sig);
|
||||||
@@ -161,7 +179,18 @@ namespace mlibc {
|
@@ -161,7 +184,18 @@ namespace mlibc {
|
||||||
*bytes_written = writec;
|
*bytes_written = writec;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -139,7 +144,7 @@ index bb85dba..a541845 100644
|
|||||||
#ifndef MLIBC_BUILDING_RTLD
|
#ifndef MLIBC_BUILDING_RTLD
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -376,6 +405,12 @@ namespace mlibc {
|
@@ -376,6 +410,12 @@ namespace mlibc {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +157,7 @@ index bb85dba..a541845 100644
|
|||||||
#ifndef MLIBC_BUILDING_RTLD
|
#ifndef MLIBC_BUILDING_RTLD
|
||||||
|
|
||||||
[[noreturn]] void sys_thread_exit() {
|
[[noreturn]] void sys_thread_exit() {
|
||||||
@@ -771,7 +806,7 @@ namespace mlibc {
|
@@ -771,7 +811,7 @@ namespace mlibc {
|
||||||
|
|
||||||
int sys_tcb_set(void *pointer) {
|
int sys_tcb_set(void *pointer) {
|
||||||
long r;
|
long r;
|
||||||
@@ -179,15 +184,16 @@ index d738e02..7e4f2a1 100644
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
diff --git mlibc-clean/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h
|
diff --git mlibc-clean/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h
|
||||||
index 5f42d62..09a5d5f 100644
|
index 5f42d62..6fbb253 100644
|
||||||
--- mlibc-clean/sysdeps/astral/include/astral/syscall.h
|
--- mlibc-clean/sysdeps/astral/include/astral/syscall.h
|
||||||
+++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h
|
+++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h
|
||||||
@@ -96,6 +96,8 @@
|
@@ -96,6 +96,9 @@
|
||||||
#define SYSCALL_SIGTIMEDWAIT 89
|
#define SYSCALL_SIGTIMEDWAIT 89
|
||||||
#define SYSCALL_SIGPENDING 90
|
#define SYSCALL_SIGPENDING 90
|
||||||
#define SYSCALL_KILLTHREAD 91
|
#define SYSCALL_KILLTHREAD 91
|
||||||
+#define SYSCALL_SHUTDOWN 92
|
+#define SYSCALL_SHUTDOWN 92
|
||||||
+#define SYSCALL_NICE 93
|
+#define SYSCALL_NICE 93
|
||||||
|
+#define SYSCALL_FLOCK 94
|
||||||
|
|
||||||
#ifndef __MLIBC_ABI_ONLY
|
#ifndef __MLIBC_ABI_ONLY
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user