Skip to content

Commit 19d5507

Browse files
ahrensbehlendorf
authored andcommitted
Illumos 4950 - files sometimes can't be removed from a full filesystem
4950 files sometimes can't be removed from a full filesystem Reviewed by: Adam Leventhal <adam.leventhal@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Sebastien Roy <sebastien.roy@delphix.com> Reviewed by: Boris Protopopov <bprotopopov@hotmail.com> Approved by: Dan McDonald <danmcd@omniti.com> References: https://www.illumos.org/issues/4950 illumos/illumos-gate@4bb7380 Porting notes: - ZoL currently does not log discards to zvols, so the portion of this patch that modifies the discard logging to mark it as freeing space has been discarded. 2. may_delete_now had been removed from zfs_remove() in ZoL. It has been reintroduced. 3. We do not try to emulate vnodes, so the following lines are not valid on Linux: mutex_enter(&vp->v_lock); may_delete_now = vp->v_count == 1 && !vn_has_cached_data(vp); mutex_exit(&vp->v_lock); This has been replaced with: mutex_enter(&zp->z_lock); may_delete_now = atomic_read(&ip->i_count) == 1 && !(zp->z_is_mapped); mutex_exit(&zp->z_lock); Ported-by: Richard Yao <richard.yao@clusterhq.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
1 parent dfe0d02 commit 19d5507

File tree

7 files changed

+57
-7
lines changed

7 files changed

+57
-7
lines changed

include/sys/dmu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,7 @@ void dmu_tx_abort(dmu_tx_t *tx);
665665
int dmu_tx_assign(dmu_tx_t *tx, enum txg_how txg_how);
666666
void dmu_tx_wait(dmu_tx_t *tx);
667667
void dmu_tx_commit(dmu_tx_t *tx);
668+
void dmu_tx_mark_netfree(dmu_tx_t *tx);
668669

669670
/*
670671
* To register a commit callback, dmu_tx_callback_register() must be called.

module/zfs/dmu.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,12 @@ dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
687687
tx = dmu_tx_create(os);
688688
dmu_tx_hold_free(tx, dn->dn_object,
689689
chunk_begin, chunk_end - chunk_begin);
690+
691+
/*
692+
* Mark this transaction as typically resulting in a net
693+
* reduction in space used.
694+
*/
695+
dmu_tx_mark_netfree(tx);
690696
err = dmu_tx_assign(tx, TXG_WAIT);
691697
if (err) {
692698
dmu_tx_abort(tx);
@@ -738,6 +744,7 @@ dmu_free_long_object(objset_t *os, uint64_t object)
738744
tx = dmu_tx_create(os);
739745
dmu_tx_hold_bonus(tx, object);
740746
dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END);
747+
dmu_tx_mark_netfree(tx);
741748
err = dmu_tx_assign(tx, TXG_WAIT);
742749
if (err == 0) {
743750
err = dmu_object_free(os, object, tx);

module/zfs/dmu_tx.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,32 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
610610
txh->txh_space_tounref += unref;
611611
}
612612

613+
/*
614+
* This function marks the transaction as being a "net free". The end
615+
* result is that refquotas will be disabled for this transaction, and
616+
* this transaction will be able to use half of the pool space overhead
617+
* (see dsl_pool_adjustedsize()). Therefore this function should only
618+
* be called for transactions that we expect will not cause a net increase
619+
* in the amount of space used (but it's OK if that is occasionally not true).
620+
*/
621+
void
622+
dmu_tx_mark_netfree(dmu_tx_t *tx)
623+
{
624+
dmu_tx_hold_t *txh;
625+
626+
txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
627+
DMU_NEW_OBJECT, THT_FREE, 0, 0);
628+
629+
/*
630+
* Pretend that this operation will free 1GB of space. This
631+
* should be large enough to cancel out the largest write.
632+
* We don't want to use something like UINT64_MAX, because that would
633+
* cause overflows when doing math with these values (e.g. in
634+
* dmu_tx_try_assign()).
635+
*/
636+
txh->txh_space_tofree = txh->txh_space_tounref = 1024 * 1024 * 1024;
637+
}
638+
613639
void
614640
dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
615641
{

module/zfs/zfs_dir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121
/*
2222
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23-
* Copyright (c) 2013 by Delphix. All rights reserved.
23+
* Copyright (c) 2013, 2014 by Delphix. All rights reserved.
2424
*/
2525

2626

@@ -578,6 +578,7 @@ zfs_purgedir(znode_t *dzp)
578578
dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
579579
/* Is this really needed ? */
580580
zfs_sa_upgrade_txholds(tx, xzp);
581+
dmu_tx_mark_netfree(tx);
581582
error = dmu_tx_assign(tx, TXG_WAIT);
582583
if (error) {
583584
dmu_tx_abort(tx);

module/zfs/zfs_vnops.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121
/*
2222
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23-
* Copyright (c) 2013 by Delphix. All rights reserved.
23+
* Copyright (c) 2012, 2015 by Delphix. All rights reserved.
2424
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
2525
* Copyright (c) 2015 by Chunwei Chen. All rights reserved.
2626
*/
@@ -1525,6 +1525,7 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr)
15251525
uint64_t obj = 0;
15261526
zfs_dirlock_t *dl;
15271527
dmu_tx_t *tx;
1528+
boolean_t may_delete_now;
15281529
boolean_t unlinked;
15291530
uint64_t txtype;
15301531
pathname_t *realnmp = NULL;
@@ -1584,6 +1585,10 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr)
15841585
dnlc_remove(dvp, name);
15851586
#endif /* HAVE_DNLC */
15861587

