Exemplo n.º 1
0
static int nfs_lookup_with_sec(struct nfs_server *server, struct dentry *parent,
			       struct dentry *dentry, struct path *path,
			       struct nfs_fh *fh, struct nfs_fattr *fattr,
			       rpc_authflavor_t *flavor)
{
	struct rpc_clnt *clone;
	struct rpc_auth *auth;
	int err;

	err = nfs_negotiate_security(parent, path->dentry, flavor);
	if (err < 0)
		goto out;
	clone  = rpc_clone_client(server->client);
	auth   = rpcauth_create(*flavor, clone);
	if (!auth) {
		err = -EIO;
		goto out_shutdown;
	}
	err = server->nfs_client->rpc_ops->lookup(clone, parent->d_inode,
						  &path->dentry->d_name,
						  fh, fattr);
out_shutdown:
	rpc_shutdown_client(clone);
out:
	return err;
}
Exemplo n.º 2
0
void nfsd4_process_cb_update(struct nfsd4_callback *cb)
{
	struct nfs4_cb_conn conn;
	struct nfs4_client *clp = cb->cb_clp;
	int err;

	/*
	 * This is either an update, or the client dying; in either case,
	 * kill the old client:
	 */
	if (clp->cl_cb_client) {
		rpc_shutdown_client(clp->cl_cb_client);
		clp->cl_cb_client = NULL;
	}
	if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
		return;
	spin_lock(&clp->cl_lock);
	/*
	 * Only serialized callback code is allowed to clear these
	 * flags; main nfsd code can only set them:
	 */
	BUG_ON(!clp->cl_cb_flags);
	clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
	memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
	spin_unlock(&clp->cl_lock);

	err = setup_callback_client(clp, &conn);
	if (err)
		warn_no_callback_path(clp, err);
}
void clear_gssp_clnt(struct sunrpc_net *sn)
{
	mutex_lock(&sn->gssp_lock);
	if (sn->gssp_clnt) {
		rpc_shutdown_client(sn->gssp_clnt);
		sn->gssp_clnt = NULL;
	}
	mutex_unlock(&sn->gssp_lock);
}
Exemplo n.º 4
0
struct vfsmount *nfs_d_automount(struct path *path)
{
	struct vfsmount *mnt;
	struct dentry *parent;
	struct nfs_fh *fh = NULL;
	struct nfs_fattr *fattr = NULL;
	struct rpc_clnt *client;

	dprintk("--> nfs_d_automount()\n");

	mnt = ERR_PTR(-ESTALE);
	if (IS_ROOT(path->dentry))
		goto out_nofree;

	mnt = ERR_PTR(-ENOMEM);
	fh = nfs_alloc_fhandle();
	fattr = nfs_alloc_fattr();
	if (fh == NULL || fattr == NULL)
		goto out;

	dprintk("%s: enter\n", __func__);

	
	parent = dget_parent(path->dentry);
	client = nfs_lookup_mountpoint(parent->d_inode, &path->dentry->d_name, fh, fattr);
	dput(parent);
	if (IS_ERR(client)) {
		mnt = ERR_CAST(client);
		goto out;
	}

	if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
		mnt = nfs_do_refmount(client, path->dentry);
	else
		mnt = nfs_do_submount(path->dentry, fh, fattr, client->cl_auth->au_flavor);
	rpc_shutdown_client(client);

	if (IS_ERR(mnt))
		goto out;

	dprintk("%s: done, success\n", __func__);
	mntget(mnt); 
	mnt_set_expiry(mnt, &nfs_automount_list);
	schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);

out:
	nfs_free_fattr(fattr);
	nfs_free_fhandle(fh);
