This is second part of kevent based AIO reading implementation.

Signed-off-by: Evgeniy Polyakov <[EMAIL PROTECTED]>

diff --git a/include/linux/kevent.h b/include/linux/kevent.h
index 376fedc..521119e 100644
--- a/include/linux/kevent.h
+++ b/include/linux/kevent.h
@@ -27,12 +27,14 @@
  */
 
 #define KEVENT_REQ_ONESHOT     0x1             /* Process this event only once 
and then dequeue. */
+#define KEVENT_REQ_ENQUEUE     0x2             /* Always add that kevent, even 
if it is ready immediately. */
 
 /*
  * Kevent return flags.
  */
 #define KEVENT_RET_BROKEN      0x1             /* Kevent is broken. */
 #define KEVENT_RET_DONE                0x2             /* Kevent processing 
was finished successfully. */
+#define KEVENT_RET_STACK       0x4             /* Kevent was allocated in 
stack. Can only be used for immediate ready kevents. */
 
 /*
  * Kevent type set.
@@ -202,7 +204,6 @@ struct kevent_user
        unsigned int            max_ready_num;          /* Requested number of 
kevents. */
 
        struct semaphore        ctl_mutex;              /* Protects against 
simultaneous kevent_user control manipulations. */
-       struct semaphore        wait_mutex;             /* Protects against 
simultaneous kevent_user waits. */
        wait_queue_head_t       wait;                   /* Wait until some 
events are ready. */
 
        atomic_t                refcnt;                 /* Reference counter, 
increased for each new kevent. */
@@ -210,6 +211,7 @@ struct kevent_user
        unsigned long           im_num;
        unsigned long           wait_num;
        unsigned long           total;
+       unsigned long           enfile;
 #endif
 };
 
@@ -220,7 +222,9 @@ void kevent_free(struct kevent *k);
 int kevent_enqueue(struct kevent *k);
 int kevent_dequeue(struct kevent *k);
 int kevent_init(struct kevent *k);
-void kevent_requeue(struct kevent *k);
+int kevent_requeue(struct kevent *k);
+struct kevent *kevent_recreate(struct kevent *kevent, gfp_t mask);
+void kevent_finish_user(struct kevent *k, int lock, int deq);
 
 #define list_for_each_entry_reverse_safe(pos, n, head, member)                 
