Merge branch 'nfs-for-2.6.32' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6...
authorJ. Bruce Fields <bfields@citi.umich.edu>
Fri, 21 Aug 2009 15:27:29 +0000 (11:27 -0400)
committerJ. Bruce Fields <bfields@citi.umich.edu>
Fri, 21 Aug 2009 15:27:29 +0000 (11:27 -0400)
Conflicts:
net/sunrpc/cache.c

14 files changed:
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfssvc.c
include/linux/nfs4.h
include/linux/nfsd/nfsd.h
include/linux/nfsd/state.h
include/linux/nfsd/xdr4.h
include/linux/sunrpc/svc.h
net/sunrpc/cache.c
net/sunrpc/svcauth_unix.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/svc_rdma_transport.c

index 7c88017..6fde431 100644 (file)
@@ -123,6 +123,35 @@ nfsd4_check_open_attributes(struct svc_rqst *rqstp,
        return status;
 }
 
+static int
+is_create_with_attrs(struct nfsd4_open *open)
+{
+       return open->op_create == NFS4_OPEN_CREATE
+               && (open->op_createmode == NFS4_CREATE_UNCHECKED
+                   || open->op_createmode == NFS4_CREATE_GUARDED
+                   || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
+}
+
+/*
+ * if error occurs when setting the acl, just clear the acl bit
+ * in the returned attr bitmap.
+ */
+static void
+do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct nfs4_acl *acl, u32 *bmval)
+{
+       __be32 status;
+
+       status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
+       if (status)
+               /*
+                * We should probably fail the whole open at this point,
+                * but we've already created the file, so it's too late;
+                * So this seems the least of evils:
+                */
+               bmval[0] &= ~FATTR4_WORD0_ACL;
+}
+
 static inline void
 fh_dup2(struct svc_fh *dst, struct svc_fh *src)
 {
@@ -206,6 +235,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
        if (status)
                goto out;
 
+       if (is_create_with_attrs(open) && open->op_acl != NULL)
+               do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval);
+
        set_change_info(&open->op_cinfo, current_fh);
        fh_dup2(current_fh, &resfh);
 
@@ -536,12 +568,17 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfserr_badtype;
        }
 
-       if (!status) {
-               fh_unlock(&cstate->current_fh);
-               set_change_info(&create->cr_cinfo, &cstate->current_fh);
-               fh_dup2(&cstate->current_fh, &resfh);
-       }
+       if (status)
+               goto out;
 
+       if (create->cr_acl != NULL)
+               do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
+                               create->cr_bmval);
+
+       fh_unlock(&cstate->current_fh);
+       set_change_info(&create->cr_cinfo, &cstate->current_fh);
+       fh_dup2(&cstate->current_fh, &resfh);
+out:
        fh_put(&resfh);
        return status;
 }
