2022-06-11 15:22:31

by Fabio M. De Francesco

[permalink] [raw]
Subject: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

The use of kmap() is being deprecated in favor of kmap_local_page(). With
kmap_local_page(), the mapping is per thread, CPU local and not globally
visible.

Therefore, use kmap_local_page() / kunmap_local() in zstd.c because in
this file the mappings are per thread and are not visible in other
contexts; meanwhile refactor zstd_compress_pages() to comply with nested
local mapping / unmapping ordering rules.

Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
HIGHMEM64G enabled.

Cc: Filipe Manana <[email protected]>
Suggested-by: Ira Weiny <[email protected]>
Signed-off-by: Fabio M. De Francesco <[email protected]>
---

Thanks to Ira Weiny for his invaluable help and persevering support.
Thanks also to Filipe Manana for identifying a fundamental detail I had overlooked:
https://lore.kernel.org/lkml/20220611093411.GA3779054@falcondesktop/

tweed32:/usr/lib/xfstests # ./check -g compress
FSTYP -- btrfs
PLATFORM -- Linux/i686 tweed32 5.19.0-rc1-vanilla-debug+ #22 SMP PREEMPT_DYNAMIC Sat Jun 11 14:31:39 CEST 2022
MKFS_OPTIONS -- /dev/loop1
MOUNT_OPTIONS -- /dev/loop1 /mnt/scratch

btrfs/024 1s ... 0s
btrfs/026 3s ... 3s
btrfs/037 1s ... 1s
btrfs/038 1s ... 0s
btrfs/041 0s ... 1s
btrfs/062 34s ... 35s
btrfs/063 18s ... 18s
btrfs/067 33s ... 32s
btrfs/068 10s ... 10s
btrfs/070 [not run] btrfs and this test needs 5 or more disks in SCRATCH_DEV_POOL
btrfs/071 [not run] btrfs and this test needs 5 or more disks in SCRATCH_DEV_POOL
btrfs/072 33s ... 33s
btrfs/073 17s ... 15s
btrfs/074 36s ... 32s
btrfs/076 0s ... 0s
btrfs/103 1s ... 1s
btrfs/106 1s ... 1s
btrfs/109 1s ... 0s
btrfs/113 0s ... 1s
btrfs/138 43s ... 46s
btrfs/149 1s ... 1s
btrfs/183 1s ... 1s
btrfs/205 1s ... 1s
btrfs/234 3s ... 3s
btrfs/246 0s ... 0s
btrfs/251 1s ... 1s
Ran: btrfs/024 btrfs/026 btrfs/037 btrfs/038 btrfs/041 btrfs/062 btrfs/063 btrfs/067 btrfs/068 btrfs/070 btrfs/071 btrfs/072 btrfs/073 btrfs/074 btrfs/076 btrfs/103 btrfs/106 btrfs/109 btrfs/113 btrfs/138 btrfs/149 btrfs/183 btrfs/205 btrfs/234 btrfs/246 btrfs/251
Not run: btrfs/070 btrfs/071
Passed all 26 tests

fs/btrfs/zstd.c | 42 +++++++++++++++++++++++-------------------
1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
index 0fe31a6f6e68..4d50eb3edce5 100644
--- a/fs/btrfs/zstd.c
+++ b/fs/btrfs/zstd.c
@@ -391,6 +391,8 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
*out_pages = 0;
*total_out = 0;
*total_in = 0;
+ workspace->in_buf.src = NULL;
+ workspace->out_buf.dst = NULL;

/* Initialize the stream */
stream = zstd_init_cstream(&params, len, workspace->mem,
@@ -403,7 +405,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,

/* map in the first page of input data */
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
- workspace->in_buf.src = kmap(in_page);
+ workspace->in_buf.src = kmap_local_page(in_page);
workspace->in_buf.pos = 0;
workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);

@@ -415,7 +417,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
goto out;
}
pages[nr_pages++] = out_page;
- workspace->out_buf.dst = kmap(out_page);
+ workspace->out_buf.dst = kmap_local_page(out_page);
workspace->out_buf.pos = 0;
workspace->out_buf.size = min_t(size_t, max_out, PAGE_SIZE);

