diff options
Diffstat (limited to 'fs/file_table.c')
-rw-r--r-- | fs/file_table.c | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 6d27befe2d48..7a0a9b872251 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -42,6 +42,7 @@ static inline void file_free_rcu(struct rcu_head *head) | |||
42 | static inline void file_free(struct file *f) | 42 | static inline void file_free(struct file *f) |
43 | { | 43 | { |
44 | percpu_counter_dec(&nr_files); | 44 | percpu_counter_dec(&nr_files); |
45 | file_check_state(f); | ||
45 | call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); | 46 | call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); |
46 | } | 47 | } |
47 | 48 | ||
@@ -83,6 +84,12 @@ int proc_nr_files(ctl_table *table, int write, struct file *filp, | |||
83 | /* Find an unused file structure and return a pointer to it. | 84 | /* Find an unused file structure and return a pointer to it. |
84 | * Returns NULL, if there are no more free file structures or | 85 | * Returns NULL, if there are no more free file structures or |
85 | * we run out of memory. | 86 | * we run out of memory. |
87 | * | ||
88 | * Be very careful using this. You are responsible for | ||
89 | * getting write access to any mount that you might assign | ||
90 | * to this filp, if it is opened for write. If this is not | ||
91 | * done, you will imbalance int the mount's writer count | ||
92 | * and a warning at __fput() time. | ||
86 | */ | 93 | */ |
87 | struct file *get_empty_filp(void) | 94 | struct file *get_empty_filp(void) |
88 | { | 95 | { |
@@ -193,6 +200,18 @@ int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry, | |||
193 | file->f_mapping = dentry->d_inode->i_mapping; | 200 | file->f_mapping = dentry->d_inode->i_mapping; |
194 | file->f_mode = mode; | 201 | file->f_mode = mode; |
195 | file->f_op = fop; | 202 | file->f_op = fop; |
203 | |||
204 | /* | ||
205 | * These mounts don't really matter in practice | ||
206 | * for r/o bind mounts. They aren't userspace- | ||
207 | * visible. We do this for consistency, and so | ||
208 | * that we can do debugging checks at __fput() | ||
209 | */ | ||
210 | if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) { | ||
211 | file_take_write(file); | ||
212 | error = mnt_want_write(mnt); | ||
213 | WARN_ON(error); | ||
214 | } | ||
196 | return error; | 215 | return error; |
197 | } | 216 | } |
198 | EXPORT_SYMBOL(init_file); | 217 | EXPORT_SYMBOL(init_file); |
@@ -205,6 +224,31 @@ void fput(struct file *file) | |||
205 | 224 | ||
206 | EXPORT_SYMBOL(fput); | 225 | EXPORT_SYMBOL(fput); |
207 | 226 | ||
227 | /** | ||
228 | * drop_file_write_access - give up ability to write to a file | ||
229 | * @file: the file to which we will stop writing | ||
230 | * | ||
231 | * This is a central place which will give up the ability | ||
232 | * to write to @file, along with access to write through | ||
233 | * its vfsmount. | ||
234 | */ | ||
235 | void drop_file_write_access(struct file *file) | ||
236 | { | ||
237 | struct vfsmount *mnt = file->f_path.mnt; | ||
238 | struct dentry *dentry = file->f_path.dentry; | ||
239 | struct inode *inode = dentry->d_inode; | ||
240 | |||
241 | put_write_access(inode); | ||
242 | |||
243 | if (special_file(inode->i_mode)) | ||
244 | return; | ||
245 | if (file_check_writeable(file) != 0) | ||
246 | return; | ||
247 | mnt_drop_write(mnt); | ||
248 | file_release_write(file); | ||
249 | } | ||
250 | EXPORT_SYMBOL_GPL(drop_file_write_access); | ||
251 | |||
208 | /* __fput is called from task context when aio completion releases the last | 252 | /* __fput is called from task context when aio completion releases the last |
209 | * last use of a struct file *. Do not use otherwise. | 253 | * last use of a struct file *. Do not use otherwise. |
210 | */ | 254 | */ |
@@ -230,10 +274,10 @@ void __fput(struct file *file) | |||
230 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) | 274 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) |
231 | cdev_put(inode->i_cdev); | 275 | cdev_put(inode->i_cdev); |
232 | fops_put(file->f_op); | 276 | fops_put(file->f_op); |
233 | if (file->f_mode & FMODE_WRITE) | ||
234 | put_write_access(inode); | ||
235 | put_pid(file->f_owner.pid); | 277 | put_pid(file->f_owner.pid); |
236 | file_kill(file); | 278 | file_kill(file); |
279 | if (file->f_mode & FMODE_WRITE) | ||
280 | drop_file_write_access(file); | ||
237 | file->f_path.dentry = NULL; | 281 | file->f_path.dentry = NULL; |
238 | file->f_path.mnt = NULL; | 282 | file->f_path.mnt = NULL; |
239 | file_free(file); | 283 | file_free(file); |