]> err.no Git - linux-2.6/blobdiff - fs/nfsd/vfs.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / fs / nfsd / vfs.c
index da3ec74d8a437f24296132fde3e52e8d5df23867..1141bd29e4e3ee3b6f3b9711ace4d7323e42bd5d 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/nfsd_idmap.h>
 #include <linux/security.h>
 #endif /* CONFIG_NFSD_V4 */
+#include <linux/jhash.h>
 
 #include <asm/uaccess.h>
 
@@ -81,10 +82,19 @@ struct raparms {
        dev_t                   p_dev;
        int                     p_set;
        struct file_ra_state    p_ra;
+       unsigned int            p_hindex;
 };
 
+struct raparm_hbucket {
+       struct raparms          *pb_head;
+       spinlock_t              pb_lock;
+} ____cacheline_aligned_in_smp;
+
 static struct raparms *                raparml;
-static struct raparms *                raparm_cache;
+#define RAPARM_HASH_BITS       4
+#define RAPARM_HASH_SIZE       (1<<RAPARM_HASH_BITS)
+#define RAPARM_HASH_MASK       (RAPARM_HASH_SIZE-1)
+static struct raparm_hbucket   raparm_hash[RAPARM_HASH_SIZE];
 
 /* 
  * 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,
        } else if (error < 0)
                goto out_nfserr;
 
-       if (pacl) {
-               error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
-               if (error < 0)
-                       goto out_nfserr;
-       }
+       error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+       if (error < 0)
+               goto out_nfserr;
 
-       if (dpacl) {
+       if (S_ISDIR(inode->i_mode)) {
                error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
                if (error < 0)
                        goto out_nfserr;
@@ -672,7 +680,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                goto out_nfserr;
 
        if (access & MAY_WRITE) {
-               flags = O_WRONLY|O_LARGEFILE;
+               if (access & MAY_READ)
+                       flags = O_RDWR|O_LARGEFILE;
+               else
+                       flags = O_WRONLY|O_LARGEFILE;
 
                DQUOT_INIT(inode);
        }
@@ -740,16 +751,20 @@ nfsd_sync_dir(struct dentry *dp)
  * Obtain the readahead parameters for the file
  * specified by (dev, ino).
  */
-static DEFINE_SPINLOCK(ra_lock);
 
 static inline struct raparms *
 nfsd_get_raparms(dev_t dev, ino_t ino)
 {
        struct raparms  *ra, **rap, **frap = NULL;
        int depth = 0;
+       unsigned int hash;
+       struct raparm_hbucket *rab;
+
+       hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
+       rab = &raparm_hash[hash];
 
-       spin_lock(&ra_lock);
-       for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
+       spin_lock(&rab->pb_lock);
+       for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
                if (ra->p_ino == ino && ra->p_dev == dev)
                        goto found;
                depth++;
@@ -758,7 +773,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
        }
        depth = nfsdstats.ra_size*11/10;
        if (!frap) {    
-               spin_unlock(&ra_lock);
+               spin_unlock(&rab->pb_lock);
                return NULL;
        }
        rap = frap;
@@ -766,15 +781,16 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
        ra->p_dev = dev;
        ra->p_ino = ino;
        ra->p_set = 0;
+       ra->p_hindex = hash;
 found:
-       if (rap != &raparm_cache) {
+       if (rap != &rab->pb_head) {
                *rap = ra->p_next;
-               ra->p_next   = raparm_cache;
-               raparm_cache = ra;
+               ra->p_next   = rab->pb_head;
+               rab->pb_head = ra;
        }
        ra->p_count++;
        nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
-       spin_unlock(&ra_lock);
+       spin_unlock(&rab->pb_lock);
        return ra;
 }
 
@@ -788,22 +804,26 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
 {
        unsigned long count = desc->count;
        struct svc_rqst *rqstp = desc->arg.data;
+       struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
 
        if (size > count)
                size = count;
 
        if (rqstp->rq_res.page_len == 0) {
                get_page(page);
-               rqstp->rq_respages[rqstp->rq_resused++] = page;
+               put_page(*pp);
+               *pp = page;
+               rqstp->rq_resused++;
                rqstp->rq_res.page_base = offset;
                rqstp->rq_res.page_len = size;
-       } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
+       } else if (page != pp[-1]) {
                get_page(page);
-               rqstp->rq_respages[rqstp->rq_resused++] = page;
+               put_page(*pp);
+               *pp = page;
+               rqstp->rq_resused++;
                rqstp->rq_res.page_len += size;
-       } else {
+       } else
                rqstp->rq_res.page_len += size;
