diff options
Diffstat (limited to 'fs/ext4/file.c')
| -rw-r--r-- | fs/ext4/file.c | 180 | 
1 files changed, 88 insertions, 92 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3da21945ff1..8695f70af1e 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -57,7 +57,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)  	return 0;  } -void ext4_unwritten_wait(struct inode *inode) +static void ext4_unwritten_wait(struct inode *inode)  {  	wait_queue_head_t *wq = ext4_ioend_wq(inode); @@ -74,132 +74,126 @@ void ext4_unwritten_wait(struct inode *inode)   * or one thread will zero the other's data, causing corruption.   */  static int -ext4_unaligned_aio(struct inode *inode, const struct iovec *iov, -		   unsigned long nr_segs, loff_t pos) +ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos)  {  	struct super_block *sb = inode->i_sb;  	int blockmask = sb->s_blocksize - 1; -	size_t count = iov_length(iov, nr_segs); -	loff_t final_size = pos + count; -	if (pos >= inode->i_size) +	if (pos >= i_size_read(inode))  		return 0; -	if ((pos & blockmask) || (final_size & blockmask)) +	if ((pos | iov_iter_alignment(from)) & blockmask)  		return 1;  	return 0;  }  static ssize_t -ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, -		    unsigned long nr_segs, loff_t pos) +ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)  {  	struct file *file = iocb->ki_filp; -	struct inode *inode = file->f_mapping->host; +	struct inode *inode = file_inode(iocb->ki_filp); +	struct mutex *aio_mutex = NULL;  	struct blk_plug plug; -	int unaligned_aio = 0; -	ssize_t ret; +	int o_direct = file->f_flags & O_DIRECT;  	int overwrite = 0; -	size_t length = iov_length(iov, nr_segs); - -	if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && -	    !is_sync_kiocb(iocb)) -		unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos); +	size_t length = iov_iter_count(from); +	ssize_t ret; +	loff_t pos = iocb->ki_pos; -	/* Unaligned direct AIO must be serialized; see comment above */ -	if (unaligned_aio) { -		mutex_lock(ext4_aio_mutex(inode)); +	/* +	 * Unaligned direct AIO must be serialized; see comment above +	 * In the case of O_APPEND, assume that we must always serialize +	 */ +	if (o_direct && +	    ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && +	    !is_sync_kiocb(iocb) && +	    (file->f_flags & O_APPEND || +	     ext4_unaligned_aio(inode, from, pos))) { +		aio_mutex = ext4_aio_mutex(inode); +		mutex_lock(aio_mutex);  		ext4_unwritten_wait(inode);  	} -	BUG_ON(iocb->ki_pos != pos); -  	mutex_lock(&inode->i_mutex); -	blk_start_plug(&plug); - -	iocb->private = &overwrite; +	if (file->f_flags & O_APPEND) +		iocb->ki_pos = pos = i_size_read(inode); -	/* check whether we do a DIO overwrite or not */ -	if (ext4_should_dioread_nolock(inode) && !unaligned_aio && -	    !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { -		struct ext4_map_blocks map; -		unsigned int blkbits = inode->i_blkbits; -		int err, len; +	/* +	 * If we have encountered a bitmap-format file, the size limit +	 * is smaller than s_maxbytes, which is for extent-mapped files. +	 */ +	if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { +		struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); -		map.m_lblk = pos >> blkbits; -		map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits) -			- map.m_lblk; -		len = map.m_len; +		if ((pos > sbi->s_bitmap_maxbytes) || +		    (pos == sbi->s_bitmap_maxbytes && length > 0)) { +			mutex_unlock(&inode->i_mutex); +			ret = -EFBIG; +			goto errout; +		} -		err = ext4_map_blocks(NULL, inode, &map, 0); -		/* -		 * 'err==len' means that all of blocks has been preallocated no -		 * matter they are initialized or not.  For excluding -		 * uninitialized extents, we need to check m_flags.  There are -		 * two conditions that indicate for initialized extents. -		 * 1) If we hit extent cache, EXT4_MAP_MAPPED flag is returned; -		 * 2) If we do a real lookup, non-flags are returned. -		 * So we should check these two conditions. -		 */ -		if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) -			overwrite = 1; +		if (pos + length > sbi->s_bitmap_maxbytes) +			iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos);  	} -	ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); -	mutex_unlock(&inode->i_mutex); - -	if (ret > 0) { -		ssize_t err; - -		err = generic_write_sync(file, pos, ret); -		if (err < 0 && ret > 0) -			ret = err; -	} -	blk_finish_plug(&plug); +	if (o_direct) { +		blk_start_plug(&plug); -	if (unaligned_aio) -		mutex_unlock(ext4_aio_mutex(inode)); +		iocb->private = &overwrite; -	return ret; -} +		/* check whether we do a DIO overwrite or not */ +		if (ext4_should_dioread_nolock(inode) && !aio_mutex && +		    !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { +			struct ext4_map_blocks map; +			unsigned int blkbits = inode->i_blkbits; +			int err, len; -static ssize_t -ext4_file_write(struct kiocb *iocb, const struct iovec *iov, -		unsigned long nr_segs, loff_t pos) -{ -	struct inode *inode = file_inode(iocb->ki_filp); -	ssize_t ret; +			map.m_lblk = pos >> blkbits; +			map.m_len = (EXT4_BLOCK_ALIGN(pos + length, blkbits) >> blkbits) +				- map.m_lblk; +			len = map.m_len; -	/* -	 * If we have encountered a bitmap-format file, the size limit -	 * is smaller than s_maxbytes, which is for extent-mapped files. -	 */ +			err = ext4_map_blocks(NULL, inode, &map, 0); +			/* +			 * 'err==len' means that all of blocks has +			 * been preallocated no matter they are +			 * initialized or not.  For excluding +			 * unwritten extents, we need to check +			 * m_flags.  There are two conditions that +			 * indicate for initialized extents.  1) If we +			 * hit extent cache, EXT4_MAP_MAPPED flag is +			 * returned; 2) If we do a real lookup, +			 * non-flags are returned.  So we should check +			 * these two conditions. +			 */ +			if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) +				overwrite = 1; +		} +	} -	if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { -		struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); -		size_t length = iov_length(iov, nr_segs); +	ret = __generic_file_write_iter(iocb, from); +	mutex_unlock(&inode->i_mutex); -		if ((pos > sbi->s_bitmap_maxbytes || -		    (pos == sbi->s_bitmap_maxbytes && length > 0))) -			return -EFBIG; +	if (ret > 0) { +		ssize_t err; -		if (pos + length > sbi->s_bitmap_maxbytes) { -			nr_segs = iov_shorten((struct iovec *)iov, nr_segs, -					      sbi->s_bitmap_maxbytes - pos); -		} +		err = generic_write_sync(file, iocb->ki_pos - ret, ret); +		if (err < 0) +			ret = err;  	} +	if (o_direct) +		blk_finish_plug(&plug); -	if (unlikely(iocb->ki_filp->f_flags & O_DIRECT)) -		ret = ext4_file_dio_write(iocb, iov, nr_segs, pos); -	else -		ret = generic_file_aio_write(iocb, iov, nr_segs, pos); - +errout: +	if (aio_mutex) +		mutex_unlock(aio_mutex);  	return ret;  }  static const struct vm_operations_struct ext4_file_vm_ops = {  	.fault		= filemap_fault, +	.map_pages	= filemap_map_pages,  	.page_mkwrite   = ext4_page_mkwrite,  	.remap_pages	= generic_file_remap_pages,  }; @@ -243,6 +237,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)  			handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1);  			if (IS_ERR(handle))  				return PTR_ERR(handle); +			BUFFER_TRACE(sbi->s_sbh, "get_write_access");  			err = ext4_journal_get_write_access(handle, sbi->s_sbh);  			if (err) {  				ext4_journal_stop(handle); @@ -592,10 +587,10 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence)  const struct file_operations ext4_file_operations = {  	.llseek		= ext4_llseek, -	.read		= do_sync_read, -	.write		= do_sync_write, -	.aio_read	= generic_file_aio_read, -	.aio_write	= ext4_file_write, +	.read		= new_sync_read, +	.write		= new_sync_write, +	.read_iter	= generic_file_read_iter, +	.write_iter	= ext4_file_write_iter,  	.unlocked_ioctl = ext4_ioctl,  #ifdef CONFIG_COMPAT  	.compat_ioctl	= ext4_compat_ioctl, @@ -605,7 +600,7 @@ const struct file_operations ext4_file_operations = {  	.release	= ext4_release_file,  	.fsync		= ext4_sync_file,  	.splice_read	= generic_file_splice_read, -	.splice_write	= generic_file_splice_write, +	.splice_write	= iter_file_splice_write,  	.fallocate	= ext4_fallocate,  }; @@ -617,6 +612,7 @@ const struct inode_operations ext4_file_inode_operations = {  	.listxattr	= ext4_listxattr,  	.removexattr	= generic_removexattr,  	.get_acl	= ext4_get_acl, +	.set_acl	= ext4_set_acl,  	.fiemap		= ext4_fiemap,  };  | 
