Add async support for reply_tcon* and ntvfs_connect
authorSam Liddicott <sam@liddicott.com>
Thu, 23 Apr 2009 12:47:59 +0000 (13:47 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 23 Apr 2009 14:57:18 +0000 (16:57 +0200)
smbsrv_tcon_backend no longer creates the ntvfs_request wrapper,
so smbsrv_reply_tcon* can now do this and then invoke ntvfs_connect
in the typical manner using SMBSRV_SETUP_NTVFS_REQUEST and
SMBSRV_CALL_NTVFS_BACKEND

Previously smbsrv_tcon_backend has been responsible for instantiating
the ntvfs_module_context to service a tree-connect request, and
then create an ntvfs_request wrapper around the smbsrv_request
and pass this to ntvfs_connect for the newly created ntvfs.

These actions could not be invoked asynchronously.

This meant that any client requests made while instantiating the
ntvfs module, including any composite's used during authentication
(or related client connections for the case of proxy modules)
would block other ntvfs modules and requests in the current process as
they executed a nested event loop to await completion.

Signed-off-by: Sam Liddicott <sam@liddicott.com>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
source4/smb_server/smb/reply.c
source4/smb_server/smb/service.c

index 9c4ee993d20129d445ccec18ab45cd9b4d34e8c2..1b309a0c1feb732d08eb399f89ccc6dce10852c0 100644 (file)
@@ -43,115 +43,169 @@ static void reply_simple_send(struct ntvfs_request *ntvfs)
 }
 
 
+/****************************************************************************
+ Reply to a tcon (async reply)
+****************************************************************************/
+static void reply_tcon_send(struct ntvfs_request *ntvfs)
+{
+       struct smbsrv_request *req;
+       union smb_tcon *con;
+
+       SMBSRV_CHECK_ASYNC_STATUS(con, union smb_tcon);
+
+       if (con->generic.level == RAW_TCON_TCON) {
+               con->tcon.out.max_xmit = req->smb_conn->negotiate.max_recv;
+               con->tcon.out.tid = req->tcon->tid;
+       } else {
+               /* TODO: take a look at tconx.in.flags! */
+               con->tconx.out.tid = req->tcon->tid;
+               con->tconx.out.dev_type = talloc_strdup(req, req->tcon->ntvfs->dev_type);
+               con->tconx.out.fs_type = talloc_strdup(req, req->tcon->ntvfs->fs_type);
+       }
+
+       /* construct reply */
+       smbsrv_setup_reply(req, 2, 0);
+
+       SSVAL(req->out.vwv, VWV(0), con->tcon.out.max_xmit);
+       SSVAL(req->out.vwv, VWV(1), con->tcon.out.tid);
+       SSVAL(req->out.hdr, HDR_TID, req->tcon->tid);
+
+       smbsrv_send_reply(req);
+}
+
 /****************************************************************************
  Reply to a tcon.
 ****************************************************************************/
 void smbsrv_reply_tcon(struct smbsrv_request *req)
 {
-       union smb_tcon con;
+       union smb_tcon *con;
        NTSTATUS status;
        uint8_t *p;
        
        /* parse request */
        SMBSRV_CHECK_WCT(req, 0);
 
-       con.tcon.level = RAW_TCON_TCON;
+       SMBSRV_TALLOC_IO_PTR(con, union smb_tcon);
+
+       con->tcon.level = RAW_TCON_TCON;
 
        p = req->in.data;       
-       p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.service, p, STR_TERMINATE);
-       p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.password, p, STR_TERMINATE);
-       p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.dev, p, STR_TERMINATE);
+       p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.service, p, STR_TERMINATE);
+       p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.password, p, STR_TERMINATE);
+       p += req_pull_ascii4(&req->in.bufinfo, &con->tcon.in.dev, p, STR_TERMINATE);
 
