- fix unusual NFS kernel client problem and add several fixes.
This commit is contained in:
parent
c3388d3bdd
commit
eb3e266891
241
am-utils-6.2-add-NFSv3-nfs_quick_reply-functionality.patch
Normal file
241
am-utils-6.2-add-NFSv3-nfs_quick_reply-functionality.patch
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
am-utils-6.2 - add NFSv3 nfs_quick_reply() functionality
|
||||||
|
|
||||||
|
From: Ian Kent <raven@themaw.net>
|
||||||
|
|
||||||
|
The implementation of the NFS v3 server does not use the hack needed
|
||||||
|
by the nfs_quick_reply() function.
|
||||||
|
|
||||||
|
Now that saving the current transort for later use by nfs_quick_reply()
|
||||||
|
avoids concurrency races it should be ok to use it.
|
||||||
|
|
||||||
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||||
|
---
|
||||||
|
amd/nfs_prot_svc.c | 13 +++++
|
||||||
|
amd/nfs_subr.c | 137 +++++++++++++++++++++++++++++++++++++++++-----------
|
||||||
|
2 files changed, 120 insertions(+), 30 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/amd/nfs_prot_svc.c b/amd/nfs_prot_svc.c
|
||||||
|
index cbde172..29b7551 100644
|
||||||
|
--- a/amd/nfs_prot_svc.c
|
||||||
|
+++ b/amd/nfs_prot_svc.c
|
||||||
|
@@ -180,7 +180,7 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
xdr_result = (xdrproc_t) xdr_diropres;
|
||||||
|
local = (nfssvcproc_t) nfsproc_lookup_2_svc;
|
||||||
|
/*
|
||||||
|
- * Cheap way to pass transp down to amfs_auto_lookuppn so it can
|
||||||
|
+ * Cheap way to pass transp down to amfs_auto_lookup so it can
|
||||||
|
* be stored in the am_node structure and later used for
|
||||||
|
* quick_reply().
|
||||||
|
*/
|
||||||
|
@@ -327,6 +327,8 @@ nfs_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
|
||||||
|
xdrproc_t _xdr_argument, _xdr_result;
|
||||||
|
nfssvcproc_t local;
|
||||||
|
|
||||||
|
+ current_transp = NULL;
|
||||||
|
+
|
||||||
|
switch (rqstp->rq_proc) {
|
||||||
|
case AM_NFS3_NULL:
|
||||||
|
_xdr_argument = (xdrproc_t) xdr_void;
|
||||||
|
@@ -350,6 +352,12 @@ nfs_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
|
||||||
|
_xdr_argument = (xdrproc_t) xdr_am_LOOKUP3args;
|
||||||
|
_xdr_result = (xdrproc_t) xdr_am_LOOKUP3res;
|
||||||
|
local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_lookup_3_svc;
|
||||||
|
+ /*
|
||||||
|
+ * Cheap way to pass transp down to amfs_auto_lookup so it can
|
||||||
|
+ * be stored in the am_node structure and later used for
|
||||||
|
+ * quick_reply().
|
||||||
|
+ */
|
||||||
|
+ current_transp = transp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AM_NFS3_ACCESS:
|
||||||
|
@@ -476,6 +484,9 @@ nfs_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = (*local) (&argument, rqstp);
|
||||||
|
+
|
||||||
|
+ current_transp = NULL;
|
||||||
|
+
|
||||||
|
if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
|
||||||
|
svcerr_systemerr (transp);
|
||||||
|
}
|
||||||
|
diff --git a/amd/nfs_subr.c b/amd/nfs_subr.c
|
||||||
|
index 07d960d..a383618 100644
|
||||||
|
--- a/amd/nfs_subr.c
|
||||||
|
+++ b/amd/nfs_subr.c
|
||||||
|
@@ -87,6 +87,9 @@ struct am_fh3 {
|
||||||
|
};
|
||||||
|
|
||||||
|
/* forward declarations */
|
||||||
|
+static int nfs_quick_reply2(am_node *mp, int error);
|
||||||
|
+static int nfs_quick_reply3(am_node *mp, int error);
|
||||||
|
+
|
||||||
|
/* converting am-filehandles to mount-points */
|
||||||
|
static am_node *fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop);
|
||||||
|
static am_node *fh_to_mp(am_nfs_fh *fhp);
|
||||||
|
@@ -255,46 +258,65 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
|
||||||
|
return &res;
|
||||||
|
}
|
||||||
|
|
||||||
|
-
|
||||||
|
void
|
||||||
|
nfs_quick_reply(am_node *mp, int error)
|
||||||
|
{
|
||||||
|
- SVCXPRT *transp = mp->am_transp;
|
||||||
|
- nfsdiropres res;
|
||||||
|
- xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
|
||||||
|
+ int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * If there's a transp structure then we can reply to the client's
|
||||||
|
- * nfs lookup request.
|
||||||
|
+ * If there's no transp structure then we can't reply to the
|
||||||
|
+ * client's nfs lookup request.
|
||||||
|
*/
|
||||||
|
- if (transp) {
|
||||||
|
- if (error == 0) {
|
||||||
|
- /*
|
||||||
|
- * Construct a valid reply to a lookup request. Same
|
||||||
|
- * code as in nfsproc_lookup_2_svc() above.
|
||||||
|
- */
|
||||||
|
- mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
|
||||||
|
- res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
|
||||||
|
- res.dr_status = NFS_OK;
|
||||||
|
- } else
|
||||||
|
- /*
|
||||||
|
- * Return the error that was passed to us.
|
||||||
|
- */
|
||||||
|
- res.dr_status = nfs_error(error);
|
||||||
|
+ if (!mp->am_transp)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (nfs_dispatcher == nfs_program_2)
|
||||||
|
+ ret = nfs_quick_reply2(mp, error);
|
||||||
|
+ else
|
||||||
|
+ ret = nfs_quick_reply3(mp, error);
|
||||||
|
+
|
||||||
|
+ if (!ret)
|
||||||
|
+ svcerr_systemerr(mp->am_transp);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Free up transp. It's only used for one reply.
|
||||||
|
+ */
|
||||||
|
+ put_nfs_xprt(mp->am_transp);
|
||||||
|
+ mp->am_transp = NULL;
|
||||||
|
+ dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
|
||||||
|
+}
|
||||||
|
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+nfs_quick_reply2(am_node *mp, int error)
|
||||||
|
+{
|
||||||
|
+ SVCXPRT *transp = mp->am_transp;
|
||||||
|
+ nfsdiropres res;
|
||||||
|
+ xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (error == 0) {
|
||||||
|
/*
|
||||||
|
- * Send off our reply
|
||||||
|
+ * Construct a valid reply to a lookup request. Same
|
||||||
|
+ * code as in nfsproc_lookup_2_svc() above.
|
||||||
|
*/
|
||||||
|
- if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res))
|
||||||
|
- svcerr_systemerr(transp);
|
||||||
|
-
|
||||||
|
+ mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
|
||||||
|
+ res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
|
||||||
|
+ res.dr_status = NFS_OK;
|
||||||
|
+ } else
|
||||||
|
/*
|
||||||
|
- * Free up transp. It's only used for one reply.
|
||||||
|
+ * Return the error that was passed to us.
|
||||||
|
*/
|
||||||
|
- put_nfs_xprt(mp->am_transp);
|
||||||
|
- mp->am_transp = NULL;
|
||||||
|
- dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
|
||||||
|
- }
|
||||||
|
+ res.dr_status = nfs_error(error);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Send off our reply
|
||||||
|
+ */
|
||||||
|
+ ret = svc_sendreply(transp,
|
||||||
|
+ (XDRPROC_T_TYPE) xdr_result,
|
||||||
|
+ (SVC_IN_ARG_TYPE) & res);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -890,6 +912,8 @@ mp_to_fh(am_node *mp, am_nfs_fh *fhp)
|
||||||
|
/* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
void
|
||||||
|
mp_to_fh3(am_node *mp, am_nfs_fh3 *fhp)
|
||||||
|
{
|
||||||
|
@@ -1257,6 +1281,61 @@ am_nfs3_lookup_3_svc(am_LOOKUP3args *argp, struct svc_req *rqstp)
|
||||||
|
return &result;
|
||||||
|
}
|
||||||
|
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+nfs_quick_reply3(am_node *mp, int error)
|
||||||
|
+{
|
||||||
|
+ SVCXPRT *transp = mp->am_transp;
|
||||||
|
+ xdrproc_t xdr_result = (xdrproc_t) xdr_am_LOOKUP3res;
|
||||||
|
+ am_LOOKUP3res result;
|
||||||
|
+ am_post_op_attr *post_op_dir;
|
||||||
|
+ am_post_op_attr *post_op_obj;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (error) {
|
||||||
|
+ /*
|
||||||
|
+ * Return the error that was passed to us.
|
||||||
|
+ */
|
||||||
|
+ post_op_dir->attributes_follow = 0;
|
||||||
|
+ result.status = nfs_error(error);
|
||||||
|
+ } else {
|
||||||
|
+ post_op_dir = &result.res_u.ok.dir_attributes;
|
||||||
|
+ post_op_obj = &result.res_u.ok.obj_attributes;
|
||||||
|
+ am_fattr3 *fattr3;
|
||||||
|
+ nfsfattr *fattr;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Construct a valid reply to a lookup request. Same
|
||||||
|
+ * code as in am_nfs3_lookup_3_svc() above.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ /* dir attributes */
|
||||||
|
+ post_op_dir->attributes_follow = 1;
|
||||||
|
+ fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
|
||||||
|
+ parent_fattr_to_fattr3(mp, fattr3);
|
||||||
|
+
|
||||||
|
+ mp_to_fh3(mp, &result.res_u.ok.object);
|
||||||
|
+
|
||||||
|
+ /* mount attributes */
|
||||||
|
+ post_op_obj->attributes_follow = 1;
|
||||||
|
+ fattr = &mp->am_fattr;
|
||||||
|
+ fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
|
||||||
|
+ fattr_to_fattr3(fattr, fattr3);
|
||||||
|
+
|
||||||
|
+ result.status = AM_NFS3_OK;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Send off our reply
|
||||||
|
+ */
|
||||||
|
+ ret = svc_sendreply(transp,
|
||||||
|
+ (XDRPROC_T_TYPE) xdr_result,
|
||||||
|
+ (SVC_IN_ARG_TYPE) &result);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
am_ACCESS3res *
|
||||||
|
am_nfs3_access_3_svc(am_ACCESS3args *argp, struct svc_req *rqstp)
|
||||||
|
{
|
127
am-utils-6.2-add-NFSv3-rpc-request-validation.patch
Normal file
127
am-utils-6.2-add-NFSv3-rpc-request-validation.patch
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
am-utils-6.2 - add NFSv3 rpc request validation
|
||||||
|
|
||||||
|
From: Ian Kent <raven@themaw.net>
|
||||||
|
|
||||||
|
The NFS v2 internal server uses several validation checks for each
|
||||||
|
RPC request it receives, also add this validation for the NFS v3
|
||||||
|
internal server.
|
||||||
|
|
||||||
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||||
|
---
|
||||||
|
amd/nfs_prot_svc.c | 65 +++++++++++++++++++++++++++++++---------------------
|
||||||
|
1 file changed, 39 insertions(+), 26 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/amd/nfs_prot_svc.c b/amd/nfs_prot_svc.c
|
||||||
|
index 29b7551..cae12d4 100644
|
||||||
|
--- a/amd/nfs_prot_svc.c
|
||||||
|
+++ b/amd/nfs_prot_svc.c
|
||||||
|
@@ -71,30 +71,9 @@ dispatcher_t nfs_dispatcher = nfs_program_2;
|
||||||
|
typedef char *(*nfssvcproc_t)(voidp, struct svc_req *);
|
||||||
|
|
||||||
|
|
||||||
|
-void
|
||||||
|
-nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
+static int
|
||||||
|
+validate_rpc_request(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
{
|
||||||
|
- union {
|
||||||
|
- am_nfs_fh nfsproc_getattr_2_arg;
|
||||||
|
- nfssattrargs nfsproc_setattr_2_arg;
|
||||||
|
- nfsdiropargs nfsproc_lookup_2_arg;
|
||||||
|
- am_nfs_fh nfsproc_readlink_2_arg;
|
||||||
|
- nfsreadargs nfsproc_read_2_arg;
|
||||||
|
- nfswriteargs nfsproc_write_2_arg;
|
||||||
|
- nfscreateargs nfsproc_create_2_arg;
|
||||||
|
- nfsdiropargs nfsproc_remove_2_arg;
|
||||||
|
- nfsrenameargs nfsproc_rename_2_arg;
|
||||||
|
- nfslinkargs nfsproc_link_2_arg;
|
||||||
|
- nfssymlinkargs nfsproc_symlink_2_arg;
|
||||||
|
- nfscreateargs nfsproc_mkdir_2_arg;
|
||||||
|
- nfsdiropargs fsproc_rmdir_2_arg;
|
||||||
|
- nfsreaddirargs nfsproc_readdir_2_arg;
|
||||||
|
- am_nfs_fh nfsproc_statfs_2_arg;
|
||||||
|
- } argument;
|
||||||
|
- char *result;
|
||||||
|
- xdrproc_t xdr_argument, xdr_result;
|
||||||
|
- nfssvcproc_t local;
|
||||||
|
-
|
||||||
|
#ifdef HAVE_TRANSPORT_TYPE_TLI
|
||||||
|
/*
|
||||||
|
* On TLI systems we don't use an INET network type, but a "ticlts" (see
|
||||||
|
@@ -109,7 +88,7 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
extern int __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid);
|
||||||
|
if (__rpc_get_local_uid(transp, &u) >= 0 && u != 0) {
|
||||||
|
plog(XLOG_WARNING, "ignoring request from UID %ld, must be 0", (long) u);
|
||||||
|
- return;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
# else /* not HAVE___RPC_GET_LOCAL_UID */
|
||||||
|
dlog("cannot verify local uid for rpc request");
|
||||||
|
@@ -126,7 +105,7 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
plog(XLOG_WARNING, "ignoring request from %s:%u, port not reserved",
|
||||||
|
inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
|
||||||
|
ntohs(sinp->sin_port));
|
||||||
|
- return;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
# endif /* MNT2_NFS_OPT_RESVPORT */
|
||||||
|
/* if the address does not match, ignore the request */
|
||||||
|
@@ -136,16 +115,47 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
plog(XLOG_WARNING, "ignoring request from %s:%u, not a local interface",
|
||||||
|
inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
|
||||||
|
ntohs(sinp->sin_port));
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s",
|
||||||
|
inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
|
||||||
|
ntohs(sinp->sin_port),
|
||||||
|
inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr));
|
||||||
|
- return;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* not HAVE_TRANPORT_TYPE_TLI */
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
|
||||||
|
+{
|
||||||
|
+ union {
|
||||||
|
+ am_nfs_fh nfsproc_getattr_2_arg;
|
||||||
|
+ nfssattrargs nfsproc_setattr_2_arg;
|
||||||
|
+ nfsdiropargs nfsproc_lookup_2_arg;
|
||||||
|
+ am_nfs_fh nfsproc_readlink_2_arg;
|
||||||
|
+ nfsreadargs nfsproc_read_2_arg;
|
||||||
|
+ nfswriteargs nfsproc_write_2_arg;
|
||||||
|
+ nfscreateargs nfsproc_create_2_arg;
|
||||||
|
+ nfsdiropargs nfsproc_remove_2_arg;
|
||||||
|
+ nfsrenameargs nfsproc_rename_2_arg;
|
||||||
|
+ nfslinkargs nfsproc_link_2_arg;
|
||||||
|
+ nfssymlinkargs nfsproc_symlink_2_arg;
|
||||||
|
+ nfscreateargs nfsproc_mkdir_2_arg;
|
||||||
|
+ nfsdiropargs fsproc_rmdir_2_arg;
|
||||||
|
+ nfsreaddirargs nfsproc_readdir_2_arg;
|
||||||
|
+ am_nfs_fh nfsproc_statfs_2_arg;
|
||||||
|
+ } argument;
|
||||||
|
+ char *result;
|
||||||
|
+ xdrproc_t xdr_argument, xdr_result;
|
||||||
|
+ nfssvcproc_t local;
|
||||||
|
+
|
||||||
|
+ if (!validate_rpc_request(rqstp, transp))
|
||||||
|
+ return;
|
||||||
|
|
||||||
|
current_transp = NULL;
|
||||||
|
|
||||||
|
@@ -327,6 +337,9 @@ nfs_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
|
||||||
|
xdrproc_t _xdr_argument, _xdr_result;
|
||||||
|
nfssvcproc_t local;
|
||||||
|
|
||||||
|
+ if (!validate_rpc_request(rqstp, transp))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
current_transp = NULL;
|
||||||
|
|
||||||
|
switch (rqstp->rq_proc) {
|
170
am-utils-6.2-add-get_nfs_xprt-and-put_nfs_xprt-functions.patch
Normal file
170
am-utils-6.2-add-get_nfs_xprt-and-put_nfs_xprt-functions.patch
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
am-utils-6.2 - add get_nfs_xprt() and put_nfs_xprt() functions
|
||||||
|
|
||||||
|
From: Ian Kent <raven@themaw.net>
|
||||||
|
|
||||||
|
The nfs_quick_reply() functionality relies on taking a copy of the
|
||||||
|
current transport for later use.
|
||||||
|
|
||||||
|
The problem with this is the context of the RPC message is kept in
|
||||||
|
the transport and if any RPC message arrives before nfs_quick_reply()
|
||||||
|
is called that context will be corrupted.
|
||||||
|
|
||||||
|
So add a function get_nfs_xprt() to replace the current transport
|
||||||
|
with a new one returning the passed in transort so nfs_quick_reply()
|
||||||
|
can use it later.
|
||||||
|
|
||||||
|
A function put_nfs_xprt() is also added (although not really needed
|
||||||
|
since it just destroys the now unused transport) for completeness.
|
||||||
|
|
||||||
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||||
|
---
|
||||||
|
conf/transp/transp_sockets.c | 44 ++++++++++++++++++++++++++++++++++++++++
|
||||||
|
conf/transp/transp_tli.c | 46 +++++++++++++++++++++++++++++++++++++++++-
|
||||||
|
include/am_utils.h | 2 ++
|
||||||
|
3 files changed, 91 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/conf/transp/transp_sockets.c b/conf/transp/transp_sockets.c
|
||||||
|
index 6326007..98f79c8 100644
|
||||||
|
--- a/conf/transp/transp_sockets.c
|
||||||
|
+++ b/conf/transp/transp_sockets.c
|
||||||
|
@@ -45,6 +45,7 @@
|
||||||
|
#include <am_defs.h>
|
||||||
|
#include <amu.h>
|
||||||
|
|
||||||
|
+static int soNFS = RPC_ANYSOCK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find the IP address that can be used to connect to the local host
|
||||||
|
@@ -273,9 +274,52 @@ create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ soNFS = *soNFSp;
|
||||||
|
+
|
||||||
|
return 0; /* all is well */
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Get a pointer to the current NFS SVCXPRT and replace it
|
||||||
|
+ * with a new one.
|
||||||
|
+ */
|
||||||
|
+SVCXPRT *
|
||||||
|
+get_nfs_xprt(SVCXPRT *nfs_xprt)
|
||||||
|
+{
|
||||||
|
+ SVCXPRT *newxprt;
|
||||||
|
+ int newfd;
|
||||||
|
+
|
||||||
|
+ if (!nfs_xprt || soNFS == RPC_ANYSOCK)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ newfd = dup(soNFS);
|
||||||
|
+ if (newfd < 0)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ xprt_unregister(nfs_xprt);
|
||||||
|
+ newxprt = svcudp_create(newfd);
|
||||||
|
+ if (!newxprt) {
|
||||||
|
+ plog(XLOG_FATAL, "Can't switch to new transport");
|
||||||
|
+ xprt_register(nfs_xprt);
|
||||||
|
+ close(newfd);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ soNFS = newfd;
|
||||||
|
+
|
||||||
|
+ return nfs_xprt;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Destroy a transport previously obtained by get_nfs_xprt().
|
||||||
|
+ */
|
||||||
|
+void put_nfs_xprt(SVCXPRT *nfs_xprt)
|
||||||
|
+{
|
||||||
|
+ if (!nfs_xprt || soNFS == RPC_ANYSOCK)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ svc_destroy(nfs_xprt);
|
||||||
|
+}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the amq service for amd (both TCP and UDP)
|
||||||
|
diff --git a/conf/transp/transp_tli.c b/conf/transp/transp_tli.c
|
||||||
|
index d26a511..ea565cc 100644
|
||||||
|
--- a/conf/transp/transp_tli.c
|
||||||
|
+++ b/conf/transp/transp_tli.c
|
||||||
|
@@ -45,7 +45,8 @@
|
||||||
|
#include <am_defs.h>
|
||||||
|
#include <amu.h>
|
||||||
|
|
||||||
|
-struct netconfig *nfsncp;
|
||||||
|
+struct netconfig *nfsncp = NULL;
|
||||||
|
+static int soNFS = RPC_ANYSOCK;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -456,9 +457,52 @@ create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ soNFS = *soNFSp;
|
||||||
|
+
|
||||||
|
return 0; /* all is well */
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Get a pointer to the current NFS SVCXPRT and replace it
|
||||||
|
+ * with a new one.
|
||||||
|
+ */
|
||||||
|
+SVCXPRT *
|
||||||
|
+get_nfs_xprt(SVCXPRT *nfs_xprt)
|
||||||
|
+{
|
||||||
|
+ SVCXPRT *newxprt;
|
||||||
|
+ int newfd;
|
||||||
|
+
|
||||||
|
+ if (!nfs_xprt || soNFS == RPC_ANYSOCK)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ newfd = dup(soNFS);
|
||||||
|
+ if (newfd < 0)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ xprt_unregister(nfs_xprt);
|
||||||
|
+ newxprt = svc_tli_create(newfd, nfsncp, NULL, 0, 0);
|
||||||
|
+ if (!newxprt) {
|
||||||
|
+ plog(XLOG_FATAL, "Can't switch to new transport");
|
||||||
|
+ xprt_register(nfs_xprt);
|
||||||
|
+ close(newfd);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ soNFS = newfd;
|
||||||
|
+
|
||||||
|
+ return nfs_xprt;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Destroy a transport previously obtained by get_nfs_xprt().
|
||||||
|
+ */
|
||||||
|
+void put_nfs_xprt(SVCXPRT *nfs_xprt)
|
||||||
|
+{
|
||||||
|
+ if (!nfs_xprt || soNFS == RPC_ANYSOCK)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ svc_destroy(nfs_xprt);
|
||||||
|
+}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bind to preferred AMQ port.
|
||||||
|
diff --git a/include/am_utils.h b/include/am_utils.h
|
||||||
|
index 0de881a..ff13c26 100644
|
||||||
|
--- a/include/am_utils.h
|
||||||
|
+++ b/include/am_utils.h
|
||||||
|
@@ -378,6 +378,8 @@ extern void compute_nfs_args(void *nap, mntent_t *mntp, int genflags, struct net
|
||||||
|
extern void destroy_nfs_args(void *nap, u_long nfs_version);
|
||||||
|
extern int create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, struct netconfig **udp_amqncpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp, struct netconfig **tcp_amqncpp, u_short preferred_amq_port);
|
||||||
|
extern int create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp), u_long nfs_version);
|
||||||
|
+extern SVCXPRT *get_nfs_xprt(SVCXPRT *nfs_xprt);
|
||||||
|
+extern void put_nfs_xprt(SVCXPRT *nfs_xprt);
|
||||||
|
extern int amu_svc_register(SVCXPRT *, u_long, u_long, void (*)(struct svc_req *, SVCXPRT *), u_long, struct netconfig *);
|
||||||
|
|
||||||
|
#ifdef HAVE_TRANSPORT_TYPE_TLI
|
52
am-utils-6.2-fix-wcc-attr-usage-in-unlink3_or_rmdir3.patch
Normal file
52
am-utils-6.2-fix-wcc-attr-usage-in-unlink3_or_rmdir3.patch
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
am-utils-6.2 - fix wcc attr usage in unlink3_or_rmdir3()
|
||||||
|
|
||||||
|
From: Ian Kent <raven@themaw.net>
|
||||||
|
|
||||||
|
The definition of the wcc post op attributes should be am_fattr3 not
|
||||||
|
am_wcc_attr in unlink3_or_rmdir3().
|
||||||
|
|
||||||
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||||
|
---
|
||||||
|
amd/nfs_subr.c | 9 +++++----
|
||||||
|
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/amd/nfs_subr.c b/amd/nfs_subr.c
|
||||||
|
index a383618..b88a40c 100644
|
||||||
|
--- a/amd/nfs_subr.c
|
||||||
|
+++ b/amd/nfs_subr.c
|
||||||
|
@@ -1058,7 +1058,8 @@ static am_nfsstat3 unlink3_or_rmdir3(am_diropargs3 *argp,
|
||||||
|
am_pre_op_attr *pre_op_dir = &wcc_data->before;
|
||||||
|
am_post_op_attr *post_op_dir = &wcc_data->after;
|
||||||
|
nfsfattr *fattr;
|
||||||
|
- am_wcc_attr *pre_op_wcc_attr, *post_op_wcc_attr;
|
||||||
|
+ am_wcc_attr *pre_op_wcc_attr;
|
||||||
|
+ am_fattr3 *post_op_wcc_attr;
|
||||||
|
am_node *mp, *ap;
|
||||||
|
int retry;
|
||||||
|
|
||||||
|
@@ -1085,7 +1086,7 @@ static am_nfsstat3 unlink3_or_rmdir3(am_diropargs3 *argp,
|
||||||
|
fattr_to_wcc_attr(fattr, pre_op_wcc_attr);
|
||||||
|
|
||||||
|
if (mp->am_fattr.na_type != NFDIR) {
|
||||||
|
- fattr_to_wcc_attr(fattr, post_op_wcc_attr);
|
||||||
|
+ fattr_to_fattr3(fattr, post_op_wcc_attr);
|
||||||
|
res = nfs_error(ENOTDIR);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
@@ -1105,14 +1106,14 @@ static am_nfsstat3 unlink3_or_rmdir3(am_diropargs3 *argp,
|
||||||
|
*/
|
||||||
|
else if (retry == ENOENT)
|
||||||
|
retry = 0;
|
||||||
|
- fattr_to_wcc_attr(fattr, post_op_wcc_attr);
|
||||||
|
+ fattr_to_fattr3(fattr, post_op_wcc_attr);
|
||||||
|
res = nfs_error(retry);
|
||||||
|
} else {
|
||||||
|
forcibly_timeout_mp(mp);
|
||||||
|
/* we can't wait for the expire so use the attributes as
|
||||||
|
* they are now for the post op wcc attributes.
|
||||||
|
*/
|
||||||
|
- fattr_to_wcc_attr(fattr, post_op_wcc_attr);
|
||||||
|
+ fattr_to_fattr3(fattr, post_op_wcc_attr);
|
||||||
|
res = AM_NFS3_OK;
|
||||||
|
}
|
||||||
|
|
93
am-utils-6.2-use-linux-libtirpc-if-present.patch
Normal file
93
am-utils-6.2-use-linux-libtirpc-if-present.patch
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
am-utils-6.2 - use Linux libtirpc if present
|
||||||
|
|
||||||
|
From: Ian Kent <raven@themaw.net>
|
||||||
|
|
||||||
|
For Linux systems, if the header files and shared libraries of libtirpc
|
||||||
|
are present use them instead of the glibc RPC implementation.
|
||||||
|
|
||||||
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||||
|
---
|
||||||
|
Makefile.am | 3 ++-
|
||||||
|
configure.ac | 4 ++++
|
||||||
|
include/am_compat.h | 8 ++++++--
|
||||||
|
m4/macros/check_linux_libtirpc.m4 | 13 +++++++++++++
|
||||||
|
4 files changed, 25 insertions(+), 3 deletions(-)
|
||||||
|
create mode 100644 m4/macros/check_linux_libtirpc.m4
|
||||||
|
|
||||||
|
diff --git a/Makefile.am b/Makefile.am
|
||||||
|
index bae4615..e094e95 100644
|
||||||
|
--- a/Makefile.am
|
||||||
|
+++ b/Makefile.am
|
||||||
|
@@ -146,7 +146,8 @@ EXTRA_DIST_M4 = \
|
||||||
|
m4/macros/type_xdrproc_t.m4 \
|
||||||
|
m4/macros/type_xfs_args.m4 \
|
||||||
|
m4/macros/type_yp_order_outorder.m4 \
|
||||||
|
- m4/macros/with_addon.m4
|
||||||
|
+ m4/macros/with_addon.m4 \
|
||||||
|
+ m4/macros/check_linux_libtirpc.m4
|
||||||
|
|
||||||
|
EXTRA_DIST_CONF = \
|
||||||
|
conf/autofs/autofs_default.h \
|
||||||
|
diff --git a/configure.ac b/configure.ac
|
||||||
|
index ce61925..98b444d 100644
|
||||||
|
--- a/configure.ac
|
||||||
|
+++ b/configure.ac
|
||||||
|
@@ -222,6 +222,9 @@ dnl lots of code. So I am forced to use a special purpose macro that sets
|
||||||
|
dnl the libraries based on the OS. Sigh. -Erez.
|
||||||
|
AMU_CHECK_OS_LIBS
|
||||||
|
|
||||||
|
+dnl use Linux libtirpc if possible
|
||||||
|
+AMU_CHECK_LIBTIRPC
|
||||||
|
+
|
||||||
|
dnl librpc and librpcsvc are needed on Solaris
|
||||||
|
AC_CHECK_LIB(rpc, clnt_sperrno)
|
||||||
|
AC_CHECK_LIB(rpcsvc, xdr_fhandle)
|
||||||
|
@@ -433,6 +436,7 @@ AC_CHECK_HEADERS( \
|
||||||
|
arpa/nameser.h \
|
||||||
|
arpa/inet.h \
|
||||||
|
bsd/rpc/rpc.h \
|
||||||
|
+ tirpc/netconfig.h \
|
||||||
|
cdfs/cdfsmount.h \
|
||||||
|
cdfs/cdfs_mount.h \
|
||||||
|
fs/udf/udf_mount.h \
|
||||||
|
diff --git a/include/am_compat.h b/include/am_compat.h
|
||||||
|
index 3463f3f..d6826fc 100644
|
||||||
|
--- a/include/am_compat.h
|
||||||
|
+++ b/include/am_compat.h
|
||||||
|
@@ -454,11 +454,15 @@ struct hsfs_args {
|
||||||
|
/*
|
||||||
|
* Define a dummy struct netconfig for non-TLI systems
|
||||||
|
*/
|
||||||
|
-#if !defined(HAVE_NETCONFIG_H) && !defined(HAVE_SYS_NETCONFIG_H)
|
||||||
|
+#if !defined(HAVE_NETCONFIG_H)
|
||||||
|
+# if !defined(HAVE_SYS_NETCONFIG_H)
|
||||||
|
+# if !defined(HAVE_TIRPC_NETCONFIG_H)
|
||||||
|
struct netconfig {
|
||||||
|
int dummy;
|
||||||
|
};
|
||||||
|
-#endif /* not HAVE_NETCONFIG_H and not HAVE_SYS_NETCONFIG_H */
|
||||||
|
+# endif /* not HAVE_TIRPC_NETCONFIG_H */
|
||||||
|
+# endif /* not HAVE_SYS_NETCONFIG_H */
|
||||||
|
+#endif /* not HAVE_NETCONFIG_H */
|
||||||
|
|
||||||
|
/* some OSs don't define INADDR_NONE and assume it's unsigned -1 */
|
||||||
|
#ifndef INADDR_NONE
|
||||||
|
diff --git a/m4/macros/check_linux_libtirpc.m4 b/m4/macros/check_linux_libtirpc.m4
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..918423c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/m4/macros/check_linux_libtirpc.m4
|
||||||
|
@@ -0,0 +1,13 @@
|
||||||
|
+dnl ######################################################################
|
||||||
|
+dnl Check for Linux libtirpc library
|
||||||
|
+AC_DEFUN([AMU_CHECK_LIBTIRPC],[
|
||||||
|
+TIRPC_CPPFLAGS=""
|
||||||
|
+TIRPC_LIBS=""
|
||||||
|
+
|
||||||
|
+AC_CHECK_HEADER(tirpc/netconfig.h,[
|
||||||
|
+ TIRPC_CPPFLAGS="-I/usr/include/tirpc"
|
||||||
|
+ AC_DEFINE(HAVE_LIBTIRPC, 1, [Define to 1 if you have libtirpc headers installed])
|
||||||
|
+ AC_CHECK_LIB(tirpc, clnt_tli_create, [TIRPC_LIBS="-ltirpc"], [TIRPC_CPPFLAGS=""])])
|
||||||
|
+ AMU_CFLAGS="$ANU_CFLAGS $TIRPC_CPPFLAGS"
|
||||||
|
+ LIBS="$LIBS $TIRPC_LIBS"
|
||||||
|
+])
|
@ -0,0 +1,60 @@
|
|||||||
|
am-utils-6.2 - use new get_nfs_xprt() and put_nfs_xprt() functions
|
||||||
|
|
||||||
|
From: Ian Kent <raven@themaw.net>
|
||||||
|
|
||||||
|
The nfs_quick_reply() function needs to know the current RPC transport
|
||||||
|
outside of the NFS LOOKUP method call. It needs this to reply to the
|
||||||
|
NFS LOOKUP call that initiated the mount.
|
||||||
|
|
||||||
|
Now there are functions that avoid transport corruption if another
|
||||||
|
request comes in during the backgroud mount make nfs_quick_reply()
|
||||||
|
use them.
|
||||||
|
|
||||||
|
Signed-off-by: Ian Kent <raven@themaw.net>
|
||||||
|
---
|
||||||
|
amd/amfs_generic.c | 3 +--
|
||||||
|
amd/map.c | 2 +-
|
||||||
|
amd/nfs_subr.c | 3 ++-
|
||||||
|
3 files changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/amd/amfs_generic.c b/amd/amfs_generic.c
|
||||||
|
index c352a32..86d0ab7 100644
|
||||||
|
--- a/amd/amfs_generic.c
|
||||||
|
+++ b/amd/amfs_generic.c
|
||||||
|
@@ -1129,8 +1129,7 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return)
|
||||||
|
*/
|
||||||
|
if (current_transp && !new_mp->am_transp) {
|
||||||
|
dlog("Saving RPC transport for %s", new_mp->am_path);
|
||||||
|
- new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT));
|
||||||
|
- *(new_mp->am_transp) = *current_transp;
|
||||||
|
+ new_mp->am_transp = get_nfs_xprt(current_transp);
|
||||||
|
}
|
||||||
|
if (error && new_mp->am_al && new_mp->am_al->al_mnt &&
|
||||||
|
(new_mp->am_al->al_mnt->mf_ops == &amfs_error_ops))
|
||||||
|
diff --git a/amd/map.c b/amd/map.c
|
||||||
|
index 0d404cf..bcb2156 100644
|
||||||
|
--- a/amd/map.c
|
||||||
|
+++ b/amd/map.c
|
||||||
|
@@ -471,7 +471,7 @@ free_map(am_node *mp)
|
||||||
|
XFREE(mp->am_name);
|
||||||
|
XFREE(mp->am_path);
|
||||||
|
XFREE(mp->am_pref);
|
||||||
|
- XFREE(mp->am_transp);
|
||||||
|
+ put_nfs_xprt(mp->am_transp);
|
||||||
|
|
||||||
|
if (mp->am_al)
|
||||||
|
free_loc(mp->am_al);
|
||||||
|
diff --git a/amd/nfs_subr.c b/amd/nfs_subr.c
|
||||||
|
index 0a43b98..07d960d 100644
|
||||||
|
--- a/amd/nfs_subr.c
|
||||||
|
+++ b/amd/nfs_subr.c
|
||||||
|
@@ -291,7 +291,8 @@ nfs_quick_reply(am_node *mp, int error)
|
||||||
|
/*
|
||||||
|
* Free up transp. It's only used for one reply.
|
||||||
|
*/
|
||||||
|
- XFREE(mp->am_transp);
|
||||||
|
+ put_nfs_xprt(mp->am_transp);
|
||||||
|
+ mp->am_transp = NULL;
|
||||||
|
dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ Summary: Automount utilities including an updated version of Amd
|
|||||||
Name: am-utils
|
Name: am-utils
|
||||||
Version: 6.2.0
|
Version: 6.2.0
|
||||||
%define upstream_version 6.2
|
%define upstream_version 6.2
|
||||||
Release: 11%{?dist}
|
Release: 12%{?dist}
|
||||||
License: BSD
|
License: BSD
|
||||||
Epoch: 5
|
Epoch: 5
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
@ -27,11 +27,13 @@ BuildRequires: systemd-units
|
|||||||
BuildRequires: texinfo
|
BuildRequires: texinfo
|
||||||
BuildRequires: gcc
|
BuildRequires: gcc
|
||||||
BuildRequires: m4
|
BuildRequires: m4
|
||||||
|
BuildRequires: libtirpc-devel
|
||||||
|
|
||||||
Requires: rpcbind
|
Requires: rpcbind
|
||||||
Requires: grep
|
Requires: grep
|
||||||
Requires: gawk
|
Requires: gawk
|
||||||
Requires: findutils
|
Requires: findutils
|
||||||
|
Requires: libtirpc
|
||||||
|
|
||||||
Requires(pre): /bin/grep
|
Requires(pre): /bin/grep
|
||||||
Requires(post): /sbin/install-info
|
Requires(post): /sbin/install-info
|
||||||
@ -51,6 +53,12 @@ Patch5: am-utils-6.2-fix-NFSv3-readdir-post_op_dir-attributes-return.patch
|
|||||||
Patch6: am-utils-6.2-fix-NFSv3-unlink3_or_rmdir3-post_op-attributes-return.patch
|
Patch6: am-utils-6.2-fix-NFSv3-unlink3_or_rmdir3-post_op-attributes-return.patch
|
||||||
|
|
||||||
Patch7: am-utils-6.2-fix-Linux-NFS-recognition-of-umounts.patch
|
Patch7: am-utils-6.2-fix-Linux-NFS-recognition-of-umounts.patch
|
||||||
|
Patch8: am-utils-6.2-add-get_nfs_xprt-and-put_nfs_xprt-functions.patch
|
||||||
|
Patch9: am-utils-6.2-use-new-get_nfs_xprt-and-put_nfs_xprt-functions.patch
|
||||||
|
Patch10: am-utils-6.2-add-NFSv3-nfs_quick_reply-functionality.patch
|
||||||
|
Patch11: am-utils-6.2-add-NFSv3-rpc-request-validation.patch
|
||||||
|
Patch12: am-utils-6.2-fix-wcc-attr-usage-in-unlink3_or_rmdir3.patch
|
||||||
|
Patch13: am-utils-6.2-use-linux-libtirpc-if-present.patch
|
||||||
|
|
||||||
# Not needed since autoreconf/libtool appear to do this automatically
|
# Not needed since autoreconf/libtool appear to do this automatically
|
||||||
# Leaving it set doesn't appear to be a problem so leave it set in
|
# Leaving it set doesn't appear to be a problem so leave it set in
|
||||||
@ -82,6 +90,12 @@ mounting and unmounting filesystems.
|
|||||||
%patch5 -p1
|
%patch5 -p1
|
||||||
%patch6 -p1
|
%patch6 -p1
|
||||||
%patch7 -p1
|
%patch7 -p1
|
||||||
|
%patch8 -p1
|
||||||
|
%patch9 -p1
|
||||||
|
%patch10 -p1
|
||||||
|
%patch11 -p1
|
||||||
|
%patch12 -p1
|
||||||
|
%patch13 -p1
|
||||||
|
|
||||||
./bootstrap
|
./bootstrap
|
||||||
|
|
||||||
@ -193,6 +207,15 @@ fi
|
|||||||
%{_libdir}/libamu.so*
|
%{_libdir}/libamu.so*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Mar 2 2016 Ian Kent <ikent@redhat.com> - 5:6.2.0-12
|
||||||
|
- add get_nfs_xprt() and put_nfs_xprt() functions.
|
||||||
|
- use new get_nfs_xprt() and put_nfs_xprt() functions.
|
||||||
|
- add NFSv3 nfs_quick_reply() functionality.
|
||||||
|
- use libtirpc instead of glibc RPC.
|
||||||
|
- add NFSv3 rpc request validation.
|
||||||
|
- fix wcc attr usage in unlink3_or_rmdir3().
|
||||||
|
- use Linux libtirpc if present.
|
||||||
|
|
||||||
* Mon Feb 29 2016 Ian Kent <ikent@redhat.com> - 5:6.2.0-11
|
* Mon Feb 29 2016 Ian Kent <ikent@redhat.com> - 5:6.2.0-11
|
||||||
- fix Linux NFS recognition of umounts.
|
- fix Linux NFS recognition of umounts.
|
||||||
- add systemd dependency on nfs-lock.service.
|
- add systemd dependency on nfs-lock.service.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user