2020-04-30 21:54:25

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 0/9] Introduce attach/clear_page_private to cleanup code

Hi,

Based on the previous thread [1], this patchset introduces attach_page_private
and clear_page_private to replace attach_page_buffers and __clear_page_buffers.
Thanks a lot for the constructive suggestions and comments from Christoph,
Matthew and Dave.

And sorry for cross post to different lists since it modifies different subsystems.

RFC -> RFC V2:

1. rename the new functions and add comments for them.
2. change the return type of attach_page_private.
3. call attach_page_private(newpage, clear_page_private(page)) to cleanup code further.
4. avoid potential use-after-free in orangefs.

[1]. https://lore.kernel.org/linux-fsdevel/[email protected]/

Thanks,
Guoqing

Guoqing Jiang (9):
include/linux/pagemap.h: introduce attach/clear_page_private
md: remove __clear_page_buffers and use attach/clear_page_private
btrfs: use attach/clear_page_private
fs/buffer.c: use attach/clear_page_private
f2fs: use attach/clear_page_private
iomap: use attach/clear_page_private
ntfs: replace attach_page_buffers with attach_page_private
orangefs: use attach/clear_page_private
buffer_head.h: remove attach_page_buffers

drivers/md/md-bitmap.c | 12 ++----------
fs/btrfs/disk-io.c | 4 +---
fs/btrfs/extent_io.c | 21 ++++++---------------
fs/btrfs/inode.c | 23 +++++------------------
fs/buffer.c | 16 ++++------------
fs/f2fs/f2fs.h | 11 ++---------
fs/iomap/buffered-io.c | 19 ++++---------------
fs/ntfs/aops.c | 2 +-
fs/ntfs/mft.c | 2 +-
fs/orangefs/inode.c | 32 ++++++--------------------------
include/linux/buffer_head.h | 8 --------
include/linux/pagemap.h | 35 +++++++++++++++++++++++++++++++++++
12 files changed, 67 insertions(+), 118 deletions(-)

--
2.17.1


2020-04-30 21:54:38

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 7/9] ntfs: replace attach_page_buffers with attach_page_private

Call the new function since attach_page_buffers will be removed.

Cc: Anton Altaparmakov <[email protected]>
Cc: [email protected]
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new function to attach_page_private.

fs/ntfs/aops.c | 2 +-
fs/ntfs/mft.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 554b744f41bf..bb0a43860ad2 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -1732,7 +1732,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) {
bh = bh->b_this_page;
} while (bh);
tail->b_this_page = head;
- attach_page_buffers(page, head);
+ attach_page_private(page, head);
} else
buffers_to_free = bh;
}
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 3aac5c917afe..fbb9f1bc623d 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -504,7 +504,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no,
bh = bh->b_this_page;
} while (bh);
tail->b_this_page = head;
- attach_page_buffers(page, head);
+ attach_page_private(page, head);
}
bh = head = page_buffers(page);
BUG_ON(!bh);
--
2.17.1

2020-04-30 21:54:44

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 5/9] f2fs: use attach/clear_page_private

Since the new pair function is introduced, we can call them to clean the
code in f2fs.h.

Cc: Jaegeuk Kim <[email protected]>
Cc: [email protected]
Acked-by: Chao Yu <[email protected]>
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new functions to attach/clear_page_private.

fs/f2fs/f2fs.h | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index ba470d5687fe..24d22bd7352d 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3051,19 +3051,12 @@ static inline void f2fs_set_page_private(struct page *page,
if (PagePrivate(page))
return;

- get_page(page);
- SetPagePrivate(page);
- set_page_private(page, data);
+ attach_page_private(page, (void *)data);
}

static inline void f2fs_clear_page_private(struct page *page)
{
- if (!PagePrivate(page))
- return;
-
- set_page_private(page, 0);
- ClearPagePrivate(page);
- f2fs_put_page(page, 0);
+ clear_page_private(page);
}

/*
--
2.17.1

2020-04-30 21:54:54

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 6/9] iomap: use attach/clear_page_private

Since the new pair function is introduced, we can call them to clean the
code in iomap.

Cc: Christoph Hellwig <[email protected]>
Cc: "Darrick J. Wong" <[email protected]>
Cc: [email protected]
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new functions to attach/clear_page_private.
2. call attach_page_private(newpage, clear_page_private(page)) to
cleanup code further as suggested by Matthew Wilcox.
3. don't return attach_page_private in iomap_page_create per the
comment from Christoph Hellwig.

fs/iomap/buffered-io.c | 19 ++++---------------
1 file changed, 4 insertions(+), 15 deletions(-)

diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 89e21961d1ad..cf4c1b02a9d8 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -59,24 +59,19 @@ iomap_page_create(struct inode *inode, struct page *page)
* migrate_page_move_mapping() assumes that pages with private data have
* their count elevated by 1.
*/
- get_page(page);
- set_page_private(page, (unsigned long)iop);
- SetPagePrivate(page);
+ attach_page_private(page, iop);
return iop;
}

static void
iomap_page_release(struct page *page)
{
- struct iomap_page *iop = to_iomap_page(page);
+ struct iomap_page *iop = clear_page_private(page);

if (!iop)
return;
WARN_ON_ONCE(atomic_read(&iop->read_count));
WARN_ON_ONCE(atomic_read(&iop->write_count));
- ClearPagePrivate(page);
- set_page_private(page, 0);
- put_page(page);
kfree(iop);
}

