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 <tuxoko@gmail.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #1962
This commit is contained in:
Chunwei Chen 2013-12-17 10:18:25 -08:00 committed by Brian Behlendorf
parent c2d439dffd
commit 7dc71949f2
2 changed files with 7 additions and 10 deletions

View File

@ -235,13 +235,9 @@ zfs_close(struct inode *ip, int flag, cred_t *cr)
ZFS_ENTER(zsb); ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp); ZFS_VERIFY_ZP(zp);
/* /* Decrement the synchronous opens in the znode */
* 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.
*/
if (flag & O_SYNC) 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) && if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) &&
!(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0) !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0)

View File

@ -36,15 +36,16 @@ zpl_open(struct inode *ip, struct file *filp)
cred_t *cr = CRED(); cred_t *cr = CRED();
int error; int error;
error = generic_file_open(ip, filp);
if (error)
return (error);
crhold(cr); crhold(cr);
error = -zfs_open(ip, filp->f_mode, filp->f_flags, cr); error = -zfs_open(ip, filp->f_mode, filp->f_flags, cr);
crfree(cr); crfree(cr);
ASSERT3S(error, <=, 0); ASSERT3S(error, <=, 0);
if (error)
return (error); return (error);
return generic_file_open(ip, filp);
} }
static int static int