]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/9p/trans_fd.c
9p-trans_fd: use single poller
[linux-2.6-omap-h63xx.git] / net / 9p / trans_fd.c
index 6dabbdb666510fcfc570a67e3f24cf598429e080..f84592345573ff6086d27c8f366a467fec4311ef 100644 (file)
@@ -44,7 +44,6 @@
 #define P9_PORT 564
 #define MAX_SOCK_BUF (64*1024)
 #define ERREQFLUSH     1
-#define SCHED_TIMEOUT  10
 #define MAXPOLLWADDR   2
 
 /**
@@ -135,17 +134,16 @@ struct p9_req {
        struct list_head req_list;
 };
 
-struct p9_mux_poll_task {
-       struct task_struct *task;
-       struct list_head mux_list;
-       int muxnum;
+struct p9_poll_wait {
+       struct p9_conn *conn;
+       wait_queue_t wait;
+       wait_queue_head_t *wait_addr;
 };
 
 /**
  * struct p9_conn - fd mux connection state information
  * @lock: protects mux_list (?)
  * @mux_list: list link for mux to manage multiple connections (?)
- * @poll_task: task polling on this connection
  * @msize: maximum size for connection (dup)
  * @extended: 9p2000.u flag (dup)
  * @trans: reference to transport instance for this connection
@@ -171,7 +169,6 @@ struct p9_mux_poll_task {
 struct p9_conn {
        spinlock_t lock; /* protect lock structure */
        struct list_head mux_list;
-       struct p9_mux_poll_task *poll_task;
        int msize;
        unsigned char extended;
        struct p9_trans *trans;
@@ -185,8 +182,8 @@ struct p9_conn {
        int wpos;
        int wsize;
        char *wbuf;
-       wait_queue_t poll_wait[MAXPOLLWADDR];
-       wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
+       struct list_head poll_pending_link;
+       struct p9_poll_wait poll_wait[MAXPOLLWADDR];
        poll_table pt;
        struct work_struct rq;
        struct work_struct wq;
@@ -220,12 +217,10 @@ static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
 static int p9_fd_write(struct p9_trans *trans, void *v, int len);
 static int p9_fd_read(struct p9_trans *trans, void *v, int len);
 
-static DEFINE_MUTEX(p9_mux_task_lock);
+static DEFINE_SPINLOCK(p9_poll_lock);
+static LIST_HEAD(p9_poll_pending_list);
 static struct workqueue_struct *p9_mux_wq;
-
-static int p9_mux_num;
-static int p9_mux_poll_task_num;
-static struct p9_mux_poll_task p9_mux_poll_tasks[100];
+static struct task_struct *p9_poll_task;
 
 static void p9_conn_destroy(struct p9_conn *);
 static unsigned int p9_fd_poll(struct p9_trans *trans,
@@ -255,130 +250,23 @@ static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
                p9_idpool_put(tag, m->tagpool);
 }
 
-/**
- * p9_mux_calc_poll_procs - calculates the number of polling procs
- * @muxnum: number of mounts
- *
- * Calculation is based on the number of mounted v9fs filesystems.
- * The current implementation returns sqrt of the number of mounts.
- */
-
-static int p9_mux_calc_poll_procs(int muxnum)
-{
-       int n;
-
-       if (p9_mux_poll_task_num)
-               n = muxnum / p9_mux_poll_task_num +
-                   (muxnum % p9_mux_poll_task_num ? 1 : 0);
-       else
-               n = 1;
-
-       if (n > ARRAY_SIZE(p9_mux_poll_tasks))
-               n = ARRAY_SIZE(p9_mux_poll_tasks);
-
-       return n;
-}
-
-static int p9_mux_poll_start(struct p9_conn *m)
+static void p9_mux_poll_stop(struct p9_conn *m)
 {
-       int i, n;
-       struct p9_mux_poll_task *vpt, *vptlast;
-       struct task_struct *pproc;
-
-       P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
-               p9_mux_poll_task_num);
-       mutex_lock(&p9_mux_task_lock);
-
-       n = p9_mux_calc_poll_procs(p9_mux_num + 1);
-       if (n > p9_mux_poll_task_num) {
-               for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
-                       if (p9_mux_poll_tasks[i].task == NULL) {
-                               vpt = &p9_mux_poll_tasks[i];
-                               P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
-                                                                       vpt);
-                               pproc = kthread_create(p9_poll_proc, vpt,
-                                                               "v9fs-poll");
-
-                               if (!IS_ERR(pproc)) {
-                                       vpt->task = pproc;
-                                       INIT_LIST_HEAD(&vpt->mux_list);
-                                       vpt->muxnum = 0;
-                                       p9_mux_poll_task_num++;
-                                       wake_up_process(vpt->task);
-                               }
-                               break;
-                       }
-               }
-
-               if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
-                       P9_DPRINTK(P9_DEBUG_ERROR,
-                                       "warning: no free poll slots\n");
-       }
+       unsigned long flags;
+       int i;
 