@@ -554,14 +549,8 @@ iomap_migrate_page(struct address_space *mapping, struct page *newpage,
if (ret != MIGRATEPAGE_SUCCESS)
return ret;

- if (page_has_private(page)) {
- ClearPagePrivate(page);
- get_page(newpage);
- set_page_private(newpage, page_private(page));
- set_page_private(page, 0);
- put_page(page);
- SetPagePrivate(newpage);
- }
+ if (page_has_private(page))
+ attach_page_private(newpage, clear_page_private(page));

if (mode != MIGRATE_SYNC_NO_COPY)
migrate_page_copy(newpage, page);
--
2.17.1

2020-04-30 21:55:00

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 8/9] orangefs: use attach/clear_page_private

Since the new pair function is introduced, we can call them to clean the
code in orangefs.

Cc: Mike Marshall <[email protected]>
Cc: Martin Brandenburg <[email protected]>
Cc: [email protected]
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new functions to attach/clear_page_private.
2. avoid potential use-after-free as suggested by Dave Chinner.

fs/orangefs/inode.c | 32 ++++++--------------------------
1 file changed, 6 insertions(+), 26 deletions(-)

diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 12ae630fbed7..139c450aca68 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -62,12 +62,7 @@ static int orangefs_writepage_locked(struct page *page,
} else {
ret = 0;
}
- if (wr) {
- kfree(wr);
- set_page_private(page, 0);
- ClearPagePrivate(page);
- put_page(page);
- }
+ kfree(clear_page_private(page));
return ret;
}

@@ -409,9 +404,7 @@ static int orangefs_write_begin(struct file *file,
wr->len = len;
wr->uid = current_fsuid();
wr->gid = current_fsgid();
- SetPagePrivate(page);
- set_page_private(page, (unsigned long)wr);
- get_page(page);
+ attach_page_private(page, wr);
okay:
return 0;
}
@@ -459,18 +452,12 @@ static void orangefs_invalidatepage(struct page *page,
wr = (struct orangefs_write_range *)page_private(page);

if (offset == 0 && length == PAGE_SIZE) {
- kfree((struct orangefs_write_range *)page_private(page));
- set_page_private(page, 0);
- ClearPagePrivate(page);
- put_page(page);
+ kfree(clear_page_private(page));
return;
/* write range entirely within invalidate range (or equal) */
} else if (page_offset(page) + offset <= wr->pos &&
wr->pos + wr->len <= page_offset(page) + offset + length) {
- kfree((struct orangefs_write_range *)page_private(page));
- set_page_private(page, 0);
- ClearPagePrivate(page);
- put_page(page);
+ kfree(clear_page_private(page));
/* XXX is this right? only caller in fs */
cancel_dirty_page(page);
return;
@@ -535,12 +522,7 @@ static int orangefs_releasepage(struct page *page, gfp_t foo)

static void orangefs_freepage(struct page *page)
{
- if (PagePrivate(page)) {
- kfree((struct orangefs_write_range *)page_private(page));
- set_page_private(page, 0);
- ClearPagePrivate(page);
- put_page(page);
- }
+ kfree(clear_page_private(page));
}

static int orangefs_launder_page(struct page *page)
@@ -740,9 +722,7 @@ vm_fault_t orangefs_page_mkwrite(struct vm_fault *vmf)
wr->len = PAGE_SIZE;
wr->uid = current_fsuid();
wr->gid = current_fsgid();
- SetPagePrivate(page);
- set_page_private(page, (unsigned long)wr);
- get_page(page);
+ attach_page_private(page, wr);
okay:

file_update_time(vmf->vma->vm_file);
--
2.17.1

2020-04-30 21:55:29

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 4/9] fs/buffer.c: use attach/clear_page_private

Since the new pair function is introduced, we can call them to clean the
code in buffer.c.

Cc: Alexander Viro <[email protected]>
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new functions to attach/clear_page_private.

fs/buffer.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index a60f60396cfa..60dd61384b13 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -123,14 +123,6 @@ void __wait_on_buffer(struct buffer_head * bh)
}
EXPORT_SYMBOL(__wait_on_buffer);

-static void
-__clear_page_buffers(struct page *page)
-{
- ClearPagePrivate(page);
- set_page_private(page, 0);
- put_page(page);
-}
-
static void buffer_io_error(struct buffer_head *bh, char *msg)
{
if (!test_bit(BH_Quiet, &bh->b_state))
@@ -906,7 +898,7 @@ link_dev_buffers(struct page *page, struct buffer_head *head)
bh = bh->b_this_page;
} while (bh);
tail->b_this_page = head;
- attach_page_buffers(page, head);
+ attach_page_private(page, head);
}

static sector_t blkdev_max_block(struct block_device *bdev, unsigned int size)
@@ -1580,7 +1572,7 @@ void create_empty_buffers(struct page *page,
bh = bh->b_this_page;
} while (bh != head);
}
- attach_page_buffers(page, head);
+ attach_page_private(page, head);
spin_unlock(&page->mapping->private_lock);
}
EXPORT_SYMBOL(create_empty_buffers);
@@ -2567,7 +2559,7 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head)
bh->b_this_page = head;
bh = bh->b_this_page;
} while (bh != head);
- attach_page_buffers(page, head);
+ attach_page_private(page, head);
spin_unlock(&page->mapping->private_lock);
}

