CRED: Fix a race in creds_are_invalid() in credentials debugging
[safe/jmp/linux-2.6] / kernel / resource.c
index e697f20..9c358e2 100644 (file)
@@ -188,20 +188,65 @@ static int __release_resource(struct resource *old)
        return -EINVAL;
 }
 
+static void __release_child_resources(struct resource *r)
+{
+       struct resource *tmp, *p;
+       resource_size_t size;
+
+       p = r->child;
+       r->child = NULL;
+       while (p) {
+               tmp = p;
+               p = p->sibling;
+
+               tmp->parent = NULL;
+               tmp->sibling = NULL;
+               __release_child_resources(tmp);
+
+               printk(KERN_DEBUG "release child resource %pR\n", tmp);
+               /* need to restore size, and keep flags */
+               size = resource_size(tmp);
+               tmp->start = 0;
+               tmp->end = size - 1;
+       }
+}
+
+void release_child_resources(struct resource *r)
+{
+       write_lock(&resource_lock);
+       __release_child_resources(r);
+       write_unlock(&resource_lock);
+}
+
 /**
- * request_resource - request and reserve an I/O or memory resource
+ * request_resource_conflict - request and reserve an I/O or memory resource
  * @root: root resource descriptor
  * @new: resource descriptor desired by caller
  *
- * Returns 0 for success, negative error code on error.
+ * Returns 0 for success, conflict resource on error.
  */
-int request_resource(struct resource *root, struct resource *new)
+struct resource *request_resource_conflict(struct resource *root, struct resource *new)
 {
        struct resource *conflict;
 
        write_lock(&resource_lock);
        conflict = __request_resource(root, new);
        write_unlock(&resource_lock);
+       return conflict;
+}
+
+/**
+ * request_resource - request and reserve an I/O or memory resource
+ * @root: root resource descriptor
+ * @new: resource descriptor desired by caller
+ *
+ * Returns 0 for success, negative error code on error.
+ */
+int request_resource(struct resource *root, struct resource *new)
+{
+       struct resource *conflict;
+
+       conflict = request_resource_conflict(root, new);
        return conflict ? -EBUSY : 0;
 }
 
@@ -274,7 +319,7 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
                void *arg, int (*func)(unsigned long, unsigned long, void *))
 {
        struct resource res;
-       unsigned long pfn, len;
+       unsigned long pfn, end_pfn;
        u64 orig_end;
        int ret = -1;
 
@@ -284,9 +329,10 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
        orig_end = res.end;
        while ((res.start < res.end) &&
                (find_next_system_ram(&res, "System RAM") >= 0)) {
-               pfn = (unsigned long)(res.start >> PAGE_SHIFT);
-               len = (unsigned long)((res.end + 1 - res.start) >> PAGE_SHIFT);
-               ret = (*func)(pfn, len, arg);
+               pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               end_pfn = (res.end + 1) >> PAGE_SHIFT;
+               if (end_pfn > pfn)
+                       ret = (*func)(pfn, end_pfn - pfn, arg);
                if (ret)
                        break;
                res.start = res.end + 1;
@@ -297,6 +343,19 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
 
 #endif
 
+static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg)
+{
+       return 1;
+}
+/*
+ * This generic page_is_ram() returns true if specified address is
+ * registered as "System RAM" in iomem_resource list.
+ */
+int __weak page_is_ram(unsigned long pfn)
+{
+       return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1;
+}
+
 /*
  * Find empty slot in the resource tree given range and alignment.
  */
@@ -304,7 +363,7 @@ static int find_resource(struct resource *root, struct resource *new,
                         resource_size_t size, resource_size_t min,
                         resource_size_t max, resource_size_t align,
                         resource_size_t (*alignf)(void *,
-                                                  struct resource *,
+                                                  const struct resource *,
                                                   resource_size_t,
                                                   resource_size_t),
                         void *alignf_data)
@@ -361,7 +420,7 @@ int allocate_resource(struct resource *root, struct resource *new,
                      resource_size_t size, resource_size_t min,
                      resource_size_t max, resource_size_t align,
                      resource_size_t (*alignf)(void *,
-                                               struct resource *,
+                                               const struct resource *,
                                                resource_size_t,
                                                resource_size_t),
                      void *alignf_data)
@@ -430,25 +489,40 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
 }
 
 /**
- * insert_resource - Inserts a resource in the resource tree
+ * insert_resource_conflict - Inserts resource in the resource tree
  * @parent: parent of the new resource
  * @new: new resource to insert
  *
- * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ * Returns 0 on success, conflict resource if the resource can't be inserted.
  *
- * This function is equivalent to request_resource when no conflict
+ * This function is equivalent to request_resource_conflict when no conflict
  * happens. If a conflict happens, and the conflicting resources
  * entirely fit within the range of the new resource, then the new
  * resource is inserted and the conflicting resources become children of
  * the new resource.
  */
-int insert_resource(struct resource *parent, struct resource *new)
+struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)
 {
        struct resource *conflict;
 
        write_lock(&resource_lock);
        conflict = __insert_resource(parent, new);
        write_unlock(&resource_lock);
+       return conflict;
+}
+
+/**
+ * insert_resource - Inserts a resource in the resource tree
+ * @parent: parent of the new resource
+ * @new: new resource to insert
+ *
+ * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ */
+int insert_resource(struct resource *parent, struct resource *new)
+{
+       struct resource *conflict;
+
+       conflict = insert_resource_conflict(parent, new);
        return conflict ? -EBUSY : 0;
 }