@@ -947,34 +984,6 @@ static struct nfsd4_operation nfsd4_ops[];
 static const char *nfsd4_op_name(unsigned opnum);
 
 /*
- * This is a replay of a compound for which no cache entry pages
- * were used. Encode the sequence operation, and if cachethis is FALSE
- * encode the uncache rep error on the next operation.
- */
-static __be32
-nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args,
-                        struct nfsd4_compoundres *resp)
-{
-       struct nfsd4_op *op;
-
-       dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__,
-               resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
-
-       /* Encode the replayed sequence operation */
-       BUG_ON(resp->opcnt != 1);
-       op = &args->ops[resp->opcnt - 1];
-       nfsd4_encode_operation(resp, op);
-
-       /*return nfserr_retry_uncached_rep in next operation. */
-       if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) {
-               op = &args->ops[resp->opcnt++];
-               op->status = nfserr_retry_uncached_rep;
-               nfsd4_encode_operation(resp, op);
-       }
-       return op->status;
-}
-
-/*
  * Enforce NFSv4.1 COMPOUND ordering rules.
  *
  * TODO:
@@ -1083,13 +1092,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                        BUG_ON(op->status == nfs_ok);
 
 encode_op:
-               /* Only from SEQUENCE or CREATE_SESSION */
+               /* Only from SEQUENCE */
                if (resp->cstate.status == nfserr_replay_cache) {
                        dprintk("%s NFS4.1 replay from cache\n", __func__);
-                       if (nfsd4_not_cached(resp))
-                               status = nfsd4_enc_uncached_replay(args, resp);
-                       else
-                               status = op->status;
+                       status = op->status;
                        goto out;
                }
                if (op->status == nfserr_replay_me) {
index 980a216..9295c4b 100644 (file)
@@ -414,35 +414,34 @@ gen_sessionid(struct nfsd4_session *ses)
 
 /*
  * Give the client the number of slots it requests bound by
- * NFSD_MAX_SLOTS_PER_SESSION and by sv_drc_max_pages.
+ * NFSD_MAX_SLOTS_PER_SESSION and by nfsd_drc_max_mem.
  *
- * If we run out of pages (sv_drc_pages_used == sv_drc_max_pages) we
- * should (up to a point) re-negotiate active sessions and reduce their
- * slot usage to make rooom for new connections. For now we just fail the
- * create session.
+ * If we run out of reserved DRC memory we should (up to a point) re-negotiate
+ * active sessions and reduce their slot usage to make rooom for new
+ * connections. For now we just fail the create session.
  */
 static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan)
 {
-       int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT;
+       int mem;
 
        if (fchan->maxreqs < 1)
                return nfserr_inval;
        else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
                fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
 
-       spin_lock(&nfsd_serv->sv_lock);
-       if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages)
-               np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used;
-       nfsd_serv->sv_drc_pages_used += np;
-       spin_unlock(&nfsd_serv->sv_lock);
+       mem = fchan->maxreqs * NFSD_SLOT_CACHE_SIZE;
 
-       if (np <= 0) {
-               status = nfserr_resource;
-               fchan->maxreqs = 0;
-       } else
-               fchan->maxreqs = np / NFSD_PAGES_PER_SLOT;
+       spin_lock(&nfsd_drc_lock);
+       if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem)
+               mem = ((nfsd_drc_max_mem - nfsd_drc_mem_used) /
+                               NFSD_SLOT_CACHE_SIZE) * NFSD_SLOT_CACHE_SIZE;
+       nfsd_drc_mem_used += mem;
+       spin_unlock(&nfsd_drc_lock);
 
-       return status;
+       fchan->maxreqs = mem / NFSD_SLOT_CACHE_SIZE;
+       if (fchan->maxreqs == 0)
+               return nfserr_resource;
+       return 0;
 }
 
 /*
@@ -466,9 +465,7 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp,
                fchan->maxresp_sz = maxcount;
        session_fchan->maxresp_sz = fchan->maxresp_sz;
 
-       /* Set the max response cached size our default which is
-        * a multiple of PAGE_SIZE and small */
-       session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE;
+       session_fchan->maxresp_cached = NFSD_SLOT_CACHE_SIZE;
        fchan->maxresp_cached = session_fchan->maxresp_cached;
 
        /* Use the client's maxops if possible */
@@ -476,10 +473,6 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp,
                fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND;
        session_fchan->maxops = fchan->maxops;
 
