From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E42C3375AA6 for ; Fri, 20 Mar 2026 08:55:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996921; cv=none; b=ZcXBkDm42Iw6VppYd/zZF9njBCxfVwHcNiaiXRWJnBr9LBKOQUIVAAZCPAS7j5LPngYSG4fZTn20zJ/mDgbF03QXYPMY7pvUDfZZeorDDkOy8FG2NFKUpBG0OlIaC+LkcC0RnXZ+38tJjp+V4mgowVE7w+3uKiC8jtOFtCORpOc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996921; c=relaxed/simple; bh=GaK3fnyt6sUtJdGJ1MYlD0Zj97Sh5Zjn/UmRR+fsbns=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=VUcWOqNcASwKI6JZF6asKogAFmLmJ+T8drgUfIWeHs/DFQ5GAfg3PfKiYv7Kgn943idf3dCt9he8P3wECzMBhDaDSRxtwSuDO3KhM9HeuV9W3bfi91bzyogKD+96FFN6pI1T974nA1jriTwOMmZlYKlk5xGbjMR96Suqkv/7nNE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=jIUegXOV; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="jIUegXOV" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-35b9894f9ceso1930577a91.2 for ; Fri, 20 Mar 2026 01:55:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996919; x=1774601719; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=WgV220nsjvXYUtCcSN6gGHf35gDIvTt1U7idg/3OBAg=; b=jIUegXOVMODGeq7BYevvelsOBx0iDFcukCVoxXqPAx1lvGDcVjngh3jzkgcXwAikrU v17PHO5tTHqnwkpnqWrRKhpvHtvIcNQ9nIlAbDT6HvZA3rtyWcTjXc2ewudEI2zgBjyD WTwAt8lAcNedTr/yYL6wu+I7ImbKsusnGS1C83eChbifDSGcafhAkbyXWXbnPIR2Jk8r 0kdNudl1ZMFAQPffrTxzR+AVlay75kPk5+gYgOaeD8qQyjPAmTeCg1pNFlfPc9CNTsca IZ22fP1m7wQOj9TrvgDp7rpZyCcN/gIicfbsAQlvMHXhy6od7AFXIhJ4HX3S4j677tX2 Mn2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996919; x=1774601719; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=WgV220nsjvXYUtCcSN6gGHf35gDIvTt1U7idg/3OBAg=; b=Vl+I0au5c9nh0x2MosIcjlxXYXtc1ZOxZd526AJTYScOY0A2diO+FvvQA2Mm0eUumB stUegENff/1nq419bCTNFSrJPHo+us1A8Ia633JcxJbNf1DTlM/yE4aPFYAGGbMCVvLo ziMCywtBaZylYuH8k4J4mTHUONzWBq6vg6ApeZbFYhKVn3vPiONMla9JQ74dVbKwhOj0 03w4zbif4G2P/jKGZtNSznDYBDxud0AuCxvvzcnjbZwwAgthl/qSkhuiSbB1hEGH/UvV jU06MoK3/WiYzF1CND104XrYP9IsRdaXVJmXaQTBZFZa+vznb2wsHdOGOqN6IOWXYT9l ZElA== X-Forwarded-Encrypted: i=1; AJvYcCXjHvQWnglsJD2hU4hHSm1PiiVPJgpzAASHxybtQ0Q1bFlVYgYarpYONiFwcHgn6/KK7WKZZtgexGZgJZY=@vger.kernel.org X-Gm-Message-State: AOJu0YzvXFr9nUKK7gpUhFbWLy9C8HUO6uDjx9uiXxUd3H9cH4Ek7Grv 6qvB8QpEVOonxJ4RnTukUpfaU9wtOrC2uJ4yyaFbgZARsJU2P5zlHAaLvvfdnDb/ZOXSiPVthzL Cquo2IA== X-Received: from pjzl15.prod.google.com ([2002:a17:90b:78f:b0:35b:9114:f5fe]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:184c:b0:354:c593:b1a8 with SMTP id 98e67ed59e1d1-35bd2be16b5mr1830414a91.13.1773996919107; Fri, 20 Mar 2026 01:55:19 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:44 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=1297; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=GaK3fnyt6sUtJdGJ1MYlD0Zj97Sh5Zjn/UmRR+fsbns=; b=+/IvBeyEb1KCNPGCJl7fYirjn/sIcTPTyTsiNvrttl0wrz+0QELKMA77pGV/5JzGwEn4uyrqU 1JFgAyJdvwDAYFphJqt0GWYWcl0P/WoopApWoF1kDXk2/A0+tEL7oab X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-1-4886b578161b@google.com> Subject: [PATCH 1/7] usb: gadget: f_subset: Fix unbalanced refcnt in geth_free From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@vger.kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable geth_alloc() increments the reference count, but geth_free() fails to decrement it. This prevents the configuration of attributes via configfs after unlinking the function. Decrement the reference count in geth_free() to ensure proper cleanup. Fixes: 02832e56f88a ("usb: gadget: f_subset: add configfs support") Cc: stable@vger.kernel.org Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/f_subset.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/fu= nction/f_subset.c index 076072386e5e..74dc6da5c767 100644 --- a/drivers/usb/gadget/function/f_subset.c +++ b/drivers/usb/gadget/function/f_subset.c @@ -6,6 +6,7 @@ * Copyright (C) 2008 Nokia Corporation */ =20 +#include #include #include #include @@ -449,8 +450,13 @@ static struct usb_function_instance *geth_alloc_inst(v= oid) static void geth_free(struct usb_function *f) { struct f_gether *eth; + struct f_gether_opts *opts; + + opts =3D container_of(f->fi, struct f_gether_opts, func_inst); =20 eth =3D func_to_geth(f); + scoped_guard(mutex, &opts->lock) + opts->refcnt--; kfree(eth); } =20 --=20 2.53.0.959.g497ff81fa9-goog From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 247AA377014 for ; Fri, 20 Mar 2026 08:55:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996923; cv=none; b=gfTVD++nxhgP0b+BTUT17QFLQPuLc1F9RZ5SCNe++aeTTX6b7qlnGnskAvxPOpfJLhvDAsXhyrA4SyLYFEkC7yslEFBLJx8qjBKN+yjtGquiyiboqPTMtKHLYvqjC7qz3PJMiPJnfr5Ubbc5AlVXpfdiC8cnvdmL5d4dZiokDqo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996923; c=relaxed/simple; bh=6Wkr6y8zvwVGvQGPNYUT30NoBb4TcsrkrqZeBgojKgk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ssw324KBwPYQ8L3KsL6pQuztS5Lw/g3nuE2m4zeg15R0z/ZYn6VK7ppgMIsVjiRG7ldbHl3x6Vvws9vIicEMGPuPokkoQ/yXTJHF9uVwSSYrB+C0xCu3L+Seqsu4qJB5YQ9uRET2cvgJuHpDkIFiKpJ9nl4qTeX+c68FET1nOnc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=uUdz5pjF; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="uUdz5pjF" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-c70ea91bfe1so1534026a12.1 for ; Fri, 20 Mar 2026 01:55:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996921; x=1774601721; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=hZ7vsqBU2jtHuNF1VCOsuin7WLACvQQEK8+9Bbcoxqo=; b=uUdz5pjFTS+WCCMmWUWscbOP1MTYn/8UbNXYHATlZNrliZ/h2THIjq3bayR+sV0wgO bYkkE9KpGJLPjD/KIHzqV1ybWiGFEKkRMUzgsZb0cgGImtDRCtsI54QWNRkxZ5pL0EUE TrTZ/1HhIb0gOfWaC668vlLMTjTRJb+HHoZXcS1RqLVGw32+qRKhAd2y3nxHYPg+xpnQ mFvLm+6msxjjq2JDN5f04Dl/J84ub2jiim65HL6pvJDkquEHVmewDvlSLKK5nWaKQuNX 2yV/w6BQ+h0MOOdjyuvXyDTWO+toL2bRlauG2M9o9rm1JrVd3tXkF387x6U3ga9x8GY7 mwZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996921; x=1774601721; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=hZ7vsqBU2jtHuNF1VCOsuin7WLACvQQEK8+9Bbcoxqo=; b=O943lC4O5USZhe4VnmT+qZ/Eb9BLuGdaV5gqInE2aSaoRvYN90JL5Xi8OzhyUK9SPJ Lt02CkJ1ece9B16gX8nroUXf7JE18TvzKqcyvmvnBrbkrZHXF5JDC/liEAXc1TvJUKrB shCaK4uwJQuqQDED6RIR9ygEswf4TwkGD7dsvtWhdYx2O74fMfyC/e0G09nEr+JRi+Mw Tr4mSBuOonEtHRcb5aSjaEus0LgVgQVMbw0VexLiovozPM9N8RHK2FM4OtNCJYSCsXMh pDn/hPeavlIMsM8YeuLnJi6hJQZivTEcp+OoQyLBbG9Tz94mSXiTT17yV/oTqGiEtiis KdVw== X-Forwarded-Encrypted: i=1; AJvYcCVK98jVMZ/VHbA5tupP9SqohvlqzJoBHR+pdNgTVGhzxEQpW9ciFQqRo+JHbIfTxN5RLdC02A21SlIQpxc=@vger.kernel.org X-Gm-Message-State: AOJu0YzvxfJNfiFkvPf95z/DLQfLFF0TEt/6MGt2hnpu2TZP9a/hiHf1 jw1uptAGcQDXXCowiT6hzFwvYeVcQlJElTfbL/Wc3cgEDLnMlg+Xm8v2Vv+WJZ6Rk5X9hfbNwRs Mk+6H5Q== X-Received: from pfbbt10.prod.google.com ([2002:a05:6a00:438a:b0:82a:6e03:a17f]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:3d10:b0:82a:77f9:c563 with SMTP id d2e1a72fcca58-82a8c22deabmr1820957b3a.12.1773996921141; Fri, 20 Mar 2026 01:55:21 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:45 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=1561; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=6Wkr6y8zvwVGvQGPNYUT30NoBb4TcsrkrqZeBgojKgk=; b=v8vZYl0ZMCKyFw75/3cvh+rKLQGT0mxQMyM9i1ZigduUl/TMQ6/WSN2wbvDbTi7ITMVr9tAy2 OgCsgnfoDZ6AJKz/G4uH9hFs6gmLjtZtgdn5E3QO8DoyM/0L6RyzjAX X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-2-4886b578161b@google.com> Subject: [PATCH 2/7] usb: gadget: f_rndis: Protect RNDIS options with mutex From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@vger.kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The class/subclass/protocol options are suspectible to race conditions as they can be accessed concurrently through configfs. Use existing mutex to protect these options. This issue was identified during code inspection. Fixes: 73517cf49bd4 ("usb: gadget: add RNDIS configfs options for class/sub= class/protocol") Cc: stable@vger.kernel.org Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/f_rndis.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/fun= ction/f_rndis.c index 8b11d8d6d89c..521b4619d6be 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -11,6 +11,7 @@ =20 /* #define VERBOSE_DEBUG */ =20 +#include #include #include #include @@ -678,9 +679,11 @@ rndis_bind(struct usb_configuration *c, struct usb_fun= ction *f) return -ENOMEM; } =20 - rndis_iad_descriptor.bFunctionClass =3D rndis_opts->class; - rndis_iad_descriptor.bFunctionSubClass =3D rndis_opts->subclass; - rndis_iad_descriptor.bFunctionProtocol =3D rndis_opts->protocol; + scoped_guard(mutex, &rndis_opts->lock) { + rndis_iad_descriptor.bFunctionClass =3D rndis_opts->class; + rndis_iad_descriptor.bFunctionSubClass =3D rndis_opts->subclass; + rndis_iad_descriptor.bFunctionProtocol =3D rndis_opts->protocol; + } =20 /* * in drivers/usb/gadget/configfs.c:configfs_composite_bind() --=20 2.53.0.959.g497ff81fa9-goog From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB52F3783A7 for ; Fri, 20 Mar 2026 08:55:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996926; cv=none; b=VfdUeG+IQ1w+UdtZbRIdG6gdHem0w6uUcY+oXx+59YuKTlj8fEoGvkl/Wof7bzqBVSRVVyoL29ZLWXq4MKIt++6xb6Yo8C/Vv47/1eqwj/07AQ24/DtVr4vkjxc6pNBM1/PHM3mtBMI/5bVrhyGCqY2k5SXRdSv/kypRdTo+/+w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996926; c=relaxed/simple; bh=r5JeqbpaQSgzfD5nVZ2+4ZgQVe4wxzOwvDAuDGO/s2g=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=JiN+UsyCpYOaUFrqERTnoIPxfV0f2Egi4kz9E8qBBS4Y5Y1ovomWFjI4AkQh4Y3tO7n16ij2klCOxd4JGaNYle/Y1rrFmIhKO9EHa7pm6yUmAO2RCqSFWKQ0lYKx9onvq7UU4mjgLBoHmd3Zv6Lsw6+mcXznbgoIiEoUT7Xi7HY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=fMCDp536; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="fMCDp536" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-35b94e2caf9so2476244a91.0 for ; Fri, 20 Mar 2026 01:55:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996923; x=1774601723; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=1dWn+d5N9BmZH7+uNOdi4sUe7sM9CUAvkoQg+RhZqyg=; b=fMCDp536uKLz+Qau+iE4aKGJzuJDU+WabL3QVGmjUvZHcTP2bHIZbKSsWK8/QTGi/+ MVvmz3D/ZPYOMMaB+wkBDDCS22U9HkXiV350DAC7+UwevyYz5fUe3+Ats0esD6AxFnrU Xfs4EafJ02JZZfydBCMGR9VbqQoDtMgYYosPSuLdUbv4Ck7bvJmc3VA2V1gIivutY3WN X8R9hA0fBycopE/mtdlos3gW1t0g3T3b62M7G+wYqaquXwYIDgTI1LdKNPaJNwLxknir pPUb432GjYnqDVYDEwyevXlLTVVKMxp0Cv4S6crNI+KkOr1HThXtdwXXk4qKyvmnqc1o Uo8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996923; x=1774601723; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=1dWn+d5N9BmZH7+uNOdi4sUe7sM9CUAvkoQg+RhZqyg=; b=s5sad7p48dJMJNeJ6ReTxQVaHwKCVu9w15meCU/xF/bBZZYY3mGAou1Aqos7XztJ/V pyXc84B6HefSZsw6DkQyFMLWfYF9vh20cOtJpw3h5lwIz/xHWog5Akb8cwnjCdJ/GRY/ i0+L+sWy2wlUb4e9t1IAOl9JB3zJnkILxkYEbOAEnq59AiEgqDha6GJlSlHH3wrP3Hnp Z+LTgscVN+tqsgj64aeYrIzK+KVJags5j39p1i7VFtCMMLhOvCaIXUquDNNuKQIy/AN9 hAREjzId5dgZ9gBmkjgHhfY0/0SyvlO70XcQ80QZLSyyi4Ls4kH4GcqdsHLAwin2VbE5 SvQQ== X-Forwarded-Encrypted: i=1; AJvYcCWVDTYUXsMZJ3NKpVZOtg2l5ODTJGntNqEUqJuMavRitwRLTId+tKtI7A7TvR2M6HD4LfUIeLClcQMvS7s=@vger.kernel.org X-Gm-Message-State: AOJu0Yw1XiQsxZwL5sPbBwYE8m2zurMsw2BeSB+XOMKOmu5EF4P7LFT5 wpTAsudzyrzYnRZvi4WAye+G8e7DoUu+V3FLedUKd6hOHfmqFF5mdseD9+pGm/bgY2o1UdJXoEe jfUzklw== X-Received: from pjbei15.prod.google.com ([2002:a17:90a:e54f:b0:359:bc4:636]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:554e:b0:35b:9ab6:1d65 with SMTP id 98e67ed59e1d1-35bd2d52dc5mr1663642a91.25.1773996923152; Fri, 20 Mar 2026 01:55:23 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:46 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=1808; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=r5JeqbpaQSgzfD5nVZ2+4ZgQVe4wxzOwvDAuDGO/s2g=; b=zvaz6HcwncN9XVtstgwC9aPtuRPoIf8obg4Gc/e+qJ+iyNk+ZMbETqriLLPo7gpzCHMvHvtdP nvSn224/OS2D+4wn+wViROkQiOArwYnBk4OQhn9dJmG8/0i0B350BWG X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-3-4886b578161b@google.com> Subject: [PATCH 3/7] usb: gadget: u_ncm: Add kernel-doc comments for struct f_ncm_opts From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Provide kernel-doc descriptions for the fields in struct f_ncm_opts to improve code readability and maintainability. Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/u_ncm.h | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/funct= ion/u_ncm.h index b1f3db8b68c1..ce2f6358688a 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -15,6 +15,20 @@ =20 #include =20 +/** + * struct f_ncm_opts - NCM function options + * @func_inst: USB function instance. + * @net: The net_device associated with the NCM function. + * @bind_count: Tracks the number of configurations the NCM function is + * bound to, preventing double-registration of the @net devic= e. + * @ncm_interf_group: ConfigFS group for NCM interface. + * @ncm_os_desc: USB OS descriptor for NCM. + * @ncm_ext_compat_id: Extended compatibility ID. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + * @max_segment_size: Maximum segment size. + */ struct f_ncm_opts { struct usb_function_instance func_inst; struct net_device *net; @@ -23,12 +37,7 @@ struct f_ncm_opts { struct config_group *ncm_interf_group; struct usb_os_desc ncm_os_desc; char ncm_ext_compat_id[16]; - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ + struct mutex lock; int refcnt; =20 --=20 2.53.0.959.g497ff81fa9-goog From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DC901375AB7 for ; Fri, 20 Mar 2026 08:55:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996928; cv=none; b=rK2WzSpD8yXXNEbt2lGoy3DuklozKCWlIrslZhGcWD23OBqegNAUoRqRvKRyVCgnkrZmgJHrdnG75GIszLgBn0xZ1MjR2odlpJa7jk3iotOaYK4sEQcUrlBX4I7fduzlCwyhi/zE+BU3Y3UcrETOKfnKOi1OE4KlQmROv1LmiYs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996928; c=relaxed/simple; bh=4/S5YwJtiRcOJLh0doDppzz03D/F2sOSKYaUGL9+H3w=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=p2xtz+rQGMlYpoQGH31CwpIhUf+t/wjfE61E9GnHcxbkN48a0nBYBiWOvD6eHapBlgQBOM3/VB9jr0t7WnB3Jts7ahlyQJKdJv8ZOthlg1kHmkOKvjz6Xw0SVyaZPPwm+M9cUg8LGmQuWctMu7icAt1nmpJVvX1ad+eYIJ1rOHU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=DO8zXwgz; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="DO8zXwgz" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2adef9d486bso5044445ad.2 for ; Fri, 20 Mar 2026 01:55:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996925; x=1774601725; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=NsaPvT56/j6vgEjoBK8KqcyeaZ1+Z9ul5l9Dxmc51yw=; b=DO8zXwgzUcijAeiQhvnEnhkT7V9/i8FA2FNsVfAg4ml69wm6/rsqew8uF3QVQcOfPg hCCMdjxrSfT9TpRY0b1mwr0BVwt8gbw7EVAJgWqdQGKmXgy/srXuubI8VIIoexg93hLQ TzkVDo8Y3XmOLWnVZIlww+NQAjXct2pQ5f74SnJKW+q0H5OL+TfKoxTyh5Eut6x9GOcr affs677YRsWTuwQPpNW9Zy45xN+vF+A7HZPgIbweW13gxTko/iQB1IGwzNS6OKRis/8/ fHRAia3tDgSCVeDNlrqAOIs5t5RYvEgXDNux8MbwSq27P23/Qwkxk22t0650DL0qSggz V9aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996925; x=1774601725; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=NsaPvT56/j6vgEjoBK8KqcyeaZ1+Z9ul5l9Dxmc51yw=; b=p4MJlcQUYkC9M2Am9can5afosS82C5NtJVhJTVqS2USQrupbbsblv4S8sW/DVOMqOy C/wR/iR4d7smYNxL9RfU+JoMqclPiuq/jT64W8F3cmZhtgC4y+YAb3COjyGBkx1DESqH LRT5xqhp8dC9L/UyshyL7gn7TrFSQ0D0e+wuHpN7C30RGyv+8p5MfDuH8eqqCLZLThjI 3hTTD48ITyHp6qSDIobYyeeCQNaOklRjVieAmwrrBQfFQONy9PE2iO0vLvOlo7AbZSeR aeYQLcpK8NAtOd0BJ2b0/11dtAP8kCKgjKGj1oj8q4lcwDnCiqRvCgs36Ftz+Nddrj47 P4rw== X-Forwarded-Encrypted: i=1; AJvYcCVahOxh5fBrMsVT8+r55qkkeSitYIA3P9q1HjdleM8/Y3Lz+iJ+BZJHYwbDztWnJ+xejbyhqTwGYmHaknI=@vger.kernel.org X-Gm-Message-State: AOJu0YzjeaA4XB0HqRiNZ5KKhw8lk8U5wDMe7FKL5FVpS2JOdx2LQEjD MPhK2a2v5lAQKzTNccAVLFM3xCmJm7cPqn0Iz+9ZkTlywXcO8Czm1olrqD5VoUQRcIfTFFov3iw 3gnqsgQ== X-Received: from plbmn16.prod.google.com ([2002:a17:903:a50:b0:2ae:6338:73ca]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:244b:b0:2b0:775f:febf with SMTP id d9443c01a7336-2b0827e31acmr20889385ad.40.1773996925176; Fri, 20 Mar 2026 01:55:25 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:47 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=5834; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=4/S5YwJtiRcOJLh0doDppzz03D/F2sOSKYaUGL9+H3w=; b=qmPTnpqjQMKy8j+UwaraSMVPgvdseTc5/s+eFxpFZgAomZWRtVZHUH3ig5ElyIv11IydUnMcg VKR1Ty7OGykDUepI5vS4nxNKI44aT8xMX2ariSqNui1PX+agKppBd6R X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-4-4886b578161b@google.com> Subject: [PATCH 4/7] usb: gadget: f_ecm: Fix net_device lifecycle with device_move From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@vger.kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks: console:/ # ls -l /sys/class/net/usb0 lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0 ls: .../gadget.0/net/usb0: No such file or directory Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering. To maintain compatibility with legacy composite drivers (e.g., multi.c), the bound flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase. Fixes: fee562a6450b ("usb: gadget: f_ecm: convert to new function interface= with backward compatibility") Cc: stable@vger.kernel.org Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/f_ecm.c | 37 ++++++++++++++++++++++++---------= ---- drivers/usb/gadget/function/u_ecm.h | 21 +++++++++++++++------ 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/funct= ion/f_ecm.c index e0c02121374e..e495bac4efeb 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -681,6 +681,7 @@ ecm_bind(struct usb_configuration *c, struct usb_functi= on *f) struct usb_ep *ep; =20 struct f_ecm_opts *ecm_opts; + struct net_device *net __free(detach_gadget) =3D NULL; struct usb_request *request __free(free_usb_request) =3D NULL; =20 if (!can_support_ecm(cdev->gadget)) @@ -688,18 +689,18 @@ ecm_bind(struct usb_configuration *c, struct usb_func= tion *f) =20 ecm_opts =3D container_of(f->fi, struct f_ecm_opts, func_inst); =20 - mutex_lock(&ecm_opts->lock); - - gether_set_gadget(ecm_opts->net, cdev->gadget); - - if (!ecm_opts->bound) { - status =3D gether_register_netdev(ecm_opts->net); - ecm_opts->bound =3D true; - } - - mutex_unlock(&ecm_opts->lock); - if (status) - return status; + scoped_guard(mutex, &ecm_opts->lock) + if (ecm_opts->bind_count =3D=3D 0 && !ecm_opts->bound) { + if (!device_is_registered(&ecm_opts->net->dev)) { + gether_set_gadget(ecm_opts->net, cdev->gadget); + status =3D gether_register_netdev(ecm_opts->net); + } else + status =3D gether_attach_gadget(ecm_opts->net, cdev->gadget); + + if (status) + return status; + net =3D ecm_opts->net; + } =20 ecm_string_defs[1].s =3D ecm->ethaddr; =20 @@ -790,6 +791,9 @@ ecm_bind(struct usb_configuration *c, struct usb_functi= on *f) =20 ecm->notify_req =3D no_free_ptr(request); =20 + ecm_opts->bind_count++; + retain_and_null_ptr(net); + DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n", ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->notify->name); @@ -836,7 +840,7 @@ static void ecm_free_inst(struct usb_function_instance = *f) struct f_ecm_opts *opts; =20 opts =3D container_of(f, struct f_ecm_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -906,9 +910,12 @@ static void ecm_free(struct usb_function *f) static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ecm *ecm =3D func_to_ecm(f); + struct f_ecm_opts *ecm_opts; =20 DBG(c->cdev, "ecm unbind\n"); =20 + ecm_opts =3D container_of(f->fi, struct f_ecm_opts, func_inst); + usb_free_all_descriptors(f); =20 if (atomic_read(&ecm->notify_count)) { @@ -918,6 +925,10 @@ static void ecm_unbind(struct usb_configuration *c, st= ruct usb_function *f) =20 kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); + + ecm_opts->bind_count--; + if (ecm_opts->bind_count =3D=3D 0 && !ecm_opts->bound) + gether_detach_gadget(ecm_opts->net); } =20 static struct usb_function *ecm_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/funct= ion/u_ecm.h index 77cfb89932be..7f666b9dea02 100644 --- a/drivers/usb/gadget/function/u_ecm.h +++ b/drivers/usb/gadget/function/u_ecm.h @@ -15,17 +15,26 @@ =20 #include =20 +/** + * struct f_ecm_opts - ECM function options + * @func_inst: USB function instance. + * @net: The net_device associated with the ECM function. + * @bound: True if the net_device is shared and pre-registered during the + * legacy composite driver's bind phase (e.g., multi.c). If false, + * the ECM function will register the net_device during its own + * bind phase. + * @bind_count: Tracks the number of configurations the ECM function is + * bound to, preventing double-registration of the @net devic= e. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_ecm_opts { struct usb_function_instance func_inst; struct net_device *net; bool bound; + int bind_count; =20 - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ struct mutex lock; int refcnt; }; --=20 2.53.0.959.g497ff81fa9-goog From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 00D68378809 for ; Fri, 20 Mar 2026 08:55:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996929; cv=none; b=k7P5v3wvJCYImGbGLY79rC0x0KBoGtCjMt1mIV18ah1exvwq5AF5R3mBgLkeMEPhMtHqZdq0f5JK09tbbNXswyrodFxKnkeCip/vsoAhx+21QmsYa/qu1tjjJgTuIBlWj1AxUZCa3IjIIgnKtxOd7wZnH2OSxO0krI8gIMl0GUQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996929; c=relaxed/simple; bh=8Njy/qbquNmaOZrR9Dys5UbmmfgjiArh2foGQuEn5lg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Q2hNS+by4jFkcoDxPWpOMiqOt7PaVVf4R9WpB81YgO6oCioquQcRanvZtMdb2e4HJd8i4uSAodtajRPwWXkOVsRo4x9TXozA7P5sSWPQM1DXpQrjXPDEYbAWbARAdpVcZFQOTPCTrM8sGTi5n2ltUEvit62RbvSlDtcxUZAerMs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=MKBmJvk5; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="MKBmJvk5" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-829b8bb5211so1881073b3a.2 for ; Fri, 20 Mar 2026 01:55:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996927; x=1774601727; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=IjDg7JCk+pqnl8F+5J0HenZUvt6BOdkz3K2TWkqBMpM=; b=MKBmJvk5GNzCypyMEmueOPKxhKiTnjtJXIn9z5QRIPMBl05LgvYuYXePwxT9l2H9H0 RTa8/92RjsEmTFGZaGQWW2agEBWbOrLqanhA8dssCw7qF8aCece0+SgX+0diTTOqtD2O nwvp2Pc6htScUAZGv/h/Dg0dc3DQgirohD51zSK4/xPr/cyEbnBBd7XO/xlVD/hd/33S 1EaxsNAe4oBhH7jTmNdrVc06cX9jURL8wHwKF2HCPuFYDvFJmCn29FIFH+PIVuGO+YCB ZH3vidQsbY6bjhVEyZcNvJ2N4/JQ8iIOIK4dHEpLr141NmFvqQZ3jkLvtybWf0ErKske WeHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996927; x=1774601727; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=IjDg7JCk+pqnl8F+5J0HenZUvt6BOdkz3K2TWkqBMpM=; b=ll5Dgz/U0RCmse3UF97CJabYlNFIoKPZIJsgMGXuJB/aOKv4XF2mCvDb04TLlcaUtj RHEDwLxeKh0jy1v4r5GpFyERtDV9tOraD3t1J0WfaVzx8MToZFzM/kGVHGm3tMqsOMiu RF6QXpCRJZl5psjW3E93MKxd12T3RcqvQE1ctunNnWLXaSKbCZVb2+2+1suLc6+wP4NB igGL+swc9LF7KV/ihBkwIkNVbCpcyjU9Qebs3qLLUTzDo8uc1cZ1wSycBuesCFjjY7of JaX0IQFNokiX70NHp3IdMUDDYZonYKLIGHH0QzI2ceQFunpVKLWGTZJI9W2bu8NYfogv u9xg== X-Forwarded-Encrypted: i=1; AJvYcCXh3s9VQuOyblSXzv71WoiqesSz2h2ReOi2rXj54yxPQ/1FJMcx0jIMq6LaBYeTqj+B3xTLhB80T8YT6vM=@vger.kernel.org X-Gm-Message-State: AOJu0YwmFCj6PJocxlhGTSNZclZVlI1OJDMhWPgs4u5EPnnPTiuxQ3XK iuyjpXuUCaPqORU+/ZnOcPI9rcTXKqZXbJ2o2Y8daTgqZdvEDPIU9PLuuuMcNpWa0uDQtY/Z4fV TGLpn8Q== X-Received: from pfbhj14.prod.google.com ([2002:a05:6a00:870e:b0:829:93d2:8904]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:10c9:b0:81b:1a87:9eb9 with SMTP id d2e1a72fcca58-82a8c28c9demr1967028b3a.25.1773996927088; Fri, 20 Mar 2026 01:55:27 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:48 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=6882; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=8Njy/qbquNmaOZrR9Dys5UbmmfgjiArh2foGQuEn5lg=; b=E8QjYOUgJgOM5Csmdy3sfsUw7fR/ax73QypTpx0yWOL5oaRfrzPbG+B6eo8WWGLrRSydEQTzD td56bvoO1zoAmv559X5ky+kPrJtsCsyo/FVxVwR+52mmxLE6gjgugWX X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-5-4886b578161b@google.com> Subject: [PATCH 5/7] usb: gadget: f_eem: Fix net_device lifecycle with device_move From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@vger.kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks: console:/ # ls -l /sys/class/net/usb0 lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0 ls: .../gadget.0/net/usb0: No such file or directory Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering. To maintain compatibility with legacy composite drivers (e.g., multi.c), the bound flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase. Fixes: b29002a15794 ("usb: gadget: f_eem: convert to new function interface= with backward compatibility") Cc: stable@vger.kernel.org Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/f_eem.c | 59 +++++++++++++++++++--------------= ---- drivers/usb/gadget/function/u_eem.h | 21 +++++++++---- 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/funct= ion/f_eem.c index 0142a0e487ee..ac37d7c1d168 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -7,6 +7,7 @@ * Copyright (C) 2009 EF Johnson Technologies */ =20 +#include #include #include #include @@ -251,24 +252,22 @@ static int eem_bind(struct usb_configuration *c, stru= ct usb_function *f) struct usb_ep *ep; =20 struct f_eem_opts *eem_opts; + struct net_device *net __free(detach_gadget) =3D NULL; =20 eem_opts =3D container_of(f->fi, struct f_eem_opts, func_inst); - /* - * in drivers/usb/gadget/configfs.c:configfs_composite_bind() - * configurations are bound in sequence with list_for_each_entry, - * in each configuration its functions are bound in sequence - * with list_for_each_entry, so we assume no race condition - * with regard to eem_opts->bound access - */ - if (!eem_opts->bound) { - mutex_lock(&eem_opts->lock); - gether_set_gadget(eem_opts->net, cdev->gadget); - status =3D gether_register_netdev(eem_opts->net); - mutex_unlock(&eem_opts->lock); - if (status) - return status; - eem_opts->bound =3D true; - } + + scoped_guard(mutex, &eem_opts->lock) + if (eem_opts->bind_count =3D=3D 0 && !eem_opts->bound) { + if (!device_is_registered(&eem_opts->net->dev)) { + gether_set_gadget(eem_opts->net, cdev->gadget); + status =3D gether_register_netdev(eem_opts->net); + } else + status =3D gether_attach_gadget(eem_opts->net, cdev->gadget); + + if (status) + return status; + net =3D eem_opts->net; + } =20 us =3D usb_gstrings_attach(cdev, eem_strings, ARRAY_SIZE(eem_string_defs)); @@ -279,21 +278,19 @@ static int eem_bind(struct usb_configuration *c, stru= ct usb_function *f) /* allocate instance-specific interface IDs */ status =3D usb_interface_id(c, f); if (status < 0) - goto fail; + return status; eem->ctrl_id =3D status; eem_intf.bInterfaceNumber =3D status; =20 - status =3D -ENODEV; - /* allocate instance-specific endpoints */ ep =3D usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc); if (!ep) - goto fail; + return -ENODEV; eem->port.in_ep =3D ep; =20 ep =3D usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc); if (!ep) - goto fail; + return -ENODEV; eem->port.out_ep =3D ep; =20 /* support all relevant hardware speeds... we expect that when @@ -309,16 +306,14 @@ static int eem_bind(struct usb_configuration *c, stru= ct usb_function *f) status =3D usb_assign_descriptors(f, eem_fs_function, eem_hs_function, eem_ss_function, eem_ss_function); if (status) - goto fail; + return status; + + eem_opts->bind_count++; + retain_and_null_ptr(net); =20 DBG(cdev, "CDC Ethernet (EEM): IN/%s OUT/%s\n", eem->port.in_ep->name, eem->port.out_ep->name); return 0; - -fail: - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } =20 static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req) @@ -597,7 +592,7 @@ static void eem_free_inst(struct usb_function_instance = *f) struct f_eem_opts *opts; =20 opts =3D container_of(f, struct f_eem_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -640,9 +635,17 @@ static void eem_free(struct usb_function *f) =20 static void eem_unbind(struct usb_configuration *c, struct usb_function *f) { + struct f_eem_opts *opts; + DBG(c->cdev, "eem unbind\n"); =20 + opts =3D container_of(f->fi, struct f_eem_opts, func_inst); + usb_free_all_descriptors(f); + + opts->bind_count--; + if (opts->bind_count =3D=3D 0 && !opts->bound) + gether_detach_gadget(opts->net); } =20 static struct usb_function *eem_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/funct= ion/u_eem.h index 3bd85dfcd71c..78ef55815219 100644 --- a/drivers/usb/gadget/function/u_eem.h +++ b/drivers/usb/gadget/function/u_eem.h @@ -15,17 +15,26 @@ =20 #include =20 +/** + * struct f_eem_opts - EEM function options + * @func_inst: USB function instance. + * @net: The net_device associated with the EEM function. + * @bound: True if the net_device is shared and pre-registered during the + * legacy composite driver's bind phase (e.g., multi.c). If false, + * the EEM function will register the net_device during its own + * bind phase. + * @bind_count: Tracks the number of configurations the EEM function is + * bound to, preventing double-registration of the @net devic= e. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_eem_opts { struct usb_function_instance func_inst; struct net_device *net; bool bound; + int bind_count; =20 - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ struct mutex lock; int refcnt; }; --=20 2.53.0.959.g497ff81fa9-goog From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E1393378D8F for ; Fri, 20 Mar 2026 08:55:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996933; cv=none; b=ttGOHB3I0hBBZjfJrQfP0Xmf7mLwJfcEqegsJ3JcPKto4XXrqK0vavYFfhQKmn9faw0aAio+i0uLlnsJUc8loyo4Lgx2KWJXjoiF4Gv2Y6Bs0wzJBCadfftNHQ5O0NhBLmq95lnIPP/aT1jClyqjgpMfnVcEoZ8buXmiRBKZ8rQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996933; c=relaxed/simple; bh=WVxp0ZIk0xYVRKf3pptNJWqovoLfJ9UKaReWVwYXoRI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=iFIGULv7D+VZeax051QABjHdwZaxeYw9C/UOZFsuPXylBu4YfM1koHSOEt3/kFPL8GUN9IViI3gV1HZeRRSEdjM7VPhAlE9KVAcoyh5l/F8XSm5PUiRh9m1/stXK3yGuZ1Vfjcly1W/TJPKxCWD11jTrAjHY+xIKMF+X5dVUuVA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=bEVhC4aw; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="bEVhC4aw" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-358df8fbd1cso2658647a91.0 for ; Fri, 20 Mar 2026 01:55:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996929; x=1774601729; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=+3atbIaOInnERa/VoAz+UbgXjD5q1aDENcAUOzWrVcA=; b=bEVhC4awlShF1WmqjoI6zSEJSx2dXkmLUCt+YJmASCgduC4kLe2sBcqW9zcqiiwkfZ MCSzwC9ngh+/LPsMBlfnxX+3g/F/ZHooL43I06cR4gnt3a0EHHFRtrq3rtHVNF6+7l76 LcWsFhGQNYBNpw7ij3oX7eczi13QaD1edVdU1wKIRvMq2bbm5UrwS278vvBbHSNjJVWE tYHfHBzQeZ77vAUl7YuZbYFAFUGK43KcDvDtptHTycHs4TN1IFsYNwW7XPHDTeO/nlZ2 /vHfM7/hXiphn8cgMr5Rgok0Xfcui5ekuBzKvO/IxTJ/1v8nVQj0buXZrbu167FY9htp zCiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996929; x=1774601729; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=+3atbIaOInnERa/VoAz+UbgXjD5q1aDENcAUOzWrVcA=; b=HCLq/QZi6kNCNTpilkQQE1sqXP5FeR9NPS7LxApeKP4WJqEjFtqBViVTSPD/SEBZR4 RbqCl7Ubk4JL1FZD3MGiL5R0ifCkFCO7MiT3pZ1qZCkCUNUO2cf0tWfaal/qlHnbsx6v iQ3h1PCbOlcrL7lm0Wnxx96kggDlA1jK38OMNwnwfCbtIYENJL7ebrpWsWcGGAjhI/gX w6x3Jrr8ikseBZUaYUJ5tyUeba9qGk918p6SrC+mpkJTaBP0uA+YG2ZHbKoqta7+u4v0 +htMwVN9lAwMxcbi9lgfefqT9UCWPHd8A7NHIOc82GVT8y9fJiKw6izZAhWslThTvXj5 dSBQ== X-Forwarded-Encrypted: i=1; AJvYcCUFMlRZuSjxF32T0mSbT5ZvJmz0IGHgJ575OTIlmx4yHQUSx8caISHfH75cAmyTag43+gyqrZ2nHlS+KEU=@vger.kernel.org X-Gm-Message-State: AOJu0Yz5+RXaNLSgkdxjAEEDbp18svX51bnTe+Q4gRjJh4X7AjWg185l 0x8c7/VUybRfiERjDHiiTCUL6wNlash44iOzzWw8dS1FE066lWHMPt3z4q3O+v9UHaiqR5tZju+ FMQ2RrQ== X-Received: from pjzg1.prod.google.com ([2002:a17:90a:e581:b0:359:fee7:eac2]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:1dcb:b0:34c:c514:ee1f with SMTP id 98e67ed59e1d1-35bd2bf4d56mr1966801a91.11.1773996929139; Fri, 20 Mar 2026 01:55:29 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:49 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=6962; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=WVxp0ZIk0xYVRKf3pptNJWqovoLfJ9UKaReWVwYXoRI=; b=Gm9M57ASM4csFeNKTWED3B6hzlFROTR2MCxjFTnBBaRH7Cim2LsP4p6D8c4rZ8WLy7LIwR+EE QivIVHCuroPC8xdZHIGQRZnxB0eHFuqYdqbYpX0HkExsR5UpbnzzPNI X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-6-4886b578161b@google.com> Subject: [PATCH 6/7] usb: gadget: f_subset: Fix net_device lifecycle with device_move From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@vger.kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks: console:/ # ls -l /sys/class/net/usb0 lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0 ls: .../gadget.0/net/usb0: No such file or directory Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering. To maintain compatibility with legacy composite drivers (e.g., multi.c), the bound flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase. Fixes: 8cedba7c73af ("usb: gadget: f_subset: convert to new function interf= ace with backward compatibility") Cc: stable@vger.kernel.org Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/f_subset.c | 57 +++++++++++++++++-------------= ---- drivers/usb/gadget/function/u_gether.h | 22 ++++++++----- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/fu= nction/f_subset.c index 74dc6da5c767..6e3265b8a3a0 100644 --- a/drivers/usb/gadget/function/f_subset.c +++ b/drivers/usb/gadget/function/f_subset.c @@ -299,25 +299,22 @@ geth_bind(struct usb_configuration *c, struct usb_fun= ction *f) struct usb_ep *ep; =20 struct f_gether_opts *gether_opts; + struct net_device *net __free(detach_gadget) =3D NULL; =20 gether_opts =3D container_of(f->fi, struct f_gether_opts, func_inst); =20 - /* - * in drivers/usb/gadget/configfs.c:configfs_composite_bind() - * configurations are bound in sequence with list_for_each_entry, - * in each configuration its functions are bound in sequence - * with list_for_each_entry, so we assume no race condition - * with regard to gether_opts->bound access - */ - if (!gether_opts->bound) { - mutex_lock(&gether_opts->lock); - gether_set_gadget(gether_opts->net, cdev->gadget); - status =3D gether_register_netdev(gether_opts->net); - mutex_unlock(&gether_opts->lock); - if (status) - return status; - gether_opts->bound =3D true; - } + scoped_guard(mutex, &gether_opts->lock) + if (gether_opts->bind_count =3D=3D 0 && !gether_opts->bound) { + if (!device_is_registered(&gether_opts->net->dev)) { + gether_set_gadget(gether_opts->net, cdev->gadget); + status =3D gether_register_netdev(gether_opts->net); + } else + status =3D gether_attach_gadget(gether_opts->net, cdev->gadget); + + if (status) + return status; + net =3D gether_opts->net; + } =20 us =3D usb_gstrings_attach(cdev, geth_strings, ARRAY_SIZE(geth_string_defs)); @@ -330,20 +327,18 @@ geth_bind(struct usb_configuration *c, struct usb_fun= ction *f) /* allocate instance-specific interface IDs */ status =3D usb_interface_id(c, f); if (status < 0) - goto fail; + return status; subset_data_intf.bInterfaceNumber =3D status; =20 - status =3D -ENODEV; - /* allocate instance-specific endpoints */ ep =3D usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc); if (!ep) - goto fail; + return -ENODEV; geth->port.in_ep =3D ep; =20 ep =3D usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc); if (!ep) - goto fail; + return -ENODEV; geth->port.out_ep =3D ep; =20 /* support all relevant hardware speeds... we expect that when @@ -361,21 +356,19 @@ geth_bind(struct usb_configuration *c, struct usb_fun= ction *f) status =3D usb_assign_descriptors(f, fs_eth_function, hs_eth_function, ss_eth_function, ss_eth_function); if (status) - goto fail; + return status; =20 /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). */ =20 + gether_opts->bind_count++; + retain_and_null_ptr(net); + DBG(cdev, "CDC Subset: IN/%s OUT/%s\n", geth->port.in_ep->name, geth->port.out_ep->name); return 0; - -fail: - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } =20 static inline struct f_gether_opts *to_f_gether_opts(struct config_item *i= tem) @@ -418,7 +411,7 @@ static void geth_free_inst(struct usb_function_instance= *f) struct f_gether_opts *opts; =20 opts =3D container_of(f, struct f_gether_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -462,8 +455,16 @@ static void geth_free(struct usb_function *f) =20 static void geth_unbind(struct usb_configuration *c, struct usb_function *= f) { + struct f_gether_opts *opts; + + opts =3D container_of(f->fi, struct f_gether_opts, func_inst); + geth_string_defs[0].id =3D 0; usb_free_all_descriptors(f); + + opts->bind_count--; + if (opts->bind_count =3D=3D 0 && !opts->bound) + gether_detach_gadget(opts->net); } =20 static struct usb_function *geth_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/fu= nction/u_gether.h index 2f7a373ed449..e7b6b51f69c1 100644 --- a/drivers/usb/gadget/function/u_gether.h +++ b/drivers/usb/gadget/function/u_gether.h @@ -15,17 +15,25 @@ =20 #include =20 +/** + * struct f_gether_opts - subset function options + * @func_inst: USB function instance. + * @net: The net_device associated with the subset function. + * @bound: True if the net_device is shared and pre-registered during the + * legacy composite driver's bind phase (e.g., multi.c). If false, + * the subset function will register the net_device during its own + * bind phase. + * @bind_count: Tracks the number of configurations the subset function is + * bound to, preventing double-registration of the @net devic= e. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_gether_opts { struct usb_function_instance func_inst; struct net_device *net; bool bound; - - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ + int bind_count; struct mutex lock; int refcnt; }; --=20 2.53.0.959.g497ff81fa9-goog From nobody Sat Apr 4 07:48:55 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BC05C346AF0 for ; Fri, 20 Mar 2026 08:55:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996934; cv=none; b=egtUTC49/RWUi95SaQRr3FORdSxtj5pxQKlVnVVnLpSE31xk0Dt+V020KE87Enqt9JJw9AOTIWYyfp2vgbn3NOY+FB9h0Z6kKahuaVgbqVy3F6LRv4I6MlgiyYPHwtcrNr+YC8BZmH8s/dJQTrmiz6TkxQZbztCyRJaYkXNrxkU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773996934; c=relaxed/simple; bh=cPeN1vUKjquyCNuYv+KhJlm53tGodtnOjIR6zLwHcWM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=q8a7nnGEerA4TRtrL1xiCTpyYmK8+TG/L4ITjMIpZC9Q3Z/9ILozVAE9sA4J7eLq1FyMFbE8X2SipHfBXEti09cTBrEqTWNsmr8JIfuH7Ux9iUHdb9yxPl8bIU5TRk4zddGy1TVbRO2c+hWEI7qoCFrEfnjkYa48IRpW7KZGSWU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=oMNDPWHv; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--khtsai.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="oMNDPWHv" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2aebfa0af7dso35446385ad.1 for ; Fri, 20 Mar 2026 01:55:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1773996931; x=1774601731; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=q+r6IZRTjAuqtqKkL9NYRrlxIcvlXL5N8kxFoBUFnCk=; b=oMNDPWHv7S6s+UsYL+wxhHq2mcRvWFfNp9QznXXvn49FopPvS7QiDGAflRx735afPt 89bTM/55pyBlQQntLfoZAvY7pQ6j/yZ5RjPdIPGK1CqReBIrM6yrOapNem4fvNfd8fH8 UxzPF9yBls9iR5YtHazkPjrV0XOu9Y/woG0Rrx1UKjBLKc6dkyx+grze8XAeJw+7/cjx PsATQDUAX6/FKUILgTrUhRb019dCx6xIKMZybnRr5/ggNifVfM9jB3bNLxbYFLjeGoUY 0ln46ii8pGzypM1Q1sdnHbv2xSEm01UdV6mUGMQXorkTd9os/prge5lw5FEyuC/L2EYE LobA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773996931; x=1774601731; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=q+r6IZRTjAuqtqKkL9NYRrlxIcvlXL5N8kxFoBUFnCk=; b=MWXwVFdAZVO24CgNxjV9XZPky6ywRaIIpisFhQ6u2dinjGnygIt3WQ79yxhjkv1/S/ +gUabCNxVHP/Rjv78RCgqX01Izm+u6IAtHku+QTuir2BmvLv/UetJZ+Gjpx6IA2TpPqj pXGiwuc3eS48B+16pm2TuZakR5fA0ozVgl1AaxmijzS9SSDYWhLXpyB0eRo7bgSOZllk qG4sIYepCl6C7fmXOW8rpfZBKzKH7UVZYLNYTKtf7uhm75N851JW6PimeXKSYi7WesA9 ZvdN9sCh8hfE2Vy65BidBQnbHhgN5SmMB+rRhDIZPdeHpmGRMaR+b1DtJSBSoAUXCeRA Q8NA== X-Forwarded-Encrypted: i=1; AJvYcCUBARknBVaU3nMS5v9zY8x5W6JDfMtGfLgKX9ao3hbEayw8dFWvtBJ5ZwLO3HrKyq76i2zopeRXSN38G84=@vger.kernel.org X-Gm-Message-State: AOJu0Yzee1oSl5em/HJw3PSEBT/WyOTPDUqKj0JlgfftVgacM4NUSIcD p4Paqn62AjwK8wIaVlqHuGNrDJG0wk01EFqij6iKrZIpzUejV1DB98HUL07ew3ZXB43zkPFM5Un WMCUTQg== X-Received: from pliy14.prod.google.com ([2002:a17:903:3d0e:b0:2ae:5344:9e72]) (user=khtsai job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:2348:b0:2ae:b9cd:d2df with SMTP id d9443c01a7336-2b0827a797amr23492035ad.34.1773996931063; Fri, 20 Mar 2026 01:55:31 -0700 (PDT) Date: Fri, 20 Mar 2026 16:54:50 +0800 In-Reply-To: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260320-usb-net-lifecycle-v1-0-4886b578161b@google.com> X-Developer-Key: i=khtsai@google.com; a=ed25519; pk=abA4Pw6dY2ZufSbSXW9mtp7xiv1AVPtgRhCFWJSEqLE= X-Developer-Signature: v=1; a=ed25519-sha256; t=1773996915; l=7379; i=khtsai@google.com; s=20250916; h=from:subject:message-id; bh=cPeN1vUKjquyCNuYv+KhJlm53tGodtnOjIR6zLwHcWM=; b=RIX8Pw9NlPIBE4VKtmrY5ajDc9rdW4WzWxkwZJbeAJQUk/Q/hGXLBiEZYwMBcLMkOUDsbThHR dypca3ELtsHBW/YW1Om4xFxztBIxL97VBNgCaMme5HNH74THPYA6vvQ X-Mailer: b4 0.14.3 Message-ID: <20260320-usb-net-lifecycle-v1-7-4886b578161b@google.com> Subject: [PATCH 7/7] usb: gadget: f_rndis: Fix net_device lifecycle with device_move From: Kuen-Han Tsai To: Greg Kroah-Hartman , Kyungmin Park , Felipe Balbi , David Lechner Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Kuen-Han Tsai , stable@vger.kernel.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The net_device is allocated during function instance creation and registered during the bind phase with the gadget device as its sysfs parent. When the function unbinds, the parent device is destroyed, but the net_device survives, resulting in dangling sysfs symlinks: console:/ # ls -l /sys/class/net/usb0 lrwxrwxrwx ... /sys/class/net/usb0 -> /sys/devices/platform/.../gadget.0/net/usb0 console:/ # ls -l /sys/devices/platform/.../gadget.0/net/usb0 ls: .../gadget.0/net/usb0: No such file or directory Use device_move() to reparent the net_device between the gadget device tree and /sys/devices/virtual across bind and unbind cycles. During the final unbind, calling device_move(NULL) moves the net_device to the virtual device tree before the gadget device is destroyed. On rebinding, device_move() reparents the device back under the new gadget, ensuring proper sysfs topology and power management ordering. To maintain compatibility with legacy composite drivers (e.g., multi.c), the borrowed_net flag is used to indicate whether the network device is shared and pre-registered during the legacy driver's bind phase. Fixes: f466c6353819 ("usb: gadget: f_rndis: convert to new function interfa= ce with backward compatibility") Cc: stable@vger.kernel.org Signed-off-by: Kuen-Han Tsai --- drivers/usb/gadget/function/f_rndis.c | 42 +++++++++++++++++++++----------= ---- drivers/usb/gadget/function/u_rndis.h | 31 +++++++++++++++++++------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/fun= ction/f_rndis.c index 521b4619d6be..7de1c5f8e326 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -666,6 +666,7 @@ rndis_bind(struct usb_configuration *c, struct usb_func= tion *f) =20 struct f_rndis_opts *rndis_opts; struct usb_os_desc_table *os_desc_table __free(kfree) =3D NULL; + struct net_device *net __free(detach_gadget) =3D NULL; struct usb_request *request __free(free_usb_request) =3D NULL; =20 if (!can_support_rndis(c)) @@ -683,21 +684,18 @@ rndis_bind(struct usb_configuration *c, struct usb_fu= nction *f) rndis_iad_descriptor.bFunctionClass =3D rndis_opts->class; rndis_iad_descriptor.bFunctionSubClass =3D rndis_opts->subclass; rndis_iad_descriptor.bFunctionProtocol =3D rndis_opts->protocol; - } =20 - /* - * in drivers/usb/gadget/configfs.c:configfs_composite_bind() - * configurations are bound in sequence with list_for_each_entry, - * in each configuration its functions are bound in sequence - * with list_for_each_entry, so we assume no race condition - * with regard to rndis_opts->bound access - */ - if (!rndis_opts->bound) { - gether_set_gadget(rndis_opts->net, cdev->gadget); - status =3D gether_register_netdev(rndis_opts->net); - if (status) - return status; - rndis_opts->bound =3D true; + if (rndis_opts->bind_count =3D=3D 0 && !rndis_opts->borrowed_net) { + if (!device_is_registered(&rndis_opts->net->dev)) { + gether_set_gadget(rndis_opts->net, cdev->gadget); + status =3D gether_register_netdev(rndis_opts->net); + } else + status =3D gether_attach_gadget(rndis_opts->net, cdev->gadget); + + if (status) + return status; + net =3D rndis_opts->net; + } } =20 us =3D usb_gstrings_attach(cdev, rndis_strings, @@ -796,6 +794,9 @@ rndis_bind(struct usb_configuration *c, struct usb_func= tion *f) } rndis->notify_req =3D no_free_ptr(request); =20 + rndis_opts->bind_count++; + retain_and_null_ptr(net); + /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). @@ -812,11 +813,11 @@ void rndis_borrow_net(struct usb_function_instance *f= , struct net_device *net) struct f_rndis_opts *opts; =20 opts =3D container_of(f, struct f_rndis_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); - opts->borrowed_net =3D opts->bound =3D true; + opts->borrowed_net =3D true; opts->net =3D net; } EXPORT_SYMBOL_GPL(rndis_borrow_net); @@ -874,7 +875,7 @@ static void rndis_free_inst(struct usb_function_instanc= e *f) =20 opts =3D container_of(f, struct f_rndis_opts, func_inst); if (!opts->borrowed_net) { - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -943,6 +944,9 @@ static void rndis_free(struct usb_function *f) static void rndis_unbind(struct usb_configuration *c, struct usb_function = *f) { struct f_rndis *rndis =3D func_to_rndis(f); + struct f_rndis_opts *rndis_opts; + + rndis_opts =3D container_of(f->fi, struct f_rndis_opts, func_inst); =20 kfree(f->os_desc_table); f->os_desc_n =3D 0; @@ -950,6 +954,10 @@ static void rndis_unbind(struct usb_configuration *c, = struct usb_function *f) =20 kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); + + rndis_opts->bind_count--; + if (rndis_opts->bind_count =3D=3D 0 && !rndis_opts->borrowed_net) + gether_detach_gadget(rndis_opts->net); } =20 static struct usb_function *rndis_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/fun= ction/u_rndis.h index a8c409b2f52f..4e64619714dc 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -15,12 +15,34 @@ =20 #include =20 +/** + * struct f_rndis_opts - RNDIS function options + * @func_inst: USB function instance. + * @vendor_id: Vendor ID. + * @manufacturer: Manufacturer string. + * @net: The net_device associated with the RNDIS function. + * @bind_count: Tracks the number of configurations the RNDIS function is + * bound to, preventing double-registration of the @net devic= e. + * @borrowed_net: True if the net_device is shared and pre-registered duri= ng + * the legacy composite driver's bind phase (e.g., multi.c). + * If false, the RNDIS function will register the net_device + * during its own bind phase. + * @rndis_interf_group: ConfigFS group for RNDIS interface. + * @rndis_os_desc: USB OS descriptor for RNDIS. + * @rndis_ext_compat_id: Extended compatibility ID. + * @class: USB class. + * @subclass: USB subclass. + * @protocol: USB protocol. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_rndis_opts { struct usb_function_instance func_inst; u32 vendor_id; const char *manufacturer; struct net_device *net; - bool bound; + int bind_count; bool borrowed_net; =20 struct config_group *rndis_interf_group; @@ -30,13 +52,6 @@ struct f_rndis_opts { u8 class; u8 subclass; u8 protocol; - - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ struct mutex lock; int refcnt; }; --=20 2.53.0.959.g497ff81fa9-goog