cregit-Linux how code gets into the kernel

Release 4.11 fs/nfsd/nfs4state.c

Directory: fs/nfsd
/*
*  Copyright (c) 2001 The Regents of the University of Michigan.
*  All rights reserved.
*
*  Kendrick Smith <kmsmith@umich.edu>
*  Andy Adamson <kandros@umich.edu>
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  1. Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*  2. Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*  3. Neither the name of the University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
*  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
*  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
*  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#include <linux/file.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/namei.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
#include <linux/ratelimit.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/addr.h>
#include <linux/jhash.h>
#include "xdr4.h"
#include "xdr4cb.h"
#include "vfs.h"
#include "current_stateid.h"

#include "netns.h"
#include "pnfs.h"


#define NFSDDBG_FACILITY                NFSDDBG_PROC


#define all_ones {{~0,~0},~0}

static const stateid_t one_stateid = {
	.si_generation = ~0,
	.si_opaque = all_ones,
};

static const stateid_t zero_stateid = {
	/* all fields zero */
};

static const stateid_t currentstateid = {
	.si_generation = 1,
};


static u64 current_sessionid = 1;


#define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t)))

#define ONE_STATEID(stateid)  (!memcmp((stateid), &one_stateid, sizeof(stateid_t)))

#define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))

/* forward declarations */
static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
static void nfs4_free_ol_stateid(struct nfs4_stid *stid);

/* Locking: */

/*
 * Currently used for the del_recall_lru and file hash table.  In an
 * effort to decrease the scope of the client_mutex, this spinlock may
 * eventually cover more:
 */
static DEFINE_SPINLOCK(state_lock);

/*
 * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
 * the refcount on the open stateid to drop.
 */
static DECLARE_WAIT_QUEUE_HEAD(close_wq);


static struct kmem_cache *openowner_slab;

static struct kmem_cache *lockowner_slab;

static struct kmem_cache *file_slab;

static struct kmem_cache *stateid_slab;

static struct kmem_cache *deleg_slab;

static struct kmem_cache *odstate_slab;

static void free_session(struct nfsd4_session *);


static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;

static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;


static bool is_session_dead(struct nfsd4_session *ses) { return ses->se_flags & NFS4_SESSION_DEAD; }

Contributors

PersonTokensPropCommitsCommitProp
Benny Halevy1055.56%150.00%
J. Bruce Fields844.44%150.00%
Total18100.00%2100.00%


