[PULL] drm-misc-fixes

2023-07-27 Thread Maxime Ripard
Hi,

Here's this week drm-misc-fixes PR

Maxime

drm-misc-fixes-2023-07-27:
A single patch to remove an unused function.
The following changes since commit ea293f823a8805735d9e00124df81a8f448ed1ae:

  drm/nouveau/kms/nv50-: init hpd_irq_lock for PIOR DP (2023-07-19 11:08:47 
+0200)

are available in the Git repository at:

  git://anongit.freedesktop.org/drm/drm-misc tags/drm-misc-fixes-2023-07-27

for you to fetch changes up to 39b1320e5dc2b707dfb5c25b0298ce9d4fc05aea:

  drm/fb-helper: Remove unused inline function drm_fb_helper_defio_init() 
(2023-07-25 20:38:37 +0200)


A single patch to remove an unused function.


YueHaibing (1):
  drm/fb-helper: Remove unused inline function drm_fb_helper_defio_init()

 include/drm/drm_fb_helper.h | 5 -
 1 file changed, 5 deletions(-)


signature.asc
Description: PGP signature


Re: [PATCH -next] drm: omapdrm: dss: Remove redundant DSSERR()

2023-07-27 Thread Ruan Jinjie



On 2023/7/27 14:57, Uwe Kleine-König wrote:
> Hello,
> 
> On Thu, Jul 27, 2023 at 11:39:23AM +, Ruan Jinjie wrote:
>> There is no need to call the DSSERR() function directly to print
>> a custom message when handling an error from platform_get_irq() function
>> as it is going to display an appropriate error message
>> in case of a failure.
>>
>> Signed-off-by: Ruan Jinjie 
>> ---
>>  drivers/gpu/drm/omapdrm/dss/dispc.c | 1 -
>>  drivers/gpu/drm/omapdrm/dss/dsi.c   | 4 +---
>>  drivers/gpu/drm/omapdrm/dss/hdmi4.c | 1 -
>>  drivers/gpu/drm/omapdrm/dss/hdmi5.c | 1 -
>>  4 files changed, 1 insertion(+), 6 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c 
>> b/drivers/gpu/drm/omapdrm/dss/dispc.c
>> index c26aab4939fa..9209103f5dc5 100644
>> --- a/drivers/gpu/drm/omapdrm/dss/dispc.c
>> +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
>> @@ -4779,7 +4779,6 @@ static int dispc_bind(struct device *dev, struct 
>> device *master, void *data)
>>  
>>  dispc->irq = platform_get_irq(dispc->pdev, 0);
>>  if (dispc->irq < 0) {
>> -DSSERR("platform_get_irq failed\n");
>>  r = -ENODEV;
>>  goto err_free;
>>  }
> 
> Orthogonal to your patch I wonder about r = -ENODEV. Wouldn't r =
> dispc->irq be the sensible option? Ditto for the other hunks.

I agree with you, r = dispc->irq will be more sensible!
> 
> Best regards
> Uwe
> 


Re: [PATCH v2 37/47] xfs: dynamically allocate the xfs-inodegc shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the xfs-inodegc shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct xfs_mount.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 39/47] zsmalloc: dynamically allocate the mm-zspool shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the mm-zspool shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct zs_pool.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 30/47] virtio_balloon: dynamically allocate the virtio-balloon shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the virtio-balloon shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct virtio_balloon.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 32/47] ext4: dynamically allocate the ext4-es shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the ext4-es shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct ext4_sb_info.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 29/47] vmw_balloon: dynamically allocate the vmw-balloon shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the vmw-balloon shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct vmballoon.
> 
> And we can simply exit vmballoon_init() when registering the shrinker
> fails. So the shrinker_registered indication is redundant, just remove it.
> 
> Signed-off-by: Qi Zheng 

Nice cleanup.

Reviewed-by: Muchun Song 




Re: [PATCH v2 36/47] xfs: dynamically allocate the xfs-buf shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the xfs-buf shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct xfs_buftarg.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 38/47] xfs: dynamically allocate the xfs-qm shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the xfs-qm shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct xfs_quotainfo.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 41/47] mm: shrinker: remove old APIs

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> Now no users are using the old APIs, just remove them.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 33/47] jbd2, ext4: dynamically allocate the jbd2-journal shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the jbd2-journal shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct journal_s.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH v2 42/47] drm/ttm: introduce pool_shrink_rwsem

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> Currently, the synchronize_shrinkers() is only used by TTM pool. It only
> requires that no shrinkers run in parallel.
> 
> After we use RCU+refcount method to implement the lockless slab shrink,
> we can not use shrinker_rwsem or synchronize_rcu() to guarantee that all
> shrinker invocations have seen an update before freeing memory.
> 
> So we introduce a new pool_shrink_rwsem to implement a private
> synchronize_shrinkers(), so as to achieve the same purpose.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




[PATCH] dt-bindings: qcom: Update RPMHPD entries for some SoCs

2023-07-27 Thread Rohit Agarwal
Update the RPMHPD references with new bindings defined in rpmhpd.h
for Qualcomm SoCs SM8[2345]50.

Signed-off-by: Rohit Agarwal 
---
 Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml| 3 ++-
 Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml   | 3 ++-
 Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml | 3 ++-
 Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml| 3 ++-
 Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml   | 3 ++-
 Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml| 3 ++-
 Documentation/devicetree/bindings/clock/qcom,videocc.yaml  | 3 ++-
 Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml | 3 ++-
 .../devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml  | 7 ---
 Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml | 3 ++-
 .../devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml  | 5 +++--
 Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml | 3 ++-
 .../devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml  | 7 ---
 Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml | 3 ++-
 .../devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml  | 7 ---
 Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml | 3 ++-
 Documentation/devicetree/bindings/mmc/sdhci-msm.yaml   | 3 ++-
 Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml  | 5 +++--
 18 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml 
b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
index d6774db..d6b81c0 100644
--- a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
@@ -83,6 +83,7 @@ examples:
   - |
 #include 
 #include 
+#include 
 clock-controller@af0 {
   compatible = "qcom,sm8250-dispcc";
   reg = <0x0af0 0x1>;
@@ -103,7 +104,7 @@ examples:
   #clock-cells = <1>;
   #reset-cells = <1>;
   #power-domain-cells = <1>;
-  power-domains = <&rpmhpd SM8250_MMCX>;
+  power-domains = <&rpmhpd RPMHPD_MMCX>;
   required-opps = <&rpmhpd_opp_low_svs>;
 };
 ...
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml 
b/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml
index 23505c8..1ea13eb 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml
@@ -52,6 +52,7 @@ examples:
   - |
 #include 
 #include 
+#include 
 
 clock-controller@abf {
   compatible = "qcom,sm8350-videocc";
@@ -59,7 +60,7 @@ examples:
   clocks = <&rpmhcc RPMH_CXO_CLK>,
<&rpmhcc RPMH_CXO_CLK_A>,
<&sleep_clk>;
-  power-domains = <&rpmhpd SM8350_MMCX>;
+  power-domains = <&rpmhpd RPMHPD_MMCX>;
   required-opps = <&rpmhpd_opp_low_svs>;
   #clock-cells = <1>;
   #reset-cells = <1>;
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml 
b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
index 87ae741..f795132 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml
@@ -65,6 +65,7 @@ examples:
 #include 
 #include 
 #include 
+#include 
 clock-controller@ade {
   compatible = "qcom,sm8450-camcc";
   reg = <0xade 0x2>;
@@ -72,7 +73,7 @@ examples:
<&rpmhcc RPMH_CXO_CLK>,
<&rpmhcc RPMH_CXO_CLK_A>,
<&sleep_clk>;
-  power-domains = <&rpmhpd SM8450_MMCX>;
+  power-domains = <&rpmhpd RPMHPD_MMCX>;
   required-opps = <&rpmhpd_opp_low_svs>;
   #clock-cells = <1>;
   #reset-cells = <1>;
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml 
b/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml
index 1dd1f69..007464a 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml
@@ -77,6 +77,7 @@ examples:
 #include 
 #include 
 #include 
+#include 
 clock-controller@af0 {
   compatible = "qcom,sm8450-dispcc";
   reg = <0x0af0 0x1>;
@@ -91,7 +92,7 @@ examples:
   #clock-cells = <1>;
   #reset-cells = <1>;
   #power-domain-cells = <1>;
-  power-domains = <&rpmhpd SM8450_MMCX>;
+  power-domains = <&rpmhpd RPMHPD_MMCX>;
   required-opps = <&rpmhpd_opp_low_svs>;
 };
 ...
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml 
b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml
index f1c6dd5..8e79767 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8450-

Re: [PATCH] drm/mgag200: Increase bandwidth for G200se A rev1

2023-07-27 Thread Roger Sewell


Jocelyn,

>> How can I check for sure whether I am using 24 or 32 bits per pixel
>> ?
> 
> The easiest solution if you already rebuilt your kernel is to print
> the variable bpp here:
> 
> https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/mgag200/mgag200_mode.c#L326
> 
> pr_info("mgag200 bpp %d\n", bpp);

Did that, and I get "mgag200 bpp 32".

> Also if you can run Wayland at 1440x900@60, that would mean the
> hardware is indeed able to handle it in 32bit.

I can indeed run Wayland at 1440x900@60.

So I think I'm right in saying that my graphics chip can handle
1440x900@60 with 32 bits per pixel.

However, while searching /var/log/messages for the bpp output above, I
also found these two lines:

/usr/libexec/gdm-x-session[2366]: (==) modeset(0): Depth 24, (==) framebuffer 
bpp 32
/usr/libexec/gdm-x-session[2366]: (==) modeset(0): RGB weight 888

in case it makes a difference.

Thanks,
Roger.


Re: [PATCH] dt-bindings: qcom: Update RPMHPD entries for some SoCs

2023-07-27 Thread Pavan Kondeti
On Thu, Jul 27, 2023 at 10:21:10AM +0530, Rohit Agarwal wrote:
> Update the RPMHPD references with new bindings defined in rpmhpd.h
> for Qualcomm SoCs SM8[2345]50.
> 
> Signed-off-by: Rohit Agarwal 
> ---
>  Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml| 3 ++-
>  Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml   | 3 ++-
>  Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml | 3 ++-
>  Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml| 3 ++-
>  Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml   | 3 ++-
>  Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml| 3 ++-
>  Documentation/devicetree/bindings/clock/qcom,videocc.yaml  | 3 ++-
>  Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml | 3 ++-
>  .../devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml  | 7 
> ---
>  Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml | 3 ++-
>  .../devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml  | 5 +++--
>  Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml | 3 ++-
>  .../devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml  | 7 
> ---
>  Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml | 3 ++-
>  .../devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml  | 7 
> ---
>  Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml | 3 ++-
>  Documentation/devicetree/bindings/mmc/sdhci-msm.yaml   | 3 ++-
>  Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml  | 5 +++--
>  18 files changed, 44 insertions(+), 26 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml 
> b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
> index d6774db..d6b81c0 100644
> --- a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
> +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
> @@ -83,6 +83,7 @@ examples:
>- |
>  #include 
>  #include 
> +#include 
>  clock-controller@af0 {
>compatible = "qcom,sm8250-dispcc";
>reg = <0x0af0 0x1>;
> @@ -103,7 +104,7 @@ examples:
>#clock-cells = <1>;
>#reset-cells = <1>;
>#power-domain-cells = <1>;
> -  power-domains = <&rpmhpd SM8250_MMCX>;
> +  power-domains = <&rpmhpd RPMHPD_MMCX>;
>required-opps = <&rpmhpd_opp_low_svs>;
>  };
>  ...

Does this file still need to include old header? The same is applicable
to some of the other files in the patch also. 

We also discussed on the other thread [1] to move the regulator level 
definitions to new header. should this change be done after that, so that 
we don't end up touching the very same files again?

[1]
https://lore.kernel.org/all/a4zztrn6jhblozdswba7psqtvjt5l765mfr3yl4llsm5gsyqef@7x6q7yabydvm/


dri-devel@lists.freedesktop.org

2023-07-27 Thread Chengfeng Ye
Sorry for the interruption, I just notice that the ndlp node
inside timer does not share with that of lpfc_cleanup_pending_mbox().

This is a false alarm and sorry again for this.

Best regards,
Chengfeng


dri-devel@lists.freedesktop.org

2023-07-27 Thread Chengfeng Ye
As &ndlp->lock is acquired by timer lpfc_els_retry_delay() under softirq
context, process context code acquiring the lock &ndlp->lock should
disable irq or bh, otherwise deadlock could happen if the timer preempt
the execution while the lock is held in process context on the same CPU.

The two lock acquisition inside lpfc_cleanup_pending_mbox() does not
disable irq or softirq.

[Deadlock Scenario]
lpfc_cmpl_els_fdisc()
-> lpfc_cleanup_pending_mbox()
-> spin_lock(&ndlp->lock);

-> lpfc_els_retry_delay()
-> lpfc_nlp_get()
-> spin_lock_irqsave(&ndlp->lock, flags); (deadlock here)

This flaw was found by an experimental static analysis tool I am
developing for irq-related deadlock.

The patch fix the potential deadlock by spin_lock_irq() to disable
irq.

Signed-off-by: Chengfeng Ye 
---
 drivers/scsi/lpfc/lpfc_sli.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 58d10f8f75a7..8555f6bb9742 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -21049,9 +21049,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
restart_loop = 1;
spin_unlock_irq(&phba->hbalock);
-   spin_lock(&ndlp->lock);
+   spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
-   spin_unlock(&ndlp->lock);
+   spin_unlock_irq(&ndlp->lock);
spin_lock_irq(&phba->hbalock);
break;
}
@@ -21067,9 +21067,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
mb->ctx_ndlp = NULL;
if (ndlp) {
-   spin_lock(&ndlp->lock);
+   spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
-   spin_unlock(&ndlp->lock);
+   spin_unlock_irq(&ndlp->lock);
lpfc_nlp_put(ndlp);
}
}
-- 
2.17.1



Re: [PATCH v2 43/47] mm: shrinker: add a secondary array for shrinker_info::{map, nr_deferred}

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> Currently, we maintain two linear arrays per node per memcg, which are
> shrinker_info::map and shrinker_info::nr_deferred. And we need to resize
> them when the shrinker_nr_max is exceeded, that is, allocate a new array,
> and then copy the old array to the new array, and finally free the old
> array by RCU.
> 
> For shrinker_info::map, we do set_bit() under the RCU lock, so we may set
> the value into the old map which is about to be freed. This may cause the
> value set to be lost. The current solution is not to copy the old map when
> resizing, but to set all the corresponding bits in the new map to 1. This
> solves the data loss problem, but bring the overhead of more pointless
> loops while doing memcg slab shrink.
> 
> For shrinker_info::nr_deferred, we will only modify it under the read lock
> of shrinker_rwsem, so it will not run concurrently with the resizing. But
> after we make memcg slab shrink lockless, there will be the same data loss
> problem as shrinker_info::map, and we can't work around it like the map.
> 
> For such resizable arrays, the most straightforward idea is to change it
> to xarray, like we did for list_lru [1]. We need to do xa_store() in the
> list_lru_add()-->set_shrinker_bit(), but this will cause memory
> allocation, and the list_lru_add() doesn't accept failure. A possible
> solution is to pre-allocate, but the location of pre-allocation is not
> well determined.
> 
> Therefore, this commit chooses to introduce a secondary array for
> shrinker_info::{map, nr_deferred}, so that we only need to copy this
> secondary array every time the size is resized. Then even if we get the
> old secondary array under the RCU lock, the found map and nr_deferred are
> also true, so no data is lost.
> 
> [1]. 
> https://lore.kernel.org/all/20220228122126.37293-13-songmuc...@bytedance.com/
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH] dt-bindings: qcom: Update RPMHPD entries for some SoCs

2023-07-27 Thread Pavan Kondeti
On Thu, Jul 27, 2023 at 12:24:10PM +0530, Rohit Agarwal wrote:
> 
> On 7/27/2023 11:06 AM, Pavan Kondeti wrote:
> > On Thu, Jul 27, 2023 at 10:21:10AM +0530, Rohit Agarwal wrote:
> > > Update the RPMHPD references with new bindings defined in rpmhpd.h
> > > for Qualcomm SoCs SM8[2345]50.
> > > 
> > > Signed-off-by: Rohit Agarwal 
> > > ---
> > >   Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml| 3 
> > > ++-
> > >   Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml   | 3 
> > > ++-
> > >   Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml | 3 
> > > ++-
> > >   Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml| 3 
> > > ++-
> > >   Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml   | 3 
> > > ++-
> > >   Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml| 3 
> > > ++-
> > >   Documentation/devicetree/bindings/clock/qcom,videocc.yaml  | 3 
> > > ++-
> > >   Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml | 3 
> > > ++-
> > >   .../devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml  | 7 
> > > ---
> > >   Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml | 3 
> > > ++-
> > >   .../devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml  | 5 
> > > +++--
> > >   Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml | 3 
> > > ++-
> > >   .../devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml  | 7 
> > > ---
> > >   Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml | 3 
> > > ++-
> > >   .../devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml  | 7 
> > > ---
> > >   Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml | 3 
> > > ++-
> > >   Documentation/devicetree/bindings/mmc/sdhci-msm.yaml   | 3 
> > > ++-
> > >   Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml  | 5 
> > > +++--
> > >   18 files changed, 44 insertions(+), 26 deletions(-)
> > > 
> > > diff --git 
> > > a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml 
> > > b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
> > > index d6774db..d6b81c0 100644
> > > --- a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
> > > +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
> > > @@ -83,6 +83,7 @@ examples:
> > > - |
> > >   #include 
> > >   #include 
> > > +#include 
> > >   clock-controller@af0 {
> > > compatible = "qcom,sm8250-dispcc";
> > > reg = <0x0af0 0x1>;
> > > @@ -103,7 +104,7 @@ examples:
> > > #clock-cells = <1>;
> > > #reset-cells = <1>;
> > > #power-domain-cells = <1>;
> > > -  power-domains = <&rpmhpd SM8250_MMCX>;
> > > +  power-domains = <&rpmhpd RPMHPD_MMCX>;
> > > required-opps = <&rpmhpd_opp_low_svs>;
> > >   };
> > >   ...
> > Does this file still need to include old header? The same is applicable
> > to some of the other files in the patch also.
> > 
> > We also discussed on the other thread [1] to move the regulator level
> > definitions to new header. should this change be done after that, so that
> > we don't end up touching the very same files again?
> > 
> > [1]
> > https://lore.kernel.org/all/a4zztrn6jhblozdswba7psqtvjt5l765mfr3yl4llsm5gsyqef@7x6q7yabydvm/
> Removing this header directly would also be fine as we are not using any
> macro defined directly in these
> bindings.
> I already checked with dt_binding_check by removing this header.
> 
Thanks for checking, then we should remove the old header in this patch
it self, right?

Thanks,
Pavan


Re: [PATCH] dt-bindings: qcom: Update RPMHPD entries for some SoCs

2023-07-27 Thread Rohit Agarwal



On 7/27/2023 11:06 AM, Pavan Kondeti wrote:

On Thu, Jul 27, 2023 at 10:21:10AM +0530, Rohit Agarwal wrote:

Update the RPMHPD references with new bindings defined in rpmhpd.h
for Qualcomm SoCs SM8[2345]50.

Signed-off-by: Rohit Agarwal 
---
  Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml| 3 ++-
  Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml   | 3 ++-
  Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml | 3 ++-
  Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml| 3 ++-
  Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml   | 3 ++-
  Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml| 3 ++-
  Documentation/devicetree/bindings/clock/qcom,videocc.yaml  | 3 ++-
  Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml | 3 ++-
  .../devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml  | 7 ---
  Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml | 3 ++-
  .../devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml  | 5 +++--
  Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml | 3 ++-
  .../devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml  | 7 ---
  Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml | 3 ++-
  .../devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml  | 7 ---
  Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml | 3 ++-
  Documentation/devicetree/bindings/mmc/sdhci-msm.yaml   | 3 ++-
  Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml  | 5 +++--
  18 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml 
b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
index d6774db..d6b81c0 100644
--- a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml
@@ -83,6 +83,7 @@ examples:
- |
  #include 
  #include 
+#include 
  clock-controller@af0 {
compatible = "qcom,sm8250-dispcc";
reg = <0x0af0 0x1>;
@@ -103,7 +104,7 @@ examples:
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
-  power-domains = <&rpmhpd SM8250_MMCX>;
+  power-domains = <&rpmhpd RPMHPD_MMCX>;
required-opps = <&rpmhpd_opp_low_svs>;
  };
  ...

Does this file still need to include old header? The same is applicable
to some of the other files in the patch also.

We also discussed on the other thread [1] to move the regulator level
definitions to new header. should this change be done after that, so that
we don't end up touching the very same files again?

[1]
https://lore.kernel.org/all/a4zztrn6jhblozdswba7psqtvjt5l765mfr3yl4llsm5gsyqef@7x6q7yabydvm/
Removing this header directly would also be fine as we are not using any 
macro defined directly in these

bindings.
I already checked with dt_binding_check by removing this header.

Thanks,
Rohit.


Re: [PATCH v2 28/47] bcache: dynamically allocate the md-bcache shrinker

2023-07-27 Thread Muchun Song




On 2023/7/24 17:43, Qi Zheng wrote:

In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the md-bcache shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct cache_set.

