Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1df7637 authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

Merge branch 'nfs-for-next' of git://linux-nfs.org/~trondmy/nfs-2.6 into for-3.10

Note conflict: Chuck's patches modified (and made static)
gss_mech_get_by_OID, which is still needed by gss-proxy patches.

The conflict resolution is a bit minimal; we may want some more cleanup.
parents dd30333c 721ccfb7
Loading
Loading
Loading
Loading
+32 −17
Original line number Diff line number Diff line
@@ -201,7 +201,9 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
	if (clp->cl_minorversion != 0)
		__set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
	__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
	error = nfs_create_rpc_client(clp, timeparms, authflavour);
	error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
	if (error == -EINVAL)
		error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL);
	if (error < 0)
		goto error;

@@ -302,7 +304,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
			   struct rpc_cred *cred)
{
	struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
	struct nfs_client *pos, *n, *prev = NULL;
	struct nfs_client *pos, *prev = NULL;
	struct nfs4_setclientid_res clid = {
		.clientid	= new->cl_clientid,
		.confirm	= new->cl_confirm,
@@ -310,10 +312,23 @@ int nfs40_walk_client_list(struct nfs_client *new,
	int status = -NFS4ERR_STALE_CLIENTID;

	spin_lock(&nn->nfs_client_lock);
	list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
	list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
		/* If "pos" isn't marked ready, we can't trust the
		 * remaining fields in "pos" */
		if (pos->cl_cons_state < NFS_CS_READY)
		if (pos->cl_cons_state > NFS_CS_READY) {
			atomic_inc(&pos->cl_count);
			spin_unlock(&nn->nfs_client_lock);

			if (prev)
				nfs_put_client(prev);
			prev = pos;

			status = nfs_wait_client_init_complete(pos);
			spin_lock(&nn->nfs_client_lock);
			if (status < 0)
				continue;
		}
		if (pos->cl_cons_state != NFS_CS_READY)
			continue;

		if (pos->rpc_ops != new->rpc_ops)
@@ -425,16 +440,16 @@ int nfs41_walk_client_list(struct nfs_client *new,
			   struct rpc_cred *cred)
{
	struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
	struct nfs_client *pos, *n, *prev = NULL;
	struct nfs_client *pos, *prev = NULL;
	int status = -NFS4ERR_STALE_CLIENTID;

	spin_lock(&nn->nfs_client_lock);
	list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
	list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
		/* If "pos" isn't marked ready, we can't trust the
		 * remaining fields in "pos", especially the client
		 * ID and serverowner fields.  Wait for CREATE_SESSION
		 * to finish. */
		if (pos->cl_cons_state < NFS_CS_READY) {
		if (pos->cl_cons_state > NFS_CS_READY) {
			atomic_inc(&pos->cl_count);
			spin_unlock(&nn->nfs_client_lock);

@@ -442,18 +457,17 @@ int nfs41_walk_client_list(struct nfs_client *new,
				nfs_put_client(prev);
			prev = pos;

			nfs4_schedule_lease_recovery(pos);
			status = nfs_wait_client_init_complete(pos);
			if (status < 0) {
				nfs_put_client(pos);
				spin_lock(&nn->nfs_client_lock);
				continue;
			if (status == 0) {
				nfs4_schedule_lease_recovery(pos);
				status = nfs4_wait_clnt_recover(pos);
			}
			status = pos->cl_cons_state;
			spin_lock(&nn->nfs_client_lock);
			if (status < 0)
				continue;
		}
		if (pos->cl_cons_state != NFS_CS_READY)
			continue;

		if (pos->rpc_ops != new->rpc_ops)
			continue;
@@ -471,17 +485,18 @@ int nfs41_walk_client_list(struct nfs_client *new,
			continue;

		atomic_inc(&pos->cl_count);
		spin_unlock(&nn->nfs_client_lock);
		*result = pos;
		status = 0;
		dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
			__func__, pos, atomic_read(&pos->cl_count));

		*result = pos;
		return 0;
		break;
	}

	/* No matching nfs_client found. */
	spin_unlock(&nn->nfs_client_lock);
	dprintk("NFS: <-- %s status = %d\n", __func__, status);
	if (prev)
		nfs_put_client(prev);
	return status;
}
#endif	/* CONFIG_NFS_V4_1 */
+24 −19
Original line number Diff line number Diff line
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
	return ret;
}

/**
 * nfs_find_best_sec - Find a security mechanism supported locally
 * @flavors: List of security tuples returned by SECINFO procedure
 *
 * Return the pseudoflavor of the first security mechanism in
 * "flavors" that is locally supported.  Return RPC_AUTH_UNIX if
 * no matching flavor is found in the array.  The "flavors" array
 * is searched in the order returned from the server, per RFC 3530
 * recommendation.
 */
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{
	struct gss_api_mech *mech;
	struct xdr_netobj oid;
	int i;
	rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
	rpc_authflavor_t pseudoflavor;
	struct nfs4_secinfo4 *secinfo;
	unsigned int i;

	for (i = 0; i < flavors->num_flavors; i++) {
		struct nfs4_secinfo_flavor *flavor;
		flavor = &flavors->flavors[i];

		if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
			pseudoflavor = flavor->flavor;
			break;
		} else if (flavor->flavor == RPC_AUTH_GSS) {
			oid.len  = flavor->gss.sec_oid4.len;
			oid.data = flavor->gss.sec_oid4.data;
			mech = gss_mech_get_by_OID(&oid);
			if (!mech)
				continue;
			pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
			gss_mech_put(mech);
		secinfo = &flavors->flavors[i];

		switch (secinfo->flavor) {
		case RPC_AUTH_NULL:
		case RPC_AUTH_UNIX:
		case RPC_AUTH_GSS:
			pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
							&secinfo->flavor_info);
			if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
				return pseudoflavor;
			break;
		}
	}

	return pseudoflavor;
	return RPC_AUTH_UNIX;
}

static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
+90 −46
Original line number Diff line number Diff line
@@ -769,6 +769,7 @@ struct nfs4_opendata {
	struct iattr attrs;
	unsigned long timestamp;
	unsigned int rpc_done : 1;
	unsigned int is_recover : 1;
	int rpc_status;
	int cancelled;
};
@@ -1101,9 +1102,12 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
		/* Save the delegation */
		nfs4_stateid_copy(&stateid, &delegation->stateid);
		rcu_read_unlock();
		nfs_release_seqid(opendata->o_arg.seqid);
		if (!opendata->is_recover) {
			ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
			if (ret != 0)
				goto out;
		}
		ret = -EAGAIN;

		/* Try to update the stateid using the delegation */
@@ -1543,15 +1547,20 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
		rcu_read_lock();
		delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
		if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
		    data->o_arg.claim != NFS4_OPEN_CLAIM_DELEG_CUR_FH &&
		    can_open_delegated(delegation, data->o_arg.fmode))
			goto unlock_no_action;
		rcu_read_unlock();
	}
	/* Update client id. */
	data->o_arg.clientid = clp->cl_clientid;
	if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
	switch (data->o_arg.claim) {
	case NFS4_OPEN_CLAIM_PREVIOUS:
	case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
	case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
		data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
	case NFS4_OPEN_CLAIM_FH:
		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
		nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
	}
	data->timestamp = jiffies;
@@ -1665,8 +1674,11 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
	data->rpc_done = 0;
	data->rpc_status = 0;
	data->cancelled = 0;
	if (isrecover)
	data->is_recover = 0;
	if (isrecover) {
		nfs4_set_sequence_privileged(&o_arg->seq_args);
		data->is_recover = 1;
	}
	task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -2130,20 +2142,25 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
		.rpc_cred	= cred,
        };
	unsigned long timestamp = jiffies;
	fmode_t fmode;
	bool truncate;
	int status;

	nfs_fattr_init(fattr);

	if (state != NULL && nfs4_valid_open_stateid(state)) {
	/* Servers should only apply open mode checks for file size changes */
	truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
	fmode = truncate ? FMODE_WRITE : FMODE_READ;

	if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
		/* Use that stateid */
	} else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
		struct nfs_lockowner lockowner = {
			.l_owner = current->files,
			.l_pid = current->tgid,
		};
		nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
				&lockowner);
	} else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
				FMODE_WRITE)) {
		/* Use that stateid */
	} else
		nfs4_stateid_copy(&arg.stateid, &zero_stateid);