@@ -3227,7 +3219,7 @@ drop_buffers(struct page *page, struct buffer_head **buffers_to_free)
bh = next;
} while (bh != head);
*buffers_to_free = head;
- __clear_page_buffers(page);
+ clear_page_private(page);
return 1;
failed:
return 0;
--
2.17.1

2020-04-30 21:55:50

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 3/9] btrfs: use attach/clear_page_private

Since the new pair function is introduced, we can call them to clean the
code in btrfs.

Cc: Chris Mason <[email protected]>
Cc: Josef Bacik <[email protected]>
Cc: David Sterba <[email protected]>
Cc: [email protected]
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new functions to attach/clear_page_private.
2. call attach_page_private(newpage, clear_page_private(page)) to
cleanup code further as suggested by Dave Chinner.

fs/btrfs/disk-io.c | 4 +---
fs/btrfs/extent_io.c | 21 ++++++---------------
fs/btrfs/inode.c | 23 +++++------------------
3 files changed, 12 insertions(+), 36 deletions(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a6cb5cbbdb9f..fe4acf821110 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -980,9 +980,7 @@ static void btree_invalidatepage(struct page *page, unsigned int offset,
btrfs_warn(BTRFS_I(page->mapping->host)->root->fs_info,
"page private not zero on page %llu",
(unsigned long long)page_offset(page));
- ClearPagePrivate(page);
- set_page_private(page, 0);
- put_page(page);
+ clear_page_private(page);
}
}

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 39e45b8a5031..095a5e83e660 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3076,22 +3076,16 @@ static int submit_extent_page(unsigned int opf,
static void attach_extent_buffer_page(struct extent_buffer *eb,
struct page *page)
{
- if (!PagePrivate(page)) {
- SetPagePrivate(page);
- get_page(page);
- set_page_private(page, (unsigned long)eb);
- } else {
+ if (!PagePrivate(page))
+ attach_page_private(page, eb);
+ else
WARN_ON(page->private != (unsigned long)eb);
- }
}

void set_page_extent_mapped(struct page *page)
{
- if (!PagePrivate(page)) {
- SetPagePrivate(page);
- get_page(page);
- set_page_private(page, EXTENT_PAGE_PRIVATE);
- }
+ if (!PagePrivate(page))
+ attach_page_private(page, (void *)EXTENT_PAGE_PRIVATE);
}

static struct extent_map *
@@ -4929,10 +4923,7 @@ static void btrfs_release_extent_buffer_pages(struct extent_buffer *eb)
* We need to make sure we haven't be attached
* to a new eb.
*/
- ClearPagePrivate(page);
- set_page_private(page, 0);
- /* One for the page private */
- put_page(page);
+ clear_page_private(page);
}

if (mapped)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 320d1062068d..34b09ab2c32a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -8303,11 +8303,8 @@ btrfs_readpages(struct file *file, struct address_space *mapping,
static int __btrfs_releasepage(struct page *page, gfp_t gfp_flags)
{
int ret = try_release_extent_mapping(page, gfp_flags);
- if (ret == 1) {
- ClearPagePrivate(page);
- set_page_private(page, 0);
- put_page(page);
- }
+ if (ret == 1)
+ clear_page_private(page);
return ret;
}

@@ -8329,14 +8326,8 @@ static int btrfs_migratepage(struct address_space *mapping,
if (ret != MIGRATEPAGE_SUCCESS)
return ret;

- if (page_has_private(page)) {
- ClearPagePrivate(page);
- get_page(newpage);
- set_page_private(newpage, page_private(page));
- set_page_private(page, 0);
- put_page(page);
- SetPagePrivate(newpage);
- }
+ if (page_has_private(page))
+ attach_page_private(newpage, clear_page_private(page));

if (PagePrivate2(page)) {
ClearPagePrivate2(page);
@@ -8458,11 +8449,7 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
}

ClearPageChecked(page);
- if (PagePrivate(page)) {
- ClearPagePrivate(page);
- set_page_private(page, 0);
- put_page(page);
- }
+ clear_page_private(page);
}

/*
--
2.17.1

2020-04-30 21:55:52

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 9/9] buffer_head.h: remove attach_page_buffers

All the callers have replaced attach_page_buffers with the new function
attach_page_private, so remove it.

Cc: Thomas Gleixner <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Roman Gushchin <[email protected]>
Cc: Andreas Dilger <[email protected]>
Signed-off-by: Guoqing Jiang <[email protected]>
---
include/linux/buffer_head.h | 8 --------
1 file changed, 8 deletions(-)

diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 15b765a181b8..22fb11e2d2e0 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -272,14 +272,6 @@ void buffer_init(void);
* inline definitions
*/

-static inline void attach_page_buffers(struct page *page,
- struct buffer_head *head)
-{
- get_page(page);
- SetPagePrivate(page);
- set_page_private(page, (unsigned long)head);
-}
-
static inline void get_bh(struct buffer_head *bh)
{
atomic_inc(&bh->b_count);
--
2.17.1

2020-04-30 21:56:17

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 2/9] md: remove __clear_page_buffers and use attach/clear_page_private

After introduce attach/clear_page_private in pagemap.h, we can remove
the duplicat code and call the new functions.

Cc: Song Liu <[email protected]>
Cc: [email protected]
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2
1. change the name of new functions to attach/clear_page_private.

drivers/md/md-bitmap.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index b952bd45bd6a..033d12063600 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -324,14 +324,6 @@ static void end_bitmap_write(struct buffer_head *bh, int uptodate)
wake_up(&bitmap->write_wait);
}

