diff --git a/fs/exec.c b/fs/exec.c
index 475543002f13847ad7e2ef42eac0d1313c7a837a..b152029f18f61e68e260d63bab4a9720f2e31ab6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1269,19 +1269,13 @@ int do_execve(char * filename,
 	struct linux_binprm *bprm;
 	struct file *file;
 	unsigned long env_p;
-	struct files_struct *files;
+	struct files_struct *displaced;
 	int retval;
 
-	files = current->files;
-	retval = unshare_files();
+	retval = unshare_files(&displaced);
 	if (retval)
 		goto out_ret;
 
-	if (files == current->files) {
-		put_files_struct(files);
-		files = NULL;
-	}
-
 	retval = -ENOMEM;
 	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
 	if (!bprm)
@@ -1340,8 +1334,8 @@ int do_execve(char * filename,
 		security_bprm_free(bprm);
 		acct_update_integrals(current);
 		kfree(bprm);
-		if (files)
-			put_files_struct(files);
+		if (displaced)
+			put_files_struct(displaced);
 		return retval;
 	}
 
@@ -1363,8 +1357,8 @@ out_kfree:
 	kfree(bprm);
 
 out_files:
-	if (files)
-		reset_files_struct(current, files);
+	if (displaced)
+		reset_files_struct(displaced);
 out_ret:
 	return retval;
 }
diff --git a/include/linux/file.h b/include/linux/file.h
index 653477021e4c545b9f4dcc983587ceb26eb11eac..69baf5a4f0a582cfeb061af5735e4a2d70e701e6 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -117,7 +117,8 @@ struct task_struct;
 
 struct files_struct *get_files_struct(struct task_struct *);
 void put_files_struct(struct files_struct *fs);
-void reset_files_struct(struct task_struct *, struct files_struct *);
+void reset_files_struct(struct files_struct *);
+int unshare_files(struct files_struct **);
 
 extern struct kmem_cache *files_cachep;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ad41d0bbcb4dd437514f0e655f6adfa2869448f9..e057438a05ad56a2acb70ed770e674da41f40a63 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2033,9 +2033,6 @@ static inline ino_t parent_ino(struct dentry *dentry)
 	return res;
 }
 
-/* kernel/fork.c */
-extern int unshare_files(void);
-
 /* Transaction based IO helpers */
 
 /*
diff --git a/kernel/exit.c b/kernel/exit.c
index 3d320003cc03f627e45d4328d53def9985333a77..97f609f574b1843556a6a07fc4c6c50180725b31 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -507,8 +507,9 @@ void put_files_struct(struct files_struct *files)
 	}
 }
 
-void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
+void reset_files_struct(struct files_struct *files)
 {
+	struct task_struct *tsk = current;
 	struct files_struct *old;
 
 	old = tsk->files;
diff --git a/kernel/fork.c b/kernel/fork.c
index 2fc11f2e2b21a7c5d19d347774de930d9e4bc0ee..efb618fc8ffe4724aafa4d14ecb324a12df1ddea 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -840,36 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
 	return 0;
 }
 
-/*
- *	Helper to unshare the files of the current task.
- *	We don't want to expose copy_files internals to
- *	the exec layer of the kernel.
- */
-
-int unshare_files(void)
-{
-	struct files_struct *files  = current->files;
-	struct files_struct *newf;
-	int error = 0;
-
-	BUG_ON(!files);
-
-	/* This can race but the race causes us to copy when we don't
-	   need to and drop the copy */
-	if(atomic_read(&files->count) == 1)
-	{
-		atomic_inc(&files->count);
-		return 0;
-	}
-	newf = dup_fd(files, &error);
-	if (newf) {
-		task_lock(current);
-		current->files = newf;
-		task_unlock(current);
-	}
-	return error;
-}
-
 static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
 {
 	struct sighand_struct *sig;
@@ -1807,3 +1777,27 @@ bad_unshare_cleanup_thread:
 bad_unshare_out:
 	return err;
 }
+
+/*
+ *	Helper to unshare the files of the current task.
+ *	We don't want to expose copy_files internals to
+ *	the exec layer of the kernel.
+ */
+
+int unshare_files(struct files_struct **displaced)
+{
+	struct task_struct *task = current;
+	struct files_struct *copy;
+	int error;
+
+	error = unshare_fd(CLONE_FILES, &copy);
+	if (error || !copy) {
+		*displaced = NULL;
+		return error;
+	}
+	*displaced = task->files;
+	task_lock(task);
+	task->files = copy;
+	task_unlock(task);
+	return 0;
+}