@@ -2167,6 +2184,13 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
		err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
		switch (err) {
		case -NFS4ERR_OPENMODE:
			if (!(sattr->ia_valid & ATTR_SIZE)) {
				pr_warn_once("NFSv4: server %s is incorrectly "
						"applying open mode checks to "
						"a SETATTR that is not "
						"changing file size.\n",
						server->nfs_client->cl_hostname);
			}
			if (state && !(state->state & FMODE_WRITE)) {
				err = -EBADF;
				if (sattr->ia_valid & ATTR_OPEN)
@@ -2536,7 +2560,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl

	auth = rpcauth_create(flavor, server->client);
	if (IS_ERR(auth)) {
		ret = -EIO;
		ret = -EACCES;
		goto out;
	}
	ret = nfs4_lookup_root(server, fhandle, info);
@@ -2544,27 +2568,36 @@ out:
	return ret;
}

/*
 * Retry pseudoroot lookup with various security flavors.  We do this when:
 *
 *   NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
 *   NFSv4.1: the server does not support the SECINFO_NO_NAME operation
 *
 * Returns zero on success, or a negative NFS4ERR value, or a
 * negative errno value.
 */
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
			      struct nfs_fsinfo *info)
{
	int i, len, status = 0;
	rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];

	len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
	if (len < 0)
		return len;

	for (i = 0; i < len; i++) {
		/* AUTH_UNIX is the default flavor if none was specified,
		 * thus has already been tried. */
		if (flav_array[i] == RPC_AUTH_UNIX)
			continue;
	/* Per 3530bis 15.33.5 */
	static const rpc_authflavor_t flav_array[] = {
		RPC_AUTH_GSS_KRB5P,
		RPC_AUTH_GSS_KRB5I,
		RPC_AUTH_GSS_KRB5,
		RPC_AUTH_UNIX,			/* courtesy */
		RPC_AUTH_NULL,
	};
	int status = -EPERM;
	size_t i;

	for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
		status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
		if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
			continue;
		break;
	}

	/*
	 * -EACCESS could mean that the user doesn't have correct permissions
	 * to access the mount.  It could also mean that we tried to mount
@@ -2577,24 +2610,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
	return status;
}

/*
 * get the file handle for the "/" directory on the server
static int nfs4_do_find_root_sec(struct nfs_server *server,
		struct nfs_fh *fhandle, struct nfs_fsinfo *info)
{
	int mv = server->nfs_client->cl_minorversion;
	return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
}

/**
 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
 * @server: initialized nfs_server handle
 * @fhandle: we fill in the pseudo-fs root file handle
 * @info: we fill in an FSINFO struct
 *
 * Returns zero on success, or a negative errno.
 */
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
			 struct nfs_fsinfo *info)
{
	int minor_version = server->nfs_client->cl_minorversion;
	int status = nfs4_lookup_root(server, fhandle, info);
	if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
		/*
		 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
		 * by nfs4_map_errors() as this function exits.
		 */
		status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
	int status;

	status = nfs4_lookup_root(server, fhandle, info);
	if ((status == -NFS4ERR_WRONGSEC) &&
	    !(server->flags & NFS_MOUNT_SECFLAVOUR))
		status = nfs4_do_find_root_sec(server, fhandle, info);

	if (status == 0)
		status = nfs4_server_capabilities(server, fhandle);
	if (status == 0)
		status = nfs4_do_fsinfo(server, fhandle, info);

	return nfs4_map_errors(status);
}

@@ -3473,12 +3518,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
	struct nfs4_exception exception = { };
	unsigned long now = jiffies;
	int err;

	do {
		err = nfs4_handle_exception(server,
				_nfs4_do_fsinfo(server, fhandle, fsinfo),
				&exception);
		err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
		if (err == 0) {
			struct nfs_client *clp = server->nfs_client;

			spin_lock(&clp->cl_lock);
			clp->cl_lease_time = fsinfo->lease_time * HZ;
			clp->cl_last_renewal = now;
			spin_unlock(&clp->cl_lock);
			break;
		}
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);
	return err;
}
@@ -4319,27 +4373,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
		struct nfs4_setclientid_res *arg,
		struct rpc_cred *cred)
{
	struct nfs_fsinfo fsinfo;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
		.rpc_argp = arg,
		.rpc_resp = &fsinfo,
		.rpc_cred = cred,
	};
	unsigned long now;
	int status;

	dprintk("NFS call  setclientid_confirm auth=%s, (client ID %llx)\n",
		clp->cl_rpcclient->cl_auth->au_ops->au_name,
		clp->cl_clientid);
	now = jiffies;
	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
	if (status == 0) {
		spin_lock(&clp->cl_lock);
		clp->cl_lease_time = fsinfo.lease_time * HZ;
		clp->cl_last_renewal = now;
		spin_unlock(&clp->cl_lock);
	}
	dprintk("NFS reply setclientid_confirm: %d\n", status);
	return status;
}
+18 −50
Original line number Diff line number Diff line
@@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
	return cred;
}