-/* copied from buffer.c */
-static void
-__clear_page_buffers(struct page *page)
-{
- ClearPagePrivate(page);
- set_page_private(page, 0);
- put_page(page);
-}
static void free_buffers(struct page *page)
{
struct buffer_head *bh;
@@ -345,7 +337,7 @@ static void free_buffers(struct page *page)
free_buffer_head(bh);
bh = next;
}
- __clear_page_buffers(page);
+ clear_page_private(page);
put_page(page);
}

@@ -374,7 +366,7 @@ static int read_page(struct file *file, unsigned long index,
ret = -ENOMEM;
goto out;
}
- attach_page_buffers(page, bh);
+ attach_page_private(page, bh);
blk_cur = index << (PAGE_SHIFT - inode->i_blkbits);
while (bh) {
block = blk_cur;
--
2.17.1

2020-04-30 21:56:27

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

The logic in attach_page_buffers and __clear_page_buffers are quite
paired, but

1. they are located in different files.

2. attach_page_buffers is implemented in buffer_head.h, so it could be
used by other files. But __clear_page_buffers is static function in
buffer.c and other potential users can't call the function, md-bitmap
even copied the function.

So, introduce the new attach/clear_page_private to replace them. With
the new pair of function, we will remove the usage of attach_page_buffers
and __clear_page_buffers in next patches. Thanks for the new names from
Christoph Hellwig.

Suggested-by: Matthew Wilcox <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: "Darrick J. Wong" <[email protected]>
Cc: William Kucharski <[email protected]>
Cc: "Kirill A. Shutemov" <[email protected]>
Cc: Andreas Gruenbacher <[email protected]>
Cc: Yang Shi <[email protected]>
Cc: Yafang Shao <[email protected]>
Cc: Song Liu <[email protected]>
Cc: [email protected]
Cc: Chris Mason <[email protected]>
Cc: Josef Bacik <[email protected]>
Cc: David Sterba <[email protected]>
Cc: [email protected]
Cc: Alexander Viro <[email protected]>
Cc: Jaegeuk Kim <[email protected]>
Cc: Chao Yu <[email protected]>
Cc: [email protected]
Cc: Christoph Hellwig <[email protected]>
Cc: [email protected]
Cc: Anton Altaparmakov <[email protected]>
Cc: [email protected]
Cc: Mike Marshall <[email protected]>
Cc: Martin Brandenburg <[email protected]>
Cc: [email protected]
Cc: Thomas Gleixner <[email protected]>
Cc: Sebastian Andrzej Siewior <[email protected]>
Cc: Roman Gushchin <[email protected]>
Cc: Andreas Dilger <[email protected]>
Signed-off-by: Guoqing Jiang <[email protected]>
---
RFC -> RFC V2: Address the comments from Christoph Hellwig
1. change function names to attach/clear_page_private and add comments.
2. change the return type of attach_page_private.

include/linux/pagemap.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)

diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index a8f7bd8ea1c6..2e515f210b18 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -205,6 +205,41 @@ static inline int page_cache_add_speculative(struct page *page, int count)
return __page_cache_add_speculative(page, count);
}

+/**
+ * attach_page_private - attach data to page's private field and set PG_private.
+ * @page: page to be attached and set flag.
+ * @data: data to attach to page's private field.
+ *
+ * Need to take reference as mm.h said "Setting PG_private should also increment
+ * the refcount".
+ */
+static inline void attach_page_private(struct page *page, void *data)
+{
+ get_page(page);
+ set_page_private(page, (unsigned long)data);
+ SetPagePrivate(page);
+}
+
+/**
+ * clear_page_private - clear page's private field and PG_private.
+ * @page: page to be cleared.
+ *
+ * The counterpart function of attach_page_private.
+ * Return: private data of page or NULL if page doesn't have private data.
+ */
+static inline void *clear_page_private(struct page *page)
+{
+ void *data = (void *)page_private(page);
+
+ if (!PagePrivate(page))
+ return NULL;
+ ClearPagePrivate(page);
+ set_page_private(page, 0);
+ put_page(page);
+
+ return data;
+}
+
#ifdef CONFIG_NUMA
extern struct page *__page_cache_alloc(gfp_t gfp);
#else
--
2.17.1

2020-04-30 22:12:21

by Andreas Grünbacher

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

Hi,

