Page MenuHomeFreeBSD

D15342.1775583621.diff
No OneTemporary

Size
4 KB
Referenced Files
None
Subscribers
None

D15342.1775583621.diff

Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
@@ -85,6 +85,7 @@
sa_attr_type_t *z_attr_table; /* SA attr mapping->id */
#define ZFS_OBJ_MTX_SZ 64
kmutex_t z_hold_mtx[ZFS_OBJ_MTX_SZ]; /* znode hold locks */
+ struct task z_unlinked_drain_task;
};
/*
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
@@ -281,6 +281,7 @@
zap_attribute_t zap;
dmu_object_info_t doi;
znode_t *zp;
+ dmu_tx_t *tx;
int error;
/*
@@ -318,6 +319,19 @@
vn_lock(ZTOV(zp), LK_EXCLUSIVE | LK_RETRY);
zp->z_unlinked = B_TRUE;
+#if defined(__FreeBSD__)
+ /*
+ * Due to changes in zfs_rmnode we need to make sure the
+ * link count is set to zero here.
+ */
+ zp->z_links = 0;
+ tx = dmu_tx_create(zfsvfs->z_os);
+ dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
+ VERIFY(0 == dmu_tx_assign(tx, TXG_WAIT));
+ VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_LINKS(zfsvfs),
+ &zp->z_links, sizeof (zp->z_links), tx));
+ dmu_tx_commit(tx);
+#endif
vput(ZTOV(zp));
}
zap_cursor_fini(&zc);
@@ -393,7 +407,6 @@
{
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
objset_t *os = zfsvfs->z_os;
- znode_t *xzp = NULL;
dmu_tx_t *tx;
uint64_t acl_obj;
uint64_t xattr_obj;
@@ -443,11 +456,8 @@
*/
error = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zfsvfs),
&xattr_obj, sizeof (xattr_obj));
- if (error == 0 && xattr_obj) {
- error = zfs_zget(zfsvfs, xattr_obj, &xzp);
- ASSERT3S(error, ==, 0);
- vn_lock(ZTOV(xzp), LK_EXCLUSIVE | LK_RETRY);
- }
+ if (error)
+ xattr_obj = 0;
acl_obj = zfs_external_acl(zp);
@@ -457,10 +467,8 @@
tx = dmu_tx_create(os);
dmu_tx_hold_free(tx, zp->z_id, 0, DMU_OBJECT_END);
dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
- if (xzp) {
+ if (xattr_obj)
dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, TRUE, NULL);
- dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
- }
if (acl_obj)
dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END);
@@ -475,9 +483,25 @@
dmu_tx_abort(tx);
zfs_znode_dmu_fini(zp);
zfs_znode_free(zp);
- goto out;
+ return;
}
+#if defined(__FreeBSD__)
+ /*
+ * FreeBSD's implemention of zfs_zget requires a vnode to back it.
+ * This means that we could end up calling into getnewvnode while
+ * calling zfs_rmnode as a result of a prior call to getnewvnode
+ * trying to clear vnodes out of the cache. If this repeats we can
+ * recurse enough that we overflow our stack. To avoid this, we
+ * avoid calling zfs_zget on the xattr znode and instead simply add
+ * it to the unlinked set and schedule a call to zfs_unlinked_drain.
+ */
+ if (xattr_obj) {
+ /* Add extended attribute directory to the unlinked set. */
+ VERIFY3U(0, ==,
+ zap_add_int(os, zfsvfs->z_unlinkedobj, xattr_obj, tx));
+ }
+#else
if (xzp) {
ASSERT(error == 0);
xzp->z_unlinked = B_TRUE; /* mark xzp for deletion */
@@ -486,6 +510,7 @@
&xzp->z_links, sizeof (xzp->z_links), tx));
zfs_unlinked_add(xzp, tx);
}
+#endif
/* Remove this znode from the unlinked set */
VERIFY3U(0, ==,
@@ -494,9 +519,16 @@
zfs_znode_delete(zp, tx);
dmu_tx_commit(tx);
-out:
- if (xzp)
- vput(ZTOV(xzp));
+
+ if (xattr_obj) {
+ /*
+ * We're using the FreeBSD taskqueue API here instead of
+ * the Solaris taskq API since the FreeBSD API allows for a
+ * task to be enqueued multiple times but executed once.
+ */
+ taskqueue_enqueue(system_taskq->tq_queue,
+ &zfsvfs->z_unlinked_drain_task);
+ }
}
static uint64_t
Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
===================================================================
--- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -972,6 +972,8 @@
return (0);
}
+static task_fn_t zfsvfs_task_unlinked_drain;
+
int
zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
{
@@ -1023,6 +1025,8 @@
mutex_init(&zfsvfs->z_lock, NULL, MUTEX_DEFAULT, NULL);
list_create(&zfsvfs->z_all_znodes, sizeof (znode_t),
offsetof(znode_t, z_link_node));
+ TASK_INIT(&zfsvfs->z_unlinked_drain_task, 0,
+ zfsvfs_task_unlinked_drain, zfsvfs);
#ifdef DIAGNOSTIC
rrm_init(&zfsvfs->z_teardown_lock, B_TRUE);
#else
@@ -2015,6 +2019,11 @@
}
#endif
+ while (taskqueue_cancel(system_taskq->tq_queue,
+ &zfsvfs->z_unlinked_drain_task, NULL) != 0)
+ taskqueue_drain(system_taskq->tq_queue,
+ &zfsvfs->z_unlinked_drain_task);
+
VERIFY(zfsvfs_teardown(zfsvfs, B_TRUE) == 0);
os = zfsvfs->z_os;
@@ -2559,3 +2568,10 @@
mtx_unlock(&mountlist_mtx);
}
#endif
+
+static void
+zfsvfs_task_unlinked_drain(void *context, int pending __unused)
+{
+
+ zfs_unlinked_drain((zfsvfs_t *)context);
+}

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 7, 5:40 PM (13 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28296139
Default Alt Text
D15342.1775583621.diff (4 KB)

Event Timeline