From 7dc71949f2f013a7bf744230d60770893ce23a6a Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Tue, 17 Dec 2013 10:18:25 -0800 Subject: [PATCH] Fix z_sync_cnt decrement in zfs_close The comment in zfs_close states that "Under Linux the zfs_close() hook is not symmetric with zfs_open()". This is not true. zfs_open/zfs_close is associated with every successful struct file creation/deletion, which should always be balanced. Here is an example of what's wrong: Process A B open(O_SYNC) z_sync_cnt = 1 open(O_SYNC) z_sync_cnt = 2 close() z_sync_cnt = 0 So z_sync_cnt is 0 even if B still has the file with O_SYNC. Also moves the generic_file_open call before zfs_open to ensure that in the case generic_file_open fails z_sync_cnt is not incremented. This is safe because generic_file_open has no side effects. Signed-off-by: Chunwei Chen Signed-off-by: Brian Behlendorf Issue #1962 --- module/zfs/zfs_vnops.c | 8 ++------ module/zfs/zpl_file.c | 9 +++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 4a34f055a..8e4694ff6 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -235,13 +235,9 @@ zfs_close(struct inode *ip, int flag, cred_t *cr) ZFS_ENTER(zsb); ZFS_VERIFY_ZP(zp); - /* - * Zero the synchronous opens in the znode. Under Linux the - * zfs_close() hook is not symmetric with zfs_open(), it is - * only called once when the last reference is dropped. - */ + /* Decrement the synchronous opens in the znode */ if (flag & O_SYNC) - zp->z_sync_cnt = 0; + atomic_dec_32(&zp->z_sync_cnt); if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) && !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0) diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 0d46eee02..690f93838 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -36,15 +36,16 @@ zpl_open(struct inode *ip, struct file *filp) cred_t *cr = CRED(); int error; + error = generic_file_open(ip, filp); + if (error) + return (error); + crhold(cr); error = -zfs_open(ip, filp->f_mode, filp->f_flags, cr); crfree(cr); ASSERT3S(error, <=, 0); - if (error) - return (error); - - return generic_file_open(ip, filp); + return (error); } static int