\
        for (pos = list_entry((head)->prev, typeof(*pos), member),      \
@@ -241,7 +245,7 @@ int kevent_init_aio(struct kevent *k);
 void kevent_storage_ready(struct kevent_storage *st, kevent_callback_t 
ready_callback, u32 event);
 int kevent_storage_init(void *origin, struct kevent_storage *st);
 void kevent_storage_fini(struct kevent_storage *st);
-int kevent_storage_enqueue(struct kevent_storage *st, struct kevent *k);
+void kevent_storage_enqueue(struct kevent_storage *st, struct kevent *k);
 void kevent_storage_dequeue(struct kevent_storage *st, struct kevent *k);
 
 int kevent_user_add_ukevent(struct ukevent *uk, struct kevent_user *u);
diff --git a/kernel/kevent/kevent.c b/kernel/kevent/kevent.c
index 9bccc66..a055f40 100644
--- a/kernel/kevent/kevent.c
+++ b/kernel/kevent/kevent.c
@@ -116,7 +116,7 @@ int kevent_init(struct kevent *k)
  * Called from ->enqueue() callback when reference counter for given
  * origin (socket, inode...) has been increased.
  */
-int kevent_storage_enqueue(struct kevent_storage *st, struct kevent *k)
+void kevent_storage_enqueue(struct kevent_storage *st, struct kevent *k)
 {
        unsigned long flags;
 
@@ -125,7 +125,6 @@ int kevent_storage_enqueue(struct kevent
        list_add_tail(&k->storage_entry, &st->list);
        st->qlen++;
        spin_unlock_irqrestore(&st->lock, flags);
-       return 0;
 }
 
 /*
@@ -146,7 +145,7 @@ void kevent_storage_dequeue(struct keven
        spin_unlock_irqrestore(&st->lock, flags);
 }
 
-static void __kevent_requeue(struct kevent *k, u32 event)
+static int kevent_callback(struct kevent *k)
 {
        int err, rem = 0;
        unsigned long flags;
@@ -162,30 +161,45 @@ static void __kevent_requeue(struct keve
        }
        rem = (k->event.req_flags & KEVENT_REQ_ONESHOT);
        spin_unlock_irqrestore(&k->lock, flags);
+       
+       if (err && rem) {
+               list_del(&k->storage_entry);
+               k->st->qlen--;
+       }
 
-       if (err) {
-               if (rem) {
-                       list_del(&k->storage_entry);
-                       k->st->qlen--;
-               }
-               
-               spin_lock_irqsave(&k->user->ready_lock, flags);
-               if (k->ready_entry.next == LIST_POISON1) {
-                       list_add_tail(&k->ready_entry, &k->user->ready_list);
-                       k->user->ready_num++;
-               }
-               spin_unlock_irqrestore(&k->user->ready_lock, flags);
-               wake_up(&k->user->wait);
+       return err;
+}
+
+static void __kevent_requeue(struct kevent *k, u32 event)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&k->user->ready_lock, flags);
+       if (k->ready_entry.next == LIST_POISON1) {
+               list_add_tail(&k->ready_entry, &k->user->ready_list);
+               k->user->ready_num++;
        }
+       spin_unlock_irqrestore(&k->user->ready_lock, flags);
+       wake_up(&k->user->wait);
 }
 
-void kevent_requeue(struct kevent *k)
+
+/*
+ * It is called 
+ */
+int kevent_requeue(struct kevent *k)
 {
+       int err;
        unsigned long flags;
        
-       spin_lock_irqsave(&k->st->lock, flags);
-       __kevent_requeue(k, 0);
-       spin_unlock_irqrestore(&k->st->lock, flags);
+       err = kevent_callback(k);
+
+       if (err) {
+               spin_lock_irqsave(&k->st->lock, flags);
+               __kevent_requeue(k, 0);
+               spin_unlock_irqrestore(&k->st->lock, flags);
+       }
+       return err;
 }
 
 /*
@@ -194,14 +208,26 @@ void kevent_requeue(struct kevent *k)
 void kevent_storage_ready(struct kevent_storage *st, kevent_callback_t 
ready_callback, u32 event)
 {
        struct kevent *k, *n;
+       unsigned long flags;
+       int err;
 
        spin_lock(&st->lock);
        list_for_each_entry_safe(k, n, &st->list, storage_entry) {
+               spin_lock_irqsave(&k->user->ready_lock, flags);
+               if (k->ready_entry.next != LIST_POISON1) {
+                       spin_unlock_irqrestore(&k->user->ready_lock, flags);
+                       continue;
+               }
+               spin_unlock_irqrestore(&k->user->ready_lock, flags);
+
                if (ready_callback)
                        ready_callback(k);
 
-               if (event & k->event.event)
-                       __kevent_requeue(k, event);
+               if (event & k->event.event) {
+                       err = kevent_callback(k);
+                       if (err)
+                               __kevent_requeue(k, event);
+               }
        }
        spin_unlock(&st->lock);
 }
@@ -235,7 +261,6 @@ struct kevent *kevent_alloc(gfp_t mask)
 void kevent_free(struct kevent *k)
 {
        memset(k, 0xab, sizeof(struct kevent));
-
        if (kevent_cache)
                kmem_cache_free(kevent_cache, k);
        else
diff --git a/kernel/kevent/kevent_aio.c b/kernel/kevent/kevent_aio.c
index 3f76803..cfd8a16 100644
--- a/kernel/kevent/kevent_aio.c
+++ b/kernel/kevent/kevent_aio.c
@@ -25,18 +25,29 @@
 #include <linux/spinlock.h>
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/swap.h>
 #include <linux/pagemap.h>
 #include <linux/bio.h>
 #include <linux/buffer_head.h>
 #include <linux/kevent.h>
 
+//#define KEVENT_AIO_DEBUG
+
+#ifdef KEVENT_AIO_DEBUG
+#define dprintk(f, a...) printk(f, ##a)
+#else
+#define dprintk(f, a...) do {} while (0)
+#endif
+
 struct kevent_aio_private
 {
        struct page             **pages;
+       int                     pg_first;
        int                     pg_num;
        int                     bio_num;
        size_t                  size;
        loff_t                  offset;
+       struct file             *file;
 };
 
 extern void bio_fs_destructor(struct bio *bio);
@@ -44,6 +55,7 @@ extern void bio_fs_destructor(struct bio
 static void kevent_aio_bio_destructor(struct bio *bio)
 {
        struct inode *inode = bio->bi_private;
+       dprintk("%s: bio=%p, num=%u, inode=%p.\n", __func__, bio, bio->bi_vcnt, 
inode);
        kevent_storage_ready(&inode->st, NULL, KEVENT_AIO_BIO);
        bio_fs_destructor(bio);
 }
@@ -78,6 +90,7 @@ static inline struct bio *kevent_mpage_b
 {
        if (bio) {
                bio->bi_end_io = kevent_mpage_end_io_read;
+               dprintk("%s: bio=%p, num=%u.\n", __func__, bio, bio->bi_vcnt);
                submit_bio(READ, bio);
        }
        return NULL;
@@ -107,7 +120,7 @@ static struct bio *kevent_mpage_readpage
                bh.b_state = 0;
                if (block_in_file < last_block) {
                        if (get_block(inode, block_in_file, &bh, 0)) {
-                               printk("%s: confused: get_block failed: 
page_block=%u.\n", __func__, page_block);
+                               dprintk("%s: confused: get_block failed: 
page_block=%u.\n", __func__, page_block);
                                goto confused;
                        }
                }
@@ -132,14 +145,14 @@ static struct bio *kevent_mpage_readpage
                }
        
                if (first_hole != blocks_per_page) {
-                       printk("%s: confused: page_block=%u, first_hole=%u, 
blocks_per_page=%u.\n", 
+                       dprintk("%s: confused: page_block=%u, first_hole=%u, 
blocks_per_page=%u.\n", 
                                        __func__, page_block, first_hole, 
blocks_per_page);
                        goto confused;          /* hole -> non-hole */
                }
 
                /* Contiguous blocks? */
                if (page_block && blocks[page_block-1] != bh.b_blocknr-1) {
-                       printk("%s: confused: page_block=%u, blocks=%Lu, 
bh.b_blocknr=%Lu.\n",
+                       dprintk("%s: confused: page_block=%u, blocks=%Lu, 
bh.b_blocknr=%Lu.\n",
                                        __func__, page_block, 
blocks[page_block-1], bh.b_blocknr-1);
                        goto confused;
                }
@@ -188,14 +201,14 @@ alloc_new:
        length = first_hole << blkbits;
        if (bio_add_page(bio, page, length, 0) < length) {
                bio = kevent_mpage_bio_submit(READ, bio);
-               printk("%s: Failed to add a page: nr_pages=%d, length=%d, 
page=%p.\n", __func__, nr_pages, length, page);
+               dprintk("%s: Failed to add a page: nr_pages=%d, length=%d, 
page=%p.\n", __func__, nr_pages, length, page);
                goto alloc_new;
        }
-#if 0
-       printk("%s: bio=%p, b=%d, m=%d, u=%d, nr_pages=%d, offset=%Lu, 
size=%Lu. page_block=%u, page=%p.\n", 
+       
+       dprintk("%s: bio=%p, b=%d, m=%d, u=%d, nr_pages=%d, offset=%Lu, 
size=%Lu. page_block=%u, page=%p.\n", 
                        __func__, bio, buffer_boundary(&bh), 
buffer_mapped(&bh), buffer_uptodate(&bh),
                        nr_pages, *offset, i_size_read(inode), page_block, 
page);
-#endif 
+       
        *offset = *offset + length;
 
        if (buffer_boundary(&bh) || (first_hole != blocks_per_page))
@@ -207,6 +220,7 @@ out:
        return bio;
 
 confused:
+       dprintk("%s: confused. bio=%p.\n", __func__, bio);
        if (bio)
                bio = kevent_mpage_bio_submit(READ, bio);
        goto out;
@@ -222,6 +236,7 @@ static int kevent_mpage_readpages(struct
        for (i=0; i<nr_pages; ++i) {
                struct page *page = pages[i];
 
+               ClearPageUptodate(page);
                bio = kevent_mpage_readpage(bio, inode, page, nr_pages-i, 
get_block, offset, &last_block_in_bio, bio_num);
        }
 
@@ -231,6 +246,83 @@ static int kevent_mpage_readpages(struct
        return 0;
 }
 
+static int kevent_aio_vfs_read(struct kevent *k)
+{
+       struct kevent_aio_private *priv = k->priv;
+       struct address_space *mapping;
+       unsigned int size = k->event.id.raw[1];
+       size_t isize;
+       int i;
+       
+       mapping = priv->file->f_mapping;
+       isize = i_size_read(priv->file->f_dentry->d_inode);
+       
+       dprintk("%s: start size=%u, offset=%Lu, isize=%zu, pg_num=%d.\n", 
__func__, size, priv->offset, isize, priv->pg_num);
+
+       for (i=0; i<priv->pg_num; ++i) {
+               struct page *page;
+               struct page *upage = priv->pages[i];
+               unsigned long nr = PAGE_CACHE_SIZE;
+               void *kptr, *uptr;
+
+               cond_resched();
+               page = find_get_page(mapping, priv->offset >> PAGE_CACHE_SHIFT);
+               if (unlikely(page == NULL)) {
+                       break;
+               }
+               if (!PageUptodate(page)) {
+                       page_cache_release(page);
+                       break;
+               }
+
+               if (mapping_writably_mapped(mapping))
+                       flush_dcache_page(page);
+
+               mark_page_accessed(page);
+
+               kptr = kmap_atomic(page, KM_USER0);
+               if (!kptr) {
+                       page_cache_release(page);
+                       break;
+               }
+               uptr = kmap_atomic(upage, KM_USER1);
+               if (!uptr) {
+                       page_cache_release(page);
+                       kunmap_atomic(kptr, KM_USER0);
+                       break;
+               }
+
+               if (nr + priv->offset > isize)
+                       nr = isize - priv->offset;
+               if (nr > size)
+                       nr = size;
+
+               memcpy(uptr, kptr, nr);
+
+               kunmap_atomic(uptr, KM_USER1);
+               kunmap_atomic(kptr, KM_USER0);
+
+               page_cache_release(page);
+               SetPageUptodate(upage);
+
+               priv->offset += nr;
+               priv->pg_first = i+1;
+               size -= nr;
+
+               if (priv->offset >= isize || !size)
+                       break;
+       }
+
+       dprintk("%s: end first=%d, num=%d, left=%u, offset=%Lu.\n", __func__, 
priv->pg_first, priv->pg_num, size, priv->offset);
+
+       k->event.id.raw[1] = size;
+
+       if (priv->offset >= isize || !size)
+               i = priv->pg_num;
+
+       return i;
+}
+
 static int kevent_aio_callback(struct kevent *k)
 {
        struct kevent_aio_private *priv = k->priv;
@@ -238,7 +330,18 @@ static int kevent_aio_callback(struct ke
        size_t size;
 
        BUG_ON(!priv);
+       BUG_ON(!priv->pages);
        
+       dprintk("%s: k=%p, priv=%p, num=%u, bio_num=%u, first=%u, size=%zu, 
off=%Lu.\n", 
+                       __func__, k, priv, priv->pg_num, priv->bio_num, 
priv->pg_first, priv->size, priv->offset);
+
+       if (!priv->bio_num) {
+               ready = kevent_aio_vfs_read(k);
+               if (ready > 0 && ready != priv->pg_num)
+                       ready = 0;
+               goto out;
+       }
+
        size = priv->size;
 
        for (i=0; i<priv->pg_num && ready > 0; ++i) {
@@ -248,21 +351,35 @@ static int kevent_aio_callback(struct ke
                        ready = -1;
                else if (!PageUptodate(page))
                        ready = 0;
-               else
-                       size -= PAGE_SIZE;
+               else {
+                       if (size < PAGE_SIZE)
+                               size = 0;
+                       else
+                               size -= PAGE_SIZE;
+               }
        }
 
        if (ready)
                k->event.id.raw[1] = size;
 
+out:
+       dprintk("%s: ready=%d, left=%u, size=%zu.\n", __func__, ready, 
k->event.id.raw[1], priv->size);
+
+       if (ready) {
+               priv->bio_num = 0;
+       }
+       
        return ready;
 }
 
 int ext3_get_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create);
 
+static unsigned int prev_offset;
+
 static int kevent_aio_enqueue(struct kevent *k)
 {
+       struct kevent *nk;
        int err, i;
        unsigned long addr = (unsigned long)k->event.ptr;
        unsigned int size = k->event.id.raw[1];
@@ -272,9 +389,17 @@ static int kevent_aio_enqueue(struct kev
        struct inode *inode;
        struct kevent_aio_private *priv;
 
+       if (prev_offset != k->event.ret_data[1]) {
+               prev_offset = k->event.ret_data[1];
+       } 
+#ifdef KEVENT_AIO_DEBUG
+       else if (printk_ratelimit())
+               dprintk(KERN_INFO "%s: k=%p, prev_offset=%u, off=%u, 
size=%u.\n", __func__, k, prev_offset, k->event.ret_data[1], size);
+#endif
+
        if ((addr & PAGE_MASK) != addr)
                return -EINVAL;
-
+       
        file = fget_light(k->event.id.raw[0], &fput_needed);
        if (!file)
                return -ENODEV;
@@ -300,28 +425,47 @@ static int kevent_aio_enqueue(struct kev
        if (err <= 0)
                goto err_out_free;
        num = err;
-       
+
        priv->pg_num = num;
        priv->size = size;
        priv->bio_num = 0;
-       priv->offset = 0;
-       
+       priv->offset = k->event.ret_data[1];
+       priv->file = file;
        k->priv = priv;
+       
+       err = k->callback(k);
+       
+       if ((k->event.req_flags & KEVENT_REQ_ENQUEUE) || !err) {
+               nk = kevent_recreate(k, GFP_KERNEL);
+               if (!nk) {
+                       err = -ENOMEM;
+                       goto err_out_release;
+               }
+
+               dprintk("%s: k=%p, priv=%p, num=%u, ready_num=%d, size=%zu, 
off=%Lu.\n", 
+                               __func__, nk, priv, priv->pg_num, 
priv->pg_first, priv->size, priv->offset);
+
+               num -= priv->pg_first;
 
-       kevent_storage_enqueue(&inode->st, k);
+               kevent_storage_enqueue(&inode->st, nk);
 
-       err = kevent_mpage_readpages(inode, priv->pages, num, &ext3_get_block, 
&priv->offset, &priv->bio_num);
-       if (err)
-               goto err_out_dequeue;
+               if (num) {
+                       err = kevent_mpage_readpages(inode, 
&priv->pages[priv->pg_first], num, &ext3_get_block, &priv->offset, 
&priv->bio_num);
+                       if (err && !(k->event.req_flags & KEVENT_REQ_ENQUEUE))
+                               goto err_out_dequeue;
+               }
+       }
 
        fput_light(file, fput_needed);
 
+       dprintk("%s: k=%p, returning %d.\n", __func__, k, err);
+       
        return err;
 
 err_out_dequeue:
-       kevent_storage_dequeue(k->st, k);
-       
-       for (i=0; i<num; ++i)
+       kevent_finish_user(nk, 0, 1);
+err_out_release:
+       for (i=0; i<priv->pg_num; ++i)
                page_cache_release(priv->pages[i]);
 err_out_free:
        kfree(priv);
@@ -330,6 +474,8 @@ err_out_iput:
 err_out_fput:
        fput_light(file, fput_needed);
 
+       k->event.id.raw[1] = size;
+
        return err;
 }
 
diff --git a/kernel/kevent/kevent_inode.c b/kernel/kevent/kevent_inode.c
index 3af0e11..ed6e0bc 100644
--- a/kernel/kevent/kevent_inode.c
+++ b/kernel/kevent/kevent_inode.c
@@ -46,14 +46,18 @@ static int kevent_inode_enqueue(struct k
        inode = igrab(file->f_dentry->d_inode);
        if (!inode)
                goto err_out_fput;
-
-       err = kevent_storage_enqueue(&inode->st, k);
-       if (err)
+       
+       k = kevent_recreate(k, GFP_KERNEL);
+       if (!k) {
+               err = -ENOMEM;
                goto err_out_iput;
+       }
+
+       kevent_storage_enqueue(&inode->st, k);
 
        fput_light(file, fput_needed);
        return 0;
-
+       
 err_out_iput:
        iput(inode);
 err_out_fput:
diff --git a/kernel/kevent/kevent_poll.c b/kernel/kevent/kevent_poll.c
index 7149770..0544ec8 100644
--- a/kernel/kevent/kevent_poll.c
+++ b/kernel/kevent/kevent_poll.c
@@ -54,14 +54,9 @@ static int kevent_poll_wait_callback(wai
        struct kevent_poll_wait_container *cont = container_of(wait, struct 
kevent_poll_wait_container, wait);
        struct kevent *k = cont->k;
        struct file *file = k->st->origin;
-       unsigned long flags;
-       u32 revents, event;
-
+       u32 revents;
+       
        revents = file->f_op->poll(file, NULL);
-       spin_lock_irqsave(&k->lock, flags);
-       event = k->event.event;
-       spin_unlock_irqrestore(&k->lock, flags);
-
        kevent_storage_ready(k->st, NULL, revents);
 
        return 0;
@@ -94,7 +89,7 @@ static void kevent_poll_qproc(struct fil
 static int kevent_poll_enqueue(struct kevent *k)
 {
        struct file *file;
-       int err, ready = 0;
+       int err;
        unsigned int revents;
        struct kevent_poll_ctl ctl;
        struct kevent_poll_private *priv;
@@ -115,20 +110,27 @@ static int kevent_poll_enqueue(struct ke
        spin_lock_init(&priv->container_lock);
        INIT_LIST_HEAD(&priv->container_list);
 
+       k = kevent_recreate(k, GFP_KERNEL);
+       if (!k) {
+               err = -ENOMEM;
+               goto err_out_free;
+       }
+
        k->priv = priv;
+       k->st = &file->st;
 
        ctl.k = k;
        init_poll_funcptr(&ctl.pt, &kevent_poll_qproc);
+       
+       kevent_storage_enqueue(&file->st, k);
 
        revents = file->f_op->poll(file, &ctl.pt);
        if (revents & k->event.event)
-               ready = 1;
+               err = 1;
+       else
+               err = 0;
 
-       err = kevent_storage_enqueue(&file->st, k);
-       if (err)
-               goto err_out_free;
-       
-       return ready;
+       return err;
 
 err_out_free:
        kmem_cache_free(kevent_poll_priv_cache, priv);
diff --git a/kernel/kevent/kevent_socket.c b/kernel/kevent/kevent_socket.c
index d3938a2..16ffc93 100644
--- a/kernel/kevent/kevent_socket.c
+++ b/kernel/kevent/kevent_socket.c
@@ -77,19 +77,24 @@ int kevent_socket_enqueue(struct kevent 
        if (!inode)
                goto err_out_fput;
 
-       err = kevent_storage_enqueue(&inode->st, k);
-       if (err)
+       k = kevent_recreate(k, GFP_KERNEL);
+       if (!k) {
+               err = -ENOMEM;
                goto err_out_iput;
+       }
+
+       kevent_storage_enqueue(&inode->st, k);
 
        err = k->callback(k);
        if (err)
-               goto err_out_dequeue;
+               goto err_out_free;
 
        fput_light(file, fput_needed);
-       return err;
+       return 0;
 
-err_out_dequeue:
+err_out_free:
        kevent_storage_dequeue(k->st, k);
+       kevent_finish_user(k, 1, 0);
 err_out_iput:
        iput(inode);
 err_out_fput:
diff --git a/kernel/kevent/kevent_timer.c b/kernel/kevent/kevent_timer.c
index 2f9291b..f678174 100644
--- a/kernel/kevent/kevent_timer.c
+++ b/kernel/kevent/kevent_timer.c
@@ -56,17 +56,19 @@ static int kevent_timer_enqueue(struct k
        err = kevent_storage_init(t, st);
        if (err)
                goto err_out_free;
+       
+       k = kevent_recreate(k, GFP_KERNEL);
+       if (!k) {
+               err = -ENOMEM;
+               goto err_out_free;
+       }
 
-       err = kevent_storage_enqueue(st, k);
-       if (err)
-               goto err_out_st_fini;
+       kevent_storage_enqueue(st, k);
        
        add_timer(t);
 
        return 0;
 
-err_out_st_fini:       
-       kevent_storage_fini(st);
 err_out_free:
        kfree(t);
 
diff --git a/kernel/kevent/kevent_user.c b/kernel/kevent/kevent_user.c
index 2f0a124..99fbf29 100644
--- a/kernel/kevent/kevent_user.c
+++ b/kernel/kevent/kevent_user.c
@@ -102,7 +102,6 @@ static struct kevent_user *kevent_user_a
        u->kevent_num = 0;
        
        init_MUTEX(&u->ctl_mutex);
-       init_MUTEX(&u->wait_mutex);
        init_waitqueue_head(&u->wait);
        u->max_ready_num = 0;
 
@@ -151,7 +150,7 @@ static inline unsigned int kevent_user_h
 #else
 static inline unsigned int kevent_user_hash(struct ukevent *uk)
 {
-       return jhash_1word(uk->id.raw[0], uk->id.raw[1]) & KEVENT_HASH_MASK;
+       return jhash_1word(uk->id.raw[0], 0) & KEVENT_HASH_MASK;
 }
 #endif
 
@@ -160,7 +159,7 @@ static inline unsigned int kevent_user_h
  * dequeue it from storage and decrease user's reference counter,
  * since this kevent does not exist anymore. That is why it is freed here.
  */
-static void kevent_finish_user(struct kevent *k, int lock, int deq)
+void kevent_finish_user(struct kevent *k, int lock, int deq)
 {
        struct kevent_user *u = k->user;
        unsigned long flags;
@@ -189,7 +188,9 @@ static void kevent_finish_user(struct ke
        spin_unlock_irqrestore(&u->ready_lock, flags);
        
        kevent_user_put(u);
-       kevent_free(k);
+
+       if (!(k->event.ret_flags & KEVENT_RET_STACK))
+               kevent_free(k);
 }
 
 /*
@@ -228,8 +229,12 @@ static struct kevent *__kevent_search(st
        
        list_for_each_entry(k, &l->kevent_list, kevent_entry) {
                spin_lock(&k->lock);
+#if 0
                if (k->event.user[0] == uk->user[0] && k->event.user[1] == 
uk->user[1] &&
                                k->event.id.raw[0] == uk->id.raw[0] && 
k->event.id.raw[1] == uk->id.raw[1]) {
+#else
+               if (k->event.id.raw[0] == uk->id.raw[0]) {
+#endif
                        found = 1;
                        spin_unlock(&k->lock);
                        break;
@@ -247,20 +252,21 @@ static int kevent_modify(struct ukevent 
        struct kevent_list *l = &u->kqueue[hash];
        int err = -ENODEV;
        unsigned long flags;
-       
+
        spin_lock_irqsave(&l->kevent_lock, flags);
        k = __kevent_search(l, uk, u);
+       spin_unlock_irqrestore(&l->kevent_lock, flags);
+
        if (k) {
                spin_lock(&k->lock);
-               k->event.event = uk->event;
-               k->event.req_flags = uk->req_flags;
+               memcpy(&k->event, uk, sizeof(struct ukevent));
                k->event.ret_flags = 0;
                spin_unlock(&k->lock);
-               kevent_requeue(k);
-               err = 0;
+               err = kevent_requeue(k);
+               if (err)
+                       memcpy(uk, &k->event, sizeof(struct ukevent));
        }
-       spin_unlock_irqrestore(&l->kevent_lock, flags);
-       
+
        return err;
 }
 
@@ -274,11 +280,11 @@ static int kevent_remove(struct ukevent 
 
        spin_lock_irqsave(&l->kevent_lock, flags);
        k = __kevent_search(l, uk, u);
+       spin_unlock_irqrestore(&l->kevent_lock, flags);
        if (k) {
-               kevent_finish_user(k, 0, 1);
+               kevent_finish_user(k, 1, 1);
                err = 0;
        }
-       spin_unlock_irqrestore(&l->kevent_lock, flags);
 
        return err;
 }
@@ -293,12 +299,14 @@ static int kevent_user_release(struct in
        struct kevent *k, *n;
        int i;
 
+       down(&u->ctl_mutex);
        for (i=0; i<KEVENT_HASH_MASK+1; ++i) {
                struct kevent_list *l = &u->kqueue[i];
                
                list_for_each_entry_safe(k, n, &l->kevent_list, kevent_entry)
                        kevent_finish_user(k, 1, 1);
        }
+       up(&u->ctl_mutex);
 
        kevent_user_put(u);
        file->private_data = NULL;
@@ -320,9 +328,11 @@ static int kevent_user_ctl_modify(struct
                        break;
                }
 
-               if (kevent_modify(&uk, u))
+               err = kevent_modify(&uk, u);
+               if (err)
+                       uk.ret_flags |= KEVENT_RET_DONE;
+               if (unlikely(err < 0))
                        uk.ret_flags |= KEVENT_RET_BROKEN;
-               uk.ret_flags |= KEVENT_RET_DONE;
 
                if (copy_to_user(arg, &uk, sizeof(struct ukevent))) {
                        err = -EINVAL;
@@ -369,52 +379,72 @@ static int kevent_user_ctl_remove(struct
        return err;
 }
 
-int kevent_user_add_ukevent(struct ukevent *uk, struct kevent_user *u)
+struct kevent *kevent_recreate(struct kevent *kevent, gfp_t mask)
 {
        struct kevent *k;
+       unsigned long flags;
+       unsigned int hash = kevent_user_hash(&kevent->event);
+       struct kevent_list *l = &kevent->user->kqueue[hash];
+
+       k = kevent;
+       if (kevent->event.ret_flags & KEVENT_RET_STACK) {
+               k = kevent_alloc(mask);
+               if (!k)
+                       return NULL;
+               memcpy(k, kevent, sizeof(struct kevent));
+               k->event.ret_flags &= ~KEVENT_RET_STACK;
+       } else if (!(k->event.req_flags & KEVENT_REQ_ENQUEUE))
+               return k;
+
+       spin_lock_irqsave(&l->kevent_lock, flags);
+       list_add_tail(&k->kevent_entry, &l->kevent_list);
+       k->user->kevent_num++;
+       kevent_user_get(k->user);
+       spin_unlock_irqrestore(&l->kevent_lock, flags);
+       
+       return k;
+}
+
+int kevent_user_add_ukevent(struct ukevent *uk, struct kevent_user *u)
+{
+       struct kevent *k, kev;
        int err;
 
-       k = kevent_alloc(GFP_KERNEL);
-       if (!k) {
-               err = -ENOMEM;
-               goto err_out_exit;
+       k = &kev;
+
+       uk->ret_flags = KEVENT_RET_STACK;
+       uk->ret_data[0] = 0;
+       
+       if (uk->req_flags & KEVENT_REQ_ENQUEUE) {
+               uk->req_flags &= ~KEVENT_REQ_ONESHOT;
+               uk->ret_flags = 0;
+
+               k = kevent_alloc(GFP_KERNEL);
+               if (!k)
+                       return -ENOMEM;
        }
 
-       memcpy(&k->event, uk, sizeof(struct ukevent));
+       memset(k, 0, sizeof(struct kevent));
 
-       k->event.ret_flags = 0;
-       k->event.ret_data[0] = 0;
-       k->event.ret_data[1] = 0;
+       memcpy(&k->event, uk, sizeof(struct ukevent));
 
        err = kevent_init(k);
        if (err) {
-               kevent_free(k);
+               if (uk->req_flags & KEVENT_REQ_ENQUEUE)
+                       kevent_free(k);
                goto err_out_exit;
        }
        k->user = u;
 #ifdef CONFIG_KEVENT_USER_STAT
        u->total++;
 #endif
-       {
-               unsigned long flags;
-               unsigned int hash = kevent_user_hash(&k->event);
-               struct kevent_list *l = &u->kqueue[hash];
-               
-               spin_lock_irqsave(&l->kevent_lock, flags);
-               list_add_tail(&k->kevent_entry, &l->kevent_list);
-               u->kevent_num++;
-               kevent_user_get(u);
-               spin_unlock_irqrestore(&l->kevent_lock, flags);
-       }
-
        err = kevent_enqueue(k);
        if (err) {
                memcpy(uk, &k->event, sizeof(struct ukevent));
                if (err < 0)
                        uk->ret_flags |= KEVENT_RET_BROKEN;
                uk->ret_flags |= KEVENT_RET_DONE;
-               kevent_finish_user(k, 1, 0);
-       } 
+       }
 
 err_out_exit:
        return err;
@@ -440,10 +470,14 @@ static int kevent_user_ctl_add(struct ke
 
        orig = arg;
        ctl_addr = arg - sizeof(struct kevent_user_control);
-#if 1
+#if 0
        err = -ENFILE;
-       if (u->kevent_num + ctl->num >= 1024)
+       if (u->kevent_num + ctl->num >= 10240) {
+#ifdef CONFIG_KEVENT_USER_STAT
+               u->enfile++;
+#endif
                goto err_out_remove;
+       }
 #endif
        for (i=0; i<ctl->num; ++i) {
                if (copy_from_user(&uk, arg, sizeof(struct ukevent))) {
@@ -493,17 +527,21 @@ static int kevent_user_wait(struct file 
        int cerr = 0, num = 0;
        void __user *ptr = arg + sizeof(struct kevent_user_control);
 
-       if (down_interruptible(&u->ctl_mutex))
-               return -ERESTARTSYS;
-
        if (!(file->f_flags & O_NONBLOCK)) {
-               if (ctl->timeout)
+               if (ctl->timeout) {
                        wait_event_interruptible_timeout(u->wait, 
                                        u->ready_num >= ctl->num, 
msecs_to_jiffies(ctl->timeout));
-               else
+                       //printk("%s: 1 timeout=%u, ready_num=%u, 
ctl->num=%u.\n", __func__, ctl->timeout, u->ready_num, ctl->num);
+               } else {
                        wait_event_interruptible_timeout(u->wait, 
                                        u->ready_num > 0, 
msecs_to_jiffies(1000));
+                       //printk("%s: 2 timeout=%u, ready_num=%u, 
ctl->num=%u.\n", __func__, 1000, u->ready_num, ctl->num);
+               }
        }
+
+       if (down_interruptible(&u->ctl_mutex))
+               return -ERESTARTSYS;
+
        while (num < ctl->num && ((k = kqueue_dequeue_ready(u)) != NULL)) {
                if (copy_to_user(ptr + num*sizeof(struct ukevent), &k->event, 
sizeof(struct ukevent)))
                        cerr = -EINVAL;


-- 
        Evgeniy Polyakov
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to