@@ -450,9 +452,9 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
if (workspace->out_buf.pos == workspace->out_buf.size) {
tot_out += PAGE_SIZE;
max_out -= PAGE_SIZE;
- kunmap(out_page);
+ kunmap_local(workspace->out_buf.dst);
if (nr_pages == nr_dest_pages) {
- out_page = NULL;
+ workspace->out_buf.dst = NULL;
ret = -E2BIG;
goto out;
}
@@ -462,7 +464,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
goto out;
}
pages[nr_pages++] = out_page;
- workspace->out_buf.dst = kmap(out_page);
+ workspace->out_buf.dst = kmap_local_page(out_page);
workspace->out_buf.pos = 0;
workspace->out_buf.size = min_t(size_t, max_out,
PAGE_SIZE);
@@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
/* Check if we need more input */
if (workspace->in_buf.pos == workspace->in_buf.size) {
tot_in += PAGE_SIZE;
- kunmap(in_page);
+ kunmap_local(workspace->out_buf.dst);
+ kunmap_local((void *)workspace->in_buf.src);
put_page(in_page);
-
start += PAGE_SIZE;
len -= PAGE_SIZE;
in_page = find_get_page(mapping, start >> PAGE_SHIFT);
- workspace->in_buf.src = kmap(in_page);
+ workspace->in_buf.src = kmap_local_page(in_page);
workspace->in_buf.pos = 0;
workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);
+ workspace->out_buf.dst = kmap_local_page(out_page);
}
}
while (1) {
@@ -510,9 +513,9 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,

tot_out += PAGE_SIZE;
max_out -= PAGE_SIZE;
- kunmap(out_page);
+ kunmap_local(workspace->out_buf.dst);
if (nr_pages == nr_dest_pages) {
- out_page = NULL;
+ workspace->out_buf.dst = NULL;
ret = -E2BIG;
goto out;
}
@@ -522,7 +525,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
goto out;
}
pages[nr_pages++] = out_page;
- workspace->out_buf.dst = kmap(out_page);
+ workspace->out_buf.dst = kmap_local_page(out_page);
workspace->out_buf.pos = 0;
workspace->out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
}
@@ -538,12 +541,12 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
out:
*out_pages = nr_pages;
/* Cleanup */
- if (in_page) {
- kunmap(in_page);
+ if (workspace->out_buf.dst)
+ kunmap_local(workspace->out_buf.dst);
+ if (workspace->in_buf.src) {
+ kunmap_local((void *)workspace->in_buf.src);
put_page(in_page);
}
- if (out_page)
- kunmap(out_page);
return ret;
}

@@ -567,7 +570,7 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
goto done;
}

- workspace->in_buf.src = kmap(pages_in[page_in_index]);
+ workspace->in_buf.src = kmap_local_page(pages_in[page_in_index]);
workspace->in_buf.pos = 0;
workspace->in_buf.size = min_t(size_t, srclen, PAGE_SIZE);

@@ -603,14 +606,15 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
break;

if (workspace->in_buf.pos == workspace->in_buf.size) {
- kunmap(pages_in[page_in_index++]);
+ kunmap_local((void *)workspace->in_buf.src);
+ page_in_index++;
if (page_in_index >= total_pages_in) {
workspace->in_buf.src = NULL;
ret = -EIO;
goto done;
}
srclen -= PAGE_SIZE;
- workspace->in_buf.src = kmap(pages_in[page_in_index]);
+ workspace->in_buf.src = kmap_local_page(pages_in[page_in_index]);
workspace->in_buf.pos = 0;
workspace->in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
}
@@ -619,7 +623,7 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
zero_fill_bio(cb->orig_bio);
done:
if (workspace->in_buf.src)
- kunmap(pages_in[page_in_index]);
+ kunmap_local((void *)workspace->in_buf.src);
return ret;
}

--
2.36.1


2022-06-13 20:34:38