-       /* try to use the client requested number of slots */
-       if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
-               fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
-
        /* FIXME: Error means no more DRC pages so the server should
         * recover pages from existing sessions. For now fail session
         * creation.
@@ -585,6 +578,9 @@ free_session(struct kref *kref)
                struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry;
                nfsd4_release_respages(e->ce_respages, e->ce_resused);
        }
+       spin_lock(&nfsd_drc_lock);
+       nfsd_drc_mem_used -= ses->se_fchannel.maxreqs * NFSD_SLOT_CACHE_SIZE;
+       spin_unlock(&nfsd_drc_lock);
        kfree(ses);
 }
 
@@ -657,8 +653,6 @@ static inline void
 free_client(struct nfs4_client *clp)
 {
        shutdown_callback_client(clp);
-       nfsd4_release_respages(clp->cl_slot.sl_cache_entry.ce_respages,
-                            clp->cl_slot.sl_cache_entry.ce_resused);
        if (clp->cl_cred.cr_group_info)
                put_group_info(clp->cl_cred.cr_group_info);
        kfree(clp->cl_principal);
@@ -1115,6 +1109,36 @@ nfsd41_copy_replay_data(struct nfsd4_compoundres *resp,
 }
 
 /*
+ * Encode the replay sequence operation from the slot values.
+ * If cachethis is FALSE encode the uncached rep error on the next
+ * operation which sets resp->p and increments resp->opcnt for
+ * nfs4svc_encode_compoundres.
+ *
+ */
+static __be32
+nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
+                         struct nfsd4_compoundres *resp)
+{
+       struct nfsd4_op *op;
+       struct nfsd4_slot *slot = resp->cstate.slot;
+
+       dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__,
+               resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);
+
+       /* Encode the replayed sequence operation */
+       op = &args->ops[resp->opcnt - 1];
+       nfsd4_encode_operation(resp, op);
+
+       /* Return nfserr_retry_uncached_rep in next operation. */
+       if (args->opcnt > 1 && slot->sl_cache_entry.ce_cachethis == 0) {
+               op = &args->ops[resp->opcnt++];
+               op->status = nfserr_retry_uncached_rep;
+               nfsd4_encode_operation(resp, op);
+       }
+       return op->status;
+}
+
+/*
  * Keep the first page of the replay. Copy the NFSv4.1 data from the first
  * cached page.  Replace any futher replay pages from the cache.
  */
@@ -1137,10 +1161,12 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
         * session inactivity timer fires and a solo sequence operation
         * is sent (lease renewal).
         */
-       if (seq && nfsd4_not_cached(resp)) {
-               seq->maxslots = resp->cstate.session->se_fchannel.maxreqs;
-               return nfs_ok;
-       }
+       seq->maxslots = resp->cstate.session->se_fchannel.maxreqs;
+
+       /* Either returns 0 or nfserr_retry_uncached */
+       status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
+       if (status == nfserr_retry_uncached_rep)
+               return status;
 
        if (!nfsd41_copy_replay_data(resp, entry)) {
                /*
@@ -1297,12 +1323,11 @@ out_copy:
        exid->clientid.cl_boot = new->cl_clientid.cl_boot;
        exid->clientid.cl_id = new->cl_clientid.cl_id;
 
-       new->cl_slot.sl_seqid = 0;
        exid->seqid = 1;
        nfsd4_set_ex_flags(new, exid);
 
        dprintk("nfsd4_exchange_id seqid %d flags %x\n",
-               new->cl_slot.sl_seqid, new->cl_exchange_flags);
+               new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
        status = nfs_ok;
 
 out:
@@ -1313,40 +1338,60 @@ error:
 }
 
 static int
-check_slot_seqid(u32 seqid, struct nfsd4_slot *slot)
+check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
 {
-       dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid,
-               slot->sl_seqid);
+       dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
+               slot_seqid);
 
        /* The slot is in use, and no response has been sent. */
-       if (slot->sl_inuse) {
-               if (seqid == slot->sl_seqid)
+       if (slot_inuse) {
+               if (seqid == slot_seqid)
                        return nfserr_jukebox;
                else
                        return nfserr_seq_misordered;
        }
        /* Normal */
-       if (likely(seqid == slot->sl_seqid + 1))
+       if (likely(seqid == slot_seqid + 1))
                return nfs_ok;
        /* Replay */
-       if (seqid == slot->sl_seqid)
+       if (seqid == slot_seqid)
                return nfserr_replay_cache;
        /* Wraparound */
-       if (seqid == 1 && (slot->sl_seqid + 1) == 0)
+       if (seqid == 1 && (slot_seqid + 1) == 0)
                return nfs_ok;
        /* Misordered replay or misordered new request */
        return nfserr_seq_misordered;
 }
 
+/*
+ * Cache the create session result into the create session single DRC
+ * slot cache by saving the xdr structure. sl_seqid has been set.
+ * Do this for solo or embedded create session operations.
+ */
+static void
+nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
+                          struct nfsd4_clid_slot *slot, int nfserr)
+{
+       slot->sl_status = nfserr;
+       memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
+}
+
+static __be32
+nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
+                           struct nfsd4_clid_slot *slot)
+{
+       memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
+       return slot->sl_status;
+}
+
 __be32
 nfsd4_create_session(struct svc_rqst *rqstp,
                     struct nfsd4_compound_state *cstate,
                     struct nfsd4_create_session *cr_ses)
 {
        u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr;
-       struct nfsd4_compoundres *resp = rqstp->rq_resp;
        struct nfs4_client *conf, *unconf;
-       struct nfsd4_slot *slot = NULL;
+       struct nfsd4_clid_slot *cs_slot = NULL;
        int status = 0;
 
        nfs4_lock_state();
@@ -1354,24 +1399,22 @@ nfsd4_create_session(struct svc_rqst *rqstp,
        conf = find_confirmed_client(&cr_ses->clientid);
 
        if (conf) {
-               slot = &conf->cl_slot;
-               status = check_slot_seqid(cr_ses->seqid, slot);
+               cs_slot = &conf->cl_cs_slot;
+               status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status == nfserr_replay_cache) {
                        dprintk("Got a create_session replay! seqid= %d\n",
-                               slot->sl_seqid);
-                       cstate->slot = slot;
-                       cstate->status = status;
+                               cs_slot->sl_seqid);
                        /* Return the cached reply status */
-                       status = nfsd4_replay_cache_entry(resp, NULL);
+                       status = nfsd4_replay_create_session(cr_ses, cs_slot);
                        goto out;
-               } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) {
+               } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
                        status = nfserr_seq_misordered;
                        dprintk("Sequence misordered!\n");
                        dprintk("Expected seqid= %d but got seqid= %d\n",
-                               slot->sl_seqid, cr_ses->seqid);
+                               cs_slot->sl_seqid, cr_ses->seqid);
                        goto out;
                }
