diff options
author | Jan Kara <jack@suse.cz> | 2012-06-12 10:20:37 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-31 01:45:47 -0400 |
commit | 14da9200140f8d722ad1767dfabadebd8b34f2ad (patch) | |
tree | ea5d88b091999f7a64af0b9d335d7cad4c79edfb /fs/open.c | |
parent | 5d37e9e6dec65cd21be68ee92de99686213e916b (diff) |
fs: Protect write paths by sb_start_write - sb_end_write
There are several entry points which dirty pages in a filesystem. mmap
(handled by block_page_mkwrite()), buffered write (handled by
__generic_file_aio_write()), splice write (generic_file_splice_write),
truncate, and fallocate (these can dirty last partial page - handled inside
each filesystem separately). Protect these places with sb_start_write() and
sb_end_write().
->page_mkwrite() calls are particularly complex since they are called with
mmap_sem held and thus we cannot use standard sb_start_write() due to lock
ordering constraints. We solve the problem by using a special freeze protection
sb_start_pagefault() which ranks below mmap_sem.
BugLink: https://bugs.launchpad.net/bugs/897421
Tested-by: Kamal Mostafa <kamal@canonical.com>
Tested-by: Peter M. Petrakis <peter.petrakis@canonical.com>
Tested-by: Dann Frazier <dann.frazier@canonical.com>
Tested-by: Massimo Morana <massimo.morana@canonical.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 7 |
1 files changed, 6 insertions, 1 deletions
@@ -164,11 +164,13 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) | |||
164 | if (IS_APPEND(inode)) | 164 | if (IS_APPEND(inode)) |
165 | goto out_putf; | 165 | goto out_putf; |
166 | 166 | ||
167 | sb_start_write(inode->i_sb); | ||
167 | error = locks_verify_truncate(inode, file, length); | 168 | error = locks_verify_truncate(inode, file, length); |
168 | if (!error) | 169 | if (!error) |
169 | error = security_path_truncate(&file->f_path); | 170 | error = security_path_truncate(&file->f_path); |
170 | if (!error) | 171 | if (!error) |
171 | error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); | 172 | error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); |
173 | sb_end_write(inode->i_sb); | ||
172 | out_putf: | 174 | out_putf: |
173 | fput(file); | 175 | fput(file); |
174 | out: | 176 | out: |
@@ -266,7 +268,10 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
266 | if (!file->f_op->fallocate) | 268 | if (!file->f_op->fallocate) |
267 | return -EOPNOTSUPP; | 269 | return -EOPNOTSUPP; |
268 | 270 | ||
269 | return file->f_op->fallocate(file, mode, offset, len); | 271 | sb_start_write(inode->i_sb); |
272 | ret = file->f_op->fallocate(file, mode, offset, len); | ||
273 | sb_end_write(inode->i_sb); | ||
274 | return ret; | ||
270 | } | 275 | } |
271 | 276 | ||
272 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | 277 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) |