1588+
mutex_enter(&zp->z_lock);
1589+
may_delete_now = atomic_read(&ip->i_count) == 1 && !(zp->z_is_mapped);
1590+
mutex_exit(&zp->z_lock);
1591+
15871592
/*
15881593
* We never delete the znode and always place it in the unlinked
15891594
* set. The dentry cache will always hold the last reference and
@@ -1609,6 +1614,14 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr)
16091614
/* charge as an update -- would be nice not to charge at all */
16101615
dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
16111616

1617+
/*
1618+
* Mark this transaction as typically resulting in a net free of
1619+
* space, unless object removal will be delayed indefinitely
1620+
* (due to active holds on the vnode due to the file being open).
1621+
*/
1622+
if (may_delete_now)
1623+
dmu_tx_mark_netfree(tx);
1624+
16121625
error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
16131626
if (error) {
16141627
zfs_dirent_unlock(dl);

module/zfs/zfs_znode.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121
/*
2222
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23-
* Copyright (c) 2013 by Delphix. All rights reserved.
23+
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
2424
*/
2525

2626
/* Portions Copyright 2007 Jeremy Teo */
@@ -1425,7 +1425,7 @@ zfs_grow_blocksize(znode_t *zp, uint64_t size, dmu_tx_t *tx)
14251425
* IN: zp - znode of file to free data in.
14261426
* end - new end-of-file
14271427
*
1428-
* RETURN: 0 on success, error code on failure
1428+
* RETURN: 0 on success, error code on failure
14291429
*/
14301430
static int
14311431
zfs_extend(znode_t *zp, uint64_t end)
@@ -1545,7 +1545,7 @@ zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
15451545
* off - start of section to free.
15461546
* len - length of section to free.
15471547
*
1548-
* RETURN: 0 on success, error code on failure
1548+
* RETURN: 0 on success, error code on failure
15491549
*/
15501550
static int
15511551
zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
@@ -1624,7 +1624,7 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
16241624
* IN: zp - znode of file to free data in.
16251625
* end - new end-of-file.
16261626
*
1627-
* RETURN: 0 on success, error code on failure
1627+
* RETURN: 0 on success, error code on failure
16281628
*/
16291629
static int
16301630
zfs_trunc(znode_t *zp, uint64_t end)
@@ -1657,6 +1657,7 @@ zfs_trunc(znode_t *zp, uint64_t end)
16571657
tx = dmu_tx_create(zsb->z_os);
16581658
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
16591659
zfs_sa_upgrade_txholds(tx, zp);
1660+
dmu_tx_mark_netfree(tx);
16601661
error = dmu_tx_assign(tx, TXG_WAIT);
16611662
if (error) {
16621663
dmu_tx_abort(tx);
@@ -1691,7 +1692,7 @@ zfs_trunc(znode_t *zp, uint64_t end)
16911692
* flag - current file open mode flags.
16921693
* log - TRUE if this action should be logged
16931694
*
1694-
* RETURN: 0 on success, error code on failure
1695+
* RETURN: 0 on success, error code on failure
16951696
*/
16961697
int
16971698
zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)

module/zfs/zvol.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ zvol_update_volsize(uint64_t volsize, objset_t *os)
277277

278278
tx = dmu_tx_create(os);
279279
dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
280+
dmu_tx_mark_netfree(tx);
280281
error = dmu_tx_assign(tx, TXG_WAIT);
281282
if (error) {
282283
dmu_tx_abort(tx);

0 commit comments

Comments
 (0)