goto out;
}
+ /**
+ * nfs_umount - Notify a server that we have unmounted this export
+ * @info: pointer to umount request arguments
+ *
+ * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
+ * use UDP.
+ */
+ void nfs_umount(const struct nfs_mount_request *info)
+ {
+ static const struct rpc_timeout nfs_umnt_timeout = {
+ .to_initval = 1 * HZ,
+ .to_maxval = 3 * HZ,
+ .to_retries = 2,
+ };
+ struct rpc_create_args args = {
+ .protocol = IPPROTO_UDP,
+ .address = info->sap,
+ .addrsize = info->salen,
+ .timeout = &nfs_umnt_timeout,
+ .servername = info->hostname,
+ .program = &mnt_program,
+ .version = info->version,
+ .authflavor = RPC_AUTH_UNIX,
+ .flags = RPC_CLNT_CREATE_NOPING,
+ };
+ struct mountres result;
+ struct rpc_message msg = {
+ .rpc_argp = info->dirpath,
+ .rpc_resp = &result,
+ };
+ struct rpc_clnt *clnt;
+ int status;
+
+ if (info->noresvport)
+ args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+
+ clnt = rpc_create(&args);
+ if (unlikely(IS_ERR(clnt)))
+ goto out_clnt_err;
+
+ dprintk("NFS: sending UMNT request for %s:%s\n",
+ (info->hostname ? info->hostname : "server"), info->dirpath);
+
+ if (info->version == NFS_MNT3_VERSION)
+ msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
+ else
+ msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
+
+ status = rpc_call_sync(clnt, &msg, 0);
+ rpc_shutdown_client(clnt);
+
+ if (unlikely(status < 0))
+ goto out_call_err;
+
+ return;
+
+ out_clnt_err:
+ dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
+ PTR_ERR(clnt));
+ return;
+
+ out_call_err:
+ dprintk("NFS: UMNT request failed, status=%d\n", status);
+ }
+
/*
* XDR encode/decode functions for MOUNT
*/
return -EIO;
status = ntohl(*p);
- for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) {
+ for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
if (mnt_errtbl[i].status == status) {
res->errno = mnt_errtbl[i].errno;
return 0;
return -EIO;
status = ntohl(*p);
- for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) {
+ for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
if (mnt3_errtbl[i].status == status) {
res->errno = mnt3_errtbl[i].errno;
return 0;
.p_statidx = MOUNTPROC_MNT,
.p_name = "MOUNT",
},
+ [MOUNTPROC_UMNT] = {
+ .p_proc = MOUNTPROC_UMNT,
+ .p_encode = (kxdrproc_t)mnt_enc_dirpath,
+ .p_arglen = MNT_enc_dirpath_sz,
+ .p_statidx = MOUNTPROC_UMNT,
+ .p_name = "UMOUNT",
+ },
};
static struct rpc_procinfo mnt3_procedures[] = {
.p_statidx = MOUNTPROC3_MNT,
.p_name = "MOUNT",
},
+ [MOUNTPROC3_UMNT] = {
+ .p_proc = MOUNTPROC3_UMNT,
+ .p_encode = (kxdrproc_t)mnt_enc_dirpath,
+ .p_arglen = MNT_enc_dirpath_sz,
+ .p_statidx = MOUNTPROC3_UMNT,
+ .p_name = "UMOUNT",
+ },
};
* Connection of transports
*/
struct delayed_work connect_worker;
- struct sockaddr_storage addr;
- unsigned short port;
+ struct sockaddr_storage srcaddr;
+ unsigned short srcport;
/*
* UDP socket buffer size parameters
return (struct sockaddr_in6 *) &xprt->addr;
}
- static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt,
- const char *protocol,
- const char *netid)
+ static void xs_format_common_peer_addresses(struct rpc_xprt *xprt)
{
- struct sockaddr_in *addr = xs_addr_in(xprt);
- char *buf;
+ struct sockaddr *sap = xs_addr(xprt);
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
+ char buf[128];
- buf = kzalloc(20, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr);
- }
- xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
-
- buf = kzalloc(8, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 8, "%u",
- ntohs(addr->sin_port));
- }
- xprt->address_strings[RPC_DISPLAY_PORT] = buf;
-
- xprt->address_strings[RPC_DISPLAY_PROTO] = protocol;
-
- buf = kzalloc(48, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 48, "addr=%pI4 port=%u proto=%s",
- &addr->sin_addr.s_addr,
- ntohs(addr->sin_port),
- protocol);
- }
- xprt->address_strings[RPC_DISPLAY_ALL] = buf;
-
- buf = kzalloc(10, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 10, "%02x%02x%02x%02x",
- NIPQUAD(addr->sin_addr.s_addr));
- }
- xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
+ (void)rpc_ntop(sap, buf, sizeof(buf));
+ xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL);
- buf = kzalloc(8, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 8, "%4hx",
- ntohs(addr->sin_port));
- }
- xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
-
- buf = kzalloc(30, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 30, "%pI4.%u.%u",
- &addr->sin_addr.s_addr,
- ntohs(addr->sin_port) >> 8,
- ntohs(addr->sin_port) & 0xff);
+ switch (sap->sa_family) {
+ case AF_INET:
+ sin = xs_addr_in(xprt);
+ (void)snprintf(buf, sizeof(buf), "%02x%02x%02x%02x",
+ NIPQUAD(sin->sin_addr.s_addr));
+ break;
+ case AF_INET6:
+ sin6 = xs_addr_in6(xprt);
+ (void)snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr);
+ break;
+ default:
+ BUG();
}
- xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
-
- xprt->address_strings[RPC_DISPLAY_NETID] = netid;
+ xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL);
}
- static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt,
- const char *protocol,
- const char *netid)
+ static void xs_format_common_peer_ports(struct rpc_xprt *xprt)
{
- struct sockaddr_in6 *addr = xs_addr_in6(xprt);
- char *buf;
+ struct sockaddr *sap = xs_addr(xprt);
+ char buf[128];
- buf = kzalloc(40, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 40, "%pI6",&addr->sin6_addr);
- }
- xprt->address_strings[RPC_DISPLAY_ADDR] = buf;
+ (void)snprintf(buf, sizeof(buf), "%u", rpc_get_port(sap));
+ xprt->address_strings[RPC_DISPLAY_PORT] = kstrdup(buf, GFP_KERNEL);
- buf = kzalloc(8, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 8, "%u",
- ntohs(addr->sin6_port));
- }
- xprt->address_strings[RPC_DISPLAY_PORT] = buf;
+ (void)snprintf(buf, sizeof(buf), "%4hx", rpc_get_port(sap));
+ xprt->address_strings[RPC_DISPLAY_HEX_PORT] = kstrdup(buf, GFP_KERNEL);
+ }
+ static void xs_format_peer_addresses(struct rpc_xprt *xprt,
+ const char *protocol,
+ const char *netid)
+ {
xprt->address_strings[RPC_DISPLAY_PROTO] = protocol;
+ xprt->address_strings[RPC_DISPLAY_NETID] = netid;
+ xs_format_common_peer_addresses(xprt);
+ xs_format_common_peer_ports(xprt);
+ }
- buf = kzalloc(64, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 64, "addr=%pI6 port=%u proto=%s",
- &addr->sin6_addr,
- ntohs(addr->sin6_port),
- protocol);
- }
- xprt->address_strings[RPC_DISPLAY_ALL] = buf;
-
- buf = kzalloc(36, GFP_KERNEL);
- if (buf)
- snprintf(buf, 36, "%pi6", &addr->sin6_addr);
-
- xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf;
-
- buf = kzalloc(8, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 8, "%4hx",
- ntohs(addr->sin6_port));
- }
- xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf;
-
- buf = kzalloc(50, GFP_KERNEL);
- if (buf) {
- snprintf(buf, 50, "%pI6.%u.%u",
- &addr->sin6_addr,
- ntohs(addr->sin6_port) >> 8,
- ntohs(addr->sin6_port) & 0xff);
- }
- xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf;
+ static void xs_update_peer_port(struct rpc_xprt *xprt)
+ {
+ kfree(xprt->address_strings[RPC_DISPLAY_HEX_PORT]);
+ kfree(xprt->address_strings[RPC_DISPLAY_PORT]);
- xprt->address_strings[RPC_DISPLAY_NETID] = netid;
+ xs_format_common_peer_ports(xprt);
}
static void xs_free_peer_addresses(struct rpc_xprt *xprt)
*/
static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
{
- struct sockaddr *addr = xs_addr(xprt);
-
dprintk("RPC: setting port for xprt %p to %u\n", xprt, port);
- switch (addr->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *)addr)->sin_port = htons(port);
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
- break;
- default:
- BUG();
- }
+ rpc_set_port(xs_addr(xprt), port);
+ xs_update_peer_port(xprt);
}
static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock)
{
- unsigned short port = transport->port;
+ unsigned short port = transport->srcport;
if (port == 0 && transport->xprt.resvport)
port = xs_get_random_port();
static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port)
{
- if (transport->port != 0)
- transport->port = 0;
+ if (transport->srcport != 0)
+ transport->srcport = 0;
if (!transport->xprt.resvport)
return 0;
if (port <= xprt_min_resvport || port > xprt_max_resvport)
unsigned short port = xs_get_srcport(transport, sock);
unsigned short last;
- sa = (struct sockaddr_in *)&transport->addr;
+ sa = (struct sockaddr_in *)&transport->srcaddr;
myaddr.sin_addr = sa->sin_addr;
do {
myaddr.sin_port = htons(port);
if (port == 0)
break;
if (err == 0) {
- transport->port = port;
+ transport->srcport = port;
break;
}
last = port;
unsigned short port = xs_get_srcport(transport, sock);
unsigned short last;
- sa = (struct sockaddr_in6 *)&transport->addr;
+ sa = (struct sockaddr_in6 *)&transport->srcaddr;
myaddr.sin6_addr = sa->sin6_addr;
do {
myaddr.sin6_port = htons(port);
if (port == 0)
break;
if (err == 0) {
- transport->port = port;
+ transport->srcport = port;
break;
}
last = port;
goto out;
}
- dprintk("RPC: worker connecting xprt %p to address: %s\n",
- xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+ dprintk("RPC: worker connecting xprt %p via %s to "
+ "%s (port %s)\n", xprt,
+ xprt->address_strings[RPC_DISPLAY_PROTO],
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PORT]);
xs_udp_finish_connecting(xprt, sock);
status = 0;
goto out;
}
- dprintk("RPC: worker connecting xprt %p to address: %s\n",
- xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+ dprintk("RPC: worker connecting xprt %p via %s to "
+ "%s (port %s)\n", xprt,
+ xprt->address_strings[RPC_DISPLAY_PROTO],
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PORT]);
xs_udp_finish_connecting(xprt, sock);
status = 0;
goto out_eagain;
}
- dprintk("RPC: worker connecting xprt %p to address: %s\n",
- xprt, xprt->address_strings[RPC_DISPLAY_ALL]);
+ dprintk("RPC: worker connecting xprt %p via %s to "
+ "%s (port %s)\n", xprt,
+ xprt->address_strings[RPC_DISPLAY_PROTO],
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PORT]);
status = xs_tcp_finish_connecting(xprt, sock);
dprintk("RPC: %p connect status %d connected %d sock state %d\n",
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
seq_printf(seq, "\txprt:\tudp %u %lu %lu %lu %lu %Lu %Lu\n",
- transport->port,
+ transport->srcport,
xprt->stat.bind_count,
xprt->stat.sends,
xprt->stat.recvs,
idle_time = (long)(jiffies - xprt->last_used) / HZ;
seq_printf(seq, "\txprt:\ttcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu\n",
- transport->port,
+ transport->srcport,
xprt->stat.bind_count,
xprt->stat.connect_count,
xprt->stat.connect_time,
memcpy(&xprt->addr, args->dstaddr, args->addrlen);
xprt->addrlen = args->addrlen;
if (args->srcaddr)
- memcpy(&new->addr, args->srcaddr, args->addrlen);
+ memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
return xprt;
}
INIT_DELAYED_WORK(&transport->connect_worker,
xs_udp_connect_worker4);
- xs_format_ipv4_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
+ xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP);
break;
case AF_INET6:
if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
INIT_DELAYED_WORK(&transport->connect_worker,
xs_udp_connect_worker6);
- xs_format_ipv6_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
+ xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
break;
default:
kfree(xprt);
return ERR_PTR(-EAFNOSUPPORT);
}
- dprintk("RPC: set up transport to address %s\n",
- xprt->address_strings[RPC_DISPLAY_ALL]);
+ if (xprt_bound(xprt))
+ dprintk("RPC: set up xprt to %s (port %s) via %s\n",
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PORT],
+ xprt->address_strings[RPC_DISPLAY_PROTO]);
+ else
+ dprintk("RPC: set up xprt to %s (autobind) via %s\n",
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PROTO]);
if (try_module_get(THIS_MODULE))
return xprt;
if (((struct sockaddr_in *)addr)->sin_port != htons(0))
xprt_set_bound(xprt);
- INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4);
- xs_format_ipv4_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
+ INIT_DELAYED_WORK(&transport->connect_worker,
+ xs_tcp_connect_worker4);
+ xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP);
break;
case AF_INET6:
if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0))
xprt_set_bound(xprt);
- INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6);
- xs_format_ipv6_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
+ INIT_DELAYED_WORK(&transport->connect_worker,
+ xs_tcp_connect_worker6);
+ xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
break;
default:
kfree(xprt);
return ERR_PTR(-EAFNOSUPPORT);
}
- dprintk("RPC: set up transport to address %s\n",
- xprt->address_strings[RPC_DISPLAY_ALL]);
+ if (xprt_bound(xprt))
+ dprintk("RPC: set up xprt to %s (port %s) via %s\n",
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PORT],
+ xprt->address_strings[RPC_DISPLAY_PROTO]);
+ else
+ dprintk("RPC: set up xprt to %s (autobind) via %s\n",
+ xprt->address_strings[RPC_DISPLAY_ADDR],
+ xprt->address_strings[RPC_DISPLAY_PROTO]);
+
if (try_module_get(THIS_MODULE))
return xprt;
xprt_unregister_transport(&xs_udp_transport);
xprt_unregister_transport(&xs_tcp_transport);
}
+
+static int param_set_uint_minmax(const char *val, struct kernel_param *kp,
+ unsigned int min, unsigned int max)
+{
+ unsigned long num;
+ int ret;
+
+ if (!val)
+ return -EINVAL;
+ ret = strict_strtoul(val, 0, &num);
+ if (ret == -EINVAL || num < min || num > max)
+ return -EINVAL;
+ *((unsigned int *)kp->arg) = num;
+ return 0;
+}
+
+static int param_set_portnr(const char *val, struct kernel_param *kp)
+{
+ return param_set_uint_minmax(val, kp,
+ RPC_MIN_RESVPORT,
+ RPC_MAX_RESVPORT);
+}
+
+static int param_get_portnr(char *buffer, struct kernel_param *kp)
+{
+ return param_get_uint(buffer, kp);
+}
+#define param_check_portnr(name, p) \
+ __param_check(name, p, unsigned int);
+
+module_param_named(min_resvport, xprt_min_resvport, portnr, 0644);
+module_param_named(max_resvport, xprt_max_resvport, portnr, 0644);
+
+static int param_set_slot_table_size(const char *val, struct kernel_param *kp)
+{
+ return param_set_uint_minmax(val, kp,
+ RPC_MIN_SLOT_TABLE,
+ RPC_MAX_SLOT_TABLE);
+}
+
+static int param_get_slot_table_size(char *buffer, struct kernel_param *kp)
+{
+ return param_get_uint(buffer, kp);
+}
+#define param_check_slot_table_size(name, p) \
+ __param_check(name, p, unsigned int);
+
+module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries,
+ slot_table_size, 0644);
+module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries,
+ slot_table_size, 0644);
+