diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/internal.h | 11 | ||||
-rw-r--r-- | fs/namespace.c | 66 | ||||
-rw-r--r-- | fs/pipe.c | 3 | ||||
-rw-r--r-- | fs/pnode.c | 4 | ||||
-rw-r--r-- | fs/pnode.h | 1 | ||||
-rw-r--r-- | fs/proc/base.c | 4 | ||||
-rw-r--r-- | fs/seq_file.c | 16 | ||||
-rw-r--r-- | fs/super.c | 1 |
8 files changed, 63 insertions, 43 deletions
diff --git a/fs/internal.h b/fs/internal.h index 392e8ccd6fc4..80aa9a023372 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -43,3 +43,14 @@ extern void __init chrdev_init(void); | |||
43 | * namespace.c | 43 | * namespace.c |
44 | */ | 44 | */ |
45 | extern int copy_mount_options(const void __user *, unsigned long *); | 45 | extern int copy_mount_options(const void __user *, unsigned long *); |
46 | |||
47 | extern void free_vfsmnt(struct vfsmount *); | ||
48 | extern struct vfsmount *alloc_vfsmnt(const char *); | ||
49 | extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); | ||
50 | extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, | ||
51 | struct vfsmount *); | ||
52 | extern void release_mounts(struct list_head *); | ||
53 | extern void umount_tree(struct vfsmount *, int, struct list_head *); | ||
54 | extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); | ||
55 | |||
56 | extern void __init mnt_init(void); | ||
diff --git a/fs/namespace.c b/fs/namespace.c index 678f7ce060f2..1bf302d0478b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1091,20 +1091,20 @@ Enomem: | |||
1091 | struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry) | 1091 | struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry) |
1092 | { | 1092 | { |
1093 | struct vfsmount *tree; | 1093 | struct vfsmount *tree; |
1094 | down_read(&namespace_sem); | 1094 | down_write(&namespace_sem); |
1095 | tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE); | 1095 | tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE); |
1096 | up_read(&namespace_sem); | 1096 | up_write(&namespace_sem); |
1097 | return tree; | 1097 | return tree; |
1098 | } | 1098 | } |
1099 | 1099 | ||
1100 | void drop_collected_mounts(struct vfsmount *mnt) | 1100 | void drop_collected_mounts(struct vfsmount *mnt) |
1101 | { | 1101 | { |
1102 | LIST_HEAD(umount_list); | 1102 | LIST_HEAD(umount_list); |
1103 | down_read(&namespace_sem); | 1103 | down_write(&namespace_sem); |
1104 | spin_lock(&vfsmount_lock); | 1104 | spin_lock(&vfsmount_lock); |
1105 | umount_tree(mnt, 0, &umount_list); | 1105 | umount_tree(mnt, 0, &umount_list); |
1106 | spin_unlock(&vfsmount_lock); | 1106 | spin_unlock(&vfsmount_lock); |
1107 | up_read(&namespace_sem); | 1107 | up_write(&namespace_sem); |
1108 | release_mounts(&umount_list); | 1108 | release_mounts(&umount_list); |
1109 | } | 1109 | } |
1110 | 1110 | ||
@@ -1205,32 +1205,32 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
1205 | return 0; | 1205 | return 0; |
1206 | } | 1206 | } |
1207 | 1207 | ||
1208 | static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) | 1208 | static int graft_tree(struct vfsmount *mnt, struct path *path) |
1209 | { | 1209 | { |
1210 | int err; | 1210 | int err; |
1211 | if (mnt->mnt_sb->s_flags & MS_NOUSER) | 1211 | if (mnt->mnt_sb->s_flags & MS_NOUSER) |
1212 | return -EINVAL; | 1212 | return -EINVAL; |
1213 | 1213 | ||
1214 | if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != | 1214 | if (S_ISDIR(path->dentry->d_inode->i_mode) != |
1215 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) | 1215 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) |
1216 | return -ENOTDIR; | 1216 | return -ENOTDIR; |
1217 | 1217 | ||
1218 | err = -ENOENT; | 1218 | err = -ENOENT; |
1219 | mutex_lock(&nd->path.dentry->d_inode->i_mutex); | 1219 | mutex_lock(&path->dentry->d_inode->i_mutex); |
1220 | if (IS_DEADDIR(nd->path.dentry->d_inode)) | 1220 | if (IS_DEADDIR(path->dentry->d_inode)) |
1221 | goto out_unlock; | 1221 | goto out_unlock; |
1222 | 1222 | ||
1223 | err = security_sb_check_sb(mnt, nd); | 1223 | err = security_sb_check_sb(mnt, path); |
1224 | if (err) | 1224 | if (err) |
1225 | goto out_unlock; | 1225 | goto out_unlock; |
1226 | 1226 | ||
1227 | err = -ENOENT; | 1227 | err = -ENOENT; |
1228 | if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) | 1228 | if (IS_ROOT(path->dentry) || !d_unhashed(path->dentry)) |
1229 | err = attach_recursive_mnt(mnt, &nd->path, NULL); | 1229 | err = attach_recursive_mnt(mnt, path, NULL); |
1230 | out_unlock: | 1230 | out_unlock: |
1231 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); | 1231 | mutex_unlock(&path->dentry->d_inode->i_mutex); |
1232 | if (!err) | 1232 | if (!err) |
1233 | security_sb_post_addmount(mnt, nd); | 1233 | security_sb_post_addmount(mnt, path); |
1234 | return err; | 1234 | return err; |
1235 | } | 1235 | } |
1236 | 1236 | ||
@@ -1294,7 +1294,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, | |||
1294 | if (!mnt) | 1294 | if (!mnt) |
1295 | goto out; | 1295 | goto out; |
1296 | 1296 | ||
1297 | err = graft_tree(mnt, nd); | 1297 | err = graft_tree(mnt, &nd->path); |
1298 | if (err) { | 1298 | if (err) { |
1299 | LIST_HEAD(umount_list); | 1299 | LIST_HEAD(umount_list); |
1300 | spin_lock(&vfsmount_lock); | 1300 | spin_lock(&vfsmount_lock); |
@@ -1501,7 +1501,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
1501 | goto unlock; | 1501 | goto unlock; |
1502 | 1502 | ||
1503 | newmnt->mnt_flags = mnt_flags; | 1503 | newmnt->mnt_flags = mnt_flags; |
1504 | if ((err = graft_tree(newmnt, nd))) | 1504 | if ((err = graft_tree(newmnt, &nd->path))) |
1505 | goto unlock; | 1505 | goto unlock; |
1506 | 1506 | ||
1507 | if (fslist) /* add to the specified expiration list */ | 1507 | if (fslist) /* add to the specified expiration list */ |
@@ -1746,7 +1746,8 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1746 | if (retval) | 1746 | if (retval) |
1747 | return retval; | 1747 | return retval; |
1748 | 1748 | ||
1749 | retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page); | 1749 | retval = security_sb_mount(dev_name, &nd.path, |
1750 | type_page, flags, data_page); | ||
1750 | if (retval) | 1751 | if (retval) |
1751 | goto dput_out; | 1752 | goto dput_out; |
1752 | 1753 | ||
@@ -1986,15 +1987,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
1986 | const char __user * put_old) | 1987 | const char __user * put_old) |
1987 | { | 1988 | { |
1988 | struct vfsmount *tmp; | 1989 | struct vfsmount *tmp; |
1989 | struct nameidata new_nd, old_nd, user_nd; | 1990 | struct nameidata new_nd, old_nd; |
1990 | struct path parent_path, root_parent; | 1991 | struct path parent_path, root_parent, root; |
1991 | int error; | 1992 | int error; |
1992 | 1993 | ||
1993 | if (!capable(CAP_SYS_ADMIN)) | 1994 | if (!capable(CAP_SYS_ADMIN)) |
1994 | return -EPERM; | 1995 | return -EPERM; |
1995 | 1996 | ||
1996 | lock_kernel(); | ||
1997 | |||
1998 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 1997 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, |
1999 | &new_nd); | 1998 | &new_nd); |
2000 | if (error) | 1999 | if (error) |
@@ -2007,14 +2006,14 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2007 | if (error) | 2006 | if (error) |
2008 | goto out1; | 2007 | goto out1; |
2009 | 2008 | ||
2010 | error = security_sb_pivotroot(&old_nd, &new_nd); | 2009 | error = security_sb_pivotroot(&old_nd.path, &new_nd.path); |
2011 | if (error) { | 2010 | if (error) { |
2012 | path_put(&old_nd.path); | 2011 | path_put(&old_nd.path); |
2013 | goto out1; | 2012 | goto out1; |
2014 | } | 2013 | } |
2015 | 2014 | ||
2016 | read_lock(¤t->fs->lock); | 2015 | read_lock(¤t->fs->lock); |
2017 | user_nd.path = current->fs->root; | 2016 | root = current->fs->root; |
2018 | path_get(¤t->fs->root); | 2017 | path_get(¤t->fs->root); |
2019 | read_unlock(¤t->fs->lock); | 2018 | read_unlock(¤t->fs->lock); |
2020 | down_write(&namespace_sem); | 2019 | down_write(&namespace_sem); |
@@ -2022,9 +2021,9 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2022 | error = -EINVAL; | 2021 | error = -EINVAL; |
2023 | if (IS_MNT_SHARED(old_nd.path.mnt) || | 2022 | if (IS_MNT_SHARED(old_nd.path.mnt) || |
2024 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || | 2023 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || |
2025 | IS_MNT_SHARED(user_nd.path.mnt->mnt_parent)) | 2024 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
2026 | goto out2; | 2025 | goto out2; |
2027 | if (!check_mnt(user_nd.path.mnt)) | 2026 | if (!check_mnt(root.mnt)) |
2028 | goto out2; | 2027 | goto out2; |
2029 | error = -ENOENT; | 2028 | error = -ENOENT; |
2030 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) | 2029 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) |
@@ -2034,13 +2033,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2034 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) | 2033 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) |
2035 | goto out2; | 2034 | goto out2; |
2036 | error = -EBUSY; | 2035 | error = -EBUSY; |
2037 | if (new_nd.path.mnt == user_nd.path.mnt || | 2036 | if (new_nd.path.mnt == root.mnt || |
2038 | old_nd.path.mnt == user_nd.path.mnt) | 2037 | old_nd.path.mnt == root.mnt) |
2039 | goto out2; /* loop, on the same file system */ | 2038 | goto out2; /* loop, on the same file system */ |
2040 | error = -EINVAL; | 2039 | error = -EINVAL; |
2041 | if (user_nd.path.mnt->mnt_root != user_nd.path.dentry) | 2040 | if (root.mnt->mnt_root != root.dentry) |
2042 | goto out2; /* not a mountpoint */ | 2041 | goto out2; /* not a mountpoint */ |
2043 | if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt) | 2042 | if (root.mnt->mnt_parent == root.mnt) |
2044 | goto out2; /* not attached */ | 2043 | goto out2; /* not attached */ |
2045 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) | 2044 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) |
2046 | goto out2; /* not a mountpoint */ | 2045 | goto out2; /* not a mountpoint */ |
@@ -2062,27 +2061,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2062 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 2061 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) |
2063 | goto out3; | 2062 | goto out3; |
2064 | detach_mnt(new_nd.path.mnt, &parent_path); | 2063 | detach_mnt(new_nd.path.mnt, &parent_path); |
2065 | detach_mnt(user_nd.path.mnt, &root_parent); | 2064 | detach_mnt(root.mnt, &root_parent); |
2066 | /* mount old root on put_old */ | 2065 | /* mount old root on put_old */ |
2067 | attach_mnt(user_nd.path.mnt, &old_nd.path); | 2066 | attach_mnt(root.mnt, &old_nd.path); |
2068 | /* mount new_root on / */ | 2067 | /* mount new_root on / */ |
2069 | attach_mnt(new_nd.path.mnt, &root_parent); | 2068 | attach_mnt(new_nd.path.mnt, &root_parent); |
2070 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2069 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2071 | spin_unlock(&vfsmount_lock); | 2070 | spin_unlock(&vfsmount_lock); |
2072 | chroot_fs_refs(&user_nd.path, &new_nd.path); | 2071 | chroot_fs_refs(&root, &new_nd.path); |
2073 | security_sb_post_pivotroot(&user_nd, &new_nd); | 2072 | security_sb_post_pivotroot(&root, &new_nd.path); |
2074 | error = 0; | 2073 | error = 0; |
2075 | path_put(&root_parent); | 2074 | path_put(&root_parent); |
2076 | path_put(&parent_path); | 2075 | path_put(&parent_path); |
2077 | out2: | 2076 | out2: |
2078 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 2077 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); |
2079 | up_write(&namespace_sem); | 2078 | up_write(&namespace_sem); |
2080 | path_put(&user_nd.path); | 2079 | path_put(&root); |
2081 | path_put(&old_nd.path); | 2080 | path_put(&old_nd.path); |
2082 | out1: | 2081 | out1: |
2083 | path_put(&new_nd.path); | 2082 | path_put(&new_nd.path); |
2084 | out0: | 2083 | out0: |
2085 | unlock_kernel(); | ||
2086 | return error; | 2084 | return error; |
2087 | out3: | 2085 | out3: |
2088 | spin_unlock(&vfsmount_lock); | 2086 | spin_unlock(&vfsmount_lock); |
@@ -988,7 +988,10 @@ struct file *create_write_pipe(void) | |||
988 | return f; | 988 | return f; |
989 | 989 | ||
990 | err_dentry: | 990 | err_dentry: |
991 | free_pipe_info(inode); | ||
991 | dput(dentry); | 992 | dput(dentry); |
993 | return ERR_PTR(err); | ||
994 | |||
992 | err_inode: | 995 | err_inode: |
993 | free_pipe_info(inode); | 996 | free_pipe_info(inode); |
994 | iput(inode); | 997 | iput(inode); |
diff --git a/fs/pnode.c b/fs/pnode.c index 1d8f5447f3f7..f968e35d9785 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/mnt_namespace.h> | 9 | #include <linux/mnt_namespace.h> |
10 | #include <linux/mount.h> | 10 | #include <linux/mount.h> |
11 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
12 | #include "internal.h" | ||
12 | #include "pnode.h" | 13 | #include "pnode.h" |
13 | 14 | ||
14 | /* return the next shared peer mount of @p */ | 15 | /* return the next shared peer mount of @p */ |
@@ -211,8 +212,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, | |||
211 | out: | 212 | out: |
212 | spin_lock(&vfsmount_lock); | 213 | spin_lock(&vfsmount_lock); |
213 | while (!list_empty(&tmp_list)) { | 214 | while (!list_empty(&tmp_list)) { |
214 | child = list_entry(tmp_list.next, struct vfsmount, mnt_hash); | 215 | child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); |
215 | list_del_init(&child->mnt_hash); | ||
216 | umount_tree(child, 0, &umount_list); | 216 | umount_tree(child, 0, &umount_list); |
217 | } | 217 | } |
218 | spin_unlock(&vfsmount_lock); | 218 | spin_unlock(&vfsmount_lock); |
diff --git a/fs/pnode.h b/fs/pnode.h index f249be2fee7a..973c3f825e7d 100644 --- a/fs/pnode.h +++ b/fs/pnode.h | |||
@@ -35,4 +35,5 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, | |||
35 | struct list_head *); | 35 | struct list_head *); |
36 | int propagate_umount(struct list_head *); | 36 | int propagate_umount(struct list_head *); |
37 | int propagate_mount_busy(struct vfsmount *, int); | 37 | int propagate_mount_busy(struct vfsmount *, int); |
38 | void mnt_release_group_id(struct vfsmount *); | ||
38 | #endif /* _LINUX_PNODE_H */ | 39 | #endif /* _LINUX_PNODE_H */ |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 81d7d145292a..7313c62e3e9d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1626,7 +1626,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, | |||
1626 | unsigned int fd, ino; | 1626 | unsigned int fd, ino; |
1627 | int retval; | 1627 | int retval; |
1628 | struct files_struct * files; | 1628 | struct files_struct * files; |
1629 | struct fdtable *fdt; | ||
1630 | 1629 | ||
1631 | retval = -ENOENT; | 1630 | retval = -ENOENT; |
1632 | if (!p) | 1631 | if (!p) |
@@ -1649,9 +1648,8 @@ static int proc_readfd_common(struct file * filp, void * dirent, | |||
1649 | if (!files) | 1648 | if (!files) |
1650 | goto out; | 1649 | goto out; |
1651 | rcu_read_lock(); | 1650 | rcu_read_lock(); |
1652 | fdt = files_fdtable(files); | ||
1653 | for (fd = filp->f_pos-2; | 1651 | for (fd = filp->f_pos-2; |
1654 | fd < fdt->max_fds; | 1652 | fd < files_fdtable(files)->max_fds; |
1655 | fd++, filp->f_pos++) { | 1653 | fd++, filp->f_pos++) { |
1656 | char name[PROC_NUMBUF]; | 1654 | char name[PROC_NUMBUF]; |
1657 | int len; | 1655 | int len; |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 9943408b315e..cdfd996ca6ef 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * into the buffer. In case of error ->start() and ->next() return | 25 | * into the buffer. In case of error ->start() and ->next() return |
26 | * ERR_PTR(error). In the end of sequence they return %NULL. ->show() | 26 | * ERR_PTR(error). In the end of sequence they return %NULL. ->show() |
27 | * returns 0 in case of success and negative number in case of error. | 27 | * returns 0 in case of success and negative number in case of error. |
28 | * Returning SEQ_SKIP means "discard this element and move on". | ||
28 | */ | 29 | */ |
29 | int seq_open(struct file *file, const struct seq_operations *op) | 30 | int seq_open(struct file *file, const struct seq_operations *op) |
30 | { | 31 | { |
@@ -114,8 +115,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
114 | if (!p || IS_ERR(p)) | 115 | if (!p || IS_ERR(p)) |
115 | break; | 116 | break; |
116 | err = m->op->show(m, p); | 117 | err = m->op->show(m, p); |
117 | if (err) | 118 | if (err < 0) |
118 | break; | 119 | break; |
120 | if (unlikely(err)) | ||
121 | m->count = 0; | ||
119 | if (m->count < m->size) | 122 | if (m->count < m->size) |
120 | goto Fill; | 123 | goto Fill; |
121 | m->op->stop(m, p); | 124 | m->op->stop(m, p); |
@@ -140,9 +143,10 @@ Fill: | |||
140 | break; | 143 | break; |
141 | } | 144 | } |
142 | err = m->op->show(m, p); | 145 | err = m->op->show(m, p); |
143 | if (err || m->count == m->size) { | 146 | if (m->count == m->size || err) { |
144 | m->count = offs; | 147 | m->count = offs; |
145 | break; | 148 | if (likely(err <= 0)) |
149 | break; | ||
146 | } | 150 | } |
147 | pos = next; | 151 | pos = next; |
148 | } | 152 | } |
@@ -199,8 +203,12 @@ static int traverse(struct seq_file *m, loff_t offset) | |||
199 | if (IS_ERR(p)) | 203 | if (IS_ERR(p)) |
200 | break; | 204 | break; |
201 | error = m->op->show(m, p); | 205 | error = m->op->show(m, p); |
202 | if (error) | 206 | if (error < 0) |
203 | break; | 207 | break; |
208 | if (unlikely(error)) { | ||
209 | error = 0; | ||
210 | m->count = 0; | ||
211 | } | ||
204 | if (m->count == m->size) | 212 | if (m->count == m->size) |
205 | goto Eoverflow; | 213 | goto Eoverflow; |
206 | if (pos + m->count > offset) { | 214 | if (pos + m->count > offset) { |
diff --git a/fs/super.c b/fs/super.c index 1f8f05ede437..4798350b2bc9 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/mutex.h> | 39 | #include <linux/mutex.h> |
40 | #include <linux/file.h> | 40 | #include <linux/file.h> |
41 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
42 | #include "internal.h" | ||
42 | 43 | ||
43 | 44 | ||
44 | LIST_HEAD(super_blocks); | 45 | LIST_HEAD(super_blocks); |