[pnfs] [PATCH 1/2] Slot Table Implementation
Iyer, Rahul
Rahul.Iyer at netapp.com
Mon Mar 19 14:01:46 EDT 2007
Yes, this seems to be a good optimization. I can work on the
optimizations once I have the callback path implemented. I'd rather have
a full featured prototype than an efficient but incomplete one. Does
that sound fine? I've added an issue to the pNFS wiki.
Thanks
Regards
Rahul
> -----Original Message-----
> From: Benny Halevy [mailto:bhalevy at panasas.com]
> Sent: Monday, March 19, 2007 10:48 AM
> To: Iyer, Rahul
> Cc: pnfs at linux-nfs.org
> Subject: Re: [pnfs] [PATCH 1/2] Slot Table Implementation
>
> One more optimization that Brent suggests is keeping a single
> "lowest free slot" index per slot table which would help
> reduce the table scan cost.
>
> When you allocate that slot mark the index as "used".
> When you free a slot that has a lower id, or if the index is
> marked as used, just update that index.
> When you want to allocate a slot and the index is marked as
> used, just scan from there upward until you find the next
> free one and update the index as "used".
>
> Benny
>
> Benny Halevy wrote:
>
> >Hmm, keeping the free list in order has the same O(n) complexity as
> >scanning for the first free slot. We just need a fast way
> to tell if
> >there are any free slots (a list, or a counter) for the queue sleep
> >condition. A single spin_lock for scanning the slot table
> (or for the
> >list) should more efficient than a test_and_set bit per slot (when
> >there's enough load) and so is a single queue rather than a
> queue per
> >slot. The latter is crucial for getting to the first slot
> that becomes
> >available and not waiting on average half the response time in the
> >system.
> >
> >Benny
> >
> >Iyer, Rahul wrote:
> >
> >
> >
> >>Hi Benny,
> >>My first idea was similar to this. That was the reason I had the
> >>unused slots and used slots lists. The reason I abandoned that was
> >>because it would be difficult to get the lowest numbered slot. The
> >>draft suggests that the client should use the lowest
> numbered slot so
> >>that the server can reclaim slots from the client if it
> sees that they
> >>are under-utilized (at least that's what I understand).It is not a
> >>hard requirement, but one that is recommended.
> >>>From draft 10, Section 2.4.10.1, Paragraph 12
> >>"The requester is required to use the lowest available slot when
> >>issuing a new request. This way, the replier may be able to retire
> >>slot entries faster."
> >>
> >>Further, this email exchange adds some more insight:
> >>http://www1.ietf.org/mail-archive/web/nfsv4/current/msg03997.html
> >>
> >>The problem I foresaw with the lists is that keeping the
> lists ordered
> >>is almost as much work as having separate lists. As for the
> atomic_t
> >>variables, I'm not too hot about the atomic variables.
> test_and_set is
> >>a bus locking instruction and so isn't such a great idea... the
> >>spin_locks are "optimized for the fast path", which is getting the
> >>spin_locks, but they're too much of a big hammer maybe.
> rw_locks might
> >>be a better idea, but i'm not 100% convinced... I'm pretty
> sure they
> >>use some sort of bus locking instruction too. As for the current
> >>implementation, scaling shouldn't be too much of a problem as the
> >>number of slots is likely to be small (few tens) and the
> worst case is
> >>bounded. I agree it is linear time, but at least the worst case
> >>doesn't run away from us. Since the RPC slots is a tunable
> parameter,
> >>it would be interesting to see what an "optimal" rpc slot
> count is...
> >>as in at what point does adding more slots make no difference to
> >>performance. Is there such a study?
> >>
> >>Another idea I can think of is to have a single lock that
> protects the
> >>whole slot table. We grab the lock and run down the slot table to
> >>select our slot (and set need_to_sleep if required), and
> then release
> >>the lock. Then, if need_to_sleep is set, we grab the lock,
> increment
> >>nr_waiters for the slot, release the lock and sleep.
> >>Should this be a spin_lock or an rw_lock, I'm not sure...
> spin_locks
> >>will harm the concurrency because it would lock out
> parallel reads. On
> >>the other hand, rw_locks are biased towards readers or writers (not
> >>sure which for Linux), so that may not be a good thing.
> >>
> >>That being said, I'm not wedded to the current
> implementation in any
> >>way... comments and better algorithms are welcome. This was
> just one
> >>way that I thought made sense.
> >>Thanks,
> >>Regards
> >>Rahul
> >>
> >>
> >>-----Original Message-----
> >>From: Benny Halevy [mailto:bhalevy at panasas.com]
> >>Sent: Sat 3/17/2007 3:54 AM
> >>To: Iyer, Rahul
> >>Cc: pnfs at linux-nfs.org
> >>Subject: Re: [pnfs] [PATCH 1/2] Slot Table Implementation
> >>
> >>Rahul, this is not urgent but I really think we should move to a
> >>single queue for several reason. With your implementation when all
> >>slots are used you have to do max_slots test_and_set operations to
> >>discover that. This will just not scale. I agree with your point
> >>about semaphores and renegotiating the number of slots so how about
> >>this (sketch) instead:
> >>
> >>nfs41_proc_sequence_done()
> >>{
> >> int need_wakeup = 0;
> >>
> >> spin_lock(&res->channel->channel_lock);
> >> list_add(&res->slot->slot_list,
> &res->channel->unused_slots);
> >> spin_unlock(&res->channel->channel_lock);
> >>
> >> /* Wake up the threads waiting on this session */
> >> rpc_wake_up(&res->channel->sl_waitq);
> >>
> >> return status;
> >> }
> >>
> >>struct nfs4_slot *nfs4_find_slot(struct nfs4_channel *channel) {
> >> struct nfs4_slot *slot;
> >>
> >> might_sleep();
> >>
> >> for (;;) {
> >> int ret =
> wait_event_interruptible(&channel->sl_waitq,
> >>
> >>!list_empty(&channel->unused_slots));
> >> if (unlikely(ret) {
> >> BUG_ON(ret != -ERESTARTSYS);
> >> break;
> >> }
> >>
> >> spin_lock(&channel->channel_lock);
> >> if (unlikely(list_empty(&channel->unused_slots))) {
> >> spin_unlock(&channel->channel_lock);
> >> continue;
> >> }
> >> slot = list_entry(channel->unused_slots.next,
> >> struct nfs4_slot,
> >> slot_list);
> >> list_del(&slot->slot_list);
> >> spin_unlock(&channel->channel_lock);
> >> return slot;
> >> }
> >>
> >> return NULL;
> >>}
> >>
> >>
> >>Iyer, Rahul wrote:
> >>
> >>
> >>
> >>>Hi Benny,
> >>>A comment inline...
> >>>Regards
> >>>Rahul
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>>-----Original Message-----
> >>>>From: Benny Halevy [mailto:bhalevy at panasas.com]
> >>>>Sent: Friday, March 16, 2007 2:24 AM
> >>>>To: Iyer, Rahul
> >>>>Cc: pnfs at linux-nfs.org
> >>>>Subject: Re: [pnfs] [PATCH 1/2] Slot Table Implementation
> >>>>
> >>>>Rahul, my comments below...
> >>>>
> >>>>Benny
> >>>>
> >>>>iyer at netapp.com wrote:
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>From: iyer <iyer at netapp.com>
> >>>>>
> >>>>>Added code to implement a slot table.
> >>>>>
> >>>>>Signed-off-by: iyer <iyer at netapp.com>
> >>>>>---
> >>>>>fs/nfs/nfs41_sessions.h | 62 --------
> >>>>>fs/nfs/nfs4_fs.h | 2 +-
> >>>>>fs/nfs/nfs4proc.c | 326
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>+++++++++++++++++++++++++++++++++++-----
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>fs/nfs/nfs4xdr.c | 24 ++--
> >>>>>fs/nfs/super.c | 6 +-
> >>>>>include/linux/nfs41_sessions.h | 72 +++++++++
> >>>>>include/linux/nfs_xdr.h | 4 +
> >>>>>include/linux/nfsd/state.h | 2 -
> >>>>>8 files changed, 378 insertions(+), 120 deletions(-) delete mode
> >>>>>100644 fs/nfs/nfs41_sessions.h create mode 100644
> >>>>>include/linux/nfs41_sessions.h
> >>>>>
> >>>>>diff --git a/fs/nfs/nfs41_sessions.h
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>b/fs/nfs/nfs41_sessions.h deleted
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>file mode 100644 index fc658c5..0000000
> >>>>>--- a/fs/nfs/nfs41_sessions.h
> >>>>>+++ /dev/null
> >>>>>@@ -1,62 +0,0 @@
> >>>>>-#ifndef __NFS4_1_SESSIONS_H__
> >>>>>-#define __NFS4_1_SESSIONS_H__
> >>>>>-
> >>>>>-typedef unsigned char sessionid_t[16];
> >>>>>-typedef u32 streamchannel_attrs;
> >>>>>-typedef u32 rdmachannel_attrs;
> >>>>>-
> >>>>>-struct nfs4_channel_attrs {
> >>>>>- unsigned long max_rqst_sz;
> >>>>>- unsigned long max_resp_sz;
> >>>>>- unsigned long max_resp_sz_cached;
> >>>>>- unsigned long max_ops;
> >>>>>- unsigned long max_reqs;
> >>>>>- streamchannel_attrs stream_attrs;
> >>>>>- rdmachannel_attrs rdma_attrs;
> >>>>>-};
> >>>>>-
> >>>>>-struct nfs4_channel {
> >>>>>- struct nfs4_channel_attrs chan_attrs;
> >>>>>- unsigned long nr_conns;
> >>>>>- struct list_head rpc_clients;
> >>>>>-};
> >>>>>-
> >>>>>-struct nfs4_session {
> >>>>>- /* Session related params */
> >>>>>- sessionid_t sess_id;
> >>>>>- u32 seqid; /* The seqid returned
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>by exchange_id */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>- u32 persist;
> >>>>>- u32 header_padding;
> >>>>>- u32 hash_alg;
> >>>>>- u32 ssv_len;
> >>>>>- u32 use_for_back_chan;
> >>>>>- u32 rdma_mode;
> >>>>>-
> >>>>>- /* Slotid management */
> >>>>>- unsigned long nr_slots_in_use;
> >>>>>- struct list_head slots_in_use;
> >>>>>- struct list_head unused_slots;
> >>>>>- struct rpc_wait_queue slot_waitq;
> >>>>>-
> >>>>>- /* The fore and back channel */
> >>>>>- struct nfs4_channel fore_channel;
> >>>>>- struct nfs4_channel back_channel;
> >>>>>-
> >>>>>- unsigned int expired;
> >>>>>- struct nfs4_client * client;
> >>>>>- struct list_head session_hashtbl;
> >>>>>- spinlock_t session_lock;
> >>>>>- /* To prevent races between create_session and sequence */
> >>>>>- int mutating;
> >>>>>- struct semaphore session_sem;
> >>>>>- atomic_t ref_count;
> >>>>>-};
> >>>>>-
> >>>>>-struct nfs4_slot {
> >>>>>- u32 slot_nr;
> >>>>>- u32 seq_nr;
> >>>>>- struct nfs4_session * session;
> >>>>>- struct list_head slot_list;
> >>>>>-};
> >>>>>-
> >>>>>-#endif
> >>>>>diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index
> >>>>>195d757..e50657e 100644
> >>>>>--- a/fs/nfs/nfs4_fs.h
> >>>>>+++ b/fs/nfs/nfs4_fs.h
> >>>>>@@ -9,7 +9,7 @@
> >>>>>#ifndef __LINUX_FS_NFS_NFS4_FS_H
> >>>>>#define __LINUX_FS_NFS_NFS4_FS_H
> >>>>>
> >>>>>-#include "nfs41_sessions.h"
> >>>>>+#include <linux/nfs41_sessions.h>
> >>>>>
> >>>>>#ifdef CONFIG_NFS_V4
> >>>>>#define NFSV4_MAX_MINORVERSION 1
> >>>>>diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index
> >>>>>167ff4a..28513a1 100644
> >>>>>--- a/fs/nfs/nfs4proc.c
> >>>>>+++ b/fs/nfs/nfs4proc.c
> >>>>>@@ -49,6 +49,7 @@
> >>>>>#include <linux/namei.h>
> >>>>>#include <linux/mount.h>
> >>>>>#include <linux/module.h>
> >>>>>+#include <linux/bitops.h>
> >>>>>
> >>>>>#include "nfs4_fs.h"
> >>>>>#include "delegation.h"
> >>>>>@@ -221,8 +222,10 @@ static int
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs41_proc_sequence_done(struct nfs4_session *session, struct
> >>>>nfs41_s
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> unsigned long timestamp;
> >>>>> struct nfs4_client *clp;
> >>>>>
> >>>>>- if (!session || !(clp = session->client))
> >>>>>- return 0;
> >>>>>+ if (!session || !(clp = session->client)) {
> >>>>>+ printk(KERN_EMERG "%s is NULL!!!\n",
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>(!session)?"session":"clp");
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ BUG();
> >>>>>+ }
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>For performance reasons the defensive code should only be active
> >>>>with kernel debugging. The conditional statement above is always
> >>>>executed needlessly and is not as clean as it could be because of
> >>>>the assignment embedded in the boolean expression.
> Therefore, this
> >>>>better be coded like this:
> >>>>
> >>>> BUG_ON(!session);
> >>>> clp = session->client;
> >>>> BUG_ON(!clp);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> if (!status) {
> >>>>> timestamp = jiffies;
> >>>>>@@ -233,17 +236,131 @@ static int
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs41_proc_sequence_done(struct nfs4_session *session, struct
> >>>>nfs41_s
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> spin_unlock(&clp->cl_lock);
> >>>>> }
> >>>>>
> >>>>>+ /* Clear the 'busy' bit on the slot that was used */
> >>>>>+ smp_mb__before_clear_bit();
> >>>>>+ clear_bit(NFS4_SLOT_BUSY, &res->slot->flags);
> >>>>>+ smp_mb__after_clear_bit();
> >>>>>+
> >>>>>+ printk(KERN_EMERG "waking up waiters on slot %d\n",
> >>>>>+res->slot->slot_nr);
> >>>>>+
> >>>>>+ /* Wake up the threads waiting on this slot */
> >>>>>+ wake_up_bit(&res->slot->flags, NFS4_SLOT_BUSY);
> >>>>>+
> >>>>> return status;
> >>>>>}
> >>>>>
> >>>>>+static int nfs4_wait_bit_interruptible(void *word) {
> >>>>>+ if (signal_pending(current))
> >>>>>+ return -ERESTARTSYS;
> >>>>>+ schedule();
> >>>>>+ return 0;
> >>>>>+}
> >>>>>+
> >>>>>+/* Find the lowest numbered slot or sleep on the least
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>loaded slot */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+struct nfs4_slot *nfs4_find_slot(struct nfs4_channel *channel) {
> >>>>>+ struct nfs4_slot_table *tbl;
> >>>>>+ struct nfs4_slot *slot;
> >>>>>+ struct nfs4_slot *target_slot;
> >>>>>+ u32 max_slots;
> >>>>>+ u32 min_waiters;
> >>>>>+ int i;
> >>>>>+ int need_to_sleep;
> >>>>>+
> >>>>>+ might_sleep();
> >>>>>+
> >>>>>+ tbl = &channel->slot_table;
> >>>>>+ min_waiters = tbl->slots[0].nr_waiters;
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>atomic_read()
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ target_slot = &tbl->slots[0];
> >>>>>+
> >>>>>+ spin_lock(&tbl->slot_tbl_lock);
> >>>>>+ /* Make a local copy of max slots so we don't need to
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>hold it through
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ * out.
> >>>>>+ * XXX Will need to revalidate this if slots are reclaimed
> >>>>>+ */
> >>>>>+ max_slots = tbl->max_slots;
> >>>>>+ spin_unlock(&tbl->slot_tbl_lock);
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>Using a spinlock here is unreasonably expensive when you
> could use
> >>>>atomic counters since the lock overhead is not amortized over
> >>>>multiple accesses to the structure.
> >>>>max_slots and nr_waiters should be defined as atomic_t and atomic
> >>>>operations be used to access them; Alternatively use one spinlock
> >>>>for the whole channel around the outer loop
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+
> >>>>>+ do {
> >>>>>+ need_to_sleep = 1;
> >>>>>+ for (i = 0; i < max_slots; ++i) {
> >>>>>+ slot = &tbl->slots[i];
> >>>>>+ if (!test_and_set_bit(NFS4_SLOT_BUSY,
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>&slot->flags)){
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ /* We found an empty slot */
> >>>>>+ target_slot = slot;
> >>>>>+ need_to_sleep = 0;
> >>>>>+ break;
> >>>>>+ }
> >>>>>+
> >>>>>+ spin_lock(&slot->slot_lock);
> >>>>>+ if (min_waiters > slot->nr_waiters) {
> >>>>>+ min_waiters = slot->nr_waiters;
> >>>>>+ target_slot = slot;
> >>>>>+ }
> >>>>>+ spin_unlock(&slot->slot_lock);
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>why lock? use atomic_read(&slot->nr_waiters) also, if several
> >>>>threads go through this code in parallel they will pick the same
> >>>>target_slot so you want to increment.
> >>>>That's another reason to use a bigger lock.
> >>>>
> >>>>
> >>>>
> >>>>
> >>>Using atomic_t is a bit hard when you have to do compare
> and set kind
> >>>of operations...
> >>>Like for instance:
> >>>
> >>>If (min_waiters > slot->nr_waiters) {
> >>> min_waiters = slot->nr_waiters;
> >>> target_slot = slot;
> >>>}
> >>>
> >>>Doing the above atomically is hard with atomic variables
> only because
> >>>the whole sequence needs to be atomic. However, I can change the
> >>>spin_lock used to rwlock_t. This should better solve the
> problem. Right?
> >>>
> >>>
> >>>
> >>>
> >>>
> >>>>>+ printk(KERN_EMERG "slot %d has busy bit
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>%s and nr_waiters is %u\n"
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ , slot->slot_nr,
> >>>>>+
> (need_to_sleep)?"set":"unset",
> >>>>>+ slot->nr_waiters);
> >>>>>+ }
> >>>>>+
> >>>>>+ /* Check whether we need to sleep. If so, sleep
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>on the BUSY bit
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ * Increment the nr_waiters before sleeping and
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>decrement it
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ * when woken up
> >>>>>+ */
> >>>>>+ if (need_to_sleep) {
> >>>>>+ printk(KERN_EMERG "sleeping on slot %d;
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>seq_nr: %d\n",
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ target_slot->slot_nr,
> >>>>>+ target_slot->seq_nr);
> >>>>>+ spin_lock(&target_slot->slot_lock);
> >>>>>+ ++target_slot->nr_waiters;
> >>>>>+ spin_unlock(&target_slot->slot_lock);
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>atomic_inc()
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+
> >>>>>+ /* XXX: We need to check the return value of
> >>>>>+ * eait_on_bit so that we can check if it's
> >>>>>+ * interrupted.
> >>>>>+ */
> >>>>>+ wait_on_bit(&target_slot->flags,
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>NFS4_SLOT_BUSY,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ nfs4_wait_bit_interruptible,
> >>>>>+ TASK_INTERRUPTIBLE);
> >>>>>+
> >>>>>+ spin_lock(&target_slot->slot_lock);
> >>>>>+ --target_slot->nr_waiters;
> >>>>>+ spin_unlock(&target_slot->slot_lock);
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>atomic_dec()
> >>>>
> >>>>But wait a second, why do you want a queue per slot to begin with?
> >>>>It seems like you can just go with a semaphore initialized to the
> >>>>number of slots, do down_interruptible before scanning for a free
> >>>>slot and up in nfs41_proc_sequence_done. Take a spin lock to scan
> >>>>the slot table (last index can be saved and rotated for
> uniformity)
> >>>>and if not free slot is found do a
> >>>>BUG() since the semaphore should prevent that from happening;
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ }
> >>>>>+ else
> >>>>>+ break;
> >>>>>+ }while (test_and_set_bit(NFS4_SLOT_BUSY,
> >>>>>+ &target_slot->flags));
> >>>>>+
> >>>>>+ printk(KERN_EMERG "slot id: %u\nseqid: %u\n
> max_slots: %u\n",
> >>>>>+ target_slot->slot_nr, target_slot->seq_nr,
> >>>>>+ max_slots);
> >>>>>+
> >>>>>+ return target_slot;
> >>>>>+}
> >>>>>+
> >>>>>static int _nfs41_proc_setup_sequence(struct nfs4_session
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>*session,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>struct nfs41_sequence_args *args, struct
> nfs41_sequence_res *res) {
> >>>>> u32 *ptr;
> >>>>>-
> >>>>>+ struct nfs4_slot *slot;
> >>>>>+
> >>>>> ptr = (u32 *)session->sess_id;
> >>>>> dprintk("%s: %u:%u:%u:%u\n", __FUNCTION__, ptr[0],
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>ptr[1], ptr[2],
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>ptr[3]);
> >>>>>
> >>>>>- memcpy(args->sessionid, (unsigned char
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>*)session->sess_id, NFS4_MAX_SESSIONID_LEN);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ memcpy(args->sessionid, (unsigned char *)session->sess_id,
> >>>>>+ NFS4_MAX_SESSIONID_LEN);
> >>>>>+
> >>>>>+ slot = nfs4_find_slot(&session->fore_channel);
> >>>>>+
> >>>>>+ /* XXX: Do we always increment this? Are there any
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>errors for which we
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ * don't increment the sequence number?
> >>>>>+ */
> >>>>>+ args->seqid = slot->seq_nr++;
> >>>>>+ args->slotid = slot->slot_nr;
> >>>>>+ args->maxslots =
> >>>>>+ session->fore_channel.slot_table.max_slots;
> >>>>>+
> >>>>>+ res->slot = slot;
> >>>>>
> >>>>> return 0;
> >>>>>}
> >>>>>@@ -1685,11 +1802,6 @@ static int nfs4_proc_get_root(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs_server *server, struct nfs_fh *fhandle,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> };
> >>>>> int status;
> >>>>>
> >>>>>- if (server->rpc_ops->setup_sequence && (status =
> >>>>>-
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>server->rpc_ops->setup_sequence(server->nfs4_state->cl_session,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>- &seqargs, &seqres)))
> >>>>>- return status;
> >>>>>-
> >>>>> /*
> >>>>> * Now we do a separate LOOKUP for each component of
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>the mount path.
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> * The LOOKUPs are done separately so that we can
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>conveniently @@
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>-1714,9 +1826,21 @@ static int nfs4_proc_get_root(struct
> nfs_server
> >>>>>*server, struct nfs_fh *fhandle,
> >>>>>
> >>>>> do {
> >>>>> nfs_fattr_init(fattr);
> >>>>>+ if (server->rpc_ops->setup_sequence &&
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>(status =
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ server->rpc_ops->setup_sequence(
> >>>>>+ server->nfs4_state->cl_session,
> >>>>>+ &seqargs, &seqres)))
> >>>>>+ return status;
> >>>>>+
> >>>>> status = nfs4_handle_exception(server,
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>rpc_call_sync(server->client, &msg, 0),
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> &exception);
> >>>>>+
> >>>>>+ if (server->rpc_ops->sequence_done)
> >>>>>+ server->rpc_ops->sequence_done(
> >>>>>+
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>server->nfs4_state->cl_session,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ &seqres, status);
> >>>>>+
> >>>>> } while (exception.retry);
> >>>>> if (status == 0)
> >>>>> continue;
> >>>>>@@ -1731,10 +1855,6 @@ static int nfs4_proc_get_root(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs_server *server, struct nfs_fh *fhandle,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> if (status == 0)
> >>>>> status = nfs4_do_fsinfo(server, fhandle, info);
> >>>>>out:
> >>>>>- if (server->rpc_ops->sequence_done)
> >>>>>-
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>server->rpc_ops->sequence_done(server->nfs4_state->cl_session,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>- &seqres, status);
> >>>>>-
> >>>>> return nfs4_map_errors(status); }
> >>>>>
> >>>>>@@ -3268,6 +3388,7 @@ int nfs4_proc_async_sequence(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs4_client *clp, struct rpc_cred *cred)
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> ret = rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
> >>>>> &nfs4_sequence_ops, (void *)jiffies);
> >>>>>
> >>>>>+ nfs41_proc_sequence_done(clp->cl_session, res, ret);
> >>>>>out:
> >>>>> return ret;
> >>>>>out_free:
> >>>>>@@ -3581,14 +3702,6 @@ nfs4_async_handle_error(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>rpc_task *task, const struct nfs_server *server)
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> return 0;
> >>>>>}
> >>>>>
> >>>>>-static int nfs4_wait_bit_interruptible(void *word) -{
> >>>>>- if (signal_pending(current))
> >>>>>- return -ERESTARTSYS;
> >>>>>- schedule();
> >>>>>- return 0;
> >>>>>-}
> >>>>>-
> >>>>>static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct
> >>>>>nfs4_client *clp) {
> >>>>> sigset_t oldset;
> >>>>>@@ -3823,6 +3936,111 @@ int nfs4_proc_get_lease_time(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs4_client *clp, struct nfs_fsinfo *fsinfo)
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> return status;
> >>>>>}
> >>>>>
> >>>>>+/* Initialize a slot table */
> >>>>>+int nfs4_init_slot_table(struct nfs4_channel *channel) {
> >>>>>+ int i;
> >>>>>+ struct nfs4_slot_table *tbl;
> >>>>>+ struct nfs4_slot *slot;
> >>>>>+
> >>>>>+ tbl = &channel->slot_table;
> >>>>>+ tbl->max_slots = channel->chan_attrs.max_reqs;
> >>>>>+
> >>>>>+ tbl->slots = kzalloc(tbl->max_slots * sizeof(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs4_slot), GFP_ATOMIC);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ if (!tbl->slots)
> >>>>>+ return -ENOMEM;
> >>>>>+
> >>>>>+ spin_lock_init(&tbl->slot_tbl_lock);
> >>>>>+
> >>>>>+ for (i = 0; i < tbl->max_slots; ++i) {
> >>>>>+ slot = &tbl->slots[i];
> >>>>>+
> >>>>>+ slot->slot_nr = i;
> >>>>>+ slot->seq_nr = 1;
> >>>>>+ slot->flags = 0;
> >>>>>+ slot->nr_waiters = 0;
> >>>>>+ spin_lock_init(&slot->slot_lock);
> >>>>>+ }
> >>>>>+
> >>>>>+ return 0;
> >>>>>+}
> >>>>>+
> >>>>>+/* Destroy the slot table */
> >>>>>+void nfs4_destroy_slot_table(struct nfs4_channel *channel) {
> >>>>>+ int i;
> >>>>>+ struct nfs4_slot *slot;
> >>>>>+ struct nfs4_slot_table *tbl;
> >>>>>+
> >>>>>+ tbl = &channel->slot_table;
> >>>>>+
> >>>>>+ for (i = 0; i < tbl->max_slots;++i) {
> >>>>>+ slot = &tbl->slots[i];
> >>>>>+
> >>>>>+ if (slot->nr_waiters)
> >>>>>+ BUG();
> >>>>>+ }
> >>>>>+
> >>>>>+ kfree(channel->slot_table.slots);
> >>>>>+ channel->slot_table.slots = NULL;
> >>>>>+
> >>>>>+ return;
> >>>>>+}
> >>>>>+
> >>>>>+/* dump the channel attributes */
> >>>>>+void nfs4_dump_channel_attrs(struct nfs4_channel_attrs *attrs) {
> >>>>>+ printk(KERN_INFO "max_rqst_sz: %u\n", attrs->max_rqst_sz);
> >>>>>+ printk(KERN_INFO "max_resp_sz: %u\n", attrs->max_resp_sz);
> >>>>>+ printk(KERN_INFO "max_resp_sz_cached: %u\n",
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>attrs->max_resp_sz_cached);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ printk(KERN_INFO "max_ops: %u\n", attrs->max_ops);
> >>>>>+ printk(KERN_INFO "max_reqs: %u\n", attrs->max_reqs); }
> >>>>>+
> >>>>>+/* Initialize the values to be used by the client in
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>CREATE_SESSION
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+*/ void nfs4_init_channel_attrs(struct nfs4_client *clp,
> >>>>>+ struct nfs4_channel_attrs *fc_attrs,
> >>>>>+ struct nfs4_channel_attrs
> *bc_attrs) {
> >>>>>+ /* XXX: We need to have good values here... 32K is a
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>wild guess */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ fc_attrs->max_rqst_sz = bc_attrs->max_rqst_sz = 32768;
> >>>>>+ fc_attrs->max_resp_sz = bc_attrs->max_resp_sz = 32768;
> >>>>>+ fc_attrs->max_resp_sz_cached =
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>bc_attrs->max_resp_sz_cached = 32768;
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ fc_attrs->max_ops = bc_attrs->max_ops = 0xFFFFFFFF;
> >>>>>+ fc_attrs->max_reqs = bc_attrs->max_reqs =
> >>>>>+
> clp->cl_rpcclient->cl_xprt->max_reqs;
> >>>>>+ fc_attrs->stream_attrs = bc_attrs->stream_attrs = 0;
> >>>>>+ fc_attrs->rdma_attrs = bc_attrs->rdma_attrs = 0;
> >>>>>+
> >>>>>+}
> >>>>>+
> >>>>>+/* Check the values returned by the server for
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>CREATE_SESSION. Since
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+we made
> >>>>>+ * our needs known, if the server gives us more than we
> need, we
> >>>>>+don't bother
> >>>>>+ * with it.
> >>>>>+ */
> >>>>>+void nfs4_adjust_channel_attrs(struct nfs4_channel_attrs
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>*req_attrs,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ struct nfs4_channel_attrs
> *resp_attrs) {
> >>>>>+ if (req_attrs->max_rqst_sz < resp_attrs->max_rqst_sz)
> >>>>>+ resp_attrs->max_rqst_sz = req_attrs->max_rqst_sz;
> >>>>>+
> >>>>>+ if (req_attrs->max_resp_sz < resp_attrs->max_resp_sz)
> >>>>>+ resp_attrs->max_resp_sz = req_attrs->max_resp_sz;
> >>>>>+
> >>>>>+ if (req_attrs->max_resp_sz_cached < resp_attrs->max_resp_sz)
> >>>>>+ resp_attrs->max_resp_sz =
> >>>>>+ req_attrs->max_resp_sz_cached;
> >>>>>+
> >>>>>+ if (req_attrs->max_ops < resp_attrs->max_ops)
> >>>>>+ resp_attrs->max_ops = req_attrs->max_ops;
> >>>>>+
> >>>>>+ if (req_attrs->max_reqs < resp_attrs->max_reqs)
> >>>>>+ resp_attrs->max_reqs = req_attrs->max_reqs;
> >>>>>+
> >>>>>+ /* XXX: We ignore the stream channel attributes... we
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>have no idea what
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ * to do with them anyways!
> >>>>>+ */
> >>>>>+}
> >>>>>+
> >>>>>int _nfs4_proc_create_session(struct nfs4_client *clp, struct
> >>>>>nfs4_session *session, struct rpc_clnt *clnt) {
> >>>>> struct nfs41_create_session_args args = { @@ -3845,7
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>+4063,19 @@ int
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>_nfs4_proc_create_session(struct nfs4_client *clp, struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs4_session *sess
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> };
> >>>>> int status;
> >>>>>
> >>>>>- status = rpc_call_sync(clnt, &msg, 0);
> >>>>>+ nfs4_init_channel_attrs(clp, &args.fc_attrs,
> &args.bc_attrs);
> >>>>>+
> >>>>>+ status = rpc_call_sync(clnt, &msg, 0);
> >>>>>+
> >>>>>+ /* Set the negotiated values in the session's
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>channel_attrs struct
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+*/
> >>>>>+
> >>>>>+ if (!status) {
> >>>>>+ nfs4_adjust_channel_attrs(&args.fc_attrs,
> >>>>>+
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>&session->fore_channel.chan_attrs);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ nfs4_adjust_channel_attrs(&args.bc_attrs,
> >>>>>+
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>&session->back_channel.chan_attrs);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ }
> >>>>>+
> >>>>> return status;
> >>>>>}
> >>>>>EXPORT_SYMBOL(_nfs4_proc_create_session);
> >>>>>@@ -3853,29 +4083,28 @@ EXPORT_SYMBOL(_nfs4_proc_create_session);
> >>>>>int nfs4_proc_create_session(struct nfs4_client *clp) {
> >>>>> int status;
> >>>>>- unsigned long now;
> >>>>> struct nfs4_session *session;
> >>>>>- struct nfs_fsinfo fsinfo;
> >>>>> u32 *ptr;
> >>>>>
> >>>>>- now = jiffies;
> >>>>>-
> >>>>> status = _nfs4_proc_create_session(clp,
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>clp->cl_session, clp->cl_rpcclient);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> if (status)
> >>>>> return status;
> >>>>>
> >>>>>- status = nfs4_proc_get_lease_time(clp, &fsinfo);
> >>>>>- if (status == 0) {
> >>>>>- /* Update lease time and schedule renewal */
> >>>>>- spin_lock(&clp->cl_lock);
> >>>>>- clp->cl_lease_time = fsinfo.lease_time * HZ;
> >>>>>- clp->cl_last_renewal = now;
> >>>>>- clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
> >>>>>- spin_unlock(&clp->cl_lock);
> >>>>>+ session = clp->cl_session;
> >>>>>
> >>>>>- nfs4_schedule_state_renewal(clp);
> >>>>>+ /* Init the fore channel */
> >>>>>+ status = nfs4_init_slot_table(&session->fore_channel);
> >>>>>+ dprintk("fc init returned %d\n", status);
> >>>>>+ if (status)
> >>>>>+ return status;
> >>>>>+
> >>>>>+ /* Init the back channel */
> >>>>>+ status = nfs4_init_slot_table(&session->back_channel);
> >>>>>+ dprintk("bc init returned %d\n", status);
> >>>>>+ if (status) {
> >>>>>+ nfs4_destroy_slot_table(&session->fore_channel);
> >>>>>+ return status;
> >>>>> }
> >>>>>- session = clp->cl_session;
> >>>>>
> >>>>> ptr = (int *)session->sess_id;
> >>>>> dprintk("sessionid is: %d:%d:%d:%d\n", ptr[0],
> ptr[1], ptr[2],
> >>>>>ptr[3]); @@ -4769,11 +4998,8 @@ struct nfs4_session
> >>>>>*nfs41_alloc_session(void)
> >>>>>
> >>>>> session->expired = 1;
> >>>>>
> >>>>>- INIT_LIST_HEAD(&session->slots_in_use);
> >>>>>- INIT_LIST_HEAD(&session->unused_slots);
> >>>>> INIT_LIST_HEAD(&session->session_hashtbl);
> >>>>>
> >>>>>- //rpc_init_wait_queue(&session->slot_waitq, "Slot
> waitqueue");
> >>>>> spin_lock_init(&session->session_lock);
> >>>>>
> >>>>> sema_init(&session->session_sem, 1); @@ -4797,6
> +5023,8 @@ void
> >>>>>nfs4_get_session(struct nfs4_session *session) void
> >>>>>nfs4_put_session(struct nfs4_session **session) {
> >>>>> if (atomic_dec_and_test(&((*session)->ref_count))) {
> >>>>>+
> nfs4_destroy_slot_table(&((*session)->fore_channel));
> >>>>>+
> nfs4_destroy_slot_table(&((*session)->back_channel));
> >>>>> nfs41_free_session(*session);
> >>>>> *session = NULL;
> >>>>> }
> >>>>>@@ -4806,7 +5034,11 @@ int nfs41_proc_setup_session(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs4_client
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>*clp) {
> >>>>> int status;
> >>>>>
> >>>>>- dprintk("in %s!\n", __FUNCTION__);
> >>>>>+ struct nfs_fsinfo fsinfo;
> >>>>>+ unsigned long now;
> >>>>>+
> >>>>>+ now = jiffies;
> >>>>>+
> >>>>> if (!clp->cl_session) {
> >>>>> /* create the session struct to hold the
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>session parameters */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> clp->cl_session = nfs41_alloc_session(); @@
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>-4844,6 +5076,20 @@ int
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>nfs41_proc_setup_session(struct nfs4_client *clp)
> >>>>> clp->cl_session->expired = 0;
> >>>>> clp->cl_session->client = clp;
> >>>>>
> >>>>>+ status = nfs4_proc_get_lease_time(clp, &fsinfo);
> >>>>>+
> >>>>>+ if (status)
> >>>>>+ goto out_free;
> >>>>>+
> >>>>>+ /* Update lease time and schedule renewal */
> >>>>>+ spin_lock(&clp->cl_lock);
> >>>>>+ clp->cl_lease_time = fsinfo.lease_time * HZ;
> >>>>>+ clp->cl_last_renewal = now;
> >>>>>+ clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
> >>>>>+ spin_unlock(&clp->cl_lock);
> >>>>>+
> >>>>>+ nfs4_schedule_state_renewal(clp);
> >>>>>+
> >>>>> clp->cl_session->mutating = 0;
> >>>>>out:
> >>>>> up(&clp->cl_session->session_sem);
> >>>>>diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index
> >>>>>5ef6d70..7da9a6a 100644
> >>>>>--- a/fs/nfs/nfs4xdr.c
> >>>>>+++ b/fs/nfs/nfs4xdr.c
> >>>>>@@ -1429,20 +1429,22 @@ static int
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>encode_create_session(struct xdr_stream *xdr, struct
> >>>>nfs41_create_ses
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> RESERVE_SPACE(2*28); /* 2 channel_attrs */
> >>>>>
> >>>>> /* Fore Channel */
> >>>>>- WRITE32(32768); /* max req size */
> >>>>>- WRITE32(32768); /* max resp size */
> >>>>>- WRITE32(32768); /* Max resp
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>size cached */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>- WRITE32(RPC_DEF_SLOT_TABLE); /* max operations */
> >>>>>- WRITE32(RPC_DEF_SLOT_TABLE); /* max requests */
> >>>>>+ WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */
> >>>>>+ WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */
> >>>>>+ WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>resp sz cached */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ WRITE32(args->fc_attrs.max_ops); /* max operations */
> >>>>>+ WRITE32(args->fc_attrs.max_reqs); /* max requests */
> >>>>>+
> >>>>> WRITE32(0); /*
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>Streamchannel attrs */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> WRITE32(0);
> /*rdmachannel_attrs */
> >>>>>
> >>>>> /* Back Channel */
> >>>>>- WRITE32(32768); /* max req size */
> >>>>>- WRITE32(32768); /* max resp size */
> >>>>>- WRITE32(32768); /* Max resp
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>size cached */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>- WRITE32(RPC_DEF_SLOT_TABLE); /* max operations */
> >>>>>- WRITE32(RPC_DEF_SLOT_TABLE); /* max requests */
> >>>>>+ WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */
> >>>>>+ WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */
> >>>>>+ WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>resp sz cached */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ WRITE32(args->bc_attrs.max_ops); /* max operations */
> >>>>>+ WRITE32(args->bc_attrs.max_reqs); /* max requests */
> >>>>>+
> >>>>> WRITE32(0); /*
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>Streamchannel attrs */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> WRITE32(0);
> /*rdmachannel_attrs */
> >>>>>
> >>>>>@@ -6404,7 +6406,7 @@ static int
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>nfs41_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
> >>>>str
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> status = decode_putrootfh(&xdr);
> >>>>> if (!status)
> >>>>> status = decode_fsinfo(&xdr, res->fsinfo);
> >>>>>- if (!status)
> >>>>>+ if (status)
> >>>>> status = -nfs_stat_to_errno(hdr.status);
> >>>>> return status;
> >>>>>}
> >>>>>diff --git a/fs/nfs/super.c b/fs/nfs/super.c index
> a3bc630..89eb564
> >>>>>100644
> >>>>>--- a/fs/nfs/super.c
> >>>>>+++ b/fs/nfs/super.c
> >>>>>@@ -1260,15 +1260,13 @@ static int nfs4_fill_super(struct
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>super_block *sb, struct nfs4_mount_data *data,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> server->nfs4_state->cl_minorversion = i;
> >>>>>
> >>>>> if (server->rpc_ops->setup_session) {
> >>>>>- int status;
> >>>>>-
> >>>>> lock_kernel();
> >>>>> down_write(&server->nfs4_state->cl_sem);
> >>>>>- status =
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>server->rpc_ops->setup_session(server->nfs4_state);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ err =
> >>>>>+ server->rpc_ops->setup_session(server->nfs4_state);
> >>>>> up_write(&server->nfs4_state->cl_sem);
> >>>>> unlock_kernel();
> >>>>>
> >>>>>- if (status) {
> >>>>>+ if (err) {
> >>>>> printk(KERN_EMERG
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>"Couldn't mount using minorversion %d\n", i);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>rpc_shutdown_client(server->client);
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>> }
> >>>>>diff --git a/include/linux/nfs41_sessions.h
> >>>>>b/include/linux/nfs41_sessions.h new file mode 100644 index
> >>>>>0000000..02f45db
> >>>>>--- /dev/null
> >>>>>+++ b/include/linux/nfs41_sessions.h
> >>>>>@@ -0,0 +1,72 @@
> >>>>>+#ifndef __NFS4_1_SESSIONS_H__
> >>>>>+#define __NFS4_1_SESSIONS_H__
> >>>>>+
> >>>>>+/* The flags for the nfs4_slot struct */
> >>>>>+#define NFS4_SLOT_BUSY 0X0 /* Slot in use */
> >>>>>+#define NFS4_SLOT_RECLAIMED 0x1 /* Slot has
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>been reclaimed by
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ the server */
> >>>>>+
> >>>>>+typedef unsigned char sessionid_t[16];
> >>>>>+typedef u32 streamchannel_attrs;
> >>>>>+typedef u32 rdmachannel_attrs;
> >>>>>+
> >>>>>+struct nfs4_channel_attrs {
> >>>>>+ u32 max_rqst_sz;
> >>>>>+ u32 max_resp_sz;
> >>>>>+ u32 max_resp_sz_cached;
> >>>>>+ u32 max_ops;
> >>>>>+ u32 max_reqs;
> >>>>>+ streamchannel_attrs stream_attrs;
> >>>>>+ rdmachannel_attrs rdma_attrs;
> >>>>>+};
> >>>>>+
> >>>>>+struct nfs4_slot {
> >>>>>+ u32 slot_nr;
> >>>>>+ u32 seq_nr;
> >>>>>+ unsigned long flags;
> >>>>>+ u32 nr_waiters;
> >>>>>+ spinlock_t slot_lock;
> >>>>>+};
> >>>>>+
> >>>>>+struct nfs4_slot_table {
> >>>>>+ struct nfs4_slot *slots;
> >>>>>+ u32 max_slots;
> >>>>>+ spinlock_t slot_tbl_lock;
> >>>>>+};
> >>>>>+
> >>>>>+struct nfs4_channel {
> >>>>>+ struct nfs4_channel_attrs chan_attrs;
> >>>>>+ struct rpc_clnt *rpc_client;
> >>>>>+ struct nfs4_slot_table slot_table;
> >>>>>+};
> >>>>>+
> >>>>>+struct nfs4_session {
> >>>>>+ /* Session related params */
> >>>>>+ sessionid_t sess_id;
> >>>>>+ u32 seqid; /* The seqid
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>returned by
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ exchange_id */
> >>>>>+ u32 persist;
> >>>>>+ u32 header_padding;
> >>>>>+ u32 hash_alg;
> >>>>>+ u32 ssv_len;
> >>>>>+ u32 use_for_back_chan;
> >>>>>+ u32 rdma_mode;
> >>>>>+
> >>>>>+ /* The fore and back channel */
> >>>>>+ struct nfs4_channel fore_channel;
> >>>>>+ struct nfs4_channel back_channel;
> >>>>>+
> >>>>>+ unsigned int expired;
> >>>>>+ struct nfs4_client * client;
> >>>>>+ struct list_head session_hashtbl;
> >>>>>+ spinlock_t session_lock;
> >>>>>+ /* To prevent races between create_session and sequence */
> >>>>>+ int mutating;
> >>>>>+ struct semaphore session_sem;
> >>>>>+ atomic_t ref_count;
> >>>>>+};
> >>>>>+
> >>>>>+
> >>>>>+#endif
> >>>>>+
> >>>>>+
> >>>>>diff --git a/include/linux/nfs_xdr.h
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>b/include/linux/nfs_xdr.h index
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>4648707..52b9e38 100644
> >>>>>--- a/include/linux/nfs_xdr.h
> >>>>>+++ b/include/linux/nfs_xdr.h
> >>>>>@@ -3,6 +3,7 @@
> >>>>>
> >>>>>#include <linux/sunrpc/xprt.h>
> >>>>>#include <linux/nfsacl.h>
> >>>>>+#include <linux/nfs41_sessions.h>
> >>>>>
> >>>>>/*
> >>>>> * To change the maximum rsize and wsize supported by the
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>NFS client,
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>adjust @@ -778,6 +779,8 @@ struct nfs41_create_session_args {
> >>>>> uint32_t use_for_backchannel;
> >>>>> uint32_t use_for_rdma;
> >>>>> uint32_t cb_program;
> >>>>>+ struct nfs4_channel_attrs fc_attrs; /* Fore
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>Channel */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>+ struct nfs4_channel_attrs bc_attrs; /* Back
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>Channel */
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>};
> >>>>>
> >>>>>struct nfs41_create_session_res {
> >>>>>@@ -805,6 +808,7 @@ struct nfs41_sequence_res {
> >>>>> u32 target_maxslots;
> >>>>> u32 status_flags;
> >>>>> struct nfs4_state_owner *sp;
> >>>>>+ struct nfs4_slot *slot;
> >>>>>};
> >>>>>
> >>>>>struct nfs4_get_lease_time_args {
> >>>>>diff --git a/include/linux/nfsd/state.h
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>b/include/linux/nfsd/state.h
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>>index 8f699b4..fde667e 100644
> >>>>>--- a/include/linux/nfsd/state.h
> >>>>>+++ b/include/linux/nfsd/state.h
> >>>>>@@ -47,8 +47,6 @@ typedef struct {
> >>>>> u32 cl_id;
> >>>>>} clientid_t;
> >>>>>
> >>>>>-typedef unsigned char sessionid_t[16];
> >>>>>-
> >>>>>typedef struct {
> >>>>> u32 so_boot;
> >>>>> u32 so_stateownerid;
> >>>>>
> >>>>>
> >>>>>
> >>>>>
> >
> >_______________________________________________
> >pNFS mailing list
> >pNFS at linux-nfs.org
> >http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs
> >
> >
>
More information about the pNFS
mailing list