static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) { if (atomic_read(&ses->se_ref) > ref_held_by_me) return nfserr_jukebox; ses->se_flags |= NFS4_SESSION_DEAD; return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields38100.00%2100.00%
Total38100.00%2100.00%


static bool is_client_expired(struct nfs4_client *clp) { return clp->cl_time == 0; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields1055.56%150.00%
Neil Brown844.44%150.00%
Total18100.00%2100.00%


static __be32 get_client_locked(struct nfs4_client *clp) { struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); if (is_client_expired(clp)) return nfserr_expired; atomic_inc(&clp->cl_refcount); return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust2240.74%125.00%
J. Bruce Fields2138.89%250.00%
Neil Brown1120.37%125.00%
Total54100.00%4100.00%

/* must be called under the client_lock */
static inline void renew_client_locked(struct nfs4_client *clp) { struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); if (is_client_expired(clp)) { WARN_ON(1); printk("%s: client (clientid %08x/%08x) already expired\n", __func__, clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); return; } dprintk("renewing client (clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); list_move_tail(&clp->cl_lru, &nn->client_lru); clp->cl_time = get_seconds(); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields97100.00%1100.00%
Total97100.00%1100.00%


static void put_client_renew_locked(struct nfs4_client *clp) { struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); if (!atomic_dec_and_test(&clp->cl_refcount)) return; if (!is_client_expired(clp)) renew_client_locked(clp); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields3560.34%133.33%
Trond Myklebust2237.93%133.33%
Fengguang Wu11.72%133.33%
Total58100.00%3100.00%


static void put_client_renew(struct nfs4_client *clp) { struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) return; if (!is_client_expired(clp)) renew_client_locked(clp); spin_unlock(&nn->client_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton63100.00%2100.00%
Total63100.00%2100.00%


static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) { __be32 status; if (is_session_dead(ses)) return nfserr_badsession; status = get_client_locked(ses->se_client); if (status) return status; atomic_inc(&ses->se_ref); return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust51100.00%1100.00%
Total51100.00%1100.00%


static void nfsd4_put_session_locked(struct nfsd4_session *ses) { struct nfs4_client *clp = ses->se_client; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) free_session(ses); put_client_renew_locked(clp); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust67100.00%2100.00%
Total67100.00%2100.00%


static void nfsd4_put_session(struct nfsd4_session *ses) { struct nfs4_client *clp = ses->se_client; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); spin_lock(&nn->client_lock); nfsd4_put_session_locked(ses); spin_unlock(&nn->client_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust55100.00%1100.00%
Total55100.00%1100.00%


static struct nfsd4_blocked_lock * find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, struct nfsd_net *nn) { struct nfsd4_blocked_lock *cur, *found = NULL; spin_lock(&nn->blocked_locks_lock); list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { if (fh_match(fh, &cur->nbl_fh)) { list_del_init(&cur->nbl_list); list_del_init(&cur->nbl_lru); found = cur; break; } } spin_unlock(&nn->blocked_locks_lock); if (found) posix_unblock_lock(&found->nbl_lock); return found; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton10899.08%375.00%
Neil Brown10.92%125.00%
Total109100.00%4100.00%


static struct nfsd4_blocked_lock * find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, struct nfsd_net *nn) { struct nfsd4_blocked_lock *nbl; nbl = find_blocked_lock(lo, fh, nn); if (!nbl) { nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); if (nbl) { fh_copy_shallow(&nbl->nbl_fh, fh); locks_init_lock(&nbl->nbl_lock); nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, &nfsd4_cb_notify_lock_ops, NFSPROC4_CLNT_CB_NOTIFY_LOCK); } } return nbl; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton105100.00%1100.00%
Total105100.00%1100.00%


static void free_blocked_lock(struct nfsd4_blocked_lock *nbl) { locks_release_private(&nbl->nbl_lock); kfree(nbl); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton24100.00%1100.00%
Total24100.00%1100.00%


static int nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) { /* * Since this is just an optimization, we don't try very hard if it * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and * just quit trying on anything else. */ switch (task->tk_status) { case -NFS4ERR_DELAY: rpc_delay(task, 1 * HZ); return 0; default: return 1; } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton45100.00%1100.00%
Total45100.00%1100.00%


static void nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb) { struct nfsd4_blocked_lock *nbl = container_of(cb, struct nfsd4_blocked_lock, nbl_cb); free_blocked_lock(nbl); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton31100.00%1100.00%
Total31100.00%1100.00%

static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { .done = nfsd4_cb_notify_lock_done, .release = nfsd4_cb_notify_lock_release, };
static inline struct nfs4_stateowner * nfs4_get_stateowner(struct nfs4_stateowner *sop) { atomic_inc(&sop->so_count); return sop; }

Contributors

PersonTokensPropCommitsCommitProp
Kinglong Mee2496.00%150.00%
Jeff Layton14.00%150.00%
Total25100.00%2100.00%


static int same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) { return (sop->so_owner.len == owner->len) && 0 == memcmp(sop->so_owner.data, owner->data, owner->len); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust4797.92%150.00%
Kinglong Mee12.08%150.00%
Total48100.00%2100.00%


static struct nfs4_openowner * find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, struct nfs4_client *clp) { struct nfs4_stateowner *so; lockdep_assert_held(&clp->cl_lock); list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], so_strhash) { if (!so->so_is_open_owner) continue; if (same_owner_str(so, &open->op_owner)) return openowner(nfs4_get_stateowner(so)); } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust7496.10%266.67%
Kinglong Mee33.90%133.33%
Total77100.00%3100.00%


static struct nfs4_openowner * find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_client *clp) { struct nfs4_openowner *oo; spin_lock(&clp->cl_lock); oo = find_openstateowner_str_locked(hashval, open, clp); spin_unlock(&clp->cl_lock); return oo; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust57100.00%2100.00%
Total57100.00%2100.00%


static inline u32 opaque_hashval(const void *ptr, int nbytes) { unsigned char *cptr = (unsigned char *) ptr; u32 x = 0; while (nbytes--) { x *= 37; x += *cptr++; } return x; }

Contributors

PersonTokensPropCommitsCommitProp
Neil Brown5198.08%150.00%
Trond Myklebust11.92%150.00%
Total52100.00%2100.00%


static void nfsd4_free_file_rcu(struct rcu_head *rcu) { struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); kmem_cache_free(file_slab, fp); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton1957.58%150.00%
J. Bruce Fields1442.42%150.00%
Total33100.00%2100.00%


void put_nfs4_file(struct nfs4_file *fi) { might_lock(&state_lock); if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { hlist_del_rcu(&fi->fi_hash); spin_unlock(&state_lock); WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2531.65%233.33%
Neil Brown2025.32%116.67%
J. Bruce Fields2025.32%116.67%
Sachin Bhamare1215.19%116.67%
Benny Halevy22.53%116.67%
Total79100.00%6100.00%


static struct file * __nfs4_get_fd(struct nfs4_file *f, int oflag) { if (f->fi_fds[oflag]) return get_file(f->fi_fds[oflag]); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust3897.44%150.00%
Neil Brown12.56%150.00%
Total39100.00%2100.00%


static struct file * find_writeable_file_locked(struct nfs4_file *f) { struct file *ret; lockdep_assert_held(&f->fi_lock); ret = __nfs4_get_fd(f, O_WRONLY); if (!ret) ret = __nfs4_get_fd(f, O_RDWR); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust52100.00%1100.00%
Total52100.00%1100.00%


static struct file * find_writeable_file(struct nfs4_file *f) { struct file *ret; spin_lock(&f->fi_lock); ret = find_writeable_file_locked(f); spin_unlock(&f->fi_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust44100.00%1100.00%
Total44100.00%1100.00%


static struct file *find_readable_file_locked(struct nfs4_file *f) { struct file *ret; lockdep_assert_held(&f->fi_lock); ret = __nfs4_get_fd(f, O_RDONLY); if (!ret) ret = __nfs4_get_fd(f, O_RDWR); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust52100.00%1100.00%
Total52100.00%1100.00%


static struct file * find_readable_file(struct nfs4_file *f) { struct file *ret; spin_lock(&f->fi_lock); ret = find_readable_file_locked(f); spin_unlock(&f->fi_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust44100.00%1100.00%
Total44100.00%1100.00%


struct file * find_any_file(struct nfs4_file *f) { struct file *ret; spin_lock(&f->fi_lock); ret = __nfs4_get_fd(f, O_RDWR); if (!ret) { ret = __nfs4_get_fd(f, O_WRONLY); if (!ret) ret = __nfs4_get_fd(f, O_RDONLY); } spin_unlock(&f->fi_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust75100.00%1100.00%
Total75100.00%1100.00%

static atomic_long_t num_delegations; unsigned long max_delegations; /* * Open owner state (share locks) */ /* hash tables for lock and open owners */ #define OWNER_HASH_BITS 8 #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) { unsigned int ret; ret = opaque_hashval(ownername->data, ownername->len); return ret & OWNER_HASH_MASK; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields3191.18%266.67%
Neil Brown38.82%133.33%
Total34100.00%3100.00%

/* hash table for nfs4_file */ #define FILE_HASH_BITS 8 #define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) { return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust31100.00%1100.00%
Total31100.00%1100.00%


static unsigned int file_hashval(struct knfsd_fh *fh) { return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust1354.17%133.33%
J. Bruce Fields833.33%133.33%
Neil Brown312.50%133.33%
Total24100.00%3100.00%

static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
static void __nfs4_file_get_access(struct nfs4_file *fp, u32 access) { lockdep_assert_held(&fp->fi_lock); if (access & NFS4_SHARE_ACCESS_WRITE) atomic_inc(&fp->fi_access[O_WRONLY]); if (access & NFS4_SHARE_ACCESS_READ) atomic_inc(&fp->fi_access[O_RDONLY]); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields2951.79%250.00%
Jeff Layton2748.21%250.00%
Total56100.00%4100.00%


static __be32 nfs4_file_get_access(struct nfs4_file *fp, u32 access) { lockdep_assert_held(&fp->fi_lock); /* Does this access mode make sense? */ if (access & ~NFS4_SHARE_ACCESS_BOTH) return nfserr_inval; /* Does it conflict with a deny mode already set? */ if ((access & fp->fi_share_deny) != 0) return nfserr_share_denied; __nfs4_file_get_access(fp, access); return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton3966.10%360.00%
J. Bruce Fields2033.90%240.00%
Total59100.00%5100.00%


static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) { /* Common case is that there is no deny mode. */ if (deny) { /* Does this deny mode make sense? */ if (deny & ~NFS4_SHARE_DENY_BOTH) return nfserr_inval; if ((deny & NFS4_SHARE_DENY_READ) && atomic_read(&fp->fi_access[O_RDONLY])) return nfserr_share_denied; if ((deny & NFS4_SHARE_DENY_WRITE) && atomic_read(&fp->fi_access[O_WRONLY])) return nfserr_share_denied; } return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton79100.00%1100.00%
Total79100.00%1100.00%


static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) { might_lock(&fp->fi_lock); if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { struct file *f1 = NULL; struct file *f2 = NULL; swap(f1, fp->fi_fds[oflag]); if (atomic_read(&fp->fi_access[1 - oflag]) == 0) swap(f2, fp->fi_fds[O_RDWR]); spin_unlock(&fp->fi_lock); if (f1) fput(f1); if (f2) fput(f2); } }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields5544.72%360.00%
Trond Myklebust5443.90%120.00%
Jeff Layton1411.38%120.00%
Total123100.00%5100.00%


static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) { WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); if (access & NFS4_SHARE_ACCESS_WRITE) __nfs4_file_put_access(fp, O_WRONLY); if (access & NFS4_SHARE_ACCESS_READ) __nfs4_file_put_access(fp, O_RDONLY); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields2858.33%150.00%
Jeff Layton2041.67%150.00%
Total48100.00%2100.00%

/* * Allocate a new open/delegation state counter. This is needed for * pNFS for proper return on close semantics. * * Note that we only allocate it for pNFS-enabled exports, otherwise * all pointers to struct nfs4_clnt_odstate are always NULL. */
static struct nfs4_clnt_odstate * alloc_clnt_odstate(struct nfs4_client *clp) { struct nfs4_clnt_odstate *co; co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); if (co) { co->co_client = clp; atomic_set(&co->co_odcount, 1); } return co; }

Contributors

PersonTokensPropCommitsCommitProp
Sachin Bhamare52100.00%1100.00%
Total52100.00%1100.00%


static void hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) { struct nfs4_file *fp = co->co_file; lockdep_assert_held(&fp->fi_lock); list_add(&co->co_perfile, &fp->fi_clnt_odstate); }

Contributors

PersonTokensPropCommitsCommitProp
Sachin Bhamare41100.00%1100.00%
Total41100.00%1100.00%


static inline void get_clnt_odstate(struct nfs4_clnt_odstate *co) { if (co) atomic_inc(&co->co_odcount); }

Contributors

PersonTokensPropCommitsCommitProp
Sachin Bhamare24100.00%1100.00%
Total24100.00%1100.00%


static void put_clnt_odstate(struct nfs4_clnt_odstate *co) { struct nfs4_file *fp; if (!co) return; fp = co->co_file; if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { list_del(&co->co_perfile); spin_unlock(&fp->fi_lock); nfsd4_return_all_file_layouts(co->co_client, fp); kmem_cache_free(odstate_slab, co); } }

Contributors

PersonTokensPropCommitsCommitProp
Sachin Bhamare77100.00%1100.00%
Total77100.00%1100.00%


static struct nfs4_clnt_odstate * find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) { struct nfs4_clnt_odstate *co; struct nfs4_client *cl; if (!new) return NULL; cl = new->co_client; spin_lock(&fp->fi_lock); list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { if (co->co_client == cl) { get_clnt_odstate(co); goto out; } } co = new; co->co_file = fp; hash_clnt_odstate_locked(new); out: spin_unlock(&fp->fi_lock); return co; }

Contributors

PersonTokensPropCommitsCommitProp
Sachin Bhamare106100.00%1100.00%
Total106100.00%1100.00%


struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, void (*sc_free)(struct nfs4_stid *)) { struct nfs4_stid *stid; int new_id; stid = kmem_cache_zalloc(slab, GFP_KERNEL); if (!stid) return NULL; idr_preload(GFP_KERNEL); spin_lock(&cl->cl_lock); new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 0, 0, GFP_NOWAIT); spin_unlock(&cl->cl_lock); idr_preload_end(); if (new_id < 0) goto out_free; stid->sc_free = sc_free; stid->sc_client = cl; stid->sc_stateid.si_opaque.so_id = new_id; stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; /* Will be incremented before return to client: */ atomic_set(&stid->sc_count, 1); spin_lock_init(&stid->sc_lock); /* * It shouldn't be a problem to reuse an opaque stateid value. * I don't think it is for 4.1. But with 4.0 I worry that, for * example, a stray write retransmission could be accepted by * the server when it should have been rejected. Therefore, * adopt a trick from the sctp code to attempt to maximize the * amount of time until an id is reused, by ensuring they always * "increase" (mod INT_MAX): */ return stid; out_free: kmem_cache_free(slab, stid); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields9353.76%433.33%
Jeff Layton3922.54%325.00%
Kinglong Mee179.83%18.33%
Trond Myklebust116.36%216.67%
Tejun Heo105.78%18.33%
Wei Yongjun31.73%18.33%
Total173100.00%12100.00%


static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) { struct nfs4_stid *stid; stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); if (!stid) return NULL; return openlockstateid(stid); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields2046.51%125.00%
Trond Myklebust1944.19%125.00%
Kinglong Mee36.98%125.00%
Jeff Layton12.33%125.00%
Total43100.00%4100.00%


static void nfs4_free_deleg(struct nfs4_stid *stid) { kmem_cache_free(deleg_slab, stid); atomic_long_dec(&num_delegations); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust24100.00%1100.00%
Total24100.00%1100.00%

/* * When we recall a delegation, we should be careful not to hand it * out again straight away. * To ensure this we keep a pair of bloom filters ('new' and 'old') * in which the filehandles of recalled delegations are "stored". * If a filehandle appear in either filter, a delegation is blocked. * When a delegation is recalled, the filehandle is stored in the "new" * filter. * Every 30 seconds we swap the filters and clear the "new" one, * unless both are empty of course. * * Each filter is 256 bits. We hash the filehandle to 32bit and use the * low 3 bytes as hash-table indices. * * 'blocked_delegations_lock', which is always taken in block_delegations(), * is used to manage concurrent access. Testing does not need the lock * except when swapping the two filters. */ static DEFINE_SPINLOCK(blocked_delegations_lock); static struct bloom_pair { int entries, old_entries; time_t swap_time; int new; /* index into 'set' */ DECLARE_BITMAP(set[2], 256); } blocked_delegations;
static int delegation_blocked(struct knfsd_fh *fh) { u32 hash; struct bloom_pair *bd = &blocked_delegations; if (bd->entries == 0) return 0; if (seconds_since_boot() - bd->swap_time > 30) { spin_lock(&blocked_delegations_lock); if (seconds_since_boot() - bd->swap_time > 30) { bd->entries -= bd->old_entries; bd->old_entries = bd->entries; memset(bd->set[bd->new], 0, sizeof(bd->set[0])); bd->new = 1-bd->new; bd->swap_time = seconds_since_boot(); } spin_unlock(&blocked_delegations_lock); } hash = jhash(&fh->fh_base, fh->fh_size, 0); if (test_bit(hash&255, bd->set[0]) && test_bit((hash>>8)&255, bd->set[0]) && test_bit((hash>>16)&255, bd->set[0])) return 1; if (test_bit(hash&255, bd->set[1]) && test_bit((hash>>8)&255, bd->set[1]) && test_bit((hash>>16)&255, bd->set[1])) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Neil Brown25498.83%133.33%
Jeff Layton20.78%133.33%
Daniel Borkmann10.39%133.33%
Total257100.00%3100.00%


static void block_delegations(struct knfsd_fh *fh) { u32 hash; struct bloom_pair *bd = &blocked_delegations; hash = jhash(&fh->fh_base, fh->fh_size, 0); spin_lock(&blocked_delegations_lock); __set_bit(hash&255, bd->set[bd->new]); __set_bit((hash>>8)&255, bd->set[bd->new]); __set_bit((hash>>16)&255, bd->set[bd->new]); if (bd->entries == 0) bd->swap_time = seconds_since_boot(); bd->entries += 1; spin_unlock(&blocked_delegations_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Neil Brown11489.76%133.33%
Jeff Layton129.45%133.33%
Daniel Borkmann10.79%133.33%
Total127100.00%3100.00%


static struct nfs4_delegation * alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, struct nfs4_clnt_odstate *odstate) { struct nfs4_delegation *dp; long n; dprintk("NFSD alloc_init_deleg\n"); n = atomic_long_inc_return(&num_delegations); if (n < 0 || n > max_delegations) goto out_dec; if (delegation_blocked(&current_fh->fh_handle)) goto out_dec; dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); if (dp == NULL) goto out_dec; /* * delegation seqid's are never incremented. The 4.1 special * meaning of seqid 0 isn't meaningful, really, but let's avoid * 0 anyway just for consistency and use 1: */ dp->dl_stid.sc_stateid.si_generation = 1; INIT_LIST_HEAD(&dp->dl_perfile); INIT_LIST_HEAD(&dp->dl_perclnt); INIT_LIST_HEAD(&dp->dl_recall_lru); dp->dl_clnt_odstate = odstate; get_clnt_odstate(odstate); dp->dl_type = NFS4_OPEN_DELEGATE_READ; dp->dl_retries = 1; nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); return dp; out_dec: atomic_long_dec(&num_delegations); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Neil Brown8646.74%633.33%
Trond Myklebust3619.57%15.56%
Christoph Hellwig2111.41%211.11%
J. Bruce Fields2111.41%527.78%
Sachin Bhamare168.70%15.56%
Kinglong Mee21.09%15.56%
Meelap Shah10.54%15.56%
Jeff Layton10.54%15.56%
Total184100.00%18100.00%


void nfs4_put_stid(struct nfs4_stid *s) { struct nfs4_file *fp = s->sc_file; struct nfs4_client *clp = s->sc_client; might_lock(&clp->cl_lock); if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) { wake_up_all(&close_wq); return; } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); spin_unlock(&clp->cl_lock); s->sc_free(s); if (fp) put_nfs4_file(fp); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust4342.57%541.67%
Jeff Layton3029.70%216.67%
J. Bruce Fields1514.85%18.33%
Neil Brown1211.88%325.00%
Benny Halevy10.99%18.33%
Total101100.00%12100.00%


void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) { stateid_t *src = &stid->sc_stateid; spin_lock(&stid->sc_lock); if (unlikely(++src->si_generation == 0)) src->si_generation = 1; memcpy(dst, src, sizeof(*dst)); spin_unlock(&stid->sc_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton70100.00%1100.00%
Total70100.00%1100.00%


static void nfs4_put_deleg_lease(struct nfs4_file *fp) { struct file *filp = NULL; spin_lock(&fp->fi_lock); if (fp->fi_deleg_file && --fp->fi_delegees == 0) swap(filp, fp->fi_deleg_file); spin_unlock(&fp->fi_lock); if (filp) { vfs_setlease(filp, F_UNLCK, NULL, (void **)&fp); fput(filp); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton4755.95%642.86%
J. Bruce Fields1720.24%428.57%
Neil Brown1315.48%321.43%
Christoph Hellwig78.33%17.14%
Total84100.00%14100.00%


void nfs4_unhash_stid(struct nfs4_stid *s) { s->sc_type = 0; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields1593.75%266.67%
Christoph Hellwig16.25%133.33%
Total16100.00%3100.00%

/** * nfs4_get_existing_delegation - Discover if this delegation already exists * @clp: a pointer to the nfs4_client we're granting a delegation to * @fp: a pointer to the nfs4_file we're granting a delegation on * * Return: * On success: NULL if an existing delegation was not found. * * On error: -EAGAIN if one was previously granted to this nfs4_client * for this nfs4_file. * */
static int nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp) { struct nfs4_delegation *searchdp = NULL; struct nfs4_client *searchclp = NULL; lockdep_assert_held(&state_lock); lockdep_assert_held(&fp->fi_lock); list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { searchclp = searchdp->dl_stid.sc_client; if (clp == searchclp) { return -EAGAIN; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Elble7698.70%150.00%
Neil Brown11.30%150.00%
Total77100.00%2100.00%

/** * hash_delegation_locked - Add a delegation to the appropriate lists * @dp: a pointer to the nfs4_delegation we are adding. * @fp: a pointer to the nfs4_file we're granting a delegation on * * Return: * On success: NULL if the delegation was successfully hashed. * * On error: -EAGAIN if one was previously granted to this * nfs4_client for this nfs4_file. Delegation is not hashed. * */
static int hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) { int status; struct nfs4_client *clp = dp->dl_stid.sc_client; lockdep_assert_held(&state_lock); lockdep_assert_held(&fp->fi_lock); status = nfs4_get_existing_delegation(clp, fp); if (status) return status; ++fp->fi_delegees; atomic_inc(&dp->dl_stid.sc_count); dp->dl_stid.sc_type = NFS4_DELEG_STID; list_add(&dp->dl_perfile, &fp->fi_delegations); list_add(&dp->dl_perclnt, &clp->cl_delegations); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Elble4136.61%111.11%
Benny Halevy3934.82%333.33%
Neil Brown1311.61%222.22%
Trond Myklebust108.93%111.11%
Jeff Layton87.14%111.11%
J. Bruce Fields10.89%111.11%
Total112100.00%9100.00%


static bool unhash_delegation_locked(struct nfs4_delegation *dp) { struct nfs4_file *fp = dp->dl_stid.sc_file; lockdep_assert_held(&state_lock); if (list_empty(&dp->dl_perfile)) return false; dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; /* Ensure that deleg break won't try to requeue it */ ++dp->dl_time; spin_lock(&fp->fi_lock); list_del_init(&dp->dl_perclnt); list_del_init(&dp->dl_recall_lru); list_del_init(&dp->dl_perfile); spin_unlock(&fp->fi_lock); return true; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton5455.10%538.46%
Benny Halevy1616.33%215.38%
Neil Brown1111.22%215.38%
Trond Myklebust1111.22%215.38%
J. Bruce Fields66.12%215.38%
Total98100.00%13100.00%


static void destroy_delegation(struct nfs4_delegation *dp) { bool unhashed; spin_lock(&state_lock); unhashed = unhash_delegation_locked(dp); spin_unlock(&state_lock); if (unhashed) { put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); nfs4_put_stid(&dp->dl_stid); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton3352.38%350.00%
J. Bruce Fields1930.16%116.67%
Sachin Bhamare711.11%116.67%
Trond Myklebust46.35%116.67%
Total63100.00%6100.00%


static void revoke_delegation(struct nfs4_delegation *dp) { struct nfs4_client *clp = dp->dl_stid.sc_client; WARN_ON(!list_empty(&dp->dl_recall_lru)); put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); if (clp->cl_minorversion == 0) nfs4_put_stid(&dp->dl_stid); else { dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; spin_lock(&clp->cl_lock); list_add(&dp->dl_recall_lru, &clp->cl_revoked); spin_unlock(&clp->cl_lock); } }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4643.40%225.00%
Jeff Layton3835.85%225.00%
Neil Brown1110.38%225.00%
Sachin Bhamare76.60%112.50%
Trond Myklebust43.77%112.50%
Total106100.00%8100.00%

/* * SETCLIENTID state */
static unsigned int clientid_hashval(u32 id) { return id & CLIENT_HASH_MASK; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields1173.33%150.00%
Neil Brown426.67%150.00%
Total15100.00%2100.00%


static unsigned int clientstr_hashval(const char *name) { return opaque_hashval(name, 8) & CLIENT_HASH_MASK; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields1881.82%150.00%
Neil Brown418.18%150.00%
Total22100.00%2100.00%

/* * 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 * only what share bits are currently in force, but also what * combinations of share bits previous opens have used. This allows us * to enforce the recommendation of rfc 3530 14.2.19 that the server * return an error if the client attempt to downgrade to a combination * of share bits not explicable by closing some of its previous opens. * * XXX: This enforcement is actually incomplete, since we don't keep * track of access/deny bit combinations; so, e.g., we allow: * * OPEN allow read, deny write * OPEN allow both, deny none * DOWNGRADE allow read, deny none * * which we should reject. */
static unsigned int bmap_to_share_mode(unsigned long bmap) { int i; unsigned int access = 0; for (i = 1; i < 4; i++) { if (test_bit(i, &bmap)) access |= i; } return access; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4382.69%266.67%
Jeff Layton917.31%133.33%
Total52100.00%3100.00%

/* set share access for a given stateid */
static inline void set_access(u32 access, struct nfs4_ol_stateid *stp) { unsigned char mask = 1 << access; WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); stp->st_access_bmap |= mask; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2775.00%250.00%
J. Bruce Fields925.00%250.00%
Total36100.00%4100.00%

/* clear share access for a given stateid */
static inline void clear_access(u32 access, struct nfs4_ol_stateid *stp) { unsigned char mask = 1 << access; WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); stp->st_access_bmap &= ~mask; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2362.16%240.00%
J. Bruce Fields1437.84%360.00%
Total37100.00%5100.00%

/* test whether a given stateid has access */
static inline bool test_access(u32 access, struct nfs4_ol_stateid *stp) { unsigned char mask = 1 << access; return (bool)(stp->st_access_bmap & mask); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2160.00%228.57%
J. Bruce Fields1440.00%571.43%
Total35100.00%7100.00%

/* set share deny for a given stateid */
static inline void set_deny(u32 deny, struct nfs4_ol_stateid *stp) { unsigned char mask = 1 << deny; WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); stp->st_deny_bmap |= mask; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2775.00%250.00%
J. Bruce Fields925.00%250.00%
Total36100.00%4100.00%

/* clear share deny for a given stateid */
static inline void clear_deny(u32 deny, struct nfs4_ol_stateid *stp) { unsigned char mask = 1 << deny; WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); stp->st_deny_bmap &= ~mask; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton37100.00%2100.00%
Total37100.00%2100.00%

/* test whether a given stateid is denying specific access */
static inline bool test_deny(u32 deny, struct nfs4_ol_stateid *stp) { unsigned char mask = 1 << deny; return (bool)(stp->st_deny_bmap & mask); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton35100.00%2100.00%
Total35100.00%2100.00%


static int nfs4_access_to_omode(u32 access) { switch (access & NFS4_SHARE_ACCESS_BOTH) { case NFS4_SHARE_ACCESS_READ: return O_RDONLY; case NFS4_SHARE_ACCESS_WRITE: return O_WRONLY; case NFS4_SHARE_ACCESS_BOTH: return O_RDWR; } WARN_ON_ONCE(1); return O_RDONLY; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields43100.00%3100.00%
Total43100.00%3100.00%

/* * A stateid that had a deny mode associated with it is being released * or downgraded. Recalculate the deny mode on the file. */
static void recalculate_deny_mode(struct nfs4_file *fp) { struct nfs4_ol_stateid *stp; spin_lock(&fp->fi_lock); fp->fi_share_deny = 0; list_for_each_entry(stp, &fp->fi_stateids, st_perfile) fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); spin_unlock(&fp->fi_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton57100.00%1100.00%
Total57100.00%1100.00%


static void reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) { int i; bool change = false; for (i = 1; i < 4; i++) { if ((i & deny) != i) { change = true; clear_deny(i, stp); } } /* Recalculate per-file deny mode if there was a change */ if (change) recalculate_deny_mode(stp->st_stid.sc_file); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton7195.95%150.00%
Trond Myklebust34.05%150.00%
Total74100.00%2100.00%

/* release all access and file references for a given stateid */
static void release_all_access(struct nfs4_ol_stateid *stp) { int i; struct nfs4_file *fp = stp->st_stid.sc_file; if (fp && stp->st_deny_bmap != 0) recalculate_deny_mode(fp); for (i = 1; i < 4; i++) { if (test_access(i, stp)) nfs4_file_put_access(stp->st_stid.sc_file, i); clear_access(i, stp); } }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4554.88%770.00%
Jeff Layton3137.80%220.00%
Trond Myklebust67.32%110.00%
Total82100.00%10100.00%


static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) { kfree(sop->so_owner.data); sop->so_ops->so_free(sop); }

Contributors

PersonTokensPropCommitsCommitProp
Kinglong Mee30100.00%1100.00%
Total30100.00%1100.00%


static void nfs4_put_stateowner(struct nfs4_stateowner *sop) { struct nfs4_client *clp = sop->so_client; might_lock(&clp->cl_lock); if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) return; sop->so_ops->so_unhash(sop); spin_unlock(&clp->cl_lock); nfs4_free_stateowner(sop); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton6698.51%375.00%
Kinglong Mee11.49%125.00%
Total67100.00%4100.00%


static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_file *fp = stp->st_stid.sc_file; lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); if (list_empty(&stp->st_perfile)) return false; spin_lock(&fp->fi_lock); list_del_init(&stp->st_perfile); spin_unlock(&fp->fi_lock); list_del(&stp->st_perstateowner); return true; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton4959.76%450.00%
Trond Myklebust2732.93%225.00%
J. Bruce Fields56.10%112.50%
Hirofumi Ogawa11.22%112.50%
Total82100.00%8100.00%


static void nfs4_free_ol_stateid(struct nfs4_stid *stid) { struct nfs4_ol_stateid *stp = openlockstateid(stid); put_clnt_odstate(stp->st_clnt_odstate); release_all_access(stp); if (stp->st_stateowner) nfs4_put_stateowner(stp->st_stateowner); kmem_cache_free(stateid_slab, stid); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2547.17%225.00%
Trond Myklebust1528.30%112.50%
Sachin Bhamare713.21%112.50%
J. Bruce Fields611.32%450.00%
Total53100.00%8100.00%


static void nfs4_free_lock_stateid(struct nfs4_stid *stid) { struct nfs4_ol_stateid *stp = openlockstateid(stid); struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); struct file *file; file = find_any_file(stp->st_stid.sc_file); if (file) filp_close(file, (fl_owner_t)lo); nfs4_free_ol_stateid(stid); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields3348.53%342.86%
Jeff Layton3044.12%114.29%
Trond Myklebust57.35%342.86%
Total68100.00%7100.00%

/* * Put the persistent reference to an already unhashed generic stateid, while * holding the cl_lock. If it's the last reference, then put it onto the * reaplist for later destruction. */
static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, struct list_head *reaplist) { struct nfs4_stid *s = &stp->st_stid; struct nfs4_client *clp = s->sc_client; lockdep_assert_held(&clp->cl_lock); WARN_ON_ONCE(!list_empty(&stp->st_locks)); if (!atomic_dec_and_test(&s->sc_count)) { wake_up_all(&close_wq); return; } idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); list_add(&stp->st_locks, reaplist); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton101100.00%1100.00%
Total101100.00%1100.00%


static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) { lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); list_del_init(&stp->st_locks); nfs4_unhash_stid(&stp->st_stid); return unhash_ol_stateid(stp); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton3577.78%444.44%
J. Bruce Fields613.33%333.33%
Chuck Lever36.67%111.11%
Christoph Hellwig12.22%111.11%
Total45100.00%9100.00%


static void release_lock_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_client *clp = stp->st_stid.sc_client; bool unhashed; spin_lock(&clp->cl_lock); unhashed = unhash_lock_stateid(stp); spin_unlock(&clp->cl_lock); if (unhashed) nfs4_put_stid(&stp->st_stid); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton4473.33%342.86%
Chuck Lever711.67%114.29%
J. Bruce Fields58.33%228.57%
Trond Myklebust46.67%114.29%
Total60100.00%7100.00%


static void unhash_lockowner_locked(struct nfs4_lockowner *lo) { struct nfs4_client *clp = lo->lo_owner.so_client; lockdep_assert_held(&clp->cl_lock); list_del_init(&lo->lo_owner.so_strhash); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust2050.00%233.33%
J. Bruce Fields1845.00%350.00%
Jeff Layton25.00%116.67%
Total40100.00%6100.00%

/* * Free a list of generic stateids that were collected earlier after being * fully unhashed. */
static void free_ol_stateid_reaplist(struct list_head *reaplist) { struct nfs4_ol_stateid *stp; struct nfs4_file *fp; might_sleep(); while (!list_empty(reaplist)) { stp = list_first_entry(reaplist, struct nfs4_ol_stateid, st_locks); list_del(&stp->st_locks); fp = stp->st_stid.sc_file; stp->st_stid.sc_free(&stp->st_stid); if (fp) put_nfs4_file(fp); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton6173.49%150.00%
Kinglong Mee2226.51%150.00%
Total83100.00%2100.00%


static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, struct list_head *reaplist) { struct nfs4_ol_stateid *stp; lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); while (!list_empty(&open_stp->st_locks)) { stp = list_entry(open_stp->st_locks.next, struct nfs4_ol_stateid, st_locks); WARN_ON(!unhash_lock_stateid(stp)); put_ol_stateid_locked(stp, reaplist); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2937.18%350.00%
J. Bruce Fields2835.90%233.33%
Trond Myklebust2126.92%116.67%
Total78100.00%6100.00%


static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, struct list_head *reaplist) { bool unhashed; lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); unhashed = unhash_ol_stateid(stp); release_open_stateid_locks(stp, reaplist); return unhashed; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton2960.42%555.56%
J. Bruce Fields1837.50%333.33%
Trond Myklebust12.08%111.11%
Total48100.00%9100.00%


static void release_open_stateid(struct nfs4_ol_stateid *stp) { LIST_HEAD(reaplist); spin_lock(&stp->st_stid.sc_client->cl_lock); if (unhash_open_stateid(stp, &reaplist)) put_ol_stateid_locked(stp, &reaplist); spin_unlock(&stp->st_stid.sc_client->cl_lock); free_ol_stateid_reaplist(&reaplist); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton4265.62%350.00%
J. Bruce Fields1929.69%233.33%
Trond Myklebust34.69%116.67%
Total64100.00%6100.00%


static void unhash_openowner_locked(struct nfs4_openowner *oo) { struct nfs4_client *clp = oo->oo_owner.so_client; lockdep_assert_held(&clp->cl_lock); list_del_init(&oo->oo_owner.so_strhash); list_del_init(&oo->oo_perclient); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields2552.08%233.33%
Trond Myklebust2041.67%233.33%
Jeff Layton24.17%116.67%
Neil Brown12.08%116.67%
Total48100.00%6100.00%


static void release_last_closed_stateid(struct nfs4_openowner *oo) { struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, nfsd_net_id); struct nfs4_ol_stateid *s; spin_lock(&nn->client_lock); s = oo->oo_last_closed_stid; if (s) { list_del_init(&oo->oo_close_lru); oo->oo_last_closed_stid = NULL; } spin_unlock(&nn->client_lock); if (s) nfs4_put_stid(&s->st_stid); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton5461.36%250.00%
J. Bruce Fields3236.36%125.00%
Trond Myklebust22.27%125.00%
Total88100.00%4100.00%


static void release_openowner(struct nfs4_openowner *oo) { struct nfs4_ol_stateid *stp; struct nfs4_client *clp = oo->oo_owner.so_client; struct list_head reaplist; INIT_LIST_HEAD(&reaplist); spin_lock(&clp->cl_lock); unhash_openowner_locked(oo); while (!list_empty(&oo->oo_owner.so_stateids)) { stp = list_first_entry(&oo->oo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); if (unhash_open_stateid(stp, &reaplist)) put_ol_stateid_locked(stp, &reaplist); } spin_unlock(&clp->cl_lock); free_ol_stateid_reaplist(&reaplist); release_last_closed_stateid(oo); nfs4_put_stateowner(&oo->oo_owner); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton8466.14%545.45%
Trond Myklebust3325.98%218.18%
J. Bruce Fields107.87%436.36%
Total127100.00%11100.00%


static inline int hash_sessionid(struct nfs4_sessionid *sessionid) { struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; return sid->sequence % SESSION_HASH_SIZE; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Eshel31100.00%1100.00%
Total31100.00%1100.00%

#ifdef CONFIG_SUNRPC_DEBUG
static inline void dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) { u32 *ptr = (u32 *)(&sessionid->data[0]); dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); }

Contributors

PersonTokensPropCommitsCommitProp
Marc Eshel6096.77%133.33%
Andy Adamson11.61%133.33%
J. Bruce Fields11.61%133.33%
Total62100.00%3100.00%

#else
static inline void dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) { }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust16100.00%1100.00%
Total16100.00%1100.00%

#endif /* * Bump the seqid on cstate->replay_owner, and clear replay_owner if it * won't be used for replay. */
void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) { struct nfs4_stateowner *so = cstate->replay_owner; if (nfserr == nfserr_replay_me) return; if (!seqid_mutating_err(ntohl(nfserr))) { nfsd4_cstate_clear_replay(cstate); return; } if (!so) return; if (so->so_is_open_owner) release_last_closed_stateid(openowner(so)); so->so_seqid++; return; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields7195.95%150.00%
Jeff Layton34.05%150.00%
Total74100.00%2100.00%


static void gen_sessionid(struct nfsd4_session *ses) { struct nfs4_client *clp = ses->se_client; struct nfsd4_sessionid *sid; sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; sid->clientid = clp->cl_clientid; sid->sequence = current_sessionid++; sid->reserved = 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson4169.49%266.67%
Marc Eshel1830.51%133.33%
Total59100.00%3100.00%

/* * The protocol defines ca_maxresponssize_cached to include the size of * the rpc header, but all we need to cache is the data starting after * the end of the initial SEQUENCE operation--the rest we regenerate * each time. Therefore we can advertise a ca_maxresponssize_cached * value that is the number of bytes in our cache plus a few additional * bytes. In order to stay on the safe side, and not promise more than * we can cache, those additional bytes must be the minimum possible: 24 * bytes of rpc header (xid through accept state, with AUTH_NULL * verifier), 12 for the compound header (with zero-length tag), and 44 * for the SEQUENCE op response: */ #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
static void free_session_slots(struct nfsd4_session *ses) { int i; for (i = 0; i < ses->se_fchannel.maxreqs; i++) kfree(ses->se_slots[i]); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields41100.00%1100.00%
Total41100.00%1100.00%

/* * We don't actually need to cache the rpc and session headers, so we * can allocate a little less for each slot: */
static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) { u32 size; if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) size = 0; else size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; return size + sizeof(struct nfsd4_slot); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields2964.44%240.00%
Andy Adamson1022.22%240.00%
Marc Eshel613.33%120.00%
Total45100.00%5100.00%

/* * XXX: If we run out of reserved DRC memory we could (up to a point) * re-negotiate active sessions and reduce their slot usage to make * room for new connections. For now we just fail the create session. */
static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) { u32 slotsize = slot_bytes(ca); u32 num = ca->maxreqs; int avail; spin_lock(&nfsd_drc_lock); avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, nfsd_drc_max_mem - nfsd_drc_mem_used); num = min_t(int, num, avail / slotsize); nfsd_drc_mem_used += num * slotsize; spin_unlock(&nfsd_drc_lock); return num; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4861.54%225.00%
Andy Adamson1417.95%450.00%
Marc Eshel1114.10%112.50%
Zhang Yanfei56.41%112.50%
Total78100.00%8100.00%


static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) { int slotsize = slot_bytes(ca); spin_lock(&nfsd_drc_lock); nfsd_drc_mem_used -= slotsize * ca->maxreqs; spin_unlock(&nfsd_drc_lock); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields3794.87%266.67%
Andy Adamson25.13%133.33%
Total39100.00%3100.00%


static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, struct nfsd4_channel_attrs *battrs) { int numslots = fattrs->maxreqs; int slotsize = slot_bytes(fattrs); struct nfsd4_session *new; int mem, i; BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) + sizeof(struct nfsd4_session) > PAGE_SIZE); mem = numslots * sizeof(struct nfsd4_slot *); new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); if (!new) return NULL; /* allocate each struct nfsd4_slot and data cache in one piece */ for (i = 0; i < numslots; i++) { new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); if (!new->se_slots[i]) goto out_free; } memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); return new; out_free: while (i--) kfree(new->se_slots[i]); kfree(new); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields13266.00%222.22%
Kinglong Mee4020.00%111.11%
Andy Adamson2110.50%444.44%
Neil Brown73.50%222.22%
Total200100.00%9100.00%


static void free_conn(struct nfsd4_conn *c) { svc_xprt_put(c->cn_xprt); kfree(c); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields23100.00%1100.00%
Total23100.00%1100.00%


static void nfsd4_conn_lost(struct svc_xpt_user *u) { struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); struct nfs4_client *clp = c->cn_session->se_client; spin_lock(&clp->cl_lock); if (!list_empty(&c->cn_persession)) { list_del(&c->cn_persession); free_conn(c); } nfsd4_probe_callback(clp); spin_unlock(&clp->cl_lock); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields84100.00%3100.00%
Total84100.00%3100.00%


static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) { struct nfsd4_conn *conn; conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); if (!conn) return NULL; svc_xprt_get(rqstp->rq_xprt); conn->cn_xprt = rqstp->rq_xprt; conn->cn_flags = flags; INIT_LIST_HEAD(&conn->cn_xpt_user.list); return conn; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields76100.00%4100.00%
Total76100.00%4100.00%


static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) { conn->cn_session = ses; list_add(&conn->cn_persession, &ses->se_conns); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields35100.00%1100.00%
Total35100.00%1100.00%


static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) { struct nfs4_client *clp = ses->se_client; spin_lock(&clp->cl_lock); __nfsd4_hash_conn(conn, ses); spin_unlock(&clp->cl_lock); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields48100.00%3100.00%
Total48100.00%3100.00%


static int nfsd4_register_conn(struct nfsd4_conn *conn) { conn->cn_xpt_user.callback = nfsd4_conn_lost; return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields32100.00%3100.00%
Total32100.00%3100.00%


static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) { int ret; nfsd4_hash_conn(conn, ses); ret = nfsd4_register_conn(conn); if (ret) /* oops; xprt is already down: */ nfsd4_conn_lost(&conn->cn_xpt_user); /* We may have gained or lost a callback channel: */ nfsd4_probe_callback_sync(ses->se_client); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4576.27%457.14%
Weston Andros Adamson711.86%114.29%
Andy Adamson711.86%228.57%
Total59100.00%7100.00%


static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) { u32 dir = NFS4_CDFC4_FORE; if (cses->flags & SESSION4_BACK_CHAN) dir |= NFS4_CDFC4_BACK; return alloc_conn(rqstp, dir); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields43100.00%2100.00%
Total43100.00%2100.00%

/* must be called under client_lock */
static void nfsd4_del_conns(struct nfsd4_session *s) { struct nfs4_client *clp = s->se_client; struct nfsd4_conn *c; spin_lock(&clp->cl_lock); while (!list_empty(&s->se_conns)) { c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); list_del_init(&c->cn_persession); spin_unlock(&clp->cl_lock); unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); free_conn(c); spin_lock(&clp->cl_lock); } spin_unlock(&clp->cl_lock); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields8880.00%228.57%
Andy Adamson1412.73%342.86%
Neil Brown87.27%228.57%
Total110100.00%7100.00%


static void __free_session(struct nfsd4_session *ses) { free_session_slots(ses); kfree(ses); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields21100.00%1100.00%
Total21100.00%1100.00%


static void free_session(struct nfsd4_session *ses) { nfsd4_del_conns(ses); nfsd4_put_drc_mem(&ses->se_fchannel); __free_session(ses); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields1344.83%550.00%
Andy Adamson931.03%220.00%
Neil Brown310.34%110.00%
Stanislav Kinsbursky26.90%110.00%
Benny Halevy26.90%110.00%
Total29100.00%10100.00%


static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) { int idx; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); new->se_client = clp; gen_sessionid(new); INIT_LIST_HEAD(&new->se_conns); new->se_cb_seq_nr = 1; new->se_flags = cses->flags; new->se_cb_prog = cses->callback_prog; new->se_cb_sec = cses->cb_sec; atomic_set(&new->se_ref, 0); idx = hash_sessionid(&new->se_sessionid); list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); spin_lock(&clp->cl_lock); list_add(&new->se_perclnt, &clp->cl_sessions); spin_unlock(&clp->cl_lock); { struct sockaddr *sa = svc_addr(rqstp); /* * This is a little silly; with sessions there's no real * use for the callback address. Use the peer address * as a reasonable default for now, but consider fixing * the rpc client not to require an address in the * future: */ rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); } }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields12462.31%1361.90%
Andy Adamson4120.60%29.52%
Stanislav Kinsbursky178.54%14.76%
Neil Brown126.03%29.52%
Olga Kornievskaia21.01%14.76%
Andrew Morton21.01%14.76%
Fengguang Wu10.50%14.76%
Total199100.00%21100.00%

/* caller must hold client_lock */
static struct nfsd4_session * __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) { struct nfsd4_session *elem; int idx; struct nfsd_net *nn = net_generic(net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); dump_sessionid(__func__, sessionid); idx = hash_sessionid(sessionid); /* Search in the appropriate list */ list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { if (!memcmp(elem->se_sessionid.data, sessionid->data, NFS4_MAX_SESSIONID_LEN)) { return elem; } } dprintk("%s: session not found\n", __func__); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson4947.12%19.09%
Neil Brown1918.27%545.45%
Stanislav Kinsbursky1817.31%19.09%
Trond Myklebust98.65%218.18%
Benny Halevy65.77%19.09%
J. Bruce Fields32.88%19.09%
Total104100.00%11100.00%


static struct nfsd4_session * find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, __be32 *ret) { struct nfsd4_session *session; __be32 status = nfserr_badsession; session = __find_in_sessionid_hashtbl(sessionid, net); if (!session) goto out; status = nfsd4_get_session_locked(session); if (status) session = NULL; out: *ret = status; return session; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust74100.00%1100.00%
Total74100.00%1100.00%

/* caller must hold client_lock */
static void unhash_session(struct nfsd4_session *ses) { struct nfs4_client *clp = ses->se_client; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); list_del(&ses->se_hash); spin_lock(&ses->se_client->cl_lock); list_del(&ses->se_perclnt); spin_unlock(&ses->se_client->cl_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust3139.74%125.00%
J. Bruce Fields2126.92%125.00%
Benny Halevy2126.92%125.00%
Stanislav Kinsbursky56.41%125.00%
Total78100.00%4100.00%

/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
static int STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) { /* * We're assuming the clid was not given out from a boot * precisely 2^32 (about 136 years) before this one. That seems * a safe assumption: */ if (clid->cl_boot == (u32)nn->boot_time) return 0; dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", clid->cl_boot, clid->cl_id, nn->boot_time); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson3975.00%250.00%
Stanislav Kinsbursky917.31%125.00%
J. Bruce Fields47.69%125.00%
Total52100.00%4100.00%

/* * XXX Should we use a slab cache ? * This type of memory management is somewhat inefficient, but we use it * anyway since SETCLIENTID is not a common operation. */
static struct nfs4_client *alloc_client(struct xdr_netobj name) { struct nfs4_client *clp; int i; clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); if (clp == NULL) return NULL; clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); if (clp->cl_name.data == NULL) goto err_no_name; clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * OWNER_HASH_SIZE, GFP_KERNEL); if (!clp->cl_ownerstr_hashtbl) goto err_no_hashtbl; for (i = 0; i < OWNER_HASH_SIZE; i++) INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); clp->cl_name.len = name.len; INIT_LIST_HEAD(&clp->cl_sessions); idr_init(&clp->cl_stateids); atomic_set(&clp->cl_refcount, 0); clp->cl_cb_state = NFSD4_CB_UNKNOWN; INIT_LIST_HEAD(&clp->cl_idhash); INIT_LIST_HEAD(&clp->cl_openowners); INIT_LIST_HEAD(&clp->cl_delegations); INIT_LIST_HEAD(&clp->cl_lru); INIT_LIST_HEAD(&clp->cl_revoked); #ifdef CONFIG_NFSD_PNFS INIT_LIST_HEAD(&clp->cl_lo_states); #endif spin_lock_init(&clp->cl_lock); rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); return clp; err_no_hashtbl: kfree(clp->cl_name.data); err_no_name: kfree(clp); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust16462.60%220.00%
Neil Brown3914.89%440.00%
Andy Adamson3212.21%110.00%
Christoph Hellwig134.96%110.00%
J. Bruce Fields93.44%110.00%
Thomas Meyer51.91%110.00%
Total262100.00%10100.00%


static void free_client(struct nfs4_client *clp) { while (!list_empty(&clp->cl_sessions)) { struct nfsd4_session *ses; ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, se_perclnt); list_del(&ses->se_perclnt); WARN_ON_ONCE(atomic_read(&ses->se_ref)); free_session(ses); } rpc_destroy_wait_queue(&clp->cl_cb_waitq); free_svc_cred(&clp->cl_cred); kfree(clp->cl_ownerstr_hashtbl); kfree(clp->cl_name.data); idr_destroy(&clp->cl_stateids); kfree(clp); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields5548.25%333.33%
Andy Adamson1815.79%111.11%
Neil Brown1815.79%222.22%
Trond Myklebust1513.16%222.22%
Jianpeng Ma (马建朋)87.02%111.11%
Total114100.00%9100.00%

/* must be called under the client_lock */
static void unhash_client_locked(struct nfs4_client *clp) { struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct nfsd4_session *ses; lockdep_assert_held(&nn->client_lock); /* Mark the client as expired! */ clp->cl_time = 0; /* Make it invisible */ if (!list_empty(&clp->cl_idhash)) { list_del_init(&clp->cl_idhash); if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) rb_erase(&clp->cl_namenode, &nn->conf_name_tree); else rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); } list_del_init(&clp->cl_lru); spin_lock(&clp->cl_lock); list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) list_del_init(&ses->se_hash); spin_unlock(&clp->cl_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust9162.33%240.00%
J. Bruce Fields2919.86%240.00%
Benny Halevy2617.81%120.00%
Total146100.00%5100.00%


static void unhash_client(struct nfs4_client *clp) { struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); spin_lock(&nn->client_lock); unhash_client_locked(clp); spin_unlock(&nn->client_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust4495.65%133.33%
Neil Brown12.17%133.33%
Andy Adamson12.17%133.33%
Total46100.00%3100.00%


static __be32 mark_client_expired_locked(struct nfs4_client *clp) { if (atomic_read(&clp->cl_refcount)) return nfserr_jukebox; unhash_client_locked(clp); return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton32100.00%1100.00%
Total32100.00%1100.00%


static void __destroy_client(struct nfs4_client *clp) { struct nfs4_openowner *oo; struct nfs4_delegation *dp; struct list_head reaplist; INIT_LIST_HEAD(&reaplist); spin_lock(&state_lock); while (!list_empty(&clp->cl_delegations)) { dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); WARN_ON(!unhash_delegation_locked(dp)); list_add(&dp->dl_recall_lru, &reaplist); } spin_unlock(&state_lock); while (!list_empty(&reaplist)) { dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); put_clnt_odstate(dp->dl_clnt_odstate); nfs4_put_deleg_lease(dp->dl_stid.sc_file); nfs4_put_stid(&dp->dl_stid); } while (!list_empty(&clp->cl_revoked)) { dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); nfs4_put_stid(&dp->dl_stid); } while (!list_empty(&clp->cl_openowners)) { oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); nfs4_get_stateowner(&oo->oo_owner); release_openowner(oo); } nfsd4_return_all_client_layouts(clp); nfsd4_shutdown_callback(clp); if (clp->cl_cb_conn.cb_xprt) svc_xprt_put(clp->cl_cb_conn.cb_xprt); free_client(clp); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson13951.87%14.55%
Benny Halevy4717.54%522.73%
Jeff Layton4115.30%522.73%
Trond Myklebust134.85%313.64%
J. Bruce Fields82.99%313.64%
Sachin Bhamare72.61%14.55%
Christoph Hellwig51.87%14.55%
Neil Brown41.49%14.55%
Andrew Elble31.12%14.55%
Kinglong Mee10.37%14.55%
Total268100.00%22100.00%


static void destroy_client(struct nfs4_client *clp) { unhash_client(clp); __destroy_client(clp); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust21100.00%1100.00%
Total21100.00%1100.00%


static void expire_client(struct nfs4_client *clp) { unhash_client(clp); nfsd4_client_record_remove(clp); __destroy_client(clp); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields2076.92%150.00%
Trond Myklebust623.08%150.00%
Total26100.00%2100.00%


static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) { memcpy(target->cl_verifier.data, source->data, sizeof(target->cl_verifier.data)); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson37100.00%1100.00%
Total37100.00%1100.00%


static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) { target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; target->cl_clientid.cl_id = source->cl_clientid.cl_id; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson40100.00%1100.00%
Total40100.00%1100.00%


int strdup_if_nonnull(char **target, char *source) { if (source) { *target = kstrdup(source, GFP_KERNEL); if (!*target) return -ENOMEM; } else *target = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4183.67%266.67%
Andy Adamson816.33%133.33%
Total49100.00%3100.00%


static int copy_cred(struct svc_cred *target, struct svc_cred *source) { int ret; ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal); if (ret) return ret; ret = strdup_if_nonnull(&target->cr_raw_principal, source->cr_raw_principal); if (ret) return ret; target->cr_flavor = source->cr_flavor; target->cr_uid = source->cr_uid; target->cr_gid = source->cr_gid; target->cr_group_info = source->cr_group_info; get_group_info(target->cr_group_info); target->cr_gss_mech = source->cr_gss_mech; if (source->cr_gss_mech) gss_mech_get(source->cr_gss_mech); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields9072.58%583.33%
Andy Adamson3427.42%116.67%
Total124100.00%6100.00%


static int compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) { if (o1->len < o2->len) return -1; if (o1->len > o2->len) return 1; return memcmp(o1->data, o2->data, o1->len); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton4472.13%150.00%
Rasmus Villemoes1727.87%150.00%
Total61100.00%2100.00%


static int same_name(const char *n1, const char *n2) { return 0 == memcmp(n1, n2, HEXDIR_LEN); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson28100.00%1100.00%
Total28100.00%1100.00%


static int same_verf(nfs4_verifier *v1, nfs4_verifier *v2) { return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson35100.00%1100.00%
Total35100.00%1100.00%


static int same_clid(clientid_t *cl1, clientid_t *cl2) { return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson35100.00%1100.00%
Total35100.00%1100.00%


static bool groups_equal(struct group_info *g1, struct group_info *g2) { int i; if (g1->ngroups != g2->ngroups) return false; for (i=0; i<g1->ngroups; i++) if (!gid_eq(g1->gid[i], g2->gid[i])) return false; return true; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields6082.19%133.33%
Alexey Dobriyan810.96%133.33%
Eric W. Biedermann56.85%133.33%
Total73100.00%3100.00%

/* * RFC 3530 language requires clid_inuse be returned when the * "principal" associated with a requests differs from that previously * used. We use uid, gid's, and gss principal string as our best * approximation. We also don't want to allow non-gss use of a client * established using gss: in theory cr_principal should catch that * change, but in practice cr_principal can be null even in the gss case * since gssd doesn't always pass down a principal string. */
static bool is_gss_cred(struct svc_cred *cr) { /* Is cr_flavor one of the gss "pseudoflavors"?: */ return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields21100.00%1100.00%
Total21100.00%1100.00%


static bool same_creds(struct svc_cred *cr1, struct svc_cred *cr2) { if ((is_gss_cred(cr1) != is_gss_cred(cr2)) || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) return false; if (cr1->cr_principal == cr2->cr_principal) return true; if (!cr1->cr_principal || !cr2->cr_principal) return false; return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields8069.57%350.00%
Andy Adamson2320.00%116.67%
Eric W. Biedermann108.70%116.67%
Vivek Trivedi21.74%116.67%
Total115100.00%6100.00%


static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) { struct svc_cred *cr = &rqstp->rq_cred; u32 service; if (!cr->cr_gss_mech) return false; service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); return service == RPC_GSS_SVC_INTEGRITY || service == RPC_GSS_SVC_PRIVACY; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields56100.00%2100.00%
Total56100.00%2100.00%


bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) { struct svc_cred *cr = &rqstp->rq_cred; if (!cl->cl_mach_cred) return true; if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) return false; if (!svc_rqst_integrity_protected(rqstp)) return false; if (cl->cl_cred.cr_raw_principal) return 0 == strcmp(cl->cl_cred.cr_raw_principal, cr->cr_raw_principal); if (!cr->cr_principal) return false; return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields11099.10%266.67%
Andrew Elble10.90%133.33%
Total111100.00%3100.00%


static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) { __be32 verf[2]; /* * This is opaque to client, so no need to byte-swap. Use * __force to keep sparse happy */ verf[0] = (__force __be32)get_seconds(); verf[1] = (__force __be32)nn->clverifier_counter++; memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); }

Contributors

PersonTokensPropCommitsCommitProp
Chuck Lever3855.07%116.67%
Andy Adamson1826.09%116.67%
Jeff Layton68.70%233.33%
Stanislav Kinsbursky57.25%116.67%
Kinglong Mee22.90%116.67%
Total69100.00%6100.00%


static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) { clp->cl_clientid.cl_boot = nn->boot_time; clp->cl_clientid.cl_id = nn->clientid_counter++; gen_confirm(clp, nn); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton44100.00%1100.00%
Total44100.00%1100.00%


static struct nfs4_stid * find_stateid_locked(struct nfs4_client *cl, stateid_t *t) { struct nfs4_stid *ret; ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); if (!ret || !ret->sc_type) return NULL; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields5398.15%685.71%
Jeff Layton11.85%114.29%
Total54100.00%7100.00%


static struct nfs4_stid * find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) { struct nfs4_stid *s; spin_lock(&cl->cl_lock); s = find_stateid_locked(cl, t); if (s != NULL) { if (typemask & s->sc_type) atomic_inc(&s->sc_count); else s = NULL; } spin_unlock(&cl->cl_lock); return s; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4656.10%675.00%
Jeff Layton2226.83%112.50%
Trond Myklebust1417.07%112.50%
Total82100.00%8100.00%


static struct nfs4_client *create_client(struct xdr_netobj name, struct svc_rqst *rqstp, nfs4_verifier *verf) { struct nfs4_client *clp; struct sockaddr *sa = svc_addr(rqstp); int ret; struct net *net = SVC_NET(rqstp); clp = alloc_client(name); if (clp == NULL) return NULL; ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); if (ret) { free_client(clp); return NULL; } nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); copy_verf(clp, verf); rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); clp->cl_cb_session = NULL; clp->net = net; return clp; }

Contributors

PersonTokensPropCommitsCommitProp
Ricardo Labiaga8351.23%111.11%
Andy Adamson2716.67%111.11%
J. Bruce Fields1710.49%222.22%
Stanislav Kinsbursky169.88%111.11%
Christoph Hellwig116.79%222.22%
Benny Halevy74.32%111.11%
Jeff Layton10.62%111.11%
Total162100.00%9100.00%


static void add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) { struct rb_node **new = &(root->rb_node), *parent = NULL; struct nfs4_client *clp; while (*new) { clp = rb_entry(*new, struct nfs4_client, cl_namenode); parent = *new; if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) new = &((*new)->rb_left); else new = &((*new)->rb_right); } rb_link_node(&new_clp->cl_namenode, parent, new); rb_insert_color(&new_clp->cl_namenode, root); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton12698.44%150.00%
Andy Adamson21.56%150.00%
Total128100.00%2100.00%


static struct nfs4_client * find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) { int cmp; struct rb_node *node = root->rb_node; struct nfs4_client *clp; while (node) { clp = rb_entry(node, struct nfs4_client, cl_namenode); cmp = compare_blob(&clp->cl_name, name); if (cmp > 0) node = node->rb_left; else if (cmp < 0) node = node->rb_right; else return clp; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton9698.97%150.00%
Rasmus Villemoes11.03%150.00%
Total97100.00%2100.00%


static void add_to_unconfirmed(struct nfs4_client *clp) { unsigned int idhashval; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); add_clp_to_name_tree(clp, &nn->unconf_name_tree); idhashval = clientid_hashval(clp->cl_clientid.cl_id); list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); renew_client_locked(clp); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson5056.18%116.67%
Stanislav Kinsbursky1820.22%233.33%
Jeff Layton1213.48%116.67%
Trond Myklebust910.11%233.33%
Total89100.00%6100.00%


static void move_to_confirmed(struct nfs4_client *clp) { unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); lockdep_assert_held(&nn->client_lock); dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); add_clp_to_name_tree(clp, &nn->conf_name_tree); set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); renew_client_locked(clp); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson6056.07%114.29%
Stanislav Kinsbursky2018.69%342.86%
Jeff Layton1816.82%114.29%
Trond Myklebust98.41%228.57%
Total107100.00%7100.00%


static struct nfs4_client * find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) { struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) { if ((bool)clp->cl_minorversion != sessions) return NULL; renew_client_locked(clp); return clp; } } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson5463.53%120.00%
J. Bruce Fields3035.29%360.00%
Trond Myklebust11.18%120.00%
Total85100.00%5100.00%


static struct nfs4_client * find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) { struct list_head *tbl = nn->conf_id_hashtbl; lockdep_assert_held(&nn->client_lock); return find_client_in_id_table(tbl, clid, sessions); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson1940.43%120.00%
J. Bruce Fields1531.91%240.00%
Trond Myklebust817.02%120.00%
Stanislav Kinsbursky510.64%120.00%
Total47100.00%5100.00%


static struct nfs4_client * find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) { struct list_head *tbl = nn->unconf_id_hashtbl; lockdep_assert_held(&nn->client_lock); return find_client_in_id_table(tbl, clid, sessions); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields3370.21%250.00%
Trond Myklebust817.02%125.00%
Andy Adamson612.77%125.00%
Total47100.00%4100.00%


static bool clp_used_exchangeid(struct nfs4_client *clp) { return clp->cl_exchange_flags != 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson1583.33%150.00%
J. Bruce Fields316.67%150.00%
Total18100.00%2100.00%


static struct nfs4_client * find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) { lockdep_assert_held(&nn->client_lock); return find_clp_in_name_tree(name, &nn->conf_name_tree); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson1129.73%120.00%
Jeff Layton924.32%120.00%
Trond Myklebust821.62%120.00%
Stanislav Kinsbursky718.92%120.00%
Neil Brown25.41%120.00%
Total37100.00%5100.00%


static struct nfs4_client * find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) { lockdep_assert_held(&nn->client_lock); return find_clp_in_name_tree(name, &nn->unconf_name_tree); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Layton924.32%120.00%
Trond Myklebust821.62%120.00%
Andy Adamson718.92%120.00%
Stanislav Kinsbursky718.92%120.00%
Neil Brown616.22%120.00%
Total37100.00%5100.00%


static void gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) { struct nfs4_cb_conn *conn = &clp->cl_cb_conn; struct sockaddr *sa = svc_addr(rqstp); u32 scopeid = rpc_get_scope_id(sa); unsigned short expected_family; /* Currently, we only support tcp and tcp6 for the callback channel */ if (se->se_callback_netid_len == 3 && !memcmp(se->se_callback_netid_val, "tcp", 3)) expected_family = AF_INET; else if (se->se_callback_netid_len == 4 && !memcmp(se->se_callback_netid_val, "tcp6", 4)) expected_family = AF_INET6; else goto out_err; conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, se->se_callback_addr_len, (struct sockaddr *)&conn->cb_addr, sizeof(conn->cb_addr)); if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) goto out_err; if (conn->cb_addr.ss_family == AF_INET6) ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; conn->cb_prog = se->se_callback_prog; conn->cb_ident = se->se_callback_ident; memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); return; out_err: conn->cb_addr.ss_family = AF_UNSPEC; conn->cb_addrlen = 0; dprintk("NFSD: this client (clientid %08x/%08x) " "will not receive delegations\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); return; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson9436.72%320.00%
Jeff Layton7830.47%320.00%
Takuma Umeya3413.28%16.67%
Neil Brown2710.55%320.00%
J. Bruce Fields145.47%213.33%
Mi Jinlong51.95%16.67%
Stanislav Kinsbursky41.56%213.33%
Total256100.00%15100.00%

/* * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. */
static void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) { struct xdr_buf *buf = resp->xdr.buf; struct nfsd4_slot *slot = resp->cstate.slot; unsigned int base; dprintk("--> %s slot %p\n", __func__, slot); slot->sl_opcnt = resp->opcnt; slot->sl_status = resp->cstate.status; slot->sl_flags |= NFSD4_SLOT_INITIALIZED; if (nfsd4_not_cached(resp)) { slot->sl_datalen = 0; return; } base = resp->cstate.data_offset; slot->sl_datalen = buf->len - base; if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) WARN(1, "%s: sessions DRC could not cache compound\n", __func__); return; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson8665.65%333.33%
J. Bruce Fields2720.61%333.33%
Neil Brown1511.45%111.11%
Dan Carpenter21.53%111.11%
Trond Myklebust10.76%111.11%
Total131100.00%9100.00%

/* * 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; /* 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_flags & NFSD4_SLOT_CACHETHIS)) { op = &args->ops[resp->opcnt++]; op->status = nfserr_retry_uncached_rep; nfsd4_encode_operation(resp, op); } return op->status; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson8379.05%240.00%
Neil Brown1615.24%240.00%
J. Bruce Fields65.71%120.00%
Total105100.00%5100.00%

/* * The sequence operation is not cached because we can use the slot and * session values. */
static __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, struct nfsd4_sequence *seq) { struct nfsd4_slot *slot = resp->cstate.slot; struct xdr_stream *xdr = &resp->xdr; __be32 *p; __be32 status; dprintk("--> %s slot %p\n", __func__, slot); status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); if (status) return status; p = xdr_reserve_space(xdr, slot->sl_datalen); if (!p) { WARN_ON_ONCE(1); return nfserr_serverfault; } xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); xdr_commit_encode(xdr); resp->opcnt = slot->sl_opcnt; return slot->sl_status; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson5743.85%550.00%
J. Bruce Fields5340.77%330.00%
Neil Brown2015.38%220.00%
Total130100.00%10100.00%

/* * Set the exchange_id flags returned by the server. */
static void nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) { #ifdef CONFIG_NFSD_PNFS new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; #else new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; #endif /* Referrals are supported, Migration is not. */ new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; /* set the wire flags to return to client. */ clid->flags = new->cl_exchange_flags; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson3874.51%266.67%
Christoph Hellwig1325.49%133.33%
Total51100.00%3100.00%


static bool client_has_openowners(struct nfs4_client *clp) { struct nfs4_openowner *oo; list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { if (!list_empty(&oo->oo_owner.so_stateids)) return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4293.33%375.00%
Andy Adamson36.67%125.00%
Total45100.00%4100.00%


static bool client_has_state(struct nfs4_client *clp) { return client_has_openowners(clp) #ifdef CONFIG_NFSD_PNFS || !list_empty(&clp->cl_lo_states) #endif || !list_empty(&clp->cl_delegations) || !list_empty(&clp->cl_sessions); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields3571.43%375.00%
Kinglong Mee1428.57%125.00%
Total49100.00%4100.00%


__be32 nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_exchange_id *exid) { struct nfs4_client *conf, *new; struct nfs4_client *unconf = NULL; __be32 status; char addr_str[INET6_ADDRSTRLEN]; nfs4_verifier verf = exid->verifier; struct sockaddr *sa = svc_addr(rqstp); bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); rpc_ntop(sa, addr_str, sizeof(addr_str)); dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " "ip_addr=%s flags %x, spa_how %d\n", __func__, rqstp, exid, exid->clname.len, exid->clname.data, addr_str, exid->flags, exid->spa_how); if (exid->flags & ~EXCHGID4_FLAG_MASK_A) return nfserr_inval; new = create_client(exid->clname, rqstp, &verf); if (new == NULL) return nfserr_jukebox; switch (exid->spa_how) { case SP4_MACH_CRED: exid->spo_must_enforce[0] = 0; exid->spo_must_enforce[1] = ( 1 << (OP_BIND_CONN_TO_SESSION - 32) | 1 << (OP_EXCHANGE_ID - 32) | 1 << (OP_CREATE_SESSION - 32) | 1 << (OP_DESTROY_SESSION - 32) | 1 << (OP_DESTROY_CLIENTID - 32)); exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 1 << (OP_OPEN_DOWNGRADE) | 1 << (OP_LOCKU) | 1 << (OP_DELEGRETURN)); exid->spo_must_allow[1] &= ( 1 << (OP_TEST_STATEID - 32) | 1 << (OP_FREE_STATEID - 32)); if (!svc_rqst_integrity_protected(rqstp)) { status = nfserr_inval; goto out_nolock; } /* * Sometimes userspace doesn't give us a principal. * Which is a bug, really. Anyway, we can't enforce * MACH_CRED in that case, better to give up now: */ if (!new->cl_cred.cr_principal && !new->cl_cred.cr_raw_principal) { status = nfserr_serverfault; goto out_nolock; } new->cl_mach_cred = true; case SP4_NONE: break; default: /* checked by xdr code */ WARN_ON_ONCE(1); case SP4_SSV: status = nfserr_encr_alg_unsupp; goto out_nolock; } /* Cases below refer to rfc 5661 section 18.35.4: */ spin_lock(&nn->client_lock); conf = find_confirmed_client_by_name(&exid->clname, nn); if (conf) { bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); bool verfs_match = same_verf(&verf, &conf->cl_verifier); if (update) { if (!clp_used_exchangeid(conf)) { /* buggy client */ status = nfserr_inval; goto out; } if (!nfsd4_mach_creds_match(conf, rqstp)) { status = nfserr_wrong_cred; goto out; } if (!creds_match) { /* case 9 */ status = nfserr_perm; goto out; } if (!verfs_match) { /* case 8 */ status = nfserr_not_same; goto out; } /* case 6 */ exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; goto out_copy; } if (!creds_match) { /* case 3 */ if (client_has_state(conf)) { status = nfserr_clid_inuse; goto out; } goto out_new; } if (verfs_match) { /* case 2 */ conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; goto out_copy; } /* case 5, client reboot */ conf = NULL; goto out_new; } if (update) { /* case 7 */ status = nfserr_noent; goto out; } unconf = find_unconfirmed_client_by_name(&exid->clname, nn); if (unconf) /* case 4, possible retry or client restart */ unhash_client_locked(unconf); /* case 1 (normal case) */ out_new: if (conf) { status = mark_client_expired_locked(conf); if (status) goto out; } new->cl_minorversion = cstate->minorversion; new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; gen_clid(new, nn); add_to_unconfirmed(new); swap(new, conf); out_copy: exid->clientid.cl_boot = conf->cl_clientid.cl_boot; exid->clientid.cl_id = conf->cl_clientid.cl_id; exid->seqid = conf->cl_cs_slot.sl_seqid + 1; nfsd4_set_ex_flags(conf, exid); dprintk("nfsd4_exchange_id seqid %d flags %x\n", conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); status = nfs_ok; out: spin_unlock(&nn->client_lock); out_nolock: if (new) expire_client(new); if (unconf) expire_client(unconf); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson26534.28%617.14%
J. Bruce Fields21527.81%1851.43%
Andrew Elble15319.79%25.71%
Trond Myklebust678.67%25.71%
Jeff Layton465.95%38.57%
Stanislav Kinsbursky212.72%38.57%
Kinglong Mee60.78%12.86%
Total773100.00%35100.00%


static __be32 check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) { 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_inuse) { if (seqid == slot_seqid) return nfserr_jukebox; else return nfserr_seq_misordered; } /* Note unsigned 32-bit arithmetic handles wraparound: */ if (likely(seqid == slot_seqid + 1)) return nfs_ok; if (seqid == slot_seqid) return nfserr_replay_cache; return nfserr_seq_misordered; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson7197.26%466.67%
J. Bruce Fields22.74%233.33%
Total73100.00%6100.00%

/* * 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, __be32 nfserr) { slot->sl_status = nfserr; memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson4097.56%150.00%
J. Bruce Fields12.44%150.00%
Total41100.00%2100.00%


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; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Adamson37100.00%1100.00%
Total37100.00%1100.00%

#define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 1 + /* MIN tag is length with zero, only length */ \ 3 + /* version, opcount, opcode */ \ XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ /* seqid, slotID, slotID, cache */ \ 4 ) * sizeof(__be32)) #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 2 + /* verifier: AUTH_NULL, length 0 */\ 1 + /* status */ \ 1 + /* MIN tag is length with zero, only length */ \ 3 + /* opcount, opcode, opstatus*/ \ XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ /* seqid, slotID, slotID, slotID, status */ \ 5 ) * sizeof(__be32))
static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) { u32 maxrpc = nn->nfsd_serv->sv_max_mesg; if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) return nfserr_toosmall; if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) return nfserr_toosmall; ca->headerpadsz = 0; ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); ca->maxresp_cached = min_t(u32, ca->maxresp_cached, NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); /* * Note decreasing slot size below client's request may make it * difficult for client to function correctly, whereas * decreasing the number of slots will (just?) affect * performance. When short on memory we therefore prefer to * decrease number of slots instead of their size. Clients that * request larger slots than they need will get poor results: */ ca->maxreqs = nfsd4_get_drc_mem(ca); if (!ca->maxreqs) return nfserr_jukebox; return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields13890.20%266.67%
Mi Jinlong159.80%133.33%
Total153100.00%3100.00%

/* * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. * These are based on similar macros in linux/sunrpc/msg_prot.h . */ #define RPC_MAX_HEADER_WITH_AUTH_SYS \ (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ sizeof(__be32))
static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) { ca->headerpadsz = 0; if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) return nfserr_toosmall; if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) return nfserr_toosmall; ca->maxresp_cached = 0; if (ca->maxops < 2) return nfserr_toosmall; return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields4983.05%133.33%
Mi Jinlong813.56%133.33%
Kinglong Mee23.39%133.33%
Total59100.00%3100.00%


static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) { switch (cbs->flavor) { case RPC_AUTH_NULL: case RPC_AUTH_UNIX: return nfs_ok; default: /* * GSS case: the spec doesn't allow us to return this * error. But it also doesn't allow us not to support * GSS. * I'd rather this fail hard than return some error the * client might think it can already handle: */ return nfserr_encr_alg_unsupp; } }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields33100.00%1100.00%
Total33100.00%1100.00%


__be32 nfsd4_create_session(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_create_session *cr_ses) { struct sockaddr *sa = svc_addr(rqstp); struct nfs4_client *conf, *unconf; struct nfs4_client *old = NULL; struct nfsd4_session *new; struct nfsd4_conn *conn; struct nfsd4_clid_slot *cs_slot = NULL; __be32 status = 0; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) return nfserr_inval; status = nfsd4_check_cb_sec(&cr_ses->cb_sec); if (status) return status; status = check_forechannel_attrs(&cr_ses->fore_channel, nn); if (status) return status; status = check_backchannel_attrs(&cr_ses->back_channel); if (status) goto out_release_drc_mem; status = nfserr_jukebox; new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); if (!new) goto out_release_drc_mem; conn = alloc_conn_from_crses(rqstp, cr_ses); if (!conn) goto out_free_session; spin_lock(&nn->client_lock); unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); conf = find_confirmed_client(&cr_ses->clientid, true, nn); WARN_ON_ONCE(conf && unconf); if (conf) { status = nfserr_wrong_cred; if (!nfsd4_mach_creds_match(conf, rqstp)) goto out_free_conn; cs_slot = &conf->cl_cs_slot; status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); if (status) { if (status == nfserr_replay_cache) status = nfsd4_replay_create_session(cr_ses, cs_slot); goto out_free_conn; } } else if (unconf) { if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { status = nfserr_clid_inuse; goto out_free_conn; } status = nfserr_wrong_cred; if (!nfsd4_mach_creds_match(unconf, rqstp)) goto out_free_conn; 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_free_conn; } old = find_confirmed_client_by_name(&unconf->cl_name, nn); if (old) { status = mark_client_expired_locked(old); if (status) { old = NULL; goto out_free_conn; } } move_to_confirmed(unconf); conf = unconf; } else { status = nfserr_stale_clientid; goto out_free_conn; } status = nfs_ok; /* Persistent sessions are not supported */ cr_ses->flags &= ~SESSION4_PERSIST; /* Upshifting from TCP to RDMA is not supported */ cr_ses->flags &= ~SESSION4_RDMA; init_session(rqstp, new, conf, cr_ses); nfsd4_get_session_locked(new); memcpy(cr_ses->sessionid.data, new->se_sessionid.data, NFS4_MAX_SESSIONID_LEN); cs_slot->sl_seqid++; cr_ses->seqid = cs_slot->sl_seqid; /* cache solo and embedded create sessions under the client_lock */ nfsd4_cache_create_session(cr_ses, cs_slot, status); spin_unlock(&nn->client_lock); /* init connection and backchannel */ nfsd4_init_conn(rqstp, conn, new); nfsd4_put_session(new); if (old) expire_client(old); return status; out_free_conn: spin_unlock(&nn->client_lock); free_conn(conn); if (old) expire_client(old); out_free_session: __free_session(new); out_release_drc_mem: nfsd4_put_drc_mem(&cr_ses->fore_channel); return status; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields23838.64%1845.00%
Andy Adamson23538.15%820.00%
Jeff Layton9014.61%410.00%
Stanislav Kinsbursky213.41%37.50%
Kinglong Mee132.11%37.50%
Mi Jinlong121.95%12.50%
Ricardo Labiaga30.49%12.50%
Chuck Lever20.32%12.50%
Andrew Elble20.32%12.50%
Total616100.00%40100.00%


static __be32 nfsd4_map_bcts_dir(u32 *dir) { switch (*dir) { case NFS4_CDFC4_FORE: case NFS4_CDFC4_BACK: return nfs_ok; case NFS4_CDFC4_FORE_OR_BOTH: case NFS4_CDFC4_BACK_OR_BOTH: *dir = NFS4_CDFC4_BOTH; return nfs_ok; }; return nfserr_inval; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields44100.00%1100.00%
Total44100.00%1100.00%


__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) { struct nfsd4_session *session = cstate->session; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); __be32 status; status = nfsd4_check_cb_sec(&bc->bc_cb_sec); if (status) return status; spin_lock(&nn->client_lock); session->se_cb_prog = bc->bc_cb_program; session->se_cb_sec = bc->bc_cb_sec; spin_unlock(&nn->client_lock); nfsd4_probe_callback(session->se_client); return nfs_ok; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields8782.08%266.67%
Stanislav Kinsbursky1917.92%133.33%
Total106100.00%3100.00%


__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_bind_conn_to_session *bcts) { __be32 status; struct nfsd4_conn *conn; struct nfsd4_session *session; struct net *net = SVC_NET(rqstp); struct nfsd_net *nn = net_generic(net, nfsd_net_id); if (!nfsd4_last_compound_op(rqstp)) return nfserr_not_only_op; spin_lock(&nn->client_lock); session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); spin_unlock(&nn->client_lock); if (!session) goto out_no_session; status = nfserr_wrong_cred; if (!nfsd4_mach_creds_match(session->se_client, rqstp)) goto out; status = nfsd4_map_bcts_dir(&bcts->dir); if (status) goto out; conn = alloc_conn(rqstp, bcts->dir); status = nfserr_jukebox; if (!conn) goto out; nfsd4_init_conn(rqstp, conn, session); status = nfs_ok; out: nfsd4_put_session(session); out_no_session: return status; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields14576.72%444.44%
Trond Myklebust2312.17%111.11%
Stanislav Kinsbursky168.47%222.22%
Bryan Schumaker42.12%111.11%
Andrew Elble10.53%111.11%
Total189100.00%9100.00%


static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) { if (!session) return 0; return !memcmp(sid, &session->se_sessionid, sizeof(*sid)); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields42100.00%1100.00%
Total42100.00%1100.00%


__be32 nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_session *sessionid) { struct nfsd4_session *ses; __be32 status; int ref_held_by_me = 0; struct net *net = SVC_NET(r); struct nfsd_net *nn = net_generic(net, nfsd_net_id); status = nfserr_not_only_op; if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { if (!nfsd4_last_compound_op(r)) goto out; ref_held_by_me++; } dump_sessionid(__func__, &sessionid->sessionid); spin_lock(&nn->client_lock); ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status); if (!ses) goto out_client_lock; status = nfserr_wrong_cred; if (!nfsd4_mach_creds_match(ses->se_client, r)) goto out_put_session; status = mark_session_dead_locked(ses, 1 + ref_held_by_me); if (status) goto out_put_session; unhash_session(ses); spin_unlock(&nn->client_lock); nfsd4_probe_callback_sync(ses->se_client); spin_lock(&nn->client_lock); status = nfs_ok; out_put_session: nfsd4_put_session_locked(ses); out_client_lock: spin_unlock(&nn->client_lock); out: return status; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields8538.46%850.00%
Benny Halevy7634.39%318.75%
Andy Adamson229.95%16.25%
Stanislav Kinsbursky209.05%212.50%
Trond Myklebust177.69%16.25%
Andrew Elble10.45%16.25%
Total221100.00%16100.00%


static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) { struct nfsd4_conn *c; list_for_each_entry(c, &s->se_conns, cn_persession) { if (c->cn_xprt == xpt) { return c; } } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields49100.00%2100.00%
Total49100.00%2100.00%


static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) { struct nfs4_client *clp = ses->se_client; struct nfsd4_conn *c; __be32 status = nfs_ok; int ret; spin_lock(&clp->cl_lock); c = __nfsd4_find_conn(new->cn_xprt, ses); if (c) goto out_free; status = nfserr_conn_not_bound_to_session; if (clp->cl_mach_cred) goto out_free; __nfsd4_hash_conn(new, ses); spin_unlock(&clp->cl_lock); ret = nfsd4_register_conn(new); if (ret) /* oops; xprt is already down: */ nfsd4_conn_lost(&new->cn_xpt_user); return nfs_ok; out_free: spin_unlock(&clp->cl_lock); free_conn(new); return status; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields133100.00%4100.00%
Total133100.00%4100.00%


static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) { struct nfsd4_compoundargs *args = rqstp->rq_argp; return args->opcnt > session->se_fchannel.maxops; }

Contributors

PersonTokensPropCommitsCommitProp
Mi Jinlong36100.00%1100.00%
Total36100.00%1100.00%


static bool nfsd4_request_too_big(struct svc_rqst *rqstp, struct nfsd4_session *session) { struct xdr_buf *xb = &rqstp->rq_arg; return xb->len > session->se_fchannel.maxreq_sz; }

Contributors

PersonTokensPropCommitsCommitProp
Mi Jinlong37100.00%1100.00%
Total37100.00%1100.00%


__be32 nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_sequence *seq) { struct nfsd4_compoundres *resp = rqstp->rq_resp; struct xdr_stream *xdr = &resp->xdr; struct nfsd4_session *session; struct nfs4_client *clp; struct nfsd4_slot *slot; struct nfsd4_conn *conn; __be32 status; int buflen; struct net *net = SVC_NET(rqstp); struct nfsd_net *nn = net_generic(net, nfsd_net_id); if (resp->opcnt != 1) return nfserr_sequence_pos; /* * Will be either used or freed by nfsd4_sequence_check_conn * below. */ conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); if (!conn) return nfserr_jukebox; spin_lock(&nn->client_lock); session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); if (!session) goto out_no_session; clp = session->se_client; status = nfserr_too_many_ops; if (nfsd4_session_too_many_ops(rqstp, session)) goto out_put_session; status = nfserr_req_too_big; if (nfsd4_request_too_big(rqstp, session)) goto out_put_session; status = nfserr_badslot; if (seq->slotid >= session->se_fchannel.maxreqs) goto out_put_session; slot = session->se_slots[seq->slotid]; dprintk("%s: slotid %d\n", __func__, seq->slotid); /* We do not negotiate the number of slots yet, so set the * maxslots to the session maxreqs which is used to encode * sr_highest_slotid and the sr_target_slot id to maxslots */ seq->maxslots = session->se_fchannel.maxreqs; status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_flags & NFSD4_SLOT_INUSE); if (status == nfserr_replay_cache) { status = nfserr_seq_misordered; if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) goto out_put_session; cstate->slot = slot; cstate->session = session; cstate->clp = clp; /* Return the cached reply status and set cstate->status * for nfsd4_proc_compound processing */ status = nfsd4_replay_cache_entry(resp, seq); cstate->status = nfserr_replay_cache; goto out; } if (status) goto out_put_session; status = nfsd4_sequence_check_conn(conn, session); conn = NULL; if (status) goto out_put_session; buflen = (seq->cachethis) ? session->se_fchannel.maxresp_cached : session->se_fchannel.maxresp_sz; status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : nfserr_rep_too_big; if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) goto out_put_session; svc_reserve(rqstp, buflen); status = nfs_ok; /* Success! bump slot seqid */ slot->sl_seqid = seq->seqid; slot->sl_flags |= NFSD4_SLOT_INUSE; if (seq->cachethis) slot->sl_flags |= NFSD4_SLOT_CACHETHIS; else slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; cstate->slot = slot; cstate->session = session; cstate->clp = clp; out: switch (clp->cl_cb_state) { case NFSD4_CB_DOWN: seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; break; case NFSD4_CB_FAULT: seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; break; default: seq->status_flags = 0; } if (!list_empty(&clp->cl_revoked)) seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; out_no_session: if (conn) free_conn(conn); spin_unlock(&nn->client_lock); return status; out_put_session: nfsd4_put_session_locked(session); goto out_no_session; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields21940.26%1440.00%
Benny Halevy16430.15%617.14%
Andy Adamson7914.52%720.00%
Mi Jinlong305.51%25.71%
Stanislav Kinsbursky162.94%25.71%
Trond Myklebust162.94%12.86%
Jeff Layton122.21%12.86%
Kinglong Mee50.92%12.86%
Alexandros Batsakis30.55%12.86%
Total544100.00%35100.00%


void nfsd4_sequence_done(struct nfsd4_compoundres *resp) { struct nfsd4_compound_state *cs = &resp->cstate; if (nfsd4_has_session(cs)) { if (cs->status != nfserr_replay_cache) { nfsd4_store_cache_entry(resp); cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; } /* Drop session reference that was taken in nfsd4_sequence() */ nfsd4_put_session(cs->session); } else if (cs->clp) put_client_renew(cs->clp); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust6181.33%266.67%
Jeff Layton1418.67%133.33%
Total75100.00%3100.00%


__be32 nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) { struct nfs4_client *conf, *unconf; struct nfs4_client *clp = NULL; __be32 status = 0; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); spin_lock(&nn->client_lock); unconf = find_unconfirmed_client(&dc->clientid, true, nn); conf = find_confirmed_client(&dc->clientid, true, nn); WARN_ON_ONCE(conf && unconf); if (conf) { if (client_has_state(conf)) { status = nfserr_clientid_busy; goto out; } status = mark_client_expired_locked(conf); if (status) goto out; clp = conf; } else if (unconf) clp = unconf; else { status = nfserr_stale_clientid; goto out; } if (!nfsd4_mach_creds_match(clp, rqstp)) { clp = NULL; status = nfserr_wrong_cred; goto out; } unhash_client_locked(clp); out: spin_unlock(&nn->client_lock); if (clp) expire_client(clp); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Mi Jinlong10349.76%19.09%
Trond Myklebust3918.84%19.09%
J. Bruce Fields3114.98%545.45%
Stanislav Kinsbursky199.18%218.18%
Jeff Layton146.76%19.09%
Andrew Elble10.48%19.09%
Total207100.00%11100.00%


__be32 nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) { __be32 status = 0; if (rc->rca_one_fs) { if (!cstate->current_fh.fh_dentry) return nfserr_nofilehandle; /* * We don't take advantage of the rca_one_fs case. * That's OK, it's optional, we can safely ignore it. */ return nfs_ok; } status = nfserr_complete_already; if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->session->se_client->cl_flags)) goto out; status = nfserr_stale_clientid; if (is_client_expired(cstate->session->se_client)) /* * The following error isn't really legal. * But we only get here if the client just explicitly * destroyed the client. Surely it no longer cares what * error it gets back on an operation for the dead * client. */ goto out; status = nfs_ok; nfsd4_client_record_create(cstate->session->se_client); out: return status; }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields6660.55%233.33%
Mi Jinlong3431.19%116.67%
Jeff Layton87.34%233.33%
Andy Adamson10.92%116.67%
Total109100.00%6100.00%


__be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setclientid *setclid) { struct xdr_netobj clname = setclid->se_name; nfs4_verifier clverifier = setclid->se_verf; struct nfs4_client *