[PATCH v3 1/3] resource: Use list_head to link sibling resource
by Baoquan He
The struct resource uses singly linked list to link siblings. It's not
easy to do reverse iteration on sibling list. So replace it with list_head.
And this makes codes in kernel/resource.c more readable after refactoring
than pointer operation.
Besides, type of member variables of struct resource, sibling and child, are
changed from 'struct resource *' to 'struct list_head'. This brings two
pointers of size increase.
Suggested-by: Andrew Morton <akpm(a)linux-foundation.org>
Signed-off-by: Baoquan He <bhe(a)redhat.com>
Cc: Patrik Jakobsson <patrik.r.jakobsson(a)gmail.com>
Cc: David Airlie <airlied(a)linux.ie>
Cc: "K. Y. Srinivasan" <kys(a)microsoft.com>
Cc: Haiyang Zhang <haiyangz(a)microsoft.com>
Cc: Stephen Hemminger <sthemmin(a)microsoft.com>
Cc: Dmitry Torokhov <dmitry.torokhov(a)gmail.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: Rob Herring <robh+dt(a)kernel.org>
Cc: Frank Rowand <frowand.list(a)gmail.com>
Cc: Keith Busch <keith.busch(a)intel.com>
Cc: Jonathan Derrick <jonathan.derrick(a)intel.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi(a)arm.com>
Cc: Bjorn Helgaas <bhelgaas(a)google.com>
Cc: Thomas Gleixner <tglx(a)linutronix.de>
Cc: Brijesh Singh <brijesh.singh(a)amd.com>
Cc: "Jérôme Glisse" <jglisse(a)redhat.com>
Cc: Borislav Petkov <bp(a)suse.de>
Cc: Tom Lendacky <thomas.lendacky(a)amd.com>
Cc: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Cc: Yaowei Bai <baiyaowei(a)cmss.chinamobile.com>
Cc: Wei Yang <richard.weiyang(a)gmail.com>
Cc: devel(a)linuxdriverproject.org
Cc: linux-input(a)vger.kernel.org
Cc: linux-nvdimm(a)lists.01.org
Cc: devicetree(a)vger.kernel.org
Cc: linux-pci(a)vger.kernel.org
---
v2->v3:
Rename resource functions first_child() and sibling() to
resource_first_chils() and resource_sibling(). Dan suggested this.
Move resource_first_chils() and resource_sibling() to linux/ioport.h
and make them as inline function. Rob suggested this. Accordingly add
linux/list.h including in linux/ioport.h, please help review if this
bring efficiency degradation or code redundancy.
The change on struct resource {} bring two pointers of size increase,
mention this in git log to make it more specifically, Rob suggested
this.
arch/sparc/kernel/ioport.c | 2 +-
drivers/gpu/drm/drm_memory.c | 3 +-
drivers/gpu/drm/gma500/gtt.c | 5 +-
drivers/hv/vmbus_drv.c | 52 ++++----
drivers/input/joystick/iforce/iforce-main.c | 4 +-
drivers/nvdimm/e820.c | 2 +-
drivers/nvdimm/namespace_devs.c | 6 +-
drivers/nvdimm/nd.h | 5 +-
drivers/of/address.c | 4 +-
drivers/parisc/lba_pci.c | 4 +-
drivers/pci/host/vmd.c | 8 +-
drivers/pci/probe.c | 2 +
drivers/pci/setup-bus.c | 2 +-
include/linux/ioport.h | 17 ++-
kernel/resource.c | 181 +++++++++++++---------------
15 files changed, 148 insertions(+), 149 deletions(-)
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 3bcef9ce74df..4e91fbbbedcc 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -669,7 +669,7 @@ static int sparc_io_proc_show(struct seq_file *m, void *v)
struct resource *root = m->private, *r;
const char *nm;
- for (r = root->child; r != NULL; r = r->sibling) {
+ list_for_each_entry(r, &root->child, sibling) {
if ((nm = r->name) == NULL) nm = "???";
seq_printf(m, "%016llx-%016llx: %s\n",
(unsigned long long)r->start,
diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c
index 3c54044214db..53e300a993dc 100644
--- a/drivers/gpu/drm/drm_memory.c
+++ b/drivers/gpu/drm/drm_memory.c
@@ -155,9 +155,8 @@ u64 drm_get_max_iomem(void)
struct resource *tmp;
resource_size_t max_iomem = 0;
- for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
+ list_for_each_entry(tmp, &iomem_resource.child, sibling)
max_iomem = max(max_iomem, tmp->end);
- }
return max_iomem;
}
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index 3949b0990916..addd3bc009af 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -565,7 +565,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
int psb_gtt_restore(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- struct resource *r = dev_priv->gtt_mem->child;
+ struct resource *r;
struct gtt_range *range;
unsigned int restored = 0, total = 0, size = 0;
@@ -573,14 +573,13 @@ int psb_gtt_restore(struct drm_device *dev)
mutex_lock(&dev_priv->gtt_mutex);
psb_gtt_init(dev, 1);
- while (r != NULL) {
+ list_for_each_entry(r, &dev_priv->gtt_mem->child, sibling) {
range = container_of(r, struct gtt_range, resource);
if (range->pages) {
psb_gtt_insert(dev, range, 1);
size += range->resource.end - range->resource.start;
restored++;
}
- r = r->sibling;
total++;
}
mutex_unlock(&dev_priv->gtt_mutex);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index b10fe26c4891..d87ec5a1bc4c 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1412,9 +1412,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
{
resource_size_t start = 0;
resource_size_t end = 0;
- struct resource *new_res;
+ struct resource *new_res, *tmp;
struct resource **old_res = &hyperv_mmio;
- struct resource **prev_res = NULL;
switch (res->type) {
@@ -1461,44 +1460,36 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
/*
* If two ranges are adjacent, merge them.
*/
- do {
- if (!*old_res) {
- *old_res = new_res;
- break;
- }
-
- if (((*old_res)->end + 1) == new_res->start) {
- (*old_res)->end = new_res->end;
+ if (!*old_res) {
+ *old_res = new_res;
+ return AE_OK;
+ }
+ tmp = *old_res;
+ list_for_each_entry_from(tmp, &tmp->parent->child, sibling) {
+ if ((tmp->end + 1) == new_res->start) {
+ tmp->end = new_res->end;
kfree(new_res);
break;
}
- if ((*old_res)->start == new_res->end + 1) {
- (*old_res)->start = new_res->start;
+ if (tmp->start == new_res->end + 1) {
+ tmp->start = new_res->start;
kfree(new_res);
break;
}
- if ((*old_res)->start > new_res->end) {
- new_res->sibling = *old_res;
- if (prev_res)
- (*prev_res)->sibling = new_res;
- *old_res = new_res;
+ if (tmp->start > new_res->end) {
+ list_add(&new_res->sibling, tmp->sibling.prev);
break;
}
-
- prev_res = old_res;
- old_res = &(*old_res)->sibling;
-
- } while (1);
+ }
return AE_OK;
}
static int vmbus_acpi_remove(struct acpi_device *device)
{
- struct resource *cur_res;
- struct resource *next_res;
+ struct resource *res;
if (hyperv_mmio) {
if (fb_mmio) {
@@ -1507,10 +1498,9 @@ static int vmbus_acpi_remove(struct acpi_device *device)
fb_mmio = NULL;
}
- for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) {
- next_res = cur_res->sibling;
- kfree(cur_res);
- }
+ res = hyperv_mmio;
+ list_for_each_entry_from(res, &res->parent->child, sibling)
+ kfree(res);
}
return 0;
@@ -1596,7 +1586,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj,
}
}
- for (iter = hyperv_mmio; iter; iter = iter->sibling) {
+ iter = hyperv_mmio;
+ list_for_each_entry_from(iter, &iter->parent->child, sibling) {
if ((iter->start >= max) || (iter->end <= min))
continue;
@@ -1639,7 +1630,8 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size)
struct resource *iter;
down(&hyperv_mmio_lock);
- for (iter = hyperv_mmio; iter; iter = iter->sibling) {
+ iter = hyperv_mmio;
+ list_for_each_entry_from(iter, &iter->parent->child, sibling) {
if ((iter->start >= start + size) || (iter->end <= start))
continue;
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index daeeb4c7e3b0..5c0be27b33ff 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -305,8 +305,8 @@ int iforce_init_device(struct iforce *iforce)
iforce->device_memory.end = 200;
iforce->device_memory.flags = IORESOURCE_MEM;
iforce->device_memory.parent = NULL;
- iforce->device_memory.child = NULL;
- iforce->device_memory.sibling = NULL;
+ INIT_LIST_HEAD(&iforce->device_memory.child);
+ INIT_LIST_HEAD(&iforce->device_memory.sibling);
/*
* Wait until device ready - until it sends its first response.
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c
index 6f9a6ffd7cde..513e661bb0d8 100644
--- a/drivers/nvdimm/e820.c
+++ b/drivers/nvdimm/e820.c
@@ -53,7 +53,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
goto err;
platform_set_drvdata(pdev, nvdimm_bus);
- for (p = iomem_resource.child; p ; p = p->sibling) {
+ list_for_each_entry(p, &iomem_resource.child, sibling) {
struct nd_region_desc ndr_desc;
if (p->desc != IORES_DESC_PERSISTENT_MEMORY_LEGACY)
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 28afdd668905..f53d410d9981 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -637,7 +637,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
retry:
first = 0;
for_each_dpa_resource(ndd, res) {
- struct resource *next = res->sibling, *new_res = NULL;
+ struct resource *next = resource_sibling(res), *new_res = NULL;
resource_size_t allocate, available = 0;
enum alloc_loc loc = ALLOC_ERR;
const char *action;
@@ -763,7 +763,7 @@ static resource_size_t scan_allocate(struct nd_region *nd_region,
* an initial "pmem-reserve pass". Only do an initial BLK allocation
* when none of the DPA space is reserved.
*/
- if ((is_pmem || !ndd->dpa.child) && n == to_allocate)
+ if ((is_pmem || list_empty(&ndd->dpa.child)) && n == to_allocate)
return init_dpa_allocation(label_id, nd_region, nd_mapping, n);
return n;
}
@@ -779,7 +779,7 @@ static int merge_dpa(struct nd_region *nd_region,
retry:
for_each_dpa_resource(ndd, res) {
int rc;
- struct resource *next = res->sibling;
+ struct resource *next = resource_sibling(res);
resource_size_t end = res->start + resource_size(res);
if (!next || strcmp(res->name, label_id->id) != 0
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 32e0364b48b9..da7da15e03e7 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -102,11 +102,10 @@ unsigned sizeof_namespace_label(struct nvdimm_drvdata *ndd);
(unsigned long long) (res ? res->start : 0), ##arg)
#define for_each_dpa_resource(ndd, res) \
- for (res = (ndd)->dpa.child; res; res = res->sibling)
+ list_for_each_entry(res, &(ndd)->dpa.child, sibling)
#define for_each_dpa_resource_safe(ndd, res, next) \
- for (res = (ndd)->dpa.child, next = res ? res->sibling : NULL; \
- res; res = next, next = next ? next->sibling : NULL)
+ list_for_each_entry_safe(res, next, &(ndd)->dpa.child, sibling)
struct nd_percpu_lane {
int count;
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 53349912ac75..e2e25719ab52 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -330,7 +330,9 @@ int of_pci_range_to_resource(struct of_pci_range *range,
{
int err;
res->flags = range->flags;
- res->parent = res->child = res->sibling = NULL;
+ res->parent = NULL;
+ INIT_LIST_HEAD(&res->child);
+ INIT_LIST_HEAD(&res->sibling);
res->name = np->full_name;
if (res->flags & IORESOURCE_IO) {
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 69bd98421eb1..7482bdfd1959 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -170,8 +170,8 @@ lba_dump_res(struct resource *r, int d)
for (i = d; i ; --i) printk(" ");
printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r,
(long)r->start, (long)r->end, r->flags);
- lba_dump_res(r->child, d+2);
- lba_dump_res(r->sibling, d);
+ lba_dump_res(resource_first_child(&r->child), d+2);
+ lba_dump_res(resource_sibling(r), d);
}
diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
index 930a8fa08bd6..c3000af903ea 100644
--- a/drivers/pci/host/vmd.c
+++ b/drivers/pci/host/vmd.c
@@ -520,14 +520,14 @@ static struct pci_ops vmd_ops = {
static void vmd_attach_resources(struct vmd_dev *vmd)
{
- vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1];
- vmd->dev->resource[VMD_MEMBAR2].child = &vmd->resources[2];
+ list_add(&vmd->resources[1].sibling, &vmd->dev->resource[VMD_MEMBAR1].child);
+ list_add(&vmd->resources[2].sibling, &vmd->dev->resource[VMD_MEMBAR2].child);
}
static void vmd_detach_resources(struct vmd_dev *vmd)
{
- vmd->dev->resource[VMD_MEMBAR1].child = NULL;
- vmd->dev->resource[VMD_MEMBAR2].child = NULL;
+ INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR1].child);
+ INIT_LIST_HEAD(&vmd->dev->resource[VMD_MEMBAR2].child);
}
/*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ac91b6fd0bcd..d162c77bec29 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -59,6 +59,8 @@ static struct resource *get_pci_domain_busn_res(int domain_nr)
r->res.start = 0;
r->res.end = 0xff;
r->res.flags = IORESOURCE_BUS | IORESOURCE_PCI_FIXED;
+ INIT_LIST_HEAD(&r->res.child);
+ INIT_LIST_HEAD(&r->res.sibling);
list_add_tail(&r->list, &pci_domain_busn_res_list);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 072784f55ea5..0d5e30004ca6 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2107,7 +2107,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
continue;
/* Ignore BARs which are still in use */
- if (res->child)
+ if (!list_empty(&res->child))
continue;
ret = add_to_list(&saved, bridge, res, 0, 0);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index da0ebaec25f0..225d13d3500a 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -12,6 +12,7 @@
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/list.h>
/*
* Resources are tree-like, allowing
* nesting etc..
@@ -22,7 +23,8 @@ struct resource {
const char *name;
unsigned long flags;
unsigned long desc;
- struct resource *parent, *sibling, *child;
+ struct list_head child, sibling;
+ struct resource *parent;
};
/*
@@ -215,7 +217,6 @@ static inline bool resource_contains(struct resource *r1, struct resource *r2)
return r1->start <= r2->start && r1->end >= r2->end;
}
-
/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
@@ -286,6 +287,18 @@ static inline bool resource_overlaps(struct resource *r1, struct resource *r2)
return (r1->start <= r2->end && r1->end >= r2->start);
}
+static inline struct resource *resource_sibling(struct resource *res)
+{
+ if (res->parent && !list_is_last(&res->sibling, &res->parent->child))
+ return list_next_entry(res, sibling);
+ return NULL;
+}
+
+static inline struct resource *resource_first_child(struct list_head *head)
+{
+ return list_first_entry_or_null(head, struct resource, sibling);
+}
+
#endif /* __ASSEMBLY__ */
#endif /* _LINUX_IOPORT_H */
diff --git a/kernel/resource.c b/kernel/resource.c
index 2af6c03858b9..4f560991c130 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -31,6 +31,8 @@ struct resource ioport_resource = {
.start = 0,
.end = IO_SPACE_LIMIT,
.flags = IORESOURCE_IO,
+ .sibling = LIST_HEAD_INIT(ioport_resource.sibling),
+ .child = LIST_HEAD_INIT(ioport_resource.child),
};
EXPORT_SYMBOL(ioport_resource);
@@ -39,6 +41,8 @@ struct resource iomem_resource = {
.start = 0,
.end = -1,
.flags = IORESOURCE_MEM,
+ .sibling = LIST_HEAD_INIT(iomem_resource.sibling),
+ .child = LIST_HEAD_INIT(iomem_resource.child),
};
EXPORT_SYMBOL(iomem_resource);
@@ -57,20 +61,20 @@ static DEFINE_RWLOCK(resource_lock);
* by boot mem after the system is up. So for reusing the resource entry
* we need to remember the resource.
*/
-static struct resource *bootmem_resource_free;
+static struct list_head bootmem_resource_free = LIST_HEAD_INIT(bootmem_resource_free);
static DEFINE_SPINLOCK(bootmem_resource_lock);
static struct resource *next_resource(struct resource *p, bool sibling_only)
{
/* Caller wants to traverse through siblings only */
if (sibling_only)
- return p->sibling;
+ return resource_sibling(p);
- if (p->child)
- return p->child;
- while (!p->sibling && p->parent)
+ if (!list_empty(&p->child))
+ return resource_first_child(&p->child);
+ while (!resource_sibling(p) && p->parent)
p = p->parent;
- return p->sibling;
+ return resource_sibling(p);
}
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
@@ -90,7 +94,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
struct resource *p = m->private;
loff_t l = 0;
read_lock(&resource_lock);
- for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
+ for (p = resource_first_child(&p->child); p && l < *pos; p = r_next(m, p, &l))
;
return p;
}
@@ -186,8 +190,7 @@ static void free_resource(struct resource *res)
if (!PageSlab(virt_to_head_page(res))) {
spin_lock(&bootmem_resource_lock);
- res->sibling = bootmem_resource_free;
- bootmem_resource_free = res;
+ list_add(&res->sibling, &bootmem_resource_free);
spin_unlock(&bootmem_resource_lock);
} else {
kfree(res);
@@ -199,10 +202,9 @@ static struct resource *alloc_resource(gfp_t flags)
struct resource *res = NULL;
spin_lock(&bootmem_resource_lock);
- if (bootmem_resource_free) {
- res = bootmem_resource_free;
- bootmem_resource_free = res->sibling;
- }
+ res = resource_first_child(&bootmem_resource_free);
+ if (res)
+ list_del(&res->sibling);
spin_unlock(&bootmem_resource_lock);
if (res)
@@ -210,6 +212,8 @@ static struct resource *alloc_resource(gfp_t flags)
else
res = kzalloc(sizeof(struct resource), flags);
+ INIT_LIST_HEAD(&res->child);
+ INIT_LIST_HEAD(&res->sibling);
return res;
}
@@ -218,7 +222,7 @@ static struct resource * __request_resource(struct resource *root, struct resour
{
resource_size_t start = new->start;
resource_size_t end = new->end;
- struct resource *tmp, **p;
+ struct resource *tmp;
if (end < start)
return root;
@@ -226,64 +230,62 @@ static struct resource * __request_resource(struct resource *root, struct resour
return root;
if (end > root->end)
return root;
- p = &root->child;
- for (;;) {
- tmp = *p;
- if (!tmp || tmp->start > end) {
- new->sibling = tmp;
- *p = new;
+
+ if (list_empty(&root->child)) {
+ list_add(&new->sibling, &root->child);
+ new->parent = root;
+ INIT_LIST_HEAD(&new->child);
+ return NULL;
+ }
+
+ list_for_each_entry(tmp, &root->child, sibling) {
+ if (tmp->start > end) {
+ list_add(&new->sibling, tmp->sibling.prev);
new->parent = root;
+ INIT_LIST_HEAD(&new->child);
return NULL;
}
- p = &tmp->sibling;
if (tmp->end < start)
continue;
return tmp;
}
+
+ list_add_tail(&new->sibling, &root->child);
+ new->parent = root;
+ INIT_LIST_HEAD(&new->child);
+ return NULL;
}
static int __release_resource(struct resource *old, bool release_child)
{
- struct resource *tmp, **p, *chd;
+ struct resource *tmp, *next, *chd;
- p = &old->parent->child;
- for (;;) {
- tmp = *p;
- if (!tmp)
- break;
+ list_for_each_entry_safe(tmp, next, &old->parent->child, sibling) {
if (tmp == old) {
- if (release_child || !(tmp->child)) {
- *p = tmp->sibling;
+ if (release_child || list_empty(&tmp->child)) {
+ list_del(&tmp->sibling);
} else {
- for (chd = tmp->child;; chd = chd->sibling) {
+ list_for_each_entry(chd, &tmp->child, sibling)
chd->parent = tmp->parent;
- if (!(chd->sibling))
- break;
- }
- *p = tmp->child;
- chd->sibling = tmp->sibling;
+ list_splice(&tmp->child, tmp->sibling.prev);
+ list_del(&tmp->sibling);
}
+
old->parent = NULL;
return 0;
}
- p = &tmp->sibling;
}
return -EINVAL;
}
static void __release_child_resources(struct resource *r)
{
- struct resource *tmp, *p;
+ struct resource *tmp, *next;
resource_size_t size;
- p = r->child;
- r->child = NULL;
- while (p) {
- tmp = p;
- p = p->sibling;
-
+ list_for_each_entry_safe(tmp, next, &r->child, sibling) {
tmp->parent = NULL;
- tmp->sibling = NULL;
+ INIT_LIST_HEAD(&tmp->sibling);
__release_child_resources(tmp);
printk(KERN_DEBUG "release child resource %pR\n", tmp);
@@ -292,6 +294,8 @@ static void __release_child_resources(struct resource *r)
tmp->start = 0;
tmp->end = size - 1;
}
+
+ INIT_LIST_HEAD(&tmp->child);
}
void release_child_resources(struct resource *r)
@@ -376,7 +380,8 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc,
read_lock(&resource_lock);
- for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) {
+ for (p = resource_first_child(&iomem_resource.child); p;
+ p = next_resource(p, sibling_only)) {
if ((p->flags & res->flags) != res->flags)
continue;
if ((desc != IORES_DESC_NONE) && (desc != p->desc))
@@ -564,7 +569,7 @@ int region_intersects(resource_size_t start, size_t size, unsigned long flags,
struct resource *p;
read_lock(&resource_lock);
- for (p = iomem_resource.child; p ; p = p->sibling) {
+ list_for_each_entry(p, &iomem_resource.child, sibling) {
bool is_type = (((p->flags & flags) == flags) &&
((desc == IORES_DESC_NONE) ||
(desc == p->desc)));
@@ -618,7 +623,7 @@ static int __find_resource(struct resource *root, struct resource *old,
resource_size_t size,
struct resource_constraint *constraint)
{
- struct resource *this = root->child;
+ struct resource *this = resource_first_child(&root->child);
struct resource tmp = *new, avail, alloc;
tmp.start = root->start;
@@ -628,7 +633,7 @@ static int __find_resource(struct resource *root, struct resource *old,
*/
if (this && this->start == root->start) {
tmp.start = (this == old) ? old->start : this->end + 1;
- this = this->sibling;
+ this = resource_sibling(this);
}
for(;;) {
if (this)
@@ -664,7 +669,7 @@ next: if (!this || this->end == root->end)
if (this != old)
tmp.start = this->end + 1;
- this = this->sibling;
+ this = resource_sibling(this);
}
return -EBUSY;
}
@@ -708,7 +713,7 @@ static int reallocate_resource(struct resource *root, struct resource *old,
goto out;
}
- if (old->child) {
+ if (!list_empty(&old->child)) {
err = -EBUSY;
goto out;
}
@@ -789,7 +794,7 @@ struct resource *lookup_resource(struct resource *root, resource_size_t start)
struct resource *res;
read_lock(&resource_lock);
- for (res = root->child; res; res = res->sibling) {
+ list_for_each_entry(res, &root->child, sibling) {
if (res->start == start)
break;
}
@@ -822,32 +827,27 @@ static struct resource * __insert_resource(struct resource *parent, struct resou
break;
}
- for (next = first; ; next = next->sibling) {
+ for (next = first; ; next = resource_sibling(next)) {
/* Partial overlap? Bad, and unfixable */
if (next->start < new->start || next->end > new->end)
return next;
- if (!next->sibling)
+ if (!resource_sibling(next))
break;
- if (next->sibling->start > new->end)
+ if (resource_sibling(next)->start > new->end)
break;
}
-
new->parent = parent;
- new->sibling = next->sibling;
- new->child = first;
+ list_add(&new->sibling, &next->sibling);
+ INIT_LIST_HEAD(&new->child);
- next->sibling = NULL;
- for (next = first; next; next = next->sibling)
+ /*
+ * From first to next, they all fall into new's region, so change them
+ * as new's children.
+ */
+ list_cut_position(&new->child, first->sibling.prev, &next->sibling);
+ list_for_each_entry(next, &new->child, sibling)
next->parent = new;
- if (parent->child == first) {
- parent->child = new;
- } else {
- next = parent->child;
- while (next->sibling != first)
- next = next->sibling;
- next->sibling = new;
- }
return NULL;
}
@@ -969,19 +969,17 @@ static int __adjust_resource(struct resource *res, resource_size_t start,
if ((start < parent->start) || (end > parent->end))
goto out;
- if (res->sibling && (res->sibling->start <= end))
+ if (resource_sibling(res) && (resource_sibling(res)->start <= end))
goto out;
- tmp = parent->child;
- if (tmp != res) {
- while (tmp->sibling != res)
- tmp = tmp->sibling;
+ if (res->sibling.prev != &parent->child) {
+ tmp = list_prev_entry(res, sibling);
if (start <= tmp->end)
goto out;
}
skip:
- for (tmp = res->child; tmp; tmp = tmp->sibling)
+ list_for_each_entry(tmp, &res->child, sibling)
if ((tmp->start < start) || (tmp->end > end))
goto out;
@@ -1206,34 +1204,32 @@ EXPORT_SYMBOL(__request_region);
void __release_region(struct resource *parent, resource_size_t start,
resource_size_t n)
{
- struct resource **p;
+ struct resource *res;
resource_size_t end;
- p = &parent->child;
+ res = resource_first_child(&parent->child);
end = start + n - 1;
write_lock(&resource_lock);
for (;;) {
- struct resource *res = *p;
-
if (!res)
break;
if (res->start <= start && res->end >= end) {
if (!(res->flags & IORESOURCE_BUSY)) {
- p = &res->child;
+ res = resource_first_child(&res->child);
continue;
}
if (res->start != start || res->end != end)
break;
- *p = res->sibling;
+ list_del(&res->sibling);
write_unlock(&resource_lock);
if (res->flags & IORESOURCE_MUXED)
wake_up(&muxed_resource_wait);
free_resource(res);
return;
}
- p = &res->sibling;
+ res = resource_sibling(res);
}
write_unlock(&resource_lock);
@@ -1268,9 +1264,7 @@ EXPORT_SYMBOL(__release_region);
int release_mem_region_adjustable(struct resource *parent,
resource_size_t start, resource_size_t size)
{
- struct resource **p;
- struct resource *res;
- struct resource *new_res;
+ struct resource *res, *new_res;
resource_size_t end;
int ret = -EINVAL;
@@ -1281,16 +1275,16 @@ int release_mem_region_adjustable(struct resource *parent,
/* The alloc_resource() result gets checked later */
new_res = alloc_resource(GFP_KERNEL);
- p = &parent->child;
+ res = resource_first_child(&parent->child);
write_lock(&resource_lock);
- while ((res = *p)) {
+ while ((res)) {
if (res->start >= end)
break;
/* look for the next resource if it does not fit into */
if (res->start > start || res->end < end) {
- p = &res->sibling;
+ res = resource_sibling(res);
continue;
}
@@ -1298,14 +1292,14 @@ int release_mem_region_adjustable(struct resource *parent,
break;
if (!(res->flags & IORESOURCE_BUSY)) {
- p = &res->child;
+ res = resource_first_child(&res->child);
continue;
}
/* found the target resource; let's adjust accordingly */
if (res->start == start && res->end == end) {
/* free the whole entry */
- *p = res->sibling;
+ list_del(&res->sibling);
free_resource(res);
ret = 0;
} else if (res->start == start && res->end != end) {
@@ -1328,14 +1322,13 @@ int release_mem_region_adjustable(struct resource *parent,
new_res->flags = res->flags;
new_res->desc = res->desc;
new_res->parent = res->parent;
- new_res->sibling = res->sibling;
- new_res->child = NULL;
+ INIT_LIST_HEAD(&new_res->child);
ret = __adjust_resource(res, res->start,
start - res->start);
if (ret)
break;
- res->sibling = new_res;
+ list_add(&new_res->sibling, &res->sibling);
new_res = NULL;
}
@@ -1516,7 +1509,7 @@ static int __init reserve_setup(char *str)
res->end = io_start + io_num - 1;
res->flags |= IORESOURCE_BUSY;
res->desc = IORES_DESC_NONE;
- res->child = NULL;
+ INIT_LIST_HEAD(&res->child);
if (request_resource(parent, res) == 0)
reserved = x+1;
}
@@ -1536,7 +1529,7 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
loff_t l;
read_lock(&resource_lock);
- for (p = p->child; p ; p = r_next(NULL, p, &l)) {
+ for (p = resource_first_child(&p->child); p; p = r_next(NULL, p, &l)) {
/*
* We can probably skip the resources without
* IORESOURCE_IO attribute?
@@ -1592,7 +1585,7 @@ bool iomem_is_exclusive(u64 addr)
addr = addr & PAGE_MASK;
read_lock(&resource_lock);
- for (p = p->child; p ; p = r_next(NULL, p, &l)) {
+ for (p = resource_first_child(&p->child); p; p = r_next(NULL, p, &l)) {
/*
* We can probably skip the resources without
* IORESOURCE_IO attribute?
--
2.13.6
2 years, 8 months
[PATCH v5 0/4] ndctl, monitor: add ndctl monitor daemon
by QI Fuli
This is the v5 patch for ndctl monitor daemon, a tiny daemon to monitor the
smart events of nvdimm DIMMs. Users can run a monitor as a one-shot command
or a daemon in background by using the [--daemon] option. DIMMs to monitor
can be selected by [--dimm] [--bus] [--region] [--namespace] options,
these options support multiple space-seperated arguments.
When a smart event fires, monitor daemon will log the notifications which
including dimm health status to syslog or a logfile by setting
[--logfile=<file|syslog>] option. monitor also can output the notifications
to stderr when it run as one-shot command by setting [--logfile=<stderr>].
The notifications follow json format and can be consumed by log collectors
like Fluentd. Users can change the configuration of monitor by editing
the default configuration file /etc/ndctl/monitor.conf or by using
[--config-file=<file>] option to override the default one.
Users can start a monitor daemon by the following command:
# ndctl monitor --dimm nmem1 --logfile /var/log/ndctl/monitor.log --daemon
Also, a monitor daemon can be started by systemd:
# systemctl start ndctl-monitor.service
In this case, monitor daemon follows the default configuration file
/etc/ndctl/monitor.conf.
Signed-off-by: QI Fuli <qi.fuli(a)jp.fujitsu.com>
Change log since v4:
- Adding OPTION_FILENAME to make sure filename is correct
- Adding configuration file
- Adding [--config-file] option to override the default cofiguration file
- Making some options support multiple space-seperated arguments
- Making systemctl enable ndctl-monitor.service command work
- Making systemctl restart ndctl-monitor.service command work
- Making the dirtctory of systemd unit file to be configurable
- Changing log_file() and log_syslog to logreport()
- Changing date format in log to nanoseconds since epoch
- Changing select() to epoll()
- Adding filter_bus() and filter_region()
Change log since v3:
- Removing create-monitor, show-monitor, list-monitor, destroy-monitor
- Adding [--daemon] option to run ndctl monitor as a daemon
- Using systemd to manage ndctl monitor daemon
- Replacing filter_monitor_dimm() with filter_dimm()
Change log since v2:
- Changing the interface of daemon to the ndctl command line
- Changing the name of daemon form "nvdimmd" to "monitor"
- Removing the config file, unit_file, nvdimmd dir
- Removing nvdimmd_test program
Change log since v1:
- Adding a config file(/etc/nvdimmd/nvdimmd.conf)
- Using struct log_ctx instead of syslog()
- Using log_syslog() to save the notify messages to syslog
- Using log_file() to save the notify messages to special file
- Adding LOG_NOTICE level to log_priority
- Using automake instead of Makefile
- Adding a new util file(nvdimmd/util.c) including helper functions
needed for nvdimm daemon
- Adding nvdimmd_test program
QI Fuli (4):
ndctl, util: add OPTION_FILENAME to parse_opt_type
ndctl, monitor: add ndctl monitor daemon
ndctl, monitor: add default configuration file
ndctl, monitor: add the unit file of systemd for ndctl-monitor service
Makefile.am | 3 +-
autogen.sh | 3 +-
builtin.h | 1 +
configure.ac | 22 ++
ndctl/Makefile.am | 12 +-
ndctl/monitor.c | 460 ++++++++++++++++++++++++++++++++++++
ndctl/monitor.conf | 37 +++
ndctl/ndctl-monitor.service | 7 +
ndctl/ndctl.c | 1 +
util/abspath.c | 28 +++
util/help.c | 5 -
util/parse-options.c | 47 +++-
util/parse-options.h | 11 +-
util/util.h | 7 +
14 files changed, 628 insertions(+), 16 deletions(-)
create mode 100644 ndctl/monitor.c
create mode 100644 ndctl/monitor.conf
create mode 100644 ndctl/ndctl-monitor.service
create mode 100644 util/abspath.c
--
2.17.0.140.g0b0cc9f86
2 years, 8 months
[PATCH v2] ndctl, filter: fix "keyword 'all' is ignored" in util_<obj>_filter()
by QI Fuli
This is a follow up patch for commit c70adc3cf6bf ("ndctl, filter: refactor
util_<obj>_filter() to support multiple space-seperated arguments")
refactored util_<obj>_filter() to support multiple space-seperated arguments.
But, when the keyword "all" is included in space-seperated arguments,
it will be treaded as <object>'s name. This patch fixes it.
Signed-off-by: QI Fuli <qi.fuli(a)jp.fujitsu.com>
Change log since v1:
- Removing the strcmp(__ident, "all") == 0 at the top of util_<obj>_filter()
- Changing the strcmp(ident, "all") == 0 to strcmp(name, "all") == 0
---
util/filter.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/util/filter.c b/util/filter.c
index 0d3cc02..1734bce 100644
--- a/util/filter.c
+++ b/util/filter.c
@@ -31,7 +31,7 @@ struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
unsigned long bus_id, id;
const char *provider, *devname, *name;
- if (!__ident || strcmp(__ident, "all") == 0)
+ if (!__ident)
return bus;
ident = strdup(__ident);
@@ -40,6 +40,9 @@ struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(name, "all") == 0)
+ break;
+
bus_id = strtoul(ident, &end, 0);
if (end == ident || end[0])
bus_id = ULONG_MAX;
@@ -69,7 +72,7 @@ struct ndctl_region *util_region_filter(struct ndctl_region *region,
const char *name, *region_name;
unsigned long region_id, id;
- if (!__ident || strcmp(__ident, "all") == 0)
+ if (!__ident)
return region;
ident = strdup(__ident);
@@ -78,6 +81,9 @@ struct ndctl_region *util_region_filter(struct ndctl_region *region,
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(name, "all") == 0)
+ break;
+
region_id = strtoul(ident, &end, 0);
if (end == ident || end[0])
region_id = ULONG_MAX;
@@ -106,7 +112,7 @@ struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns,
const char *name;
char *ident, *save;
- if (!__ident || strcmp(__ident, "all") == 0)
+ if (!__ident)
return ndns;
ident = strdup(__ident);
@@ -115,6 +121,9 @@ struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns,
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(name, "all") == 0)
+ break;
+
if (strcmp(name, ndctl_namespace_get_devname(ndns)) == 0)
break;
@@ -137,7 +146,7 @@ struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm,
const char *name, *dimm_name;
unsigned long dimm_id, id;
- if (!__ident || strcmp(__ident, "all") == 0)
+ if (!__ident)
return dimm;
ident = strdup(__ident);
@@ -146,6 +155,9 @@ struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm,
for (name = strtok_r(ident, " ", &save); name;
name = strtok_r(NULL, " ", &save)) {
+ if (strcmp(name, "all") == 0)
+ break;
+
dimm_id = strtoul(ident, &end, 0);
if (end == ident || end[0])
dimm_id = ULONG_MAX;
--
2.17.0.140.g0b0cc9f86
2 years, 8 months
[PATCH] pmem: fix badblocks population for raw mode
by Toshi Kani
pmem_attach_disk() calls nvdimm_badblocks_populate() with resource
range uninitialized in the case of raw mode. This leads the pmem
driver to hit MCE despite of ARS reporting the range bad.
Initialize 'bb_res' for raw mode.
Fixes: e8d513483300 ("memremap: change devm_memremap_pages interface to use struct dev_pagemap")
Signed-off-by: Toshi Kani <toshi.kani(a)hpe.com>
Cc: Christoph Hellwig <hch(a)lst.de>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: <stable(a)vger.kernel.org>
---
drivers/nvdimm/pmem.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 9d714926ecf5..2d7875209bce 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -367,9 +367,11 @@ static int pmem_attach_disk(struct device *dev,
addr = devm_memremap_pages(dev, &pmem->pgmap);
pmem->pfn_flags |= PFN_MAP;
memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res));
- } else
+ } else {
addr = devm_memremap(dev, pmem->phys_addr,
pmem->size, ARCH_MEMREMAP_PMEM);
+ memcpy(&bb_res, res, sizeof(bb_res));
+ }
/*
* At release time the queue must be frozen before
2 years, 8 months
[RESEND 0/3] Add support for memcpy_mcsafe
by Balbir Singh
memcpy_mcsafe() is an API currently used by the pmem subsystem to convert
errors while doing a memcpy (machine check exception errors) to a return
value. This patchset consists of three patches
1. The first patch is a bug fix to handle machine check errors correctly
while walking the page tables in kernel mode, due to huge pmd/pud sizes
2. The second patch adds memcpy_mcsafe() support, this is largely derived
from existing code
3. The third patch registers for callbacks on machine check exceptions and
in them uses specialized knowledge of the type of page to decide whether
to handle the MCE as is or to return to a fixup address present in
memcpy_mcsafe(). If a fixup address is used, then we return an error
value of -EFAULT to the caller.
Testing
A large part of the testing was done under a simulator by selectively
inserting machine check exceptions in a test driver doing memcpy_mcsafe
via ioctls.
Balbir Singh (3):
powerpc/mce: Bug fixes for MCE handling in kernel space
powerpc/memcpy: Add memcpy_mcsafe for pmem
powerpc/mce: Handle memcpy_mcsafe
arch/powerpc/include/asm/mce.h | 3 +-
arch/powerpc/include/asm/string.h | 2 +
arch/powerpc/kernel/mce.c | 76 +++++++++++-
arch/powerpc/kernel/mce_power.c | 17 +--
arch/powerpc/lib/Makefile | 2 +-
arch/powerpc/lib/memcpy_mcsafe_64.S | 225 ++++++++++++++++++++++++++++++++++++
6 files changed, 314 insertions(+), 11 deletions(-)
create mode 100644 arch/powerpc/lib/memcpy_mcsafe_64.S
--
2.13.6
2 years, 8 months
Re: [Qemu-devel] [RFC v2 1/2] virtio: add pmem driver
by Pankaj Gupta
> > > > + int err;
> > > > +
> > > > + sg_init_one(&sg, buf, sizeof(buf));
> > > > +
> > > > + err = virtqueue_add_outbuf(vpmem->req_vq, &sg, 1, buf, GFP_KERNEL);
> > > > +
> > > > + if (err) {
> > > > + dev_err(&vdev->dev, "failed to send command to virtio pmem
> > > > device\n");
> > > > + return;
> > > > + }
> > > > +
> > > > + virtqueue_kick(vpmem->req_vq);
> > >
> > > Is any locking necessary? Two CPUs must not invoke virtio_pmem_flush()
> > > at the same time. Not sure if anything guarantees this, maybe you're
> > > relying on libnvdimm but I haven't checked.
> >
> > I thought about it to some extent, and wanted to go ahead with simple
> > version first:
> >
> > - I think file 'inode -> locking' sill is there for request on single file.
> > - For multiple files, our aim is to just flush the backend block image.
> > - Even there is collision for virt queue read/write entry it should just
> > trigger a Qemu fsync.
> > We just want most recent flush to assure guest writes are synced
> > properly.
> >
> > Important point here: We are doing entire block fsync for guest virtual
> > disk.
>
> I don't understand your answer. Is locking necessary or not?
It will be required with other changes.
>
> From the virtqueue_add_outbuf() documentation:
>
> * Caller must ensure we don't call this with other virtqueue operations
> * at the same time (except where noted).
Yes, I also saw it. But thought if can avoid it with current functionality. :)
Thanks,
Pankaj
2 years, 9 months
[PATCH v4 0/4] ndctl: convert actions to use util_filter_walk
by Dave Jiang
util_filter_walk() does the looping through bus/dimm/region/namespace
that a lot of the operations in ndctl uses. Converting them to common
code and reduce maintenance on individual versions of the same code.
In this series we are convering namespace, region, and dimm actions.
---
v4:
- change struct names to be less confusing. (Dan)
v3:
- fixed some corner cases in namespace patch.
- changed param renaming to reduce change for util_filter_params. (Dan)
- Adding conversion to region
- Adding conversion to dimm
v2:
- split out the conversion of util_filter_params to make things more
readable (Dan).
- Not pass in mode as util_filter_params and put back the mode check in
util_filter_walk() (Dan).
---
Dave Jiang (4):
ndctl: convert namespace actions to use util_filter_params
ndctl: convert namespace actions to use util_filter_walk()
ndctl: convert region actions to use util_filter_walk()
ndctl: convert dimm actions to use util_filter_walk()
ndctl/dimm.c | 83 ++++++++++++++---------
ndctl/namespace.c | 195 +++++++++++++++++++++++++++++------------------------
ndctl/region.c | 59 ++++++++++------
test/btt-check.sh | 2 -
util/filter.c | 5 +
util/filter.h | 23 ++++++
6 files changed, 221 insertions(+), 146 deletions(-)
--
2 years, 9 months
[PATCH v3] dax: Change return type to vm_fault_t
by Souptick Joarder
Use new return type vm_fault_t for fault and huge_fault
handler. For now, this is just documenting that the
function returns a VM_FAULT value rather than an errno.
Once all instances are converted, vm_fault_t will become
a distinct type.
Reference id -> 1c8f422059ae ("mm: change return type to
vm_fault_t")
Previously vm_insert_mixed() returns err which driver
mapped into VM_FAULT_* type. The new function
vmf_insert_mixed() will replace this inefficiency by
returning VM_FAULT_* type.
Signed-off-by: Souptick Joarder <jrdr.linux(a)gmail.com>
Reviewed-by: Matthew Wilcox <mawilcox(a)microsoft.com>
Reviewed-by: Ross Zwisler <ross.zwisler(a)linux.intel.com>
---
v2: Modified the change log
v3: Updated the change log and
added Ross in review list
drivers/dax/device.c | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 2137dbc..a122701 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -243,11 +243,11 @@ __weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff,
return -1;
}
-static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
+static vm_fault_t __dev_dax_pte_fault(struct dev_dax *dev_dax,
+ struct vm_fault *vmf)
{
struct device *dev = &dev_dax->dev;
struct dax_region *dax_region;
- int rc = VM_FAULT_SIGBUS;
phys_addr_t phys;
pfn_t pfn;
unsigned int fault_size = PAGE_SIZE;
@@ -274,17 +274,11 @@ static int __dev_dax_pte_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
pfn = phys_to_pfn_t(phys, dax_region->pfn_flags);
- rc = vm_insert_mixed(vmf->vma, vmf->address, pfn);
-
- if (rc == -ENOMEM)
- return VM_FAULT_OOM;
- if (rc < 0 && rc != -EBUSY)
- return VM_FAULT_SIGBUS;
-
- return VM_FAULT_NOPAGE;
+ return vmf_insert_mixed(vmf->vma, vmf->address, pfn);
}
-static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
+static vm_fault_t __dev_dax_pmd_fault(struct dev_dax *dev_dax,
+ struct vm_fault *vmf)
{
unsigned long pmd_addr = vmf->address & PMD_MASK;
struct device *dev = &dev_dax->dev;
@@ -335,7 +329,8 @@ static int __dev_dax_pmd_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
}
#ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
-static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
+static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
+ struct vm_fault *vmf)
{
unsigned long pud_addr = vmf->address & PUD_MASK;
struct device *dev = &dev_dax->dev;
@@ -386,13 +381,14 @@ static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
vmf->flags & FAULT_FLAG_WRITE);
}
#else
-static int __dev_dax_pud_fault(struct dev_dax *dev_dax, struct vm_fault *vmf)
+static vm_fault_t __dev_dax_pud_fault(struct dev_dax *dev_dax,
+ struct vm_fault *vmf)
{
return VM_FAULT_FALLBACK;
}
#endif /* !CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
-static int dev_dax_huge_fault(struct vm_fault *vmf,
+static vm_fault_t dev_dax_huge_fault(struct vm_fault *vmf,
enum page_entry_size pe_size)
{
int rc, id;
@@ -423,7 +419,7 @@ static int dev_dax_huge_fault(struct vm_fault *vmf,
return rc;
}
-static int dev_dax_fault(struct vm_fault *vmf)
+static vm_fault_t dev_dax_fault(struct vm_fault *vmf)
{
return dev_dax_huge_fault(vmf, PE_SIZE_PTE);
}
--
1.9.1
2 years, 9 months
转发linux-nvdimm:
by 您好:
linux-nvdimm:746894720
采购流程优化及供应商评估与管理
时间地点: 5月04-05日深圳
学员对象:高层管理者、采购部门、品管部门、物流部门、设计部门、财务部门及其他相关部门的职业经理人。
费 用:3800元
报名咨询电话:0755-61288035 手机:18890700600 (微信同号)赵先生
课程简介:
时至2018,采购职业经理人应具备哪些能力和素质?采购流程管理应该选用全责制还是分段制?供应商作假,采购方应该如何防范?采购方与供应商应该建立什么样的职业关系?在面对数十家供应商时,我们应该如何分类管理?评估新供应商时的难度和挑战有哪些?为什么我们与供应商会经常发生合同或订单纠纷?信得过的供应商还要不要加强日常管理?货期延误,我方有无责任?每年的供应商绩效评估究竟发挥了多大的作用?
课程收益:
Ø 供应商管理的挑战有哪些?
Ø 如何优化采购运作流程?
Ø 如何做好供应商的分类管理?
Ø 如何做好供应市场的调查?
Ø 如何选对我们的采购对象?
Ø 如何评估新供应商?
Ø 如何防范合同的纠纷?
Ø 如何做好供应商的日常管理?
如何评估现行供应商?
培训内容:
第一讲:供应商管理的挑战有哪些?
l 供应商参假出事,采购方有无责任
l “家丑”怎么会曝光
l 如何提升我们的采购能力及操守?
l 什么样的人适合做采购?
l 如何使采购人员具有良好的操守?
l 如何实施采购轮岗制度
l 做好轮岗制度的前提
l 完善的采购制度体系
l 外资与民企相互学习些什么?
第二讲:如何优化采购运作流程?
l 采购管理的功能流程是什么?
l ‘确定采购要求’的标准依据是什么
l 零售业的‘确定采购要求’
l 零售业确定采购要求是指:
l 进货品种越多越好还是不要太多好
l 门店应该引进何种新品
l ‘寻找供应商’时的注意事项
l 砍价与评估供应商的先后关系
l 如何做到“性价比”最高
l 砍价的方式
l “采购计划”包含哪些内容
l ‘付款’工作的主要内容
l 影响采购运作流程的因素有哪些?
l 什么是‘全责制与分段制’
l ‘全责制与分段制’的优缺点
l 老板式采购模式的利与弊
l 采购运作流程不合理的后果
l 如何做好采购运作流程的优化
l 如何将公司现行的采购运作画成流程图
l 第二步:调整流程中不合理的部分
l 第三步:调整采购岗位的设置
l 什么是聘任制专业职称评级制度
l 制造业采购岗位设置的基本模式
l 设定‘现金(紧急)采购员’的意义
l 第四步:更新“岗位职责说明书”
l 《岗位职责说明书》应包括哪些内容
l 采购人员的职责分配
第三讲:如何做好供应商的分类管理?
l 采购管理有几大类别?
l 原材料、运作性采购物品如何分类
l 采购物品分类的作用是什么?
l 分散采购好还是集中采购好?
l 同一物品的单一与多家策略
l 经销商是多好还是少好?
l 为什么要用经销商?
l 哪种物品应经销商综合化
l 集中采购的优缺点
l 买卖关系的类别
l 两类关系的采购策略区别?
l 买卖关系的确定
l 如何降低各类物品的采购成本
l 服务性供应商的分类意义是什么
l 采购物品分类的关键难度是什么
l 什么是Pareto(帕累托)分类法
l 如何进行帕累托分类?
l 第一步:对所需分析的指标,从大到小进行排序
l 第二步:计算每一物品占总体的百分率
l 第三步:计算每一物品的累积百分率
l 造成采购风险的因素有哪些?
l 不同供应市场的采购风险分析
l 不同采购类型的分类区别
l 商贸性采购的物品如何分类
l 商贸采购的战略定位
l 五类商品的采购要求
l 找厂家好还是中间商好
l 商贸采购的买卖关系确定
l 如何提高获利性
第四讲:如何做好供应市场的调查?
l 供应产品如何分类
l 如何了解供应市场的大与小
l 造成‘生产’难度的因素有哪些?
l 产品供应的地域性特征
l 生产供应厂家的数量及部分名录
l 众多供应商,我选谁?
l 行业及企业的生命周期阶段
l 行业政策与法规的影响
l 供应市场竞争的特点?
l 营销模式
l 供应链特性
l 原材料供应的特点
l 供应价格变化的影响因素
l 物价指标的类别
l 什么是CPI指标?
l 什么是PPI?
l 什么是PMI?
l 如何获取供应市场的信息?
第五讲:如何选对我们的采购对象?
l 供应商表现的分类
l 如何减少傲慢型供应商
l 工业品营销与消费品营销的区别
l 供应商的客户分类
l 供应商为何会报不同的价?
l 我们应该如何选择供应商?
l 如何减少尴尬型供应商
l 如何选择恰当的供应商生产类型
l 培养供应商与开发新供应商的比较
l 开发新供应商的原则
l 先看能力还是先看态度
l 供应商开发的三步曲
第六讲:如何评估新供应商?
l 新供应商评估的五大步骤
l 第一步:供应商评估的四大内容
l 不同类型供应商的评价侧重点
l 产品的现状
l 产品的性能与质量
l 什么是供应商的质量水平
l 如何评估供应商的保障能力?
l 管理认证的意义
l 培训评估为什么重要
l 供应商的采购管理
l 设备管理
l 供应商的内部监测与改进
l 供应商的实力?
l 评估实力的依据
l 如何评估供应商的愿望
l 不同生产类型供应商的评估重点
l 服务性供应商的特点
l 服务性供应商的评估指标
l 生产外包供应商(经销商)的评估
l 第二步:应该问谁?
l 第三步:怎么问?
l 调查问卷设计的注意事项
l 问题设计的形式
l 第四步:如何给供应商的现状打分?
l 如何制定打分的标准
l 如何计算打分的结果
l 为什么要进行权重性计算
l 评估指标的权重分析
l 如何分析调研结果?
l 新供应商是否合格的评判标准
l 第五步:新供应商评估审批表的填报
l 为什么要填报“新供应商评估审批表”
l ‘新供应商评估审批表’模版
l 什么是供应商的认证?
第七讲:如何防范合同的纠纷?
l 为什么会产生合同纠纷?
l 案例一
l 口头协议有效吗?
l 案例二
l 不同合同类型的纠纷
l 案例三
l 合同法的四项基本原则
l 案例四
l 要约与要约邀请
l 案例五
l 签了字的合同可以改吗?
l 价格经常波动的材料如何定价
l 合同定价模式
l 国际合同与国内合同的区别
第八讲:如何做好供应商的日常管理?
第一节:供应商的关系管理
l 区别对待,分类管理
l 合作型供应商的产生原因
l 如何与独家供应或依存度高的的供应商相处?
l 如何与“领导选定”的供应商相处
l 如何与“感情好,但能力较差”的供应商相处
第二节:采购订单的跟踪管理
l 实物采购订货的工作流程
l 制定采购订单时的考虑要素
l 如何确保供应商及时收到订单
l 如何跟单
l 如何把好入仓验收关
l 为什么抽样方法很重要?
l 抽样的三类方法
l 如何抽样?
l 如何取样?
l 我方‘挑着用’的后果
l 为什么会“不得不收”?
l 工厂原材料的库存策略
l 商贸产品的库存策略
l 如何跟踪服务商的服务
第三节:供应商的风险管理
l 什么是供应商的风险管理?
l 如何做好供应商的风险管理?
l 第一步:供应商不履约的原因会有哪些?
第二步:各种原因的排序性分析
l 第三步:一旦发生怎么办?
第九讲:如何做好采购管理的绩效评估?
第一节:如何有效评估供应商的
l 为什么要建立‘现用供应商’的评估体系
l 新供应商评估与现行供应商评估的区别?
l 现行供应商的评估的原则
l 供应商表现的考评指标
l 质量指标
l 如何评估服务商的服务质量
l 供应指标
l 经济指标
l 零售型供货商的经济指标
l 服务指标
l 供应商表现的评估频率
l 建立供应商电子档案库的注意事项
l 为什么要建立“供应商电子档案库”
l 如何建立“合格供应商电子档案”
l 如何判断供应商表现的好与坏
l 与它的同行比较(SWOT分析法)
l 好供应商的奖励
l 表现不佳的供应商?
第二节:如何做好采购人员的绩效评估
l 评价采购人员工作表现的三大方面
l 有无违反公司规定的行为
如何建立“采购节约奖”制度
培训讲师:张仲豪
张仲豪老师毕业于美国密西根州立大学,硕士学位,是改革开放后早期的海归派高级职业经理人。曾先后任职于美国亨氏、英国联合饼干、美国美赞臣等500强跨国公司,担任公司运作总监及其他高级管理职务。二十多年的实战经历,专长于采购与供应链管理,是国内采购物流领域中少有的集丰富海外工作经验、国内资深管理阅历及国际权威认证于一身的实战派管理与咨询专家。
张老师是国际四大职业证书授权讲师:美国注册物流师(CTL)认证、ILT国际物流职业资格认证”、CIPS国际注册采购与供应经理认证、ITC国际贸易中心授权采购与供应链管理国际资格认证中心。
2 years, 9 months
[PATCH v3 0/4] convert actions to use util_filter_walk
by Dave Jiang
util_filter_walk() does the looping through bus/dimm/region/namespace
that a lot of the operations in ndctl uses. Converting them to common
code and reduce maintenance on individual versions of the same code.
In this series we are convering namespace, region, and dimm actions.
---
v3:
- fixed some corner cases in namespace patch.
- changed param renaming to reduce change for util_filter_params. (Dan)
- Adding conversion to region
- Adding conversion to dimm
v2:
- split out the conversion of util_filter_params to make things more
readable (Dan).
- Not pass in mode as util_filter_params and put back the mode check in
util_filter_walk() (Dan).
Dave Jiang (4):
ndctl: convert namespace actions to use util_filter_params
ndctl: convert namespace actions to use util_filter_walk()
ndctl: convert region actions to use util_filter_walk()
ndctl: convert dimm actions to use util_filter_walk()
ndctl/dimm.c | 83 ++++++++++++++---------
ndctl/namespace.c | 195 +++++++++++++++++++++++++++++------------------------
ndctl/region.c | 59 ++++++++++------
test/btt-check.sh | 2 -
util/filter.c | 5 +
util/filter.h | 23 ++++++
6 files changed, 221 insertions(+), 146 deletions(-)
--
2 years, 9 months