mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-21 14:11:20 +00:00
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.
This commit is contained in:
commit
bc84e0a160
16 changed files with 95 additions and 172 deletions
|
@ -224,12 +224,11 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
v9fs_umount_begin(struct vfsmount *vfsmnt, int flags)
|
v9fs_umount_begin(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info;
|
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
||||||
|
|
||||||
if (flags & MNT_FORCE)
|
v9fs_session_cancel(v9ses);
|
||||||
v9fs_session_cancel(v9ses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct super_operations v9fs_super_ops = {
|
static const struct super_operations v9fs_super_ops = {
|
||||||
|
|
|
@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
||||||
unsigned long interp_load_addr = 0;
|
unsigned long interp_load_addr = 0;
|
||||||
unsigned long start_code, end_code, start_data, end_data;
|
unsigned long start_code, end_code, start_data, end_data;
|
||||||
unsigned long reloc_func_desc = 0;
|
unsigned long reloc_func_desc = 0;
|
||||||
struct files_struct *files;
|
|
||||||
int executable_stack = EXSTACK_DEFAULT;
|
int executable_stack = EXSTACK_DEFAULT;
|
||||||
unsigned long def_flags = 0;
|
unsigned long def_flags = 0;
|
||||||
struct {
|
struct {
|
||||||
|
@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
||||||
goto out_free_ph;
|
goto out_free_ph;
|
||||||
}
|
}
|
||||||
|
|
||||||
files = current->files; /* Refcounted so ok */
|
|
||||||
retval = unshare_files();
|
|
||||||
if (retval < 0)
|
|
||||||
goto out_free_ph;
|
|
||||||
if (files == current->files) {
|
|
||||||
put_files_struct(files);
|
|
||||||
files = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* exec will make our files private anyway, but for the a.out
|
|
||||||
loader stuff we need to do it earlier */
|
|
||||||
retval = get_unused_fd();
|
retval = get_unused_fd();
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto out_free_fh;
|
goto out_free_ph;
|
||||||
get_file(bprm->file);
|
get_file(bprm->file);
|
||||||
fd_install(elf_exec_fileno = retval, bprm->file);
|
fd_install(elf_exec_fileno = retval, bprm->file);
|
||||||
|
|
||||||
|
@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out_free_dentry;
|
goto out_free_dentry;
|
||||||
|
|
||||||
/* Discard our unneeded old files struct */
|
|
||||||
if (files) {
|
|
||||||
put_files_struct(files);
|
|
||||||
files = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OK, This is the point of no return */
|
/* OK, This is the point of no return */
|
||||||
current->flags &= ~PF_FORKNOEXEC;
|
current->flags &= ~PF_FORKNOEXEC;
|
||||||
current->mm->def_flags = def_flags;
|
current->mm->def_flags = def_flags;
|
||||||
|
@ -1016,9 +998,6 @@ out_free_interp:
|
||||||
kfree(elf_interpreter);
|
kfree(elf_interpreter);
|
||||||
out_free_file:
|
out_free_file:
|
||||||
sys_close(elf_exec_fileno);
|
sys_close(elf_exec_fileno);
|
||||||
out_free_fh:
|
|
||||||
if (files)
|
|
||||||
reset_files_struct(current, files);
|
|
||||||
out_free_ph:
|
out_free_ph:
|
||||||
kfree(elf_phdata);
|
kfree(elf_phdata);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
||||||
char *iname_addr = iname;
|
char *iname_addr = iname;
|
||||||
int retval;
|
int retval;
|
||||||
int fd_binary = -1;
|
int fd_binary = -1;
|
||||||
struct files_struct *files = NULL;
|
|
||||||
|
|
||||||
retval = -ENOEXEC;
|
retval = -ENOEXEC;
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
|
@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
||||||
|
|
||||||
if (fmt->flags & MISC_FMT_OPEN_BINARY) {
|
if (fmt->flags & MISC_FMT_OPEN_BINARY) {
|
||||||
|
|
||||||
files = current->files;
|
|
||||||
retval = unshare_files();
|
|
||||||
if (retval < 0)
|
|
||||||
goto _ret;
|
|
||||||
if (files == current->files) {
|
|
||||||
put_files_struct(files);
|
|
||||||
files = NULL;
|
|
||||||
}
|
|
||||||
/* if the binary should be opened on behalf of the
|
/* if the binary should be opened on behalf of the
|
||||||
* interpreter than keep it open and assign descriptor
|
* interpreter than keep it open and assign descriptor
|
||||||
* to it */
|
* to it */
|
||||||
fd_binary = get_unused_fd();
|
fd_binary = get_unused_fd();
|
||||||
if (fd_binary < 0) {
|
if (fd_binary < 0) {
|
||||||
retval = fd_binary;
|
retval = fd_binary;
|
||||||
goto _unshare;
|
goto _ret;
|
||||||
}
|
}
|
||||||
fd_install(fd_binary, bprm->file);
|
fd_install(fd_binary, bprm->file);
|
||||||
|
|
||||||
|
@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto _error;
|
goto _error;
|
||||||
|
|
||||||
if (files) {
|
|
||||||
put_files_struct(files);
|
|
||||||
files = NULL;
|
|
||||||
}
|
|
||||||
_ret:
|
_ret:
|
||||||
return retval;
|
return retval;
|
||||||
_error:
|
_error:
|
||||||
|
@ -216,9 +203,6 @@ _error:
|
||||||
sys_close(fd_binary);
|
sys_close(fd_binary);
|
||||||
bprm->interp_flags = 0;
|
bprm->interp_flags = 0;
|
||||||
bprm->interp_data = 0;
|
bprm->interp_data = 0;
|
||||||
_unshare:
|
|
||||||
if (files)
|
|
||||||
reset_files_struct(current, files);
|
|
||||||
goto _ret;
|
goto _ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
|
||||||
unsigned long som_entry;
|
unsigned long som_entry;
|
||||||
struct som_hdr *som_ex;
|
struct som_hdr *som_ex;
|
||||||
struct som_exec_auxhdr *hpuxhdr;
|
struct som_exec_auxhdr *hpuxhdr;
|
||||||
struct files_struct *files;
|
|
||||||
|
|
||||||
/* Get the exec-header */
|
/* Get the exec-header */
|
||||||
som_ex = (struct som_hdr *) bprm->buf;
|
som_ex = (struct som_hdr *) bprm->buf;
|
||||||
|
@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
files = current->files; /* Refcounted so ok */
|
|
||||||
retval = unshare_files();
|
|
||||||
if (retval < 0)
|
|
||||||
goto out_free;
|
|
||||||
if (files == current->files) {
|
|
||||||
put_files_struct(files);
|
|
||||||
files = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = get_unused_fd();
|
retval = get_unused_fd();
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
|
@ -25,14 +25,26 @@
|
||||||
|
|
||||||
static LIST_HEAD(cifs_dfs_automount_list);
|
static LIST_HEAD(cifs_dfs_automount_list);
|
||||||
|
|
||||||
/*
|
static void cifs_dfs_expire_automounts(struct work_struct *work);
|
||||||
* DFS functions
|
static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
|
||||||
*/
|
cifs_dfs_expire_automounts);
|
||||||
|
static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
|
||||||
|
|
||||||
void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
|
static void cifs_dfs_expire_automounts(struct work_struct *work)
|
||||||
{
|
{
|
||||||
mark_mounts_for_expiry(&cifs_dfs_automount_list);
|
struct list_head *list = &cifs_dfs_automount_list;
|
||||||
mark_mounts_for_expiry(&cifs_dfs_automount_list);
|
|
||||||
|
mark_mounts_for_expiry(list);
|
||||||
|
if (!list_empty(list))
|
||||||
|
schedule_delayed_work(&cifs_dfs_automount_task,
|
||||||
|
cifs_dfs_mountpoint_expiry_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cifs_dfs_release_automount_timer(void)
|
||||||
|
{
|
||||||
|
BUG_ON(!list_empty(&cifs_dfs_automount_list));
|
||||||
|
cancel_delayed_work(&cifs_dfs_automount_task);
|
||||||
|
flush_scheduled_work();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,10 +273,11 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
|
||||||
err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist);
|
err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case 0:
|
case 0:
|
||||||
dput(nd->path.dentry);
|
path_put(&nd->path);
|
||||||
mntput(nd->path.mnt);
|
|
||||||
nd->path.mnt = newmnt;
|
nd->path.mnt = newmnt;
|
||||||
nd->path.dentry = dget(newmnt->mnt_root);
|
nd->path.dentry = dget(newmnt->mnt_root);
|
||||||
|
schedule_delayed_work(&cifs_dfs_automount_task,
|
||||||
|
cifs_dfs_mountpoint_expiry_timeout);
|
||||||
break;
|
break;
|
||||||
case -EBUSY:
|
case -EBUSY:
|
||||||
/* someone else made a mount here whilst we were busy */
|
/* someone else made a mount here whilst we were busy */
|
||||||
|
|
|
@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
|
static void cifs_umount_begin(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||||
struct cifsTconInfo *tcon;
|
struct cifsTconInfo *tcon;
|
||||||
|
|
||||||
dfs_shrink_umount_helper(vfsmnt);
|
|
||||||
|
|
||||||
if (!(flags & MNT_FORCE))
|
|
||||||
return;
|
|
||||||
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
|
|
||||||
if (cifs_sb == NULL)
|
if (cifs_sb == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1100,6 +1095,7 @@ exit_cifs(void)
|
||||||
cFYI(DBG2, ("exit_cifs"));
|
cFYI(DBG2, ("exit_cifs"));
|
||||||
cifs_proc_clean();
|
cifs_proc_clean();
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
cifs_dfs_release_automount_timer();
|
||||||
unregister_key_type(&key_type_dns_resolver);
|
unregister_key_type(&key_type_dns_resolver);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
|
|
|
@ -104,13 +104,7 @@ extern int mode_to_acl(struct inode *inode, const char *path, __u64);
|
||||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||||
const char *);
|
const char *);
|
||||||
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
|
extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
extern void cifs_dfs_release_automount_timer(void);
|
||||||
extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt);
|
|
||||||
#else
|
|
||||||
static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif /* DFS_UPCALL */
|
|
||||||
void cifs_proc_init(void);
|
void cifs_proc_init(void);
|
||||||
void cifs_proc_clean(void);
|
void cifs_proc_clean(void);
|
||||||
|
|
||||||
|
|
28
fs/exec.c
28
fs/exec.c
|
@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
|
||||||
{
|
{
|
||||||
char * name;
|
char * name;
|
||||||
int i, ch, retval;
|
int i, ch, retval;
|
||||||
struct files_struct *files;
|
|
||||||
char tcomm[sizeof(current->comm)];
|
char tcomm[sizeof(current->comm)];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm)
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure we have private file handles. Ask the
|
|
||||||
* fork helper to do the work for us and the exit
|
|
||||||
* helper to do the cleanup of the old one.
|
|
||||||
*/
|
|
||||||
files = current->files; /* refcounted so safe to hold */
|
|
||||||
retval = unshare_files();
|
|
||||||
if (retval)
|
|
||||||
goto out;
|
|
||||||
/*
|
/*
|
||||||
* Release all of the old mmap stuff
|
* Release all of the old mmap stuff
|
||||||
*/
|
*/
|
||||||
retval = exec_mmap(bprm->mm);
|
retval = exec_mmap(bprm->mm);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto mmap_failed;
|
goto out;
|
||||||
|
|
||||||
bprm->mm = NULL; /* We're using it now */
|
bprm->mm = NULL; /* We're using it now */
|
||||||
|
|
||||||
/* This is the point of no return */
|
/* This is the point of no return */
|
||||||
put_files_struct(files);
|
|
||||||
|
|
||||||
current->sas_ss_sp = current->sas_ss_size = 0;
|
current->sas_ss_sp = current->sas_ss_size = 0;
|
||||||
|
|
||||||
if (current->euid == current->uid && current->egid == current->gid)
|
if (current->euid == current->uid && current->egid == current->gid)
|
||||||
|
@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mmap_failed:
|
|
||||||
reset_files_struct(current, files);
|
|
||||||
out:
|
out:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -1283,12 +1269,17 @@ int do_execve(char * filename,
|
||||||
struct linux_binprm *bprm;
|
struct linux_binprm *bprm;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
unsigned long env_p;
|
unsigned long env_p;
|
||||||
|
struct files_struct *displaced;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
retval = unshare_files(&displaced);
|
||||||
|
if (retval)
|
||||||
|
goto out_ret;
|
||||||
|
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
|
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
|
||||||
if (!bprm)
|
if (!bprm)
|
||||||
goto out_ret;
|
goto out_files;
|
||||||
|
|
||||||
file = open_exec(filename);
|
file = open_exec(filename);
|
||||||
retval = PTR_ERR(file);
|
retval = PTR_ERR(file);
|
||||||
|
@ -1343,6 +1334,8 @@ int do_execve(char * filename,
|
||||||
security_bprm_free(bprm);
|
security_bprm_free(bprm);
|
||||||
acct_update_integrals(current);
|
acct_update_integrals(current);
|
||||||
kfree(bprm);
|
kfree(bprm);
|
||||||
|
if (displaced)
|
||||||
|
put_files_struct(displaced);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1363,6 +1356,9 @@ out_file:
|
||||||
out_kfree:
|
out_kfree:
|
||||||
kfree(bprm);
|
kfree(bprm);
|
||||||
|
|
||||||
|
out_files:
|
||||||
|
if (displaced)
|
||||||
|
reset_files_struct(displaced);
|
||||||
out_ret:
|
out_ret:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
40
fs/fcntl.c
40
fs/fcntl.c
|
@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd)
|
||||||
* file_lock held for write.
|
* file_lock held for write.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int locate_fd(struct files_struct *files,
|
static int locate_fd(unsigned int orig_start, int cloexec)
|
||||||
struct file *file, unsigned int orig_start)
|
|
||||||
{
|
{
|
||||||
|
struct files_struct *files = current->files;
|
||||||
unsigned int newfd;
|
unsigned int newfd;
|
||||||
unsigned int start;
|
unsigned int start;
|
||||||
int error;
|
int error;
|
||||||
struct fdtable *fdt;
|
struct fdtable *fdt;
|
||||||
|
|
||||||
|
spin_lock(&files->file_lock);
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -97,42 +99,28 @@ repeat:
|
||||||
if (error)
|
if (error)
|
||||||
goto repeat;
|
goto repeat;
|
||||||
|
|
||||||
/*
|
|
||||||
* We reacquired files_lock, so we are safe as long as
|
|
||||||
* we reacquire the fdtable pointer and use it while holding
|
|
||||||
* the lock, no one can free it during that time.
|
|
||||||
*/
|
|
||||||
if (start <= files->next_fd)
|
if (start <= files->next_fd)
|
||||||
files->next_fd = newfd + 1;
|
files->next_fd = newfd + 1;
|
||||||
|
|
||||||
|
FD_SET(newfd, fdt->open_fds);
|
||||||
|
if (cloexec)
|
||||||
|
FD_SET(newfd, fdt->close_on_exec);
|
||||||
|
else
|
||||||
|
FD_CLR(newfd, fdt->close_on_exec);
|
||||||
error = newfd;
|
error = newfd;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
spin_unlock(&files->file_lock);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dupfd(struct file *file, unsigned int start, int cloexec)
|
static int dupfd(struct file *file, unsigned int start, int cloexec)
|
||||||
{
|
{
|
||||||
struct files_struct * files = current->files;
|
int fd = locate_fd(start, cloexec);
|
||||||
struct fdtable *fdt;
|
if (fd >= 0)
|
||||||
int fd;
|
|
||||||
|
|
||||||
spin_lock(&files->file_lock);
|
|
||||||
fd = locate_fd(files, file, start);
|
|
||||||
if (fd >= 0) {
|
|
||||||
/* locate_fd() may have expanded fdtable, load the ptr */
|
|
||||||
fdt = files_fdtable(files);
|
|
||||||
FD_SET(fd, fdt->open_fds);
|
|
||||||
if (cloexec)
|
|
||||||
FD_SET(fd, fdt->close_on_exec);
|
|
||||||
else
|
|
||||||
FD_CLR(fd, fdt->close_on_exec);
|
|
||||||
spin_unlock(&files->file_lock);
|
|
||||||
fd_install(fd, file);
|
fd_install(fd, file);
|
||||||
} else {
|
else
|
||||||
spin_unlock(&files->file_lock);
|
|
||||||
fput(file);
|
fput(file);
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,10 +242,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
|
||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags)
|
static void fuse_umount_begin(struct super_block *sb)
|
||||||
{
|
{
|
||||||
if (flags & MNT_FORCE)
|
fuse_abort_conn(get_fuse_conn_super(sb));
|
||||||
fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fuse_send_destroy(struct fuse_conn *fc)
|
static void fuse_send_destroy(struct fuse_conn *fc)
|
||||||
|
|
|
@ -1061,10 +1061,11 @@ static int do_umount(struct vfsmount *mnt, int flags)
|
||||||
* about for the moment.
|
* about for the moment.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
lock_kernel();
|
if (flags & MNT_FORCE && sb->s_op->umount_begin) {
|
||||||
if (sb->s_op->umount_begin)
|
lock_kernel();
|
||||||
sb->s_op->umount_begin(mnt, flags);
|
sb->s_op->umount_begin(sb);
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No sense to grab the lock for this test, but test itself looks
|
* No sense to grab the lock for this test, but test itself looks
|
||||||
|
|
|
@ -198,7 +198,7 @@ static match_table_t nfs_secflavor_tokens = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void nfs_umount_begin(struct vfsmount *, int);
|
static void nfs_umount_begin(struct super_block *);
|
||||||
static int nfs_statfs(struct dentry *, struct kstatfs *);
|
static int nfs_statfs(struct dentry *, struct kstatfs *);
|
||||||
static int nfs_show_options(struct seq_file *, struct vfsmount *);
|
static int nfs_show_options(struct seq_file *, struct vfsmount *);
|
||||||
static int nfs_show_stats(struct seq_file *, struct vfsmount *);
|
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)
|
||||||
* Begin unmount by attempting to remove all automounted mountpoints we added
|
* Begin unmount by attempting to remove all automounted mountpoints we added
|
||||||
* in response to xdev traversals and referrals
|
* in response to xdev traversals and referrals
|
||||||
*/
|
*/
|
||||||
static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
|
static void nfs_umount_begin(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb);
|
struct nfs_server *server = NFS_SB(sb);
|
||||||
struct rpc_clnt *rpc;
|
struct rpc_clnt *rpc;
|
||||||
|
|
||||||
if (!(flags & MNT_FORCE))
|
|
||||||
return;
|
|
||||||
/* -EIO all pending I/O */
|
/* -EIO all pending I/O */
|
||||||
rpc = server->client_acl;
|
rpc = server->client_acl;
|
||||||
if (!IS_ERR(rpc))
|
if (!IS_ERR(rpc))
|
||||||
|
|
|
@ -117,7 +117,8 @@ struct task_struct;
|
||||||
|
|
||||||
struct files_struct *get_files_struct(struct task_struct *);
|
struct files_struct *get_files_struct(struct task_struct *);
|
||||||
void put_files_struct(struct files_struct *fs);
|
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;
|
extern struct kmem_cache *files_cachep;
|
||||||
|
|
||||||
|
|
|
@ -1309,7 +1309,7 @@ struct super_operations {
|
||||||
int (*statfs) (struct dentry *, struct kstatfs *);
|
int (*statfs) (struct dentry *, struct kstatfs *);
|
||||||
int (*remount_fs) (struct super_block *, int *, char *);
|
int (*remount_fs) (struct super_block *, int *, char *);
|
||||||
void (*clear_inode) (struct inode *);
|
void (*clear_inode) (struct inode *);
|
||||||
void (*umount_begin) (struct vfsmount *, int);
|
void (*umount_begin) (struct super_block *);
|
||||||
|
|
||||||
int (*show_options)(struct seq_file *, struct vfsmount *);
|
int (*show_options)(struct seq_file *, struct vfsmount *);
|
||||||
int (*show_stats)(struct seq_file *, struct vfsmount *);
|
int (*show_stats)(struct seq_file *, struct vfsmount *);
|
||||||
|
@ -2034,9 +2034,6 @@ static inline ino_t parent_ino(struct dentry *dentry)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kernel/fork.c */
|
|
||||||
extern int unshare_files(void);
|
|
||||||
|
|
||||||
/* Transaction based IO helpers */
|
/* Transaction based IO helpers */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -507,10 +507,9 @@ void put_files_struct(struct files_struct *files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(put_files_struct);
|
void reset_files_struct(struct files_struct *files)
|
||||||
|
|
||||||
void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
|
|
||||||
{
|
{
|
||||||
|
struct task_struct *tsk = current;
|
||||||
struct files_struct *old;
|
struct files_struct *old;
|
||||||
|
|
||||||
old = tsk->files;
|
old = tsk->files;
|
||||||
|
@ -519,7 +518,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
|
||||||
task_unlock(tsk);
|
task_unlock(tsk);
|
||||||
put_files_struct(old);
|
put_files_struct(old);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(reset_files_struct);
|
|
||||||
|
|
||||||
void exit_files(struct task_struct *tsk)
|
void exit_files(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
|
|
|
@ -805,12 +805,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: we may be using current for both targets (See exec.c)
|
|
||||||
* This works because we cache current->files (old) as oldf. Don't
|
|
||||||
* break this.
|
|
||||||
*/
|
|
||||||
tsk->files = NULL;
|
|
||||||
newf = dup_fd(oldf, &error);
|
newf = dup_fd(oldf, &error);
|
||||||
if (!newf)
|
if (!newf)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -846,34 +840,6 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
|
||||||
return 0;
|
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;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
rc = copy_files(0, current);
|
|
||||||
if(rc)
|
|
||||||
current->files = files;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(unshare_files);
|
|
||||||
|
|
||||||
static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
|
static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
struct sighand_struct *sig;
|
struct sighand_struct *sig;
|
||||||
|
@ -1811,3 +1777,27 @@ bad_unshare_cleanup_thread:
|
||||||
bad_unshare_out:
|
bad_unshare_out:
|
||||||
return err;
|
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, ©);
|
||||||
|
if (error || !copy) {
|
||||||
|
*displaced = NULL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
*displaced = task->files;
|
||||||
|
task_lock(task);
|
||||||
|
task->files = copy;
|
||||||
|
task_unlock(task);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue