Skip to content
Snippets Groups Projects
nfs4state.c 58.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	nfs_expire_all_delegations(clp);
    	if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
    
    		nfs4_schedule_state_manager(clp);
    
    	dprintk("%s: server %s declared a backchannel fault\n", __func__,
    			clp->cl_hostname);
    
    static void nfs41_handle_cb_path_down(struct nfs_client *clp)
    {
    	if (test_and_set_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
    		&clp->cl_state) == 0)
    		nfs4_schedule_state_manager(clp);
    }
    
    
    void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
    {
    	if (!flags)
    		return;
    
    
    	dprintk("%s: \"%s\" (client ID %llx) flags=0x%08x\n",
    		__func__, clp->cl_hostname, clp->cl_clientid, flags);
    
    
    	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
    
    		nfs41_handle_server_reboot(clp);
    
    	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
    
    			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
    			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
    
    			    SEQ4_STATUS_LEASE_MOVED))
    		nfs41_handle_state_revoked(clp);
    
    	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
    
    		nfs41_handle_recallable_state_revoked(clp);
    
    	if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT)
    		nfs41_handle_backchannel_fault(clp);
    	else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
    				SEQ4_STATUS_CB_PATH_DOWN_SESSION))
    
    		nfs41_handle_cb_path_down(clp);
    
    static int nfs4_reset_session(struct nfs_client *clp)
    {
    
    	nfs4_begin_drain_session(clp);
    
    	cred = nfs4_get_exchange_id_cred(clp);
    	status = nfs4_proc_destroy_session(clp->cl_session, cred);
    
    	if (status && status != -NFS4ERR_BADSESSION &&
    	    status != -NFS4ERR_DEADSESSION) {
    
    		status = nfs4_recovery_handle_error(clp, status);
    
    		goto out;
    	}
    
    	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
    
    	status = nfs4_proc_create_session(clp, cred);
    
    		dprintk("%s: session reset failed with status %d for server %s!\n",
    			__func__, status, clp->cl_hostname);
    
    		status = nfs4_handle_reclaim_lease_error(clp, status);
    
    	dprintk("%s: session reset was successful for server %s!\n",
    			__func__, clp->cl_hostname);
    
    static int nfs4_bind_conn_to_session(struct nfs_client *clp)
    {
    
    	nfs4_begin_drain_session(clp);
    
    	cred = nfs4_get_exchange_id_cred(clp);
    	ret = nfs4_proc_bind_conn_to_session(clp, cred);
    	if (cred)
    		put_rpccred(cred);
    
    	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
    
    		dprintk("%s: bind_conn_to_session was successful for server %s!\n",
    			__func__, clp->cl_hostname);
    
    		break;
    	case -NFS4ERR_DELAY:
    		ssleep(1);
    		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
    		break;
    	default:
    		return nfs4_recovery_handle_error(clp, ret);
    	}
    	return 0;
    
    #else /* CONFIG_NFS_V4_1 */
    
    static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
    
    static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
    
    
    static int nfs4_bind_conn_to_session(struct nfs_client *clp)
    {
    	return 0;
    }
    
    #endif /* CONFIG_NFS_V4_1 */
    
    
    static void nfs4_state_manager(struct nfs_client *clp)
    
    	const char *section = "", *section_sep = "";
    
    
    	/* Ensure exclusive access to NFSv4 state */
    
    		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
    
    			status = nfs4_purge_lease(clp);
    
    		if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
    
    			section = "lease expired";
    
    			/* We're going to have to re-establish a clientid */
    			status = nfs4_reclaim_lease(clp);
    
    		/* Initialize or reset the session */
    
    		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
    
    			section = "reset session";
    
    			status = nfs4_reset_session(clp);
    
    			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
    				continue;
    			if (status < 0)
    
    		/* Send BIND_CONN_TO_SESSION */
    		if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
    
    			section = "bind conn to session";
    
    			status = nfs4_bind_conn_to_session(clp);
    			if (status < 0)
    				goto out_error;
    
    		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
    			section = "check lease";
    			status = nfs4_check_lease(clp);
    			if (status < 0)
    				goto out_error;
    			continue;
    		}
    
    
    		/* First recover reboot state... */
    
    		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
    
    			section = "reclaim reboot";
    
    			status = nfs4_do_reclaim(clp,
    
    			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
    
    			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
    
    			nfs4_state_end_reclaim_reboot(clp);
    
    			if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
    				continue;
    			if (status < 0)
    				goto out_error;
    
    		/* Now recover expired state... */
    		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
    
    			section = "reclaim nograce";
    
    			status = nfs4_do_reclaim(clp,
    
    				clp->cl_mvops->nograce_recovery_ops);
    
    			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
    
    			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
    
    			    test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
    				continue;
    			if (status < 0)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		}
    
    		nfs4_end_drain_session(clp);
    
    		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
    			nfs_client_return_marked_delegations(clp);
    			continue;
    		}
    
    
    		nfs4_clear_state_manager_bit(clp);
    
    		/* Did we race with an attempt to give us more work? */
    		if (clp->cl_state == 0)
    			break;
    		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
    			break;
    
    	} while (atomic_read(&clp->cl_count) > 1);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out_error:
    
    	if (strlen(section))
    		section_sep = ": ";
    	pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
    			" with error %d\n", section_sep, section,
    			clp->cl_hostname, -status);
    
    	nfs4_end_drain_session(clp);
    
    	nfs4_clear_state_manager_bit(clp);
    }
    
    static int nfs4_run_state_manager(void *ptr)
    {
    	struct nfs_client *clp = ptr;
    
    	allow_signal(SIGKILL);
    	nfs4_state_manager(clp);
    	nfs_put_client(clp);
    	module_put_and_exit(0);
    	return 0;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /*
     * Local variables:
     *  c-basic-offset: 8
     * End:
     */