diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 145 |
1 files changed, 83 insertions, 62 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index db3ad849a289..ee9a179ebdf3 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -530,9 +530,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
530 | nfs_readdir_descriptor_t my_desc, | 530 | nfs_readdir_descriptor_t my_desc, |
531 | *desc = &my_desc; | 531 | *desc = &my_desc; |
532 | struct nfs_entry my_entry; | 532 | struct nfs_entry my_entry; |
533 | struct nfs_fh fh; | 533 | int res = -ENOMEM; |
534 | struct nfs_fattr fattr; | ||
535 | long res; | ||
536 | 534 | ||
537 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 535 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
538 | dentry->d_parent->d_name.name, dentry->d_name.name, | 536 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -554,9 +552,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
554 | 552 | ||
555 | my_entry.cookie = my_entry.prev_cookie = 0; | 553 | my_entry.cookie = my_entry.prev_cookie = 0; |
556 | my_entry.eof = 0; | 554 | my_entry.eof = 0; |
557 | my_entry.fh = &fh; | 555 | my_entry.fh = nfs_alloc_fhandle(); |
558 | my_entry.fattr = &fattr; | 556 | my_entry.fattr = nfs_alloc_fattr(); |
559 | nfs_fattr_init(&fattr); | 557 | if (my_entry.fh == NULL || my_entry.fattr == NULL) |
558 | goto out_alloc_failed; | ||
559 | |||
560 | desc->entry = &my_entry; | 560 | desc->entry = &my_entry; |
561 | 561 | ||
562 | nfs_block_sillyrename(dentry); | 562 | nfs_block_sillyrename(dentry); |
@@ -598,7 +598,10 @@ out: | |||
598 | nfs_unblock_sillyrename(dentry); | 598 | nfs_unblock_sillyrename(dentry); |
599 | if (res > 0) | 599 | if (res > 0) |
600 | res = 0; | 600 | res = 0; |
601 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n", | 601 | out_alloc_failed: |
602 | nfs_free_fattr(my_entry.fattr); | ||
603 | nfs_free_fhandle(my_entry.fh); | ||
604 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", | ||
602 | dentry->d_parent->d_name.name, dentry->d_name.name, | 605 | dentry->d_parent->d_name.name, dentry->d_name.name, |
603 | res); | 606 | res); |
604 | return res; | 607 | return res; |
@@ -776,9 +779,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
776 | struct inode *dir; | 779 | struct inode *dir; |
777 | struct inode *inode; | 780 | struct inode *inode; |
778 | struct dentry *parent; | 781 | struct dentry *parent; |
782 | struct nfs_fh *fhandle = NULL; | ||
783 | struct nfs_fattr *fattr = NULL; | ||
779 | int error; | 784 | int error; |
780 | struct nfs_fh fhandle; | ||
781 | struct nfs_fattr fattr; | ||
782 | 785 | ||
783 | parent = dget_parent(dentry); | 786 | parent = dget_parent(dentry); |
784 | dir = parent->d_inode; | 787 | dir = parent->d_inode; |
@@ -811,14 +814,22 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
811 | if (NFS_STALE(inode)) | 814 | if (NFS_STALE(inode)) |
812 | goto out_bad; | 815 | goto out_bad; |
813 | 816 | ||
814 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 817 | error = -ENOMEM; |
818 | fhandle = nfs_alloc_fhandle(); | ||
819 | fattr = nfs_alloc_fattr(); | ||
820 | if (fhandle == NULL || fattr == NULL) | ||
821 | goto out_error; | ||
822 | |||
823 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | ||
815 | if (error) | 824 | if (error) |
816 | goto out_bad; | 825 | goto out_bad; |
817 | if (nfs_compare_fh(NFS_FH(inode), &fhandle)) | 826 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
818 | goto out_bad; | 827 | goto out_bad; |
819 | if ((error = nfs_refresh_inode(inode, &fattr)) != 0) | 828 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
820 | goto out_bad; | 829 | goto out_bad; |
821 | 830 | ||
831 | nfs_free_fattr(fattr); | ||
832 | nfs_free_fhandle(fhandle); | ||
822 | out_set_verifier: | 833 | out_set_verifier: |
823 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 834 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
824 | out_valid: | 835 | out_valid: |
@@ -842,11 +853,21 @@ out_zap_parent: | |||
842 | shrink_dcache_parent(dentry); | 853 | shrink_dcache_parent(dentry); |
843 | } | 854 | } |
844 | d_drop(dentry); | 855 | d_drop(dentry); |
856 | nfs_free_fattr(fattr); | ||
857 | nfs_free_fhandle(fhandle); | ||
845 | dput(parent); | 858 | dput(parent); |
846 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | 859 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", |
847 | __func__, dentry->d_parent->d_name.name, | 860 | __func__, dentry->d_parent->d_name.name, |
848 | dentry->d_name.name); | 861 | dentry->d_name.name); |
849 | return 0; | 862 | return 0; |
863 | out_error: | ||
864 | nfs_free_fattr(fattr); | ||
865 | nfs_free_fhandle(fhandle); | ||
866 | dput(parent); | ||
867 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", | ||
868 | __func__, dentry->d_parent->d_name.name, | ||
869 | dentry->d_name.name, error); | ||
870 | return error; | ||
850 | } | 871 | } |
851 | 872 | ||
852 | /* | 873 | /* |
@@ -911,9 +932,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
911 | struct dentry *res; | 932 | struct dentry *res; |
912 | struct dentry *parent; | 933 | struct dentry *parent; |
913 | struct inode *inode = NULL; | 934 | struct inode *inode = NULL; |
935 | struct nfs_fh *fhandle = NULL; | ||
936 | struct nfs_fattr *fattr = NULL; | ||
914 | int error; | 937 | int error; |
915 | struct nfs_fh fhandle; | ||
916 | struct nfs_fattr fattr; | ||
917 | 938 | ||
918 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", | 939 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", |
919 | dentry->d_parent->d_name.name, dentry->d_name.name); | 940 | dentry->d_parent->d_name.name, dentry->d_name.name); |
@@ -923,7 +944,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
923 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 944 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
924 | goto out; | 945 | goto out; |
925 | 946 | ||
926 | res = ERR_PTR(-ENOMEM); | ||
927 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 947 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; |
928 | 948 | ||
929 | /* | 949 | /* |
@@ -936,17 +956,23 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
936 | goto out; | 956 | goto out; |
937 | } | 957 | } |
938 | 958 | ||
959 | res = ERR_PTR(-ENOMEM); | ||
960 | fhandle = nfs_alloc_fhandle(); | ||
961 | fattr = nfs_alloc_fattr(); | ||
962 | if (fhandle == NULL || fattr == NULL) | ||
963 | goto out; | ||
964 | |||
939 | parent = dentry->d_parent; | 965 | parent = dentry->d_parent; |
940 | /* Protect against concurrent sillydeletes */ | 966 | /* Protect against concurrent sillydeletes */ |
941 | nfs_block_sillyrename(parent); | 967 | nfs_block_sillyrename(parent); |
942 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 968 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
943 | if (error == -ENOENT) | 969 | if (error == -ENOENT) |
944 | goto no_entry; | 970 | goto no_entry; |
945 | if (error < 0) { | 971 | if (error < 0) { |
946 | res = ERR_PTR(error); | 972 | res = ERR_PTR(error); |
947 | goto out_unblock_sillyrename; | 973 | goto out_unblock_sillyrename; |
948 | } | 974 | } |
949 | inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); | 975 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
950 | res = (struct dentry *)inode; | 976 | res = (struct dentry *)inode; |
951 | if (IS_ERR(res)) | 977 | if (IS_ERR(res)) |
952 | goto out_unblock_sillyrename; | 978 | goto out_unblock_sillyrename; |
@@ -962,6 +988,8 @@ no_entry: | |||
962 | out_unblock_sillyrename: | 988 | out_unblock_sillyrename: |
963 | nfs_unblock_sillyrename(parent); | 989 | nfs_unblock_sillyrename(parent); |
964 | out: | 990 | out: |
991 | nfs_free_fattr(fattr); | ||
992 | nfs_free_fhandle(fhandle); | ||
965 | return res; | 993 | return res; |
966 | } | 994 | } |
967 | 995 | ||
@@ -1052,7 +1080,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1052 | struct inode *dir; | 1080 | struct inode *dir; |
1053 | int openflags, ret = 0; | 1081 | int openflags, ret = 0; |
1054 | 1082 | ||
1055 | if (!is_atomic_open(nd)) | 1083 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
1056 | goto no_open; | 1084 | goto no_open; |
1057 | parent = dget_parent(dentry); | 1085 | parent = dget_parent(dentry); |
1058 | dir = parent->d_inode; | 1086 | dir = parent->d_inode; |
@@ -1669,28 +1697,33 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry) | |||
1669 | smp_mb__after_atomic_dec(); | 1697 | smp_mb__after_atomic_dec(); |
1670 | } | 1698 | } |
1671 | 1699 | ||
1700 | static void nfs_access_free_list(struct list_head *head) | ||
1701 | { | ||
1702 | struct nfs_access_entry *cache; | ||
1703 | |||
1704 | while (!list_empty(head)) { | ||
1705 | cache = list_entry(head->next, struct nfs_access_entry, lru); | ||
1706 | list_del(&cache->lru); | ||
1707 | nfs_access_free_entry(cache); | ||
1708 | } | ||
1709 | } | ||
1710 | |||
1672 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | 1711 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) |
1673 | { | 1712 | { |
1674 | LIST_HEAD(head); | 1713 | LIST_HEAD(head); |
1675 | struct nfs_inode *nfsi; | 1714 | struct nfs_inode *nfsi; |
1676 | struct nfs_access_entry *cache; | 1715 | struct nfs_access_entry *cache; |
1677 | 1716 | ||
1678 | restart: | 1717 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
1718 | return (nr_to_scan == 0) ? 0 : -1; | ||
1719 | |||
1679 | spin_lock(&nfs_access_lru_lock); | 1720 | spin_lock(&nfs_access_lru_lock); |
1680 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1721 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { |
1681 | struct rw_semaphore *s_umount; | ||
1682 | struct inode *inode; | 1722 | struct inode *inode; |
1683 | 1723 | ||
1684 | if (nr_to_scan-- == 0) | 1724 | if (nr_to_scan-- == 0) |
1685 | break; | 1725 | break; |
1686 | s_umount = &nfsi->vfs_inode.i_sb->s_umount; | 1726 | inode = &nfsi->vfs_inode; |
1687 | if (!down_read_trylock(s_umount)) | ||
1688 | continue; | ||
1689 | inode = igrab(&nfsi->vfs_inode); | ||
1690 | if (inode == NULL) { | ||
1691 | up_read(s_umount); | ||
1692 | continue; | ||
1693 | } | ||
1694 | spin_lock(&inode->i_lock); | 1727 | spin_lock(&inode->i_lock); |
1695 | if (list_empty(&nfsi->access_cache_entry_lru)) | 1728 | if (list_empty(&nfsi->access_cache_entry_lru)) |
1696 | goto remove_lru_entry; | 1729 | goto remove_lru_entry; |
@@ -1704,61 +1737,47 @@ restart: | |||
1704 | else { | 1737 | else { |
1705 | remove_lru_entry: | 1738 | remove_lru_entry: |
1706 | list_del_init(&nfsi->access_cache_inode_lru); | 1739 | list_del_init(&nfsi->access_cache_inode_lru); |
1740 | smp_mb__before_clear_bit(); | ||
1707 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | 1741 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); |
1742 | smp_mb__after_clear_bit(); | ||
1708 | } | 1743 | } |
1709 | spin_unlock(&inode->i_lock); | ||
1710 | spin_unlock(&nfs_access_lru_lock); | ||
1711 | iput(inode); | ||
1712 | up_read(s_umount); | ||
1713 | goto restart; | ||
1714 | } | 1744 | } |
1715 | spin_unlock(&nfs_access_lru_lock); | 1745 | spin_unlock(&nfs_access_lru_lock); |
1716 | while (!list_empty(&head)) { | 1746 | nfs_access_free_list(&head); |
1717 | cache = list_entry(head.next, struct nfs_access_entry, lru); | ||
1718 | list_del(&cache->lru); | ||
1719 | nfs_access_free_entry(cache); | ||
1720 | } | ||
1721 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; | 1747 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; |
1722 | } | 1748 | } |
1723 | 1749 | ||
1724 | static void __nfs_access_zap_cache(struct inode *inode) | 1750 | static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) |
1725 | { | 1751 | { |
1726 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1727 | struct rb_root *root_node = &nfsi->access_cache; | 1752 | struct rb_root *root_node = &nfsi->access_cache; |
1728 | struct rb_node *n, *dispose = NULL; | 1753 | struct rb_node *n; |
1729 | struct nfs_access_entry *entry; | 1754 | struct nfs_access_entry *entry; |
1730 | 1755 | ||
1731 | /* Unhook entries from the cache */ | 1756 | /* Unhook entries from the cache */ |
1732 | while ((n = rb_first(root_node)) != NULL) { | 1757 | while ((n = rb_first(root_node)) != NULL) { |
1733 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | 1758 | entry = rb_entry(n, struct nfs_access_entry, rb_node); |
1734 | rb_erase(n, root_node); | 1759 | rb_erase(n, root_node); |
1735 | list_del(&entry->lru); | 1760 | list_move(&entry->lru, head); |
1736 | n->rb_left = dispose; | ||
1737 | dispose = n; | ||
1738 | } | 1761 | } |
1739 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1762 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; |
1740 | spin_unlock(&inode->i_lock); | ||
1741 | |||
1742 | /* Now kill them all! */ | ||
1743 | while (dispose != NULL) { | ||
1744 | n = dispose; | ||
1745 | dispose = n->rb_left; | ||
1746 | nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); | ||
1747 | } | ||
1748 | } | 1763 | } |
1749 | 1764 | ||
1750 | void nfs_access_zap_cache(struct inode *inode) | 1765 | void nfs_access_zap_cache(struct inode *inode) |
1751 | { | 1766 | { |
1767 | LIST_HEAD(head); | ||
1768 | |||
1769 | if (test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags) == 0) | ||
1770 | return; | ||
1752 | /* Remove from global LRU init */ | 1771 | /* Remove from global LRU init */ |
1753 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1772 | spin_lock(&nfs_access_lru_lock); |
1754 | spin_lock(&nfs_access_lru_lock); | 1773 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
1755 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | 1774 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
1756 | spin_unlock(&nfs_access_lru_lock); | ||
1757 | } | ||
1758 | 1775 | ||
1759 | spin_lock(&inode->i_lock); | 1776 | spin_lock(&inode->i_lock); |
1760 | /* This will release the spinlock */ | 1777 | __nfs_access_zap_cache(NFS_I(inode), &head); |
1761 | __nfs_access_zap_cache(inode); | 1778 | spin_unlock(&inode->i_lock); |
1779 | spin_unlock(&nfs_access_lru_lock); | ||
1780 | nfs_access_free_list(&head); | ||
1762 | } | 1781 | } |
1763 | 1782 | ||
1764 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) | 1783 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) |
@@ -1809,8 +1828,8 @@ out_stale: | |||
1809 | nfs_access_free_entry(cache); | 1828 | nfs_access_free_entry(cache); |
1810 | return -ENOENT; | 1829 | return -ENOENT; |
1811 | out_zap: | 1830 | out_zap: |
1812 | /* This will release the spinlock */ | 1831 | spin_unlock(&inode->i_lock); |
1813 | __nfs_access_zap_cache(inode); | 1832 | nfs_access_zap_cache(inode); |
1814 | return -ENOENT; | 1833 | return -ENOENT; |
1815 | } | 1834 | } |
1816 | 1835 | ||
@@ -1865,9 +1884,11 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
1865 | smp_mb__after_atomic_inc(); | 1884 | smp_mb__after_atomic_inc(); |
1866 | 1885 | ||
1867 | /* Add inode to global LRU list */ | 1886 | /* Add inode to global LRU list */ |
1868 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1887 | if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
1869 | spin_lock(&nfs_access_lru_lock); | 1888 | spin_lock(&nfs_access_lru_lock); |
1870 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | 1889 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
1890 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, | ||
1891 | &nfs_access_lru_list); | ||
1871 | spin_unlock(&nfs_access_lru_lock); | 1892 | spin_unlock(&nfs_access_lru_lock); |
1872 | } | 1893 | } |
1873 | } | 1894 | } |