diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 146 |
1 files changed, 100 insertions, 46 deletions
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 = { |