out_nofree:
	if (IS_ERR(mnt))
		dprintk("<-- %s(): error %ld\n", __func__, PTR_ERR(mnt));
	else
		dprintk("<-- %s() = %p\n", __func__, mnt);
	return mnt;
}
Exemplo n.º 5
0
int set_gssp_clnt(struct net *net)
{
	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
	struct rpc_clnt *clnt;
	int ret;

	mutex_lock(&sn->gssp_lock);
	ret = gssp_rpc_create(net, &clnt);
	if (!ret) {
		if (sn->gssp_clnt)
			rpc_shutdown_client(sn->gssp_clnt);
		sn->gssp_clnt = clnt;
	}
	mutex_unlock(&sn->gssp_lock);
	return ret;
}
Exemplo n.º 6
0
static int do_probe_callback(void *data)
{
	struct nfs4_client *clp = data;
	struct nfs4_callback *cb = &clp->cl_callback;
	struct rpc_message msg = {
		.rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
		.rpc_argp       = clp,
	};
	int status;

	status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);

	if (status) {
		rpc_shutdown_client(cb->cb_client);
		cb->cb_client = NULL;
	} else
		atomic_set(&cb->cb_set, 1);
	put_nfs4_client(clp);
	return 0;
}
Exemplo n.º 7
0
void
nfs_put_super(struct super_block *sb)
{
    struct nfs_server *server = &sb->u.nfs_sb.s_server;
    struct rpc_clnt	*rpc;

    if ((rpc = server->client) != NULL)
        rpc_shutdown_client(rpc);

    if (!(server->flags & NFS_MOUNT_NONLM))
        lockd_down();	/* release rpc.lockd */
    rpciod_down();		/* release rpciod */
    /*
     * Invalidate the dircache for this superblock.
     */
    nfs_invalidate_dircache_sb(sb);

    kfree(server->hostname);

    MOD_DEC_USE_COUNT;
}
Exemplo n.º 8
0
/*
 * Shut down the hosts module.
 * Note that this routine is called only at server shutdown time.
 */
void
nlm_shutdown_hosts(void)
{
	struct nlm_host	*host;
	int		i;

	dprintk("lockd: shutting down host module\n");
	down(&nlm_host_sema);

	/* First, make all hosts eligible for gc */
	dprintk("lockd: nuking all hosts...\n");
	for (i = 0; i < NLM_HOST_NRHASH; i++) {
		for (host = nlm_hosts[i]; host; host = host->h_next) {
			host->h_expires = jiffies - 1;
			if (host->h_rpcclnt != NULL) {
				rpc_shutdown_client(host->h_rpcclnt);
				host->h_rpcclnt = NULL;
			}
		}
	}

	/* Then, perform a garbage collection pass */
	nlm_gc_hosts();
	up(&nlm_host_sema);

	/* complain if any hosts are left */
	if (nrhosts) {
		printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
		dprintk("lockd: %d hosts left:\n", nrhosts);
		for (i = 0; i < NLM_HOST_NRHASH; i++) {
			for (host = nlm_hosts[i]; host; host = host->h_next) {
				dprintk("       %s (cnt %d use %d exp %ld)\n",
					host->h_name, atomic_read(&host->h_count),
					host->h_inuse, host->h_expires);
			}
		}
	}
}
/*
 * Please call rpc_shutdown_client() when you are done with this client.
 */
struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *clnt, struct inode *inode,
					struct qstr *name)
{
	struct rpc_clnt *clone;
	struct rpc_auth *auth;
	rpc_authflavor_t flavor;

	flavor = nfs4_negotiate_security(inode, name);
	if (flavor < 0)
		return ERR_PTR(flavor);

	clone = rpc_clone_client(clnt);
	if (IS_ERR(clone))
		return clone;

	auth = rpcauth_create(flavor, clone);
	if (!auth) {
		rpc_shutdown_client(clone);
		clone = ERR_PTR(-EIO);
	}

	return clone;
}
Exemplo n.º 10
0
Arquivo: inode.c Projeto: nhanh0/hah
void
nfs_put_super(struct super_block *sb)
{
	struct nfs_server *server = &sb->u.nfs_sb.s_server;
	struct rpc_clnt	*rpc;

	/*
	 * First get rid of the request flushing daemon.
	 * Relies on rpc_shutdown_client() waiting on all
	 * client tasks to finish.
	 */
	nfs_reqlist_exit(server);

	if ((rpc = server->client) != NULL)
		rpc_shutdown_client(rpc);

	nfs_reqlist_free(server);

	if (!(server->flags & NFS_MOUNT_NONLM))
		lockd_down();	/* release rpc.lockd */
	rpciod_down();		/* release rpciod */

	kfree(server->hostname);
}
Exemplo n.º 11
0
static int do_probe_callback(void *data)
{
	struct nfs4_client *clp = data;
	struct sockaddr_in	addr;
	struct nfs4_callback    *cb = &clp->cl_callback;
	struct rpc_timeout	timeparms = {
		.to_initval	= (NFSD_LEASE_TIME/4) * HZ,
		.to_retries	= 5,
		.to_maxval	= (NFSD_LEASE_TIME/2) * HZ,
		.to_exponential	= 1,
	};
	struct rpc_program *	program = &cb->cb_program;
	struct rpc_create_args args = {
		.protocol	= IPPROTO_TCP,
		.address	= (struct sockaddr *)&addr,
		.addrsize	= sizeof(addr),
		.timeout	= &timeparms,
		.program	= program,
		.version	= nfs_cb_version[1]->number,
		.authflavor	= RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
		.flags		= (RPC_CLNT_CREATE_NOPING),
	};
	struct rpc_message msg = {
		.rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
		.rpc_argp       = clp,
	};
	struct rpc_clnt *client;
	int status;

	/* Initialize address */
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(cb->cb_port);
	addr.sin_addr.s_addr = htonl(cb->cb_addr);

	/* Initialize rpc_program */
	program->name = "nfs4_cb";
	program->number = cb->cb_prog;
	program->nrvers = ARRAY_SIZE(nfs_cb_version);
	program->version = nfs_cb_version;
	program->stats = &cb->cb_stat;

	/* Initialize rpc_stat */
	memset(program->stats, 0, sizeof(cb->cb_stat));
	program->stats->program = program;

	/* Create RPC client */
	client = rpc_create(&args);
	if (IS_ERR(client)) {
		dprintk("NFSD: couldn't create callback client\n");
		status = PTR_ERR(client);
		goto out_err;
	}

	status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);

	if (status)
		goto out_release_client;

	cb->cb_client = client;
	atomic_set(&cb->cb_set, 1);
	put_nfs4_client(clp);
	return 0;
out_release_client:
	rpc_shutdown_client(client);
out_err:
	put_nfs4_client(clp);
	dprintk("NFSD: warning: no callback path to client %.*s\n",
		(int)clp->cl_name.len, clp->cl_name.data);
	return status;
}

/*
 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
 */
void
nfsd4_probe_callback(struct nfs4_client *clp)
{
	struct task_struct *t;

	BUG_ON(atomic_read(&clp->cl_callback.cb_set));

	/* the task holds a reference to the nfs4_client struct */
	atomic_inc(&clp->cl_count);

	t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");

	if (IS_ERR(t))
		atomic_dec(&clp->cl_count);

	return;
}

/*
 * called with dp->dl_count inc'ed.
 * nfs4_lock_state() may or may not have been called.
 */
void
nfsd4_cb_recall(struct nfs4_delegation *dp)
{
	struct nfs4_client *clp = dp->dl_client;
	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
	struct nfs4_cb_recall *cbr = &dp->dl_recall;
	struct rpc_message msg = {
		.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
		.rpc_argp = cbr,
	};
	int retries = 1;
	int status = 0;

	cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */
	cbr->cbr_dp = dp;

	status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
	while (retries--) {
		switch (status) {
			case -EIO:
				/* Network partition? */
				atomic_set(&clp->cl_callback.cb_set, 0);
			case -EBADHANDLE:
			case -NFS4ERR_BAD_STATEID:
				/* Race: client probably got cb_recall
				 * before open reply granting delegation */
				break;
			default:
				goto out_put_cred;
		}
		ssleep(2);
		status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
	}
out_put_cred:
	/*
	 * Success or failure, now we're either waiting for lease expiration
	 * or deleg_return.
	 */
	put_nfs4_client(clp);
	nfs4_put_delegation(dp);
	return;
}
Exemplo n.º 12
0
/*
 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
 */
