Merge branch 'for-2.6.39' of git://linux-nfs.org/~bfields/linux
[pandora-kernel.git] / fs / nfsd / nfs4state.c
index 7b566ec..aa309aa 100644 (file)
@@ -148,7 +148,7 @@ static struct list_head     ownerstr_hashtbl[OWNER_HASH_SIZE];
 /* hash table for nfs4_file */
 #define FILE_HASH_BITS                   8
 #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
-#define FILE_HASH_MASK                  (FILE_HASH_SIZE - 1)
+
 /* hash table for (open)nfs4_stateid */
 #define STATEID_HASH_BITS              10
 #define STATEID_HASH_SIZE              (1 << STATEID_HASH_BITS)
@@ -316,64 +316,6 @@ static struct list_head    unconf_id_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head client_lru;
 static struct list_head close_lru;
 
-static void unhash_generic_stateid(struct nfs4_stateid *stp)
-{
-       list_del(&stp->st_hash);
-       list_del(&stp->st_perfile);
-       list_del(&stp->st_perstateowner);
-}
-
-static void free_generic_stateid(struct nfs4_stateid *stp)
-{
-       put_nfs4_file(stp->st_file);
-       kmem_cache_free(stateid_slab, stp);
-}
-
-static void release_lock_stateid(struct nfs4_stateid *stp)
-{
-       struct file *file;
-
-       unhash_generic_stateid(stp);
-       file = find_any_file(stp->st_file);
-       if (file)
-               locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
-       free_generic_stateid(stp);
-}
-
-static void unhash_lockowner(struct nfs4_stateowner *sop)
-{
-       struct nfs4_stateid *stp;
-
-       list_del(&sop->so_idhash);
-       list_del(&sop->so_strhash);
-       list_del(&sop->so_perstateid);
-       while (!list_empty(&sop->so_stateids)) {
-               stp = list_first_entry(&sop->so_stateids,
-                               struct nfs4_stateid, st_perstateowner);
-               release_lock_stateid(stp);
-       }
-}
-
-static void release_lockowner(struct nfs4_stateowner *sop)
-{
-       unhash_lockowner(sop);
-       nfs4_put_stateowner(sop);
-}
-
-static void
-release_stateid_lockowners(struct nfs4_stateid *open_stp)
-{
-       struct nfs4_stateowner *lock_sop;
-
-       while (!list_empty(&open_stp->st_lockowners)) {
-               lock_sop = list_entry(open_stp->st_lockowners.next,
-                               struct nfs4_stateowner, so_perstateid);
-               /* list_del(&open_stp->st_lockowners);  */
-               BUG_ON(lock_sop->so_is_open_owner);
-               release_lockowner(lock_sop);
-       }
-}
-
 /*
  * We store the NONE, READ, WRITE, and BOTH bits separately in the
  * st_{access,deny}_bmap field of the stateid, in order to track not
@@ -446,13 +388,74 @@ static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
        return nfs4_access_to_omode(access);
 }
 
-static void release_open_stateid(struct nfs4_stateid *stp)
+static void unhash_generic_stateid(struct nfs4_stateid *stp)
 {
-       int oflag = nfs4_access_bmap_to_omode(stp);
+       list_del(&stp->st_hash);
+       list_del(&stp->st_perfile);
+       list_del(&stp->st_perstateowner);
+}
+
+static void free_generic_stateid(struct nfs4_stateid *stp)
+{
+       int oflag;
+
+       if (stp->st_access_bmap) {
+               oflag = nfs4_access_bmap_to_omode(stp);
+               nfs4_file_put_access(stp->st_file, oflag);
+               put_nfs4_file(stp->st_file);
+       }
+       kmem_cache_free(stateid_slab, stp);
+}
+
+static void release_lock_stateid(struct nfs4_stateid *stp)
+{
+       struct file *file;
 
+       unhash_generic_stateid(stp);
+       file = find_any_file(stp->st_file);
+       if (file)
+               locks_remove_posix(file, (fl_owner_t)stp->st_stateowner);
+       free_generic_stateid(stp);
+}
+
+static void unhash_lockowner(struct nfs4_stateowner *sop)
+{
+       struct nfs4_stateid *stp;
+
+       list_del(&sop->so_idhash);
+       list_del(&sop->so_strhash);
+       list_del(&sop->so_perstateid);
+       while (!list_empty(&sop->so_stateids)) {
+               stp = list_first_entry(&sop->so_stateids,
+                               struct nfs4_stateid, st_perstateowner);
+               release_lock_stateid(stp);
+       }
+}
+
+static void release_lockowner(struct nfs4_stateowner *sop)
+{
+       unhash_lockowner(sop);
+       nfs4_put_stateowner(sop);
+}
+
+static void
+release_stateid_lockowners(struct nfs4_stateid *open_stp)
+{
+       struct nfs4_stateowner *lock_sop;
+
+       while (!list_empty(&open_stp->st_lockowners)) {
+               lock_sop = list_entry(open_stp->st_lockowners.next,
+                               struct nfs4_stateowner, so_perstateid);
+               /* list_del(&open_stp->st_lockowners);  */
+               BUG_ON(lock_sop->so_is_open_owner);
+               release_lockowner(lock_sop);
+       }
+}
+
+static void release_open_stateid(struct nfs4_stateid *stp)
+{
        unhash_generic_stateid(stp);
        release_stateid_lockowners(stp);
-       nfs4_file_put_access(stp->st_file, oflag);
        free_generic_stateid(stp);
 }
 
@@ -608,7 +611,8 @@ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4
        u32 maxrpc = nfsd_serv->sv_max_mesg;
 
        new->maxreqs = numslots;
-       new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
+       new->maxresp_cached = min_t(u32, req->maxresp_cached,
+                                       slotsize + NFSD_MIN_HDR_SEQ_SZ);
        new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
        new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
        new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
@@ -3054,7 +3058,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
        if (ONE_STATEID(stateid) && (flags & RD_STATE))
                return nfs_ok;
        else if (locks_in_grace()) {
-               /* Answer in remaining cases depends on existance of
+               /* Answer in remaining cases depends on existence of
                 * conflicting state; so we must wait out the grace period. */
                return nfserr_grace;
        } else if (flags & WR_STATE)
@@ -3674,7 +3678,7 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
 /*
  * Alloc a lock owner structure.
  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
- * occured. 
+ * occurred. 
  *
  * strhashval = lock_ownerstr_hashval 
  */
@@ -3735,6 +3739,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;
+       stp->st_access_bmap = 0;
        stp->st_deny_bmap = open_stp->st_deny_bmap;
        stp->st_openstp = open_stp;
 
@@ -3749,6 +3754,17 @@ check_lock_length(u64 offset, u64 length)
             LOFF_OVERFLOW(offset, length)));
 }
 
+static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access)
+{
+       struct nfs4_file *fp = lock_stp->st_file;
+       int oflag = nfs4_access_to_omode(access);
+
+       if (test_bit(access, &lock_stp->st_access_bmap))
+               return;
+       nfs4_file_get_access(fp, oflag);
+       __set_bit(access, &lock_stp->st_access_bmap);
+}
+
 /*
  *  LOCK operation 
  */
@@ -3765,7 +3781,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file_lock conflock;
        __be32 status = 0;
        unsigned int strhashval;
-       unsigned int cmd;
        int err;
 
        dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
@@ -3847,22 +3862,18 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        switch (lock->lk_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
-                       if (find_readable_file(lock_stp->st_file)) {
-                               nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ);
-                               filp = find_readable_file(lock_stp->st_file);
-                       }
+                       filp = find_readable_file(lock_stp->st_file);
+                       if (filp)
+                               get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
                        file_lock.fl_type = F_RDLCK;
-                       cmd = F_SETLK;
-               break;
+                       break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
-                       if (find_writeable_file(lock_stp->st_file)) {
-                               nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE);
-                               filp = find_writeable_file(lock_stp->st_file);
-                       }
+                       filp = find_writeable_file(lock_stp->st_file);
+                       if (filp)
+                               get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
                        file_lock.fl_type = F_WRLCK;
-                       cmd = F_SETLK;
-               break;
+                       break;
                default:
                        status = nfserr_inval;
                goto out;
@@ -3886,7 +3897,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        * Note: locks.c uses the BKL to protect the inode's lock list.
        */
 
-       err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
+       err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
        switch (-err) {
        case 0: /* success! */
                update_stateid(&lock_stp->st_stateid);