diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 23:25:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 23:25:04 -0400 |
commit | aab174f0df5d72d31caccf281af5f614fa254578 (patch) | |
tree | 2a172c5009c4ac8755e858593154c258ce7709a0 /kernel | |
parent | ca41cc96b2813221b05af57d0355157924de5a07 (diff) | |
parent | 2bd2c1941f141ad780135ccc1cd08ca71a24f10a (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs update from Al Viro:
- big one - consolidation of descriptor-related logics; almost all of
that is moved to fs/file.c
(BTW, I'm seriously tempted to rename the result to fd.c. As it is,
we have a situation when file_table.c is about handling of struct
file and file.c is about handling of descriptor tables; the reasons
are historical - file_table.c used to be about a static array of
struct file we used to have way back).
A lot of stray ends got cleaned up and converted to saner primitives,
disgusting mess in android/binder.c is still disgusting, but at least
doesn't poke so much in descriptor table guts anymore. A bunch of
relatively minor races got fixed in process, plus an ext4 struct file
leak.
- related thing - fget_light() partially unuglified; see fdget() in
there (and yes, it generates the code as good as we used to have).
- also related - bits of Cyrill's procfs stuff that got entangled into
that work; _not_ all of it, just the initial move to fs/proc/fd.c and
switch of fdinfo to seq_file.
- Alex's fs/coredump.c spiltoff - the same story, had been easier to
take that commit than mess with conflicts. The rest is a separate
pile, this was just a mechanical code movement.
- a few misc patches all over the place. Not all for this cycle,
there'll be more (and quite a few currently sit in akpm's tree)."
Fix up trivial conflicts in the android binder driver, and some fairly
simple conflicts due to two different changes to the sock_alloc_file()
interface ("take descriptor handling from sock_alloc_file() to callers"
vs "net: Providing protocol type via system.sockprotoname xattr of
/proc/PID/fd entries" adding a dentry name to the socket)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (72 commits)
MAX_LFS_FILESIZE should be a loff_t
compat: fs: Generic compat_sys_sendfile implementation
fs: push rcu_barrier() from deactivate_locked_super() to filesystems
btrfs: reada_extent doesn't need kref for refcount
coredump: move core dump functionality into its own file
coredump: prevent double-free on an error path in core dumper
usb/gadget: fix misannotations
fcntl: fix misannotations
ceph: don't abuse d_delete() on failure exits
hypfs: ->d_parent is never NULL or negative
vfs: delete surplus inode NULL check
switch simple cases of fget_light to fdget
new helpers: fdget()/fdput()
switch o2hb_region_dev_write() to fget_light()
proc_map_files_readdir(): don't bother with grabbing files
make get_file() return its argument
vhost_set_vring(): turn pollstart/pollstop into bool
switch prctl_set_mm_exe_file() to fget_light()
switch xfs_find_handle() to fget_light()
switch xfs_swapext() to fget_light()
...
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/core.c | 72 | ||||
-rw-r--r-- | kernel/exit.c | 97 | ||||
-rw-r--r-- | kernel/sys.c | 14 | ||||
-rw-r--r-- | kernel/taskstats.c | 11 |
4 files changed, 44 insertions, 150 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index deec4e50eb30..f16f3c58f11a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -468,14 +468,13 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, | |||
468 | { | 468 | { |
469 | struct perf_cgroup *cgrp; | 469 | struct perf_cgroup *cgrp; |
470 | struct cgroup_subsys_state *css; | 470 | struct cgroup_subsys_state *css; |
471 | struct file *file; | 471 | struct fd f = fdget(fd); |
472 | int ret = 0, fput_needed; | 472 | int ret = 0; |
473 | 473 | ||
474 | file = fget_light(fd, &fput_needed); | 474 | if (!f.file) |
475 | if (!file) | ||
476 | return -EBADF; | 475 | return -EBADF; |
477 | 476 | ||
478 | css = cgroup_css_from_dir(file, perf_subsys_id); | 477 | css = cgroup_css_from_dir(f.file, perf_subsys_id); |
479 | if (IS_ERR(css)) { | 478 | if (IS_ERR(css)) { |
480 | ret = PTR_ERR(css); | 479 | ret = PTR_ERR(css); |
481 | goto out; | 480 | goto out; |
@@ -501,7 +500,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event, | |||
501 | ret = -EINVAL; | 500 | ret = -EINVAL; |
502 | } | 501 | } |
503 | out: | 502 | out: |
504 | fput_light(file, fput_needed); | 503 | fdput(f); |
505 | return ret; | 504 | return ret; |
506 | } | 505 | } |
507 | 506 | ||
@@ -3234,21 +3233,18 @@ unlock: | |||
3234 | 3233 | ||
3235 | static const struct file_operations perf_fops; | 3234 | static const struct file_operations perf_fops; |
3236 | 3235 | ||
3237 | static struct file *perf_fget_light(int fd, int *fput_needed) | 3236 | static inline int perf_fget_light(int fd, struct fd *p) |
3238 | { | 3237 | { |
3239 | struct file *file; | 3238 | struct fd f = fdget(fd); |
3240 | 3239 | if (!f.file) | |
3241 | file = fget_light(fd, fput_needed); | 3240 | return -EBADF; |
3242 | if (!file) | ||
3243 | return ERR_PTR(-EBADF); | ||
3244 | 3241 | ||
3245 | if (file->f_op != &perf_fops) { | 3242 | if (f.file->f_op != &perf_fops) { |
3246 | fput_light(file, *fput_needed); | 3243 | fdput(f); |
3247 | *fput_needed = 0; | 3244 | return -EBADF; |
3248 | return ERR_PTR(-EBADF); | ||
3249 | } | 3245 | } |
3250 | 3246 | *p = f; | |
3251 | return file; | 3247 | return 0; |
3252 | } | 3248 | } |
3253 | 3249 | ||
3254 | static int perf_event_set_output(struct perf_event *event, | 3250 | static int perf_event_set_output(struct perf_event *event, |
@@ -3280,22 +3276,19 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
3280 | 3276 | ||
3281 | case PERF_EVENT_IOC_SET_OUTPUT: | 3277 | case PERF_EVENT_IOC_SET_OUTPUT: |
3282 | { | 3278 | { |
3283 | struct file *output_file = NULL; | ||
3284 | struct perf_event *output_event = NULL; | ||
3285 | int fput_needed = 0; | ||
3286 | int ret; | 3279 | int ret; |
3287 | |||
3288 | if (arg != -1) { | 3280 | if (arg != -1) { |
3289 | output_file = perf_fget_light(arg, &fput_needed); | 3281 | struct perf_event *output_event; |
3290 | if (IS_ERR(output_file)) | 3282 | struct fd output; |
3291 | return PTR_ERR(output_file); | 3283 | ret = perf_fget_light(arg, &output); |
3292 | output_event = output_file->private_data; | 3284 | if (ret) |
3285 | return ret; | ||
3286 | output_event = output.file->private_data; | ||
3287 | ret = perf_event_set_output(event, output_event); | ||
3288 | fdput(output); | ||
3289 | } else { | ||
3290 | ret = perf_event_set_output(event, NULL); | ||
3293 | } | 3291 | } |
3294 | |||
3295 | ret = perf_event_set_output(event, output_event); | ||
3296 | if (output_event) | ||
3297 | fput_light(output_file, fput_needed); | ||
3298 | |||
3299 | return ret; | 3292 | return ret; |
3300 | } | 3293 | } |
3301 | 3294 | ||
@@ -6443,12 +6436,11 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6443 | struct perf_event_attr attr; | 6436 | struct perf_event_attr attr; |
6444 | struct perf_event_context *ctx; | 6437 | struct perf_event_context *ctx; |
6445 | struct file *event_file = NULL; | 6438 | struct file *event_file = NULL; |
6446 | struct file *group_file = NULL; | 6439 | struct fd group = {NULL, 0}; |
6447 | struct task_struct *task = NULL; | 6440 | struct task_struct *task = NULL; |
6448 | struct pmu *pmu; | 6441 | struct pmu *pmu; |
6449 | int event_fd; | 6442 | int event_fd; |
6450 | int move_group = 0; | 6443 | int move_group = 0; |
6451 | int fput_needed = 0; | ||
6452 | int err; | 6444 | int err; |
6453 | 6445 | ||
6454 | /* for future expandability... */ | 6446 | /* for future expandability... */ |
@@ -6478,17 +6470,15 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6478 | if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) | 6470 | if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) |
6479 | return -EINVAL; | 6471 | return -EINVAL; |
6480 | 6472 | ||
6481 | event_fd = get_unused_fd_flags(O_RDWR); | 6473 | event_fd = get_unused_fd(); |
6482 | if (event_fd < 0) | 6474 | if (event_fd < 0) |
6483 | return event_fd; | 6475 | return event_fd; |
6484 | 6476 | ||
6485 | if (group_fd != -1) { | 6477 | if (group_fd != -1) { |
6486 | group_file = perf_fget_light(group_fd, &fput_needed); | 6478 | err = perf_fget_light(group_fd, &group); |
6487 | if (IS_ERR(group_file)) { | 6479 | if (err) |
6488 | err = PTR_ERR(group_file); | ||
6489 | goto err_fd; | 6480 | goto err_fd; |
6490 | } | 6481 | group_leader = group.file->private_data; |
6491 | group_leader = group_file->private_data; | ||
6492 | if (flags & PERF_FLAG_FD_OUTPUT) | 6482 | if (flags & PERF_FLAG_FD_OUTPUT) |
6493 | output_event = group_leader; | 6483 | output_event = group_leader; |
6494 | if (flags & PERF_FLAG_FD_NO_GROUP) | 6484 | if (flags & PERF_FLAG_FD_NO_GROUP) |
@@ -6664,7 +6654,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6664 | * of the group leader will find the pointer to itself in | 6654 | * of the group leader will find the pointer to itself in |
6665 | * perf_group_detach(). | 6655 | * perf_group_detach(). |
6666 | */ | 6656 | */ |
6667 | fput_light(group_file, fput_needed); | 6657 | fdput(group); |
6668 | fd_install(event_fd, event_file); | 6658 | fd_install(event_fd, event_file); |
6669 | return event_fd; | 6659 | return event_fd; |
6670 | 6660 | ||
@@ -6678,7 +6668,7 @@ err_task: | |||
6678 | if (task) | 6668 | if (task) |
6679 | put_task_struct(task); | 6669 | put_task_struct(task); |
6680 | err_group_fd: | 6670 | err_group_fd: |
6681 | fput_light(group_file, fput_needed); | 6671 | fdput(group); |
6682 | err_fd: | 6672 | err_fd: |
6683 | put_unused_fd(event_fd); | 6673 | put_unused_fd(event_fd); |
6684 | return err; | 6674 | return err; |
diff --git a/kernel/exit.c b/kernel/exit.c index 42f25952edd9..346616c0092c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -457,108 +457,13 @@ void daemonize(const char *name, ...) | |||
457 | /* Become as one with the init task */ | 457 | /* Become as one with the init task */ |
458 | 458 | ||
459 | daemonize_fs_struct(); | 459 | daemonize_fs_struct(); |
460 | exit_files(current); | 460 | daemonize_descriptors(); |
461 | current->files = init_task.files; | ||
462 | atomic_inc(¤t->files->count); | ||
463 | 461 | ||
464 | reparent_to_kthreadd(); | 462 | reparent_to_kthreadd(); |
465 | } | 463 | } |
466 | 464 | ||
467 | EXPORT_SYMBOL(daemonize); | 465 | EXPORT_SYMBOL(daemonize); |
468 | 466 | ||
469 | static void close_files(struct files_struct * files) | ||
470 | { | ||
471 | int i, j; | ||
472 | struct fdtable *fdt; | ||
473 | |||
474 | j = 0; | ||
475 | |||
476 | /* | ||
477 | * It is safe to dereference the fd table without RCU or | ||
478 | * ->file_lock because this is the last reference to the | ||
479 | * files structure. But use RCU to shut RCU-lockdep up. | ||
480 | */ | ||
481 | rcu_read_lock(); | ||
482 | fdt = files_fdtable(files); | ||
483 | rcu_read_unlock(); | ||
484 | for (;;) { | ||
485 | unsigned long set; | ||
486 | i = j * BITS_PER_LONG; | ||
487 | if (i >= fdt->max_fds) | ||
488 | break; | ||
489 | set = fdt->open_fds[j++]; | ||
490 | while (set) { | ||
491 | if (set & 1) { | ||
492 | struct file * file = xchg(&fdt->fd[i], NULL); | ||
493 | if (file) { | ||
494 | filp_close(file, files); | ||
495 | cond_resched(); | ||
496 | } | ||
497 | } | ||
498 | i++; | ||
499 | set >>= 1; | ||
500 | } | ||
501 | } | ||
502 | } | ||
503 | |||
504 | struct files_struct *get_files_struct(struct task_struct *task) | ||
505 | { | ||
506 | struct files_struct *files; | ||
507 | |||
508 | task_lock(task); | ||
509 | files = task->files; | ||
510 | if (files) | ||
511 | atomic_inc(&files->count); | ||
512 | task_unlock(task); | ||
513 | |||
514 | return files; | ||
515 | } | ||
516 | |||
517 | void put_files_struct(struct files_struct *files) | ||
518 | { | ||
519 | struct fdtable *fdt; | ||
520 | |||
521 | if (atomic_dec_and_test(&files->count)) { | ||
522 | close_files(files); | ||
523 | /* | ||
524 | * Free the fd and fdset arrays if we expanded them. | ||
525 | * If the fdtable was embedded, pass files for freeing | ||
526 | * at the end of the RCU grace period. Otherwise, | ||
527 | * you can free files immediately. | ||
528 | */ | ||
529 | rcu_read_lock(); | ||
530 | fdt = files_fdtable(files); | ||
531 | if (fdt != &files->fdtab) | ||
532 | kmem_cache_free(files_cachep, files); | ||
533 | free_fdtable(fdt); | ||
534 | rcu_read_unlock(); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | void reset_files_struct(struct files_struct *files) | ||
539 | { | ||
540 | struct task_struct *tsk = current; | ||
541 | struct files_struct *old; | ||
542 | |||
543 | old = tsk->files; | ||
544 | task_lock(tsk); | ||
545 | tsk->files = files; | ||
546 | task_unlock(tsk); | ||
547 | put_files_struct(old); | ||
548 | } | ||
549 | |||
550 | void exit_files(struct task_struct *tsk) | ||
551 | { | ||
552 | struct files_struct * files = tsk->files; | ||
553 | |||
554 | if (files) { | ||
555 | task_lock(tsk); | ||
556 | tsk->files = NULL; | ||
557 | task_unlock(tsk); | ||
558 | put_files_struct(files); | ||
559 | } | ||
560 | } | ||
561 | |||
562 | #ifdef CONFIG_MM_OWNER | 467 | #ifdef CONFIG_MM_OWNER |
563 | /* | 468 | /* |
564 | * A task is exiting. If it owned this mm, find a new owner for the mm. | 469 | * A task is exiting. If it owned this mm, find a new owner for the mm. |
diff --git a/kernel/sys.c b/kernel/sys.c index 241507f23eca..f9492284e5d2 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1788,15 +1788,15 @@ SYSCALL_DEFINE1(umask, int, mask) | |||
1788 | #ifdef CONFIG_CHECKPOINT_RESTORE | 1788 | #ifdef CONFIG_CHECKPOINT_RESTORE |
1789 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | 1789 | static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) |
1790 | { | 1790 | { |
1791 | struct file *exe_file; | 1791 | struct fd exe; |
1792 | struct dentry *dentry; | 1792 | struct dentry *dentry; |
1793 | int err; | 1793 | int err; |
1794 | 1794 | ||
1795 | exe_file = fget(fd); | 1795 | exe = fdget(fd); |
1796 | if (!exe_file) | 1796 | if (!exe.file) |
1797 | return -EBADF; | 1797 | return -EBADF; |
1798 | 1798 | ||
1799 | dentry = exe_file->f_path.dentry; | 1799 | dentry = exe.file->f_path.dentry; |
1800 | 1800 | ||
1801 | /* | 1801 | /* |
1802 | * Because the original mm->exe_file points to executable file, make | 1802 | * Because the original mm->exe_file points to executable file, make |
@@ -1805,7 +1805,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | |||
1805 | */ | 1805 | */ |
1806 | err = -EACCES; | 1806 | err = -EACCES; |
1807 | if (!S_ISREG(dentry->d_inode->i_mode) || | 1807 | if (!S_ISREG(dentry->d_inode->i_mode) || |
1808 | exe_file->f_path.mnt->mnt_flags & MNT_NOEXEC) | 1808 | exe.file->f_path.mnt->mnt_flags & MNT_NOEXEC) |
1809 | goto exit; | 1809 | goto exit; |
1810 | 1810 | ||
1811 | err = inode_permission(dentry->d_inode, MAY_EXEC); | 1811 | err = inode_permission(dentry->d_inode, MAY_EXEC); |
@@ -1839,12 +1839,12 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) | |||
1839 | goto exit_unlock; | 1839 | goto exit_unlock; |
1840 | 1840 | ||
1841 | err = 0; | 1841 | err = 0; |
1842 | set_mm_exe_file(mm, exe_file); | 1842 | set_mm_exe_file(mm, exe.file); /* this grabs a reference to exe.file */ |
1843 | exit_unlock: | 1843 | exit_unlock: |
1844 | up_write(&mm->mmap_sem); | 1844 | up_write(&mm->mmap_sem); |
1845 | 1845 | ||
1846 | exit: | 1846 | exit: |
1847 | fput(exe_file); | 1847 | fdput(exe); |
1848 | return err; | 1848 | return err; |
1849 | } | 1849 | } |
1850 | 1850 | ||
diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 5eab1f3edfa5..610f0838d555 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c | |||
@@ -424,16 +424,15 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
424 | struct nlattr *na; | 424 | struct nlattr *na; |
425 | size_t size; | 425 | size_t size; |
426 | u32 fd; | 426 | u32 fd; |
427 | struct file *file; | 427 | struct fd f; |
428 | int fput_needed; | ||
429 | 428 | ||
430 | na = info->attrs[CGROUPSTATS_CMD_ATTR_FD]; | 429 | na = info->attrs[CGROUPSTATS_CMD_ATTR_FD]; |
431 | if (!na) | 430 | if (!na) |
432 | return -EINVAL; | 431 | return -EINVAL; |
433 | 432 | ||
434 | fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]); | 433 | fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_FD]); |
435 | file = fget_light(fd, &fput_needed); | 434 | f = fdget(fd); |
436 | if (!file) | 435 | if (!f.file) |
437 | return 0; | 436 | return 0; |
438 | 437 | ||
439 | size = nla_total_size(sizeof(struct cgroupstats)); | 438 | size = nla_total_size(sizeof(struct cgroupstats)); |
@@ -453,7 +452,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
453 | stats = nla_data(na); | 452 | stats = nla_data(na); |
454 | memset(stats, 0, sizeof(*stats)); | 453 | memset(stats, 0, sizeof(*stats)); |
455 | 454 | ||
456 | rc = cgroupstats_build(stats, file->f_dentry); | 455 | rc = cgroupstats_build(stats, f.file->f_dentry); |
457 | if (rc < 0) { | 456 | if (rc < 0) { |
458 | nlmsg_free(rep_skb); | 457 | nlmsg_free(rep_skb); |
459 | goto err; | 458 | goto err; |
@@ -462,7 +461,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
462 | rc = send_reply(rep_skb, info); | 461 | rc = send_reply(rep_skb, info); |
463 | 462 | ||
464 | err: | 463 | err: |
465 | fput_light(file, fput_needed); | 464 | fdput(f); |
466 | return rc; | 465 | return rc; |
467 | } | 466 | } |
468 | 467 | ||