summary refs log tree commit diff
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-16 17:45:56 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-16 17:45:56 -0700
commit8759957b77ac1b5b5bdfac5ba049789107e85190 (patch)
tree82d520563ea686259f29fab26abec293b5ee6a5f /kernel
parent6968e6f8329d014920331dd2cf166ccd474b5299 (diff)
parent489011652a2d5555901def04c24d68874e8ba9a1 (diff)
downloadlinux-8759957b77ac1b5b5bdfac5ba049789107e85190.tar.gz
Merge tag 'libnvdimm-for-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams:

 - Asynchronous address range scrub:

     Given the capacities of next generation persistent memory devices a
     scrub operation to find all poison may take 10s of seconds.  We
     want this scrub work to be done asynchronously with the rest of
     system initialization, so we move it out of line from the NFIT
     probing, i.e. acpi_nfit_add().

 - Clear poison:

     ACPI 6.1 introduces the ability to send "clear error" commands to
     the ACPI0012:00 device representing the root of an "nvdimm bus".
     Similar to relocating a bad block on a disk, this support clears
     media errors in response to a write.

 - Persistent memory resource tracking:

     A persistent memory range may be designated as simply "reserved" by
     platform firmware in the efi/e820 memory map.  Later when the NFIT
     driver loads it discovers that the range is "Persistent Memory".

     The NFIT bus driver inserts a resource to advertise that
     "persistent" attribute in the system resource tree for /proc/iomem
     and kernel-internal usages.

 - Miscellaneous cleanups and fixes:

     Workaround section misaligned pmem ranges when allocating a struct
     page memmap, fix handling of the read-only case in the ioctl path,
     and clean up block device major number allocation.

* tag 'libnvdimm-for-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (26 commits)
  libnvdimm, pmem: clear poison on write
  libnvdimm, pmem: fix kmap_atomic() leak in error path
  nvdimm/btt: don't allocate unused major device number
  nvdimm/blk: don't allocate unused major device number
  pmem: don't allocate unused major device number
  ACPI: Change NFIT driver to insert new resource
  resource: Export insert_resource and remove_resource
  resource: Add remove_resource interface
  resource: Change __request_region to inherit from immediate parent
  libnvdimm, pmem: fix ia64 build, use PHYS_PFN
  nfit, libnvdimm: clear poison command support
  libnvdimm, pfn: 'resource'-address and 'size' attributes for pfn devices
  libnvdimm, pmem: adjust for section collisions with 'System RAM'
  libnvdimm, pmem: fix 'pfn' support for section-misaligned namespaces
  libnvdimm: Fix security issue with DSM IOCTL.
  libnvdimm: Clean-up access mode check.
  tools/testing/nvdimm: expand ars unit testing
  nfit: disable userspace initiated ars during scrub
  nfit: scrub and register regions in a workqueue
  nfit, libnvdimm: async region scrub workqueue
  ...
Diffstat (limited to 'kernel')
-rw-r--r--kernel/resource.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index 4d466052426b..2e78ead30934 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -233,9 +233,9 @@ static struct resource * __request_resource(struct resource *root, struct resour
 	}
 }
 
-static int __release_resource(struct resource *old)
+static int __release_resource(struct resource *old, bool release_child)
 {
-	struct resource *tmp, **p;
+	struct resource *tmp, **p, *chd;
 
 	p = &old->parent->child;
 	for (;;) {
@@ -243,7 +243,17 @@ static int __release_resource(struct resource *old)
 		if (!tmp)
 			break;
 		if (tmp == old) {
-			*p = tmp->sibling;
+			if (release_child || !(tmp->child)) {
+				*p = tmp->sibling;
+			} else {
+				for (chd = tmp->child;; chd = chd->sibling) {
+					chd->parent = tmp->parent;
+					if (!(chd->sibling))
+						break;
+				}
+				*p = tmp->child;
+				chd->sibling = tmp->sibling;
+			}
 			old->parent = NULL;
 			return 0;
 		}
@@ -325,7 +335,7 @@ int release_resource(struct resource *old)
 	int retval;
 
 	write_lock(&resource_lock);
-	retval = __release_resource(old);
+	retval = __release_resource(old, true);
 	write_unlock(&resource_lock);
 	return retval;
 }
@@ -679,7 +689,7 @@ static int reallocate_resource(struct resource *root, struct resource *old,
 		old->start = new.start;
 		old->end = new.end;
 	} else {
-		__release_resource(old);
+		__release_resource(old, true);
 		*old = new;
 		conflict = __request_resource(root, old);
 		BUG_ON(conflict);
@@ -825,6 +835,9 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
  * 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.
+ *
+ * This function is intended for producers of resources, such as FW modules
+ * and bus drivers.
  */
 struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)
 {
@@ -842,6 +855,9 @@ struct resource *insert_resource_conflict(struct resource *parent, struct resour
  * @new: new resource to insert
  *
  * Returns 0 on success, -EBUSY if the resource can't be inserted.
+ *
+ * This function is intended for producers of resources, such as FW modules
+ * and bus drivers.
  */
 int insert_resource(struct resource *parent, struct resource *new)
 {
@@ -850,6 +866,7 @@ int insert_resource(struct resource *parent, struct resource *new)
 	conflict = insert_resource_conflict(parent, new);
 	return conflict ? -EBUSY : 0;
 }
+EXPORT_SYMBOL_GPL(insert_resource);
 
 /**
  * insert_resource_expand_to_fit - Insert a resource into the resource tree
@@ -885,6 +902,32 @@ void insert_resource_expand_to_fit(struct resource *root, struct resource *new)
 	write_unlock(&resource_lock);
 }
 
+/**
+ * remove_resource - Remove a resource in the resource tree
+ * @old: resource to remove
+ *
+ * Returns 0 on success, -EINVAL if the resource is not valid.
+ *
+ * This function removes a resource previously inserted by insert_resource()
+ * or insert_resource_conflict(), and moves the children (if any) up to
+ * where they were before.  insert_resource() and insert_resource_conflict()
+ * insert a new resource, and move any conflicting resources down to the
+ * children of the new resource.
+ *
+ * insert_resource(), insert_resource_conflict() and remove_resource() are
+ * intended for producers of resources, such as FW modules and bus drivers.
+ */
+int remove_resource(struct resource *old)
+{
+	int retval;
+
+	write_lock(&resource_lock);
+	retval = __release_resource(old, false);
+	write_unlock(&resource_lock);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(remove_resource);
+
 static int __adjust_resource(struct resource *res, resource_size_t start,
 				resource_size_t size)
 {
@@ -1085,15 +1128,16 @@ struct resource * __request_region(struct resource *parent,
 	res->name = name;
 	res->start = start;
 	res->end = start + n - 1;
-	res->flags = resource_type(parent) | resource_ext_type(parent);
-	res->flags |= IORESOURCE_BUSY | flags;
-	res->desc = IORES_DESC_NONE;
 
 	write_lock(&resource_lock);
 
 	for (;;) {
 		struct resource *conflict;
 
+		res->flags = resource_type(parent) | resource_ext_type(parent);
+		res->flags |= IORESOURCE_BUSY | flags;
+		res->desc = parent->desc;
+
 		conflict = __request_resource(parent, res);
 		if (!conflict)
 			break;