diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 22:05:55 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 22:05:55 -0400 |
| commit | bc84e0a160e383deb56568f4e03bc51b1ce16775 (patch) | |
| tree | 3c8cf1ae23c2f9c165bd7ce63a40b1d5c3aee275 | |
| parent | a92910723a5af54f81373875fd95133c88df94bd (diff) | |
| parent | f8f95702f0c4529b0f59488f4509608f0c160e77 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
[PATCH] sanitize locate_fd()
[PATCH] sanitize unshare_files/reset_files_struct
[PATCH] sanitize handling of shared descriptor tables in failing execve()
[PATCH] close race in unshare_files()
[PATCH] restore sane ->umount_begin() API
cifs: timeout dfs automounts +little fix.
| -rw-r--r-- | fs/9p/vfs_super.c | 7 | ||||
| -rw-r--r-- | fs/binfmt_elf.c | 23 | ||||
| -rw-r--r-- | fs/binfmt_misc.c | 18 | ||||
| -rw-r--r-- | fs/binfmt_som.c | 10 | ||||
| -rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 29 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 10 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 8 | ||||
| -rw-r--r-- | fs/exec.c | 28 | ||||
| -rw-r--r-- | fs/fcntl.c | 40 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 5 | ||||
| -rw-r--r-- | fs/namespace.c | 9 | ||||
| -rw-r--r-- | fs/nfs/super.c | 8 | ||||
| -rw-r--r-- | include/linux/file.h | 3 | ||||
| -rw-r--r-- | include/linux/fs.h | 5 | ||||
| -rw-r--r-- | kernel/exit.c | 6 | ||||
| -rw-r--r-- | kernel/fork.c | 58 |
16 files changed, 95 insertions, 172 deletions
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 678c02f1ae23..a452ac67fc94 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
| @@ -224,12 +224,11 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | static void | 226 | static void |
| 227 | v9fs_umount_begin(struct vfsmount *vfsmnt, int flags) | 227 | v9fs_umount_begin(struct super_block *sb) |
| 228 | { | 228 | { |
| 229 | struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info; | 229 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
| 230 | 230 | ||
| 231 | if (flags & MNT_FORCE) | 231 | v9fs_session_cancel(v9ses); |
| 232 | v9fs_session_cancel(v9ses); | ||
| 233 | } | 232 | } |
| 234 | 233 | ||
| 235 | static const struct super_operations v9fs_super_ops = { | 234 | static const struct super_operations v9fs_super_ops = { |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 5e1a4fb5cacb..9924581df6f6 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 543 | unsigned long interp_load_addr = 0; | 543 | unsigned long interp_load_addr = 0; |
| 544 | unsigned long start_code, end_code, start_data, end_data; | 544 | unsigned long start_code, end_code, start_data, end_data; |
| 545 | unsigned long reloc_func_desc = 0; | 545 | unsigned long reloc_func_desc = 0; |
| 546 | struct files_struct *files; | ||
| 547 | int executable_stack = EXSTACK_DEFAULT; | 546 | int executable_stack = EXSTACK_DEFAULT; |
| 548 | unsigned long def_flags = 0; | 547 | unsigned long def_flags = 0; |
| 549 | struct { | 548 | struct { |
| @@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 593 | goto out_free_ph; | 592 | goto out_free_ph; |
| 594 | } | 593 | } |
| 595 | 594 | ||
| 596 | files = current->files; /* Refcounted so ok */ | ||
| 597 | retval = unshare_files(); | ||
| 598 | if (retval < 0) | ||
| 599 | goto out_free_ph; | ||
| 600 | if (files == current->files) { | ||
| 601 | put_files_struct(files); | ||
| 602 | files = NULL; | ||
| 603 | } | ||
| 604 | |||
| 605 | /* exec will make our files private anyway, but for the a.out | ||
| 606 | loader stuff we need to do it earlier */ | ||
| 607 | retval = get_unused_fd(); | 595 | retval = get_unused_fd(); |
| 608 | if (retval < 0) | 596 | if (retval < 0) |
| 609 | goto out_free_fh; | 597 | goto out_free_ph; |
| 610 | get_file(bprm->file); | 598 | get_file(bprm->file); |
| 611 | fd_install(elf_exec_fileno = retval, bprm->file); | 599 | fd_install(elf_exec_fileno = retval, bprm->file); |
| 612 | 600 | ||
| @@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 728 | if (retval) | 716 | if (retval) |
| 729 | goto out_free_dentry; | 717 | goto out_free_dentry; |
| 730 | 718 | ||
| 731 | /* Discard our unneeded old files struct */ | ||
| 732 | if (files) { | ||
| 733 | put_files_struct(files); | ||
| 734 | files = NULL; | ||
| 735 | } | ||
| 736 | |||
| 737 | /* OK, This is the point of no return */ | 719 | /* OK, This is the point of no return */ |
| 738 | current->flags &= ~PF_FORKNOEXEC; | 720 | current->flags &= ~PF_FORKNOEXEC; |
| 739 | current->mm->def_flags = def_flags; | 721 | current->mm->def_flags = def_flags; |
| @@ -1016,9 +998,6 @@ out_free_interp: | |||
| 1016 | kfree(elf_interpreter); | 998 | kfree(elf_interpreter); |
| 1017 | out_free_file: | 999 | out_free_file: |
| 1018 | sys_close(elf_exec_fileno); | 1000 | sys_close(elf_exec_fileno); |
| 1019 | out_free_fh: | ||
| 1020 | if (files) | ||
| 1021 | reset_files_struct(current, files); | ||
| 1022 | out_free_ph: | 1001 | out_free_ph: |
| 1023 | kfree(elf_phdata); | 1002 | kfree(elf_phdata); |
| 1024 | goto out; | 1003 | goto out; |
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index b53c7e5f41bb..dbf0ac0523de 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
| @@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 110 | char *iname_addr = iname; | 110 | char *iname_addr = iname; |
| 111 | int retval; | 111 | int retval; |
| 112 | int fd_binary = -1; | 112 | int fd_binary = -1; |
| 113 | struct files_struct *files = NULL; | ||
| 114 | 113 | ||
| 115 | retval = -ENOEXEC; | 114 | retval = -ENOEXEC; |
| 116 | if (!enabled) | 115 | if (!enabled) |
| @@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 133 | 132 | ||
| 134 | if (fmt->flags & MISC_FMT_OPEN_BINARY) { | 133 | if (fmt->flags & MISC_FMT_OPEN_BINARY) { |
| 135 | 134 | ||
| 136 | files = current->files; | ||
| 137 | retval = unshare_files(); | ||
| 138 | if (retval < 0) | ||
| 139 | goto _ret; | ||
| 140 | if (files == current->files) { | ||
| 141 | put_files_struct(files); | ||
| 142 | files = NULL; | ||
| 143 | } | ||
| 144 | /* if the binary should be opened on behalf of the | 135 | /* if the binary should be opened on behalf of the |
| 145 | * interpreter than keep it open and assign descriptor | 136 | * interpreter than keep it open and assign descriptor |
| 146 | * to it */ | 137 | * to it */ |
| 147 | fd_binary = get_unused_fd(); | 138 | fd_binary = get_unused_fd(); |
| 148 | if (fd_binary < 0) { | 139 | if (fd_binary < 0) { |
| 149 | retval = fd_binary; | 140 | retval = fd_binary; |
| 150 | goto _unshare; | 141 | goto _ret; |
| 151 | } | 142 | } |
| 152 | fd_install(fd_binary, bprm->file); | 143 | fd_install(fd_binary, bprm->file); |
| 153 | 144 | ||
| @@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 205 | if (retval < 0) | 196 | if (retval < 0) |
| 206 | goto _error; | 197 | goto _error; |
| 207 | 198 | ||
| 208 | if (files) { | ||
| 209 | put_files_struct(files); | ||
| 210 | files = NULL; | ||
| 211 | } | ||
| 212 | _ret: | 199 | _ret: |
| 213 | return retval; | 200 | return retval; |
| 214 | _error: | 201 | _error: |
| @@ -216,9 +203,6 @@ _error: | |||
| 216 | sys_close(fd_binary); | 203 | sys_close(fd_binary); |
| 217 | bprm->interp_flags = 0; | 204 | bprm->interp_flags = 0; |
| 218 | bprm->interp_data = 0; | 205 | bprm->interp_data = 0; |
| 219 | _unshare: | ||
| 220 | if (files) | ||
| 221 | reset_files_struct(current, files); | ||
| 222 | goto _ret; | 206 | goto _ret; |
| 223 | } | 207 | } |
| 224 | 208 | ||
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index 14c63527c762..fdc36bfd6a7b 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c | |||
| @@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 194 | unsigned long som_entry; | 194 | unsigned long som_entry; |
| 195 | struct som_hdr *som_ex; | 195 | struct som_hdr *som_ex; |
| 196 | struct som_exec_auxhdr *hpuxhdr; | 196 | struct som_exec_auxhdr *hpuxhdr; |
| 197 | struct files_struct *files; | ||
| 198 | 197 | ||
| 199 | /* Get the exec-header */ | 198 | /* Get the exec-header */ |
| 200 | som_ex = (struct som_hdr *) bprm->buf; | 199 | som_ex = (struct som_hdr *) bprm->buf; |
| @@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 221 | goto out_free; | 220 | goto out_free; |
| 222 | } | 221 | } |
| 223 | 222 | ||
| 224 | files = current->files; /* Refcounted so ok */ | ||
| 225 | retval = unshare_files(); | ||
| 226 | if (retval < 0) | ||
| 227 | goto out_free; | ||
| 228 | if (files == current->files) { | ||
| 229 | put_files_struct(files); | ||
| 230 | files = NULL; | ||
| 231 | } | ||
| 232 | |||
| 233 | retval = get_unused_fd(); | 223 | retval = get_unused_fd(); |
| 234 | if (retval < 0) | 224 | if (retval < 0) |
| 235 | goto out_free; | 225 | goto out_free; |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index f53f41ff1665..95024c066d89 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -25,14 +25,26 @@ | |||
| 25 | 25 | ||
| 26 | static LIST_HEAD(cifs_dfs_automount_list); | 26 | static LIST_HEAD(cifs_dfs_automount_list); |
| 27 | 27 | ||
| 28 | /* | 28 | static void cifs_dfs_expire_automounts(struct work_struct *work); |
| 29 | * DFS functions | 29 | static DECLARE_DELAYED_WORK(cifs_dfs_automount_task, |
| 30 | */ | 30 | cifs_dfs_expire_automounts); |
| 31 | static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ; | ||
| 32 | |||
| 33 | static void cifs_dfs_expire_automounts(struct work_struct *work) | ||
| 34 | { | ||
| 35 | struct list_head *list = &cifs_dfs_automount_list; | ||
| 36 | |||
| 37 | mark_mounts_for_expiry(list); | ||
| 38 | if (!list_empty(list)) | ||
| 39 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
| 40 | cifs_dfs_mountpoint_expiry_timeout); | ||
| 41 | } | ||
| 31 | 42 | ||
| 32 | void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) | 43 | void cifs_dfs_release_automount_timer(void) |
| 33 | { | 44 | { |
| 34 | mark_mounts_for_expiry(&cifs_dfs_automount_list); | 45 | BUG_ON(!list_empty(&cifs_dfs_automount_list)); |
| 35 | mark_mounts_for_expiry(&cifs_dfs_automount_list); | 46 | cancel_delayed_work(&cifs_dfs_automount_task); |
| 47 | flush_scheduled_work(); | ||
| 36 | } | 48 | } |
| 37 | 49 | ||
| 38 | /** | 50 | /** |
| @@ -261,10 +273,11 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 261 | err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); | 273 | err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); |
| 262 | switch (err) { | 274 | switch (err) { |
| 263 | case 0: | 275 | case 0: |
| 264 | dput(nd->path.dentry); | 276 | path_put(&nd->path); |
| 265 | mntput(nd->path.mnt); | ||
| 266 | nd->path.mnt = newmnt; | 277 | nd->path.mnt = newmnt; |
| 267 | nd->path.dentry = dget(newmnt->mnt_root); | 278 | nd->path.dentry = dget(newmnt->mnt_root); |
| 279 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
| 280 | cifs_dfs_mountpoint_expiry_timeout); | ||
| 268 | break; | 281 | break; |
| 269 | case -EBUSY: | 282 | case -EBUSY: |
| 270 | /* someone else made a mount here whilst we were busy */ | 283 | /* someone else made a mount here whilst we were busy */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index a04b17e5a9d0..39c2cbdface7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = { | |||
| 466 | }; | 466 | }; |
| 467 | #endif | 467 | #endif |
| 468 | 468 | ||
| 469 | static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags) | 469 | static void cifs_umount_begin(struct super_block *sb) |
| 470 | { | 470 | { |
| 471 | struct cifs_sb_info *cifs_sb; | 471 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 472 | struct cifsTconInfo *tcon; | 472 | struct cifsTconInfo *tcon; |
| 473 | 473 | ||
| 474 | dfs_shrink_umount_helper(vfsmnt); | ||
| 475 | |||
| 476 | if (!(flags & MNT_FORCE)) | ||
| 477 | return; | ||
| 478 | cifs_sb = CIFS_SB(vfsmnt->mnt_sb); | ||
| 479 | if (cifs_sb == NULL) | 474 | if (cifs_sb == NULL) |
| 480 | return; | 475 | return; |
| 481 | 476 | ||
| @@ -1100,6 +1095,7 @@ exit_cifs(void) | |||
| 1100 | cFYI(DBG2, ("exit_cifs")); | 1095 | cFYI(DBG2, ("exit_cifs")); |
| 1101 | cifs_proc_clean(); | 1096 | cifs_proc_clean(); |
| 1102 | #ifdef CONFIG_CIFS_DFS_UPCALL | 1097 | #ifdef CONFIG_CIFS_DFS_UPCALL |
| 1098 | cifs_dfs_release_automount_timer(); | ||
| 1103 | unregister_key_type(&key_type_dns_resolver); | 1099 | unregister_key_type(&key_type_dns_resolver); |
| 1104 | #endif | 1100 | #endif |
| 1105 | #ifdef CONFIG_CIFS_UPCALL | 1101 | #ifdef CONFIG_CIFS_UPCALL |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0c83da4a7dab..50f9fdae19b3 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -104,13 +104,7 @@ extern int mode_to_acl(struct inode *inode, const char *path, __u64); | |||
| 104 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 104 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
| 105 | const char *); | 105 | const char *); |
| 106 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); | 106 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); |
| 107 | #ifdef CONFIG_CIFS_DFS_UPCALL | 107 | extern void cifs_dfs_release_automount_timer(void); |
| 108 | extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt); | ||
| 109 | #else | ||
| 110 | static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) | ||
| 111 | { | ||
| 112 | } | ||
| 113 | #endif /* DFS_UPCALL */ | ||
| 114 | void cifs_proc_init(void); | 108 | void cifs_proc_init(void); |
| 115 | void cifs_proc_clean(void); | 109 | void cifs_proc_clean(void); |
| 116 | 110 | ||
| @@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 953 | { | 953 | { |
| 954 | char * name; | 954 | char * name; |
| 955 | int i, ch, retval; | 955 | int i, ch, retval; |
| 956 | struct files_struct *files; | ||
| 957 | char tcomm[sizeof(current->comm)]; | 956 | char tcomm[sizeof(current->comm)]; |
| 958 | 957 | ||
| 959 | /* | 958 | /* |
| @@ -965,26 +964,15 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 965 | goto out; | 964 | goto out; |
| 966 | 965 | ||
| 967 | /* | 966 | /* |
| 968 | * Make sure we have private file handles. Ask the | ||
| 969 | * fork helper to do the work for us and the exit | ||
| 970 | * helper to do the cleanup of the old one. | ||
| 971 | */ | ||
| 972 | files = current->files; /* refcounted so safe to hold */ | ||
| 973 | retval = unshare_files(); | ||
| 974 | if (retval) | ||
| 975 | goto out; | ||
| 976 | /* | ||
| 977 | * Release all of the old mmap stuff | 967 | * Release all of the old mmap stuff |
| 978 | */ | 968 | */ |
| 979 | retval = exec_mmap(bprm->mm); | 969 | retval = exec_mmap(bprm->mm); |
| 980 | if (retval) | 970 | if (retval) |
| 981 | goto mmap_failed; | 971 | goto out; |
| 982 | 972 | ||
| 983 | bprm->mm = NULL; /* We're using it now */ | 973 | bprm->mm = NULL; /* We're using it now */ |
| 984 | 974 | ||
| 985 | /* This is the point of no return */ | 975 | /* This is the point of no return */ |
| 986 | put_files_struct(files); | ||
| 987 | |||
| 988 | current->sas_ss_sp = current->sas_ss_size = 0; | 976 | current->sas_ss_sp = current->sas_ss_size = 0; |
| 989 | 977 | ||
| 990 | if (current->euid == current->uid && current->egid == current->gid) | 978 | if (current->euid == current->uid && current->egid == current->gid) |
| @@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 1034 | 1022 | ||
| 1035 | return 0; | 1023 | return 0; |
| 1036 | 1024 | ||
| 1037 | mmap_failed: | ||
| 1038 | reset_files_struct(current, files); | ||
| 1039 | out: | 1025 | out: |
| 1040 | return retval; | 1026 | return retval; |
| 1041 | } | 1027 | } |
| @@ -1283,12 +1269,17 @@ int do_execve(char * filename, | |||
| 1283 | struct linux_binprm *bprm; | 1269 | struct linux_binprm *bprm; |
| 1284 | struct file *file; | 1270 | struct file *file; |
| 1285 | unsigned long env_p; | 1271 | unsigned long env_p; |
| 1272 | struct files_struct *displaced; | ||
| 1286 | int retval; | 1273 | int retval; |
| 1287 | 1274 | ||
| 1275 | retval = unshare_files(&displaced); | ||
| 1276 | if (retval) | ||
| 1277 | goto out_ret; | ||
| 1278 | |||
| 1288 | retval = -ENOMEM; | 1279 | retval = -ENOMEM; |
| 1289 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | 1280 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
| 1290 | if (!bprm) | 1281 | if (!bprm) |
| 1291 | goto out_ret; | 1282 | goto out_files; |
| 1292 | 1283 | ||
| 1293 | file = open_exec(filename); | 1284 | file = open_exec(filename); |
| 1294 | retval = PTR_ERR(file); | 1285 | retval = PTR_ERR(file); |
| @@ -1343,6 +1334,8 @@ int do_execve(char * filename, | |||
| 1343 | security_bprm_free(bprm); | 1334 | security_bprm_free(bprm); |
| 1344 | acct_update_integrals(current); | 1335 | acct_update_integrals(current); |
| 1345 | kfree(bprm); | 1336 | kfree(bprm); |
| 1337 | if (displaced) | ||
| 1338 | put_files_struct(displaced); | ||
| 1346 | return retval; | 1339 | return retval; |
| 1347 | } | 1340 | } |
| 1348 | 1341 | ||
| @@ -1363,6 +1356,9 @@ out_file: | |||
| 1363 | out_kfree: | 1356 | out_kfree: |
| 1364 | kfree(bprm); | 1357 | kfree(bprm); |
| 1365 | 1358 | ||
| 1359 | out_files: | ||
| 1360 | if (displaced) | ||
| 1361 | reset_files_struct(displaced); | ||
| 1366 | out_ret: | 1362 | out_ret: |
| 1367 | return retval; | 1363 | return retval; |
| 1368 | } | 1364 | } |
diff --git a/fs/fcntl.c b/fs/fcntl.c index e632da761fc1..3f3ac630ccde 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd) | |||
| 55 | * file_lock held for write. | 55 | * file_lock held for write. |
| 56 | */ | 56 | */ |
| 57 | 57 | ||
| 58 | static int locate_fd(struct files_struct *files, | 58 | static int locate_fd(unsigned int orig_start, int cloexec) |
| 59 | struct file *file, unsigned int orig_start) | ||
| 60 | { | 59 | { |
| 60 | struct files_struct *files = current->files; | ||
| 61 | unsigned int newfd; | 61 | unsigned int newfd; |
| 62 | unsigned int start; | 62 | unsigned int start; |
| 63 | int error; | 63 | int error; |
| 64 | struct fdtable *fdt; | 64 | struct fdtable *fdt; |
| 65 | 65 | ||
| 66 | spin_lock(&files->file_lock); | ||
| 67 | |||
| 66 | error = -EINVAL; | 68 | error = -EINVAL; |
| 67 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 69 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
| 68 | goto out; | 70 | goto out; |
| @@ -97,42 +99,28 @@ repeat: | |||
| 97 | if (error) | 99 | if (error) |
| 98 | goto repeat; | 100 | goto repeat; |
| 99 | 101 | ||
| 100 | /* | ||
| 101 | * We reacquired files_lock, so we are safe as long as | ||
| 102 | * we reacquire the fdtable pointer and use it while holding | ||
| 103 | * the lock, no one can free it during that time. | ||
| 104 | */ | ||
| 105 | if (start <= files->next_fd) | 102 | if (start <= files->next_fd) |
| 106 | files->next_fd = newfd + 1; | 103 | files->next_fd = newfd + 1; |
| 107 | 104 | ||
| 105 | FD_SET(newfd, fdt->open_fds); | ||
| 106 | if (cloexec) | ||
| 107 | FD_SET(newfd, fdt->close_on_exec); | ||
| 108 | else | ||
| 109 | FD_CLR(newfd, fdt->close_on_exec); | ||
| 108 | error = newfd; | 110 | error = newfd; |
| 109 | 111 | ||
| 110 | out: | 112 | out: |
| 113 | spin_unlock(&files->file_lock); | ||
| 111 | return error; | 114 | return error; |
| 112 | } | 115 | } |
| 113 | 116 | ||
| 114 | static int dupfd(struct file *file, unsigned int start, int cloexec) | 117 | static int dupfd(struct file *file, unsigned int start, int cloexec) |
| 115 | { | 118 | { |
| 116 | struct files_struct * files = current->files; | 119 | int fd = locate_fd(start, cloexec); |
| 117 | struct fdtable *fdt; | 120 | if (fd >= 0) |
| 118 | int fd; | ||
| 119 | |||
| 120 | spin_lock(&files->file_lock); | ||
| 121 | fd = locate_fd(files, file, start); | ||
| 122 | if (fd >= 0) { | ||
| 123 | /* locate_fd() may have expanded fdtable, load the ptr */ | ||
| 124 | fdt = files_fdtable(files); | ||
| 125 | FD_SET(fd, fdt->open_fds); | ||
| 126 | if (cloexec) | ||
| 127 | FD_SET(fd, fdt->close_on_exec); | ||
| 128 | else | ||
| 129 | FD_CLR(fd, fdt->close_on_exec); | ||
| 130 | spin_unlock(&files->file_lock); | ||
| 131 | fd_install(fd, file); | 121 | fd_install(fd, file); |
| 132 | } else { | 122 | else |
| 133 | spin_unlock(&files->file_lock); | ||
| 134 | fput(file); | 123 | fput(file); |
| 135 | } | ||
| 136 | 124 | ||
| 137 | return fd; | 125 | return fd; |
| 138 | } | 126 | } |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 033f7bdd47e8..4df34da2284a 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -242,10 +242,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
| 242 | return inode; | 242 | return inode; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) | 245 | static void fuse_umount_begin(struct super_block *sb) |
| 246 | { | 246 | { |
| 247 | if (flags & MNT_FORCE) | 247 | fuse_abort_conn(get_fuse_conn_super(sb)); |
| 248 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); | ||
| 249 | } | 248 | } |
| 250 | 249 | ||
| 251 | static void fuse_send_destroy(struct fuse_conn *fc) | 250 | static void fuse_send_destroy(struct fuse_conn *fc) |
diff --git a/fs/namespace.c b/fs/namespace.c index 0505fb61aa74..f48f98110c30 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -1061,10 +1061,11 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
| 1061 | * about for the moment. | 1061 | * about for the moment. |
| 1062 | */ | 1062 | */ |
| 1063 | 1063 | ||
| 1064 | lock_kernel(); | 1064 | if (flags & MNT_FORCE && sb->s_op->umount_begin) { |
| 1065 | if (sb->s_op->umount_begin) | 1065 | lock_kernel(); |
| 1066 | sb->s_op->umount_begin(mnt, flags); | 1066 | sb->s_op->umount_begin(sb); |
| 1067 | unlock_kernel(); | 1067 | unlock_kernel(); |
| 1068 | } | ||
| 1068 | 1069 | ||
| 1069 | /* | 1070 | /* |
| 1070 | * No sense to grab the lock for this test, but test itself looks | 1071 | * No sense to grab the lock for this test, but test itself looks |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 20a1cb1810fe..fa220dc74609 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -198,7 +198,7 @@ static match_table_t nfs_secflavor_tokens = { | |||
| 198 | }; | 198 | }; |
| 199 | 199 | ||
| 200 | 200 | ||
| 201 | static void nfs_umount_begin(struct vfsmount *, int); | 201 | static void nfs_umount_begin(struct super_block *); |
| 202 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 202 | static int nfs_statfs(struct dentry *, struct kstatfs *); |
| 203 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 203 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
| 204 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | 204 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); |
| @@ -647,13 +647,11 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
| 647 | * Begin unmount by attempting to remove all automounted mountpoints we added | 647 | * Begin unmount by attempting to remove all automounted mountpoints we added |
| 648 | * in response to xdev traversals and referrals | 648 | * in response to xdev traversals and referrals |
| 649 | */ | 649 | */ |
| 650 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | 650 | static void nfs_umount_begin(struct super_block *sb) |
| 651 | { | 651 | { |
| 652 | struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); | 652 | struct nfs_server *server = NFS_SB(sb); |
| 653 | struct rpc_clnt *rpc; | 653 | struct rpc_clnt *rpc; |
| 654 | 654 | ||
| 655 | if (!(flags & MNT_FORCE)) | ||
| 656 | return; | ||
| 657 | /* -EIO all pending I/O */ | 655 | /* -EIO all pending I/O */ |
| 658 | rpc = server->client_acl; | 656 | rpc = server->client_acl; |
| 659 | if (!IS_ERR(rpc)) | 657 | if (!IS_ERR(rpc)) |
diff --git a/include/linux/file.h b/include/linux/file.h index 653477021e4c..69baf5a4f0a5 100644 --- a/include/linux/file.h +++ b/include/linux/file.h | |||
| @@ -117,7 +117,8 @@ struct task_struct; | |||
| 117 | 117 | ||
| 118 | struct files_struct *get_files_struct(struct task_struct *); | 118 | struct files_struct *get_files_struct(struct task_struct *); |
| 119 | void put_files_struct(struct files_struct *fs); | 119 | void put_files_struct(struct files_struct *fs); |
| 120 | void reset_files_struct(struct task_struct *, struct files_struct *); | 120 | void reset_files_struct(struct files_struct *); |
| 121 | int unshare_files(struct files_struct **); | ||
| 121 | 122 | ||
| 122 | extern struct kmem_cache *files_cachep; | 123 | extern struct kmem_cache *files_cachep; |
| 123 | 124 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 6556f2f967e5..d6d7c52055c6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1309,7 +1309,7 @@ struct super_operations { | |||
| 1309 | int (*statfs) (struct dentry *, struct kstatfs *); | 1309 | int (*statfs) (struct dentry *, struct kstatfs *); |
| 1310 | int (*remount_fs) (struct super_block *, int *, char *); | 1310 | int (*remount_fs) (struct super_block *, int *, char *); |
| 1311 | void (*clear_inode) (struct inode *); | 1311 | void (*clear_inode) (struct inode *); |
| 1312 | void (*umount_begin) (struct vfsmount *, int); | 1312 | void (*umount_begin) (struct super_block *); |
| 1313 | 1313 | ||
| 1314 | int (*show_options)(struct seq_file *, struct vfsmount *); | 1314 | int (*show_options)(struct seq_file *, struct vfsmount *); |
| 1315 | int (*show_stats)(struct seq_file *, struct vfsmount *); | 1315 | int (*show_stats)(struct seq_file *, struct vfsmount *); |
| @@ -2034,9 +2034,6 @@ static inline ino_t parent_ino(struct dentry *dentry) | |||
| 2034 | return res; | 2034 | return res; |
| 2035 | } | 2035 | } |
| 2036 | 2036 | ||
| 2037 | /* kernel/fork.c */ | ||
| 2038 | extern int unshare_files(void); | ||
| 2039 | |||
| 2040 | /* Transaction based IO helpers */ | 2037 | /* Transaction based IO helpers */ |
| 2041 | 2038 | ||
| 2042 | /* | 2039 | /* |
diff --git a/kernel/exit.c b/kernel/exit.c index cece89f80ab4..97f609f574b1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -507,10 +507,9 @@ void put_files_struct(struct files_struct *files) | |||
| 507 | } | 507 | } |
| 508 | } | 508 | } |
| 509 | 509 | ||
| 510 | EXPORT_SYMBOL(put_files_struct); | 510 | void reset_files_struct(struct files_struct *files) |
| 511 | |||
| 512 | void reset_files_struct(struct task_struct *tsk, struct files_struct *files) | ||
| 513 | { | 511 | { |
| 512 | struct task_struct *tsk = current; | ||
| 514 | struct files_struct *old; | 513 | struct files_struct *old; |
| 515 | 514 | ||
| 516 | old = tsk->files; | 515 | old = tsk->files; |
| @@ -519,7 +518,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files) | |||
| 519 | task_unlock(tsk); | 518 | task_unlock(tsk); |
| 520 | put_files_struct(old); | 519 | put_files_struct(old); |
| 521 | } | 520 | } |
| 522 | EXPORT_SYMBOL(reset_files_struct); | ||
| 523 | 521 | ||
| 524 | void exit_files(struct task_struct *tsk) | 522 | void exit_files(struct task_struct *tsk) |
| 525 | { | 523 | { |
diff --git a/kernel/fork.c b/kernel/fork.c index 89fe414645e9..efb618fc8ffe 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -805,12 +805,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | |||
| 805 | goto out; | 805 | goto out; |
| 806 | } | 806 | } |
| 807 | 807 | ||
| 808 | /* | ||
| 809 | * Note: we may be using current for both targets (See exec.c) | ||
| 810 | * This works because we cache current->files (old) as oldf. Don't | ||
| 811 | * break this. | ||
| 812 | */ | ||
| 813 | tsk->files = NULL; | ||
| 814 | newf = dup_fd(oldf, &error); | 808 | newf = dup_fd(oldf, &error); |
| 815 | if (!newf) | 809 | if (!newf) |
| 816 | goto out; | 810 | goto out; |
| @@ -846,34 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk) | |||
| 846 | return 0; | 840 | return 0; |
| 847 | } | 841 | } |
| 848 | 842 | ||
| 849 | /* | ||
| 850 | * Helper to unshare the files of the current task. | ||
| 851 | * We don't want to expose copy_files internals to | ||
| 852 | * the exec layer of the kernel. | ||
| 853 | */ | ||
| 854 | |||
| 855 | int unshare_files(void) | ||
| 856 | { | ||
| 857 | struct files_struct *files = current->files; | ||
| 858 | int rc; | ||
| 859 | |||
| 860 | BUG_ON(!files); | ||
| 861 | |||
| 862 | /* This can race but the race causes us to copy when we don't | ||
| 863 | need to and drop the copy */ | ||
| 864 | if(atomic_read(&files->count) == 1) | ||
| 865 | { | ||
| 866 | atomic_inc(&files->count); | ||
| 867 | return 0; | ||
| 868 | } | ||
| 869 | rc = copy_files(0, current); | ||
| 870 | if(rc) | ||
| 871 | current->files = files; | ||
| 872 | return rc; | ||
| 873 | } | ||
| 874 | |||
| 875 | EXPORT_SYMBOL(unshare_files); | ||
| 876 | |||
| 877 | static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) | 843 | static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) |
| 878 | { | 844 | { |
| 879 | struct sighand_struct *sig; | 845 | struct sighand_struct *sig; |
| @@ -1811,3 +1777,27 @@ bad_unshare_cleanup_thread: | |||
| 1811 | bad_unshare_out: | 1777 | bad_unshare_out: |
| 1812 | return err; | 1778 | return err; |
| 1813 | } | 1779 | } |
| 1780 | |||
| 1781 | /* | ||
| 1782 | * Helper to unshare the files of the current task. | ||
| 1783 | * We don't want to expose copy_files internals to | ||
| 1784 | * the exec layer of the kernel. | ||
| 1785 | */ | ||
| 1786 | |||
| 1787 | int unshare_files(struct files_struct **displaced) | ||
| 1788 | { | ||
| 1789 | struct task_struct *task = current; | ||
| 1790 | struct files_struct *copy; | ||
| 1791 | int error; | ||
| 1792 | |||
| 1793 | error = unshare_fd(CLONE_FILES, ©); | ||
| 1794 | if (error || !copy) { | ||
| 1795 | *displaced = NULL; | ||
| 1796 | return error; | ||
| 1797 | } | ||
| 1798 | *displaced = task->files; | ||
| 1799 | task_lock(task); | ||
| 1800 | task->files = copy; | ||
| 1801 | task_unlock(task); | ||
| 1802 | return 0; | ||
| 1803 | } | ||