-       n = (p9_mux_num + 1) / p9_mux_poll_task_num +
-           ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
-
-       vptlast = NULL;
-       for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
-               vpt = &p9_mux_poll_tasks[i];
-               if (vpt->task != NULL) {
-                       vptlast = vpt;
-                       if (vpt->muxnum < n) {
-                               P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
-                               list_add(&m->mux_list, &vpt->mux_list);
-                               vpt->muxnum++;
-                               m->poll_task = vpt;
-                               memset(&m->poll_waddr, 0,
-                                                       sizeof(m->poll_waddr));
-                               init_poll_funcptr(&m->pt, p9_pollwait);
-                               break;
-                       }
-               }
-       }
+       for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
+               struct p9_poll_wait *pwait = &m->poll_wait[i];
 
-       if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
-               if (vptlast == NULL) {
-                       mutex_unlock(&p9_mux_task_lock);
-                       return -ENOMEM;
+               if (pwait->wait_addr) {
+                       remove_wait_queue(pwait->wait_addr, &pwait->wait);
+                       pwait->wait_addr = NULL;
                }
-
-               P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
-               list_add(&m->mux_list, &vptlast->mux_list);
-               vptlast->muxnum++;
-               m->poll_task = vptlast;
-               memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
-               init_poll_funcptr(&m->pt, p9_pollwait);
        }
 
-       p9_mux_num++;
-       mutex_unlock(&p9_mux_task_lock);
-
-       return 0;
-}
-
-static void p9_mux_poll_stop(struct p9_conn *m)
-{
-       int i;
-       struct p9_mux_poll_task *vpt;
-
-       mutex_lock(&p9_mux_task_lock);
-       vpt = m->poll_task;
-       list_del(&m->mux_list);
-       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
-               if (m->poll_waddr[i] != NULL) {
-                       remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
-                       m->poll_waddr[i] = NULL;
-               }
-       }
-       vpt->muxnum--;
-       if (!vpt->muxnum) {
-               P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
-               kthread_stop(vpt->task);
-               vpt->task = NULL;
-               p9_mux_poll_task_num--;
-       }
-       p9_mux_num--;
-       mutex_unlock(&p9_mux_task_lock);
+       spin_lock_irqsave(&p9_poll_lock, flags);
+       list_del_init(&m->poll_pending_link);
+       spin_unlock_irqrestore(&p9_poll_lock, flags);
 }
 
 /**
@@ -414,11 +302,8 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans)
        INIT_LIST_HEAD(&m->unsent_req_list);
        INIT_WORK(&m->rq, p9_read_work);
        INIT_WORK(&m->wq, p9_write_work);
-       n = p9_mux_poll_start(m);
-       if (n) {
-               kfree(m);
-               return ERR_PTR(n);
-       }
+       INIT_LIST_HEAD(&m->poll_pending_link);
+       init_poll_funcptr(&m->pt, p9_pollwait);
 
        n = p9_fd_poll(trans, &m->pt);
        if (n & POLLIN) {
@@ -431,11 +316,12 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans)
                set_bit(Wpending, &m->wsched);
        }
 
-       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
-               if (IS_ERR(m->poll_waddr[i])) {
+       for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
+               if (IS_ERR(m->poll_wait[i].wait_addr)) {
                        p9_mux_poll_stop(m);
                        kfree(m);
-                       return (void *)m->poll_waddr;   /* the error code */
+                       /* return the error code */
+                       return (void *)m->poll_wait[i].wait_addr;
                }
        }
 
@@ -464,6 +350,23 @@ static void p9_conn_destroy(struct p9_conn *m)
        kfree(m);
 }
 
