1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

r3507: - added deferred replies on sharing violation in pvfs open. The

deferred reply is short-circuited immediately when the file is
  closed by another user, allowing it to be opened by the waiting user.

- added a sane set of timeval manipulation routines

- converted all the events code and code that uses it to use struct
  timeval instead of time_t, which allows for microsecond resolution
  instead of 1 second resolution. This was needed for doing the pvfs
  deferred open code, and is why the patch is so big.
(This used to be commit 0d51511d408d91eb5f68a35e980e0875299b1831)
This commit is contained in:
Andrew Tridgell 2004-11-03 10:09:48 +00:00 committed by Gerald (Jerry) Carter
parent 90a8c4acc7
commit dde0705807
36 changed files with 726 additions and 222 deletions

@ -28,7 +28,8 @@ struct event_context {
struct fd_event *next, *prev;
int fd;
uint16_t flags; /* see EVENT_FD_* flags */
void (*handler)(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags);
void (*handler)(struct event_context *ev, struct fd_event *fde,
struct timeval t, uint16_t flags);
void *private;
int ref_count;
} *fd_events;
@ -36,8 +37,9 @@ struct event_context {
/* list of timed events */
struct timed_event {
struct timed_event *next, *prev;
time_t next_event;
void (*handler)(struct event_context *ev, struct timed_event *te, time_t t);
struct timeval next_event;
void (*handler)(struct event_context *ev, struct timed_event *te,
struct timeval t);
void *private;
int ref_count;
} *timed_events;
@ -45,7 +47,8 @@ struct event_context {
/* list of loop events - called on each select() */
struct loop_event {
struct loop_event *next, *prev;
void (*handler)(struct event_context *ev, struct loop_event *le, time_t t);
void (*handler)(struct event_context *ev, struct loop_event *le,
struct timeval t);
void *private;
int ref_count;
} *loop_events;

@ -29,5 +29,6 @@ struct messaging_context;
#define MSG_PING 2
#define MSG_PONG 3
#define MSG_BRL_RETRY 4
#define MSG_PVFS_RETRY_OPEN 5
#endif

@ -440,7 +440,7 @@ NTSTATUS ldapsrv_flush_responses(struct ldapsrv_connection *conn)
/*
called when a LDAP socket becomes readable
*/
static void ldapsrv_recv(struct server_connection *conn, time_t t,
static void ldapsrv_recv(struct server_connection *conn, struct timeval t,
uint16_t flags)
{
struct ldapsrv_connection *ldap_conn = conn->private_data;
@ -536,7 +536,7 @@ static void ldapsrv_recv(struct server_connection *conn, time_t t,
/*
called when a LDAP socket becomes writable
*/
static void ldapsrv_send(struct server_connection *conn, time_t t,
static void ldapsrv_send(struct server_connection *conn, struct timeval t,
uint16_t flags)
{
struct ldapsrv_connection *ldap_conn = conn->private_data;
@ -558,7 +558,7 @@ static void ldapsrv_send(struct server_connection *conn, time_t t,
/*
called when connection is idle
*/
static void ldapsrv_idle(struct server_connection *conn, time_t t)
static void ldapsrv_idle(struct server_connection *conn, struct timeval t)
{
DEBUG(10,("ldapsrv_idle: not implemented!\n"));
return;

@ -72,7 +72,8 @@ ADD_OBJ_FILES = \
lib/events.o \
lib/db_wrap.o \
lib/server_mutex.o \
lib/idtree.o
lib/idtree.o \
lib/unix_privs.o
REQUIRED_SUBSYSTEMS = \
LIBTDB CHARSET LIBREPLACE LIBNETIF LIBCRYPTO
# End SUBSYSTEM LIBBASIC

@ -285,15 +285,14 @@ void event_loop_exit(struct event_context *ev, int code)
*/
int event_loop_once(struct event_context *ev)
{
time_t t;
fd_set r_fds, w_fds;
struct fd_event *fe;
struct loop_event *le;
struct timed_event *te;
int selrtn;
struct timeval tval;
struct timeval tval, t;
t = time(NULL);
t = timeval_current();
/* the loop events are called on each loop. Be careful to allow the
event to remove itself */
@ -310,7 +309,6 @@ int event_loop_once(struct event_context *ev)
le = next;
}
ZERO_STRUCT(tval);
FD_ZERO(&r_fds);
FD_ZERO(&w_fds);
@ -336,17 +334,12 @@ int event_loop_once(struct event_context *ev)
/* start with a reasonable max timeout */
tval.tv_sec = 600;
tval.tv_usec = 0;
/* work out the right timeout for all timed events */
for (te=ev->timed_events;te;te=te->next) {
int timeout = te->next_event - t;
if (timeout < 0) {
timeout = 0;
}
if (te->ref_count &&
timeout < tval.tv_sec) {
tval.tv_sec = timeout;
}
struct timeval tv = timeval_diff(&te->next_event, &t);
tval = timeval_min(&tv, &tval);
}
/* only do a select() if there're fd_events
@ -368,7 +361,7 @@ int event_loop_once(struct event_context *ev)
*/
selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval);
t = time(NULL);
t = timeval_current();
if (selrtn == -1 && errno == EBADF) {
/* the socket is dead! this should never
@ -404,11 +397,11 @@ int event_loop_once(struct event_context *ev)
if (te->ref_count == 0) {
DLIST_REMOVE(ev->timed_events, te);
talloc_free(te);
} else if (te->next_event <= t) {
} else if (timeval_compare(&te->next_event, &t) >= 0) {
te->ref_count++;
te->handler(ev, te, t);
te->ref_count--;
if (te->next_event <= t) {
if (timeval_compare(&te->next_event, &t) >= 0) {
/* the handler didn't set a time for the
next event - remove the event */
event_remove_timed(ev, te);

@ -29,6 +29,9 @@
/* change the message version with any incompatible changes in the protocol */
#define MESSAGING_VERSION 1
/* the number of microseconds to backoff in retrying to send a message */
#define MESSAGING_BACKOFF 250000
struct messaging_context {
servid_t server_id;
struct socket_context *sock;
@ -119,7 +122,7 @@ static void messaging_dispatch(struct messaging_context *msg, struct messaging_r
handle IO for a single message
*/
static void messaging_recv_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16_t flags)
struct timeval t, uint16_t flags)
{
struct messaging_rec *rec = fde->private;
struct messaging_context *msg = rec->msg;
@ -200,7 +203,7 @@ static int rec_destructor(void *ptr)
handle a new incoming connection
*/
static void messaging_listen_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16_t flags)
struct timeval t, uint16_t flags)
{
struct messaging_context *msg = fde->private;
struct messaging_rec *rec;
@ -272,7 +275,7 @@ void messaging_deregister(struct messaging_context *msg, uint32_t msg_type, void
handle IO for sending a message
*/
static void messaging_send_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16_t flags)
struct timeval t, uint16_t flags)
{
struct messaging_rec *rec = fde->private;
NTSTATUS status;
@ -323,20 +326,34 @@ static void messaging_send_handler(struct event_context *ev, struct fd_event *fd
}
/*
wrapper around socket_connect with raised privileges
*/
static NTSTATUS try_connect(struct messaging_rec *rec)
{
NTSTATUS status;
void *priv = root_privileges();
status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0);
talloc_free(priv);
return status;
}
/*
when the servers listen queue is full we use this to backoff the message
*/
static void messaging_backoff_handler(struct event_context *ev, struct timed_event *te, time_t t)
static void messaging_backoff_handler(struct event_context *ev, struct timed_event *te,
struct timeval t)
{
struct messaging_rec *rec = te->private;
struct messaging_context *msg = rec->msg;
NTSTATUS status;
struct fd_event fde;
status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0);
status = try_connect(rec);
if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
/* backoff again */
te->next_event = t+1;
te->next_event = timeval_add(&t, 0, MESSAGING_BACKOFF);
return;
}
@ -356,7 +373,7 @@ static void messaging_backoff_handler(struct event_context *ev, struct timed_eve
talloc_set_destructor(rec, rec_destructor);
messaging_send_handler(msg->event.ev, rec->fde, 0, EVENT_FD_WRITE);
messaging_send_handler(msg->event.ev, rec->fde, timeval_zero(), EVENT_FD_WRITE);
}
@ -396,11 +413,11 @@ NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t
rec->path = messaging_path(rec, server);
status = socket_connect(rec->sock, NULL, 0, rec->path, 0, 0);
status = try_connect(rec);
if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
/* backoff on this message - the servers listen queue is full */
struct timed_event te;
te.next_event = time(NULL)+1;
te.next_event = timeval_current_ofs(0, MESSAGING_BACKOFF);
te.handler = messaging_backoff_handler;
te.private = rec;
event_add_timed(msg->event.ev, &te);
@ -421,11 +438,25 @@ NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t
talloc_set_destructor(rec, rec_destructor);
messaging_send_handler(msg->event.ev, rec->fde, 0, EVENT_FD_WRITE);
messaging_send_handler(msg->event.ev, rec->fde, timeval_zero(), EVENT_FD_WRITE);
return NT_STATUS_OK;
}
/*
Send a message to a particular server, with the message containing a single pointer
*/
NTSTATUS messaging_send_ptr(struct messaging_context *msg, servid_t server,
uint32_t msg_type, void *ptr)
{
DATA_BLOB blob;
blob.data = (void *)&ptr;
blob.length = sizeof(void *);
return messaging_send(msg, server, msg_type, &blob);
}
/*
destroy the messaging context

@ -386,9 +386,144 @@ NTTIME nttime_from_string(const char *s)
return strtoull(s, NULL, 0);
}
int64_t usec_time_diff(struct timeval *larget, struct timeval *smallt)
/*
return (tv1 - tv2) in microseconds
*/
int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2)
{
int64_t sec_diff = larget->tv_sec - smallt->tv_sec;
return (sec_diff * 1000000) + (int64_t)(larget->tv_usec - smallt->tv_usec);
int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
}
/*
return a zero timeval
*/
struct timeval timeval_zero(void)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
return tv;
}
/*
return a timeval for the current time
*/
struct timeval timeval_current(void)
{
struct timeval tv;
GetTimeOfDay(&tv);
return tv;
}
/*
return a timeval struct with the given elements
*/
struct timeval timeval_set(uint32_t secs, uint32_t usecs)
{
struct timeval tv;
tv.tv_sec = secs;
tv.tv_usec = usecs;
return tv;
}
/*
return a timeval ofs microseconds after tv
*/
struct timeval timeval_add(struct timeval *tv, uint32_t secs, uint32_t usecs)
{
struct timeval tv2 = *tv;
const uint_t million = 1000000;
tv2.tv_sec += secs;
tv2.tv_usec += usecs;
tv2.tv_sec += tv2.tv_usec / million;
tv2.tv_usec = tv2.tv_usec % million;
return tv2;
}
/*
return the sum of two timeval structures
*/
struct timeval timeval_sum(struct timeval *tv1, struct timeval *tv2)
{
return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
}
/*
return a timeval secs/usecs into the future
*/
struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
{
struct timeval tv = timeval_current();
return timeval_add(&tv, secs, usecs);
}
/*
compare two timeval structures.
Return 1 if tv2 > tv1
Return 0 if tv2 == tv1
Return -1 if tv2 < tv1
*/
int timeval_compare(struct timeval *tv1, struct timeval *tv2)
{
if (tv2->tv_sec > tv1->tv_sec) return 1;
if (tv2->tv_sec < tv1->tv_sec) return -1;
if (tv2->tv_usec > tv1->tv_usec) return 1;
if (tv2->tv_usec < tv1->tv_usec) return -1;
return 0;
}
/*
return True if a timer is in the past
*/
BOOL timeval_expired(struct timeval *tv)
{
struct timeval tv2 = timeval_current();
if (tv2.tv_sec > tv->tv_sec) return True;
if (tv2.tv_sec < tv->tv_sec) return False;
return (tv2.tv_usec >= tv->tv_usec);
}
/*
return the number of seconds elapsed since a given time
*/
double timeval_elapsed(struct timeval *tv)
{
struct timeval tv2 = timeval_current();
return (tv2.tv_sec - tv->tv_sec) +
(tv2.tv_usec - tv->tv_usec)*1.0e-6;
}
/*
return the lesser of two timevals
*/
struct timeval timeval_min(struct timeval *tv1, struct timeval *tv2)
{
if (tv1->tv_sec < tv2->tv_sec) return *tv1;
if (tv1->tv_sec > tv2->tv_sec) return *tv2;
if (tv1->tv_usec < tv2->tv_usec) return *tv1;
return *tv2;
}
/*
return the difference between two timevals as a timeval
if tv2 comes after tv1, then return a zero timeval
(this is *tv1 - *tv2)
*/
struct timeval timeval_diff(struct timeval *tv1, struct timeval *tv2)
{
struct timeval t;
if (timeval_compare(tv1, tv2) >= 0) {
return timeval_zero();
}
t.tv_sec = tv1->tv_sec - tv2->tv_sec;
if (tv2->tv_usec > tv1->tv_usec) {
t.tv_sec--;
t.tv_usec = 1000000 - (tv2->tv_usec - tv1->tv_usec);
} else {
t.tv_usec = tv1->tv_usec - tv2->tv_usec;
}
return t;
}

69
source4/lib/unix_privs.c Normal file

@ -0,0 +1,69 @@
/*
Unix SMB/CIFS implementation.
gain/lose root privileges
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "system/passwd.h"
/*
there are times when smbd needs to temporarily gain root privileges
to do some operation. To do this you call root_privileges(), which
returns a talloc handle. To restore your previous privileges
talloc_free() this pointer.
Note that this call is considered successful even if it does not
manage to gain too privileges, but it will call smb_abort() if it
fails to restore the privileges afterwards. The logic is that
failing to gain root access can be caught by whatever operation
needs to be run as root failing, but failing to lose the root
privileges is dangerous.
This also means that this code is safe to be called from completely
unprivileged processes.
*/
struct saved_state {
uid_t uid;
};
static int privileges_destructor(void *ptr)
{
struct saved_state *s = ptr;
if (geteuid() != s->uid &&
seteuid(s->uid) != 0) {
smb_panic("Failed to restore privileges");
}
return 0;
}
void *root_privileges(void)
{
struct saved_state *s;
s = talloc_p(NULL, struct saved_state);
if (!s) return NULL;
s->uid = geteuid();
if (s->uid != 0) {
seteuid(0);
}
talloc_set_destructor(s, privileges_destructor);
return s;
}

@ -33,7 +33,7 @@ static void smbcli_transport_process_send(struct smbcli_transport *transport);
an event has happened on the socket
*/
static void smbcli_transport_event_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16_t flags)
struct timeval t, uint16_t flags)
{
struct smbcli_transport *transport = fde->private;
@ -233,21 +233,21 @@ again:
}
static void idle_handler(struct event_context *ev,
struct timed_event *te, time_t t)
struct timed_event *te, struct timeval t)
{
struct smbcli_transport *transport = te->private;
te->next_event = t + transport->idle.period;
te->next_event = timeval_add(&te->next_event, 0, transport->idle.period);
transport->idle.func(transport, transport->idle.private);
}
/*
setup the idle handler for a transport
the period is in seconds
the period is in microseconds
*/
void smbcli_transport_idle_handler(struct smbcli_transport *transport,
void (*idle_func)(struct smbcli_transport *, void *),
uint_t period,
void *private)
void (*idle_func)(struct smbcli_transport *, void *),
uint64_t period,
void *private)
{
struct timed_event te;
transport->idle.func = idle_func;
@ -258,7 +258,7 @@ void smbcli_transport_idle_handler(struct smbcli_transport *transport,
event_remove_timed(transport->event.ctx, transport->event.te);
}
te.next_event = time(NULL) + period;
te.next_event = timeval_current_ofs(0, period);
te.handler = idle_handler;
te.private = transport;
transport->event.te = event_add_timed(transport->event.ctx, &te);

@ -114,7 +114,7 @@ struct smbcli_transport {
uint_t readbraw_pending:1;
/* an idle function - if this is defined then it will be
called once every period seconds while we are waiting
called once every period microseconds while we are waiting
for a packet */
struct {
void (*func)(struct smbcli_transport *, void *);

@ -190,7 +190,7 @@ static void sock_process_recv(struct dcerpc_pipe *p)
called when a IO is triggered by the events system
*/
static void sock_io_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16_t flags)
struct timeval t, uint16_t flags)
{
struct dcerpc_pipe *p = fde->private;
struct sock_private *sock = p->transport.private;

@ -78,7 +78,8 @@ static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uin
/*
a handler for read events on a connection to a backend server
*/
static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde,
struct timeval t, uint16_t flags)
{
struct cvfs_private *private = fde->private;
struct smbsrv_tcon *tcon = private->tcon;
@ -149,7 +150,7 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
/* we need to receive oplock break requests from the server */
smbcli_oplock_handler(private->transport, oplock_handler, private);
smbcli_transport_idle_handler(private->transport, idle_func, 1, private);
smbcli_transport_idle_handler(private->transport, idle_func, 50000, private);
private->transport->event.fde->handler = cifs_socket_handler;
private->transport->event.fde->private = private;

@ -333,17 +333,14 @@ static void brl_notify_unlock(struct brl_context *brl,
for (i=0;i<count;i++) {
if (locks[i].lock_type >= PENDING_READ_LOCK &&
brl_overlap(&locks[i], removed_lock)) {
DATA_BLOB data;
if (last_notice != -1 && brl_overlap(&locks[i], &locks[last_notice])) {
continue;
}
if (locks[i].lock_type == PENDING_WRITE_LOCK) {
last_notice = i;
}
data.data = (void *)&locks[i].notify_ptr;
data.length = sizeof(void *);
messaging_send(brl->messaging_ctx, locks[i].context.server, MSG_BRL_RETRY, &data);
messaging_send_ptr(brl->messaging_ctx, locks[i].context.server,
MSG_BRL_RETRY, locks[i].notify_ptr);
}
}
}

@ -39,6 +39,7 @@
*/
#include "includes.h"
#include "messages.h"
struct odb_context {
struct tdb_wrap *w;
@ -58,6 +59,8 @@ struct odb_entry {
uint32_t share_access;
uint32_t create_options;
uint32_t access_mask;
void *notify_ptr;
BOOL pending;
};
@ -152,6 +155,8 @@ static BOOL share_conflict(struct odb_entry *e1, struct odb_entry *e2)
{
#define CHECK_MASK(am, sa, right, share) if (((am) & (right)) && !((sa) & (share))) return True
if (e1->pending || e2->pending) return False;
/* if either open involves no read.write or delete access then
it can't conflict */
if (!(e1->access_mask & (SA_RIGHT_FILE_WRITE_APPEND |
@ -219,6 +224,8 @@ NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum,
e.share_access = share_access;
e.create_options = create_options;
e.access_mask = access_mask;
e.notify_ptr = NULL;
e.pending = False;
/* check the existing file opens to see if they
conflict */
@ -254,6 +261,56 @@ NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum,
}
/*
register a pending open file in the open files database
*/
NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private)
{
struct odb_context *odb = lck->odb;
TDB_DATA dbuf;
struct odb_entry e;
char *tp;
struct odb_entry *elist;
int count;
dbuf = tdb_fetch(odb->w->tdb, lck->key);
e.server = odb->server;
e.tid = odb->tid;
e.fnum = 0;
e.share_access = 0;
e.create_options = 0;
e.access_mask = 0;
e.notify_ptr = private;
e.pending = True;
/* check the existing file opens to see if they
conflict */
elist = (struct odb_entry *)dbuf.dptr;
count = dbuf.dsize / sizeof(struct odb_entry);
tp = Realloc(dbuf.dptr, (count+1) * sizeof(struct odb_entry));
if (tp == NULL) {
if (dbuf.dptr) free(dbuf.dptr);
return NT_STATUS_NO_MEMORY;
}
dbuf.dptr = tp;
dbuf.dsize = (count+1) * sizeof(struct odb_entry);
memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
&e, sizeof(struct odb_entry));
if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
free(dbuf.dptr);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
free(dbuf.dptr);
return NT_STATUS_OK;
}
/*
remove a opendb entry
*/
@ -274,6 +331,15 @@ NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum)
elist = (struct odb_entry *)dbuf.dptr;
count = dbuf.dsize / sizeof(struct odb_entry);
/* send any pending notifications */
for (i=0;i<count;i++) {
if (elist[i].pending) {
messaging_send_ptr(odb->messaging_ctx, elist[i].server,
MSG_PVFS_RETRY_OPEN, elist[i].notify_ptr);
}
}
/* find the entry, and delete it */
for (i=0;i<count;i++) {
if (fnum == elist[i].fnum &&
@ -308,6 +374,60 @@ NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum)
}
/*
remove a pending opendb entry
*/
NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private)
{
struct odb_context *odb = lck->odb;
TDB_DATA dbuf;
struct odb_entry *elist;
int i, count;
NTSTATUS status;
dbuf = tdb_fetch(odb->w->tdb, lck->key);
if (dbuf.dptr == NULL) {
return NT_STATUS_UNSUCCESSFUL;
}
elist = (struct odb_entry *)dbuf.dptr;
count = dbuf.dsize / sizeof(struct odb_entry);
/* find the entry, and delete it */
for (i=0;i<count;i++) {
if (private == elist[i].notify_ptr &&
odb->server == elist[i].server &&
odb->tid == elist[i].tid) {
if (i < count-1) {
memmove(elist+i, elist+i+1,
(count - (i+1)) * sizeof(struct odb_entry));
}
break;
}
}
status = NT_STATUS_OK;
if (i == count) {
status = NT_STATUS_UNSUCCESSFUL;
} else if (count == 1) {
if (tdb_delete(odb->w->tdb, lck->key) != 0) {
status = NT_STATUS_INTERNAL_DB_CORRUPTION;
}
} else {
dbuf.dsize = (count-1) * sizeof(struct odb_entry);
if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
status = NT_STATUS_INTERNAL_DB_CORRUPTION;
}
}
free(dbuf.dptr);
return status;
}
/*
update create options on an open file
*/
@ -386,6 +506,8 @@ NTSTATUS odb_can_open(struct odb_context *odb, DATA_BLOB *key,
e.share_access = share_access;
e.create_options = create_options;
e.access_mask = access_mask;
e.notify_ptr = NULL;
e.pending = False;
for (i=0;i<count;i++) {
if (share_conflict(elist+i, &e)) {

@ -56,7 +56,7 @@ struct pvfs_pending_lock {
struct smbsrv_request *req;
int pending_lock;
void *wait_handle;
time_t end_time;
struct timeval end_time;
};
/*
@ -301,8 +301,9 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
pending->f = f;
pending->req = req;
/* round up to the nearest second */
pending->end_time = time(NULL) + ((lck->lockx.in.timeout+999)/1000);
pending->end_time =
timeval_current_ofs(lck->lockx.in.timeout/1000,
1000*(lck->lockx.in.timeout%1000));
}
if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) {

@ -25,6 +25,7 @@
#include "system/time.h"
#include "system/filesys.h"
#include "dlinklist.h"
#include "messages.h"
/*
create file handles with convenient numbers for sniffers
@ -33,6 +34,8 @@
#define PVFS_MIN_NEW_FNUM 0x200
#define PVFS_MIN_DIR_FNUM 0x300
#define SHARING_VIOLATION_DELAY 1000000
/*
find open file handle given fnum
*/
@ -125,7 +128,6 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
fnum = idr_get_new_above(pvfs->idtree_fnum, f, PVFS_MIN_DIR_FNUM, UINT16_MAX);
if (fnum == -1) {
talloc_free(f);
return NT_STATUS_TOO_MANY_OPENED_FILES;
}
@ -228,10 +230,12 @@ static int pvfs_fd_destructor(void *p)
return 0;
}
status = odb_close_file(lck, f->fnum);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
f->name->full_name, nt_errstr(status)));
if (f->have_opendb_entry) {
status = odb_close_file(lck, f->fnum);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
f->name->full_name, nt_errstr(status)));
}
}
talloc_free(lck);
@ -370,6 +374,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
f->access_mask = access_mask;
f->seek_offset = 0;
f->position = 0;
f->have_opendb_entry = True;
DLIST_ADD(pvfs->open_files, f);
@ -398,6 +403,166 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
}
/*
open am existing file - called from both the open retry code
and the main open code
*/
NTSTATUS pvfs_open_existing(struct pvfs_file *f,
union smb_open *io,
int open_flags)
{
int fd;
NTSTATUS status;
/* do the actual open */
fd = open(f->name->full_name, open_flags);
if (fd == -1) {
return pvfs_map_errno(f->pvfs, errno);
}
f->fd = fd;
/* re-resolve the open fd */
status = pvfs_resolve_name_fd(f->pvfs, fd, f->name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
io->generic.out.oplock_level = NO_OPLOCK;
io->generic.out.fnum = f->fnum;
io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
io->generic.out.create_time = f->name->dos.create_time;
io->generic.out.access_time = f->name->dos.access_time;
io->generic.out.write_time = f->name->dos.write_time;
io->generic.out.change_time = f->name->dos.change_time;
io->generic.out.attrib = f->name->dos.attrib;
io->generic.out.alloc_size = f->name->dos.alloc_size;
io->generic.out.size = f->name->st.st_size;
io->generic.out.file_type = FILE_TYPE_DISK;
io->generic.out.ipc_state = 0;
io->generic.out.is_directory = 0;
/* success - keep the file handle */
talloc_steal(f->pvfs, f);
return NT_STATUS_OK;
}
/*
state of a pending open retry
*/
struct pvfs_open_retry {
union smb_open *io;
struct pvfs_file *f;
struct smbsrv_request *req;
void *wait_handle;
struct timeval end_time;
int open_flags;
};
/* destroy a pending open request */
static int pvfs_retry_destructor(void *ptr)
{
struct pvfs_open_retry *r = ptr;
struct odb_lock *lck;
lck = odb_lock(r->req, r->f->pvfs->odb_context, &r->f->locking_key);
if (lck != NULL) {
odb_remove_pending(lck, r);
}
return 0;
}
/*
retry an open
*/
static void pvfs_open_retry(void *private, BOOL timed_out)
{
struct pvfs_open_retry *r = private;
struct odb_lock *lck;
struct pvfs_file *f = r->f;
struct smbsrv_request *req = r->req;
NTSTATUS status;
lck = odb_lock(req, f->pvfs->odb_context, &f->locking_key);
if (lck == NULL) {
req->async_states->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
req->async_states->send_fn(req);
return;
}
/* see if we are allowed to open at the same time as existing opens */
status = odb_open_file(lck, f->fnum, f->share_access,
f->create_options, f->access_mask);
if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) && !timed_out) {
talloc_free(lck);
return;
}
talloc_free(r->wait_handle);
if (!NT_STATUS_IS_OK(status)) {
req->async_states->status = status;
req->async_states->send_fn(req);
return;
}
f->have_opendb_entry = True;
/* do the rest of the open work */
status = pvfs_open_existing(f, r->io, r->open_flags);
if (NT_STATUS_IS_OK(status)) {
talloc_steal(f->pvfs, f);
}
req->async_states->status = status;
req->async_states->send_fn(req);
}
/*
setup for a open retry after a sharing violation
*/
static NTSTATUS pvfs_open_setup_retry(struct smbsrv_request *req,
union smb_open *io,
struct pvfs_file *f,
struct odb_lock *lck,
int open_flags)
{
struct pvfs_open_retry *r;
struct pvfs_state *pvfs = f->pvfs;
NTSTATUS status;
r = talloc_p(req, struct pvfs_open_retry);
if (r == NULL) {
return NT_STATUS_NO_MEMORY;
}
r->io = io;
r->f = f;
r->req = req;
r->end_time = timeval_current_ofs(0, SHARING_VIOLATION_DELAY);
r->open_flags = open_flags;
/* setup a pending lock */
status = odb_open_file_pending(lck, r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, r->end_time,
pvfs_open_retry, r);
if (r->wait_handle == NULL) {
return NT_STATUS_NO_MEMORY;
}
talloc_free(lck);
talloc_steal(pvfs, req);
talloc_set_destructor(r, pvfs_retry_destructor);
return NT_STATUS_OK;
}
/*
open a file
*/
@ -405,7 +570,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
struct smbsrv_request *req, union smb_open *io)
{
struct pvfs_state *pvfs = ntvfs->private_data;
int fd, flags;
int flags;
struct pvfs_filename *name;
struct pvfs_file *f;
NTSTATUS status;
@ -539,11 +704,26 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
return NT_STATUS_TOO_MANY_OPENED_FILES;
}
f->fnum = fnum;
f->fd = -1;
f->name = talloc_steal(f, name);
f->session = req->session;
f->smbpid = req->smbpid;
f->pvfs = pvfs;
f->pending_list = NULL;
f->lock_count = 0;
f->create_options = io->generic.in.create_options;
f->share_access = io->generic.in.share_access;
f->access_mask = access_mask;
f->seek_offset = 0;
f->position = 0;
f->have_opendb_entry = False;
/* form the lock context used for byte range locking and
opendb locking */
status = pvfs_locking_key(name, f, &f->locking_key);
if (!NT_STATUS_IS_OK(status)) {
idr_remove(pvfs->idtree_fnum, fnum);
idr_remove(pvfs->idtree_fnum, f->fnum);
return status;
}
@ -558,65 +738,31 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
/* see if we are allowed to open at the same time as existing opens */
status = odb_open_file(lck, fnum, share_access, create_options, access_mask);
if (!NT_STATUS_IS_OK(status)) {
idr_remove(pvfs->idtree_fnum, fnum);
return status;
}
f->fnum = fnum;
f->fd = -1;
f->name = talloc_steal(f, name);
f->session = req->session;
f->smbpid = req->smbpid;
f->pvfs = pvfs;
f->pending_list = NULL;
f->lock_count = 0;
f->create_options = io->generic.in.create_options;
f->share_access = io->generic.in.share_access;
f->access_mask = access_mask;
f->seek_offset = 0;
f->position = 0;
DLIST_ADD(pvfs->open_files, f);
/* setup a destructor to avoid file descriptor leaks on
abnormal termination */
talloc_set_destructor(f, pvfs_fd_destructor);
/* do the actual open */
fd = open(name->full_name, flags);
if (fd == -1) {
return pvfs_map_errno(pvfs, errno);
/* see if we are allowed to open at the same time as existing opens */
status = odb_open_file(lck, f->fnum, share_access, create_options, access_mask);
/* on a sharing violation we need to retry when the file is closed by
the other user, or after 1 second */
if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
return pvfs_open_setup_retry(req, io, f, lck, flags);
}
f->fd = fd;
/* re-resolve the open fd */
status = pvfs_resolve_name_fd(pvfs, fd, name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
io->generic.out.oplock_level = NO_OPLOCK;
io->generic.out.fnum = f->fnum;
io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
io->generic.out.create_time = name->dos.create_time;
io->generic.out.access_time = name->dos.access_time;
io->generic.out.write_time = name->dos.write_time;
io->generic.out.change_time = name->dos.change_time;
io->generic.out.attrib = name->dos.attrib;
io->generic.out.alloc_size = name->dos.alloc_size;
io->generic.out.size = name->st.st_size;
io->generic.out.file_type = FILE_TYPE_DISK;
io->generic.out.ipc_state = 0;
io->generic.out.is_directory = 0;
f->have_opendb_entry = True;
/* success - keep the file handle */
talloc_steal(pvfs, f);
return NT_STATUS_OK;
/* do the rest of the open work */
return pvfs_open_existing(f, io, flags);
}
@ -677,7 +823,6 @@ NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
for (f=pvfs->open_files;f;f=next) {
next = f->next;
if (f->session == req->session) {
DLIST_REMOVE(pvfs->open_files, f);
talloc_free(f);
}
}
@ -698,7 +843,6 @@ NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
for (f=pvfs->open_files;f;f=next) {
next = f->next;
if (f->smbpid == req->smbpid) {
DLIST_REMOVE(pvfs->open_files, f);
talloc_free(f);
}
}

