diff options
Diffstat (limited to 'fs/f2fs/file.c')
| -rw-r--r-- | fs/f2fs/file.c | 183 | 
1 files changed, 147 insertions, 36 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 61af721329fa..a0e6d2c65a9e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -33,6 +33,18 @@  #include "trace.h"  #include <trace/events/f2fs.h> +static int f2fs_filemap_fault(struct vm_fault *vmf) +{ +	struct inode *inode = file_inode(vmf->vma->vm_file); +	int err; + +	down_read(&F2FS_I(inode)->i_mmap_sem); +	err = filemap_fault(vmf); +	up_read(&F2FS_I(inode)->i_mmap_sem); + +	return err; +} +  static int f2fs_vm_page_mkwrite(struct vm_fault *vmf)  {  	struct page *page = vmf->page; @@ -59,13 +71,14 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf)  	f2fs_balance_fs(sbi, dn.node_changed);  	file_update_time(vmf->vma->vm_file); +	down_read(&F2FS_I(inode)->i_mmap_sem);  	lock_page(page);  	if (unlikely(page->mapping != inode->i_mapping ||  			page_offset(page) > i_size_read(inode) ||  			!PageUptodate(page))) {  		unlock_page(page);  		err = -EFAULT; -		goto out; +		goto out_sem;  	}  	/* @@ -94,6 +107,8 @@ mapped:  	if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode))  		f2fs_wait_on_encrypted_page_writeback(sbi, dn.data_blkaddr); +out_sem: +	up_read(&F2FS_I(inode)->i_mmap_sem);  out:  	sb_end_pagefault(inode->i_sb);  	f2fs_update_time(sbi, REQ_TIME); @@ -101,7 +116,7 @@ out:  }  static const struct vm_operations_struct f2fs_file_vm_ops = { -	.fault		= filemap_fault, +	.fault		= f2fs_filemap_fault,  	.map_pages	= filemap_map_pages,  	.page_mkwrite	= f2fs_vm_page_mkwrite,  }; @@ -415,14 +430,6 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)  	struct inode *inode = file_inode(file);  	int err; -	if (f2fs_encrypted_inode(inode)) { -		err = fscrypt_get_encryption_info(inode); -		if (err) -			return 0; -		if (!f2fs_encrypted_inode(inode)) -			return -ENOKEY; -	} -  	/* we don't need to use inline_data strictly */  	err = f2fs_convert_inline_inode(inode);  	if (err) @@ -435,11 +442,10 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)  static int f2fs_file_open(struct inode *inode, struct file *filp)  { -	int ret = generic_file_open(inode, filp);  	struct dentry *dir; -	if (!ret && f2fs_encrypted_inode(inode)) { -		ret = fscrypt_get_encryption_info(inode); +	if (f2fs_encrypted_inode(inode)) { +		int ret = fscrypt_get_encryption_info(inode);  		if (ret)  			return -EACCES;  		if (!fscrypt_has_encryption_key(inode)) @@ -452,7 +458,7 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)  		return -EPERM;  	}  	dput(dir); -	return ret; +	return dquot_file_open(inode, filp);  }  int truncate_data_blocks_range(struct dnode_of_data *dn, int count) @@ -527,8 +533,10 @@ static int truncate_partial_data_page(struct inode *inode, u64 from,  truncate_out:  	f2fs_wait_on_page_writeback(page, DATA, true);  	zero_user(page, offset, PAGE_SIZE - offset); -	if (!cache_only || !f2fs_encrypted_inode(inode) || -					!S_ISREG(inode->i_mode)) + +	/* An encrypted inode should have a key and truncate the last page. */ +	f2fs_bug_on(F2FS_I_SB(inode), cache_only && f2fs_encrypted_inode(inode)); +	if (!cache_only)  		set_page_dirty(page);  	f2fs_put_page(page, 1);  	return 0; @@ -633,11 +641,31 @@ int f2fs_truncate(struct inode *inode)  }  int f2fs_getattr(const struct path *path, struct kstat *stat, -		 u32 request_mask, unsigned int flags) +		 u32 request_mask, unsigned int query_flags)  {  	struct inode *inode = d_inode(path->dentry); +	struct f2fs_inode_info *fi = F2FS_I(inode); +	unsigned int flags; + +	flags = fi->i_flags & FS_FL_USER_VISIBLE; +	if (flags & FS_APPEND_FL) +		stat->attributes |= STATX_ATTR_APPEND; +	if (flags & FS_COMPR_FL) +		stat->attributes |= STATX_ATTR_COMPRESSED; +	if (f2fs_encrypted_inode(inode)) +		stat->attributes |= STATX_ATTR_ENCRYPTED; +	if (flags & FS_IMMUTABLE_FL) +		stat->attributes |= STATX_ATTR_IMMUTABLE; +	if (flags & FS_NODUMP_FL) +		stat->attributes |= STATX_ATTR_NODUMP; + +	stat->attributes_mask |= (STATX_ATTR_APPEND | +				  STATX_ATTR_COMPRESSED | +				  STATX_ATTR_ENCRYPTED | +				  STATX_ATTR_IMMUTABLE | +				  STATX_ATTR_NODUMP); +  	generic_fillattr(inode, stat); -	stat->blocks <<= 3;  	return 0;  } @@ -681,14 +709,34 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)  	if (err)  		return err; +	if (is_quota_modification(inode, attr)) { +		err = dquot_initialize(inode); +		if (err) +			return err; +	} +	if ((attr->ia_valid & ATTR_UID && +		!uid_eq(attr->ia_uid, inode->i_uid)) || +		(attr->ia_valid & ATTR_GID && +		!gid_eq(attr->ia_gid, inode->i_gid))) { +		err = dquot_transfer(inode, attr); +		if (err) +			return err; +	} +  	if (attr->ia_valid & ATTR_SIZE) { -		if (f2fs_encrypted_inode(inode) && -				fscrypt_get_encryption_info(inode)) -			return -EACCES; +		if (f2fs_encrypted_inode(inode)) { +			err = fscrypt_get_encryption_info(inode); +			if (err) +				return err; +			if (!fscrypt_has_encryption_key(inode)) +				return -ENOKEY; +		}  		if (attr->ia_size <= i_size_read(inode)) { +			down_write(&F2FS_I(inode)->i_mmap_sem);  			truncate_setsize(inode, attr->ia_size);  			err = f2fs_truncate(inode); +			up_write(&F2FS_I(inode)->i_mmap_sem);  			if (err)  				return err;  		} else { @@ -696,7 +744,9 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)  			 * do not trim all blocks after i_size if target size is  			 * larger than i_size.  			 */ +			down_write(&F2FS_I(inode)->i_mmap_sem);  			truncate_setsize(inode, attr->ia_size); +			up_write(&F2FS_I(inode)->i_mmap_sem);  			/* should convert inline inode here */  			if (!f2fs_may_inline_data(inode)) { @@ -839,12 +889,14 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)  			blk_start = (loff_t)pg_start << PAGE_SHIFT;  			blk_end = (loff_t)pg_end << PAGE_SHIFT; +			down_write(&F2FS_I(inode)->i_mmap_sem);  			truncate_inode_pages_range(mapping, blk_start,  					blk_end - 1);  			f2fs_lock_op(sbi);  			ret = truncate_hole(inode, pg_start, pg_end);  			f2fs_unlock_op(sbi); +			up_write(&F2FS_I(inode)->i_mmap_sem);  		}  	} @@ -957,9 +1009,9 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,  				if (do_replace[i]) {  					f2fs_i_blocks_write(src_inode, -								1, false); +							1, false, false);  					f2fs_i_blocks_write(dst_inode, -								1, true); +							1, true, false);  					f2fs_replace_block(sbi, &dn, dn.data_blkaddr,  					blkaddr[i], ni.version, true, false); @@ -1083,16 +1135,17 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)  	pg_start = offset >> PAGE_SHIFT;  	pg_end = (offset + len) >> PAGE_SHIFT; +	down_write(&F2FS_I(inode)->i_mmap_sem);  	/* write out all dirty pages from offset */  	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);  	if (ret) -		return ret; +		goto out;  	truncate_pagecache(inode, offset);  	ret = f2fs_do_collapse(inode, pg_start, pg_end);  	if (ret) -		return ret; +		goto out;  	/* write out all moved pages, if possible */  	filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX); @@ -1105,6 +1158,8 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)  	if (!ret)  		f2fs_i_size_write(inode, new_size); +out: +	up_write(&F2FS_I(inode)->i_mmap_sem);  	return ret;  } @@ -1169,9 +1224,10 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,  	if (ret)  		return ret; +	down_write(&F2FS_I(inode)->i_mmap_sem);  	ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);  	if (ret) -		return ret; +		goto out_sem;  	truncate_pagecache_range(inode, offset, offset + len - 1); @@ -1185,7 +1241,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,  		ret = fill_zero(inode, pg_start, off_start,  						off_end - off_start);  		if (ret) -			return ret; +			goto out_sem;  		new_size = max_t(loff_t, new_size, offset + len);  	} else { @@ -1193,7 +1249,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,  			ret = fill_zero(inode, pg_start++, off_start,  						PAGE_SIZE - off_start);  			if (ret) -				return ret; +				goto out_sem;  			new_size = max_t(loff_t, new_size,  					(loff_t)pg_start << PAGE_SHIFT); @@ -1242,6 +1298,8 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,  out:  	if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size)  		f2fs_i_size_write(inode, new_size); +out_sem: +	up_write(&F2FS_I(inode)->i_mmap_sem);  	return ret;  } @@ -1271,14 +1329,15 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)  	f2fs_balance_fs(sbi, true); +	down_write(&F2FS_I(inode)->i_mmap_sem);  	ret = truncate_blocks(inode, i_size_read(inode), true);  	if (ret) -		return ret; +		goto out;  	/* write out all dirty pages from offset */  	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);  	if (ret) -		return ret; +		goto out;  	truncate_pagecache(inode, offset); @@ -1307,6 +1366,8 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)  	if (!ret)  		f2fs_i_size_write(inode, new_size); +out: +	up_write(&F2FS_I(inode)->i_mmap_sem);  	return ret;  } @@ -1475,6 +1536,13 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)  	inode_lock(inode); +	/* Is it quota file? Do not allow user to mess with it */ +	if (IS_NOQUOTA(inode)) { +		inode_unlock(inode); +		ret = -EPERM; +		goto unlock_out; +	} +  	flags = f2fs_mask_flags(inode->i_mode, flags);  	oldflags = fi->i_flags; @@ -1493,7 +1561,8 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)  	inode->i_ctime = current_time(inode);  	f2fs_set_inode_flags(inode); - +	f2fs_mark_inode_dirty_sync(inode, false); +unlock_out:  	inode_unlock(inode);  out:  	mnt_drop_write_file(filp); @@ -1862,6 +1931,50 @@ out:  	return ret;  } +static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) +{ +	struct inode *inode = file_inode(filp); +	struct f2fs_sb_info *sbi = F2FS_I_SB(inode); +	struct f2fs_gc_range range; +	u64 end; +	int ret; + +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; + +	if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg, +							sizeof(range))) +		return -EFAULT; + +	if (f2fs_readonly(sbi->sb)) +		return -EROFS; + +	ret = mnt_want_write_file(filp); +	if (ret) +		return ret; + +	end = range.start + range.len; +	if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) +		return -EINVAL; +do_more: +	if (!range.sync) { +		if (!mutex_trylock(&sbi->gc_mutex)) { +			ret = -EBUSY; +			goto out; +		} +	} else { +		mutex_lock(&sbi->gc_mutex); +	} + +	ret = f2fs_gc(sbi, range.sync, true, GET_SEGNO(sbi, range.start)); +	range.start += sbi->blocks_per_seg; +	if (range.start <= end) +		goto do_more; +out: +	mnt_drop_write_file(filp); +	return ret; +} +  static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)  {  	struct inode *inode = file_inode(filp); @@ -2306,6 +2419,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		return f2fs_ioc_get_encryption_pwsalt(filp, arg);  	case F2FS_IOC_GARBAGE_COLLECT:  		return f2fs_ioc_gc(filp, arg); +	case F2FS_IOC_GARBAGE_COLLECT_RANGE: +		return f2fs_ioc_gc_range(filp, arg);  	case F2FS_IOC_WRITE_CHECKPOINT:  		return f2fs_ioc_write_checkpoint(filp, arg);  	case F2FS_IOC_DEFRAGMENT: @@ -2326,11 +2441,6 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)  	struct blk_plug plug;  	ssize_t ret; -	if (f2fs_encrypted_inode(inode) && -				!fscrypt_has_encryption_key(inode) && -				fscrypt_get_encryption_info(inode)) -		return -EACCES; -  	inode_lock(inode);  	ret = generic_write_checks(iocb, from);  	if (ret > 0) { @@ -2379,6 +2489,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  	case F2FS_IOC_GET_ENCRYPTION_PWSALT:  	case F2FS_IOC_GET_ENCRYPTION_POLICY:  	case F2FS_IOC_GARBAGE_COLLECT: +	case F2FS_IOC_GARBAGE_COLLECT_RANGE:  	case F2FS_IOC_WRITE_CHECKPOINT:  	case F2FS_IOC_DEFRAGMENT:  	case F2FS_IOC_MOVE_RANGE:  | 
