aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-12 17:27:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:08:53 -0400
commitdcfadfa4ec5a12404a99ad6426871a6b03a62b37 (patch)
treea8c2898366470e795dac369040b905985c0bb9fc
parentf33ff9927f42045116d738ee47ff7bc59f739bd7 (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.c59
-rw-r--r--fs/file.c12
-rw-r--r--include/linux/fdtable.h3
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 {
362static void 362static void
363binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); 363binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer);
364 364
365/*
366 * copied from get_unused_fd_flags
367 */
368int task_get_unused_fd_flags(struct binder_proc *proc, int flags) 365int 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
382repeat: 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
427out: 380 return __alloc_fd(files, 0, rlim_cur, flags);
428 spin_unlock(&files->file_lock);
429 return error;
430} 381}
431 382
432/* 383/*
diff --git a/fs/file.c b/fs/file.c
index 08922af4a62c..a3a0705f8f51 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -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 */
423int alloc_fd(unsigned start, unsigned flags) 423int __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
481int alloc_fd(unsigned start, unsigned flags)
482{
483 return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
484}
485
482int get_unused_fd_flags(unsigned flags) 486int 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}
486EXPORT_SYMBOL(get_unused_fd_flags); 490EXPORT_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 *);
125int unshare_files(struct files_struct **); 125int unshare_files(struct files_struct **);
126struct files_struct *dup_fd(struct files_struct *, int *); 126struct files_struct *dup_fd(struct files_struct *, int *);
127 127
128extern int __alloc_fd(struct files_struct *files,
129 unsigned start, unsigned end, unsigned flags);
130
128extern struct kmem_cache *files_cachep; 131extern struct kmem_cache *files_cachep;
129 132
130#endif /* __LINUX_FDTABLE_H */ 133#endif /* __LINUX_FDTABLE_H */