void
nfsd4_probe_callback(struct nfs4_client *clp)
{
	struct sockaddr_in	addr, saddr;
	struct nfs4_callback    *cb = &clp->cl_callback;
	struct rpc_timeout	timeparms;
	struct rpc_xprt *	xprt;
	struct rpc_program *	program = &cb->cb_program;
	struct rpc_stat *	stat = &cb->cb_stat;
	struct rpc_clnt *	clnt;
	struct rpc_message msg = {
		.rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
		.rpc_argp       = clp,
	};
	char                    hostname[32];
	int status;

	if (atomic_read(&cb->cb_set))
		return;

	/* Initialize address */
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(cb->cb_port);
	addr.sin_addr.s_addr = htonl(cb->cb_addr);

	/* Initialize timeout */
	timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ;
	timeparms.to_retries = 0;
	timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ;
	timeparms.to_exponential = 1;

	/* Create RPC transport */
	xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms);
	if (IS_ERR(xprt)) {
		dprintk("NFSD: couldn't create callback transport!\n");
		goto out_err;
	}

	/* Initialize rpc_program */
	program->name = "nfs4_cb";
	program->number = cb->cb_prog;
	program->nrvers = ARRAY_SIZE(nfs_cb_version);
	program->version = nfs_cb_version;
	program->stats = stat;

	/* Initialize rpc_stat */
	memset(stat, 0, sizeof(struct rpc_stat));
	stat->program = program;

	/* Create RPC client
 	 *
	 * XXX AUTH_UNIX only - need AUTH_GSS....
	 */
	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
	clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
	if (IS_ERR(clnt)) {
		dprintk("NFSD: couldn't create callback client\n");
		goto out_err;
	}
	clnt->cl_intr = 0;
	clnt->cl_softrtry = 1;

	/* Set source address */
	if (cb->cb_saddr){
		memset(&saddr, 0, sizeof(saddr));
		saddr.sin_family = AF_INET;
		saddr.sin_addr.s_addr = cb->cb_saddr;
		xprt->srcaddr = saddr;
	}

	/* Kick rpciod, put the call on the wire. */

	if (rpciod_up() != 0) {
		dprintk("nfsd: couldn't start rpciod for callbacks!\n");
		goto out_clnt;
	}

	cb->cb_client = clnt;

	/* the task holds a reference to the nfs4_client struct */
	atomic_inc(&clp->cl_count);

	msg.rpc_cred = nfsd4_lookupcred(clp,0);
	if (IS_ERR(msg.rpc_cred))
		goto out_rpciod;
	status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
	put_rpccred(msg.rpc_cred);

	if (status != 0) {
		dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
		goto out_rpciod;
	}
	return;

out_rpciod:
	atomic_dec(&clp->cl_count);
	rpciod_down();
	cb->cb_client = NULL;
out_clnt:
	rpc_shutdown_client(clnt);
out_err:
	dprintk("NFSD: warning: no callback path to client %.*s\n",
		(int)clp->cl_name.len, clp->cl_name.data);
}
Exemplo n.º 13
0
/**
 * rpcb_register - set or unset a port registration with the local rpcbind svc
 * @prog: RPC program number to bind
 * @vers: RPC version number to bind
 * @prot: transport protocol to use to make this request
 * @port: port value to register
 * @okay: result code
 *
 * port == 0 means unregister, port != 0 means register.
 *
 * This routine supports only rpcbind version 2.
 */
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
{
	struct sockaddr_in sin = {
		.sin_family		= AF_INET,
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
	};
	struct rpcbind_args map = {
		.r_prog		= prog,
		.r_vers		= vers,
		.r_prot		= prot,
		.r_port		= port,
	};
	struct rpc_message msg = {
		.rpc_proc	= &rpcb_procedures2[port ?
					RPCBPROC_SET : RPCBPROC_UNSET],
		.rpc_argp	= &map,
		.rpc_resp	= okay,
	};
	struct rpc_clnt *rpcb_clnt;
	int error = 0;

	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
			"rpcbind\n", (port ? "" : "un"),
			prog, vers, prot, port);

	rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
				sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1);
	if (IS_ERR(rpcb_clnt))
		return PTR_ERR(rpcb_clnt);

	error = rpc_call_sync(rpcb_clnt, &msg, 0);

	rpc_shutdown_client(rpcb_clnt);
	if (error < 0)
		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
				"server (errno %d).\n", -error);
	dprintk("RPC:       registration status %d/%d\n", error, *okay);

	return error;
}