-       if (!con.tcon.in.service || !con.tcon.in.password || !con.tcon.in.dev) {
+       if (!con->tcon.in.service || !con->tcon.in.password || !con->tcon.in.dev) {
                smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
                return;
        }
 
-       /* call backend */
-       status = smbsrv_tcon_backend(req, &con);
-
+       /* Instantiate backend */
+       status = smbsrv_tcon_backend(req, con);
        if (!NT_STATUS_IS_OK(status)) {
                smbsrv_send_error(req, status);
                return;
        }
 
-       /* construct reply */
-       smbsrv_setup_reply(req, 2, 0);
+       SMBSRV_SETUP_NTVFS_REQUEST(reply_tcon_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
 
-       SSVAL(req->out.vwv, VWV(0), con.tcon.out.max_xmit);
-       SSVAL(req->out.vwv, VWV(1), con.tcon.out.tid);
-       SSVAL(req->out.hdr, HDR_TID, req->tcon->tid);
-  
-       smbsrv_send_reply(req);
+       /* Invoke NTVFS connection hook */
+       SMBSRV_CALL_NTVFS_BACKEND(ntvfs_connect(req->ntvfs, req->tcon->share_name));
 }
 
 
+/****************************************************************************
+ Reply to a tcon and X (async reply)
+****************************************************************************/
+static void reply_tcon_and_X_send(struct ntvfs_request *ntvfs)
+{
+       struct smbsrv_request *req;
+       union smb_tcon *con;
+
+       SMBSRV_CHECK_ASYNC_STATUS(con, union smb_tcon);
+
+       if (con->generic.level == RAW_TCON_TCON) {
+               con->tcon.out.max_xmit = req->smb_conn->negotiate.max_recv;
+               con->tcon.out.tid = req->tcon->tid;
+       } else {
+               /* TODO: take a look at tconx.in.flags! */
+               con->tconx.out.tid = req->tcon->tid;
+               con->tconx.out.dev_type = talloc_strdup(req, req->tcon->ntvfs->dev_type);
+               con->tconx.out.fs_type = talloc_strdup(req, req->tcon->ntvfs->fs_type);
+       }
+
+       /* construct reply - two variants */
+       if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
+               smbsrv_setup_reply(req, 2, 0);
+
+               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+               SSVAL(req->out.vwv, VWV(1), 0);
+
+               req_push_str(req, NULL, con->tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
+       } else {
+               smbsrv_setup_reply(req, 3, 0);
+
+               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+               SSVAL(req->out.vwv, VWV(1), 0);
+               SSVAL(req->out.vwv, VWV(2), con->tconx.out.options);
+
+               req_push_str(req, NULL, con->tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
+               req_push_str(req, NULL, con->tconx.out.fs_type, -1, STR_TERMINATE);
+       }
+
+       /* set the incoming and outgoing tid to the just created one */
+       SSVAL(req->in.hdr, HDR_TID, con->tconx.out.tid);
+       SSVAL(req->out.hdr,HDR_TID, con->tconx.out.tid);
+
+       smbsrv_chain_reply(req);
+}
+
 /****************************************************************************
  Reply to a tcon and X.
 ****************************************************************************/
 void smbsrv_reply_tcon_and_X(struct smbsrv_request *req)
 {
        NTSTATUS status;
-       union smb_tcon con;
+       union smb_tcon *con;
        uint8_t *p;
        uint16_t passlen;
 
-       con.tconx.level = RAW_TCON_TCONX;
+       SMBSRV_TALLOC_IO_PTR(con, union smb_tcon);
+
+       con->tconx.level = RAW_TCON_TCONX;
 
        /* parse request */
        SMBSRV_CHECK_WCT(req, 4);
 
-       con.tconx.in.flags  = SVAL(req->in.vwv, VWV(2));
-       passlen             = SVAL(req->in.vwv, VWV(3));
+       con->tconx.in.flags  = SVAL(req->in.vwv, VWV(2));
+       passlen              = SVAL(req->in.vwv, VWV(3));
 
        p = req->in.data;
 
-       if (!req_pull_blob(&req->in.bufinfo, p, passlen, &con.tconx.in.password)) {
+       if (!req_pull_blob(&req->in.bufinfo, p, passlen, &con->tconx.in.password)) {
                smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD);
                return;
        }
        p += passlen;
 
-       p += req_pull_string(&req->in.bufinfo, &con.tconx.in.path, p, -1, STR_TERMINATE);
-       p += req_pull_string(&req->in.bufinfo, &con.tconx.in.device, p, -1, STR_ASCII);
+       p += req_pull_string(&req->in.bufinfo, &con->tconx.in.path, p, -1, STR_TERMINATE);
+       p += req_pull_string(&req->in.bufinfo, &con->tconx.in.device, p, -1, STR_ASCII);
 
-       if (!con.tconx.in.path || !con.tconx.in.device) {
+       if (!con->tconx.in.path || !con->tconx.in.device) {
                smbsrv_send_error(req, NT_STATUS_BAD_DEVICE_TYPE);
                return;
        }
 
-       /* call backend */
-       status = smbsrv_tcon_backend(req, &con);
-
+       /* Instantiate backend */
+       status = smbsrv_tcon_backend(req, con);
        if (!NT_STATUS_IS_OK(status)) {
                smbsrv_send_error(req, status);
                return;
        }
 
-       /* construct reply - two variants */
-       if (req->smb_conn->negotiate.protocol < PROTOCOL_NT1) {
-               smbsrv_setup_reply(req, 2, 0);
-
-               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
-               SSVAL(req->out.vwv, VWV(1), 0);
-
-               req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
-       } else {
-               smbsrv_setup_reply(req, 3, 0);
-
-               SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
-               SSVAL(req->out.vwv, VWV(1), 0);
-               SSVAL(req->out.vwv, VWV(2), con.tconx.out.options);
-
-               req_push_str(req, NULL, con.tconx.out.dev_type, -1, STR_TERMINATE|STR_ASCII);
-               req_push_str(req, NULL, con.tconx.out.fs_type, -1, STR_TERMINATE);
-       }
-
-       /* set the incoming and outgoing tid to the just created one */
-       SSVAL(req->in.hdr, HDR_TID, con.tconx.out.tid);
-       SSVAL(req->out.hdr,HDR_TID, con.tconx.out.tid);
+       SMBSRV_SETUP_NTVFS_REQUEST(reply_tcon_and_X_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
 
-       smbsrv_chain_reply(req);
+       /* Invoke NTVFS connection hook */
+       SMBSRV_CALL_NTVFS_BACKEND(ntvfs_connect(req->ntvfs, req->tcon->share_name));
 }
 
 
index 52471c09c99623ab0c69574a1bf856a18e449c1b..85d169fc1386b347a3fda596eba5b2447cfc9fe0 100644 (file)
@@ -27,6 +27,7 @@
 /****************************************************************************
   Make a connection, given the snum to connect to, and the vuser of the
   connecting user if appropriate.
+  Does note invoke the NTVFS connection hook
 ****************************************************************************/
 static NTSTATUS make_connection_scfg(struct smbsrv_request *req,
                                     struct share_config *scfg,
@@ -88,23 +89,6 @@ static NTSTATUS make_connection_scfg(struct smbsrv_request *req,
                goto failed;
        }
 
-       req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,
-                                         req->session->session_info,
-                                         SVAL(req->in.hdr,HDR_PID),
-                                         req->request_time,
-                                         req, NULL, 0);
-       if (!req->ntvfs) {
-               status = NT_STATUS_NO_MEMORY;
-               goto failed;
-       }
-
-       /* Invoke NTVFS connection hook */
-       status = ntvfs_connect(req->ntvfs, scfg->name);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("make_connection: NTVFS make connection failed!\n"));
-               goto failed;
-       }
-
        return NT_STATUS_OK;
 
 failed:
@@ -204,9 +188,6 @@ NTSTATUS smbsrv_tcon_backend(struct smbsrv_request *req, union smb_tcon *con)
                return status;
        }
 
-       con->tconx.out.tid = req->tcon->tid;
-       con->tconx.out.dev_type = talloc_strdup(req, req->tcon->ntvfs->dev_type);
-       con->tconx.out.fs_type = talloc_strdup(req, req->tcon->ntvfs->fs_type);
        con->tconx.out.options = SMB_SUPPORT_SEARCH_BITS | (share_int_option(req->tcon->ntvfs->config, SHARE_CSC_POLICY, SHARE_CSC_POLICY_DEFAULT) << 2);
        if (share_bool_option(req->tcon->ntvfs->config, SHARE_MSDFS_ROOT, SHARE_MSDFS_ROOT_DEFAULT) && lp_host_msdfs(req->smb_conn->lp_ctx)) {
                con->tconx.out.options |= SMB_SHARE_IN_DFS;