* [PATCH v4 0/3] Fixes and rework of rpmsg_eptdev_add()
@ 2025-11-18 15:41 Dawei Li
2025-11-18 15:41 ` [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path " Dawei Li
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Dawei Li @ 2025-11-18 15:41 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: linux-remoteproc, linux-kernel, dawei.li, set_pte_at
This is V4 of series fixing fallout introduced by anonymous inode eptdev
code and rework the exception handing paths.
And it tries to address a long suffering issue related to WARN() in
error path.
Change for v4:
- Re-layout the patches in series
1/3: Fix potential WARN In error patch of rpmsg_eptdev_add().
2/3: Rework exception handling of rpmsg_eptdev_add() and callers.
3/3: Merge branches in rpmsg_eptdev_add().
Link to v3:
https://lore.kernel.org/all/20251113153909.3789-1-dawei.li@linux.dev/
Change for v3:
- Split it into 3 patches:
1/3: Fix legacy bug.
2/3: Fix new bug introduced by anonymous eptdev code.
3/3: Rework error handling code.
Link to v2:
https://lore.kernel.org/all/20251112150108.49017-1-dawei.li@linux.dev/
Change for v2:
- Add put_device() when __rpmsg_eptdev_open() failed.
Link to v1:
https://lore.kernel.org/all/20251112142813.33708-1-dawei.li@linux.dev/
Dawei Li (3):
rpmsg: char: Fix WARN() in error path of rpmsg_eptdev_add()
rpmsg: char: Rework of rpmsg_eptdev_add() and its callers
rpmsg: char: Merge cdev branches in rpmsg_eptdev_add()
drivers/rpmsg/rpmsg_char.c | 60 ++++++++++++++++++++------------------
1 file changed, 31 insertions(+), 29 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path of rpmsg_eptdev_add() 2025-11-18 15:41 [PATCH v4 0/3] Fixes and rework of rpmsg_eptdev_add() Dawei Li @ 2025-11-18 15:41 ` Dawei Li 2025-11-19 4:07 ` Zhongqiu Han 2025-11-19 17:14 ` Mathieu Poirier 2025-11-18 15:41 ` [PATCH v4 2/3] rpmsg: char: Rework of rpmsg_eptdev_add() and its callers Dawei Li 2025-11-18 15:41 ` [PATCH v4 3/3] rpmsg: char: Merge cdev branches in rpmsg_eptdev_add() Dawei Li 2 siblings, 2 replies; 9+ messages in thread From: Dawei Li @ 2025-11-18 15:41 UTC (permalink / raw) To: andersson, mathieu.poirier Cc: linux-remoteproc, linux-kernel, dawei.li, set_pte_at put_device() is called on error path of rpmsg_eptdev_add() to cleanup resource attached to eptdev->dev, unfortunately it's bogus cause dev->release() is not set yet. When a struct device instance is destroyed, driver core framework checks the possible release() callback from candidates below: - struct device::release() - dev->type->release() - dev->class->dev_release() Rpmsg eptdev owns none of them so WARN() will complain the absence of release(). Fix it by: - Pre-assign dev->release() before potential error path. - Check before ida_free() in dev->release(). By fixing error path of rpmsg_eptdev_add() and fixing potential memory leak in rpmsg_anonymous_eptdev_create(), this work paves the way of rework of rpmsg_eptdev_add() and its callers. Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") Signed-off-by: Dawei Li <dawei.li@linux.dev> --- drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 34b35ea74aab..373b627581e8 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -408,8 +408,13 @@ static void rpmsg_eptdev_release_device(struct device *dev) { struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); - ida_free(&rpmsg_ept_ida, dev->id); - if (eptdev->dev.devt) + /* + * release() can be invoked from error path of rpmsg_eptdev_add(), + * WARN() will be fired if ida_free() is feed with invalid ID. + */ + if (likely(ida_exists(&rpmsg_ept_ida, dev->id))) + ida_free(&rpmsg_ept_ida, dev->id); + if (eptdev->dev.devt && likely(ida_exists(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)))) ida_free(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)); kfree(eptdev); } @@ -458,6 +463,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, struct device *dev = &eptdev->dev; int ret; + dev->release = rpmsg_eptdev_release_device; + eptdev->chinfo = chinfo; if (cdev) { @@ -471,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, /* Anonymous inode device still need device name for dev_err() and friends */ ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); if (ret < 0) - goto free_minor_ida; + goto free_eptdev; dev->id = ret; dev_set_name(dev, "rpmsg%d", ret); @@ -480,22 +487,13 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, if (cdev) { ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); if (ret) - goto free_ept_ida; + goto free_eptdev; } - /* We can now rely on the release function for cleanup */ - dev->release = rpmsg_eptdev_release_device; - return ret; -free_ept_ida: - ida_free(&rpmsg_ept_ida, dev->id); -free_minor_ida: - if (cdev) - ida_free(&rpmsg_minor_ida, MINOR(dev->devt)); free_eptdev: put_device(dev); - kfree(eptdev); return ret; } @@ -561,6 +559,8 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par if (!ret) *pfd = fd; + else + put_device(&eptdev->dev); return ret; } -- 2.25.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path of rpmsg_eptdev_add() 2025-11-18 15:41 ` [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path " Dawei Li @ 2025-11-19 4:07 ` Zhongqiu Han 2025-11-19 10:56 ` Dawei Li 2025-11-19 17:14 ` Mathieu Poirier 1 sibling, 1 reply; 9+ messages in thread From: Zhongqiu Han @ 2025-11-19 4:07 UTC (permalink / raw) To: Dawei Li, andersson, mathieu.poirier Cc: linux-remoteproc, linux-kernel, set_pte_at, zhongqiu.han On 11/18/2025 11:41 PM, Dawei Li wrote: > put_device() is called on error path of rpmsg_eptdev_add() to cleanup > resource attached to eptdev->dev, unfortunately it's bogus cause > dev->release() is not set yet. > > When a struct device instance is destroyed, driver core framework checks > the possible release() callback from candidates below: > - struct device::release() > - dev->type->release() > - dev->class->dev_release() > > Rpmsg eptdev owns none of them so WARN() will complain the absence of > release(). > > Fix it by: > - Pre-assign dev->release() before potential error path. > - Check before ida_free() in dev->release(). > > By fixing error path of rpmsg_eptdev_add() and fixing potential memory > leak in rpmsg_anonymous_eptdev_create(), this work paves the way of rework > of rpmsg_eptdev_add() and its callers. > > Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") > Signed-off-by: Dawei Li <dawei.li@linux.dev> > --- > drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++------------- > 1 file changed, 13 insertions(+), 13 deletions(-) > > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c > index 34b35ea74aab..373b627581e8 100644 > --- a/drivers/rpmsg/rpmsg_char.c > +++ b/drivers/rpmsg/rpmsg_char.c > @@ -408,8 +408,13 @@ static void rpmsg_eptdev_release_device(struct device *dev) > { > struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); > > - ida_free(&rpmsg_ept_ida, dev->id); > - if (eptdev->dev.devt) > + /* > + * release() can be invoked from error path of rpmsg_eptdev_add(), > + * WARN() will be fired if ida_free() is feed with invalid ID. > + */ > + if (likely(ida_exists(&rpmsg_ept_ida, dev->id))) > + ida_free(&rpmsg_ept_ida, dev->id); > + if (eptdev->dev.devt && likely(ida_exists(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)))) > ida_free(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)); > kfree(eptdev); > } > @@ -458,6 +463,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > struct device *dev = &eptdev->dev; > int ret; > > + dev->release = rpmsg_eptdev_release_device; > + > eptdev->chinfo = chinfo; > > if (cdev) { > @@ -471,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > /* Anonymous inode device still need device name for dev_err() and friends */ > ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); > if (ret < 0) > - goto free_minor_ida; > + goto free_eptdev; > dev->id = ret; > dev_set_name(dev, "rpmsg%d", ret); > > @@ -480,22 +487,13 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > if (cdev) { > ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); > if (ret) > - goto free_ept_ida; > + goto free_eptdev; > } > > - /* We can now rely on the release function for cleanup */ > - dev->release = rpmsg_eptdev_release_device; > - > return ret; > > -free_ept_ida: > - ida_free(&rpmsg_ept_ida, dev->id); > -free_minor_ida: > - if (cdev) > - ida_free(&rpmsg_minor_ida, MINOR(dev->devt)); > free_eptdev: > put_device(dev); > - kfree(eptdev); Hi Dawei, Thanks for your new version~ Patch 1/3 will introduce a use-after-free of eptdev in func rpmsg_anonymous_eptdev_create(), https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git/tree/drivers/rpmsg/rpmsg_char.c?h=for-next#n548 even though this issue will be resolved in 2/3. However, 1/3, as an independent commit, should not introduce a new bug. > > return ret; > } > @@ -561,6 +559,8 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par > > if (!ret) > *pfd = fd; > + else > + put_device(&eptdev->dev); > > return ret; > } -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path of rpmsg_eptdev_add() 2025-11-19 4:07 ` Zhongqiu Han @ 2025-11-19 10:56 ` Dawei Li 2025-11-19 12:26 ` Zhongqiu Han 0 siblings, 1 reply; 9+ messages in thread From: Dawei Li @ 2025-11-19 10:56 UTC (permalink / raw) To: Zhongqiu Han Cc: andersson, mathieu.poirier, linux-remoteproc, linux-kernel, set_pte_at, dawei.li On Wed, Nov 19, 2025 at 12:07:02PM +0800, Zhongqiu Han wrote: > On 11/18/2025 11:41 PM, Dawei Li wrote: > > put_device() is called on error path of rpmsg_eptdev_add() to cleanup > > resource attached to eptdev->dev, unfortunately it's bogus cause > > dev->release() is not set yet. > > > > When a struct device instance is destroyed, driver core framework checks > > the possible release() callback from candidates below: > > - struct device::release() > > - dev->type->release() > > - dev->class->dev_release() > > > > Rpmsg eptdev owns none of them so WARN() will complain the absence of > > release(). > > > > Fix it by: > > - Pre-assign dev->release() before potential error path. > > - Check before ida_free() in dev->release(). > > > > By fixing error path of rpmsg_eptdev_add() and fixing potential memory > > leak in rpmsg_anonymous_eptdev_create(), this work paves the way of rework > > of rpmsg_eptdev_add() and its callers. > > > > Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") > > Signed-off-by: Dawei Li <dawei.li@linux.dev> > > --- > > drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++------------- > > 1 file changed, 13 insertions(+), 13 deletions(-) > > > > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c > > index 34b35ea74aab..373b627581e8 100644 > > --- a/drivers/rpmsg/rpmsg_char.c > > +++ b/drivers/rpmsg/rpmsg_char.c > > @@ -408,8 +408,13 @@ static void rpmsg_eptdev_release_device(struct device *dev) > > { > > struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); > > - ida_free(&rpmsg_ept_ida, dev->id); > > - if (eptdev->dev.devt) > > + /* > > + * release() can be invoked from error path of rpmsg_eptdev_add(), > > + * WARN() will be fired if ida_free() is feed with invalid ID. > > + */ > > + if (likely(ida_exists(&rpmsg_ept_ida, dev->id))) > > + ida_free(&rpmsg_ept_ida, dev->id); > > + if (eptdev->dev.devt && likely(ida_exists(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)))) > > ida_free(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)); > > kfree(eptdev); > > } > > @@ -458,6 +463,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > > struct device *dev = &eptdev->dev; > > int ret; > > + dev->release = rpmsg_eptdev_release_device; > > + > > eptdev->chinfo = chinfo; > > if (cdev) { > > @@ -471,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > > /* Anonymous inode device still need device name for dev_err() and friends */ > > ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); > > if (ret < 0) > > - goto free_minor_ida; > > + goto free_eptdev; > > dev->id = ret; > > dev_set_name(dev, "rpmsg%d", ret); > > @@ -480,22 +487,13 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > > if (cdev) { > > ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); > > if (ret) > > - goto free_ept_ida; > > + goto free_eptdev; > > } > > - /* We can now rely on the release function for cleanup */ > > - dev->release = rpmsg_eptdev_release_device; > > - > > return ret; > > -free_ept_ida: > > - ida_free(&rpmsg_ept_ida, dev->id); > > -free_minor_ida: > > - if (cdev) > > - ida_free(&rpmsg_minor_ida, MINOR(dev->devt)); > > free_eptdev: > > put_device(dev); > > - kfree(eptdev); > > > Hi Dawei, > > Thanks for your new version~ > > Patch 1/3 will introduce a use-after-free of eptdev in func > rpmsg_anonymous_eptdev_create(), > > https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git/tree/drivers/rpmsg/rpmsg_char.c?h=for-next#n548 > > even though this issue will be resolved in 2/3. However, 1/3, as an > independent commit, should not introduce a new bug. FWIW, it's not new bug introduced by this commit, it's introduced by 2410558f5f11, which is supposed to be fixed in patch[2/3]. And new reorganize of series is trying to address the comments from Mathieu[1], If I understand it correctly. Bjorn, Mathieu, What's your inputs on this? I will respin v5 if you find it necessary. Diff between v5 from v4: patch[1/3]: Remove dev_err(&eptdev->dev) from rpmsg_anonymous_eptdev_create(); patch[2/3]: Bring back dev_err(&eptdev->dev) to rpmsg_anonymous_eptdev_create(); [1] https://lore.kernel.org/all/aRd8mDzQWXtEFnmt@p14s/ > > > > return ret; > > } > > @@ -561,6 +559,8 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par > > if (!ret) > > *pfd = fd; > > + else > > + put_device(&eptdev->dev); > > return ret; > > } > > > -- > Thx and BRs, > Zhongqiu Han Thanks, Dawei ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path of rpmsg_eptdev_add() 2025-11-19 10:56 ` Dawei Li @ 2025-11-19 12:26 ` Zhongqiu Han 0 siblings, 0 replies; 9+ messages in thread From: Zhongqiu Han @ 2025-11-19 12:26 UTC (permalink / raw) To: Dawei Li Cc: andersson, mathieu.poirier, linux-remoteproc, linux-kernel, set_pte_at, zhongqiu.han On 11/19/2025 6:56 PM, Dawei Li wrote: > On Wed, Nov 19, 2025 at 12:07:02PM +0800, Zhongqiu Han wrote: >> On 11/18/2025 11:41 PM, Dawei Li wrote: >>> put_device() is called on error path of rpmsg_eptdev_add() to cleanup >>> resource attached to eptdev->dev, unfortunately it's bogus cause >>> dev->release() is not set yet. >>> >>> When a struct device instance is destroyed, driver core framework checks >>> the possible release() callback from candidates below: >>> - struct device::release() >>> - dev->type->release() >>> - dev->class->dev_release() >>> >>> Rpmsg eptdev owns none of them so WARN() will complain the absence of >>> release(). >>> >>> Fix it by: >>> - Pre-assign dev->release() before potential error path. >>> - Check before ida_free() in dev->release(). >>> >>> By fixing error path of rpmsg_eptdev_add() and fixing potential memory >>> leak in rpmsg_anonymous_eptdev_create(), this work paves the way of rework >>> of rpmsg_eptdev_add() and its callers. >>> >>> Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") >>> Signed-off-by: Dawei Li <dawei.li@linux.dev> >>> --- >>> drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++------------- >>> 1 file changed, 13 insertions(+), 13 deletions(-) >>> >>> diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c >>> index 34b35ea74aab..373b627581e8 100644 >>> --- a/drivers/rpmsg/rpmsg_char.c >>> +++ b/drivers/rpmsg/rpmsg_char.c >>> @@ -408,8 +408,13 @@ static void rpmsg_eptdev_release_device(struct device *dev) >>> { >>> struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); >>> - ida_free(&rpmsg_ept_ida, dev->id); >>> - if (eptdev->dev.devt) >>> + /* >>> + * release() can be invoked from error path of rpmsg_eptdev_add(), >>> + * WARN() will be fired if ida_free() is feed with invalid ID. >>> + */ >>> + if (likely(ida_exists(&rpmsg_ept_ida, dev->id))) >>> + ida_free(&rpmsg_ept_ida, dev->id); >>> + if (eptdev->dev.devt && likely(ida_exists(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)))) >>> ida_free(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)); >>> kfree(eptdev); >>> } >>> @@ -458,6 +463,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, >>> struct device *dev = &eptdev->dev; >>> int ret; >>> + dev->release = rpmsg_eptdev_release_device; >>> + >>> eptdev->chinfo = chinfo; >>> if (cdev) { >>> @@ -471,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, >>> /* Anonymous inode device still need device name for dev_err() and friends */ >>> ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); >>> if (ret < 0) >>> - goto free_minor_ida; >>> + goto free_eptdev; >>> dev->id = ret; >>> dev_set_name(dev, "rpmsg%d", ret); >>> @@ -480,22 +487,13 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, >>> if (cdev) { >>> ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); >>> if (ret) >>> - goto free_ept_ida; >>> + goto free_eptdev; >>> } >>> - /* We can now rely on the release function for cleanup */ >>> - dev->release = rpmsg_eptdev_release_device; >>> - >>> return ret; >>> -free_ept_ida: >>> - ida_free(&rpmsg_ept_ida, dev->id); >>> -free_minor_ida: >>> - if (cdev) >>> - ida_free(&rpmsg_minor_ida, MINOR(dev->devt)); >>> free_eptdev: >>> put_device(dev); >>> - kfree(eptdev); >> >> >> Hi Dawei, >> >> Thanks for your new version~ >> >> Patch 1/3 will introduce a use-after-free of eptdev in func >> rpmsg_anonymous_eptdev_create(), >> >> https://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git/tree/drivers/rpmsg/rpmsg_char.c?h=for-next#n548 >> >> even though this issue will be resolved in 2/3. However, 1/3, as an >> independent commit, should not introduce a new bug. > > FWIW, it's not new bug introduced by this commit, it's introduced by > 2410558f5f11, which is supposed to be fixed in patch[2/3]. Hi Dawei, I checked commit 2410558f5f11 and see that the issue existed before this patch. Thanks for clarifying, > > And new reorganize of series is trying to address the comments from > Mathieu[1], If I understand it correctly. > > Bjorn, Mathieu, > What's your inputs on this? I will respin v5 if you find it necessary. > > Diff between v5 from v4: > patch[1/3]: Remove dev_err(&eptdev->dev) from rpmsg_anonymous_eptdev_create(); > > patch[2/3]: Bring back dev_err(&eptdev->dev) to rpmsg_anonymous_eptdev_create(); > > [1] https://lore.kernel.org/all/aRd8mDzQWXtEFnmt@p14s/ > >> >> >>> return ret; >>> } >>> @@ -561,6 +559,8 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par >>> if (!ret) >>> *pfd = fd; >>> + else >>> + put_device(&eptdev->dev); >>> return ret; >>> } >> >> >> -- >> Thx and BRs, >> Zhongqiu Han > > Thanks, > > Dawei -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path of rpmsg_eptdev_add() 2025-11-18 15:41 ` [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path " Dawei Li 2025-11-19 4:07 ` Zhongqiu Han @ 2025-11-19 17:14 ` Mathieu Poirier 1 sibling, 0 replies; 9+ messages in thread From: Mathieu Poirier @ 2025-11-19 17:14 UTC (permalink / raw) To: Dawei Li; +Cc: andersson, linux-remoteproc, linux-kernel, set_pte_at On Tue, Nov 18, 2025 at 11:41:05PM +0800, Dawei Li wrote: > put_device() is called on error path of rpmsg_eptdev_add() to cleanup > resource attached to eptdev->dev, unfortunately it's bogus cause > dev->release() is not set yet. > > When a struct device instance is destroyed, driver core framework checks > the possible release() callback from candidates below: > - struct device::release() > - dev->type->release() > - dev->class->dev_release() > > Rpmsg eptdev owns none of them so WARN() will complain the absence of > release(). > > Fix it by: > - Pre-assign dev->release() before potential error path. > - Check before ida_free() in dev->release(). > > By fixing error path of rpmsg_eptdev_add() and fixing potential memory > leak in rpmsg_anonymous_eptdev_create(), this work paves the way of rework > of rpmsg_eptdev_add() and its callers. > > Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") > Signed-off-by: Dawei Li <dawei.li@linux.dev> > --- > drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++------------- > 1 file changed, 13 insertions(+), 13 deletions(-) > > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c > index 34b35ea74aab..373b627581e8 100644 > --- a/drivers/rpmsg/rpmsg_char.c > +++ b/drivers/rpmsg/rpmsg_char.c > @@ -408,8 +408,13 @@ static void rpmsg_eptdev_release_device(struct device *dev) > { > struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev); > > - ida_free(&rpmsg_ept_ida, dev->id); > - if (eptdev->dev.devt) > + /* > + * release() can be invoked from error path of rpmsg_eptdev_add(), > + * WARN() will be fired if ida_free() is feed with invalid ID. > + */ > + if (likely(ida_exists(&rpmsg_ept_ida, dev->id))) > + ida_free(&rpmsg_ept_ida, dev->id); > + if (eptdev->dev.devt && likely(ida_exists(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)))) > ida_free(&rpmsg_minor_ida, MINOR(eptdev->dev.devt)); > kfree(eptdev); > } > @@ -458,6 +463,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > struct device *dev = &eptdev->dev; > int ret; > > + dev->release = rpmsg_eptdev_release_device; > + A device's release function if for an allocated device, not to address an error path. This should have been left where it was. > eptdev->chinfo = chinfo; > > if (cdev) { > @@ -471,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > /* Anonymous inode device still need device name for dev_err() and friends */ > ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); > if (ret < 0) > - goto free_minor_ida; > + goto free_eptdev; > dev->id = ret; > dev_set_name(dev, "rpmsg%d", ret); > > @@ -480,22 +487,13 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > if (cdev) { > ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); > if (ret) > - goto free_ept_ida; > + goto free_eptdev; > } > > - /* We can now rely on the release function for cleanup */ > - dev->release = rpmsg_eptdev_release_device; > - > return ret; > > -free_ept_ida: > - ida_free(&rpmsg_ept_ida, dev->id); > -free_minor_ida: > - if (cdev) > - ida_free(&rpmsg_minor_ida, MINOR(dev->devt)); > free_eptdev: > put_device(dev); > - kfree(eptdev); You're doing two things at the same time, i.e dealing with the kfree() _and_ put_device(). As indicated before, if this function fails the kfree() needs to happend in the error handling of rpmsg_eptdev_add() in rpmsg_anonymous_eptdev_create() and not in rpmsg_eptdev_release_device(). I am now at a point where I have spent too much time on this patchet - continuing to work on it would be unfair to other people waiting for their patches to be reviewed. As such I have backed-out this feature from the rpmsg-next tree. Thanks, Mathieu > > return ret; > } > @@ -561,6 +559,8 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par > > if (!ret) > *pfd = fd; > + else > + put_device(&eptdev->dev); > > return ret; > } > -- > 2.25.1 > ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 2/3] rpmsg: char: Rework of rpmsg_eptdev_add() and its callers 2025-11-18 15:41 [PATCH v4 0/3] Fixes and rework of rpmsg_eptdev_add() Dawei Li 2025-11-18 15:41 ` [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path " Dawei Li @ 2025-11-18 15:41 ` Dawei Li 2025-11-19 13:03 ` Zhongqiu Han 2025-11-18 15:41 ` [PATCH v4 3/3] rpmsg: char: Merge cdev branches in rpmsg_eptdev_add() Dawei Li 2 siblings, 1 reply; 9+ messages in thread From: Dawei Li @ 2025-11-18 15:41 UTC (permalink / raw) To: andersson, mathieu.poirier Cc: linux-remoteproc, linux-kernel, dawei.li, set_pte_at For every caller of rpmsg_eptdev_add(), eptdev is allocated in rpmsg_eptdev_alloc(). Resource should be freed where it's allocated, In this case, eptdev should be freed in caller of rpmsg_eptdev_add() rather than rpmsg_eptdev_add() itself. Move the error handling from rpmsg_eptdev_add() to its callers. Fixes: 2410558f5f11 ("rpmsg: char: Implement eptdev based on anonymous inode") Signed-off-by: Dawei Li <dawei.li@linux.dev> --- drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 373b627581e8..56371899212f 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -470,7 +470,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, if (cdev) { ret = ida_alloc_max(&rpmsg_minor_ida, RPMSG_DEV_MAX - 1, GFP_KERNEL); if (ret < 0) - goto free_eptdev; + return ret; dev->devt = MKDEV(MAJOR(rpmsg_major), ret); } @@ -478,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, /* Anonymous inode device still need device name for dev_err() and friends */ ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); if (ret < 0) - goto free_eptdev; + return ret; dev->id = ret; dev_set_name(dev, "rpmsg%d", ret); @@ -486,15 +486,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, if (cdev) { ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); - if (ret) - goto free_eptdev; } - return ret; - -free_eptdev: - put_device(dev); - return ret; } @@ -507,12 +500,17 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent struct rpmsg_channel_info chinfo) { struct rpmsg_eptdev *eptdev; + int ret; eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, parent); if (IS_ERR(eptdev)) return PTR_ERR(eptdev); - return rpmsg_chrdev_eptdev_add(eptdev, chinfo); + ret = rpmsg_chrdev_eptdev_add(eptdev, chinfo); + if (ret) + put_device(&eptdev->dev); + + return ret; } EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create); @@ -544,6 +542,7 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par ret = rpmsg_eptdev_add(eptdev, chinfo, false); if (ret) { dev_err(&eptdev->dev, "failed to add %s\n", eptdev->chinfo.name); + put_device(&eptdev->dev); return ret; } @@ -571,6 +570,7 @@ static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev) struct rpmsg_channel_info chinfo; struct rpmsg_eptdev *eptdev; struct device *dev = &rpdev->dev; + int ret; memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); chinfo.src = rpdev->src; @@ -589,7 +589,11 @@ static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev) */ eptdev->default_ept->priv = eptdev; - return rpmsg_chrdev_eptdev_add(eptdev, chinfo); + ret = rpmsg_chrdev_eptdev_add(eptdev, chinfo); + if (ret) + put_device(&eptdev->dev); + + return ret; } static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev) -- 2.25.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] rpmsg: char: Rework of rpmsg_eptdev_add() and its callers 2025-11-18 15:41 ` [PATCH v4 2/3] rpmsg: char: Rework of rpmsg_eptdev_add() and its callers Dawei Li @ 2025-11-19 13:03 ` Zhongqiu Han 0 siblings, 0 replies; 9+ messages in thread From: Zhongqiu Han @ 2025-11-19 13:03 UTC (permalink / raw) To: Dawei Li, andersson, mathieu.poirier Cc: linux-remoteproc, linux-kernel, set_pte_at, zhongqiu.han On 11/18/2025 11:41 PM, Dawei Li wrote: > For every caller of rpmsg_eptdev_add(), eptdev is allocated in > rpmsg_eptdev_alloc(). Resource should be freed where it's allocated, > In this case, eptdev should be freed in caller of rpmsg_eptdev_add() rather > than rpmsg_eptdev_add() itself. > > Move the error handling from rpmsg_eptdev_add() to its callers. > > Fixes: 2410558f5f11 ("rpmsg: char: Implement eptdev based on anonymous inode") Just for reference, it would be better if the commit message clearly explained what is being fixed. Just like V3 2/3 https://lore.kernel.org/all/20251113153909.3789-3-dawei.li@linux.dev/ > Signed-off-by: Dawei Li <dawei.li@linux.dev> > --- > drivers/rpmsg/rpmsg_char.c | 26 +++++++++++++++----------- > 1 file changed, 15 insertions(+), 11 deletions(-) > > diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c > index 373b627581e8..56371899212f 100644 > --- a/drivers/rpmsg/rpmsg_char.c > +++ b/drivers/rpmsg/rpmsg_char.c > @@ -470,7 +470,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > if (cdev) { > ret = ida_alloc_max(&rpmsg_minor_ida, RPMSG_DEV_MAX - 1, GFP_KERNEL); > if (ret < 0) > - goto free_eptdev; > + return ret; > > dev->devt = MKDEV(MAJOR(rpmsg_major), ret); > } > @@ -478,7 +478,7 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > /* Anonymous inode device still need device name for dev_err() and friends */ > ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); > if (ret < 0) > - goto free_eptdev; > + return ret; > dev->id = ret; > dev_set_name(dev, "rpmsg%d", ret); > > @@ -486,15 +486,8 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, > > if (cdev) { > ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); > - if (ret) > - goto free_eptdev; > } > > - return ret; > - > -free_eptdev: > - put_device(dev); > - > return ret; > } > > @@ -507,12 +500,17 @@ int rpmsg_chrdev_eptdev_create(struct rpmsg_device *rpdev, struct device *parent > struct rpmsg_channel_info chinfo) > { > struct rpmsg_eptdev *eptdev; > + int ret; > > eptdev = rpmsg_chrdev_eptdev_alloc(rpdev, parent); > if (IS_ERR(eptdev)) > return PTR_ERR(eptdev); > > - return rpmsg_chrdev_eptdev_add(eptdev, chinfo); > + ret = rpmsg_chrdev_eptdev_add(eptdev, chinfo); > + if (ret) > + put_device(&eptdev->dev); > + > + return ret; > } > EXPORT_SYMBOL(rpmsg_chrdev_eptdev_create); > > @@ -544,6 +542,7 @@ int rpmsg_anonymous_eptdev_create(struct rpmsg_device *rpdev, struct device *par > ret = rpmsg_eptdev_add(eptdev, chinfo, false); > if (ret) { > dev_err(&eptdev->dev, "failed to add %s\n", eptdev->chinfo.name); > + put_device(&eptdev->dev); > return ret; > } > > @@ -571,6 +570,7 @@ static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev) > struct rpmsg_channel_info chinfo; > struct rpmsg_eptdev *eptdev; > struct device *dev = &rpdev->dev; > + int ret; > > memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); > chinfo.src = rpdev->src; > @@ -589,7 +589,11 @@ static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev) > */ > eptdev->default_ept->priv = eptdev; > > - return rpmsg_chrdev_eptdev_add(eptdev, chinfo); > + ret = rpmsg_chrdev_eptdev_add(eptdev, chinfo); > + if (ret) > + put_device(&eptdev->dev); > + > + return ret; > } > > static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev) -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 3/3] rpmsg: char: Merge cdev branches in rpmsg_eptdev_add() 2025-11-18 15:41 [PATCH v4 0/3] Fixes and rework of rpmsg_eptdev_add() Dawei Li 2025-11-18 15:41 ` [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path " Dawei Li 2025-11-18 15:41 ` [PATCH v4 2/3] rpmsg: char: Rework of rpmsg_eptdev_add() and its callers Dawei Li @ 2025-11-18 15:41 ` Dawei Li 2 siblings, 0 replies; 9+ messages in thread From: Dawei Li @ 2025-11-18 15:41 UTC (permalink / raw) To: andersson, mathieu.poirier Cc: linux-remoteproc, linux-kernel, dawei.li, set_pte_at There are two if(cdev) branches in rpmsg_eptdev_add(), merge them. Note that cdev_device_add() still must be last one since dev->release() doesn't reclaim cdev related resource. Signed-off-by: Dawei Li <dawei.li@linux.dev> --- drivers/rpmsg/rpmsg_char.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c index 56371899212f..505411029fe0 100644 --- a/drivers/rpmsg/rpmsg_char.c +++ b/drivers/rpmsg/rpmsg_char.c @@ -467,14 +467,6 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, eptdev->chinfo = chinfo; - if (cdev) { - ret = ida_alloc_max(&rpmsg_minor_ida, RPMSG_DEV_MAX - 1, GFP_KERNEL); - if (ret < 0) - return ret; - - dev->devt = MKDEV(MAJOR(rpmsg_major), ret); - } - /* Anonymous inode device still need device name for dev_err() and friends */ ret = ida_alloc(&rpmsg_ept_ida, GFP_KERNEL); if (ret < 0) @@ -485,6 +477,12 @@ static int rpmsg_eptdev_add(struct rpmsg_eptdev *eptdev, ret = 0; if (cdev) { + ret = ida_alloc_max(&rpmsg_minor_ida, RPMSG_DEV_MAX - 1, GFP_KERNEL); + if (ret < 0) + return ret; + + dev->devt = MKDEV(MAJOR(rpmsg_major), ret); + ret = cdev_device_add(&eptdev->cdev, &eptdev->dev); } -- 2.25.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-11-19 17:14 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-11-18 15:41 [PATCH v4 0/3] Fixes and rework of rpmsg_eptdev_add() Dawei Li 2025-11-18 15:41 ` [PATCH v4 1/3] rpmsg: char: Fix WARN() in error path " Dawei Li 2025-11-19 4:07 ` Zhongqiu Han 2025-11-19 10:56 ` Dawei Li 2025-11-19 12:26 ` Zhongqiu Han 2025-11-19 17:14 ` Mathieu Poirier 2025-11-18 15:41 ` [PATCH v4 2/3] rpmsg: char: Rework of rpmsg_eptdev_add() and its callers Dawei Li 2025-11-19 13:03 ` Zhongqiu Han 2025-11-18 15:41 ` [PATCH v4 3/3] rpmsg: char: Merge cdev branches in rpmsg_eptdev_add() Dawei Li
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox