Skip to content

Commit 5049f1c

Browse files
author
Delphix Engineering
committed
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
2 parents cab858f + 3faa9c4 commit 5049f1c

File tree

18 files changed

+334
-109
lines changed

18 files changed

+334
-109
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ dist_noinst_DATA = \
3333
Doxyfile \
3434
NEWS \
3535
README.md \
36+
attributes.md \
3637
objects.md \
3738
threads.md
3839

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
next
22
----
3+
* Incompatible API changes:
4+
- kdump_get_typed_attr(): parameters and type mismatch behaviour
5+
- kdump_attr_ref_get(): result must be discarded
36
* Support flattened ELF dump files.
47
* Support partially rearranged makedumpfile split files.
58
* Parse QEMU CPU state ELF notes.

attributes.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
Attributes {#attributes}
2+
==========
3+
4+
All meta-information about a dump file is stored in attributes. All attributes
5+
form a tree-like dictionary, where every attribute is placed according to its
6+
path from the root node. The textual representation of this path, where path
7+
elements are delimited by dots, is called _attribute key_.
8+
9+
Some attributes are present in every [kdump_ctx_t] object, although not
10+
necessarily set. They are called _global attributes_. Other attributes may be
11+
created by the library as needed, e.g. CPU registers. It is not possible to
12+
create a new attribute with an arbitrary path through the public API.
13+
14+
Every attribute has a type and an optional value. The type and value can be
15+
queried with `kdump_get_attr`. If the attribute is unset (i.e. it does not
16+
have a value), this function returns `KDUMP_ERR_NODATA`. Attribute value can
17+
be set (or unset) with `kdump_set_attr`, but the type of an attribute cannot
18+
be changed.
19+
20+
Lifetime
21+
--------
22+
23+
Trivial types do not implement reference counting. The attribute value is
24+
always copied. Following types are trivial:
25+
- `KDUMP_NUMBER`
26+
- `KDUMP_ADDRESS`
27+
- `KDUMP_STRING`
28+
29+
Other attribute types refer to objects, and reference counting is used to make
30+
sure that the object does not unexpectedly disappear if the attribute value is
31+
(directly or indirectly) changed. Following types are reference-counted:
32+
- `KDUMP_BITMAP`
33+
- `KDUMP_BLOB`
34+
35+
For historical reasons, the simple attribute API (`kdump_get_attr`,
36+
`kdump_get_attr` and friends) does not increase the reference count of the
37+
returned data. User of this API must not modify the context object while
38+
making use of the returned attribute value. On the other hand, they don't have
39+
to do anything when they are finished.
40+
41+
When a value is returned by the reference-based API (`kdump_attr_ref_get`),
42+
reference count is increased (or a new dynamic string is allocated). Users of
43+
the attribute reference API should release the underlying resources with a
44+
call to `kdump_attr_discard`.
45+
46+
When a new value is set with `kdump_set_attr`, attributes with a trivial type
47+
make a copy of the new value, and attributes with a reference-counted type
48+
take ownership of the reference from the caller.
49+
50+
Well-known Attributes
51+
---------------------
52+
53+
Some attribute keys are available as macros. The intention is to spot mistakes
54+
earlier: A typo in a macro name is detected at build time, whereas a typo in a
55+
key string is not detected until run time.
56+
57+
Implementation
58+
--------------
59+
60+
Internally, there are two types of attributes:
61+
62+
- global, and
63+
- allocated.
64+
65+
Global attributes are allocated at dictionary initialization time, i.e. they
66+
exist in every dictionary object (albeit possibly unset). They can be looked
67+
up directly using a value from [enum global_keyidx] (identifiers with a `GKI_`
68+
prefix) as an index into the `global_attrs` fixed-size array in
69+
[struct attr_dict]. They can also be looked up through the hash table, like
70+
any other attribute, but that's less efficient, of course.
71+
72+
The values of some global attributes are assumed to be always available and
73+
valid. These values are in fact stored in [struct kdump_shared] and can be
74+
accessed from here with zero overhead by inline helper functions. These
75+
attributes are called _static_ and are used for frequently accessed values,
76+
such as `arch.byte_order` or `file.pagemap`.
77+
78+
It is possible to associate attribute operations with static attributes.
79+
However, the `revalidate` hook is not called when the value is accessed
80+
internally by the library using the `get_` or `sget_` helper functions.
81+
It is usually a bug to set `flags.invalid` for a static attribute.
82+
83+
All non-global attributes are dynamically allocated by `new_attr`, and there
84+
is nothing special about them.
85+
86+
Volatile and Persistent Attributes
87+
----------------------------------
88+
89+
Volatile attributes are cleared when a file format probe returns an error.
90+
Persistent attributes are kept. All attributes set through the public API are
91+
persistent. This implementation detail allows to set attribute values while
92+
probing a file format and remove those attributes automatically if it turns
93+
out to be a different file type.
94+
95+
The difference between volatile and persistent attributes is not visible in
96+
the public API.
97+
98+
[kdump_ctx_t]: @ref kdump_ctx_t
99+
[struct kdump_shared]: @ref kdump_shared
100+
[enum global_keyidx]: @ref global_keyidx
101+
[struct attr_dict]: @ref attr_dict

examples/dumpattr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ show_attr(kdump_ctx_t *ctx, kdump_attr_ref_t *ref, int indent, const char *key)
134134
printf("<unknown>\n");
135135
}
136136

