Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse bugfixes from Miklos Szeredi:
 "Just a bunch of bugfixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: use list_for_each_entry() for list traversing
  fuse: readdir: check for slash in names
  fuse: hotfix truncate_pagecache() issue
  fuse: invalidate inode attributes on xattr modification
  fuse: postpone end_page_writeback() in fuse_writepage_locked()
This commit is contained in:
Linus Torvalds 2013-09-09 09:18:23 -07:00
commit 16d70e1529
5 changed files with 29 additions and 8 deletions

View File

@ -1765,11 +1765,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
/* Look up request on processing list by unique ID */ /* Look up request on processing list by unique ID */
static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
{ {
struct list_head *entry; struct fuse_req *req;
list_for_each(entry, &fc->processing) { list_for_each_entry(req, &fc->processing, list) {
struct fuse_req *req;
req = list_entry(entry, struct fuse_req, list);
if (req->in.h.unique == unique || req->intr_unique == unique) if (req->in.h.unique == unique || req->intr_unique == unique)
return req; return req;
} }

View File

@ -1177,6 +1177,8 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
return -EIO; return -EIO;
if (reclen > nbytes) if (reclen > nbytes)
break; break;
if (memchr(dirent->name, '/', dirent->namelen) != NULL)
return -EIO;
if (!dir_emit(ctx, dirent->name, dirent->namelen, if (!dir_emit(ctx, dirent->name, dirent->namelen,
dirent->ino, dirent->type)) dirent->ino, dirent->type))
@ -1315,6 +1317,8 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
return -EIO; return -EIO;
if (reclen > nbytes) if (reclen > nbytes)
break; break;
if (memchr(dirent->name, '/', dirent->namelen) != NULL)
return -EIO;
if (!over) { if (!over) {
/* We fill entries into dstbuf only as much as /* We fill entries into dstbuf only as much as
@ -1585,6 +1589,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
struct file *file) struct file *file)
{ {
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_req *req; struct fuse_req *req;
struct fuse_setattr_in inarg; struct fuse_setattr_in inarg;
struct fuse_attr_out outarg; struct fuse_attr_out outarg;
@ -1612,8 +1617,10 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
if (is_truncate) if (is_truncate) {
fuse_set_nowrite(inode); fuse_set_nowrite(inode);
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
}
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg)); memset(&outarg, 0, sizeof(outarg));
@ -1675,12 +1682,14 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
invalidate_inode_pages2(inode->i_mapping); invalidate_inode_pages2(inode->i_mapping);
} }
clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
return 0; return 0;
error: error:
if (is_truncate) if (is_truncate)
fuse_release_nowrite(inode); fuse_release_nowrite(inode);
clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
return err; return err;
} }
@ -1744,6 +1753,8 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
fc->no_setxattr = 1; fc->no_setxattr = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
} }
if (!err)
fuse_invalidate_attr(inode);
return err; return err;
} }
@ -1873,6 +1884,8 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
fc->no_removexattr = 1; fc->no_removexattr = 1;
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
} }
if (!err)
fuse_invalidate_attr(inode);
return err; return err;
} }

View File

@ -629,7 +629,8 @@ static void fuse_read_update_size(struct inode *inode, loff_t size,
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
spin_lock(&fc->lock); spin_lock(&fc->lock);
if (attr_ver == fi->attr_version && size < inode->i_size) { if (attr_ver == fi->attr_version && size < inode->i_size &&
!test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
fi->attr_version = ++fc->attr_version; fi->attr_version = ++fc->attr_version;
i_size_write(inode, size); i_size_write(inode, size);
} }
@ -1032,12 +1033,16 @@ static ssize_t fuse_perform_write(struct file *file,
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
int err = 0; int err = 0;
ssize_t res = 0; ssize_t res = 0;
if (is_bad_inode(inode)) if (is_bad_inode(inode))
return -EIO; return -EIO;
if (inode->i_size < pos + iov_iter_count(ii))
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
do { do {
struct fuse_req *req; struct fuse_req *req;
ssize_t count; ssize_t count;
@ -1073,6 +1078,7 @@ static ssize_t fuse_perform_write(struct file *file,
if (res > 0) if (res > 0)
fuse_write_update_size(inode, pos); fuse_write_update_size(inode, pos);
clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
fuse_invalidate_attr(inode); fuse_invalidate_attr(inode);
return res > 0 ? res : err; return res > 0 ? res : err;
@ -1529,7 +1535,6 @@ static int fuse_writepage_locked(struct page *page)
inc_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK); inc_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK);
inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP); inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
end_page_writeback(page);
spin_lock(&fc->lock); spin_lock(&fc->lock);
list_add(&req->writepages_entry, &fi->writepages); list_add(&req->writepages_entry, &fi->writepages);
@ -1537,6 +1542,8 @@ static int fuse_writepage_locked(struct page *page)
fuse_flush_writepages(inode); fuse_flush_writepages(inode);
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
end_page_writeback(page);
return 0; return 0;
err_free: err_free:

View File

@ -115,6 +115,8 @@ struct fuse_inode {
enum { enum {
/** Advise readdirplus */ /** Advise readdirplus */
FUSE_I_ADVISE_RDPLUS, FUSE_I_ADVISE_RDPLUS,
/** An operation changing file size is in progress */
FUSE_I_SIZE_UNSTABLE,
}; };
struct fuse_conn; struct fuse_conn;

View File

@ -201,7 +201,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
struct timespec old_mtime; struct timespec old_mtime;
spin_lock(&fc->lock); spin_lock(&fc->lock);
if (attr_version != 0 && fi->attr_version > attr_version) { if ((attr_version != 0 && fi->attr_version > attr_version) ||
test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
return; return;
} }