pax_global_header00006660000000000000000000000064133177760720014527gustar00rootroot0000000000000052 comment=39ef3d07dd7f7337780884659008e5a26e9f76cf
ndctl-61.2/000077500000000000000000000000001331777607200125635ustar00rootroot00000000000000ndctl-61.2/.gitignore000066400000000000000000000015601331777607200145550ustar00rootroot00000000000000*.o
*.xml
.deps/
.libs/
Makefile
!contrib/Makefile
Makefile.in
/aclocal.m4
/autom4te.cache
/build-aux
/config.*
/configure
/libtool
/stamp-h1
*.1
Documentation/daxctl/asciidoc.conf
Documentation/ndctl/asciidoc.conf
Documentation/daxctl/asciidoctor-extensions.rb
Documentation/ndctl/asciidoctor-extensions.rb
.dirstamp
daxctl/daxctl
daxctl/lib/libdaxctl.la
daxctl/lib/libdaxctl.lo
daxctl/lib/libdaxctl.pc
*.a
ndctl/lib/libndctl.pc
ndctl/ndctl
rhel/
sles/ndctl.spec
util/log.lo
util/sysfs.lo
version.m4
*.swp
cscope.files
cscope*.out
tags
test/*.log
test/*.trs
test/blk-ns
test/dax-dev
test/dax-errors
test/dax-pmd
test/daxdev-errors
test/device-dax
test/dpa-alloc
test/dsm-fail
test/hugetlb
test/image
test/libndctl
test/mmap
test/multi-pmem
test/parent-uuid
test/pmem-ns
test/smart-listen
test/smart-notify
test/fio.job
test/local-write-0-verify.state
test/ack-shutdown-count-set
ndctl-61.2/COPYING000066400000000000000000000636251331777607200136320ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
ndctl-61.2/Documentation/000077500000000000000000000000001331777607200153745ustar00rootroot00000000000000ndctl-61.2/Documentation/COPYING000066400000000000000000000433341331777607200164360ustar00rootroot00000000000000All files in this directory (Documentation/) unless otherwise noted in
the file itself are licensed under the GPLv2.
---------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
ndctl-61.2/Documentation/asciidoc.conf.in000066400000000000000000000046551331777607200204400ustar00rootroot00000000000000## linkUTILITY: macro
#
# Copyright (c) 2005, Sergey Vlasov
# Copyright (c) 2005, Jonas Fonseca
#
# Originally copied from GIT source (commit d1c2e113c5b6 "[PATCH]
# Documentation: Add asciidoc.conf file and gitlink: macro")
#
# Usage: linkUTILITY:command[manpage-section]
#
# Note, {0} is the manpage section, while {target} is the command.
#
# Show PERF link as: (); if section is defined, else just show
# the command.
[macros]
(?su)[\\]?(?PlinkUTILITY):(?P\S*?)\[(?P.*?)\]=
[attributes]
asterisk=*
plus=+
caret=^
startsb=[
endsb=]
tilde=~
ifdef::backend-docbook[]
[linkUTILITY-inlinemacro]
{0%{target}}
{0#}
{0#{target}{0}}
{0#}
endif::backend-docbook[]
ifdef::backend-docbook[]
ifndef::UTILITY-asciidoc-no-roff[]
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
# v1.72 breaks with this because it replaces dots not in roff requests.
[listingblock]
{title}
ifdef::doctype-manpage[]
.ft C
endif::doctype-manpage[]
|
ifdef::doctype-manpage[]
.ft
endif::doctype-manpage[]
{title#}
endif::UTILITY-asciidoc-no-roff[]
ifdef::UTILITY-asciidoc-no-roff[]
ifdef::doctype-manpage[]
# The following two small workarounds insert a simple paragraph after screen
[listingblock]
{title}
|
{title#}
[verseblock]
{title}
{title%}
{title#}
|
{title#}
{title%}
endif::doctype-manpage[]
endif::UTILITY-asciidoc-no-roff[]
endif::backend-docbook[]
ifdef::doctype-manpage[]
ifdef::backend-docbook[]
[header]
template::[header-declarations]
{mantitle}
{manvolnum}
UTILITY
{UTILITY_version}
UTILITY Manual
{manname}
{manpurpose}
endif::backend-docbook[]
endif::doctype-manpage[]
ifdef::backend-xhtml11[]
[linkUTILITY-inlinemacro]
{target}{0?({0})}
endif::backend-xhtml11[]
ndctl-61.2/Documentation/asciidoctor-extensions.rb.in000066400000000000000000000016341331777607200230320ustar00rootroot00000000000000require 'asciidoctor'
require 'asciidoctor/extensions'
module @Utility@
module Documentation
class Link@Utility@Processor < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :chrome
def process(parent, target, attrs)
if parent.document.basebackend? 'html'
prefix = parent.document.attr('@utility@-relative-html-prefix')
%(#{target}(#{attrs[1]})\n)
elsif parent.document.basebackend? 'manpage'
"#{target}(#{attrs[1]})"
elsif parent.document.basebackend? 'docbook'
"\n" \
"#{target}" \
"#{attrs[1]}\n" \
"\n"
end
end
end
end
end
Asciidoctor::Extensions.register do
inline_macro @Utility@::Documentation::Link@Utility@Processor, :link@utility@
end
ndctl-61.2/Documentation/copyright.txt000066400000000000000000000004471331777607200201520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
COPYRIGHT
---------
Copyright (c) 2016 - 2018, Intel Corporation. License GPLv2: GNU GPL
version 2 . This is free software:
you are free to change and redistribute it. There is NO WARRANTY, to
the extent permitted by law.
ndctl-61.2/Documentation/daxctl/000077500000000000000000000000001331777607200166535ustar00rootroot00000000000000ndctl-61.2/Documentation/daxctl/Makefile.am000066400000000000000000000030261331777607200207100ustar00rootroot00000000000000# Copyright(c) 2015-2017 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
if USE_ASCIIDOCTOR
do_subst = sed -e 's,@Utility@,Daxctl,g' -e's,@utility@,daxctl,g'
CONFFILE = asciidoctor-extensions.rb
asciidoctor-extensions.rb: ../asciidoctor-extensions.rb.in
$(AM_V_GEN) $(do_subst) < $< > $@
else
do_subst = sed -e 's,UTILITY,daxctl,g'
CONFFILE = asciidoc.conf
asciidoc.conf: ../asciidoc.conf.in
$(AM_V_GEN) $(do_subst) < $< > $@
endif
man1_MANS = \
daxctl.1 \
daxctl-list.1
CLEANFILES = $(man1_MANS)
XML_DEPS = \
../../version.m4 \
../copyright.txt \
Makefile \
$(CONFFILE)
RM ?= rm -f
if USE_ASCIIDOCTOR
%.1: %.txt $(XML_DEPS)
$(AM_V_GEN)$(RM) $@+ $@ && \
$(ASCIIDOC) -b manpage -d manpage -acompat-mode \
-I. -rasciidoctor-extensions \
-amansource=daxctl -amanmanual="daxctl Manual" \
-andctl_version=$(VERSION) -o $@+ $< && \
mv $@+ $@
else
%.xml: %.txt $(XML_DEPS)
$(AM_V_GEN)$(RM) $@+ $@ && \
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
--unsafe -adaxctl_version=$(VERSION) -o $@+ $< && \
mv $@+ $@
%.1: %.xml $(XML_DEPS)
$(AM_V_GEN)$(RM) $@ && \
$(XMLTO) -o . -m ../manpage-normal.xsl man $<
endif
ndctl-61.2/Documentation/daxctl/daxctl-list.txt000066400000000000000000000035631331777607200216530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
daxctl-list(1)
==============
NAME
----
daxctl-list - dump the platform Device-DAX regions, devices, and
attributes in json.
SYNOPSIS
--------
[verse]
'daxctl list' []
Walk all the device-dax-regions in the system and list all device
instances along with some of their major attributes.
Options can be specified to limit the output to objects of a certain
class. Where the classes are regions or devices. By default, 'daxctl
list' with no options is equivalent to:
[verse]
daxctl list --devices
EXAMPLE
-------
----
# daxctl list --regions --devices
{
"id":1,
"devices":[
{
"chardev":"dax1.0",
"size":3233808384
}
]
}
----
OPTIONS
-------
-r::
--region=::
A device-dax region is a contiguous range of memory that
hosts one or more /dev/daxX.Y devices, where X is the region id
and Y is the device instance id. The keyword 'all' can be
specified to carry out the operation on every region in the
system.
-d::
--dev=::
Specify a dax device name, .
tuple, or keyword 'all' to filter the listing. For
example to list the first device instance in region1:
----
# daxctl list --dev=1.0
{
"chardev":"dax1.0",
"size":3233808384
}
----
-D::
--devices::
Include device-dax instance info in the listing (default)
-R::
--regions::
Include region info in the listing
-i::
--idle::
Include idle (not enabled / zero-sized) devices in the listing
-u::
--human::
By default 'daxctl list' will output machine-friendly raw-integer
data. Instead, with this flag, numbers representing storage size
will be formatted as human readable strings with units, other
fields are converted to hexadecimal strings. Example:
----
# daxctl list
{
"chardev":"dax1.0",
"size":32828817408
}
# daxctl list --human
{
"chardev":"dax1.0",
"size":"30.57 GiB (32.83 GB)"
}
----
include::../copyright.txt[]
ndctl-61.2/Documentation/daxctl/daxctl.txt000066400000000000000000000012671331777607200207010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
daxctl(1)
=========
NAME
----
daxctl - Provides enumeration and provisioning commands for the Linux kernel Device-DAX facility
SYNOPSIS
--------
[verse]
'daxctl' [--version] [--help] COMMAND [ARGS]
OPTIONS
-------
-v::
--version::
Display daxctl version.
-h::
--help::
Run daxctl help command.
DESCRIPTION
-----------
The daxctl utility provides enumeration and provisioning commands for
the Linux kernel Device-DAX facility. This facility enables DAX mappings
of performance / feature differentiated memory without need of a
filesystem.
include::../copyright.txt[]
SEE ALSO
--------
linkdaxctl:ndctl-create-namespace[1],
linkdaxctl:ndctl-list[1]
ndctl-61.2/Documentation/manpage-base.xsl000066400000000000000000000026721331777607200204530ustar00rootroot00000000000000
sp
br
ndctl-61.2/Documentation/manpage-normal.xsl000066400000000000000000000013551331777607200210260ustar00rootroot00000000000000
\
.
ndctl-61.2/Documentation/ndctl/000077500000000000000000000000001331777607200165005ustar00rootroot00000000000000ndctl-61.2/Documentation/ndctl/Makefile.am000066400000000000000000000042701331777607200205370ustar00rootroot00000000000000# Copyright(c) 2015-2017 Intel Corporation.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
if USE_ASCIIDOCTOR
do_subst = sed -e 's,@Utility@,Ndctl,g' -e's,@utility@,ndctl,g'
CONFFILE = asciidoctor-extensions.rb
asciidoctor-extensions.rb: ../asciidoctor-extensions.rb.in
$(AM_V_GEN) $(do_subst) < $< > $@
else
do_subst = sed -e 's,UTILITY,ndctl,g'
CONFFILE = asciidoc.conf
asciidoc.conf: ../asciidoc.conf.in
$(AM_V_GEN) $(do_subst) < $< > $@
endif
man1_MANS = \
ndctl.1 \
ndctl-wait-scrub.1 \
ndctl-start-scrub.1 \
ndctl-zero-labels.1 \
ndctl-read-labels.1 \
ndctl-write-labels.1 \
ndctl-init-labels.1 \
ndctl-check-labels.1 \
ndctl-enable-region.1 \
ndctl-disable-region.1 \
ndctl-enable-dimm.1 \
ndctl-disable-dimm.1 \
ndctl-enable-namespace.1 \
ndctl-disable-namespace.1 \
ndctl-create-namespace.1 \
ndctl-destroy-namespace.1 \
ndctl-check-namespace.1 \
ndctl-inject-error.1 \
ndctl-inject-smart.1 \
ndctl-update-firmware.1 \
ndctl-list.1
CLEANFILES = $(man1_MANS)
XML_DEPS = \
../../version.m4 \
Makefile \
$(CONFFILE) \
../copyright.txt \
region-description.txt \
xable-region-options.txt \
dimm-description.txt \
xable-dimm-options.txt \
xable-namespace-options.txt \
ars-description.txt \
labels-description.txt \
labels-options.txt
RM ?= rm -f
if USE_ASCIIDOCTOR
%.1: %.txt $(XML_DEPS)
$(AM_V_GEN)$(RM) $@+ $@ && \
$(ASCIIDOC) -b manpage -d manpage -acompat-mode \
-I. -rasciidoctor-extensions \
-amansource=ndctl -amanmanual="ndctl Manual" \
-andctl_version=$(VERSION) -o $@+ $< && \
mv $@+ $@
else
%.xml: %.txt $(XML_DEPS)
$(AM_V_GEN)$(RM) $@+ $@ && \
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
--unsafe -andctl_version=$(VERSION) -o $@+ $< && \
mv $@+ $@
%.1: %.xml $(XML_DEPS)
$(AM_V_GEN)$(RM) $@ && \
$(XMLTO) -o . -m ../manpage-normal.xsl man $<
endif
ndctl-61.2/Documentation/ndctl/ars-description.txt000066400000000000000000000005731331777607200223540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
DESCRIPTION
-----------
NVDIMM Address Range Scrub is a capability provided by platform firmware
that allows for the discovery of memory errors by system software. It
enables system software to pre-emptively avoid accesses that could lead
to uncorrectable memory error handling events, and it otherwise allows
memory errors to be enumerated.
ndctl-61.2/Documentation/ndctl/dimm-description.txt000066400000000000000000000015141331777607200225110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
DESCRIPTION
-----------
A generic DIMM device object, named /dev/nmemX, is registered for each
memory device indicated in the ACPI NFIT table, or other platform NVDIMM
resource discovery mechanism. The LIBNVDIMM core provides a built-in
driver for these DIMM devices. The driver is responsible for
determining if the DIMM implements a namespace label area, and
initializing the kernel's in-memory copy of that label data.
The kernel performs runtime modifications of that data when namespace
provisioning actions are taken, and actively blocks userspace from
initiating label data changes while the DIMM is active in any region.
Disabling a DIMM, after all the regions it is a member of have been
disabled, allows userspace to manually update the label data to be
consumed when the DIMM is next enabled.
ndctl-61.2/Documentation/ndctl/human-option.txt000066400000000000000000000004031331777607200216540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
-u::
--human::
Format numbers representing storage sizes, or offsets as human
readable strings with units instead of the default machine-friendly
raw-integer data. Convert other numeric fields into hexadecimal strings.
ndctl-61.2/Documentation/ndctl/labels-description.txt000066400000000000000000000004271331777607200230270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
DESCRIPTION
-----------
The namespace label area is a small persistent partition of capacity
available on some NVDIMM devices. The label area is used to resolve
aliasing between 'pmem' and 'blk' capacity by delineating namespace
boundaries.
ndctl-61.2/Documentation/ndctl/labels-options.txt000066400000000000000000000007341331777607200222000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
::
One or more 'nmemX' device names. The keyword 'all' can be specified to
operate on every dimm in the system, optionally filtered by bus id (see
--bus= option).
-b::
--bus=::
Limit operation to memory devices (dimms) that are on the given bus.
Where 'bus' can be a provider name or a bus id number.
-v::
Turn on verbose debug messages in the library (if ndctl was built with
logging and debug enabled).
ndctl-61.2/Documentation/ndctl/namespace-description.txt000066400000000000000000000053411331777607200235210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
THEORY OF OPERATION
-------------------
The capacity of an NVDIMM REGION (contiguous span of persistent memory)
is accessed via one or more NAMESPACE devices. REGION is the Linux term
for what ACPI and UEFI call a DIMM-interleave-set, or a
system-physical-address-range that is striped (by the memory controller)
across one or more memory modules.
The UEFI specification defines the 'NVDIMM Label Protocol' as the
combination of label area access methods and a data format for
provisioning one or more NAMESPACE objects from a REGION. Note that
label support is optional and if Linux does not detect the label
capability it will automatically instantiate a "label-less" namespace
per region. Examples of label-less namespaces are the ones created by
the kernel's 'memmap=ss!nn' command line option (see the nvdimm wiki on
kernel.org), or NVDIMMs without a valid 'namespace index' in their label
area.
A namespace can be provisioned to operate in one of 4 modes, 'fsdax',
'devdax', 'sector', and 'raw'. Here are the expected usage models for
these modes:
- fsdax: Filesystem-DAX mode is the default mode of a namespace
when specifying 'ndctl create-namespace' with no options. It creates
a block device (/dev/pmemX[.Y]) that supports the DAX capabilities
of Linux filesystems (xfs and ext4 to date). DAX removes the page
cache from the I/O path and allows mmap(2) to establish direct
mappings to persistent memory media. The DAX capability enables
workloads / working-sets that would exceed the capacity of the page
cache to scale up to the capacity of persistent memory. Workloads
that fit in page cache or perform bulk data transfers may not see
benefit from DAX. When in doubt, pick this mode.
- devdax: Device-DAX mode enables similar mmap(2) DAX mapping
capabilities as Filesystem-DAX. However, instead of a block-device
that can support a DAX-enabled filesystem, this mode emits a single
character device file (/dev/daxX.Y). Use this mode to assign
persistent memory to a virtual-machine, register persistent memory
for RDMA, or when gigantic mappings are needed.
- sector: Use this mode to host legacy filesystems that do
not checksum metadata or applications that are not prepared for torn
sectors after a crash. Expected usage for this mode is for small
boot volumes. This mode is compatible with other operating systems.
- raw: Raw mode is effectively just a memory disk that does
not support DAX. Typically this indicates a namespace that was
created by tooling or another operating system that did not know how
to create a Linux 'fsdax' or 'devdax' mode namespace. This mode is
compatible with other operating systems, but again, does not support
DAX operation.
ndctl-61.2/Documentation/ndctl/ndctl-check-labels.txt000066400000000000000000000012051331777607200226560ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-check-labels(1)
====================
NAME
----
ndctl-check-labels - determine if the given dimms have a valid namespace index block
SYNOPSIS
--------
[verse]
'ndctl check-labels' [..] []
include::labels-description.txt[]
In addition to checking if a label area has a valid index block, running
this command in verbose mode reports the reason the index block is
deemed invalid.
OPTIONS
-------
include::labels-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
ndctl-61.2/Documentation/ndctl/ndctl-check-namespace.txt000066400000000000000000000041011331777607200233460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-check-namespace(1)
=========================
NAME
----
ndctl-check-namespace - check namespace metadata consistency
SYNOPSIS
--------
[verse]
'ndctl check-namespace' []
DESCRIPTION
-----------
A namespace in the 'sector' mode will have metadata on it to describe
the kernel BTT (Block Translation Table). The check-namespace command
can be used to check the consistency of this metadata, and optionally,
also attempt to repair it, if it has enough information to do so.
The namespace being checked has to be disabled before initiating a
check on it as a precautionary measure. The --force option can override
this.
EXAMPLES
--------
Check a namespace (only report errors)
[verse]
ndctl disable-namespace namespace0.0
ndctl check-namespace namespace0.0
Check a namespace, and perform repairs if possible
[verse]
ndctl disable-namespace namespace0.0
ndctl check-namespace --repair namespace0.0
OPTIONS
-------
-R::
--repair::
Perform metadata repairs if possible. Without this option,
the raw namespace contents will not be touched.
-L::
--rewrite-log::
Regenerate the BTT log and write it to media. This can be used to
convert from the old (pre 4.15) padding format that was incompatible
with other BTT implementations to the updated format. This requires
the --repair option to be provided.
WARNING: Do not interrupt this operation as it can potentially cause
unrecoverable metadata corruption. It is highly recommended to create
a backup of the raw namespace before attempting this.
-f::
--force::
Unless this option is specified, a check-namespace operation
will fail if the namespace is presently active. Specifying
--force causes the namespace to be disabled before checking.
-v::
--verbose::
Emit debug messages for the namespace check process.
-r::
--region=::
include::xable-region-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-disable-namespace[1],
linkndctl:ndctl-enable-namespace[1],
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
ndctl-61.2/Documentation/ndctl/ndctl-create-namespace.txt000066400000000000000000000203221331777607200235370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-create-namespace(1)
=========================
NAME
----
ndctl-create-namespace - provision or reconfigure a namespace
SYNOPSIS
--------
[verse]
'ndctl create-namespace' []
include::namespace-description.txt[]
EXAMPLES
--------
Create a maximally sized pmem namespace in 'fsdax' mode (the
default)
[verse]
ndctl create-namespace
Convert namespace0.0 to 'sector' mode
[verse]
ndctl create-namespace -f -e namespace0.0 --mode=sector
OPTIONS
-------
-t::
--type=::
Create a 'pmem' or 'blk' namespace (subject to available
capacity). A pmem namespace supports the dax (direct access)
capability to linkndctl:mmap[2] persistent memory directly into
a process address space. A blk namespace access persistent
memory through a block-window-aperture. Compared to pmem it
supports a traditional storage error model (EIO on error rather
than a cpu exception on a bad memory access), but it does not
support dax.
-m::
--mode=::
- "raw": expose the namespace capacity directly with
limitations. Neither a raw pmem namepace nor raw blk
namespace support sector atomicity by default (see "sector"
mode below). A raw pmem namespace may have limited to no dax
support depending the kernel. In other words operations like
direct-I/O targeting a dax buffer may fail for a pmem
namespace in raw mode or indirect through a page-cache buffer.
See "fsdax" and "devdax" mode for dax operation.
- "sector": persistent memory, given that it is byte
addressable, does not support sector atomicity. The
problematic aspect of sector tearing is that most applications
do not know they have a atomic sector update dependency. At
least a disk rarely ever tears sectors and if it does it
almost certainly returns a checksum error on access.
Persistent memory devices will always tear and always
silently. Until an application is audited to be robust in the
presence of sector-tearing "safe" mode is recommended. This
imposes some performance overhead and disables the dax
capability. (also known as "safe" or "btt" mode)
- "fsdax": A pmem namespace in this mode supports dax
operation with a block-device based filesystem (in previous
ndctl releases this mode was named "memory" mode). This mode
comes at the cost of allocating per-page metadata. The
capacity can be allocated from "System RAM", or from a
reserved portion of "Persistent Memory" (see the --map=
option). Note that a filesystem is required for dax
operation, the resulting raw block device (/dev/pmemX) will
use the page cache. See "devdax" mode for raw device access
that supports dax.
- "devdax": The device-dax character device interface is a
statically allocated / raw access analogue of filesystem-dax
(in previous ndctl releases this mode was named "dax" mode).
It allows memory ranges to be mapped without need of an
intervening filesystem. The device-dax is interface strict,
precise and predictable. Specifically the interface:
* Guarantees fault granularity with respect to a given page
size (4K, 2M, or 1G on x86) set at configuration time.
* Enforces deterministic behavior by being strict about what
fault scenarios are supported. I.e. if a device is
configured with a 2M alignment an attempt to fault a 4K
aligned offset will result in SIGBUS.
-s::
--size=::
For NVDIMM devices that support namespace labels, set the
namespace size in bytes. Otherwise it defaults to the maximum
size specified by platform firmware. This option supports the
suffixes "k" or "K" for KiB, "m" or "M" for MiB, "g" or "G" for
GiB and "t" or "T" for TiB.
For pmem namepsaces the size must be a multiple of the
interleave-width and the namespace alignment (see
below).
-a::
--align::
Applications that want to establish dax memory mappings with
page table entries greater than system base page size (4K on
x86) need a persistent memory namespace that is sufficiently
aligned. For "fsdax" and "devdax" mode this defaults to 2M.
Note that "devdax" mode enforces all mappings to be aligned to
this value, i.e. it fails unaligned mapping attempts. The
"fsdax" alignment setting determines the starting alignment of
filesystem extents and may limit the possible granularities,
if a large mapping is not possible it will silently fall back
to a smaller page size.
-e::
--reconfig=::
Reconfigure an existing namespace (change the mode, sector size,
etc...). All namespace parameters, save uuid, default to the
current attributes of the specified namespace. The namespace is
then re-created with the specified modifications. The uuid is
refreshed to a new value by default whenever the data layout of
a namespace is changed, see --uuid= to set a specific uuid.
-u::
--uuid=::
This option is not recommended as a new uuid should be generated
every time a namespace is (re-)created. For recovery scenarios
however the uuid may be specified.
-n::
--name=::
For NVDIMM devices that support namespace labels,
specify a human friendly name for a namespace. This name is
available as a device attribute for use in udev rules.
-l::
--sector-size::
Specify the logical sector size (LBA size) of the
Linux block device associated with an namespace.
-M::
--map=::
A pmem namespace in "fsdax" or "devdax" mode requires allocation of
per-page metadata. The allocation can be drawn from either:
- "mem": typical system memory
- "dev": persistent memory reserved from the namespace
Given relative capacities of "Persistent Memory" to "System
RAM" the allocation defaults to reserving space out of the
namespace directly ("--map=dev"). The overhead is 64-bytes per
4K (16GB per 1TB) on x86.
-f::
--force::
Unless this option is specified the 'reconfigure namespace'
operation will fail if the namespace is presently active.
Specifying --force causes the namespace to be disabled before
the operation is attempted. However, if the namespace is
mounted then the 'disable namespace' and 'reconfigure
namespace' operations will be aborted. The namespace must be
unmounted before being reconfigured.
-L::
--autolabel::
--no-autolabel::
Legacy NVDIMM devices do not support namespace labels. In that
case the kernel creates region-sized namespaces that can not
be deleted. Their mode can be changed, but they can not be
resized smaller than their parent region. This is termed a
"label-less namespace". In contrast, NVDIMMs and hypervisors
that support the ACPI 6.2 label area definition (ACPI 6.2
Section 6.5.10 NVDIMM Label Methods) support "labelled
namespace" operation.
- There are two cases where the kernel will default to
label-less operation:
* NVDIMM does not support labels
* The NVDIMM supports labels, but the Label Index Block (see
UEFI 2.7) is not present and there is no capacity aliasing
between 'blk' and 'pmem' regions.
- In the latter case the configuration can be upgraded to
labelled operation by writing an index block on all DIMMs in a
region and re-enabling that region. The 'autolabel' capability
of 'ndctl create-namespace --reconfig' tries to do this by
default if it can determine that all DIMM capacity is
referenced by the namespace being reconfigured. It will
otherwise fail to autolabel and remain in label-less mode if
it finds a DIMM contributes capacity to more than one region.
This check prevents inadvertent data loss of that other region
is in active use. The --autolabel option is implied by
default, the --no-autolabel option can be used to disable this
behavior. When automatic labeling fails and labelled operation
is still desired the safety policy can be bypassed by the
following commands, note that all data on all regions is
forfeited by running these commands:
ndctl disable-region all
ndctl init-labels all
ndctl enable-region all
-v::
--verbose::
Emit debug messages for the namespace creation process
-r::
--region=::
include::xable-region-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-zero-labels[1],
linkndctl:ndctl-init-labels[1],
linkndctl:ndctl-disable-namespace[1],
linkndctl:ndctl-enable-namespace[1],
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
https://nvdimm.wiki.kernel.org[Linux Persistent Memory Wiki]
ndctl-61.2/Documentation/ndctl/ndctl-destroy-namespace.txt000066400000000000000000000014561331777607200237740ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-destroy-namespace(1)
=========================
NAME
----
ndctl-destroy-namespace - destroy the given namespace(s)
SYNOPSIS
--------
[verse]
'ndctl destroy-namespace' []
include::namespace-description.txt[]
OPTIONS
-------
include::xable-namespace-options.txt[]
-f::
--force::
Unless this option is specified the 'destroy namespace'
operation will fail if the namespace is presently active.
Specifying --force causes the namespace to be disabled before
the operation is attempted. However, if the namespace is
mounted then the 'disable namespace' and 'destroy
namespace' operations will be aborted. The namespace must be
unmounted before being destroyed.
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-create-namespace[1]
ndctl-61.2/Documentation/ndctl/ndctl-disable-dimm.txt000066400000000000000000000005771331777607200227030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-disable-dimm(1)
=====================
NAME
----
ndctl-disable-dimm - disable one or more idle dimms
SYNOPSIS
--------
[verse]
'ndctl disable-dimm' []
include::dimm-description.txt[]
OPTIONS
-------
::
include::xable-dimm-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-enable-dimm[1]
ndctl-61.2/Documentation/ndctl/ndctl-disable-namespace.txt000066400000000000000000000006361331777607200237050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-disable-namespace(1)
=========================
NAME
----
ndctl-disable-namespace - disable the given namespace(s)
SYNOPSIS
--------
[verse]
'ndctl disable-namespace' []
include::namespace-description.txt[]
OPTIONS
-------
include::xable-namespace-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-disable-namespace[1]
ndctl-61.2/Documentation/ndctl/ndctl-disable-region.txt000066400000000000000000000006541331777607200232340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-disable-region(1)
=======================
NAME
----
ndctl-disable-region - disable the given region(s) and all descendant namespaces
SYNOPSIS
--------
[verse]
'ndctl disable-region' []
include::region-description.txt[]
OPTIONS
-------
::
include::xable-region-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-enable-region[1]
ndctl-61.2/Documentation/ndctl/ndctl-enable-dimm.txt000066400000000000000000000005631331777607200225210ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-enable-dimm(1)
====================
NAME
----
ndctl-enable-dimm - enable one more dimms
SYNOPSIS
--------
[verse]
'ndctl enable-dimm' []
include::dimm-description.txt[]
OPTIONS
-------
::
include::xable-dimm-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-disable-dimm[1]
ndctl-61.2/Documentation/ndctl/ndctl-enable-namespace.txt000066400000000000000000000006321331777607200235240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-enable-namespace(1)
=========================
NAME
----
ndctl-enable-namespace - enable the given namespace(s)
SYNOPSIS
--------
[verse]
'ndctl enable-namespace' []
include::namespace-description.txt[]
OPTIONS
-------
include::xable-namespace-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-disable-namespace[1]
ndctl-61.2/Documentation/ndctl/ndctl-enable-region.txt000066400000000000000000000006501331777607200230530ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-enable-region(1)
======================
NAME
----
ndctl-enable-region - enable the given region(s) and all descendant namespaces
SYNOPSIS
--------
[verse]
'ndctl enable-region' []
include::region-description.txt[]
OPTIONS
-------
::
include::xable-region-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-disable-region[1]
ndctl-61.2/Documentation/ndctl/ndctl-init-labels.txt000066400000000000000000000036411331777607200225520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-init-labels(1)
====================
NAME
----
ndctl-init-labels - initialize the label data area on a dimm or set of dimms
SYNOPSIS
--------
[verse]
'ndctl init-labels' [..] []
include::labels-description.txt[]
By default, and in kernels prior to v4.10, the kernel only honors labels
when a DIMM aliases PMEM and BLK capacity. Starting with v4.10 the
kernel will honor labels for sub-dividing PMEM if all the DIMMs in an
interleave set / region have a valid namespace index block.
This command can be used to initialize the namespace index block if it
is missing or reinitialize it if it is damaged. Note that
reinitialization effectively destroys all existing namespace labels on
the DIMM.
EXAMPLE
-------
Find the DIMMs that comprise a given region:
----
# ndctl list -RD --region=region1
{
"dimms":[
{
"dev":"nmem0",
"id":"8680-56341200"
}
],
"regions":[
{
"dev":"region1",
"size":268435456,
"available_size":0,
"type":"pmem",
"mappings":[
{
"dimm":"nmem0",
"offset":13958643712,
"length":268435456
}
]
}
]
}
----
Disable that region so the DIMM label area can be written from
userspace:
----
# ndctl disable-region region1
----
Initialize labels:
----
# ndctl init-labels nmem0
----
Re-enable the region:
----
# ndctl enable-region region1
----
Create a namespace in that region:
----
# ndctl create-namespace --region=region1
----
OPTIONS
-------
include::labels-options.txt[]
-f::
--force::
Force initialization of the label space even if there appears to
be an existing / valid namespace index. Warning, this will
destroy all defined namespaces on the dimm.
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-create-namespace[1],
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
ndctl-61.2/Documentation/ndctl/ndctl-inject-error.txt000066400000000000000000000076601331777607200227570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-inject-error(1)
=====================
NAME
----
ndctl-inject-error - inject media errors at a namespace offset
SYNOPSIS
--------
[verse]
'ndctl inject-error' []
include::namespace-description.txt[]
ndctl-inject-error can be used to ask the platform to simulate media errors
in the NVDIMM address space to aid debugging and development of features
related to error handling.
By default, injecting an error actually only injects an error to the first 'n'
bytes of the block, where 'n' is the output of ndctl_cmd_ars_cap_get_size().
In other words, we only inject one 'ars_unit' per sector. This is sufficient
for Linux to mark the whole sector as bad, and will show up as such in the
various 'badblocks' lists in the kernel. If multiple blocks are being injected,
only the first 'n' bytes of each block specified will be injected as errors.
This can be overridden by the --saturate option, which will force the entire
block to be injected as an error.
WARNING: These commands are DANGEROUS and can cause data loss. They are
only provided for testing and debugging purposes.
EXAMPLES
--------
Inject errors in namespace0.0 at block 12 for 2 blocks (i.e. 12, 13)
[verse]
ndctl inject-error --block=12 --count=2 namespace0.0
Check status of injected errors on namespace0.0
[verse]
ndctl inject-error --status namespace0.0
Uninject errors at block 12 for 2 blocks on namespace0.0
[verse]
ndctl inject-error --uninject --block=12 --count=2 namespace0.0
OPTIONS
-------
-B::
--block=::
Namespace block offset in 512 byte sized blocks where the error is
to be injected.
NOTE: The offset is interpreted in different ways based on the "mode"
of the namespace. For "raw" mode, the offset is the base namespace
offset. For "fsdax" mode (i.e. a "pfn" namespace), the offset is
relative to the user-visible part of the namespace, and the offset
introduced by the kernel's metadata will be accounted for. For a
"sector" mode namespace (i.e. a "BTT" namespace), the offset is
relative to the base namespace, as the BTT translation details are
internal to the kernel, and can't be accounted for while injecting
errors.
-n::
--count=::
Number of blocks to inject as errors. This is also in terms of fixed,
512 byte blocks.
-d::
--uninject::
This option will ask the platform to remove any injected errors for the
specified block offset, and count.
WARNING: This will not clear the kernel's internal badblock tracking,
those can only be cleared by doing a write to the affected locations.
Hence use the --clear option only if you know exactly what you are
doing. For normal usage, injected errors should only be cleared by
doing writes. Do not expect have the original data intact after
injecting an error, and clearing it using --clear - it will be lost,
as the only "real" way to clear the error location is to write to it
or zero it (truncate/hole-punch).
-t::
--status::
This option will retrieve the status of injected errors. Note that
this will not retrieve all known/latent errors (i.e. non injected
ones), and is NOT equivalent to performing an Address Range Scrub.
-N::
--no-notify::
This option is only valid when injecting errors. By default, the error
inject command and will ask platform firmware to trigger a notification
in the kernel, asking it to update its state of known errors.
With this option, the error will still be injected, the kernel will not
get a notification, and the error will appear as a latent media error
when the location is accessed. If the platform firmware does not
support this feature, this will have no effect.
-S::
--saturate::
This option forces error injection or un-injection to cover the entire
address range covered by the specified block(s).
-v::
--verbose::
Emit debug messages for the error injection process
include::human-option.txt[]
-r::
--region=::
include::xable-region-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-list[1],
ndctl-61.2/Documentation/ndctl/ndctl-inject-smart.txt000066400000000000000000000044171331777607200227510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-inject-smart(1)
=====================
NAME
----
ndctl-inject-smart - perform smart threshold/injection operations on a DIMM
SYNOPSIS
--------
[verse]
'ndctl inject-smart' []
DESCRIPTION
-----------
A generic DIMM device object, named /dev/nmemX, is registered for each
memory device indicated in the ACPI NFIT table, or other platform NVDIMM
resource discovery mechanism.
ndctl-inject-smart can be used to set smart thresholds, and inject smart
attributes.
EXAMPLES
--------
Set smart controller temperature and spares threshold for DIMM-0 to 32C, spares
threshold to 8, and enable the spares alarm.
[verse]
ndctl inject-smart --ctrl-temperature-threshold=32 --spares-threshold=8 --spares-alarm nmem0
Inject a media temperature value of 52 and fatal health status flag for DIMM-0
[verse]
ndctl inject-smart --media-temperature=52 --health=fatal nmem0
OPTIONS
-------
-b::
--bus=::
Enforce that the operation only be carried on devices that are
attached to the given bus. Where 'bus' can be a provider name or a bus
id number.
-m::
--media-temperature=::
Inject for the media temperature smart attribute.
-M::
--media-temperature-threshold=::
Set for the smart media temperature threshold.
--media-temperature-alarm=::
Enable or disable the smart media temperature alarm. Options are
'on' or 'off'.
-c::
--ctrl-temperature=::
Inject for the controller temperature smart attribute.
-C::
--ctrl-temperature-threshold=::
Set for the smart controller temperature threshold.
--ctrl-temperature-alarm=::
Enable or disable the smart controller temperature alarm. Options are
'on' or 'off'.
-s::
--spares=::
Inject for the spares smart attribute.
-S::
--spares-threshold=::
Set for the smart spares threshold.
--spares-alarm=::
Enable or disable the smart spares alarm. Options are 'on' or 'off'.
-H::
--health=::
Smart attribute for health status. Provide either 'fatal' or 'nominal'
to set the state of the attribute.
-U::
--unsafe-shutdown=::
Set the flag to spoof an unsafe shutdown on the next power down.
-v::
--verbose::
Emit debug messages for the error injection process
include::human-option.txt[]
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-list[1],
ndctl-61.2/Documentation/ndctl/ndctl-list.txt000066400000000000000000000104231331777607200213160ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-list(1)
=============
NAME
----
ndctl-list - dump the platform nvdimm device topology and attributes in json
SYNOPSIS
--------
[verse]
'ndctl list' []
Walk all the nvdimm buses in the system and list all attached devices
along with some of their major attributes.
Options can be specified to limit the output to devices of a certain
class. Where the classes are buses, dimms, regions, and namespaces. By
default, 'ndctl list' with no options is equivalent to:
[verse]
ndctl list --namespaces --bus=all --region=all
EXAMPLE
-------
----
# ndctl list --buses --namespaces
{
"provider":"nfit_test.1",
"dev":"ndbus2",
"namespaces":[
{
"dev":"namespace9.0",
"mode":"raw",
"size":33554432,
"blockdev":"pmem9"
}
]
}
{
"provider":"nfit_test.0",
"dev":"ndbus1"
}
{
"provider":"e820",
"dev":"ndbus0",
"namespaces":[
{
"dev":"namespace0.0",
"mode":"fsdax",
"size":8589934592,
"blockdev":"pmem0"
}
]
}
----
OPTIONS
-------
-r::
--region=::
include::xable-region-options.txt[]
-d::
--dimm=::
An 'nmemX' device name, or dimm id number. Filter listing by
devices that reference the given dimm. For example to see all
namespaces comprised of storage capacity on nmem0:
----
# ndctl list --dimm=nmem0 --namespaces
----
-n::
--namespace=::
An 'namespaceX.Y' device name, or namespace region plus id tuple
'X.Y'. Limit the namespace list to the single identified device
if present.
-t::
--type=::
Filter listing by region type ('pmem' or 'blk')
-m::
--mode=::
Filter listing by the mode ('raw', 'fsdax', 'sector' or 'devdax')
of the namespace(s).
-U::
--numa-node=::
Filter listing by numa node
-B::
--buses::
Include bus info in the listing
-D::
--dimms::
Include dimm info in the listing
-H::
--health::
Include dimm health info in the listing. For example:
[verse]
{
"dev":"nmem0",
"health":{
"health_state":"non-critical",
"temperature_celsius":23,
"spares_percentage":75,
"alarm_temperature":true,
"alarm_spares":true,
"temperature_threshold":40,
"spares_threshold":5,
"life_used_percentage":5,
"shutdown_state":"clean"
}
}
-F::
--firmware::
Include dimm firmware info in the listing. For example:
[verse]
{
"dev":"nmem0",
"firmware":{
"current_version":0,
"next_version":1,
"need_powercycle":true
}
}
-X::
--device-dax::
Include device-dax ("daxregion") details when a namespace is in
"devdax" mode.
[verse]
{
"dev":"namespace0.0",
"mode":"devdax",
"size":4225761280,
"uuid":"18ae1bbb-bb62-4efc-86df-4a5caacb5dcc",
"daxregion":{
"id":0,
"size":4225761280,
"align":2097152,
"devices":[
{
"chardev":"dax0.0",
"size":4225761280
}
]
}
}
-R::
--regions::
Include region info in the listing
-N::
--namespaces::
Include namespace info in the listing. Namespace info is
listed by default if no other options are specified to the command.
-i::
--idle::
Include idle (not enabled) devices in the listing
-M::
--media-errors::
Include media errors (badblocks) in the listing. Note that the
'badblock_count' property is included in the listing by default
when the count is non-zero, otherwise it is hidden. Also, if the
namespace is in 'sector' mode the 'badblocks' listing is not
included and 'badblock_count' property may include blocks that are
located in metadata, or unused capacity in the namespace. Convert
a 'sector' namespace into 'raw' mode to list precise 'badblocks'
offsets.
[verse]
{
"dev":"namespace7.0",
"mode":"raw",
"size":33554432,
"blockdev":"pmem7",
"badblock_count":17,
"badblocks":[
{
"offset":4,
"length":1
},
{
"offset":32768,
"length":8
},
{
"offset":65528,
"length":8
}
]
}
include::human-option.txt[]
----
# ndctl list --region=7
{
"dev":"region7",
"size":67108864,
"available_size":67108864,
"type":"pmem",
"iset_id":-6382611090938810793,
"badblock_count":8
}
----
----
# ndctl list --human --region=7
{
"dev":"region7",
"size":"64.00 MiB (67.11 MB)",
"available_size":"64.00 MiB (67.11 MB)",
"type":"pmem",
"iset_id":"0xa76c6907811fae57",
"badblock_count":8
}
----
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-create-namespace[1]
ndctl-61.2/Documentation/ndctl/ndctl-read-labels.txt000066400000000000000000000013371331777607200225220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-read-labels(1)
====================
NAME
----
ndctl-read-labels - read out the label area on a dimm or set of dimms
SYNOPSIS
--------
[verse]
'ndctl read-labels' [..] []
include::labels-description.txt[]
This command dumps the raw binary data in a dimm's label area to stdout or a
file. In the multi-dimm case the data is concatenated.
OPTIONS
-------
include::labels-options.txt[]
-o::
--output::
output file
-j::
--json::
parse the label data into json assuming the 'NVDIMM Namespace
Specification' format.
include::../copyright.txt[]
SEE ALSO
--------
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
ndctl-61.2/Documentation/ndctl/ndctl-start-scrub.txt000066400000000000000000000026531331777607200226220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-start-scrub(1)
====================
NAME
----
ndctl-start-scrub - start an Address Range Scrub (ARS) operation
SYNOPSIS
--------
[verse]
'ndctl start-scrub' [ ... ] []
include::ars-description.txt[]
The kernel provides a sysfs file ('scrub') that when written with the
string "1\n" initiates an ARS operation. The 'ndctl start-scrub'
operation starts an ARS, across all specified buses, and the kernel in
turn proceeds to scrub every persistent memory address region on the
specified buses.
EXAMPLE
-------
Start a scrub on all nvdimm buses in the system. The json listing report
only includes the buses that support ARS operations.
----
# ndctl start-scrub
[
{
"provider":"nfit_test.1",
"dev":"ndbus3",
"scrub_state":"active"
},
{
"provider":"nfit_test.0",
"dev":"ndbus2",
"scrub_state":"active"
}
]
----
When specifying an individual bus, or if there is only one bus in the
system, the command reports whether ARS support is available.
----
# ndctl start-scrub e820
error starting scrub: Operation not supported
----
OPTIONS
-------
-v::
--verbose::
Emit debug messages for the ARS start process
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-wait-scrub[1],
http://www.uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf[ACPI
6.2 Specification Section 9.20.7.2 Address Range Scrubbing (ARS) Overview]
ndctl-61.2/Documentation/ndctl/ndctl-update-firmware.txt000066400000000000000000000012221331777607200234340ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-update-firmware(1)
========================
NAME
----
ndctl-update-firmware - provides for updating the firmware on an NVDIMM
SYNOPSIS
--------
[verse]
'ndctl update-firmware' []
DESCRIPTION
-----------
Provide a generic interface for updating NVDIMM firmware. The use of this
depends on support from the underlying libndctl, kernel, as well as the
platform itself.
OPTIONS
-------
::
include::xable-dimm-options.txt[]
-f::
--firmware::
firmware file used to perform the update
-v::
--verbose::
Emit debug messages for the namespace check process.
include::../copyright.txt[]
ndctl-61.2/Documentation/ndctl/ndctl-wait-scrub.txt000066400000000000000000000030441331777607200224240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-wait-scrub(1)
====================
NAME
----
ndctl-wait-scrub - wait for an Address Range Scrub (ARS) operation to complete
SYNOPSIS
--------
[verse]
'ndctl wait-scrub' [ ... ] []
include::ars-description.txt[]
The kernel provides a POLL(2) capable sysfs file ('scrub') to indicate
the state of ARS. The 'scrub' file maintains a running count of ARS runs
that have taken place. While a current run is in progress a '+'
character is emitted along with the current count. The 'ndctl
wait-scrub' operation waits for 'scrub', across all specified buses, to
indicate not in-progress at least once.
EXAMPLE
-------
Wait for scrub on all nvdimm buses in the system. The json listing
report at the end only includes the buses that support ARS operations.
----
# ndctl wait-scrub
[
{
"provider":"nfit_test.1",
"dev":"ndbus3",
"scrub_state":"idle"
},
{
"provider":"nfit_test.0",
"dev":"ndbus2",
"scrub_state":"idle"
}
]
----
When specifying an individual bus, or if there is only one bus in the
system, the command reports whether ARS support is available.
----
# ndctl wait-scrub e820
error waiting for scrub completion: Operation not supported
----
OPTIONS
-------
-v::
--verbose::
Emit debug messages for the ARS wait process
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-start-scrub[1],
http://www.uefi.org/sites/default/files/resources/ACPI%206_2_A_Sept29.pdf[ACPI
6.2 Specification Section 9.20.7.2 Address Range Scrubbing (ARS) Overview]
ndctl-61.2/Documentation/ndctl/ndctl-write-labels.txt000066400000000000000000000012361331777607200227370ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-write-labels(1)
=====================
NAME
----
ndctl-write-labels - write data to the label area on a dimm
SYNOPSIS
--------
[verse]
'ndctl write-labels [-i ]'
include::labels-description.txt[]
Read data from the input filename, or stdin, and write it to the given
device. Note that the device must not be active in any region,
otherwise the kernel will not allow write access to the device's label
data area.
OPTIONS
-------
include::labels-options.txt[]
-i::
--input::
input file
SEE ALSO
--------
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
ndctl-61.2/Documentation/ndctl/ndctl-zero-labels.txt000066400000000000000000000010441331777607200225610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl-zero-labels(1)
====================
NAME
----
ndctl-zero-labels - zero out the label area on a dimm or set of dimms
SYNOPSIS
--------
[verse]
'ndctl zero-labels' [..] []
include::labels-description.txt[]
This command resets the device to its default state by
deleting all labels.
OPTIONS
-------
include::labels-options.txt[]
include::../copyright.txt[]
SEE ALSO
--------
http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol]
ndctl-61.2/Documentation/ndctl/ndctl.txt000066400000000000000000000026421331777607200203510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
ndctl(1)
=======
NAME
----
ndctl - Manage "libnvdimm" subsystem devices (Non-volatile Memory)
SYNOPSIS
--------
[verse]
'ndctl' [--version] [--help] [OPTIONS] COMMAND [ARGS]
OPTIONS
-------
-v::
--version::
Display ndctl version.
-h::
--help::
Run ndctl help command.
DESCRIPTION
-----------
ndctl is utility for managing the "libnvdimm" kernel subsystem.
The "libnvdimm" subsystem defines a kernel device model and control
message interface for platform NVDIMM resources like those defined by
the ACPI 6.0 NFIT (NVDIMM Firmware Interface Table). Operations
supported by the tool include, provisioning capacity (namespaces), as
well as enumerating/enabling/disabling the devices (dimms, regions,
namspaces) associated with an NVDIMM bus.
include::../copyright.txt[]
SEE ALSO
--------
linkndctl:ndctl-create-namespace[1],
linkndctl:ndctl-destroy-namespace[1],
linkndctl:ndctl-check-namespace[1],
linkndctl:ndctl-enable-region[1],
linkndctl:ndctl-disable-region[1],
linkndctl:ndctl-enable-dimm[1],
linkndctl:ndctl-disable-dimm[1],
linkndctl:ndctl-enable-namespace[1],
linkndctl:ndctl-disable-namespace[1],
linkndctl:ndctl-zero-labels[1],
linkndctl:ndctl-read-labels[1],
linkndctl:ndctl-inject-error[1],
linkndctl:ndctl-list[1],
https://www.kernel.org/doc/Documentation/nvdimm/nvdimm.txt[LIBNVDIMM
Overview],
http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf[NVDIMM Driver
Writer's Guide]
ndctl-61.2/Documentation/ndctl/region-description.txt000066400000000000000000000007071331777607200230510ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
DESCRIPTION
-----------
A generic REGION device is registered for each PMEM range or
BLK-aperture set. LIBNVDIMM provides a built-in driver for these REGION
devices. This driver is responsible for reconciling the aliased DPA
mappings across all regions, parsing the LABEL, if present, and then
emitting NAMESPACE devices with the resolved/exclusive DPA-boundaries
for the nd_pmem or nd_blk device driver to consume.
ndctl-61.2/Documentation/ndctl/xable-dimm-options.txt000066400000000000000000000006051331777607200227520ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
A 'nmemX' device name, or a dimm id number. The keyword 'all' can
be specified to carry out the operation on every dimm in the system,
optionally filtered by bus id (see --bus= option).
-b::
--bus=::
Enforce that the operation only be carried on devices that are
attached to the given bus. Where 'bus' can be a provider name or a bus
id number.
ndctl-61.2/Documentation/ndctl/xable-namespace-options.txt000066400000000000000000000005361331777607200237630ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
::
A 'namespaceX.Y' device name. The keyword 'all' can be specified to carry out
the operation on every namespace in the system, optionally filtered by region
(see --region=option)
-r::
--region=::
include::xable-region-options.txt[]
-v::
--verbose::
Emit debug messages for the namespace operation
ndctl-61.2/Documentation/ndctl/xable-region-options.txt000066400000000000000000000006131331777607200233060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0
A 'regionX' device name, or a region id number. The keyword 'all' can
be specified to carry out the operation on every region in the system,
optionally filtered by bus id (see --bus= option).
-b::
--bus=::
Enforce that the operation only be carried on devices that are
attached to the given bus. Where 'bus' can be a provider name or a bus
id number.
ndctl-61.2/Makefile.am000066400000000000000000000040051331777607200146160ustar00rootroot00000000000000include Makefile.am.in
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
SUBDIRS = . daxctl/lib ndctl/lib ndctl daxctl
if ENABLE_DOCS
SUBDIRS += Documentation/ndctl Documentation/daxctl
endif
SUBDIRS += test
BUILT_SOURCES = version.m4
version.m4: FORCE
$(AM_V_GEN)$(top_srcdir)/git-version-gen
FORCE:
noinst_SCRIPTS = rhel/ndctl.spec sles/ndctl.spec
CLEANFILES += $(noinst_SCRIPTS)
do_rhel_subst = sed -e 's,VERSION,$(VERSION),g' \
-e 's,DAX_DNAME,daxctl-devel,g' \
-e 's,DNAME,ndctl-devel,g' \
-e '/^%defattr.*/d' \
-e 's,DAX_LNAME,daxctl-libs,g' \
-e 's,LNAME,ndctl-libs,g'
do_sles_subst = sed -e 's,VERSION,$(VERSION),g' \
-e 's,DAX_DNAME,libdaxctl-devel,g' \
-e 's,DNAME,libndctl-devel,g' \
-e 's,%license,%doc,g' \
-e 's,\(^License:.*GPL\)v2,\1-2.0,g' \
-e "s,DAX_LNAME,libdaxctl$$(($(LIBDAXCTL_CURRENT) - $(LIBDAXCTL_AGE))),g" \
-e "s,LNAME,libndctl$$(($(LIBNDCTL_CURRENT) - $(LIBNDCTL_AGE))),g"
rhel/ndctl.spec: ndctl.spec.in Makefile.am version.m4
$(AM_V_GEN)$(MKDIR_P) rhel; $(do_rhel_subst) < $< > $@
sles/ndctl.spec: ndctl.spec.in Makefile.am version.m4
$(AM_V_GEN)$(MKDIR_P) sles; cat sles/header $< | $(do_sles_subst) > $@
if ENABLE_BASH_COMPLETION
bashcompletiondir = $(BASH_COMPLETION_DIR)
dist_bashcompletion_DATA = contrib/ndctl
endif
noinst_LIBRARIES = libccan.a
libccan_a_SOURCES = \
ccan/str/str.h \
ccan/str/str_debug.h \
ccan/str/str.c \
ccan/str/debug.c \
ccan/list/list.h \
ccan/list/list.c \
ccan/container_of/container_of.h \
ccan/check_type/check_type.h \
ccan/build_assert/build_assert.h \
ccan/array_size/array_size.h \
ccan/minmax/minmax.h \
ccan/short_types/short_types.h \
ccan/endian/endian.h
noinst_LIBRARIES += libutil.a
libutil_a_SOURCES = \
util/parse-options.c \
util/parse-options.h \
util/usage.c \
util/size.c \
util/main.c \
util/help.c \
util/strbuf.c \
util/wrapper.c \
util/filter.c \
util/bitmap.c \
util/abspath.c
nobase_include_HEADERS = daxctl/libdaxctl.h
ndctl-61.2/Makefile.am.in000066400000000000000000000016271331777607200152320ustar00rootroot00000000000000EXTRA_DIST =
CLEANFILES =
AM_MAKEFLAGS = --no-print-directory
AM_CPPFLAGS = \
-include $(top_builddir)/config.h \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DPREFIX=\""$(prefix)"\" \
-DNDCTL_MAN_PATH=\""$(mandir)"\" \
-I${top_srcdir}/ndctl/lib \
-I${top_srcdir}/ndctl \
-I${top_srcdir}/ \
$(KMOD_CFLAGS) \
$(UDEV_CFLAGS) \
$(UUID_CFLAGS) \
$(JSON_CFLAGS)
AM_CFLAGS = ${my_CFLAGS} \
-fvisibility=hidden \
-ffunction-sections \
-fdata-sections
AM_LDFLAGS = \
-Wl,--gc-sections \
-Wl,--as-needed
SED_PROCESS = \
$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \
-e 's,@VERSION\@,$(VERSION),g' \
-e 's,@prefix\@,$(prefix),g' \
-e 's,@exec_prefix\@,$(exec_prefix),g' \
-e 's,@libdir\@,$(libdir),g' \
-e 's,@includedir\@,$(includedir),g' \
< $< > $@ || rm $@
LIBNDCTL_CURRENT=16
LIBNDCTL_REVISION=1
LIBNDCTL_AGE=10
LIBDAXCTL_CURRENT=3
LIBDAXCTL_REVISION=0
LIBDAXCTL_AGE=2
ndctl-61.2/README.md000066400000000000000000000071001331777607200140400ustar00rootroot00000000000000# ndctl
Utility library for managing the libnvdimm (non-volatile memory device)
sub-system in the Linux kernel
Build
=====
```
./autogen.sh
./configure CFLAGS='-g -O2' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64
make
make check
sudo make install
```
There are a number of packages required for the build steps that may not
be installed by default. For information about the required packages,
see the "BuildRequires:" lines in ndctl.spec.in.
https://github.com/pmem/ndctl/blob/master/ndctl.spec.in
Documentation
=============
See the latest documentation for the NVDIMM kernel sub-system here:
https://git.kernel.org/cgit/linux/kernel/git/nvdimm/nvdimm.git/tree/Documentation/nvdimm/nvdimm.txt?h=libnvdimm-for-next
A getting started guide is also available on the kernel.org nvdimm wiki:
https://nvdimm.wiki.kernel.org/start
Unit Tests
==========
The unit tests run by `make check` require the nfit_test.ko module to be
loaded. To build and install nfit_test.ko:
1. Obtain the kernel source. For example,
`git clone -b libnvdimm-for-next git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git`
1. Skip to step 3 if the kernel version is >= v4.8. Otherwise, for
kernel versions < v4.8, configure the kernel to make some memory
available to CMA (contiguous memory allocator). This will be used to
emulate DAX.
```
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=200
```
**or**
`cma=200M` on the kernel command line.
1. Compile the libnvdimm sub-system as a module, make sure "zone device"
memory is enabled, and enable the btt, pfn, and dax features of the
sub-system:
```
CONFIG_X86_PMEM_LEGACY=m
CONFIG_ZONE_DEVICE=y
CONFIG_LIBNVDIMM=m
CONFIG_BLK_DEV_PMEM=m
CONFIG_ND_BLK=m
CONFIG_BTT=y
CONFIG_NVDIMM_PFN=y
CONFIG_NVDIMM_DAX=y
CONFIG_DEV_DAX_PMEM=m
```
1. Build and install the unit test enabled libnvdimm modules in the
following order. The unit test modules need to be in place prior to
the `depmod` that runs during the final `modules_install`
```
make M=tools/testing/nvdimm
sudo make M=tools/testing/nvdimm modules_install
sudo make modules_install
```
1. Now run `make check` in the ndctl source directory, or `ndctl test`,
if ndctl was built with `--enable-test`.
Troubleshooting
===============
The unit tests will validate that the environment is set up correctly
before they try to run. If the platform is misconfigured, i.e. the unit
test modules are not available, or the test versions of the modules are
superseded by the "in-tree/production" version of the modules `make
check` will skip tests and report a message like the following in
test/test-suite.log:
```
SKIP: libndctl
==============
test/init: nfit_test_init: nfit.ko: appears to be production version: /lib/modules/4.8.8-200.fc24.x86_64/kernel/drivers/acpi/nfit/nfit.ko.xz
__ndctl_test_skip: explicit skip test_libndctl:2684
nfit_test unavailable skipping tests
```
If the unit test modules are indeed available in the modules 'extra'
directory the default depmod policy can be overridden by adding a file
to /etc/depmod.d with the following contents:
```
override nfit * extra
override device_dax * extra
override dax_pmem * extra
override libnvdimm * extra
override nd_blk * extra
override nd_btt * extra
override nd_e820 * extra
override nd_pmem * extra
```
The nfit_test module emulates pmem with memory allocated via vmalloc().
One of the side effects is that this breaks 'physically contiguous'
assumptions in the driver. Use the '--align=4K option to 'ndctl
create-namespace' to avoid these corner case scenarios.
ndctl-61.2/autogen.sh000077500000000000000000000014261331777607200145670ustar00rootroot00000000000000#!/bin/sh -e
if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then
cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \
chmod +x .git/hooks/pre-commit && \
echo "Activated pre-commit hook."
fi
$(dirname $0)/git-version-gen
reconf_args=''
[ -n "$*" ] && reconf_args="$*"
autoreconf --install --symlink $reconf_args
libdir() {
echo $(cd $1/$(gcc -print-multi-os-directory); pwd)
}
args="--prefix=/usr \
--sysconfdir=/etc \
--libdir=$(libdir /usr/lib)"
echo
echo "----------------------------------------------------------------"
echo "Initialized build system. For a common configuration please run:"
echo "----------------------------------------------------------------"
echo
echo "./configure CFLAGS='-g -O2' $args"
echo
ndctl-61.2/builtin.h000066400000000000000000000043071331777607200144060ustar00rootroot00000000000000/*
* Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _NDCTL_BUILTIN_H_
#define _NDCTL_BUILTIN_H_
extern const char ndctl_usage_string[];
extern const char ndctl_more_info_string[];
struct cmd_struct {
const char *cmd;
int (*fn)(int, const char **, void *ctx);
};
int cmd_create_nfit(int argc, const char **argv, void *ctx);
int cmd_enable_namespace(int argc, const char **argv, void *ctx);
int cmd_create_namespace(int argc, const char **argv, void *ctx);
int cmd_destroy_namespace(int argc, const char **argv, void *ctx);
int cmd_disable_namespace(int argc, const char **argv, void *ctx);
int cmd_check_namespace(int argc, const char **argv, void *ctx);
int cmd_enable_region(int argc, const char **argv, void *ctx);
int cmd_disable_region(int argc, const char **argv, void *ctx);
int cmd_enable_dimm(int argc, const char **argv, void *ctx);
int cmd_disable_dimm(int argc, const char **argv, void *ctx);
int cmd_zero_labels(int argc, const char **argv, void *ctx);
int cmd_read_labels(int argc, const char **argv, void *ctx);
int cmd_write_labels(int argc, const char **argv, void *ctx);
int cmd_init_labels(int argc, const char **argv, void *ctx);
int cmd_check_labels(int argc, const char **argv, void *ctx);
int cmd_inject_error(int argc, const char **argv, void *ctx);
int cmd_wait_scrub(int argc, const char **argv, void *ctx);
int cmd_start_scrub(int argc, const char **argv, void *ctx);
int cmd_list(int argc, const char **argv, void *ctx);
#ifdef ENABLE_TEST
int cmd_test(int argc, const char **argv, void *ctx);
#endif
#ifdef ENABLE_DESTRUCTIVE
int cmd_bat(int argc, const char **argv, void *ctx);
#endif
int cmd_update_firmware(int argc, const char **argv, void *ctx);
int cmd_inject_smart(int argc, const char **argv, void *ctx);
#endif /* _NDCTL_BUILTIN_H_ */
ndctl-61.2/ccan/000077500000000000000000000000001331777607200134675ustar00rootroot00000000000000ndctl-61.2/ccan/array_size/000077500000000000000000000000001331777607200156375ustar00rootroot00000000000000ndctl-61.2/ccan/array_size/LICENSE000077700000000000000000000000001331777607200213622../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/array_size/array_size.h000066400000000000000000000015711331777607200201640ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_ARRAY_SIZE_H
#define CCAN_ARRAY_SIZE_H
#include "config.h"
#include
/**
* ARRAY_SIZE - get the number of elements in a visible array
* @arr: the array whose size you want.
*
* This does not work on pointers, or arrays declared as [], or
* function parameters. With correct compiler support, such usage
* will cause a build error (see build_assert).
*/
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr))
#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
/* Two gcc extensions.
* &a[0] degrades to a pointer: a different type from an array */
#define _array_size_chk(arr) \
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \
typeof(&(arr)[0])))
#else
#define _array_size_chk(arr) 0
#endif
#endif /* CCAN_ALIGNOF_H */
ndctl-61.2/ccan/build_assert/000077500000000000000000000000001331777607200161475ustar00rootroot00000000000000ndctl-61.2/ccan/build_assert/LICENSE000077700000000000000000000000001331777607200216722../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/build_assert/build_assert.h000066400000000000000000000023141331777607200210000ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_BUILD_ASSERT_H
#define CCAN_BUILD_ASSERT_H
/**
* BUILD_ASSERT - assert a build-time dependency.
* @cond: the compile-time condition which must be true.
*
* Your compile will fail if the condition isn't true, or can't be evaluated
* by the compiler. This can only be used within a function.
*
* Example:
* #include
* ...
* static char *foo_to_char(struct foo *foo)
* {
* // This code needs string to be at start of foo.
* BUILD_ASSERT(offsetof(struct foo, string) == 0);
* return (char *)foo;
* }
*/
#define BUILD_ASSERT(cond) \
do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
/**
* BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
* @cond: the compile-time condition which must be true.
*
* Your compile will fail if the condition isn't true, or can't be evaluated
* by the compiler. This can be used in an expression: its value is "0".
*
* Example:
* #define foo_to_char(foo) \
* ((char *)(foo) \
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
*/
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
#endif /* CCAN_BUILD_ASSERT_H */
ndctl-61.2/ccan/check_type/000077500000000000000000000000001331777607200156055ustar00rootroot00000000000000ndctl-61.2/ccan/check_type/LICENSE000077700000000000000000000000001331777607200213302../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/check_type/check_type.h000066400000000000000000000045051331777607200201000ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_CHECK_TYPE_H
#define CCAN_CHECK_TYPE_H
#include "config.h"
/**
* check_type - issue a warning or build failure if type is not correct.
* @expr: the expression whose type we should check (not evaluated).
* @type: the exact type we expect the expression to be.
*
* This macro is usually used within other macros to try to ensure that a macro
* argument is of the expected type. No type promotion of the expression is
* done: an unsigned int is not the same as an int!
*
* check_type() always evaluates to 0.
*
* If your compiler does not support typeof, then the best we can do is fail
* to compile if the sizes of the types are unequal (a less complete check).
*
* Example:
* // They should always pass a 64-bit value to _set_some_value!
* #define set_some_value(expr) \
* _set_some_value((check_type((expr), uint64_t), (expr)))
*/
/**
* check_types_match - issue a warning or build failure if types are not same.
* @expr1: the first expression (not evaluated).
* @expr2: the second expression (not evaluated).
*
* This macro is usually used within other macros to try to ensure that
* arguments are of identical types. No type promotion of the expressions is
* done: an unsigned int is not the same as an int!
*
* check_types_match() always evaluates to 0.
*
* If your compiler does not support typeof, then the best we can do is fail
* to compile if the sizes of the types are unequal (a less complete check).
*
* Example:
* // Do subtraction to get to enclosing type, but make sure that
* // pointer is of correct type for that member.
* #define container_of(mbr_ptr, encl_type, mbr) \
* (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
* ((encl_type *) \
* ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
*/
#if HAVE_TYPEOF
#define check_type(expr, type) \
((typeof(expr) *)0 != (type *)0)
#define check_types_match(expr1, expr2) \
((typeof(expr1) *)0 != (typeof(expr2) *)0)
#else
#include
/* Without typeof, we can only test the sizes. */
#define check_type(expr, type) \
BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
#define check_types_match(expr1, expr2) \
BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
#endif /* HAVE_TYPEOF */
#endif /* CCAN_CHECK_TYPE_H */
ndctl-61.2/ccan/container_of/000077500000000000000000000000001331777607200161355ustar00rootroot00000000000000ndctl-61.2/ccan/container_of/LICENSE000077700000000000000000000000001331777607200216602../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/container_of/container_of.h000066400000000000000000000061341331777607200207600ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_CONTAINER_OF_H
#define CCAN_CONTAINER_OF_H
#include
#include "config.h"
#include
/**
* container_of - get pointer to enclosing structure
* @member_ptr: pointer to the structure member
* @containing_type: the type this member is within
* @member: the name of this member within the structure.
*
* Given a pointer to a member of a structure, this macro does pointer
* subtraction to return the pointer to the enclosing type.
*
* Example:
* struct foo {
* int fielda, fieldb;
* // ...
* };
* struct info {
* int some_other_field;
* struct foo my_foo;
* };
*
* static struct info *foo_to_info(struct foo *foo)
* {
* return container_of(foo, struct info, my_foo);
* }
*/
#define container_of(member_ptr, containing_type, member) \
((containing_type *) \
((char *)(member_ptr) \
- container_off(containing_type, member)) \
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
/**
* container_off - get offset to enclosing structure
* @containing_type: the type this member is within
* @member: the name of this member within the structure.
*
* Given a pointer to a member of a structure, this macro does
* typechecking and figures out the offset to the enclosing type.
*
* Example:
* struct foo {
* int fielda, fieldb;
* // ...
* };
* struct info {
* int some_other_field;
* struct foo my_foo;
* };
*
* static struct info *foo_to_info(struct foo *foo)
* {
* size_t off = container_off(struct info, my_foo);
* return (void *)((char *)foo - off);
* }
*/
#define container_off(containing_type, member) \
offsetof(containing_type, member)
/**
* container_of_var - get pointer to enclosing structure using a variable
* @member_ptr: pointer to the structure member
* @container_var: a pointer of same type as this member's container
* @member: the name of this member within the structure.
*
* Given a pointer to a member of a structure, this macro does pointer
* subtraction to return the pointer to the enclosing type.
*
* Example:
* static struct info *foo_to_i(struct foo *foo)
* {
* struct info *i = container_of_var(foo, i, my_foo);
* return i;
* }
*/
#if HAVE_TYPEOF
#define container_of_var(member_ptr, container_var, member) \
container_of(member_ptr, typeof(*container_var), member)
#else
#define container_of_var(member_ptr, container_var, member) \
((void *)((char *)(member_ptr) - \
container_off_var(container_var, member)))
#endif
/**
* container_off_var - get offset of a field in enclosing structure
* @container_var: a pointer to a container structure
* @member: the name of a member within the structure.
*
* Given (any) pointer to a structure and a its member name, this
* macro does pointer subtraction to return offset of member in a
* structure memory layout.
*
*/
#if HAVE_TYPEOF
#define container_off_var(var, member) \
container_off(typeof(*var), member)
#else
#define container_off_var(var, member) \
((const char *)&(var)->member - (const char *)(var))
#endif
#endif /* CCAN_CONTAINER_OF_H */
ndctl-61.2/ccan/endian/000077500000000000000000000000001331777607200147255ustar00rootroot00000000000000ndctl-61.2/ccan/endian/LICENSE000077700000000000000000000000001331777607200204502../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/endian/endian.h000066400000000000000000000220031331777607200163310ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_ENDIAN_H
#define CCAN_ENDIAN_H
#include
#include "config.h"
/**
* BSWAP_16 - reverse bytes in a constant uint16_t value.
* @val: constant value whose bytes to swap.
*
* Designed to be usable in constant-requiring initializers.
*
* Example:
* struct mystruct {
* char buf[BSWAP_16(0x1234)];
* };
*/
#define BSWAP_16(val) \
((((uint16_t)(val) & 0x00ff) << 8) \
| (((uint16_t)(val) & 0xff00) >> 8))
/**
* BSWAP_32 - reverse bytes in a constant uint32_t value.
* @val: constant value whose bytes to swap.
*
* Designed to be usable in constant-requiring initializers.
*
* Example:
* struct mystruct {
* char buf[BSWAP_32(0xff000000)];
* };
*/
#define BSWAP_32(val) \
((((uint32_t)(val) & 0x000000ff) << 24) \
| (((uint32_t)(val) & 0x0000ff00) << 8) \
| (((uint32_t)(val) & 0x00ff0000) >> 8) \
| (((uint32_t)(val) & 0xff000000) >> 24))
/**
* BSWAP_64 - reverse bytes in a constant uint64_t value.
* @val: constantvalue whose bytes to swap.
*
* Designed to be usable in constant-requiring initializers.
*
* Example:
* struct mystruct {
* char buf[BSWAP_64(0xff00000000000000ULL)];
* };
*/
#define BSWAP_64(val) \
((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \
| (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \
| (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \
| (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \
| (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \
| (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \
| (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \
| (((uint64_t)(val) & 0xff00000000000000ULL) >> 56))
#if HAVE_BYTESWAP_H
#include
#else
/**
* bswap_16 - reverse bytes in a uint16_t value.
* @val: value whose bytes to swap.
*
* Example:
* // Output contains "1024 is 4 as two bytes reversed"
* printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
*/
static inline uint16_t bswap_16(uint16_t val)
{
return BSWAP_16(val);
}
/**
* bswap_32 - reverse bytes in a uint32_t value.
* @val: value whose bytes to swap.
*
* Example:
* // Output contains "1024 is 262144 as four bytes reversed"
* printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
*/
static inline uint32_t bswap_32(uint32_t val)
{
return BSWAP_32(val);
}
#endif /* !HAVE_BYTESWAP_H */
#if !HAVE_BSWAP_64
/**
* bswap_64 - reverse bytes in a uint64_t value.
* @val: value whose bytes to swap.
*
* Example:
* // Output contains "1024 is 1125899906842624 as eight bytes reversed"
* printf("1024 is %llu as eight bytes reversed\n",
* (unsigned long long)bswap_64(1024));
*/
static inline uint64_t bswap_64(uint64_t val)
{
return BSWAP_64(val);
}
#endif
/* Sanity check the defines. We don't handle weird endianness. */
#if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN
#error "Unknown endian"
#elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
#error "Can't compile for both big and little endian."
#endif
#ifdef __CHECKER__
/* sparse needs forcing to remove bitwise attribute from ccan/short_types */
#define ENDIAN_CAST __attribute__((force))
#define ENDIAN_TYPE __attribute__((bitwise))
#else
#define ENDIAN_CAST
#define ENDIAN_TYPE
#endif
typedef uint64_t ENDIAN_TYPE leint64_t;
typedef uint64_t ENDIAN_TYPE beint64_t;
typedef uint32_t ENDIAN_TYPE leint32_t;
typedef uint32_t ENDIAN_TYPE beint32_t;
typedef uint16_t ENDIAN_TYPE leint16_t;
typedef uint16_t ENDIAN_TYPE beint16_t;
#if HAVE_LITTLE_ENDIAN
/**
* CPU_TO_LE64 - convert a constant uint64_t value to little-endian
* @native: constant to convert
*/
#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)(native))
/**
* CPU_TO_LE32 - convert a constant uint32_t value to little-endian
* @native: constant to convert
*/
#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)(native))
/**
* CPU_TO_LE16 - convert a constant uint16_t value to little-endian
* @native: constant to convert
*/
#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)(native))
/**
* LE64_TO_CPU - convert a little-endian uint64_t constant
* @le_val: little-endian constant to convert
*/
#define LE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
/**
* LE32_TO_CPU - convert a little-endian uint32_t constant
* @le_val: little-endian constant to convert
*/
#define LE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
/**
* LE16_TO_CPU - convert a little-endian uint16_t constant
* @le_val: little-endian constant to convert
*/
#define LE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
#else /* ... HAVE_BIG_ENDIAN */
#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)BSWAP_64(native))
#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)BSWAP_32(native))
#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)BSWAP_16(native))
#define LE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
#define LE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
#define LE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
#endif /* HAVE_BIG_ENDIAN */
#if HAVE_BIG_ENDIAN
/**
* CPU_TO_BE64 - convert a constant uint64_t value to big-endian
* @native: constant to convert
*/
#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)(native))
/**
* CPU_TO_BE32 - convert a constant uint32_t value to big-endian
* @native: constant to convert
*/
#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)(native))
/**
* CPU_TO_BE16 - convert a constant uint16_t value to big-endian
* @native: constant to convert
*/
#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)(native))
/**
* BE64_TO_CPU - convert a big-endian uint64_t constant
* @le_val: big-endian constant to convert
*/
#define BE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
/**
* BE32_TO_CPU - convert a big-endian uint32_t constant
* @le_val: big-endian constant to convert
*/
#define BE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
/**
* BE16_TO_CPU - convert a big-endian uint16_t constant
* @le_val: big-endian constant to convert
*/
#define BE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
#else /* ... HAVE_LITTLE_ENDIAN */
#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)BSWAP_64(native))
#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)BSWAP_32(native))
#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)BSWAP_16(native))
#define BE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
#define BE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
#define BE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
#endif /* HAVE_LITTE_ENDIAN */
/**
* cpu_to_le64 - convert a uint64_t value to little-endian
* @native: value to convert
*/
static inline leint64_t cpu_to_le64(uint64_t native)
{
return CPU_TO_LE64(native);
}
/**
* cpu_to_le32 - convert a uint32_t value to little-endian
* @native: value to convert
*/
static inline leint32_t cpu_to_le32(uint32_t native)
{
return CPU_TO_LE32(native);
}
/**
* cpu_to_le16 - convert a uint16_t value to little-endian
* @native: value to convert
*/
static inline leint16_t cpu_to_le16(uint16_t native)
{
return CPU_TO_LE16(native);
}
/**
* le64_to_cpu - convert a little-endian uint64_t value
* @le_val: little-endian value to convert
*/
static inline uint64_t le64_to_cpu(leint64_t le_val)
{
return LE64_TO_CPU(le_val);
}
/**
* le32_to_cpu - convert a little-endian uint32_t value
* @le_val: little-endian value to convert
*/
static inline uint32_t le32_to_cpu(leint32_t le_val)
{
return LE32_TO_CPU(le_val);
}
/**
* le16_to_cpu - convert a little-endian uint16_t value
* @le_val: little-endian value to convert
*/
static inline uint16_t le16_to_cpu(leint16_t le_val)
{
return LE16_TO_CPU(le_val);
}
/**
* cpu_to_be64 - convert a uint64_t value to big endian.
* @native: value to convert
*/
static inline beint64_t cpu_to_be64(uint64_t native)
{
return ((ENDIAN_CAST beint64_t)BSWAP_64(native));
return CPU_TO_BE64(native);
}
/**
* cpu_to_be32 - convert a uint32_t value to big endian.
* @native: value to convert
*/
static inline beint32_t cpu_to_be32(uint32_t native)
{
return CPU_TO_BE32(native);
}
/**
* cpu_to_be16 - convert a uint16_t value to big endian.
* @native: value to convert
*/
static inline beint16_t cpu_to_be16(uint16_t native)
{
return CPU_TO_BE16(native);
}
/**
* be64_to_cpu - convert a big-endian uint64_t value
* @be_val: big-endian value to convert
*/
static inline uint64_t be64_to_cpu(beint64_t be_val)
{
return BE64_TO_CPU(be_val);
}
/**
* be32_to_cpu - convert a big-endian uint32_t value
* @be_val: big-endian value to convert
*/
static inline uint32_t be32_to_cpu(beint32_t be_val)
{
return BE32_TO_CPU(be_val);
}
/**
* be16_to_cpu - convert a big-endian uint16_t value
* @be_val: big-endian value to convert
*/
static inline uint16_t be16_to_cpu(beint16_t be_val)
{
return BE16_TO_CPU(be_val);
}
/* Whichever they include first, they get these definitions. */
#ifdef CCAN_SHORT_TYPES_H
/**
* be64/be32/be16 - 64/32/16 bit big-endian representation.
*/
typedef beint64_t be64;
typedef beint32_t be32;
typedef beint16_t be16;
/**
* le64/le32/le16 - 64/32/16 bit little-endian representation.
*/
typedef leint64_t le64;
typedef leint32_t le32;
typedef leint16_t le16;
#endif
#endif /* CCAN_ENDIAN_H */
ndctl-61.2/ccan/list/000077500000000000000000000000001331777607200144425ustar00rootroot00000000000000ndctl-61.2/ccan/list/LICENSE000077700000000000000000000000001331777607200206572../../licenses/BSD-MITustar00rootroot00000000000000ndctl-61.2/ccan/list/list.c000066400000000000000000000017501331777607200155640ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */
#include
#include
#include "list.h"
static void *corrupt(const char *abortstr,
const struct list_node *head,
const struct list_node *node,
unsigned int count)
{
if (abortstr) {
fprintf(stderr,
"%s: prev corrupt in node %p (%u) of %p\n",
abortstr, node, count, head);
abort();
}
return NULL;
}
struct list_node *list_check_node(const struct list_node *node,
const char *abortstr)
{
const struct list_node *p, *n;
int count = 0;
for (p = node, n = node->next; n != node; p = n, n = n->next) {
count++;
if (n->prev != p)
return corrupt(abortstr, node, n, count);
}
/* Check prev on head node. */
if (node->prev != p)
return corrupt(abortstr, node, node, 0);
return (struct list_node *)node;
}
struct list_head *list_check(const struct list_head *h, const char *abortstr)
{
if (!list_check_node(&h->n, abortstr))
return NULL;
return (struct list_head *)h;
}
ndctl-61.2/ccan/list/list.h000066400000000000000000000447171331777607200156030ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */
#ifndef CCAN_LIST_H
#define CCAN_LIST_H
//#define CCAN_LIST_DEBUG 1
#include
#include
#include
#include
#include
/**
* struct list_node - an entry in a doubly-linked list
* @next: next entry (self if empty)
* @prev: previous entry (self if empty)
*
* This is used as an entry in a linked list.
* Example:
* struct child {
* const char *name;
* // Linked list of all us children.
* struct list_node list;
* };
*/
struct list_node
{
struct list_node *next, *prev;
};
/**
* struct list_head - the head of a doubly-linked list
* @h: the list_head (containing next and prev pointers)
*
* This is used as the head of a linked list.
* Example:
* struct parent {
* const char *name;
* struct list_head children;
* unsigned int num_children;
* };
*/
struct list_head
{
struct list_node n;
};
/**
* list_check - check head of a list for consistency
* @h: the list_head
* @abortstr: the location to print on aborting, or NULL.
*
* Because list_nodes have redundant information, consistency checking between
* the back and forward links can be done. This is useful as a debugging check.
* If @abortstr is non-NULL, that will be printed in a diagnostic if the list
* is inconsistent, and the function will abort.
*
* Returns the list head if the list is consistent, NULL if not (it
* can never return NULL if @abortstr is set).
*
* See also: list_check_node()
*
* Example:
* static void dump_parent(struct parent *p)
* {
* struct child *c;
*
* printf("%s (%u children):\n", p->name, p->num_children);
* list_check(&p->children, "bad child list");
* list_for_each(&p->children, c, list)
* printf(" -> %s\n", c->name);
* }
*/
struct list_head *list_check(const struct list_head *h, const char *abortstr);
/**
* list_check_node - check node of a list for consistency
* @n: the list_node
* @abortstr: the location to print on aborting, or NULL.
*
* Check consistency of the list node is in (it must be in one).
*
* See also: list_check()
*
* Example:
* static void dump_child(const struct child *c)
* {
* list_check_node(&c->list, "bad child list");
* printf("%s\n", c->name);
* }
*/
struct list_node *list_check_node(const struct list_node *n,
const char *abortstr);
#define LIST_LOC __FILE__ ":" stringify(__LINE__)
#ifdef CCAN_LIST_DEBUG
#define list_debug(h, loc) list_check((h), loc)
#define list_debug_node(n, loc) list_check_node((n), loc)
#else
#define list_debug(h, loc) (h)
#define list_debug_node(n, loc) (n)
#endif
/**
* LIST_HEAD_INIT - initializer for an empty list_head
* @name: the name of the list.
*
* Explicit initializer for an empty list.
*
* See also:
* LIST_HEAD, list_head_init()
*
* Example:
* static struct list_head my_list = LIST_HEAD_INIT(my_list);
*/
#define LIST_HEAD_INIT(name) { { &name.n, &name.n } }
/**
* LIST_HEAD - define and initialize an empty list_head
* @name: the name of the list.
*
* The LIST_HEAD macro defines a list_head and initializes it to an empty
* list. It can be prepended by "static" to define a static list_head.
*
* See also:
* LIST_HEAD_INIT, list_head_init()
*
* Example:
* static LIST_HEAD(my_global_list);
*/
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/**
* list_head_init - initialize a list_head
* @h: the list_head to set to the empty list
*
* Example:
* ...
* struct parent *parent = malloc(sizeof(*parent));
*
* list_head_init(&parent->children);
* parent->num_children = 0;
*/
static inline void list_head_init(struct list_head *h)
{
h->n.next = h->n.prev = &h->n;
}
/**
* list_add - add an entry at the start of a linked list.
* @h: the list_head to add the node to
* @n: the list_node to add to the list.
*
* The list_node does not need to be initialized; it will be overwritten.
* Example:
* struct child *child = malloc(sizeof(*child));
*
* child->name = "marvin";
* list_add(&parent->children, &child->list);
* parent->num_children++;
*/
#define list_add(h, n) list_add_(h, n, LIST_LOC)
static inline void list_add_(struct list_head *h,
struct list_node *n,
const char *abortstr)
{
n->next = h->n.next;
n->prev = &h->n;
h->n.next->prev = n;
h->n.next = n;
(void)list_debug(h, abortstr);
}
/**
* list_add_tail - add an entry at the end of a linked list.
* @h: the list_head to add the node to
* @n: the list_node to add to the list.
*
* The list_node does not need to be initialized; it will be overwritten.
* Example:
* list_add_tail(&parent->children, &child->list);
* parent->num_children++;
*/
#define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC)
static inline void list_add_tail_(struct list_head *h,
struct list_node *n,
const char *abortstr)
{
n->next = &h->n;
n->prev = h->n.prev;
h->n.prev->next = n;
h->n.prev = n;
(void)list_debug(h, abortstr);
}
/**
* list_empty - is a list empty?
* @h: the list_head
*
* If the list is empty, returns true.
*
* Example:
* assert(list_empty(&parent->children) == (parent->num_children == 0));
*/
#define list_empty(h) list_empty_(h, LIST_LOC)
static inline bool list_empty_(const struct list_head *h, const char* abortstr)
{
(void)list_debug(h, abortstr);
return h->n.next == &h->n;
}
/**
* list_empty_nodebug - is a list empty (and don't perform debug checks)?
* @h: the list_head
*
* If the list is empty, returns true.
* This differs from list_empty() in that if CCAN_LIST_DEBUG is set it
* will NOT perform debug checks. Only use this function if you REALLY
* know what you're doing.
*
* Example:
* assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0));
*/
#ifndef CCAN_LIST_DEBUG
#define list_empty_nodebug(h) list_empty(h)
#else
static inline bool list_empty_nodebug(const struct list_head *h)
{
return h->n.next == &h->n;
}
#endif
/**
* list_del - delete an entry from an (unknown) linked list.
* @n: the list_node to delete from the list.
*
* Note that this leaves @n in an undefined state; it can be added to
* another list, but not deleted again.
*
* See also:
* list_del_from()
*
* Example:
* list_del(&child->list);
* parent->num_children--;
*/
#define list_del(n) list_del_(n, LIST_LOC)
static inline void list_del_(struct list_node *n, const char* abortstr)
{
(void)list_debug_node(n, abortstr);
n->next->prev = n->prev;
n->prev->next = n->next;
#ifdef CCAN_LIST_DEBUG
/* Catch use-after-del. */
n->next = n->prev = NULL;
#endif
}
/**
* list_del_from - delete an entry from a known linked list.
* @h: the list_head the node is in.
* @n: the list_node to delete from the list.
*
* This explicitly indicates which list a node is expected to be in,
* which is better documentation and can catch more bugs.
*
* See also: list_del()
*
* Example:
* list_del_from(&parent->children, &child->list);
* parent->num_children--;
*/
static inline void list_del_from(struct list_head *h, struct list_node *n)
{
#ifdef CCAN_LIST_DEBUG
{
/* Thorough check: make sure it was in list! */
struct list_node *i;
for (i = h->n.next; i != n; i = i->next)
assert(i != &h->n);
}
#endif /* CCAN_LIST_DEBUG */
/* Quick test that catches a surprising number of bugs. */
assert(!list_empty(h));
list_del(n);
}
/**
* list_entry - convert a list_node back into the structure containing it.
* @n: the list_node
* @type: the type of the entry
* @member: the list_node member of the type
*
* Example:
* // First list entry is children.next; convert back to child.
* child = list_entry(parent->children.n.next, struct child, list);
*
* See Also:
* list_top(), list_for_each()
*/
#define list_entry(n, type, member) container_of(n, type, member)
/**
* list_top - get the first entry in a list
* @h: the list_head
* @type: the type of the entry
* @member: the list_node member of the type
*
* If the list is empty, returns NULL.
*
* Example:
* struct child *first;
* first = list_top(&parent->children, struct child, list);
* if (!first)
* printf("Empty list!\n");
*/
#define list_top(h, type, member) \
((type *)list_top_((h), list_off_(type, member)))
static inline const void *list_top_(const struct list_head *h, size_t off)
{
if (list_empty(h))
return NULL;
return (const char *)h->n.next - off;
}
/**
* list_pop - remove the first entry in a list
* @h: the list_head
* @type: the type of the entry
* @member: the list_node member of the type
*
* If the list is empty, returns NULL.
*
* Example:
* struct child *one;
* one = list_pop(&parent->children, struct child, list);
* if (!one)
* printf("Empty list!\n");
*/
#define list_pop(h, type, member) \
((type *)list_pop_((h), list_off_(type, member)))
static inline const void *list_pop_(const struct list_head *h, size_t off)
{
struct list_node *n;
if (list_empty(h))
return NULL;
n = h->n.next;
list_del(n);
return (const char *)n - off;
}
/**
* list_tail - get the last entry in a list
* @h: the list_head
* @type: the type of the entry
* @member: the list_node member of the type
*
* If the list is empty, returns NULL.
*
* Example:
* struct child *last;
* last = list_tail(&parent->children, struct child, list);
* if (!last)
* printf("Empty list!\n");
*/
#define list_tail(h, type, member) \
((type *)list_tail_((h), list_off_(type, member)))
static inline const void *list_tail_(const struct list_head *h, size_t off)
{
if (list_empty(h))
return NULL;
return (const char *)h->n.prev - off;
}
/**
* list_for_each - iterate through a list.
* @h: the list_head (warning: evaluated multiple times!)
* @i: the structure containing the list_node
* @member: the list_node member of the structure
*
* This is a convenient wrapper to iterate @i over the entire list. It's
* a for loop, so you can break and continue as normal.
*
* Example:
* list_for_each(&parent->children, child, list)
* printf("Name: %s\n", child->name);
*/
#define list_for_each(h, i, member) \
list_for_each_off(h, i, list_off_var_(i, member))
/**
* list_for_each_rev - iterate through a list backwards.
* @h: the list_head
* @i: the structure containing the list_node
* @member: the list_node member of the structure
*
* This is a convenient wrapper to iterate @i over the entire list. It's
* a for loop, so you can break and continue as normal.
*
* Example:
* list_for_each_rev(&parent->children, child, list)
* printf("Name: %s\n", child->name);
*/
#define list_for_each_rev(h, i, member) \
for (i = container_of_var(list_debug(h, LIST_LOC)->n.prev, i, member); \
&i->member != &(h)->n; \
i = container_of_var(i->member.prev, i, member))
/**
* list_for_each_safe - iterate through a list, maybe during deletion
* @h: the list_head
* @i: the structure containing the list_node
* @nxt: the structure containing the list_node
* @member: the list_node member of the structure
*
* This is a convenient wrapper to iterate @i over the entire list. It's
* a for loop, so you can break and continue as normal. The extra variable
* @nxt is used to hold the next element, so you can delete @i from the list.
*
* Example:
* struct child *next;
* list_for_each_safe(&parent->children, child, next, list) {
* list_del(&child->list);
* parent->num_children--;
* }
*/
#define list_for_each_safe(h, i, nxt, member) \
list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
/**
* list_next - get the next entry in a list
* @h: the list_head
* @i: a pointer to an entry in the list.
* @member: the list_node member of the structure
*
* If @i was the last entry in the list, returns NULL.
*
* Example:
* struct child *second;
* second = list_next(&parent->children, first, list);
* if (!second)
* printf("No second child!\n");
*/
#define list_next(h, i, member) \
((list_typeof(i))list_entry_or_null(list_debug(h, \
__FILE__ ":" stringify(__LINE__)), \
(i)->member.next, \
list_off_var_((i), member)))
/**
* list_prev - get the previous entry in a list
* @h: the list_head
* @i: a pointer to an entry in the list.
* @member: the list_node member of the structure
*
* If @i was the first entry in the list, returns NULL.
*
* Example:
* first = list_prev(&parent->children, second, list);
* if (!first)
* printf("Can't go back to first child?!\n");
*/
#define list_prev(h, i, member) \
((list_typeof(i))list_entry_or_null(list_debug(h, \
__FILE__ ":" stringify(__LINE__)), \
(i)->member.prev, \
list_off_var_((i), member)))
/**
* list_append_list - empty one list onto the end of another.
* @to: the list to append into
* @from: the list to empty.
*
* This takes the entire contents of @from and moves it to the end of
* @to. After this @from will be empty.
*
* Example:
* struct list_head adopter;
*
* list_append_list(&adopter, &parent->children);
* assert(list_empty(&parent->children));
* parent->num_children = 0;
*/
#define list_append_list(t, f) list_append_list_(t, f, \
__FILE__ ":" stringify(__LINE__))
static inline void list_append_list_(struct list_head *to,
struct list_head *from,
const char *abortstr)
{
struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
struct list_node *to_tail = list_debug(to, abortstr)->n.prev;
/* Sew in head and entire list. */
to->n.prev = from_tail;
from_tail->next = &to->n;
to_tail->next = &from->n;
from->n.prev = to_tail;
/* Now remove head. */
list_del(&from->n);
list_head_init(from);
}
/**
* list_prepend_list - empty one list into the start of another.
* @to: the list to prepend into
* @from: the list to empty.
*
* This takes the entire contents of @from and moves it to the start
* of @to. After this @from will be empty.
*
* Example:
* list_prepend_list(&adopter, &parent->children);
* assert(list_empty(&parent->children));
* parent->num_children = 0;
*/
#define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC)
static inline void list_prepend_list_(struct list_head *to,
struct list_head *from,
const char *abortstr)
{
struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
struct list_node *to_head = list_debug(to, abortstr)->n.next;
/* Sew in head and entire list. */
to->n.next = &from->n;
from->n.prev = &to->n;
to_head->prev = from_tail;
from_tail->next = to_head;
/* Now remove head. */
list_del(&from->n);
list_head_init(from);
}
/**
* list_for_each_off - iterate through a list of memory regions.
* @h: the list_head
* @i: the pointer to a memory region wich contains list node data.
* @off: offset(relative to @i) at which list node data resides.
*
* This is a low-level wrapper to iterate @i over the entire list, used to
* implement all oher, more high-level, for-each constructs. It's a for loop,
* so you can break and continue as normal.
*
* WARNING! Being the low-level macro that it is, this wrapper doesn't know
* nor care about the type of @i. The only assumtion made is that @i points
* to a chunk of memory that at some @offset, relative to @i, contains a
* properly filled `struct node_list' which in turn contains pointers to
* memory chunks and it's turtles all the way down. Whith all that in mind
* remember that given the wrong pointer/offset couple this macro will
* happilly churn all you memory untill SEGFAULT stops it, in other words
* caveat emptor.
*
* It is worth mentioning that one of legitimate use-cases for that wrapper
* is operation on opaque types with known offset for `struct list_node'
* member(preferably 0), because it allows you not to disclose the type of
* @i.
*
* Example:
* list_for_each_off(&parent->children, child,
* offsetof(struct child, list))
* printf("Name: %s\n", child->name);
*/
#define list_for_each_off(h, i, off) \
for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.next, \
(off)); \
list_node_from_off_((void *)i, (off)) != &(h)->n; \
i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \
(off)))
/**
* list_for_each_safe_off - iterate through a list of memory regions, maybe
* during deletion
* @h: the list_head
* @i: the pointer to a memory region wich contains list node data.
* @nxt: the structure containing the list_node
* @off: offset(relative to @i) at which list node data resides.
*
* For details see `list_for_each_off' and `list_for_each_safe'
* descriptions.
*
* Example:
* list_for_each_safe_off(&parent->children, child,
* next, offsetof(struct child, list))
* printf("Name: %s\n", child->name);
*/
#define list_for_each_safe_off(h, i, nxt, off) \
for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.next, \
(off)), \
nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \
(off)); \
list_node_from_off_(i, (off)) != &(h)->n; \
i = nxt, \
nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \
(off)))
/* Other -off variants. */
#define list_entry_off(n, type, off) \
((type *)list_node_from_off_((n), (off)))
#define list_head_off(h, type, off) \
((type *)list_head_off((h), (off)))
#define list_tail_off(h, type, off) \
((type *)list_tail_((h), (off)))
#define list_add_off(h, n, off) \
list_add((h), list_node_from_off_((n), (off)))
#define list_del_off(n, off) \
list_del(list_node_from_off_((n), (off)))
#define list_del_from_off(h, n, off) \
list_del_from(h, list_node_from_off_((n), (off)))
/* Offset helper functions so we only single-evaluate. */
static inline void *list_node_to_off_(struct list_node *node, size_t off)
{
return (void *)((char *)node - off);
}
static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
{
return (struct list_node *)((char *)ptr + off);
}
/* Get the offset of the member, but make sure it's a list_node. */
#define list_off_(type, member) \
(container_off(type, member) + \
check_type(((type *)0)->member, struct list_node))
#define list_off_var_(var, member) \
(container_off_var(var, member) + \
check_type(var->member, struct list_node))
#if HAVE_TYPEOF
#define list_typeof(var) typeof(var)
#else
#define list_typeof(var) void *
#endif
/* Returns member, or NULL if at end of list. */
static inline void *list_entry_or_null(const struct list_head *h,
const struct list_node *n,
size_t off)
{
if (n == &h->n)
return NULL;
return (char *)n - off;
}
#endif /* CCAN_LIST_H */
ndctl-61.2/ccan/minmax/000077500000000000000000000000001331777607200147605ustar00rootroot00000000000000ndctl-61.2/ccan/minmax/LICENSE000077700000000000000000000000001331777607200205032../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/minmax/minmax.h000066400000000000000000000023721331777607200164260ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_MINMAX_H
#define CCAN_MINMAX_H
#include "config.h"
#include
#if !HAVE_STATEMENT_EXPR || !HAVE_TYPEOF
/*
* Without these, there's no way to avoid unsafe double evaluation of
* the arguments
*/
#error Sorry, minmax module requires statement expressions and typeof
#endif
#if HAVE_BUILTIN_TYPES_COMPATIBLE_P
#define MINMAX_ASSERT_COMPATIBLE(a, b) \
BUILD_ASSERT(__builtin_types_compatible_p(a, b))
#else
#define MINMAX_ASSERT_COMPATIBLE(a, b) \
do { } while (0)
#endif
#define min(a, b) \
({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
MINMAX_ASSERT_COMPATIBLE(typeof(_a), typeof(_b)); \
_a < _b ? _a : _b; \
})
#define max(a, b) \
({ \
typeof(a) __a = (a); \
typeof(b) __b = (b); \
MINMAX_ASSERT_COMPATIBLE(typeof(__a), typeof(__b)); \
__a > __b ? __a : __b; \
})
#define clamp(v, f, c) (max(min((v), (c)), (f)))
#define min_t(t, a, b) \
({ \
t _ta = (a); \
t _tb = (b); \
min(_ta, _tb); \
})
#define max_t(t, a, b) \
({ \
t _ta = (a); \
t _tb = (b); \
max(_ta, _tb); \
})
#define clamp_t(t, v, f, c) \
({ \
t _tv = (v); \
t _tf = (f); \
t _tc = (c); \
clamp(_tv, _tf, _tc); \
})
#endif /* CCAN_MINMAX_H */
ndctl-61.2/ccan/short_types/000077500000000000000000000000001331777607200160525ustar00rootroot00000000000000ndctl-61.2/ccan/short_types/LICENSE000077700000000000000000000000001331777607200215752../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/short_types/short_types.h000066400000000000000000000014311331777607200206050ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_SHORT_TYPES_H
#define CCAN_SHORT_TYPES_H
#include
/**
* u64/s64/u32/s32/u16/s16/u8/s8 - short names for explicitly-sized types.
*/
typedef uint64_t u64;
typedef int64_t s64;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint16_t u16;
typedef int16_t s16;
typedef uint8_t u8;
typedef int8_t s8;
/* Whichever they include first, they get these definitions. */
#ifdef CCAN_ENDIAN_H
/**
* be64/be32/be16 - 64/32/16 bit big-endian representation.
*/
typedef beint64_t be64;
typedef beint32_t be32;
typedef beint16_t be16;
/**
* le64/le32/le16 - 64/32/16 bit little-endian representation.
*/
typedef leint64_t le64;
typedef leint32_t le32;
typedef leint16_t le16;
#endif
#endif /* CCAN_SHORT_TYPES_H */
ndctl-61.2/ccan/str/000077500000000000000000000000001331777607200142775ustar00rootroot00000000000000ndctl-61.2/ccan/str/LICENSE000077700000000000000000000000001331777607200200222../../licenses/CC0ustar00rootroot00000000000000ndctl-61.2/ccan/str/debug.c000066400000000000000000000031021331777607200155250ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#include "config.h"
#include
#include
#include
#include
#ifdef CCAN_STR_DEBUG
/* Because we mug the real ones with macros, we need our own wrappers. */
int str_isalnum(int i)
{
assert(i >= -1 && i < 256);
return isalnum(i);
}
int str_isalpha(int i)
{
assert(i >= -1 && i < 256);
return isalpha(i);
}
int str_isascii(int i)
{
assert(i >= -1 && i < 256);
return isascii(i);
}
#if HAVE_ISBLANK
int str_isblank(int i)
{
assert(i >= -1 && i < 256);
return isblank(i);
}
#endif
int str_iscntrl(int i)
{
assert(i >= -1 && i < 256);
return iscntrl(i);
}
int str_isdigit(int i)
{
assert(i >= -1 && i < 256);
return isdigit(i);
}
int str_isgraph(int i)
{
assert(i >= -1 && i < 256);
return isgraph(i);
}
int str_islower(int i)
{
assert(i >= -1 && i < 256);
return islower(i);
}
int str_isprint(int i)
{
assert(i >= -1 && i < 256);
return isprint(i);
}
int str_ispunct(int i)
{
assert(i >= -1 && i < 256);
return ispunct(i);
}
int str_isspace(int i)
{
assert(i >= -1 && i < 256);
return isspace(i);
}
int str_isupper(int i)
{
assert(i >= -1 && i < 256);
return isupper(i);
}
int str_isxdigit(int i)
{
assert(i >= -1 && i < 256);
return isxdigit(i);
}
#undef strstr
#undef strchr
#undef strrchr
char *str_strstr(const char *haystack, const char *needle)
{
return strstr(haystack, needle);
}
char *str_strchr(const char *haystack, int c)
{
return strchr(haystack, c);
}
char *str_strrchr(const char *haystack, int c)
{
return strrchr(haystack, c);
}
#endif
ndctl-61.2/ccan/str/str.c000066400000000000000000000004331331777607200152530ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#include
size_t strcount(const char *haystack, const char *needle)
{
size_t i = 0, nlen = strlen(needle);
while ((haystack = strstr(haystack, needle)) != NULL) {
i++;
haystack += nlen;
}
return i;
}
ndctl-61.2/ccan/str/str.h000066400000000000000000000135031331777607200152620ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_STR_H
#define CCAN_STR_H
#include "config.h"
#include
#include
#include
#include
/**
* streq - Are two strings equal?
* @a: first string
* @b: first string
*
* This macro is arguably more readable than "!strcmp(a, b)".
*
* Example:
* if (streq(somestring, ""))
* printf("String is empty!\n");
*/
#define streq(a,b) (strcmp((a),(b)) == 0)
/**
* strstarts - Does this string start with this prefix?
* @str: string to test
* @prefix: prefix to look for at start of str
*
* Example:
* if (strstarts(somestring, "foo"))
* printf("String %s begins with 'foo'!\n", somestring);
*/
#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
/**
* strends - Does this string end with this postfix?
* @str: string to test
* @postfix: postfix to look for at end of str
*
* Example:
* if (strends(somestring, "foo"))
* printf("String %s end with 'foo'!\n", somestring);
*/
static inline bool strends(const char *str, const char *postfix)
{
if (strlen(str) < strlen(postfix))
return false;
return streq(str + strlen(str) - strlen(postfix), postfix);
}
/**
* stringify - Turn expression into a string literal
* @expr: any C expression
*
* Example:
* #define PRINT_COND_IF_FALSE(cond) \
* ((cond) || printf("%s is false!", stringify(cond)))
*/
#define stringify(expr) stringify_1(expr)
/* Double-indirection required to stringify expansions */
#define stringify_1(expr) #expr
/**
* strcount - Count number of (non-overlapping) occurrences of a substring.
* @haystack: a C string
* @needle: a substring
*
* Example:
* assert(strcount("aaa aaa", "a") == 6);
* assert(strcount("aaa aaa", "ab") == 0);
* assert(strcount("aaa aaa", "aa") == 2);
*/
size_t strcount(const char *haystack, const char *needle);
/**
* STR_MAX_CHARS - Maximum possible size of numeric string for this type.
* @type_or_expr: a pointer or integer type or expression.
*
* This provides enough space for a nul-terminated string which represents the
* largest possible value for the type or expression.
*
* Note: The implementation adds extra space so hex values or negative
* values will fit (eg. sprintf(... "%p"). )
*
* Example:
* char str[STR_MAX_CHARS(int)];
*
* sprintf(str, "%i", 7);
*/
#define STR_MAX_CHARS(type_or_expr) \
((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \
+ STR_MAX_CHARS_TCHECK_(type_or_expr))
#if HAVE_TYPEOF
/* Only a simple type can have 0 assigned, so test that. */
#define STR_MAX_CHARS_TCHECK_(type_or_expr) \
({ typeof(type_or_expr) x = 0; (void)x; 0; })
#else
#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0
#endif
/**
* cisalnum - isalnum() which takes a char (and doesn't accept EOF)
* @c: a character
*
* Surprisingly, the standard ctype.h isalnum() takes an int, which
* must have the value of EOF (-1) or an unsigned char. This variant
* takes a real char, and doesn't accept EOF.
*/
static inline bool cisalnum(char c)
{
return isalnum((unsigned char)c);
}
static inline bool cisalpha(char c)
{
return isalpha((unsigned char)c);
}
static inline bool cisascii(char c)
{
return isascii((unsigned char)c);
}
#if HAVE_ISBLANK
static inline bool cisblank(char c)
{
return isblank((unsigned char)c);
}
#endif
static inline bool ciscntrl(char c)
{
return iscntrl((unsigned char)c);
}
static inline bool cisdigit(char c)
{
return isdigit((unsigned char)c);
}
static inline bool cisgraph(char c)
{
return isgraph((unsigned char)c);
}
static inline bool cislower(char c)
{
return islower((unsigned char)c);
}
static inline bool cisprint(char c)
{
return isprint((unsigned char)c);
}
static inline bool cispunct(char c)
{
return ispunct((unsigned char)c);
}
static inline bool cisspace(char c)
{
return isspace((unsigned char)c);
}
static inline bool cisupper(char c)
{
return isupper((unsigned char)c);
}
static inline bool cisxdigit(char c)
{
return isxdigit((unsigned char)c);
}
#include
/* These checks force things out of line, hence they are under DEBUG. */
#ifdef CCAN_STR_DEBUG
#include
/* These are commonly misused: they take -1 or an *unsigned* char value. */
#undef isalnum
#undef isalpha
#undef isascii
#undef isblank
#undef iscntrl
#undef isdigit
#undef isgraph
#undef islower
#undef isprint
#undef ispunct
#undef isspace
#undef isupper
#undef isxdigit
/* You can use a char if char is unsigned. */
#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
#define str_check_arg_(i) \
((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \
char) \
|| (char)255 > 0))
#else
#define str_check_arg_(i) (i)
#endif
#define isalnum(i) str_isalnum(str_check_arg_(i))
#define isalpha(i) str_isalpha(str_check_arg_(i))
#define isascii(i) str_isascii(str_check_arg_(i))
#if HAVE_ISBLANK
#define isblank(i) str_isblank(str_check_arg_(i))
#endif
#define iscntrl(i) str_iscntrl(str_check_arg_(i))
#define isdigit(i) str_isdigit(str_check_arg_(i))
#define isgraph(i) str_isgraph(str_check_arg_(i))
#define islower(i) str_islower(str_check_arg_(i))
#define isprint(i) str_isprint(str_check_arg_(i))
#define ispunct(i) str_ispunct(str_check_arg_(i))
#define isspace(i) str_isspace(str_check_arg_(i))
#define isupper(i) str_isupper(str_check_arg_(i))
#define isxdigit(i) str_isxdigit(str_check_arg_(i))
#if HAVE_TYPEOF
/* With GNU magic, we can make const-respecting standard string functions. */
#undef strstr
#undef strchr
#undef strrchr
/* + 0 is needed to decay array into pointer. */
#define strstr(haystack, needle) \
((typeof((haystack) + 0))str_strstr((haystack), (needle)))
#define strchr(haystack, c) \
((typeof((haystack) + 0))str_strchr((haystack), (c)))
#define strrchr(haystack, c) \
((typeof((haystack) + 0))str_strrchr((haystack), (c)))
#endif
#endif /* CCAN_STR_DEBUG */
#endif /* CCAN_STR_H */
ndctl-61.2/ccan/str/str_debug.h000066400000000000000000000014061331777607200164270ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_STR_DEBUG_H
#define CCAN_STR_DEBUG_H
/* #define CCAN_STR_DEBUG 1 */
#ifdef CCAN_STR_DEBUG
/* Because we mug the real ones with macros, we need our own wrappers. */
int str_isalnum(int i);
int str_isalpha(int i);
int str_isascii(int i);
#if HAVE_ISBLANK
int str_isblank(int i);
#endif
int str_iscntrl(int i);
int str_isdigit(int i);
int str_isgraph(int i);
int str_islower(int i);
int str_isprint(int i);
int str_ispunct(int i);
int str_isspace(int i);
int str_isupper(int i);
int str_isxdigit(int i);
char *str_strstr(const char *haystack, const char *needle);
char *str_strchr(const char *s, int c);
char *str_strrchr(const char *s, int c);
#endif /* CCAN_STR_DEBUG */
#endif /* CCAN_STR_DEBUG_H */
ndctl-61.2/configure.ac000066400000000000000000000131051331777607200150510ustar00rootroot00000000000000AC_PREREQ(2.60)
m4_include([version.m4])
AC_INIT([ndctl],
GIT_VERSION,
[linux-nvdimm@lists.01.org],
[ndctl],
[https://github.com/pmem/ndctl])
AC_CONFIG_SRCDIR([ndctl/lib/libndctl.c])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([
check-news
foreign
1.11
-Wall
-Wno-portability
silent-rules
tar-pax
no-dist-gzip
dist-xz
subdir-objects
])
AC_PROG_CC_STDC
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
AC_CONFIG_MACRO_DIR([m4])
AM_SILENT_RULES([yes])
LT_INIT([
disable-static
pic-only
])
AC_PREFIX_DEFAULT([/usr])
AC_PROG_SED
AC_PROG_MKDIR_P
AC_ARG_ENABLE([docs],
AS_HELP_STRING([--disable-docs],
[disable documentation build @<:@default=enabled@:>@]),
[], enable_docs=yes)
AS_IF([test "x$enable_docs" = "xyes"], [
AC_DEFINE(ENABLE_DOCS, [1], [Documentation / man pages.])
])
AM_CONDITIONAL([ENABLE_DOCS], [test "x$enable_docs" = "xyes"])
AC_ARG_ENABLE([asciidoctor],
AS_HELP_STRING([--enable-asciidoctor],
[use asciidoctor for documentation build]),
[], enable_asciidoctor=no)
AM_CONDITIONAL([USE_ASCIIDOCTOR], [test "x$enable_asciidoctor" = "xyes"])
if test "x$enable_asciidoctor" = "xyes"; then
asciidoc="asciidoctor"
else
asciidoc="asciidoc"
fi
AC_CHECK_PROG(ASCIIDOC, [$asciidoc], [$(which $asciidoc)], [missing])
if test "x$ASCIIDOC" = xmissing -a "x$enable_docs" = "xyes"; then
AC_MSG_ERROR([$asciidoc needed to build documentation])
fi
AC_SUBST([ASCIIDOC])
if test x"$asciidoc" = x"asciidoc"; then
AC_CHECK_PROG(XMLTO, [xmlto], [$(which xmlto)], [missing])
if test "x$XMLTO" = xmissing -a "x$enable_docs" = "xyes"; then
AC_MSG_ERROR([xmlto needed to build documentation])
fi
AC_SUBST([XMLTO])
fi
AC_C_TYPEOF
AC_DEFINE([HAVE_STATEMENT_EXPR], 1, [Define to 1 if you have statement expressions.])
AC_C_BIGENDIAN(
AC_DEFINE(HAVE_BIG_ENDIAN, 1, [Define to 1 if big-endian-arch]),
AC_DEFINE(HAVE_LITTLE_ENDIAN, 1, [Define to 1 if little-endian-arch]),
[], [])
AC_ARG_ENABLE([logging],
AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]),
[], enable_logging=yes)
AS_IF([test "x$enable_logging" = "xyes"], [
AC_DEFINE(ENABLE_LOGGING, [1], [System logging.])
])
AC_ARG_ENABLE([debug],
AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]),
[], [enable_debug=no])
AS_IF([test "x$enable_debug" = "xyes"], [
AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.])
])
AC_ARG_ENABLE([destructive],
AS_HELP_STRING([--enable-destructive], [enable destructive functional tests @<:@default=disabled@:>@]),
[], [enable_destructive=no])
AS_IF([test "x$enable_destructive" = "xyes"],
[AC_DEFINE([ENABLE_DESTRUCTIVE], [1], [destructive functional tests support])])
AM_CONDITIONAL([ENABLE_DESTRUCTIVE], [test "x$enable_destructive" = "xyes"])
AC_ARG_ENABLE([test],
AS_HELP_STRING([--enable-test], [enable ndctl test command @<:@default=disabled@:>@]),
[], [enable_test=$enable_destructive])
AS_IF([test "x$enable_test" = "xyes"],
[AC_DEFINE([ENABLE_TEST], [1], [ndctl test support])])
AM_CONDITIONAL([ENABLE_TEST], [test "x$enable_test" = "xyes"])
AC_CHECK_DECLS([BUS_MCEERR_AR], [enable_bus_mc_err=yes], [], [[#include ]])
AC_CHECK_DECLS([MAP_SYNC], [enable_map_sync=yes], [], [[#include ]])
AS_IF([test "x$enable_bus_mc_err" = "xyes" -a "x$enable_map_sync" = "xyes"],
[AC_DEFINE([ENABLE_POISON], [1], [ndctl test poison support])])
AM_CONDITIONAL([ENABLE_POISON],
[test "x$enable_bus_mc_err" = "xyes" -a "x$enable_map_sync" = "xyes"])
PKG_CHECK_MODULES([KMOD], [libkmod])
PKG_CHECK_MODULES([UDEV], [libudev])
PKG_CHECK_MODULES([UUID], [uuid])
PKG_CHECK_MODULES([JSON], [json-c])
AC_ARG_WITH([bash-completion-dir],
AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
[Install the bash auto-completion script in this directory. @<:@default=yes@:>@]),
[],
[with_bash_completion_dir=yes])
if test "x$with_bash_completion_dir" = "xyes"; then
PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0],
[BASH_COMPLETION_DIR="`pkg-config --variable=completionsdir bash-completion`"],
[BASH_COMPLETION_DIR="$datadir/bash-completion/completions"])
else
BASH_COMPLETION_DIR="$with_bash_completion_dir"
fi
AC_SUBST([BASH_COMPLETION_DIR])
AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"])
AC_ARG_ENABLE([local],
AS_HELP_STRING([--disable-local], [build against kernel ndctl.h @<:@default=system@:>@]),
[], [enable_local=yes])
AC_CHECK_HEADERS_ONCE([linux/version.h])
AC_CHECK_FUNCS([ \
__secure_getenv \
secure_getenv\
])
my_CFLAGS="\
-Wall \
-Wchar-subscripts \
-Wformat-security \
-Wmissing-declarations \
-Wmissing-prototypes \
-Wnested-externs \
-Wpointer-arith \
-Wshadow \
-Wsign-compare \
-Wstrict-prototypes \
-Wtype-limits \
-Wmaybe-uninitialized \
-Wdeclaration-after-statement \
-Wunused-result \
-D_FORTIFY_SOURCE=2 \
-O2
"
AC_SUBST([my_CFLAGS])
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_FILES([
Makefile
daxctl/lib/Makefile
ndctl/lib/Makefile
ndctl/Makefile
daxctl/Makefile
test/Makefile
Documentation/ndctl/Makefile
Documentation/daxctl/Makefile
])
AC_OUTPUT
AC_MSG_RESULT([
$PACKAGE $VERSION
=====
prefix: ${prefix}
sysconfdir: ${sysconfdir}
libdir: ${libdir}
includedir: ${includedir}
compiler: ${CC}
cflags: ${CFLAGS}
ldflags: ${LDFLAGS}
logging: ${enable_logging}
debug: ${enable_debug}
])
ndctl-61.2/contrib/000077500000000000000000000000001331777607200142235ustar00rootroot00000000000000ndctl-61.2/contrib/do_abidiff000077500000000000000000000040701331777607200162200ustar00rootroot00000000000000#!/bin/bash -e
range="$*"
old="${range%%..*}"
new="${range##*..}"
err()
{
echo "$1"
exit 1
}
build_rpm()
{
local cur=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
local ref="$1"
local version=""
# prepare ndctl tree
rm -rf results_ndctl
git checkout -b rel_${ref} $ref
./autogen.sh
./configure CFLAGS='-g -O2' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64
make clean
make rhel/ndctl.spec
cp rhel/ndctl.spec .
# build and copy RPMs
version="$(./git-version)"
git archive --format=tar --prefix="ndctl-${version}/" HEAD | gzip > ndctl-${version}.tar.gz
fedpkg --release master --module-name ndctl mockbuild
mkdir -p release/rel_${ref}/
cp results_ndctl/*/*/*.x86_64.rpm release/rel_${ref}/
# restore ndctl branch and cleanup
git checkout $cur
git branch -D rel_${ref}
rm ndctl-${version}.tar.gz
rm ndctl-${version}*.src.rpm
rm -rf results_ndctl
rm -f ndctl.spec
}
do_diff()
{
local pkg="$1"
local old_base="$(find . -regex "./release/rel_${old}/${pkg}-[0-9]+.*" | head -1)"
local new_base="$(find . -regex "./release/rel_${new}/${pkg}-[0-9]+.*" | head -1)"
local old_dev="$(find . -regex "./release/rel_${old}/${pkg}-devel-[0-9]+.*" | head -1)"
local new_dev="$(find . -regex "./release/rel_${new}/${pkg}-devel-[0-9]+.*" | head -1)"
local old_lib="$(find . -regex "./release/rel_${old}/${pkg}-libs-[0-9]+.*" | head -1)"
local new_lib="$(find . -regex "./release/rel_${new}/${pkg}-libs-[0-9]+.*" | head -1)"
[ -n "$pkg" ] || err "specify a package for diff (ndctl, daxctl)"
abipkgdiff --dso-only --no-added-syms --harmless --drop-private-types \
--devel1 "$old_dev" --devel2 "$new_dev" \
"$old_base" "$new_base"
abipkgdiff --no-added-syms --harmless --drop-private-types \
--devel1 "$old_dev" --devel2 "$new_dev" \
"$old_lib" "$new_lib"
}
[ -e "COPYING" ] || err "Run from the top level of an ndctl tree"
if ! command -v "abipkgdiff" >/dev/null; then
err "missing abipkgdiff. Please install libabigail"
fi
rm -rf release/rel*
build_rpm $old > release/buildlog_$old 2>&1
build_rpm $new > release/buildlog_$new 2>&1
do_diff ndctl
do_diff daxctl
ndctl-61.2/contrib/ndctl000077500000000000000000000230761331777607200152650ustar00rootroot00000000000000# ndctl bash and zsh completion
# Taken from perf's completion script.
__my_reassemble_comp_words_by_ref()
{
local exclude i j first
# Which word separators to exclude?
exclude="${1//[^$COMP_WORDBREAKS]}"
cword_=$COMP_CWORD
if [ -z "$exclude" ]; then
words_=("${COMP_WORDS[@]}")
return
fi
# List of word completion separators has shrunk;
# re-assemble words to complete.
for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
# Append each nonempty word consisting of just
# word separator characters to the current word.
first=t
while
[ $i -gt 0 ] &&
[ -n "${COMP_WORDS[$i]}" ] &&
# word consists of excluded word separators
[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
do
# Attach to the previous token,
# unless the previous token is the command name.
if [ $j -ge 2 ] && [ -n "$first" ]; then
((j--))
fi
first=
words_[$j]=${words_[j]}${COMP_WORDS[i]}
if [ $i = $COMP_CWORD ]; then
cword_=$j
fi
if (($i < ${#COMP_WORDS[@]} - 1)); then
((i++))
else
# Done.
return
fi
done
words_[$j]=${words_[j]}${COMP_WORDS[i]}
if [ $i = $COMP_CWORD ]; then
cword_=$j
fi
done
}
# Define preload_get_comp_words_by_ref="false", if the function
# __ndctl_get_comp_words_by_ref() is required instead.
preload_get_comp_words_by_ref="true"
if [ $preload_get_comp_words_by_ref = "true" ]; then
type _get_comp_words_by_ref &>/dev/null ||
preload_get_comp_words_by_ref="false"
fi
[ $preload_get_comp_words_by_ref = "true" ] ||
__ndctl_get_comp_words_by_ref()
{
local exclude cur_ words_ cword_
if [ "$1" = "-n" ]; then
exclude=$2
shift 2
fi
__my_reassemble_comp_words_by_ref "$exclude"
cur_=${words_[cword_]}
while [ $# -gt 0 ]; do
case "$1" in
cur)
cur=$cur_
;;
prev)
prev=${words_[$cword_-1]}
;;
words)
words=("${words_[@]}")
;;
cword)
cword=$cword_
;;
esac
shift
done
}
__ndctlcomp()
{
local i=0
COMPREPLY=( $( compgen -W "$1" -- "$2" ) )
for cword in "${COMPREPLY[@]}"; do
if [[ "$cword" == @(--bus|--region|--type|--mode|--size|--dimm|--reconfig|--uuid|--name|--sector-size|--map|--namespace|--input|--output|--label-version|--align|--block|--count|--firmware|--media-temperature|--ctrl-temperature|--spares|--media-temperature-threshold|--ctrl-temperature-threshold|--spares-threshold|--media-temperature-alarm|--ctrl-temperature-alarm|--spares-alarm|--numa-node) ]]; then
COMPREPLY[$i]="${cword}="
else
COMPREPLY[$i]="${cword} "
fi
((i++))
done
}
__ndctl_get_buses()
{
local opts="--buses $*"
[ -n "$dimm_filter" ] && opts="$opts --dimm=$dimm_filter"
[ -n "$reg_filter" ] && opts="$opts --region=$reg_filter"
[ -n "$ns_filter" ] && opts="$opts --namespace=$ns_filter"
echo "$(ndctl list $opts | grep -E "^\s*\"provider\":" | cut -d\" -f4)"
}
__ndctl_get_regions()
{
local opts="--regions $*"
[ -n "$bus_filter" ] && opts="$opts --bus=$bus_filter"
[ -n "$dimm_filter" ] && opts="$opts --dimm=$dimm_filter"
[ -n "$ns_filter" ] && opts="$opts --namespace=$ns_filter"
[ -n "$type_filter" ] && opts="$opts --type=$type_filter"
[ -n "$idle_filter" ] && opts="$opts --idle"
echo "$(ndctl list $opts | grep -E "^\s*\"dev\":" | cut -d\" -f4)"
}
__ndctl_get_ns()
{
opts="--namespaces $*"
[ -n "$bus_filter" ] && opts="$opts --bus=$bus_filter"
[ -n "$dimm_filter" ] && opts="$opts --dimm=$dimm_filter"
[ -n "$reg_filter" ] && opts="$opts --region=$reg_filter"
[ -n "$mode_filter" ] && opts="$opts --mode=$mode_filter"
[ -n "$type_filter" ] && opts="$opts --type=$type_filter"
[ -n "$idle_filter" ] && opts="$opts --idle"
echo "$(ndctl list $opts | grep -E "^\s*\"dev\":" | cut -d\" -f4)"
}
__ndctl_get_dimms()
{
opts="--dimms $*"
[ -n "$bus_filter" ] && opts="$opts --bus=$bus_filter"
[ -n "$reg_filter" ] && opts="$opts --region=$reg_filter"
[ -n "$ns_filter" ] && opts="$opts --namespace=$ns_filter"
echo "$(ndctl list $opts | grep -E "^\s*\"dev\":" | cut -d\" -f4)"
}
__ndctl_get_sector_sizes()
{
if [[ "$mode_filter" == @(raw|memory|fsdax) ]]; then
echo "512 4096"
elif [[ "$mode_filter" == @(dax|devdax) ]]; then
return
else
echo "512 520 528 4096 4104 4160 4224"
fi
}
__ndctl_get_nodes()
{
local nlist=""
for node in /sys/devices/system/node/node*; do
node="$(basename $node)"
if [[ $node =~ node([0-9]+) ]]; then
nlist="$nlist ${BASH_REMATCH[1]}"
else
continue
fi
done
echo "$nlist"
}
__ndctl_file_comp()
{
local cur="$1"
_filedir
}
__ndctl_comp_options()
{
local cur=$1
local opts
if [[ "$cur" == *=* ]]; then
local cur_subopt=${cur%%=*}
case $cur_subopt in
--bus)
opts=$(__ndctl_get_buses)
;;
--region)
opts=$(__ndctl_get_regions)
;;
--dimm)
opts=$(__ndctl_get_dimms -i)
;;
--namespace)
opts=$(__ndctl_get_ns)
;;
--reconfig)
# It is ok to reconfig disabled namespaces
opts=$(__ndctl_get_ns -i)
;;
--type)
opts="pmem blk"
if [[ "$mode_filter" == @(dax|memory|fsdax|devdax) ]]; then
opts="pmem"
fi
;;
--mode)
opts="raw sector fsdax devdax"
if [[ "$type_filter" == "blk" ]]; then
opts="raw sector"
fi
;;
--sector-size)
opts=$(__ndctl_get_sector_sizes)
;;
--map)
opts="mem dev"
;;
--output)
;&
--input)
;&
--firmware)
__ndctl_file_comp "${cur##*=}"
return
;;
--label-version)
opts="1.1 1.2"
;;
--media-temperature-alarm)
;&
--ctrl-temperature-alarm)
;&
--spares-alarm)
opts="on off"
;;
--numa-node)
opts=$(__ndctl_get_nodes)
;;
*)
return
;;
esac
__ndctlcomp "$opts" "${cur##*=}"
fi
}
__ndctl_comp_non_option_args()
{
local subcmd=$1
local cur=$2
local opts
case $subcmd in
enable-namespace)
opts="$(__ndctl_get_ns -i) all"
;;
disable-namespace)
;&
destroy-namespace)
opts="$(__ndctl_get_ns -i) all"
;;
check-namespace)
opts="$(__ndctl_get_ns -i) all"
;;
enable-region)
opts="$(__ndctl_get_regions -i) all"
;;
disable-region)
opts="$(__ndctl_get_regions) all"
;;
enable-dimm)
opts="$(__ndctl_get_dimms -i) all"
;;
disable-dimm)
opts="$(__ndctl_get_dimms) all"
;;
init-labels)
;&
check-labels)
;&
read-labels)
;&
write-labels)
;&
zero-labels)
opts="$(__ndctl_get_dimms -i) all"
;;
inject-error)
opts="$(__ndctl_get_ns -i)"
;;
inject-smart)
opts="$(__ndctl_get_dimms -i)"
;;
wait-scrub)
;&
start-scrub)
opts="$(__ndctl_get_buses) all"
;;
*)
return
;;
esac
__ndctlcomp "$opts" "$cur"
}
__ndctl_add_special_opts()
{
local subcmd=$1
case $subcmd in
create-namespace)
opts="$opts --no-autolabel"
;;
esac
}
__ndctl_prev_skip_opts ()
{
local i cmd_ cmds_
let i=cword-1
cmds_=$($cmd $1 --list-cmds)
prev_skip_opts=()
while [ $i -ge 0 ]; do
if [[ ${words[i]} == $1 ]]; then
return
fi
for cmd_ in $cmds_; do
if [[ ${words[i]} == $cmd_ ]]; then
prev_skip_opts=${words[i]}
return
fi
done
((i--))
done
}
__ndctl_init_filters()
{
bus_filter=''
reg_filter=''
ns_filter=''
dimm_filter=''
type_filter=''
idle_filter=''
mode_filter=''
for __word in "${words[@]}"; do
if [[ "$__word" =~ --bus=(.*) ]]; then
bus_filter="${BASH_REMATCH[1]}"
# lets make sure this is in the list of buses
local buses=$(__ndctl_get_buses)
[[ "$buses" == *"$bus_filter"* ]] || bus_filter=''
fi
if [[ "$__word" =~ --region=(.*) ]]; then
reg_filter="${BASH_REMATCH[1]}"
# lets make sure this is in the list of regions
local regions=$(__ndctl_get_regions -i)
[[ "$regions" == *"$reg_filter"* ]] || reg_filter=''
fi
if [[ "$__word" =~ --namespace=(.*) ]]; then
ns_filter="${BASH_REMATCH[1]}"
# lets make sure this is in the list of namespaces
local nss=$(__ndctl_get_ns -i)
[[ "$nss" == *"$ns_filter"* ]] || ns_filter=''
fi
if [[ "$__word" =~ --dimm=(.*) ]]; then
dimm_filter="${BASH_REMATCH[1]}"
# lets make sure this is in the list of dimms
local dimms=$(__ndctl_get_dimms)
[[ "$dimms" == *"$dimm_filter"* ]] || dimm_filter=''
fi
if [[ "$__word" =~ --idle ]]; then
idle_filter="1"
fi
if [[ "$__word" =~ --type=(.*) ]]; then
type_filter="${BASH_REMATCH[1]}"
fi
if [[ "$__word" =~ --mode=(.*) ]]; then
mode_filter="${BASH_REMATCH[1]}"
fi
done
}
__ndctl_main()
{
local cmd subcmd
cmd=${words[0]}
COMPREPLY=()
__ndctl_init_filters
# Skip options backward and find the last ndctl command
__ndctl_prev_skip_opts
subcmd=$prev_skip_opts
# List ndctl subcommands or long options
if [ -z $subcmd ]; then
if [[ $cur == --* ]]; then
cmds="--version --help --list-cmds"
else
cmds=$($cmd --list-cmds)
fi
__ndctlcomp "$cmds" "$cur"
else
# List long option names
if [[ $cur == --* ]]; then
opts=$($cmd $subcmd --list-opts)
__ndctl_add_special_opts "$subcmd"
__ndctlcomp "$opts" "$cur"
__ndctl_comp_options "$cur"
else
[ -z "$subcmd" ] && return
__ndctl_comp_non_option_args "$subcmd" "$cur"
fi
fi
}
if [[ -n ${ZSH_VERSION-} ]]; then
autoload -U +X compinit && compinit
__ndctlcomp()
{
emulate -L zsh
local c IFS=$' \t\n'
local -a array
for c in ${=1}; do
case $c in
--*=*|*.) ;;
*) c="$c " ;;
esac
array[${#array[@]}+1]="$c"
done
compset -P '*[=:]'
compadd -Q -S '' -a -- array && _ret=0
}
_ndctl()
{
local _ret=1 cur cword prev
cur=${words[CURRENT]}
prev=${words[CURRENT-1]}
let cword=CURRENT-1
emulate ksh -c __ndctl_main
let _ret && _default && _ret=0
return _ret
}
compdef _ndctl ndctl
return
fi
type ndctl &>/dev/null &&
_ndctl()
{
local cur words cword prev
if [ $preload_get_comp_words_by_ref = "true" ]; then
_get_comp_words_by_ref -n =: cur words cword prev
else
__ndctl_get_comp_words_by_ref -n =: cur words cword prev
fi
__ndctl_main
} &&
complete -o nospace -F _ndctl ndctl 2>/dev/null
ndctl-61.2/contrib/prepare-release.sh000077500000000000000000000131501331777607200176360ustar00rootroot00000000000000#!/bin/bash -e
# Arguments:
# fix - fixup release instead of a full release
# ignore_rev - ignore the check for _REVISION in libtool versioning checks
# Notes:
# - Checkout to the appropriate branch beforehand
# master - for major release
# ndctl-xx.y - for fixup release
# This is important for generating the shortlog
# - Add a temporary commit that updates the libtool versions as needed.
# This will later become the release commit. Use --amend to add in the
# git-version update and the message body.
# Pre-reqs:
# - libabigail (for abipkgdiff)
# - fedpkg (for mock build)
# TODO
# - auto generate a release commit/tag message template
# - determine the most recent kernel release and add it to the above
# - perform documentation update for pmem.io/ndctl
cleanup()
{
rm -rf release
mkdir release/
}
err()
{
echo "$1"
exit 1
}
parse_args()
{
local args="$*"
grep -q "fix" <<< "$args" && rel_fix="1" || rel_fix=""
grep -q "ignore_rev" <<< "$args" && ignore_rev="1" || ignore_rev=""
}
check_branch()
{
local cur=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if [ -n "$rel_fix" ]; then
# fixup release, expect ndctl-xx.y branch
if ! grep -Eq "^ndctl.[0-9]+\.y$" <<< "$cur"; then
err "expected an ndctl-xx.y branch for fixup release"
fi
else
# major release, expect master branch
if ! grep -Eq "^master$" <<< "$cur"; then
err "expected master branch for a major release"
fi
fi
if ! git diff-index --quiet HEAD --; then
err "$cur has uncommitted/unstaged changes"
fi
}
last_maj()
{
git tag | sort -V | grep -E "v[0-9]+$" | tail -1
}
last_fix()
{
local base="$1"
git tag | sort -V | grep -E "$base\.?[0-9]*$" | tail -1
}
next_maj()
{
local last="$1"
local num=${last#v}
newnum="$((num + 1))"
echo "v$newnum"
}
next_fix()
{
local last="$1"
local num=${last##*.}
local base=${last%%.*}
newnum=$((num + 1))
echo "$base.$newnum"
}
gen_lists()
{
local range="$1"
git shortlog "$range" > release/shortlog
git log --pretty=format:"%s" "$range" > release/commits
c_count=$(git log --pretty=format:"%s" "$range" | wc -l)
}
# Check libtool versions in Makefile.am.in
# $1: lib name (currently libndctl or libdaxctl)
check_libtool_vers()
{
local lib="$1"
local lib_u="${lib^^}"
local libdir="${lib##lib}"
local symfile="${libdir}/lib/${lib}.sym"
local last_cur=$(git show $last_ref:Makefile.am.in | grep -E "^${lib_u}_CURRENT" | cut -d'=' -f2)
local last_rev=$(git show $last_ref:Makefile.am.in | grep -E "^${lib_u}_REVISION" | cut -d'=' -f2)
local last_age=$(git show $last_ref:Makefile.am.in | grep -E "^${lib_u}_AGE" | cut -d'=' -f2)
local last_soname=$((last_cur - last_age))
local next_cur=$(git show HEAD:Makefile.am.in | grep -E "^${lib_u}_CURRENT" | cut -d'=' -f2)
local next_rev=$(git show HEAD:Makefile.am.in | grep -E "^${lib_u}_REVISION" | cut -d'=' -f2)
local next_age=$(git show HEAD:Makefile.am.in | grep -E "^${lib_u}_AGE" | cut -d'=' -f2)
local next_soname=$((next_cur - next_age))
local soname_diff=$((next_soname - last_soname))
# generally libtool versions either reset to zero or increase only by one
# _CURRENT monotonically increases (by one)
if [ "$((next_cur - last_cur))" -gt 1 ]; then
err "${lib_u}_CURRENT can increase at most by 1"
fi
if [ "$next_rev" -ne 0 ]; then
if [ "$((next_rev - last_rev))" -gt 1 ]; then
err "${lib_u}_REVISION can increase at most by 1"
fi
fi
if [ "$next_age" -ne 0 ]; then
if [ "$((next_age - last_age))" -gt 1 ]; then
err "${lib_u}_AGE can increase at most by 1"
fi
fi
# test for soname change
if [ "$soname_diff" -ne 0 ]; then
err "${lib}: expected soname to stay unchanged"
fi
# tests based on whether symfile changed
# compatibility breaking changes are left for libabigail to detect
test -s "$symfile" || err "$symfile: not found"
if [ -n "$(git diff --name-only $last_ref..HEAD $symfile)" ]; then
# symfile has changed, cur and age should increase
if [ "$((next_cur - last_cur))" -ne 1 ]; then
err "based on $symfile, ${lib_u}_CURRENT should've increased by 1"
fi
if [ "$((next_age - last_age))" -ne 1 ]; then
err "based on $symfile, ${lib_u}_AGE should've increased by 1"
fi
else
# no changes to symfile, revision should've increased if source changed
if [ -n "$ignore_rev" ]; then
: # skip
elif [ -n "$(git diff --name-only $last_ref..HEAD $libdir/)" ]; then
if [ "$((next_rev - last_rev))" -ne 1 ]; then
err "based on $symfile, ${lib_u}_REVISION should've increased by 1"
fi
fi
fi
}
# main
cleanup
parse_args "$*"
check_branch
[ -e "COPYING" ] || err "Run from the top level of an ndctl tree"
last_maj=$(last_maj)
test -n "$last_maj" || err "Unable to determine last release"
last_fix=$(last_fix $last_maj)
test -n "$last_fix" || err "Unable to determine last fixup tag for $last_maj"
next_maj=$(next_maj "$last_maj")
next_fix=$(next_fix "$last_fix")
[ -n "$rel_fix" ] && last_ref="$last_fix" || last_ref="$last_maj"
[ -n "$rel_fix" ] && next_ref="$next_fix" || next_ref="$next_maj"
check_libtool_vers "libndctl"
check_libtool_vers "libdaxctl"
gen_lists ${last_ref}..HEAD
# For ABI diff purposes, use the latest fixes tag
contrib/do_abidiff ${last_fix}..HEAD
# once everything passes, update the git-version
sed -i -e "s/DEF_VER=[0-9]\+.*/DEF_VER=${next_ref#v}/" git-version
echo "Ready to release ndctl-$next_ref with $c_count new commits."
echo "Add git-version to the top commit to get the updated version."
echo "Use release/commits and release/shortlog to compose the release message"
echo "The release commit typically contains the Makefile.am.in libtool version"
echo "update, and the git-version update."
echo "Finally, ensure the release commit as well as the tag are PGP signed."
ndctl-61.2/daxctl/000077500000000000000000000000001331777607200140425ustar00rootroot00000000000000ndctl-61.2/daxctl/Makefile.am000066400000000000000000000003131331777607200160730ustar00rootroot00000000000000include $(top_srcdir)/Makefile.am.in
bin_PROGRAMS = daxctl
daxctl_SOURCES =\
daxctl.c \
list.c \
../util/json.c
daxctl_LDADD =\
lib/libdaxctl.la \
../libutil.a \
$(UUID_LIBS) \
$(JSON_LIBS)
ndctl-61.2/daxctl/daxctl.c000066400000000000000000000053101331777607200154640ustar00rootroot00000000000000/*
* Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
* Copyright(c) 2005 Andreas Ericsson. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
/* originally copied from perf and git */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const char daxctl_usage_string[] = "daxctl [--version] [--help] COMMAND [ARGS]";
const char daxctl_more_info_string[] =
"See 'daxctl help COMMAND' for more information on a specific command.\n"
" daxctl --list-cmds to see all available commands";
static int cmd_version(int argc, const char **argv, void *ctx)
{
printf("%s\n", VERSION);
return 0;
}
static int cmd_help(int argc, const char **argv, void *ctx)
{
const char * const builtin_help_subcommands[] = {
"list", NULL,
};
struct option builtin_help_options[] = {
OPT_END(),
};
const char *builtin_help_usage[] = {
"daxctl help [command]",
NULL
};
argc = parse_options_subcommand(argc, argv, builtin_help_options,
builtin_help_subcommands, builtin_help_usage, 0);
if (!argv[0]) {
printf("\n usage: %s\n\n", daxctl_usage_string);
printf("\n %s\n\n", daxctl_more_info_string);
return 0;
}
return help_show_man_page(argv[0], "daxctl", "DAXCTL_MAN_VIEWER");
}
int cmd_list(int argc, const char **argv, void *ctx);
static struct cmd_struct commands[] = {
{ "version", cmd_version },
{ "list", cmd_list },
{ "help", cmd_help },
};
int main(int argc, const char **argv)
{
struct daxctl_ctx *ctx;
int rc;
/* Look for flags.. */
argv++;
argc--;
main_handle_options(&argv, &argc, daxctl_usage_string, commands,
ARRAY_SIZE(commands));
if (argc > 0) {
if (!prefixcmp(argv[0], "--"))
argv[0] += 2;
} else {
/* The user didn't specify a command; give them help */
printf("\n usage: %s\n\n", daxctl_usage_string);
printf("\n %s\n\n", daxctl_more_info_string);
goto out;
}
rc = daxctl_new(&ctx);
if (rc)
goto out;
main_handle_internal_command(argc, argv, ctx, commands,
ARRAY_SIZE(commands));
daxctl_unref(ctx);
fprintf(stderr, "Unknown command: '%s'\n", argv[0]);
out:
return 1;
}
ndctl-61.2/daxctl/lib/000077500000000000000000000000001331777607200146105ustar00rootroot00000000000000ndctl-61.2/daxctl/lib/Makefile.am000066400000000000000000000013161331777607200166450ustar00rootroot00000000000000include $(top_srcdir)/Makefile.am.in
%.pc: %.pc.in Makefile
$(SED_PROCESS)
pkginclude_HEADERS = ../libdaxctl.h
lib_LTLIBRARIES = libdaxctl.la
libdaxctl_la_SOURCES =\
../libdaxctl.h \
libdaxctl-private.h \
../../util/sysfs.c \
../../util/sysfs.h \
../../util/log.c \
../../util/log.h \
libdaxctl.c
libdaxctl_la_LIBADD =\
$(UUID_LIBS)
EXTRA_DIST += libdaxctl.sym
libdaxctl_la_LDFLAGS = $(AM_LDFLAGS) \
-version-info $(LIBDAXCTL_CURRENT):$(LIBDAXCTL_REVISION):$(LIBDAXCTL_AGE) \
-Wl,--version-script=$(top_srcdir)/daxctl/lib/libdaxctl.sym
libdaxctl_la_DEPENDENCIES = libdaxctl.sym
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libdaxctl.pc
EXTRA_DIST += libdaxctl.pc.in
CLEANFILES += libdaxctl.pc
ndctl-61.2/daxctl/lib/libdaxctl-private.h000066400000000000000000000023101331777607200203730ustar00rootroot00000000000000/*
* Copyright (c) 2014-2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*/
#ifndef _LIBDAXCTL_PRIVATE_H_
#define _LIBDAXCTL_PRIVATE_H_
#define DAXCTL_EXPORT __attribute__ ((visibility("default")))
/**
* struct daxctl_region - container for dax_devices
*/
#define REGION_BUF_SIZE 50
struct daxctl_region {
int id;
uuid_t uuid;
int refcount;
char *devname;
size_t buf_len;
void *region_buf;
int devices_init;
char *region_path;
unsigned long align;
unsigned long long size;
struct daxctl_ctx *ctx;
struct list_node list;
struct list_head devices;
};
struct daxctl_dev {
int id, major, minor;
void *dev_buf;
size_t buf_len;
char *dev_path;
struct list_node list;
unsigned long long size;
struct daxctl_region *region;
};
#endif /* _LIBDAXCTL_PRIVATE_H_ */
ndctl-61.2/daxctl/lib/libdaxctl.c000066400000000000000000000330331331777607200167240ustar00rootroot00000000000000/*
* Copyright (c) 2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "libdaxctl-private.h"
static const char *attrs = "dax_region";
static void free_region(struct daxctl_region *region, struct list_head *head);
/**
* struct daxctl_ctx - library user context to find "nd" instances
*
* Instantiate with daxctl_new(), which takes an initial reference. Free
* the context by dropping the reference count to zero with
* daxctl_unref(), or take additional references with daxctl_ref()
* @timeout: default library timeout in milliseconds
*/
struct daxctl_ctx {
/* log_ctx must be first member for daxctl_set_log_fn compat */
struct log_ctx ctx;
int refcount;
void *userdata;
int regions_init;
struct list_head regions;
};
/**
* daxctl_get_userdata - retrieve stored data pointer from library context
* @ctx: daxctl library context
*
* This might be useful to access from callbacks like a custom logging
* function.
*/
DAXCTL_EXPORT void *daxctl_get_userdata(struct daxctl_ctx *ctx)
{
if (ctx == NULL)
return NULL;
return ctx->userdata;
}
/**
* daxctl_set_userdata - store custom @userdata in the library context
* @ctx: daxctl library context
* @userdata: data pointer
*/
DAXCTL_EXPORT void daxctl_set_userdata(struct daxctl_ctx *ctx, void *userdata)
{
if (ctx == NULL)
return;
ctx->userdata = userdata;
}
/**
* daxctl_new - instantiate a new library context
* @ctx: context to establish
*
* Returns zero on success and stores an opaque pointer in ctx. The
* context is freed by daxctl_unref(), i.e. daxctl_new() implies an
* internal daxctl_ref().
*/
DAXCTL_EXPORT int daxctl_new(struct daxctl_ctx **ctx)
{
struct daxctl_ctx *c;
c = calloc(1, sizeof(struct daxctl_ctx));
if (!c)
return -ENOMEM;
c->refcount = 1;
log_init(&c->ctx, "libdaxctl", "DAXCTL_LOG");
info(c, "ctx %p created\n", c);
dbg(c, "log_priority=%d\n", c->ctx.log_priority);
*ctx = c;
list_head_init(&c->regions);
return 0;
}
/**
* daxctl_ref - take an additional reference on the context
* @ctx: context established by daxctl_new()
*/
DAXCTL_EXPORT struct daxctl_ctx *daxctl_ref(struct daxctl_ctx *ctx)
{
if (ctx == NULL)
return NULL;
ctx->refcount++;
return ctx;
}
/**
* daxctl_unref - drop a context reference count
* @ctx: context established by daxctl_new()
*
* Drop a reference and if the resulting reference count is 0 destroy
* the context.
*/
DAXCTL_EXPORT void daxctl_unref(struct daxctl_ctx *ctx)
{
struct daxctl_region *region, *_r;
if (ctx == NULL)
return;
ctx->refcount--;
if (ctx->refcount > 0)
return;
list_for_each_safe(&ctx->regions, region, _r, list)
free_region(region, &ctx->regions);
info(ctx, "context %p released\n", ctx);
free(ctx);
}
/**
* daxctl_set_log_fn - override default log routine
* @ctx: daxctl library context
* @log_fn: function to be called for logging messages
*
* The built-in logging writes to stderr. It can be overridden by a
* custom function, to plug log messages into the user's logging
* functionality.
*/
DAXCTL_EXPORT void daxctl_set_log_fn(struct daxctl_ctx *ctx,
void (*daxctl_log_fn)(struct daxctl_ctx *ctx, int priority,
const char *file, int line, const char *fn,
const char *format, va_list args))
{
ctx->ctx.log_fn = (log_fn) daxctl_log_fn;
info(ctx, "custom logging function %p registered\n", daxctl_log_fn);
}
/**
* daxctl_get_log_priority - retrieve current library loglevel (syslog)
* @ctx: daxctl library context
*/
DAXCTL_EXPORT int daxctl_get_log_priority(struct daxctl_ctx *ctx)
{
return ctx->ctx.log_priority;
}
/**
* daxctl_set_log_priority - set log verbosity
* @priority: from syslog.h, LOG_ERR, LOG_INFO, LOG_DEBUG
*
* Note: LOG_DEBUG requires library be built with "configure --enable-debug"
*/
DAXCTL_EXPORT void daxctl_set_log_priority(struct daxctl_ctx *ctx, int priority)
{
ctx->ctx.log_priority = priority;
}
DAXCTL_EXPORT struct daxctl_ctx *daxctl_region_get_ctx(
struct daxctl_region *region)
{
return region->ctx;
}
DAXCTL_EXPORT void daxctl_region_get_uuid(struct daxctl_region *region, uuid_t uu)
{
uuid_copy(uu, region->uuid);
}
static void free_dev(struct daxctl_dev *dev, struct list_head *head)
{
if (head)
list_del_from(head, &dev->list);
free(dev->dev_buf);
free(dev->dev_path);
free(dev);
}
static void free_region(struct daxctl_region *region, struct list_head *head)
{
struct daxctl_dev *dev, *_d;
list_for_each_safe(®ion->devices, dev, _d, list)
free_dev(dev, ®ion->devices);
if (head)
list_del_from(head, ®ion->list);
free(region->region_path);
free(region->region_buf);
free(region->devname);
free(region);
}
DAXCTL_EXPORT void daxctl_region_unref(struct daxctl_region *region)
{
struct daxctl_ctx *ctx;
if (!region)
return;
region->refcount--;
if (region->refcount)
return;
ctx = region->ctx;
dbg(ctx, "%s: %s\n", __func__, daxctl_region_get_devname(region));
free_region(region, &ctx->regions);
}
DAXCTL_EXPORT void daxctl_region_ref(struct daxctl_region *region)
{
if (region)
region->refcount++;
}
static struct daxctl_region *add_dax_region(void *parent, int id,
const char *base)
{
struct daxctl_region *region, *region_dup;
struct daxctl_ctx *ctx = parent;
char buf[SYSFS_ATTR_SIZE];
char *path;
dbg(ctx, "%s: \'%s\'\n", __func__, base);
daxctl_region_foreach(ctx, region_dup)
if (strcmp(region_dup->region_path, base) == 0)
return region_dup;
path = calloc(1, strlen(base) + 100);
if (!path)
return NULL;
region = calloc(1, sizeof(*region));
if (!region)
goto err_region;
region->id = id;
region->align = -1;
region->size = -1;
region->ctx = ctx;
region->refcount = 1;
list_head_init(®ion->devices);
region->devname = strdup(devpath_to_devname(base));
sprintf(path, "%s/%s/size", base, attrs);
if (sysfs_read_attr(ctx, path, buf) == 0)
region->size = strtoull(buf, NULL, 0);
sprintf(path, "%s/%s/align", base, attrs);
if (sysfs_read_attr(ctx, path, buf) == 0)
region->align = strtoul(buf, NULL, 0);
region->region_path = strdup(base);
if (!region->region_path)
goto err_read;
region->region_buf = calloc(1, strlen(path) + strlen(attrs)
+ REGION_BUF_SIZE);
if (!region->region_buf)
goto err_read;
region->buf_len = strlen(path) + REGION_BUF_SIZE;
list_add(&ctx->regions, ®ion->list);
free(path);
return region;
err_read:
free(region->region_buf);
free(region->region_path);
free(region);
err_region:
free(path);
return NULL;
}
DAXCTL_EXPORT struct daxctl_region *daxctl_new_region(struct daxctl_ctx *ctx,
int id, uuid_t uuid, const char *path)
{
struct daxctl_region *region;
region = add_dax_region(ctx, id, path);
if (!region)
return NULL;
uuid_copy(region->uuid, uuid);
dbg(ctx, "%s: %s\n", __func__, daxctl_region_get_devname(region));
return region;
}
static void *add_dax_dev(void *parent, int id, const char *daxdev_base)
{
const char *devname = devpath_to_devname(daxdev_base);
char *path = calloc(1, strlen(daxdev_base) + 100);
struct daxctl_region *region = parent;
struct daxctl_ctx *ctx = region->ctx;
struct daxctl_dev *dev, *dev_dup;
char buf[SYSFS_ATTR_SIZE];
struct stat st;
if (!path)
return NULL;
dbg(ctx, "%s: base: \'%s\'\n", __func__, daxdev_base);
dev = calloc(1, sizeof(*dev));
if (!dev)
goto err_dev;
dev->id = id;
dev->region = region;
sprintf(path, "/dev/%s", devname);
if (stat(path, &st) < 0)
goto err_read;
dev->major = major(st.st_rdev);
dev->minor = minor(st.st_rdev);
sprintf(path, "%s/size", daxdev_base);
if (sysfs_read_attr(ctx, path, buf) < 0)
goto err_read;
dev->size = strtoull(buf, NULL, 0);
dev->dev_path = strdup(daxdev_base);
if (!dev->dev_path)
goto err_read;
dev->dev_buf = calloc(1, strlen(daxdev_base) + 50);
if (!dev->dev_buf)
goto err_read;
dev->buf_len = strlen(daxdev_base) + 50;
daxctl_dev_foreach(region, dev_dup)
if (dev_dup->id == dev->id) {
free_dev(dev, NULL);
free(path);
return dev_dup;
}
list_add(®ion->devices, &dev->list);
free(path);
return dev;
err_read:
free(dev->dev_buf);
free(dev->dev_path);
free(dev);
err_dev:
free(path);
return NULL;
}
DAXCTL_EXPORT int daxctl_region_get_id(struct daxctl_region *region)
{
return region->id;
}
DAXCTL_EXPORT unsigned long daxctl_region_get_align(struct daxctl_region *region)
{
return region->align;
}
DAXCTL_EXPORT unsigned long long daxctl_region_get_size(struct daxctl_region *region)
{
return region->size;
}
DAXCTL_EXPORT const char *daxctl_region_get_devname(struct daxctl_region *region)
{
return region->devname;
}
DAXCTL_EXPORT const char *daxctl_region_get_path(struct daxctl_region *region)
{
return region->region_path;
}
DAXCTL_EXPORT unsigned long long daxctl_region_get_available_size(
struct daxctl_region *region)
{
struct daxctl_ctx *ctx = daxctl_region_get_ctx(region);
char *path = region->region_buf;
char buf[SYSFS_ATTR_SIZE], *end;
int len = region->buf_len;
unsigned long long avail;
if (snprintf(path, len, "%s/%s/available_size",
region->region_path, attrs) >= len) {
err(ctx, "%s: buffer too small!\n",
daxctl_region_get_devname(region));
return 0;
}
if (sysfs_read_attr(ctx, path, buf) < 0)
return 0;
avail = strtoull(buf, &end, 0);
if (buf[0] && *end == '\0')
return avail;
return 0;
}
DAXCTL_EXPORT struct daxctl_dev *daxctl_region_get_dev_seed(
struct daxctl_region *region)
{
struct daxctl_ctx *ctx = daxctl_region_get_ctx(region);
char *path = region->region_buf;
int len = region->buf_len;
char buf[SYSFS_ATTR_SIZE];
struct daxctl_dev *dev;
if (snprintf(path, len, "%s/%s/seed", region->region_path, attrs) >= len) {
err(ctx, "%s: buffer too small!\n",
daxctl_region_get_devname(region));
return NULL;
}
if (sysfs_read_attr(ctx, path, buf) < 0)
return NULL;
daxctl_dev_foreach(region, dev)
if (strcmp(buf, daxctl_dev_get_devname(dev)) == 0)
return dev;
return NULL;
}
static void dax_devices_init(struct daxctl_region *region)
{
struct daxctl_ctx *ctx = daxctl_region_get_ctx(region);
char daxdev_fmt[50];
char *region_path;
if (region->devices_init)
return;
region->devices_init = 1;
sprintf(daxdev_fmt, "dax%d.", region->id);
if (asprintf(®ion_path, "%s/dax", region->region_path) < 0) {
dbg(ctx, "region path alloc fail\n");
return;
}
sysfs_device_parse(ctx, region_path, daxdev_fmt, region, add_dax_dev);
free(region_path);
}
static char *dax_region_path(const char *base, const char *device)
{
char *path, *region_path, *c;
if (asprintf(&path, "%s/%s", base, device) < 0)
return NULL;
/* dax_region must be the instance's direct parent */
region_path = realpath(path, NULL);
free(path);
if (!region_path)
return NULL;
/* 'region_path' is now regionX/dax/daxX.Y', trim back to regionX */
c = strrchr(region_path, '/');
if (!c) {
free(region_path);
return NULL;
}
*c = '\0';
c = strrchr(region_path, '/');
if (!c) {
free(region_path);
return NULL;
}
*c = '\0';
return region_path;
}
static void dax_regions_init(struct daxctl_ctx *ctx)
{
const char *base = "/sys/class/dax";
struct dirent *de;
DIR *dir;
if (ctx->regions_init)
return;
ctx->regions_init = 1;
dir = opendir(base);
if (!dir) {
dbg(ctx, "no dax regions found\n");
return;
}
while ((de = readdir(dir)) != NULL) {
struct daxctl_region *region;
int id, region_id;
char *dev_path;
if (de->d_ino == 0)
continue;
if (sscanf(de->d_name, "dax%d.%d", ®ion_id, &id) != 2)
continue;
dev_path = dax_region_path(base, de->d_name);
if (!dev_path) {
err(ctx, "dax region path allocation failure\n");
continue;
}
region = add_dax_region(ctx, region_id, dev_path);
free(dev_path);
if (!region)
err(ctx, "add_dax_region() for %s failed\n", de->d_name);
}
closedir(dir);
}
DAXCTL_EXPORT struct daxctl_dev *daxctl_dev_get_first(struct daxctl_region *region)
{
dax_devices_init(region);
return list_top(®ion->devices, struct daxctl_dev, list);
}
DAXCTL_EXPORT struct daxctl_dev *daxctl_dev_get_next(struct daxctl_dev *dev)
{
struct daxctl_region *region = dev->region;
return list_next(®ion->devices, dev, list);
}
DAXCTL_EXPORT struct daxctl_region *daxctl_region_get_first(
struct daxctl_ctx *ctx)
{
dax_regions_init(ctx);
return list_top(&ctx->regions, struct daxctl_region, list);
}
DAXCTL_EXPORT struct daxctl_region *daxctl_region_get_next(
struct daxctl_region *region)
{
struct daxctl_ctx *ctx = region->ctx;
return list_next(&ctx->regions, region, list);
}
DAXCTL_EXPORT struct daxctl_region *daxctl_dev_get_region(struct daxctl_dev *dev)
{
return dev->region;
}
DAXCTL_EXPORT int daxctl_dev_get_id(struct daxctl_dev *dev)
{
return dev->id;
}
DAXCTL_EXPORT const char *daxctl_dev_get_devname(struct daxctl_dev *dev)
{
return devpath_to_devname(dev->dev_path);
}
DAXCTL_EXPORT int daxctl_dev_get_major(struct daxctl_dev *dev)
{
return dev->major;
}
DAXCTL_EXPORT int daxctl_dev_get_minor(struct daxctl_dev *dev)
{
return dev->minor;
}
DAXCTL_EXPORT unsigned long long daxctl_dev_get_size(struct daxctl_dev *dev)
{
return dev->size;
}
ndctl-61.2/daxctl/lib/libdaxctl.pc.in000066400000000000000000000003401331777607200175040ustar00rootroot00000000000000prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libdaxctl
Description: Manage "Device DAX" devices
Version: @VERSION@
Libs: -L${libdir} -ldaxctl
Libs.private:
Cflags: -I${includedir}
ndctl-61.2/daxctl/lib/libdaxctl.sym000066400000000000000000000016151331777607200173130ustar00rootroot00000000000000LIBDAXCTL_1 {
global:
daxctl_get_userdata;
daxctl_set_userdata;
daxctl_ref;
daxctl_get_log_priority;
daxctl_set_log_fn;
daxctl_unref;
daxctl_set_log_priority;
daxctl_new;
local:
*;
};
LIBDAXCTL_2 {
global:
daxctl_region_unref;
daxctl_new_region;
daxctl_region_ref;
daxctl_region_unref;
daxctl_region_get_uuid;
daxctl_region_get_id;
daxctl_region_get_ctx;
daxctl_dev_get_first;
daxctl_dev_get_next;
daxctl_dev_get_region;
daxctl_dev_get_id;
daxctl_dev_get_devname;
daxctl_dev_get_major;
daxctl_dev_get_minor;
daxctl_dev_get_size;
} LIBDAXCTL_1;
LIBDAXCTL_3 {
global:
daxctl_region_get_available_size;
daxctl_region_get_devname;
daxctl_region_get_dev_seed;
} LIBDAXCTL_2;
LIBDAXCTL_4 {
global:
daxctl_region_get_size;
daxctl_region_get_align;
daxctl_region_get_first;
daxctl_region_get_next;
} LIBDAXCTL_3;
LIBDAXCTL_5 {
global:
daxctl_region_get_path;
} LIBDAXCTL_4;
ndctl-61.2/daxctl/libdaxctl.h000066400000000000000000000062541331777607200161700ustar00rootroot00000000000000/*
* Copyright (c) 2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*/
#ifndef _LIBDAXCTL_H_
#define _LIBDAXCTL_H_
#include
#include
#ifdef HAVE_LIBUUID
#include
#else
typedef unsigned char uuid_t[16];
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct daxctl_ctx;
struct daxctl_ctx *daxctl_ref(struct daxctl_ctx *ctx);
void daxctl_unref(struct daxctl_ctx *ctx);
int daxctl_new(struct daxctl_ctx **ctx);
void daxctl_set_log_fn(struct daxctl_ctx *ctx,
void (*log_fn)(struct daxctl_ctx *ctx, int priority,
const char *file, int line, const char *fn,
const char *format, va_list args));
int daxctl_get_log_priority(struct daxctl_ctx *ctx);
void daxctl_set_log_priority(struct daxctl_ctx *ctx, int priority);
void daxctl_set_userdata(struct daxctl_ctx *ctx, void *userdata);
void *daxctl_get_userdata(struct daxctl_ctx *ctx);
struct daxctl_region;
struct daxctl_region *daxctl_new_region(struct daxctl_ctx *ctx, int id,
uuid_t uuid, const char *path);
struct daxctl_region *daxctl_region_get_first(struct daxctl_ctx *ctx);
struct daxctl_region *daxctl_region_get_next(struct daxctl_region *region);
void daxctl_region_ref(struct daxctl_region *region);
void daxctl_region_unref(struct daxctl_region *region);
void daxctl_region_get_uuid(struct daxctl_region *region, uuid_t uu);
int daxctl_region_get_id(struct daxctl_region *region);
struct daxctl_ctx *daxctl_region_get_ctx(struct daxctl_region *region);
unsigned long long daxctl_region_get_available_size(
struct daxctl_region *region);
unsigned long long daxctl_region_get_size(struct daxctl_region *region);
unsigned long daxctl_region_get_align(struct daxctl_region *region);
const char *daxctl_region_get_devname(struct daxctl_region *region);
const char *daxctl_region_get_path(struct daxctl_region *region);
struct daxctl_dev *daxctl_region_get_dev_seed(struct daxctl_region *region);
struct daxctl_dev;
struct daxctl_dev *daxctl_dev_get_first(struct daxctl_region *region);
struct daxctl_dev *daxctl_dev_get_next(struct daxctl_dev *dev);
struct daxctl_region *daxctl_dev_get_region(struct daxctl_dev *dev);
int daxctl_dev_get_id(struct daxctl_dev *dev);
const char *daxctl_dev_get_devname(struct daxctl_dev *dev);
int daxctl_dev_get_major(struct daxctl_dev *dev);
int daxctl_dev_get_minor(struct daxctl_dev *dev);
unsigned long long daxctl_dev_get_size(struct daxctl_dev *dev);
#define daxctl_dev_foreach(region, dev) \
for (dev = daxctl_dev_get_first(region); \
dev != NULL; \
dev = daxctl_dev_get_next(dev))
#define daxctl_region_foreach(ctx, region) \
for (region = daxctl_region_get_first(ctx); \
region != NULL; \
region = daxctl_region_get_next(region))
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
ndctl-61.2/daxctl/list.c000066400000000000000000000064131331777607200151650ustar00rootroot00000000000000/*
* Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static struct {
bool devs;
bool regions;
bool idle;
bool human;
} list;
static unsigned long listopts_to_flags(void)
{
unsigned long flags = 0;
if (list.devs)
flags |= UTIL_JSON_DAX_DEVS;
if (list.idle)
flags |= UTIL_JSON_IDLE;
if (list.human)
flags |= UTIL_JSON_HUMAN;
return flags;
}
static struct {
const char *dev;
int region_id;
} param = {
.region_id = -1,
};
static int did_fail;
static int jflag = JSON_C_TO_STRING_PRETTY;
#define fail(fmt, ...) \
do { \
did_fail = 1; \
fprintf(stderr, "daxctl-%s:%s:%d: " fmt, \
VERSION, __func__, __LINE__, ##__VA_ARGS__); \
} while (0)
static int num_list_flags(void)
{
return list.regions + list.devs;
}
int cmd_list(int argc, const char **argv, void *ctx)
{
const struct option options[] = {
OPT_INTEGER('r', "region", ¶m.region_id, "filter by region"),
OPT_STRING('d', "dev", ¶m.dev, "dev-id",
"filter by dax device instance name"),
OPT_BOOLEAN('D', "devices", &list.devs, "include dax device info"),
OPT_BOOLEAN('R', "regions", &list.regions, "include dax region info"),
OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
OPT_BOOLEAN('u', "human", &list.human,
"use human friendly number formats "),
OPT_END(),
};
const char * const u[] = {
"daxctl list []",
NULL
};
struct json_object *jregions = NULL;
struct json_object *jdevs = NULL;
struct daxctl_region *region;
int i;
argc = parse_options(argc, argv, options, u, 0);
for (i = 0; i < argc; i++)
error("unknown parameter \"%s\"\n", argv[i]);
if (argc)
usage_with_options(u, options);
if (num_list_flags() == 0) {
list.regions = param.region_id >= 0;
list.devs = !!param.dev;
}
if (num_list_flags() == 0)
list.devs = true;
daxctl_region_foreach(ctx, region) {
struct json_object *jregion = NULL;
if (param.region_id >= 0 && param.region_id
!= daxctl_region_get_id(region))
continue;
if (list.regions) {
if (!jregions) {
jregions = json_object_new_array();
if (!jregions) {
fail("\n");
continue;
}
}
jregion = util_daxctl_region_to_json(region,
param.dev, listopts_to_flags());
if (!jregion) {
fail("\n");
continue;
}
json_object_array_add(jregions, jregion);
} else if (list.devs)
jdevs = util_daxctl_devs_to_list(region, jdevs,
param.dev, listopts_to_flags());
}
if (jregions)
util_display_json_array(stdout, jregions, jflag);
else if (jdevs)
util_display_json_array(stdout, jdevs, jflag);
if (did_fail)
return -ENOMEM;
return 0;
}
ndctl-61.2/git-version000077500000000000000000000016511331777607200147620ustar00rootroot00000000000000#!/bin/bash
to_ver() {
VN=$1
#drop leading 'v' out of the version so its a pure number
if [ ${VN:0:1} = "v" ]; then
VN=${VN:1}
fi
echo $VN
}
dirty() {
VN=$(to_ver $1)
git update-index -q --refresh
if test -z "$(git diff-index --name-only HEAD --)"; then
echo "$VN"
else
echo "${VN}.dirty"
fi
}
DEF_VER=61.2
LF='
'
# First see if there is a version file (included in release tarballs),
# then try git-describe, then default.
if test -f version; then
VN=$(cat version) || VN="$DEF_VER"
elif test -d ${GIT_DIR:-.git} -o -f .git &&
VN=$(git describe --match "v[0-9]*" --abbrev=7 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
VN="$(dirty $VN)"
esac; then
VN=$(echo "$VN" | sed -e 's/-/./g');
else
read COMMIT COMMIT_SUBJECT </dev/null)
EOF
if [ -z $COMMIT ]; then
VN="${DEF_VER}+"
else
VN="$(dirty ${DEF_VER}.git$COMMIT)"
fi
fi
echo $VN
ndctl-61.2/git-version-gen000077500000000000000000000004421331777607200155260ustar00rootroot00000000000000#!/bin/sh
GVF=version.m4
if test -r $GVF; then
VC=$(sed -e 's/m4_define(\[GIT_VERSION], \[//' <$GVF)
VC=$(echo $VC | sed -e 's/\])//')
else
VC=unset
fi
VN=$(./git-version)
test "$VN" = "$VC" || {
echo >&2 "GIT_VERSION = $VN"
echo "m4_define([GIT_VERSION], [$VN])" >$GVF
exit 0
}
ndctl-61.2/licenses/000077500000000000000000000000001331777607200143705ustar00rootroot00000000000000ndctl-61.2/licenses/BSD-MIT000066400000000000000000000017771331777607200153660ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
ndctl-61.2/licenses/CC0000066400000000000000000000143571331777607200146720ustar00rootroot00000000000000Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
moral rights retained by the original author(s) and/or performer(s);
publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
rights protecting the extraction, dissemination, use and reuse of data in a Work;
database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
ndctl-61.2/m4/000077500000000000000000000000001331777607200131035ustar00rootroot00000000000000ndctl-61.2/m4/.gitignore000066400000000000000000000001001331777607200150620ustar00rootroot00000000000000libtool.m4
ltoptions.m4
ltsugar.m4
ltversion.m4
lt~obsolete.m4
ndctl-61.2/make-git-snapshot.sh000077500000000000000000000011501331777607200164520ustar00rootroot00000000000000#!/bin/bash
set -e
NAME=ndctl
REFDIR="$HOME/git/ndctl" # for faster cloning, if available
UPSTREAM=$REFDIR #TODO update once we have a public upstream
OUTDIR=$HOME/rpmbuild/SOURCES
[ -n "$1" ] && HEAD="$1" || HEAD="HEAD"
WORKDIR="$(mktemp -d --tmpdir "$NAME.XXXXXXXXXX")"
trap 'rm -rf $WORKDIR' exit
[ -d "$REFDIR" ] && REFERENCE="--reference $REFDIR"
git clone $REFERENCE "$UPSTREAM" "$WORKDIR"
VERSION=$(./git-version)
DIRNAME="ndctl-${VERSION}"
git archive --remote="$WORKDIR" --format=tar --prefix="$DIRNAME/" HEAD | gzip > $OUTDIR/"ndctl-${VERSION}.tar.gz"
echo "Written $OUTDIR/ndctl-${VERSION}.tar.gz"
ndctl-61.2/ndctl.spec.in000066400000000000000000000101621331777607200151500ustar00rootroot00000000000000Name: ndctl
Version: VERSION
Release: 1%{?dist}
Summary: Manage "libnvdimm" subsystem devices (Non-volatile Memory)
License: GPLv2
Group: System Environment/Base
Url: https://github.com/pmem/ndctl
Source0: https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
Requires: LNAME%{?_isa} = %{version}-%{release}
Requires: DAX_LNAME%{?_isa} = %{version}-%{release}
BuildRequires: autoconf
BuildRequires: asciidoc
BuildRequires: xmlto
BuildRequires: automake
BuildRequires: libtool
BuildRequires: pkgconfig
BuildRequires: pkgconfig(libkmod)
BuildRequires: pkgconfig(libudev)
BuildRequires: pkgconfig(uuid)
BuildRequires: pkgconfig(json-c)
BuildRequires: pkgconfig(bash-completion)
%description
Utility library for managing the "libnvdimm" subsystem. The "libnvdimm"
subsystem defines a kernel device model and control message interface for
platform NVDIMM resources like those defined by the ACPI 6+ NFIT (NVDIMM
Firmware Interface Table).
%package -n DNAME
Summary: Development files for libndctl
License: LGPLv2
Group: Development/Libraries
Requires: LNAME%{?_isa} = %{version}-%{release}
%description -n DNAME
The %{name}-devel package contains libraries and header files for
developing applications that use %{name}.
%package -n daxctl
Summary: Manage Device-DAX instances
License: GPLv2
Group: System Environment/Base
Requires: DAX_LNAME%{?_isa} = %{version}-%{release}
%description -n daxctl
The daxctl utility provides enumeration and provisioning commands for
the Linux kernel Device-DAX facility. This facility enables DAX mappings
of performance / feature differentiated memory without need of a
filesystem.
%package -n DAX_DNAME
Summary: Development files for libdaxctl
License: LGPLv2
Group: Development/Libraries
Requires: DAX_LNAME%{?_isa} = %{version}-%{release}
%description -n DAX_DNAME
The %{name}-devel package contains libraries and header files for
developing applications that use %{name}, a library for enumerating
"Device DAX" devices. Device DAX is a facility for establishing DAX
mappings of performance / feature-differentiated memory.
%package -n LNAME
Summary: Management library for "libnvdimm" subsystem devices (Non-volatile Memory)
License: LGPLv2
Group: System Environment/Libraries
Requires: DAX_LNAME%{?_isa} = %{version}-%{release}
%description -n LNAME
Libraries for %{name}.
%package -n DAX_LNAME
Summary: Management library for "Device DAX" devices
License: LGPLv2
Group: System Environment/Libraries
%description -n DAX_LNAME
Device DAX is a facility for establishing DAX mappings of performance /
feature-differentiated memory. DAX_LNAME provides an enumeration /
control API for these devices.
%prep
%setup -q ndctl-%{version}
%build
echo %{version} > version
./autogen.sh
%configure --disable-static --disable-silent-rules
make %{?_smp_mflags}
%install
%make_install
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%check
make check
%post -n LNAME -p /sbin/ldconfig
%postun -n LNAME -p /sbin/ldconfig
%post -n DAX_LNAME -p /sbin/ldconfig
%postun -n DAX_LNAME -p /sbin/ldconfig
%define bashcompdir %(pkg-config --variable=completionsdir bash-completion)
%files
%defattr(-,root,root)
%license util/COPYING licenses/BSD-MIT licenses/CC0
%{_bindir}/ndctl
%{_mandir}/man1/ndctl*
%{bashcompdir}/
%files -n daxctl
%defattr(-,root,root)
%license util/COPYING licenses/BSD-MIT licenses/CC0
%{_bindir}/daxctl
%{_mandir}/man1/daxctl*
%files -n LNAME
%defattr(-,root,root)
%doc README.md
%license COPYING licenses/BSD-MIT licenses/CC0
%{_libdir}/libndctl.so.*
%files -n DAX_LNAME
%defattr(-,root,root)
%doc README.md
%license COPYING licenses/BSD-MIT licenses/CC0
%{_libdir}/libdaxctl.so.*
%files -n DNAME
%defattr(-,root,root)
%license COPYING
%{_includedir}/ndctl/
%{_libdir}/libndctl.so
%{_libdir}/pkgconfig/libndctl.pc
%files -n DAX_DNAME
%defattr(-,root,root)
%license COPYING
%{_includedir}/daxctl/
%{_libdir}/libdaxctl.so
%{_libdir}/pkgconfig/libdaxctl.pc
%changelog
* Fri May 27 2016 Dan Williams - 53-1
- add daxctl-libs + daxctl-devel packages
- add bash completion
* Mon Apr 04 2016 Dan Williams - 52-1
- Initial rpm submission to Fedora
ndctl-61.2/ndctl/000077500000000000000000000000001331777607200136675ustar00rootroot00000000000000ndctl-61.2/ndctl/Makefile.am000066400000000000000000000013721331777607200157260ustar00rootroot00000000000000include $(top_srcdir)/Makefile.am.in
bin_PROGRAMS = ndctl
ndctl_SOURCES = ndctl.c \
bus.c \
create-nfit.c \
namespace.c \
check.c \
region.c \
dimm.c \
../util/log.c \
list.c \
test.c \
../util/json.c \
util/json-smart.c \
util/json-firmware.c \
inject-error.c \
inject-smart.c
if ENABLE_DESTRUCTIVE
ndctl_SOURCES += ../test/blk_namespaces.c \
../test/pmem_namespaces.c
ndctl_SOURCES += bat.c
endif
ndctl_LDADD =\
lib/libndctl.la \
../daxctl/lib/libdaxctl.la \
../libutil.a \
$(UUID_LIBS) \
$(KMOD_LIBS) \
$(JSON_LIBS)
if ENABLE_TEST
ndctl_SOURCES += ../test/libndctl.c \
../test/dsm-fail.c \
../util/sysfs.c \
../test/dpa-alloc.c \
../test/parent-uuid.c \
../test/multi-pmem.c \
../test/core.c
endif
ndctl-61.2/ndctl/action.h000066400000000000000000000005141331777607200153150ustar00rootroot00000000000000/*
* Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef __NDCTL_ACTION_H__
#define __NDCTL_ACTION_H__
enum device_action {
ACTION_ENABLE,
ACTION_DISABLE,
ACTION_CREATE,
ACTION_DESTROY,
ACTION_CHECK,
ACTION_WAIT,
ACTION_START,
};
#endif /* __NDCTL_ACTION_H__ */
ndctl-61.2/ndctl/bat.c000066400000000000000000000032611331777607200146030ustar00rootroot00000000000000/*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include
#include
#include
#include
#include
int cmd_bat(int argc, const char **argv, void *ctx)
{
int loglevel = LOG_DEBUG, i, rc;
struct ndctl_test *test;
bool force = false;
const char * const u[] = {
"ndctl bat []",
NULL
};
const struct option options[] = {
OPT_INTEGER('l', "loglevel", &loglevel,
"set the log level (default LOG_DEBUG)"),
OPT_BOOLEAN('f', "force", &force,
"force run all tests regardless of required kernel"),
OPT_END(),
};
argc = parse_options(argc, argv, options, u, 0);
for (i = 0; i < argc; i++)
error("unknown parameter \"%s\"\n", argv[i]);
if (argc)
usage_with_options(u, options);
if (force)
test = ndctl_test_new(UINT_MAX);
else
test = ndctl_test_new(0);
if (!test) {
fprintf(stderr, "failed to initialize test\n");
return EXIT_FAILURE;
}
rc = test_blk_namespaces(loglevel, test, ctx);
fprintf(stderr, "test_blk_namespaces: %s\n", rc ? "FAIL" : "PASS");
if (rc && rc != 77)
return rc;
rc = test_pmem_namespaces(loglevel, test, ctx);
fprintf(stderr, "test_pmem_namespaces: %s\n", rc ? "FAIL" : "PASS");
return ndctl_test_result(test, rc);
}
ndctl-61.2/ndctl/bus.c000066400000000000000000000054571331777607200146370ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2015-2018 Intel Corporation. All rights reserved. */
#include
#include
#include
#include
#include "action.h"
#include
#include
#include
#include
#include
#include
#include
#include
static struct {
bool verbose;
} param;
static const struct option bus_options[] = {
OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug"),
OPT_END(),
};
static int scrub_action(struct ndctl_bus *bus, enum device_action action)
{
switch (action) {
case ACTION_WAIT:
return ndctl_bus_wait_for_scrub_completion(bus);
case ACTION_START:
return ndctl_bus_start_scrub(bus);
default:
return -EINVAL;
}
}
static int bus_action(int argc, const char **argv, const char *usage,
const struct option *options, enum device_action action,
struct ndctl_ctx *ctx)
{
const char * const u[] = {
usage,
NULL
};
struct json_object *jbuses, *jbus;
int i, rc, success = 0, fail = 0;
struct ndctl_bus *bus;
const char *all = "all";
argc = parse_options(argc, argv, options, u, 0);
if (param.verbose)
ndctl_set_log_priority(ctx, LOG_DEBUG);
if (argc == 0) {
argc = 1;
argv = &all;
} else
for (i = 0; i < argc; i++)
if (strcmp(argv[i], "all") == 0) {
argv[0] = "all";
argc = 1;
break;
}
jbuses = json_object_new_array();
if (!jbuses)
return -ENOMEM;
for (i = 0; i < argc; i++) {
int found = 0;
ndctl_bus_foreach(ctx, bus) {
if (!util_bus_filter(bus, argv[i]))
continue;
found++;
rc = scrub_action(bus, action);
if (rc == 0) {
success++;
jbus = util_bus_to_json(bus);
if (jbus)
json_object_array_add(jbuses, jbus);
} else if (!fail)
fail = rc;
}
if (!found && param.verbose)
fprintf(stderr, "no bus matches id: %s\n", argv[i]);
}
if (success)
util_display_json_array(stdout, jbuses,
JSON_C_TO_STRING_PRETTY);
else
json_object_put(jbuses);
if (success)
return success;
return fail ? fail : -ENXIO;
}
int cmd_start_scrub(int argc, const char **argv, void *ctx)
{
char *usage = "ndctl start-scrub [ ... ] []";
int start = bus_action(argc, argv, usage, bus_options,
ACTION_START, ctx);
if (start <= 0) {
fprintf(stderr, "error starting scrub: %s\n",
strerror(-start));
return start;
} else {
return 0;
}
}
int cmd_wait_scrub(int argc, const char **argv, void *ctx)
{
char *usage = "ndctl wait-scrub [ ... ] []";
int wait = bus_action(argc, argv, usage, bus_options,
ACTION_WAIT, ctx);
if (wait <= 0) {
fprintf(stderr, "error waiting for scrub completion: %s\n",
strerror(-wait));
return wait;
} else {
return 0;
}
}
ndctl-61.2/ndctl/check.c000066400000000000000000001013721331777607200151140ustar00rootroot00000000000000/*
* Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct check_opts {
bool verbose;
bool force;
bool repair;
bool logfix;
};
struct btt_chk {
char *path;
int fd;
uuid_t parent_uuid;
unsigned long long rawsize;
unsigned long long nlba;
int start_off;
int num_arenas;
long sys_page_size;
struct arena_info *arena;
struct check_opts *opts;
struct log_ctx ctx;
};
struct arena_info {
struct arena_map map;
u64 size; /* Total bytes for this arena */
u64 external_lba_start;
u32 internal_nlba;
u32 internal_lbasize;
u32 external_nlba;
u32 external_lbasize;
u32 nfree;
u16 version_major;
u16 version_minor;
u64 nextoff;
u64 infooff;
u64 dataoff;
u64 mapoff;
u64 logoff;
u64 info2off;
u32 flags;
int num;
struct btt_chk *bttc;
int log_index[2];
};
static sigjmp_buf sj_env;
static void sigbus_hdl(int sig, siginfo_t *siginfo, void *ptr)
{
siglongjmp(sj_env, 1);
}
static int repair_msg(struct btt_chk *bttc)
{
info(bttc, " Run with --repair to make the changes\n");
return 0;
}
/**
* btt_read_info - read an info block from a given offset
* @bttc: the main btt_chk structure for this btt
* @btt_sb: struct btt_sb where the info block will be copied into
* @offset: offset in the raw namespace to read the info block from
*
* This will also use 'pread' to read the info block, and not mmap+loads
* as this is used before the mappings are set up.
*/
static int btt_read_info(struct btt_chk *bttc, struct btt_sb *btt_sb, u64 off)
{
ssize_t size;
size = pread(bttc->fd, btt_sb, sizeof(*btt_sb), off);
if (size < 0) {
err(bttc, "unable to read first info block: %s\n",
strerror(errno));
return -errno;
}
if (size != sizeof(*btt_sb)) {
err(bttc, "short read of first info block: %ld\n", size);
return -ENXIO;
}
return 0;
}
/**
* btt_write_info - write an info block to the given offset
* @bttc: the main btt_chk structure for this btt
* @btt_sb: struct btt_sb where the info block will be copied from
* @offset: offset in the raw namespace to write the info block to
*
* This will also use 'pwrite' to write the info block, and not mmap+stores
* as this is used before the mappings are set up.
*/
static int btt_write_info(struct btt_chk *bttc, struct btt_sb *btt_sb, u64 off)
{
ssize_t size;
int rc;
if (!bttc->opts->repair) {
err(bttc, "BTT info block at offset %#lx needs to be restored\n",
off);
repair_msg(bttc);
return -EIO;
}
info(bttc, "Restoring BTT info block at offset %#lx\n", off);
size = pwrite(bttc->fd, btt_sb, sizeof(*btt_sb), off);
if (size < 0) {
err(bttc, "unable to write the info block: %s\n",
strerror(errno));
return -errno;
}
if (size != sizeof(*btt_sb)) {
err(bttc, "short write of the info block: %ld\n", size);
return -ENXIO;
}
rc = fsync(bttc->fd);
if (rc < 0)
return -errno;
return 0;
}
/**
* btt_copy_to_info2 - restore the backup info block using the main one
* @a: the arena_info handle for this arena
*
* Called when a corrupted backup info block is detected. Copies the
* main info block over to the backup location. This is done using
* mmap + stores, and thus needs a msync.
*/
static int btt_copy_to_info2(struct arena_info *a)
{
void *ms_align;
size_t ms_size;
if (!a->bttc->opts->repair) {
err(a->bttc, "Arena %d: BTT info2 needs to be restored\n",
a->num);
return repair_msg(a->bttc);
}
printf("Arena %d: Restoring BTT info2\n", a->num);
memcpy(a->map.info2, a->map.info, BTT_INFO_SIZE);
ms_align = (void *)rounddown((u64)a->map.info2, a->bttc->sys_page_size);
ms_size = max(BTT_INFO_SIZE, a->bttc->sys_page_size);
if (msync(ms_align, ms_size, MS_SYNC) < 0)
return -errno;
return 0;
}
/*
* btt_map_lookup - given a pre-map Arena Block Address, return the post-map ABA
* @a: the arena_info handle for this arena
* @lba: the logical block address for which we are performing the lookup
*
* This will correctly account for map entries in the 'initial state'
*/
static u32 btt_map_lookup(struct arena_info *a, u32 lba)
{
u32 raw_mapping;
raw_mapping = le32_to_cpu(a->map.map[lba]);
if (raw_mapping & MAP_ENT_NORMAL)
return raw_mapping & MAP_LBA_MASK;
else
return lba;
}
static int btt_map_write(struct arena_info *a, u32 lba, u32 mapping)
{
void *ms_align;
if (!a->bttc->opts->repair) {
err(a->bttc,
"Arena %d: map[%#x] needs to be updated to %#x\n",
a->num, lba, mapping);
return repair_msg(a->bttc);
}
info(a->bttc, "Arena %d: Updating map[%#x] to %#x\n", a->num,
lba, mapping);
/*
* We want to set neither of the Z or E flags, and in the actual
* layout, this means setting the bit positions of both to '1' to
* indicate a 'normal' map entry
*/
mapping |= MAP_ENT_NORMAL;
a->map.map[lba] = cpu_to_le32(mapping);
ms_align = (void *)rounddown((u64)&a->map.map[lba],
a->bttc->sys_page_size);
if (msync(ms_align, a->bttc->sys_page_size, MS_SYNC) < 0)
return -errno;
return 0;
}
static void btt_log_group_read(struct arena_info *a, u32 lane,
struct log_group *log)
{
memcpy(log, &a->map.log[lane], LOG_GRP_SIZE);
}
static void btt_log_group_write(struct arena_info *a, u32 lane,
struct log_group *log)
{
memcpy(&a->map.log[lane], log, LOG_GRP_SIZE);
}
static u32 log_seq(struct log_group *log, int log_idx)
{
return le32_to_cpu(log->ent[log_idx].seq);
}
/*
* This function accepts two log entries, and uses the sequence number to
* find the 'older' entry. The return value indicates which of the two was
* the 'old' entry
*/
static int btt_log_get_old(struct arena_info *a, struct log_group *log)
{
int idx0 = a->log_index[0];
int idx1 = a->log_index[1];
int old;
if (log_seq(log, idx0) == 0) {
log->ent[idx0].seq = cpu_to_le32(1);
return 0;
}
if (log_seq(log, idx0) < log_seq(log, idx1)) {
if ((log_seq(log, idx1) - log_seq(log, idx0)) == 1)
old = 0;
else
old = 1;
} else {
if ((log_seq(log, idx0) - log_seq(log, idx1)) == 1)
old = 1;
else
old = 0;
}
return old;
}
static int btt_log_read(struct arena_info *a, u32 lane, struct log_entry *ent)
{
int new_ent;
struct log_group log;
if (ent == NULL)
return -EINVAL;
btt_log_group_read(a, lane, &log);
new_ent = 1 - btt_log_get_old(a, &log);
memcpy(ent, &log.ent[a->log_index[new_ent]], LOG_ENT_SIZE);
return 0;
}
static int btt_checksum_verify(struct btt_sb *btt_sb)
{
uint64_t sum;
le64 sum_save;
BUILD_BUG_ON(sizeof(struct btt_sb) != SZ_4K);
sum_save = btt_sb->checksum;
btt_sb->checksum = 0;
sum = fletcher64(btt_sb, sizeof(*btt_sb), 1);
if (sum != sum_save)
return 1;
/* restore the checksum in the buffer */
btt_sb->checksum = sum_save;
return 0;
}
/*
* Never pass a mmapped buffer to this as it will attempt to write to
* the buffer, and we want writes to only happened in a controlled fashion.
* In the non --repair case, even if such a buffer is passed, the write will
* result in a fault due to the readonly mmap flags.
*/
static int btt_info_verify(struct btt_chk *bttc, struct btt_sb *btt_sb)
{
if (memcmp(btt_sb->signature, BTT_SIG, BTT_SIG_LEN) != 0)
return -ENXIO;
if (!uuid_is_null(btt_sb->parent_uuid))
if (uuid_compare(bttc->parent_uuid, btt_sb->parent_uuid) != 0)
return -ENXIO;
if (btt_checksum_verify(btt_sb))
return -ENXIO;
return 0;
}
static int btt_info_read_verify(struct btt_chk *bttc, struct btt_sb *btt_sb,
u64 off)
{
int rc;
rc = btt_read_info(bttc, btt_sb, off);
if (rc)
return rc;
rc = btt_info_verify(bttc, btt_sb);
if (rc)
return rc;
return 0;
}
enum btt_errcodes {
BTT_OK = 0,
BTT_LOG_EQL_SEQ = 0x100,
BTT_LOG_OOB_SEQ,
BTT_LOG_OOB_LBA,
BTT_LOG_OOB_OLD,
BTT_LOG_OOB_NEW,
BTT_LOG_MAP_ERR,
BTT_MAP_OOB,
BTT_BITMAP_ERROR,
BTT_LOGFIX_ERR,
};
static void btt_xlat_status(struct arena_info *a, int errcode)
{
switch(errcode) {
case BTT_OK:
break;
case BTT_LOG_EQL_SEQ:
err(a->bttc,
"arena %d: found a pair of log entries with the same sequence number\n",
a->num);
break;
case BTT_LOG_OOB_SEQ:
err(a->bttc,
"arena %d: found a log entry with an out of bounds sequence number\n",
a->num);
break;
case BTT_LOG_OOB_LBA:
err(a->bttc,
"arena %d: found a log entry with an out of bounds LBA\n",
a->num);
break;
case BTT_LOG_OOB_OLD:
err(a->bttc,
"arena %d: found a log entry with an out of bounds 'old' mapping\n",
a->num);
break;
case BTT_LOG_OOB_NEW:
err(a->bttc,
"arena %d: found a log entry with an out of bounds 'new' mapping\n",
a->num);
break;
case BTT_LOG_MAP_ERR:
info(a->bttc,
"arena %d: found a log entry that does not match with a map entry\n",
a->num);
break;
case BTT_MAP_OOB:
err(a->bttc,
"arena %d: found a map entry that is out of bounds\n",
a->num);
break;
case BTT_BITMAP_ERROR:
err(a->bttc,
"arena %d: bitmap error: internal blocks are incorrectly referenced\n",
a->num);
break;
case BTT_LOGFIX_ERR:
err(a->bttc,
"arena %d: rewrite-log error: log may be in an unknown/unrecoverable state\n",
a->num);
break;
default:
err(a->bttc, "arena %d: unknown error: %d\n",
a->num, errcode);
}
}
/* Check that log entries are self consistent */
static int btt_check_log_entries(struct arena_info *a)
{
int idx0 = a->log_index[0];
int idx1 = a->log_index[1];
unsigned int i;
int rc = 0;
/*
* First, check both 'slots' for sequence numbers being distinct
* and in bounds
*/
for (i = 0; i < a->nfree; i++) {
struct log_group *log = &a->map.log[i];
if (log_seq(log, idx0) == log_seq(log, idx1))
return BTT_LOG_EQL_SEQ;
if (log_seq(log, idx0) > 3 || log_seq(log, idx1) > 3)
return BTT_LOG_OOB_SEQ;
}
/*
* Next, check only the 'new' slot in each lane for the remaining
* fields being in bounds
*/
for (i = 0; i < a->nfree; i++) {
struct log_entry ent;
rc = btt_log_read(a, i, &ent);
if (rc)
return rc;
if (ent.lba >= a->external_nlba)
return BTT_LOG_OOB_LBA;
if (ent.old_map >= a->internal_nlba)
return BTT_LOG_OOB_OLD;
if (ent.new_map >= a->internal_nlba)
return BTT_LOG_OOB_NEW;
}
return rc;
}
/* Check that map entries are self consistent */
static int btt_check_map_entries(struct arena_info *a)
{
unsigned int i;
u32 mapping;
for (i = 0; i < a->external_nlba; i++) {
mapping = btt_map_lookup(a, i);
if (mapping >= a->internal_nlba)
return BTT_MAP_OOB;
}
return 0;
}
/* Check that each flog entry has the correct corresponding map entry */
static int btt_check_log_map(struct arena_info *a)
{
unsigned int i;
u32 mapping;
int rc = 0, rc_saved = 0;
for (i = 0; i < a->nfree; i++) {
struct log_entry ent;
rc = btt_log_read(a, i, &ent);
if (rc)
return rc;
mapping = btt_map_lookup(a, ent.lba);
/*
* Case where the flog was written, but map couldn't be
* updated. The kernel should also be able to detect and
* fix this condition.
*/
if (ent.new_map != mapping && ent.old_map == mapping) {
info(a->bttc,
"arena %d: log[%d].new_map (%#x) doesn't match map[%#x] (%#x)\n",
a->num, i, ent.new_map, ent.lba, mapping);
rc = btt_map_write(a, ent.lba, ent.new_map);
if (rc)
rc_saved = rc;
}
}
return rc_saved ? BTT_LOG_MAP_ERR : 0;
}
static int btt_check_info2(struct arena_info *a)
{
/*
* Repair info2 if needed. The main info-block can be trusted
* as it has been verified during arena discovery
*/
if(memcmp(a->map.info2, a->map.info, BTT_INFO_SIZE))
return btt_copy_to_info2(a);
return 0;
}
/*
* This will create a bitmap where each bit corresponds to an internal
* 'block'. Between the BTT map and flog (representing 'free' blocks),
* every single internal block must be represented exactly once. This
* check will detect cases where either one or more blocks are never
* referenced, or if a block is referenced more than once.
*/
static int btt_check_bitmap(struct arena_info *a)
{
unsigned long *bm;
u32 i, btt_mapping;
int rc = BTT_BITMAP_ERROR;
bm = bitmap_alloc(a->internal_nlba);
if (bm == NULL)
return -ENOMEM;
/* map 'external_nlba' number of map entries */
for (i = 0; i < a->external_nlba; i++) {
btt_mapping = btt_map_lookup(a, i);
if (test_bit(btt_mapping, bm)) {
info(a->bttc,
"arena %d: internal block %#x is referenced by two map entries\n",
a->num, btt_mapping);
goto out;
}
bitmap_set(bm, btt_mapping, 1);
}
/* map 'nfree' number of flog entries */
for (i = 0; i < a->nfree; i++) {
struct log_entry ent;
rc = btt_log_read(a, i, &ent);
if (rc)
goto out;
if (test_bit(ent.old_map, bm)) {
info(a->bttc,
"arena %d: internal block %#x is referenced by two map/log entries\n",
a->num, ent.old_map);
rc = BTT_BITMAP_ERROR;
goto out;
}
bitmap_set(bm, ent.old_map, 1);
}
/* check that the bitmap is full */
if (!bitmap_full(bm, a->internal_nlba))
rc = BTT_BITMAP_ERROR;
out:
free(bm);
return rc;
}
static int btt_rewrite_log(struct arena_info *a)
{
struct log_group log;
int rc;
u32 i;
info(a->bttc, "arena %d: rewriting log\n", a->num);
/*
* To rewrite the log, we implicitly use the 'new' padding scheme of
* (0, 1) but resetting the log to a completely initial state (i.e.
* slot-0 contains a made-up entry containing the 'free' block from
* the existing current log entry, and a sequence number of '1'. All
* other slots are zeroed.
*
* This way of rewriting the log is the most flexible as it can be
* (ab)used to convert a new padding format back to the old one.
* Since it only recreates slot-0, which is common between both
* existing formats, an older kernel will simply initialize the free
* list using those slot-0 entries, and run with it as though slot-2
* is the other valid slot.
*/
memset(&log, 0, LOG_GRP_SIZE);
for (i = 0; i < a->nfree; i++) {
struct log_entry ent;
rc = btt_log_read(a, i, &ent);
if (rc)
return BTT_LOGFIX_ERR;
log.ent[0].lba = ent.lba;
log.ent[0].old_map = ent.old_map;
log.ent[0].new_map = ent.new_map;
log.ent[0].seq = 1;
btt_log_group_write(a, i, &log);
}
return 0;
}
static int btt_check_arenas(struct btt_chk *bttc)
{
struct arena_info *a = NULL;
int i, rc;
for(i = 0; i < bttc->num_arenas; i++) {
info(bttc, "checking arena %d\n", i);
a = &bttc->arena[i];
rc = btt_check_log_entries(a);
if (rc)
break;
rc = btt_check_map_entries(a);
if (rc)
break;
rc = btt_check_log_map(a);
if (rc)
break;
rc = btt_check_info2(a);
if (rc)
break;
/*
* bitmap test has to be after check_log_map so that any
* pending log updates have been performed. Otherwise the
* bitmap test may result in a false positive
*/
rc = btt_check_bitmap(a);
if (rc)
break;
if (bttc->opts->logfix) {
rc = btt_rewrite_log(a);
if (rc)
break;
}
}
if (a && rc != BTT_OK) {
btt_xlat_status(a, rc);
return -ENXIO;
}
return 0;
}
/*
* This copies over information from the info block to the arena_info struct.
* The main difference is that all the offsets (infooff, mapoff etc) were
* relative to the arena in the info block, but in arena_info, we use
* arena_off to make these offsets absolute, i.e. relative to the start of
* the raw namespace.
*/
static int btt_parse_meta(struct arena_info *arena, struct btt_sb *btt_sb,
u64 arena_off)
{
arena->internal_nlba = le32_to_cpu(btt_sb->internal_nlba);
arena->internal_lbasize = le32_to_cpu(btt_sb->internal_lbasize);
arena->external_nlba = le32_to_cpu(btt_sb->external_nlba);
arena->external_lbasize = le32_to_cpu(btt_sb->external_lbasize);
arena->nfree = le32_to_cpu(btt_sb->nfree);
if (arena->internal_nlba - arena->external_nlba != arena->nfree)
return -ENXIO;
if (arena->internal_lbasize != arena->external_lbasize)
return -ENXIO;
arena->version_major = le16_to_cpu(btt_sb->version_major);
arena->version_minor = le16_to_cpu(btt_sb->version_minor);
arena->nextoff = (btt_sb->nextoff == 0) ? 0 : (arena_off +
le64_to_cpu(btt_sb->nextoff));
arena->infooff = arena_off;
arena->dataoff = arena_off + le64_to_cpu(btt_sb->dataoff);
arena->mapoff = arena_off + le64_to_cpu(btt_sb->mapoff);
arena->logoff = arena_off + le64_to_cpu(btt_sb->logoff);
arena->info2off = arena_off + le64_to_cpu(btt_sb->info2off);
arena->size = (le64_to_cpu(btt_sb->nextoff) > 0)
? (le64_to_cpu(btt_sb->nextoff))
: (arena->info2off - arena->infooff + BTT_INFO_SIZE);
arena->flags = le32_to_cpu(btt_sb->flags);
if (btt_sb->flags & IB_FLAG_ERROR_MASK) {
err(arena->bttc, "Info block error flag is set, aborting\n");
return -ENXIO;
}
return 0;
}
static bool ent_is_padding(struct log_entry *ent)
{
return (ent->lba == 0) && (ent->old_map == 0) && (ent->new_map == 0)
&& (ent->seq == 0);
}
/*
* Detecting valid log indices: We read a log group, and iterate over its
* four slots. We expect that a padding slot will be all-zeroes, and use this
* to detect a padding slot vs. an actual entry.
*
* If a log_group is in the initial state, i.e. hasn't been used since the
* creation of this BTT layout, it will have three of the four slots with
* zeroes. We skip over these log_groups for the detection of log_index. If
* all log_groups are in the initial state (i.e. the BTT has never been
* written to), it is safe to assume the 'new format' of log entries in slots
* (0, 1).
*/
static int log_set_indices(struct arena_info *arena)
{
bool idx_set = false, initial_state = true;
int log_index[2] = {-1, -1};
struct log_group log;
int j, next_idx = 0;
u32 pad_count = 0;
u32 i;
for (i = 0; i < arena->nfree; i++) {
btt_log_group_read(arena, i, &log);
for (j = 0; j < 4; j++) {
if (!idx_set) {
if (ent_is_padding(&log.ent[j])) {
pad_count++;
continue;
} else {
/* Skip if index has been recorded */
if ((next_idx == 1) &&
(j == log_index[0]))
continue;
/* valid entry, record index */
log_index[next_idx] = j;
next_idx++;
}
if (next_idx == 2) {
/* two valid entries found */
idx_set = true;
} else if (next_idx > 2) {
/* too many valid indices */
return -ENXIO;
}
} else {
/*
* once the indices have been set, just verify
* that all subsequent log groups are either in
* their initial state or follow the same
* indices.
*/
if (j == log_index[0]) {
/* entry must be 'valid' */
if (ent_is_padding(&log.ent[j]))
return -ENXIO;
} else if (j == log_index[1]) {
;
/*
* log_index[1] can be padding if the
* lane never got used and it is still
* in the initial state (three 'padding'
* entries)
*/
} else {
/* entry must be invalid (padding) */
if (!ent_is_padding(&log.ent[j]))
return -ENXIO;
}
}
}
/*
* If any of the log_groups have more than one valid,
* non-padding entry, then the we are no longer in the
* initial_state
*/
if (pad_count < 3)
initial_state = false;
pad_count = 0;
}
if (!initial_state && !idx_set)
return -ENXIO;
/*
* If all the entries in the log were in the initial state,
* assume new padding scheme
*/
if (initial_state)
log_index[1] = 1;
/*
* Only allow the known permutations of log/padding indices,
* i.e. (0, 1), and (0, 2)
*/
if ((log_index[0] == 0) && ((log_index[1] == 1) || (log_index[1] == 2)))
; /* known index possibilities */
else {
err(arena->bttc, "Found an unknown padding scheme\n");
return -ENXIO;
}
arena->log_index[0] = log_index[0];
arena->log_index[1] = log_index[1];
info(arena->bttc, "arena[%d]: log_index_0 = %d\n",
arena->num, log_index[0]);
info(arena->bttc, "arena[%d]: log_index_1 = %d\n",
arena->num, log_index[1]);
return 0;
}
static int btt_discover_arenas(struct btt_chk *bttc)
{
int ret = 0;
struct arena_info *arena;
struct btt_sb *btt_sb;
size_t remaining = bttc->rawsize;
size_t cur_off = bttc->start_off;
u64 cur_nlba = 0;
int i = 0;
btt_sb = calloc(1, sizeof(*btt_sb));
if (!btt_sb)
return -ENOMEM;
while (remaining) {
/* Alloc memory for arena */
arena = realloc(bttc->arena, (i + 1) * sizeof(*arena));
if (!arena) {
ret = -ENOMEM;
goto out;
} else {
bttc->arena = arena;
arena = &bttc->arena[i];
/* zero the new memory */
memset(arena, 0, sizeof(*arena));
}
arena->infooff = cur_off;
ret = btt_read_info(bttc, btt_sb, cur_off);
if (ret)
goto out;
if (btt_info_verify(bttc, btt_sb) != 0) {
u64 offset;
/* Try to find the backup info block */
if (remaining <= ARENA_MAX_SIZE)
offset = rounddown(bttc->rawsize, SZ_4K) -
BTT_INFO_SIZE;
else
offset = cur_off + ARENA_MAX_SIZE -
BTT_INFO_SIZE;
info(bttc,
"Arena %d: Attempting recover info-block using info2\n", i);
ret = btt_read_info(bttc, btt_sb, offset);
if (ret) {
err(bttc, "Unable to read backup info block (offset %#lx)\n",
offset);
goto out;
}
ret = btt_info_verify(bttc, btt_sb);
if (ret) {
err(bttc, "Backup info block (offset %#lx) verification failed\n",
offset);
goto out;
}
ret = btt_write_info(bttc, btt_sb, cur_off);
if (ret) {
err(bttc, "Restoration of the info block failed: %s (%d)\n",
strerror(abs(ret)), ret);
goto out;
}
}
arena->num = i;
arena->bttc = bttc;
arena->external_lba_start = cur_nlba;
ret = btt_parse_meta(arena, btt_sb, cur_off);
if (ret) {
err(bttc, "Problem parsing arena[%d] metadata\n", i);
goto out;
}
remaining -= arena->size;
cur_off += arena->size;
cur_nlba += arena->external_nlba;
i++;
if (arena->nextoff == 0)
break;
}
bttc->num_arenas = i;
bttc->nlba = cur_nlba;
info(bttc, "found %d BTT arena%s\n", bttc->num_arenas,
(bttc->num_arenas > 1) ? "s" : "");
free(btt_sb);
return ret;
out:
free(bttc->arena);
free(btt_sb);
return ret;
}
static int btt_create_mappings(struct btt_chk *bttc)
{
struct arena_info *a;
int mmap_flags;
int i;
if (!bttc->opts->repair)
mmap_flags = PROT_READ;
else
mmap_flags = PROT_READ|PROT_WRITE;
for (i = 0; i < bttc->num_arenas; i++) {
a = &bttc->arena[i];
a->map.info_len = BTT_INFO_SIZE;
a->map.info = mmap(NULL, a->map.info_len, mmap_flags,
MAP_SHARED, bttc->fd, a->infooff);
if (a->map.info == MAP_FAILED) {
err(bttc, "mmap arena[%d].info [sz = %#lx, off = %#lx] failed: %s\n",
i, a->map.info_len, a->infooff, strerror(errno));
return -errno;
}
a->map.data_len = a->mapoff - a->dataoff;
a->map.data = mmap(NULL, a->map.data_len, mmap_flags,
MAP_SHARED, bttc->fd, a->dataoff);
if (a->map.data == MAP_FAILED) {
err(bttc, "mmap arena[%d].data [sz = %#lx, off = %#lx] failed: %s\n",
i, a->map.data_len, a->dataoff, strerror(errno));
return -errno;
}
a->map.map_len = a->logoff - a->mapoff;
a->map.map = mmap(NULL, a->map.map_len, mmap_flags,
MAP_SHARED, bttc->fd, a->mapoff);
if (a->map.map == MAP_FAILED) {
err(bttc, "mmap arena[%d].map [sz = %#lx, off = %#lx] failed: %s\n",
i, a->map.map_len, a->mapoff, strerror(errno));
return -errno;
}
a->map.log_len = a->info2off - a->logoff;
a->map.log = mmap(NULL, a->map.log_len, mmap_flags,
MAP_SHARED, bttc->fd, a->logoff);
if (a->map.log == MAP_FAILED) {
err(bttc, "mmap arena[%d].log [sz = %#lx, off = %#lx] failed: %s\n",
i, a->map.log_len, a->logoff, strerror(errno));
return -errno;
}
a->map.info2_len = BTT_INFO_SIZE;
a->map.info2 = mmap(NULL, a->map.info2_len, mmap_flags,
MAP_SHARED, bttc->fd, a->info2off);
if (a->map.info2 == MAP_FAILED) {
err(bttc, "mmap arena[%d].info2 [sz = %#lx, off = %#lx] failed: %s\n",
i, a->map.info2_len, a->info2off, strerror(errno));
return -errno;
}
}
return 0;
}
static void btt_remove_mappings(struct btt_chk *bttc)
{
struct arena_info *a;
int i;
for (i = 0; i < bttc->num_arenas; i++) {
a = &bttc->arena[i];
if (a->map.info)
munmap(a->map.info, a->map.info_len);
if (a->map.data)
munmap(a->map.data, a->map.data_len);
if (a->map.map)
munmap(a->map.map, a->map.map_len);
if (a->map.log)
munmap(a->map.log, a->map.log_len);
if (a->map.info2)
munmap(a->map.info2, a->map.info2_len);
}
}
static int btt_sb_get_expected_offset(struct btt_sb *btt_sb)
{
u16 version_major, version_minor;
version_major = le16_to_cpu(btt_sb->version_major);
version_minor = le16_to_cpu(btt_sb->version_minor);
if (version_major == 1 && version_minor == 1)
return BTT1_START_OFFSET;
else if (version_major == 2 && version_minor == 0)
return BTT2_START_OFFSET;
else
return -ENXIO;
}
static int __btt_recover_first_sb(struct btt_chk *bttc, int off)
{
int rc, est_arenas = 0;
u64 offset, remaining;
struct btt_sb *btt_sb;
/* Estimate the number of arenas */
remaining = bttc->rawsize - off;
while (remaining) {
if (remaining < ARENA_MIN_SIZE && est_arenas == 0)
return -EINVAL;
if (remaining > ARENA_MAX_SIZE) {
/* full-size arena */
remaining -= ARENA_MAX_SIZE;
est_arenas++;
continue;
}
if (remaining < ARENA_MIN_SIZE) {
/* 'remaining' was too small for another arena */
break;
} else {
/* last, short arena */
remaining = 0;
est_arenas++;
break;
}
}
info(bttc, "estimated arenas: %d, remaining bytes: %#lx\n",
est_arenas, remaining);
btt_sb = malloc(2 * sizeof(*btt_sb));
if (btt_sb == NULL)
return -ENOMEM;
/* Read the original first info block into btt_sb[0] */
rc = btt_read_info(bttc, &btt_sb[0], off);
if (rc)
goto out;
/* Attepmt 1: try recovery from expected end of the first arena */
if (est_arenas == 1)
offset = rounddown(bttc->rawsize - remaining, SZ_4K) -
BTT_INFO_SIZE;
else
offset = ARENA_MAX_SIZE - BTT_INFO_SIZE + off;
info(bttc, "Attempting recover info-block from end-of-arena offset %#lx\n",
offset);
rc = btt_info_read_verify(bttc, &btt_sb[1], offset);
if (rc == 0) {
int expected_offset = btt_sb_get_expected_offset(&btt_sb[1]);
/*
* The fact that the btt_sb is self-consistent doesn't tell us
* what BTT version it was, if restoring from the end of the
* arena. (i.e. a consistent sb may be found for any valid
* start offset). Use the version information in the sb to
* determine what the expected start offset is.
*/
if ((expected_offset < 0) || (expected_offset != off)) {
rc = -ENXIO;
goto out;
}
rc = btt_write_info(bttc, &btt_sb[1], off);
goto out;
}
/*
* Attempt 2: From the very end of 'rawsize', try to copy the fields
* that are constant in every arena (only valid when multiple arenas
* are present)
*/
if (est_arenas > 1) {
offset = rounddown(bttc->rawsize - remaining, SZ_4K) -
BTT_INFO_SIZE;
info(bttc, "Attempting to recover info-block from end offset %#lx\n",
offset);
rc = btt_info_read_verify(bttc, &btt_sb[1], offset);
if (rc)
goto out;
/* copy over the arena0 specific fields from btt_sb[0] */
btt_sb[1].flags = btt_sb[0].flags;
btt_sb[1].external_nlba = btt_sb[0].external_nlba;
btt_sb[1].internal_nlba = btt_sb[0].internal_nlba;
btt_sb[1].nextoff = btt_sb[0].nextoff;
btt_sb[1].dataoff = btt_sb[0].dataoff;
btt_sb[1].mapoff = btt_sb[0].mapoff;
btt_sb[1].logoff = btt_sb[0].logoff;
btt_sb[1].info2off = btt_sb[0].info2off;
btt_sb[1].checksum = btt_sb[0].checksum;
rc = btt_info_verify(bttc, &btt_sb[1]);
if (rc == 0) {
rc = btt_write_info(bttc, &btt_sb[1], off);
goto out;
}
}
/*
* Attempt 3: use info2off as-is, and check if we find a valid info
* block at that location.
*/
offset = le32_to_cpu(btt_sb[0].info2off);
if (offset > min(bttc->rawsize - BTT_INFO_SIZE,
ARENA_MAX_SIZE - BTT_INFO_SIZE + off)) {
rc = -ENXIO;
goto out;
}
if (offset) {
info(bttc, "Attempting to recover info-block from info2 offset %#lx\n",
offset);
rc = btt_info_read_verify(bttc, &btt_sb[1],
offset + off);
if (rc == 0) {
rc = btt_write_info(bttc, &btt_sb[1], off);
goto out;
}
} else
rc = -ENXIO;
out:
free(btt_sb);
return rc;
}
static int btt_recover_first_sb(struct btt_chk *bttc)
{
int offsets[BTT_NUM_OFFSETS] = {
BTT1_START_OFFSET,
BTT2_START_OFFSET,
};
int i, rc;
for (i = 0; i < BTT_NUM_OFFSETS; i++) {
rc = __btt_recover_first_sb(bttc, offsets[i]);
if (rc == 0) {
bttc->start_off = offsets[i];
return rc;
}
}
return rc;
}
int namespace_check(struct ndctl_namespace *ndns, bool verbose, bool force,
bool repair, bool logfix)
{
const char *devname = ndctl_namespace_get_devname(ndns);
struct check_opts __opts = {
.verbose = verbose,
.force = force,
.repair = repair,
.logfix = logfix,
}, *opts = &__opts;
int raw_mode, rc, disabled_flag = 0, open_flags;
struct btt_sb *btt_sb;
struct btt_chk *bttc;
struct sigaction act;
char path[50];
int i;
bttc = calloc(1, sizeof(*bttc));
if (bttc == NULL)
return -ENOMEM;
log_init(&bttc->ctx, devname, "NDCTL_CHECK_NAMESPACE");
if (opts->verbose)
bttc->ctx.log_priority = LOG_DEBUG;
memset(&act, 0, sizeof(act));
act.sa_sigaction = sigbus_hdl;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGBUS, &act, 0)) {
err(bttc, "Unable to set sigaction\n");
rc = -errno;
goto out_bttc;
}
if (opts->logfix) {
if (!opts->repair) {
err(bttc, "--rewrite-log also requires --repair\n");
rc = -EINVAL;
goto out_bttc;
}
info(bttc,
"WARNING: interruption may cause unrecoverable metadata corruption\n");
}
bttc->opts = opts;
bttc->sys_page_size = sysconf(_SC_PAGESIZE);
bttc->rawsize = ndctl_namespace_get_size(ndns);
ndctl_namespace_get_uuid(ndns, bttc->parent_uuid);
info(bttc, "checking %s\n", devname);
if (ndctl_namespace_is_active(ndns)) {
if (opts->force) {
rc = ndctl_namespace_disable_safe(ndns);
if (rc)
goto out_bttc;
disabled_flag = 1;
} else {
err(bttc, "%s: check aborted, namespace online\n",
devname);
rc = -EBUSY;
goto out_bttc;
}
}
/* In typical usage, the current raw_mode should be false. */
raw_mode = ndctl_namespace_get_raw_mode(ndns);
/*
* Putting the namespace into raw mode will allow us to access
* the btt metadata.
*/
rc = ndctl_namespace_set_raw_mode(ndns, 1);
if (rc < 0) {
err(bttc, "%s: failed to set the raw mode flag: %s (%d)\n",
devname, strerror(abs(rc)), rc);
goto out_ns;
}
/*
* Now enable the namespace. This will result in a pmem device
* node showing up in /dev that is in raw mode.
*/
rc = ndctl_namespace_enable(ndns);
if (rc != 0) {
err(bttc, "%s: failed to enable in raw mode: %s (%d)\n",
devname, strerror(abs(rc)), rc);
goto out_ns;
}
sprintf(path, "/dev/%s", ndctl_namespace_get_block_device(ndns));
bttc->path = path;
btt_sb = malloc(sizeof(*btt_sb));
if (btt_sb == NULL) {
rc = -ENOMEM;
goto out_ns;
}
if (!bttc->opts->repair)
open_flags = O_RDONLY|O_EXCL;
else
open_flags = O_RDWR|O_EXCL;
bttc->fd = open(bttc->path, open_flags);
if (bttc->fd < 0) {
err(bttc, "unable to open %s: %s\n",
bttc->path, strerror(errno));
rc = -errno;
goto out_sb;
}
/*
* This is where we jump to if we receive a SIGBUS, prior to doing any
* mmaped reads, and can safely abort
*/
if (sigsetjmp(sj_env, 1)) {
err(bttc, "Received a SIGBUS\n");
err(bttc,
"Metadata corruption found, recovery is not possible\n");
rc = -EFAULT;
goto out_close;
}
/* Try reading a BTT1 info block first */
rc = btt_info_read_verify(bttc, btt_sb, BTT1_START_OFFSET);
if (rc == 0)
bttc->start_off = BTT1_START_OFFSET;
if (rc) {
/* Try reading a BTT2 info block */
rc = btt_info_read_verify(bttc, btt_sb, BTT2_START_OFFSET);
if (rc == 0)
bttc->start_off = BTT2_START_OFFSET;
if (rc) {
rc = btt_recover_first_sb(bttc);
if (rc) {
err(bttc, "Unable to recover any BTT info blocks\n");
goto out_close;
}
/*
* btt_recover_first_sb will have set bttc->start_off
* based on the version it found
*/
rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off);
if (rc)
goto out_close;
}
}
rc = btt_discover_arenas(bttc);
if (rc)
goto out_close;
rc = btt_create_mappings(bttc);
if (rc)
goto out_close;
for (i = 0; i < bttc->num_arenas; i++) {
rc = log_set_indices(&bttc->arena[i]);
if (rc) {
err(bttc,
"Unable to deduce log/padding indices\n");
goto out_close;
}
}
rc = btt_check_arenas(bttc);
btt_remove_mappings(bttc);
out_close:
close(bttc->fd);
out_sb:
free(btt_sb);
out_ns:
ndctl_namespace_set_raw_mode(ndns, raw_mode);
ndctl_namespace_disable_invalidate(ndns);
if (disabled_flag)
if(ndctl_namespace_enable(ndns) < 0)
err(bttc, "%s: failed to re-enable namespace\n",
devname);
out_bttc:
free(bttc);
return rc;
}
ndctl-61.2/ndctl/create-nfit.c000066400000000000000000000117631331777607200162440ustar00rootroot00000000000000/*
* Copyright(c) 2014 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEFAULT_NFIT "local_nfit.bin"
static const char *nfit_file = DEFAULT_NFIT;
static LIST_HEAD(spas);
struct spa {
struct list_node list;
unsigned long long size, offset;
};
static int parse_add_spa(const struct option *option, const char *__arg, int unset)
{
struct spa *s = calloc(1, sizeof(struct spa));
char *arg = strdup(__arg);
char *size, *offset;
int rc = -ENOMEM;
if (!s || !arg)
goto err;
rc = -EINVAL;
size = arg;
offset = strchr(arg, ',');
if (!offset)
goto err;
*offset++ = '\0';
s->size = parse_size64(size);
if (s->size == ULLONG_MAX)
goto err;
s->offset = parse_size64(offset);
if (s->offset == ULLONG_MAX)
goto err;
list_add_tail(&spas, &s->list);
free(arg);
return 0;
err:
error("failed to parse --add-spa=%s\n", __arg);
free(arg);
free(s);
return rc;
}
static unsigned char nfit_checksum(void *buf, size_t size)
{
unsigned char sum, *data = buf;
size_t i;
for (sum = 0, i = 0; i < size; i++)
sum += data[i];
return 0 - sum;
}
static void writeq(unsigned long long v, void *a)
{
unsigned long long *p = a;
*p = htole64(v);
}
static void writel(unsigned long v, void *a)
{
unsigned long *p = a;
*p = htole32(v);
}
static void writew(unsigned short v, void *a)
{
unsigned short *p = a;
*p = htole16(v);
}
static void writeb(unsigned char v, void *a)
{
unsigned char *p = a;
*p = v;
}
static struct nfit *create_nfit(struct list_head *spa_list)
{
struct nfit_spa *nfit_spa;
struct nfit *nfit;
struct spa *s;
size_t size;
char *buf;
int i;
size = sizeof(struct nfit);
list_for_each(spa_list, s, list)
size += sizeof(struct nfit_spa);
buf = calloc(1, size);
if (!buf)
return NULL;
/* nfit header */
nfit = (struct nfit *) buf;
memcpy(nfit->signature, "NFIT", 4);
writel(size, &nfit->length);
writeb(1, &nfit->revision);
memcpy(nfit->oemid, "LOCAL", 6);
writew(1, &nfit->oem_tbl_id);
writel(1, &nfit->oem_revision);
writel(0x80860000, &nfit->creator_id);
writel(1, &nfit->creator_revision);
nfit_spa = (struct nfit_spa *) (buf + sizeof(*nfit));
i = 1;
list_for_each(spa_list, s, list) {
writew(NFIT_TABLE_SPA, &nfit_spa->type);
writew(sizeof(*nfit_spa), &nfit_spa->length);
nfit_spa_uuid_pm(&nfit_spa->type_uuid);
writew(i++, &nfit_spa->range_index);
writeq(s->offset, &nfit_spa->spa_base);
writeq(s->size, &nfit_spa->spa_length);
nfit_spa++;
}
writeb(nfit_checksum(buf, size), &nfit->checksum);
return nfit;
}
static int write_nfit(struct nfit *nfit, const char *file, int force)
{
int fd;
ssize_t rc;
mode_t mode = S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP;
fd = open(file, O_RDWR|O_CREAT|O_EXCL, mode);
if (fd < 0 && !force && errno == EEXIST) {
error("\"%s\" exists, overwrite with --force\n", file);
return -EEXIST;
} else if (fd < 0 && force && errno == EEXIST) {
fd = open(file, O_RDWR|O_CREAT|O_TRUNC, mode);
}
if (fd < 0) {
error("Failed to open \"%s\": %s\n", file, strerror(errno));
return -errno;
}
rc = write(fd, nfit, le32toh(nfit->length));
close(fd);
return rc;
}
struct ndctl_ctx;
int cmd_create_nfit(int argc, const char **argv, void *ctx)
{
int i, rc = -ENXIO, force = 0;
const char * const u[] = {
"ndctl create-nfit []",
NULL
};
const struct option options[] = {
OPT_CALLBACK('a', "add-spa", NULL, "size,offset",
"add a system-physical-address range table entry",
parse_add_spa),
OPT_STRING('o', NULL, &nfit_file, "file",
"output to (default: " DEFAULT_NFIT ")"),
OPT_INCR('f', "force", &force, "overwrite if it already exists"),
OPT_END(),
};
struct spa *s, *_s;
struct nfit *nfit = NULL;
argc = parse_options(argc, argv, options, u, 0);
for (i = 0; i < argc; i++)
error("unknown parameter \"%s\"\n", argv[i]);
if (list_empty(&spas))
error("specify at least one --add-spa= option\n");
if (argc || list_empty(&spas))
usage_with_options(u, options);
nfit = create_nfit(&spas);
if (!nfit)
goto out;
rc = write_nfit(nfit, nfit_file, force);
if ((unsigned int) rc == le32toh(nfit->length)) {
fprintf(stderr, "wrote %d bytes to %s\n",
le32toh(nfit->length), nfit_file);
rc = 0;
}
out:
free(nfit);
list_for_each_safe(&spas, s, _s, list) {
list_del(&s->list);
free(s);
}
return rc;
}
ndctl-61.2/ndctl/dimm.c000066400000000000000000000647241331777607200147760ustar00rootroot00000000000000/*
* Copyright (c) 2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct action_context {
struct json_object *jdimms;
enum ndctl_namespace_version labelversion;
FILE *f_out;
FILE *f_in;
struct update_context update;
};
static int action_disable(struct ndctl_dimm *dimm, struct action_context *actx)
{
if (ndctl_dimm_is_active(dimm)) {
fprintf(stderr, "%s is active, skipping...\n",
ndctl_dimm_get_devname(dimm));
return -EBUSY;
}
return ndctl_dimm_disable(dimm);
}
static int action_enable(struct ndctl_dimm *dimm, struct action_context *actx)
{
return ndctl_dimm_enable(dimm);
}
static int action_zero(struct ndctl_dimm *dimm, struct action_context *actx)
{
return ndctl_dimm_zero_labels(dimm);
}
static struct json_object *dump_label_json(struct ndctl_dimm *dimm,
struct ndctl_cmd *cmd_read, ssize_t size)
{
struct json_object *jarray = json_object_new_array();
struct json_object *jlabel = NULL;
struct namespace_label nslabel;
unsigned int slot = -1;
ssize_t offset;
if (!jarray)
return NULL;
for (offset = NSINDEX_ALIGN * 2; offset < size;
offset += ndctl_dimm_sizeof_namespace_label(dimm)) {
ssize_t len = min_t(ssize_t,
ndctl_dimm_sizeof_namespace_label(dimm),
size - offset);
struct json_object *jobj;
char uuid[40];
slot++;
jlabel = json_object_new_object();
if (!jlabel)
break;
if (len < (ssize_t) ndctl_dimm_sizeof_namespace_label(dimm))
break;
len = ndctl_cmd_cfg_read_get_data(cmd_read, &nslabel, len, offset);
if (len < 0)
break;
if (le32_to_cpu(nslabel.slot) != slot)
continue;
uuid_unparse((void *) nslabel.uuid, uuid);
jobj = json_object_new_string(uuid);
if (!jobj)
break;
json_object_object_add(jlabel, "uuid", jobj);
nslabel.name[NSLABEL_NAME_LEN - 1] = 0;
jobj = json_object_new_string(nslabel.name);
if (!jobj)
break;
json_object_object_add(jlabel, "name", jobj);
jobj = json_object_new_int(le32_to_cpu(nslabel.slot));
if (!jobj)
break;
json_object_object_add(jlabel, "slot", jobj);
jobj = json_object_new_int(le16_to_cpu(nslabel.position));
if (!jobj)
break;
json_object_object_add(jlabel, "position", jobj);
jobj = json_object_new_int(le16_to_cpu(nslabel.nlabel));
if (!jobj)
break;
json_object_object_add(jlabel, "nlabel", jobj);
jobj = json_object_new_int64(le64_to_cpu(nslabel.isetcookie));
if (!jobj)
break;
json_object_object_add(jlabel, "isetcookie", jobj);
jobj = json_object_new_int64(le64_to_cpu(nslabel.lbasize));
if (!jobj)
break;
json_object_object_add(jlabel, "lbasize", jobj);
jobj = json_object_new_int64(le64_to_cpu(nslabel.dpa));
if (!jobj)
break;
json_object_object_add(jlabel, "dpa", jobj);
jobj = json_object_new_int64(le64_to_cpu(nslabel.rawsize));
if (!jobj)
break;
json_object_object_add(jlabel, "rawsize", jobj);
json_object_array_add(jarray, jlabel);
if (ndctl_dimm_sizeof_namespace_label(dimm) < 256)
continue;
uuid_unparse((void *) nslabel.type_guid, uuid);
jobj = json_object_new_string(uuid);
if (!jobj)
break;
json_object_object_add(jlabel, "type_guid", jobj);
uuid_unparse((void *) nslabel.abstraction_guid, uuid);
jobj = json_object_new_string(uuid);
if (!jobj)
break;
json_object_object_add(jlabel, "abstraction_guid", jobj);
}
if (json_object_array_length(jarray) < 1) {
json_object_put(jarray);
if (jlabel)
json_object_put(jlabel);
jarray = NULL;
}
return jarray;
}
static struct json_object *dump_index_json(struct ndctl_cmd *cmd_read, ssize_t size)
{
struct json_object *jarray = json_object_new_array();
struct json_object *jindex = NULL;
struct namespace_index nsindex;
ssize_t offset;
if (!jarray)
return NULL;
for (offset = 0; offset < NSINDEX_ALIGN * 2; offset += NSINDEX_ALIGN) {
ssize_t len = min_t(ssize_t, sizeof(nsindex), size - offset);
struct json_object *jobj;
jindex = json_object_new_object();
if (!jindex)
break;
if (len < (ssize_t) sizeof(nsindex))
break;
len = ndctl_cmd_cfg_read_get_data(cmd_read, &nsindex, len, offset);
if (len < 0)
break;
nsindex.sig[NSINDEX_SIG_LEN - 1] = 0;
jobj = json_object_new_string(nsindex.sig);
if (!jobj)
break;
json_object_object_add(jindex, "signature", jobj);
jobj = json_object_new_int(le16_to_cpu(nsindex.major));
if (!jobj)
break;
json_object_object_add(jindex, "major", jobj);
jobj = json_object_new_int(le16_to_cpu(nsindex.minor));
if (!jobj)
break;
json_object_object_add(jindex, "minor", jobj);
jobj = json_object_new_int(1 << (7 + nsindex.labelsize));
if (!jobj)
break;
json_object_object_add(jindex, "labelsize", jobj);
jobj = json_object_new_int(le32_to_cpu(nsindex.seq));
if (!jobj)
break;
json_object_object_add(jindex, "seq", jobj);
jobj = json_object_new_int(le32_to_cpu(nsindex.nslot));
if (!jobj)
break;
json_object_object_add(jindex, "nslot", jobj);
json_object_array_add(jarray, jindex);
}
if (json_object_array_length(jarray) < 1) {
json_object_put(jarray);
if (jindex)
json_object_put(jindex);
jarray = NULL;
}
return jarray;
}
static struct json_object *dump_json(struct ndctl_dimm *dimm,
struct ndctl_cmd *cmd_read, ssize_t size)
{
struct json_object *jdimm = json_object_new_object();
struct json_object *jlabel, *jobj, *jindex;
if (!jdimm)
return NULL;
jindex = dump_index_json(cmd_read, size);
if (!jindex)
goto err_jindex;
jlabel = dump_label_json(dimm, cmd_read, size);
if (!jlabel)
goto err_jlabel;
jobj = json_object_new_string(ndctl_dimm_get_devname(dimm));
if (!jobj)
goto err_jobj;
json_object_object_add(jdimm, "dev", jobj);
json_object_object_add(jdimm, "index", jindex);
json_object_object_add(jdimm, "label", jlabel);
return jdimm;
err_jobj:
json_object_put(jlabel);
err_jlabel:
json_object_put(jindex);
err_jindex:
json_object_put(jdimm);
return NULL;
}
static int rw_bin(FILE *f, struct ndctl_cmd *cmd, ssize_t size, int rw)
{
char buf[4096];
ssize_t offset, write = 0;
for (offset = 0; offset < size; offset += sizeof(buf)) {
ssize_t len = min_t(ssize_t, sizeof(buf), size - offset), rc;
if (rw) {
len = fread(buf, 1, len, f);
if (len == 0)
break;
rc = ndctl_cmd_cfg_write_set_data(cmd, buf, len, offset);
if (rc < 0)
return -ENXIO;
write += len;
} else {
len = ndctl_cmd_cfg_read_get_data(cmd, buf, len, offset);
if (len < 0)
return len;
rc = fwrite(buf, 1, len, f);
if (rc != len)
return -ENXIO;
fflush(f);
}
}
if (write)
return ndctl_cmd_submit(cmd);
return 0;
}
static int action_write(struct ndctl_dimm *dimm, struct action_context *actx)
{
struct ndctl_cmd *cmd_read, *cmd_write;
ssize_t size;
int rc = 0;
if (ndctl_dimm_is_active(dimm)) {
fprintf(stderr, "dimm is active, abort label write\n");
return -EBUSY;
}
cmd_read = ndctl_dimm_read_labels(dimm);
if (!cmd_read)
return -ENXIO;
cmd_write = ndctl_dimm_cmd_new_cfg_write(cmd_read);
if (!cmd_write) {
ndctl_cmd_unref(cmd_read);
return -ENXIO;
}
size = ndctl_cmd_cfg_read_get_size(cmd_read);
rc = rw_bin(actx->f_in, cmd_write, size, 1);
/*
* If the dimm is already disabled the kernel is not holding a cached
* copy of the label space.
*/
if (!ndctl_dimm_is_enabled(dimm))
goto out;
rc = ndctl_dimm_disable(dimm);
if (rc)
goto out;
rc = ndctl_dimm_enable(dimm);
out:
ndctl_cmd_unref(cmd_read);
ndctl_cmd_unref(cmd_write);
return rc;
}
static int action_read(struct ndctl_dimm *dimm, struct action_context *actx)
{
struct ndctl_cmd *cmd_read;
ssize_t size;
int rc = 0;
cmd_read = ndctl_dimm_read_labels(dimm);
if (!cmd_read)
return -ENXIO;
size = ndctl_cmd_cfg_read_get_size(cmd_read);
if (actx->jdimms) {
struct json_object *jdimm = dump_json(dimm, cmd_read, size);
if (jdimm)
json_object_array_add(actx->jdimms, jdimm);
else
rc = -ENOMEM;
} else
rc = rw_bin(actx->f_out, cmd_read, size, 0);
ndctl_cmd_unref(cmd_read);
return rc;
}
static int update_verify_input(struct action_context *actx)
{
int rc;
struct stat st;
rc = fstat(fileno(actx->f_in), &st);
if (rc == -1) {
rc = -errno;
fprintf(stderr, "fstat failed: %s\n", strerror(errno));
return rc;
}
if (!S_ISREG(st.st_mode)) {
fprintf(stderr, "Input not a regular file.\n");
return -EINVAL;
}
if (st.st_size == 0) {
fprintf(stderr, "Input file size is 0.\n");
return -EINVAL;
}
actx->update.fw_size = st.st_size;
return 0;
}
static int verify_fw_size(struct update_context *uctx)
{
struct fw_info *fw = &uctx->dimm_fw;
if (uctx->fw_size > fw->store_size) {
error("Firmware file size greater than DIMM store\n");
return -ENOSPC;
}
return 0;
}
static int submit_get_firmware_info(struct ndctl_dimm *dimm,
struct action_context *actx)
{
struct update_context *uctx = &actx->update;
struct fw_info *fw = &uctx->dimm_fw;
struct ndctl_cmd *cmd;
int rc;
enum ND_FW_STATUS status;
cmd = ndctl_dimm_cmd_new_fw_get_info(dimm);
if (!cmd)
return -ENXIO;
rc = ndctl_cmd_submit(cmd);
if (rc < 0)
return rc;
status = ndctl_cmd_fw_xlat_firmware_status(cmd);
if (status != FW_SUCCESS) {
fprintf(stderr, "GET FIRMWARE INFO on DIMM %s failed: %#x\n",
ndctl_dimm_get_devname(dimm), status);
return -ENXIO;
}
fw->store_size = ndctl_cmd_fw_info_get_storage_size(cmd);
if (fw->store_size == UINT_MAX)
return -ENXIO;
fw->update_size = ndctl_cmd_fw_info_get_max_send_len(cmd);
if (fw->update_size == UINT_MAX)
return -ENXIO;
fw->query_interval = ndctl_cmd_fw_info_get_query_interval(cmd);
if (fw->query_interval == UINT_MAX)
return -ENXIO;
fw->max_query = ndctl_cmd_fw_info_get_max_query_time(cmd);
if (fw->max_query == UINT_MAX)
return -ENXIO;
fw->run_version = ndctl_cmd_fw_info_get_run_version(cmd);
if (fw->run_version == ULLONG_MAX)
return -ENXIO;
rc = verify_fw_size(uctx);
ndctl_cmd_unref(cmd);
return rc;
}
static int submit_start_firmware_upload(struct ndctl_dimm *dimm,
struct action_context *actx)
{
struct update_context *uctx = &actx->update;
struct fw_info *fw = &uctx->dimm_fw;
struct ndctl_cmd *cmd;
int rc;
enum ND_FW_STATUS status;
cmd = ndctl_dimm_cmd_new_fw_start_update(dimm);
if (!cmd)
return -ENXIO;
rc = ndctl_cmd_submit(cmd);
if (rc < 0)
return rc;
status = ndctl_cmd_fw_xlat_firmware_status(cmd);
if (status != FW_SUCCESS) {
fprintf(stderr,
"START FIRMWARE UPDATE on DIMM %s failed: %#x\n",
ndctl_dimm_get_devname(dimm), status);
if (status == FW_EBUSY)
fprintf(stderr, "Another firmware upload in progress"
" or firmware already updated.\n");
return -ENXIO;
}
fw->context = ndctl_cmd_fw_start_get_context(cmd);
if (fw->context == UINT_MAX) {
fprintf(stderr,
"Retrieved firmware context invalid on DIMM %s\n",
ndctl_dimm_get_devname(dimm));
return -ENXIO;
}
uctx->start = cmd;
return 0;
}
static int get_fw_data_from_file(FILE *file, void *buf, uint32_t len)
{
size_t rc;
rc = fread(buf, len, 1, file);
if (rc != 1) {
if (feof(file))
fprintf(stderr,
"Firmware file shorter than expected\n");
else if (ferror(file))
fprintf(stderr, "Firmware file read error\n");
return -EBADF;
}
return len;
}
static int send_firmware(struct ndctl_dimm *dimm,
struct action_context *actx)
{
struct update_context *uctx = &actx->update;
struct fw_info *fw = &uctx->dimm_fw;
struct ndctl_cmd *cmd = NULL;
ssize_t read;
int rc = -ENXIO;
enum ND_FW_STATUS status;
uint32_t copied = 0, len, remain;
void *buf;
buf = malloc(fw->update_size);
if (!buf)
return -ENOMEM;
remain = uctx->fw_size;
while (remain) {
len = min(fw->update_size, remain);
read = get_fw_data_from_file(actx->f_in, buf, len);
if (read < 0) {
rc = read;
goto cleanup;
}
cmd = ndctl_dimm_cmd_new_fw_send(uctx->start, copied, read,
buf);
if (!cmd) {
rc = -ENXIO;
goto cleanup;
}
rc = ndctl_cmd_submit(cmd);
if (rc < 0)
goto cleanup;
status = ndctl_cmd_fw_xlat_firmware_status(cmd);
if (status != FW_SUCCESS) {
error("SEND FIRMWARE failed: %#x\n", status);
rc = -ENXIO;
goto cleanup;
}
copied += read;
remain -= read;
ndctl_cmd_unref(cmd);
cmd = NULL;
}
cleanup:
ndctl_cmd_unref(cmd);
free(buf);
return rc;
}
static int submit_finish_firmware(struct ndctl_dimm *dimm,
struct action_context *actx)
{
struct update_context *uctx = &actx->update;
struct ndctl_cmd *cmd;
int rc;
enum ND_FW_STATUS status;
cmd = ndctl_dimm_cmd_new_fw_finish(uctx->start);
if (!cmd)
return -ENXIO;
rc = ndctl_cmd_submit(cmd);
if (rc < 0)
goto out;
status = ndctl_cmd_fw_xlat_firmware_status(cmd);
if (status != FW_SUCCESS) {
fprintf(stderr,
"FINISH FIRMWARE UPDATE on DIMM %s failed: %#x\n",
ndctl_dimm_get_devname(dimm), status);
rc = -ENXIO;
goto out;
}
out:
ndctl_cmd_unref(cmd);
return rc;
}
static int submit_abort_firmware(struct ndctl_dimm *dimm,
struct action_context *actx)
{
struct update_context *uctx = &actx->update;
struct ndctl_cmd *cmd;
int rc;
enum ND_FW_STATUS status;
cmd = ndctl_dimm_cmd_new_fw_abort(uctx->start);
if (!cmd)
return -ENXIO;
rc = ndctl_cmd_submit(cmd);
if (rc < 0)
goto out;
status = ndctl_cmd_fw_xlat_firmware_status(cmd);
if (!(status & ND_CMD_STATUS_FIN_ABORTED)) {
fprintf(stderr,
"Firmware update abort on DIMM %s failed: %#x\n",
ndctl_dimm_get_devname(dimm), status);
rc = -ENXIO;
goto out;
}
out:
ndctl_cmd_unref(cmd);
return rc;
}
static int query_fw_finish_status(struct ndctl_dimm *dimm,
struct action_context *actx)
{
struct update_context *uctx = &actx->update;
struct fw_info *fw = &uctx->dimm_fw;
struct ndctl_cmd *cmd;
int rc;
enum ND_FW_STATUS status;
bool done = false;
struct timespec now, before, after;
uint64_t ver;
cmd = ndctl_dimm_cmd_new_fw_finish_query(uctx->start);
if (!cmd)
return -ENXIO;
rc = clock_gettime(CLOCK_MONOTONIC, &before);
if (rc < 0)
goto out;
now.tv_nsec = fw->query_interval / 1000;
now.tv_sec = 0;
do {
rc = ndctl_cmd_submit(cmd);
if (rc < 0)
break;
status = ndctl_cmd_fw_xlat_firmware_status(cmd);
switch (status) {
case FW_SUCCESS:
ver = ndctl_cmd_fw_fquery_get_fw_rev(cmd);
if (ver == 0) {
fprintf(stderr, "No firmware updated.\n");
rc = -ENXIO;
goto out;
}
printf("Image updated successfully to DIMM %s.\n",
ndctl_dimm_get_devname(dimm));
printf("Firmware version %#lx.\n", ver);
printf("Cold reboot to activate.\n");
done = true;
rc = 0;
break;
case FW_EBUSY:
/* Still on going, continue */
rc = clock_gettime(CLOCK_MONOTONIC, &after);
if (rc < 0) {
rc = -errno;
goto out;
}
/*
* If we expire max query time,
* we timed out
*/
if (after.tv_sec - before.tv_sec >
fw->max_query / 1000000) {
rc = -ETIMEDOUT;
goto out;
}
/*
* Sleep the interval dictated by firmware
* before query again.
*/
rc = nanosleep(&now, NULL);
if (rc < 0) {
rc = -errno;
goto out;
}
break;
case FW_EBADFW:
fprintf(stderr,
"Firmware failed to verify by DIMM %s.\n",
ndctl_dimm_get_devname(dimm));
case FW_EINVAL_CTX:
case FW_ESEQUENCE:
done = true;
rc = -ENXIO;
goto out;
case FW_ENORES:
fprintf(stderr,
"Firmware update sequence timed out: %s\n",
ndctl_dimm_get_devname(dimm));
rc = -ETIMEDOUT;
done = true;
goto out;
default:
fprintf(stderr,
"Unknown update status: %#x on DIMM %s\n",
status, ndctl_dimm_get_devname(dimm));
rc = -EINVAL;
done = true;
goto out;
}
} while (!done);
out:
ndctl_cmd_unref(cmd);
return rc;
}
static int update_firmware(struct ndctl_dimm *dimm,
struct action_context *actx)
{
int rc;
rc = submit_get_firmware_info(dimm, actx);
if (rc < 0)
return rc;
rc = submit_start_firmware_upload(dimm, actx);
if (rc < 0)
return rc;
printf("Uploading firmware to DIMM %s.\n",
ndctl_dimm_get_devname(dimm));
rc = send_firmware(dimm, actx);
if (rc < 0) {
fprintf(stderr, "Firmware send failed. Aborting!\n");
rc = submit_abort_firmware(dimm, actx);
if (rc < 0)
fprintf(stderr, "Aborting update sequence failed.\n");
return rc;
}
/*
* Done reading file, reset firmware file back to beginning for
* next update.
*/
rewind(actx->f_in);
rc = submit_finish_firmware(dimm, actx);
if (rc < 0) {
fprintf(stderr, "Unable to end update sequence.\n");
rc = submit_abort_firmware(dimm, actx);
if (rc < 0)
fprintf(stderr, "Aborting update sequence failed.\n");
return rc;
}
rc = query_fw_finish_status(dimm, actx);
if (rc < 0)
return rc;
return 0;
}
static int action_update(struct ndctl_dimm *dimm, struct action_context *actx)
{
int rc;
rc = ndctl_dimm_fw_update_supported(dimm);
switch (rc) {
case -ENOTTY:
error("%s: firmware update not supported by ndctl.",
ndctl_dimm_get_devname(dimm));
return rc;
case -EOPNOTSUPP:
error("%s: firmware update not supported by the kernel",
ndctl_dimm_get_devname(dimm));
return rc;
case -EIO:
error("%s: firmware update not supported by either platform firmware or the kernel.",
ndctl_dimm_get_devname(dimm));
return rc;
}
rc = update_verify_input(actx);
if (rc < 0)
return rc;
rc = update_firmware(dimm, actx);
if (rc < 0)
return rc;
ndctl_cmd_unref(actx->update.start);
return rc;
}
static struct parameters {
const char *bus;
const char *outfile;
const char *infile;
const char *labelversion;
bool force;
bool json;
bool verbose;
} param = {
.labelversion = "1.1",
};
static int __action_init(struct ndctl_dimm *dimm,
enum ndctl_namespace_version version, int chk_only)
{
struct ndctl_cmd *cmd_read;
int rc;
cmd_read = ndctl_dimm_read_labels(dimm);
if (!cmd_read)
return -ENXIO;
/*
* If the region goes active after this point, i.e. we're racing
* another administrative action, the kernel will fail writes to
* the label area.
*/
if (!chk_only && ndctl_dimm_is_active(dimm)) {
fprintf(stderr, "%s: regions active, abort label write\n",
ndctl_dimm_get_devname(dimm));
rc = -EBUSY;
goto out;
}
rc = ndctl_dimm_validate_labels(dimm);
if (chk_only)
goto out;
if (rc >= 0 && !param.force) {
fprintf(stderr, "%s: error: labels already initialized\n",
ndctl_dimm_get_devname(dimm));
rc = -EBUSY;
goto out;
}
rc = ndctl_dimm_init_labels(dimm, version);
if (rc < 0)
goto out;
/*
* If the dimm is already disabled the kernel is not holding a cached
* copy of the label space.
*/
if (!ndctl_dimm_is_enabled(dimm))
goto out;
rc = ndctl_dimm_disable(dimm);
if (rc)
goto out;
rc = ndctl_dimm_enable(dimm);
out:
ndctl_cmd_unref(cmd_read);
return rc;
}
static int action_init(struct ndctl_dimm *dimm, struct action_context *actx)
{
return __action_init(dimm, actx->labelversion, 0);
}
static int action_check(struct ndctl_dimm *dimm, struct action_context *actx)
{
return __action_init(dimm, 0, 1);
}
#define BASE_OPTIONS() \
OPT_STRING('b', "bus", ¶m.bus, "bus-id", \
" must be on a bus with an id/provider of "), \
OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug")
#define READ_OPTIONS() \
OPT_STRING('o', "output", ¶m.outfile, "output-file", \
"filename to write label area contents"), \
OPT_BOOLEAN('j', "json", ¶m.json, "parse label data into json")
#define WRITE_OPTIONS() \
OPT_STRING('i', "input", ¶m.infile, "input-file", \
"filename to read label area data")
#define UPDATE_OPTIONS() \
OPT_STRING('f', "firmware", ¶m.infile, "firmware-file", \
"firmware filename for update")
#define INIT_OPTIONS() \
OPT_BOOLEAN('f', "force", ¶m.force, \
"force initialization even if existing index-block present"), \
OPT_STRING('V', "label-version", ¶m.labelversion, "version-number", \
"namespace label specification version (default: 1.1)")
static const struct option read_options[] = {
BASE_OPTIONS(),
READ_OPTIONS(),
OPT_END(),
};
static const struct option write_options[] = {
BASE_OPTIONS(),
WRITE_OPTIONS(),
OPT_END(),
};
static const struct option update_options[] = {
BASE_OPTIONS(),
UPDATE_OPTIONS(),
OPT_END(),
};
static const struct option base_options[] = {
BASE_OPTIONS(),
OPT_END(),
};
static const struct option init_options[] = {
BASE_OPTIONS(),
INIT_OPTIONS(),
OPT_END(),
};
static int dimm_action(int argc, const char **argv, void *ctx,
int (*action)(struct ndctl_dimm *dimm, struct action_context *actx),
const struct option *options, const char *usage)
{
struct action_context actx = { 0 };
int i, rc = 0, count = 0, err = 0;
struct ndctl_dimm *single = NULL;
const char * const u[] = {
usage,
NULL
};
unsigned long id;
argc = parse_options(argc, argv, options, u, 0);
if (argc == 0)
usage_with_options(u, options);
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "all") == 0) {
argv[0] = "all";
argc = 1;
break;
}
if (sscanf(argv[i], "nmem%lu", &id) != 1) {
fprintf(stderr, "'%s' is not a valid dimm name\n",
argv[i]);
err++;
}
}
if (err == argc) {
usage_with_options(u, options);
return -EINVAL;
}
if (param.json) {
actx.jdimms = json_object_new_array();
if (!actx.jdimms)
return -ENOMEM;
}
if (!param.outfile)
actx.f_out = stdout;
else {
actx.f_out = fopen(param.outfile, "w+");
if (!actx.f_out) {
fprintf(stderr, "failed to open: %s: (%s)\n",
param.outfile, strerror(errno));
rc = -errno;
goto out;
}
}
if (!param.infile) {
if (action == action_update) {
usage_with_options(u, options);
return -EINVAL;
}
actx.f_in = stdin;
} else {
actx.f_in = fopen(param.infile, "r");
if (!actx.f_in) {
fprintf(stderr, "failed to open: %s: (%s)\n",
param.infile, strerror(errno));
rc = -errno;
goto out;
}
}
if (param.verbose)
ndctl_set_log_priority(ctx, LOG_DEBUG);
if (strcmp(param.labelversion, "1.1") == 0)
actx.labelversion = NDCTL_NS_VERSION_1_1;
else if (strcmp(param.labelversion, "v1.1") == 0)
actx.labelversion = NDCTL_NS_VERSION_1_1;
else if (strcmp(param.labelversion, "1.2") == 0)
actx.labelversion = NDCTL_NS_VERSION_1_2;
else if (strcmp(param.labelversion, "v1.2") == 0)
actx.labelversion = NDCTL_NS_VERSION_1_2;
else {
fprintf(stderr, "'%s' is not a valid label version\n",
param.labelversion);
rc = -EINVAL;
goto out;
}
rc = 0;
err = 0;
count = 0;
for (i = 0; i < argc; i++) {
struct ndctl_dimm *dimm;
struct ndctl_bus *bus;
if (sscanf(argv[i], "nmem%lu", &id) != 1
&& strcmp(argv[i], "all") != 0)
continue;
ndctl_bus_foreach(ctx, bus) {
if (!util_bus_filter(bus, param.bus))
continue;
ndctl_dimm_foreach(bus, dimm) {
if (!util_dimm_filter(dimm, argv[i]))
continue;
if (action == action_write) {
single = dimm;
rc = 0;
} else
rc = action(dimm, &actx);
if (rc == 0)
count++;
else if (rc && !err)
err = rc;
}
}
}
rc = err;
if (action == action_write) {
if (count > 1) {
error("write-labels only supports writing a single dimm\n");
usage_with_options(u, options);
return -EINVAL;
} else if (single)
rc = action(single, &actx);
}
if (actx.jdimms)
util_display_json_array(actx.f_out, actx.jdimms,
JSON_C_TO_STRING_PRETTY);
if (actx.f_out != stdout)
fclose(actx.f_out);
if (actx.f_in != stdin)
fclose(actx.f_in);
out:
/*
* count if some actions succeeded, 0 if none were attempted,
* negative error code otherwise.
*/
if (count > 0)
return count;
return rc;
}
int cmd_write_labels(int argc, const char **argv, void *ctx)
{
int count = dimm_action(argc, argv, ctx, action_write, write_options,
"ndctl write-labels [-i ]");
fprintf(stderr, "wrote %d nmem%s\n", count >= 0 ? count : 0,
count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}
int cmd_read_labels(int argc, const char **argv, void *ctx)
{
int count = dimm_action(argc, argv, ctx, action_read, read_options,
"ndctl read-labels [..] [-o ]");
fprintf(stderr, "read %d nmem%s\n", count >= 0 ? count : 0,
count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}
int cmd_zero_labels(int argc, const char **argv, void *ctx)
{
int count = dimm_action(argc, argv, ctx, action_zero, base_options,
"ndctl zero-labels [..