aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakuma Umeya <tumeya@redhat.com>2010-12-15 00:09:01 -0500
committerJ. Bruce Fields <bfields@redhat.com>2011-01-04 19:43:01 -0500
commit6f3d772fb8a039de8f21d725f5e38c252b4c0efd (patch)
treea62c900be0d2766223f0e5630cebaaf2ffee0efb
parent3c726023402a2f3b28f49b9d90ebf9e71151157d (diff)
nfs4: set source address when callback is generated
when callback is generated in NFSv4 server, it doesn't set the source address. When an alias IP is utilized on NFSv4 server and suppose the client is accessing via that alias IP (e.g. eth0:0), the client invokes the callback to the IP address that is set on the original device (e.g. eth0). This behavior results in timeout of xprt. The patch sets the IP address that the client should invoke callback to. Signed-off-by: Takuma Umeya <tumeya@redhat.com> [bfields@redhat.com: Simplify gen_callback arguments, use helper function] Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4callback.c1
-rw-r--r--fs/nfsd/nfs4state.c22
-rw-r--r--fs/nfsd/state.h1
3 files changed, 21 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index a08580553fda..dd183af24fe6 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -484,6 +484,7 @@ static int setup_callback_client(struct nfs4_client *clp,
484 .net = &init_net, 484 .net = &init_net,
485 .address = (struct sockaddr *) &conn->cb_addr, 485 .address = (struct sockaddr *) &conn->cb_addr,
486 .addrsize = conn->cb_addrlen, 486 .addrsize = conn->cb_addrlen,
487 .saddress = (struct sockaddr *) &conn->cb_saddr,
487 .timeout = &timeparms, 488 .timeout = &timeparms,
488 .program = &cb_program, 489 .program = &cb_program,
489 .version = 0, 490 .version = 0,
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 87d4c48b6069..b583e4e800ab 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1163,10 +1163,26 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
1163 return NULL; 1163 return NULL;
1164} 1164}
1165 1165
1166static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
1167{
1168 switch (family) {
1169 case AF_INET:
1170 ((struct sockaddr_in *)sa)->sin_family = AF_INET;
1171 ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
1172 return;
1173 case AF_INET6:
1174 ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
1175 ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
1176 return;
1177 }
1178}
1179
1166static void 1180static void
1167gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) 1181gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
1168{ 1182{
1169 struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 1183 struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
1184 struct sockaddr *sa = svc_addr(rqstp);
1185 u32 scopeid = rpc_get_scope_id(sa);
1170 unsigned short expected_family; 1186 unsigned short expected_family;
1171 1187
1172 /* Currently, we only support tcp and tcp6 for the callback channel */ 1188 /* Currently, we only support tcp and tcp6 for the callback channel */
@@ -1192,6 +1208,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
1192 1208
1193 conn->cb_prog = se->se_callback_prog; 1209 conn->cb_prog = se->se_callback_prog;
1194 conn->cb_ident = se->se_callback_ident; 1210 conn->cb_ident = se->se_callback_ident;
1211 rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
1195 return; 1212 return;
1196out_err: 1213out_err:
1197 conn->cb_addr.ss_family = AF_UNSPEC; 1214 conn->cb_addr.ss_family = AF_UNSPEC;
@@ -1768,7 +1785,6 @@ __be32
1768nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 1785nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1769 struct nfsd4_setclientid *setclid) 1786 struct nfsd4_setclientid *setclid)
1770{ 1787{
1771 struct sockaddr *sa = svc_addr(rqstp);
1772 struct xdr_netobj clname = { 1788 struct xdr_netobj clname = {
1773 .len = setclid->se_namelen, 1789 .len = setclid->se_namelen,
1774 .data = setclid->se_name, 1790 .data = setclid->se_name,
@@ -1871,7 +1887,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1871 * for consistent minorversion use throughout: 1887 * for consistent minorversion use throughout:
1872 */ 1888 */
1873 new->cl_minorversion = 0; 1889 new->cl_minorversion = 0;
1874 gen_callback(new, setclid, rpc_get_scope_id(sa)); 1890 gen_callback(new, setclid, rqstp);
1875 add_to_unconfirmed(new, strhashval); 1891 add_to_unconfirmed(new, strhashval);
1876 setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 1892 setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
1877 setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 1893 setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 84b230217b1b..cf6dc83fd545 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -96,6 +96,7 @@ struct nfs4_delegation {
96struct nfs4_cb_conn { 96struct nfs4_cb_conn {
97 /* SETCLIENTID info */ 97 /* SETCLIENTID info */
98 struct sockaddr_storage cb_addr; 98 struct sockaddr_storage cb_addr;
99 struct sockaddr_storage cb_saddr;
99 size_t cb_addrlen; 100 size_t cb_addrlen;
100 u32 cb_prog; /* used only in 4.0 case; 101 u32 cb_prog; /* used only in 4.0 case;
101 per-session otherwise */ 102 per-session otherwise */