Implement compat32 shims for ksem syscalls.

Reviewed by:	jhb
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2010-03-19 11:08:43 +00:00
parent 75d633cbf6
commit 0e5d5bc279
2 changed files with 138 additions and 67 deletions

View File

@ -697,16 +697,19 @@
398 AUE_FHSTATFS NOPROTO { int fhstatfs(const struct fhandle *u_fhp, \
struct statfs *buf); }
399 AUE_NULL UNIMPL nosys
; XXX implement these?
400 AUE_NULL UNIMPL ksem_close
401 AUE_NULL UNIMPL ksem_post
402 AUE_NULL UNIMPL ksem_wait
403 AUE_NULL UNIMPL ksem_trywait
404 AUE_NULL UNIMPL ksem_init
405 AUE_NULL UNIMPL ksem_open
406 AUE_NULL UNIMPL ksem_unlink
407 AUE_NULL UNIMPL ksem_getvalue
408 AUE_NULL UNIMPL ksem_destroy
400 AUE_NULL NOSTD|NOPROTO { int ksem_close(semid_t id); }
401 AUE_NULL NOSTD|NOPROTO { int ksem_post(semid_t id); }
402 AUE_NULL NOSTD|NOPROTO { int ksem_wait(semid_t id); }
403 AUE_NULL NOSTD|NOPROTO { int ksem_trywait(semid_t id); }
404 AUE_NULL NOSTD { int freebsd32_ksem_init(semid_t *idp, \
unsigned int value); }
405 AUE_NULL NOSTD { int freebsd32_ksem_open(semid_t *idp, \
const char *name, int oflag, \
mode_t mode, unsigned int value); }
406 AUE_NULL NOSTD|NOPROTO { int ksem_unlink(const char *name); }
407 AUE_NULL NOSTD|NOPROTO { int ksem_getvalue(semid_t id, \
int *val); }
408 AUE_NULL NOSTD|NOPROTO { int ksem_destroy(semid_t id); }
409 AUE_NULL UNIMPL __mac_get_pid
410 AUE_NULL UNIMPL __mac_get_link
411 AUE_NULL UNIMPL __mac_set_link
@ -765,7 +768,8 @@
const char *path, int attrnamespace, \
void *data, size_t nbytes); }
440 AUE_NULL UNIMPL kse_switchin
441 AUE_NULL UNIMPL ksem_timedwait
441 AUE_NULL NOSTD { int freebsd32_ksem_timedwait(semid_t id, \
const struct timespec32 *abstime); }
442 AUE_NULL STD { int freebsd32_thr_suspend( \
const struct timespec32 *timeout); }
443 AUE_NULL NOPROTO { int thr_wake(long id); }

View File

@ -34,6 +34,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_compat.h"
#include "opt_posix.h"
#include <sys/param.h>
@ -112,7 +113,7 @@ static struct ksem *ksem_alloc(struct ucred *ucred, mode_t mode,
unsigned int value);
static int ksem_create(struct thread *td, const char *path,
semid_t *semidp, mode_t mode, unsigned int value,
int flags);
int flags, int compat32);
static void ksem_drop(struct ksem *ks);
static int ksem_get(struct thread *td, semid_t id, struct file **fpp);
static struct ksem *ksem_hold(struct ksem *ks);
@ -374,16 +375,44 @@ ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred)
return (ENOENT);
}
static int
ksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd,
int compat32)
{
semid_t semid;
#ifdef COMPAT_FREEBSD32
int32_t semid32;
#endif
void *ptr;
size_t ptrs;
#ifdef COMPAT_FREEBSD32
if (compat32) {
semid32 = fd;
ptr = &semid32;
ptrs = sizeof(semid32);
} else {
#endif
semid = fd;
ptr = &semid;
ptrs = sizeof(semid);
compat32 = 0; /* silence gcc */
#ifdef COMPAT_FREEBSD32
}
#endif
return (copyout(ptr, semidp, ptrs));
}
/* Other helper routines. */
static int
ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
unsigned int value, int flags)
unsigned int value, int flags, int compat32)
{
struct filedesc *fdp;
struct ksem *ks;
struct file *fp;
char *path;
semid_t semid;
Fnv32_t fnv;
int error, fd;
@ -404,8 +433,7 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
* premature, but it is a lot easier to handle errors as opposed
* to later when we've possibly created a new semaphore, etc.
*/
semid = fd;
error = copyout(&semid, semidp, sizeof(semid));
error = ksem_create_copyout_semid(td, semidp, fd, compat32);
if (error) {
fdclose(fdp, fp, fd, td);
fdrop(fp, td);
@ -530,7 +558,7 @@ ksem_init(struct thread *td, struct ksem_init_args *uap)
{
return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
0));
0, 0));
}
#ifndef _SYS_SYSPROTO_H_
@ -551,7 +579,7 @@ ksem_open(struct thread *td, struct ksem_open_args *uap)
if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
return (EINVAL);
return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
uap->oflag));
uap->oflag, 0));
}
#ifndef _SYS_SYSPROTO_H_
@ -832,38 +860,85 @@ ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
return (error);
}
#define SYSCALL_DATA(syscallname) \
static int syscallname##_syscall = SYS_##syscallname; \
static int syscallname##_registered; \
static struct sysent syscallname##_old_sysent; \
MAKE_SYSENT(syscallname);
static struct syscall_helper_data ksem_syscalls[] = {
SYSCALL_INIT_HELPER(ksem_init),
SYSCALL_INIT_HELPER(ksem_open),
SYSCALL_INIT_HELPER(ksem_unlink),
SYSCALL_INIT_HELPER(ksem_close),
SYSCALL_INIT_HELPER(ksem_post),
SYSCALL_INIT_HELPER(ksem_wait),
SYSCALL_INIT_HELPER(ksem_timedwait),
SYSCALL_INIT_HELPER(ksem_trywait),
SYSCALL_INIT_HELPER(ksem_getvalue),
SYSCALL_INIT_HELPER(ksem_destroy),
SYSCALL_INIT_LAST
};
#define SYSCALL_REGISTER(syscallname) do { \
error = syscall_register(& syscallname##_syscall, \
& syscallname##_sysent, & syscallname##_old_sysent); \
if (error) \
return (error); \
syscallname##_registered = 1; \
} while(0)
#ifdef COMPAT_FREEBSD32
#include <compat/freebsd32/freebsd32.h>
#include <compat/freebsd32/freebsd32_proto.h>
#include <compat/freebsd32/freebsd32_signal.h>
#include <compat/freebsd32/freebsd32_syscall.h>
#include <compat/freebsd32/freebsd32_util.h>
#define SYSCALL_DEREGISTER(syscallname) do { \
if (syscallname##_registered) { \
syscallname##_registered = 0; \
syscall_deregister(& syscallname##_syscall, \
& syscallname##_old_sysent); \
} \
} while(0)
int
freebsd32_ksem_init(struct thread *td, struct freebsd32_ksem_init_args *uap)
{
SYSCALL_DATA(ksem_init);
SYSCALL_DATA(ksem_open);
SYSCALL_DATA(ksem_unlink);
SYSCALL_DATA(ksem_close);
SYSCALL_DATA(ksem_post);
SYSCALL_DATA(ksem_wait);
SYSCALL_DATA(ksem_timedwait);
SYSCALL_DATA(ksem_trywait);
SYSCALL_DATA(ksem_getvalue);
SYSCALL_DATA(ksem_destroy);
return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
0, 1));
}
int
freebsd32_ksem_open(struct thread *td, struct freebsd32_ksem_open_args *uap)
{
if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
return (EINVAL);
return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
uap->oflag, 1));
}
int
freebsd32_ksem_timedwait(struct thread *td,
struct freebsd32_ksem_timedwait_args *uap)
{
struct timespec32 abstime32;
struct timespec *ts, abstime;
int error;
/*
* We allow a null timespec (wait forever).
*/
if (uap->abstime == NULL)
ts = NULL;
else {
error = copyin(uap->abstime, &abstime32, sizeof(abstime32));
if (error != 0)
return (error);
CP(abstime32, abstime, tv_sec);
CP(abstime32, abstime, tv_nsec);
if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
return (EINVAL);
ts = &abstime;
}
return (kern_sem_wait(td, uap->id, 0, ts));
}
static struct syscall_helper_data ksem32_syscalls[] = {
SYSCALL32_INIT_HELPER(freebsd32_ksem_init),
SYSCALL32_INIT_HELPER(freebsd32_ksem_open),
SYSCALL32_INIT_HELPER(ksem_unlink),
SYSCALL32_INIT_HELPER(ksem_close),
SYSCALL32_INIT_HELPER(ksem_post),
SYSCALL32_INIT_HELPER(ksem_wait),
SYSCALL32_INIT_HELPER(freebsd32_ksem_timedwait),
SYSCALL32_INIT_HELPER(ksem_trywait),
SYSCALL32_INIT_HELPER(ksem_getvalue),
SYSCALL32_INIT_HELPER(ksem_destroy),
SYSCALL_INIT_LAST
};
#endif
static int
ksem_module_init(void)
@ -877,16 +952,14 @@ ksem_module_init(void)
p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
SYSCALL_REGISTER(ksem_init);
SYSCALL_REGISTER(ksem_open);
SYSCALL_REGISTER(ksem_unlink);
SYSCALL_REGISTER(ksem_close);
SYSCALL_REGISTER(ksem_post);
SYSCALL_REGISTER(ksem_wait);
SYSCALL_REGISTER(ksem_timedwait);
SYSCALL_REGISTER(ksem_trywait);
SYSCALL_REGISTER(ksem_getvalue);
SYSCALL_REGISTER(ksem_destroy);
error = syscall_helper_register(ksem_syscalls);
if (error)
return (error);
#ifdef COMPAT_FREEBSD32
error = syscall32_helper_register(ksem32_syscalls);
if (error)
return (error);
#endif
return (0);
}
@ -894,16 +967,10 @@ static void
ksem_module_destroy(void)
{
SYSCALL_DEREGISTER(ksem_init);
SYSCALL_DEREGISTER(ksem_open);
SYSCALL_DEREGISTER(ksem_unlink);
SYSCALL_DEREGISTER(ksem_close);
SYSCALL_DEREGISTER(ksem_post);
SYSCALL_DEREGISTER(ksem_wait);
SYSCALL_DEREGISTER(ksem_timedwait);
SYSCALL_DEREGISTER(ksem_trywait);
SYSCALL_DEREGISTER(ksem_getvalue);
SYSCALL_DEREGISTER(ksem_destroy);
#ifdef COMPAT_FREEBSD32
syscall32_helper_unregister(ksem32_syscalls);
#endif
syscall_helper_unregister(ksem_syscalls);
hashdestroy(ksem_dictionary, M_KSEM, ksem_hash);
sx_destroy(&ksem_dict_lock);