* Introduced ref-counting for the I/O contexts.

* The I/O context related vfs_*() functions have io_context* instead of void*
  parameters/return values, now.
* vfs_new_io_context(): Lock the parent I/O context before getting its table
  size. Otherwise the table size could change until we do.
* vfs_resize_fd_table(): Fixed use of MutexLocker. We created only a temporary
  object, not one with function scope.
* Renamed load_image_etc() to load_image_internal() and added a parameter for
  specifying the parent team of the one to create.
* Introduced a kernel private load_image_etc() with a few more arguments than
  load_image().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29375 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-03-02 00:26:22 +00:00
parent 9b9aa75aac
commit 5ecc4b3775
7 changed files with 109 additions and 55 deletions
+3 -2
View File
@@ -14,8 +14,6 @@ extern "C" {
#endif #endif
status_t team_init(struct kernel_args *args); status_t team_init(struct kernel_args *args);
team_id team_create_team(const char *path, const char *name, char **args,
int argc, char **envp, int envc, int priority);
status_t wait_for_team(team_id id, status_t *returnCode); status_t wait_for_team(team_id id, status_t *returnCode);
void team_remove_team(struct team *team); void team_remove_team(struct team *team);
void team_delete_team(struct team *team); void team_delete_team(struct team *team);
@@ -36,6 +34,9 @@ struct team *team_get_team_struct_locked(team_id id);
int32 team_max_teams(void); int32 team_max_teams(void);
int32 team_used_teams(void); int32 team_used_teams(void);
thread_id load_image_etc(int32 argCount, const char* const* args,
const char* const* env, int32 priority, team_id parentID, uint32 flags);
void team_set_job_control_state(struct team* team, job_control_state newState, void team_set_job_control_state(struct team* team, job_control_state newState,
int signal, bool threadsLocked); int signal, bool threadsLocked);
void team_set_controlling_tty(int32 index); void team_set_controlling_tty(int32 index);
+2 -1
View File
@@ -54,6 +54,7 @@ typedef enum job_control_state {
struct image; // defined in image.c struct image; // defined in image.c
struct io_context;
struct realtime_sem_context; // defined in realtime_sem.cpp struct realtime_sem_context; // defined in realtime_sem.cpp
struct select_info; struct select_info;
struct user_thread; // defined in libroot/user_thread.h struct user_thread; // defined in libroot/user_thread.h
@@ -172,7 +173,7 @@ struct team {
int num_threads; // number of threads in this team int num_threads; // number of threads in this team
int state; // current team state, see above int state; // current team state, see above
int32 flags; int32 flags;
void *io_context; struct io_context *io_context;
struct realtime_sem_context *realtime_sem_context; struct realtime_sem_context *realtime_sem_context;
struct xsi_sem_context *xsi_sem_context; struct xsi_sem_context *xsi_sem_context;
sem_id death_sem; // semaphore to wait on for dying threads sem_id death_sem; // semaphore to wait on for dying threads
+2
View File
@@ -21,6 +21,8 @@ extern "C" {
void inherit_parent_user_and_group(struct team* team, void inherit_parent_user_and_group(struct team* team,
struct team* parent); struct team* parent);
void inherit_parent_user_and_group_locked(struct team* team,
struct team* parent);
status_t update_set_id_user_and_group(struct team* team, const char* file); status_t update_set_id_user_and_group(struct team* team, const char* file);
// syscalls // syscalls
+5 -3
View File
@@ -46,6 +46,7 @@ typedef struct io_context {
struct vnode *root; struct vnode *root;
struct vnode *cwd; struct vnode *cwd;
mutex io_mutex; mutex io_mutex;
int32 ref_count;
uint32 table_size; uint32 table_size;
uint32 num_used_fds; uint32 num_used_fds;
struct file_descriptor **fds; struct file_descriptor **fds;
@@ -69,9 +70,10 @@ extern "C" {
status_t vfs_init(struct kernel_args *args); status_t vfs_init(struct kernel_args *args);
status_t vfs_bootstrap_file_systems(void); status_t vfs_bootstrap_file_systems(void);
void vfs_mount_boot_file_system(struct kernel_args *args); void vfs_mount_boot_file_system(struct kernel_args *args);
void vfs_exec_io_context(void *context); void vfs_exec_io_context(io_context *context);
void *vfs_new_io_context(void *parentContext); io_context *vfs_new_io_context(io_context *parentContext);
status_t vfs_free_io_context(void *context); void vfs_get_io_context(io_context *context);
void vfs_put_io_context(io_context *context);
struct rlimit; struct rlimit;
int vfs_getrlimit(int resource, struct rlimit * rlp); int vfs_getrlimit(int resource, struct rlimit * rlp);
+25 -15
View File
@@ -4595,9 +4595,8 @@ vfs_unlock_vnode_if_locked(struct file_descriptor* descriptor)
have the O_CLOEXEC flag set. have the O_CLOEXEC flag set.
*/ */
void void
vfs_exec_io_context(void* _context) vfs_exec_io_context(io_context* context)
{ {
struct io_context* context = (struct io_context*)_context;
uint32 i; uint32 i;
for (i = 0; i < context->table_size; i++) { for (i = 0; i < context->table_size; i++) {
@@ -4626,23 +4625,24 @@ vfs_exec_io_context(void* _context)
/*! Sets up a new io_control structure, and inherits the properties /*! Sets up a new io_control structure, and inherits the properties
of the parent io_control if it is given. of the parent io_control if it is given.
*/ */
void* io_context*
vfs_new_io_context(void* _parentContext) vfs_new_io_context(io_context* parentContext)
{ {
size_t tableSize; size_t tableSize;
struct io_context* context; struct io_context* context;
struct io_context* parentContext;
context = (io_context*)malloc(sizeof(struct io_context)); context = (io_context*)malloc(sizeof(struct io_context));
if (context == NULL) if (context == NULL)
return NULL; return NULL;
memset(context, 0, sizeof(struct io_context)); memset(context, 0, sizeof(struct io_context));
context->ref_count = 1;
parentContext = (struct io_context*)_parentContext; MutexLocker parentLocker;
if (parentContext) if (parentContext) {
parentLocker.SetTo(parentContext->io_mutex, false);
tableSize = parentContext->table_size; tableSize = parentContext->table_size;
else } else
tableSize = DEFAULT_FD_TABLE_SIZE; tableSize = DEFAULT_FD_TABLE_SIZE;
// allocate space for FDs and their close-on-exec flag // allocate space for FDs and their close-on-exec flag
@@ -4669,8 +4669,6 @@ vfs_new_io_context(void* _parentContext)
if (parentContext) { if (parentContext) {
size_t i; size_t i;
mutex_lock(&parentContext->io_mutex);
mutex_lock(&sIOContextRootLock); mutex_lock(&sIOContextRootLock);
context->root = parentContext->root; context->root = parentContext->root;
if (context->root) if (context->root)
@@ -4695,7 +4693,7 @@ vfs_new_io_context(void* _parentContext)
} }
} }
mutex_unlock(&parentContext->io_mutex); parentLocker.Unlock();
} else { } else {
context->root = sRoot; context->root = sRoot;
context->cwd = sRoot; context->cwd = sRoot;
@@ -4716,10 +4714,9 @@ vfs_new_io_context(void* _parentContext)
} }
status_t static status_t
vfs_free_io_context(void* _ioContext) vfs_free_io_context(io_context* context)
{ {
struct io_context* context = (struct io_context*)_ioContext;
uint32 i; uint32 i;
if (context->root) if (context->root)
@@ -4747,13 +4744,26 @@ vfs_free_io_context(void* _ioContext)
} }
void vfs_get_io_context(io_context *context)
{
atomic_add(&context->ref_count, 1);
}
void vfs_put_io_context(io_context *context)
{
if (atomic_add(&context->ref_count, -1) == 1)
vfs_free_io_context(context);
}
static status_t static status_t
vfs_resize_fd_table(struct io_context* context, const int newSize) vfs_resize_fd_table(struct io_context* context, const int newSize)
{ {
if (newSize <= 0 || newSize > MAX_FD_TABLE_SIZE) if (newSize <= 0 || newSize > MAX_FD_TABLE_SIZE)
return EINVAL; return EINVAL;
MutexLocker(context->io_mutex); MutexLocker _(context->io_mutex);
int oldSize = context->table_size; int oldSize = context->table_size;
int oldCloseOnExitBitmapSize = (oldSize + 7) / 8; int oldCloseOnExitBitmapSize = (oldSize + 7) / 8;
+63 -31
View File
@@ -1085,37 +1085,33 @@ team_create_thread_start(void *args)
} }
/*! The BeOS kernel exports a function with this name, but most probably with
different parameters; we should not make it public.
*/
static thread_id static thread_id
load_image_etc(char**& _flatArgs, size_t flatArgsSize, int32 argCount, load_image_internal(char**& _flatArgs, size_t flatArgsSize, int32 argCount,
int32 envCount, int32 priority, uint32 flags, port_id errorPort, int32 envCount, int32 priority, team_id parentID, uint32 flags,
uint32 errorToken) port_id errorPort, uint32 errorToken)
{ {
char** flatArgs = _flatArgs; char** flatArgs = _flatArgs;
struct team *team, *parent; struct team *team;
const char *threadName; const char *threadName;
thread_id thread; thread_id thread;
status_t status; status_t status;
cpu_status state; cpu_status state;
struct team_arg *teamArgs; struct team_arg *teamArgs;
struct team_loading_info loadingInfo; struct team_loading_info loadingInfo;
io_context* parentIOContext = NULL;
if (flatArgs == NULL || argCount == 0) if (flatArgs == NULL || argCount == 0)
return B_BAD_VALUE; return B_BAD_VALUE;
const char* path = flatArgs[0]; const char* path = flatArgs[0];
TRACE(("load_image_etc: name '%s', args = %p, argCount = %ld\n", TRACE(("load_image_internal: name '%s', args = %p, argCount = %ld\n",
path, flatArgs, argCount)); path, flatArgs, argCount));
team = create_team_struct(path, false); team = create_team_struct(path, false);
if (team == NULL) if (team == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
parent = thread_get_current_thread()->team;
if (flags & B_WAIT_TILL_LOADED) { if (flags & B_WAIT_TILL_LOADED) {
loadingInfo.thread = thread_get_current_thread(); loadingInfo.thread = thread_get_current_thread();
loadingInfo.result = B_ERROR; loadingInfo.result = B_ERROR;
@@ -1123,21 +1119,38 @@ load_image_etc(char**& _flatArgs, size_t flatArgsSize, int32 argCount,
team->loading_info = &loadingInfo; team->loading_info = &loadingInfo;
} }
// Inherit the parent's user/group, but also check the executable's InterruptsSpinLocker teamLocker(gTeamSpinlock);
// set-user/group-id permission
inherit_parent_user_and_group(team, parent);
update_set_id_user_and_group(team, path);
state = disable_interrupts(); // get the parent team
GRAB_TEAM_LOCK(); struct team* parent;
if (parentID == B_CURRENT_TEAM)
parent = thread_get_current_thread()->team;
else
parent = team_get_team_struct_locked(parentID);
if (parent == NULL) {
teamLocker.Unlock();
status = B_BAD_TEAM_ID;
goto err0;
}
// inherit the parent's user/group
inherit_parent_user_and_group_locked(team, parent);
hash_insert(sTeamHash, team); hash_insert(sTeamHash, team);
insert_team_into_parent(parent, team); insert_team_into_parent(parent, team);
insert_team_into_group(parent->group, team); insert_team_into_group(parent->group, team);
sUsedTeams++; sUsedTeams++;
RELEASE_TEAM_LOCK(); // get a reference to the parent's I/O context -- we need it to create ours
restore_interrupts(state); parentIOContext = parent->io_context;
vfs_get_io_context(parentIOContext);
teamLocker.Unlock();
// check the executable's set-user/group-id permission
update_set_id_user_and_group(team, path);
status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount, status = create_team_arg(&teamArgs, path, flatArgs, flatArgsSize, argCount,
envCount, errorPort, errorToken); envCount, errorPort, errorToken);
@@ -1149,12 +1162,16 @@ load_image_etc(char**& _flatArgs, size_t flatArgsSize, int32 argCount,
// args are owned by the team_arg structure now // args are owned by the team_arg structure now
// create a new io_context for this team // create a new io_context for this team
team->io_context = vfs_new_io_context(parent->io_context); team->io_context = vfs_new_io_context(parentIOContext);
if (!team->io_context) { if (!team->io_context) {
status = B_NO_MEMORY; status = B_NO_MEMORY;
goto err2; goto err2;
} }
// We don't need the parent's I/O context any longer.
vfs_put_io_context(parentIOContext);
parentIOContext = NULL;
// remove any fds that have the CLOEXEC flag set (emulating BeOS behaviour) // remove any fds that have the CLOEXEC flag set (emulating BeOS behaviour)
vfs_exec_io_context(team->io_context); vfs_exec_io_context(team->io_context);
@@ -1229,21 +1246,25 @@ err5:
err4: err4:
vm_put_address_space(team->address_space); vm_put_address_space(team->address_space);
err3: err3:
vfs_free_io_context(team->io_context); vfs_put_io_context(team->io_context);
err2: err2:
free_team_arg(teamArgs); free_team_arg(teamArgs);
err1: err1:
if (parentIOContext != NULL)
vfs_put_io_context(parentIOContext);
// remove the team structure from the team hash table and delete the team structure // remove the team structure from the team hash table and delete the team structure
state = disable_interrupts(); state = disable_interrupts();
GRAB_TEAM_LOCK(); GRAB_TEAM_LOCK();
remove_team_from_group(team); remove_team_from_group(team);
remove_team_from_parent(parent, team); remove_team_from_parent(team->parent, team);
hash_remove(sTeamHash, team); hash_remove(sTeamHash, team);
RELEASE_TEAM_LOCK(); RELEASE_TEAM_LOCK();
restore_interrupts(state); restore_interrupts(state);
err0:
delete_team_struct(team); delete_team_struct(team);
return status; return status;
@@ -1431,7 +1452,8 @@ fork_team(void)
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
// create a new team // create a new team
// ToDo: this is very similar to team_create_team() - maybe we can do something about it :) // TODO: this is very similar to load_image_internal() - maybe we can do
// something about it :)
team = create_team_struct(parentTeam->name, false); team = create_team_struct(parentTeam->name, false);
if (team == NULL) if (team == NULL)
@@ -1562,7 +1584,7 @@ err4:
err3: err3:
delete_realtime_sem_context(team->realtime_sem_context); delete_realtime_sem_context(team->realtime_sem_context);
err25: err25:
vfs_free_io_context(team->io_context); vfs_put_io_context(team->io_context);
err2: err2:
free(forkArgs); free(forkArgs);
err1: err1:
@@ -2354,7 +2376,7 @@ team_delete_team(struct team *team)
// free team resources // free team resources
vfs_free_io_context(team->io_context); vfs_put_io_context(team->io_context);
delete_realtime_sem_context(team->realtime_sem_context); delete_realtime_sem_context(team->realtime_sem_context);
xsi_sem_undo(team); xsi_sem_undo(team);
delete_owned_ports(teamID); delete_owned_ports(teamID);
@@ -2638,6 +2660,15 @@ team_free_user_thread(struct thread* thread)
thread_id thread_id
load_image(int32 argCount, const char **args, const char **env) load_image(int32 argCount, const char **args, const char **env)
{
return load_image_etc(argCount, args, env, B_NORMAL_PRIORITY,
B_CURRENT_TEAM, B_WAIT_TILL_LOADED);
}
thread_id
load_image_etc(int32 argCount, const char* const* args,
const char* const* env, int32 priority, team_id parentID, uint32 flags)
{ {
// we need to flatten the args and environment // we need to flatten the args and environment
@@ -2685,11 +2716,11 @@ load_image(int32 argCount, const char **args, const char **env)
*slot++ = NULL; *slot++ = NULL;
thread_id thread = load_image_etc(flatArgs, size, argCount, envCount, thread_id thread = load_image_internal(flatArgs, size, argCount, envCount,
B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED, -1, 0); B_NORMAL_PRIORITY, parentID, B_WAIT_TILL_LOADED, -1, 0);
free(flatArgs); free(flatArgs);
// load_image_etc() unset our variable if it took over ownership // load_image_internal() unset our variable if it took over ownership
return thread; return thread;
} }
@@ -3277,7 +3308,7 @@ _user_load_image(const char* const* userFlatArgs, size_t flatArgsSize,
int32 argCount, int32 envCount, int32 priority, uint32 flags, int32 argCount, int32 envCount, int32 priority, uint32 flags,
port_id errorPort, uint32 errorToken) port_id errorPort, uint32 errorToken)
{ {
TRACE(("_user_load_image_etc: argc = %ld\n", argCount)); TRACE(("_user_load_image: argc = %ld\n", argCount));
if (argCount < 1) if (argCount < 1)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -3289,11 +3320,12 @@ _user_load_image(const char* const* userFlatArgs, size_t flatArgsSize,
if (error != B_OK) if (error != B_OK)
return error; return error;
thread_id thread = load_image_etc(flatArgs, _ALIGN(flatArgsSize), argCount, thread_id thread = load_image_internal(flatArgs, _ALIGN(flatArgsSize),
envCount, priority, flags, errorPort, errorToken); argCount, envCount, priority, B_CURRENT_TEAM, flags, errorPort,
errorToken);
free(flatArgs); free(flatArgs);
// load_image_etc() unset our variable if it took over ownership // load_image_internal() unset our variable if it took over ownership
return thread; return thread;
} }
+9 -3
View File
@@ -243,10 +243,8 @@ common_setgroups(int groupCount, const gid_t* groupList, bool kernel)
void void
inherit_parent_user_and_group(struct team* team, struct team* parent) inherit_parent_user_and_group_locked(struct team* team, struct team* parent)
{ {
InterruptsSpinLocker _(gTeamSpinlock);
team->saved_set_uid = parent->saved_set_uid; team->saved_set_uid = parent->saved_set_uid;
team->real_uid = parent->real_uid; team->real_uid = parent->real_uid;
team->effective_uid = parent->effective_uid; team->effective_uid = parent->effective_uid;
@@ -260,6 +258,14 @@ inherit_parent_user_and_group(struct team* team, struct team* parent)
} }
void
inherit_parent_user_and_group(struct team* team, struct team* parent)
{
InterruptsSpinLocker _(gTeamSpinlock);
inherit_parent_user_and_group_locked(team, parent);
}
status_t status_t
update_set_id_user_and_group(struct team* team, const char* file) update_set_id_user_and_group(struct team* team, const char* file)
{ {