by David Sterba

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco wrote:
> The use of kmap() is being deprecated in favor of kmap_local_page(). With
> kmap_local_page(), the mapping is per thread, CPU local and not globally
> visible.
>
> Therefore, use kmap_local_page() / kunmap_local() in zstd.c because in
> this file the mappings are per thread and are not visible in other
> contexts; meanwhile refactor zstd_compress_pages() to comply with nested
> local mapping / unmapping ordering rules.
>
> Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
> HIGHMEM64G enabled.
>
> Cc: Filipe Manana <[email protected]>
> Suggested-by: Ira Weiny <[email protected]>
> Signed-off-by: Fabio M. De Francesco <[email protected]>
> ---
>
> @@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> /* Check if we need more input */
> if (workspace->in_buf.pos == workspace->in_buf.size) {
> tot_in += PAGE_SIZE;
> - kunmap(in_page);
> + kunmap_local(workspace->out_buf.dst);
> + kunmap_local((void *)workspace->in_buf.src);

Why is the cast needed? I see that it leads to a warning but we pass a
const buffer and that breaks the API contract as in kunmap it would be
accessed as non-const and potentially changed without warning or
compiler error. If kunmap_local does not touch the buffer and 'const
void*' would work too, then it should be fixed.

2022-06-13 23:26:19

by Fabio M. De Francesco

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On lunedì 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco wrote:
> > The use of kmap() is being deprecated in favor of kmap_local_page().
With
> > kmap_local_page(), the mapping is per thread, CPU local and not
globally
> > visible.
> >
> > Therefore, use kmap_local_page() / kunmap_local() in zstd.c because in
> > this file the mappings are per thread and are not visible in other
> > contexts; meanwhile refactor zstd_compress_pages() to comply with
nested
> > local mapping / unmapping ordering rules.
> >
> > Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
> > HIGHMEM64G enabled.
> >
> > Cc: Filipe Manana <[email protected]>
> > Suggested-by: Ira Weiny <[email protected]>
> > Signed-off-by: Fabio M. De Francesco <[email protected]>
> > ---
> >
> > @@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws,
struct address_space *mapping,
> > /* Check if we need more input */
> > if (workspace->in_buf.pos == workspace->in_buf.size) {
> > tot_in += PAGE_SIZE;
> > - kunmap(in_page);
> > + kunmap_local(workspace->out_buf.dst);
> > + kunmap_local((void *)workspace->in_buf.src);
>
> Why is the cast needed?

As I wrote in an email I sent some days ago ("[RFC PATCH] btrfs: Replace
kmap() with kmap_local_page() in zstd.c")[1] I get a series of errors like
the following:

/usr/src/git/kernels/linux/fs/btrfs/zstd.c:547:33: warning: passing
argument 1 of '__kunmap_local' discards 'const' qualifier from pointer
target type [-Wdiscarded-qualifiers]
547 | kunmap_local(workspace->in_buf.src);
| ~~~~~~~~~~~~~~~~~^~~~
/usr/src/git/kernels/linux/include/linux/highmem-internal.h:284:17: note:
in definition of macro 'kunmap_local'
284 | __kunmap_local(__addr); \
| ^~~~~~
/usr/src/git/kernels/linux/include/linux/highmem-internal.h:92:41: note:
expected 'void *' but argument is of type 'const void *'
92 | static inline void __kunmap_local(void *vaddr)
| ~~~~~~^~~~~

Therefore, this is a (bad?) hack to make these changes compile.
A better solution is changing the prototype of __kunmap_local(); I
suppose that Andrew won't object, but who knows?

(+Cc Andrew Morton).

I was waiting for your comments. At now I've done about 15 conversions
across the kernel but it's the first time I had to pass a pointer to const
void to kunmap_local(). Therefore, I was not sure if changing the API were
better suited (however I have already discussed this with Ira).

> I see that it leads to a warning but we pass a
> const buffer and that breaks the API contract as in kunmap it would be
> accessed as non-const and potentially changed without warning or
> compiler error. If kunmap_local does not touch the buffer

Yes, correct, kunmap_local() does _not_ touch the buffer.

> and 'const
> void*' would work too, then it should be fixed.

I'll send an RFC patch for changing __kunmap_local() and the other
functions of the calls chain down to kunmap_local_indexed().
Furthermore, changes to kunmap_local_indexed() prototype require also
changes to __kunmap_atomic() (if I recall correctly...).

Thanks for your review,

Fabio


2022-06-13 23:44:44

by Fabio M. De Francesco

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On martedì 14 giugno 2022 01:22:50 CEST Fabio M. De Francesco wrote:
> On lunedì 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco wrote:
> > > The use of kmap() is being deprecated in favor of kmap_local_page().
> With
> > > kmap_local_page(), the mapping is per thread, CPU local and not
> globally
> > > visible.
> > >
> > > Therefore, use kmap_local_page() / kunmap_local() in zstd.c because
in
> > > this file the mappings are per thread and are not visible in other
> > > contexts; meanwhile refactor zstd_compress_pages() to comply with
> nested
> > > local mapping / unmapping ordering rules.
> > >
> > > Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
> > > HIGHMEM64G enabled.
> > >
> > > Cc: Filipe Manana <[email protected]>
> > > Suggested-by: Ira Weiny <[email protected]>
> > > Signed-off-by: Fabio M. De Francesco <[email protected]>
> > > ---
> > >
> > > @@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws,
> struct address_space *mapping,
> > > /* Check if we need more input */
> > > if (workspace->in_buf.pos == workspace->in_buf.size) {
> > > tot_in += PAGE_SIZE;
> > > - kunmap(in_page);
> > > + kunmap_local(workspace->out_buf.dst);
> > > + kunmap_local((void *)workspace->in_buf.src);
> >
> > Why is the cast needed?
>
> As I wrote in an email I sent some days ago ("[RFC PATCH] btrfs: Replace
> kmap() with kmap_local_page() in zstd.c")[1] I get a series of errors
like
> the following:
>
> /usr/src/git/kernels/linux/fs/btrfs/zstd.c:547:33: warning: passing
> argument 1 of '__kunmap_local' discards 'const' qualifier from pointer
> target type [-Wdiscarded-qualifiers]
> 547 | kunmap_local(workspace->in_buf.src);
> | ~~~~~~~~~~~~~~~~~^~~~
> /usr/src/git/kernels/linux/include/linux/highmem-internal.h:284:17: note:
> in definition of macro 'kunmap_local'
> 284 | __kunmap_local(__addr); \
> | ^~~~~~
> /usr/src/git/kernels/linux/include/linux/highmem-internal.h:92:41: note:
> expected 'void *' but argument is of type 'const void *'
> 92 | static inline void __kunmap_local(void *vaddr)
> | ~~~~~~^~~~~
>
> Therefore, this is a (bad?) hack to make these changes compile.
> A better solution is changing the prototype of __kunmap_local(); I
> suppose that Andrew won't object, but who knows?
>
> (+Cc Andrew Morton).
>
> I was waiting for your comments. At now I've done about 15 conversions
> across the kernel but it's the first time I had to pass a pointer to
const
> void to kunmap_local(). Therefore, I was not sure if changing the API
were
> better suited (however I have already discussed this with Ira).
>
> > I see that it leads to a warning but we pass a
> > const buffer and that breaks the API contract as in kunmap it would be
> > accessed as non-const and potentially changed without warning or
> > compiler error. If kunmap_local does not touch the buffer
>
> Yes, correct, kunmap_local() does _not_ touch the buffer.
>
> > and 'const
> > void*' would work too, then it should be fixed.
>
> I'll send an RFC patch for changing __kunmap_local() and the other
> functions of the calls chain down to kunmap_local_indexed().
> Furthermore, changes to kunmap_local_indexed() prototype require also
> changes to __kunmap_atomic() (if I recall correctly...).
>
> Thanks for your review,
>
> Fabio
>
Sorry, I forgot to paste a link:
[1] https://lore.kernel.org/lkml/[email protected]/

Fabio


2022-06-14 14:38:46

by David Sterba

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On Tue, Jun 14, 2022 at 01:22:50AM +0200, Fabio M. De Francesco wrote:
> On luned? 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco wrote:
> > > The use of kmap() is being deprecated in favor of kmap_local_page().
> With
> > > kmap_local_page(), the mapping is per thread, CPU local and not
> globally
> > > visible.
> > >
> > > Therefore, use kmap_local_page() / kunmap_local() in zstd.c because in
> > > this file the mappings are per thread and are not visible in other
> > > contexts; meanwhile refactor zstd_compress_pages() to comply with
> nested
> > > local mapping / unmapping ordering rules.
> > >
> > > Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
> > > HIGHMEM64G enabled.
> > >
> > > Cc: Filipe Manana <[email protected]>
> > > Suggested-by: Ira Weiny <[email protected]>
> > > Signed-off-by: Fabio M. De Francesco <[email protected]>
> > > ---
> > >
> > > @@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws,
> struct address_space *mapping,
> > > /* Check if we need more input */
> > > if (workspace->in_buf.pos == workspace->in_buf.size) {
> > > tot_in += PAGE_SIZE;
> > > - kunmap(in_page);
> > > + kunmap_local(workspace->out_buf.dst);
> > > + kunmap_local((void *)workspace->in_buf.src);
> >
> > Why is the cast needed?
>
> As I wrote in an email I sent some days ago ("[RFC PATCH] btrfs: Replace
> kmap() with kmap_local_page() in zstd.c")[1] I get a series of errors like
> the following:
>
> /usr/src/git/kernels/linux/fs/btrfs/zstd.c:547:33: warning: passing
> argument 1 of '__kunmap_local' discards 'const' qualifier from pointer
> target type [-Wdiscarded-qualifiers]
> 547 | kunmap_local(workspace->in_buf.src);
> | ~~~~~~~~~~~~~~~~~^~~~
> /usr/src/git/kernels/linux/include/linux/highmem-internal.h:284:17: note:
> in definition of macro 'kunmap_local'
> 284 | __kunmap_local(__addr); \
> | ^~~~~~
> /usr/src/git/kernels/linux/include/linux/highmem-internal.h:92:41: note:
> expected 'void *' but argument is of type 'const void *'
> 92 | static inline void __kunmap_local(void *vaddr)
> | ~~~~~~^~~~~
>
> Therefore, this is a (bad?) hack to make these changes compile.

I think it's a bad practice and that API that does not modify parameters
should declare the pointers const. Type casts should be used in
justified cases and not to paper over fixable issues.

> A better solution is changing the prototype of __kunmap_local(); I
> suppose that Andrew won't object, but who knows?
>
> (+Cc Andrew Morton).
>
> I was waiting for your comments. At now I've done about 15 conversions
> across the kernel but it's the first time I had to pass a pointer to const
> void to kunmap_local(). Therefore, I was not sure if changing the API were
> better suited (however I have already discussed this with Ira).

IMHO it should be fixed in the API.

2022-06-14 16:42:19

by Fabio M. De Francesco

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On martedì 14 giugno 2022 16:25:21 CEST David Sterba wrote:
> On Tue, Jun 14, 2022 at 01:22:50AM +0200, Fabio M. De Francesco wrote:
> > On lunedì 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco
wrote:
> > > > The use of kmap() is being deprecated in favor of
kmap_local_page().
> > With
> > > > kmap_local_page(), the mapping is per thread, CPU local and not
> > globally
> > > > visible.
> > > >
> > > > Therefore, use kmap_local_page() / kunmap_local() in zstd.c because
in
> > > > this file the mappings are per thread and are not visible in other
> > > > contexts; meanwhile refactor zstd_compress_pages() to comply with
> > nested
> > > > local mapping / unmapping ordering rules.
> > > >
> > > > Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
> > > > HIGHMEM64G enabled.
> > > >
> > > > Cc: Filipe Manana <[email protected]>
> > > > Suggested-by: Ira Weiny <[email protected]>
> > > > Signed-off-by: Fabio M. De Francesco <[email protected]>
> > > > ---
> > > >
> > > > @@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws,
> > struct address_space *mapping,
> > > > /* Check if we need more input */
> > > > if (workspace->in_buf.pos == workspace->in_buf.size) {
> > > > tot_in += PAGE_SIZE;
> > > > - kunmap(in_page);
> > > > + kunmap_local(workspace->out_buf.dst);
> > > > + kunmap_local((void *)workspace->in_buf.src);
> > >
> > > Why is the cast needed?
> >
> > As I wrote in an email I sent some days ago ("[RFC PATCH] btrfs:
Replace
> > kmap() with kmap_local_page() in zstd.c")[1] I get a series of errors
like
> > the following:
> >
> > /usr/src/git/kernels/linux/fs/btrfs/zstd.c:547:33: warning: passing
> > argument 1 of '__kunmap_local' discards 'const' qualifier from pointer
> > target type [-Wdiscarded-qualifiers]
> > 547 | kunmap_local(workspace->in_buf.src);
> > | ~~~~~~~~~~~~~~~~~^~~~
> > /usr/src/git/kernels/linux/include/linux/highmem-internal.h:284:17:
note:
> > in definition of macro 'kunmap_local'
> > 284 | __kunmap_local(__addr); \
> > | ^~~~~~
> > /usr/src/git/kernels/linux/include/linux/highmem-internal.h:92:41:
note:
> > expected 'void *' but argument is of type 'const void *'
> > 92 | static inline void __kunmap_local(void *vaddr)
> > | ~~~~~~^~~~~
> >
> > Therefore, this is a (bad?) hack to make these changes compile.
>
> I think it's a bad practice and that API that does not modify parameters
> should declare the pointers const. Type casts should be used in
> justified cases and not to paper over fixable issues.
>
> > A better solution is changing the prototype of __kunmap_local(); I
> > suppose that Andrew won't object, but who knows?
> >
> > (+Cc Andrew Morton).
> >
> > I was waiting for your comments. At now I've done about 15 conversions
> > across the kernel but it's the first time I had to pass a pointer to
const
> > void to kunmap_local(). Therefore, I was not sure if changing the API
were
> > better suited (however I have already discussed this with Ira).
>
> IMHO it should be fixed in the API.
>
I agree with you in full.

At the same time when you sent this email I submitted a patch to change
kunmap_local() and kunmap_atomic().

After Andrew takes them I'll send v2 of this patch to zstd.c without those
unnecessary casts.

Thanks for your review,

Fabio



2022-06-14 17:46:38

by Ira Weiny

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On Tue, Jun 14, 2022 at 06:28:48PM +0200, Fabio M. De Francesco wrote:
> On marted? 14 giugno 2022 16:25:21 CEST David Sterba wrote:
> > On Tue, Jun 14, 2022 at 01:22:50AM +0200, Fabio M. De Francesco wrote:
> > > On luned? 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > > > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco
> >

[snip]

> > > A better solution is changing the prototype of __kunmap_local(); I
> > > suppose that Andrew won't object, but who knows?
> > >
> > > (+Cc Andrew Morton).
> > >
> > > I was waiting for your comments. At now I've done about 15 conversions
> > > across the kernel but it's the first time I had to pass a pointer to
> const
> > > void to kunmap_local(). Therefore, I was not sure if changing the API
> were
> > > better suited (however I have already discussed this with Ira).
> >
> > IMHO it should be fixed in the API.
> >
> I agree with you in full.
>
> At the same time when you sent this email I submitted a patch to change
> kunmap_local() and kunmap_atomic().
>
> After Andrew takes them I'll send v2 of this patch to zstd.c without those
> unnecessary casts.

David,

Would you be willing to take this through your tree as a pre-patch to the kmap
changes in btrfs?

That would be easier for Fabio and probably you and Andrew in the long run.

Ira

>
> Thanks for your review,
>
> Fabio
>
>
>

2022-06-15 05:52:27

by Fabio M. De Francesco

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On martedì 14 giugno 2022 19:07:34 CEST Ira Weiny wrote:
> On Tue, Jun 14, 2022 at 06:28:48PM +0200, Fabio M. De Francesco wrote:
> > On martedì 14 giugno 2022 16:25:21 CEST David Sterba wrote:
> > > On Tue, Jun 14, 2022 at 01:22:50AM +0200, Fabio M. De Francesco
wrote:
> > > > On lunedì 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > > > > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco
> > >
>
> [snip]
>
> > > > A better solution is changing the prototype of __kunmap_local(); I
> > > > suppose that Andrew won't object, but who knows?
> > > >
> > > > (+Cc Andrew Morton).
> > > >
> > > > I was waiting for your comments. At now I've done about 15
conversions
> > > > across the kernel but it's the first time I had to pass a pointer
to
> > const
> > > > void to kunmap_local(). Therefore, I was not sure if changing the
API
> > were
> > > > better suited (however I have already discussed this with Ira).
> > >
> > > IMHO it should be fixed in the API.
> > >
> > I agree with you in full.
> >
> > At the same time when you sent this email I submitted a patch to change
> > kunmap_local() and kunmap_atomic().
> >
> > After Andrew takes them I'll send v2 of this patch to zstd.c without
those
> > unnecessary casts.
>
> David,
>
> Would you be willing to take this through your tree as a pre-patch to the
kmap
> changes in btrfs?
>
> That would be easier for Fabio and probably you and Andrew in the long
run.
>
> Ira

David,

Please drop the first version of the changes[1] to the API and instead take
my second version.[2] I've only reworked the commit message (and subject,
but this was involuntary) to make explicit that the fundamental reason
behind these changes are semantic correctness.

Thanks,

Fabio

[1] https://lore.kernel.org/lkml/[email protected]/

[2] https://lore.kernel.org/lkml/[email protected]/



2022-06-15 13:50:10

by David Sterba

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On Tue, Jun 14, 2022 at 10:07:34AM -0700, Ira Weiny wrote:
> On Tue, Jun 14, 2022 at 06:28:48PM +0200, Fabio M. De Francesco wrote:
> > On marted? 14 giugno 2022 16:25:21 CEST David Sterba wrote:
> > > On Tue, Jun 14, 2022 at 01:22:50AM +0200, Fabio M. De Francesco wrote:
> > > > On luned? 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > > > > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco
>
> > > > A better solution is changing the prototype of __kunmap_local(); I
> > > > suppose that Andrew won't object, but who knows?
> > > >
> > > > (+Cc Andrew Morton).
> > > >
> > > > I was waiting for your comments. At now I've done about 15 conversions
> > > > across the kernel but it's the first time I had to pass a pointer to
> > const
> > > > void to kunmap_local(). Therefore, I was not sure if changing the API
> > were
> > > > better suited (however I have already discussed this with Ira).
> > >
> > > IMHO it should be fixed in the API.
> > >
> > I agree with you in full.
> >
> > At the same time when you sent this email I submitted a patch to change
> > kunmap_local() and kunmap_atomic().
> >
> > After Andrew takes them I'll send v2 of this patch to zstd.c without those
> > unnecessary casts.
>
> David,
>
> Would you be willing to take this through your tree as a pre-patch to the kmap
> changes in btrfs?
>
> That would be easier for Fabio and probably you and Andrew in the long run.

Yes, no problem. I could probably send all the kmap conversions after
tests so it does not need to wait until the next cycle.

2022-06-15 13:50:48

by David Sterba

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On Tue, Jun 14, 2022 at 10:07:34AM -0700, Ira Weiny wrote:
> On Tue, Jun 14, 2022 at 06:28:48PM +0200, Fabio M. De Francesco wrote:
> > On marted? 14 giugno 2022 16:25:21 CEST David Sterba wrote:
> > > On Tue, Jun 14, 2022 at 01:22:50AM +0200, Fabio M. De Francesco wrote:
> > > > On luned? 13 giugno 2022 20:39:13 CEST David Sterba wrote:
> > > > > On Sat, Jun 11, 2022 at 03:52:03PM +0200, Fabio M. De Francesco
> > >
>
> [snip]
>
> > > > A better solution is changing the prototype of __kunmap_local(); I
> > > > suppose that Andrew won't object, but who knows?
> > > >
> > > > (+Cc Andrew Morton).
> > > >
> > > > I was waiting for your comments. At now I've done about 15 conversions
> > > > across the kernel but it's the first time I had to pass a pointer to
> > const
> > > > void to kunmap_local(). Therefore, I was not sure if changing the API
> > were
> > > > better suited (however I have already discussed this with Ira).
> > >
> > > IMHO it should be fixed in the API.
> > >
> > I agree with you in full.
> >
> > At the same time when you sent this email I submitted a patch to change
> > kunmap_local() and kunmap_atomic().
> >
> > After Andrew takes them I'll send v2 of this patch to zstd.c without those
> > unnecessary casts.
>
> David,
>
> Would you be willing to take this through your tree as a pre-patch to the kmap
> changes in btrfs?
>
> That would be easier for Fabio and probably you and Andrew in the long run.

Yes, no problem if the patch has an ack. I could probably send all the
kmap conversions after tests so it does not need to wait until the next
cycle.

2022-07-14 00:36:10

by Wang Yugui

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

Hi,

Compiler warning:

fs/btrfs/zstd.c:478:55: warning: passing argument 1 of ??__kunmap_local?? discards ??const?? qualifier from pointer target type [-Wdiscarded-qualifiers]
478 | kunmap_local(workspace->in_buf.src);
./include/linux/highmem-internal.h:284:24: note: in definition of macro ??kunmap_local??
284 | __kunmap_local(__addr); \
| ^~~~~~
./include/linux/highmem-internal.h:200:41: note: expected ??void *?? but argument is of type ??const void *??
200 | static inline void __kunmap_local(void *addr)
| ~~~~~~^~~~

Best Regards
Wang Yugui ([email protected])
2022/07/14

> The use of kmap() is being deprecated in favor of kmap_local_page(). With
> kmap_local_page(), the mapping is per thread, CPU local and not globally
> visible.
>
> Therefore, use kmap_local_page() / kunmap_local() in zstd.c because in
> this file the mappings are per thread and are not visible in other
> contexts; meanwhile refactor zstd_compress_pages() to comply with nested
> local mapping / unmapping ordering rules.
>
> Tested with xfstests on a QEMU + KVM 32 bits VM with 4GB of RAM and
> HIGHMEM64G enabled.
>
> Cc: Filipe Manana <[email protected]>
> Suggested-by: Ira Weiny <[email protected]>
> Signed-off-by: Fabio M. De Francesco <[email protected]>
> ---
>
> Thanks to Ira Weiny for his invaluable help and persevering support.
> Thanks also to Filipe Manana for identifying a fundamental detail I had overlooked:
> https://lore.kernel.org/lkml/20220611093411.GA3779054@falcondesktop/
>
> tweed32:/usr/lib/xfstests # ./check -g compress
> FSTYP -- btrfs
> PLATFORM -- Linux/i686 tweed32 5.19.0-rc1-vanilla-debug+ #22 SMP PREEMPT_DYNAMIC Sat Jun 11 14:31:39 CEST 2022
> MKFS_OPTIONS -- /dev/loop1
> MOUNT_OPTIONS -- /dev/loop1 /mnt/scratch
>
> btrfs/024 1s ... 0s
> btrfs/026 3s ... 3s
> btrfs/037 1s ... 1s
> btrfs/038 1s ... 0s
> btrfs/041 0s ... 1s
> btrfs/062 34s ... 35s
> btrfs/063 18s ... 18s
> btrfs/067 33s ... 32s
> btrfs/068 10s ... 10s
> btrfs/070 [not run] btrfs and this test needs 5 or more disks in SCRATCH_DEV_POOL
> btrfs/071 [not run] btrfs and this test needs 5 or more disks in SCRATCH_DEV_POOL
> btrfs/072 33s ... 33s
> btrfs/073 17s ... 15s
> btrfs/074 36s ... 32s
> btrfs/076 0s ... 0s
> btrfs/103 1s ... 1s
> btrfs/106 1s ... 1s
> btrfs/109 1s ... 0s
> btrfs/113 0s ... 1s
> btrfs/138 43s ... 46s
> btrfs/149 1s ... 1s
> btrfs/183 1s ... 1s
> btrfs/205 1s ... 1s
> btrfs/234 3s ... 3s
> btrfs/246 0s ... 0s
> btrfs/251 1s ... 1s
> Ran: btrfs/024 btrfs/026 btrfs/037 btrfs/038 btrfs/041 btrfs/062 btrfs/063 btrfs/067 btrfs/068 btrfs/070 btrfs/071 btrfs/072 btrfs/073 btrfs/074 btrfs/076 btrfs/103 btrfs/106 btrfs/109 btrfs/113 btrfs/138 btrfs/149 btrfs/183 btrfs/205 btrfs/234 btrfs/246 btrfs/251
> Not run: btrfs/070 btrfs/071
> Passed all 26 tests
>
> fs/btrfs/zstd.c | 42 +++++++++++++++++++++++-------------------
> 1 file changed, 23 insertions(+), 19 deletions(-)
>
> diff --git a/fs/btrfs/zstd.c b/fs/btrfs/zstd.c
> index 0fe31a6f6e68..4d50eb3edce5 100644
> --- a/fs/btrfs/zstd.c
> +++ b/fs/btrfs/zstd.c
> @@ -391,6 +391,8 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> *out_pages = 0;
> *total_out = 0;
> *total_in = 0;
> + workspace->in_buf.src = NULL;
> + workspace->out_buf.dst = NULL;
>
> /* Initialize the stream */
> stream = zstd_init_cstream(&params, len, workspace->mem,
> @@ -403,7 +405,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
>
> /* map in the first page of input data */
> in_page = find_get_page(mapping, start >> PAGE_SHIFT);
> - workspace->in_buf.src = kmap(in_page);
> + workspace->in_buf.src = kmap_local_page(in_page);
> workspace->in_buf.pos = 0;
> workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);
>
> @@ -415,7 +417,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> goto out;
> }
> pages[nr_pages++] = out_page;
> - workspace->out_buf.dst = kmap(out_page);
> + workspace->out_buf.dst = kmap_local_page(out_page);
> workspace->out_buf.pos = 0;
> workspace->out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
>
> @@ -450,9 +452,9 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> if (workspace->out_buf.pos == workspace->out_buf.size) {
> tot_out += PAGE_SIZE;
> max_out -= PAGE_SIZE;
> - kunmap(out_page);
> + kunmap_local(workspace->out_buf.dst);
> if (nr_pages == nr_dest_pages) {
> - out_page = NULL;
> + workspace->out_buf.dst = NULL;
> ret = -E2BIG;
> goto out;
> }
> @@ -462,7 +464,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> goto out;
> }
> pages[nr_pages++] = out_page;
> - workspace->out_buf.dst = kmap(out_page);
> + workspace->out_buf.dst = kmap_local_page(out_page);
> workspace->out_buf.pos = 0;
> workspace->out_buf.size = min_t(size_t, max_out,
> PAGE_SIZE);
> @@ -477,15 +479,16 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> /* Check if we need more input */
> if (workspace->in_buf.pos == workspace->in_buf.size) {
> tot_in += PAGE_SIZE;
> - kunmap(in_page);
> + kunmap_local(workspace->out_buf.dst);
> + kunmap_local((void *)workspace->in_buf.src);
> put_page(in_page);
> -
> start += PAGE_SIZE;
> len -= PAGE_SIZE;
> in_page = find_get_page(mapping, start >> PAGE_SHIFT);
> - workspace->in_buf.src = kmap(in_page);
> + workspace->in_buf.src = kmap_local_page(in_page);
> workspace->in_buf.pos = 0;
> workspace->in_buf.size = min_t(size_t, len, PAGE_SIZE);
> + workspace->out_buf.dst = kmap_local_page(out_page);
> }
> }
> while (1) {
> @@ -510,9 +513,9 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
>
> tot_out += PAGE_SIZE;
> max_out -= PAGE_SIZE;
> - kunmap(out_page);
> + kunmap_local(workspace->out_buf.dst);
> if (nr_pages == nr_dest_pages) {
> - out_page = NULL;
> + workspace->out_buf.dst = NULL;
> ret = -E2BIG;
> goto out;
> }
> @@ -522,7 +525,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> goto out;
> }
> pages[nr_pages++] = out_page;
> - workspace->out_buf.dst = kmap(out_page);
> + workspace->out_buf.dst = kmap_local_page(out_page);
> workspace->out_buf.pos = 0;
> workspace->out_buf.size = min_t(size_t, max_out, PAGE_SIZE);
> }
> @@ -538,12 +541,12 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
> out:
> *out_pages = nr_pages;
> /* Cleanup */
> - if (in_page) {
> - kunmap(in_page);
> + if (workspace->out_buf.dst)
> + kunmap_local(workspace->out_buf.dst);
> + if (workspace->in_buf.src) {
> + kunmap_local((void *)workspace->in_buf.src);
> put_page(in_page);
> }
> - if (out_page)
> - kunmap(out_page);
> return ret;
> }
>
> @@ -567,7 +570,7 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
> goto done;
> }
>
> - workspace->in_buf.src = kmap(pages_in[page_in_index]);
> + workspace->in_buf.src = kmap_local_page(pages_in[page_in_index]);
> workspace->in_buf.pos = 0;
> workspace->in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
>
> @@ -603,14 +606,15 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
> break;
>
> if (workspace->in_buf.pos == workspace->in_buf.size) {
> - kunmap(pages_in[page_in_index++]);
> + kunmap_local((void *)workspace->in_buf.src);
> + page_in_index++;
> if (page_in_index >= total_pages_in) {
> workspace->in_buf.src = NULL;
> ret = -EIO;
> goto done;
> }
> srclen -= PAGE_SIZE;
> - workspace->in_buf.src = kmap(pages_in[page_in_index]);
> + workspace->in_buf.src = kmap_local_page(pages_in[page_in_index]);
> workspace->in_buf.pos = 0;
> workspace->in_buf.size = min_t(size_t, srclen, PAGE_SIZE);
> }
> @@ -619,7 +623,7 @@ int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
> zero_fill_bio(cb->orig_bio);
> done:
> if (workspace->in_buf.src)
> - kunmap(pages_in[page_in_index]);
> + kunmap_local((void *)workspace->in_buf.src);
> return ret;
> }
>
> --
> 2.36.1


2022-07-14 07:48:54

by Fabio M. De Francesco

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On giovedì 14 luglio 2022 02:25:20 CEST Wang Yugui wrote:
> Hi,
>
> Compiler warning:
>
> fs/btrfs/zstd.c:478:55: warning: passing argument 1 of ‘__kunmap_local’
discards ‘const’ qualifier from pointer target type [-Wdiscarded-
qualifiers]
> 478 | kunmap_local(workspace->in_buf.src);
> ./include/linux/highmem-internal.h:284:24: note: in definition of macro
‘kunmap_local’
> 284 | __kunmap_local(__addr); \
> | ^~~~~~
> ./include/linux/highmem-internal.h:200:41: note: expected ‘void *’ but
argument is of type ‘const void *’
> 200 | static inline void __kunmap_local(void *addr)
> | ~~~~~~^~~~
>
> Best Regards
> Wang Yugui ([email protected])
> 2022/07/14

Thanks for the build test, but you're a little late :)

This patch is superseded by a series of two: please see
[PATCH v6 0/2] btrfs: Replace kmap() with kmap_local_page() in zstd.c
at https://lore.kernel.org/lkml/[email protected]/

In that series, patch 1/2 changes __kunmap_{local,atomic}() prototypes to
take pointers to const void.

Regards,

Fabio

> > The use of kmap() is being deprecated in favor of kmap_local_page().
With
> > kmap_local_page(), the mapping is per thread, CPU local and not
globally
> > visible.
> >
> > Therefore, use kmap_local_page() / kunmap_local() in zstd.c because in
> > this file the mappings are per thread and are not visible in other
> > contexts; meanwhile refactor zstd_compress_pages() to comply with
nested
> > local mapping / unmapping ordering rules.
> >


2022-07-14 12:47:04

by David Sterba

[permalink] [raw]
Subject: Re: [PATCH] btrfs: Replace kmap() with kmap_local_page() in zstd.c

On Thu, Jul 14, 2022 at 08:25:20AM +0800, Wang Yugui wrote:
> Hi,
>
> Compiler warning:
>
> fs/btrfs/zstd.c:478:55: warning: passing argument 1 of ‘__kunmap_local’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
> 478 | kunmap_local(workspace->in_buf.src);
> ./include/linux/highmem-internal.h:284:24: note: in definition of macro ‘kunmap_local’
> 284 | __kunmap_local(__addr); \
> | ^~~~~~
> ./include/linux/highmem-internal.h:200:41: note: expected ‘void *’ but argument is of type ‘const void *’
> 200 | static inline void __kunmap_local(void *addr)
> | ~~~~~~^~~~

This requires patch
https://lore.kernel.org/all/[email protected]/
that adds const to kmap/kunmap API.