Outstanding Ventura CA 3D-Printing Opportunities
by Nicholas Meyler
New Exclusive Retained Searches from
Wingate Dunross, Inc.
My new client in Ventura, CA has retained me on a set of exciting new searches in the field of 3D Printing, one of the hottest growth fields in the high-technology world.
Imagine a world where everybody can create.
Imagine the fastest and the most accurate 3D Printer.
Imagine a 3D Printer really easy-to-use.
A 3D Printer perfect for the industrial and professional users.
A 3D Printer driven by an Intelligent System, by a Cognitive System.
The Best Technology in The Best Design.
And now we need your help.
About My Client:
My Client is a 3D printing startup that integrates the latest exponential technologies in components, sensors, optical systems and chemistry to apply Moore’s Law to a new, proprietary 3D Printing technology. The result is a desktop, professional 3D Printer that takes 3D Printing from hours to minutes making it FASTER, with a LARGER build volume, at HIGHER resolutions and a LOWER cost. They're doing this with a user experience and a design oriented approach making their 3D technology elegant and compact.
Their 3D printer has been designed to offer the best and the smartest ultra-fast 3D Printing experience, from a clean cartridge system to a complete cognitive hardware and stand-alone technology that let users adopt this machine quickly in any kind of environment and for any type of usage.
(1) SOFTWARE ENGINEER
VENTURA (CA) | ENGINEERING | FULL-TIME
Job Description:
The Software Engineer will be responsible for the design, development, implementation and maintenance of software for the 3D Printer.
Responsibilities:
Create technical specifications and develop software solutions based upon the specifications
Design, develop and implement software and associated features on the 3D Printer
Design and develop user interfaces and application frameworks that support communication with the 3D Printer Hardware and Firmware, 3D print file placement, file viewing, file editing and assigning process values
Collaborate and work closely with Systems, Mechanical, Electrical and Process Engineers to develop and implement the software features desired by those Engineers
Perform design and code reviews, unit-tests and system integrations
Develop software requirements and software project plan
Support QA testing of the developed software
Participate in software alpha and beta test programs
Experience:
3 to 5 years of experience in the relevant Engineering discipline
Requirements:
BS or MS in Computer Science or Computer Engineering
Three years of experience developing commercial software applications
Proficient in C#, .NET and C++
Excellent Object Oriented Design skills
Good knowledge of Operating Systems
Excellent knowledge of Embedded Systems
Good understanding of Communication Protocols
Experience with Application frameworks and design patterns
Experience with GUI Development using frameworks
Proficiency using modern software development processes, including software configuration management tools and defect tracking tools
Excellent documentation skills, communication skills and collaboration skills
(2) PRINT PROCESS ENGINEER
VENTURA (CA) | ENGINEERING | FULL-TIME
Job Description:
The Process Engineer will be responsible for the development and optimization of processes for the 3D Printer and its Print technology involving new equipment and new materials.
Responsibilities:
Develop, optimize and test processes for 3D Print technology involving associated hardware, software, materials and post-processing
Understand the complex system interactions between the software, hardware and materials as they relate to the print process
Heavily interact with Materials, Software, Mechanical, Electrical and Optical Engineers, while developing and optimizing processes with variable parameters using statistical methods
Heavily participate in printer integration activities involving various Engineering disciplines
Design test plans and execute testing of the 3D Printer’s hardware, software and materials
Evaluate printer performance and suggest areas for improvement
Assist various Engineers to scale up hardware and materials for manufactureability
Independently conduct hands-on experiments and develop thorough reports on the research
Participate in software, hardware and materials alpha and beta test programs
Experience:
3 to 5 years of experience in the relevant Engineering discipline
Requirements:
BS or MS in Chemical, Materials, Mechanical or Electrical Engineering
Strong analytical and problem solving skills to work on problems of diverse scope where analysis of data requires evaluation of multiple variables simultaneously
Experience in selecting methods and techniques for defining problems and obtaining solutions
Ability to identify the various abstract and concrete variables that control the process and determine and optimize the effect of those variables on the print process
Ability to partner with various Engineering cross functions and identify and report relevant problems
Experience and deep knowledge about statistics and process control
Ability to analyze the collected data and present the analysis in a statistical format
Ability to write reports, process guides and manuals
Strong communication, interpersonal and collaborative skills
(3) SYSTEMS ENGINEER
VENTURA (CA) | ENGINEERING | FULL-TIME
Job Description:
The Systems Engineer will be responsible for the system and subsystem (electrical and mechanical) architecture and design of their 3D Printer including conception, analysis, design, integration, optimization and testing of the System.
Responsibilities:
Responsible for analysis, design, building and integration of mechanical and electrical systems and subsystems for the 3D Printer
Collaborate directly with other Engineers to specify system requirements, implement designs and troubleshoot issues
Participate in design and development of motion control systems, motor drive electronics and micro-processor boards
Conduct design review with other Engineers and prepare system design documents
Conceptualize test plans for end-to-end validation strategy around all design changes that affect the printing process
Provide support for electrical and mechanical systems and subsystems from concept through production
Identify appropriate vendors and build initial relationships for procurement
Experience:
3 to 5 years of experience in the relevant Engineering discipline
Requirements:
BS or MS in Electrical or Mechanical Engineering
Proven experience in system requirements specification and design document preparation.
Strong knowledge of Electrical Engineering and Mechanical Engineering principles, processes and tools
Knowledge in electrical subsystem design
Strong understanding and knowledge of motion control systems and electric motors like Stepper and Servo motors
Experience developing motor drive electronics for different motor types
Circuit board design experience utilizing micro-processor based hardware – preferred but not required
Ability to develop low level firmware for processor based control boards
Project management capabilities - Ability to lead tasks, prioritizing actions, time management
Experience with CAD is required (preferably with SolidWorks)
Hands on attitude with the ability to operate standard soldering and electrical test equipment
Excellent documentation skills, communication skills and collaboration skills
Another Client is looking for a
(4) Senior Polymer Scientist (Cleveland, OH)
Duties/Responsibilities:
My exciting new Client is searching for a dynamic individual with experience in organic and polymer synthesis, and polymer application development. This Senior Polymer Scientist will be part of an application development group of scientists and chemists. Responsibilities will include conducting laboratory synthesis and polymer characterization, interpreting and reporting results, maintaining instrumentation, documenting procedures, validating test methods, developing new applications, and advising others on test method capabilities. They may serve as the project and customer point person for internal and external collaborations.
Education/Experience Requirements:
Ph.D. or M.S. in Polymer Chemistry, Materials Science, or Chemistry
5+ years of experience in polymer application development for microelectronics or other high value markets (e.g., display technologies, silicon wafer/chip coatings, OLED, biomedical applications, etc.)
Track record of successfully driving research and development projects to commercial success
Strong understanding of structure-property relationships for improvement of mechanical properties
Knowledge of polymer synthesis techniques (e.g., ROMP, organometallic catalysis, vinyl addition and free radical polymerization, condensation polymerization, etc.)
Understanding of methods to prepare photo-definable materials (e.g., positive-tone, negative-tone)
Familiarity with formulation chemistry (e.g. adhesion promoters, antioxidants, etc.)
Proficient with cleanroom equipment (e.g., spin-coating, photo-exposure alignment tools, profilometry, laser microscope, reactive ion-etch, sputtering, electroplating, etc.)
Familiarity with statistical analysis and Design of Experiments
Understanding of methods to characterize chemicals and materials by Instron, DSC, DMA, TGA, DRM, GPC, HPLC and NMR
Proven publication track record
Proven capability of working with patent attorney in scoping out the invention and drafting new patent applications
Willingness to spend majority of time in laboratory
Strong knowledge of chemical properties, hazards and safe handling practices
Proficiency in Japanese would be advantageous
General Skills and Physical Requirements:
Proficiency in MS Outlook, Word, Excel and PowerPoint
Good written and verbal communication skills
Good attention to detail and keen observation skills
Good interpersonal skills
Ability to maintain thorough, accurate records
Good mechanical aptitude
Ability to multi-task
Action-oriented
Manual dexterity required to use syringes and to operate and maintain instruments
Able to stand for prolonged periods of time, for up to 2 consecutive hours
Company Profile:
This Client is a wholly-owned subsidiary of a large corporation which is a pioneer in plastics with over 6,000 employees and $2Bn in annual sales. They are involved in the development of a novel platform of polymers based on cyclic olefins that are polymerized using a proprietary class of organometallic catalysts. Application areas include the semiconductor, optoelectronic and electronic packaging markets. Ongoing development and commercial activities with multiple Fortune 500 companies in the micro-electronics and semi-conductor industries is the primary business focus.
Benefits:
A wide range of competitive benefits including:
Comprehensive medical, dental, life insurance and disability plans available on the date of hire
Vacation and Holiday pay available on the date of hire
Competitive wages
401 (K) and Profit Sharing Plan
A great work environment
If you are interested in applying for one or more of these positions, please respond with a resume. Referrals and recommendations are also welcomed.
Best Regards,
Nicholas Meyler
President/GM, Technology
Wingate Dunross, Inc.
ph (818)597-3200 ext. 211
<nickm(a)wdsearch.com>
http://app.streamsend.com/private/u4Kt/nKR/rPOzpjo/unsubscribe/28725495
5 years, 5 months
Re: [PATCH v3] libnvdimm: fix clear poison locking with spinlock and mempool
by Dan Williams
On Tue, Apr 11, 2017 at 3:19 PM, Dave Jiang <dave.jiang(a)intel.com> wrote:
> The following warning results from holding a lane spinlock,
> preempt_disable(), or the btt map spinlock and then trying to take the
> reconfig_mutex to walk the poison list and potentially add new entries.
>
> BUG: sleeping function called from invalid context at kernel/locking/mutex.
> c:747
> in_atomic(): 1, irqs_disabled(): 0, pid: 17159, name: dd
> [..]
> Call Trace:
> dump_stack+0x85/0xc8
> ___might_sleep+0x184/0x250
> __might_sleep+0x4a/0x90
> __mutex_lock+0x58/0x9b0
> ? nvdimm_bus_lock+0x21/0x30 [libnvdimm]
> ? __nvdimm_bus_badblocks_clear+0x2f/0x60 [libnvdimm]
> ? acpi_nfit_forget_poison+0x79/0x80 [nfit]
> ? _raw_spin_unlock+0x27/0x40
> mutex_lock_nested+0x1b/0x20
> nvdimm_bus_lock+0x21/0x30 [libnvdimm]
> nvdimm_forget_poison+0x25/0x50 [libnvdimm]
> nvdimm_clear_poison+0x106/0x140 [libnvdimm]
> nsio_rw_bytes+0x164/0x270 [libnvdimm]
> btt_write_pg+0x1de/0x3e0 [nd_btt]
> ? blk_queue_enter+0x30/0x290
> btt_make_request+0x11a/0x310 [nd_btt]
> ? blk_queue_enter+0xb7/0x290
> ? blk_queue_enter+0x30/0x290
> generic_make_request+0x118/0x3b0
>
> Two things are done to address this issue. First, we introduce a spinlock to
> protect the poison list. This allows us to not having to acquire the
> reconfig_mutex for touching the poison list. Second, we allocate the poison
> entries using GFP_NOWAIT and avoid the sleep with GFP_KERNEL.
Need to drop the mempool references out of the subject and changelog,
also I only think we should use GFP_NOWAIT in the I/O path. In the
other add_poison() paths that are currently using GFP_KERNEL we can
just drop the lock to do the allocation. That limits the damage of a
memory allocation failure to clearing errors, not tracking new errors.
5 years, 5 months
[PATCH v3] libnvdimm: fix clear poison locking with spinlock and mempool
by Dave Jiang
The following warning results from holding a lane spinlock,
preempt_disable(), or the btt map spinlock and then trying to take the
reconfig_mutex to walk the poison list and potentially add new entries.
BUG: sleeping function called from invalid context at kernel/locking/mutex.
c:747
in_atomic(): 1, irqs_disabled(): 0, pid: 17159, name: dd
[..]
Call Trace:
dump_stack+0x85/0xc8
___might_sleep+0x184/0x250
__might_sleep+0x4a/0x90
__mutex_lock+0x58/0x9b0
? nvdimm_bus_lock+0x21/0x30 [libnvdimm]
? __nvdimm_bus_badblocks_clear+0x2f/0x60 [libnvdimm]
? acpi_nfit_forget_poison+0x79/0x80 [nfit]
? _raw_spin_unlock+0x27/0x40
mutex_lock_nested+0x1b/0x20
nvdimm_bus_lock+0x21/0x30 [libnvdimm]
nvdimm_forget_poison+0x25/0x50 [libnvdimm]
nvdimm_clear_poison+0x106/0x140 [libnvdimm]
nsio_rw_bytes+0x164/0x270 [libnvdimm]
btt_write_pg+0x1de/0x3e0 [nd_btt]
? blk_queue_enter+0x30/0x290
btt_make_request+0x11a/0x310 [nd_btt]
? blk_queue_enter+0xb7/0x290
? blk_queue_enter+0x30/0x290
generic_make_request+0x118/0x3b0
Two things are done to address this issue. First, we introduce a spinlock to
protect the poison list. This allows us to not having to acquire the
reconfig_mutex for touching the poison list. Second, we allocate the poison
entries using GFP_NOWAIT and avoid the sleep with GFP_KERNEL.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
drivers/nvdimm/bus.c | 7 ++++---
drivers/nvdimm/core.c | 25 ++++++++-----------------
drivers/nvdimm/nd-core.h | 1 +
include/linux/libnvdimm.h | 2 --
4 files changed, 13 insertions(+), 22 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 5ad2e59..d214ac44 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -296,6 +296,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
init_waitqueue_head(&nvdimm_bus->probe_wait);
nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
mutex_init(&nvdimm_bus->reconfig_mutex);
+ spin_lock_init(&nvdimm_bus->poison_lock);
if (nvdimm_bus->id < 0) {
kfree(nvdimm_bus);
return NULL;
@@ -364,9 +365,9 @@ static int nd_bus_remove(struct device *dev)
nd_synchronize();
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ spin_lock(&nvdimm_bus->poison_lock);
free_poison_list(&nvdimm_bus->poison_list);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
nvdimm_bus_destroy_ndctl(nvdimm_bus);
@@ -990,7 +991,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (clear_err->cleared) {
/* clearing the poison list we keep track of */
- __nvdimm_forget_poison(nvdimm_bus, clear_err->address,
+ nvdimm_forget_poison(nvdimm_bus, clear_err->address,
clear_err->cleared);
/* now sync the badblocks lists */
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 40a3da0..9567b08 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -539,7 +539,7 @@ static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
struct nd_poison *pl;
if (list_empty(&nvdimm_bus->poison_list))
- return add_poison(nvdimm_bus, addr, length, GFP_KERNEL);
+ return add_poison(nvdimm_bus, addr, length, GFP_NOWAIT);
/*
* There is a chance this is a duplicate, check for those first.
@@ -559,30 +559,29 @@ static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
* as any overlapping ranges will get resolved when the list is consumed
* and converted to badblocks
*/
- return add_poison(nvdimm_bus, addr, length, GFP_KERNEL);
+ return add_poison(nvdimm_bus, addr, length, GFP_NOWAIT);
}
int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
{
int rc;
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ spin_lock(&nvdimm_bus->poison_lock);
rc = bus_add_poison(nvdimm_bus, addr, length);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
return rc;
}
EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
-void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
+void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
unsigned int len)
{
struct list_head *poison_list = &nvdimm_bus->poison_list;
u64 clr_end = start + len - 1;
struct nd_poison *pl, *next;
- lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
-
+ spin_lock(&nvdimm_bus->poison_lock);
WARN_ON_ONCE(list_empty(poison_list));
/*
@@ -629,21 +628,13 @@ void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
u64 new_len = pl_end - new_start + 1;
/* Add new entry covering the right half */
- add_poison(nvdimm_bus, new_start, new_len, GFP_NOIO);
+ add_poison(nvdimm_bus, new_start, new_len, GFP_NOWAIT);
/* Adjust this entry to cover the left half */
pl->length = start - pl->start;
continue;
}
}
-}
-EXPORT_SYMBOL_GPL(__nvdimm_forget_poison);
-
-void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
- phys_addr_t start, unsigned int len)
-{
- nvdimm_bus_lock(&nvdimm_bus->dev);
- __nvdimm_forget_poison(nvdimm_bus, start, len);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
}
EXPORT_SYMBOL_GPL(nvdimm_forget_poison);
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 8623e57..4c4bd20 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -32,6 +32,7 @@ struct nvdimm_bus {
struct list_head poison_list;
struct list_head mapping_list;
struct mutex reconfig_mutex;
+ spinlock_t poison_lock;
};
struct nvdimm {
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 1c609e8..98b2076 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -122,8 +122,6 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length);
void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
phys_addr_t start, unsigned int len);
-void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
- phys_addr_t start, unsigned int len);
struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
struct nvdimm_bus_descriptor *nfit_desc);
void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
5 years, 5 months
[PATCH v2] libnvdimm: fix clear poison locking with spinlock and mempool
by Dave Jiang
The following warning results from holding a lane spinlock,
preempt_disable(), or the btt map spinlock and then trying to take the
reconfig_mutex to walk the poison list and potentially add new entries.
BUG: sleeping function called from invalid context at kernel/locking/mutex.
c:747
in_atomic(): 1, irqs_disabled(): 0, pid: 17159, name: dd
[..]
Call Trace:
dump_stack+0x85/0xc8
___might_sleep+0x184/0x250
__might_sleep+0x4a/0x90
__mutex_lock+0x58/0x9b0
? nvdimm_bus_lock+0x21/0x30 [libnvdimm]
? __nvdimm_bus_badblocks_clear+0x2f/0x60 [libnvdimm]
? acpi_nfit_forget_poison+0x79/0x80 [nfit]
? _raw_spin_unlock+0x27/0x40
mutex_lock_nested+0x1b/0x20
nvdimm_bus_lock+0x21/0x30 [libnvdimm]
nvdimm_forget_poison+0x25/0x50 [libnvdimm]
nvdimm_clear_poison+0x106/0x140 [libnvdimm]
nsio_rw_bytes+0x164/0x270 [libnvdimm]
btt_write_pg+0x1de/0x3e0 [nd_btt]
? blk_queue_enter+0x30/0x290
btt_make_request+0x11a/0x310 [nd_btt]
? blk_queue_enter+0xb7/0x290
? blk_queue_enter+0x30/0x290
generic_make_request+0x118/0x3b0
Two things are done to address this issue. First, we introduce a spinlock to
protect the poison list. This allows us to not having to acquire the
reconfig_mutex for touching the poison list. Second, we allocate the poison
entries using GFP_NOWAIT and avoid the sleep with GFP_KERNEL.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
drivers/nvdimm/bus.c | 12 +++++++-----
drivers/nvdimm/core.c | 25 ++++++++-----------------
drivers/nvdimm/nd-core.h | 1 +
include/linux/libnvdimm.h | 2 --
4 files changed, 16 insertions(+), 24 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 5ad2e59..fe41146 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -296,6 +296,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
init_waitqueue_head(&nvdimm_bus->probe_wait);
nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
mutex_init(&nvdimm_bus->reconfig_mutex);
+ spin_lock_init(&nvdimm_bus->poison_lock);
if (nvdimm_bus->id < 0) {
kfree(nvdimm_bus);
return NULL;
@@ -342,8 +343,9 @@ static int child_unregister(struct device *dev, void *data)
return 0;
}
-static void free_poison_list(struct list_head *poison_list)
+static void free_poison_list(struct nvdimm_bus *nvdimm_bus)
{
+ struct list_head *poison_list = &nvdimm_bus->poison_list;
struct nd_poison *pl, *next;
list_for_each_entry_safe(pl, next, poison_list, list) {
@@ -364,9 +366,9 @@ static int nd_bus_remove(struct device *dev)
nd_synchronize();
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
- nvdimm_bus_lock(&nvdimm_bus->dev);
- free_poison_list(&nvdimm_bus->poison_list);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_lock(&nvdimm_bus->poison_lock);
+ free_poison_list(nvdimm_bus);
+ spin_unlock(&nvdimm_bus->poison_lock);
nvdimm_bus_destroy_ndctl(nvdimm_bus);
@@ -990,7 +992,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (clear_err->cleared) {
/* clearing the poison list we keep track of */
- __nvdimm_forget_poison(nvdimm_bus, clear_err->address,
+ nvdimm_forget_poison(nvdimm_bus, clear_err->address,
clear_err->cleared);
/* now sync the badblocks lists */
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 40a3da0..9567b08 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -539,7 +539,7 @@ static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
struct nd_poison *pl;
if (list_empty(&nvdimm_bus->poison_list))
- return add_poison(nvdimm_bus, addr, length, GFP_KERNEL);
+ return add_poison(nvdimm_bus, addr, length, GFP_NOWAIT);
/*
* There is a chance this is a duplicate, check for those first.
@@ -559,30 +559,29 @@ static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
* as any overlapping ranges will get resolved when the list is consumed
* and converted to badblocks
*/
- return add_poison(nvdimm_bus, addr, length, GFP_KERNEL);
+ return add_poison(nvdimm_bus, addr, length, GFP_NOWAIT);
}
int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
{
int rc;
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ spin_lock(&nvdimm_bus->poison_lock);
rc = bus_add_poison(nvdimm_bus, addr, length);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
return rc;
}
EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
-void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
+void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
unsigned int len)
{
struct list_head *poison_list = &nvdimm_bus->poison_list;
u64 clr_end = start + len - 1;
struct nd_poison *pl, *next;
- lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
-
+ spin_lock(&nvdimm_bus->poison_lock);
WARN_ON_ONCE(list_empty(poison_list));
/*
@@ -629,21 +628,13 @@ void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
u64 new_len = pl_end - new_start + 1;
/* Add new entry covering the right half */
- add_poison(nvdimm_bus, new_start, new_len, GFP_NOIO);
+ add_poison(nvdimm_bus, new_start, new_len, GFP_NOWAIT);
/* Adjust this entry to cover the left half */
pl->length = start - pl->start;
continue;
}
}
-}
-EXPORT_SYMBOL_GPL(__nvdimm_forget_poison);
-
-void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
- phys_addr_t start, unsigned int len)
-{
- nvdimm_bus_lock(&nvdimm_bus->dev);
- __nvdimm_forget_poison(nvdimm_bus, start, len);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
}
EXPORT_SYMBOL_GPL(nvdimm_forget_poison);
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 8623e57..4c4bd20 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -32,6 +32,7 @@ struct nvdimm_bus {
struct list_head poison_list;
struct list_head mapping_list;
struct mutex reconfig_mutex;
+ spinlock_t poison_lock;
};
struct nvdimm {
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 1c609e8..98b2076 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -122,8 +122,6 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length);
void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
phys_addr_t start, unsigned int len);
-void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
- phys_addr_t start, unsigned int len);
struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
struct nvdimm_bus_descriptor *nfit_desc);
void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
5 years, 5 months
[PATCH] libnvdimm: fix clear poison locking with spinlock and mempool
by Dave Jiang
The following warning results from holding a lane spinlock,
preempt_disable(), or the btt map spinlock and then trying to take the
reconfig_mutex to walk the poison list and potentially add new entries.
BUG: sleeping function called from invalid context at kernel/locking/mutex.
c:747
in_atomic(): 1, irqs_disabled(): 0, pid: 17159, name: dd
[..]
Call Trace:
dump_stack+0x85/0xc8
___might_sleep+0x184/0x250
__might_sleep+0x4a/0x90
__mutex_lock+0x58/0x9b0
? nvdimm_bus_lock+0x21/0x30 [libnvdimm]
? __nvdimm_bus_badblocks_clear+0x2f/0x60 [libnvdimm]
? acpi_nfit_forget_poison+0x79/0x80 [nfit]
? _raw_spin_unlock+0x27/0x40
mutex_lock_nested+0x1b/0x20
nvdimm_bus_lock+0x21/0x30 [libnvdimm]
nvdimm_forget_poison+0x25/0x50 [libnvdimm]
nvdimm_clear_poison+0x106/0x140 [libnvdimm]
nsio_rw_bytes+0x164/0x270 [libnvdimm]
btt_write_pg+0x1de/0x3e0 [nd_btt]
? blk_queue_enter+0x30/0x290
btt_make_request+0x11a/0x310 [nd_btt]
? blk_queue_enter+0xb7/0x290
? blk_queue_enter+0x30/0x290
generic_make_request+0x118/0x3b0
Two things are done to address this issue. First, we introduce a spinlock to
protect the poison list. This allows us to not having to acquire the
reconfig_mutex for touching the poison list. Second, we introduce a mempool
for the poison list entry allocation. This provides a pool of entries we can
allocate from. Once we run out, we will acquire entries via GFP_NOWAIT to
avoid the sleep with GFP_KERNEL allocation.
Signed-off-by: Dave Jiang <dave.jiang(a)intel.com>
---
drivers/nvdimm/bus.c | 16 ++++++++-----
drivers/nvdimm/core.c | 56 +++++++++++++++++++++++++++------------------
drivers/nvdimm/nd-core.h | 1 +
include/linux/libnvdimm.h | 2 --
4 files changed, 45 insertions(+), 30 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 5ad2e59..dc9b403 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -24,6 +24,7 @@
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/mm.h>
+#include <linux/mempool.h>
#include <linux/nd.h>
#include "nd-core.h"
#include "nd.h"
@@ -33,6 +34,7 @@ int nvdimm_major;
static int nvdimm_bus_major;
static struct class *nd_class;
static DEFINE_IDA(nd_ida);
+extern mempool_t *poison_mempool;
static int to_nd_device_type(struct device *dev)
{
@@ -296,6 +298,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
init_waitqueue_head(&nvdimm_bus->probe_wait);
nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
mutex_init(&nvdimm_bus->reconfig_mutex);
+ spin_lock_init(&nvdimm_bus->poison_lock);
if (nvdimm_bus->id < 0) {
kfree(nvdimm_bus);
return NULL;
@@ -342,13 +345,14 @@ static int child_unregister(struct device *dev, void *data)
return 0;
}
-static void free_poison_list(struct list_head *poison_list)
+static void free_poison_list(struct nvdimm_bus *nvdimm_bus)
{
+ struct list_head *poison_list = &nvdimm_bus->poison_list;
struct nd_poison *pl, *next;
list_for_each_entry_safe(pl, next, poison_list, list) {
list_del(&pl->list);
- kfree(pl);
+ mempool_free(pl, poison_mempool);
}
list_del_init(poison_list);
}
@@ -364,9 +368,9 @@ static int nd_bus_remove(struct device *dev)
nd_synchronize();
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
- nvdimm_bus_lock(&nvdimm_bus->dev);
- free_poison_list(&nvdimm_bus->poison_list);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_lock(&nvdimm_bus->poison_lock);
+ free_poison_list(nvdimm_bus);
+ spin_unlock(&nvdimm_bus->poison_lock);
nvdimm_bus_destroy_ndctl(nvdimm_bus);
@@ -990,7 +994,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (clear_err->cleared) {
/* clearing the poison list we keep track of */
- __nvdimm_forget_poison(nvdimm_bus, clear_err->address,
+ nvdimm_forget_poison(nvdimm_bus, clear_err->address,
clear_err->cleared);
/* now sync the badblocks lists */
diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c
index 40a3da0..8475578 100644
--- a/drivers/nvdimm/core.c
+++ b/drivers/nvdimm/core.c
@@ -21,11 +21,15 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/mempool.h>
#include "nd-core.h"
#include "nd.h"
LIST_HEAD(nvdimm_bus_list);
DEFINE_MUTEX(nvdimm_bus_list_mutex);
+struct kmem_cache *poison_cache;
+mempool_t *poison_mempool;
+
void nvdimm_bus_lock(struct device *dev)
{
@@ -518,12 +522,11 @@ void nvdimm_badblocks_populate(struct nd_region *nd_region,
}
EXPORT_SYMBOL_GPL(nvdimm_badblocks_populate);
-static int add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length,
- gfp_t flags)
+static int add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
{
struct nd_poison *pl;
- pl = kzalloc(sizeof(*pl), flags);
+ pl = mempool_alloc(poison_mempool, GFP_NOWAIT);
if (!pl)
return -ENOMEM;
@@ -539,7 +542,7 @@ static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
struct nd_poison *pl;
if (list_empty(&nvdimm_bus->poison_list))
- return add_poison(nvdimm_bus, addr, length, GFP_KERNEL);
+ return add_poison(nvdimm_bus, addr, length);
/*
* There is a chance this is a duplicate, check for those first.
@@ -559,30 +562,29 @@ static int bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
* as any overlapping ranges will get resolved when the list is consumed
* and converted to badblocks
*/
- return add_poison(nvdimm_bus, addr, length, GFP_KERNEL);
+ return add_poison(nvdimm_bus, addr, length);
}
int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length)
{
int rc;
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ spin_lock(&nvdimm_bus->poison_lock);
rc = bus_add_poison(nvdimm_bus, addr, length);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
return rc;
}
EXPORT_SYMBOL_GPL(nvdimm_bus_add_poison);
-void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
+void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
unsigned int len)
{
struct list_head *poison_list = &nvdimm_bus->poison_list;
u64 clr_end = start + len - 1;
struct nd_poison *pl, *next;
- lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
-
+ spin_lock(&nvdimm_bus->poison_lock);
WARN_ON_ONCE(list_empty(poison_list));
/*
@@ -604,7 +606,7 @@ void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
/* Delete completely overlapped poison entries */
if ((pl->start >= start) && (pl_end <= clr_end)) {
list_del(&pl->list);
- kfree(pl);
+ mempool_free(pl, poison_mempool);
continue;
}
/* Adjust start point of partially cleared entries */
@@ -629,21 +631,13 @@ void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus, phys_addr_t start,
u64 new_len = pl_end - new_start + 1;
/* Add new entry covering the right half */
- add_poison(nvdimm_bus, new_start, new_len, GFP_NOIO);
+ add_poison(nvdimm_bus, new_start, new_len);
/* Adjust this entry to cover the left half */
pl->length = start - pl->start;
continue;
}
}
-}
-EXPORT_SYMBOL_GPL(__nvdimm_forget_poison);
-
-void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
- phys_addr_t start, unsigned int len)
-{
- nvdimm_bus_lock(&nvdimm_bus->dev);
- __nvdimm_forget_poison(nvdimm_bus, start, len);
- nvdimm_bus_unlock(&nvdimm_bus->dev);
+ spin_unlock(&nvdimm_bus->poison_lock);
}
EXPORT_SYMBOL_GPL(nvdimm_forget_poison);
@@ -680,9 +674,21 @@ static __init int libnvdimm_init(void)
{
int rc;
+ poison_cache = kmem_cache_create("nvdimm_bus_poison",
+ sizeof(struct nd_poison), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!poison_cache)
+ return -ENOMEM;
+
+ poison_mempool = mempool_create_slab_pool(SZ_4K, poison_cache);
+ if (!poison_mempool) {
+ rc = -ENOMEM;
+ goto err_mempool;
+ }
+
rc = nvdimm_bus_init();
if (rc)
- return rc;
+ goto err_bus;
rc = nvdimm_init();
if (rc)
goto err_dimm;
@@ -694,6 +700,10 @@ static __init int libnvdimm_init(void)
nvdimm_exit();
err_dimm:
nvdimm_bus_exit();
+ err_bus:
+ mempool_destroy(poison_mempool);
+ err_mempool:
+ kmem_cache_destroy(poison_cache);
return rc;
}
@@ -705,6 +715,8 @@ static __exit void libnvdimm_exit(void)
nvdimm_bus_exit();
nd_region_devs_exit();
nvdimm_devs_exit();
+ mempool_destroy(poison_mempool);
+ kmem_cache_destroy(poison_cache);
}
MODULE_LICENSE("GPL v2");
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 8623e57..4c4bd20 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -32,6 +32,7 @@ struct nvdimm_bus {
struct list_head poison_list;
struct list_head mapping_list;
struct mutex reconfig_mutex;
+ spinlock_t poison_lock;
};
struct nvdimm {
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 1c609e8..98b2076 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -122,8 +122,6 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
int nvdimm_bus_add_poison(struct nvdimm_bus *nvdimm_bus, u64 addr, u64 length);
void nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
phys_addr_t start, unsigned int len);
-void __nvdimm_forget_poison(struct nvdimm_bus *nvdimm_bus,
- phys_addr_t start, unsigned int len);
struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
struct nvdimm_bus_descriptor *nfit_desc);
void nvdimm_bus_unregister(struct nvdimm_bus *nvdimm_bus);
5 years, 5 months
[RFC PATCH] Report the Health Status Detail for the HPE1 DSM family
by Linda Knippers
Dan,
This is an RFC because I'd like some initial feedback on the
approach. I think this is what you had in mind from your last
exchanges with Brian but I wanted to check a few things before
going too far.
1) Do we want to export a library function for what could be a long
list of DSM-family-specific health information? I think there
could be some common information between the HPE1 and MSFT DSM
but much will not be common.
2) If we do export the functions, would we need to also export
the ndctl-hpe1.h include file or consolidate the information into
an already exported file?
3) Do you want json-smart.c to keep growing or should new smart
functions provide their own matching json functions?
4) The code in json-smart.c with a macro was a quick prototype
but if you have feedback on the json parts, that would be appreciated.
Right now the detail is reported as a string if all is well and an
array if there are errors. I'm not sure about that or whether
the strings should have spaces.
Anyway, here's the patch ...
This patch adds a new interface to provide Health Status Detail.
This field is reported as part of the Smart Health with the HPE1
DSM family so the function for the Intel family is NULL. If
the field is available, the ndctl --health option will decode
the bits that make up the field.
On a healthy device, the output would look something like:
{
"dev":"nmem0",
"id":"802c-01-1521-b300bdbc",
"health":{
"health_state":"ok",
"temperature_celsius":25.000000,
"spares_percentage":99,
"alarm_temperature":false,
"alarm_spares":false,
"temperature_threshold":50.000000,
"spares_threshold":20,
"life_used_percentage":2,
"shutdown_state":"clean",
"health_status_detail":"ok"
}
}
A device with every possible error could look like this:
{
"dev":"nmem0",
"id":"802c-01-1521-b300bdbc",
"health":{
"health_state":"ok",
"temperature_celsius":25.000000,
"spares_percentage":99,
"alarm_temperature":false,
"alarm_spares":false,
"temperature_threshold":50.000000,
"spares_threshold":20,
"life_used_percentage":2,
"shutdown_state":"clean",
"health_status_detail":[
"energy source error",
"controller error",
"UC ECC error",
"CE trip",
"save error",
"restore error",
"arm error",
"erase error",
"configuration error",
"firmware error",
"vendor specific error"
]
}
}
---
ndctl/lib/libndctl-hpe1.c | 12 ++++++++++++
ndctl/lib/libndctl-private.h | 1 +
ndctl/lib/libndctl-smart.c | 2 ++
ndctl/lib/libndctl.sym | 1 +
ndctl/libndctl.h.in | 5 +++++
ndctl/ndctl.h | 1 +
ndctl/util/json-smart.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 68 insertions(+)
diff --git a/ndctl/lib/libndctl-hpe1.c b/ndctl/lib/libndctl-hpe1.c
index ec54252..23b76a4 100644
--- a/ndctl/lib/libndctl-hpe1.c
+++ b/ndctl/lib/libndctl-hpe1.c
@@ -63,6 +63,7 @@ static struct ndctl_cmd *hpe1_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_USED_VALID;
hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_SHUTDOWN_VALID;
hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_VENDOR_VALID;
+ hpe1->u.smart.in_valid_flags |= NDN_HPE1_SMART_DETAIL_VALID;
cmd->firmware_status = &hpe1->u.smart.status;
@@ -104,6 +105,8 @@ static unsigned int hpe1_cmd_smart_get_flags(struct ndctl_cmd *cmd)
flags |= ND_SMART_SHUTDOWN_VALID;
if (hpe1flags & NDN_HPE1_SMART_VENDOR_VALID)
flags |= ND_SMART_VENDOR_VALID;
+ if (hpe1flags & NDN_HPE1_SMART_DETAIL_VALID)
+ flags |= ND_SMART_DETAIL_VALID;
return flags;
}
@@ -282,6 +285,14 @@ static unsigned int hpe1_cmd_smart_threshold_get_spares(struct ndctl_cmd *cmd)
return CMD_HPE1_SMART_THRESH(cmd)->spare_block_threshold;
}
+static unsigned int hpe1_cmd_smart_get_detail(struct ndctl_cmd *cmd)
+{
+ if (hpe1_smart_valid(cmd) < 0)
+ return UINT_MAX;
+
+ return CMD_HPE1_SMART(cmd)->mod_hlth_stat;
+}
+
struct ndctl_smart_ops * const hpe1_smart_ops = &(struct ndctl_smart_ops) {
.new_smart = hpe1_dimm_cmd_new_smart,
@@ -298,4 +309,5 @@ struct ndctl_smart_ops * const hpe1_smart_ops = &(struct ndctl_smart_ops) {
.smart_threshold_get_alarm_control = hpe1_cmd_smart_threshold_get_alarm_control,
.smart_threshold_get_temperature = hpe1_cmd_smart_threshold_get_temperature,
.smart_threshold_get_spares = hpe1_cmd_smart_threshold_get_spares,
+ .smart_get_detail = hpe1_cmd_smart_get_detail,
};
diff --git a/ndctl/lib/libndctl-private.h b/ndctl/lib/libndctl-private.h
index 3e67db0..e379e7d 100644
--- a/ndctl/lib/libndctl-private.h
+++ b/ndctl/lib/libndctl-private.h
@@ -221,6 +221,7 @@ struct ndctl_smart_ops {
unsigned int (*smart_threshold_get_alarm_control)(struct ndctl_cmd *);
unsigned int (*smart_threshold_get_temperature)(struct ndctl_cmd *);
unsigned int (*smart_threshold_get_spares)(struct ndctl_cmd *);
+ unsigned int (*smart_get_detail)(struct ndctl_cmd *);
};
#if HAS_SMART == 1
diff --git a/ndctl/lib/libndctl-smart.c b/ndctl/lib/libndctl-smart.c
index 73a49ef..890fa47 100644
--- a/ndctl/lib/libndctl-smart.c
+++ b/ndctl/lib/libndctl-smart.c
@@ -63,6 +63,7 @@ smart_cmd_op(ndctl_cmd_smart_get_vendor_data, smart_get_vendor_data, unsigned ch
smart_cmd_op(ndctl_cmd_smart_threshold_get_alarm_control, smart_threshold_get_alarm_control, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_threshold_get_temperature, smart_threshold_get_temperature, unsigned int, 0)
smart_cmd_op(ndctl_cmd_smart_threshold_get_spares, smart_threshold_get_spares, unsigned int, 0)
+smart_cmd_op(ndctl_cmd_smart_get_detail, smart_get_detail, unsigned int, 0)
/*
* The following intel_dimm_*() and intel_smart_*() functions implement
@@ -202,4 +203,5 @@ struct ndctl_smart_ops * const intel_smart_ops = &(struct ndctl_smart_ops) {
.smart_threshold_get_alarm_control = intel_cmd_smart_threshold_get_alarm_control,
.smart_threshold_get_temperature = intel_cmd_smart_threshold_get_temperature,
.smart_threshold_get_spares = intel_cmd_smart_threshold_get_spares,
+ .smart_get_detail = NULL,
};
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index be2e368..d3a55f4 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -110,6 +110,7 @@ global:
ndctl_cmd_smart_threshold_get_alarm_control;
ndctl_cmd_smart_threshold_get_temperature;
ndctl_cmd_smart_threshold_get_spares;
+ ndctl_cmd_smart_get_detail;
ndctl_dimm_zero_labels;
ndctl_dimm_get_available_labels;
ndctl_region_get_first;
diff --git a/ndctl/libndctl.h.in b/ndctl/libndctl.h.in
index c27581d..d215c48 100644
--- a/ndctl/libndctl.h.in
+++ b/ndctl/libndctl.h.in
@@ -280,6 +280,7 @@ struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(struct ndctl_dimm *dimm);
unsigned int ndctl_cmd_smart_threshold_get_alarm_control(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_threshold_get_temperature(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_threshold_get_spares(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_detail(struct ndctl_cmd *cmd);
#else
static inline struct ndctl_cmd *ndctl_dimm_cmd_new_smart(struct ndctl_dimm *dimm)
{
@@ -341,6 +342,10 @@ static inline unsigned int ndctl_cmd_smart_threshold_get_spares(
{
return 0;
}
+static inline unsigned int ndctl_cmd_smart_get_detail(struct ndctl_cmd *cmd)
+{
+ return 0;
+}
#endif
struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(struct ndctl_dimm *dimm,
diff --git a/ndctl/ndctl.h b/ndctl/ndctl.h
index 3b1d703..0bdf96f 100644
--- a/ndctl/ndctl.h
+++ b/ndctl/ndctl.h
@@ -28,6 +28,7 @@ struct nd_cmd_smart {
#define ND_SMART_ALARM_VALID (1 << 9)
#define ND_SMART_SHUTDOWN_VALID (1 << 10)
#define ND_SMART_VENDOR_VALID (1 << 11)
+#define ND_SMART_DETAIL_VALID (1 << 13)
#define ND_SMART_SPARE_TRIP (1 << 0)
#define ND_SMART_TEMP_TRIP (1 << 1)
#define ND_SMART_CTEMP_TRIP (1 << 2)
diff --git a/ndctl/util/json-smart.c b/ndctl/util/json-smart.c
index 94519da..304a66a 100644
--- a/ndctl/util/json-smart.c
+++ b/ndctl/util/json-smart.c
@@ -10,6 +10,7 @@
#else
#include <ndctl.h>
#endif
+#include "lib/ndctl-hpe1.h"
static double parse_smart_temperature(unsigned int temp)
{
@@ -151,6 +152,51 @@ struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
json_object_object_add(jhealth, "shutdown_state", jobj);
}
+#define json_detail(jobj,jstring,detail,bit,string) \
+{ \
+ if (detail & bit) { \
+ jstring = json_object_new_string(string); \
+ if (jstring) \
+ json_object_array_add(jobj,jstring); \
+ } \
+}
+
+ if (flags & ND_SMART_DETAIL_VALID) {
+ unsigned int detail = ndctl_cmd_smart_get_detail(cmd);
+ if (detail) {
+ jobj = json_object_new_array();
+ json_object *jstring = NULL;
+
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_ES_FAILURE, "energy source error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_CTLR_FAILURE, "controller error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_UE_TRIP, "UC ECC error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_CE_TRIP, "CE trip")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_SAVE_FAILED, "save error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_RESTORE_FAILED, "restore error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_ARM_FAILED, "arm error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_ERASE_FAILED, "erase error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_CONFIG_ERROR, "configuration error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_FW_ERROR, "firmware error")
+ json_detail(jobj, jstring, detail,
+ NDN_HPE1_SMART_VENDOR_ERROR, "vendor specific error")
+ }
+ else
+ jobj = json_object_new_string("ok");
+ if (jobj)
+ json_object_object_add(jhealth, "health_status_detail",
+ jobj);
+ }
+
ndctl_cmd_unref(cmd);
return jhealth;
err:
--
1.8.3.1
5 years, 5 months
[PATCH] libnvdimm: fix btt vs clear poison locking
by Dan Williams
The following warning results from holding a lane spinlock,
preempt_disable(), or the btt map spinlock and then trying to take the
reconfig_mutex to walk the poison list and potentially add new entries.
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:747
in_atomic(): 1, irqs_disabled(): 0, pid: 17159, name: dd
[..]
Call Trace:
dump_stack+0x85/0xc8
___might_sleep+0x184/0x250
__might_sleep+0x4a/0x90
__mutex_lock+0x58/0x9b0
? nvdimm_bus_lock+0x21/0x30 [libnvdimm]
? __nvdimm_bus_badblocks_clear+0x2f/0x60 [libnvdimm]
? acpi_nfit_forget_poison+0x79/0x80 [nfit]
? _raw_spin_unlock+0x27/0x40
mutex_lock_nested+0x1b/0x20
nvdimm_bus_lock+0x21/0x30 [libnvdimm]
nvdimm_forget_poison+0x25/0x50 [libnvdimm]
nvdimm_clear_poison+0x106/0x140 [libnvdimm]
nsio_rw_bytes+0x164/0x270 [libnvdimm]
btt_write_pg+0x1de/0x3e0 [nd_btt]
? blk_queue_enter+0x30/0x290
btt_make_request+0x11a/0x310 [nd_btt]
? blk_queue_enter+0xb7/0x290
? blk_queue_enter+0x30/0x290
generic_make_request+0x118/0x3b0
As a minimal fix, disable error clearing when the BTT is enabled. For
the final fix a larger rework of the poison list locking is needed.
Note that this is not a problem in the blk case since that path never
calls nvdimm_clear_poison().
Cc: <stable(a)vger.kernel.org>
Fixes: 82bf1037f2ca ("libnvdimm: check and clear poison before writing to pmem")
Cc: Dave Jiang <dave.jiang(a)intel.com>
Reported-by: Vishal Verma <vishal.l.verma(a)intel.com>
Signed-off-by: Dan Williams <dan.j.williams(a)intel.com>
---
drivers/nvdimm/claim.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c
index b3323c0697f6..36da71e5a591 100644
--- a/drivers/nvdimm/claim.c
+++ b/drivers/nvdimm/claim.c
@@ -243,7 +243,15 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns,
}
if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) {
- if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) {
+ /*
+ * FIXME: nsio_rw_bytes() may be called from atomic
+ * context in the BTT case and nvdimm_clear_poison()
+ * takes a sleeping lock. Until the locking can be
+ * reworked this capability depends on !BTT or BROKEN.
+ */
+ if ((!IS_ENABLED(CONFIG_BTT) || IS_ENABLED(CONFIG_BROKEN))
+ && IS_ALIGNED(offset, 512)
+ && IS_ALIGNED(size, 512)) {
long cleared;
cleared = nvdimm_clear_poison(&ndns->dev, offset, size);
5 years, 5 months
Re:最新权威薪酬设计模式.docx
by 蒋圾
linux-nvdimm
掌 握 国 际 国 内 最 规 范 的 薪 酬 设 计 方 法,成 为 相 应 的 专 业 者
详*情*附*件*亲*启
1:38:09
5 years, 5 months