Skip to content

Commit

Permalink
fuse: truncate file if async dio failed
Browse files Browse the repository at this point in the history
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: Maxim Patlasov <mpatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
  • Loading branch information
Maxim Patlasov authored and Miklos Szeredi committed Apr 18, 2013
1 parent 439ee5f commit efb9fa9
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 10 deletions.
17 changes: 9 additions & 8 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct file *file)
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;
Expand All @@ -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;

Expand Down Expand Up @@ -1671,10 +1667,15 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,

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,
Expand Down
22 changes: 20 additions & 2 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -2419,8 +2433,12 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
kfree(io);
}

if (rw == WRITE && ret > 0)
fuse_write_update_size(inode, pos);
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;
}
Expand Down
3 changes: 3 additions & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit efb9fa9

Please sign in to comment.