/**
 * rpcb_getport_sync - obtain the port for an RPC service on a given host
 * @sin: address of remote peer
 * @prog: RPC program number to bind
 * @vers: RPC version number to bind
 * @prot: transport protocol to use to make this request
 *
 * Return value is the requested advertised port number,
 * or a negative errno value.
 *
 * Called from outside the RPC client in a synchronous task context.
 * Uses default timeout parameters specified by underlying transport.
 *
 * XXX: Needs to support IPv6
 */
int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
{
	struct rpcbind_args map = {
		.r_prog		= prog,
		.r_vers		= vers,
		.r_prot		= prot,
		.r_port		= 0,
	};
	struct rpc_message msg = {
		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
		.rpc_argp	= &map,
		.rpc_resp	= &map.r_port,
	};
	struct rpc_clnt	*rpcb_clnt;
	int status;

	dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);

	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
				sizeof(*sin), prot, 2, 0);
	if (IS_ERR(rpcb_clnt))
		return PTR_ERR(rpcb_clnt);

	status = rpc_call_sync(rpcb_clnt, &msg, 0);
	rpc_shutdown_client(rpcb_clnt);

	if (status >= 0) {
		if (map.r_port != 0)
			return map.r_port;
		status = -EACCES;
	}
	return status;
}
EXPORT_SYMBOL_GPL(rpcb_getport_sync);

static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version)
{
	struct rpc_message msg = {
		.rpc_proc = rpcb_next_version[version].rpc_proc,
		.rpc_argp = map,
		.rpc_resp = &map->r_port,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = rpcb_clnt,
		.rpc_message = &msg,
		.callback_ops = &rpcb_getport_ops,
		.callback_data = map,
		.flags = RPC_TASK_ASYNC,
	};

	return rpc_run_task(&task_setup_data);
}

/**
 * rpcb_getport_async - obtain the port for a given RPC service on a given host
 * @task: task that is waiting for portmapper request
 *
 * This one can be called for an ongoing RPC request, and can be used in
 * an async (rpciod) context.
 */
