Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efb9fa9e authored by Maxim Patlasov's avatar Maxim Patlasov Committed by Miklos Szeredi
Browse files

fuse: truncate file if async dio failed



The patch improves error handling in fuse_direct_IO(): if we successfully
submitted several fuse requests on behalf of synchronous direct write
extending file and some of them failed, let's try to do our best to clean-up.

Changed in v2: reuse fuse_do_setattr(). Thanks to Brian for suggestion.

Signed-off-by: default avatarMaxim Patlasov <mpatlasov@parallels.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 439ee5f0
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -1562,10 +1562,9 @@ void fuse_release_nowrite(struct inode *inode)
 * vmtruncate() doesn't allow for this case, so do the rlimit checking
 * and the actual truncation by hand.
 */
static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
int fuse_do_setattr(struct inode *inode, struct iattr *attr,
		    struct file *file)
{
	struct inode *inode = entry->d_inode;
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_req *req;
	struct fuse_setattr_in inarg;
@@ -1574,9 +1573,6 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
	loff_t oldsize;
	int err;

	if (!fuse_allow_current_process(fc))
		return -EACCES;

	if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
		attr->ia_valid |= ATTR_FORCE;

@@ -1671,10 +1667,15 @@ error:

static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{
	struct inode *inode = entry->d_inode;

	if (!fuse_allow_current_process(get_fuse_conn(inode)))
		return -EACCES;

	if (attr->ia_valid & ATTR_FILE)
		return fuse_do_setattr(entry, attr, attr->ia_file);
		return fuse_do_setattr(inode, attr, attr->ia_file);
	else
		return fuse_do_setattr(entry, attr, NULL);
		return fuse_do_setattr(inode, attr, NULL);
}

static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
+20 −2
Original line number Diff line number Diff line
@@ -2352,6 +2352,20 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc,
	return 0;
}

static void fuse_do_truncate(struct file *file)
{
	struct inode *inode = file->f_mapping->host;
	struct iattr attr;

	attr.ia_valid = ATTR_SIZE;
	attr.ia_size = i_size_read(inode);

	attr.ia_file = file;
	attr.ia_valid |= ATTR_FILE;

	fuse_do_setattr(inode, &attr, file);
}

static ssize_t
fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
			loff_t offset, unsigned long nr_segs)
@@ -2419,8 +2433,12 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
		kfree(io);
	}

	if (rw == WRITE && ret > 0)
	if (rw == WRITE) {
		if (ret > 0)
			fuse_write_update_size(inode, pos);
		else if (ret < 0 && offset + count > i_size)
			fuse_do_truncate(file);
	}

	return ret;
}
+3 −0
Original line number Diff line number Diff line
@@ -863,4 +863,7 @@ int fuse_dev_release(struct inode *inode, struct file *file);

void fuse_write_update_size(struct inode *inode, loff_t pos);

int fuse_do_setattr(struct inode *inode, struct iattr *attr,
		    struct file *file);

#endif /* _FS_FUSE_I_H */