Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions drivers/ntb/ntb_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ MODULE_VERSION(NTB_TRANSPORT_VER);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Intel Corporation");

static unsigned long max_mw_size;
static unsigned long max_mw_size = 256 * 1024 * 1024;
module_param(max_mw_size, ulong, 0644);
MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows");

Expand Down Expand Up @@ -927,8 +927,8 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
xlat_size = round_up(size, xlat_align_size);
buff_size = round_up(size, xlat_align);

/* No need to re-setup */
if (mw->xlat_size == xlat_size)
/* No need to re-setup if size already matches */
if (mw->xlat_size == xlat_size && mw->buff_size == buff_size)
return 0;

if (mw->buff_size)
Expand Down Expand Up @@ -1048,8 +1048,11 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt)
if (!nt->link_is_up)
cancel_delayed_work_sync(&nt->link_work);

for (i = 0; i < nt->mw_count; i++)
ntb_free_mw(nt, i);
/*
* Do NOT free MW memory on link down. Memory is retained across
* link cycles to avoid fragmentation from repeated allocation.
* Memory is only freed on device removal in ntb_transport_free().
*/

/* The scratchpad registers keep the values if the remote side
* goes down, blast them now to give them a sane value the next
Expand Down Expand Up @@ -1332,6 +1335,34 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt,
return 0;
}

/*
* Speculatively pre-allocate memory assuming symmetric config.
* This grabs contiguous memory early before fragmentation.
* If peer has different size, we'll reallocate on link-up.
*/
static void ntb_preallocate_mws(struct ntb_transport_ctx *nt)
{
struct ntb_transport_mw *mw;
resource_size_t size;
int i, rc;

for (i = 0; i < nt->mw_count; i++) {
mw = &nt->mw_vec[i];
size = mw->phys_size;

if (max_mw_size && size > max_mw_size)
size = max_mw_size;

rc = ntb_set_mw(nt, i, size);
if (rc) {
dev_info(&nt->ndev->pdev->dev,
"Failed to preallocate MW%d (size %llx): %d\n",
i, (unsigned long long)size, rc);
/* Continue - link-up will retry */
}
}
}

static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
{
struct ntb_transport_ctx *nt;
Expand Down Expand Up @@ -1476,6 +1507,9 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work);
nt->link_is_up = false;

/* Speculatively pre-allocate MW buffers to avoid fragmentation */
ntb_preallocate_mws(nt);

rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops);
if (rc)
goto err2;
Expand All @@ -1495,9 +1529,11 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev)
err2:
kfree(nt->qp_vec);
err1:
while (i--) {
for (i = 0; i < mw_count; i++) {
mw = &nt->mw_vec[i];
iounmap(mw->vbase);
ntb_free_mw(nt, i);
if (mw->vbase)
iounmap(mw->vbase);
}
kfree(nt->mw_vec);
err:
Expand Down
33 changes: 31 additions & 2 deletions fs/nfsd/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,20 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
nfsd_mountpoint(dentry, exp) == 2) {
/* This is only a mountpoint in some other namespace */
path_put(&path);
#ifdef CONFIG_TRUENAS
/*
* For snapdir entries we set LOOKUP_AUTOMOUNT above, so
* if the path is unchanged the automount was attempted
* and failed (EISDIR from zfsctl_snapshot_mount). This
* can happen transiently when zfs_suspend_fs races with
* the mount helper after the z_teardown_lock deadlock
* fix (see https://github.com/openzfs/zfs/pull/18415).
* Return ESTALE so the client retries via LOOKUP rather
* than caching the ctldir stub as an empty directory.
*/
if (is_snapdir)
err = -ESTALE;
#endif /* CONFIG_TRUENAS */
goto out;
}

Expand All @@ -201,8 +215,23 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
* allowed without an explicit export of the new
* directory.
*/
if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT))
err = 0;
if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT)) {
#ifdef CONFIG_TRUENAS
/*
* For ZFS snapshot entries under a zfs_snapdir
* export, the fallback dentry is an automount
* stub with simple_dir_operations that returns
* empty READDIR (NFS4_OK, zero entries). The
* client caches this silently with no error
* signal to trigger re-resolution. Return ESTALE
* so the client retries via LOOKUP.
*/
if (is_snapdir)
err = -ESTALE;
else
#endif /* CONFIG_TRUENAS */
err = 0;
}
path_put(&path);
goto out;
}
Expand Down
Loading