]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix z_sync_cnt decrement in zfs_close
authorChunwei Chen <tuxoko@gmail.com>
Tue, 17 Dec 2013 18:18:25 +0000 (10:18 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 17 Dec 2013 18:28:27 +0000 (10:28 -0800)
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 <tuxoko@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #1962

module/zfs/zfs_vnops.c
module/zfs/zpl_file.c

index 4a34f055aeafd95868f4531ef47ef669bff33b83..8e4694ff6286223860f7232aee1b2a66301ee777 100644 (file)
@@ -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)
index 0d46eee0268962477ef6b3a2fd559ff7ceaea8e3..690f938389dfe9d9760995587a5d3a9998fa2bdf 100644 (file)
@@ -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