diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-04 18:34:27 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-04 18:34:27 -0400 |
| commit | d15fee814d8d30bbb4859ef8fef7a1f96327635b (patch) | |
| tree | 1168811b0b28ec6fb9ccb65476019323e5ba9035 | |
| parent | 56c225fe399c27c1f1a098048903f8e74f4ec45f (diff) | |
| parent | f3846266f593595632a07242fcbc6c24bc2ade68 (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.c | 5 | ||||
| -rw-r--r-- | fs/fuse/dir.c | 119 | ||||
| -rw-r--r-- | fs/fuse/file.c | 286 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 22 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 29 | ||||
| -rw-r--r-- | include/uapi/linux/fuse.h | 7 |
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 | ||
| 101 | static ssize_t cuse_write(struct file *file, const char __user *buf, | 101 | static 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 | ||
| 115 | static int cuse_open(struct inode *inode, struct file *file) | 116 | static 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 | ||
| 1480 | static bool update_mtime(unsigned ivalid) | 1488 | static 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 | ||
| 1494 | static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) | 1506 | static 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 | ||
| 1579 | static 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 | */ | ||
| 1600 | int 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); | 1694 | inarg.lock_owner = fuse_lock_owner_id(fc, current->files); |
| 1623 | } | 1695 | } |
| 1624 | req->in.h.opcode = FUSE_SETATTR; | 1696 | fuse_setattr_fill(fc, req, inode, &inarg, &outarg); |
| 1625 | req->in.h.nodeid = get_node_id(inode); | ||
| 1626 | req->in.numargs = 1; | ||
| 1627 | req->in.args[0].size = sizeof(inarg); | ||
| 1628 | req->in.args[0].value = &inarg; | ||
| 1629 | req->out.numargs = 1; | ||
| 1630 | if (fc->minor < 9) | ||
| 1631 | req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE; | ||
| 1632 | else | ||
| 1633 | req->out.args[0].size = sizeof(outarg); | ||
| 1634 | req->out.args[0].value = &outarg; | ||
| 1635 | fuse_request_send(fc, req); | 1697 | fuse_request_send(fc, req); |
| 1636 | err = req->out.h.error; | 1698 | err = req->out.h.error; |
| 1637 | fuse_put_request(fc, req); | 1699 | fuse_put_request(fc, req); |
| @@ -1648,10 +1710,18 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
| 1648 | } | 1710 | } |
| 1649 | 1711 | ||
| 1650 | spin_lock(&fc->lock); | 1712 | spin_lock(&fc->lock); |
| 1713 | /* the kernel maintains i_mtime locally */ | ||
| 1714 | if (trust_local_mtime && (attr->ia_valid & ATTR_MTIME)) { | ||
| 1715 | inode->i_mtime = attr->ia_mtime; | ||
| 1716 | clear_bit(FUSE_I_MTIME_DIRTY, &fi->state); | ||
| 1717 | } | ||
| 1718 | |||
| 1651 | fuse_change_attributes_common(inode, &outarg.attr, | 1719 | fuse_change_attributes_common(inode, &outarg.attr, |
| 1652 | attr_timeout(&outarg)); | 1720 | attr_timeout(&outarg)); |
| 1653 | oldsize = inode->i_size; | 1721 | oldsize = inode->i_size; |
| 1654 | i_size_write(inode, outarg.attr.size); | 1722 | /* see the comment in fuse_change_attributes() */ |
| 1723 | if (!is_wb || is_truncate || !S_ISREG(inode->i_mode)) | ||
| 1724 | i_size_write(inode, outarg.attr.size); | ||
| 1655 | 1725 | ||
| 1656 | if (is_truncate) { | 1726 | if (is_truncate) { |
| 1657 | /* NOTE: this may release/reacquire fc->lock */ | 1727 | /* NOTE: this may release/reacquire fc->lock */ |
| @@ -1663,7 +1733,8 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
| 1663 | * Only call invalidate_inode_pages2() after removing | 1733 | * Only call invalidate_inode_pages2() after removing |
| 1664 | * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. | 1734 | * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. |
| 1665 | */ | 1735 | */ |
| 1666 | if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { | 1736 | if ((is_truncate || !is_wb) && |
| 1737 | S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { | ||
| 1667 | truncate_pagecache(inode, outarg.attr.size); | 1738 | truncate_pagecache(inode, outarg.attr.size); |
| 1668 | invalidate_inode_pages2(inode->i_mapping); | 1739 | invalidate_inode_pages2(inode->i_mapping); |
| 1669 | } | 1740 | } |
| @@ -1875,6 +1946,17 @@ static int fuse_removexattr(struct dentry *entry, const char *name) | |||
| 1875 | return err; | 1946 | return err; |
| 1876 | } | 1947 | } |
| 1877 | 1948 | ||
| 1949 | static int fuse_update_time(struct inode *inode, struct timespec *now, | ||
| 1950 | int flags) | ||
| 1951 | { | ||
| 1952 | if (flags & S_MTIME) { | ||
| 1953 | inode->i_mtime = *now; | ||
| 1954 | set_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state); | ||
| 1955 | BUG_ON(!S_ISREG(inode->i_mode)); | ||
| 1956 | } | ||
| 1957 | return 0; | ||
| 1958 | } | ||
| 1959 | |||
| 1878 | static const struct inode_operations fuse_dir_inode_operations = { | 1960 | static const struct inode_operations fuse_dir_inode_operations = { |
| 1879 | .lookup = fuse_lookup, | 1961 | .lookup = fuse_lookup, |
| 1880 | .mkdir = fuse_mkdir, | 1962 | .mkdir = fuse_mkdir, |
| @@ -1914,6 +1996,7 @@ static const struct inode_operations fuse_common_inode_operations = { | |||
| 1914 | .getxattr = fuse_getxattr, | 1996 | .getxattr = fuse_getxattr, |
| 1915 | .listxattr = fuse_listxattr, | 1997 | .listxattr = fuse_listxattr, |
| 1916 | .removexattr = fuse_removexattr, | 1998 | .removexattr = fuse_removexattr, |
| 1999 | .update_time = fuse_update_time, | ||
| 1917 | }; | 2000 | }; |
| 1918 | 2001 | ||
| 1919 | static const struct inode_operations fuse_symlink_inode_operations = { | 2002 | static const struct inode_operations fuse_symlink_inode_operations = { |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 77bcc303c3ae..65df7d8be4f5 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -188,6 +188,22 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | |||
| 188 | } | 188 | } |
| 189 | EXPORT_SYMBOL_GPL(fuse_do_open); | 189 | EXPORT_SYMBOL_GPL(fuse_do_open); |
| 190 | 190 | ||
| 191 | static void fuse_link_write_file(struct file *file) | ||
| 192 | { | ||
| 193 | struct inode *inode = file_inode(file); | ||
| 194 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
| 195 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
| 196 | struct fuse_file *ff = file->private_data; | ||
| 197 | /* | ||
| 198 | * file may be written through mmap, so chain it onto the | ||
| 199 | * inodes's write_file list | ||
| 200 | */ | ||
| 201 | spin_lock(&fc->lock); | ||
| 202 | if (list_empty(&ff->write_entry)) | ||
| 203 | list_add(&ff->write_entry, &fi->write_files); | ||
| 204 | spin_unlock(&fc->lock); | ||
| 205 | } | ||
| 206 | |||
| 191 | void fuse_finish_open(struct inode *inode, struct file *file) | 207 | void fuse_finish_open(struct inode *inode, struct file *file) |
| 192 | { | 208 | { |
| 193 | struct fuse_file *ff = file->private_data; | 209 | struct fuse_file *ff = file->private_data; |
| @@ -208,6 +224,8 @@ void fuse_finish_open(struct inode *inode, struct file *file) | |||
| 208 | spin_unlock(&fc->lock); | 224 | spin_unlock(&fc->lock); |
| 209 | fuse_invalidate_attr(inode); | 225 | fuse_invalidate_attr(inode); |
| 210 | } | 226 | } |
| 227 | if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache) | ||
| 228 | fuse_link_write_file(file); | ||
| 211 | } | 229 | } |
| 212 | 230 | ||
| 213 | int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | 231 | int fuse_open_common(struct inode *inode, struct file *file, bool isdir) |
| @@ -292,6 +310,15 @@ static int fuse_open(struct inode *inode, struct file *file) | |||
| 292 | 310 | ||
| 293 | static int fuse_release(struct inode *inode, struct file *file) | 311 | static int fuse_release(struct inode *inode, struct file *file) |
| 294 | { | 312 | { |
| 313 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
| 314 | |||
| 315 | /* see fuse_vma_close() for !writeback_cache case */ | ||
| 316 | if (fc->writeback_cache) | ||
| 317 | filemap_write_and_wait(file->f_mapping); | ||
| 318 | |||
| 319 | if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) | ||
| 320 | fuse_flush_mtime(file, true); | ||
| 321 | |||
| 295 | fuse_release_common(file, FUSE_RELEASE); | 322 | fuse_release_common(file, FUSE_RELEASE); |
| 296 | 323 | ||
| 297 | /* return value is ignored by VFS */ | 324 | /* return value is ignored by VFS */ |
| @@ -333,12 +360,13 @@ u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) | |||
| 333 | } | 360 | } |
| 334 | 361 | ||
| 335 | /* | 362 | /* |
| 336 | * Check if page is under writeback | 363 | * Check if any page in a range is under writeback |
| 337 | * | 364 | * |
| 338 | * This is currently done by walking the list of writepage requests | 365 | * This is currently done by walking the list of writepage requests |
| 339 | * for the inode, which can be pretty inefficient. | 366 | * for the inode, which can be pretty inefficient. |
| 340 | */ | 367 | */ |
| 341 | static bool fuse_page_is_writeback(struct inode *inode, pgoff_t index) | 368 | static bool fuse_range_is_writeback(struct inode *inode, pgoff_t idx_from, |
| 369 | pgoff_t idx_to) | ||
| 342 | { | 370 | { |
| 343 | struct fuse_conn *fc = get_fuse_conn(inode); | 371 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 344 | struct fuse_inode *fi = get_fuse_inode(inode); | 372 | struct fuse_inode *fi = get_fuse_inode(inode); |
| @@ -351,8 +379,8 @@ static bool fuse_page_is_writeback(struct inode *inode, pgoff_t index) | |||
| 351 | 379 | ||
| 352 | BUG_ON(req->inode != inode); | 380 | BUG_ON(req->inode != inode); |
| 353 | curr_index = req->misc.write.in.offset >> PAGE_CACHE_SHIFT; | 381 | curr_index = req->misc.write.in.offset >> PAGE_CACHE_SHIFT; |
| 354 | if (curr_index <= index && | 382 | if (idx_from < curr_index + req->num_pages && |
| 355 | index < curr_index + req->num_pages) { | 383 | curr_index <= idx_to) { |
| 356 | found = true; | 384 | found = true; |
| 357 | break; | 385 | break; |
| 358 | } | 386 | } |
| @@ -362,6 +390,11 @@ static bool fuse_page_is_writeback(struct inode *inode, pgoff_t index) | |||
| 362 | return found; | 390 | return found; |
| 363 | } | 391 | } |
| 364 | 392 | ||
| 393 | static inline bool fuse_page_is_writeback(struct inode *inode, pgoff_t index) | ||
| 394 | { | ||
| 395 | return fuse_range_is_writeback(inode, index, index); | ||
| 396 | } | ||
| 397 | |||
| 365 | /* | 398 | /* |
| 366 | * Wait for page writeback to be completed. | 399 | * Wait for page writeback to be completed. |
| 367 | * | 400 | * |
| @@ -376,6 +409,21 @@ static int fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index) | |||
| 376 | return 0; | 409 | return 0; |
| 377 | } | 410 | } |
| 378 | 411 | ||
| 412 | /* | ||
| 413 | * Wait for all pending writepages on the inode to finish. | ||
| 414 | * | ||
| 415 | * This is currently done by blocking further writes with FUSE_NOWRITE | ||
| 416 | * and waiting for all sent writes to complete. | ||
| 417 | * | ||
| 418 | * This must be called under i_mutex, otherwise the FUSE_NOWRITE usage | ||
| 419 | * could conflict with truncation. | ||
| 420 | */ | ||
| 421 | static void fuse_sync_writes(struct inode *inode) | ||
| 422 | { | ||
| 423 | fuse_set_nowrite(inode); | ||
| 424 | fuse_release_nowrite(inode); | ||
| 425 | } | ||
| 426 | |||
| 379 | static int fuse_flush(struct file *file, fl_owner_t id) | 427 | static int fuse_flush(struct file *file, fl_owner_t id) |
| 380 | { | 428 | { |
| 381 | struct inode *inode = file_inode(file); | 429 | struct inode *inode = file_inode(file); |
| @@ -391,6 +439,14 @@ static int fuse_flush(struct file *file, fl_owner_t id) | |||
| 391 | if (fc->no_flush) | 439 | if (fc->no_flush) |
| 392 | return 0; | 440 | return 0; |
| 393 | 441 | ||
| 442 | err = filemap_write_and_wait(file->f_mapping); | ||
| 443 | if (err) | ||
| 444 | return err; | ||
| 445 | |||
| 446 | mutex_lock(&inode->i_mutex); | ||
| 447 | fuse_sync_writes(inode); | ||
| 448 | mutex_unlock(&inode->i_mutex); | ||
| 449 | |||
| 394 | req = fuse_get_req_nofail_nopages(fc, file); | 450 | req = fuse_get_req_nofail_nopages(fc, file); |
| 395 | memset(&inarg, 0, sizeof(inarg)); | 451 | memset(&inarg, 0, sizeof(inarg)); |
| 396 | inarg.fh = ff->fh; | 452 | inarg.fh = ff->fh; |
| @@ -411,21 +467,6 @@ static int fuse_flush(struct file *file, fl_owner_t id) | |||
| 411 | return err; | 467 | return err; |
| 412 | } | 468 | } |
| 413 | 469 | ||
| 414 | /* | ||
| 415 | * Wait for all pending writepages on the inode to finish. | ||
| 416 | * | ||
| 417 | * This is currently done by blocking further writes with FUSE_NOWRITE | ||
| 418 | * and waiting for all sent writes to complete. | ||
| 419 | * | ||
| 420 | * This must be called under i_mutex, otherwise the FUSE_NOWRITE usage | ||
| 421 | * could conflict with truncation. | ||
| 422 | */ | ||
| 423 | static void fuse_sync_writes(struct inode *inode) | ||
| 424 | { | ||
| 425 | fuse_set_nowrite(inode); | ||
| 426 | fuse_release_nowrite(inode); | ||
| 427 | } | ||
| 428 | |||
| 429 | int fuse_fsync_common(struct file *file, loff_t start, loff_t end, | 470 | int fuse_fsync_common(struct file *file, loff_t start, loff_t end, |
| 430 | int datasync, int isdir) | 471 | int datasync, int isdir) |
| 431 | { | 472 | { |
| @@ -459,6 +500,12 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, | |||
| 459 | 500 | ||
| 460 | fuse_sync_writes(inode); | 501 | fuse_sync_writes(inode); |
| 461 | 502 | ||
| 503 | if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) { | ||
| 504 | int err = fuse_flush_mtime(file, false); | ||
| 505 | if (err) | ||
| 506 | goto out; | ||
| 507 | } | ||
| 508 | |||
| 462 | req = fuse_get_req_nopages(fc); | 509 | req = fuse_get_req_nopages(fc); |
| 463 | if (IS_ERR(req)) { | 510 | if (IS_ERR(req)) { |
| 464 | err = PTR_ERR(req); | 511 | err = PTR_ERR(req); |
| @@ -655,7 +702,33 @@ static void fuse_read_update_size(struct inode *inode, loff_t size, | |||
| 655 | spin_unlock(&fc->lock); | 702 | spin_unlock(&fc->lock); |
| 656 | } | 703 | } |
| 657 | 704 | ||
| 658 | static int fuse_readpage(struct file *file, struct page *page) | 705 | static void fuse_short_read(struct fuse_req *req, struct inode *inode, |
| 706 | u64 attr_ver) | ||
| 707 | { | ||
| 708 | size_t num_read = req->out.args[0].size; | ||
| 709 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
| 710 | |||
| 711 | if (fc->writeback_cache) { | ||
| 712 | /* | ||
| 713 | * A hole in a file. Some data after the hole are in page cache, | ||
| 714 | * but have not reached the client fs yet. So, the hole is not | ||
| 715 | * present there. | ||
| 716 | */ | ||
| 717 | int i; | ||
| 718 | int start_idx = num_read >> PAGE_CACHE_SHIFT; | ||
| 719 | size_t off = num_read & (PAGE_CACHE_SIZE - 1); | ||
| 720 | |||
| 721 | for (i = start_idx; i < req->num_pages; i++) { | ||
| 722 | zero_user_segment(req->pages[i], off, PAGE_CACHE_SIZE); | ||
| 723 | off = 0; | ||
| 724 | } | ||
| 725 | } else { | ||
| 726 | loff_t pos = page_offset(req->pages[0]) + num_read; | ||
| 727 | fuse_read_update_size(inode, pos, attr_ver); | ||
| 728 | } | ||
| 729 | } | ||
| 730 | |||
| 731 | static int fuse_do_readpage(struct file *file, struct page *page) | ||
| 659 | { | 732 | { |
| 660 | struct fuse_io_priv io = { .async = 0, .file = file }; | 733 | struct fuse_io_priv io = { .async = 0, .file = file }; |
| 661 | struct inode *inode = page->mapping->host; | 734 | struct inode *inode = page->mapping->host; |
| @@ -667,10 +740,6 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
| 667 | u64 attr_ver; | 740 | u64 attr_ver; |
| 668 | int err; | 741 | int err; |
| 669 | 742 | ||
| 670 | err = -EIO; | ||
| 671 | if (is_bad_inode(inode)) | ||
| 672 | goto out; | ||
| 673 | |||
| 674 | /* | 743 | /* |
| 675 | * Page writeback can extend beyond the lifetime of the | 744 | * Page writeback can extend beyond the lifetime of the |
| 676 | * page-cache page, so make sure we read a properly synced | 745 | * page-cache page, so make sure we read a properly synced |
| @@ -679,9 +748,8 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
| 679 | fuse_wait_on_page_writeback(inode, page->index); | 748 | fuse_wait_on_page_writeback(inode, page->index); |
| 680 | 749 | ||
| 681 | req = fuse_get_req(fc, 1); | 750 | req = fuse_get_req(fc, 1); |
| 682 | err = PTR_ERR(req); | ||
| 683 | if (IS_ERR(req)) | 751 | if (IS_ERR(req)) |
| 684 | goto out; | 752 | return PTR_ERR(req); |
| 685 | 753 | ||
| 686 | attr_ver = fuse_get_attr_version(fc); | 754 | attr_ver = fuse_get_attr_version(fc); |
| 687 | 755 | ||
| @@ -692,18 +760,32 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
| 692 | req->page_descs[0].length = count; | 760 | req->page_descs[0].length = count; |
| 693 | num_read = fuse_send_read(req, &io, pos, count, NULL); | 761 | num_read = fuse_send_read(req, &io, pos, count, NULL); |
| 694 | err = req->out.h.error; | 762 | err = req->out.h.error; |
| 695 | fuse_put_request(fc, req); | ||
| 696 | 763 | ||
| 697 | if (!err) { | 764 | if (!err) { |
| 698 | /* | 765 | /* |
| 699 | * Short read means EOF. If file size is larger, truncate it | 766 | * Short read means EOF. If file size is larger, truncate it |
| 700 | */ | 767 | */ |
| 701 | if (num_read < count) | 768 | if (num_read < count) |
| 702 | fuse_read_update_size(inode, pos + num_read, attr_ver); | 769 | fuse_short_read(req, inode, attr_ver); |
| 703 | 770 | ||
| 704 | SetPageUptodate(page); | 771 | SetPageUptodate(page); |
| 705 | } | 772 | } |
| 706 | 773 | ||
| 774 | fuse_put_request(fc, req); | ||
| 775 | |||
| 776 | return err; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int fuse_readpage(struct file *file, struct page *page) | ||
| 780 | { | ||
| 781 | struct inode *inode = page->mapping->host; | ||
| 782 | int err; | ||
| 783 | |||
| 784 | err = -EIO; | ||
| 785 | if (is_bad_inode(inode)) | ||
| 786 | goto out; | ||
| 787 | |||
| 788 | err = fuse_do_readpage(file, page); | ||
| 707 | fuse_invalidate_atime(inode); | 789 | fuse_invalidate_atime(inode); |
| 708 | out: | 790 | out: |
| 709 | unlock_page(page); | 791 | unlock_page(page); |
| @@ -726,13 +808,9 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) | |||
| 726 | /* | 808 | /* |
| 727 | * Short read means EOF. If file size is larger, truncate it | 809 | * Short read means EOF. If file size is larger, truncate it |
| 728 | */ | 810 | */ |
| 729 | if (!req->out.h.error && num_read < count) { | 811 | if (!req->out.h.error && num_read < count) |
| 730 | loff_t pos; | 812 | fuse_short_read(req, inode, req->misc.read.attr_ver); |
| 731 | 813 | ||
| 732 | pos = page_offset(req->pages[0]) + num_read; | ||
| 733 | fuse_read_update_size(inode, pos, | ||
| 734 | req->misc.read.attr_ver); | ||
| 735 | } | ||
| 736 | fuse_invalidate_atime(inode); | 814 | fuse_invalidate_atime(inode); |
| 737 | } | 815 | } |
| 738 | 816 | ||
| @@ -922,16 +1000,21 @@ static size_t fuse_send_write(struct fuse_req *req, struct fuse_io_priv *io, | |||
| 922 | return req->misc.write.out.size; | 1000 | return req->misc.write.out.size; |
| 923 | } | 1001 | } |
| 924 | 1002 | ||
| 925 | void fuse_write_update_size(struct inode *inode, loff_t pos) | 1003 | bool fuse_write_update_size(struct inode *inode, loff_t pos) |
| 926 | { | 1004 | { |
| 927 | struct fuse_conn *fc = get_fuse_conn(inode); | 1005 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 928 | struct fuse_inode *fi = get_fuse_inode(inode); | 1006 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 1007 | bool ret = false; | ||
| 929 | 1008 | ||
| 930 | spin_lock(&fc->lock); | 1009 | spin_lock(&fc->lock); |
| 931 | fi->attr_version = ++fc->attr_version; | 1010 | fi->attr_version = ++fc->attr_version; |
| 932 | if (pos > inode->i_size) | 1011 | if (pos > inode->i_size) { |
| 933 | i_size_write(inode, pos); | 1012 | i_size_write(inode, pos); |
| 1013 | ret = true; | ||
| 1014 | } | ||
| 934 | spin_unlock(&fc->lock); | 1015 | spin_unlock(&fc->lock); |
| 1016 | |||
| 1017 | return ret; | ||
| 935 | } | 1018 | } |
| 936 | 1019 | ||
| 937 | static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file, | 1020 | static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file, |
| @@ -1116,6 +1199,15 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 1116 | struct iov_iter i; | 1199 | struct iov_iter i; |
| 1117 | loff_t endbyte = 0; | 1200 | loff_t endbyte = 0; |
| 1118 | 1201 | ||
| 1202 | if (get_fuse_conn(inode)->writeback_cache) { | ||
| 1203 | /* Update size (EOF optimization) and mode (SUID clearing) */ | ||
| 1204 | err = fuse_update_attributes(mapping->host, NULL, file, NULL); | ||
| 1205 | if (err) | ||
| 1206 | return err; | ||
| 1207 | |||
| 1208 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
| 1209 | } | ||
| 1210 | |||
| 1119 | WARN_ON(iocb->ki_pos != pos); | 1211 | WARN_ON(iocb->ki_pos != pos); |
| 1120 | 1212 | ||
| 1121 | ocount = 0; | 1213 | ocount = 0; |
| @@ -1289,13 +1381,18 @@ static inline int fuse_iter_npages(const struct iov_iter *ii_p) | |||
| 1289 | 1381 | ||
| 1290 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, | 1382 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, |
| 1291 | unsigned long nr_segs, size_t count, loff_t *ppos, | 1383 | unsigned long nr_segs, size_t count, loff_t *ppos, |
| 1292 | int write) | 1384 | int flags) |
| 1293 | { | 1385 | { |
| 1386 | int write = flags & FUSE_DIO_WRITE; | ||
| 1387 | int cuse = flags & FUSE_DIO_CUSE; | ||
| 1294 | struct file *file = io->file; | 1388 | struct file *file = io->file; |
| 1389 | struct inode *inode = file->f_mapping->host; | ||
| 1295 | struct fuse_file *ff = file->private_data; | 1390 | struct fuse_file *ff = file->private_data; |
| 1296 | struct fuse_conn *fc = ff->fc; | 1391 | struct fuse_conn *fc = ff->fc; |
| 1297 | size_t nmax = write ? fc->max_write : fc->max_read; | 1392 | size_t nmax = write ? fc->max_write : fc->max_read; |
| 1298 | loff_t pos = *ppos; | 1393 | loff_t pos = *ppos; |
| 1394 | pgoff_t idx_from = pos >> PAGE_CACHE_SHIFT; | ||
| 1395 | pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT; | ||
| 1299 | ssize_t res = 0; | 1396 | ssize_t res = 0; |
| 1300 | struct fuse_req *req; | 1397 | struct fuse_req *req; |
| 1301 | struct iov_iter ii; | 1398 | struct iov_iter ii; |
| @@ -1309,6 +1406,14 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, | |||
| 1309 | if (IS_ERR(req)) | 1406 | if (IS_ERR(req)) |
| 1310 | return PTR_ERR(req); | 1407 | return PTR_ERR(req); |
| 1311 | 1408 | ||
| 1409 | if (!cuse && fuse_range_is_writeback(inode, idx_from, idx_to)) { | ||
| 1410 | if (!write) | ||
| 1411 | mutex_lock(&inode->i_mutex); | ||
| 1412 | fuse_sync_writes(inode); | ||
| 1413 | if (!write) | ||
| 1414 | mutex_unlock(&inode->i_mutex); | ||
| 1415 | } | ||
| 1416 | |||
| 1312 | while (count) { | 1417 | while (count) { |
| 1313 | size_t nres; | 1418 | size_t nres; |
| 1314 | fl_owner_t owner = current->files; | 1419 | fl_owner_t owner = current->files; |
| @@ -1397,7 +1502,8 @@ static ssize_t __fuse_direct_write(struct fuse_io_priv *io, | |||
| 1397 | 1502 | ||
| 1398 | res = generic_write_checks(file, ppos, &count, 0); | 1503 | res = generic_write_checks(file, ppos, &count, 0); |
| 1399 | if (!res) | 1504 | if (!res) |
| 1400 | res = fuse_direct_io(io, iov, nr_segs, count, ppos, 1); | 1505 | res = fuse_direct_io(io, iov, nr_segs, count, ppos, |
| 1506 | FUSE_DIO_WRITE); | ||
| 1401 | 1507 | ||
| 1402 | fuse_invalidate_attr(inode); | 1508 | fuse_invalidate_attr(inode); |
| 1403 | 1509 | ||
| @@ -1885,6 +1991,77 @@ out: | |||
| 1885 | return err; | 1991 | return err; |
| 1886 | } | 1992 | } |
| 1887 | 1993 | ||
| 1994 | /* | ||
| 1995 | * It's worthy to make sure that space is reserved on disk for the write, | ||
| 1996 | * but how to implement it without killing performance need more thinking. | ||
| 1997 | */ | ||
| 1998 | static int fuse_write_begin(struct file *file, struct address_space *mapping, | ||
| 1999 | loff_t pos, unsigned len, unsigned flags, | ||
| 2000 | struct page **pagep, void **fsdata) | ||
| 2001 | { | ||
| 2002 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | ||
| 2003 | struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode); | ||
| 2004 | struct page *page; | ||
| 2005 | loff_t fsize; | ||
| 2006 | int err = -ENOMEM; | ||
| 2007 | |||
| 2008 | WARN_ON(!fc->writeback_cache); | ||
| 2009 | |||
| 2010 | page = grab_cache_page_write_begin(mapping, index, flags); | ||
| 2011 | if (!page) | ||
| 2012 | goto error; | ||
| 2013 | |||
| 2014 | fuse_wait_on_page_writeback(mapping->host, page->index); | ||
| 2015 | |||
| 2016 | if (PageUptodate(page) || len == PAGE_CACHE_SIZE) | ||
| 2017 | goto success; | ||
| 2018 | /* | ||
| 2019 | * Check if the start this page comes after the end of file, in which | ||
| 2020 | * case the readpage can be optimized away. | ||
| 2021 | */ | ||
| 2022 | fsize = i_size_read(mapping->host); | ||
| 2023 | if (fsize <= (pos & PAGE_CACHE_MASK)) { | ||
| 2024 | size_t off = pos & ~PAGE_CACHE_MASK; | ||
| 2025 | if (off) | ||
| 2026 | zero_user_segment(page, 0, off); | ||
| 2027 | goto success; | ||
| 2028 | } | ||
| 2029 | err = fuse_do_readpage(file, page); | ||
| 2030 | if (err) | ||
| 2031 | goto cleanup; | ||
| 2032 | success: | ||
| 2033 | *pagep = page; | ||
| 2034 | return 0; | ||
| 2035 | |||
| 2036 | cleanup: | ||
| 2037 | unlock_page(page); | ||
| 2038 | page_cache_release(page); | ||
| 2039 | error: | ||
| 2040 | return err; | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | static int fuse_write_end(struct file *file, struct address_space *mapping, | ||
| 2044 | loff_t pos, unsigned len, unsigned copied, | ||
| 2045 | struct page *page, void *fsdata) | ||
| 2046 | { | ||
| 2047 | struct inode *inode = page->mapping->host; | ||
| 2048 | |||
| 2049 | if (!PageUptodate(page)) { | ||
| 2050 | /* Zero any unwritten bytes at the end of the page */ | ||
| 2051 | size_t endoff = (pos + copied) & ~PAGE_CACHE_MASK; | ||
| 2052 | if (endoff) | ||
| 2053 | zero_user_segment(page, endoff, PAGE_CACHE_SIZE); | ||
| 2054 | SetPageUptodate(page); | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | fuse_write_update_size(inode, pos + copied); | ||
| 2058 | set_page_dirty(page); | ||
| 2059 | unlock_page(page); | ||
| 2060 | page_cache_release(page); | ||
| 2061 | |||
| 2062 | return copied; | ||
| 2063 | } | ||
| 2064 | |||
| 1888 | static int fuse_launder_page(struct page *page) | 2065 | static int fuse_launder_page(struct page *page) |
| 1889 | { | 2066 | { |
| 1890 | int err = 0; | 2067 | int err = 0; |
| @@ -1946,20 +2123,9 @@ static const struct vm_operations_struct fuse_file_vm_ops = { | |||
| 1946 | 2123 | ||
| 1947 | static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) | 2124 | static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) |
| 1948 | { | 2125 | { |
| 1949 | if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) { | 2126 | if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) |
| 1950 | struct inode *inode = file_inode(file); | 2127 | fuse_link_write_file(file); |
| 1951 | struct fuse_conn *fc = get_fuse_conn(inode); | 2128 | |
| 1952 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
| 1953 | struct fuse_file *ff = file->private_data; | ||
| 1954 | /* | ||
| 1955 | * file may be written through mmap, so chain it onto the | ||
| 1956 | * inodes's write_file list | ||
| 1957 | */ | ||
| 1958 | spin_lock(&fc->lock); | ||
| 1959 | if (list_empty(&ff->write_entry)) | ||
| 1960 | list_add(&ff->write_entry, &fi->write_files); | ||
| 1961 | spin_unlock(&fc->lock); | ||
| 1962 | } | ||
| 1963 | file_accessed(file); | 2129 | file_accessed(file); |
| 1964 | vma->vm_ops = &fuse_file_vm_ops; | 2130 | vma->vm_ops = &fuse_file_vm_ops; |
| 1965 | return 0; | 2131 | return 0; |
| @@ -2606,7 +2772,7 @@ static void fuse_register_polled_file(struct fuse_conn *fc, | |||
| 2606 | { | 2772 | { |
| 2607 | spin_lock(&fc->lock); | 2773 | spin_lock(&fc->lock); |
| 2608 | if (RB_EMPTY_NODE(&ff->polled_node)) { | 2774 | if (RB_EMPTY_NODE(&ff->polled_node)) { |
| 2609 | struct rb_node **link, *parent; | 2775 | struct rb_node **link, *uninitialized_var(parent); |
| 2610 | 2776 | ||
| 2611 | link = fuse_find_polled_node(fc, ff->kh, &parent); | 2777 | link = fuse_find_polled_node(fc, ff->kh, &parent); |
| 2612 | BUG_ON(*link); | 2778 | BUG_ON(*link); |
| @@ -2850,8 +3016,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | |||
| 2850 | goto out; | 3016 | goto out; |
| 2851 | 3017 | ||
| 2852 | /* we could have extended the file */ | 3018 | /* we could have extended the file */ |
| 2853 | if (!(mode & FALLOC_FL_KEEP_SIZE)) | 3019 | if (!(mode & FALLOC_FL_KEEP_SIZE)) { |
| 2854 | fuse_write_update_size(inode, offset + length); | 3020 | bool changed = fuse_write_update_size(inode, offset + length); |
| 3021 | |||
| 3022 | if (changed && fc->writeback_cache) { | ||
| 3023 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
| 3024 | |||
| 3025 | inode->i_mtime = current_fs_time(inode->i_sb); | ||
| 3026 | set_bit(FUSE_I_MTIME_DIRTY, &fi->state); | ||
| 3027 | } | ||
| 3028 | } | ||
| 2855 | 3029 | ||
| 2856 | if (mode & FALLOC_FL_PUNCH_HOLE) | 3030 | if (mode & FALLOC_FL_PUNCH_HOLE) |
| 2857 | truncate_pagecache_range(inode, offset, offset + length - 1); | 3031 | truncate_pagecache_range(inode, offset, offset + length - 1); |
| @@ -2915,6 +3089,8 @@ static const struct address_space_operations fuse_file_aops = { | |||
| 2915 | .set_page_dirty = __set_page_dirty_nobuffers, | 3089 | .set_page_dirty = __set_page_dirty_nobuffers, |
| 2916 | .bmap = fuse_bmap, | 3090 | .bmap = fuse_bmap, |
| 2917 | .direct_IO = fuse_direct_IO, | 3091 | .direct_IO = fuse_direct_IO, |
| 3092 | .write_begin = fuse_write_begin, | ||
| 3093 | .write_end = fuse_write_end, | ||
| 2918 | }; | 3094 | }; |
| 2919 | 3095 | ||
| 2920 | void fuse_init_file_inode(struct inode *inode) | 3096 | void fuse_init_file_inode(struct inode *inode) |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 2da5db2c8bdb..a257ed8ebee6 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -119,6 +119,8 @@ enum { | |||
| 119 | FUSE_I_INIT_RDPLUS, | 119 | FUSE_I_INIT_RDPLUS, |
| 120 | /** An operation changing file size is in progress */ | 120 | /** An operation changing file size is in progress */ |
| 121 | FUSE_I_SIZE_UNSTABLE, | 121 | FUSE_I_SIZE_UNSTABLE, |
| 122 | /** i_mtime has been updated locally; a flush to userspace needed */ | ||
| 123 | FUSE_I_MTIME_DIRTY, | ||
| 122 | }; | 124 | }; |
| 123 | 125 | ||
| 124 | struct fuse_conn; | 126 | struct fuse_conn; |
| @@ -480,6 +482,9 @@ struct fuse_conn { | |||
| 480 | /** Set if bdi is valid */ | 482 | /** Set if bdi is valid */ |
| 481 | unsigned bdi_initialized:1; | 483 | unsigned bdi_initialized:1; |
| 482 | 484 | ||
| 485 | /** write-back cache policy (default is write-through) */ | ||
| 486 | unsigned writeback_cache:1; | ||
| 487 | |||
| 483 | /* | 488 | /* |
| 484 | * The following bitfields are only for optimization purposes | 489 | * The following bitfields are only for optimization purposes |
| 485 | * and hence races in setting them will not cause malfunction | 490 | * and hence races in setting them will not cause malfunction |
| @@ -863,9 +868,20 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | |||
| 863 | 868 | ||
| 864 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 869 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
| 865 | bool isdir); | 870 | bool isdir); |
| 871 | |||
| 872 | /** | ||
| 873 | * fuse_direct_io() flags | ||
| 874 | */ | ||
| 875 | |||
| 876 | /** If set, it is WRITE; otherwise - READ */ | ||
| 877 | #define FUSE_DIO_WRITE (1 << 0) | ||
| 878 | |||
| 879 | /** CUSE pass fuse_direct_io() a file which f_mapping->host is not from FUSE */ | ||
| 880 | #define FUSE_DIO_CUSE (1 << 1) | ||
| 881 | |||
| 866 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, | 882 | ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov, |
| 867 | unsigned long nr_segs, size_t count, loff_t *ppos, | 883 | unsigned long nr_segs, size_t count, loff_t *ppos, |
| 868 | int write); | 884 | int flags); |
| 869 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | 885 | long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, |
| 870 | unsigned int flags); | 886 | unsigned int flags); |
| 871 | long fuse_ioctl_common(struct file *file, unsigned int cmd, | 887 | long fuse_ioctl_common(struct file *file, unsigned int cmd, |
| @@ -873,7 +889,9 @@ long fuse_ioctl_common(struct file *file, unsigned int cmd, | |||
| 873 | unsigned fuse_file_poll(struct file *file, poll_table *wait); | 889 | unsigned fuse_file_poll(struct file *file, poll_table *wait); |
| 874 | int fuse_dev_release(struct inode *inode, struct file *file); | 890 | int fuse_dev_release(struct inode *inode, struct file *file); |
| 875 | 891 | ||
| 876 | void fuse_write_update_size(struct inode *inode, loff_t pos); | 892 | bool fuse_write_update_size(struct inode *inode, loff_t pos); |
| 893 | |||
| 894 | int fuse_flush_mtime(struct file *file, bool nofail); | ||
| 877 | 895 | ||
| 878 | int fuse_do_setattr(struct inode *inode, struct iattr *attr, | 896 | int fuse_do_setattr(struct inode *inode, struct iattr *attr, |
| 879 | struct file *file); | 897 | struct file *file); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 9c761b611c54..b4bff1b15028 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -170,8 +170,11 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
| 170 | inode->i_blocks = attr->blocks; | 170 | inode->i_blocks = attr->blocks; |
| 171 | inode->i_atime.tv_sec = attr->atime; | 171 | inode->i_atime.tv_sec = attr->atime; |
| 172 | inode->i_atime.tv_nsec = attr->atimensec; | 172 | inode->i_atime.tv_nsec = attr->atimensec; |
| 173 | inode->i_mtime.tv_sec = attr->mtime; | 173 | /* mtime from server may be stale due to local buffered write */ |
| 174 | inode->i_mtime.tv_nsec = attr->mtimensec; | 174 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) { |
| 175 | inode->i_mtime.tv_sec = attr->mtime; | ||
| 176 | inode->i_mtime.tv_nsec = attr->mtimensec; | ||
| 177 | } | ||
| 175 | inode->i_ctime.tv_sec = attr->ctime; | 178 | inode->i_ctime.tv_sec = attr->ctime; |
| 176 | inode->i_ctime.tv_nsec = attr->ctimensec; | 179 | inode->i_ctime.tv_nsec = attr->ctimensec; |
| 177 | 180 | ||
| @@ -197,6 +200,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
| 197 | { | 200 | { |
| 198 | struct fuse_conn *fc = get_fuse_conn(inode); | 201 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 199 | struct fuse_inode *fi = get_fuse_inode(inode); | 202 | struct fuse_inode *fi = get_fuse_inode(inode); |
| 203 | bool is_wb = fc->writeback_cache; | ||
| 200 | loff_t oldsize; | 204 | loff_t oldsize; |
| 201 | struct timespec old_mtime; | 205 | struct timespec old_mtime; |
| 202 | 206 | ||
| @@ -211,10 +215,16 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | |||
| 211 | fuse_change_attributes_common(inode, attr, attr_valid); | 215 | fuse_change_attributes_common(inode, attr, attr_valid); |
| 212 | 216 | ||
| 213 | oldsize = inode->i_size; | 217 | oldsize = inode->i_size; |
| 214 | i_size_write(inode, attr->size); | 218 | /* |
| 219 | * In case of writeback_cache enabled, the cached writes beyond EOF | ||
| 220 | * extend local i_size without keeping userspace server in sync. So, | ||
| 221 | * attr->size coming from server can be stale. We cannot trust it. | ||
| 222 | */ | ||
| 223 | if (!is_wb || !S_ISREG(inode->i_mode)) | ||
| 224 | i_size_write(inode, attr->size); | ||
| 215 | spin_unlock(&fc->lock); | 225 | spin_unlock(&fc->lock); |
| 216 | 226 | ||
| 217 | if (S_ISREG(inode->i_mode)) { | 227 | if (!is_wb && S_ISREG(inode->i_mode)) { |
| 218 | bool inval = false; | 228 | bool inval = false; |
| 219 | 229 | ||
| 220 | if (oldsize != attr->size) { | 230 | if (oldsize != attr->size) { |
| @@ -243,6 +253,8 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
| 243 | { | 253 | { |
| 244 | inode->i_mode = attr->mode & S_IFMT; | 254 | inode->i_mode = attr->mode & S_IFMT; |
| 245 | inode->i_size = attr->size; | 255 | inode->i_size = attr->size; |
| 256 | inode->i_mtime.tv_sec = attr->mtime; | ||
| 257 | inode->i_mtime.tv_nsec = attr->mtimensec; | ||
| 246 | if (S_ISREG(inode->i_mode)) { | 258 | if (S_ISREG(inode->i_mode)) { |
| 247 | fuse_init_common(inode); | 259 | fuse_init_common(inode); |
| 248 | fuse_init_file_inode(inode); | 260 | fuse_init_file_inode(inode); |
| @@ -289,7 +301,9 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
| 289 | return NULL; | 301 | return NULL; |
| 290 | 302 | ||
| 291 | if ((inode->i_state & I_NEW)) { | 303 | if ((inode->i_state & I_NEW)) { |
| 292 | inode->i_flags |= S_NOATIME|S_NOCMTIME; | 304 | inode->i_flags |= S_NOATIME; |
| 305 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) | ||
| 306 | inode->i_flags |= S_NOCMTIME; | ||
| 293 | inode->i_generation = generation; | 307 | inode->i_generation = generation; |
| 294 | inode->i_data.backing_dev_info = &fc->bdi; | 308 | inode->i_data.backing_dev_info = &fc->bdi; |
| 295 | fuse_init_inode(inode, attr); | 309 | fuse_init_inode(inode, attr); |
| @@ -873,6 +887,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
| 873 | } | 887 | } |
| 874 | if (arg->flags & FUSE_ASYNC_DIO) | 888 | if (arg->flags & FUSE_ASYNC_DIO) |
| 875 | fc->async_dio = 1; | 889 | fc->async_dio = 1; |
| 890 | if (arg->flags & FUSE_WRITEBACK_CACHE) | ||
| 891 | fc->writeback_cache = 1; | ||
| 876 | } else { | 892 | } else { |
| 877 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 893 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
| 878 | fc->no_lock = 1; | 894 | fc->no_lock = 1; |
| @@ -900,7 +916,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
| 900 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK | | 916 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK | |
| 901 | FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ | | 917 | FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ | |
| 902 | FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA | | 918 | FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA | |
| 903 | FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO; | 919 | FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | |
| 920 | FUSE_WRITEBACK_CACHE; | ||
| 904 | req->in.h.opcode = FUSE_INIT; | 921 | req->in.h.opcode = FUSE_INIT; |
| 905 | req->in.numargs = 1; | 922 | req->in.numargs = 1; |
| 906 | req->in.args[0].size = sizeof(*arg); | 923 | req->in.args[0].size = sizeof(*arg); |
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 60bb2f9f7b74..cf4750e1bb49 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h | |||
| @@ -93,6 +93,9 @@ | |||
| 93 | * | 93 | * |
| 94 | * 7.22 | 94 | * 7.22 |
| 95 | * - add FUSE_ASYNC_DIO | 95 | * - add FUSE_ASYNC_DIO |
| 96 | * | ||
| 97 | * 7.23 | ||
| 98 | * - add FUSE_WRITEBACK_CACHE | ||
| 96 | */ | 99 | */ |
| 97 | 100 | ||
| 98 | #ifndef _LINUX_FUSE_H | 101 | #ifndef _LINUX_FUSE_H |
| @@ -128,7 +131,7 @@ | |||
| 128 | #define FUSE_KERNEL_VERSION 7 | 131 | #define FUSE_KERNEL_VERSION 7 |
| 129 | 132 | ||
| 130 | /** Minor version number of this interface */ | 133 | /** Minor version number of this interface */ |
| 131 | #define FUSE_KERNEL_MINOR_VERSION 22 | 134 | #define FUSE_KERNEL_MINOR_VERSION 23 |
| 132 | 135 | ||
| 133 | /** The node ID of the root inode */ | 136 | /** The node ID of the root inode */ |
| 134 | #define FUSE_ROOT_ID 1 | 137 | #define FUSE_ROOT_ID 1 |
| @@ -219,6 +222,7 @@ struct fuse_file_lock { | |||
| 219 | * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) | 222 | * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) |
| 220 | * FUSE_READDIRPLUS_AUTO: adaptive readdirplus | 223 | * FUSE_READDIRPLUS_AUTO: adaptive readdirplus |
| 221 | * FUSE_ASYNC_DIO: asynchronous direct I/O submission | 224 | * FUSE_ASYNC_DIO: asynchronous direct I/O submission |
| 225 | * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes | ||
| 222 | */ | 226 | */ |
| 223 | #define FUSE_ASYNC_READ (1 << 0) | 227 | #define FUSE_ASYNC_READ (1 << 0) |
| 224 | #define FUSE_POSIX_LOCKS (1 << 1) | 228 | #define FUSE_POSIX_LOCKS (1 << 1) |
| @@ -236,6 +240,7 @@ struct fuse_file_lock { | |||
| 236 | #define FUSE_DO_READDIRPLUS (1 << 13) | 240 | #define FUSE_DO_READDIRPLUS (1 << 13) |
| 237 | #define FUSE_READDIRPLUS_AUTO (1 << 14) | 241 | #define FUSE_READDIRPLUS_AUTO (1 << 14) |
| 238 | #define FUSE_ASYNC_DIO (1 << 15) | 242 | #define FUSE_ASYNC_DIO (1 << 15) |
| 243 | #define FUSE_WRITEBACK_CACHE (1 << 16) | ||
| 239 | 244 | ||
| 240 | /** | 245 | /** |
| 241 | * CUSE INIT request/reply flags | 246 | * CUSE INIT request/reply flags |