137+
kdump_attr_discard(ctx, &attr);
137138
return 0;
138139
}
139140

include/libkdumpfile/kdumpfile.h.in

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -732,29 +732,38 @@ kdump_clear_attr(kdump_ctx_t *ctx, const char *key)
732732
* @param valp Value (filled on successful return).
733733
* @returns Error status.
734734
*
735-
* Note that the caller does not hold a reference to the attribute, so
736-
* it is not generally safe to use this function in a multi-threaded
737-
* program, or across another library call which modifies the attribute
738-
* (explicitly or implicitly).
735+
* This function is useful only when the caller can fully control the
736+
* lifetime of the returned attribute value. In that case, the value
737+
* is valid only as long as no changes are made to the containing dump
738+
* file object.
739+
*
740+
* Note that attribute data (or the attribute hierarchy itself) may
741+
* change as a side effect of another operation. Merely reading dump
742+
* data or attributes will never invalidate the attribute value, i.e.
743+
* it is safe to dereference pointers. However, the returned value may
744+
* become stale, for example cache statistics.
745+
*
746+
* A more robust API is provided by @ref kdump_attr_ref_get.
739747
*/
740748
kdump_status kdump_get_attr(kdump_ctx_t *ctx, const char *key,
741749
kdump_attr_t *valp);
742750

743-
/** Get a dump file attribute, checking its type.
751+
/** Get a dump file attribute with a given type.
744752
* @param ctx Dump file object.
745753
* @param key Attribute key.
754+
* @param type Expected attribute type.
746755
* @param valp Value (updated on return).
747756
* @returns Error status.
748757
*
749-
* The @c type field in @c valp must be set to the expected attribute
750-
* type by the caller. It is an error if the attribute is of a different
751-
* type, but @c valp is updated to its value anyway.
758+
* If the attribute is of a different type, this function returns
759+
* KDUMP_ERR_INVALID and does not change @p valp.
752760
*
753-
* Note that the caller does not hold a reference to the attribute. See
754-
* the description of @ref kdump_get_attr for limitations.
761+
* The caller must ensure the lifetime of the returned data is valid. See
762+
* the description of @ref kdump_get_attr for more details.
755763
*/
756764
kdump_status kdump_get_typed_attr(kdump_ctx_t *ctx, const char *key,
757-
kdump_attr_t *valp);
765+
kdump_attr_type_t type,
766+
kdump_attr_value_t *valp);
758767

759768
/** Get a numeric attribute.
760769
*
@@ -766,14 +775,8 @@ kdump_status kdump_get_typed_attr(kdump_ctx_t *ctx, const char *key,
766775
static inline kdump_status
767776
kdump_get_number_attr(kdump_ctx_t *ctx, const char *key, kdump_num_t *num)
768777
{
769-
kdump_attr_t attr;
770-
kdump_status ret;
771-
772-
attr.type = KDUMP_NUMBER;
773-
ret = kdump_get_typed_attr(ctx, key, &attr);
774-
if (ret == KDUMP_OK)
775-
*num = attr.val.number;
776-
return ret;
778+
return kdump_get_typed_attr(ctx, key, KDUMP_NUMBER,
779+
(kdump_attr_value_t *)num);
777780
}
778781

779782
/** Get an address attribute.
@@ -786,14 +789,8 @@ kdump_get_number_attr(kdump_ctx_t *ctx, const char *key, kdump_num_t *num)
786789
static inline kdump_status
787790
kdump_get_address_attr(kdump_ctx_t *ctx, const char *key, kdump_addr_t *addr)
788791
{
789-
kdump_attr_t attr;
790-
kdump_status ret;
791-
792-
attr.type = KDUMP_ADDRESS;
793-
ret = kdump_get_typed_attr(ctx, key, &attr);
794-
if (ret == KDUMP_OK)
795-
*addr = attr.val.address;
796-
return ret;
792+
return kdump_get_typed_attr(ctx, key, KDUMP_ADDRESS,
793+
(kdump_attr_value_t *)addr);
797794
}
798795

799796
/** Get a string attribute.
@@ -803,20 +800,14 @@ kdump_get_address_attr(kdump_ctx_t *ctx, const char *key, kdump_addr_t *addr)
803800
* @param str[out] Filled with the attribute value on successful return.
804801
* @returns Error status.
805802
*
806-
* Note that the caller does not hold a reference to the string. See
807-
* the description of @ref kdump_get_attr for limitations.
803+
* The caller must ensure the lifetime of the returned data is valid. See
804+
* the description of @ref kdump_get_attr for more details.
808805
*/
809806
static inline kdump_status
810807
kdump_get_string_attr(kdump_ctx_t *ctx, const char *key, const char **str)
811808
{
812-
kdump_attr_t attr;
813-
kdump_status ret;
814-
815-
attr.type = KDUMP_STRING;
816-
ret = kdump_get_typed_attr(ctx, key, &attr);
817-
if (ret == KDUMP_OK)
818-
*str = attr.val.string;
819-
return ret;
809+
return kdump_get_typed_attr(ctx, key, KDUMP_STRING,
810+
(kdump_attr_value_t *)str);
820811
}
821812

822813
/** Get a reference to an attribute
@@ -863,14 +854,42 @@ int kdump_attr_ref_isset(kdump_attr_ref_t *ref);
863854
/** Get attribute data by reference.
864855
* @param ctx Dump file object.
865856
* @param[in] ref Attribute reference.
866-
* @param[out] valp Attribute value (filled on successful return).
857+
* @param[out] valp Attribute value (filled on return).
858+
* @returns Error status.
867859
*
868-
* This works just like @ref kdump_get_attr, except that the attribute
869-
* is denoted by a reference rather than by its key path.
860+
* This works similarly to @ref kdump_get_attr, except:
861+
* - the attribute is denoted by a reference rather than by path,
862+
* - the returned data stays valid even if changes are made to the dump
863+
* object.
864+
*
865+
* The returned value may be a dynamically allocated copy of the attribute
866+
* value and/or it may hold an extra reference to the underlying objects.
867+
* You should free up these resources with @ref kdump_attr_discard when
868+
* the data is no longer needed.
869+
*
870+
* If the function returns an error, it is not necessary to discard the
871+
* result. However, the type of @p valp is set to @c KDUMP_NIL, so it is
872+
* always safe to call @ref kdump_attr_discard on the result. The goal of
873+
* this feature is to simplify code flow in callers.
870874
*/
871875
kdump_status kdump_attr_ref_get(kdump_ctx_t *ctx, const kdump_attr_ref_t *ref,
872876
kdump_attr_t *valp);
873877