Am Do., 30. Apr. 2020 um 23:56 Uhr schrieb Guoqing Jiang
<[email protected]>:
> The logic in attach_page_buffers and __clear_page_buffers are quite
> paired, but
>
> 1. they are located in different files.
>
> 2. attach_page_buffers is implemented in buffer_head.h, so it could be
> used by other files. But __clear_page_buffers is static function in
> buffer.c and other potential users can't call the function, md-bitmap
> even copied the function.
>
> So, introduce the new attach/clear_page_private to replace them. With
> the new pair of function, we will remove the usage of attach_page_buffers
> and __clear_page_buffers in next patches. Thanks for the new names from
> Christoph Hellwig.
>
> Suggested-by: Matthew Wilcox <[email protected]>
> Cc: Andrew Morton <[email protected]>
> Cc: "Darrick J. Wong" <[email protected]>
> Cc: William Kucharski <[email protected]>
> Cc: "Kirill A. Shutemov" <[email protected]>
> Cc: Andreas Gruenbacher <[email protected]>
> Cc: Yang Shi <[email protected]>
> Cc: Yafang Shao <[email protected]>
> Cc: Song Liu <[email protected]>
> Cc: [email protected]
> Cc: Chris Mason <[email protected]>
> Cc: Josef Bacik <[email protected]>
> Cc: David Sterba <[email protected]>
> Cc: [email protected]
> Cc: Alexander Viro <[email protected]>
> Cc: Jaegeuk Kim <[email protected]>
> Cc: Chao Yu <[email protected]>
> Cc: [email protected]
> Cc: Christoph Hellwig <[email protected]>
> Cc: [email protected]
> Cc: Anton Altaparmakov <[email protected]>
> Cc: [email protected]
> Cc: Mike Marshall <[email protected]>
> Cc: Martin Brandenburg <[email protected]>
> Cc: [email protected]
> Cc: Thomas Gleixner <[email protected]>
> Cc: Sebastian Andrzej Siewior <[email protected]>
> Cc: Roman Gushchin <[email protected]>
> Cc: Andreas Dilger <[email protected]>
> Signed-off-by: Guoqing Jiang <[email protected]>
> ---
> RFC -> RFC V2: Address the comments from Christoph Hellwig
> 1. change function names to attach/clear_page_private and add comments.
> 2. change the return type of attach_page_private.
>
> include/linux/pagemap.h | 35 +++++++++++++++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
>
> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
> index a8f7bd8ea1c6..2e515f210b18 100644
> --- a/include/linux/pagemap.h
> +++ b/include/linux/pagemap.h
> @@ -205,6 +205,41 @@ static inline int page_cache_add_speculative(struct page *page, int count)
> return __page_cache_add_speculative(page, count);
> }
>
> +/**
> + * attach_page_private - attach data to page's private field and set PG_private.
> + * @page: page to be attached and set flag.
> + * @data: data to attach to page's private field.
> + *
> + * Need to take reference as mm.h said "Setting PG_private should also increment
> + * the refcount".
> + */
> +static inline void attach_page_private(struct page *page, void *data)
> +{
> + get_page(page);
> + set_page_private(page, (unsigned long)data);
> + SetPagePrivate(page);
> +}
> +
> +/**
> + * clear_page_private - clear page's private field and PG_private.
> + * @page: page to be cleared.
> + *
> + * The counterpart function of attach_page_private.
> + * Return: private data of page or NULL if page doesn't have private data.
> + */
> +static inline void *clear_page_private(struct page *page)
> +{
> + void *data = (void *)page_private(page);
> +
> + if (!PagePrivate(page))
> + return NULL;
> + ClearPagePrivate(page);
> + set_page_private(page, 0);
> + put_page(page);
> +
> + return data;
> +}
> +

I like this in general, but the name clear_page_private suggests that
this might be the inverse operation of set_page_private, which it is
not. So maybe this can be renamed to detach_page_private to more
clearly indicate that it pairs with attach_page_private?

> #ifdef CONFIG_NUMA
> extern struct page *__page_cache_alloc(gfp_t gfp);
> #else
> --
> 2.17.1
>

Thanks,
Andreas

2020-04-30 22:18:27

by Matthew Wilcox

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

On Thu, Apr 30, 2020 at 11:44:42PM +0200, Guoqing Jiang wrote:
> +/**
> + * attach_page_private - attach data to page's private field and set PG_private.
> + * @page: page to be attached and set flag.
> + * @data: data to attach to page's private field.
> + *
> + * Need to take reference as mm.h said "Setting PG_private should also increment
> + * the refcount".
> + */

I don't think this will read well when added to the API documentation.
Try this:

/**
* attach_page_private - Attach private data to a page.
* @page: Page to attach data to.
* @data: Data to attach to page.
*
* Attaching private data to a page increments the page's reference count.
* The data must be detached before the page will be freed.
*/

> +/**
> + * clear_page_private - clear page's private field and PG_private.
> + * @page: page to be cleared.
> + *
> + * The counterpart function of attach_page_private.
> + * Return: private data of page or NULL if page doesn't have private data.
> + */

Seems to me that the opposite of "attach" is "detach", not "clear".

/**
* detach_page_private - Detach private data from a page.
* @page: Page to detach data from.
*
* Removes the data that was previously attached to the page and decrements
* the refcount on the page.
*
* Return: Data that was attached to the page.
*/

2020-05-01 01:45:01

by Al Viro

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

On Thu, Apr 30, 2020 at 03:13:38PM -0700, Matthew Wilcox wrote:

> > +/**
> > + * clear_page_private - clear page's private field and PG_private.
> > + * @page: page to be cleared.
> > + *
> > + * The counterpart function of attach_page_private.
> > + * Return: private data of page or NULL if page doesn't have private data.
> > + */
>
> Seems to me that the opposite of "attach" is "detach", not "clear".

Or "remove", perhaps...

2020-05-01 01:52:21

by Al Viro

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

On Fri, May 01, 2020 at 02:42:29AM +0100, Al Viro wrote:
> On Thu, Apr 30, 2020 at 03:13:38PM -0700, Matthew Wilcox wrote:
>
> > > +/**
> > > + * clear_page_private - clear page's private field and PG_private.
> > > + * @page: page to be cleared.
> > > + *
> > > + * The counterpart function of attach_page_private.
> > > + * Return: private data of page or NULL if page doesn't have private data.
> > > + */
> >
> > Seems to me that the opposite of "attach" is "detach", not "clear".
>
> Or "remove", perhaps...

