diff options
Diffstat (limited to 'fs/overlayfs/inode.c')
| -rw-r--r-- | fs/overlayfs/inode.c | 29 | 
1 files changed, 26 insertions, 3 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 1dbeab6cf96e..c831c2e5f803 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -59,16 +59,37 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)  	if (err)  		goto out; +	if (attr->ia_valid & ATTR_SIZE) { +		struct inode *realinode = d_inode(ovl_dentry_real(dentry)); + +		err = -ETXTBSY; +		if (atomic_read(&realinode->i_writecount) < 0) +			goto out_drop_write; +	} +  	err = ovl_copy_up(dentry);  	if (!err) { +		struct inode *winode = NULL; +  		upperdentry = ovl_dentry_upper(dentry); +		if (attr->ia_valid & ATTR_SIZE) { +			winode = d_inode(upperdentry); +			err = get_write_access(winode); +			if (err) +				goto out_drop_write; +		} +  		inode_lock(upperdentry->d_inode);  		err = notify_change(upperdentry, attr, NULL);  		if (!err)  			ovl_copyattr(upperdentry->d_inode, dentry->d_inode);  		inode_unlock(upperdentry->d_inode); + +		if (winode) +			put_write_access(winode);  	} +out_drop_write:  	ovl_drop_write(dentry);  out:  	return err; @@ -121,16 +142,18 @@ int ovl_permission(struct inode *inode, int mask)  		err = vfs_getattr(&realpath, &stat);  		if (err) -			return err; +			goto out_dput; +		err = -ESTALE;  		if ((stat.mode ^ inode->i_mode) & S_IFMT) -			return -ESTALE; +			goto out_dput;  		inode->i_mode = stat.mode;  		inode->i_uid = stat.uid;  		inode->i_gid = stat.gid; -		return generic_permission(inode, mask); +		err = generic_permission(inode, mask); +		goto out_dput;  	}  	/* Careful in RCU walk mode */  | 
