diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/afs/mntpt.c | 2 | ||||
| -rw-r--r-- | fs/block_dev.c | 5 | ||||
| -rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 2 | ||||
| -rw-r--r-- | fs/devpts/inode.c | 16 | ||||
| -rw-r--r-- | fs/dquot.c | 33 | ||||
| -rw-r--r-- | fs/ext3/super.c | 3 | ||||
| -rw-r--r-- | fs/ext4/super.c | 3 | ||||
| -rw-r--r-- | fs/fcntl.c | 140 | ||||
| -rw-r--r-- | fs/file.c | 61 | ||||
| -rw-r--r-- | fs/namei.c | 17 | ||||
| -rw-r--r-- | fs/namespace.c | 16 | ||||
| -rw-r--r-- | fs/nfs/namespace.c | 2 | ||||
| -rw-r--r-- | fs/open.c | 56 | ||||
| -rw-r--r-- | fs/proc/generic.c | 27 | ||||
| -rw-r--r-- | fs/reiserfs/super.c | 16 |
15 files changed, 178 insertions, 221 deletions
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 2f5503902c3..78db4953a80 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -232,7 +232,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | mntget(newmnt); | 234 | mntget(newmnt); |
| 235 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); | 235 | err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts); |
| 236 | switch (err) { | 236 | switch (err) { |
| 237 | case 0: | 237 | case 0: |
| 238 | path_put(&nd->path); | 238 | path_put(&nd->path); |
diff --git a/fs/block_dev.c b/fs/block_dev.c index dcf37cada36..aff54219e04 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -941,8 +941,10 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part) | |||
| 941 | * hooks: /n/, see "layering violations". | 941 | * hooks: /n/, see "layering violations". |
| 942 | */ | 942 | */ |
| 943 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); | 943 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); |
| 944 | if (ret != 0) | 944 | if (ret != 0) { |
| 945 | bdput(bdev); | ||
| 945 | return ret; | 946 | return ret; |
| 947 | } | ||
| 946 | 948 | ||
| 947 | ret = -ENXIO; | 949 | ret = -ENXIO; |
| 948 | file->f_mapping = bdev->bd_inode->i_mapping; | 950 | file->f_mapping = bdev->bd_inode->i_mapping; |
| @@ -1234,6 +1236,7 @@ fail: | |||
| 1234 | bdev = ERR_PTR(error); | 1236 | bdev = ERR_PTR(error); |
| 1235 | goto out; | 1237 | goto out; |
| 1236 | } | 1238 | } |
| 1239 | EXPORT_SYMBOL(lookup_bdev); | ||
| 1237 | 1240 | ||
| 1238 | /** | 1241 | /** |
| 1239 | * open_bdev_excl - open a block device by name and set it up for use | 1242 | * open_bdev_excl - open a block device by name and set it up for use |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index d82374c9e32..d2c8eef84f3 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -226,7 +226,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 226 | int err; | 226 | int err; |
| 227 | 227 | ||
| 228 | mntget(newmnt); | 228 | mntget(newmnt); |
| 229 | err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); | 229 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags, mntlist); |
| 230 | switch (err) { | 230 | switch (err) { |
| 231 | case 0: | 231 | case 0: |
| 232 | path_put(&nd->path); | 232 | path_put(&nd->path); |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 285b64a8b06..488eb424f66 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | #define DEVPTS_DEFAULT_MODE 0600 | 29 | #define DEVPTS_DEFAULT_MODE 0600 |
| 30 | 30 | ||
| 31 | extern int pty_limit; /* Config limit on Unix98 ptys */ | 31 | extern int pty_limit; /* Config limit on Unix98 ptys */ |
| 32 | static DEFINE_IDR(allocated_ptys); | 32 | static DEFINE_IDA(allocated_ptys); |
| 33 | static DEFINE_MUTEX(allocated_ptys_lock); | 33 | static DEFINE_MUTEX(allocated_ptys_lock); |
| 34 | 34 | ||
| 35 | static struct vfsmount *devpts_mnt; | 35 | static struct vfsmount *devpts_mnt; |
| @@ -180,24 +180,24 @@ static struct dentry *get_node(int num) | |||
| 180 | int devpts_new_index(void) | 180 | int devpts_new_index(void) |
| 181 | { | 181 | { |
| 182 | int index; | 182 | int index; |
| 183 | int idr_ret; | 183 | int ida_ret; |
| 184 | 184 | ||
| 185 | retry: | 185 | retry: |
| 186 | if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { | 186 | if (!ida_pre_get(&allocated_ptys, GFP_KERNEL)) { |
| 187 | return -ENOMEM; | 187 | return -ENOMEM; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | mutex_lock(&allocated_ptys_lock); | 190 | mutex_lock(&allocated_ptys_lock); |
| 191 | idr_ret = idr_get_new(&allocated_ptys, NULL, &index); | 191 | ida_ret = ida_get_new(&allocated_ptys, &index); |
| 192 | if (idr_ret < 0) { | 192 | if (ida_ret < 0) { |
| 193 | mutex_unlock(&allocated_ptys_lock); | 193 | mutex_unlock(&allocated_ptys_lock); |
| 194 | if (idr_ret == -EAGAIN) | 194 | if (ida_ret == -EAGAIN) |
| 195 | goto retry; | 195 | goto retry; |
| 196 | return -EIO; | 196 | return -EIO; |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | if (index >= pty_limit) { | 199 | if (index >= pty_limit) { |
| 200 | idr_remove(&allocated_ptys, index); | 200 | ida_remove(&allocated_ptys, index); |
| 201 | mutex_unlock(&allocated_ptys_lock); | 201 | mutex_unlock(&allocated_ptys_lock); |
| 202 | return -EIO; | 202 | return -EIO; |
| 203 | } | 203 | } |
| @@ -208,7 +208,7 @@ retry: | |||
| 208 | void devpts_kill_index(int idx) | 208 | void devpts_kill_index(int idx) |
| 209 | { | 209 | { |
| 210 | mutex_lock(&allocated_ptys_lock); | 210 | mutex_lock(&allocated_ptys_lock); |
| 211 | idr_remove(&allocated_ptys, idx); | 211 | ida_remove(&allocated_ptys, idx); |
| 212 | mutex_unlock(&allocated_ptys_lock); | 212 | mutex_unlock(&allocated_ptys_lock); |
| 213 | } | 213 | } |
| 214 | 214 | ||
diff --git a/fs/dquot.c b/fs/dquot.c index 1346eebe74c..8ec4d6cc763 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
| @@ -1793,6 +1793,21 @@ static int vfs_quota_on_remount(struct super_block *sb, int type) | |||
| 1793 | return ret; | 1793 | return ret; |
| 1794 | } | 1794 | } |
| 1795 | 1795 | ||
| 1796 | int vfs_quota_on_path(struct super_block *sb, int type, int format_id, | ||
| 1797 | struct path *path) | ||
| 1798 | { | ||
| 1799 | int error = security_quota_on(path->dentry); | ||
| 1800 | if (error) | ||
| 1801 | return error; | ||
| 1802 | /* Quota file not on the same filesystem? */ | ||
| 1803 | if (path->mnt->mnt_sb != sb) | ||
| 1804 | error = -EXDEV; | ||
| 1805 | else | ||
| 1806 | error = vfs_quota_on_inode(path->dentry->d_inode, type, | ||
| 1807 | format_id); | ||
| 1808 | return error; | ||
| 1809 | } | ||
| 1810 | |||
| 1796 | /* Actual function called from quotactl() */ | 1811 | /* Actual function called from quotactl() */ |
| 1797 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, | 1812 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, |
| 1798 | int remount) | 1813 | int remount) |
| @@ -1804,19 +1819,10 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, | |||
| 1804 | return vfs_quota_on_remount(sb, type); | 1819 | return vfs_quota_on_remount(sb, type); |
| 1805 | 1820 | ||
| 1806 | error = path_lookup(path, LOOKUP_FOLLOW, &nd); | 1821 | error = path_lookup(path, LOOKUP_FOLLOW, &nd); |
| 1807 | if (error < 0) | 1822 | if (!error) { |
| 1808 | return error; | 1823 | error = vfs_quota_on_path(sb, type, format_id, &nd.path); |
| 1809 | error = security_quota_on(nd.path.dentry); | 1824 | path_put(&nd.path); |
| 1810 | if (error) | 1825 | } |
| 1811 | goto out_path; | ||
| 1812 | /* Quota file not on the same filesystem? */ | ||
| 1813 | if (nd.path.mnt->mnt_sb != sb) | ||
| 1814 | error = -EXDEV; | ||
| 1815 | else | ||
| 1816 | error = vfs_quota_on_inode(nd.path.dentry->d_inode, type, | ||
| 1817 | format_id); | ||
| 1818 | out_path: | ||
| 1819 | path_put(&nd.path); | ||
| 1820 | return error; | 1826 | return error; |
| 1821 | } | 1827 | } |
| 1822 | 1828 | ||
| @@ -2185,6 +2191,7 @@ EXPORT_SYMBOL(unregister_quota_format); | |||
| 2185 | EXPORT_SYMBOL(dqstats); | 2191 | EXPORT_SYMBOL(dqstats); |
| 2186 | EXPORT_SYMBOL(dq_data_lock); | 2192 | EXPORT_SYMBOL(dq_data_lock); |
| 2187 | EXPORT_SYMBOL(vfs_quota_on); | 2193 | EXPORT_SYMBOL(vfs_quota_on); |
| 2194 | EXPORT_SYMBOL(vfs_quota_on_path); | ||
| 2188 | EXPORT_SYMBOL(vfs_quota_on_mount); | 2195 | EXPORT_SYMBOL(vfs_quota_on_mount); |
| 2189 | EXPORT_SYMBOL(vfs_quota_off); | 2196 | EXPORT_SYMBOL(vfs_quota_off); |
| 2190 | EXPORT_SYMBOL(vfs_quota_sync); | 2197 | EXPORT_SYMBOL(vfs_quota_sync); |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 8ddced38467..f38a5afc39a 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -2810,8 +2810,9 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2810 | journal_unlock_updates(EXT3_SB(sb)->s_journal); | 2810 | journal_unlock_updates(EXT3_SB(sb)->s_journal); |
| 2811 | } | 2811 | } |
| 2812 | 2812 | ||
| 2813 | err = vfs_quota_on_path(sb, type, format_id, &nd.path); | ||
| 2813 | path_put(&nd.path); | 2814 | path_put(&nd.path); |
| 2814 | return vfs_quota_on(sb, type, format_id, path, remount); | 2815 | return err; |
| 2815 | } | 2816 | } |
| 2816 | 2817 | ||
| 2817 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 2818 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index b5479b1dff1..1e69f29a8c5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -3352,8 +3352,9 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
| 3352 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 3352 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); |
| 3353 | } | 3353 | } |
| 3354 | 3354 | ||
| 3355 | err = vfs_quota_on_path(sb, type, format_id, &nd.path); | ||
| 3355 | path_put(&nd.path); | 3356 | path_put(&nd.path); |
| 3356 | return vfs_quota_on(sb, type, format_id, path, remount); | 3357 | return err; |
| 3357 | } | 3358 | } |
| 3358 | 3359 | ||
| 3359 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 3360 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 61d62513681..ac4f7db9f13 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -49,73 +49,6 @@ static int get_close_on_exec(unsigned int fd) | |||
| 49 | return res; | 49 | return res; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /* | ||
| 53 | * locate_fd finds a free file descriptor in the open_fds fdset, | ||
| 54 | * expanding the fd arrays if necessary. Must be called with the | ||
| 55 | * file_lock held for write. | ||
| 56 | */ | ||
| 57 | |||
| 58 | static int locate_fd(unsigned int orig_start, int cloexec) | ||
| 59 | { | ||
| 60 | struct files_struct *files = current->files; | ||
| 61 | unsigned int newfd; | ||
| 62 | unsigned int start; | ||
| 63 | int error; | ||
| 64 | struct fdtable *fdt; | ||
| 65 | |||
| 66 | spin_lock(&files->file_lock); | ||
| 67 | repeat: | ||
| 68 | fdt = files_fdtable(files); | ||
| 69 | /* | ||
| 70 | * Someone might have closed fd's in the range | ||
| 71 | * orig_start..fdt->next_fd | ||
| 72 | */ | ||
| 73 | start = orig_start; | ||
| 74 | if (start < files->next_fd) | ||
| 75 | start = files->next_fd; | ||
| 76 | |||
| 77 | newfd = start; | ||
| 78 | if (start < fdt->max_fds) | ||
| 79 | newfd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
| 80 | fdt->max_fds, start); | ||
| 81 | |||
| 82 | error = expand_files(files, newfd); | ||
| 83 | if (error < 0) | ||
| 84 | goto out; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * If we needed to expand the fs array we | ||
| 88 | * might have blocked - try again. | ||
| 89 | */ | ||
| 90 | if (error) | ||
| 91 | goto repeat; | ||
| 92 | |||
| 93 | if (start <= files->next_fd) | ||
| 94 | files->next_fd = newfd + 1; | ||
| 95 | |||
| 96 | FD_SET(newfd, fdt->open_fds); | ||
| 97 | if (cloexec) | ||
| 98 | FD_SET(newfd, fdt->close_on_exec); | ||
| 99 | else | ||
| 100 | FD_CLR(newfd, fdt->close_on_exec); | ||
| 101 | error = newfd; | ||
| 102 | |||
| 103 | out: | ||
| 104 | spin_unlock(&files->file_lock); | ||
| 105 | return error; | ||
| 106 | } | ||
| 107 | |||
| 108 | static int dupfd(struct file *file, unsigned int start, int cloexec) | ||
| 109 | { | ||
| 110 | int fd = locate_fd(start, cloexec); | ||
| 111 | if (fd >= 0) | ||
| 112 | fd_install(fd, file); | ||
| 113 | else | ||
| 114 | fput(file); | ||
| 115 | |||
| 116 | return fd; | ||
| 117 | } | ||
| 118 | |||
| 119 | asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | 52 | asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) |
| 120 | { | 53 | { |
| 121 | int err = -EBADF; | 54 | int err = -EBADF; |
| @@ -130,31 +63,35 @@ asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | |||
| 130 | return -EINVAL; | 63 | return -EINVAL; |
| 131 | 64 | ||
| 132 | spin_lock(&files->file_lock); | 65 | spin_lock(&files->file_lock); |
| 133 | if (!(file = fcheck(oldfd))) | ||
| 134 | goto out_unlock; | ||
| 135 | get_file(file); /* We are now finished with oldfd */ | ||
| 136 | |||
| 137 | err = expand_files(files, newfd); | 66 | err = expand_files(files, newfd); |
| 67 | file = fcheck(oldfd); | ||
| 68 | if (unlikely(!file)) | ||
| 69 | goto Ebadf; | ||
| 138 | if (unlikely(err < 0)) { | 70 | if (unlikely(err < 0)) { |
| 139 | if (err == -EMFILE) | 71 | if (err == -EMFILE) |
| 140 | err = -EBADF; | 72 | goto Ebadf; |
| 141 | goto out_fput; | 73 | goto out_unlock; |
| 142 | } | 74 | } |
| 143 | 75 | /* | |
| 144 | /* To avoid races with open() and dup(), we will mark the fd as | 76 | * We need to detect attempts to do dup2() over allocated but still |
| 145 | * in-use in the open-file bitmap throughout the entire dup2() | 77 | * not finished descriptor. NB: OpenBSD avoids that at the price of |
| 146 | * process. This is quite safe: do_close() uses the fd array | 78 | * extra work in their equivalent of fget() - they insert struct |
| 147 | * entry, not the bitmap, to decide what work needs to be | 79 | * file immediately after grabbing descriptor, mark it larval if |
| 148 | * done. --sct */ | 80 | * more work (e.g. actual opening) is needed and make sure that |
| 149 | /* Doesn't work. open() might be there first. --AV */ | 81 | * fget() treats larval files as absent. Potentially interesting, |
| 150 | 82 | * but while extra work in fget() is trivial, locking implications | |
| 151 | /* Yes. It's a race. In user space. Nothing sane to do */ | 83 | * and amount of surgery on open()-related paths in VFS are not. |
| 84 | * FreeBSD fails with -EBADF in the same situation, NetBSD "solution" | ||
| 85 | * deadlocks in rather amusing ways, AFAICS. All of that is out of | ||
| 86 | * scope of POSIX or SUS, since neither considers shared descriptor | ||
| 87 | * tables and this condition does not arise without those. | ||
| 88 | */ | ||
| 152 | err = -EBUSY; | 89 | err = -EBUSY; |
| 153 | fdt = files_fdtable(files); | 90 | fdt = files_fdtable(files); |
| 154 | tofree = fdt->fd[newfd]; | 91 | tofree = fdt->fd[newfd]; |
| 155 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) | 92 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) |
| 156 | goto out_fput; | 93 | goto out_unlock; |
| 157 | 94 | get_file(file); | |
| 158 | rcu_assign_pointer(fdt->fd[newfd], file); | 95 | rcu_assign_pointer(fdt->fd[newfd], file); |
| 159 | FD_SET(newfd, fdt->open_fds); | 96 | FD_SET(newfd, fdt->open_fds); |
| 160 | if (flags & O_CLOEXEC) | 97 | if (flags & O_CLOEXEC) |
| @@ -165,17 +102,14 @@ asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | |||
| 165 | 102 | ||
| 166 | if (tofree) | 103 | if (tofree) |
| 167 | filp_close(tofree, files); | 104 | filp_close(tofree, files); |
| 168 | err = newfd; | ||
| 169 | out: | ||
| 170 | return err; | ||
| 171 | out_unlock: | ||
| 172 | spin_unlock(&files->file_lock); | ||
| 173 | goto out; | ||
| 174 | 105 | ||
| 175 | out_fput: | 106 | return newfd; |
| 107 | |||
| 108 | Ebadf: | ||
| 109 | err = -EBADF; | ||
| 110 | out_unlock: | ||
| 176 | spin_unlock(&files->file_lock); | 111 | spin_unlock(&files->file_lock); |
| 177 | fput(file); | 112 | return err; |
| 178 | goto out; | ||
| 179 | } | 113 | } |
| 180 | 114 | ||
| 181 | asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | 115 | asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) |
| @@ -194,10 +128,15 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | |||
| 194 | asmlinkage long sys_dup(unsigned int fildes) | 128 | asmlinkage long sys_dup(unsigned int fildes) |
| 195 | { | 129 | { |
| 196 | int ret = -EBADF; | 130 | int ret = -EBADF; |
| 197 | struct file * file = fget(fildes); | 131 | struct file *file = fget(fildes); |
| 198 | 132 | ||
| 199 | if (file) | 133 | if (file) { |
| 200 | ret = dupfd(file, 0, 0); | 134 | ret = get_unused_fd(); |
| 135 | if (ret >= 0) | ||
| 136 | fd_install(ret, file); | ||
| 137 | else | ||
| 138 | fput(file); | ||
| 139 | } | ||
| 201 | return ret; | 140 | return ret; |
| 202 | } | 141 | } |
| 203 | 142 | ||
| @@ -322,8 +261,11 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
| 322 | case F_DUPFD_CLOEXEC: | 261 | case F_DUPFD_CLOEXEC: |
| 323 | if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 262 | if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
| 324 | break; | 263 | break; |
| 325 | get_file(filp); | 264 | err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0); |
| 326 | err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC); | 265 | if (err >= 0) { |
| 266 | get_file(filp); | ||
| 267 | fd_install(err, filp); | ||
| 268 | } | ||
| 327 | break; | 269 | break; |
| 328 | case F_GETFD: | 270 | case F_GETFD: |
| 329 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; | 271 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; |
| @@ -6,6 +6,7 @@ | |||
| 6 | * Manage the dynamic fd arrays in the process files_struct. | 6 | * Manage the dynamic fd arrays in the process files_struct. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/module.h> | ||
| 9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
| 10 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 11 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| @@ -432,3 +433,63 @@ struct files_struct init_files = { | |||
| 432 | }, | 433 | }, |
| 433 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), | 434 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), |
| 434 | }; | 435 | }; |
| 436 | |||
| 437 | /* | ||
| 438 | * allocate a file descriptor, mark it busy. | ||
| 439 | */ | ||
| 440 | int alloc_fd(unsigned start, unsigned flags) | ||
| 441 | { | ||
| 442 | struct files_struct *files = current->files; | ||
| 443 | unsigned int fd; | ||
| 444 | int error; | ||
| 445 | struct fdtable *fdt; | ||
| 446 | |||
| 447 | spin_lock(&files->file_lock); | ||
| 448 | repeat: | ||
| 449 | fdt = files_fdtable(files); | ||
| 450 | fd = start; | ||
| 451 | if (fd < files->next_fd) | ||
| 452 | fd = files->next_fd; | ||
| 453 | |||
| 454 | if (fd < fdt->max_fds) | ||
| 455 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
| 456 | fdt->max_fds, fd); | ||
| 457 | |||
| 458 | error = expand_files(files, fd); | ||
| 459 | if (error < 0) | ||
| 460 | goto out; | ||
| 461 | |||
| 462 | /* | ||
| 463 | * If we needed to expand the fs array we | ||
| 464 | * might have blocked - try again. | ||
| 465 | */ | ||
| 466 | if (error) | ||
| 467 | goto repeat; | ||
| 468 | |||
| 469 | if (start <= files->next_fd) | ||
| 470 | files->next_fd = fd + 1; | ||
| 471 | |||
| 472 | FD_SET(fd, fdt->open_fds); | ||
| 473 | if (flags & O_CLOEXEC) | ||
| 474 | FD_SET(fd, fdt->close_on_exec); | ||
| 475 | else | ||
| 476 | FD_CLR(fd, fdt->close_on_exec); | ||
| 477 | error = fd; | ||
| 478 | #if 1 | ||
| 479 | /* Sanity check */ | ||
| 480 | if (rcu_dereference(fdt->fd[fd]) != NULL) { | ||
| 481 | printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); | ||
| 482 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
| 483 | } | ||
| 484 | #endif | ||
| 485 | |||
| 486 | out: | ||
| 487 | spin_unlock(&files->file_lock); | ||
| 488 | return error; | ||
| 489 | } | ||
| 490 | |||
| 491 | int get_unused_fd(void) | ||
| 492 | { | ||
| 493 | return alloc_fd(0, 0); | ||
| 494 | } | ||
| 495 | EXPORT_SYMBOL(get_unused_fd); | ||
diff --git a/fs/namei.c b/fs/namei.c index a7b0a0b8012..4ea63ed5e79 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -274,7 +274,7 @@ int inode_permission(struct inode *inode, int mask) | |||
| 274 | return retval; | 274 | return retval; |
| 275 | 275 | ||
| 276 | return security_inode_permission(inode, | 276 | return security_inode_permission(inode, |
| 277 | mask & (MAY_READ|MAY_WRITE|MAY_EXEC)); | 277 | mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND)); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | /** | 280 | /** |
| @@ -1431,8 +1431,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
| 1431 | * 3. We should have write and exec permissions on dir | 1431 | * 3. We should have write and exec permissions on dir |
| 1432 | * 4. We can't do it if dir is immutable (done in permission()) | 1432 | * 4. We can't do it if dir is immutable (done in permission()) |
| 1433 | */ | 1433 | */ |
| 1434 | static inline int may_create(struct inode *dir, struct dentry *child, | 1434 | static inline int may_create(struct inode *dir, struct dentry *child) |
| 1435 | struct nameidata *nd) | ||
| 1436 | { | 1435 | { |
| 1437 | if (child->d_inode) | 1436 | if (child->d_inode) |
| 1438 | return -EEXIST; | 1437 | return -EEXIST; |
| @@ -1504,7 +1503,7 @@ void unlock_rename(struct dentry *p1, struct dentry *p2) | |||
| 1504 | int vfs_create(struct inode *dir, struct dentry *dentry, int mode, | 1503 | int vfs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 1505 | struct nameidata *nd) | 1504 | struct nameidata *nd) |
| 1506 | { | 1505 | { |
| 1507 | int error = may_create(dir, dentry, nd); | 1506 | int error = may_create(dir, dentry); |
| 1508 | 1507 | ||
| 1509 | if (error) | 1508 | if (error) |
| 1510 | return error; | 1509 | return error; |
| @@ -1948,7 +1947,7 @@ EXPORT_SYMBOL_GPL(lookup_create); | |||
| 1948 | 1947 | ||
| 1949 | int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | 1948 | int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) |
| 1950 | { | 1949 | { |
| 1951 | int error = may_create(dir, dentry, NULL); | 1950 | int error = may_create(dir, dentry); |
| 1952 | 1951 | ||
| 1953 | if (error) | 1952 | if (error) |
| 1954 | return error; | 1953 | return error; |
| @@ -2049,7 +2048,7 @@ asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) | |||
| 2049 | 2048 | ||
| 2050 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 2049 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
| 2051 | { | 2050 | { |
| 2052 | int error = may_create(dir, dentry, NULL); | 2051 | int error = may_create(dir, dentry); |
| 2053 | 2052 | ||
| 2054 | if (error) | 2053 | if (error) |
| 2055 | return error; | 2054 | return error; |
| @@ -2316,7 +2315,7 @@ asmlinkage long sys_unlink(const char __user *pathname) | |||
| 2316 | 2315 | ||
| 2317 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) | 2316 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) |
| 2318 | { | 2317 | { |
| 2319 | int error = may_create(dir, dentry, NULL); | 2318 | int error = may_create(dir, dentry); |
| 2320 | 2319 | ||
| 2321 | if (error) | 2320 | if (error) |
| 2322 | return error; | 2321 | return error; |
| @@ -2386,7 +2385,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
| 2386 | if (!inode) | 2385 | if (!inode) |
| 2387 | return -ENOENT; | 2386 | return -ENOENT; |
| 2388 | 2387 | ||
| 2389 | error = may_create(dir, new_dentry, NULL); | 2388 | error = may_create(dir, new_dentry); |
| 2390 | if (error) | 2389 | if (error) |
| 2391 | return error; | 2390 | return error; |
| 2392 | 2391 | ||
| @@ -2595,7 +2594,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2595 | return error; | 2594 | return error; |
| 2596 | 2595 | ||
| 2597 | if (!new_dentry->d_inode) | 2596 | if (!new_dentry->d_inode) |
| 2598 | error = may_create(new_dir, new_dentry, NULL); | 2597 | error = may_create(new_dir, new_dentry); |
| 2599 | else | 2598 | else |
| 2600 | error = may_delete(new_dir, new_dentry, is_dir); | 2599 | error = may_delete(new_dir, new_dentry, is_dir); |
| 2601 | if (error) | 2600 | if (error) |
diff --git a/fs/namespace.c b/fs/namespace.c index 411728c0c8b..6e283c93b50 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -1667,31 +1667,31 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, | |||
| 1667 | if (IS_ERR(mnt)) | 1667 | if (IS_ERR(mnt)) |
| 1668 | return PTR_ERR(mnt); | 1668 | return PTR_ERR(mnt); |
| 1669 | 1669 | ||
| 1670 | return do_add_mount(mnt, nd, mnt_flags, NULL); | 1670 | return do_add_mount(mnt, &nd->path, mnt_flags, NULL); |
| 1671 | } | 1671 | } |
| 1672 | 1672 | ||
| 1673 | /* | 1673 | /* |
| 1674 | * add a mount into a namespace's mount tree | 1674 | * add a mount into a namespace's mount tree |
| 1675 | * - provide the option of adding the new mount to an expiration list | 1675 | * - provide the option of adding the new mount to an expiration list |
| 1676 | */ | 1676 | */ |
| 1677 | int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | 1677 | int do_add_mount(struct vfsmount *newmnt, struct path *path, |
| 1678 | int mnt_flags, struct list_head *fslist) | 1678 | int mnt_flags, struct list_head *fslist) |
| 1679 | { | 1679 | { |
| 1680 | int err; | 1680 | int err; |
| 1681 | 1681 | ||
| 1682 | down_write(&namespace_sem); | 1682 | down_write(&namespace_sem); |
| 1683 | /* Something was mounted here while we slept */ | 1683 | /* Something was mounted here while we slept */ |
| 1684 | while (d_mountpoint(nd->path.dentry) && | 1684 | while (d_mountpoint(path->dentry) && |
| 1685 | follow_down(&nd->path.mnt, &nd->path.dentry)) | 1685 | follow_down(&path->mnt, &path->dentry)) |
| 1686 | ; | 1686 | ; |
| 1687 | err = -EINVAL; | 1687 | err = -EINVAL; |
| 1688 | if (!check_mnt(nd->path.mnt)) | 1688 | if (!check_mnt(path->mnt)) |
| 1689 | goto unlock; | 1689 | goto unlock; |
| 1690 | 1690 | ||
| 1691 | /* Refuse the same filesystem on the same mount point */ | 1691 | /* Refuse the same filesystem on the same mount point */ |
| 1692 | err = -EBUSY; | 1692 | err = -EBUSY; |
| 1693 | if (nd->path.mnt->mnt_sb == newmnt->mnt_sb && | 1693 | if (path->mnt->mnt_sb == newmnt->mnt_sb && |
| 1694 | nd->path.mnt->mnt_root == nd->path.dentry) | 1694 | path->mnt->mnt_root == path->dentry) |
| 1695 | goto unlock; | 1695 | goto unlock; |
| 1696 | 1696 | ||
| 1697 | err = -EINVAL; | 1697 | err = -EINVAL; |
| @@ -1699,7 +1699,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 1699 | goto unlock; | 1699 | goto unlock; |
| 1700 | 1700 | ||
| 1701 | newmnt->mnt_flags = mnt_flags; | 1701 | newmnt->mnt_flags = mnt_flags; |
| 1702 | if ((err = graft_tree(newmnt, &nd->path))) | 1702 | if ((err = graft_tree(newmnt, path))) |
| 1703 | goto unlock; | 1703 | goto unlock; |
| 1704 | 1704 | ||
| 1705 | if (fslist) /* add to the specified expiration list */ | 1705 | if (fslist) /* add to the specified expiration list */ |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 2f285ef7639..66df08dd1ca 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -129,7 +129,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 129 | goto out_err; | 129 | goto out_err; |
| 130 | 130 | ||
| 131 | mntget(mnt); | 131 | mntget(mnt); |
| 132 | err = do_add_mount(mnt, nd, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, | 132 | err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, |
| 133 | &nfs_automount_list); | 133 | &nfs_automount_list); |
| 134 | if (err < 0) { | 134 | if (err < 0) { |
| 135 | mntput(mnt); | 135 | mntput(mnt); |
| @@ -963,62 +963,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
| 963 | } | 963 | } |
| 964 | EXPORT_SYMBOL(dentry_open); | 964 | EXPORT_SYMBOL(dentry_open); |
| 965 | 965 | ||
| 966 | /* | ||
| 967 | * Find an empty file descriptor entry, and mark it busy. | ||
| 968 | */ | ||
| 969 | int get_unused_fd_flags(int flags) | ||
| 970 | { | ||
| 971 | struct files_struct * files = current->files; | ||
| 972 | int fd, error; | ||
| 973 | struct fdtable *fdt; | ||
| 974 | |||
| 975 | spin_lock(&files->file_lock); | ||
| 976 | |||
| 977 | repeat: | ||
| 978 | fdt = files_fdtable(files); | ||
| 979 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds, | ||
| 980 | files->next_fd); | ||
| 981 | |||
| 982 | /* Do we need to expand the fd array or fd set? */ | ||
| 983 | error = expand_files(files, fd); | ||
| 984 | if (error < 0) | ||
| 985 | goto out; | ||
| 986 | |||
| 987 | if (error) { | ||
| 988 | /* | ||
| 989 | * If we needed to expand the fs array we | ||
| 990 | * might have blocked - try again. | ||
| 991 | */ | ||
| 992 | goto repeat; | ||
| 993 | } | ||
| 994 | |||
| 995 | FD_SET(fd, fdt->open_fds); | ||
| 996 | if (flags & O_CLOEXEC) | ||
| 997 | FD_SET(fd, fdt->close_on_exec); | ||
| 998 | else | ||
| 999 | FD_CLR(fd, fdt->close_on_exec); | ||
| 1000 | files->next_fd = fd + 1; | ||
| 1001 | #if 1 | ||
| 1002 | /* Sanity check */ | ||
| 1003 | if (fdt->fd[fd] != NULL) { | ||
| 1004 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); | ||
| 1005 | fdt->fd[fd] = NULL; | ||
| 1006 | } | ||
| 1007 | #endif | ||
| 1008 | error = fd; | ||
| 1009 | |||
| 1010 | out: | ||
| 1011 | spin_unlock(&files->file_lock); | ||
| 1012 | return error; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | int get_unused_fd(void) | ||
| 1016 | { | ||
| 1017 | return get_unused_fd_flags(0); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | EXPORT_SYMBOL(get_unused_fd); | ||
| 1021 | |||
| 1022 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) | 966 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) |
| 1023 | { | 967 | { |
| 1024 | struct fdtable *fdt = files_fdtable(files); | 968 | struct fdtable *fdt = files_fdtable(files); |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index cb4096cc3fb..4fb81e9c94e 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -300,10 +300,10 @@ out: | |||
| 300 | return rtn; | 300 | return rtn; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | static DEFINE_IDR(proc_inum_idr); | 303 | static DEFINE_IDA(proc_inum_ida); |
| 304 | static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | 304 | static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ |
| 305 | 305 | ||
| 306 | #define PROC_DYNAMIC_FIRST 0xF0000000UL | 306 | #define PROC_DYNAMIC_FIRST 0xF0000000U |
| 307 | 307 | ||
| 308 | /* | 308 | /* |
| 309 | * Return an inode number between PROC_DYNAMIC_FIRST and | 309 | * Return an inode number between PROC_DYNAMIC_FIRST and |
| @@ -311,36 +311,33 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | |||
| 311 | */ | 311 | */ |
| 312 | static unsigned int get_inode_number(void) | 312 | static unsigned int get_inode_number(void) |
| 313 | { | 313 | { |
| 314 | int i, inum = 0; | 314 | unsigned int i; |
| 315 | int error; | 315 | int error; |
| 316 | 316 | ||
| 317 | retry: | 317 | retry: |
| 318 | if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0) | 318 | if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0) |
| 319 | return 0; | 319 | return 0; |
| 320 | 320 | ||
| 321 | spin_lock(&proc_inum_lock); | 321 | spin_lock(&proc_inum_lock); |
| 322 | error = idr_get_new(&proc_inum_idr, NULL, &i); | 322 | error = ida_get_new(&proc_inum_ida, &i); |
| 323 | spin_unlock(&proc_inum_lock); | 323 | spin_unlock(&proc_inum_lock); |
| 324 | if (error == -EAGAIN) | 324 | if (error == -EAGAIN) |
| 325 | goto retry; | 325 | goto retry; |
| 326 | else if (error) | 326 | else if (error) |
| 327 | return 0; | 327 | return 0; |
| 328 | 328 | ||
| 329 | inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST; | 329 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { |
| 330 | 330 | spin_lock(&proc_inum_lock); | |
| 331 | /* inum will never be more than 0xf0ffffff, so no check | 331 | ida_remove(&proc_inum_ida, i); |
| 332 | * for overflow. | 332 | spin_unlock(&proc_inum_lock); |
| 333 | */ | 333 | } |
| 334 | 334 | return PROC_DYNAMIC_FIRST + i; | |
| 335 | return inum; | ||
| 336 | } | 335 | } |
| 337 | 336 | ||
| 338 | static void release_inode_number(unsigned int inum) | 337 | static void release_inode_number(unsigned int inum) |
| 339 | { | 338 | { |
| 340 | int id = (inum - PROC_DYNAMIC_FIRST) | ~MAX_ID_MASK; | ||
| 341 | |||
| 342 | spin_lock(&proc_inum_lock); | 339 | spin_lock(&proc_inum_lock); |
| 343 | idr_remove(&proc_inum_idr, id); | 340 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
| 344 | spin_unlock(&proc_inum_lock); | 341 | spin_unlock(&proc_inum_lock); |
| 345 | } | 342 | } |
| 346 | 343 | ||
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 879e54d35c2..282a13596c7 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -2076,8 +2076,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2076 | return err; | 2076 | return err; |
| 2077 | /* Quotafile not on the same filesystem? */ | 2077 | /* Quotafile not on the same filesystem? */ |
| 2078 | if (nd.path.mnt->mnt_sb != sb) { | 2078 | if (nd.path.mnt->mnt_sb != sb) { |
| 2079 | path_put(&nd.path); | 2079 | err = -EXDEV; |
| 2080 | return -EXDEV; | 2080 | goto out; |
| 2081 | } | 2081 | } |
| 2082 | inode = nd.path.dentry->d_inode; | 2082 | inode = nd.path.dentry->d_inode; |
| 2083 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ | 2083 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ |
| @@ -2087,8 +2087,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2087 | reiserfs_warning(sb, | 2087 | reiserfs_warning(sb, |
| 2088 | "reiserfs: Unpacking tail of quota file failed" | 2088 | "reiserfs: Unpacking tail of quota file failed" |
| 2089 | " (%d). Cannot turn on quotas.", err); | 2089 | " (%d). Cannot turn on quotas.", err); |
| 2090 | path_put(&nd.path); | 2090 | err = -EINVAL; |
| 2091 | return -EINVAL; | 2091 | goto out; |
| 2092 | } | 2092 | } |
| 2093 | mark_inode_dirty(inode); | 2093 | mark_inode_dirty(inode); |
| 2094 | } | 2094 | } |
| @@ -2109,13 +2109,15 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2109 | /* Just start temporary transaction and finish it */ | 2109 | /* Just start temporary transaction and finish it */ |
| 2110 | err = journal_begin(&th, sb, 1); | 2110 | err = journal_begin(&th, sb, 1); |
| 2111 | if (err) | 2111 | if (err) |
| 2112 | return err; | 2112 | goto out; |
| 2113 | err = journal_end_sync(&th, sb, 1); | 2113 | err = journal_end_sync(&th, sb, 1); |
| 2114 | if (err) | 2114 | if (err) |
| 2115 | return err; | 2115 | goto out; |
| 2116 | } | 2116 | } |
| 2117 | err = vfs_quota_on_path(sb, type, format_id, &nd.path); | ||
| 2118 | out: | ||
| 2117 | path_put(&nd.path); | 2119 | path_put(&nd.path); |
| 2118 | return vfs_quota_on(sb, type, format_id, path, 0); | 2120 | return err; |
| 2119 | } | 2121 | } |
| 2120 | 2122 | ||
| 2121 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 2123 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
