.llseek = generic_file_llseek,
.read = generic_read_dir,
.iterate_shared = ntfs_readdir,
- .fsync = generic_file_fsync,
+ .fsync = ntfs_file_fsync,
.open = ntfs_file_open,
.unlocked_ioctl = ntfs_ioctl,
#ifdef CONFIG_COMPAT
/*
* ntfs_file_fsync - file_operations::fsync
*/
-static int ntfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+int ntfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
struct inode *inode = file_inode(file);
- if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
+ struct super_block *sb = inode->i_sb;
+ struct ntfs_sb_info *sbi = sb->s_fs_info;
+ int err, ret;
+
+ if (unlikely(ntfs3_forced_shutdown(sb)))
return -EIO;
- return generic_file_fsync(file, start, end, datasync);
+ ret = file_write_and_wait_range(file, start, end);
+ if (ret)
+ return ret;
+
+ ret = write_inode_now(inode, !datasync);
+
+ if (!ret) {
+ ret = ni_write_parents(ntfs_i(inode), !datasync);
+ }
+
+ if (!ret) {
+ ntfs_set_state(sbi, NTFS_DIRTY_CLEAR);
+ ntfs_update_mftmirr(sbi, false);
+ }
+
+ err = sync_blockdev(sb->s_bdev);
+ if (unlikely(err && !ret))
+ ret = err;
+ if (!ret)
+ blkdev_issue_flush(sb->s_bdev);
+ return ret;
}
// clang-format off
return false;
}
+/*
+ * ni_write_parents
+ *
+ * Helper function for ntfs_file_fsync.
+ */
+int ni_write_parents(struct ntfs_inode *ni, int sync)
+{
+ int err = 0;
+ struct ATTRIB *attr = NULL;
+ struct ATTR_LIST_ENTRY *le = NULL;
+ struct ntfs_sb_info *sbi = ni->mi.sbi;
+ struct super_block *sb = sbi->sb;
+
+ while ((attr = ni_find_attr(ni, attr, &le, ATTR_NAME, NULL, 0, NULL,
+ NULL))) {
+ struct inode *dir;
+ struct ATTR_FILE_NAME *fname;
+
+ fname = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME);
+ if (!fname)
+ continue;
+
+ /* Check simple case when parent inode equals current inode. */
+ if (ino_get(&fname->home) == ni->vfs_inode.i_ino) {
+ if (MFT_REC_ROOT != ni->vfs_inode.i_ino) {
+ ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+ err = -EINVAL;
+ }
+ continue;
+ }
+
+ dir = ntfs_iget5(sb, &fname->home, NULL);
+ if (IS_ERR(dir)) {
+ ntfs_inode_warn(
+ &ni->vfs_inode,
+ "failed to open parent directory r=%lx to write",
+ (long)ino_get(&fname->home));
+ continue;
+ }
+
+ if (!is_bad_inode(dir)) {
+ int err2 = write_inode_now(dir, sync);
+ if (!err)
+ err = err2;
+ }
+ iput(dir);
+ }
+
+ return err;
+}
+
/*
* ni_update_parent
*
int ntfs_file_open(struct inode *inode, struct file *file);
int ntfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len);
+int ntfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
long ntfs_ioctl(struct file *filp, u32 cmd, unsigned long arg);
long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg);
extern const struct inode_operations ntfs_special_inode_operations;
struct NTFS_DE *new_de);
bool ni_is_dirty(struct inode *inode);
+int ni_write_parents(struct ntfs_inode *ni, int sync);
/* Globals from fslog.c */
bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes);