diff options
Diffstat (limited to 'fs/nfs/callback_proc.c')
| -rw-r--r-- | fs/nfs/callback_proc.c | 99 | 
1 files changed, 46 insertions, 53 deletions
| diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 54cea8ad5a76..1b5d809a105e 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -8,6 +8,7 @@  #include <linux/nfs4.h>  #include <linux/nfs_fs.h>  #include <linux/slab.h> +#include <linux/rcupdate.h>  #include "nfs4_fs.h"  #include "callback.h"  #include "delegation.h" @@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args,  	res->bitmap[0] = res->bitmap[1] = 0;  	res->status = htonl(NFS4ERR_BADHANDLE); -	dprintk("NFS: GETATTR callback request from %s\n", +	dprintk_rcu("NFS: GETATTR callback request from %s\n",  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));  	inode = nfs_delegation_find_inode(cps->clp, &args->fh); @@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,  	if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */  		goto out; -	dprintk("NFS: RECALL callback request from %s\n", +	dprintk_rcu("NFS: RECALL callback request from %s\n",  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));  	res = htonl(NFS4ERR_BADHANDLE); @@ -86,8 +87,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,  		res = 0;  		break;  	case -ENOENT: -		if (res != 0) -			res = htonl(NFS4ERR_BAD_STATEID); +		res = htonl(NFS4ERR_BAD_STATEID);  		break;  	default:  		res = htonl(NFS4ERR_RESOURCE); @@ -98,52 +98,64 @@ out:  	return res;  } -int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) -{ -	if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, -					 sizeof(delegation->stateid.data)) != 0) -		return 0; -	return 1; -} -  #if defined(CONFIG_NFS_V4_1) -static u32 initiate_file_draining(struct nfs_client *clp, -				  struct cb_layoutrecallargs *args) +/* + * Lookup a layout by filehandle. + * + * Note: gets a refcount on the layout hdr and on its respective inode. + * Caller must put the layout hdr and the inode. + * + * TODO: keep track of all layouts (and delegations) in a hash table + * hashed by filehandle. + */ +static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)  {  	struct nfs_server *server; -	struct pnfs_layout_hdr *lo;  	struct inode *ino; -	bool found = false; -	u32 rv = NFS4ERR_NOMATCHING_LAYOUT; -	LIST_HEAD(free_me_list); +	struct pnfs_layout_hdr *lo; -	spin_lock(&clp->cl_lock); -	rcu_read_lock();  	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {  		list_for_each_entry(lo, &server->layouts, plh_layouts) { -			if (nfs_compare_fh(&args->cbl_fh, -					   &NFS_I(lo->plh_inode)->fh)) +			if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))  				continue;  			ino = igrab(lo->plh_inode);  			if (!ino)  				continue; -			found = true; -			/* Without this, layout can be freed as soon -			 * as we release cl_lock. -			 */  			get_layout_hdr(lo); -			break; +			return lo;  		} -		if (found) -			break;  	} + +	return NULL; +} + +static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh) +{ +	struct pnfs_layout_hdr *lo; + +	spin_lock(&clp->cl_lock); +	rcu_read_lock(); +	lo = get_layout_by_fh_locked(clp, fh);  	rcu_read_unlock();  	spin_unlock(&clp->cl_lock); -	if (!found) +	return lo; +} + +static u32 initiate_file_draining(struct nfs_client *clp, +				  struct cb_layoutrecallargs *args) +{ +	struct inode *ino; +	struct pnfs_layout_hdr *lo; +	u32 rv = NFS4ERR_NOMATCHING_LAYOUT; +	LIST_HEAD(free_me_list); + +	lo = get_layout_by_fh(clp, &args->cbl_fh); +	if (!lo)  		return NFS4ERR_NOMATCHING_LAYOUT; +	ino = lo->plh_inode;  	spin_lock(&ino->i_lock);  	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||  	    mark_matching_lsegs_invalid(lo, &free_me_list, @@ -213,17 +225,13 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,  static u32 do_callback_layoutrecall(struct nfs_client *clp,  				    struct cb_layoutrecallargs *args)  { -	u32 res = NFS4ERR_DELAY; +	u32 res;  	dprintk("%s enter, type=%i\n", __func__, args->cbl_recall_type); -	if (test_and_set_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state)) -		goto out;  	if (args->cbl_recall_type == RETURN_FILE)  		res = initiate_file_draining(clp, args);  	else  		res = initiate_bulk_draining(clp, args); -	clear_bit(NFS4CLNT_LAYOUTRECALL, &clp->cl_state); -out:  	dprintk("%s returning %i\n", __func__, res);  	return res; @@ -303,21 +311,6 @@ out:  	return res;  } -int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) -{ -	if (delegation == NULL) -		return 0; - -	if (stateid->stateid.seqid != 0) -		return 0; -	if (memcmp(&delegation->stateid.stateid.other, -		   &stateid->stateid.other, -		   NFS4_STATEID_OTHER_SIZE)) -		return 0; - -	return 1; -} -  /*   * Validate the sequenceID sent by the server.   * Return success if the sequenceID is one more than what we last saw on @@ -441,7 +434,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,  	int i;  	__be32 status = htonl(NFS4ERR_BADSESSION); -	clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid); +	clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid);  	if (clp == NULL)  		goto out; @@ -517,7 +510,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,  	if (!cps->clp) /* set in cb_sequence */  		goto out; -	dprintk("NFS: RECALL_ANY callback request from %s\n", +	dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));  	status = cpu_to_be32(NFS4ERR_INVAL); @@ -552,7 +545,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,  	if (!cps->clp) /* set in cb_sequence */  		goto out; -	dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", +	dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",  		rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),  		args->crsa_target_max_slots); | 
