Re: [PATCH v2 2/5] zram: make dict update in comp_params_store() atomic

haoqin huang <[email protected]> Wed, 29 Jul 2026 12:06:44 +0800
Newsgroups org.kernel.vger.linux-block,org.kernel.vger.linux-kernel
Message-ID <CAEjiKSm_q1X4O9H44raKYYo8WQRxNRBUN4VFi7+-JW_JkWkbVw@mail.gmail.com>
On Wed, Jul 29, 2026 at 10:30 AM Sergey Senozhatsky
<[email protected]> wrote:
>
> On (26/07/28 17:29), Haoqin Huang wrote:
> > comp_params_store() resets old parameters before reading a new dict,
> > so if kernel_read_file_from_path() fails the params are left broken
> > and the actual error is swallowed. Fix by reading into a temporary
> > buffer first, swapping only on success. Use sz <= 0 to also reject
> > zero-size dicts.
> >
> > Signed-off-by: Haoqin Huang <[email protected]>
> > Signed-off-by: Rongwei Wang <[email protected]>
> > ---
> >  drivers/block/zram/zram_drv.c | 20 +++++++++++---------
> >  1 file changed, 11 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
> > index ace65c586072..9ea7ba9d1ed0 100644
> > --- a/drivers/block/zram/zram_drv.c
> > +++ b/drivers/block/zram/zram_drv.c
> > @@ -1699,21 +1699,23 @@ static int comp_params_store(struct zram *zram, u32 prio, s32 level,
> >                            const char *dict_path,
> >                            struct deflate_params *deflate_params)
> >  {
> > +     void *new_dict = NULL;
> >       ssize_t sz = 0;
> >
> > -     comp_params_reset(zram, prio);
>
> I don't see why is that a problem.  All you wanted to do here is to
> handle zero i_size.  Why do we need dict setting to be atomic?
>

comp_params_reset() calls vfree() on the old dict and resets level/
winbits to NOT_SET before reading the new dict.  If
kernel_read_file_from_path() then fails for any reason, not just
zero-size, but also ENOENT, ENOMEM, etc. the old dict is already
freed and unrecoverable, and the params are left in a broken,
half-reset state.

The "atomic" in the subject is about all-or-nothing semantics: don't
destroy valid state until the replacement is confirmed good.  Reading
into a temp buffer first, then swapping only on success, is the natural
way to do that.  The sz <= 0 check falls out naturally.

That said, if you prefer a more minimal fix, I can drop the temp-buffer
approach and just change sz < 0 to sz <= 0.  But since reading into
a temp buffer first protects against all failure paths, not just zero-size,
it seemed worth doing in one step.

> >       if (dict_path) {
> > -             sz = kernel_read_file_from_path(dict_path, 0,
> > -                                             &zram->params[prio].dict,
> > -                                             INT_MAX,
> > -                                             NULL,
> > -                                             READING_POLICY);
> > -             if (sz < 0)
> > -                     return -EINVAL;
> > +             sz = kernel_read_file_from_path(dict_path, 0, &new_dict,
> > +                                             INT_MAX, NULL, READING_POLICY);
> > +             if (sz <= 0) {
> > +                     vfree(new_dict);
> > +                     if (sz == 0)
> > +                             return -EINVAL;
> > +                     return sz;
> > +             }
> >       }
> >
> > +     comp_params_reset(zram, prio);
> >       zram->params[prio].dict_sz = sz;
> > +     zram->params[prio].dict = new_dict;
> >       zram->params[prio].level = level;
> >       zram->params[prio].deflate.winbits = deflate_params->winbits;