Signed-off-by: Qi Zheng 
---
  drivers/md/bcache/bcache.h |  2 +-
  drivers/md/bcache/btree.c  | 27 ---
  drivers/md/bcache/sysfs.c  |  3 ++-
  3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 5a79bb3c272f..c622bc50f81b 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -541,7 +541,7 @@ struct cache_set {
struct bio_set  bio_split;
  
  	/* For the btree cache */

-   struct shrinker shrink;
+   struct shrinker *shrink;
  
  	/* For the btree cache and anything allocation related */

struct mutexbucket_lock;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index fd121a61f17c..c176c7fc77d9 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -667,7 +667,7 @@ static int mca_reap(struct btree *b, unsigned int 
min_order, bool flush)
  static unsigned long bch_mca_scan(struct shrinker *shrink,
  struct shrink_control *sc)
  {
-   struct cache_set *c = container_of(shrink, struct cache_set, shrink);
+   struct cache_set *c = shrink->private_data;
struct btree *b, *t;
unsigned long i, nr = sc->nr_to_scan;
unsigned long freed = 0;
@@ -734,7 +734,7 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
  static unsigned long bch_mca_count(struct shrinker *shrink,
   struct shrink_control *sc)
  {
-   struct cache_set *c = container_of(shrink, struct cache_set, shrink);
+   struct cache_set *c = shrink->private_data;
  
  	if (c->shrinker_disabled)

return 0;
@@ -752,8 +752,8 @@ void bch_btree_cache_free(struct cache_set *c)
  
  	closure_init_stack(&cl);
  
-	if (c->shrink.list.next)

-   unregister_shrinker(&c->shrink);
+   if (c->shrink)
+   shrinker_unregister(c->shrink);
  
  	mutex_lock(&c->bucket_lock);
  
@@ -828,14 +828,19 @@ int bch_btree_cache_alloc(struct cache_set *c)

c->verify_data = NULL;
  #endif
  
-	c->shrink.count_objects = bch_mca_count;

-   c->shrink.scan_objects = bch_mca_scan;
-   c->shrink.seeks = 4;
-   c->shrink.batch = c->btree_pages * 2;
+   c->shrink = shrinker_alloc(0, "md-bcache:%pU", c->set_uuid);
+   if (!c->shrink) {
+   pr_warn("bcache: %s: could not allocate shrinker\n", __func__);
+   return -ENOMEM;


Seems you have cheanged the semantic of this. In the past,
it is better to have a shrinker, but now it becomes a mandatory.
Right? I don't know if it is acceptable. From my point of view,
just do the cleanup, don't change any behaviour.


+   }
+
+   c->shrink->count_objects = bch_mca_count;
+   c->shrink->scan_objects = bch_mca_scan;
+   c->shrink->seeks = 4;
+   c->shrink->batch = c->btree_pages * 2;
+   c->shrink->private_data = c;
  
-	if (register_shrinker(&c->shrink, "md-bcache:%pU", c->set_uuid))

-   pr_warn("bcache: %s: could not register shrinker\n",
-   __func__);
+   shrinker_register(c->shrink);
  
  	return 0;

  }
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 0e2c1880f60b..45d8af755de6 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -866,7 +866,8 @@ STORE(__bch_cache_set)
  
  		sc.gfp_mask = GFP_KERNEL;

sc.nr_to_scan = strtoul_or_return(buf);
-   c->shrink.scan_objects(&c->shrink, &sc);
+   if (c->shrink)
+   c->shrink->scan_objects(c->shrink, &sc);
}
  
  	sysfs_strtoul_clamp(congested_read_threshold_us,




[PATCH -next] drm/bridge: fix -Wunused-const-variable= warning

2023-07-27 Thread Zhu Wang
When building with W=1, the following warning occurs.

drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c:48:17: warning: 
‘anx781x_i2c_addresses’ defined but not used [-Wunused-const-variable=]
 static const u8 anx781x_i2c_addresses[] = {
 ^
drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c:40:17: warning: 
‘anx7808_i2c_addresses’ defined but not used [-Wunused-const-variable=]
 static const u8 anx7808_i2c_addresses[] = {

The definition of above two data variables is included by the
macro CONFIG_OF, so we also include the data variable
definitions in the macro CONFIG_OF. And in addition the data
variable anx78xx_match_table is included in the macro CONFIG_OF,
so we add CONFIG_OF to the place where it is used.

Fixes: 5d97408e0d70 ("drm/bridge: move ANA78xx driver to analogix subdirectory")

Signed-off-by: Zhu Wang 
---
 drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c 
b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
index 06a3e3243e19..799b33cebdd5 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
@@ -37,6 +37,7 @@
 
 #define XTAL_CLK   270 /* 27M */
 
+#if IS_ENABLED(CONFIG_OF)
 static const u8 anx7808_i2c_addresses[] = {
[I2C_IDX_TX_P0] = 0x78,
[I2C_IDX_TX_P1] = 0x7a,
@@ -52,6 +53,7 @@ static const u8 anx781x_i2c_addresses[] = {
[I2C_IDX_RX_P0] = 0x7e,
[I2C_IDX_RX_P1] = 0x80,
 };
+#endif
 
 struct anx78xx_platform_data {
struct regulator *dvdd10;
@@ -1387,7 +1389,9 @@ MODULE_DEVICE_TABLE(of, anx78xx_match_table);
 static struct i2c_driver anx78xx_driver = {
.driver = {
   .name = "anx7814",
+#if IS_ENABLED(CONFIG_OF)
   .of_match_table = of_match_ptr(anx78xx_match_table),
+#endif
  },
.probe = anx78xx_i2c_probe,
.remove = anx78xx_i2c_remove,
-- 
2.17.1



[PATCH -next] drm/radeon: fix -Wunused-but-set-variable warning

2023-07-27 Thread Zhu Wang
When building with W=1, the following warning occurs.

drivers/gpu/drm/radeon/radeon_ttm.c:200:20: warning: variable ‘rbo’ set but not 
used [-Wunused-but-set-variable]
  struct radeon_bo *rbo;

The variable 'rbo' is used only in WARN_ON_ONCE in the function
radeon_bo_move, and WARN_ON_ONCE is removed in the following
patch, so we removed 'rbo' to remove the
-Wunused-but-set-variable warning.

Fixes: f87c1f0b7b79 ("drm/ttm: prevent moving of pinned BOs")
Signed-off-by: Zhu Wang 
---
 drivers/gpu/drm/radeon/radeon_ttm.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c 
b/drivers/gpu/drm/radeon/radeon_ttm.c
index 4eb83ccc4906..de4e6d78f1e1 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -197,7 +197,6 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, 
bool evict,
 {
struct ttm_resource *old_mem = bo->resource;
struct radeon_device *rdev;
-   struct radeon_bo *rbo;
int r;
 
if (new_mem->mem_type == TTM_PL_TT) {
@@ -210,7 +209,6 @@ static int radeon_bo_move(struct ttm_buffer_object *bo, 
bool evict,
if (r)
return r;
 
-   rbo = container_of(bo, struct radeon_bo, tbo);
rdev = radeon_get_rdev(bo->bdev);
if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM &&
 bo->ttm == NULL)) {
-- 
2.17.1



[PATCH v2] gpu: drm: Use dev_err_probe instead of dev_err

2023-07-27 Thread Wang Ming
It is possible that dma_request_chan will return EPROBE_DEFER,
which means that disp->dev is not ready yet. In this case,
dev_err(disp->dev), there will be no output. This patch fixes the bug.

Signed-off-by: Wang Ming 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 3b87eebddc97..676f09fe8594 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -1094,8 +1094,8 @@ static int zynqmp_disp_layer_request_dma(struct 
zynqmp_disp *disp,
 "%s%u", dma_names[layer->id], i);
dma->chan = dma_request_chan(disp->dev, dma_channel_name);
if (IS_ERR(dma->chan)) {
-   dev_err(disp->dev, "failed to request dma channel\n");
-   ret = PTR_ERR(dma->chan);
+   ret = dev_err_probe(disp->dev, PTR_ERR(dma->chan),
+   "failed to request dma channel\n");
dma->chan = NULL;
return ret;
}
-- 
2.25.1



Re: [PATCH v2 31/47] mbcache: dynamically allocate the mbcache shrinker

2023-07-27 Thread Muchun Song



> On Jul 24, 2023, at 17:43, Qi Zheng  wrote:
> 
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the mbcache shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct mb_cache.
> 
> Signed-off-by: Qi Zheng 

Reviewed-by: Muchun Song 




Re: [PATCH 2/3] dt-bindings: display: panel: Document Hydis HV070WX2-1E0

2023-07-27 Thread Krzysztof Kozlowski
On 26/07/2023 20:50, Thierry Reding wrote:
> From: Thierry Reding 
> 
> The Hydis HV070WX2-1E0 is a 7" WXGA (800x1280) TFT LCD LVDS panel that
> is one of the variants used on Google Nexus 7.
> 
> Signed-off-by: Thierry Reding 
> ---
>  Documentation/devicetree/bindings/display/panel/panel-lvds.yaml | 2 ++
>  1 file changed, 2 insertions(+)

Acked-by: Krzysztof Kozlowski 

Best regards,
Krzysztof



dri-devel@lists.freedesktop.org

2023-07-27 Thread Chengfeng Ye
As &ndlp->lock is acquired by timer lpfc_els_retry_delay() under softirq
context, process context code acquiring the lock &phba->hbalock should
disable irq or bh, otherwise deadlock could happen if the timer preempt
the execution while the lock is held in process context on the same CPU.

The two lock acquisition inside lpfc_cleanup_pending_mbox() does not
disable irq or softirq.

[Deadlock Scenario]
lpfc_cmpl_els_fdisc()
-> lpfc_cleanup_pending_mbox()
-> spin_lock(&ndlp->lock);

-> lpfc_els_retry_delay()
-> lpfc_nlp_get()
-> spin_lock_irqsave(&ndlp->lock, flags); (deadlock here)

This flaw was found by an experimental static analysis tool I am
developing for irq-related deadlock.

The patch fix the potential deadlock by spin_lock_irq() to disable
irq.

Signed-off-by: Chengfeng Ye 
---
 drivers/scsi/lpfc/lpfc_sli.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 58d10f8f75a7..8555f6bb9742 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -21049,9 +21049,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
restart_loop = 1;
spin_unlock_irq(&phba->hbalock);
-   spin_lock(&ndlp->lock);
+   spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
-   spin_unlock(&ndlp->lock);
+   spin_unlock_irq(&ndlp->lock);
spin_lock_irq(&phba->hbalock);
break;
}
@@ -21067,9 +21067,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
mb->ctx_ndlp = NULL;
if (ndlp) {
-   spin_lock(&ndlp->lock);
+   spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
-   spin_unlock(&ndlp->lock);
+   spin_unlock_irq(&ndlp->lock);
lpfc_nlp_put(ndlp);
}
}
-- 
2.17.1



Re: [PATCH 1/3] dt-bindings: display: panel: Move HannStar HSD101PWW2 to LVDS

2023-07-27 Thread Krzysztof Kozlowski
On 26/07/2023 20:48, Thierry Reding wrote:
> From: Thierry Reding 
> 
> The HannStar HSD101PWW2 is an LVDS panel, so move it to the correct
> bindings file.
> 
> Signed-off-by: Thierry Reding 
> ---

Acked-by: Krzysztof Kozlowski 

Best regards,
Krzysztof



Re: [PATCH v2 40/47] fs: super: dynamically allocate the s_shrink

2023-07-27 Thread Muchun Song




On 2023/7/24 17:43, Qi Zheng wrote:

In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the s_shrink, so that it can be freed asynchronously
using kfree_rcu(). Then it doesn't need to wait for RCU read-side critical
section when releasing the struct super_block.

Signed-off-by: Qi Zheng 


Reviewed-by: Muchun Song 


Re: [PATCH 1/3] dt-bindings: display: panel: Move Chunghwa CLAA070WP03XG to LVDS

2023-07-27 Thread Krzysztof Kozlowski
On 26/07/2023 20:50, Thierry Reding wrote:
> From: Thierry Reding 
> 
> The Chunghwa CLAA070WP03XG is an LVDS panel, so move it to the correct
> bindings file.
> 
> Signed-off-by: Thierry Reding 
> ---

Acked-by: Krzysztof Kozlowski 

Best regards,
Krzysztof



Re: [PATCH v2] drm/mediatek: Fix potential memory leak if vmap() fail

2023-07-27 Thread suijingfeng

Hi,


Thanks a lot!


On 2023/7/27 09:47, CK Hu (胡俊光) wrote:

Hi, Jingfeng:

On Thu, 2023-07-06 at 21:40 +0800, Sui Jingfeng wrote:
>   
> External email : Please do not click links or open attachments until

> you have verified the sender or the content.
>  Also return -ENOMEM if such a failure happens, the implement should
> take
> responsibility for the error handling.

Reviewed-by: CK Hu 

> 
> Fixes: 3df64d7b0a4f ("drm/mediatek: Implement gem prime vmap/vunmap

> function")
> Reviewed-by: Matthias Brugger 
> Reviewed-by: Alexandre Mergnat 
> Signed-off-by: Sui Jingfeng 
> ---
>  drivers/gpu/drm/mediatek/mtk_drm_gem.c | 6 +-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c

> b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> index a25b28d3ee90..9f364df52478 100644
> --- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> +++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
> @@ -247,7 +247,11 @@ int mtk_drm_gem_prime_vmap(struct drm_gem_object
> *obj, struct iosys_map *map)
>  
>  mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP,

> pgprot_writecombine(PAGE_KERNEL));
> -
> +if (!mtk_gem->kvaddr) {
> +kfree(sgt);
> +kfree(mtk_gem->pages);
> +return -ENOMEM;
> +}
>  out:
>  kfree(sgt);
>  iosys_map_set_vaddr(map, mtk_gem->kvaddr);
> -- 
> 2.34.1


* MEDIATEK Confidentiality Notice 
The information contained in this e-mail message (including any
attachments) may be confidential, proprietary, privileged, or otherwise
exempt from disclosure under applicable laws. It is intended to be
conveyed only to the designated recipient(s). Any use, dissemination,
distribution, printing, retaining or copying of this e-mail (including its
attachments) by unintended recipient(s) is strictly prohibited and may
be unlawful. If you are not an intended recipient of this e-mail, or believe
that you have received this e-mail in error, please notify the sender
immediately (by replying to this e-mail), delete any and all copies of
this e-mail (including any attachments) from your system, and do not
disclose the content of this e-mail to any other person. Thank you!




Re: [PATCH] drm/ttm: check null pointer before accessing when swapping

2023-07-27 Thread Christian König

Am 24.07.23 um 15:36 schrieb Alex Deucher:

On Sun, Jul 23, 2023 at 10:43 PM Guchun Chen  wrote:

Add a check to avoid null pointer dereference as below:

[   90.002283] general protection fault, probably for non-canonical
address 0xdc00:  [#1] PREEMPT SMP KASAN NOPTI
[   90.002292] KASAN: null-ptr-deref in range
[0x-0x0007]
[   90.002346]  ? exc_general_protection+0x159/0x240
[   90.002352]  ? asm_exc_general_protection+0x26/0x30
[   90.002357]  ? ttm_bo_evict_swapout_allowable+0x322/0x5e0 [ttm]
[   90.002365]  ? ttm_bo_evict_swapout_allowable+0x42e/0x5e0 [ttm]
[   90.002373]  ttm_bo_swapout+0x134/0x7f0 [ttm]
[   90.002383]  ? __pfx_ttm_bo_swapout+0x10/0x10 [ttm]
[   90.002391]  ? lock_acquire+0x44d/0x4f0
[   90.002398]  ? ttm_device_swapout+0xa5/0x260 [ttm]
[   90.002412]  ? lock_acquired+0x355/0xa00
[   90.002416]  ? do_raw_spin_trylock+0xb6/0x190
[   90.002421]  ? __pfx_lock_acquired+0x10/0x10
[   90.002426]  ? ttm_global_swapout+0x25/0x210 [ttm]
[   90.002442]  ttm_device_swapout+0x198/0x260 [ttm]
[   90.002456]  ? __pfx_ttm_device_swapout+0x10/0x10 [ttm]
[   90.002472]  ttm_global_swapout+0x75/0x210 [ttm]
[   90.002486]  ttm_tt_populate+0x187/0x3f0 [ttm]
[   90.002501]  ttm_bo_handle_move_mem+0x437/0x590 [ttm]
[   90.002517]  ttm_bo_validate+0x275/0x430 [ttm]
[   90.002530]  ? __pfx_ttm_bo_validate+0x10/0x10 [ttm]
[   90.002544]  ? kasan_save_stack+0x33/0x60
[   90.002550]  ? kasan_set_track+0x25/0x30
[   90.002554]  ? __kasan_kmalloc+0x8f/0xa0
[   90.002558]  ? amdgpu_gtt_mgr_new+0x81/0x420 [amdgpu]
[   90.003023]  ? ttm_resource_alloc+0xf6/0x220 [ttm]
[   90.003038]  amdgpu_bo_pin_restricted+0x2dd/0x8b0 [amdgpu]
[   90.003210]  ? __x64_sys_ioctl+0x131/0x1a0
[   90.003210]  ? do_syscall_64+0x60/0x90

Fixes: a2848d08742c ("drm/ttm: never consider pinned BOs for eviction&swap")
Tested-by: Mikhail Gavrilov 
Signed-off-by: Guchun Chen 

Reviewed-by: Alex Deucher 


Reviewed-by: Christian König 

Has this already been pushed to drm-misc-next?

Thanks,
Christian.




---
  drivers/gpu/drm/ttm/ttm_bo.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 7139a522b2f3..54e3083076b7 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -519,7 +519,8 @@ static bool ttm_bo_evict_swapout_allowable(struct 
ttm_buffer_object *bo,

 if (bo->pin_count) {
 *locked = false;
-   *busy = false;
+   if (busy)
+   *busy = false;
 return false;
 }

--
2.25.1





RE: [PATCH] drm/ttm: check null pointer before accessing when swapping

2023-07-27 Thread Chen, Guchun
[Public]

> -Original Message-
> From: Koenig, Christian 
> Sent: Thursday, July 27, 2023 3:28 PM
> To: Alex Deucher ; Chen, Guchun
> 
> Cc: Deucher, Alexander ; airl...@gmail.com;
> dan...@ffwll.ch; dri-devel@lists.freedesktop.org; Mikhail Gavrilov
> 
> Subject: Re: [PATCH] drm/ttm: check null pointer before accessing when
> swapping
>
> Am 24.07.23 um 15:36 schrieb Alex Deucher:
> > On Sun, Jul 23, 2023 at 10:43 PM Guchun Chen 
> wrote:
> >> Add a check to avoid null pointer dereference as below:
> >>
> >> [   90.002283] general protection fault, probably for non-canonical
> >> address 0xdc00:  [#1] PREEMPT SMP KASAN NOPTI
> >> [   90.002292] KASAN: null-ptr-deref in range
> >> [0x-0x0007]
> >> [   90.002346]  ? exc_general_protection+0x159/0x240
> >> [   90.002352]  ? asm_exc_general_protection+0x26/0x30
> >> [   90.002357]  ? ttm_bo_evict_swapout_allowable+0x322/0x5e0 [ttm]
> >> [   90.002365]  ? ttm_bo_evict_swapout_allowable+0x42e/0x5e0 [ttm]
> >> [   90.002373]  ttm_bo_swapout+0x134/0x7f0 [ttm]
> >> [   90.002383]  ? __pfx_ttm_bo_swapout+0x10/0x10 [ttm]
> >> [   90.002391]  ? lock_acquire+0x44d/0x4f0
> >> [   90.002398]  ? ttm_device_swapout+0xa5/0x260 [ttm]
> >> [   90.002412]  ? lock_acquired+0x355/0xa00
> >> [   90.002416]  ? do_raw_spin_trylock+0xb6/0x190
> >> [   90.002421]  ? __pfx_lock_acquired+0x10/0x10
> >> [   90.002426]  ? ttm_global_swapout+0x25/0x210 [ttm]
> >> [   90.002442]  ttm_device_swapout+0x198/0x260 [ttm]
> >> [   90.002456]  ? __pfx_ttm_device_swapout+0x10/0x10 [ttm]
> >> [   90.002472]  ttm_global_swapout+0x75/0x210 [ttm]
> >> [   90.002486]  ttm_tt_populate+0x187/0x3f0 [ttm]
> >> [   90.002501]  ttm_bo_handle_move_mem+0x437/0x590 [ttm]
> >> [   90.002517]  ttm_bo_validate+0x275/0x430 [ttm]
> >> [   90.002530]  ? __pfx_ttm_bo_validate+0x10/0x10 [ttm]
> >> [   90.002544]  ? kasan_save_stack+0x33/0x60
> >> [   90.002550]  ? kasan_set_track+0x25/0x30
> >> [   90.002554]  ? __kasan_kmalloc+0x8f/0xa0
> >> [   90.002558]  ? amdgpu_gtt_mgr_new+0x81/0x420 [amdgpu]
> >> [   90.003023]  ? ttm_resource_alloc+0xf6/0x220 [ttm]
> >> [   90.003038]  amdgpu_bo_pin_restricted+0x2dd/0x8b0 [amdgpu]
> >> [   90.003210]  ? __x64_sys_ioctl+0x131/0x1a0
> >> [   90.003210]  ? do_syscall_64+0x60/0x90
> >>
> >> Fixes: a2848d08742c ("drm/ttm: never consider pinned BOs for
> >> eviction&swap")
> >> Tested-by: Mikhail Gavrilov 
> >> Signed-off-by: Guchun Chen 
> > Reviewed-by: Alex Deucher 
>
> Reviewed-by: Christian König 
>
> Has this already been pushed to drm-misc-next?
>
> Thanks,
> Christian.

Not yet, Christian, as I don't have push permission. I saw you were on 
vacation, so I would expect to ping you to push after you are back with full 
recharge.

Regards,
Guchun

> >
> >> ---
> >>   drivers/gpu/drm/ttm/ttm_bo.c | 3 ++-
> >>   1 file changed, 2 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c
> >> b/drivers/gpu/drm/ttm/ttm_bo.c index 7139a522b2f3..54e3083076b7
> >> 100644
> >> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> >> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
> >> @@ -519,7 +519,8 @@ static bool
> ttm_bo_evict_swapout_allowable(struct
> >> ttm_buffer_object *bo,
> >>
> >>  if (bo->pin_count) {
> >>  *locked = false;
> >> -   *busy = false;
> >> +   if (busy)
> >> +   *busy = false;
> >>  return false;
> >>  }
> >>
> >> --
> >> 2.25.1
> >>



RE: [RFC v1 1/3] mm/mmu_notifier: Add a new notifier for mapping updates (new pages)

2023-07-27 Thread Kasireddy, Vivek
Hi Jason,

> 
> On Tue, Jul 25, 2023 at 10:44:09PM +, Kasireddy, Vivek wrote:
> > > If you still need the memory mapped then you re-call hmm_range_fault
> > > and re-obtain it. hmm_range_fault will resolve all the races and you
> > > get new pages.
> 
> > IIUC, for my udmabuf use-case, it looks like calling hmm_range_fault
> > immediately after an invalidate (range notification) would preemptively
> fault in
> > new pages before a write. The problem with that is if a read occurs on
> those
> > new pages, then the data is incorrect as a write may not have
> > happened yet.
> 
> It cannot be, if you use hmm_range_fault correctly you cannot get
> corruption no matter what is done to the mmap'd memfd. If there is
> otherwise it is a hmm_range_fault bug plain and simple.
> 
> > Ideally, what I am looking for is for getting new pages at the time of or 
> > after
> > a write; until then, it is ok to use the old pages given my use-case.
> 
> It is wrong, if you are synchronizing the vma then you must use the
> latest copy. If your use case can tolerate it then keep a 'not
> present' indication for the missing pages until you actually need
> them, but dmabuf doesn't really provide an API for that.
> 
> > I think the difference comes down to whether we (udmabuf driver) want to
> > grab the new pages after getting notified about a PTE update because
> > of a fault
> 
> Why? You still haven't explained why you want this.
Ok, let me explain using one of the udmabuf selftests (added in patch #3)
to describe the problem (sorry, I'd have to use the terms memfd, hole, etc)
I am trying to solve:
size = MEMFD_SIZE * page_size;
memfd = create_memfd_with_seals(size, false);
addr1 = mmap_fd(memfd, size);
write_to_memfd(addr1, size, 'a');
buf = create_udmabuf_list(devfd, memfd, size);
addr2 = mmap_fd(buf, NUM_PAGES * NUM_ENTRIES * getpagesize());
punch_hole(memfd, MEMFD_SIZE / 2);
   -> At this point, if I were to read addr1, it'd still have "a" in relevant 
areas
because a new write hasn't happened yet. And, since this results in an
invalidation (notification) of the associated VMA range, I could 
register
a callback in udmabuf driver and get notified but I am not sure how or
why that would be useful.

write_to_memfd(addr1, size, 'b');
   -> Here, the hole gets refilled as a result of the above writes which trigger
faults and the PTEs are updated to point to new pages. When this 
happens,
the udmabuf driver needs to be made aware of the new pages that were
faulted in because of the new writes. Since there does not appear to be
a way to get notified when the hole is written to, the solution I came 
up
with is to either add a new notifier or add calls to change_pte() when 
the
PTEs do get updated. However, considering your suggestion to use
hmm_range_fault(), it is not clear to me how it would help while the 
hole
is being written to as the writes occur outside of the udmabuf driver. 
And,
there is no way to get notified or track them either, AFAICS from 
inside the
udmabuf driver.

Thanks,
Vivek

> 
> If you are writing to the pages then you have to do this
> 
> If you are reading from the pages then hmm_range_fault should return
> the zero page for a hole until it is written too
> 
> Jason


Re: [PATCH] drm/ttm: check null pointer before accessing when swapping

2023-07-27 Thread Mikhail Gavrilov
On Thu, Jul 27, 2023 at 12:33 PM Chen, Guchun  wrote:
> > Reviewed-by: Christian König 
> >
> > Has this already been pushed to drm-misc-next?
> >
> > Thanks,
> > Christian.
>
> Not yet, Christian, as I don't have push permission. I saw you were on 
> vacation, so I would expect to ping you to push after you are back with full 
> recharge.

I expect to see it in drm-fixes-6.5 cause the problem appeared during
the 6.5 release cycle.
And yes, I follow all pull requests. This patch was not included in
yesterday's pull request :(

-- 
Best Regards,
Mike Gavrilov.


Re: [PATCH v2] dma-buf: Fix the typo in DMA-BUF statistics doc

2023-07-27 Thread Christian König

Am 18.07.23 um 13:16 schrieb Luc Ma:

From: Luc Ma 

The kernel-doc for DMA-BUF statistics mentions /sys/kernel/dma-buf/buffers
but the correct path is /sys/kernel/dmabuf/buffers instead.

Signed-off-by: Luc Ma 
Reviewed-by: Javier Martinez Canillas 


Reviewed and pushed to drm-misc-next.

Thanks,
Christian.


---
  drivers/dma-buf/dma-buf-sysfs-stats.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma-buf/dma-buf-sysfs-stats.c 
b/drivers/dma-buf/dma-buf-sysfs-stats.c
index 6cfbbf0720bd..b5b62e40ccc1 100644
--- a/drivers/dma-buf/dma-buf-sysfs-stats.c
+++ b/drivers/dma-buf/dma-buf-sysfs-stats.c
@@ -33,7 +33,7 @@
   * into their address space. This necessitated the creation of the DMA-BUF 
sysfs
   * statistics interface to provide per-buffer information on production 
systems.
   *
- * The interface at ``/sys/kernel/dma-buf/buffers`` exposes information about
+ * The interface at ``/sys/kernel/dmabuf/buffers`` exposes information about
   * every DMA-BUF when ``CONFIG_DMABUF_SYSFS_STATS`` is enabled.
   *
   * The following stats are exposed by the interface:




Re: [Freedreno] [PATCH 06/12] drm/msm/adreno: Allow SoC specific gpu device table entries

2023-07-27 Thread Konrad Dybcio
On 27.07.2023 00:53, Rob Clark wrote:
> On Wed, Jul 26, 2023 at 3:33 PM Dmitry Baryshkov
>  wrote:
>>
>> On Thu, 27 Jul 2023 at 01:04, Rob Clark  wrote:
>>>
>>> On Wed, Jul 26, 2023 at 2:43 PM Dmitry Baryshkov
>>>  wrote:

 On 26/07/2023 23:11, Rob Clark wrote:
> On Wed, Jul 26, 2023 at 1:00 PM Dmitry Baryshkov
>  wrote:
>>
>> On Wed, 26 Jul 2023 at 21:28, Rob Clark  wrote:
>>>
>>> On Thu, Jul 13, 2023 at 1:26 PM Akhil P Oommen 
>>>  wrote:

 On Fri, Jul 07, 2023 at 05:34:04AM +0300, Dmitry Baryshkov wrote:
>
> On 07/07/2023 00:10, Rob Clark wrote:
>> From: Rob Clark 
>>
>> There are cases where there are differences due to SoC integration.
>> Such as cache-coherency support, and (in the next patch) e-fuse to
>> speedbin mappings.
>
> I have the feeling that we are trying to circumvent the way DT works. 
> I'd
> suggest adding explicit SoC-compatible strings to Adreno bindings and 
> then
> using of_device_id::data and then of_device_get_match_data().
>
 Just thinking, then how about a unique compatible string which we match
 to identify gpu->info and drop chip-id check completely here?
>>>
>>> Ok, I think we could do this, so something like:
>>>
>>>compatible = "qcom,sm4350-adreno-619.0", qcom,adreno-619.0", 
>>> "qcom,adreno"
>>>
>>> ?
>>>
>>> It looks like we don't have gpu dt bits upstream yet for either sm4350
>>> or sm6375, so I suppose we could get away with this change
>>
>> I think we can even skip the 619.0 part in the SoC compat string.
>> So it will be:
>>
>> compatible = "qcom,sm4350-adreno", qcom,adreno-619.0", "qcom,adreno";
>>
>> In future we can drop the chipid part completely and handle that as a
>> part of SoC data:
>>
>> compatible = "qcom,sm4350-adreno", "qcom,adreno";
>>
>> With the driver knowing that sm4350-adreno means ADRENO_ID(6,1,9,0)
>>
>
> I don't think we can do that, there are cases where the same SoC had
> multiple revisions of adreno.

 Is that the case for the production versions of the SoC? In other
 subsystems what we usually do is that we add support only for the latest
 SoC revision (which would probably mean the latest GPU patch revision).
 Previous GPU revisions can be added in the following way (pure example):

 qcom,sm4350-adreno -> 6,1,9,1 // assuming v2.0 or v1.1 is the commercial
 sample
 qcom,sm4350-v1-adreno -> 6,1,9,0

>>>
>>> My recollection was that nexus4 shipped with an early version of 8064
>>> which needed userspace workarounds that later 8064 did not.  Not sure
>>> if that is the only such example, but it is one that userspace needed
>>> to be aware of.
>>
>> Good question. I don't have nexus4, and both nexus7 and ifc6410 work fine.
>>
>> And this is a perfect use case for "qcom,apq8064-v1.1-adreno" compat string.
> 
> I no longer have a n4 that boots.. but if I did both it and the later
> ones should work properly if they expose the appropriate chip id
> 
> I do still prefer parsing the chip-id out of the compatible.  It
> avoids needing separate table entries just to have a different
> chip-id.  Maybe the scheme that is used elsewhere makes sense when it
> is only the kernel that needs to be aware of the device-id.  And maybe
> we could just done matching based on compat-id in userspace as well,
> but (a) msm and freedreno pre-date dt, and (b) that ship has already
> sailed.
I think a per-soc dt would be the better approach..

We could probably solve the revision issue with a socid readout of
the silicon revision and override based on that?

Konrad



Re: [PATCH 1/3] dt-bindings: display: panel: Move HannStar HSD101PWW2 to LVDS

2023-07-27 Thread Laurent Pinchart
Hi Thierry,

Thank you for the patch.

On Wed, Jul 26, 2023 at 08:48:55PM +0200, Thierry Reding wrote:
> From: Thierry Reding 
> 
> The HannStar HSD101PWW2 is an LVDS panel, so move it to the correct
> bindings file.
> 
> Signed-off-by: Thierry Reding 
> ---
>  Documentation/devicetree/bindings/display/panel/panel-lvds.yaml | 2 ++
>  .../devicetree/bindings/display/panel/panel-simple.yaml | 2 --
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml 
> b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> index 929fe046d1e7..344e5df40c2f 100644
> --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> @@ -40,6 +40,8 @@ properties:
>  items:
>- enum:
>- auo,b101ew05
> +  # HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS 
> panel
> +  - hannstar,hsd101pww2
>- tbs,a711-panel
>  
>- const: panel-lvds
> diff --git 
> a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml 
> b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> index df1cec8fd21b..f4d9da4afefd 100644
> --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> @@ -168,8 +168,6 @@ properties:
>- hannstar,hsd070pww1
>  # HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel
>- hannstar,hsd100pxn1

I'm wondering if it would make sense to move them all in one go ?
Regardless, this patch is OK, so

Reviewed-by: Laurent Pinchart 

> -# HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel
> -  - hannstar,hsd101pww2
>  # Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
>- hit,tx23d38vm0caa
>  # InfoVision Optoelectronics M133NWF4 R0 13.3" FHD (1920x1080) TFT 
> LCD panel

-- 
Regards,

Laurent Pinchart


Re: [PATCH 1/3] dt-bindings: display: panel: Move Chunghwa CLAA070WP03XG to LVDS

2023-07-27 Thread Laurent Pinchart
Hi Thierry,

Thank you for the patch.

On Wed, Jul 26, 2023 at 08:50:08PM +0200, Thierry Reding wrote:
> From: Thierry Reding 
> 
> The Chunghwa CLAA070WP03XG is an LVDS panel, so move it to the correct
> bindings file.
> 
> Signed-off-by: Thierry Reding 

Reviewed-by: Laurent Pinchart 

> ---
>  Documentation/devicetree/bindings/display/panel/panel-lvds.yaml | 2 ++
>  .../devicetree/bindings/display/panel/panel-simple.yaml | 2 --
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml 
> b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> index 344e5df40c2f..dbbf32a8be87 100644
> --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> @@ -40,6 +40,8 @@ properties:
>  items:
>- enum:
>- auo,b101ew05
> +  # Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel
> +  - chunghwa,claa070wp03xg
># HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS 
> panel
>- hannstar,hsd101pww2
>- tbs,a711-panel
> diff --git 
> a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml 
> b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> index f4d9da4afefd..67959290b212 100644
> --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml
> @@ -103,8 +103,6 @@ properties:
>- cdtech,s070wv95-ct16
>  # Chefree CH101OLHLWH-002 10.1" (1280x800) color TFT LCD panel
>- chefree,ch101olhlwh-002
> -# Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel
> -  - chunghwa,claa070wp03xg
>  # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
>- chunghwa,claa101wa01a
>  # Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel

-- 
Regards,

Laurent Pinchart


Re: [PATCH 2/3] dt-bindings: display: panel: Document Hydis HV070WX2-1E0

2023-07-27 Thread Laurent Pinchart
Hi Thierry,

Thank you for the patch.

On Wed, Jul 26, 2023 at 08:50:09PM +0200, Thierry Reding wrote:
> From: Thierry Reding 
> 
> The Hydis HV070WX2-1E0 is a 7" WXGA (800x1280) TFT LCD LVDS panel that
> is one of the variants used on Google Nexus 7.
> 
> Signed-off-by: Thierry Reding 

Reviewed-by: Laurent Pinchart 

> ---
>  Documentation/devicetree/bindings/display/panel/panel-lvds.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml 
> b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> index dbbf32a8be87..9f1016551e0b 100644
> --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml
> @@ -44,6 +44,8 @@ properties:
>- chunghwa,claa070wp03xg
># HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS 
> panel
>- hannstar,hsd101pww2
> +  # Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel
> +  - hydis,hv070wx2-1e0
>- tbs,a711-panel
>  
>- const: panel-lvds

-- 
Regards,

Laurent Pinchart


[PATCH v3 00/49] use refcount+RCU method to implement lockless slab shrink

2023-07-27 Thread Qi Zheng
Hi all,

1. Background
=

We used to implement the lockless slab shrink with SRCU [1], but then kernel
test robot reported -88.8% regression in stress-ng.ramfs.ops_per_sec test
case [2], so we reverted it [3].

This patch series aims to re-implement the lockless slab shrink using the
refcount+RCU method proposed by Dave Chinner [4].

[1]. 
https://lore.kernel.org/lkml/20230313112819.38938-1-zhengqi.a...@bytedance.com/
[2]. https://lore.kernel.org/lkml/202305230837.db2c233f-yujie@intel.com/
[3]. https://lore.kernel.org/all/20230609081518.3039120-1-qi.zh...@linux.dev/
[4]. https://lore.kernel.org/lkml/zijhou1d55d4h...@dread.disaster.area/

2. Implementation
=

Currently, the shrinker instances can be divided into the following three types:

a) global shrinker instance statically defined in the kernel, such as
   workingset_shadow_shrinker.

b) global shrinker instance statically defined in the kernel modules, such as
   mmu_shrinker in x86.

c) shrinker instance embedded in other structures.

For case a, the memory of shrinker instance is never freed. For case b, the
memory of shrinker instance will be freed after synchronize_rcu() when the
module is unloaded. For case c, the memory of shrinker instance will be freed
along with the structure it is embedded in.

In preparation for implementing lockless slab shrink, we need to dynamically
allocate those shrinker instances in case c, then the memory can be dynamically
freed alone by calling kfree_rcu().

This patchset adds the following new APIs for dynamically allocating shrinker,
and add a private_data field to struct shrinker to record and get the original
embedded structure.

1. shrinker_alloc()
2. shrinker_register()
3. shrinker_free()

In order to simplify shrinker-related APIs and make shrinker more independent of
other kernel mechanisms, this patchset uses the above APIs to convert all
shrinkers (including case a and b) to dynamically allocated, and then remove all
existing APIs. This will also have another advantage mentioned by Dave Chinner:

```
The other advantage of this is that it will break all the existing out of tree
code and third party modules using the old API and will no longer work with a
kernel using lockless slab shrinkers. They need to break (both at the source and
binary levels) to stop bad things from happening due to using uncoverted
shrinkers in the new setup.
```

Then we free the shrinker by calling call_rcu(), and use 
rcu_read_{lock,unlock}()
to ensure that the shrinker instance is valid. And the shrinker::refcount
mechanism ensures that the shrinker instance will not be run again after
unregistration. So the structure that records the pointer of shrinker instance
can be safely freed without waiting for the RCU read-side critical section.

In this way, while we implement the lockless slab shrink, we don't need to be
blocked in unregister_shrinker() to wait RCU read-side critical section.

PATCH 1: fix memory leak in binder_init()
PATCH 2: move some shrinker-related function declarations to mm/internal.h
PATCH 3: move shrinker-related code into a separate file
PATCH 4: remove redundant shrinker_rwsem in debugfs operations
PATCH 5: add infrastructure for dynamically allocating shrinker
PATCH 6 ~ 23: dynamically allocate the shrinker instances in case a and b
PATCH 24 ~ 42: dynamically allocate the shrinker instances in case c
PATCH 43: remove old APIs
PATCH 44: introduce pool_shrink_rwsem to implement private 
synchronize_shrinkers()
PATCH 45: add a secondary array for shrinker_info::{map, nr_deferred}
PATCH 46 ~ 47: implement the lockless slab shrink
PATCH 48 ~ 49: convert shrinker_rwsem to mutex

3. Testing
==

3.1 slab shrink stress test
---

We can reproduce the down_read_trylock() hotspot through the following script:

```

DIR="/root/shrinker/memcg/mnt"

do_create()
{
mkdir -p /sys/fs/cgroup/memory/test
echo 4G > /sys/fs/cgroup/memory/test/memory.limit_in_bytes
for i in `seq 0 $1`;
do
mkdir -p /sys/fs/cgroup/memory/test/$i;
echo $$ > /sys/fs/cgroup/memory/test/$i/cgroup.procs;
mkdir -p $DIR/$i;
done
}

do_mount()
{
for i in `seq $1 $2`;
do
mount -t tmpfs $i $DIR/$i;
done
}

do_touch()
{
for i in `seq $1 $2`;
do
echo $$ > /sys/fs/cgroup/memory/test/$i/cgroup.procs;
dd if=/dev/zero of=$DIR/$i/file$i bs=1M count=1 &
done
}

case "$1" in
  touch)
do_touch $2 $3
;;
  test)
do_create 4000
do_mount 0 4000
do_touch 0 3000
;;
  *)
exit 1
;;
esac
```

Save the above script, then run test and touch commands. Then we can use the
following perf command to view hotspots:

perf top -U -F 999

1) Before applying this patchset:

  40.44%  [kernel][k] down_read_trylock
  17.59%  [kernel][k] up_read
  13.64%  [kernel][k] pv_native_safe_halt
  11.90%  [kernel][k] shrink_slab
   8.21%  [kernel][k] idr_

[PATCH v3 01/49] binder: fix memory leak in binder_init()

2023-07-27 Thread Qi Zheng
In binder_init(), the destruction of binder_alloc_shrinker_init() is not
performed in the wrong path, which will cause memory leaks. So this commit
introduces binder_alloc_shrinker_exit() and calls it in the wrong path to
fix that.

Fixes: f2517eb76f1f ("android: binder: Add global lru shrinker to binder")
Signed-off-by: Qi Zheng 
Acked-by: Carlos Llamas 
---
 drivers/android/binder.c   | 1 +
 drivers/android/binder_alloc.c | 6 ++
 drivers/android/binder_alloc.h | 1 +
 3 files changed, 8 insertions(+)

diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 486c8271cab7..d720f93d8b19 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -6617,6 +6617,7 @@ static int __init binder_init(void)
 
 err_alloc_device_names_failed:
debugfs_remove_recursive(binder_debugfs_dir_entry_root);
+   binder_alloc_shrinker_exit();
 
return ret;
 }
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 662a2a2e2e84..e3db8297095a 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -1087,6 +1087,12 @@ int binder_alloc_shrinker_init(void)
return ret;
 }
 
+void binder_alloc_shrinker_exit(void)
+{
+   unregister_shrinker(&binder_shrinker);
+   list_lru_destroy(&binder_alloc_lru);
+}
+
 /**
  * check_buffer() - verify that buffer/offset is safe to access
  * @alloc: binder_alloc for this proc
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index 138d1d5af9ce..dc1e2b01dd64 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -129,6 +129,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct 
binder_alloc *alloc,
  int pid);
 extern void binder_alloc_init(struct binder_alloc *alloc);
 extern int binder_alloc_shrinker_init(void);
+extern void binder_alloc_shrinker_exit(void);
 extern void binder_alloc_vma_close(struct binder_alloc *alloc);
 extern struct binder_buffer *
 binder_alloc_prepare_to_free(struct binder_alloc *alloc,
-- 
2.30.2



[PATCH v3 02/49] mm: move some shrinker-related function declarations to mm/internal.h

2023-07-27 Thread Qi Zheng
The following functions are only used inside the mm subsystem, so it's
better to move their declarations to the mm/internal.h file.

1. shrinker_debugfs_add()
2. shrinker_debugfs_detach()
3. shrinker_debugfs_remove()

Signed-off-by: Qi Zheng 
---
 include/linux/shrinker.h | 19 ---
 mm/internal.h| 28 
 2 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index 224293b2dd06..8dc15aa37410 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -106,28 +106,9 @@ extern void free_prealloced_shrinker(struct shrinker 
*shrinker);
 extern void synchronize_shrinkers(void);
 
 #ifdef CONFIG_SHRINKER_DEBUG
-extern int shrinker_debugfs_add(struct shrinker *shrinker);
-extern struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
- int *debugfs_id);
-extern void shrinker_debugfs_remove(struct dentry *debugfs_entry,
-   int debugfs_id);
 extern int __printf(2, 3) shrinker_debugfs_rename(struct shrinker *shrinker,
  const char *fmt, ...);
 #else /* CONFIG_SHRINKER_DEBUG */
-static inline int shrinker_debugfs_add(struct shrinker *shrinker)
-{
-   return 0;
-}
-static inline struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
-int *debugfs_id)
-{
-   *debugfs_id = -1;
-   return NULL;
-}
-static inline void shrinker_debugfs_remove(struct dentry *debugfs_entry,
-  int debugfs_id)
-{
-}
 static inline __printf(2, 3)
 int shrinker_debugfs_rename(struct shrinker *shrinker, const char *fmt, ...)
 {
diff --git a/mm/internal.h b/mm/internal.h
index 5a03bc4782a2..8aeaf16ae039 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1135,4 +1135,32 @@ struct vma_prepare {
struct vm_area_struct *remove;
struct vm_area_struct *remove2;
 };
+
+/*
+ * shrinker related functions
+ */
+
+#ifdef CONFIG_SHRINKER_DEBUG
+extern int shrinker_debugfs_add(struct shrinker *shrinker);
+extern struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
+ int *debugfs_id);
+extern void shrinker_debugfs_remove(struct dentry *debugfs_entry,
+   int debugfs_id);
+#else /* CONFIG_SHRINKER_DEBUG */
+static inline int shrinker_debugfs_add(struct shrinker *shrinker)
+{
+   return 0;
+}
+static inline struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
+int *debugfs_id)
+{
+   *debugfs_id = -1;
+   return NULL;
+}
+static inline void shrinker_debugfs_remove(struct dentry *debugfs_entry,
+  int debugfs_id)
+{
+}
+#endif /* CONFIG_SHRINKER_DEBUG */
+
 #endif /* __MM_INTERNAL_H */
-- 
2.30.2



[PATCH v3 03/49] mm: vmscan: move shrinker-related code into a separate file

2023-07-27 Thread Qi Zheng
The mm/vmscan.c file is too large, so separate the shrinker-related
code from it into a separate file. No functional changes.

Signed-off-by: Qi Zheng 
---
 mm/Makefile   |   4 +-
 mm/internal.h |   2 +
 mm/shrinker.c | 709 ++
 mm/vmscan.c   | 701 -
 4 files changed, 713 insertions(+), 703 deletions(-)
 create mode 100644 mm/shrinker.c

diff --git a/mm/Makefile b/mm/Makefile
index e6d9a1d5e84d..48a2ab9f86ac 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -48,8 +48,8 @@ endif
 
 obj-y  := filemap.o mempool.o oom_kill.o fadvise.o \
   maccess.o page-writeback.o folio-compat.o \
-  readahead.o swap.o truncate.o vmscan.o shmem.o \
-  util.o mmzone.o vmstat.o backing-dev.o \
+  readahead.o swap.o truncate.o vmscan.o shrinker.o \
+  shmem.o util.o mmzone.o vmstat.o backing-dev.o \
   mm_init.o percpu.o slab_common.o \
   compaction.o show_mem.o\
   interval_tree.o list_lru.o workingset.o \
diff --git a/mm/internal.h b/mm/internal.h
index 8aeaf16ae039..8b82038dcc6a 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1139,6 +1139,8 @@ struct vma_prepare {
 /*
  * shrinker related functions
  */
+unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct mem_cgroup *memcg,
+ int priority);
 
 #ifdef CONFIG_SHRINKER_DEBUG
 extern int shrinker_debugfs_add(struct shrinker *shrinker);
diff --git a/mm/shrinker.c b/mm/shrinker.c
new file mode 100644
index ..043c87ccfab4
--- /dev/null
+++ b/mm/shrinker.c
@@ -0,0 +1,709 @@
+// SPDX-License-Identifier: GPL-2.0
+#include 
+#include 
+#include 
+#include 
+
+#include "internal.h"
+
+LIST_HEAD(shrinker_list);
+DECLARE_RWSEM(shrinker_rwsem);
+
+#ifdef CONFIG_MEMCG
+static int shrinker_nr_max;
+
+/* The shrinker_info is expanded in a batch of BITS_PER_LONG */
+static inline int shrinker_map_size(int nr_items)
+{
+   return (DIV_ROUND_UP(nr_items, BITS_PER_LONG) * sizeof(unsigned long));
+}
+
+static inline int shrinker_defer_size(int nr_items)
+{
+   return (round_up(nr_items, BITS_PER_LONG) * sizeof(atomic_long_t));
+}
+
+void free_shrinker_info(struct mem_cgroup *memcg)
+{
+   struct mem_cgroup_per_node *pn;
+   struct shrinker_info *info;
+   int nid;
+
+   for_each_node(nid) {
+   pn = memcg->nodeinfo[nid];
+   info = rcu_dereference_protected(pn->shrinker_info, true);
+   kvfree(info);
+   rcu_assign_pointer(pn->shrinker_info, NULL);
+   }
+}
+
+int alloc_shrinker_info(struct mem_cgroup *memcg)
+{
+   struct shrinker_info *info;
+   int nid, size, ret = 0;
+   int map_size, defer_size = 0;
+
+   down_write(&shrinker_rwsem);
+   map_size = shrinker_map_size(shrinker_nr_max);
+   defer_size = shrinker_defer_size(shrinker_nr_max);
+   size = map_size + defer_size;
+   for_each_node(nid) {
+   info = kvzalloc_node(sizeof(*info) + size, GFP_KERNEL, nid);
+   if (!info) {
+   free_shrinker_info(memcg);
+   ret = -ENOMEM;
+   break;
+   }
+   info->nr_deferred = (atomic_long_t *)(info + 1);
+   info->map = (void *)info->nr_deferred + defer_size;
+   info->map_nr_max = shrinker_nr_max;
+   rcu_assign_pointer(memcg->nodeinfo[nid]->shrinker_info, info);
+   }
+   up_write(&shrinker_rwsem);
+
+   return ret;
+}
+
+static struct shrinker_info *shrinker_info_protected(struct mem_cgroup *memcg,
+int nid)
+{
+   return rcu_dereference_protected(memcg->nodeinfo[nid]->shrinker_info,
+lockdep_is_held(&shrinker_rwsem));
+}
+
+static int expand_one_shrinker_info(struct mem_cgroup *memcg,
+   int map_size, int defer_size,
+   int old_map_size, int old_defer_size,
+   int new_nr_max)
+{
+   struct shrinker_info *new, *old;
+   struct mem_cgroup_per_node *pn;
+   int nid;
+   int size = map_size + defer_size;
+
+   for_each_node(nid) {
+   pn = memcg->nodeinfo[nid];
+   old = shrinker_info_protected(memcg, nid);
+   /* Not yet online memcg */
+   if (!old)
+   return 0;
+
+   /* Already expanded this shrinker_info */
+   if (new_nr_max <= old->map_nr_max)
+   continue;
+
+   new = kvmalloc_node(sizeof(*new) + size, GFP_KERNEL, nid);
+   if (!new)
+   return -ENOMEM;
+
+   new->nr_deferred = (atomic_long_t *)(new + 1);
+   n

[PATCH v3 04/49] mm: shrinker: remove redundant shrinker_rwsem in debugfs operations

2023-07-27 Thread Qi Zheng
The debugfs_remove_recursive() will wait for debugfs_file_put() to return,
so the shrinker will not be freed when doing debugfs operations (such as
shrinker_debugfs_count_show() and shrinker_debugfs_scan_write()), so there
is no need to hold shrinker_rwsem during debugfs operations.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 mm/shrinker_debug.c | 14 --
 1 file changed, 14 deletions(-)

diff --git a/mm/shrinker_debug.c b/mm/shrinker_debug.c
index 3ab53fad8876..f1becfd45853 100644
--- a/mm/shrinker_debug.c
+++ b/mm/shrinker_debug.c
@@ -55,11 +55,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, 
void *v)
if (!count_per_node)
return -ENOMEM;
 
-   ret = down_read_killable(&shrinker_rwsem);
-   if (ret) {
-   kfree(count_per_node);
-   return ret;
-   }
rcu_read_lock();
 
memcg_aware = shrinker->flags & SHRINKER_MEMCG_AWARE;
@@ -92,7 +87,6 @@ static int shrinker_debugfs_count_show(struct seq_file *m, 
void *v)
} while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL);
 
rcu_read_unlock();
-   up_read(&shrinker_rwsem);
 
kfree(count_per_node);
return ret;
@@ -117,7 +111,6 @@ static ssize_t shrinker_debugfs_scan_write(struct file 
*file,
struct mem_cgroup *memcg = NULL;
int nid;
char kbuf[72];
-   ssize_t ret;
 
read_len = size < (sizeof(kbuf) - 1) ? size : (sizeof(kbuf) - 1);
if (copy_from_user(kbuf, buf, read_len))
@@ -146,12 +139,6 @@ static ssize_t shrinker_debugfs_scan_write(struct file 
*file,
return -EINVAL;
}
 
-   ret = down_read_killable(&shrinker_rwsem);
-   if (ret) {
-   mem_cgroup_put(memcg);
-   return ret;
-   }
-
sc.nid = nid;
sc.memcg = memcg;
sc.nr_to_scan = nr_to_scan;
@@ -159,7 +146,6 @@ static ssize_t shrinker_debugfs_scan_write(struct file 
*file,
 
shrinker->scan_objects(shrinker, &sc);
 
-   up_read(&shrinker_rwsem);
mem_cgroup_put(memcg);
 
return size;
-- 
2.30.2



[PATCH v3 05/49] mm: shrinker: add infrastructure for dynamically allocating shrinker

2023-07-27 Thread Qi Zheng
Currently, the shrinker instances can be divided into the following three
types:

a) global shrinker instance statically defined in the kernel, such as
   workingset_shadow_shrinker.

b) global shrinker instance statically defined in the kernel modules, such
   as mmu_shrinker in x86.

c) shrinker instance embedded in other structures.

For case a, the memory of shrinker instance is never freed. For case b,
the memory of shrinker instance will be freed after synchronize_rcu() when
the module is unloaded. For case c, the memory of shrinker instance will
be freed along with the structure it is embedded in.

In preparation for implementing lockless slab shrink, we need to
dynamically allocate those shrinker instances in case c, then the memory
can be dynamically freed alone by calling kfree_rcu().

So this commit adds the following new APIs for dynamically allocating
shrinker, and add a private_data field to struct shrinker to record and
get the original embedded structure.

1. shrinker_alloc()

Used to allocate shrinker instance itself and related memory, it will
return a pointer to the shrinker instance on success and NULL on failure.

2. shrinker_register()

Used to register the shrinker instance, which is same as the current
register_shrinker_prepared().

3. shrinker_free()

Used to unregister (if needed) and free the shrinker instance.

In order to simplify shrinker-related APIs and make shrinker more
independent of other kernel mechanisms, subsequent submissions will use
the above API to convert all shrinkers (including case a and b) to
dynamically allocated, and then remove all existing APIs.

This will also have another advantage mentioned by Dave Chinner:

```
The other advantage of this is that it will break all the existing
out of tree code and third party modules using the old API and will
no longer work with a kernel using lockless slab shrinkers. They
need to break (both at the source and binary levels) to stop bad
things from happening due to using uncoverted shrinkers in the new
setup.
```

Signed-off-by: Qi Zheng 
---
 include/linux/shrinker.h |   7 +++
 mm/internal.h|  11 +
 mm/shrinker.c| 101 +++
 mm/shrinker_debug.c  |  17 ++-
 4 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index 8dc15aa37410..cc23ff0aee20 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -70,6 +70,8 @@ struct shrinker {
int seeks;  /* seeks to recreate an obj */
unsigned flags;
 
+   void *private_data;
+
/* These are for internal use */
struct list_head list;
 #ifdef CONFIG_MEMCG
@@ -95,6 +97,11 @@ struct shrinker {
  * non-MEMCG_AWARE shrinker should not have this flag set.
  */
 #define SHRINKER_NONSLAB   (1 << 3)
+#define SHRINKER_ALLOCATED (1 << 4)
+
+struct shrinker *shrinker_alloc(unsigned int flags, const char *fmt, ...);
+void shrinker_register(struct shrinker *shrinker);
+void shrinker_free(struct shrinker *shrinker);
 
 extern int __printf(2, 3) prealloc_shrinker(struct shrinker *shrinker,
const char *fmt, ...);
diff --git a/mm/internal.h b/mm/internal.h
index 8b82038dcc6a..38434175df86 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1144,6 +1144,9 @@ unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct 
mem_cgroup *memcg,
 
 #ifdef CONFIG_SHRINKER_DEBUG
 extern int shrinker_debugfs_add(struct shrinker *shrinker);
+extern int shrinker_debugfs_name_alloc(struct shrinker *shrinker,
+  const char *fmt, va_list ap);
+extern void shrinker_debugfs_name_free(struct shrinker *shrinker);
 extern struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
  int *debugfs_id);
 extern void shrinker_debugfs_remove(struct dentry *debugfs_entry,
@@ -1153,6 +1156,14 @@ static inline int shrinker_debugfs_add(struct shrinker 
*shrinker)
 {
return 0;
 }
+static inline int shrinker_debugfs_name_alloc(struct shrinker *shrinker,
+ const char *fmt, va_list ap)
+{
+   return 0;
+}
+static inline void shrinker_debugfs_name_free(struct shrinker *shrinker)
+{
+}
 static inline struct dentry *shrinker_debugfs_detach(struct shrinker *shrinker,
 int *debugfs_id)
 {
diff --git a/mm/shrinker.c b/mm/shrinker.c
index 043c87ccfab4..43a375f954f3 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -550,6 +550,107 @@ unsigned long shrink_slab(gfp_t gfp_mask, int nid, struct 
mem_cgroup *memcg,
return freed;
 }
 
+struct shrinker *shrinker_alloc(unsigned int flags, const char *fmt, ...)
+{
+   struct shrinker *shrinker;
+   unsigned int size;
+   va_list ap;
+   int err;
+
+   shrinker = kzalloc(sizeof(struct shrinker), GFP_KERNEL);
+   if (!shrinker)
+   ret

[PATCH v3 06/49] kvm: mmu: dynamically allocate the x86-mmu shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the x86-mmu shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 arch/x86/kvm/mmu/mmu.c | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index ec169f5c7dce..15fc92a24a26 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -6847,11 +6847,7 @@ static unsigned long mmu_shrink_count(struct shrinker 
*shrink,
return percpu_counter_read_positive(&kvm_total_used_mmu_pages);
 }
 
-static struct shrinker mmu_shrinker = {
-   .count_objects = mmu_shrink_count,
-   .scan_objects = mmu_shrink_scan,
-   .seeks = DEFAULT_SEEKS * 10,
-};
+static struct shrinker *mmu_shrinker;
 
 static void mmu_destroy_caches(void)
 {
@@ -6984,10 +6980,16 @@ int kvm_mmu_vendor_module_init(void)
if (percpu_counter_init(&kvm_total_used_mmu_pages, 0, GFP_KERNEL))
goto out;
 
-   ret = register_shrinker(&mmu_shrinker, "x86-mmu");
-   if (ret)
+   mmu_shrinker = shrinker_alloc(0, "x86-mmu");
+   if (!mmu_shrinker)
goto out_shrinker;
 
+   mmu_shrinker->count_objects = mmu_shrink_count;
+   mmu_shrinker->scan_objects = mmu_shrink_scan;
+   mmu_shrinker->seeks = DEFAULT_SEEKS * 10;
+
+   shrinker_register(mmu_shrinker);
+
return 0;
 
 out_shrinker:
@@ -7009,7 +7011,7 @@ void kvm_mmu_vendor_module_exit(void)
 {
mmu_destroy_caches();
percpu_counter_destroy(&kvm_total_used_mmu_pages);
-   unregister_shrinker(&mmu_shrinker);
+   shrinker_free(mmu_shrinker);
 }
 
 /*
-- 
2.30.2



[PATCH v3 07/49] binder: dynamically allocate the android-binder shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the android-binder shrinker.

Signed-off-by: Qi Zheng 
---
 drivers/android/binder_alloc.c | 31 +++
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index e3db8297095a..62675cedd38e 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -1053,11 +1053,7 @@ binder_shrink_scan(struct shrinker *shrink, struct 
shrink_control *sc)
NULL, sc->nr_to_scan);
 }
 
-static struct shrinker binder_shrinker = {
-   .count_objects = binder_shrink_count,
-   .scan_objects = binder_shrink_scan,
-   .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *binder_shrinker;
 
 /**
  * binder_alloc_init() - called by binder_open() for per-proc initialization
@@ -1077,19 +1073,30 @@ void binder_alloc_init(struct binder_alloc *alloc)
 
 int binder_alloc_shrinker_init(void)
 {
-   int ret = list_lru_init(&binder_alloc_lru);
+   int ret;
 
-   if (ret == 0) {
-   ret = register_shrinker(&binder_shrinker, "android-binder");
-   if (ret)
-   list_lru_destroy(&binder_alloc_lru);
+   ret = list_lru_init(&binder_alloc_lru);
+   if (ret)
+   return ret;
+
+   binder_shrinker = shrinker_alloc(0, "android-binder");
+   if (!binder_shrinker) {
+   list_lru_destroy(&binder_alloc_lru);
+   return -ENOMEM;
}
-   return ret;
+
+   binder_shrinker->count_objects = binder_shrink_count;
+   binder_shrinker->scan_objects = binder_shrink_scan;
+   binder_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(binder_shrinker);
+
+   return 0;
 }
 
 void binder_alloc_shrinker_exit(void)
 {
-   unregister_shrinker(&binder_shrinker);
+   shrinker_free(binder_shrinker);
list_lru_destroy(&binder_alloc_lru);
 }
 
-- 
2.30.2



[PATCH v3 08/49] drm/ttm: dynamically allocate the drm-ttm_pool shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the drm-ttm_pool shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/gpu/drm/ttm/ttm_pool.c | 23 +++
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index cddb9151d20f..c9c9618c0dce 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -73,7 +73,7 @@ static struct ttm_pool_type global_dma32_uncached[MAX_ORDER + 
1];
 
 static spinlock_t shrinker_lock;
 static struct list_head shrinker_list;
-static struct shrinker mm_shrinker;
+static struct shrinker *mm_shrinker;
 
 /* Allocate pages of size 1 << order with the given gfp_flags */
 static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags,
@@ -734,8 +734,8 @@ static int ttm_pool_debugfs_shrink_show(struct seq_file *m, 
void *data)
struct shrink_control sc = { .gfp_mask = GFP_NOFS };
 
fs_reclaim_acquire(GFP_KERNEL);
-   seq_printf(m, "%lu/%lu\n", ttm_pool_shrinker_count(&mm_shrinker, &sc),
-  ttm_pool_shrinker_scan(&mm_shrinker, &sc));
+   seq_printf(m, "%lu/%lu\n", ttm_pool_shrinker_count(mm_shrinker, &sc),
+  ttm_pool_shrinker_scan(mm_shrinker, &sc));
fs_reclaim_release(GFP_KERNEL);
 
return 0;
@@ -779,10 +779,17 @@ int ttm_pool_mgr_init(unsigned long num_pages)
&ttm_pool_debugfs_shrink_fops);
 #endif
 
-   mm_shrinker.count_objects = ttm_pool_shrinker_count;
-   mm_shrinker.scan_objects = ttm_pool_shrinker_scan;
-   mm_shrinker.seeks = 1;
-   return register_shrinker(&mm_shrinker, "drm-ttm_pool");
+   mm_shrinker = shrinker_alloc(0, "drm-ttm_pool");
+   if (!mm_shrinker)
+   return -ENOMEM;
+
+   mm_shrinker->count_objects = ttm_pool_shrinker_count;
+   mm_shrinker->scan_objects = ttm_pool_shrinker_scan;
+   mm_shrinker->seeks = 1;
+
+   shrinker_register(mm_shrinker);
+
+   return 0;
 }
 
 /**
@@ -802,6 +809,6 @@ void ttm_pool_mgr_fini(void)
ttm_pool_type_fini(&global_dma32_uncached[i]);
}
 
-   unregister_shrinker(&mm_shrinker);
+   shrinker_free(mm_shrinker);
WARN_ON(!list_empty(&shrinker_list));
 }
-- 
2.30.2



[PATCH v3 09/49] xenbus/backend: dynamically allocate the xen-backend shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the xen-backend shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/xen/xenbus/xenbus_probe_backend.c | 18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c 
b/drivers/xen/xenbus/xenbus_probe_backend.c
index da96c260e26b..929c41a5ccee 100644
--- a/drivers/xen/xenbus/xenbus_probe_backend.c
+++ b/drivers/xen/xenbus/xenbus_probe_backend.c
@@ -284,13 +284,9 @@ static unsigned long backend_shrink_memory_count(struct 
shrinker *shrinker,
return 0;
 }
 
-static struct shrinker backend_memory_shrinker = {
-   .count_objects = backend_shrink_memory_count,
-   .seeks = DEFAULT_SEEKS,
-};
-
 static int __init xenbus_probe_backend_init(void)
 {
+   struct shrinker *backend_memory_shrinker;
static struct notifier_block xenstore_notifier = {
.notifier_call = backend_probe_and_watch
};
@@ -305,8 +301,16 @@ static int __init xenbus_probe_backend_init(void)
 
register_xenstore_notifier(&xenstore_notifier);
 
-   if (register_shrinker(&backend_memory_shrinker, "xen-backend"))
-   pr_warn("shrinker registration failed\n");
+   backend_memory_shrinker = shrinker_alloc(0, "xen-backend");
+   if (!backend_memory_shrinker) {
+   pr_warn("shrinker allocation failed\n");
+   return 0;
+   }
+
+   backend_memory_shrinker->count_objects = backend_shrink_memory_count;
+   backend_memory_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(backend_memory_shrinker);
 
return 0;
 }
-- 
2.30.2



[PATCH v3 10/49] erofs: dynamically allocate the erofs-shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the erofs-shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/erofs/utils.c | 20 +---
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/fs/erofs/utils.c b/fs/erofs/utils.c
index cc6fb9e98899..6e1a828e6ca3 100644
--- a/fs/erofs/utils.c
+++ b/fs/erofs/utils.c
@@ -270,19 +270,25 @@ static unsigned long erofs_shrink_scan(struct shrinker 
*shrink,
return freed;
 }
 
-static struct shrinker erofs_shrinker_info = {
-   .scan_objects = erofs_shrink_scan,
-   .count_objects = erofs_shrink_count,
-   .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *erofs_shrinker_info;
 
 int __init erofs_init_shrinker(void)
 {
-   return register_shrinker(&erofs_shrinker_info, "erofs-shrinker");
+   erofs_shrinker_info = shrinker_alloc(0, "erofs-shrinker");
+   if (!erofs_shrinker_info)
+   return -ENOMEM;
+
+   erofs_shrinker_info->count_objects = erofs_shrink_count;
+   erofs_shrinker_info->scan_objects = erofs_shrink_scan;
+   erofs_shrinker_info->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(erofs_shrinker_info);
+
+   return 0;
 }
 
 void erofs_exit_shrinker(void)
 {
-   unregister_shrinker(&erofs_shrinker_info);
+   shrinker_free(erofs_shrinker_info);
 }
 #endif /* !CONFIG_EROFS_FS_ZIP */
-- 
2.30.2



[PATCH v3 11/49] f2fs: dynamically allocate the f2fs-shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the f2fs-shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/f2fs/super.c | 32 
 1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index a123f1378d57..9200b67aa745 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -83,11 +83,27 @@ void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, 
unsigned int rate,
 #endif
 
 /* f2fs-wide shrinker description */
-static struct shrinker f2fs_shrinker_info = {
-   .scan_objects = f2fs_shrink_scan,
-   .count_objects = f2fs_shrink_count,
-   .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *f2fs_shrinker_info;
+
+static int __init f2fs_init_shrinker(void)
+{
+   f2fs_shrinker_info = shrinker_alloc(0, "f2fs-shrinker");
+   if (!f2fs_shrinker_info)
+   return -ENOMEM;
+
+   f2fs_shrinker_info->count_objects = f2fs_shrink_count;
+   f2fs_shrinker_info->scan_objects = f2fs_shrink_scan;
+   f2fs_shrinker_info->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(f2fs_shrinker_info);
+
+   return 0;
+}
+
+static void f2fs_exit_shrinker(void)
+{
+   shrinker_free(f2fs_shrinker_info);
+}
 
 enum {
Opt_gc_background,
@@ -4937,7 +4953,7 @@ static int __init init_f2fs_fs(void)
err = f2fs_init_sysfs();
if (err)
goto free_garbage_collection_cache;
-   err = register_shrinker(&f2fs_shrinker_info, "f2fs-shrinker");
+   err = f2fs_init_shrinker();
if (err)
goto free_sysfs;
err = register_filesystem(&f2fs_fs_type);
@@ -4982,7 +4998,7 @@ static int __init init_f2fs_fs(void)
f2fs_destroy_root_stats();
unregister_filesystem(&f2fs_fs_type);
 free_shrinker:
-   unregister_shrinker(&f2fs_shrinker_info);
+   f2fs_exit_shrinker();
 free_sysfs:
f2fs_exit_sysfs();
 free_garbage_collection_cache:
@@ -5014,7 +5030,7 @@ static void __exit exit_f2fs_fs(void)
f2fs_destroy_post_read_processing();
f2fs_destroy_root_stats();
unregister_filesystem(&f2fs_fs_type);
-   unregister_shrinker(&f2fs_shrinker_info);
+   f2fs_exit_shrinker();
f2fs_exit_sysfs();
f2fs_destroy_garbage_collection_cache();
f2fs_destroy_extent_cache();
-- 
2.30.2



[PATCH v3 12/49] gfs2: dynamically allocate the gfs2-glock shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the gfs2-glock shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/gfs2/glock.c | 20 +++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 1438e7465e30..8d582ba7514f 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -2046,11 +2046,7 @@ static unsigned long gfs2_glock_shrink_count(struct 
shrinker *shrink,
return vfs_pressure_ratio(atomic_read(&lru_count));
 }
 
-static struct shrinker glock_shrinker = {
-   .seeks = DEFAULT_SEEKS,
-   .count_objects = gfs2_glock_shrink_count,
-   .scan_objects = gfs2_glock_shrink_scan,
-};
+static struct shrinker *glock_shrinker;
 
 /**
  * glock_hash_walk - Call a function for glock in a hash bucket
@@ -2472,13 +2468,19 @@ int __init gfs2_glock_init(void)
return -ENOMEM;
}
 
-   ret = register_shrinker(&glock_shrinker, "gfs2-glock");
-   if (ret) {
+   glock_shrinker = shrinker_alloc(0, "gfs2-glock");
+   if (!glock_shrinker) {
destroy_workqueue(glock_workqueue);
rhashtable_destroy(&gl_hash_table);
-   return ret;
+   return -ENOMEM;
}
 
+   glock_shrinker->count_objects = gfs2_glock_shrink_count;
+   glock_shrinker->scan_objects = gfs2_glock_shrink_scan;
+   glock_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(glock_shrinker);
+
for (i = 0; i < GLOCK_WAIT_TABLE_SIZE; i++)
init_waitqueue_head(glock_wait_table + i);
 
@@ -2487,7 +2489,7 @@ int __init gfs2_glock_init(void)
 
 void gfs2_glock_exit(void)
 {
-   unregister_shrinker(&glock_shrinker);
+   shrinker_free(glock_shrinker);
rhashtable_destroy(&gl_hash_table);
destroy_workqueue(glock_workqueue);
 }
-- 
2.30.2



[PATCH v3 13/49] gfs2: dynamically allocate the gfs2-qd shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the gfs2-qd shrinker.

Signed-off-by: Qi Zheng 
---
 fs/gfs2/main.c  |  6 +++---
 fs/gfs2/quota.c | 26 --
 fs/gfs2/quota.h |  3 ++-
 3 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index afcb32854f14..e47b1cc79f59 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -147,7 +147,7 @@ static int __init init_gfs2_fs(void)
if (!gfs2_trans_cachep)
goto fail_cachep8;
 
-   error = register_shrinker(&gfs2_qd_shrinker, "gfs2-qd");
+   error = gfs2_qd_shrinker_init();
if (error)
goto fail_shrinker;
 
@@ -196,7 +196,7 @@ static int __init init_gfs2_fs(void)
 fail_wq2:
destroy_workqueue(gfs_recovery_wq);
 fail_wq1:
-   unregister_shrinker(&gfs2_qd_shrinker);
+   gfs2_qd_shrinker_exit();
 fail_shrinker:
kmem_cache_destroy(gfs2_trans_cachep);
 fail_cachep8:
@@ -229,7 +229,7 @@ static int __init init_gfs2_fs(void)
 
 static void __exit exit_gfs2_fs(void)
 {
-   unregister_shrinker(&gfs2_qd_shrinker);
+   gfs2_qd_shrinker_exit();
gfs2_glock_exit();
gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index aa5fd06d47bc..6cbf323bc4d0 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -186,13 +186,27 @@ static unsigned long gfs2_qd_shrink_count(struct shrinker 
*shrink,
return vfs_pressure_ratio(list_lru_shrink_count(&gfs2_qd_lru, sc));
 }
 
-struct shrinker gfs2_qd_shrinker = {
-   .count_objects = gfs2_qd_shrink_count,
-   .scan_objects = gfs2_qd_shrink_scan,
-   .seeks = DEFAULT_SEEKS,
-   .flags = SHRINKER_NUMA_AWARE,
-};
+static struct shrinker *gfs2_qd_shrinker;
+
+int __init gfs2_qd_shrinker_init(void)
+{
+   gfs2_qd_shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE, "gfs2-qd");
+   if (!gfs2_qd_shrinker)
+   return -ENOMEM;
+
+   gfs2_qd_shrinker->count_objects = gfs2_qd_shrink_count;
+   gfs2_qd_shrinker->scan_objects = gfs2_qd_shrink_scan;
+   gfs2_qd_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(gfs2_qd_shrinker);
 
+   return 0;
+}
+
+void gfs2_qd_shrinker_exit(void)
+{
+   shrinker_free(gfs2_qd_shrinker);
+}
 
 static u64 qd2index(struct gfs2_quota_data *qd)
 {
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
index 21ada332d555..f0d54dcbbc75 100644
--- a/fs/gfs2/quota.h
+++ b/fs/gfs2/quota.h
@@ -59,7 +59,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip,
 }
 
 extern const struct quotactl_ops gfs2_quotactl_ops;
-extern struct shrinker gfs2_qd_shrinker;
+int __init gfs2_qd_shrinker_init(void);
+void gfs2_qd_shrinker_exit(void);
 extern struct list_lru gfs2_qd_lru;
 extern void __init gfs2_quota_hash_init(void);
 
-- 
2.30.2



[PATCH v3 14/49] NFSv4.2: dynamically allocate the nfs-xattr shrinkers

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the nfs-xattr shrinkers.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/nfs/nfs42xattr.c | 87 +++--
 1 file changed, 44 insertions(+), 43 deletions(-)

diff --git a/fs/nfs/nfs42xattr.c b/fs/nfs/nfs42xattr.c
index 911f634ba3da..2ad66a8922f4 100644
--- a/fs/nfs/nfs42xattr.c
+++ b/fs/nfs/nfs42xattr.c
@@ -796,28 +796,9 @@ static unsigned long nfs4_xattr_cache_scan(struct shrinker 
*shrink,
 static unsigned long nfs4_xattr_entry_scan(struct shrinker *shrink,
   struct shrink_control *sc);
 
-static struct shrinker nfs4_xattr_cache_shrinker = {
-   .count_objects  = nfs4_xattr_cache_count,
-   .scan_objects   = nfs4_xattr_cache_scan,
-   .seeks  = DEFAULT_SEEKS,
-   .flags  = SHRINKER_MEMCG_AWARE,
-};
-
-static struct shrinker nfs4_xattr_entry_shrinker = {
-   .count_objects  = nfs4_xattr_entry_count,
-   .scan_objects   = nfs4_xattr_entry_scan,
-   .seeks  = DEFAULT_SEEKS,
-   .batch  = 512,
-   .flags  = SHRINKER_MEMCG_AWARE,
-};
-
-static struct shrinker nfs4_xattr_large_entry_shrinker = {
-   .count_objects  = nfs4_xattr_entry_count,
-   .scan_objects   = nfs4_xattr_entry_scan,
-   .seeks  = 1,
-   .batch  = 512,
-   .flags  = SHRINKER_MEMCG_AWARE,
-};
+static struct shrinker *nfs4_xattr_cache_shrinker;
+static struct shrinker *nfs4_xattr_entry_shrinker;
+static struct shrinker *nfs4_xattr_large_entry_shrinker;
 
 static enum lru_status
 cache_lru_isolate(struct list_head *item,
@@ -943,7 +924,7 @@ nfs4_xattr_entry_scan(struct shrinker *shrink, struct 
shrink_control *sc)
struct nfs4_xattr_entry *entry;
struct list_lru *lru;
 
-   lru = (shrink == &nfs4_xattr_large_entry_shrinker) ?
+   lru = (shrink == nfs4_xattr_large_entry_shrinker) ?
&nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;
 
freed = list_lru_shrink_walk(lru, sc, entry_lru_isolate, &dispose);
@@ -971,7 +952,7 @@ nfs4_xattr_entry_count(struct shrinker *shrink, struct 
shrink_control *sc)
unsigned long count;
struct list_lru *lru;
 
-   lru = (shrink == &nfs4_xattr_large_entry_shrinker) ?
+   lru = (shrink == nfs4_xattr_large_entry_shrinker) ?
&nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;
 
count = list_lru_shrink_count(lru, sc);
@@ -991,18 +972,34 @@ static void nfs4_xattr_cache_init_once(void *p)
INIT_LIST_HEAD(&cache->dispose);
 }
 
-static int nfs4_xattr_shrinker_init(struct shrinker *shrinker,
-   struct list_lru *lru, const char *name)
+typedef unsigned long (*count_objects_cb)(struct shrinker *s,
+ struct shrink_control *sc);
+typedef unsigned long (*scan_objects_cb)(struct shrinker *s,
+struct shrink_control *sc);
+
+static int __init nfs4_xattr_shrinker_init(struct shrinker **shrinker,
+  struct list_lru *lru, const char 
*name,
+  count_objects_cb count,
+  scan_objects_cb scan, long batch, 
int seeks)
 {
-   int ret = 0;
+   int ret;
 
-   ret = register_shrinker(shrinker, name);
-   if (ret)
+   *shrinker = shrinker_alloc(SHRINKER_MEMCG_AWARE, name);
+   if (!*shrinker)
+   return -ENOMEM;
+
+   ret = list_lru_init_memcg(lru, *shrinker);
+   if (ret) {
+   shrinker_free(*shrinker);
return ret;
+   }
 
-   ret = list_lru_init_memcg(lru, shrinker);
-   if (ret)
-   unregister_shrinker(shrinker);
+   (*shrinker)->count_objects = count;
+   (*shrinker)->scan_objects = scan;
+   (*shrinker)->batch = batch;
+   (*shrinker)->seeks = seeks;
+
+   shrinker_register(*shrinker);
 
return ret;
 }
@@ -1010,7 +1007,7 @@ static int nfs4_xattr_shrinker_init(struct shrinker 
*shrinker,
 static void nfs4_xattr_shrinker_destroy(struct shrinker *shrinker,
struct list_lru *lru)
 {
-   unregister_shrinker(shrinker);
+   shrinker_free(shrinker);
list_lru_destroy(lru);
 }
 
@@ -1026,27 +1023,31 @@ int __init nfs4_xattr_cache_init(void)
return -ENOMEM;
 
ret = nfs4_xattr_shrinker_init(&nfs4_xattr_cache_shrinker,
-  &nfs4_xattr_cache_lru,
-  "nfs-xattr_cache");
+  &nfs4_xattr_cache_lru, "nfs-xattr_cache",
+  nfs4_xattr_cache_count,
+  nfs4_xattr_cache_scan, 0, DEFAULT_SEEKS);
if (ret)
goto out1;
 
ret = nfs4_xattr_shrinker_init(&nfs4_xattr_entry_shrinker,
-

[PATCH v3 15/49] nfs: dynamically allocate the nfs-acl shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the nfs-acl shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/nfs/super.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2284f749d892..072d82e1be06 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -129,11 +129,7 @@ static void nfs_ssc_unregister_ops(void)
 }
 #endif /* CONFIG_NFS_V4_2 */
 
-static struct shrinker acl_shrinker = {
-   .count_objects  = nfs_access_cache_count,
-   .scan_objects   = nfs_access_cache_scan,
-   .seeks  = DEFAULT_SEEKS,
-};
+static struct shrinker *acl_shrinker;
 
 /*
  * Register the NFS filesystems
@@ -153,9 +149,17 @@ int __init register_nfs_fs(void)
ret = nfs_register_sysctl();
if (ret < 0)
goto error_2;
-   ret = register_shrinker(&acl_shrinker, "nfs-acl");
-   if (ret < 0)
+
+   acl_shrinker = shrinker_alloc(0, "nfs-acl");
+   if (!acl_shrinker)
goto error_3;
+
+   acl_shrinker->count_objects = nfs_access_cache_count;
+   acl_shrinker->scan_objects = nfs_access_cache_scan;
+   acl_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(acl_shrinker);
+
 #ifdef CONFIG_NFS_V4_2
nfs_ssc_register_ops();
 #endif
@@ -175,7 +179,7 @@ int __init register_nfs_fs(void)
  */
 void __exit unregister_nfs_fs(void)
 {
-   unregister_shrinker(&acl_shrinker);
+   shrinker_free(acl_shrinker);
nfs_unregister_sysctl();
unregister_nfs4_fs();
 #ifdef CONFIG_NFS_V4_2
-- 
2.30.2



[PATCH v3 16/49] nfsd: dynamically allocate the nfsd-filecache shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the nfsd-filecache shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/nfsd/filecache.c | 22 --
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index ee9c923192e0..872eb9501965 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -521,11 +521,7 @@ nfsd_file_lru_scan(struct shrinker *s, struct 
shrink_control *sc)
return ret;
 }
 
-static struct shrinker nfsd_file_shrinker = {
-   .scan_objects = nfsd_file_lru_scan,
-   .count_objects = nfsd_file_lru_count,
-   .seeks = 1,
-};
+static struct shrinker *nfsd_file_shrinker;
 
 /**
  * nfsd_file_cond_queue - conditionally unhash and queue a nfsd_file
@@ -746,12 +742,18 @@ nfsd_file_cache_init(void)
goto out_err;
}
 
-   ret = register_shrinker(&nfsd_file_shrinker, "nfsd-filecache");
-   if (ret) {
-   pr_err("nfsd: failed to register nfsd_file_shrinker: %d\n", 
ret);
+   nfsd_file_shrinker = shrinker_alloc(0, "nfsd-filecache");
+   if (!nfsd_file_shrinker) {
+   pr_err("nfsd: failed to allocate nfsd_file_shrinker\n");
goto out_lru;
}
 
+   nfsd_file_shrinker->count_objects = nfsd_file_lru_count;
+   nfsd_file_shrinker->scan_objects = nfsd_file_lru_scan;
+   nfsd_file_shrinker->seeks = 1;
+
+   shrinker_register(nfsd_file_shrinker);
+
ret = lease_register_notifier(&nfsd_file_lease_notifier);
if (ret) {
pr_err("nfsd: unable to register lease notifier: %d\n", ret);
@@ -774,7 +776,7 @@ nfsd_file_cache_init(void)
 out_notifier:
lease_unregister_notifier(&nfsd_file_lease_notifier);
 out_shrinker:
-   unregister_shrinker(&nfsd_file_shrinker);
+   shrinker_free(nfsd_file_shrinker);
 out_lru:
list_lru_destroy(&nfsd_file_lru);
 out_err:
@@ -891,7 +893,7 @@ nfsd_file_cache_shutdown(void)
return;
 
lease_unregister_notifier(&nfsd_file_lease_notifier);
-   unregister_shrinker(&nfsd_file_shrinker);
+   shrinker_free(nfsd_file_shrinker);
/*
 * make sure all callers of nfsd_file_lru_cb are done before
 * calling nfsd_file_cache_purge
-- 
2.30.2



[PATCH v3 17/49] quota: dynamically allocate the dquota-cache shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the dquota-cache shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/quota/dquot.c | 18 ++
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index e8232242dd34..8883e6992f7c 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -791,12 +791,6 @@ dqcache_shrink_count(struct shrinker *shrink, struct 
shrink_control *sc)
percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]));
 }
 
-static struct shrinker dqcache_shrinker = {
-   .count_objects = dqcache_shrink_count,
-   .scan_objects = dqcache_shrink_scan,
-   .seeks = DEFAULT_SEEKS,
-};
-
 /*
  * Safely release dquot and put reference to dquot.
  */
@@ -2957,6 +2951,7 @@ static int __init dquot_init(void)
 {
int i, ret;
unsigned long nr_hash, order;
+   struct shrinker *dqcache_shrinker;
 
printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__);
 
@@ -2991,8 +2986,15 @@ static int __init dquot_init(void)
pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld,"
" %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order));
 
-   if (register_shrinker(&dqcache_shrinker, "dquota-cache"))
-   panic("Cannot register dquot shrinker");
+   dqcache_shrinker = shrinker_alloc(0, "dquota-cache");
+   if (!dqcache_shrinker)
+   panic("Cannot allocate dquot shrinker");
+
+   dqcache_shrinker->count_objects = dqcache_shrink_count;
+   dqcache_shrinker->scan_objects = dqcache_shrink_scan;
+   dqcache_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(dqcache_shrinker);
 
return 0;
 }
-- 
2.30.2



[PATCH v3 18/49] ubifs: dynamically allocate the ubifs-slab shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the ubifs-slab shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/ubifs/super.c | 22 --
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b08fb28d16b5..c690782388a8 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -54,11 +54,7 @@ module_param_cb(default_version, &ubifs_default_version_ops, 
&ubifs_default_vers
 static struct kmem_cache *ubifs_inode_slab;
 
 /* UBIFS TNC shrinker description */
-static struct shrinker ubifs_shrinker_info = {
-   .scan_objects = ubifs_shrink_scan,
-   .count_objects = ubifs_shrink_count,
-   .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *ubifs_shrinker_info;
 
 /**
  * validate_inode - validate inode.
@@ -2373,7 +2369,7 @@ static void inode_slab_ctor(void *obj)
 
 static int __init ubifs_init(void)
 {
-   int err;
+   int err = -ENOMEM;
 
BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24);
 
@@ -2439,10 +2435,16 @@ static int __init ubifs_init(void)
if (!ubifs_inode_slab)
return -ENOMEM;
 
-   err = register_shrinker(&ubifs_shrinker_info, "ubifs-slab");
-   if (err)
+   ubifs_shrinker_info = shrinker_alloc(0, "ubifs-slab");
+   if (!ubifs_shrinker_info)
goto out_slab;
 
+   ubifs_shrinker_info->count_objects = ubifs_shrink_count;
+   ubifs_shrinker_info->scan_objects = ubifs_shrink_scan;
+   ubifs_shrinker_info->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(ubifs_shrinker_info);
+
err = ubifs_compressors_init();
if (err)
goto out_shrinker;
@@ -2467,7 +2469,7 @@ static int __init ubifs_init(void)
dbg_debugfs_exit();
ubifs_compressors_exit();
 out_shrinker:
-   unregister_shrinker(&ubifs_shrinker_info);
+   shrinker_free(ubifs_shrinker_info);
 out_slab:
kmem_cache_destroy(ubifs_inode_slab);
return err;
@@ -2483,7 +2485,7 @@ static void __exit ubifs_exit(void)
dbg_debugfs_exit();
ubifs_sysfs_exit();
ubifs_compressors_exit();
-   unregister_shrinker(&ubifs_shrinker_info);
+   shrinker_free(ubifs_shrinker_info);
 
/*
 * Make sure all delayed rcu free inodes are flushed before we
-- 
2.30.2



[PATCH v3 19/49] rcu: dynamically allocate the rcu-lazy shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the rcu-lazy shrinker.

Signed-off-by: Qi Zheng 
---
 kernel/rcu/tree_nocb.h | 20 +++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/kernel/rcu/tree_nocb.h b/kernel/rcu/tree_nocb.h
index 5598212d1f27..e1c59c33738a 100644
--- a/kernel/rcu/tree_nocb.h
+++ b/kernel/rcu/tree_nocb.h
@@ -1396,13 +1396,6 @@ lazy_rcu_shrink_scan(struct shrinker *shrink, struct 
shrink_control *sc)
 
return count ? count : SHRINK_STOP;
 }
-
-static struct shrinker lazy_rcu_shrinker = {
-   .count_objects = lazy_rcu_shrink_count,
-   .scan_objects = lazy_rcu_shrink_scan,
-   .batch = 0,
-   .seeks = DEFAULT_SEEKS,
-};
 #endif // #ifdef CONFIG_RCU_LAZY
 
 void __init rcu_init_nohz(void)
@@ -1410,6 +1403,7 @@ void __init rcu_init_nohz(void)
int cpu;
struct rcu_data *rdp;
const struct cpumask *cpumask = NULL;
+   struct shrinker * __maybe_unused lazy_rcu_shrinker;
 
 #if defined(CONFIG_NO_HZ_FULL)
if (tick_nohz_full_running && !cpumask_empty(tick_nohz_full_mask))
@@ -1436,8 +1430,16 @@ void __init rcu_init_nohz(void)
return;
 
 #ifdef CONFIG_RCU_LAZY
-   if (register_shrinker(&lazy_rcu_shrinker, "rcu-lazy"))
-   pr_err("Failed to register lazy_rcu shrinker!\n");
+   lazy_rcu_shrinker = shrinker_alloc(0, "rcu-lazy");
+   if (!lazy_rcu_shrinker) {
+   pr_err("Failed to allocate lazy_rcu shrinker!\n");
+   } else {
+   lazy_rcu_shrinker->count_objects = lazy_rcu_shrink_count;
+   lazy_rcu_shrinker->scan_objects = lazy_rcu_shrink_scan;
+   lazy_rcu_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(lazy_rcu_shrinker);
+   }
 #endif // #ifdef CONFIG_RCU_LAZY
 
if (!cpumask_subset(rcu_nocb_mask, cpu_possible_mask)) {
-- 
2.30.2



[PATCH v3 20/49] rcu: dynamically allocate the rcu-kfree shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the rcu-kfree shrinker.

Signed-off-by: Qi Zheng 
---
 kernel/rcu/tree.c | 22 +-
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index cb1caefa8bd0..6d2f82f79c65 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -3449,13 +3449,6 @@ kfree_rcu_shrink_scan(struct shrinker *shrink, struct 
shrink_control *sc)
return freed == 0 ? SHRINK_STOP : freed;
 }
 
-static struct shrinker kfree_rcu_shrinker = {
-   .count_objects = kfree_rcu_shrink_count,
-   .scan_objects = kfree_rcu_shrink_scan,
-   .batch = 0,
-   .seeks = DEFAULT_SEEKS,
-};
-
 void __init kfree_rcu_scheduler_running(void)
 {
int cpu;
@@ -4931,6 +4924,7 @@ static void __init kfree_rcu_batch_init(void)
 {
int cpu;
int i, j;
+   struct shrinker *kfree_rcu_shrinker;
 
/* Clamp it to [0:100] seconds interval. */
if (rcu_delay_page_cache_fill_msec < 0 ||
@@ -4962,8 +4956,18 @@ static void __init kfree_rcu_batch_init(void)
INIT_DELAYED_WORK(&krcp->page_cache_work, fill_page_cache_func);
krcp->initialized = true;
}
-   if (register_shrinker(&kfree_rcu_shrinker, "rcu-kfree"))
-   pr_err("Failed to register kfree_rcu() shrinker!\n");
+
+   kfree_rcu_shrinker = shrinker_alloc(0, "rcu-kfree");
+   if (!kfree_rcu_shrinker) {
+   pr_err("Failed to allocate kfree_rcu() shrinker!\n");
+   return;
+   }
+
+   kfree_rcu_shrinker->count_objects = kfree_rcu_shrink_count;
+   kfree_rcu_shrinker->scan_objects = kfree_rcu_shrink_scan;
+   kfree_rcu_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(kfree_rcu_shrinker);
 }
 
 void __init rcu_init(void)
-- 
2.30.2



[PATCH v3 21/49] mm: thp: dynamically allocate the thp-related shrinkers

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the thp-zero and thp-deferred_split
shrinkers.

Signed-off-by: Qi Zheng 
---
 mm/huge_memory.c | 69 +++-
 1 file changed, 45 insertions(+), 24 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e371503f7746..a0dbb55b4913 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -65,7 +65,11 @@ unsigned long transparent_hugepage_flags __read_mostly =
(1scan_objects = shrink_huge_zero_page_scan;
+   huge_zero_page_shrinker->seeks = DEFAULT_SEEKS;
+   shrinker_register(huge_zero_page_shrinker);
+
+   deferred_split_shrinker->count_objects = deferred_split_count;
+   deferred_split_shrinker->scan_objects = deferred_split_scan;
+   deferred_split_shrinker->seeks = DEFAULT_SEEKS;
+   shrinker_register(deferred_split_shrinker);
+
+   return 0;
+}
+
+static void __init thp_shrinker_exit(void)
+{
+   shrinker_free(huge_zero_page_shrinker);
+   shrinker_free(deferred_split_shrinker);
+}
+
 static int __init hugepage_init(void)
 {
int err;
@@ -482,12 +516,9 @@ static int __init hugepage_init(void)
if (err)
goto err_slab;
 
-   err = register_shrinker(&huge_zero_page_shrinker, "thp-zero");
-   if (err)
-   goto err_hzp_shrinker;
-   err = register_shrinker(&deferred_split_shrinker, "thp-deferred_split");
+   err = thp_shrinker_init();
if (err)
-   goto err_split_shrinker;
+   goto err_shrinker;
 
/*
 * By default disable transparent hugepages on smaller systems,
@@ -505,10 +536,8 @@ static int __init hugepage_init(void)
 
return 0;
 err_khugepaged:
-   unregister_shrinker(&deferred_split_shrinker);
-err_split_shrinker:
-   unregister_shrinker(&huge_zero_page_shrinker);
-err_hzp_shrinker:
+   thp_shrinker_exit();
+err_shrinker:
khugepaged_destroy();
 err_slab:
hugepage_exit_sysfs(hugepage_kobj);
@@ -2833,7 +2862,7 @@ void deferred_split_folio(struct folio *folio)
 #ifdef CONFIG_MEMCG
if (memcg)
set_shrinker_bit(memcg, folio_nid(folio),
-deferred_split_shrinker.id);
+deferred_split_shrinker->id);
 #endif
}
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
@@ -2907,14 +2936,6 @@ static unsigned long deferred_split_scan(struct shrinker 
*shrink,
return split;
 }
 
-static struct shrinker deferred_split_shrinker = {
-   .count_objects = deferred_split_count,
-   .scan_objects = deferred_split_scan,
-   .seeks = DEFAULT_SEEKS,
-   .flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE |
-SHRINKER_NONSLAB,
-};
-
 #ifdef CONFIG_DEBUG_FS
 static void split_huge_pages_all(void)
 {
-- 
2.30.2



[PATCH v3 22/49] sunrpc: dynamically allocate the sunrpc_cred shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the sunrpc_cred shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 net/sunrpc/auth.c | 19 +++
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 2f16f9d17966..6b898b1be6f5 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -861,11 +861,7 @@ rpcauth_uptodatecred(struct rpc_task *task)
test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
 }
 
-static struct shrinker rpc_cred_shrinker = {
-   .count_objects = rpcauth_cache_shrink_count,
-   .scan_objects = rpcauth_cache_shrink_scan,
-   .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *rpc_cred_shrinker;
 
 int __init rpcauth_init_module(void)
 {
@@ -874,9 +870,16 @@ int __init rpcauth_init_module(void)
err = rpc_init_authunix();
if (err < 0)
goto out1;
-   err = register_shrinker(&rpc_cred_shrinker, "sunrpc_cred");
-   if (err < 0)
+   rpc_cred_shrinker = shrinker_alloc(0, "sunrpc_cred");
+   if (!rpc_cred_shrinker)
goto out2;
+
+   rpc_cred_shrinker->count_objects = rpcauth_cache_shrink_count;
+   rpc_cred_shrinker->scan_objects = rpcauth_cache_shrink_scan;
+   rpc_cred_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(rpc_cred_shrinker);
+
return 0;
 out2:
rpc_destroy_authunix();
@@ -887,5 +890,5 @@ int __init rpcauth_init_module(void)
 void rpcauth_remove_module(void)
 {
rpc_destroy_authunix();
-   unregister_shrinker(&rpc_cred_shrinker);
+   shrinker_free(rpc_cred_shrinker);
 }
-- 
2.30.2



[PATCH v3 23/49] mm: workingset: dynamically allocate the mm-shadow shrinker

2023-07-27 Thread Qi Zheng
Use new APIs to dynamically allocate the mm-shadow shrinker.

Signed-off-by: Qi Zheng 
---
 mm/workingset.c | 27 ++-
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/mm/workingset.c b/mm/workingset.c
index da58a26d0d4d..3c53138903a7 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -763,13 +763,6 @@ static unsigned long scan_shadow_nodes(struct shrinker 
*shrinker,
NULL);
 }
 
-static struct shrinker workingset_shadow_shrinker = {
-   .count_objects = count_shadow_nodes,
-   .scan_objects = scan_shadow_nodes,
-   .seeks = 0, /* ->count reports only fully expendable nodes */
-   .flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE,
-};
-
 /*
  * Our list_lru->lock is IRQ-safe as it nests inside the IRQ-safe
  * i_pages lock.
@@ -778,9 +771,10 @@ static struct lock_class_key shadow_nodes_key;
 
 static int __init workingset_init(void)
 {
+   struct shrinker *workingset_shadow_shrinker;
unsigned int timestamp_bits;
unsigned int max_order;
-   int ret;
+   int ret = -ENOMEM;
 
BUILD_BUG_ON(BITS_PER_LONG < EVICTION_SHIFT);
/*
@@ -797,17 +791,24 @@ static int __init workingset_init(void)
pr_info("workingset: timestamp_bits=%d max_order=%d bucket_order=%u\n",
   timestamp_bits, max_order, bucket_order);
 
-   ret = prealloc_shrinker(&workingset_shadow_shrinker, "mm-shadow");
-   if (ret)
+   workingset_shadow_shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE |
+   SHRINKER_MEMCG_AWARE,
+   "mm-shadow");
+   if (!workingset_shadow_shrinker)
goto err;
+
ret = __list_lru_init(&shadow_nodes, true, &shadow_nodes_key,
- &workingset_shadow_shrinker);
+ workingset_shadow_shrinker);
if (ret)
goto err_list_lru;
-   register_shrinker_prepared(&workingset_shadow_shrinker);
+
+   workingset_shadow_shrinker->count_objects = count_shadow_nodes;
+   workingset_shadow_shrinker->scan_objects = scan_shadow_nodes;
+
+   shrinker_register(workingset_shadow_shrinker);
return 0;
 err_list_lru:
-   free_prealloced_shrinker(&workingset_shadow_shrinker);
+   shrinker_free(workingset_shadow_shrinker);
 err:
return ret;
 }
-- 
2.30.2



[PATCH v3 24/49] drm/i915: dynamically allocate the i915_gem_mm shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the i915_gem_mm shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct drm_i915_private.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 30 +++-
 drivers/gpu/drm/i915/i915_drv.h  |  2 +-
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c 
b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
index 214763942aa2..4504eb4f31d5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
@@ -284,8 +284,7 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private 
*i915)
 static unsigned long
 i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
 {
-   struct drm_i915_private *i915 =
-   container_of(shrinker, struct drm_i915_private, mm.shrinker);
+   struct drm_i915_private *i915 = shrinker->private_data;
unsigned long num_objects;
unsigned long count;
 
@@ -302,8 +301,8 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct 
shrink_control *sc)
if (num_objects) {
unsigned long avg = 2 * count / num_objects;
 
-   i915->mm.shrinker.batch =
-   max((i915->mm.shrinker.batch + avg) >> 1,
+   i915->mm.shrinker->batch =
+   max((i915->mm.shrinker->batch + avg) >> 1,
128ul /* default SHRINK_BATCH */);
}
 
@@ -313,8 +312,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct 
shrink_control *sc)
 static unsigned long
 i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
 {
-   struct drm_i915_private *i915 =
-   container_of(shrinker, struct drm_i915_private, mm.shrinker);
+   struct drm_i915_private *i915 = shrinker->private_data;
unsigned long freed;
 
sc->nr_scanned = 0;
@@ -422,12 +420,18 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, 
unsigned long event, void *ptr
 
 void i915_gem_driver_register__shrinker(struct drm_i915_private *i915)
 {
-   i915->mm.shrinker.scan_objects = i915_gem_shrinker_scan;
-   i915->mm.shrinker.count_objects = i915_gem_shrinker_count;
-   i915->mm.shrinker.seeks = DEFAULT_SEEKS;
-   i915->mm.shrinker.batch = 4096;
-   drm_WARN_ON(&i915->drm, register_shrinker(&i915->mm.shrinker,
- "drm-i915_gem"));
+   i915->mm.shrinker = shrinker_alloc(0, "drm-i915_gem");
+   if (!i915->mm.shrinker) {
+   drm_WARN_ON(&i915->drm, 1);
+   } else {
+   i915->mm.shrinker->scan_objects = i915_gem_shrinker_scan;
+   i915->mm.shrinker->count_objects = i915_gem_shrinker_count;
+   i915->mm.shrinker->seeks = DEFAULT_SEEKS;
+   i915->mm.shrinker->batch = 4096;
+   i915->mm.shrinker->private_data = i915;
+
+   shrinker_register(i915->mm.shrinker);
+   }
 
i915->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
drm_WARN_ON(&i915->drm, register_oom_notifier(&i915->mm.oom_notifier));
@@ -443,7 +447,7 @@ void i915_gem_driver_unregister__shrinker(struct 
drm_i915_private *i915)
unregister_vmap_purge_notifier(&i915->mm.vmap_notifier));
drm_WARN_ON(&i915->drm,
unregister_oom_notifier(&i915->mm.oom_notifier));
-   unregister_shrinker(&i915->mm.shrinker);
+   shrinker_free(i915->mm.shrinker);
 }
 
 void i915_gem_shrinker_taints_mutex(struct drm_i915_private *i915,
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 682ef2b5c7d5..389e8bf140d7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -163,7 +163,7 @@ struct i915_gem_mm {
 
struct notifier_block oom_notifier;
struct notifier_block vmap_notifier;
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
 
 #ifdef CONFIG_MMU_NOTIFIER
/**
-- 
2.30.2



[PATCH v3 25/49] drm/msm: dynamically allocate the drm-msm_gem shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the drm-msm_gem shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct msm_drm_private.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/gpu/drm/msm/msm_drv.c  |  4 ++-
 drivers/gpu/drm/msm/msm_drv.h  |  4 +--
 drivers/gpu/drm/msm/msm_gem_shrinker.c | 34 --
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 4bd028fa7500..7f20249d6071 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -462,7 +462,9 @@ static int msm_drm_init(struct device *dev, const struct 
drm_driver *drv)
if (ret)
goto err_msm_uninit;
 
-   msm_gem_shrinker_init(ddev);
+   ret = msm_gem_shrinker_init(ddev);
+   if (ret)
+   goto err_msm_uninit;
 
if (priv->kms_init) {
ret = priv->kms_init(ddev);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 02fd6c7d0bb7..e2fc56f161b5 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -221,7 +221,7 @@ struct msm_drm_private {
} vram;
 
struct notifier_block vmap_notifier;
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
 
struct drm_atomic_state *pm_state;
 
@@ -283,7 +283,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 unsigned long msm_gem_shrinker_shrink(struct drm_device *dev, unsigned long 
nr_to_scan);
 #endif
 
-void msm_gem_shrinker_init(struct drm_device *dev);
+int msm_gem_shrinker_init(struct drm_device *dev);
 void msm_gem_shrinker_cleanup(struct drm_device *dev);
 
 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c 
b/drivers/gpu/drm/msm/msm_gem_shrinker.c
index f38296ad8743..2063e4f8 100644
--- a/drivers/gpu/drm/msm/msm_gem_shrinker.c
+++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c
@@ -34,8 +34,7 @@ static bool can_block(struct shrink_control *sc)
 static unsigned long
 msm_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
 {
-   struct msm_drm_private *priv =
-   container_of(shrinker, struct msm_drm_private, shrinker);
+   struct msm_drm_private *priv = shrinker->private_data;
unsigned count = priv->lru.dontneed.count;
 
if (can_swap())
@@ -100,8 +99,7 @@ active_evict(struct drm_gem_object *obj)
 static unsigned long
 msm_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
 {
-   struct msm_drm_private *priv =
-   container_of(shrinker, struct msm_drm_private, shrinker);
+   struct msm_drm_private *priv = shrinker->private_data;
struct {
struct drm_gem_lru *lru;
bool (*shrink)(struct drm_gem_object *obj);
@@ -148,10 +146,11 @@ msm_gem_shrinker_shrink(struct drm_device *dev, unsigned 
long nr_to_scan)
struct shrink_control sc = {
.nr_to_scan = nr_to_scan,
};
-   int ret;
+   unsigned long ret = SHRINK_STOP;
 
fs_reclaim_acquire(GFP_KERNEL);
-   ret = msm_gem_shrinker_scan(&priv->shrinker, &sc);
+   if (priv->shrinker)
+   ret = msm_gem_shrinker_scan(priv->shrinker, &sc);
fs_reclaim_release(GFP_KERNEL);
 
return ret;
@@ -210,16 +209,25 @@ msm_gem_shrinker_vmap(struct notifier_block *nb, unsigned 
long event, void *ptr)
  *
  * This function registers and sets up the msm shrinker.
  */
-void msm_gem_shrinker_init(struct drm_device *dev)
+int msm_gem_shrinker_init(struct drm_device *dev)
 {
struct msm_drm_private *priv = dev->dev_private;
-   priv->shrinker.count_objects = msm_gem_shrinker_count;
-   priv->shrinker.scan_objects = msm_gem_shrinker_scan;
-   priv->shrinker.seeks = DEFAULT_SEEKS;
-   WARN_ON(register_shrinker(&priv->shrinker, "drm-msm_gem"));
+
+   priv->shrinker = shrinker_alloc(0, "drm-msm_gem");
+   if (!priv->shrinker)
+   return -ENOMEM;
+
+   priv->shrinker->count_objects = msm_gem_shrinker_count;
+   priv->shrinker->scan_objects = msm_gem_shrinker_scan;
+   priv->shrinker->seeks = DEFAULT_SEEKS;
+   priv->shrinker->private_data = priv;
+
+   shrinker_register(priv->shrinker);
 
priv->vmap_notifier.notifier_call = msm_gem_shrinker_vmap;
WARN_ON(register_vmap_purge_notifier(&priv->vmap_notifier));
+
+   return 0;
 }
 
 /**
@@ -232,8 +240,8 @@ void msm_gem_shrinker_cleanup(struct drm_device *dev)
 {
struct msm_drm_private *priv = dev->dev_private;
 
-   if (priv->shrinker.nr_deferred) {
+   if (priv->shrinker) {
WARN_ON(unregister_vmap_purge_notifier(&priv->vmap_notifier));
-   unregister_shrinker(&priv

[PATCH v3 26/49] drm/panfrost: dynamically allocate the drm-panfrost shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the drm-panfrost shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct panfrost_device.

Signed-off-by: Qi Zheng 
Reviewed-by: Steven Price 
---
 drivers/gpu/drm/panfrost/panfrost_device.h|  2 +-
 drivers/gpu/drm/panfrost/panfrost_drv.c   |  6 +++-
 drivers/gpu/drm/panfrost/panfrost_gem.h   |  2 +-
 .../gpu/drm/panfrost/panfrost_gem_shrinker.c  | 30 +++
 4 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h 
b/drivers/gpu/drm/panfrost/panfrost_device.h
index b0126b9fbadc..e667e5689353 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -118,7 +118,7 @@ struct panfrost_device {
 
struct mutex shrinker_lock;
struct list_head shrinker_list;
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
 
struct panfrost_devfreq pfdevfreq;
 };
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c 
b/drivers/gpu/drm/panfrost/panfrost_drv.c
index a2ab99698ca8..e1d0e3a23757 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -601,10 +601,14 @@ static int panfrost_probe(struct platform_device *pdev)
if (err < 0)
goto err_out1;
 
-   panfrost_gem_shrinker_init(ddev);
+   err = panfrost_gem_shrinker_init(ddev);
+   if (err)
+   goto err_out2;
 
return 0;
 
+err_out2:
+   drm_dev_unregister(ddev);
 err_out1:
pm_runtime_disable(pfdev->dev);
panfrost_device_fini(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h 
b/drivers/gpu/drm/panfrost/panfrost_gem.h
index ad2877eeeccd..863d2ec8d4f0 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -81,7 +81,7 @@ panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
 void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping);
 void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo);
 
-void panfrost_gem_shrinker_init(struct drm_device *dev);
+int panfrost_gem_shrinker_init(struct drm_device *dev);
 void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
 
 #endif /* __PANFROST_GEM_H__ */
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c 
b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index 6a71a2555f85..3dfe2b7ccdd9 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -18,8 +18,7 @@
 static unsigned long
 panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control 
*sc)
 {
-   struct panfrost_device *pfdev =
-   container_of(shrinker, struct panfrost_device, shrinker);
+   struct panfrost_device *pfdev = shrinker->private_data;
struct drm_gem_shmem_object *shmem;
unsigned long count = 0;
 
@@ -65,8 +64,7 @@ static bool panfrost_gem_purge(struct drm_gem_object *obj)
 static unsigned long
 panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control 
*sc)
 {
-   struct panfrost_device *pfdev =
-   container_of(shrinker, struct panfrost_device, shrinker);
+   struct panfrost_device *pfdev = shrinker->private_data;
struct drm_gem_shmem_object *shmem, *tmp;
unsigned long freed = 0;
 
@@ -97,13 +95,22 @@ panfrost_gem_shrinker_scan(struct shrinker *shrinker, 
struct shrink_control *sc)
  *
  * This function registers and sets up the panfrost shrinker.
  */
-void panfrost_gem_shrinker_init(struct drm_device *dev)
+int panfrost_gem_shrinker_init(struct drm_device *dev)
 {
struct panfrost_device *pfdev = dev->dev_private;
-   pfdev->shrinker.count_objects = panfrost_gem_shrinker_count;
-   pfdev->shrinker.scan_objects = panfrost_gem_shrinker_scan;
-   pfdev->shrinker.seeks = DEFAULT_SEEKS;
-   WARN_ON(register_shrinker(&pfdev->shrinker, "drm-panfrost"));
+
+   pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");
+   if (!pfdev->shrinker)
+   return -ENOMEM;
+
+   pfdev->shrinker->count_objects = panfrost_gem_shrinker_count;
+   pfdev->shrinker->scan_objects = panfrost_gem_shrinker_scan;
+   pfdev->shrinker->seeks = DEFAULT_SEEKS;
+   pfdev->shrinker->private_data = pfdev;
+
+   shrinker_register(pfdev->shrinker);
+
+   return 0;
 }
 
 /**
@@ -116,7 +123,6 @@ void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
 {
struct panfrost_device *pfdev = dev->dev_private;
 
-   if (pfdev->shrinker.nr_deferred) {
-   unregister_shrinker(&pfdev->shrinker);
-   }
+   if (pfdev->shrinker)
+   shrinker_free(pfdev->shrinker);
 }
-- 
2.30.2



[PATCH v3 27/49] dm: dynamically allocate the dm-bufio shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the dm-bufio shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct dm_bufio_client.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/md/dm-bufio.c | 26 +++---
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index bc309e41d074..5a9124b83d53 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -963,7 +963,7 @@ struct dm_bufio_client {
 
sector_t start;
 
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
struct work_struct shrink_work;
atomic_long_t need_shrink;
 
@@ -2368,7 +2368,7 @@ static unsigned long dm_bufio_shrink_scan(struct shrinker 
*shrink, struct shrink
 {
struct dm_bufio_client *c;
 
-   c = container_of(shrink, struct dm_bufio_client, shrinker);
+   c = shrink->private_data;
atomic_long_add(sc->nr_to_scan, &c->need_shrink);
queue_work(dm_bufio_wq, &c->shrink_work);
 
@@ -2377,7 +2377,7 @@ static unsigned long dm_bufio_shrink_scan(struct shrinker 
*shrink, struct shrink
 
 static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct 
shrink_control *sc)
 {
-   struct dm_bufio_client *c = container_of(shrink, struct 
dm_bufio_client, shrinker);
+   struct dm_bufio_client *c = shrink->private_data;
unsigned long count = cache_total(&c->cache);
unsigned long retain_target = get_retain_buffers(c);
unsigned long queued_for_cleanup = atomic_long_read(&c->need_shrink);
@@ -2490,15 +2490,19 @@ struct dm_bufio_client *dm_bufio_client_create(struct 
block_device *bdev, unsign
INIT_WORK(&c->shrink_work, shrink_work);
atomic_long_set(&c->need_shrink, 0);
 
-   c->shrinker.count_objects = dm_bufio_shrink_count;
-   c->shrinker.scan_objects = dm_bufio_shrink_scan;
-   c->shrinker.seeks = 1;
-   c->shrinker.batch = 0;
-   r = register_shrinker(&c->shrinker, "dm-bufio:(%u:%u)",
- MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-   if (r)
+   c->shrinker = shrinker_alloc(0, "dm-bufio:(%u:%u)",
+MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
+   if (!c->shrinker)
goto bad;
 
+   c->shrinker->count_objects = dm_bufio_shrink_count;
+   c->shrinker->scan_objects = dm_bufio_shrink_scan;
+   c->shrinker->seeks = 1;
+   c->shrinker->batch = 0;
+   c->shrinker->private_data = c;
+
+   shrinker_register(c->shrinker);
+
mutex_lock(&dm_bufio_clients_lock);
dm_bufio_client_count++;
list_add(&c->client_list, &dm_bufio_all_clients);
@@ -2537,7 +2541,7 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
 
drop_buffers(c);
 
-   unregister_shrinker(&c->shrinker);
+   shrinker_free(c->shrinker);
flush_work(&c->shrink_work);
 
mutex_lock(&dm_bufio_clients_lock);
-- 
2.30.2



Re: [PATCH] drm/ttm: check null pointer before accessing when swapping

2023-07-27 Thread Christian König

Am 27.07.23 um 09:39 schrieb Mikhail Gavrilov:

On Thu, Jul 27, 2023 at 12:33 PM Chen, Guchun  wrote:

Reviewed-by: Christian König 

Has this already been pushed to drm-misc-next?

Thanks,
Christian.

Not yet, Christian, as I don't have push permission. I saw you were on 
vacation, so I would expect to ping you to push after you are back with full 
recharge.

I expect to see it in drm-fixes-6.5 cause the problem appeared during
the 6.5 release cycle.


Good point. The patch introducing the problem had a CC: stable tag as well.

So I've added the appropriate tags and pushed it to drm-misc-fixes.

Thanks,
Christian.


And yes, I follow all pull requests. This patch was not included in
yesterday's pull request :(




[PATCH v3 28/49] dm zoned: dynamically allocate the dm-zoned-meta shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the dm-zoned-meta shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct dmz_metadata.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/md/dm-zoned-metadata.c | 28 
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index 9d3cca8e3dc9..0bcb26a43578 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -187,7 +187,7 @@ struct dmz_metadata {
struct rb_root  mblk_rbtree;
struct list_headmblk_lru_list;
struct list_headmblk_dirty_list;
-   struct shrinker mblk_shrinker;
+   struct shrinker *mblk_shrinker;
 
/* Zone allocation management */
struct mutexmap_lock;
@@ -615,7 +615,7 @@ static unsigned long dmz_shrink_mblock_cache(struct 
dmz_metadata *zmd,
 static unsigned long dmz_mblock_shrinker_count(struct shrinker *shrink,
   struct shrink_control *sc)
 {
-   struct dmz_metadata *zmd = container_of(shrink, struct dmz_metadata, 
mblk_shrinker);
+   struct dmz_metadata *zmd = shrink->private_data;
 
return atomic_read(&zmd->nr_mblks);
 }
@@ -626,7 +626,7 @@ static unsigned long dmz_mblock_shrinker_count(struct 
shrinker *shrink,
 static unsigned long dmz_mblock_shrinker_scan(struct shrinker *shrink,
  struct shrink_control *sc)
 {
-   struct dmz_metadata *zmd = container_of(shrink, struct dmz_metadata, 
mblk_shrinker);
+   struct dmz_metadata *zmd = shrink->private_data;
unsigned long count;
 
spin_lock(&zmd->mblk_lock);
@@ -2936,19 +2936,23 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
 */
zmd->min_nr_mblks = 2 + zmd->nr_map_blocks + zmd->zone_nr_bitmap_blocks 
* 16;
zmd->max_nr_mblks = zmd->min_nr_mblks + 512;
-   zmd->mblk_shrinker.count_objects = dmz_mblock_shrinker_count;
-   zmd->mblk_shrinker.scan_objects = dmz_mblock_shrinker_scan;
-   zmd->mblk_shrinker.seeks = DEFAULT_SEEKS;
 
/* Metadata cache shrinker */
-   ret = register_shrinker(&zmd->mblk_shrinker, "dm-zoned-meta:(%u:%u)",
-   MAJOR(dev->bdev->bd_dev),
-   MINOR(dev->bdev->bd_dev));
-   if (ret) {
-   dmz_zmd_err(zmd, "Register metadata cache shrinker failed");
+   zmd->mblk_shrinker = shrinker_alloc(0,  "dm-zoned-meta:(%u:%u)",
+   MAJOR(dev->bdev->bd_dev),
+   MINOR(dev->bdev->bd_dev));
+   if (!zmd->mblk_shrinker) {
+   dmz_zmd_err(zmd, "Allocate metadata cache shrinker failed");
goto err;
}
 
+   zmd->mblk_shrinker->count_objects = dmz_mblock_shrinker_count;
+   zmd->mblk_shrinker->scan_objects = dmz_mblock_shrinker_scan;
+   zmd->mblk_shrinker->seeks = DEFAULT_SEEKS;
+   zmd->mblk_shrinker->private_data = zmd;
+
+   shrinker_register(zmd->mblk_shrinker);
+
dmz_zmd_info(zmd, "DM-Zoned metadata version %d", zmd->sb_version);
for (i = 0; i < zmd->nr_devs; i++)
dmz_print_dev(zmd, i);
@@ -2995,7 +2999,7 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
  */
 void dmz_dtr_metadata(struct dmz_metadata *zmd)
 {
-   unregister_shrinker(&zmd->mblk_shrinker);
+   shrinker_free(zmd->mblk_shrinker);
dmz_cleanup_metadata(zmd);
kfree(zmd);
 }
-- 
2.30.2



[PATCH v3 29/49] md/raid5: dynamically allocate the md-raid5 shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the md-raid5 shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct r5conf.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/md/raid5.c | 25 ++---
 drivers/md/raid5.h |  2 +-
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 85b3004594e0..fbb4e6f5ff43 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -7414,7 +7414,7 @@ static void free_conf(struct r5conf *conf)
 
log_exit(conf);
 
-   unregister_shrinker(&conf->shrinker);
+   shrinker_free(conf->shrinker);
free_thread_groups(conf);
shrink_stripes(conf);
raid5_free_percpu(conf);
@@ -7462,7 +7462,7 @@ static int raid5_alloc_percpu(struct r5conf *conf)
 static unsigned long raid5_cache_scan(struct shrinker *shrink,
  struct shrink_control *sc)
 {
-   struct r5conf *conf = container_of(shrink, struct r5conf, shrinker);
+   struct r5conf *conf = shrink->private_data;
unsigned long ret = SHRINK_STOP;
 
if (mutex_trylock(&conf->cache_size_mutex)) {
@@ -7483,7 +7483,7 @@ static unsigned long raid5_cache_scan(struct shrinker 
*shrink,
 static unsigned long raid5_cache_count(struct shrinker *shrink,
   struct shrink_control *sc)
 {
-   struct r5conf *conf = container_of(shrink, struct r5conf, shrinker);
+   struct r5conf *conf = shrink->private_data;
 
if (conf->max_nr_stripes < conf->min_nr_stripes)
/* unlikely, but not impossible */
@@ -7718,18 +7718,21 @@ static struct r5conf *setup_conf(struct mddev *mddev)
 * it reduces the queue depth and so can hurt throughput.
 * So set it rather large, scaled by number of devices.
 */
-   conf->shrinker.seeks = DEFAULT_SEEKS * conf->raid_disks * 4;
-   conf->shrinker.scan_objects = raid5_cache_scan;
-   conf->shrinker.count_objects = raid5_cache_count;
-   conf->shrinker.batch = 128;
-   conf->shrinker.flags = 0;
-   ret = register_shrinker(&conf->shrinker, "md-raid5:%s", mdname(mddev));
-   if (ret) {
-   pr_warn("md/raid:%s: couldn't register shrinker.\n",
+   conf->shrinker = shrinker_alloc(0, "md-raid5:%s", mdname(mddev));
+   if (!conf->shrinker) {
+   pr_warn("md/raid:%s: couldn't allocate shrinker.\n",
mdname(mddev));
goto abort;
}
 
+   conf->shrinker->seeks = DEFAULT_SEEKS * conf->raid_disks * 4;
+   conf->shrinker->scan_objects = raid5_cache_scan;
+   conf->shrinker->count_objects = raid5_cache_count;
+   conf->shrinker->batch = 128;
+   conf->shrinker->private_data = conf;
+
+   shrinker_register(conf->shrinker);
+
sprintf(pers_name, "raid%d", mddev->new_level);
rcu_assign_pointer(conf->thread,
   md_register_thread(raid5d, mddev, pers_name));
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 97a795979a35..22bea20eccbd 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -670,7 +670,7 @@ struct r5conf {
wait_queue_head_t   wait_for_stripe;
wait_queue_head_t   wait_for_overlap;
unsigned long   cache_state;
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
int pool_size; /* number of disks in stripeheads in 
pool */
spinlock_t  device_lock;
struct disk_info*disks;
-- 
2.30.2



[PATCH v3 30/49] bcache: dynamically allocate the md-bcache shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the md-bcache shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct cache_set.

Signed-off-by: Qi Zheng 
---
 drivers/md/bcache/bcache.h |  2 +-
 drivers/md/bcache/btree.c  | 27 ---
 drivers/md/bcache/sysfs.c  |  3 ++-
 3 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 5a79bb3c272f..c622bc50f81b 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -541,7 +541,7 @@ struct cache_set {
struct bio_set  bio_split;
 
/* For the btree cache */
-   struct shrinker shrink;
+   struct shrinker *shrink;
 
/* For the btree cache and anything allocation related */
struct mutexbucket_lock;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index fd121a61f17c..ae5cbb55861f 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -667,7 +667,7 @@ static int mca_reap(struct btree *b, unsigned int 
min_order, bool flush)
 static unsigned long bch_mca_scan(struct shrinker *shrink,
  struct shrink_control *sc)
 {
-   struct cache_set *c = container_of(shrink, struct cache_set, shrink);
+   struct cache_set *c = shrink->private_data;
struct btree *b, *t;
unsigned long i, nr = sc->nr_to_scan;
unsigned long freed = 0;
@@ -734,7 +734,7 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
 static unsigned long bch_mca_count(struct shrinker *shrink,
   struct shrink_control *sc)
 {
-   struct cache_set *c = container_of(shrink, struct cache_set, shrink);
+   struct cache_set *c = shrink->private_data;
 
if (c->shrinker_disabled)
return 0;
@@ -752,8 +752,8 @@ void bch_btree_cache_free(struct cache_set *c)
 
closure_init_stack(&cl);
 
-   if (c->shrink.list.next)
-   unregister_shrinker(&c->shrink);
+   if (c->shrink)
+   shrinker_free(c->shrink);
 
mutex_lock(&c->bucket_lock);
 
@@ -828,14 +828,19 @@ int bch_btree_cache_alloc(struct cache_set *c)
c->verify_data = NULL;
 #endif
 
-   c->shrink.count_objects = bch_mca_count;
-   c->shrink.scan_objects = bch_mca_scan;
-   c->shrink.seeks = 4;
-   c->shrink.batch = c->btree_pages * 2;
+   c->shrink = shrinker_alloc(0, "md-bcache:%pU", c->set_uuid);
+   if (!c->shrink) {
+   pr_warn("bcache: %s: could not allocate shrinker\n", __func__);
+   return 0;
+   }
+
+   c->shrink->count_objects = bch_mca_count;
+   c->shrink->scan_objects = bch_mca_scan;
+   c->shrink->seeks = 4;
+   c->shrink->batch = c->btree_pages * 2;
+   c->shrink->private_data = c;
 
-   if (register_shrinker(&c->shrink, "md-bcache:%pU", c->set_uuid))
-   pr_warn("bcache: %s: could not register shrinker\n",
-   __func__);
+   shrinker_register(c->shrink);
 
return 0;
 }
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 0e2c1880f60b..45d8af755de6 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -866,7 +866,8 @@ STORE(__bch_cache_set)
 
sc.gfp_mask = GFP_KERNEL;
sc.nr_to_scan = strtoul_or_return(buf);
-   c->shrink.scan_objects(&c->shrink, &sc);
+   if (c->shrink)
+   c->shrink->scan_objects(c->shrink, &sc);
}
 
sysfs_strtoul_clamp(congested_read_threshold_us,
-- 
2.30.2



[PATCH v3 31/49] vmw_balloon: dynamically allocate the vmw-balloon shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the vmw-balloon shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct vmballoon.

And we can simply exit vmballoon_init() when registering the shrinker
fails. So the shrinker_registered indication is redundant, just remove it.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/misc/vmw_balloon.c | 38 --
 1 file changed, 12 insertions(+), 26 deletions(-)

diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index 9ce9b9e0e9b6..ac2cdb6cdf74 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -380,16 +380,7 @@ struct vmballoon {
/**
 * @shrinker: shrinker interface that is used to avoid over-inflation.
 */
-   struct shrinker shrinker;
-
-   /**
-* @shrinker_registered: whether the shrinker was registered.
-*
-* The shrinker interface does not handle gracefully the removal of
-* shrinker that was not registered before. This indication allows to
-* simplify the unregistration process.
-*/
-   bool shrinker_registered;
+   struct shrinker *shrinker;
 };
 
 static struct vmballoon balloon;
@@ -1568,29 +1559,27 @@ static unsigned long vmballoon_shrinker_count(struct 
shrinker *shrinker,
 
 static void vmballoon_unregister_shrinker(struct vmballoon *b)
 {
-   if (b->shrinker_registered)
-   unregister_shrinker(&b->shrinker);
-   b->shrinker_registered = false;
+   shrinker_free(b->shrinker);
 }
 
 static int vmballoon_register_shrinker(struct vmballoon *b)
 {
-   int r;
-
/* Do nothing if the shrinker is not enabled */
if (!vmwballoon_shrinker_enable)
return 0;
 
-   b->shrinker.scan_objects = vmballoon_shrinker_scan;
-   b->shrinker.count_objects = vmballoon_shrinker_count;
-   b->shrinker.seeks = DEFAULT_SEEKS;
+   b->shrinker = shrinker_alloc(0, "vmw-balloon");
+   if (!b->shrinker)
+   return -ENOMEM;
 
-   r = register_shrinker(&b->shrinker, "vmw-balloon");
+   b->shrinker->scan_objects = vmballoon_shrinker_scan;
+   b->shrinker->count_objects = vmballoon_shrinker_count;
+   b->shrinker->seeks = DEFAULT_SEEKS;
+   b->shrinker->private_data = b;
 
-   if (r == 0)
-   b->shrinker_registered = true;
+   shrinker_register(b->shrinker);
 
-   return r;
+   return 0;
 }
 
 /*
@@ -1883,7 +1872,7 @@ static int __init vmballoon_init(void)
 
error = vmballoon_register_shrinker(&balloon);
if (error)
-   goto fail;
+   return error;
 
/*
 * Initialization of compaction must be done after the call to
@@ -1905,9 +1894,6 @@ static int __init vmballoon_init(void)
vmballoon_debugfs_init(&balloon);
 
return 0;
-fail:
-   vmballoon_unregister_shrinker(&balloon);
-   return error;
 }
 
 /*
-- 
2.30.2



[PATCH v3 32/49] virtio_balloon: dynamically allocate the virtio-balloon shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the virtio-balloon shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct virtio_balloon.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/virtio/virtio_balloon.c | 25 +++--
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 5b15936a5214..82e6087073a9 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -111,7 +111,7 @@ struct virtio_balloon {
struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
 
/* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
 
/* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */
struct notifier_block oom_nb;
@@ -816,8 +816,7 @@ static unsigned long shrink_free_pages(struct 
virtio_balloon *vb,
 static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
  struct shrink_control *sc)
 {
-   struct virtio_balloon *vb = container_of(shrinker,
-   struct virtio_balloon, shrinker);
+   struct virtio_balloon *vb = shrinker->private_data;
 
return shrink_free_pages(vb, sc->nr_to_scan);
 }
@@ -825,8 +824,7 @@ static unsigned long virtio_balloon_shrinker_scan(struct 
shrinker *shrinker,
 static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
   struct shrink_control *sc)
 {
-   struct virtio_balloon *vb = container_of(shrinker,
-   struct virtio_balloon, shrinker);
+   struct virtio_balloon *vb = shrinker->private_data;
 
return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
 }
@@ -847,16 +845,23 @@ static int virtio_balloon_oom_notify(struct 
notifier_block *nb,
 
 static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb)
 {
-   unregister_shrinker(&vb->shrinker);
+   shrinker_free(vb->shrinker);
 }
 
 static int virtio_balloon_register_shrinker(struct virtio_balloon *vb)
 {
-   vb->shrinker.scan_objects = virtio_balloon_shrinker_scan;
-   vb->shrinker.count_objects = virtio_balloon_shrinker_count;
-   vb->shrinker.seeks = DEFAULT_SEEKS;
+   vb->shrinker = shrinker_alloc(0, "virtio-balloon");
+   if (!vb->shrinker)
+   return -ENOMEM;
 
-   return register_shrinker(&vb->shrinker, "virtio-balloon");
+   vb->shrinker->scan_objects = virtio_balloon_shrinker_scan;
+   vb->shrinker->count_objects = virtio_balloon_shrinker_count;
+   vb->shrinker->seeks = DEFAULT_SEEKS;
+   vb->shrinker->private_data = vb;
+
+   shrinker_register(vb->shrinker);
+
+   return 0;
 }
 
 static int virtballoon_probe(struct virtio_device *vdev)
-- 
2.30.2



[PATCH v3 33/49] mbcache: dynamically allocate the mbcache shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the mbcache shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct mb_cache.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/mbcache.c | 23 +--
 1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/fs/mbcache.c b/fs/mbcache.c
index 2a4b8b549e93..0d1e24e9a5e3 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -37,7 +37,7 @@ struct mb_cache {
struct list_headc_list;
/* Number of entries in cache */
unsigned long   c_entry_count;
-   struct shrinker c_shrink;
+   struct shrinker *c_shrink;
/* Work for shrinking when the cache has too many entries */
struct work_struct  c_shrink_work;
 };
@@ -293,8 +293,7 @@ EXPORT_SYMBOL(mb_cache_entry_touch);
 static unsigned long mb_cache_count(struct shrinker *shrink,
struct shrink_control *sc)
 {
-   struct mb_cache *cache = container_of(shrink, struct mb_cache,
- c_shrink);
+   struct mb_cache *cache = shrink->private_data;
 
return cache->c_entry_count;
 }
@@ -333,8 +332,7 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
 static unsigned long mb_cache_scan(struct shrinker *shrink,
   struct shrink_control *sc)
 {
-   struct mb_cache *cache = container_of(shrink, struct mb_cache,
- c_shrink);
+   struct mb_cache *cache = shrink->private_data;
return mb_cache_shrink(cache, sc->nr_to_scan);
 }
 
@@ -377,15 +375,20 @@ struct mb_cache *mb_cache_create(int bucket_bits)
for (i = 0; i < bucket_count; i++)
INIT_HLIST_BL_HEAD(&cache->c_hash[i]);
 
-   cache->c_shrink.count_objects = mb_cache_count;
-   cache->c_shrink.scan_objects = mb_cache_scan;
-   cache->c_shrink.seeks = DEFAULT_SEEKS;
-   if (register_shrinker(&cache->c_shrink, "mbcache-shrinker")) {
+   cache->c_shrink = shrinker_alloc(0, "mbcache-shrinker");
+   if (!cache->c_shrink) {
kfree(cache->c_hash);
kfree(cache);
goto err_out;
}
 
+   cache->c_shrink->count_objects = mb_cache_count;
+   cache->c_shrink->scan_objects = mb_cache_scan;
+   cache->c_shrink->seeks = DEFAULT_SEEKS;
+   cache->c_shrink->private_data = cache;
+
+   shrinker_register(cache->c_shrink);
+
INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker);
 
return cache;
@@ -406,7 +409,7 @@ void mb_cache_destroy(struct mb_cache *cache)
 {
struct mb_cache_entry *entry, *next;
 
-   unregister_shrinker(&cache->c_shrink);
+   shrinker_free(cache->c_shrink);
 
/*
 * We don't bother with any locking. Cache must not be used at this
-- 
2.30.2



[PATCH v3 34/49] ext4: dynamically allocate the ext4-es shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the ext4-es shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct ext4_sb_info.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/ext4/ext4.h   |  2 +-
 fs/ext4/extents_status.c | 22 --
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 1e2259d9967d..82397bf0b33e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1657,7 +1657,7 @@ struct ext4_sb_info {
__u32 s_csum_seed;
 
/* Reclaim extents from extent status tree */
-   struct shrinker s_es_shrinker;
+   struct shrinker *s_es_shrinker;
struct list_head s_es_list; /* List of inodes with reclaimable 
extents */
long s_es_nr_inode;
struct ext4_es_stats s_es_stats;
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index 9b5b8951afb4..74bb64fadbc4 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -1596,7 +1596,7 @@ static unsigned long ext4_es_count(struct shrinker 
*shrink,
unsigned long nr;
struct ext4_sb_info *sbi;
 
-   sbi = container_of(shrink, struct ext4_sb_info, s_es_shrinker);
+   sbi = shrink->private_data;
nr = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_shk_cnt);
trace_ext4_es_shrink_count(sbi->s_sb, sc->nr_to_scan, nr);
return nr;
@@ -1605,8 +1605,7 @@ static unsigned long ext4_es_count(struct shrinker 
*shrink,
 static unsigned long ext4_es_scan(struct shrinker *shrink,
  struct shrink_control *sc)
 {
-   struct ext4_sb_info *sbi = container_of(shrink,
-   struct ext4_sb_info, s_es_shrinker);
+   struct ext4_sb_info *sbi = shrink->private_data;
int nr_to_scan = sc->nr_to_scan;
int ret, nr_shrunk;
 
@@ -1690,14 +1689,17 @@ int ext4_es_register_shrinker(struct ext4_sb_info *sbi)
if (err)
goto err3;
 
-   sbi->s_es_shrinker.scan_objects = ext4_es_scan;
-   sbi->s_es_shrinker.count_objects = ext4_es_count;
-   sbi->s_es_shrinker.seeks = DEFAULT_SEEKS;
-   err = register_shrinker(&sbi->s_es_shrinker, "ext4-es:%s",
-   sbi->s_sb->s_id);
-   if (err)
+   sbi->s_es_shrinker = shrinker_alloc(0, "ext4-es:%s", sbi->s_sb->s_id);
+   if (!sbi->s_es_shrinker)
goto err4;
 
+   sbi->s_es_shrinker->scan_objects = ext4_es_scan;
+   sbi->s_es_shrinker->count_objects = ext4_es_count;
+   sbi->s_es_shrinker->seeks = DEFAULT_SEEKS;
+   sbi->s_es_shrinker->private_data = sbi;
+
+   shrinker_register(sbi->s_es_shrinker);
+
return 0;
 err4:
percpu_counter_destroy(&sbi->s_es_stats.es_stats_shk_cnt);
@@ -1716,7 +1718,7 @@ void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi)
percpu_counter_destroy(&sbi->s_es_stats.es_stats_cache_misses);
percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt);
percpu_counter_destroy(&sbi->s_es_stats.es_stats_shk_cnt);
-   unregister_shrinker(&sbi->s_es_shrinker);
+   shrinker_free(sbi->s_es_shrinker);
 }
 
 /*
-- 
2.30.2



[PATCH v3 35/49] jbd2, ext4: dynamically allocate the jbd2-journal shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the jbd2-journal shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct journal_s.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/jbd2/journal.c| 27 +--
 include/linux/jbd2.h |  2 +-
 2 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 1b5a45ab62b0..4c421da03fee 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1298,7 +1298,7 @@ static int jbd2_min_tag_size(void)
 static unsigned long jbd2_journal_shrink_scan(struct shrinker *shrink,
  struct shrink_control *sc)
 {
-   journal_t *journal = container_of(shrink, journal_t, j_shrinker);
+   journal_t *journal = shrink->private_data;
unsigned long nr_to_scan = sc->nr_to_scan;
unsigned long nr_shrunk;
unsigned long count;
@@ -1324,7 +1324,7 @@ static unsigned long jbd2_journal_shrink_scan(struct 
shrinker *shrink,
 static unsigned long jbd2_journal_shrink_count(struct shrinker *shrink,
   struct shrink_control *sc)
 {
-   journal_t *journal = container_of(shrink, journal_t, j_shrinker);
+   journal_t *journal = shrink->private_data;
unsigned long count;
 
count = percpu_counter_read_positive(&journal->j_checkpoint_jh_count);
@@ -1412,19 +1412,26 @@ static journal_t *journal_init_common(struct 
block_device *bdev,
journal->j_superblock = (journal_superblock_t *)bh->b_data;
 
journal->j_shrink_transaction = NULL;
-   journal->j_shrinker.scan_objects = jbd2_journal_shrink_scan;
-   journal->j_shrinker.count_objects = jbd2_journal_shrink_count;
-   journal->j_shrinker.seeks = DEFAULT_SEEKS;
-   journal->j_shrinker.batch = journal->j_max_transaction_buffers;
 
if (percpu_counter_init(&journal->j_checkpoint_jh_count, 0, GFP_KERNEL))
goto err_cleanup;
 
-   if (register_shrinker(&journal->j_shrinker, "jbd2-journal:(%u:%u)",
- MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev))) {
+   journal->j_shrinker = shrinker_alloc(0, "jbd2-journal:(%u:%u)",
+MAJOR(bdev->bd_dev),
+MINOR(bdev->bd_dev));
+   if (!journal->j_shrinker) {
percpu_counter_destroy(&journal->j_checkpoint_jh_count);
goto err_cleanup;
}
+
+   journal->j_shrinker->scan_objects = jbd2_journal_shrink_scan;
+   journal->j_shrinker->count_objects = jbd2_journal_shrink_count;
+   journal->j_shrinker->seeks = DEFAULT_SEEKS;
+   journal->j_shrinker->batch = journal->j_max_transaction_buffers;
+   journal->j_shrinker->private_data = journal;
+
+   shrinker_register(journal->j_shrinker);
+
return journal;
 
 err_cleanup:
@@ -2187,9 +2194,9 @@ int jbd2_journal_destroy(journal_t *journal)
brelse(journal->j_sb_buffer);
}
 
-   if (journal->j_shrinker.flags & SHRINKER_REGISTERED) {
+   if (journal->j_shrinker) {
percpu_counter_destroy(&journal->j_checkpoint_jh_count);
-   unregister_shrinker(&journal->j_shrinker);
+   shrinker_free(journal->j_shrinker);
}
if (journal->j_proc_entry)
jbd2_stats_proc_exit(journal);
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 44c298aa58d4..beb4c4586320 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -891,7 +891,7 @@ struct journal_s
 * Journal head shrinker, reclaim buffer's journal head which
 * has been written back.
 */
-   struct shrinker j_shrinker;
+   struct shrinker *j_shrinker;
 
/**
 * @j_checkpoint_jh_count:
-- 
2.30.2



[PATCH v3 36/49] nfsd: dynamically allocate the nfsd-client shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the nfsd-client shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct nfsd_net.

Signed-off-by: Qi Zheng 
Acked-by: Chuck Lever 
Acked-by: Jeff Layton 
---
 fs/nfsd/netns.h |  2 +-
 fs/nfsd/nfs4state.c | 20 
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index ec49b200b797..f669444d5336 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -195,7 +195,7 @@ struct nfsd_net {
int nfs4_max_clients;
 
atomic_tnfsd_courtesy_clients;
-   struct shrinker nfsd_client_shrinker;
+   struct shrinker *nfsd_client_shrinker;
struct work_struct  nfsd_shrinker_work;
 };
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ef7118ebee00..75334a43ded4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4388,8 +4388,7 @@ static unsigned long
 nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
 {
int count;
-   struct nfsd_net *nn = container_of(shrink,
-   struct nfsd_net, nfsd_client_shrinker);
+   struct nfsd_net *nn = shrink->private_data;
 
count = atomic_read(&nn->nfsd_courtesy_clients);
if (!count)
@@ -8123,12 +8122,17 @@ static int nfs4_state_create_net(struct net *net)
INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
get_net(net);
 
-   nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
-   nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
-   nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
-
-   if (register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client"))
+   nn->nfsd_client_shrinker = shrinker_alloc(0, "nfsd-client");
+   if (!nn->nfsd_client_shrinker)
goto err_shrinker;
+
+   nn->nfsd_client_shrinker->scan_objects = nfsd4_state_shrinker_scan;
+   nn->nfsd_client_shrinker->count_objects = nfsd4_state_shrinker_count;
+   nn->nfsd_client_shrinker->seeks = DEFAULT_SEEKS;
+   nn->nfsd_client_shrinker->private_data = nn;
+
+   shrinker_register(nn->nfsd_client_shrinker);
+
return 0;
 
 err_shrinker:
@@ -8226,7 +8230,7 @@ nfs4_state_shutdown_net(struct net *net)
struct list_head *pos, *next, reaplist;
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-   unregister_shrinker(&nn->nfsd_client_shrinker);
+   shrinker_free(nn->nfsd_client_shrinker);
cancel_work(&nn->nfsd_shrinker_work);
cancel_delayed_work_sync(&nn->laundromat_work);
locks_end_grace(&nn->nfsd4_manager);
-- 
2.30.2



[PATCH v3 37/49] nfsd: dynamically allocate the nfsd-reply shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the nfsd-reply shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct nfsd_net.

Signed-off-by: Qi Zheng 
Acked-by: Chuck Lever 
Acked-by: Jeff Layton 
---
 fs/nfsd/netns.h|  2 +-
 fs/nfsd/nfscache.c | 31 ---
 2 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index f669444d5336..ab303a8b77d5 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -177,7 +177,7 @@ struct nfsd_net {
/* size of cache when we saw the longest hash chain */
unsigned int longest_chain_cachesize;
 
-   struct shrinker nfsd_reply_cache_shrinker;
+   struct shrinker *nfsd_reply_cache_shrinker;
 
/* tracking server-to-server copy mounts */
spinlock_t  nfsd_ssc_lock;
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 80621a709510..fd56a52aa5fb 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -201,26 +201,29 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
 {
unsigned int hashsize;
unsigned int i;
-   int status = 0;
 
nn->max_drc_entries = nfsd_cache_size_limit();
atomic_set(&nn->num_drc_entries, 0);
hashsize = nfsd_hashsize(nn->max_drc_entries);
nn->maskbits = ilog2(hashsize);
 
-   nn->nfsd_reply_cache_shrinker.scan_objects = nfsd_reply_cache_scan;
-   nn->nfsd_reply_cache_shrinker.count_objects = nfsd_reply_cache_count;
-   nn->nfsd_reply_cache_shrinker.seeks = 1;
-   status = register_shrinker(&nn->nfsd_reply_cache_shrinker,
-  "nfsd-reply:%s", nn->nfsd_name);
-   if (status)
-   return status;
-
nn->drc_hashtbl = kvzalloc(array_size(hashsize,
sizeof(*nn->drc_hashtbl)), GFP_KERNEL);
if (!nn->drc_hashtbl)
+   return -ENOMEM;
+
+   nn->nfsd_reply_cache_shrinker = shrinker_alloc(0, "nfsd-reply:%s",
+  nn->nfsd_name);
+   if (!nn->nfsd_reply_cache_shrinker)
goto out_shrinker;
 
+   nn->nfsd_reply_cache_shrinker->scan_objects = nfsd_reply_cache_scan;
+   nn->nfsd_reply_cache_shrinker->count_objects = nfsd_reply_cache_count;
+   nn->nfsd_reply_cache_shrinker->seeks = 1;
+   nn->nfsd_reply_cache_shrinker->private_data = nn;
+
+   shrinker_register(nn->nfsd_reply_cache_shrinker);
+
for (i = 0; i < hashsize; i++) {
INIT_LIST_HEAD(&nn->drc_hashtbl[i].lru_head);
spin_lock_init(&nn->drc_hashtbl[i].cache_lock);
@@ -229,7 +232,7 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
 
return 0;
 out_shrinker:
-   unregister_shrinker(&nn->nfsd_reply_cache_shrinker);
+   kvfree(nn->drc_hashtbl);
printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
return -ENOMEM;
 }
@@ -239,7 +242,7 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn)
struct nfsd_cacherep *rp;
unsigned int i;
 
-   unregister_shrinker(&nn->nfsd_reply_cache_shrinker);
+   shrinker_free(nn->nfsd_reply_cache_shrinker);
 
for (i = 0; i < nn->drc_hashsize; i++) {
struct list_head *head = &nn->drc_hashtbl[i].lru_head;
@@ -323,8 +326,7 @@ nfsd_prune_bucket_locked(struct nfsd_net *nn, struct 
nfsd_drc_bucket *b,
 static unsigned long
 nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc)
 {
-   struct nfsd_net *nn = container_of(shrink,
-   struct nfsd_net, nfsd_reply_cache_shrinker);
+   struct nfsd_net *nn = shrink->private_data;
 
return atomic_read(&nn->num_drc_entries);
 }
@@ -343,8 +345,7 @@ nfsd_reply_cache_count(struct shrinker *shrink, struct 
shrink_control *sc)
 static unsigned long
 nfsd_reply_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
-   struct nfsd_net *nn = container_of(shrink,
-   struct nfsd_net, nfsd_reply_cache_shrinker);
+   struct nfsd_net *nn = shrink->private_data;
unsigned long freed = 0;
LIST_HEAD(dispose);
unsigned int i;
-- 
2.30.2



[PATCH v3 38/49] xfs: dynamically allocate the xfs-buf shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the xfs-buf shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct xfs_buftarg.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/xfs/xfs_buf.c | 25 ++---
 fs/xfs/xfs_buf.h |  2 +-
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 15d1e5a7c2d3..715730fc91cb 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -1906,8 +1906,7 @@ xfs_buftarg_shrink_scan(
struct shrinker *shrink,
struct shrink_control   *sc)
 {
-   struct xfs_buftarg  *btp = container_of(shrink,
-   struct xfs_buftarg, bt_shrinker);
+   struct xfs_buftarg  *btp = shrink->private_data;
LIST_HEAD(dispose);
unsigned long   freed;
 
@@ -1929,8 +1928,7 @@ xfs_buftarg_shrink_count(
struct shrinker *shrink,
struct shrink_control   *sc)
 {
-   struct xfs_buftarg  *btp = container_of(shrink,
-   struct xfs_buftarg, bt_shrinker);
+   struct xfs_buftarg  *btp = shrink->private_data;
return list_lru_shrink_count(&btp->bt_lru, sc);
 }
 
@@ -1938,7 +1936,7 @@ void
 xfs_free_buftarg(
struct xfs_buftarg  *btp)
 {
-   unregister_shrinker(&btp->bt_shrinker);
+   shrinker_free(btp->bt_shrinker);
ASSERT(percpu_counter_sum(&btp->bt_io_count) == 0);
percpu_counter_destroy(&btp->bt_io_count);
list_lru_destroy(&btp->bt_lru);
@@ -2021,13 +2019,18 @@ xfs_alloc_buftarg(
if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL))
goto error_lru;
 
-   btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count;
-   btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan;
-   btp->bt_shrinker.seeks = DEFAULT_SEEKS;
-   btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE;
-   if (register_shrinker(&btp->bt_shrinker, "xfs-buf:%s",
- mp->m_super->s_id))
+   btp->bt_shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE, "xfs-buf:%s",
+ mp->m_super->s_id);
+   if (!btp->bt_shrinker)
goto error_pcpu;
+
+   btp->bt_shrinker->count_objects = xfs_buftarg_shrink_count;
+   btp->bt_shrinker->scan_objects = xfs_buftarg_shrink_scan;
+   btp->bt_shrinker->seeks = DEFAULT_SEEKS;
+   btp->bt_shrinker->private_data = btp;
+
+   shrinker_register(btp->bt_shrinker);
+
return btp;
 
 error_pcpu:
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index 549c60942208..4e6969a675f7 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -102,7 +102,7 @@ typedef struct xfs_buftarg {
size_t  bt_logical_sectormask;
 
/* LRU control structures */
-   struct shrinker bt_shrinker;
+   struct shrinker *bt_shrinker;
struct list_lru bt_lru;
 
struct percpu_counter   bt_io_count;
-- 
2.30.2



[PATCH v3 39/49] xfs: dynamically allocate the xfs-inodegc shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the xfs-inodegc shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct xfs_mount.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/xfs/xfs_icache.c | 26 +++---
 fs/xfs/xfs_mount.c  |  4 ++--
 fs/xfs/xfs_mount.h  |  2 +-
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 453890942d9f..751c380afd5a 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -2225,8 +2225,7 @@ xfs_inodegc_shrinker_count(
struct shrinker *shrink,
struct shrink_control   *sc)
 {
-   struct xfs_mount*mp = container_of(shrink, struct xfs_mount,
-  m_inodegc_shrinker);
+   struct xfs_mount*mp = shrink->private_data;
struct xfs_inodegc  *gc;
int cpu;
 
@@ -2247,8 +2246,7 @@ xfs_inodegc_shrinker_scan(
struct shrinker *shrink,
struct shrink_control   *sc)
 {
-   struct xfs_mount*mp = container_of(shrink, struct xfs_mount,
-  m_inodegc_shrinker);
+   struct xfs_mount*mp = shrink->private_data;
struct xfs_inodegc  *gc;
int cpu;
boolno_items = true;
@@ -2284,13 +2282,19 @@ int
 xfs_inodegc_register_shrinker(
struct xfs_mount*mp)
 {
-   struct shrinker *shrink = &mp->m_inodegc_shrinker;
+   mp->m_inodegc_shrinker = shrinker_alloc(SHRINKER_NONSLAB,
+   "xfs-inodegc:%s",
+   mp->m_super->s_id);
+   if (!mp->m_inodegc_shrinker)
+   return -ENOMEM;
+
+   mp->m_inodegc_shrinker->count_objects = xfs_inodegc_shrinker_count;
+   mp->m_inodegc_shrinker->scan_objects = xfs_inodegc_shrinker_scan;
+   mp->m_inodegc_shrinker->seeks = 0;
+   mp->m_inodegc_shrinker->batch = XFS_INODEGC_SHRINKER_BATCH;
+   mp->m_inodegc_shrinker->private_data = mp;
 
-   shrink->count_objects = xfs_inodegc_shrinker_count;
-   shrink->scan_objects = xfs_inodegc_shrinker_scan;
-   shrink->seeks = 0;
-   shrink->flags = SHRINKER_NONSLAB;
-   shrink->batch = XFS_INODEGC_SHRINKER_BATCH;
+   shrinker_register(mp->m_inodegc_shrinker);
 
-   return register_shrinker(shrink, "xfs-inodegc:%s", mp->m_super->s_id);
+   return 0;
 }
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index fb87ffb48f7f..640d09891a4e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1018,7 +1018,7 @@ xfs_mountfs(
  out_log_dealloc:
xfs_log_mount_cancel(mp);
  out_inodegc_shrinker:
-   unregister_shrinker(&mp->m_inodegc_shrinker);
+   shrinker_free(mp->m_inodegc_shrinker);
  out_fail_wait:
if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
xfs_buftarg_drain(mp->m_logdev_targp);
@@ -1100,7 +1100,7 @@ xfs_unmountfs(
 #if defined(DEBUG)
xfs_errortag_clearall(mp);
 #endif
-   unregister_shrinker(&mp->m_inodegc_shrinker);
+   shrinker_free(mp->m_inodegc_shrinker);
xfs_free_perag(mp);
 
xfs_errortag_del(mp);
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index e2866e7fa60c..562c294ca08e 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -217,7 +217,7 @@ typedef struct xfs_mount {
atomic_tm_agirotor; /* last ag dir inode alloced */
 
/* Memory shrinker to throttle and reprioritize inodegc */
-   struct shrinker m_inodegc_shrinker;
+   struct shrinker *m_inodegc_shrinker;
/*
 * Workqueue item so that we can coalesce multiple inode flush attempts
 * into a single flush.
-- 
2.30.2



[PATCH v3 40/49] xfs: dynamically allocate the xfs-qm shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the xfs-qm shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct xfs_quotainfo.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/xfs/xfs_qm.c | 26 +-
 fs/xfs/xfs_qm.h |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 6abcc34fafd8..032f0a208bd2 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -504,8 +504,7 @@ xfs_qm_shrink_scan(
struct shrinker *shrink,
struct shrink_control   *sc)
 {
-   struct xfs_quotainfo*qi = container_of(shrink,
-   struct xfs_quotainfo, qi_shrinker);
+   struct xfs_quotainfo*qi = shrink->private_data;
struct xfs_qm_isolate   isol;
unsigned long   freed;
int error;
@@ -539,8 +538,7 @@ xfs_qm_shrink_count(
struct shrinker *shrink,
struct shrink_control   *sc)
 {
-   struct xfs_quotainfo*qi = container_of(shrink,
-   struct xfs_quotainfo, qi_shrinker);
+   struct xfs_quotainfo*qi = shrink->private_data;
 
return list_lru_shrink_count(&qi->qi_lru, sc);
 }
@@ -680,16 +678,18 @@ xfs_qm_init_quotainfo(
if (XFS_IS_PQUOTA_ON(mp))
xfs_qm_set_defquota(mp, XFS_DQTYPE_PROJ, qinf);
 
-   qinf->qi_shrinker.count_objects = xfs_qm_shrink_count;
-   qinf->qi_shrinker.scan_objects = xfs_qm_shrink_scan;
-   qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
-   qinf->qi_shrinker.flags = SHRINKER_NUMA_AWARE;
-
-   error = register_shrinker(&qinf->qi_shrinker, "xfs-qm:%s",
- mp->m_super->s_id);
-   if (error)
+   qinf->qi_shrinker = shrinker_alloc(SHRINKER_NUMA_AWARE, "xfs-qm:%s",
+  mp->m_super->s_id);
+   if (!qinf->qi_shrinker)
goto out_free_inos;
 
+   qinf->qi_shrinker->count_objects = xfs_qm_shrink_count;
+   qinf->qi_shrinker->scan_objects = xfs_qm_shrink_scan;
+   qinf->qi_shrinker->seeks = DEFAULT_SEEKS;
+   qinf->qi_shrinker->private_data = qinf;
+
+   shrinker_register(qinf->qi_shrinker);
+
return 0;
 
 out_free_inos:
@@ -718,7 +718,7 @@ xfs_qm_destroy_quotainfo(
qi = mp->m_quotainfo;
ASSERT(qi != NULL);
 
-   unregister_shrinker(&qi->qi_shrinker);
+   shrinker_free(qi->qi_shrinker);
list_lru_destroy(&qi->qi_lru);
xfs_qm_destroy_quotainos(qi);
mutex_destroy(&qi->qi_tree_lock);
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h
index 9683f0457d19..d5c9fc4ba591 100644
--- a/fs/xfs/xfs_qm.h
+++ b/fs/xfs/xfs_qm.h
@@ -63,7 +63,7 @@ struct xfs_quotainfo {
struct xfs_def_quotaqi_usr_default;
struct xfs_def_quotaqi_grp_default;
struct xfs_def_quotaqi_prj_default;
-   struct shrinker qi_shrinker;
+   struct shrinker *qi_shrinker;
 
/* Minimum and maximum quota expiration timestamp values. */
time64_tqi_expiry_min;
-- 
2.30.2



[PATCH v3 41/49] zsmalloc: dynamically allocate the mm-zspool shrinker

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the mm-zspool shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct zs_pool.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 mm/zsmalloc.c | 28 
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index b96230402a8d..e63302e07c97 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -229,7 +229,7 @@ struct zs_pool {
struct zs_pool_stats stats;
 
/* Compact classes */
-   struct shrinker shrinker;
+   struct shrinker *shrinker;
 
 #ifdef CONFIG_ZSMALLOC_STAT
struct dentry *stat_dentry;
@@ -2086,8 +2086,7 @@ static unsigned long zs_shrinker_scan(struct shrinker 
*shrinker,
struct shrink_control *sc)
 {
unsigned long pages_freed;
-   struct zs_pool *pool = container_of(shrinker, struct zs_pool,
-   shrinker);
+   struct zs_pool *pool = shrinker->private_data;
 
/*
 * Compact classes and calculate compaction delta.
@@ -2105,8 +2104,7 @@ static unsigned long zs_shrinker_count(struct shrinker 
*shrinker,
int i;
struct size_class *class;
unsigned long pages_to_free = 0;
-   struct zs_pool *pool = container_of(shrinker, struct zs_pool,
-   shrinker);
+   struct zs_pool *pool = shrinker->private_data;
 
for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
class = pool->size_class[i];
@@ -2121,18 +2119,24 @@ static unsigned long zs_shrinker_count(struct shrinker 
*shrinker,
 
 static void zs_unregister_shrinker(struct zs_pool *pool)
 {
-   unregister_shrinker(&pool->shrinker);
+   shrinker_free(pool->shrinker);
 }
 
 static int zs_register_shrinker(struct zs_pool *pool)
 {
-   pool->shrinker.scan_objects = zs_shrinker_scan;
-   pool->shrinker.count_objects = zs_shrinker_count;
-   pool->shrinker.batch = 0;
-   pool->shrinker.seeks = DEFAULT_SEEKS;
+   pool->shrinker = shrinker_alloc(0, "mm-zspool:%s", pool->name);
+   if (!pool->shrinker)
+   return -ENOMEM;
+
+   pool->shrinker->scan_objects = zs_shrinker_scan;
+   pool->shrinker->count_objects = zs_shrinker_count;
+   pool->shrinker->batch = 0;
+   pool->shrinker->seeks = DEFAULT_SEEKS;
+   pool->shrinker->private_data = pool;
 
-   return register_shrinker(&pool->shrinker, "mm-zspool:%s",
-pool->name);
+   shrinker_register(pool->shrinker);
+
+   return 0;
 }
 
 static int calculate_zspage_chain_size(int class_size)
-- 
2.30.2



[PATCH v3 42/49] fs: super: dynamically allocate the s_shrink

2023-07-27 Thread Qi Zheng
In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the s_shrink, so that it can be freed asynchronously
using kfree_rcu(). Then it doesn't need to wait for RCU read-side critical
section when releasing the struct super_block.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 fs/btrfs/super.c   |  2 +-
 fs/kernfs/mount.c  |  2 +-
 fs/proc/root.c |  2 +-
 fs/super.c | 36 
 include/linux/fs.h |  2 +-
 5 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index cffdd6f7f8e8..4c9c878b0da4 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1519,7 +1519,7 @@ static struct dentry *btrfs_mount_root(struct 
file_system_type *fs_type,
error = -EBUSY;
} else {
snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
-   shrinker_debugfs_rename(&s->s_shrink, "sb-%s:%s", fs_type->name,
+   shrinker_debugfs_rename(s->s_shrink, "sb-%s:%s", fs_type->name,
s->s_id);
btrfs_sb(s)->bdev_holder = fs_type;
error = btrfs_fill_super(s, fs_devices, data);
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index d49606accb07..2657ff1181f1 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -256,7 +256,7 @@ static int kernfs_fill_super(struct super_block *sb, struct 
kernfs_fs_context *k
sb->s_time_gran = 1;
 
/* sysfs dentries and inodes don't require IO to create */
-   sb->s_shrink.seeks = 0;
+   sb->s_shrink->seeks = 0;
 
/* get root inode, initialize and unlock it */
down_read(&kf_root->kernfs_rwsem);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index a86e65a608da..22b78b28b477 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -188,7 +188,7 @@ static int proc_fill_super(struct super_block *s, struct 
fs_context *fc)
s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
 
/* procfs dentries and inodes don't require IO to create */
-   s->s_shrink.seeks = 0;
+   s->s_shrink->seeks = 0;
 
pde_get(&proc_root);
root_inode = proc_get_inode(s, &proc_root);
diff --git a/fs/super.c b/fs/super.c
index da68584815e4..68b3877af941 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -67,7 +67,7 @@ static unsigned long super_cache_scan(struct shrinker *shrink,
longdentries;
longinodes;
 
-   sb = container_of(shrink, struct super_block, s_shrink);
+   sb = shrink->private_data;
 
/*
 * Deadlock avoidance.  We may hold various FS locks, and we don't want
@@ -120,7 +120,7 @@ static unsigned long super_cache_count(struct shrinker 
*shrink,
struct super_block *sb;
longtotal_objects = 0;
 
-   sb = container_of(shrink, struct super_block, s_shrink);
+   sb = shrink->private_data;
 
/*
 * We don't call trylock_super() here as it is a scalability bottleneck,
@@ -182,7 +182,7 @@ static void destroy_unused_super(struct super_block *s)
security_sb_free(s);
put_user_ns(s->s_user_ns);
kfree(s->s_subtype);
-   free_prealloced_shrinker(&s->s_shrink);
+   shrinker_free(s->s_shrink);
/* no delays needed */
destroy_super_work(&s->destroy_work);
 }
@@ -259,16 +259,20 @@ static struct super_block *alloc_super(struct 
file_system_type *type, int flags,
s->s_time_min = TIME64_MIN;
s->s_time_max = TIME64_MAX;
 
-   s->s_shrink.seeks = DEFAULT_SEEKS;
-   s->s_shrink.scan_objects = super_cache_scan;
-   s->s_shrink.count_objects = super_cache_count;
-   s->s_shrink.batch = 1024;
-   s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE;
-   if (prealloc_shrinker(&s->s_shrink, "sb-%s", type->name))
+   s->s_shrink = shrinker_alloc(SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE,
+"sb-%s", type->name);
+   if (!s->s_shrink)
goto fail;
-   if (list_lru_init_memcg(&s->s_dentry_lru, &s->s_shrink))
+
+   s->s_shrink->seeks = DEFAULT_SEEKS;
+   s->s_shrink->scan_objects = super_cache_scan;
+   s->s_shrink->count_objects = super_cache_count;
+   s->s_shrink->batch = 1024;
+   s->s_shrink->private_data = s;
+
+   if (list_lru_init_memcg(&s->s_dentry_lru, s->s_shrink))
goto fail;
-   if (list_lru_init_memcg(&s->s_inode_lru, &s->s_shrink))
+   if (list_lru_init_memcg(&s->s_inode_lru, s->s_shrink))
goto fail;
return s;
 
@@ -326,7 +330,7 @@ void deactivate_locked_super(struct super_block *s)
 {
struct file_system_type *fs = s->s_type;
if (atomic_dec_and_test(&s->s_active)) {
-   unregister_shrinker(&s->s_shrink);
+   shrinker_free(s->s_shrink);
fs->kill_sb(s);
 
/*
@@ -599,7 +603,7 @@ struct super_block *sget_fc(struct fs_context *fc,
h

[PATCH v3 43/49] mm: shrinker: remove old APIs

2023-07-27 Thread Qi Zheng
Now no users are using the old APIs, just remove them.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 include/linux/shrinker.h |   7 --
 mm/shrinker.c| 143 ---
 2 files changed, 150 deletions(-)

diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index cc23ff0aee20..c55c07c3f0cb 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -103,13 +103,6 @@ struct shrinker *shrinker_alloc(unsigned int flags, const 
char *fmt, ...);
 void shrinker_register(struct shrinker *shrinker);
 void shrinker_free(struct shrinker *shrinker);
 
-extern int __printf(2, 3) prealloc_shrinker(struct shrinker *shrinker,
-   const char *fmt, ...);
-extern void register_shrinker_prepared(struct shrinker *shrinker);
-extern int __printf(2, 3) register_shrinker(struct shrinker *shrinker,
-   const char *fmt, ...);
-extern void unregister_shrinker(struct shrinker *shrinker);
-extern void free_prealloced_shrinker(struct shrinker *shrinker);
 extern void synchronize_shrinkers(void);
 
 #ifdef CONFIG_SHRINKER_DEBUG
diff --git a/mm/shrinker.c b/mm/shrinker.c
index 43a375f954f3..3ab301ff122d 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -651,149 +651,6 @@ void shrinker_free(struct shrinker *shrinker)
 }
 EXPORT_SYMBOL_GPL(shrinker_free);
 
-/*
- * Add a shrinker callback to be called from the vm.
- */
-static int __prealloc_shrinker(struct shrinker *shrinker)
-{
-   unsigned int size;
-   int err;
-
-   if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
-   err = prealloc_memcg_shrinker(shrinker);
-   if (err != -ENOSYS)
-   return err;
-
-   shrinker->flags &= ~SHRINKER_MEMCG_AWARE;
-   }
-
-   size = sizeof(*shrinker->nr_deferred);
-   if (shrinker->flags & SHRINKER_NUMA_AWARE)
-   size *= nr_node_ids;
-
-   shrinker->nr_deferred = kzalloc(size, GFP_KERNEL);
-   if (!shrinker->nr_deferred)
-   return -ENOMEM;
-
-   return 0;
-}
-
-#ifdef CONFIG_SHRINKER_DEBUG
-int prealloc_shrinker(struct shrinker *shrinker, const char *fmt, ...)
-{
-   va_list ap;
-   int err;
-
-   va_start(ap, fmt);
-   shrinker->name = kvasprintf_const(GFP_KERNEL, fmt, ap);
-   va_end(ap);
-   if (!shrinker->name)
-   return -ENOMEM;
-
-   err = __prealloc_shrinker(shrinker);
-   if (err) {
-   kfree_const(shrinker->name);
-   shrinker->name = NULL;
-   }
-
-   return err;
-}
-#else
-int prealloc_shrinker(struct shrinker *shrinker, const char *fmt, ...)
-{
-   return __prealloc_shrinker(shrinker);
-}
-#endif
-
-void free_prealloced_shrinker(struct shrinker *shrinker)
-{
-#ifdef CONFIG_SHRINKER_DEBUG
-   kfree_const(shrinker->name);
-   shrinker->name = NULL;
-#endif
-   if (shrinker->flags & SHRINKER_MEMCG_AWARE) {
-   down_write(&shrinker_rwsem);
-   unregister_memcg_shrinker(shrinker);
-   up_write(&shrinker_rwsem);
-   return;
-   }
-
-   kfree(shrinker->nr_deferred);
-   shrinker->nr_deferred = NULL;
-}
-
-void register_shrinker_prepared(struct shrinker *shrinker)
-{
-   down_write(&shrinker_rwsem);
-   list_add_tail(&shrinker->list, &shrinker_list);
-   shrinker->flags |= SHRINKER_REGISTERED;
-   shrinker_debugfs_add(shrinker);
-   up_write(&shrinker_rwsem);
-}
-
-static int __register_shrinker(struct shrinker *shrinker)
-{
-   int err = __prealloc_shrinker(shrinker);
-
-   if (err)
-   return err;
-   register_shrinker_prepared(shrinker);
-   return 0;
-}
-
-#ifdef CONFIG_SHRINKER_DEBUG
-int register_shrinker(struct shrinker *shrinker, const char *fmt, ...)
-{
-   va_list ap;
-   int err;
-
-   va_start(ap, fmt);
-   shrinker->name = kvasprintf_const(GFP_KERNEL, fmt, ap);
-   va_end(ap);
-   if (!shrinker->name)
-   return -ENOMEM;
-
-   err = __register_shrinker(shrinker);
-   if (err) {
-   kfree_const(shrinker->name);
-   shrinker->name = NULL;
-   }
-   return err;
-}
-#else
-int register_shrinker(struct shrinker *shrinker, const char *fmt, ...)
-{
-   return __register_shrinker(shrinker);
-}
-#endif
-EXPORT_SYMBOL(register_shrinker);
-
-/*
- * Remove one
- */
-void unregister_shrinker(struct shrinker *shrinker)
-{
-   struct dentry *debugfs_entry;
-   int debugfs_id;
-
-   if (!(shrinker->flags & SHRINKER_REGISTERED))
-   return;
-
-   down_write(&shrinker_rwsem);
-   list_del(&shrinker->list);
-   shrinker->flags &= ~SHRINKER_REGISTERED;
-   if (shrinker->flags & SHRINKER_MEMCG_AWARE)
-   unregister_memcg_shrinker(shrinker);
-   debugfs_entry = shrinker_debugfs_detach(shrinker, &debugfs_id);
-   up_write(&shrinker_rwsem);
-
-   shrinker_deb

[PATCH v3 44/49] drm/ttm: introduce pool_shrink_rwsem

2023-07-27 Thread Qi Zheng
Currently, the synchronize_shrinkers() is only used by TTM pool. It only
requires that no shrinkers run in parallel.

After we use RCU+refcount method to implement the lockless slab shrink,
we can not use shrinker_rwsem or synchronize_rcu() to guarantee that all
shrinker invocations have seen an update before freeing memory.

So we introduce a new pool_shrink_rwsem to implement a private
synchronize_shrinkers(), so as to achieve the same purpose.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 drivers/gpu/drm/ttm/ttm_pool.c | 15 +++
 include/linux/shrinker.h   |  2 --
 mm/shrinker.c  | 15 ---
 3 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index c9c9618c0dce..38b4c280725c 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -74,6 +74,7 @@ static struct ttm_pool_type global_dma32_uncached[MAX_ORDER + 
1];
 static spinlock_t shrinker_lock;
 static struct list_head shrinker_list;
 static struct shrinker *mm_shrinker;
+static DECLARE_RWSEM(pool_shrink_rwsem);
 
 /* Allocate pages of size 1 << order with the given gfp_flags */
 static struct page *ttm_pool_alloc_page(struct ttm_pool *pool, gfp_t gfp_flags,
@@ -317,6 +318,7 @@ static unsigned int ttm_pool_shrink(void)
unsigned int num_pages;
struct page *p;
 
+   down_read(&pool_shrink_rwsem);
spin_lock(&shrinker_lock);
pt = list_first_entry(&shrinker_list, typeof(*pt), shrinker_list);
list_move_tail(&pt->shrinker_list, &shrinker_list);
@@ -329,6 +331,7 @@ static unsigned int ttm_pool_shrink(void)
} else {
num_pages = 0;
}
+   up_read(&pool_shrink_rwsem);
 
return num_pages;
 }
@@ -572,6 +575,18 @@ void ttm_pool_init(struct ttm_pool *pool, struct device 
*dev,
 }
 EXPORT_SYMBOL(ttm_pool_init);
 
+/**
+ * synchronize_shrinkers - Wait for all running shrinkers to complete.
+ *
+ * This is useful to guarantee that all shrinker invocations have seen an
+ * update, before freeing memory, similar to rcu.
+ */
+static void synchronize_shrinkers(void)
+{
+   down_write(&pool_shrink_rwsem);
+   up_write(&pool_shrink_rwsem);
+}
+
 /**
  * ttm_pool_fini - Cleanup a pool
  *
diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index c55c07c3f0cb..025c8070dd86 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -103,8 +103,6 @@ struct shrinker *shrinker_alloc(unsigned int flags, const 
char *fmt, ...);
 void shrinker_register(struct shrinker *shrinker);
 void shrinker_free(struct shrinker *shrinker);
 
-extern void synchronize_shrinkers(void);
-
 #ifdef CONFIG_SHRINKER_DEBUG
 extern int __printf(2, 3) shrinker_debugfs_rename(struct shrinker *shrinker,
  const char *fmt, ...);
diff --git a/mm/shrinker.c b/mm/shrinker.c
index 3ab301ff122d..a27779ed3798 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -650,18 +650,3 @@ void shrinker_free(struct shrinker *shrinker)
kfree(shrinker);
 }
 EXPORT_SYMBOL_GPL(shrinker_free);
-
-/**
- * synchronize_shrinkers - Wait for all running shrinkers to complete.
- *
- * This is equivalent to calling unregister_shrink() and register_shrinker(),
- * but atomically and with less overhead. This is useful to guarantee that all
- * shrinker invocations have seen an update, before freeing memory, similar to
- * rcu.
- */
-void synchronize_shrinkers(void)
-{
-   down_write(&shrinker_rwsem);
-   up_write(&shrinker_rwsem);
-}
-EXPORT_SYMBOL(synchronize_shrinkers);
-- 
2.30.2



[PATCH v3 45/49] mm: shrinker: add a secondary array for shrinker_info::{map, nr_deferred}

2023-07-27 Thread Qi Zheng
Currently, we maintain two linear arrays per node per memcg, which are
shrinker_info::map and shrinker_info::nr_deferred. And we need to resize
them when the shrinker_nr_max is exceeded, that is, allocate a new array,
and then copy the old array to the new array, and finally free the old
array by RCU.

For shrinker_info::map, we do set_bit() under the RCU lock, so we may set
the value into the old map which is about to be freed. This may cause the
value set to be lost. The current solution is not to copy the old map when
resizing, but to set all the corresponding bits in the new map to 1. This
solves the data loss problem, but bring the overhead of more pointless
loops while doing memcg slab shrink.

For shrinker_info::nr_deferred, we will only modify it under the read lock
of shrinker_rwsem, so it will not run concurrently with the resizing. But
after we make memcg slab shrink lockless, there will be the same data loss
problem as shrinker_info::map, and we can't work around it like the map.

For such resizable arrays, the most straightforward idea is to change it
to xarray, like we did for list_lru [1]. We need to do xa_store() in the
list_lru_add()-->set_shrinker_bit(), but this will cause memory
allocation, and the list_lru_add() doesn't accept failure. A possible
solution is to pre-allocate, but the location of pre-allocation is not
well determined.

Therefore, this commit chooses to introduce a secondary array for
shrinker_info::{map, nr_deferred}, so that we only need to copy this
secondary array every time the size is resized. Then even if we get the
old secondary array under the RCU lock, the found map and nr_deferred are
also true, so no data is lost.

[1]. 
https://lore.kernel.org/all/20220228122126.37293-13-songmuc...@bytedance.com/

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
 include/linux/memcontrol.h |  12 +-
 include/linux/shrinker.h   |  17 +++
 mm/shrinker.c  | 250 +++--
 3 files changed, 172 insertions(+), 107 deletions(-)

diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index e765d1ff9cbb..2c9327d27c3b 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct mem_cgroup;
 struct obj_cgroup;
@@ -88,17 +89,6 @@ struct mem_cgroup_reclaim_iter {
unsigned int generation;
 };
 
-/*
- * Bitmap and deferred work of shrinker::id corresponding to memcg-aware
- * shrinkers, which have elements charged to this memcg.
- */
-struct shrinker_info {
-   struct rcu_head rcu;
-   atomic_long_t *nr_deferred;
-   unsigned long *map;
-   int map_nr_max;
-};
-
 struct lruvec_stats_percpu {
/* Local (CPU and cgroup) state */
long state[NR_VM_NODE_STAT_ITEMS];
diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index 025c8070dd86..eb342994675a 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -5,6 +5,23 @@
 #include 
 #include 
 
+#define SHRINKER_UNIT_BITS BITS_PER_LONG
+
+/*
+ * Bitmap and deferred work of shrinker::id corresponding to memcg-aware
+ * shrinkers, which have elements charged to the memcg.
+ */
+struct shrinker_info_unit {
+   atomic_long_t nr_deferred[SHRINKER_UNIT_BITS];
+   DECLARE_BITMAP(map, SHRINKER_UNIT_BITS);
+};
+
+struct shrinker_info {
+   struct rcu_head rcu;
+   int map_nr_max;
+   struct shrinker_info_unit *unit[];
+};
+
 /*
  * This struct is used to pass information from page reclaim to the shrinkers.
  * We consolidate the values for easier extension later.
diff --git a/mm/shrinker.c b/mm/shrinker.c
index a27779ed3798..1911c06b8af5 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -12,15 +12,50 @@ DECLARE_RWSEM(shrinker_rwsem);
 #ifdef CONFIG_MEMCG
 static int shrinker_nr_max;
 
-/* The shrinker_info is expanded in a batch of BITS_PER_LONG */
-static inline int shrinker_map_size(int nr_items)
+static inline int shrinker_unit_size(int nr_items)
 {
-   return (DIV_ROUND_UP(nr_items, BITS_PER_LONG) * sizeof(unsigned long));
+   return (DIV_ROUND_UP(nr_items, SHRINKER_UNIT_BITS) * sizeof(struct 
shrinker_info_unit *));
 }
 
-static inline int shrinker_defer_size(int nr_items)
+static inline void shrinker_unit_free(struct shrinker_info *info, int start)
 {
-   return (round_up(nr_items, BITS_PER_LONG) * sizeof(atomic_long_t));
+   struct shrinker_info_unit **unit;
+   int nr, i;
+
+   if (!info)
+   return;
+
+   unit = info->unit;
+   nr = DIV_ROUND_UP(info->map_nr_max, SHRINKER_UNIT_BITS);
+
+   for (i = start; i < nr; i++) {
+   if (!unit[i])
+   break;
+
+   kvfree(unit[i]);
+   unit[i] = NULL;
+   }
+}
+
+static inline int shrinker_unit_alloc(struct shrinker_info *new,
+  struct shrinker_info *old, int nid)
+{
+   struct shrinker_info_unit *unit;
+   int nr = DIV_ROUND_UP

[PATCH v3 46/49] mm: shrinker: make global slab shrink lockless

2023-07-27 Thread Qi Zheng
The shrinker_rwsem is a global read-write lock in shrinkers subsystem,
which protects most operations such as slab shrink, registration and
unregistration of shrinkers, etc. This can easily cause problems in the
following cases.

1) When the memory pressure is high and there are many filesystems
   mounted or unmounted at the same time, slab shrink will be affected
   (down_read_trylock() failed).

   Such as the real workload mentioned by Kirill Tkhai:

   ```
   One of the real workloads from my experience is start
   of an overcommitted node containing many starting
   containers after node crash (or many resuming containers
   after reboot for kernel update). In these cases memory
   pressure is huge, and the node goes round in long reclaim.
   ```

2) If a shrinker is blocked (such as the case mentioned
   in [1]) and a writer comes in (such as mount a fs),
   then this writer will be blocked and cause all
   subsequent shrinker-related operations to be blocked.

Even if there is no competitor when shrinking slab, there may still be a
problem. The down_read_trylock() may become a perf hotspot with frequent
calls to shrink_slab(). Because of the poor multicore scalability of
atomic operations, this can lead to a significant drop in IPC
(instructions per cycle).

We used to implement the lockless slab shrink with SRCU [2], but then
kernel test robot reported -88.8% regression in
stress-ng.ramfs.ops_per_sec test case [3], so we reverted it [4].

This commit uses the refcount+RCU method [5] proposed by Dave Chinner
to re-implement the lockless global slab shrink. The memcg slab shrink is
handled in the subsequent patch.

For now, all shrinker instances are converted to dynamically allocated and
will be freed by call_rcu(). So we can use rcu_read_{lock,unlock}() to
ensure that the shrinker instance is valid.

And the shrinker instance will not be run again after unregistration. So
the structure that records the pointer of shrinker instance can be safely
freed without waiting for the RCU read-side critical section.

In this way, while we implement the lockless slab shrink, we don't need to
be blocked in unregister_shrinker().

The following are the test results:

stress-ng --timeout 60 --times --verify --metrics-brief --ramfs 9 &

1) Before applying this patchset:

setting to a 60 second run per stressor
dispatching hogs: 9 ramfs
stressor   bogo ops real time  usr time  sys time   bogo ops/s bogo 
ops/s
  (secs)(secs)(secs)   (real time) (usr+sys 
time)
ramfs735238 60.00 12.37363.70 12253.05
1955.08
for a 60.01s run time:
   1440.27s available CPU time
 12.36s user time   (  0.86%)
363.70s system time ( 25.25%)
376.06s total time  ( 26.11%)
load average: 10.79 4.47 1.69
passed: 9: ramfs (9)
failed: 0
skipped: 0
successful run completed in 60.01s (1 min, 0.01 secs)

2) After applying this patchset:

setting to a 60 second run per stressor
dispatching hogs: 9 ramfs
stressor   bogo ops real time  usr time  sys time   bogo ops/s bogo 
ops/s
  (secs)(secs)(secs)   (real time) (usr+sys 
time)
ramfs746698 60.00 12.45376.16 12444.02
1921.47
for a 60.01s run time:
   1440.28s available CPU time
 12.44s user time   (  0.86%)
376.16s system time ( 26.12%)
388.60s total time  ( 26.98%)
load average: 9.01 3.85 1.49
passed: 9: ramfs (9)
failed: 0
skipped: 0
successful run completed in 60.01s (1 min, 0.01 secs)

We can see that the ops/s has hardly changed.

[1]. 
https://lore.kernel.org/lkml/20191129214541.3110-1-ptikhomi...@virtuozzo.com/
[2]. 
https://lore.kernel.org/lkml/20230313112819.38938-1-zhengqi.a...@bytedance.com/
[3]. https://lore.kernel.org/lkml/202305230837.db2c233f-yujie@intel.com/
[4]. https://lore.kernel.org/all/20230609081518.3039120-1-qi.zh...@linux.dev/
[5]. https://lore.kernel.org/lkml/zijhou1d55d4h...@dread.disaster.area/

Signed-off-by: Qi Zheng 
---
 include/linux/shrinker.h | 17 ++
 mm/shrinker.c| 70 +---
 2 files changed, 68 insertions(+), 19 deletions(-)

diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index eb342994675a..f06225f18531 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -4,6 +4,8 @@
 
 #include 
 #include 
+#include 
+#include 
 
 #define SHRINKER_UNIT_BITS BITS_PER_LONG
 
@@ -87,6 +89,10 @@ struct shrinker {
int seeks;  /* seeks to recreate an obj */
unsigned flags;
 
+   refcount_t refcount;
+   struct completion done;
+   struct rcu_head rcu;
+
void *private_data;
 
/* These are for internal use */
@@ -120,6 +126,17 @@ struct shrinker *shrinker_alloc(unsigned int flags, const 
char *fmt, ...);
 void shrinker_register(struct shrinker *shrinker);
 void shrinker_free(struct shrinker *shrinker);
 
+static inline bool shrinker_try_get(struct shrinker *shrinker)
+

[PATCH v3 47/49] mm: shrinker: make memcg slab shrink lockless

2023-07-27 Thread Qi Zheng
Like global slab shrink, this commit also uses refcount+RCU method to make
memcg slab shrink lockless.

Use the following script to do slab shrink stress test:

```

DIR="/root/shrinker/memcg/mnt"

do_create()
{
mkdir -p /sys/fs/cgroup/memory/test
echo 4G > /sys/fs/cgroup/memory/test/memory.limit_in_bytes
for i in `seq 0 $1`;
do
mkdir -p /sys/fs/cgroup/memory/test/$i;
echo $$ > /sys/fs/cgroup/memory/test/$i/cgroup.procs;
mkdir -p $DIR/$i;
done
}

do_mount()
{
for i in `seq $1 $2`;
do
mount -t tmpfs $i $DIR/$i;
done
}

do_touch()
{
for i in `seq $1 $2`;
do
echo $$ > /sys/fs/cgroup/memory/test/$i/cgroup.procs;
dd if=/dev/zero of=$DIR/$i/file$i bs=1M count=1 &
done
}

case "$1" in
  touch)
do_touch $2 $3
;;
  test)
do_create 4000
do_mount 0 4000
do_touch 0 3000
;;
  *)
exit 1
;;
esac
```

Save the above script, then run test and touch commands. Then we can use
the following perf command to view hotspots:

perf top -U -F 999

1) Before applying this patchset:

  40.44%  [kernel][k] down_read_trylock
  17.59%  [kernel][k] up_read
  13.64%  [kernel][k] pv_native_safe_halt
  11.90%  [kernel][k] shrink_slab
   8.21%  [kernel][k] idr_find
   2.71%  [kernel][k] _find_next_bit
   1.36%  [kernel][k] shrink_node
   0.81%  [kernel][k] shrink_lruvec
   0.80%  [kernel][k] __radix_tree_lookup
   0.50%  [kernel][k] do_shrink_slab
   0.21%  [kernel][k] list_lru_count_one
   0.16%  [kernel][k] mem_cgroup_iter

2) After applying this patchset:

  60.17%  [kernel]   [k] shrink_slab
  20.42%  [kernel]   [k] pv_native_safe_halt
   3.03%  [kernel]   [k] do_shrink_slab
   2.73%  [kernel]   [k] shrink_node
   2.27%  [kernel]   [k] shrink_lruvec
   2.00%  [kernel]   [k] __rcu_read_unlock
   1.92%  [kernel]   [k] mem_cgroup_iter
   0.98%  [kernel]   [k] __rcu_read_lock
   0.91%  [kernel]   [k] osq_lock
   0.63%  [kernel]   [k] mem_cgroup_calculate_protection
   0.55%  [kernel]   [k] shrinker_put
   0.46%  [kernel]   [k] list_lru_count_one

We can see that the first perf hotspot becomes shrink_slab, which is what
we expect.

Signed-off-by: Qi Zheng 
---
 mm/shrinker.c | 80 ++-
 1 file changed, 54 insertions(+), 26 deletions(-)

diff --git a/mm/shrinker.c b/mm/shrinker.c
index d318f5621862..fee6f62904fb 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -107,6 +107,12 @@ static struct shrinker_info 
*shrinker_info_protected(struct mem_cgroup *memcg,
 lockdep_is_held(&shrinker_rwsem));
 }
 
+static struct shrinker_info *shrinker_info_rcu(struct mem_cgroup *memcg,
+  int nid)
+{
+   return rcu_dereference(memcg->nodeinfo[nid]->shrinker_info);
+}
+
 static int expand_one_shrinker_info(struct mem_cgroup *memcg, int new_size,
int old_size, int new_nr_max)
 {
@@ -198,7 +204,7 @@ void set_shrinker_bit(struct mem_cgroup *memcg, int nid, 
int shrinker_id)
struct shrinker_info_unit *unit;
 
rcu_read_lock();
-   info = rcu_dereference(memcg->nodeinfo[nid]->shrinker_info);
+   info = shrinker_info_rcu(memcg, nid);
unit = info->unit[shriner_id_to_index(shrinker_id)];
if (!WARN_ON_ONCE(shrinker_id >= info->map_nr_max)) {
/* Pairs with smp mb in shrink_slab() */
@@ -211,7 +217,7 @@ void set_shrinker_bit(struct mem_cgroup *memcg, int nid, 
int shrinker_id)
 
 static DEFINE_IDR(shrinker_idr);
 
-static int prealloc_memcg_shrinker(struct shrinker *shrinker)
+static int shrinker_memcg_alloc(struct shrinker *shrinker)
 {
int id, ret = -ENOMEM;
 
@@ -219,7 +225,6 @@ static int prealloc_memcg_shrinker(struct shrinker 
*shrinker)
return -ENOSYS;
 
down_write(&shrinker_rwsem);
-   /* This may call shrinker, so it must use down_read_trylock() */
id = idr_alloc(&shrinker_idr, shrinker, 0, 0, GFP_KERNEL);
if (id < 0)
goto unlock;
@@ -237,7 +242,7 @@ static int prealloc_memcg_shrinker(struct shrinker 
*shrinker)
return ret;
 }
 
-static void unregister_memcg_shrinker(struct shrinker *shrinker)
+static void shrinker_memcg_remove(struct shrinker *shrinker)
 {
int id = shrinker->id;
 
@@ -253,10 +258,15 @@ static long xchg_nr_deferred_memcg(int nid, struct 
shrinker *shrinker,
 {
struct shrinker_info *info;
struct shrinker_info_unit *unit;
+   long nr_deferred;
 
-   info = shrinker_info_protected(memcg, nid);
+   rcu_read_lock();
+   info = shrinker_info_rcu(memcg, nid);
unit = info->unit[shriner_id_to_index(s

[PATCH v3 48/49] mm: shrinker: hold write lock to reparent shrinker nr_deferred

2023-07-27 Thread Qi Zheng
For now, reparent_shrinker_deferred() is the only holder of read lock of
shrinker_rwsem. And it already holds the global cgroup_mutex, so it will
not be called in parallel.

Therefore, in order to convert shrinker_rwsem to shrinker_mutex later,
here we change to hold the write lock of shrinker_rwsem to reparent.

Signed-off-by: Qi Zheng 
---
 mm/shrinker.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/shrinker.c b/mm/shrinker.c
index fee6f62904fb..a12dede5d21f 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -299,7 +299,7 @@ void reparent_shrinker_deferred(struct mem_cgroup *memcg)
parent = root_mem_cgroup;
 
/* Prevent from concurrent shrinker_info expand */
-   down_read(&shrinker_rwsem);
+   down_write(&shrinker_rwsem);
for_each_node(nid) {
child_info = shrinker_info_protected(memcg, nid);
parent_info = shrinker_info_protected(parent, nid);
@@ -312,7 +312,7 @@ void reparent_shrinker_deferred(struct mem_cgroup *memcg)
}
}
}
-   up_read(&shrinker_rwsem);
+   up_write(&shrinker_rwsem);
 }
 #else
 static int shrinker_memcg_alloc(struct shrinker *shrinker)
-- 
2.30.2



[PATCH v3 49/49] mm: shrinker: convert shrinker_rwsem to mutex

2023-07-27 Thread Qi Zheng
Now there are no readers of shrinker_rwsem, so we can simply replace it
with mutex lock.

Signed-off-by: Qi Zheng 
---
 drivers/md/dm-cache-metadata.c |  2 +-
 fs/super.c |  2 +-
 mm/shrinker.c  | 28 ++--
 mm/shrinker_debug.c| 14 +++---
 4 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index acffed750e3e..9e0c69958587 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -1828,7 +1828,7 @@ int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
 * Replacement block manager (new_bm) is created and old_bm destroyed 
outside of
 * cmd root_lock to avoid ABBA deadlock that would result (due to 
life-cycle of
 * shrinker associated with the block manager's bufio client vs cmd 
root_lock).
-* - must take shrinker_rwsem without holding cmd->root_lock
+* - must take shrinker_mutex without holding cmd->root_lock
 */
new_bm = dm_block_manager_create(cmd->bdev, 
DM_CACHE_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
 CACHE_MAX_CONCURRENT_LOCKS);
diff --git a/fs/super.c b/fs/super.c
index 68b3877af941..fdde72e2a357 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -54,7 +54,7 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = {
  * One thing we have to be careful of with a per-sb shrinker is that we don't
  * drop the last active reference to the superblock from within the shrinker.
  * If that happens we could trigger unregistering the shrinker from within the
- * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we
+ * shrinker path and that leads to deadlock on the shrinker_mutex. Hence we
  * take a passive reference to the superblock to avoid this from occurring.
  */
 static unsigned long super_cache_scan(struct shrinker *shrink,
diff --git a/mm/shrinker.c b/mm/shrinker.c
index a12dede5d21f..3d44a335ef3c 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -8,7 +8,7 @@
 #include "internal.h"
 
 LIST_HEAD(shrinker_list);
-DECLARE_RWSEM(shrinker_rwsem);
+DEFINE_MUTEX(shrinker_mutex);
 
 #ifdef CONFIG_MEMCG
 static int shrinker_nr_max;
@@ -80,7 +80,7 @@ int alloc_shrinker_info(struct mem_cgroup *memcg)
int nid, ret = 0;
int array_size = 0;
 
-   down_write(&shrinker_rwsem);
+   mutex_lock(&shrinker_mutex);
array_size = shrinker_unit_size(shrinker_nr_max);
for_each_node(nid) {
info = kvzalloc_node(sizeof(*info) + array_size, GFP_KERNEL, 
nid);
@@ -91,7 +91,7 @@ int alloc_shrinker_info(struct mem_cgroup *memcg)
goto err;
rcu_assign_pointer(memcg->nodeinfo[nid]->shrinker_info, info);
}
-   up_write(&shrinker_rwsem);
+   mutex_unlock(&shrinker_mutex);
 
return ret;
 
@@ -104,7 +104,7 @@ static struct shrinker_info *shrinker_info_protected(struct 
mem_cgroup *memcg,
 int nid)
 {
return rcu_dereference_protected(memcg->nodeinfo[nid]->shrinker_info,
-lockdep_is_held(&shrinker_rwsem));
+lockdep_is_held(&shrinker_mutex));
 }
 
 static struct shrinker_info *shrinker_info_rcu(struct mem_cgroup *memcg,
@@ -161,7 +161,7 @@ static int expand_shrinker_info(int new_id)
if (!root_mem_cgroup)
goto out;
 
-   lockdep_assert_held(&shrinker_rwsem);
+   lockdep_assert_held(&shrinker_mutex);
 
new_size = shrinker_unit_size(new_nr_max);
old_size = shrinker_unit_size(shrinker_nr_max);
@@ -224,7 +224,7 @@ static int shrinker_memcg_alloc(struct shrinker *shrinker)
if (mem_cgroup_disabled())
return -ENOSYS;
 
-   down_write(&shrinker_rwsem);
+   mutex_lock(&shrinker_mutex);
id = idr_alloc(&shrinker_idr, shrinker, 0, 0, GFP_KERNEL);
if (id < 0)
goto unlock;
@@ -238,7 +238,7 @@ static int shrinker_memcg_alloc(struct shrinker *shrinker)
shrinker->id = id;
ret = 0;
 unlock:
-   up_write(&shrinker_rwsem);
+   mutex_unlock(&shrinker_mutex);
return ret;
 }
 
@@ -248,7 +248,7 @@ static void shrinker_memcg_remove(struct shrinker *shrinker)
 
BUG_ON(id < 0);
 
-   lockdep_assert_held(&shrinker_rwsem);
+   lockdep_assert_held(&shrinker_mutex);
 
idr_remove(&shrinker_idr, id);
 }
@@ -299,7 +299,7 @@ void reparent_shrinker_deferred(struct mem_cgroup *memcg)
parent = root_mem_cgroup;
 
/* Prevent from concurrent shrinker_info expand */
-   down_write(&shrinker_rwsem);
+   mutex_lock(&shrinker_mutex);
for_each_node(nid) {
child_info = shrinker_info_protected(memcg, nid);
parent_info = shrinker_info_protected(parent, nid);
@@ -312,7 +312,7 @@ void reparent_shrinker_deferred(struct 

Re: [PATCH v3 28/49] dm zoned: dynamically allocate the dm-zoned-meta shrinker

2023-07-27 Thread Damien Le Moal
On 7/27/23 17:04, Qi Zheng wrote:
> In preparation for implementing lockless slab shrink, use new APIs to
> dynamically allocate the dm-zoned-meta shrinker, so that it can be freed
> asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
> read-side critical section when releasing the struct dmz_metadata.
> 
> Signed-off-by: Qi Zheng 
> Reviewed-by: Muchun Song 
> ---
>  drivers/md/dm-zoned-metadata.c | 28 
>  1 file changed, 16 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
> index 9d3cca8e3dc9..0bcb26a43578 100644
> --- a/drivers/md/dm-zoned-metadata.c
> +++ b/drivers/md/dm-zoned-metadata.c
> @@ -187,7 +187,7 @@ struct dmz_metadata {
>   struct rb_root  mblk_rbtree;
>   struct list_headmblk_lru_list;
>   struct list_headmblk_dirty_list;
> - struct shrinker mblk_shrinker;
> + struct shrinker *mblk_shrinker;
>  
>   /* Zone allocation management */
>   struct mutexmap_lock;
> @@ -615,7 +615,7 @@ static unsigned long dmz_shrink_mblock_cache(struct 
> dmz_metadata *zmd,
>  static unsigned long dmz_mblock_shrinker_count(struct shrinker *shrink,
>  struct shrink_control *sc)
>  {
> - struct dmz_metadata *zmd = container_of(shrink, struct dmz_metadata, 
> mblk_shrinker);
> + struct dmz_metadata *zmd = shrink->private_data;
>  
>   return atomic_read(&zmd->nr_mblks);
>  }
> @@ -626,7 +626,7 @@ static unsigned long dmz_mblock_shrinker_count(struct 
> shrinker *shrink,
>  static unsigned long dmz_mblock_shrinker_scan(struct shrinker *shrink,
> struct shrink_control *sc)
>  {
> - struct dmz_metadata *zmd = container_of(shrink, struct dmz_metadata, 
> mblk_shrinker);
> + struct dmz_metadata *zmd = shrink->private_data;
>   unsigned long count;
>  
>   spin_lock(&zmd->mblk_lock);
> @@ -2936,19 +2936,23 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
>*/
>   zmd->min_nr_mblks = 2 + zmd->nr_map_blocks + zmd->zone_nr_bitmap_blocks 
> * 16;
>   zmd->max_nr_mblks = zmd->min_nr_mblks + 512;
> - zmd->mblk_shrinker.count_objects = dmz_mblock_shrinker_count;
> - zmd->mblk_shrinker.scan_objects = dmz_mblock_shrinker_scan;
> - zmd->mblk_shrinker.seeks = DEFAULT_SEEKS;
>  
>   /* Metadata cache shrinker */
> - ret = register_shrinker(&zmd->mblk_shrinker, "dm-zoned-meta:(%u:%u)",
> - MAJOR(dev->bdev->bd_dev),
> - MINOR(dev->bdev->bd_dev));
> - if (ret) {
> - dmz_zmd_err(zmd, "Register metadata cache shrinker failed");
> + zmd->mblk_shrinker = shrinker_alloc(0,  "dm-zoned-meta:(%u:%u)",
> + MAJOR(dev->bdev->bd_dev),
> + MINOR(dev->bdev->bd_dev));
> + if (!zmd->mblk_shrinker) {
> + dmz_zmd_err(zmd, "Allocate metadata cache shrinker failed");

ret is not set here, so dmz_ctr_metadata() will return success. You need to add:
ret = -ENOMEM;
or something.
>   goto err;
>   }
>  
> + zmd->mblk_shrinker->count_objects = dmz_mblock_shrinker_count;
> + zmd->mblk_shrinker->scan_objects = dmz_mblock_shrinker_scan;
> + zmd->mblk_shrinker->seeks = DEFAULT_SEEKS;
> + zmd->mblk_shrinker->private_data = zmd;
> +
> + shrinker_register(zmd->mblk_shrinker);

I fail to see how this new shrinker API is better... Why isn't there a
shrinker_alloc_and_register() function ? That would avoid adding all this code
all over the place as the new API call would be very similar to the current
shrinker_register() call with static allocation.

> +
>   dmz_zmd_info(zmd, "DM-Zoned metadata version %d", zmd->sb_version);
>   for (i = 0; i < zmd->nr_devs; i++)
>   dmz_print_dev(zmd, i);
> @@ -2995,7 +2999,7 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
>   */
>  void dmz_dtr_metadata(struct dmz_metadata *zmd)
>  {
> - unregister_shrinker(&zmd->mblk_shrinker);
> + shrinker_free(zmd->mblk_shrinker);
>   dmz_cleanup_metadata(zmd);
>   kfree(zmd);
>  }

-- 
Damien Le Moal
Western Digital Research



Re: [PATCH] drm/tests: Remove CONFIG_DRM_FBDEV_EMULATION on .kunitconfig

2023-07-27 Thread Arnd Bergmann
On Thu, Jul 27, 2023, at 00:03, Arthur Grillo wrote:
> Using the `kunit_tool` with the command:
>
> tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm/tests/
>
> Lead to this error[0]. Fix it by expliciting removing the
> CONFIG_DRM_FBDEV_EMULATION.
>
> [0]
> ERROR:root:
> WARNING: unmet direct dependencies detected for FRAMEBUFFER_CONSOLE
>   Depends on [n]: VT [=n] && FB_CORE [=y] && !UML [=y]
>   Selected by [y]:
>   - DRM_FBDEV_EMULATION [=y] && HAS_IOMEM [=y] && DRM [=y] && !EXPERT [=n]
>

I think that's a bug in the Kconfig files that should be fixed
by enforcing the correct set of dependencies. I have not encountered
this in my randconfig builds (with a lot of other fixes applied)

In linux-next, CONFIG_VT cannot be disabled if CONFIG_EXPERT=n,
so this does not happen.

> diff --git a/drivers/gpu/drm/tests/.kunitconfig 
> b/drivers/gpu/drm/tests/.kunitconfig
> index 6ec04b4c979d..c50b5a12faae 100644
> --- a/drivers/gpu/drm/tests/.kunitconfig
> +++ b/drivers/gpu/drm/tests/.kunitconfig
> @@ -1,3 +1,4 @@
>  CONFIG_KUNIT=y
>  CONFIG_DRM=y
>  CONFIG_DRM_KUNIT_TEST=y
> +CONFIG_DRM_FBDEV_EMULATION=n
>
> base-commit: 45b58669e532bcdfd6e1593488d1f23eabd55428

Changing the local config should not be required after fixing
the Kconfig files.

Arnd


Re: [PATCH 4/6] drm/msm/mdss: populate missing data

2023-07-27 Thread Dmitry Baryshkov
On Thu, 27 Jul 2023 at 02:14, Abhinav Kumar  wrote:
>
>
>
> On 7/26/2023 3:58 PM, Dmitry Baryshkov wrote:
> > On Thu, 27 Jul 2023 at 01:30, Abhinav Kumar  
> > wrote:
> >>
> >>
> >>
> >> On 5/21/2023 10:10 AM, Dmitry Baryshkov wrote:
> >>> As we are going to use MDSS data for DPU programming, populate missing
> >>> MDSS data. The UBWC 1.0 and no UBWC cases do not require MDSS
> >>> programming, so skip them.
> >>>
> >>
> >> Can you pls point me to the downstream references you used for msm8998?
> >
> > msm-3.18, drivers/video/msm/mdss/mdss_mdp.c
> >
> > See the function mdss_mdp_hw_rev_caps_init(). It sets has_ubwc for MDP
> > 1.07 (msm8996), 1.14 (msm8937) / 1.16  (msm8953) and 3.0 (msm8998).
> >
>
> It sets has_ubwc but I still cannot locate where it says version is 1.0.
> Because the 0x58 register reads 0 and not 1 for msm8998.

What would be the version then? 0.0 sounds strange. I'm yet to check
whether UBWC works on 8996 / 8998.

> >> Was that just taken from catalog? If so I would ask for the reference
> >> for the catalog too.
> >>
> >> As per the register the decoder version is 0x0 and not 1.
> >>
> >> Even encoder version is 0 from what i see and not 1. Thats why a
> >> dec_version of UBWC_1_0 is not doing anything i assume.
> >>


-- 
With best wishes
Dmitry


Re: [PATCH 5/6] drm/msm/dpu: use MDSS data for programming SSPP

2023-07-27 Thread Dmitry Baryshkov
On Thu, 27 Jul 2023 at 02:20, Abhinav Kumar  wrote:
>
>
>
> On 5/21/2023 10:10 AM, Dmitry Baryshkov wrote:
> > Switch to using data from MDSS driver to program the SSPP fetch and UBWC
> > configuration.
> >
> > Signed-off-by: Dmitry Baryshkov 
> > ---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c | 18 +++---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h |  7 +--
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 16 +++-
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h |  1 +
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c  |  3 ++-
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h  |  2 ++
> >   6 files changed, 36 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c 
> > b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
> > index cf70a9bd1034..bfd82c2921af 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
> > @@ -8,6 +8,8 @@
> >   #include "dpu_hw_sspp.h"
> >   #include "dpu_kms.h"
> >
> > +#include "msm_mdss.h"
> > +
> >   #include 
> >
> >   #define DPU_FETCH_CONFIG_RESET_VALUE   0x0087
> > @@ -308,26 +310,26 @@ static void dpu_hw_sspp_setup_format(struct 
> > dpu_sw_pipe *pipe,
> >   DPU_REG_WRITE(c, SSPP_FETCH_CONFIG,
> >   DPU_FETCH_CONFIG_RESET_VALUE |
> >   ctx->ubwc->highest_bank_bit << 18);
>
> Does this needs to be protected with if ctx->ubwc check?

Yes... And it should have been already.

>
> > - switch (ctx->ubwc->ubwc_version) {
> > - case DPU_HW_UBWC_VER_10:
> > + switch (ctx->ubwc->ubwc_enc_version) {
> > + case UBWC_1_0:
>
> The values of UBWC_x_x dont match the values of DPU_HW_UBWC_VER_xx.
> What was the reason for the catalog to go with DPU_HW_UBWC_VER_xx in the
> catalog for the encoder version in the first place? Because looking at
> the registers UBWC_x_x is the correct value.
>
> If we cannot find the reason why, it should be noted in the commit text
> that the values we are using did change.

Huh? This is just an enum. It isn't a part of uABI, nor it is written
to the hardware.

>
> >   fast_clear = fmt->alpha_enable ? BIT(31) : 0;
> >   DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
> >   fast_clear | (ctx->ubwc->ubwc_swizzle 
> > & 0x1) |
> >   BIT(8) |
> >   (ctx->ubwc->highest_bank_bit << 4));
> >   break;
> > - case DPU_HW_UBWC_VER_20:
> > + case UBWC_2_0:
> >   fast_clear = fmt->alpha_enable ? BIT(31) : 0;
> >   DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
> >   fast_clear | 
> > (ctx->ubwc->ubwc_swizzle) |
> >   (ctx->ubwc->highest_bank_bit << 4));
> >   break;
> > - case DPU_HW_UBWC_VER_30:
> > + case UBWC_3_0:
> >   DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
> >   BIT(30) | (ctx->ubwc->ubwc_swizzle) |
> >   (ctx->ubwc->highest_bank_bit << 4));
> >   break;
> > - case DPU_HW_UBWC_VER_40:
> > + case UBWC_4_0:
> >   DPU_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
> >   DPU_FORMAT_IS_YUV(fmt) ? 0 : BIT(30));
> >   break;
> > @@ -793,7 +795,9 @@ static const struct dpu_sspp_cfg *_sspp_offset(enum 
> > dpu_sspp sspp,
> >   }
> >
> >   struct dpu_hw_sspp *dpu_hw_sspp_init(enum dpu_sspp idx,
> > - void __iomem *addr, const struct dpu_mdss_cfg *catalog)
> > +  void __iomem *addr,
> > +  const struct dpu_mdss_cfg *catalog,
> > +  const struct msm_mdss_data *mdss_data)
> >   {
> >   struct dpu_hw_sspp *hw_pipe;
> >   const struct dpu_sspp_cfg *cfg;
> > @@ -813,7 +817,7 @@ struct dpu_hw_sspp *dpu_hw_sspp_init(enum dpu_sspp idx,
> >
> >   /* Assign ops */
> >   hw_pipe->catalog = catalog;
> > - hw_pipe->ubwc = catalog->ubwc;
> > + hw_pipe->ubwc = mdss_data;
> >   hw_pipe->idx = idx;
> >   hw_pipe->cap = cfg;
> >   _setup_layer_ops(hw_pipe, hw_pipe->cap->features);
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h 
> > b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
> > index 74b98b6b3bc3..8d4ae9d24674 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
> > @@ -351,7 +351,7 @@ struct dpu_hw_sspp {
> >   struct dpu_hw_blk base;
> >   struct dpu_hw_blk_reg_map hw;
> >   const struct dpu_mdss_cfg *catalog;
> > - const struct dpu_ubwc_cfg *ubwc;
> > + const struct msm_mdss_data *ubwc;
> >
>

Re: [PATCH v3 28/49] dm zoned: dynamically allocate the dm-zoned-meta shrinker

2023-07-27 Thread Qi Zheng

Hi,

On 2023/7/27 16:30, Damien Le Moal wrote:

On 7/27/23 17:04, Qi Zheng wrote:

In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the dm-zoned-meta shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct dmz_metadata.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
  drivers/md/dm-zoned-metadata.c | 28 
  1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index 9d3cca8e3dc9..0bcb26a43578 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -187,7 +187,7 @@ struct dmz_metadata {
struct rb_root  mblk_rbtree;
struct list_headmblk_lru_list;
struct list_headmblk_dirty_list;
-   struct shrinker mblk_shrinker;
+   struct shrinker *mblk_shrinker;
  
  	/* Zone allocation management */

struct mutexmap_lock;
@@ -615,7 +615,7 @@ static unsigned long dmz_shrink_mblock_cache(struct 
dmz_metadata *zmd,
  static unsigned long dmz_mblock_shrinker_count(struct shrinker *shrink,
   struct shrink_control *sc)
  {
-   struct dmz_metadata *zmd = container_of(shrink, struct dmz_metadata, 
mblk_shrinker);
+   struct dmz_metadata *zmd = shrink->private_data;
  
  	return atomic_read(&zmd->nr_mblks);

  }
@@ -626,7 +626,7 @@ static unsigned long dmz_mblock_shrinker_count(struct 
shrinker *shrink,
  static unsigned long dmz_mblock_shrinker_scan(struct shrinker *shrink,
  struct shrink_control *sc)
  {
-   struct dmz_metadata *zmd = container_of(shrink, struct dmz_metadata, 
mblk_shrinker);
+   struct dmz_metadata *zmd = shrink->private_data;
unsigned long count;
  
  	spin_lock(&zmd->mblk_lock);

@@ -2936,19 +2936,23 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
 */
zmd->min_nr_mblks = 2 + zmd->nr_map_blocks + zmd->zone_nr_bitmap_blocks 
* 16;
zmd->max_nr_mblks = zmd->min_nr_mblks + 512;
-   zmd->mblk_shrinker.count_objects = dmz_mblock_shrinker_count;
-   zmd->mblk_shrinker.scan_objects = dmz_mblock_shrinker_scan;
-   zmd->mblk_shrinker.seeks = DEFAULT_SEEKS;
  
  	/* Metadata cache shrinker */

-   ret = register_shrinker(&zmd->mblk_shrinker, "dm-zoned-meta:(%u:%u)",
-   MAJOR(dev->bdev->bd_dev),
-   MINOR(dev->bdev->bd_dev));
-   if (ret) {
-   dmz_zmd_err(zmd, "Register metadata cache shrinker failed");
+   zmd->mblk_shrinker = shrinker_alloc(0,  "dm-zoned-meta:(%u:%u)",
+   MAJOR(dev->bdev->bd_dev),
+   MINOR(dev->bdev->bd_dev));
+   if (!zmd->mblk_shrinker) {
+   dmz_zmd_err(zmd, "Allocate metadata cache shrinker failed");


ret is not set here, so dmz_ctr_metadata() will return success. You need to add:
ret = -ENOMEM;
or something.


Indeed, will fix.


goto err;
}
  
+	zmd->mblk_shrinker->count_objects = dmz_mblock_shrinker_count;

+   zmd->mblk_shrinker->scan_objects = dmz_mblock_shrinker_scan;
+   zmd->mblk_shrinker->seeks = DEFAULT_SEEKS;
+   zmd->mblk_shrinker->private_data = zmd;
+
+   shrinker_register(zmd->mblk_shrinker);


I fail to see how this new shrinker API is better... Why isn't there a
shrinker_alloc_and_register() function ? That would avoid adding all this code
all over the place as the new API call would be very similar to the current
shrinker_register() call with static allocation.


In some registration scenarios, memory needs to be allocated in advance.
So we continue to use the previous prealloc/register_prepared()
algorithm. The shrinker_alloc_and_register() is just a helper function
that combines the two, and this increases the number of APIs that
shrinker exposes to the outside, so I choose not to add this helper.

Thanks,
Qi




+
dmz_zmd_info(zmd, "DM-Zoned metadata version %d", zmd->sb_version);
for (i = 0; i < zmd->nr_devs; i++)
dmz_print_dev(zmd, i);
@@ -2995,7 +2999,7 @@ int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev,
   */
  void dmz_dtr_metadata(struct dmz_metadata *zmd)
  {
-   unregister_shrinker(&zmd->mblk_shrinker);
+   shrinker_free(zmd->mblk_shrinker);
dmz_cleanup_metadata(zmd);
kfree(zmd);
  }




Re: [PATCH v3 15/49] nfs: dynamically allocate the nfs-acl shrinker

2023-07-27 Thread Qi Zheng




On 2023/7/27 16:04, Qi Zheng wrote:

Use new APIs to dynamically allocate the nfs-acl shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
  fs/nfs/super.c | 20 
  1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2284f749d892..072d82e1be06 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -129,11 +129,7 @@ static void nfs_ssc_unregister_ops(void)
  }
  #endif /* CONFIG_NFS_V4_2 */
  
-static struct shrinker acl_shrinker = {

-   .count_objects  = nfs_access_cache_count,
-   .scan_objects   = nfs_access_cache_scan,
-   .seeks  = DEFAULT_SEEKS,
-};
+static struct shrinker *acl_shrinker;
  
  /*

   * Register the NFS filesystems
@@ -153,9 +149,17 @@ int __init register_nfs_fs(void)
ret = nfs_register_sysctl();
if (ret < 0)
goto error_2;
-   ret = register_shrinker(&acl_shrinker, "nfs-acl");
-   if (ret < 0)
+
+   acl_shrinker = shrinker_alloc(0, "nfs-acl");
+   if (!acl_shrinker)
goto error_3;


Here should set ret to -ENOMEM, will fix.


+
+   acl_shrinker->count_objects = nfs_access_cache_count;
+   acl_shrinker->scan_objects = nfs_access_cache_scan;
+   acl_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(acl_shrinker);
+
  #ifdef CONFIG_NFS_V4_2
nfs_ssc_register_ops();
  #endif
@@ -175,7 +179,7 @@ int __init register_nfs_fs(void)
   */
  void __exit unregister_nfs_fs(void)
  {
-   unregister_shrinker(&acl_shrinker);
+   shrinker_free(acl_shrinker);
nfs_unregister_sysctl();
unregister_nfs4_fs();
  #ifdef CONFIG_NFS_V4_2


Re: [PATCH v3 16/49] nfsd: dynamically allocate the nfsd-filecache shrinker

2023-07-27 Thread Qi Zheng




On 2023/7/27 16:04, Qi Zheng wrote:

Use new APIs to dynamically allocate the nfsd-filecache shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
  fs/nfsd/filecache.c | 22 --
  1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
index ee9c923192e0..872eb9501965 100644
--- a/fs/nfsd/filecache.c
+++ b/fs/nfsd/filecache.c
@@ -521,11 +521,7 @@ nfsd_file_lru_scan(struct shrinker *s, struct 
shrink_control *sc)
return ret;
  }
  
-static struct shrinker	nfsd_file_shrinker = {

-   .scan_objects = nfsd_file_lru_scan,
-   .count_objects = nfsd_file_lru_count,
-   .seeks = 1,
-};
+static struct shrinker *nfsd_file_shrinker;
  
  /**

   * nfsd_file_cond_queue - conditionally unhash and queue a nfsd_file
@@ -746,12 +742,18 @@ nfsd_file_cache_init(void)
goto out_err;
}
  
-	ret = register_shrinker(&nfsd_file_shrinker, "nfsd-filecache");

-   if (ret) {
-   pr_err("nfsd: failed to register nfsd_file_shrinker: %d\n", 
ret);
+   nfsd_file_shrinker = shrinker_alloc(0, "nfsd-filecache");
+   if (!nfsd_file_shrinker) {


Here should set ret to -ENOMEM, will fix.


+   pr_err("nfsd: failed to allocate nfsd_file_shrinker\n");
goto out_lru;
}
  
+	nfsd_file_shrinker->count_objects = nfsd_file_lru_count;

+   nfsd_file_shrinker->scan_objects = nfsd_file_lru_scan;
+   nfsd_file_shrinker->seeks = 1;
+
+   shrinker_register(nfsd_file_shrinker);
+
ret = lease_register_notifier(&nfsd_file_lease_notifier);
if (ret) {
pr_err("nfsd: unable to register lease notifier: %d\n", ret);
@@ -774,7 +776,7 @@ nfsd_file_cache_init(void)
  out_notifier:
lease_unregister_notifier(&nfsd_file_lease_notifier);
  out_shrinker:
-   unregister_shrinker(&nfsd_file_shrinker);
+   shrinker_free(nfsd_file_shrinker);
  out_lru:
list_lru_destroy(&nfsd_file_lru);
  out_err:
@@ -891,7 +893,7 @@ nfsd_file_cache_shutdown(void)
return;
  
  	lease_unregister_notifier(&nfsd_file_lease_notifier);

-   unregister_shrinker(&nfsd_file_shrinker);
+   shrinker_free(nfsd_file_shrinker);
/*
 * make sure all callers of nfsd_file_lru_cb are done before
 * calling nfsd_file_cache_purge


Re: [PATCH v3 22/49] sunrpc: dynamically allocate the sunrpc_cred shrinker

2023-07-27 Thread Qi Zheng




On 2023/7/27 16:04, Qi Zheng wrote:

Use new APIs to dynamically allocate the sunrpc_cred shrinker.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
  net/sunrpc/auth.c | 19 +++
  1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 2f16f9d17966..6b898b1be6f5 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -861,11 +861,7 @@ rpcauth_uptodatecred(struct rpc_task *task)
test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
  }
  
-static struct shrinker rpc_cred_shrinker = {

-   .count_objects = rpcauth_cache_shrink_count,
-   .scan_objects = rpcauth_cache_shrink_scan,
-   .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *rpc_cred_shrinker;
  
  int __init rpcauth_init_module(void)

  {
@@ -874,9 +870,16 @@ int __init rpcauth_init_module(void)
err = rpc_init_authunix();
if (err < 0)
goto out1;
-   err = register_shrinker(&rpc_cred_shrinker, "sunrpc_cred");
-   if (err < 0)
+   rpc_cred_shrinker = shrinker_alloc(0, "sunrpc_cred");
+   if (!rpc_cred_shrinker)


Here should set err to -ENOMEM, will fix.


goto out2;
+
+   rpc_cred_shrinker->count_objects = rpcauth_cache_shrink_count;
+   rpc_cred_shrinker->scan_objects = rpcauth_cache_shrink_scan;
+   rpc_cred_shrinker->seeks = DEFAULT_SEEKS;
+
+   shrinker_register(rpc_cred_shrinker);
+
return 0;
  out2:
rpc_destroy_authunix();
@@ -887,5 +890,5 @@ int __init rpcauth_init_module(void)
  void rpcauth_remove_module(void)
  {
rpc_destroy_authunix();
-   unregister_shrinker(&rpc_cred_shrinker);
+   shrinker_free(rpc_cred_shrinker);
  }


Re: [PATCH v3 27/49] dm: dynamically allocate the dm-bufio shrinker

2023-07-27 Thread Qi Zheng




On 2023/7/27 16:04, Qi Zheng wrote:

In preparation for implementing lockless slab shrink, use new APIs to
dynamically allocate the dm-bufio shrinker, so that it can be freed
asynchronously using kfree_rcu(). Then it doesn't need to wait for RCU
read-side critical section when releasing the struct dm_bufio_client.

Signed-off-by: Qi Zheng 
Reviewed-by: Muchun Song 
---
  drivers/md/dm-bufio.c | 26 +++---
  1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index bc309e41d074..5a9124b83d53 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -963,7 +963,7 @@ struct dm_bufio_client {
  
  	sector_t start;
  
-	struct shrinker shrinker;

+   struct shrinker *shrinker;
struct work_struct shrink_work;
atomic_long_t need_shrink;
  
@@ -2368,7 +2368,7 @@ static unsigned long dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink

  {
struct dm_bufio_client *c;
  
-	c = container_of(shrink, struct dm_bufio_client, shrinker);

+   c = shrink->private_data;
atomic_long_add(sc->nr_to_scan, &c->need_shrink);
queue_work(dm_bufio_wq, &c->shrink_work);
  
@@ -2377,7 +2377,7 @@ static unsigned long dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink
  
  static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)

  {
-   struct dm_bufio_client *c = container_of(shrink, struct 
dm_bufio_client, shrinker);
+   struct dm_bufio_client *c = shrink->private_data;
unsigned long count = cache_total(&c->cache);
unsigned long retain_target = get_retain_buffers(c);
unsigned long queued_for_cleanup = atomic_long_read(&c->need_shrink);
@@ -2490,15 +2490,19 @@ struct dm_bufio_client *dm_bufio_client_create(struct 
block_device *bdev, unsign
INIT_WORK(&c->shrink_work, shrink_work);
atomic_long_set(&c->need_shrink, 0);
  
-	c->shrinker.count_objects = dm_bufio_shrink_count;

-   c->shrinker.scan_objects = dm_bufio_shrink_scan;
-   c->shrinker.seeks = 1;
-   c->shrinker.batch = 0;
-   r = register_shrinker(&c->shrinker, "dm-bufio:(%u:%u)",
- MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-   if (r)
+   c->shrinker = shrinker_alloc(0, "dm-bufio:(%u:%u)",
+MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
+   if (!c->shrinker)


Here should set r to -ENOMEM, will fix.


goto bad;
  
+	c->shrinker->count_objects = dm_bufio_shrink_count;

+   c->shrinker->scan_objects = dm_bufio_shrink_scan;
+   c->shrinker->seeks = 1;
+   c->shrinker->batch = 0;
+   c->shrinker->private_data = c;
+
+   shrinker_register(c->shrinker);
+
mutex_lock(&dm_bufio_clients_lock);
dm_bufio_client_count++;
list_add(&c->client_list, &dm_bufio_all_clients);
@@ -2537,7 +2541,7 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
  
  	drop_buffers(c);
  
-	unregister_shrinker(&c->shrinker);

+   shrinker_free(c->shrinker);
flush_work(&c->shrink_work);
  
  	mutex_lock(&dm_bufio_clients_lock);


  1   2   3   4   >