diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-05-06 12:09:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-05-06 12:09:35 -0400 |
commit | 256cf4c438e60116785a83b060614c63c7477e84 (patch) | |
tree | 2ed8ea7520d7467854be1cf966cf937cd4bbab0b | |
parent | 9bd29c56ade57106501d21fd4b0936644a426cb6 (diff) | |
parent | 1560c974dcd40a8d3f193283acd7cc6aee13dc13 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse fixes from Miklos Szeredi:
"This adds ctime update in the new cached writeback mode and also
fixes/simplifies the mtime update handling. Support for rename flags
(aka renameat2) is also added to the userspace API"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: add renameat2 support
fuse: clear MS_I_VERSION
fuse: clear FUSE_I_CTIME_DIRTY flag on setattr
fuse: trust kernel i_ctime only
fuse: remove .update_time
fuse: allow ctime flushing to userspace
fuse: fuse: add time_gran to INIT_OUT
fuse: add .write_inode
fuse: clean up fsync
fuse: fuse: fallocate: use file_update_time()
fuse: update mtime on open(O_TRUNC) in atomic_o_trunc mode
fuse: update mtime on truncate(2)
fuse: do not use uninitialized i_mode
fuse: fix mtime update error in fsync
fuse: check fallocate mode
fuse: add __exit to fuse_ctl_cleanup
-rw-r--r-- | fs/fuse/control.c | 2 | ||||
-rw-r--r-- | fs/fuse/dir.c | 146 | ||||
-rw-r--r-- | fs/fuse/file.c | 84 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 10 | ||||
-rw-r--r-- | fs/fuse/inode.c | 16 | ||||
-rw-r--r-- | include/uapi/linux/fuse.h | 22 |
6 files changed, 192 insertions, 88 deletions
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index a0b0855d00a9..205e0d5d5307 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c | |||
@@ -348,7 +348,7 @@ int __init fuse_ctl_init(void) | |||
348 | return register_filesystem(&fuse_ctl_fs_type); | 348 | return register_filesystem(&fuse_ctl_fs_type); |
349 | } | 349 | } |
350 | 350 | ||
351 | void fuse_ctl_cleanup(void) | 351 | void __exit fuse_ctl_cleanup(void) |
352 | { | 352 | { |
353 | unregister_filesystem(&fuse_ctl_fs_type); | 353 | unregister_filesystem(&fuse_ctl_fs_type); |
354 | } | 354 | } |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 5b4e035b364c..42198359fa1b 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -679,6 +679,14 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, | |||
679 | return create_new_entry(fc, req, dir, entry, S_IFLNK); | 679 | return create_new_entry(fc, req, dir, entry, S_IFLNK); |
680 | } | 680 | } |
681 | 681 | ||
682 | static inline void fuse_update_ctime(struct inode *inode) | ||
683 | { | ||
684 | if (!IS_NOCMTIME(inode)) { | ||
685 | inode->i_ctime = current_fs_time(inode->i_sb); | ||
686 | mark_inode_dirty_sync(inode); | ||
687 | } | ||
688 | } | ||
689 | |||
682 | static int fuse_unlink(struct inode *dir, struct dentry *entry) | 690 | static int fuse_unlink(struct inode *dir, struct dentry *entry) |
683 | { | 691 | { |
684 | int err; | 692 | int err; |
@@ -713,6 +721,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) | |||
713 | fuse_invalidate_attr(inode); | 721 | fuse_invalidate_attr(inode); |
714 | fuse_invalidate_attr(dir); | 722 | fuse_invalidate_attr(dir); |
715 | fuse_invalidate_entry_cache(entry); | 723 | fuse_invalidate_entry_cache(entry); |
724 | fuse_update_ctime(inode); | ||
716 | } else if (err == -EINTR) | 725 | } else if (err == -EINTR) |
717 | fuse_invalidate_entry(entry); | 726 | fuse_invalidate_entry(entry); |
718 | return err; | 727 | return err; |
@@ -743,23 +752,26 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) | |||
743 | return err; | 752 | return err; |
744 | } | 753 | } |
745 | 754 | ||
746 | static int fuse_rename(struct inode *olddir, struct dentry *oldent, | 755 | static int fuse_rename_common(struct inode *olddir, struct dentry *oldent, |
747 | struct inode *newdir, struct dentry *newent) | 756 | struct inode *newdir, struct dentry *newent, |
757 | unsigned int flags, int opcode, size_t argsize) | ||
748 | { | 758 | { |
749 | int err; | 759 | int err; |
750 | struct fuse_rename_in inarg; | 760 | struct fuse_rename2_in inarg; |
751 | struct fuse_conn *fc = get_fuse_conn(olddir); | 761 | struct fuse_conn *fc = get_fuse_conn(olddir); |
752 | struct fuse_req *req = fuse_get_req_nopages(fc); | 762 | struct fuse_req *req; |
753 | 763 | ||
764 | req = fuse_get_req_nopages(fc); | ||
754 | if (IS_ERR(req)) | 765 | if (IS_ERR(req)) |
755 | return PTR_ERR(req); | 766 | return PTR_ERR(req); |
756 | 767 | ||
757 | memset(&inarg, 0, sizeof(inarg)); | 768 | memset(&inarg, 0, argsize); |
758 | inarg.newdir = get_node_id(newdir); | 769 | inarg.newdir = get_node_id(newdir); |
759 | req->in.h.opcode = FUSE_RENAME; | 770 | inarg.flags = flags; |
771 | req->in.h.opcode = opcode; | ||
760 | req->in.h.nodeid = get_node_id(olddir); | 772 | req->in.h.nodeid = get_node_id(olddir); |
761 | req->in.numargs = 3; | 773 | req->in.numargs = 3; |
762 | req->in.args[0].size = sizeof(inarg); | 774 | req->in.args[0].size = argsize; |
763 | req->in.args[0].value = &inarg; | 775 | req->in.args[0].value = &inarg; |
764 | req->in.args[1].size = oldent->d_name.len + 1; | 776 | req->in.args[1].size = oldent->d_name.len + 1; |
765 | req->in.args[1].value = oldent->d_name.name; | 777 | req->in.args[1].value = oldent->d_name.name; |
@@ -771,15 +783,22 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, | |||
771 | if (!err) { | 783 | if (!err) { |
772 | /* ctime changes */ | 784 | /* ctime changes */ |
773 | fuse_invalidate_attr(oldent->d_inode); | 785 | fuse_invalidate_attr(oldent->d_inode); |
786 | fuse_update_ctime(oldent->d_inode); | ||
787 | |||
788 | if (flags & RENAME_EXCHANGE) { | ||
789 | fuse_invalidate_attr(newent->d_inode); | ||
790 | fuse_update_ctime(newent->d_inode); | ||
791 | } | ||
774 | 792 | ||
775 | fuse_invalidate_attr(olddir); | 793 | fuse_invalidate_attr(olddir); |
776 | if (olddir != newdir) | 794 | if (olddir != newdir) |
777 | fuse_invalidate_attr(newdir); | 795 | fuse_invalidate_attr(newdir); |
778 | 796 | ||
779 | /* newent will end up negative */ | 797 | /* newent will end up negative */ |
780 | if (newent->d_inode) { | 798 | if (!(flags & RENAME_EXCHANGE) && newent->d_inode) { |
781 | fuse_invalidate_attr(newent->d_inode); | 799 | fuse_invalidate_attr(newent->d_inode); |
782 | fuse_invalidate_entry_cache(newent); | 800 | fuse_invalidate_entry_cache(newent); |
801 | fuse_update_ctime(newent->d_inode); | ||
783 | } | 802 | } |
784 | } else if (err == -EINTR) { | 803 | } else if (err == -EINTR) { |
785 | /* If request was interrupted, DEITY only knows if the | 804 | /* If request was interrupted, DEITY only knows if the |
@@ -795,6 +814,36 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, | |||
795 | return err; | 814 | return err; |
796 | } | 815 | } |
797 | 816 | ||
817 | static int fuse_rename(struct inode *olddir, struct dentry *oldent, | ||
818 | struct inode *newdir, struct dentry *newent) | ||
819 | { | ||
820 | return fuse_rename_common(olddir, oldent, newdir, newent, 0, | ||
821 | FUSE_RENAME, sizeof(struct fuse_rename_in)); | ||
822 | } | ||
823 | |||
824 | static int fuse_rename2(struct inode *olddir, struct dentry *oldent, | ||
825 | struct inode *newdir, struct dentry *newent, | ||
826 | unsigned int flags) | ||
827 | { | ||
828 | struct fuse_conn *fc = get_fuse_conn(olddir); | ||
829 | int err; | ||
830 | |||
831 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | ||
832 | return -EINVAL; | ||
833 | |||
834 | if (fc->no_rename2 || fc->minor < 23) | ||
835 | return -EINVAL; | ||
836 | |||
837 | err = fuse_rename_common(olddir, oldent, newdir, newent, flags, | ||
838 | FUSE_RENAME2, sizeof(struct fuse_rename2_in)); | ||
839 | if (err == -ENOSYS) { | ||
840 | fc->no_rename2 = 1; | ||
841 | err = -EINVAL; | ||
842 | } | ||
843 | return err; | ||
844 | |||
845 | } | ||
846 | |||
798 | static int fuse_link(struct dentry *entry, struct inode *newdir, | 847 | static int fuse_link(struct dentry *entry, struct inode *newdir, |
799 | struct dentry *newent) | 848 | struct dentry *newent) |
800 | { | 849 | { |
@@ -829,6 +878,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, | |||
829 | inc_nlink(inode); | 878 | inc_nlink(inode); |
830 | spin_unlock(&fc->lock); | 879 | spin_unlock(&fc->lock); |
831 | fuse_invalidate_attr(inode); | 880 | fuse_invalidate_attr(inode); |
881 | fuse_update_ctime(inode); | ||
832 | } else if (err == -EINTR) { | 882 | } else if (err == -EINTR) { |
833 | fuse_invalidate_attr(inode); | 883 | fuse_invalidate_attr(inode); |
834 | } | 884 | } |
@@ -846,6 +896,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, | |||
846 | attr->size = i_size_read(inode); | 896 | attr->size = i_size_read(inode); |
847 | attr->mtime = inode->i_mtime.tv_sec; | 897 | attr->mtime = inode->i_mtime.tv_sec; |
848 | attr->mtimensec = inode->i_mtime.tv_nsec; | 898 | attr->mtimensec = inode->i_mtime.tv_nsec; |
899 | attr->ctime = inode->i_ctime.tv_sec; | ||
900 | attr->ctimensec = inode->i_ctime.tv_nsec; | ||
849 | } | 901 | } |
850 | 902 | ||
851 | stat->dev = inode->i_sb->s_dev; | 903 | stat->dev = inode->i_sb->s_dev; |
@@ -1504,7 +1556,7 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime) | |||
1504 | } | 1556 | } |
1505 | 1557 | ||
1506 | static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg, | 1558 | static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg, |
1507 | bool trust_local_mtime) | 1559 | bool trust_local_cmtime) |
1508 | { | 1560 | { |
1509 | unsigned ivalid = iattr->ia_valid; | 1561 | unsigned ivalid = iattr->ia_valid; |
1510 | 1562 | ||
@@ -1523,13 +1575,18 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg, | |||
1523 | if (!(ivalid & ATTR_ATIME_SET)) | 1575 | if (!(ivalid & ATTR_ATIME_SET)) |
1524 | arg->valid |= FATTR_ATIME_NOW; | 1576 | arg->valid |= FATTR_ATIME_NOW; |
1525 | } | 1577 | } |
1526 | if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_mtime)) { | 1578 | if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) { |
1527 | arg->valid |= FATTR_MTIME; | 1579 | arg->valid |= FATTR_MTIME; |
1528 | arg->mtime = iattr->ia_mtime.tv_sec; | 1580 | arg->mtime = iattr->ia_mtime.tv_sec; |
1529 | arg->mtimensec = iattr->ia_mtime.tv_nsec; | 1581 | arg->mtimensec = iattr->ia_mtime.tv_nsec; |
1530 | if (!(ivalid & ATTR_MTIME_SET) && !trust_local_mtime) | 1582 | if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime) |
1531 | arg->valid |= FATTR_MTIME_NOW; | 1583 | arg->valid |= FATTR_MTIME_NOW; |
1532 | } | 1584 | } |
1585 | if ((ivalid & ATTR_CTIME) && trust_local_cmtime) { | ||
1586 | arg->valid |= FATTR_CTIME; | ||
1587 | arg->ctime = iattr->ia_ctime.tv_sec; | ||
1588 | arg->ctimensec = iattr->ia_ctime.tv_nsec; | ||
1589 | } | ||
1533 | } | 1590 | } |
1534 | 1591 | ||
1535 | /* | 1592 | /* |
@@ -1597,39 +1654,38 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req, | |||
1597 | /* | 1654 | /* |
1598 | * Flush inode->i_mtime to the server | 1655 | * Flush inode->i_mtime to the server |
1599 | */ | 1656 | */ |
1600 | int fuse_flush_mtime(struct file *file, bool nofail) | 1657 | int fuse_flush_times(struct inode *inode, struct fuse_file *ff) |
1601 | { | 1658 | { |
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); | 1659 | struct fuse_conn *fc = get_fuse_conn(inode); |
1605 | struct fuse_req *req = NULL; | 1660 | struct fuse_req *req; |
1606 | struct fuse_setattr_in inarg; | 1661 | struct fuse_setattr_in inarg; |
1607 | struct fuse_attr_out outarg; | 1662 | struct fuse_attr_out outarg; |
1608 | int err; | 1663 | int err; |
1609 | 1664 | ||
1610 | if (nofail) { | 1665 | req = fuse_get_req_nopages(fc); |
1611 | req = fuse_get_req_nofail_nopages(fc, file); | 1666 | if (IS_ERR(req)) |
1612 | } else { | 1667 | return PTR_ERR(req); |
1613 | req = fuse_get_req_nopages(fc); | ||
1614 | if (IS_ERR(req)) | ||
1615 | return PTR_ERR(req); | ||
1616 | } | ||
1617 | 1668 | ||
1618 | memset(&inarg, 0, sizeof(inarg)); | 1669 | memset(&inarg, 0, sizeof(inarg)); |
1619 | memset(&outarg, 0, sizeof(outarg)); | 1670 | memset(&outarg, 0, sizeof(outarg)); |
1620 | 1671 | ||
1621 | inarg.valid |= FATTR_MTIME; | 1672 | inarg.valid = FATTR_MTIME; |
1622 | inarg.mtime = inode->i_mtime.tv_sec; | 1673 | inarg.mtime = inode->i_mtime.tv_sec; |
1623 | inarg.mtimensec = inode->i_mtime.tv_nsec; | 1674 | inarg.mtimensec = inode->i_mtime.tv_nsec; |
1624 | 1675 | if (fc->minor >= 23) { | |
1676 | inarg.valid |= FATTR_CTIME; | ||
1677 | inarg.ctime = inode->i_ctime.tv_sec; | ||
1678 | inarg.ctimensec = inode->i_ctime.tv_nsec; | ||
1679 | } | ||
1680 | if (ff) { | ||
1681 | inarg.valid |= FATTR_FH; | ||
1682 | inarg.fh = ff->fh; | ||
1683 | } | ||
1625 | fuse_setattr_fill(fc, req, inode, &inarg, &outarg); | 1684 | fuse_setattr_fill(fc, req, inode, &inarg, &outarg); |
1626 | fuse_request_send(fc, req); | 1685 | fuse_request_send(fc, req); |
1627 | err = req->out.h.error; | 1686 | err = req->out.h.error; |
1628 | fuse_put_request(fc, req); | 1687 | fuse_put_request(fc, req); |
1629 | 1688 | ||
1630 | if (!err) | ||
1631 | clear_bit(FUSE_I_MTIME_DIRTY, &fi->state); | ||
1632 | |||
1633 | return err; | 1689 | return err; |
1634 | } | 1690 | } |
1635 | 1691 | ||
@@ -1653,7 +1709,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
1653 | bool is_wb = fc->writeback_cache; | 1709 | bool is_wb = fc->writeback_cache; |
1654 | loff_t oldsize; | 1710 | loff_t oldsize; |
1655 | int err; | 1711 | int err; |
1656 | bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode); | 1712 | bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode); |
1657 | 1713 | ||
1658 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) | 1714 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
1659 | attr->ia_valid |= ATTR_FORCE; | 1715 | attr->ia_valid |= ATTR_FORCE; |
@@ -1678,11 +1734,13 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
1678 | if (is_truncate) { | 1734 | if (is_truncate) { |
1679 | fuse_set_nowrite(inode); | 1735 | fuse_set_nowrite(inode); |
1680 | set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); | 1736 | set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); |
1737 | if (trust_local_cmtime && attr->ia_size != inode->i_size) | ||
1738 | attr->ia_valid |= ATTR_MTIME | ATTR_CTIME; | ||
1681 | } | 1739 | } |
1682 | 1740 | ||
1683 | memset(&inarg, 0, sizeof(inarg)); | 1741 | memset(&inarg, 0, sizeof(inarg)); |
1684 | memset(&outarg, 0, sizeof(outarg)); | 1742 | memset(&outarg, 0, sizeof(outarg)); |
1685 | iattr_to_fattr(attr, &inarg, trust_local_mtime); | 1743 | iattr_to_fattr(attr, &inarg, trust_local_cmtime); |
1686 | if (file) { | 1744 | if (file) { |
1687 | struct fuse_file *ff = file->private_data; | 1745 | struct fuse_file *ff = file->private_data; |
1688 | inarg.valid |= FATTR_FH; | 1746 | inarg.valid |= FATTR_FH; |
@@ -1711,9 +1769,12 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
1711 | 1769 | ||
1712 | spin_lock(&fc->lock); | 1770 | spin_lock(&fc->lock); |
1713 | /* the kernel maintains i_mtime locally */ | 1771 | /* the kernel maintains i_mtime locally */ |
1714 | if (trust_local_mtime && (attr->ia_valid & ATTR_MTIME)) { | 1772 | if (trust_local_cmtime) { |
1715 | inode->i_mtime = attr->ia_mtime; | 1773 | if (attr->ia_valid & ATTR_MTIME) |
1716 | clear_bit(FUSE_I_MTIME_DIRTY, &fi->state); | 1774 | inode->i_mtime = attr->ia_mtime; |
1775 | if (attr->ia_valid & ATTR_CTIME) | ||
1776 | inode->i_ctime = attr->ia_ctime; | ||
1777 | /* FIXME: clear I_DIRTY_SYNC? */ | ||
1717 | } | 1778 | } |
1718 | 1779 | ||
1719 | fuse_change_attributes_common(inode, &outarg.attr, | 1780 | fuse_change_attributes_common(inode, &outarg.attr, |
@@ -1810,8 +1871,10 @@ static int fuse_setxattr(struct dentry *entry, const char *name, | |||
1810 | fc->no_setxattr = 1; | 1871 | fc->no_setxattr = 1; |
1811 | err = -EOPNOTSUPP; | 1872 | err = -EOPNOTSUPP; |
1812 | } | 1873 | } |
1813 | if (!err) | 1874 | if (!err) { |
1814 | fuse_invalidate_attr(inode); | 1875 | fuse_invalidate_attr(inode); |
1876 | fuse_update_ctime(inode); | ||
1877 | } | ||
1815 | return err; | 1878 | return err; |
1816 | } | 1879 | } |
1817 | 1880 | ||
@@ -1941,20 +2004,11 @@ static int fuse_removexattr(struct dentry *entry, const char *name) | |||
1941 | fc->no_removexattr = 1; | 2004 | fc->no_removexattr = 1; |
1942 | err = -EOPNOTSUPP; | 2005 | err = -EOPNOTSUPP; |
1943 | } | 2006 | } |
1944 | if (!err) | 2007 | if (!err) { |
1945 | fuse_invalidate_attr(inode); | 2008 | fuse_invalidate_attr(inode); |
1946 | return err; | 2009 | fuse_update_ctime(inode); |
1947 | } | ||
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 | } | 2010 | } |
1957 | return 0; | 2011 | return err; |
1958 | } | 2012 | } |
1959 | 2013 | ||
1960 | static const struct inode_operations fuse_dir_inode_operations = { | 2014 | static const struct inode_operations fuse_dir_inode_operations = { |
@@ -1964,6 +2018,7 @@ static const struct inode_operations fuse_dir_inode_operations = { | |||
1964 | .unlink = fuse_unlink, | 2018 | .unlink = fuse_unlink, |
1965 | .rmdir = fuse_rmdir, | 2019 | .rmdir = fuse_rmdir, |
1966 | .rename = fuse_rename, | 2020 | .rename = fuse_rename, |
2021 | .rename2 = fuse_rename2, | ||
1967 | .link = fuse_link, | 2022 | .link = fuse_link, |
1968 | .setattr = fuse_setattr, | 2023 | .setattr = fuse_setattr, |
1969 | .create = fuse_create, | 2024 | .create = fuse_create, |
@@ -1996,7 +2051,6 @@ static const struct inode_operations fuse_common_inode_operations = { | |||
1996 | .getxattr = fuse_getxattr, | 2051 | .getxattr = fuse_getxattr, |
1997 | .listxattr = fuse_listxattr, | 2052 | .listxattr = fuse_listxattr, |
1998 | .removexattr = fuse_removexattr, | 2053 | .removexattr = fuse_removexattr, |
1999 | .update_time = fuse_update_time, | ||
2000 | }; | 2054 | }; |
2001 | 2055 | ||
2002 | static const struct inode_operations fuse_symlink_inode_operations = { | 2056 | static const struct inode_operations fuse_symlink_inode_operations = { |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 13f8bdec5110..96d513e01a5d 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -223,6 +223,8 @@ void fuse_finish_open(struct inode *inode, struct file *file) | |||
223 | i_size_write(inode, 0); | 223 | i_size_write(inode, 0); |
224 | spin_unlock(&fc->lock); | 224 | spin_unlock(&fc->lock); |
225 | fuse_invalidate_attr(inode); | 225 | fuse_invalidate_attr(inode); |
226 | if (fc->writeback_cache) | ||
227 | file_update_time(file); | ||
226 | } | 228 | } |
227 | if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache) | 229 | if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache) |
228 | fuse_link_write_file(file); | 230 | fuse_link_write_file(file); |
@@ -232,18 +234,26 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | |||
232 | { | 234 | { |
233 | struct fuse_conn *fc = get_fuse_conn(inode); | 235 | struct fuse_conn *fc = get_fuse_conn(inode); |
234 | int err; | 236 | int err; |
237 | bool lock_inode = (file->f_flags & O_TRUNC) && | ||
238 | fc->atomic_o_trunc && | ||
239 | fc->writeback_cache; | ||
235 | 240 | ||
236 | err = generic_file_open(inode, file); | 241 | err = generic_file_open(inode, file); |
237 | if (err) | 242 | if (err) |
238 | return err; | 243 | return err; |
239 | 244 | ||
245 | if (lock_inode) | ||
246 | mutex_lock(&inode->i_mutex); | ||
247 | |||
240 | err = fuse_do_open(fc, get_node_id(inode), file, isdir); | 248 | err = fuse_do_open(fc, get_node_id(inode), file, isdir); |
241 | if (err) | ||
242 | return err; | ||
243 | 249 | ||
244 | fuse_finish_open(inode, file); | 250 | if (!err) |
251 | fuse_finish_open(inode, file); | ||
245 | 252 | ||
246 | return 0; | 253 | if (lock_inode) |
254 | mutex_unlock(&inode->i_mutex); | ||
255 | |||
256 | return err; | ||
247 | } | 257 | } |
248 | 258 | ||
249 | static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode) | 259 | static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode) |
@@ -314,10 +324,7 @@ static int fuse_release(struct inode *inode, struct file *file) | |||
314 | 324 | ||
315 | /* see fuse_vma_close() for !writeback_cache case */ | 325 | /* see fuse_vma_close() for !writeback_cache case */ |
316 | if (fc->writeback_cache) | 326 | if (fc->writeback_cache) |
317 | filemap_write_and_wait(file->f_mapping); | 327 | write_inode_now(inode, 1); |
318 | |||
319 | if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) | ||
320 | fuse_flush_mtime(file, true); | ||
321 | 328 | ||
322 | fuse_release_common(file, FUSE_RELEASE); | 329 | fuse_release_common(file, FUSE_RELEASE); |
323 | 330 | ||
@@ -439,7 +446,7 @@ static int fuse_flush(struct file *file, fl_owner_t id) | |||
439 | if (fc->no_flush) | 446 | if (fc->no_flush) |
440 | return 0; | 447 | return 0; |
441 | 448 | ||
442 | err = filemap_write_and_wait(file->f_mapping); | 449 | err = write_inode_now(inode, 1); |
443 | if (err) | 450 | if (err) |
444 | return err; | 451 | return err; |
445 | 452 | ||
@@ -480,13 +487,6 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, | |||
480 | if (is_bad_inode(inode)) | 487 | if (is_bad_inode(inode)) |
481 | return -EIO; | 488 | return -EIO; |
482 | 489 | ||
483 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
484 | if (err) | ||
485 | return err; | ||
486 | |||
487 | if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) | ||
488 | return 0; | ||
489 | |||
490 | mutex_lock(&inode->i_mutex); | 490 | mutex_lock(&inode->i_mutex); |
491 | 491 | ||
492 | /* | 492 | /* |
@@ -494,17 +494,17 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end, | |||
494 | * wait for all outstanding writes, before sending the FSYNC | 494 | * wait for all outstanding writes, before sending the FSYNC |
495 | * request. | 495 | * request. |
496 | */ | 496 | */ |
497 | err = write_inode_now(inode, 0); | 497 | err = filemap_write_and_wait_range(inode->i_mapping, start, end); |
498 | if (err) | 498 | if (err) |
499 | goto out; | 499 | goto out; |
500 | 500 | ||
501 | fuse_sync_writes(inode); | 501 | fuse_sync_writes(inode); |
502 | err = sync_inode_metadata(inode, 1); | ||
503 | if (err) | ||
504 | goto out; | ||
502 | 505 | ||
503 | if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) { | 506 | if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) |
504 | int err = fuse_flush_mtime(file, false); | 507 | goto out; |
505 | if (err) | ||
506 | goto out; | ||
507 | } | ||
508 | 508 | ||
509 | req = fuse_get_req_nopages(fc); | 509 | req = fuse_get_req_nopages(fc); |
510 | if (IS_ERR(req)) { | 510 | if (IS_ERR(req)) { |
@@ -1659,13 +1659,13 @@ static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req) | |||
1659 | fuse_writepage_free(fc, req); | 1659 | fuse_writepage_free(fc, req); |
1660 | } | 1660 | } |
1661 | 1661 | ||
1662 | static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc, | 1662 | static struct fuse_file *__fuse_write_file_get(struct fuse_conn *fc, |
1663 | struct fuse_inode *fi) | 1663 | struct fuse_inode *fi) |
1664 | { | 1664 | { |
1665 | struct fuse_file *ff = NULL; | 1665 | struct fuse_file *ff = NULL; |
1666 | 1666 | ||
1667 | spin_lock(&fc->lock); | 1667 | spin_lock(&fc->lock); |
1668 | if (!WARN_ON(list_empty(&fi->write_files))) { | 1668 | if (!list_empty(&fi->write_files)) { |
1669 | ff = list_entry(fi->write_files.next, struct fuse_file, | 1669 | ff = list_entry(fi->write_files.next, struct fuse_file, |
1670 | write_entry); | 1670 | write_entry); |
1671 | fuse_file_get(ff); | 1671 | fuse_file_get(ff); |
@@ -1675,6 +1675,29 @@ static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc, | |||
1675 | return ff; | 1675 | return ff; |
1676 | } | 1676 | } |
1677 | 1677 | ||
1678 | static struct fuse_file *fuse_write_file_get(struct fuse_conn *fc, | ||
1679 | struct fuse_inode *fi) | ||
1680 | { | ||
1681 | struct fuse_file *ff = __fuse_write_file_get(fc, fi); | ||
1682 | WARN_ON(!ff); | ||
1683 | return ff; | ||
1684 | } | ||
1685 | |||
1686 | int fuse_write_inode(struct inode *inode, struct writeback_control *wbc) | ||
1687 | { | ||
1688 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
1689 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
1690 | struct fuse_file *ff; | ||
1691 | int err; | ||
1692 | |||
1693 | ff = __fuse_write_file_get(fc, fi); | ||
1694 | err = fuse_flush_times(inode, ff); | ||
1695 | if (ff) | ||
1696 | fuse_file_put(ff, 0); | ||
1697 | |||
1698 | return err; | ||
1699 | } | ||
1700 | |||
1678 | static int fuse_writepage_locked(struct page *page) | 1701 | static int fuse_writepage_locked(struct page *page) |
1679 | { | 1702 | { |
1680 | struct address_space *mapping = page->mapping; | 1703 | struct address_space *mapping = page->mapping; |
@@ -2972,6 +2995,9 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | |||
2972 | bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) || | 2995 | bool lock_inode = !(mode & FALLOC_FL_KEEP_SIZE) || |
2973 | (mode & FALLOC_FL_PUNCH_HOLE); | 2996 | (mode & FALLOC_FL_PUNCH_HOLE); |
2974 | 2997 | ||
2998 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | ||
2999 | return -EOPNOTSUPP; | ||
3000 | |||
2975 | if (fc->no_fallocate) | 3001 | if (fc->no_fallocate) |
2976 | return -EOPNOTSUPP; | 3002 | return -EOPNOTSUPP; |
2977 | 3003 | ||
@@ -3017,12 +3043,8 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, | |||
3017 | if (!(mode & FALLOC_FL_KEEP_SIZE)) { | 3043 | if (!(mode & FALLOC_FL_KEEP_SIZE)) { |
3018 | bool changed = fuse_write_update_size(inode, offset + length); | 3044 | bool changed = fuse_write_update_size(inode, offset + length); |
3019 | 3045 | ||
3020 | if (changed && fc->writeback_cache) { | 3046 | if (changed && fc->writeback_cache) |
3021 | struct fuse_inode *fi = get_fuse_inode(inode); | 3047 | file_update_time(file); |
3022 | |||
3023 | inode->i_mtime = current_fs_time(inode->i_sb); | ||
3024 | set_bit(FUSE_I_MTIME_DIRTY, &fi->state); | ||
3025 | } | ||
3026 | } | 3048 | } |
3027 | 3049 | ||
3028 | if (mode & FALLOC_FL_PUNCH_HOLE) | 3050 | if (mode & FALLOC_FL_PUNCH_HOLE) |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index a257ed8ebee6..7aa5c75e0de1 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -119,8 +119,6 @@ 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, | ||
124 | }; | 122 | }; |
125 | 123 | ||
126 | struct fuse_conn; | 124 | struct fuse_conn; |
@@ -544,6 +542,9 @@ struct fuse_conn { | |||
544 | /** Is fallocate not implemented by fs? */ | 542 | /** Is fallocate not implemented by fs? */ |
545 | unsigned no_fallocate:1; | 543 | unsigned no_fallocate:1; |
546 | 544 | ||
545 | /** Is rename with flags implemented by fs? */ | ||
546 | unsigned no_rename2:1; | ||
547 | |||
547 | /** Use enhanced/automatic page cache invalidation. */ | 548 | /** Use enhanced/automatic page cache invalidation. */ |
548 | unsigned auto_inval_data:1; | 549 | unsigned auto_inval_data:1; |
549 | 550 | ||
@@ -725,7 +726,7 @@ int fuse_dev_init(void); | |||
725 | void fuse_dev_cleanup(void); | 726 | void fuse_dev_cleanup(void); |
726 | 727 | ||
727 | int fuse_ctl_init(void); | 728 | int fuse_ctl_init(void); |
728 | void fuse_ctl_cleanup(void); | 729 | void __exit fuse_ctl_cleanup(void); |
729 | 730 | ||
730 | /** | 731 | /** |
731 | * Allocate a request | 732 | * Allocate a request |
@@ -891,7 +892,8 @@ int fuse_dev_release(struct inode *inode, struct file *file); | |||
891 | 892 | ||
892 | bool fuse_write_update_size(struct inode *inode, loff_t pos); | 893 | bool fuse_write_update_size(struct inode *inode, loff_t pos); |
893 | 894 | ||
894 | int fuse_flush_mtime(struct file *file, bool nofail); | 895 | int fuse_flush_times(struct inode *inode, struct fuse_file *ff); |
896 | int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); | ||
895 | 897 | ||
896 | int fuse_do_setattr(struct inode *inode, struct iattr *attr, | 898 | int fuse_do_setattr(struct inode *inode, struct iattr *attr, |
897 | struct file *file); | 899 | struct file *file); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 8d611696fcad..754dcf23de8a 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -175,9 +175,9 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
175 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) { | 175 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) { |
176 | inode->i_mtime.tv_sec = attr->mtime; | 176 | inode->i_mtime.tv_sec = attr->mtime; |
177 | inode->i_mtime.tv_nsec = attr->mtimensec; | 177 | inode->i_mtime.tv_nsec = attr->mtimensec; |
178 | inode->i_ctime.tv_sec = attr->ctime; | ||
179 | inode->i_ctime.tv_nsec = attr->ctimensec; | ||
178 | } | 180 | } |
179 | inode->i_ctime.tv_sec = attr->ctime; | ||
180 | inode->i_ctime.tv_nsec = attr->ctimensec; | ||
181 | 181 | ||
182 | if (attr->blksize != 0) | 182 | if (attr->blksize != 0) |
183 | inode->i_blkbits = ilog2(attr->blksize); | 183 | inode->i_blkbits = ilog2(attr->blksize); |
@@ -256,6 +256,8 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
256 | inode->i_size = attr->size; | 256 | inode->i_size = attr->size; |
257 | inode->i_mtime.tv_sec = attr->mtime; | 257 | inode->i_mtime.tv_sec = attr->mtime; |
258 | inode->i_mtime.tv_nsec = attr->mtimensec; | 258 | inode->i_mtime.tv_nsec = attr->mtimensec; |
259 | inode->i_ctime.tv_sec = attr->ctime; | ||
260 | inode->i_ctime.tv_nsec = attr->ctimensec; | ||
259 | if (S_ISREG(inode->i_mode)) { | 261 | if (S_ISREG(inode->i_mode)) { |
260 | fuse_init_common(inode); | 262 | fuse_init_common(inode); |
261 | fuse_init_file_inode(inode); | 263 | fuse_init_file_inode(inode); |
@@ -303,7 +305,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
303 | 305 | ||
304 | if ((inode->i_state & I_NEW)) { | 306 | if ((inode->i_state & I_NEW)) { |
305 | inode->i_flags |= S_NOATIME; | 307 | inode->i_flags |= S_NOATIME; |
306 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) | 308 | if (!fc->writeback_cache || !S_ISREG(attr->mode)) |
307 | inode->i_flags |= S_NOCMTIME; | 309 | inode->i_flags |= S_NOCMTIME; |
308 | inode->i_generation = generation; | 310 | inode->i_generation = generation; |
309 | inode->i_data.backing_dev_info = &fc->bdi; | 311 | inode->i_data.backing_dev_info = &fc->bdi; |
@@ -788,6 +790,7 @@ static const struct super_operations fuse_super_operations = { | |||
788 | .alloc_inode = fuse_alloc_inode, | 790 | .alloc_inode = fuse_alloc_inode, |
789 | .destroy_inode = fuse_destroy_inode, | 791 | .destroy_inode = fuse_destroy_inode, |
790 | .evict_inode = fuse_evict_inode, | 792 | .evict_inode = fuse_evict_inode, |
793 | .write_inode = fuse_write_inode, | ||
791 | .drop_inode = generic_delete_inode, | 794 | .drop_inode = generic_delete_inode, |
792 | .remount_fs = fuse_remount_fs, | 795 | .remount_fs = fuse_remount_fs, |
793 | .put_super = fuse_put_super, | 796 | .put_super = fuse_put_super, |
@@ -890,6 +893,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
890 | fc->async_dio = 1; | 893 | fc->async_dio = 1; |
891 | if (arg->flags & FUSE_WRITEBACK_CACHE) | 894 | if (arg->flags & FUSE_WRITEBACK_CACHE) |
892 | fc->writeback_cache = 1; | 895 | fc->writeback_cache = 1; |
896 | if (arg->time_gran && arg->time_gran <= 1000000000) | ||
897 | fc->sb->s_time_gran = arg->time_gran; | ||
898 | else | ||
899 | fc->sb->s_time_gran = 1000000000; | ||
900 | |||
893 | } else { | 901 | } else { |
894 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 902 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
895 | fc->no_lock = 1; | 903 | fc->no_lock = 1; |
@@ -996,7 +1004,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
996 | if (sb->s_flags & MS_MANDLOCK) | 1004 | if (sb->s_flags & MS_MANDLOCK) |
997 | goto err; | 1005 | goto err; |
998 | 1006 | ||
999 | sb->s_flags &= ~MS_NOSEC; | 1007 | sb->s_flags &= ~(MS_NOSEC | MS_I_VERSION); |
1000 | 1008 | ||
1001 | if (!parse_fuse_opt((char *) data, &d, is_bdev)) | 1009 | if (!parse_fuse_opt((char *) data, &d, is_bdev)) |
1002 | goto err; | 1010 | goto err; |
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index cf4750e1bb49..40b5ca8a1b1f 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h | |||
@@ -96,6 +96,11 @@ | |||
96 | * | 96 | * |
97 | * 7.23 | 97 | * 7.23 |
98 | * - add FUSE_WRITEBACK_CACHE | 98 | * - add FUSE_WRITEBACK_CACHE |
99 | * - add time_gran to fuse_init_out | ||
100 | * - add reserved space to fuse_init_out | ||
101 | * - add FATTR_CTIME | ||
102 | * - add ctime and ctimensec to fuse_setattr_in | ||
103 | * - add FUSE_RENAME2 request | ||
99 | */ | 104 | */ |
100 | 105 | ||
101 | #ifndef _LINUX_FUSE_H | 106 | #ifndef _LINUX_FUSE_H |
@@ -191,6 +196,7 @@ struct fuse_file_lock { | |||
191 | #define FATTR_ATIME_NOW (1 << 7) | 196 | #define FATTR_ATIME_NOW (1 << 7) |
192 | #define FATTR_MTIME_NOW (1 << 8) | 197 | #define FATTR_MTIME_NOW (1 << 8) |
193 | #define FATTR_LOCKOWNER (1 << 9) | 198 | #define FATTR_LOCKOWNER (1 << 9) |
199 | #define FATTR_CTIME (1 << 10) | ||
194 | 200 | ||
195 | /** | 201 | /** |
196 | * Flags returned by the OPEN request | 202 | * Flags returned by the OPEN request |
@@ -348,6 +354,7 @@ enum fuse_opcode { | |||
348 | FUSE_BATCH_FORGET = 42, | 354 | FUSE_BATCH_FORGET = 42, |
349 | FUSE_FALLOCATE = 43, | 355 | FUSE_FALLOCATE = 43, |
350 | FUSE_READDIRPLUS = 44, | 356 | FUSE_READDIRPLUS = 44, |
357 | FUSE_RENAME2 = 45, | ||
351 | 358 | ||
352 | /* CUSE specific operations */ | 359 | /* CUSE specific operations */ |
353 | CUSE_INIT = 4096, | 360 | CUSE_INIT = 4096, |
@@ -426,6 +433,12 @@ struct fuse_rename_in { | |||
426 | uint64_t newdir; | 433 | uint64_t newdir; |
427 | }; | 434 | }; |
428 | 435 | ||
436 | struct fuse_rename2_in { | ||
437 | uint64_t newdir; | ||
438 | uint32_t flags; | ||
439 | uint32_t padding; | ||
440 | }; | ||
441 | |||
429 | struct fuse_link_in { | 442 | struct fuse_link_in { |
430 | uint64_t oldnodeid; | 443 | uint64_t oldnodeid; |
431 | }; | 444 | }; |
@@ -438,10 +451,10 @@ struct fuse_setattr_in { | |||
438 | uint64_t lock_owner; | 451 | uint64_t lock_owner; |
439 | uint64_t atime; | 452 | uint64_t atime; |
440 | uint64_t mtime; | 453 | uint64_t mtime; |
441 | uint64_t unused2; | 454 | uint64_t ctime; |
442 | uint32_t atimensec; | 455 | uint32_t atimensec; |
443 | uint32_t mtimensec; | 456 | uint32_t mtimensec; |
444 | uint32_t unused3; | 457 | uint32_t ctimensec; |
445 | uint32_t mode; | 458 | uint32_t mode; |
446 | uint32_t unused4; | 459 | uint32_t unused4; |
447 | uint32_t uid; | 460 | uint32_t uid; |
@@ -559,6 +572,9 @@ struct fuse_init_in { | |||
559 | uint32_t flags; | 572 | uint32_t flags; |
560 | }; | 573 | }; |
561 | 574 | ||
575 | #define FUSE_COMPAT_INIT_OUT_SIZE 8 | ||
576 | #define FUSE_COMPAT_22_INIT_OUT_SIZE 24 | ||
577 | |||
562 | struct fuse_init_out { | 578 | struct fuse_init_out { |
563 | uint32_t major; | 579 | uint32_t major; |
564 | uint32_t minor; | 580 | uint32_t minor; |
@@ -567,6 +583,8 @@ struct fuse_init_out { | |||
567 | uint16_t max_background; | 583 | uint16_t max_background; |
568 | uint16_t congestion_threshold; | 584 | uint16_t congestion_threshold; |
569 | uint32_t max_write; | 585 | uint32_t max_write; |
586 | uint32_t time_gran; | ||
587 | uint32_t unused[9]; | ||
570 | }; | 588 | }; |
571 | 589 | ||
572 | #define CUSE_INIT_INFO_MAX 4096 | 590 | #define CUSE_INIT_INFO_MAX 4096 |