aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-04 18:34:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-04 18:34:27 -0400
commitd15fee814d8d30bbb4859ef8fef7a1f96327635b (patch)
tree1168811b0b28ec6fb9ccb65476019323e5ba9035
parent56c225fe399c27c1f1a098048903f8e74f4ec45f (diff)
parentf3846266f593595632a07242fcbc6c24bc2ade68 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse update from Miklos Szeredi: "This series adds cached writeback support to fuse, improving write throughput" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: fix "uninitialized variable" warning fuse: Turn writeback cache on fuse: Fix O_DIRECT operations vs cached writeback misorder fuse: fuse_flush() should wait on writeback fuse: Implement write_begin/write_end callbacks fuse: restructure fuse_readpage() fuse: Flush files on wb close fuse: Trust kernel i_mtime only fuse: Trust kernel i_size only fuse: Connection bit for enabling writeback fuse: Prepare to handle short reads fuse: Linking file to inode helper
-rw-r--r--fs/fuse/cuse.c5
-rw-r--r--fs/fuse/dir.c119
-rw-r--r--fs/fuse/file.c286
-rw-r--r--fs/fuse/fuse_i.h22
-rw-r--r--fs/fuse/inode.c29
-rw-r--r--include/uapi/linux/fuse.h7
6 files changed, 384 insertions, 84 deletions
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index b96a49b37d66..23e363f38302 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -95,7 +95,7 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
95 struct iovec iov = { .iov_base = buf, .iov_len = count }; 95 struct iovec iov = { .iov_base = buf, .iov_len = count };
96 struct fuse_io_priv io = { .async = 0, .file = file }; 96 struct fuse_io_priv io = { .async = 0, .file = file };
97 97
98 return fuse_direct_io(&io, &iov, 1, count, &pos, 0); 98 return fuse_direct_io(&io, &iov, 1, count, &pos, FUSE_DIO_CUSE);
99} 99}
100 100
101static ssize_t cuse_write(struct file *file, const char __user *buf, 101static ssize_t cuse_write(struct file *file, const char __user *buf,
@@ -109,7 +109,8 @@ static ssize_t cuse_write(struct file *file, const char __user *buf,
109 * No locking or generic_write_checks(), the server is 109 * No locking or generic_write_checks(), the server is
110 * responsible for locking and sanity checks. 110 * responsible for locking and sanity checks.
111 */ 111 */
112 return fuse_direct_io(&io, &iov, 1, count, &pos, 1); 112 return fuse_direct_io(&io, &iov, 1, count, &pos,
113 FUSE_DIO_WRITE | FUSE_DIO_CUSE);
113} 114}
114 115
115static int cuse_open(struct inode *inode, struct file *file) 116static int cuse_open(struct inode *inode, struct file *file)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 1d1292c581c3..5b4e035b364c 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -839,6 +839,14 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
839 struct kstat *stat) 839 struct kstat *stat)
840{ 840{
841 unsigned int blkbits; 841 unsigned int blkbits;
842 struct fuse_conn *fc = get_fuse_conn(inode);
843
844 /* see the comment in fuse_change_attributes() */
845 if (fc->writeback_cache && S_ISREG(inode->i_mode)) {
846 attr->size = i_size_read(inode);
847 attr->mtime = inode->i_mtime.tv_sec;
848 attr->mtimensec = inode->i_mtime.tv_nsec;
849 }
842 850
843 stat->dev = inode->i_sb->s_dev; 851 stat->dev = inode->i_sb->s_dev;
844 stat->ino = attr->ino; 852 stat->ino = attr->ino;
@@ -1477,12 +1485,16 @@ static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd,
1477 FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); 1485 FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR);
1478} 1486}
1479 1487
1480static bool update_mtime(unsigned ivalid) 1488static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
1481{ 1489{
1482 /* Always update if mtime is explicitly set */ 1490 /* Always update if mtime is explicitly set */
1483 if (ivalid & ATTR_MTIME_SET) 1491 if (ivalid & ATTR_MTIME_SET)
1484 return true; 1492 return true;
1485 1493
1494 /* Or if kernel i_mtime is the official one */
1495 if (trust_local_mtime)
1496 return true;
1497
1486 /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 1498 /* If it's an open(O_TRUNC) or an ftruncate(), don't update */
1487 if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 1499 if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
1488 return false; 1500 return false;
@@ -1491,7 +1503,8 @@ static bool update_mtime(unsigned ivalid)
1491 return true; 1503 return true;
1492} 1504}
1493 1505
1494static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 1506static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
1507 bool trust_local_mtime)
1495{ 1508{
1496 unsigned ivalid = iattr->ia_valid; 1509 unsigned ivalid = iattr->ia_valid;
1497 1510
@@ -1510,11 +1523,11 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
1510 if (!(ivalid & ATTR_ATIME_SET)) 1523 if (!(ivalid & ATTR_ATIME_SET))
1511 arg->valid |= FATTR_ATIME_NOW; 1524 arg->valid |= FATTR_ATIME_NOW;
1512 } 1525 }
1513 if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { 1526 if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_mtime)) {
1514 arg->valid |= FATTR_MTIME; 1527 arg->valid |= FATTR_MTIME;
1515 arg->mtime = iattr->ia_mtime.tv_sec; 1528 arg->mtime = iattr->ia_mtime.tv_sec;
1516 arg->mtimensec = iattr->ia_mtime.tv_nsec; 1529 arg->mtimensec = iattr->ia_mtime.tv_nsec;
1517 if (!(ivalid & ATTR_MTIME_SET)) 1530 if (!(ivalid & ATTR_MTIME_SET) && !trust_local_mtime)
1518 arg->valid |= FATTR_MTIME_NOW; 1531 arg->valid |= FATTR_MTIME_NOW;
1519 } 1532 }
1520} 1533}
@@ -1563,6 +1576,63 @@ void fuse_release_nowrite(struct inode *inode)
1563 spin_unlock(&fc->lock); 1576 spin_unlock(&fc->lock);
1564} 1577}
1565 1578
1579static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req,
1580 struct inode *inode,
1581 struct fuse_setattr_in *inarg_p,
1582 struct fuse_attr_out *outarg_p)
1583{
1584 req->in.h.opcode = FUSE_SETATTR;
1585 req->in.h.nodeid = get_node_id(inode);
1586 req->in.numargs = 1;
1587 req->in.args[0].size = sizeof(*inarg_p);
1588 req->in.args[0].value = inarg_p;
1589 req->out.numargs = 1;
1590 if (fc->minor < 9)
1591 req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
1592 else
1593 req->out.args[0].size = sizeof(*outarg_p);
1594 req->out.args[0].value = outarg_p;
1595}
1596
1597/*
1598 * Flush inode->i_mtime to the server
1599 */
1600int fuse_flush_mtime(struct file *file, bool nofail)
1601{
1602 struct inode *inode = file->f_mapping->host;
1603 struct fuse_inode *fi = get_fuse_inode(inode);
1604 struct fuse_conn *fc = get_fuse_conn(inode);
1605 struct fuse_req *req = NULL;
1606 struct fuse_setattr_in inarg;
1607 struct fuse_attr_out outarg;
1608 int err;
1609
1610 if (nofail) {
1611 req = fuse_get_req_nofail_nopages(fc, file);
1612 } else {
1613 req = fuse_get_req_nopages(fc);
1614 if (IS_ERR(req))
1615 return PTR_ERR(req);
1616 }
1617
1618 memset(&inarg, 0, sizeof(inarg));
1619 memset(&outarg, 0, sizeof(outarg));
1620
1621 inarg.valid |= FATTR_MTIME;
1622 inarg.mtime = inode->i_mtime.tv_sec;
1623 inarg.mtimensec = inode->i_mtime.tv_nsec;
1624
1625 fuse_setattr_fill(fc, req, inode, &inarg, &outarg);
1626 fuse_request_send(fc, req);
1627 err = req->out.h.error;
1628 fuse_put_request(fc, req);
1629
1630 if (!err)
1631 clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
1632
1633 return err;
1634}
1635
1566/* 1636/*
1567 * Set attributes, and at the same time refresh them. 1637 * Set attributes, and at the same time refresh them.
1568 * 1638 *
@@ -1580,8 +1650,10 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1580 struct fuse_setattr_in inarg; 1650 struct fuse_setattr_in inarg;
1581 struct fuse_attr_out outarg; 1651 struct fuse_attr_out outarg;
1582 bool is_truncate = false; 1652 bool is_truncate = false;
1653 bool is_wb = fc->writeback_cache;
1583 loff_t oldsize; 1654 loff_t oldsize;
1584 int err; 1655 int err;
1656 bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode);
1585 1657
1586 if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) 1658 if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
1587 attr->ia_valid |= ATTR_FORCE; 1659 attr->ia_valid |= ATTR_FORCE;
@@ -1610,7 +1682,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1610 1682
1611 memset(&inarg, 0, sizeof(inarg)); 1683 memset(&inarg, 0, sizeof(inarg));
1612 memset(&outarg, 0, sizeof(outarg)); 1684 memset(&outarg, 0, sizeof(outarg));
1613 iattr_to_fattr(attr, &inarg); 1685 iattr_to_fattr(attr, &inarg, trust_local_mtime);
1614 if (file) { 1686 if (file) {
1615 struct fuse_file *ff = file->private_data; 1687 struct fuse_file *ff = file->private_data;
1616 inarg.valid |= FATTR_FH; 1688 inarg.valid |= FATTR_FH;
@@ -1621,17 +1693,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1621 inarg.valid |= FATTR_LOCKOWNER; 1693 inarg.valid |= FATTR_LOCKOWNER;
1622 inarg.lock_owner = fuse_lock_owner_id(fc, current->files);