]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
RDS: Do not call set_page_dirty() with irqs off
authorAndy Grover <andy.grover@oracle.com>
Thu, 11 Mar 2010 20:37:05 +0000 (12:37 -0800)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Tue, 7 Jul 2015 23:41:22 +0000 (16:41 -0700)
set_page_dirty() unconditionally re-enables interrupts, so
if we call it with irqs off, they will be on after the call,
and that's bad. This patch moves the call after we've re-enabled
interrupts in send_drop_to(), so it's safe.

Also, add BUG_ONs to let us know if we ever do call set_page_dirty
with interrupts off.

Signed-off-by: Andy Grover <andy.grover@oracle.com>
net/rds/ib_rdma.c
net/rds/rdma.c
net/rds/send.c

index 0ae87ecb850ca8a9a5ca15971b61ffd81cec5f25..72f797c93660ac683d1c0d59882e1bc983e71ed6 100644 (file)
@@ -440,6 +440,7 @@ static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
 
                        /* FIXME we need a way to tell a r/w MR
                         * from a r/o MR */
+                       BUG_ON(in_interrupt());
                        set_page_dirty(page);
                        put_page(page);
                }
index 23e79f63a66b0373ebf61936570f91746152a7ab..13caed358c6de46e7abff60f528775646c10d3ad 100644 (file)
@@ -441,8 +441,10 @@ void rds_rdma_free_op(struct rds_rdma_op *ro)
                /* Mark page dirty if it was possibly modified, which
                 * is the case for a RDMA_READ which copies from remote
                 * to local memory */
-               if (!ro->r_write)
+               if (!ro->r_write) {
+                       BUG_ON(in_interrupt());
                        set_page_dirty(page);
+               }
                put_page(page);
        }
 
index f997714d6dc0ae73e80afeedfef08ae2b5e09a8c..67e19742dbdc450ac416176db923d97f4de001b5 100644 (file)
@@ -507,12 +507,13 @@ EXPORT_SYMBOL_GPL(rds_send_get_message);
  */
 void rds_send_remove_from_sock(struct list_head *messages, int status)
 {
-       unsigned long flags = 0; /* silence gcc :P */
+       unsigned long flags;
        struct rds_sock *rs = NULL;
        struct rds_message *rm;
 
-       local_irq_save(flags);
        while (!list_empty(messages)) {
+               int was_on_sock = 0;
+
                rm = list_entry(messages->next, struct rds_message,
                                m_conn_item);
                list_del_init(&rm->m_conn_item);
@@ -527,7 +528,7 @@ void rds_send_remove_from_sock(struct list_head *messages, int status)
                 * while we're messing with it. It does not prevent the
                 * message from being removed from the socket, though.
                 */
-               spin_lock(&rm->m_rs_lock);
+               spin_lock_irqsave(&rm->m_rs_lock, flags);
                if (!test_bit(RDS_MSG_ON_SOCK, &rm->m_flags))
                        goto unlock_and_drop;
 
@@ -557,21 +558,22 @@ void rds_send_remove_from_sock(struct list_head *messages, int status)
                                        notifier->n_status = status;
                                rm->m_rdma_op->r_notifier = NULL;
                        }
-                       rds_message_put(rm);
+                       was_on_sock = 1;
                        rm->m_rs = NULL;
                }
                spin_unlock(&rs->rs_lock);
 
 unlock_and_drop:
-               spin_unlock(&rm->m_rs_lock);
+               spin_unlock_irqrestore(&rm->m_rs_lock, flags);
                rds_message_put(rm);
+               if (was_on_sock)
+                       rds_message_put(rm);
        }
 
        if (rs) {
                rds_wake_sk_sleep(rs);
                sock_put(rds_rs_to_sk(rs));
        }
-       local_irq_restore(flags);
 }
 
 /*