diff options
Diffstat (limited to 'module/zfs/zfs_vnops.c')
-rw-r--r-- | module/zfs/zfs_vnops.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 1552b61e0..6f25a6fff 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -125,7 +125,11 @@ * forever, because the previous txg can't quiesce until B's tx commits. * * If dmu_tx_assign() returns ERESTART and zsb->z_assign is TXG_NOWAIT, - * then drop all locks, call dmu_tx_wait(), and try again. + * then drop all locks, call dmu_tx_wait(), and try again. On subsequent + * calls to dmu_tx_assign(), pass TXG_WAITED rather than TXG_NOWAIT, + * to indicate that this operation has already called dmu_tx_wait(). + * This will ensure that we don't retry forever, waiting a short bit + * each time. * * (5) If the operation succeeded, generate the intent log entry for it * before dropping locks. This ensures that the ordering of events @@ -147,12 +151,13 @@ * rw_enter(...); // grab any other locks you need * tx = dmu_tx_create(...); // get DMU tx * dmu_tx_hold_*(); // hold each object you might modify - * error = dmu_tx_assign(tx, TXG_NOWAIT); // try to assign + * error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); * if (error) { * rw_exit(...); // drop locks * zfs_dirent_unlock(dl); // unlock directory entry * iput(...); // release held vnodes * if (error == ERESTART) { + * waited = B_TRUE; * dmu_tx_wait(tx); * dmu_tx_abort(tx); * goto top; @@ -1279,6 +1284,7 @@ zfs_create(struct inode *dip, char *name, vattr_t *vap, int excl, zfs_acl_ids_t acl_ids; boolean_t fuid_dirtied; boolean_t have_acl = B_FALSE; + boolean_t waited = B_FALSE; /* * If we have an ephemeral id, ACL, or XVATTR then @@ -1391,10 +1397,11 @@ top: dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, acl_ids.z_aclp->z_acl_bytes); } - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { zfs_dirent_unlock(dl); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; @@ -1524,6 +1531,7 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr) #endif /* HAVE_PN_UTILS */ int error; int zflg = ZEXISTS; + boolean_t waited = B_FALSE; ZFS_ENTER(zsb); ZFS_VERIFY_ZP(dzp); @@ -1599,13 +1607,14 @@ top: /* charge as an update -- would be nice not to charge at all */ dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL); - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { zfs_dirent_unlock(dl); iput(ip); if (xzp) iput(ZTOI(xzp)); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; @@ -1710,6 +1719,7 @@ zfs_mkdir(struct inode *dip, char *dirname, vattr_t *vap, struct inode **ipp, gid_t gid = crgetgid(cr); zfs_acl_ids_t acl_ids; boolean_t fuid_dirtied; + boolean_t waited = B_FALSE; ASSERT(S_ISDIR(vap->va_mode)); @@ -1801,10 +1811,11 @@ top: dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes + ZFS_SA_BASE_ATTR_SIZE); - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { zfs_dirent_unlock(dl); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; @@ -1882,6 +1893,7 @@ zfs_rmdir(struct inode *dip, char *name, struct inode *cwd, cred_t *cr, dmu_tx_t *tx; int error; int zflg = ZEXISTS; + boolean_t waited = B_FALSE; ZFS_ENTER(zsb); ZFS_VERIFY_ZP(dzp); @@ -1935,13 +1947,14 @@ top: dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL); zfs_sa_upgrade_txholds(tx, zp); zfs_sa_upgrade_txholds(tx, dzp); - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { rw_exit(&zp->z_parent_lock); rw_exit(&zp->z_name_lock); zfs_dirent_unlock(dl); iput(ip); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; @@ -3169,6 +3182,7 @@ zfs_rename(struct inode *sdip, char *snm, struct inode *tdip, char *tnm, int cmp, serr, terr; int error = 0; int zflg = 0; + boolean_t waited = B_FALSE; ZFS_ENTER(zsb); ZFS_VERIFY_ZP(sdzp); @@ -3383,7 +3397,7 @@ top: zfs_sa_upgrade_txholds(tx, szp); dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL); - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { if (zl != NULL) zfs_rename_unlock(&zl); @@ -3397,6 +3411,7 @@ top: if (tzp) iput(ZTOI(tzp)); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; @@ -3504,6 +3519,7 @@ zfs_symlink(struct inode *dip, char *name, vattr_t *vap, char *link, zfs_acl_ids_t acl_ids; boolean_t fuid_dirtied; uint64_t txtype = TX_SYMLINK; + boolean_t waited = B_FALSE; ASSERT(S_ISLNK(vap->va_mode)); @@ -3568,10 +3584,11 @@ top: } if (fuid_dirtied) zfs_fuid_txhold(zsb, tx); - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { zfs_dirent_unlock(dl); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; @@ -3699,6 +3716,7 @@ zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr) int zf = ZNEW; uint64_t parent; uid_t owner; + boolean_t waited = B_FALSE; ASSERT(S_ISDIR(tdip->i_mode)); @@ -3782,10 +3800,11 @@ top: dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name); zfs_sa_upgrade_txholds(tx, szp); zfs_sa_upgrade_txholds(tx, dzp); - error = dmu_tx_assign(tx, TXG_NOWAIT); + error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT); if (error) { zfs_dirent_unlock(dl); if (error == ERESTART) { + waited = B_TRUE; dmu_tx_wait(tx); dmu_tx_abort(tx); goto top; |