diff options
71 files changed, 462 insertions, 164 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 9b6ed7c9f34f..ca7e25292542 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -412,7 +412,7 @@ prototypes: | |||
412 | int (*open) (struct inode *, struct file *); | 412 | int (*open) (struct inode *, struct file *); |
413 | int (*flush) (struct file *); | 413 | int (*flush) (struct file *); |
414 | int (*release) (struct inode *, struct file *); | 414 | int (*release) (struct inode *, struct file *); |
415 | int (*fsync) (struct file *, int datasync); | 415 | int (*fsync) (struct file *, loff_t start, loff_t end, int datasync); |
416 | int (*aio_fsync) (struct kiocb *, int datasync); | 416 | int (*aio_fsync) (struct kiocb *, int datasync); |
417 | int (*fasync) (int, struct file *, int); | 417 | int (*fasync) (int, struct file *, int); |
418 | int (*lock) (struct file *, int, struct file_lock *); | 418 | int (*lock) (struct file *, int, struct file_lock *); |
@@ -438,9 +438,7 @@ prototypes: | |||
438 | 438 | ||
439 | locking rules: | 439 | locking rules: |
440 | All may block except for ->setlease. | 440 | All may block except for ->setlease. |
441 | No VFS locks held on entry except for ->fsync and ->setlease. | 441 | No VFS locks held on entry except for ->setlease. |
442 | |||
443 | ->fsync() has i_mutex on inode. | ||
444 | 442 | ||
445 | ->setlease has the file_list_lock held and must not sleep. | 443 | ->setlease has the file_list_lock held and must not sleep. |
446 | 444 | ||
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 6b96773e27cb..7f8861d341ea 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting | |||
@@ -421,3 +421,10 @@ data and there is a virtual hole at the end of the file. So if the provided | |||
421 | offset is less than i_size and SEEK_DATA is specified, return the same offset. | 421 | offset is less than i_size and SEEK_DATA is specified, return the same offset. |
422 | If the above is true for the offset and you are given SEEK_HOLE, return the end | 422 | If the above is true for the offset and you are given SEEK_HOLE, return the end |
423 | of the file. If the offset is i_size or greater return -ENXIO in either case. | 423 | of the file. If the offset is i_size or greater return -ENXIO in either case. |
424 | |||
425 | [mandatory] | ||
426 | If you have your own ->fsync() you must make sure to call | ||
427 | filemap_write_and_wait_range() so that all dirty pages are synced out properly. | ||
428 | You must also keep in mind that ->fsync() is not called with i_mutex held | ||
429 | anymore, so if you require i_mutex locking you must make sure to take it and | ||
430 | release it yourself. | ||
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 6bf85b78cfea..eff6617c9a0f 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -777,7 +777,7 @@ struct file_operations { | |||
777 | int (*open) (struct inode *, struct file *); | 777 | int (*open) (struct inode *, struct file *); |
778 | int (*flush) (struct file *); | 778 | int (*flush) (struct file *); |
779 | int (*release) (struct inode *, struct file *); | 779 | int (*release) (struct inode *, struct file *); |
780 | int (*fsync) (struct file *, int datasync); | 780 | int (*fsync) (struct file *, loff_t, loff_t, int datasync); |
781 | int (*aio_fsync) (struct kiocb *, int datasync); | 781 | int (*aio_fsync) (struct kiocb *, int datasync); |
782 | int (*fasync) (int, struct file *, int); | 782 | int (*fasync) (int, struct file *, int); |
783 | int (*lock) (struct file *, int, struct file_lock *); | 783 | int (*lock) (struct file *, int, struct file_lock *); |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 3c7c3f82d842..fb59c46e9e9e 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -1850,9 +1850,16 @@ out: | |||
1850 | return ret; | 1850 | return ret; |
1851 | } | 1851 | } |
1852 | 1852 | ||
1853 | static int spufs_mfc_fsync(struct file *file, int datasync) | 1853 | static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
1854 | { | 1854 | { |
1855 | return spufs_mfc_flush(file, NULL); | 1855 | struct inode *inode = file->f_path.dentry->d_inode; |
1856 | int err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
1857 | if (!err) { | ||
1858 | mutex_lock(&inode->i_mutex); | ||
1859 | err = spufs_mfc_flush(file, NULL); | ||
1860 | mutex_unlock(&inode->i_mutex); | ||
1861 | } | ||
1862 | return err; | ||
1856 | } | 1863 | } |
1857 | 1864 | ||
1858 | static int spufs_mfc_fasync(int fd, struct file *file, int on) | 1865 | static int spufs_mfc_fasync(int fd, struct file *file, int on) |
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index 5a06787e5be3..d0c57c2e2909 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c | |||
@@ -309,9 +309,14 @@ static int ps3flash_flush(struct file *file, fl_owner_t id) | |||
309 | return ps3flash_writeback(ps3flash_dev); | 309 | return ps3flash_writeback(ps3flash_dev); |
310 | } | 310 | } |
311 | 311 | ||
312 | static int ps3flash_fsync(struct file *file, int datasync) | 312 | static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
313 | { | 313 | { |
314 | return ps3flash_writeback(ps3flash_dev); | 314 | struct inode *inode = file->f_path.dentry->d_inode; |
315 | int err; | ||
316 | mutex_lock(&inode->i_mutex); | ||
317 | err = ps3flash_writeback(ps3flash_dev); | ||
318 | mutex_unlock(&inode->i_mutex); | ||
319 | return err; | ||
315 | } | 320 | } |
316 | 321 | ||
317 | static irqreturn_t ps3flash_interrupt(int irq, void *data) | 322 | static irqreturn_t ps3flash_interrupt(int irq, void *data) |
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 191f3bb3c41a..3320a50ba4f0 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c | |||
@@ -189,12 +189,16 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) | |||
189 | return new_offset; | 189 | return new_offset; |
190 | } | 190 | } |
191 | 191 | ||
192 | static int vol_cdev_fsync(struct file *file, int datasync) | 192 | static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
193 | { | 193 | { |
194 | struct ubi_volume_desc *desc = file->private_data; | 194 | struct ubi_volume_desc *desc = file->private_data; |
195 | struct ubi_device *ubi = desc->vol->ubi; | 195 | struct ubi_device *ubi = desc->vol->ubi; |
196 | 196 | struct inode *inode = file->f_path.dentry->d_inode; | |
197 | return ubi_sync(ubi->ubi_num); | 197 | int err; |
198 | mutex_lock(&inode->i_mutex); | ||
199 | err = ubi_sync(ubi->ubi_num); | ||
200 | mutex_unlock(&inode->i_mutex); | ||
201 | return err; | ||
198 | } | 202 | } |
199 | 203 | ||
200 | 204 | ||
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index c0f0ac7c1cdb..f3c6060c96b8 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c | |||
@@ -887,11 +887,16 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb) | |||
887 | /* | 887 | /* |
888 | * We want fsync() to work on POHMELFS. | 888 | * We want fsync() to work on POHMELFS. |
889 | */ | 889 | */ |
890 | static int pohmelfs_fsync(struct file *file, int datasync) | 890 | static int pohmelfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
891 | { | 891 | { |
892 | struct inode *inode = file->f_mapping->host; | 892 | struct inode *inode = file->f_mapping->host; |
893 | 893 | int err = filemap_write_and_wait_range(inode->i_mapping, start, end); | |
894 | return sync_inode_metadata(inode, 1); | 894 | if (!err) { |
895 | mutex_lock(&inode->i_mutex); | ||
896 | err = sync_inode_metadata(inode, 1); | ||
897 | mutex_unlock(&inode->i_mutex); | ||
898 | } | ||
899 | return err; | ||
895 | } | 900 | } |
896 | 901 | ||
897 | ssize_t pohmelfs_write(struct file *file, const char __user *buf, | 902 | ssize_t pohmelfs_write(struct file *file, const char __user *buf, |
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 271ef94668e7..978e6a101bf2 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c | |||
@@ -795,12 +795,14 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) | |||
795 | } | 795 | } |
796 | 796 | ||
797 | static int | 797 | static int |
798 | printer_fsync(struct file *fd, int datasync) | 798 | printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) |
799 | { | 799 | { |
800 | struct printer_dev *dev = fd->private_data; | 800 | struct printer_dev *dev = fd->private_data; |
801 | struct inode *inode = fd->f_path.dentry->d_inode; | ||
801 | unsigned long flags; | 802 | unsigned long flags; |
802 | int tx_list_empty; | 803 | int tx_list_empty; |
803 | 804 | ||
805 | mutex_lock(&inode->i_mutex); | ||
804 | spin_lock_irqsave(&dev->lock, flags); | 806 | spin_lock_irqsave(&dev->lock, flags); |
805 | tx_list_empty = (likely(list_empty(&dev->tx_reqs))); | 807 | tx_list_empty = (likely(list_empty(&dev->tx_reqs))); |
806 | spin_unlock_irqrestore(&dev->lock, flags); | 808 | spin_unlock_irqrestore(&dev->lock, flags); |
@@ -810,6 +812,7 @@ printer_fsync(struct file *fd, int datasync) | |||
810 | wait_event_interruptible(dev->tx_flush_wait, | 812 | wait_event_interruptible(dev->tx_flush_wait, |
811 | (likely(list_empty(&dev->tx_reqs_active)))); | 813 | (likely(list_empty(&dev->tx_reqs_active)))); |
812 | } | 814 | } |
815 | mutex_unlock(&inode->i_mutex); | ||
813 | 816 | ||
814 | return 0; | 817 | return 0; |
815 | } | 818 | } |
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 804000183c5e..32814e8800e0 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c | |||
@@ -66,19 +66,26 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | int fb_deferred_io_fsync(struct file *file, int datasync) | 69 | int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
70 | { | 70 | { |
71 | struct fb_info *info = file->private_data; | 71 | struct fb_info *info = file->private_data; |
72 | struct inode *inode = file->f_path.dentry->d_inode; | ||
73 | int err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
74 | if (err) | ||
75 | return err; | ||
72 | 76 | ||
73 | /* Skip if deferred io is compiled-in but disabled on this fbdev */ | 77 | /* Skip if deferred io is compiled-in but disabled on this fbdev */ |
74 | if (!info->fbdefio) | 78 | if (!info->fbdefio) |
75 | return 0; | 79 | return 0; |
76 | 80 | ||
81 | mutex_lock(&inode->i_mutex); | ||
77 | /* Kill off the delayed work */ | 82 | /* Kill off the delayed work */ |
78 | cancel_delayed_work_sync(&info->deferred_work); | 83 | cancel_delayed_work_sync(&info->deferred_work); |
79 | 84 | ||
80 | /* Run it immediately */ | 85 | /* Run it immediately */ |
81 | return schedule_delayed_work(&info->deferred_work, 0); | 86 | err = schedule_delayed_work(&info->deferred_work, 0); |
87 | mutex_unlock(&inode->i_mutex); | ||
88 | return err; | ||
82 | } | 89 | } |
83 | EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); | 90 | EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); |
84 | 91 | ||
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 4014160903a9..46ce357ca1ab 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -70,7 +70,8 @@ ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); | |||
70 | ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64); | 70 | ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64); |
71 | void v9fs_blank_wstat(struct p9_wstat *wstat); | 71 | void v9fs_blank_wstat(struct p9_wstat *wstat); |
72 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); | 72 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); |
73 | int v9fs_file_fsync_dotl(struct file *filp, int datasync); | 73 | int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, |
74 | int datasync); | ||
74 | ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, | 75 | ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, |
75 | const char __user *, size_t, loff_t *, int); | 76 | const char __user *, size_t, loff_t *, int); |
76 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); | 77 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index ffed55817f0c..3c173fcc2c5a 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -519,32 +519,50 @@ out: | |||
519 | } | 519 | } |
520 | 520 | ||
521 | 521 | ||
522 | static int v9fs_file_fsync(struct file *filp, int datasync) | 522 | static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, |
523 | int datasync) | ||
523 | { | 524 | { |
524 | struct p9_fid *fid; | 525 | struct p9_fid *fid; |
526 | struct inode *inode = filp->f_mapping->host; | ||
525 | struct p9_wstat wstat; | 527 | struct p9_wstat wstat; |
526 | int retval; | 528 | int retval; |
527 | 529 | ||
530 | retval = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
531 | if (retval) | ||
532 | return retval; | ||
533 | |||
534 | mutex_lock(&inode->i_mutex); | ||
528 | P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); | 535 | P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); |
529 | 536 | ||
530 | fid = filp->private_data; | 537 | fid = filp->private_data; |
531 | v9fs_blank_wstat(&wstat); | 538 | v9fs_blank_wstat(&wstat); |
532 | 539 | ||
533 | retval = p9_client_wstat(fid, &wstat); | 540 | retval = p9_client_wstat(fid, &wstat); |
541 | mutex_unlock(&inode->i_mutex); | ||
542 | |||
534 | return retval; | 543 | return retval; |
535 | } | 544 | } |
536 | 545 | ||
537 | int v9fs_file_fsync_dotl(struct file *filp, int datasync) | 546 | int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, |
547 | int datasync) | ||
538 | { | 548 | { |
539 | struct p9_fid *fid; | 549 | struct p9_fid *fid; |
550 | struct inode *inode = filp->f_mapping->host; | ||
540 | int retval; | 551 | int retval; |
541 | 552 | ||
553 | retval = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
554 | if (retval) | ||
555 | return retval; | ||
556 | |||
557 | mutex_lock(&inode->i_mutex); | ||
542 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n", | 558 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n", |
543 | filp, datasync); | 559 | filp, datasync); |
544 | 560 | ||
545 | fid = filp->private_data; | 561 | fid = filp->private_data; |
546 | 562 | ||
547 | retval = p9_client_fsync(fid, datasync); | 563 | retval = p9_client_fsync(fid, datasync); |
564 | mutex_unlock(&inode->i_mutex); | ||
565 | |||
548 | return retval; | 566 | return retval; |
549 | } | 567 | } |
550 | 568 | ||
diff --git a/fs/affs/affs.h b/fs/affs/affs.h index 0e95f73a7023..c2b9c79eb64e 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h | |||
@@ -182,7 +182,7 @@ extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dent | |||
182 | 182 | ||
183 | void affs_free_prealloc(struct inode *inode); | 183 | void affs_free_prealloc(struct inode *inode); |
184 | extern void affs_truncate(struct inode *); | 184 | extern void affs_truncate(struct inode *); |
185 | int affs_file_fsync(struct file *, int); | 185 | int affs_file_fsync(struct file *, loff_t, loff_t, int); |
186 | 186 | ||
187 | /* dir.c */ | 187 | /* dir.c */ |
188 | 188 | ||
diff --git a/fs/affs/file.c b/fs/affs/file.c index acf321b70fcd..2f4c935cb327 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
@@ -923,14 +923,20 @@ affs_truncate(struct inode *inode) | |||
923 | affs_free_prealloc(inode); | 923 | affs_free_prealloc(inode); |
924 | } | 924 | } |
925 | 925 | ||
926 | int affs_file_fsync(struct file *filp, int datasync) | 926 | int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) |
927 | { | 927 | { |
928 | struct inode *inode = filp->f_mapping->host; | 928 | struct inode *inode = filp->f_mapping->host; |
929 | int ret, err; | 929 | int ret, err; |
930 | 930 | ||
931 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
932 | if (err) | ||
933 | return err; | ||
934 | |||
935 | mutex_lock(&inode->i_mutex); | ||
931 | ret = write_inode_now(inode, 0); | 936 | ret = write_inode_now(inode, 0); |
932 | err = sync_blockdev(inode->i_sb->s_bdev); | 937 | err = sync_blockdev(inode->i_sb->s_bdev); |
933 | if (!ret) | 938 | if (!ret) |
934 | ret = err; | 939 | ret = err; |
940 | mutex_unlock(&inode->i_mutex); | ||
935 | return ret; | 941 | return ret; |
936 | } | 942 | } |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f396d337b817..d2b0888126d4 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -750,7 +750,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); | |||
750 | extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, | 750 | extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, |
751 | unsigned long, loff_t); | 751 | unsigned long, loff_t); |
752 | extern int afs_writeback_all(struct afs_vnode *); | 752 | extern int afs_writeback_all(struct afs_vnode *); |
753 | extern int afs_fsync(struct file *, int); | 753 | extern int afs_fsync(struct file *, loff_t, loff_t, int); |
754 | 754 | ||
755 | 755 | ||
756 | /*****************************************************************************/ | 756 | /*****************************************************************************/ |
diff --git a/fs/afs/write.c b/fs/afs/write.c index b806285ff853..9aa52d93c73c 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
@@ -681,9 +681,10 @@ int afs_writeback_all(struct afs_vnode *vnode) | |||
681 | * - the return status from this call provides a reliable indication of | 681 | * - the return status from this call provides a reliable indication of |
682 | * whether any write errors occurred for this process. | 682 | * whether any write errors occurred for this process. |
683 | */ | 683 | */ |
684 | int afs_fsync(struct file *file, int datasync) | 684 | int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
685 | { | 685 | { |
686 | struct dentry *dentry = file->f_path.dentry; | 686 | struct dentry *dentry = file->f_path.dentry; |
687 | struct inode *inode = file->f_mapping->host; | ||
687 | struct afs_writeback *wb, *xwb; | 688 | struct afs_writeback *wb, *xwb; |
688 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); | 689 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); |
689 | int ret; | 690 | int ret; |
@@ -692,12 +693,19 @@ int afs_fsync(struct file *file, int datasync) | |||
692 | vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, | 693 | vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, |
693 | datasync); | 694 | datasync); |
694 | 695 | ||
696 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
697 | if (ret) | ||
698 | return ret; | ||
699 | mutex_lock(&inode->i_mutex); | ||
700 | |||
695 | /* use a writeback record as a marker in the queue - when this reaches | 701 | /* use a writeback record as a marker in the queue - when this reaches |
696 | * the front of the queue, all the outstanding writes are either | 702 | * the front of the queue, all the outstanding writes are either |
697 | * completed or rejected */ | 703 | * completed or rejected */ |
698 | wb = kzalloc(sizeof(*wb), GFP_KERNEL); | 704 | wb = kzalloc(sizeof(*wb), GFP_KERNEL); |
699 | if (!wb) | 705 | if (!wb) { |
700 | return -ENOMEM; | 706 | ret = -ENOMEM; |
707 | goto out; | ||
708 | } | ||
701 | wb->vnode = vnode; | 709 | wb->vnode = vnode; |
702 | wb->first = 0; | 710 | wb->first = 0; |
703 | wb->last = -1; | 711 | wb->last = -1; |
@@ -720,7 +728,7 @@ int afs_fsync(struct file *file, int datasync) | |||
720 | if (ret < 0) { | 728 | if (ret < 0) { |
721 | afs_put_writeback(wb); | 729 | afs_put_writeback(wb); |
722 | _leave(" = %d [wb]", ret); | 730 | _leave(" = %d [wb]", ret); |
723 | return ret; | 731 | goto out; |
724 | } | 732 | } |
725 | 733 | ||
726 | /* wait for the preceding writes to actually complete */ | 734 | /* wait for the preceding writes to actually complete */ |
@@ -729,6 +737,8 @@ int afs_fsync(struct file *file, int datasync) | |||
729 | vnode->writebacks.next == &wb->link); | 737 | vnode->writebacks.next == &wb->link); |
730 | afs_put_writeback(wb); | 738 | afs_put_writeback(wb); |
731 | _leave(" = %d", ret); | 739 | _leave(" = %d", ret); |
740 | out: | ||
741 | mutex_unlock(&inode->i_mutex); | ||
732 | return ret; | 742 | return ret; |
733 | } | 743 | } |
734 | 744 | ||
diff --git a/fs/bad_inode.c b/fs/bad_inode.c index f024d8aaddef..9205cf25f1c6 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c | |||
@@ -87,7 +87,8 @@ static int bad_file_release(struct inode *inode, struct file *filp) | |||
87 | return -EIO; | 87 | return -EIO; |
88 | } | 88 | } |
89 | 89 | ||
90 | static int bad_file_fsync(struct file *file, int datasync) | 90 | static int bad_file_fsync(struct file *file, loff_t start, loff_t end, |
91 | int datasync) | ||
91 | { | 92 | { |
92 | return -EIO; | 93 | return -EIO; |
93 | } | 94 | } |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 966617a422d9..9fb0b15331d3 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -378,7 +378,7 @@ out: | |||
378 | return retval; | 378 | return retval; |
379 | } | 379 | } |
380 | 380 | ||
381 | int blkdev_fsync(struct file *filp, int datasync) | 381 | int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) |
382 | { | 382 | { |
383 | struct inode *bd_inode = filp->f_mapping->host; | 383 | struct inode *bd_inode = filp->f_mapping->host; |
384 | struct block_device *bdev = I_BDEV(bd_inode); | 384 | struct block_device *bdev = I_BDEV(bd_inode); |
@@ -389,14 +389,10 @@ int blkdev_fsync(struct file *filp, int datasync) | |||
389 | * i_mutex and doing so causes performance issues with concurrent | 389 | * i_mutex and doing so causes performance issues with concurrent |
390 | * O_SYNC writers to a block device. | 390 | * O_SYNC writers to a block device. |
391 | */ | 391 | */ |
392 | mutex_unlock(&bd_inode->i_mutex); | ||
393 | |||
394 | error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); | 392 | error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); |
395 | if (error == -EOPNOTSUPP) | 393 | if (error == -EOPNOTSUPP) |
396 | error = 0; | 394 | error = 0; |
397 | 395 | ||
398 | mutex_lock(&bd_inode->i_mutex); | ||
399 | |||
400 | return error; | 396 | return error; |
401 | } | 397 | } |
402 | EXPORT_SYMBOL(blkdev_fsync); | 398 | EXPORT_SYMBOL(blkdev_fsync); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f1ff62bff1b3..82be74efbb26 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2605,7 +2605,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
2605 | int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, | 2605 | int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, |
2606 | struct inode *inode); | 2606 | struct inode *inode); |
2607 | int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); | 2607 | int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); |
2608 | int btrfs_sync_file(struct file *file, int datasync); | 2608 | int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); |
2609 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | 2609 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, |
2610 | int skip_pinned); | 2610 | int skip_pinned); |
2611 | extern const struct file_operations btrfs_file_operations; | 2611 | extern const struct file_operations btrfs_file_operations; |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index bd4d061c6e4d..59cbdb120ad0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1452,7 +1452,7 @@ int btrfs_release_file(struct inode *inode, struct file *filp) | |||
1452 | * important optimization for directories because holding the mutex prevents | 1452 | * important optimization for directories because holding the mutex prevents |
1453 | * new operations on the dir while we write to disk. | 1453 | * new operations on the dir while we write to disk. |
1454 | */ | 1454 | */ |
1455 | int btrfs_sync_file(struct file *file, int datasync) | 1455 | int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) |
1456 | { | 1456 | { |
1457 | struct dentry *dentry = file->f_path.dentry; | 1457 | struct dentry *dentry = file->f_path.dentry; |
1458 | struct inode *inode = dentry->d_inode; | 1458 | struct inode *inode = dentry->d_inode; |
@@ -1462,9 +1462,13 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
1462 | 1462 | ||
1463 | trace_btrfs_sync_file(file, datasync); | 1463 | trace_btrfs_sync_file(file, datasync); |
1464 | 1464 | ||
1465 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
1466 | if (ret) | ||
1467 | return ret; | ||
1468 | mutex_lock(&inode->i_mutex); | ||
1469 | |||
1465 | /* we wait first, since the writeback may change the inode */ | 1470 | /* we wait first, since the writeback may change the inode */ |
1466 | root->log_batch++; | 1471 | root->log_batch++; |
1467 | /* the VFS called filemap_fdatawrite for us */ | ||
1468 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | 1472 | btrfs_wait_ordered_range(inode, 0, (u64)-1); |
1469 | root->log_batch++; | 1473 | root->log_batch++; |
1470 | 1474 | ||
@@ -1472,8 +1476,10 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
1472 | * check the transaction that last modified this inode | 1476 | * check the transaction that last modified this inode |
1473 | * and see if its already been committed | 1477 | * and see if its already been committed |
1474 | */ | 1478 | */ |
1475 | if (!BTRFS_I(inode)->last_trans) | 1479 | if (!BTRFS_I(inode)->last_trans) { |
1480 | mutex_unlock(&inode->i_mutex); | ||
1476 | goto out; | 1481 | goto out; |
1482 | } | ||
1477 | 1483 | ||
1478 | /* | 1484 | /* |
1479 | * if the last transaction that changed this file was before | 1485 | * if the last transaction that changed this file was before |
@@ -1484,6 +1490,7 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
1484 | if (BTRFS_I(inode)->last_trans <= | 1490 | if (BTRFS_I(inode)->last_trans <= |
1485 | root->fs_info->last_trans_committed) { | 1491 | root->fs_info->last_trans_committed) { |
1486 | BTRFS_I(inode)->last_trans = 0; | 1492 | BTRFS_I(inode)->last_trans = 0; |
1493 | mutex_unlock(&inode->i_mutex); | ||
1487 | goto out; | 1494 | goto out; |
1488 | } | 1495 | } |
1489 | 1496 | ||
@@ -1496,12 +1503,15 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
1496 | trans = btrfs_start_transaction(root, 0); | 1503 | trans = btrfs_start_transaction(root, 0); |
1497 | if (IS_ERR(trans)) { | 1504 | if (IS_ERR(trans)) { |
1498 | ret = PTR_ERR(trans); | 1505 | ret = PTR_ERR(trans); |
1506 | mutex_unlock(&inode->i_mutex); | ||
1499 | goto out; | 1507 | goto out; |
1500 | } | 1508 | } |
1501 | 1509 | ||
1502 | ret = btrfs_log_dentry_safe(trans, root, dentry); | 1510 | ret = btrfs_log_dentry_safe(trans, root, dentry); |
1503 | if (ret < 0) | 1511 | if (ret < 0) { |
1512 | mutex_unlock(&inode->i_mutex); | ||
1504 | goto out; | 1513 | goto out; |
1514 | } | ||
1505 | 1515 | ||
1506 | /* we've logged all the items and now have a consistent | 1516 | /* we've logged all the items and now have a consistent |
1507 | * version of the file in the log. It is possible that | 1517 | * version of the file in the log. It is possible that |
@@ -1513,7 +1523,7 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
1513 | * file again, but that will end up using the synchronization | 1523 | * file again, but that will end up using the synchronization |
1514 | * inside btrfs_sync_log to keep things safe. | 1524 | * inside btrfs_sync_log to keep things safe. |
1515 | */ | 1525 | */ |
1516 | mutex_unlock(&dentry->d_inode->i_mutex); | 1526 | mutex_unlock(&inode->i_mutex); |
1517 | 1527 | ||
1518 | if (ret != BTRFS_NO_LOG_SYNC) { | 1528 | if (ret != BTRFS_NO_LOG_SYNC) { |
1519 | if (ret > 0) { | 1529 | if (ret > 0) { |
@@ -1528,7 +1538,6 @@ int btrfs_sync_file(struct file *file, int datasync) | |||
1528 | } else { | 1538 | } else { |
1529 | ret = btrfs_end_transaction(trans, root); | 1539 | ret = btrfs_end_transaction(trans, root); |
1530 | } | 1540 | } |
1531 | mutex_lock(&dentry->d_inode->i_mutex); | ||
1532 | out: | 1541 | out: |
1533 | return ret > 0 ? -EIO : ret; | 1542 | return ret > 0 ? -EIO : ret; |
1534 | } | 1543 | } |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index f605753c8fe9..8d74ad7ba556 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -1811,7 +1811,7 @@ out: | |||
1811 | spin_unlock(&ci->i_unsafe_lock); | 1811 | spin_unlock(&ci->i_unsafe_lock); |
1812 | } | 1812 | } |
1813 | 1813 | ||
1814 | int ceph_fsync(struct file *file, int datasync) | 1814 | int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
1815 | { | 1815 | { |
1816 | struct inode *inode = file->f_mapping->host; | 1816 | struct inode *inode = file->f_mapping->host; |
1817 | struct ceph_inode_info *ci = ceph_inode(inode); | 1817 | struct ceph_inode_info *ci = ceph_inode(inode); |
@@ -1822,9 +1822,10 @@ int ceph_fsync(struct file *file, int datasync) | |||
1822 | dout("fsync %p%s\n", inode, datasync ? " datasync" : ""); | 1822 | dout("fsync %p%s\n", inode, datasync ? " datasync" : ""); |
1823 | sync_write_wait(inode); | 1823 | sync_write_wait(inode); |
1824 | 1824 | ||
1825 | ret = filemap_write_and_wait(inode->i_mapping); | 1825 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); |
1826 | if (ret < 0) | 1826 | if (ret < 0) |
1827 | return ret; | 1827 | return ret; |
1828 | mutex_lock(&inode->i_mutex); | ||
1828 | 1829 | ||
1829 | dirty = try_flush_caps(inode, NULL, &flush_tid); | 1830 | dirty = try_flush_caps(inode, NULL, &flush_tid); |
1830 | dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); | 1831 | dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); |
@@ -1841,6 +1842,7 @@ int ceph_fsync(struct file *file, int datasync) | |||
1841 | } | 1842 | } |
1842 | 1843 | ||
1843 | dout("fsync %p%s done\n", inode, datasync ? " datasync" : ""); | 1844 | dout("fsync %p%s done\n", inode, datasync ? " datasync" : ""); |
1845 | mutex_unlock(&inode->i_mutex); | ||
1844 | return ret; | 1846 | return ret; |
1845 | } | 1847 | } |
1846 | 1848 | ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 0972b457a03f..1065ac779840 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -1118,7 +1118,8 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size, | |||
1118 | * an fsync() on a dir will wait for any uncommitted directory | 1118 | * an fsync() on a dir will wait for any uncommitted directory |
1119 | * operations to commit. | 1119 | * operations to commit. |
1120 | */ | 1120 | */ |
1121 | static int ceph_dir_fsync(struct file *file, int datasync) | 1121 | static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, |
1122 | int datasync) | ||
1122 | { | 1123 | { |
1123 | struct inode *inode = file->f_path.dentry->d_inode; | 1124 | struct inode *inode = file->f_path.dentry->d_inode; |
1124 | struct ceph_inode_info *ci = ceph_inode(inode); | 1125 | struct ceph_inode_info *ci = ceph_inode(inode); |
@@ -1128,6 +1129,11 @@ static int ceph_dir_fsync(struct file *file, int datasync) | |||
1128 | int ret = 0; | 1129 | int ret = 0; |
1129 | 1130 | ||
1130 | dout("dir_fsync %p\n", inode); | 1131 | dout("dir_fsync %p\n", inode); |
1132 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
1133 | if (ret) | ||
1134 | return ret; | ||
1135 | mutex_lock(&inode->i_mutex); | ||
1136 | |||
1131 | spin_lock(&ci->i_unsafe_lock); | 1137 | spin_lock(&ci->i_unsafe_lock); |
1132 | if (list_empty(head)) | 1138 | if (list_empty(head)) |
1133 | goto out; | 1139 | goto out; |
@@ -1161,6 +1167,8 @@ static int ceph_dir_fsync(struct file *file, int datasync) | |||
1161 | } while (req->r_tid < last_tid); | 1167 | } while (req->r_tid < last_tid); |
1162 | out: | 1168 | out: |
1163 | spin_unlock(&ci->i_unsafe_lock); | 1169 | spin_unlock(&ci->i_unsafe_lock); |
1170 | mutex_unlock(&inode->i_mutex); | ||
1171 | |||
1164 | return ret; | 1172 | return ret; |
1165 | } | 1173 | } |
1166 | 1174 | ||
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 56c41ef47cad..30446b144e3d 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -728,7 +728,8 @@ extern void ceph_put_cap(struct ceph_mds_client *mdsc, | |||
728 | 728 | ||
729 | extern void ceph_queue_caps_release(struct inode *inode); | 729 | extern void ceph_queue_caps_release(struct inode *inode); |
730 | extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc); | 730 | extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc); |
731 | extern int ceph_fsync(struct file *file, int datasync); | 731 | extern int ceph_fsync(struct file *file, loff_t start, loff_t end, |
732 | int datasync); | ||
732 | extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, | 733 | extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, |
733 | struct ceph_mds_session *session); | 734 | struct ceph_mds_session *session); |
734 | extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, | 735 | extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 036ca83e5f46..fbd050c8d52a 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -91,8 +91,8 @@ extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, | |||
91 | extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | 91 | extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, |
92 | unsigned long nr_segs, loff_t pos); | 92 | unsigned long nr_segs, loff_t pos); |
93 | extern int cifs_lock(struct file *, int, struct file_lock *); | 93 | extern int cifs_lock(struct file *, int, struct file_lock *); |
94 | extern int cifs_fsync(struct file *, int); | 94 | extern int cifs_fsync(struct file *, loff_t, loff_t, int); |
95 | extern int cifs_strict_fsync(struct file *, int); | 95 | extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int); |
96 | extern int cifs_flush(struct file *, fl_owner_t id); | 96 | extern int cifs_flush(struct file *, fl_owner_t id); |
97 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); | 97 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); |
98 | extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); | 98 | extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index bb71471a4d9d..cef584451113 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1401,7 +1401,8 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
1401 | return rc; | 1401 | return rc; |
1402 | } | 1402 | } |
1403 | 1403 | ||
1404 | int cifs_strict_fsync(struct file *file, int datasync) | 1404 | int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, |
1405 | int datasync) | ||
1405 | { | 1406 | { |
1406 | int xid; | 1407 | int xid; |
1407 | int rc = 0; | 1408 | int rc = 0; |
@@ -1410,6 +1411,11 @@ int cifs_strict_fsync(struct file *file, int datasync) | |||
1410 | struct inode *inode = file->f_path.dentry->d_inode; | 1411 | struct inode *inode = file->f_path.dentry->d_inode; |
1411 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1412 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1412 | 1413 | ||
1414 | rc = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
1415 | if (rc) | ||
1416 | return rc; | ||
1417 | mutex_lock(&inode->i_mutex); | ||
1418 | |||
1413 | xid = GetXid(); | 1419 | xid = GetXid(); |
1414 | 1420 | ||
1415 | cFYI(1, "Sync file - name: %s datasync: 0x%x", | 1421 | cFYI(1, "Sync file - name: %s datasync: 0x%x", |
@@ -1428,16 +1434,23 @@ int cifs_strict_fsync(struct file *file, int datasync) | |||
1428 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | 1434 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); |
1429 | 1435 | ||
1430 | FreeXid(xid); | 1436 | FreeXid(xid); |
1437 | mutex_unlock(&inode->i_mutex); | ||
1431 | return rc; | 1438 | return rc; |
1432 | } | 1439 | } |
1433 | 1440 | ||
1434 | int cifs_fsync(struct file *file, int datasync) | 1441 | int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
1435 | { | 1442 | { |
1436 | int xid; | 1443 | int xid; |
1437 | int rc = 0; | 1444 | int rc = 0; |
1438 | struct cifs_tcon *tcon; | 1445 | struct cifs_tcon *tcon; |
1439 | struct cifsFileInfo *smbfile = file->private_data; | 1446 | struct cifsFileInfo *smbfile = file->private_data; |
1440 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1447 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1448 | struct inode *inode = file->f_mapping->host; | ||
1449 | |||
1450 | rc = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
1451 | if (rc) | ||
1452 | return rc; | ||
1453 | mutex_lock(&inode->i_mutex); | ||
1441 | 1454 | ||
1442 | xid = GetXid(); | 1455 | xid = GetXid(); |
1443 | 1456 | ||
@@ -1449,6 +1462,7 @@ int cifs_fsync(struct file *file, int datasync) | |||
1449 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | 1462 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); |
1450 | 1463 | ||
1451 | FreeXid(xid); | 1464 | FreeXid(xid); |
1465 | mutex_unlock(&inode->i_mutex); | ||
1452 | return rc; | 1466 | return rc; |
1453 | } | 1467 | } |
1454 | 1468 | ||
diff --git a/fs/coda/coda_int.h b/fs/coda/coda_int.h index 6b443ff43a19..b7143cf783ac 100644 --- a/fs/coda/coda_int.h +++ b/fs/coda/coda_int.h | |||
@@ -11,7 +11,7 @@ extern int coda_fake_statfs; | |||
11 | 11 | ||
12 | void coda_destroy_inodecache(void); | 12 | void coda_destroy_inodecache(void); |
13 | int coda_init_inodecache(void); | 13 | int coda_init_inodecache(void); |
14 | int coda_fsync(struct file *coda_file, int datasync); | 14 | int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync); |
15 | void coda_sysctl_init(void); | 15 | void coda_sysctl_init(void); |
16 | void coda_sysctl_clean(void); | 16 | void coda_sysctl_clean(void); |
17 | 17 | ||
diff --git a/fs/coda/file.c b/fs/coda/file.c index 0433057be330..8edd404e6419 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c | |||
@@ -199,7 +199,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file) | |||
199 | return 0; | 199 | return 0; |
200 | } | 200 | } |
201 | 201 | ||
202 | int coda_fsync(struct file *coda_file, int datasync) | 202 | int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) |
203 | { | 203 | { |
204 | struct file *host_file; | 204 | struct file *host_file; |
205 | struct inode *coda_inode = coda_file->f_path.dentry->d_inode; | 205 | struct inode *coda_inode = coda_file->f_path.dentry->d_inode; |
@@ -210,6 +210,11 @@ int coda_fsync(struct file *coda_file, int datasync) | |||
210 | S_ISLNK(coda_inode->i_mode))) | 210 | S_ISLNK(coda_inode->i_mode))) |
211 | return -EINVAL; | 211 | return -EINVAL; |
212 | 212 | ||
213 | err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end); | ||
214 | if (err) | ||
215 | return err; | ||
216 | mutex_lock(&coda_inode->i_mutex); | ||
217 | |||
213 | cfi = CODA_FTOC(coda_file); | 218 | cfi = CODA_FTOC(coda_file); |
214 | BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); | 219 | BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); |
215 | host_file = cfi->cfi_container; | 220 | host_file = cfi->cfi_container; |
@@ -217,6 +222,7 @@ int coda_fsync(struct file *coda_file, int datasync) | |||
217 | err = vfs_fsync(host_file, datasync); | 222 | err = vfs_fsync(host_file, datasync); |
218 | if (!err && !datasync) | 223 | if (!err && !datasync) |
219 | err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); | 224 | err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); |
225 | mutex_unlock(&coda_inode->i_mutex); | ||
220 | 226 | ||
221 | return err; | 227 | return err; |
222 | } | 228 | } |
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 4ec9eb00a241..c6ac98cf9baa 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
@@ -270,14 +270,15 @@ static int ecryptfs_release(struct inode *inode, struct file *file) | |||
270 | } | 270 | } |
271 | 271 | ||
272 | static int | 272 | static int |
273 | ecryptfs_fsync(struct file *file, int datasync) | 273 | ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
274 | { | 274 | { |
275 | int rc = 0; | 275 | int rc = 0; |
276 | 276 | ||
277 | rc = generic_file_fsync(file, datasync); | 277 | rc = generic_file_fsync(file, start, end, datasync); |
278 | if (rc) | 278 | if (rc) |
279 | goto out; | 279 | goto out; |
280 | rc = vfs_fsync(ecryptfs_file_to_lower(file), datasync); | 280 | rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end, |
281 | datasync); | ||
281 | out: | 282 | out: |
282 | return rc; | 283 | return rc; |
283 | } | 284 | } |
diff --git a/fs/exofs/file.c b/fs/exofs/file.c index 45ca323d8363..491c6c078e7f 100644 --- a/fs/exofs/file.c +++ b/fs/exofs/file.c | |||
@@ -42,11 +42,19 @@ static int exofs_release_file(struct inode *inode, struct file *filp) | |||
42 | * Note, in exofs all metadata is written as part of inode, regardless. | 42 | * Note, in exofs all metadata is written as part of inode, regardless. |
43 | * The writeout is synchronous | 43 | * The writeout is synchronous |
44 | */ | 44 | */ |
45 | static int exofs_file_fsync(struct file *filp, int datasync) | 45 | static int exofs_file_fsync(struct file *filp, loff_t start, loff_t end, |
46 | int datasync) | ||
46 | { | 47 | { |
48 | struct inode *inode = filp->f_mapping->host; | ||
47 | int ret; | 49 | int ret; |
48 | 50 | ||
51 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
52 | if (ret) | ||
53 | return ret; | ||
54 | |||
55 | mutex_lock(&inode->i_mutex); | ||
49 | ret = sync_inode_metadata(filp->f_mapping->host, 1); | 56 | ret = sync_inode_metadata(filp->f_mapping->host, 1); |
57 | mutex_unlock(&inode->i_mutex); | ||
50 | return ret; | 58 | return ret; |
51 | } | 59 | } |
52 | 60 | ||
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 645be9e7ee47..af9fc89b1b2d 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -150,7 +150,8 @@ extern void ext2_write_super (struct super_block *); | |||
150 | extern const struct file_operations ext2_dir_operations; | 150 | extern const struct file_operations ext2_dir_operations; |
151 | 151 | ||
152 | /* file.c */ | 152 | /* file.c */ |
153 | extern int ext2_fsync(struct file *file, int datasync); | 153 | extern int ext2_fsync(struct file *file, loff_t start, loff_t end, |
154 | int datasync); | ||
154 | extern const struct inode_operations ext2_file_inode_operations; | 155 | extern const struct inode_operations ext2_file_inode_operations; |
155 | extern const struct file_operations ext2_file_operations; | 156 | extern const struct file_operations ext2_file_operations; |
156 | extern const struct file_operations ext2_xip_file_operations; | 157 | extern const struct file_operations ext2_xip_file_operations; |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 49eec9456c5b..82e06321de35 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp) | |||
40 | return 0; | 40 | return 0; |
41 | } | 41 | } |
42 | 42 | ||
43 | int ext2_fsync(struct file *file, int datasync) | 43 | int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
44 | { | 44 | { |
45 | int ret; | 45 | int ret; |
46 | struct super_block *sb = file->f_mapping->host->i_sb; | 46 | struct super_block *sb = file->f_mapping->host->i_sb; |
47 | struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; | 47 | struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; |
48 | 48 | ||
49 | ret = generic_file_fsync(file, datasync); | 49 | ret = generic_file_fsync(file, start, end, datasync); |
50 | if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { | 50 | if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { |
51 | /* We don't really know where the IO error happened... */ | 51 | /* We don't really know where the IO error happened... */ |
52 | ext2_error(sb, __func__, | 52 | ext2_error(sb, __func__, |
diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c index 09b13bb34c94..0bcf63adb80a 100644 --- a/fs/ext3/fsync.c +++ b/fs/ext3/fsync.c | |||
@@ -43,7 +43,7 @@ | |||
43 | * inode to disk. | 43 | * inode to disk. |
44 | */ | 44 | */ |
45 | 45 | ||
46 | int ext3_sync_file(struct file *file, int datasync) | 46 | int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) |
47 | { | 47 | { |
48 | struct inode *inode = file->f_mapping->host; | 48 | struct inode *inode = file->f_mapping->host; |
49 | struct ext3_inode_info *ei = EXT3_I(inode); | 49 | struct ext3_inode_info *ei = EXT3_I(inode); |
@@ -54,6 +54,17 @@ int ext3_sync_file(struct file *file, int datasync) | |||
54 | if (inode->i_sb->s_flags & MS_RDONLY) | 54 | if (inode->i_sb->s_flags & MS_RDONLY) |
55 | return 0; | 55 | return 0; |
56 | 56 | ||
57 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
58 | if (ret) | ||
59 | return ret; | ||
60 | |||
61 | /* | ||
62 | * Taking the mutex here just to keep consistent with how fsync was | ||
63 | * called previously, however it looks like we don't need to take | ||
64 | * i_mutex at all. | ||
65 | */ | ||
66 | mutex_lock(&inode->i_mutex); | ||
67 | |||
57 | J_ASSERT(ext3_journal_current_handle() == NULL); | 68 | J_ASSERT(ext3_journal_current_handle() == NULL); |
58 | 69 | ||
59 | /* | 70 | /* |
@@ -70,8 +81,10 @@ int ext3_sync_file(struct file *file, int datasync) | |||
70 | * (they were dirtied by commit). But that's OK - the blocks are | 81 | * (they were dirtied by commit). But that's OK - the blocks are |
71 | * safe in-journal, which is all fsync() needs to ensure. | 82 | * safe in-journal, which is all fsync() needs to ensure. |
72 | */ | 83 | */ |
73 | if (ext3_should_journal_data(inode)) | 84 | if (ext3_should_journal_data(inode)) { |
85 | mutex_unlock(&inode->i_mutex); | ||
74 | return ext3_force_commit(inode->i_sb); | 86 | return ext3_force_commit(inode->i_sb); |
87 | } | ||
75 | 88 | ||
76 | if (datasync) | 89 | if (datasync) |
77 | commit_tid = atomic_read(&ei->i_datasync_tid); | 90 | commit_tid = atomic_read(&ei->i_datasync_tid); |
@@ -91,5 +104,6 @@ int ext3_sync_file(struct file *file, int datasync) | |||
91 | */ | 104 | */ |
92 | if (needs_barrier) | 105 | if (needs_barrier) |
93 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 106 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
107 | mutex_unlock(&inode->i_mutex); | ||
94 | return ret; | 108 | return ret; |
95 | } | 109 | } |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 1921392cd708..fa44df879711 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1758,7 +1758,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, | |||
1758 | extern void ext4_htree_free_dir_info(struct dir_private_info *p); | 1758 | extern void ext4_htree_free_dir_info(struct dir_private_info *p); |
1759 | 1759 | ||
1760 | /* fsync.c */ | 1760 | /* fsync.c */ |
1761 | extern int ext4_sync_file(struct file *, int); | 1761 | extern int ext4_sync_file(struct file *, loff_t, loff_t, int); |
1762 | extern int ext4_flush_completed_IO(struct inode *); | 1762 | extern int ext4_flush_completed_IO(struct inode *); |
1763 | 1763 | ||
1764 | /* hash.c */ | 1764 | /* hash.c */ |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index ce66d2fe826c..da3bed3e0c29 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -151,6 +151,32 @@ static int ext4_sync_parent(struct inode *inode) | |||
151 | return ret; | 151 | return ret; |
152 | } | 152 | } |
153 | 153 | ||
154 | /** | ||
155 | * __sync_file - generic_file_fsync without the locking and filemap_write | ||
156 | * @inode: inode to sync | ||
157 | * @datasync: only sync essential metadata if true | ||
158 | * | ||
159 | * This is just generic_file_fsync without the locking. This is needed for | ||
160 | * nojournal mode to make sure this inodes data/metadata makes it to disk | ||
161 | * properly. The i_mutex should be held already. | ||
162 | */ | ||
163 | static int __sync_inode(struct inode *inode, int datasync) | ||
164 | { | ||
165 | int err; | ||
166 | int ret; | ||
167 | |||
168 | ret = sync_mapping_buffers(inode->i_mapping); | ||
169 | if (!(inode->i_state & I_DIRTY)) | ||
170 | return ret; | ||
171 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
172 | return ret; | ||
173 | |||
174 | err = sync_inode_metadata(inode, 1); | ||
175 | if (ret == 0) | ||
176 | ret = err; | ||
177 | return ret; | ||
178 | } | ||
179 | |||
154 | /* | 180 | /* |
155 | * akpm: A new design for ext4_sync_file(). | 181 | * akpm: A new design for ext4_sync_file(). |
156 | * | 182 | * |
@@ -165,7 +191,7 @@ static int ext4_sync_parent(struct inode *inode) | |||
165 | * i_mutex lock is held when entering and exiting this function | 191 | * i_mutex lock is held when entering and exiting this function |
166 | */ | 192 | */ |
167 | 193 | ||
168 | int ext4_sync_file(struct file *file, int datasync) | 194 | int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) |
169 | { | 195 | { |
170 | struct inode *inode = file->f_mapping->host; | 196 | struct inode *inode = file->f_mapping->host; |
171 | struct ext4_inode_info *ei = EXT4_I(inode); | 197 | struct ext4_inode_info *ei = EXT4_I(inode); |
@@ -178,15 +204,20 @@ int ext4_sync_file(struct file *file, int datasync) | |||
178 | 204 | ||
179 | trace_ext4_sync_file_enter(file, datasync); | 205 | trace_ext4_sync_file_enter(file, datasync); |
180 | 206 | ||
207 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
208 | if (ret) | ||
209 | return ret; | ||
210 | mutex_lock(&inode->i_mutex); | ||
211 | |||
181 | if (inode->i_sb->s_flags & MS_RDONLY) | 212 | if (inode->i_sb->s_flags & MS_RDONLY) |
182 | return 0; | 213 | goto out; |
183 | 214 | ||
184 | ret = ext4_flush_completed_IO(inode); | 215 | ret = ext4_flush_completed_IO(inode); |
185 | if (ret < 0) | 216 | if (ret < 0) |
186 | goto out; | 217 | goto out; |
187 | 218 | ||
188 | if (!journal) { | 219 | if (!journal) { |
189 | ret = generic_file_fsync(file, datasync); | 220 | ret = __sync_inode(inode, datasync); |
190 | if (!ret && !list_empty(&inode->i_dentry)) | 221 | if (!ret && !list_empty(&inode->i_dentry)) |
191 | ret = ext4_sync_parent(inode); | 222 | ret = ext4_sync_parent(inode); |
192 | goto out; | 223 | goto out; |
@@ -220,6 +251,7 @@ int ext4_sync_file(struct file *file, int datasync) | |||
220 | if (needs_barrier) | 251 | if (needs_barrier) |
221 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 252 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
222 | out: | 253 | out: |
254 | mutex_unlock(&inode->i_mutex); | ||
223 | trace_ext4_sync_file_exit(inode, ret); | 255 | trace_ext4_sync_file_exit(inode, ret); |
224 | return ret; | 256 | return ret; |
225 | } | 257 | } |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index a975b4147e91..a5d3853822e0 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -310,7 +310,8 @@ extern int fat_setattr(struct dentry * dentry, struct iattr * attr); | |||
310 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); | 310 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); |
311 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | 311 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
312 | struct kstat *stat); | 312 | struct kstat *stat); |
313 | extern int fat_file_fsync(struct file *file, int datasync); | 313 | extern int fat_file_fsync(struct file *file, loff_t start, loff_t end, |
314 | int datasync); | ||
314 | 315 | ||
315 | /* fat/inode.c */ | 316 | /* fat/inode.c */ |
316 | extern void fat_attach(struct inode *inode, loff_t i_pos); | 317 | extern void fat_attach(struct inode *inode, loff_t i_pos); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index e1587c54d3c1..c118acf16e43 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -149,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp) | |||
149 | return 0; | 149 | return 0; |
150 | } | 150 | } |
151 | 151 | ||
152 | int fat_file_fsync(struct file *filp, int datasync) | 152 | int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) |
153 | { | 153 | { |
154 | struct inode *inode = filp->f_mapping->host; | 154 | struct inode *inode = filp->f_mapping->host; |
155 | int res, err; | 155 | int res, err; |
156 | 156 | ||
157 | res = generic_file_fsync(filp, datasync); | 157 | res = generic_file_fsync(filp, start, end, datasync); |
158 | err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); | 158 | err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); |
159 | 159 | ||
160 | return res ? res : err; | 160 | return res ? res : err; |
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 |
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 89c39e53760d..f82cb5e1cb6b 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -544,7 +544,9 @@ static int gfs2_close(struct inode *inode, struct file *file) | |||
544 | 544 | ||
545 | /** | 545 | /** |
546 | * gfs2_fsync - sync the dirty data for a file (across the cluster) | 546 | * gfs2_fsync - sync the dirty data for a file (across the cluster) |
547 | * @file: the file that points to the dentry (we ignore this) | 547 | * @file: the file that points to the dentry |
548 | * @start: the start position in the file to sync | ||
549 | * @end: the end position in the file to sync | ||
548 | * @datasync: set if we can ignore timestamp changes | 550 | * @datasync: set if we can ignore timestamp changes |
549 | * | 551 | * |
550 | * The VFS will flush data for us. We only need to worry | 552 | * The VFS will flush data for us. We only need to worry |
@@ -553,23 +555,32 @@ static int gfs2_close(struct inode *inode, struct file *file) | |||
553 | * Returns: errno | 555 | * Returns: errno |
554 | */ | 556 | */ |
555 | 557 | ||
556 | static int gfs2_fsync(struct file *file, int datasync) | 558 | static int gfs2_fsync(struct file *file, loff_t start, loff_t end, |
559 | int datasync) | ||
557 | { | 560 | { |
558 | struct inode *inode = file->f_mapping->host; | 561 | struct inode *inode = file->f_mapping->host; |
559 | int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); | 562 | int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC); |
560 | struct gfs2_inode *ip = GFS2_I(inode); | 563 | struct gfs2_inode *ip = GFS2_I(inode); |
561 | int ret; | 564 | int ret; |
562 | 565 | ||
566 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
567 | if (ret) | ||
568 | return ret; | ||
569 | mutex_lock(&inode->i_mutex); | ||
570 | |||
563 | if (datasync) | 571 | if (datasync) |
564 | sync_state &= ~I_DIRTY_SYNC; | 572 | sync_state &= ~I_DIRTY_SYNC; |
565 | 573 | ||
566 | if (sync_state) { | 574 | if (sync_state) { |
567 | ret = sync_inode_metadata(inode, 1); | 575 | ret = sync_inode_metadata(inode, 1); |
568 | if (ret) | 576 | if (ret) { |
577 | mutex_unlock(&inode->i_mutex); | ||
569 | return ret; | 578 | return ret; |
579 | } | ||
570 | gfs2_ail_flush(ip->i_gl); | 580 | gfs2_ail_flush(ip->i_gl); |
571 | } | 581 | } |
572 | 582 | ||
583 | mutex_unlock(&inode->i_mutex); | ||
573 | return 0; | 584 | return 0; |
574 | } | 585 | } |
575 | 586 | ||
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 5e7c3f309617..96a1b625fc74 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
@@ -627,12 +627,18 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) | |||
627 | return 0; | 627 | return 0; |
628 | } | 628 | } |
629 | 629 | ||
630 | static int hfs_file_fsync(struct file *filp, int datasync) | 630 | static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, |
631 | int datasync) | ||
631 | { | 632 | { |
632 | struct inode *inode = filp->f_mapping->host; | 633 | struct inode *inode = filp->f_mapping->host; |
633 | struct super_block * sb; | 634 | struct super_block * sb; |
634 | int ret, err; | 635 | int ret, err; |
635 | 636 | ||
637 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
638 | if (ret) | ||
639 | return ret; | ||
640 | mutex_lock(&inode->i_mutex); | ||
641 | |||
636 | /* sync the inode to buffers */ | 642 | /* sync the inode to buffers */ |
637 | ret = write_inode_now(inode, 0); | 643 | ret = write_inode_now(inode, 0); |
638 | 644 | ||
@@ -649,6 +655,7 @@ static int hfs_file_fsync(struct file *filp, int datasync) | |||
649 | err = sync_blockdev(sb->s_bdev); | 655 | err = sync_blockdev(sb->s_bdev); |
650 | if (!ret) | 656 | if (!ret) |
651 | ret = err; | 657 | ret = err; |
658 | mutex_unlock(&inode->i_mutex); | ||
652 | return ret; | 659 | return ret; |
653 | } | 660 | } |
654 | 661 | ||
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index d6857523336d..38184e360932 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -392,7 +392,8 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *); | |||
392 | int hfsplus_cat_write_inode(struct inode *); | 392 | int hfsplus_cat_write_inode(struct inode *); |
393 | struct inode *hfsplus_new_inode(struct super_block *, int); | 393 | struct inode *hfsplus_new_inode(struct super_block *, int); |
394 | void hfsplus_delete_inode(struct inode *); | 394 | void hfsplus_delete_inode(struct inode *); |
395 | int hfsplus_file_fsync(struct file *file, int datasync); | 395 | int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, |
396 | int datasync); | ||
396 | 397 | ||
397 | /* ioctl.c */ | 398 | /* ioctl.c */ |
398 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | 399 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 5b1cb98741cc..30486e01d003 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -308,13 +308,19 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | int hfsplus_file_fsync(struct file *file, int datasync) | 311 | int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, |
312 | int datasync) | ||
312 | { | 313 | { |
313 | struct inode *inode = file->f_mapping->host; | 314 | struct inode *inode = file->f_mapping->host; |
314 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 315 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
315 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); | 316 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
316 | int error = 0, error2; | 317 | int error = 0, error2; |
317 | 318 | ||
319 | error = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
320 | if (error) | ||
321 | return error; | ||
322 | mutex_lock(&inode->i_mutex); | ||
323 | |||
318 | /* | 324 | /* |
319 | * Sync inode metadata into the catalog and extent trees. | 325 | * Sync inode metadata into the catalog and extent trees. |
320 | */ | 326 | */ |
@@ -342,6 +348,8 @@ int hfsplus_file_fsync(struct file *file, int datasync) | |||
342 | if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) | 348 | if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) |
343 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 349 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
344 | 350 | ||
351 | mutex_unlock(&inode->i_mutex); | ||
352 | |||
345 | return error; | 353 | return error; |
346 | } | 354 | } |
347 | 355 | ||
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 6e449c599b9d..0d22afdd4611 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -362,9 +362,20 @@ retry: | |||
362 | return 0; | 362 | return 0; |
363 | } | 363 | } |
364 | 364 | ||
365 | int hostfs_fsync(struct file *file, int datasync) | 365 | int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
366 | { | 366 | { |
367 | return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync); | 367 | struct inode *inode = file->f_mapping->host; |
368 | int ret; | ||
369 | |||
370 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
371 | if (ret) | ||
372 | return ret; | ||
373 | |||
374 | mutex_lock(&inode->i_mutex); | ||
375 | ret = fsync_file(HOSTFS_I(inode)->fd, datasync); | ||
376 | mutex_unlock(&inode->i_mutex); | ||
377 | |||
378 | return ret; | ||
368 | } | 379 | } |
369 | 380 | ||
370 | static const struct file_operations hostfs_file_fops = { | 381 | static const struct file_operations hostfs_file_fops = { |
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 89c500ee5213..89d2a5803ae3 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c | |||
@@ -18,9 +18,14 @@ static int hpfs_file_release(struct inode *inode, struct file *file) | |||
18 | return 0; | 18 | return 0; |
19 | } | 19 | } |
20 | 20 | ||
21 | int hpfs_file_fsync(struct file *file, int datasync) | 21 | int hpfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
22 | { | 22 | { |
23 | struct inode *inode = file->f_mapping->host; | 23 | struct inode *inode = file->f_mapping->host; |
24 | int ret; | ||
25 | |||
26 | ret = filemap_write_and_wait_range(file->f_mapping, start, end); | ||
27 | if (ret) | ||
28 | return ret; | ||
24 | return sync_blockdev(inode->i_sb->s_bdev); | 29 | return sync_blockdev(inode->i_sb->s_bdev); |
25 | } | 30 | } |
26 | 31 | ||
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index dd552f862c8f..331b5e234ef3 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h | |||
@@ -258,7 +258,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *, | |||
258 | 258 | ||
259 | /* file.c */ | 259 | /* file.c */ |
260 | 260 | ||
261 | int hpfs_file_fsync(struct file *, int); | 261 | int hpfs_file_fsync(struct file *, loff_t, loff_t, int); |
262 | extern const struct file_operations hpfs_file_ops; | 262 | extern const struct file_operations hpfs_file_ops; |
263 | extern const struct inode_operations hpfs_file_iops; | 263 | extern const struct inode_operations hpfs_file_iops; |
264 | extern const struct address_space_operations hpfs_aops; | 264 | extern const struct address_space_operations hpfs_aops; |
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 85c098a499f3..8635be5ffd97 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c | |||
@@ -573,9 +573,10 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir) | |||
573 | return err; | 573 | return err; |
574 | } | 574 | } |
575 | 575 | ||
576 | static int hppfs_fsync(struct file *file, int datasync) | 576 | static int hppfs_fsync(struct file *file, loff_t start, loff_t end, |
577 | int datasync) | ||
577 | { | 578 | { |
578 | return 0; | 579 | return filemap_write_and_wait_range(file->f_mapping, start, end); |
579 | } | 580 | } |
580 | 581 | ||
581 | static const struct file_operations hppfs_dir_fops = { | 582 | static const struct file_operations hppfs_dir_fops = { |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 1c0a08d711aa..3989f7e09f7f 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -27,13 +27,20 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
27 | struct page **pagep, void **fsdata); | 27 | struct page **pagep, void **fsdata); |
28 | static int jffs2_readpage (struct file *filp, struct page *pg); | 28 | static int jffs2_readpage (struct file *filp, struct page *pg); |
29 | 29 | ||
30 | int jffs2_fsync(struct file *filp, int datasync) | 30 | int jffs2_fsync(struct file *filp, loff_t start, loff_t end, int datasync) |
31 | { | 31 | { |
32 | struct inode *inode = filp->f_mapping->host; | 32 | struct inode *inode = filp->f_mapping->host; |
33 | struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | 33 | struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); |
34 | int ret; | ||
35 | |||
36 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
37 | if (ret) | ||
38 | return ret; | ||
34 | 39 | ||
40 | mutex_lock(&inode->i_mutex); | ||
35 | /* Trigger GC to flush any pending writes for this inode */ | 41 | /* Trigger GC to flush any pending writes for this inode */ |
36 | jffs2_flush_wbuf_gc(c, inode->i_ino); | 42 | jffs2_flush_wbuf_gc(c, inode->i_ino); |
43 | mutex_unlock(&inode->i_mutex); | ||
37 | 44 | ||
38 | return 0; | 45 | return 0; |
39 | } | 46 | } |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 65c6c43ca482..9c252835e8e5 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations; | |||
158 | extern const struct file_operations jffs2_file_operations; | 158 | extern const struct file_operations jffs2_file_operations; |
159 | extern const struct inode_operations jffs2_file_inode_operations; | 159 | extern const struct inode_operations jffs2_file_inode_operations; |
160 | extern const struct address_space_operations jffs2_file_address_operations; | 160 | extern const struct address_space_operations jffs2_file_address_operations; |
161 | int jffs2_fsync(struct file *, int); | 161 | int jffs2_fsync(struct file *, loff_t, loff_t, int); |
162 | int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); | 162 | int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); |
163 | 163 | ||
164 | /* ioctl.c */ | 164 | /* ioctl.c */ |
diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 9f32315acef1..7527855b5cc6 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c | |||
@@ -28,19 +28,26 @@ | |||
28 | #include "jfs_acl.h" | 28 | #include "jfs_acl.h" |
29 | #include "jfs_debug.h" | 29 | #include "jfs_debug.h" |
30 | 30 | ||
31 | int jfs_fsync(struct file *file, int datasync) | 31 | int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
32 | { | 32 | { |
33 | struct inode *inode = file->f_mapping->host; | 33 | struct inode *inode = file->f_mapping->host; |
34 | int rc = 0; | 34 | int rc = 0; |
35 | 35 | ||
36 | rc = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
37 | if (rc) | ||
38 | return rc; | ||
39 | |||
40 | mutex_lock(&inode->i_mutex); | ||
36 | if (!(inode->i_state & I_DIRTY) || | 41 | if (!(inode->i_state & I_DIRTY) || |
37 | (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) { | 42 | (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) { |
38 | /* Make sure committed changes hit the disk */ | 43 | /* Make sure committed changes hit the disk */ |
39 | jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1); | 44 | jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1); |
45 | mutex_unlock(&inode->i_mutex); | ||
40 | return rc; | 46 | return rc; |
41 | } | 47 | } |
42 | 48 | ||
43 | rc |= jfs_commit_inode(inode, 1); | 49 | rc |= jfs_commit_inode(inode, 1); |
50 | mutex_unlock(&inode->i_mutex); | ||
44 | 51 | ||
45 | return rc ? -EIO : 0; | 52 | return rc ? -EIO : 0; |
46 | } | 53 | } |
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index ec2fb8b945fc..9271cfe4a149 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h | |||
@@ -21,7 +21,7 @@ | |||
21 | struct fid; | 21 | struct fid; |
22 | 22 | ||
23 | extern struct inode *ialloc(struct inode *, umode_t); | 23 | extern struct inode *ialloc(struct inode *, umode_t); |
24 | extern int jfs_fsync(struct file *, int); | 24 | extern int jfs_fsync(struct file *, loff_t, loff_t, int); |
25 | extern long jfs_ioctl(struct file *, unsigned int, unsigned long); | 25 | extern long jfs_ioctl(struct file *, unsigned int, unsigned long); |
26 | extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); | 26 | extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); |
27 | extern struct inode *jfs_iget(struct super_block *, unsigned long); | 27 | extern struct inode *jfs_iget(struct super_block *, unsigned long); |
diff --git a/fs/libfs.c b/fs/libfs.c index bd50b11f92da..8f2271a5df53 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -905,21 +905,29 @@ EXPORT_SYMBOL_GPL(generic_fh_to_parent); | |||
905 | * filesystems which track all non-inode metadata in the buffers list | 905 | * filesystems which track all non-inode metadata in the buffers list |
906 | * hanging off the address_space structure. | 906 | * hanging off the address_space structure. |
907 | */ | 907 | */ |
908 | int generic_file_fsync(struct file *file, int datasync) | 908 | int generic_file_fsync(struct file *file, loff_t start, loff_t end, |
909 | int datasync) | ||
909 | { | 910 | { |
910 | struct inode *inode = file->f_mapping->host; | 911 | struct inode *inode = file->f_mapping->host; |
911 | int err; | 912 | int err; |
912 | int ret; | 913 | int ret; |
913 | 914 | ||
915 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
916 | if (err) | ||
917 | return err; | ||
918 | |||
919 | mutex_lock(&inode->i_mutex); | ||
914 | ret = sync_mapping_buffers(inode->i_mapping); | 920 | ret = sync_mapping_buffers(inode->i_mapping); |
915 | if (!(inode->i_state & I_DIRTY)) | 921 | if (!(inode->i_state & I_DIRTY)) |
916 | return ret; | 922 | goto out; |
917 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 923 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) |
918 | return ret; | 924 | goto out; |
919 | 925 | ||
920 | err = sync_inode_metadata(inode, 1); | 926 | err = sync_inode_metadata(inode, 1); |
921 | if (ret == 0) | 927 | if (ret == 0) |
922 | ret = err; | 928 | ret = err; |
929 | out: | ||
930 | mutex_unlock(&inode->i_mutex); | ||
923 | return ret; | 931 | return ret; |
924 | } | 932 | } |
925 | EXPORT_SYMBOL(generic_file_fsync); | 933 | EXPORT_SYMBOL(generic_file_fsync); |
@@ -956,7 +964,7 @@ EXPORT_SYMBOL(generic_check_addressable); | |||
956 | /* | 964 | /* |
957 | * No-op implementation of ->fsync for in-memory filesystems. | 965 | * No-op implementation of ->fsync for in-memory filesystems. |
958 | */ | 966 | */ |
959 | int noop_fsync(struct file *file, int datasync) | 967 | int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
960 | { | 968 | { |
961 | return 0; | 969 | return 0; |
962 | } | 970 | } |
diff --git a/fs/logfs/file.c b/fs/logfs/file.c index c2ad7028def4..b548c87a86f1 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c | |||
@@ -219,11 +219,20 @@ long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
219 | } | 219 | } |
220 | } | 220 | } |
221 | 221 | ||
222 | int logfs_fsync(struct file *file, int datasync) | 222 | int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
223 | { | 223 | { |
224 | struct super_block *sb = file->f_mapping->host->i_sb; | 224 | struct super_block *sb = file->f_mapping->host->i_sb; |
225 | struct inode *inode = file->f_mapping->host; | ||
226 | int ret; | ||
227 | |||
228 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
229 | if (ret) | ||
230 | return ret; | ||
225 | 231 | ||
232 | mutex_lock(&inode->i_mutex); | ||
226 | logfs_write_anchor(sb); | 233 | logfs_write_anchor(sb); |
234 | mutex_unlock(&inode->i_mutex); | ||
235 | |||
227 | return 0; | 236 | return 0; |
228 | } | 237 | } |
229 | 238 | ||
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index 57afd4a6fabb..f22d108bfa5d 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h | |||
@@ -506,7 +506,7 @@ extern const struct file_operations logfs_reg_fops; | |||
506 | extern const struct address_space_operations logfs_reg_aops; | 506 | extern const struct address_space_operations logfs_reg_aops; |
507 | int logfs_readpage(struct file *file, struct page *page); | 507 | int logfs_readpage(struct file *file, struct page *page); |
508 | long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 508 | long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
509 | int logfs_fsync(struct file *file, int datasync); | 509 | int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync); |
510 | 510 | ||
511 | /* gc.c */ | 511 | /* gc.c */ |
512 | u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec); | 512 | u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec); |
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 0ed65e0c3dfe..64a326418aa2 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c | |||
@@ -20,9 +20,9 @@ | |||
20 | 20 | ||
21 | #include "ncp_fs.h" | 21 | #include "ncp_fs.h" |
22 | 22 | ||
23 | static int ncp_fsync(struct file *file, int datasync) | 23 | static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
24 | { | 24 | { |
25 | return 0; | 25 | return filemap_write_and_wait_range(file->f_mapping, start, end); |
26 | } | 26 | } |
27 | 27 | ||
28 | /* | 28 | /* |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 8a45e6d1f6a4..57f578e2560a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -56,7 +56,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *); | |||
56 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | 56 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); |
57 | static int nfs_rename(struct inode *, struct dentry *, | 57 | static int nfs_rename(struct inode *, struct dentry *, |
58 | struct inode *, struct dentry *); | 58 | struct inode *, struct dentry *); |
59 | static int nfs_fsync_dir(struct file *, int); | 59 | static int nfs_fsync_dir(struct file *, loff_t, loff_t, int); |
60 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 60 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
61 | static void nfs_readdir_clear_array(struct page*); | 61 | static void nfs_readdir_clear_array(struct page*); |
62 | 62 | ||
@@ -945,15 +945,19 @@ out: | |||
945 | * All directory operations under NFS are synchronous, so fsync() | 945 | * All directory operations under NFS are synchronous, so fsync() |
946 | * is a dummy operation. | 946 | * is a dummy operation. |
947 | */ | 947 | */ |
948 | static int nfs_fsync_dir(struct file *filp, int datasync) | 948 | static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end, |
949 | int datasync) | ||
949 | { | 950 | { |
950 | struct dentry *dentry = filp->f_path.dentry; | 951 | struct dentry *dentry = filp->f_path.dentry; |
952 | struct inode *inode = dentry->d_inode; | ||
951 | 953 | ||
952 | dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", | 954 | dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", |
953 | dentry->d_parent->d_name.name, dentry->d_name.name, | 955 | dentry->d_parent->d_name.name, dentry->d_name.name, |
954 | datasync); | 956 | datasync); |
955 | 957 | ||
958 | mutex_lock(&inode->i_mutex); | ||
956 | nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC); | 959 | nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC); |
960 | mutex_unlock(&inode->i_mutex); | ||
957 | return 0; | 961 | return 0; |
958 | } | 962 | } |
959 | 963 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2c1705b6acd7..28b8c3f3cda3 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -55,7 +55,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
55 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, | 55 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, |
56 | unsigned long nr_segs, loff_t pos); | 56 | unsigned long nr_segs, loff_t pos); |
57 | static int nfs_file_flush(struct file *, fl_owner_t id); | 57 | static int nfs_file_flush(struct file *, fl_owner_t id); |
58 | static int nfs_file_fsync(struct file *, int datasync); | 58 | static int nfs_file_fsync(struct file *, loff_t, loff_t, int datasync); |
59 | static int nfs_check_flags(int flags); | 59 | static int nfs_check_flags(int flags); |
60 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); | 60 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); |
61 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); | 61 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); |
@@ -308,7 +308,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
308 | * fall back to doing a synchronous write. | 308 | * fall back to doing a synchronous write. |
309 | */ | 309 | */ |
310 | static int | 310 | static int |
311 | nfs_file_fsync(struct file *file, int datasync) | 311 | nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
312 | { | 312 | { |
313 | struct dentry *dentry = file->f_path.dentry; | 313 | struct dentry *dentry = file->f_path.dentry; |
314 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 314 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
@@ -316,11 +316,15 @@ nfs_file_fsync(struct file *file, int datasync) | |||
316 | int have_error, status; | 316 | int have_error, status; |
317 | int ret = 0; | 317 | int ret = 0; |
318 | 318 | ||
319 | |||
320 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", | 319 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", |
321 | dentry->d_parent->d_name.name, dentry->d_name.name, | 320 | dentry->d_parent->d_name.name, dentry->d_name.name, |
322 | datasync); | 321 | datasync); |
323 | 322 | ||
323 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
324 | if (ret) | ||
325 | return ret; | ||
326 | mutex_lock(&inode->i_mutex); | ||
327 | |||
324 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 328 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
325 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | 329 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
326 | status = nfs_commit_inode(inode, FLUSH_SYNC); | 330 | status = nfs_commit_inode(inode, FLUSH_SYNC); |
@@ -332,6 +336,7 @@ nfs_file_fsync(struct file *file, int datasync) | |||
332 | if (!ret && !datasync) | 336 | if (!ret && !datasync) |
333 | /* application has asked for meta-data sync */ | 337 | /* application has asked for meta-data sync */ |
334 | ret = pnfs_layoutcommit_inode(inode, true); | 338 | ret = pnfs_layoutcommit_inode(inode, true); |
339 | mutex_unlock(&inode->i_mutex); | ||
335 | return ret; | 340 | return ret; |
336 | } | 341 | } |
337 | 342 | ||
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index d7eeca62febd..26601529dc17 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include "nilfs.h" | 27 | #include "nilfs.h" |
28 | #include "segment.h" | 28 | #include "segment.h" |
29 | 29 | ||
30 | int nilfs_sync_file(struct file *file, int datasync) | 30 | int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) |
31 | { | 31 | { |
32 | /* | 32 | /* |
33 | * Called from fsync() system call | 33 | * Called from fsync() system call |
@@ -40,8 +40,15 @@ int nilfs_sync_file(struct file *file, int datasync) | |||
40 | struct inode *inode = file->f_mapping->host; | 40 | struct inode *inode = file->f_mapping->host; |
41 | int err; | 41 | int err; |
42 | 42 | ||
43 | if (!nilfs_inode_dirty(inode)) | 43 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); |
44 | if (err) | ||
45 | return err; | ||
46 | mutex_lock(&inode->i_mutex); | ||
47 | |||
48 | if (!nilfs_inode_dirty(inode)) { | ||
49 | mutex_unlock(&inode->i_mutex); | ||
44 | return 0; | 50 | return 0; |
51 | } | ||
45 | 52 | ||
46 | if (datasync) | 53 | if (datasync) |
47 | err = nilfs_construct_dsync_segment(inode->i_sb, inode, 0, | 54 | err = nilfs_construct_dsync_segment(inode->i_sb, inode, 0, |
@@ -49,6 +56,7 @@ int nilfs_sync_file(struct file *file, int datasync) | |||
49 | else | 56 | else |
50 | err = nilfs_construct_segment(inode->i_sb); | 57 | err = nilfs_construct_segment(inode->i_sb); |
51 | 58 | ||
59 | mutex_unlock(&inode->i_mutex); | ||
52 | return err; | 60 | return err; |
53 | } | 61 | } |
54 | 62 | ||
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 6fb7511c0328..255d5e1c03b7 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -235,7 +235,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, | |||
235 | struct page *, struct inode *); | 235 | struct page *, struct inode *); |
236 | 236 | ||
237 | /* file.c */ | 237 | /* file.c */ |
238 | extern int nilfs_sync_file(struct file *, int); | 238 | extern int nilfs_sync_file(struct file *, loff_t, loff_t, int); |
239 | 239 | ||
240 | /* ioctl.c */ | 240 | /* ioctl.c */ |
241 | long nilfs_ioctl(struct file *, unsigned int, unsigned long); | 241 | long nilfs_ioctl(struct file *, unsigned int, unsigned long); |
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 0f48e7c5d9e1..99e36107ff60 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c | |||
@@ -1527,13 +1527,20 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp) | |||
1527 | * this problem for now. We do write the $BITMAP attribute if it is present | 1527 | * this problem for now. We do write the $BITMAP attribute if it is present |
1528 | * which is the important one for a directory so things are not too bad. | 1528 | * which is the important one for a directory so things are not too bad. |
1529 | */ | 1529 | */ |
1530 | static int ntfs_dir_fsync(struct file *filp, int datasync) | 1530 | static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end, |
1531 | int datasync) | ||
1531 | { | 1532 | { |
1532 | struct inode *bmp_vi, *vi = filp->f_mapping->host; | 1533 | struct inode *bmp_vi, *vi = filp->f_mapping->host; |
1533 | int err, ret; | 1534 | int err, ret; |
1534 | ntfs_attr na; | 1535 | ntfs_attr na; |
1535 | 1536 | ||
1536 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | 1537 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); |
1538 | |||
1539 | err = filemap_write_and_wait_range(vi->i_mapping, start, end); | ||
1540 | if (err) | ||
1541 | return err; | ||
1542 | mutex_lock(&vi->i_mutex); | ||
1543 | |||
1537 | BUG_ON(!S_ISDIR(vi->i_mode)); | 1544 | BUG_ON(!S_ISDIR(vi->i_mode)); |
1538 | /* If the bitmap attribute inode is in memory sync it, too. */ | 1545 | /* If the bitmap attribute inode is in memory sync it, too. */ |
1539 | na.mft_no = vi->i_ino; | 1546 | na.mft_no = vi->i_ino; |
@@ -1555,6 +1562,7 @@ static int ntfs_dir_fsync(struct file *filp, int datasync) | |||
1555 | else | 1562 | else |
1556 | ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " | 1563 | ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " |
1557 | "%u.", datasync ? "data" : "", vi->i_ino, -ret); | 1564 | "%u.", datasync ? "data" : "", vi->i_ino, -ret); |
1565 | mutex_unlock(&vi->i_mutex); | ||
1558 | return ret; | 1566 | return ret; |
1559 | } | 1567 | } |
1560 | 1568 | ||
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index b59f5ac26bef..c587e2d27183 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -2152,12 +2152,19 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2152 | * with this inode but since we have no simple way of getting to them we ignore | 2152 | * with this inode but since we have no simple way of getting to them we ignore |
2153 | * this problem for now. | 2153 | * this problem for now. |
2154 | */ | 2154 | */ |
2155 | static int ntfs_file_fsync(struct file *filp, int datasync) | 2155 | static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end, |
2156 | int datasync) | ||
2156 | { | 2157 | { |
2157 | struct inode *vi = filp->f_mapping->host; | 2158 | struct inode *vi = filp->f_mapping->host; |
2158 | int err, ret = 0; | 2159 | int err, ret = 0; |
2159 | 2160 | ||
2160 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | 2161 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); |
2162 | |||
2163 | err = filemap_write_and_wait_range(vi->i_mapping, start, end); | ||
2164 | if (err) | ||
2165 | return err; | ||
2166 | mutex_lock(&vi->i_mutex); | ||
2167 | |||
2161 | BUG_ON(S_ISDIR(vi->i_mode)); | 2168 | BUG_ON(S_ISDIR(vi->i_mode)); |
2162 | if (!datasync || !NInoNonResident(NTFS_I(vi))) | 2169 | if (!datasync || !NInoNonResident(NTFS_I(vi))) |
2163 | ret = __ntfs_write_inode(vi, 1); | 2170 | ret = __ntfs_write_inode(vi, 1); |
@@ -2175,6 +2182,7 @@ static int ntfs_file_fsync(struct file *filp, int datasync) | |||
2175 | else | 2182 | else |
2176 | ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " | 2183 | ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error " |
2177 | "%u.", datasync ? "data" : "", vi->i_ino, -ret); | 2184 | "%u.", datasync ? "data" : "", vi->i_ino, -ret); |
2185 | mutex_unlock(&vi->i_mutex); | ||
2178 | return ret; | 2186 | return ret; |
2179 | } | 2187 | } |
2180 | 2188 | ||
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 22d604601957..0fc2bd34039d 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -171,7 +171,8 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file) | |||
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | 173 | ||
174 | static int ocfs2_sync_file(struct file *file, int datasync) | 174 | static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end, |
175 | int datasync) | ||
175 | { | 176 | { |
176 | int err = 0; | 177 | int err = 0; |
177 | journal_t *journal; | 178 | journal_t *journal; |
@@ -184,6 +185,16 @@ static int ocfs2_sync_file(struct file *file, int datasync) | |||
184 | file->f_path.dentry->d_name.name, | 185 | file->f_path.dentry->d_name.name, |
185 | (unsigned long long)datasync); | 186 | (unsigned long long)datasync); |
186 | 187 | ||
188 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
189 | if (err) | ||
190 | return err; | ||
191 | |||
192 | /* | ||
193 | * Probably don't need the i_mutex at all in here, just putting it here | ||
194 | * to be consistent with how fsync used to be called, someone more | ||
195 | * familiar with the fs could possibly remove it. | ||
196 | */ | ||
197 | mutex_lock(&inode->i_mutex); | ||
187 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) { | 198 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) { |
188 | /* | 199 | /* |
189 | * We still have to flush drive's caches to get data to the | 200 | * We still have to flush drive's caches to get data to the |
@@ -200,6 +211,7 @@ static int ocfs2_sync_file(struct file *file, int datasync) | |||
200 | bail: | 211 | bail: |
201 | if (err) | 212 | if (err) |
202 | mlog_errno(err); | 213 | mlog_errno(err); |
214 | mutex_unlock(&inode->i_mutex); | ||
203 | 215 | ||
204 | return (err < 0) ? -EIO : 0; | 216 | return (err < 0) ? -EIO : 0; |
205 | } | 217 | } |
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 198dabf1b2bb..133e9355dc6f 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c | |||
@@ -14,7 +14,8 @@ | |||
14 | extern const struct reiserfs_key MIN_KEY; | 14 | extern const struct reiserfs_key MIN_KEY; |
15 | 15 | ||
16 | static int reiserfs_readdir(struct file *, void *, filldir_t); | 16 | static int reiserfs_readdir(struct file *, void *, filldir_t); |
17 | static int reiserfs_dir_fsync(struct file *filp, int datasync); | 17 | static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, |
18 | int datasync); | ||
18 | 19 | ||
19 | const struct file_operations reiserfs_dir_operations = { | 20 | const struct file_operations reiserfs_dir_operations = { |
20 | .llseek = generic_file_llseek, | 21 | .llseek = generic_file_llseek, |
@@ -27,13 +28,21 @@ const struct file_operations reiserfs_dir_operations = { | |||
27 | #endif | 28 | #endif |
28 | }; | 29 | }; |
29 | 30 | ||
30 | static int reiserfs_dir_fsync(struct file *filp, int datasync) | 31 | static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end, |
32 | int datasync) | ||
31 | { | 33 | { |
32 | struct inode *inode = filp->f_mapping->host; | 34 | struct inode *inode = filp->f_mapping->host; |
33 | int err; | 35 | int err; |
36 | |||
37 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
38 | if (err) | ||
39 | return err; | ||
40 | |||
41 | mutex_lock(&inode->i_mutex); | ||
34 | reiserfs_write_lock(inode->i_sb); | 42 | reiserfs_write_lock(inode->i_sb); |
35 | err = reiserfs_commit_for_inode(inode); | 43 | err = reiserfs_commit_for_inode(inode); |
36 | reiserfs_write_unlock(inode->i_sb); | 44 | reiserfs_write_unlock(inode->i_sb); |
45 | mutex_unlock(&inode->i_mutex); | ||
37 | if (err < 0) | 46 | if (err < 0) |
38 | return err; | 47 | return err; |
39 | return 0; | 48 | return 0; |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index bbf31003d308..c7156dc39ce7 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -140,12 +140,18 @@ static void reiserfs_vfs_truncate_file(struct inode *inode) | |||
140 | * be removed... | 140 | * be removed... |
141 | */ | 141 | */ |
142 | 142 | ||
143 | static int reiserfs_sync_file(struct file *filp, int datasync) | 143 | static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end, |
144 | int datasync) | ||
144 | { | 145 | { |
145 | struct inode *inode = filp->f_mapping->host; | 146 | struct inode *inode = filp->f_mapping->host; |
146 | int err; | 147 | int err; |
147 | int barrier_done; | 148 | int barrier_done; |
148 | 149 | ||
150 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
151 | if (err) | ||
152 | return err; | ||
153 | |||
154 | mutex_lock(&inode->i_mutex); | ||
149 | BUG_ON(!S_ISREG(inode->i_mode)); | 155 | BUG_ON(!S_ISREG(inode->i_mode)); |
150 | err = sync_mapping_buffers(inode->i_mapping); | 156 | err = sync_mapping_buffers(inode->i_mapping); |
151 | reiserfs_write_lock(inode->i_sb); | 157 | reiserfs_write_lock(inode->i_sb); |
@@ -153,6 +159,7 @@ static int reiserfs_sync_file(struct file *filp, int datasync) | |||
153 | reiserfs_write_unlock(inode->i_sb); | 159 | reiserfs_write_unlock(inode->i_sb); |
154 | if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb)) | 160 | if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb)) |
155 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 161 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
162 | mutex_unlock(&inode->i_mutex); | ||
156 | if (barrier_done < 0) | 163 | if (barrier_done < 0) |
157 | return barrier_done; | 164 | return barrier_done; |
158 | return (err < 0) ? -EIO : 0; | 165 | return (err < 0) ? -EIO : 0; |
@@ -165,28 +165,9 @@ SYSCALL_DEFINE1(syncfs, int, fd) | |||
165 | */ | 165 | */ |
166 | int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) | 166 | int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) |
167 | { | 167 | { |
168 | struct address_space *mapping = file->f_mapping; | 168 | if (!file->f_op || !file->f_op->fsync) |
169 | int err, ret; | 169 | return -EINVAL; |
170 | 170 | return file->f_op->fsync(file, start, end, datasync); | |
171 | if (!file->f_op || !file->f_op->fsync) { | ||
172 | ret = -EINVAL; | ||
173 | goto out; | ||
174 | } | ||
175 | |||
176 | ret = filemap_write_and_wait_range(mapping, start, end); | ||
177 | |||
178 | /* | ||
179 | * We need to protect against concurrent writers, which could cause | ||
180 | * livelocks in fsync_buffers_list(). | ||
181 | */ | ||
182 | mutex_lock(&mapping->host->i_mutex); | ||
183 | err = file->f_op->fsync(file, datasync); | ||
184 | if (!ret) | ||
185 | ret = err; | ||
186 | mutex_unlock(&mapping->host->i_mutex); | ||
187 | |||
188 | out: | ||
189 | return ret; | ||
190 | } | 171 | } |
191 | EXPORT_SYMBOL(vfs_fsync_range); | 172 | EXPORT_SYMBOL(vfs_fsync_range); |
192 | 173 | ||
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 5e7fccfc4b29..89ef9a2f7837 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c | |||
@@ -1304,7 +1304,7 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
1304 | return NULL; | 1304 | return NULL; |
1305 | } | 1305 | } |
1306 | 1306 | ||
1307 | int ubifs_fsync(struct file *file, int datasync) | 1307 | int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
1308 | { | 1308 | { |
1309 | struct inode *inode = file->f_mapping->host; | 1309 | struct inode *inode = file->f_mapping->host; |
1310 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 1310 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
@@ -1319,14 +1319,16 @@ int ubifs_fsync(struct file *file, int datasync) | |||
1319 | */ | 1319 | */ |
1320 | return 0; | 1320 | return 0; |
1321 | 1321 | ||
1322 | /* | 1322 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); |
1323 | * VFS has already synchronized dirty pages for this inode. Synchronize | 1323 | if (err) |
1324 | * the inode unless this is a 'datasync()' call. | 1324 | return err; |
1325 | */ | 1325 | mutex_lock(&inode->i_mutex); |
1326 | |||
1327 | /* Synchronize the inode unless this is a 'datasync()' call. */ | ||
1326 | if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) { | 1328 | if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) { |
1327 | err = inode->i_sb->s_op->write_inode(inode, NULL); | 1329 | err = inode->i_sb->s_op->write_inode(inode, NULL); |
1328 | if (err) | 1330 | if (err) |
1329 | return err; | 1331 | goto out; |
1330 | } | 1332 | } |
1331 | 1333 | ||
1332 | /* | 1334 | /* |
@@ -1334,10 +1336,9 @@ int ubifs_fsync(struct file *file, int datasync) | |||
1334 | * them. | 1336 | * them. |
1335 | */ | 1337 | */ |
1336 | err = ubifs_sync_wbufs_by_inode(c, inode); | 1338 | err = ubifs_sync_wbufs_by_inode(c, inode); |
1337 | if (err) | 1339 | out: |
1338 | return err; | 1340 | mutex_unlock(&inode->i_mutex); |
1339 | 1341 | return err; | |
1340 | return 0; | ||
1341 | } | 1342 | } |
1342 | 1343 | ||
1343 | /** | 1344 | /** |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index f79983d6f860..4cd648501fa4 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -1720,7 +1720,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c); | |||
1720 | int ubifs_calc_dark(const struct ubifs_info *c, int spc); | 1720 | int ubifs_calc_dark(const struct ubifs_info *c, int spc); |
1721 | 1721 | ||
1722 | /* file.c */ | 1722 | /* file.c */ |
1723 | int ubifs_fsync(struct file *file, int datasync); | 1723 | int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync); |
1724 | int ubifs_setattr(struct dentry *dentry, struct iattr *attr); | 1724 | int ubifs_setattr(struct dentry *dentry, struct iattr *attr); |
1725 | 1725 | ||
1726 | /* dir.c */ | 1726 | /* dir.c */ |
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 7f782af286bf..fbbf657df0cd 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -127,6 +127,8 @@ xfs_iozero( | |||
127 | STATIC int | 127 | STATIC int |
128 | xfs_file_fsync( | 128 | xfs_file_fsync( |
129 | struct file *file, | 129 | struct file *file, |
130 | loff_t start, | ||
131 | loff_t end, | ||
130 | int datasync) | 132 | int datasync) |
131 | { | 133 | { |
132 | struct inode *inode = file->f_mapping->host; | 134 | struct inode *inode = file->f_mapping->host; |
@@ -138,6 +140,10 @@ xfs_file_fsync( | |||
138 | 140 | ||
139 | trace_xfs_file_fsync(ip); | 141 | trace_xfs_file_fsync(ip); |
140 | 142 | ||
143 | error = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
144 | if (error) | ||
145 | return error; | ||
146 | |||
141 | if (XFS_FORCED_SHUTDOWN(mp)) | 147 | if (XFS_FORCED_SHUTDOWN(mp)) |
142 | return -XFS_ERROR(EIO); | 148 | return -XFS_ERROR(EIO); |
143 | 149 | ||
@@ -875,18 +881,11 @@ xfs_file_aio_write( | |||
875 | /* Handle various SYNC-type writes */ | 881 | /* Handle various SYNC-type writes */ |
876 | if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { | 882 | if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) { |
877 | loff_t end = pos + ret - 1; | 883 | loff_t end = pos + ret - 1; |
878 | int error, error2; | ||
879 | 884 | ||
880 | xfs_rw_iunlock(ip, iolock); | 885 | xfs_rw_iunlock(ip, iolock); |
881 | error = filemap_write_and_wait_range(mapping, pos, end); | 886 | ret = -xfs_file_fsync(file, pos, end, |
887 | (file->f_flags & __O_SYNC) ? 0 : 1); | ||
882 | xfs_rw_ilock(ip, iolock); | 888 | xfs_rw_ilock(ip, iolock); |
883 | |||
884 | error2 = -xfs_file_fsync(file, | ||
885 | (file->f_flags & __O_SYNC) ? 0 : 1); | ||
886 | if (error) | ||
887 | ret = error; | ||
888 | else if (error2) | ||
889 | ret = error2; | ||
890 | } | 889 | } |
891 | 890 | ||
892 | out_unlock: | 891 | out_unlock: |
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 5e06acf95d0f..0c473fd79acb 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h | |||
@@ -877,7 +877,7 @@ extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, | |||
877 | extern void ext3_htree_free_dir_info(struct dir_private_info *p); | 877 | extern void ext3_htree_free_dir_info(struct dir_private_info *p); |
878 | 878 | ||
879 | /* fsync.c */ | 879 | /* fsync.c */ |
880 | extern int ext3_sync_file(struct file *, int); | 880 | extern int ext3_sync_file(struct file *, loff_t, loff_t, int); |
881 | 881 | ||
882 | /* hash.c */ | 882 | /* hash.c */ |
883 | extern int ext3fs_dirhash(const char *name, int len, struct | 883 | extern int ext3fs_dirhash(const char *name, int len, struct |
diff --git a/include/linux/fb.h b/include/linux/fb.h index 6a8274877171..1d6836c498dd 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -1043,7 +1043,8 @@ extern void fb_deferred_io_open(struct fb_info *info, | |||
1043 | struct inode *inode, | 1043 | struct inode *inode, |
1044 | struct file *file); | 1044 | struct file *file); |
1045 | extern void fb_deferred_io_cleanup(struct fb_info *info); | 1045 | extern void fb_deferred_io_cleanup(struct fb_info *info); |
1046 | extern int fb_deferred_io_fsync(struct file *file, int datasync); | 1046 | extern int fb_deferred_io_fsync(struct file *file, loff_t start, |
1047 | loff_t end, int datasync); | ||
1047 | 1048 | ||
1048 | static inline bool fb_be_math(struct fb_info *info) | 1049 | static inline bool fb_be_math(struct fb_info *info) |
1049 | { | 1050 | { |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 4a61f98823a6..9cd2075c4a39 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1572,7 +1572,7 @@ struct file_operations { | |||
1572 | int (*open) (struct inode *, struct file *); | 1572 | int (*open) (struct inode *, struct file *); |
1573 | int (*flush) (struct file *, fl_owner_t id); | 1573 | int (*flush) (struct file *, fl_owner_t id); |
1574 | int (*release) (struct inode *, struct file *); | 1574 | int (*release) (struct inode *, struct file *); |
1575 | int (*fsync) (struct file *, int datasync); | 1575 | int (*fsync) (struct file *, loff_t, loff_t, int datasync); |
1576 | int (*aio_fsync) (struct kiocb *, int datasync); | 1576 | int (*aio_fsync) (struct kiocb *, int datasync); |
1577 | int (*fasync) (int, struct file *, int); | 1577 | int (*fasync) (int, struct file *, int); |
1578 | int (*lock) (struct file *, int, struct file_lock *); | 1578 | int (*lock) (struct file *, int, struct file_lock *); |
@@ -2360,7 +2360,8 @@ extern int generic_segment_checks(const struct iovec *iov, | |||
2360 | /* fs/block_dev.c */ | 2360 | /* fs/block_dev.c */ |
2361 | extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, | 2361 | extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, |
2362 | unsigned long nr_segs, loff_t pos); | 2362 | unsigned long nr_segs, loff_t pos); |
2363 | extern int blkdev_fsync(struct file *filp, int datasync); | 2363 | extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, |
2364 | int datasync); | ||
2364 | 2365 | ||
2365 | /* fs/splice.c */ | 2366 | /* fs/splice.c */ |
2366 | extern ssize_t generic_file_splice_read(struct file *, loff_t *, | 2367 | extern ssize_t generic_file_splice_read(struct file *, loff_t *, |
@@ -2490,7 +2491,7 @@ extern int simple_link(struct dentry *, struct inode *, struct dentry *); | |||
2490 | extern int simple_unlink(struct inode *, struct dentry *); | 2491 | extern int simple_unlink(struct inode *, struct dentry *); |
2491 | extern int simple_rmdir(struct inode *, struct dentry *); | 2492 | extern int simple_rmdir(struct inode *, struct dentry *); |
2492 | extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); | 2493 | extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); |
2493 | extern int noop_fsync(struct file *, int); | 2494 | extern int noop_fsync(struct file *, loff_t, loff_t, int); |
2494 | extern int simple_empty(struct dentry *); | 2495 | extern int simple_empty(struct dentry *); |
2495 | extern int simple_readpage(struct file *file, struct page *page); | 2496 | extern int simple_readpage(struct file *file, struct page *page); |
2496 | extern int simple_write_begin(struct file *file, struct address_space *mapping, | 2497 | extern int simple_write_begin(struct file *file, struct address_space *mapping, |
@@ -2515,7 +2516,7 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count, | |||
2515 | extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, | 2516 | extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, |
2516 | const void __user *from, size_t count); | 2517 | const void __user *from, size_t count); |
2517 | 2518 | ||
2518 | extern int generic_file_fsync(struct file *, int); | 2519 | extern int generic_file_fsync(struct file *, loff_t, loff_t, int); |
2519 | 2520 | ||
2520 | extern int generic_check_addressable(unsigned, u64); | 2521 | extern int generic_check_addressable(unsigned, u64); |
2521 | 2522 | ||
@@ -277,13 +277,13 @@ static int shm_release(struct inode *ino, struct file *file) | |||
277 | return 0; | 277 | return 0; |
278 | } | 278 | } |
279 | 279 | ||
280 | static int shm_fsync(struct file *file, int datasync) | 280 | static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
281 | { | 281 | { |
282 | struct shm_file_data *sfd = shm_file_data(file); | 282 | struct shm_file_data *sfd = shm_file_data(file); |
283 | 283 | ||
284 | if (!sfd->file->f_op->fsync) | 284 | if (!sfd->file->f_op->fsync) |
285 | return -EINVAL; | 285 | return -EINVAL; |
286 | return sfd->file->f_op->fsync(sfd->file, datasync); | 286 | return sfd->file->f_op->fsync(sfd->file, start, end, datasync); |
287 | } | 287 | } |
288 | 288 | ||
289 | static unsigned long shm_get_unmapped_area(struct file *file, | 289 | static unsigned long shm_get_unmapped_area(struct file *file, |