aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-25 22:05:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-25 22:05:55 -0400
commitbc84e0a160e383deb56568f4e03bc51b1ce16775 (patch)
tree3c8cf1ae23c2f9c165bd7ce63a40b1d5c3aee275
parenta92910723a5af54f81373875fd95133c88df94bd (diff)
parentf8f95702f0c4529b0f59488f4509608f0c160e77 (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.c7
-rw-r--r--fs/binfmt_elf.c23
-rw-r--r--fs/binfmt_misc.c18
-rw-r--r--fs/binfmt_som.c10
-rw-r--r--fs/cifs/cifs_dfs_ref.c29
-rw-r--r--fs/cifs/cifsfs.c10
-rw-r--r--fs/cifs/cifsproto.h8
-rw-r--r--fs/exec.c28
-rw-r--r--fs/fcntl.c40
-rw-r--r--fs/fuse/inode.c5
-rw-r--r--fs/namespace.c9
-rw-r--r--fs/nfs/super.c8
-rw-r--r--include/linux/file.h3
-rw-r--r--include/linux/fs.h5
-rw-r--r--kernel/exit.c6
-rw-r--r--kernel/fork.c58
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
226static void 226static void
227v9fs_umount_begin(struct vfsmount *vfsmnt, int flags) 227v9fs_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
235static const struct super_operations v9fs_super_ops = { 234static 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);
1017out_free_file: 999out_free_file:
1018 sys_close(elf_exec_fileno); 1000 sys_close(elf_exec_fileno);
1019out_free_fh:
1020 if (files)
1021 reset_files_struct(current, files);
1022out_free_ph: 1001out_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
26static LIST_HEAD(cifs_dfs_automount_list); 26static LIST_HEAD(cifs_dfs_automount_list);
27 27
28/* 28static void cifs_dfs_expire_automounts(struct work_struct *work);
29 * DFS functions 29static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
30*/ 30 cifs_dfs_expire_automounts);
31static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
32
33static 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
32void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) 43void 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
469static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags) 469static 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);
104extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 104extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
105 const char *); 105 const char *);
106extern int cifs_umount(struct super_block *, struct cifs_sb_info *); 106extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
107#ifdef CONFIG_CIFS_DFS_UPCALL 107extern void cifs_dfs_release_automount_timer(void);
108extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
109#else
110static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
111{
112}
113#endif /* DFS_UPCALL */
114void cifs_proc_init(void); 108void cifs_proc_init(void);
115void cifs_proc_clean(void); 109void cifs_proc_clean(void);
116 110
diff --git a/fs/exec.c b/fs/exec.c
index 54a0a557b678..b152029f18f6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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
1037mmap_failed:
1038 reset_files_struct(current, files);
1039out: 1025out:
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:
1363out_kfree: 1356out_kfree:
1364 kfree(bprm); 1357 kfree(bprm);
1365 1358
1359out_files:
1360 if (displaced)
1361 reset_files_struct(displaced);
1366out_ret: 1362out_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
58static int locate_fd(struct files_struct *files, 58static 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
110out: 112out:
113 spin_unlock(&files->file_lock);
111 return error; 114 return error;
112} 115}
113 116
114static int dupfd(struct file *file, unsigned int start, int cloexec) 117static 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
245static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) 245static 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
251static void fuse_send_destroy(struct fuse_conn *fc) 250static 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
201static void nfs_umount_begin(struct vfsmount *, int); 201static void nfs_umount_begin(struct super_block *);
202static int nfs_statfs(struct dentry *, struct kstatfs *); 202static int nfs_statfs(struct dentry *, struct kstatfs *);
203static int nfs_show_options(struct seq_file *, struct vfsmount *); 203static int nfs_show_options(struct seq_file *, struct vfsmount *);
204static int nfs_show_stats(struct seq_file *, struct vfsmount *); 204static 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 */
650static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) 650static 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
118struct files_struct *get_files_struct(struct task_struct *); 118struct files_struct *get_files_struct(struct task_struct *);
119void put_files_struct(struct files_struct *fs); 119void put_files_struct(struct files_struct *fs);
120void reset_files_struct(struct task_struct *, struct files_struct *); 120void reset_files_struct(struct files_struct *);
121int unshare_files(struct files_struct **);
121 122
122extern struct kmem_cache *files_cachep; 123extern 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 */
2038extern 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
510EXPORT_SYMBOL(put_files_struct); 510void reset_files_struct(struct files_struct *files)
511
512void 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}
522EXPORT_SYMBOL(reset_files_struct);
523 521
524void exit_files(struct task_struct *tsk) 522void 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
855int 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
875EXPORT_SYMBOL(unshare_files);
876
877static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) 843static 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:
1811bad_unshare_out: 1777bad_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
1787int 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, &copy);
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}