nfsd4: check for negative dentry before use in nfsv4 readdir
[safe/jmp/linux-2.6] / fs / nfsd / nfs4callback.c
index 3ddc9fb..290289b 100644 (file)
@@ -361,9 +361,8 @@ static struct rpc_program cb_program = {
 /* Reference counting, callback cleanup, etc., all look racy as heck.
  * And why is cb_set an atomic? */
 
-static int do_probe_callback(void *data)
+static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp)
 {
-       struct nfs4_client *clp = data;
        struct sockaddr_in      addr;
        struct nfs4_callback    *cb = &clp->cl_callback;
        struct rpc_timeout      timeparms = {
@@ -384,17 +383,10 @@ static int do_probe_callback(void *data)
                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
                .client_name    = clp->cl_principal,
        };
-       struct rpc_message msg = {
-               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
-               .rpc_argp       = clp,
-       };
        struct rpc_clnt *client;
-       int status;
 
-       if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) {
-               status = nfserr_cb_path_down;
-               goto out_err;
-       }
+       if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
+               return ERR_PTR(-EINVAL);
 
        /* Initialize address */
        memset(&addr, 0, sizeof(addr));
@@ -404,9 +396,29 @@ static int do_probe_callback(void *data)
 
        /* Create RPC client */
        client = rpc_create(&args);
+       if (IS_ERR(client))
+               dprintk("NFSD: couldn't create callback client: %ld\n",
+                       PTR_ERR(client));
+       return client;
+
+}
+
+static int do_probe_callback(void *data)
+{
+       struct nfs4_client *clp = data;
+       struct nfs4_callback    *cb = &clp->cl_callback;
+       struct rpc_message msg = {
+               .rpc_proc       = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
+               .rpc_argp       = clp,
+       };
+       struct rpc_clnt *client;
+       int status;
+
+       client = setup_callback_client(clp);
        if (IS_ERR(client)) {
-               dprintk("NFSD: couldn't create callback client\n");
                status = PTR_ERR(client);
+               dprintk("NFSD: couldn't create callback client: %d\n",
+                                                               status);
                goto out_err;
        }
 
@@ -422,10 +434,10 @@ static int do_probe_callback(void *data)
 out_release_client:
        rpc_shutdown_client(client);
 out_err:
-       dprintk("NFSD: warning: no callback path to client %.*s\n",
-               (int)clp->cl_name.len, clp->cl_name.data);
+       dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
+               (int)clp->cl_name.len, clp->cl_name.data, status);
        put_nfs4_client(clp);
-       return status;
+       return 0;
 }
 
 /*
@@ -490,9 +502,7 @@ out_put_cred:
         * Success or failure, now we're either waiting for lease expiration
         * or deleg_return.
         */
-       nfs4_lock_state();
        put_nfs4_client(clp);
        nfs4_put_delegation(dp);
-       nfs4_unlock_state();
        return;
 }