Actually, "detach" is better - neither "clear" nor "remove" imply "... and give
me what used to be attached there", as this thing is doing.

2020-05-01 06:40:10

by Guoqing Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

On 5/1/20 12:10 AM, Andreas Grünbacher wrote:
> Hi,
>
> Am Do., 30. Apr. 2020 um 23:56 Uhr schrieb Guoqing Jiang
> <[email protected]>:
>> The logic in attach_page_buffers and __clear_page_buffers are quite
>> paired, but
>>
>> 1. they are located in different files.
>>
>> 2. attach_page_buffers is implemented in buffer_head.h, so it could be
>> used by other files. But __clear_page_buffers is static function in
>> buffer.c and other potential users can't call the function, md-bitmap
>> even copied the function.
>>
>> So, introduce the new attach/clear_page_private to replace them. With
>> the new pair of function, we will remove the usage of attach_page_buffers
>> and __clear_page_buffers in next patches. Thanks for the new names from
>> Christoph Hellwig.
>>
>> Suggested-by: Matthew Wilcox <[email protected]>
>> Cc: Andrew Morton <[email protected]>
>> Cc: "Darrick J. Wong" <[email protected]>
>> Cc: William Kucharski <[email protected]>
>> Cc: "Kirill A. Shutemov" <[email protected]>
>> Cc: Andreas Gruenbacher <[email protected]>
>> Cc: Yang Shi <[email protected]>
>> Cc: Yafang Shao <[email protected]>
>> Cc: Song Liu <[email protected]>
>> Cc: [email protected]
>> Cc: Chris Mason <[email protected]>
>> Cc: Josef Bacik <[email protected]>
>> Cc: David Sterba <[email protected]>
>> Cc: [email protected]
>> Cc: Alexander Viro <[email protected]>
>> Cc: Jaegeuk Kim <[email protected]>
>> Cc: Chao Yu <[email protected]>
>> Cc: [email protected]
>> Cc: Christoph Hellwig <[email protected]>
>> Cc: [email protected]
>> Cc: Anton Altaparmakov <[email protected]>
>> Cc: [email protected]
>> Cc: Mike Marshall <[email protected]>
>> Cc: Martin Brandenburg <[email protected]>
>> Cc: [email protected]
>> Cc: Thomas Gleixner <[email protected]>
>> Cc: Sebastian Andrzej Siewior <[email protected]>
>> Cc: Roman Gushchin <[email protected]>
>> Cc: Andreas Dilger <[email protected]>
>> Signed-off-by: Guoqing Jiang <[email protected]>
>> ---
>> RFC -> RFC V2: Address the comments from Christoph Hellwig
>> 1. change function names to attach/clear_page_private and add comments.
>> 2. change the return type of attach_page_private.
>>
>> include/linux/pagemap.h | 35 +++++++++++++++++++++++++++++++++++
>> 1 file changed, 35 insertions(+)
>>
>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
>> index a8f7bd8ea1c6..2e515f210b18 100644
>> --- a/include/linux/pagemap.h
>> +++ b/include/linux/pagemap.h
>> @@ -205,6 +205,41 @@ static inline int page_cache_add_speculative(struct page *page, int count)
>> return __page_cache_add_speculative(page, count);
>> }
>>
>> +/**
>> + * attach_page_private - attach data to page's private field and set PG_private.
>> + * @page: page to be attached and set flag.
>> + * @data: data to attach to page's private field.
>> + *
>> + * Need to take reference as mm.h said "Setting PG_private should also increment
>> + * the refcount".
>> + */
>> +static inline void attach_page_private(struct page *page, void *data)
>> +{
>> + get_page(page);
>> + set_page_private(page, (unsigned long)data);
>> + SetPagePrivate(page);
>> +}
>> +
>> +/**
>> + * clear_page_private - clear page's private field and PG_private.
>> + * @page: page to be cleared.
>> + *
>> + * The counterpart function of attach_page_private.
>> + * Return: private data of page or NULL if page doesn't have private data.
>> + */
>> +static inline void *clear_page_private(struct page *page)
>> +{
>> + void *data = (void *)page_private(page);
>> +
>> + if (!PagePrivate(page))
>> + return NULL;
>> + ClearPagePrivate(page);
>> + set_page_private(page, 0);
>> + put_page(page);
>> +
>> + return data;
>> +}
>> +
> I like this in general, but the name clear_page_private suggests that
> this might be the inverse operation of set_page_private, which it is
> not. So maybe this can be renamed to detach_page_private to more
> clearly indicate that it pairs with attach_page_private?

Yes, the new name is better, thank you!

Cheers,
Guoqing

2020-05-01 06:41:40

by Guoqing Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

On 5/1/20 12:13 AM, Matthew Wilcox wrote:
> On Thu, Apr 30, 2020 at 11:44:42PM +0200, Guoqing Jiang wrote:
>> +/**
>> + * attach_page_private - attach data to page's private field and set PG_private.
>> + * @page: page to be attached and set flag.
>> + * @data: data to attach to page's private field.
>> + *
>> + * Need to take reference as mm.h said "Setting PG_private should also increment
>> + * the refcount".
>> + */
> I don't think this will read well when added to the API documentation.
> Try this:
>
> /**
> * attach_page_private - Attach private data to a page.
> * @page: Page to attach data to.
> * @data: Data to attach to page.
> *
> * Attaching private data to a page increments the page's reference count.
> * The data must be detached before the page will be freed.
> */
>
>> +/**
>> + * clear_page_private - clear page's private field and PG_private.
>> + * @page: page to be cleared.
>> + *
>> + * The counterpart function of attach_page_private.
>> + * Return: private data of page or NULL if page doesn't have private data.
>> + */
> Seems to me that the opposite of "attach" is "detach", not "clear".
>
> /**
> * detach_page_private - Detach private data from a page.
> * @page: Page to detach data from.
> *
> * Removes the data that was previously attached to the page and decrements
> * the refcount on the page.
> *
> * Return: Data that was attached to the page.
> */

