Re: [PATCH v2 4/7] nfsd: run the fence script when a block layout lease break times out
From: Chuck Lever
Date: Wed Oct 14 2026 - 17:05:16 EST
On 10/14/26, Daejun Park wrote:
> @@ -1004,7 +1075,33 @@ static void nfsd4_layout_fence_worker(struct work_struct *work)
> clp = ls->ls_stid.sc_client;
> nn = net_generic(clp->net, nfsd_net_id);
> bdev = nf->nf_file->f_path.mnt->mnt_sb->s_bdev;
> - if (nfsd4_layout_ops[ls->ls_layout_type]->fence_client(ls, nf)) {
> + ops = nfsd4_layout_ops[ls->ls_layout_type];
> + if (!ops->fence_client) {
> + struct nfsd4_fence_script *fs = ls->ls_fence_script;
> +
> + /*
> + * The layout type cannot fence. Run the fence script, as a
> + * failed recall does, and give the lease up once it is done.
> + */
> + if (!fs) {
> + fs = nfsd4_start_fence_script(ls, nf);
> + ls->ls_fence_script = fs;
> + }
> + nfsd_file_put(nf);
> + /* Pairs with nfsd4_fence_script_work() */
> + if (fs && smp_load_acquire(&fs->done))
> + goto dispose;
> + spin_lock(&ls->ls_lock);
> + if (ls->ls_fence_stopped) {
> + spin_unlock(&ls->ls_lock);
> + goto dispose;
> + }
> + mod_delayed_work(system_dfl_wq, &ls->ls_fence_work,
> + NFSD4_FENCE_SCRIPT_POLL);
> + spin_unlock(&ls->ls_lock);
> + return;
> + }
When nfsd4_start_fence_script() returns NULL, fs stays NULL,
the done check is skipped, and the worker re-arms itself every
100 ms until an allocation succeeds. The fence_client failure
path right below backs off through ls_fence_delay and warns
once; this path does neither. A GFP_KERNEL allocation this
small rarely fails, so the practical exposure is tiny, but the
retry could reuse ls_fence_delay rather than the script poll
interval when fs is NULL.
Also, the fence script can run twice for one stateid. The
lease break times out first and this worker runs it. If
the client stays silent, the CB_LAYOUTRECALL later reaches its
two-lease-period cutoff and nfsd4_cb_layout_done() runs it
again through nfsd4_cb_layout_fail(), since that path checks
only whether layouts remain and never ls_fenced. For a dead
client both fire. nfsd4_cb_layout_done() could skip the fence
when ls_fenced is already set.
Related: nfsd4_cb_layout_fail() now builds the same address
string and s_id that nfsd4_start_fence_script() builds, and
hands them to the same helper. If the first became a call to
the second, the two fence triggers would share one argv
construction.
--
Chuck Lever (Come to NFS bake-a-thon! https://nfsv4bat.org)