-       }
 
        desc->count = count - size;
        desc->written += size;
@@ -833,8 +853,8 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        if (ra && ra->p_set)
                file->f_ra = ra->p_ra;
 
-       if (file->f_op->sendfile) {
-               svc_pushback_unused_pages(rqstp);
+       if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
+               rqstp->rq_resused = 1;
                err = file->f_op->sendfile(file, &offset, *count,
                                                 nfsd_read_actor, rqstp);
        } else {
@@ -846,11 +866,12 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 
        /* Write back readahead params */
        if (ra) {
-               spin_lock(&ra_lock);
+               struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
+               spin_lock(&rab->pb_lock);
                ra->p_ra = file->f_ra;
                ra->p_set = 1;
                ra->p_count--;
-               spin_unlock(&ra_lock);
+               spin_unlock(&rab->pb_lock);
        }
 
        if (err >= 0) {
@@ -1111,7 +1132,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
         */
        if (!resfhp->fh_dentry) {
                /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
-               fh_lock(fhp);
+               fh_lock_nested(fhp, I_MUTEX_PARENT);
                dchild = lookup_one_len(fname, dentry, flen);
                err = PTR_ERR(dchild);
                if (IS_ERR(dchild))
@@ -1237,7 +1258,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
        err = nfserr_notdir;
        if(!dirp->i_op || !dirp->i_op->lookup)
                goto out;
-       fh_lock(fhp);
+       fh_lock_nested(fhp, I_MUTEX_PARENT);
 
        /*
         * Compose the response file handle.
@@ -1491,7 +1512,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
        if (isdotent(name, len))
                goto out;
 
-       fh_lock(ffhp);
+       fh_lock_nested(ffhp, I_MUTEX_PARENT);
        ddir = ffhp->fh_dentry;
        dirp = ddir->d_inode;
 
@@ -1516,14 +1537,15 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                        err = nfserrno(err);
        }
 
-       fh_unlock(ffhp);
        dput(dnew);
+out_unlock:
+       fh_unlock(ffhp);
 out:
        return err;
 
 out_nfserr:
        err = nfserrno(err);
-       goto out;
+       goto out_unlock;
 }
 
 /*
@@ -1552,7 +1574,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        tdir = tdentry->d_inode;
 
        err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
-       if (fdir->i_sb != tdir->i_sb)
+       if (ffhp->fh_export != tfhp->fh_export)
                goto out;
 
        err = nfserr_perm;
@@ -1640,7 +1662,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (err)
                goto out;
 
-       fh_lock(fhp);
+       fh_lock_nested(fhp, I_MUTEX_PARENT);
        dentry = fhp->fh_dentry;
        dirp = dentry->d_inode;
 
@@ -1825,11 +1847,11 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
 void
 nfsd_racache_shutdown(void)
 {
-       if (!raparm_cache)
+       if (!raparml)
                return;
        dprintk("nfsd: freeing readahead buffers.\n");
        kfree(raparml);
-       raparm_cache = raparml = NULL;
+       raparml = NULL;
 }
 /*
  * Initialize readahead param cache
@@ -1838,19 +1860,31 @@ int
 nfsd_racache_init(int cache_size)
 {
        int     i;
+       int     j = 0;
+       int     nperbucket;
 
-       if (raparm_cache)
+
+       if (raparml)
                return 0;
+       if (cache_size < 2*RAPARM_HASH_SIZE)
+               cache_size = 2*RAPARM_HASH_SIZE;
        raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);
 
        if (raparml != NULL) {
                dprintk("nfsd: allocating %d readahead buffers.\n",
                        cache_size);
+               for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
+                       raparm_hash[i].pb_head = NULL;
+                       spin_lock_init(&raparm_hash[i].pb_lock);
+               }
+               nperbucket = cache_size >> RAPARM_HASH_BITS;
                memset(raparml, 0, sizeof(struct raparms) * cache_size);
                for (i = 0; i < cache_size - 1; i++) {
-                       raparml[i].p_next = raparml + i + 1;
+                       if (i % nperbucket == 0)
+                               raparm_hash[j++].pb_head = raparml + i;
+                       if (i % nperbucket < nperbucket-1)
+                               raparml[i].p_next = raparml + i + 1;
                }
-               raparm_cache = raparml;
        } else {
                printk(KERN_WARNING
                       "nfsd: Could not allocate memory read-ahead cache.\n");