FAILED: patch "[PATCH] NFSv4/pnfs: Free the netid when draining a data-server" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x a7c8e96d1b9fa327cbdea514d047c8295b28d49a
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026110412-compost-spending-c7bf@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a7c8e96d1b9fa327cbdea514d047c8295b28d49a Mon Sep 17 00:00:00 2001
From: Benjamin Coddington <[email protected]>
Date: Tue, 15 Sep 2026 08:22:03 -0400
Subject: [PATCH] NFSv4/pnfs: Free the netid when draining a data-server
address list
nfs4_pnfs_ds_addr_free() releases all three of an address entry's allocations, but the four sites that drain a decoded list before it reaches a data server open-code the loop and free only da_remotestr and the entry, leaking da_netid. Both layout drivers drain that list when nfs4_pnfs_ds_add() returned a data server already in the cache, and again on their error exits.
Lift the drain into nfs4_pnfs_ds_addr_list_free() so an address list has one owner. A striping mount reaches the cached case on nearly every GETDEVICEINFO, since many deviceIDs name the same data servers.
fs/nfs/filelayout/filelayoutdev.c +2 -15
@@ -177,27 +177,14 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,trace_fl_getdevinfo (server, &pdev->dev_id, dsaddr->ds_list[i]->ds_remotestr);/* If DS was already in cache, free ds addrs */ -while (!list_empty (&dsaddrs)) { - da =list_first_entry (&dsaddrs, - struct nfs4_pnfs_ds_addr, - da_node); -list_del_init (&da->da_node); -kfree (da->da_remotestr); -kfree (da); - } +nfs4_pnfs_ds_addr_list_free (&dsaddrs); }folio_put (scratch);return dsaddr; out_err_drain_dsaddrs: -while (!list_empty (&dsaddrs)) { - da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, - da_node); -list_del_init (&da->da_node); -kfree (da->da_remotestr); -kfree (da); - } +nfs4_pnfs_ds_addr_list_free (&dsaddrs); out_err_free_deviceid:nfs4_fl_free_deviceid (dsaddr);/* stripe_indicies was part of dsaddr */
fs/nfs/flexfilelayout/flexfilelayoutdev.c +2 -15
@@ -159,26 +159,13 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, goto out_err_drain_dsaddrs;/* If DS was already in cache, free ds addrs */ -while (!list_empty (&dsaddrs)) { - da =list_first_entry (&dsaddrs, - struct nfs4_pnfs_ds_addr, - da_node); -list_del_init (&da->da_node); -kfree (da->da_remotestr); -kfree (da); - } +nfs4_pnfs_ds_addr_list_free (&dsaddrs);folio_put (scratch);return new_ds; out_err_drain_dsaddrs: -while (!list_empty (&dsaddrs)) { - da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, - da_node); -list_del_init (&da->da_node); -kfree (da->da_remotestr); -kfree (da); - } +nfs4_pnfs_ds_addr_list_free (&dsaddrs);kfree (ds_versions); out_scratch:
fs/nfs/pnfs.h +1 -0
@@ -427,6 +427,7 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr (struct net *net,struct xdr_stream *xdr,gfp_t gfp_flags); +void nfs4_pnfs_ds_addr_list_free (struct list_head *dsaddrs); void pnfs_layout_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg, struct nfs_commit_info *cinfo,
fs/nfs/pnfs_nfs.c +13 -8
@@ -633,23 +633,28 @@ static void nfs4_pnfs_ds_addr_free(struct nfs4_pnfs_ds_addr *da)kfree (da); } -static void destroy_ds (struct nfs4_pnfs_ds *ds) +void nfs4_pnfs_ds_addr_list_free (struct list_head *dsaddrs) {struct nfs4_pnfs_ds_addr *da; +while (!list_empty (dsaddrs)) { + da = list_first_entry(dsaddrs, struct nfs4_pnfs_ds_addr, + da_node); +list_del_init (&da->da_node); +nfs4_pnfs_ds_addr_free (da); + } +} +EXPORT_SYMBOL_GPL (nfs4_pnfs_ds_addr_list_free); + +static void destroy_ds (struct nfs4_pnfs_ds *ds) +{dprintk ("--> %s\n" , __func__);ifdebug (FACILITY)print_ds (ds);nfs_put_client (ds->ds_clp); -while (!list_empty (&ds->ds_addrs)) { - da =list_first_entry (&ds->ds_addrs, - struct nfs4_pnfs_ds_addr, - da_node); -list_del_init (&da->da_node); -nfs4_pnfs_ds_addr_free (da); - } +nfs4_pnfs_ds_addr_list_free (&ds->ds_addrs);kfree (ds->ds_remotestr);kfree (ds);