-               conf->cl_slot.sl_seqid++;
+               cs_slot->sl_seqid++;
        } else if (unconf) {
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
                    (ip_addr != unconf->cl_addr)) {
@@ -1379,15 +1422,15 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                        goto out;
                }
 
-               slot = &unconf->cl_slot;
-               status = check_slot_seqid(cr_ses->seqid, slot);
+               cs_slot = &unconf->cl_cs_slot;
+               status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
                if (status) {
                        /* an unconfirmed replay returns misordered */
                        status = nfserr_seq_misordered;
-                       goto out;
+                       goto out_cache;
                }
 
-               slot->sl_seqid++; /* from 0 to 1 */
+               cs_slot->sl_seqid++; /* from 0 to 1 */
                move_to_confirmed(unconf);
 
                /*
@@ -1408,12 +1451,11 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 
        memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data,
               NFS4_MAX_SESSIONID_LEN);
-       cr_ses->seqid = slot->sl_seqid;
+       cr_ses->seqid = cs_slot->sl_seqid;
 
-       slot->sl_inuse = true;
-       cstate->slot = slot;
-       /* Ensure a page is used for the cache */
-       slot->sl_cache_entry.ce_cachethis = 1;
+out_cache:
+       /* cache solo and embedded create sessions under the state lock */
+       nfsd4_cache_create_session(cr_ses, cs_slot, status);
 out:
        nfs4_unlock_state();
        dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -1481,7 +1523,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        slot = &session->se_slots[seq->slotid];
        dprintk("%s: slotid %d\n", __func__, seq->slotid);
 
-       status = check_slot_seqid(seq->seqid, slot);
+       status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse);
        if (status == nfserr_replay_cache) {
                cstate->slot = slot;
                cstate->session = session;
index 2dcc7fe..fdf632b 100644 (file)
@@ -3313,8 +3313,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
                        dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
                        resp->cstate.slot->sl_inuse = 0;
                }
-               if (resp->cstate.session)
-                       nfsd4_put_session(resp->cstate.session);
+               nfsd4_put_session(resp->cstate.session);
        }
        return 1;
 }