Thanks you very much, Mattew! Will change them in next version.

Best Regards,
Guoqing

2020-05-01 06:44:40

by Guoqing Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH V2 1/9] include/linux/pagemap.h: introduce attach/clear_page_private

On 5/1/20 3:49 AM, Al Viro wrote:
> On Fri, May 01, 2020 at 02:42:29AM +0100, Al Viro wrote:
>> On Thu, Apr 30, 2020 at 03:13:38PM -0700, Matthew Wilcox wrote:
>>
>>>> +/**
>>>> + * clear_page_private - clear page's private field and PG_private.
>>>> + * @page: page to be cleared.
>>>> + *
>>>> + * The counterpart function of attach_page_private.
>>>> + * Return: private data of page or NULL if page doesn't have private data.
>>>> + */
>>> Seems to me that the opposite of "attach" is "detach", not "clear".
>> Or "remove", perhaps...
> Actually, "detach" is better - neither "clear" nor "remove" imply "... and give
> me what used to be attached there", as this thing is doing.

Ok, seems we have reached the agreement about the new name ;-), will
follow the instruction.

Thanks & Regards,
Guoqing

2020-05-01 22:20:45

by Matthew Wilcox

[permalink] [raw]
Subject: Re: [RFC PATCH V2 0/9] Introduce attach/clear_page_private to cleanup code

On Thu, Apr 30, 2020 at 11:44:41PM +0200, Guoqing Jiang wrote:
> include/linux/pagemap.h: introduce attach/clear_page_private
> md: remove __clear_page_buffers and use attach/clear_page_private
> btrfs: use attach/clear_page_private
> fs/buffer.c: use attach/clear_page_private
> f2fs: use attach/clear_page_private
> iomap: use attach/clear_page_private
> ntfs: replace attach_page_buffers with attach_page_private
> orangefs: use attach/clear_page_private
> buffer_head.h: remove attach_page_buffers

I think mm/migrate.c could also use this:

ClearPagePrivate(page);
set_page_private(newpage, page_private(page));
set_page_private(page, 0);
put_page(page);
get_page(newpage);

2020-05-01 22:44:19

by Guoqing Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH V2 0/9] Introduce attach/clear_page_private to cleanup code

On 5/2/20 12:16 AM, Matthew Wilcox wrote:
> On Thu, Apr 30, 2020 at 11:44:41PM +0200, Guoqing Jiang wrote:
>> include/linux/pagemap.h: introduce attach/clear_page_private
>> md: remove __clear_page_buffers and use attach/clear_page_private
>> btrfs: use attach/clear_page_private
>> fs/buffer.c: use attach/clear_page_private
>> f2fs: use attach/clear_page_private
>> iomap: use attach/clear_page_private
>> ntfs: replace attach_page_buffers with attach_page_private
>> orangefs: use attach/clear_page_private
>> buffer_head.h: remove attach_page_buffers
> I think mm/migrate.c could also use this:
>
> ClearPagePrivate(page);
> set_page_private(newpage, page_private(page));
> set_page_private(page, 0);
> put_page(page);
> get_page(newpage);
>

Thanks for checking!  Assume the below change is appropriate.

