]> granicus.if.org Git - zfs/commitdiff
zfs does not honor NFS sync write semantics
authorGeorge Wilson <gwilson@zfsmail.com>
Mon, 11 Mar 2019 16:13:37 +0000 (12:13 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 11 Mar 2019 16:13:37 +0000 (09:13 -0700)
The linux kernel's nfsd implementation use RWF_SYNC to determine if the
write is synchronous or not. This flag is used to set the kernel's I/O
control block flags. Unfortunately, ZFS was not updated to inspect these
flags so NFS sync writes were not being honored.

This change maps the IOCB_* flags to the ZFS equivalent.

Reviewed-by: Don Brady <don.brady@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: George Wilson <george.wilson@delphix.com>
Closes #8474
Closes #8452
Closes #8486

module/zfs/zpl_file.c

index 8d9c44b37294531d73e51f36bf2aae7f90d6055b..45e82c80d5ed387a6619b15e848cf587ec8c59d8 100644 (file)
@@ -216,6 +216,30 @@ zpl_aio_fsync(struct kiocb *kiocb, int datasync)
 #error "Unsupported fops->fsync() implementation"
 #endif
 
+static inline int
+zfs_io_flags(struct kiocb *kiocb)
+{
+       int flags = 0;
+
+#if defined(IOCB_DSYNC)
+       if (kiocb->ki_flags & IOCB_DSYNC)
+               flags |= FDSYNC;
+#endif
+#if defined(IOCB_SYNC)
+       if (kiocb->ki_flags & IOCB_SYNC)
+               flags |= FSYNC;
+#endif
+#if defined(IOCB_APPEND)
+       if (kiocb->ki_flags & IOCB_APPEND)
+               flags |= FAPPEND;
+#endif
+#if defined(IOCB_DIRECT)
+       if (kiocb->ki_flags & IOCB_DIRECT)
+               flags |= FDIRECT;
+#endif
+       return (flags);
+}
+
 static ssize_t
 zpl_read_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
     unsigned long nr_segs, loff_t *ppos, uio_seg_t segment, int flags,
@@ -266,10 +290,12 @@ zpl_iter_read_common(struct kiocb *kiocb, const struct iovec *iovp,
        cred_t *cr = CRED();
        struct file *filp = kiocb->ki_filp;
        ssize_t read;
+       unsigned int f_flags = filp->f_flags;
 
+       f_flags |= zfs_io_flags(kiocb);
        crhold(cr);
        read = zpl_read_common_iovec(filp->f_mapping->host, iovp, count,
-           nr_segs, &kiocb->ki_pos, seg, filp->f_flags, cr, skip);
+           nr_segs, &kiocb->ki_pos, seg, f_flags, cr, skip);
        crfree(cr);
 
        file_accessed(filp);
@@ -362,10 +388,12 @@ zpl_iter_write_common(struct kiocb *kiocb, const struct iovec *iovp,
        cred_t *cr = CRED();
        struct file *filp = kiocb->ki_filp;
        ssize_t wrote;
+       unsigned int f_flags = filp->f_flags;
 
+       f_flags |= zfs_io_flags(kiocb);
        crhold(cr);
        wrote = zpl_write_common_iovec(filp->f_mapping->host, iovp, count,
-           nr_segs, &kiocb->ki_pos, seg, filp->f_flags, cr, skip);
+           nr_segs, &kiocb->ki_pos, seg, f_flags, cr, skip);
        crfree(cr);
 
        return (wrote);