Skip to content

Commit 728d392

Browse files
Javier Pellojankara
authored andcommitted
fs/ext2: Avoid page_address on pages returned by ext2_get_page
Commit 782b76d ("fs/ext2: Replace kmap() with kmap_local_page()") replaced the kmap/kunmap calls in ext2_get_page/ext2_put_page with kmap_local_page/kunmap_local for efficiency reasons. As a necessary side change, the commit also made ext2_get_page (and ext2_find_entry and ext2_dotdot) return the mapping address along with the page itself, as it is required for kunmap_local, and converted uses of page_address on such pages to use the newly returned address instead. However, uses of page_address on such pages were missed in ext2_check_page and ext2_delete_entry, which triggers oopses if kmap_local_page happens to return an address from high memory. Fix this now by converting the remaining uses of page_address to use the right address, as returned by kmap_local_page. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Ira Weiny <[email protected]> Signed-off-by: Javier Pello <[email protected]> Fixes: 782b76d ("fs/ext2: Replace kmap() with kmap_local_page()") Signed-off-by: Jan Kara <[email protected]>
1 parent 2acf15b commit 728d392

File tree

3 files changed

+10
-9
lines changed

3 files changed

+10
-9
lines changed

fs/ext2/dir.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,11 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
106106
return err;
107107
}
108108

109-
static bool ext2_check_page(struct page *page, int quiet)
109+
static bool ext2_check_page(struct page *page, int quiet, char *kaddr)
110110
{
111111
struct inode *dir = page->mapping->host;
112112
struct super_block *sb = dir->i_sb;
113113
unsigned chunk_size = ext2_chunk_size(dir);
114-
char *kaddr = page_address(page);
115114
u32 max_inumber = le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count);
116115
unsigned offs, rec_len;
117116
unsigned limit = PAGE_SIZE;
@@ -205,7 +204,8 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n,
205204
if (!IS_ERR(page)) {
206205
*page_addr = kmap_local_page(page);
207206
if (unlikely(!PageChecked(page))) {
208-
if (PageError(page) || !ext2_check_page(page, quiet))
207+
if (PageError(page) || !ext2_check_page(page, quiet,
208+
*page_addr))
209209
goto fail;
210210
}
211211
}
@@ -584,10 +584,10 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
584584
* ext2_delete_entry deletes a directory entry by merging it with the
585585
* previous entry. Page is up-to-date.
586586
*/
587-
int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
587+
int ext2_delete_entry (struct ext2_dir_entry_2 *dir, struct page *page,
588+
char *kaddr)
588589
{
589590
struct inode *inode = page->mapping->host;
590-
char *kaddr = page_address(page);
591591
unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
592592
unsigned to = ((char *)dir - kaddr) +
593593
ext2_rec_len_from_disk(dir->rec_len);
@@ -607,7 +607,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
607607
de = ext2_next_entry(de);
608608
}
609609
if (pde)
610-
from = (char*)pde - (char*)page_address(page);
610+
from = (char *)pde - kaddr;
611611
pos = page_offset(page) + from;
612612
lock_page(page);
613613
err = ext2_prepare_chunk(page, pos, to - from);

fs/ext2/ext2.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,8 @@ extern int ext2_inode_by_name(struct inode *dir,
740740
extern int ext2_make_empty(struct inode *, struct inode *);
741741
extern struct ext2_dir_entry_2 *ext2_find_entry(struct inode *, const struct qstr *,
742742
struct page **, void **res_page_addr);
743-
extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
743+
extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page,
744+
char *kaddr);
744745
extern int ext2_empty_dir (struct inode *);
745746
extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p, void **pa);
746747
extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, void *,

fs/ext2/namei.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry)
293293
goto out;
294294
}
295295

296-
err = ext2_delete_entry (de, page);
296+
err = ext2_delete_entry (de, page, page_addr);
297297
ext2_put_page(page, page_addr);
298298
if (err)
299299
goto out;
@@ -397,7 +397,7 @@ static int ext2_rename (struct user_namespace * mnt_userns,
397397
old_inode->i_ctime = current_time(old_inode);
398398
mark_inode_dirty(old_inode);
399399

400-
ext2_delete_entry(old_de, old_page);
400+
ext2_delete_entry(old_de, old_page, old_page_addr);
401401

402402
if (dir_de) {
403403
if (old_dir != new_dir)

0 commit comments

Comments
 (0)