list_for_each_entry(sop, &matches, so_perclient) { 
while (!list_empty(&matches)) { sop = list_entry(matches.next, struct nfs4_stateowner, so_perclient); /* unhash_stateowner deletes so_perclient only * for openowners. */ list_del(&sop->so_perclient); 
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner){	clientid_t *clid = &rlockowner->rl_clientid;	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",		clid->cl_boot, clid->cl_id);	/* XXX check for lease expiration */	status = nfserr_stale_clientid;	if (STALE_CLIENTID(clid)) {		printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n");		return status;	}	nfs4_lock_state();	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);			}		}	}	/* 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();	return status;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/0fa822e452084032b8495ca0d8e0199329847815/nfs4state.c/clean/fs/nfsd/nfs4state.c