878+
/** Discard attribute data value.
879+
* @param ctx Dump file object.
880+
* @param attr Attribute data.
881+
*
882+
* Perform any actions necessary to release resources by the attribute data.
883+
* This function may decrement object references, free dynamically allocated
884+
* memory, or even do nothing, depending on the data type.
885+
*
886+
* Call this function when the data returned by @ref kdump_attr_ref_get is no
887+
* longer needed. Do *NOT* call this function on attribute data returned by
888+
* @ref kdump_get_attr.
889+
*/
890+
void
891+
kdump_attr_discard(kdump_ctx_t *ctx, kdump_attr_t *attr);
892+
874893
/** Set attribute data by reference.
875894
* @param ctx Dump file object.
876895
* @param[in] ref Attribute reference.

python/kdumpfile.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -199,26 +199,37 @@ static PyObject *kdumpfile_read (PyObject *_self, PyObject *args, PyObject *kw)
199199
static PyObject *
200200
attr_new(kdumpfile_object *kdumpfile, kdump_attr_ref_t *ref, kdump_attr_t *attr)
201201
{
202+
PyObject *obj = NULL;
203+
202204
if (attr->type != KDUMP_DIRECTORY)
203205
kdump_attr_unref(kdumpfile->ctx, ref);
204206

205207
switch (attr->type) {
206208
case KDUMP_NUMBER:
207-
return PyLong_FromUnsignedLong(attr->val.number);
209+
obj = PyLong_FromUnsignedLong(attr->val.number);
210+
break;
208211
case KDUMP_ADDRESS:
209-
return PyLong_FromUnsignedLong(attr->val.address);
212+
obj = PyLong_FromUnsignedLong(attr->val.address);
213+
break;
210214
case KDUMP_STRING:
211-
return PyString_FromString(attr->val.string);
215+
obj = PyString_FromString(attr->val.string);
216+
break;
212217
case KDUMP_DIRECTORY:
213-
return attr_dir_new(kdumpfile, ref);
218+
obj= attr_dir_new(kdumpfile, ref);
219+
break;
214220
case KDUMP_BITMAP:
215-
return bmp_new(attr->val.bitmap);
221+
obj = bmp_new(attr->val.bitmap);
222+
break;
216223
case KDUMP_BLOB:
217-
return blob_new(attr->val.blob);
224+
obj = blob_new(attr->val.blob);
225+
break;
218226
default:
219227
PyErr_SetString(PyExc_RuntimeError, "Unhandled attr type");
220-
return NULL;
221228
}
229+
230+
kdump_attr_discard(kdumpfile->ctx, attr);
231+
232+
return obj;
222233
}
223234

224235
PyDoc_STRVAR(get_addrxlat_ctx__doc__,
@@ -1604,14 +1615,15 @@ attr_iteritem_next(PyObject *_self)
16041615

16051616
result = PyTuple_New(2);
16061617
if (result == NULL)
1607-
return NULL;
1618+
goto err_attr;
16081619
key = PyString_FromString(self->iter.key);
16091620
if (!key)
16101621
goto err_result;
16111622
value = attr_new(self->kdumpfile, &self->iter.pos, &attr);
16121623
if (!value)
16131624
goto err_key;
16141625

1626+
kdump_attr_discard(self->kdumpfile->ctx, &attr);
16151627
PyTuple_SET_ITEM(result, 0, key);
16161628
PyTuple_SET_ITEM(result, 1, value);
16171629
return attr_iter_advance(self, result);
@@ -1620,6 +1632,8 @@ attr_iteritem_next(PyObject *_self)
16201632
Py_DECREF(key);
16211633
err_result:
16221634
Py_DECREF(result);
1635+
err_attr:
1636+
kdump_attr_discard(self->kdumpfile->ctx, &attr);
16231637
return NULL;
16241638
}
16251639

src/kdumpfile/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ libkdumpfile_la_LIBADD = \
6464
$(SNAPPY_LIBS) \
6565
$(ZSTD_LIBS)
6666

67-
libkdumpfile_la_LDFLAGS = -version-info 11:0:1
67+
libkdumpfile_la_LDFLAGS = -version-info 12:0:0
6868

6969
if HAVE_LD_VERSION_SCRIPT
7070
libkdumpfile_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libkdumpfile.map

0 commit comments

Comments
 (0)