Skip to content

Commit

Permalink
SUNRPC: use sockaddr + size when creating remote transport endpoints
Browse files Browse the repository at this point in the history
Prepare for more generic transport endpoint handling needed by transports
that might use different forms of addressing, such as IPv6.

Introduce a single function call to replace the two-call
xprt_create_proto/rpc_create_client API.  Define a new rpc_create_args
structure that allows callers to pass in remote endpoint addresses of
varying length.

Test-plan:
Compile kernel with CONFIG_NFS enabled.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Chuck Lever authored and Trond Myklebust committed Sep 23, 2006
1 parent 6ca9482 commit c286676
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 0 deletions.
22 changes: 22 additions & 0 deletions include/linux/sunrpc/clnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,28 @@ struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
struct rpc_clnt *rpc_new_client(struct rpc_xprt *xprt, char *servname,
struct rpc_program *info,
u32 version, rpc_authflavor_t authflavor);

struct rpc_create_args {
int protocol;
struct sockaddr *address;
size_t addrsize;
struct rpc_timeout *timeout;
char *servername;
struct rpc_program *program;
u32 version;
rpc_authflavor_t authflavor;
unsigned long flags;
};

/* Values for "flags" field */
#define RPC_CLNT_CREATE_HARDRTRY (1UL << 0)
#define RPC_CLNT_CREATE_INTR (1UL << 1)
#define RPC_CLNT_CREATE_AUTOBIND (1UL << 2)
#define RPC_CLNT_CREATE_ONESHOT (1UL << 3)
#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4)
#define RPC_CLNT_CREATE_NOPING (1UL << 5)

struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
struct rpc_program *, int);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
Expand Down
1 change: 1 addition & 0 deletions include/linux/sunrpc/xprt.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long
/*
* Generic internal transport functions
*/
struct rpc_xprt * xprt_create_transport(int proto, struct sockaddr *addr, size_t size, struct rpc_timeout *toparms);
void xprt_connect(struct rpc_task *task);
void xprt_reserve(struct rpc_task *task);
int xprt_reserve_xprt(struct rpc_task *task);
Expand Down
61 changes: 61 additions & 0 deletions net/sunrpc/clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,67 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
return ERR_PTR(err);
}

/*
* rpc_create - create an RPC client and transport with one call
* @args: rpc_clnt create argument structure
*
* Creates and initializes an RPC transport and an RPC client.
*
* It can ping the server in order to determine if it is up, and to see if
* it supports this program and version. RPC_CLNT_CREATE_NOPING disables
* this behavior so asynchronous tasks can also use rpc_create.
*/
struct rpc_clnt *rpc_create(struct rpc_create_args *args)
{
struct rpc_xprt *xprt;
struct rpc_clnt *clnt;

xprt = xprt_create_transport(args->protocol, args->address,
args->addrsize, args->timeout);
if (IS_ERR(xprt))
return (struct rpc_clnt *)xprt;

/*
* By default, kernel RPC client connects from a reserved port.
* CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
* but it is always enabled for rpciod, which handles the connect
* operation.
*/
xprt->resvport = 1;
if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
xprt->resvport = 0;

dprintk("RPC: creating %s client for %s (xprt %p)\n",
args->program->name, args->servername, xprt);

clnt = rpc_new_client(xprt, args->servername, args->program,
args->version, args->authflavor);
if (IS_ERR(clnt))
return clnt;

if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
int err = rpc_ping(clnt, RPC_TASK_SOFT|RPC_TASK_NOINTR);
if (err != 0) {
rpc_shutdown_client(clnt);
return ERR_PTR(err);
}
}

clnt->cl_softrtry = 1;
if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
clnt->cl_softrtry = 0;

if (args->flags & RPC_CLNT_CREATE_INTR)
clnt->cl_intr = 1;
if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
clnt->cl_autobind = 1;
if (args->flags & RPC_CLNT_CREATE_ONESHOT)
clnt->cl_oneshot = 1;

return clnt;
}
EXPORT_SYMBOL(rpc_create);

/**
* Create an RPC client
* @xprt - pointer to xprt struct
Expand Down
75 changes: 75 additions & 0 deletions net/sunrpc/xprt.c
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,81 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
to->to_exponential = 0;
}

/**
* xprt_create_transport - create an RPC transport
* @proto: requested transport protocol
* @ap: remote peer address
* @size: length of address
* @to: timeout parameters
*
*/
struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to)
{
int result;
struct rpc_xprt *xprt;
struct rpc_rqst *req;

if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) {
dprintk("RPC: xprt_create_transport: no memory\n");
return ERR_PTR(-ENOMEM);
}
if (size <= sizeof(xprt->addr)) {
memcpy(&xprt->addr, ap, size);
xprt->addrlen = size;
} else {
kfree(xprt);
dprintk("RPC: xprt_create_transport: address too large\n");
return ERR_PTR(-EBADF);
}

switch (proto) {
case IPPROTO_UDP:
result = xs_setup_udp(xprt, to);
break;
case IPPROTO_TCP:
result = xs_setup_tcp(xprt, to);
break;
default:
printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
proto);
return ERR_PTR(-EIO);
}
if (result) {
kfree(xprt);
dprintk("RPC: xprt_create_transport: failed, %d\n", result);
return ERR_PTR(result);
}

spin_lock_init(&xprt->transport_lock);
spin_lock_init(&xprt->reserve_lock);

INIT_LIST_HEAD(&xprt->free);
INIT_LIST_HEAD(&xprt->recv);
INIT_WORK(&xprt->task_cleanup, xprt_autoclose, xprt);
init_timer(&xprt->timer);
xprt->timer.function = xprt_init_autodisconnect;
xprt->timer.data = (unsigned long) xprt;
xprt->last_used = jiffies;
xprt->cwnd = RPC_INITCWND;

rpc_init_wait_queue(&xprt->binding, "xprt_binding");
rpc_init_wait_queue(&xprt->pending, "xprt_pending");
rpc_init_wait_queue(&xprt->sending, "xprt_sending");
rpc_init_wait_queue(&xprt->resend, "xprt_resend");
rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");

/* initialize free list */
for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--)
list_add(&req->rq_list, &xprt->free);

xprt_init_xid(xprt);

dprintk("RPC: created transport %p with %u slots\n", xprt,
xprt->max_reqs);

return xprt;
}

static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
{
int result;
Expand Down

0 comments on commit c286676

Please sign in to comment.