]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'rcu/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck...
authorIngo Molnar <mingo@elte.hu>
Thu, 7 Oct 2010 07:43:11 +0000 (09:43 +0200)
committerIngo Molnar <mingo@elte.hu>
Thu, 7 Oct 2010 07:43:11 +0000 (09:43 +0200)
1  2 
Documentation/DocBook/kernel-locking.tmpl
drivers/vhost/vhost.c
include/linux/cgroup.h
kernel/cgroup.c
kernel/rcupdate.c
lib/radix-tree.c

index d7884b13fb1190c4c8f670b71319a1e4f0c861bf,a0d479d1e1dd872bd1ae7b4d17d4582df03a384c..f66f4df186908f5d6ba79171e303949683107a1e
@@@ -1645,9 -1645,7 +1645,9 @@@ the amount of locking which needs to b
        all the readers who were traversing the list when we deleted the
        element are finished.  We use <function>call_rcu()</function> to
        register a callback which will actually destroy the object once
 -      the readers are finished.
 +      all pre-existing readers are finished.  Alternatively,
 +      <function>synchronize_rcu()</function> may be used to block until
 +      all pre-existing are finished.
      </para>
      <para>
        But how does Read Copy Update know when the readers are
  -        object_put(obj);
  +        list_del_rcu(&amp;obj-&gt;list);
           cache_num--;
 -+        call_rcu(&amp;obj-&gt;rcu, cache_delete_rcu, obj);
 ++        call_rcu(&amp;obj-&gt;rcu, cache_delete_rcu);
   }
  
   /* Must be holding cache_lock */
           if (++cache_num > MAX_CACHE_SIZE) {
                   struct object *i, *outcast = NULL;
                   list_for_each_entry(i, &amp;cache, list) {
 -@@ -85,6 +94,7 @@
 -         obj-&gt;popularity = 0;
 -         atomic_set(&amp;obj-&gt;refcnt, 1); /* The cache holds a reference */
 -         spin_lock_init(&amp;obj-&gt;lock);
 -+        INIT_RCU_HEAD(&amp;obj-&gt;rcu);
 -
 -         spin_lock_irqsave(&amp;cache_lock, flags);
 -         __cache_add(obj);
  @@ -104,12 +114,11 @@
   struct object *cache_find(int id)
   {
@@@ -1955,6 -1961,12 +1955,12 @@@ machines due to caching
     </sect1>
    </chapter>
  
+   <chapter id="apiref">
+    <title>Mutex API reference</title>
+ !Iinclude/linux/mutex.h
+ !Ekernel/mutex.c
+   </chapter>
    <chapter id="references">
     <title>Further reading</title>
  
diff --combined drivers/vhost/vhost.c
index b5c49478d2032ecc9051f23b23f4dff832bd24d3,4b99117f3ecd209c63571c610f813bd41d50abba..ff33e7ccb1d02b893b4df0a19eee6f281baaed81
@@@ -284,7 -284,7 +284,7 @@@ long vhost_dev_reset_owner(struct vhost
        vhost_dev_cleanup(dev);
  
        memory->nregions = 0;
 -      dev->memory = memory;
 +      RCU_INIT_POINTER(dev->memory, memory);
        return 0;
  }
  
@@@ -316,15 -316,17 +316,18 @@@ void vhost_dev_cleanup(struct vhost_de
                fput(dev->log_file);
        dev->log_file = NULL;
        /* No one will access memory at this point */
 -      kfree(dev->memory);
 -      dev->memory = NULL;
 +      kfree(rcu_dereference_protected(dev->memory,
 +                                      lockdep_is_held(&dev->mutex)));
 +      RCU_INIT_POINTER(dev->memory, NULL);
        if (dev->mm)
                mmput(dev->mm);
        dev->mm = NULL;
  
        WARN_ON(!list_empty(&dev->work_list));
-       kthread_stop(dev->worker);
+       if (dev->worker) {
+               kthread_stop(dev->worker);
+               dev->worker = NULL;
+       }
  }
  
  static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
@@@ -402,22 -404,14 +405,22 @@@ static int vq_access_ok(unsigned int nu
  /* Caller should have device mutex but not vq mutex */
  int vhost_log_access_ok(struct vhost_dev *dev)
  {
 -      return memory_access_ok(dev, dev->memory, 1);
 +      struct vhost_memory *mp;
 +
 +      mp = rcu_dereference_protected(dev->memory,
 +                                     lockdep_is_held(&dev->mutex));
 +      return memory_access_ok(dev, mp, 1);
  }
  
  /* Verify access for write logging. */
  /* Caller should have vq mutex and device mutex */
  static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
  {
 -      return vq_memory_access_ok(log_base, vq->dev->memory,
 +      struct vhost_memory *mp;
 +
 +      mp = rcu_dereference_protected(vq->dev->memory,
 +                                     lockdep_is_held(&vq->mutex));
 +      return vq_memory_access_ok(log_base, mp,
                            vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
                (!vq->log_used || log_access_ok(log_base, vq->log_addr,
                                        sizeof *vq->used +
@@@ -457,8 -451,7 +460,8 @@@ static long vhost_set_memory(struct vho
                kfree(newmem);
                return -EFAULT;
        }
 -      oldmem = d->memory;
 +      oldmem = rcu_dereference_protected(d->memory,
 +                                         lockdep_is_held(&d->mutex));
        rcu_assign_pointer(d->memory, newmem);
        synchronize_rcu();
        kfree(oldmem);
diff --combined include/linux/cgroup.h
index 3cb7d04308cdc4fd2670bd89af83b49d28dbdb20,0c991023ee475fad85136a04b00cb8d2699a382b..709dfb901d1124c75656fb0f7591826683bd2c5d
@@@ -75,7 -75,7 +75,7 @@@ struct cgroup_subsys_state 
  
        unsigned long flags;
        /* ID for this css, if possible */
 -      struct css_id *id;
 +      struct css_id __rcu *id;
  };
  
  /* bits in struct cgroup_subsys_state flags field */
@@@ -205,7 -205,7 +205,7 @@@ struct cgroup 
        struct list_head children;      /* my children */
  
        struct cgroup *parent;          /* my parent */
 -      struct dentry *dentry;          /* cgroup fs entry, RCU protected */
 +      struct dentry __rcu *dentry;    /* cgroup fs entry, RCU protected */
  
        /* Private pointers for each registered subsystem */
        struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
@@@ -578,7 -578,12 +578,12 @@@ struct task_struct *cgroup_iter_next(st
  void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
  int cgroup_scan_tasks(struct cgroup_scanner *scan);
  int cgroup_attach_task(struct cgroup *, struct task_struct *);
- int cgroup_attach_task_current_cg(struct task_struct *);
+ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
+ static inline int cgroup_attach_task_current_cg(struct task_struct *tsk)
+ {
+       return cgroup_attach_task_all(current, tsk);
+ }
  
  /*
   * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
@@@ -636,6 -641,11 +641,11 @@@ static inline int cgroupstats_build(str
  }
  
  /* No cgroups - nothing to do */
+ static inline int cgroup_attach_task_all(struct task_struct *from,
+                                        struct task_struct *t)
+ {
+       return 0;
+ }
  static inline int cgroup_attach_task_current_cg(struct task_struct *t)
  {
        return 0;
diff --combined kernel/cgroup.c
index e5c5497a7dca3a6efe0687813668f754b909fc23,c9483d8f6140ed6cb4e06fa6139e2aeb907b3d47..291ba3d04beab08f0edc4a0239bae956941e50d9
@@@ -138,7 -138,7 +138,7 @@@ struct css_id 
         * is called after synchronize_rcu(). But for safe use, css_is_removed()
         * css_tryget() should be used for avoiding race.
         */
 -      struct cgroup_subsys_state *css;
 +      struct cgroup_subsys_state __rcu *css;
        /*
         * ID of this css.
         */
  }
  
  /**
-  * cgroup_attach_task_current_cg - attach task 'tsk' to current task's cgroup
+  * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
+  * @from: attach to all cgroups of a given task
   * @tsk: the task to be attached
   */
- int cgroup_attach_task_current_cg(struct task_struct *tsk)
+ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
  {
        struct cgroupfs_root *root;
-       struct cgroup *cur_cg;
        int retval = 0;
  
        cgroup_lock();
        for_each_active_root(root) {
-               cur_cg = task_cgroup_from_root(current, root);
-               retval = cgroup_attach_task(cur_cg, tsk);
+               struct cgroup *from_cg = task_cgroup_from_root(from, root);
+               retval = cgroup_attach_task(from_cg, tsk);
                if (retval)
                        break;
        }
  
        return retval;
  }
- EXPORT_SYMBOL_GPL(cgroup_attach_task_current_cg);
+ EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
  
  /*
   * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex
diff --combined kernel/rcupdate.c
index 6c79e851521c9e8e633e0cbaf61db5dd93b0b9ae,0af1dc70fece2f456cc37006b0c554581e89c74c..a23a57a976d1a46f69cb2c32ecc38dd78e5e8b08
@@@ -73,14 -73,12 +73,14 @@@ int debug_lockdep_rcu_enabled(void
  EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
  
  /**
 - * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section?
 + * rcu_read_lock_bh_held() - might we be in RCU-bh read-side critical section?
   *
   * Check for bottom half being disabled, which covers both the
   * CONFIG_PROVE_RCU and not cases.  Note that if someone uses
   * rcu_read_lock_bh(), but then later enables BH, lockdep (if enabled)
 - * will show the situation.
 + * will show the situation.  This is useful for debug checks in functions
 + * that require that they be called within an RCU read-side critical
 + * section.
   *
   * Check debug_lockdep_rcu_enabled() to prevent false positives during boot.
   */
@@@ -88,7 -86,7 +88,7 @@@ int rcu_read_lock_bh_held(void
  {
        if (!debug_lockdep_rcu_enabled())
                return 1;
-       return in_softirq();
+       return in_softirq() || irqs_disabled();
  }
  EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
  
diff --combined lib/radix-tree.c
index 0ccbcdf75000999d0e0eb2f77fc4ced4c1dac13e,efd16fa80b1cfd55f2e1f1295f1cd45765925abf..6f412ab4c24f812fc8b7290c4a1e06cc0250ea62
@@@ -49,7 -49,7 +49,7 @@@ struct radix_tree_node 
        unsigned int    height;         /* Height from the bottom */
        unsigned int    count;
        struct rcu_head rcu_head;
 -      void            *slots[RADIX_TREE_MAP_SIZE];
 +      void __rcu      *slots[RADIX_TREE_MAP_SIZE];
        unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
  };
  
@@@ -174,14 -174,16 +174,16 @@@ static void radix_tree_node_rcu_free(st
  {
        struct radix_tree_node *node =
                        container_of(head, struct radix_tree_node, rcu_head);
+       int i;
  
        /*
         * must only free zeroed nodes into the slab. radix_tree_shrink
         * can leave us with a non-NULL entry in the first slot, so clear
         * that here to make sure.
         */
-       tag_clear(node, 0, 0);
-       tag_clear(node, 1, 0);
+       for (i = 0; i < RADIX_TREE_MAX_TAGS; i++)
+               tag_clear(node, i, 0);
        node->slots[0] = NULL;
        node->count = 0;
  
@@@ -623,6 -625,13 +625,13 @@@ EXPORT_SYMBOL(radix_tree_tag_get)
   * also settag. The function stops either after tagging nr_to_tag items or
   * after reaching last_index.
   *
+  * The tags must be set from the leaf level only and propagated back up the
+  * path to the root. We must do this so that we resolve the full path before
+  * setting any tags on intermediate nodes. If we set tags as we descend, then
+  * we can get to the leaf node and find that the index that has the iftag
+  * set is outside the range we are scanning. This reults in dangling tags and
+  * can lead to problems with later tag operations (e.g. livelocks on lookups).
+  *
   * The function returns number of leaves where the tag was set and sets
   * *first_indexp to the first unscanned index.
   * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must
@@@ -633,9 -642,13 +642,13 @@@ unsigned long radix_tree_range_tag_if_t
                unsigned long nr_to_tag,
                unsigned int iftag, unsigned int settag)
  {
-       unsigned int height = root->height, shift;
-       unsigned long tagged = 0, index = *first_indexp;
-       struct radix_tree_node *open_slots[height], *slot;
+       unsigned int height = root->height;
+       struct radix_tree_path path[height];
+       struct radix_tree_path *pathp = path;
+       struct radix_tree_node *slot;
+       unsigned int shift;
+       unsigned long tagged = 0;
+       unsigned long index = *first_indexp;
  
        last_index = min(last_index, radix_tree_maxindex(height));
        if (index > last_index)
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        slot = radix_tree_indirect_to_ptr(root->rnode);
  
+       /*
+        * we fill the path from (root->height - 2) to 0, leaving the index at
+        * (root->height - 1) as a terminator. Zero the node in the terminator
+        * so that we can use this to end walk loops back up the path.
+        */
+       path[height - 1].node = NULL;
        for (;;) {
                int offset;
  
                        goto next;
                if (!tag_get(slot, iftag, offset))
                        goto next;
+               if (height > 1) {
+                       /* Go down one level */
+                       height--;
+                       shift -= RADIX_TREE_MAP_SHIFT;
+                       path[height - 1].node = slot;
+                       path[height - 1].offset = offset;
+                       slot = slot->slots[offset];
+                       continue;
+               }
+               /* tag the leaf */
+               tagged++;
                tag_set(slot, settag, offset);
-               if (height == 1) {
-                       tagged++;
-                       goto next;
+               /* walk back up the path tagging interior nodes */
+               pathp = &path[0];
+               while (pathp->node) {
+                       /* stop if we find a node with the tag already set */
+                       if (tag_get(pathp->node, settag, pathp->offset))
+                               break;
+                       tag_set(pathp->node, settag, pathp->offset);
+                       pathp++;
                }
-               /* Go down one level */
-               height--;
-               shift -= RADIX_TREE_MAP_SHIFT;
-               open_slots[height] = slot;
-               slot = slot->slots[offset];
-               continue;
  next:
                /* Go to next item at level determined by 'shift' */
                index = ((index >> shift) + 1) << shift;
                         * last_index is guaranteed to be in the tree, what
                         * we do below cannot wander astray.
                         */
-                       slot = open_slots[height];
+                       slot = path[height - 1].node;
                        height++;
                        shift += RADIX_TREE_MAP_SHIFT;
                }