Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=d9664c95afe5baa92ea56eff6a1c18e7b7a2cbe7
Commit:     d9664c95afe5baa92ea56eff6a1c18e7b7a2cbe7
Parent:     fe71b5f3871af2c281a08acd4bedd2da25e46bc3
Author:     Jan Harkes <[EMAIL PROTECTED]>
AuthorDate: Thu Jul 19 01:48:46 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Thu Jul 19 10:04:48 2007 -0700

    coda: block signals during upcall processing
    
    We ignore signals for about 30 seconds to give userspace a chance to see the
    upcall.  As we did not block signals we ended up in a busy loop for the
    remainder of the period when a signal is received.
    
    Signed-off-by: Jan Harkes <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 fs/coda/upcall.c           |   81 ++++++++++++++++++++++++++++++++-----------
 include/linux/coda_psdev.h |    1 -
 2 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 44332ef..ad65ee0 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -638,42 +638,83 @@ int venus_statfs(struct dentry *dentry, struct kstatfs 
*sfs)
 
 /*
  * coda_upcall and coda_downcall routines.
- * 
  */
+static void block_signals(sigset_t *old)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       *old = current->blocked;
+
+       sigfillset(&current->blocked);
+       sigdelset(&current->blocked, SIGKILL);
+       sigdelset(&current->blocked, SIGSTOP);
+       sigdelset(&current->blocked, SIGINT);
+
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+static void unblock_signals(sigset_t *old)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       current->blocked = *old;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+/* Don't allow signals to interrupt the following upcalls before venus
+ * has seen them,
+ * - CODA_CLOSE or CODA_RELEASE upcall  (to avoid reference count problems)
+ * - CODA_STORE                                (to avoid data loss)
+ */
+#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
+                              (((r)->uc_opcode != CODA_CLOSE && \
+                                (r)->uc_opcode != CODA_STORE && \
+                                (r)->uc_opcode != CODA_RELEASE) || \
+                               (r)->uc_flags & REQ_READ))
 
-static inline void coda_waitfor_upcall(struct upc_req *vmp)
+static inline void coda_waitfor_upcall(struct upc_req *req)
 {
        DECLARE_WAITQUEUE(wait, current);
+       unsigned long timeout = jiffies + coda_timeout * HZ;
+       sigset_t old;
+       int blocked;
 
-       vmp->uc_posttime = jiffies;
+       block_signals(&old);
+       blocked = 1;
 
-       add_wait_queue(&vmp->uc_sleep, &wait);
+       add_wait_queue(&req->uc_sleep, &wait);
        for (;;) {
-               if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 
+               if (CODA_INTERRUPTIBLE(req))
                        set_current_state(TASK_INTERRUPTIBLE);
                else
                        set_current_state(TASK_UNINTERRUPTIBLE);
 
                /* got a reply */
-               if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
+               if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
                        break;
 
-               if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && 
signal_pending(current) ) {
-                       /* if this process really wants to die, let it go */
-                       if ( sigismember(&(current->pending.signal), SIGKILL) ||
-                            sigismember(&(current->pending.signal), SIGINT) )
-                               break;
-                       /* signal is present: after timeout always return 
-                          really smart idea, probably useless ... */
-                       if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
-                               break; 
+               if (blocked && time_after(jiffies, timeout) &&
+                   CODA_INTERRUPTIBLE(req))
+               {
+                       unblock_signals(&old);
+                       blocked = 0;
                }
-               schedule();
+
+               if (signal_pending(current)) {
+                       list_del(&req->uc_chain);
+                       break;
+               }
+
+               if (blocked)
+                       schedule_timeout(HZ);
+               else
+                       schedule();
        }
-       remove_wait_queue(&vmp->uc_sleep, &wait);
-       set_current_state(TASK_RUNNING);
+       if (blocked)
+               unblock_signals(&old);
 
-       return;
+       remove_wait_queue(&req->uc_sleep, &wait);
+       set_current_state(TASK_RUNNING);
 }
 
 
@@ -750,8 +791,6 @@ static int coda_upcall(struct coda_sb_info *sbi,
                goto exit;
        }
 
-       list_del(&(req->uc_chain));
-
        /* Interrupted before venus read it. */
        if (!(req->uc_flags & REQ_READ))
                goto exit;
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index b541bb3..f28c2f7 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -85,7 +85,6 @@ struct upc_req {
        u_short             uc_opcode;  /* copied from data to save lookup */
        int                 uc_unique;
        wait_queue_head_t   uc_sleep;   /* process' wait queue */
-       unsigned long       uc_posttime;
 };
 
 #define REQ_ASYNC  0x1
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to