#include <linux/slab.h>
#include <linux/namei.h>
#include <linux/swap.h>
+#include <linux/pagemap.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/clnt.h>
#include "xdr4.h"
/* forward declarations */
static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
+static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
+static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
-static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
-static void nfs4_set_recdir(char *recdir);
+static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner);
/* Locking: */
* Open owner state (share locks)
*/
-/* hash tables for nfs4_stateowner */
-#define OWNER_HASH_BITS 8
-#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
-#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
+/* hash tables for open owners */
+#define OPEN_OWNER_HASH_BITS 8
+#define OPEN_OWNER_HASH_SIZE (1 << OPEN_OWNER_HASH_BITS)
+#define OPEN_OWNER_HASH_MASK (OPEN_OWNER_HASH_SIZE - 1)
-#define ownerid_hashval(id) \
- ((id) & OWNER_HASH_MASK)
-#define ownerstr_hashval(clientid, ownername) \
- (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
+static unsigned int open_ownerid_hashval(const u32 id)
+{
+ return id & OPEN_OWNER_HASH_MASK;
+}
+
+static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
+{
+ unsigned int ret;
-static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
-static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
+ ret = opaque_hashval(ownername->data, ownername->len);
+ ret += clientid;
+ return ret & OPEN_OWNER_HASH_MASK;
+}
+
+static struct list_head open_ownerid_hashtbl[OPEN_OWNER_HASH_SIZE];
+static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
/* hash table for nfs4_file */
#define FILE_HASH_BITS 8
#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)
#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)
-#define file_hashval(x) \
- hash_ptr(x, FILE_HASH_BITS)
-#define stateid_hashval(owner_id, file_id) \
- (((owner_id) + (file_id)) & STATEID_HASH_MASK)
+static unsigned int file_hashval(struct inode *ino)
+{
+ /* XXX: why are we hashing on inode pointer, anyway? */
+ return hash_ptr(ino, FILE_HASH_BITS);
+}
+
+static unsigned int stateid_hashval(u32 owner_id, u32 file_id)
+{
+ return (owner_id + file_id) & STATEID_HASH_MASK;
+}
static struct list_head file_hashtbl[FILE_HASH_SIZE];
static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
#define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS)
#define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1)
-#define clientid_hashval(id) \
- ((id) & CLIENT_HASH_MASK)
-#define clientstr_hashval(name) \
- (opaque_hashval((name), 8) & CLIENT_HASH_MASK)
+static unsigned int clientid_hashval(u32 id)
+{
+ return id & CLIENT_HASH_MASK;
+}
+
+static unsigned int clientstr_hashval(const char *name)
+{
+ return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
+}
+
/*
* reclaim_str_hashtbl[] holds known client info from previous reset/reboot
* used in reboot/reset lease grace period processing
BUG();
}
-static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp)
-{
- unsigned int access;
-
- set_access(&access, stp->st_access_bmap);
- return nfs4_access_to_omode(access);
-}
-
static void unhash_generic_stateid(struct nfs4_stateid *stp)
{
list_del(&stp->st_hash);
static void free_generic_stateid(struct nfs4_stateid *stp)
{
- int oflag;
+ int i;
if (stp->st_access_bmap) {
- oflag = nfs4_access_bmap_to_omode(stp);
- nfs4_file_put_access(stp->st_file, oflag);
+ for (i = 1; i < 4; i++) {
+ if (test_bit(i, &stp->st_access_bmap))
+ nfs4_file_put_access(stp->st_file,
+ nfs4_access_to_omode(i));
+ }
}
put_nfs4_file(stp->st_file);
kmem_cache_free(stateid_slab, stp);
return slot->sl_status;
}
+#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 fchannel)
+{
+ return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ
+ || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ;
+}
+
__be32
nfsd4_create_session(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
cr_ses->flags &= ~SESSION4_PERSIST;
cr_ses->flags &= ~SESSION4_RDMA;
+ status = nfserr_toosmall;
+ if (check_forechannel_attrs(cr_ses->fore_channel))
+ goto out;
+
status = nfserr_jukebox;
new = alloc_init_session(rqstp, conf, cr_ses);
if (!new)
return args->opcnt > session->se_fchannel.maxops;
}
+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;
+}
+
__be32
nfsd4_sequence(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
if (nfsd4_session_too_many_ops(rqstp, session))
goto out;
+ status = nfserr_req_too_big;
+ if (nfsd4_request_too_big(rqstp, session))
+ goto out;
+
status = nfserr_badslot;
if (seq->slotid >= session->se_fchannel.maxreqs)
goto out;
* of 5 bullet points, labeled as CASE0 - CASE4 below.
*/
unconf = find_unconfirmed_client_by_str(dname, strhashval);
- status = nfserr_resource;
+ status = nfserr_jukebox;
if (!conf) {
/*
* RFC 3530 14.2.33 CASE 4:
kmem_cache_free(stateowner_slab, sop);
}
-static inline struct nfs4_stateowner *
-alloc_stateowner(struct xdr_netobj *owner)
+static void init_nfs4_replay(struct nfs4_replay *rp)
+{
+ rp->rp_status = nfserr_serverfault;
+ rp->rp_buflen = 0;
+ rp->rp_buf = rp->rp_ibuf;
+}
+
+static inline struct nfs4_stateowner *alloc_stateowner(struct xdr_netobj *owner, struct nfs4_client *clp)
{
struct nfs4_stateowner *sop;
- if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) {
- if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {
- memcpy(sop->so_owner.data, owner->data, owner->len);
- sop->so_owner.len = owner->len;
- kref_init(&sop->so_ref);
- return sop;
- }
+ sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL);
+ if (!sop)
+ return NULL;
+
+ sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
+ if (!sop->so_owner.data) {
kmem_cache_free(stateowner_slab, sop);
+ return NULL;
}
- return NULL;
+ sop->so_owner.len = owner->len;
+
+ kref_init(&sop->so_ref);
+ INIT_LIST_HEAD(&sop->so_perclient);
+ INIT_LIST_HEAD(&sop->so_stateids);
+ INIT_LIST_HEAD(&sop->so_perstateid);
+ INIT_LIST_HEAD(&sop->so_close_lru);
+ sop->so_id = current_ownerid++;
+ sop->so_time = 0;
+ sop->so_client = clp;
+ init_nfs4_replay(&sop->so_replay);
+ return sop;
+}
+
+static void hash_openowner(struct nfs4_stateowner *sop, struct nfs4_client *clp, unsigned int strhashval)
+{
+ unsigned int idhashval;
+
+ idhashval = open_ownerid_hashval(sop->so_id);
+ list_add(&sop->so_idhash, &open_ownerid_hashtbl[idhashval]);
+ list_add(&sop->so_strhash, &open_ownerstr_hashtbl[strhashval]);
+ list_add(&sop->so_perclient, &clp->cl_openowners);
}
static struct nfs4_stateowner *
alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
struct nfs4_stateowner *sop;
- struct nfs4_replay *rp;
- unsigned int idhashval;
- if (!(sop = alloc_stateowner(&open->op_owner)))
+ sop = alloc_stateowner(&open->op_owner, clp);
+ if (!sop)
return NULL;
- idhashval = ownerid_hashval(current_ownerid);
- INIT_LIST_HEAD(&sop->so_idhash);
- INIT_LIST_HEAD(&sop->so_strhash);
- INIT_LIST_HEAD(&sop->so_perclient);
- INIT_LIST_HEAD(&sop->so_stateids);
- INIT_LIST_HEAD(&sop->so_perstateid); /* not used */
- INIT_LIST_HEAD(&sop->so_close_lru);
- sop->so_time = 0;
- list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
- list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perclient, &clp->cl_openowners);
sop->so_is_open_owner = 1;
- sop->so_id = current_ownerid++;
- sop->so_client = clp;
sop->so_seqid = open->op_seqid;
sop->so_confirmed = 0;
- rp = &sop->so_replay;
- rp->rp_status = nfserr_serverfault;
- rp->rp_buflen = 0;
- rp->rp_buf = rp->rp_ibuf;
+ hash_openowner(sop, clp, strhashval);
return sop;
}
{
struct nfs4_stateowner *so = NULL;
- list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
+ list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) {
if (same_owner_str(so, &open->op_owner, &open->op_clientid))
return so;
}
return ret;
}
-static inline void
-nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
-{
- if (share_access & NFS4_SHARE_ACCESS_WRITE)
- nfs4_file_put_access(fp, O_WRONLY);
- if (share_access & NFS4_SHARE_ACCESS_READ)
- nfs4_file_put_access(fp, O_RDONLY);
-}
-
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
{
/* We're assuming the state code never drops its reference
}
static const struct lock_manager_operations nfsd_lease_mng_ops = {
- .fl_break = nfsd_break_deleg_cb,
- .fl_change = nfsd_change_deleg_cb,
+ .lm_break = nfsd_break_deleg_cb,
+ .lm_change = nfsd_change_deleg_cb,
};
if (STALE_CLIENTID(&open->op_clientid))
return nfserr_stale_clientid;
- strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
+ strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
sop = find_openstateowner_str(strhashval, open);
open->op_stateowner = sop;
if (!sop) {
if (open->op_stateowner == NULL) {
sop = alloc_init_open_stateowner(strhashval, clp, open);
if (sop == NULL)
- return nfserr_resource;
+ return nfserr_jukebox;
open->op_stateowner = sop;
}
list_del_init(&sop->so_close_lru);
return flags;
}
-static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
-*fp, struct svc_fh *cur_fh, u32 nfs4_access)
+static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
+ struct svc_fh *cur_fh, struct nfsd4_open *open)
{
__be32 status;
- int oflag = nfs4_access_to_omode(nfs4_access);
- int access = nfs4_access_to_access(nfs4_access);
+ int oflag = nfs4_access_to_omode(open->op_share_access);
+ int access = nfs4_access_to_access(open->op_share_access);
+
+ /* CLAIM_DELEGATE_CUR is used in response to a broken lease;
+ * allowing it to break the lease and return EAGAIN leaves the
+ * client unable to make progress in returning the delegation */
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
+ access |= NFSD_MAY_NOT_BREAK_LEASE;
if (!fp->fi_fds[oflag]) {
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
stp = nfs4_alloc_stateid();
if (stp == NULL)
- return nfserr_resource;
+ return nfserr_jukebox;
- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access);
+ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
if (status) {
kmem_cache_free(stateid_slab, stp);
return status;
new_access = !test_bit(op_share_access, &stp->st_access_bmap);
if (new_access) {
- status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access);
+ status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
if (status)
return status;
}
status = nfsd4_truncate(rqstp, cur_fh, open);
if (status) {
if (new_access) {
- int oflag = nfs4_access_to_omode(new_access);
+ int oflag = nfs4_access_to_omode(op_share_access);
nfs4_file_put_access(fp, oflag);
}
return status;
status = nfserr_bad_stateid;
if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
goto out;
- status = nfserr_resource;
+ status = nfserr_jukebox;
fp = alloc_init_file(ino);
if (fp == NULL)
goto out;
return locks_in_grace() && mandatory_lock(inode);
}
-static int check_stateid_generation(stateid_t *in, stateid_t *ref, int flags)
+static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
{
/*
* When sessions are used the stateid generation number is ignored
* when it is zero.
*/
- if ((flags & HAS_SESSION) && in->si_generation == 0)
+ if (has_session && in->si_generation == 0)
goto out;
/* If the client sends us a stateid from the future, it's buggy: */
return stateid->si_fileid == 0;
}
+static int is_open_stateid(struct nfs4_stateid *stateid)
+{
+ return stateid->st_openstp == NULL;
+}
+
+__be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
+{
+ struct nfs4_stateid *stp = NULL;
+ __be32 status = nfserr_stale_stateid;
+
+ if (STALE_STATEID(stateid))
+ goto out;
+
+ status = nfserr_expired;
+ stp = search_for_stateid(stateid);
+ if (!stp)
+ goto out;
+ status = nfserr_bad_stateid;
+
+ if (!stp->st_stateowner->so_confirmed)
+ goto out;
+
+ status = check_stateid_generation(stateid, &stp->st_stateid, has_session);
+ if (status)
+ goto out;
+
+ status = nfs_ok;
+out:
+ return status;
+}
+
/*
* Checks for stateid operations
*/
if (grace_disallows_io(ino))
return nfserr_grace;
- if (nfsd4_has_session(cstate))
- flags |= HAS_SESSION;
-
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
return check_special_stateids(current_fh, stateid, flags);
dp = find_delegation_stateid(ino, stateid);
if (!dp)
goto out;
- status = check_stateid_generation(stateid, &dp->dl_stateid,
- flags);
+ status = check_stateid_generation(stateid, &dp->dl_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
status = nfs4_check_delegmode(dp, flags);
if (!stp->st_stateowner->so_confirmed)
goto out;
status = check_stateid_generation(stateid, &stp->st_stateid,
- flags);
+ nfsd4_has_session(cstate));
if (status)
goto out;
status = nfs4_check_openmode(stp, flags);
return status;
}
+static __be32
+nfsd4_free_delegation_stateid(stateid_t *stateid)
+{
+ struct nfs4_delegation *dp = search_for_delegation(stateid);
+ if (dp)
+ return nfserr_locks_held;
+ return nfserr_bad_stateid;
+}
+
+static __be32
+nfsd4_free_lock_stateid(struct nfs4_stateid *stp)
+{
+ if (check_for_locks(stp->st_file, stp->st_stateowner))
+ return nfserr_locks_held;
+ release_lock_stateid(stp);
+ return nfs_ok;
+}
+
+/*
+ * Test if the stateid is valid
+ */
+__be32
+nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_test_stateid *test_stateid)
+{
+ test_stateid->ts_has_session = nfsd4_has_session(cstate);
+ return nfs_ok;
+}
+
+/*
+ * Free a state id
+ */
+__be32
+nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_free_stateid *free_stateid)
+{
+ stateid_t *stateid = &free_stateid->fr_stateid;
+ struct nfs4_stateid *stp;
+ __be32 ret;
+
+ nfs4_lock_state();
+ if (is_delegation_stateid(stateid)) {
+ ret = nfsd4_free_delegation_stateid(stateid);
+ goto out;
+ }
+
+ stp = search_for_stateid(stateid);
+ if (!stp) {
+ ret = nfserr_bad_stateid;
+ goto out;
+ }
+ if (stateid->si_generation != 0) {
+ if (stateid->si_generation < stp->st_stateid.si_generation) {
+ ret = nfserr_old_stateid;
+ goto out;
+ }
+ if (stateid->si_generation > stp->st_stateid.si_generation) {
+ ret = nfserr_bad_stateid;
+ goto out;
+ }
+ }
+
+ if (is_open_stateid(stp)) {
+ ret = nfserr_locks_held;
+ goto out;
+ } else {
+ ret = nfsd4_free_lock_stateid(stp);
+ goto out;
+ }
+
+out:
+ nfs4_unlock_state();
+ return ret;
+}
+
static inline int
setlkflg (int type)
{
if (STALE_STATEID(stateid))
return nfserr_stale_stateid;
- if (nfsd4_has_session(cstate))
- flags |= HAS_SESSION;
-
/*
* We return BAD_STATEID if filehandle doesn't match stateid,
* the confirmed flag is incorrecly set, or the generation
if (lock->lk_is_new) {
if (!sop->so_is_open_owner)
return nfserr_bad_stateid;
- if (!(flags & HAS_SESSION) &&
+ if (!nfsd4_has_session(cstate) &&
!same_clid(&clp->cl_clientid, lockclid))
return nfserr_bad_stateid;
/* stp is the open stateid */
* For the moment, we ignore the possibility of
* generation number wraparound.
*/
- if (!(flags & HAS_SESSION) && seqid != sop->so_seqid)
+ if (!nfsd4_has_session(cstate) && seqid != sop->so_seqid)
goto check_replay;
if (sop->so_confirmed && flags & CONFIRM) {
" confirmed yet!\n");
return nfserr_bad_stateid;
}
- status = check_stateid_generation(stateid, &stp->st_stateid, flags);
+ status = check_stateid_generation(stateid, &stp->st_stateid, nfsd4_has_session(cstate));
if (status)
return status;
renew_client(sop->so_client);
return status;
}
-
-/*
- * unset all bits in union bitmap (bmap) that
- * do not exist in share (from successful OPEN_DOWNGRADE)
- */
-static void
-reset_union_bmap_access(unsigned long access, unsigned long *bmap)
+static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access)
{
int i;
+
for (i = 1; i < 4; i++) {
- if ((i & access) != i)
- __clear_bit(i, bmap);
+ if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) {
+ nfs4_file_put_access(stp->st_file, i);
+ __clear_bit(i, &stp->st_access_bmap);
+ }
}
}
{
__be32 status;
struct nfs4_stateid *stp;
- unsigned int share_access;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
(int)cstate->current_fh.fh_dentry->d_name.len,
stp->st_deny_bmap, od->od_share_deny);
goto out;
}
- set_access(&share_access, stp->st_access_bmap);
- nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access);
+ nfs4_file_downgrade(stp, od->od_share_access);
- reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
update_stateid(&stp->st_stateid);
stateid_t *stateid = &dr->dr_stateid;
struct inode *inode;
__be32 status;
- int flags = 0;
if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
return status;
inode = cstate->current_fh.fh_dentry->d_inode;
- if (nfsd4_has_session(cstate))
- flags |= HAS_SESSION;
nfs4_lock_state();
status = nfserr_bad_stateid;
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
dp = find_delegation_stateid(inode, stateid);
if (!dp)
goto out;
- status = check_stateid_generation(stateid, &dp->dl_stateid, flags);
+ status = check_stateid_generation(stateid, &dp->dl_stateid, nfsd4_has_session(cstate));
if (status)
goto out;
renew_client(dp->dl_client);
return end > start ? end - 1: NFS4_MAX_UINT64;
}
-#define lockownerid_hashval(id) \
- ((id) & LOCK_HASH_MASK)
+static unsigned int lockownerid_hashval(u32 id)
+{
+ return id & LOCK_HASH_MASK;
+}
static inline unsigned int
lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
+static int
+same_stateid(stateid_t *id_one, stateid_t *id_two)
+{
+ if (id_one->si_stateownerid != id_two->si_stateownerid)
+ return 0;
+ return id_one->si_fileid == id_two->si_fileid;
+}
+
static struct nfs4_stateid *
find_stateid(stateid_t *stid, int flags)
{
return NULL;
}
+static struct nfs4_stateid *
+search_for_stateid(stateid_t *stid)
+{
+ struct nfs4_stateid *local;
+ unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid);
+
+ list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
+ if (same_stateid(&local->st_stateid, stid))
+ return local;
+ }
+
+ list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
+ if (same_stateid(&local->st_stateid, stid))
+ return local;
+ }
+ return NULL;
+}
+
+static struct nfs4_delegation *
+search_for_delegation(stateid_t *stid)
+{
+ struct nfs4_file *fp;
+ struct nfs4_delegation *dp;
+ struct list_head *pos;
+ int i;
+
+ for (i = 0; i < FILE_HASH_SIZE; i++) {
+ list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
+ list_for_each(pos, &fp->fi_delegations) {
+ dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
+ if (same_stateid(&dp->dl_stateid, stid))
+ return dp;
+ }
+ }
+ }
+ return NULL;
+}
+
static struct nfs4_delegation *
find_delegation_stateid(struct inode *ino, stateid_t *stid)
{
return NULL;
}
+static void hash_lockowner(struct nfs4_stateowner *sop, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp)
+{
+ unsigned int idhashval;
+
+ idhashval = lockownerid_hashval(sop->so_id);
+ list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
+ list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
+ list_add(&sop->so_perstateid, &open_stp->st_lockowners);
+}
+
/*
* Alloc a lock owner structure.
* Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
static struct nfs4_stateowner *
alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {
struct nfs4_stateowner *sop;
- struct nfs4_replay *rp;
- unsigned int idhashval;
- if (!(sop = alloc_stateowner(&lock->lk_new_owner)))
+ sop = alloc_stateowner(&lock->lk_new_owner, clp);
+ if (!sop)
return NULL;
- idhashval = lockownerid_hashval(current_ownerid);
- INIT_LIST_HEAD(&sop->so_idhash);
- INIT_LIST_HEAD(&sop->so_strhash);
- INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_stateids);
- INIT_LIST_HEAD(&sop->so_perstateid);
- INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
- sop->so_time = 0;
- list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
- list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perstateid, &open_stp->st_lockowners);
sop->so_is_open_owner = 0;
- sop->so_id = current_ownerid++;
- sop->so_client = clp;
/* It is the openowner seqid that will be incremented in encode in the
* case of new lockowners; so increment the lock seqid manually: */
sop->so_seqid = lock->lk_new_lock_seqid + 1;
sop->so_confirmed = 1;
- rp = &sop->so_replay;
- rp->rp_status = nfserr_serverfault;
- rp->rp_buflen = 0;
- rp->rp_buf = rp->rp_ibuf;
+ hash_lockowner(sop, strhashval, clp, open_stp);
return sop;
}
/* XXX: Do we need to check for duplicate stateowners on
* the same file, or should they just be allowed (and
* create new stateids)? */
- status = nfserr_resource;
+ status = nfserr_jukebox;
lock_sop = alloc_init_lock_stateowner(strhashval,
open_sop->so_client, open_stp, lock);
if (lock_sop == NULL)
case (EDEADLK):
status = nfserr_deadlock;
break;
- default:
+ default:
dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
- status = nfserr_resource;
+ status = nfserrno(err);
break;
}
out:
if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid))
goto out;
- if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) {
- dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
- if (status == nfserr_symlink)
- status = nfserr_inval;
+ if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
goto out;
- }
inode = cstate->current_fh.fh_dentry->d_inode;
locks_init_lock(&file_lock);
for (i = 0; i < FILE_HASH_SIZE; i++) {
INIT_LIST_HEAD(&file_hashtbl[i]);
}
- for (i = 0; i < OWNER_HASH_SIZE; i++) {
- INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
- INIT_LIST_HEAD(&ownerid_hashtbl[i]);
+ for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
+ INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
+ INIT_LIST_HEAD(&open_ownerid_hashtbl[i]);
}
for (i = 0; i < STATEID_HASH_SIZE; i++) {
INIT_LIST_HEAD(&stateid_hashtbl[i]);
int status;
nfs4_lock_state();
- nfsd4_init_recdir(user_recovery_dirname);
+ nfsd4_init_recdir();
status = nfsd4_recdir_load();
nfs4_unlock_state();
if (status)
nfs4_unlock_state();
nfsd4_destroy_callback_queue();
}
-
-/*
- * user_recovery_dirname is protected by the nfsd_mutex since it's only
- * accessed when nfsd is starting.
- */
-static void
-nfs4_set_recdir(char *recdir)
-{
- strcpy(user_recovery_dirname, recdir);
-}
-
-/*
- * Change the NFSv4 recovery directory to recdir.
- */
-int
-nfs4_reset_recoverydir(char *recdir)
-{
- int status;
- struct path path;
-
- status = kern_path(recdir, LOOKUP_FOLLOW, &path);
- if (status)
- return status;
- status = -ENOTDIR;
- if (S_ISDIR(path.dentry->d_inode->i_mode)) {
- nfs4_set_recdir(recdir);
- status = 0;
- }
- path_put(&path);
- return status;
-}
-
-char *
-nfs4_recoverydir(void)
-{
- return user_recovery_dirname;
-}