@ -58,10 +58,9 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin
struct pvfs_wait *pwait = private;
struct smbsrv_request *req;
/* we need to check that this one is for us. This sender sends
the private pointer as the body of the message. This might
seem a little unusual, but as the pointer is guaranteed
unique for this server, it is a good token */
/* we need to check that this one is for us. See
messaging_send_ptr() for the other side of this.
*/
if (data->length != sizeof(void *) ||
*(void **)data->data != pwait->private) {
return;
@ -82,7 +81,8 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin
/*
receive a timeout on a message wait
*/
static void pvfs_wait_timeout(struct event_context *ev, struct timed_event *te, time_t t)
static void pvfs_wait_timeout(struct event_context *ev,
struct timed_event *te, struct timeval t)
{
struct pvfs_wait *pwait = te->private;
struct smbsrv_request *req = pwait->req;
@ -116,7 +116,7 @@ static int pvfs_wait_destructor(void *ptr)
void *pvfs_wait_message(struct pvfs_state *pvfs,
struct smbsrv_request *req,
int msg_type,
time_t end_time,
struct timeval end_time,
void (*fn)(void *, BOOL),
void *private)
{

@ -112,6 +112,8 @@ struct pvfs_file {
/* yes, we need 2 independent positions ... */
uint64_t seek_offset;
uint64_t position;
BOOL have_opendb_entry;
};

@ -1057,21 +1057,18 @@ static void dcesrv_accept(struct server_connection *srv_conn)
dcesrv_sock_accept(srv_conn);
}
static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
static void dcesrv_recv(struct server_connection *srv_conn,
struct timeval t, uint16_t flags)
{
dcesrv_sock_recv(srv_conn, t, flags);
}
static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
static void dcesrv_send(struct server_connection *srv_conn,
struct timeval t, uint16_t flags)
{
dcesrv_sock_send(srv_conn, t, flags);
}
static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
{
dcesrv_sock_idle(srv_conn, t);
}
static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
{
dcesrv_sock_close(srv_conn, reason);
@ -1190,7 +1187,7 @@ static const struct server_service_ops dcesrv_ops = {
.accept_connection = dcesrv_accept,
.recv_handler = dcesrv_recv,
.send_handler = dcesrv_send,
.idle_handler = dcesrv_idle,
.idle_handler = NULL,
.close_connection = dcesrv_close,
.service_exit = dcesrv_exit,
};

@ -248,7 +248,7 @@ void dcesrv_sock_accept(struct server_connection *conn)
return;
}
void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
void dcesrv_sock_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
{
NTSTATUS status;
struct dcesrv_connection *dce_conn = conn->private_data;
@ -288,7 +288,7 @@ void dcesrv_sock_recv(struct server_connection *conn, time_t t, uint16_t flags)
return;
}
void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
void dcesrv_sock_send(struct server_connection *conn, struct timeval t, uint16_t flags)
{
struct dcesrv_connection *dce_conn = conn->private_data;
NTSTATUS status;
@ -308,14 +308,6 @@ void dcesrv_sock_send(struct server_connection *conn, time_t t, uint16_t flags)
return;
}
void dcesrv_sock_idle(struct server_connection *conn, time_t t)
{
DEBUG(10,("dcesrv_sock_idle\n"));
conn->event.idle->next_event = t + 5;
return;
}
void dcesrv_sock_close(struct server_connection *conn, const char *reason)
{
struct dcesrv_connection *dce_conn = conn->private_data;

@ -723,7 +723,7 @@ static void smbsrv_init(struct server_service *service, const struct model_ops *
/*
called when a SMB socket becomes readable
*/
static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
{
struct smbsrv_connection *smb_conn = conn->private_data;
NTSTATUS status;
@ -744,7 +744,7 @@ static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags
/*
called when a SMB socket becomes writable
*/
static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
{
struct smbsrv_connection *smb_conn = conn->private_data;
@ -787,11 +787,10 @@ static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags
/*
called when connection is idle
*/
static void smbsrv_idle(struct server_connection *conn, time_t t)
static void smbsrv_idle(struct server_connection *conn, struct timeval t)
{
DEBUG(10,("smbsrv_idle: not implemented!\n"));
conn->event.idle->next_event = t + 5;
conn->event.idle->next_event = timeval_add(&t, 5, 0);
return;
}

@ -40,10 +40,12 @@ struct model_ops {
void (*model_startup)(void);
/* function to accept new connection */
void (*accept_connection)(struct event_context *, struct fd_event *, time_t, uint16_t);
void (*accept_connection)(struct event_context *, struct fd_event *,
struct timeval t, uint16_t);
/* function to terminate a connection */
void (*terminate_connection)(struct server_connection *srv_conn, const char *reason);
void (*terminate_connection)(struct server_connection *srv_conn,
const char *reason);
/* function to exit server */
void (*exit_server)(struct server_context *srv_ctx, const char *reason);

@ -38,7 +38,8 @@ static void single_start_server(void)
/*
called when a listening socket becomes readable
*/
static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags)
static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
struct timeval t, uint16_t flags)
{
NTSTATUS status;
struct socket_context *sock;
@ -55,7 +56,7 @@ static void single_accept_connection(struct event_context *ev, struct fd_event *
conn = server_setup_connection(ev, server_socket, sock, t, socket_get_fd(sock));
if (!conn) {
DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n"));
DEBUG(0,("server_setup_connection failed\n"));
return;
}

@ -39,7 +39,7 @@ static void standard_model_startup(void)
called when a listening socket becomes readable
*/
static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_fde,
time_t t, uint16_t flags)
struct timeval t, uint16_t flags)
{
NTSTATUS status;
struct socket_context *sock;

@ -205,7 +205,7 @@ static int server_destructor(void *ptr)
struct server_connection *server_setup_connection(struct event_context *ev,
struct server_socket *server_socket,
struct socket_context *sock,
time_t t,
struct timeval t,
servid_t server_id)
{
struct fd_event fde;
@ -226,13 +226,13 @@ struct server_connection *server_setup_connection(struct event_context *ev,
fde.handler = server_io_handler;
idle.private = srv_conn;
idle.next_event = t + SERVER_DEFAULT_IDLE_TIME;
idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0);
idle.handler = server_idle_handler;
srv_conn->event.ctx = ev;
srv_conn->event.fde = &fde;
srv_conn->event.idle = &idle;
srv_conn->event.idle_time = SERVER_DEFAULT_IDLE_TIME;
srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0);
srv_conn->server_socket = server_socket;
srv_conn->service = server_socket->service;
@ -269,11 +269,12 @@ void server_terminate_connection(struct server_connection *srv_conn, const char
srv_conn->service->model_ops->terminate_connection(srv_conn, reason);
}
void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags)
void server_io_handler(struct event_context *ev, struct fd_event *fde,
struct timeval t, uint16_t flags)
{
struct server_connection *conn = fde->private;
conn->event.idle->next_event = t + conn->event.idle_time;
conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
if (flags & EVENT_FD_WRITE) {
conn->service->ops->send_handler(conn, t, flags);
@ -286,13 +287,14 @@ void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t,
}
void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t)
void server_idle_handler(struct event_context *ev, struct timed_event *idle,
struct timeval t)
{
struct server_connection *conn = idle->private;
conn->event.idle->next_event = t + conn->event.idle_time;
conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time);
conn->service->ops->idle_handler(conn,t);
conn->service->ops->idle_handler(conn, t);
}
/*
return the operations structure for a named backend of the specified type

@ -48,13 +48,13 @@ struct server_service_ops {
void (*accept_connection)(struct server_connection *);
/* function to accept new connection */
void (*recv_handler)(struct server_connection *, time_t, uint16_t);
void (*recv_handler)(struct server_connection *, struct timeval, uint16_t);
/* function to accept new connection */
void (*send_handler)(struct server_connection *, time_t, uint16_t);
void (*send_handler)(struct server_connection *, struct timeval, uint16_t);
/* function to accept new connection */
void (*idle_handler)(struct server_connection *, time_t);
void (*idle_handler)(struct server_connection *, struct timeval);
/* function to close a connection */
void (*close_connection)(struct server_connection *, const char *reason);
@ -114,7 +114,7 @@ struct server_connection {
struct event_context *ctx;
struct fd_event *fde;
struct timed_event *idle;
time_t idle_time;
struct timeval idle_time;
} event;
servid_t server_id;

@ -35,9 +35,9 @@ BOOL torture_dirtest1(void)
int i;
struct smbcli_state *cli;
int fnum;
double t1;
BOOL correct = True;
extern int torture_numops;
struct timeval tv;
printf("starting dirtest1\n");
@ -48,6 +48,7 @@ BOOL torture_dirtest1(void)
printf("Creating %d random filenames\n", torture_numops);
srandom(0);
tv = timeval_current();
for (i=0;i<torture_numops;i++) {
char *fname;
asprintf(&fname, "\\%x", (int)random());
@ -61,13 +62,11 @@ BOOL torture_dirtest1(void)
free(fname);
}
t1 = end_timer();
printf("Matched %d\n", smbcli_list(cli->tree, "a*.*", 0, list_fn, NULL));
printf("Matched %d\n", smbcli_list(cli->tree, "b*.*", 0, list_fn, NULL));
printf("Matched %d\n", smbcli_list(cli->tree, "xyzabc", 0, list_fn, NULL));
printf("dirtest core %g seconds\n", end_timer() - t1);
printf("dirtest core %g seconds\n", timeval_elapsed(&tv));
srandom(0);
for (i=0;i<torture_numops;i++) {

@ -189,7 +189,7 @@ static BOOL connect_servers(void)
}
smbcli_oplock_handler(servers[i].cli[j]->transport, oplock_handler, NULL);
smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 1, NULL);
smbcli_transport_idle_handler(servers[i].cli[j]->transport, idle_func, 50000, NULL);
}
}

@ -58,6 +58,7 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
int ping_count = 0;
int pong_count = 0;
BOOL ret = True;
struct timeval tv;
if (fork() == 0) {
struct messaging_context *msg_ctx2 = messaging_init(mem_ctx, 1, ev);
@ -83,10 +84,10 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
messaging_register(msg_ctx, &pong_count, MY_PONG, pong_message);
start_timer();
tv = timeval_current();
printf("Sending pings for 10 seconds\n");
while (end_timer() < 10.0) {
while (timeval_elapsed(&tv) < 10.0) {
DATA_BLOB data;
NTSTATUS status1, status2;
@ -113,7 +114,7 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
printf("waiting for %d remaining replies (done %d)\n",
ping_count - pong_count, pong_count);
while (end_timer() < 30 && pong_count < ping_count) {
while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
event_loop_once(ev);
}
@ -125,7 +126,8 @@ static BOOL test_ping_speed(TALLOC_CTX *mem_ctx)
ret = False;
}
printf("ping rate of %.0f messages/sec\n", (ping_count+pong_count)/end_timer());
printf("ping rate of %.0f messages/sec\n",
(ping_count+pong_count)/timeval_elapsed(&tv));
talloc_free(msg_ctx);

@ -36,18 +36,18 @@
#ifdef _STANDALONE_
typedef enum {False=0,True=1} BOOL;
static struct timeval tp1,tp2;
static void start_timer(void)
static struct timeval current_time(void)
{
gettimeofday(&tp1,NULL);
struct timeval tv;
GetTimeOfDay(&tv);
return tv;
}
static double end_timer(void)
static double elapsed_time(struct timeval *tv)
{
gettimeofday(&tp2,NULL);
return((tp2.tv_sec - tp1.tv_sec) +
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
struct timeval tv2 = current_time();
return (tv2.tv_sec - tv->tv_sec) +
(tv2.tv_usec - tv->tv_usec)*1.0e-6;
}
#endif /* _STANDALONE_ */
@ -642,10 +642,11 @@ static BOOL test_speed(void)
{
void *ctx = talloc(NULL, 0);
unsigned count;
struct timeval tv;
printf("MEASURING TALLOC VS MALLOC SPEED\n");
start_timer();
tv = timeval_current();
count = 0;
do {
void *p1, *p2, *p3;
@ -654,13 +655,13 @@ static BOOL test_speed(void)
p3 = talloc(p1, 300);
talloc_free(p1);
count += 3;
} while (end_timer() < 5.0);
} while (timeval_elapsed(&tv) < 5.0);
printf("talloc: %.0f ops/sec\n", count/end_timer());
printf("talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
talloc_free(ctx);
start_timer();
tv = timeval_current();
count = 0;
do {
void *p1, *p2, *p3;
@ -671,9 +672,9 @@ static BOOL test_speed(void)
free(p2);
free(p3);
count += 3;
} while (end_timer() < 5.0);
} while (timeval_elapsed(&tv) < 5.0);
printf("malloc: %.0f ops/sec\n", count/end_timer());
printf("malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv));
return True;
}

@ -37,6 +37,9 @@ static BOOL run_netbench(struct smbcli_state *cli, int client)
fstring params[20];
const char *p;
BOOL correct = True;
struct timeval tv;
tv = timeval_current();
nb_setup(cli, client, warmup);
@ -52,15 +55,15 @@ static BOOL run_netbench(struct smbcli_state *cli, int client)
again:
while (fgets(line, sizeof(line)-1, f)) {
NTSTATUS status;
double t = end_timer();
if (warmup && t >= warmup) {
if (warmup &&
timeval_elapsed(&tv) >= warmup) {
warmup = 0;
nb_warmup_done();
start_timer();
tv = timeval_current();
}
if (end_timer() >= timelimit) {
if (timeval_elapsed(&tv) >= timelimit) {
goto done;
}

@ -31,6 +31,7 @@ static int nbio_id;
static int nprocs;
static BOOL bypass_io;
static int warmup;
static struct timeval tv;
struct ftable {
struct ftable *next, *prev;
@ -76,7 +77,7 @@ void nb_alarm(int sig)
if (!children[i].done) num_clients++;
}
t = end_timer();
t = timeval_elapsed(&tv);
if (warmup) {
printf("%4d %8d %.2f MB/sec warmup %.0f sec \n",
@ -91,7 +92,7 @@ void nb_alarm(int sig)
}
if (warmup && t >= warmup) {
start_timer();
tv = timeval_current();
warmup = 0;
}
@ -156,7 +157,7 @@ void nb_setup(struct smbcli_state *cli, int id, int warmupt)
warmup = warmupt;
nbio_id = id;
c = cli;
start_timer();
tv = timeval_current();
if (children) {
children[nbio_id].done = 0;
}

@ -42,6 +42,8 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
int fnum;
BOOL ret = True;
struct smbcli_request *req;
struct timeval tv;
double d;
printf("testing multiplexed open/open/close\n");
@ -64,14 +66,25 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
CHECK_STATUS(status, NT_STATUS_OK);
fnum = io.ntcreatex.out.fnum;
tv = timeval_current();
/* send an open that will conflict */
io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
d = timeval_elapsed(&tv);
if (d < 0.5 || d > 1.5) {
printf("bad timeout for conflict - %.2f should be 1.0\n", d);
ret = False;
} else {
printf("open delay %.2f\n", d);
}
/*
same request, but async
*/
tv = timeval_current();
req = smb_raw_open_send(cli->tree, &io);
/* and close the file */
@ -81,6 +94,14 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
status = smb_raw_open_recv(req, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
d = timeval_elapsed(&tv);
if (d > 0.25) {
printf("bad timeout for async conflict - %.2f should be <0.25\n", d);
ret = False;
} else {
printf("async open delay %.2f\n", d);
}
smbcli_close(cli->tree, io.ntcreatex.out.fnum);
done:

@ -266,6 +266,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
int fnum = -1, fnum2;
BOOL ret = True;
int i;
struct timeval tv;
struct {
uint16_t open_func;
BOOL with_file;
@ -398,13 +399,13 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
fnum = io.openx.out.fnum;
io.openx.in.timeout = 20000;
start_timer();
tv = timeval_current();
io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_NONE;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
if (end_timer() > 3) {
printf("(%s) Incorrect timing in openx with timeout - waited %d seconds\n",
__location__, (int)end_timer());
if (timeval_elapsed(&tv) > 3.0) {
printf("(%s) Incorrect timing in openx with timeout - waited %.2f seconds\n",
__location__, timeval_elapsed(&tv));
ret = False;
}
smbcli_close(cli->tree, fnum);

@ -937,22 +937,19 @@ static BOOL run_deferopen(struct smbcli_state *cli, int dummy)
int fnum = -1;
do {
struct timeval tv_start, tv_end;
GetTimeOfDay(&tv_start);
struct timeval tv;
tv = timeval_current();
fnum = smbcli_nt_create_full(cli->tree, fname, 0, GENERIC_RIGHTS_FILE_ALL_ACCESS,
FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE,
NTCREATEX_DISP_OPEN_IF, 0, 0);
if (fnum != -1) {
break;
}
GetTimeOfDay(&tv_end);
if (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION)) {
/* Sharing violation errors need to be 1 second apart. */
int64_t tdif = usec_time_diff(&tv_end, &tv_start);
if (tdif < 500000 || tdif > 1500000) {
fprintf(stderr,"Timing incorrect %lld.%lld for share violation\n",
tdif / (int64_t)1000000,
tdif % (int64_t)1000000);
double e = timeval_elapsed(&tv);
if (e < 0.5 || e > 1.5) {
fprintf(stderr,"Timing incorrect %.2f violation\n",
e);
}
}
} while (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION));
@ -2269,6 +2266,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
char **unc_list = NULL;
const char *p;
int num_unc_names = 0;
struct timeval tv;
synccount = 0;
@ -2300,7 +2298,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
child_status_out[i] = True;
}
start_timer();
tv = timeval_current();
for (i=0;i<torture_nprocs;i++) {
procnum = i;
@ -2364,18 +2362,18 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
}
if (synccount == torture_nprocs) break;
msleep(100);
} while (end_timer() < start_time_limit);
} while (timeval_elapsed(&tv) < start_time_limit);
if (synccount != torture_nprocs) {
printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
*result = False;
return end_timer();
return timeval_elapsed(&tv);
}
printf("Starting %d clients\n", torture_nprocs);
/* start the client load */
start_timer();
tv = timeval_current();
for (i=0;i<torture_nprocs;i++) {
child_status[i] = 0;
}
@ -2398,7 +2396,7 @@ double torture_create_procs(BOOL (*fn)(struct smbcli_state *, int), BOOL *result
*result = False;
}
}
return end_timer();
return timeval_elapsed(&tv);
}
#define FLAG_MULTIPROC 1
@ -2557,12 +2555,12 @@ static BOOL run_test(const char *name)
}
} else {
start_timer();
struct timeval tv = timeval_current();
if (!torture_ops[i].fn()) {
ret = False;
printf("TEST %s FAILED!\n", torture_ops[i].name);
}
t = end_timer();
t = timeval_elapsed(&tv);
}
printf("%s took %g secs\n\n", torture_ops[i].name, t);
}

@ -24,21 +24,6 @@
#include "system/time.h"
static struct timeval tp1,tp2;
void start_timer(void)
{
gettimeofday(&tp1,NULL);
}
double end_timer(void)
{
gettimeofday(&tp2,NULL);
return((tp2.tv_sec - tp1.tv_sec) +
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
}
/*
create a directory, returning a handle to it
*/