void rpcb_getport_async(struct rpc_task *task)
{
	struct rpc_clnt *clnt = task->tk_client;
	u32 bind_version;
	struct rpc_xprt *xprt = task->tk_xprt;
	struct rpc_clnt	*rpcb_clnt;
	static struct rpcbind_args *map;
	struct rpc_task	*child;
	struct sockaddr_storage addr;
	struct sockaddr *sap = (struct sockaddr *)&addr;
	size_t salen;
	int status;
	struct rpcb_info *info;

	dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
		task->tk_pid, __FUNCTION__,
		clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);

	/* Autobind on cloned rpc clients is discouraged */
	BUG_ON(clnt->cl_parent != clnt);

	if (xprt_test_and_set_binding(xprt)) {
		status = -EAGAIN;	/* tell caller to check again */
		dprintk("RPC: %5u %s: waiting for another binder\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nowake;
	}

	/* Put self on queue before sending rpcbind request, in case
	 * rpcb_getport_done completes before we return from rpc_run_task */
	rpc_sleep_on(&xprt->binding, task, NULL, NULL);

	/* Someone else may have bound if we slept */
	if (xprt_bound(xprt)) {
		status = 0;
		dprintk("RPC: %5u %s: already bound\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}

	salen = rpc_peeraddr(clnt, sap, sizeof(addr));

	/* Don't ever use rpcbind v2 for AF_INET6 requests */
	switch (sap->sa_family) {
	case AF_INET:
		info = rpcb_next_version;
		break;
	case AF_INET6:
		info = rpcb_next_version6;
		break;
	default:
		status = -EAFNOSUPPORT;
		dprintk("RPC: %5u %s: bad address family\n",
				task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}
	if (info[xprt->bind_index].rpc_proc == NULL) {
		xprt->bind_index = 0;
		status = -EPFNOSUPPORT;
		dprintk("RPC: %5u %s: no more getport versions available\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}
	bind_version = info[xprt->bind_index].rpc_vers;

	dprintk("RPC: %5u %s: trying rpcbind version %u\n",
		task->tk_pid, __FUNCTION__, bind_version);

	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
				bind_version, 0);
	if (IS_ERR(rpcb_clnt)) {
		status = PTR_ERR(rpcb_clnt);
		dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
			task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
		goto bailout_nofree;
	}

	map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
	if (!map) {
		status = -ENOMEM;
		dprintk("RPC: %5u %s: no memory available\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}
	map->r_prog = clnt->cl_prog;
	map->r_vers = clnt->cl_vers;
	map->r_prot = xprt->prot;
	map->r_port = 0;
	map->r_xprt = xprt_get(xprt);
	map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
	map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
	map->r_owner = RPCB_OWNER_STRING;	/* ignored for GETADDR */

	child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index);
	rpc_release_client(rpcb_clnt);
	if (IS_ERR(child)) {
		status = -EIO;
		dprintk("RPC: %5u %s: rpc_run_task failed\n",
			task->tk_pid, __FUNCTION__);
		goto bailout;
	}
	rpc_put_task(child);

	task->tk_xprt->stat.bind_count++;
	return;

bailout:
	kfree(map);
	xprt_put(xprt);
bailout_nofree:
	rpcb_wake_rpcbind_waiters(xprt, status);
bailout_nowake:
	task->tk_status = status;
}
EXPORT_SYMBOL_GPL(rpcb_getport_async);

/*
 * Rpcbind child task calls this callback via tk_exit.
 */
static void rpcb_getport_done(struct rpc_task *child, void *data)
{
	struct rpcbind_args *map = data;
	struct rpc_xprt *xprt = map->r_xprt;
	int status = child->tk_status;

	/* Garbage reply: retry with a lesser rpcbind version */
	if (status == -EIO)
		status = -EPROTONOSUPPORT;

	/* rpcbind server doesn't support this rpcbind protocol version */
	if (status == -EPROTONOSUPPORT)
		xprt->bind_index++;

	if (status < 0) {
		/* rpcbind server not available on remote host? */
		xprt->ops->set_port(xprt, 0);
	} else if (map->r_port == 0) {
		/* Requested RPC service wasn't registered on remote host */
		xprt->ops->set_port(xprt, 0);
		status = -EACCES;
	} else {
		/* Succeeded */
		xprt->ops->set_port(xprt, map->r_port);
		xprt_set_bound(xprt);
		status = 0;
	}

	dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
			child->tk_pid, status, map->r_port);

	rpcb_wake_rpcbind_waiters(xprt, status);
}

static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
			       struct rpcbind_args *rpcb)
{
	dprintk("RPC:       rpcb_encode_mapping(%u, %u, %d, %u)\n",
			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
	*p++ = htonl(rpcb->r_prog);
	*p++ = htonl(rpcb->r_vers);
	*p++ = htonl(rpcb->r_prot);
	*p++ = htonl(rpcb->r_port);

	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
	return 0;
}

static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
			       unsigned short *portp)
{
	*portp = (unsigned short) ntohl(*p++);
	dprintk("RPC:      rpcb_decode_getport result %u\n",
			*portp);
	return 0;
}

static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
			   unsigned int *boolp)
{
	*boolp = (unsigned int) ntohl(*p++);
	dprintk("RPC:      rpcb_decode_set result %u\n",
			*boolp);
	return 0;
}

static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
			       struct rpcbind_args *rpcb)
{
	dprintk("RPC:       rpcb_encode_getaddr(%u, %u, %s)\n",
			rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
	*p++ = htonl(rpcb->r_prog);
	*p++ = htonl(rpcb->r_vers);

	p = xdr_encode_string(p, rpcb->r_netid);
	p = xdr_encode_string(p, rpcb->r_addr);
	p = xdr_encode_string(p, rpcb->r_owner);

	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);

	return 0;
}
Exemplo n.º 14
0
/*
 * The way this works is that the mount process passes a structure
 * in the data argument which contains the server's IP address
 * and the root file handle obtained from the server's mount
 * daemon. We stash these away in the private superblock fields.
 */
struct super_block *
nfs_read_super(struct super_block *sb, void *raw_data, int silent)
{
    struct nfs_mount_data	*data = (struct nfs_mount_data *) raw_data;
    struct nfs_server	*server;
    struct rpc_xprt		*xprt;
    struct rpc_clnt		*clnt;
    struct nfs_fh		*root_fh;
    struct inode		*root_inode;
    unsigned int		authflavor;
    int			tcp;
    struct sockaddr_in	srvaddr;
    struct rpc_timeout	timeparms;
    struct nfs_fattr	fattr;

    MOD_INC_USE_COUNT;
    if (!data)
        goto out_miss_args;

    /* No NFS V3. */
    if (data->flags & NFS_MOUNT_VER3)
        goto out_fail;

    /* Don't complain if "mount" is newer. */
    if (data->version < NFS_MOUNT_VERSION) {
        printk("nfs warning: mount version %s than kernel\n",
               data->version < NFS_MOUNT_VERSION ? "older" : "newer");
        if (data->version < 2)
            data->namlen = 0;
        if (data->version < 3)
            data->bsize  = 0;
    }

    /* We now require that the mount process passes the remote address */
    memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
    if (srvaddr.sin_addr.s_addr == INADDR_ANY)
        goto out_no_remote;

    lock_super(sb);

    sb->s_flags |= MS_ODD_RENAME; /* This should go away */

    sb->s_magic      = NFS_SUPER_MAGIC;
    sb->s_op         = &nfs_sops;
    sb->s_blocksize  = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
    sb->u.nfs_sb.s_root = data->root;
    server           = &sb->u.nfs_sb.s_server;
    server->rsize    = nfs_block_size(data->rsize, NULL);
    server->wsize    = nfs_block_size(data->wsize, NULL);
    server->flags    = data->flags;

    if (data->flags & NFS_MOUNT_NOAC) {
        data->acregmin = data->acregmax = 0;
        data->acdirmin = data->acdirmax = 0;
    }
    server->acregmin = data->acregmin*HZ;
    server->acregmax = data->acregmax*HZ;
    server->acdirmin = data->acdirmin*HZ;
    server->acdirmax = data->acdirmax*HZ;

    server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
    if (!server->hostname)
        goto out_unlock;
    strcpy(server->hostname, data->hostname);

    /* Which protocol do we use? */
    tcp   = (data->flags & NFS_MOUNT_TCP);

    /* Initialize timeout values */
    timeparms.to_initval = data->timeo * HZ / 10;
    timeparms.to_retries = data->retrans;
    timeparms.to_maxval  = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
    timeparms.to_exponential = 1;

    /* Now create transport and client */
    xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
                             &srvaddr, &timeparms);
    if (xprt == NULL)
        goto out_no_xprt;

    /* Choose authentication flavor */
    authflavor = RPC_AUTH_UNIX;
    if (data->flags & NFS_MOUNT_SECURE)
        authflavor = RPC_AUTH_DES;
    else if (data->flags & NFS_MOUNT_KERBEROS)
        authflavor = RPC_AUTH_KRB;

    clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
                             NFS_VERSION, authflavor);
    if (clnt == NULL)
        goto out_no_client;

    clnt->cl_intr     = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
    clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
    clnt->cl_chatty   = 1;
    server->client    = clnt;

    /* Fire up rpciod if not yet running */
    if (rpciod_up() != 0)
        goto out_no_iod;

    /*
     * Keep the super block locked while we try to get
     * the root fh attributes.
     */
    root_fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
    if (!root_fh)
        goto out_no_fh;
    *root_fh = data->root;

    if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
        goto out_no_fattr;

    clnt->cl_to_err = 1;

    root_inode = __nfs_fhget(sb, &fattr);
    if (!root_inode)
        goto out_no_root;
    sb->s_root = d_alloc_root(root_inode, NULL);
    if (!sb->s_root)
        goto out_no_root;
    sb->s_root->d_op = &nfs_dentry_operations;
    sb->s_root->d_fsdata = root_fh;

    /* We're airborne */
    unlock_super(sb);

    /* Check whether to start the lockd process */
    if (!(server->flags & NFS_MOUNT_NONLM))
        lockd_up();
    return sb;

    /* Yargs. It didn't work out. */
