ext2, dax: introduce ext2_dax_aops

In preparation for the dax implementation to start associating dax pages
to inodes via page->mapping, we need to provide a 'struct
address_space_operations' instance for dax. Otherwise, direct-I/O
triggers incorrect page cache assumptions and warnings.

Reviewed-by: Jan Kara <jack@suse.com>
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Dan Williams 2017-12-21 12:25:11 -08:00
Родитель 5f0663bb4a
Коммит fb094c9074
3 изменённых файлов: 30 добавлений и 35 удалений

Просмотреть файл

@ -814,6 +814,7 @@ extern const struct inode_operations ext2_file_inode_operations;
extern const struct file_operations ext2_file_operations; extern const struct file_operations ext2_file_operations;
/* inode.c */ /* inode.c */
extern void ext2_set_file_ops(struct inode *inode);
extern const struct address_space_operations ext2_aops; extern const struct address_space_operations ext2_aops;
extern const struct address_space_operations ext2_nobh_aops; extern const struct address_space_operations ext2_nobh_aops;
extern const struct iomap_ops ext2_iomap_ops; extern const struct iomap_ops ext2_iomap_ops;

Просмотреть файл

@ -940,9 +940,6 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
loff_t offset = iocb->ki_pos; loff_t offset = iocb->ki_pos;
ssize_t ret; ssize_t ret;
if (WARN_ON_ONCE(IS_DAX(inode)))
return -EIO;
ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block);
if (ret < 0 && iov_iter_rw(iter) == WRITE) if (ret < 0 && iov_iter_rw(iter) == WRITE)
ext2_write_failed(mapping, offset + count); ext2_write_failed(mapping, offset + count);
@ -952,17 +949,16 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
static int static int
ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
{ {
#ifdef CONFIG_FS_DAX
if (dax_mapping(mapping)) {
return dax_writeback_mapping_range(mapping,
mapping->host->i_sb->s_bdev,
wbc);
}
#endif
return mpage_writepages(mapping, wbc, ext2_get_block); return mpage_writepages(mapping, wbc, ext2_get_block);
} }
static int
ext2_dax_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
return dax_writeback_mapping_range(mapping,
mapping->host->i_sb->s_bdev, wbc);
}
const struct address_space_operations ext2_aops = { const struct address_space_operations ext2_aops = {
.readpage = ext2_readpage, .readpage = ext2_readpage,
.readpages = ext2_readpages, .readpages = ext2_readpages,
@ -990,6 +986,13 @@ const struct address_space_operations ext2_nobh_aops = {
.error_remove_page = generic_error_remove_page, .error_remove_page = generic_error_remove_page,
}; };
static const struct address_space_operations ext2_dax_aops = {
.writepages = ext2_dax_writepages,
.direct_IO = noop_direct_IO,
.set_page_dirty = noop_set_page_dirty,
.invalidatepage = noop_invalidatepage,
};
/* /*
* Probably it should be a library function... search for first non-zero word * Probably it should be a library function... search for first non-zero word
* or memcmp with zero_page, whatever is better for particular architecture. * or memcmp with zero_page, whatever is better for particular architecture.
@ -1388,6 +1391,18 @@ void ext2_set_inode_flags(struct inode *inode)
inode->i_flags |= S_DAX; inode->i_flags |= S_DAX;
} }
void ext2_set_file_ops(struct inode *inode)
{
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
if (IS_DAX(inode))
inode->i_mapping->a_ops = &ext2_dax_aops;
else if (test_opt(inode->i_sb, NOBH))
inode->i_mapping->a_ops = &ext2_nobh_aops;
else
inode->i_mapping->a_ops = &ext2_aops;
}
struct inode *ext2_iget (struct super_block *sb, unsigned long ino) struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
{ {
struct ext2_inode_info *ei; struct ext2_inode_info *ei;
@ -1480,14 +1495,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
ei->i_data[n] = raw_inode->i_block[n]; ei->i_data[n] = raw_inode->i_block[n];
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations; ext2_set_file_ops(inode);
if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations; inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations; inode->i_fop = &ext2_dir_operations;

Просмотреть файл

@ -107,14 +107,7 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
inode->i_op = &ext2_file_inode_operations; ext2_set_file_ops(inode);
if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
mark_inode_dirty(inode); mark_inode_dirty(inode);
return ext2_add_nondir(dentry, inode); return ext2_add_nondir(dentry, inode);
} }
@ -125,14 +118,7 @@ static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
inode->i_op = &ext2_file_inode_operations; ext2_set_file_ops(inode);
if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
mark_inode_dirty(inode); mark_inode_dirty(inode);
d_tmpfile(dentry, inode); d_tmpfile(dentry, inode);
unlock_new_inode(inode); unlock_new_inode(inode);