new helper: __alloc_fd()
Essentially, alloc_fd() in a files_struct we own a reference to. Most of the time wanting to use it is a sign of lousy API design (such as android/binder). It's *not* a general-purpose interface; better that than open-coding its guts, but again, playing with other process' descriptor table is a sign of bad design. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
f33ff9927f
commit
dcfadfa4ec
3 changed files with 16 additions and 58 deletions
|
@ -362,71 +362,22 @@ struct binder_transaction {
|
||||||
static void
|
static void
|
||||||
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
|
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
|
||||||
|
|
||||||
/*
|
|
||||||
* copied from get_unused_fd_flags
|
|
||||||
*/
|
|
||||||
int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
|
int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
|
||||||
{
|
{
|
||||||
struct files_struct *files = proc->files;
|
struct files_struct *files = proc->files;
|
||||||
int fd, error;
|
|
||||||
struct fdtable *fdt;
|
|
||||||
unsigned long rlim_cur;
|
unsigned long rlim_cur;
|
||||||
unsigned long irqs;
|
unsigned long irqs;
|
||||||
|
|
||||||
if (files == NULL)
|
if (files == NULL)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
error = -EMFILE;
|
if (!lock_task_sighand(proc->tsk, &irqs))
|
||||||
spin_lock(&files->file_lock);
|
return -EMFILE;
|
||||||
|
|
||||||
repeat:
|
rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);
|
||||||
fdt = files_fdtable(files);
|
|
||||||
fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, files->next_fd);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* N.B. For clone tasks sharing a files structure, this test
|
|
||||||
* will limit the total number of files that can be opened.
|
|
||||||
*/
|
|
||||||
rlim_cur = 0;
|
|
||||||
if (lock_task_sighand(proc->tsk, &irqs)) {
|
|
||||||
rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur;
|
|
||||||
unlock_task_sighand(proc->tsk, &irqs);
|
unlock_task_sighand(proc->tsk, &irqs);
|
||||||
}
|
|
||||||
if (fd >= rlim_cur)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Do we need to expand the fd array or fd set? */
|
return __alloc_fd(files, 0, rlim_cur, flags);
|
||||||
error = expand_files(files, fd);
|
|
||||||
if (error < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
/*
|
|
||||||
* If we needed to expand the fs array we
|
|
||||||
* might have blocked - try again.
|
|
||||||
*/
|
|
||||||
error = -EMFILE;
|
|
||||||
goto repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
__set_open_fd(fd, fdt);
|
|
||||||
if (flags & O_CLOEXEC)
|
|
||||||
__set_close_on_exec(fd, fdt);
|
|
||||||
else
|
|
||||||
__clear_close_on_exec(fd, fdt);
|
|
||||||
files->next_fd = fd + 1;
|
|
||||||
#if 1
|
|
||||||
/* Sanity check */
|
|
||||||
if (fdt->fd[fd] != NULL) {
|
|
||||||
pr_warn("get_unused_fd: slot %d not NULL!\n", fd);
|
|
||||||
fdt->fd[fd] = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
error = fd;
|
|
||||||
|
|
||||||
out:
|
|
||||||
spin_unlock(&files->file_lock);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
12
fs/file.c
12
fs/file.c
|
@ -420,11 +420,10 @@ struct files_struct init_files = {
|
||||||
/*
|
/*
|
||||||
* allocate a file descriptor, mark it busy.
|
* allocate a file descriptor, mark it busy.
|
||||||
*/
|
*/
|
||||||
int alloc_fd(unsigned start, unsigned flags)
|
int __alloc_fd(struct files_struct *files,
|
||||||
|
unsigned start, unsigned end, unsigned flags)
|
||||||
{
|
{
|
||||||
struct files_struct *files = current->files;
|
|
||||||
unsigned int fd;
|
unsigned int fd;
|
||||||
unsigned end = rlimit(RLIMIT_NOFILE);
|
|
||||||
int error;
|
int error;
|
||||||
struct fdtable *fdt;
|
struct fdtable *fdt;
|
||||||
|
|
||||||
|
@ -479,8 +478,13 @@ out:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int alloc_fd(unsigned start, unsigned flags)
|
||||||
|
{
|
||||||
|
return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
|
||||||
|
}
|
||||||
|
|
||||||
int get_unused_fd_flags(unsigned flags)
|
int get_unused_fd_flags(unsigned flags)
|
||||||
{
|
{
|
||||||
return alloc_fd(0, flags);
|
return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_unused_fd_flags);
|
EXPORT_SYMBOL(get_unused_fd_flags);
|
||||||
|
|
|
@ -125,6 +125,9 @@ void reset_files_struct(struct files_struct *);
|
||||||
int unshare_files(struct files_struct **);
|
int unshare_files(struct files_struct **);
|
||||||
struct files_struct *dup_fd(struct files_struct *, int *);
|
struct files_struct *dup_fd(struct files_struct *, int *);
|
||||||
|
|
||||||
|
extern int __alloc_fd(struct files_struct *files,
|
||||||
|
unsigned start, unsigned end, unsigned flags);
|
||||||
|
|
||||||
extern struct kmem_cache *files_cachep;
|
extern struct kmem_cache *files_cachep;
|
||||||
|
|
||||||
#endif /* __LINUX_FDTABLE_H */
|
#endif /* __LINUX_FDTABLE_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue