mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									5f0663bb4a
								
							
						
					
					
						commit
						fb094c9074
					
				
					 3 changed files with 30 additions and 35 deletions
				
			
		| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue