dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
if (dp == NULL)
return dp;
- INIT_LIST_HEAD(&dp->dl_del_perfile);
- INIT_LIST_HEAD(&dp->dl_del_perclnt);
+ INIT_LIST_HEAD(&dp->dl_perfile);
+ INIT_LIST_HEAD(&dp->dl_perclnt);
INIT_LIST_HEAD(&dp->dl_recall_lru);
dp->dl_client = clp;
get_nfs4_file(fp);
current_fh->fh_handle.fh_size);
dp->dl_time = 0;
atomic_set(&dp->dl_count, 1);
- list_add(&dp->dl_del_perfile, &fp->fi_delegations);
- list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt);
+ list_add(&dp->dl_perfile, &fp->fi_delegations);
+ list_add(&dp->dl_perclnt, &clp->cl_delegations);
return dp;
}
static void
unhash_delegation(struct nfs4_delegation *dp)
{
- list_del_init(&dp->dl_del_perfile);
- list_del_init(&dp->dl_del_perclnt);
+ list_del_init(&dp->dl_perfile);
+ list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_recall_lru);
spin_unlock(&recall_lock);
INIT_LIST_HEAD(&reaplist);
spin_lock(&recall_lock);
- while (!list_empty(&clp->cl_del_perclnt)) {
- dp = list_entry(clp->cl_del_perclnt.next, struct nfs4_delegation, dl_del_perclnt);
+ while (!list_empty(&clp->cl_delegations)) {
+ dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
dp->dl_flock);
- list_del_init(&dp->dl_del_perclnt);
+ list_del_init(&dp->dl_perclnt);
list_move(&dp->dl_recall_lru, &reaplist);
}
spin_unlock(&recall_lock);
list_del(&clp->cl_idhash);
list_del(&clp->cl_strhash);
list_del(&clp->cl_lru);
- while (!list_empty(&clp->cl_perclient)) {
- sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);
+ while (!list_empty(&clp->cl_openowners)) {
+ sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
release_stateowner(sop);
}
put_nfs4_client(clp);
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_count, 1);
atomic_set(&clp->cl_callback.cb_set, 0);
- clp->cl_callback.cb_parsed = 0;
INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_strhash);
- INIT_LIST_HEAD(&clp->cl_perclient);
- INIT_LIST_HEAD(&clp->cl_del_perclnt);
+ INIT_LIST_HEAD(&clp->cl_openowners);
+ INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
out:
return clp;
goto out_err;
cb->cb_prog = se->se_callback_prog;
cb->cb_ident = se->se_callback_ident;
- cb->cb_parsed = 1;
return;
out_err:
printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
"will not receive delegations\n",
clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- cb->cb_parsed = 0;
return;
}
nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
{
u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
- struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
+ struct nfs4_client *conf, *unconf;
nfs4_verifier confirm = setclientid_confirm->sc_confirm;
clientid_t * clid = &setclientid_confirm->sc_clientid;
int status;
*/
nfs4_lock_state();
- clp = find_confirmed_client(clid);
- if (clp) {
- status = nfserr_clid_inuse;
- if (clp->cl_addr != ip_addr) {
- printk("NFSD: setclientid: string in use by client"
- "(clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- goto out;
- }
- conf = clp;
- }
- clp = find_unconfirmed_client(clid);
- if (clp) {
- status = nfserr_clid_inuse;
- if (clp->cl_addr != ip_addr) {
- printk("NFSD: setclientid: string in use by client"
- "(clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- goto out;
- }
- unconf = clp;
- }
- /* CASE 1:
- * unconf record that matches input clientid and input confirm.
- * conf record that matches input clientid.
- * conf and unconf records match names, verifiers
- */
+
+ conf = find_confirmed_client(clid);
+ unconf = find_unconfirmed_client(clid);
+
+ status = nfserr_clid_inuse;
+ if (conf && conf->cl_addr != ip_addr)
+ goto out;
+ if (unconf && unconf->cl_addr != ip_addr)
+ goto out;
+
if ((conf && unconf) &&
(cmp_verf(&unconf->cl_confirm, &confirm)) &&
(cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
(same_name(conf->cl_recdir,unconf->cl_recdir)) &&
(!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
+ /* CASE 1:
+ * unconf record that matches input clientid and input confirm.
+ * conf record that matches input clientid.
+ * conf and unconf records match names, verifiers
+ */
if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
else {
/* XXX: We just turn off callbacks until we can handle
* change request correctly. */
- clp = conf;
- clp->cl_callback.cb_parsed = 0;
- gen_confirm(clp);
+ atomic_set(&conf->cl_callback.cb_set, 0);
+ gen_confirm(conf);
expire_client(unconf);
status = nfs_ok;
}
- }
- /* CASE 2:
- * conf record that matches input clientid.
- * if unconf record that matches input clientid, then unconf->cl_name
- * or unconf->cl_verifier don't match the conf record.
- */
- else if ((conf && !unconf) ||
+ } else if ((conf && !unconf) ||
((conf && unconf) &&
(!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
!same_name(conf->cl_recdir, unconf->cl_recdir)))) {
- if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
+ /* CASE 2:
+ * conf record that matches input clientid.
+ * if unconf record matches input clientid, then
+ * unconf->cl_name or unconf->cl_verifier don't match the
+ * conf record.
+ */
+ if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred))
status = nfserr_clid_inuse;
- } else {
- clp = conf;
+ else
status = nfs_ok;
- }
- }
- /* CASE 3:
- * conf record not found.
- * unconf record found.
- * unconf->cl_confirm matches input confirm
- */
- else if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) {
+ } else if (!conf && unconf
+ && cmp_verf(&unconf->cl_confirm, &confirm)) {
+ /* CASE 3:
+ * conf record not found.
+ * unconf record found.
+ * unconf->cl_confirm matches input confirm
+ */
if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
status = nfserr_clid_inuse;
} else {
if (conf) {
expire_client(conf);
}
- clp = unconf;
move_to_confirmed(unconf);
+ conf = unconf;
status = nfs_ok;
}
- }
- /* CASE 4:
- * conf record not found, or if conf, then conf->cl_confirm does not
- * match input confirm.
- * unconf record not found, or if unconf, then unconf->cl_confirm
- * does not match input confirm.
- */
- else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) &&
- (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) {
+ } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm)))
+ && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm,
+ &confirm)))) {
+ /* CASE 4:
+ * conf record not found, or if conf, conf->cl_confirm does not
+ * match input confirm.
+ * unconf record not found, or if unconf, unconf->cl_confirm
+ * does not match input confirm.
+ */
status = nfserr_stale_clientid;
- }
- else {
+ } else {
/* check that we have hit one of the cases...*/
status = nfserr_clid_inuse;
}
out:
if (!status)
- nfsd4_probe_callback(clp);
+ nfsd4_probe_callback(conf);
nfs4_unlock_state();
return status;
}
INIT_LIST_HEAD(&sop->so_idhash);
INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient);
- INIT_LIST_HEAD(&sop->so_perfilestate);
- INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */
+ 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_perclient);
+ list_add(&sop->so_perclient, &clp->cl_openowners);
sop->so_is_open_owner = 1;
sop->so_id = current_ownerid++;
sop->so_client = clp;
{
struct nfs4_stateowner *lock_sop;
- while (!list_empty(&open_stp->st_perlockowner)) {
- lock_sop = list_entry(open_stp->st_perlockowner.next,
- struct nfs4_stateowner, so_perlockowner);
- /* list_del(&open_stp->st_perlockowner); */
+ while (!list_empty(&open_stp->st_lockowners)) {
+ lock_sop = list_entry(open_stp->st_lockowners.next,
+ struct nfs4_stateowner, so_perstateid);
+ /* list_del(&open_stp->st_lockowners); */
BUG_ON(lock_sop->so_is_open_owner);
release_stateowner(lock_sop);
}
list_del(&sop->so_strhash);
if (sop->so_is_open_owner)
list_del(&sop->so_perclient);
- list_del(&sop->so_perlockowner);
- while (!list_empty(&sop->so_perfilestate)) {
- stp = list_entry(sop->so_perfilestate.next,
- struct nfs4_stateid, st_perfilestate);
+ list_del(&sop->so_perstateid);
+ while (!list_empty(&sop->so_stateids)) {
+ stp = list_entry(sop->so_stateids.next,
+ struct nfs4_stateid, st_perstateowner);
if (sop->so_is_open_owner)
release_stateid(stp, OPEN_STATE);
else
unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
INIT_LIST_HEAD(&stp->st_hash);
- INIT_LIST_HEAD(&stp->st_perfilestate);
- INIT_LIST_HEAD(&stp->st_perlockowner);
+ INIT_LIST_HEAD(&stp->st_perstateowner);
+ INIT_LIST_HEAD(&stp->st_lockowners);
INIT_LIST_HEAD(&stp->st_perfile);
list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
- list_add(&stp->st_perfilestate, &sop->so_perfilestate);
+ list_add(&stp->st_perstateowner, &sop->so_stateids);
list_add(&stp->st_perfile, &fp->fi_stateids);
stp->st_stateowner = sop;
get_nfs4_file(fp);
list_del(&stp->st_hash);
list_del(&stp->st_perfile);
- list_del(&stp->st_perfilestate);
+ list_del(&stp->st_perstateowner);
if (flags & OPEN_STATE) {
release_stateid_lockowners(stp);
stp->st_vfs_file = NULL;
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
- if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
+ if (sop->so_confirmed && list_empty(&sop->so_stateids))
move_to_close_lru(sop);
}
{
struct nfs4_delegation *dp;
- list_for_each_entry(dp, &fp->fi_delegations, dl_del_perfile) {
+ list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
return dp;
}
}
renew_client(clp);
status = nfserr_cb_path_down;
- if (!list_empty(&clp->cl_del_perclnt)
+ if (!list_empty(&clp->cl_delegations)
&& !atomic_read(&clp->cl_callback.cb_set))
goto out;
status = nfs_ok;
deny->ld_type = NFS4_WRITE_LT;
}
-static struct nfs4_stateowner *
-find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid)
-{
- struct nfs4_stateowner *local = NULL;
- int i;
-
- for (i = 0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {
- if (!cmp_owner_str(local, owner, clid))
- continue;
- return local;
- }
- }
- return NULL;
-}
-
static struct nfs4_stateowner *
find_lockstateowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
INIT_LIST_HEAD(&sop->so_idhash);
INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient);
- INIT_LIST_HEAD(&sop->so_perfilestate);
- INIT_LIST_HEAD(&sop->so_perlockowner);
+ 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_perlockowner, &open_stp->st_perlockowner);
+ list_add(&sop->so_perstateid, &open_stp->st_lockowners);
sop->so_is_open_owner = 0;
sop->so_id = current_ownerid++;
sop->so_client = clp;
goto out;
INIT_LIST_HEAD(&stp->st_hash);
INIT_LIST_HEAD(&stp->st_perfile);
- INIT_LIST_HEAD(&stp->st_perfilestate);
- INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
+ INIT_LIST_HEAD(&stp->st_perstateowner);
+ INIT_LIST_HEAD(&stp->st_lockowners); /* not used */
list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
list_add(&stp->st_perfile, &fp->fi_stateids);
- list_add(&stp->st_perfilestate, &sop->so_perfilestate);
+ list_add(&stp->st_perstateowner, &sop->so_stateids);
stp->st_stateowner = sop;
get_nfs4_file(fp);
stp->st_file = fp;
int
nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
{
- struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL;
+ struct nfs4_stateowner *open_sop = NULL;
struct nfs4_stateid *lock_stp;
struct file *filp;
struct file_lock file_lock;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
open_sop->so_client->cl_clientid.cl_id,
&lock->v.new.owner);
- /*
- * If we already have this lock owner, the client is in
- * error (or our bookeeping is wrong!)
- * for asking for a 'new lock'.
- */
- status = nfserr_bad_stateid;
- lock_sop = find_lockstateowner(&lock->v.new.owner,
- &lock->v.new.clientid);
- if (lock_sop)
- goto out;
+ /* 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;
if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
goto out;
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
- struct nfs4_stateowner *local = NULL;
+ struct nfs4_stateowner *sop;
+ struct nfs4_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
+ struct list_head matches;
+ int i;
int status;
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
nfs4_lock_state();
- status = nfs_ok;
- local = find_lockstateowner(owner, clid);
- if (local) {
- struct nfs4_stateid *stp;
-
- /* check for any locks held by any stateid
- * associated with the (lock) stateowner */
- status = nfserr_locks_held;
- list_for_each_entry(stp, &local->so_perfilestate,
- st_perfilestate) {
- if (check_for_locks(stp->st_vfs_file, local))
- goto out;
+ status = nfserr_locks_held;
+ /* XXX: we're doing a linear search through all the lockowners.
+ * Yipes! For now we'll just hope clients aren't really using
+ * release_lockowner much, but eventually we have to fix these
+ * data structures. */
+ INIT_LIST_HEAD(&matches);
+ for (i = 0; i < LOCK_HASH_SIZE; i++) {
+ list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
+ if (!cmp_owner_str(sop, owner, clid))
+ continue;
+ list_for_each_entry(stp, &sop->so_stateids,
+ st_perstateowner) {
+ if (check_for_locks(stp->st_vfs_file, sop))
+ goto out;
+ /* Note: so_perclient unused for lockowners,
+ * so it's OK to fool with here. */
+ list_add(&sop->so_perclient, &matches);
+ }
}
- /* no locks held by (lock) stateowner */
- status = nfs_ok;
- release_stateowner(local);
+ }
+ /* Clients probably won't expect us to return with some (but not all)
+ * of the lockowner state released; so don't release any until all
+ * have been checked. */
+ status = nfs_ok;
+ list_for_each_entry(sop, &matches, so_perclient) {
+ release_stateowner(sop);
}
out:
nfs4_unlock_state();