@@ -757,42 +757,73 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
}
}
+static void gss_pipe_dentry_destroy(struct rpc_pipe *pipe)
+{
+ if (pipe->dentry != NULL) {
+ rpc_unlink(pipe->dentry);
+ pipe->dentry = NULL;
+ }
+}
+
+/*
+ * Release existing pipe dentries, but leave the rpc_pipe data
+ * ready to receive fresh dentries if subsequently needed.
+ */
static void gss_pipes_dentries_destroy(struct rpc_auth *auth)
{
struct gss_auth *gss_auth;
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
- if (gss_auth->pipe[0]->dentry)
- rpc_unlink(gss_auth->pipe[0]->dentry);
- if (gss_auth->pipe[1]->dentry)
- rpc_unlink(gss_auth->pipe[1]->dentry);
+
+ dprintk("RPC: %s auth=%p, clnt=%p\n",
+ __func__, auth, gss_auth->client);
+
+ gss_pipe_dentry_destroy(gss_auth->pipe[0]);
+ gss_pipe_dentry_destroy(gss_auth->pipe[1]);
}
+/*
+ * On success, zero is returned and both elements of the rpc_pipe
+ * array are populated with valid dentries. Otherwise an error value
+ * is returned, the dentries are freed, and both ->dentry pointers are
+ * set to NULL.
+ */
static int gss_pipes_dentries_create(struct rpc_auth *auth)
{
- int err;
+ int err = 0;
struct gss_auth *gss_auth;
struct rpc_clnt *clnt;
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
clnt = gss_auth->client;
- gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
- "gssd",
- clnt, gss_auth->pipe[1]);
- if (IS_ERR(gss_auth->pipe[1]->dentry))
- return PTR_ERR(gss_auth->pipe[1]->dentry);
- gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
- gss_auth->mech->gm_name,
- clnt, gss_auth->pipe[0]);
- if (IS_ERR(gss_auth->pipe[0]->dentry)) {
- err = PTR_ERR(gss_auth->pipe[0]->dentry);
- goto err_unlink_pipe_1;
+ if (gss_auth->pipe[1]->dentry == NULL) {
+ gss_auth->pipe[1]->dentry =
+ rpc_mkpipe_dentry(clnt->cl_dentry, "gssd", clnt,
+ gss_auth->pipe[1]);
+ if (IS_ERR(gss_auth->pipe[1]->dentry)) {
+ err = PTR_ERR(gss_auth->pipe[1]->dentry);
+ gss_auth->pipe[1]->dentry = NULL;
+ goto out_err;
+ }
}
+
+ if (gss_auth->pipe[0]->dentry == NULL) {
+ gss_auth->pipe[0]->dentry =
+ rpc_mkpipe_dentry(clnt->cl_dentry,
+ gss_auth->mech->gm_name,
+ clnt, gss_auth->pipe[0]);
+ if (IS_ERR(gss_auth->pipe[0]->dentry)) {
+ err = PTR_ERR(gss_auth->pipe[0]->dentry);
+ gss_auth->pipe[0]->dentry = NULL;
+ goto out_err;
+ }
+ }
+
return 0;
-err_unlink_pipe_1:
- rpc_unlink(gss_auth->pipe[1]->dentry);
+out_err:
+ gss_pipes_dentries_destroy(auth);
return err;
}
We are about to make pipe data shareable. gss_pipes_dentries_create() and gss_pipes_dentries_destroy() have to be more careful when dealing with their dentry pointers. Namely: 1. When asked to create a dentry, don't write over possibly valid pointers, but instead preserve an existing dentry 2. When unlinking a dentry, make sure the ->dentry pointer is NULL 3. If creating a dentry fails, don't leak the ERR_PTR value, make sure the ->dentry pointer is NULL 2. and 3. are needed so that 1. can recognize when a new dentry should be created. This is clean up, mostly. But it's necessary because unmounting a pipe FS can cause pipe dentries, but not the pipe data, to be released (via ->pipes_destroy). The functions that manage pipe data for gss_create() have to be prepared for finding an existing shared rpc_pipe_data object that has a dentry, or doesn't, and then do the correct thing in either case. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Cc: Stanislav Kinsbursky <skinsbursky@parallels.com> --- net/sunrpc/auth_gss/auth_gss.c | 67 +++++++++++++++++++++++++++++----------- 1 files changed, 49 insertions(+), 18 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html