+static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       struct p9_poll_wait *pwait =
+               container_of(wait, struct p9_poll_wait, wait);
+       struct p9_conn *m = pwait->conn;
+       unsigned long flags;
+       DECLARE_WAITQUEUE(dummy_wait, p9_poll_task);
+
+       spin_lock_irqsave(&p9_poll_lock, flags);
+       if (list_empty(&m->poll_pending_link))
+               list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
+       spin_unlock_irqrestore(&p9_poll_lock, flags);
+
+       /* perform the default wake up operation */
+       return default_wake_function(&dummy_wait, mode, sync, key);
+}
+
 /**
  * p9_pollwait - add poll task to the wait queue
  * @filp: file pointer being polled
@@ -476,29 +379,32 @@ static void p9_conn_destroy(struct p9_conn *m)
 static void
 p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)
 {
+       struct p9_conn *m = container_of(p, struct p9_conn, pt);
+       struct p9_poll_wait *pwait = NULL;
        int i;
-       struct p9_conn *m;
 
-       m = container_of(p, struct p9_conn, pt);
-       for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
-               if (m->poll_waddr[i] == NULL)
+       for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) {
+               if (m->poll_wait[i].wait_addr == NULL) {
+                       pwait = &m->poll_wait[i];
                        break;
+               }
+       }
 
-       if (i >= ARRAY_SIZE(m->poll_waddr)) {
+       if (!pwait) {
                P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
                return;
        }
 
-       m->poll_waddr[i] = wait_address;
-
        if (!wait_address) {
                P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
-               m->poll_waddr[i] = ERR_PTR(-EIO);
+               pwait->wait_addr = ERR_PTR(-EIO);
                return;
        }
 
-       init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
-       add_wait_queue(wait_address, &m->poll_wait[i]);
+       pwait->conn = m;
+       pwait->wait_addr = wait_address;
+       init_waitqueue_func_entry(&pwait->wait, p9_pollwake);
+       add_wait_queue(wait_address, &pwait->wait);
 }
 
 /**
@@ -553,23 +459,34 @@ static void p9_poll_mux(struct p9_conn *m)
 
 static int p9_poll_proc(void *a)
 {
-       struct p9_conn *m, *mtmp;
-       struct p9_mux_poll_task *vpt;
+       unsigned long flags;
 
-       vpt = a;
-       P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
+       P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current);
+ repeat:
+       spin_lock_irqsave(&p9_poll_lock, flags);
+       while (!list_empty(&p9_poll_pending_list)) {
+               struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
+                                                       struct p9_conn,
+                                                       poll_pending_link);
+               list_del_init(&conn->poll_pending_link);
+               spin_unlock_irqrestore(&p9_poll_lock, flags);
 
-               list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
-                       p9_poll_mux(m);
-               }
+               p9_poll_mux(conn);
 
-               P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
-               schedule_timeout(SCHED_TIMEOUT * HZ);
+               spin_lock_irqsave(&p9_poll_lock, flags);
        }
+       spin_unlock_irqrestore(&p9_poll_lock, flags);
 
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (list_empty(&p9_poll_pending_list)) {
+               P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
+               schedule();
+       }
        __set_current_state(TASK_RUNNING);
+
+       if (!kthread_should_stop())
+               goto repeat;
+
        P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
        return 0;
 }
@@ -1602,17 +1519,19 @@ static struct p9_trans_module p9_fd_trans = {
 
 int p9_trans_fd_init(void)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
-               p9_mux_poll_tasks[i].task = NULL;
-
        p9_mux_wq = create_workqueue("v9fs");
        if (!p9_mux_wq) {
                printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
                return -ENOMEM;
        }
 
+       p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll");
+       if (IS_ERR(p9_poll_task)) {
+               destroy_workqueue(p9_mux_wq);
+               printk(KERN_WARNING "v9fs: mux: creating poll task failed\n");
+               return PTR_ERR(p9_poll_task);
+       }
+
        v9fs_register_trans(&p9_tcp_trans);
        v9fs_register_trans(&p9_unix_trans);
        v9fs_register_trans(&p9_fd_trans);
@@ -1622,6 +1541,7 @@ int p9_trans_fd_init(void)
 
 void p9_trans_fd_exit(void)
 {
+       kthread_stop(p9_poll_task);
        v9fs_unregister_trans(&p9_tcp_trans);
        v9fs_unregister_trans(&p9_unix_trans);
        v9fs_unregister_trans(&p9_fd_trans);