diff --git a/mm/migrate.c b/mm/migrate.c
index 7160c1556f79..f214adfb3fa4 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -797,10 +797,7 @@ static int __buffer_migrate_page(struct
address_space *mapping,
        if (rc != MIGRATEPAGE_SUCCESS)
                goto unlock_buffers;

-       ClearPagePrivate(page);
-       set_page_private(newpage, page_private(page));
-       set_page_private(page, 0);
-       put_page(page);
+       set_page_private(newpage, detach_page_private(page));
        get_page(newpage);

        bh = head;


Cheers,
Guoqing

2020-05-02 00:45:49

by Matthew Wilcox

[permalink] [raw]
Subject: Re: [RFC PATCH V2 0/9] Introduce attach/clear_page_private to cleanup code

On Sat, May 02, 2020 at 12:42:15AM +0200, Guoqing Jiang wrote:
> On 5/2/20 12:16 AM, Matthew Wilcox wrote:
> > On Thu, Apr 30, 2020 at 11:44:41PM +0200, Guoqing Jiang wrote:
> > > include/linux/pagemap.h: introduce attach/clear_page_private
> > > md: remove __clear_page_buffers and use attach/clear_page_private
> > > btrfs: use attach/clear_page_private
> > > fs/buffer.c: use attach/clear_page_private
> > > f2fs: use attach/clear_page_private
> > > iomap: use attach/clear_page_private
> > > ntfs: replace attach_page_buffers with attach_page_private
> > > orangefs: use attach/clear_page_private
> > > buffer_head.h: remove attach_page_buffers
> > I think mm/migrate.c could also use this:
> >
> > ClearPagePrivate(page);
> > set_page_private(newpage, page_private(page));
> > set_page_private(page, 0);
> > put_page(page);
> > get_page(newpage);
> >
>
> Thanks for checking!? Assume the below change is appropriate.
>
> diff --git a/mm/migrate.c b/mm/migrate.c
> index 7160c1556f79..f214adfb3fa4 100644
> --- a/mm/migrate.c
> +++ b/mm/migrate.c
> @@ -797,10 +797,7 @@ static int __buffer_migrate_page(struct address_space
> *mapping,
> ??????? if (rc != MIGRATEPAGE_SUCCESS)
> ??????????????? goto unlock_buffers;
>
> -?????? ClearPagePrivate(page);
> -?????? set_page_private(newpage, page_private(page));
> -?????? set_page_private(page, 0);
> -?????? put_page(page);
> +?????? set_page_private(newpage, detach_page_private(page));
> ??????? get_page(newpage);

I think you can do:

@@ -797,11 +797,7 @@ static int __buffer_migrate_page(struct address_space *mapping,
if (rc != MIGRATEPAGE_SUCCESS)
goto unlock_buffers;

- ClearPagePrivate(page);
- set_page_private(newpage, page_private(page));
- set_page_private(page, 0);
- put_page(page);
- get_page(newpage);
+ attach_page_private(newpage, detach_page_private(page));

bh = head;
do {
@@ -810,8 +806,6 @@ static int __buffer_migrate_page(struct address_space *mapping,

} while (bh != head);

- SetPagePrivate(newpage);
-
if (mode != MIGRATE_SYNC_NO_COPY)

... but maybe there's a subtlety to the ordering of the setup of the bh
and setting PagePrivate that means what you have there is a better patch.
Anybody know?

2020-05-02 08:59:38

by Guoqing Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH V2 0/9] Introduce attach/clear_page_private to cleanup code

On 5/2/20 2:41 AM, Matthew Wilcox wrote:
> On Sat, May 02, 2020 at 12:42:15AM +0200, Guoqing Jiang wrote:
>> On 5/2/20 12:16 AM, Matthew Wilcox wrote:
>>> On Thu, Apr 30, 2020 at 11:44:41PM +0200, Guoqing Jiang wrote:
>>>> include/linux/pagemap.h: introduce attach/clear_page_private
>>>> md: remove __clear_page_buffers and use attach/clear_page_private
>>>> btrfs: use attach/clear_page_private
>>>> fs/buffer.c: use attach/clear_page_private
>>>> f2fs: use attach/clear_page_private
>>>> iomap: use attach/clear_page_private
>>>> ntfs: replace attach_page_buffers with attach_page_private
>>>> orangefs: use attach/clear_page_private
>>>> buffer_head.h: remove attach_page_buffers
>>> I think mm/migrate.c could also use this:
>>>
>>> ClearPagePrivate(page);
>>> set_page_private(newpage, page_private(page));
>>> set_page_private(page, 0);
>>> put_page(page);
>>> get_page(newpage);
>>>
>> Thanks for checking!  Assume the below change is appropriate.
>>
>> diff --git a/mm/migrate.c b/mm/migrate.c
>> index 7160c1556f79..f214adfb3fa4 100644
>> --- a/mm/migrate.c
>> +++ b/mm/migrate.c
>> @@ -797,10 +797,7 @@ static int __buffer_migrate_page(struct address_space
>> *mapping,
>>         if (rc != MIGRATEPAGE_SUCCESS)
>>                 goto unlock_buffers;
>>
>> -       ClearPagePrivate(page);
>> -       set_page_private(newpage, page_private(page));
>> -       set_page_private(page, 0);
>> -       put_page(page);
>> +       set_page_private(newpage, detach_page_private(page));
>>         get_page(newpage);
> I think you can do:
>
> @@ -797,11 +797,7 @@ static int __buffer_migrate_page(struct address_space *mapping,
> if (rc != MIGRATEPAGE_SUCCESS)
> goto unlock_buffers;
>
> - ClearPagePrivate(page);
> - set_page_private(newpage, page_private(page));
> - set_page_private(page, 0);
> - put_page(page);
> - get_page(newpage);
> + attach_page_private(newpage, detach_page_private(page));
>
> bh = head;
> do {
> @@ -810,8 +806,6 @@ static int __buffer_migrate_page(struct address_space *mapping,
>
> } while (bh != head);
>
> - SetPagePrivate(newpage);
> -
> if (mode != MIGRATE_SYNC_NO_COPY)
>
> ... but maybe there's a subtlety to the ordering of the setup of the bh
> and setting PagePrivate that means what you have there is a better patch.

Yes, it is better but not sure if the order can be changed here. And seems
the original commit is this one.

commit e965f9630c651fa4249039fd4b80c9392d07a856
Author: Christoph Lameter <[email protected]>
Date:   Wed Feb 1 03:05:41 2006 -0800

    [PATCH] Direct Migration V9: Avoid writeback / page_migrate() method

    Migrate a page with buffers without requiring writeback

    This introduces a new address space operation migratepage() that
may be used
    by a filesystem to implement its own version of page migration.

    A version is provided that migrates buffers attached to pages. Some
    filesystems (ext2, ext3, xfs) are modified to utilize this feature.

    The swapper address space operation are modified so that a regular
    migrate_page() will occur for anonymous pages without writeback
(migrate_pages
    forces every anonymous page to have a swap entry).

Hope mm experts could take a look, so CC more people and mm list. And
the question is that if we can setting PagePrivate before setup bh in the
__buffer_migrate_page, thanks for your any further input.

Thanks,
Guoqing