fixed handling of change notify buffer overruns
authorAndrew Tridgell <tridge@samba.org>
Fri, 5 Jun 2009 06:25:44 +0000 (16:25 +1000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 5 Jun 2009 06:25:44 +0000 (16:25 +1000)
When the notify buffer overruns and there are no pending notify
requests, the notify buffer doesn't actually get destroyed, it just
gets put in a state where new notifies are discarded and the next
notify change request will return 0 changes.

source4/ntvfs/posix/pvfs_notify.c

index 09aa0f64e63e837ac985b92fa38ee38d53b59b2c..3e6f442d613cf40ce9f0317ec94828fbe54faf86 100644 (file)
@@ -34,6 +34,7 @@ struct pvfs_notify_buffer {
        struct notify_changes *changes;
        uint32_t max_buffer_size;
        uint32_t current_buffer_size;
        struct notify_changes *changes;
        uint32_t max_buffer_size;
        uint32_t current_buffer_size;
+       bool overflowed;
 
        /* a list of requests waiting for events on this handle */
        struct notify_pending {
 
        /* a list of requests waiting for events on this handle */
        struct notify_pending {
@@ -71,7 +72,7 @@ static void pvfs_notify_send(struct pvfs_notify_buffer *notify_buffer,
                while (notify_buffer->pending) {
                        pvfs_notify_send(notify_buffer, NT_STATUS_OK, immediate);
                }
                while (notify_buffer->pending) {
                        pvfs_notify_send(notify_buffer, NT_STATUS_OK, immediate);
                }
-               talloc_free(notify_buffer);
+               notify_buffer->overflowed = true;
                return;
        }
 
                return;
        }
 
@@ -88,6 +89,7 @@ static void pvfs_notify_send(struct pvfs_notify_buffer *notify_buffer,
        info->nttrans.out.num_changes = notify_buffer->num_changes;
        info->nttrans.out.changes = talloc_steal(req, notify_buffer->changes);
        notify_buffer->num_changes = 0;
        info->nttrans.out.num_changes = notify_buffer->num_changes;
        info->nttrans.out.changes = talloc_steal(req, notify_buffer->changes);
        notify_buffer->num_changes = 0;
+       notify_buffer->overflowed = false;
        notify_buffer->changes = NULL;
        notify_buffer->current_buffer_size = 0;
 
        notify_buffer->changes = NULL;
        notify_buffer->current_buffer_size = 0;
 
@@ -133,6 +135,10 @@ static void pvfs_notify_callback(void *private_data, const struct notify_event *
        struct notify_changes *n2;
        char *new_path;
 
        struct notify_changes *n2;
        char *new_path;
 
+       if (n->overflowed) {
+               return;
+       }
+
        n2 = talloc_realloc(n, n->changes, struct notify_changes, n->num_changes+1);
        if (n2 == NULL) {
                /* nothing much we can do for this */
        n2 = talloc_realloc(n, n->changes, struct notify_changes, n->num_changes+1);
        if (n2 == NULL) {
                /* nothing much we can do for this */
@@ -267,7 +273,8 @@ NTSTATUS pvfs_notify(struct ntvfs_module_context *ntvfs,
        DLIST_ADD_END(f->notify_buffer->pending, pending, struct notify_pending *);
 
        /* if the buffer is empty then start waiting */
        DLIST_ADD_END(f->notify_buffer->pending, pending, struct notify_pending *);
 
        /* if the buffer is empty then start waiting */
-       if (f->notify_buffer->num_changes == 0) {
+       if (f->notify_buffer->num_changes == 0 && 
+           !f->notify_buffer->overflowed) {
                struct pvfs_wait *wait_handle;
                wait_handle = pvfs_wait_message(pvfs, req, -1,
                                                timeval_zero(),
                struct pvfs_wait *wait_handle;
                wait_handle = pvfs_wait_message(pvfs, req, -1,
                                                timeval_zero(),