index 7e906c5..b764d7d 100644 (file)
@@ -776,10 +776,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
                size -= len;
                mesg += len;
        }
-
-       mutex_unlock(&nfsd_mutex);
-       return (mesg-buf);
-
+       rv = mesg - buf;
 out_free:
        kfree(nthreads);
        mutex_unlock(&nfsd_mutex);
index 492c79b..d68cd05 100644 (file)
@@ -66,6 +66,16 @@ struct timeval                       nfssvc_boot;
 DEFINE_MUTEX(nfsd_mutex);
 struct svc_serv                *nfsd_serv;
 
+/*
+ * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
+ * nfsd_drc_max_pages limits the total amount of memory available for
+ * version 4.1 DRC caches.
+ * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage.
+ */
+spinlock_t     nfsd_drc_lock;
+unsigned int   nfsd_drc_max_mem;
+unsigned int   nfsd_drc_mem_used;
+
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 static struct svc_stat nfsd_acl_svcstats;
 static struct svc_version *    nfsd_acl_version[] = {
@@ -235,13 +245,12 @@ void nfsd_reset_versions(void)
  */
 static void set_max_drc(void)
 {
-       /* The percent of nr_free_buffer_pages used by the V4.1 server DRC */
-       #define NFSD_DRC_SIZE_SHIFT     7
-       nfsd_serv->sv_drc_max_pages = nr_free_buffer_pages()
-                                               >> NFSD_DRC_SIZE_SHIFT;
-       nfsd_serv->sv_drc_pages_used = 0;
-       dprintk("%s svc_drc_max_pages %u\n", __func__,
-               nfsd_serv->sv_drc_max_pages);
+       #define NFSD_DRC_SIZE_SHIFT     10
+       nfsd_drc_max_mem = (nr_free_buffer_pages()
+                                       >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE;
+       nfsd_drc_mem_used = 0;
+       spin_lock_init(&nfsd_drc_lock);
+       dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem);
 }
 
 int nfsd_create_serv(void)
index bd2eba5..aff924a 100644 (file)
@@ -234,7 +234,7 @@ enum nfs_opnum4 {
 Needs to be updated if more operations are defined in future.*/
 
 #define FIRST_NFS4_OP  OP_ACCESS
-#define LAST_NFS4_OP   OP_RELEASE_LOCKOWNER
+#define LAST_NFS4_OP   OP_RECLAIM_COMPLETE
 
 enum nfsstat4 {
        NFS4_OK = 0,
index 2b49d67..2812ed5 100644 (file)
@@ -56,6 +56,9 @@ extern struct svc_version     nfsd_version2, nfsd_version3,
 extern u32                     nfsd_supported_minorversion;
 extern struct mutex            nfsd_mutex;
 extern struct svc_serv         *nfsd_serv;
+extern spinlock_t              nfsd_drc_lock;
+extern unsigned int            nfsd_drc_max_mem;
+extern unsigned int            nfsd_drc_mem_used;
 
 extern struct seq_operations nfs_exports_op;
 
index 57ab2ed..58bb197 100644 (file)
@@ -96,6 +96,7 @@ struct nfs4_cb_conn {
 #define NFSD_MAX_SLOTS_PER_SESSION     128
 /* Maximum number of pages per slot cache entry */
 #define NFSD_PAGES_PER_SLOT    1
+#define NFSD_SLOT_CACHE_SIZE           PAGE_SIZE
 /* Maximum number of operations per session compound */
 #define NFSD_MAX_OPS_PER_COMPOUND      16
 
@@ -126,6 +127,25 @@ struct nfsd4_channel_attrs {
        u32             rdma_attrs;
 };
 
+struct nfsd4_create_session {
+       clientid_t                      clientid;
+       struct nfs4_sessionid           sessionid;
+       u32                             seqid;
+       u32                             flags;
+       struct nfsd4_channel_attrs      fore_channel;
+       struct nfsd4_channel_attrs      back_channel;
+       u32                             callback_prog;
+       u32                             uid;
+       u32                             gid;
+};
+
+/* The single slot clientid cache structure */
+struct nfsd4_clid_slot {
+       u32                             sl_seqid;
+       __be32                          sl_status;
+       struct nfsd4_create_session     sl_cr_ses;
+};
+
 struct nfsd4_session {
        struct kref             se_ref;
        struct list_head        se_hash;        /* hash by sessionid */
@@ -192,7 +212,7 @@ struct nfs4_client {
 
        /* for nfs41 */
        struct list_head        cl_sessions;
-       struct nfsd4_slot       cl_slot;        /* create_session slot */
+       struct nfsd4_clid_slot  cl_cs_slot;     /* create_session slot */
        u32                     cl_exchange_flags;
        struct nfs4_sessionid   cl_sessionid;
 };
index 2bacf75..5e4beb0 100644 (file)
@@ -366,18 +366,6 @@ struct nfsd4_exchange_id {
        int             spa_how;
 };
 
-struct nfsd4_create_session {
-       clientid_t              clientid;
-       struct nfs4_sessionid   sessionid;
-       u32                     seqid;
-       u32                     flags;
-       struct nfsd4_channel_attrs fore_channel;
-       struct nfsd4_channel_attrs back_channel;
-       u32                     callback_prog;
-       u32                     uid;
-       u32                     gid;
-};
-
 struct nfsd4_sequence {
        struct nfs4_sessionid   sessionid;              /* request/response */
        u32                     seqid;                  /* request/response */
index ea80096..52e8cb0 100644 (file)
@@ -94,8 +94,6 @@ struct svc_serv {
        struct module *         sv_module;      /* optional module to count when
                                                 * adding threads */
        svc_thread_fn           sv_function;    /* main function for threads */
-       unsigned int            sv_drc_max_pages; /* Total pages for DRC */
-       unsigned int            sv_drc_pages_used;/* DRC pages used */
 #if defined(CONFIG_NFS_V4_1)
        struct list_head        sv_cb_list;     /* queue for callback requests
                                                 * that arrive over the same
index 45cdaff..ade8a7e 100644 (file)
@@ -103,7 +103,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
 EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
 
 
-static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
+static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
 
 static int cache_fresh_locked(struct cache_head *head, time_t expiry)
 {
@@ -119,7 +119,7 @@ static void cache_fresh_unlocked(struct cache_head *head,
                cache_revisit_request(head);
        if (test_and_clear_bit(CACHE_PENDING, &head->flags)) {
                cache_revisit_request(head);
-               queue_loose(detail, head);
+               cache_dequeue(detail, head);
        }
 }
 
@@ -184,6 +184,22 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
        return cd->cache_upcall(cd, h);
 }
 
+static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h)
+{
+       if (!test_bit(CACHE_VALID, &h->flags) ||
+           h->expiry_time < get_seconds())
+               return -EAGAIN;
+       else if (detail->flush_time > h->last_refresh)
+               return -EAGAIN;
+       else {
+               /* entry is valid */
+               if (test_bit(CACHE_NEGATIVE, &h->flags))
+                       return -ENOENT;
+               else
+                       return 0;
+       }
+}
+
 /*
  * This is the generic cache management routine for all
  * the authentication caches.
@@ -192,8 +208,10 @@ static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
  *
  *
  * Returns 0 if the cache_head can be used, or cache_puts it and returns
- * -EAGAIN if upcall is pending,
- * -ETIMEDOUT if upcall failed and should be retried,
+ * -EAGAIN if upcall is pending and request has been queued
+ * -ETIMEDOUT if upcall failed or request could not be queue or
+ *           upcall completed but item is still invalid (implying that
+ *           the cache item has been replaced with a newer one).
  * -ENOENT if cache entry was negative
  */
 int cache_check(struct cache_detail *detail,
@@ -203,17 +221,7 @@ int cache_check(struct cache_detail *detail,
        long refresh_age, age;
 
        /* First decide return status as best we can */
-       if (!test_bit(CACHE_VALID, &h->flags) ||
-           h->expiry_time < get_seconds())
-               rv = -EAGAIN;
-       else if (detail->flush_time > h->last_refresh)
-               rv = -EAGAIN;
-       else {
-               /* entry is valid */
-               if (test_bit(CACHE_NEGATIVE, &h->flags))
-                       rv = -ENOENT;
-               else rv = 0;
-       }
+       rv = cache_is_valid(detail, h);
 
        /* now see if we want to start an upcall */
        refresh_age = (h->expiry_time - h->last_refresh);
@@ -229,6 +237,7 @@ int cache_check(struct cache_detail *detail,
                        switch (cache_make_upcall(detail, h)) {
                        case -EINVAL:
                                clear_bit(CACHE_PENDING, &h->flags);
+                               cache_revisit_request(h);
                                if (rv == -EAGAIN) {
                                        set_bit(CACHE_NEGATIVE, &h->flags);
                                        cache_fresh_unlocked(h, detail,
@@ -245,10 +254,14 @@ int cache_check(struct cache_detail *detail,
                }
        }
 
-       if (rv == -EAGAIN)
-               if (cache_defer_req(rqstp, h) != 0)
-                       rv = -ETIMEDOUT;
-
+       if (rv == -EAGAIN) {
+               if (cache_defer_req(rqstp, h) == 0) {
+                       /* Request is not deferred */
+                       rv = cache_is_valid(detail, h);
+                       if (rv == -EAGAIN)
+                               rv = -ETIMEDOUT;
+               }
+       }
        if (rv)
                cache_put(h, detail);
        return rv;
@@ -396,7 +409,7 @@ static int cache_clean(void)
                                )
                                continue;
                        if (test_and_clear_bit(CACHE_PENDING, &ch->flags))
-                               queue_loose(current_detail, ch);
+                               cache_dequeue(current_detail, ch);
 
                        if (atomic_read(&ch->ref.refcount) == 1)
                                break;
@@ -412,8 +425,10 @@ static int cache_clean(void)
                if (!ch)
                        current_index ++;
                spin_unlock(&cache_list_lock);
-               if (ch)
+               if (ch) {
+                       cache_revisit_request(ch);
                        cache_put(ch, d);
+               }
        } else
                spin_unlock(&cache_list_lock);
 
@@ -496,11 +511,11 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
                 * or continue and drop the oldest below
                 */
                if (net_random()&1)
-                       return -ETIMEDOUT;
+                       return 0;
        }
        dreq = req->defer(req);
        if (dreq == NULL)
-               return -ETIMEDOUT;
+               return 0;
 
        dreq->item = item;
 
@@ -530,8 +545,9 @@ static int cache_defer_req(struct cache_req *req, struct cache_head *item)
        if (!test_bit(CACHE_PENDING, &item->flags)) {
                /* must have just been validated... */
                cache_revisit_request(item);
+               return 0;
        }
-       return 0;
+       return 1;
 }
 
 static void cache_revisit_request(struct cache_head *item)
@@ -887,7 +903,7 @@ static int cache_release(struct inode *inode, struct file *filp,
 
 
 
-static void queue_loose(struct cache_detail *detail, struct cache_head *ch)
+static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch)
 {
        struct cache_queue *cq;
        spin_lock(&queue_lock);
index 6caffa3..117f68a 100644 (file)
@@ -668,6 +668,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
        case 0:
                *gip = ug->gi;
                get_group_info(*gip);
+               cache_put(&ug->h, &unix_gid_cache);
                return 0;
        default:
                return -EAGAIN;
index 23128ee..99a826d 100644 (file)
@@ -432,29 +432,49 @@ static void svc_tcp_write_space(struct sock *sk)
 }
 
 /*
+ * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
+ */
+static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
+                                    struct cmsghdr *cmh)
+{
+       struct in_pktinfo *pki = CMSG_DATA(cmh);
+       if (cmh->cmsg_type != IP_PKTINFO)
+               return 0;
+       rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
+       return 1;
+}
+
+/*
+ * See net/ipv6/datagram.c : datagram_recv_ctl
+ */
+static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
+                                    struct cmsghdr *cmh)
+{
+       struct in6_pktinfo *pki = CMSG_DATA(cmh);
+       if (cmh->cmsg_type != IPV6_PKTINFO)
+               return 0;
+       ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
+       return 1;
+}
+
+/*
  * Copy the UDP datagram's destination address to the rqstp structure.
  * The 'destination' address in this case is the address to which the
  * peer sent the datagram, i.e. our local address. For multihomed
  * hosts, this can change from msg to msg. Note that only the IP
  * address changes, the port number should remain the same.
  */
-static void svc_udp_get_dest_address(struct svc_rqst *rqstp,
-                                    struct cmsghdr *cmh)
+static int svc_udp_get_dest_address(struct svc_rqst *rqstp,
+                                   struct cmsghdr *cmh)
 {
-       struct svc_sock *svsk =
-               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
-       switch (svsk->sk_sk->sk_family) {
-       case AF_INET: {
-               struct in_pktinfo *pki = CMSG_DATA(cmh);
-               rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr;
-               break;
-               }
-       case AF_INET6: {
-               struct in6_pktinfo *pki = CMSG_DATA(cmh);
-               ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr);
-               break;
-               }
+       switch (cmh->cmsg_level) {
+       case SOL_IP:
+               return svc_udp_get_dest_address4(rqstp, cmh);
+       case SOL_IPV6:
+               return svc_udp_get_dest_address6(rqstp, cmh);
        }
+
+       return 0;
 }
 
 /*
@@ -531,16 +551,15 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
 
        rqstp->rq_prot = IPPROTO_UDP;
 
-       if (cmh->cmsg_level != IPPROTO_IP ||
-           cmh->cmsg_type != IP_PKTINFO) {
+       if (!svc_udp_get_dest_address(rqstp, cmh)) {
                if (net_ratelimit())
-                       printk("rpcsvc: received unknown control message:"
-                              "%d/%d\n",
-                              cmh->cmsg_level, cmh->cmsg_type);
+                       printk(KERN_WARNING
+                               "svc: received unknown control message %d/%d; "
+                               "dropping RPC reply datagram\n",
+                                       cmh->cmsg_level, cmh->cmsg_type);
                skb_free_datagram(svsk->sk_sk, skb);
                return 0;
        }
-       svc_udp_get_dest_address(rqstp, cmh);
 
        if (skb_is_nonlinear(skb)) {
                /* we have to copy */
@@ -651,8 +670,7 @@ static struct svc_xprt_class svc_udp_class = {
 
 static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
 {
-       int one = 1;
-       mm_segment_t oldfs;
+       int err, level, optname, one = 1;
 
        svc_xprt_init(&svc_udp_class, &svsk->sk_xprt, serv);
        clear_bit(XPT_CACHE_AUTH, &svsk->sk_xprt.xpt_flags);
@@ -671,12 +689,22 @@ static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv)
        set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
        set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
 
-       oldfs = get_fs();
-       set_fs(KERNEL_DS);
        /* make sure we get destination address info */
-       svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO,
-                                      (char __user *)&one, sizeof(one));
-       set_fs(oldfs);
+       switch (svsk->sk_sk->sk_family) {
+       case AF_INET:
+               level = SOL_IP;
+               optname = IP_PKTINFO;
+               break;
+       case AF_INET6:
+               level = SOL_IPV6;
+               optname = IPV6_RECVPKTINFO;
+               break;
+       default:
+               BUG();
+       }
+       err = kernel_setsockopt(svsk->sk_sock, level, optname,
+                                       (char *)&one, sizeof(one));
+       dprintk("svc: kernel_setsockopt returned %d\n", err);
 }
 
 /*
index 5151f9f..0cf5e8c 100644 (file)
@@ -730,12 +730,12 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
                goto err;
 
        mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
-       if (!mr)
+       if (IS_ERR(mr))
                goto err_free_frmr;
 
        pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
                                         RPCSVC_MAXPAGES);
-       if (!pl)
+       if (IS_ERR(pl))
                goto err_free_mr;
 
        frmr->mr = mr;