diff options
Diffstat (limited to 'fs/open.c')
| -rw-r--r-- | fs/open.c | 64 | 
1 files changed, 48 insertions, 16 deletions
| diff --git a/fs/open.c b/fs/open.c index ffcfef67ac86..932e5a6de63b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -81,14 +81,18 @@ long vfs_truncate(const struct path *path, loff_t length)  	if (!S_ISREG(inode->i_mode))  		return -EINVAL; -	error = mnt_want_write(path->mnt); -	if (error) -		goto out; -  	idmap = mnt_idmap(path->mnt);  	error = inode_permission(idmap, inode, MAY_WRITE);  	if (error) -		goto mnt_drop_write_and_out; +		return error; + +	error = fsnotify_truncate_perm(path, length); +	if (error) +		return error; + +	error = mnt_want_write(path->mnt); +	if (error) +		return error;  	error = -EPERM;  	if (IS_APPEND(inode)) @@ -114,7 +118,7 @@ put_write_and_out:  	put_write_access(inode);  mnt_drop_write_and_out:  	mnt_drop_write(path->mnt); -out: +  	return error;  }  EXPORT_SYMBOL_GPL(vfs_truncate); @@ -175,11 +179,18 @@ long do_ftruncate(struct file *file, loff_t length, int small)  	/* Check IS_APPEND on real upper inode */  	if (IS_APPEND(file_inode(file)))  		return -EPERM; -	sb_start_write(inode->i_sb); +  	error = security_file_truncate(file); -	if (!error) -		error = do_truncate(file_mnt_idmap(file), dentry, length, -				    ATTR_MTIME | ATTR_CTIME, file); +	if (error) +		return error; + +	error = fsnotify_truncate_perm(&file->f_path, length); +	if (error) +		return error; + +	sb_start_write(inode->i_sb); +	error = do_truncate(file_mnt_idmap(file), dentry, length, +			    ATTR_MTIME | ATTR_CTIME, file);  	sb_end_write(inode->i_sb);  	return error; @@ -894,7 +905,7 @@ static int do_dentry_open(struct file *f,  	f->f_sb_err = file_sample_sb_err(f);  	if (unlikely(f->f_flags & O_PATH)) { -		f->f_mode = FMODE_PATH | FMODE_OPENED; +		f->f_mode = FMODE_PATH | FMODE_OPENED | FMODE_NONOTIFY;  		f->f_op = &empty_fops;  		return 0;  	} @@ -922,6 +933,12 @@ static int do_dentry_open(struct file *f,  	if (error)  		goto cleanup_all; +	/* +	 * Set FMODE_NONOTIFY_* bits according to existing permission watches. +	 * If FMODE_NONOTIFY was already set for an fanotify fd, this doesn't +	 * change anything. +	 */ +	file_set_fsnotify_mode(f);  	error = fsnotify_open_perm(f);  	if (error)  		goto cleanup_all; @@ -1098,6 +1115,23 @@ struct file *dentry_open(const struct path *path, int flags,  }  EXPORT_SYMBOL(dentry_open); +struct file *dentry_open_nonotify(const struct path *path, int flags, +				  const struct cred *cred) +{ +	struct file *f = alloc_empty_file(flags, cred); +	if (!IS_ERR(f)) { +		int error; + +		f->f_mode |= FMODE_NONOTIFY; +		error = vfs_open(path, f); +		if (error) { +			fput(f); +			f = ERR_PTR(error); +		} +	} +	return f; +} +  /**   * dentry_create - Create and open a file   * @path: path to create @@ -1195,7 +1229,7 @@ inline struct open_how build_open_how(int flags, umode_t mode)  inline int build_open_flags(const struct open_how *how, struct open_flags *op)  {  	u64 flags = how->flags; -	u64 strip = __FMODE_NONOTIFY | O_CLOEXEC; +	u64 strip = O_CLOEXEC;  	int lookup_flags = 0;  	int acc_mode = ACC_MODE(flags); @@ -1203,9 +1237,7 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op)  			 "struct open_flags doesn't yet handle flags > 32 bits");  	/* -	 * Strip flags that either shouldn't be set by userspace like -	 * FMODE_NONOTIFY or that aren't relevant in determining struct -	 * open_flags like O_CLOEXEC. +	 * Strip flags that aren't relevant in determining struct open_flags.  	 */  	flags &= ~strip; @@ -1497,7 +1529,7 @@ static int filp_flush(struct file *filp, fl_owner_t id)  {  	int retval = 0; -	if (CHECK_DATA_CORRUPTION(file_count(filp) == 0, +	if (CHECK_DATA_CORRUPTION(file_count(filp) == 0, filp,  			"VFS: Close: file count is 0 (f_op=%ps)",  			filp->f_op)) {  		return 0; | 
