diff options
author | Josef Bacik <josef@redhat.com> | 2011-07-16 20:44:56 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-20 20:47:59 -0400 |
commit | 02c24a82187d5a628c68edfe71ae60dc135cd178 (patch) | |
tree | c8dbaba4d82e2b20ed4335910a564a1f7d90fcf6 /fs/fuse | |
parent | 22735068d53c7115e384bc88dea95b17e76a6839 (diff) |
fs: push i_mutex and filemap_write_and_wait down into ->fsync() handlers
Btrfs needs to be able to control how filemap_write_and_wait_range() is called
in fsync to make it less of a painful operation, so push down taking i_mutex and
the calling of filemap_write_and_wait() down into the ->fsync() handlers. Some
file systems can drop taking the i_mutex altogether it seems, like ext3 and
ocfs2. For correctness sake I just pushed everything down in all cases to make
sure that we keep the current behavior the same for everybody, and then each
individual fs maintainer can make up their mind about what to do from there.
Thanks,
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 5 | ||||
-rw-r--r-- | fs/fuse/file.c | 24 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 |
3 files changed, 23 insertions, 9 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 02063dde2728..9f63e493a9b6 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -1176,9 +1176,10 @@ static int fuse_dir_release(struct inode *inode, struct file *file) | |||
1176 | return 0; | 1176 | return 0; |
1177 | } | 1177 | } |
1178 | 1178 | ||
1179 | static int fuse_dir_fsync(struct file *file, int datasync) | 1179 | static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, |
1180 | int datasync) | ||
1180 | { | 1181 | { |
1181 | return fuse_fsync_common(file, datasync, 1); | 1182 | return fuse_fsync_common(file, start, end, datasync, 1); |
1182 | } | 1183 | } |
1183 | 1184 | ||
1184 | static bool update_mtime(unsigned ivalid) | 1185 | static bool update_mtime(unsigned ivalid) |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 73b89df20851..7bb685cdd00c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -400,7 +400,8 @@ static void fuse_sync_writes(struct inode *inode) | |||
400 | fuse_release_nowrite(inode); | 400 | fuse_release_nowrite(inode); |
401 | } | 401 | } |
402 | 402 | ||
403 | int fuse_fsync_common(struct file *file, int datasync, int isdir) | 403 | int fuse_fsync_common(struct file *file, loff_t start, loff_t end, |
404 | int datasync, int isdir) | ||
404 | { | 405 | { |
405 | struct inode *inode = file->f_mapping->host; | 406 | struct inode *inode = file->f_mapping->host; |
406 | struct fuse_conn *fc = get_fuse_conn(inode); | 407 | struct fuse_conn *fc = get_fuse_conn(inode); |
@@ -412,9 +413,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir) | |||
412 | if (is_bad_inode(inode)) | 413 | if (is_bad_inode(inode)) |
413 | return -EIO; | 414 | return -EIO; |
414 | 415 | ||
416 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
417 | if (err) | ||
418 | return err; | ||
419 | |||
415 | if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) | 420 | if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) |
416 | return 0; | 421 | return 0; |
417 | 422 | ||
423 | mutex_lock(&inode->i_mutex); | ||
424 | |||
418 | /* | 425 | /* |
419 | * Start writeback against all dirty pages of the inode, then | 426 | * Start writeback against all dirty pages of the inode, then |
420 | * wait for all outstanding writes, before sending the FSYNC | 427 | * wait for all outstanding writes, before sending the FSYNC |
@@ -422,13 +429,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir) | |||
422 | */ | 429 | */ |
423 | err = write_inode_now(inode, 0); | 430 | err = write_inode_now(inode, 0); |
424 | if (err) | 431 | if (err) |
425 | return err; | 432 | goto out; |
426 | 433 | ||
427 | fuse_sync_writes(inode); | 434 | fuse_sync_writes(inode); |
428 | 435 | ||
429 | req = fuse_get_req(fc); | 436 | req = fuse_get_req(fc); |
430 | if (IS_ERR(req)) | 437 | if (IS_ERR(req)) { |
431 | return PTR_ERR(req); | 438 | err = PTR_ERR(req); |
439 | goto out; | ||
440 | } | ||
432 | 441 | ||
433 | memset(&inarg, 0, sizeof(inarg)); | 442 | memset(&inarg, 0, sizeof(inarg)); |
434 | inarg.fh = ff->fh; | 443 | inarg.fh = ff->fh; |
@@ -448,12 +457,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir) | |||
448 | fc->no_fsync = 1; | 457 | fc->no_fsync = 1; |
449 | err = 0; | 458 | err = 0; |
450 | } | 459 | } |
460 | out: | ||
461 | mutex_unlock(&inode->i_mutex); | ||
451 | return err; | 462 | return err; |
452 | } | 463 | } |
453 | 464 | ||
454 | static int fuse_fsync(struct file *file, int datasync) | 465 | static int fuse_fsync(struct file *file, loff_t start, loff_t end, |
466 | int datasync) | ||
455 | { | 467 | { |
456 | return fuse_fsync_common(file, datasync, 0); | 468 | return fuse_fsync_common(file, start, end, datasync, 0); |
457 | } | 469 | } |
458 | 470 | ||
459 | void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, | 471 | void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index b788becada76..c6aa2d4b8517 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -589,7 +589,8 @@ void fuse_release_common(struct file *file, int opcode); | |||
589 | /** | 589 | /** |
590 | * Send FSYNC or FSYNCDIR request | 590 | * Send FSYNC or FSYNCDIR request |
591 | */ | 591 | */ |
592 | int fuse_fsync_common(struct file *file, int datasync, int isdir); | 592 | int fuse_fsync_common(struct file *file, loff_t start, loff_t end, |
593 | int datasync, int isdir); | ||
593 | 594 | ||
594 | /** | 595 | /** |
595 | * Notify poll wakeup | 596 | * Notify poll wakeup |