out_no_root:
    printk("nfs_read_super: get root inode failed\n");
    iput(root_inode);
    goto out_free_fh;

out_no_fattr:
    printk("nfs_read_super: get root fattr failed\n");
out_free_fh:
    kfree(root_fh);
out_no_fh:
    rpciod_down();
    goto out_shutdown;

out_no_iod:
    printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
out_shutdown:
    rpc_shutdown_client(server->client);
    goto out_free_host;

out_no_client:
    printk(KERN_WARNING "NFS: cannot create RPC client.\n");
    xprt_destroy(xprt);
    goto out_free_host;

out_no_xprt:
    printk(KERN_WARNING "NFS: cannot create RPC transport.\n");

out_free_host:
    kfree(server->hostname);
out_unlock:
    unlock_super(sb);
    goto out_fail;

out_no_remote:
    printk("NFS: mount program didn't pass remote address!\n");
    goto out_fail;

out_miss_args:
    printk("nfs_read_super: missing data argument\n");

out_fail:
    sb->s_dev = 0;
    MOD_DEC_USE_COUNT;
    return NULL;
}
Exemplo n.º 15
0
/**
 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
 * @dentry - parent directory
 * @locations - array of NFSv4 server location information
 *
 */
static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
					    const struct nfs4_fs_locations *locations)
{
	struct vfsmount *mnt = ERR_PTR(-ENOENT);
	struct nfs_clone_mount mountdata = {
		.sb = dentry->d_sb,
		.dentry = dentry,
		.authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor,
	};
	char *page = NULL, *page2 = NULL;
	int loc, error;

	if (locations == NULL || locations->nlocations <= 0)
		goto out;

	dprintk("%s: referral at %s/%s\n", __func__,
		dentry->d_parent->d_name.name, dentry->d_name.name);

	page = (char *) __get_free_page(GFP_USER);
	if (!page)
		goto out;

	page2 = (char *) __get_free_page(GFP_USER);
	if (!page2)
		goto out;

	/* Ensure fs path is a prefix of current dentry path */
	error = nfs4_validate_fspath(dentry, locations, page, page2);
	if (error < 0) {
		mnt = ERR_PTR(error);
		goto out;
	}

	for (loc = 0; loc < locations->nlocations; loc++) {
		const struct nfs4_fs_location *location = &locations->locations[loc];

		if (location == NULL || location->nservers <= 0 ||
		    location->rootpath.ncomponents == 0)
			continue;

		mnt = try_location(&mountdata, page, page2, location);
		if (!IS_ERR(mnt))
			break;
	}

out:
	free_page((unsigned long) page);
	free_page((unsigned long) page2);
	dprintk("%s: done\n", __func__);
	return mnt;
}

