From e67de63ba6c6de60400e7deb4664d259f6dfb638 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 13 Jul 2009 18:43:10 -0700 Subject: Make cli_posix_lock/unlock asynchronous. Jeremy. --- source3/client/client.c | 4 +- source3/include/proto.h | 21 +++- source3/libsmb/clifile.c | 273 ++++++++++++++++++++++++++++++++++++---------- source3/torture/torture.c | 12 ++ 4 files changed, 247 insertions(+), 63 deletions(-) (limited to 'source3') diff --git a/source3/client/client.c b/source3/client/client.c index ed45f4e2ca..6b273b47b0 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -2605,7 +2605,7 @@ static int cmd_lock(void) len = (uint64_t)strtol(buf, (char **)NULL, 16); - if (!cli_posix_lock(cli, fnum, start, len, true, lock_type)) { + if (!NT_STATUS_IS_OK(cli_posix_lock(cli, fnum, start, len, true, lock_type))) { d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli)); } @@ -2639,7 +2639,7 @@ static int cmd_unlock(void) len = (uint64_t)strtol(buf, (char **)NULL, 16); - if (!cli_posix_unlock(cli, fnum, start, len)) { + if (!NT_STATUS_IS_OK(cli_posix_unlock(cli, fnum, start, len))) { d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli)); } diff --git a/source3/include/proto.h b/source3/include/proto.h index c0ce35a865..7b3eaa0659 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2516,11 +2516,26 @@ bool cli_unlock(struct cli_state *cli, uint16_t fnum, uint32_t offset, uint32_t bool cli_lock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type); bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len); -bool cli_posix_lock(struct cli_state *cli, uint16_t fnum, +struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint64_t offset, + uint64_t len, + bool wait_lock, + enum brl_type lock_type); +NTSTATUS cli_posix_lock_recv(struct tevent_req *req); +NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type); -bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len); -bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen); +struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint64_t offset, + uint64_t len); +NTSTATUS cli_posix_unlock_recv(struct tevent_req *req); +NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len); struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index af67fcb746..0e2b3640f2 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2857,103 +2857,260 @@ bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_ Get/unlock a POSIX lock on a file - internal function. ****************************************************************************/ -static bool cli_posix_lock_internal(struct cli_state *cli, uint16_t fnum, - uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type) +struct posix_lock_state { + uint16_t setup; + uint8_t param[4]; + uint8_t data[POSIX_LOCK_DATA_SIZE]; +}; + +static void cli_posix_unlock_internal_done(struct tevent_req *subreq) { - unsigned int param_len = 4; - unsigned int data_len = POSIX_LOCK_DATA_SIZE; - uint16_t setup = TRANSACT2_SETFILEINFO; - char param[4]; - unsigned char data[POSIX_LOCK_DATA_SIZE]; - char *rparam=NULL, *rdata=NULL; - int saved_timeout = cli->timeout; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct posix_lock_state *state = tevent_req_data(req, struct posix_lock_state); + NTSTATUS status; - SSVAL(param,0,fnum); - SSVAL(param,2,SMB_SET_POSIX_LOCK); + status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint64_t offset, + uint64_t len, + bool wait_lock, + enum brl_type lock_type) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct posix_lock_state *state = NULL; + req = tevent_req_create(mem_ctx, &state, struct posix_lock_state); + if (req == NULL) { + return NULL; + } + + /* Setup setup word. */ + SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO); + + /* Setup param array. */ + SSVAL(&state->param, 0, fnum); + SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK); + + /* Setup data array. */ switch (lock_type) { case READ_LOCK: - SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ); + SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET, + POSIX_LOCK_TYPE_READ); break; case WRITE_LOCK: - SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE); + SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET, + POSIX_LOCK_TYPE_WRITE); break; case UNLOCK_LOCK: - SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK); + SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET, + POSIX_LOCK_TYPE_UNLOCK); break; default: - return False; + return NULL; } if (wait_lock) { - SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT); - cli->timeout = 0x7FFFFFFF; + SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET, + POSIX_LOCK_FLAG_WAIT); } else { - SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT); - } - - SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid); - SOFF_T(data, POSIX_LOCK_START_OFFSET, offset); - SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len); - - if (!cli_send_trans(cli, SMBtrans2, - NULL, /* name */ - -1, 0, /* fid, flags */ - &setup, 1, 0, /* setup, length, max */ - param, param_len, 2, /* param, length, max */ - (char *)&data, data_len, cli->max_xmit /* data, length, max */ - )) { - cli->timeout = saved_timeout; - return False; - } + SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET, + POSIX_LOCK_FLAG_NOWAIT); + } + + SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid); + SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset); + SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len); + + subreq = cli_trans_send(state, /* mem ctx. */ + ev, /* event ctx. */ + cli, /* cli_state. */ + SMBtrans2, /* cmd. */ + NULL, /* pipe name. */ + -1, /* fid. */ + 0, /* function. */ + 0, /* flags. */ + &state->setup, /* setup. */ + 1, /* num setup uint16_t words. */ + 0, /* max returned setup. */ + state->param, /* param. */ + 4, /* num param. */ + 2, /* max returned param. */ + state->data, /* data. */ + POSIX_LOCK_DATA_SIZE, /* num data. */ + 0); /* max returned data. */ - if (!cli_receive_trans(cli, SMBtrans2, - &rparam, ¶m_len, - &rdata, &data_len)) { - cli->timeout = saved_timeout; - SAFE_FREE(rdata); - SAFE_FREE(rparam); - return False; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - - cli->timeout = saved_timeout; - - SAFE_FREE(rdata); - SAFE_FREE(rparam); - - return True; + tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req); + return req; } /**************************************************************************** POSIX Lock a file. ****************************************************************************/ -bool cli_posix_lock(struct cli_state *cli, uint16_t fnum, +struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint64_t offset, + uint64_t len, + bool wait_lock, + enum brl_type lock_type) +{ + return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len, + wait_lock, lock_type); +} + +NTSTATUS cli_posix_lock_recv(struct tevent_req *req) +{ + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + return NT_STATUS_OK; +} + +NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type) { + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + NTSTATUS status = NT_STATUS_OK; + + if (cli_has_async_calls(cli)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) { - return False; + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_posix_lock_send(frame, + ev, + cli, + fnum, + offset, + len, + wait_lock, + lock_type); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; } - return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type); + + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = cli_posix_lock_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** POSIX Unlock a file. ****************************************************************************/ -bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len) +struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint64_t offset, + uint64_t len) { - return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK); + return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len, + false, UNLOCK_LOCK); } -/**************************************************************************** - POSIX Get any lock covering a file. -****************************************************************************/ +NTSTATUS cli_posix_unlock_recv(struct tevent_req *req) +{ + NTSTATUS status; -bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen) + if (tevent_req_is_nterror(req, &status)) { + return status; + } + return NT_STATUS_OK; +} + +NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len) { - return True; + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev = NULL; + struct tevent_req *req = NULL; + NTSTATUS status = NT_STATUS_OK; + + if (cli_has_async_calls(cli)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_posix_unlock_send(frame, + ev, + cli, + fnum, + offset, + len); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = cli_posix_unlock_recv(req); + + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } /**************************************************************************** diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 8e38093e33..8cebc2adcc 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -4295,6 +4295,18 @@ static bool run_simple_posix_open_test(int dummy) goto out; } + /* Do a POSIX lock/unlock. */ + if (!NT_STATUS_IS_OK(cli_posix_lock(cli1, fnum1, 0, 100, true, WRITE_LOCK))) { + printf("POSIX lock failed\n"); + goto out; + } + + /* Punch a hole in the locked area. */ + if (!NT_STATUS_IS_OK(cli_posix_unlock(cli1, fnum1, 10, 80))) { + printf("POSIX unlock failed\n"); + goto out; + } + cli_close(cli1, fnum1); /* Open the symlink for read - this should fail. A POSIX -- cgit