static void nfs4_clear_machine_cred(struct nfs_client *clp)
{
	struct rpc_cred *cred;

	spin_lock(&clp->cl_lock);
	cred = clp->cl_machine_cred;
	clp->cl_machine_cred = NULL;
	spin_unlock(&clp->cl_lock);
	if (cred != NULL)
		put_rpccred(cred);
}

static struct rpc_cred *
nfs4_get_renew_cred_server_locked(struct nfs_server *server)
{
@@ -1776,10 +1764,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
		return -EPERM;
	case -EACCES:
		if (clp->cl_machine_cred == NULL)
			return -EACCES;
		/* Handle case where the user hasn't set up machine creds */
		nfs4_clear_machine_cred(clp);
	case -NFS4ERR_DELAY:
	case -ETIMEDOUT:
	case -EAGAIN:
@@ -1874,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
{
	const struct nfs4_state_recovery_ops *ops =
				clp->cl_mvops->reboot_recovery_ops;
	rpc_authflavor_t *flavors, flav, save;
	struct rpc_clnt *clnt;
	struct rpc_cred *cred;
	int i, len, status;
	int i, status;

	dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);

	len = NFS_MAX_SECFLAVORS;
	flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
	if (flavors == NULL) {
		status = -ENOMEM;
		goto out;
	}
	len = rpcauth_list_flavors(flavors, len);
	if (len < 0) {
		status = len;
		goto out_free;
	}
	clnt = clp->cl_rpcclient;
	save = clnt->cl_auth->au_flavor;
	i = 0;

	mutex_lock(&nfs_clid_init_mutex);
	status  = -ENOENT;
again:
	status  = -ENOENT;
	cred = ops->get_clid_cred(clp);
	if (cred == NULL)
		goto out_unlock;
@@ -1908,12 +1879,6 @@ again:
	switch (status) {
	case 0:
		break;

	case -EACCES:
		if (clp->cl_machine_cred == NULL)
			break;
		/* Handle case where the user hasn't set up machine creds */
		nfs4_clear_machine_cred(clp);
	case -NFS4ERR_DELAY:
	case -ETIMEDOUT:
	case -EAGAIN:
@@ -1922,22 +1887,23 @@ again:
		dprintk("NFS: %s after status %d, retrying\n",
			__func__, status);
		goto again;

	case -EACCES:
		if (i++)
			break;
	case -NFS4ERR_CLID_INUSE:
	case -NFS4ERR_WRONGSEC:
		status = -EPERM;
		if (i >= len)
			break;

		flav = flavors[i++];
		if (flav == save)
			flav = flavors[i++];
		clnt = rpc_clone_client_set_auth(clnt, flav);
		clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
		if (IS_ERR(clnt)) {
			status = PTR_ERR(clnt);
			break;
		}
		clp->cl_rpcclient = clnt;
		/* Note: this is safe because we haven't yet marked the
		 * client as ready, so we are the only user of
		 * clp->cl_rpcclient
		 */
		clnt = xchg(&clp->cl_rpcclient, clnt);
		rpc_shutdown_client(clnt);
		clnt = clp->cl_rpcclient;
		goto again;

	case -NFS4ERR_MINOR_VERS_MISMATCH:
@@ -1948,13 +1914,15 @@ again:
	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
				 * in nfs4_exchange_id */
		status = -EKEYEXPIRED;
		break;
	default:
		pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
				__func__, status);
		status = -EIO;
	}

out_unlock:
	mutex_unlock(&nfs_clid_init_mutex);
out_free:
	kfree(flavors);
out:
	dprintk("NFS: %s: status = %d\n", __func__, status);
	return status;
}
+2 −0
Original line number Diff line number Diff line
@@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,

	dfprintk(MOUNT, "--> nfs4_try_mount()\n");

	if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR)
		data->auth_flavors[0] = RPC_AUTH_UNIX;
	export_path = data->nfs_server.export_path;
	data->nfs_server.export_path = "/";
	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
Loading