/*
 * nfs_do_refmount - handle crossing a referral on server
 * @dentry - dentry of referral
 *
 */
static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
{
	struct vfsmount *mnt = ERR_PTR(-ENOMEM);
	struct dentry *parent;
	struct nfs4_fs_locations *fs_locations = NULL;
	struct page *page;
	int err;

	/* BUG_ON(IS_ROOT(dentry)); */
	dprintk("%s: enter\n", __func__);

	page = alloc_page(GFP_KERNEL);
	if (page == NULL)
		goto out;

	fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
	if (fs_locations == NULL)
		goto out_free;

	/* Get locations */
	mnt = ERR_PTR(-ENOENT);

	parent = dget_parent(dentry);
	dprintk("%s: getting locations for %s/%s\n",
		__func__, parent->d_name.name, dentry->d_name.name);

	err = nfs4_proc_fs_locations(client, parent->d_inode, &dentry->d_name, fs_locations, page);
	dput(parent);
	if (err != 0 ||
	    fs_locations->nlocations <= 0 ||
	    fs_locations->fs_path.ncomponents <= 0)
		goto out_free;

	mnt = nfs_follow_referral(dentry, fs_locations);
out_free:
	__free_page(page);
	kfree(fs_locations);
out:
	dprintk("%s: done\n", __func__);
	return mnt;
}

struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
			       struct nfs_fh *fh, struct nfs_fattr *fattr)
{
	struct dentry *parent = dget_parent(dentry);
	struct rpc_clnt *client;
	struct vfsmount *mnt;

	/* Look it up again to get its attributes and sec flavor */
	client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr);
	dput(parent);
	if (IS_ERR(client))
		return ERR_CAST(client);

	if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
		mnt = nfs_do_refmount(client, dentry);
	else
		mnt = nfs_do_submount(dentry, fh, fattr, client->cl_auth->au_flavor);

	rpc_shutdown_client(client);
	return mnt;
}