diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-08-12 17:27:30 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-26 21:08:53 -0400 |
commit | dcfadfa4ec5a12404a99ad6426871a6b03a62b37 (patch) | |
tree | a8c2898366470e795dac369040b905985c0bb9fc | |
parent | f33ff9927f42045116d738ee47ff7bc59f739bd7 (diff) |
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>
-rw-r--r-- | drivers/staging/android/binder.c | 59 | ||||
-rw-r--r-- | fs/file.c | 12 | ||||
-rw-r--r-- | include/linux/fdtable.h | 3 |
3 files changed, 16 insertions, 58 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index b9a534c46aac..4946d282a35c 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c | |||
@@ -362,71 +362,22 @@ struct binder_transaction { | |||
362 | static void | 362 | static void |
363 | binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); | 363 | binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); |
364 | 364 | ||
365 | /* | ||
366 | * copied from get_unused_fd_flags | ||
367 | */ | ||
368 | int task_get_unused_fd_flags(struct binder_proc *proc, int flags) | 365 | int task_get_unused_fd_flags(struct binder_proc *proc, int flags) |
369 | { | 366 | { |
370 | struct files_struct *files = proc->files; | 367 | struct files_struct *files = proc->files; |
371 | int fd, error; | ||
372 | struct fdtable *fdt; | ||
373 | unsigned long rlim_cur; | 368 | unsigned long rlim_cur; |
374 | unsigned long irqs; | 369 | unsigned long irqs; |
375 | 370 | ||
376 | if (files == NULL) | 371 | if (files == NULL) |
377 | return -ESRCH; | 372 | return -ESRCH; |
378 | 373 | ||
379 | error = -EMFILE; | 374 | if (!lock_task_sighand(proc->tsk, &irqs)) |
380 | spin_lock(&files->file_lock); | 375 | return -EMFILE; |
381 | 376 | ||
382 | repeat: | 377 | rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); |
383 | fdt = files_fdtable(files); | 378 | unlock_task_sighand(proc->tsk, &irqs); |
384 | fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, files->next_fd); | ||
385 | |||
386 | /* | ||
387 | * N.B. For clone tasks sharing a files structure, this test | ||
388 | * will limit the total number of files that can be opened. | ||
389 | */ | ||
390 | rlim_cur = 0; | ||
391 | if (lock_task_sighand(proc->tsk, &irqs)) { | ||
392 | rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur; | ||
393 | unlock_task_sighand(proc->tsk, &irqs); | ||
394 | } | ||
395 | if (fd >= rlim_cur) | ||
396 | goto out; | ||
397 | |||
398 | /* Do we need to expand the fd array or fd set? */ | ||
399 | error = expand_files(files, fd); | ||
400 | if (error < 0) | ||
401 | goto out; | ||
402 | |||
403 | if (error) { | ||
404 | /* | ||
405 | * If we needed to expand the fs array we | ||
406 | * might have blocked - try again. | ||
407 | */ | ||
408 | error = -EMFILE; | ||
409 | goto repeat; | ||
410 | } | ||
411 | |||
412 | __set_open_fd(fd, fdt); | ||
413 | if (flags & O_CLOEXEC) | ||
414 | __set_close_on_exec(fd, fdt); | ||
415 | else | ||
416 | __clear_close_on_exec(fd, fdt); | ||
417 | files->next_fd = fd + 1; | ||
418 | #if 1 | ||
419 | /* Sanity check */ | ||
420 | if (fdt->fd[fd] != NULL) { | ||
421 | pr_warn("get_unused_fd: slot %d not NULL!\n", fd); | ||
422 | fdt->fd[fd] = NULL; | ||
423 | } | ||
424 | #endif | ||
425 | error = fd; | ||
426 | 379 | ||
427 | out: | 380 | return __alloc_fd(files, 0, rlim_cur, flags); |
428 | spin_unlock(&files->file_lock); | ||
429 | return error; | ||
430 | } | 381 | } |
431 | 382 | ||
432 | /* | 383 | /* |
@@ -420,11 +420,10 @@ struct files_struct init_files = { | |||
420 | /* | 420 | /* |
421 | * allocate a file descriptor, mark it busy. | 421 | * allocate a file descriptor, mark it busy. |
422 | */ | 422 | */ |
423 | int alloc_fd(unsigned start, unsigned flags) | 423 | int __alloc_fd(struct files_struct *files, |
424 | unsigned start, unsigned end, unsigned flags) | ||
424 | { | 425 | { |
425 | struct files_struct *files = current->files; | ||
426 | unsigned int fd; | 426 | unsigned int fd; |
427 | unsigned end = rlimit(RLIMIT_NOFILE); | ||
428 | int error; | 427 | int error; |
429 | struct fdtable *fdt; | 428 | struct fdtable *fdt; |
430 | 429 | ||
@@ -479,8 +478,13 @@ out: | |||
479 | return error; | 478 | return error; |
480 | } | 479 | } |
481 | 480 | ||
481 | int alloc_fd(unsigned start, unsigned flags) | ||
482 | { | ||
483 | return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags); | ||
484 | } | ||
485 | |||
482 | int get_unused_fd_flags(unsigned flags) | 486 | int get_unused_fd_flags(unsigned flags) |
483 | { | 487 | { |
484 | return alloc_fd(0, flags); | 488 | return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); |
485 | } | 489 | } |
486 | EXPORT_SYMBOL(get_unused_fd_flags); | 490 | EXPORT_SYMBOL(get_unused_fd_flags); |
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 158a41eed314..b84ca064f727 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h | |||
@@ -125,6 +125,9 @@ void reset_files_struct(struct files_struct *); | |||
125 | int unshare_files(struct files_struct **); | 125 | int unshare_files(struct files_struct **); |
126 | struct files_struct *dup_fd(struct files_struct *, int *); | 126 | struct files_struct *dup_fd(struct files_struct *, int *); |
127 | 127 | ||
128 | extern int __alloc_fd(struct files_struct *files, | ||
129 | unsigned start, unsigned end, unsigned flags); | ||
130 | |||
128 | extern struct kmem_cache *files_cachep; | 131 | extern struct kmem_cache *files_cachep; |
129 | 132 | ||
130 | #endif /* __LINUX_FDTABLE_H */ | 133 | #endif /* __LINUX_FDTABLE_H */ |