diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 86 |
1 files changed, 58 insertions, 28 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 443ebc52e382..1141bd29e4e3 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/nfsd_idmap.h> | 54 | #include <linux/nfsd_idmap.h> |
55 | #include <linux/security.h> | 55 | #include <linux/security.h> |
56 | #endif /* CONFIG_NFSD_V4 */ | 56 | #endif /* CONFIG_NFSD_V4 */ |
57 | #include <linux/jhash.h> | ||
57 | 58 | ||
58 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
59 | 60 | ||
@@ -81,10 +82,19 @@ struct raparms { | |||
81 | dev_t p_dev; | 82 | dev_t p_dev; |
82 | int p_set; | 83 | int p_set; |
83 | struct file_ra_state p_ra; | 84 | struct file_ra_state p_ra; |
85 | unsigned int p_hindex; | ||
84 | }; | 86 | }; |
85 | 87 | ||
88 | struct raparm_hbucket { | ||
89 | struct raparms *pb_head; | ||
90 | spinlock_t pb_lock; | ||
91 | } ____cacheline_aligned_in_smp; | ||
92 | |||
86 | static struct raparms * raparml; | 93 | static struct raparms * raparml; |
87 | static struct raparms * raparm_cache; | 94 | #define RAPARM_HASH_BITS 4 |
95 | #define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS) | ||
96 | #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) | ||
97 | static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; | ||
88 | 98 | ||
89 | /* | 99 | /* |
90 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed | 100 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed |
@@ -437,13 +447,11 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
437 | } else if (error < 0) | 447 | } else if (error < 0) |
438 | goto out_nfserr; | 448 | goto out_nfserr; |
439 | 449 | ||
440 | if (pacl) { | 450 | error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); |
441 | error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); | 451 | if (error < 0) |
442 | if (error < 0) | 452 | goto out_nfserr; |
443 | goto out_nfserr; | ||
444 | } | ||
445 | 453 | ||
446 | if (dpacl) { | 454 | if (S_ISDIR(inode->i_mode)) { |
447 | error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); | 455 | error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); |
448 | if (error < 0) | 456 | if (error < 0) |
449 | goto out_nfserr; | 457 | goto out_nfserr; |
@@ -743,16 +751,20 @@ nfsd_sync_dir(struct dentry *dp) | |||
743 | * Obtain the readahead parameters for the file | 751 | * Obtain the readahead parameters for the file |
744 | * specified by (dev, ino). | 752 | * specified by (dev, ino). |
745 | */ | 753 | */ |
746 | static DEFINE_SPINLOCK(ra_lock); | ||
747 | 754 | ||
748 | static inline struct raparms * | 755 | static inline struct raparms * |
749 | nfsd_get_raparms(dev_t dev, ino_t ino) | 756 | nfsd_get_raparms(dev_t dev, ino_t ino) |
750 | { | 757 | { |
751 | struct raparms *ra, **rap, **frap = NULL; | 758 | struct raparms *ra, **rap, **frap = NULL; |
752 | int depth = 0; | 759 | int depth = 0; |
760 | unsigned int hash; | ||
761 | struct raparm_hbucket *rab; | ||
753 | 762 | ||
754 | spin_lock(&ra_lock); | 763 | hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK; |
755 | for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) { | 764 | rab = &raparm_hash[hash]; |
765 | |||
766 | spin_lock(&rab->pb_lock); | ||
767 | for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) { | ||
756 | if (ra->p_ino == ino && ra->p_dev == dev) | 768 | if (ra->p_ino == ino && ra->p_dev == dev) |
757 | goto found; | 769 | goto found; |
758 | depth++; | 770 | depth++; |
@@ -761,7 +773,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino) | |||
761 | } | 773 | } |
762 | depth = nfsdstats.ra_size*11/10; | 774 | depth = nfsdstats.ra_size*11/10; |
763 | if (!frap) { | 775 | if (!frap) { |
764 | spin_unlock(&ra_lock); | 776 | spin_unlock(&rab->pb_lock); |
765 | return NULL; | 777 | return NULL; |
766 | } | 778 | } |
767 | rap = frap; | 779 | rap = frap; |
@@ -769,15 +781,16 @@ nfsd_get_raparms(dev_t dev, ino_t ino) | |||
769 | ra->p_dev = dev; | 781 | ra->p_dev = dev; |
770 | ra->p_ino = ino; | 782 | ra->p_ino = ino; |
771 | ra->p_set = 0; | 783 | ra->p_set = 0; |
784 | ra->p_hindex = hash; | ||
772 | found: | 785 | found: |
773 | if (rap != &raparm_cache) { | 786 | if (rap != &rab->pb_head) { |
774 | *rap = ra->p_next; | 787 | *rap = ra->p_next; |
775 | ra->p_next = raparm_cache; | 788 | ra->p_next = rab->pb_head; |
776 | raparm_cache = ra; | 789 | rab->pb_head = ra; |
777 | } | 790 | } |
778 | ra->p_count++; | 791 | ra->p_count++; |
779 | nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; | 792 | nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; |
780 | spin_unlock(&ra_lock); | 793 | spin_unlock(&rab->pb_lock); |
781 | return ra; | 794 | return ra; |
782 | } | 795 | } |
783 | 796 | ||
@@ -791,22 +804,26 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset | |||
791 | { | 804 | { |
792 | unsigned long count = desc->count; | 805 | unsigned long count = desc->count; |
793 | struct svc_rqst *rqstp = desc->arg.data; | 806 | struct svc_rqst *rqstp = desc->arg.data; |
807 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; | ||
794 | 808 | ||
795 | if (size > count) | 809 | if (size > count) |
796 | size = count; | 810 | size = count; |
797 | 811 | ||
798 | if (rqstp->rq_res.page_len == 0) { | 812 | if (rqstp->rq_res.page_len == 0) { |
799 | get_page(page); | 813 | get_page(page); |
800 | rqstp->rq_respages[rqstp->rq_resused++] = page; | 814 | put_page(*pp); |
815 | *pp = page; | ||
816 | rqstp->rq_resused++; | ||
801 | rqstp->rq_res.page_base = offset; | 817 | rqstp->rq_res.page_base = offset; |
802 | rqstp->rq_res.page_len = size; | 818 | rqstp->rq_res.page_len = size; |
803 | } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) { | 819 | } else if (page != pp[-1]) { |
804 | get_page(page); | 820 | get_page(page); |
805 | rqstp->rq_respages[rqstp->rq_resused++] = page; | 821 | put_page(*pp); |
822 | *pp = page; | ||
823 | rqstp->rq_resused++; | ||
806 | rqstp->rq_res.page_len += size; | 824 | rqstp->rq_res.page_len += size; |
807 | } else { | 825 | } else |
808 | rqstp->rq_res.page_len += size; | 826 | rqstp->rq_res.page_len += size; |
809 | } | ||
810 | 827 | ||
811 | desc->count = count - size; | 828 | desc->count = count - size; |
812 | desc->written += size; | 829 | desc->written += size; |
@@ -837,7 +854,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
837 | file->f_ra = ra->p_ra; | 854 | file->f_ra = ra->p_ra; |
838 | 855 | ||
839 | if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { | 856 | if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { |
840 | svc_pushback_unused_pages(rqstp); | 857 | rqstp->rq_resused = 1; |
841 | err = file->f_op->sendfile(file, &offset, *count, | 858 | err = file->f_op->sendfile(file, &offset, *count, |
842 | nfsd_read_actor, rqstp); | 859 | nfsd_read_actor, rqstp); |
843 | } else { | 860 | } else { |
@@ -849,11 +866,12 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
849 | 866 | ||
850 | /* Write back readahead params */ | 867 | /* Write back readahead params */ |
851 | if (ra) { | 868 | if (ra) { |
852 | spin_lock(&ra_lock); | 869 | struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; |
870 | spin_lock(&rab->pb_lock); | ||
853 | ra->p_ra = file->f_ra; | 871 | ra->p_ra = file->f_ra; |
854 | ra->p_set = 1; | 872 | ra->p_set = 1; |
855 | ra->p_count--; | 873 | ra->p_count--; |
856 | spin_unlock(&ra_lock); | 874 | spin_unlock(&rab->pb_lock); |
857 | } | 875 | } |
858 | 876 | ||
859 | if (err >= 0) { | 877 | if (err >= 0) { |
@@ -1829,11 +1847,11 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | |||
1829 | void | 1847 | void |
1830 | nfsd_racache_shutdown(void) | 1848 | nfsd_racache_shutdown(void) |
1831 | { | 1849 | { |
1832 | if (!raparm_cache) | 1850 | if (!raparml) |
1833 | return; | 1851 | return; |
1834 | dprintk("nfsd: freeing readahead buffers.\n"); | 1852 | dprintk("nfsd: freeing readahead buffers.\n"); |
1835 | kfree(raparml); | 1853 | kfree(raparml); |
1836 | raparm_cache = raparml = NULL; | 1854 | raparml = NULL; |
1837 | } | 1855 | } |
1838 | /* | 1856 | /* |
1839 | * Initialize readahead param cache | 1857 | * Initialize readahead param cache |
@@ -1842,19 +1860,31 @@ int | |||
1842 | nfsd_racache_init(int cache_size) | 1860 | nfsd_racache_init(int cache_size) |
1843 | { | 1861 | { |
1844 | int i; | 1862 | int i; |
1863 | int j = 0; | ||
1864 | int nperbucket; | ||
1865 | |||
1845 | 1866 | ||
1846 | if (raparm_cache) | 1867 | if (raparml) |
1847 | return 0; | 1868 | return 0; |
1869 | if (cache_size < 2*RAPARM_HASH_SIZE) | ||
1870 | cache_size = 2*RAPARM_HASH_SIZE; | ||
1848 | raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL); | 1871 | raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL); |
1849 | 1872 | ||
1850 | if (raparml != NULL) { | 1873 | if (raparml != NULL) { |
1851 | dprintk("nfsd: allocating %d readahead buffers.\n", | 1874 | dprintk("nfsd: allocating %d readahead buffers.\n", |
1852 | cache_size); | 1875 | cache_size); |
1876 | for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) { | ||
1877 | raparm_hash[i].pb_head = NULL; | ||
1878 | spin_lock_init(&raparm_hash[i].pb_lock); | ||
1879 | } | ||
1880 | nperbucket = cache_size >> RAPARM_HASH_BITS; | ||
1853 | memset(raparml, 0, sizeof(struct raparms) * cache_size); | 1881 | memset(raparml, 0, sizeof(struct raparms) * cache_size); |
1854 | for (i = 0; i < cache_size - 1; i++) { | 1882 | for (i = 0; i < cache_size - 1; i++) { |
1855 | raparml[i].p_next = raparml + i + 1; | 1883 | if (i % nperbucket == 0) |
1884 | raparm_hash[j++].pb_head = raparml + i; | ||
1885 | if (i % nperbucket < nperbucket-1) | ||
1886 | raparml[i].p_next = raparml + i + 1; | ||
1856 | } | 1887 | } |
1857 | raparm_cache = raparml; | ||
1858 | } else { | 1888 | } else { |
1859 | printk(KERN_WARNING | 1889 | printk(KERN_WARNING |
1860 | "nfsd: Could not allocate memory read-ahead cache.\n"); | 1890 | "nfsd: Could not allocate memory read-ahead cache.\n"); |